@patternfly/pfe-core 5.0.5 → 5.0.7

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.
@@ -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":";;AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AA2DhE;;;;GAIG;AACH,SAAS,eAAe,CAA2B,IAAU,EAAE,QAAiB;IAC9E,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAA2B,IAAwB;IACvE,OAAO,IAAI,YAAY,OAAO;WACzB,IAAI,EAAE,aAAa,EAAE,IAAI,KAAK,SAAS;WACvC,IAAI,EAAE,IAAI,KAAK,cAAc;WAC7B,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;AAChC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAA2B,IAAU;IACjE,OAAO,CAAC,UAAU,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC;WAC3E,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;WAC7C,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;WAC7B,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;WAC1B,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AACnC,CAAC;AAED,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,OAAO,iBAAiB;IAGrB,MAAM,CAAC,EAAE,CACd,IAA4B,EAC5B,OAAuC;QAEvC,mBAAmB,GAAG,IAAI,CAAC;QAC3B,MAAM,QAAQ,GAAG,IAAI,iBAAiB,CAAO,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5D,mBAAmB,GAAG,KAAK,CAAC;QAC5B,OAAO,QAAmC,CAAC;IAC7C,CAAC;IAqBD,IAAI,SAAS;QACX,OAAO,uBAAA,IAAI,kCAAS,CAAC,iBAAiB,EAAE,EAAE,IAAI,IAAI,CAAC,IAA8B,CAAC;IACpF,CAAC;IAED,IAAI,KAAK;QACP,OAAO,CAAC,CAAC,uBAAA,IAAI,kCAAS,CAAC,KAAK,CAAC;IAC/B,CAAC;IAED,IAAI,KAAK,CAAC,CAAU;QAClB,uBAAA,IAAI,kCAAS,CAAC,KAAK,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK;QACP,OAAO,uBAAA,IAAI,gCAAO,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,IAAI,KAAK,CAAC,KAAa;QACrB,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,uBAAA,IAAI,gCAAO,CAAC,EAAE,CAAC;YAC7C,uBAAA,IAAI,4BAAU,KAAK,MAAA,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,IAAI,QAAQ,CAAC,QAAgB;QAC3B,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,uBAAA,IAAI,wCAAe,CAAC,CAAC,EAAE,CAAC;YACpE,uBAAA,IAAI,oCAAkB,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAA,CAAC;YACxC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC9B,uBAAA,IAAI,kCAAS,CAAC,eAAe,CAAC,IAAI,EAAE,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YACrE,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACV,OAAO,CAAC,GAAG,uBAAA,IAAI,wCAAe,CAAC,CAAC;IAClC,CAAC;IAED,YACS,IAA4B,EACnC,OAAuC;;QADhC,SAAI,GAAJ,IAAI,CAAwB;QArErC,0DAA0D;QAC1D,+CAAkC,IAAI,EAAC;QAEvC,6CAIE;QAEF,gBAAgB;QAChB,mCAAiB,EAAE,EAAC;QAEpB,2CAAiB,IAAI,GAAS,EAAC;QAE/B,uCAAa,KAAK,EAAC;QAEnB,kCAAkC;QAClC,aAAQ,GAAG,KAAK,CAAC;QAqFjB,8CAAmC,EAAE,EAAC;QAkKtC;;;;;WAKG;QACH,qCAAW,CAAC,KAAiB,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,uBAAA,IAAI,yEAAkB,MAAtB,IAAI,EAAmB,KAAK,CAAC,CAAC;YAC3C,8IAA4B,uBAAA,IAAI,yEAAkB,MAAtB,IAAI,EAAmB,KAAK,CAAC,MAAA,CAAC;YAC1D,IAAI,IAAI,IAAI,CAAC,uBAAA,IAAI,kCAAS,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChD,uBAAuB;gBACvB,sCAAsC;gBACtC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;oBAChB,+CAA+C;oBAC/C,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC;oBACzB,uCAAuC;oBACvC,0DAA0D;gBAC1D,CAAC;qBAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;oBAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,CACrD,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,oBAAoB,KAAK,IAAI;wBAC/E,CAAC,CAAC,oBAAoB,KAAK,IAAI,CAAC,CAAC;oBACrC,qCAAqC;oBACrC,+DAA+D;oBAC/D,2GAA2G;oBAC3G,6FAA6F;gBAC7F,CAAC;qBAAM,CAAC;oBACN,MAAM,YAAY,GAAG,uBAAA,IAAI,4CAAoB,CAAC;oBAC9C,gEAAgE;oBAChE,MAAM,SAAS,GAAG,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;oBACxD,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBACzF,6DAA6D;oBAC7D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;wBAC5C,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;4BAC3B,OAAO,SAAS,CAAC;wBACnB,CAAC;6BAAM,CAAC;4BACN,OAAO,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;wBACvC,CAAC;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YACD,uBAAA,IAAI,wCAAsB,IAAI,MAAA,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC,EAAC;QAEF;;;WAGG;QACH,qCAAW,CAAC,KAAoB,EAAE,EAAE;YAClC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;gBAC1B,uBAAA,IAAI,wCAAsB,IAAI,MAAA,CAAC;YACjC,CAAC;QACH,CAAC,EAAC;QAEF;;;;WAIG;QACH,uCAAa,CAAC,KAAoB,EAAE,EAAE;YACpC,MAAM,IAAI,GAAG,uBAAA,IAAI,yEAAkB,MAAtB,IAAI,EAAmB,KAAK,CAAC,CAAC;YAE3C,IAAI,IAAI,CAAC,QAAQ;mBACZ,KAAK,CAAC,MAAM;mBACZ,KAAK,CAAC,OAAO;mBACb,CAAC,uBAAA,IAAI,uEAAY,EAAE,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,kDAAkD;YAClD,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACxC,+IAA4B,uBAAA,IAAI,kCAAS,CAAC,gBAAgB,EAAE,IAAI,IAAI,OAAA,CAAC;YACvE,CAAC;YAED,QAAQ,KAAK,CAAC,GAAG,EAAE,CAAC;gBAClB,gCAAgC;gBAChC,KAAK,GAAG,CAAC;gBACT,KAAK,GAAG;oBACN,IAAI,KAAK,CAAC,OAAO;2BACV,CAAC,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS;+BAC5B,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;wBAC/C,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,uBAAA,IAAI,kCAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;wBACvF,IAAI,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC;4BACxD,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;wBACrB,CAAC;6BAAM,CAAC;4BACN,IAAI,CAAC,QAAQ,GAAG,eAAe,CAAC;wBAClC,CAAC;wBACD,KAAK,CAAC,cAAc,EAAE,CAAC;oBACzB,CAAC;oBACD,MAAM;gBACR,KAAK,OAAO;oBACV,qEAAqE;oBACrE,wDAAwD;oBACxD,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;wBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC;wBACrB,uBAAA,IAAI,mEAAY,MAAhB,IAAI,EAAa,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC1C,KAAK,CAAC,cAAc,EAAE,CAAC;oBACzB,CAAC;oBACD,MAAM;gBACR,KAAK,SAAS;oBACZ,IAAI,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,IAAI,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;wBACvE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;wBAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACzC,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,CAAC,CAAC;+BACvB,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;6BACnC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,uBAAA,IAAI,kCAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;oBACrD,CAAC;oBACD,MAAM;gBACR,KAAK,WAAW;oBACd,IAAI,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,IAAI,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;wBACvE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;wBAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACzC,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,CAAC,CAAC;+BACvB,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;6BACnC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,uBAAA,IAAI,kCAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;oBACrD,CAAC;oBACD,MAAM;gBACR,KAAK,GAAG;oBACN,qEAAqE;oBACrE,wDAAwD;oBACxD,IAAI,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;wBAC5C,uBAAA,IAAI,mEAAY,MAAhB,IAAI,EAAa,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;wBACvC,KAAK,CAAC,cAAc,EAAE,CAAC;oBACzB,CAAC;yBAAM,IAAI,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC9C,uBAAA,IAAI,mEAAY,MAAhB,IAAI,EAAa,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC/C,KAAK,CAAC,cAAc,EAAE,CAAC;oBACzB,CAAC;oBACD,MAAM;gBACR;oBACE,MAAM;YACV,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC5B,CAAC,EAAC;QApUA,uBAAA,IAAI,8BAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAA,CAAC;QACxE,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,QAAQ;eACN,CAAC,CAAC,IAAI,YAAY,WAAW,CAAC;eAC9B,OAAO,OAAO,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC;gBACd,0DAA0D;gBAC1D,kEAAkE;aACnE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACf,CAAC;QACD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAuC,CAAC;QAC7F,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAmC,CAAC;QAC7C,CAAC;QACD,iBAAiB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAiD,CAAC,CAAC;QACzF,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,uBAAA,IAAI,kCAAS,CAAC,KAAK,IAAI,KAAK,CAAC;QAC1C,IAAI,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC;YAChC,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;QAC/B,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAWD;;;OAGG;IACH,UAAU;QACR,MAAM,IAAI,GAAG,uBAAA,IAAI,2CAAkB,CAAC;QACpC,uBAAA,IAAI,uCAAqB,uBAAA,IAAI,kCAAS,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,MAAA,CAAC;QACrE,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,uBAAA,IAAI,2CAAkB,CAAC,EAAE,CAAC;YACvD,uBAAA,IAAI,gFAAyB,MAA7B,IAAI,EAA0B,IAAI,CAAC,CAAC;YACpC,KAAK,MAAM,EAAE,IAAI,uBAAA,IAAI,2CAAkB,EAAE,CAAC;gBACxC,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,uBAAA,IAAI,oCAAW,CAAC,CAAC;gBAChD,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,uBAAA,IAAI,kCAAS,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,uBAAA,IAAI,gCAAO,CAAC;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC5B,mBAAmB,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACrD,mBAAmB,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,WAAW;QACT,IAAI,CAAC,uBAAA,IAAI,oCAAW,EAAE,CAAC;YACrB,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,OAAO,EAAE,uBAAA,IAAI,kCAAS,CAAC,CAAC;YACzD,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,SAAS,EAAE,uBAAA,IAAI,oCAAW,CAAC,CAAC;YAC7D,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,OAAO,EAAE,uBAAA,IAAI,kCAAS,CAAC,CAAC;YACzD,uBAAA,IAAI,gCAAc,IAAI,MAAA,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACvE,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,CAAC,uBAAA,IAAI,kCAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,gBAAgB;QACd,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,OAAO,EAAE,uBAAA,IAAI,kCAAS,CAAC,CAAC;QAC5D,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,SAAS,EAAE,uBAAA,IAAI,oCAAW,CAAC,CAAC;QAChE,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,OAAO,EAAE,uBAAA,IAAI,kCAAS,CAAC,CAAC;QAC5D,uBAAA,IAAI,gFAAyB,MAA7B,IAAI,CAA2B,CAAC;QAChC,uBAAA,IAAI,gCAAc,KAAK,MAAA,CAAC;IAC1B,CAAC;IAEM,UAAU,CAAC,IAAU;QAC1B,OAAO,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;;sjBAlDwB,GAAG,GAAG,uBAAA,IAAI,2CAAkB;IACnD,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,EAAE,CAAC,mBAAmB,CAAC,SAAS,EAAE,uBAAA,IAAI,oCAAW,CAAC,CAAC;QACnD,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,uBAAA,IAAI,kCAAS,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;IAgDC,OAAO,CAAC,uBAAA,IAAI,2CAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;QAC1C,CAAC,CAAC,uBAAA,IAAI,2CAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC;AACnE,CAAC,qFASiB,KAAY;IAC5B,2DAA2D;IAC3D,0CAA0C;IAC1C,uCAAuC;IACvC,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;IACpE,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;SAAM,IAAI,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;WAC/B,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;WAC3D,6BAA6B,IAAI,WAAW,CAAC,SAAS,EAAE,CAAC;QACrE,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;SAAM,IAAI,KAAK,CAAC,MAAM,YAAY,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC,2BAA2B,EAAE,CAAC;QAC3F,OAAO,KAAK,CAAC,MAAM,CAAC,2BAAmC,CAAC;IAC1D,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;WACnB,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;WAClC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC;QAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,IAAI,YAAY,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC;YACxE,MAAM,wBAAwB,GAAG,IAAI,CAAC,SAAS,CAAC;YAChD,MAAM,cAAc,GAAG,OAAO,CAAC;YAC/B,IAAI,cAAc,IAAI,wBAAwB,EAAE,CAAC;gBAC/C,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;oBACxC,OAAO,cAAc,CAAC;gBACxB,CAAC;qBAAM,CAAC;oBACN,MAAM,KAAK,GACT,KAAK,CAAC,IAAI,CAAC,wBAAwB,EAAE,QAAQ,IAAI,EAAE,CAAC;yBAC/C,MAAM,CAAC,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC;yBAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;yBACtB,OAAO,CAAC,cAAc,CAAC,CAAC;oBAC/B,OAAO,uBAAA,IAAI,gCAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,0EAA0E;QAC1E,MAAM,OAAO,GAAG,KAAK,CAAC,MAAqB,CAAC;QAE5C,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAA2B,CAAC;QAE5D,MAAM,UAAU,GAAG,OAAO,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC;QAC1D,MAAM,wBAAwB,GAC1B,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS;YAChD,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC;gBAC9C,CAAC,CAAC,IAAI,CAAC;QAET,MAAM,oCAAoC,GACxC,IAAI,CAAC,aAAa,CAAC,mBAAmB,wBAAwB,EAAE,EAAE,2BAA2B,CAAC,CAAC;QAEjG,MAAM,gBAAgB,GACpB,oCAAoC,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC;QAE9E,MAAM,cAAc,GAClB,gBAAgB,IAAI,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAgB,CAAC;QAE3E,IAAI,cAAc,IAAI,wBAAwB,EAAE,CAAC;YAC/C,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACxC,OAAO,cAAc,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,0DAA0D;gBAC1D,sEAAsE;gBACtE,uFAAuF;gBACvF,MAAM,UAAU,GAAG,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC;uBACpC,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;gBACtD,MAAM,UAAU,GAAG,uBAAA,IAAI,gCAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,KAAK,UAAU,CACxE,CAAC;gBACF,OAAO,UAAU,IAAI,IAAI,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,MAAM,sBAAsB,GAC1B,wBAAwB,CAAC,CAAC,CAAC,wBAAwB;YACrD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACd,CAAC,YAAY,WAAW,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAgB,CAAC;QAEnE,IAAI,sBAAsB,EAAE,CAAC;YAC3B,MAAM,gCAAgC,GAAG,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;iBAC/E,MAAM,CAAC,uBAAA,IAAI,kCAAS,CAAC,MAAM,CAAC,CAAC;YAElC,MAAM,KAAK,GAAG,gCAAgC;iBACzC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YAE5C,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC,yEAwIW,IAAU,EAAE,SAAS,GAAG,KAAK;IACvC,IAAI,uBAAA,IAAI,kCAAS,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,OAAO;IACT,CAAC;SAAM,IAAI,IAAI,CAAC,KAAK,IAAI,SAAS,EAAE,CAAC;QACnC,6CAA6C;QAC7C,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,IAAI,CAAC,KAAK,IAAI,uBAAA,IAAI,wCAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACxD,CAAC;SAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAvac,2BAAS,GAAG,IAAI,OAAO,EAA0D,AAAxE,CAAyE","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"]}
@@ -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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","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 } 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"]}
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"]}
@@ -1,4 +1,4 @@
1
- var _ScrollSpyController_instances, _a, _ScrollSpyController_instances_1, _ScrollSpyController_tagNames, _ScrollSpyController_activeAttribute, _ScrollSpyController_io, _ScrollSpyController_passedLinks, _ScrollSpyController_force, _ScrollSpyController_intersected, _ScrollSpyController_root, _ScrollSpyController_rootMargin, _ScrollSpyController_threshold, _ScrollSpyController_intersectingTargets, _ScrollSpyController_linkTargetMap, _ScrollSpyController_getRootNode, _ScrollSpyController_getHash, _ScrollSpyController_onIntersection, _ScrollSpyController_linkChildren_get, _ScrollSpyController_initializing, _ScrollSpyController_initIo, _ScrollSpyController_markPassed, _ScrollSpyController_setActive, _ScrollSpyController_activateHash, _ScrollSpyController_nextIntersection, _ScrollSpyController_onIo;
1
+ var _ScrollSpyController_instances, _a, _ScrollSpyController_instances_1, _ScrollSpyController_tagNames, _ScrollSpyController_activeAttribute, _ScrollSpyController_io, _ScrollSpyController_passedLinks, _ScrollSpyController_force, _ScrollSpyController_forceAbort, _ScrollSpyController_forceTimeout, _ScrollSpyController_intersected, _ScrollSpyController_root, _ScrollSpyController_rootMargin, _ScrollSpyController_threshold, _ScrollSpyController_intersectingTargets, _ScrollSpyController_linkTargetMap, _ScrollSpyController_getRootNode, _ScrollSpyController_getHash, _ScrollSpyController_onIntersection, _ScrollSpyController_linkChildren_get, _ScrollSpyController_initializing, _ScrollSpyController_releaseForce, _ScrollSpyController_initIo, _ScrollSpyController_markPassed, _ScrollSpyController_setActive, _ScrollSpyController_activateHash, _ScrollSpyController_nextIntersection, _ScrollSpyController_onIo;
2
2
  import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
