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,13 +1,9 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/time_picker_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/logical_scroll.ts
|
|
6
3
|
function isRtl(element) {
|
|
7
4
|
return window.getComputedStyle(element).direction === "rtl";
|
|
8
5
|
}
|
|
9
6
|
|
|
10
|
-
// src/utils/arrow_step.ts
|
|
11
7
|
function logicalArrowKey(key, element) {
|
|
12
8
|
if (key !== "ArrowRight" && key !== "ArrowLeft") return key;
|
|
13
9
|
if (!isRtl(element)) return key;
|
|
@@ -17,8 +13,108 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
17
13
|
if (!event.key.startsWith("Arrow")) return false;
|
|
18
14
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
19
15
|
}
|
|
16
|
+
function hasModifierChord(event) {
|
|
17
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
21
|
+
if (element.getAttribute(name) === value) return false;
|
|
22
|
+
beforeWrite?.();
|
|
23
|
+
if (value === null) element.removeAttribute(name);
|
|
24
|
+
else element.setAttribute(name, value);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var AuthoredMutationWatcher = class {
|
|
29
|
+
#onAuthored;
|
|
30
|
+
#claims = null;
|
|
31
|
+
#observer = null;
|
|
32
|
+
constructor(onAuthored) {
|
|
33
|
+
this.#onAuthored = onAuthored;
|
|
34
|
+
}
|
|
35
|
+
observe(root, options) {
|
|
36
|
+
this.disconnect();
|
|
37
|
+
const observer = new MutationObserver((records) => {
|
|
38
|
+
if (this.#observer !== observer) return;
|
|
39
|
+
const authored = this.#filter(records);
|
|
40
|
+
if (authored.length > 0) this.#onAuthored(authored);
|
|
41
|
+
});
|
|
42
|
+
this.#observer = observer;
|
|
43
|
+
this.#claims = { attributes: /* @__PURE__ */ new Map(), children: /* @__PURE__ */ new Map() };
|
|
44
|
+
observer.observe(root, {
|
|
45
|
+
attributes: true,
|
|
46
|
+
attributeFilter: [...options.attributes],
|
|
47
|
+
subtree: options.subtree ?? false,
|
|
48
|
+
childList: options.childList ?? false
|
|
49
|
+
});
|
|
50
|
+
if (options.ancestorAttributes) {
|
|
51
|
+
let ancestor = root.parentElement;
|
|
52
|
+
while (ancestor) {
|
|
53
|
+
observer.observe(ancestor, {
|
|
54
|
+
attributes: true,
|
|
55
|
+
attributeFilter: [...options.ancestorAttributes]
|
|
56
|
+
});
|
|
57
|
+
ancestor = ancestor.parentElement;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
claim(target, name, value) {
|
|
62
|
+
const claims = this.#claims?.attributes;
|
|
63
|
+
let attributes = claims?.get(target);
|
|
64
|
+
if (!attributes) {
|
|
65
|
+
attributes = /* @__PURE__ */ new Map();
|
|
66
|
+
claims?.set(target, attributes);
|
|
67
|
+
}
|
|
68
|
+
const pending = attributes.get(name);
|
|
69
|
+
attributes.set(name, { value, count: (pending?.count ?? 0) + 1 });
|
|
70
|
+
}
|
|
71
|
+
claimCurrent(target, name) {
|
|
72
|
+
this.claim(target, name, target.getAttribute(name));
|
|
73
|
+
}
|
|
74
|
+
claimChildList(target, added, removed) {
|
|
75
|
+
const claims = this.#claims?.children;
|
|
76
|
+
const pending = claims?.get(target) ?? { added: /* @__PURE__ */ new Map(), removed: /* @__PURE__ */ new Map() };
|
|
77
|
+
for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) + 1);
|
|
78
|
+
for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) + 1);
|
|
79
|
+
claims?.set(target, pending);
|
|
80
|
+
}
|
|
81
|
+
take() {
|
|
82
|
+
return this.#filter(this.#observer?.takeRecords() ?? []);
|
|
83
|
+
}
|
|
84
|
+
disconnect() {
|
|
85
|
+
this.#observer?.disconnect();
|
|
86
|
+
this.#observer = null;
|
|
87
|
+
this.#claims = null;
|
|
88
|
+
}
|
|
89
|
+
#filter(records) {
|
|
90
|
+
const authored = records.filter((record) => !this.#consume(record));
|
|
91
|
+
this.#claims?.attributes.clear();
|
|
92
|
+
this.#claims?.children.clear();
|
|
93
|
+
return authored;
|
|
94
|
+
}
|
|
95
|
+
#consume(record) {
|
|
96
|
+
if (record.type === "attributes") {
|
|
97
|
+
const target = record.target;
|
|
98
|
+
const pending2 = this.#claims?.attributes.get(target)?.get(record.attributeName);
|
|
99
|
+
if (!pending2 || pending2.count === 0 || target.getAttribute(record.attributeName) !== pending2.value) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
pending2.count -= 1;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const pending = this.#claims?.children.get(record.target);
|
|
106
|
+
if (!pending) return false;
|
|
107
|
+
const added = [...record.addedNodes];
|
|
108
|
+
const removed = [...record.removedNodes];
|
|
109
|
+
if (added.some((node) => !pending.added.get(node)) || removed.some((node) => !pending.removed.get(node))) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) - 1);
|
|
113
|
+
for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) - 1);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
20
117
|
|
|
21
|
-
// src/utils/field_mirror.ts
|
|
22
118
|
function writeField(field, value) {
|
|
23
119
|
if (field.value === value) return false;
|
|
24
120
|
field.value = value;
|
|
@@ -28,27 +124,36 @@ function commitField(target) {
|
|
|
28
124
|
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
29
125
|
}
|
|
30
126
|
|
|
31
|
-
|
|
127
|
+
var ListenerSet = class {
|
|
128
|
+
#abort = new AbortController();
|
|
129
|
+
add(target, type, handler, options) {
|
|
130
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
131
|
+
}
|
|
132
|
+
dispose() {
|
|
133
|
+
this.#abort.abort();
|
|
134
|
+
this.#abort = new AbortController();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
32
138
|
var MicrotaskCoalescer = class {
|
|
33
139
|
#run;
|
|
34
140
|
#queued = false;
|
|
35
141
|
#active = false;
|
|
36
142
|
#generation = 0;
|
|
37
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
38
143
|
constructor(run) {
|
|
39
144
|
this.#run = run;
|
|
40
145
|
}
|
|
41
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
42
146
|
activate() {
|
|
43
147
|
this.#active = true;
|
|
44
148
|
}
|
|
45
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
46
149
|
cancel() {
|
|
47
150
|
this.#active = false;
|
|
48
151
|
this.#queued = false;
|
|
49
152
|
this.#generation += 1;
|
|
50
153
|
}
|
|
51
|
-
|
|
154
|
+
get pending() {
|
|
155
|
+
return this.#queued;
|
|
156
|
+
}
|
|
52
157
|
schedule() {
|
|
53
158
|
if (!this.#active || this.#queued) return;
|
|
54
159
|
this.#queued = true;
|
|
@@ -61,93 +166,183 @@ var MicrotaskCoalescer = class {
|
|
|
61
166
|
}
|
|
62
167
|
};
|
|
63
168
|
|
|
64
|
-
|
|
169
|
+
var MorphRenderWatcher = class {
|
|
170
|
+
#listeners = new ListenerSet();
|
|
171
|
+
#pass;
|
|
172
|
+
#element = null;
|
|
173
|
+
#onMorph = () => this.#pass.schedule();
|
|
174
|
+
constructor(run) {
|
|
175
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
176
|
+
}
|
|
177
|
+
observe(element) {
|
|
178
|
+
if (this.#element === element) return;
|
|
179
|
+
this.disconnect();
|
|
180
|
+
this.#element = element;
|
|
181
|
+
this.#pass.activate();
|
|
182
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
183
|
+
}
|
|
184
|
+
schedule() {
|
|
185
|
+
this.#pass.schedule();
|
|
186
|
+
}
|
|
187
|
+
get pending() {
|
|
188
|
+
return this.#pass.pending;
|
|
189
|
+
}
|
|
190
|
+
disconnect() {
|
|
191
|
+
this.#listeners.dispose();
|
|
192
|
+
this.#pass.cancel();
|
|
193
|
+
this.#element = null;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
var MoveCounter = class {
|
|
198
|
+
#sequence = 0;
|
|
199
|
+
record() {
|
|
200
|
+
this.#sequence += 1;
|
|
201
|
+
return this.#sequence;
|
|
202
|
+
}
|
|
203
|
+
isLatest(token) {
|
|
204
|
+
return token === this.#sequence;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
var NUMBER_BOUNDS = {
|
|
209
|
+
positive: { finite: true, exclusiveMin: 0 }};
|
|
210
|
+
function matchesNumberBounds(value, bounds) {
|
|
211
|
+
if (!Number.isFinite(value)) {
|
|
212
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
213
|
+
if (direction === null) return false;
|
|
214
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
215
|
+
}
|
|
216
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
217
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
218
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
219
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
220
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function readNumber(raw, fallback, bounds) {
|
|
225
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
var NumberValueReader = class {
|
|
229
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
230
|
+
read(owner, name, raw, fallback, bounds) {
|
|
231
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
232
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
233
|
+
this.#lastRejected.delete(name);
|
|
234
|
+
return resolved;
|
|
235
|
+
}
|
|
236
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
237
|
+
const literal = owner.element.getAttribute(attribute);
|
|
238
|
+
if (literal === null) {
|
|
239
|
+
this.#lastRejected.delete(name);
|
|
240
|
+
return resolved;
|
|
241
|
+
}
|
|
242
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
243
|
+
this.#lastRejected.set(name, literal);
|
|
244
|
+
console.warn(
|
|
245
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return resolved;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
65
252
|
function targetSelector(identifier, name) {
|
|
66
253
|
return `[data-${identifier}-target~="${name}"]`;
|
|
67
254
|
}
|
|
68
255
|
|
|
69
|
-
// src/controllers/time_picker_controller.ts
|
|
70
256
|
var AM = 0;
|
|
71
257
|
var PM = 1;
|
|
72
258
|
var SECONDS_PER_MINUTE = 60;
|
|
73
259
|
var SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
|
|
74
260
|
var SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
|
|
75
|
-
var
|
|
76
|
-
|
|
261
|
+
var TimePickerController = class _TimePickerController extends Controller {
|
|
262
|
+
#numbers = new NumberValueReader();
|
|
263
|
+
#moves = new MoveCounter();
|
|
264
|
+
#connectionGeneration = 0;
|
|
265
|
+
#move = 0;
|
|
77
266
|
static targets = ["segment", "field"];
|
|
78
267
|
static values = {
|
|
79
268
|
hourCycle: { type: Number, default: 24 },
|
|
269
|
+
hour12ZeroBased: { type: Boolean, default: false },
|
|
80
270
|
step: { type: Number, default: 1 },
|
|
81
271
|
seconds: { type: Boolean, default: false },
|
|
82
|
-
wrap: { type: Boolean, default: true }
|
|
272
|
+
wrap: { type: Boolean, default: true },
|
|
273
|
+
amLabel: { type: String, default: "AM" },
|
|
274
|
+
pmLabel: { type: String, default: "PM" }
|
|
275
|
+
};
|
|
276
|
+
static valueConstraints = {
|
|
277
|
+
hourCycle: { finite: true, allowedValues: [12, 24] },
|
|
278
|
+
step: NUMBER_BOUNDS.positive
|
|
83
279
|
};
|
|
84
280
|
static actions = ["onKeydown"];
|
|
85
281
|
static events = ["change", "reconcile"];
|
|
86
|
-
|
|
87
|
-
* Collapses target, Value, and retained-attribute morphs into one render that
|
|
88
|
-
* dispatches no `change`.
|
|
89
|
-
*/
|
|
90
|
-
#reconcile = new MicrotaskCoalescer(() => this.#reconcileDom());
|
|
91
|
-
/** Canonical state; the displayed hour and meridiem are derived from this value. */
|
|
282
|
+
#reconcile = new MorphRenderWatcher(() => this.#reconcileDom());
|
|
92
283
|
#state = { hour: 0, minute: 0, second: 0 };
|
|
93
|
-
/** Direct-entry digit buffer and the segment it belongs to. */
|
|
94
284
|
#typeBuffer = "";
|
|
95
285
|
#typeSegment = null;
|
|
96
|
-
/** Last composed value, used to suppress duplicate user notifications. */
|
|
97
286
|
#lastValue = "";
|
|
98
|
-
#
|
|
99
|
-
#
|
|
287
|
+
#renderedHourMode = null;
|
|
288
|
+
#renderedSegments = /* @__PURE__ */ new WeakSet();
|
|
289
|
+
#authoredSegments = /* @__PURE__ */ new Set();
|
|
290
|
+
#observer = new AuthoredMutationWatcher((records) => {
|
|
291
|
+
if (!this.#recordAuthoredSegments(records)) return;
|
|
292
|
+
this.#reconcile.schedule();
|
|
293
|
+
});
|
|
100
294
|
#domDirty = false;
|
|
101
|
-
|
|
295
|
+
#listeners = new ListenerSet();
|
|
102
296
|
connect() {
|
|
103
|
-
this.#
|
|
104
|
-
this.#
|
|
105
|
-
this.element.addEventListener("focusout", this.#onFocusOut);
|
|
297
|
+
this.#reconcile.observe(this.element);
|
|
298
|
+
this.#listeners.add(this.element, "focusout", this.#onFocusOut);
|
|
106
299
|
this.#domDirty = false;
|
|
107
300
|
this.#adoptDomState();
|
|
108
301
|
this.#render();
|
|
109
302
|
this.#observeMutations();
|
|
110
303
|
}
|
|
111
|
-
/** Releases the observer, listener, queued reconciliation, and transient input state. */
|
|
112
304
|
disconnect() {
|
|
113
|
-
this.#
|
|
114
|
-
this.#reconcile.
|
|
115
|
-
this.
|
|
116
|
-
this.#observer
|
|
117
|
-
this.#observer = null;
|
|
305
|
+
this.#connectionGeneration += 1;
|
|
306
|
+
this.#reconcile.disconnect();
|
|
307
|
+
this.#listeners.dispose();
|
|
308
|
+
this.#observer.disconnect();
|
|
118
309
|
this.#domDirty = false;
|
|
310
|
+
this.#renderedHourMode = null;
|
|
311
|
+
this.#renderedSegments = /* @__PURE__ */ new WeakSet();
|
|
312
|
+
this.#authoredSegments.clear();
|
|
119
313
|
this.#clearTypeBuffer();
|
|
120
314
|
this.#lastValue = "";
|
|
121
315
|
}
|
|
122
|
-
/** Re-renders the canonical instant when 12/24-hour presentation changes at runtime. */
|
|
123
316
|
hourCycleValueChanged() {
|
|
124
317
|
this.#reconcile.schedule();
|
|
125
318
|
}
|
|
126
|
-
|
|
319
|
+
hour12ZeroBasedValueChanged() {
|
|
320
|
+
this.#reconcile.schedule();
|
|
321
|
+
}
|
|
127
322
|
secondsValueChanged() {
|
|
128
323
|
this.#reconcile.schedule();
|
|
129
324
|
}
|
|
130
|
-
|
|
325
|
+
amLabelValueChanged() {
|
|
326
|
+
this.#reconcile.schedule();
|
|
327
|
+
}
|
|
328
|
+
pmLabelValueChanged() {
|
|
329
|
+
this.#reconcile.schedule();
|
|
330
|
+
}
|
|
131
331
|
segmentTargetConnected() {
|
|
132
332
|
this.#domDirty = true;
|
|
133
|
-
this.#clearTypeBuffer();
|
|
134
333
|
this.#reconcile.schedule();
|
|
135
334
|
}
|
|
136
|
-
|
|
137
|
-
|
|
335
|
+
segmentTargetDisconnected(segment) {
|
|
336
|
+
if (segment && !this.segmentTargets.includes(segment)) this.#renderedSegments.delete(segment);
|
|
138
337
|
this.#domDirty = true;
|
|
139
|
-
this.#clearTypeBuffer();
|
|
140
338
|
this.#reconcile.schedule();
|
|
141
339
|
}
|
|
142
|
-
/** Reflects the current composed value into a field added or replaced at runtime. */
|
|
143
340
|
fieldTargetConnected() {
|
|
144
341
|
this.#reconcile.schedule();
|
|
145
342
|
}
|
|
146
|
-
/** Reconciles silently when the optional field leaves at runtime. */
|
|
147
343
|
fieldTargetDisconnected() {
|
|
148
344
|
this.#reconcile.schedule();
|
|
149
345
|
}
|
|
150
|
-
/** Handles APG stepping, inter-segment focus moves, jumps, and direct entry. */
|
|
151
346
|
onKeydown(event) {
|
|
152
347
|
if (isReservedArrowChord(event)) return;
|
|
153
348
|
const segment = event.target?.closest(
|
|
@@ -157,7 +352,9 @@ var TimePickerController = class extends Controller {
|
|
|
157
352
|
const kind = this.#kindOf(segment);
|
|
158
353
|
if (!kind) return;
|
|
159
354
|
const key = logicalArrowKey(event.key, this.element);
|
|
160
|
-
if ((key === "Home" || key === "End") &&
|
|
355
|
+
if ((key === "Home" || key === "End") && hasModifierChord(event)) return;
|
|
356
|
+
if (this.#adoptPendingDom()) this.#reconcile.schedule();
|
|
357
|
+
if (this.#renderedHourMode !== this.#hourMode) this.#clearTypeBuffer();
|
|
161
358
|
switch (key) {
|
|
162
359
|
case "ArrowUp":
|
|
163
360
|
event.preventDefault();
|
|
@@ -186,7 +383,7 @@ var TimePickerController = class extends Controller {
|
|
|
186
383
|
this.#commitRender();
|
|
187
384
|
break;
|
|
188
385
|
default:
|
|
189
|
-
if (kind !== "meridiem" && /^[0-9]$/.test(event.key) && !
|
|
386
|
+
if (kind !== "meridiem" && /^[0-9]$/.test(event.key) && !event.ctrlKey && !event.altKey && !event.metaKey) {
|
|
190
387
|
event.preventDefault();
|
|
191
388
|
this.#typeDigit(segment, kind, event.key);
|
|
192
389
|
return;
|
|
@@ -195,7 +392,6 @@ var TimePickerController = class extends Controller {
|
|
|
195
392
|
}
|
|
196
393
|
this.#clearTypeBuffer();
|
|
197
394
|
}
|
|
198
|
-
/** Clears direct-entry state when Tab, Shift+Tab, or pointer focus leaves a segment. */
|
|
199
395
|
#onFocusOut = (event) => {
|
|
200
396
|
const segment = event.target?.closest(
|
|
201
397
|
targetSelector(this.identifier, "segment")
|
|
@@ -203,13 +399,11 @@ var TimePickerController = class extends Controller {
|
|
|
203
399
|
if (!segment || !this.segmentTargets.includes(segment)) return;
|
|
204
400
|
this.#clearTypeBuffer();
|
|
205
401
|
};
|
|
206
|
-
/** Uses the normalized positive-integer minute step; other segments step by one. */
|
|
207
402
|
#delta(kind) {
|
|
208
403
|
if (kind !== "minute") return 1;
|
|
209
|
-
const step = Math.trunc(this
|
|
210
|
-
return
|
|
404
|
+
const step = Math.trunc(this.#safeStep);
|
|
405
|
+
return step > 0 ? step : 1;
|
|
211
406
|
}
|
|
212
|
-
/** Mutates one complete action and then renders/notifies its final value once. */
|
|
213
407
|
#step(kind, delta) {
|
|
214
408
|
if (kind === "meridiem" && this.wrapValue) {
|
|
215
409
|
this.#state.hour = modulo(this.#state.hour + 12, 24);
|
|
@@ -225,7 +419,6 @@ var TimePickerController = class extends Controller {
|
|
|
225
419
|
}
|
|
226
420
|
this.#commitRender();
|
|
227
421
|
}
|
|
228
|
-
/** Accumulates a typed digit, rendering once and advancing after completion. */
|
|
229
422
|
#typeDigit(segment, kind, digit) {
|
|
230
423
|
if (this.#typeSegment !== kind) this.#typeBuffer = "";
|
|
231
424
|
this.#typeSegment = kind;
|
|
@@ -233,34 +426,46 @@ var TimePickerController = class extends Controller {
|
|
|
233
426
|
const candidate = Number(`${this.#typeBuffer}${digit}`);
|
|
234
427
|
this.#typeBuffer = candidate <= max ? `${this.#typeBuffer}${digit}` : digit;
|
|
235
428
|
this.#setDisplayed(kind, Number(this.#typeBuffer));
|
|
236
|
-
this.#commitRender();
|
|
429
|
+
this.#commitRender(true);
|
|
237
430
|
if (this.#typeBuffer.length >= 2 || Number(this.#typeBuffer) * 10 > max) {
|
|
238
431
|
this.#clearTypeBuffer();
|
|
239
432
|
this.#focusSibling(segment, 1);
|
|
240
433
|
}
|
|
241
434
|
}
|
|
242
|
-
/** Moves focus to the previous/next valid segment, if one exists. */
|
|
243
435
|
#focusSibling(segment, direction) {
|
|
244
436
|
const segments = this.segmentTargets.filter((candidate) => this.#kindOf(candidate) !== null);
|
|
245
437
|
const index = segments.indexOf(segment);
|
|
246
438
|
segments[index + direction]?.focus();
|
|
247
439
|
}
|
|
248
|
-
/** Clears the direct-entry buffer and its owning segment together. */
|
|
249
440
|
#clearTypeBuffer() {
|
|
250
441
|
this.#typeBuffer = "";
|
|
251
442
|
this.#typeSegment = null;
|
|
252
443
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (this.#domDirty)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
444
|
+
#adoptPendingDom() {
|
|
445
|
+
this.#recordAuthoredSegments(this.#observer.take());
|
|
446
|
+
if (!this.#domDirty) return false;
|
|
447
|
+
this.#domDirty = false;
|
|
448
|
+
this.#clearTypeBuffer();
|
|
449
|
+
this.#adoptDomState();
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
#recordAuthoredSegments(records) {
|
|
453
|
+
let changed = false;
|
|
454
|
+
for (const { target } of records) {
|
|
455
|
+
if (!(target instanceof HTMLElement) || !this.segmentTargets.includes(target)) continue;
|
|
456
|
+
this.#authoredSegments.add(target);
|
|
457
|
+
changed = true;
|
|
259
458
|
}
|
|
459
|
+
if (changed) this.#domDirty = true;
|
|
460
|
+
return changed;
|
|
461
|
+
}
|
|
462
|
+
#reconcileDom() {
|
|
463
|
+
this.#adoptPendingDom();
|
|
260
464
|
this.#render();
|
|
261
465
|
}
|
|
262
|
-
/** Rebuilds canonical state from the targets; an absent hour represents midnight. */
|
|
263
466
|
#adoptDomState() {
|
|
467
|
+
const mode = this.#hourMode;
|
|
468
|
+
const presentationChanged = this.#renderedHourMode !== null && this.#renderedHourMode !== mode;
|
|
264
469
|
let displayedHour = 0;
|
|
265
470
|
let meridiem = AM;
|
|
266
471
|
let minute = 0;
|
|
@@ -268,58 +473,56 @@ var TimePickerController = class extends Controller {
|
|
|
268
473
|
for (const segment of this.segmentTargets) {
|
|
269
474
|
const kind = this.#kindOf(segment);
|
|
270
475
|
if (!kind) continue;
|
|
271
|
-
const
|
|
476
|
+
const retained = presentationChanged && this.#renderedSegments.has(segment) && !this.#authoredSegments.has(segment);
|
|
477
|
+
let value;
|
|
478
|
+
if (retained && kind === "hour") {
|
|
479
|
+
value = mode === "h23" ? this.#state.hour : this.#state.hour % 12;
|
|
480
|
+
} else if (retained && kind === "meridiem") {
|
|
481
|
+
value = this.#state.hour >= 12 ? PM : AM;
|
|
482
|
+
} else {
|
|
483
|
+
value = this.#authoredValue(segment, kind);
|
|
484
|
+
}
|
|
272
485
|
if (kind === "hour") displayedHour = value;
|
|
273
486
|
else if (kind === "minute") minute = value;
|
|
274
487
|
else if (kind === "second") second = value;
|
|
275
488
|
else meridiem = value;
|
|
276
489
|
}
|
|
277
490
|
this.#state = {
|
|
278
|
-
hour: this
|
|
491
|
+
hour: this.#safeHourCycle === 12 ? displayedHour % 12 + (meridiem === PM ? 12 : 0) : displayedHour,
|
|
279
492
|
minute,
|
|
280
493
|
second
|
|
281
494
|
};
|
|
495
|
+
this.#authoredSegments.clear();
|
|
282
496
|
}
|
|
283
|
-
/** Reads and integer-clamps one authored `aria-valuenow`. */
|
|
284
497
|
#authoredValue(segment, kind) {
|
|
285
498
|
const raw = Number(segment.getAttribute("aria-valuenow"));
|
|
286
499
|
const { min, max } = this.#bounds(kind);
|
|
287
500
|
if (!Number.isFinite(raw)) return min;
|
|
288
501
|
return Math.min(max, Math.max(min, Math.trunc(raw)));
|
|
289
502
|
}
|
|
290
|
-
/** Writes a displayed segment value back into canonical state without rendering. */
|
|
291
503
|
#setDisplayed(kind, raw) {
|
|
292
504
|
const { min, max } = this.#bounds(kind);
|
|
293
505
|
const value = Math.min(max, Math.max(min, Math.trunc(raw)));
|
|
294
506
|
if (kind === "hour") {
|
|
295
|
-
this.#state.hour = this
|
|
507
|
+
this.#state.hour = this.#safeHourCycle === 12 ? value % 12 + (this.#state.hour >= 12 ? 12 : 0) : value;
|
|
296
508
|
} else if (kind === "minute" || kind === "second") {
|
|
297
509
|
this.#state[kind] = value;
|
|
298
510
|
} else {
|
|
299
511
|
this.#state.hour = this.#state.hour % 12 + (value === PM ? 12 : 0);
|
|
300
512
|
}
|
|
301
513
|
}
|
|
302
|
-
/** Converts seconds with day wrapping into the canonical three-unit state. */
|
|
303
514
|
#setFromSeconds(raw) {
|
|
304
515
|
const seconds = modulo(raw, SECONDS_PER_DAY);
|
|
305
516
|
this.#state.hour = Math.floor(seconds / SECONDS_PER_HOUR);
|
|
306
517
|
this.#state.minute = Math.floor(seconds % SECONDS_PER_HOUR / SECONDS_PER_MINUTE);
|
|
307
518
|
this.#state.second = seconds % SECONDS_PER_MINUTE;
|
|
308
519
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
this.#
|
|
312
|
-
|
|
313
|
-
|
|
520
|
+
#renderSegments(preserveTypeBuffer = false) {
|
|
521
|
+
const mode = this.#hourMode;
|
|
522
|
+
if (this.#renderedHourMode !== mode && !preserveTypeBuffer) this.#clearTypeBuffer();
|
|
523
|
+
this.#renderedHourMode = mode;
|
|
524
|
+
for (const segment of this.segmentTargets) this.#renderSegment(segment);
|
|
314
525
|
}
|
|
315
|
-
/**
|
|
316
|
-
* Reflects canonical state during connection or DOM reconciliation.
|
|
317
|
-
*
|
|
318
|
-
* No user edit reaches here, so `change` never fires from this path. A pass
|
|
319
|
-
* that moves the committed value reports `reconcile` instead.
|
|
320
|
-
*
|
|
321
|
-
* @stimeoRenderRoot
|
|
322
|
-
*/
|
|
323
526
|
#render() {
|
|
324
527
|
this.#renderSegments();
|
|
325
528
|
const value = this.#composedValue;
|
|
@@ -327,53 +530,61 @@ var TimePickerController = class extends Controller {
|
|
|
327
530
|
this.#writeField(value);
|
|
328
531
|
this.#lastValue = value;
|
|
329
532
|
if (previous !== "" && value !== previous) {
|
|
533
|
+
this.#move = this.#moves.record();
|
|
330
534
|
this.dispatch("reconcile", { detail: { value } });
|
|
331
535
|
}
|
|
332
536
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
this.#renderSegments();
|
|
537
|
+
#commitRender(preserveTypeBuffer = false) {
|
|
538
|
+
const generation = this.#connectionGeneration;
|
|
539
|
+
this.#renderSegments(preserveTypeBuffer);
|
|
336
540
|
const value = this.#composedValue;
|
|
337
|
-
|
|
338
|
-
if (value !== this.#lastValue) this.dispatch("change", { detail: { value } });
|
|
541
|
+
const changed = value !== this.#lastValue;
|
|
339
542
|
this.#lastValue = value;
|
|
543
|
+
if (changed) this.#move = this.#moves.record();
|
|
544
|
+
const move = this.#move;
|
|
545
|
+
if (this.#writeField(value)) commitField(this.fieldTarget);
|
|
546
|
+
if (generation !== this.#connectionGeneration || !this.#moves.isLatest(move)) return;
|
|
547
|
+
if (changed) this.dispatch("change", { detail: { value } });
|
|
340
548
|
}
|
|
341
|
-
/** Reflects one segment's value and controller-owned ARIA bounds/text. */
|
|
342
549
|
#renderSegment(segment) {
|
|
343
550
|
const kind = this.#kindOf(segment);
|
|
344
551
|
if (!kind) return;
|
|
552
|
+
this.#renderedSegments.add(segment);
|
|
345
553
|
const value = this.#displayValue(kind);
|
|
346
|
-
const text = kind === "meridiem" ? value === PM ?
|
|
554
|
+
const text = kind === "meridiem" ? value === PM ? this.pmLabelValue : this.amLabelValue : pad(value);
|
|
347
555
|
const { min, max } = this.#bounds(kind);
|
|
348
|
-
|
|
556
|
+
const serialized = String(value);
|
|
557
|
+
setAttributeIfChanged(segment, "aria-valuenow", serialized, () => {
|
|
558
|
+
this.#observer.claim(segment, "aria-valuenow", serialized);
|
|
559
|
+
});
|
|
349
560
|
segment.setAttribute("aria-valuetext", text);
|
|
350
561
|
segment.setAttribute("aria-valuemin", String(min));
|
|
351
562
|
segment.setAttribute("aria-valuemax", String(max));
|
|
352
563
|
segment.textContent = text;
|
|
353
564
|
}
|
|
354
|
-
/** Writes a composed value to the optional form field and reports whether it changed. */
|
|
355
565
|
#writeField(value) {
|
|
356
566
|
return this.hasFieldTarget && writeField(this.fieldTarget, value);
|
|
357
567
|
}
|
|
358
|
-
/** The canonical form value composed as `HH:MM[:SS]`. */
|
|
359
568
|
get #composedValue() {
|
|
360
569
|
const parts = [pad(this.#state.hour), pad(this.#state.minute)];
|
|
361
570
|
if (this.secondsValue) parts.push(pad(this.#state.second));
|
|
362
571
|
return parts.join(":");
|
|
363
572
|
}
|
|
364
|
-
/** Returns a canonical unit in the presentation form exposed by its segment. */
|
|
365
573
|
#displayValue(kind) {
|
|
366
574
|
if (kind === "hour") {
|
|
367
|
-
|
|
575
|
+
const mode = this.#hourMode;
|
|
576
|
+
if (mode === "h23") return this.#state.hour;
|
|
577
|
+
const hour = this.#state.hour % 12;
|
|
578
|
+
return mode === "h11" ? hour : hour || 12;
|
|
368
579
|
}
|
|
369
580
|
if (kind === "meridiem") return this.#state.hour >= 12 ? PM : AM;
|
|
370
581
|
return this.#state[kind];
|
|
371
582
|
}
|
|
372
|
-
/** The inclusive controller-owned bounds for a segment kind. */
|
|
373
583
|
#bounds(kind) {
|
|
374
584
|
switch (kind) {
|
|
375
585
|
case "hour":
|
|
376
|
-
|
|
586
|
+
if (this.#hourMode === "h23") return { min: 0, max: 23 };
|
|
587
|
+
return this.#hourMode === "h11" ? { min: 0, max: 11 } : { min: 1, max: 12 };
|
|
377
588
|
case "minute":
|
|
378
589
|
case "second":
|
|
379
590
|
return { min: 0, max: 59 };
|
|
@@ -381,39 +592,12 @@ var TimePickerController = class extends Controller {
|
|
|
381
592
|
return { min: AM, max: PM };
|
|
382
593
|
}
|
|
383
594
|
}
|
|
384
|
-
/** Watches retained segment state while excluding this controller's own reflections. */
|
|
385
595
|
#observeMutations() {
|
|
386
|
-
|
|
387
|
-
const changed = records.some(
|
|
388
|
-
({ target }) => target instanceof HTMLElement && this.segmentTargets.includes(target)
|
|
389
|
-
);
|
|
390
|
-
if (!changed) return;
|
|
391
|
-
this.#domDirty = true;
|
|
392
|
-
this.#clearTypeBuffer();
|
|
393
|
-
this.#reconcile.schedule();
|
|
394
|
-
});
|
|
395
|
-
this.#observer = observer;
|
|
396
|
-
this.#observeWith(observer);
|
|
397
|
-
}
|
|
398
|
-
/** Registers retained attribute observation on the controller subtree. */
|
|
399
|
-
#observeWith(observer) {
|
|
400
|
-
observer.observe(this.element, {
|
|
596
|
+
this.#observer.observe(this.element, {
|
|
401
597
|
subtree: true,
|
|
402
|
-
attributes:
|
|
403
|
-
attributeFilter: ["aria-valuenow", "data-segment"]
|
|
598
|
+
attributes: ["aria-valuenow", "data-segment"]
|
|
404
599
|
});
|
|
405
600
|
}
|
|
406
|
-
/** Temporarily pauses observation so derived ARIA writes cannot become DOM input. */
|
|
407
|
-
#withoutObservation(run) {
|
|
408
|
-
const observer = this.#observer;
|
|
409
|
-
observer?.disconnect();
|
|
410
|
-
try {
|
|
411
|
-
run();
|
|
412
|
-
} finally {
|
|
413
|
-
if (observer && this.#connected) this.#observeWith(observer);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
/** Reads a segment's declared kind, or null when absent/invalid. */
|
|
417
601
|
#kindOf(segment) {
|
|
418
602
|
const kind = segment.getAttribute("data-segment");
|
|
419
603
|
if (kind === "hour" || kind === "minute" || kind === "second" || kind === "meridiem") {
|
|
@@ -421,10 +605,31 @@ var TimePickerController = class extends Controller {
|
|
|
421
605
|
}
|
|
422
606
|
return null;
|
|
423
607
|
}
|
|
424
|
-
/** Canonical state as seconds since the start of its nominal day. */
|
|
425
608
|
get #secondsOfDay() {
|
|
426
609
|
return this.#state.hour * SECONDS_PER_HOUR + this.#state.minute * SECONDS_PER_MINUTE + this.#state.second;
|
|
427
610
|
}
|
|
611
|
+
get #hourMode() {
|
|
612
|
+
if (this.#safeHourCycle !== 12) return "h23";
|
|
613
|
+
return this.hour12ZeroBasedValue ? "h11" : "h12";
|
|
614
|
+
}
|
|
615
|
+
get #safeHourCycle() {
|
|
616
|
+
return this.#numbers.read(
|
|
617
|
+
this,
|
|
618
|
+
"hourCycle",
|
|
619
|
+
this.hourCycleValue,
|
|
620
|
+
_TimePickerController.values.hourCycle.default,
|
|
621
|
+
_TimePickerController.valueConstraints.hourCycle
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
get #safeStep() {
|
|
625
|
+
return this.#numbers.read(
|
|
626
|
+
this,
|
|
627
|
+
"step",
|
|
628
|
+
this.stepValue,
|
|
629
|
+
_TimePickerController.values.step.default,
|
|
630
|
+
_TimePickerController.valueConstraints.step
|
|
631
|
+
);
|
|
632
|
+
}
|
|
428
633
|
};
|
|
429
634
|
function modulo(value, modulus) {
|
|
430
635
|
return (value % modulus + modulus) % modulus;
|
|
@@ -434,5 +639,4 @@ function pad(value) {
|
|
|
434
639
|
}
|
|
435
640
|
|
|
436
641
|
export { TimePickerController };
|
|
437
|
-
//# sourceMappingURL=time_picker_controller.js.map
|
|
438
642
|
//# sourceMappingURL=time_picker_controller.js.map
|