stimeo-ui 0.13.0 → 0.14.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 (103) hide show
  1. package/CHANGELOG.md +39 -5
  2. package/dist/cable/index.d.ts +1 -1
  3. package/dist/cable/index.js.map +1 -1
  4. package/dist/controllers/accordion_controller.d.ts +1 -1
  5. package/dist/controllers/accordion_controller.js.map +1 -1
  6. package/dist/controllers/calendar_controller.d.ts +2 -2
  7. package/dist/controllers/calendar_controller.js +31 -7
  8. package/dist/controllers/calendar_controller.js.map +1 -1
  9. package/dist/controllers/carousel_controller.js +8 -6
  10. package/dist/controllers/carousel_controller.js.map +1 -1
  11. package/dist/controllers/clipboard_controller.d.ts +1 -1
  12. package/dist/controllers/clipboard_controller.js.map +1 -1
  13. package/dist/controllers/collapsible_controller.d.ts +1 -1
  14. package/dist/controllers/collapsible_controller.js.map +1 -1
  15. package/dist/controllers/conditional_fields_controller.js +7 -1
  16. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  17. package/dist/controllers/currency_input_controller.js +68 -23
  18. package/dist/controllers/currency_input_controller.js.map +1 -1
  19. package/dist/controllers/date_range_picker_controller.d.ts +3 -3
  20. package/dist/controllers/date_range_picker_controller.js +31 -7
  21. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  22. package/dist/controllers/dialog_controller.d.ts +2 -2
  23. package/dist/controllers/dialog_controller.js.map +1 -1
  24. package/dist/controllers/direct_upload_controller.js +21 -10
  25. package/dist/controllers/direct_upload_controller.js.map +1 -1
  26. package/dist/controllers/dismissible_controller.d.ts +1 -1
  27. package/dist/controllers/dismissible_controller.js.map +1 -1
  28. package/dist/controllers/dropdown_controller.d.ts +1 -1
  29. package/dist/controllers/dropdown_controller.js.map +1 -1
  30. package/dist/controllers/form_field_controller.js +7 -1
  31. package/dist/controllers/form_field_controller.js.map +1 -1
  32. package/dist/controllers/input_mask_controller.d.ts +3 -2
  33. package/dist/controllers/input_mask_controller.js +33 -12
  34. package/dist/controllers/input_mask_controller.js.map +1 -1
  35. package/dist/controllers/intersection_controller.js +10 -5
  36. package/dist/controllers/intersection_controller.js.map +1 -1
  37. package/dist/controllers/lazy_frame_controller.js +10 -5
  38. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  39. package/dist/controllers/local_time_controller.d.ts +3 -2
  40. package/dist/controllers/local_time_controller.js +34 -7
  41. package/dist/controllers/local_time_controller.js.map +1 -1
  42. package/dist/controllers/masonry_controller.d.ts +1 -1
  43. package/dist/controllers/masonry_controller.js +1 -1
  44. package/dist/controllers/masonry_controller.js.map +1 -1
  45. package/dist/controllers/menu_controller.js +10 -2
  46. package/dist/controllers/menu_controller.js.map +1 -1
  47. package/dist/controllers/menubar_controller.js +10 -2
  48. package/dist/controllers/menubar_controller.js.map +1 -1
  49. package/dist/controllers/navigation_menu_controller.js +8 -2
  50. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  51. package/dist/controllers/otp_controller.js +23 -10
  52. package/dist/controllers/otp_controller.js.map +1 -1
  53. package/dist/controllers/overflow_menu_controller.js +10 -1
  54. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  55. package/dist/controllers/password_reveal_controller.d.ts +1 -1
  56. package/dist/controllers/password_reveal_controller.js.map +1 -1
  57. package/dist/controllers/pointer_drag_controller.js +10 -3
  58. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  59. package/dist/controllers/portal_controller.js +21 -10
  60. package/dist/controllers/portal_controller.js.map +1 -1
  61. package/dist/controllers/radio_group_controller.js +11 -3
  62. package/dist/controllers/radio_group_controller.js.map +1 -1
  63. package/dist/controllers/read_more_controller.d.ts +1 -1
  64. package/dist/controllers/read_more_controller.js.map +1 -1
  65. package/dist/controllers/relative_time_controller.js +31 -5
  66. package/dist/controllers/relative_time_controller.js.map +1 -1
  67. package/dist/controllers/reset_before_cache_controller.js +23 -10
  68. package/dist/controllers/reset_before_cache_controller.js.map +1 -1
  69. package/dist/controllers/resizable_controller.js +7 -2
  70. package/dist/controllers/resizable_controller.js.map +1 -1
  71. package/dist/controllers/roving_controller.js +7 -3
  72. package/dist/controllers/roving_controller.js.map +1 -1
  73. package/dist/controllers/scroll_visibility_controller.d.ts +1 -1
  74. package/dist/controllers/scroll_visibility_controller.js +22 -13
  75. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  76. package/dist/controllers/scrollspy_controller.d.ts +1 -1
  77. package/dist/controllers/scrollspy_controller.js +11 -6
  78. package/dist/controllers/scrollspy_controller.js.map +1 -1
  79. package/dist/controllers/smart_sticky_header_controller.js +23 -12
  80. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  81. package/dist/controllers/sticky_observer_controller.js +10 -5
  82. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  83. package/dist/controllers/switch_controller.d.ts +1 -1
  84. package/dist/controllers/switch_controller.js.map +1 -1
  85. package/dist/controllers/tabs_controller.d.ts +1 -1
  86. package/dist/controllers/tabs_controller.js.map +1 -1
  87. package/dist/controllers/theme_controller.d.ts +2 -3
  88. package/dist/controllers/theme_controller.js +23 -13
  89. package/dist/controllers/theme_controller.js.map +1 -1
  90. package/dist/controllers/toggle_group_controller.js +11 -3
  91. package/dist/controllers/toggle_group_controller.js.map +1 -1
  92. package/dist/controllers/toolbar_controller.js +7 -3
  93. package/dist/controllers/toolbar_controller.js.map +1 -1
  94. package/dist/index.js +165 -171
  95. package/dist/index.js.map +1 -1
  96. package/dist/inspector/cli.d.ts +38 -1
  97. package/dist/inspector/cli.js +80 -7
  98. package/dist/inspector/cli.js.map +1 -1
  99. package/dist/inspector/cli_bin.js +103 -7
  100. package/dist/inspector/cli_bin.js.map +1 -1
  101. package/dist/inspector/examples.json +5 -5
  102. package/dist/inspector/manifest.json +127 -1
  103. package/package.json +9 -11
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/safe_timeout.ts","../../src/utils/transition_completion.ts","../../src/controllers/collapsible_controller.ts"],"names":[],"mappings":"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","file":"collapsible_controller.js","sourcesContent":["/**\n * Self-cleaning timer registries shared by Stimeo controllers.\n *\n * Stimulus controllers frequently schedule `setTimeout` / `setInterval` work\n * (auto-dismiss, debouncing, polling). When the element leaves the DOM — a\n * Turbo Drive navigation, a Turbo Stream replacement, or any `disconnect()` —\n * orphaned timers keep firing against a detached controller, leaking memory and\n * mutating stale state. {@link SafeTimeout} and {@link SafeInterval} track every\n * timer they create so a single {@link TimerRegistry.clearAll | clearAll()} call\n * in `disconnect()` tears them all down.\n *\n * These are intentionally low-level primitives: they own *registration and\n * cleanup only*. Higher-level policy (pause/resume, remaining-time accounting)\n * stays in the individual controllers so per-widget semantics are not flattened\n * into a lowest-common-denominator helper.\n */\n\n/**\n * Largest delay a timer can hold: the platform stores it in a 32-bit signed\n * integer, and anything larger overflows to `1`, so a delay meant to be far in\n * the future fires almost immediately. A declared delay above this bound names\n * no delay at all, and a controller reading one falls back to its default.\n */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/**\n * Shared registry bookkeeping for the timeout/interval variants.\n *\n * Subclasses provide the scheduling primitive ({@link schedule}) and its matching\n * canceller ({@link cancel}); this base owns the set of live ids plus the\n * per-id and bulk teardown shared by both.\n */\nabstract class TimerRegistry {\n /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */\n protected readonly ids = new Set<number>();\n\n /** Schedules the underlying platform timer and returns its id. */\n protected abstract schedule(callback: () => void, delay: number): number;\n\n /** Cancels the underlying platform timer for `id`. */\n protected abstract cancel(id: number): void;\n\n /**\n * Cancels a single tracked timer.\n *\n * No-ops if the id is unknown (already cleared, fired, or never owned by this\n * registry), so callers can clear defensively without guarding.\n */\n clear(id: number): void {\n if (this.ids.delete(id)) {\n this.cancel(id);\n }\n }\n\n /**\n * Cancels every tracked timer. Call this from a controller's `disconnect()`\n * to guarantee no timer outlives the element.\n */\n clearAll(): void {\n for (const id of this.ids) {\n this.cancel(id);\n }\n this.ids.clear();\n }\n\n /** Number of timers currently tracked (pending). */\n get size(): number {\n return this.ids.size;\n }\n}\n\n/**\n * `setTimeout` wrapper that auto-forgets each timer once it fires and supports\n * bulk teardown on disconnect.\n *\n * @example\n * ```ts\n * #timers = new SafeTimeout();\n *\n * connect() {\n * this.#timers.set(() => this.dismiss(), 5000);\n * }\n *\n * disconnect() {\n * this.#timers.clearAll();\n * }\n * ```\n */\nexport class SafeTimeout extends TimerRegistry {\n /**\n * Schedules `callback` after `delay` ms and returns the timer id.\n *\n * The id is removed from the registry automatically when the timeout fires,\n * so {@link TimerRegistry.size | size} reflects only still-pending timers.\n */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(() => {\n this.ids.delete(id);\n callback();\n }, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setTimeout(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearTimeout(id);\n }\n}\n\n/**\n * `setInterval` wrapper that tracks every interval for bulk teardown on\n * disconnect. Unlike {@link SafeTimeout}, intervals are retained until they are\n * explicitly cleared because they fire repeatedly.\n *\n * @example\n * ```ts\n * #intervals = new SafeInterval();\n *\n * connect() {\n * this.#intervals.set(() => this.tick(), 1000);\n * }\n *\n * disconnect() {\n * this.#intervals.clearAll();\n * }\n * ```\n */\nexport class SafeInterval extends TimerRegistry {\n /** Schedules a repeating `callback` every `delay` ms and returns the timer id. */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(callback, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setInterval(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearInterval(id);\n }\n}\n","import { SafeTimeout } from \"./safe_timeout\";\n\n/** Computed transition fields needed to determine when an element has settled. */\nexport type TransitionStyle = Pick<\n CSSStyleDeclaration,\n \"transitionProperty\" | \"transitionDuration\" | \"transitionDelay\"\n>;\n\n/** Parsed transition property paired with its effective duration and delay. */\ninterface TransitionTiming {\n property: string;\n totalMs: number;\n}\n\n/** Parses a CSS `<time>` into milliseconds, returning `0` for malformed values. */\nfunction timeMs(value: string): number {\n const trimmed = value.trim();\n const amount = Number.parseFloat(trimmed);\n if (!Number.isFinite(amount)) return 0;\n if (trimmed.endsWith(\"ms\")) return amount;\n if (trimmed.endsWith(\"s\")) return amount * 1000;\n return 0;\n}\n\n/** Splits a computed comma-separated CSS list into normalized, non-empty items. */\nfunction cssList(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * Pairs transition properties, durations, and delays using CSS list repetition.\n *\n * The `transition-property` list determines the number of transitions. Shorter\n * duration/delay lists repeat, while extra values are ignored. A negative delay\n * shortens the remaining wall-clock time, and a non-positive total is settled.\n */\nfunction transitionTimings(style: TransitionStyle): TransitionTiming[] {\n const properties = cssList(style.transitionProperty);\n const durations = cssList(style.transitionDuration).map(timeMs);\n const delays = cssList(style.transitionDelay).map(timeMs);\n const effectiveProperties =\n properties.length > 0\n ? properties\n : Array.from({ length: Math.max(durations.length, delays.length, 1) }, () => \"all\");\n const effectiveDurations = durations.length > 0 ? durations : [0];\n const effectiveDelays = delays.length > 0 ? delays : [0];\n\n return effectiveProperties\n .filter((property) => property !== \"none\")\n .map((property, index) => ({\n property,\n totalMs: Math.max(\n 0,\n (effectiveDurations[index % effectiveDurations.length] ?? 0) +\n (effectiveDelays[index % effectiveDelays.length] ?? 0),\n ),\n }));\n}\n\n/** Maximum total over already-parsed timings (0 when the list is empty). */\nfunction maxTotalMs(timings: TransitionTiming[]): number {\n return timings.reduce((max, { totalMs }) => Math.max(max, totalMs), 0);\n}\n\n/** Maximum effective transition duration plus delay, in milliseconds. */\nexport function maxTransitionTotalMs(style: TransitionStyle): number {\n return maxTotalMs(transitionTimings(style));\n}\n\n/** Optional tuning for a single {@link TransitionCompletion.wait} call. */\nexport interface TransitionWaitOptions {\n /**\n * Positive wall-clock override (ms) for the bounded fallback, replacing the\n * auto-computed `max + 50ms` timer verbatim. It also keeps the wait armed for\n * a computed 0ms transition (no synchronous completion): the consumer asserts\n * a transition budget that computed styles cannot see. Non-positive and\n * non-finite (`NaN` / `Infinity`) values are ignored.\n */\n timeoutMs?: number;\n}\n\n/**\n * Owns one cancellable wait for an element's CSS transitions to settle.\n *\n * When available, active CSS transitions provide their expanded property names.\n * Tracking those names lets shorthand declarations settle from their longhand\n * terminal events. A terminal event from an interrupted phase is ignored while a\n * replacement transition for the same property is still active. Because that set\n * is sampled when the wait is armed, a property whose transition only starts a\n * frame later would otherwise be settled over; the still-running set is therefore\n * re-read before completing and adopted when it is not yet empty. Without Web\n * Animations data, explicit transition properties retain the declared-property\n * behavior and the ambiguous `transition-property: all` form waits until the\n * computed maximum wall-clock time. A `max + 50ms` timeout is always armed\n * because browsers emit no terminal event when a property never transitions, an\n * ancestor disappears, or rendering is otherwise interrupted; a consumer with\n * better knowledge can replace that fallback via\n * {@link TransitionWaitOptions.timeoutMs}.\n */\nexport class TransitionCompletion {\n readonly #timers = new SafeTimeout();\n #element: HTMLElement | null = null;\n #complete: (() => void) | null = null;\n #pendingProperties: Set<string> | null = null;\n #deadline = 0;\n\n /**\n * Replaces any prior wait and invokes `complete` synchronously for a 0ms\n * transition (including when `getComputedStyle` is unavailable).\n *\n * With a positive `options.timeoutMs` the synchronous fast-path is skipped and\n * the override replaces the auto-computed fallback (see {@link TransitionWaitOptions}).\n */\n wait(element: HTMLElement, complete: () => void, options: TransitionWaitOptions = {}): void {\n this.cancel();\n\n const requested = options.timeoutMs ?? 0;\n const override = Number.isFinite(requested) && requested > 0 ? requested : 0;\n // A non-browser / partial-DOM environment cannot report a computable\n // transition, which is indistinguishable from a 0ms one.\n const timings =\n typeof window.getComputedStyle === \"function\"\n ? transitionTimings(window.getComputedStyle(element))\n : [];\n const maximum = maxTotalMs(timings);\n if (maximum <= 0 && override <= 0) {\n complete();\n return;\n }\n\n this.#element = element;\n this.#complete = complete;\n this.#deadline = Date.now() + maximum;\n const activeProperties = this.#activeTransitionProperties(element);\n this.#pendingProperties =\n activeProperties.size > 0 ? activeProperties : this.#explicitPendingProperties(timings);\n element.addEventListener(\"transitionend\", this.#onTerminal);\n element.addEventListener(\"transitioncancel\", this.#onTerminal);\n this.#timers.set(() => this.#finish(), override > 0 ? override : maximum + 50);\n }\n\n /** Cancels the pending wait without invoking its completion callback. */\n cancel(): void {\n this.#complete = null;\n this.#teardown();\n }\n\n /**\n * Handles terminal events from the observed element only.\n *\n * For explicit property lists, every declared positive-time property must\n * settle. For `all`, no reliable property set exists, so an event can finish\n * only after the computed maximum time; the safety timeout owns the usual path.\n */\n readonly #onTerminal = (event: Event): void => {\n if (event.target !== this.#element) return;\n const transitionEvent = event as TransitionEvent;\n // A pseudo-element's transition is reported with its originating element\n // as `target`; it must not settle the element's own transition.\n if (transitionEvent.pseudoElement) return;\n\n if (this.#pendingProperties) {\n const propertyName = transitionEvent.propertyName;\n const active = this.#activeTransitionProperties(this.#element);\n // An interrupted transition queues its cancel event before the replacement\n // phase starts, but dispatch can happen after the new wait is armed. The\n // replacement is then the active transition for this property, so the stale\n // terminal event must not settle the new phase.\n if (active.has(propertyName)) return;\n if (!this.#pendingProperties.delete(propertyName)) return;\n if (this.#pendingProperties.size > 0) return;\n // The tracked set is an arm-time snapshot, so a transition the phase starts\n // one frame later is absent from it. Re-reading the still-running set before\n // settling adopts those stragglers instead of completing over them; the\n // fallback timer stays armed, so this cannot extend the wait unboundedly.\n if (active.size > 0) {\n this.#pendingProperties = active;\n return;\n }\n this.#finish();\n return;\n }\n\n if (Date.now() >= this.#deadline) this.#finish();\n };\n\n /**\n * Returns active CSS transition properties expanded to the names reported by\n * terminal events. CSS animations and pseudo-element effects are excluded.\n */\n #activeTransitionProperties(element: HTMLElement | null): Set<string> {\n if (!element || typeof element.getAnimations !== \"function\") return new Set();\n\n try {\n const properties = element.getAnimations().flatMap((animation) => {\n if (animation.playState === \"idle\" || animation.playState === \"finished\") return [];\n const effect = animation.effect as KeyframeEffect | null;\n // A pseudo-element effect names the originating element as its target, so\n // `target` alone cannot separate it. Its terminal events are ignored, so\n // tracking its properties would only strand the wait on the fallback.\n if (effect?.pseudoElement) return [];\n const target = effect?.target;\n if (target && target !== element) return [];\n const property = (animation as Partial<CSSTransition>).transitionProperty;\n return typeof property === \"string\" && property.length > 0 ? [property] : [];\n });\n return new Set(properties);\n } catch {\n // Partial DOM implementations can expose getAnimations without supporting\n // it. The declared-property tracker and bounded timer remain safe fallbacks.\n return new Set();\n }\n }\n\n /** Returns explicit positive-time properties, or `null` for the ambiguous `all`. */\n #explicitPendingProperties(timings: TransitionTiming[]): Set<string> | null {\n if (timings.some(({ property }) => property === \"all\")) return null;\n const pending = new Set(\n timings.filter(({ totalMs }) => totalMs > 0).map(({ property }) => property),\n );\n // An empty set is only reachable through a timeout override (a 0ms transition\n // otherwise completes synchronously). With nothing to track, fall back to the\n // deadline rule so any terminal event can settle the wait, exactly like `all`.\n return pending.size > 0 ? pending : null;\n }\n\n /** Completes exactly once, releasing listeners and the fallback before the callback. */\n #finish(): void {\n const complete = this.#complete;\n if (!complete) return;\n this.#complete = null;\n this.#teardown();\n complete();\n }\n\n /** Releases the exact element listeners and timer owned by the current wait. */\n #teardown(): void {\n this.#timers.clearAll();\n this.#element?.removeEventListener(\"transitionend\", this.#onTerminal);\n this.#element?.removeEventListener(\"transitioncancel\", this.#onTerminal);\n this.#element = null;\n this.#pendingProperties = null;\n this.#deadline = 0;\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { TransitionCompletion } from \"../utils/transition_completion\";\n\n/**\n * Headless, accessible single-disclosure (collapsible) behavior.\n *\n * Markup contract (identifier: `stimeo--collapsible`):\n * <div data-controller=\"stimeo--collapsible\">\n * <button data-stimeo--collapsible-target=\"trigger\"\n * data-action=\"stimeo--collapsible#toggle\"\n * aria-expanded=\"false\" aria-controls=\"more\">Show details</button>\n * <div id=\"more\" data-stimeo--collapsible-target=\"content\"\n * data-state=\"closed\" hidden>…</div>\n * </div>\n *\n * Implements the WAI-ARIA APG **Disclosure** pattern for a single inline region.\n * Unlike {@link AccordionController} it manages exactly one trigger/content pair\n * with no sibling coordination, and unlike a dropdown the content expands in\n * flow and never closes on an outside click.\n *\n * @remarks\n * Behavior only — the consumer owns the height transition and all decoration.\n * The controller keeps the open lifecycle ordered so `hidden` (effectively\n * `display:none`) never blocks measurement or the transition:\n * - **Open**: drop `hidden` → measure the natural height into\n * `--stimeo--collapsible-content-height` → set `data-state=\"open\"`.\n * - **Close**: set `data-state=\"closed\"` (CSS shrinks the height) → re-apply\n * `hidden` once the transition settles. With no transition (or reduced motion,\n * which the consumer's CSS expresses as a zero duration) it is applied\n * immediately; an owned fallback covers missing terminal events.\n */\nexport class CollapsibleController extends Controller<HTMLElement> {\n static override targets = [\"trigger\", \"content\"];\n static override values = {\n open: { type: Boolean, default: false },\n };\n static actions = [\"toggle\"] as const;\n\n declare readonly triggerTarget: HTMLElement;\n declare readonly contentTarget: HTMLElement;\n declare readonly hasTriggerTarget: boolean;\n declare readonly hasContentTarget: boolean;\n\n declare openValue: boolean;\n\n /** Owns the cancellable close-transition wait and its bounded fallback. */\n readonly #transition = new TransitionCompletion();\n /** Distinguishes dynamic target churn from the callbacks that precede `connect()`. */\n #connected = false;\n\n /**\n * Establishes the initial open/closed state without waiting for a close transition.\n *\n * The DOM is the source of truth on reconnect (Turbo cache restore / morph): an\n * **explicit** state attribute — `aria-expanded=\"true\"`/`\"false\"` (or, with no\n * trigger, `data-state=\"open\"`/`\"closed\"`) — is honored verbatim so a region the\n * user opened *or* closed survives a back-navigation, even when the declarative\n * `open` Value disagrees. An already-open region remains open without a\n * close/reopen cycle. The Value only seeds a genuinely fresh render where no\n * state attribute is present yet; any opening animation in that case belongs to\n * the consumer's CSS.\n */\n override connect(): void {\n this.#connected = true;\n this.#apply(this.#initialOpen(), false);\n }\n\n /** Resolves the connect-time state: explicit DOM state wins, else the `open` Value. */\n #initialOpen(): boolean {\n if (this.hasTriggerTarget) {\n const expanded = this.triggerTarget.getAttribute(\"aria-expanded\");\n if (expanded === \"true\") return true;\n if (expanded === \"false\") return false;\n } else if (this.hasContentTarget) {\n const state = this.contentTarget.getAttribute(\"data-state\");\n if (state === \"open\") return true;\n if (state === \"closed\") return false;\n }\n return this.openValue;\n }\n\n override disconnect(): void {\n this.#connected = false;\n this.#transition.cancel();\n }\n\n /** Reconciles a replacement trigger target with the content's live state. */\n triggerTargetConnected(trigger: HTMLElement): void {\n if (!this.#connected || !this.hasContentTarget) return;\n trigger.setAttribute(\n \"aria-expanded\",\n this.contentTarget.getAttribute(\"data-state\") === \"open\" ? \"true\" : \"false\",\n );\n }\n\n /** Reconciles a replacement content target with the disclosure's live state. */\n contentTargetConnected(content: HTMLElement): void {\n if (!this.#connected) return;\n this.#transition.cancel();\n const open = this.hasTriggerTarget\n ? this.triggerTarget.getAttribute(\"aria-expanded\") === \"true\"\n : content.getAttribute(\"data-state\") === \"open\";\n this.#applyContent(content, open, false);\n }\n\n /** Cancels a wait tied to a content target that was removed or replaced. */\n contentTargetDisconnected(): void {\n this.#transition.cancel();\n }\n\n /** Toggles the region open/closed. Bound via `data-action` (click). */\n toggle(): void {\n this.#apply(!this.#isOpen, true);\n }\n\n /**\n * Whether the region is logically open. Read from `aria-expanded` (not the\n * content's `hidden`) so a click *during* a close transition — when `hidden`\n * is still deferred — correctly reopens instead of re-closing.\n */\n get #isOpen(): boolean {\n if (this.hasTriggerTarget) {\n return this.triggerTarget.getAttribute(\"aria-expanded\") === \"true\";\n }\n return this.hasContentTarget && this.contentTarget.getAttribute(\"data-state\") === \"open\";\n }\n\n /**\n * Drives the disclosure to `open`, syncing the trigger's `aria-expanded` and\n * the content's `hidden` / `data-state` / height variable in an order where\n * `hidden` never blocks measurement or the transition.\n *\n * @param open - Target state.\n * @param waitForCloseTransition - When `false` (initial `connect`) the close\n * path applies `hidden` immediately. This flag does not suppress consumer CSS\n * on the open path.\n */\n #apply(open: boolean, waitForCloseTransition: boolean): void {\n if (this.hasTriggerTarget) {\n this.triggerTarget.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n }\n if (!this.hasContentTarget) return;\n\n const content = this.contentTarget;\n this.#transition.cancel();\n this.#applyContent(content, open, waitForCloseTransition);\n }\n\n /** Reflects one content target without relying on a later target lookup. */\n #applyContent(content: HTMLElement, open: boolean, waitForCloseTransition: boolean): void {\n if (open) {\n content.hidden = false;\n // Measure the natural height only once it is laid out (hidden removed) so\n // the consumer's `height` transition has a concrete target to animate to.\n content.style.setProperty(\n \"--stimeo--collapsible-content-height\",\n `${content.scrollHeight}px`,\n );\n content.setAttribute(\"data-state\", \"open\");\n return;\n }\n\n content.setAttribute(\"data-state\", \"closed\");\n if (waitForCloseTransition) {\n this.#applyHiddenAfterTransition(content);\n } else {\n content.hidden = true;\n }\n }\n\n /**\n * Re-applies `hidden` once the close transition settles. Guarded against a\n * reopen mid-transition; the shared waiter also guarantees a bounded fallback\n * when the browser emits no terminal transition event.\n */\n #applyHiddenAfterTransition(content: HTMLElement): void {\n this.#transition.wait(content, () => {\n if (content.getAttribute(\"data-state\") === \"closed\") {\n content.hidden = true;\n }\n });\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/safe_timeout.ts","../../src/utils/transition_completion.ts","../../src/controllers/collapsible_controller.ts"],"names":[],"mappings":"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","file":"collapsible_controller.js","sourcesContent":["/**\n * Self-cleaning timer registries shared by Stimeo controllers.\n *\n * Stimulus controllers frequently schedule `setTimeout` / `setInterval` work\n * (auto-dismiss, debouncing, polling). When the element leaves the DOM — a\n * Turbo Drive navigation, a Turbo Stream replacement, or any `disconnect()` —\n * orphaned timers keep firing against a detached controller, leaking memory and\n * mutating stale state. {@link SafeTimeout} and {@link SafeInterval} track every\n * timer they create so a single {@link TimerRegistry.clearAll | clearAll()} call\n * in `disconnect()` tears them all down.\n *\n * These are intentionally low-level primitives: they own *registration and\n * cleanup only*. Higher-level policy (pause/resume, remaining-time accounting)\n * stays in the individual controllers so per-widget semantics are not flattened\n * into a lowest-common-denominator helper.\n */\n\n/**\n * Largest delay a timer can hold: the platform stores it in a 32-bit signed\n * integer, and anything larger overflows to `1`, so a delay meant to be far in\n * the future fires almost immediately. A declared delay above this bound names\n * no delay at all, and a controller reading one falls back to its default.\n */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/**\n * Shared registry bookkeeping for the timeout/interval variants.\n *\n * Subclasses provide the scheduling primitive ({@link schedule}) and its matching\n * canceller ({@link cancel}); this base owns the set of live ids plus the\n * per-id and bulk teardown shared by both.\n */\nabstract class TimerRegistry {\n /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */\n protected readonly ids = new Set<number>();\n\n /** Schedules the underlying platform timer and returns its id. */\n protected abstract schedule(callback: () => void, delay: number): number;\n\n /** Cancels the underlying platform timer for `id`. */\n protected abstract cancel(id: number): void;\n\n /**\n * Cancels a single tracked timer.\n *\n * No-ops if the id is unknown (already cleared, fired, or never owned by this\n * registry), so callers can clear defensively without guarding.\n */\n clear(id: number): void {\n if (this.ids.delete(id)) {\n this.cancel(id);\n }\n }\n\n /**\n * Cancels every tracked timer. Call this from a controller's `disconnect()`\n * to guarantee no timer outlives the element.\n */\n clearAll(): void {\n for (const id of this.ids) {\n this.cancel(id);\n }\n this.ids.clear();\n }\n\n /** Number of timers currently tracked (pending). */\n get size(): number {\n return this.ids.size;\n }\n}\n\n/**\n * `setTimeout` wrapper that auto-forgets each timer once it fires and supports\n * bulk teardown on disconnect.\n *\n * @example\n * ```ts\n * #timers = new SafeTimeout();\n *\n * connect() {\n * this.#timers.set(() => this.dismiss(), 5000);\n * }\n *\n * disconnect() {\n * this.#timers.clearAll();\n * }\n * ```\n */\nexport class SafeTimeout extends TimerRegistry {\n /**\n * Schedules `callback` after `delay` ms and returns the timer id.\n *\n * The id is removed from the registry automatically when the timeout fires,\n * so {@link TimerRegistry.size | size} reflects only still-pending timers.\n */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(() => {\n this.ids.delete(id);\n callback();\n }, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setTimeout(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearTimeout(id);\n }\n}\n\n/**\n * `setInterval` wrapper that tracks every interval for bulk teardown on\n * disconnect. Unlike {@link SafeTimeout}, intervals are retained until they are\n * explicitly cleared because they fire repeatedly.\n *\n * @example\n * ```ts\n * #intervals = new SafeInterval();\n *\n * connect() {\n * this.#intervals.set(() => this.tick(), 1000);\n * }\n *\n * disconnect() {\n * this.#intervals.clearAll();\n * }\n * ```\n */\nexport class SafeInterval extends TimerRegistry {\n /** Schedules a repeating `callback` every `delay` ms and returns the timer id. */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(callback, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setInterval(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearInterval(id);\n }\n}\n","import { SafeTimeout } from \"./safe_timeout\";\n\n/** Computed transition fields needed to determine when an element has settled. */\nexport type TransitionStyle = Pick<\n CSSStyleDeclaration,\n \"transitionProperty\" | \"transitionDuration\" | \"transitionDelay\"\n>;\n\n/** Parsed transition property paired with its effective duration and delay. */\ninterface TransitionTiming {\n property: string;\n totalMs: number;\n}\n\n/** Parses a CSS `<time>` into milliseconds, returning `0` for malformed values. */\nfunction timeMs(value: string): number {\n const trimmed = value.trim();\n const amount = Number.parseFloat(trimmed);\n if (!Number.isFinite(amount)) return 0;\n if (trimmed.endsWith(\"ms\")) return amount;\n if (trimmed.endsWith(\"s\")) return amount * 1000;\n return 0;\n}\n\n/** Splits a computed comma-separated CSS list into normalized, non-empty items. */\nfunction cssList(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * Pairs transition properties, durations, and delays using CSS list repetition.\n *\n * The `transition-property` list determines the number of transitions. Shorter\n * duration/delay lists repeat, while extra values are ignored. A negative delay\n * shortens the remaining wall-clock time, and a non-positive total is settled.\n */\nfunction transitionTimings(style: TransitionStyle): TransitionTiming[] {\n const properties = cssList(style.transitionProperty);\n const durations = cssList(style.transitionDuration).map(timeMs);\n const delays = cssList(style.transitionDelay).map(timeMs);\n const effectiveProperties =\n properties.length > 0\n ? properties\n : Array.from({ length: Math.max(durations.length, delays.length, 1) }, () => \"all\");\n const effectiveDurations = durations.length > 0 ? durations : [0];\n const effectiveDelays = delays.length > 0 ? delays : [0];\n\n return effectiveProperties\n .filter((property) => property !== \"none\")\n .map((property, index) => ({\n property,\n totalMs: Math.max(\n 0,\n (effectiveDurations[index % effectiveDurations.length] ?? 0) +\n (effectiveDelays[index % effectiveDelays.length] ?? 0),\n ),\n }));\n}\n\n/** Maximum total over already-parsed timings (0 when the list is empty). */\nfunction maxTotalMs(timings: TransitionTiming[]): number {\n return timings.reduce((max, { totalMs }) => Math.max(max, totalMs), 0);\n}\n\n/** Maximum effective transition duration plus delay, in milliseconds. */\nexport function maxTransitionTotalMs(style: TransitionStyle): number {\n return maxTotalMs(transitionTimings(style));\n}\n\n/** Optional tuning for a single {@link TransitionCompletion.wait} call. */\nexport interface TransitionWaitOptions {\n /**\n * Positive wall-clock override (ms) for the bounded fallback, replacing the\n * auto-computed `max + 50ms` timer verbatim. It also keeps the wait armed for\n * a computed 0ms transition (no synchronous completion): the consumer asserts\n * a transition budget that computed styles cannot see. Non-positive and\n * non-finite (`NaN` / `Infinity`) values are ignored.\n */\n timeoutMs?: number;\n}\n\n/**\n * Owns one cancellable wait for an element's CSS transitions to settle.\n *\n * When available, active CSS transitions provide their expanded property names.\n * Tracking those names lets shorthand declarations settle from their longhand\n * terminal events. A terminal event from an interrupted phase is ignored while a\n * replacement transition for the same property is still active. Because that set\n * is sampled when the wait is armed, a property whose transition only starts a\n * frame later would otherwise be settled over; the still-running set is therefore\n * re-read before completing and adopted when it is not yet empty. Without Web\n * Animations data, explicit transition properties retain the declared-property\n * behavior and the ambiguous `transition-property: all` form waits until the\n * computed maximum wall-clock time. A `max + 50ms` timeout is always armed\n * because browsers emit no terminal event when a property never transitions, an\n * ancestor disappears, or rendering is otherwise interrupted; a consumer with\n * better knowledge can replace that fallback via\n * {@link TransitionWaitOptions.timeoutMs}.\n */\nexport class TransitionCompletion {\n readonly #timers = new SafeTimeout();\n #element: HTMLElement | null = null;\n #complete: (() => void) | null = null;\n #pendingProperties: Set<string> | null = null;\n #deadline = 0;\n\n /**\n * Replaces any prior wait and invokes `complete` synchronously for a 0ms\n * transition (including when `getComputedStyle` is unavailable).\n *\n * With a positive `options.timeoutMs` the synchronous fast-path is skipped and\n * the override replaces the auto-computed fallback (see {@link TransitionWaitOptions}).\n */\n wait(element: HTMLElement, complete: () => void, options: TransitionWaitOptions = {}): void {\n this.cancel();\n\n const requested = options.timeoutMs ?? 0;\n const override = Number.isFinite(requested) && requested > 0 ? requested : 0;\n // A non-browser / partial-DOM environment cannot report a computable\n // transition, which is indistinguishable from a 0ms one.\n const timings =\n typeof window.getComputedStyle === \"function\"\n ? transitionTimings(window.getComputedStyle(element))\n : [];\n const maximum = maxTotalMs(timings);\n if (maximum <= 0 && override <= 0) {\n complete();\n return;\n }\n\n this.#element = element;\n this.#complete = complete;\n this.#deadline = Date.now() + maximum;\n const activeProperties = this.#activeTransitionProperties(element);\n this.#pendingProperties =\n activeProperties.size > 0 ? activeProperties : this.#explicitPendingProperties(timings);\n element.addEventListener(\"transitionend\", this.#onTerminal);\n element.addEventListener(\"transitioncancel\", this.#onTerminal);\n this.#timers.set(() => this.#finish(), override > 0 ? override : maximum + 50);\n }\n\n /** Cancels the pending wait without invoking its completion callback. */\n cancel(): void {\n this.#complete = null;\n this.#teardown();\n }\n\n /**\n * Handles terminal events from the observed element only.\n *\n * For explicit property lists, every declared positive-time property must\n * settle. For `all`, no reliable property set exists, so an event can finish\n * only after the computed maximum time; the safety timeout owns the usual path.\n */\n readonly #onTerminal = (event: Event): void => {\n if (event.target !== this.#element) return;\n const transitionEvent = event as TransitionEvent;\n // A pseudo-element's transition is reported with its originating element\n // as `target`; it must not settle the element's own transition.\n if (transitionEvent.pseudoElement) return;\n\n if (this.#pendingProperties) {\n const propertyName = transitionEvent.propertyName;\n const active = this.#activeTransitionProperties(this.#element);\n // An interrupted transition queues its cancel event before the replacement\n // phase starts, but dispatch can happen after the new wait is armed. The\n // replacement is then the active transition for this property, so the stale\n // terminal event must not settle the new phase.\n if (active.has(propertyName)) return;\n if (!this.#pendingProperties.delete(propertyName)) return;\n if (this.#pendingProperties.size > 0) return;\n // The tracked set is an arm-time snapshot, so a transition the phase starts\n // one frame later is absent from it. Re-reading the still-running set before\n // settling adopts those stragglers instead of completing over them; the\n // fallback timer stays armed, so this cannot extend the wait unboundedly.\n if (active.size > 0) {\n this.#pendingProperties = active;\n return;\n }\n this.#finish();\n return;\n }\n\n if (Date.now() >= this.#deadline) this.#finish();\n };\n\n /**\n * Returns active CSS transition properties expanded to the names reported by\n * terminal events. CSS animations and pseudo-element effects are excluded.\n */\n #activeTransitionProperties(element: HTMLElement | null): Set<string> {\n if (!element || typeof element.getAnimations !== \"function\") return new Set();\n\n try {\n const properties = element.getAnimations().flatMap((animation) => {\n if (animation.playState === \"idle\" || animation.playState === \"finished\") return [];\n const effect = animation.effect as KeyframeEffect | null;\n // A pseudo-element effect names the originating element as its target, so\n // `target` alone cannot separate it. Its terminal events are ignored, so\n // tracking its properties would only strand the wait on the fallback.\n if (effect?.pseudoElement) return [];\n const target = effect?.target;\n if (target && target !== element) return [];\n const property = (animation as Partial<CSSTransition>).transitionProperty;\n return typeof property === \"string\" && property.length > 0 ? [property] : [];\n });\n return new Set(properties);\n } catch {\n // Partial DOM implementations can expose getAnimations without supporting\n // it. The declared-property tracker and bounded timer remain safe fallbacks.\n return new Set();\n }\n }\n\n /** Returns explicit positive-time properties, or `null` for the ambiguous `all`. */\n #explicitPendingProperties(timings: TransitionTiming[]): Set<string> | null {\n if (timings.some(({ property }) => property === \"all\")) return null;\n const pending = new Set(\n timings.filter(({ totalMs }) => totalMs > 0).map(({ property }) => property),\n );\n // An empty set is only reachable through a timeout override (a 0ms transition\n // otherwise completes synchronously). With nothing to track, fall back to the\n // deadline rule so any terminal event can settle the wait, exactly like `all`.\n return pending.size > 0 ? pending : null;\n }\n\n /** Completes exactly once, releasing listeners and the fallback before the callback. */\n #finish(): void {\n const complete = this.#complete;\n if (!complete) return;\n this.#complete = null;\n this.#teardown();\n complete();\n }\n\n /** Releases the exact element listeners and timer owned by the current wait. */\n #teardown(): void {\n this.#timers.clearAll();\n this.#element?.removeEventListener(\"transitionend\", this.#onTerminal);\n this.#element?.removeEventListener(\"transitioncancel\", this.#onTerminal);\n this.#element = null;\n this.#pendingProperties = null;\n this.#deadline = 0;\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { TransitionCompletion } from \"../utils/transition_completion\";\n\n/**\n * Headless, accessible single-disclosure (collapsible) behavior.\n *\n * Markup contract (identifier: `stimeo--collapsible`):\n * <div data-controller=\"stimeo--collapsible\">\n * <button data-stimeo--collapsible-target=\"trigger\"\n * data-action=\"click->stimeo--collapsible#toggle\"\n * aria-expanded=\"false\" aria-controls=\"more\">Show details</button>\n * <div id=\"more\" data-stimeo--collapsible-target=\"content\"\n * data-state=\"closed\" hidden>…</div>\n * </div>\n *\n * Implements the WAI-ARIA APG **Disclosure** pattern for a single inline region.\n * Unlike {@link AccordionController} it manages exactly one trigger/content pair\n * with no sibling coordination, and unlike a dropdown the content expands in\n * flow and never closes on an outside click.\n *\n * @remarks\n * Behavior only — the consumer owns the height transition and all decoration.\n * The controller keeps the open lifecycle ordered so `hidden` (effectively\n * `display:none`) never blocks measurement or the transition:\n * - **Open**: drop `hidden` → measure the natural height into\n * `--stimeo--collapsible-content-height` → set `data-state=\"open\"`.\n * - **Close**: set `data-state=\"closed\"` (CSS shrinks the height) → re-apply\n * `hidden` once the transition settles. With no transition (or reduced motion,\n * which the consumer's CSS expresses as a zero duration) it is applied\n * immediately; an owned fallback covers missing terminal events.\n */\nexport class CollapsibleController extends Controller<HTMLElement> {\n static override targets = [\"trigger\", \"content\"];\n static override values = {\n open: { type: Boolean, default: false },\n };\n static actions = [\"toggle\"] as const;\n\n declare readonly triggerTarget: HTMLElement;\n declare readonly contentTarget: HTMLElement;\n declare readonly hasTriggerTarget: boolean;\n declare readonly hasContentTarget: boolean;\n\n declare openValue: boolean;\n\n /** Owns the cancellable close-transition wait and its bounded fallback. */\n readonly #transition = new TransitionCompletion();\n /** Distinguishes dynamic target churn from the callbacks that precede `connect()`. */\n #connected = false;\n\n /**\n * Establishes the initial open/closed state without waiting for a close transition.\n *\n * The DOM is the source of truth on reconnect (Turbo cache restore / morph): an\n * **explicit** state attribute — `aria-expanded=\"true\"`/`\"false\"` (or, with no\n * trigger, `data-state=\"open\"`/`\"closed\"`) — is honored verbatim so a region the\n * user opened *or* closed survives a back-navigation, even when the declarative\n * `open` Value disagrees. An already-open region remains open without a\n * close/reopen cycle. The Value only seeds a genuinely fresh render where no\n * state attribute is present yet; any opening animation in that case belongs to\n * the consumer's CSS.\n */\n override connect(): void {\n this.#connected = true;\n this.#apply(this.#initialOpen(), false);\n }\n\n /** Resolves the connect-time state: explicit DOM state wins, else the `open` Value. */\n #initialOpen(): boolean {\n if (this.hasTriggerTarget) {\n const expanded = this.triggerTarget.getAttribute(\"aria-expanded\");\n if (expanded === \"true\") return true;\n if (expanded === \"false\") return false;\n } else if (this.hasContentTarget) {\n const state = this.contentTarget.getAttribute(\"data-state\");\n if (state === \"open\") return true;\n if (state === \"closed\") return false;\n }\n return this.openValue;\n }\n\n override disconnect(): void {\n this.#connected = false;\n this.#transition.cancel();\n }\n\n /** Reconciles a replacement trigger target with the content's live state. */\n triggerTargetConnected(trigger: HTMLElement): void {\n if (!this.#connected || !this.hasContentTarget) return;\n trigger.setAttribute(\n \"aria-expanded\",\n this.contentTarget.getAttribute(\"data-state\") === \"open\" ? \"true\" : \"false\",\n );\n }\n\n /** Reconciles a replacement content target with the disclosure's live state. */\n contentTargetConnected(content: HTMLElement): void {\n if (!this.#connected) return;\n this.#transition.cancel();\n const open = this.hasTriggerTarget\n ? this.triggerTarget.getAttribute(\"aria-expanded\") === \"true\"\n : content.getAttribute(\"data-state\") === \"open\";\n this.#applyContent(content, open, false);\n }\n\n /** Cancels a wait tied to a content target that was removed or replaced. */\n contentTargetDisconnected(): void {\n this.#transition.cancel();\n }\n\n /** Toggles the region open/closed. Bound via `data-action` (click). */\n toggle(): void {\n this.#apply(!this.#isOpen, true);\n }\n\n /**\n * Whether the region is logically open. Read from `aria-expanded` (not the\n * content's `hidden`) so a click *during* a close transition — when `hidden`\n * is still deferred — correctly reopens instead of re-closing.\n */\n get #isOpen(): boolean {\n if (this.hasTriggerTarget) {\n return this.triggerTarget.getAttribute(\"aria-expanded\") === \"true\";\n }\n return this.hasContentTarget && this.contentTarget.getAttribute(\"data-state\") === \"open\";\n }\n\n /**\n * Drives the disclosure to `open`, syncing the trigger's `aria-expanded` and\n * the content's `hidden` / `data-state` / height variable in an order where\n * `hidden` never blocks measurement or the transition.\n *\n * @param open - Target state.\n * @param waitForCloseTransition - When `false` (initial `connect`) the close\n * path applies `hidden` immediately. This flag does not suppress consumer CSS\n * on the open path.\n */\n #apply(open: boolean, waitForCloseTransition: boolean): void {\n if (this.hasTriggerTarget) {\n this.triggerTarget.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n }\n if (!this.hasContentTarget) return;\n\n const content = this.contentTarget;\n this.#transition.cancel();\n this.#applyContent(content, open, waitForCloseTransition);\n }\n\n /** Reflects one content target without relying on a later target lookup. */\n #applyContent(content: HTMLElement, open: boolean, waitForCloseTransition: boolean): void {\n if (open) {\n content.hidden = false;\n // Measure the natural height only once it is laid out (hidden removed) so\n // the consumer's `height` transition has a concrete target to animate to.\n content.style.setProperty(\n \"--stimeo--collapsible-content-height\",\n `${content.scrollHeight}px`,\n );\n content.setAttribute(\"data-state\", \"open\");\n return;\n }\n\n content.setAttribute(\"data-state\", \"closed\");\n if (waitForCloseTransition) {\n this.#applyHiddenAfterTransition(content);\n } else {\n content.hidden = true;\n }\n }\n\n /**\n * Re-applies `hidden` once the close transition settles. Guarded against a\n * reopen mid-transition; the shared waiter also guarantees a bounded fallback\n * when the browser emits no terminal transition event.\n */\n #applyHiddenAfterTransition(content: HTMLElement): void {\n this.#transition.wait(content, () => {\n if (content.getAttribute(\"data-state\") === \"closed\") {\n content.hidden = true;\n }\n });\n }\n}\n"]}
@@ -2,6 +2,12 @@ import { Controller } from '@hotwired/stimulus';
2
2
 