3
3
  import { isServer } from 'lit';
4
4
  export class ScrollSpyController {
@@ -36,6 +36,10 @@ export class ScrollSpyController {
36
36
  _ScrollSpyController_passedLinks.set(this, new Set());
37
37
  /** Ignore intersections? */
38
38
  _ScrollSpyController_force.set(this, false);
39
+ /** AbortController to cancel previous force-release listeners */
40
+ _ScrollSpyController_forceAbort.set(this, void 0);
41
+ /** Timeout handle for force-release safety valve */
42
+ _ScrollSpyController_forceTimeout.set(this, void 0);
39
43
  /** Has the intersection observer found an element? */
40
44
  _ScrollSpyController_intersected.set(this, false);
41
45
  _ScrollSpyController_root.set(this, void 0);
@@ -64,12 +68,16 @@ export class ScrollSpyController {
64
68
  hostDisconnected() {
65
69
  __classPrivateFieldGet(_a, _a, "f", _ScrollSpyController_instances_1).delete(this);
66
70
  __classPrivateFieldGet(this, _ScrollSpyController_io, "f")?.disconnect();
71
+ __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_releaseForce).call(this);
67
72
  }
68
73
  /**
69
74
  * Explicitly set the active item
70
75
  * @param link usually an `<a>`
71
76
  */
72
77
  async setActive(link) {
78
+ // Cancel any previous programmatic scroll's force state
79
+ __classPrivateFieldGet(this, _ScrollSpyController_forceAbort, "f")?.abort();
80
+ clearTimeout(__classPrivateFieldGet(this, _ScrollSpyController_forceTimeout, "f"));
73
81
  __classPrivateFieldSet(this, _ScrollSpyController_force, true, "f");
74
82
  __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_setActive).call(this, link);
75
83
  let sawActive = false;
@@ -79,11 +87,15 @@ export class ScrollSpyController {
79
87
  sawActive = true;
80
88
  }
81
89
  }
82
- await __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_nextIntersection).call(this);
83
- __classPrivateFieldSet(this, _ScrollSpyController_force, false, "f");
90
+ // Force is released when the scroll completes (scrollend event),
91
+ // or after a 3-second safety timeout
92
+ __classPrivateFieldSet(this, _ScrollSpyController_forceAbort, new AbortController(), "f");
93
+ const { signal } = __classPrivateFieldGet(this, _ScrollSpyController_forceAbort, "f");
94
+ addEventListener('scrollend', () => __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_releaseForce).call(this), { once: true, signal });
95
+ __classPrivateFieldSet(this, _ScrollSpyController_forceTimeout, setTimeout(() => __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_releaseForce).call(this), 3000), "f");
84
96
  }
