Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

makeup-expander

Package Overview
Dependencies
Maintainers
5
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

makeup-expander - npm Package Compare versions

Comparing version 0.7.3 to 0.8.0

264

index.js

@@ -19,3 +19,3 @@ 'use strict';

alwaysDoFocusManagement: false,
// in the case we want mouse click to move focus (e.g. menu buttons)
ariaControls: true,
autoCollapse: false,

@@ -33,30 +33,50 @@ collapseOnFocusOut: false,

simulateSpacebarClick: false
}; // when options.expandOnClick is true, we set a flag if spacebar or enter are pressed
// the idea being that this flag is set BEFORE the click event
};
function _onKeyDown(e) {
var keyCode = e.keyCode;
function onHostKeyDown(e) {
if (e.keyCode === 13 || e.keyCode === 32) {
this._keyboardClickFlag = true;
} // if host element does not naturally trigger a click event on spacebar, we can force one to trigger here.
// careful! if host already triggers click events naturally, we end up with a "double-click".
if (keyCode === 13 || keyCode === 32) {
this.keyDownFlag = true; // if host element does not naturally trigger a click event on spacebar, we can force one to trigger here.
// careful! if host already triggers click events naturally, we end up with a "double-click".
if (keyCode === 32 && this.options.simulateSpacebarClick === true) {
this.hostEl.click();
}
if (e.keyCode === 32 && this.options.simulateSpacebarClick === true) {
this.hostEl.click();
}
}
function processDocumentClick(event, el) {
if (el.contains(event.target) === false) {
el.dispatchEvent(new CustomEvent('clickOut', {
bubbles: false
}));
}
function onHostMouseDown() {
this._mouseClickFlag = true;
}
function _onDocumentClick(e) {
processDocumentClick(e, this.el);
function onHostClick() {
this._expandWasKeyboardClickActivated = this._keyboardClickFlag;
this._expandWasMouseClickActivated = this._mouseClickFlag;
this.expanded = !this.expanded;
}
function onHostFocus() {
this._expandWasFocusActivated = true;
this.expanded = true;
}
function onHostHover() {
this._expandWasHoverActivated = true;
this.expanded = true;
}
function onFocusExit() {
this.expanded = false;
}
function onMouseLeave() {
this.expanded = false;
}
function _onDocumentClick() {
if (this.el.contains(event.target) === false) {
this.expanded = false;
}
}
function _onDocumentTouchStart() {

@@ -70,9 +90,29 @@ this.documentClick = true;

function _onDocumentTouchEnd(e) {
if (this.documentClick) {
function _onDocumentTouchEnd() {
if (this.documentClick === true) {
this.documentClick = false;
processDocumentClick(e, this.el);
if (this.el.contains(event.target) === false) {
this.expanded = false;
}
}
}
function manageFocus(focusManagement, contentEl) {
if (focusManagement === 'content') {
contentEl.setAttribute('tabindex', '-1');
contentEl.focus();
} else if (focusManagement === 'focusable') {
focusables(contentEl)[0].focus();
} else if (focusManagement === 'interactive') {
focusables(contentEl, true)[0].focus();
} else if (focusManagement !== null) {
var el = contentEl.querySelector("#".concat(focusManagement));
if (el) {
el.focus();
}
}
}
module.exports =

@@ -88,10 +128,6 @@ /*#__PURE__*/

this.expandeeEl = el.querySelector(this.options.contentSelector);
this.keyDownFlag = false;
this.documentClick = false; // ensure the widget and expandee have an id
nextID(this.el, 'expander');
nextID(this.expandeeEl, "".concat(this.el.id, "-content"));
this.contentEl = el.querySelector(this.options.contentSelector);
ExitEmitter.addFocusExit(this.el);
this._hostKeyDownListener = _onKeyDown.bind(this);
this._hostKeyDownListener = onHostKeyDown.bind(this);
this._hostMouseDownListener = onHostMouseDown.bind(this);
this._documentClickListener = _onDocumentClick.bind(this);

@@ -101,8 +137,7 @@ this._documentTouchStartListener = _onDocumentTouchStart.bind(this);

this._documentTouchEndListener = _onDocumentTouchEnd.bind(this);
this._hostClickListener = this.toggle.bind(this);
this._hostFocusListener = this.expand.bind(this);
this._hostHoverListener = this.expand.bind(this);
this._focusExitListener = this.collapse.bind(this);
this._mouseLeaveListener = this.collapse.bind(this);
this._clickOutListener = this.collapse.bind(this);
this._hostClickListener = onHostClick.bind(this);
this._hostFocusListener = onHostFocus.bind(this);
this._hostHoverListener = onHostHover.bind(this);
this._focusExitListener = onFocusExit.bind(this);
this._mouseLeaveListener = onMouseLeave.bind(this);

@@ -113,3 +148,9 @@ if (this.hostEl.getAttribute('aria-expanded') === null) {

this.hostEl.setAttribute('aria-controls', this.expandeeEl.id);
if (this.options.ariaControls === true) {
// ensure the widget has an id
nextID(this.el, 'expander');
this.contentEl.id = this.contentEl.id || "".concat(this.el.id, "-content");
this.hostEl.setAttribute('aria-controls', this.contentEl.id);
}
this.expandOnClick = this.options.expandOnClick;

@@ -127,79 +168,59 @@ this.expandOnFocus = this.options.expandOnFocus;

_createClass(_class, [{
key: "isExpanded",
value: function isExpanded() {
return this.hostEl.getAttribute('aria-expanded') === 'true';
key: "sleep",
value: function sleep() {
if (this._destroyed !== true) {
this.expandOnClick = false;
this.expandOnFocus = false;
this.expandOnHover = false;
this.collapseOnClickOut = false;
this.collapseOnFocusOut = false;
this.collapseOnMouseOut = false;
}
}
}, {
key: "collapse",
value: function collapse() {
if (this.isExpanded() === true) {
this.hostEl.setAttribute('aria-expanded', 'false');
key: "destroy",
value: function destroy() {
this.sleep();
this._destroyed = true;
this._hostKeyDownListener = null;
this._hostMouseDownListener = null;
this._documentClickListener = null;
this._documentTouchStartListener = null;
this._documentTouchMoveListener = null;
this._documentTouchEndListener = null;
this._hostClickListener = null;
this._hostFocusListener = null;
this._hostHoverListener = null;
this._focusExitListener = null;
this._mouseLeaveListener = null;
} // DEPRECATED (remove in v1.0.0)
if (this.options.expandedClass) {
this.el.classList.remove(this.options.expandedClass);
}
}, {
key: "isExpanded",
value: function isExpanded() {
return this.expanded;
} // DEPRECATED (remove in v1.0.0)
this.el.dispatchEvent(new CustomEvent('expander-collapse', {
bubbles: true,
detail: this.expandeeEl
}));
}
} // todo: refactor to remove "isKeyboard" param
}, {
key: "expand",
value: function expand(isKeyboard) {
if (this.isExpanded() === false) {
this.hostEl.setAttribute('aria-expanded', 'true');
value: function expand() {
this.expanded = true;
} // DEPRECATED (remove in v1.0.0)
if (this.options.expandedClass) {
this.el.classList.add(this.options.expandedClass);
} // todo: refactor focus management. We could run into a bad situation where mouse hover moves focus.
}, {
key: "collapse",
value: function collapse() {
this.expanded = false;
} // DEPRECATED (remove in v1.0.0)
if (isKeyboard === true || this.options.alwaysDoFocusManagement === true) {
var focusManagement = this.options.focusManagement;
if (focusManagement === 'content') {
this.expandeeEl.setAttribute('tabindex', '-1');
this.expandeeEl.focus();
} else if (focusManagement === 'focusable') {
focusables(this.expandeeEl)[0].focus();
} else if (focusManagement === 'interactive') {
focusables(this.expandeeEl, true)[0].focus();
} else if (focusManagement !== null) {
var el = this.expandeeEl.querySelector("#".concat(focusManagement));
if (el) {
el.focus();
}
}
}
this.el.dispatchEvent(new CustomEvent('expander-expand', {
bubbles: true,
detail: this.expandeeEl
}));
}
}
}, {
key: "toggle",
value: function toggle() {
if (this.isExpanded() === true) {
this.collapse();
} else {
this.expand(this.keyDownFlag);
}
this.expanded = !this.expanded;
} // DEPRECATED (remove in v1.0.0)
this.keyDownFlag = false;
}
}, {
key: "cancelAsync",
value: function cancelAsync() {
this.expandOnClick = false;
this.expandOnFocus = false;
this.expandOnHover = false;
this.collapseOnClickOut = false;
this.collapseOnFocusOut = false;
this.collapseOnMouseOut = false;
this.sleep();
}

@@ -211,2 +232,3 @@ }, {

this.hostEl.addEventListener('keydown', this._hostKeyDownListener);
this.hostEl.addEventListener('mousedown', this._hostMouseDownListener);
this.hostEl.addEventListener('click', this._hostClickListener);

@@ -220,2 +242,3 @@

this.hostEl.removeEventListener('click', this._hostClickListener);
this.hostEl.removeEventListener('mousedown', this._hostMouseDownListener);
this.hostEl.removeEventListener('keydown', this._hostKeyDownListener);

@@ -259,5 +282,3 @@ }

document.addEventListener('touchend', this._documentTouchEndListener);
this.el.addEventListener('clickOut', this._clickOutListener);
} else {
this.el.removeEventListener('clickOut', this._clickOutListener);
document.removeEventListener('click', this._documentClickListener);

@@ -287,2 +308,45 @@ document.removeEventListener('touchstart', this._documentTouchStartListener);

}
}, {
key: "expanded",
get: function get() {
return this.hostEl.getAttribute('aria-expanded') === 'true';
},
set: function set(bool) {
if (bool === true && this.expanded === false) {
this.hostEl.setAttribute('aria-expanded', 'true');
if (this.options.expandedClass) {
this.el.classList.add(this.options.expandedClass);
}
if (this._expandWasKeyboardClickActivated || this._expandWasMouseClickActivated && this.options.alwaysDoFocusManagement) {
manageFocus(this.options.focusManagement, this.contentEl);
}
this.el.dispatchEvent(new CustomEvent('expander-expand', {
bubbles: true,
detail: this.contentEl
}));
}
if (bool === false && this.expanded === true) {
this.hostEl.setAttribute('aria-expanded', 'false');
if (this.options.expandedClass) {
this.el.classList.remove(this.options.expandedClass);
}
this.el.dispatchEvent(new CustomEvent('expander-collapse', {
bubbles: true,
detail: this.contentEl
}));
}
this._expandWasKeyboardClickActivated = false;
this._expandWasMouseClickActivated = false;
this._expandWasFocusActivated = false;
this._expandWasHoverActivated = false;
this._keyboardClickFlag = false;
this._mouseClickFlag = false;
}
}]);

@@ -289,0 +353,0 @@

{
"name": "makeup-expander",
"description": "Creates the basic interactivity for an element that expands and collapses another element.",
"version": "0.7.3",
"version": "0.8.0",
"main": "index.js",

@@ -51,3 +51,3 @@ "repository": "https://github.com/makeup-js/makeup-expander.git",

"nodelist-foreach-polyfill": "^1",
"onchange": "^5",
"onchange": "^6",
"parallelshell": "^3",

@@ -59,5 +59,5 @@ "puppeteer": "^1",

"custom-event-polyfill": "^1",
"makeup-exit-emitter": "~0.1.1",
"makeup-exit-emitter": "~0.2.0",
"makeup-focusables": "~0.0.4",
"makeup-next-id": "~0.0.3"
"makeup-next-id": "~0.1.1"
},

@@ -64,0 +64,0 @@ "files": [

@@ -26,4 +26,6 @@ # makeup-expander

## Example
## Example 1: Requires aria-expanded only
In the first example, our expanded content is adjacent to the host element.
```html

@@ -70,6 +72,44 @@ <div class="expander">

## Example 2: Requires aria-expanded and a class
In this second example, our expanded content is not adjacent to the host element.
```html
<div class="expander">
<span>
<input class="expander__host" type="text">
</span>
<div class="expander__content">
<p>Any kind of HTML control can go inside...</p>
<p>A link: <a id="foo" href="http://www.ebay.com">www.ebay.com</a></p>
<p>A button: <button>Click Me</button></p>
<p>An input: <input type="text" aria-label="Dummy textbox"></p>
<p>A checkbox: <input type="checkbox" aria-label="Dummy checkbox"></p>
</div>
</div>
```
A CSS classname is required as our styling hook. This can be passed in via the options.
```js
// options
const options = {
expandedClass: 'expander--expanded',
expandOnFocus: true
};
```
Setting focus on the host (a text input) sets it's aria-expanded state *and* add adds the chosen class to the root. CSS can be used to display the content accordingly, for example:
```css
.expander--expanded .expander__content {
display: block;
}
```
## Params
* `el`: the root widget el
* `options.alwaysDoFocusManagement`: honour `focusManagement` setting even when non-keyboard device is used (default: false)
* `options.alwaysDoFocusManagement`: whether `focusManagement` option (see below) should apply for mouse click
* `options.ariaControls`: specify whether `aria-controls` relationship should be created between host and overlay (default: true)
* `options.autoCollapse`: applies a collapse behavior (`collapseOnClick`, `collapseOnFocusOut`, `collapseOnMouseOut`) based on expand behaviour (default: false)

@@ -83,3 +123,3 @@ * `options.collapseOnClickOut`: whether the content should collapse when clicking outside of content (default: false)

* `options.expandOnHover`: whether the host should be hover activated (default: false)
* `options.focusManagement`: where keyboard focus should go (null, 'content', 'focusable', 'interactive', or ID reference) after expanded (default: null)
* `options.focusManagement`: where keyboard focus should go (null, 'content', 'focusable', 'interactive', or ID reference) when expanded via `ENTER` or `SPACEBAR` (default: null)
* `options.hostSelector`: the query selector for the host element in relation to the widget (default: '.expander__host')

@@ -95,2 +135,3 @@ * `options.expandedClass`: the class which will be used on the root element to signify expanded state. **Example:** `foo--expanded`; this mirrors the `aria-expanded="true"` setting on the host element

* `collapseOnMouseOut`
* `expanded`
* `expandOnClick`

@@ -102,6 +143,6 @@ * `expandOnFocus`

* `collapse()`: set state to collapsed
* `expand()`: set state to expanded
* `isExpanded()`: returns expanded state
* `toggle()`: toggle expanded/collapsed state
* `collapse()`: set state to collapsed (DEPRECATED)
* `expand()`: set state to expanded (DEPRECATED)
* `isExpanded()`: returns expanded state (DEPRECATED)
* `toggle()`: toggle expanded/collapsed state (DEPRECATED)

@@ -108,0 +149,0 @@ ## Events

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc