stimeo-ui 0.8.0 → 0.10.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.
Files changed (167) hide show
  1. package/CHANGELOG.md +163 -0
  2. package/dist/controllers/accordion_controller.js.map +1 -1
  3. package/dist/controllers/alert_dialog_controller.js +17 -7
  4. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  5. package/dist/controllers/announcer_controller.js +1 -1
  6. package/dist/controllers/announcer_controller.js.map +1 -1
  7. package/dist/controllers/auto_submit_controller.js.map +1 -1
  8. package/dist/controllers/avatar_controller.js.map +1 -1
  9. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  10. package/dist/controllers/bulk_select_controller.d.ts +62 -15
  11. package/dist/controllers/bulk_select_controller.js +139 -28
  12. package/dist/controllers/bulk_select_controller.js.map +1 -1
  13. package/dist/controllers/calendar_controller.js.map +1 -1
  14. package/dist/controllers/carousel_controller.js.map +1 -1
  15. package/dist/controllers/character_counter_controller.js.map +1 -1
  16. package/dist/controllers/clipboard_controller.d.ts +48 -15
  17. package/dist/controllers/clipboard_controller.js +102 -20
  18. package/dist/controllers/clipboard_controller.js.map +1 -1
  19. package/dist/controllers/collapsible_controller.d.ts +1 -1
  20. package/dist/controllers/collapsible_controller.js +1 -1
  21. package/dist/controllers/collapsible_controller.js.map +1 -1
  22. package/dist/controllers/color_picker_controller.d.ts +37 -6
  23. package/dist/controllers/color_picker_controller.js +180 -43
  24. package/dist/controllers/color_picker_controller.js.map +1 -1
  25. package/dist/controllers/combobox_controller.js.map +1 -1
  26. package/dist/controllers/command_palette_controller.js +15 -5
  27. package/dist/controllers/command_palette_controller.js.map +1 -1
  28. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  29. package/dist/controllers/confirm_controller.js +15 -5
  30. package/dist/controllers/confirm_controller.js.map +1 -1
  31. package/dist/controllers/context_menu_controller.d.ts +5 -4
  32. package/dist/controllers/context_menu_controller.js.map +1 -1
  33. package/dist/controllers/count_up_controller.js.map +1 -1
  34. package/dist/controllers/countdown_controller.js +1 -1
  35. package/dist/controllers/countdown_controller.js.map +1 -1
  36. package/dist/controllers/data_grid_controller.d.ts +25 -9
  37. package/dist/controllers/data_grid_controller.js +151 -25
  38. package/dist/controllers/data_grid_controller.js.map +1 -1
  39. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  40. package/dist/controllers/dialog_controller.js +15 -5
  41. package/dist/controllers/dialog_controller.js.map +1 -1
  42. package/dist/controllers/direct_upload_controller.d.ts +2 -2
  43. package/dist/controllers/direct_upload_controller.js +1 -5
  44. package/dist/controllers/direct_upload_controller.js.map +1 -1
  45. package/dist/controllers/dismissible_controller.js.map +1 -1
  46. package/dist/controllers/drawer_controller.d.ts +2 -2
  47. package/dist/controllers/drawer_controller.js +17 -7
  48. package/dist/controllers/drawer_controller.js.map +1 -1
  49. package/dist/controllers/editable_controller.d.ts +34 -9
  50. package/dist/controllers/editable_controller.js +83 -30
  51. package/dist/controllers/editable_controller.js.map +1 -1
  52. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  53. package/dist/controllers/filter_controller.d.ts +15 -3
  54. package/dist/controllers/filter_controller.js +32 -1
  55. package/dist/controllers/filter_controller.js.map +1 -1
  56. package/dist/controllers/flash_controller.js.map +1 -1
  57. package/dist/controllers/focus_controller.d.ts +5 -0
  58. package/dist/controllers/focus_controller.js +45 -7
  59. package/dist/controllers/focus_controller.js.map +1 -1
  60. package/dist/controllers/form_field_controller.js +1 -1
  61. package/dist/controllers/form_field_controller.js.map +1 -1
  62. package/dist/controllers/form_validation_controller.js.map +1 -1
  63. package/dist/controllers/frame_loading_controller.js.map +1 -1
  64. package/dist/controllers/highlight_controller.js.map +1 -1
  65. package/dist/controllers/input_mask_controller.js.map +1 -1
  66. package/dist/controllers/intersection_controller.d.ts +4 -3
  67. package/dist/controllers/intersection_controller.js.map +1 -1
  68. package/dist/controllers/lazy_frame_controller.d.ts +2 -2
  69. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  70. package/dist/controllers/listbox_controller.js.map +1 -1
  71. package/dist/controllers/masonry_controller.d.ts +36 -5
  72. package/dist/controllers/masonry_controller.js +129 -17
  73. package/dist/controllers/masonry_controller.js.map +1 -1
  74. package/dist/controllers/menu_controller.d.ts +1 -1
  75. package/dist/controllers/menu_controller.js.map +1 -1
  76. package/dist/controllers/menubar_controller.js +2 -2
  77. package/dist/controllers/menubar_controller.js.map +1 -1
  78. package/dist/controllers/meter_controller.d.ts +1 -1
  79. package/dist/controllers/meter_controller.js.map +1 -1
  80. package/dist/controllers/multi_select_controller.js +1 -1
  81. package/dist/controllers/multi_select_controller.js.map +1 -1
  82. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  83. package/dist/controllers/nested_form_controller.js.map +1 -1
  84. package/dist/controllers/number_input_controller.js.map +1 -1
  85. package/dist/controllers/otp_controller.d.ts +4 -1
  86. package/dist/controllers/otp_controller.js +29 -16
  87. package/dist/controllers/otp_controller.js.map +1 -1
  88. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  89. package/dist/controllers/overflow_menu_controller.js +2 -2
  90. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  91. package/dist/controllers/pagination_controller.d.ts +1 -1
  92. package/dist/controllers/pagination_controller.js.map +1 -1
  93. package/dist/controllers/password_reveal_controller.d.ts +27 -2
  94. package/dist/controllers/password_reveal_controller.js +102 -3
  95. package/dist/controllers/password_reveal_controller.js.map +1 -1
  96. package/dist/controllers/password_strength_controller.d.ts +71 -17
  97. package/dist/controllers/password_strength_controller.js +287 -42
  98. package/dist/controllers/password_strength_controller.js.map +1 -1
  99. package/dist/controllers/pointer_drag_controller.d.ts +3 -2
  100. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  101. package/dist/controllers/popover_controller.js.map +1 -1
  102. package/dist/controllers/portal_controller.d.ts +1 -1
  103. package/dist/controllers/portal_controller.js.map +1 -1
  104. package/dist/controllers/progress_controller.js.map +1 -1
  105. package/dist/controllers/radio_group_controller.js.map +1 -1
  106. package/dist/controllers/range_slider_controller.js.map +1 -1
  107. package/dist/controllers/rating_controller.js.map +1 -1
  108. package/dist/controllers/read_more_controller.js.map +1 -1
  109. package/dist/controllers/relative_time_controller.js.map +1 -1
  110. package/dist/controllers/reset_before_cache_controller.d.ts +26 -4
  111. package/dist/controllers/reset_before_cache_controller.js +51 -5
  112. package/dist/controllers/reset_before_cache_controller.js.map +1 -1
  113. package/dist/controllers/resizable_controller.d.ts +23 -7
  114. package/dist/controllers/resizable_controller.js +128 -55
  115. package/dist/controllers/resizable_controller.js.map +1 -1
  116. package/dist/controllers/roving_controller.d.ts +2 -1
  117. package/dist/controllers/roving_controller.js.map +1 -1
  118. package/dist/controllers/scroll_area_controller.js.map +1 -1
  119. package/dist/controllers/scroll_restore_controller.d.ts +33 -11
  120. package/dist/controllers/scroll_restore_controller.js +127 -27
  121. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  122. package/dist/controllers/scroll_visibility_controller.d.ts +42 -10
  123. package/dist/controllers/scroll_visibility_controller.js +167 -14
  124. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  125. package/dist/controllers/scrollspy_controller.js.map +1 -1
  126. package/dist/controllers/separator_controller.js.map +1 -1
  127. package/dist/controllers/sidebar_controller.js +15 -5
  128. package/dist/controllers/sidebar_controller.js.map +1 -1
  129. package/dist/controllers/skeleton_controller.js.map +1 -1
  130. package/dist/controllers/slider_controller.js.map +1 -1
  131. package/dist/controllers/spinner_controller.js.map +1 -1
  132. package/dist/controllers/step_indicator_controller.js +0 -5
  133. package/dist/controllers/step_indicator_controller.js.map +1 -1
  134. package/dist/controllers/stick_to_bottom_controller.d.ts +3 -2
  135. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  136. package/dist/controllers/submit_once_controller.js.map +1 -1
  137. package/dist/controllers/switch_controller.js.map +1 -1
  138. package/dist/controllers/tabs_controller.js.map +1 -1
  139. package/dist/controllers/tags_input_controller.js.map +1 -1
  140. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  141. package/dist/controllers/theme_controller.d.ts +32 -6
  142. package/dist/controllers/theme_controller.js +151 -40
  143. package/dist/controllers/theme_controller.js.map +1 -1
  144. package/dist/controllers/time_picker_controller.js.map +1 -1
  145. package/dist/controllers/toast_controller.d.ts +2 -2
  146. package/dist/controllers/toast_controller.js +2 -2
  147. package/dist/controllers/toast_controller.js.map +1 -1
  148. package/dist/controllers/toggle_group_controller.js.map +1 -1
  149. package/dist/controllers/toolbar_controller.js.map +1 -1
  150. package/dist/controllers/transition_controller.d.ts +11 -7
  151. package/dist/controllers/transition_controller.js +79 -15
  152. package/dist/controllers/transition_controller.js.map +1 -1
  153. package/dist/controllers/tree_view_controller.js.map +1 -1
  154. package/dist/index.d.ts +6 -3
  155. package/dist/index.js +1612 -529
  156. package/dist/index.js.map +1 -1
  157. package/dist/inspector/cli.d.ts +3 -4
  158. package/dist/inspector/cli.js +3 -0
  159. package/dist/inspector/cli.js.map +1 -1
  160. package/dist/inspector/cli_bin.js +8 -5
  161. package/dist/inspector/cli_bin.js.map +1 -1
  162. package/dist/inspector/examples.json +25 -25
  163. package/dist/inspector/manifest.json +18 -11
  164. package/dist/positioning/index.d.ts +18 -4
  165. package/dist/positioning/index.js +84 -25
  166. package/dist/positioning/index.js.map +1 -1
  167. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/owned_pointer_session.ts","../../src/utils/range.ts","../../src/utils/stepped_value.ts","../../src/controllers/range_slider_controller.ts"],"names":["position"],"mappings":"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","file":"range_slider_controller.js","sourcesContent":["/** 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 * 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","/** Callbacks driven by one owned pointer until it ends or is cancelled. */\nexport interface OwnedPointerSessionHandlers {\n /** Receives movement from the initiating pointer only. */\n readonly move: (event: PointerEvent) => void;\n /** Runs once after every listener and pointer capture have been released. */\n readonly end?: () => void;\n}\n\n/**\n * Owns one pointer across document-level movement and termination events.\n *\n * A controller may have at most one instance at a time. The session filters\n * every event by the initiating `pointerId`, captures the pointer when the DOM\n * implementation supports it, and binds all fallback document listeners to one\n * abort signal. Calling {@link OwnedPointerSession.end} is idempotent.\n */\nexport class OwnedPointerSession {\n readonly pointerId: number;\n readonly #owner: HTMLElement;\n readonly #handlers: OwnedPointerSessionHandlers;\n readonly #abort = new AbortController();\n #active = true;\n\n constructor(start: PointerEvent, owner: HTMLElement, handlers: OwnedPointerSessionHandlers) {\n this.pointerId = start.pointerId;\n this.#owner = owner;\n this.#handlers = handlers;\n\n const { signal } = this.#abort;\n owner.ownerDocument.addEventListener(\"pointermove\", this.#onMove, { signal });\n owner.ownerDocument.addEventListener(\"pointerup\", this.#onEndEvent, { signal });\n owner.ownerDocument.addEventListener(\"pointercancel\", this.#onEndEvent, { signal });\n owner.addEventListener(\"lostpointercapture\", this.#onLostCapture, { signal });\n\n // Pointer capture is progressive here: happy-dom and older DOM shims may not\n // implement it, while the document listeners still preserve ownership.\n try {\n owner.setPointerCapture?.(this.pointerId);\n } catch {\n // A synthetic or already-ended pointer cannot be captured; filtering and\n // AbortController teardown remain sufficient for that environment.\n }\n }\n\n /** Whether this session still owns its pointer and listeners. */\n get active(): boolean {\n return this.#active;\n }\n\n /** Whether `event` belongs to the initiating pointer of the live session. */\n owns(event: PointerEvent): boolean {\n return this.#active && event.pointerId === this.pointerId;\n }\n\n /** Releases capture/listeners and invokes the end callback exactly once. */\n end(): void {\n if (!this.#active) return;\n this.#active = false;\n this.#abort.abort();\n try {\n this.#owner.releasePointerCapture?.(this.pointerId);\n } catch {\n // Losing capture because the owner detached is already an ended session.\n }\n this.#handlers.end?.();\n }\n\n readonly #onMove = (event: PointerEvent): void => {\n if (this.owns(event)) this.#handlers.move(event);\n };\n\n readonly #onEndEvent = (event: PointerEvent): void => {\n if (this.owns(event)) this.end();\n };\n\n readonly #onLostCapture = (event: Event): void => {\n const pointerId = (event as PointerEvent).pointerId;\n if (typeof pointerId === \"number\" && pointerId !== this.pointerId) return;\n this.end();\n };\n}\n","/**\n * Range normalization shared by the value-bearing controllers (progress, meter,\n * slider, range-slider).\n *\n * Each of them publishes \"where the value sits inside `[min, max]`\" as a CSS\n * custom property the consumer multiplies a track by, and each has to answer the\n * same degenerate cases: empty and inverted ranges cannot express progress, and\n * malformed Number Values can produce `NaN`. Keeping the rule in one place is\n * what makes those answers identical across the four.\n */\n\n/**\n * Fraction of `[min, max]` that `value` occupies, always within `[0, 1]`.\n *\n * `value` is clamped into the range first, so a value outside it reports a full\n * or empty track rather than pushing the fraction past the ends.\n *\n * An empty, inverted, or non-numeric range yields `0`. That is a deliberate\n * floor rather than a computed result: `min === max` would produce `NaN`, and\n * `min > max` would report a full track for a value that is really out of range.\n * Non-finite results are floored for the same reason. These results reach\n * assistive tech, because the same fraction drives the percentage substituted\n * into `aria-valuetext`.\n */\nexport function rangeFraction(value: number, min: number, max: number): number {\n const span = max - min;\n if (!(span > 0)) return 0;\n\n const clamped = Math.min(max, Math.max(min, value));\n let fraction: number;\n if (Number.isFinite(span)) {\n fraction = (clamped - min) / span;\n } else {\n // Scaling preserves the ratio when two finite endpoints straddle zero so\n // widely that their subtraction overflows to Infinity.\n const scale = Math.max(Math.abs(min), Math.abs(max));\n fraction = (clamped / scale - min / scale) / (max / scale - min / scale);\n }\n\n if (!Number.isFinite(fraction)) return 0;\n return Math.min(1, Math.max(0, fraction));\n}\n","/** Configuration for a value constrained to a stepped numeric range. */\nexport interface SteppedRange {\n /** Inclusive lower endpoint. May be infinite for an unbounded control. */\n readonly min: number;\n /** Inclusive upper endpoint. May be infinite for an unbounded control. */\n readonly max: number;\n /** Requested step. Non-finite and non-positive values fall back to `1`. */\n readonly step: number;\n /** Step-grid origin. Defaults to a finite `min`, otherwise `0`. */\n readonly base?: number;\n}\n\n/** The positive finite step used at runtime and by keyboard stepping. */\nexport function effectiveStep(step: number): number {\n return Number.isFinite(step) && step > 0 ? step : 1;\n}\n\n/**\n * Clamps a raw value and selects its nearest allowed value.\n *\n * The allowed set is the step grid plus each finite range endpoint. Keeping the\n * endpoints in that set makes an authored `aria-valuemin`/`aria-valuemax`\n * truthful even when the upper endpoint is not aligned to the grid. A value\n * exactly between two allowed values resolves upward.\n */\nexport function snapSteppedValue(raw: number, range: SteppedRange): number {\n if (!(range.min <= range.max)) return finiteFallback(range.min, range.max);\n\n const input = Number.isNaN(raw) ? finiteFallback(range.min, range.max) : raw;\n const clamped = Math.min(range.max, Math.max(range.min, input));\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (Number.isFinite(range.min)) candidates.push(range.min);\n if (Number.isFinite(range.max)) candidates.push(range.max);\n\n const gridPosition = (clamped - base) / step;\n if (Number.isFinite(gridPosition)) {\n addGridCandidate(candidates, Math.floor(gridPosition), range, base, step);\n addGridCandidate(candidates, Math.ceil(gridPosition), range, base, step);\n }\n\n if (candidates.length === 0) return clamped;\n let nearest = candidates[0] as number;\n let nearestDistance = Math.abs(clamped - nearest);\n for (const candidate of candidates.slice(1)) {\n const distance = Math.abs(clamped - candidate);\n if (\n distance < nearestDistance ||\n (nearlyEqual(distance, nearestDistance) && candidate > nearest)\n ) {\n nearest = candidate;\n nearestDistance = distance;\n }\n }\n return nearest;\n}\n\n/**\n * Moves through the ordered allowed-value set by an integer number of steps.\n *\n * This differs from adding `step * count` and snapping afterward at an\n * off-grid endpoint: with `max=94, step=10`, one decrement from `94` must land\n * on `90`, and one increment from `90` must reach the advertised maximum `94`.\n */\nexport function stepSteppedValue(current: number, count: number, range: SteppedRange): number {\n const value = snapSteppedValue(current, range);\n const distance = Math.abs(Math.trunc(count));\n if (!Number.isFinite(distance) || distance === 0) return value;\n const direction = Math.sign(count);\n const adjacent = adjacentSteppedValue(value, direction, range);\n\n // The first move accounts for a possibly off-grid endpoint. From there a\n // direct grid jump is equivalent to repeated adjacency, and avoids work that\n // grows with Page-step magnitudes or programmatic counts.\n const raw = adjacent + direction * (distance - 1) * effectiveStep(range.step);\n return snapSteppedValue(raw, range);\n}\n\n/** Returns the next member of the ordered endpoint-plus-grid set. */\nfunction adjacentSteppedValue(current: number, direction: number, range: SteppedRange): number {\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (direction > 0) {\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.floor(position) + 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate < current || nearlyEqual(candidate, current)) {\n gridIndex += 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate > current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.min(...candidates), range);\n }\n\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.ceil(position) - 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate > current || nearlyEqual(candidate, current)) {\n gridIndex -= 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate < current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.max(...candidates), range);\n}\n\n/** Adds one grid value when it falls inside the inclusive range. */\nfunction addGridCandidate(\n candidates: number[],\n index: number,\n range: SteppedRange,\n base: number,\n step: number,\n): void {\n const candidate = cleanGridValue(base + index * step, base, step);\n if (within(candidate, range.min, range.max)) candidates.push(clamp(candidate, range));\n}\n\n/** A finite authored base wins; otherwise the finite lower bound or zero does. */\nfunction stepBase(range: SteppedRange): number {\n if (range.base !== undefined && Number.isFinite(range.base)) return range.base;\n return Number.isFinite(range.min) ? range.min : 0;\n}\n\n/** Removes binary noise without discarding significant integer-place digits. */\nfunction cleanGridValue(value: number, base: number, step: number): number {\n const precision = Math.max(decimalPlaces(base), decimalPlaces(step));\n // `toFixed` accepts at most 100 fractional digits. Below that limit it rounds\n // according to the authored grid precision rather than an arbitrary total\n // significant-digit count, which keeps unit steps distinct at large bases.\n return precision <= 100 ? Number(value.toFixed(precision)) : value;\n}\n\n/** Number of fractional decimal places represented by a finite JS number. */\nfunction decimalPlaces(value: number): number {\n const [coefficient = \"\", exponentText] = Math.abs(value).toString().toLowerCase().split(\"e\");\n const fractionLength = coefficient.split(\".\")[1]?.length ?? 0;\n const exponent = exponentText === undefined ? 0 : Number(exponentText);\n return Math.max(0, fractionLength - exponent);\n}\n\n/** Inclusive range check tolerant only of arithmetic noise at an endpoint. */\nfunction within(value: number, min: number, max: number): boolean {\n return (value > min || nearlyEqual(value, min)) && (value < max || nearlyEqual(value, max));\n}\n\n/** Clamps a candidate whose only overshoot may be floating-point noise. */\nfunction clamp(value: number, range: SteppedRange): number {\n return Math.min(range.max, Math.max(range.min, value));\n}\n\n/** Relative comparison used only to collapse arithmetic noise, not real steps. */\nfunction nearlyEqual(left: number, right: number): boolean {\n const scale = Math.max(Math.abs(left), Math.abs(right));\n return (\n Number.isFinite(left) &&\n Number.isFinite(right) &&\n Math.abs(left - right) <= Number.EPSILON * scale\n );\n}\n\n/** Stable fallback for malformed ranges or `NaN` input. */\nfunction finiteFallback(min: number, max: number): number {\n if (Number.isFinite(min)) return min;\n if (Number.isFinite(max)) return max;\n return 0;\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { isRtl } from \"../utils/logical_scroll\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { OwnedPointerSession } from \"../utils/owned_pointer_session\";\nimport { rangeFraction } from \"../utils/range\";\nimport { type SteppedRange, snapSteppedValue, stepSteppedValue } from \"../utils/stepped_value\";\n\n/** CSS custom properties exposing each thumb's position (0..1) to the consumer. */\nconst START_PROPERTY = \"--stimeo--range-slider-start\";\nconst END_PROPERTY = \"--stimeo--range-slider-end\";\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\n\n/**\n * Headless, accessible **two-thumb range slider** behavior (APG Slider —\n * Multi-Thumb). A derivative of {@link SliderController}: it manages two thumbs\n * (`start` ≤ `end`) that constrain each other.\n *\n * Markup contract (identifier: `stimeo--range-slider`):\n * <div data-controller=\"stimeo--range-slider\"\n * data-stimeo--range-slider-min-value=\"0\"\n * data-stimeo--range-slider-max-value=\"100\"\n * data-stimeo--range-slider-step-value=\"1\"\n * data-stimeo--range-slider-start-value=\"20\"\n * data-stimeo--range-slider-end-value=\"80\">\n * <div data-stimeo--range-slider-target=\"track\"\n * data-action=\"pointerdown->stimeo--range-slider#onPointerDown\">\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Minimum\"\n * data-stimeo--range-slider-target=\"startThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Maximum\"\n * data-stimeo--range-slider-target=\"endThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * </div>\n * </div>\n *\n * @remarks\n * Behavior only — the consumer owns all layout (positioning the thumbs and the\n * selected range from the fractions). Only the horizontal orientation is handled.\n * Each thumb's movable range is bounded by the *other* thumb's current value,\n * reflected on its `aria-valuemin`/`aria-valuemax` so assistive tech announces the\n * live constraint.\n *\n * Behavior provided (per focused thumb):\n * - `ArrowRight`/`ArrowUp` increase and `ArrowLeft`/`ArrowDown` decrease by one\n * step; `Home`/`End` jump to that thumb's movable min/max; `PageUp`/`PageDown`\n * move by ten steps. A thumb never crosses the other.\n * - Pointer press/drag on the track moves the nearest thumb.\n * When the thumbs overlap, a press above their shared value selects `end`\n * and a press below selects `start`, so the pair remains expandable.\n * - `min`, `max`, `start`, and `end` must be finite. Invalid runtime endpoints\n * fall back to `0`/`100`; invalid thumb Values fall back to the corresponding\n * effective endpoint. A `max` below `min` collapses the range to `min`.\n * - `step` must be finite and positive; invalid runtime input falls back to `1`.\n * Finite movable endpoints remain allowed off the shared step grid.\n *\n * The fractions are value ratios, not positions, so only the consumer knows\n * whether their track mirrors under RTL. Set `logicalTrack` to declare that it\n * does: the pointer mapping and the horizontal arrow pair then follow the\n * writing direction. Left unset, nothing here reads `direction`.\n */\nexport class RangeSliderController extends Controller<HTMLElement> {\n static override targets = [\"track\", \"startThumb\", \"endThumb\"];\n static override values = {\n min: { type: Number, default: DEFAULT_MIN },\n max: { type: Number, default: DEFAULT_MAX },\n step: { type: Number, default: 1 },\n start: { type: Number, default: 0 },\n end: { type: Number, default: 100 },\n logicalTrack: { type: Boolean, default: false },\n };\n static actions = [\"onKeydown\", \"onPointerDown\"] as const;\n static events = [\"change\"] as const;\n\n declare readonly trackTarget: HTMLElement;\n declare readonly startThumbTarget: HTMLElement;\n declare readonly endThumbTarget: HTMLElement;\n declare readonly hasTrackTarget: boolean;\n declare readonly hasStartThumbTarget: boolean;\n declare readonly hasEndThumbTarget: boolean;\n declare minValue: number;\n declare maxValue: number;\n declare stepValue: number;\n declare startValue: number;\n declare endValue: number;\n declare logicalTrackValue: boolean;\n\n /** One initiating pointer owns each live drag and its stable target snapshot. */\n #drag: RangeSliderDrag | null = null;\n\n /** Whether the consumer declared a mirroring track and the direction mirrors it. */\n get #mirrored(): boolean {\n return this.logicalTrackValue && isRtl(this.element);\n }\n\n /**\n * Collapses a morph that swaps render inputs into one repaint, and refuses the\n * pass Stimulus delivers before `connect()`.\n */\n readonly #repaint = new MicrotaskCoalescer(() => this.#render());\n\n override connect(): void {\n this.#repaint.activate();\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#commit(pair.start, pair.end, null, false);\n }\n\n /** Cancels any active pointer drag so document listeners never leak. */\n override disconnect(): void {\n this.#repaint.cancel();\n this.#endDrag();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `min` at runtime. */\n minValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `max` at runtime. */\n maxValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `step` at runtime. */\n stepValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `start` at runtime. */\n startValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `end` at runtime. */\n endValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Hydrates a replacement start thumb and restores live-drag focus ownership. */\n startThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderStartThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Drops a stale start-thumb reference without orphaning the track gesture. */\n startThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Hydrates a replacement end thumb and restores live-drag focus ownership. */\n endThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderEndThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Drops a stale end-thumb reference without orphaning the track gesture. */\n endThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Ends a gesture whose geometry target disappeared or ceased being a target. */\n trackTargetDisconnected(track: HTMLElement): void {\n if (this.#drag?.track === track) this.#endDrag();\n }\n\n /** Keyboard stepping for whichever thumb is focused (the action's element). */\n onKeydown(event: KeyboardEvent): void {\n if (isReservedArrowChord(event)) return;\n const thumb = event.currentTarget as HTMLElement;\n const isStart = this.hasStartThumbTarget && thumb === this.startThumbTarget;\n const isEnd = this.hasEndThumbTarget && thumb === this.endThumbTarget;\n const effectiveRange = this.#effectiveRange;\n const pair = this.#currentPair(effectiveRange);\n let kind: RangeThumb;\n let current: number;\n let range: { min: number; max: number; step: number; base: number };\n if (isStart) {\n kind = \"start\";\n current = pair.start;\n range = {\n min: effectiveRange.min,\n max: pair.end,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n } else {\n if (!isEnd) return;\n kind = \"end\";\n current = pair.end;\n range = {\n min: pair.start,\n max: effectiveRange.max,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n }\n\n let next: number | null = null;\n // On a mirrored track the greater value sits at the visual left, so the\n // horizontal pair trades places; `Home`/`End` name bounds, not a direction.\n switch (this.#mirrored ? logicalArrowKey(event.key, this.element) : event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n next = stepSteppedValue(current, 1, range);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n next = stepSteppedValue(current, -1, range);\n break;\n case \"PageUp\":\n next = stepSteppedValue(current, 10, range);\n break;\n case \"PageDown\":\n next = stepSteppedValue(current, -10, range);\n break;\n case \"Home\":\n next = range.min;\n break;\n case \"End\":\n next = range.max;\n break;\n default:\n return;\n }\n event.preventDefault();\n this.#moveThumb(kind, next);\n }\n\n /** Begins a pointer drag on the track, moving the thumb nearest the press. */\n onPointerDown(event: PointerEvent): void {\n if (\n event.button !== 0 ||\n this.#drag ||\n !this.hasTrackTarget ||\n !this.hasStartThumbTarget ||\n !this.hasEndThumbTarget\n ) {\n return;\n }\n const track = this.trackTarget;\n // Resolve the direction once for the whole gesture: reading it per move\n // would query computed style on every frame, and a drag that flipped\n // mid-gesture would be incoherent anyway.\n const mirrored = this.#mirrored;\n const value = this.#valueFromClientX(event.clientX, mirrored, track);\n if (value === null) return;\n event.preventDefault();\n\n // Pick the nearer thumb. An ordinary midpoint tie stays deterministic on\n // start; an overlapped pair uses the press direction so it can expand.\n // Only read a target getter behind its has*Target guard — Stimulus throws\n // when an absent target is accessed.\n const pair = this.#currentPair(this.#effectiveRange);\n const kind = this.#nearestThumb(value, pair);\n let thumb: HTMLElement;\n if (kind === \"start\") thumb = this.startThumbTarget;\n else thumb = this.endThumbTarget;\n this.#moveThumb(kind, value);\n thumb.focus();\n\n const drag: RangeSliderDrag = { pointer: null, track, thumb, kind };\n drag.pointer = new OwnedPointerSession(event, track, {\n move: (move) => {\n if (!track.isConnected) {\n this.#endDrag();\n return;\n }\n const moved = this.#valueFromClientX(move.clientX, mirrored, track);\n if (moved !== null) this.#moveThumb(kind, moved);\n },\n end: () => {\n if (this.#drag === drag) this.#drag = null;\n },\n });\n this.#drag = drag;\n }\n\n /** Maps a pointer X coordinate to a raw value using the track geometry. */\n #valueFromClientX(clientX: number, mirrored: boolean, track: HTMLElement): number | null {\n const rect = track.getBoundingClientRect();\n if (rect.width === 0) return null;\n const offset = (clientX - rect.left) / rect.width;\n const fraction = mirrored ? 1 - offset : offset;\n const range = this.#effectiveRange;\n return range.min + fraction * (range.max - range.min);\n }\n\n /**\n * Chooses the closest thumb while keeping an overlapped pair expandable.\n * Ordinary midpoint ties stay deterministic on `start`; at an overlap, a\n * press above the shared value selects `end` and a press below selects\n * `start`.\n */\n #nearestThumb(value: number, pair: RangePair): RangeThumb {\n const startDistance = Math.abs(value - pair.start);\n const endDistance = Math.abs(value - pair.end);\n if (endDistance < startDistance) return \"end\";\n if (pair.start === pair.end && value > pair.start) return \"end\";\n return \"start\";\n }\n\n /** Moves one thumb to a new raw value, keeping the pair ordered. */\n #moveThumb(kind: RangeThumb, raw: number): void {\n const pair = this.#currentPair(this.#effectiveRange);\n if (kind === \"start\") {\n this.#commit(raw, pair.end, \"start\", true);\n } else {\n this.#commit(pair.start, raw, \"end\", true);\n }\n }\n\n /**\n * Clamps and snaps `start`/`end`, enforces `start ≤ end`, stores the pair, and\n * reflects it onto the thumbs' ARIA attributes and the range custom\n * properties. Dispatches `stimeo--range-slider:change` only when a\n * user-driven update changes the normalized pair, with\n * `{ start: number, end: number }` in `detail`.\n */\n #commit(start: number, end: number, moving: RangeThumb | null, notify: boolean): void {\n const range = this.#effectiveRange;\n const previous = this.#currentPair(range);\n let nextStart = snapSteppedValue(start, range);\n let nextEnd = snapSteppedValue(end, range);\n // Keep them ordered: a thumb pushed past its partner stops at the partner.\n if (nextStart > nextEnd) {\n if (moving === \"start\") nextStart = nextEnd;\n else if (moving === \"end\") nextEnd = nextStart;\n else [nextStart, nextEnd] = [nextEnd, nextStart];\n }\n\n if (!Object.is(this.startValue, nextStart)) this.startValue = nextStart;\n if (!Object.is(this.endValue, nextEnd)) this.endValue = nextEnd;\n const pair = { start: nextStart, end: nextEnd };\n this.#renderPair(pair, range);\n\n if (notify && (nextStart !== previous.start || nextEnd !== previous.end)) {\n this.dispatch(\"change\", { detail: { start: nextStart, end: nextEnd } });\n }\n }\n\n /**\n * Reflects morph-supplied Values without writing them back or dispatching.\n *\n * @stimeoRenderRoot\n */\n #render(): void {\n const range = this.#effectiveRange;\n this.#renderPair(this.#currentPair(range), range);\n }\n\n /** Reflects one normalized pair onto both thumbs and CSS properties. */\n #renderPair(pair: RangePair, range: SteppedRange): void {\n if (this.hasStartThumbTarget) {\n this.#renderStartThumb(this.startThumbTarget, pair, range);\n }\n if (this.hasEndThumbTarget) {\n this.#renderEndThumb(this.endThumbTarget, pair, range);\n }\n this.#renderFractions(pair, range);\n }\n\n /** Writes only changed ARIA for the lower thumb. */\n #renderStartThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", range.min);\n this.#setAria(thumb, \"aria-valuemax\", pair.end);\n this.#setAria(thumb, \"aria-valuenow\", pair.start);\n }\n\n /** Writes only changed ARIA for the upper thumb. */\n #renderEndThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", pair.start);\n this.#setAria(thumb, \"aria-valuemax\", range.max);\n this.#setAria(thumb, \"aria-valuenow\", pair.end);\n }\n\n /** Writes one numeric ARIA attribute only when its serialized value changed. */\n #setAria(thumb: HTMLElement, name: string, value: number): void {\n const next = String(value);\n if (thumb.getAttribute(name) !== next) thumb.setAttribute(name, next);\n }\n\n /** Writes the two behavior-only fraction hooks only when they changed. */\n #renderFractions(pair: RangePair, range: SteppedRange): void {\n const start = String(rangeFraction(pair.start, range.min, range.max));\n const end = String(rangeFraction(pair.end, range.min, range.max));\n if (this.element.style.getPropertyValue(START_PROPERTY) !== start) {\n this.element.style.setProperty(START_PROPERTY, start);\n }\n if (this.element.style.getPropertyValue(END_PROPERTY) !== end) {\n this.element.style.setProperty(END_PROPERTY, end);\n }\n }\n\n /** Current normalized and ordered pair derived from live declarative Values. */\n #currentPair(range: SteppedRange): RangePair {\n const rawStart = Number.isFinite(this.startValue) ? this.startValue : range.min;\n const rawEnd = Number.isFinite(this.endValue) ? this.endValue : range.max;\n const start = snapSteppedValue(rawStart, range);\n const end = snapSteppedValue(rawEnd, range);\n if (start <= end) return { start, end };\n return { start: end, end: start };\n }\n\n /**\n * Finite ordered range used by ARIA, keyboard, pointer, and CSS reflection.\n * Invalid endpoints fall back to the public defaults; an authored `max`\n * below `min` collapses to the finite minimum.\n */\n get #effectiveRange(): SteppedRange {\n const min = Number.isFinite(this.minValue) ? this.minValue : DEFAULT_MIN;\n const authoredMax = Number.isFinite(this.maxValue) ? this.maxValue : DEFAULT_MAX;\n return { min, max: Math.max(min, authoredMax), step: this.stepValue, base: min };\n }\n\n /** Ends the current pointer session without dispatching another change. */\n #endDrag(): void {\n const drag = this.#drag;\n this.#drag = null;\n drag?.pointer?.end();\n }\n}\n\n/** Which thumb owns a keyboard or pointer move. */\ntype RangeThumb = \"start\" | \"end\";\n\n/** One normalized pair reflected on the two public slider roles. */\ninterface RangePair {\n readonly start: number;\n readonly end: number;\n}\n\n/** Stable DOM and gesture state owned for the duration of one pointer drag. */\ninterface RangeSliderDrag {\n pointer: OwnedPointerSession | null;\n readonly track: HTMLElement;\n thumb: HTMLElement | null;\n readonly kind: RangeThumb;\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/owned_pointer_session.ts","../../src/utils/range.ts","../../src/utils/stepped_value.ts","../../src/controllers/range_slider_controller.ts"],"names":["position"],"mappings":"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","file":"range_slider_controller.js","sourcesContent":["/** 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 * 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","/** Callbacks driven by one owned pointer until it ends or is cancelled. */\nexport interface OwnedPointerSessionHandlers {\n /** Receives movement from the initiating pointer only. */\n readonly move: (event: PointerEvent) => void;\n /** Runs once after every listener and pointer capture have been released. */\n readonly end?: () => void;\n}\n\n/**\n * Owns one pointer across document-level movement and termination events.\n *\n * A controller may have at most one instance at a time. The session filters\n * every event by the initiating `pointerId`, captures the pointer when the DOM\n * implementation supports it, and binds all fallback document listeners to one\n * abort signal. Calling {@link OwnedPointerSession.end} is idempotent.\n */\nexport class OwnedPointerSession {\n readonly pointerId: number;\n readonly #owner: HTMLElement;\n readonly #handlers: OwnedPointerSessionHandlers;\n readonly #abort = new AbortController();\n #active = true;\n\n constructor(start: PointerEvent, owner: HTMLElement, handlers: OwnedPointerSessionHandlers) {\n this.pointerId = start.pointerId;\n this.#owner = owner;\n this.#handlers = handlers;\n\n const { signal } = this.#abort;\n owner.ownerDocument.addEventListener(\"pointermove\", this.#onMove, { signal });\n owner.ownerDocument.addEventListener(\"pointerup\", this.#onEndEvent, { signal });\n owner.ownerDocument.addEventListener(\"pointercancel\", this.#onEndEvent, { signal });\n owner.addEventListener(\"lostpointercapture\", this.#onLostCapture, { signal });\n\n // Pointer capture is progressive here: happy-dom and older DOM shims may not\n // implement it, while the document listeners still preserve ownership.\n try {\n owner.setPointerCapture?.(this.pointerId);\n } catch {\n // A synthetic or already-ended pointer cannot be captured; filtering and\n // AbortController teardown remain sufficient for that environment.\n }\n }\n\n /** Whether this session still owns its pointer and listeners. */\n get active(): boolean {\n return this.#active;\n }\n\n /** Whether `event` belongs to the initiating pointer of the live session. */\n owns(event: PointerEvent): boolean {\n return this.#active && event.pointerId === this.pointerId;\n }\n\n /** Releases capture/listeners and invokes the end callback exactly once. */\n end(): void {\n if (!this.#active) return;\n this.#active = false;\n this.#abort.abort();\n try {\n this.#owner.releasePointerCapture?.(this.pointerId);\n } catch {\n // Losing capture because the owner detached is already an ended session.\n }\n this.#handlers.end?.();\n }\n\n readonly #onMove = (event: PointerEvent): void => {\n if (this.owns(event)) this.#handlers.move(event);\n };\n\n readonly #onEndEvent = (event: PointerEvent): void => {\n if (this.owns(event)) this.end();\n };\n\n readonly #onLostCapture = (event: Event): void => {\n const pointerId = (event as PointerEvent).pointerId;\n if (typeof pointerId === \"number\" && pointerId !== this.pointerId) return;\n this.end();\n };\n}\n","/**\n * Range normalization shared by the value-bearing controllers (progress, meter,\n * slider, range-slider).\n *\n * Each of them publishes \"where the value sits inside `[min, max]`\" as a CSS\n * custom property the consumer multiplies a track by, and each has to answer the\n * same degenerate cases: empty and inverted ranges cannot express progress, and\n * malformed Number Values can produce `NaN`. Keeping the rule in one place is\n * what makes those answers identical across the four.\n */\n\n/**\n * Fraction of `[min, max]` that `value` occupies, always within `[0, 1]`.\n *\n * `value` is clamped into the range first, so a value outside it reports a full\n * or empty track rather than pushing the fraction past the ends.\n *\n * An empty, inverted, or non-numeric range yields `0`. That is a deliberate\n * floor rather than a computed result: `min === max` would produce `NaN`, and\n * `min > max` would report a full track for a value that is really out of range.\n * Non-finite results are floored for the same reason. These results reach\n * assistive tech, because the same fraction drives the percentage substituted\n * into `aria-valuetext`.\n */\nexport function rangeFraction(value: number, min: number, max: number): number {\n const span = max - min;\n if (!(span > 0)) return 0;\n\n const clamped = Math.min(max, Math.max(min, value));\n let fraction: number;\n if (Number.isFinite(span)) {\n fraction = (clamped - min) / span;\n } else {\n // Scaling preserves the ratio when two finite endpoints straddle zero so\n // widely that their subtraction overflows to Infinity.\n const scale = Math.max(Math.abs(min), Math.abs(max));\n fraction = (clamped / scale - min / scale) / (max / scale - min / scale);\n }\n\n if (!Number.isFinite(fraction)) return 0;\n return Math.min(1, Math.max(0, fraction));\n}\n","/** Configuration for a value constrained to a stepped numeric range. */\nexport interface SteppedRange {\n /** Inclusive lower endpoint. May be infinite for an unbounded control. */\n readonly min: number;\n /** Inclusive upper endpoint. May be infinite for an unbounded control. */\n readonly max: number;\n /** Requested step. Non-finite and non-positive values fall back to `1`. */\n readonly step: number;\n /** Step-grid origin. Defaults to a finite `min`, otherwise `0`. */\n readonly base?: number;\n}\n\n/** The positive finite step used at runtime and by keyboard stepping. */\nexport function effectiveStep(step: number): number {\n return Number.isFinite(step) && step > 0 ? step : 1;\n}\n\n/**\n * Clamps a raw value and selects its nearest allowed value.\n *\n * The allowed set is the step grid plus each finite range endpoint. Keeping the\n * endpoints in that set makes an authored `aria-valuemin`/`aria-valuemax`\n * truthful even when the upper endpoint is not aligned to the grid. A value\n * exactly between two allowed values resolves upward.\n */\nexport function snapSteppedValue(raw: number, range: SteppedRange): number {\n if (!(range.min <= range.max)) return finiteFallback(range.min, range.max);\n\n const input = Number.isNaN(raw) ? finiteFallback(range.min, range.max) : raw;\n const clamped = Math.min(range.max, Math.max(range.min, input));\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (Number.isFinite(range.min)) candidates.push(range.min);\n if (Number.isFinite(range.max)) candidates.push(range.max);\n\n const gridPosition = (clamped - base) / step;\n if (Number.isFinite(gridPosition)) {\n addGridCandidate(candidates, Math.floor(gridPosition), range, base, step);\n addGridCandidate(candidates, Math.ceil(gridPosition), range, base, step);\n }\n\n if (candidates.length === 0) return clamped;\n let nearest = candidates[0] as number;\n let nearestDistance = Math.abs(clamped - nearest);\n for (const candidate of candidates.slice(1)) {\n const distance = Math.abs(clamped - candidate);\n if (\n distance < nearestDistance ||\n (nearlyEqual(distance, nearestDistance) && candidate > nearest)\n ) {\n nearest = candidate;\n nearestDistance = distance;\n }\n }\n return nearest;\n}\n\n/**\n * Moves through the ordered allowed-value set by an integer number of steps.\n *\n * This differs from adding `step * count` and snapping afterward at an\n * off-grid endpoint: with `max=94, step=10`, one decrement from `94` must land\n * on `90`, and one increment from `90` must reach the advertised maximum `94`.\n */\nexport function stepSteppedValue(current: number, count: number, range: SteppedRange): number {\n const value = snapSteppedValue(current, range);\n const distance = Math.abs(Math.trunc(count));\n if (!Number.isFinite(distance) || distance === 0) return value;\n const direction = Math.sign(count);\n const adjacent = adjacentSteppedValue(value, direction, range);\n\n // The first move accounts for a possibly off-grid endpoint. From there a\n // direct grid jump is equivalent to repeated adjacency, and avoids work that\n // grows with Page-step magnitudes or programmatic counts.\n const raw = adjacent + direction * (distance - 1) * effectiveStep(range.step);\n return snapSteppedValue(raw, range);\n}\n\n/** Returns the next member of the ordered endpoint-plus-grid set. */\nfunction adjacentSteppedValue(current: number, direction: number, range: SteppedRange): number {\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (direction > 0) {\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.floor(position) + 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate < current || nearlyEqual(candidate, current)) {\n gridIndex += 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate > current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.min(...candidates), range);\n }\n\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.ceil(position) - 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate > current || nearlyEqual(candidate, current)) {\n gridIndex -= 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate < current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.max(...candidates), range);\n}\n\n/** Adds one grid value when it falls inside the inclusive range. */\nfunction addGridCandidate(\n candidates: number[],\n index: number,\n range: SteppedRange,\n base: number,\n step: number,\n): void {\n const candidate = cleanGridValue(base + index * step, base, step);\n if (within(candidate, range.min, range.max)) candidates.push(clamp(candidate, range));\n}\n\n/** A finite authored base wins; otherwise the finite lower bound or zero does. */\nfunction stepBase(range: SteppedRange): number {\n if (range.base !== undefined && Number.isFinite(range.base)) return range.base;\n return Number.isFinite(range.min) ? range.min : 0;\n}\n\n/** Removes binary noise without discarding significant integer-place digits. */\nfunction cleanGridValue(value: number, base: number, step: number): number {\n const precision = Math.max(decimalPlaces(base), decimalPlaces(step));\n // `toFixed` accepts at most 100 fractional digits. Below that limit it rounds\n // according to the authored grid precision rather than an arbitrary total\n // significant-digit count, which keeps unit steps distinct at large bases.\n return precision <= 100 ? Number(value.toFixed(precision)) : value;\n}\n\n/** Number of fractional decimal places represented by a finite JS number. */\nfunction decimalPlaces(value: number): number {\n const [coefficient = \"\", exponentText] = Math.abs(value).toString().toLowerCase().split(\"e\");\n const fractionLength = coefficient.split(\".\")[1]?.length ?? 0;\n const exponent = exponentText === undefined ? 0 : Number(exponentText);\n return Math.max(0, fractionLength - exponent);\n}\n\n/** Inclusive range check tolerant only of arithmetic noise at an endpoint. */\nfunction within(value: number, min: number, max: number): boolean {\n return (value > min || nearlyEqual(value, min)) && (value < max || nearlyEqual(value, max));\n}\n\n/** Clamps a candidate whose only overshoot may be floating-point noise. */\nfunction clamp(value: number, range: SteppedRange): number {\n return Math.min(range.max, Math.max(range.min, value));\n}\n\n/** Relative comparison used only to collapse arithmetic noise, not real steps. */\nfunction nearlyEqual(left: number, right: number): boolean {\n const scale = Math.max(Math.abs(left), Math.abs(right));\n return (\n Number.isFinite(left) &&\n Number.isFinite(right) &&\n Math.abs(left - right) <= Number.EPSILON * scale\n );\n}\n\n/** Stable fallback for malformed ranges or `NaN` input. */\nfunction finiteFallback(min: number, max: number): number {\n if (Number.isFinite(min)) return min;\n if (Number.isFinite(max)) return max;\n return 0;\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { isRtl } from \"../utils/logical_scroll\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { OwnedPointerSession } from \"../utils/owned_pointer_session\";\nimport { rangeFraction } from \"../utils/range\";\nimport { type SteppedRange, snapSteppedValue, stepSteppedValue } from \"../utils/stepped_value\";\n\n/** CSS custom properties exposing each thumb's position (0..1) to the consumer. */\nconst START_PROPERTY = \"--stimeo--range-slider-start\";\nconst END_PROPERTY = \"--stimeo--range-slider-end\";\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\n\n/**\n * Headless, accessible **two-thumb range slider** behavior (APG Slider —\n * Multi-Thumb). A derivative of {@link SliderController}: it manages two thumbs\n * (`start` ≤ `end`) that constrain each other.\n *\n * Markup contract (identifier: `stimeo--range-slider`):\n * <div data-controller=\"stimeo--range-slider\"\n * data-stimeo--range-slider-min-value=\"0\"\n * data-stimeo--range-slider-max-value=\"100\"\n * data-stimeo--range-slider-step-value=\"1\"\n * data-stimeo--range-slider-start-value=\"20\"\n * data-stimeo--range-slider-end-value=\"80\">\n * <div data-stimeo--range-slider-target=\"track\"\n * data-action=\"pointerdown->stimeo--range-slider#onPointerDown\">\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Minimum\"\n * data-stimeo--range-slider-target=\"startThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Maximum\"\n * data-stimeo--range-slider-target=\"endThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * </div>\n * </div>\n *\n * @remarks\n * Behavior only — the consumer owns all layout (positioning the thumbs and the\n * selected range from the fractions). Only the horizontal orientation is handled.\n * Each thumb's movable range is bounded by the *other* thumb's current value,\n * reflected on its `aria-valuemin`/`aria-valuemax` so assistive tech announces the\n * live constraint.\n *\n * Behavior provided (per focused thumb):\n * - `ArrowRight`/`ArrowUp` increase and `ArrowLeft`/`ArrowDown` decrease by one\n * step; `Home`/`End` jump to that thumb's movable min/max; `PageUp`/`PageDown`\n * move by ten steps. A thumb never crosses the other.\n * - Pointer press/drag on the track moves the nearest thumb.\n * When the thumbs overlap, a press above their shared value selects `end`\n * and a press below selects `start`, so the pair remains expandable.\n * - `min`, `max`, `start`, and `end` must be finite. Invalid runtime endpoints\n * fall back to `0`/`100`; invalid thumb Values fall back to the corresponding\n * effective endpoint. A `max` below `min` collapses the range to `min`.\n * - `step` must be finite and positive; invalid runtime input falls back to `1`.\n * Finite movable endpoints remain allowed off the shared step grid.\n *\n * The fractions are value ratios, not positions, so only the consumer knows\n * whether their track mirrors under RTL. Set `logicalTrack` to declare that it\n * does: the pointer mapping and the horizontal arrow pair then follow the\n * writing direction. Left unset, nothing here reads `direction`.\n */\nexport class RangeSliderController extends Controller<HTMLElement> {\n static override targets = [\"track\", \"startThumb\", \"endThumb\"];\n static override values = {\n min: { type: Number, default: DEFAULT_MIN },\n max: { type: Number, default: DEFAULT_MAX },\n step: { type: Number, default: 1 },\n start: { type: Number, default: 0 },\n end: { type: Number, default: 100 },\n logicalTrack: { type: Boolean, default: false },\n };\n static actions = [\"onKeydown\", \"onPointerDown\"] as const;\n static events = [\"change\"] as const;\n\n declare readonly trackTarget: HTMLElement;\n declare readonly startThumbTarget: HTMLElement;\n declare readonly endThumbTarget: HTMLElement;\n declare readonly hasTrackTarget: boolean;\n declare readonly hasStartThumbTarget: boolean;\n declare readonly hasEndThumbTarget: boolean;\n declare minValue: number;\n declare maxValue: number;\n declare stepValue: number;\n declare startValue: number;\n declare endValue: number;\n declare logicalTrackValue: boolean;\n\n /** One initiating pointer owns each live drag and its stable target snapshot. */\n #drag: RangeSliderDrag | null = null;\n\n /** Whether the consumer declared a mirroring track and the direction mirrors it. */\n get #mirrored(): boolean {\n return this.logicalTrackValue && isRtl(this.element);\n }\n\n /**\n * Collapses a morph that swaps render inputs into one repaint, and refuses the\n * pass Stimulus delivers before `connect()`.\n */\n readonly #repaint = new MicrotaskCoalescer(() => this.#render());\n\n override connect(): void {\n this.#repaint.activate();\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#commit(pair.start, pair.end, null, false);\n }\n\n /** Cancels any active pointer drag so document listeners never leak. */\n override disconnect(): void {\n this.#repaint.cancel();\n this.#endDrag();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `min` at runtime. */\n minValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `max` at runtime. */\n maxValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `step` at runtime. */\n stepValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `start` at runtime. */\n startValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `end` at runtime. */\n endValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Hydrates a replacement start thumb and restores live-drag focus ownership. */\n startThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderStartThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Drops a stale start-thumb reference without orphaning the track gesture. */\n startThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Hydrates a replacement end thumb and restores live-drag focus ownership. */\n endThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderEndThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Drops a stale end-thumb reference without orphaning the track gesture. */\n endThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Ends a gesture whose geometry target disappeared or ceased being a target. */\n trackTargetDisconnected(track: HTMLElement): void {\n if (this.#drag?.track === track) this.#endDrag();\n }\n\n /** Keyboard stepping for whichever thumb is focused (the action's element). */\n onKeydown(event: KeyboardEvent): void {\n if (isReservedArrowChord(event)) return;\n const thumb = event.currentTarget as HTMLElement;\n const isStart = this.hasStartThumbTarget && thumb === this.startThumbTarget;\n const isEnd = this.hasEndThumbTarget && thumb === this.endThumbTarget;\n const effectiveRange = this.#effectiveRange;\n const pair = this.#currentPair(effectiveRange);\n let kind: RangeThumb;\n let current: number;\n let range: { min: number; max: number; step: number; base: number };\n if (isStart) {\n kind = \"start\";\n current = pair.start;\n range = {\n min: effectiveRange.min,\n max: pair.end,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n } else {\n if (!isEnd) return;\n kind = \"end\";\n current = pair.end;\n range = {\n min: pair.start,\n max: effectiveRange.max,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n }\n\n let next: number | null = null;\n // On a mirrored track the greater value sits at the visual left, so the\n // horizontal pair trades places; `Home`/`End` name bounds, not a direction.\n switch (this.#mirrored ? logicalArrowKey(event.key, this.element) : event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n next = stepSteppedValue(current, 1, range);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n next = stepSteppedValue(current, -1, range);\n break;\n case \"PageUp\":\n next = stepSteppedValue(current, 10, range);\n break;\n case \"PageDown\":\n next = stepSteppedValue(current, -10, range);\n break;\n case \"Home\":\n next = range.min;\n break;\n case \"End\":\n next = range.max;\n break;\n default:\n return;\n }\n event.preventDefault();\n this.#moveThumb(kind, next);\n }\n\n /** Begins a pointer drag on the track, moving the thumb nearest the press. */\n onPointerDown(event: PointerEvent): void {\n if (\n event.button !== 0 ||\n this.#drag ||\n !this.hasTrackTarget ||\n !this.hasStartThumbTarget ||\n !this.hasEndThumbTarget\n ) {\n return;\n }\n const track = this.trackTarget;\n // Resolve the direction once for the whole gesture: reading it per move\n // would query computed style on every frame, and a drag that flipped\n // mid-gesture would be incoherent anyway.\n const mirrored = this.#mirrored;\n const value = this.#valueFromClientX(event.clientX, mirrored, track);\n if (value === null) return;\n event.preventDefault();\n\n // Pick the nearer thumb. An ordinary midpoint tie stays deterministic on\n // start; an overlapped pair uses the press direction so it can expand.\n // Only read a target getter behind its has*Target guard — Stimulus throws\n // when an absent target is accessed.\n const pair = this.#currentPair(this.#effectiveRange);\n const kind = this.#nearestThumb(value, pair);\n let thumb: HTMLElement;\n if (kind === \"start\") thumb = this.startThumbTarget;\n else thumb = this.endThumbTarget;\n this.#moveThumb(kind, value);\n thumb.focus();\n\n const drag: RangeSliderDrag = { pointer: null, track, thumb, kind };\n drag.pointer = new OwnedPointerSession(event, track, {\n move: (move) => {\n if (!track.isConnected) {\n this.#endDrag();\n return;\n }\n const moved = this.#valueFromClientX(move.clientX, mirrored, track);\n if (moved !== null) this.#moveThumb(kind, moved);\n },\n end: () => {\n if (this.#drag === drag) this.#drag = null;\n },\n });\n this.#drag = drag;\n }\n\n /** Maps a pointer X coordinate to a raw value using the track geometry. */\n #valueFromClientX(clientX: number, mirrored: boolean, track: HTMLElement): number | null {\n const rect = track.getBoundingClientRect();\n if (rect.width === 0) return null;\n const offset = (clientX - rect.left) / rect.width;\n const fraction = mirrored ? 1 - offset : offset;\n const range = this.#effectiveRange;\n return range.min + fraction * (range.max - range.min);\n }\n\n /**\n * Chooses the closest thumb while keeping an overlapped pair expandable.\n * Ordinary midpoint ties stay deterministic on `start`; at an overlap, a\n * press above the shared value selects `end` and a press below selects\n * `start`.\n */\n #nearestThumb(value: number, pair: RangePair): RangeThumb {\n const startDistance = Math.abs(value - pair.start);\n const endDistance = Math.abs(value - pair.end);\n if (endDistance < startDistance) return \"end\";\n if (pair.start === pair.end && value > pair.start) return \"end\";\n return \"start\";\n }\n\n /** Moves one thumb to a new raw value, keeping the pair ordered. */\n #moveThumb(kind: RangeThumb, raw: number): void {\n const pair = this.#currentPair(this.#effectiveRange);\n if (kind === \"start\") {\n this.#commit(raw, pair.end, \"start\", true);\n } else {\n this.#commit(pair.start, raw, \"end\", true);\n }\n }\n\n /**\n * Clamps and snaps `start`/`end`, enforces `start ≤ end`, stores the pair, and\n * reflects it onto the thumbs' ARIA attributes and the range custom\n * properties. Dispatches `stimeo--range-slider:change` only when a\n * user-driven update changes the normalized pair, with\n * `{ start: number, end: number }` in `detail`.\n */\n #commit(start: number, end: number, moving: RangeThumb | null, notify: boolean): void {\n const range = this.#effectiveRange;\n const previous = this.#currentPair(range);\n let nextStart = snapSteppedValue(start, range);\n let nextEnd = snapSteppedValue(end, range);\n // Keep them ordered: a thumb pushed past its partner stops at the partner.\n if (nextStart > nextEnd) {\n if (moving === \"start\") nextStart = nextEnd;\n else if (moving === \"end\") nextEnd = nextStart;\n else [nextStart, nextEnd] = [nextEnd, nextStart];\n }\n\n if (!Object.is(this.startValue, nextStart)) this.startValue = nextStart;\n if (!Object.is(this.endValue, nextEnd)) this.endValue = nextEnd;\n const pair = { start: nextStart, end: nextEnd };\n this.#renderPair(pair, range);\n\n if (notify && (nextStart !== previous.start || nextEnd !== previous.end)) {\n this.dispatch(\"change\", { detail: { start: nextStart, end: nextEnd } });\n }\n }\n\n /**\n * Reflects morph-supplied Values without writing them back or dispatching.\n *\n * @stimeoRenderRoot\n */\n #render(): void {\n const range = this.#effectiveRange;\n this.#renderPair(this.#currentPair(range), range);\n }\n\n /** Reflects one normalized pair onto both thumbs and CSS properties. */\n #renderPair(pair: RangePair, range: SteppedRange): void {\n if (this.hasStartThumbTarget) {\n this.#renderStartThumb(this.startThumbTarget, pair, range);\n }\n if (this.hasEndThumbTarget) {\n this.#renderEndThumb(this.endThumbTarget, pair, range);\n }\n this.#renderFractions(pair, range);\n }\n\n /** Writes only changed ARIA for the lower thumb. */\n #renderStartThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", range.min);\n this.#setAria(thumb, \"aria-valuemax\", pair.end);\n this.#setAria(thumb, \"aria-valuenow\", pair.start);\n }\n\n /** Writes only changed ARIA for the upper thumb. */\n #renderEndThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", pair.start);\n this.#setAria(thumb, \"aria-valuemax\", range.max);\n this.#setAria(thumb, \"aria-valuenow\", pair.end);\n }\n\n /** Writes one numeric ARIA attribute only when its serialized value changed. */\n #setAria(thumb: HTMLElement, name: string, value: number): void {\n const next = String(value);\n if (thumb.getAttribute(name) !== next) thumb.setAttribute(name, next);\n }\n\n /** Writes the two behavior-only fraction hooks only when they changed. */\n #renderFractions(pair: RangePair, range: SteppedRange): void {\n const start = String(rangeFraction(pair.start, range.min, range.max));\n const end = String(rangeFraction(pair.end, range.min, range.max));\n if (this.element.style.getPropertyValue(START_PROPERTY) !== start) {\n this.element.style.setProperty(START_PROPERTY, start);\n }\n if (this.element.style.getPropertyValue(END_PROPERTY) !== end) {\n this.element.style.setProperty(END_PROPERTY, end);\n }\n }\n\n /** Current normalized and ordered pair derived from live declarative Values. */\n #currentPair(range: SteppedRange): RangePair {\n const rawStart = Number.isFinite(this.startValue) ? this.startValue : range.min;\n const rawEnd = Number.isFinite(this.endValue) ? this.endValue : range.max;\n const start = snapSteppedValue(rawStart, range);\n const end = snapSteppedValue(rawEnd, range);\n if (start <= end) return { start, end };\n return { start: end, end: start };\n }\n\n /**\n * Finite ordered range used by ARIA, keyboard, pointer, and CSS reflection.\n * Invalid endpoints fall back to the public defaults; an authored `max`\n * below `min` collapses to the finite minimum.\n */\n get #effectiveRange(): SteppedRange {\n const min = Number.isFinite(this.minValue) ? this.minValue : DEFAULT_MIN;\n const authoredMax = Number.isFinite(this.maxValue) ? this.maxValue : DEFAULT_MAX;\n return { min, max: Math.max(min, authoredMax), step: this.stepValue, base: min };\n }\n\n /** Ends the current pointer session without dispatching another change. */\n #endDrag(): void {\n const drag = this.#drag;\n this.#drag = null;\n drag?.pointer?.end();\n }\n}\n\n/** Which thumb owns a keyboard or pointer move. */\ntype RangeThumb = \"start\" | \"end\";\n\n/** One normalized pair reflected on the two public slider roles. */\ninterface RangePair {\n readonly start: number;\n readonly end: number;\n}\n\n/** Stable DOM and gesture state owned for the duration of one pointer drag. */\ninterface RangeSliderDrag {\n pointer: OwnedPointerSession | null;\n readonly track: HTMLElement;\n thumb: HTMLElement | null;\n readonly kind: RangeThumb;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/attribute_lease.ts","../../src/utils/before_cache_reset.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/roving_tabindex.ts","../../src/utils/tabindex_loan.ts","../../src/controllers/rating_controller.ts"],"names":[],"mappings":"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","file":"rating_controller.js","sourcesContent":["/** 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","/** One temporarily controlled attribute value and the authored value it displaced. */\ninterface AttributeLeaseRecord {\n readonly original: string | null;\n written: string | null;\n}\n\n/**\n * Temporarily controls one attribute across a changing set of elements.\n *\n * The first write remembers the authored value, including the distinction between\n * an absent attribute and an authored empty string. Returning a lease restores that\n * value only while the attribute still matches the controller's last write. If a\n * consumer changed it in the meantime, the consumer owns the new value and teardown\n * leaves it alone.\n *\n * A `null` write deliberately removes the attribute while retaining the lease. This\n * is useful for derived ARIA whose valid absence is itself controller state, such as\n * an unbounded `aria-valuemin` or a blank spinbutton's `aria-valuenow`.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events.\n * A consumer that must not let a derived value become the authored baseline of a\n * cached page returns its leases from its own `turbo:before-cache` rewind, where the\n * matching `disconnect()` also releases the subscription.\n */\nexport class AttributeLease<T extends Element = Element> {\n readonly #attribute: string;\n readonly #records = new Map<T, AttributeLeaseRecord>();\n\n /** @param attribute - The attribute whose temporary values this lease owns. */\n constructor(attribute: string) {\n this.#attribute = attribute;\n }\n\n /** Writes or removes the leased attribute while preserving its authored value. */\n write(element: T, value: string | null): void {\n const existing = this.#records.get(element);\n if (existing) {\n existing.written = value;\n } else {\n this.#records.set(element, {\n original: element.getAttribute(this.#attribute),\n written: value,\n });\n }\n\n this.#reflect(element, value);\n }\n\n /** Returns one lease without overwriting a value subsequently authored by a consumer. */\n return(element: T): void {\n const record = this.#records.get(element);\n if (!record) return;\n this.#records.delete(element);\n const stillOwned = element.getAttribute(this.#attribute) === record.written;\n if (stillOwned) this.#reflect(element, record.original);\n }\n\n /** Reflects only a real value transition, avoiding self-triggered mutation work. */\n #reflect(element: T, value: string | null): void {\n if (element.getAttribute(this.#attribute) === value) return;\n if (value === null) element.removeAttribute(this.#attribute);\n else element.setAttribute(this.#attribute, value);\n }\n\n /** Returns every outstanding lease using the same ownership check as {@link return}. */\n returnAll(): void {\n for (const element of Array.from(this.#records.keys())) this.return(element);\n }\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way (the `MicrotaskCoalescer` split).\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/**\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 * 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 { BeforeCacheReset } from \"./before_cache_reset\";\n\n/**\n * Shared bookkeeping for a `tabindex` a controller lends an element temporarily.\n *\n * A controller that must move focus somewhere the author never made focusable\n * (a landmark root, a scroll destination) reaches for the same trick: add a\n * `tabindex` just-in-time and hand it back once it is no longer needed. The\n * borrow is the easy half; the return is what the two conditions below are for.\n *\n * **Returning needs two conditions, not one.** Owning the borrow is not enough:\n * the attribute must also still hold the value this instance wrote. A consumer\n * that changed it afterwards — `tabindex=\"0\"` to make the root its own Tab stop\n * — owns it now, and removing it there silently discards authored markup. The\n * bookkeeping is dropped either way, since the loan is over regardless of who\n * ends up owning the value.\n *\n * **Never borrow over an existing value.** An element that already carries a\n * `tabindex` is the author's to control, so there is nothing to lend and nothing\n * to return.\n *\n * Every live loan also owns a shared `turbo:before-cache` subscription. The loan\n * is returned before Turbo can copy it into a snapshot, so consumers get cache\n * safety without duplicating a lifecycle hook; `returnAll()` removes the\n * subscription again as soon as no loan remains.\n *\n * The registry is keyed by element, so a controller borrowing on a single\n * element (`this.element`) and one borrowing across a changing set of targets\n * use the same API — the single-element case is a set of one. It holds no\n * opinion about *when* to borrow or where focus goes next; that stays in the\n * controller.\n *\n * **The API is deliberately two methods.** This file's own doc block is dropped\n * from `dist`, but every member comment is inlined into **each** consumer entry\n * (`tsup` builds with `splitting: false`), so rationale belongs here, only the\n * contract belongs on the members, and every method no consumer calls is still\n * paid for once per consumer entry.\n *\n * @example\n * ```ts\n * readonly #tabindex = new TabindexLoan();\n *\n * #rescueFocus() {\n * this.#tabindex.lend(this.element);\n * this.element.focus();\n * }\n *\n * disconnect() {\n * this.#tabindex.returnAll();\n * }\n * ```\n */\nexport class TabindexLoan<T extends HTMLElement = HTMLElement> {\n readonly #value: string;\n readonly #lent = new Set<T>();\n /** Returns live loans before Turbo can copy them into its page snapshot. */\n readonly #beforeCache = new BeforeCacheReset(() => this.returnAll());\n\n /**\n * @param value - the `tabindex` to lend. `\"-1\"` (the default) is\n * programmatically focusable but not a Tab stop; `\"0\"` is a real Tab stop,\n * which a scroll region with no focusable content of its own needs.\n */\n constructor(value: string = \"-1\") {\n this.#value = value;\n }\n\n /** Lends `element` the value; no-ops when it already carries a `tabindex`. */\n lend(element: T): void {\n if (element.hasAttribute(\"tabindex\")) return;\n element.setAttribute(\"tabindex\", this.#value);\n this.#lent.add(element);\n // Subscribe only while a real loan exists. Keeping this guarantee here means\n // every consumer is Turbo-safe without another lifecycle hook to remember.\n this.#beforeCache.activate();\n }\n\n /** Takes back every loan whose value is still the one that was lent. */\n returnAll(): void {\n for (const element of this.#lent) {\n if (element.getAttribute(\"tabindex\") === this.#value) element.removeAttribute(\"tabindex\");\n }\n this.#lent.clear();\n this.#beforeCache.deactivate();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord } from \"../utils/arrow_step\";\nimport { AttributeLease } from \"../utils/attribute_lease\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport { isRtl } from \"../utils/logical_scroll\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { RovingTabindex } from \"../utils/roving_tabindex\";\nimport { TabindexLoan } from \"../utils/tabindex_loan\";\n\n/**\n * Headless, accessible rating behavior over an ordinal symbol sequence.\n *\n * Markup contract (identifier: `stimeo--rating`):\n * <div data-controller=\"stimeo--rating\" role=\"radiogroup\" aria-label=\"Rating\"\n * data-stimeo--rating-value-value=\"3\">\n * <span role=\"radio\" aria-checked=\"false\" aria-label=\"1 star\" tabindex=\"-1\"\n * data-stimeo--rating-target=\"symbol\"\n * data-action=\"click->stimeo--rating#select\n * mouseenter->stimeo--rating#preview\n * mouseleave->stimeo--rating#endPreview\n * focus->stimeo--rating#preview\n * blur->stimeo--rating#endPreview\n * keydown->stimeo--rating#onKeydown\">★</span>\n * <!-- later symbols continue the 1..N scale in DOM order -->\n * <input type=\"hidden\" data-stimeo--rating-target=\"field\" />\n * </div>\n *\n * Implements the WAI-ARIA APG **Radio Group** pattern as an ordinal scale. The\n * live DOM order is the sole source of symbol values: the first symbol is 1 and\n * the last is N. Unlike a generic radio group, arrows deliberately clamp rather\n * than wrap because the values have an ordered lower and upper bound.\n *\n * `change` and `reconcile` dispatch `{ value: number }`.\n *\n * @remarks\n * Behavior only — consumers style `[aria-checked]` and `data-rating-hover`. In\n * `readonly` mode the group becomes `role=\"img\"`; the consumer supplies the\n * human-readable accessible name (for example, \"Rated 3 of 5\"). Focus standing on\n * a symbol when that mode begins lands on the root and returns to the Tab stop\n * when it ends, so it is never left on a node outside the accessibility tree.\n *\n * `stimeo--rating:change` is reserved for a user operation that changes the\n * committed value. A DOM or configuration reconciliation that clamps the value\n * emits `stimeo--rating:reconcile` instead. Initial reflection emits neither.\n */\nexport class RatingController extends Controller<HTMLElement> {\n static override targets = [\"symbol\", \"field\"];\n static override values = {\n value: { type: Number, default: 0 },\n clearable: { type: Boolean, default: true },\n readonly: { type: Boolean, default: false },\n };\n static actions = [\"endPreview\", \"onKeydown\", \"preview\", \"select\"] as const;\n static events = [\"change\", \"reconcile\"] as const;\n\n declare readonly symbolTargets: HTMLElement[];\n declare readonly fieldTarget: HTMLInputElement;\n declare readonly hasFieldTarget: boolean;\n declare valueValue: number;\n declare clearableValue: boolean;\n declare readonlyValue: boolean;\n\n readonly #roving = new RovingTabindex(() => this.symbolTargets);\n readonly #rootRole = new AttributeLease<HTMLElement>(\"role\");\n readonly #symbolRole = new AttributeLease<HTMLElement>(\"role\");\n readonly #symbolAriaHidden = new AttributeLease<HTMLElement>(\"aria-hidden\");\n readonly #rootTabindex = new TabindexLoan();\n readonly #repaint = new MicrotaskCoalescer(() => this.#reconcileScale());\n readonly #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());\n #connected = false;\n #rescuedFocus = false;\n\n /** Reflects declarative state without announcing an initial user change. */\n override connect(): void {\n this.#repaint.activate();\n this.#beforeCache.activate();\n this.#apply(this.#normalize(this.valueValue), { focus: false });\n this.#connected = true;\n }\n\n /** Drops a queued reconciliation and hands every borrowed attribute back. */\n override disconnect(): void {\n this.#connected = false;\n this.#repaint.cancel();\n this.#beforeCache.deactivate();\n this.#releaseReadonly();\n }\n\n /** Removes a runtime-added symbol's authored Tab stop before the batch repaint. */\n symbolTargetConnected(symbol: HTMLElement): void {\n if (this.#connected === false) return;\n symbol.tabIndex = -1;\n this.#repaint.schedule();\n }\n\n /** Releases readonly ownership and reconciles the remaining DOM-ordered scale. */\n symbolTargetDisconnected(symbol: HTMLElement): void {\n this.#symbolRole.return(symbol);\n this.#symbolAriaHidden.return(symbol);\n this.#repaint.schedule();\n }\n\n /** Reflects into a hidden field added or replaced after connection. */\n fieldTargetConnected(): void {\n this.#repaint.schedule();\n }\n\n /** Reconciles after a hidden field is removed or replaced. */\n fieldTargetDisconnected(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code or a Turbo morph changes `value`. */\n valueValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code changes whether value 0 is permitted. */\n clearableValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code enters or leaves the readonly snapshot. */\n readonlyValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Selects or clears the clicked symbol. Bound via `data-action` (click). */\n select(event: Event): void {\n if (this.readonlyValue) return;\n const ordinal = this.#symbolOrdinal(event.currentTarget);\n if (ordinal === null) return;\n const current = this.#normalize(this.valueValue);\n this.#commit(this.clearableValue && ordinal === current ? 0 : ordinal, {\n focus: ordinal === current,\n });\n }\n\n /** Previews a fill range on hover or focus without committing it. */\n preview(event: Event): void {\n if (this.readonlyValue) return;\n const ordinal = this.#symbolOrdinal(event.currentTarget);\n if (ordinal !== null) this.#setFillRange(ordinal);\n }\n\n /** Restores the fill range after hover or focus leaves a symbol. */\n endPreview(): void {\n if (this.readonlyValue) return;\n this.#setFillRange(this.#normalize(this.valueValue));\n }\n\n /** Arrow/Home/End/Space/Delete keyboard control, clamped without wrapping. */\n onKeydown(event: KeyboardEvent): void {\n if (event.defaultPrevented || isReservedArrowChord(event) || this.readonlyValue) return;\n\n const current = this.#normalize(this.valueValue);\n let next: number | null = null;\n const rtl = isRtl(this.element);\n\n // Horizontal keys follow writing direction. Vertical keys express value:\n // ArrowUp is always more and ArrowDown is always less.\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n next = current + (event.key === \"ArrowRight\" && rtl ? -1 : 1);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n next = current - (event.key === \"ArrowLeft\" && rtl ? -1 : 1);\n break;\n case \"Home\":\n next = this.#minValue;\n break;\n case \"End\":\n next = this.symbolTargets.length;\n break;\n case \" \":\n case \"Enter\":\n next = this.#symbolOrdinal(event.currentTarget);\n break;\n case \"Delete\":\n case \"Backspace\":\n // A pointer clears by pressing the committed symbol again. This is the\n // keyboard's way to the same state, kept off Space so that a symbol\n // announced as a radio still answers Space the way a radio does.\n if (!this.clearableValue) return;\n next = 0;\n break;\n default:\n return;\n }\n\n if (next === null) return;\n event.preventDefault();\n this.#commit(next, { focus: true });\n }\n\n /**\n * Repaints one settled target/Value mutation batch and reports only a value\n * this controller had to normalize.\n *\n * @stimeoRenderRoot\n */\n #reconcileScale(): void {\n const requested = this.valueValue;\n const value = this.#normalize(requested);\n this.#apply(value, { focus: false });\n if (!Object.is(value, requested)) {\n this.dispatch(\"reconcile\", { detail: { value } });\n }\n }\n\n /** Applies one user operation and emits only when its committed value changes. */\n #commit(raw: number, { focus }: { focus: boolean }): void {\n const previous = this.#normalize(this.valueValue);\n const value = this.#normalize(raw);\n this.#apply(value, { focus });\n if (value !== previous) this.dispatch(\"change\", { detail: { value } });\n }\n\n /** Synchronizes value, ARIA, roving focus, form state, and the visual fill hook. */\n #apply(value: number, { focus }: { focus: boolean }): void {\n if (!Object.is(this.valueValue, value)) this.valueValue = value;\n this.symbolTargets.forEach((symbol, index) => {\n symbol.setAttribute(\"aria-checked\", value > 0 && index + 1 === value ? \"true\" : \"false\");\n });\n\n if (this.readonlyValue) {\n this.#applyReadonly();\n } else {\n const returning = this.#releaseReadonly();\n this.#roving.setActive(value > 0 ? value - 1 : 0, { focus: focus || returning });\n }\n\n if (this.hasFieldTarget) this.fieldTarget.value = String(value);\n this.#setFillRange(value);\n }\n\n /** Marks the first `range` symbols with the consumer-owned fill hook. */\n #setFillRange(range: number): void {\n this.symbolTargets.forEach((symbol, index) => {\n symbol.toggleAttribute(\"data-rating-hover\", range > 0 && index < range);\n });\n }\n\n /**\n * Temporarily turns the radiogroup into a non-interactive image snapshot.\n *\n * Each lease is returned before it is taken again, so a value the consumer\n * wrote while readonly becomes the value the lease restores on release. The\n * return is a no-op on an attribute still holding this controller's own\n * write, which is the ordinary case.\n */\n #applyReadonly(): void {\n this.#rescueFocus();\n this.#rootRole.return(this.element);\n this.#rootRole.write(this.element, \"img\");\n for (const symbol of this.symbolTargets) {\n this.#symbolRole.return(symbol);\n this.#symbolRole.write(symbol, null);\n this.#symbolAriaHidden.return(symbol);\n this.#symbolAriaHidden.write(symbol, \"true\");\n }\n this.#roving.setActive(-1);\n }\n\n /**\n * Hands every readonly borrowing back before Turbo clones the page.\n *\n * The snapshot is taken while the controller is still connected, so an\n * element left as `role=\"img\"` with hidden symbols is what a restored page\n * connects against — and that markup would be read as the authored one,\n * leaving no way back to the radiogroup. Rewinding first keeps the cached\n * copy identical to what the consumer wrote.\n */\n #rewindForCache(): void {\n this.#releaseReadonly();\n const value = this.#normalize(this.valueValue);\n this.#roving.setActive(value > 0 ? value - 1 : 0);\n }\n\n /**\n * Lands focus on the root before the symbols leave the accessibility tree.\n *\n * A symbol holding focus when readonly begins would keep it while losing its\n * role and gaining `aria-hidden`, stranding the user on a node no longer in\n * the tree. The root is the one element that survives the transition named:\n * it carries the consumer's accessible name under `role=\"img\"`.\n */\n #rescueFocus(): void {\n const active = document.activeElement;\n if (!(active instanceof HTMLElement) || active === this.element) return;\n if (!this.element.contains(active)) return;\n this.#rootTabindex.lend(this.element);\n this.element.focus();\n this.#rescuedFocus = true;\n }\n\n /**\n * Restores authored roles and visibility after leaving readonly mode.\n *\n * @returns whether focus is standing on the root because {@link #rescueFocus}\n * put it there, and therefore belongs back on the Tab stop.\n */\n #releaseReadonly(): boolean {\n const returning = this.#rescuedFocus && document.activeElement === this.element;\n this.#rescuedFocus = false;\n this.#rootRole.return(this.element);\n this.#symbolRole.returnAll();\n this.#symbolAriaHidden.returnAll();\n this.#rootTabindex.returnAll();\n return returning;\n }\n\n /** Normalizes a raw value to an integer ordinal in the live DOM range. */\n #normalize(raw: number): number {\n const maximum = this.symbolTargets.length;\n const ordinal = Number.isFinite(raw) ? Math.round(raw) : this.#minValue;\n return Math.min(maximum, Math.max(this.#minValue, ordinal));\n }\n\n /** Lowest selectable value: 0 when clearable, otherwise 1. */\n get #minValue(): number {\n return this.clearableValue ? 0 : 1;\n }\n\n /** Returns a target's 1-based position, or null when the action host is invalid. */\n #symbolOrdinal(target: EventTarget | null): number | null {\n const targets: readonly (EventTarget | null)[] = this.symbolTargets;\n const index = targets.indexOf(target);\n return index < 0 ? null : index + 1;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/attribute_lease.ts","../../src/utils/before_cache_reset.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/roving_tabindex.ts","../../src/utils/tabindex_loan.ts","../../src/controllers/rating_controller.ts"],"names":[],"mappings":"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","file":"rating_controller.js","sourcesContent":["/** 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","/** One temporarily controlled attribute value and the authored value it displaced. */\ninterface AttributeLeaseRecord {\n readonly original: string | null;\n written: string | null;\n}\n\n/**\n * Temporarily controls one attribute across a changing set of elements.\n *\n * The first write remembers the authored value, including the distinction between\n * an absent attribute and an authored empty string. Returning a lease restores that\n * value only while the attribute still matches the controller's last write. If a\n * consumer changed it in the meantime, the consumer owns the new value and teardown\n * leaves it alone.\n *\n * A `null` write deliberately removes the attribute while retaining the lease. This\n * is useful for derived ARIA whose valid absence is itself controller state, such as\n * an unbounded `aria-valuemin` or a blank spinbutton's `aria-valuenow`.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events.\n * A consumer that must not let a derived value become the authored baseline of a\n * cached page returns its leases from its own `turbo:before-cache` rewind, where the\n * matching `disconnect()` also releases the subscription.\n */\nexport class AttributeLease<T extends Element = Element> {\n readonly #attribute: string;\n readonly #records = new Map<T, AttributeLeaseRecord>();\n\n /** @param attribute - The attribute whose temporary values this lease owns. */\n constructor(attribute: string) {\n this.#attribute = attribute;\n }\n\n /** Writes or removes the leased attribute while preserving its authored value. */\n write(element: T, value: string | null): void {\n const existing = this.#records.get(element);\n if (existing) {\n existing.written = value;\n } else {\n this.#records.set(element, {\n original: element.getAttribute(this.#attribute),\n written: value,\n });\n }\n\n this.#reflect(element, value);\n }\n\n /** Returns one lease without overwriting a value subsequently authored by a consumer. */\n return(element: T): void {\n const record = this.#records.get(element);\n if (!record) return;\n this.#records.delete(element);\n const stillOwned = element.getAttribute(this.#attribute) === record.written;\n if (stillOwned) this.#reflect(element, record.original);\n }\n\n /** Reflects only a real value transition, avoiding self-triggered mutation work. */\n #reflect(element: T, value: string | null): void {\n if (element.getAttribute(this.#attribute) === value) return;\n if (value === null) element.removeAttribute(this.#attribute);\n else element.setAttribute(this.#attribute, value);\n }\n\n /** Returns every outstanding lease using the same ownership check as {@link return}. */\n returnAll(): void {\n for (const element of Array.from(this.#records.keys())) this.return(element);\n }\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way.\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/**\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 * 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 { BeforeCacheReset } from \"./before_cache_reset\";\n\n/**\n * Shared bookkeeping for a `tabindex` a controller lends an element temporarily.\n *\n * A controller that must move focus somewhere the author never made focusable\n * (a landmark root, a scroll destination) reaches for the same trick: add a\n * `tabindex` just-in-time and hand it back once it is no longer needed. The\n * borrow is the easy half; the return is what the two conditions below are for.\n *\n * **Returning needs two conditions, not one.** Owning the borrow is not enough:\n * the attribute must also still hold the value this instance wrote. A consumer\n * that changed it afterwards — `tabindex=\"0\"` to make the root its own Tab stop\n * — owns it now, and removing it there silently discards authored markup. The\n * bookkeeping is dropped either way, since the loan is over regardless of who\n * ends up owning the value.\n *\n * **Never borrow over an existing value.** An element that already carries a\n * `tabindex` is the author's to control, so there is nothing to lend and nothing\n * to return.\n *\n * Every live loan also owns a shared `turbo:before-cache` subscription. The loan\n * is returned before Turbo can copy it into a snapshot, so consumers get cache\n * safety without duplicating a lifecycle hook; `returnAll()` removes the\n * subscription again as soon as no loan remains.\n *\n * The registry is keyed by element, so a controller borrowing on a single\n * element (`this.element`) and one borrowing across a changing set of targets\n * use the same API — the single-element case is a set of one. It holds no\n * opinion about *when* to borrow or where focus goes next; that stays in the\n * controller.\n *\n * **The API is deliberately two methods.** This file's own doc block is dropped\n * from `dist`, but every member comment is inlined into **each** consumer entry\n * (`tsup` builds with `splitting: false`), so rationale belongs here, only the\n * contract belongs on the members, and every method no consumer calls is still\n * paid for once per consumer entry.\n *\n * @example\n * ```ts\n * readonly #tabindex = new TabindexLoan();\n *\n * #rescueFocus() {\n * this.#tabindex.lend(this.element);\n * this.element.focus();\n * }\n *\n * disconnect() {\n * this.#tabindex.returnAll();\n * }\n * ```\n */\nexport class TabindexLoan<T extends HTMLElement = HTMLElement> {\n readonly #value: string;\n readonly #lent = new Set<T>();\n /** Returns live loans before Turbo can copy them into its page snapshot. */\n readonly #beforeCache = new BeforeCacheReset(() => this.returnAll());\n\n /**\n * @param value - the `tabindex` to lend. `\"-1\"` (the default) is\n * programmatically focusable but not a Tab stop; `\"0\"` is a real Tab stop,\n * which a scroll region with no focusable content of its own needs.\n */\n constructor(value: string = \"-1\") {\n this.#value = value;\n }\n\n /** Lends `element` the value; no-ops when it already carries a `tabindex`. */\n lend(element: T): void {\n if (element.hasAttribute(\"tabindex\")) return;\n element.setAttribute(\"tabindex\", this.#value);\n this.#lent.add(element);\n // Subscribe only while a real loan exists. Keeping this guarantee here means\n // every consumer is Turbo-safe without another lifecycle hook to remember.\n this.#beforeCache.activate();\n }\n\n /** Takes back every loan whose value is still the one that was lent. */\n returnAll(): void {\n for (const element of this.#lent) {\n if (element.getAttribute(\"tabindex\") === this.#value) element.removeAttribute(\"tabindex\");\n }\n this.#lent.clear();\n this.#beforeCache.deactivate();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord } from \"../utils/arrow_step\";\nimport { AttributeLease } from \"../utils/attribute_lease\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport { isRtl } from \"../utils/logical_scroll\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { RovingTabindex } from \"../utils/roving_tabindex\";\nimport { TabindexLoan } from \"../utils/tabindex_loan\";\n\n/**\n * Headless, accessible rating behavior over an ordinal symbol sequence.\n *\n * Markup contract (identifier: `stimeo--rating`):\n * <div data-controller=\"stimeo--rating\" role=\"radiogroup\" aria-label=\"Rating\"\n * data-stimeo--rating-value-value=\"3\">\n * <span role=\"radio\" aria-checked=\"false\" aria-label=\"1 star\" tabindex=\"-1\"\n * data-stimeo--rating-target=\"symbol\"\n * data-action=\"click->stimeo--rating#select\n * mouseenter->stimeo--rating#preview\n * mouseleave->stimeo--rating#endPreview\n * focus->stimeo--rating#preview\n * blur->stimeo--rating#endPreview\n * keydown->stimeo--rating#onKeydown\">★</span>\n * <!-- later symbols continue the 1..N scale in DOM order -->\n * <input type=\"hidden\" data-stimeo--rating-target=\"field\" />\n * </div>\n *\n * Implements the WAI-ARIA APG **Radio Group** pattern as an ordinal scale. The\n * live DOM order is the sole source of symbol values: the first symbol is 1 and\n * the last is N. Unlike a generic radio group, arrows deliberately clamp rather\n * than wrap because the values have an ordered lower and upper bound.\n *\n * `change` and `reconcile` dispatch `{ value: number }`.\n *\n * @remarks\n * Behavior only — consumers style `[aria-checked]` and `data-rating-hover`. In\n * `readonly` mode the group becomes `role=\"img\"`; the consumer supplies the\n * human-readable accessible name (for example, \"Rated 3 of 5\"). Focus standing on\n * a symbol when that mode begins lands on the root and returns to the Tab stop\n * when it ends, so it is never left on a node outside the accessibility tree.\n *\n * `stimeo--rating:change` is reserved for a user operation that changes the\n * committed value. A DOM or configuration reconciliation that clamps the value\n * emits `stimeo--rating:reconcile` instead. Initial reflection emits neither.\n */\nexport class RatingController extends Controller<HTMLElement> {\n static override targets = [\"symbol\", \"field\"];\n static override values = {\n value: { type: Number, default: 0 },\n clearable: { type: Boolean, default: true },\n readonly: { type: Boolean, default: false },\n };\n static actions = [\"endPreview\", \"onKeydown\", \"preview\", \"select\"] as const;\n static events = [\"change\", \"reconcile\"] as const;\n\n declare readonly symbolTargets: HTMLElement[];\n declare readonly fieldTarget: HTMLInputElement;\n declare readonly hasFieldTarget: boolean;\n declare valueValue: number;\n declare clearableValue: boolean;\n declare readonlyValue: boolean;\n\n readonly #roving = new RovingTabindex(() => this.symbolTargets);\n readonly #rootRole = new AttributeLease<HTMLElement>(\"role\");\n readonly #symbolRole = new AttributeLease<HTMLElement>(\"role\");\n readonly #symbolAriaHidden = new AttributeLease<HTMLElement>(\"aria-hidden\");\n readonly #rootTabindex = new TabindexLoan();\n readonly #repaint = new MicrotaskCoalescer(() => this.#reconcileScale());\n readonly #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());\n #connected = false;\n #rescuedFocus = false;\n\n /** Reflects declarative state without announcing an initial user change. */\n override connect(): void {\n this.#repaint.activate();\n this.#beforeCache.activate();\n this.#apply(this.#normalize(this.valueValue), { focus: false });\n this.#connected = true;\n }\n\n /** Drops a queued reconciliation and hands every borrowed attribute back. */\n override disconnect(): void {\n this.#connected = false;\n this.#repaint.cancel();\n this.#beforeCache.deactivate();\n this.#releaseReadonly();\n }\n\n /** Removes a runtime-added symbol's authored Tab stop before the batch repaint. */\n symbolTargetConnected(symbol: HTMLElement): void {\n if (this.#connected === false) return;\n symbol.tabIndex = -1;\n this.#repaint.schedule();\n }\n\n /** Releases readonly ownership and reconciles the remaining DOM-ordered scale. */\n symbolTargetDisconnected(symbol: HTMLElement): void {\n this.#symbolRole.return(symbol);\n this.#symbolAriaHidden.return(symbol);\n this.#repaint.schedule();\n }\n\n /** Reflects into a hidden field added or replaced after connection. */\n fieldTargetConnected(): void {\n this.#repaint.schedule();\n }\n\n /** Reconciles after a hidden field is removed or replaced. */\n fieldTargetDisconnected(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code or a Turbo morph changes `value`. */\n valueValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code changes whether value 0 is permitted. */\n clearableValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code enters or leaves the readonly snapshot. */\n readonlyValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Selects or clears the clicked symbol. Bound via `data-action` (click). */\n select(event: Event): void {\n if (this.readonlyValue) return;\n const ordinal = this.#symbolOrdinal(event.currentTarget);\n if (ordinal === null) return;\n const current = this.#normalize(this.valueValue);\n this.#commit(this.clearableValue && ordinal === current ? 0 : ordinal, {\n focus: ordinal === current,\n });\n }\n\n /** Previews a fill range on hover or focus without committing it. */\n preview(event: Event): void {\n if (this.readonlyValue) return;\n const ordinal = this.#symbolOrdinal(event.currentTarget);\n if (ordinal !== null) this.#setFillRange(ordinal);\n }\n\n /** Restores the fill range after hover or focus leaves a symbol. */\n endPreview(): void {\n if (this.readonlyValue) return;\n this.#setFillRange(this.#normalize(this.valueValue));\n }\n\n /** Arrow/Home/End/Space/Delete keyboard control, clamped without wrapping. */\n onKeydown(event: KeyboardEvent): void {\n if (event.defaultPrevented || isReservedArrowChord(event) || this.readonlyValue) return;\n\n const current = this.#normalize(this.valueValue);\n let next: number | null = null;\n const rtl = isRtl(this.element);\n\n // Horizontal keys follow writing direction. Vertical keys express value:\n // ArrowUp is always more and ArrowDown is always less.\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n next = current + (event.key === \"ArrowRight\" && rtl ? -1 : 1);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n next = current - (event.key === \"ArrowLeft\" && rtl ? -1 : 1);\n break;\n case \"Home\":\n next = this.#minValue;\n break;\n case \"End\":\n next = this.symbolTargets.length;\n break;\n case \" \":\n case \"Enter\":\n next = this.#symbolOrdinal(event.currentTarget);\n break;\n case \"Delete\":\n case \"Backspace\":\n // A pointer clears by pressing the committed symbol again. This is the\n // keyboard's way to the same state, kept off Space so that a symbol\n // announced as a radio still answers Space the way a radio does.\n if (!this.clearableValue) return;\n next = 0;\n break;\n default:\n return;\n }\n\n if (next === null) return;\n event.preventDefault();\n this.#commit(next, { focus: true });\n }\n\n /**\n * Repaints one settled target/Value mutation batch and reports only a value\n * this controller had to normalize.\n *\n * @stimeoRenderRoot\n */\n #reconcileScale(): void {\n const requested = this.valueValue;\n const value = this.#normalize(requested);\n this.#apply(value, { focus: false });\n if (!Object.is(value, requested)) {\n this.dispatch(\"reconcile\", { detail: { value } });\n }\n }\n\n /** Applies one user operation and emits only when its committed value changes. */\n #commit(raw: number, { focus }: { focus: boolean }): void {\n const previous = this.#normalize(this.valueValue);\n const value = this.#normalize(raw);\n this.#apply(value, { focus });\n if (value !== previous) this.dispatch(\"change\", { detail: { value } });\n }\n\n /** Synchronizes value, ARIA, roving focus, form state, and the visual fill hook. */\n #apply(value: number, { focus }: { focus: boolean }): void {\n if (!Object.is(this.valueValue, value)) this.valueValue = value;\n this.symbolTargets.forEach((symbol, index) => {\n symbol.setAttribute(\"aria-checked\", value > 0 && index + 1 === value ? \"true\" : \"false\");\n });\n\n if (this.readonlyValue) {\n this.#applyReadonly();\n } else {\n const returning = this.#releaseReadonly();\n this.#roving.setActive(value > 0 ? value - 1 : 0, { focus: focus || returning });\n }\n\n if (this.hasFieldTarget) this.fieldTarget.value = String(value);\n this.#setFillRange(value);\n }\n\n /** Marks the first `range` symbols with the consumer-owned fill hook. */\n #setFillRange(range: number): void {\n this.symbolTargets.forEach((symbol, index) => {\n symbol.toggleAttribute(\"data-rating-hover\", range > 0 && index < range);\n });\n }\n\n /**\n * Temporarily turns the radiogroup into a non-interactive image snapshot.\n *\n * Each lease is returned before it is taken again, so a value the consumer\n * wrote while readonly becomes the value the lease restores on release. The\n * return is a no-op on an attribute still holding this controller's own\n * write, which is the ordinary case.\n */\n #applyReadonly(): void {\n this.#rescueFocus();\n this.#rootRole.return(this.element);\n this.#rootRole.write(this.element, \"img\");\n for (const symbol of this.symbolTargets) {\n this.#symbolRole.return(symbol);\n this.#symbolRole.write(symbol, null);\n this.#symbolAriaHidden.return(symbol);\n this.#symbolAriaHidden.write(symbol, \"true\");\n }\n this.#roving.setActive(-1);\n }\n\n /**\n * Hands every readonly borrowing back before Turbo clones the page.\n *\n * The snapshot is taken while the controller is still connected, so an\n * element left as `role=\"img\"` with hidden symbols is what a restored page\n * connects against — and that markup would be read as the authored one,\n * leaving no way back to the radiogroup. Rewinding first keeps the cached\n * copy identical to what the consumer wrote.\n */\n #rewindForCache(): void {\n this.#releaseReadonly();\n const value = this.#normalize(this.valueValue);\n this.#roving.setActive(value > 0 ? value - 1 : 0);\n }\n\n /**\n * Lands focus on the root before the symbols leave the accessibility tree.\n *\n * A symbol holding focus when readonly begins would keep it while losing its\n * role and gaining `aria-hidden`, stranding the user on a node no longer in\n * the tree. The root is the one element that survives the transition named:\n * it carries the consumer's accessible name under `role=\"img\"`.\n */\n #rescueFocus(): void {\n const active = document.activeElement;\n if (!(active instanceof HTMLElement) || active === this.element) return;\n if (!this.element.contains(active)) return;\n this.#rootTabindex.lend(this.element);\n this.element.focus();\n this.#rescuedFocus = true;\n }\n\n /**\n * Restores authored roles and visibility after leaving readonly mode.\n *\n * @returns whether focus is standing on the root because {@link #rescueFocus}\n * put it there, and therefore belongs back on the Tab stop.\n */\n #releaseReadonly(): boolean {\n const returning = this.#rescuedFocus && document.activeElement === this.element;\n this.#rescuedFocus = false;\n this.#rootRole.return(this.element);\n this.#symbolRole.returnAll();\n this.#symbolAriaHidden.returnAll();\n this.#rootTabindex.returnAll();\n return returning;\n }\n\n /** Normalizes a raw value to an integer ordinal in the live DOM range. */\n #normalize(raw: number): number {\n const maximum = this.symbolTargets.length;\n const ordinal = Number.isFinite(raw) ? Math.round(raw) : this.#minValue;\n return Math.min(maximum, Math.max(this.#minValue, ordinal));\n }\n\n /** Lowest selectable value: 0 when clearable, otherwise 1. */\n get #minValue(): number {\n return this.clearableValue ? 0 : 1;\n }\n\n /** Returns a target's 1-based position, or null when the action host is invalid. */\n #symbolOrdinal(target: EventTarget | null): number | null {\n const targets: readonly (EventTarget | null)[] = this.symbolTargets;\n const index = targets.indexOf(target);\n return index < 0 ? null : index + 1;\n }\n}\n"]}