85
97
  }
86
- _a = ScrollSpyController, _ScrollSpyController_tagNames = new WeakMap(), _ScrollSpyController_activeAttribute = new WeakMap(), _ScrollSpyController_io = new WeakMap(), _ScrollSpyController_passedLinks = new WeakMap(), _ScrollSpyController_force = new WeakMap(), _ScrollSpyController_intersected = new WeakMap(), _ScrollSpyController_root = new WeakMap(), _ScrollSpyController_rootMargin = new WeakMap(), _ScrollSpyController_threshold = new WeakMap(), _ScrollSpyController_intersectingTargets = new WeakMap(), _ScrollSpyController_linkTargetMap = new WeakMap(), _ScrollSpyController_getRootNode = new WeakMap(), _ScrollSpyController_getHash = new WeakMap(), _ScrollSpyController_onIntersection = new WeakMap(), _ScrollSpyController_initializing = new WeakMap(), _ScrollSpyController_instances = new WeakSet(), _ScrollSpyController_linkChildren_get = function _ScrollSpyController_linkChildren_get() {
98
+ _a = ScrollSpyController, _ScrollSpyController_tagNames = new WeakMap(), _ScrollSpyController_activeAttribute = new WeakMap(), _ScrollSpyController_io = new WeakMap(), _ScrollSpyController_passedLinks = new WeakMap(), _ScrollSpyController_force = new WeakMap(), _ScrollSpyController_forceAbort = new WeakMap(), _ScrollSpyController_forceTimeout = new WeakMap(), _ScrollSpyController_intersected = new WeakMap(), _ScrollSpyController_root = new WeakMap(), _ScrollSpyController_rootMargin = new WeakMap(), _ScrollSpyController_threshold = new WeakMap(), _ScrollSpyController_intersectingTargets = new WeakMap(), _ScrollSpyController_linkTargetMap = new WeakMap(), _ScrollSpyController_getRootNode = new WeakMap(), _ScrollSpyController_getHash = new WeakMap(), _ScrollSpyController_onIntersection = new WeakMap(), _ScrollSpyController_initializing = new WeakMap(), _ScrollSpyController_instances = new WeakSet(), _ScrollSpyController_linkChildren_get = function _ScrollSpyController_linkChildren_get() {
87
99
  if (isServer) {
88
100
  return [];
89
101
  }
@@ -91,6 +103,15 @@ _a = ScrollSpyController, _ScrollSpyController_tagNames = new WeakMap(), _Scroll
91
103
  return Array.from(this.host.querySelectorAll(__classPrivateFieldGet(this, _ScrollSpyController_tagNames, "f").join(',')))
92
104
  .filter(__classPrivateFieldGet(this, _ScrollSpyController_getHash, "f"));
93
105
  }
106
+ }, _ScrollSpyController_releaseForce = function _ScrollSpyController_releaseForce() {
107
+ if (!__classPrivateFieldGet(this, _ScrollSpyController_force, "f")) {
108
+ return;
109
+ }
110
+ __classPrivateFieldSet(this, _ScrollSpyController_force, false, "f");
111
+ __classPrivateFieldGet(this, _ScrollSpyController_forceAbort, "f")?.abort();
112
+ __classPrivateFieldSet(this, _ScrollSpyController_forceAbort, undefined, "f");
113
+ clearTimeout(__classPrivateFieldGet(this, _ScrollSpyController_forceTimeout, "f"));
114
+ __classPrivateFieldSet(this, _ScrollSpyController_forceTimeout, undefined, "f");
94
115
  }, _ScrollSpyController_initIo = async function _ScrollSpyController_initIo() {
95
116
  const rootNode = __classPrivateFieldGet(this, _ScrollSpyController_getRootNode, "f").call(this);
96
117
  if (rootNode instanceof Document || rootNode instanceof ShadowRoot) {
@@ -130,23 +151,32 @@ _a = ScrollSpyController, _ScrollSpyController_tagNames = new WeakMap(), _Scroll
130
151
  }
131
152
  }, _ScrollSpyController_nextIntersection = async function _ScrollSpyController_nextIntersection() {
132
153
  __classPrivateFieldSet(this, _ScrollSpyController_intersected, false, "f");
133
- // safeguard the loop
134
- setTimeout(() => __classPrivateFieldSet(this, _ScrollSpyController_intersected, false, "f"), 3000);
154
+ // safeguard: break the loop after 3s even if no intersection fires
155
+ const timer = setTimeout(() => __classPrivateFieldSet(this, _ScrollSpyController_intersected, true, "f"), 3000);
135
156
  while (!__classPrivateFieldGet(this, _ScrollSpyController_intersected, "f")) {
136
157
  await new Promise(requestAnimationFrame);
137
158
  }
159
+ clearTimeout(timer);
138
160
  }, _ScrollSpyController_onIo = async function _ScrollSpyController_onIo(entries) {
139
161
  if (!__classPrivateFieldGet(this, _ScrollSpyController_force, "f")) {
140
- for (const { target, boundingClientRect, intersectionRect } of entries) {
162
+ for (const entry of entries) {
163
+ const { target, boundingClientRect } = entry;
141
164
  const selector = `:is(${__classPrivateFieldGet(this, _ScrollSpyController_tagNames, "f").join(',')})[href="#${target.id}"]`;
142
165
  const link = this.host.querySelector(selector);
143
166
  if (link) {
144
- __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_markPassed).call(this, link, boundingClientRect.top < intersectionRect.top);
167
+ // Mark as passed if the element's top has reached the root's top edge.
168
+ // Using rootBounds (not intersectionRect) so that elements exactly AT the
169
+ // viewport top are correctly considered "passed" (the current section).
170
+ const rootTop = entry.rootBounds?.top ?? 0;
171
+ __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_markPassed).call(this, link, boundingClientRect.top <= rootTop + 2);
145
172
  }
146
173
  }
147
- const link = [...__classPrivateFieldGet(this, _ScrollSpyController_passedLinks, "f")];
148
- const last = link.at(-1);
149
- __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_setActive).call(this, last ?? __classPrivateFieldGet(this, _ScrollSpyController_instances, "a", _ScrollSpyController_linkChildren_get).at(0));
174
+ // Sort passed links by DOM order rather than Set insertion order
175
+ const linkOrder = __classPrivateFieldGet(this, _ScrollSpyController_instances, "a", _ScrollSpyController_linkChildren_get);
176
+ const passed = [...__classPrivateFieldGet(this, _ScrollSpyController_passedLinks, "f")]
177
+ .sort((a, b) => linkOrder.indexOf(a) - linkOrder.indexOf(b));
178
+ const last = passed.at(-1);
179
+ __classPrivateFieldGet(this, _ScrollSpyController_instances, "m", _ScrollSpyController_setActive).call(this, last ?? linkOrder.at(0));
150
180
  }
