stimeo-ui 0.4.0 → 0.6.0
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/CHANGELOG.md +184 -0
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/aspect_ratio_controller.d.ts +3 -5
- package/dist/controllers/aspect_ratio_controller.js +19 -11
- package/dist/controllers/aspect_ratio_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.d.ts +36 -15
- package/dist/controllers/avatar_controller.js +195 -40
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.js +5 -1
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +12 -3
- package/dist/controllers/carousel_controller.js +90 -10
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.d.ts +31 -5
- package/dist/controllers/checkbox_controller.js +136 -25
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.js +8 -3
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +1 -1
- package/dist/controllers/collapsible_controller.js +4 -1
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +9 -3
- package/dist/controllers/color_picker_controller.js +41 -11
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +1 -1
- package/dist/controllers/context_menu_controller.js +2 -2
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +5 -3
- package/dist/controllers/countdown_controller.js +5 -1
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +23 -4
- package/dist/controllers/date_range_picker_controller.js +162 -31
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +1 -1
- package/dist/controllers/direct_upload_controller.js +3 -3
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.d.ts +27 -7
- package/dist/controllers/empty_state_controller.js +107 -16
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +7 -1
- package/dist/controllers/file_dropzone_controller.js +26 -3
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +25 -5
- package/dist/controllers/flash_controller.js +161 -21
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +2 -3
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +8 -2
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +19 -2
- package/dist/controllers/frame_loading_controller.js +94 -22
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +8 -4
- package/dist/controllers/highlight_controller.js +38 -1
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +2 -2
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +5 -4
- package/dist/controllers/idle_controller.js +39 -6
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.js +2 -0
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +1 -1
- package/dist/controllers/masonry_controller.js +1 -1
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.js +5 -3
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.js +3 -1
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +46 -12
- package/dist/controllers/multi_select_controller.js +460 -151
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.d.ts +15 -13
- package/dist/controllers/network_status_controller.js +1 -3
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +29 -3
- package/dist/controllers/number_input_controller.js +455 -64
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.js +5 -1
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.js +38 -1
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +4 -4
- package/dist/controllers/password_strength_controller.js +21 -3
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +4 -4
- package/dist/controllers/persist_controller.js +24 -5
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +10 -0
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +2 -2
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +1 -2
- package/dist/controllers/portal_controller.js +10 -0
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +1 -1
- package/dist/controllers/progress_controller.js +7 -3
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +41 -15
- package/dist/controllers/radio_group_controller.js +540 -56
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +23 -0
- package/dist/controllers/range_slider_controller.js +385 -94
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +36 -31
- package/dist/controllers/rating_controller.js +274 -89
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.js +2 -0
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.js +33 -0
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.d.ts +4 -0
- package/dist/controllers/roving_controller.js +60 -5
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +7 -1
- package/dist/controllers/scroll_area_controller.js +155 -23
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.js +33 -0
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/separator_controller.js +13 -17
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +2 -2
- package/dist/controllers/skeleton_controller.js +71 -3
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +17 -1
- package/dist/controllers/slider_controller.js +325 -48
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +15 -10
- package/dist/controllers/spinner_controller.js +18 -3
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +1 -1
- package/dist/controllers/step_indicator_controller.js +3 -1
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.js +2 -0
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +12 -8
- package/dist/controllers/switch_controller.js +162 -18
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +41 -11
- package/dist/controllers/tags_input_controller.js +356 -120
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.js +1 -1
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +42 -10
- package/dist/controllers/time_picker_controller.js +296 -104
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +39 -13
- package/dist/controllers/toggle_group_controller.js +378 -55
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +5 -3
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +2 -2
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.d.ts +2 -3
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +1 -2
- package/dist/controllers/tree_view_controller.js +24 -4
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.js +3811 -1048
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +92 -4
- package/dist/inspector/cli.js +174 -6
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +234 -8
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +24 -24
- package/dist/inspector/manifest.json +573 -59
- package/dist/positioning/index.d.ts +2 -2
- package/dist/positioning/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/aria_ids.ts","../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/composition_tracker.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/option_scroll.ts","../../src/utils/roving_tabindex.ts","../../src/utils/tabindex_loan.ts","../../src/controllers/multi_select_controller.ts"],"names":[],"mappings":"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","file":"multi_select_controller.js","sourcesContent":["/**\n * Minimal id primitives for wiring ARIA relationships.\n *\n * Accessible relationships such as `aria-describedby`, `aria-errormessage`,\n * `aria-labelledby`, and `aria-activedescendant` reference their targets by DOM\n * `id`. When a controller must establish such a relationship but the consumer's\n * markup left the target without an `id`, it needs to mint one that is stable for\n * the page's lifetime and guaranteed not to collide with another generated id.\n *\n * These helpers own *only* id generation/assignment. The linking policy (which\n * attribute, what order, when to add or remove it) stays in each controller —\n * this deliberately avoids a premature generic \"ARIA linker\" abstraction.\n */\n\n/**\n * Monotonic counter backing {@link uniqueId}. Module-scoped so every generated\n * id is unique across all controller instances sharing this module in a document.\n */\nlet counter = 0;\n\n/**\n * Returns a unique, DOM-id-safe string of the form `` `${prefix}-${n}` `` where\n * `n` increases on each call.\n *\n * The counter alone guarantees uniqueness against other *generated* ids, but a\n * consumer-authored element could already own `` `${prefix}-${n}` ``. When a\n * `document` is available the candidate is therefore advanced until no element\n * with that id exists, so a generated id never collides with author markup\n * either — the minimal \"id registry\" guarantee these helpers exist to provide.\n *\n * @param prefix - Leading segment of the id (e.g. a controller's identifier).\n * Defaults to `\"stimeo\"`.\n */\nexport function uniqueId(prefix = \"stimeo\"): string {\n let candidate: string;\n do {\n counter += 1;\n candidate = `${prefix}-${counter}`;\n } while (typeof document !== \"undefined\" && document.getElementById(candidate) !== null);\n return candidate;\n}\n\n/**\n * Returns `element`'s existing `id`, or assigns it a freshly generated\n * {@link uniqueId} (with the given `prefix`) and returns that. Idempotent: an\n * element that already has an id keeps it, so consumer-authored ids are never\n * overwritten.\n *\n * @param element - The element to read or stamp an `id` onto.\n * @param prefix - Prefix forwarded to {@link uniqueId} when one must be generated.\n * @returns The element's id (existing or newly assigned).\n */\nexport function ensureId(element: Element, prefix = \"stimeo\"): string {\n if (element.id) return element.id;\n const id = uniqueId(prefix);\n element.id = id;\n return id;\n}\n","/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n","/** Minimal event shape carrying the platform's per-event composition signal. */\nexport interface CompositionSignal {\n readonly isComposing?: boolean;\n}\n\n/** Hooks that keep component-specific work outside {@link CompositionTracker}. */\nexport interface CompositionTrackerOptions {\n /** Runs after lifecycle state is set for a `compositionstart` event. */\n readonly onStart?: (event: Event) => void;\n /** Runs after lifecycle state is cleared for a `compositionend` event. */\n readonly onEnd?: (event: Event) => void;\n}\n\n/**\n * Owns IME composition listeners and transient state for one or more event targets.\n *\n * Some browsers omit `KeyboardEvent.isComposing` on the keydown that confirms a\n * conversion. Tracking `compositionstart` through `compositionend` supplies the\n * missing lifecycle signal without relying on deprecated numeric key codes.\n * Component policy stays with the consumer: filtering, validation, and submission\n * belong in the optional {@link CompositionTrackerOptions.onEnd} callback.\n *\n * @example\n * ```ts\n * #composition = new CompositionTracker({ onEnd: () => this.filter() });\n *\n * connect(): void {\n * this.#composition.observe(this.inputTarget);\n * }\n *\n * disconnect(): void {\n * this.#composition.disconnect();\n * }\n *\n * onKeydown(event: KeyboardEvent): void {\n * if (this.#composition.isComposing(event)) return;\n * }\n * ```\n */\nexport class CompositionTracker {\n readonly #observedTargets = new Set<EventTarget>();\n readonly #activeTargets = new Set<EventTarget>();\n readonly #onStart: ((event: Event) => void) | undefined;\n readonly #onEnd: ((event: Event) => void) | undefined;\n\n constructor(options: CompositionTrackerOptions = {}) {\n this.#onStart = options.onStart;\n this.#onEnd = options.onEnd;\n }\n\n /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */\n observe(target: EventTarget): void {\n if (this.#observedTargets.has(target)) return;\n target.addEventListener(\"compositionstart\", this.#handleStart);\n target.addEventListener(\"compositionend\", this.#handleEnd);\n this.#observedTargets.add(target);\n }\n\n /** Stops tracking one target and clears any active composition it owned. */\n unobserve(target: EventTarget): void {\n if (!this.#observedTargets.delete(target)) return;\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n this.#activeTargets.delete(target);\n }\n\n /** Releases every listener and clears state so reconnect starts cleanly. */\n disconnect(): void {\n for (const target of this.#observedTargets) {\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n }\n this.#observedTargets.clear();\n this.#activeTargets.clear();\n }\n\n /** True when lifecycle tracking or the current event reports composition. */\n isComposing(event?: CompositionSignal): boolean {\n return this.#activeTargets.size > 0 || event?.isComposing === true;\n }\n\n readonly #handleStart = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.add(event.currentTarget);\n this.#onStart?.(event);\n };\n\n readonly #handleEnd = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);\n this.#onEnd?.(event);\n };\n}\n","/**\n * Collapses many target callbacks from one DOM mutation into a single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element, so\n * replacing a list of N options delivers N callbacks — but the useful unit of\n * work is \"reconcile against the DOM that resulted\", once, after the batch has\n * settled. Every controller that owns a reconcilable target set needs the same\n * shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers the *initial* target callbacks\n * ahead of `connect()`. Reconciling there would compute a fallback against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","/**\n * Scroll-follow for virtually-focused listbox options.\n *\n * Listbox-style widgets that track their active option with\n * `aria-activedescendant` keep DOM focus on the input/trigger, so the\n * browser's native \"scroll the focused element into view\" never runs — in a\n * scrollable list (`max-height` + `overflow`) the active option can walk right\n * out of sight on ArrowDown/ArrowUp. This helper keeps it visible.\n *\n * It adjusts the LIST's own `scrollTop` only — deliberately not\n * `scrollIntoView({ block: \"nearest\" })`, which may also scroll ancestor\n * scrolling boxes (the page) when a floating popup pokes past a viewport\n * edge, desyncing anchored/marker-composed placements. (Command-palette uses\n * `scrollIntoView` because its page is scroll-locked behind the modal;\n * page-floating popups must use this helper instead.)\n */\n\n/**\n * Scrolls `option` into view within `list` by minimally adjusting\n * `list.scrollTop`. No-ops when the list does not actually scroll. Never\n * touches any other scrolling box.\n *\n * @param list - The scrollable listbox container.\n * @param option - The (virtually focused) option to keep visible.\n */\nexport function scrollOptionIntoView(list: HTMLElement, option: HTMLElement): void {\n if (list.scrollHeight <= list.clientHeight) return;\n const listRect = list.getBoundingClientRect();\n const optionRect = option.getBoundingClientRect();\n if (optionRect.top < listRect.top) {\n list.scrollTop -= listRect.top - optionRect.top;\n } else if (optionRect.bottom > listRect.bottom) {\n list.scrollTop += optionRect.bottom - listRect.bottom;\n }\n}\n","/**\n * Low-level roving-tabindex primitive shared by composite-widget controllers.\n *\n * The APG roving-tabindex pattern keeps a composite widget a single Tab stop:\n * exactly one item is in the Tab sequence (`tabindex=\"0\"`) while the rest are\n * removed from it (`tabindex=\"-1\"`), and the arrow keys move both DOM focus and\n * that single tabbable position together. {@link RovingTabindex} owns *only* that\n * mechanical bookkeeping — \"which one item is tabbable, and move focus there\".\n *\n * It is intentionally **policy-free**. Orientation, wrapping vs. clamping,\n * selection-follows-focus, typeahead, and `Home`/`End` semantics differ per APG\n * pattern (Radio Group, Toolbar, Rating, …); folding them into one helper would\n * flatten those widgets to a lowest common denominator and lose each pattern's\n * correctness. Those decisions therefore stay in each controller, which calls\n * {@link RovingTabindex.setActive} with an index it computed itself (optionally\n * via the pure {@link rovingMove} helper).\n *\n * @remarks\n * Items are read lazily through a getter so a controller can add or remove\n * targets (Stimulus re-scans the DOM) without re-wiring this helper.\n */\nexport class RovingTabindex {\n /** Returns the current ordered item elements; called on every operation. */\n readonly #getItems: () => HTMLElement[];\n\n /**\n * @param getItems - Returns the current ordered item elements. Called on every\n * operation so the live target list is always used.\n */\n constructor(getItems: () => HTMLElement[]) {\n this.#getItems = getItems;\n }\n\n /** Index of the currently tabbable item (`tabindex=\"0\"`), or `-1` if none. */\n get activeIndex(): number {\n return this.#getItems().findIndex((item) => item.tabIndex === 0);\n }\n\n /**\n * Makes exactly the item at `index` tabbable (`tabindex=\"0\"`) and removes every\n * other item from the Tab sequence (`tabindex=\"-1\"`). An out-of-range `index`\n * (e.g. `-1`) leaves all items at `-1`, which a controller can use to express\n * \"nothing is currently tabbable\".\n *\n * @param index - Position of the item to make tabbable.\n * @param options - Pass `{ focus: true }` to also move DOM focus to that item.\n */\n setActive(index: number, { focus = false }: { focus?: boolean } = {}): void {\n const items = this.#getItems();\n items.forEach((item, i) => {\n item.tabIndex = i === index ? 0 : -1;\n });\n if (focus) items[index]?.focus();\n }\n}\n\n/** Edge behavior for {@link rovingMove}: cycle past the ends, or stop at them. */\nexport type RovingWrap = \"wrap\" | \"clamp\";\n\n/**\n * Pure helper that resolves the target index for a one-step directional move.\n *\n * Keyboard/orientation mapping stays in the caller: it decides that a key means\n * `delta` `+1` (next) or `-1` (previous) and whether the widget should `\"wrap\"`\n * (Radio Group, Toolbar) or `\"clamp\"` at the ends.\n *\n * @param current - The index focus is moving from.\n * @param length - Number of items in the set.\n * @param delta - `+1` to move to the next item, `-1` for the previous.\n * @param wrap - `\"wrap\"` cycles around the ends; `\"clamp\"` stops at them.\n * @returns The resolved index, or `-1` when there are no items.\n */\nexport function rovingMove(\n current: number,\n length: number,\n delta: number,\n wrap: RovingWrap,\n): number {\n if (length === 0) return -1;\n const next = current + delta;\n if (wrap === \"wrap\") return (next + length) % length;\n return Math.min(length - 1, Math.max(0, next));\n}\n","/**\n * Shared bookkeeping for a `tabindex` a controller lends an element temporarily.\n *\n * A controller that must move focus somewhere the author never made focusable\n * (a landmark root, a scroll destination) reaches for the same trick: add a\n * `tabindex` just-in-time and hand it back once it is no longer needed. The\n * borrow is the easy half; the return is what the two conditions below are for.\n *\n * **Returning needs two conditions, not one.** Owning the borrow is not enough:\n * the attribute must also still hold the value this instance wrote. A consumer\n * that changed it afterwards — `tabindex=\"0\"` to make the root its own Tab stop\n * — owns it now, and removing it there silently discards authored markup. The\n * bookkeeping is dropped either way, since the loan is over regardless of who\n * ends up owning the value.\n *\n * **Never borrow over an existing value.** An element that already carries a\n * `tabindex` is the author's to control, so there is nothing to lend and nothing\n * to return.\n *\n * The registry is keyed by element, so a controller borrowing on a single\n * element (`this.element`) and one borrowing across a changing set of targets\n * use the same API — the single-element case is a set of one. It holds no\n * opinion about *when* to borrow or where focus goes next; that stays in the\n * controller.\n *\n * **The API is deliberately two methods.** This file's own doc block is dropped\n * from `dist`, but every member comment is inlined into **each** consumer entry\n * (`tsup` builds with `splitting: false`), so rationale belongs here, only the\n * contract belongs on the members, and every method no consumer calls is still\n * paid for once per consumer entry.\n *\n * @example\n * ```ts\n * readonly #tabindex = new TabindexLoan();\n *\n * #rescueFocus() {\n * this.#tabindex.lend(this.element);\n * this.element.focus();\n * }\n *\n * disconnect() {\n * this.#tabindex.returnAll();\n * }\n * ```\n */\nexport class TabindexLoan<T extends HTMLElement = HTMLElement> {\n readonly #value: string;\n readonly #lent = new Set<T>();\n\n /**\n * @param value - the `tabindex` to lend. `\"-1\"` (the default) is\n * programmatically focusable but not a Tab stop; `\"0\"` is a real Tab stop,\n * which a scroll region with no focusable content of its own needs.\n */\n constructor(value: string = \"-1\") {\n this.#value = value;\n }\n\n /** Lends `element` the value; no-ops when it already carries a `tabindex`. */\n lend(element: T): void {\n if (element.hasAttribute(\"tabindex\")) return;\n element.setAttribute(\"tabindex\", this.#value);\n this.#lent.add(element);\n }\n\n /** Takes back every loan whose value is still the one that was lent. */\n returnAll(): void {\n for (const element of this.#lent) {\n if (element.getAttribute(\"tabindex\") === this.#value) element.removeAttribute(\"tabindex\");\n }\n this.#lent.clear();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { ensureId } from \"../utils/aria_ids\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { CompositionTracker } from \"../utils/composition_tracker\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { scrollOptionIntoView } from \"../utils/option_scroll\";\nimport { RovingTabindex } from \"../utils/roving_tabindex\";\nimport { TabindexLoan } from \"../utils/tabindex_loan\";\n\n/**\n * Headless, accessible multi-select combobox with chips.\n *\n * Markup contract (identifier: `stimeo--multi-select`):\n * <div data-controller=\"stimeo--multi-select\">\n * <ul data-stimeo--multi-select-target=\"tags\" aria-label=\"Selected\"></ul>\n * <input type=\"text\" role=\"combobox\" aria-expanded=\"false\"\n * aria-autocomplete=\"list\" aria-controls=\"ms-list\"\n * data-stimeo--multi-select-target=\"input\"\n * data-action=\"input->stimeo--multi-select#filter\n * keydown->stimeo--multi-select#onKeydown\n * focus->stimeo--multi-select#open\" />\n * <ul id=\"ms-list\" role=\"listbox\" aria-multiselectable=\"true\" hidden\n * data-stimeo--multi-select-target=\"list\">\n * <li id=\"ms-opt-1\" role=\"option\" aria-selected=\"false\" data-value=\"apple\"\n * data-stimeo--multi-select-target=\"option\"\n * data-action=\"click->stimeo--multi-select#toggleOption\">Apple</li>\n * </ul>\n * <span role=\"status\" aria-live=\"polite\" class=\"visually-hidden\"\n * data-stimeo--multi-select-target=\"status\"></span>\n * <!-- Optional: submit the selection as name=\"fruits[]\" hidden inputs. -->\n * <div data-stimeo--multi-select-target=\"fields\"></div>\n * <template data-stimeo--multi-select-target=\"tagTemplate\">…</template>\n * </div>\n *\n * Implements the WAI-ARIA APG **Combobox** pattern in its list-autocomplete,\n * multi-select form. Focus stays on the input; the active option is tracked with\n * `aria-activedescendant` and selection with `aria-selected`. Selected options are\n * mirrored as removable chips. For single selection use {@link ListboxController}\n * or Combobox; for free-text tags use {@link TagsInputController}.\n *\n * Behavior provided:\n * - Typing filters options by substring and opens the list; `ArrowDown`/`ArrowUp`\n * (wrapping), `Home`/`End` move the active option; `Enter` toggles it (the list\n * stays open); `Escape`/`Tab`/outside click close.\n * - Toggling syncs `aria-selected`, adds/removes a `Remove {label}` chip, mirrors\n * the live region, and dispatches `stimeo--multi-select:change` with `values`;\n * filtering dispatches `stimeo--multi-select:filter` for async candidates.\n * - The chips are one roving Tab stop: `ArrowLeft`/`ArrowRight` move between them,\n * `Delete`/`Backspace` remove the focused chip, and `Backspace` on an empty\n * input removes the last; removal re-homes focus to a neighbor or the input.\n * - `max` caps the selection (`0` = unlimited).\n * - With a `fields` target the selected values are mirrored into named hidden\n * inputs (default name `options[]`), so the selection submits with a normal\n * form and no consumer JS — parity with {@link TagsInputController}. An optional\n * `form` value sets the hidden inputs' `form` attribute, associating them with a\n * `<form>` by id even when the picker lives outside it. Without a `fields`\n * target the hidden inputs are simply not written.\n */\nexport class MultiSelectController extends Controller<HTMLElement> {\n static override targets = [\n \"input\",\n \"list\",\n \"option\",\n \"tags\",\n \"tag\",\n \"tagTemplate\",\n \"status\",\n \"fields\",\n ];\n static override values = {\n max: { type: Number, default: 0 },\n name: { type: String, default: \"options[]\" },\n form: { type: String, default: \"\" },\n };\n static actions = [\"close\", \"filter\", \"onKeydown\", \"open\", \"toggleOption\"] as const;\n static events = [\"change\", \"filter\"] as const;\n\n declare readonly inputTarget: HTMLInputElement;\n declare readonly listTarget: HTMLElement;\n declare readonly optionTargets: HTMLElement[];\n declare readonly tagsTarget: HTMLElement;\n declare readonly tagTargets: HTMLElement[];\n declare readonly tagTemplateTarget: HTMLTemplateElement;\n declare readonly statusTarget: HTMLElement;\n declare readonly fieldsTarget: HTMLElement;\n declare readonly hasListTarget: boolean;\n declare readonly hasInputTarget: boolean;\n declare readonly hasTagsTarget: boolean;\n declare readonly hasTagTemplateTarget: boolean;\n declare readonly hasStatusTarget: boolean;\n declare readonly hasFieldsTarget: boolean;\n\n declare maxValue: number;\n declare nameValue: string;\n declare formValue: string;\n declare readonly hasFormValue: boolean;\n\n /** Stable id of the active option; the current target is resolved from the DOM. */\n #activeOptionId: string | null = null;\n /** Whether the root borrowed a tab stop to catch focus, so teardown can undo it. */\n readonly #tabindex = new TabindexLoan();\n /** Prevents initial/teardown target callbacks from mutating authored DOM. */\n #connected = false;\n /** Collapses one batch of target callbacks into a single final-DOM reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n /** Absorbs the browser's redundant final input after compositionend. */\n #ignorePostCompositionInput = false;\n /** Owns IME lifecycle state; confirmed text emits one filter result. */\n readonly #composition = new CompositionTracker({\n onStart: () => {\n this.#ignorePostCompositionInput = false;\n },\n onEnd: () => {\n // Apply the confirmed query even in browsers that omit a final input event.\n // When the usual final input follows synchronously, absorb it so async\n // consumers receive one filter event for the confirmed text, not two.\n this.#ignorePostCompositionInput = true;\n queueMicrotask(() => {\n this.#ignorePostCompositionInput = false;\n });\n this.filter();\n },\n });\n readonly #roving = new RovingTabindex(() => this.#removeButtons);\n\n /** Starts closed, syncs chips for any pre-selected options, and listens out. */\n override connect(): void {\n if (this.hasInputTarget) this.#composition.observe(this.inputTarget);\n this.#normalizeSelection();\n this.close();\n if (this.hasTagsTarget) {\n this.tagsTarget.addEventListener(\"keydown\", this.#onTagKeydown);\n this.tagsTarget.addEventListener(\"click\", this.#onTagClick);\n this.#rebuildTags();\n }\n // Seed the hidden fields from any pre-selected options so the form submits\n // the initial selection without an interaction.\n this.#syncFields();\n document.addEventListener(\"click\", this.#onOutsideClick, true);\n this.#connected = true;\n this.#reconcile.activate();\n }\n\n /**\n * Derives the chips from the selected options, idempotently: a Turbo Drive cache\n * restore or morph can re-connect with chips already in the DOM, so they are\n * cleared before deriving afresh to avoid duplicates.\n */\n #rebuildTags(): void {\n if (!this.hasTagsTarget) return;\n for (const tag of this.tagTargets) tag.remove();\n for (const option of this.#selectedOptions) this.#appendTag(option);\n if (this.#removeButtons.length > 0) this.#roving.setActive(0);\n }\n\n /** Tears down document and chip listeners on disconnect (Turbo included). */\n override disconnect(): void {\n this.#connected = false;\n this.#reconcile.cancel();\n this.#composition.disconnect();\n this.#ignorePostCompositionInput = false;\n if (this.hasTagsTarget) {\n this.tagsTarget.removeEventListener(\"keydown\", this.#onTagKeydown);\n this.tagsTarget.removeEventListener(\"click\", this.#onTagClick);\n }\n document.removeEventListener(\"click\", this.#onOutsideClick, true);\n this.#releaseTabindex();\n }\n\n /** Reconciles active state after an option target is added at runtime. */\n optionTargetConnected(): void {\n this.#scheduleOptionReconcile();\n }\n\n /** Cleans a removed target and reconciles active state against the surviving DOM. */\n optionTargetDisconnected(option: HTMLElement): void {\n if (!this.#connected) return;\n // `#setActive` can only scan current targets; clean the old node explicitly in\n // case a Turbo morph reuses it elsewhere.\n option.removeAttribute(\"data-active\");\n this.#scheduleOptionReconcile();\n }\n\n /** Schedules one reconciliation after all callbacks in the mutation batch. */\n #scheduleOptionReconcile(): void {\n this.#reconcile.schedule();\n }\n\n /**\n * Keeps a surviving/same-id active target, otherwise falls back to the first\n * visible one — and brings the derived state back in line with the new option set.\n *\n * The baseline pass fills in any missing `aria-selected`, and the chips and\n * hidden fields are re-derived from it, because the options are the truth source\n * for the selection. The chips are rebuilt **only when the selected value set\n * actually moved**: the rebuild removes and recreates every chip, so running it\n * for an unrelated option would drop focus from a chip's remove button to\n * `<body>`, losing the keyboard user's place for something that did not concern\n * them.\n */\n #reconcileOptions(): void {\n const visible = this.#visibleOptions;\n const active = this.#activeOption;\n const next = this.#isClosed ? null : active && !active.hidden ? active : (visible[0] ?? null);\n this.#setActive(next);\n this.#reflectEmpty();\n\n this.#normalizeSelection();\n const selected = this.#selectedOptions;\n // Compared as a set, not a sequence: the chips are in selection order while\n // the options are in DOM order, so an index-wise comparison reports a change\n // for every selection the user made out of DOM order and rebuilds forever.\n const nextValues = selected.map((option) => this.#optionValue(option)).sort();\n const tagValues = this.tagTargets.map((tag) => tag.dataset.value ?? \"\").sort();\n const unchanged =\n nextValues.length === tagValues.length &&\n nextValues.every((value, index) => value === tagValues[index]);\n if (unchanged) this.#refreshTagLabels(selected);\n else this.#rebuildTags();\n this.#syncFields();\n }\n\n /**\n * Gives every option an explicit `aria-selected`, without changing which ones\n * the author chose. An absent value means \"not selectable\" in ARIA, so a\n * forgotten attribute hides a selectable option. Several `true` is the normal\n * case here — the list is `aria-multiselectable` — so nothing is dropped.\n */\n #normalizeSelection(): void {\n for (const option of this.optionTargets) {\n if (option.getAttribute(\"aria-selected\") !== \"true\") {\n option.setAttribute(\"aria-selected\", \"false\");\n }\n }\n }\n\n /**\n * Tracks an input added initially or after connect, and makes it describe the\n * widget that is actually on screen: a swapped-in input arrives with the\n * authored ARIA of a fresh node while this controller still holds the popup\n * state, and the open path cannot repair that (it seeds an active option only\n * when there is none), so a live list would go unannounced.\n */\n inputTargetConnected(input: HTMLInputElement): void {\n this.#composition.observe(input);\n input.setAttribute(\"aria-expanded\", String(!this.#isClosed));\n const active = this.#activeOption;\n if (active) input.setAttribute(\"aria-activedescendant\", ensureId(active, \"stimeo-ms-opt\"));\n else input.removeAttribute(\"aria-activedescendant\");\n }\n\n /** Removes composition listeners when the active input is replaced or removed. */\n inputTargetDisconnected(input: HTMLInputElement): void {\n this.#composition.unobserve(input);\n this.#ignorePostCompositionInput = false;\n }\n\n /** Filters confirmed input text, opens, and re-seeds the active option. */\n filter(event?: InputEvent): void {\n if (event && this.#ignorePostCompositionInput) {\n this.#ignorePostCompositionInput = false;\n return;\n }\n if (this.#composition.isComposing(event)) return;\n const query = this.inputTarget.value.trim().toLowerCase();\n for (const option of this.optionTargets) {\n const label = (option.textContent ?? \"\").trim().toLowerCase();\n option.hidden = query !== \"\" && !label.includes(query);\n }\n this.open();\n const visible = this.#visibleOptions;\n this.#reflectEmpty();\n this.#setActive(visible[0] ?? null);\n this.dispatch(\"filter\", { detail: { query } });\n }\n\n /**\n * Opens the list and activates the first visible option when none is active.\n *\n * Needs the input, which owns `aria-expanded` and `aria-activedescendant`: a\n * list shown without one is a popup no assistive technology is told about. So\n * opening is skipped entirely, where {@link close} still closes.\n */\n open(): void {\n if (!this.hasListTarget || !this.hasInputTarget) return;\n this.listTarget.hidden = false;\n this.inputTarget.setAttribute(\"aria-expanded\", \"true\");\n if (!this.#activeOption) this.#setActive(this.#visibleOptions[0] ?? null);\n }\n\n /**\n * Closes the list and clears the active option.\n *\n * Survives a missing input in both directions. `connect()` calls this second,\n * so dereferencing the input here would throw before the chips, the roving\n * seed, the chip listeners, the hidden fields and the outside-click listener —\n * and Stimulus keeps the controller alive after that throw, so none of them\n * would ever run and the selection would silently stop submitting. An input\n * removed while the list is open must still let it come down *and* forget its\n * active option, so only the `aria-expanded` write is guarded.\n */\n close(): void {\n if (!this.hasListTarget) return;\n this.listTarget.hidden = true;\n this.#setActive(null);\n if (!this.hasInputTarget) return;\n this.inputTarget.setAttribute(\"aria-expanded\", \"false\");\n }\n\n /** Routes input keyboard interaction per the multi-select combobox model. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key must not ALSO open the\n // list or move the active option — composition depends on this yield.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n // Ignore keys fired during IME composition: the `Enter` that confirms a\n // candidate (and arrows that move within it) must not select an option or\n // navigate the chip list. Controller-owned lifecycle state covers confirming\n // events that omit the standard per-event signal.\n if (this.#composition.isComposing(event)) return;\n // Target callbacks are MutationObserver-driven. Resolve a replacement now, or\n // clear a removed id now, so a synchronously dispatched key cannot commit a\n // detached node before the callback gets its turn.\n this.#reconcileActiveForInteraction();\n // Logical, not physical. The key is normalised rather than a new case added:\n // the two horizontal branches are not mirror images — only one guards its\n // edge, and the other hands focus back to the input — so swapping the key\n // keeps each branch, guards and all, with its own direction. Both handlers\n // read the same element on purpose; probing the focused child would let the\n // input and the chips disagree at the boundary between them.\n switch (logicalArrowKey(event.key, this.element)) {\n case \"ArrowDown\":\n event.preventDefault();\n if (this.#isClosed) this.open();\n else this.#moveActive(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (this.#isClosed) this.open();\n else this.#moveActive(-1);\n break;\n case \"Home\":\n if (!this.#isClosed) {\n event.preventDefault();\n this.#setActive(this.#visibleOptions[0] ?? null);\n }\n break;\n case \"End\": {\n if (!this.#isClosed) {\n event.preventDefault();\n const visible = this.#visibleOptions;\n this.#setActive(visible[visible.length - 1] ?? null);\n }\n break;\n }\n case \"Enter\": {\n const active = this.#activeOption;\n if (!this.#isClosed && active) {\n event.preventDefault();\n this.#toggleSelection(active);\n }\n break;\n }\n case \"Escape\":\n // A press an inner handler already owned is yielded at the top of this\n // handler. Escape is consumed only while the list is open: with it closed\n // the press stays free for the shared resolver, so an enclosing dialog\n // still closes from a focused input.\n if (this.#isClosed) break;\n event.preventDefault();\n this.close();\n break;\n case \"Backspace\":\n if (this.inputTarget.value === \"\") {\n const buttons = this.#removeButtons;\n if (buttons.length > 0) {\n event.preventDefault();\n this.#removeTagAt(buttons.length - 1);\n }\n }\n break;\n case \"ArrowLeft\":\n if (this.inputTarget.value === \"\" && this.#removeButtons.length > 0) {\n event.preventDefault();\n this.#roving.setActive(this.#removeButtons.length - 1, { focus: true });\n }\n break;\n case \"Tab\":\n this.close();\n break;\n default:\n break;\n }\n }\n\n /**\n * Toggles the clicked option's selection. Bound via `data-action`. Focus is\n * re-homed to the input afterwards: options are non-focusable, so the click blurs\n * the input to `body` — and with the list deliberately staying open, every\n * keyboard affordance (Escape, arrows, typing) is bound to the input and would\n * otherwise go dead until the user clicks back in (\"focus stays on the input\").\n */\n toggleOption(event: Event): void {\n const option = (event.currentTarget as HTMLElement).closest<HTMLElement>('[role=\"option\"]');\n if (!option || !this.optionTargets.includes(option)) return;\n this.#toggleSelection(option);\n this.#focusInput();\n }\n\n /**\n * Re-homes focus to the input, or leaves it where it is when there is none.\n *\n * All three callers run *after* an option or a chip already took focus, and all\n * three are reachable without an input — options and chips carry their own\n * `data-action`. Throwing here would leave the chip removed but focus stranded\n * on a detached button.\n */\n #focusInput(): void {\n if (this.hasInputTarget) this.inputTarget.focus();\n }\n\n /**\n * Re-homes focus after the last chip was removed: to the input, else the root.\n *\n * Unlike the other {@link #focusInput} callers, the element that held focus has\n * just left the DOM, so \"leave it alone\" is not an option — the browser already\n * dropped it to `<body>`. The root borrows a `tabindex=\"-1\"` just-in-time (not a\n * Tab stop, handed back on teardown). Focus that landed on a real element is\n * left alone, so a chip removed out of band never steals it.\n */\n #focusAfterLastTag(): void {\n if (this.hasInputTarget) {\n this.inputTarget.focus();\n return;\n }\n const doc = this.element.ownerDocument;\n const active = doc.activeElement;\n // Anything else still holding focus keeps it; only `<body>`, the root element\n // and a detached node mean the browser had nowhere to put it.\n if (active && active !== doc.body && active !== doc.documentElement && active.isConnected) {\n return;\n }\n this.#tabindex.lend(this.element);\n this.element.focus();\n }\n\n /**\n * Returns the borrowed tab stop. Owning the borrow is not enough — the value\n * has to still be the one this instance wrote, since a consumer that changed it\n * afterwards owns it now.\n */\n #releaseTabindex(): void {\n this.#tabindex.returnAll();\n }\n\n /**\n * Removes the chip whose remove button was clicked, deselecting its option.\n * Delegated on the tags container (like `#onTagKeydown`) rather than bound\n * per chip via `data-action`, so it works the instant a chip is appended without\n * waiting on Stimulus to wire a freshly created element.\n */\n readonly #onTagClick = (event: MouseEvent): void => {\n const button = (event.target as HTMLElement).closest(\"button\");\n if (!button || !this.tagsTarget.contains(button)) return;\n const index = this.#removeButtons.indexOf(button as HTMLButtonElement);\n if (index !== -1) this.#removeTagAt(index);\n };\n\n /** Moves the active option by `delta` among visible options, wrapping. */\n #moveActive(delta: number): void {\n const visible = this.#visibleOptions;\n if (visible.length === 0) return;\n const current = this.#activeOption ? visible.indexOf(this.#activeOption) : -1;\n const candidate = current === -1 ? (delta > 0 ? 0 : visible.length - 1) : current + delta;\n const next = (candidate + visible.length) % visible.length;\n this.#setActive(visible[next] ?? null);\n }\n\n /** Selects/deselects `option`, honoring `max`, and syncs chip + live region. */\n #toggleSelection(option: HTMLElement): void {\n const selected = option.getAttribute(\"aria-selected\") === \"true\";\n if (!selected && this.maxValue > 0 && this.#selectedOptions.length >= this.maxValue) {\n return;\n }\n option.setAttribute(\"aria-selected\", String(!selected));\n if (selected) {\n this.#removeTagFor(option);\n } else {\n this.#appendTag(option);\n }\n this.#announce(this.#optionLabel(option));\n this.#refreshRoving();\n this.#syncFields();\n this.dispatch(\"change\", { detail: { values: this.#values } });\n }\n\n /**\n * Re-reads each chip's label from its option, in place.\n *\n * The value order alone does not say the chips are still correct: a server can\n * re-render the same candidate with a new label (\"Apple\" → \"Green Apple\"), and\n * the chip text and its `Remove {label}` name are both derived from the option.\n * Updating them here keeps the rebuild — which would drop focus — for the case\n * that actually needs it, a changed selection.\n */\n #refreshTagLabels(selected: readonly HTMLElement[]): void {\n // Paired by value rather than by position: the chips are in selection order\n // and the options in DOM order, so the two lists hold the same values in\n // different places and an index-wise pairing would relabel the wrong chip.\n const options = new Map(selected.map((option) => [this.#optionValue(option), option]));\n for (const tag of this.tagTargets) {\n const option = options.get(tag.dataset.value ?? \"\");\n if (!option) continue;\n const text = this.#optionLabel(option);\n const label = tag.querySelector<HTMLElement>('[data-multi-select-slot=\"label\"]');\n if (label && label.textContent !== text) label.textContent = text;\n const button = tag.querySelector(\"button\");\n const name = `Remove ${text}`;\n if (button && button.getAttribute(\"aria-label\") !== name) {\n button.setAttribute(\"aria-label\", name);\n }\n }\n }\n\n /** Builds one chip from the template for `option`. */\n #appendTag(option: HTMLElement): void {\n if (!this.hasTagTemplateTarget || !this.hasTagsTarget) return;\n const fragment = this.tagTemplateTarget.content.cloneNode(true) as DocumentFragment;\n const tag = fragment.querySelector<HTMLElement>('[data-stimeo--multi-select-target=\"tag\"]');\n const label = fragment.querySelector<HTMLElement>('[data-multi-select-slot=\"label\"]');\n const button = fragment.querySelector<HTMLButtonElement>(\"button\");\n if (!tag || !button) return;\n const text = this.#optionLabel(option);\n tag.dataset.value = this.#optionValue(option);\n if (label) label.textContent = text;\n button.setAttribute(\"aria-label\", `Remove ${text}`);\n button.tabIndex = -1;\n this.tagsTarget.appendChild(fragment);\n }\n\n /** Removes the chip mirroring `option`, if present. */\n #removeTagFor(option: HTMLElement): void {\n const value = this.#optionValue(option);\n const tag = this.tagTargets.find((candidate) => candidate.dataset.value === value);\n tag?.remove();\n }\n\n /** Removes chip `index` and deselects its option, re-homing focus. */\n #removeTagAt(index: number): void {\n const tag = this.tagTargets[index];\n if (!tag) return;\n const value = tag.dataset.value ?? \"\";\n // Match by the option's stable value, which falls back to its label when no\n // data-value is present, so a label-keyed chip still finds its option.\n const option = this.optionTargets.find((candidate) => this.#optionValue(candidate) === value);\n if (option) option.setAttribute(\"aria-selected\", \"false\");\n tag.remove();\n // Prefer the option's display label for the announcement (e.g. \"Apple\"),\n // which can differ from its data-value (e.g. \"apple\").\n this.#announce(option ? this.#optionLabel(option) : value);\n this.#refreshRoving();\n this.#syncFields();\n this.dispatch(\"change\", { detail: { values: this.#values } });\n\n const remaining = this.#removeButtons;\n if (remaining.length === 0) {\n this.#focusAfterLastTag();\n } else {\n this.#roving.setActive(Math.min(index, remaining.length - 1), { focus: true });\n }\n }\n\n /** Arrow navigation and deletion within the chip list (delegated). */\n readonly #onTagKeydown = (event: KeyboardEvent): void => {\n // A descendant widget that already claimed the key must not ALSO move the\n // chip focus — composition depends on this yield. Chips render from the\n // consumer's template, so an arbitrary widget can live inside one.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n const button = (event.target as HTMLElement).closest(\"button\");\n if (!button) return;\n const buttons = this.#removeButtons;\n const index = buttons.indexOf(button);\n if (index === -1) return;\n // Logical, not physical. The key is normalised rather than a new case added:\n // the two horizontal branches are not mirror images — only one guards its\n // edge, and the other hands focus back to the input — so swapping the key\n // keeps each branch, guards and all, with its own direction. Both handlers\n // read the same element on purpose; probing the focused child would let the\n // input and the chips disagree at the boundary between them.\n switch (logicalArrowKey(event.key, this.element)) {\n case \"ArrowLeft\":\n if (index > 0) {\n event.preventDefault();\n this.#roving.setActive(index - 1, { focus: true });\n }\n break;\n case \"ArrowRight\":\n event.preventDefault();\n if (index < buttons.length - 1) this.#roving.setActive(index + 1, { focus: true });\n else this.#focusInput();\n break;\n case \"Delete\":\n case \"Backspace\":\n event.preventDefault();\n this.#removeTagAt(index);\n break;\n default:\n break;\n }\n };\n\n /**\n * Marks `option` active via `data-active` and the input's\n * `aria-activedescendant` (the attribute is removed, not emptied, when null).\n *\n * The state half runs even with no input, so a `close()` that cannot touch ARIA\n * still clears it: {@link open} seeds an active option only when there is none,\n * so a stale one makes the next open skip the seeding and a replacement input\n * gets no `aria-activedescendant` at all.\n */\n #setActive(option: HTMLElement | null): void {\n const activeId = option ? ensureId(option, \"stimeo-ms-opt\") : null;\n this.#activeOptionId = activeId;\n for (const candidate of this.optionTargets) {\n candidate.toggleAttribute(\"data-active\", candidate === option);\n }\n // Virtual focus never triggers the browser's native focus-scrolling, so a\n // scrollable list must follow the active option itself (list-only scroll).\n if (option && this.hasListTarget) scrollOptionIntoView(this.listTarget, option);\n if (!this.hasInputTarget) return;\n if (activeId !== null) {\n this.inputTarget.setAttribute(\"aria-activedescendant\", activeId);\n } else {\n this.inputTarget.removeAttribute(\"aria-activedescendant\");\n }\n }\n\n /** Repairs only active identity before a key; the fallback waits for the target callback. */\n #reconcileActiveForInteraction(): void {\n const activeId = this.#activeOptionId;\n if (activeId === null) return;\n const resolved = this.#activeOption;\n const active = resolved && !resolved.hidden ? resolved : null;\n const marked = this.optionTargets.filter((candidate) => candidate.hasAttribute(\"data-active\"));\n const idref = this.hasInputTarget\n ? this.inputTarget.getAttribute(\"aria-activedescendant\")\n : null;\n if (!active || marked.length !== 1 || marked[0] !== active || idref !== activeId) {\n this.#setActive(active);\n }\n }\n\n /** Reflects whether the open list currently has no visible option targets. */\n #reflectEmpty(): void {\n this.element.toggleAttribute(\n \"data-stimeo--multi-select-empty\",\n !this.#isClosed && this.#visibleOptions.length === 0,\n );\n }\n\n /**\n * Mirrors the selected values into named hidden inputs under the `fields`\n * target so the selection submits with a normal form (parity with tags-input).\n * No-ops without a `fields` target. When the\n * `form` value is set, each input gets a matching `form` attribute so the picker\n * can submit with a `<form>` it lives outside of.\n */\n #syncFields(): void {\n if (!this.hasFieldsTarget) return;\n this.fieldsTarget.replaceChildren(\n ...this.#values.map((value) => {\n const input = document.createElement(\"input\");\n input.type = \"hidden\";\n input.name = this.nameValue;\n input.value = value;\n if (this.hasFormValue && this.formValue !== \"\") input.setAttribute(\"form\", this.formValue);\n return input;\n }),\n );\n }\n\n /** Keeps exactly one chip remove button tabbable after the set changes. */\n #refreshRoving(): void {\n if (this.#removeButtons.length > 0 && this.#roving.activeIndex === -1)\n this.#roving.setActive(0);\n }\n\n /** Mirrors the changed option label into the live region. */\n #announce(text: string): void {\n if (this.hasStatusTarget) this.statusTarget.textContent = text;\n }\n\n /** Closes the list on a click outside the controller element. */\n readonly #onOutsideClick = (event: MouseEvent): void => {\n if (!this.#isClosed && !this.element.contains(event.target as Node)) this.close();\n };\n\n /** Trimmed visible label of an option. */\n #optionLabel(option: HTMLElement): string {\n return (option.textContent ?? \"\").trim();\n }\n\n /** An option's stable value: its `data-value`, else its display label. */\n #optionValue(option: HTMLElement): string {\n return option.dataset.value ?? this.#optionLabel(option);\n }\n\n /** Options not hidden by the current filter. */\n get #visibleOptions(): HTMLElement[] {\n return this.optionTargets.filter((option) => !option.hidden);\n }\n\n /** Current active target resolved by stable id, never a detached node reference. */\n get #activeOption(): HTMLElement | null {\n const activeId = this.#activeOptionId;\n if (activeId === null) return null;\n return this.optionTargets.find((option) => option.id === activeId) ?? null;\n }\n\n /** Options currently selected. */\n get #selectedOptions(): HTMLElement[] {\n return this.optionTargets.filter((option) => option.getAttribute(\"aria-selected\") === \"true\");\n }\n\n /** Selected values in option order. */\n get #values(): string[] {\n return this.#selectedOptions.map((option) => this.#optionValue(option));\n }\n\n /** The chip remove buttons in order (the roving navigation set). */\n get #removeButtons(): HTMLButtonElement[] {\n return this.hasTagsTarget\n ? Array.from(this.tagsTarget.querySelectorAll<HTMLButtonElement>(\"button\"))\n : [];\n }\n\n /** Whether the list is currently hidden. */\n get #isClosed(): boolean {\n return !this.hasListTarget || this.listTarget.hidden !== false;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/announce.ts","../../src/utils/aria_ids.ts","../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/roving_tabindex.ts","../../src/utils/chip_row.ts","../../src/utils/composition_tracker.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/option_scroll.ts","../../src/utils/before_cache_reset.ts","../../src/utils/tabindex_loan.ts","../../src/controllers/multi_select_controller.ts"],"names":["entry","button"],"mappings":"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","file":"multi_select_controller.js","sourcesContent":["/**\n * Sends one message to the page's shared `stimeo--announcer`.\n *\n * A component that has to reach assistive tech does not carry a live region of its\n * own: a region only announces what changes *after* assistive tech already knows\n * about it, which a region that appears (or is un-hidden) with its message cannot\n * satisfy. The one region that can is the announcer sitting in the page from the\n * start, so state changes are handed to it as an event and it does the reading.\n *\n * The event goes to `window` because the announcer is usually a sibling high in the\n * document rather than an ancestor of the component dispatching it.\n *\n * Wording comes from the consumer — the library ships no English strings — so an\n * empty message is silently dropped and nothing is announced.\n *\n * @example\n * ```ts\n * announce(this.announceTextValue, { assertive: false });\n * ```\n */\nexport function announce(message: string, options: { assertive?: boolean } = {}): void {\n const text = message.trim();\n if (text.length === 0) return;\n window.dispatchEvent(\n new CustomEvent(\"stimeo--announcer:announce\", {\n detail: { message: text, assertive: options.assertive === true },\n }),\n );\n}\n\n/**\n * Fills `{name}` placeholders in an announcement template from `values`.\n *\n * The same substitution the value-text templates use, so a consumer writes\n * `\"{percent}% complete\"` in one attribute and gets the same rules everywhere. A\n * placeholder with no matching entry is left as authored rather than blanked, which\n * keeps a typo visible instead of silently swallowing the word.\n */\nexport function fillTemplate(template: string, values: Record<string, string | number>): string {\n return template.replace(/\\{([a-zA-Z][a-zA-Z0-9]*)\\}/g, (match, name: string) => {\n const replacement = values[name];\n return replacement === undefined ? match : String(replacement);\n });\n}\n","/**\n * Minimal id primitives for wiring ARIA relationships.\n *\n * Accessible relationships such as `aria-describedby`, `aria-errormessage`,\n * `aria-labelledby`, and `aria-activedescendant` reference their targets by DOM\n * `id`. When a controller must establish such a relationship but the consumer's\n * markup left the target without an `id`, it needs to mint one that is stable for\n * the page's lifetime and guaranteed not to collide with another generated id.\n *\n * These helpers own *only* id generation/assignment. The linking policy (which\n * attribute, what order, when to add or remove it) stays in each controller —\n * this deliberately avoids a premature generic \"ARIA linker\" abstraction.\n */\n\n/**\n * Monotonic counter backing {@link uniqueId}. Module-scoped so every generated\n * id is unique across all controller instances sharing this module in a document.\n */\nlet counter = 0;\n\n/**\n * Returns a unique, DOM-id-safe string of the form `` `${prefix}-${n}` `` where\n * `n` increases on each call.\n *\n * The counter alone guarantees uniqueness against other *generated* ids, but a\n * consumer-authored element could already own `` `${prefix}-${n}` ``. When a\n * `document` is available the candidate is therefore advanced until no element\n * with that id exists, so a generated id never collides with author markup\n * either — the minimal \"id registry\" guarantee these helpers exist to provide.\n *\n * @param prefix - Leading segment of the id (e.g. a controller's identifier).\n * Defaults to `\"stimeo\"`.\n */\nexport function uniqueId(prefix = \"stimeo\"): string {\n let candidate: string;\n do {\n counter += 1;\n candidate = `${prefix}-${counter}`;\n } while (typeof document !== \"undefined\" && document.getElementById(candidate) !== null);\n return candidate;\n}\n\n/**\n * Returns `element`'s existing `id`, or assigns it a freshly generated\n * {@link uniqueId} (with the given `prefix`) and returns that. Idempotent: an\n * element that already has an id keeps it, so consumer-authored ids are never\n * overwritten.\n *\n * @param element - The element to read or stamp an `id` onto.\n * @param prefix - Prefix forwarded to {@link uniqueId} when one must be generated.\n * @returns The element's id (existing or newly assigned).\n */\nexport function ensureId(element: Element, prefix = \"stimeo\"): string {\n if (element.id) return element.id;\n const id = uniqueId(prefix);\n element.id = id;\n return id;\n}\n","/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n","/**\n * Low-level roving-tabindex primitive shared by composite-widget controllers.\n *\n * The APG roving-tabindex pattern keeps a composite widget a single Tab stop:\n * exactly one item is in the Tab sequence (`tabindex=\"0\"`) while the rest are\n * removed from it (`tabindex=\"-1\"`), and the arrow keys move both DOM focus and\n * that single tabbable position together. {@link RovingTabindex} owns *only* that\n * mechanical bookkeeping — \"which one item is tabbable, and move focus there\".\n *\n * It is intentionally **policy-free**. Orientation, wrapping vs. clamping,\n * selection-follows-focus, typeahead, and `Home`/`End` semantics differ per APG\n * pattern (Radio Group, Toolbar, Rating, …); folding them into one helper would\n * flatten those widgets to a lowest common denominator and lose each pattern's\n * correctness. Those decisions therefore stay in each controller, which calls\n * {@link RovingTabindex.setActive} with an index it computed itself (optionally\n * via the pure {@link rovingMove} helper).\n *\n * @remarks\n * Items are read lazily through a getter so a controller can add or remove\n * targets (Stimulus re-scans the DOM) without re-wiring this helper. A caller\n * that already captured one event-scoped snapshot may pass it to\n * {@link RovingTabindex.setActive}, avoiding a second live-target scan while\n * preserving one coherent collection for the whole operation.\n */\nexport class RovingTabindex {\n /** Returns the current ordered item elements; called on every operation. */\n readonly #getItems: () => HTMLElement[];\n\n /**\n * @param getItems - Returns the current ordered item elements. Called on every\n * operation so the live target list is always used.\n */\n constructor(getItems: () => HTMLElement[]) {\n this.#getItems = getItems;\n }\n\n /** Index of the currently tabbable item (`tabindex=\"0\"`), or `-1` if none. */\n get activeIndex(): number {\n return this.#getItems().findIndex((item) => item.tabIndex === 0);\n }\n\n /**\n * Makes exactly the item at `index` tabbable (`tabindex=\"0\"`) and removes every\n * other item from the Tab sequence (`tabindex=\"-1\"`). An out-of-range `index`\n * (e.g. `-1`) leaves all items at `-1`, which a controller can use to express\n * \"nothing is currently tabbable\".\n *\n * @param index - Position of the item to make tabbable.\n * @param options - Pass `{ focus: true }` to also move DOM focus to that item,\n * and `items` to reuse an event-scoped collection snapshot.\n */\n setActive(\n index: number,\n options: { focus?: boolean; items?: readonly HTMLElement[] } = {},\n ): void {\n const { focus = false } = options;\n const items = options.items ?? this.#getItems();\n items.forEach((item, i) => {\n item.tabIndex = i === index ? 0 : -1;\n });\n if (focus) items[index]?.focus();\n }\n}\n\n/** Edge behavior for {@link rovingMove}: cycle past the ends, or stop at them. */\nexport type RovingWrap = \"wrap\" | \"clamp\";\n\n/**\n * Pure helper that resolves the target index for a one-step directional move.\n *\n * Keyboard/orientation mapping stays in the caller: it decides that a key means\n * `delta` `+1` (next) or `-1` (previous) and whether the widget should `\"wrap\"`\n * (Radio Group, Toolbar) or `\"clamp\"` at the ends.\n *\n * @param current - The index focus is moving from.\n * @param length - Number of items in the set.\n * @param delta - `+1` to move to the next item, `-1` for the previous.\n * @param wrap - `\"wrap\"` cycles around the ends; `\"clamp\"` stops at them.\n * @returns The resolved index, or `-1` when there are no items.\n */\nexport function rovingMove(\n current: number,\n length: number,\n delta: number,\n wrap: RovingWrap,\n): number {\n if (length === 0) return -1;\n const next = current + delta;\n if (wrap === \"wrap\") return (next + length) % length;\n return Math.min(length - 1, Math.max(0, next));\n}\n","import { isReservedArrowChord, logicalArrowKey } from \"./arrow_step\";\nimport { RovingTabindex } from \"./roving_tabindex\";\n\n/** Consumer-owned behavior that differs between removable-chip widgets. */\nexport interface ChipRowOptions {\n /** Element whose writing direction defines logical previous/next. */\n readonly directionElement: HTMLElement;\n /** Returns the current chip elements in navigation order. */\n readonly getItems: () => readonly HTMLElement[];\n /** Resolves the one remove button owned by a chip. Defaults to its first button. */\n readonly getButton?: (item: HTMLElement) => HTMLButtonElement | null;\n /** Removes the chip currently occupying `index`. */\n readonly onRemove: (index: number) => void;\n /** Receives focus when navigation moves past the logical end of the row. */\n readonly focusAfterEnd: () => void;\n}\n\n/**\n * Delegated interaction and roving-tabindex mechanics for a row of removable chips.\n *\n * The selection model stays in the consuming controller: this helper knows only\n * how to resolve one consumer-declared remove button per chip, move between those\n * buttons, delegate click/delete requests by index, and bind those listeners to\n * a replaceable row target. Restricting the button set to the declared chip items\n * deliberately excludes sibling controls such as an authored \"Clear all\" button.\n */\nexport class ChipRow {\n readonly #directionElement: HTMLElement;\n readonly #getItems: () => readonly HTMLElement[];\n readonly #getButton: (item: HTMLElement) => HTMLButtonElement | null;\n readonly #onRemove: (index: number) => void;\n readonly #focusAfterEnd: () => void;\n readonly #roving = new RovingTabindex(() => this.buttons);\n #container: HTMLElement | null = null;\n\n constructor(options: ChipRowOptions) {\n this.#directionElement = options.directionElement;\n this.#getItems = options.getItems;\n this.#getButton = options.getButton ?? ((item) => item.querySelector(\"button\"));\n this.#onRemove = options.onRemove;\n this.#focusAfterEnd = options.focusAfterEnd;\n }\n\n /**\n * Binds delegation to `container`; any row currently bound is released first.\n * Idempotent for the same node, so target callbacks may call it freely.\n */\n connect(container: HTMLElement): void {\n if (this.#container === container) return;\n this.disconnect();\n this.#container = container;\n container.addEventListener(\"click\", this.#onClick);\n container.addEventListener(\"keydown\", this.#onKeydown);\n }\n\n /**\n * Releases the current row. When `container` is supplied, a stale disconnect\n * callback cannot tear listeners off a newer replacement target.\n */\n disconnect(container?: HTMLElement): void {\n const current = this.#container;\n if (!current || (container !== undefined && current !== container)) return;\n current.removeEventListener(\"click\", this.#onClick);\n current.removeEventListener(\"keydown\", this.#onKeydown);\n this.#container = null;\n }\n\n /** Current remove buttons, at most one consumer-resolved button per chip item. */\n get buttons(): HTMLButtonElement[] {\n return this.#entries.map(({ button }) => button);\n }\n\n /** Number of currently navigable remove buttons. */\n get length(): number {\n return this.buttons.length;\n }\n\n /** Declared-item index of the last navigable chip, or `-1` for an empty row. */\n get lastIndex(): number {\n return this.#entries.at(-1)?.itemIndex ?? -1;\n }\n\n /** Keeps exactly one button tabbable, preferring the first authored Tab stop. */\n ensureTabStop(): void {\n const buttons = this.#entries.map(({ button }) => button);\n const active = buttons.findIndex((button) => button.tabIndex === 0);\n const count = buttons.filter((button) => button.tabIndex === 0).length;\n if (buttons.length > 0 && count !== 1) {\n this.#roving.setActive(active === -1 ? 0 : active, { items: buttons });\n }\n }\n\n /** Focuses the last chip, returning false for an empty row. */\n focusLast(): boolean {\n const buttons = this.#entries.map(({ button }) => button);\n const last = buttons.length - 1;\n if (last < 0) return false;\n this.#roving.setActive(last, { focus: true, items: buttons });\n return true;\n }\n\n /**\n * Focuses the chip that followed a removed index, or the new last chip.\n * Returns false when removal emptied the row so the consumer can rescue focus.\n */\n focusAfterRemoval(index: number): boolean {\n const entries = this.#entries;\n if (entries.length === 0) return false;\n const following = entries.findIndex((entry) => entry.itemIndex >= index);\n this.#roving.setActive(following === -1 ? entries.length - 1 : following, {\n focus: true,\n items: entries.map(({ button }) => button),\n });\n return true;\n }\n\n /** Current remove-button entries, retaining each button's declared item index. */\n get #entries(): Array<{ button: HTMLButtonElement; itemIndex: number }> {\n return this.#getItems().flatMap((item, itemIndex) => {\n const button = this.#getButton(item);\n return button ? [{ button, itemIndex }] : [];\n });\n }\n\n /** Resolves a delegated event to the remove button owned by a declared chip. */\n #entry(event: Event): {\n button: HTMLButtonElement;\n buttonIndex: number;\n buttons: HTMLButtonElement[];\n itemIndex: number;\n } | null {\n const target = event.target;\n if (!(target instanceof Element)) return null;\n const button = target.closest<HTMLButtonElement>(\"button\");\n const entries = this.#entries;\n const buttonIndex = entries.findIndex((entry) => entry.button === button);\n if (buttonIndex === -1) return null;\n const entry = entries[buttonIndex] as { button: HTMLButtonElement; itemIndex: number };\n return { ...entry, buttonIndex, buttons: entries.map(({ button }) => button) };\n }\n\n /** Delegates removal clicks without waiting for Stimulus to wire a new chip. */\n readonly #onClick = (event: MouseEvent): void => {\n const entry = this.#entry(event);\n if (!entry) return;\n this.#onRemove(entry.itemIndex);\n };\n\n /** Applies the shared logical-arrow and removal policy within the chip row. */\n readonly #onKeydown = (event: KeyboardEvent): void => {\n if (event.defaultPrevented || isReservedArrowChord(event)) return;\n const entry = this.#entry(event);\n if (!entry) return;\n const buttons = entry.buttons;\n const index = entry.buttonIndex;\n\n switch (logicalArrowKey(event.key, this.#directionElement)) {\n case \"ArrowLeft\":\n if (index > 0) {\n event.preventDefault();\n this.#roving.setActive(index - 1, { focus: true, items: buttons });\n }\n break;\n case \"ArrowRight\":\n event.preventDefault();\n if (index < buttons.length - 1) {\n this.#roving.setActive(index + 1, { focus: true, items: buttons });\n } else {\n this.#focusAfterEnd();\n }\n break;\n case \"Delete\":\n case \"Backspace\":\n event.preventDefault();\n this.#onRemove(entry.itemIndex);\n break;\n default:\n break;\n }\n };\n}\n","/** Minimal event shape carrying the platform's per-event composition signal. */\nexport interface CompositionSignal {\n readonly isComposing?: boolean;\n}\n\n/** Hooks that keep component-specific work outside {@link CompositionTracker}. */\nexport interface CompositionTrackerOptions {\n /** Runs after lifecycle state is set for a `compositionstart` event. */\n readonly onStart?: (event: Event) => void;\n /** Runs after lifecycle state is cleared for a `compositionend` event. */\n readonly onEnd?: (event: Event) => void;\n}\n\n/**\n * Owns IME composition listeners and transient state for one or more event targets.\n *\n * Some browsers omit `KeyboardEvent.isComposing` on the keydown that confirms a\n * conversion. Tracking `compositionstart` through `compositionend` supplies the\n * missing lifecycle signal without relying on deprecated numeric key codes.\n * Component policy stays with the consumer: filtering, validation, and submission\n * belong in the optional {@link CompositionTrackerOptions.onEnd} callback.\n *\n * @example\n * ```ts\n * #composition = new CompositionTracker({ onEnd: () => this.filter() });\n *\n * connect(): void {\n * this.#composition.observe(this.inputTarget);\n * }\n *\n * disconnect(): void {\n * this.#composition.disconnect();\n * }\n *\n * onKeydown(event: KeyboardEvent): void {\n * if (this.#composition.isComposing(event)) return;\n * }\n * ```\n */\nexport class CompositionTracker {\n readonly #observedTargets = new Set<EventTarget>();\n readonly #activeTargets = new Set<EventTarget>();\n readonly #onStart: ((event: Event) => void) | undefined;\n readonly #onEnd: ((event: Event) => void) | undefined;\n\n constructor(options: CompositionTrackerOptions = {}) {\n this.#onStart = options.onStart;\n this.#onEnd = options.onEnd;\n }\n\n /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */\n observe(target: EventTarget): void {\n if (this.#observedTargets.has(target)) return;\n target.addEventListener(\"compositionstart\", this.#handleStart);\n target.addEventListener(\"compositionend\", this.#handleEnd);\n this.#observedTargets.add(target);\n }\n\n /** Stops tracking one target and clears any active composition it owned. */\n unobserve(target: EventTarget): void {\n if (!this.#observedTargets.delete(target)) return;\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n this.#activeTargets.delete(target);\n }\n\n /** Releases every listener and clears state so reconnect starts cleanly. */\n disconnect(): void {\n for (const target of this.#observedTargets) {\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n }\n this.#observedTargets.clear();\n this.#activeTargets.clear();\n }\n\n /** True when lifecycle tracking or the current event reports composition. */\n isComposing(event?: CompositionSignal): boolean {\n return this.#activeTargets.size > 0 || event?.isComposing === true;\n }\n\n readonly #handleStart = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.add(event.currentTarget);\n this.#onStart?.(event);\n };\n\n readonly #handleEnd = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);\n this.#onEnd?.(event);\n };\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","/**\n * Scroll-follow for virtually-focused listbox options.\n *\n * Listbox-style widgets that track their active option with\n * `aria-activedescendant` keep DOM focus on the input/trigger, so the\n * browser's native \"scroll the focused element into view\" never runs — in a\n * scrollable list (`max-height` + `overflow`) the active option can walk right\n * out of sight on ArrowDown/ArrowUp. This helper keeps it visible.\n *\n * It adjusts the LIST's own `scrollTop` only — deliberately not\n * `scrollIntoView({ block: \"nearest\" })`, which may also scroll ancestor\n * scrolling boxes (the page) when a floating popup pokes past a viewport\n * edge, desyncing anchored/marker-composed placements. (Command-palette uses\n * `scrollIntoView` because its page is scroll-locked behind the modal;\n * page-floating popups must use this helper instead.)\n */\n\n/**\n * Scrolls `option` into view within `list` by minimally adjusting\n * `list.scrollTop`. No-ops when the list does not actually scroll. Never\n * touches any other scrolling box.\n *\n * @param list - The scrollable listbox container.\n * @param option - The (virtually focused) option to keep visible.\n */\nexport function scrollOptionIntoView(list: HTMLElement, option: HTMLElement): void {\n if (list.scrollHeight <= list.clientHeight) return;\n const listRect = list.getBoundingClientRect();\n const optionRect = option.getBoundingClientRect();\n if (optionRect.top < listRect.top) {\n list.scrollTop -= listRect.top - optionRect.top;\n } else if (optionRect.bottom > listRect.bottom) {\n list.scrollTop += optionRect.bottom - listRect.bottom;\n }\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way (the `MicrotaskCoalescer` split).\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","import { BeforeCacheReset } from \"./before_cache_reset\";\n\n/**\n * Shared bookkeeping for a `tabindex` a controller lends an element temporarily.\n *\n * A controller that must move focus somewhere the author never made focusable\n * (a landmark root, a scroll destination) reaches for the same trick: add a\n * `tabindex` just-in-time and hand it back once it is no longer needed. The\n * borrow is the easy half; the return is what the two conditions below are for.\n *\n * **Returning needs two conditions, not one.** Owning the borrow is not enough:\n * the attribute must also still hold the value this instance wrote. A consumer\n * that changed it afterwards — `tabindex=\"0\"` to make the root its own Tab stop\n * — owns it now, and removing it there silently discards authored markup. The\n * bookkeeping is dropped either way, since the loan is over regardless of who\n * ends up owning the value.\n *\n * **Never borrow over an existing value.** An element that already carries a\n * `tabindex` is the author's to control, so there is nothing to lend and nothing\n * to return.\n *\n * Every live loan also owns a shared `turbo:before-cache` subscription. The loan\n * is returned before Turbo can copy it into a snapshot, so consumers get cache\n * safety without duplicating a lifecycle hook; `returnAll()` removes the\n * subscription again as soon as no loan remains.\n *\n * The registry is keyed by element, so a controller borrowing on a single\n * element (`this.element`) and one borrowing across a changing set of targets\n * use the same API — the single-element case is a set of one. It holds no\n * opinion about *when* to borrow or where focus goes next; that stays in the\n * controller.\n *\n * **The API is deliberately two methods.** This file's own doc block is dropped\n * from `dist`, but every member comment is inlined into **each** consumer entry\n * (`tsup` builds with `splitting: false`), so rationale belongs here, only the\n * contract belongs on the members, and every method no consumer calls is still\n * paid for once per consumer entry.\n *\n * @example\n * ```ts\n * readonly #tabindex = new TabindexLoan();\n *\n * #rescueFocus() {\n * this.#tabindex.lend(this.element);\n * this.element.focus();\n * }\n *\n * disconnect() {\n * this.#tabindex.returnAll();\n * }\n * ```\n */\nexport class TabindexLoan<T extends HTMLElement = HTMLElement> {\n readonly #value: string;\n readonly #lent = new Set<T>();\n /** Returns live loans before Turbo can copy them into its page snapshot. */\n readonly #beforeCache = new BeforeCacheReset(() => this.returnAll());\n\n /**\n * @param value - the `tabindex` to lend. `\"-1\"` (the default) is\n * programmatically focusable but not a Tab stop; `\"0\"` is a real Tab stop,\n * which a scroll region with no focusable content of its own needs.\n */\n constructor(value: string = \"-1\") {\n this.#value = value;\n }\n\n /** Lends `element` the value; no-ops when it already carries a `tabindex`. */\n lend(element: T): void {\n if (element.hasAttribute(\"tabindex\")) return;\n element.setAttribute(\"tabindex\", this.#value);\n this.#lent.add(element);\n // Subscribe only while a real loan exists. Keeping this guarantee here means\n // every consumer is Turbo-safe without another lifecycle hook to remember.\n this.#beforeCache.activate();\n }\n\n /** Takes back every loan whose value is still the one that was lent. */\n returnAll(): void {\n for (const element of this.#lent) {\n if (element.getAttribute(\"tabindex\") === this.#value) element.removeAttribute(\"tabindex\");\n }\n this.#lent.clear();\n this.#beforeCache.deactivate();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { announce, fillTemplate } from \"../utils/announce\";\nimport { ensureId } from \"../utils/aria_ids\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { ChipRow } from \"../utils/chip_row\";\nimport { CompositionTracker } from \"../utils/composition_tracker\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { scrollOptionIntoView } from \"../utils/option_scroll\";\nimport { TabindexLoan } from \"../utils/tabindex_loan\";\n\n/**\n * Headless, accessible multi-select combobox with chips.\n *\n * Markup contract (identifier: `stimeo--multi-select`):\n * <div data-controller=\"stimeo--multi-select\"\n * data-stimeo--multi-select-announce-text-value=\"{label} selected; {count} total\"\n * data-stimeo--multi-select-announce-removed-text-value=\"{label} removed; {count} total\">\n * <ul data-stimeo--multi-select-target=\"tags\" aria-label=\"Selected\"></ul>\n * <input type=\"text\" role=\"combobox\" aria-expanded=\"false\"\n * aria-autocomplete=\"list\" aria-controls=\"ms-list\"\n * data-stimeo--multi-select-target=\"input\"\n * data-action=\"input->stimeo--multi-select#filter\n * keydown->stimeo--multi-select#onKeydown\n * focus->stimeo--multi-select#open\" />\n * <ul id=\"ms-list\" role=\"listbox\" aria-multiselectable=\"true\" hidden\n * data-stimeo--multi-select-target=\"list\">\n * <li id=\"ms-opt-1\" role=\"option\" aria-selected=\"false\" data-value=\"apple\"\n * data-stimeo--multi-select-target=\"option\"\n * data-action=\"click->stimeo--multi-select#toggleOption\">Apple</li>\n * </ul>\n * <!-- Optional: submit the selection as name=\"fruits[]\" hidden inputs. -->\n * <div data-stimeo--multi-select-target=\"fields\"></div>\n * <template data-stimeo--multi-select-target=\"tagTemplate\">\n * <li data-stimeo--multi-select-target=\"tag\">\n * <span data-stimeo--multi-select-target=\"label\"></span>\n * <button type=\"button\" tabindex=\"-1\" aria-label=\"Remove {label}\"\n * data-stimeo--multi-select-target=\"remove\">×</button>\n * </li>\n * </template>\n * </div>\n *\n * Implements the WAI-ARIA APG **Combobox** pattern in its list-autocomplete,\n * multi-select form. Focus stays on the input; the active option is tracked with\n * `aria-activedescendant` and selection with `aria-selected`. Selected options are\n * mirrored as removable chips. For single selection use {@link ListboxController}\n * or Combobox; for free-text tags use {@link TagsInputController}.\n *\n * Behavior provided:\n * - Typing filters options by substring and opens the list; `ArrowDown`/`ArrowUp`\n * (wrapping), `Home`/`End` move the active option; `Enter` toggles it (the list\n * stays open); `Escape`/`Tab`/outside click close.\n * - Toggling syncs `aria-selected`, expands the author-localized remove-button\n * name from the chip template, adds/removes the chip, sends localized text to\n * the shared announcer, and dispatches\n * `stimeo--multi-select:change` with `values`; filtering dispatches\n * `stimeo--multi-select:filter` for async candidates. Option churn or a lowered\n * `max` that moves the selection without a user edit is reported as\n * `stimeo--multi-select:reconcile`, carrying the same `values` detail.\n * - The chips are one roving Tab stop: `ArrowLeft`/`ArrowRight` move between them,\n * `Delete`/`Backspace` remove the focused chip, and `Backspace` on an empty\n * input removes the last and keeps input focus; removal from a chip re-homes\n * focus to a neighbor or the input.\n * - `max` is a permanent selection invariant across initial markup, interaction,\n * runtime options, and runtime cap changes (`0` = unlimited).\n * - With a `fields` target the selected values are mirrored into named hidden\n * inputs (default name `options[]`), so the selection submits with a normal\n * form and no consumer JS — parity with {@link TagsInputController}. An optional\n * `form` value sets the hidden inputs' `form` attribute, associating them with a\n * `<form>` by id even when the picker lives outside it. Without a `fields`\n * target the hidden inputs are simply not written.\n */\nexport class MultiSelectController extends Controller<HTMLElement> {\n static override targets = [\n \"input\",\n \"list\",\n \"option\",\n \"tags\",\n \"tag\",\n \"tagTemplate\",\n \"label\",\n \"remove\",\n \"fields\",\n ];\n static override values = {\n max: { type: Number, default: 0 },\n name: { type: String, default: \"options[]\" },\n form: { type: String, default: \"\" },\n announceText: { type: String, default: \"\" },\n announceRemovedText: { type: String, default: \"\" },\n };\n static actions = [\"close\", \"filter\", \"onKeydown\", \"open\", \"toggleOption\"] as const;\n static events = [\"change\", \"filter\", \"reconcile\"] as const;\n\n declare readonly inputTarget: HTMLInputElement;\n declare readonly listTarget: HTMLElement;\n declare readonly optionTargets: HTMLElement[];\n declare readonly tagsTarget: HTMLElement;\n declare readonly tagTargets: HTMLElement[];\n declare readonly tagTemplateTarget: HTMLTemplateElement;\n declare readonly labelTargets: HTMLElement[];\n declare readonly removeTargets: HTMLButtonElement[];\n declare readonly fieldsTarget: HTMLElement;\n declare readonly hasListTarget: boolean;\n declare readonly hasInputTarget: boolean;\n declare readonly hasTagsTarget: boolean;\n declare readonly hasTagTemplateTarget: boolean;\n declare readonly hasFieldsTarget: boolean;\n\n declare maxValue: number;\n declare nameValue: string;\n declare formValue: string;\n declare readonly hasFormValue: boolean;\n declare announceTextValue: string;\n declare announceRemovedTextValue: string;\n\n /** Stable id of the active option; the current target is resolved from the DOM. */\n #activeOptionId: string | null = null;\n /** Whether the root borrowed a tab stop to catch focus, so teardown can undo it. */\n readonly #tabindex = new TabindexLoan();\n /** Last reconciled selection, used to distinguish state changes from derived-DOM repair. */\n #selectionValues: string[] = [];\n /** Whether initial normalization finished, so a fields callback cannot mirror stale state. */\n #connected = false;\n /** Collapses one batch of target callbacks into a single final-DOM reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n /** Absorbs the browser's redundant final input after compositionend. */\n #ignorePostCompositionInput = false;\n /** Owns IME lifecycle state; confirmed text emits one filter result. */\n readonly #composition = new CompositionTracker({\n onStart: () => {\n this.#ignorePostCompositionInput = false;\n },\n onEnd: () => {\n // Apply the confirmed query even in browsers that omit a final input event.\n // When the usual final input follows synchronously, absorb it so async\n // consumers receive one filter event for the confirmed text, not two.\n this.#ignorePostCompositionInput = true;\n queueMicrotask(() => {\n this.#ignorePostCompositionInput = false;\n });\n this.filter();\n },\n });\n /** Whether this connection already reported its unusable chip template. */\n #warnedTemplate = false;\n /** Shared delegated interaction for the replaceable row of removable chips. */\n readonly #chipRow = new ChipRow({\n directionElement: this.element,\n getItems: () => this.tagTargets,\n getButton: (tag) =>\n tag.querySelector<HTMLButtonElement>('button[data-stimeo--multi-select-target~=\"remove\"]'),\n onRemove: (index) => this.#removeTagAt(index),\n focusAfterEnd: () => this.#focusInput(),\n });\n\n /** Starts closed, syncs chips for any pre-selected options, and listens out. */\n override connect(): void {\n this.#warnedTemplate = false;\n // A fresh connection has no prior selection to preserve: deterministic DOM\n // order decides which authored selections survive a finite max.\n this.#normalizeSelection([]);\n this.close();\n if (this.hasTagsTarget) {\n this.#chipRow.connect(this.tagsTarget);\n this.#rebuildTags();\n }\n this.#selectionValues = this.#values;\n // Seed the hidden fields from any pre-selected options so the form submits\n // the initial selection without an interaction.\n this.#syncFields();\n document.addEventListener(\"click\", this.#onOutsideClick, true);\n this.#connected = true;\n this.#reconcile.activate();\n }\n\n /**\n * Derives the chips from the selected options, idempotently: a Turbo Drive cache\n * restore or morph can re-connect with chips already in the DOM, so they are\n * cleared before deriving afresh to avoid duplicates.\n */\n #rebuildTags(): void {\n if (!this.hasTagsTarget || !this.hasTagTemplateTarget) return;\n const fragments: DocumentFragment[] = [];\n for (const option of this.#selectedOptions) {\n const fragment = this.#buildTag(option);\n if (!fragment) return;\n fragments.push(fragment);\n }\n for (const tag of this.tagTargets) tag.remove();\n this.tagsTarget.append(...fragments);\n this.#chipRow.ensureTabStop();\n }\n\n /** Tears down document and chip listeners on disconnect (Turbo included). */\n override disconnect(): void {\n this.#connected = false;\n this.#reconcile.cancel();\n this.#composition.disconnect();\n this.#ignorePostCompositionInput = false;\n this.#chipRow.disconnect();\n document.removeEventListener(\"click\", this.#onOutsideClick, true);\n this.#releaseTabindex();\n }\n\n /** Reconciles active state after an option target is added at runtime. */\n optionTargetConnected(): void {\n this.#scheduleOptionReconcile();\n }\n\n /** Cleans a removed target and reconciles active state against the surviving DOM. */\n optionTargetDisconnected(option: HTMLElement): void {\n // `#setActive` can only scan current targets; clean the old node explicitly in\n // case a Turbo morph reuses it elsewhere.\n option.removeAttribute(\"data-active\");\n this.#scheduleOptionReconcile();\n }\n\n /** Rebinds delegated chip interaction when Turbo replaces the tags container. */\n tagsTargetConnected(tags: HTMLElement): void {\n this.#chipRow.connect(tags);\n this.#scheduleOptionReconcile();\n }\n\n /** Releases only the row that actually disconnected, never a newer replacement. */\n tagsTargetDisconnected(tags: HTMLElement): void {\n this.#chipRow.disconnect(tags);\n this.#scheduleOptionReconcile();\n }\n\n /** Seeds a fields target inserted after connect from the current selection. */\n fieldsTargetConnected(): void {\n if (this.#connected) this.#syncFields();\n }\n\n /** Reconciles a runtime max change, including dropping any newly invalid overflow. */\n maxValueChanged(): void {\n this.#scheduleOptionReconcile();\n }\n\n /** Rebuilds submitted fields when their public name changes at runtime. */\n nameValueChanged(): void {\n this.#scheduleOptionReconcile();\n }\n\n /** Rebuilds submitted fields when their associated form changes at runtime. */\n formValueChanged(): void {\n this.#scheduleOptionReconcile();\n }\n\n /** Schedules one reconciliation after all callbacks in the mutation batch. */\n #scheduleOptionReconcile(): void {\n this.#reconcile.schedule();\n }\n\n /**\n * Keeps a surviving/same-id active target, otherwise falls back to the first\n * visible one — and brings the derived state back in line with the new option set.\n *\n * The baseline pass fills in any missing `aria-selected`, and the chips and\n * hidden fields are re-derived from it, because the options are the truth source\n * for the selection. The chips are rebuilt **only when the selected value set\n * actually moved**: the rebuild removes and recreates every chip, so running it\n * for an unrelated option would drop focus from a chip's remove button to\n * `<body>`, losing the keyboard user's place for something that did not concern\n * them.\n */\n #reconcileOptions(): void {\n const visible = this.#visibleOptions;\n const active = this.#activeOption;\n const next = this.#isClosed ? null : active && !active.hidden ? active : (visible[0] ?? null);\n this.#setActive(next);\n this.#reflectEmpty();\n\n const previous = this.#selectionValues;\n const previousLabels = new Map(\n this.tagTargets.map((tag) => [\n tag.dataset.value ?? \"\",\n (\n tag.querySelector<HTMLElement>('[data-stimeo--multi-select-target~=\"label\"]')\n ?.textContent ?? \"\"\n ).trim(),\n ]),\n );\n // Prefer the interaction order represented by live chips. A tags target can\n // be replaced with an empty container, so the last reconciled option set is\n // the fallback that prevents a derived-DOM repair from evicting user choices.\n const priority = [\n ...new Set([...this.tagTargets.map((tag) => tag.dataset.value ?? \"\"), ...previous]),\n ];\n this.#normalizeSelection(priority);\n const selected = this.#selectedOptions;\n // Compared as a set, not a sequence: the chips are in selection order while\n // the options are in DOM order, so an index-wise comparison reports a change\n // for every selection the user made out of DOM order and rebuilds forever.\n const nextValues = selected.map((option) => this.#optionValue(option)).sort();\n const tagValues = this.tagTargets.map((tag) => tag.dataset.value ?? \"\").sort();\n const unchanged =\n nextValues.length === tagValues.length &&\n nextValues.every((value, index) => value === tagValues[index]);\n if (unchanged) this.#refreshTagLabels(selected);\n else this.#rebuildTags();\n this.#syncFields();\n\n const values = this.#values;\n const changed = !this.#sameSelection(previous, values);\n this.#selectionValues = values;\n if (!changed) return;\n\n const options = new Map(selected.map((option) => [this.#optionValue(option), option]));\n for (const value of previous) {\n if (!values.includes(value)) {\n this.#announceTransition(false, previousLabels.get(value) || value, value, values.length);\n }\n }\n for (const value of values) {\n if (previous.includes(value)) continue;\n // `values` is derived from `selected`, so this lookup is total.\n const option = options.get(value) as HTMLElement;\n this.#announceTransition(true, this.#optionLabel(option), value, values.length);\n }\n // Runtime option churn and the `max` cap move the selection by this\n // controller's rules, so the repair is reported apart from `change`, which\n // stays reserved for the user's own add and remove.\n this.dispatch(\"reconcile\", { detail: { values } });\n }\n\n /**\n * Gives every option an explicit `aria-selected` and enforces the current cap.\n * Priority preserves existing chip order at runtime; a fresh connection passes\n * no priority, so deterministic option DOM order chooses the initial survivors.\n */\n #normalizeSelection(priority: readonly string[]): void {\n const selected = this.optionTargets.filter(\n (option) => option.getAttribute(\"aria-selected\") === \"true\",\n );\n const limit = this.#selectionLimit;\n const kept = new Set<HTMLElement>();\n\n if (limit === 0) {\n for (const option of selected) kept.add(option);\n } else {\n for (const value of priority) {\n if (kept.size >= limit) break;\n const option = selected.find(\n (candidate) => !kept.has(candidate) && this.#optionValue(candidate) === value,\n );\n if (option) kept.add(option);\n }\n for (const option of selected) {\n if (kept.size >= limit) break;\n kept.add(option);\n }\n }\n\n for (const option of this.optionTargets) {\n option.setAttribute(\"aria-selected\", String(kept.has(option)));\n }\n }\n\n /**\n * Tracks an input added initially or after connect, and makes it describe the\n * widget that is actually on screen: a swapped-in input arrives with the\n * authored ARIA of a fresh node while this controller still holds the popup\n * state, and the open path cannot repair that (it seeds an active option only\n * when there is none), so a live list would go unannounced.\n */\n inputTargetConnected(input: HTMLInputElement): void {\n this.#composition.observe(input);\n input.setAttribute(\"aria-expanded\", String(!this.#isClosed));\n const active = this.#activeOption;\n if (active) input.setAttribute(\"aria-activedescendant\", ensureId(active, \"stimeo-ms-opt\"));\n else input.removeAttribute(\"aria-activedescendant\");\n }\n\n /** Removes composition listeners when the active input is replaced or removed. */\n inputTargetDisconnected(input: HTMLInputElement): void {\n this.#composition.unobserve(input);\n this.#ignorePostCompositionInput = false;\n }\n\n /** Filters confirmed input text, opens, and re-seeds the active option. */\n filter(event?: InputEvent): void {\n if (!this.hasInputTarget) return;\n if (event && this.#ignorePostCompositionInput) {\n this.#ignorePostCompositionInput = false;\n return;\n }\n if (this.#composition.isComposing(event)) return;\n const query = this.inputTarget.value.trim().toLowerCase();\n for (const option of this.optionTargets) {\n const label = (option.textContent ?? \"\").trim().toLowerCase();\n option.hidden = query !== \"\" && !label.includes(query);\n }\n this.open();\n const visible = this.#visibleOptions;\n this.#reflectEmpty();\n this.#setActive(visible[0] ?? null);\n this.dispatch(\"filter\", { detail: { query } });\n }\n\n /**\n * Opens the list and activates the first visible option when none is active.\n *\n * Needs the input, which owns `aria-expanded` and `aria-activedescendant`: a\n * list shown without one is a popup no assistive technology is told about. So\n * opening is skipped entirely, where {@link close} still closes.\n */\n open(): void {\n if (!this.hasListTarget || !this.hasInputTarget) {\n this.#reflectEmpty();\n return;\n }\n this.listTarget.hidden = false;\n this.inputTarget.setAttribute(\"aria-expanded\", \"true\");\n if (!this.#activeOption) this.#setActive(this.#visibleOptions[0] ?? null);\n this.#reflectEmpty();\n }\n\n /**\n * Closes the list and clears the active option.\n *\n * Survives a missing input in both directions. `connect()` calls this second,\n * so dereferencing the input here would throw before the chips, the roving\n * seed, the chip listeners, the hidden fields and the outside-click listener —\n * and Stimulus keeps the controller alive after that throw, so none of them\n * would ever run and the selection would silently stop submitting. An input\n * removed while the list is open must still let it come down *and* forget its\n * active option, so only the `aria-expanded` write is guarded.\n */\n close(): void {\n if (this.hasListTarget) this.listTarget.hidden = true;\n this.#setActive(null);\n if (this.hasInputTarget) this.inputTarget.setAttribute(\"aria-expanded\", \"false\");\n this.#reflectEmpty();\n }\n\n /** Routes input keyboard interaction per the multi-select combobox model. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key must not ALSO open the\n // list or move the active option — composition depends on this yield.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n if (!this.hasInputTarget) return;\n // Ignore keys fired during IME composition: the `Enter` that confirms a\n // candidate (and arrows that move within it) must not select an option or\n // navigate the chip list. Controller-owned lifecycle state covers confirming\n // events that omit the standard per-event signal.\n if (this.#composition.isComposing(event)) return;\n // Target callbacks are MutationObserver-driven. Resolve a replacement now, or\n // clear a removed id now, so a synchronously dispatched key cannot commit a\n // detached node before the callback gets its turn.\n this.#reconcileActiveForInteraction();\n // Logical, not physical. The key is normalised rather than a new case added:\n // the two horizontal branches are not mirror images — only one guards its\n // edge, and the other hands focus back to the input — so swapping the key\n // keeps each branch, guards and all, with its own direction. Both handlers\n // read the same element on purpose; probing the focused child would let the\n // input and the chips disagree at the boundary between them.\n switch (logicalArrowKey(event.key, this.element)) {\n case \"ArrowDown\":\n event.preventDefault();\n if (this.#isClosed) this.open();\n else this.#moveActive(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (this.#isClosed) this.open();\n else this.#moveActive(-1);\n break;\n case \"Home\":\n if (!this.#isClosed) {\n event.preventDefault();\n this.#setActive(this.#visibleOptions[0] ?? null);\n }\n break;\n case \"End\": {\n if (!this.#isClosed) {\n event.preventDefault();\n const visible = this.#visibleOptions;\n this.#setActive(visible[visible.length - 1] ?? null);\n }\n break;\n }\n case \"Enter\": {\n const active = this.#activeOption;\n if (!this.#isClosed && active) {\n event.preventDefault();\n this.#toggleSelection(active);\n }\n break;\n }\n case \"Escape\":\n // A press an inner handler already owned is yielded at the top of this\n // handler. Escape is consumed only while the list is open: with it closed\n // the press stays free for the shared resolver, so an enclosing dialog\n // still closes from a focused input.\n if (this.#isClosed) break;\n event.preventDefault();\n this.close();\n break;\n case \"Backspace\":\n if (this.inputTarget.value === \"\") {\n const last = this.#chipRow.lastIndex;\n if (last >= 0) {\n event.preventDefault();\n this.#removeTagAt(last, \"input\");\n }\n }\n break;\n case \"ArrowLeft\":\n if (this.inputTarget.value === \"\" && this.#chipRow.length > 0) {\n event.preventDefault();\n this.#chipRow.focusLast();\n }\n break;\n case \"Tab\":\n this.close();\n break;\n default:\n break;\n }\n }\n\n /**\n * Toggles the clicked option's selection. Bound via `data-action`. Focus is\n * re-homed to the input afterwards: options are non-focusable, so the click blurs\n * the input to `body` — and with the list deliberately staying open, every\n * keyboard affordance (Escape, arrows, typing) is bound to the input and would\n * otherwise go dead until the user clicks back in (\"focus stays on the input\").\n */\n toggleOption(event: Event): void {\n const option = (event.currentTarget as HTMLElement).closest<HTMLElement>('[role=\"option\"]');\n if (!option || !this.optionTargets.includes(option)) return;\n this.#toggleSelection(option);\n this.#focusInput();\n }\n\n /**\n * Re-homes focus to the input, or leaves it where it is when there is none.\n *\n * All three callers run *after* an option or a chip already took focus, and all\n * three are reachable without an input — options and chips carry their own\n * `data-action`. Throwing here would leave the chip removed but focus stranded\n * on a detached button.\n */\n #focusInput(): void {\n if (this.hasInputTarget) this.inputTarget.focus();\n }\n\n /**\n * Re-homes focus after the last chip was removed: to the input, else the root.\n *\n * Unlike the other {@link #focusInput} callers, the element that held focus has\n * just left the DOM, so \"leave it alone\" is not an option — the browser already\n * dropped it to `<body>`. The root borrows a `tabindex=\"-1\"` just-in-time (not a\n * Tab stop, handed back before Turbo caches or on teardown). Focus that landed\n * on a real element is left alone, so a chip removed out of band never steals it.\n */\n #focusAfterLastTag(): void {\n if (this.hasInputTarget) {\n this.inputTarget.focus();\n return;\n }\n const doc = this.element.ownerDocument;\n const active = doc.activeElement;\n // Anything else still holding focus keeps it; only `<body>`, the root element\n // and a detached node mean the browser had nowhere to put it.\n if (active && active !== doc.body && active !== doc.documentElement && active.isConnected) {\n return;\n }\n this.#tabindex.lend(this.element);\n this.element.focus();\n }\n\n /**\n * Returns the borrowed tab stop. Owning the borrow is not enough — the value\n * has to still be the one this instance wrote, since a consumer that changed it\n * afterwards owns it now.\n */\n #releaseTabindex(): void {\n this.#tabindex.returnAll();\n }\n\n /** Moves the active option by `delta` among visible options, wrapping. */\n #moveActive(delta: number): void {\n const visible = this.#visibleOptions;\n const active = this.#activeOption;\n // `null` is the deliberate \"not found\" sentinel; Array#indexOf accepts it\n // at runtime and returns -1, although this array's static item type excludes it.\n const current = visible.indexOf(active as HTMLElement);\n const candidate = current === -1 ? (delta > 0 ? 0 : visible.length - 1) : current + delta;\n const next = (candidate + visible.length) % visible.length;\n this.#setActive(visible[next] ?? null);\n }\n\n /** Selects/deselects `option`, honoring `max`, and syncs chip + announcement. */\n #toggleSelection(option: HTMLElement): void {\n const selected = option.getAttribute(\"aria-selected\") === \"true\";\n const limit = this.#selectionLimit;\n if (!selected && limit > 0 && this.#selectedOptions.length >= limit) {\n return;\n }\n if (selected) {\n option.setAttribute(\"aria-selected\", \"false\");\n this.#removeTagFor(option);\n } else {\n // Chips are a display affordance here, not the value model: the selection\n // lives on `aria-selected` and the hidden fields, so a field authored\n // without a chip template still selects. An authored template that cannot\n // be completed is the opposite case — leaving a selection whose chip is\n // missing would be the half-applied state, so that one aborts instead.\n if (this.hasTagTemplateTarget && !this.#appendTag(option)) return;\n option.setAttribute(\"aria-selected\", \"true\");\n }\n this.#refreshRoving();\n this.#syncFields();\n const values = this.#values;\n this.#selectionValues = values;\n this.#announceTransition(\n !selected,\n this.#optionLabel(option),\n this.#optionValue(option),\n values.length,\n );\n this.dispatch(\"change\", { detail: { values } });\n }\n\n /**\n * Re-reads each chip's label from its option, in place.\n *\n * The value order alone does not say the chips are still correct: a server can\n * re-render the same candidate with a new label (\"Apple\" → \"Green Apple\"), and\n * the chip text and its `Remove {label}` name are both derived from the option.\n * Updating them here keeps the rebuild — which would drop focus — for the case\n * that actually needs it, a changed selection.\n */\n #refreshTagLabels(selected: readonly HTMLElement[]): void {\n // Paired by value rather than by position: the chips are in selection order\n // and the options in DOM order, so the two lists hold the same values in\n // different places and an index-wise pairing would relabel the wrong chip.\n const options = new Map(selected.map((option) => [this.#optionValue(option), option]));\n for (const tag of this.tagTargets) {\n // The caller established equal selected/tag value sets before refreshing.\n const option = options.get(tag.dataset.value ?? \"\") as HTMLElement;\n const text = this.#optionLabel(option);\n const label = tag.querySelector<HTMLElement>('[data-stimeo--multi-select-target~=\"label\"]');\n const button = tag.querySelector<HTMLButtonElement>(\n 'button[data-stimeo--multi-select-target~=\"remove\"]',\n );\n const name = this.#removeName(text, this.#optionValue(option));\n // Relabelling is one transaction, like building the chip is. Writing the\n // visible text without its accessible name would leave the button naming\n // a value the chip no longer shows, so a name this template cannot produce\n // holds the old text in place too.\n if (!label || !button || !name) continue;\n if (label.textContent !== text) label.textContent = text;\n if (button.getAttribute(\"aria-label\") !== name) button.setAttribute(\"aria-label\", name);\n }\n }\n\n /** Builds one chip from the template for `option`. */\n #appendTag(option: HTMLElement): boolean {\n if (!this.hasTagsTarget) {\n this.#warnTemplate('a \"tags\" target to append the chip to');\n return false;\n }\n const fragment = this.#buildTag(option);\n if (!fragment) return false;\n this.tagsTarget.appendChild(fragment);\n return true;\n }\n\n /**\n * Builds one fully named chip without mutating the live tag row, or `null`\n * when the authored template cannot produce one. Both callers establish the\n * template first: a field authored without `tagTemplate` renders no chips at\n * all — a supported configuration — and never reaches here.\n */\n #buildTag(option: HTMLElement): DocumentFragment | null {\n const fragment = this.tagTemplateTarget.content.cloneNode(true) as DocumentFragment;\n const tag = fragment.querySelector<HTMLElement>('[data-stimeo--multi-select-target~=\"tag\"]');\n const label = fragment.querySelector<HTMLElement>(\n '[data-stimeo--multi-select-target~=\"label\"]',\n );\n const button = fragment.querySelector<HTMLButtonElement>(\n 'button[data-stimeo--multi-select-target~=\"remove\"]',\n );\n const text = this.#optionLabel(option);\n const value = this.#optionValue(option);\n const removeName = button?.getAttribute(\"aria-label\")?.trim() ?? \"\";\n if (!tag) return this.#warnTemplate('a \"tag\" target');\n if (!label) return this.#warnTemplate('a \"label\" target');\n if (!button) return this.#warnTemplate('a \"remove\" target <button>');\n if (removeName === \"\") {\n return this.#warnTemplate('a non-empty aria-label on its \"remove\" target');\n }\n tag.dataset.value = value;\n label.textContent = text;\n button.setAttribute(\"aria-label\", fillTemplate(removeName, { label: text, value }));\n button.tabIndex = -1;\n return fragment;\n }\n\n /**\n * Reports an unusable chip template to the author, once per connection.\n *\n * The selection itself stays untouched — no `aria-selected`, chip, hidden\n * field, announcement, or event moves. Without this line the only symptom is\n * a listbox whose options refuse to select, and the two causes the Inspector\n * cannot see statically (a name that renders empty from a missing\n * translation, a server-rendered template) would have no diagnostic anywhere.\n */\n #warnTemplate(missing: string): null {\n if (!this.#warnedTemplate) {\n this.#warnedTemplate = true;\n console.warn(\n `Stimeo UI: \"${this.identifier}\" changed no selection because its chip template lacks ${missing}.`,\n );\n }\n return null;\n }\n\n /** Expands the current template's localized remove-button name. */\n #removeName(label: string, value: string): string | null {\n if (!this.hasTagTemplateTarget) return null;\n const template = this.tagTemplateTarget.content\n .querySelector<HTMLButtonElement>('button[data-stimeo--multi-select-target~=\"remove\"]')\n ?.getAttribute(\"aria-label\")\n ?.trim();\n return template ? fillTemplate(template, { label, value }) : null;\n }\n\n /** Removes the chip mirroring `option`, if present. */\n #removeTagFor(option: HTMLElement): void {\n const value = this.#optionValue(option);\n const tag = this.tagTargets.find((candidate) => candidate.dataset.value === value);\n tag?.remove();\n }\n\n /** Removes chip `index` and deselects its option, re-homing focus. */\n #removeTagAt(index: number, focus: \"neighbor\" | \"input\" = \"neighbor\"): void {\n const tag = this.tagTargets[index];\n if (!tag) return;\n const value = tag.dataset.value ?? \"\";\n // Match by the option's stable value, which falls back to its label when no\n // data-value is present, so a label-keyed chip still finds its option.\n const option = this.optionTargets.find((candidate) => this.#optionValue(candidate) === value);\n if (option) option.setAttribute(\"aria-selected\", \"false\");\n tag.remove();\n // Prefer the option's display label for the announcement (e.g. \"Apple\"),\n // which can differ from its data-value (e.g. \"apple\").\n this.#refreshRoving();\n this.#syncFields();\n const values = this.#values;\n this.#selectionValues = values;\n this.#announceTransition(\n false,\n option ? this.#optionLabel(option) : value,\n value,\n values.length,\n );\n this.dispatch(\"change\", { detail: { values } });\n\n if (focus === \"input\") {\n this.#focusInput();\n return;\n }\n if (!this.#chipRow.focusAfterRemoval(index)) this.#focusAfterLastTag();\n }\n\n /**\n * Marks `option` active via `data-active` and the input's\n * `aria-activedescendant` (the attribute is removed, not emptied, when null).\n *\n * The state half runs even with no input, so a `close()` that cannot touch ARIA\n * still clears it: {@link open} seeds an active option only when there is none,\n * so a stale one makes the next open skip the seeding and a replacement input\n * gets no `aria-activedescendant` at all.\n */\n #setActive(option: HTMLElement | null): void {\n const activeId = option ? ensureId(option, \"stimeo-ms-opt\") : null;\n this.#activeOptionId = activeId;\n for (const candidate of this.optionTargets) {\n candidate.toggleAttribute(\"data-active\", candidate === option);\n }\n // Virtual focus never triggers the browser's native focus-scrolling, so a\n // scrollable list must follow the active option itself (list-only scroll).\n if (option && this.hasListTarget) scrollOptionIntoView(this.listTarget, option);\n if (!this.hasInputTarget) return;\n if (activeId !== null) {\n this.inputTarget.setAttribute(\"aria-activedescendant\", activeId);\n } else {\n this.inputTarget.removeAttribute(\"aria-activedescendant\");\n }\n }\n\n /** Repairs only active identity before a key; the fallback waits for the target callback. */\n #reconcileActiveForInteraction(): void {\n const activeId = this.#activeOptionId;\n if (activeId === null) return;\n const resolved = this.#activeOption;\n const active = resolved && !resolved.hidden ? resolved : null;\n const marked = this.optionTargets.filter((candidate) => candidate.hasAttribute(\"data-active\"));\n // The only caller returns before reaching here when the input is absent.\n const idref = this.inputTarget.getAttribute(\"aria-activedescendant\");\n if (!active || marked.length !== 1 || marked[0] !== active || idref !== activeId) {\n this.#setActive(active);\n }\n }\n\n /** Reflects whether the open list currently has no visible option targets. */\n #reflectEmpty(): void {\n this.element.toggleAttribute(\n \"data-stimeo--multi-select-empty\",\n !this.#isClosed && this.#visibleOptions.length === 0,\n );\n }\n\n /**\n * Mirrors the selected values into named hidden inputs under the `fields`\n * target so the selection submits with a normal form (parity with tags-input).\n * No-ops without a `fields` target. When the\n * `form` value is set, each input gets a matching `form` attribute so the picker\n * can submit with a `<form>` it lives outside of.\n */\n #syncFields(): void {\n if (!this.hasFieldsTarget) return;\n this.fieldsTarget.replaceChildren(\n ...this.#values.map((value) => {\n const input = document.createElement(\"input\");\n input.type = \"hidden\";\n input.name = this.nameValue;\n input.value = value;\n if (this.hasFormValue && this.formValue !== \"\") input.setAttribute(\"form\", this.formValue);\n return input;\n }),\n );\n }\n\n /** Keeps exactly one chip remove button tabbable after the set changes. */\n #refreshRoving(): void {\n this.#chipRow.ensureTabStop();\n }\n\n /** Sends one localized selection transition through the page's shared announcer. */\n #announceTransition(selected: boolean, label: string, value: string, count: number): void {\n const template = selected ? this.announceTextValue : this.announceRemovedTextValue;\n announce(fillTemplate(template, { label, value, count }));\n }\n\n /** Whether two arrays represent the same selection set, independent of DOM order. */\n #sameSelection(left: readonly string[], right: readonly string[]): boolean {\n if (left.length !== right.length) return false;\n const a = [...left].sort();\n const b = [...right].sort();\n return a.every((value, index) => value === b[index]);\n }\n\n /** Closes the list on a click outside the controller element. */\n readonly #onOutsideClick = (event: MouseEvent): void => {\n if (!this.#isClosed && !this.element.contains(event.target as Node)) this.close();\n };\n\n /** Trimmed visible label of an option. */\n #optionLabel(option: HTMLElement): string {\n return (option.textContent ?? \"\").trim();\n }\n\n /** An option's stable value: its `data-value`, else its display label. */\n #optionValue(option: HTMLElement): string {\n return option.dataset.value ?? this.#optionLabel(option);\n }\n\n /** Options not hidden by the current filter. */\n get #visibleOptions(): HTMLElement[] {\n return this.optionTargets.filter((option) => !option.hidden);\n }\n\n /** Current active target resolved by stable id, never a detached node reference. */\n get #activeOption(): HTMLElement | null {\n return this.optionTargets.find((option) => option.id === this.#activeOptionId) ?? null;\n }\n\n /** Options currently selected. */\n get #selectedOptions(): HTMLElement[] {\n return this.optionTargets.filter((option) => option.getAttribute(\"aria-selected\") === \"true\");\n }\n\n /** Selected values in option order. */\n get #values(): string[] {\n return this.#selectedOptions.map((option) => this.#optionValue(option));\n }\n\n /** Normalized cardinality cap: zero is unlimited and positive fractions round down. */\n get #selectionLimit(): number {\n if (!Number.isFinite(this.maxValue) || this.maxValue <= 0) return 0;\n return Math.max(1, Math.floor(this.maxValue));\n }\n\n /** Whether the list is currently hidden. */\n get #isClosed(): boolean {\n return !this.hasListTarget || this.listTarget.hidden !== false;\n }\n}\n"]}
|
|
@@ -5,29 +5,31 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
5
5
|
* dedicated APG pattern).
|
|
6
6
|
*
|
|
7
7
|
* Markup contract (identifier: `stimeo--network-status`):
|
|
8
|
-
* <div data-controller="stimeo--network-status"
|
|
9
|
-
*
|
|
8
|
+
* <div data-controller="stimeo--network-status"
|
|
9
|
+
* data-stimeo--network-status-announce-text-value="You are offline."
|
|
10
|
+
* data-stimeo--network-status-announce-online-text-value="Back online.">
|
|
11
|
+
* <div hidden data-stimeo--network-status-target="offline">
|
|
10
12
|
* You are offline.
|
|
11
13
|
* </div>
|
|
12
|
-
* <div
|
|
14
|
+
* <div hidden data-stimeo--network-status-target="online">
|
|
13
15
|
* Back online.
|
|
14
16
|
* </div>
|
|
15
17
|
* </div>
|
|
16
18
|
*
|
|
17
19
|
* Reads `navigator.onLine` on connect and subscribes to the `window`
|
|
18
|
-
* `online`/`offline` events, toggling the matching banner. The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* `online`/`offline` events, toggling the matching banner. The banners are the
|
|
21
|
+
* visual half; assistive tech hears the transition through `announceText`
|
|
22
|
+
* (assertive, because losing connectivity is urgent) and `announceOnlineText`
|
|
23
|
+
* (polite), which go to the page's announcer.
|
|
21
24
|
*
|
|
22
25
|
* @remarks
|
|
23
26
|
* Behavior only. `navigator.onLine` is the browser's *guess* — it does not
|
|
24
|
-
* guarantee server reachability, which stays the consumer's job.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* auto-hide timer are removed/cleared on `disconnect()` (Turbo included).
|
|
27
|
+
* guarantee server reachability, which stays the consumer's job. A banner that is
|
|
28
|
+
* merely un-hidden at the moment of the change is not reliably read, which is why
|
|
29
|
+
* the wording goes to the page's announcer — a region that stands in the document
|
|
30
|
+
* independently of this component. The transition is guarded so an unchanged
|
|
31
|
+
* state never re-announces. The event listeners and the auto-hide timer are
|
|
32
|
+
* removed/cleared on `disconnect()` (Turbo included).
|
|
31
33
|
*/
|
|
32
34
|
declare class NetworkStatusController extends Controller<HTMLElement> {
|
|
33
35
|
#private;
|
|
@@ -124,9 +124,7 @@ var NetworkStatusController = class extends Controller {
|
|
|
124
124
|
#showOffline() {
|
|
125
125
|
this.#timers.clearAll();
|
|
126
126
|
if (this.hasOnlineTarget) this.onlineTarget.hidden = true;
|
|
127
|
-
if (this.hasOfflineTarget)
|
|
128
|
-
this.offlineTarget.hidden = false;
|
|
129
|
-
}
|
|
127
|
+
if (this.hasOfflineTarget) this.offlineTarget.hidden = false;
|
|
130
128
|
}
|
|
131
129
|
/** Shows the recovery banner, optionally auto-hiding it after `onlineAutoHide`. */
|
|
132
130
|
#showOnline() {
|