stimeo-ui 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +8 -1
- package/dist/cable/index.d.ts +79 -23
- package/dist/cable/index.js +363 -436
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +4 -2
- package/dist/controllers/accordion_controller.js +166 -55
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +12 -2
- package/dist/controllers/alert_dialog_controller.js +862 -221
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +35 -5
- package/dist/controllers/announcer_controller.js +135 -198
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/aspect_ratio_controller.js +0 -10
- package/dist/controllers/aspect_ratio_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.d.ts +30 -6
- package/dist/controllers/auto_submit_controller.js +271 -127
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +171 -105
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.js +0 -130
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +18 -0
- package/dist/controllers/bulk_select_controller.js +262 -52
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +24 -5
- package/dist/controllers/calendar_controller.js +175 -209
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +34 -7
- package/dist/controllers/carousel_controller.js +461 -399
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +17 -1
- package/dist/controllers/character_counter_controller.js +246 -156
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.d.ts +7 -2
- package/dist/controllers/checkbox_controller.js +32 -74
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +16 -5
- package/dist/controllers/clipboard_controller.js +168 -147
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +16 -4
- package/dist/controllers/collapsible_controller.js +301 -120
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +18 -6
- package/dist/controllers/color_picker_controller.js +149 -139
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +23 -5
- package/dist/controllers/combobox_controller.js +360 -133
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +45 -14
- package/dist/controllers/command_palette_controller.js +970 -358
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.d.ts +15 -2
- package/dist/controllers/conditional_fields_controller.js +166 -124
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +49 -12
- package/dist/controllers/confirm_controller.js +939 -248
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +31 -4
- package/dist/controllers/context_menu_controller.js +256 -128
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.d.ts +13 -1
- package/dist/controllers/count_up_controller.js +73 -21
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +45 -1
- package/dist/controllers/countdown_controller.js +183 -148
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +21 -2
- package/dist/controllers/currency_input_controller.js +134 -158
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +15 -4
- package/dist/controllers/data_grid_controller.js +114 -186
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +30 -5
- package/dist/controllers/date_range_picker_controller.js +288 -206
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +13 -1
- package/dist/controllers/dialog_controller.js +858 -223
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +24 -7
- package/dist/controllers/direct_upload_controller.js +73 -153
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.js +14 -48
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.d.ts +19 -0
- package/dist/controllers/dismissible_controller.js +175 -21
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +39 -11
- package/dist/controllers/drawer_controller.js +933 -341
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +31 -1
- package/dist/controllers/dropdown_controller.js +312 -82
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.d.ts +12 -1
- package/dist/controllers/editable_controller.js +158 -68
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.js +67 -53
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +60 -18
- package/dist/controllers/file_dropzone_controller.js +311 -207
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.js +67 -39
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +31 -8
- package/dist/controllers/flash_controller.js +172 -314
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +12 -3
- package/dist/controllers/focus_controller.js +654 -240
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +147 -132
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +13 -86
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +41 -9
- package/dist/controllers/frame_loading_controller.js +264 -213
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +22 -2
- package/dist/controllers/highlight_controller.js +107 -75
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +56 -3
- package/dist/controllers/hover_card_controller.js +309 -118
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +42 -1
- package/dist/controllers/idle_controller.js +267 -101
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.js +71 -72
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.d.ts +32 -13
- package/dist/controllers/intersection_controller.js +147 -106
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +16 -0
- package/dist/controllers/lazy_frame_controller.js +9 -65
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +34 -2
- package/dist/controllers/listbox_controller.js +306 -204
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +1 -1
- package/dist/controllers/local_time_controller.js +54 -64
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +11 -3
- package/dist/controllers/masonry_controller.js +70 -93
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +32 -7
- package/dist/controllers/menu_controller.js +214 -156
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +4 -4
- package/dist/controllers/menubar_controller.js +170 -329
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +20 -0
- package/dist/controllers/meter_controller.js +151 -67
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +32 -4
- package/dist/controllers/multi_select_controller.js +593 -358
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +8 -1
- package/dist/controllers/navigation_menu_controller.js +124 -232
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.d.ts +10 -0
- package/dist/controllers/nested_form_controller.js +352 -182
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.d.ts +23 -0
- package/dist/controllers/network_status_controller.js +242 -54
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +26 -2
- package/dist/controllers/number_input_controller.js +320 -263
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +16 -76
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +20 -4
- package/dist/controllers/otp_controller.js +198 -193
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
- package/dist/controllers/overflow_indicator_controller.js +116 -113
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +48 -11
- package/dist/controllers/overflow_menu_controller.js +343 -283
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +35 -6
- package/dist/controllers/pagination_controller.js +295 -119
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +45 -8
- package/dist/controllers/password_reveal_controller.js +389 -121
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +14 -5
- package/dist/controllers/password_strength_controller.js +99 -153
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +11 -4
- package/dist/controllers/persist_controller.js +237 -103
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +19 -7
- package/dist/controllers/pointer_drag_controller.js +185 -165
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +38 -2
- package/dist/controllers/popover_controller.js +236 -97
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +44 -4
- package/dist/controllers/portal_controller.js +209 -76
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.d.ts +10 -4
- package/dist/controllers/preview_guard_controller.js +232 -116
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +11 -0
- package/dist/controllers/progress_controller.js +125 -56
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +14 -5
- package/dist/controllers/radio_group_controller.js +117 -137
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +43 -3
- package/dist/controllers/range_slider_controller.js +192 -105
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +20 -4
- package/dist/controllers/rating_controller.js +418 -207
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +2 -0
- package/dist/controllers/read_more_controller.js +134 -63
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +1 -1
- package/dist/controllers/reading_progress_controller.js +147 -135
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.d.ts +18 -4
- package/dist/controllers/relative_time_controller.js +145 -110
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
- package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
- package/dist/controllers/reset_on_restore_controller.js.map +1 -0
- package/dist/controllers/resizable_controller.d.ts +28 -2
- package/dist/controllers/resizable_controller.js +255 -139
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.js +39 -84
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +7 -3
- package/dist/controllers/scroll_area_controller.js +428 -225
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.js +0 -53
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
- package/dist/controllers/scroll_visibility_controller.js +395 -145
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +6 -1
- package/dist/controllers/scrollspy_controller.js +181 -242
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +19 -4
- package/dist/controllers/separator_controller.js +267 -140
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +64 -7
- package/dist/controllers/sidebar_controller.js +1023 -386
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +23 -0
- package/dist/controllers/skeleton_controller.js +248 -97
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +27 -1
- package/dist/controllers/slider_controller.js +159 -79
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
- package/dist/controllers/smart_sticky_header_controller.js +162 -63
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +0 -112
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +39 -4
- package/dist/controllers/spinner_controller.js +277 -169
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +5 -0
- package/dist/controllers/step_indicator_controller.js +99 -46
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +12 -3
- package/dist/controllers/stepper_controller.js +114 -73
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +6 -0
- package/dist/controllers/stick_to_bottom_controller.js +262 -138
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.d.ts +11 -0
- package/dist/controllers/sticky_observer_controller.js +214 -49
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +23 -8
- package/dist/controllers/submit_once_controller.js +294 -205
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +12 -1
- package/dist/controllers/switch_controller.js +33 -60
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +2 -2
- package/dist/controllers/tabs_controller.js +35 -29
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +12 -0
- package/dist/controllers/tags_input_controller.js +136 -145
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
- package/dist/controllers/textarea_autosize_controller.js +71 -58
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +21 -9
- package/dist/controllers/theme_controller.js +130 -112
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +18 -1
- package/dist/controllers/time_picker_controller.js +146 -80
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +36 -11
- package/dist/controllers/toast_controller.js +186 -297
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +12 -3
- package/dist/controllers/toggle_group_controller.js +95 -136
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +68 -98
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +45 -3
- package/dist/controllers/tooltip_controller.js +158 -124
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.d.ts +22 -4
- package/dist/controllers/transition_controller.js +123 -119
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +21 -11
- package/dist/controllers/tree_view_controller.js +150 -345
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6370 -9346
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +23 -3
- package/dist/inspector/cli.js +92 -37
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +92 -56
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +8 -8
- package/dist/inspector/manifest.json +787 -100
- package/dist/positioning/index.d.ts +8 -0
- package/dist/positioning/index.js +148 -47
- package/dist/positioning/index.js.map +1 -1
- package/package.json +6 -6
- package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
- package/dist/controllers/reset_before_cache_controller.js.map +0 -1
|
@@ -1,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,7 +248,6 @@ function monthLabelFormatter(locale) {
|
|
|
114
248
|
return intlFormatter(Intl.DateTimeFormat, locale, MONTH_LABEL_OPTIONS, "en");
|
|
115
249
|
}
|
|
116
250
|
|
|
117
|
-
// src/utils/field_mirror.ts
|
|
118
251
|
function writeField(field, value) {
|
|
119
252
|
if (field.value === value) return false;
|
|
120
253
|
field.value = value;
|
|
@@ -124,32 +257,37 @@ function commitField(target) {
|
|
|
124
257
|
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
125
258
|
}
|
|
126
259
|
|
|
127
|
-
// src/utils/locale.ts
|
|
128
260
|
function resolveLocale(element, declared = "") {
|
|
129
261
|
return declared || element.closest("[lang]")?.getAttribute("lang") || void 0;
|
|
130
262
|
}
|
|
131
263
|
|
|
132
|
-
|
|
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
|
+
|
|
133
275
|
var MicrotaskCoalescer = class {
|
|
134
276
|
#run;
|
|
135
277
|
#queued = false;
|
|
136
278
|
#active = false;
|
|
137
279
|
#generation = 0;
|
|
138
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
139
280
|
constructor(run) {
|
|
140
281
|
this.#run = run;
|
|
141
282
|
}
|
|
142
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
143
283
|
activate() {
|
|
144
284
|
this.#active = true;
|
|
145
285
|
}
|
|
146
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
147
286
|
cancel() {
|
|
148
287
|
this.#active = false;
|
|
149
288
|
this.#queued = false;
|
|
150
289
|
this.#generation += 1;
|
|
151
290
|
}
|
|
152
|
-
/** Requests one pass after the batch settles. Idempotent; inert outside the window. */
|
|
153
291
|
schedule() {
|
|
154
292
|
if (!this.#active || this.#queued) return;
|
|
155
293
|
this.#queued = true;
|
|
@@ -162,43 +300,49 @@ var MicrotaskCoalescer = class {
|
|
|
162
300
|
}
|
|
163
301
|
};
|
|
164
302
|
|
|
165
|
-
|
|
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
|
+
|
|
166
328
|
var TimerRegistry = class {
|
|
167
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
168
329
|
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
330
|
clear(id) {
|
|
176
331
|
if (this.ids.delete(id)) {
|
|
177
332
|
this.cancel(id);
|
|
178
333
|
}
|
|
179
334
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
182
|
-
* to guarantee no timer outlives the element.
|
|
183
|
-
*/
|
|
184
335
|
clearAll() {
|
|
185
336
|
for (const id of this.ids) {
|
|
186
337
|
this.cancel(id);
|
|
187
338
|
}
|
|
188
339
|
this.ids.clear();
|
|
189
340
|
}
|
|
190
|
-
/** Number of timers currently tracked (pending). */
|
|
191
341
|
get size() {
|
|
192
342
|
return this.ids.size;
|
|
193
343
|
}
|
|
194
344
|
};
|
|
195
345
|
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
346
|
set(callback, delay) {
|
|
203
347
|
const id = this.schedule(() => {
|
|
204
348
|
this.ids.delete(id);
|
|
@@ -215,7 +359,6 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
215
359
|
}
|
|
216
360
|
};
|
|
217
361
|
|
|
218
|
-
// src/utils/string_list.ts
|
|
219
362
|
function parseStringList(raw, fallback = []) {
|
|
220
363
|
const text = raw.trim();
|
|
221
364
|
if (text.length === 0) return [...fallback];
|
|
@@ -229,67 +372,42 @@ function parseStringList(raw, fallback = []) {
|
|
|
229
372
|
return parsed.filter((entry) => typeof entry === "string");
|
|
230
373
|
}
|
|
231
374
|
|
|
232
|
-
// src/utils/target_selector.ts
|
|
233
375
|
function targetSelector(identifier, name) {
|
|
234
376
|
return `[data-${identifier}-target~="${name}"]`;
|
|
235
377
|
}
|
|
236
378
|
|
|
237
|
-
// src/controllers/date_range_picker_controller.ts
|
|
238
379
|
var GRID_SIZE = 42;
|
|
239
380
|
var DateRangePickerController = class extends Controller {
|
|
381
|
+
#fieldWrites = /* @__PURE__ */ new WeakMap();
|
|
240
382
|
static targets = ["grid", "monthLabel", "cell", "status", "startField", "endField"];
|
|
241
383
|
static values = {
|
|
242
384
|
min: { type: String, default: "" },
|
|
243
385
|
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
386
|
disabledDates: { type: String, default: "" },
|
|
248
387
|
locale: { type: String, default: "" }
|
|
249
388
|
};
|
|
250
389
|
static actions = ["applyPreset", "next", "onKeydown", "prev", "previewTo", "selectDate"];
|
|
251
390
|
static events = ["change", "monthchange", "reconcile"];
|
|
252
|
-
/** The month currently rendered, as `YYYY-MM`. */
|
|
253
391
|
#viewMonth = "";
|
|
254
|
-
/** The confirmed range endpoints (ISO), or "" when unset. */
|
|
255
392
|
#startDate = "";
|
|
256
393
|
#endDate = "";
|
|
257
|
-
/** The first endpoint of an in-progress selection (ISO), or "" when idle. */
|
|
258
394
|
#pendingStart = "";
|
|
259
|
-
/** The hovered/focused date previewed while selecting (ISO), or "". */
|
|
260
395
|
#previewDate = "";
|
|
261
|
-
/** The roving-focus date in the grid (local time). */
|
|
262
396
|
#focusedDate = /* @__PURE__ */ new Date();
|
|
263
|
-
/** Deferred focus after an async month transition (cancelled on teardown). */
|
|
264
397
|
#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
398
|
#rangeMoves = 0;
|
|
270
|
-
/** How many month transitions have started, so one a listener starts mid-paint keeps its focus. */
|
|
271
399
|
#transitions = 0;
|
|
272
|
-
/** The declared unavailable dates, indexed for the per-cell paint lookup. */
|
|
273
400
|
#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
401
|
#announcedMonth = null;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
#repaint = new
|
|
402
|
+
#multiselectable = new AttributeLease(
|
|
403
|
+
"aria-multiselectable",
|
|
404
|
+
this.identifier
|
|
405
|
+
);
|
|
406
|
+
#repaint = new MorphRenderWatcher(() => {
|
|
283
407
|
this.#render();
|
|
284
408
|
});
|
|
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
409
|
connect() {
|
|
291
|
-
this.#repaint.
|
|
292
|
-
this.#beforeCache.activate();
|
|
410
|
+
this.#repaint.observe(this.element);
|
|
293
411
|
const authoredStart = this.hasStartFieldTarget ? normalizeISO(this.startFieldTarget.value) : "";
|
|
294
412
|
const authoredEnd = this.hasEndFieldTarget ? normalizeISO(this.endFieldTarget.value) : "";
|
|
295
413
|
[this.#startDate, this.#endDate] = this.#selectableRange(
|
|
@@ -301,58 +419,78 @@ var DateRangePickerController = class extends Controller {
|
|
|
301
419
|
const anchor = parseISODateString(this.#startDate) ?? this.#clampToBounds(/* @__PURE__ */ new Date()) ?? /* @__PURE__ */ new Date();
|
|
302
420
|
this.#focusedDate = anchor;
|
|
303
421
|
this.#viewMonth = toISOMonthString(anchor);
|
|
304
|
-
if (this.hasGridTarget) this.gridTarget.setAttribute("aria-multiselectable", "true");
|
|
305
422
|
this.#render();
|
|
306
423
|
}
|
|
307
|
-
/** Cancels any pending deferred focus so it never fires on a detached element. */
|
|
308
424
|
disconnect() {
|
|
309
|
-
this.#repaint.
|
|
310
|
-
this.#beforeCache.deactivate();
|
|
425
|
+
this.#repaint.disconnect();
|
|
311
426
|
this.#focusTimer.clearAll();
|
|
312
427
|
}
|
|
313
|
-
/** Repaints the label when application code changes `locale` at runtime. */
|
|
314
428
|
localeValueChanged() {
|
|
315
429
|
this.#repaint.schedule();
|
|
316
430
|
}
|
|
317
|
-
/** Repaints when application code (or a Turbo morph) changes `min` at runtime. */
|
|
318
431
|
minValueChanged() {
|
|
319
432
|
this.#repaint.schedule();
|
|
320
433
|
}
|
|
321
|
-
/** Repaints when application code (or a Turbo morph) changes `max` at runtime. */
|
|
322
434
|
maxValueChanged() {
|
|
323
435
|
this.#repaint.schedule();
|
|
324
436
|
}
|
|
325
|
-
/** Re-indexes the unavailable dates and repaints when the declared set changes. */
|
|
326
437
|
disabledDatesValueChanged() {
|
|
327
438
|
this.#disabledDates = new Set(parseStringList(this.disabledDatesValue));
|
|
328
439
|
this.#repaint.schedule();
|
|
329
440
|
}
|
|
330
|
-
|
|
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
|
+
}
|
|
331
466
|
prev(event) {
|
|
332
467
|
event?.preventDefault();
|
|
333
468
|
this.#shiftMonth(-1);
|
|
334
469
|
}
|
|
335
|
-
/** Navigates to the next month. */
|
|
336
470
|
next(event) {
|
|
337
471
|
event?.preventDefault();
|
|
338
472
|
this.#shiftMonth(1);
|
|
339
473
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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);
|
|
343
479
|
if (!cell) return;
|
|
344
480
|
const date = cell.getAttribute("data-date");
|
|
345
481
|
if (!date || !this.#isSelectable(date)) return;
|
|
346
|
-
this.#choose(date);
|
|
482
|
+
this.#choose(date, reason);
|
|
347
483
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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);
|
|
351
489
|
if (!cell) return;
|
|
352
490
|
const date = cell.getAttribute("data-date");
|
|
353
491
|
if (!date) return;
|
|
354
492
|
let shouldRender = false;
|
|
355
|
-
if (event
|
|
493
|
+
if (event?.type.startsWith("focus")) {
|
|
356
494
|
const parsed = parseISODateString(date);
|
|
357
495
|
if (parsed) this.#focusedDate = parsed;
|
|
358
496
|
shouldRender = cell.getAttribute("tabindex") !== "0";
|
|
@@ -363,9 +501,11 @@ var DateRangePickerController = class extends Controller {
|
|
|
363
501
|
}
|
|
364
502
|
if (shouldRender) this.#render();
|
|
365
503
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
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);
|
|
369
509
|
const range = computePreset(button?.getAttribute("data-range") ?? "");
|
|
370
510
|
if (!range) return;
|
|
371
511
|
const intersection = this.#intersectRange(range);
|
|
@@ -375,10 +515,14 @@ var DateRangePickerController = class extends Controller {
|
|
|
375
515
|
const move = this.#setConfirmed(start, end);
|
|
376
516
|
const endDate = parseISODateString(end);
|
|
377
517
|
if (endDate) this.#focusedDate = endDate;
|
|
378
|
-
this.#transitionTo(
|
|
379
|
-
|
|
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);
|
|
380
525
|
}
|
|
381
|
-
/** Grid keyboard navigation, selection (Enter/Space), and Escape-to-cancel. */
|
|
382
526
|
onKeydown(event) {
|
|
383
527
|
if (event.defaultPrevented) return;
|
|
384
528
|
if (isReservedArrowChord(event)) return;
|
|
@@ -433,8 +577,7 @@ var DateRangePickerController = class extends Controller {
|
|
|
433
577
|
event.preventDefault();
|
|
434
578
|
this.#moveFocusTo(next);
|
|
435
579
|
}
|
|
436
|
-
|
|
437
|
-
#choose(date) {
|
|
580
|
+
#choose(date, reason = "user") {
|
|
438
581
|
if (!this.#pendingStart || !this.#isSelectable(this.#pendingStart)) {
|
|
439
582
|
this.#pendingStart = date;
|
|
440
583
|
this.#previewDate = date;
|
|
@@ -446,54 +589,38 @@ var DateRangePickerController = class extends Controller {
|
|
|
446
589
|
const [start, end] = date < this.#pendingStart ? [date, this.#pendingStart] : [this.#pendingStart, date];
|
|
447
590
|
const move = this.#setConfirmed(start, end);
|
|
448
591
|
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
|
-
*/
|
|
592
|
+
this.#reportConfirmed(move, reason);
|
|
593
|
+
}
|
|
457
594
|
#setConfirmed(start, end) {
|
|
595
|
+
const changed = start !== this.#startDate || end !== this.#endDate;
|
|
458
596
|
this.#startDate = start;
|
|
459
597
|
this.#endDate = end;
|
|
460
598
|
this.#pendingStart = "";
|
|
461
599
|
this.#previewDate = "";
|
|
600
|
+
if (!changed) return null;
|
|
462
601
|
this.#rangeMoves += 1;
|
|
463
602
|
return this.#rangeMoves;
|
|
464
603
|
}
|
|
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 } });
|
|
604
|
+
#reportConfirmed(move, reason) {
|
|
605
|
+
if (move === null || move !== this.#rangeMoves) return;
|
|
606
|
+
this.dispatch("change", { detail: { start: this.#startDate, end: this.#endDate, reason } });
|
|
473
607
|
}
|
|
474
|
-
/** Moves roving focus to `date`, transitioning the month when needed. */
|
|
475
608
|
#moveFocusTo(date) {
|
|
476
609
|
this.#focusedDate = date;
|
|
477
610
|
const iso = toISODateString(date);
|
|
478
611
|
if (this.#pendingStart && this.#isSelectable(iso)) this.#previewDate = iso;
|
|
479
612
|
this.#transitionTo(toISOMonthString(date), iso);
|
|
480
613
|
}
|
|
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) {
|
|
614
|
+
#transitionTo(month, dateStr, confirmed = false, canFocus = () => true) {
|
|
489
615
|
const isTransition = month !== this.#viewMonth;
|
|
490
616
|
this.#focusTimer.clearAll();
|
|
491
617
|
this.#viewMonth = month;
|
|
492
618
|
this.#transitions += 1;
|
|
493
619
|
const transition = this.#transitions;
|
|
494
620
|
this.#render(confirmed);
|
|
495
|
-
if (transition !== this.#transitions) return;
|
|
621
|
+
if (transition !== this.#transitions || !canFocus()) return;
|
|
496
622
|
const focusCell = () => {
|
|
623
|
+
if (!canFocus()) return;
|
|
497
624
|
this.cellTargets.find((c) => c.getAttribute("data-date") === dateStr)?.focus();
|
|
498
625
|
};
|
|
499
626
|
if (isTransition) {
|
|
@@ -502,7 +629,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
502
629
|
focusCell();
|
|
503
630
|
}
|
|
504
631
|
}
|
|
505
|
-
/** Shifts the displayed month by `delta`, keeping focus within it. */
|
|
506
632
|
#shiftMonth(delta) {
|
|
507
633
|
const info = parseISOMonthString(this.#viewMonth);
|
|
508
634
|
if (!info) return;
|
|
@@ -513,17 +639,8 @@ var DateRangePickerController = class extends Controller {
|
|
|
513
639
|
this.#focusedDate = target;
|
|
514
640
|
this.#render();
|
|
515
641
|
}
|
|
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
642
|
#render(confirmed = false) {
|
|
643
|
+
if (this.hasGridTarget) this.#multiselectable.write(this.gridTarget, "true");
|
|
527
644
|
const info = parseISOMonthString(this.#viewMonth);
|
|
528
645
|
if (!info) return;
|
|
529
646
|
const { year, month } = info;
|
|
@@ -576,8 +693,8 @@ var DateRangePickerController = class extends Controller {
|
|
|
576
693
|
const moved = this.#mirrorFields();
|
|
577
694
|
if (confirmed) {
|
|
578
695
|
this.#announce();
|
|
579
|
-
for (const [field, value] of moved) {
|
|
580
|
-
if (field.value === value) commitField(field);
|
|
696
|
+
for (const [field, value, write] of moved) {
|
|
697
|
+
if (field.value === value && this.#fieldWrites.get(field) === write) commitField(field);
|
|
581
698
|
}
|
|
582
699
|
}
|
|
583
700
|
const previous = this.#announcedMonth;
|
|
@@ -589,12 +706,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
589
706
|
this.dispatch("reconcile", { detail: { start: this.#startDate, end: this.#endDate } });
|
|
590
707
|
}
|
|
591
708
|
}
|
|
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
709
|
#narrowConfirmedRange() {
|
|
599
710
|
const [start, end] = this.#selectableRange(this.#startDate, this.#endDate);
|
|
600
711
|
if (start === this.#startDate && end === this.#endDate) return false;
|
|
@@ -603,11 +714,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
603
714
|
this.#rangeMoves += 1;
|
|
604
715
|
return true;
|
|
605
716
|
}
|
|
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
717
|
#selectableRange(start, end) {
|
|
612
718
|
let from = parseISODateString(start || end);
|
|
613
719
|
let to = parseISODateString(end || start);
|
|
@@ -621,7 +727,6 @@ var DateRangePickerController = class extends Controller {
|
|
|
621
727
|
if (from.getTime() > to.getTime()) return ["", ""];
|
|
622
728
|
return [start ? toISODateString(from) : "", end ? toISODateString(to) : ""];
|
|
623
729
|
}
|
|
624
|
-
/** The ordered [start, end] pair to paint: the preview while selecting, else confirmed. */
|
|
625
730
|
#visualRange() {
|
|
626
731
|
if (this.#pendingStart) {
|
|
627
732
|
const other = this.#previewDate || this.#pendingStart;
|
|
@@ -629,81 +734,59 @@ var DateRangePickerController = class extends Controller {
|
|
|
629
734
|
}
|
|
630
735
|
return [this.#startDate, this.#endDate];
|
|
631
736
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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
|
+
}
|
|
637
742
|
#mirrorFields() {
|
|
638
743
|
const moved = [];
|
|
639
|
-
if (this.hasStartFieldTarget && writeField(this.startFieldTarget, this.#startDate)) {
|
|
640
|
-
moved.push([
|
|
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
|
+
]);
|
|
641
750
|
}
|
|
642
|
-
if (this.hasEndFieldTarget && writeField(this.endFieldTarget, this.#endDate)) {
|
|
643
|
-
moved.push([
|
|
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
|
+
]);
|
|
644
757
|
}
|
|
645
758
|
return moved;
|
|
646
759
|
}
|
|
647
|
-
/** Announces the confirmed range in the live status region. */
|
|
648
760
|
#announce() {
|
|
649
761
|
if (this.hasStatusTarget && this.#startDate && this.#endDate) {
|
|
650
762
|
this.statusTarget.textContent = `${this.#startDate} \u2013 ${this.#endDate}`;
|
|
651
763
|
}
|
|
652
764
|
}
|
|
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
765
|
#isSelectable(iso) {
|
|
662
766
|
return !this.#outOfBounds(iso) && !this.#disabledDates.has(iso);
|
|
663
767
|
}
|
|
664
|
-
/** True when `iso` falls outside the `[min, max]` bounds. */
|
|
665
768
|
#outOfBounds(iso) {
|
|
666
769
|
if (this.minValue && iso < this.minValue) return true;
|
|
667
770
|
if (this.maxValue && iso > this.maxValue) return true;
|
|
668
771
|
return false;
|
|
669
772
|
}
|
|
670
|
-
/** Clamps a generated ISO date string into `[min, max]`. */
|
|
671
773
|
#clampISO(iso) {
|
|
672
774
|
if (this.minValue && iso < this.minValue) return this.minValue;
|
|
673
775
|
if (this.maxValue && iso > this.maxValue) return this.maxValue;
|
|
674
776
|
return iso;
|
|
675
777
|
}
|
|
676
|
-
/** Clamps a Date into `[min, max]`, returning null only when unparseable. */
|
|
677
778
|
#clampToBounds(date) {
|
|
678
779
|
const clamped = this.#clampISO(toISODateString(date));
|
|
679
780
|
return parseISODateString(clamped);
|
|
680
781
|
}
|
|
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
782
|
#intersectRange(range) {
|
|
690
783
|
const start = this.minValue && range.start < this.minValue ? this.minValue : range.start;
|
|
691
784
|
const end = this.maxValue && range.end > this.maxValue ? this.maxValue : range.end;
|
|
692
785
|
return start <= end ? { start, end } : null;
|
|
693
786
|
}
|
|
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
787
|
#cellFrom(target) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
) ?? null;
|
|
788
|
+
const cell = target instanceof Element ? target.closest(targetSelector(this.identifier, "cell")) : null;
|
|
789
|
+
return cell && this.cellTargets.includes(cell) ? cell : null;
|
|
707
790
|
}
|
|
708
791
|
};
|
|
709
792
|
function addDays(date, n) {
|
|
@@ -763,5 +846,4 @@ function computePreset(name) {
|
|
|
763
846
|
}
|
|
764
847
|
|
|
765
848
|
export { DateRangePickerController };
|
|
766
|
-
//# sourceMappingURL=date_range_picker_controller.js.map
|
|
767
849
|
//# sourceMappingURL=date_range_picker_controller.js.map
|