151
181
  __classPrivateFieldSet(this, _ScrollSpyController_intersected, true, "f");
152
182
  __classPrivateFieldGet(this, _ScrollSpyController_intersectingTargets, "f").clear();
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-spy-controller.js","sourceRoot":"","sources":["scroll-spy-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit';\n\nexport interface ScrollSpyControllerOptions extends IntersectionObserverInit {\n /**\n * Tag names of legal link children.\n * Legal children must have an `href` property/attribute pair, like `<a>`.\n */\n tagNames: string[];\n\n /**\n * Attribute to set on the active link element.\n * @default 'active'\n */\n activeAttribute?: string;\n\n /**\n * The root node to query content for\n * @default the host's root node\n */\n rootNode?: Node;\n\n /**\n * function to call on link children to get their URL hash (i.e. id to scroll to)\n * @default el => el.getAttribute('href');\n */\n getHash?: (el: Element) => string | null;\n\n /**\n * Optional callback for when an intersection occurs\n */\n onIntersection?(): void;\n}\n\nexport class ScrollSpyController implements ReactiveController {\n static #instances = new Set<ScrollSpyController>;\n\n static {\n if (!isServer) {\n addEventListener('scroll', () => {\n if (Math.round(window.innerHeight + window.scrollY) >= document.body.scrollHeight) {\n this.#instances.forEach(ssc => {\n ssc.#setActive(ssc.#linkChildren.at(-1));\n });\n }\n }, { passive: true });\n addEventListener('hashchange', () => {\n this.#instances.forEach(ssc => {\n ssc.#activateHash();\n });\n });\n }\n }\n\n #tagNames: string[];\n\n #activeAttribute: string;\n\n #io?: IntersectionObserver;\n\n /** Which link's targets have already scrolled past? */\n #passedLinks = new Set<Element>();\n\n /** Ignore intersections? */\n #force = false;\n\n /** Has the intersection observer found an element? */\n #intersected = false;\n\n #root: ScrollSpyControllerOptions['root'];\n\n #rootMargin?: string;\n\n #threshold: number | number[];\n\n #intersectingTargets = new Set<Element>();\n\n #linkTargetMap = new Map<Element, Element | null>();\n\n #getRootNode: () => Node | null;\n\n #getHash: (el: Element) => string | null;\n\n #onIntersection?: () => void;\n\n get #linkChildren(): Element[] {\n if (isServer) {\n return [];\n } else {\n return Array.from(this.host.querySelectorAll(this.#tagNames.join(',')))\n .filter(this.#getHash);\n }\n }\n\n get root(): Element | Document | null | undefined {\n return this.#root;\n }\n\n set root(v) {\n this.#root = v;\n this.#io?.disconnect();\n this.#initIo();\n }\n\n get rootMargin(): string | undefined {\n return this.#rootMargin;\n }\n\n set rootMargin(v) {\n this.#rootMargin = v;\n this.#io?.disconnect();\n this.#initIo();\n }\n\n get threshold(): number | number[] {\n return this.#threshold;\n }\n\n set threshold(v) {\n this.#threshold = v;\n this.#io?.disconnect();\n this.#initIo();\n }\n\n constructor(\n private host: ReactiveControllerHost & HTMLElement,\n options: ScrollSpyControllerOptions,\n ) {\n host.addController(this);\n this.#tagNames = options.tagNames;\n this.#root = options.root;\n this.#rootMargin = options.rootMargin;\n this.#activeAttribute = options.activeAttribute ?? 'active';\n this.#threshold = options.threshold ?? 0.85;\n this.#getRootNode = () => options.rootNode ?? host.getRootNode?.() ?? null;\n this.#getHash = options?.getHash ?? ((el: Element) => el.getAttribute('href'));\n this.#onIntersection = options?.onIntersection;\n }\n\n hostConnected(): void {\n ScrollSpyController.#instances.add(this);\n this.#initIo();\n }\n\n hostDisconnected(): void {\n ScrollSpyController.#instances.delete(this);\n this.#io?.disconnect();\n }\n\n #initializing = true;\n\n async #initIo() {\n const rootNode = this.#getRootNode();\n if (rootNode instanceof Document || rootNode instanceof ShadowRoot) {\n const { rootMargin, threshold, root } = this;\n this.#io = new IntersectionObserver(r => this.#onIo(r), { root, rootMargin, threshold });\n for (const link of this.#linkChildren) {\n const id = this.#getHash(link)?.replace('#', '');\n if (id) {\n const target = document.getElementById(id);\n if (target) {\n this.#io?.observe(target);\n this.#linkTargetMap.set(link, target);\n }\n }\n }\n }\n }\n\n #markPassed(link: Element, force: boolean) {\n if (force) {\n this.#passedLinks.add(link);\n } else {\n this.#passedLinks.delete(link);\n }\n }\n\n #setActive(link?: EventTarget | null) {\n for (const child of this.#linkChildren) {\n child.toggleAttribute(this.#activeAttribute, child === link);\n }\n }\n\n async #activateHash() {\n const links = this.#linkChildren;\n const { hash } = location;\n if (!hash) {\n this.setActive(links.at(0) ?? null);\n } else {\n await this.#nextIntersection();\n this.setActive(links.find(x => this.#getHash(x) === hash) ?? null);\n }\n }\n\n async #nextIntersection() {\n this.#intersected = false;\n // safeguard the loop\n setTimeout(() => this.#intersected = false, 3000);\n while (!this.#intersected) {\n await new Promise(requestAnimationFrame);\n }\n }\n\n async #onIo(entries: IntersectionObserverEntry[]) {\n if (!this.#force) {\n for (const { target, boundingClientRect, intersectionRect } of entries) {\n const selector = `:is(${this.#tagNames.join(',')})[href=\"#${target.id}\"]`;\n const link = this.host.querySelector(selector);\n if (link) {\n this.#markPassed(link, boundingClientRect.top < intersectionRect.top);\n }\n }\n const link = [...this.#passedLinks];\n const last = link.at(-1);\n this.#setActive(last ?? this.#linkChildren.at(0));\n }\n this.#intersected = true;\n this.#intersectingTargets.clear();\n for (const entry of entries) {\n if (entry.isIntersecting) {\n this.#intersectingTargets.add(entry.target);\n }\n }\n if (this.#initializing) {\n const ints = entries?.filter(x => x.isIntersecting) ?? [];\n if (this.#intersectingTargets.size > 0) {\n const [{ target = null } = {}] = ints;\n const { id } = target ?? {};\n if (id) {\n const link = this.#linkChildren.find(link => this.#getHash(link) === `#${id}`);\n if (link) {\n this.#setActive(link);\n }\n }\n }\n this.#initializing = false;\n }\n this.#onIntersection?.();\n }\n\n /**\n * Explicitly set the active item\n * @param link usually an `<a>`\n */\n public async setActive(link: EventTarget | null): Promise<void> {\n this.#force = true;\n this.#setActive(link);\n let sawActive = false;\n for (const child of this.#linkChildren) {\n this.#markPassed(child, !sawActive);\n if (child === link) {\n sawActive = true;\n }\n }\n await this.#nextIntersection();\n this.#force = false;\n }\n}\n"]}
1
+ {"version":3,"file":"scroll-spy-controller.js","sourceRoot":"","sources":["scroll-spy-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit';\n\nexport interface ScrollSpyControllerOptions extends IntersectionObserverInit {\n /**\n * Tag names of legal link children.\n * Legal children must have an `href` property/attribute pair, like `<a>`.\n */\n tagNames: string[];\n\n /**\n * Attribute to set on the active link element.\n * @default 'active'\n */\n activeAttribute?: string;\n\n /**\n * The root node to query content for\n * @default the host's root node\n */\n rootNode?: Node;\n\n /**\n * function to call on link children to get their URL hash (i.e. id to scroll to)\n * @default el => el.getAttribute('href');\n */\n getHash?: (el: Element) => string | null;\n\n /**\n * Optional callback for when an intersection occurs\n */\n onIntersection?(): void;\n}\n\nexport class ScrollSpyController implements ReactiveController {\n static #instances = new Set<ScrollSpyController>;\n\n static {\n if (!isServer) {\n addEventListener('scroll', () => {\n if (Math.round(window.innerHeight + window.scrollY) >= document.body.scrollHeight) {\n this.#instances.forEach(ssc => {\n ssc.#setActive(ssc.#linkChildren.at(-1));\n });\n }\n }, { passive: true });\n addEventListener('hashchange', () => {\n this.#instances.forEach(ssc => {\n ssc.#activateHash();\n });\n });\n }\n }\n\n #tagNames: string[];\n\n #activeAttribute: string;\n\n #io?: IntersectionObserver;\n\n /** Which link's targets have already scrolled past? */\n #passedLinks = new Set<Element>();\n\n /** Ignore intersections? */\n #force = false;\n\n /** AbortController to cancel previous force-release listeners */\n #forceAbort?: AbortController;\n\n /** Timeout handle for force-release safety valve */\n #forceTimeout?: ReturnType<typeof setTimeout>;\n\n /** Has the intersection observer found an element? */\n #intersected = false;\n\n #root: ScrollSpyControllerOptions['root'];\n\n #rootMargin?: string;\n\n #threshold: number | number[];\n\n #intersectingTargets = new Set<Element>();\n\n #linkTargetMap = new Map<Element, Element | null>();\n\n #getRootNode: () => Node | null;\n\n #getHash: (el: Element) => string | null;\n\n #onIntersection?: () => void;\n\n get #linkChildren(): Element[] {\n if (isServer) {\n return [];\n } else {\n return Array.from(this.host.querySelectorAll(this.#tagNames.join(',')))\n .filter(this.#getHash);\n }\n }\n\n get root(): Element | Document | null | undefined {\n return this.#root;\n }\n\n set root(v) {\n this.#root = v;\n this.#io?.disconnect();\n this.#initIo();\n }\n\n get rootMargin(): string | undefined {\n return this.#rootMargin;\n }\n\n set rootMargin(v) {\n this.#rootMargin = v;\n this.#io?.disconnect();\n this.#initIo();\n }\n\n get threshold(): number | number[] {\n return this.#threshold;\n }\n\n set threshold(v) {\n this.#threshold = v;\n this.#io?.disconnect();\n this.#initIo();\n }\n\n constructor(\n private host: ReactiveControllerHost & HTMLElement,\n options: ScrollSpyControllerOptions,\n ) {\n host.addController(this);\n this.#tagNames = options.tagNames;\n this.#root = options.root;\n this.#rootMargin = options.rootMargin;\n this.#activeAttribute = options.activeAttribute ?? 'active';\n this.#threshold = options.threshold ?? 0.85;\n this.#getRootNode = () => options.rootNode ?? host.getRootNode?.() ?? null;\n this.#getHash = options?.getHash ?? ((el: Element) => el.getAttribute('href'));\n this.#onIntersection = options?.onIntersection;\n }\n\n hostConnected(): void {\n ScrollSpyController.#instances.add(this);\n this.#initIo();\n }\n\n hostDisconnected(): void {\n ScrollSpyController.#instances.delete(this);\n this.#io?.disconnect();\n this.#releaseForce();\n }\n\n #initializing = true;\n\n /** Cancel force mode and clean up associated listeners */\n #releaseForce() {\n if (!this.#force) {\n return;\n }\n this.#force = false;\n this.#forceAbort?.abort();\n this.#forceAbort = undefined;\n clearTimeout(this.#forceTimeout);\n this.#forceTimeout = undefined;\n }\n\n async #initIo() {\n const rootNode = this.#getRootNode();\n if (rootNode instanceof Document || rootNode instanceof ShadowRoot) {\n const { rootMargin, threshold, root } = this;\n this.#io = new IntersectionObserver(r => this.#onIo(r), { root, rootMargin, threshold });\n for (const link of this.#linkChildren) {\n const id = this.#getHash(link)?.replace('#', '');\n if (id) {\n const target = document.getElementById(id);\n if (target) {\n this.#io?.observe(target);\n this.#linkTargetMap.set(link, target);\n }\n }\n }\n }\n }\n\n #markPassed(link: Element, force: boolean) {\n if (force) {\n this.#passedLinks.add(link);\n } else {\n this.#passedLinks.delete(link);\n }\n }\n\n #setActive(link?: EventTarget | null) {\n for (const child of this.#linkChildren) {\n child.toggleAttribute(this.#activeAttribute, child === link);\n }\n }\n\n async #activateHash() {\n const links = this.#linkChildren;\n const { hash } = location;\n if (!hash) {\n this.setActive(links.at(0) ?? null);\n } else {\n await this.#nextIntersection();\n this.setActive(links.find(x => this.#getHash(x) === hash) ?? null);\n }\n }\n\n async #nextIntersection() {\n this.#intersected = false;\n // safeguard: break the loop after 3s even if no intersection fires\n const timer = setTimeout(() => this.#intersected = true, 3000);\n while (!this.#intersected) {\n await new Promise(requestAnimationFrame);\n }\n clearTimeout(timer);\n }\n\n async #onIo(entries: IntersectionObserverEntry[]) {\n if (!this.#force) {\n for (const entry of entries) {\n const { target, boundingClientRect } = entry;\n const selector = `:is(${this.#tagNames.join(',')})[href=\"#${target.id}\"]`;\n const link = this.host.querySelector(selector);\n if (link) {\n // Mark as passed if the element's top has reached the root's top edge.\n // Using rootBounds (not intersectionRect) so that elements exactly AT the\n // viewport top are correctly considered \"passed\" (the current section).\n const rootTop = entry.rootBounds?.top ?? 0;\n this.#markPassed(link, boundingClientRect.top <= rootTop + 2);\n }\n }\n // Sort passed links by DOM order rather than Set insertion order\n const linkOrder = this.#linkChildren;\n const passed = [...this.#passedLinks]\n .sort((a, b) => linkOrder.indexOf(a) - linkOrder.indexOf(b));\n const last = passed.at(-1);\n this.#setActive(last ?? linkOrder.at(0));\n }\n this.#intersected = true;\n this.#intersectingTargets.clear();\n for (const entry of entries) {\n if (entry.isIntersecting) {\n this.#intersectingTargets.add(entry.target);\n }\n }\n if (this.#initializing) {\n const ints = entries?.filter(x => x.isIntersecting) ?? [];\n if (this.#intersectingTargets.size > 0) {\n const [{ target = null } = {}] = ints;\n const { id } = target ?? {};\n if (id) {\n const link = this.#linkChildren.find(link => this.#getHash(link) === `#${id}`);\n if (link) {\n this.#setActive(link);\n }\n }\n }\n this.#initializing = false;\n }\n this.#onIntersection?.();\n }\n\n /**\n * Explicitly set the active item\n * @param link usually an `<a>`\n */\n public async setActive(link: EventTarget | null): Promise<void> {\n // Cancel any previous programmatic scroll's force state\n this.#forceAbort?.abort();\n clearTimeout(this.#forceTimeout);\n\n this.#force = true;\n this.#setActive(link);\n\n let sawActive = false;\n for (const child of this.#linkChildren) {\n this.#markPassed(child, !sawActive);\n if (child === link) {\n sawActive = true;\n }\n }\n\n // Force is released when the scroll completes (scrollend event),\n // or after a 3-second safety timeout\n this.#forceAbort = new AbortController();\n const { signal } = this.#forceAbort;\n addEventListener('scrollend', () => this.#releaseForce(), { once: true, signal });\n this.#forceTimeout = setTimeout(() => this.#releaseForce(), 3000);\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};