stimeo-ui 0.16.0 → 0.18.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 +136 -0
- package/README.md +27 -11
- package/dist/cable/index.d.ts +88 -31
- package/dist/cable/index.js +384 -449
- package/dist/cable/index.js.map +1 -1
- package/dist/coerce-JtZVNG5h.d.ts +20 -0
- package/dist/controllers/accordion_controller.d.ts +4 -2
- package/dist/controllers/accordion_controller.js +174 -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 +903 -235
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +37 -5
- package/dist/controllers/announcer_controller.js +238 -205
- 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 +414 -145
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +185 -107
- 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 +21 -3
- package/dist/controllers/bulk_select_controller.js +282 -58
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +38 -16
- package/dist/controllers/calendar_controller.js +228 -260
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +43 -12
- package/dist/controllers/carousel_controller.js +536 -436
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +44 -7
- package/dist/controllers/character_counter_controller.js +493 -207
- 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 +38 -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 +261 -149
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +17 -5
- package/dist/controllers/collapsible_controller.js +304 -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 +178 -146
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +24 -6
- package/dist/controllers/combobox_controller.js +522 -156
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +51 -20
- package/dist/controllers/command_palette_controller.js +1156 -395
- 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 +300 -171
- 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 +980 -262
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +80 -18
- package/dist/controllers/context_menu_controller.js +346 -153
- 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 +47 -3
- package/dist/controllers/countdown_controller.js +281 -158
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +93 -10
- package/dist/controllers/currency_input_controller.js +575 -225
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +25 -12
- package/dist/controllers/data_grid_controller.js +248 -214
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +42 -14
- package/dist/controllers/date_range_picker_controller.js +338 -235
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +17 -6
- package/dist/controllers/dialog_controller.js +899 -237
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +25 -8
- package/dist/controllers/direct_upload_controller.js +97 -167
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +6 -1
- package/dist/controllers/dirty_form_controller.js +72 -69
- 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 +196 -24
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +39 -11
- package/dist/controllers/drawer_controller.js +974 -355
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +31 -1
- package/dist/controllers/dropdown_controller.js +339 -96
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.d.ts +12 -1
- package/dist/controllers/editable_controller.js +315 -88
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.js +79 -58
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +63 -18
- package/dist/controllers/file_dropzone_controller.js +322 -211
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.js +77 -42
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +35 -12
- package/dist/controllers/flash_controller.js +238 -347
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +15 -6
- package/dist/controllers/focus_controller.js +679 -240
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +156 -132
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.d.ts +3 -3
- package/dist/controllers/form_validation_controller.js +31 -97
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +47 -14
- package/dist/controllers/frame_loading_controller.js +275 -217
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +27 -6
- 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 +60 -4
- package/dist/controllers/hover_card_controller.js +327 -130
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +48 -6
- package/dist/controllers/idle_controller.js +271 -101
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +30 -13
- package/dist/controllers/input_mask_controller.js +483 -97
- 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 +150 -106
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +19 -2
- package/dist/controllers/lazy_frame_controller.js +24 -68
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +44 -9
- package/dist/controllers/listbox_controller.js +523 -240
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +9 -7
- package/dist/controllers/local_time_controller.js +102 -77
- 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 +80 -96
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +55 -11
- package/dist/controllers/menu_controller.js +302 -188
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +51 -9
- package/dist/controllers/menubar_controller.js +232 -345
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +33 -20
- package/dist/controllers/meter_controller.js +417 -87
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +48 -18
- package/dist/controllers/multi_select_controller.js +785 -393
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +27 -6
- package/dist/controllers/navigation_menu_controller.js +190 -250
- 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 +396 -192
- 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 +268 -62
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +50 -8
- package/dist/controllers/number_input_controller.js +610 -303
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.d.ts +8 -5
- package/dist/controllers/optimistic_controller.js +45 -87
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +55 -8
- package/dist/controllers/otp_controller.js +658 -255
- 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 +122 -113
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +58 -20
- package/dist/controllers/overflow_menu_controller.js +470 -295
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +37 -7
- package/dist/controllers/pagination_controller.js +332 -123
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +46 -8
- package/dist/controllers/password_reveal_controller.js +392 -121
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +15 -6
- package/dist/controllers/password_strength_controller.js +111 -158
- 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 +165 -111
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +35 -12
- package/dist/controllers/pointer_drag_controller.js +434 -188
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +41 -5
- package/dist/controllers/popover_controller.js +269 -113
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +44 -4
- package/dist/controllers/portal_controller.js +215 -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 +243 -116
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +20 -19
- package/dist/controllers/progress_controller.js +391 -78
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +21 -9
- package/dist/controllers/radio_group_controller.js +278 -211
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +47 -6
- package/dist/controllers/range_slider_controller.js +220 -113
- 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 +458 -211
- 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 +138 -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 +166 -137
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.d.ts +20 -6
- package/dist/controllers/relative_time_controller.js +211 -112
- 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} +103 -38
- package/dist/controllers/reset_on_restore_controller.js.map +1 -0
- package/dist/controllers/resizable_controller.d.ts +31 -2
- package/dist/controllers/resizable_controller.js +299 -150
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.d.ts +3 -3
- package/dist/controllers/roving_controller.js +49 -88
- 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 +490 -246
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.d.ts +3 -3
- package/dist/controllers/scroll_restore_controller.js +14 -55
- 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 +432 -149
- 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 +193 -248
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +20 -5
- package/dist/controllers/separator_controller.js +285 -142
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +65 -8
- package/dist/controllers/sidebar_controller.js +1069 -404
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +23 -0
- package/dist/controllers/skeleton_controller.js +259 -101
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +29 -2
- package/dist/controllers/slider_controller.js +187 -86
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +22 -4
- package/dist/controllers/smart_sticky_header_controller.js +173 -66
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.d.ts +4 -4
- package/dist/controllers/sortable_controller.js +26 -125
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +39 -4
- package/dist/controllers/spinner_controller.js +288 -173
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +9 -4
- package/dist/controllers/step_indicator_controller.js +105 -46
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +14 -6
- package/dist/controllers/stepper_controller.js +120 -73
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +9 -1
- package/dist/controllers/stick_to_bottom_controller.js +275 -140
- 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 +220 -49
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +24 -8
- package/dist/controllers/submit_once_controller.js +376 -227
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +18 -4
- package/dist/controllers/switch_controller.js +201 -84
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +9 -6
- package/dist/controllers/tabs_controller.js +41 -30
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +16 -3
- package/dist/controllers/tags_input_controller.js +293 -173
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +11 -1
- package/dist/controllers/textarea_autosize_controller.js +108 -74
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +24 -11
- package/dist/controllers/theme_controller.js +140 -116
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +55 -5
- package/dist/controllers/time_picker_controller.js +331 -127
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +40 -16
- package/dist/controllers/toast_controller.js +244 -324
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +14 -6
- package/dist/controllers/toggle_group_controller.js +252 -191
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.d.ts +8 -6
- package/dist/controllers/toolbar_controller.js +219 -120
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +49 -4
- 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 +22 -12
- package/dist/controllers/tree_view_controller.js +283 -369
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.js +8573 -10410
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +38 -14
- package/dist/inspector/cli.js +108 -40
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +145 -64
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +20 -20
- package/dist/inspector/manifest.json +802 -101
- package/dist/positioning/index.d.ts +15 -7
- package/dist/positioning/index.js +154 -47
- package/dist/positioning/index.js.map +1 -1
- package/package.json +11 -10
- 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/safe_timeout.ts","../../src/utils/state_regions.ts","../../src/utils/string_list.ts","../../src/controllers/idle_controller.ts"],"names":[],"mappings":"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","file":"idle_controller.js","sourcesContent":["/**\n * Self-cleaning timer registries shared by Stimeo controllers.\n *\n * Stimulus controllers frequently schedule `setTimeout` / `setInterval` work\n * (auto-dismiss, debouncing, polling). When the element leaves the DOM — a\n * Turbo Drive navigation, a Turbo Stream replacement, or any `disconnect()` —\n * orphaned timers keep firing against a detached controller, leaking memory and\n * mutating stale state. {@link SafeTimeout} and {@link SafeInterval} track every\n * timer they create so a single {@link TimerRegistry.clearAll | clearAll()} call\n * in `disconnect()` tears them all down.\n *\n * These are intentionally low-level primitives: they own *registration and\n * cleanup only*. Higher-level policy (pause/resume, remaining-time accounting)\n * stays in the individual controllers so per-widget semantics are not flattened\n * into a lowest-common-denominator helper.\n */\n\n/**\n * Largest delay a timer can hold: the platform stores it in a 32-bit signed\n * integer, and anything larger overflows to `1`, so a delay meant to be far in\n * the future fires almost immediately. A declared delay above this bound names\n * no delay at all, and a controller reading one falls back to its default.\n */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/**\n * Shared registry bookkeeping for the timeout/interval variants.\n *\n * Subclasses provide the scheduling primitive ({@link schedule}) and its matching\n * canceller ({@link cancel}); this base owns the set of live ids plus the\n * per-id and bulk teardown shared by both.\n */\nabstract class TimerRegistry {\n /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */\n protected readonly ids = new Set<number>();\n\n /** Schedules the underlying platform timer and returns its id. */\n protected abstract schedule(callback: () => void, delay: number): number;\n\n /** Cancels the underlying platform timer for `id`. */\n protected abstract cancel(id: number): void;\n\n /**\n * Cancels a single tracked timer.\n *\n * No-ops if the id is unknown (already cleared, fired, or never owned by this\n * registry), so callers can clear defensively without guarding.\n */\n clear(id: number): void {\n if (this.ids.delete(id)) {\n this.cancel(id);\n }\n }\n\n /**\n * Cancels every tracked timer. Call this from a controller's `disconnect()`\n * to guarantee no timer outlives the element.\n */\n clearAll(): void {\n for (const id of this.ids) {\n this.cancel(id);\n }\n this.ids.clear();\n }\n\n /** Number of timers currently tracked (pending). */\n get size(): number {\n return this.ids.size;\n }\n}\n\n/**\n * `setTimeout` wrapper that auto-forgets each timer once it fires and supports\n * bulk teardown on disconnect.\n *\n * @example\n * ```ts\n * #timers = new SafeTimeout();\n *\n * connect() {\n * this.#timers.set(() => this.dismiss(), 5000);\n * }\n *\n * disconnect() {\n * this.#timers.clearAll();\n * }\n * ```\n */\nexport class SafeTimeout extends TimerRegistry {\n /**\n * Schedules `callback` after `delay` ms and returns the timer id.\n *\n * The id is removed from the registry automatically when the timeout fires,\n * so {@link TimerRegistry.size | size} reflects only still-pending timers.\n */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(() => {\n this.ids.delete(id);\n callback();\n }, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setTimeout(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearTimeout(id);\n }\n}\n\n/**\n * `setInterval` wrapper that tracks every interval for bulk teardown on\n * disconnect. Unlike {@link SafeTimeout}, intervals are retained until they are\n * explicitly cleared because they fire repeatedly.\n *\n * @example\n * ```ts\n * #intervals = new SafeInterval();\n *\n * connect() {\n * this.#intervals.set(() => this.tick(), 1000);\n * }\n *\n * disconnect() {\n * this.#intervals.clearAll();\n * }\n * ```\n */\nexport class SafeInterval extends TimerRegistry {\n /** Schedules a repeating `callback` every `delay` ms and returns the timer id. */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(callback, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setInterval(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearInterval(id);\n }\n}\n","/** What a consumer declares once about the regions one boolean state reveals. */\nexport interface StateRegionsOptions {\n /** Returns the declared regions shown while the state holds. */\n readonly whenTrue: () => readonly HTMLElement[];\n /**\n * Returns the declared regions shown while the state does not hold. Omitted by a\n * state whose other side has nothing of its own to show.\n */\n readonly whenFalse?: () => readonly HTMLElement[];\n}\n\n/**\n * Owns `hidden` on the regions a boolean state reveals.\n *\n * A region is a **declared** target, so the consumer decides whether one exists at\n * all; where it does, which side is shown is a pure function of the state and the\n * controller writes it unconditionally. An authored `hidden` is therefore not read\n * back — the first reflection after a connection settles it, and a restored DOM\n * cannot leave a region contradicting the state it belongs to.\n *\n * The regions arrive as the caller's own target arrays, which Stimulus has already\n * scoped to this instance: a nested controller registered under the same identifier\n * keeps its own regions. `host` narrows that set further, to the regions inside one\n * trigger or item, so a widget with several of them reflects each independently.\n *\n * **Two sides are a pair.** Where the state has a `whenFalse` side and only one half\n * sits inside `host`, the half that is there is left in view: hiding it would take\n * the only label with it, and the static check names the missing one instead. What\n * the author wrote on a lone half is theirs and stays — only a half this instance\n * took out of view is given back, which is what a pair losing one side at runtime\n * leaves behind.\n *\n * `hidden` moves only when it changes, so a consumer watching its own subtree for\n * attribute mutations sees one record per transition rather than one per reflection.\n *\n * @example\n * ```ts\n * readonly #labels = new StateRegions({\n * whenTrue: () => this.expandedLabelTargets,\n * whenFalse: () => this.collapsedLabelTargets,\n * });\n *\n * #reflect(): void {\n * this.#labels.reflect(this.triggerTarget, this.#expanded);\n * }\n * ```\n */\nexport class StateRegions {\n readonly #whenTrue: () => readonly HTMLElement[];\n readonly #whenFalse: (() => readonly HTMLElement[]) | null;\n readonly #taken = new WeakSet<HTMLElement>();\n\n constructor(options: StateRegionsOptions) {\n this.#whenTrue = options.whenTrue;\n this.#whenFalse = options.whenFalse ?? null;\n }\n\n /** Shows the regions inside `host` that belong to `isTrue` and hides the others. */\n reflect(host: Element, isTrue: boolean): void {\n const shown = this.#inside(host, this.#whenTrue());\n if (!this.#whenFalse) {\n for (const region of shown) this.#write(region, !isTrue);\n return;\n }\n const hiddenSide = this.#inside(host, this.#whenFalse());\n if (shown.length === 0 || hiddenSide.length === 0) {\n for (const region of shown) this.#give(region);\n for (const region of hiddenSide) this.#give(region);\n return;\n }\n for (const region of shown) this.#write(region, !isTrue);\n for (const region of hiddenSide) this.#write(region, isTrue);\n }\n\n /** Writes `hidden` where it moves, noting which regions it takes out of view. */\n #write(region: HTMLElement, hidden: boolean): void {\n if (hidden) this.#taken.add(region);\n else this.#taken.delete(region);\n if (region.hidden !== hidden) region.hidden = hidden;\n }\n\n /** Returns a region this instance hid; one it never hid keeps what it carries. */\n #give(region: HTMLElement): void {\n if (this.#taken.delete(region)) region.hidden = false;\n }\n\n /** The declared regions that sit within `host`, which may be the host itself. */\n #inside(host: Element, regions: readonly HTMLElement[]): HTMLElement[] {\n return regions.filter((region) => host.contains(region));\n }\n}\n","/**\n * JSON string-list parsing for the controllers that take a list as a Value.\n *\n * Stimulus offers an `Array` Value type, but its reader runs `JSON.parse` inside\n * the value observer — **before** the `<name>ValueChanged` callback — and\n * rethrows on malformed text. The throw propagates out of the observer that runs\n * during connection, so a single unparseable attribute stops the controller from\n * connecting at all: no lifecycle callback runs and the element is left inert\n * rather than degraded. A consumer cannot guard against it either, because the\n * callback that would hold the `try` never runs.\n *\n * Declaring the attribute as a `String` Value and parsing it here keeps a\n * malformed declaration local to the value it declares. The attribute text is\n * identical either way (`'[\"a\", \"b\"]'`), so markup does not change with the\n * declaration.\n */\n\n/**\n * Parses `raw` as a JSON array of strings.\n *\n * Returns `fallback` when the text is absent, unparseable, or not an array, so a\n * malformed declaration behaves like an omitted one. A parsed array keeps only\n * its string entries: every caller indexes or compares strings, and a stray\n * number would otherwise sit in the list without ever matching.\n *\n * An explicit `\"[]\"` is honoured as an empty list rather than falling back — it\n * is the only way to declare \"none\" against a non-empty default.\n *\n * @param raw - the attribute text, e.g. `'[\"password\"]'`.\n * @param fallback - the list to use when `raw` declares nothing usable.\n */\nexport function parseStringList(raw: string, fallback: readonly string[] = []): string[] {\n // The common case is an undeclared attribute, and `JSON.parse(\"\")` answers it\n // by throwing. Reaching the same fallback without building an exception keeps\n // the callers that ask per element off that path.\n const text = raw.trim();\n if (text.length === 0) return [...fallback];\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return [...fallback];\n }\n\n if (!Array.isArray(parsed)) return [...fallback];\n return parsed.filter((entry): entry is string => typeof entry === \"string\");\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { SafeTimeout } from \"../utils/safe_timeout\";\nimport { StateRegions } from \"../utils/state_regions\";\nimport { parseStringList } from \"../utils/string_list\";\n\n/** Activity signals watched unless the consumer declares its own list. */\nconst DEFAULT_ACTIVITY_EVENTS = [\n \"mousemove\",\n \"mousedown\",\n \"keydown\",\n \"wheel\",\n \"touchstart\",\n \"scroll\",\n];\n\n/**\n * Headless inactivity / session-timeout detector: fires `idle` after `timeout` ms\n * with no user activity, an optional `prompt` `promptBefore` ms earlier, and\n * `active` when the user returns (no dedicated APG pattern; supports WCAG 2.2.1 by\n * giving the app a warning hook before a timeout).\n *\n * Markup contract (identifier: `stimeo--idle`):\n * <body data-controller=\"stimeo--idle\"\n * data-stimeo--idle-timeout-value=\"900000\"\n * data-stimeo--idle-prompt-before-value=\"60000\"\n * data-action=\"stimeo--idle:prompt->session#warn\n * stimeo--idle:idle->session#logout\">\n * <p data-stimeo--idle-target=\"prompt\" hidden>Your session expires in a minute.</p>\n * <p data-stimeo--idle-target=\"idle\" hidden>You have been signed out.</p>\n * </body>\n *\n * Activity events (`events`, passive) are watched on `document` with capture so\n * non-bubbling ones like `scroll` are seen anywhere; returning to a hidden tab\n * (`visibilitychange` → visible) counts as activity too. The controller element carries\n * `data-prompt` while the warning stands and `data-idle` once the timeout is reached,\n * and the optional `prompt` / `idle` targets are the regions those phases reveal:\n * declared where the page has something to show, shown while their phase holds and\n * hidden otherwise, whatever visibility the markup was authored with.\n *\n * `prompt` dispatches `{ remaining }`; `idle` and `active` dispatch `{}`.\n *\n * @remarks\n * Behavior only — it renders no warning UI (pair with Dialog/Confirm) and never\n * touches the server session. Timers are owned by `SafeTimeout` and the\n * listeners are removed on `disconnect()` (Turbo navigation included). Place one on\n * the root element. Every visit reconnects the controller and re-arms the timeout\n * from that moment — `data-turbo-permanent` keeps the element, not the elapsed count.\n */\nexport class IdleController extends Controller<HTMLElement> {\n static override values = {\n timeout: { type: Number, default: 900_000 },\n promptBefore: { type: Number, default: 0 },\n // A JSON list read through `parseStringList` rather than Stimulus's `Array`\n // type: that reader throws out of the value observer before any callback\n // runs, so one malformed attribute would stop the detector connecting.\n events: { type: String, default: \"\" },\n };\n static override targets = [\"prompt\", \"idle\"];\n static events = [\"prompt\", \"idle\", \"active\"] as const;\n\n declare timeoutValue: number;\n declare promptBeforeValue: number;\n declare eventsValue: string;\n declare readonly promptTargets: HTMLElement[];\n declare readonly idleTargets: HTMLElement[];\n\n /** The regions of the warning window, revealed alongside `data-prompt`. */\n readonly #promptRegions = new StateRegions({ whenTrue: () => this.promptTargets });\n /** The regions of the elapsed timeout, revealed alongside `data-idle`. */\n readonly #idleRegions = new StateRegions({ whenTrue: () => this.idleTargets });\n\n readonly #timeouts = new SafeTimeout();\n #idle = false;\n #prompted = false;\n /** Timestamp of the last activity; the timers self-reschedule against it. */\n #lastActivity = 0;\n /**\n * Activity types actually registered on `document`, so `disconnect()` unbinds the\n * same set even when `events` changed while connected (a Turbo morph can rewrite\n * the Value in place, and the removal must match the registration, not the Value).\n */\n #boundEvents: string[] = [];\n\n readonly #onActivity = (): void => {\n // Hot path (fires on every mousemove/scroll/wheel): just record the time. The\n // prompt/idle timers re-check this when they fire and reschedule if needed, so we\n // never tear down and re-create timers on each event (no per-event timer churn).\n this.#lastActivity = Date.now();\n if (this.#idle || this.#prompted) {\n // We were already idle/prompted, so the timers have lapsed — wake and re-arm.\n this.#idle = false;\n this.#prompted = false;\n this.#reflect();\n this.dispatch(\"active\", { detail: {} });\n this.#arm();\n }\n };\n\n readonly #onVisibility = (): void => {\n // Returning to the tab is activity; leaving it keeps the clock running (being\n // away counts toward the timeout).\n if (document.visibilityState === \"visible\") this.#onActivity();\n };\n\n override connect(): void {\n // Connecting always starts a fresh cycle (#arm() re-bases the clock), so the phase\n // that arrived with the DOM — a restored Turbo snapshot, a moved element — describes\n // a period this instance is not in. Reflecting the fresh cycle drops it; leaving it\n // would claim the user is idle for the whole next active window with no `active` to\n // correct it. Normalizing is not a transition, so nothing is dispatched here.\n this.#idle = false;\n this.#prompted = false;\n this.#reflect();\n this.#boundEvents = parseStringList(this.eventsValue, DEFAULT_ACTIVITY_EVENTS);\n for (const type of this.#boundEvents) {\n document.addEventListener(type, this.#onActivity, { passive: true, capture: true });\n }\n document.addEventListener(\"visibilitychange\", this.#onVisibility);\n this.#arm();\n }\n\n override disconnect(): void {\n for (const type of this.#boundEvents) {\n document.removeEventListener(type, this.#onActivity, { capture: true });\n }\n this.#boundEvents = [];\n document.removeEventListener(\"visibilitychange\", this.#onVisibility);\n this.#timeouts.clearAll();\n }\n\n /**\n * Schedules the prompt and idle checks from the current activity baseline.\n *\n * @stimeoRuntimeOnly `timeout` and `promptBefore` time the checks this call arms.\n */\n #arm(): void {\n this.#timeouts.clearAll();\n this.#lastActivity = Date.now();\n const { promptBeforeValue: prompt, timeoutValue: timeout } = this;\n if (prompt > 0 && prompt < timeout) {\n this.#timeouts.set(() => this.#checkPrompt(), timeout - prompt);\n }\n this.#timeouts.set(() => this.#checkIdle(), timeout);\n }\n\n /**\n * Idle-timer callback: go idle only if there has genuinely been no activity for\n * `timeout`; otherwise reschedule for the remaining time. This lets activity events\n * stay O(1) (a timestamp write) while the deadline still tracks the last activity.\n *\n * @stimeoRuntimeOnly `timeout` sets the deadline this one check compares against; the phase it\n * shows follows the elapsed time.\n */\n #checkIdle(): void {\n const remaining = this.timeoutValue - (Date.now() - this.#lastActivity);\n if (remaining > 0) {\n this.#timeouts.set(() => this.#checkIdle(), remaining);\n return;\n }\n this.#idle = true;\n this.#prompted = false;\n this.#reflect();\n this.dispatch(\"idle\", { detail: {} });\n }\n\n /**\n * Prompt-timer callback: warn at `promptBefore` before the idle deadline. A window\n * narrowed while the cycle runs can push the warning onto the deadline or past it,\n * and the phase it belongs to is the one before idle, so a lapsed cycle keeps the\n * phase it reached. The next window opens with the cycle that activity arms.\n *\n * @stimeoRuntimeOnly `timeout` and `promptBefore` set the deadlines this one check compares\n * against; the phase it shows follows the elapsed time.\n */\n #checkPrompt(): void {\n if (this.#idle) return;\n const remaining =\n this.timeoutValue - this.promptBeforeValue - (Date.now() - this.#lastActivity);\n if (remaining > 0) {\n this.#timeouts.set(() => this.#checkPrompt(), remaining);\n return;\n }\n this.#prompted = true;\n this.#reflect();\n this.dispatch(\"prompt\", { detail: { remaining: this.promptBeforeValue } });\n }\n\n /** Applies the current phase to a warning region inserted or replaced at runtime. */\n promptTargetConnected(): void {\n this.#promptRegions.reflect(this.element, this.#prompted);\n }\n\n /** Applies the current phase to an idle region inserted or replaced at runtime. */\n idleTargetConnected(): void {\n this.#idleRegions.reflect(this.element, this.#idle);\n }\n\n /**\n * Writes the phase to the element and to the declared regions. Both hooks and both\n * regions are a pure function of the two flags, so every place that moves a flag ends\n * here and the markup can never disagree with the phase the detector is in.\n */\n #reflect(): void {\n const { element } = this;\n if (this.#prompted) element.setAttribute(\"data-prompt\", \"true\");\n else element.removeAttribute(\"data-prompt\");\n if (this.#idle) element.setAttribute(\"data-idle\", \"true\");\n else element.removeAttribute(\"data-idle\");\n this.#promptRegions.reflect(element, this.#prompted);\n this.#idleRegions.reflect(element, this.#idle);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/listener_set.ts","../../src/utils/timer_bounds.ts","../../src/utils/number_bounds.ts","../../src/utils/coerce.ts","../../src/utils/number_value.ts","../../src/utils/safe_timeout.ts","../../src/utils/attribute_write.ts","../../src/utils/shared_registry.ts","../../src/utils/state_regions.ts","../../src/utils/string_list.ts","../../src/controllers/idle_controller.ts"],"names":[],"mappings":";;AA8EO,IAAM,cAAN,MAAkB;AAAA,EAEvB,MAAA,GAAS,IAAI,eAAA,EAAgB;AAAA,EAqB7B,GAAA,CAAI,MAAA,EAAqB,IAAA,EAAc,OAAA,EAAwB,OAAA,EAAiC;AAC9F,IAAA,MAAA,CAAO,gBAAA,CAAiB,IAAA,EAAM,OAAA,EAAS,EAAE,GAAG,SAAS,MAAA,EAAQ,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,CAAA;AAAA,EACnF;AAAA,EAMA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAClB,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,eAAA,EAAgB;AAAA,EACpC;AACF,CAAA;;AC3GO,IAAM,kBAAA,GAAqB,UAAA;;ACwB3B,IAAM,aAAA,GAAgB;AAAA,EAE3B,WAAA,EAAa,EAAE,MAAA,EAAQ,IAAA,EAAM,KAAK,CAAA,EAAE;AAAA,EAOpC,eAAe,EAAE,MAAA,EAAQ,MAAM,YAAA,EAAc,CAAA,EAAG,KAAK,kBAAA;AACvD,CAAA;AAMO,SAAS,mBAAA,CAAoB,OAAe,MAAA,EAA+B;AAChF,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AAC3B,IAAA,MAAM,YAAY,KAAA,KAAU,QAAA,GAAW,UAAA,GAAa,KAAA,KAAU,YAAY,UAAA,GAAa,IAAA;AACvF,IAAA,IAAI,SAAA,KAAc,MAAM,OAAO,KAAA;AAC/B,IAAA,IAAI,OAAO,aAAA,KAAkB,MAAA,IAAU,MAAA,CAAO,aAAA,KAAkB,WAAW,OAAO,KAAA;AAAA,EACpF;AACA,EAAA,IAAI,OAAO,GAAA,KAAQ,MAAA,IAAa,KAAA,GAAQ,MAAA,CAAO,KAAK,OAAO,KAAA;AAC3D,EAAA,IAAI,OAAO,GAAA,KAAQ,MAAA,IAAa,KAAA,GAAQ,MAAA,CAAO,KAAK,OAAO,KAAA;AAC3D,EAAA,IAAI,OAAO,YAAA,KAAiB,MAAA,IAAa,KAAA,IAAS,MAAA,CAAO,cAAc,OAAO,KAAA;AAC9E,EAAA,IAAI,OAAO,OAAA,IAAW,CAAC,OAAO,SAAA,CAAU,KAAK,GAAG,OAAO,KAAA;AACvD,EAAA,IAAI,MAAA,CAAO,kBAAkB,MAAA,IAAa,CAAC,OAAO,aAAA,CAAc,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,KAAA;AACxF,EAAA,OAAO,IAAA;AACT;;ACrBO,SAAS,UAAA,CAAW,GAAA,EAAa,QAAA,EAAkB,MAAA,EAA8B;AACtF,EAAA,OAAO,mBAAA,CAAoB,GAAA,EAAK,MAAM,CAAA,GAAI,GAAA,GAAM,QAAA;AAClD;;AC7BO,IAAM,oBAAN,MAAwB;AAAA,EAEpB,aAAA,uBAAoB,GAAA,EAAoB;AAAA,EAGjD,IAAA,CACE,KAAA,EACA,IAAA,EACA,GAAA,EACA,UACA,MAAA,EACQ;AACR,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,GAAA,EAAK,QAAA,EAAU,MAAM,CAAA;AACjD,IAAA,IAAI,mBAAA,CAAoB,GAAA,EAAK,MAAM,CAAA,EAAG;AACpC,MAAA,IAAA,CAAK,aAAA,CAAc,OAAO,IAAI,CAAA;AAC9B,MAAA,OAAO,QAAA;AAAA,IACT;AACA,IAAA,MAAM,SAAA,GAAY,CAAA,KAAA,EAAQ,KAAA,CAAM,UAAU,IAAI,IAAA,CAAK,OAAA,CAAQ,QAAA,EAAU,CAAC,WAAW,CAAA,CAAA,EAAI,MAAA,CAAO,WAAA,EAAa,EAAE,CAAC,CAAA,MAAA,CAAA;AAC5G,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,YAAA,CAAa,SAAS,CAAA;AACpD,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA,IAAA,CAAK,aAAA,CAAc,OAAO,IAAI,CAAA;AAC9B,MAAA,OAAO,QAAA;AAAA,IACT;AACA,IAAA,IAAI,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,IAAI,MAAM,OAAA,EAAS;AAC5C,MAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,IAAA,EAAM,OAAO,CAAA;AACpC,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,YAAA,EAAe,KAAA,CAAM,UAAU,CAAA,+BAAA,EAAkC,IAAI,CAAA,cAAA,EAAiB,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA,QAAA,EAAW,QAAQ,CAAA,CAAA;AAAA,OAClI;AAAA,IACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AACF,CAAA;;ACfA,IAAe,gBAAf,MAA6B;AAAA,EAER,GAAA,uBAAU,GAAA,EAAY;AAAA,EAczC,MAAM,EAAA,EAAkB;AACtB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA,EAAG;AACvB,MAAA,IAAA,CAAK,OAAO,EAAE,CAAA;AAAA,IAChB;AAAA,EACF;AAAA,EAMA,QAAA,GAAiB;AACf,IAAA,KAAA,MAAW,EAAA,IAAM,KAAK,GAAA,EAAK;AACzB,MAAA,IAAA,CAAK,OAAO,EAAE,CAAA;AAAA,IAChB;AACA,IAAA,IAAA,CAAK,IAAI,KAAA,EAAM;AAAA,EACjB;AAAA,EAGA,IAAI,IAAA,GAAe;AACjB,IAAA,OAAO,KAAK,GAAA,CAAI,IAAA;AAAA,EAClB;AACF,CAAA;AAmBO,IAAM,WAAA,GAAN,cAA0B,aAAA,CAAc;AAAA,EAO7C,GAAA,CAAI,UAAsB,KAAA,EAAuB;AAC/C,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,QAAA,CAAS,MAAM;AAC7B,MAAA,IAAA,CAAK,GAAA,CAAI,OAAO,EAAE,CAAA;AAClB,MAAA,QAAA,EAAS;AAAA,IACX,GAAG,KAAK,CAAA;AACR,IAAA,IAAA,CAAK,GAAA,CAAI,IAAI,EAAE,CAAA;AACf,IAAA,OAAO,EAAA;AAAA,EACT;AAAA,EAEU,QAAA,CAAS,UAAsB,KAAA,EAAuB;AAC9D,IAAA,OAAO,MAAA,CAAO,UAAA,CAAW,QAAA,EAAU,KAAK,CAAA;AAAA,EAC1C;AAAA,EAEU,OAAO,EAAA,EAAkB;AACjC,IAAA,MAAA,CAAO,aAAa,EAAE,CAAA;AAAA,EACxB;AACF,CAAA;;AC5FO,SAAS,qBAAA,CACd,OAAA,EACA,IAAA,EACA,KAAA,EACA,WAAA,EACS;AACT,EAAA,IAAI,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA,KAAM,OAAO,OAAO,KAAA;AAEjD,EAAA,IAAI,KAAA,KAAU,IAAA,EAAM,OAAA,CAAQ,eAAA,CAAgB,IAAI,CAAA;AAAA,OAC3C,OAAA,CAAQ,YAAA,CAAa,IAAA,EAAM,KAAK,CAAA;AACrC,EAAA,OAAO,IAAA;AACT;;ACIO,SAAS,cAAA,CAAiC,KAAa,MAAA,EAAoB;AAChF,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,UAAA;AACd,EAAA,MAAM,QAAA,GAAW,MAAM,MAAM,CAAA;AAC7B,EAAA,IAAI,QAAA,KAAa,QAAW,OAAO,QAAA;AACnC,EAAA,MAAM,WAAW,MAAA,EAAO;AACxB,EAAA,MAAA,CAAO,eAAe,UAAA,EAAY,MAAA,EAAQ,EAAE,KAAA,EAAO,UAAU,CAAA;AAC7D,EAAA,OAAO,QAAA;AACT;;ACkFO,IAAM,YAAA,GAAN,MAAM,aAAA,CAAa;AAAA,EAExB,OAAgB,SAAA,GAAY,cAAA;AAAA,IAC1B,qCAAA;AAAA,IACA,OAA6B,EAAE,MAAA,kBAAQ,IAAI,SAAQ,EAAG,KAAA,kBAAO,IAAI,GAAA,EAAI,EAAE;AAAA,GACzE;AAAA,EACS,SAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EAMT,WAAA,CAAY,SAA8B,KAAA,EAAe;AACvD,IAAA,IAAA,CAAK,YAAY,OAAA,CAAQ,QAAA;AACzB,IAAA,IAAA,CAAK,UAAA,GAAa,QAAQ,SAAA,IAAa,IAAA;AACvC,IAAA,IAAA,CAAK,OAAA,GAAU,QAAQ,KAAK,CAAA,cAAA,CAAA;AAC5B,IAAA,aAAA,CAAa,SAAA,CAAU,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA;AAAA,EAC/C;AAAA,EAGA,OAAA,CAAQ,MAAe,MAAA,EAAuB;AAC5C,IAAA,MAAM,QAAQ,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AACjD,IAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AACpB,MAAA,KAAA,MAAW,UAAU,KAAA,EAAO,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,CAAC,MAAM,CAAA;AACvD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,aAAa,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,IAAA,CAAK,YAAY,CAAA;AACvD,IAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,UAAA,CAAW,WAAW,CAAA,EAAG;AACjD,MAAA,KAAA,MAAW,MAAA,IAAU,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAC7C,MAAA,KAAA,MAAW,MAAA,IAAU,UAAA,EAAY,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAClD,MAAA;AAAA,IACF;AACA,IAAA,KAAA,MAAW,UAAU,KAAA,EAAO,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,CAAC,MAAM,CAAA;AACvD,IAAA,KAAA,MAAW,MAAA,IAAU,UAAA,EAAY,IAAA,CAAK,MAAA,CAAO,QAAQ,MAAM,CAAA;AAAA,EAC7D;AAAA,EAOA,QAAQ,IAAA,EAAqB;AAC3B,IAAA,KAAA,MAAW,MAAA,IAAU,CAAC,IAAA,EAAM,GAAG,KAAK,gBAAA,CAAiB,GAAG,CAAC,CAAA,EAAG;AAC1D,MAAA,IAAI,EAAE,kBAAkB,WAAA,CAAA,EAAc;AACtC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAC/B,MAAA,MAAM,IAAA,GAAO,KAAA,IAAS,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AACtC,MAAA,IAAI,CAAC,KAAA,IAAS,CAAC,IAAA,EAAM;AACrB,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,KAAW,IAAA,CAAK,OAAA,IAAW,CAAC,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAA;AACjF,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAChC,MAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AACrB,MAAA,MAAM,KAAA,GAAQ,MAAM,KAAK,CAAA;AACzB,MAAA,IAAI,KAAA,EAAO,KAAA,CAAM,MAAA,KAAW,IAAA,CAAK,MAAA;AACjC,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,QAAQ,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,GAAI,MAAA;AAC/C,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,IAAI,OAAO,MAAA,KAAW,KAAA,CAAM,OAAA,EAAS,MAAA,CAAO,SAAS,KAAA,CAAM,OAAA;AAAA,QAC7D,CAAA,MAAO;AACL,UAAA,qBAAA,CAAsB,MAAA,EAAQ,QAAA,EAAU,IAAA,CAAK,QAAQ,CAAA;AAAA,QACvD;AAAA,MACF;AACA,MAAA,IAAA,CAAK,KAAA,CAAM,QAAQ,KAAK,CAAA;AAAA,IAC1B;AAAA,EACF;AAAA,EAGA,MAAA,CAAO,QAAqB,MAAA,EAAuB;AACjD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA;AAChC,IAAA,MAAM,IAAA,GAAO,KAAK,KAAA,CAAM,KAAK,KAAK,IAAA,CAAK,QAAA,CAAS,QAAQ,KAAK,CAAA;AAC7D,IAAA,MAAM,QAAQ,CAAC,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,OAAO,IAAI,CAAA;AAChD,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAI,KAAA,IAAS,MAAA,CAAO,MAAA,KAAW,MAAA,SAAe,MAAA,GAAS,MAAA;AACvD,IAAA,IAAA,CAAK,KAAA,CAAM,QAAQ,KAAK,CAAA;AAAA,EAC1B;AAAA,EAGA,MAAM,MAAA,EAA2B;AAC/B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAC/B,IAAA,IAAI,KAAA,IAAS,KAAK,KAAA,CAAM,KAAK,GAAG,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA;AAAA,EACpE;AAAA,EAGA,MAAM,MAAA,EAA+C;AACnD,IAAA,OAAO,aAAA,CAAa,SAAA,CAAU,MAAA,CAAO,GAAA,CAAI,MAAM,CAAA,IAAK,MAAA,CAAO,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA,GAChF,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,GAClB,MAAA;AAAA,EACN;AAAA,EAGA,OAAO,MAAA,EAAmC;AACxC,IAAA,MAAM,MAAA,GAAS,cAAa,SAAA,CAAU,MAAA;AACtC,IAAA,MAAM,QAAQ,MAAA,CAAO,GAAA,CAAI,MAAM,CAAA,IAAK,IAAA,CAAK,MAAM,MAAM,CAAA;AACrD,IAAA,MAAA,CAAO,GAAA,CAAI,QAAQ,KAAK,CAAA;AACxB,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAGA,MAAM,MAAA,EAAmC;AACvC,IAAA,MAAM,QAAwD,EAAC;AAC/D,IAAA,KAAA,MAAW,MAAA,IAAU,aAAA,CAAa,SAAA,CAAU,KAAA,EAAO;AACjD,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,MAAM,CAAA;AAC1C,MAAA,IAAI,MAAM,KAAA,CAAM,IAAA,CAAK,EAAE,GAAG,IAAA,EAAM,QAAQ,CAAA;AAAA,IAC1C;AACA,IAAA,MAAM,QAAQ,CAAC,EAAE,OAAA,EAAQ,KACvB,QAAQ,MAAA,CAAO,CAAC,IAAA,KAAS,KAAA,CAAM,KAAK,CAAC,KAAA,KAAU,MAAM,MAAA,KAAW,IAAI,CAAC,CAAA,CAAE,MAAA;AACzE,IAAA,OAAO,KAAA,CACJ,KAAK,CAAC,GAAA,EAAK,UAAU,KAAA,CAAM,GAAG,IAAI,KAAA,CAAM,KAAK,CAAC,CAAA,CAC9C,GAAA,CAAI,CAAC,EAAE,MAAA,EAAQ,UAAU,OAAA,EAAS,MAAA,IAAU,KAAA,MAAW;AAAA,MACtD,QAAA,EAAU,IAAA;AAAA,MACV,MAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA,EAAQ,UAAU,KAAA,GAAQ;AAAA,KAC5B,CAAE,CAAA;AAAA,EACN;AAAA,EAGA,MAAM,KAAA,EAA6C;AACjD,IAAA,MAAM,OACJ,KAAA,CAAM,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,aAAa,IAAI,CAAA,IAC3C,MAAM,IAAA,CAAK,CAAC,SAAS,IAAA,CAAK,QAAA,KAAa,QAAQ,IAAA,CAAK,MAAA,KAAW,KAAK,OAAO,CAAA;AAC7E,IAAA,IAAI,IAAA,OAAW,QAAA,GAAW,IAAA;AAC1B,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAGA,QAAA,CAAS,MAAA,EAAqB,KAAA,EAA8B,IAAA,EAA2B;AACrF,IAAA,OAAO,KAAA,CAAM,KAAA,CAAM,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,KAAA,KAAU,KAAA,CAAM,OAAA,KAAY,OAAO,MAAM,CAAA;AAAA,EAC7F;AAAA,EAGA,QAAA,CAAS,QAAqB,KAAA,EAAiC;AAC7D,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,EAAA,CAAG,EAAE,CAAA;AACvB,IAAA,MAAM,OAAO,GAAA,IAAO,MAAA,CAAO,MAAA,KAAW,GAAA,CAAI,UAAU,GAAA,GAAM,MAAA;AAC1D,IAAA,MAAM,IAAA,GAAmB;AAAA,MACvB,QAAA,EAAU,IAAA;AAAA,MACV,QAAQ,IAAA,CAAK,OAAA;AAAA,MACb,UAAU,IAAA,GAAO,IAAA,CAAK,QAAA,GAAW,MAAA,CAAO,aAAa,QAAQ,CAAA;AAAA,MAC7D,OAAA,EAAS,KAAA;AAAA,MACT,QAAQ,IAAA,KAAS;AAAA,KACnB;AACA,IAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AACf,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAGA,KAAA,CAAM,QAAqB,KAAA,EAAoC;AAC7D,IAAA,MAAM,OAAA,uBAAc,GAAA,CAA2B,CAAC,CAAC,IAAA,CAAK,OAAA,EAAS,IAAI,CAAC,CAAC,CAAA;AACrE,IAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AAC7B,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,KAAK,EAAE,GAAA,CAAI,CAAC,KAAA,KAAU,KAAA,CAAM,MAAM,CAAA;AAC/D,MAAA,MAAM,OAAA,GAAU,CAAC,GAAG,IAAI,IAAI,KAAA,CAAM,OAAA,EAAS,CAAC,EAAE,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,KAAS,KAAK,MAAM,CAAA;AACnF,MAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,OAAA,CAAQ,WAAW,CAAA,GAAI,EAAC,GAAI,CAAC,KAAK,CAAA;AAChE,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,IAAA,CAAK,MAAA;AAAA,QACL,MAAA,CAAO,YAAA,CAAa,QAAQ,CAAA,KAAM,IAAA,CAAK,YACrC,OAAA,CAAQ,MAAA,KAAW,CAAA,IACnB,KAAA,KAAU,KAAA,CAAM,MAAA,GAAS,IACvB,IAAA,GACA,IAAA,CAAK,SAAA,CAAU,CAAC,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,OAAA,EAAS,GAAG,MAAA,EAAQ,GAAG,OAAO,CAAC;AAAA,OACzE;AAAA,IACF,CAAC,CAAA;AACD,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,QAAQ,CAAA,IAAK,OAAA,EAAS;AACtC,MAAA,qBAAA,CAAsB,MAAA,EAAQ,MAAM,QAAQ,CAAA;AAAA,IAC9C;AAAA,EACF;AAAA,EAOA,SAAA,CAAU,QAAqB,IAAA,EAAmC;AAChE,IAAA,IAAI;AACF,MAAA,MAAM,SAAkB,IAAA,CAAK,KAAA,CAAM,OAAO,YAAA,CAAa,IAAI,KAAK,MAAM,CAAA;AACtE,MAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,GAAG,OAAO,IAAA;AACnC,MAAA,MAAM,CAAC,QAAA,EAAU,OAAA,EAAS,GAAG,IAAI,CAAA,GAAI,MAAA;AACrC,MAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,OAAO,QAAA,KAAa,UAAU,OAAO,IAAA;AAC9D,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,CAAC,CAAA,KAAM,KAAA;AAC3B,MAAA,MAAM,OAAA,GAAU,MAAA,GAAS,IAAA,GAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5C,MAAA,IAAI,CAAC,QAAQ,KAAA,CAAM,CAAC,UAA2B,OAAO,KAAA,KAAU,QAAQ,CAAA,EAAG,OAAO,IAAA;AAClF,MAAA,OAAO,OAAO,YAAY,SAAA,GAAY,EAAE,UAAU,OAAA,EAAS,MAAA,EAAQ,SAAQ,GAAI,IAAA;AAAA,IACjF,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA,EAGA,OAAA,CAAQ,MAAe,OAAA,EAAgD;AACrE,IAAA,OAAO,QAAQ,MAAA,CAAO,CAAC,WAAW,IAAA,CAAK,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,EACzD;AACF,CAAA;;ACtRO,SAAS,eAAA,CAAgB,GAAA,EAAa,QAAA,GAA8B,EAAC,EAAa;AAIvF,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,EAAK;AACtB,EAAA,IAAI,KAAK,MAAA,KAAW,CAAA,EAAG,OAAO,CAAC,GAAG,QAAQ,CAAA;AAE1C,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,CAAC,GAAG,QAAQ,CAAA;AAAA,EACrB;AAEA,EAAA,IAAI,CAAC,MAAM,OAAA,CAAQ,MAAM,GAAG,OAAO,CAAC,GAAG,QAAQ,CAAA;AAC/C,EAAA,OAAO,OAAO,MAAA,CAAO,CAAC,KAAA,KAA2B,OAAO,UAAU,QAAQ,CAAA;AAC5E;;ACtCA,IAAM,uBAAA,GAA0B;AAAA,EAC9B,WAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA;AAgDO,IAAM,cAAA,GAAN,MAAM,eAAA,SAAuB,UAAA,CAAwB;AAAA,EAEjD,QAAA,GAAW,IAAI,iBAAA,EAAkB;AAAA,EAE1C,OAAgB,MAAA,GAAS;AAAA,IACvB,OAAA,EAAS,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,GAAA,EAAQ;AAAA,IAC1C,YAAA,EAAc,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,CAAA,EAAE;AAAA,IAIzC,MAAA,EAAQ,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,EAAA;AAAG,GACtC;AAAA,EAEA,OAAO,gBAAA,GAAmB;AAAA,IACxB,SAAS,aAAA,CAAc,aAAA;AAAA,IACvB,cAAc,aAAA,CAAc;AAAA,GAC9B;AAAA,EACA,OAAgB,OAAA,GAAU,CAAC,QAAA,EAAU,MAAM,CAAA;AAAA,EAC3C,OAAO,MAAA,GAAS,CAAC,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,EASlC,iBAAiB,IAAI,YAAA;AAAA,IAC5B,EAAE,QAAA,EAAU,MAAM,IAAA,CAAK,aAAA,EAAc;AAAA,IACrC,IAAA,CAAK;AAAA,GACP;AAAA,EAES,YAAA,GAAe,IAAI,YAAA,CAAa,EAAE,QAAA,EAAU,MAAM,IAAA,CAAK,WAAA,EAAY,EAAG,IAAA,CAAK,UAAU,CAAA;AAAA,EAErF,SAAA,GAAY,IAAI,WAAA,EAAY;AAAA,EACrC,KAAA,GAAQ,KAAA;AAAA,EACR,SAAA,GAAY,KAAA;AAAA,EAEZ,aAAA,GAAgB,CAAA;AAAA,EAEhB,UAAA,GAAa,KAAA;AAAA,EAMJ,kBAAA,GAAqB,IAAI,WAAA,EAAY;AAAA,EAErC,oBAAA,GAAuB,IAAI,WAAA,EAAY;AAAA,EAKhD,eAAyB,EAAC;AAAA,EAEjB,cAAc,MAAY;AAIjC,IAAA,IAAA,CAAK,aAAA,GAAgB,KAAK,GAAA,EAAI;AAC9B,IAAA,IAAI,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,SAAA,EAAW;AAEhC,MAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,MAAA,IAAA,CAAK,SAAA,GAAY,KAAA;AACjB,MAAA,IAAA,CAAK,QAAA,EAAS;AACd,MAAA,IAAA,CAAK,SAAS,QAAA,EAAU,EAAE,MAAA,EAAQ,IAAI,CAAA;AACtC,MAAA,IAAA,CAAK,IAAA,EAAK;AAAA,IACZ;AAAA,EACF,CAAA;AAAA,EAES,gBAAgB,MAAY;AAGnC,IAAA,IAAI,QAAA,CAAS,eAAA,KAAoB,SAAA,EAAW,IAAA,CAAK,WAAA,EAAY;AAAA,EAC/D,CAAA;AAAA,EAES,OAAA,GAAgB;AAMvB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,SAAA,GAAY,KAAA;AACjB,IAAA,IAAA,CAAK,QAAA,EAAS;AACd,IAAA,IAAA,CAAK,aAAA,CAAc,eAAA,CAAgB,IAAA,CAAK,WAAA,EAAa,uBAAuB,CAAC,CAAA;AAC7E,IAAA,IAAA,CAAK,oBAAA,CAAqB,GAAA,CAAI,QAAA,EAAU,kBAAA,EAAoB,KAAK,aAAa,CAAA;AAC9E,IAAA,IAAA,CAAK,IAAA,EAAK;AAAA,EACZ;AAAA,EAES,UAAA,GAAmB;AAC1B,IAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAClB,IAAA,IAAA,CAAK,mBAAmB,OAAA,EAAQ;AAChC,IAAA,IAAA,CAAK,qBAAqB,OAAA,EAAQ;AAClC,IAAA,IAAA,CAAK,UAAU,QAAA,EAAS;AAAA,EAC1B;AAAA,EAOA,kBAAA,GAA2B;AACzB,IAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AACtB,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,WAAA,EAAa,uBAAuB,CAAA;AACvE,IAAA,IACE,KAAA,CAAM,MAAA,KAAW,IAAA,CAAK,YAAA,CAAa,UACnC,KAAA,CAAM,KAAA,CAAM,CAAC,IAAA,EAAM,KAAA,KAAU,IAAA,KAAS,IAAA,CAAK,YAAA,CAAa,KAAK,CAAC,CAAA;AAE9D,MAAA;AACF,IAAA,IAAA,CAAK,cAAc,KAAK,CAAA;AAAA,EAC1B;AAAA,EAOA,mBAAA,GAA4B;AAC1B,IAAA,IAAI,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,SAAA,EAAU;AAAA,EACtC;AAAA,EAOA,wBAAA,GAAiC;AAC/B,IAAA,IAAI,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,SAAA,EAAU;AAAA,EACtC;AAAA,EAGA,cAAc,KAAA,EAAuB;AACnC,IAAA,IAAA,CAAK,mBAAmB,OAAA,EAAQ;AAChC,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,QAAA,EAAU,IAAA,EAAM,KAAK,WAAA,EAAa;AAAA,QAC5D,OAAA,EAAS,IAAA;AAAA,QACT,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,IACH;AACA,IAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AAAA,EACtB;AAAA,EAGA,IAAA,GAAa;AACX,IAAA,IAAA,CAAK,aAAA,GAAgB,KAAK,GAAA,EAAI;AAC9B,IAAA,IAAA,CAAK,SAAA,EAAU;AAAA,EACjB;AAAA,EAYA,SAAA,GAAkB;AAChB,IAAA,IAAA,CAAK,UAAU,QAAA,EAAS;AACxB,IAAA,IAAI,KAAK,KAAA,EAAO;AAChB,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,aAAA;AAClC,IAAA,MAAM,UAAU,IAAA,CAAK,YAAA;AACrB,IAAA,MAAM,SAAS,IAAA,CAAK,iBAAA;AACpB,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,MAAM,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,SAAA,CAAU,OAAA,GAAU,OAAO,CAAC,CAAA;AAC7E,IAAA,IAAI,IAAA,CAAK,SAAA,IAAa,MAAA,IAAU,CAAA,IAAK,UAAU,OAAA,EAAS;AACxD,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,UAAU,OAAO,CAAA;AAC/C,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,MAAM,IAAA,CAAK,YAAA,CAAa,IAAI,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,OAAA,GAAU,MAAA,GAAS,OAAO,CAAC,CAAA;AAAA,EAC9F;AAAA,EAGA,UAAU,SAAA,EAA2B;AACnC,IAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,SAAA,EAAW,CAAC,GAAG,kBAAkB,CAAA;AAAA,EAC5D;AAAA,EAYA,UAAA,GAAmB;AACjB,IAAA,MAAM,YAAY,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,GAAA,KAAQ,IAAA,CAAK,aAAA,CAAA;AACzD,IAAA,IAAI,YAAY,CAAA,EAAG;AACjB,MAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,MAAM,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,kBAAkB,CAAC,CAAA;AACnF,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAA,IAAA,CAAK,SAAA,GAAY,KAAA;AACjB,IAAA,IAAA,CAAK,QAAA,EAAS;AACd,IAAA,IAAA,CAAK,SAAS,MAAA,EAAQ,EAAE,MAAA,EAAQ,IAAI,CAAA;AAAA,EACtC;AAAA,EAcA,YAAA,CAAa,IAAA,GAAO,IAAA,CAAK,iBAAA,EAAyB;AAChD,IAAA,IAAI,KAAK,KAAA,EAAO;AAChB,IAAA,MAAM,SAAA,GACJ,KAAK,YAAA,GAAe,IAAA,CAAK,qBAAqB,IAAA,CAAK,GAAA,KAAQ,IAAA,CAAK,aAAA,CAAA;AAClE,IAAA,IAAI,YAAY,CAAA,EAAG;AACjB,MAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,MAAM,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,kBAAkB,CAAC,CAAA;AACrF,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,IAAA,IAAA,CAAK,QAAA,EAAS;AACd,IAAA,IAAA,CAAK,QAAA,CAAS,UAAU,EAAE,MAAA,EAAQ,EAAE,SAAA,EAAW,IAAA,IAAQ,CAAA;AAAA,EACzD;AAAA,EAGA,qBAAA,GAA8B;AAC5B,IAAA,IAAA,CAAK,cAAA,CAAe,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,KAAK,SAAS,CAAA;AAAA,EAC1D;AAAA,EAGA,mBAAA,GAA4B;AAC1B,IAAA,IAAA,CAAK,YAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,KAAK,KAAK,CAAA;AAAA,EACpD;AAAA,EAOA,QAAA,GAAiB;AACf,IAAA,MAAM,EAAE,SAAQ,GAAI,IAAA;AACpB,IAAA,IAAI,IAAA,CAAK,SAAA,EAAW,OAAA,CAAQ,YAAA,CAAa,eAAe,MAAM,CAAA;AAAA,SACzD,OAAA,CAAQ,gBAAgB,aAAa,CAAA;AAC1C,IAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,CAAQ,YAAA,CAAa,aAAa,MAAM,CAAA;AAAA,SACnD,OAAA,CAAQ,gBAAgB,WAAW,CAAA;AACxC,IAAA,IAAA,CAAK,cAAA,CAAe,OAAA,CAAQ,OAAA,EAAS,IAAA,CAAK,SAAS,CAAA;AACnD,IAAA,IAAA,CAAK,YAAA,CAAa,OAAA,CAAQ,OAAA,EAAS,IAAA,CAAK,KAAK,CAAA;AAAA,EAC/C;AAAA,EAEA,IAAI,YAAA,GAAuB;AACzB,IAAA,OAAO,KAAK,QAAA,CAAS,IAAA;AAAA,MACnB,IAAA;AAAA,MACA,SAAA;AAAA,MACA,IAAA,CAAK,YAAA;AAAA,MACL,eAAA,CAAe,OAAO,OAAA,CAAQ,OAAA;AAAA,MAC9B,gBAAe,gBAAA,CAAiB;AAAA,KAClC;AAAA,EACF;AAAA,EAGA,IAAI,iBAAA,GAA4B;AAC9B,IAAA,OAAO,KAAK,QAAA,CAAS,IAAA;AAAA,MACnB,IAAA;AAAA,MACA,cAAA;AAAA,MACA,IAAA,CAAK,iBAAA;AAAA,MACL,eAAA,CAAe,OAAO,YAAA,CAAa,OAAA;AAAA,MACnC,gBAAe,gBAAA,CAAiB;AAAA,KAClC;AAAA,EACF;AACF","file":"idle_controller.js","sourcesContent":["/** What {@link ListenerSet.add} passes on besides the signal it supplies itself. */\nexport type ListenerOptions = Omit<AddEventListenerOptions, \"signal\">;\n\n/**\n * The event map a target's own `addEventListener` types its handlers with: the\n * window's, a document's, an HTML or SVG element's, any other element's, or a\n * media query list's. Other targets name none.\n */\ntype EventMapOf<T extends EventTarget> = T extends Window\n ? WindowEventMap\n : T extends Document\n ? DocumentEventMap\n : T extends HTMLElement\n ? HTMLElementEventMap\n : T extends SVGElement\n ? SVGElementEventMap\n : T extends Element\n ? ElementEventMap\n : T extends MediaQueryList\n ? MediaQueryListEventMap\n : Record<never, never>;\n\n/**\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.\n * {@link 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 * A lifetime shorter than the connection — while a Value holds, until a first\n * load, while a subscription is open — gets a set of its own, which the end of\n * that lifetime disposes. A controller therefore holds one set per lifetime: the\n * connection's, and one for each swapped receiver or shorter span.\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, listeners of\n * several elements that come and go one at a time, and those one gesture holds\n * keep their own pair of calls or a signal of their own.\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. A removal by hand would have to repeat that\n * flag; aborting the signal releases the listener without it.\n *\n * A `type` the target's own event map names types `handler` with that event,\n * as the target's `addEventListener` does, so a handler written for a\n * `KeyboardEvent` is passed as it is; any other `type` takes an\n * `EventListener`.\n */\n add<T extends EventTarget, K extends keyof EventMapOf<T> & string>(\n target: T,\n type: K,\n handler: (event: EventMapOf<T>[K]) => void,\n options?: ListenerOptions,\n ): void;\n add(target: EventTarget, type: string, handler: EventListener, options?: ListenerOptions): void;\n add(target: EventTarget, type: string, handler: EventListener, options?: ListenerOptions): 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 * Largest delay a timer can hold: the platform stores it in a 32-bit signed\n * integer, and anything larger wraps around, so a delay meant to be far in the\n * future can fire almost immediately. A declared delay above this bound names\n * no delay at all, and a controller reading one falls back to its default.\n */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n","import { MAX_TIMER_DELAY_MS } from \"./timer_bounds\";\n\n/** Semantic constraints on an already decoded number, independent of the DOM. */\nexport interface NumberBounds {\n /** Finite numbers are required, including when this field is omitted. */\n readonly finite?: true;\n /** Inclusive lower endpoint. */\n readonly min?: number;\n /** Inclusive upper endpoint. */\n readonly max?: number;\n /** Exclusive lower endpoint. */\n readonly exclusiveMin?: number;\n /** Require a number without a fractional part. */\n readonly integer?: boolean;\n /** Exact decoded numbers accepted by a discrete contract. */\n readonly allowedValues?: readonly number[];\n /** JSON-safe exceptions to finite-number checking for unbounded endpoints. */\n readonly allowInfinity?: \"negative\" | \"positive\" | \"both\";\n}\n\n/** One constraint for each Number Value, including shorthand declarations. */\nexport type NumberValueConstraints<Values> = {\n readonly [Key in keyof Values as Values[Key] extends\n | NumberConstructor\n | { type: NumberConstructor }\n ? Key\n : never]: NumberBounds;\n};\n\n/** Reusable semantic domains; fractional inputs remain fractional unless excluded. */\nexport const NUMBER_BOUNDS = {\n finite: { finite: true },\n nonNegative: { finite: true, min: 0 },\n positive: { finite: true, exclusiveMin: 0 },\n nonNegativeInteger: { finite: true, min: 0, integer: true },\n positiveInteger: { finite: true, exclusiveMin: 0, integer: true },\n lowerBound: { finite: true, allowInfinity: \"negative\" },\n upperBound: { finite: true, allowInfinity: \"positive\" },\n timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS },\n positiveTimer: { finite: true, exclusiveMin: 0, max: MAX_TIMER_DELAY_MS },\n} as const satisfies Record<string, NumberBounds>;\n\n/**\n * Checks all declared bounds without rounding, clamping, or coercing the input.\n * Infinity exceptions relax only finite checking; every other bound still applies.\n */\nexport function matchesNumberBounds(value: number, bounds: NumberBounds): boolean {\n if (!Number.isFinite(value)) {\n const direction = value === Infinity ? \"positive\" : value === -Infinity ? \"negative\" : null;\n if (direction === null) return false;\n if (bounds.allowInfinity !== \"both\" && bounds.allowInfinity !== direction) return false;\n }\n if (bounds.min !== undefined && value < bounds.min) return false;\n if (bounds.max !== undefined && value > bounds.max) return false;\n if (bounds.exclusiveMin !== undefined && value <= bounds.exclusiveMin) return false;\n if (bounds.integer && !Number.isInteger(value)) return false;\n if (bounds.allowedValues !== undefined && !bounds.allowedValues.includes(value)) return false;\n return true;\n}\n\n/** Decodes a Number Value literal; action params use their own JSON decoder. */\nexport function decodeNumberValue(raw: string): number {\n return Number(raw.replace(/_/g, \"\"));\n}\n","/**\n * Numeric coercion for controllers that accept a number through a Value, an action\n * param, or an event detail.\n *\n * Stimulus decodes action params as JSON when possible and leaves other text\n * untouched. CustomEvent detail can also supply a number or numeric string.\n * The reader accepts those two types while rejecting blank and non-finite input.\n */\n\nimport { matchesNumberBounds, type NumberBounds } from \"./number_bounds\";\n\n/** Numeric update input, accepting decoded action params before CustomEvent detail. */\nexport type NumericValueEvent = Event & {\n params?: { amount?: unknown };\n detail?: { value?: unknown };\n};\n\n/** Reads the nullish action-param/detail precedence without falling back from invalid input. */\nexport function eventNumber(event: NumericValueEvent): number | null {\n return toFiniteNumber(event.params?.amount ?? event.detail?.value);\n}\n\n/**\n * Reads a finite number or nonblank numeric string; other input returns `null`.\n * Blank strings cannot silently reset a value to zero.\n */\nexport function toFiniteNumber(raw: unknown): number | null {\n if (typeof raw !== \"number\" && typeof raw !== \"string\") return null;\n if (typeof raw === \"string\" && raw.trim().length === 0) return null;\n const value = Number(raw);\n return Number.isFinite(value) ? value : null;\n}\n\n/**\n * Returns an accepted decoded Number Value or the caller's fallback unchanged.\n * The caller owns the fallback contract; this reader does not parse or write a Value.\n */\nexport function readNumber(raw: number, fallback: number, bounds: NumberBounds): number {\n return matchesNumberBounds(raw, bounds) ? raw : fallback;\n}\n","import { readNumber } from \"./coerce\";\nimport { matchesNumberBounds, type NumberBounds } from \"./number_bounds\";\n\n/** The instance identity carried by a Number Value read. */\nexport interface NumberValueOwner {\n readonly identifier: string;\n readonly element: Element;\n}\n\n/** Reads current declarations at the point of use without rewriting their attributes. */\nexport class NumberValueReader {\n /** The last rejected literal per Value; no history grows for an unchanged instance. */\n readonly #lastRejected = new Map<string, string>();\n\n /** Resolves the declared number using its own fallback and shared class contract. */\n read(\n owner: NumberValueOwner,\n name: string,\n raw: number,\n fallback: number,\n bounds: NumberBounds,\n ): number {\n const resolved = readNumber(raw, fallback, bounds);\n if (matchesNumberBounds(raw, bounds)) {\n this.#lastRejected.delete(name);\n return resolved;\n }\n const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;\n const literal = owner.element.getAttribute(attribute);\n if (literal === null) {\n this.#lastRejected.delete(name);\n return resolved;\n }\n if (this.#lastRejected.get(name) !== literal) {\n this.#lastRejected.set(name, literal);\n console.warn(\n `Stimeo UI: \"${owner.identifier}\" has an invalid number Value \"${name}\" declaration ${JSON.stringify(literal)}; using ${fallback}.`,\n );\n }\n return resolved;\n }\n}\n","/**\n * Self-cleaning timer registries shared by Stimeo controllers.\n *\n * Stimulus controllers frequently schedule `setTimeout` / `setInterval` work\n * (auto-dismiss, debouncing, polling). When the element leaves the DOM — a\n * Turbo Drive navigation, a Turbo Stream replacement, or any `disconnect()` —\n * orphaned timers keep firing against a detached controller, leaking memory and\n * mutating stale state. {@link SafeTimeout} and {@link SafeInterval} track every\n * timer they create so a single {@link TimerRegistry.clearAll | clearAll()} call\n * in `disconnect()` tears them all down.\n *\n * These are intentionally low-level primitives: they own *registration and\n * cleanup only*. One pending timer per key is `KeyedTimers`\n * (`keyed_timers.ts`), and a timer a person can hold open, with its remaining-time\n * accounting, is `PausableTimers` (`pausable_timers.ts`).\n */\n\nexport { MAX_TIMER_DELAY_MS } from \"./timer_bounds\";\n\n/**\n * Shared registry bookkeeping for the timeout/interval variants.\n *\n * Subclasses provide the scheduling primitive ({@link schedule}) and its matching\n * canceller ({@link cancel}); this base owns the set of live ids plus the\n * per-id and bulk teardown shared by both.\n */\nabstract class TimerRegistry {\n /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */\n protected readonly ids = new Set<number>();\n\n /** Schedules the underlying platform timer and returns its id. */\n protected abstract schedule(callback: () => void, delay: number): number;\n\n /** Cancels the underlying platform timer for `id`. */\n protected abstract cancel(id: number): void;\n\n /**\n * Cancels a single tracked timer.\n *\n * No-ops if the id is unknown (already cleared, fired, or never owned by this\n * registry), so callers can clear defensively without guarding.\n */\n clear(id: number): void {\n if (this.ids.delete(id)) {\n this.cancel(id);\n }\n }\n\n /**\n * Cancels every tracked timer. Call this from a controller's `disconnect()`\n * to guarantee no timer outlives the element.\n */\n clearAll(): void {\n for (const id of this.ids) {\n this.cancel(id);\n }\n this.ids.clear();\n }\n\n /** Number of timers currently tracked (pending). */\n get size(): number {\n return this.ids.size;\n }\n}\n\n/**\n * `setTimeout` wrapper that auto-forgets each timer once it fires and supports\n * bulk teardown on disconnect.\n *\n * @example\n * ```ts\n * #timers = new SafeTimeout();\n *\n * connect() {\n * this.#timers.set(() => this.dismiss(), 5000);\n * }\n *\n * disconnect() {\n * this.#timers.clearAll();\n * }\n * ```\n */\nexport class SafeTimeout extends TimerRegistry {\n /**\n * Schedules `callback` after `delay` ms and returns the timer id.\n *\n * The id is removed from the registry automatically when the timeout fires,\n * so {@link TimerRegistry.size | size} reflects only still-pending timers.\n */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(() => {\n this.ids.delete(id);\n callback();\n }, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setTimeout(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearTimeout(id);\n }\n}\n\n/**\n * `setInterval` wrapper that tracks every interval for bulk teardown on\n * disconnect. Unlike {@link SafeTimeout}, intervals are retained until they are\n * explicitly cleared because they fire repeatedly.\n *\n * @example\n * ```ts\n * #intervals = new SafeInterval();\n *\n * connect() {\n * this.#intervals.set(() => this.tick(), 1000);\n * }\n *\n * disconnect() {\n * this.#intervals.clearAll();\n * }\n * ```\n */\nexport class SafeInterval extends TimerRegistry {\n /** Schedules a repeating `callback` every `delay` ms and returns the timer id. */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(callback, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setInterval(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearInterval(id);\n }\n}\n","/**\n * Reflects a serialized attribute value only when the current value differs.\n *\n * A same-value `setAttribute` still queues a mutation record for every observer, so an\n * unchanged value writes nothing.\n *\n * @param element - The element whose attribute is reflected.\n * @param name - The attribute name, using the non-namespaced DOM API.\n * @param value - The serialized value, or null to remove the attribute.\n * @param beforeWrite - Called only for a change, before the DOM mutation, so the\n * caller can record ownership or identify its own observer records.\n * @returns Whether an attribute was written or removed.\n */\nexport function setAttributeIfChanged(\n element: Element,\n name: string,\n value: string | null,\n beforeWrite?: () => void,\n): boolean {\n if (element.getAttribute(name) === value) return false;\n beforeWrite?.();\n if (value === null) element.removeAttribute(name);\n else element.setAttribute(name, value);\n return true;\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 { setAttributeIfChanged } from \"./attribute_write\";\nimport { sharedRegistry } from \"./shared_registry\";\n\n/** What a consumer declares once about the regions one boolean state reveals. */\nexport interface StateRegionsOptions {\n /** Returns the declared regions shown while the state holds. */\n readonly whenTrue: () => readonly HTMLElement[];\n /**\n * Returns the declared regions shown while the state does not hold. Omitted by a\n * state whose other side has nothing of its own to show.\n */\n readonly whenFalse?: () => readonly HTMLElement[];\n}\n\n/** One instance's hold on one region's `hidden`, in the stack every instance shares. */\ninterface RegionHold {\n /** The instance holding it; `null` for a hold read from a copy's record until it is taken. */\n instance: object | null;\n readonly record: string;\n /** What the author wrote: the `hidden` it hands back with nothing beneath it. */\n readonly authored: string | null;\n /** Whether the visibility it wrote last hides the region. */\n written: boolean;\n /** Whether it hands back what the hold beneath it wrote last instead. */\n linked: boolean;\n}\n\n/** What an instance's record on a region says. */\ninterface RegionRecord {\n readonly authored: string | null;\n readonly written: boolean;\n readonly linked: boolean;\n /** The records of the other owners' holds beneath it, nearest first. */\n readonly beneath: readonly string[];\n}\n\n/** The holds on each region and every instance's record name. */\ninterface StateRegionsRegistry {\n readonly stacks: WeakMap<HTMLElement, RegionHold[]>;\n readonly names: Set<string>;\n}\n\n/**\n * Owns `hidden` on the regions a boolean state reveals.\n *\n * A region is a **declared** target, so the consumer decides whether one exists at\n * all; where it does, which side is shown is a pure function of the state and the\n * controller writes it unconditionally. An authored `hidden` is therefore not read\n * back — the first reflection after a connection settles it, and a restored DOM\n * cannot leave a region contradicting the state it belongs to.\n *\n * The regions arrive as the caller's own target arrays, which Stimulus has already\n * scoped to this instance: a nested controller registered under the same identifier\n * keeps its own regions. `host` narrows that set further, to the regions inside one\n * trigger or item, so a widget with several of them reflects each independently.\n *\n * **Two sides are a pair.** Where the state has a `whenFalse` side and only one half\n * sits inside `host`, the half that is there is left in view: hiding it would take\n * the only label with it, and the static check names the missing one instead. What\n * the author wrote on a lone half is theirs and stays — only a half this instance\n * took out of view is given back, which is what a pair losing one side at runtime\n * leaves behind.\n *\n * `hidden` moves only where it changes, and the record below only where what it says changes:\n * a transition costs a consumer watching its own subtree for attribute mutations two of them on\n * each region it moves — `hidden` and the record — and a reflection that moves nothing costs\n * none. A write that moves no `hidden` — the page moved the region first, or another\n * instance's hold lies above this one — changes only the record.\n *\n * **Every instance shares one stack of holds per region**, whatever its owner and whichever\n * file of the package constructed it (the stacks are one per page): the holds sit in the order\n * their instances first wrote the region, each with the visibility it wrote last. The region's\n * visibility is the highest hold's that carries it, and the page's when none does. A write\n * moves `hidden` unless a hold above the writer carries the region's visibility, so the top\n * hold always shows its writes and the page's visibility gives way to the next write of any\n * hold. A release gives a visibility back only from the hold the region's visibility is: the\n * one the hold beneath it wrote last, or the author's `hidden` once nothing is beneath it; any\n * other release only leaves the stack. Holds that wrote the same visibility are told apart by\n * the stack: the higher one keeps it. A first write over a top hold whose visibility the page\n * has replaced takes the region's `hidden` as the author's. Two instances of one owner on one\n * region stack the same way.\n *\n * **The stack travels with the region.** While the region carries anything but what the author\n * wrote under its top hold, or a hold lies on another hold or is covered by one, the region\n * carries that hold's owner's record `data-<owner>-hidden-region`: JSON of what the author\n * wrote (a string, or `null` for an absent attribute), whether the visibility written last\n * hides the region, `false` where the hold hands back the author's `hidden` rather than the\n * latest visibility of the hold beneath it, and the records of every hold beneath it, nearest\n * first; the last release of an owner removes it. A copy of the region — a page Turbo restores\n * from its cache — therefore carries the stack, read back under the record names of the\n * instances constructed so far and ordered by the records each hold lists beneath it, and an\n * instance that reflects, gives back or releases the copy takes the hold its owner's record\n * describes over in place. Complete records for distinct owners preserve their order across\n * a copy, including release without a new reflection. Records describe owners, not instances:\n * one owner holding the region more than once leaves only its topmost hold's record, which\n * the first of its instances to write or release on the copy takes. Its lower holds and\n * positions are absent; mutually listed owners cannot express their full live order. A hold\n * that showed the author's `hidden` alone carries no record and is taken by its first write\n * on the copy. Missing or unreadable records also leave their holds unknown, so copying the\n * DOM does not promise identical decisions for every live stack. A new stack with no readable\n * record takes the current value as the author's; a morph can remove records while existing\n * holds remain in memory until released.\n *\n * @example\n * ```ts\n * readonly #labels = new StateRegions(\n * {\n * whenTrue: () => this.expandedLabelTargets,\n * whenFalse: () => this.collapsedLabelTargets,\n * },\n * this.identifier,\n * );\n *\n * #reflect(): void {\n * this.#labels.reflect(this.triggerTarget, this.#expanded);\n * }\n * ```\n */\nexport class StateRegions {\n /** The holds on each region, bottom first, and the record names; one per page. */\n static readonly #registry = sharedRegistry(\n \"stimeo-ui.state-regions.registry.v1\",\n (): StateRegionsRegistry => ({ stacks: new WeakMap(), names: new Set() }),\n );\n readonly #whenTrue: () => readonly HTMLElement[];\n readonly #whenFalse: (() => readonly HTMLElement[]) | null;\n readonly #record: string;\n\n /**\n * @param options - The declared regions of each side.\n * @param owner - Names the record on a region; the controller's identifier.\n */\n constructor(options: StateRegionsOptions, owner: string) {\n this.#whenTrue = options.whenTrue;\n this.#whenFalse = options.whenFalse ?? null;\n this.#record = `data-${owner}-hidden-region`;\n StateRegions.#registry.names.add(this.#record);\n }\n\n /** Shows the regions inside `host` that belong to `isTrue` and hides the others. */\n reflect(host: Element, isTrue: boolean): void {\n const shown = this.#inside(host, this.#whenTrue());\n if (!this.#whenFalse) {\n for (const region of shown) this.#write(region, !isTrue);\n return;\n }\n const hiddenSide = this.#inside(host, this.#whenFalse());\n if (shown.length === 0 || hiddenSide.length === 0) {\n for (const region of shown) this.#give(region);\n for (const region of hiddenSide) this.#give(region);\n return;\n }\n for (const region of shown) this.#write(region, !isTrue);\n for (const region of hiddenSide) this.#write(region, isTrue);\n }\n\n /**\n * Restores the regions this instance wrote inside `host` to what the hold beneath it wrote last\n * or the authored `hidden`, unless changed since; found by scan, as the declared lists stop\n * resolving with targets.\n */\n release(host: Element): void {\n for (const region of [host, ...host.querySelectorAll(\"*\")]) {\n if (!(region instanceof HTMLElement)) continue;\n const stack = this.#held(region);\n const hold = stack && this.#take(stack);\n if (!stack || !hold) continue;\n const owns = region.hidden === hold.written && !this.#covered(region, 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 if (owns) {\n const below = hold.linked ? stack[index - 1] : undefined;\n if (below) {\n if (region.hidden !== below.written) region.hidden = below.written;\n } else {\n setAttributeIfChanged(region, \"hidden\", hold.authored);\n }\n }\n this.#mark(region, stack);\n }\n }\n\n /** Writes `hidden` where it moves, unless a hold above this one carries the region's. */\n #write(region: HTMLElement, hidden: boolean): void {\n const stack = this.#stack(region);\n const hold = this.#take(stack) ?? this.#acquire(region, stack);\n const shows = !this.#covered(region, stack, hold);\n hold.written = hidden;\n if (shows && region.hidden !== hidden) region.hidden = hidden;\n this.#mark(region, stack);\n }\n\n /** Returns a region this instance hid; one it never hid keeps what it carries. */\n #give(region: HTMLElement): void {\n const stack = this.#held(region);\n if (stack && this.#take(stack)?.written) this.#write(region, false);\n }\n\n /** The region's stack, while it has one or carries this owner's record. */\n #held(region: HTMLElement): RegionHold[] | undefined {\n return StateRegions.#registry.stacks.has(region) || region.hasAttribute(this.#record)\n ? this.#stack(region)\n : undefined;\n }\n\n /** The region's stack, read from its records the first time. */\n #stack(region: HTMLElement): RegionHold[] {\n const stacks = StateRegions.#registry.stacks;\n const stack = stacks.get(region) ?? this.#seed(region);\n stacks.set(region, stack);\n return stack;\n }\n\n /** The holds a copy's records describe, each above every hold its record lists beneath. */\n #seed(region: HTMLElement): RegionHold[] {\n const found: (RegionRecord & { readonly record: string })[] = [];\n for (const record of StateRegions.#registry.names) {\n const read = this.#recorded(region, 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(({ record, authored, written, linked }, index) => ({\n instance: null,\n record,\n authored,\n written,\n linked: linked && index > 0,\n }));\n }\n\n /** Its hold in `stack`, taking over one read from its record. */\n #take(stack: RegionHold[]): RegionHold | undefined {\n const hold =\n stack.find((held) => held.instance === this) ??\n stack.find((held) => held.instance === null && held.record === this.#record);\n if (hold) hold.instance = this;\n return hold;\n }\n\n /** Whether a hold above `hold` carries the region's visibility, then that hold's. */\n #covered(region: HTMLElement, stack: readonly RegionHold[], hold: RegionHold): boolean {\n return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === region.hidden);\n }\n\n /** A new hold on top, over the top hold while the region shows what it wrote. */\n #acquire(region: HTMLElement, stack: RegionHold[]): RegionHold {\n const top = stack.at(-1);\n const over = top && region.hidden === top.written ? top : undefined;\n const hold: RegionHold = {\n instance: this,\n record: this.#record,\n authored: over ? over.authored : region.getAttribute(\"hidden\"),\n written: false,\n linked: over !== undefined,\n };\n stack.push(hold);\n return hold;\n }\n\n /** Leaves each owner's record of its topmost hold, or none where nothing needs one. */\n #mark(region: HTMLElement, stack: readonly RegionHold[]): 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 records.set(\n hold.record,\n region.getAttribute(\"hidden\") === hold.authored &&\n beneath.length === 0 &&\n index === stack.length - 1\n ? null\n : JSON.stringify([hold.authored, hold.written, ...marker, ...beneath]),\n );\n });\n for (const [name, recorded] of records) {\n setAttributeIfChanged(region, name, recorded);\n }\n }\n\n /**\n * The author's `hidden`, the visibility written last, whether it hands back the visibility\n * beneath it (`false` before the names when it does not) and the records beneath that the\n * record `name` on `region` holds.\n */\n #recorded(region: HTMLElement, name: string): RegionRecord | null {\n try {\n const parsed: unknown = JSON.parse(region.getAttribute(name) ?? \"null\");\n if (!Array.isArray(parsed)) return null;\n const [authored, written, ...rest] = parsed as unknown[];\n if (authored !== null && typeof authored !== \"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 typeof written === \"boolean\" ? { authored, written, linked, beneath } : null;\n } catch {\n return null;\n }\n }\n\n /** The declared regions that sit within `host`, which may be the host itself. */\n #inside(host: Element, regions: readonly HTMLElement[]): HTMLElement[] {\n return regions.filter((region) => host.contains(region));\n }\n}\n","/**\n * JSON string-list parsing for the controllers that take a list as a Value.\n *\n * Stimulus offers an `Array` Value type, but its reader runs `JSON.parse` inside\n * the value observer — **before** the `<name>ValueChanged` callback — and\n * rethrows on malformed text. The throw propagates out of the observer that runs\n * during connection, so a single unparseable attribute stops the controller from\n * connecting at all: no lifecycle callback runs and the element is left inert\n * rather than degraded. A consumer cannot guard against it either, because the\n * callback that would hold the `try` never runs.\n *\n * Declaring the attribute as a `String` Value and parsing it here keeps a\n * malformed declaration local to the value it declares. The attribute text is\n * identical either way (`'[\"a\", \"b\"]'`), so markup does not change with the\n * declaration.\n */\n\n/**\n * Parses `raw` as a JSON array of strings.\n *\n * Returns `fallback` when the text is absent, unparseable, or not an array, so a\n * malformed declaration behaves like an omitted one. A parsed array keeps only\n * its string entries: every caller indexes or compares strings, and a stray\n * number would otherwise sit in the list without ever matching.\n *\n * An explicit `\"[]\"` is honoured as an empty list rather than falling back — it\n * is the only way to declare \"none\" against a non-empty default.\n *\n * @param raw - the attribute text, e.g. `'[\"password\"]'`.\n * @param fallback - the list to use when `raw` declares nothing usable.\n */\nexport function parseStringList(raw: string, fallback: readonly string[] = []): string[] {\n // The common case is an undeclared attribute, and `JSON.parse(\"\")` answers it\n // by throwing. Reaching the same fallback without building an exception keeps\n // the callers that ask per element off that path.\n const text = raw.trim();\n if (text.length === 0) return [...fallback];\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return [...fallback];\n }\n\n if (!Array.isArray(parsed)) return [...fallback];\n return parsed.filter((entry): entry is string => typeof entry === \"string\");\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { ListenerSet } from \"../utils/listener_set\";\nimport { NUMBER_BOUNDS, type NumberValueConstraints } from \"../utils/number_bounds\";\nimport { NumberValueReader } from \"../utils/number_value\";\nimport { MAX_TIMER_DELAY_MS, SafeTimeout } from \"../utils/safe_timeout\";\nimport { StateRegions } from \"../utils/state_regions\";\nimport { parseStringList } from \"../utils/string_list\";\n\n/** Activity signals watched unless the consumer declares its own list. */\nconst DEFAULT_ACTIVITY_EVENTS = [\n \"mousemove\",\n \"mousedown\",\n \"keydown\",\n \"wheel\",\n \"touchstart\",\n \"scroll\",\n];\n\n/**\n * Headless inactivity / session-timeout detector: fires `idle` after `timeout` ms\n * with no user activity, an optional `prompt` `promptBefore` ms earlier, and\n * `active` when the user returns (no dedicated APG pattern; supports WCAG 2.2.1 by\n * giving the app a warning hook before a timeout).\n *\n * Markup contract (identifier: `stimeo--idle`):\n * <body data-controller=\"stimeo--idle\"\n * data-stimeo--idle-timeout-value=\"900000\"\n * data-stimeo--idle-prompt-before-value=\"60000\"\n * data-action=\"stimeo--idle:prompt->session#warn\n * stimeo--idle:idle->session#logout\">\n * <p data-stimeo--idle-target=\"prompt\" hidden>Your session expires in a minute.</p>\n * <p data-stimeo--idle-target=\"idle\" hidden>You have been signed out.</p>\n * </body>\n *\n * Activity events (`events`, passive) are watched on `document` with capture so\n * non-bubbling ones like `scroll` are seen anywhere; returning to a hidden tab\n * (`visibilitychange` → visible) counts as activity too. The controller element carries\n * `data-prompt` while the warning stands and `data-idle` once the timeout is reached,\n * and the optional `prompt` / `idle` targets are the regions those phases reveal:\n * declared where the page has something to show, shown while their phase holds and\n * hidden otherwise, whatever visibility the markup was authored with.\n *\n * `prompt` dispatches `{ remaining }`, the milliseconds left before `idle`: `promptBefore`\n * when the warning comes on schedule, and less when a declaration changed mid-cycle has\n * already put the cycle inside the warning window. `idle` and `active` dispatch `{}`.\n *\n * The three Values follow a change made while connected (a Turbo morph, a script).\n * `events` swaps the watched set: the old listeners go and the declared ones are added\n * once. `timeout` and `promptBefore` move the pending checks to the deadlines the new\n * declaration sets from the same last activity, so the time already spent inactive\n * counts; a deadline the elapsed time has already passed is acted on at once, and a\n * cycle past both deadlines goes idle without a warning for a window that is over. A\n * phase already reached stays: a raised warning goes only on activity or at the\n * timeout, and an idle detector schedules nothing until activity arms the next cycle\n * with the declaration in force.\n *\n * @remarks\n * Behavior only — it renders no warning UI (pair with `stimeo--dialog` or\n * `stimeo--confirm`) and never touches the server session. Timers are owned by\n * `SafeTimeout` and the listeners are removed on `disconnect()` (Turbo navigation\n * included). Place one on the root element. Every visit reconnects the controller and\n * re-arms the timeout from that moment — `data-turbo-permanent` keeps the element, not\n * the elapsed count.\n */\nexport class IdleController extends Controller<HTMLElement> {\n /** Numeric read boundaries share one reader for this controller instance. */\n readonly #numbers = new NumberValueReader();\n\n static override values = {\n timeout: { type: Number, default: 900_000 },\n promptBefore: { type: Number, default: 0 },\n // A JSON list read through `parseStringList` rather than Stimulus's `Array`\n // type: that reader throws out of the value observer before any callback\n // runs, so one malformed attribute would stop the detector connecting.\n events: { type: String, default: \"\" },\n };\n\n static valueConstraints = {\n timeout: NUMBER_BOUNDS.positiveTimer,\n promptBefore: NUMBER_BOUNDS.nonNegative,\n } satisfies NumberValueConstraints<typeof IdleController.values>;\n static override targets = [\"prompt\", \"idle\"];\n static events = [\"prompt\", \"idle\", \"active\"] as const;\n\n declare timeoutValue: number;\n declare promptBeforeValue: number;\n declare eventsValue: string;\n declare readonly promptTargets: HTMLElement[];\n declare readonly idleTargets: HTMLElement[];\n\n /** The regions of the warning window, revealed alongside `data-prompt`. */\n readonly #promptRegions = new StateRegions(\n { whenTrue: () => this.promptTargets },\n this.identifier,\n );\n /** The regions of the elapsed timeout, revealed alongside `data-idle`. */\n readonly #idleRegions = new StateRegions({ whenTrue: () => this.idleTargets }, this.identifier);\n\n readonly #timeouts = new SafeTimeout();\n #idle = false;\n #prompted = false;\n /** Timestamp of the last activity; the timers self-reschedule against it. */\n #lastActivity = 0;\n /** Whether the controller is between `connect()` and `disconnect()`. */\n #connected = false;\n /**\n * The activity listeners on `document`. Releasing them goes through the signal they\n * were registered with, so the removal always matches the registration — capture flag\n * included — whatever `events` says by then.\n */\n readonly #activityListeners = new ListenerSet();\n /** The `visibilitychange` listener, held for the whole connection. */\n readonly #visibilityListeners = new ListenerSet();\n /**\n * Activity types the listeners were last registered for, which a new `events` is\n * compared with.\n */\n #boundEvents: string[] = [];\n\n readonly #onActivity = (): void => {\n // Hot path (fires on every mousemove/scroll/wheel): just record the time. The\n // prompt/idle timers re-check this when they fire and reschedule if needed, so we\n // never tear down and re-create timers on each event (no per-event timer churn).\n this.#lastActivity = Date.now();\n if (this.#idle || this.#prompted) {\n // We were already idle/prompted, so the timers have lapsed — wake and re-arm.\n this.#idle = false;\n this.#prompted = false;\n this.#reflect();\n this.dispatch(\"active\", { detail: {} });\n this.#arm();\n }\n };\n\n readonly #onVisibility = (): void => {\n // Returning to the tab is activity; leaving it keeps the clock running (being\n // away counts toward the timeout).\n if (document.visibilityState === \"visible\") this.#onActivity();\n };\n\n override connect(): void {\n // Connecting always starts a fresh cycle (#arm() re-bases the clock), so the phase\n // that arrived with the DOM — a restored Turbo snapshot, a moved element — describes\n // a period this instance is not in. Reflecting the fresh cycle drops it; leaving it\n // would claim the user is idle for the whole next active window with no `active` to\n // correct it. Normalizing is not a transition, so nothing is dispatched here.\n this.#connected = true;\n this.#idle = false;\n this.#prompted = false;\n this.#reflect();\n this.#bindActivity(parseStringList(this.eventsValue, DEFAULT_ACTIVITY_EVENTS));\n this.#visibilityListeners.add(document, \"visibilitychange\", this.#onVisibility);\n this.#arm();\n }\n\n override disconnect(): void {\n this.#connected = false;\n this.#activityListeners.dispose();\n this.#visibilityListeners.dispose();\n this.#timeouts.clearAll();\n }\n\n /**\n * Swaps the watched activity set for the one a runtime change declares. A declaration\n * that parses to the list already registered changes nothing. Stimulus also calls this\n * ahead of `connect()`, which registers the list itself.\n */\n eventsValueChanged(): void {\n if (!this.#connected) return;\n const types = parseStringList(this.eventsValue, DEFAULT_ACTIVITY_EVENTS);\n if (\n types.length === this.#boundEvents.length &&\n types.every((type, index) => type === this.#boundEvents[index])\n )\n return;\n this.#bindActivity(types);\n }\n\n /**\n * Moves the pending checks to the deadlines a runtime change of `timeout` sets, from the\n * same last activity. Stimulus also calls this ahead of `connect()`, which arms the cycle\n * itself.\n */\n timeoutValueChanged(): void {\n if (this.#connected) this.#schedule();\n }\n\n /**\n * Moves the pending warning to the deadline a runtime change of `promptBefore` sets, from\n * the same last activity. Stimulus also calls this ahead of `connect()`, which arms the\n * cycle itself.\n */\n promptBeforeValueChanged(): void {\n if (this.#connected) this.#schedule();\n }\n\n /** Replaces the registered activity listeners with one passive capture listener per type. */\n #bindActivity(types: string[]): void {\n this.#activityListeners.dispose();\n for (const type of types) {\n this.#activityListeners.add(document, type, this.#onActivity, {\n passive: true,\n capture: true,\n });\n }\n this.#boundEvents = types;\n }\n\n /** Starts a cycle: the activity baseline is now, and the checks are scheduled from it. */\n #arm(): void {\n this.#lastActivity = Date.now();\n this.#schedule();\n }\n\n /**\n * Schedules the pending checks from the last activity and the current declarations,\n * replacing whatever was pending. A deadline already behind the elapsed time is checked\n * at once. The idle check is scheduled first, so when both deadlines have passed it runs\n * first and the warning check finds the cycle over. A warning that comes due at once\n * reports the time left from now rather than the whole window. A raised warning is not\n * scheduled again, and an idle detector schedules nothing.\n *\n * @stimeoRuntimeOnly `timeout` and `promptBefore` time the checks this call schedules.\n */\n #schedule(): void {\n this.#timeouts.clearAll();\n if (this.#idle) return;\n const elapsed = Date.now() - this.#lastActivity;\n const timeout = this.#safeTimeout;\n const prompt = this.#safePromptBefore;\n this.#timeouts.set(() => this.#checkIdle(), this.#delayFor(timeout - elapsed));\n if (this.#prompted || prompt <= 0 || prompt >= timeout) return;\n const left = Math.min(prompt, timeout - elapsed);\n this.#timeouts.set(() => this.#checkPrompt(left), this.#delayFor(timeout - prompt - elapsed));\n }\n\n /** The platform delay for a deadline `remaining` ms away: at once when past, capped when far. */\n #delayFor(remaining: number): number {\n return Math.min(Math.max(remaining, 0), MAX_TIMER_DELAY_MS);\n }\n\n /**\n * Idle-timer callback: go idle only if there has genuinely been no activity for\n * `timeout`; otherwise reschedule for the remaining time. This lets activity events\n * stay O(1) (a timestamp write) while the deadline still tracks the last activity.\n * A clock rewind can put that deadline beyond one platform timer; capped waits\n * recheck the same baseline without advancing the idle transition.\n *\n * @stimeoRuntimeOnly `timeout` sets the deadline this one check compares against; the phase it\n * shows follows the elapsed time.\n */\n #checkIdle(): void {\n const remaining = this.#safeTimeout - (Date.now() - this.#lastActivity);\n if (remaining > 0) {\n this.#timeouts.set(() => this.#checkIdle(), Math.min(remaining, MAX_TIMER_DELAY_MS));\n return;\n }\n this.#idle = true;\n this.#prompted = false;\n this.#reflect();\n this.dispatch(\"idle\", { detail: {} });\n }\n\n /**\n * Prompt-timer callback: warn at `promptBefore` before the idle deadline. A window\n * narrowed while the cycle runs can push the warning onto the deadline or past it,\n * and the phase it belongs to is the one before idle, so a lapsed cycle keeps the\n * phase it reached. The next window opens with the cycle that activity arms.\n * Clock rewinds use capped waits while retaining the same warning deadline.\n *\n * @param left - the time before idle that the warning reports; a check that has to wait\n * again reports the whole window when it comes due.\n * @stimeoRuntimeOnly `timeout` and `promptBefore` set the deadlines this one check compares\n * against; the phase it shows follows the elapsed time.\n */\n #checkPrompt(left = this.#safePromptBefore): void {\n if (this.#idle) return;\n const remaining =\n this.#safeTimeout - this.#safePromptBefore - (Date.now() - this.#lastActivity);\n if (remaining > 0) {\n this.#timeouts.set(() => this.#checkPrompt(), Math.min(remaining, MAX_TIMER_DELAY_MS));\n return;\n }\n this.#prompted = true;\n this.#reflect();\n this.dispatch(\"prompt\", { detail: { remaining: left } });\n }\n\n /** Applies the current phase to a warning region inserted or replaced at runtime. */\n promptTargetConnected(): void {\n this.#promptRegions.reflect(this.element, this.#prompted);\n }\n\n /** Applies the current phase to an idle region inserted or replaced at runtime. */\n idleTargetConnected(): void {\n this.#idleRegions.reflect(this.element, this.#idle);\n }\n\n /**\n * Writes the phase to the element and to the declared regions. Both hooks and both\n * regions are a pure function of the two flags, so every place that moves a flag ends\n * here and the markup can never disagree with the phase the detector is in.\n */\n #reflect(): void {\n const { element } = this;\n if (this.#prompted) element.setAttribute(\"data-prompt\", \"true\");\n else element.removeAttribute(\"data-prompt\");\n if (this.#idle) element.setAttribute(\"data-idle\", \"true\");\n else element.removeAttribute(\"data-idle\");\n this.#promptRegions.reflect(element, this.#prompted);\n this.#idleRegions.reflect(element, this.#idle);\n }\n /** Current `timeout` declaration resolved against its numeric contract. */\n get #safeTimeout(): number {\n return this.#numbers.read(\n this,\n \"timeout\",\n this.timeoutValue,\n IdleController.values.timeout.default,\n IdleController.valueConstraints.timeout,\n );\n }\n\n /** Current `promptBefore` declaration resolved against its numeric contract. */\n get #safePromptBefore(): number {\n return this.#numbers.read(\n this,\n \"promptBefore\",\n this.promptBeforeValue,\n IdleController.values.promptBefore.default,\n IdleController.valueConstraints.promptBefore,\n );\n }\n}\n"]}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Synchronously prepares a new detached form for managed raw-field submission.
|
|
5
|
+
* Registration is idempotent and lasts for this form element in its document;
|
|
6
|
+
* later fields and repeated FormData constructions need no further calls.
|
|
7
|
+
* Connected forms, and forms where `stimeo--input-mask` has synchronized a managed field,
|
|
8
|
+
* are automatic. Call this before constructing FormData for any other detached
|
|
9
|
+
* form, including an existing form that received a managed field only by a DOM
|
|
10
|
+
* move. This observes submission only, without committing edits or releasing
|
|
11
|
+
* raw-field ownership. Discard the form to discard its registration.
|
|
12
|
+
*/
|
|
13
|
+
declare function prepareInputMaskForm(form: HTMLFormElement): void;
|
|
3
14
|
/** The outcome of applying a fixed mask to a raw string. */
|
|
4
15
|
interface MaskResult {
|
|
5
16
|
/** The formatted (masked) string. */
|
|
@@ -36,16 +47,23 @@ declare function applyMask(value: string, pattern: string, tokens: ReadonlyMap<s
|
|
|
36
47
|
* `change` and `reconcile` dispatch `{ masked, unmasked, complete }`.
|
|
37
48
|
*
|
|
38
49
|
* @remarks
|
|
39
|
-
* Behavior only and **idempotent** —
|
|
40
|
-
* the
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* the
|
|
50
|
+
* Behavior only and **idempotent** — a snapshot of the committed derived output
|
|
51
|
+
* repairs the hooks and the maintained sink while the IME owns the field's text.
|
|
52
|
+
* Page-wide registries coordinate the last writer and each sink's form transport
|
|
53
|
+
* identity. `connect()` re-formats the existing value and is stable across Turbo
|
|
54
|
+
* restore/morph. The controller sits on the `<input>` itself (a void element), so
|
|
55
|
+
* the raw-value sink is not a Stimulus target; it is the
|
|
56
|
+
* `[data-stimeo--input-mask-unmask]` field resolved nearest-first among the
|
|
57
|
+
* associated form's own controls (an explicit pairing by the sink attribute's
|
|
45
58
|
* value naming the input's `id` wins; otherwise the closest ancestor's value-less
|
|
46
59
|
* sink) — when one form holds several masked inputs, wrap each input+sink pair in a
|
|
47
60
|
* container or pair them by `id`.
|
|
48
61
|
*
|
|
62
|
+
* A maintained named sink carries a reserved internal DOM name. Native FormData and
|
|
63
|
+
* submission expose its original name and entry position. A removed source contributes
|
|
64
|
+
* an empty raw entry without committing a draft or changing the maintained DOM value.
|
|
65
|
+
* Consumers find the sink by id or pairing attribute rather than its DOM name.
|
|
66
|
+
*
|
|
49
67
|
* Formatting never steals keys: it rejects disallowed characters silently and keeps
|
|
50
68
|
* the caret on insert, Backspace, and range replacement (WCAG 2.2 3.3.2 / 1.3.5;
|
|
51
69
|
* the expected format is the consumer's `aria-describedby`). The caret anchors on
|
|
@@ -65,11 +83,10 @@ declare function applyMask(value: string, pattern: string, tokens: ReadonlyMap<s
|
|
|
65
83
|
* after `pattern` / `tokens` / `unmaskToHidden` changed. A malformed `tokens`
|
|
66
84
|
* declaration falls back to the default tokens, and a single broken source falls
|
|
67
85
|
* back to that key's default: it is parsed once in `tokensValueChanged`, and the
|
|
68
|
-
* hot path only ever sees the validated map. A field
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* `disconnect()`.
|
|
86
|
+
* hot path only ever sees the validated map. A field the user cannot edit
|
|
87
|
+
* (`readonly`, `disabled`, or inside a disabled `<fieldset>`) keeps the value the
|
|
88
|
+
* page authored — the sink and the state hooks still follow it, but the field
|
|
89
|
+
* itself is never rewritten. The composition listener is released on `disconnect()`.
|
|
73
90
|
*/
|
|
74
91
|
declare class InputMaskController extends Controller<HTMLInputElement> {
|
|
75
92
|
#private;
|
|
@@ -95,7 +112,7 @@ declare class InputMaskController extends Controller<HTMLInputElement> {
|
|
|
95
112
|
/** Re-parses the declaration and re-formats under the tokens it now selects. */
|
|
96
113
|
tokensValueChanged(): void;
|
|
97
114
|
patternValueChanged(): void;
|
|
98
|
-
/**
|
|
115
|
+
/** Takes back the raw value it stops maintaining so a submit cannot carry it stale. */
|
|
99
116
|
unmaskToHiddenValueChanged(): void;
|
|
100
117
|
connect(): void;
|
|
101
118
|
disconnect(): void;
|
|
@@ -103,4 +120,4 @@ declare class InputMaskController extends Controller<HTMLInputElement> {
|
|
|
103
120
|
format(event?: Event): void;
|
|
104
121
|
}
|
|
105
122
|
|
|
106
|
-
export { InputMaskController, type MaskResult, applyMask };
|
|
123
|
+
export { InputMaskController, type MaskResult, applyMask, prepareInputMaskForm };
|