stimeo-ui 0.15.0 → 0.16.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 +178 -0
- package/README.md +120 -0
- package/dist/cable/index.js +63 -15
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +30 -3
- package/dist/controllers/accordion_controller.js +98 -9
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +8 -7
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +3 -2
- package/dist/controllers/announcer_controller.js +8 -1
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js +43 -2
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +1 -1
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +9 -8
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +4 -4
- package/dist/controllers/bulk_select_controller.js +7 -6
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +85 -23
- package/dist/controllers/calendar_controller.js +323 -123
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +67 -22
- package/dist/controllers/carousel_controller.js +263 -38
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +1 -1
- package/dist/controllers/character_counter_controller.js +40 -2
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.js +54 -10
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +28 -2
- package/dist/controllers/clipboard_controller.js +63 -5
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +25 -1
- package/dist/controllers/collapsible_controller.js +99 -14
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +29 -8
- package/dist/controllers/color_picker_controller.js +80 -34
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +10 -1
- package/dist/controllers/combobox_controller.js +106 -16
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +3 -3
- package/dist/controllers/command_palette_controller.js +35 -3
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js +56 -11
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.js +3 -0
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +6 -0
- package/dist/controllers/context_menu_controller.js +32 -12
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +30 -1
- package/dist/controllers/countdown_controller.js +129 -26
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +74 -15
- package/dist/controllers/currency_input_controller.js +205 -58
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +63 -18
- package/dist/controllers/data_grid_controller.js +195 -29
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +34 -6
- package/dist/controllers/date_range_picker_controller.js +139 -27
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +10 -3
- package/dist/controllers/dialog_controller.js +35 -8
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.js +22 -4
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +2 -2
- package/dist/controllers/dirty_form_controller.js +14 -1
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js +1 -0
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +18 -10
- package/dist/controllers/drawer_controller.js +54 -19
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +9 -3
- package/dist/controllers/dropdown_controller.js +36 -9
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.js +34 -0
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js +144 -51
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +10 -4
- package/dist/controllers/filter_controller.js +20 -6
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +26 -6
- package/dist/controllers/flash_controller.js +305 -46
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.js +1 -0
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +7 -5
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +19 -13
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.js +16 -2
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js +19 -2
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +10 -2
- package/dist/controllers/hover_card_controller.js +40 -14
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +16 -3
- package/dist/controllers/idle_controller.js +90 -5
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +5 -2
- package/dist/controllers/input_mask_controller.js +65 -9
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.js +3 -0
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.js +11 -2
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +50 -8
- package/dist/controllers/listbox_controller.js +203 -45
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.js +0 -2
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +9 -3
- package/dist/controllers/menu_controller.js +45 -16
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +11 -0
- package/dist/controllers/menubar_controller.js +58 -24
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.js +9 -5
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +18 -3
- package/dist/controllers/multi_select_controller.js +278 -104
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +11 -0
- package/dist/controllers/navigation_menu_controller.js +48 -15
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js +37 -8
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.js +9 -1
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +36 -8
- package/dist/controllers/number_input_controller.js +124 -21
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +14 -1
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +22 -7
- package/dist/controllers/otp_controller.js +198 -55
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
- package/dist/controllers/overflow_indicator_controller.js +84 -13
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +26 -6
- package/dist/controllers/overflow_menu_controller.js +112 -41
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +19 -11
- package/dist/controllers/pagination_controller.js +74 -28
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +15 -1
- package/dist/controllers/password_reveal_controller.js +59 -2
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/persist_controller.js +30 -8
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +131 -52
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +9 -3
- package/dist/controllers/popover_controller.js +45 -11
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +1 -1
- package/dist/controllers/portal_controller.js +6 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.js +16 -1
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.js +8 -4
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +6 -4
- package/dist/controllers/radio_group_controller.js +42 -17
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +49 -1
- package/dist/controllers/range_slider_controller.js +88 -42
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +14 -3
- package/dist/controllers/rating_controller.js +39 -15
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +24 -2
- package/dist/controllers/read_more_controller.js +69 -2
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +16 -2
- package/dist/controllers/resizable_controller.js +82 -22
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js +5 -1
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.js +0 -1
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +3 -2
- package/dist/controllers/scrollspy_controller.js +6 -0
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +41 -14
- package/dist/controllers/separator_controller.js +66 -37
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +20 -3
- package/dist/controllers/sidebar_controller.js +77 -18
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.js +6 -1
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +45 -7
- package/dist/controllers/slider_controller.js +82 -47
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.js +11 -1
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +17 -2
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.js +10 -2
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +19 -17
- package/dist/controllers/step_indicator_controller.js +18 -17
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +34 -9
- package/dist/controllers/stepper_controller.js +101 -19
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
- package/dist/controllers/stick_to_bottom_controller.js +75 -5
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +3 -2
- package/dist/controllers/submit_once_controller.js +16 -3
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +29 -7
- package/dist/controllers/switch_controller.js +101 -10
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +12 -0
- package/dist/controllers/tabs_controller.js +21 -2
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +15 -3
- package/dist/controllers/tags_input_controller.js +209 -59
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +20 -3
- package/dist/controllers/theme_controller.js +64 -14
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.js +23 -8
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +52 -15
- package/dist/controllers/toast_controller.js +337 -54
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +49 -7
- package/dist/controllers/toggle_group_controller.js +159 -23
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +32 -0
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +8 -0
- package/dist/controllers/tooltip_controller.js +39 -13
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.js +4 -0
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +39 -8
- package/dist/controllers/tree_view_controller.js +169 -16
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +4588 -1535
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +72 -6
- package/dist/inspector/cli.js +262 -51
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +309 -51
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +40 -40
- package/dist/inspector/manifest.json +525 -59
- package/dist/positioning/index.js +2 -0
- package/dist/positioning/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/announce.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/controllers/tags_input_controller.ts"],"names":["entry","button"],"mappings":"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","file":"tags_input_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","/** 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/**\n * True when a press arrived carrying any modifier, for the keys the browser and\n * the OS own outright: return without calling `preventDefault()` and without\n * moving any state.\n *\n * `Control+Home` and `Control+End` jump the document to its ends, and a widget\n * that swallows them makes the shortcut work or not depending on where focus\n * happens to sit. {@link isReservedArrowChord} answers the same question for the\n * arrows, but returns `false` for every other key so that this one can decide.\n *\n * There is no `allow` list here on purpose. APG assigns no modifier chord to\n * `Home`/`End`, so a widget that wanted one would be claiming a combination the\n * pattern never gave it.\n *\n * @example\n * ```ts\n * case \"Home\":\n * case \"End\":\n * if (hasModifierChord(event)) return;\n * ```\n */\nexport function hasModifierChord(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\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","import { Controller } from \"@hotwired/stimulus\";\nimport { announce, fillTemplate } from \"../utils/announce\";\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\";\n\n/**\n * Headless, accessible free-input tags / chips field.\n *\n * Markup contract (identifier: `stimeo--tags-input`):\n * <div data-controller=\"stimeo--tags-input\"\n * data-stimeo--tags-input-delimiter-value=\",\"\n * data-stimeo--tags-input-announce-text-value=\"{label} added; {count} total\"\n * data-stimeo--tags-input-announce-removed-text-value=\"{label} removed; {count} total\">\n * <ul role=\"list\" aria-label=\"Tags\" data-stimeo--tags-input-target=\"tags\"></ul>\n * <input type=\"text\" aria-label=\"Add tag\" aria-describedby=\"tags-help\"\n * data-stimeo--tags-input-target=\"input\"\n * data-action=\"keydown->stimeo--tags-input#onKeydown\" />\n * <div data-stimeo--tags-input-target=\"fields\"></div>\n * <template data-stimeo--tags-input-target=\"tagTemplate\">\n * <li role=\"listitem\" data-stimeo--tags-input-target=\"tag\">\n * <span data-stimeo--tags-input-target=\"label\"></span>\n * <!-- Removal is delegated on the tags container; no per-chip action needed. -->\n * <button type=\"button\" tabindex=\"-1\" aria-label=\"Remove {label}\"\n * data-stimeo--tags-input-target=\"remove\">×</button>\n * </li>\n * </template>\n * </div>\n *\n * There is no single established APG pattern; this composes a labeled text input\n * with a roving-tabindex list of removable chips, mapping to WCAG 2.1.1, 2.4.7,\n * 4.1.2, 4.1.3, and 1.3.1. Unlike {@link MultiSelectController} (pick from a\n * candidate list) the user types arbitrary strings.\n *\n * Behavior provided:\n * - `Enter` or the configured delimiter commits the trimmed input as a tag.\n * - Empty / duplicate / over-limit additions are rejected with\n * `stimeo--tags-input:reject`; duplicates are allowed when `allowDuplicates`.\n * - Tags render transactionally from the `tagTemplate`; its author-localized\n * remove-button `aria-label` expands `{label}` / `{value}`. The\n * `fields` container mirrors the tag set as `name`d hidden inputs for form\n * submission. User changes dispatch `stimeo--tags-input:change`; DOM/Turbo tag\n * changes dispatch `stimeo--tags-input:reconcile`; authored templates route\n * localized addition/removal text to the shared announcer.\n * - The remove buttons form one roving Tab stop: `ArrowLeft`/`ArrowRight` move\n * between them (right past the end returns to the input), `Delete`/`Backspace`\n * delete the focused tag, and `Backspace` on an empty input deletes the last.\n * - Removing from a chip moves focus to its neighbor (else the input); removing\n * via empty-input `Backspace` keeps focus in the input for continued editing.\n * `change` and `reconcile` dispatch `{ tags: string[] }`; `reject` dispatches\n * `{ value: string, reason: \"duplicate\" | \"empty\" | \"max\" }`.\n */\nexport class TagsInputController extends Controller<HTMLElement> {\n static override targets = [\"input\", \"tags\", \"tag\", \"tagTemplate\", \"label\", \"remove\", \"fields\"];\n static override values = {\n delimiter: { type: String, default: \",\" },\n max: { type: Number, default: 0 },\n allowDuplicates: { type: Boolean, default: false },\n name: { type: String, default: \"tags[]\" },\n announceText: { type: String, default: \"\" },\n announceRemovedText: { type: String, default: \"\" },\n };\n static actions = [\"onKeydown\"] as const;\n static events = [\"change\", \"reconcile\", \"reject\"] as const;\n\n declare readonly inputTarget: HTMLInputElement;\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 hasFieldsTarget: boolean;\n declare readonly hasTagTemplateTarget: boolean;\n declare readonly hasInputTarget: boolean;\n declare readonly hasTagsTarget: boolean;\n\n declare delimiterValue: string;\n declare maxValue: number;\n declare allowDuplicatesValue: boolean;\n declare nameValue: string;\n declare announceTextValue: string;\n declare announceRemovedTextValue: string;\n\n /** Last reconciled tag order, separating user edits from DOM/Turbo repair. */\n #tagValues: string[] = [];\n /** Whether this connection already reported its unusable chip template. */\n #warnedTemplate = false;\n /** Collapses one target/Value mutation batch into one final-DOM repair pass. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileTags());\n readonly #chipRow = new ChipRow({\n directionElement: this.element,\n getItems: () => this.tagTargets,\n getButton: (tag) =>\n tag.querySelector<HTMLButtonElement>('button[data-stimeo--tags-input-target~=\"remove\"]'),\n onRemove: (index) => this.#removeAt(index),\n focusAfterEnd: () => this.#focusInput(),\n });\n /** Owns IME lifecycle state for commit-key guarding. */\n readonly #composition = new CompositionTracker();\n\n /** Wires tag-list keyboard navigation and removal, and seeds the single Tab stop. */\n override connect(): void {\n this.#warnedTemplate = false;\n if (this.hasInputTarget) this.#composition.observe(this.inputTarget);\n if (this.hasTagsTarget) this.#chipRow.connect(this.tagsTarget);\n const tags = this.#values;\n this.#syncState(tags);\n this.#tagValues = tags;\n this.#reconcile.activate();\n }\n\n /** Releases the delegated listeners so no handler outlives the element. */\n override disconnect(): void {\n this.#reconcile.cancel();\n this.#composition.disconnect();\n this.#chipRow.disconnect();\n }\n\n /** Tracks an input added initially or after connect. */\n inputTargetConnected(input: HTMLInputElement): void {\n this.#composition.observe(input);\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 }\n\n /** Rebinds delegation and derived state when the tags container is replaced. */\n tagsTargetConnected(_tags: HTMLElement): void {\n this.#reconcile.schedule();\n }\n\n /** Releases only the row that disconnected, leaving a newer target intact. */\n tagsTargetDisconnected(tags: HTMLElement): void {\n this.#chipRow.disconnect(tags);\n this.#reconcile.schedule();\n }\n\n /** Reconciles a tag inserted by Turbo, a server render, or another controller. */\n tagTargetConnected(_tag: HTMLElement): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles a tag removed by Turbo, a server render, or another controller. */\n tagTargetDisconnected(_tag: HTMLElement): void {\n this.#reconcile.schedule();\n }\n\n /** Seeds a fields target inserted after connect. */\n fieldsTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Rebuilds submitted fields when the public name changes at runtime. */\n nameValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Recomputes the full hook when the cap changes at runtime. */\n maxValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Commits on `Enter`/delimiter and deletes the last tag on empty `Backspace`. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key must not ALSO commit a tag\n // or reach into the chips — 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 commit/navigate the\n // chip list. Controller-owned lifecycle state covers confirming events that\n // omit the standard per-event signal.\n if (this.#composition.isComposing(event)) return;\n if (event.key === \"Enter\" || event.key === this.delimiterValue) {\n event.preventDefault();\n this.#commitInput();\n return;\n }\n if (event.key === \"Backspace\" && this.inputTarget.value === \"\") {\n const last = this.#chipRow.lastIndex;\n if (last >= 0) {\n event.preventDefault();\n this.#removeAt(last, \"input\");\n }\n return;\n }\n // Same normalisation as the chip handler below, read from the same element.\n if (logicalArrowKey(event.key, this.element) === \"ArrowLeft\" && this.inputTarget.value === \"\") {\n if (this.#chipRow.length > 0) {\n event.preventDefault();\n this.#chipRow.focusLast();\n }\n }\n }\n\n /** Validates and adds the current input value as a tag, then clears the input. */\n #commitInput(): void {\n const value = this.inputTarget.value.trim();\n if (value === \"\") {\n this.#reject(value, \"empty\");\n return;\n }\n if (this.maxValue > 0 && this.tagTargets.length >= this.maxValue) {\n this.#reject(value, \"max\");\n return;\n }\n if (!this.allowDuplicatesValue && this.#values.includes(value)) {\n this.#reject(value, \"duplicate\");\n return;\n }\n if (!this.#appendTag(value)) return;\n this.inputTarget.value = \"\";\n const tags = this.#values;\n this.#syncState(tags);\n this.#tagValues = tags;\n this.#announceTransition(true, value, tags.length);\n this.dispatch(\"change\", { detail: { tags } });\n }\n\n /** Builds one chip from the template and appends it to the tag list. */\n #appendTag(value: string): boolean {\n if (!this.hasTagsTarget) return false;\n if (!this.hasTagTemplateTarget) return this.#warnTemplate('a \"tagTemplate\" target');\n const fragment = this.tagTemplateTarget.content.cloneNode(true) as DocumentFragment;\n const tag = fragment.querySelector<HTMLElement>('[data-stimeo--tags-input-target~=\"tag\"]');\n const label = fragment.querySelector<HTMLElement>('[data-stimeo--tags-input-target~=\"label\"]');\n const button = fragment.querySelector<HTMLButtonElement>(\n 'button[data-stimeo--tags-input-target~=\"remove\"]',\n );\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 = value;\n button.setAttribute(\"aria-label\", fillTemplate(removeName, { label: value, value }));\n button.tabIndex = -1;\n this.tagsTarget.appendChild(fragment);\n return true;\n }\n\n /**\n * Reports an unusable chip template to the author, once per connection.\n *\n * The commit itself stays a no-op — nothing about the input, the tag set, the\n * hidden fields, the announcement, or the events changes. Without this line\n * the only symptom is a field that accepts no tags at all, and the two causes\n * the Inspector cannot see statically (a name that renders empty from a\n * missing translation, a server-rendered template) would have no diagnostic\n * anywhere.\n */\n #warnTemplate(missing: string): false {\n if (!this.#warnedTemplate) {\n this.#warnedTemplate = true;\n console.warn(\n `Stimeo UI: \"${this.identifier}\" added no tag because its chip template lacks ${missing}.`,\n );\n }\n return false;\n }\n\n /** Removes the tag at `index`, then applies the interaction-origin focus policy. */\n #removeAt(index: number, focus: \"neighbor\" | \"input\" = \"neighbor\"): void {\n const tag = this.tagTargets[index];\n if (!tag) return;\n const value = tag.dataset.value ?? \"\";\n tag.remove();\n const tags = this.#values;\n this.#syncState(tags);\n this.#tagValues = tags;\n this.#announceTransition(false, value, tags.length);\n this.dispatch(\"change\", { detail: { tags } });\n if (focus === \"input\") {\n this.#focusInput();\n return;\n }\n if (!this.#chipRow.focusAfterRemoval(index)) this.#focusInput();\n }\n\n /** Moves focus to the current input when one exists. */\n #focusInput(): void {\n if (this.hasInputTarget) this.inputTarget.focus();\n }\n\n /** Rebuilds the hidden form fields, the `full` flag, and the roving Tab stop. */\n #syncState(values: readonly string[]): void {\n if (this.hasFieldsTarget) {\n this.fieldsTarget.replaceChildren(\n ...values.map((value) => {\n const input = document.createElement(\"input\");\n input.type = \"hidden\";\n input.name = this.nameValue;\n input.value = value;\n return input;\n }),\n );\n }\n const full = this.maxValue > 0 && values.length >= this.maxValue;\n this.element.toggleAttribute(\"data-stimeo--tags-input-full\", full);\n // Keep exactly one remove button tabbable so the chip list is a single stop.\n this.#chipRow.ensureTabStop();\n }\n\n /** Repairs derived state after DOM/Turbo changes and reports a changed tag order. */\n #reconcileTags(): void {\n if (this.hasTagsTarget) this.#chipRow.connect(this.tagsTarget);\n else this.#chipRow.disconnect();\n const tags = this.#values;\n this.#syncState(tags);\n const changed = !this.#sameTags(this.#tagValues, tags);\n this.#tagValues = tags;\n if (changed) this.dispatch(\"reconcile\", { detail: { tags } });\n }\n\n /** Sends one localized tag transition through the page's shared announcer. */\n #announceTransition(added: boolean, value: string, count: number): void {\n const template = added ? this.announceTextValue : this.announceRemovedTextValue;\n announce(fillTemplate(template, { label: value, value, count }));\n }\n\n /** Reports rejection with `{ value, reason: \"duplicate\" | \"empty\" | \"max\" }`. */\n #reject(value: string, reason: \"duplicate\" | \"empty\" | \"max\"): void {\n this.dispatch(\"reject\", { detail: { value, reason } });\n }\n\n /** Current tag values in order. */\n get #values(): string[] {\n return this.tagTargets.map((tag) => tag.dataset.value ?? \"\");\n }\n\n /** Whether two arrays carry the same values in the same submitted order. */\n #sameTags(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/announce.ts","../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/element_part.ts","../../src/utils/roving_tabindex.ts","../../src/utils/chip_row.ts","../../src/utils/composition_tracker.ts","../../src/utils/field_mirror.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/target_selector.ts","../../src/utils/template_row.ts","../../src/controllers/tags_input_controller.ts"],"names":["entry","button","name"],"mappings":"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","file":"tags_input_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","/** 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/**\n * True when a press arrived carrying any modifier, for the keys the browser and\n * the OS own outright: return without calling `preventDefault()` and without\n * moving any state.\n *\n * `Control+Home` and `Control+End` jump the document to its ends, and a widget\n * that swallows them makes the shortcut work or not depending on where focus\n * happens to sit. {@link isReservedArrowChord} answers the same question for the\n * arrows, but returns `false` for every other key so that this one can decide.\n *\n * There is no `allow` list here on purpose. APG assigns no modifier chord to\n * `Home`/`End`, so a widget that wanted one would be claiming a combination the\n * pattern never gave it.\n *\n * @example\n * ```ts\n * case \"Home\":\n * case \"End\":\n * if (hasModifierChord(event)) return;\n * ```\n */\nexport function hasModifierChord(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\n}\n","/**\n * The element a selector names within `root`, which may be `root` itself.\n *\n * A target declaration is a space-separated token list, so one element can name\n * several at once: a row built from a `<template>` is its own row target, its own\n * label, and its own button where the author writes it that way. `querySelector`\n * never returns its receiver, so resolving a part with it alone reaches nothing on\n * such a row and leaves it rendered but inert.\n *\n * The selector is composed by the caller, so a tag name written into it still\n * narrows the match — a row that is not a `<button>` does not answer for one.\n *\n * @example\n * ```ts\n * const button = matchingPart<HTMLButtonElement>(row, `button${selector(\"remove\")}`);\n * ```\n */\nexport function matchingPart<E extends HTMLElement = HTMLElement>(\n root: HTMLElement,\n selector: string,\n): E | null {\n return root.matches(selector) ? (root as unknown as E) : root.querySelector<E>(selector);\n}\n\n/**\n * Writes `text` as the label of `slot`, keeping the elements nested inside it.\n *\n * A row that names itself its own label holds the rest of the row inside the\n * element the text goes into — the remove button among them. Replacing the whole\n * subtree takes those with it and leaves a chip that is rendered but has nothing to\n * press, so only the slot's own text moves: the first text node carries the value\n * and the rest go, which puts the label where the template left room for it. A slot\n * holding nothing but text is written whole, which is the ordinary row.\n */\nexport function writeLabel(slot: HTMLElement, text: string): void {\n if (slot.childElementCount === 0) {\n slot.textContent = text;\n return;\n }\n let first: ChildNode | null = null;\n for (const node of Array.from(slot.childNodes)) {\n if (node.nodeType !== Node.TEXT_NODE) continue;\n if (first) node.remove();\n else first = node;\n }\n if (first) first.nodeValue = text;\n else slot.prepend(text);\n}\n\n/**\n * Reads back the label {@link writeLabel} wrote, without what sits beside it.\n *\n * The same row that holds the remove button inside its label slot returns that\n * button's glyph from `textContent`, which is enough to make a comparison\n * against the authored label never match — so every pass rewrites a label that\n * did not change — and to put the glyph into an announcement. Only the slot's\n * own text nodes carry the label, which on the ordinary row — a slot holding\n * nothing but text — is the whole of it.\n */\nexport function readLabel(slot: HTMLElement | null): string {\n if (!slot) return \"\";\n let text = \"\";\n for (const node of Array.from(slot.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) text += node.nodeValue ?? \"\";\n }\n return text.trim();\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 { matchingPart } from \"./element_part\";\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 =\n options.getButton ?? ((item) => matchingPart<HTMLButtonElement>(item, \"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/** Minimal `input` shape needed to tell a composition echo from a fresh edit. */\nexport interface ConfirmedInputSignal {\n readonly target: EventTarget | null;\n readonly inputType?: string;\n}\n\n/**\n * The `inputType` values an engine reports on an `input` that belongs to a\n * composition rather than to an edit the user just made.\n */\nconst COMPOSITION_INPUT_TYPES = new Set([\n \"insertCompositionText\",\n \"insertFromComposition\",\n \"deleteCompositionText\",\n \"deleteByComposition\",\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 * The tracker also owns the other half of that lifecycle: **the `input` some\n * engines send after `compositionend` to echo the text just confirmed.** A\n * consumer that ran `onEnd` and then handled the echo would commit the same\n * confirmation twice, so {@link CompositionTracker.consumesConfirmedInput} tells\n * the echo apart and the consumer returns early on it.\n *\n * **What the echo is not, is the harder half.** Not every engine sends one —\n * Chromium ends a confirmation at `compositionend` with no `input` after it — so\n * a window that waits for the echo and only closes on the next key would swallow\n * the first edit that arrives without one: dictation, autofill, a drop,\n * `insertText`. Two things keep that from happening. The window closes on the\n * next anything — a key, a new composition, any `input`, losing the field — and\n * an `input` that reports an `inputType` outside {@link COMPOSITION_INPUT_TYPES}\n * is an edit, so it is never folded. Only an engine that reports no `inputType`\n * at all is left relying on the window alone.\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 * onInput(event: InputEvent): void {\n * if (this.#composition.consumesConfirmedInput(event)) return;\n * if (this.#composition.isComposing(event)) return;\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 /** The field whose confirming `input` is still owed, while the window is open. */\n #confirmedTarget: EventTarget | null = null;\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 target.addEventListener(\"keydown\", this.#handleKeydown);\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 target.removeEventListener(\"keydown\", this.#handleKeydown);\n this.#activeTargets.delete(target);\n if (this.#confirmedTarget === target) this.#confirmedTarget = null;\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 target.removeEventListener(\"keydown\", this.#handleKeydown);\n }\n this.#observedTargets.clear();\n this.#activeTargets.clear();\n this.#confirmedTarget = null;\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 /**\n * Whether `event` is the `input` echoing the composition just confirmed.\n *\n * Asking closes the window either way, so one confirmation is folded at most\n * once and a consumer asks once per `input`.\n */\n consumesConfirmedInput(event: ConfirmedInputSignal): boolean {\n const confirmed = this.#confirmedTarget;\n this.#confirmedTarget = null;\n if (confirmed === null || confirmed !== event.target) return false;\n // An engine that reports no kind at all leaves `inputType` empty, and the\n // window is then the only signal there is.\n const inputType = event.inputType;\n return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);\n }\n\n readonly #handleStart = (event: Event): void => {\n this.#confirmedTarget = null;\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.#confirmedTarget = event.target;\n this.#onEnd?.(event);\n };\n\n /** A key on an observed field opens an edit of its own, so no echo is owed. */\n readonly #handleKeydown = (): void => {\n this.#confirmedTarget = null;\n };\n}\n","/**\n * The hidden form fields a widget keeps in step with the state it owns.\n *\n * A widget whose value lives in ARIA attributes submits nothing on its own, so\n * it mirrors that value into `<input type=\"hidden\">` — one field for a single\n * value, a container of generated fields for a set. The mirror is one-way: the\n * widget's own state stays the source of truth and the field is what the form\n * reads.\n *\n * The write and the report are separate calls because they answer to different\n * rules. A mirror is refreshed on connect, after a morph, and whenever the\n * widget repairs itself — none of which a form should treat as an edit. Only\n * the user's own commit reports one, which is why {@link commitField} is never\n * folded into the writes.\n */\n\n/** How a widget's generated fields identify themselves to the form. */\nexport interface GeneratedFieldOptions {\n /** The `name` every generated input submits under. */\n readonly name: string;\n /** The `form` id, for a widget that sits outside the form it submits to. */\n readonly form?: string;\n}\n\n/**\n * Mirrors one value into a hidden field.\n *\n * @returns Whether the field's value moved.\n *\n * @example\n * ```ts\n * if (writeField(this.fieldTarget, String(value)) && userDriven) {\n * commitField(this.fieldTarget);\n * }\n * ```\n */\nexport function writeField(field: HTMLInputElement, value: string): boolean {\n if (field.value === value) return false;\n field.value = value;\n return true;\n}\n\n/**\n * Mirrors a set of values into `container` as generated hidden fields, in the\n * order given.\n *\n * A container that already submits exactly this set is left untouched, children\n * and all — the mirror is refreshed far more often than it moves (every connect,\n * morph and repair), and a rebuild that changes nothing is still a DOM mutation\n * a consumer's observer and a `:empty` rule can see.\n *\n * @returns Whether the submitted set moved — its values, their order, the\n * `name`, or the `form`.\n */\nexport function writeFields(\n container: HTMLElement,\n values: readonly string[],\n { name, form = \"\" }: GeneratedFieldOptions,\n): boolean {\n const current = [...container.children];\n const submits =\n current.length === values.length &&\n current.every(\n (child, index) =>\n child instanceof HTMLInputElement &&\n child.type === \"hidden\" &&\n child.value === values[index] &&\n child.name === name &&\n (child.getAttribute(\"form\") ?? \"\") === form,\n );\n if (submits) return false;\n\n container.replaceChildren(\n ...values.map((value) => {\n const input = document.createElement(\"input\");\n input.type = \"hidden\";\n input.name = name;\n input.value = value;\n if (form !== \"\") input.setAttribute(\"form\", form);\n return input;\n }),\n );\n return true;\n}\n\n/**\n * Reports a committed value from `target` the way a native form control does:\n * one bubbling, non-cancelable `change`.\n *\n * Call it only for a move the user made. Form-level behaviors listen for this —\n * validation re-checks, auto-submit — and a mirror refreshed by a morph or a\n * repair is not something the user submitted.\n *\n * `target` is the element that carries the value: the hidden field for a single\n * mirrored value, the container for a generated set (whose own inputs are\n * replaced on every write), or a widget's own native control where that is what\n * the form reads.\n */\nexport function commitField(target: HTMLElement): void {\n target.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n\n/**\n * Reports an edit a widget made on the user's behalf, the way the browser\n * reports its own: one bubbling `input`, then one bubbling `change`.\n *\n * This is for a widget that owns the stepping or picking its *own* native\n * control would otherwise do — writing `control.value` from script fires\n * nothing, so a form listening for either event never hears the edit. Use\n * {@link commitField} instead where the element is a mirror of state held\n * elsewhere: a hidden field has no native edit to imitate, so it reports the\n * commit alone.\n *\n * Call it only for a move the user made, and only where the widget really did\n * the writing — an edit the browser already reported would be doubled.\n */\nexport function commitEdit(control: HTMLElement): void {\n control.dispatchEvent(new Event(\"input\", { bubbles: true }));\n control.dispatchEvent(new Event(\"change\", { bubbles: true }));\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 * The attribute selector for one declared target, in a controller's own namespace.\n *\n * Stimulus reads `data-<identifier>-target` as a **space-separated token list**, so a\n * single element can carry several target names at once. Matching the attribute value\n * whole would reach only the elements that declare exactly one name, which is why the\n * name is paired with `~=`.\n *\n * `identifier` is the name the controller is registered under, so the selector reaches\n * the markup that registration renders rather than one fixed spelling.\n */\nexport function targetSelector(identifier: string, name: string): string {\n return `[data-${identifier}-target~=\"${name}\"]`;\n}\n","import { fillTemplate } from \"./announce\";\nimport { matchingPart } from \"./element_part\";\nimport { targetSelector } from \"./target_selector\";\n\n/**\n * Clones the first element of a `<template>`, and nothing else.\n *\n * A template is authored across lines, so its content holds whitespace text nodes\n * around that element — and a second element, where one is written. Cloning the\n * element on its own makes it the whole unit the caller appends, so the same node\n * a later `remove()` takes back is everything that went in, and the parent's child\n * list stays equal to its element list.\n *\n * `null` when the content has no element at all.\n */\nexport function cloneTemplateRoot(template: HTMLTemplateElement): HTMLElement | null {\n const root = template.content.firstElementChild;\n return root instanceof HTMLElement ? (root.cloneNode(true) as HTMLElement) : null;\n}\n\n/** What a consumer declares once about the rows it builds from a `<template>`. */\nexport interface TemplateRowOptions<R extends string, O extends string> {\n /** The controller identifier the row's parts are declared against. */\n readonly identifier: string;\n /** Target name the row itself carries. */\n readonly root: string;\n /** Target names the row must contain; the first one missing is the one reported. */\n readonly required: readonly R[];\n /** Target names the row may contain; a missing one resolves to `null`. */\n readonly optional?: readonly O[];\n /** Target name of the `<button>` whose authored `aria-label` names the row. */\n readonly button: string;\n /** What the widget did not do, e.g. `\"added no tag\"`. */\n readonly outcome: string;\n /** What the author wrote it in, e.g. `\"chip template\"`. */\n readonly noun: string;\n}\n\n/** One row: the element to append, the parts inside it, and its named button. */\nexport interface TemplateRowParts<R extends string, O extends string> {\n readonly root: HTMLElement;\n readonly slots: Readonly<Record<R, HTMLElement> & Record<O, HTMLElement | null>>;\n readonly button: HTMLButtonElement;\n}\n\n/**\n * Builds one row from an authored `<template>`, naming an unusable one once per connection.\n *\n * **The row is the template's only element, and it carries {@link\n * TemplateRowOptions.root} itself.** Cloning it alone ({@link cloneTemplateRoot})\n * makes what the caller appends exactly what a later `remove()` takes back; a row\n * wrapped in another element, or standing beside a second one, would leave that\n * other element behind on every removal — or never be rendered at all — so such a\n * template is refused rather than half-built.\n *\n * Parts resolve through the caller's own namespace, derived from the identifier\n * the controller is registered under, so a registration under any name reaches\n * the attributes that registration renders.\n *\n * A template that cannot produce a row yields `null` and changes nothing: what a\n * refused row means for the selection, the field, or the announcement stays with\n * the caller. The diagnostic names what is wrong — the element count, or the first\n * missing part — because the only other symptom is a widget that silently adds\n * nothing, and the causes a static check cannot see — a server-rendered template,\n * a name that renders empty from a missing translation — would have no diagnostic\n * anywhere. It is written once per connection, so one authoring mistake cannot\n * flood the console.\n *\n * @example\n * ```ts\n * readonly #rows = new TemplateRow({\n * identifier: this.identifier,\n * root: \"tag\",\n * required: [\"label\"],\n * button: \"remove\",\n * outcome: \"added no tag\",\n * noun: \"chip template\",\n * });\n *\n * connect(): void {\n * this.#rows.connect();\n * }\n * ```\n */\nexport class TemplateRow<R extends string, O extends string = never> {\n readonly #options: TemplateRowOptions<R, O>;\n #warned = false;\n\n constructor(options: TemplateRowOptions<R, O>) {\n this.#options = options;\n }\n\n /** The attribute selector for one declared part, in this controller's namespace. */\n selector(name: string): string {\n return targetSelector(this.#options.identifier, name);\n }\n\n /** Re-arms the once-per-connection diagnostic. */\n connect(): void {\n this.#warned = false;\n }\n\n /**\n * Names one missing part on the console, at most once per connection, and\n * returns `null` so a caller can hand it straight back.\n */\n report(missing: string): null {\n return this.#say(`lacks ${missing}`);\n }\n\n /** Writes one diagnostic per connection, saying what the template got wrong. */\n #say(problem: string): null {\n if (this.#warned) return null;\n this.#warned = true;\n const { identifier, outcome, noun } = this.#options;\n console.warn(`Stimeo UI: \"${identifier}\" ${outcome} because its ${noun} ${problem}.`);\n return null;\n }\n\n /**\n * Clones the row and resolves its parts, or names what the template got wrong\n * and returns `null`. `values` fills the button's authored `aria-label`.\n */\n instantiate(\n template: HTMLTemplateElement,\n values: Record<string, string | number>,\n ): TemplateRowParts<R, O> | null {\n const { root: rootName, required, optional, button: buttonName } = this.#options;\n const root = cloneTemplateRoot(template);\n if (!root?.matches(this.selector(rootName))) {\n return this.report(`${this.#article(rootName)} \"${rootName}\" root`);\n }\n // One element, and it is the row: anything beside it would be left behind by\n // a removal that takes the row back, which is the accumulation this contract\n // exists to stop. The row here is the one that was asked for, so the count is\n // what the diagnostic names — a missing part would point at the wrong element.\n const count = template.content.children.length;\n if (count !== 1) {\n return this.#say(`holds ${count} elements, and the row has to be its only one`);\n }\n // Required parts are resolved before they are written, so the declared shape\n // holds for every row returned at all — a missing one leaves through `report`\n // instead. The accumulator is keyed loosely because that ordering is what\n // makes the narrower return type true, and no index signature can say so.\n const slots: Record<string, HTMLElement | null> = {};\n for (const name of required) {\n const part = this.#resolve(root, name);\n if (!part) return this.report(`${this.#article(name)} \"${name}\" target`);\n slots[name] = part;\n }\n for (const name of optional ?? []) slots[name] = this.#resolve(root, name);\n const named = this.#resolve(root, buttonName);\n if (!(named instanceof HTMLButtonElement)) {\n return this.report(`${this.#article(buttonName)} \"${buttonName}\" target <button>`);\n }\n const button = named;\n const name = button.getAttribute(\"aria-label\")?.trim() ?? \"\";\n if (name === \"\") return this.report(`a non-empty aria-label on its \"${buttonName}\" target`);\n button.setAttribute(\"aria-label\", fillTemplate(name, values));\n return { root, slots, button } as TemplateRowParts<R, O>;\n }\n\n /** The row may be its own part; otherwise the first descendant carrying the target. */\n #resolve(root: HTMLElement, name: string): HTMLElement | null {\n return matchingPart(root, this.selector(name));\n }\n\n #article(name: string): string {\n return /^[aeiou]/i.test(name) ? \"an\" : \"a\";\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { announce, fillTemplate } from \"../utils/announce\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { ChipRow } from \"../utils/chip_row\";\nimport { CompositionTracker } from \"../utils/composition_tracker\";\nimport { matchingPart, writeLabel } from \"../utils/element_part\";\nimport { commitField, writeFields } from \"../utils/field_mirror\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { TemplateRow } from \"../utils/template_row\";\n\n/**\n * Headless, accessible free-input tags / chips field.\n *\n * Markup contract (identifier: `stimeo--tags-input`):\n * <div data-controller=\"stimeo--tags-input\"\n * data-stimeo--tags-input-delimiter-value=\",\"\n * data-stimeo--tags-input-announce-text-value=\"{label} added; {count} total\"\n * data-stimeo--tags-input-announce-removed-text-value=\"{label} removed; {count} total\">\n * <ul role=\"list\" aria-label=\"Tags\" data-stimeo--tags-input-target=\"tags\"></ul>\n * <input type=\"text\" aria-label=\"Add tag\" aria-describedby=\"tags-help\"\n * data-stimeo--tags-input-target=\"input\"\n * data-action=\"keydown->stimeo--tags-input#onKeydown\" />\n * <div data-stimeo--tags-input-target=\"fields\"></div>\n * <template data-stimeo--tags-input-target=\"tagTemplate\">\n * <li role=\"listitem\" data-stimeo--tags-input-target=\"tag\">\n * <span data-stimeo--tags-input-target=\"label\"></span>\n * <!-- Removal is delegated on the tags container; no per-chip action needed. -->\n * <button type=\"button\" tabindex=\"-1\" aria-label=\"Remove {label}\"\n * data-stimeo--tags-input-target=\"remove\">×</button>\n * </li>\n * </template>\n * </div>\n *\n * There is no single established APG pattern; this composes a labeled text input\n * with a roving-tabindex list of removable chips, mapping to WCAG 2.1.1, 2.4.7,\n * 4.1.2, 4.1.3, and 1.3.1. Unlike {@link MultiSelectController} (pick from a\n * candidate list) the user types arbitrary strings.\n *\n * Behavior provided:\n * - `Enter` or the configured delimiter commits the trimmed input as a tag.\n * - Empty / duplicate / over-limit additions are rejected with\n * `stimeo--tags-input:reject`; duplicates are allowed when `allowDuplicates`.\n * - Tags render transactionally from the `tagTemplate`; its author-localized\n * remove-button `aria-label` expands `{label}` / `{value}`. The\n * `fields` container mirrors the tag set as `name`d hidden inputs for form\n * submission; `form` associates them with a `<form>` by id when the field\n * sits outside it. A tag the user added or removed also emits a native\n * bubbling `change` from that container, the way a form control does, so\n * `stimeo--auto-submit` and form-level validation hear it; the rebuilds that\n * follow connect, a replacement container, tag churn, or a `name` / `form`\n * change stay silent. User changes dispatch `stimeo--tags-input:change`;\n * DOM/Turbo tag changes dispatch `stimeo--tags-input:reconcile`; authored\n * templates route localized addition/removal text to the shared announcer.\n * - The remove buttons form one roving Tab stop: `ArrowLeft`/`ArrowRight` move\n * between them (right past the end returns to the input), `Delete`/`Backspace`\n * delete the focused tag, and `Backspace` on an empty input deletes the last.\n * - Removing from a chip moves focus to its neighbor (else the input); removing\n * via empty-input `Backspace` keeps focus in the input for continued editing.\n * `change` and `reconcile` dispatch `{ tags: string[] }`; `reject` dispatches\n * `{ value: string, reason: \"duplicate\" | \"empty\" | \"max\" }`.\n */\nexport class TagsInputController extends Controller<HTMLElement> {\n static override targets = [\"input\", \"tags\", \"tag\", \"tagTemplate\", \"label\", \"remove\", \"fields\"];\n static override values = {\n delimiter: { type: String, default: \",\" },\n max: { type: Number, default: 0 },\n allowDuplicates: { type: Boolean, default: false },\n name: { type: String, default: \"tags[]\" },\n form: { type: String, default: \"\" },\n announceText: { type: String, default: \"\" },\n announceRemovedText: { type: String, default: \"\" },\n };\n static actions = [\"onKeydown\"] as const;\n static events = [\"change\", \"reconcile\", \"reject\"] as const;\n\n declare readonly inputTarget: HTMLInputElement;\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 hasFieldsTarget: boolean;\n declare readonly hasTagTemplateTarget: boolean;\n declare readonly hasInputTarget: boolean;\n declare readonly hasTagsTarget: boolean;\n\n declare delimiterValue: string;\n declare maxValue: number;\n declare allowDuplicatesValue: boolean;\n declare nameValue: string;\n declare formValue: string;\n declare announceTextValue: string;\n declare announceRemovedTextValue: string;\n\n /** Last reconciled tag order, separating user edits from DOM/Turbo repair. */\n #tagValues: string[] = [];\n /** Builds one chip from the authored template and owns its diagnostic. */\n readonly #rows = new TemplateRow({\n identifier: this.identifier,\n root: \"tag\",\n required: [\"label\"],\n button: \"remove\",\n outcome: \"added no tag\",\n noun: \"chip template\",\n });\n /** Collapses one target/Value mutation batch into one final-DOM repair pass. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileTags());\n readonly #chipRow = new ChipRow({\n directionElement: this.element,\n getItems: () => this.tagTargets,\n getButton: (tag) =>\n matchingPart<HTMLButtonElement>(tag, `button${this.#rows.selector(\"remove\")}`),\n onRemove: (index) => this.#removeAt(index),\n focusAfterEnd: () => this.#focusInput(),\n });\n /** Owns IME lifecycle state for commit-key guarding. */\n readonly #composition = new CompositionTracker();\n\n /** Wires tag-list keyboard navigation and removal, and seeds the single Tab stop. */\n override connect(): void {\n this.#rows.connect();\n if (this.hasInputTarget) this.#composition.observe(this.inputTarget);\n if (this.hasTagsTarget) this.#chipRow.connect(this.tagsTarget);\n const tags = this.#values;\n this.#syncState(tags);\n this.#tagValues = tags;\n this.#reconcile.activate();\n }\n\n /** Releases the delegated listeners so no handler outlives the element. */\n override disconnect(): void {\n this.#reconcile.cancel();\n this.#composition.disconnect();\n this.#chipRow.disconnect();\n }\n\n /** Tracks an input added initially or after connect. */\n inputTargetConnected(input: HTMLInputElement): void {\n this.#composition.observe(input);\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 }\n\n /** Rebinds delegation and derived state when the tags container is replaced. */\n tagsTargetConnected(_tags: HTMLElement): void {\n this.#reconcile.schedule();\n }\n\n /** Releases only the row that disconnected, leaving a newer target intact. */\n tagsTargetDisconnected(tags: HTMLElement): void {\n this.#chipRow.disconnect(tags);\n this.#reconcile.schedule();\n }\n\n /** Reconciles a tag inserted by Turbo, a server render, or another controller. */\n tagTargetConnected(_tag: HTMLElement): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles a tag removed by Turbo, a server render, or another controller. */\n tagTargetDisconnected(_tag: HTMLElement): void {\n this.#reconcile.schedule();\n }\n\n /** Seeds a fields target inserted after connect. */\n fieldsTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Rebuilds submitted fields when the public name changes at runtime. */\n nameValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Repoints submitted fields when the owning form changes at runtime. */\n formValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Recomputes the full hook when the cap changes at runtime. */\n maxValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Commits on `Enter`/delimiter and deletes the last tag on empty `Backspace`. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key must not ALSO commit a tag\n // or reach into the chips — 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 commit/navigate the\n // chip list. Controller-owned lifecycle state covers confirming events that\n // omit the standard per-event signal.\n if (this.#composition.isComposing(event)) return;\n if (event.key === \"Enter\" || event.key === this.delimiterValue) {\n event.preventDefault();\n this.#commitInput();\n return;\n }\n if (event.key === \"Backspace\" && this.inputTarget.value === \"\") {\n const last = this.#chipRow.lastIndex;\n if (last >= 0) {\n event.preventDefault();\n this.#removeAt(last, \"input\");\n }\n return;\n }\n // Same normalisation as the chip handler below, read from the same element.\n if (logicalArrowKey(event.key, this.element) === \"ArrowLeft\" && this.inputTarget.value === \"\") {\n if (this.#chipRow.length > 0) {\n event.preventDefault();\n this.#chipRow.focusLast();\n }\n }\n }\n\n /**\n * Validates and adds the current input value as a tag, then clears the input.\n *\n * @stimeoRuntimeOnly `max` and `allowDuplicates` decide whether this one entry is taken.\n */\n #commitInput(): void {\n const value = this.inputTarget.value.trim();\n if (value === \"\") {\n this.#reject(value, \"empty\");\n return;\n }\n if (this.maxValue > 0 && this.tagTargets.length >= this.maxValue) {\n this.#reject(value, \"max\");\n return;\n }\n if (!this.allowDuplicatesValue && this.#values.includes(value)) {\n this.#reject(value, \"duplicate\");\n return;\n }\n if (!this.#appendTag(value)) return;\n this.inputTarget.value = \"\";\n const tags = this.#values;\n this.#syncState(tags, true);\n this.#tagValues = tags;\n this.#announceTransition(true, value, tags.length);\n this.dispatch(\"change\", { detail: { tags } });\n }\n\n /**\n * Builds one chip from the template and appends it to the tag list.\n *\n * A refused row leaves the commit a no-op — nothing about the input, the tag\n * set, the hidden fields, the announcement, or the events changes — and the\n * row reports why on the console once per connection.\n */\n #appendTag(value: string): boolean {\n if (!this.hasTagsTarget) return false;\n if (!this.hasTagTemplateTarget) {\n this.#rows.report('a \"tagTemplate\" target');\n return false;\n }\n const row = this.#rows.instantiate(this.tagTemplateTarget, { label: value, value });\n if (!row) return false;\n row.root.dataset.value = value;\n writeLabel(row.slots.label, value);\n // Chip buttons are a single Tab stop the roving helper hands out.\n row.button.tabIndex = -1;\n this.tagsTarget.appendChild(row.root);\n return true;\n }\n\n /** Removes the tag at `index`, then applies the interaction-origin focus policy. */\n #removeAt(index: number, focus: \"neighbor\" | \"input\" = \"neighbor\"): void {\n const tag = this.tagTargets[index];\n if (!tag) return;\n const value = tag.dataset.value ?? \"\";\n tag.remove();\n const tags = this.#values;\n this.#syncState(tags, true);\n this.#tagValues = tags;\n this.#announceTransition(false, value, tags.length);\n this.dispatch(\"change\", { detail: { tags } });\n if (focus === \"input\") {\n this.#focusInput();\n return;\n }\n if (!this.#chipRow.focusAfterRemoval(index)) this.#focusInput();\n }\n\n /** Moves focus to the current input when one exists. */\n #focusInput(): void {\n if (this.hasInputTarget) this.inputTarget.focus();\n }\n\n /**\n * Rebuilds the hidden form fields, the `full` flag, and the roving Tab stop.\n *\n * @stimeoRenderRoot\n */\n #syncState(values: readonly string[], notify = false): void {\n if (this.hasFieldsTarget) {\n const options = { name: this.nameValue, form: this.formValue };\n if (writeFields(this.fieldsTarget, values, options) && notify) {\n commitField(this.fieldsTarget);\n }\n }\n const full = this.maxValue > 0 && values.length >= this.maxValue;\n this.element.toggleAttribute(`data-${this.identifier}-full`, full);\n // Keep exactly one remove button tabbable so the chip list is a single stop.\n this.#chipRow.ensureTabStop();\n }\n\n /** Repairs derived state after DOM/Turbo changes and reports a changed tag order. */\n #reconcileTags(): void {\n if (this.hasTagsTarget) this.#chipRow.connect(this.tagsTarget);\n else this.#chipRow.disconnect();\n const tags = this.#values;\n this.#syncState(tags);\n const changed = !this.#sameTags(this.#tagValues, tags);\n this.#tagValues = tags;\n if (changed) this.dispatch(\"reconcile\", { detail: { tags } });\n }\n\n /**\n * Sends one localized tag transition through the page's shared announcer.\n *\n * @stimeoRuntimeOnly The texts word the one announcement of this change.\n */\n #announceTransition(added: boolean, value: string, count: number): void {\n const template = added ? this.announceTextValue : this.announceRemovedTextValue;\n announce(fillTemplate(template, { label: value, value, count }));\n }\n\n /** Reports rejection with `{ value, reason: \"duplicate\" | \"empty\" | \"max\" }`. */\n #reject(value: string, reason: \"duplicate\" | \"empty\" | \"max\"): void {\n this.dispatch(\"reject\", { detail: { value, reason } });\n }\n\n /** Current tag values in order. */\n get #values(): string[] {\n return this.tagTargets.map((tag) => tag.dataset.value ?? \"\");\n }\n\n /** Whether two arrays carry the same values in the same submitted order. */\n #sameTags(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n }\n}\n"]}
|
|
@@ -28,7 +28,10 @@ type ThemeMode = "light" | "dark" | "system";
|
|
|
28
28
|
* <button data-controller="stimeo--theme" data-action="click->stimeo--theme#toggle"
|
|
29
29
|
* aria-pressed="false">Dark mode</button>
|
|
30
30
|
*
|
|
31
|
-
* `change` dispatches `{ mode, resolved }
|
|
31
|
+
* `change` dispatches `{ mode, resolved }` when a selection or the OS preference moves
|
|
32
|
+
* one of the two. `reconcile` dispatches the same `{ mode, resolved }` when a `mode`
|
|
33
|
+
* declaration that changes after connect moves one of them — the declaration
|
|
34
|
+
* itself, or a stored choice that outranks it. Connecting is silent.
|
|
32
35
|
*
|
|
33
36
|
* @remarks
|
|
34
37
|
* Behavior only — the actual palette is the consumer's CSS keyed off `data-theme`
|
|
@@ -38,7 +41,9 @@ type ThemeMode = "light" | "dark" | "system";
|
|
|
38
41
|
* in sync. Arrow/Home/End move focus across the radiogroup as the APG radio pattern
|
|
39
42
|
* requires; applying a theme never moves focus. The `prefers-color-scheme` listener is attached on
|
|
40
43
|
* `connect()` and removed on `disconnect()` (Turbo included). FOUC avoidance for the
|
|
41
|
-
* very first paint is an inline `<head>` snippet, not this controller.
|
|
44
|
+
* very first paint is an inline `<head>` snippet, not this controller. A `mode`
|
|
45
|
+
* declaration rewritten after connect is followed, but never over a stored choice
|
|
46
|
+
* ({@link ThemeController.modeValueChanged}).
|
|
42
47
|
*
|
|
43
48
|
* Every declaration is validated where it enters, and an unreadable one falls back
|
|
44
49
|
* to that Value's default rather than taking the widget with it: a `mode` outside
|
|
@@ -70,7 +75,7 @@ declare class ThemeController extends Controller<HTMLElement> {
|
|
|
70
75
|
};
|
|
71
76
|
};
|
|
72
77
|
static actions: readonly ["set", "toggle"];
|
|
73
|
-
static events: readonly ["change"];
|
|
78
|
+
static events: readonly ["change", "reconcile"];
|
|
74
79
|
readonly optionTargets: HTMLElement[];
|
|
75
80
|
readonly hasOptionTarget: boolean;
|
|
76
81
|
modeValue: string;
|
|
@@ -80,6 +85,18 @@ declare class ThemeController extends Controller<HTMLElement> {
|
|
|
80
85
|
disconnect(): void;
|
|
81
86
|
/** Validates the `target` declaration once, so the render path never parses. */
|
|
82
87
|
targetValueChanged(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Re-renders for a `mode` declaration changed after connect — a Turbo morph
|
|
90
|
+
* re-rendering the server's markup over the live element, or a script.
|
|
91
|
+
*
|
|
92
|
+
* A stored choice outranks the declaration: a Value that disagrees with it is written
|
|
93
|
+
* back to it, so a morph that brings the server's default never overrides what the
|
|
94
|
+
* user saved. Without one, the declaration is applied. Either way storage is left
|
|
95
|
+
* alone, and a pair on screen that moved is reported as `reconcile`, not `change` —
|
|
96
|
+
* the page moved the declaration, not a selection. The reported pair is re-seeded
|
|
97
|
+
* first, so the next selection is compared with what is on screen.
|
|
98
|
+
*/
|
|
99
|
+
modeValueChanged(): void;
|
|
83
100
|
/** Re-derives the single Tab stop and ARIA for an option set that changed. */
|
|
84
101
|
optionTargetConnected(): void;
|
|
85
102
|
/** Re-derives them again when an option leaves, so a Tab stop always remains. */
|
|
@@ -113,20 +113,20 @@ var ThemeController = class extends Controller {
|
|
|
113
113
|
target: { type: String, default: DEFAULT_TARGET }
|
|
114
114
|
};
|
|
115
115
|
static actions = ["set", "toggle"];
|
|
116
|
-
static events = ["change"];
|
|
116
|
+
static events = ["change", "reconcile"];
|
|
117
117
|
/** The OS dark-mode query, watched so `system` tracks live changes. */
|
|
118
118
|
#media = null;
|
|
119
|
-
/** Gate for the target callbacks, which Stimulus runs before `connect()`. */
|
|
119
|
+
/** Gate for the target and `mode` callbacks, which Stimulus runs before `connect()`. */
|
|
120
120
|
#connected = false;
|
|
121
121
|
/** The `target` declaration after validation; the default when unparsable. */
|
|
122
122
|
#targetSelector = DEFAULT_TARGET;
|
|
123
123
|
/** Owns the single Tab stop across the option set (APG radiogroup). */
|
|
124
124
|
#roving = new RovingTabindex(() => this.optionTargets);
|
|
125
125
|
/**
|
|
126
|
-
* The pair last reported, so a move can be told from a
|
|
127
|
-
* readable after the fact — assigning the Value updates the
|
|
128
|
-
* comparison, and the OS query has already flipped by the time it
|
|
129
|
-
* so what was reported has to be kept rather than recomputed.
|
|
126
|
+
* The pair on screen as last reported or re-seeded, so a move can be told from a
|
|
127
|
+
* repeat. Neither side is readable after the fact — assigning the Value updates the
|
|
128
|
+
* mode before any comparison, and the OS query has already flipped by the time it
|
|
129
|
+
* notifies — so what was reported has to be kept rather than recomputed.
|
|
130
130
|
*/
|
|
131
131
|
#published = {
|
|
132
132
|
mode: DEFAULT_MODE,
|
|
@@ -189,13 +189,32 @@ var ThemeController = class extends Controller {
|
|
|
189
189
|
targetValueChanged() {
|
|
190
190
|
this.#targetSelector = validSelector(this.element, this.targetValue, DEFAULT_TARGET);
|
|
191
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Re-renders for a `mode` declaration changed after connect — a Turbo morph
|
|
194
|
+
* re-rendering the server's markup over the live element, or a script.
|
|
195
|
+
*
|
|
196
|
+
* A stored choice outranks the declaration: a Value that disagrees with it is written
|
|
197
|
+
* back to it, so a morph that brings the server's default never overrides what the
|
|
198
|
+
* user saved. Without one, the declaration is applied. Either way storage is left
|
|
199
|
+
* alone, and a pair on screen that moved is reported as `reconcile`, not `change` —
|
|
200
|
+
* the page moved the declaration, not a selection. The reported pair is re-seeded
|
|
201
|
+
* first, so the next selection is compared with what is on screen.
|
|
202
|
+
*/
|
|
203
|
+
modeValueChanged() {
|
|
204
|
+
if (!this.#connected) return;
|
|
205
|
+
if (this.modeValue === this.#published.mode) return;
|
|
206
|
+
const stored = this.#readStored();
|
|
207
|
+
if (stored !== null && this.modeValue !== stored) this.modeValue = stored;
|
|
208
|
+
this.#applyTheme();
|
|
209
|
+
this.#reconcileControls();
|
|
210
|
+
}
|
|
192
211
|
/** Re-derives the single Tab stop and ARIA for an option set that changed. */
|
|
193
212
|
optionTargetConnected() {
|
|
194
|
-
if (this.#connected) this.#
|
|
213
|
+
if (this.#connected) this.#reconcileControls();
|
|
195
214
|
}
|
|
196
215
|
/** Re-derives them again when an option leaves, so a Tab stop always remains. */
|
|
197
216
|
optionTargetDisconnected() {
|
|
198
|
-
if (this.#connected) this.#
|
|
217
|
+
if (this.#connected) this.#reconcileControls();
|
|
199
218
|
}
|
|
200
219
|
/**
|
|
201
220
|
* Selects the mode the activated option declares.
|
|
@@ -227,18 +246,45 @@ var ThemeController = class extends Controller {
|
|
|
227
246
|
#commit() {
|
|
228
247
|
this.#applyTheme();
|
|
229
248
|
this.#syncControls();
|
|
249
|
+
const moved = this.#settle();
|
|
250
|
+
if (moved) this.dispatch("change", { detail: moved });
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Re-derives the controls from the mode on screen for a change the page made — a
|
|
254
|
+
* `mode` declaration or an option set — and reports a pair that moved since the
|
|
255
|
+
* last report as `reconcile`. An option coming or going moves neither half of the
|
|
256
|
+
* pair, so of these changes only a declaration reports.
|
|
257
|
+
*/
|
|
258
|
+
#reconcileControls() {
|
|
259
|
+
this.#syncControls();
|
|
260
|
+
const moved = this.#settle();
|
|
261
|
+
if (moved) this.dispatch("reconcile", { detail: moved });
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Takes the pair on screen as the reported one and returns it when it differs
|
|
265
|
+
* from the one reported before, or `null` when neither half moved.
|
|
266
|
+
*
|
|
267
|
+
* The baseline moves before anything is dispatched, so a listener that selects
|
|
268
|
+
* another mode is measured from the pair it was just told about. What is
|
|
269
|
+
* returned is a copy: the baseline has to survive a listener that writes to what
|
|
270
|
+
* it was handed, or the next unchanged operation reads as a move.
|
|
271
|
+
*/
|
|
272
|
+
#settle() {
|
|
230
273
|
const next = this.#current;
|
|
231
274
|
const last = this.#published;
|
|
232
275
|
this.#published = next;
|
|
233
|
-
if (last.mode
|
|
234
|
-
|
|
235
|
-
}
|
|
276
|
+
if (last.mode === next.mode && last.resolved === next.resolved) return null;
|
|
277
|
+
return { ...next };
|
|
236
278
|
}
|
|
237
|
-
/** The pair the `change`
|
|
279
|
+
/** The pair the `change` and `reconcile` details carry, read from current state. */
|
|
238
280
|
get #current() {
|
|
239
281
|
return { mode: this.#mode, resolved: this.#resolved() };
|
|
240
282
|
}
|
|
241
|
-
/**
|
|
283
|
+
/**
|
|
284
|
+
* Writes `data-theme` + `color-scheme` (the resolved theme) onto the target.
|
|
285
|
+
*
|
|
286
|
+
* @stimeoRenderRoot
|
|
287
|
+
*/
|
|
242
288
|
#applyTheme() {
|
|
243
289
|
const root = this.#targetElement();
|
|
244
290
|
if (!root) return;
|
|
@@ -246,7 +292,11 @@ var ThemeController = class extends Controller {
|
|
|
246
292
|
root.setAttribute("data-theme", resolved);
|
|
247
293
|
root.style.setProperty("color-scheme", resolved);
|
|
248
294
|
}
|
|
249
|
-
/**
|
|
295
|
+
/**
|
|
296
|
+
* Keeps the radiogroup (aria-checked + roving tabindex) or toggle (aria-pressed) in sync.
|
|
297
|
+
*
|
|
298
|
+
* @stimeoRenderRoot
|
|
299
|
+
*/
|
|
250
300
|
#syncControls() {
|
|
251
301
|
const options = this.optionTargets;
|
|
252
302
|
if (options.length > 0) {
|