@patternfly/pfe-core 5.0.5 → 5.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/controllers/activedescendant-controller.d.ts +8 -1
- package/controllers/activedescendant-controller.js +32 -1
- package/controllers/activedescendant-controller.js.map +1 -1
- package/controllers/at-focus-controller.d.ts +6 -3
- package/controllers/at-focus-controller.js +56 -32
- package/controllers/at-focus-controller.js.map +1 -1
- package/controllers/combobox-controller.d.ts +3 -3
- package/controllers/combobox-controller.js +34 -7
- package/controllers/combobox-controller.js.map +1 -1
- package/controllers/internals-controller.d.ts +30 -11
- package/controllers/internals-controller.js +57 -11
- package/controllers/internals-controller.js.map +1 -1
- package/controllers/listbox-controller.d.ts +6 -3
- package/controllers/listbox-controller.js +23 -13
- package/controllers/listbox-controller.js.map +1 -1
- package/controllers/logger.js +1 -1
- package/controllers/logger.js.map +1 -1
- package/controllers/roving-tabindex-controller.js +15 -0
- package/controllers/roving-tabindex-controller.js.map +1 -1
- package/controllers/test/at-focus-controller.spec.d.ts +1 -0
- package/controllers/test/at-focus-controller.spec.js +214 -0
- package/controllers/test/at-focus-controller.spec.js.map +1 -0
- package/custom-elements.json +118 -22
- package/functions/arraysAreEquivalent.js +2 -7
- package/functions/arraysAreEquivalent.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listbox-controller.js","sourceRoot":"","sources":["listbox-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport type { RequireProps } from '../core.ts';\n\nimport { isServer } from 'lit';\nimport { arraysAreEquivalent } from '../functions/arraysAreEquivalent.js';\n\n/**\n * Options for listbox controller\n */\nexport interface ListboxControllerOptions<Item extends HTMLElement> {\n /**\n * Whether the listbox supports multiple selections.\n */\n multi?: boolean;\n /**\n * Optional callback to control the selection behavior of items. By default, ListboxController\n * will set the `aria-selected` attribute. When overriding this option, it will call it on your\n * element with the selected state.\n * Callers **must** ensure that the correct ARIA state is set.\n */\n setItemSelected?(item: Item, selected: boolean): void;\n /**\n * Optional predicate to ascertain whether a custom element item is disabled or not\n * By default, if the item matches any of these conditions, it is considered disabled:\n * 1. it's `disabled` DOM property is `true`\n * 1. it has the `aria-disabled=\"true\"` attribute\n * 2. it has the `disabled` attribute present\n * 3. it matches the `:disabled` pseudo selector\n */\n isItemDisabled?(item: Item): boolean;\n /**\n * Predicate which determines if a given element is in fact an item\n * instead of e.g a presentational divider. By default, elements must meet the following criteria\n * 1. element a child of a listbox role,\n * 2. element does not have role=\"presentation\"\n * 2. element is not an `<hr>`\n * **NB**: When overriding, you must avoid outside references. This predicate must\n * only consider the element itself, without reference to the host element's items array.\n * @example ```js\n * isItem: (item) => item instanceof MyCustomItem\n * ```\n */\n isItem?(item: EventTarget | null): item is Item;\n /**\n * Function returning the item which currently has assistive technology focus.\n * In most cases, this should be the `atFocusedItem` of an ATFocusController\n * i.e. RovingTabindexController or ActivedescendantController.\n *\n */\n getATFocusedItem(): Item | null;\n /**\n * Function returning the DOM node which is the direct parent of the item elements\n * Defaults to the controller host.\n * If the controller host is not an HTMLElement, this *must* be set\n */\n getItemsContainer?(): HTMLElement | null;\n /**\n * Optional function returning an additional DOM node which controls the listbox, e.g.\n * a combobox input.\n */\n getControlsElements?(): HTMLElement[];\n}\n\n/**\n * This is the default method for setting the selected state on an item element\n * @param item the item\n * @param selected is this item selected\n */\nfunction setItemSelected<Item extends HTMLElement>(item: Item, selected: boolean) {\n if (selected) {\n item.setAttribute('aria-selected', 'true');\n } else {\n item.removeAttribute('aria-selected');\n }\n}\n\n/**\n * @param item possible disabled item\n * @package do not import this outside of `@patternfly/pfe-core`, it is subject to change at any time\n */\nexport function isItem<Item extends HTMLElement>(item: EventTarget | null): item is Item {\n return item instanceof Element\n && item?.parentElement?.role === 'listbox'\n && item?.role !== 'presentation'\n && item?.localName !== 'hr';\n}\n\n/**\n * This is a fib. aria-disabled might not be present on an element that uses internals,\n * and the `disabled` attribute may not accurately represent the disabled state.\n * short of patching the `attachInternals` constructor, it may not be possible at\n * runtime to know with certainty that an arbitrary custom element is disabled or not.\n * @param item possibly disabled item\n * @package do not import this outside of `@patternfly/pfe-core`, it is subject to change at any time\n */\nexport function isItemDisabled<Item extends HTMLElement>(item: Item): boolean {\n return ('disabled' in item && typeof item.disabled === 'boolean' && item.disabled)\n || item.getAttribute('aria-disabled') === 'true'\n || item.hasAttribute('disabled')\n || item.hasAttribute('inert')\n || item.matches(':disabled');\n}\n\nlet constructingAllowed = false;\n\n/**\n * Implements listbox semantics and accesibility. As there are two recognized\n * patterns for implementing keyboard interactions with listbox patterns,\n * provide a secondary controller (either RovingTabindexController or\n * ActiveDescendantController) to complete the implementation.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_focus_vs_selection\n *\n * > Occasionally, it may appear as if two elements on the page have focus at the same time.\n * > For example, in a multi-select list box, when an option is selected it may be greyed.\n * > Yet, the focus indicator can still be moved to other options, which may also be selected.\n * > Similarly, when a user activates a tab in a tablist, the selected state is set on the tab\n * > and its visual appearance changes. However, the user can still navigate, moving the focus\n * > indicator elsewhere on the page while the tab retains its selected appearance and state.\n * >\n * > Focus and selection are quite different. From the keyboard user's perspective,\n * > focus is a pointer, like a mouse pointer; it tracks the path of navigation.\n * > There is only one point of focus at any time and all operations take place at the\n * > point of focus. On the other hand, selection is an operation that can be performed in\n * > some widgets, such as list boxes, trees, and tablists. If a widget supports only single\n * > selection, then only one item can be selected and very often the selected state will simply\n * > follow the focus when focus is moved inside of the widget.\n * > That is, in some widgets, moving focus may also perform the select operation.\n * > However, if the widget supports multiple selection, then more than one item can be in a\n * > selected state, and keys for moving focus do not perform selection. Some multi-select widgets\n * > do support key commands that both move focus and change selection, but those keys are\n * > different from the normal navigation keys. Finally, when focus leaves a widget that includes\n * > a selected element, the selected state persists.\n * >\n * > From the developer's perspective, the difference is simple -- the focused element is the\n * > active element (document.activeElement). Selected elements are elements that have\n * > aria-selected=\"true\".\n * >\n * > With respect to focus and the selected state, the most important considerations for designers\n * > and developers are:\n * >\n * > - The visual focus indicator must always be visible.\n * > - The selected state must be visually distinct from the focus indicator.\n */\nexport class ListboxController<Item extends HTMLElement> implements ReactiveController {\n private static instances = new WeakMap<ReactiveControllerHost, ListboxController<HTMLElement>>();\n\n public static of<Item extends HTMLElement>(\n host: ReactiveControllerHost,\n options: ListboxControllerOptions<Item>,\n ): ListboxController<Item> {\n constructingAllowed = true;\n const instance = new ListboxController<Item>(host, options);\n constructingAllowed = false;\n return instance as ListboxController<Item>;\n }\n\n /** Current active descendant when shift key is pressed */\n #shiftStartingItem: Item | null = null;\n\n #options: RequireProps<ListboxControllerOptions<Item>,\n | 'setItemSelected'\n | 'isItemDisabled'\n | 'isItem'\n >;\n\n /** All items */\n #items: Item[] = [];\n\n #selectedItems = new Set<Item>;\n\n #listening = false;\n\n /** Whether listbox is disabled */\n disabled = false;\n\n get container(): HTMLElement {\n return this.#options.getItemsContainer?.() ?? this.host as unknown as HTMLElement;\n }\n\n get multi(): boolean {\n return !!this.#options.multi;\n }\n\n set multi(v: boolean) {\n this.#options.multi = v;\n this.host.requestUpdate();\n }\n\n get items(): Item[] {\n return this.#items;\n }\n\n /**\n * register's the host's Item elements as listbox controller items\n * sets aria-setsize and aria-posinset on items\n * @param items items\n */\n set items(items: Item[]) {\n this.#items = items;\n this.#items.forEach((item, index, _items) => {\n item.ariaSetSize = _items.length.toString();\n item.ariaPosInSet = (index + 1).toString();\n });\n }\n\n /**\n * sets the listbox value based on selected options\n * @param selected item or items\n */\n set selected(selected: Item[]) {\n if (!arraysAreEquivalent(selected, Array.from(this.#selectedItems))) {\n this.#selectedItems = new Set(selected);\n for (const item of this.items) {\n this.#options.setItemSelected(item, this.#selectedItems.has(item));\n }\n this.host.requestUpdate();\n }\n }\n\n /**\n * array of options which are selected\n */\n get selected(): Item[] {\n return [...this.#selectedItems];\n }\n\n private constructor(\n public host: ReactiveControllerHost,\n options: ListboxControllerOptions<Item>,\n ) {\n this.#options = { setItemSelected, isItemDisabled, isItem, ...options };\n if (!constructingAllowed) {\n throw new Error('ListboxController must be constructed with `ListboxController.of()`');\n }\n if (!isServer\n && !(host instanceof HTMLElement)\n && typeof options.getItemsContainer !== 'function') {\n throw new Error([\n 'ListboxController requires the host to be an HTMLElement',\n 'or for the initializer to include a getItemsContainer() function',\n ].join(' '));\n }\n const instance = ListboxController.instances.get(host) as unknown as ListboxController<Item>;\n if (instance) {\n return instance as ListboxController<Item>;\n }\n ListboxController.instances.set(host, this as unknown as ListboxController<HTMLElement>);\n this.host.addController(this);\n this.multi = this.#options.multi ?? false;\n if (this.container?.isConnected) {\n this.hostConnected();\n }\n }\n\n async hostConnected(): Promise<void> {\n await this.host.updateComplete;\n this.hostUpdate();\n this.hostUpdated();\n }\n\n #controlsElements: HTMLElement[] = [];\n\n #removeControlsListeners(els = this.#controlsElements) {\n for (const el of els) {\n el.removeEventListener('keydown', this.#onKeydown);\n el.removeEventListener('keyup', this.#onKeyup);\n }\n }\n\n hostUpdate(): void {\n const last = this.#controlsElements;\n this.#controlsElements = this.#options.getControlsElements?.() ?? [];\n if (!arraysAreEquivalent(last, this.#controlsElements)) {\n this.#removeControlsListeners(last);\n for (const el of this.#controlsElements) {\n el.addEventListener('keydown', this.#onKeydown);\n el.addEventListener('keyup', this.#onKeyup);\n }\n }\n }\n\n hostUpdated(): void {\n if (!this.#listening) {\n this.container?.addEventListener('click', this.#onClick);\n this.container?.addEventListener('keydown', this.#onKeydown);\n this.container?.addEventListener('keyup', this.#onKeyup);\n this.#listening = true;\n }\n this.container?.setAttribute('role', 'listbox');\n this.container?.setAttribute('aria-disabled', String(!!this.disabled));\n this.container?.setAttribute('aria-multiselectable', String(!!this.#options.multi));\n }\n\n hostDisconnected(): void {\n this.container?.removeEventListener('click', this.#onClick);\n this.container?.removeEventListener('keydown', this.#onKeydown);\n this.container?.removeEventListener('keyup', this.#onKeyup);\n this.#removeControlsListeners();\n this.#listening = false;\n }\n\n public isSelected(item: Item): boolean {\n return this.#selectedItems.has(item);\n }\n\n get #isExpanded() {\n return !this.#controlsElements.length ? true\n : this.#controlsElements.every(x => x.ariaExpanded === 'true');\n }\n\n /**\n * In the case where aria IDL attributes are not supported,\n * we need to correlate the item in the event path (i.e. the shadow dom clone)\n * with the item in listbox controller's root (i.e. the hidden light dom original)\n * XXX: as long as there is no DOM preceeding the shadow root clones, this will work\n * @param event click or keyboard event\n */\n #getItemFromEvent(event: Event): Item | null {\n // NOTE(bennypowers): I am aware that this function *sucks*\n // you're more than welcome to improve it.\n // make sure there are unit tests first\n const path = event.composedPath();\n const tabindexed = this.items.some(x => x.hasAttribute('tabindex'));\n if (tabindexed) {\n const item = path.find(this.#options.isItem);\n if (item) {\n return item;\n }\n } else if (this.#options.isItem(event.target)\n && event.target.getRootNode() !== this.container.getRootNode()\n && 'ariaActiveDescendantElement' in HTMLElement.prototype) {\n return event.target;\n } else if (event.target instanceof HTMLElement && event.target.ariaActiveDescendantElement) {\n return event.target.ariaActiveDescendantElement as Item;\n } else if (event.type === 'click'\n && this.#options.isItem(event.target)\n && event.target.id) {\n const element = event.target;\n const root = element.getRootNode();\n if (root instanceof ShadowRoot && this.container.getRootNode() === root) {\n const shadowRootListboxElement = this.container;\n const shadowRootItem = element;\n if (shadowRootItem && shadowRootListboxElement) {\n if (this.items.includes(shadowRootItem)) {\n return shadowRootItem;\n } else {\n const index =\n Array.from(shadowRootListboxElement?.children ?? [])\n .filter(this.#options.isItem)\n .filter(x => !x.hidden)\n .indexOf(shadowRootItem);\n return this.#items.filter(x => !x.hidden)[index];\n }\n }\n }\n } else {\n // otherwise, query the root (e.g. shadow root) for the associated element\n const element = event.target as HTMLElement;\n\n const root = element.getRootNode() as ShadowRoot | Document;\n\n const controlsId = element?.getAttribute('aria-controls');\n const shadowRootListboxElement =\n this.#options.isItem(element) ? this.container\n : controlsId ? root.getElementById(controlsId)\n : null;\n\n const shadowRootHasActiveDescendantElement =\n root.querySelector(`[aria-controls=\"${shadowRootListboxElement?.id}\"][aria-activedescendant]`);\n\n const shadowRootItemId =\n shadowRootHasActiveDescendantElement?.getAttribute('aria-activedescendant');\n\n const shadowRootItem =\n shadowRootItemId && root.getElementById(shadowRootItemId) as Item | null;\n\n if (shadowRootItem && shadowRootListboxElement) {\n if (this.items.includes(shadowRootItem)) {\n return shadowRootItem;\n } else {\n const index =\n Array.from(shadowRootListboxElement?.children ?? [])\n .filter(this.#options.isItem)\n .filter(x => !x.hidden)\n .indexOf(shadowRootItem);\n return this.#items.filter(x => !x.hidden)[index];\n }\n }\n\n const itemFromEventContainer =\n shadowRootListboxElement ? shadowRootListboxElement\n : path.find(x =>\n x instanceof HTMLElement && x.role === 'listbox') as HTMLElement;\n\n if (itemFromEventContainer) {\n const possiblyShadowRootContainerItems = Array.from(itemFromEventContainer.children)\n .filter(this.#options.isItem);\n\n const index = possiblyShadowRootContainerItems\n .findIndex(node => path.includes(node));\n\n if (index >= 0) {\n return this.items[index] ?? null;\n }\n }\n }\n\n return null;\n }\n\n /**\n * handles clicking on a listbox option:\n * which selects an item by default\n * or toggles selection if multiselectable\n * @param event click event\n */\n #onClick = (event: MouseEvent) => {\n const item = this.#getItemFromEvent(event);\n this.#shiftStartingItem ??= this.#getItemFromEvent(event);\n if (item && !this.#options.isItemDisabled(item)) {\n // Case: single select?\n // just reset the selected list.\n if (!this.multi) {\n // select target and deselect all other options\n this.selected = [item];\n // Case: multi select, but no shift key\n // toggle target, keep all other previously selected\n } else if (!event.shiftKey) {\n this.selected = this.items.filter(possiblySelectedItem =>\n this.#selectedItems.has(possiblySelectedItem) ? possiblySelectedItem !== item\n : possiblySelectedItem === item);\n // Case: multi select, with shift key\n // find all items between previously selected and target,\n // and select them (if reference item is selected) or deselect them (if reference item is deselected)\n // Do not wrap around from end to start, rather, only select withing the range of 0-end\n } else {\n const startingItem = this.#shiftStartingItem!;\n // whether options will be selected (true) or deselected (false)\n const selecting = this.#selectedItems.has(startingItem);\n const [start, end] = [this.items.indexOf(startingItem), this.items.indexOf(item)].sort();\n // de/select all options between active descendant and target\n this.selected = this.items.filter((item, i) => {\n if (i >= start && i <= end) {\n return selecting;\n } else {\n return this.#selectedItems.has(item);\n }\n });\n }\n }\n this.#shiftStartingItem = item;\n this.host.requestUpdate();\n };\n\n /**\n * track whether shift key is being used for multiselectable listbox\n * @param event keyup event\n */\n #onKeyup = (event: KeyboardEvent) => {\n if (event.key === 'Shift') {\n this.#shiftStartingItem = null;\n }\n };\n\n /**\n * filters listbox by keyboard event when slotted option has focus,\n * or by external element such as a text field\n * @param event keydown event\n */\n #onKeydown = (event: KeyboardEvent) => {\n const item = this.#getItemFromEvent(event);\n\n if (this.disabled\n || event.altKey\n || event.metaKey\n || !this.#isExpanded) {\n return;\n }\n\n // need to set for keyboard support of multiselect\n if (event.key === 'Shift' && this.multi) {\n this.#shiftStartingItem ??= this.#options.getATFocusedItem() ?? null;\n }\n\n switch (event.key) {\n // ctrl+A de/selects all options\n case 'a':\n case 'A':\n if (event.ctrlKey\n && (event.target === this.container\n || this.#options.isItem(event.target))) {\n const selectableItems = this.items.filter(item => !this.#options.isItemDisabled(item));\n if (arraysAreEquivalent(this.selected, selectableItems)) {\n this.selected = [];\n } else {\n this.selected = selectableItems;\n }\n event.preventDefault();\n }\n break;\n case 'Enter':\n // enter and space are only applicable if a listbox option is clicked\n // an external text input should not trigger multiselect\n if (item && !event.shiftKey) {\n const focused = item;\n this.#selectItem(focused, event.shiftKey);\n event.preventDefault();\n }\n break;\n case 'ArrowUp':\n if (this.multi && event.shiftKey && this.#options.isItem(event.target)) {\n const item = event.target;\n this.selected = this.items.filter((x, i) =>\n this.#selectedItems.has(x)\n || i === this.items.indexOf(item) - 1)\n .filter(x => !this.#options.isItemDisabled(x));\n }\n break;\n case 'ArrowDown':\n if (this.multi && event.shiftKey && this.#options.isItem(event.target)) {\n const item = event.target;\n this.selected = this.items.filter((x, i) =>\n this.#selectedItems.has(x)\n || i === this.items.indexOf(item) + 1)\n .filter(x => !this.#options.isItemDisabled(x));\n }\n break;\n case ' ':\n // enter and space are only applicable if a listbox option is clicked\n // an external text input should not trigger multiselect\n if (item && event.target === this.container) {\n this.#selectItem(item, event.shiftKey);\n event.preventDefault();\n } else if (this.#options.isItem(event.target)) {\n this.#selectItem(event.target, event.shiftKey);\n event.preventDefault();\n }\n break;\n default:\n break;\n }\n this.host.requestUpdate();\n };\n\n #selectItem(item: Item, shiftDown = false) {\n if (this.#options.isItemDisabled(item)) {\n return;\n } else if (this.multi && shiftDown) {\n // update starting item for other multiselect\n this.selected = [...this.selected, item];\n } else if (this.multi && this.#selectedItems.has(item)) {\n this.selected = this.selected.filter(x => x !== item);\n } else if (this.multi) {\n this.selected = this.selected.concat(item);\n } else {\n this.selected = [item];\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"listbox-controller.js","sourceRoot":"","sources":["listbox-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport type { RequireProps } from '../core.ts';\n\nimport { isServer } from 'lit';\nimport { arraysAreEquivalent } from '../functions/arraysAreEquivalent.js';\nimport { InternalsController } from './internals-controller.js';\n\n/**\n * Options for listbox controller\n */\nexport interface ListboxControllerOptions<Item extends HTMLElement> {\n /**\n * Whether the listbox supports multiple selections.\n */\n multi?: boolean;\n /**\n * Optional callback to control the selection behavior of items. By default, ListboxController\n * will set the `aria-selected` attribute. When overriding this option, it will call it on your\n * element with the selected state.\n * Callers **must** ensure that the correct ARIA state is set.\n */\n setItemSelected?(item: Item, selected: boolean): void;\n /**\n * Optional predicate to ascertain whether a custom element item is disabled or not\n * By default, if the item matches any of these conditions, it is considered disabled:\n * 1. it's `disabled` DOM property is `true`\n * 1. it has the `aria-disabled=\"true\"` attribute\n * 2. it has the `disabled` attribute present\n * 3. it matches the `:disabled` pseudo selector\n */\n isItemDisabled?(item: Item): boolean;\n /**\n * Predicate which determines if a given element is in fact an item\n * instead of e.g a presentational divider. By default, elements must meet the following criteria\n * 1. element a child of a listbox role,\n * 2. element does not have role=\"presentation\"\n * 2. element is not an `<hr>`\n * **NB**: When overriding, you must avoid outside references. This predicate must\n * only consider the element itself, without reference to the host element's items array.\n * @example ```js\n * isItem: (item) => item instanceof MyCustomItem\n * ```\n */\n isItem?(item: EventTarget | null): item is Item;\n /**\n * Function returning the item which currently has assistive technology focus.\n * In most cases, this should be the `atFocusedItem` of an ATFocusController\n * i.e. RovingTabindexController or ActivedescendantController.\n *\n */\n getATFocusedItem(): Item | null;\n /**\n * Function returning the DOM node which is the direct parent of the item elements\n * Defaults to the controller host.\n * If the controller host is not an HTMLElement, this *must* be set\n */\n getItemsContainer?(): HTMLElement | null;\n /**\n * Optional function returning an additional DOM node which controls the listbox, e.g.\n * a combobox input.\n */\n getControlsElements?(): HTMLElement[];\n}\n\n/**\n * This is the default method for setting the selected state on an item element\n * @param item the item\n * @param selected is this item selected\n */\nfunction setItemSelected<Item extends HTMLElement>(item: Item, selected: boolean) {\n if (selected) {\n item.setAttribute('aria-selected', 'true');\n } else {\n item.removeAttribute('aria-selected');\n }\n}\n\n/**\n * @param item possible disabled item\n * @package do not import this outside of `@patternfly/pfe-core`, it is subject to change at any time\n */\nexport function isItem<Item extends HTMLElement>(item: EventTarget | null): item is Item {\n return item instanceof Element\n && item?.parentElement?.role === 'listbox'\n && item?.role !== 'presentation'\n && item?.localName !== 'hr';\n}\n\n/**\n * This is a fib. aria-disabled might not be present on an element that uses internals,\n * and the `disabled` attribute may not accurately represent the disabled state.\n * short of patching the `attachInternals` constructor, it may not be possible at\n * runtime to know with certainty that an arbitrary custom element is disabled or not.\n * @param item possibly disabled item\n * @package do not import this outside of `@patternfly/pfe-core`, it is subject to change at any time\n */\nexport function isItemDisabled<Item extends HTMLElement>(item: Item): boolean {\n return ('disabled' in item && typeof item.disabled === 'boolean' && item.disabled)\n || item.getAttribute('aria-disabled') === 'true'\n || item.hasAttribute('disabled')\n || item.hasAttribute('inert')\n || item.matches(':disabled');\n}\n\nlet constructingAllowed = false;\n\n/**\n * Implements listbox semantics and accesibility. As there are two recognized\n * patterns for implementing keyboard interactions with listbox patterns,\n * provide a secondary controller (either RovingTabindexController or\n * ActiveDescendantController) to complete the implementation.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_focus_vs_selection\n *\n * > Occasionally, it may appear as if two elements on the page have focus at the same time.\n * > For example, in a multi-select list box, when an option is selected it may be greyed.\n * > Yet, the focus indicator can still be moved to other options, which may also be selected.\n * > Similarly, when a user activates a tab in a tablist, the selected state is set on the tab\n * > and its visual appearance changes. However, the user can still navigate, moving the focus\n * > indicator elsewhere on the page while the tab retains its selected appearance and state.\n * >\n * > Focus and selection are quite different. From the keyboard user's perspective,\n * > focus is a pointer, like a mouse pointer; it tracks the path of navigation.\n * > There is only one point of focus at any time and all operations take place at the\n * > point of focus. On the other hand, selection is an operation that can be performed in\n * > some widgets, such as list boxes, trees, and tablists. If a widget supports only single\n * > selection, then only one item can be selected and very often the selected state will simply\n * > follow the focus when focus is moved inside of the widget.\n * > That is, in some widgets, moving focus may also perform the select operation.\n * > However, if the widget supports multiple selection, then more than one item can be in a\n * > selected state, and keys for moving focus do not perform selection. Some multi-select widgets\n * > do support key commands that both move focus and change selection, but those keys are\n * > different from the normal navigation keys. Finally, when focus leaves a widget that includes\n * > a selected element, the selected state persists.\n * >\n * > From the developer's perspective, the difference is simple -- the focused element is the\n * > active element (document.activeElement). Selected elements are elements that have\n * > aria-selected=\"true\".\n * >\n * > With respect to focus and the selected state, the most important considerations for designers\n * > and developers are:\n * >\n * > - The visual focus indicator must always be visible.\n * > - The selected state must be visually distinct from the focus indicator.\n */\nexport class ListboxController<Item extends HTMLElement> implements ReactiveController {\n private static instances = new WeakMap<ReactiveControllerHost, ListboxController<HTMLElement>>();\n\n public static of<Item extends HTMLElement>(\n host: ReactiveControllerHost,\n options: ListboxControllerOptions<Item>,\n ): ListboxController<Item> {\n constructingAllowed = true;\n const instance = new ListboxController<Item>(host, options);\n constructingAllowed = false;\n return instance as ListboxController<Item>;\n }\n\n /** Current active descendant when shift key is pressed */\n #shiftStartingItem: Item | null = null;\n\n #options: RequireProps<ListboxControllerOptions<Item>,\n | 'setItemSelected'\n | 'isItemDisabled'\n | 'isItem'\n >;\n\n /** All items */\n #items: Item[] = [];\n\n #selectedItems = new Set<Item>;\n\n #listening = false;\n\n /** Whether listbox is disabled */\n disabled = false;\n\n get container(): HTMLElement {\n return this.#options.getItemsContainer?.() ?? this.host as unknown as HTMLElement;\n }\n\n get multi(): boolean {\n return !!this.#options.multi;\n }\n\n set multi(v: boolean) {\n this.#options.multi = v;\n this.host.requestUpdate();\n }\n\n get items(): Item[] {\n return this.#items;\n }\n\n /**\n * Registers the host's item elements as listbox controller items.\n * @param items - Array of listbox option elements.\n */\n set items(items: Item[]) {\n if (!arraysAreEquivalent(items, this.#items)) {\n this.#items = items;\n this.host.requestUpdate();\n }\n }\n\n /**\n * sets the listbox value based on selected options\n * @param selected item or items\n */\n set selected(selected: Item[]) {\n if (!arraysAreEquivalent(selected, Array.from(this.#selectedItems))) {\n this.#selectedItems = new Set(selected);\n for (const item of this.items) {\n this.#options.setItemSelected(item, this.#selectedItems.has(item));\n }\n this.host.requestUpdate();\n }\n }\n\n /**\n * array of options which are selected\n */\n get selected(): Item[] {\n return [...this.#selectedItems];\n }\n\n private constructor(\n public host: ReactiveControllerHost,\n options: ListboxControllerOptions<Item>,\n ) {\n this.#options = { setItemSelected, isItemDisabled, isItem, ...options };\n if (!constructingAllowed) {\n throw new Error('ListboxController must be constructed with `ListboxController.of()`');\n }\n if (!isServer\n && !(host instanceof HTMLElement)\n && typeof options.getItemsContainer !== 'function') {\n throw new Error([\n 'ListboxController requires the host to be an HTMLElement',\n 'or for the initializer to include a getItemsContainer() function',\n ].join(' '));\n }\n const instance = ListboxController.instances.get(host) as unknown as ListboxController<Item>;\n if (instance) {\n return instance as ListboxController<Item>;\n }\n ListboxController.instances.set(host, this as unknown as ListboxController<HTMLElement>);\n this.host.addController(this);\n this.multi = this.#options.multi ?? false;\n if (this.container?.isConnected) {\n this.hostConnected();\n }\n }\n\n async hostConnected(): Promise<void> {\n await this.host.updateComplete;\n this.hostUpdate();\n this.hostUpdated();\n }\n\n #controlsElements: HTMLElement[] = [];\n\n #removeControlsListeners(els = this.#controlsElements) {\n for (const el of els) {\n el.removeEventListener('keydown', this.#onKeydown);\n el.removeEventListener('keyup', this.#onKeyup);\n }\n }\n\n /**\n * Called during host update; syncs control element listeners and\n * applies aria-posinset/aria-setsize to each item via InternalsController.\n */\n hostUpdate(): void {\n const last = this.#controlsElements;\n this.#controlsElements = this.#options.getControlsElements?.() ?? [];\n if (!arraysAreEquivalent(last, this.#controlsElements)) {\n this.#removeControlsListeners(last);\n for (const el of this.#controlsElements) {\n el.addEventListener('keydown', this.#onKeydown);\n el.addEventListener('keyup', this.#onKeyup);\n }\n }\n const items = this.#items;\n items.forEach((item, index) => {\n InternalsController.setAriaPosInSet(item, index + 1);\n InternalsController.setAriaSetSize(item, items.length);\n });\n }\n\n hostUpdated(): void {\n if (!this.#listening) {\n this.container?.addEventListener('click', this.#onClick);\n this.container?.addEventListener('keydown', this.#onKeydown);\n this.container?.addEventListener('keyup', this.#onKeyup);\n this.#listening = true;\n }\n this.container?.setAttribute('role', 'listbox');\n this.container?.setAttribute('aria-disabled', String(!!this.disabled));\n this.container?.setAttribute('aria-multiselectable', String(!!this.#options.multi));\n }\n\n hostDisconnected(): void {\n this.container?.removeEventListener('click', this.#onClick);\n this.container?.removeEventListener('keydown', this.#onKeydown);\n this.container?.removeEventListener('keyup', this.#onKeyup);\n this.#removeControlsListeners();\n this.#listening = false;\n }\n\n public isSelected(item: Item): boolean {\n return this.#selectedItems.has(item);\n }\n\n get #isExpanded() {\n return !this.#controlsElements.length ? true\n : this.#controlsElements.every(x => x.ariaExpanded === 'true');\n }\n\n /**\n * In the case where aria IDL attributes are not supported,\n * we need to correlate the item in the event path (i.e. the shadow dom clone)\n * with the item in listbox controller's root (i.e. the hidden light dom original)\n * XXX: as long as there is no DOM preceeding the shadow root clones, this will work\n * @param event click or keyboard event\n */\n #getItemFromEvent(event: Event): Item | null {\n // NOTE(bennypowers): I am aware that this function *sucks*\n // you're more than welcome to improve it.\n // make sure there are unit tests first\n const path = event.composedPath();\n const tabindexed = this.items.some(x => x.hasAttribute('tabindex'));\n if (tabindexed) {\n const item = path.find(this.#options.isItem);\n if (item) {\n return item;\n }\n } else if (this.#options.isItem(event.target)\n && event.target.getRootNode() !== this.container.getRootNode()\n && 'ariaActiveDescendantElement' in HTMLElement.prototype) {\n return event.target;\n } else if (event.target instanceof HTMLElement && event.target.ariaActiveDescendantElement) {\n return event.target.ariaActiveDescendantElement as Item;\n } else if (event.type === 'click'\n && this.#options.isItem(event.target)\n && event.target.id) {\n const element = event.target;\n const root = element.getRootNode();\n if (root instanceof ShadowRoot && this.container.getRootNode() === root) {\n const shadowRootListboxElement = this.container;\n const shadowRootItem = element;\n if (shadowRootItem && shadowRootListboxElement) {\n if (this.items.includes(shadowRootItem)) {\n return shadowRootItem;\n } else {\n const index =\n Array.from(shadowRootListboxElement?.children ?? [])\n .filter(this.#options.isItem)\n .filter(x => !x.hidden)\n .indexOf(shadowRootItem);\n return this.#items.filter(x => !x.hidden)[index];\n }\n }\n }\n } else {\n // otherwise, query the root (e.g. shadow root) for the associated element\n const element = event.target as HTMLElement;\n\n const root = element.getRootNode() as ShadowRoot | Document;\n\n const controlsId = element?.getAttribute('aria-controls');\n const shadowRootListboxElement =\n this.#options.isItem(element) ? this.container\n : controlsId ? root.getElementById(controlsId)\n : null;\n\n const shadowRootHasActiveDescendantElement =\n root.querySelector(`[aria-controls=\"${shadowRootListboxElement?.id}\"][aria-activedescendant]`);\n\n const shadowRootItemId =\n shadowRootHasActiveDescendantElement?.getAttribute('aria-activedescendant');\n\n const shadowRootItem =\n shadowRootItemId && root.getElementById(shadowRootItemId) as Item | null;\n\n if (shadowRootItem && shadowRootListboxElement) {\n if (this.items.includes(shadowRootItem)) {\n return shadowRootItem;\n } else {\n // Shadow clone needs to be mapped back to light DOM item.\n // Match by value attribute or text content since index-based matching\n // doesn't work when items are filtered (hidden state differs between clone and source)\n const cloneValue = shadowRootItem.getAttribute('value')\n ?? shadowRootItem.textContent?.trim();\n const sourceItem = this.#items.find(item =>\n (item.getAttribute('value') ?? item.textContent?.trim()) === cloneValue\n );\n return sourceItem ?? null;\n }\n }\n\n const itemFromEventContainer =\n shadowRootListboxElement ? shadowRootListboxElement\n : path.find(x =>\n x instanceof HTMLElement && x.role === 'listbox') as HTMLElement;\n\n if (itemFromEventContainer) {\n const possiblyShadowRootContainerItems = Array.from(itemFromEventContainer.children)\n .filter(this.#options.isItem);\n\n const index = possiblyShadowRootContainerItems\n .findIndex(node => path.includes(node));\n\n if (index >= 0) {\n return this.items[index] ?? null;\n }\n }\n }\n\n return null;\n }\n\n /**\n * handles clicking on a listbox option:\n * which selects an item by default\n * or toggles selection if multiselectable\n * @param event click event\n */\n #onClick = (event: MouseEvent) => {\n const item = this.#getItemFromEvent(event);\n this.#shiftStartingItem ??= this.#getItemFromEvent(event);\n if (item && !this.#options.isItemDisabled(item)) {\n // Case: single select?\n // just reset the selected list.\n if (!this.multi) {\n // select target and deselect all other options\n this.selected = [item];\n // Case: multi select, but no shift key\n // toggle target, keep all other previously selected\n } else if (!event.shiftKey) {\n this.selected = this.items.filter(possiblySelectedItem =>\n this.#selectedItems.has(possiblySelectedItem) ? possiblySelectedItem !== item\n : possiblySelectedItem === item);\n // Case: multi select, with shift key\n // find all items between previously selected and target,\n // and select them (if reference item is selected) or deselect them (if reference item is deselected)\n // Do not wrap around from end to start, rather, only select withing the range of 0-end\n } else {\n const startingItem = this.#shiftStartingItem!;\n // whether options will be selected (true) or deselected (false)\n const selecting = this.#selectedItems.has(startingItem);\n const [start, end] = [this.items.indexOf(startingItem), this.items.indexOf(item)].sort();\n // de/select all options between active descendant and target\n this.selected = this.items.filter((item, i) => {\n if (i >= start && i <= end) {\n return selecting;\n } else {\n return this.#selectedItems.has(item);\n }\n });\n }\n }\n this.#shiftStartingItem = item;\n this.host.requestUpdate();\n };\n\n /**\n * track whether shift key is being used for multiselectable listbox\n * @param event keyup event\n */\n #onKeyup = (event: KeyboardEvent) => {\n if (event.key === 'Shift') {\n this.#shiftStartingItem = null;\n }\n };\n\n /**\n * filters listbox by keyboard event when slotted option has focus,\n * or by external element such as a text field\n * @param event keydown event\n */\n #onKeydown = (event: KeyboardEvent) => {\n const item = this.#getItemFromEvent(event);\n\n if (this.disabled\n || event.altKey\n || event.metaKey\n || !this.#isExpanded) {\n return;\n }\n\n // need to set for keyboard support of multiselect\n if (event.key === 'Shift' && this.multi) {\n this.#shiftStartingItem ??= this.#options.getATFocusedItem() ?? null;\n }\n\n switch (event.key) {\n // ctrl+A de/selects all options\n case 'a':\n case 'A':\n if (event.ctrlKey\n && (event.target === this.container\n || this.#options.isItem(event.target))) {\n const selectableItems = this.items.filter(item => !this.#options.isItemDisabled(item));\n if (arraysAreEquivalent(this.selected, selectableItems)) {\n this.selected = [];\n } else {\n this.selected = selectableItems;\n }\n event.preventDefault();\n }\n break;\n case 'Enter':\n // enter and space are only applicable if a listbox option is clicked\n // an external text input should not trigger multiselect\n if (item && !event.shiftKey) {\n const focused = item;\n this.#selectItem(focused, event.shiftKey);\n event.preventDefault();\n }\n break;\n case 'ArrowUp':\n if (this.multi && event.shiftKey && this.#options.isItem(event.target)) {\n const item = event.target;\n this.selected = this.items.filter((x, i) =>\n this.#selectedItems.has(x)\n || i === this.items.indexOf(item) - 1)\n .filter(x => !this.#options.isItemDisabled(x));\n }\n break;\n case 'ArrowDown':\n if (this.multi && event.shiftKey && this.#options.isItem(event.target)) {\n const item = event.target;\n this.selected = this.items.filter((x, i) =>\n this.#selectedItems.has(x)\n || i === this.items.indexOf(item) + 1)\n .filter(x => !this.#options.isItemDisabled(x));\n }\n break;\n case ' ':\n // enter and space are only applicable if a listbox option is clicked\n // an external text input should not trigger multiselect\n if (item && event.target === this.container) {\n this.#selectItem(item, event.shiftKey);\n event.preventDefault();\n } else if (this.#options.isItem(event.target)) {\n this.#selectItem(event.target, event.shiftKey);\n event.preventDefault();\n }\n break;\n default:\n break;\n }\n this.host.requestUpdate();\n };\n\n #selectItem(item: Item, shiftDown = false) {\n if (this.#options.isItemDisabled(item)) {\n return;\n } else if (this.multi && shiftDown) {\n // update starting item for other multiselect\n this.selected = [...this.selected, item];\n } else if (this.multi && this.#selectedItems.has(item)) {\n this.selected = this.selected.filter(x => x !== item);\n } else if (this.multi) {\n this.selected = this.selected.concat(item);\n } else {\n this.selected = [item];\n }\n }\n}\n"]}
|
package/controllers/logger.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isServer } from 'lit';
|
|
2
2
|
export class Logger {
|
|
3
|
+
static { this.instances = new WeakMap(); }
|
|
3
4
|
get prefix() {
|
|
4
5
|
if (!isServer && this.host instanceof HTMLElement) {
|
|
5
6
|
return `[${this.host.localName}${this.host.id ? `#${this.host.id}` : ''}]`;
|
|
@@ -132,5 +133,4 @@ export class Logger {
|
|
|
132
133
|
this.debug('connected');
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
|
-
Logger.instances = new WeakMap();
|
|
136
136
|
//# sourceMappingURL=logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAwD,MAAM,KAAK,CAAC;AAErF,MAAM,OAAO,MAAM;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":"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","sourcesContent":["import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit';\n\nexport class Logger implements ReactiveController {\n private static logDebug: boolean;\n\n private static instances = new WeakMap<ReactiveControllerHost, Logger>();\n\n private get prefix() {\n if (!isServer && this.host instanceof HTMLElement) {\n return `[${this.host.localName}${this.host.id ? `#${this.host.id}` : ''}]`;\n } else {\n return `[${this.host.constructor.name}]`;\n }\n }\n\n /**\n * A boolean value that indicates if the logging should be printed to the console; used for debugging.\n * For use in a JS file or script tag; can also be added in the constructor of a component during development.\n * @example Logger.debugLog(true);\n * @param [preference=null]\n */\n static debugLog(preference = null): boolean {\n // wrap localStorage references in a try/catch; merely referencing it can\n // throw errors in some locked down environments\n try {\n if (preference !== null) {\n Logger.logDebug = !!preference;\n localStorage.pfeLog = !!preference;\n }\n return localStorage.pfeLog === 'true';\n } catch {\n return Logger.logDebug;\n }\n }\n\n /* eslint-disable no-console */\n\n /**\n * A logging wrapper which checks the debugLog boolean and prints to the console if true.\n * @example Logger.debug(\"Hello\");\n * @param msgs console.log params\n */\n static debug(...msgs: unknown[]): void {\n if (Logger.debugLog()) {\n console.debug(...msgs);\n }\n }\n\n /**\n * A logging wrapper which checks the debugLog boolean and prints to the console if true.\n * @example Logger.info(\"Hello\");\n * @param msgs console.log params\n */\n static info(...msgs: unknown[]): void {\n if (Logger.debugLog()) {\n console.info(...msgs);\n }\n }\n\n /**\n * A logging wrapper which checks the debugLog boolean and prints to the console if true.\n * @example Logger.log(\"Hello\");\n * @param msgs console.log params\n */\n static log(...msgs: unknown[]): void {\n if (Logger.debugLog()) {\n console.log(...msgs);\n }\n }\n\n /**\n * A console warning wrapper which formats your output with useful debugging information.\n * @example Logger.warn(\"Hello\");\n * @param msgs console.log params\n */\n static warn(...msgs: unknown[]): void {\n console.warn(...msgs);\n }\n\n /**\n * A console error wrapper which formats your output with useful debugging information.\n * For use inside a component's function.\n * @example Logger.error(\"Hello\");\n * @param msgs console.log params\n */\n static error(...msgs: unknown[]): void {\n console.error([...msgs].join(' '));\n }\n\n /* eslint-enable no-console */\n\n /**\n * Debug logging that outputs the tag name as a prefix automatically\n * @example this.logger.log(\"Hello\");\n * @param msgs console.log params\n */\n debug(...msgs: unknown[]): void {\n Logger.debug(this.prefix, ...msgs);\n }\n\n /**\n * Info logging that outputs the tag name as a prefix automatically\n * @example this.logger.log(\"Hello\");\n * @param msgs console.log params\n */\n info(...msgs: unknown[]): void {\n Logger.info(this.prefix, ...msgs);\n }\n\n /**\n * Local logging that outputs the tag name as a prefix automatically\n * @example this.logger.log(\"Hello\");\n * @param msgs console.log params\n */\n log(...msgs: unknown[]): void {\n Logger.log(this.prefix, ...msgs);\n }\n\n /**\n * Local warning wrapper that outputs the tag name as a prefix automatically.\n * For use inside a component's function.\n * @example this.logger.warn(\"Hello\");\n * @param msgs console.log params\n */\n warn(...msgs: unknown[]): void {\n Logger.warn(this.prefix, ...msgs);\n }\n\n /**\n * Local error wrapper that outputs the tag name as a prefix automatically.\n * For use inside a component's function.\n * @example this.logger.error(\"Hello\");\n * @param msgs console.log params\n */\n error(...msgs: unknown[]): void {\n Logger.error(this.prefix, ...msgs);\n }\n\n constructor(private host: ReactiveControllerHost) {\n // We only need one logger instance per host\n if (Logger.instances.get(host)) {\n return Logger.instances.get(host) as Logger;\n }\n host.addController(this);\n Logger.instances.set(host, this);\n }\n\n hostConnected(): void {\n this.debug('connected');\n }\n}\n"]}
|
|
@@ -59,6 +59,21 @@ export class RovingTabindexController extends ATFocusController {
|
|
|
59
59
|
if (!isServer) {
|
|
60
60
|
if (container instanceof HTMLElement) {
|
|
61
61
|
container.addEventListener('focusin', () => __classPrivateFieldSet(this, _RovingTabindexController_gainedInitialFocus, true, "f"), { once: true });
|
|
62
|
+
// Sync atFocusedItemIndex when an item receives DOM focus (e.g., via mouse click)
|
|
63
|
+
// This ensures keyboard navigation starts from the correct position
|
|
64
|
+
container.addEventListener('focusin', (event) => {
|
|
65
|
+
const target = event.target;
|
|
66
|
+
const index = this.items.indexOf(target);
|
|
67
|
+
// Only update if the target is a valid item and index differs
|
|
68
|
+
if (index >= 0 && index !== this.atFocusedItemIndex) {
|
|
69
|
+
// Update index via setter, but avoid the focus() call by temporarily
|
|
70
|
+
// clearing #gainedInitialFocus to prevent redundant focus
|
|
71
|
+
const hadInitialFocus = __classPrivateFieldGet(this, _RovingTabindexController_gainedInitialFocus, "f");
|
|
72
|
+
__classPrivateFieldSet(this, _RovingTabindexController_gainedInitialFocus, false, "f");
|
|
73
|
+
this.atFocusedItemIndex = index;
|
|
74
|
+
__classPrivateFieldSet(this, _RovingTabindexController_gainedInitialFocus, hadInitialFocus, "f");
|
|
75
|
+
}
|
|
76
|
+
});
|
|
62
77
|
}
|
|
63
78
|
else {
|
|
64
79
|
__classPrivateFieldGet(this, _RovingTabindexController_logger, "f").warn('RovingTabindexController requires a getItemsContainer function');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roving-tabindex-controller.js","sourceRoot":"","sources":["roving-tabindex-controller.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"roving-tabindex-controller.js","sourceRoot":"","sources":["roving-tabindex-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { isServer, type ReactiveControllerHost } from 'lit';\nimport { ATFocusController, type ATFocusControllerOptions } from './at-focus-controller.js';\nimport { Logger } from './logger.js';\nimport { bound } from '../decorators/bound.js';\n\nexport type RovingTabindexControllerOptions<Item extends HTMLElement> =\n ATFocusControllerOptions<Item>;\n\n/**\n * Implements roving tabindex, as described in WAI-ARIA practices, [Managing Focus Within\n * Components Using a Roving tabindex][rti]\n *\n * [rti]: https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_roving_tabindex\n */\nexport class RovingTabindexController<\n Item extends HTMLElement = HTMLElement\n> extends ATFocusController<Item> {\n static of<Item extends HTMLElement>(\n host: ReactiveControllerHost,\n options: RovingTabindexControllerOptions<Item>,\n ): RovingTabindexController<Item> {\n return new RovingTabindexController(host, options);\n }\n\n #logger = new Logger(this.host);\n\n #gainedInitialFocus = false;\n\n #itemsSet = new Set<Item>();\n\n get atFocusedItemIndex(): number {\n return super.atFocusedItemIndex;\n }\n\n /**\n * Sets the DOM Focus on the item with assistive technology focus\n * @param item item\n */\n set atFocusedItemIndex(index: number) {\n super.atFocusedItemIndex = index;\n const item = this.items.at(this.atFocusedItemIndex);\n for (const i of this.items) {\n i.tabIndex = item === i ? 0 : -1;\n }\n if (this.#gainedInitialFocus) {\n item?.focus();\n }\n this.host.requestUpdate();\n }\n\n get items() {\n return this._items;\n }\n\n public set items(items: Item[]) {\n this._items = items;\n this.#itemsSet = new Set(items);\n const pivot = Math.max(0, this.atFocusedItemIndex);\n const [firstFocusable] = this.atFocusableItems;\n const firstFocusableIndex = firstFocusable ? items.indexOf(firstFocusable) : -1;\n const pivotFocusableIndex = items.indexOf(this.items\n .slice(pivot)\n .concat(this.items.slice(0, pivot))\n .find(item => this.atFocusableItems.includes(item))!);\n this.atFocusedItemIndex = Math.max(firstFocusableIndex, pivotFocusableIndex);\n this.host.requestUpdate();\n }\n\n private constructor(\n public host: ReactiveControllerHost,\n options: RovingTabindexControllerOptions<Item>,\n ) {\n super(host, options);\n this.initItems();\n const container = options.getItemsContainer?.() ?? this.host;\n if (!isServer) {\n if (container instanceof HTMLElement) {\n container.addEventListener('focusin', () =>\n this.#gainedInitialFocus = true, { once: true });\n // Sync atFocusedItemIndex when an item receives DOM focus (e.g., via mouse click)\n // This ensures keyboard navigation starts from the correct position\n container.addEventListener('focusin', (event: FocusEvent) => {\n const target = event.target as Item;\n const index = this.items.indexOf(target);\n // Only update if the target is a valid item and index differs\n if (index >= 0 && index !== this.atFocusedItemIndex) {\n // Update index via setter, but avoid the focus() call by temporarily\n // clearing #gainedInitialFocus to prevent redundant focus\n const hadInitialFocus = this.#gainedInitialFocus;\n this.#gainedInitialFocus = false;\n this.atFocusedItemIndex = index;\n this.#gainedInitialFocus = hadInitialFocus;\n }\n });\n } else {\n this.#logger.warn('RovingTabindexController requires a getItemsContainer function');\n }\n }\n }\n\n @bound\n protected override onKeydown(event: KeyboardEvent): void {\n if (!event.ctrlKey\n && !event.altKey\n && !event.metaKey\n && !!this.atFocusableItems.length\n && !!event.composedPath().some(node => this.#itemsSet.has(node as Item))) {\n super.onKeydown(event);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { expect, fixture } from '@open-wc/testing';
|
|
3
|
+
import { customElement } from 'lit/decorators/custom-element.js';
|
|
4
|
+
import { LitElement, html } from 'lit';
|
|
5
|
+
import { RovingTabindexController } from '../roving-tabindex-controller.js';
|
|
6
|
+
let TestElement = class TestElement extends LitElement {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.controller = RovingTabindexController.of(this, {
|
|
10
|
+
getItems: () => [...this.querySelectorAll('.item')],
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
render() {
|
|
14
|
+
return html `<slot></slot>`;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
TestElement = __decorate([
|
|
18
|
+
customElement('x-at-focus-test')
|
|
19
|
+
], TestElement);
|
|
20
|
+
describe('ATFocusController', function () {
|
|
21
|
+
describe('atFocusedItemIndex', function () {
|
|
22
|
+
describe('with all items focusable', function () {
|
|
23
|
+
let element;
|
|
24
|
+
beforeEach(async function () {
|
|
25
|
+
element = await fixture(html `
|
|
26
|
+
<x-at-focus-test>
|
|
27
|
+
<div class="item">0</div>
|
|
28
|
+
<div class="item">1</div>
|
|
29
|
+
<div class="item">2</div>
|
|
30
|
+
<div class="item">3</div>
|
|
31
|
+
<div class="item">4</div>
|
|
32
|
+
</x-at-focus-test>
|
|
33
|
+
`);
|
|
34
|
+
});
|
|
35
|
+
it('initializes to first item', function () {
|
|
36
|
+
expect(element.controller.atFocusedItemIndex).to.equal(0);
|
|
37
|
+
});
|
|
38
|
+
it('sets to a valid index', function () {
|
|
39
|
+
element.controller.atFocusedItemIndex = 3;
|
|
40
|
+
expect(element.controller.atFocusedItemIndex).to.equal(3);
|
|
41
|
+
});
|
|
42
|
+
it('wraps to last item when navigating before start', function () {
|
|
43
|
+
element.controller.atFocusedItemIndex = 0;
|
|
44
|
+
element.controller.atFocusedItemIndex--;
|
|
45
|
+
const { items } = element.controller;
|
|
46
|
+
expect(items.at(element.controller.atFocusedItemIndex))
|
|
47
|
+
.to.equal(items[4]);
|
|
48
|
+
});
|
|
49
|
+
it('wraps to first item when navigating past end', function () {
|
|
50
|
+
element.controller.atFocusedItemIndex = 4;
|
|
51
|
+
element.controller.atFocusedItemIndex++;
|
|
52
|
+
expect(element.controller.atFocusedItemIndex).to.equal(0);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('with non-focusable placeholder at index 0', function () {
|
|
56
|
+
let element;
|
|
57
|
+
beforeEach(async function () {
|
|
58
|
+
element = await fixture(html `
|
|
59
|
+
<x-at-focus-test>
|
|
60
|
+
<div class="item" aria-hidden="true">Placeholder</div>
|
|
61
|
+
<div class="item">1</div>
|
|
62
|
+
<div class="item">2</div>
|
|
63
|
+
<div class="item">3</div>
|
|
64
|
+
<div class="item">4</div>
|
|
65
|
+
</x-at-focus-test>
|
|
66
|
+
`);
|
|
67
|
+
});
|
|
68
|
+
it('initializes to first focusable item', function () {
|
|
69
|
+
expect(element.controller.atFocusedItemIndex).to.equal(1);
|
|
70
|
+
});
|
|
71
|
+
it('wraps to last when navigating up from first focusable', function () {
|
|
72
|
+
element.controller.atFocusedItemIndex = 1;
|
|
73
|
+
element.controller.atFocusedItemIndex--;
|
|
74
|
+
expect(element.controller.atFocusedItemIndex).to.equal(4);
|
|
75
|
+
});
|
|
76
|
+
it('snaps to first focusable when set to placeholder from elsewhere', function () {
|
|
77
|
+
element.controller.atFocusedItemIndex = 3;
|
|
78
|
+
element.controller.atFocusedItemIndex = 0;
|
|
79
|
+
expect(element.controller.atFocusedItemIndex).to.equal(1);
|
|
80
|
+
});
|
|
81
|
+
it('wraps to first focusable when navigating past end', function () {
|
|
82
|
+
element.controller.atFocusedItemIndex = 4;
|
|
83
|
+
element.controller.atFocusedItemIndex++;
|
|
84
|
+
expect(element.controller.atFocusedItemIndex).to.equal(1);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe('with mid-list non-focusable items', function () {
|
|
88
|
+
let element;
|
|
89
|
+
beforeEach(async function () {
|
|
90
|
+
element = await fixture(html `
|
|
91
|
+
<x-at-focus-test>
|
|
92
|
+
<div class="item">A</div>
|
|
93
|
+
<div class="item" aria-hidden="true">X</div>
|
|
94
|
+
<div class="item">B</div>
|
|
95
|
+
<div class="item" aria-hidden="true">Y</div>
|
|
96
|
+
<div class="item">C</div>
|
|
97
|
+
</x-at-focus-test>
|
|
98
|
+
`);
|
|
99
|
+
});
|
|
100
|
+
it('scans forward past non-focusable item', function () {
|
|
101
|
+
element.controller.atFocusedItemIndex = 0;
|
|
102
|
+
element.controller.atFocusedItemIndex++;
|
|
103
|
+
expect(element.controller.atFocusedItemIndex).to.equal(2);
|
|
104
|
+
});
|
|
105
|
+
it('scans backward past non-focusable item', function () {
|
|
106
|
+
element.controller.atFocusedItemIndex = 2;
|
|
107
|
+
element.controller.atFocusedItemIndex--;
|
|
108
|
+
expect(element.controller.atFocusedItemIndex).to.equal(0);
|
|
109
|
+
});
|
|
110
|
+
it('scans forward past second non-focusable item', function () {
|
|
111
|
+
element.controller.atFocusedItemIndex = 2;
|
|
112
|
+
element.controller.atFocusedItemIndex++;
|
|
113
|
+
expect(element.controller.atFocusedItemIndex).to.equal(4);
|
|
114
|
+
});
|
|
115
|
+
it('scans backward past second non-focusable item', function () {
|
|
116
|
+
element.controller.atFocusedItemIndex = 4;
|
|
117
|
+
element.controller.atFocusedItemIndex--;
|
|
118
|
+
expect(element.controller.atFocusedItemIndex).to.equal(2);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('with consecutive non-focusable items', function () {
|
|
122
|
+
let element;
|
|
123
|
+
beforeEach(async function () {
|
|
124
|
+
element = await fixture(html `
|
|
125
|
+
<x-at-focus-test>
|
|
126
|
+
<div class="item">A</div>
|
|
127
|
+
<div class="item" aria-hidden="true">X</div>
|
|
128
|
+
<div class="item" aria-hidden="true">Y</div>
|
|
129
|
+
<div class="item">B</div>
|
|
130
|
+
</x-at-focus-test>
|
|
131
|
+
`);
|
|
132
|
+
});
|
|
133
|
+
it('scans forward past two consecutive non-focusable items', function () {
|
|
134
|
+
element.controller.atFocusedItemIndex = 0;
|
|
135
|
+
element.controller.atFocusedItemIndex++;
|
|
136
|
+
expect(element.controller.atFocusedItemIndex).to.equal(3);
|
|
137
|
+
});
|
|
138
|
+
it('scans backward past two consecutive non-focusable items', function () {
|
|
139
|
+
element.controller.atFocusedItemIndex = 3;
|
|
140
|
+
element.controller.atFocusedItemIndex--;
|
|
141
|
+
expect(element.controller.atFocusedItemIndex).to.equal(0);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe('with non-focusable tail', function () {
|
|
145
|
+
let element;
|
|
146
|
+
beforeEach(async function () {
|
|
147
|
+
element = await fixture(html `
|
|
148
|
+
<x-at-focus-test>
|
|
149
|
+
<div class="item">A</div>
|
|
150
|
+
<div class="item">B</div>
|
|
151
|
+
<div class="item" aria-hidden="true">X</div>
|
|
152
|
+
<div class="item" aria-hidden="true">Y</div>
|
|
153
|
+
</x-at-focus-test>
|
|
154
|
+
`);
|
|
155
|
+
});
|
|
156
|
+
it('wraps to first when navigating forward into non-focusable tail', function () {
|
|
157
|
+
element.controller.atFocusedItemIndex = 1;
|
|
158
|
+
element.controller.atFocusedItemIndex++;
|
|
159
|
+
expect(element.controller.atFocusedItemIndex).to.equal(0);
|
|
160
|
+
});
|
|
161
|
+
it('wraps to last focusable when navigating backward into non-focusable head', async function () {
|
|
162
|
+
const el = await fixture(html `
|
|
163
|
+
<x-at-focus-test>
|
|
164
|
+
<div class="item" aria-hidden="true">X</div>
|
|
165
|
+
<div class="item" aria-hidden="true">Y</div>
|
|
166
|
+
<div class="item">A</div>
|
|
167
|
+
<div class="item">B</div>
|
|
168
|
+
</x-at-focus-test>
|
|
169
|
+
`);
|
|
170
|
+
el.controller.atFocusedItemIndex = 2;
|
|
171
|
+
el.controller.atFocusedItemIndex--;
|
|
172
|
+
expect(el.controller.atFocusedItemIndex).to.equal(3);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('with only one focusable item', function () {
|
|
176
|
+
let element;
|
|
177
|
+
beforeEach(async function () {
|
|
178
|
+
element = await fixture(html `
|
|
179
|
+
<x-at-focus-test>
|
|
180
|
+
<div class="item" aria-hidden="true">X</div>
|
|
181
|
+
<div class="item">A</div>
|
|
182
|
+
<div class="item" aria-hidden="true">Y</div>
|
|
183
|
+
</x-at-focus-test>
|
|
184
|
+
`);
|
|
185
|
+
});
|
|
186
|
+
it('stays on sole focusable item when navigating forward', function () {
|
|
187
|
+
expect(element.controller.atFocusedItemIndex).to.equal(1);
|
|
188
|
+
element.controller.atFocusedItemIndex++;
|
|
189
|
+
expect(element.controller.atFocusedItemIndex).to.equal(1);
|
|
190
|
+
});
|
|
191
|
+
it('stays on sole focusable item when navigating backward', function () {
|
|
192
|
+
expect(element.controller.atFocusedItemIndex).to.equal(1);
|
|
193
|
+
element.controller.atFocusedItemIndex--;
|
|
194
|
+
expect(element.controller.atFocusedItemIndex).to.equal(1);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('with no focusable items', function () {
|
|
198
|
+
let element;
|
|
199
|
+
beforeEach(async function () {
|
|
200
|
+
element = await fixture(html `
|
|
201
|
+
<x-at-focus-test>
|
|
202
|
+
<div class="item" aria-hidden="true">X</div>
|
|
203
|
+
<div class="item" aria-hidden="true">Y</div>
|
|
204
|
+
</x-at-focus-test>
|
|
205
|
+
`);
|
|
206
|
+
});
|
|
207
|
+
it('stores index as-is', function () {
|
|
208
|
+
element.controller.atFocusedItemIndex = 0;
|
|
209
|
+
expect(element.controller.atFocusedItemIndex).to.equal(0);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
//# sourceMappingURL=at-focus-controller.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"at-focus-controller.spec.js","sourceRoot":"","sources":["at-focus-controller.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture } from '@open-wc/testing';\nimport { customElement } from 'lit/decorators/custom-element.js';\nimport { LitElement, html } from 'lit';\n\nimport { RovingTabindexController } from '../roving-tabindex-controller.js';\n\n@customElement('x-at-focus-test')\nclass TestElement extends LitElement {\n controller = RovingTabindexController.of(this, {\n getItems: () => [...this.querySelectorAll<HTMLElement>('.item')],\n });\n\n protected override render() {\n return html`<slot></slot>`;\n }\n}\n\ndescribe('ATFocusController', function() {\n describe('atFocusedItemIndex', function() {\n describe('with all items focusable', function() {\n let element: TestElement;\n\n beforeEach(async function() {\n element = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\">0</div>\n <div class=\"item\">1</div>\n <div class=\"item\">2</div>\n <div class=\"item\">3</div>\n <div class=\"item\">4</div>\n </x-at-focus-test>\n `);\n });\n\n it('initializes to first item', function() {\n expect(element.controller.atFocusedItemIndex).to.equal(0);\n });\n\n it('sets to a valid index', function() {\n element.controller.atFocusedItemIndex = 3;\n expect(element.controller.atFocusedItemIndex).to.equal(3);\n });\n\n it('wraps to last item when navigating before start', function() {\n element.controller.atFocusedItemIndex = 0;\n element.controller.atFocusedItemIndex--;\n const { items } = element.controller;\n expect(items.at(element.controller.atFocusedItemIndex))\n .to.equal(items[4]);\n });\n\n it('wraps to first item when navigating past end', function() {\n element.controller.atFocusedItemIndex = 4;\n element.controller.atFocusedItemIndex++;\n expect(element.controller.atFocusedItemIndex).to.equal(0);\n });\n });\n\n describe('with non-focusable placeholder at index 0', function() {\n let element: TestElement;\n\n beforeEach(async function() {\n element = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\" aria-hidden=\"true\">Placeholder</div>\n <div class=\"item\">1</div>\n <div class=\"item\">2</div>\n <div class=\"item\">3</div>\n <div class=\"item\">4</div>\n </x-at-focus-test>\n `);\n });\n\n it('initializes to first focusable item', function() {\n expect(element.controller.atFocusedItemIndex).to.equal(1);\n });\n\n it('wraps to last when navigating up from first focusable', function() {\n element.controller.atFocusedItemIndex = 1;\n element.controller.atFocusedItemIndex--;\n expect(element.controller.atFocusedItemIndex).to.equal(4);\n });\n\n it('snaps to first focusable when set to placeholder from elsewhere', function() {\n element.controller.atFocusedItemIndex = 3;\n element.controller.atFocusedItemIndex = 0;\n expect(element.controller.atFocusedItemIndex).to.equal(1);\n });\n\n it('wraps to first focusable when navigating past end', function() {\n element.controller.atFocusedItemIndex = 4;\n element.controller.atFocusedItemIndex++;\n expect(element.controller.atFocusedItemIndex).to.equal(1);\n });\n });\n\n describe('with mid-list non-focusable items', function() {\n let element: TestElement;\n\n beforeEach(async function() {\n element = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\">A</div>\n <div class=\"item\" aria-hidden=\"true\">X</div>\n <div class=\"item\">B</div>\n <div class=\"item\" aria-hidden=\"true\">Y</div>\n <div class=\"item\">C</div>\n </x-at-focus-test>\n `);\n });\n\n it('scans forward past non-focusable item', function() {\n element.controller.atFocusedItemIndex = 0;\n element.controller.atFocusedItemIndex++;\n expect(element.controller.atFocusedItemIndex).to.equal(2);\n });\n\n it('scans backward past non-focusable item', function() {\n element.controller.atFocusedItemIndex = 2;\n element.controller.atFocusedItemIndex--;\n expect(element.controller.atFocusedItemIndex).to.equal(0);\n });\n\n it('scans forward past second non-focusable item', function() {\n element.controller.atFocusedItemIndex = 2;\n element.controller.atFocusedItemIndex++;\n expect(element.controller.atFocusedItemIndex).to.equal(4);\n });\n\n it('scans backward past second non-focusable item', function() {\n element.controller.atFocusedItemIndex = 4;\n element.controller.atFocusedItemIndex--;\n expect(element.controller.atFocusedItemIndex).to.equal(2);\n });\n });\n\n describe('with consecutive non-focusable items', function() {\n let element: TestElement;\n\n beforeEach(async function() {\n element = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\">A</div>\n <div class=\"item\" aria-hidden=\"true\">X</div>\n <div class=\"item\" aria-hidden=\"true\">Y</div>\n <div class=\"item\">B</div>\n </x-at-focus-test>\n `);\n });\n\n it('scans forward past two consecutive non-focusable items', function() {\n element.controller.atFocusedItemIndex = 0;\n element.controller.atFocusedItemIndex++;\n expect(element.controller.atFocusedItemIndex).to.equal(3);\n });\n\n it('scans backward past two consecutive non-focusable items', function() {\n element.controller.atFocusedItemIndex = 3;\n element.controller.atFocusedItemIndex--;\n expect(element.controller.atFocusedItemIndex).to.equal(0);\n });\n });\n\n describe('with non-focusable tail', function() {\n let element: TestElement;\n\n beforeEach(async function() {\n element = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\">A</div>\n <div class=\"item\">B</div>\n <div class=\"item\" aria-hidden=\"true\">X</div>\n <div class=\"item\" aria-hidden=\"true\">Y</div>\n </x-at-focus-test>\n `);\n });\n\n it('wraps to first when navigating forward into non-focusable tail', function() {\n element.controller.atFocusedItemIndex = 1;\n element.controller.atFocusedItemIndex++;\n expect(element.controller.atFocusedItemIndex).to.equal(0);\n });\n\n it('wraps to last focusable when navigating backward into non-focusable head', async function() {\n const el: TestElement = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\" aria-hidden=\"true\">X</div>\n <div class=\"item\" aria-hidden=\"true\">Y</div>\n <div class=\"item\">A</div>\n <div class=\"item\">B</div>\n </x-at-focus-test>\n `);\n el.controller.atFocusedItemIndex = 2;\n el.controller.atFocusedItemIndex--;\n expect(el.controller.atFocusedItemIndex).to.equal(3);\n });\n });\n\n describe('with only one focusable item', function() {\n let element: TestElement;\n\n beforeEach(async function() {\n element = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\" aria-hidden=\"true\">X</div>\n <div class=\"item\">A</div>\n <div class=\"item\" aria-hidden=\"true\">Y</div>\n </x-at-focus-test>\n `);\n });\n\n it('stays on sole focusable item when navigating forward', function() {\n expect(element.controller.atFocusedItemIndex).to.equal(1);\n element.controller.atFocusedItemIndex++;\n expect(element.controller.atFocusedItemIndex).to.equal(1);\n });\n\n it('stays on sole focusable item when navigating backward', function() {\n expect(element.controller.atFocusedItemIndex).to.equal(1);\n element.controller.atFocusedItemIndex--;\n expect(element.controller.atFocusedItemIndex).to.equal(1);\n });\n });\n\n describe('with no focusable items', function() {\n let element: TestElement;\n\n beforeEach(async function() {\n element = await fixture(html`\n <x-at-focus-test>\n <div class=\"item\" aria-hidden=\"true\">X</div>\n <div class=\"item\" aria-hidden=\"true\">Y</div>\n </x-at-focus-test>\n `);\n });\n\n it('stores index as-is', function() {\n element.controller.atFocusedItemIndex = 0;\n expect(element.controller.atFocusedItemIndex).to.equal(0);\n });\n });\n });\n});\n"]}
|