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,8 +1,5 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/character_counter_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/announce.ts
|
|
6
3
|
function announce(message, options = {}) {
|
|
7
4
|
const text = message.trim();
|
|
8
5
|
if (text.length === 0) return;
|
|
@@ -19,144 +16,246 @@ function fillTemplate(template, values) {
|
|
|
19
16
|
});
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
function sharedRegistry(key, create) {
|
|
20
|
+
const symbol = Symbol.for(key);
|
|
21
|
+
const scope = globalThis;
|
|
22
|
+
const existing = scope[symbol];
|
|
23
|
+
if (existing !== void 0) return existing;
|
|
24
|
+
const registry = create();
|
|
25
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
26
|
+
return registry;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isAttributeValue(value) {
|
|
30
|
+
return value === null || typeof value === "string";
|
|
31
|
+
}
|
|
32
|
+
function readLeaseRecord(element, record) {
|
|
33
|
+
try {
|
|
34
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
35
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
36
|
+
const [original, written, ...rest] = parsed;
|
|
37
|
+
const linked = rest[0] !== false;
|
|
38
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
39
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
40
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
41
|
+
} catch {
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
var AttributeLease = class _AttributeLease {
|
|
46
|
+
static #registry = sharedRegistry(
|
|
47
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
48
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
49
|
+
);
|
|
24
50
|
#attribute;
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
#record;
|
|
52
|
+
#base;
|
|
53
|
+
#held = /* @__PURE__ */ new Set();
|
|
54
|
+
constructor(attribute, owner, options = {}) {
|
|
28
55
|
this.#attribute = attribute;
|
|
56
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
57
|
+
this.#base = options.base === true;
|
|
58
|
+
const names = _AttributeLease.#registry.names;
|
|
59
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
29
60
|
}
|
|
30
|
-
/** Writes or removes the leased attribute while preserving its authored value. */
|
|
31
61
|
write(element, value) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
this.#reflect(element, value);
|
|
62
|
+
const stack = this.#stack(element);
|
|
63
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
64
|
+
this.#held.add(element);
|
|
65
|
+
const shows = !this.#covered(element, stack, hold);
|
|
66
|
+
hold.written = value;
|
|
67
|
+
this.#mark(element, stack);
|
|
68
|
+
if (shows) this.#reflect(element, value);
|
|
42
69
|
}
|
|
43
|
-
/** Returns one lease without overwriting a value subsequently authored by a consumer. */
|
|
44
70
|
return(element) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
this.#
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
71
|
+
const held = this.#held.delete(element);
|
|
72
|
+
const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
|
|
73
|
+
const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
|
|
74
|
+
const hold = this.#take(stack);
|
|
75
|
+
if (!hold) return false;
|
|
76
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
77
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
78
|
+
const index = stack.indexOf(hold);
|
|
79
|
+
stack.splice(index, 1);
|
|
80
|
+
const above = stack[index];
|
|
81
|
+
if (above) above.linked &&= hold.linked;
|
|
82
|
+
this.#mark(element, stack);
|
|
83
|
+
if (!owns) return true;
|
|
84
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
85
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
returnAll() {
|
|
89
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
90
|
+
}
|
|
91
|
+
#stack(element) {
|
|
92
|
+
const stacks = _AttributeLease.#registry.stacks;
|
|
93
|
+
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
94
|
+
stacks.set(element, byAttribute);
|
|
95
|
+
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
96
|
+
byAttribute.set(this.#attribute, stack);
|
|
97
|
+
return stack;
|
|
98
|
+
}
|
|
99
|
+
#seed(element) {
|
|
100
|
+
const found = [];
|
|
101
|
+
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
102
|
+
const read = readLeaseRecord(element, record);
|
|
103
|
+
if (read) found.push({ ...read, record });
|
|
104
|
+
}
|
|
105
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
106
|
+
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
107
|
+
lease: null,
|
|
108
|
+
record,
|
|
109
|
+
written,
|
|
110
|
+
original,
|
|
111
|
+
linked: linked && index > 0
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
#take(stack) {
|
|
115
|
+
const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
|
|
116
|
+
if (hold) hold.lease = this;
|
|
117
|
+
return hold;
|
|
118
|
+
}
|
|
119
|
+
#acquire(element, stack) {
|
|
120
|
+
const current = element.getAttribute(this.#attribute);
|
|
121
|
+
const top = stack.at(-1);
|
|
122
|
+
const bottom = stack[0];
|
|
123
|
+
const over = top?.written === current ? top : void 0;
|
|
124
|
+
const from = this.#base ? bottom : over;
|
|
125
|
+
const hold = {
|
|
126
|
+
lease: this,
|
|
127
|
+
record: this.#record,
|
|
128
|
+
written: current,
|
|
129
|
+
original: from ? from.original : current,
|
|
130
|
+
linked: !this.#base && over !== void 0
|
|
131
|
+
};
|
|
132
|
+
if (this.#base && bottom) {
|
|
133
|
+
bottom.linked = true;
|
|
134
|
+
stack.unshift(hold);
|
|
135
|
+
} else stack.push(hold);
|
|
136
|
+
return hold;
|
|
137
|
+
}
|
|
138
|
+
#covered(element, stack, hold) {
|
|
139
|
+
const current = element.getAttribute(this.#attribute);
|
|
140
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
141
|
+
}
|
|
142
|
+
#mark(element, stack) {
|
|
143
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
144
|
+
stack.forEach((hold, index) => {
|
|
145
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
146
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
147
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
148
|
+
records.set(
|
|
149
|
+
hold.record,
|
|
150
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
for (const [name, recorded] of records) {
|
|
154
|
+
if (element.getAttribute(name) === recorded) continue;
|
|
155
|
+
if (recorded === null) element.removeAttribute(name);
|
|
156
|
+
else element.setAttribute(name, recorded);
|
|
157
|
+
}
|
|
50
158
|
}
|
|
51
|
-
/** Reflects only a real value transition, avoiding self-triggered mutation work. */
|
|
52
159
|
#reflect(element, value) {
|
|
53
160
|
if (element.getAttribute(this.#attribute) === value) return;
|
|
54
161
|
if (value === null) element.removeAttribute(this.#attribute);
|
|
55
162
|
else element.setAttribute(this.#attribute, value);
|
|
56
163
|
}
|
|
57
|
-
/** Returns every outstanding lease using the same ownership check as {@link return}. */
|
|
58
|
-
returnAll() {
|
|
59
|
-
for (const element of Array.from(this.#records.keys())) this.return(element);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// src/utils/before_cache_reset.ts
|
|
64
|
-
var BeforeCacheReset = class _BeforeCacheReset {
|
|
65
|
-
/** Every subscribed instance, iterated by the one shared document listener. */
|
|
66
|
-
static #subscribers = /* @__PURE__ */ new Set();
|
|
67
|
-
/** The shared listener; installed while at least one instance is subscribed. */
|
|
68
|
-
static #onBeforeCache = () => {
|
|
69
|
-
for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
|
|
70
|
-
};
|
|
71
|
-
#rewind;
|
|
72
|
-
/** @param rewind - the pass that returns this controller's state to its initial form. */
|
|
73
|
-
constructor(rewind) {
|
|
74
|
-
this.#rewind = rewind;
|
|
75
|
-
}
|
|
76
|
-
/** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
|
|
77
|
-
activate() {
|
|
78
|
-
const first = _BeforeCacheReset.#subscribers.size === 0;
|
|
79
|
-
_BeforeCacheReset.#subscribers.add(this);
|
|
80
|
-
if (first) {
|
|
81
|
-
document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
/** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
|
|
85
|
-
deactivate() {
|
|
86
|
-
_BeforeCacheReset.#subscribers.delete(this);
|
|
87
|
-
if (_BeforeCacheReset.#subscribers.size > 0) return;
|
|
88
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
89
|
-
}
|
|
90
164
|
};
|
|
91
165
|
|
|
92
|
-
|
|
166
|
+
var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
167
|
+
"insertCompositionText",
|
|
168
|
+
"insertFromComposition",
|
|
169
|
+
"deleteCompositionText",
|
|
170
|
+
"deleteByComposition"
|
|
171
|
+
]);
|
|
93
172
|
var CompositionTracker = class {
|
|
94
173
|
#observedTargets = /* @__PURE__ */ new Set();
|
|
95
174
|
#activeTargets = /* @__PURE__ */ new Set();
|
|
96
175
|
#onStart;
|
|
97
176
|
#onEnd;
|
|
177
|
+
#confirmedTarget = null;
|
|
98
178
|
constructor(options = {}) {
|
|
99
179
|
this.#onStart = options.onStart;
|
|
100
180
|
this.#onEnd = options.onEnd;
|
|
101
181
|
}
|
|
102
|
-
/** Starts lifecycle tracking for `target`; repeated calls are idempotent. */
|
|
103
182
|
observe(target) {
|
|
104
183
|
if (this.#observedTargets.has(target)) return;
|
|
105
184
|
target.addEventListener("compositionstart", this.#handleStart);
|
|
106
185
|
target.addEventListener("compositionend", this.#handleEnd);
|
|
186
|
+
target.addEventListener("keydown", this.#handleKeydown);
|
|
107
187
|
this.#observedTargets.add(target);
|
|
108
188
|
}
|
|
109
|
-
/** Stops tracking one target and clears any active composition it owned. */
|
|
110
189
|
unobserve(target) {
|
|
111
190
|
if (!this.#observedTargets.delete(target)) return;
|
|
112
191
|
target.removeEventListener("compositionstart", this.#handleStart);
|
|
113
192
|
target.removeEventListener("compositionend", this.#handleEnd);
|
|
193
|
+
target.removeEventListener("keydown", this.#handleKeydown);
|
|
114
194
|
this.#activeTargets.delete(target);
|
|
195
|
+
if (this.#confirmedTarget === target) this.#confirmedTarget = null;
|
|
115
196
|
}
|
|
116
|
-
/** Releases every listener and clears state so reconnect starts cleanly. */
|
|
117
197
|
disconnect() {
|
|
118
198
|
for (const target of this.#observedTargets) {
|
|
119
199
|
target.removeEventListener("compositionstart", this.#handleStart);
|
|
120
200
|
target.removeEventListener("compositionend", this.#handleEnd);
|
|
201
|
+
target.removeEventListener("keydown", this.#handleKeydown);
|
|
121
202
|
}
|
|
122
203
|
this.#observedTargets.clear();
|
|
123
204
|
this.#activeTargets.clear();
|
|
205
|
+
this.#confirmedTarget = null;
|
|
124
206
|
}
|
|
125
|
-
/** True when lifecycle tracking or the current event reports composition. */
|
|
126
207
|
isComposing(event) {
|
|
127
208
|
return this.#activeTargets.size > 0 || event?.isComposing === true;
|
|
128
209
|
}
|
|
210
|
+
consumesConfirmedInput(event) {
|
|
211
|
+
const confirmed = this.#confirmedTarget;
|
|
212
|
+
this.#confirmedTarget = null;
|
|
213
|
+
if (confirmed === null || confirmed !== event.target) return false;
|
|
214
|
+
const inputType = event.inputType;
|
|
215
|
+
return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);
|
|
216
|
+
}
|
|
129
217
|
#handleStart = (event) => {
|
|
218
|
+
this.#confirmedTarget = null;
|
|
130
219
|
if (event.currentTarget) this.#activeTargets.add(event.currentTarget);
|
|
131
220
|
this.#onStart?.(event);
|
|
132
221
|
};
|
|
133
222
|
#handleEnd = (event) => {
|
|
134
223
|
if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);
|
|
224
|
+
this.#confirmedTarget = event.target;
|
|
135
225
|
this.#onEnd?.(event);
|
|
136
226
|
};
|
|
227
|
+
#handleKeydown = () => {
|
|
228
|
+
this.#confirmedTarget = null;
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
var ListenerSet = class {
|
|
233
|
+
#abort = new AbortController();
|
|
234
|
+
add(target, type, handler, options) {
|
|
235
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
236
|
+
}
|
|
237
|
+
dispose() {
|
|
238
|
+
this.#abort.abort();
|
|
239
|
+
this.#abort = new AbortController();
|
|
240
|
+
}
|
|
137
241
|
};
|
|
138
242
|
|
|
139
|
-
// src/utils/microtask_coalescer.ts
|
|
140
243
|
var MicrotaskCoalescer = class {
|
|
141
244
|
#run;
|
|
142
245
|
#queued = false;
|
|
143
246
|
#active = false;
|
|
144
247
|
#generation = 0;
|
|
145
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
146
248
|
constructor(run) {
|
|
147
249
|
this.#run = run;
|
|
148
250
|
}
|
|
149
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
150
251
|
activate() {
|
|
151
252
|
this.#active = true;
|
|
152
253
|
}
|
|
153
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
154
254
|
cancel() {
|
|
155
255
|
this.#active = false;
|
|
156
256
|
this.#queued = false;
|
|
157
257
|
this.#generation += 1;
|
|
158
258
|
}
|
|
159
|
-
/** Requests one pass after the batch settles. Idempotent; inert outside the window. */
|
|
160
259
|
schedule() {
|
|
161
260
|
if (!this.#active || this.#queued) return;
|
|
162
261
|
this.#queued = true;
|
|
@@ -169,43 +268,93 @@ var MicrotaskCoalescer = class {
|
|
|
169
268
|
}
|
|
170
269
|
};
|
|
171
270
|
|
|
172
|
-
|
|
271
|
+
var MorphRenderWatcher = class {
|
|
272
|
+
#listeners = new ListenerSet();
|
|
273
|
+
#pass;
|
|
274
|
+
#element = null;
|
|
275
|
+
#onMorph = () => this.#pass.schedule();
|
|
276
|
+
constructor(run) {
|
|
277
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
278
|
+
}
|
|
279
|
+
observe(element) {
|
|
280
|
+
if (this.#element === element) return;
|
|
281
|
+
this.disconnect();
|
|
282
|
+
this.#element = element;
|
|
283
|
+
this.#pass.activate();
|
|
284
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
285
|
+
}
|
|
286
|
+
schedule() {
|
|
287
|
+
this.#pass.schedule();
|
|
288
|
+
}
|
|
289
|
+
disconnect() {
|
|
290
|
+
this.#listeners.dispose();
|
|
291
|
+
this.#pass.cancel();
|
|
292
|
+
this.#element = null;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
var NUMBER_BOUNDS = {
|
|
297
|
+
nonNegative: { finite: true, min: 0 }};
|
|
298
|
+
function matchesNumberBounds(value, bounds) {
|
|
299
|
+
if (!Number.isFinite(value)) {
|
|
300
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
301
|
+
if (direction === null) return false;
|
|
302
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
303
|
+
}
|
|
304
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
305
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
306
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
307
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
308
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function readNumber(raw, fallback, bounds) {
|
|
313
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
var NumberValueReader = class {
|
|
317
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
318
|
+
read(owner, name, raw, fallback, bounds) {
|
|
319
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
320
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
321
|
+
this.#lastRejected.delete(name);
|
|
322
|
+
return resolved;
|
|
323
|
+
}
|
|
324
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
325
|
+
const literal = owner.element.getAttribute(attribute);
|
|
326
|
+
if (literal === null) {
|
|
327
|
+
this.#lastRejected.delete(name);
|
|
328
|
+
return resolved;
|
|
329
|
+
}
|
|
330
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
331
|
+
this.#lastRejected.set(name, literal);
|
|
332
|
+
console.warn(
|
|
333
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
return resolved;
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
173
340
|
var TimerRegistry = class {
|
|
174
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
175
341
|
ids = /* @__PURE__ */ new Set();
|
|
176
|
-
/**
|
|
177
|
-
* Cancels a single tracked timer.
|
|
178
|
-
*
|
|
179
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
180
|
-
* registry), so callers can clear defensively without guarding.
|
|
181
|
-
*/
|
|
182
342
|
clear(id) {
|
|
183
343
|
if (this.ids.delete(id)) {
|
|
184
344
|
this.cancel(id);
|
|
185
345
|
}
|
|
186
346
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
189
|
-
* to guarantee no timer outlives the element.
|
|
190
|
-
*/
|
|
191
347
|
clearAll() {
|
|
192
348
|
for (const id of this.ids) {
|
|
193
349
|
this.cancel(id);
|
|
194
350
|
}
|
|
195
351
|
this.ids.clear();
|
|
196
352
|
}
|
|
197
|
-
/** Number of timers currently tracked (pending). */
|
|
198
353
|
get size() {
|
|
199
354
|
return this.ids.size;
|
|
200
355
|
}
|
|
201
356
|
};
|
|
202
357
|
var SafeTimeout = class extends TimerRegistry {
|
|
203
|
-
/**
|
|
204
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
205
|
-
*
|
|
206
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
207
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
208
|
-
*/
|
|
209
358
|
set(callback, delay) {
|
|
210
359
|
const id = this.schedule(() => {
|
|
211
360
|
this.ids.delete(id);
|
|
@@ -222,8 +371,8 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
222
371
|
}
|
|
223
372
|
};
|
|
224
373
|
|
|
225
|
-
// src/controllers/character_counter_controller.ts
|
|
226
374
|
var CharacterCounterController = class _CharacterCounterController extends Controller {
|
|
375
|
+
#numbers = new NumberValueReader();
|
|
227
376
|
static targets = ["input", "output"];
|
|
228
377
|
static values = {
|
|
229
378
|
max: { type: Number, default: 0 },
|
|
@@ -231,13 +380,18 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
231
380
|
mode: { type: String, default: "remaining" },
|
|
232
381
|
announceText: { type: String, default: "" }
|
|
233
382
|
};
|
|
383
|
+
static valueConstraints = {
|
|
384
|
+
max: NUMBER_BOUNDS.nonNegative,
|
|
385
|
+
warnAt: NUMBER_BOUNDS.nonNegative
|
|
386
|
+
};
|
|
234
387
|
static events = ["change", "reconcile"];
|
|
235
|
-
/** Delay (ms) before one settled count is sent to the shared announcer. */
|
|
236
388
|
static #announceDelay = 200;
|
|
237
389
|
#timeouts = new SafeTimeout();
|
|
238
|
-
#ariaInvalid = new AttributeLease(
|
|
239
|
-
|
|
240
|
-
|
|
390
|
+
#ariaInvalid = new AttributeLease(
|
|
391
|
+
"aria-invalid",
|
|
392
|
+
this.identifier
|
|
393
|
+
);
|
|
394
|
+
#repaint = new MorphRenderWatcher(() => this.#reconcile(true));
|
|
241
395
|
#composition = new CompositionTracker({
|
|
242
396
|
onEnd: (event) => this.#commitFrom(event.currentTarget)
|
|
243
397
|
});
|
|
@@ -249,59 +403,46 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
249
403
|
#onInput = (event) => {
|
|
250
404
|
const field = this.#boundField;
|
|
251
405
|
if (!field || event.currentTarget !== field || this.#field !== field) return;
|
|
406
|
+
if (this.#composition.consumesConfirmedInput(event)) return;
|
|
252
407
|
if (this.#composition.isComposing(event)) return;
|
|
253
408
|
this.#commit(field);
|
|
254
409
|
};
|
|
255
|
-
/** Reflects the current DOM state and opens the mutation-reconciliation window. */
|
|
256
410
|
connect() {
|
|
257
|
-
this.#repaint.
|
|
258
|
-
this.#beforeCache.activate();
|
|
411
|
+
this.#repaint.observe(this.element);
|
|
259
412
|
this.#reconcile(false);
|
|
260
413
|
}
|
|
261
|
-
/** Releases listeners, timers, borrowed ARIA, and controller-owned state hooks. */
|
|
262
414
|
disconnect() {
|
|
263
|
-
this.#repaint.
|
|
264
|
-
this.#beforeCache.deactivate();
|
|
415
|
+
this.#repaint.disconnect();
|
|
265
416
|
this.#cancelAnnouncement();
|
|
266
417
|
this.#bindField(null);
|
|
267
|
-
this.#composition.disconnect();
|
|
268
418
|
this.#clearStateHooks();
|
|
269
419
|
this.#lastLength = null;
|
|
270
420
|
this.#lastDetail = null;
|
|
271
421
|
}
|
|
272
|
-
/** Rebinds and repaints after an input target is added or replaced at runtime. */
|
|
273
422
|
inputTargetConnected() {
|
|
274
423
|
this.#repaint.schedule();
|
|
275
424
|
}
|
|
276
|
-
/** Releases and repaints after an input target is removed or replaced at runtime. */
|
|
277
425
|
inputTargetDisconnected() {
|
|
278
426
|
this.#repaint.schedule();
|
|
279
427
|
}
|
|
280
|
-
/** Initializes a display target inserted after the controller connected. */
|
|
281
428
|
outputTargetConnected() {
|
|
282
429
|
this.#repaint.schedule();
|
|
283
430
|
}
|
|
284
|
-
/** Reconciles the optional display target set after a removal or replacement. */
|
|
285
431
|
outputTargetDisconnected() {
|
|
286
432
|
this.#repaint.schedule();
|
|
287
433
|
}
|
|
288
|
-
/** Repaints when application code or a Turbo morph changes `max`. */
|
|
289
434
|
maxValueChanged() {
|
|
290
435
|
this.#repaint.schedule();
|
|
291
436
|
}
|
|
292
|
-
/** Repaints when application code or a Turbo morph changes `warnAt`. */
|
|
293
437
|
warnAtValueChanged() {
|
|
294
438
|
this.#repaint.schedule();
|
|
295
439
|
}
|
|
296
|
-
/** Repaints when application code or a Turbo morph changes `mode`. */
|
|
297
440
|
modeValueChanged() {
|
|
298
441
|
this.#repaint.schedule();
|
|
299
442
|
}
|
|
300
|
-
/** Cancels a pending old message when its consumer-authored template changes. */
|
|
301
443
|
announceTextValueChanged() {
|
|
302
444
|
this.#repaint.schedule();
|
|
303
445
|
}
|
|
304
|
-
/** Rebinds one mutation batch and reports a changed controller-derived state. */
|
|
305
446
|
#reconcile(report) {
|
|
306
447
|
const previous = this.#lastDetail;
|
|
307
448
|
const owedField = this.#announceId === null ? null : this.#boundField;
|
|
@@ -324,13 +465,11 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
324
465
|
this.dispatch("reconcile", { detail });
|
|
325
466
|
}
|
|
326
467
|
}
|
|
327
|
-
/** Commits a composition only when it came from the field still owned here. */
|
|
328
468
|
#commitFrom(target) {
|
|
329
469
|
const field = this.#boundField;
|
|
330
470
|
if (!field || target !== field || this.#field !== field) return;
|
|
331
471
|
this.#commit(field);
|
|
332
472
|
}
|
|
333
|
-
/** Reflects one confirmed user input and reports only a real length transition. */
|
|
334
473
|
#commit(field) {
|
|
335
474
|
const reading = this.#render(field);
|
|
336
475
|
const previousLength = this.#lastLength;
|
|
@@ -347,7 +486,6 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
347
486
|
this.dispatch("change", { detail });
|
|
348
487
|
this.#scheduleAnnouncement(reading);
|
|
349
488
|
}
|
|
350
|
-
/** Selects the public event state from the richer internal reading. */
|
|
351
489
|
#detail(reading) {
|
|
352
490
|
return {
|
|
353
491
|
length: reading.length,
|
|
@@ -355,19 +493,13 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
355
493
|
over: reading.over
|
|
356
494
|
};
|
|
357
495
|
}
|
|
358
|
-
/** Compares exactly the state carried by `change` and `reconcile`. */
|
|
359
496
|
#detailsDiffer(left, right) {
|
|
360
497
|
return left.length !== right.length || left.remaining !== right.remaining || left.over !== right.over;
|
|
361
498
|
}
|
|
362
|
-
/**
|
|
363
|
-
* Synchronizes visible count, state hooks, and temporary validation ARIA.
|
|
364
|
-
*
|
|
365
|
-
* @stimeoRenderRoot
|
|
366
|
-
*/
|
|
367
499
|
#render(field) {
|
|
368
500
|
const length = field.value.length;
|
|
369
|
-
const max = this.#normalizeCount(this
|
|
370
|
-
const warnAt = this.#normalizeCount(this
|
|
501
|
+
const max = this.#normalizeCount(this.#safeMax);
|
|
502
|
+
const warnAt = this.#normalizeCount(this.#safeWarnAt);
|
|
371
503
|
const remaining = max > 0 ? max - length : null;
|
|
372
504
|
const over = remaining !== null && remaining < 0;
|
|
373
505
|
const near = remaining !== null && warnAt > 0 && !over && remaining <= warnAt;
|
|
@@ -378,14 +510,11 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
378
510
|
this.#writeOutput(text);
|
|
379
511
|
return { length, remaining, over, max, text };
|
|
380
512
|
}
|
|
381
|
-
/** Clears derived output when the declarative input set has no usable field. */
|
|
382
513
|
#renderEmpty() {
|
|
383
|
-
this.#ariaInvalid.returnAll();
|
|
384
514
|
this.#reflectedOver = null;
|
|
385
515
|
this.#clearStateHooks();
|
|
386
516
|
this.#writeOutput("");
|
|
387
517
|
}
|
|
388
|
-
/** Replaces the observed field symmetrically, returning state from the old one. */
|
|
389
518
|
#bindField(field) {
|
|
390
519
|
if (field === this.#boundField) return;
|
|
391
520
|
const previous = this.#boundField;
|
|
@@ -401,14 +530,12 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
401
530
|
field.addEventListener("input", this.#onInput);
|
|
402
531
|
this.#composition.observe(field);
|
|
403
532
|
}
|
|
404
|
-
/** Leases `aria-invalid` only on the edge into over-limit, then returns it. */
|
|
405
533
|
#reflectInvalid(field, over) {
|
|
406
|
-
if (this.#reflectedOver === over) return;
|
|
534
|
+
if (this.#reflectedOver === over && (!over || field.hasAttribute("aria-invalid"))) return;
|
|
407
535
|
this.#reflectedOver = over;
|
|
408
536
|
if (over) this.#ariaInvalid.write(field, "true");
|
|
409
537
|
else this.#ariaInvalid.return(field);
|
|
410
538
|
}
|
|
411
|
-
/** Builds the visible count for the normalized display mode. */
|
|
412
539
|
#format(length, remaining, max) {
|
|
413
540
|
if (remaining === null) return String(length);
|
|
414
541
|
switch (this.#mode) {
|
|
@@ -420,7 +547,6 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
420
547
|
return String(remaining);
|
|
421
548
|
}
|
|
422
549
|
}
|
|
423
|
-
/** Debounces one i18n-neutral message into the shared polite announcer. */
|
|
424
550
|
#scheduleAnnouncement(reading) {
|
|
425
551
|
this.#cancelAnnouncement();
|
|
426
552
|
const message = fillTemplate(this.announceTextValue, {
|
|
@@ -436,17 +562,14 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
436
562
|
this.#announceId = null;
|
|
437
563
|
}, _CharacterCounterController.#announceDelay);
|
|
438
564
|
}
|
|
439
|
-
/** Cancels the one outstanding announcement without touching visible output. */
|
|
440
565
|
#cancelAnnouncement() {
|
|
441
566
|
if (this.#announceId !== null) this.#timeouts.clear(this.#announceId);
|
|
442
567
|
this.#announceId = null;
|
|
443
568
|
}
|
|
444
|
-
/** Writes the optional display only when its text actually changed. */
|
|
445
569
|
#writeOutput(text) {
|
|
446
570
|
if (!this.hasOutputTarget || this.outputTarget.textContent === text) return;
|
|
447
571
|
this.outputTarget.textContent = text;
|
|
448
572
|
}
|
|
449
|
-
/** Reflects a presence-style state hook without redundant attribute writes. */
|
|
450
573
|
#toggle(name, on) {
|
|
451
574
|
if (on) {
|
|
452
575
|
if (this.element.getAttribute(name) !== "true") this.element.setAttribute(name, "true");
|
|
@@ -454,29 +577,17 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
454
577
|
this.element.removeAttribute(name);
|
|
455
578
|
}
|
|
456
579
|
}
|
|
457
|
-
/** Removes both state hooks owned by this controller. */
|
|
458
580
|
#clearStateHooks() {
|
|
459
581
|
this.#toggle("data-over-limit", false);
|
|
460
582
|
this.#toggle("data-near-limit", false);
|
|
461
583
|
}
|
|
462
|
-
/** Returns borrowed ARIA and transient hooks before Turbo snapshots the page. */
|
|
463
|
-
#rewindForCache() {
|
|
464
|
-
this.#cancelAnnouncement();
|
|
465
|
-
this.#ariaInvalid.returnAll();
|
|
466
|
-
this.#reflectedOver = null;
|
|
467
|
-
this.#clearStateHooks();
|
|
468
|
-
}
|
|
469
|
-
/** Converts a public count Value into a finite non-negative integer. */
|
|
470
584
|
#normalizeCount(raw) {
|
|
471
|
-
if (!Number.isFinite(raw)) return 0;
|
|
472
585
|
return Math.max(0, Math.trunc(raw));
|
|
473
586
|
}
|
|
474
|
-
/** Falls back to `remaining` when an authored display mode is unknown. */
|
|
475
587
|
get #mode() {
|
|
476
588
|
if (this.modeValue === "used" || this.modeValue === "both") return this.modeValue;
|
|
477
589
|
return "remaining";
|
|
478
590
|
}
|
|
479
|
-
/** The watched field: the first target, or a directly controlled form field. */
|
|
480
591
|
get #field() {
|
|
481
592
|
if (this.hasInputTarget) return this.inputTarget;
|
|
482
593
|
const element = this.element;
|
|
@@ -484,8 +595,25 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
|
|
|
484
595
|
return element;
|
|
485
596
|
return null;
|
|
486
597
|
}
|
|
598
|
+
get #safeMax() {
|
|
599
|
+
return this.#numbers.read(
|
|
600
|
+
this,
|
|
601
|
+
"max",
|
|
602
|
+
this.maxValue,
|
|
603
|
+
_CharacterCounterController.values.max.default,
|
|
604
|
+
_CharacterCounterController.valueConstraints.max
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
get #safeWarnAt() {
|
|
608
|
+
return this.#numbers.read(
|
|
609
|
+
this,
|
|
610
|
+
"warnAt",
|
|
611
|
+
this.warnAtValue,
|
|
612
|
+
_CharacterCounterController.values.warnAt.default,
|
|
613
|
+
_CharacterCounterController.valueConstraints.warnAt
|
|
614
|
+
);
|
|
615
|
+
}
|
|
487
616
|
};
|
|
488
617
|
|
|
489
618
|
export { CharacterCounterController };
|
|
490
|
-
//# sourceMappingURL=character_counter_controller.js.map
|
|
491
619
|
//# sourceMappingURL=character_counter_controller.js.map
|