3
3
  // src/controllers/conditional_fields_controller.ts
4
4
 
5
+ // src/utils/event_owner.ts
6
+ function ownerIndex(candidates, node) {
7
+ if (!(node instanceof Node)) return -1;
8
+ return candidates.findIndex((candidate) => candidate.contains(node));
9
+ }
10
+
5
11
  // src/utils/focus_candidate.ts
6
12
  function inheritsFieldsetDisabled(control) {
7
13
  let fieldset = control.closest("fieldset[disabled]");
@@ -393,7 +399,7 @@ var ConditionalFieldsController = class extends Controller {
393
399
  }
394
400
  /** Whether an authored mutation target belongs to a trigger, region, or managed control. */
395
401
  #elementAffectsState(target, triggers, regions) {
396
- return triggers.some((trigger) => trigger === target || trigger.contains(target)) || regions.some((region) => region === target || region.contains(target));
402
+ return ownerIndex(triggers, target) !== -1 || ownerIndex(regions, target) !== -1;
397
403
  }
398
404
  /** Whether a form owns at least one current trigger, including `form=` associations. */
399
405
  #hasTriggerOwnedBy(form) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/focus_candidate.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/before_cache_reset.ts","../../src/utils/tabindex_loan.ts","../../src/controllers/conditional_fields_controller.ts"],"names":[],"mappings":";;;;;AAWO,SAAS,yBAAyB,OAAA,EAA+B;AACtE,EAAA,IAAI,QAAA,GAA2B,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,CAAA;AACnE,EAAA,OAAO,QAAA,EAAU;AACf,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,CAAE,IAAA,CAAK,CAAC,KAAA,KAAU,KAAA,CAAM,OAAA,KAAY,QAAQ,CAAA;AACvF,IAAA,IAAI,CAAC,MAAA,EAAQ,QAAA,CAAS,OAAO,GAAG,OAAO,IAAA;AACvC,IAAA,QAAA,GAAW,QAAA,CAAS,aAAA,EAAe,OAAA,CAAQ,oBAAoB,CAAA,IAAK,IAAA;AAAA,EACtE;AACA,EAAA,OAAO,KAAA;AACT;AAgDO,SAAS,aAAa,OAAA,EAA+B;AAC1D,EAAA,IAAI,OAAA,CAAQ,OAAA,CAAQ,mBAAmB,CAAA,EAAG,OAAO,KAAA;AACjD,EAAA,IAAI,OAAA,YAAmB,gBAAA,IAAoB,OAAA,CAAQ,IAAA,KAAS,UAAU,OAAO,KAAA;AAC7E,EAAA,IAAI,EAAE,UAAA,IAAc,OAAA,CAAA,EAAU,OAAO,IAAA;AACrC,EAAA,IAAK,OAAA,CAAgD,UAAU,OAAO,KAAA;AACtE,EAAA,OAAO,CAAC,yBAAyB,OAAO,CAAA;AAC1C;;;ACpBO,IAAM,qBAAN,MAAyB;AAAA,EACrB,IAAA;AAAA,EACT,OAAA,GAAU,KAAA;AAAA,EACV,OAAA,GAAU,KAAA;AAAA,EACV,WAAA,GAAc,CAAA;AAAA;AAAA,EAGd,YAAY,GAAA,EAAiB;AAC3B,IAAA,IAAA,CAAK,IAAA,GAAO,GAAA;AAAA,EACd;AAAA;AAAA,EAGA,QAAA,GAAiB;AACf,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAAA,EACjB;AAAA;AAAA,EAGA,MAAA,GAAe;AACb,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,IAAA,CAAK,WAAA,IAAe,CAAA;AAAA,EACtB;AAAA;AAAA,EAGA,QAAA,GAAiB;AACf,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,OAAA,EAAS;AACnC,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,MAAM,aAAa,IAAA,CAAK,WAAA;AACxB,IAAA,cAAA,CAAe,MAAM;AAEnB,MAAA,IAAI,UAAA,KAAe,KAAK,WAAA,IAAe,CAAC,KAAK,OAAA,IAAW,CAAC,KAAK,OAAA,EAAS;AACvE,MAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,MAAA,IAAA,CAAK,IAAA,EAAK;AAAA,IACZ,CAAC,CAAA;AAAA,EACH;AACF,CAAA;;;AC7CO,IAAM,gBAAA,GAAN,MAAM,iBAAA,CAAiB;AAAA;AAAA,EAE5B,OAAgB,YAAA,mBAAe,IAAI,GAAA,EAAsB;AAAA;AAAA,EAGzD,OAAgB,iBAAiB,MAAY;AAC3C,IAAA,KAAA,MAAW,UAAA,IAAc,iBAAA,CAAiB,YAAA,EAAc,UAAA,CAAW,OAAA,EAAQ;AAAA,EAC7E,CAAA;AAAA,EAES,OAAA;AAAA;AAAA,EAGT,YAAY,MAAA,EAAoB;AAC9B,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,EACjB;AAAA;AAAA,EAGA,QAAA,GAAiB;AACf,IAAA,MAAM,KAAA,GAAQ,iBAAA,CAAiB,YAAA,CAAa,IAAA,KAAS,CAAA;AACrD,IAAA,iBAAA,CAAiB,YAAA,CAAa,IAAI,IAAI,CAAA;AACtC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAA,EAAsB,iBAAA,CAAiB,cAAc,CAAA;AAAA,IACjF;AAAA,EACF;AAAA;AAAA,EAGA,UAAA,GAAmB;AACjB,IAAA,iBAAA,CAAiB,YAAA,CAAa,OAAO,IAAI,CAAA;AACzC,IAAA,IAAI,iBAAA,CAAiB,YAAA,CAAa,IAAA,GAAO,CAAA,EAAG;AAC5C,IAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAA,EAAsB,iBAAA,CAAiB,cAAc,CAAA;AAAA,EACpF;AACF,CAAA;;;ACtBO,IAAM,eAAN,MAAwD;AAAA,EACpD,MAAA;AAAA,EACA,KAAA,uBAAY,GAAA,EAAO;AAAA;AAAA,EAEnB,eAAe,IAAI,gBAAA,CAAiB,MAAM,IAAA,CAAK,WAAW,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnE,WAAA,CAAY,QAAgB,IAAA,EAAM;AAChC,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AAAA,EAChB;AAAA;AAAA,EAGA,KAAK,OAAA,EAAkB;AACrB,IAAA,IAAI,OAAA,CAAQ,YAAA,CAAa,UAAU,CAAA,EAAG;AACtC,IAAA,OAAA,CAAQ,YAAA,CAAa,UAAA,EAAY,IAAA,CAAK,MAAM,CAAA;AAC5C,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,OAAO,CAAA;AAGtB,IAAA,IAAA,CAAK,aAAa,QAAA,EAAS;AAAA,EAC7B;AAAA;AAAA,EAGA,SAAA,GAAkB;AAChB,IAAA,KAAA,MAAW,OAAA,IAAW,KAAK,KAAA,EAAO;AAChC,MAAA,IAAI,OAAA,CAAQ,aAAa,UAAU,CAAA,KAAM,KAAK,MAAA,EAAQ,OAAA,CAAQ,gBAAgB,UAAU,CAAA;AAAA,IAC1F;AACA,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AACjB,IAAA,IAAA,CAAK,aAAa,UAAA,EAAW;AAAA,EAC/B;AACF,CAAA;;;ACxEA,IAAM,eAAA,GAAkB,2BAAA;AAGxB,IAAM,mBAAA,GAAsB;AAAA,EAC1B,QAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,UAAA;AAAA,EACA,mBAAA;AAAA,EACA,qBAAA;AAAA,EACA,iBAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA;AA6CO,IAAM,2BAAA,GAAN,cAA0C,UAAA,CAAwB;AAAA,EACvE,OAAgB,OAAA,GAAU,CAAC,SAAA,EAAW,QAAQ,CAAA;AAAA,EAC9C,OAAgB,MAAA,GAAS;AAAA,IACvB,aAAA,EAAe,EAAE,IAAA,EAAM,OAAA,EAAS,SAAS,IAAA,EAAK;AAAA,IAC9C,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,KAAA;AAAM,GACxC;AAAA,EACA,OAAO,OAAA,GAAU,CAAC,UAAU,CAAA;AAAA,EAC5B,OAAO,MAAA,GAAS,CAAC,QAAA,EAAU,WAAW,CAAA;AAAA;AAAA,EAStC,YAAA,uBAAmB,OAAA,EAA8B;AAAA;AAAA,EAEjD,eAAA,uBAAsB,OAAA,EAAiD;AAAA,EACvE,UAAA,GAAa,KAAA;AAAA;AAAA,EAGJ,aAAa,IAAI,kBAAA,CAAmB,MAAM,IAAA,CAAK,eAAe,CAAA;AAAA;AAAA,EAE9D,aAAA,GAAgB,IAAI,YAAA,EAA0B;AAAA;AAAA,EAE9C,SAAA,GAAY,IAAI,gBAAA,CAAiB,CAAC,YAAY,IAAA,CAAK,YAAA,CAAa,OAAO,CAAC,CAAA;AAAA;AAAA,EAGxE,eAAA,GAAkB,CAAC,KAAA,KAAuB;AACjD,IAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,IAAA,MAAM,WAAW,IAAA,CAAK,cAAA;AACtB,IAAA,IAAI,MAAA,YAAkB,WAAW,QAAA,CAAS,IAAA,CAAK,CAAC,OAAA,KAAY,OAAA,KAAY,MAAM,CAAA,EAAG;AAC/E,MAAA,IAAA,CAAK,cAAc,QAAQ,CAAA;AAAA,IAC7B;AAAA,EACF,CAAA;AAAA;AAAA,EAGS,WAAW,MAAY;AAC9B,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B,CAAA;AAAA;AAAA,EAGS,QAAA,GAAW,CAAC,KAAA,KAAuB;AAC1C,IAAA,MAAM,OAAO,KAAA,CAAM,MAAA;AACnB,IAAA,IAAI,IAAA,YAAgB,eAAA,IAAmB,IAAA,CAAK,kBAAA,CAAmB,IAAI,CAAA,EAAG;AACpE,MAAA,cAAA,CAAe,MAAM;AACnB,QAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,EAAkB,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,MACxD,CAAC,CAAA;AAAA,IACH;AAAA,EACF,CAAA;AAAA;AAAA,EAGS,OAAA,GAAgB;AACvB,IAAA,IAAA,CAAK,YAAA,uBAAmB,OAAA,EAAQ;AAChC,IAAA,IAAA,CAAK,eAAA,uBAAsB,OAAA,EAAQ;AACnC,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AACzB,IAAA,IAAA,CAAK,OAAA,EAAQ;AACb,IAAA,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS;AAAA,MACnC,UAAA,EAAY,IAAA;AAAA,MACZ,eAAA,EAAiB,mBAAA;AAAA,MACjB,SAAA,EAAW,IAAA;AAAA,MACX,OAAA,EAAS;AAAA,KACV,CAAA;AACD,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,IAAA,CAAK,OAAA,CAAQ,gBAAA,CAAiB,QAAA,EAAU,IAAA,CAAK,eAAe,CAAA;AAC5D,IAAA,IAAA,CAAK,OAAA,CAAQ,gBAAA,CAAiB,OAAA,EAAS,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,IAAA,CAAK,OAAA,CAAQ,gBAAA,CAAiB,qBAAA,EAAuB,IAAA,CAAK,QAAQ,CAAA;AAClE,IAAA,QAAA,CAAS,gBAAA,CAAiB,OAAA,EAAS,IAAA,CAAK,QAAA,EAAU,IAAI,CAAA;AAAA,EACxD;AAAA;AAAA,EAGS,UAAA,GAAmB;AAC1B,IAAA,IAAA,CAAK,WAAW,MAAA,EAAO;AACvB,IAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAClB,IAAA,IAAA,CAAK,UAAU,UAAA,EAAW;AAC1B,IAAA,IAAA,CAAK,OAAA,CAAQ,mBAAA,CAAoB,QAAA,EAAU,IAAA,CAAK,eAAe,CAAA;AAC/D,IAAA,IAAA,CAAK,OAAA,CAAQ,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,eAAe,CAAA;AAC9D,IAAA,IAAA,CAAK,OAAA,CAAQ,mBAAA,CAAoB,qBAAA,EAAuB,IAAA,CAAK,QAAQ,CAAA;AACrE,IAAA,QAAA,CAAS,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,QAAA,EAAU,IAAI,CAAA;AACzD,IAAA,IAAA,CAAK,cAAc,SAAA,EAAU;AAAA,EAC/B;AAAA;AAAA,EAGA,sBAAA,GAA+B;AAC7B,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,yBAAA,GAAkC;AAChC,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,qBAAA,GAA8B;AAC5B,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,wBAAA,GAAiC;AAC/B,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,iBAAA,GAA0B;AACxB,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,yBAAA,GAAkC;AAChC,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,QAAA,GAAiB;AACf,IAAA,IAAA,CAAK,aAAA,EAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAA,CAAQ,QAAA,GAAsB,IAAA,CAAK,cAAA,EAAoC;AACrE,IAAA,MAAM,UAAU,IAAA,CAAK,aAAA;AACrB,IAAA,MAAM,IAAA,uBAAW,GAAA,EAA0B;AAC3C,IAAA,KAAA,MAAW,MAAA,IAAU,SAAS,IAAA,CAAK,GAAA,CAAI,QAAQ,IAAA,CAAK,UAAA,CAAW,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAEhF,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAiB;AACrC,IAAA,MAAM,gBAAA,GAAmB;AAAA,MACvB,GAAG,QAAQ,MAAA,CAAO,CAAC,WAAW,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,KAAM,IAAI,CAAA;AAAA,MACvD,GAAG,QAAQ,MAAA,CAAO,CAAC,WAAW,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,KAAM,KAAK;AAAA,KAC1D;AACA,IAAA,KAAA,MAAW,UAAU,gBAAA,EAAkB;AACrC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAC/B,MAAA,IAAI,YAAY,MAAA,IAAa,IAAA,CAAK,aAAa,MAAA,EAAQ,OAAA,EAAS,IAAI,CAAA,EAAG;AACrE,QAAA,OAAA,CAAQ,IAAI,MAAM,CAAA;AAAA,MACpB;AAAA,IACF;AAEA,IAAA,OAAO,OAAA,CACJ,OAAO,CAAC,MAAA,KAAW,QAAQ,GAAA,CAAI,MAAM,CAAC,CAAA,CACtC,GAAA,CAAI,CAAC,MAAA,MAAY,EAAE,QAAQ,OAAA,EAAS,IAAA,CAAK,IAAI,MAAM,CAAA,KAAM,MAAK,CAAE,CAAA;AAAA,EACrE;AAAA;AAAA,EAGA,aAAA,CAAc,QAAA,GAAsB,IAAA,CAAK,cAAA,EAAsB;AAC7D,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAC3C,MAAA,IAAA,CAAK,QAAA,CAAS,QAAA,EAAU,EAAE,MAAA,EAAQ,CAAA;AAAA,IACpC;AAAA,EACF;AAAA;AAAA,EAGA,aAAA,GAAsB;AACpB,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,EAAQ,EAAG;AACnC,MAAA,IAAA,CAAK,QAAA,CAAS,WAAA,EAAa,EAAE,MAAA,EAAQ,CAAA;AAAA,IACvC;AAAA,EACF;AAAA;AAAA,EAGA,YAAA,CACE,MAAA,EACA,OAAA,EACA,IAAA,EACS;AACT,IAAA,MAAM,WAAW,IAAA,CAAK,YAAA,CAAa,IAAI,MAAM,CAAA,IAAK,CAAC,MAAA,CAAO,MAAA;AAC1D,IAAA,MAAM,UAAU,OAAA,KAAY,QAAA;AAC5B,IAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,OAAO,CAAA;AAErC,IAAA,IAAI,CAAC,OAAA,EAAS,IAAA,CAAK,aAAA,CAAc,QAAQ,IAAI,CAAA;AAC7C,IAAA,IAAA,CAAK,gBAAA,CAAiB,QAAQ,OAAO,CAAA;AACrC,IAAA,IAAA,CAAK,mBAAA,CAAoB,QAAQ,OAAO,CAAA;AACxC,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA,EAGA,gBAAA,CAAiB,QAAqB,OAAA,EAAwB;AAC5D,IAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,EAAQ,QAAA,EAAU,OAAA,GAAU,OAAO,EAAE,CAAA;AAC1D,IAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,EAAQ,aAAA,EAAe,OAAA,GAAU,OAAO,MAAM,CAAA;AACnE,IAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,EAAQ,cAAA,EAAgB,OAAA,GAAU,SAAS,IAAI,CAAA;AAAA,EACtE;AAAA;AAAA,EAGA,mBAAA,CAAoB,QAAqB,OAAA,EAAwB;AAC/D,IAAA,MAAM,aAAA,GAAgB,CAAC,OAAA,IAAW,IAAA,CAAK,kBAAA;AACvC,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,gBAAA,CAA8B,iCAAiC,CAAA;AACvF,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,YAAA,CAAa,eAAe,CAAA;AACnD,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,IAAI,CAAC,QAAQ,QAAA,EAAU;AACrB,UAAA,IAAA,CAAK,eAAA,CAAgB,OAAA,EAAS,UAAA,EAAY,EAAE,CAAA;AAC5C,UAAA,IAAA,CAAK,eAAA,CAAgB,OAAA,EAAS,eAAA,EAAiB,MAAM,CAAA;AAAA,QACvD,WAAW,MAAA,IAAU,OAAA,CAAQ,YAAA,CAAa,eAAe,MAAM,MAAA,EAAQ;AACrE,UAAA,IAAA,CAAK,eAAA,CAAgB,OAAA,EAAS,eAAA,EAAiB,MAAM,CAAA;AAAA,QACvD;AAAA,MACF,WAAW,MAAA,EAAQ;AACjB,QAAA,IAAA,CAAK,eAAA,CAAgB,OAAA,EAAS,UAAA,EAAY,IAAI,CAAA;AAC9C,QAAA,IAAA,CAAK,eAAA,CAAgB,OAAA,EAAS,eAAA,EAAiB,IAAI,CAAA;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,UAAA,CAAW,QAAqB,QAAA,EAA8B;AAC5D,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,aAAA,CAAc,MAAM,CAAA;AAC3C,IAAA,IAAI,SAAA,KAAc,IAAA,EAAM,OAAO,CAAC,MAAA,CAAO,MAAA;AACvC,IAAA,OACE,QAAA,CAAS,MAAA,GAAS,CAAA,KACjB,IAAA,CAAK,UAAA,KAAe,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,SAAS,CAAA,GAAI,QAAA,CAAS,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,EAEpF;AAAA;AAAA,EAGA,cAAc,MAAA,EAA6D;AACzE,IAAA,IAAI,MAAA,CAAO,YAAA,CAAa,mBAAmB,CAAA,EAAG;AAC5C,MAAA,OAAO,CAAC,OAAA,KAAY,IAAA,CAAK,UAAA,CAAW,OAAO,CAAA;AAAA,IAC7C;AACA,IAAA,IAAI,MAAA,CAAO,YAAA,CAAa,qBAAqB,CAAA,EAAG;AAC9C,MAAA,OAAO,CAAC,OAAA,KAAY,CAAC,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA,IAC9C;AACA,IAAA,MAAM,MAAA,GAAS,OAAO,OAAA,CAAQ,SAAA;AAC9B,IAAA,IAAI,WAAW,MAAA,EAAW;AACxB,MAAA,OAAO,CAAC,OAAA,KAAY,IAAA,CAAK,aAAA,CAAc,SAAS,MAAM,CAAA;AAAA,IACxD;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,WAAW,OAAA,EAA2B;AACpC,IAAA,OAAO,OAAA,YAAmB,oBAAoB,OAAA,CAAQ,OAAA;AAAA,EACxD;AAAA;AAAA,EAGA,aAAA,CAAc,SAAkB,MAAA,EAAyB;AACvD,IAAA,IACE,mBAAmB,gBAAA,KAClB,OAAA,CAAQ,SAAS,UAAA,IAAc,OAAA,CAAQ,SAAS,OAAA,CAAA,EACjD;AACA,MAAA,OAAO,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,KAAA,KAAU,MAAA;AAAA,IAC9C;AACA,IAAA,OAAO,QAAQ,KAAA,KAAU,MAAA;AAAA,EAC3B;AAAA;AAAA,EAGA,aAAA,CAAc,QAAqB,IAAA,EAA+C;AAChF,IAAA,MAAM,SAAS,QAAA,CAAS,aAAA;AACxB,IAAA,IAAI,UAAU,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,EAAG,IAAA,CAAK,WAAW,IAAI,CAAA;AAAA,EAC7D;AAAA;AAAA,EAGA,WAAW,IAAA,EAA+C;AACxD,IAAA,MAAM,WAAA,GAAc,KAAK,cAAA,CAAe,IAAA;AAAA,MACtC,CAAC,YAAY,YAAA,CAAa,OAAO,KAAK,IAAA,CAAK,aAAA,CAAc,SAAS,IAAI;AAAA,KACxE;AACA,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,IAAA,CAAK,cAAc,SAAA,EAAU;AAC7B,MAAA,WAAA,CAAY,KAAA,EAAM;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA;AACpC,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAAA,EACrB;AAAA;AAAA,EAGA,aAAA,CAAc,WAAwB,IAAA,EAAkD;AACtF,IAAA,OAAO,CAAC,GAAG,IAAI,CAAA,CAAE,MAAM,CAAC,CAAC,MAAA,EAAQ,OAAO,MAAM,OAAA,IAAW,CAAC,MAAA,CAAO,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,EACtF;AAAA;AAAA,EAGA,eAAA,CAAgB,OAAA,EAAkB,IAAA,EAAc,KAAA,EAAgC;AAC9E,IAAA,IAAI,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA,KAAM,KAAA,EAAO;AACxC,MAAA,IAAI,KAAK,UAAA,EAAY;AACnB,QAAA,IAAI,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,OAAO,CAAA;AAC7C,QAAA,IAAI,CAAC,MAAA,EAAQ;AACX,UAAA,MAAA,uBAAa,GAAA,EAAI;AACjB,UAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,OAAA,EAAS,MAAM,CAAA;AAAA,QAC1C;AACA,QAAA,MAAA,CAAO,GAAA,CAAI,MAAM,KAAK,CAAA;AAAA,MACxB;AACA,MAAA,IAAI,KAAA,KAAU,IAAA,EAAM,OAAA,CAAQ,eAAA,CAAgB,IAAI,CAAA;AAAA,WAC3C,OAAA,CAAQ,YAAA,CAAa,IAAA,EAAM,KAAK,CAAA;AAAA,IACvC;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,OAAA,EAAiC;AAC5C,IAAA,MAAM,WAAW,IAAA,CAAK,cAAA;AACtB,IAAA,MAAM,UAAU,IAAA,CAAK,aAAA;AACrB,IAAA,MAAM,aAAA,uBAAoB,GAAA,EAA0B;AACpD,IAAA,IAAI,cAAA,GAAiB,KAAA;AAErB,IAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,MAAA,IAAI,MAAA,CAAO,IAAA,KAAS,YAAA,IAAgB,MAAA,CAAO,kBAAkB,OAAA,EAAS;AACpE,QAAA,MAAM,OAAO,MAAA,CAAO,aAAA;AACpB,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,OAAO,MAAM,CAAA;AACrD,QAAA,IAAI,IAAA,IAAQ,MAAA,EAAQ,GAAA,CAAI,IAAI,CAAA,EAAG;AAC7B,UAAA,IAAI,KAAA,GAAQ,aAAA,CAAc,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA;AAC3C,UAAA,IAAI,CAAC,KAAA,EAAO;AACV,YAAA,KAAA,uBAAY,GAAA,EAAI;AAChB,YAAA,aAAA,CAAc,GAAA,CAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA;AAAA,UACxC;AACA,UAAA,KAAA,CAAM,IAAI,IAAI,CAAA;AACd,UAAA,IAAI,MAAA,CAAO,OAAO,YAAA,CAAa,IAAI,MAAM,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA,EAAG;AAAA,QAC7D;AAAA,MACF;AACA,MAAA,IACE,MAAA,CAAO,kBAAkB,OAAA,IACzB,IAAA,CAAK,qBAAqB,MAAA,CAAO,MAAA,EAAQ,QAAA,EAAU,OAAO,CAAA,EAC1D;AACA,QAAA,cAAA,GAAiB,IAAA;AAAA,MACnB;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,CAAC,OAAA,EAAS,KAAK,CAAA,IAAK,aAAA,EAAe;AAC5C,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,OAAO,CAAA;AAC/C,MAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,MAAA,EAAQ,MAAA,CAAO,IAAI,CAAA;AAAA,IAC/C;AACA,IAAA,IAAI,cAAA,EAAgB,IAAA,CAAK,UAAA,CAAW,QAAA,EAAS;AAAA,EAC/C;AAAA;AAAA,EAGA,oBAAA,CAAqB,MAAA,EAAiB,QAAA,EAAqB,OAAA,EAAiC;AAC1F,IAAA,OACE,QAAA,CAAS,KAAK,CAAC,OAAA,KAAY,YAAY,MAAA,IAAU,OAAA,CAAQ,SAAS,MAAM,CAAC,KACzE,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,KAAW,UAAU,MAAA,CAAO,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,EAEzE;AAAA;AAAA,EAGA,mBAAmB,IAAA,EAAgC;AACjD,IAAA,OAAO,KAAK,cAAA,CAAe,IAAA,CAAK,CAAC,OAAA,KAAY,OAAA,CAAQ,SAAS,IAAI,CAAA;AAAA,EACpE;AACF","file":"conditional_fields_controller.js","sourcesContent":["/**\n * Whether a disabled `<fieldset>` ancestor actually reaches `control`.\n *\n * HTML exempts the contents of a fieldset's **first direct-child `<legend>`**, and\n * the exemption is per fieldset — a control legal in one legend can still be\n * disabled by a second, outer fieldset, so the walk continues upward.\n *\n * Exported on its own for callers that need the disabled-inheritance rule without\n * the rest of {@link canTakeFocus} — a control's availability check, or a `hidden`\n * walk bounded at a widget root, which is a different rule to compose with.\n */\nexport function inheritsFieldsetDisabled(control: HTMLElement): boolean {\n let fieldset: Element | null = control.closest(\"fieldset[disabled]\");\n while (fieldset) {\n const legend = Array.from(fieldset.children).find((child) => child.tagName === \"LEGEND\");\n if (!legend?.contains(control)) return true;\n fieldset = fieldset.parentElement?.closest(\"fieldset[disabled]\") ?? null;\n }\n return false;\n}\n\n/**\n * Whether an element can actually take focus, checked **before** `focus()` runs.\n *\n * A controller that must move focus off a control it is about to disable or hide\n * picks a destination and calls `focus()` on it. If that destination cannot take\n * focus, the call **fails silently**: `hidden` and natively `disabled` elements\n * swallow it, so the caret stays in the subtree that is disappearing and lands on\n * `<body>` a frame later — the exact outcome the rescue exists to prevent, minus\n * any signal that it happened.\n *\n * Testing after the fact is the obvious alternative and is deliberately not the\n * rule. Reading `document.activeElement` back only works in a real browser, and\n * looping over candidates that way performs a real focus move per failure —\n * observable to assistive technology. Checking first costs nothing and catches\n * the cases that actually occur.\n *\n * **`aria-disabled` is not disqualifying.** It is the attribute an author uses\n * for a control that must stay *discoverable*, and the roving contract keeps\n * such items reachable. Only the four conditions that make the platform refuse\n * focus are checked: `hidden` / `inert` (an ancestor's counts),\n * `input[type=\"hidden\"]`, the native `disabled` property, and `disabled`\n * inherited from an ancestor `fieldset`. CSS-only invisibility is handled by\n * {@link isRenderedForFocus} when a consumer needs sequential-focus semantics.\n *\n * Reading `:disabled` instead of walking the fieldset chain would be shorter, but\n * that pseudo-class is not evaluated consistently outside real browsers and this\n * has to be right headlessly too. happy-dom in particular focuses a `<button>`\n * inside a disabled fieldset where a real engine refuses, so the inheritance is\n * spelled out rather than delegated.\n *\n * What a consumer does when nothing survives is its own call: some fall back to\n * their landmark, while a widget whose caret already sits somewhere legitimate\n * refuses the move outright rather than relocating it.\n *\n * @example\n * ```ts\n * const target = candidates.find(canTakeFocus);\n * if (target) target.focus();\n * else {\n * this.#tabindex.lend(this.element); // nothing left: fall back to the landmark\n * this.element.focus();\n * }\n * ```\n *\n * @param element - the candidate destination\n */\nexport function canTakeFocus(element: HTMLElement): boolean {\n if (element.closest(\"[hidden], [inert]\")) return false;\n if (element instanceof HTMLInputElement && element.type === \"hidden\") return false;\n if (!(\"disabled\" in element)) return true;\n if ((element as HTMLElement & { disabled: boolean }).disabled) return false;\n return !inheritsFieldsetDisabled(element);\n}\n\n/** Elements whose semantics or authored attributes can place them in sequential focus order. */\nexport const TAB_STOP_CANDIDATE_SELECTOR = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"input\",\n \"select\",\n \"textarea\",\n \"summary\",\n \"iframe\",\n \"audio[controls]\",\n \"video[controls]\",\n \"[tabindex]\",\n \"[contenteditable]\",\n].join(\",\");\n\n/** Optional browser visibility API used to exclude CSS-hidden candidates. */\ninterface VisibilityCheckable {\n checkVisibility?: (options?: { visibilityProperty?: boolean }) => boolean;\n}\n\n/** Whether CSS visibility allows an otherwise eligible element to participate in focus order. */\nexport function isRenderedForFocus(element: HTMLElement): boolean {\n const check = (element as HTMLElement & VisibilityCheckable).checkVisibility;\n return typeof check === \"function\" ? check.call(element, { visibilityProperty: true }) : true;\n}\n\n/** Parses an authored `tabindex`; invalid syntax has no explicit focus-order meaning. */\nfunction authoredTabindex(element: HTMLElement): number | null {\n const value = element.getAttribute(\"tabindex\");\n if (value === null || !/^[+-]?\\d+$/.test(value.trim())) return null;\n return Number(value);\n}\n\n/** Whether the element's native semantics place it in sequential focus order. */\nfunction hasNativeTabStop(element: HTMLElement): boolean {\n if (element instanceof HTMLAnchorElement || element instanceof HTMLAreaElement) {\n return element.hasAttribute(\"href\");\n }\n if (\n element instanceof HTMLButtonElement ||\n element instanceof HTMLSelectElement ||\n element instanceof HTMLTextAreaElement\n ) {\n return true;\n }\n if (element instanceof HTMLInputElement) return element.type !== \"hidden\";\n if (element instanceof HTMLIFrameElement) return true;\n if (element.tagName === \"AUDIO\" || element.tagName === \"VIDEO\") {\n return element.hasAttribute(\"controls\");\n }\n if (element instanceof HTMLElement && element.tagName === \"SUMMARY\") {\n const details = element.parentElement;\n return (\n details instanceof HTMLDetailsElement &&\n Array.from(details.children).find((child) => child.tagName === \"SUMMARY\") === element\n );\n }\n return false;\n}\n\n/** Whether an explicit `contenteditable` value creates an editable tab stop. */\nfunction hasEditableTabStop(element: HTMLElement): boolean {\n const value = element.getAttribute(\"contenteditable\")?.toLowerCase();\n return value === \"\" || value === \"true\" || value === \"plaintext-only\";\n}\n\n/**\n * Whether an element is a usable sequential Tab stop right now.\n *\n * Native semantics, authored `tabindex`, editable hosts, inherited disabled state,\n * HTML `hidden`/`inert`, and CSS visibility are evaluated together. `aria-disabled`\n * remains focusable because it communicates unavailability without removing the\n * control from discovery order.\n */\nexport function isTabStop(element: HTMLElement): boolean {\n if (!canTakeFocus(element) || !isRenderedForFocus(element)) return false;\n\n const tabindex = authoredTabindex(element);\n if (tabindex !== null) return tabindex >= 0;\n return hasNativeTabStop(element) || hasEditableTabStop(element);\n}\n\n/** Returns every usable sequential Tab stop below `root` in document order. */\nexport function tabStopsWithin(root: ParentNode): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(TAB_STOP_CANDIDATE_SELECTOR)).filter(\n isTabStop,\n );\n}\n\n/** Returns the first usable sequential Tab stop below `root`, if one exists. */\nexport function firstTabStop(root: ParentNode): HTMLElement | null {\n for (const candidate of root.querySelectorAll<HTMLElement>(TAB_STOP_CANDIDATE_SELECTOR)) {\n if (isTabStop(candidate)) return candidate;\n }\n return null;\n}\n\n/** Whether `root` contains at least one usable sequential Tab stop. */\nexport function hasTabStop(root: ParentNode): boolean {\n return firstTabStop(root) !== null;\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 * 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","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 { canTakeFocus } from \"../utils/focus_candidate\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { TabindexLoan } from \"../utils/tabindex_loan\";\n\n/** Trigger controls whose live state drives region visibility. */\ntype Trigger = HTMLInputElement | HTMLSelectElement;\n/** Form controls inside a region that can be excluded from submission. */\ntype Disableable = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | HTMLButtonElement;\n/** One logical visibility transition settled during an evaluation pass. */\ntype RegionTransition = { region: HTMLElement; visible: boolean };\n\n/** Marker on controls this component disabled, so authored disabled state remains untouched. */\nconst DISABLED_MARKER = \"data-conditional-disabled\";\n\n/** Retained-DOM inputs and controller outputs that can require reconciliation. */\nconst OBSERVED_ATTRIBUTES = [\n \"hidden\",\n \"aria-hidden\",\n \"data-visible\",\n DISABLED_MARKER,\n \"disabled\",\n \"data-when-checked\",\n \"data-when-unchecked\",\n \"data-when-value\",\n \"checked\",\n \"selected\",\n \"value\",\n \"type\",\n];\n\n/** Attribute value expected after one controller-owned DOM write. */\ntype ExpectedAttribute = string | null;\n\n/**\n * Headless dependent-fields behavior: shows/hides (and enables/disables) regions\n * from trigger control values while keeping submission and accessibility state in\n * sync (no dedicated APG pattern).\n *\n * Markup contract (identifier: `stimeo--conditional-fields`):\n * <form data-controller=\"stimeo--conditional-fields\">\n * <input type=\"checkbox\" data-stimeo--conditional-fields-target=\"trigger\">\n * <fieldset data-stimeo--conditional-fields-target=\"region\" data-when-checked>\n * …address…\n * </fieldset>\n * </form>\n *\n * A region declares one condition: `data-when-checked`, `data-when-unchecked`,\n * or `data-when-value=\"x\"`. The condition is combined across all triggers using\n * `match` (`\"any\"` by default, or `\"all\"`). A region with no condition preserves\n * its authored `hidden` state; a declared condition with no triggers is false.\n *\n * Hidden regions receive `hidden` and `aria-hidden=\"true\"`; visible regions expose\n * `data-visible=\"true\"`. With `disableHidden`, descendant controls are disabled and\n * marked with `data-conditional-disabled=\"true\"`, and only marked controls are\n * re-enabled. Before a focused region is hidden, focus moves to the first trigger\n * that can actually receive it. If every trigger is unsafe — including one inside\n * another region being hidden in the same pass — the controller root temporarily\n * receives `tabindex=\"-1\"` and focus.\n *\n * `change` and `reconcile` dispatch `{ region, visible }`.\n *\n * @remarks\n * Behavior only. Trigger `input` / `change`, dynamic targets and descendants,\n * condition attributes, Values, native form reset, and Turbo retained-element\n * morphs all reconcile against the live DOM. Direct writes to an input's live\n * `checked` / `value` property remain observable only when the caller also emits\n * the corresponding native event. DOM repair is silent. User input or the public\n * action dispatches `stimeo--conditional-fields:change`; a lifecycle, Value,\n * reset, mutation, or morph reconciliation dispatches\n * `stimeo--conditional-fields:reconcile` instead. Initial connection is silent.\n * Every listener, observer, queued pass, and borrowed root `tabindex` is released\n * on `disconnect()`.\n */\nexport class ConditionalFieldsController extends Controller<HTMLElement> {\n static override targets = [\"trigger\", \"region\"];\n static override values = {\n disableHidden: { type: Boolean, default: true },\n match: { type: String, default: \"any\" },\n };\n static actions = [\"evaluate\"] as const;\n static events = [\"change\", \"reconcile\"] as const;\n\n declare readonly triggerTargets: Trigger[];\n declare readonly regionTargets: HTMLElement[];\n\n declare disableHiddenValue: boolean;\n declare matchValue: string;\n\n /** Logical state last committed for each current region; rebuilt on every connect. */\n #lastVisible = new WeakMap<HTMLElement, boolean>();\n /** Controller writes awaiting an observer callback, separated from authored morphs. */\n #internalWrites = new WeakMap<Element, Map<string, ExpectedAttribute>>();\n #observing = false;\n\n /** Coalesces one target/morph/mutation batch into one full DOM reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileDom());\n /** Provides the last-resort focus landmark without claiming an authored tabindex. */\n readonly #rootTabindex = new TabindexLoan<HTMLElement>();\n /** Watches retained targets and controls whose declarative or reflected state changed. */\n readonly #observer = new MutationObserver((records) => this.#onMutations(records));\n\n /** Evaluates only events whose source is one of this instance's live trigger targets. */\n readonly #onTriggerInput = (event: Event): void => {\n const target = event.target;\n const triggers = this.triggerTargets;\n if (target instanceof Element && triggers.some((trigger) => trigger === target)) {\n this.#commitChange(triggers);\n }\n };\n\n /** Reconciles property-only retained-element changes after Turbo morphs. */\n readonly #onMorph = (): void => {\n this.#reconcile.schedule();\n };\n\n /** Reconciles the settled defaults after a non-cancelled owning form reset. */\n readonly #onReset = (event: Event): void => {\n const form = event.target;\n if (form instanceof HTMLFormElement && this.#hasTriggerOwnedBy(form)) {\n queueMicrotask(() => {\n if (!event.defaultPrevented) this.#reconcile.schedule();\n });\n }\n };\n\n /** Reflects initial live state and opens every retained-DOM reconciliation path. */\n override connect(): void {\n this.#lastVisible = new WeakMap();\n this.#internalWrites = new WeakMap();\n this.#reconcile.activate();\n this.#settle();\n this.#observer.observe(this.element, {\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n childList: true,\n subtree: true,\n });\n this.#observing = true;\n this.element.addEventListener(\"change\", this.#onTriggerInput);\n this.element.addEventListener(\"input\", this.#onTriggerInput);\n this.element.addEventListener(\"turbo:morph-element\", this.#onMorph);\n document.addEventListener(\"reset\", this.#onReset, true);\n }\n\n /** Releases all external resources and returns the temporary focus landmark loan. */\n override disconnect(): void {\n this.#reconcile.cancel();\n this.#observing = false;\n this.#observer.disconnect();\n this.element.removeEventListener(\"change\", this.#onTriggerInput);\n this.element.removeEventListener(\"input\", this.#onTriggerInput);\n this.element.removeEventListener(\"turbo:morph-element\", this.#onMorph);\n document.removeEventListener(\"reset\", this.#onReset, true);\n this.#rootTabindex.returnAll();\n }\n\n /** Reconciles after a trigger target is inserted or restored. */\n triggerTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles after a trigger target is removed or replaced. */\n triggerTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Initializes a region target inserted or restored at runtime. */\n regionTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles the remaining region set after a target leaves. */\n regionTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles when application code or a morph changes the match policy. */\n matchValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles control ownership when hidden controls become enabled or excluded. */\n disableHiddenValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-evaluates every region and repairs all reflected DOM state. */\n evaluate(): void {\n this.#commitChange();\n }\n\n /**\n * Computes one settled plan, shows destinations before hiding sources, and then\n * returns logical transitions in DOM order after every region is internally coherent.\n */\n #settle(triggers: Trigger[] = this.triggerTargets): RegionTransition[] {\n const regions = this.regionTargets;\n const plan = new Map<HTMLElement, boolean>();\n for (const region of regions) plan.set(region, this.#isVisible(region, triggers));\n\n const changed = new Set<HTMLElement>();\n const applicationOrder = [\n ...regions.filter((region) => plan.get(region) === true),\n ...regions.filter((region) => plan.get(region) === false),\n ];\n for (const region of applicationOrder) {\n const visible = plan.get(region);\n if (visible !== undefined && this.#applyRegion(region, visible, plan)) {\n changed.add(region);\n }\n }\n\n return regions\n .filter((region) => changed.has(region))\n .map((region) => ({ region, visible: plan.get(region) === true }));\n }\n\n /** Reports logical transitions caused by user input or the public action. */\n #commitChange(triggers: Trigger[] = this.triggerTargets): void {\n for (const detail of this.#settle(triggers)) {\n this.dispatch(\"change\", { detail });\n }\n }\n\n /** Reports logical transitions derived from DOM, lifecycle, reset, or Value state. */\n #reconcileDom(): void {\n for (const detail of this.#settle()) {\n this.dispatch(\"reconcile\", { detail });\n }\n }\n\n /** Applies one planned state while keeping event history separate from DOM repair. */\n #applyRegion(\n region: HTMLElement,\n visible: boolean,\n plan: ReadonlyMap<HTMLElement, boolean>,\n ): boolean {\n const previous = this.#lastVisible.get(region) ?? !region.hidden;\n const changed = visible !== previous;\n this.#lastVisible.set(region, visible);\n\n if (!visible) this.#retreatFocus(region, plan);\n this.#syncRegionState(region, visible);\n this.#syncRegionControls(region, visible);\n return changed;\n }\n\n /** Reflects visibility idempotently, recording writes so the observer ignores its own work. */\n #syncRegionState(region: HTMLElement, visible: boolean): void {\n this.#writeAttribute(region, \"hidden\", visible ? null : \"\");\n this.#writeAttribute(region, \"aria-hidden\", visible ? null : \"true\");\n this.#writeAttribute(region, \"data-visible\", visible ? \"true\" : null);\n }\n\n /** Enables/disables descendant controls, touching only state carrying our marker. */\n #syncRegionControls(region: HTMLElement, visible: boolean): void {\n const shouldDisable = !visible && this.disableHiddenValue;\n const controls = region.querySelectorAll<Disableable>(\"input, textarea, select, button\");\n for (const control of controls) {\n const marked = control.hasAttribute(DISABLED_MARKER);\n if (shouldDisable) {\n if (!control.disabled) {\n this.#writeAttribute(control, \"disabled\", \"\");\n this.#writeAttribute(control, DISABLED_MARKER, \"true\");\n } else if (marked && control.getAttribute(DISABLED_MARKER) !== \"true\") {\n this.#writeAttribute(control, DISABLED_MARKER, \"true\");\n }\n } else if (marked) {\n this.#writeAttribute(control, \"disabled\", null);\n this.#writeAttribute(control, DISABLED_MARKER, null);\n }\n }\n }\n\n /** Whether a region's declared condition holds across `triggers` per `match`. */\n #isVisible(region: HTMLElement, triggers: Trigger[]): boolean {\n const predicate = this.#predicateFor(region);\n if (predicate === null) return !region.hidden;\n return (\n triggers.length > 0 &&\n (this.matchValue === \"all\" ? triggers.every(predicate) : triggers.some(predicate))\n );\n }\n\n /** Builds the deterministic per-trigger predicate from the region's condition. */\n #predicateFor(region: HTMLElement): ((trigger: Trigger) => boolean) | null {\n if (region.hasAttribute(\"data-when-checked\")) {\n return (trigger) => this.#isChecked(trigger);\n }\n if (region.hasAttribute(\"data-when-unchecked\")) {\n return (trigger) => !this.#isChecked(trigger);\n }\n const wanted = region.dataset.whenValue;\n if (wanted !== undefined) {\n return (trigger) => this.#matchesValue(trigger, wanted);\n }\n return null;\n }\n\n #isChecked(trigger: Trigger): boolean {\n return trigger instanceof HTMLInputElement && trigger.checked;\n }\n\n /** A trigger has a value when a radio/checkbox is selected, or its control value matches. */\n #matchesValue(trigger: Trigger, wanted: string): boolean {\n if (\n trigger instanceof HTMLInputElement &&\n (trigger.type === \"checkbox\" || trigger.type === \"radio\")\n ) {\n return trigger.checked && trigger.value === wanted;\n }\n return trigger.value === wanted;\n }\n\n /** Moves focus to the first safe trigger, or to the controller landmark as a fallback. */\n #retreatFocus(region: HTMLElement, plan: ReadonlyMap<HTMLElement, boolean>): void {\n const active = document.activeElement;\n if (active && region.contains(active)) this.#moveFocus(plan);\n }\n\n /** Moves focus after the caller establishes that the active node is being hidden. */\n #moveFocus(plan: ReadonlyMap<HTMLElement, boolean>): void {\n const destination = this.triggerTargets.find(\n (trigger) => canTakeFocus(trigger) && this.#survivesPlan(trigger, plan),\n );\n if (destination) {\n this.#rootTabindex.returnAll();\n destination.focus();\n return;\n }\n\n this.#rootTabindex.lend(this.element);\n this.element.focus();\n }\n\n /** Whether a focus candidate sits outside every region this pass will hide. */\n #survivesPlan(candidate: HTMLElement, plan: ReadonlyMap<HTMLElement, boolean>): boolean {\n return [...plan].every(([region, visible]) => visible || !region.contains(candidate));\n }\n\n /** Records one idempotent attribute write before MutationObserver sees it. */\n #writeAttribute(element: Element, name: string, value: ExpectedAttribute): void {\n if (element.getAttribute(name) !== value) {\n if (this.#observing) {\n let writes = this.#internalWrites.get(element);\n if (!writes) {\n writes = new Map();\n this.#internalWrites.set(element, writes);\n }\n writes.set(name, value);\n }\n if (value === null) element.removeAttribute(name);\n else element.setAttribute(name, value);\n }\n }\n\n /** Separates authored records from controller writes and queues one relevant repair. */\n #onMutations(records: MutationRecord[]): void {\n const triggers = this.triggerTargets;\n const regions = this.regionTargets;\n const touchedWrites = new Map<Element, Set<string>>();\n let needsReconcile = false;\n\n for (const record of records) {\n if (record.type === \"attributes\" && record.target instanceof Element) {\n const name = record.attributeName;\n const writes = this.#internalWrites.get(record.target);\n if (name && writes?.has(name)) {\n let names = touchedWrites.get(record.target);\n if (!names) {\n names = new Set();\n touchedWrites.set(record.target, names);\n }\n names.add(name);\n if (record.target.getAttribute(name) === writes.get(name)) continue;\n }\n }\n if (\n record.target instanceof Element &&\n this.#elementAffectsState(record.target, triggers, regions)\n ) {\n needsReconcile = true;\n }\n }\n\n for (const [element, names] of touchedWrites) {\n const writes = this.#internalWrites.get(element);\n for (const name of names) writes?.delete(name);\n }\n if (needsReconcile) this.#reconcile.schedule();\n }\n\n /** Whether an authored mutation target belongs to a trigger, region, or managed control. */\n #elementAffectsState(target: Element, triggers: Trigger[], regions: HTMLElement[]): boolean {\n return (\n triggers.some((trigger) => trigger === target || trigger.contains(target)) ||\n regions.some((region) => region === target || region.contains(target))\n );\n }\n\n /** Whether a form owns at least one current trigger, including `form=` associations. */\n #hasTriggerOwnedBy(form: HTMLFormElement): boolean {\n return this.triggerTargets.some((trigger) => trigger.form === form);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/event_owner.ts","../../src/utils/focus_candidate.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/before_cache_reset.ts","../../src/utils/tabindex_loan.ts","../../src/controllers/conditional_fields_controller.ts"],"names":[],"mappings":"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","file":"conditional_fields_controller.js","sourcesContent":["/**\n * Resolves which of a controller's elements owns a node.\n *\n * A delegated listener hears events from a whole subtree, so the handler's first\n * job is almost always the same question: which item, handle, or control does\n * this `event.target` belong to? The same question comes up for a\n * `MutationRecord.target`, for `document.activeElement`, and for a\n * `relatedTarget` on the way out of a hover region.\n *\n * The answer is `Node.contains()`, which is **inclusive** — an element contains\n * itself — so testing the candidate for identity as well would be redundant.\n *\n * **The guard is what makes this safe to call with a raw event target.**\n * `event.target` is typed `EventTarget | null`, and `contains()` takes a `Node?`:\n * browsers throw `TypeError` for anything else, and `window` — the everyday\n * `EventTarget` that is not a `Node` — is what an event dispatched at it carries.\n * Narrowing here means a caller never has to cast, and the rule cannot drift\n * between the places that ask the question.\n *\n * Scope stays with the caller. These helpers say *which candidate owns the node*,\n * not *whether the node belongs to this controller at all* — a component with\n * nested instances of itself decides that first (by comparing the closest\n * annotated ancestor) and passes the candidates it owns.\n */\n\n/**\n * Index in `candidates` of the first one that is, or contains, `node`.\n *\n * `-1` when none does, when `node` is absent, and when it is an `EventTarget`\n * that is not a `Node`. Candidates are tested in array order, so a nested pair\n * resolves to whichever the caller listed first.\n */\nexport function ownerIndex<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): number {\n if (!(node instanceof Node)) return -1;\n return candidates.findIndex((candidate) => candidate.contains(node));\n}\n\n/**\n * The first candidate that is, or contains, `node`; `null` when none does.\n *\n * A miss indexes the array at `-1`, which reads as `undefined` and lands on the\n * same `null` the absent cases produce.\n */\nexport function ownerOf<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): T | null {\n return candidates[ownerIndex(candidates, node)] ?? null;\n}\n","/**\n * Whether a disabled `<fieldset>` ancestor actually reaches `control`.\n *\n * HTML exempts the contents of a fieldset's **first direct-child `<legend>`**, and\n * the exemption is per fieldset — a control legal in one legend can still be\n * disabled by a second, outer fieldset, so the walk continues upward.\n *\n * Exported on its own for callers that need the disabled-inheritance rule without\n * the rest of {@link canTakeFocus} — a control's availability check, or a `hidden`\n * walk bounded at a widget root, which is a different rule to compose with.\n */\nexport function inheritsFieldsetDisabled(control: HTMLElement): boolean {\n let fieldset: Element | null = control.closest(\"fieldset[disabled]\");\n while (fieldset) {\n const legend = Array.from(fieldset.children).find((child) => child.tagName === \"LEGEND\");\n if (!legend?.contains(control)) return true;\n fieldset = fieldset.parentElement?.closest(\"fieldset[disabled]\") ?? null;\n }\n return false;\n}\n\n/**\n * Whether an element can actually take focus, checked **before** `focus()` runs.\n *\n * A controller that must move focus off a control it is about to disable or hide\n * picks a destination and calls `focus()` on it. If that destination cannot take\n * focus, the call **fails silently**: `hidden` and natively `disabled` elements\n * swallow it, so the caret stays in the subtree that is disappearing and lands on\n * `<body>` a frame later — the exact outcome the rescue exists to prevent, minus\n * any signal that it happened.\n *\n * Testing after the fact is the obvious alternative and is deliberately not the\n * rule. Reading `document.activeElement` back only works in a real browser, and\n * looping over candidates that way performs a real focus move per failure —\n * observable to assistive technology. Checking first costs nothing and catches\n * the cases that actually occur.\n *\n * **`aria-disabled` is not disqualifying.** It is the attribute an author uses\n * for a control that must stay *discoverable*, and the roving contract keeps\n * such items reachable. Only the four conditions that make the platform refuse\n * focus are checked: `hidden` / `inert` (an ancestor's counts),\n * `input[type=\"hidden\"]`, the native `disabled` property, and `disabled`\n * inherited from an ancestor `fieldset`. CSS-only invisibility is handled by\n * {@link isRenderedForFocus} when a consumer needs sequential-focus semantics.\n *\n * Reading `:disabled` instead of walking the fieldset chain would be shorter, but\n * that pseudo-class is not evaluated consistently outside real browsers and this\n * has to be right headlessly too. happy-dom in particular focuses a `<button>`\n * inside a disabled fieldset where a real engine refuses, so the inheritance is\n * spelled out rather than delegated.\n *\n * What a consumer does when nothing survives is its own call: some fall back to\n * their landmark, while a widget whose caret already sits somewhere legitimate\n * refuses the move outright rather than relocating it.\n *\n * @example\n * ```ts\n * const target = candidates.find(canTakeFocus);\n * if (target) target.focus();\n * else {\n * this.#tabindex.lend(this.element); // nothing left: fall back to the landmark\n * this.element.focus();\n * }\n * ```\n *\n * @param element - the candidate destination\n */\nexport function canTakeFocus(element: HTMLElement): boolean {\n if (element.closest(\"[hidden], [inert]\")) return false;\n if (element instanceof HTMLInputElement && element.type === \"hidden\") return false;\n if (!(\"disabled\" in element)) return true;\n if ((element as HTMLElement & { disabled: boolean }).disabled) return false;\n return !inheritsFieldsetDisabled(element);\n}\n\n/** Elements whose semantics or authored attributes can place them in sequential focus order. */\nexport const TAB_STOP_CANDIDATE_SELECTOR = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"input\",\n \"select\",\n \"textarea\",\n \"summary\",\n \"iframe\",\n \"audio[controls]\",\n \"video[controls]\",\n \"[tabindex]\",\n \"[contenteditable]\",\n].join(\",\");\n\n/** Optional browser visibility API used to exclude CSS-hidden candidates. */\ninterface VisibilityCheckable {\n checkVisibility?: (options?: { visibilityProperty?: boolean }) => boolean;\n}\n\n/** Whether CSS visibility allows an otherwise eligible element to participate in focus order. */\nexport function isRenderedForFocus(element: HTMLElement): boolean {\n const check = (element as HTMLElement & VisibilityCheckable).checkVisibility;\n return typeof check === \"function\" ? check.call(element, { visibilityProperty: true }) : true;\n}\n\n/** Parses an authored `tabindex`; invalid syntax has no explicit focus-order meaning. */\nfunction authoredTabindex(element: HTMLElement): number | null {\n const value = element.getAttribute(\"tabindex\");\n if (value === null || !/^[+-]?\\d+$/.test(value.trim())) return null;\n return Number(value);\n}\n\n/** Whether the element's native semantics place it in sequential focus order. */\nfunction hasNativeTabStop(element: HTMLElement): boolean {\n if (element instanceof HTMLAnchorElement || element instanceof HTMLAreaElement) {\n return element.hasAttribute(\"href\");\n }\n if (\n element instanceof HTMLButtonElement ||\n element instanceof HTMLSelectElement ||\n element instanceof HTMLTextAreaElement\n ) {\n return true;\n }\n if (element instanceof HTMLInputElement) return element.type !== \"hidden\";\n if (element instanceof HTMLIFrameElement) return true;\n if (element.tagName === \"AUDIO\" || element.tagName === \"VIDEO\") {\n return element.hasAttribute(\"controls\");\n }\n if (element instanceof HTMLElement && element.tagName === \"SUMMARY\") {\n const details = element.parentElement;\n return (\n details instanceof HTMLDetailsElement &&\n Array.from(details.children).find((child) => child.tagName === \"SUMMARY\") === element\n );\n }\n return false;\n}\n\n/** Whether an explicit `contenteditable` value creates an editable tab stop. */\nfunction hasEditableTabStop(element: HTMLElement): boolean {\n const value = element.getAttribute(\"contenteditable\")?.toLowerCase();\n return value === \"\" || value === \"true\" || value === \"plaintext-only\";\n}\n\n/**\n * Whether an element is a usable sequential Tab stop right now.\n *\n * Native semantics, authored `tabindex`, editable hosts, inherited disabled state,\n * HTML `hidden`/`inert`, and CSS visibility are evaluated together. `aria-disabled`\n * remains focusable because it communicates unavailability without removing the\n * control from discovery order.\n */\nexport function isTabStop(element: HTMLElement): boolean {\n if (!canTakeFocus(element) || !isRenderedForFocus(element)) return false;\n\n const tabindex = authoredTabindex(element);\n if (tabindex !== null) return tabindex >= 0;\n return hasNativeTabStop(element) || hasEditableTabStop(element);\n}\n\n/** Returns every usable sequential Tab stop below `root` in document order. */\nexport function tabStopsWithin(root: ParentNode): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(TAB_STOP_CANDIDATE_SELECTOR)).filter(\n isTabStop,\n );\n}\n\n/** Returns the first usable sequential Tab stop below `root`, if one exists. */\nexport function firstTabStop(root: ParentNode): HTMLElement | null {\n for (const candidate of root.querySelectorAll<HTMLElement>(TAB_STOP_CANDIDATE_SELECTOR)) {\n if (isTabStop(candidate)) return candidate;\n }\n return null;\n}\n\n/** Whether `root` contains at least one usable sequential Tab stop. */\nexport function hasTabStop(root: ParentNode): boolean {\n return firstTabStop(root) !== null;\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 * 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","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 { ownerIndex } from \"../utils/event_owner\";\nimport { canTakeFocus } from \"../utils/focus_candidate\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { TabindexLoan } from \"../utils/tabindex_loan\";\n\n/** Trigger controls whose live state drives region visibility. */\ntype Trigger = HTMLInputElement | HTMLSelectElement;\n/** Form controls inside a region that can be excluded from submission. */\ntype Disableable = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | HTMLButtonElement;\n/** One logical visibility transition settled during an evaluation pass. */\ntype RegionTransition = { region: HTMLElement; visible: boolean };\n\n/** Marker on controls this component disabled, so authored disabled state remains untouched. */\nconst DISABLED_MARKER = \"data-conditional-disabled\";\n\n/** Retained-DOM inputs and controller outputs that can require reconciliation. */\nconst OBSERVED_ATTRIBUTES = [\n \"hidden\",\n \"aria-hidden\",\n \"data-visible\",\n DISABLED_MARKER,\n \"disabled\",\n \"data-when-checked\",\n \"data-when-unchecked\",\n \"data-when-value\",\n \"checked\",\n \"selected\",\n \"value\",\n \"type\",\n];\n\n/** Attribute value expected after one controller-owned DOM write. */\ntype ExpectedAttribute = string | null;\n\n/**\n * Headless dependent-fields behavior: shows/hides (and enables/disables) regions\n * from trigger control values while keeping submission and accessibility state in\n * sync (no dedicated APG pattern).\n *\n * Markup contract (identifier: `stimeo--conditional-fields`):\n * <form data-controller=\"stimeo--conditional-fields\">\n * <input type=\"checkbox\" data-stimeo--conditional-fields-target=\"trigger\">\n * <fieldset data-stimeo--conditional-fields-target=\"region\" data-when-checked>\n * …address…\n * </fieldset>\n * </form>\n *\n * A region declares one condition: `data-when-checked`, `data-when-unchecked`,\n * or `data-when-value=\"x\"`. The condition is combined across all triggers using\n * `match` (`\"any\"` by default, or `\"all\"`). A region with no condition preserves\n * its authored `hidden` state; a declared condition with no triggers is false.\n *\n * Hidden regions receive `hidden` and `aria-hidden=\"true\"`; visible regions expose\n * `data-visible=\"true\"`. With `disableHidden`, descendant controls are disabled and\n * marked with `data-conditional-disabled=\"true\"`, and only marked controls are\n * re-enabled. Before a focused region is hidden, focus moves to the first trigger\n * that can actually receive it. If every trigger is unsafe — including one inside\n * another region being hidden in the same pass — the controller root temporarily\n * receives `tabindex=\"-1\"` and focus.\n *\n * `change` and `reconcile` dispatch `{ region, visible }`.\n *\n * @remarks\n * Behavior only. Trigger `input` / `change`, dynamic targets and descendants,\n * condition attributes, Values, native form reset, and Turbo retained-element\n * morphs all reconcile against the live DOM. Direct writes to an input's live\n * `checked` / `value` property remain observable only when the caller also emits\n * the corresponding native event. DOM repair is silent. User input or the public\n * action dispatches `stimeo--conditional-fields:change`; a lifecycle, Value,\n * reset, mutation, or morph reconciliation dispatches\n * `stimeo--conditional-fields:reconcile` instead. Initial connection is silent.\n * Every listener, observer, queued pass, and borrowed root `tabindex` is released\n * on `disconnect()`.\n */\nexport class ConditionalFieldsController extends Controller<HTMLElement> {\n static override targets = [\"trigger\", \"region\"];\n static override values = {\n disableHidden: { type: Boolean, default: true },\n match: { type: String, default: \"any\" },\n };\n static actions = [\"evaluate\"] as const;\n static events = [\"change\", \"reconcile\"] as const;\n\n declare readonly triggerTargets: Trigger[];\n declare readonly regionTargets: HTMLElement[];\n\n declare disableHiddenValue: boolean;\n declare matchValue: string;\n\n /** Logical state last committed for each current region; rebuilt on every connect. */\n #lastVisible = new WeakMap<HTMLElement, boolean>();\n /** Controller writes awaiting an observer callback, separated from authored morphs. */\n #internalWrites = new WeakMap<Element, Map<string, ExpectedAttribute>>();\n #observing = false;\n\n /** Coalesces one target/morph/mutation batch into one full DOM reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileDom());\n /** Provides the last-resort focus landmark without claiming an authored tabindex. */\n readonly #rootTabindex = new TabindexLoan<HTMLElement>();\n /** Watches retained targets and controls whose declarative or reflected state changed. */\n readonly #observer = new MutationObserver((records) => this.#onMutations(records));\n\n /** Evaluates only events whose source is one of this instance's live trigger targets. */\n readonly #onTriggerInput = (event: Event): void => {\n const target = event.target;\n const triggers = this.triggerTargets;\n if (target instanceof Element && triggers.some((trigger) => trigger === target)) {\n this.#commitChange(triggers);\n }\n };\n\n /** Reconciles property-only retained-element changes after Turbo morphs. */\n readonly #onMorph = (): void => {\n this.#reconcile.schedule();\n };\n\n /** Reconciles the settled defaults after a non-cancelled owning form reset. */\n readonly #onReset = (event: Event): void => {\n const form = event.target;\n if (form instanceof HTMLFormElement && this.#hasTriggerOwnedBy(form)) {\n queueMicrotask(() => {\n if (!event.defaultPrevented) this.#reconcile.schedule();\n });\n }\n };\n\n /** Reflects initial live state and opens every retained-DOM reconciliation path. */\n override connect(): void {\n this.#lastVisible = new WeakMap();\n this.#internalWrites = new WeakMap();\n this.#reconcile.activate();\n this.#settle();\n this.#observer.observe(this.element, {\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n childList: true,\n subtree: true,\n });\n this.#observing = true;\n this.element.addEventListener(\"change\", this.#onTriggerInput);\n this.element.addEventListener(\"input\", this.#onTriggerInput);\n this.element.addEventListener(\"turbo:morph-element\", this.#onMorph);\n document.addEventListener(\"reset\", this.#onReset, true);\n }\n\n /** Releases all external resources and returns the temporary focus landmark loan. */\n override disconnect(): void {\n this.#reconcile.cancel();\n this.#observing = false;\n this.#observer.disconnect();\n this.element.removeEventListener(\"change\", this.#onTriggerInput);\n this.element.removeEventListener(\"input\", this.#onTriggerInput);\n this.element.removeEventListener(\"turbo:morph-element\", this.#onMorph);\n document.removeEventListener(\"reset\", this.#onReset, true);\n this.#rootTabindex.returnAll();\n }\n\n /** Reconciles after a trigger target is inserted or restored. */\n triggerTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles after a trigger target is removed or replaced. */\n triggerTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Initializes a region target inserted or restored at runtime. */\n regionTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles the remaining region set after a target leaves. */\n regionTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles when application code or a morph changes the match policy. */\n matchValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles control ownership when hidden controls become enabled or excluded. */\n disableHiddenValueChanged(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-evaluates every region and repairs all reflected DOM state. */\n evaluate(): void {\n this.#commitChange();\n }\n\n /**\n * Computes one settled plan, shows destinations before hiding sources, and then\n * returns logical transitions in DOM order after every region is internally coherent.\n */\n #settle(triggers: Trigger[] = this.triggerTargets): RegionTransition[] {\n const regions = this.regionTargets;\n const plan = new Map<HTMLElement, boolean>();\n for (const region of regions) plan.set(region, this.#isVisible(region, triggers));\n\n const changed = new Set<HTMLElement>();\n const applicationOrder = [\n ...regions.filter((region) => plan.get(region) === true),\n ...regions.filter((region) => plan.get(region) === false),\n ];\n for (const region of applicationOrder) {\n const visible = plan.get(region);\n if (visible !== undefined && this.#applyRegion(region, visible, plan)) {\n changed.add(region);\n }\n }\n\n return regions\n .filter((region) => changed.has(region))\n .map((region) => ({ region, visible: plan.get(region) === true }));\n }\n\n /** Reports logical transitions caused by user input or the public action. */\n #commitChange(triggers: Trigger[] = this.triggerTargets): void {\n for (const detail of this.#settle(triggers)) {\n this.dispatch(\"change\", { detail });\n }\n }\n\n /** Reports logical transitions derived from DOM, lifecycle, reset, or Value state. */\n #reconcileDom(): void {\n for (const detail of this.#settle()) {\n this.dispatch(\"reconcile\", { detail });\n }\n }\n\n /** Applies one planned state while keeping event history separate from DOM repair. */\n #applyRegion(\n region: HTMLElement,\n visible: boolean,\n plan: ReadonlyMap<HTMLElement, boolean>,\n ): boolean {\n const previous = this.#lastVisible.get(region) ?? !region.hidden;\n const changed = visible !== previous;\n this.#lastVisible.set(region, visible);\n\n if (!visible) this.#retreatFocus(region, plan);\n this.#syncRegionState(region, visible);\n this.#syncRegionControls(region, visible);\n return changed;\n }\n\n /** Reflects visibility idempotently, recording writes so the observer ignores its own work. */\n #syncRegionState(region: HTMLElement, visible: boolean): void {\n this.#writeAttribute(region, \"hidden\", visible ? null : \"\");\n this.#writeAttribute(region, \"aria-hidden\", visible ? null : \"true\");\n this.#writeAttribute(region, \"data-visible\", visible ? \"true\" : null);\n }\n\n /** Enables/disables descendant controls, touching only state carrying our marker. */\n #syncRegionControls(region: HTMLElement, visible: boolean): void {\n const shouldDisable = !visible && this.disableHiddenValue;\n const controls = region.querySelectorAll<Disableable>(\"input, textarea, select, button\");\n for (const control of controls) {\n const marked = control.hasAttribute(DISABLED_MARKER);\n if (shouldDisable) {\n if (!control.disabled) {\n this.#writeAttribute(control, \"disabled\", \"\");\n this.#writeAttribute(control, DISABLED_MARKER, \"true\");\n } else if (marked && control.getAttribute(DISABLED_MARKER) !== \"true\") {\n this.#writeAttribute(control, DISABLED_MARKER, \"true\");\n }\n } else if (marked) {\n this.#writeAttribute(control, \"disabled\", null);\n this.#writeAttribute(control, DISABLED_MARKER, null);\n }\n }\n }\n\n /** Whether a region's declared condition holds across `triggers` per `match`. */\n #isVisible(region: HTMLElement, triggers: Trigger[]): boolean {\n const predicate = this.#predicateFor(region);\n if (predicate === null) return !region.hidden;\n return (\n triggers.length > 0 &&\n (this.matchValue === \"all\" ? triggers.every(predicate) : triggers.some(predicate))\n );\n }\n\n /** Builds the deterministic per-trigger predicate from the region's condition. */\n #predicateFor(region: HTMLElement): ((trigger: Trigger) => boolean) | null {\n if (region.hasAttribute(\"data-when-checked\")) {\n return (trigger) => this.#isChecked(trigger);\n }\n if (region.hasAttribute(\"data-when-unchecked\")) {\n return (trigger) => !this.#isChecked(trigger);\n }\n const wanted = region.dataset.whenValue;\n if (wanted !== undefined) {\n return (trigger) => this.#matchesValue(trigger, wanted);\n }\n return null;\n }\n\n #isChecked(trigger: Trigger): boolean {\n return trigger instanceof HTMLInputElement && trigger.checked;\n }\n\n /** A trigger has a value when a radio/checkbox is selected, or its control value matches. */\n #matchesValue(trigger: Trigger, wanted: string): boolean {\n if (\n trigger instanceof HTMLInputElement &&\n (trigger.type === \"checkbox\" || trigger.type === \"radio\")\n ) {\n return trigger.checked && trigger.value === wanted;\n }\n return trigger.value === wanted;\n }\n\n /** Moves focus to the first safe trigger, or to the controller landmark as a fallback. */\n #retreatFocus(region: HTMLElement, plan: ReadonlyMap<HTMLElement, boolean>): void {\n const active = document.activeElement;\n if (active && region.contains(active)) this.#moveFocus(plan);\n }\n\n /** Moves focus after the caller establishes that the active node is being hidden. */\n #moveFocus(plan: ReadonlyMap<HTMLElement, boolean>): void {\n const destination = this.triggerTargets.find(\n (trigger) => canTakeFocus(trigger) && this.#survivesPlan(trigger, plan),\n );\n if (destination) {\n this.#rootTabindex.returnAll();\n destination.focus();\n return;\n }\n\n this.#rootTabindex.lend(this.element);\n this.element.focus();\n }\n\n /** Whether a focus candidate sits outside every region this pass will hide. */\n #survivesPlan(candidate: HTMLElement, plan: ReadonlyMap<HTMLElement, boolean>): boolean {\n return [...plan].every(([region, visible]) => visible || !region.contains(candidate));\n }\n\n /** Records one idempotent attribute write before MutationObserver sees it. */\n #writeAttribute(element: Element, name: string, value: ExpectedAttribute): void {\n if (element.getAttribute(name) !== value) {\n if (this.#observing) {\n let writes = this.#internalWrites.get(element);\n if (!writes) {\n writes = new Map();\n this.#internalWrites.set(element, writes);\n }\n writes.set(name, value);\n }\n if (value === null) element.removeAttribute(name);\n else element.setAttribute(name, value);\n }\n }\n\n /** Separates authored records from controller writes and queues one relevant repair. */\n #onMutations(records: MutationRecord[]): void {\n const triggers = this.triggerTargets;\n const regions = this.regionTargets;\n const touchedWrites = new Map<Element, Set<string>>();\n let needsReconcile = false;\n\n for (const record of records) {\n if (record.type === \"attributes\" && record.target instanceof Element) {\n const name = record.attributeName;\n const writes = this.#internalWrites.get(record.target);\n if (name && writes?.has(name)) {\n let names = touchedWrites.get(record.target);\n if (!names) {\n names = new Set();\n touchedWrites.set(record.target, names);\n }\n names.add(name);\n if (record.target.getAttribute(name) === writes.get(name)) continue;\n }\n }\n if (\n record.target instanceof Element &&\n this.#elementAffectsState(record.target, triggers, regions)\n ) {\n needsReconcile = true;\n }\n }\n\n for (const [element, names] of touchedWrites) {\n const writes = this.#internalWrites.get(element);\n for (const name of names) writes?.delete(name);\n }\n if (needsReconcile) this.#reconcile.schedule();\n }\n\n /** Whether an authored mutation target belongs to a trigger, region, or managed control. */\n #elementAffectsState(target: Element, triggers: Trigger[], regions: HTMLElement[]): boolean {\n return ownerIndex(triggers, target) !== -1 || ownerIndex(regions, target) !== -1;\n }\n\n /** Whether a form owns at least one current trigger, including `form=` associations. */\n #hasTriggerOwnedBy(form: HTMLFormElement): boolean {\n return this.triggerTargets.some((trigger) => trigger.form === form);\n }\n}\n"]}
