stimeo-ui 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +212 -0
- package/README.md +120 -0
- package/dist/cable/index.js +123 -29
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +30 -3
- package/dist/controllers/accordion_controller.js +98 -9
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +8 -7
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +3 -2
- package/dist/controllers/announcer_controller.js +96 -62
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js +83 -7
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +1 -1
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +38 -11
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +4 -4
- package/dist/controllers/bulk_select_controller.js +7 -6
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +101 -23
- package/dist/controllers/calendar_controller.js +340 -123
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +67 -22
- package/dist/controllers/carousel_controller.js +263 -38
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +1 -1
- package/dist/controllers/character_counter_controller.js +40 -2
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.js +81 -12
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +28 -2
- package/dist/controllers/clipboard_controller.js +63 -5
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +25 -1
- package/dist/controllers/collapsible_controller.js +99 -14
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +29 -8
- package/dist/controllers/color_picker_controller.js +80 -34
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +10 -1
- package/dist/controllers/combobox_controller.js +106 -16
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +3 -3
- package/dist/controllers/command_palette_controller.js +35 -3
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js +85 -17
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.js +3 -0
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +6 -0
- package/dist/controllers/context_menu_controller.js +32 -12
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +30 -1
- package/dist/controllers/countdown_controller.js +129 -26
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +77 -16
- package/dist/controllers/currency_input_controller.js +221 -67
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +63 -18
- package/dist/controllers/data_grid_controller.js +195 -29
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +41 -6
- package/dist/controllers/date_range_picker_controller.js +151 -30
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +10 -3
- package/dist/controllers/dialog_controller.js +35 -8
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.js +22 -4
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +2 -2
- package/dist/controllers/dirty_form_controller.js +46 -13
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js +1 -0
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +18 -10
- package/dist/controllers/drawer_controller.js +54 -19
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +9 -3
- package/dist/controllers/dropdown_controller.js +36 -9
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.js +34 -0
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js +144 -51
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +10 -4
- package/dist/controllers/filter_controller.js +20 -6
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +26 -6
- package/dist/controllers/flash_controller.js +432 -71
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.js +1 -0
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +7 -5
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +19 -13
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.js +45 -8
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js +82 -25
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +10 -2
- package/dist/controllers/hover_card_controller.js +40 -14
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +16 -3
- package/dist/controllers/idle_controller.js +90 -5
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +5 -2
- package/dist/controllers/input_mask_controller.js +65 -9
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.js +3 -0
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.js +11 -2
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +50 -8
- package/dist/controllers/listbox_controller.js +203 -45
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.js +10 -5
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +3 -3
- package/dist/controllers/masonry_controller.js +31 -15
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +9 -3
- package/dist/controllers/menu_controller.js +45 -16
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +11 -0
- package/dist/controllers/menubar_controller.js +58 -24
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.js +9 -5
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +18 -3
- package/dist/controllers/multi_select_controller.js +278 -104
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +11 -0
- package/dist/controllers/navigation_menu_controller.js +48 -15
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js +37 -8
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.js +9 -1
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +36 -8
- package/dist/controllers/number_input_controller.js +124 -21
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +42 -5
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +22 -7
- package/dist/controllers/otp_controller.js +198 -55
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
- package/dist/controllers/overflow_indicator_controller.js +115 -21
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +26 -6
- package/dist/controllers/overflow_menu_controller.js +141 -44
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +19 -11
- package/dist/controllers/pagination_controller.js +74 -28
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +15 -1
- package/dist/controllers/password_reveal_controller.js +59 -2
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/persist_controller.js +30 -8
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +131 -52
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +9 -3
- package/dist/controllers/popover_controller.js +45 -11
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +1 -1
- package/dist/controllers/portal_controller.js +6 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.js +16 -1
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.js +8 -4
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +6 -4
- package/dist/controllers/radio_group_controller.js +42 -17
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +49 -1
- package/dist/controllers/range_slider_controller.js +88 -42
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +14 -3
- package/dist/controllers/rating_controller.js +39 -15
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +24 -2
- package/dist/controllers/read_more_controller.js +100 -7
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.js +65 -19
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.js +10 -5
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +16 -2
- package/dist/controllers/resizable_controller.js +82 -22
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js +75 -27
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.js +37 -16
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.js +49 -30
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +3 -2
- package/dist/controllers/scrollspy_controller.js +71 -26
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +41 -14
- package/dist/controllers/separator_controller.js +66 -37
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +20 -3
- package/dist/controllers/sidebar_controller.js +77 -18
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.js +6 -1
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +45 -7
- package/dist/controllers/slider_controller.js +82 -47
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.js +60 -26
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +17 -2
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.js +10 -2
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +19 -17
- package/dist/controllers/step_indicator_controller.js +18 -17
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +34 -9
- package/dist/controllers/stepper_controller.js +101 -19
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
- package/dist/controllers/stick_to_bottom_controller.js +104 -8
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +3 -2
- package/dist/controllers/submit_once_controller.js +45 -9
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +29 -7
- package/dist/controllers/switch_controller.js +101 -10
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +12 -0
- package/dist/controllers/tabs_controller.js +21 -2
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +15 -3
- package/dist/controllers/tags_input_controller.js +209 -59
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.js +29 -3
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +20 -3
- package/dist/controllers/theme_controller.js +64 -14
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.js +23 -8
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +55 -15
- package/dist/controllers/toast_controller.js +451 -105
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +49 -7
- package/dist/controllers/toggle_group_controller.js +159 -23
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +32 -0
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +8 -0
- package/dist/controllers/tooltip_controller.js +39 -13
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.js +4 -0
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +39 -8
- package/dist/controllers/tree_view_controller.js +169 -16
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +5002 -1911
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +72 -6
- package/dist/inspector/cli.js +262 -51
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +309 -51
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +40 -40
- package/dist/inspector/manifest.json +529 -61
- package/dist/positioning/index.js +2 -0
- package/dist/positioning/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/composition_tracker.ts","../../src/utils/half_width.ts","../../src/utils/intl_format.ts","../../src/controllers/currency_input_controller.ts"],"names":["formatted"],"mappings":"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","file":"currency_input_controller.js","sourcesContent":["/** 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 * Construction of `Intl` formatters for the controllers that take a locale, and\n * the options that go with it, from a declaration.\n *\n * Every `Intl` constructor resolves locale data on the way in, which makes it\n * too costly to rebuild on a hot path, and rejects a malformed language tag,\n * currency code, time zone or digit count with a `RangeError`. Both concerns are\n * handled here once. A formatter is built at most once per distinct request and\n * shared by every caller that asks for the same one. A `RangeError` is caught\n * and answered the way the caller asked: by rebuilding under a fallback locale,\n * or by returning `null` so the caller can leave its authored text alone. Any\n * other failure is a programming fault and propagates.\n */\n\n/** The constructor shape the `Intl` formatter classes share. */\nexport interface IntlFormatterConstructor<F, O extends object> {\n new (locales?: string | string[], options?: O): F;\n}\n\n/** Built formatters, and refusals, per constructor; see `cacheKey` for the key. */\nconst formatters = new WeakMap<object, Map<string, unknown>>();\n\n/**\n * A formatter for `locale` with `options`.\n *\n * With `fallbackLocale`, a `RangeError` from the constructor is answered by\n * building the same options under the fallback instead, so the result is never\n * `null`; the fallback's own failure propagates. Without it, a `RangeError`\n * yields `null` and the caller decides what to show. Errors of any other kind\n * propagate in both forms.\n *\n * Results are cached per constructor and `(locale, options, fallback)`, `null`\n * included, so asking again on every render costs one map lookup.\n */\nexport function intlFormatter<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n fallbackLocale: string,\n): F;\nexport function intlFormatter<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n): F | null;\nexport function intlFormatter<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n fallbackLocale?: string,\n): F | null {\n const cache = cacheFor(factory);\n const key = cacheKey(locale, options, fallbackLocale);\n if (cache.has(key)) return cache.get(key) as F | null;\n const formatter = construct(factory, locale, options, fallbackLocale);\n cache.set(key, formatter);\n return formatter;\n}\n\n/** The cache for one constructor, created on first use. */\nfunction cacheFor(factory: object): Map<string, unknown> {\n const existing = formatters.get(factory);\n if (existing) return existing;\n const created = new Map<string, unknown>();\n formatters.set(factory, created);\n return created;\n}\n\n/**\n * One key per distinct request. `JSON.stringify` drops an option left\n * `undefined`, which is how the constructor reads it too. Two spellings of the\n * same options differing only in key order key separately; that costs one extra\n * formatter, never a wrong one, and call sites pass a fixed literal anyway.\n */\nfunction cacheKey(\n locale: string | undefined,\n options: object,\n fallbackLocale: string | undefined,\n): string {\n return JSON.stringify([locale, options, fallbackLocale]);\n}\n\n/** Builds the formatter under the `RangeError` contract described on `intlFormatter`. */\nfunction construct<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n fallbackLocale: string | undefined,\n): F | null {\n try {\n return new factory(locale, options);\n } catch (error) {\n if (!(error instanceof RangeError)) throw error;\n if (fallbackLocale === undefined) return null;\n return new factory(fallbackLocale, options);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { CompositionTracker } from \"../utils/composition_tracker\";\nimport { halfWidthChar } from \"../utils/half_width\";\nimport { intlFormatter } from \"../utils/intl_format\";\n\n/** The number-shaped pieces of an in-progress entry, in typing order. */\ninterface EntryParts {\n /** The leading sign exactly as typed (`\"\"` when none). */\n sign: \"\" | \"-\" | \"+\";\n /** Integer digits with grouping stripped (may be empty mid-entry). */\n int: string;\n /** Whether a decimal mark was typed. */\n hasDot: boolean;\n /** Fraction digits exactly as typed; rounding happens only on blur. */\n frac: string;\n}\n\n/** One scan of the display text: its structure and the numeric value it holds. */\ninterface Scan {\n parts: EntryParts;\n /** The finite value, or `null` while no digit has been typed yet. */\n value: number | null;\n}\n\n/**\n * Headless currency / amount input behavior: groups digits for display while\n * keeping a machine-readable number in a hidden field, and mirrors the\n * normalized value to a visually-hidden span so assistive tech reads the real\n * amount rather than the grouped display string.\n *\n * Markup contract (identifier: `stimeo--currency-input`):\n * <div data-controller=\"stimeo--currency-input\"\n * data-stimeo--currency-input-locale-value=\"en-US\"\n * data-stimeo--currency-input-currency-value=\"USD\"\n * data-stimeo--currency-input-precision-value=\"2\">\n * <input type=\"text\" inputmode=\"decimal\"\n * aria-describedby=\"amt-sr\"\n * data-stimeo--currency-input-target=\"display\"\n * data-action=\"input->stimeo--currency-input#onInput\n * blur->stimeo--currency-input#format\" />\n * <span id=\"amt-sr\" class=\"visually-hidden\"\n * data-stimeo--currency-input-target=\"srValue\"></span>\n * <input type=\"hidden\" data-stimeo--currency-input-target=\"field\" />\n * </div>\n *\n * `change` dispatches `{ value: number | null, formatted: string }` — `null`\n * (with an empty `formatted`) when the amount is cleared, so consumers hear\n * every transition of the numeric value, including back to empty.\n *\n * @remarks\n * Behavior only — no styling, no validation (range/required belong to the\n * consumer or Form Field). The display field is the sole Tab stop and keeps its\n * native text-editing behavior; this controller never steals focus.\n *\n * While typing, the entry is preserved as typed: grouping is applied to the\n * integer digits per locale, a leading sign and a trailing decimal mark stay in\n * place, fraction digits are kept verbatim, and the caret is restored after the\n * same significant character it followed. Negative amounts are in scope. The\n * fixed-precision rounding is applied on `blur`, never mid-entry.\n * Full-width digits, signs, and marks (an IME confirming 0-9/./-) are\n * normalized to their ASCII forms rather than stripped; the locale's own\n * digits (a non-Latin default numbering system such as ar-EG's) are mapped\n * back the same way; and U+2212 MINUS SIGN is read as a sign. An ASCII \".\"\n * only counts as a decimal mark in locales where it is not the grouping\n * separator. Together these keep the controller's own output re-parseable to\n * the same value in every locale. Events fired mid-IME-composition are\n * ignored; the confirmed text is formatted once on `compositionend`.\n *\n * A malformed `locale`, `currency`, or `precision` declaration falls back to\n * that Value's default instead of throwing: each is validated once in its\n * `<name>ValueChanged`, and the hot path only ever sees validated values\n * through cached `Intl.NumberFormat` instances (rebuilt on Value changes, never\n * per keystroke). Late-arriving or swapped `field` / `srValue` / `display`\n * targets are re-synced on connection. The composition listeners are released\n * on `disconnect()`.\n *\n * Honest a11y note: a hidden `<input>` is not exposed to assistive tech, so the\n * normalized value is *also* published as text in the `srValue` span referenced\n * by the display's `aria-describedby` — that, not the hidden field, is what a\n * screen reader announces.\n */\nexport class CurrencyInputController extends Controller<HTMLElement> {\n static override targets = [\"display\", \"field\", \"srValue\"];\n static override values = {\n locale: { type: String, default: \"en-US\" },\n currency: { type: String, default: \"\" },\n precision: { type: Number, default: 2 },\n };\n static actions = [\"format\", \"onInput\"] as const;\n static events = [\"change\"] as const;\n\n declare readonly displayTarget: HTMLInputElement;\n declare readonly fieldTarget: HTMLInputElement;\n declare readonly srValueTarget: HTMLElement;\n declare readonly hasDisplayTarget: boolean;\n declare readonly hasFieldTarget: boolean;\n declare readonly hasSrValueTarget: boolean;\n declare localeValue: string;\n declare currencyValue: string;\n declare precisionValue: number;\n\n /** Last committed numeric value, to suppress duplicate `change` dispatches. */\n #lastValue: number | null = null;\n #started = false;\n\n /** Validated mirrors of the Values; the hot path never reads a raw Value. */\n #locale = \"en-US\";\n #currency = \"\";\n #precision = 2;\n\n /** Formatters rebuilt only when a Value changes, never per keystroke. */\n #grouping!: Intl.NumberFormat;\n #fixed!: Intl.NumberFormat;\n #accessible!: Intl.NumberFormat;\n #group = \",\";\n #decimal = \".\";\n /** The locale's non-Latin digits mapped back to ASCII (empty for Latin locales). */\n readonly #digits = new Map<string, string>();\n\n /** Holds mid-composition input so the IME's uncommitted text is never rewritten. */\n readonly #composition = new CompositionTracker({\n onEnd: () => this.#reformat(false),\n });\n\n /** Re-validates on declaration changes and re-renders the committed display. */\n localeValueChanged(): void {\n this.#applyValueChange();\n }\n\n currencyValueChanged(): void {\n this.#applyValueChange();\n }\n\n precisionValueChanged(): void {\n this.#applyValueChange();\n }\n\n /**\n * Scans the display under the *outgoing* configuration (its separators wrote\n * that text), then revalidates and re-renders under the new one — so a locale\n * switch re-interprets the value, never the old text with new separators.\n */\n #applyValueChange(): void {\n const scan =\n this.#started && this.hasDisplayTarget ? this.#scan(this.displayTarget.value) : null;\n this.#revalidate();\n if (!scan || !this.hasDisplayTarget) return;\n if (document.activeElement === this.displayTarget) {\n const formatted = this.#render(scan.parts);\n this.displayTarget.value = formatted;\n this.#reflect(scan.value, formatted);\n } else if (scan.value === null) {\n this.displayTarget.value = \"\";\n this.#reflect(null, \"\");\n } else {\n const rounded = round(scan.value, this.#precision);\n const formatted = this.#fixed.format(rounded);\n this.displayTarget.value = formatted;\n this.#reflect(rounded, formatted);\n }\n }\n\n /** Normalizes any pre-filled display value to its fixed-precision form. */\n override connect(): void {\n this.#started = true;\n if (!this.hasDisplayTarget) return;\n // Seed lastValue with the *rounded* initial value so the idempotent\n // connect-time reformat does not dispatch a spurious `change`.\n const { value } = this.#scan(this.displayTarget.value);\n this.#lastValue = value === null ? null : round(value, this.#precision);\n if (value === null) {\n this.displayTarget.value = \"\";\n this.#reflect(null, \"\");\n } else {\n this.#reformat(true);\n }\n }\n\n override disconnect(): void {\n this.#started = false;\n this.#composition.disconnect();\n }\n\n /** Tracks composition on an arriving (or swapped-in) display and normalizes it. */\n displayTargetConnected(target: HTMLInputElement): void {\n this.#composition.observe(target);\n if (this.#started) this.#reformat(true);\n }\n\n displayTargetDisconnected(target: HTMLInputElement): void {\n this.#composition.unobserve(target);\n }\n\n /** Syncs a late-arriving hidden field without touching the display or events. */\n fieldTargetConnected(): void {\n if (this.#started) this.#resync();\n }\n\n /** Syncs a late-arriving screen-reader span the same way. */\n srValueTargetConnected(): void {\n if (this.#started) this.#resync();\n }\n\n /** Re-groups digits as the user types, preserving the caret position. */\n onInput(event: Event): void {\n if (this.#composition.isComposing(event as InputEvent)) return;\n this.#reformat(false);\n }\n\n /** Applies the fixed-precision rounding on blur. */\n format(): void {\n this.#reformat(true);\n }\n\n /**\n * Parses the display value, rewrites it grouped (optionally at fixed\n * precision), keeps the caret stable by significant characters, and syncs the\n * field, the screen-reader span, and the `change` event.\n *\n * @stimeoRenderRoot\n */\n #reformat(fixedPrecision: boolean): void {\n if (!this.hasDisplayTarget) return;\n const raw = this.displayTarget.value;\n const { parts, value } = this.#scan(raw);\n\n if (fixedPrecision) {\n if (value === null) {\n // Blur with no digits (an abandoned sign or dot) clears the entry.\n this.displayTarget.value = \"\";\n this.#reflect(null, \"\");\n return;\n }\n const rounded = round(value, this.#precision);\n const formatted = this.#fixed.format(rounded);\n this.displayTarget.value = formatted;\n this.#reflect(rounded, formatted);\n return;\n }\n\n const formatted = this.#render(parts);\n if (formatted !== raw) {\n const caret = this.displayTarget.selectionStart;\n const anchor = caret === null ? null : this.#significantBefore(raw, caret);\n this.displayTarget.value = formatted;\n if (anchor !== null) this.#restoreCaret(formatted, anchor);\n }\n // The display may hold an in-progress \"-\", but a null value always rides\n // with an empty `formatted` so consumers can treat the pair as \"cleared\".\n this.#reflect(value, value === null ? \"\" : formatted);\n }\n\n /**\n * The in-progress rendering: grouped integer, sign and fraction as typed.\n *\n * @stimeoRenderRoot\n */\n #render(parts: EntryParts): string {\n const int = parts.int === \"\" ? \"\" : this.#grouping.format(BigInt(parts.int));\n const frac = parts.hasDot ? this.#decimal + parts.frac : \"\";\n return parts.sign + int + frac;\n }\n\n /** Restores the caret to sit just after the n-th significant character. */\n #restoreCaret(formatted: string, significantBefore: number): void {\n let seen = 0;\n let position = formatted.length;\n for (let i = 0; i < formatted.length; i++) {\n if (seen >= significantBefore) {\n position = i;\n break;\n }\n if (this.#isSignificant(formatted[i] as string)) seen += 1;\n }\n try {\n this.displayTarget.setSelectionRange(position, position);\n } catch {\n // Some hosts disallow selection on certain input states; the value is\n // already correct, so a failed caret restore is non-fatal.\n }\n }\n\n /**\n * Counts the characters before `caret` that survive into the rendering,\n * applying the same acceptance rules as {@link #scan} — a rejected keystroke\n * (a mid-string sign, a second decimal mark) must not shift the anchor.\n */\n #significantBefore(text: string, caret: number): number {\n let count = 0;\n let sawSign = false;\n let sawDigit = false;\n let sawDot = false;\n for (const ch of this.#normalize(text.slice(0, caret))) {\n if (ch >= \"0\" && ch <= \"9\") {\n count += 1;\n sawDigit = true;\n } else if ((ch === \"-\" || ch === \"+\") && !sawSign && !sawDigit && !sawDot) {\n count += 1;\n sawSign = true;\n } else if (this.#isDecimalMark(ch) && !sawDot) {\n count += 1;\n sawDot = true;\n }\n }\n return count;\n }\n\n /** Digits, signs, and the decimal mark anchor the caret; grouping does not. */\n #isSignificant(ch: string): boolean {\n if (ch >= \"0\" && ch <= \"9\") return true;\n if (ch === \"-\" || ch === \"+\") return true;\n return ch === this.#decimal || (ch === \".\" && this.#group !== \".\");\n }\n\n /** Writes the normalized value to the field, the SR span, and the empty hook. */\n #write(value: number | null): void {\n const isEmpty = value === null;\n if (this.hasFieldTarget) this.fieldTarget.value = isEmpty ? \"\" : String(value);\n if (this.hasSrValueTarget) {\n this.srValueTarget.textContent = isEmpty ? \"\" : this.#accessible.format(value);\n }\n this.element.toggleAttribute(\"data-stimeo--currency-input-empty\", isEmpty);\n }\n\n /** {@link #write}, then reports a moved value as `change` (`\"\"` rides with `null`). */\n #reflect(value: number | null, formatted: string): void {\n this.#write(value);\n if (value !== this.#lastValue) {\n this.#lastValue = value;\n this.dispatch(\"change\", { detail: { value, formatted } });\n }\n }\n\n /**\n * Scans arbitrary input text into its number-shaped parts and value. Keeps\n * digits, one leading sign, one decimal mark, and the fraction verbatim;\n * everything else (grouping, symbols, words) is dropped. An ASCII \".\" is only\n * a decimal mark where it is not the locale's grouping separator. Precision\n * plays no part here — rounding belongs to the blur-time format.\n */\n #scan(text: string): Scan {\n let sign: EntryParts[\"sign\"] = \"\";\n let int = \"\";\n let hasDot = false;\n let frac = \"\";\n for (const ch of this.#normalize(text)) {\n if (ch >= \"0\" && ch <= \"9\") {\n if (hasDot) frac += ch;\n else int += ch;\n } else if ((ch === \"-\" || ch === \"+\") && sign === \"\" && int === \"\" && !hasDot) {\n sign = ch;\n } else if (this.#isDecimalMark(ch) && !hasDot) {\n hasDot = true;\n }\n }\n const parts: EntryParts = { sign, int, hasDot, frac };\n // `Number` accepts \"12.\" and \".5\" alike, so one dotted form covers every\n // shape — and a digit-less entry (\"\", \"-\", \".\") reads as NaN, hence null.\n const value = Number(`${sign}${int}.${frac}`);\n return { parts, value: Number.isFinite(value) ? value : null };\n }\n\n /** Whether `ch` reads as this locale's decimal mark. */\n #isDecimalMark(ch: string): boolean {\n return ch === this.#decimal || (ch === \".\" && this.#group !== \".\");\n }\n\n /** Re-syncs field / srValue / hook from the current display without dispatching. */\n #resync(): void {\n if (!this.hasDisplayTarget) return;\n this.#write(this.#scan(this.displayTarget.value).value);\n }\n\n /**\n * Validates the declared Values, falling back to each Value's default when a\n * declaration cannot be interpreted (a malformed locale or currency tag, a\n * precision outside `Intl`'s 0–100 integer range), and rebuilds the cached\n * formatters from the validated set.\n */\n #revalidate(): void {\n const declaredLocale = intlFormatter(Intl.NumberFormat, this.localeValue, {});\n this.#locale = declaredLocale === null ? \"en-US\" : this.localeValue;\n\n const precision = this.precisionValue;\n this.#precision =\n Number.isInteger(precision) && precision >= 0 && precision <= 100 ? precision : 2;\n\n this.#currency = \"\";\n if (this.currencyValue !== \"\") {\n const declaredCurrency = intlFormatter(Intl.NumberFormat, this.#locale, {\n style: \"currency\",\n currency: this.currencyValue,\n });\n // An unknown code falls through to the plain-number accessible text.\n if (declaredCurrency !== null) this.#currency = this.currencyValue;\n }\n\n this.#grouping = intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n { useGrouping: true, maximumFractionDigits: 0 },\n this.#locale,\n );\n this.#fixed = intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n {\n useGrouping: true,\n minimumFractionDigits: this.#precision,\n maximumFractionDigits: this.#precision,\n },\n this.#locale,\n );\n this.#accessible = this.#currency\n ? intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n { style: \"currency\", currency: this.#currency },\n this.#locale,\n )\n : this.#fixed;\n\n const parts = intlFormatter(Intl.NumberFormat, this.#locale, {}, this.#locale).formatToParts(\n 11111.1,\n );\n this.#group = parts.find((p) => p.type === \"group\")?.value ?? \",\";\n this.#decimal = parts.find((p) => p.type === \"decimal\")?.value ?? \".\";\n\n // Locales whose default numbering system is not Latin (ar-EG, fa-IR, …)\n // format with their own digits; mapping them back keeps the controller's\n // own output re-parseable to the same value.\n this.#digits.clear();\n const digitFormatter = intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n { useGrouping: false },\n this.#locale,\n );\n for (let i = 0; i <= 9; i++) {\n const digit = digitFormatter.format(i);\n if (digit !== String(i)) this.#digits.set(digit, String(i));\n }\n }\n\n /**\n * Maps the locale's own digits to ASCII, folds full-width forms (the digits,\n * signs, and marks an IME confirms as 0-9+-.,) through the shared\n * half-width mapping, and reads U+2212 MINUS SIGN as \"-\", which some locales'\n * formatted output uses for negatives.\n */\n #normalize(text: string): string {\n let out = \"\";\n for (const ch of text) {\n const mapped = this.#digits.get(ch);\n if (mapped !== undefined) {\n out += mapped;\n } else if (ch === \"−\") {\n out += \"-\";\n } else {\n out += halfWidthChar(ch);\n }\n }\n return out;\n }\n}\n\n/** Rounds `value` to `precision` decimal places, avoiding `-0`; overflow keeps `value`. */\nfunction round(value: number, precision: number): number {\n const factor = 10 ** Math.max(0, precision);\n const rounded = Math.round(value * factor) / factor;\n if (!Number.isFinite(rounded)) return value;\n return rounded === 0 ? 0 : rounded;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/composition_tracker.ts","../../src/utils/half_width.ts","../../src/utils/intl_format.ts","../../src/utils/locale.ts","../../src/controllers/currency_input_controller.ts"],"names":[],"mappings":"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","file":"currency_input_controller.js","sourcesContent":["/** Minimal event shape carrying the platform's per-event composition signal. */\nexport interface CompositionSignal {\n readonly isComposing?: boolean;\n}\n\n/** Minimal `input` shape needed to tell a composition echo from a fresh edit. */\nexport interface ConfirmedInputSignal {\n readonly target: EventTarget | null;\n readonly inputType?: string;\n}\n\n/**\n * The `inputType` values an engine reports on an `input` that belongs to a\n * composition rather than to an edit the user just made.\n */\nconst COMPOSITION_INPUT_TYPES = new Set([\n \"insertCompositionText\",\n \"insertFromComposition\",\n \"deleteCompositionText\",\n \"deleteByComposition\",\n]);\n\n/** Hooks that keep component-specific work outside {@link CompositionTracker}. */\nexport interface CompositionTrackerOptions {\n /** Runs after lifecycle state is set for a `compositionstart` event. */\n readonly onStart?: (event: Event) => void;\n /** Runs after lifecycle state is cleared for a `compositionend` event. */\n readonly onEnd?: (event: Event) => void;\n}\n\n/**\n * Owns IME composition listeners and transient state for one or more event targets.\n *\n * Some browsers omit `KeyboardEvent.isComposing` on the keydown that confirms a\n * conversion. Tracking `compositionstart` through `compositionend` supplies the\n * missing lifecycle signal without relying on deprecated numeric key codes.\n * Component policy stays with the consumer: filtering, validation, and submission\n * belong in the optional {@link CompositionTrackerOptions.onEnd} callback.\n *\n * The tracker also owns the other half of that lifecycle: **the `input` some\n * engines send after `compositionend` to echo the text just confirmed.** A\n * consumer that ran `onEnd` and then handled the echo would commit the same\n * confirmation twice, so {@link CompositionTracker.consumesConfirmedInput} tells\n * the echo apart and the consumer returns early on it.\n *\n * **What the echo is not, is the harder half.** Not every engine sends one —\n * Chromium ends a confirmation at `compositionend` with no `input` after it — so\n * a window that waits for the echo and only closes on the next key would swallow\n * the first edit that arrives without one: dictation, autofill, a drop,\n * `insertText`. Two things keep that from happening. The window closes on the\n * next anything — a key, a new composition, any `input`, losing the field — and\n * an `input` that reports an `inputType` outside {@link COMPOSITION_INPUT_TYPES}\n * is an edit, so it is never folded. Only an engine that reports no `inputType`\n * at all is left relying on the window alone.\n *\n * @example\n * ```ts\n * #composition = new CompositionTracker({ onEnd: () => this.filter() });\n *\n * connect(): void {\n * this.#composition.observe(this.inputTarget);\n * }\n *\n * disconnect(): void {\n * this.#composition.disconnect();\n * }\n *\n * onInput(event: InputEvent): void {\n * if (this.#composition.consumesConfirmedInput(event)) return;\n * if (this.#composition.isComposing(event)) return;\n * }\n *\n * onKeydown(event: KeyboardEvent): void {\n * if (this.#composition.isComposing(event)) return;\n * }\n * ```\n */\nexport class CompositionTracker {\n readonly #observedTargets = new Set<EventTarget>();\n readonly #activeTargets = new Set<EventTarget>();\n readonly #onStart: ((event: Event) => void) | undefined;\n readonly #onEnd: ((event: Event) => void) | undefined;\n /** The field whose confirming `input` is still owed, while the window is open. */\n #confirmedTarget: EventTarget | null = null;\n\n constructor(options: CompositionTrackerOptions = {}) {\n this.#onStart = options.onStart;\n this.#onEnd = options.onEnd;\n }\n\n /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */\n observe(target: EventTarget): void {\n if (this.#observedTargets.has(target)) return;\n target.addEventListener(\"compositionstart\", this.#handleStart);\n target.addEventListener(\"compositionend\", this.#handleEnd);\n target.addEventListener(\"keydown\", this.#handleKeydown);\n this.#observedTargets.add(target);\n }\n\n /** Stops tracking one target and clears any active composition it owned. */\n unobserve(target: EventTarget): void {\n if (!this.#observedTargets.delete(target)) return;\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n target.removeEventListener(\"keydown\", this.#handleKeydown);\n this.#activeTargets.delete(target);\n if (this.#confirmedTarget === target) this.#confirmedTarget = null;\n }\n\n /** Releases every listener and clears state so reconnect starts cleanly. */\n disconnect(): void {\n for (const target of this.#observedTargets) {\n target.removeEventListener(\"compositionstart\", this.#handleStart);\n target.removeEventListener(\"compositionend\", this.#handleEnd);\n target.removeEventListener(\"keydown\", this.#handleKeydown);\n }\n this.#observedTargets.clear();\n this.#activeTargets.clear();\n this.#confirmedTarget = null;\n }\n\n /** True when lifecycle tracking or the current event reports composition. */\n isComposing(event?: CompositionSignal): boolean {\n return this.#activeTargets.size > 0 || event?.isComposing === true;\n }\n\n /**\n * Whether `event` is the `input` echoing the composition just confirmed.\n *\n * Asking closes the window either way, so one confirmation is folded at most\n * once and a consumer asks once per `input`.\n */\n consumesConfirmedInput(event: ConfirmedInputSignal): boolean {\n const confirmed = this.#confirmedTarget;\n this.#confirmedTarget = null;\n if (confirmed === null || confirmed !== event.target) return false;\n // An engine that reports no kind at all leaves `inputType` empty, and the\n // window is then the only signal there is.\n const inputType = event.inputType;\n return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);\n }\n\n readonly #handleStart = (event: Event): void => {\n this.#confirmedTarget = null;\n if (event.currentTarget) this.#activeTargets.add(event.currentTarget);\n this.#onStart?.(event);\n };\n\n readonly #handleEnd = (event: Event): void => {\n if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);\n this.#confirmedTarget = event.target;\n this.#onEnd?.(event);\n };\n\n /** A key on an observed field opens an edit of its own, so no echo is owed. */\n readonly #handleKeydown = (): void => {\n this.#confirmedTarget = null;\n };\n}\n","/** 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 * Construction of `Intl` formatters for the controllers that take a locale, and\n * the options that go with it, from a declaration.\n *\n * Every `Intl` constructor resolves locale data on the way in, which makes it\n * too costly to rebuild on a hot path, and rejects a malformed language tag,\n * currency code, time zone or digit count with a `RangeError`. Both concerns are\n * handled here once. A formatter is built at most once per distinct request and\n * shared by every caller that asks for the same one. A `RangeError` is caught\n * and answered the way the caller asked: by rebuilding under a fallback locale,\n * or by returning `null` so the caller can leave its authored text alone. Any\n * other failure is a programming fault and propagates.\n */\n\n/** The constructor shape the `Intl` formatter classes share. */\nexport interface IntlFormatterConstructor<F, O extends object> {\n new (locales?: string | string[], options?: O): F;\n}\n\n/** Built formatters, and refusals, per constructor; see `cacheKey` for the key. */\nconst formatters = new WeakMap<object, Map<string, unknown>>();\n\n/**\n * A formatter for `locale` with `options`.\n *\n * With `fallbackLocale`, a `RangeError` from the constructor is answered by\n * building the same options under the fallback instead, so the result is never\n * `null`; the fallback's own failure propagates. Without it, a `RangeError`\n * yields `null` and the caller decides what to show. Errors of any other kind\n * propagate in both forms.\n *\n * Results are cached per constructor and `(locale, options, fallback)`, `null`\n * included, so asking again on every render costs one map lookup.\n */\nexport function intlFormatter<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n fallbackLocale: string,\n): F;\nexport function intlFormatter<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n): F | null;\nexport function intlFormatter<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n fallbackLocale?: string,\n): F | null {\n const cache = cacheFor(factory);\n const key = cacheKey(locale, options, fallbackLocale);\n if (cache.has(key)) return cache.get(key) as F | null;\n const formatter = construct(factory, locale, options, fallbackLocale);\n cache.set(key, formatter);\n return formatter;\n}\n\n/** The cache for one constructor, created on first use. */\nfunction cacheFor(factory: object): Map<string, unknown> {\n const existing = formatters.get(factory);\n if (existing) return existing;\n const created = new Map<string, unknown>();\n formatters.set(factory, created);\n return created;\n}\n\n/**\n * One key per distinct request. `JSON.stringify` drops an option left\n * `undefined`, which is how the constructor reads it too. Two spellings of the\n * same options differing only in key order key separately; that costs one extra\n * formatter, never a wrong one, and call sites pass a fixed literal anyway.\n */\nfunction cacheKey(\n locale: string | undefined,\n options: object,\n fallbackLocale: string | undefined,\n): string {\n return JSON.stringify([locale, options, fallbackLocale]);\n}\n\n/** Builds the formatter under the `RangeError` contract described on `intlFormatter`. */\nfunction construct<F, O extends object>(\n factory: IntlFormatterConstructor<F, O>,\n locale: string | undefined,\n options: O,\n fallbackLocale: string | undefined,\n): F | null {\n try {\n return new factory(locale, options);\n } catch (error) {\n if (!(error instanceof RangeError)) throw error;\n if (fallbackLocale === undefined) return null;\n return new factory(fallbackLocale, options);\n }\n}\n","/**\n * The locale a component formats in: its own declaration, else the language of\n * the text around it, else the runtime default.\n *\n * `lang` is inherited in HTML, so the language that applies to an element is the\n * nearest one on the element itself or on an ancestor — not the document\n * element's, which is only the farthest of them. An empty `lang` there means the\n * language is unknown and stops the inheritance at that point, so it resolves to\n * the runtime default rather than to a `lang` further up.\n *\n * Resolution only, and the value is passed through as authored. Whether `Intl`\n * accepts the tag, and what to show when it does not, is the caller's contract.\n *\n * @example\n * ```ts\n * intlFormatter(Intl.DateTimeFormat, resolveLocale(this.element, this.localeValue), options);\n * ```\n */\nexport function resolveLocale(element: Element, declared = \"\"): string | undefined {\n return declared || element.closest(\"[lang]\")?.getAttribute(\"lang\") || undefined;\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { CompositionTracker } from \"../utils/composition_tracker\";\nimport { halfWidthChar } from \"../utils/half_width\";\nimport { intlFormatter } from \"../utils/intl_format\";\nimport { resolveLocale } from \"../utils/locale\";\n\n/** The number-shaped pieces of an in-progress entry, in typing order. */\ninterface EntryParts {\n /** The leading sign exactly as typed (`\"\"` when none). */\n sign: \"\" | \"-\" | \"+\";\n /** Integer digits with grouping stripped (may be empty mid-entry). */\n int: string;\n /** Whether a decimal mark was typed. */\n hasDot: boolean;\n /** Fraction digits exactly as typed; rounding happens only on blur. */\n frac: string;\n}\n\n/** One scan of the display text: its structure and the numeric value it holds. */\ninterface Scan {\n parts: EntryParts;\n /** The finite value, or `null` while no digit has been typed yet. */\n value: number | null;\n}\n\n/** Who moved the value: the user editing the display, or the page. */\ntype Cause = \"edit\" | \"reconcile\";\n\n/**\n * The locale a declaration falls back to when `Intl` rejects it, so a broken tag\n * still leaves a field that formats and parses the same way every time.\n */\nconst FALLBACK_LOCALE = \"en-US\";\n\n/**\n * Headless currency / amount input behavior: groups digits for display while\n * keeping a machine-readable number in a hidden field, and mirrors the\n * normalized value to a visually-hidden span so assistive tech reads the real\n * amount rather than the grouped display string.\n *\n * Markup contract (identifier: `stimeo--currency-input`):\n * <div data-controller=\"stimeo--currency-input\"\n * data-stimeo--currency-input-locale-value=\"en-US\"\n * data-stimeo--currency-input-currency-value=\"USD\"\n * data-stimeo--currency-input-precision-value=\"2\">\n * <input type=\"text\" inputmode=\"decimal\"\n * aria-describedby=\"amt-sr\"\n * data-stimeo--currency-input-target=\"display\"\n * data-action=\"input->stimeo--currency-input#onInput\n * blur->stimeo--currency-input#format\" />\n * <span id=\"amt-sr\" class=\"visually-hidden\"\n * data-stimeo--currency-input-target=\"srValue\"></span>\n * <input type=\"hidden\" data-stimeo--currency-input-target=\"field\" />\n * </div>\n *\n * `change` and `reconcile` dispatch `{ value: number | null, formatted: string }`\n * — `null` (with an empty `formatted`) when the amount is cleared, so consumers\n * hear every transition of the numeric value, including back to empty. `change`\n * is the user's edit: typing, or the rounding applied on `blur`. `reconcile` is a\n * value the page moved: a `locale`, `currency` or `precision` change that\n * re-rounds the committed amount, a display target swapped in holding another\n * amount, a reconnect that rounds an entry left unrounded mid-typing, or a move\n * that ends a composition before its `compositionend`. Connecting over a\n * server-rendered value reports neither.\n *\n * @remarks\n * Behavior only — no styling, no validation (range/required belong to the\n * consumer or `stimeo--form-field`). The display field is the sole Tab stop and keeps its\n * native text-editing behavior; this controller never steals focus.\n *\n * While typing, the entry is preserved as typed: grouping is applied to the\n * integer digits per locale, a leading sign and a trailing decimal mark stay in\n * place, fraction digits are kept verbatim, and the caret is restored after the\n * same significant character it followed. Negative amounts are in scope. The\n * fixed-precision rounding is applied on `blur`, never mid-entry.\n * Full-width digits, signs, and marks (an IME confirming 0-9/./-) are\n * normalized to their ASCII forms rather than stripped; the locale's own\n * digits (a non-Latin default numbering system such as ar-EG's) are mapped\n * back the same way; and U+2212 MINUS SIGN is read as a sign. An ASCII \".\"\n * only counts as a decimal mark in locales where it is not the grouping\n * separator. Together these keep the controller's own output re-parseable to\n * the same value in every locale. Events fired mid-IME-composition are\n * ignored; the confirmed text is formatted once on `compositionend`. A\n * `locale` / `currency` / `precision` change that arrives mid-composition\n * leaves the uncommitted text alone and applies right after that confirmed\n * text has been read. A composition this controller stops hearing — its display\n * leaves, or the controller disconnects, before `compositionend` — ends there:\n * a display still in place is read as `compositionend` would read it, and a\n * value that moves is reported as `reconcile`. A field or screen-reader span\n * arriving mid-composition takes the committed value.\n *\n * Display text is read with the declarations it was written for. This\n * controller's own rendering was written with the separators in force, so a\n * declaration change reads it before they change. Any other text is the page's\n * — a display swapped in, or text written into the display alongside a\n * declaration change — written for the declarations the page carries, so it is\n * read with those.\n *\n * With no `locale` declared the field formats in the nearest `lang` up the\n * ancestor chain, else in the runtime default. A malformed `locale` falls back\n * to `en-US`, and a malformed `currency` or `precision` to that Value's default,\n * instead of throwing. The declarations, the nearest `lang` among them, are\n * read and validated before a display is read after they may have moved — on a\n * Value change, when the controller connects, and when a display arrives; the\n * hot path only ever sees validated values through cached `Intl.NumberFormat`\n * instances, never built per keystroke. Late-arriving or swapped `field` /\n * `srValue` / `display` targets are re-synced on connection.\n *\n * Reconnecting starts from the committed value: a display still showing this\n * controller's own rendering is not read back but re-rendered from that value\n * under the current declarations, so a `locale` changed while the element was\n * away never re-reads its separators. The re-render is the fixed-precision\n * form, so it rounds whenever the value has more places than the current\n * `precision` allows — because `precision` changed while the element was away,\n * or because the entry was left unrounded mid-typing (`1.555` becomes `1.56`) —\n * and a value it moves is reported as `reconcile`. The composition listeners\n * are released on `disconnect()`.\n *\n * Honest a11y note: a hidden `<input>` is not exposed to assistive tech, so the\n * normalized value is *also* published as text in the `srValue` span referenced\n * by the display's `aria-describedby` — that, not the hidden field, is what a\n * screen reader announces.\n */\nexport class CurrencyInputController extends Controller<HTMLElement> {\n static override targets = [\"display\", \"field\", \"srValue\"];\n static override values = {\n locale: { type: String, default: \"\" },\n currency: { type: String, default: \"\" },\n precision: { type: Number, default: 2 },\n };\n static actions = [\"format\", \"onInput\"] as const;\n static events = [\"change\", \"reconcile\"] as const;\n\n declare readonly displayTarget: HTMLInputElement;\n declare readonly fieldTarget: HTMLInputElement;\n declare readonly srValueTarget: HTMLElement;\n declare readonly hasDisplayTarget: boolean;\n declare readonly hasFieldTarget: boolean;\n declare readonly hasSrValueTarget: boolean;\n declare localeValue: string;\n declare currencyValue: string;\n declare precisionValue: number;\n\n /** The numeric value last committed; both events report only a move away from it. */\n #lastValue: number | null = null;\n #started = false;\n /** A declaration change that arrived mid-composition, applied once nothing composes. */\n #changeHeld = false;\n /** The display a composition is running on, until that composition ends. */\n #composing: EventTarget | null = null;\n /**\n * The display text this controller last rendered. It tells this controller's own\n * text, written with the separators in force, from text the page wrote.\n */\n #rendered: string | null = null;\n\n /** Validated mirrors of the Values; the hot path never reads a raw Value. */\n #locale: string | undefined;\n #currency = \"\";\n #precision = 2;\n\n /** Formatters rebuilt when the declarations are taken in, never per keystroke. */\n #grouping!: Intl.NumberFormat;\n #fixed!: Intl.NumberFormat;\n #accessible!: Intl.NumberFormat;\n #group = \",\";\n #decimal = \".\";\n /** The locale's non-Latin digits mapped back to ASCII (empty for Latin locales). */\n readonly #digits = new Map<string, string>();\n\n /**\n * Holds mid-composition input so the IME's uncommitted text is never rewritten.\n * The confirmed text is formatted once, and a declaration change the composition\n * held back is applied after it.\n */\n readonly #composition = new CompositionTracker({\n onStart: (event) => {\n this.#composing = event.currentTarget;\n },\n onEnd: () => {\n this.#composing = null;\n this.#reformat(false, \"edit\");\n this.#applyHeldChange();\n },\n });\n\n /**\n * Re-validates on declaration changes and re-renders the committed display,\n * reporting a value the re-render moved as `reconcile`.\n */\n localeValueChanged(): void {\n this.#applyValueChange();\n }\n\n currencyValueChanged(): void {\n this.#applyValueChange();\n }\n\n precisionValueChanged(): void {\n this.#applyValueChange();\n }\n\n /**\n * Reads the display with the declarations its text was written for, then\n * re-renders it under the new ones — so a locale switch re-interprets the\n * value, never the old text with new separators, and text the page wrote for\n * the declarations it changes is never read with the old ones.\n *\n * While the display is composing, its text is the IME's: the change is held,\n * configuration and all, until the composition ends, so the confirmed text is\n * read with the separators it was typed against before the change applies.\n *\n * @stimeoRenderRoot\n */\n #applyValueChange(): void {\n if (this.#composition.isComposing()) {\n this.#changeHeld = true;\n return;\n }\n // With nothing to read, the next display or the next connect takes the\n // declarations in before reading.\n if (!this.#started || !this.hasDisplayTarget) return;\n const scan = this.#readDisplay();\n if (document.activeElement === this.displayTarget) {\n const formatted = this.#render(scan.parts);\n this.#show(formatted);\n this.#reflect(scan.value, formatted, \"reconcile\");\n } else {\n this.#renderFixed(scan.value, \"reconcile\");\n }\n }\n\n /** Applies a declaration change a composition held back. */\n #applyHeldChange(): void {\n if (!this.#changeHeld) return;\n this.#changeHeld = false;\n this.#applyValueChange();\n }\n\n /**\n * Reads the display and takes in the declarations the page carries now. This\n * controller's own rendering was written with the separators in force, so it\n * is read before they change; any other text is the page's, written for the\n * declarations it carries, so it is read after.\n */\n #readDisplay(): Scan {\n const text = this.displayTarget.value;\n const own = text === this.#rendered ? this.#scan(text) : null;\n this.#takeInDeclarations();\n return own ?? this.#scan(text);\n }\n\n /** Takes in the declarations the page carries now, a change a composition held among them. */\n #takeInDeclarations(): void {\n this.#changeHeld = false;\n this.#revalidate();\n }\n\n /**\n * Takes in the declarations the page carries now and normalizes the display\n * to its fixed-precision form.\n *\n * A display still showing this controller's own last rendering is not read\n * back: its separators may belong to declarations that changed while the\n * controller was away, and the committed value is known anyway. That value is\n * re-rendered at the current fixed precision, which rounds it whether\n * `precision` changed meanwhile or the entry was left unrounded mid-typing, and\n * a move the rounding causes is reported as `reconcile`. Any other text is the\n * page's, written for the declarations it carries, so it is read with them.\n */\n override connect(): void {\n this.#started = true;\n this.#takeInDeclarations();\n if (!this.hasDisplayTarget) return;\n if (this.displayTarget.value === this.#rendered) {\n this.#renderFixed(this.#lastValue, \"reconcile\");\n return;\n }\n // Seed the baseline with the *rounded* initial value: the idempotent\n // connect-time reformat describes the value the page rendered, so it\n // reports nothing.\n const { value } = this.#scan(this.displayTarget.value);\n this.#lastValue = value === null ? null : round(value, this.#precision);\n this.#renderFixed(value, \"reconcile\");\n }\n\n /**\n * Releases the composition listeners. A composition still running hears no\n * `compositionend` once they are gone, so it ends here; a change it held is\n * taken in on the next `connect()`.\n */\n override disconnect(): void {\n this.#endUntrackedComposition();\n this.#composition.disconnect();\n this.#started = false;\n }\n\n /**\n * Tracks composition on an arriving (or swapped-in) display and normalizes it\n * under the declarations the page carries now, reading this controller's own\n * rendering with the separators it was written under; an amount that differs\n * from the committed one is the page's, so it is reported as `reconcile`.\n */\n displayTargetConnected(target: HTMLInputElement): void {\n this.#composition.observe(target);\n if (!this.#started) return;\n this.#renderFixed(this.#readDisplay().value, \"reconcile\");\n }\n\n /**\n * Stops tracking a display that leaves. A composition running on it hears no\n * `compositionend` any more, so it ends here; a change it held waits for the\n * next display to be read.\n */\n displayTargetDisconnected(target: HTMLInputElement): void {\n this.#composition.unobserve(target);\n this.#endUntrackedComposition();\n }\n\n /**\n * Ends a composition no `compositionend` will reach. A display still in place —\n * one a move re-inserted, or the display of a controller that moves — holds the\n * text the composition left, typed against the declarations in force, so it is\n * read as `compositionend` would read it and becomes this controller's own\n * rendering. The page's move ended the composition, so a value it moves is\n * reported as `reconcile`. A display that left takes its composition along.\n */\n #endUntrackedComposition(): void {\n const display = this.#composing;\n this.#composing = null;\n if (this.hasDisplayTarget && this.displayTarget === display) {\n this.#reformat(false, \"reconcile\");\n }\n }\n\n /** Syncs a late-arriving hidden field without touching the display or events. */\n fieldTargetConnected(): void {\n if (this.#started) this.#resync();\n }\n\n /** Syncs a late-arriving screen-reader span the same way. */\n srValueTargetConnected(): void {\n if (this.#started) this.#resync();\n }\n\n /** Re-groups digits as the user types, preserving the caret position. */\n onInput(event: Event): void {\n if (this.#composition.isComposing(event as InputEvent)) return;\n this.#reformat(false, \"edit\");\n }\n\n /** Applies the fixed-precision rounding on blur. */\n format(): void {\n this.#reformat(true, \"edit\");\n }\n\n /**\n * Parses the display value, rewrites it grouped (optionally at fixed\n * precision), keeps the caret stable by significant characters, and syncs the\n * field, the screen-reader span, and the event `cause` selects.\n */\n #reformat(fixedPrecision: boolean, cause: Cause): void {\n if (!this.hasDisplayTarget) return;\n const raw = this.displayTarget.value;\n const { parts, value } = this.#scan(raw);\n\n if (fixedPrecision) {\n // Blur with no digits (an abandoned sign or dot) clears the entry.\n this.#renderFixed(value, cause);\n return;\n }\n\n const formatted = this.#render(parts);\n if (formatted !== raw) {\n const caret = this.displayTarget.selectionStart;\n const anchor = caret === null ? null : this.#significantBefore(raw, caret);\n this.displayTarget.value = formatted;\n if (anchor !== null) this.#restoreCaret(formatted, anchor);\n }\n this.#rendered = formatted;\n this.#reflect(value, formatted, cause);\n }\n\n /**\n * Shows `value` at the fixed precision — an empty display for no value — and\n * reports a move under the event `cause` selects.\n */\n #renderFixed(value: number | null, cause: Cause): void {\n if (value === null) {\n this.#show(\"\");\n this.#reflect(null, \"\", cause);\n return;\n }\n const rounded = round(value, this.#precision);\n const formatted = this.#fixed.format(rounded);\n this.#show(formatted);\n this.#reflect(rounded, formatted, cause);\n }\n\n /** Writes `text` to the display as this controller's own rendering. */\n #show(text: string): void {\n this.displayTarget.value = text;\n this.#rendered = text;\n }\n\n /**\n * The in-progress rendering: grouped integer, sign and fraction as typed.\n */\n #render(parts: EntryParts): string {\n const int = parts.int === \"\" ? \"\" : this.#grouping.format(BigInt(parts.int));\n const frac = parts.hasDot ? this.#decimal + parts.frac : \"\";\n return parts.sign + int + frac;\n }\n\n /** Restores the caret to sit just after the n-th significant character. */\n #restoreCaret(formatted: string, significantBefore: number): void {\n let seen = 0;\n let position = formatted.length;\n for (let i = 0; i < formatted.length; i++) {\n if (seen >= significantBefore) {\n position = i;\n break;\n }\n if (this.#isSignificant(formatted[i] as string)) seen += 1;\n }\n try {\n this.displayTarget.setSelectionRange(position, position);\n } catch {\n // Some hosts disallow selection on certain input states; the value is\n // already correct, so a failed caret restore is non-fatal.\n }\n }\n\n /**\n * Counts the characters before `caret` that survive into the rendering,\n * applying the same acceptance rules as {@link #scan} — a rejected keystroke\n * (a mid-string sign, a second decimal mark) must not shift the anchor.\n */\n #significantBefore(text: string, caret: number): number {\n let count = 0;\n let sawSign = false;\n let sawDigit = false;\n let sawDot = false;\n for (const ch of this.#normalize(text.slice(0, caret))) {\n if (ch >= \"0\" && ch <= \"9\") {\n count += 1;\n sawDigit = true;\n } else if ((ch === \"-\" || ch === \"+\") && !sawSign && !sawDigit && !sawDot) {\n count += 1;\n sawSign = true;\n } else if (this.#isDecimalMark(ch) && !sawDot) {\n count += 1;\n sawDot = true;\n }\n }\n return count;\n }\n\n /** Digits, signs, and the decimal mark anchor the caret; grouping does not. */\n #isSignificant(ch: string): boolean {\n if (ch >= \"0\" && ch <= \"9\") return true;\n if (ch === \"-\" || ch === \"+\") return true;\n return ch === this.#decimal || (ch === \".\" && this.#group !== \".\");\n }\n\n /** Writes the normalized value to the field, the SR span, and the empty hook. */\n #write(value: number | null): void {\n const isEmpty = value === null;\n if (this.hasFieldTarget) this.fieldTarget.value = isEmpty ? \"\" : String(value);\n if (this.hasSrValueTarget) {\n this.srValueTarget.textContent = isEmpty ? \"\" : this.#accessible.format(value);\n }\n this.element.toggleAttribute(`data-${this.identifier}-empty`, isEmpty);\n }\n\n /**\n * {@link #write}, then reports a moved value under the event `cause` selects:\n * `change` for the user's edit, `reconcile` for a move the page caused. The\n * display may hold an in-progress `-`, but a `null` value always rides with an\n * empty `formatted`, whichever event reports it, so consumers can treat the\n * pair as cleared.\n */\n #reflect(value: number | null, formatted: string, cause: Cause): void {\n this.#write(value);\n if (value === this.#lastValue) return;\n this.#lastValue = value;\n const detail = { value, formatted: value === null ? \"\" : formatted };\n if (cause === \"edit\") this.dispatch(\"change\", { detail });\n else this.dispatch(\"reconcile\", { detail });\n }\n\n /**\n * Scans arbitrary input text into its number-shaped parts and value. Keeps\n * digits, one leading sign, one decimal mark, and the fraction verbatim;\n * everything else (grouping, symbols, words) is dropped. An ASCII \".\" is only\n * a decimal mark where it is not the locale's grouping separator. Precision\n * plays no part here — rounding belongs to the blur-time format.\n */\n #scan(text: string): Scan {\n let sign: EntryParts[\"sign\"] = \"\";\n let int = \"\";\n let hasDot = false;\n let frac = \"\";\n for (const ch of this.#normalize(text)) {\n if (ch >= \"0\" && ch <= \"9\") {\n if (hasDot) frac += ch;\n else int += ch;\n } else if ((ch === \"-\" || ch === \"+\") && sign === \"\" && int === \"\" && !hasDot) {\n sign = ch;\n } else if (this.#isDecimalMark(ch) && !hasDot) {\n hasDot = true;\n }\n }\n const parts: EntryParts = { sign, int, hasDot, frac };\n // `Number` accepts \"12.\" and \".5\" alike, so one dotted form covers every\n // shape — and a digit-less entry (\"\", \"-\", \".\") reads as NaN, hence null.\n const value = Number(`${sign}${int}.${frac}`);\n return { parts, value: Number.isFinite(value) ? value : null };\n }\n\n /** Whether `ch` reads as this locale's decimal mark. */\n #isDecimalMark(ch: string): boolean {\n return ch === this.#decimal || (ch === \".\" && this.#group !== \".\");\n }\n\n /**\n * Re-syncs field / srValue / hook without dispatching: from the display, or —\n * while it is composing, when its text is not committed yet — from the value\n * last committed.\n */\n #resync(): void {\n if (!this.hasDisplayTarget) return;\n const value = this.#composition.isComposing()\n ? this.#lastValue\n : this.#scan(this.displayTarget.value).value;\n this.#write(value);\n }\n\n /**\n * Validates the declared Values, falling back to each Value's default when a\n * declaration cannot be interpreted (a malformed locale or currency tag, a\n * precision outside `Intl`'s 0–100 integer range), and rebuilds the cached\n * formatters from the validated set.\n */\n #revalidate(): void {\n const resolved = resolveLocale(this.element, this.localeValue);\n const usable = intlFormatter(Intl.NumberFormat, resolved, {});\n this.#locale = usable === null ? FALLBACK_LOCALE : resolved;\n\n const precision = this.precisionValue;\n this.#precision =\n Number.isInteger(precision) && precision >= 0 && precision <= 100 ? precision : 2;\n\n this.#currency = \"\";\n if (this.currencyValue !== \"\") {\n const declaredCurrency = intlFormatter(Intl.NumberFormat, this.#locale, {\n style: \"currency\",\n currency: this.currencyValue,\n });\n // An unknown code falls through to the plain-number accessible text.\n if (declaredCurrency !== null) this.#currency = this.currencyValue;\n }\n\n this.#grouping = intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n { useGrouping: true, maximumFractionDigits: 0 },\n FALLBACK_LOCALE,\n );\n this.#fixed = intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n {\n useGrouping: true,\n minimumFractionDigits: this.#precision,\n maximumFractionDigits: this.#precision,\n },\n FALLBACK_LOCALE,\n );\n this.#accessible = this.#currency\n ? intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n { style: \"currency\", currency: this.#currency },\n FALLBACK_LOCALE,\n )\n : this.#fixed;\n\n const parts = intlFormatter(Intl.NumberFormat, this.#locale, {}, FALLBACK_LOCALE).formatToParts(\n 11111.1,\n );\n this.#group = parts.find((p) => p.type === \"group\")?.value ?? \",\";\n this.#decimal = parts.find((p) => p.type === \"decimal\")?.value ?? \".\";\n\n // Locales whose default numbering system is not Latin (ar-EG, fa-IR, …)\n // format with their own digits; mapping them back keeps the controller's\n // own output re-parseable to the same value.\n this.#digits.clear();\n const digitFormatter = intlFormatter(\n Intl.NumberFormat,\n this.#locale,\n { useGrouping: false },\n FALLBACK_LOCALE,\n );\n for (let i = 0; i <= 9; i++) {\n const digit = digitFormatter.format(i);\n if (digit !== String(i)) this.#digits.set(digit, String(i));\n }\n }\n\n /**\n * Maps the locale's own digits to ASCII, folds full-width forms (the digits,\n * signs, and marks an IME confirms as 0-9+-.,) through the shared\n * half-width mapping, and reads U+2212 MINUS SIGN as \"-\", which some locales'\n * formatted output uses for negatives.\n */\n #normalize(text: string): string {\n let out = \"\";\n for (const ch of text) {\n const mapped = this.#digits.get(ch);\n if (mapped !== undefined) {\n out += mapped;\n } else if (ch === \"−\") {\n out += \"-\";\n } else {\n out += halfWidthChar(ch);\n }\n }\n return out;\n }\n}\n\n/** Rounds `value` to `precision` decimal places, avoiding `-0`; overflow keeps `value`. */\nfunction round(value: number, precision: number): number {\n const factor = 10 ** Math.max(0, precision);\n const rounded = Math.round(value * factor) / factor;\n if (!Number.isFinite(rounded)) return value;\n return rounded === 0 ? 0 : rounded;\n}\n"]}
|
|
@@ -6,14 +6,16 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
6
6
|
*
|
|
7
7
|
* Markup contract (identifier: `stimeo--data-grid`):
|
|
8
8
|
* <table data-controller="stimeo--data-grid" role="grid" aria-label="Users"
|
|
9
|
-
* data-stimeo--data-grid-selection-value="single"
|
|
9
|
+
* data-stimeo--data-grid-selection-value="single"
|
|
10
|
+
* data-stimeo--data-grid-name-value="user_id">
|
|
11
|
+
* <caption><div data-stimeo--data-grid-target="fields"></div></caption>
|
|
10
12
|
* <thead><tr role="row">
|
|
11
13
|
* <th role="columnheader" aria-sort="none" tabindex="-1"
|
|
12
14
|
* data-stimeo--data-grid-target="columnHeader"
|
|
13
15
|
* data-action="click->stimeo--data-grid#sort
|
|
14
16
|
* keydown->stimeo--data-grid#onKeydown">Name</th>
|
|
15
17
|
* </tr></thead>
|
|
16
|
-
* <tbody><tr role="row" aria-selected="false"
|
|
18
|
+
* <tbody><tr role="row" aria-selected="false" data-value="7"
|
|
17
19
|
* data-stimeo--data-grid-target="row">
|
|
18
20
|
* <td role="gridcell" tabindex="0" data-stimeo--data-grid-target="cell"
|
|
19
21
|
* data-action="keydown->stimeo--data-grid#onKeydown">Jane</td>
|
|
@@ -25,15 +27,38 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
25
27
|
* `-1`); arrow keys move both DOM focus and that tabbable position. Sort state is
|
|
26
28
|
* exposed via `aria-sort` on headers, selection via `aria-selected` on rows.
|
|
27
29
|
*
|
|
28
|
-
* `selectionchange` dispatches `{ rows: HTMLElement[] }
|
|
30
|
+
* `selectionchange` dispatches `{ rows: HTMLElement[] }` when the user changes the
|
|
31
|
+
* selection; `sort` dispatches
|
|
29
32
|
* `{ column: HTMLElement, direction: "ascending" | "descending" | "none" }`.
|
|
30
33
|
*
|
|
34
|
+
* `reconcile` dispatches `{ rows: HTMLElement[] }` — the selected rows, as
|
|
35
|
+
* `selectionchange` carries them — when the page moves the selection instead: a
|
|
36
|
+
* selected row removed or dropped from the targets, a morph or a script writing
|
|
37
|
+
* a row's `aria-selected` or a selected row's `data-value`, a selected row that
|
|
38
|
+
* arrives ahead of the selection in `single` mode, or a runtime `selection` that
|
|
39
|
+
* collapses it. One batch of such changes reports once, and only when the
|
|
40
|
+
* selected rows or the values they submit differ from the selection last settled
|
|
41
|
+
* — on connect, by the user, or by the previous `reconcile` — so connecting
|
|
42
|
+
* reports nothing.
|
|
43
|
+
*
|
|
44
|
+
* With a `fields` target the selected rows are mirrored into `name`d hidden
|
|
45
|
+
* inputs so the selection can be submitted and read server-side — one per
|
|
46
|
+
* selected row that carries a `data-value`, in DOM order; a row without one
|
|
47
|
+
* submits nothing. `form` points them at a `<form>` by id when the container
|
|
48
|
+
* sits outside it. A selection the user made emits a native bubbling `change`
|
|
49
|
+
* from the container, the way a form control does, so `stimeo--auto-submit` and
|
|
50
|
+
* form-level validation hear it. The mirror is refreshed silently on connect,
|
|
51
|
+
* on a replacement container, on row churn, and whenever `selection`, `name` or
|
|
52
|
+
* `form` changes; a selection the page moved is reported by `reconcile` alone.
|
|
53
|
+
*
|
|
31
54
|
* @remarks
|
|
32
55
|
* Behavior only — the consumer performs the actual data sort/render in response to
|
|
33
|
-
* the `sort` event and owns all styling.
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
56
|
+
* the `sort` event and owns all styling. While connected a `MutationObserver`
|
|
57
|
+
* watches the rows' `aria-selected` and `data-value`, which a morph can rewrite
|
|
58
|
+
* without adding or removing a target; `disconnect()` releases it and drops a
|
|
59
|
+
* pending pass. `connect()` rebuilds the single tab stop idempotently from the
|
|
60
|
+
* DOM, and the target callbacks rebuild it again after rows or cells are added or
|
|
61
|
+
* removed at runtime.
|
|
37
62
|
*
|
|
38
63
|
* Behavior provided:
|
|
39
64
|
* - `Arrow*` move between cells (clamped at edges); `Home`/`End` to the row's
|
|
@@ -62,33 +87,53 @@ declare class DataGridController extends Controller<HTMLElement> {
|
|
|
62
87
|
type: StringConstructor;
|
|
63
88
|
default: string;
|
|
64
89
|
};
|
|
90
|
+
name: {
|
|
91
|
+
type: StringConstructor;
|
|
92
|
+
default: string;
|
|
93
|
+
};
|
|
94
|
+
form: {
|
|
95
|
+
type: StringConstructor;
|
|
96
|
+
default: string;
|
|
97
|
+
};
|
|
65
98
|
};
|
|
66
99
|
static actions: readonly ["onKeydown", "sort", "toggleSelect"];
|
|
67
|
-
static events: readonly ["selectionchange", "sort"];
|
|
100
|
+
static events: readonly ["selectionchange", "sort", "reconcile"];
|
|
68
101
|
readonly columnHeaderTargets: HTMLElement[];
|
|
69
102
|
readonly rowTargets: HTMLElement[];
|
|
70
103
|
readonly cellTargets: HTMLElement[];
|
|
104
|
+
readonly fieldsTarget: HTMLElement;
|
|
105
|
+
readonly hasFieldsTarget: boolean;
|
|
71
106
|
selectionValue: string;
|
|
107
|
+
nameValue: string;
|
|
108
|
+
formValue: string;
|
|
72
109
|
/**
|
|
73
|
-
* Establishes a single tab stop across all navigable cells/headers
|
|
74
|
-
*
|
|
110
|
+
* Establishes a single tab stop across all navigable cells/headers, brings the
|
|
111
|
+
* rows to their baseline, and settles the selection without reporting it.
|
|
75
112
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* cached
|
|
79
|
-
*
|
|
113
|
+
* The whole baseline runs here rather than in the Value callbacks: Stimulus
|
|
114
|
+
* delivers those before `connect()`, where the pass is refused, and a
|
|
115
|
+
* re-attached element reuses its cached context, whose value observer does not
|
|
116
|
+
* fire again.
|
|
80
117
|
*/
|
|
81
118
|
connect(): void;
|
|
82
|
-
/**
|
|
119
|
+
/** Releases the row observer and drops a queued pass, so neither outlives the element. */
|
|
83
120
|
disconnect(): void;
|
|
84
121
|
/**
|
|
85
|
-
*
|
|
86
|
-
* (
|
|
87
|
-
*
|
|
122
|
+
* Re-renders `aria-multiselectable`, the rows and the fields when application
|
|
123
|
+
* code (or a Turbo morph) changes `selection` at runtime; a selection the new
|
|
124
|
+
* mode collapses is reported as `reconcile`.
|
|
88
125
|
*/
|
|
89
126
|
selectionValueChanged(): void;
|
|
127
|
+
/** Rebuilds the submitted fields when the public name changes at runtime. */
|
|
128
|
+
nameValueChanged(): void;
|
|
129
|
+
/** Repoints the submitted fields when the owning form changes at runtime. */
|
|
130
|
+
formValueChanged(): void;
|
|
131
|
+
/** Seeds a fields container inserted after connect from the current selection. */
|
|
132
|
+
fieldsTargetConnected(): void;
|
|
90
133
|
/** Re-establishes the baselines for a row added after connect. */
|
|
91
134
|
rowTargetConnected(): void;
|
|
135
|
+
/** Settles the selection again when a row leaves the grid or drops its target token. */
|
|
136
|
+
rowTargetDisconnected(): void;
|
|
92
137
|
/** Re-establishes the tab stop when a cell joins the grid after connect. */
|
|
93
138
|
cellTargetConnected(): void;
|
|
94
139
|
/** Re-establishes the tab stop when a cell leaves the grid. */
|