stimeo-ui 0.16.0 → 0.17.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 +31 -0
- package/README.md +8 -1
- package/dist/cable/index.d.ts +79 -23
- package/dist/cable/index.js +363 -436
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +4 -2
- package/dist/controllers/accordion_controller.js +166 -55
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +12 -2
- package/dist/controllers/alert_dialog_controller.js +862 -221
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +35 -5
- package/dist/controllers/announcer_controller.js +135 -198
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/aspect_ratio_controller.js +0 -10
- package/dist/controllers/aspect_ratio_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.d.ts +30 -6
- package/dist/controllers/auto_submit_controller.js +271 -127
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +171 -105
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.js +0 -130
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +18 -0
- package/dist/controllers/bulk_select_controller.js +262 -52
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +24 -5
- package/dist/controllers/calendar_controller.js +175 -209
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +34 -7
- package/dist/controllers/carousel_controller.js +461 -399
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +17 -1
- package/dist/controllers/character_counter_controller.js +246 -156
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.d.ts +7 -2
- package/dist/controllers/checkbox_controller.js +32 -74
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +16 -5
- package/dist/controllers/clipboard_controller.js +168 -147
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +16 -4
- package/dist/controllers/collapsible_controller.js +301 -120
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +18 -6
- package/dist/controllers/color_picker_controller.js +149 -139
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +23 -5
- package/dist/controllers/combobox_controller.js +360 -133
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +45 -14
- package/dist/controllers/command_palette_controller.js +970 -358
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.d.ts +15 -2
- package/dist/controllers/conditional_fields_controller.js +166 -124
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +49 -12
- package/dist/controllers/confirm_controller.js +939 -248
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +31 -4
- package/dist/controllers/context_menu_controller.js +256 -128
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.d.ts +13 -1
- package/dist/controllers/count_up_controller.js +73 -21
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +45 -1
- package/dist/controllers/countdown_controller.js +183 -148
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +21 -2
- package/dist/controllers/currency_input_controller.js +134 -158
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +15 -4
- package/dist/controllers/data_grid_controller.js +114 -186
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +30 -5
- package/dist/controllers/date_range_picker_controller.js +288 -206
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +13 -1
- package/dist/controllers/dialog_controller.js +858 -223
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +24 -7
- package/dist/controllers/direct_upload_controller.js +73 -153
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.js +14 -48
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.d.ts +19 -0
- package/dist/controllers/dismissible_controller.js +175 -21
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +39 -11
- package/dist/controllers/drawer_controller.js +933 -341
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +31 -1
- package/dist/controllers/dropdown_controller.js +312 -82
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.d.ts +12 -1
- package/dist/controllers/editable_controller.js +158 -68
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.js +67 -53
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +60 -18
- package/dist/controllers/file_dropzone_controller.js +311 -207
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.js +67 -39
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +31 -8
- package/dist/controllers/flash_controller.js +172 -314
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +12 -3
- package/dist/controllers/focus_controller.js +654 -240
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +147 -132
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +13 -86
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +41 -9
- package/dist/controllers/frame_loading_controller.js +264 -213
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +22 -2
- package/dist/controllers/highlight_controller.js +107 -75
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +56 -3
- package/dist/controllers/hover_card_controller.js +309 -118
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +42 -1
- package/dist/controllers/idle_controller.js +267 -101
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.js +71 -72
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.d.ts +32 -13
- package/dist/controllers/intersection_controller.js +147 -106
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +16 -0
- package/dist/controllers/lazy_frame_controller.js +9 -65
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +34 -2
- package/dist/controllers/listbox_controller.js +306 -204
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +1 -1
- package/dist/controllers/local_time_controller.js +54 -64
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +11 -3
- package/dist/controllers/masonry_controller.js +70 -93
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +32 -7
- package/dist/controllers/menu_controller.js +214 -156
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +4 -4
- package/dist/controllers/menubar_controller.js +170 -329
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +20 -0
- package/dist/controllers/meter_controller.js +151 -67
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +32 -4
- package/dist/controllers/multi_select_controller.js +593 -358
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +8 -1
- package/dist/controllers/navigation_menu_controller.js +124 -232
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.d.ts +10 -0
- package/dist/controllers/nested_form_controller.js +352 -182
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.d.ts +23 -0
- package/dist/controllers/network_status_controller.js +242 -54
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +26 -2
- package/dist/controllers/number_input_controller.js +320 -263
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +16 -76
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +20 -4
- package/dist/controllers/otp_controller.js +198 -193
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
- package/dist/controllers/overflow_indicator_controller.js +116 -113
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +48 -11
- package/dist/controllers/overflow_menu_controller.js +343 -283
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +35 -6
- package/dist/controllers/pagination_controller.js +295 -119
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +45 -8
- package/dist/controllers/password_reveal_controller.js +389 -121
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +14 -5
- package/dist/controllers/password_strength_controller.js +99 -153
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +11 -4
- package/dist/controllers/persist_controller.js +237 -103
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +19 -7
- package/dist/controllers/pointer_drag_controller.js +185 -165
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +38 -2
- package/dist/controllers/popover_controller.js +236 -97
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +44 -4
- package/dist/controllers/portal_controller.js +209 -76
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.d.ts +10 -4
- package/dist/controllers/preview_guard_controller.js +232 -116
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +11 -0
- package/dist/controllers/progress_controller.js +125 -56
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +14 -5
- package/dist/controllers/radio_group_controller.js +117 -137
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +43 -3
- package/dist/controllers/range_slider_controller.js +192 -105
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +20 -4
- package/dist/controllers/rating_controller.js +418 -207
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +2 -0
- package/dist/controllers/read_more_controller.js +134 -63
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +1 -1
- package/dist/controllers/reading_progress_controller.js +147 -135
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.d.ts +18 -4
- package/dist/controllers/relative_time_controller.js +145 -110
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
- package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
- package/dist/controllers/reset_on_restore_controller.js.map +1 -0
- package/dist/controllers/resizable_controller.d.ts +28 -2
- package/dist/controllers/resizable_controller.js +255 -139
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.js +39 -84
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +7 -3
- package/dist/controllers/scroll_area_controller.js +428 -225
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.js +0 -53
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
- package/dist/controllers/scroll_visibility_controller.js +395 -145
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +6 -1
- package/dist/controllers/scrollspy_controller.js +181 -242
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +19 -4
- package/dist/controllers/separator_controller.js +267 -140
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +64 -7
- package/dist/controllers/sidebar_controller.js +1023 -386
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +23 -0
- package/dist/controllers/skeleton_controller.js +248 -97
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +27 -1
- package/dist/controllers/slider_controller.js +159 -79
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
- package/dist/controllers/smart_sticky_header_controller.js +162 -63
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +0 -112
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +39 -4
- package/dist/controllers/spinner_controller.js +277 -169
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +5 -0
- package/dist/controllers/step_indicator_controller.js +99 -46
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +12 -3
- package/dist/controllers/stepper_controller.js +114 -73
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +6 -0
- package/dist/controllers/stick_to_bottom_controller.js +262 -138
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.d.ts +11 -0
- package/dist/controllers/sticky_observer_controller.js +214 -49
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +23 -8
- package/dist/controllers/submit_once_controller.js +294 -205
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +12 -1
- package/dist/controllers/switch_controller.js +33 -60
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +2 -2
- package/dist/controllers/tabs_controller.js +35 -29
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +12 -0
- package/dist/controllers/tags_input_controller.js +136 -145
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
- package/dist/controllers/textarea_autosize_controller.js +71 -58
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +21 -9
- package/dist/controllers/theme_controller.js +130 -112
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +18 -1
- package/dist/controllers/time_picker_controller.js +146 -80
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +36 -11
- package/dist/controllers/toast_controller.js +186 -297
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +12 -3
- package/dist/controllers/toggle_group_controller.js +95 -136
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +68 -98
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +45 -3
- package/dist/controllers/tooltip_controller.js +158 -124
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.d.ts +22 -4
- package/dist/controllers/transition_controller.js +123 -119
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +21 -11
- package/dist/controllers/tree_view_controller.js +150 -345
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6370 -9346
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +23 -3
- package/dist/inspector/cli.js +92 -37
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +92 -56
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +8 -8
- package/dist/inspector/manifest.json +787 -100
- package/dist/positioning/index.d.ts +8 -0
- package/dist/positioning/index.js +148 -47
- package/dist/positioning/index.js.map +1 -1
- package/package.json +6 -6
- package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
- package/dist/controllers/reset_before_cache_controller.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/before_cache_reset.ts","../../src/utils/style_property_lease.ts","../../src/utils/transient_hooks.ts","../../src/controllers/preview_guard_controller.ts"],"names":[],"mappings":"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","file":"preview_guard_controller.js","sourcesContent":["/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way.\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/** One temporarily controlled style property and the authored declaration it displaced. */\ninterface StylePropertyLeaseRecord {\n readonly originalValue: string;\n readonly originalPriority: string;\n writtenValue: string | null;\n writtenPriority: string;\n}\n\n/**\n * Temporarily controls one inline CSS property across a changing set of elements.\n *\n * Authored value and priority are restored only while the declaration still matches\n * the last leased write. A later consumer write therefore wins.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events:\n * a consumer returns its leases from its own `turbo:before-cache` rewind.\n */\nexport class StylePropertyLease<T extends HTMLElement = HTMLElement> {\n readonly #property: string;\n readonly #records = new Map<T, StylePropertyLeaseRecord>();\n\n /** @param property - The CSS property whose temporary values this lease owns. */\n constructor(property: string) {\n this.#property = property;\n }\n\n /** Writes or removes the leased declaration while preserving its authored value. */\n write(element: T, value: string | null, priority = \"\"): void {\n const existing = this.#records.get(element);\n if (existing) {\n existing.writtenValue = value;\n existing.writtenPriority = value === null ? \"\" : priority;\n } else {\n this.#records.set(element, {\n originalValue: element.style.getPropertyValue(this.#property),\n originalPriority: element.style.getPropertyPriority(this.#property),\n writtenValue: value,\n writtenPriority: value === null ? \"\" : priority,\n });\n }\n\n this.#reflect(element, value, priority);\n }\n\n /** Returns one lease without overwriting a later consumer declaration. */\n return(element: T): void {\n const record = this.#records.get(element);\n if (!record) return;\n this.#records.delete(element);\n\n const style = element.style;\n const stillOwned =\n style.getPropertyValue(this.#property) === (record.writtenValue ?? \"\") &&\n style.getPropertyPriority(this.#property) === record.writtenPriority;\n if (stillOwned) {\n this.#reflect(element, record.originalValue, record.originalPriority);\n }\n }\n\n /** Returns every outstanding declaration lease. */\n returnAll(): void {\n for (const element of Array.from(this.#records.keys())) this.return(element);\n }\n\n /** Reflects only a real declaration transition. */\n #reflect(element: T, value: string | null, priority: string): void {\n const style = element.style;\n const nextValue = value ?? \"\";\n const nextPriority = value === null ? \"\" : priority;\n if (\n style.getPropertyValue(this.#property) === nextValue &&\n style.getPropertyPriority(this.#property) === nextPriority\n ) {\n return;\n }\n if (value === null) style.removeProperty(this.#property);\n else style.setProperty(this.#property, value, priority);\n }\n}\n","/**\n * Drops the transient state hooks a connection inherited, so the cycle it opens\n * starts from a DOM that claims nothing.\n *\n * A transient hook is an attribute a controller writes to say \"this is happening\n * right now\" — a drag in progress, a form with unsaved edits, a refused\n * subscription. Its lifetime belongs to the interaction, not to the element, and\n * the two come apart whenever the element outlives the instance that wrote it: a\n * Turbo cache snapshot taken mid-interaction restores the hook with the markup,\n * and an element re-inserted elsewhere in the page carries it along. Nothing\n * takes such a hook off, because the instance that owned it is gone; consumer\n * CSS then keeps claiming a state no one is in.\n *\n * **`turbo:before-cache` cannot do this job**, which is why the pass belongs in\n * `connect()`: that event fires for a navigation only, so an in-page move — the\n * other half of the population — never reaches it, and a hook that arrived with\n * a moved element would survive. `connect()` covers both, because both end in a\n * connection.\n *\n * Scope is the **drop** only. What the fresh cycle should say instead is the\n * consumer's: a value re-read from the live DOM, a roster refilled by the\n * stream, a measurement retaken from the current scroll position, a slot emptied\n * of the last result. Those answers differ per consumer and none of them is a\n * hook removal, so the pass stops where every consumer agrees.\n *\n * A declaration names one group of hooks and carries no per-instance state, so\n * it belongs at module scope, shared by every instance the page connects. A\n * consumer writes as many as it has groups — hooks it drops under different\n * conditions cannot share one. The exception is a hook whose name is only known\n * at runtime, such as one built from the registered identifier: that\n * declaration is a field, because the name is.\n *\n * **A drop is not always right.** The population splits on one question: can the\n * state a hook describes outlive the instance that wrote it? Where it cannot — a\n * drag ends with the pointer, a subscription dies with its socket — dropping on\n * every connection is correct. Where it can — a submission in flight is not\n * interrupted by an in-page move — only a connection that follows a real restore\n * may drop, and the consumer answers \"did a session survive?\" with the signal it\n * already holds for its own teardown (a live-session field, a `DetachGate`\n * probe). The drop then sits behind that answer, as the second example shows.\n *\n * @example Unconditional — the state cannot outlive the instance.\n * ```ts\n * const TRANSIENT = new TransientHooks({ attributes: [\"data-sortable-dragging\"] });\n *\n * connect(): void {\n * TRANSIENT.reset(this.element);\n * }\n * ```\n *\n * @example Gated — an in-page move must not drop a live state.\n * ```ts\n * const TRANSIENT = new TransientHooks({ attributes: [\"data-optimistic\"] });\n *\n * connect(): void {\n * const restored = !this.#connected && !this.#gate.pending;\n * this.#gate.cancel();\n * this.#connected = true;\n * if (restored) TRANSIENT.reset(this.element);\n * }\n * ```\n */\n\n/** What a consumer declares once about the hooks its interaction owns. */\nexport interface TransientHooksOptions {\n /**\n * The attribute names a connection may find written by an earlier one. Hooks\n * a consumer drops under different conditions belong to different\n * declarations, so each one can be reset on its own.\n */\n readonly attributes: readonly string[];\n}\n\n/**\n * One consumer's declaration of the hooks its interaction owns, dropped from an\n * element by {@link TransientHooks.reset}.\n *\n * Every member comment inside this class body is inlined into each consumer\n * bundle (`tsup` builds with `splitting: false`), so rationale belongs in this\n * file's own block, which `dist` drops, and only the contract belongs inside.\n */\nexport class TransientHooks {\n readonly #attributes: readonly string[];\n\n constructor(options: TransientHooksOptions) {\n this.#attributes = options.attributes;\n }\n\n /** Drops the declared hooks from `element`; what it carries besides stays. */\n reset(element: Element): void {\n for (const attribute of this.#attributes) element.removeAttribute(attribute);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport { StylePropertyLease } from \"../utils/style_property_lease\";\nimport { TransientHooks } from \"../utils/transient_hooks\";\n\n/** The hook a connection may find written by an earlier, now-gone one. */\nconst TRANSIENT = new TransientHooks({ attributes: [\"data-preview-hidden\"] });\n\n/**\n * Headless **preview guard** (Hotwire-specific): hides or placeholders a volatile element\n * — a balance, a notification count, a live timestamp — *only while Turbo is showing a\n * preview* (`html[data-turbo-preview]`), so a stale cached snapshot does not briefly flash\n * the old value on a back/restore visit. No APG pattern; it keeps displayed information\n * accurate and hands focus back if guarding took it.\n *\n * Markup contract (identifier: `stimeo--preview-guard`):\n * <span data-controller=\"stimeo--preview-guard\"\n * data-stimeo--preview-guard-placeholder-value=\"—\">¥123,456</span>\n *\n * Watches `<html>` for the `data-turbo-preview` attribute with a `MutationObserver`.\n * While it is present the element is guarded, and `placeholder` alone decides how: empty\n * (the default) makes it `visibility: hidden` — its box is kept, so nothing shifts — and\n * any other value takes its place as the element's content. The element carries\n * `data-preview-hidden` and emits `hide`; when the preview clears it is restored and\n * `show` fires. A `placeholder` changed while guarded re-guards to match it.\n *\n * `hide` and `show` dispatch `{}`.\n *\n * @remarks\n * Behavior only — restoring the *fresh* value is the normal render's job, not this\n * controller's (it just un-hides what was there). State is derived from the DOM (no\n * module-scope state), and the guard is reversible in three ways that do not depend on\n * each other: the child nodes a placeholder displaced are held and put back intact, the\n * inline `visibility` is leased so an authored declaration — and one the consumer writes\n * while guarded — survives, and a fresh `connect()` clears a `data-preview-hidden` it\n * finds already on the element. The rewind Turbo's snapshot needs runs on\n * `turbo:before-cache` rather than `disconnect()`, so an in-page move keeps the guard\n * instead of flashing the stale value between the two lifecycle calls — and the instance\n * that comes back re-forms it rather than reading the hook as someone else's leftover.\n *\n * Focus is only ever handed back, never taken: an element that held focus when the guard\n * went up gets it back on show, and focus resting anywhere else is left alone.\n */\nexport class PreviewGuardController extends Controller<HTMLElement> {\n static override values = {\n placeholder: { type: String, default: \"\" },\n };\n static events = [\"hide\", \"show\"] as const;\n\n declare placeholderValue: string;\n\n readonly #visibility = new StylePropertyLease(\"visibility\");\n readonly #beforeCache = new BeforeCacheReset(() => this.#restore());\n\n #observer: MutationObserver | null = null;\n #connected = false;\n #hidden = false;\n /** Child nodes a placeholder displaced; non-null marks that content — not visibility — was swapped. */\n #savedNodes: DocumentFragment | null = null;\n /** The descendant that held focus when the guard went up, so show can hand it back. */\n #focused: HTMLElement | null = null;\n\n override connect(): void {\n this.#connected = true;\n // The hook means \"the connection now running has this element guarded\", and which of\n // the two connects is happening is only knowable from the instance. A restored\n // snapshot brings a fresh controller to an element that still carries the hook, with\n // nothing in the DOM to say what was underneath it, so that one drops it. An in-page\n // move brings the *same* instance back still holding the guard, so that one re-forms\n // instead — against the `placeholder` as it stands now, since a morph can swap it\n // while the element is detached, where the value callback has no connection to act on.\n if (this.#hidden) this.#reguard();\n else TRANSIENT.reset(this.element);\n this.#beforeCache.activate();\n if (typeof MutationObserver !== \"undefined\") {\n this.#observer = new MutationObserver(() => this.#sync());\n this.#observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-turbo-preview\"],\n });\n }\n // Sync once in case we connect while a preview is already on screen.\n this.#sync();\n }\n\n override disconnect(): void {\n this.#connected = false;\n this.#beforeCache.deactivate();\n this.#observer?.disconnect();\n this.#observer = null;\n }\n\n /**\n * Re-guards to match a `placeholder` changed at runtime — the value is the content on\n * display while the guard is up, so a morph that swaps it must not leave the old one.\n */\n placeholderValueChanged(): void {\n if (!this.#connected || !this.#hidden) return;\n this.#reguard();\n }\n\n /**\n * Reflects the current `data-turbo-preview` state onto the element.\n *\n * @stimeoRenderRoot\n */\n #sync(): void {\n const previewing = document.documentElement.hasAttribute(\"data-turbo-preview\");\n if (previewing && !this.#hidden) this.#hide();\n else if (!previewing && this.#hidden) this.#show();\n }\n\n #hide(): void {\n this.#focused = this.#focusedInside();\n this.#applyGuard();\n this.dispatch(\"hide\", { detail: {} });\n }\n\n /** Puts the guard up in the form the current `placeholder` calls for. */\n #applyGuard(): void {\n this.#hidden = true;\n if (this.placeholderValue === \"\") {\n this.#visibility.write(this.element, \"hidden\");\n } else {\n this.#savedNodes = document.createDocumentFragment();\n this.#savedNodes.append(...this.element.childNodes);\n this.element.textContent = this.placeholderValue;\n }\n this.element.setAttribute(\"data-preview-hidden\", \"true\");\n }\n\n /**\n * Re-forms a guard that is already up so it matches the current `placeholder`.\n *\n * No event: `hide` reports that the guard went up, and it has not come down. Swapping\n * one stand-in text for another writes only that text — putting the held content back\n * first would reconnect the whole subtree for an instant. Only a change of *form* —\n * to or from the empty placeholder — has to revert, and the focus the guard is holding\n * carries across it rather than being handed back and taken again.\n *\n * @stimeoRenderRoot\n */\n #reguard(): void {\n if (this.#savedNodes && this.placeholderValue !== \"\") {\n this.element.textContent = this.placeholderValue;\n return;\n }\n const held = this.#focused;\n this.#revert();\n this.#applyGuard();\n this.#focused = held;\n }\n\n #show(): void {\n this.#restore();\n this.dispatch(\"show\", { detail: {} });\n }\n\n /** Reverts the guard and hands focus back. Used by show and by the snapshot rewind. */\n #restore(): void {\n this.#revert();\n this.#refocus();\n }\n\n /**\n * Puts the element back the way the guard found it.\n *\n * Every step is a no-op on an element this controller never guarded: the lease returns\n * only declarations it recorded, and the hook is removed whether or not it is there.\n */\n #revert(): void {\n this.#hidden = false;\n if (this.#savedNodes) {\n this.element.textContent = \"\";\n this.element.append(this.#savedNodes);\n this.#savedNodes = null;\n } else {\n this.#visibility.return(this.element);\n }\n this.element.removeAttribute(\"data-preview-hidden\");\n }\n\n /**\n * The focused element the guard is about to make unfocusable, if any.\n *\n * The element itself counts as well as its descendants: guarding takes focus either way\n * — a `visibility: hidden` subtree cannot hold it, and a placeholder displaces the nodes\n * outright — so the browser drops focus to `<body>` the moment the guard goes up.\n */\n #focusedInside(): HTMLElement | null {\n const active = document.activeElement;\n return active instanceof HTMLElement && this.element.contains(active) ? active : null;\n }\n\n /**\n * Hands focus back to the element the guard took it from.\n *\n * Only when that element is still in the document and focus has not moved on since —\n * anything else is the user's or another controller's, and putting it back would be\n * taking it.\n */\n #refocus(): void {\n const target = this.#focused;\n this.#focused = null;\n if (!target?.isConnected || document.activeElement !== document.body) return;\n target.focus();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/listener_set.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/morph_render_watcher.ts","../../src/utils/shared_registry.ts","../../src/utils/style_property_lease.ts","../../src/utils/transient_hooks.ts","../../src/controllers/preview_guard_controller.ts"],"names":[],"mappings":"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","file":"preview_guard_controller.js","sourcesContent":["/**\n * Owns every listener a controller attaches for one connected lifetime and\n * releases them together, so an event name is spelled once and the release\n * cannot drift from the registration.\n *\n * Detaching by hand repeats three things at the release site — the type, the\n * handler reference and the capture flag — and any one of them drifting leaves\n * a listener alive on an element the controller no longer drives. Aborting the\n * signal a registration was created with releases it whatever it was made of,\n * so the release site names nothing.\n *\n * One set per lifetime, held as a field and never rebuilt. {@link\n * ListenerSet.dispose} is the only thing that closes a generation, and it opens\n * the next one in the same step, so the lifecycle hooks can call `add` and\n * `dispose` in any order any number of times, and no `add` ever meets an\n * already aborted signal — a DOM that registers a listener on such a signal\n * would keep it forever. Rebuilding the set instead would leak:\n * `addEventListener` matches an existing registration on target, type, callback\n * and capture alone, so re-adding the same handler while the first registration\n * is live is discarded, and that live registration keeps the signal it was\n * attached with — a set built by a second `connect()` can never release what it\n * appears to own.\n *\n * Scope is the registration only. Timers, observers, leases and the order they\n * are unwound in stay with the controller, which places `dispose()` in its\n * cleanup sequence. A receiver that changes at runtime (a\n * swapped target) is rebound by calling `dispose()` and then `add()` again from\n * the rebind, not by a second set.\n *\n * The set must own every registration of a tuple it holds: a listener the same\n * target already carries for the same type, callback and capture flag keeps the\n * right to remove it, and this set's `add` for that tuple is discarded. A\n * subscription shared between instances behind a participant count, or one that\n * lives for less than the connection, keeps its own pair of calls.\n *\n * @example\n * ```ts\n * readonly #listeners = new ListenerSet();\n *\n * connect(): void {\n * this.#listeners.add(this.element, \"submit\", this.#onNativeSubmit, { capture: true });\n * this.#listeners.add(this.element, \"turbo:submit-start\", this.#onSubmitStart);\n * this.#listeners.add(this.element, \"turbo:submit-end\", this.#onSubmitEnd);\n * }\n *\n * disconnect(): void {\n * this.#listeners.dispose();\n * }\n * ```\n */\nexport class ListenerSet {\n /** The generation every `add` joins until the next `dispose()`. */\n #abort = new AbortController();\n\n /**\n * Attaches `handler` to the open generation, exactly as the caller spelled it.\n *\n * The set supplies the signal, so `options` carries everything else the DOM\n * accepts — `capture` included, which has to match at release time and no\n * longer has a second place to drift from.\n */\n add(\n target: EventTarget,\n type: string,\n handler: EventListener,\n options?: Omit<AddEventListenerOptions, \"signal\">,\n ): void {\n target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });\n }\n\n /**\n * Releases every listener of the open generation, synchronously, and opens the\n * next one. Idempotent, and safe before anything has been added.\n */\n dispose(): void {\n this.#abort.abort();\n this.#abort = new AbortController();\n }\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * @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 { ListenerSet } from \"./listener_set\";\nimport { MicrotaskCoalescer } from \"./microtask_coalescer\";\n\n/**\n * Coalesces retained-element morphs and explicit lifecycle requests into one pass.\n *\n * Observe the controller's element after its initial state is settled. Morphs on\n * that element and bubbling morphs on its descendants share the same microtask\n * as {@link schedule}. The callback repairs derived output; the controller owns\n * any logical transition reporting. {@link disconnect} releases the listener and\n * cancels pending work, including work from an earlier connected lifetime.\n */\nexport class MorphRenderWatcher {\n readonly #listeners = new ListenerSet();\n readonly #pass: MicrotaskCoalescer;\n #element: Element | null = null;\n readonly #onMorph = (): void => this.#pass.schedule();\n\n /** @param run - the single pass that repairs the settled controller's output. */\n constructor(run: () => void) {\n this.#pass = new MicrotaskCoalescer(run);\n }\n\n /** Opens observation; observing the same element again preserves queued work. */\n observe(element: Element): void {\n if (this.#element === element) return;\n this.disconnect();\n this.#element = element;\n this.#pass.activate();\n this.#listeners.add(element, \"turbo:morph-element\", this.#onMorph);\n }\n\n /** Requests one pass; requests outside an observed lifetime are ignored. */\n schedule(): void {\n this.#pass.schedule();\n }\n\n /** Releases observation and pending work synchronously; safe to repeat. */\n disconnect(): void {\n this.#listeners.dispose();\n this.#pass.cancel();\n this.#element = null;\n }\n}\n","/**\n * One registry per page for every copy of the library.\n *\n * Each `stimeo-ui/controllers/*` file, and each opt-in entry, is built on its own and carries\n * its own copy of every utility it uses, so a page that imports controllers one by one, or one\n * of them next to the barrel, evaluates a utility several times. A registry that coordinates\n * instances of different controllers — the stacks of leased values, the loans of a\n * `tabindex`, the Escape layers, the focus traps — must not be split by that: a dialog inside\n * a drawer, or a character counter and a form field on one input, coordinate whichever files\n * they came from. So such a registry lives once on `globalThis`, under a `Symbol.for` key the\n * copies agree on, and the first copy to ask for it creates it.\n *\n * The key names the registry and the version of its shape\n * (`stimeo-ui.<utility>.registry.v<n>`). Copies whose registries have the same shape share\n * one; a release that changes the shape changes the version, so a copy of another release\n * keeps a registry of its own instead of reading entries it does not understand — the two\n * then coordinate within each release only. An entry another copy put in a registry is read\n * through its fields alone, never through `#private` members, which belong to the class of\n * the copy that created it.\n */\n\n/**\n * The registry stored under `key`, created by `create` on first use.\n *\n * @param key - `stimeo-ui.<utility>.registry.v<n>`: the version is that of the shape `create`\n * returns.\n * @param create - Builds the empty registry.\n */\nexport function sharedRegistry<T extends object>(key: string, create: () => T): T {\n const symbol = Symbol.for(key);\n const scope = globalThis as unknown as Record<symbol, T | undefined>;\n const existing = scope[symbol];\n if (existing !== undefined) return existing;\n const registry = create();\n Object.defineProperty(globalThis, symbol, { value: registry });\n return registry;\n}\n","import { sharedRegistry } from \"./shared_registry\";\n\n/** What a lease's record says: the authored declaration, the last write and the leases beneath. */\ninterface StylePropertyLeaseRecord {\n readonly originalValue: string;\n readonly originalPriority: string;\n readonly writtenValue: string | null;\n readonly writtenPriority: string;\n /** Whether it hands back what the lease right beneath it wrote last. */\n readonly linked: boolean;\n /** The records of the other owners' leases beneath it, nearest first. */\n readonly beneath: readonly string[];\n}\n\n/** One lease's hold on one element's property, in the stack every lease of it shares. */\ninterface StyleHold {\n /** The lease holding it; `null` for a hold read from a copy's record until its lease takes it. */\n lease: object | null;\n readonly record: string;\n writtenValue: string | null;\n writtenPriority: string;\n /** What it hands back with nothing beneath it: the author's declaration. */\n readonly originalValue: string;\n readonly originalPriority: string;\n /** Whether it hands back what the hold beneath it wrote last instead. */\n linked: boolean;\n}\n\n/** The holds on each element by property, and every lease's record name by property. */\ninterface StylePropertyLeaseRegistry {\n readonly stacks: WeakMap<HTMLElement, Map<string, StyleHold[]>>;\n readonly names: Map<string, Set<string>>;\n}\n\n/**\n * Temporarily controls one inline CSS property across a changing set of elements.\n *\n * Authored value and priority are restored only while the declaration still matches\n * the last leased write. A later consumer write therefore wins.\n *\n * **Every lease of a property shares one stack of holds per element**, whatever its owner\n * and whichever file of the package constructed it (the stacks are one per page): the holds\n * sit in the order their leases first wrote the element, each with the declaration it wrote\n * last. The element's declaration is the highest hold's that carries it, and the page's when\n * none does. A write reaches the element unless a hold above the writer carries the element's\n * declaration, so the top hold always shows its writes and the page's declaration gives way to\n * the next write of any hold. A return gives a declaration back only from the hold the\n * element's declaration is: the one the hold beneath it wrote last, or the author's once\n * nothing is beneath it; any other return only leaves the stack. Holds that wrote the same\n * declaration are told apart by the stack: the higher one keeps it. A first write over a top\n * hold whose declaration the page has replaced takes the element's declaration as the\n * author's. Two instances of one controller that write the same property on\n * `document.documentElement` stack the same way.\n *\n * **The stack travels with the element.** While a hold carries a declaration other than the\n * author's, lies on another hold or is covered by one, the element carries its owner's record\n * `data-<owner>-style-<property>-lease`: JSON of the author's value and priority, the value\n * and priority the hold wrote last (`null` for a removal), `false` where the hold hands back\n * the author's declaration rather than the latest one of the hold beneath it, and the records\n * of every hold beneath it, nearest first. Returning the last lease of an owner removes its\n * record. A copy of the element — a page Turbo restores from its cache — therefore carries the\n * stack, read back under the record names of the leases constructed so far and ordered by the\n * records each hold lists beneath it, and each lease takes the hold its owner's record\n * describes over in place. Complete records for distinct owners preserve their order across\n * a copy. Records describe owners, not instances: one owner holding the element more than\n * once leaves only its topmost hold's record, which the first of its leases to write or return\n * on the copy takes. Its lower holds and positions are absent; mutually listed owners cannot\n * express their full live order. A hold that showed the author's declaration alone carries\n * no record and is taken by its first write on the copy. Missing or unreadable records also\n * leave their holds unknown, so copying the DOM does not promise identical decisions for\n * every live stack. A new stack with no readable record takes the current declaration as the\n * author's; a morph can remove records while existing holds remain in memory until returned.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events.\n */\nexport class StylePropertyLease<T extends HTMLElement = HTMLElement> {\n /** The holds on each element, bottom first, and the record names; one per page. */\n static readonly #registry = sharedRegistry(\n \"stimeo-ui.style-property-lease.registry.v1\",\n (): StylePropertyLeaseRegistry => ({ stacks: new WeakMap(), names: new Map() }),\n );\n readonly #property: string;\n readonly #record: string;\n readonly #held = new Set<T>();\n\n /**\n * @param property - The CSS property whose temporary values this lease owns.\n * @param owner - Names the record on the element; the controller's identifier.\n */\n constructor(property: string, owner: string) {\n this.#property = property;\n this.#record = `data-${owner}-style-${property}-lease`;\n const names = StylePropertyLease.#registry.names;\n names.set(property, (names.get(property) ?? new Set<string>()).add(this.#record));\n }\n\n /** Writes or removes the leased declaration while preserving its authored value. */\n write(element: T, value: string | null, priority = \"\"): void {\n const stack = this.#stack(element);\n const hold = this.#take(stack) ?? this.#acquire(element, stack);\n this.#held.add(element);\n const shows = !this.#covered(element, stack, hold);\n hold.writtenValue = value;\n hold.writtenPriority = value === null ? \"\" : priority;\n this.#mark(element, stack);\n if (shows) this.#show(element, value, hold.writtenPriority);\n }\n\n /**\n * Returns one lease, also on a restored copy, to the declaration the hold beneath it wrote\n * last or the author's, without overwriting a declaration a consumer wrote since.\n */\n return(element: T): void {\n const held = this.#held.delete(element);\n const known = StylePropertyLease.#registry.stacks.get(element)?.has(this.#property);\n const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];\n const hold = this.#take(stack);\n if (!hold) return;\n const owns = this.#carries(element, hold) && !this.#covered(element, stack, hold);\n const index = stack.indexOf(hold);\n stack.splice(index, 1);\n const above = stack[index];\n if (above) above.linked &&= hold.linked;\n this.#mark(element, stack);\n if (!owns) return;\n const below = hold.linked ? stack[index - 1] : undefined;\n if (below) this.#show(element, below.writtenValue, below.writtenPriority);\n else this.#show(element, hold.originalValue, hold.originalPriority);\n }\n\n /** Returns every outstanding declaration lease. */\n returnAll(): void {\n for (const element of Array.from(this.#held)) this.return(element);\n }\n\n /** The record `name` on `element`, or `null` when it is none a lease could write. */\n #recorded(element: T, name: string): StylePropertyLeaseRecord | null {\n try {\n const parsed: unknown = JSON.parse(element.getAttribute(name) ?? \"null\");\n if (!Array.isArray(parsed)) return null;\n const [originalValue, originalPriority, writtenValue, writtenPriority, ...rest] =\n parsed as unknown[];\n if (typeof originalValue !== \"string\" || typeof originalPriority !== \"string\") return null;\n if (typeof writtenValue !== \"string\" && writtenValue !== null) return null;\n if (typeof writtenPriority !== \"string\") return null;\n const linked = rest[0] !== false;\n const beneath = linked ? rest : rest.slice(1);\n if (!beneath.every((under): under is string => typeof under === \"string\")) return null;\n return { originalValue, originalPriority, writtenValue, writtenPriority, linked, beneath };\n } catch {\n return null;\n }\n }\n\n /** The element's stack, read from its records the first time. */\n #stack(element: T): StyleHold[] {\n const stacks = StylePropertyLease.#registry.stacks;\n const byProperty = stacks.get(element) ?? new Map<string, StyleHold[]>();\n stacks.set(element, byProperty);\n const stack = byProperty.get(this.#property) ?? this.#seed(element);\n byProperty.set(this.#property, stack);\n return stack;\n }\n\n /** The holds a copy's records describe, each above every hold its record lists beneath. */\n #seed(element: T): StyleHold[] {\n const found: (StylePropertyLeaseRecord & { readonly record: string })[] = [];\n for (const record of StylePropertyLease.#registry.names.get(this.#property) ?? []) {\n const read = this.#recorded(element, record);\n if (read) found.push({ ...read, record });\n }\n const depth = ({ beneath }: (typeof found)[number]) =>\n beneath.filter((name) => found.some((other) => other.record === name)).length;\n return found\n .sort((one, other) => depth(one) - depth(other))\n .map((entry, index) => ({\n lease: null,\n record: entry.record,\n writtenValue: entry.writtenValue,\n writtenPriority: entry.writtenPriority,\n originalValue: entry.originalValue,\n originalPriority: entry.originalPriority,\n linked: entry.linked && index > 0,\n }));\n }\n\n /** Its hold in `stack`, taking over one read from its record. */\n #take(stack: StyleHold[]): StyleHold | undefined {\n const hold =\n stack.find((held) => held.lease === this) ??\n stack.find((held) => held.lease === null && held.record === this.#record);\n if (hold) hold.lease = this;\n return hold;\n }\n\n /** A new hold on top, over the top hold while the element carries its declaration. */\n #acquire(element: T, stack: StyleHold[]): StyleHold {\n const top = stack.at(-1);\n const over = top && this.#carries(element, top) ? top : undefined;\n const style = element.style;\n const hold: StyleHold = {\n lease: this,\n record: this.#record,\n writtenValue: null,\n writtenPriority: \"\",\n originalValue: over ? over.originalValue : style.getPropertyValue(this.#property),\n originalPriority: over ? over.originalPriority : style.getPropertyPriority(this.#property),\n linked: over !== undefined,\n };\n stack.push(hold);\n return hold;\n }\n\n /** Whether a hold above `hold` carries the element's declaration, then that hold's. */\n #covered(element: T, stack: readonly StyleHold[], hold: StyleHold): boolean {\n return stack.slice(stack.indexOf(hold) + 1).some((above) => this.#carries(element, above));\n }\n\n /** Leaves each owner's record of its topmost hold, or none where nothing needs one. */\n #mark(element: T, stack: readonly StyleHold[]): void {\n const records = new Map<string, string | null>([[this.#record, null]]);\n stack.forEach((hold, index) => {\n const names = stack.slice(0, index).map((under) => under.record);\n const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);\n const marker = hold.linked || beneath.length === 0 ? [] : [false];\n const { originalValue, originalPriority, writtenValue, writtenPriority } = hold;\n records.set(\n hold.record,\n (writtenValue ?? \"\") === originalValue &&\n writtenPriority === originalPriority &&\n beneath.length === 0 &&\n index === stack.length - 1\n ? null\n : JSON.stringify([\n originalValue,\n originalPriority,\n writtenValue,\n writtenPriority,\n ...marker,\n ...beneath,\n ]),\n );\n });\n for (const [name, recorded] of records) {\n if (element.getAttribute(name) === recorded) continue;\n if (recorded === null) element.removeAttribute(name);\n else element.setAttribute(name, recorded);\n }\n }\n\n /** Whether the element carries the declaration `hold` wrote last. */\n #carries(element: T, hold: StyleHold): boolean {\n return this.#holds(element, hold.writtenValue ?? \"\", hold.writtenPriority);\n }\n\n /** Whether the inline declaration is `value` with `priority`. */\n #holds(element: T, value: string, priority: string): boolean {\n const style = element.style;\n return (\n style.getPropertyValue(this.#property) === value &&\n style.getPropertyPriority(this.#property) === priority\n );\n }\n\n /** Writes the declaration, or removes it for `null`, unless the element already carries it. */\n #show(element: T, value: string | null, priority: string): void {\n if (this.#holds(element, value ?? \"\", priority)) return;\n if (value === null) element.style.removeProperty(this.#property);\n else element.style.setProperty(this.#property, value, priority);\n }\n}\n","/**\n * Drops the transient state hooks a connection inherited, so the cycle it opens\n * starts from a DOM that claims nothing.\n *\n * A transient hook is an attribute a controller writes to say \"this is happening\n * right now\" — a drag in progress, a form with unsaved edits, a refused\n * subscription. Its lifetime belongs to the interaction, not to the element, and\n * the two come apart whenever the element outlives the instance that wrote it: a\n * Turbo cache snapshot taken mid-interaction restores the hook with the markup,\n * and an element re-inserted elsewhere in the page carries it along. Nothing\n * takes such a hook off, because the instance that owned it is gone; consumer\n * CSS then keeps claiming a state no one is in.\n *\n * **`turbo:before-cache` cannot do this job**, which is why the pass belongs in\n * `connect()`: Turbo also dispatches that event on pages that stay, where the hook\n * is still true, and an in-page move — the other half of the population — never\n * reaches it, so a hook that arrived with a moved element would survive.\n * `connect()` covers both, because both end in a connection.\n *\n * Scope is the **drop** only. What the fresh cycle should say instead is the\n * consumer's: a value re-read from the live DOM, a roster refilled by the\n * stream, a measurement retaken from the current scroll position, a slot emptied\n * of the last result. Those answers differ per consumer and none of them is a\n * hook removal, so the pass stops where every consumer agrees.\n *\n * A declaration names one group of hooks and carries no per-instance state, so\n * it belongs at module scope, shared by every instance the page connects. A\n * consumer writes as many as it has groups — hooks it drops under different\n * conditions cannot share one. The exception is a hook whose name is only known\n * at runtime, such as one built from the registered identifier: that\n * declaration is a field, because the name is.\n *\n * **A drop is not always right.** The population splits on one question: can the\n * state a hook describes outlive the instance that wrote it? Where it cannot — a\n * drag ends with the pointer, a subscription dies with its socket — dropping on\n * every connection is correct. Where it can — a submission in flight is not\n * interrupted by an in-page move — only a connection that follows a real restore\n * may drop, and the consumer answers \"did a session survive?\" with the signal it\n * already holds for its own teardown (a live-session field, a `DetachGate`\n * probe). The drop then sits behind that answer, as the second example shows.\n *\n * @example Unconditional — the state cannot outlive the instance.\n * ```ts\n * const TRANSIENT = new TransientHooks({ attributes: [\"data-sortable-dragging\"] });\n *\n * connect(): void {\n * TRANSIENT.reset(this.element);\n * }\n * ```\n *\n * @example Gated — an in-page move must not drop a live state.\n * ```ts\n * const TRANSIENT = new TransientHooks({ attributes: [\"data-optimistic\"] });\n *\n * connect(): void {\n * const restored = !this.#connected && !this.#gate.pending;\n * this.#gate.cancel();\n * this.#connected = true;\n * if (restored) TRANSIENT.reset(this.element);\n * }\n * ```\n */\n\n/** What a consumer declares once about the hooks its interaction owns. */\nexport interface TransientHooksOptions {\n /**\n * The attribute names a connection may find written by an earlier one. Hooks\n * a consumer drops under different conditions belong to different\n * declarations, so each one can be reset on its own.\n */\n readonly attributes: readonly string[];\n}\n\n/**\n * One consumer's declaration of the hooks its interaction owns, dropped from an\n * element by {@link TransientHooks.reset}.\n */\nexport class TransientHooks {\n readonly #attributes: readonly string[];\n\n constructor(options: TransientHooksOptions) {\n this.#attributes = options.attributes;\n }\n\n /** Drops the declared hooks from `element`; what it carries besides stays. */\n reset(element: Element): void {\n for (const attribute of this.#attributes) element.removeAttribute(attribute);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { MorphRenderWatcher } from \"../utils/morph_render_watcher\";\nimport { StylePropertyLease } from \"../utils/style_property_lease\";\nimport { TransientHooks } from \"../utils/transient_hooks\";\n\n/** The hook a connection may find written by an earlier, now-gone one. */\nconst TRANSIENT = new TransientHooks({ attributes: [\"data-preview-hidden\"] });\n\n/** Suffix of the record of the content a placeholder displaced; see the class remarks. */\nconst CONTENT_RECORD = \"content\";\n\n/**\n * Headless **preview guard** (Hotwire-specific): hides or placeholders a volatile element\n * — a balance, a notification count, a live timestamp — *only while Turbo is showing a\n * preview* (`html[data-turbo-preview]`), so a stale cached snapshot does not briefly flash\n * the old value on a back/restore visit. No APG pattern; it keeps displayed information\n * accurate and hands focus back if guarding took it.\n *\n * Markup contract (identifier: `stimeo--preview-guard`):\n * <span data-controller=\"stimeo--preview-guard\"\n * data-stimeo--preview-guard-placeholder-value=\"—\">¥123,456</span>\n *\n * Watches `<html>` for the `data-turbo-preview` attribute with a `MutationObserver`.\n * While it is present the element is guarded, and `placeholder` alone decides how: empty\n * (the default) makes it `visibility: hidden` — its box is kept, so nothing shifts — and\n * any other value takes its place as the element's content. The element carries\n * `data-preview-hidden` and emits `hide`; when the preview clears it is restored and\n * `show` fires. A `placeholder` changed while guarded re-guards to match it.\n *\n * `hide` and `show` dispatch `{}`.\n *\n * @remarks\n * Behavior only — restoring the *fresh* value is the normal render's job, not this\n * controller's (it just un-hides what was there). State is derived from the DOM (no\n * module-scope state), and the guard is reversible in three ways that do not depend on\n * each other: the child nodes a placeholder displaced are held and put back intact, the\n * inline `visibility` is leased so an authored declaration — and one the consumer writes\n * while guarded — survives, and a fresh `connect()` clears a `data-preview-hidden` it\n * finds already on the element. A placeholder also records the markup it displaced on\n * the element as `data-<identifier>-content` (a JSON string), and the `visibility` lease\n * leaves its own record, so a copy of the element taken while guarded — a page Turbo\n * restores from its cache — gets its content or its `visibility` back from the fresh\n * `connect()` that finds them. Nothing comes down on `turbo:before-cache`,\n * which Turbo also dispatches on pages that stay (a state-less `popstate`, a refresh of\n * a cached URL), where the preview is still on screen; nor on `disconnect()`, so an\n * in-page move keeps the guard instead of flashing the stale value between the two\n * lifecycle calls — and the instance that comes back re-forms it rather than reading\n * the hook as someone else's leftover.\n *\n * Focus is only ever handed back, never taken: an element that held focus when the guard\n * went up gets it back on show, and focus resting anywhere else is left alone.\n */\nexport class PreviewGuardController extends Controller<HTMLElement> {\n static override values = {\n placeholder: { type: String, default: \"\" },\n };\n static events = [\"hide\", \"show\"] as const;\n\n declare placeholderValue: string;\n\n readonly #visibility = new StylePropertyLease(\"visibility\", this.identifier);\n\n #observer: MutationObserver | null = null;\n #connected = false;\n #hidden = false;\n /** Child nodes a placeholder displaced; non-null marks that content — not visibility — was swapped. */\n #savedNodes: DocumentFragment | null = null;\n /** The descendant that held focus when the guard went up, so show can hand it back. */\n #focused: HTMLElement | null = null;\n\n readonly #morphRender = new MorphRenderWatcher(() => {\n this.#sync();\n if (this.#hidden) this.#reguard();\n });\n\n override connect(): void {\n this.#morphRender.observe(this.element);\n this.#connected = true;\n // The hook means \"the connection now running has this element guarded\", and which of\n // the two connects is happening is only knowable from the instance. A restored\n // snapshot brings a fresh controller to an element that still carries the hook, with\n // no instance left holding what was underneath it, so that one puts back the content\n // a placeholder recorded and drops the hook. An in-page move brings the *same*\n // instance back still holding the guard, so that one re-forms instead — against the\n // `placeholder` as it stands now, since a morph can swap it while the element is\n // detached, where the value callback has no connection to act on.\n if (this.#hidden) {\n this.#reguard();\n } else {\n if (this.element.hasAttribute(\"data-preview-hidden\")) this.#restoreRecordedContent();\n this.#visibility.return(this.element);\n TRANSIENT.reset(this.element);\n }\n if (typeof MutationObserver !== \"undefined\") {\n this.#observer = new MutationObserver(() => this.#sync());\n this.#observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-turbo-preview\"],\n });\n }\n // Sync once in case we connect while a preview is already on screen.\n this.#sync();\n }\n\n override disconnect(): void {\n this.#morphRender.disconnect();\n this.#connected = false;\n this.#observer?.disconnect();\n this.#observer = null;\n }\n\n /**\n * Re-guards to match a `placeholder` changed at runtime — the value is the content on\n * display while the guard is up, so a morph that swaps it must not leave the old one.\n */\n placeholderValueChanged(): void {\n if (!this.#connected || !this.#hidden) return;\n this.#reguard();\n }\n\n /**\n * Reflects the current `data-turbo-preview` state onto the element.\n *\n * @stimeoRenderRoot\n */\n #sync(): void {\n const previewing = document.documentElement.hasAttribute(\"data-turbo-preview\");\n if (previewing && !this.#hidden) this.#hide();\n else if (!previewing && this.#hidden) this.#show();\n }\n\n #hide(): void {\n this.#focused = this.#focusedInside();\n this.#applyGuard();\n this.dispatch(\"hide\", { detail: {} });\n }\n\n /** Puts the guard up in the form the current `placeholder` calls for. */\n #applyGuard(): void {\n this.#hidden = true;\n if (this.placeholderValue === \"\") {\n this.#visibility.write(this.element, \"hidden\");\n } else {\n this.element.setAttribute(this.#contentRecord, JSON.stringify(this.element.innerHTML));\n this.#savedNodes = document.createDocumentFragment();\n this.#savedNodes.append(...this.element.childNodes);\n this.element.textContent = this.placeholderValue;\n }\n this.element.setAttribute(\"data-preview-hidden\", \"true\");\n }\n\n /** The record of the content a placeholder displaced, in this controller's namespace. */\n get #contentRecord(): string {\n return `data-${this.identifier}-${CONTENT_RECORD}`;\n }\n\n /**\n * Puts back the content a copy of a guarded element records — no instance holds its\n * nodes any more — and drops the record.\n */\n #restoreRecordedContent(): void {\n const raw = this.element.getAttribute(this.#contentRecord) ?? \"null\";\n this.element.removeAttribute(this.#contentRecord);\n let content: unknown = null;\n try {\n content = JSON.parse(raw);\n } catch {\n // A record that is not JSON holds no content.\n }\n if (typeof content === \"string\") this.element.innerHTML = content;\n }\n\n /**\n * Re-forms a guard that is already up so it matches the current `placeholder`.\n *\n * No event: `hide` reports that the guard went up, and it has not come down. Swapping\n * one stand-in text for another writes only that text — putting the held content back\n * first would reconnect the whole subtree for an instant. Only a change of *form* —\n * to or from the empty placeholder — has to revert, and the focus the guard is holding\n * carries across it rather than being handed back and taken again.\n *\n * @stimeoRenderRoot\n */\n #reguard(): void {\n this.element.setAttribute(\"data-preview-hidden\", \"true\");\n if (this.#savedNodes && this.placeholderValue !== \"\") {\n this.element.textContent = this.placeholderValue;\n return;\n }\n const held = this.#focused;\n this.#revert();\n this.#applyGuard();\n this.#focused = held;\n }\n\n #show(): void {\n this.#restore();\n this.dispatch(\"show\", { detail: {} });\n }\n\n /** Reverts the guard and hands focus back. */\n #restore(): void {\n this.#revert();\n this.#refocus();\n }\n\n /**\n * Puts the element back the way the guard found it.\n *\n * Every step is a no-op on an element this controller never guarded: the lease returns\n * only declarations it recorded, and the hook is removed whether or not it is there.\n */\n #revert(): void {\n this.#hidden = false;\n if (this.#savedNodes) {\n this.element.textContent = \"\";\n this.element.append(this.#savedNodes);\n this.#savedNodes = null;\n this.element.removeAttribute(this.#contentRecord);\n } else {\n this.#visibility.return(this.element);\n }\n this.element.removeAttribute(\"data-preview-hidden\");\n }\n\n /**\n * The focused element the guard is about to make unfocusable, if any.\n *\n * The element itself counts as well as its descendants: guarding takes focus either way\n * — a `visibility: hidden` subtree cannot hold it, and a placeholder displaces the nodes\n * outright — so the browser drops focus to `<body>` the moment the guard goes up.\n */\n #focusedInside(): HTMLElement | null {\n const active = document.activeElement;\n return active instanceof HTMLElement && this.element.contains(active) ? active : null;\n }\n\n /**\n * Hands focus back to the element the guard took it from.\n *\n * Only when that element is still in the document and focus has not moved on since —\n * anything else is the user's or another controller's, and putting it back would be\n * taking it.\n */\n #refocus(): void {\n const target = this.#focused;\n this.#focused = null;\n if (!target?.isConnected || document.activeElement !== document.body) return;\n target.focus();\n }\n}\n"]}
|
|
@@ -69,6 +69,17 @@ declare class ProgressController extends Controller<HTMLElement> {
|
|
|
69
69
|
default: string;
|
|
70
70
|
};
|
|
71
71
|
};
|
|
72
|
+
static valueConstraints: {
|
|
73
|
+
value: {
|
|
74
|
+
readonly finite: true;
|
|
75
|
+
};
|
|
76
|
+
min: {
|
|
77
|
+
readonly finite: true;
|
|
78
|
+
};
|
|
79
|
+
max: {
|
|
80
|
+
readonly finite: true;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
72
83
|
static actions: readonly ["setValue"];
|
|
73
84
|
static events: readonly ["change", "complete"];
|
|
74
85
|
readonly barTarget: HTMLElement;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/progress_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/announce.ts
|
|
6
3
|
function announce(message, options = {}) {
|
|
7
4
|
const text = message.trim();
|
|
8
5
|
if (text.length === 0) return;
|
|
@@ -19,34 +16,59 @@ function fillTemplate(template, values) {
|
|
|
19
16
|
});
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
var NUMBER_BOUNDS = {
|
|
20
|
+
finite: { finite: true }};
|
|
21
|
+
function matchesNumberBounds(value, bounds) {
|
|
22
|
+
if (!Number.isFinite(value)) {
|
|
23
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
24
|
+
if (direction === null) return false;
|
|
25
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
26
|
+
}
|
|
27
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
28
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
29
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
30
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
31
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
function toFiniteNumber(raw) {
|
|
24
|
-
if (
|
|
25
|
-
|
|
36
|
+
if (typeof raw !== "number" && typeof raw !== "string") return null;
|
|
37
|
+
if (typeof raw === "string" && raw.trim().length === 0) return null;
|
|
38
|
+
const value = Number(raw);
|
|
26
39
|
return Number.isFinite(value) ? value : null;
|
|
27
40
|
}
|
|
41
|
+
function readNumber(raw, fallback, bounds) {
|
|
42
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var ListenerSet = class {
|
|
46
|
+
#abort = new AbortController();
|
|
47
|
+
add(target, type, handler, options) {
|
|
48
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
49
|
+
}
|
|
50
|
+
dispose() {
|
|
51
|
+
this.#abort.abort();
|
|
52
|
+
this.#abort = new AbortController();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
28
55
|
|
|
29
|
-
// src/utils/microtask_coalescer.ts
|
|
30
56
|
var MicrotaskCoalescer = class {
|
|
31
57
|
#run;
|
|
32
58
|
#queued = false;
|
|
33
59
|
#active = false;
|
|
34
60
|
#generation = 0;
|
|
35
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
36
61
|
constructor(run) {
|
|
37
62
|
this.#run = run;
|
|
38
63
|
}
|
|
39
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
40
64
|
activate() {
|
|
41
65
|
this.#active = true;
|
|
42
66
|
}
|
|
43
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
44
67
|
cancel() {
|
|
45
68
|
this.#active = false;
|
|
46
69
|
this.#queued = false;
|
|
47
70
|
this.#generation += 1;
|
|
48
71
|
}
|
|
49
|
-
/** Requests one pass after the batch settles. Idempotent; inert outside the window. */
|
|
50
72
|
schedule() {
|
|
51
73
|
if (!this.#active || this.#queued) return;
|
|
52
74
|
this.#queued = true;
|
|
@@ -59,7 +81,55 @@ var MicrotaskCoalescer = class {
|
|
|
59
81
|
}
|
|
60
82
|
};
|
|
61
83
|
|
|
62
|
-
|
|
84
|
+
var MorphRenderWatcher = class {
|
|
85
|
+
#listeners = new ListenerSet();
|
|
86
|
+
#pass;
|
|
87
|
+
#element = null;
|
|
88
|
+
#onMorph = () => this.#pass.schedule();
|
|
89
|
+
constructor(run) {
|
|
90
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
91
|
+
}
|
|
92
|
+
observe(element) {
|
|
93
|
+
if (this.#element === element) return;
|
|
94
|
+
this.disconnect();
|
|
95
|
+
this.#element = element;
|
|
96
|
+
this.#pass.activate();
|
|
97
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
98
|
+
}
|
|
99
|
+
schedule() {
|
|
100
|
+
this.#pass.schedule();
|
|
101
|
+
}
|
|
102
|
+
disconnect() {
|
|
103
|
+
this.#listeners.dispose();
|
|
104
|
+
this.#pass.cancel();
|
|
105
|
+
this.#element = null;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
var NumberValueReader = class {
|
|
110
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
111
|
+
read(owner, name, raw, fallback, bounds) {
|
|
112
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
113
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
114
|
+
this.#lastRejected.delete(name);
|
|
115
|
+
return resolved;
|
|
116
|
+
}
|
|
117
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
118
|
+
const literal = owner.element.getAttribute(attribute);
|
|
119
|
+
if (literal === null) {
|
|
120
|
+
this.#lastRejected.delete(name);
|
|
121
|
+
return resolved;
|
|
122
|
+
}
|
|
123
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
124
|
+
this.#lastRejected.set(name, literal);
|
|
125
|
+
console.warn(
|
|
126
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
return resolved;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
63
133
|
function rangeFraction(value, min, max) {
|
|
64
134
|
const span = max - min;
|
|
65
135
|
if (!(span > 0)) return 0;
|
|
@@ -75,10 +145,9 @@ function rangeFraction(value, min, max) {
|
|
|
75
145
|
return Math.min(1, Math.max(0, fraction));
|
|
76
146
|
}
|
|
77
147
|
|
|
78
|
-
// src/controllers/progress_controller.ts
|
|
79
148
|
var OWNED_VALUE_TEXT = "owns-valuetext";
|
|
80
|
-
var ProgressController = class extends Controller {
|
|
81
|
-
|
|
149
|
+
var ProgressController = class _ProgressController extends Controller {
|
|
150
|
+
#numbers = new NumberValueReader();
|
|
82
151
|
get #ownedValueText() {
|
|
83
152
|
return `data-${this.identifier}-${OWNED_VALUE_TEXT}`;
|
|
84
153
|
}
|
|
@@ -91,29 +160,23 @@ var ProgressController = class extends Controller {
|
|
|
91
160
|
valueText: { type: String, default: "" },
|
|
92
161
|
announceText: { type: String, default: "" }
|
|
93
162
|
};
|
|
163
|
+
static valueConstraints = {
|
|
164
|
+
value: NUMBER_BOUNDS.finite,
|
|
165
|
+
min: NUMBER_BOUNDS.finite,
|
|
166
|
+
max: NUMBER_BOUNDS.finite
|
|
167
|
+
};
|
|
94
168
|
static actions = ["setValue"];
|
|
95
169
|
static events = ["change", "complete"];
|
|
96
|
-
|
|
97
|
-
* Collapses a morph that swaps several render inputs at once into one repaint.
|
|
98
|
-
* A single update usually rewrites the whole set, and each Value would otherwise
|
|
99
|
-
* repaint on its own.
|
|
100
|
-
*/
|
|
101
|
-
#repaint = new MicrotaskCoalescer(() => {
|
|
170
|
+
#repaint = new MorphRenderWatcher(() => {
|
|
102
171
|
this.#render();
|
|
103
172
|
});
|
|
104
173
|
connect() {
|
|
105
|
-
this.#repaint.
|
|
174
|
+
this.#repaint.observe(this.element);
|
|
106
175
|
this.#render();
|
|
107
176
|
}
|
|
108
|
-
/** Closes the window in which a queued repaint may still run. */
|
|
109
177
|
disconnect() {
|
|
110
|
-
this.#repaint.
|
|
178
|
+
this.#repaint.disconnect();
|
|
111
179
|
}
|
|
112
|
-
/**
|
|
113
|
-
* Updates the progress value from an action param (`amount`) or a
|
|
114
|
-
* `detail.value` CustomEvent, normalizes it into range, syncs ARIA, and
|
|
115
|
-
* dispatches `change` (always) plus `complete` when `max` is reached.
|
|
116
|
-
*/
|
|
117
180
|
setValue(event) {
|
|
118
181
|
const next = toFiniteNumber(event.params?.amount ?? event.detail?.value);
|
|
119
182
|
if (next === null) return;
|
|
@@ -122,49 +185,37 @@ var ProgressController = class extends Controller {
|
|
|
122
185
|
this.indeterminateValue = false;
|
|
123
186
|
this.#render();
|
|
124
187
|
this.dispatch("change", { detail: { value, ratio: this.#ratio } });
|
|
125
|
-
if (value >= this
|
|
188
|
+
if (value >= this.#safeMax) {
|
|
126
189
|
this.dispatch("complete", { detail: { value } });
|
|
127
190
|
announce(
|
|
128
191
|
fillTemplate(this.announceTextValue, { value, percent: Math.round(this.#ratio * 100) })
|
|
129
192
|
);
|
|
130
193
|
}
|
|
131
194
|
}
|
|
132
|
-
/** Repaints when application code (or a Turbo morph) changes `indeterminate` at runtime. */
|
|
133
195
|
indeterminateValueChanged() {
|
|
134
196
|
this.#repaint.schedule();
|
|
135
197
|
}
|
|
136
|
-
/** Repaints when application code (or a Turbo morph) changes `value` at runtime. */
|
|
137
198
|
valueValueChanged() {
|
|
138
199
|
this.#repaint.schedule();
|
|
139
200
|
}
|
|
140
|
-
/** Repaints when application code (or a Turbo morph) changes `min` at runtime. */
|
|
141
201
|
minValueChanged() {
|
|
142
202
|
this.#repaint.schedule();
|
|
143
203
|
}
|
|
144
|
-
/** Repaints when application code (or a Turbo morph) changes `max` at runtime. */
|
|
145
204
|
maxValueChanged() {
|
|
146
205
|
this.#repaint.schedule();
|
|
147
206
|
}
|
|
148
|
-
/** Repaints when application code (or a Turbo morph) changes `valueText` at runtime. */
|
|
149
207
|
valueTextValueChanged() {
|
|
150
208
|
this.#repaint.schedule();
|
|
151
209
|
}
|
|
152
|
-
/** Clamps `raw` into the configured `[min, max]` range. */
|
|
153
210
|
#clamp(raw) {
|
|
154
|
-
return Math.min(this
|
|
211
|
+
return Math.min(this.#safeMax, Math.max(this.#safeMin, raw));
|
|
155
212
|
}
|
|
156
|
-
/** Current fraction of the range in `[0, 1]`; `0` when the range is empty. */
|
|
157
213
|
get #ratio() {
|
|
158
|
-
return rangeFraction(this
|
|
214
|
+
return rangeFraction(this.#safeValue, this.#safeMin, this.#safeMax);
|
|
159
215
|
}
|
|
160
|
-
/**
|
|
161
|
-
* Reflects value/range/indeterminate onto ARIA, `data-state`, and the ratio.
|
|
162
|
-
*
|
|
163
|
-
* @stimeoRenderRoot
|
|
164
|
-
*/
|
|
165
216
|
#render() {
|
|
166
|
-
this.element.setAttribute("aria-valuemin", String(this
|
|
167
|
-
this.element.setAttribute("aria-valuemax", String(this
|
|
217
|
+
this.element.setAttribute("aria-valuemin", String(this.#safeMin));
|
|
218
|
+
this.element.setAttribute("aria-valuemax", String(this.#safeMax));
|
|
168
219
|
if (this.indeterminateValue) {
|
|
169
220
|
this.element.removeAttribute("aria-valuenow");
|
|
170
221
|
this.#clearOwnValueText();
|
|
@@ -172,19 +223,12 @@ var ProgressController = class extends Controller {
|
|
|
172
223
|
this.element.setAttribute("data-state", "indeterminate");
|
|
173
224
|
return;
|
|
174
225
|
}
|
|
175
|
-
const value = this.#clamp(this
|
|
226
|
+
const value = this.#clamp(this.#safeValue);
|
|
176
227
|
this.element.setAttribute("aria-valuenow", String(value));
|
|
177
228
|
this.element.style.setProperty("--stimeo--progress-ratio", String(this.#ratio));
|
|
178
229
|
this.element.setAttribute("data-state", "determinate");
|
|
179
230
|
this.#applyValueText(value);
|
|
180
231
|
}
|
|
181
|
-
/**
|
|
182
|
-
* Sets `aria-valuetext` from the consumer-provided template, substituting
|
|
183
|
-
* `{value}` and `{percent}`. Left to the consumer so the human-readable text
|
|
184
|
-
* stays i18n-neutral in the library. With no template the attribute belongs to
|
|
185
|
-
* the consumer, so only a text this controller wrote is taken back
|
|
186
|
-
* ({@link OWNED_VALUE_TEXT}).
|
|
187
|
-
*/
|
|
188
232
|
#applyValueText(value) {
|
|
189
233
|
if (this.valueTextValue.length === 0) {
|
|
190
234
|
this.#clearOwnValueText();
|
|
@@ -195,14 +239,39 @@ var ProgressController = class extends Controller {
|
|
|
195
239
|
this.element.setAttribute("aria-valuetext", text);
|
|
196
240
|
this.element.setAttribute(this.#ownedValueText, "");
|
|
197
241
|
}
|
|
198
|
-
/** Removes `aria-valuetext` only when this controller is the one that wrote it. */
|
|
199
242
|
#clearOwnValueText() {
|
|
200
243
|
if (!this.element.hasAttribute(this.#ownedValueText)) return;
|
|
201
244
|
this.element.removeAttribute("aria-valuetext");
|
|
202
245
|
this.element.removeAttribute(this.#ownedValueText);
|
|
203
246
|
}
|
|
247
|
+
get #safeValue() {
|
|
248
|
+
return this.#numbers.read(
|
|
249
|
+
this,
|
|
250
|
+
"value",
|
|
251
|
+
this.valueValue,
|
|
252
|
+
_ProgressController.values.value.default,
|
|
253
|
+
_ProgressController.valueConstraints.value
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
get #safeMin() {
|
|
257
|
+
return this.#numbers.read(
|
|
258
|
+
this,
|
|
259
|
+
"min",
|
|
260
|
+
this.minValue,
|
|
261
|
+
_ProgressController.values.min.default,
|
|
262
|
+
_ProgressController.valueConstraints.min
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
get #safeMax() {
|
|
266
|
+
return this.#numbers.read(
|
|
267
|
+
this,
|
|
268
|
+
"max",
|
|
269
|
+
this.maxValue,
|
|
270
|
+
_ProgressController.values.max.default,
|
|
271
|
+
_ProgressController.valueConstraints.max
|
|
272
|
+
);
|
|
273
|
+
}
|
|
204
274
|
};
|
|
205
275
|
|
|
206
276
|
export { ProgressController };
|
|
207
|
-
//# sourceMappingURL=progress_controller.js.map
|
|
208
277
|
//# sourceMappingURL=progress_controller.js.map
|