@@ -58,6 +58,36 @@ function halfWidthChar(char) {
58
58
  return char === "\u3000" ? " " : char;
59
59
  }
60
60
 
61
+ // src/utils/intl_format.ts
62
+ var formatters = /* @__PURE__ */ new WeakMap();
63
+ function intlFormatter(factory, locale, options, fallbackLocale) {
64
+ const cache = cacheFor(factory);
65
+ const key = cacheKey(locale, options, fallbackLocale);
66
+ if (cache.has(key)) return cache.get(key);
67
+ const formatter = construct(factory, locale, options, fallbackLocale);
68
+ cache.set(key, formatter);
69
+ return formatter;
70
+ }
71
+ function cacheFor(factory) {
72
+ const existing = formatters.get(factory);
73
+ if (existing) return existing;
74
+ const created = /* @__PURE__ */ new Map();
75
+ formatters.set(factory, created);
76
+ return created;
77
+ }
78
+ function cacheKey(locale, options, fallbackLocale) {
79
+ return JSON.stringify([locale, options, fallbackLocale]);
80
+ }
81
+ function construct(factory, locale, options, fallbackLocale) {
82
+ try {
83
+ return new factory(locale, options);
84
+ } catch (error) {
85
+ if (!(error instanceof RangeError)) throw error;
86
+ if (fallbackLocale === void 0) return null;
87
+ return new factory(fallbackLocale, options);
88
+ }
89
+ }
90
+
61
91
  // src/controllers/currency_input_controller.ts
