stimeo-ui 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +209 -0
- package/README.md +128 -1
- package/dist/cable/index.d.ts +79 -23
- package/dist/cable/index.js +392 -417
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +34 -5
- package/dist/controllers/accordion_controller.js +228 -28
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +20 -9
- package/dist/controllers/alert_dialog_controller.js +862 -221
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +38 -7
- package/dist/controllers/announcer_controller.js +135 -191
- 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 +295 -110
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +172 -106
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +0 -129
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +22 -4
- package/dist/controllers/bulk_select_controller.js +264 -53
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +109 -28
- package/dist/controllers/calendar_controller.js +346 -180
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +99 -27
- package/dist/controllers/carousel_controller.js +587 -300
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +18 -2
- package/dist/controllers/character_counter_controller.js +271 -143
- 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 +77 -75
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +44 -7
- package/dist/controllers/clipboard_controller.js +187 -108
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +41 -5
- package/dist/controllers/collapsible_controller.js +374 -108
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +47 -14
- package/dist/controllers/color_picker_controller.js +183 -127
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +33 -6
- package/dist/controllers/combobox_controller.js +426 -109
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +45 -14
- package/dist/controllers/command_palette_controller.js +994 -350
- 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 +212 -125
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +49 -12
- package/dist/controllers/confirm_controller.js +939 -245
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +36 -3
- package/dist/controllers/context_menu_controller.js +275 -127
- 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 +75 -2
- package/dist/controllers/countdown_controller.js +235 -97
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +93 -15
- package/dist/controllers/currency_input_controller.js +241 -118
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +78 -22
- package/dist/controllers/data_grid_controller.js +229 -135
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +64 -11
- package/dist/controllers/date_range_picker_controller.js +359 -165
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +22 -3
- package/dist/controllers/dialog_controller.js +887 -225
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +24 -7
- package/dist/controllers/direct_upload_controller.js +80 -142
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +2 -2
- package/dist/controllers/dirty_form_controller.js +26 -47
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.d.ts +19 -0
- package/dist/controllers/dismissible_controller.js +175 -20
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +52 -16
- package/dist/controllers/drawer_controller.js +963 -336
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +39 -3
- package/dist/controllers/dropdown_controller.js +342 -85
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.d.ts +12 -1
- package/dist/controllers/editable_controller.js +182 -58
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.js +67 -53
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +60 -18
- package/dist/controllers/file_dropzone_controller.js +426 -229
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +10 -4
- package/dist/controllers/filter_controller.js +78 -36
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +57 -14
- package/dist/controllers/flash_controller.js +328 -211
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +12 -3
- package/dist/controllers/focus_controller.js +654 -239
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +153 -136
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +29 -96
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +41 -9
- package/dist/controllers/frame_loading_controller.js +263 -198
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +22 -2
- package/dist/controllers/highlight_controller.js +119 -70
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +65 -4
- package/dist/controllers/hover_card_controller.js +335 -118
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +58 -4
- package/dist/controllers/idle_controller.js +316 -65
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +5 -2
- package/dist/controllers/input_mask_controller.js +116 -61
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.d.ts +32 -13
- package/dist/controllers/intersection_controller.js +147 -103
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +16 -0
- package/dist/controllers/lazy_frame_controller.js +9 -56
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +84 -10
- package/dist/controllers/listbox_controller.js +413 -153
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +1 -1
- package/dist/controllers/local_time_controller.js +54 -64
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +11 -3
- package/dist/controllers/masonry_controller.js +70 -95
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +40 -9
- package/dist/controllers/menu_controller.js +254 -167
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +15 -4
- package/dist/controllers/menubar_controller.js +206 -331
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +20 -0
- package/dist/controllers/meter_controller.js +159 -71
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +50 -7
- package/dist/controllers/multi_select_controller.js +797 -388
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +19 -1
- package/dist/controllers/navigation_menu_controller.js +156 -231
- 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 +373 -174
- 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 +241 -45
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +62 -10
- package/dist/controllers/number_input_controller.js +387 -227
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +28 -75
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +38 -7
- package/dist/controllers/otp_controller.js +344 -196
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +13 -12
- package/dist/controllers/overflow_indicator_controller.js +167 -93
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +66 -9
- package/dist/controllers/overflow_menu_controller.js +408 -277
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +52 -15
- package/dist/controllers/pagination_controller.js +342 -120
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +60 -9
- package/dist/controllers/password_reveal_controller.js +424 -99
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +14 -5
- package/dist/controllers/password_strength_controller.js +99 -153
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +11 -4
- package/dist/controllers/persist_controller.js +252 -96
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +19 -7
- package/dist/controllers/pointer_drag_controller.js +263 -164
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +46 -4
- package/dist/controllers/popover_controller.js +267 -94
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +44 -4
- package/dist/controllers/portal_controller.js +209 -72
- 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 -112
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +11 -0
- package/dist/controllers/progress_controller.js +132 -59
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +19 -8
- package/dist/controllers/radio_group_controller.js +138 -133
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +92 -4
- package/dist/controllers/range_slider_controller.js +245 -112
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +33 -6
- package/dist/controllers/rating_controller.js +429 -194
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +26 -2
- package/dist/controllers/read_more_controller.js +185 -47
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +1 -1
- package/dist/controllers/reading_progress_controller.js +147 -135
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.d.ts +18 -4
- package/dist/controllers/relative_time_controller.js +145 -110
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
- package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
- package/dist/controllers/reset_on_restore_controller.js.map +1 -0
- package/dist/controllers/resizable_controller.d.ts +44 -4
- package/dist/controllers/resizable_controller.js +294 -118
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.js +39 -84
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +7 -3
- package/dist/controllers/scroll_area_controller.js +428 -221
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.js +0 -53
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
- package/dist/controllers/scroll_visibility_controller.js +395 -146
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +9 -3
- package/dist/controllers/scrollspy_controller.js +181 -236
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +59 -17
- package/dist/controllers/separator_controller.js +288 -132
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +81 -7
- package/dist/controllers/sidebar_controller.js +1071 -375
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +23 -0
- package/dist/controllers/skeleton_controller.js +248 -92
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +72 -8
- package/dist/controllers/slider_controller.js +211 -96
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
- package/dist/controllers/smart_sticky_header_controller.js +163 -54
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +13 -110
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +39 -4
- package/dist/controllers/spinner_controller.js +277 -161
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +24 -17
- package/dist/controllers/step_indicator_controller.js +107 -53
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +43 -9
- package/dist/controllers/stepper_controller.js +171 -48
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +25 -0
- package/dist/controllers/stick_to_bottom_controller.js +310 -116
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.d.ts +11 -0
- package/dist/controllers/sticky_observer_controller.js +214 -49
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +22 -6
- package/dist/controllers/submit_once_controller.js +294 -192
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +40 -7
- package/dist/controllers/switch_controller.js +107 -43
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +13 -1
- package/dist/controllers/tabs_controller.js +50 -25
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +27 -3
- package/dist/controllers/tags_input_controller.js +290 -149
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
- package/dist/controllers/textarea_autosize_controller.js +71 -58
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +37 -8
- package/dist/controllers/theme_controller.js +148 -80
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +18 -1
- package/dist/controllers/time_picker_controller.js +162 -81
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +85 -23
- package/dist/controllers/toast_controller.js +365 -193
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +60 -9
- package/dist/controllers/toggle_group_controller.js +194 -99
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +92 -90
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +52 -2
- package/dist/controllers/tooltip_controller.js +185 -125
- 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 -115
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +59 -18
- package/dist/controllers/tree_view_controller.js +248 -290
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +33 -3
- package/dist/index.js +8649 -8572
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +95 -9
- package/dist/inspector/cli.js +343 -77
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +390 -96
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +45 -45
- package/dist/inspector/manifest.json +1308 -155
- package/dist/positioning/index.d.ts +8 -0
- package/dist/positioning/index.js +148 -45
- package/dist/positioning/index.js.map +1 -1
- package/package.json +7 -7
- 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,31 @@
|
|
|
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;
|
|
@@ -18,36 +36,153 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
18
36
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
19
37
|
}
|
|
20
38
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
function sharedRegistry(key, create) {
|
|
40
|
+
const symbol = Symbol.for(key);
|
|
41
|
+
const scope = globalThis;
|
|
42
|
+
const existing = scope[symbol];
|
|
43
|
+
if (existing !== void 0) return existing;
|
|
44
|
+
const registry = create();
|
|
45
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
46
|
+
return registry;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isAttributeValue(value) {
|
|
50
|
+
return value === null || typeof value === "string";
|
|
51
|
+
}
|
|
52
|
+
function readLeaseRecord(element, record) {
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
55
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
56
|
+
const [original, written, ...rest] = parsed;
|
|
57
|
+
const linked = rest[0] !== false;
|
|
58
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
59
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
60
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
61
|
+
} catch {
|
|
62
|
+
return void 0;
|
|
33
63
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
}
|
|
65
|
+
var AttributeLease = class _AttributeLease {
|
|
66
|
+
static #registry = sharedRegistry(
|
|
67
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
68
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
69
|
+
);
|
|
70
|
+
#attribute;
|
|
71
|
+
#record;
|
|
72
|
+
#base;
|
|
73
|
+
#held = /* @__PURE__ */ new Set();
|
|
74
|
+
constructor(attribute, owner, options = {}) {
|
|
75
|
+
this.#attribute = attribute;
|
|
76
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
77
|
+
this.#base = options.base === true;
|
|
78
|
+
const names = _AttributeLease.#registry.names;
|
|
79
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
80
|
+
}
|
|
81
|
+
write(element, value) {
|
|
82
|
+
const stack = this.#stack(element);
|
|
83
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
84
|
+
this.#held.add(element);
|
|
85
|
+
const shows = !this.#covered(element, stack, hold);
|
|
86
|
+
hold.written = value;
|
|
87
|
+
this.#mark(element, stack);
|
|
88
|
+
if (shows) this.#reflect(element, value);
|
|
89
|
+
}
|
|
90
|
+
return(element) {
|
|
91
|
+
const held = this.#held.delete(element);
|
|
92
|
+
const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
|
|
93
|
+
const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
|
|
94
|
+
const hold = this.#take(stack);
|
|
95
|
+
if (!hold) return false;
|
|
96
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
97
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
98
|
+
const index = stack.indexOf(hold);
|
|
99
|
+
stack.splice(index, 1);
|
|
100
|
+
const above = stack[index];
|
|
101
|
+
if (above) above.linked &&= hold.linked;
|
|
102
|
+
this.#mark(element, stack);
|
|
103
|
+
if (!owns) return true;
|
|
104
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
105
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
returnAll() {
|
|
109
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
110
|
+
}
|
|
111
|
+
#stack(element) {
|
|
112
|
+
const stacks = _AttributeLease.#registry.stacks;
|
|
113
|
+
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
114
|
+
stacks.set(element, byAttribute);
|
|
115
|
+
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
116
|
+
byAttribute.set(this.#attribute, stack);
|
|
117
|
+
return stack;
|
|
118
|
+
}
|
|
119
|
+
#seed(element) {
|
|
120
|
+
const found = [];
|
|
121
|
+
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
122
|
+
const read = readLeaseRecord(element, record);
|
|
123
|
+
if (read) found.push({ ...read, record });
|
|
124
|
+
}
|
|
125
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
126
|
+
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
127
|
+
lease: null,
|
|
128
|
+
record,
|
|
129
|
+
written,
|
|
130
|
+
original,
|
|
131
|
+
linked: linked && index > 0
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
#take(stack) {
|
|
135
|
+
const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
|
|
136
|
+
if (hold) hold.lease = this;
|
|
137
|
+
return hold;
|
|
138
|
+
}
|
|
139
|
+
#acquire(element, stack) {
|
|
140
|
+
const current = element.getAttribute(this.#attribute);
|
|
141
|
+
const top = stack.at(-1);
|
|
142
|
+
const bottom = stack[0];
|
|
143
|
+
const over = top?.written === current ? top : void 0;
|
|
144
|
+
const from = this.#base ? bottom : over;
|
|
145
|
+
const hold = {
|
|
146
|
+
lease: this,
|
|
147
|
+
record: this.#record,
|
|
148
|
+
written: current,
|
|
149
|
+
original: from ? from.original : current,
|
|
150
|
+
linked: !this.#base && over !== void 0
|
|
151
|
+
};
|
|
152
|
+
if (this.#base && bottom) {
|
|
153
|
+
bottom.linked = true;
|
|
154
|
+
stack.unshift(hold);
|
|
155
|
+
} else stack.push(hold);
|
|
156
|
+
return hold;
|
|
157
|
+
}
|
|
158
|
+
#covered(element, stack, hold) {
|
|
159
|
+
const current = element.getAttribute(this.#attribute);
|
|
160
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
161
|
+
}
|
|
162
|
+
#mark(element, stack) {
|
|
163
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
164
|
+
stack.forEach((hold, index) => {
|
|
165
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
166
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
167
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
168
|
+
records.set(
|
|
169
|
+
hold.record,
|
|
170
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
for (const [name, recorded] of records) {
|
|
174
|
+
if (element.getAttribute(name) === recorded) continue;
|
|
175
|
+
if (recorded === null) element.removeAttribute(name);
|
|
176
|
+
else element.setAttribute(name, recorded);
|
|
40
177
|
}
|
|
41
178
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
179
|
+
#reflect(element, value) {
|
|
180
|
+
if (element.getAttribute(this.#attribute) === value) return;
|
|
181
|
+
if (value === null) element.removeAttribute(this.#attribute);
|
|
182
|
+
else element.setAttribute(this.#attribute, value);
|
|
47
183
|
}
|
|
48
184
|
};
|
|
49
185
|
|
|
50
|
-
// src/utils/intl_format.ts
|
|
51
186
|
var formatters = /* @__PURE__ */ new WeakMap();
|
|
52
187
|
function intlFormatter(factory, locale, options, fallbackLocale) {
|
|
53
188
|
const cache = cacheFor(factory);
|
|
@@ -76,7 +211,6 @@ function construct(factory, locale, options, fallbackLocale) {
|
|
|
76
211
|
}
|
|
77
212
|
}
|
|
78
213
|
|
|
79
|
-
// src/utils/dates.ts
|
|
80
214
|
function toISODateString(date) {
|
|
81
215
|
const year = date.getFullYear();
|
|
82
216
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
@@ -114,32 +248,46 @@ function monthLabelFormatter(locale) {
|
|
|
114
248
|
return intlFormatter(Intl.DateTimeFormat, locale, MONTH_LABEL_OPTIONS, "en");
|
|
115
249
|
}
|
|
116
250
|
|
|
117
|
-
|
|
251
|
+
function writeField(field, value) {
|
|
252
|
+
if (field.value === value) return false;
|
|
253
|
+
field.value = value;
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
function commitField(target) {
|
|
257
|
+
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
258
|
+
}
|
|
259
|
+
|
|
118
260
|
function resolveLocale(element, declared = "") {
|
|
119
261
|
return declared || element.closest("[lang]")?.getAttribute("lang") || void 0;
|
|
120
262
|
}
|
|
121
263
|
|
|
122
|
-
|
|
264
|
+
var ListenerSet = class {
|
|
265
|
+
#abort = new AbortController();
|
|
266
|
+
add(target, type, handler, options) {
|
|
267
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
268
|
+
}
|
|
269
|
+
dispose() {
|
|
270
|
+
this.#abort.abort();
|
|
271
|
+
this.#abort = new AbortController();
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
123
275
|
var MicrotaskCoalescer = class {
|
|
124
276
|
#run;
|
|
125
277
|
#queued = false;
|
|
126
278
|
#active = false;
|
|
127
279
|
#generation = 0;
|
|
128
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
129
280
|
constructor(run) {
|
|
130
281
|
this.#run = run;
|
|
131
282
|
}
|
|
132
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
133
283
|
activate() {
|
|
134
284
|
this.#active = true;
|
|
135
285
|
}
|
|
136
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
137
286
|
cancel() {
|
|
138
287
|
this.#active = false;
|
|
139
288
|
this.#queued = false;
|
|
140
289
|
this.#generation += 1;
|
|
141
290
|
}
|
|
142
|
-
/** Requests one pass after the batch settles. Idempotent; inert outside the window. */
|
|
143
291
|
schedule() {
|
|
144
292
|
if (!this.#active || this.#queued) return;
|
|
145
293
|
this.#queued = true;
|
|
@@ -152,43 +300,49 @@ var MicrotaskCoalescer = class {
|
|
|
152
300
|
}
|
|
153
301
|
};
|
|
154
302
|
|
|
155
|
-
|
|
303
|
+
var MorphRenderWatcher = class {
|
|
304
|
+
#listeners = new ListenerSet();
|
|
305
|
+
#pass;
|
|
306
|
+
#element = null;
|
|
307
|
+
#onMorph = () => this.#pass.schedule();
|
|
308
|
+
constructor(run) {
|
|
309
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
310
|
+
}
|
|
311
|
+
observe(element) {
|
|
312
|
+
if (this.#element === element) return;
|
|
313
|
+
this.disconnect();
|
|
314
|
+
this.#element = element;
|
|
315
|
+
this.#pass.activate();
|
|
316
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
317
|
+
}
|
|
318
|
+
schedule() {
|
|
319
|
+
this.#pass.schedule();
|
|
320
|
+
}
|
|
321
|
+
disconnect() {
|
|
322
|
+
this.#listeners.dispose();
|
|
323
|
+
this.#pass.cancel();
|
|
324
|
+
this.#element = null;
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
156
328
|
var TimerRegistry = class {
|
|
157
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
158
329
|
ids = /* @__PURE__ */ new Set();
|
|
159
|
-
/**
|
|
160
|
-
* Cancels a single tracked timer.
|
|
161
|
-
*
|
|
162
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
163
|
-
* registry), so callers can clear defensively without guarding.
|
|
164
|
-
*/
|
|
165
330
|
clear(id) {
|
|
166
331
|
if (this.ids.delete(id)) {
|
|
167
332
|
this.cancel(id);
|
|
168
333
|
}
|
|
169
334
|
}
|
|
170
|
-
/**
|
|
171
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
172
|
-
* to guarantee no timer outlives the element.
|
|
173
|
-
*/
|
|
174
335
|
clearAll() {
|
|
175
336
|
for (const id of this.ids) {
|
|
176
337
|
this.cancel(id);
|
|
177
338
|
}
|
|
178
339
|
this.ids.clear();
|
|
179
340
|
}
|
|
180
|
-
/** Number of timers currently tracked (pending). */
|
|
181
341
|
get size() {
|
|
182
342
|
return this.ids.size;
|
|
183
343
|
}
|
|
184
344
|
};
|
|
185
345
|
var SafeTimeout = class extends TimerRegistry {
|
|
186
|
-
/**
|
|
187
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
188
|
-
*
|
|
189
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
190
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
191
|
-
*/
|
|
192
346
|
set(callback, delay) {
|
|
193
347
|
const id = this.schedule(() => {
|
|
194
348
|
this.ids.delete(id);
|
|
@@ -205,7 +359,6 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
205
359
|
}
|
|
206
360
|
};
|
|
207
361
|
|
|
208
|
-
// src/utils/string_list.ts
|
|
209
362
|
function parseStringList(raw, fallback = []) {
|
|
210
363
|
const text = raw.trim();
|
|
211
364
|
if (text.length === 0) return [...fallback];
|
|
@@ -219,113 +372,125 @@ function parseStringList(raw, fallback = []) {
|
|
|
219
372
|
return parsed.filter((entry) => typeof entry === "string");
|
|
220
373
|
}
|
|
221
374
|
|
|
222
|
-
|
|
375
|
+
function targetSelector(identifier, name) {
|
|
376
|
+
return `[data-${identifier}-target~="${name}"]`;
|
|
377
|
+
}
|
|
378
|
+
|
|
223
379
|
var GRID_SIZE = 42;
|
|
224
380
|
var DateRangePickerController = class extends Controller {
|
|
381
|
+
#fieldWrites = /* @__PURE__ */ new WeakMap();
|
|
225
382
|
static targets = ["grid", "monthLabel", "cell", "status", "startField", "endField"];
|
|
226
383
|
static values = {
|
|
227
384
|
min: { type: String, default: "" },
|
|
228
385
|
max: { type: String, default: "" },
|
|
229
|
-
// A JSON list read through `parseStringList` rather than Stimulus's `Array`
|
|
230
|
-
// type: that reader throws out of the value observer before any callback
|
|
231
|
-
// runs, so one malformed attribute would stop the picker from connecting.
|
|
232
386
|
disabledDates: { type: String, default: "" },
|
|
233
387
|
locale: { type: String, default: "" }
|
|
234
388
|
};
|
|
235
389
|
static actions = ["applyPreset", "next", "onKeydown", "prev", "previewTo", "selectDate"];
|
|
236
|
-
static events = ["change", "monthchange"];
|
|
237
|
-
/** The month currently rendered, as `YYYY-MM`. */
|
|
390
|
+
static events = ["change", "monthchange", "reconcile"];
|
|
238
391
|
#viewMonth = "";
|
|
239
|
-
/** The confirmed range endpoints (ISO), or "" when unset. */
|
|
240
392
|
#startDate = "";
|
|
241
393
|
#endDate = "";
|
|
242
|
-
/** The first endpoint of an in-progress selection (ISO), or "" when idle. */
|
|
243
394
|
#pendingStart = "";
|
|
244
|
-
/** The hovered/focused date previewed while selecting (ISO), or "". */
|
|
245
395
|
#previewDate = "";
|
|
246
|
-
/** The roving-focus date in the grid (local time). */
|
|
247
396
|
#focusedDate = /* @__PURE__ */ new Date();
|
|
248
|
-
/** Deferred focus after an async month transition (cancelled on teardown). */
|
|
249
397
|
#focusTimer = new SafeTimeout();
|
|
250
|
-
|
|
398
|
+
#rangeMoves = 0;
|
|
399
|
+
#transitions = 0;
|
|
251
400
|
#disabledDates = /* @__PURE__ */ new Set();
|
|
252
|
-
/** Rewinds an unfinished selection before Turbo snapshots the page. */
|
|
253
|
-
#beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
|
|
254
|
-
/** Last painted month, or `null` until the initial paint has settled. */
|
|
255
401
|
#announcedMonth = null;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
#repaint = new
|
|
402
|
+
#multiselectable = new AttributeLease(
|
|
403
|
+
"aria-multiselectable",
|
|
404
|
+
this.identifier
|
|
405
|
+
);
|
|
406
|
+
#repaint = new MorphRenderWatcher(() => {
|
|
261
407
|
this.#render();
|
|
262
408
|
});
|
|
263
|
-
/** Seeds and normalizes the range from optional hidden fields, then paints the grid. */
|
|
264
409
|
connect() {
|
|
265
|
-
this.#repaint.
|
|
266
|
-
this.#beforeCache.activate();
|
|
410
|
+
this.#repaint.observe(this.element);
|
|
267
411
|
const authoredStart = this.hasStartFieldTarget ? normalizeISO(this.startFieldTarget.value) : "";
|
|
268
412
|
const authoredEnd = this.hasEndFieldTarget ? normalizeISO(this.endFieldTarget.value) : "";
|
|
269
|
-
[this.#startDate, this.#endDate] =
|
|
413
|
+
[this.#startDate, this.#endDate] = this.#selectableRange(
|
|
414
|
+
...orderRange(authoredStart, authoredEnd)
|
|
415
|
+
);
|
|
270
416
|
this.#pendingStart = "";
|
|
271
417
|
this.#previewDate = "";
|
|
272
418
|
this.#announcedMonth = null;
|
|
273
|
-
this.#commitFields();
|
|
274
419
|
const anchor = parseISODateString(this.#startDate) ?? this.#clampToBounds(/* @__PURE__ */ new Date()) ?? /* @__PURE__ */ new Date();
|
|
275
420
|
this.#focusedDate = anchor;
|
|
276
421
|
this.#viewMonth = toISOMonthString(anchor);
|
|
277
|
-
if (this.hasGridTarget) this.gridTarget.setAttribute("aria-multiselectable", "true");
|
|
278
422
|
this.#render();
|
|
279
423
|
}
|
|
280
|
-
/** Cancels any pending deferred focus so it never fires on a detached element. */
|
|
281
424
|
disconnect() {
|
|
282
|
-
this.#repaint.
|
|
283
|
-
this.#beforeCache.deactivate();
|
|
425
|
+
this.#repaint.disconnect();
|
|
284
426
|
this.#focusTimer.clearAll();
|
|
285
427
|
}
|
|
286
|
-
/** Repaints the label when application code changes `locale` at runtime. */
|
|
287
428
|
localeValueChanged() {
|
|
288
429
|
this.#repaint.schedule();
|
|
289
430
|
}
|
|
290
|
-
/** Repaints when application code (or a Turbo morph) changes `min` at runtime. */
|
|
291
431
|
minValueChanged() {
|
|
292
432
|
this.#repaint.schedule();
|
|
293
433
|
}
|
|
294
|
-
/** Repaints when application code (or a Turbo morph) changes `max` at runtime. */
|
|
295
434
|
maxValueChanged() {
|
|
296
435
|
this.#repaint.schedule();
|
|
297
436
|
}
|
|
298
|
-
/** Re-indexes the unavailable dates and repaints when the declared set changes. */
|
|
299
437
|
disabledDatesValueChanged() {
|
|
300
438
|
this.#disabledDates = new Set(parseStringList(this.disabledDatesValue));
|
|
301
439
|
this.#repaint.schedule();
|
|
302
440
|
}
|
|
303
|
-
|
|
441
|
+
gridTargetConnected() {
|
|
442
|
+
this.#repaint.schedule();
|
|
443
|
+
}
|
|
444
|
+
gridTargetDisconnected(grid) {
|
|
445
|
+
if (!this.gridTargets.includes(grid)) this.#multiselectable.return(grid);
|
|
446
|
+
this.#repaint.schedule();
|
|
447
|
+
}
|
|
448
|
+
monthLabelTargetConnected() {
|
|
449
|
+
this.#repaint.schedule();
|
|
450
|
+
}
|
|
451
|
+
monthLabelTargetDisconnected() {
|
|
452
|
+
this.#repaint.schedule();
|
|
453
|
+
}
|
|
454
|
+
startFieldTargetConnected() {
|
|
455
|
+
this.#repaint.schedule();
|
|
456
|
+
}
|
|
457
|
+
startFieldTargetDisconnected() {
|
|
458
|
+
this.#repaint.schedule();
|
|
459
|
+
}
|
|
460
|
+
endFieldTargetConnected() {
|
|
461
|
+
this.#repaint.schedule();
|
|
462
|
+
}
|
|
463
|
+
endFieldTargetDisconnected() {
|
|
464
|
+
this.#repaint.schedule();
|
|
465
|
+
}
|
|
304
466
|
prev(event) {
|
|
305
467
|
event?.preventDefault();
|
|
306
468
|
this.#shiftMonth(-1);
|
|
307
469
|
}
|
|
308
|
-
/** Navigates to the next month. */
|
|
309
470
|
next(event) {
|
|
310
471
|
event?.preventDefault();
|
|
311
472
|
this.#shiftMonth(1);
|
|
312
473
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
474
|
+
selectDate(source) {
|
|
475
|
+
const { origin, reason } = actionSource(source);
|
|
476
|
+
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
477
|
+
return;
|
|
478
|
+
const cell = this.#cellFrom(origin);
|
|
316
479
|
if (!cell) return;
|
|
317
480
|
const date = cell.getAttribute("data-date");
|
|
318
481
|
if (!date || !this.#isSelectable(date)) return;
|
|
319
|
-
this.#choose(date);
|
|
482
|
+
this.#choose(date, reason);
|
|
320
483
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
484
|
+
previewTo(source) {
|
|
485
|
+
const { event, origin } = actionSource(source);
|
|
486
|
+
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
487
|
+
return;
|
|
488
|
+
const cell = this.#cellFrom(origin);
|
|
324
489
|
if (!cell) return;
|
|
325
490
|
const date = cell.getAttribute("data-date");
|
|
326
491
|
if (!date) return;
|
|
327
492
|
let shouldRender = false;
|
|
328
|
-
if (event
|
|
493
|
+
if (event?.type.startsWith("focus")) {
|
|
329
494
|
const parsed = parseISODateString(date);
|
|
330
495
|
if (parsed) this.#focusedDate = parsed;
|
|
331
496
|
shouldRender = cell.getAttribute("tabindex") !== "0";
|
|
@@ -336,27 +501,28 @@ var DateRangePickerController = class extends Controller {
|
|
|
336
501
|
}
|
|
337
502
|
if (shouldRender) this.#render();
|
|
338
503
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const button =
|
|
504
|
+
applyPreset(source) {
|
|
505
|
+
const { event, origin, reason } = actionSource(source);
|
|
506
|
+
const button = origin?.closest("[data-range]");
|
|
507
|
+
if (!button || !this.element.contains(button)) return;
|
|
508
|
+
const focus = event !== null || this.element.contains(document.activeElement);
|
|
342
509
|
const range = computePreset(button?.getAttribute("data-range") ?? "");
|
|
343
510
|
if (!range) return;
|
|
344
511
|
const intersection = this.#intersectRange(range);
|
|
345
512
|
if (!intersection) return;
|
|
346
513
|
const { start, end } = intersection;
|
|
347
514
|
if (!this.#isSelectable(start) || !this.#isSelectable(end)) return;
|
|
348
|
-
|
|
349
|
-
this.#endDate = end;
|
|
350
|
-
this.#pendingStart = "";
|
|
351
|
-
this.#previewDate = "";
|
|
515
|
+
const move = this.#setConfirmed(start, end);
|
|
352
516
|
const endDate = parseISODateString(end);
|
|
353
517
|
if (endDate) this.#focusedDate = endDate;
|
|
354
|
-
this.#
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
518
|
+
this.#transitionTo(
|
|
519
|
+
toISOMonthString(parseISODateString(end) ?? /* @__PURE__ */ new Date()),
|
|
520
|
+
end,
|
|
521
|
+
true,
|
|
522
|
+
() => focus && (event !== null || this.element.contains(document.activeElement))
|
|
523
|
+
);
|
|
524
|
+
this.#reportConfirmed(move, reason);
|
|
358
525
|
}
|
|
359
|
-
/** Grid keyboard navigation, selection (Enter/Space), and Escape-to-cancel. */
|
|
360
526
|
onKeydown(event) {
|
|
361
527
|
if (event.defaultPrevented) return;
|
|
362
528
|
if (isReservedArrowChord(event)) return;
|
|
@@ -411,9 +577,8 @@ var DateRangePickerController = class extends Controller {
|
|
|
411
577
|
event.preventDefault();
|
|
412
578
|
this.#moveFocusTo(next);
|
|
413
579
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (!this.#pendingStart) {
|
|
580
|
+
#choose(date, reason = "user") {
|
|
581
|
+
if (!this.#pendingStart || !this.#isSelectable(this.#pendingStart)) {
|
|
417
582
|
this.#pendingStart = date;
|
|
418
583
|
this.#previewDate = date;
|
|
419
584
|
const parsed = parseISODateString(date);
|
|
@@ -422,29 +587,40 @@ var DateRangePickerController = class extends Controller {
|
|
|
422
587
|
return;
|
|
423
588
|
}
|
|
424
589
|
const [start, end] = date < this.#pendingStart ? [date, this.#pendingStart] : [this.#pendingStart, date];
|
|
590
|
+
const move = this.#setConfirmed(start, end);
|
|
591
|
+
this.#render(true);
|
|
592
|
+
this.#reportConfirmed(move, reason);
|
|
593
|
+
}
|
|
594
|
+
#setConfirmed(start, end) {
|
|
595
|
+
const changed = start !== this.#startDate || end !== this.#endDate;
|
|
425
596
|
this.#startDate = start;
|
|
426
597
|
this.#endDate = end;
|
|
427
598
|
this.#pendingStart = "";
|
|
428
599
|
this.#previewDate = "";
|
|
429
|
-
|
|
430
|
-
this.#
|
|
431
|
-
this.#
|
|
432
|
-
|
|
600
|
+
if (!changed) return null;
|
|
601
|
+
this.#rangeMoves += 1;
|
|
602
|
+
return this.#rangeMoves;
|
|
603
|
+
}
|
|
604
|
+
#reportConfirmed(move, reason) {
|
|
605
|
+
if (move === null || move !== this.#rangeMoves) return;
|
|
606
|
+
this.dispatch("change", { detail: { start: this.#startDate, end: this.#endDate, reason } });
|
|
433
607
|
}
|
|
434
|
-
/** Moves roving focus to `date`, transitioning the month when needed. */
|
|
435
608
|
#moveFocusTo(date) {
|
|
436
609
|
this.#focusedDate = date;
|
|
437
610
|
const iso = toISODateString(date);
|
|
438
611
|
if (this.#pendingStart && this.#isSelectable(iso)) this.#previewDate = iso;
|
|
439
612
|
this.#transitionTo(toISOMonthString(date), iso);
|
|
440
613
|
}
|
|
441
|
-
|
|
442
|
-
#transitionTo(month, dateStr) {
|
|
614
|
+
#transitionTo(month, dateStr, confirmed = false, canFocus = () => true) {
|
|
443
615
|
const isTransition = month !== this.#viewMonth;
|
|
444
616
|
this.#focusTimer.clearAll();
|
|
445
617
|
this.#viewMonth = month;
|
|
446
|
-
this.#
|
|
618
|
+
this.#transitions += 1;
|
|
619
|
+
const transition = this.#transitions;
|
|
620
|
+
this.#render(confirmed);
|
|
621
|
+
if (transition !== this.#transitions || !canFocus()) return;
|
|
447
622
|
const focusCell = () => {
|
|
623
|
+
if (!canFocus()) return;
|
|
448
624
|
this.cellTargets.find((c) => c.getAttribute("data-date") === dateStr)?.focus();
|
|
449
625
|
};
|
|
450
626
|
if (isTransition) {
|
|
@@ -453,7 +629,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
453
629
|
focusCell();
|
|
454
630
|
}
|
|
455
631
|
}
|
|
456
|
-
/** Shifts the displayed month by `delta`, keeping focus within it. */
|
|
457
632
|
#shiftMonth(delta) {
|
|
458
633
|
const info = parseISOMonthString(this.#viewMonth);
|
|
459
634
|
if (!info) return;
|
|
@@ -464,16 +639,17 @@ var DateRangePickerController = class extends Controller {
|
|
|
464
639
|
this.#focusedDate = target;
|
|
465
640
|
this.#render();
|
|
466
641
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
*
|
|
470
|
-
* @stimeoRenderRoot
|
|
471
|
-
*/
|
|
472
|
-
#render() {
|
|
642
|
+
#render(confirmed = false) {
|
|
643
|
+
if (this.hasGridTarget) this.#multiselectable.write(this.gridTarget, "true");
|
|
473
644
|
const info = parseISOMonthString(this.#viewMonth);
|
|
474
645
|
if (!info) return;
|
|
475
646
|
const { year, month } = info;
|
|
647
|
+
if (this.#pendingStart && !this.#isSelectable(this.#pendingStart)) {
|
|
648
|
+
this.#pendingStart = "";
|
|
649
|
+
this.#previewDate = "";
|
|
650
|
+
}
|
|
476
651
|
if (this.#previewDate && !this.#isSelectable(this.#previewDate)) this.#previewDate = "";
|
|
652
|
+
const narrowed = this.#narrowConfirmedRange();
|
|
477
653
|
if (this.hasMonthLabelTarget) {
|
|
478
654
|
const formatter = monthLabelFormatter(resolveLocale(this.element, this.localeValue));
|
|
479
655
|
this.monthLabelTarget.textContent = formatter.format(new Date(year, month - 1, 1));
|
|
@@ -513,13 +689,44 @@ var DateRangePickerController = class extends Controller {
|
|
|
513
689
|
const fallback = cells.find((cell) => cell.getAttribute("data-outside") === "false") ?? cells[0];
|
|
514
690
|
fallback?.setAttribute("tabindex", "0");
|
|
515
691
|
}
|
|
692
|
+
const move = this.#rangeMoves;
|
|
693
|
+
const moved = this.#mirrorFields();
|
|
694
|
+
if (confirmed) {
|
|
695
|
+
this.#announce();
|
|
696
|
+
for (const [field, value, write] of moved) {
|
|
697
|
+
if (field.value === value && this.#fieldWrites.get(field) === write) commitField(field);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
516
700
|
const previous = this.#announcedMonth;
|
|
517
701
|
this.#announcedMonth = this.#viewMonth;
|
|
518
702
|
if (previous !== null && previous !== this.#viewMonth) {
|
|
519
703
|
this.dispatch("monthchange", { detail: { month: this.#viewMonth } });
|
|
520
704
|
}
|
|
705
|
+
if (narrowed && move === this.#rangeMoves) {
|
|
706
|
+
this.dispatch("reconcile", { detail: { start: this.#startDate, end: this.#endDate } });
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
#narrowConfirmedRange() {
|
|
710
|
+
const [start, end] = this.#selectableRange(this.#startDate, this.#endDate);
|
|
711
|
+
if (start === this.#startDate && end === this.#endDate) return false;
|
|
712
|
+
this.#startDate = start;
|
|
713
|
+
this.#endDate = end;
|
|
714
|
+
this.#rangeMoves += 1;
|
|
715
|
+
return true;
|
|
716
|
+
}
|
|
717
|
+
#selectableRange(start, end) {
|
|
718
|
+
let from = parseISODateString(start || end);
|
|
719
|
+
let to = parseISODateString(end || start);
|
|
720
|
+
if (!from || !to) return [start, end];
|
|
721
|
+
while (from.getTime() <= to.getTime() && !this.#isSelectable(toISODateString(from))) {
|
|
722
|
+
from = addDays(from, 1);
|
|
723
|
+
}
|
|
724
|
+
while (to.getTime() >= from.getTime() && !this.#isSelectable(toISODateString(to))) {
|
|
725
|
+
to = addDays(to, -1);
|
|
726
|
+
}
|
|
727
|
+
if (from.getTime() > to.getTime()) return ["", ""];
|
|
728
|
+
return [start ? toISODateString(from) : "", end ? toISODateString(to) : ""];
|
|
521
729
|
}
|
|
522
|
-
/** The ordered [start, end] pair to paint: the preview while selecting, else confirmed. */
|
|
523
730
|
#visualRange() {
|
|
524
731
|
if (this.#pendingStart) {
|
|
525
732
|
const other = this.#previewDate || this.#pendingStart;
|
|
@@ -527,71 +734,59 @@ var DateRangePickerController = class extends Controller {
|
|
|
527
734
|
}
|
|
528
735
|
return [this.#startDate, this.#endDate];
|
|
529
736
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
737
|
+
#writeField(field, value) {
|
|
738
|
+
if (!writeField(field, value)) return false;
|
|
739
|
+
this.#fieldWrites.set(field, (this.#fieldWrites.get(field) ?? 0) + 1);
|
|
740
|
+
return true;
|
|
741
|
+
}
|
|
742
|
+
#mirrorFields() {
|
|
743
|
+
const moved = [];
|
|
744
|
+
if (this.hasStartFieldTarget && this.#writeField(this.startFieldTarget, this.#startDate)) {
|
|
745
|
+
moved.push([
|
|
746
|
+
this.startFieldTarget,
|
|
747
|
+
this.#startDate,
|
|
748
|
+
this.#fieldWrites.get(this.startFieldTarget) ?? 0
|
|
749
|
+
]);
|
|
750
|
+
}
|
|
751
|
+
if (this.hasEndFieldTarget && this.#writeField(this.endFieldTarget, this.#endDate)) {
|
|
752
|
+
moved.push([
|
|
753
|
+
this.endFieldTarget,
|
|
754
|
+
this.#endDate,
|
|
755
|
+
this.#fieldWrites.get(this.endFieldTarget) ?? 0
|
|
756
|
+
]);
|
|
757
|
+
}
|
|
758
|
+
return moved;
|
|
534
759
|
}
|
|
535
|
-
/** Announces the confirmed range in the live status region. */
|
|
536
760
|
#announce() {
|
|
537
761
|
if (this.hasStatusTarget && this.#startDate && this.#endDate) {
|
|
538
762
|
this.statusTarget.textContent = `${this.#startDate} \u2013 ${this.#endDate}`;
|
|
539
763
|
}
|
|
540
764
|
}
|
|
541
|
-
/**
|
|
542
|
-
* True when `iso` may be chosen as a range endpoint.
|
|
543
|
-
*
|
|
544
|
-
* The single availability question in the controller: the grid paint, the
|
|
545
|
-
* preview, and both commit paths ask it, so a cell's `aria-disabled` and what
|
|
546
|
-
* a click on that cell does are the same decision rather than two that have to
|
|
547
|
-
* be kept in step.
|
|
548
|
-
*/
|
|
549
765
|
#isSelectable(iso) {
|
|
550
766
|
return !this.#outOfBounds(iso) && !this.#disabledDates.has(iso);
|
|
551
767
|
}
|
|
552
|
-
/** True when `iso` falls outside the `[min, max]` bounds. */
|
|
553
768
|
#outOfBounds(iso) {
|
|
554
769
|
if (this.minValue && iso < this.minValue) return true;
|
|
555
770
|
if (this.maxValue && iso > this.maxValue) return true;
|
|
556
771
|
return false;
|
|
557
772
|
}
|
|
558
|
-
/** Clamps a generated ISO date string into `[min, max]`. */
|
|
559
773
|
#clampISO(iso) {
|
|
560
774
|
if (this.minValue && iso < this.minValue) return this.minValue;
|
|
561
775
|
if (this.maxValue && iso > this.maxValue) return this.maxValue;
|
|
562
776
|
return iso;
|
|
563
777
|
}
|
|
564
|
-
/** Clamps a Date into `[min, max]`, returning null only when unparseable. */
|
|
565
778
|
#clampToBounds(date) {
|
|
566
779
|
const clamped = this.#clampISO(toISODateString(date));
|
|
567
780
|
return parseISODateString(clamped);
|
|
568
781
|
}
|
|
569
|
-
/**
|
|
570
|
-
* Intersects a preset with `[min, max]`, rejecting a disjoint interval.
|
|
571
|
-
*
|
|
572
|
-
* Only the bounds narrow a preset here: `disabledDates` excludes single days,
|
|
573
|
-
* not sub-intervals, so it cannot shrink one to a still-contiguous range. A
|
|
574
|
-
* day it excludes is still refused as an endpoint — the caller checks that —
|
|
575
|
-
* but a preset that merely spans one keeps its span.
|
|
576
|
-
*/
|
|
577
782
|
#intersectRange(range) {
|
|
578
783
|
const start = this.minValue && range.start < this.minValue ? this.minValue : range.start;
|
|
579
784
|
const end = this.maxValue && range.end > this.maxValue ? this.maxValue : range.end;
|
|
580
785
|
return start <= end ? { start, end } : null;
|
|
581
786
|
}
|
|
582
|
-
/** Removes provisional range state before Turbo freezes a cached snapshot. */
|
|
583
|
-
#rewindForCache() {
|
|
584
|
-
this.#focusTimer.clearAll();
|
|
585
|
-
if (!this.#pendingStart && !this.#previewDate) return;
|
|
586
|
-
this.#pendingStart = "";
|
|
587
|
-
this.#previewDate = "";
|
|
588
|
-
this.#render();
|
|
589
|
-
}
|
|
590
|
-
/** Resolves the cell element from an event target, or null. */
|
|
591
787
|
#cellFrom(target) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
) ?? null;
|
|
788
|
+
const cell = target instanceof Element ? target.closest(targetSelector(this.identifier, "cell")) : null;
|
|
789
|
+
return cell && this.cellTargets.includes(cell) ? cell : null;
|
|
595
790
|
}
|
|
596
791
|
};
|
|
597
792
|
function addDays(date, n) {
|
|
@@ -651,5 +846,4 @@ function computePreset(name) {
|
|
|
651
846
|
}
|
|
652
847
|
|
|
653
848
|
export { DateRangePickerController };
|
|
654
|
-
//# sourceMappingURL=date_range_picker_controller.js.map
|
|
655
849
|
//# sourceMappingURL=date_range_picker_controller.js.map
|