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

makeup-listbox

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

makeup-listbox - npm Package Compare versions

Comparing version 0.2.1 to 0.3.0

package-lock.json

343

dist/cjs/index.js

@@ -7,36 +7,19 @@ "use strict";

exports.default = void 0;
var ActiveDescendant = _interopRequireWildcard(require("makeup-active-descendant"));
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; }
/**
* 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.
*/
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
var defaultOptions = {
activeDescendantClassName: 'listbox__option--active',
// the classname applied to the current active desdcendant
autoReset: null,
// passed to makeup-active-descendant
autoInit: 'ariaSelectedOrInteractive',
autoReset: 'ariaSelectedOrInteractive',
autoSelect: true,

@@ -52,14 +35,16 @@ // when true, aria-checked state matches active-descendant

useAriaChecked: true // doubles up on support for aria-selected to announce visible selected/checked state
};
var _default = /*#__PURE__*/function () {
function _default(widgetEl, selectedOptions) {
_classCallCheck(this, _default);
function isSpacebarOrEnter(keyCode) {
return keyCode === 13 || keyCode === 32;
}
class _default {
constructor(widgetEl, selectedOptions) {
this._options = Object.assign({}, defaultOptions, selectedOptions);
this.el = widgetEl; // in cases such as combobox, the active-descendant logic is controlled by a parent widget
this.el = widgetEl;
this._activeDescendantRootEl = this._options.listboxOwnerElement || this.el; // todo: not sure this check is needed any more
// in cases such as combobox, the active-descendant logic is controlled by a parent widget
this._activeDescendantRootEl = this._options.listboxOwnerElement || this.el;
// todo: not sure this check is needed any more
if (widgetEl.getAttribute('role') === 'listbox') {

@@ -70,17 +55,6 @@ this._listboxEl = widgetEl;

}
if (!this._options.focusableElement && this._listboxEl.getAttribute('tabindex') === null) {
this._listboxEl.setAttribute('tabindex', '0');
}
this._activeDescendant = ActiveDescendant.createLinear(this._activeDescendantRootEl, this._options.focusableElement || this._listboxEl, this._listboxEl, '[role=option]', {
activeDescendantClassName: this._options.activeDescendantClassName,
autoInit: this.index,
autoReset: this._options.autoReset,
axis: 'y',
ignoreButtons: true
});
PreventScrollKeys.add(this.el);
this._onFocusListener = _onFocus.bind(this);
this._onMouseDownListener = _onMouseDown.bind(this);
this._onKeyDownListener = _onKeyDown.bind(this);

@@ -91,180 +65,102 @@ this._onClickListener = _onClick.bind(this);

this.el.classList.add('listbox--js');
if (!this._options.customElementMode) {
this._mutationObserver = new MutationObserver(this._onMutationListener);
this._observeMutations();
this._observeEvents();
}
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'
});
}
_createClass(_default, [{
key: "_observeMutations",
value: function _observeMutations() {
if (!this._options.customElementMode) {
this._mutationObserver.observe(this._listboxEl, {
attributeFilter: ['aria-selected'],
attributes: true,
childList: true,
subtree: true
});
}
_observeMutations() {
if (!this._options.customElementMode) {
this._mutationObserver.observe(this._listboxEl, {
attributeFilter: ['aria-selected'],
attributes: true,
childList: true,
subtree: true
});
}
}, {
key: "_unobserveMutations",
value: function _unobserveMutations() {
if (!this._options.customElementMode) {
this._mutationObserver.disconnect();
}
}
_unobserveMutations() {
if (!this._options.customElementMode) {
this._mutationObserver.disconnect();
}
}, {
key: "_observeEvents",
value: function _observeEvents() {
if (this._destroyed !== true) {
this._listboxEl.addEventListener('focus', this._onFocusListener);
this._listboxEl.addEventListener('mousedown', this._onMouseDownListener);
this._activeDescendantRootEl.addEventListener('activeDescendantChange', this._onActiveDescendantChangeListener);
this._listboxEl.addEventListener('keydown', this._onKeyDownListener);
this._listboxEl.addEventListener('click', this._onClickListener);
}
_observeEvents() {
if (this._destroyed !== true) {
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);
}
get index() {
return this.items.findIndex(el => el.getAttribute('aria-selected') === 'true');
}
get items() {
return this._activeDescendant.items;
}
select(index) {
this._unobserveMutations();
if (_indexInBounds(index, this.items.length)) {
var matchingItem = this.items[index];
matchingItem.setAttribute('aria-selected', 'true');
if (this._options.useAriaChecked === true) {
matchingItem.setAttribute('aria-checked', 'true');
}
}
}, {
key: "_unobserveEvents",
value: function _unobserveEvents() {
this._listboxEl.removeEventListener('focus', this._onFocusListener);
this._listboxEl.removeEventListener('mousedown', this._onMouseDownListener);
this._listboxEl.removeEventListener('keydown', this._onKeyDownListener);
this._listboxEl.removeEventListener('click', this._onClickListener);
this._activeDescendantRootEl.removeEventListener('activeDescendantChange', this._onActiveDescendantChangeListener);
}
}, {
key: "index",
get: function get() {
return _toConsumableArray(this.items).findIndex(function (el) {
return el.getAttribute('aria-selected') === 'true';
});
}
}, {
key: "items",
get: function get() {
return this._listboxEl.querySelectorAll('[role=option]');
}
}, {
key: "select",
value: function select(index) {
this._unobserveMutations();
if (_indexInBounds(index, this.items.length)) {
this.items[index].setAttribute('aria-selected', 'true');
if (this._options.useAriaChecked === true) {
this.items[index].setAttribute('aria-checked', 'true');
this.el.dispatchEvent(new CustomEvent('makeup-listbox-change', {
detail: {
optionIndex: index,
optionValue: matchingItem.innerText
}
this.el.dispatchEvent(new CustomEvent('makeup-listbox-change', {
detail: {
optionIndex: index,
optionValue: this.items[index].innerText
}
}));
}
this._observeMutations();
}));
}
}, {
key: "unselect",
value: function unselect(index) {
this._unobserveMutations();
if (_indexInBounds(index, this.items.length)) {
this.items[index].setAttribute('aria-selected', 'false');
if (this._options.useAriaChecked === true) {
this.items[index].setAttribute('aria-checked', 'false');
}
this._observeMutations();
}
unselect(index) {
this._unobserveMutations();
if (_indexInBounds(index, this.items.length)) {
var matchingItem = this.items[index];
matchingItem.setAttribute('aria-selected', 'false');
if (this._options.useAriaChecked === true) {
matchingItem.setAttribute('aria-checked', 'false');
}
this._observeMutations();
}
}, {
key: "destroy",
value: function destroy() {
this._destroyed = true;
this._unobserveMutations();
this._unobserveEvents();
this._onFocusListener = null;
this._onMouseDownListener = null;
this._onKeyDownListener = null;
this._onClickListener = null;
this._onActiveDescendantChangeListener = null;
this._onMutationListener = null;
}
}]);
return _default;
}();
/*
* For listbox with auto select, the first keyboard focus should set selection to first option
*/
exports.default = _default;
function _onFocus() {
this._unobserveMutations();
if (this._mouseDownFlag !== true && this._options.autoSelect === true && this.index === -1) {
this._activeDescendant.index = 0;
this.items[0].setAttribute('aria-selected', 'true');
if (this._options.useAriaChecked === true) {
this.items[0].setAttribute('aria-checked', 'true');
}
this._observeMutations();
}
this._mouseDownFlag = false;
this._observeMutations();
destroy() {
this._destroyed = true;
this._unobserveMutations();
this._unobserveEvents();
this._onKeyDownListener = null;
this._onClickListener = null;
this._onActiveDescendantChangeListener = null;
this._onMutationListener = null;
}
}
/*
* This flag is used to help us detect if first focus comes from keyboard or as a result of mouse _onClick
*/
function _onMouseDown() {
this._mouseDownFlag = true;
}
exports.default = _default;
function _onKeyDown(e) {
if (e.keyCode === 13 || e.keyCode === 32) {
// enter key or spacebar key
var toElIndex = this._activeDescendant.index;
var toEl = this.items[toElIndex];
var isTolElSelected = toEl.getAttribute('aria-selected') === 'true';
if (this._options.autoSelect === false && isTolElSelected === false) {
this.unselect(this.index);
this.select(toElIndex);
}
var 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
this.unselect(this.index);
this.select(this._activeDescendant.index);
}
}
function _onClick(e) {
// unlike the keyDown event, the click event target can be a child element of the option
// e.g. <div role="option"><span>Item 1</span></div>
var toEl = e.target.closest('[role=option]');
var toElIndex = toEl.dataset.makeupIndex;
var toElIndex = this.items.indexOf(toEl);
var isTolElSelected = toEl.getAttribute('aria-selected') === 'true';
if (this._options.autoSelect === false && isTolElSelected === false) {
// todo: this.select() should take care of unselecting any existing selections
this.unselect(this.index);

@@ -274,47 +170,32 @@ this.select(toElIndex);

}
function _onActiveDescendantChange(e) {
this.el.dispatchEvent(new CustomEvent('makeup-listbox-active-descendant-change', {
detail: e.detail
}));
var {
fromIndex,
toIndex
} = e.detail;
if (this._options.autoSelect === true) {
var fromEl = this.items[e.detail.fromIndex];
var toEl = this.items[e.detail.toIndex];
var fromEl = this.items[fromIndex];
var toEl = this.items[toIndex];
if (fromEl) {
this.unselect(e.detail.fromIndex);
// todo: this.select() should take care of unselecting any existing selections
this.unselect(fromIndex);
}
if (toEl) {
this.select(e.detail.toIndex);
this.select(toIndex);
}
}
}
function _onMutation(mutationsList) {
var _iterator = _createForOfIteratorHelper(mutationsList),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var mutation = _step.value;
if (mutation.type === 'attributes') {
this.el.dispatchEvent(new CustomEvent('makeup-listbox-mutation', {
detail: {
attributeName: mutation.attributeName
}
}));
}
for (var mutation of mutationsList) {
if (mutation.type === 'attributes') {
this.el.dispatchEvent(new CustomEvent('makeup-listbox-mutation', {
detail: {
attributeName: mutation.attributeName
}
}));
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
function _indexInBounds(index, size) {
return index > -1 && index < size;
}

@@ -5,3 +5,4 @@ import * as ActiveDescendant from "makeup-active-descendant";

activeDescendantClassName: "listbox__option--active",
autoReset: null,
autoInit: "ariaSelectedOrInteractive",
autoReset: "ariaSelectedOrInteractive",
autoSelect: true,

@@ -14,2 +15,5 @@ customElementMode: false,

};
function isSpacebarOrEnter(keyCode) {
return keyCode === 13 || keyCode === 32;
}
class src_default {

@@ -28,12 +32,3 @@ constructor(widgetEl, selectedOptions) {

}
this._activeDescendant = ActiveDescendant.createLinear(this._activeDescendantRootEl, this._options.focusableElement || this._listboxEl, this._listboxEl, "[role=option]", {
activeDescendantClassName: this._options.activeDescendantClassName,
autoInit: this.index,
autoReset: this._options.autoReset,
axis: "y",
ignoreButtons: true
});
PreventScrollKeys.add(this.el);
this._onFocusListener = _onFocus.bind(this);
this._onMouseDownListener = _onMouseDown.bind(this);
this._onKeyDownListener = _onKeyDown.bind(this);

@@ -49,2 +44,14 @@ this._onClickListener = _onClick.bind(this);

}
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"
}
);
}

@@ -68,5 +75,6 @@ _observeMutations() {

if (this._destroyed !== true) {
this._listboxEl.addEventListener("focus", this._onFocusListener);
this._listboxEl.addEventListener("mousedown", this._onMouseDownListener);
this._activeDescendantRootEl.addEventListener("activeDescendantChange", this._onActiveDescendantChangeListener);
this._activeDescendantRootEl.addEventListener(
"activeDescendantChange",
this._onActiveDescendantChangeListener
);
this._listboxEl.addEventListener("keydown", this._onKeyDownListener);

@@ -77,13 +85,14 @@ this._listboxEl.addEventListener("click", this._onClickListener);

_unobserveEvents() {
this._listboxEl.removeEventListener("focus", this._onFocusListener);
this._listboxEl.removeEventListener("mousedown", this._onMouseDownListener);
this._listboxEl.removeEventListener("keydown", this._onKeyDownListener);
this._listboxEl.removeEventListener("click", this._onClickListener);
this._activeDescendantRootEl.removeEventListener("activeDescendantChange", this._onActiveDescendantChangeListener);
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");
}
get items() {
return this._listboxEl.querySelectorAll("[role=option]");
return this._activeDescendant.items;
}

@@ -93,5 +102,6 @@ select(index) {

if (_indexInBounds(index, this.items.length)) {
this.items[index].setAttribute("aria-selected", "true");
const matchingItem = this.items[index];
matchingItem.setAttribute("aria-selected", "true");
if (this._options.useAriaChecked === true) {
this.items[index].setAttribute("aria-checked", "true");
matchingItem.setAttribute("aria-checked", "true");
}

@@ -101,3 +111,3 @@ this.el.dispatchEvent(new CustomEvent("makeup-listbox-change", {

optionIndex: index,
optionValue: this.items[index].innerText
optionValue: matchingItem.innerText
}

@@ -111,5 +121,6 @@ }));

if (_indexInBounds(index, this.items.length)) {
this.items[index].setAttribute("aria-selected", "false");
const matchingItem = this.items[index];
matchingItem.setAttribute("aria-selected", "false");
if (this._options.useAriaChecked === true) {
this.items[index].setAttribute("aria-checked", "false");
matchingItem.setAttribute("aria-checked", "false");
}

@@ -123,4 +134,2 @@ }

this._unobserveEvents();
this._onFocusListener = null;
this._onMouseDownListener = null;
this._onKeyDownListener = null;

@@ -132,26 +141,7 @@ this._onClickListener = null;

}
function _onFocus() {
this._unobserveMutations();
if (this._mouseDownFlag !== true && this._options.autoSelect === true && this.index === -1) {
this._activeDescendant.index = 0;
this.items[0].setAttribute("aria-selected", "true");
if (this._options.useAriaChecked === true) {
this.items[0].setAttribute("aria-checked", "true");
}
}
this._mouseDownFlag = false;
this._observeMutations();
}
function _onMouseDown() {
this._mouseDownFlag = true;
}
function _onKeyDown(e) {
if (e.keyCode === 13 || e.keyCode === 32) {
const toElIndex = this._activeDescendant.index;
const toEl = this.items[toElIndex];
const isTolElSelected = toEl.getAttribute("aria-selected") === "true";
if (this._options.autoSelect === false && isTolElSelected === false) {
this.unselect(this.index);
this.select(toElIndex);
}
const activeDescendantEl = this._activeDescendant.currentItem;
if (isSpacebarOrEnter(e.keyCode) && activeDescendantEl?.getAttribute("aria-selected") !== "true") {
this.unselect(this.index);
this.select(this._activeDescendant.index);
}

@@ -161,3 +151,3 @@ }

const toEl = e.target.closest("[role=option]");
const toElIndex = toEl.dataset.makeupIndex;
const toElIndex = this.items.indexOf(toEl);
const isTolElSelected = toEl.getAttribute("aria-selected") === "true";

@@ -170,13 +160,11 @@ if (this._options.autoSelect === false && isTolElSelected === false) {

function _onActiveDescendantChange(e) {
this.el.dispatchEvent(new CustomEvent("makeup-listbox-active-descendant-change", {
detail: e.detail
}));
const { fromIndex, toIndex } = e.detail;
if (this._options.autoSelect === true) {
const fromEl = this.items[e.detail.fromIndex];
const toEl = this.items[e.detail.toIndex];
const fromEl = this.items[fromIndex];
const toEl = this.items[toIndex];
if (fromEl) {
this.unselect(e.detail.fromIndex);
this.unselect(fromIndex);
}
if (toEl) {
this.select(e.detail.toIndex);
this.select(toIndex);
}

@@ -183,0 +171,0 @@ }

{
"name": "makeup-listbox",
"description": "A JavaScript class representing an ARIA listbox",
"version": "0.2.1",
"version": "0.3.0",
"main": "./dist/cjs/index.js",

@@ -24,3 +24,3 @@ "module": "./dist/mjs/index.js",

"makeup-prevent-scroll-keys": "~0.2.0",
"makeup-active-descendant": "~0.5.1"
"makeup-active-descendant": "~0.6.0"
},

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

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