stimeo-ui 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/dist/controllers/bulk_select_controller.d.ts +62 -15
- package/dist/controllers/bulk_select_controller.js +139 -28
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +48 -15
- package/dist/controllers/clipboard_controller.js +102 -20
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +37 -6
- package/dist/controllers/color_picker_controller.js +180 -43
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +25 -9
- package/dist/controllers/data_grid_controller.js +150 -24
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/editable_controller.d.ts +34 -9
- package/dist/controllers/editable_controller.js +83 -30
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +15 -3
- package/dist/controllers/filter_controller.js +32 -1
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +34 -5
- package/dist/controllers/masonry_controller.js +129 -17
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +4 -1
- package/dist/controllers/otp_controller.js +29 -16
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/reset_before_cache_controller.d.ts +25 -2
- package/dist/controllers/reset_before_cache_controller.js +51 -5
- package/dist/controllers/reset_before_cache_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +23 -7
- package/dist/controllers/resizable_controller.js +128 -55
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/index.js +860 -339
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.js +2 -0
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +2 -0
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +22 -22
- package/dist/inspector/manifest.json +12 -8
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/aria_ids.ts","../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/attribute_lease.ts","../../src/utils/before_cache_reset.ts","../../src/utils/composition_tracker.ts","../../src/utils/half_width.ts","../../src/utils/microtask_coalescer.ts","../../src/controllers/otp_controller.ts"],"names":[],"mappings":"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","file":"otp_controller.js","sourcesContent":["/**\n * Minimal id primitives for wiring ARIA relationships.\n *\n * Accessible relationships such as `aria-describedby`, `aria-errormessage`,\n * `aria-labelledby`, and `aria-activedescendant` reference their targets by DOM\n * `id`. When a controller must establish such a relationship but the consumer's\n * markup left the target without an `id`, it needs to mint one that is stable for\n * the page's lifetime and guaranteed not to collide with another generated id.\n *\n * These helpers own *only* id generation/assignment. The linking policy (which\n * attribute, what order, when to add or remove it) stays in each controller —\n * this deliberately avoids a premature generic \"ARIA linker\" abstraction.\n */\n\n/**\n * Monotonic counter backing {@link uniqueId}. Module-scoped so every generated\n * id is unique across all controller instances sharing this module in a document.\n */\nlet counter = 0;\n\n/**\n * Returns a unique, DOM-id-safe string of the form `` `${prefix}-${n}` `` where\n * `n` increases on each call.\n *\n * The counter alone guarantees uniqueness against other *generated* ids, but a\n * consumer-authored element could already own `` `${prefix}-${n}` ``. When a\n * `document` is available the candidate is therefore advanced until no element\n * with that id exists, so a generated id never collides with author markup\n * either — the minimal \"id registry\" guarantee these helpers exist to provide.\n *\n * @param prefix - Leading segment of the id (e.g. a controller's identifier).\n * Defaults to `\"stimeo\"`.\n */\nexport function uniqueId(prefix = \"stimeo\"): string {\n let candidate: string;\n do {\n counter += 1;\n candidate = `${prefix}-${counter}`;\n } while (typeof document !== \"undefined\" && document.getElementById(candidate) !== null);\n return candidate;\n}\n\n/**\n * Returns `element`'s existing `id`, or assigns it a freshly generated\n * {@link uniqueId} (with the given `prefix`) and returns that. Idempotent: an\n * element that already has an id keeps it, so consumer-authored ids are never\n * overwritten.\n *\n * @param element - The element to read or stamp an `id` onto.\n * @param prefix - Prefix forwarded to {@link uniqueId} when one must be generated.\n * @returns The element's id (existing or newly assigned).\n */\nexport function ensureId(element: Element, prefix = \"stimeo\"): string {\n if (element.id) return element.id;\n const id = uniqueId(prefix);\n element.id = id;\n return id;\n}\n","/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n","/** One temporarily controlled attribute value and the authored value it displaced. */\ninterface AttributeLeaseRecord {\n readonly original: string | null;\n written: string | null;\n}\n\n/**\n * Temporarily controls one attribute across a changing set of elements.\n *\n * The first write remembers the authored value, including the distinction between\n * an absent attribute and an authored empty string. Returning a lease restores that\n * value only while the attribute still matches the controller's last write. If a\n * consumer changed it in the meantime, the consumer owns the new value and teardown\n * leaves it alone.\n *\n * A `null` write deliberately removes the attribute while retaining the lease. This\n * is useful for derived ARIA whose valid absence is itself controller state, such as\n * an unbounded `aria-valuemin` or a blank spinbutton's `aria-valuenow`.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events.\n * A consumer that must not let a derived value become the authored baseline of a\n * cached page returns its leases from its own `turbo:before-cache` rewind, where the\n * matching `disconnect()` also releases the subscription.\n */\nexport class AttributeLease<T extends Element = Element> {\n readonly #attribute: string;\n readonly #records = new Map<T, AttributeLeaseRecord>();\n\n /** @param attribute - The attribute whose temporary values this lease owns. */\n constructor(attribute: string) {\n this.#attribute = attribute;\n }\n\n /** Writes or removes the leased attribute while preserving its authored value. */\n write(element: T, value: string | null): void {\n const existing = this.#records.get(element);\n if (existing) {\n existing.written = value;\n } else {\n this.#records.set(element, {\n original: element.getAttribute(this.#attribute),\n written: value,\n });\n }\n\n this.#reflect(element, value);\n }\n\n /** Returns one lease without overwriting a value subsequently authored by a consumer. */\n return(element: T): void {\n const record = this.#records.get(element);\n if (!record) return;\n this.#records.delete(element);\n const stillOwned = element.getAttribute(this.#attribute) === record.written;\n if (stillOwned) this.#reflect(element, record.original);\n }\n\n /** Reflects only a real value transition, avoiding self-triggered mutation work. */\n #reflect(element: T, value: string | null): void {\n if (element.getAttribute(this.#attribute) === value) return;\n if (value === null) element.removeAttribute(this.#attribute);\n else element.setAttribute(this.#attribute, value);\n }\n\n /** Returns every outstanding lease using the same ownership check as {@link return}. */\n returnAll(): void {\n for (const element of Array.from(this.#records.keys())) this.return(element);\n }\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way (the `MicrotaskCoalescer` split).\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/** Minimal event shape carrying the platform's per-event composition signal. */\nexport interface CompositionSignal {\n readonly isComposing?: boolean;\n}\n\n/** Hooks that keep component-specific work outside {@link CompositionTracker}. */\nexport interface CompositionTrackerOptions {\n /** Runs after lifecycle state is set for a `compositionstart` event. */\n readonly onStart?: (event: Event) => void;\n /** Runs after lifecycle state is cleared for a `compositionend` event. */\n readonly onEnd?: (event: Event) => void;\n}\n\n/**\n * Owns IME composition listeners and transient state for one or more event targets.\n *\n * Some browsers omit `KeyboardEvent.isComposing` on the keydown that confirms a\n * conversion. Tracking `compositionstart` through `compositionend` supplies the\n * missing lifecycle signal without relying on deprecated numeric key codes.\n * Component policy stays with the consumer: filtering, validation, and submission\n * belong in the optional {@link CompositionTrackerOptions.onEnd} callback.\n *\n * @example\n * ```ts\n * #composition = new CompositionTracker({ onEnd: () => this.filter() });\n *\n * connect(): void {\n * this.#composition.observe(this.inputTarget);\n * }\n *\n * disconnect(): void {\n * this.#composition.disconnect();\n * }\n *\n * onKeydown(event: KeyboardEvent): void {\n * if (this.#composition.isComposing(event)) return;\n * }\n * ```\n */\nexport class CompositionTracker {\n readonly #observedTargets = new Set<EventTarget>();\n readonly #activeTargets = new Set<EventTarget>();\n readonly #onStart: ((event: Event) => void) | undefined;\n readonly #onEnd: ((event: Event) => void) | undefined;\n\n constructor(options: CompositionTrackerOptions = {}) {\n this.#onStart = options.onStart;\n this.#onEnd = options.onEnd;\n }\n\n /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */\n observe(target: EventTarget): void {\n if (this.#observedTargets.has(target)) return;\n target.addEventListener(\"compositionstart\", this.#handleStart);\n target.addEventListener(\"compositionend\", this.#handleEnd);\n this.#observedTargets.add(target);\n }\n\n /** Stops tracking one target and clears any active composition it owned. */\n unobserve(target: EventTarget): void {\n if (!this.#observedTargets.delete(target)) return;\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n this.#activeTargets.delete(target);\n }\n\n /** Releases every listener and clears state so reconnect starts cleanly. */\n disconnect(): void {\n for (const target of this.#observedTargets) {\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n }\n this.#observedTargets.clear();\n this.#activeTargets.clear();\n }\n\n /** True when lifecycle tracking or the current event reports composition. */\n isComposing(event?: CompositionSignal): boolean {\n return this.#activeTargets.size > 0 || event?.isComposing === true;\n }\n\n readonly #handleStart = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.add(event.currentTarget);\n this.#onStart?.(event);\n };\n\n readonly #handleEnd = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);\n this.#onEnd?.(event);\n };\n}\n","/** The distance between a full-width ASCII code point and its half-width twin. */\nconst FULL_WIDTH_SHIFT = 0xfee0;\n\n/**\n * The half-width form of `char`, or `char` itself when it has none.\n *\n * An IME confirming in full-width mode produces U+FF01–U+FF5E (and U+3000 for\n * the space) where the page means ASCII — the digits of a phone number, the\n * letters of a code, the separators between them. Reading those as their ASCII\n * equivalents keeps confirmed text usable instead of discarding it. Characters\n * outside that block, including kana and astral code points, are returned\n * unchanged, so this never rewrites text a consumer meant to keep as typed.\n */\nexport function halfWidthChar(char: string): string {\n if (char >= \"!\" && char <= \"~\") {\n return String.fromCharCode(char.charCodeAt(0) - FULL_WIDTH_SHIFT);\n }\n return char === \" \" ? \" \" : char;\n}\n\n/** Every full-width ASCII character in `text` rewritten by {@link halfWidthChar}. */\nexport function toHalfWidth(text: string): string {\n let out = \"\";\n for (const char of text) out += halfWidthChar(char);\n return out;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { ensureId } from \"../utils/aria_ids\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { AttributeLease } from \"../utils/attribute_lease\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport { CompositionTracker } from \"../utils/composition_tracker\";\nimport { toHalfWidth } from \"../utils/half_width\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\n\n/** Single-character pattern used when a `pattern` declaration cannot compile. */\nconst DEFAULT_PATTERN = \"[0-9]\";\n\n/** Compiles one anchored single-character matcher, or `null` for a broken source. */\nfunction compilePattern(source: string): RegExp | null {\n try {\n return new RegExp(`^${source}$`);\n } catch {\n return null;\n }\n}\n\n/** Whether a press carries a modifier, which makes it the document's to handle. */\nfunction hasModifier(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\n}\n\n/**\n * Headless, accessible One-Time Password / PIN input logic.\n *\n * Markup contract (identifier: `stimeo--otp`):\n * <div data-controller=\"stimeo--otp\"\n * data-stimeo--otp-pattern-value=\"[0-9]\"\n * role=\"group\" aria-label=\"One-time passcode\">\n * <input data-stimeo--otp-target=\"field\" inputmode=\"numeric\" maxlength=\"1\"\n * autocomplete=\"one-time-code\" aria-label=\"Digit 1\"\n * data-action=\"input->stimeo--otp#onInput\n * keydown->stimeo--otp#onKeydown\n * paste->stimeo--otp#onPaste\n * pointerdown->stimeo--otp#onPointerDown\" />\n * <!-- repeat one field per digit -->\n * <p data-stimeo--otp-target=\"error\" hidden>Digits only.</p>\n * <input type=\"hidden\" data-stimeo--otp-target=\"value\" name=\"otp\" />\n * </div>\n *\n * The passcode length is the number of connected `field` targets, so nothing has\n * to declare it twice and fields added or removed at runtime are absorbed.\n *\n * Entry rules:\n * - Text carrying more than one accepted character — an OS `one-time-code`\n * autofill, a password manager, an IME committing several digits, a paste —\n * is spread across the following writable fields from the entry point.\n * - `disabled` and `readonly` fields keep their value: they are never written\n * and never receive auto-advance focus, matching what the platform allows a\n * user to do by hand.\n * - Input that lands nowhere rolls the field back to the digit it last\n * committed, and is the only thing that reports `invalid` or reveals the\n * `error` target. Discarding a separator inside otherwise usable text\n * (`\"1234-56\"`) is a successful entry.\n * - Pointing at an empty field ahead of an earlier empty one lands on the\n * earliest empty field instead, so a passcode fills in order. Keyboard focus\n * is never redirected.\n *\n * `change` and `complete` dispatch `{ value: string }` and fire only when the\n * combined value actually moves — one confirmed IME character emits one event,\n * and a passcode re-completed with a different digit reports the new value.\n * A value moved by adding or removing fields is the page's doing rather than an\n * edit, so it is reported as `reconcile` with the same `{ value: string }`.\n * `invalid` dispatches `{ pattern: string }` carrying the compiled pattern.\n *\n * Controller-owned output: `data-filled` on each entered field, `data-state`\n * (`empty` / `partial` / `complete`) on the root, and — while input is being\n * reported invalid — `aria-invalid`, `aria-errormessage`, `aria-describedby`,\n * and the `error` target's `hidden`. Those four are leased, so authored values\n * return on teardown and before the page is cached.\n *\n * @remarks\n * Behavior only. `connect()` reads the fields back as the source of truth, which\n * is what restores consistency after a `type=\"password\"` field returns from the\n * Turbo cache emptied, or after a native form reset. A `pattern` that cannot\n * compile falls back to `[0-9]`; the compiled matcher is built once per\n * declaration rather than per keystroke.\n */\nexport class OtpController extends Controller<HTMLElement> {\n static override targets = [\"field\", \"value\", \"error\"];\n static override values = {\n pattern: { type: String, default: DEFAULT_PATTERN },\n };\n static actions = [\"onInput\", \"onKeydown\", \"onPaste\", \"onPointerDown\", \"clear\"] as const;\n static events = [\"change\", \"complete\", \"invalid\", \"reconcile\"] as const;\n\n declare readonly fieldTargets: HTMLInputElement[];\n declare readonly valueTarget: HTMLInputElement;\n declare readonly errorTarget: HTMLElement;\n declare readonly hasValueTarget: boolean;\n declare readonly hasErrorTarget: boolean;\n\n declare patternValue: string;\n\n /** Validated matcher; the hot path never compiles a raw declaration. */\n #pattern = new RegExp(`^${DEFAULT_PATTERN}$`);\n /** Source of {@link #pattern}, reported in `invalid` so consumers can word it. */\n #patternSource = DEFAULT_PATTERN;\n /** Combined value carried by the last dispatch; keeps a no-op sync silent. */\n #lastValue: string | null = null;\n /** Field whose confirming `input` after `compositionend` is already handled. */\n #confirmedField: HTMLInputElement | null = null;\n /** True between connect and disconnect, so pre-connect Value changes stay silent. */\n #connected = false;\n /** Digit each field last committed, restored when rejected input replaced it. */\n readonly #committed = new WeakMap<HTMLInputElement, string>();\n\n /** Collapses one batch of field target callbacks into a single reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileFields());\n\n readonly #ariaInvalid = new AttributeLease<HTMLInputElement>(\"aria-invalid\");\n readonly #ariaErrorMessage = new AttributeLease<HTMLInputElement>(\"aria-errormessage\");\n readonly #ariaDescribedBy = new AttributeLease<HTMLInputElement>(\"aria-describedby\");\n readonly #errorHidden = new AttributeLease<HTMLElement>(\"hidden\");\n readonly #state = new AttributeLease<HTMLElement>(\"data-state\");\n\n /** Rewinds the transient error surface before Turbo freezes the page. */\n readonly #beforeCache = new BeforeCacheReset(() => this.#clearError());\n\n /** Owns IME lifecycle state across every digit field. */\n readonly #composition = new CompositionTracker({\n onStart: () => {\n this.#confirmedField = null;\n },\n onEnd: (event) => {\n const input = this.#fieldFrom(event);\n if (!input) return;\n // The browser follows a commit with one more `input` carrying the same\n // text; marking the field lets that echo be dropped instead of rerun.\n this.#confirmedField = input;\n // `maxlength` has already cut the field down to one character, but the\n // commit itself carries the whole confirmed string — so a conversion that\n // ends in several characters still reaches the fields after this one.\n const committed = (event as CompositionEvent).data ?? \"\";\n this.#accept(input, committed.length > input.value.length ? committed : input.value);\n },\n });\n\n override connect(): void {\n this.#connected = true;\n for (const field of this.fieldTargets) this.#bind(field);\n document.addEventListener(\"reset\", this.#onReset, true);\n this.#beforeCache.activate();\n this.#reconcile.activate();\n this.#adopt();\n this.#lastValue = this.#sync();\n }\n\n override disconnect(): void {\n this.#connected = false;\n for (const field of this.fieldTargets) this.#unbind(field);\n this.#composition.disconnect();\n document.removeEventListener(\"reset\", this.#onReset, true);\n this.#beforeCache.deactivate();\n this.#reconcile.cancel();\n this.#clearError();\n this.#state.return(this.element);\n }\n\n /**\n * Stimulus lifecycle callback when a new field target enters the DOM.\n * Wires the new field and folds the wider digit count into one reconciliation,\n * which stays inert until `connect()` opens the window.\n */\n fieldTargetConnected(element: HTMLInputElement): void {\n this.#bind(element);\n this.#adoptField(element);\n this.#reconcile.schedule();\n }\n\n /** Releases a dropped field's listeners and leases, then reconciles the rest. */\n fieldTargetDisconnected(element: HTMLInputElement): void {\n this.#unbind(element);\n this.#returnFieldLeases(element);\n this.#reconcile.schedule();\n }\n\n /**\n * Re-validates a changed `pattern` declaration once and drops any entered digit\n * the new pattern no longer accepts, so the combined value stays interpretable.\n */\n patternValueChanged(): void {\n const compiled = compilePattern(this.patternValue);\n this.#patternSource = compiled ? this.patternValue : DEFAULT_PATTERN;\n this.#pattern = compiled ?? new RegExp(`^${DEFAULT_PATTERN}$`);\n if (!this.#connected) return;\n\n let dropped = false;\n for (const field of this.fieldTargets) {\n if (field.value === \"\" || !this.#isWritable(field)) continue;\n if (this.#pattern.test(field.value)) continue;\n this.#writeField(field, \"\");\n dropped = true;\n }\n if (dropped) this.#syncAndDispatch();\n }\n\n /** Handles keystroke inputs, distributes autofilled text, and advances focus. */\n onInput(event: Event): void {\n const input = this.#fieldFrom(event);\n if (!input) return;\n\n const confirmed = this.#confirmedField;\n this.#confirmedField = null;\n if (confirmed === input) return;\n\n // Guard during active composition to prevent premature focus switching\n if (this.#composition.isComposing(event as InputEvent)) return;\n\n this.#accept(input);\n }\n\n /** Handles Backspace clearing, arrows, and home/end navigation. */\n onKeydown(event: KeyboardEvent): void {\n if (isReservedArrowChord(event)) return;\n const input = this.#fieldFrom(event);\n if (!input) return;\n\n // A keyed edit always starts with this event, so no post-commit echo is pending\n this.#confirmedField = null;\n // Do not trigger keydown actions during composition\n if (this.#composition.isComposing(event)) return;\n\n const index = this.fieldTargets.indexOf(input);\n const fields = this.fieldTargets;\n // Logical, not physical. The key is normalised rather than the\n // delta negated: these two branches are not mirror images — their bounds\n // guards differ — so swapping the key keeps each guard with its own direction.\n\n switch (logicalArrowKey(event.key, this.element)) {\n case \"Backspace\":\n if (hasModifier(event)) break;\n if (input.value && this.#isWritable(input)) {\n // Filled field: clear it where it stands\n event.preventDefault();\n this.#writeField(input, \"\");\n this.#clearError();\n this.#syncAndDispatch();\n } else {\n // Empty field: step back to the previous writable digit and wipe it\n const previous = this.#writableBefore(index);\n if (previous) {\n event.preventDefault();\n this.#writeField(previous, \"\");\n previous.focus();\n this.#clearError();\n this.#syncAndDispatch();\n }\n }\n break;\n\n case \"ArrowLeft\": {\n const previous = this.#focusableBefore(index);\n if (previous) {\n event.preventDefault();\n previous.focus();\n }\n break;\n }\n\n case \"ArrowRight\": {\n const next = this.#focusableAfter(index);\n if (next) {\n event.preventDefault();\n next.focus();\n }\n break;\n }\n\n case \"Home\": {\n // Control+Home belongs to the document, not to the digit group\n if (hasModifier(event)) break;\n const first = fields.find((field) => this.#isFocusable(field));\n if (first) {\n event.preventDefault();\n first.focus();\n }\n break;\n }\n\n case \"End\": {\n if (hasModifier(event)) break;\n const last = fields\n .slice()\n .reverse()\n .find((field) => this.#isFocusable(field));\n if (last) {\n event.preventDefault();\n last.focus();\n }\n break;\n }\n\n default:\n break;\n }\n }\n\n /** Divides pasted string characters across the available input fields. */\n onPaste(event: ClipboardEvent): void {\n const input = this.#fieldFrom(event);\n if (!input) return;\n\n event.preventDefault();\n this.#confirmedField = null;\n this.#distribute(input, toHalfWidth(event.clipboardData?.getData(\"text\") ?? \"\"));\n }\n\n /**\n * Redirects a pointer landing on an empty field to the earliest empty one, so\n * a passcode is entered in order. Filled fields stay directly reachable for\n * correction, and keyboard focus is left alone.\n */\n onPointerDown(event: Event): void {\n const input = this.#fieldFrom(event);\n if (input?.value !== \"\") return;\n\n const first = this.fieldTargets.find((field) => this.#isWritable(field) && field.value === \"\");\n if (!first || first === input) return;\n\n event.preventDefault();\n first.focus();\n }\n\n /** Empties every writable field and restarts entry at the first of them. */\n clear(): void {\n for (const field of this.fieldTargets) {\n if (this.#isWritable(field)) this.#writeField(field, \"\");\n }\n this.#clearError();\n this.fieldTargets.find((field) => this.#isWritable(field))?.focus();\n this.#syncAndDispatch();\n }\n\n readonly #onFieldFocus = (event: FocusEvent): void => {\n const input = event.currentTarget as HTMLInputElement | null;\n if (input) {\n // Auto-selection enables effortless character overwrites\n input.select();\n }\n };\n\n /** Reconciles derived state after a non-cancelled reset restores the fields. */\n readonly #onReset = (event: Event): void => {\n const form = event.target;\n if (!(form instanceof HTMLFormElement) || !this.#ownedBy(form)) return;\n queueMicrotask(() => {\n if (event.defaultPrevented) return;\n this.#adopt();\n this.#syncAndDispatch();\n });\n };\n\n /** Whether a form owns at least one field or the hidden combined value. */\n #ownedBy(form: HTMLFormElement): boolean {\n if (this.fieldTargets.some((field) => field.form === form)) return true;\n return this.hasValueTarget && this.valueTarget.form === form;\n }\n\n #bind(field: HTMLInputElement): void {\n field.addEventListener(\"focus\", this.#onFieldFocus);\n this.#composition.observe(field);\n }\n\n #unbind(field: HTMLInputElement): void {\n field.removeEventListener(\"focus\", this.#onFieldFocus);\n this.#composition.unobserve(field);\n if (this.#confirmedField === field) this.#confirmedField = null;\n }\n\n /** Reads every field back so a restored or reset group starts consistent. */\n #adopt(): void {\n for (const field of this.fieldTargets) this.#adoptField(field);\n this.#clearError();\n // Nothing has been rejected yet, whatever visibility the restored DOM carries\n if (this.hasErrorTarget) this.errorTarget.setAttribute(\"hidden\", \"\");\n }\n\n /** Takes one field's current value as the truth behind its derived state. */\n #adoptField(field: HTMLInputElement): void {\n this.#committed.set(field, field.value);\n this.#markFilled(field, field.value);\n }\n\n /**\n * Absorbs a batch of field additions or removals as one value transition.\n *\n * The page, not the user, moved the value here, so it is reported as\n * `reconcile`: automation listening for `change` must not read a re-render as\n * an edit, and a passcode that happens to end up full must not fire the\n * `complete` that submits it.\n */\n #reconcileFields(): void {\n const previous = this.#lastValue;\n const combined = this.#sync();\n if (combined === previous) return;\n this.#lastValue = combined;\n this.dispatch(\"reconcile\", { detail: { value: combined } });\n }\n\n /**\n * Validates the text an entry point received and distributes what it accepts.\n * `text` defaults to the field's own value; a confirmation passes the string it\n * committed, which `maxlength` would otherwise have truncated.\n */\n #accept(input: HTMLInputElement, text: string = input.value): void {\n const raw = toHalfWidth(text);\n if (raw === \"\") {\n // Emptying a field is a legitimate edit, not rejected input\n this.#writeField(input, \"\");\n this.#clearError();\n this.#syncAndDispatch();\n return;\n }\n\n this.#distribute(input, raw);\n }\n\n /**\n * Fills `text`'s accepted characters into the writable fields at and after the\n * entry point, then leaves focus on the field after the last one filled.\n */\n #distribute(from: HTMLInputElement, text: string): void {\n const accepted = Array.from(text).filter((char) => this.#pattern.test(char));\n let reached = false;\n const slots = this.fieldTargets.filter((field) => {\n reached ||= field === from;\n return reached && this.#isWritable(field);\n });\n const filled = Math.min(accepted.length, slots.length);\n\n if (filled === 0) {\n // Nothing landed: restore the digit the entry point had committed\n this.#restore(from);\n this.#showError();\n this.#sync();\n return;\n }\n\n for (let i = 0; i < filled; i++) {\n const field = slots[i];\n const char = accepted[i];\n if (field && char) this.#writeField(field, char);\n }\n\n const last = slots[filled - 1];\n if (last) (this.#writableAfter(last) ?? last).focus();\n\n this.#clearError();\n this.#syncAndDispatch();\n }\n\n /** Restores the digit a field committed before rejected input replaced it. */\n #restore(field: HTMLInputElement): void {\n this.#writeField(field, this.#committed.get(field) ?? \"\");\n }\n\n /** Commits one field's value and the derived hook that reports it as entered. */\n #writeField(field: HTMLInputElement, value: string): void {\n field.value = value;\n this.#committed.set(field, value);\n this.#markFilled(field, value);\n }\n\n #markFilled(field: HTMLInputElement, value: string): void {\n if (value) field.setAttribute(\"data-filled\", \"true\");\n else field.removeAttribute(\"data-filled\");\n }\n\n #isWritable(field: HTMLInputElement): boolean {\n return !field.disabled && !field.readOnly;\n }\n\n #isFocusable(field: HTMLInputElement): boolean {\n return !field.disabled;\n }\n\n #writableAfter(field: HTMLInputElement): HTMLInputElement | null {\n const fields = this.fieldTargets;\n return fields.slice(fields.indexOf(field) + 1).find((next) => this.#isWritable(next)) ?? null;\n }\n\n #writableBefore(index: number): HTMLInputElement | null {\n return this.#before(index).find((field) => this.#isWritable(field)) ?? null;\n }\n\n #focusableAfter(index: number): HTMLInputElement | null {\n return this.fieldTargets.slice(index + 1).find((field) => this.#isFocusable(field)) ?? null;\n }\n\n #focusableBefore(index: number): HTMLInputElement | null {\n return this.#before(index).find((field) => this.#isFocusable(field)) ?? null;\n }\n\n /** Fields before `index`, nearest first; empty at the first field. */\n #before(index: number): HTMLInputElement[] {\n return this.fieldTargets.slice(0, Math.max(index, 0)).reverse();\n }\n\n /** The event's field target, or `null` when the wiring points somewhere else. */\n #fieldFrom(event: Event): HTMLInputElement | null {\n const input = event.currentTarget;\n return this.fieldTargets.find((field) => field === input) ?? null;\n }\n\n #combinedValue(): string {\n return this.fieldTargets.map((field) => field.value).join(\"\");\n }\n\n /** Every field carries a character, and there is at least one field. */\n #isComplete(): boolean {\n const fields = this.fieldTargets;\n return fields.length > 0 && fields.every((field) => field.value.length > 0);\n }\n\n /** Mirrors the combined value into the form and the root's readable state. */\n #sync(): string {\n const combined = this.#combinedValue();\n\n if (this.hasValueTarget) {\n this.valueTarget.value = combined;\n }\n this.#state.write(this.element, this.#stateName(combined));\n\n return combined;\n }\n\n #stateName(combined: string): string {\n if (combined.length === 0) return \"empty\";\n return this.#isComplete() ? \"complete\" : \"partial\";\n }\n\n #syncAndDispatch(): void {\n const combined = this.#sync();\n if (combined === this.#lastValue) return;\n this.#lastValue = combined;\n\n this.dispatch(\"change\", { detail: { value: combined } });\n\n // Completed state when every field carries a character\n if (this.#isComplete()) {\n this.dispatch(\"complete\", { detail: { value: combined } });\n }\n }\n\n /** Surfaces rejected input on every field and on the optional error target. */\n #showError(): void {\n const errorId = this.hasErrorTarget ? ensureId(this.errorTarget, \"stimeo--otp-error\") : null;\n\n for (const field of this.fieldTargets) {\n this.#ariaInvalid.write(field, \"true\");\n if (!errorId) continue;\n this.#ariaErrorMessage.write(field, errorId);\n // Assistive tech without aria-errormessage support still reads a description\n this.#ariaDescribedBy.write(field, this.#describedByWith(field, errorId));\n }\n if (this.hasErrorTarget) this.#errorHidden.write(this.errorTarget, null);\n\n // Behavior only: emit a neutral payload and let the consumer compose/localize\n // the user-facing message. The pattern is reported so consumers can word it.\n this.dispatch(\"invalid\", { detail: { pattern: this.#patternSource } });\n }\n\n /** Returns every error lease, restoring the authored error surface. */\n #clearError(): void {\n this.#ariaInvalid.returnAll();\n this.#ariaErrorMessage.returnAll();\n this.#ariaDescribedBy.returnAll();\n this.#errorHidden.returnAll();\n }\n\n #returnFieldLeases(field: HTMLInputElement): void {\n this.#ariaInvalid.return(field);\n this.#ariaErrorMessage.return(field);\n this.#ariaDescribedBy.return(field);\n }\n\n /** The field's own description tokens with the error id appended once. */\n #describedByWith(field: HTMLInputElement, errorId: string): string {\n const tokens = (field.getAttribute(\"aria-describedby\") ?? \"\")\n .split(/\\s+/)\n .filter((token) => token.length > 0 && token !== errorId);\n return [...tokens, errorId].join(\" \");\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/aria_ids.ts","../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/attribute_lease.ts","../../src/utils/before_cache_reset.ts","../../src/utils/composition_tracker.ts","../../src/utils/half_width.ts","../../src/utils/microtask_coalescer.ts","../../src/controllers/otp_controller.ts"],"names":[],"mappings":"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","file":"otp_controller.js","sourcesContent":["/**\n * Minimal id primitives for wiring ARIA relationships.\n *\n * Accessible relationships such as `aria-describedby`, `aria-errormessage`,\n * `aria-labelledby`, and `aria-activedescendant` reference their targets by DOM\n * `id`. When a controller must establish such a relationship but the consumer's\n * markup left the target without an `id`, it needs to mint one that is stable for\n * the page's lifetime and guaranteed not to collide with another generated id.\n *\n * These helpers own *only* id generation/assignment. The linking policy (which\n * attribute, what order, when to add or remove it) stays in each controller —\n * this deliberately avoids a premature generic \"ARIA linker\" abstraction.\n */\n\n/**\n * Monotonic counter backing {@link uniqueId}. Module-scoped so every generated\n * id is unique across all controller instances sharing this module in a document.\n */\nlet counter = 0;\n\n/**\n * Returns a unique, DOM-id-safe string of the form `` `${prefix}-${n}` `` where\n * `n` increases on each call.\n *\n * The counter alone guarantees uniqueness against other *generated* ids, but a\n * consumer-authored element could already own `` `${prefix}-${n}` ``. When a\n * `document` is available the candidate is therefore advanced until no element\n * with that id exists, so a generated id never collides with author markup\n * either — the minimal \"id registry\" guarantee these helpers exist to provide.\n *\n * @param prefix - Leading segment of the id (e.g. a controller's identifier).\n * Defaults to `\"stimeo\"`.\n */\nexport function uniqueId(prefix = \"stimeo\"): string {\n let candidate: string;\n do {\n counter += 1;\n candidate = `${prefix}-${counter}`;\n } while (typeof document !== \"undefined\" && document.getElementById(candidate) !== null);\n return candidate;\n}\n\n/**\n * Returns `element`'s existing `id`, or assigns it a freshly generated\n * {@link uniqueId} (with the given `prefix`) and returns that. Idempotent: an\n * element that already has an id keeps it, so consumer-authored ids are never\n * overwritten.\n *\n * @param element - The element to read or stamp an `id` onto.\n * @param prefix - Prefix forwarded to {@link uniqueId} when one must be generated.\n * @returns The element's id (existing or newly assigned).\n */\nexport function ensureId(element: Element, prefix = \"stimeo\"): string {\n if (element.id) return element.id;\n const id = uniqueId(prefix);\n element.id = id;\n return id;\n}\n","/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n","/** One temporarily controlled attribute value and the authored value it displaced. */\ninterface AttributeLeaseRecord {\n readonly original: string | null;\n written: string | null;\n}\n\n/**\n * Temporarily controls one attribute across a changing set of elements.\n *\n * The first write remembers the authored value, including the distinction between\n * an absent attribute and an authored empty string. Returning a lease restores that\n * value only while the attribute still matches the controller's last write. If a\n * consumer changed it in the meantime, the consumer owns the new value and teardown\n * leaves it alone.\n *\n * A `null` write deliberately removes the attribute while retaining the lease. This\n * is useful for derived ARIA whose valid absence is itself controller state, such as\n * an unbounded `aria-valuemin` or a blank spinbutton's `aria-valuenow`.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events.\n * A consumer that must not let a derived value become the authored baseline of a\n * cached page returns its leases from its own `turbo:before-cache` rewind, where the\n * matching `disconnect()` also releases the subscription.\n */\nexport class AttributeLease<T extends Element = Element> {\n readonly #attribute: string;\n readonly #records = new Map<T, AttributeLeaseRecord>();\n\n /** @param attribute - The attribute whose temporary values this lease owns. */\n constructor(attribute: string) {\n this.#attribute = attribute;\n }\n\n /** Writes or removes the leased attribute while preserving its authored value. */\n write(element: T, value: string | null): void {\n const existing = this.#records.get(element);\n if (existing) {\n existing.written = value;\n } else {\n this.#records.set(element, {\n original: element.getAttribute(this.#attribute),\n written: value,\n });\n }\n\n this.#reflect(element, value);\n }\n\n /** Returns one lease without overwriting a value subsequently authored by a consumer. */\n return(element: T): void {\n const record = this.#records.get(element);\n if (!record) return;\n this.#records.delete(element);\n const stillOwned = element.getAttribute(this.#attribute) === record.written;\n if (stillOwned) this.#reflect(element, record.original);\n }\n\n /** Reflects only a real value transition, avoiding self-triggered mutation work. */\n #reflect(element: T, value: string | null): void {\n if (element.getAttribute(this.#attribute) === value) return;\n if (value === null) element.removeAttribute(this.#attribute);\n else element.setAttribute(this.#attribute, value);\n }\n\n /** Returns every outstanding lease using the same ownership check as {@link return}. */\n returnAll(): void {\n for (const element of Array.from(this.#records.keys())) this.return(element);\n }\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way (the `MicrotaskCoalescer` split).\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/** Minimal event shape carrying the platform's per-event composition signal. */\nexport interface CompositionSignal {\n readonly isComposing?: boolean;\n}\n\n/** Hooks that keep component-specific work outside {@link CompositionTracker}. */\nexport interface CompositionTrackerOptions {\n /** Runs after lifecycle state is set for a `compositionstart` event. */\n readonly onStart?: (event: Event) => void;\n /** Runs after lifecycle state is cleared for a `compositionend` event. */\n readonly onEnd?: (event: Event) => void;\n}\n\n/**\n * Owns IME composition listeners and transient state for one or more event targets.\n *\n * Some browsers omit `KeyboardEvent.isComposing` on the keydown that confirms a\n * conversion. Tracking `compositionstart` through `compositionend` supplies the\n * missing lifecycle signal without relying on deprecated numeric key codes.\n * Component policy stays with the consumer: filtering, validation, and submission\n * belong in the optional {@link CompositionTrackerOptions.onEnd} callback.\n *\n * @example\n * ```ts\n * #composition = new CompositionTracker({ onEnd: () => this.filter() });\n *\n * connect(): void {\n * this.#composition.observe(this.inputTarget);\n * }\n *\n * disconnect(): void {\n * this.#composition.disconnect();\n * }\n *\n * onKeydown(event: KeyboardEvent): void {\n * if (this.#composition.isComposing(event)) return;\n * }\n * ```\n */\nexport class CompositionTracker {\n readonly #observedTargets = new Set<EventTarget>();\n readonly #activeTargets = new Set<EventTarget>();\n readonly #onStart: ((event: Event) => void) | undefined;\n readonly #onEnd: ((event: Event) => void) | undefined;\n\n constructor(options: CompositionTrackerOptions = {}) {\n this.#onStart = options.onStart;\n this.#onEnd = options.onEnd;\n }\n\n /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */\n observe(target: EventTarget): void {\n if (this.#observedTargets.has(target)) return;\n target.addEventListener(\"compositionstart\", this.#handleStart);\n target.addEventListener(\"compositionend\", this.#handleEnd);\n this.#observedTargets.add(target);\n }\n\n /** Stops tracking one target and clears any active composition it owned. */\n unobserve(target: EventTarget): void {\n if (!this.#observedTargets.delete(target)) return;\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n this.#activeTargets.delete(target);\n }\n\n /** Releases every listener and clears state so reconnect starts cleanly. */\n disconnect(): void {\n for (const target of this.#observedTargets) {\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n }\n this.#observedTargets.clear();\n this.#activeTargets.clear();\n }\n\n /** True when lifecycle tracking or the current event reports composition. */\n isComposing(event?: CompositionSignal): boolean {\n return this.#activeTargets.size > 0 || event?.isComposing === true;\n }\n\n readonly #handleStart = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.add(event.currentTarget);\n this.#onStart?.(event);\n };\n\n readonly #handleEnd = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);\n this.#onEnd?.(event);\n };\n}\n","/** The distance between a full-width ASCII code point and its half-width twin. */\nconst FULL_WIDTH_SHIFT = 0xfee0;\n\n/**\n * The half-width form of `char`, or `char` itself when it has none.\n *\n * An IME confirming in full-width mode produces U+FF01–U+FF5E (and U+3000 for\n * the space) where the page means ASCII — the digits of a phone number, the\n * letters of a code, the separators between them. Reading those as their ASCII\n * equivalents keeps confirmed text usable instead of discarding it. Characters\n * outside that block, including kana and astral code points, are returned\n * unchanged, so this never rewrites text a consumer meant to keep as typed.\n */\nexport function halfWidthChar(char: string): string {\n if (char >= \"!\" && char <= \"~\") {\n return String.fromCharCode(char.charCodeAt(0) - FULL_WIDTH_SHIFT);\n }\n return char === \" \" ? \" \" : char;\n}\n\n/** Every full-width ASCII character in `text` rewritten by {@link halfWidthChar}. */\nexport function toHalfWidth(text: string): string {\n let out = \"\";\n for (const char of text) out += halfWidthChar(char);\n return out;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { ensureId } from \"../utils/aria_ids\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { AttributeLease } from \"../utils/attribute_lease\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport { CompositionTracker } from \"../utils/composition_tracker\";\nimport { toHalfWidth } from \"../utils/half_width\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\n\n/** Single-character pattern used when a `pattern` declaration cannot compile. */\nconst DEFAULT_PATTERN = \"[0-9]\";\n\n/** Compiles one anchored single-character matcher, or `null` for a broken source. */\nfunction compilePattern(source: string): RegExp | null {\n try {\n return new RegExp(`^${source}$`);\n } catch {\n return null;\n }\n}\n\n/** Whether a press carries a modifier, which makes it the document's to handle. */\nfunction hasModifier(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\n}\n\n/**\n * The controller-derived state a consumer can observe.\n *\n * The combined value alone does not identify it: the same string spread over a\n * different number of fields reads as a different `data-state`, so completeness\n * is carried alongside the value rather than inferred from it.\n */\ninterface OtpState {\n readonly value: string;\n readonly state: string;\n}\n\n/** Compares exactly the derived state the root publishes. */\nfunction statesDiffer(left: OtpState, right: OtpState): boolean {\n return left.value !== right.value || left.state !== right.state;\n}\n\n/**\n * Headless, accessible One-Time Password / PIN input logic.\n *\n * Markup contract (identifier: `stimeo--otp`):\n * <div data-controller=\"stimeo--otp\"\n * data-stimeo--otp-pattern-value=\"[0-9]\"\n * role=\"group\" aria-label=\"One-time passcode\">\n * <input data-stimeo--otp-target=\"field\" inputmode=\"numeric\" maxlength=\"1\"\n * autocomplete=\"one-time-code\" aria-label=\"Digit 1\"\n * data-action=\"input->stimeo--otp#onInput\n * keydown->stimeo--otp#onKeydown\n * paste->stimeo--otp#onPaste\n * pointerdown->stimeo--otp#onPointerDown\" />\n * <!-- repeat one field per digit -->\n * <p data-stimeo--otp-target=\"error\" hidden>Digits only.</p>\n * <input type=\"hidden\" data-stimeo--otp-target=\"value\" name=\"otp\" />\n * </div>\n *\n * The passcode length is the number of connected `field` targets, so nothing has\n * to declare it twice and fields added or removed at runtime are absorbed.\n *\n * Entry rules:\n * - Text carrying more than one accepted character — an OS `one-time-code`\n * autofill, a password manager, an IME committing several digits, a paste —\n * is spread across the following writable fields from the entry point.\n * - `disabled` and `readonly` fields keep their value: they are never written\n * and never receive auto-advance focus, matching what the platform allows a\n * user to do by hand.\n * - Input that lands nowhere rolls the field back to the digit it last\n * committed, and is the only thing that reports `invalid` or reveals the\n * `error` target. Discarding a separator inside otherwise usable text\n * (`\"1234-56\"`) is a successful entry.\n * - Pointing at an empty field ahead of an earlier empty one lands on the\n * earliest empty field instead, so a passcode fills in order. Keyboard focus\n * is never redirected.\n *\n * `change` and `complete` dispatch `{ value: string }` and fire only when the\n * combined value actually moves — one confirmed IME character emits one event,\n * and a passcode re-completed with a different digit reports the new value.\n * State moved by adding or removing fields is the page's doing rather than an\n * edit, so it is reported as `reconcile` with the same `{ value: string }`.\n * Completeness belongs to that state: dropping a trailing empty field completes\n * a passcode whose combined value never moved, and that transition is reported\n * too, so a consumer reading `data-state` is never left behind a silent move.\n * `invalid` dispatches `{ pattern: string }` carrying the compiled pattern.\n *\n * Controller-owned output: `data-filled` on each entered field, `data-state`\n * (`empty` / `partial` / `complete`) on the root, and — while input is being\n * reported invalid — `aria-invalid`, `aria-errormessage`, `aria-describedby`,\n * and the `error` target's `hidden`. Those four are leased, so authored values\n * return on teardown and before the page is cached.\n *\n * @remarks\n * Behavior only. `connect()` reads the fields back as the source of truth, which\n * is what restores consistency after a `type=\"password\"` field returns from the\n * Turbo cache emptied, or after a native form reset. A `pattern` that cannot\n * compile falls back to `[0-9]`; the compiled matcher is built once per\n * declaration rather than per keystroke.\n */\nexport class OtpController extends Controller<HTMLElement> {\n static override targets = [\"field\", \"value\", \"error\"];\n static override values = {\n pattern: { type: String, default: DEFAULT_PATTERN },\n };\n static actions = [\"onInput\", \"onKeydown\", \"onPaste\", \"onPointerDown\", \"clear\"] as const;\n static events = [\"change\", \"complete\", \"invalid\", \"reconcile\"] as const;\n\n declare readonly fieldTargets: HTMLInputElement[];\n declare readonly valueTarget: HTMLInputElement;\n declare readonly errorTarget: HTMLElement;\n declare readonly hasValueTarget: boolean;\n declare readonly hasErrorTarget: boolean;\n\n declare patternValue: string;\n\n /** Validated matcher; the hot path never compiles a raw declaration. */\n #pattern = new RegExp(`^${DEFAULT_PATTERN}$`);\n /** Source of {@link #pattern}, reported in `invalid` so consumers can word it. */\n #patternSource = DEFAULT_PATTERN;\n /** Public state carried by the last dispatch; keeps a no-op sync silent. */\n #published: OtpState | null = null;\n /** Field whose confirming `input` after `compositionend` is already handled. */\n #confirmedField: HTMLInputElement | null = null;\n /** True between connect and disconnect, so pre-connect Value changes stay silent. */\n #connected = false;\n /** Digit each field last committed, restored when rejected input replaced it. */\n readonly #committed = new WeakMap<HTMLInputElement, string>();\n\n /** Collapses one batch of field target callbacks into a single reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileFields());\n\n readonly #ariaInvalid = new AttributeLease<HTMLInputElement>(\"aria-invalid\");\n readonly #ariaErrorMessage = new AttributeLease<HTMLInputElement>(\"aria-errormessage\");\n readonly #ariaDescribedBy = new AttributeLease<HTMLInputElement>(\"aria-describedby\");\n readonly #errorHidden = new AttributeLease<HTMLElement>(\"hidden\");\n readonly #state = new AttributeLease<HTMLElement>(\"data-state\");\n\n /** Rewinds the transient error surface before Turbo freezes the page. */\n readonly #beforeCache = new BeforeCacheReset(() => this.#clearError());\n\n /** Owns IME lifecycle state across every digit field. */\n readonly #composition = new CompositionTracker({\n onStart: () => {\n this.#confirmedField = null;\n },\n onEnd: (event) => {\n const input = this.#fieldFrom(event);\n if (!input) return;\n // The browser follows a commit with one more `input` carrying the same\n // text; marking the field lets that echo be dropped instead of rerun.\n this.#confirmedField = input;\n // `maxlength` has already cut the field down to one character, but the\n // commit itself carries the whole confirmed string — so a conversion that\n // ends in several characters still reaches the fields after this one.\n const committed = (event as CompositionEvent).data ?? \"\";\n this.#accept(input, committed.length > input.value.length ? committed : input.value);\n },\n });\n\n override connect(): void {\n this.#connected = true;\n for (const field of this.fieldTargets) this.#bind(field);\n document.addEventListener(\"reset\", this.#onReset, true);\n this.#beforeCache.activate();\n this.#reconcile.activate();\n this.#adopt();\n this.#sync();\n }\n\n override disconnect(): void {\n this.#connected = false;\n for (const field of this.fieldTargets) this.#unbind(field);\n this.#composition.disconnect();\n document.removeEventListener(\"reset\", this.#onReset, true);\n this.#beforeCache.deactivate();\n this.#reconcile.cancel();\n this.#clearError();\n this.#state.return(this.element);\n }\n\n /**\n * Stimulus lifecycle callback when a new field target enters the DOM.\n * Wires the new field and folds the wider digit count into one reconciliation,\n * which stays inert until `connect()` opens the window.\n */\n fieldTargetConnected(element: HTMLInputElement): void {\n this.#bind(element);\n this.#adoptField(element);\n this.#reconcile.schedule();\n }\n\n /** Releases a dropped field's listeners and leases, then reconciles the rest. */\n fieldTargetDisconnected(element: HTMLInputElement): void {\n this.#unbind(element);\n this.#returnFieldLeases(element);\n this.#reconcile.schedule();\n }\n\n /**\n * Re-validates a changed `pattern` declaration once and drops any entered digit\n * the new pattern no longer accepts, so the combined value stays interpretable.\n */\n patternValueChanged(): void {\n const compiled = compilePattern(this.patternValue);\n this.#patternSource = compiled ? this.patternValue : DEFAULT_PATTERN;\n this.#pattern = compiled ?? new RegExp(`^${DEFAULT_PATTERN}$`);\n if (!this.#connected) return;\n\n let dropped = false;\n for (const field of this.fieldTargets) {\n if (field.value === \"\" || !this.#isWritable(field)) continue;\n if (this.#pattern.test(field.value)) continue;\n this.#writeField(field, \"\");\n dropped = true;\n }\n if (dropped) this.#syncAndDispatch();\n }\n\n /** Handles keystroke inputs, distributes autofilled text, and advances focus. */\n onInput(event: Event): void {\n const input = this.#fieldFrom(event);\n if (!input) return;\n\n const confirmed = this.#confirmedField;\n this.#confirmedField = null;\n if (confirmed === input) return;\n\n // Guard during active composition to prevent premature focus switching\n if (this.#composition.isComposing(event as InputEvent)) return;\n\n this.#accept(input);\n }\n\n /** Handles Backspace clearing, arrows, and home/end navigation. */\n onKeydown(event: KeyboardEvent): void {\n if (isReservedArrowChord(event)) return;\n const input = this.#fieldFrom(event);\n if (!input) return;\n\n // A keyed edit always starts with this event, so no post-commit echo is pending\n this.#confirmedField = null;\n // Do not trigger keydown actions during composition\n if (this.#composition.isComposing(event)) return;\n\n const index = this.fieldTargets.indexOf(input);\n const fields = this.fieldTargets;\n // Logical, not physical. The key is normalised rather than the\n // delta negated: these two branches are not mirror images — their bounds\n // guards differ — so swapping the key keeps each guard with its own direction.\n\n switch (logicalArrowKey(event.key, this.element)) {\n case \"Backspace\":\n if (hasModifier(event)) break;\n if (input.value && this.#isWritable(input)) {\n // Filled field: clear it where it stands\n event.preventDefault();\n this.#writeField(input, \"\");\n this.#clearError();\n this.#syncAndDispatch();\n } else {\n // Empty field: step back to the previous writable digit and wipe it\n const previous = this.#writableBefore(index);\n if (previous) {\n event.preventDefault();\n this.#writeField(previous, \"\");\n previous.focus();\n this.#clearError();\n this.#syncAndDispatch();\n }\n }\n break;\n\n case \"ArrowLeft\": {\n const previous = this.#focusableBefore(index);\n if (previous) {\n event.preventDefault();\n previous.focus();\n }\n break;\n }\n\n case \"ArrowRight\": {\n const next = this.#focusableAfter(index);\n if (next) {\n event.preventDefault();\n next.focus();\n }\n break;\n }\n\n case \"Home\": {\n // Control+Home belongs to the document, not to the digit group\n if (hasModifier(event)) break;\n const first = fields.find((field) => this.#isFocusable(field));\n if (first) {\n event.preventDefault();\n first.focus();\n }\n break;\n }\n\n case \"End\": {\n if (hasModifier(event)) break;\n const last = fields\n .slice()\n .reverse()\n .find((field) => this.#isFocusable(field));\n if (last) {\n event.preventDefault();\n last.focus();\n }\n break;\n }\n\n default:\n break;\n }\n }\n\n /** Divides pasted string characters across the available input fields. */\n onPaste(event: ClipboardEvent): void {\n const input = this.#fieldFrom(event);\n if (!input) return;\n\n event.preventDefault();\n this.#confirmedField = null;\n this.#distribute(input, toHalfWidth(event.clipboardData?.getData(\"text\") ?? \"\"));\n }\n\n /**\n * Redirects a pointer landing on an empty field to the earliest empty one, so\n * a passcode is entered in order. Filled fields stay directly reachable for\n * correction, and keyboard focus is left alone.\n */\n onPointerDown(event: Event): void {\n const input = this.#fieldFrom(event);\n if (input?.value !== \"\") return;\n\n const first = this.fieldTargets.find((field) => this.#isWritable(field) && field.value === \"\");\n if (!first || first === input) return;\n\n event.preventDefault();\n first.focus();\n }\n\n /** Empties every writable field and restarts entry at the first of them. */\n clear(): void {\n for (const field of this.fieldTargets) {\n if (this.#isWritable(field)) this.#writeField(field, \"\");\n }\n this.#clearError();\n this.fieldTargets.find((field) => this.#isWritable(field))?.focus();\n this.#syncAndDispatch();\n }\n\n readonly #onFieldFocus = (event: FocusEvent): void => {\n const input = event.currentTarget as HTMLInputElement | null;\n if (input) {\n // Auto-selection enables effortless character overwrites\n input.select();\n }\n };\n\n /** Reconciles derived state after a non-cancelled reset restores the fields. */\n readonly #onReset = (event: Event): void => {\n const form = event.target;\n if (!(form instanceof HTMLFormElement) || !this.#ownedBy(form)) return;\n queueMicrotask(() => {\n if (event.defaultPrevented) return;\n this.#adopt();\n this.#syncAndDispatch();\n });\n };\n\n /** Whether a form owns at least one field or the hidden combined value. */\n #ownedBy(form: HTMLFormElement): boolean {\n if (this.fieldTargets.some((field) => field.form === form)) return true;\n return this.hasValueTarget && this.valueTarget.form === form;\n }\n\n #bind(field: HTMLInputElement): void {\n field.addEventListener(\"focus\", this.#onFieldFocus);\n this.#composition.observe(field);\n }\n\n #unbind(field: HTMLInputElement): void {\n field.removeEventListener(\"focus\", this.#onFieldFocus);\n this.#composition.unobserve(field);\n if (this.#confirmedField === field) this.#confirmedField = null;\n }\n\n /** Reads every field back so a restored or reset group starts consistent. */\n #adopt(): void {\n for (const field of this.fieldTargets) this.#adoptField(field);\n this.#clearError();\n // Nothing has been rejected yet, whatever visibility the restored DOM carries\n if (this.hasErrorTarget) this.errorTarget.setAttribute(\"hidden\", \"\");\n }\n\n /** Takes one field's current value as the truth behind its derived state. */\n #adoptField(field: HTMLInputElement): void {\n this.#committed.set(field, field.value);\n this.#markFilled(field, field.value);\n }\n\n /**\n * Absorbs a batch of field additions or removals as one state transition.\n *\n * The page, not the user, moved the state here, so it is reported as\n * `reconcile`: automation listening for `change` must not read a re-render as\n * an edit, and a passcode that happens to end up full must not fire the\n * `complete` that submits it.\n *\n * Completeness moves on its own when the field count changes: dropping a\n * trailing empty field completes a passcode whose combined value never moved,\n * and adding one un-completes it. Comparing the whole derived state, not the\n * string it contains, is what makes those transitions reportable.\n */\n #reconcileFields(): void {\n const previous = this.#published;\n const current = this.#sync();\n if (previous && !statesDiffer(previous, current)) return;\n this.dispatch(\"reconcile\", { detail: { value: current.value } });\n }\n\n /**\n * Validates the text an entry point received and distributes what it accepts.\n * `text` defaults to the field's own value; a confirmation passes the string it\n * committed, which `maxlength` would otherwise have truncated.\n */\n #accept(input: HTMLInputElement, text: string = input.value): void {\n const raw = toHalfWidth(text);\n if (raw === \"\") {\n // Emptying a field is a legitimate edit, not rejected input\n this.#writeField(input, \"\");\n this.#clearError();\n this.#syncAndDispatch();\n return;\n }\n\n this.#distribute(input, raw);\n }\n\n /**\n * Fills `text`'s accepted characters into the writable fields at and after the\n * entry point, then leaves focus on the field after the last one filled.\n */\n #distribute(from: HTMLInputElement, text: string): void {\n const accepted = Array.from(text).filter((char) => this.#pattern.test(char));\n let reached = false;\n const slots = this.fieldTargets.filter((field) => {\n reached ||= field === from;\n return reached && this.#isWritable(field);\n });\n const filled = Math.min(accepted.length, slots.length);\n\n if (filled === 0) {\n // Nothing landed: restore the digit the entry point had committed\n this.#restore(from);\n this.#showError();\n this.#sync();\n return;\n }\n\n for (let i = 0; i < filled; i++) {\n const field = slots[i];\n const char = accepted[i];\n if (field && char) this.#writeField(field, char);\n }\n\n const last = slots[filled - 1];\n if (last) (this.#writableAfter(last) ?? last).focus();\n\n this.#clearError();\n this.#syncAndDispatch();\n }\n\n /** Restores the digit a field committed before rejected input replaced it. */\n #restore(field: HTMLInputElement): void {\n this.#writeField(field, this.#committed.get(field) ?? \"\");\n }\n\n /** Commits one field's value and the derived hook that reports it as entered. */\n #writeField(field: HTMLInputElement, value: string): void {\n field.value = value;\n this.#committed.set(field, value);\n this.#markFilled(field, value);\n }\n\n #markFilled(field: HTMLInputElement, value: string): void {\n if (value) field.setAttribute(\"data-filled\", \"true\");\n else field.removeAttribute(\"data-filled\");\n }\n\n #isWritable(field: HTMLInputElement): boolean {\n return !field.disabled && !field.readOnly;\n }\n\n #isFocusable(field: HTMLInputElement): boolean {\n return !field.disabled;\n }\n\n #writableAfter(field: HTMLInputElement): HTMLInputElement | null {\n const fields = this.fieldTargets;\n return fields.slice(fields.indexOf(field) + 1).find((next) => this.#isWritable(next)) ?? null;\n }\n\n #writableBefore(index: number): HTMLInputElement | null {\n return this.#before(index).find((field) => this.#isWritable(field)) ?? null;\n }\n\n #focusableAfter(index: number): HTMLInputElement | null {\n return this.fieldTargets.slice(index + 1).find((field) => this.#isFocusable(field)) ?? null;\n }\n\n #focusableBefore(index: number): HTMLInputElement | null {\n return this.#before(index).find((field) => this.#isFocusable(field)) ?? null;\n }\n\n /** Fields before `index`, nearest first; empty at the first field. */\n #before(index: number): HTMLInputElement[] {\n return this.fieldTargets.slice(0, Math.max(index, 0)).reverse();\n }\n\n /** The event's field target, or `null` when the wiring points somewhere else. */\n #fieldFrom(event: Event): HTMLInputElement | null {\n const input = event.currentTarget;\n return this.fieldTargets.find((field) => field === input) ?? null;\n }\n\n #combinedValue(): string {\n return this.fieldTargets.map((field) => field.value).join(\"\");\n }\n\n /** Every field carries a character, and there is at least one field. */\n #isComplete(): boolean {\n const fields = this.fieldTargets;\n return fields.length > 0 && fields.every((field) => field.value.length > 0);\n }\n\n /**\n * Mirrors the combined value into the form and the root's readable state, and\n * records what was published so the next pass can compare against it.\n */\n #sync(): OtpState {\n const combined = this.#combinedValue();\n\n if (this.hasValueTarget) {\n this.valueTarget.value = combined;\n }\n const state = this.#stateName(combined);\n this.#state.write(this.element, state);\n\n const published: OtpState = { value: combined, state };\n this.#published = published;\n return published;\n }\n\n #stateName(combined: string): string {\n if (combined.length === 0) return \"empty\";\n return this.#isComplete() ? \"complete\" : \"partial\";\n }\n\n #syncAndDispatch(): void {\n const previous = this.#published;\n const { value: combined } = this.#sync();\n if (previous?.value === combined) return;\n\n this.dispatch(\"change\", { detail: { value: combined } });\n\n // Completed state when every field carries a character\n if (this.#isComplete()) {\n this.dispatch(\"complete\", { detail: { value: combined } });\n }\n }\n\n /** Surfaces rejected input on every field and on the optional error target. */\n #showError(): void {\n const errorId = this.hasErrorTarget ? ensureId(this.errorTarget, \"stimeo--otp-error\") : null;\n\n for (const field of this.fieldTargets) {\n this.#ariaInvalid.write(field, \"true\");\n if (!errorId) continue;\n this.#ariaErrorMessage.write(field, errorId);\n // Assistive tech without aria-errormessage support still reads a description\n this.#ariaDescribedBy.write(field, this.#describedByWith(field, errorId));\n }\n if (this.hasErrorTarget) this.#errorHidden.write(this.errorTarget, null);\n\n // Behavior only: emit a neutral payload and let the consumer compose/localize\n // the user-facing message. The pattern is reported so consumers can word it.\n this.dispatch(\"invalid\", { detail: { pattern: this.#patternSource } });\n }\n\n /** Returns every error lease, restoring the authored error surface. */\n #clearError(): void {\n this.#ariaInvalid.returnAll();\n this.#ariaErrorMessage.returnAll();\n this.#ariaDescribedBy.returnAll();\n this.#errorHidden.returnAll();\n }\n\n #returnFieldLeases(field: HTMLInputElement): void {\n this.#ariaInvalid.return(field);\n this.#ariaErrorMessage.return(field);\n this.#ariaDescribedBy.return(field);\n }\n\n /** The field's own description tokens with the error id appended once. */\n #describedByWith(field: HTMLInputElement, errorId: string): string {\n const tokens = (field.getAttribute(\"aria-describedby\") ?? \"\")\n .split(/\\s+/)\n .filter((token) => token.length > 0 && token !== errorId);\n return [...tokens, errorId].join(\" \");\n }\n}\n"]}
|
|
@@ -11,15 +11,23 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
11
11
|
* <details data-reset-attr="open">…</details> <!-- remove these attributes -->
|
|
12
12
|
* <div data-reset-class="is-open is-loading">…</div> <!-- remove these classes -->
|
|
13
13
|
* <form data-reset-form>…</form> <!-- form.reset() -->
|
|
14
|
-
* <input data-reset-value> <!--
|
|
14
|
+
* <input data-reset-value> <!-- back to its authored state -->
|
|
15
15
|
* <div data-reset-hidden>transient overlay</div> <!-- re-hide -->
|
|
16
16
|
* <div data-reset-remove>flash toast</div> <!-- drop from the DOM -->
|
|
17
17
|
* </body>
|
|
18
18
|
*
|
|
19
|
+
* `scope` narrows the sweep to the first descendant matching that CSS selector;
|
|
20
|
+
* left empty (the default) it covers the whole element. A selector the engine
|
|
21
|
+
* cannot read falls back to that default rather than taking the sweep down with
|
|
22
|
+
* it, and so does one that matches nothing.
|
|
23
|
+
*
|
|
24
|
+
* `reset` dispatches `{}`; `request` dispatches `{}`.
|
|
25
|
+
*
|
|
19
26
|
* @remarks
|
|
20
27
|
* Behavior only and **idempotent** — every run converges on the same initial state,
|
|
21
28
|
* holding no module-scope state. It does the cross-cutting DOM cleanup directly
|
|
22
|
-
* (attribute removal, class removal,
|
|
29
|
+
* (attribute removal, class removal, restoring a field to its authored state,
|
|
30
|
+
* re-hiding, node removal) and, when
|
|
23
31
|
* `dispatchReset` is on, fires `stimeo--reset-before-cache:request` so individual
|
|
24
32
|
* Stimeo controllers can run their own close logic. The `turbo:before-cache`
|
|
25
33
|
* listener is paired to `connect()` / `disconnect()` so it never double-registers or
|
|
@@ -41,12 +49,27 @@ declare class ResetBeforeCacheController extends Controller<HTMLElement> {
|
|
|
41
49
|
static events: readonly ["reset", "request"];
|
|
42
50
|
scopeValue: string;
|
|
43
51
|
dispatchResetValue: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Validates the scope declaration once, keeping only a selector the engine can
|
|
54
|
+
* read.
|
|
55
|
+
*
|
|
56
|
+
* A selector reads back as an ordinary string, so a malformed one survives
|
|
57
|
+
* until it is handed to the DOM — and this part runs from a single listener
|
|
58
|
+
* whose whole job is to keep a cached page from freezing. Falling back to the
|
|
59
|
+
* default keeps that job running with a visible, findable result instead of
|
|
60
|
+
* silently taking the sweep down.
|
|
61
|
+
*/
|
|
62
|
+
scopeValueChanged(): void;
|
|
44
63
|
connect(): void;
|
|
45
64
|
disconnect(): void;
|
|
46
65
|
/**
|
|
47
66
|
* Resets transient UI within scope to its initial state. Asks controllers to
|
|
48
67
|
* close (via `request`) first, then applies the declarative `data-reset-*` cleanup,
|
|
49
68
|
* and finally emits `reset`. Safe to call any number of times (idempotent).
|
|
69
|
+
*
|
|
70
|
+
* `dispatchReset` decides only whether the `request` ask goes out; the cleanup
|
|
71
|
+
* and the closing `reset` run either way. Both the listener and this action
|
|
72
|
+
* reach the same sweep, so `reset` is emitted for a manual call too.
|
|
50
73
|
*/
|
|
51
74
|
reset(): void;
|
|
52
75
|
}
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
3
|
// src/controllers/reset_before_cache_controller.ts
|
|
4
|
+
var STATELESS_INPUT_TYPES = /* @__PURE__ */ new Set(["hidden", "submit", "reset", "button", "image"]);
|
|
5
|
+
function restoreField(element) {
|
|
6
|
+
if (element instanceof HTMLTextAreaElement) {
|
|
7
|
+
element.value = element.defaultValue;
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (element instanceof HTMLSelectElement) {
|
|
11
|
+
for (const option of element.options) option.selected = option.hasAttribute("selected");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (element instanceof HTMLInputElement) {
|
|
15
|
+
if (element.type === "checkbox" || element.type === "radio") {
|
|
16
|
+
element.checked = element.defaultChecked;
|
|
17
|
+
} else if (element.type === "file") {
|
|
18
|
+
element.value = "";
|
|
19
|
+
} else if (!STATELESS_INPUT_TYPES.has(element.type)) {
|
|
20
|
+
element.value = element.defaultValue;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
4
24
|
var ResetBeforeCacheController = class extends Controller {
|
|
5
25
|
static values = {
|
|
6
26
|
scope: { type: String, default: "" },
|
|
@@ -8,8 +28,32 @@ var ResetBeforeCacheController = class extends Controller {
|
|
|
8
28
|
};
|
|
9
29
|
static actions = ["reset"];
|
|
10
30
|
static events = ["reset", "request"];
|
|
31
|
+
/** The `scope` declaration after validation; empty when it cannot be parsed. */
|
|
32
|
+
#scopeSelector = "";
|
|
11
33
|
/** Runs the reset just before Turbo caches the snapshot. */
|
|
12
34
|
#onBeforeCache = () => this.reset();
|
|
35
|
+
/**
|
|
36
|
+
* Validates the scope declaration once, keeping only a selector the engine can
|
|
37
|
+
* read.
|
|
38
|
+
*
|
|
39
|
+
* A selector reads back as an ordinary string, so a malformed one survives
|
|
40
|
+
* until it is handed to the DOM — and this part runs from a single listener
|
|
41
|
+
* whose whole job is to keep a cached page from freezing. Falling back to the
|
|
42
|
+
* default keeps that job running with a visible, findable result instead of
|
|
43
|
+
* silently taking the sweep down.
|
|
44
|
+
*/
|
|
45
|
+
scopeValueChanged() {
|
|
46
|
+
const selector = this.scopeValue;
|
|
47
|
+
if (selector.length > 0) {
|
|
48
|
+
try {
|
|
49
|
+
this.element.matches(selector);
|
|
50
|
+
this.#scopeSelector = selector;
|
|
51
|
+
return;
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
this.#scopeSelector = "";
|
|
56
|
+
}
|
|
13
57
|
connect() {
|
|
14
58
|
document.addEventListener("turbo:before-cache", this.#onBeforeCache);
|
|
15
59
|
}
|
|
@@ -20,6 +64,10 @@ var ResetBeforeCacheController = class extends Controller {
|
|
|
20
64
|
* Resets transient UI within scope to its initial state. Asks controllers to
|
|
21
65
|
* close (via `request`) first, then applies the declarative `data-reset-*` cleanup,
|
|
22
66
|
* and finally emits `reset`. Safe to call any number of times (idempotent).
|
|
67
|
+
*
|
|
68
|
+
* `dispatchReset` decides only whether the `request` ask goes out; the cleanup
|
|
69
|
+
* and the closing `reset` run either way. Both the listener and this action
|
|
70
|
+
* reach the same sweep, so `reset` is emitted for a manual call too.
|
|
23
71
|
*/
|
|
24
72
|
reset() {
|
|
25
73
|
const root = this.#scopeRoot();
|
|
@@ -38,9 +86,7 @@ var ResetBeforeCacheController = class extends Controller {
|
|
|
38
86
|
if (element instanceof HTMLFormElement) element.reset();
|
|
39
87
|
}
|
|
40
88
|
for (const element of root.querySelectorAll("[data-reset-value]")) {
|
|
41
|
-
|
|
42
|
-
element.value = "";
|
|
43
|
-
}
|
|
89
|
+
restoreField(element);
|
|
44
90
|
}
|
|
45
91
|
for (const element of root.querySelectorAll("[data-reset-hidden]")) {
|
|
46
92
|
element.hidden = true;
|
|
@@ -52,8 +98,8 @@ var ResetBeforeCacheController = class extends Controller {
|
|
|
52
98
|
}
|
|
53
99
|
/** The scan root: a `scope` descendant when set, else the controller element. */
|
|
54
100
|
#scopeRoot() {
|
|
55
|
-
if (!this
|
|
56
|
-
return this.element.querySelector(this
|
|
101
|
+
if (!this.#scopeSelector) return this.element;
|
|
102
|
+
return this.element.querySelector(this.#scopeSelector) ?? this.element;
|
|
57
103
|
}
|
|
58
104
|
};
|
|
59
105
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/controllers/reset_before_cache_controller.ts"],"names":[],"mappings":";;;AA2BO,IAAM,0BAAA,GAAN,cAAyC,UAAA,CAAwB;AAAA,EACtE,OAAgB,MAAA,GAAS;AAAA,IACvB,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,EAAA,EAAG;AAAA,IACnC,aAAA,EAAe,EAAE,IAAA,EAAM,OAAA,EAAS,SAAS,IAAA;AAAK,GAChD;AAAA,EACA,OAAO,OAAA,GAAU,CAAC,OAAO,CAAA;AAAA,EACzB,OAAO,MAAA,GAAS,CAAC,OAAA,EAAS,SAAS,CAAA;AAAA;AAAA,EAM1B,cAAA,GAAiB,MAAY,IAAA,CAAK,KAAA,EAAM;AAAA,EAExC,OAAA,GAAgB;AACvB,IAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAA,EAAsB,IAAA,CAAK,cAAc,CAAA;AAAA,EACrE;AAAA,EAES,UAAA,GAAmB;AAC1B,IAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAA,EAAsB,IAAA,CAAK,cAAc,CAAA;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAA,GAAc;AACZ,IAAA,MAAM,IAAA,GAAO,KAAK,UAAA,EAAW;AAE7B,IAAA,IAAI,IAAA,CAAK,kBAAA,EAAoB,IAAA,CAAK,QAAA,CAAS,SAAS,CAAA;AAEpD,IAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,gBAAA,CAAiB,mBAAmB,CAAA,EAAG;AAChE,MAAA,KAAA,MAAW,IAAA,IAAA,CAAS,QAAQ,YAAA,CAAa,iBAAiB,KAAK,EAAA,EAAI,KAAA,CAAM,KAAK,CAAA,EAAG;AAC/E,QAAA,IAAI,IAAA,EAAM,OAAA,CAAQ,eAAA,CAAgB,IAAI,CAAA;AAAA,MACxC;AAAA,IACF;AACA,IAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,gBAAA,CAAiB,oBAAoB,CAAA,EAAG;AACjE,MAAA,KAAA,MAAW,KAAA,IAAA,CAAU,QAAQ,YAAA,CAAa,kBAAkB,KAAK,EAAA,EAAI,KAAA,CAAM,KAAK,CAAA,EAAG;AACjF,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,SAAA,CAAU,MAAA,CAAO,KAAK,CAAA;AAAA,MAC3C;AAAA,IACF;AACA,IAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,gBAAA,CAAiB,mBAAmB,CAAA,EAAG;AAChE,MAAA,IAAI,OAAA,YAAmB,eAAA,EAAiB,OAAA,CAAQ,KAAA,EAAM;AAAA,IACxD;AACA,IAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,gBAAA,CAAiB,oBAAoB,CAAA,EAAG;AACjE,MAAA,IACE,OAAA,YAAmB,gBAAA,IACnB,OAAA,YAAmB,mBAAA,IACnB,mBAAmB,iBAAA,EACnB;AACA,QAAA,OAAA,CAAQ,KAAA,GAAQ,EAAA;AAAA,MAClB;AAAA,IACF;AACA,IAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,gBAAA,CAA8B,qBAAqB,CAAA,EAAG;AAC/E,MAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AAAA,IACnB;AAEA,IAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,gBAAA,CAAiB,qBAAqB,CAAA,EAAG;AAClE,MAAA,OAAA,CAAQ,MAAA,EAAO;AAAA,IACjB;AAEA,IAAA,IAAA,CAAK,SAAS,OAAO,CAAA;AAAA,EACvB;AAAA;AAAA,EAGA,UAAA,GAAsB;AACpB,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,OAAO,IAAA,CAAK,OAAA;AAClC,IAAA,OAAO,KAAK,OAAA,CAAQ,aAAA,CAAc,IAAA,CAAK,UAAU,KAAK,IAAA,CAAK,OAAA;AAAA,EAC7D;AACF","file":"reset_before_cache_controller.js","sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\n\n/**\n * Headless **before-cache reset** — the most Hotwire-specific gap part (no APG\n * pattern). On `turbo:before-cache` it returns transient UI (open menus/modals,\n * typed-in values, spinning indicators) to its initial state, so a page restored by\n * the Back button is not frozen mid-interaction. Place one on `<body>`.\n *\n * Markup contract (identifier: `stimeo--reset-before-cache`):\n * <body data-controller=\"stimeo--reset-before-cache\">\n * <details data-reset-attr=\"open\">…</details> <!-- remove these attributes -->\n * <div data-reset-class=\"is-open is-loading\">…</div> <!-- remove these classes -->\n * <form data-reset-form>…</form> <!-- form.reset() -->\n * <input data-reset-value> <!-- clear the value -->\n * <div data-reset-hidden>transient overlay</div> <!-- re-hide -->\n * <div data-reset-remove>flash toast</div> <!-- drop from the DOM -->\n * </body>\n *\n * @remarks\n * Behavior only and **idempotent** — every run converges on the same initial state,\n * holding no module-scope state. It does the cross-cutting DOM cleanup directly\n * (attribute removal, class removal, value clearing, re-hiding, node removal) and, when\n * `dispatchReset` is on, fires `stimeo--reset-before-cache:request` so individual\n * Stimeo controllers can run their own close logic. The `turbo:before-cache`\n * listener is paired to `connect()` / `disconnect()` so it never double-registers or\n * leaks. {@link reset} is also a public action for manual triggering.\n */\nexport class ResetBeforeCacheController extends Controller<HTMLElement> {\n static override values = {\n scope: { type: String, default: \"\" },\n dispatchReset: { type: Boolean, default: true },\n };\n static actions = [\"reset\"] as const;\n static events = [\"reset\", \"request\"] as const;\n\n declare scopeValue: string;\n declare dispatchResetValue: boolean;\n\n /** Runs the reset just before Turbo caches the snapshot. */\n readonly #onBeforeCache = (): void => this.reset();\n\n override connect(): void {\n document.addEventListener(\"turbo:before-cache\", this.#onBeforeCache);\n }\n\n override disconnect(): void {\n document.removeEventListener(\"turbo:before-cache\", this.#onBeforeCache);\n }\n\n /**\n * Resets transient UI within scope to its initial state. Asks controllers to\n * close (via `request`) first, then applies the declarative `data-reset-*` cleanup,\n * and finally emits `reset`. Safe to call any number of times (idempotent).\n */\n reset(): void {\n const root = this.#scopeRoot();\n\n if (this.dispatchResetValue) this.dispatch(\"request\");\n\n for (const element of root.querySelectorAll(\"[data-reset-attr]\")) {\n for (const name of (element.getAttribute(\"data-reset-attr\") ?? \"\").split(/\\s+/)) {\n if (name) element.removeAttribute(name);\n }\n }\n for (const element of root.querySelectorAll(\"[data-reset-class]\")) {\n for (const token of (element.getAttribute(\"data-reset-class\") ?? \"\").split(/\\s+/)) {\n if (token) element.classList.remove(token);\n }\n }\n for (const element of root.querySelectorAll(\"[data-reset-form]\")) {\n if (element instanceof HTMLFormElement) element.reset();\n }\n for (const element of root.querySelectorAll(\"[data-reset-value]\")) {\n if (\n element instanceof HTMLInputElement ||\n element instanceof HTMLTextAreaElement ||\n element instanceof HTMLSelectElement\n ) {\n element.value = \"\";\n }\n }\n for (const element of root.querySelectorAll<HTMLElement>(\"[data-reset-hidden]\")) {\n element.hidden = true;\n }\n // Removal runs last so it cannot drop a node another rule still needed to visit.\n for (const element of root.querySelectorAll(\"[data-reset-remove]\")) {\n element.remove();\n }\n\n this.dispatch(\"reset\");\n }\n\n /** The scan root: a `scope` descendant when set, else the controller element. */\n #scopeRoot(): Element {\n if (!this.scopeValue) return this.element;\n return this.element.querySelector(this.scopeValue) ?? this.element;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/controllers/reset_before_cache_controller.ts"],"names":[],"mappings":"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","file":"reset_before_cache_controller.js","sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\n\n/** Field types whose state is authored markup rather than something a user changed. */\nconst STATELESS_INPUT_TYPES = new Set([\"hidden\", \"submit\", \"reset\", \"button\", \"image\"]);\n\n/**\n * Returns one field to the state its markup declared, discarding what the user\n * changed — the single-field form of a form reset.\n *\n * Assigning `\"\"` would not do this. For a text field it throws away the authored\n * value; for a checkbox, a radio, or a hidden field the `value` IDL attribute\n * writes straight through to the content attribute, so the markup itself is\n * rewritten while the checkedness (the part the user actually moved) is left\n * alone; and for a select it can leave nothing selected at all — a state the page\n * never had.\n */\nfunction restoreField(element: Element): void {\n if (element instanceof HTMLTextAreaElement) {\n element.value = element.defaultValue;\n return;\n }\n if (element instanceof HTMLSelectElement) {\n // An option's declared selectedness is its `selected` content attribute.\n for (const option of element.options) option.selected = option.hasAttribute(\"selected\");\n return;\n }\n if (element instanceof HTMLInputElement) {\n if (element.type === \"checkbox\" || element.type === \"radio\") {\n element.checked = element.defaultChecked;\n } else if (element.type === \"file\") {\n // A file field takes no value but the empty one, so assigning its default\n // back would throw on markup that declared one.\n element.value = \"\";\n } else if (!STATELESS_INPUT_TYPES.has(element.type)) {\n element.value = element.defaultValue;\n }\n }\n}\n\n/**\n * Headless **before-cache reset** — the most Hotwire-specific gap part (no APG\n * pattern). On `turbo:before-cache` it returns transient UI (open menus/modals,\n * typed-in values, spinning indicators) to its initial state, so a page restored by\n * the Back button is not frozen mid-interaction. Place one on `<body>`.\n *\n * Markup contract (identifier: `stimeo--reset-before-cache`):\n * <body data-controller=\"stimeo--reset-before-cache\">\n * <details data-reset-attr=\"open\">…</details> <!-- remove these attributes -->\n * <div data-reset-class=\"is-open is-loading\">…</div> <!-- remove these classes -->\n * <form data-reset-form>…</form> <!-- form.reset() -->\n * <input data-reset-value> <!-- back to its authored state -->\n * <div data-reset-hidden>transient overlay</div> <!-- re-hide -->\n * <div data-reset-remove>flash toast</div> <!-- drop from the DOM -->\n * </body>\n *\n * `scope` narrows the sweep to the first descendant matching that CSS selector;\n * left empty (the default) it covers the whole element. A selector the engine\n * cannot read falls back to that default rather than taking the sweep down with\n * it, and so does one that matches nothing.\n *\n * `reset` dispatches `{}`; `request` dispatches `{}`.\n *\n * @remarks\n * Behavior only and **idempotent** — every run converges on the same initial state,\n * holding no module-scope state. It does the cross-cutting DOM cleanup directly\n * (attribute removal, class removal, restoring a field to its authored state,\n * re-hiding, node removal) and, when\n * `dispatchReset` is on, fires `stimeo--reset-before-cache:request` so individual\n * Stimeo controllers can run their own close logic. The `turbo:before-cache`\n * listener is paired to `connect()` / `disconnect()` so it never double-registers or\n * leaks. {@link reset} is also a public action for manual triggering.\n */\nexport class ResetBeforeCacheController extends Controller<HTMLElement> {\n static override values = {\n scope: { type: String, default: \"\" },\n dispatchReset: { type: Boolean, default: true },\n };\n static actions = [\"reset\"] as const;\n static events = [\"reset\", \"request\"] as const;\n\n declare scopeValue: string;\n declare dispatchResetValue: boolean;\n\n /** The `scope` declaration after validation; empty when it cannot be parsed. */\n #scopeSelector = \"\";\n\n /** Runs the reset just before Turbo caches the snapshot. */\n readonly #onBeforeCache = (): void => this.reset();\n\n /**\n * Validates the scope declaration once, keeping only a selector the engine can\n * read.\n *\n * A selector reads back as an ordinary string, so a malformed one survives\n * until it is handed to the DOM — and this part runs from a single listener\n * whose whole job is to keep a cached page from freezing. Falling back to the\n * default keeps that job running with a visible, findable result instead of\n * silently taking the sweep down.\n */\n scopeValueChanged(): void {\n const selector = this.scopeValue;\n if (selector.length > 0) {\n try {\n this.element.matches(selector);\n this.#scopeSelector = selector;\n return;\n } catch {\n // Unparsable selector: fall through to the default below.\n }\n }\n this.#scopeSelector = \"\";\n }\n\n override connect(): void {\n document.addEventListener(\"turbo:before-cache\", this.#onBeforeCache);\n }\n\n override disconnect(): void {\n document.removeEventListener(\"turbo:before-cache\", this.#onBeforeCache);\n }\n\n /**\n * Resets transient UI within scope to its initial state. Asks controllers to\n * close (via `request`) first, then applies the declarative `data-reset-*` cleanup,\n * and finally emits `reset`. Safe to call any number of times (idempotent).\n *\n * `dispatchReset` decides only whether the `request` ask goes out; the cleanup\n * and the closing `reset` run either way. Both the listener and this action\n * reach the same sweep, so `reset` is emitted for a manual call too.\n */\n reset(): void {\n const root = this.#scopeRoot();\n\n if (this.dispatchResetValue) this.dispatch(\"request\");\n\n for (const element of root.querySelectorAll(\"[data-reset-attr]\")) {\n for (const name of (element.getAttribute(\"data-reset-attr\") ?? \"\").split(/\\s+/)) {\n if (name) element.removeAttribute(name);\n }\n }\n for (const element of root.querySelectorAll(\"[data-reset-class]\")) {\n for (const token of (element.getAttribute(\"data-reset-class\") ?? \"\").split(/\\s+/)) {\n if (token) element.classList.remove(token);\n }\n }\n for (const element of root.querySelectorAll(\"[data-reset-form]\")) {\n if (element instanceof HTMLFormElement) element.reset();\n }\n for (const element of root.querySelectorAll(\"[data-reset-value]\")) {\n restoreField(element);\n }\n for (const element of root.querySelectorAll<HTMLElement>(\"[data-reset-hidden]\")) {\n element.hidden = true;\n }\n // Removal runs last so it cannot drop a node another rule still needed to visit.\n for (const element of root.querySelectorAll(\"[data-reset-remove]\")) {\n element.remove();\n }\n\n this.dispatch(\"reset\");\n }\n\n /** The scan root: a `scope` descendant when set, else the controller element. */\n #scopeRoot(): Element {\n if (!this.#scopeSelector) return this.element;\n return this.element.querySelector(this.#scopeSelector) ?? this.element;\n }\n}\n"]}
|
|
@@ -7,6 +7,7 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
7
7
|
* <div data-controller="stimeo--resizable"
|
|
8
8
|
* data-stimeo--resizable-min-value="20"
|
|
9
9
|
* data-stimeo--resizable-max-value="80"
|
|
10
|
+
* data-stimeo--resizable-step-value="1"
|
|
10
11
|
* data-stimeo--resizable-value-value="50">
|
|
11
12
|
* <div data-stimeo--resizable-target="primary" id="pane-1">Pane A</div>
|
|
12
13
|
* <div role="separator" tabindex="0" aria-orientation="vertical"
|
|
@@ -21,8 +22,10 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
21
22
|
* Implements the WAI-ARIA APG **Window Splitter** pattern:
|
|
22
23
|
* - Robust dragging track using W3C `setPointerCapture` to ensure uninterrupted dragging
|
|
23
24
|
* even when pointers quickly stray outside the separator area.
|
|
24
|
-
* -
|
|
25
|
-
*
|
|
25
|
+
* - Arrow keys move the divider by `step` percent, along the axis
|
|
26
|
+
* `aria-orientation` names; `Home` / `End` jump to the ends of the range.
|
|
27
|
+
* - `Enter` collapses the primary pane to the minimum and puts it back where it
|
|
28
|
+
* was, which is what the pattern means by restoring a previous position.
|
|
26
29
|
* - Root-level CSS custom property `--stimeo--resizable-fraction` (0..1) driving
|
|
27
30
|
* presentation styles.
|
|
28
31
|
* - `F6` cycles focus through the panes, which the pattern lists as optional.
|
|
@@ -32,6 +35,16 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
32
35
|
* @remarks
|
|
33
36
|
* Behavior only. The controller adjusts the CSS custom property on the root element,
|
|
34
37
|
* updates ARIA values on the separator, and emits `stimeo--resizable:change` events.
|
|
38
|
+
*
|
|
39
|
+
* Both the range and the position are percentages. A bound that is not a finite
|
|
40
|
+
* number falls back to its Value default, a maximum below the minimum collapses
|
|
41
|
+
* onto that minimum, and a step that is not a positive finite number falls back
|
|
42
|
+
* to `1` — so an unreadable declaration narrows what the widget can do without
|
|
43
|
+
* ever publishing `NaN` to CSS or to assistive tech.
|
|
44
|
+
*
|
|
45
|
+
* `aria-orientation` is the author's, and its absence means `horizontal` — the
|
|
46
|
+
* value ARIA gives a separator that does not say. Reading any other default here
|
|
47
|
+
* would make the announced axis and the answering arrow keys disagree.
|
|
35
48
|
*/
|
|
36
49
|
declare class ResizableController extends Controller<HTMLElement> {
|
|
37
50
|
#private;
|
|
@@ -69,16 +82,19 @@ declare class ResizableController extends Controller<HTMLElement> {
|
|
|
69
82
|
connect(): void;
|
|
70
83
|
/** Cancels any active pointer drag so listeners never leak past disconnect. */
|
|
71
84
|
disconnect(): void;
|
|
72
|
-
/**
|
|
73
|
-
* Stimulus lifecycle callback when the valueValue changes.
|
|
74
|
-
* Keeps CSS fractions and ARIA status completely aligned.
|
|
75
|
-
*/
|
|
85
|
+
/** Re-renders when application code (or a Turbo morph) changes `value` at runtime. */
|
|
76
86
|
valueValueChanged(): void;
|
|
87
|
+
/** Re-renders when application code (or a Turbo morph) changes `min` at runtime. */
|
|
88
|
+
minValueChanged(): void;
|
|
89
|
+
/** Re-renders when application code (or a Turbo morph) changes `max` at runtime. */
|
|
90
|
+
maxValueChanged(): void;
|
|
91
|
+
/** Re-publishes range and position onto a separator swapped in after connect. */
|
|
92
|
+
separatorTargetConnected(): void;
|
|
77
93
|
/** Starts active pointer drag tracking and locks capture. */
|
|
78
94
|
onPointerDown(event: PointerEvent): void;
|
|
79
95
|
/** Keydown adjustments for ArrowUp/Down/Left/Right and Home/End. */
|
|
80
96
|
onKeydown(event: KeyboardEvent): void;
|
|
81
|
-
/** Double-click or Enter to collapse
|
|
97
|
+
/** Double-click or Enter to collapse the primary pane, or put it back. */
|
|
82
98
|
toggle(): void;
|
|
83
99
|
}
|
|
84
100
|
|