makeup-listbox
Advanced tools
Comparing version 0.3.1 to 0.3.2
{ | ||
"dependencies":[ | ||
"require: ./dist/index.js" | ||
] | ||
"dependencies": ["require: ./dist/index.js"] | ||
} |
@@ -9,17 +9,17 @@ "use strict"; | ||
var PreventScrollKeys = _interopRequireWildcard(require("makeup-prevent-scroll-keys")); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } | ||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } | ||
/** | ||
* A listbox can be a standalone focusable widget, or controlled by a separate, focusable widget | ||
* (a textbox for example, in the case of a combobox or datepicker) | ||
* | ||
* This listbox code currently supports single-selct only! | ||
* This code has been copied from Skin & MIND Patterns and has not yet been cleaned up. | ||
*/ | ||
* A listbox can be a standalone focusable widget, or controlled by a separate, focusable widget | ||
* (a textbox for example, in the case of a combobox or datepicker) | ||
* | ||
* This listbox code currently supports single-selct only! | ||
* This code has been copied from Skin & MIND Patterns and has not yet been cleaned up. | ||
*/ | ||
var defaultOptions = { | ||
activeDescendantClassName: 'listbox__option--active', | ||
const defaultOptions = { | ||
activeDescendantClassName: "listbox__option--active", | ||
// the classname applied to the current active desdcendant | ||
autoInit: 'ariaSelectedOrInteractive', | ||
autoReset: 'ariaSelectedOrInteractive', | ||
autoInit: "ariaSelectedOrInteractive", | ||
autoReset: "ariaSelectedOrInteractive", | ||
autoSelect: true, | ||
@@ -34,5 +34,6 @@ // when true, aria-checked state matches active-descendant | ||
// todo | ||
useAriaChecked: true // doubles up on support for aria-selected to announce visible selected/checked state | ||
useAriaChecked: true, | ||
// doubles up on support for aria-selected to announce visible selected/checked state | ||
valueSelector: ".listbox__value" // Selector to get value from | ||
}; | ||
function isSpacebarOrEnter(keyCode) { | ||
@@ -50,9 +51,9 @@ return keyCode === 13 || keyCode === 32; | ||
// todo: not sure this check is needed any more | ||
if (widgetEl.getAttribute('role') === 'listbox') { | ||
if (widgetEl.getAttribute("role") === "listbox") { | ||
this._listboxEl = widgetEl; | ||
} else { | ||
this._listboxEl = this.el.querySelector('[role=listbox]'); | ||
this._listboxEl = this.el.querySelector("[role=listbox]"); | ||
} | ||
if (!this._options.focusableElement && this._listboxEl.getAttribute('tabindex') === null) { | ||
this._listboxEl.setAttribute('tabindex', '0'); | ||
if (!this._options.focusableElement && this._listboxEl.getAttribute("tabindex") === null) { | ||
this._listboxEl.setAttribute("tabindex", "0"); | ||
} | ||
@@ -64,3 +65,3 @@ PreventScrollKeys.add(this.el); | ||
this._onMutationListener = _onMutation.bind(this); | ||
this.el.classList.add('listbox--js'); | ||
this.el.classList.add("listbox--js"); | ||
if (!this._options.customElementMode) { | ||
@@ -71,7 +72,7 @@ this._mutationObserver = new MutationObserver(this._onMutationListener); | ||
} | ||
this._activeDescendant = ActiveDescendant.createLinear(this._activeDescendantRootEl, this._options.focusableElement || this._listboxEl, this._listboxEl, '[role=option]', { | ||
this._activeDescendant = ActiveDescendant.createLinear(this._activeDescendantRootEl, this._options.focusableElement || this._listboxEl, this._listboxEl, "[role=option]", { | ||
activeDescendantClassName: this._options.activeDescendantClassName, | ||
autoInit: this._options.autoInit, | ||
autoReset: this._options.autoReset, | ||
axis: 'y' | ||
axis: "y" | ||
}); | ||
@@ -82,3 +83,3 @@ } | ||
this._mutationObserver.observe(this._listboxEl, { | ||
attributeFilter: ['aria-selected'], | ||
attributeFilter: ["aria-selected"], | ||
attributes: true, | ||
@@ -97,14 +98,14 @@ childList: true, | ||
if (this._destroyed !== true) { | ||
this._activeDescendantRootEl.addEventListener('activeDescendantChange', this._onActiveDescendantChangeListener); | ||
this._listboxEl.addEventListener('keydown', this._onKeyDownListener); | ||
this._listboxEl.addEventListener('click', this._onClickListener); | ||
this._activeDescendantRootEl.addEventListener("activeDescendantChange", this._onActiveDescendantChangeListener); | ||
this._listboxEl.addEventListener("keydown", this._onKeyDownListener); | ||
this._listboxEl.addEventListener("click", this._onClickListener); | ||
} | ||
} | ||
_unobserveEvents() { | ||
this._listboxEl.removeEventListener('keydown', this._onKeyDownListener); | ||
this._listboxEl.removeEventListener('click', this._onClickListener); | ||
this._activeDescendantRootEl.removeEventListener('activeDescendantChange', this._onActiveDescendantChangeListener); | ||
this._listboxEl.removeEventListener("keydown", this._onKeyDownListener); | ||
this._listboxEl.removeEventListener("click", this._onClickListener); | ||
this._activeDescendantRootEl.removeEventListener("activeDescendantChange", this._onActiveDescendantChangeListener); | ||
} | ||
get index() { | ||
return this.items.findIndex(el => el.getAttribute('aria-selected') === 'true'); | ||
return this.items.findIndex(el => el.getAttribute("aria-selected") === "true"); | ||
} | ||
@@ -116,13 +117,25 @@ get items() { | ||
this._unobserveMutations(); | ||
var itemEl = this.items[index]; | ||
if (itemEl && itemEl.getAttribute('aria-disabled') !== 'true') { | ||
var matchingItem = this.items[index]; | ||
matchingItem.setAttribute('aria-selected', 'true'); | ||
const itemEl = this.items[index]; | ||
if (itemEl && itemEl.getAttribute("aria-disabled") !== "true") { | ||
const matchingItem = this.items[index]; | ||
let optionValue; | ||
matchingItem.setAttribute("aria-selected", "true"); | ||
if (this._options.useAriaChecked === true) { | ||
matchingItem.setAttribute('aria-checked', 'true'); | ||
matchingItem.setAttribute("aria-checked", "true"); | ||
} | ||
this.el.dispatchEvent(new CustomEvent('makeup-listbox-change', { | ||
optionValue = matchingItem.innerText; | ||
// Check if value selector is present and use that to get innerText instead | ||
// If its not present, will default to innerText of the whole item | ||
if (this._options.valueSelector) { | ||
const valueSelector = matchingItem.querySelector(this._options.valueSelector); | ||
if (valueSelector) { | ||
optionValue = valueSelector.innerText; | ||
} | ||
} | ||
this.el.dispatchEvent(new CustomEvent("makeup-listbox-change", { | ||
detail: { | ||
el: matchingItem, | ||
optionIndex: index, | ||
optionValue: matchingItem.innerText | ||
optionValue | ||
} | ||
@@ -135,8 +148,8 @@ })); | ||
this._unobserveMutations(); | ||
var itemEl = this.items[index]; | ||
if (itemEl && itemEl.getAttribute('aria-disabled') !== 'true') { | ||
var matchingItem = this.items[index]; | ||
matchingItem.setAttribute('aria-selected', 'false'); | ||
const itemEl = this.items[index]; | ||
if (itemEl && itemEl.getAttribute("aria-disabled") !== "true") { | ||
const matchingItem = this.items[index]; | ||
matchingItem.setAttribute("aria-selected", "false"); | ||
if (this._options.useAriaChecked === true) { | ||
matchingItem.setAttribute('aria-checked', 'false'); | ||
matchingItem.setAttribute("aria-checked", "false"); | ||
} | ||
@@ -158,4 +171,4 @@ } | ||
function _onKeyDown(e) { | ||
var activeDescendantEl = this._activeDescendant.currentItem; | ||
if (isSpacebarOrEnter(e.keyCode) && (activeDescendantEl === null || activeDescendantEl === void 0 ? void 0 : activeDescendantEl.getAttribute('aria-selected')) !== 'true') { | ||
const activeDescendantEl = this._activeDescendant.currentItem; | ||
if (isSpacebarOrEnter(e.keyCode) && (activeDescendantEl === null || activeDescendantEl === void 0 ? void 0 : activeDescendantEl.getAttribute("aria-selected")) !== "true") { | ||
// todo: this.select() should take care of unselecting any existing selections | ||
@@ -169,6 +182,6 @@ this.unselect(this.index); | ||
// e.g. <div role="option"><span>Item 1</span></div> | ||
var toEl = e.target.closest('[role=option]'); | ||
var toElIndex = this.items.indexOf(toEl); | ||
var isTolElSelected = toEl.getAttribute('aria-selected') === 'true'; | ||
var isTolElDisabled = toEl.getAttribute('aria-disabled') === 'true'; | ||
const toEl = e.target.closest("[role=option]"); | ||
const toElIndex = this.items.indexOf(toEl); | ||
const isTolElSelected = toEl.getAttribute("aria-selected") === "true"; | ||
const isTolElDisabled = toEl.getAttribute("aria-disabled") === "true"; | ||
if (!isTolElDisabled && this._options.autoSelect === false && isTolElSelected === false) { | ||
@@ -181,3 +194,3 @@ // todo: this.select() should take care of unselecting any existing selections | ||
function _onActiveDescendantChange(e) { | ||
var { | ||
const { | ||
fromIndex, | ||
@@ -187,4 +200,4 @@ toIndex | ||
if (this._options.autoSelect === true) { | ||
var fromEl = this.items[fromIndex]; | ||
var toEl = this.items[toIndex]; | ||
const fromEl = this.items[fromIndex]; | ||
const toEl = this.items[toIndex]; | ||
if (fromEl) { | ||
@@ -200,5 +213,5 @@ // todo: this.select() should take care of unselecting any existing selections | ||
function _onMutation(mutationsList) { | ||
for (var mutation of mutationsList) { | ||
if (mutation.type === 'attributes') { | ||
this.el.dispatchEvent(new CustomEvent('makeup-listbox-mutation', { | ||
for (const mutation of mutationsList) { | ||
if (mutation.type === "attributes") { | ||
this.el.dispatchEvent(new CustomEvent("makeup-listbox-mutation", { | ||
detail: { | ||
@@ -205,0 +218,0 @@ attributeName: mutation.attributeName |
@@ -5,10 +5,18 @@ import * as ActiveDescendant from "makeup-active-descendant"; | ||
activeDescendantClassName: "listbox__option--active", | ||
// the classname applied to the current active desdcendant | ||
autoInit: "ariaSelectedOrInteractive", | ||
autoReset: "ariaSelectedOrInteractive", | ||
autoSelect: true, | ||
// when true, aria-checked state matches active-descendant | ||
customElementMode: false, | ||
focusableElement: null, | ||
// used in a combobox/datepicker scenario | ||
listboxOwnerElement: null, | ||
// used in a combobox/datepicker scenario | ||
multiSelect: false, | ||
useAriaChecked: true | ||
// todo | ||
useAriaChecked: true, | ||
// doubles up on support for aria-selected to announce visible selected/checked state | ||
valueSelector: ".listbox__value" | ||
// Selector to get value from | ||
}; | ||
@@ -72,6 +80,3 @@ function isSpacebarOrEnter(keyCode) { | ||
if (this._destroyed !== true) { | ||
this._activeDescendantRootEl.addEventListener( | ||
"activeDescendantChange", | ||
this._onActiveDescendantChangeListener | ||
); | ||
this._activeDescendantRootEl.addEventListener("activeDescendantChange", this._onActiveDescendantChangeListener); | ||
this._listboxEl.addEventListener("keydown", this._onKeyDownListener); | ||
@@ -84,6 +89,3 @@ this._listboxEl.addEventListener("click", this._onClickListener); | ||
this._listboxEl.removeEventListener("click", this._onClickListener); | ||
this._activeDescendantRootEl.removeEventListener( | ||
"activeDescendantChange", | ||
this._onActiveDescendantChangeListener | ||
); | ||
this._activeDescendantRootEl.removeEventListener("activeDescendantChange", this._onActiveDescendantChangeListener); | ||
} | ||
@@ -101,2 +103,3 @@ get index() { | ||
const matchingItem = this.items[index]; | ||
let optionValue; | ||
matchingItem.setAttribute("aria-selected", "true"); | ||
@@ -106,8 +109,18 @@ if (this._options.useAriaChecked === true) { | ||
} | ||
this.el.dispatchEvent(new CustomEvent("makeup-listbox-change", { | ||
detail: { | ||
optionIndex: index, | ||
optionValue: matchingItem.innerText | ||
optionValue = matchingItem.innerText; | ||
if (this._options.valueSelector) { | ||
const valueSelector = matchingItem.querySelector(this._options.valueSelector); | ||
if (valueSelector) { | ||
optionValue = valueSelector.innerText; | ||
} | ||
})); | ||
} | ||
this.el.dispatchEvent( | ||
new CustomEvent("makeup-listbox-change", { | ||
detail: { | ||
el: matchingItem, | ||
optionIndex: index, | ||
optionValue | ||
} | ||
}) | ||
); | ||
} | ||
@@ -171,7 +184,9 @@ this._observeMutations(); | ||
if (mutation.type === "attributes") { | ||
this.el.dispatchEvent(new CustomEvent("makeup-listbox-mutation", { | ||
detail: { | ||
attributeName: mutation.attributeName | ||
} | ||
})); | ||
this.el.dispatchEvent( | ||
new CustomEvent("makeup-listbox-mutation", { | ||
detail: { | ||
attributeName: mutation.attributeName | ||
} | ||
}) | ||
); | ||
} | ||
@@ -178,0 +193,0 @@ } |
{ | ||
"name": "makeup-listbox", | ||
"description": "A JavaScript class representing an ARIA listbox", | ||
"version": "0.3.1", | ||
"version": "0.3.2", | ||
"main": "./dist/cjs/index.js", | ||
@@ -6,0 +6,0 @@ "module": "./dist/mjs/index.js", |
@@ -15,28 +15,28 @@ # makeup-listbox | ||
<div class="listbox" data-auto-select="true"> | ||
<div class="listbox__options" role="listbox" tabindex="0"> | ||
<div class="listbox__option" role="option" aria-selected="false"> | ||
<span class="listbox__value">Option 1</span> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<use xlink:href="icon.svg#icon-tick-small"></use> | ||
</svg> | ||
</svg> | ||
</div> | ||
<div class="listbox__option" role="option" aria-selected="false"> | ||
<span class="listbox__value">Option 2</span> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<use xlink:href="icon.svg#icon-tick-small"></use> | ||
</svg> | ||
</svg> | ||
</div> | ||
<div class="listbox__option" role="option" aria-selected="false"> | ||
<span class="listbox__value">Option 3</span> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<use xlink:href="icon.svg#icon-tick-small"></use> | ||
</svg> | ||
</svg> | ||
</div> | ||
<div class="listbox__options" role="listbox" tabindex="0"> | ||
<div class="listbox__option" role="option" aria-selected="false"> | ||
<span class="listbox__value">Option 1</span> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<use href="icon.svg#icon-tick-small"></use> | ||
</svg> | ||
</svg> | ||
</div> | ||
<div class="listbox__option" role="option" aria-selected="false"> | ||
<span class="listbox__value">Option 2</span> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<use href="icon.svg#icon-tick-small"></use> | ||
</svg> | ||
</svg> | ||
</div> | ||
<div class="listbox__option" role="option" aria-selected="false"> | ||
<span class="listbox__value">Option 3</span> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<svg class="icon icon--tick-small" focusable="false" height="8" width="8"> | ||
<use href="icon.svg#icon-tick-small"></use> | ||
</svg> | ||
</svg> | ||
</div> | ||
</div> | ||
</div> | ||
@@ -52,10 +52,10 @@ ``` | ||
```js | ||
import Listbox from 'makeup-listbox'; | ||
import Listbox from "makeup-listbox"; | ||
document.querySelectorAll('.listbox').forEach(function(el, i) { | ||
const widget = new Listbox(el, config); | ||
document.querySelectorAll(".listbox").forEach(function (el, i) { | ||
const widget = new Listbox(el, config); | ||
el.addEventListener('makeup-listbox-change', function(e) { | ||
console.log(e.type, e.detail); | ||
}); | ||
el.addEventListener("makeup-listbox-change", function (e) { | ||
console.log(e.type, e.detail); | ||
}); | ||
}); | ||
@@ -76,3 +76,3 @@ ``` | ||
* `optionIndex`: the index position of the selected option | ||
* `optionValue`: the value of the selected option | ||
- `optionIndex`: the index position of the selected option | ||
- `optionValue`: the value of the selected option |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18602
5
399
1