62
92
  var CurrencyInputController = class extends Controller {
63
93
  static targets = ["display", "field", "srValue"];
@@ -309,37 +339,52 @@ var CurrencyInputController = class extends Controller {
309
339
  * formatters from the validated set.
310
340
  */
311
341
  #revalidate() {
312
- this.#locale = "en-US";
313
- try {
314
- new Intl.NumberFormat(this.localeValue);
315
- this.#locale = this.localeValue;
316
- } catch {
317
- }
342
+ const declaredLocale = intlFormatter(Intl.NumberFormat, this.localeValue, {});
343
+ this.#locale = declaredLocale === null ? "en-US" : this.localeValue;
318
344
  const precision = this.precisionValue;
319
345
  this.#precision = Number.isInteger(precision) && precision >= 0 && precision <= 100 ? precision : 2;
320
346
  this.#currency = "";
321
347
  if (this.currencyValue !== "") {
322
- try {
323
- new Intl.NumberFormat(this.#locale, { style: "currency", currency: this.currencyValue });
324
- this.#currency = this.currencyValue;
325
- } catch {
326
- }
348
+ const declaredCurrency = intlFormatter(Intl.NumberFormat, this.#locale, {
349
+ style: "currency",
350
+ currency: this.currencyValue
351
+ });
352
+ if (declaredCurrency !== null) this.#currency = this.currencyValue;
327
353
  }
328
- this.#grouping = new Intl.NumberFormat(this.#locale, {
329
- useGrouping: true,
330
- maximumFractionDigits: 0
331
- });
332
- this.#fixed = new Intl.NumberFormat(this.#locale, {
333
- useGrouping: true,
334
- minimumFractionDigits: this.#precision,
335
- maximumFractionDigits: this.#precision
336
- });
337
- this.#accessible = this.#currency ? new Intl.NumberFormat(this.#locale, { style: "currency", currency: this.#currency }) : this.#fixed;
338
- const parts = new Intl.NumberFormat(this.#locale).formatToParts(11111.1);
354
+ this.#grouping = intlFormatter(
355
+ Intl.NumberFormat,
356
+ this.#locale,
357
+ { useGrouping: true, maximumFractionDigits: 0 },
358
+ this.#locale
359
+ );
360
+ this.#fixed = intlFormatter(
361
+ Intl.NumberFormat,
362
+ this.#locale,
363
+ {
364
+ useGrouping: true,
365
+ minimumFractionDigits: this.#precision,
366
+ maximumFractionDigits: this.#precision
367
+ },
368
+ this.#locale
369
+ );
370
+ this.#accessible = this.#currency ? intlFormatter(
371
+ Intl.NumberFormat,
372
+ this.#locale,
373
+ { style: "currency", currency: this.#currency },
374
+ this.#locale
375
+ ) : this.#fixed;
376
+ const parts = intlFormatter(Intl.NumberFormat, this.#locale, {}, this.#locale).formatToParts(
377
+ 11111.1
378
+ );
339
379
  this.#group = parts.find((p) => p.type === "group")?.value ?? ",";
340
380
  this.#decimal = parts.find((p) => p.type === "decimal")?.value ?? ".";
341
381
  this.#digits.clear();
342
- const digitFormatter = new Intl.NumberFormat(this.#locale, { useGrouping: false });
382
+ const digitFormatter = intlFormatter(
383
+ Intl.NumberFormat,
384
+ this.#locale,
385
+ { useGrouping: false },
386
+ this.#locale
387
+ );
343
388
  for (let i = 0; i <= 9; i++) {
344
389
  const digit = digitFormatter.format(i);
345
390
  if (digit !== String(i)) this.#digits.set(digit, String(i));