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,53 +1,201 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
|
|
4
|
+
var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
|
|
5
|
+
function stateReasonFor(event) {
|
|
6
|
+
if (!event) return "api";
|
|
7
|
+
if (FOCUS_EVENTS.has(event.type)) return "focus";
|
|
8
|
+
if (POINTER_EVENTS.has(event.type)) return "pointer";
|
|
9
|
+
return "user";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function actionSource(source) {
|
|
13
|
+
if (source instanceof HTMLElement) {
|
|
14
|
+
return { event: null, host: source, origin: source, reason: "api" };
|
|
15
|
+
}
|
|
16
|
+
const event = source ?? null;
|
|
17
|
+
return {
|
|
18
|
+
event,
|
|
19
|
+
host: event?.currentTarget instanceof Element ? event.currentTarget : null,
|
|
20
|
+
origin: event?.target instanceof Element ? event.target : null,
|
|
21
|
+
reason: stateReasonFor(event)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
4
24
|
|
|
5
|
-
// src/utils/logical_scroll.ts
|
|
6
25
|
function isRtl(element) {
|
|
7
26
|
return window.getComputedStyle(element).direction === "rtl";
|
|
8
27
|
}
|
|
9
28
|
|
|
10
|
-
// src/utils/arrow_step.ts
|
|
11
29
|
function logicalArrowKey(key, element) {
|
|
12
30
|
if (key !== "ArrowRight" && key !== "ArrowLeft") return key;
|
|
13
31
|
if (!isRtl(element)) return key;
|
|
14
32
|
return key === "ArrowRight" ? "ArrowLeft" : "ArrowRight";
|
|
15
33
|
}
|
|
34
|
+
function gridDirectionElement(grid, root) {
|
|
35
|
+
const table = grid.closest("table");
|
|
36
|
+
return table !== null && root.contains(table) ? table : grid;
|
|
37
|
+
}
|
|
16
38
|
function isReservedArrowChord(event, allow = []) {
|
|
17
39
|
if (!event.key.startsWith("Arrow")) return false;
|
|
18
40
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
19
41
|
}
|
|
42
|
+
function hasModifierChord(event) {
|
|
43
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
44
|
+
}
|
|
20
45
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
47
|
+
if (element.getAttribute(name) === value) return false;
|
|
48
|
+
if (value === null) element.removeAttribute(name);
|
|
49
|
+
else element.setAttribute(name, value);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function sharedRegistry(key, create) {
|
|
54
|
+
const symbol = Symbol.for(key);
|
|
55
|
+
const scope = globalThis;
|
|
56
|
+
const existing = scope[symbol];
|
|
57
|
+
if (existing !== void 0) return existing;
|
|
58
|
+
const registry2 = create();
|
|
59
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
60
|
+
return registry2;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
var registry = sharedRegistry(
|
|
64
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
65
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
66
|
+
);
|
|
67
|
+
function isAttributeValue(value) {
|
|
68
|
+
return value === null || typeof value === "string";
|
|
69
|
+
}
|
|
70
|
+
function readLeaseRecord(element, record) {
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
73
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
74
|
+
const [original, written, ...rest] = parsed;
|
|
75
|
+
const linked = rest[0] !== false;
|
|
76
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
77
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
78
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
79
|
+
} catch {
|
|
80
|
+
return void 0;
|
|
33
81
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
82
|
+
}
|
|
83
|
+
function attributeStack(element, attribute) {
|
|
84
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
85
|
+
registry.stacks.set(element, byAttribute);
|
|
86
|
+
const known = byAttribute.get(attribute);
|
|
87
|
+
if (known) return known;
|
|
88
|
+
const found = [];
|
|
89
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
90
|
+
const read = readLeaseRecord(element, record);
|
|
91
|
+
if (read) found.push({ ...read, record });
|
|
92
|
+
}
|
|
93
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
94
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
95
|
+
lease: null,
|
|
96
|
+
record,
|
|
97
|
+
written,
|
|
98
|
+
original,
|
|
99
|
+
linked: linked && index > 0
|
|
100
|
+
}));
|
|
101
|
+
byAttribute.set(attribute, stack);
|
|
102
|
+
return stack;
|
|
103
|
+
}
|
|
104
|
+
function findHold(stack, lease, record) {
|
|
105
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
106
|
+
}
|
|
107
|
+
var AttributeLease = class {
|
|
108
|
+
#attribute;
|
|
109
|
+
#record;
|
|
110
|
+
#base;
|
|
111
|
+
#preserveAuthor;
|
|
112
|
+
#held = /* @__PURE__ */ new Set();
|
|
113
|
+
constructor(attribute, owner, options = {}) {
|
|
114
|
+
this.#attribute = attribute;
|
|
115
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
116
|
+
this.#base = options.base === true;
|
|
117
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
118
|
+
const names = registry.names;
|
|
119
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
120
|
+
}
|
|
121
|
+
write(element, value) {
|
|
122
|
+
const stack = attributeStack(element, this.#attribute);
|
|
123
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
124
|
+
this.#held.add(element);
|
|
125
|
+
const shows = !this.#covered(element, stack, hold);
|
|
126
|
+
hold.written = value;
|
|
127
|
+
this.#mark(element, stack);
|
|
128
|
+
if (shows) this.#reflect(element, value);
|
|
129
|
+
}
|
|
130
|
+
return(element) {
|
|
131
|
+
const held = this.#held.delete(element);
|
|
132
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
133
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
134
|
+
const hold = this.#take(stack);
|
|
135
|
+
if (!hold) return false;
|
|
136
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
137
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
138
|
+
const index = stack.indexOf(hold);
|
|
139
|
+
stack.splice(index, 1);
|
|
140
|
+
const above = stack[index];
|
|
141
|
+
if (above) above.linked &&= hold.linked;
|
|
142
|
+
this.#mark(element, stack);
|
|
143
|
+
if (!owns) return true;
|
|
144
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
145
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
returnAll() {
|
|
149
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
150
|
+
}
|
|
151
|
+
#take(stack) {
|
|
152
|
+
const hold = findHold(stack, this, this.#record);
|
|
153
|
+
if (hold) hold.lease = this;
|
|
154
|
+
return hold;
|
|
155
|
+
}
|
|
156
|
+
#acquire(element, stack) {
|
|
157
|
+
const current = element.getAttribute(this.#attribute);
|
|
158
|
+
const top = stack.at(-1);
|
|
159
|
+
const bottom = stack[0];
|
|
160
|
+
const over = top?.written === current ? top : void 0;
|
|
161
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
162
|
+
const hold = {
|
|
163
|
+
lease: this,
|
|
164
|
+
record: this.#record,
|
|
165
|
+
written: current,
|
|
166
|
+
original: from ? from.original : current,
|
|
167
|
+
linked: !this.#base && over !== void 0
|
|
168
|
+
};
|
|
169
|
+
if (this.#base && bottom) {
|
|
170
|
+
bottom.linked = true;
|
|
171
|
+
stack.unshift(hold);
|
|
172
|
+
} else stack.push(hold);
|
|
173
|
+
return hold;
|
|
174
|
+
}
|
|
175
|
+
#covered(element, stack, hold) {
|
|
176
|
+
const current = element.getAttribute(this.#attribute);
|
|
177
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
178
|
+
}
|
|
179
|
+
#mark(element, stack) {
|
|
180
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
181
|
+
stack.forEach((hold, index) => {
|
|
182
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
183
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
184
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
185
|
+
records.set(
|
|
186
|
+
hold.record,
|
|
187
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
for (const [name, recorded] of records) {
|
|
191
|
+
setAttributeIfChanged(element, name, recorded);
|
|
40
192
|
}
|
|
41
193
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
_BeforeCacheReset.#subscribers.delete(this);
|
|
45
|
-
if (_BeforeCacheReset.#subscribers.size > 0) return;
|
|
46
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
194
|
+
#reflect(element, value) {
|
|
195
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
47
196
|
}
|
|
48
197
|
};
|
|
49
198
|
|
|
50
|
-
// src/utils/intl_format.ts
|
|
51
199
|
var formatters = /* @__PURE__ */ new WeakMap();
|
|
52
200
|
function intlFormatter(factory, locale, options, fallbackLocale) {
|
|
53
201
|
const cache = cacheFor(factory);
|
|
@@ -76,7 +224,6 @@ function construct(factory, locale, options, fallbackLocale) {
|
|
|
76
224
|
}
|
|
77
225
|
}
|
|
78
226
|
|
|
79
|
-
// src/utils/dates.ts
|
|
80
227
|
function toISODateString(date) {
|
|
81
228
|
const year = date.getFullYear();
|
|
82
229
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
@@ -109,12 +256,35 @@ function parseISOMonthString(monthStr) {
|
|
|
109
256
|
function toISOMonthString(date) {
|
|
110
257
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
|
|
111
258
|
}
|
|
259
|
+
function monthGridDays(year, month, weekStart) {
|
|
260
|
+
const first = new Date(year, month - 1, 1);
|
|
261
|
+
const offset = (first.getDay() - weekStart + 7) % 7;
|
|
262
|
+
const current = new Date(first);
|
|
263
|
+
current.setDate(first.getDate() - offset);
|
|
264
|
+
const days = [];
|
|
265
|
+
for (let i = 0; i < 42; i++) {
|
|
266
|
+
days.push(new Date(current));
|
|
267
|
+
current.setDate(current.getDate() + 1);
|
|
268
|
+
}
|
|
269
|
+
return days;
|
|
270
|
+
}
|
|
271
|
+
function dateInMonthClamped(date, year, month) {
|
|
272
|
+
const target = new Date(year, month - 1, 1);
|
|
273
|
+
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
274
|
+
target.setDate(Math.min(date.getDate(), lastDay));
|
|
275
|
+
return target;
|
|
276
|
+
}
|
|
277
|
+
function shiftMonthClamped(date, delta) {
|
|
278
|
+
return dateInMonthClamped(date, date.getFullYear(), date.getMonth() + 1 + delta);
|
|
279
|
+
}
|
|
280
|
+
function shiftYearClamped(date, delta) {
|
|
281
|
+
return dateInMonthClamped(date, date.getFullYear() + delta, date.getMonth() + 1);
|
|
282
|
+
}
|
|
112
283
|
var MONTH_LABEL_OPTIONS = { month: "long", year: "numeric" };
|
|
113
284
|
function monthLabelFormatter(locale) {
|
|
114
285
|
return intlFormatter(Intl.DateTimeFormat, locale, MONTH_LABEL_OPTIONS, "en");
|
|
115
286
|
}
|
|
116
287
|
|
|
117
|
-
// src/utils/field_mirror.ts
|
|
118
288
|
function writeField(field, value) {
|
|
119
289
|
if (field.value === value) return false;
|
|
120
290
|
field.value = value;
|
|
@@ -124,32 +294,40 @@ function commitField(target) {
|
|
|
124
294
|
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
125
295
|
}
|
|
126
296
|
|
|
127
|
-
// src/utils/locale.ts
|
|
128
297
|
function resolveLocale(element, declared = "") {
|
|
129
298
|
return declared || element.closest("[lang]")?.getAttribute("lang") || void 0;
|
|
130
299
|
}
|
|
131
300
|
|
|
132
|
-
|
|
301
|
+
var ListenerSet = class {
|
|
302
|
+
#abort = new AbortController();
|
|
303
|
+
add(target, type, handler, options) {
|
|
304
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
305
|
+
}
|
|
306
|
+
dispose() {
|
|
307
|
+
this.#abort.abort();
|
|
308
|
+
this.#abort = new AbortController();
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
133
312
|
var MicrotaskCoalescer = class {
|
|
134
313
|
#run;
|
|
135
314
|
#queued = false;
|
|
136
315
|
#active = false;
|
|
137
316
|
#generation = 0;
|
|
138
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
139
317
|
constructor(run) {
|
|
140
318
|
this.#run = run;
|
|
141
319
|
}
|
|
142
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
143
320
|
activate() {
|
|
144
321
|
this.#active = true;
|
|
145
322
|
}
|
|
146
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
147
323
|
cancel() {
|
|
148
324
|
this.#active = false;
|
|
149
325
|
this.#queued = false;
|
|
150
326
|
this.#generation += 1;
|
|
151
327
|
}
|
|
152
|
-
|
|
328
|
+
get pending() {
|
|
329
|
+
return this.#queued;
|
|
330
|
+
}
|
|
153
331
|
schedule() {
|
|
154
332
|
if (!this.#active || this.#queued) return;
|
|
155
333
|
this.#queued = true;
|
|
@@ -162,43 +340,52 @@ var MicrotaskCoalescer = class {
|
|
|
162
340
|
}
|
|
163
341
|
};
|
|
164
342
|
|
|
165
|
-
|
|
343
|
+
var MorphRenderWatcher = class {
|
|
344
|
+
#listeners = new ListenerSet();
|
|
345
|
+
#pass;
|
|
346
|
+
#element = null;
|
|
347
|
+
#onMorph = () => this.#pass.schedule();
|
|
348
|
+
constructor(run) {
|
|
349
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
350
|
+
}
|
|
351
|
+
observe(element) {
|
|
352
|
+
if (this.#element === element) return;
|
|
353
|
+
this.disconnect();
|
|
354
|
+
this.#element = element;
|
|
355
|
+
this.#pass.activate();
|
|
356
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
357
|
+
}
|
|
358
|
+
schedule() {
|
|
359
|
+
this.#pass.schedule();
|
|
360
|
+
}
|
|
361
|
+
get pending() {
|
|
362
|
+
return this.#pass.pending;
|
|
363
|
+
}
|
|
364
|
+
disconnect() {
|
|
365
|
+
this.#listeners.dispose();
|
|
366
|
+
this.#pass.cancel();
|
|
367
|
+
this.#element = null;
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
|
|
166
371
|
var TimerRegistry = class {
|
|
167
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
168
372
|
ids = /* @__PURE__ */ new Set();
|
|
169
|
-
/**
|
|
170
|
-
* Cancels a single tracked timer.
|
|
171
|
-
*
|
|
172
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
173
|
-
* registry), so callers can clear defensively without guarding.
|
|
174
|
-
*/
|
|
175
373
|
clear(id) {
|
|
176
374
|
if (this.ids.delete(id)) {
|
|
177
375
|
this.cancel(id);
|
|
178
376
|
}
|
|
179
377
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
182
|
-
* to guarantee no timer outlives the element.
|
|
183
|
-
*/
|
|
184
378
|
clearAll() {
|
|
185
379
|
for (const id of this.ids) {
|
|
186
380
|
this.cancel(id);
|
|
187
381
|
}
|
|
188
382
|
this.ids.clear();
|
|
189
383
|
}
|
|
190
|
-
/** Number of timers currently tracked (pending). */
|
|
191
384
|
get size() {
|
|
192
385
|
return this.ids.size;
|
|
193
386
|
}
|
|
194
387
|
};
|
|
195
388
|
var SafeTimeout = class extends TimerRegistry {
|
|
196
|
-
/**
|
|
197
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
198
|
-
*
|
|
199
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
200
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
201
|
-
*/
|
|
202
389
|
set(callback, delay) {
|
|
203
390
|
const id = this.schedule(() => {
|
|
204
391
|
this.ids.delete(id);
|
|
@@ -215,7 +402,6 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
215
402
|
}
|
|
216
403
|
};
|
|
217
404
|
|
|
218
|
-
// src/utils/string_list.ts
|
|
219
405
|
function parseStringList(raw, fallback = []) {
|
|
220
406
|
const text = raw.trim();
|
|
221
407
|
if (text.length === 0) return [...fallback];
|
|
@@ -229,67 +415,42 @@ function parseStringList(raw, fallback = []) {
|
|
|
229
415
|
return parsed.filter((entry) => typeof entry === "string");
|
|
230
416
|
}
|
|
231
417
|
|
|
232
|
-
// src/utils/target_selector.ts
|
|
233
418
|
function targetSelector(identifier, name) {
|
|
234
419
|
return `[data-${identifier}-target~="${name}"]`;
|
|
235
420
|
}
|
|
236
421
|
|
|
237
|
-
// src/controllers/date_range_picker_controller.ts
|
|
238
422
|
var GRID_SIZE = 42;
|
|
239
423
|
var DateRangePickerController = class extends Controller {
|
|
424
|
+
#fieldWrites = /* @__PURE__ */ new WeakMap();
|
|
240
425
|
static targets = ["grid", "monthLabel", "cell", "status", "startField", "endField"];
|
|
241
426
|
static values = {
|
|
242
427
|
min: { type: String, default: "" },
|
|
243
428
|
max: { type: String, default: "" },
|
|
244
|
-
// A JSON list read through `parseStringList` rather than Stimulus's `Array`
|
|
245
|
-
// type: that reader throws out of the value observer before any callback
|
|
246
|
-
// runs, so one malformed attribute would stop the picker from connecting.
|
|
247
429
|
disabledDates: { type: String, default: "" },
|
|
248
430
|
locale: { type: String, default: "" }
|
|
249
431
|
};
|
|
250
432
|
static actions = ["applyPreset", "next", "onKeydown", "prev", "previewTo", "selectDate"];
|
|
251
433
|
static events = ["change", "monthchange", "reconcile"];
|
|
252
|
-
/** The month currently rendered, as `YYYY-MM`. */
|
|
253
434
|
#viewMonth = "";
|
|
254
|
-
/** The confirmed range endpoints (ISO), or "" when unset. */
|
|
255
435
|
#startDate = "";
|
|
256
436
|
#endDate = "";
|
|
257
|
-
/** The first endpoint of an in-progress selection (ISO), or "" when idle. */
|
|
258
437
|
#pendingStart = "";
|
|
259
|
-
/** The hovered/focused date previewed while selecting (ISO), or "". */
|
|
260
438
|
#previewDate = "";
|
|
261
|
-
/** The roving-focus date in the grid (local time). */
|
|
262
439
|
#focusedDate = /* @__PURE__ */ new Date();
|
|
263
|
-
/** Deferred focus after an async month transition (cancelled on teardown). */
|
|
264
440
|
#focusTimer = new SafeTimeout();
|
|
265
|
-
/**
|
|
266
|
-
* How many times the confirmed range has moved — a commit or a narrowing — so
|
|
267
|
-
* a report still pending for a range a listener has since replaced can tell.
|
|
268
|
-
*/
|
|
269
441
|
#rangeMoves = 0;
|
|
270
|
-
/** How many month transitions have started, so one a listener starts mid-paint keeps its focus. */
|
|
271
442
|
#transitions = 0;
|
|
272
|
-
/** The declared unavailable dates, indexed for the per-cell paint lookup. */
|
|
273
443
|
#disabledDates = /* @__PURE__ */ new Set();
|
|
274
|
-
/** Rewinds an unfinished selection before Turbo snapshots the page. */
|
|
275
|
-
#beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
|
|
276
|
-
/** Last painted month, or `null` until the initial paint has settled. */
|
|
277
444
|
#announcedMonth = null;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
#repaint = new
|
|
445
|
+
#multiselectable = new AttributeLease(
|
|
446
|
+
"aria-multiselectable",
|
|
447
|
+
this.identifier
|
|
448
|
+
);
|
|
449
|
+
#repaint = new MorphRenderWatcher(() => {
|
|
283
450
|
this.#render();
|
|
284
451
|
});
|
|
285
|
-
/**
|
|
286
|
-
* Seeds the range from optional hidden fields — ordered, and narrowed to the
|
|
287
|
-
* days that can be chosen — then paints the grid, which writes the range back
|
|
288
|
-
* to the fields silently.
|
|
289
|
-
*/
|
|
290
452
|
connect() {
|
|
291
|
-
this.#repaint.
|
|
292
|
-
this.#beforeCache.activate();
|
|
453
|
+
this.#repaint.observe(this.element);
|
|
293
454
|
const authoredStart = this.hasStartFieldTarget ? normalizeISO(this.startFieldTarget.value) : "";
|
|
294
455
|
const authoredEnd = this.hasEndFieldTarget ? normalizeISO(this.endFieldTarget.value) : "";
|
|
295
456
|
[this.#startDate, this.#endDate] = this.#selectableRange(
|
|
@@ -301,58 +462,78 @@ var DateRangePickerController = class extends Controller {
|
|
|
301
462
|
const anchor = parseISODateString(this.#startDate) ?? this.#clampToBounds(/* @__PURE__ */ new Date()) ?? /* @__PURE__ */ new Date();
|
|
302
463
|
this.#focusedDate = anchor;
|
|
303
464
|
this.#viewMonth = toISOMonthString(anchor);
|
|
304
|
-
if (this.hasGridTarget) this.gridTarget.setAttribute("aria-multiselectable", "true");
|
|
305
465
|
this.#render();
|
|
306
466
|
}
|
|
307
|
-
/** Cancels any pending deferred focus so it never fires on a detached element. */
|
|
308
467
|
disconnect() {
|
|
309
|
-
this.#repaint.
|
|
310
|
-
this.#beforeCache.deactivate();
|
|
468
|
+
this.#repaint.disconnect();
|
|
311
469
|
this.#focusTimer.clearAll();
|
|
312
470
|
}
|
|
313
|
-
/** Repaints the label when application code changes `locale` at runtime. */
|
|
314
471
|
localeValueChanged() {
|
|
315
472
|
this.#repaint.schedule();
|
|
316
473
|
}
|
|
317
|
-
/** Repaints when application code (or a Turbo morph) changes `min` at runtime. */
|
|
318
474
|
minValueChanged() {
|
|
319
475
|
this.#repaint.schedule();
|
|
320
476
|
}
|
|
321
|
-
/** Repaints when application code (or a Turbo morph) changes `max` at runtime. */
|
|
322
477
|
maxValueChanged() {
|
|
323
478
|
this.#repaint.schedule();
|
|
324
479
|
}
|
|
325
|
-
/** Re-indexes the unavailable dates and repaints when the declared set changes. */
|
|
326
480
|
disabledDatesValueChanged() {
|
|
327
481
|
this.#disabledDates = new Set(parseStringList(this.disabledDatesValue));
|
|
328
482
|
this.#repaint.schedule();
|
|
329
483
|
}
|
|
330
|
-
|
|
484
|
+
gridTargetConnected() {
|
|
485
|
+
this.#repaint.schedule();
|
|
486
|
+
}
|
|
487
|
+
gridTargetDisconnected(grid) {
|
|
488
|
+
if (!this.gridTargets.includes(grid)) this.#multiselectable.return(grid);
|
|
489
|
+
this.#repaint.schedule();
|
|
490
|
+
}
|
|
491
|
+
monthLabelTargetConnected() {
|
|
492
|
+
this.#repaint.schedule();
|
|
493
|
+
}
|
|
494
|
+
monthLabelTargetDisconnected() {
|
|
495
|
+
this.#repaint.schedule();
|
|
496
|
+
}
|
|
497
|
+
startFieldTargetConnected() {
|
|
498
|
+
this.#repaint.schedule();
|
|
499
|
+
}
|
|
500
|
+
startFieldTargetDisconnected() {
|
|
501
|
+
this.#repaint.schedule();
|
|
502
|
+
}
|
|
503
|
+
endFieldTargetConnected() {
|
|
504
|
+
this.#repaint.schedule();
|
|
505
|
+
}
|
|
506
|
+
endFieldTargetDisconnected() {
|
|
507
|
+
this.#repaint.schedule();
|
|
508
|
+
}
|
|
331
509
|
prev(event) {
|
|
332
510
|
event?.preventDefault();
|
|
333
511
|
this.#shiftMonth(-1);
|
|
334
512
|
}
|
|
335
|
-
/** Navigates to the next month. */
|
|
336
513
|
next(event) {
|
|
337
514
|
event?.preventDefault();
|
|
338
515
|
this.#shiftMonth(1);
|
|
339
516
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
517
|
+
selectDate(source) {
|
|
518
|
+
const { origin, reason } = actionSource(source);
|
|
519
|
+
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
520
|
+
return;
|
|
521
|
+
const cell = this.#cellFrom(origin);
|
|
343
522
|
if (!cell) return;
|
|
344
523
|
const date = cell.getAttribute("data-date");
|
|
345
524
|
if (!date || !this.#isSelectable(date)) return;
|
|
346
|
-
this.#choose(date);
|
|
525
|
+
this.#choose(date, reason);
|
|
347
526
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
527
|
+
previewTo(source) {
|
|
528
|
+
const { event, origin } = actionSource(source);
|
|
529
|
+
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
530
|
+
return;
|
|
531
|
+
const cell = this.#cellFrom(origin);
|
|
351
532
|
if (!cell) return;
|
|
352
533
|
const date = cell.getAttribute("data-date");
|
|
353
534
|
if (!date) return;
|
|
354
535
|
let shouldRender = false;
|
|
355
|
-
if (event
|
|
536
|
+
if (event?.type.startsWith("focus")) {
|
|
356
537
|
const parsed = parseISODateString(date);
|
|
357
538
|
if (parsed) this.#focusedDate = parsed;
|
|
358
539
|
shouldRender = cell.getAttribute("tabindex") !== "0";
|
|
@@ -363,9 +544,11 @@ var DateRangePickerController = class extends Controller {
|
|
|
363
544
|
}
|
|
364
545
|
if (shouldRender) this.#render();
|
|
365
546
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const button =
|
|
547
|
+
applyPreset(source) {
|
|
548
|
+
const { event, origin, reason } = actionSource(source);
|
|
549
|
+
const button = origin?.closest("[data-range]");
|
|
550
|
+
if (!button || !this.element.contains(button)) return;
|
|
551
|
+
const focus = event !== null || this.element.contains(document.activeElement);
|
|
369
552
|
const range = computePreset(button?.getAttribute("data-range") ?? "");
|
|
370
553
|
if (!range) return;
|
|
371
554
|
const intersection = this.#intersectRange(range);
|
|
@@ -375,13 +558,20 @@ var DateRangePickerController = class extends Controller {
|
|
|
375
558
|
const move = this.#setConfirmed(start, end);
|
|
376
559
|
const endDate = parseISODateString(end);
|
|
377
560
|
if (endDate) this.#focusedDate = endDate;
|
|
378
|
-
this.#transitionTo(
|
|
379
|
-
|
|
561
|
+
this.#transitionTo(
|
|
562
|
+
toISOMonthString(parseISODateString(end) ?? /* @__PURE__ */ new Date()),
|
|
563
|
+
end,
|
|
564
|
+
true,
|
|
565
|
+
() => focus && (event !== null || this.element.contains(document.activeElement))
|
|
566
|
+
);
|
|
567
|
+
this.#reportConfirmed(move, reason);
|
|
380
568
|
}
|
|
381
|
-
/** Grid keyboard navigation, selection (Enter/Space), and Escape-to-cancel. */
|
|
382
569
|
onKeydown(event) {
|
|
383
570
|
if (event.defaultPrevented) return;
|
|
384
571
|
if (isReservedArrowChord(event)) return;
|
|
572
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
573
|
+
if ((event.key === "PageUp" || event.key === "PageDown") && (event.ctrlKey || event.altKey || event.metaKey))
|
|
574
|
+
return;
|
|
385
575
|
const cell = this.#cellFrom(event.target);
|
|
386
576
|
if (!cell) return;
|
|
387
577
|
const dateStr = cell.getAttribute("data-date") ?? "";
|
|
@@ -402,7 +592,8 @@ var DateRangePickerController = class extends Controller {
|
|
|
402
592
|
return;
|
|
403
593
|
}
|
|
404
594
|
let next = null;
|
|
405
|
-
|
|
595
|
+
const directionElement = this.hasGridTarget ? gridDirectionElement(this.gridTarget, this.element) : this.element;
|
|
596
|
+
switch (logicalArrowKey(event.key, directionElement)) {
|
|
406
597
|
case "ArrowLeft":
|
|
407
598
|
next = addDays(date, -1);
|
|
408
599
|
break;
|
|
@@ -433,8 +624,7 @@ var DateRangePickerController = class extends Controller {
|
|
|
433
624
|
event.preventDefault();
|
|
434
625
|
this.#moveFocusTo(next);
|
|
435
626
|
}
|
|
436
|
-
|
|
437
|
-
#choose(date) {
|
|
627
|
+
#choose(date, reason = "user") {
|
|
438
628
|
if (!this.#pendingStart || !this.#isSelectable(this.#pendingStart)) {
|
|
439
629
|
this.#pendingStart = date;
|
|
440
630
|
this.#previewDate = date;
|
|
@@ -446,54 +636,38 @@ var DateRangePickerController = class extends Controller {
|
|
|
446
636
|
const [start, end] = date < this.#pendingStart ? [date, this.#pendingStart] : [this.#pendingStart, date];
|
|
447
637
|
const move = this.#setConfirmed(start, end);
|
|
448
638
|
this.#render(true);
|
|
449
|
-
this.#reportConfirmed(move);
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Makes `start`–`end` the confirmed range, ending any selection in progress,
|
|
453
|
-
* ahead of the paint that shows it.
|
|
454
|
-
*
|
|
455
|
-
* @returns The move count the range is now at, which its `change` checks.
|
|
456
|
-
*/
|
|
639
|
+
this.#reportConfirmed(move, reason);
|
|
640
|
+
}
|
|
457
641
|
#setConfirmed(start, end) {
|
|
642
|
+
const changed = start !== this.#startDate || end !== this.#endDate;
|
|
458
643
|
this.#startDate = start;
|
|
459
644
|
this.#endDate = end;
|
|
460
645
|
this.#pendingStart = "";
|
|
461
646
|
this.#previewDate = "";
|
|
647
|
+
if (!changed) return null;
|
|
462
648
|
this.#rangeMoves += 1;
|
|
463
649
|
return this.#rangeMoves;
|
|
464
650
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
* range on has had the range it moved to reported instead.
|
|
469
|
-
*/
|
|
470
|
-
#reportConfirmed(move) {
|
|
471
|
-
if (move !== this.#rangeMoves) return;
|
|
472
|
-
this.dispatch("change", { detail: { start: this.#startDate, end: this.#endDate } });
|
|
651
|
+
#reportConfirmed(move, reason) {
|
|
652
|
+
if (move === null || move !== this.#rangeMoves) return;
|
|
653
|
+
this.dispatch("change", { detail: { start: this.#startDate, end: this.#endDate, reason } });
|
|
473
654
|
}
|
|
474
|
-
/** Moves roving focus to `date`, transitioning the month when needed. */
|
|
475
655
|
#moveFocusTo(date) {
|
|
476
656
|
this.#focusedDate = date;
|
|
477
657
|
const iso = toISODateString(date);
|
|
478
658
|
if (this.#pendingStart && this.#isSelectable(iso)) this.#previewDate = iso;
|
|
479
659
|
this.#transitionTo(toISOMonthString(date), iso);
|
|
480
660
|
}
|
|
481
|
-
|
|
482
|
-
* Renders `month`, then focuses the cell for `dateStr` (deferred if async).
|
|
483
|
-
* A listener of the paint's reports that started another move has placed
|
|
484
|
-
* focus itself, so this one leaves it there.
|
|
485
|
-
*
|
|
486
|
-
* @param confirmed - Whether the paint shows a range the user has just confirmed.
|
|
487
|
-
*/
|
|
488
|
-
#transitionTo(month, dateStr, confirmed = false) {
|
|
661
|
+
#transitionTo(month, dateStr, confirmed = false, canFocus = () => true) {
|
|
489
662
|
const isTransition = month !== this.#viewMonth;
|
|
490
663
|
this.#focusTimer.clearAll();
|
|
491
664
|
this.#viewMonth = month;
|
|
492
665
|
this.#transitions += 1;
|
|
493
666
|
const transition = this.#transitions;
|
|
494
667
|
this.#render(confirmed);
|
|
495
|
-
if (transition !== this.#transitions) return;
|
|
668
|
+
if (transition !== this.#transitions || !canFocus()) return;
|
|
496
669
|
const focusCell = () => {
|
|
670
|
+
if (!canFocus()) return;
|
|
497
671
|
this.cellTargets.find((c) => c.getAttribute("data-date") === dateStr)?.focus();
|
|
498
672
|
};
|
|
499
673
|
if (isTransition) {
|
|
@@ -502,28 +676,16 @@ var DateRangePickerController = class extends Controller {
|
|
|
502
676
|
focusCell();
|
|
503
677
|
}
|
|
504
678
|
}
|
|
505
|
-
/** Shifts the displayed month by `delta`, keeping focus within it. */
|
|
506
679
|
#shiftMonth(delta) {
|
|
507
680
|
const info = parseISOMonthString(this.#viewMonth);
|
|
508
681
|
if (!info) return;
|
|
509
|
-
const target =
|
|
682
|
+
const target = dateInMonthClamped(this.#focusedDate, info.year, info.month + delta);
|
|
510
683
|
this.#viewMonth = toISOMonthString(target);
|
|
511
|
-
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
512
|
-
target.setDate(Math.min(this.#focusedDate.getDate(), lastDay));
|
|
513
684
|
this.#focusedDate = target;
|
|
514
685
|
this.#render();
|
|
515
686
|
}
|
|
516
|
-
/**
|
|
517
|
-
* Builds the six-week grid and binds range/roving/disabled state per cell,
|
|
518
|
-
* mirrors the confirmed range to the hidden fields, then reports what the
|
|
519
|
-
* paint moved.
|
|
520
|
-
*
|
|
521
|
-
* @param confirmed - Whether the paint shows a range the user has just
|
|
522
|
-
* confirmed, which the status then announces and each moved field reports.
|
|
523
|
-
*
|
|
524
|
-
* @stimeoRenderRoot
|
|
525
|
-
*/
|
|
526
687
|
#render(confirmed = false) {
|
|
688
|
+
if (this.hasGridTarget) this.#multiselectable.write(this.gridTarget, "true");
|
|
527
689
|
const info = parseISOMonthString(this.#viewMonth);
|
|
528
690
|
if (!info) return;
|
|
529
691
|
const { year, month } = info;
|
|
@@ -538,7 +700,7 @@ var DateRangePickerController = class extends Controller {
|
|
|
538
700
|
this.monthLabelTarget.textContent = formatter.format(new Date(year, month - 1, 1));
|
|
539
701
|
}
|
|
540
702
|
const [rangeStart, rangeEnd] = this.#visualRange();
|
|
541
|
-
const days =
|
|
703
|
+
const days = monthGridDays(year, month, 0);
|
|
542
704
|
const focusedStr = toISODateString(this.#focusedDate);
|
|
543
705
|
const todayStr = toISODateString(/* @__PURE__ */ new Date());
|
|
544
706
|
const cells = this.cellTargets;
|
|
@@ -576,8 +738,8 @@ var DateRangePickerController = class extends Controller {
|
|
|
576
738
|
const moved = this.#mirrorFields();
|
|
577
739
|
if (confirmed) {
|
|
578
740
|
this.#announce();
|
|
579
|
-
for (const [field, value] of moved) {
|
|
580
|
-
if (field.value === value) commitField(field);
|
|
741
|
+
for (const [field, value, write] of moved) {
|
|
742
|
+
if (field.value === value && this.#fieldWrites.get(field) === write) commitField(field);
|
|
581
743
|
}
|
|
582
744
|
}
|
|
583
745
|
const previous = this.#announcedMonth;
|
|
@@ -589,12 +751,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
589
751
|
this.dispatch("reconcile", { detail: { start: this.#startDate, end: this.#endDate } });
|
|
590
752
|
}
|
|
591
753
|
}
|
|
592
|
-
/**
|
|
593
|
-
* Narrows the confirmed range to days that can still be chosen. The paint
|
|
594
|
-
* mirrors it to the fields without reporting a commit.
|
|
595
|
-
*
|
|
596
|
-
* @returns Whether the range moved.
|
|
597
|
-
*/
|
|
598
754
|
#narrowConfirmedRange() {
|
|
599
755
|
const [start, end] = this.#selectableRange(this.#startDate, this.#endDate);
|
|
600
756
|
if (start === this.#startDate && end === this.#endDate) return false;
|
|
@@ -603,11 +759,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
603
759
|
this.#rangeMoves += 1;
|
|
604
760
|
return true;
|
|
605
761
|
}
|
|
606
|
-
/**
|
|
607
|
-
* The range `start`–`end` with each end moved inward to the nearest day that
|
|
608
|
-
* can be chosen, or two empty strings when none of its days can be. A lone
|
|
609
|
-
* endpoint is the one-day range it names, and stays lone.
|
|
610
|
-
*/
|
|
611
762
|
#selectableRange(start, end) {
|
|
612
763
|
let from = parseISODateString(start || end);
|
|
613
764
|
let to = parseISODateString(end || start);
|
|
@@ -621,7 +772,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
621
772
|
if (from.getTime() > to.getTime()) return ["", ""];
|
|
622
773
|
return [start ? toISODateString(from) : "", end ? toISODateString(to) : ""];
|
|
623
774
|
}
|
|
624
|
-
/** The ordered [start, end] pair to paint: the preview while selecting, else confirmed. */
|
|
625
775
|
#visualRange() {
|
|
626
776
|
if (this.#pendingStart) {
|
|
627
777
|
const other = this.#previewDate || this.#pendingStart;
|
|
@@ -629,81 +779,59 @@ var DateRangePickerController = class extends Controller {
|
|
|
629
779
|
}
|
|
630
780
|
return [this.#startDate, this.#endDate];
|
|
631
781
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
782
|
+
#writeField(field, value) {
|
|
783
|
+
if (!writeField(field, value)) return false;
|
|
784
|
+
this.#fieldWrites.set(field, (this.#fieldWrites.get(field) ?? 0) + 1);
|
|
785
|
+
return true;
|
|
786
|
+
}
|
|
637
787
|
#mirrorFields() {
|
|
638
788
|
const moved = [];
|
|
639
|
-
if (this.hasStartFieldTarget && writeField(this.startFieldTarget, this.#startDate)) {
|
|
640
|
-
moved.push([
|
|
789
|
+
if (this.hasStartFieldTarget && this.#writeField(this.startFieldTarget, this.#startDate)) {
|
|
790
|
+
moved.push([
|
|
791
|
+
this.startFieldTarget,
|
|
792
|
+
this.#startDate,
|
|
793
|
+
this.#fieldWrites.get(this.startFieldTarget) ?? 0
|
|
794
|
+
]);
|
|
641
795
|
}
|
|
642
|
-
if (this.hasEndFieldTarget && writeField(this.endFieldTarget, this.#endDate)) {
|
|
643
|
-
moved.push([
|
|
796
|
+
if (this.hasEndFieldTarget && this.#writeField(this.endFieldTarget, this.#endDate)) {
|
|
797
|
+
moved.push([
|
|
798
|
+
this.endFieldTarget,
|
|
799
|
+
this.#endDate,
|
|
800
|
+
this.#fieldWrites.get(this.endFieldTarget) ?? 0
|
|
801
|
+
]);
|
|
644
802
|
}
|
|
645
803
|
return moved;
|
|
646
804
|
}
|
|
647
|
-
/** Announces the confirmed range in the live status region. */
|
|
648
805
|
#announce() {
|
|
649
806
|
if (this.hasStatusTarget && this.#startDate && this.#endDate) {
|
|
650
807
|
this.statusTarget.textContent = `${this.#startDate} \u2013 ${this.#endDate}`;
|
|
651
808
|
}
|
|
652
809
|
}
|
|
653
|
-
/**
|
|
654
|
-
* True when `iso` may be chosen as a range endpoint.
|
|
655
|
-
*
|
|
656
|
-
* The single availability question in the controller: the grid paint, the
|
|
657
|
-
* preview, and both commit paths ask it, so a cell's `aria-disabled` and what
|
|
658
|
-
* a click on that cell does are the same decision rather than two that have to
|
|
659
|
-
* be kept in step.
|
|
660
|
-
*/
|
|
661
810
|
#isSelectable(iso) {
|
|
662
811
|
return !this.#outOfBounds(iso) && !this.#disabledDates.has(iso);
|
|
663
812
|
}
|
|
664
|
-
/** True when `iso` falls outside the `[min, max]` bounds. */
|
|
665
813
|
#outOfBounds(iso) {
|
|
666
814
|
if (this.minValue && iso < this.minValue) return true;
|
|
667
815
|
if (this.maxValue && iso > this.maxValue) return true;
|
|
668
816
|
return false;
|
|
669
817
|
}
|
|
670
|
-
/** Clamps a generated ISO date string into `[min, max]`. */
|
|
671
818
|
#clampISO(iso) {
|
|
672
819
|
if (this.minValue && iso < this.minValue) return this.minValue;
|
|
673
820
|
if (this.maxValue && iso > this.maxValue) return this.maxValue;
|
|
674
821
|
return iso;
|
|
675
822
|
}
|
|
676
|
-
/** Clamps a Date into `[min, max]`, returning null only when unparseable. */
|
|
677
823
|
#clampToBounds(date) {
|
|
678
824
|
const clamped = this.#clampISO(toISODateString(date));
|
|
679
825
|
return parseISODateString(clamped);
|
|
680
826
|
}
|
|
681
|
-
/**
|
|
682
|
-
* Intersects a preset with `[min, max]`, rejecting a disjoint interval.
|
|
683
|
-
*
|
|
684
|
-
* Only the bounds narrow a preset here: `disabledDates` excludes single days,
|
|
685
|
-
* not sub-intervals, so it cannot shrink one to a still-contiguous range. A
|
|
686
|
-
* day it excludes is still refused as an endpoint — the caller checks that —
|
|
687
|
-
* but a preset that merely spans one keeps its span.
|
|
688
|
-
*/
|
|
689
827
|
#intersectRange(range) {
|
|
690
828
|
const start = this.minValue && range.start < this.minValue ? this.minValue : range.start;
|
|
691
829
|
const end = this.maxValue && range.end > this.maxValue ? this.maxValue : range.end;
|
|
692
830
|
return start <= end ? { start, end } : null;
|
|
693
831
|
}
|
|
694
|
-
/** Removes provisional range state before Turbo freezes a cached snapshot. */
|
|
695
|
-
#rewindForCache() {
|
|
696
|
-
this.#focusTimer.clearAll();
|
|
697
|
-
if (!this.#pendingStart && !this.#previewDate) return;
|
|
698
|
-
this.#pendingStart = "";
|
|
699
|
-
this.#previewDate = "";
|
|
700
|
-
this.#render();
|
|
701
|
-
}
|
|
702
|
-
/** Resolves the cell element from an event target, or null. */
|
|
703
832
|
#cellFrom(target) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
) ?? null;
|
|
833
|
+
const cell = target instanceof Element ? target.closest(targetSelector(this.identifier, "cell")) : null;
|
|
834
|
+
return cell && this.cellTargets.includes(cell) ? cell : null;
|
|
707
835
|
}
|
|
708
836
|
};
|
|
709
837
|
function addDays(date, n) {
|
|
@@ -711,30 +839,6 @@ function addDays(date, n) {
|
|
|
711
839
|
next.setDate(next.getDate() + n);
|
|
712
840
|
return next;
|
|
713
841
|
}
|
|
714
|
-
function shiftMonthClamped(date, delta) {
|
|
715
|
-
const target = new Date(date.getFullYear(), date.getMonth() + delta, 1);
|
|
716
|
-
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
717
|
-
target.setDate(Math.min(date.getDate(), lastDay));
|
|
718
|
-
return target;
|
|
719
|
-
}
|
|
720
|
-
function shiftYearClamped(date, delta) {
|
|
721
|
-
const target = new Date(date.getFullYear() + delta, date.getMonth(), 1);
|
|
722
|
-
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
723
|
-
target.setDate(Math.min(date.getDate(), lastDay));
|
|
724
|
-
return target;
|
|
725
|
-
}
|
|
726
|
-
function gridDays(year, month) {
|
|
727
|
-
const first = new Date(year, month - 1, 1);
|
|
728
|
-
const start = new Date(first);
|
|
729
|
-
start.setDate(first.getDate() - first.getDay());
|
|
730
|
-
const days = [];
|
|
731
|
-
const current = new Date(start);
|
|
732
|
-
for (let i = 0; i < GRID_SIZE; i++) {
|
|
733
|
-
days.push(new Date(current));
|
|
734
|
-
current.setDate(current.getDate() + 1);
|
|
735
|
-
}
|
|
736
|
-
return days;
|
|
737
|
-
}
|
|
738
842
|
function normalizeISO(value) {
|
|
739
843
|
const date = parseISODateString(value.trim());
|
|
740
844
|
return date ? toISODateString(date) : "";
|
|
@@ -763,5 +867,4 @@ function computePreset(name) {
|
|
|
763
867
|
}
|
|
764
868
|
|
|
765
869
|
export { DateRangePickerController };
|
|
766
|
-
//# sourceMappingURL=date_range_picker_controller.js.map
|
|
767
870
|
//# sourceMappingURL=date_range_picker_controller.js.map
|