stimeo-ui 0.14.0 → 0.16.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 +212 -0
- package/README.md +120 -0
- package/dist/cable/index.js +123 -29
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +30 -3
- package/dist/controllers/accordion_controller.js +98 -9
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +8 -7
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +3 -2
- package/dist/controllers/announcer_controller.js +96 -62
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js +83 -7
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +1 -1
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +38 -11
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +4 -4
- package/dist/controllers/bulk_select_controller.js +7 -6
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +101 -23
- package/dist/controllers/calendar_controller.js +340 -123
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +67 -22
- package/dist/controllers/carousel_controller.js +263 -38
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +1 -1
- package/dist/controllers/character_counter_controller.js +40 -2
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.js +81 -12
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +28 -2
- package/dist/controllers/clipboard_controller.js +63 -5
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +25 -1
- package/dist/controllers/collapsible_controller.js +99 -14
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +29 -8
- package/dist/controllers/color_picker_controller.js +80 -34
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +10 -1
- package/dist/controllers/combobox_controller.js +106 -16
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +3 -3
- package/dist/controllers/command_palette_controller.js +35 -3
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js +85 -17
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.js +3 -0
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +6 -0
- package/dist/controllers/context_menu_controller.js +32 -12
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +30 -1
- package/dist/controllers/countdown_controller.js +129 -26
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +77 -16
- package/dist/controllers/currency_input_controller.js +221 -67
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +63 -18
- package/dist/controllers/data_grid_controller.js +195 -29
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +41 -6
- package/dist/controllers/date_range_picker_controller.js +151 -30
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +10 -3
- package/dist/controllers/dialog_controller.js +35 -8
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.js +22 -4
- 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 +46 -13
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js +1 -0
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +18 -10
- package/dist/controllers/drawer_controller.js +54 -19
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +9 -3
- package/dist/controllers/dropdown_controller.js +36 -9
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.js +34 -0
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js +144 -51
- 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 +20 -6
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +26 -6
- package/dist/controllers/flash_controller.js +432 -71
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.js +1 -0
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +7 -5
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +19 -13
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.js +45 -8
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js +82 -25
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +10 -2
- package/dist/controllers/hover_card_controller.js +40 -14
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +16 -3
- package/dist/controllers/idle_controller.js +90 -5
- 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 +65 -9
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.js +3 -0
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.js +11 -2
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +50 -8
- package/dist/controllers/listbox_controller.js +203 -45
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.js +10 -5
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +3 -3
- package/dist/controllers/masonry_controller.js +31 -15
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +9 -3
- package/dist/controllers/menu_controller.js +45 -16
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +11 -0
- package/dist/controllers/menubar_controller.js +58 -24
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.js +9 -5
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +18 -3
- package/dist/controllers/multi_select_controller.js +278 -104
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +11 -0
- package/dist/controllers/navigation_menu_controller.js +48 -15
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js +37 -8
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.js +9 -1
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +36 -8
- package/dist/controllers/number_input_controller.js +124 -21
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +42 -5
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +22 -7
- package/dist/controllers/otp_controller.js +198 -55
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
- package/dist/controllers/overflow_indicator_controller.js +115 -21
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +26 -6
- package/dist/controllers/overflow_menu_controller.js +141 -44
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +19 -11
- package/dist/controllers/pagination_controller.js +74 -28
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +15 -1
- package/dist/controllers/password_reveal_controller.js +59 -2
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/persist_controller.js +30 -8
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +131 -52
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +9 -3
- package/dist/controllers/popover_controller.js +45 -11
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +1 -1
- package/dist/controllers/portal_controller.js +6 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.js +16 -1
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.js +8 -4
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +6 -4
- package/dist/controllers/radio_group_controller.js +42 -17
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +49 -1
- package/dist/controllers/range_slider_controller.js +88 -42
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +14 -3
- package/dist/controllers/rating_controller.js +39 -15
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +24 -2
- package/dist/controllers/read_more_controller.js +100 -7
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.js +65 -19
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.js +10 -5
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +16 -2
- package/dist/controllers/resizable_controller.js +82 -22
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js +75 -27
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.js +37 -16
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.js +49 -30
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +3 -2
- package/dist/controllers/scrollspy_controller.js +71 -26
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +41 -14
- package/dist/controllers/separator_controller.js +66 -37
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +20 -3
- package/dist/controllers/sidebar_controller.js +77 -18
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.js +6 -1
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +45 -7
- package/dist/controllers/slider_controller.js +82 -47
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.js +60 -26
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +17 -2
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.js +10 -2
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +19 -17
- package/dist/controllers/step_indicator_controller.js +18 -17
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +34 -9
- package/dist/controllers/stepper_controller.js +101 -19
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
- package/dist/controllers/stick_to_bottom_controller.js +104 -8
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +3 -2
- package/dist/controllers/submit_once_controller.js +45 -9
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +29 -7
- package/dist/controllers/switch_controller.js +101 -10
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +12 -0
- package/dist/controllers/tabs_controller.js +21 -2
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +15 -3
- package/dist/controllers/tags_input_controller.js +209 -59
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.js +29 -3
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +20 -3
- package/dist/controllers/theme_controller.js +64 -14
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.js +23 -8
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +55 -15
- package/dist/controllers/toast_controller.js +451 -105
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +49 -7
- package/dist/controllers/toggle_group_controller.js +159 -23
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +32 -0
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +8 -0
- package/dist/controllers/tooltip_controller.js +39 -13
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.js +4 -0
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +39 -8
- package/dist/controllers/tree_view_controller.js +169 -16
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +5002 -1911
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +72 -6
- package/dist/inspector/cli.js +262 -51
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +309 -51
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +40 -40
- package/dist/inspector/manifest.json +529 -61
- package/dist/positioning/index.js +2 -0
- package/dist/positioning/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -18,6 +18,16 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
18
18
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// src/utils/field_mirror.ts
|
|
22
|
+
function writeField(field, value) {
|
|
23
|
+
if (field.value === value) return false;
|
|
24
|
+
field.value = value;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
function commitField(target) {
|
|
28
|
+
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
// src/utils/microtask_coalescer.ts
|
|
22
32
|
var MicrotaskCoalescer = class {
|
|
23
33
|
#run;
|
|
@@ -53,54 +63,46 @@ var MicrotaskCoalescer = class {
|
|
|
53
63
|
|
|
54
64
|
// src/utils/owned_pointer_session.ts
|
|
55
65
|
var OwnedPointerSession = class {
|
|
56
|
-
pointerId;
|
|
66
|
+
#pointerId;
|
|
57
67
|
#owner;
|
|
58
68
|
#handlers;
|
|
59
69
|
#abort = new AbortController();
|
|
60
70
|
#active = true;
|
|
61
71
|
constructor(start, owner, handlers) {
|
|
62
|
-
this
|
|
72
|
+
this.#pointerId = start.pointerId;
|
|
63
73
|
this.#owner = owner;
|
|
64
74
|
this.#handlers = handlers;
|
|
65
75
|
const { signal } = this.#abort;
|
|
66
76
|
owner.ownerDocument.addEventListener("pointermove", this.#onMove, { signal });
|
|
67
77
|
owner.ownerDocument.addEventListener("pointerup", this.#onEndEvent, { signal });
|
|
68
78
|
owner.ownerDocument.addEventListener("pointercancel", this.#onEndEvent, { signal });
|
|
69
|
-
owner.addEventListener("lostpointercapture", this.#onLostCapture, { signal });
|
|
70
79
|
try {
|
|
71
|
-
owner.setPointerCapture?.(this
|
|
80
|
+
owner.setPointerCapture?.(this.#pointerId);
|
|
72
81
|
} catch {
|
|
73
82
|
}
|
|
74
83
|
}
|
|
75
|
-
/**
|
|
76
|
-
get active() {
|
|
77
|
-
return this.#active;
|
|
78
|
-
}
|
|
79
|
-
/** Whether `event` belongs to the initiating pointer of the live session. */
|
|
80
|
-
owns(event) {
|
|
81
|
-
return this.#active && event.pointerId === this.pointerId;
|
|
82
|
-
}
|
|
83
|
-
/** Releases capture/listeners and invokes the end callback exactly once. */
|
|
84
|
+
/** Releases capture and listeners, then reports the end exactly once. */
|
|
84
85
|
end() {
|
|
86
|
+
this.#finish("teardown");
|
|
87
|
+
}
|
|
88
|
+
#finish(kind) {
|
|
85
89
|
if (!this.#active) return;
|
|
86
90
|
this.#active = false;
|
|
87
91
|
this.#abort.abort();
|
|
88
92
|
try {
|
|
89
|
-
this.#owner.releasePointerCapture?.(this
|
|
93
|
+
this.#owner.releasePointerCapture?.(this.#pointerId);
|
|
90
94
|
} catch {
|
|
91
95
|
}
|
|
92
|
-
this.#handlers.end?.();
|
|
96
|
+
this.#handlers.end?.(kind);
|
|
97
|
+
}
|
|
98
|
+
#owns(event) {
|
|
99
|
+
return this.#active && event.pointerId === this.#pointerId;
|
|
93
100
|
}
|
|
94
101
|
#onMove = (event) => {
|
|
95
|
-
if (this
|
|
102
|
+
if (this.#owns(event)) this.#handlers.move(event);
|
|
96
103
|
};
|
|
97
104
|
#onEndEvent = (event) => {
|
|
98
|
-
if (this
|
|
99
|
-
};
|
|
100
|
-
#onLostCapture = (event) => {
|
|
101
|
-
const pointerId = event.pointerId;
|
|
102
|
-
if (typeof pointerId === "number" && pointerId !== this.pointerId) return;
|
|
103
|
-
this.end();
|
|
105
|
+
if (this.#owns(event)) this.#finish(event.type === "pointerup" ? "up" : "cancel");
|
|
104
106
|
};
|
|
105
107
|
};
|
|
106
108
|
|
|
@@ -232,7 +234,7 @@ var END_PROPERTY = "--stimeo--range-slider-end";
|
|
|
232
234
|
var DEFAULT_MIN = 0;
|
|
233
235
|
var DEFAULT_MAX = 100;
|
|
234
236
|
var RangeSliderController = class extends Controller {
|
|
235
|
-
static targets = ["track", "startThumb", "endThumb"];
|
|
237
|
+
static targets = ["track", "startThumb", "endThumb", "startField", "endField"];
|
|
236
238
|
static values = {
|
|
237
239
|
min: { type: Number, default: DEFAULT_MIN },
|
|
238
240
|
max: { type: Number, default: DEFAULT_MAX },
|
|
@@ -242,9 +244,14 @@ var RangeSliderController = class extends Controller {
|
|
|
242
244
|
logicalTrack: { type: Boolean, default: false }
|
|
243
245
|
};
|
|
244
246
|
static actions = ["onKeydown", "onPointerDown"];
|
|
245
|
-
static events = ["change"];
|
|
247
|
+
static events = ["change", "reconcile"];
|
|
246
248
|
/** One initiating pointer owns each live drag and its stable target snapshot. */
|
|
247
249
|
#drag = null;
|
|
250
|
+
/**
|
|
251
|
+
* The pair last published: taken on connect, then moved by each user commit
|
|
252
|
+
* and by each repaint that reports a page-driven move.
|
|
253
|
+
*/
|
|
254
|
+
#settled = { start: DEFAULT_MIN, end: DEFAULT_MAX };
|
|
248
255
|
/** Whether the consumer declared a mirroring track and the direction mirrors it. */
|
|
249
256
|
get #mirrored() {
|
|
250
257
|
return this.logicalTrackValue && isRtl(this.element);
|
|
@@ -254,11 +261,14 @@ var RangeSliderController = class extends Controller {
|
|
|
254
261
|
* pass Stimulus delivers before `connect()`.
|
|
255
262
|
*/
|
|
256
263
|
#repaint = new MicrotaskCoalescer(() => this.#render());
|
|
264
|
+
/**
|
|
265
|
+
* Renders the normalized, ordered pair without writing it back, and takes it
|
|
266
|
+
* as the baseline, so connecting reports nothing.
|
|
267
|
+
*/
|
|
257
268
|
connect() {
|
|
258
269
|
this.#repaint.activate();
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
this.#commit(pair.start, pair.end, null, false);
|
|
270
|
+
this.#settled = this.#currentPair(this.#effectiveRange);
|
|
271
|
+
this.#render();
|
|
262
272
|
}
|
|
263
273
|
/** Cancels any active pointer drag so document listeners never leak. */
|
|
264
274
|
disconnect() {
|
|
@@ -313,6 +323,14 @@ var RangeSliderController = class extends Controller {
|
|
|
313
323
|
}
|
|
314
324
|
this.#repaint.schedule();
|
|
315
325
|
}
|
|
326
|
+
/** Fills a start field inserted or replaced at runtime on the next repaint. */
|
|
327
|
+
startFieldTargetConnected() {
|
|
328
|
+
this.#repaint.schedule();
|
|
329
|
+
}
|
|
330
|
+
/** Fills an end field inserted or replaced at runtime on the next repaint. */
|
|
331
|
+
endFieldTargetConnected() {
|
|
332
|
+
this.#repaint.schedule();
|
|
333
|
+
}
|
|
316
334
|
/** Drops a stale end-thumb reference without orphaning the track gesture. */
|
|
317
335
|
endThumbTargetDisconnected(thumb) {
|
|
318
336
|
if (this.#drag?.kind === "end" && this.#drag.thumb === thumb) this.#drag.thumb = null;
|
|
@@ -439,44 +457,72 @@ var RangeSliderController = class extends Controller {
|
|
|
439
457
|
#moveThumb(kind, raw) {
|
|
440
458
|
const pair = this.#currentPair(this.#effectiveRange);
|
|
441
459
|
if (kind === "start") {
|
|
442
|
-
this.#commit(raw, pair.end, "start"
|
|
460
|
+
this.#commit(raw, pair.end, "start");
|
|
443
461
|
} else {
|
|
444
|
-
this.#commit(pair.start, raw, "end"
|
|
462
|
+
this.#commit(pair.start, raw, "end");
|
|
445
463
|
}
|
|
446
464
|
}
|
|
447
465
|
/**
|
|
448
|
-
* Clamps and snaps
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
466
|
+
* Clamps and snaps the pair a user's move of the `moving` thumb produced,
|
|
467
|
+
* stops that thumb at its partner, stores the pair, and reflects it onto the
|
|
468
|
+
* thumbs' ARIA attributes and the range custom properties. The pair is
|
|
469
|
+
* reported as `change` when it differs from the pair last published — not from
|
|
470
|
+
* the pair the move started from — so a page write no repaint has published
|
|
471
|
+
* yet is reported once, as this change, and a move that ends on the pair last
|
|
472
|
+
* published reports nothing. The baseline moves before any report goes out,
|
|
473
|
+
* so the repaint the Value writes schedule — and any move a subscriber makes
|
|
474
|
+
* while the report is dispatched — is measured from this pair.
|
|
453
475
|
*/
|
|
454
|
-
#commit(start, end, moving
|
|
476
|
+
#commit(start, end, moving) {
|
|
455
477
|
const range = this.#effectiveRange;
|
|
456
|
-
const previous = this.#currentPair(range);
|
|
457
478
|
let nextStart = snapSteppedValue(start, range);
|
|
458
479
|
let nextEnd = snapSteppedValue(end, range);
|
|
459
480
|
if (nextStart > nextEnd) {
|
|
460
481
|
if (moving === "start") nextStart = nextEnd;
|
|
461
|
-
else
|
|
462
|
-
else [nextStart, nextEnd] = [nextEnd, nextStart];
|
|
482
|
+
else nextEnd = nextStart;
|
|
463
483
|
}
|
|
484
|
+
const pair = { start: nextStart, end: nextEnd };
|
|
485
|
+
const reported = this.#settled;
|
|
486
|
+
this.#settled = pair;
|
|
464
487
|
if (!Object.is(this.startValue, nextStart)) this.startValue = nextStart;
|
|
465
488
|
if (!Object.is(this.endValue, nextEnd)) this.endValue = nextEnd;
|
|
466
|
-
const pair = { start: nextStart, end: nextEnd };
|
|
467
489
|
this.#renderPair(pair, range);
|
|
468
|
-
|
|
490
|
+
this.#mirrorFields(pair, true);
|
|
491
|
+
if (nextStart !== reported.start || nextEnd !== reported.end) {
|
|
469
492
|
this.dispatch("change", { detail: { start: nextStart, end: nextEnd } });
|
|
470
493
|
}
|
|
471
494
|
}
|
|
472
495
|
/**
|
|
473
|
-
* Reflects
|
|
496
|
+
* Reflects the Values the page supplied without writing them back. A published
|
|
497
|
+
* pair that moved from the last one is reported once as `reconcile`; the
|
|
498
|
+
* fields follow without a native `change`.
|
|
474
499
|
*
|
|
475
500
|
* @stimeoRenderRoot
|
|
476
501
|
*/
|
|
477
502
|
#render() {
|
|
478
503
|
const range = this.#effectiveRange;
|
|
479
|
-
this.#
|
|
504
|
+
const pair = this.#currentPair(range);
|
|
505
|
+
this.#renderPair(pair, range);
|
|
506
|
+
this.#mirrorFields(pair, false);
|
|
507
|
+
const settled = this.#settled;
|
|
508
|
+
if (pair.start === settled.start && pair.end === settled.end) return;
|
|
509
|
+
this.#settled = pair;
|
|
510
|
+
this.dispatch("reconcile", { detail: { start: pair.start, end: pair.end } });
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Mirrors the pair into the optional form fields, reporting only a user's
|
|
514
|
+
* move. Each end is compared on its own, so dragging one thumb never reports
|
|
515
|
+
* a commit from the field the other thumb owns.
|
|
516
|
+
*/
|
|
517
|
+
#mirrorFields(pair, notify) {
|
|
518
|
+
if (this.hasStartFieldTarget) {
|
|
519
|
+
const field = this.startFieldTarget;
|
|
520
|
+
if (writeField(field, String(pair.start)) && notify) commitField(field);
|
|
521
|
+
}
|
|
522
|
+
if (this.hasEndFieldTarget) {
|
|
523
|
+
const field = this.endFieldTarget;
|
|
524
|
+
if (writeField(field, String(pair.end)) && notify) commitField(field);
|
|
525
|
+
}
|
|
480
526
|
}
|
|
481
527
|
/** Reflects one normalized pair onto both thumbs and CSS properties. */
|
|
482
528
|
#renderPair(pair, range) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/owned_pointer_session.ts","../../src/utils/range.ts","../../src/utils/stepped_value.ts","../../src/controllers/range_slider_controller.ts"],"names":["position"],"mappings":"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","file":"range_slider_controller.js","sourcesContent":["/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n\n/**\n * True when a press arrived carrying any modifier, for the keys the browser and\n * the OS own outright: return without calling `preventDefault()` and without\n * moving any state.\n *\n * `Control+Home` and `Control+End` jump the document to its ends, and a widget\n * that swallows them makes the shortcut work or not depending on where focus\n * happens to sit. {@link isReservedArrowChord} answers the same question for the\n * arrows, but returns `false` for every other key so that this one can decide.\n *\n * There is no `allow` list here on purpose. APG assigns no modifier chord to\n * `Home`/`End`, so a widget that wanted one would be claiming a combination the\n * pattern never gave it.\n *\n * @example\n * ```ts\n * case \"Home\":\n * case \"End\":\n * if (hasModifierChord(event)) return;\n * ```\n */\nexport function hasModifierChord(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","/** Callbacks driven by one owned pointer until it ends or is cancelled. */\nexport interface OwnedPointerSessionHandlers {\n /** Receives movement from the initiating pointer only. */\n readonly move: (event: PointerEvent) => void;\n /** Runs once after every listener and pointer capture have been released. */\n readonly end?: () => void;\n}\n\n/**\n * Owns one pointer across document-level movement and termination events.\n *\n * A controller may have at most one instance at a time. The session filters\n * every event by the initiating `pointerId`, captures the pointer when the DOM\n * implementation supports it, and binds all fallback document listeners to one\n * abort signal. Calling {@link OwnedPointerSession.end} is idempotent.\n */\nexport class OwnedPointerSession {\n readonly pointerId: number;\n readonly #owner: HTMLElement;\n readonly #handlers: OwnedPointerSessionHandlers;\n readonly #abort = new AbortController();\n #active = true;\n\n constructor(start: PointerEvent, owner: HTMLElement, handlers: OwnedPointerSessionHandlers) {\n this.pointerId = start.pointerId;\n this.#owner = owner;\n this.#handlers = handlers;\n\n const { signal } = this.#abort;\n owner.ownerDocument.addEventListener(\"pointermove\", this.#onMove, { signal });\n owner.ownerDocument.addEventListener(\"pointerup\", this.#onEndEvent, { signal });\n owner.ownerDocument.addEventListener(\"pointercancel\", this.#onEndEvent, { signal });\n owner.addEventListener(\"lostpointercapture\", this.#onLostCapture, { signal });\n\n // Pointer capture is progressive here: happy-dom and older DOM shims may not\n // implement it, while the document listeners still preserve ownership.\n try {\n owner.setPointerCapture?.(this.pointerId);\n } catch {\n // A synthetic or already-ended pointer cannot be captured; filtering and\n // AbortController teardown remain sufficient for that environment.\n }\n }\n\n /** Whether this session still owns its pointer and listeners. */\n get active(): boolean {\n return this.#active;\n }\n\n /** Whether `event` belongs to the initiating pointer of the live session. */\n owns(event: PointerEvent): boolean {\n return this.#active && event.pointerId === this.pointerId;\n }\n\n /** Releases capture/listeners and invokes the end callback exactly once. */\n end(): void {\n if (!this.#active) return;\n this.#active = false;\n this.#abort.abort();\n try {\n this.#owner.releasePointerCapture?.(this.pointerId);\n } catch {\n // Losing capture because the owner detached is already an ended session.\n }\n this.#handlers.end?.();\n }\n\n readonly #onMove = (event: PointerEvent): void => {\n if (this.owns(event)) this.#handlers.move(event);\n };\n\n readonly #onEndEvent = (event: PointerEvent): void => {\n if (this.owns(event)) this.end();\n };\n\n readonly #onLostCapture = (event: Event): void => {\n const pointerId = (event as PointerEvent).pointerId;\n if (typeof pointerId === \"number\" && pointerId !== this.pointerId) return;\n this.end();\n };\n}\n","/**\n * Range normalization shared by the value-bearing controllers (progress, meter,\n * slider, range-slider).\n *\n * Each of them publishes \"where the value sits inside `[min, max]`\" as a CSS\n * custom property the consumer multiplies a track by, and each has to answer the\n * same degenerate cases: empty and inverted ranges cannot express progress, and\n * malformed Number Values can produce `NaN`. Keeping the rule in one place is\n * what makes those answers identical across the four.\n */\n\n/**\n * Fraction of `[min, max]` that `value` occupies, always within `[0, 1]`.\n *\n * `value` is clamped into the range first, so a value outside it reports a full\n * or empty track rather than pushing the fraction past the ends.\n *\n * An empty, inverted, or non-numeric range yields `0`. That is a deliberate\n * floor rather than a computed result: `min === max` would produce `NaN`, and\n * `min > max` would report a full track for a value that is really out of range.\n * Non-finite results are floored for the same reason. These results reach\n * assistive tech, because the same fraction drives the percentage substituted\n * into `aria-valuetext`.\n */\nexport function rangeFraction(value: number, min: number, max: number): number {\n const span = max - min;\n if (!(span > 0)) return 0;\n\n const clamped = Math.min(max, Math.max(min, value));\n let fraction: number;\n if (Number.isFinite(span)) {\n fraction = (clamped - min) / span;\n } else {\n // Scaling preserves the ratio when two finite endpoints straddle zero so\n // widely that their subtraction overflows to Infinity.\n const scale = Math.max(Math.abs(min), Math.abs(max));\n fraction = (clamped / scale - min / scale) / (max / scale - min / scale);\n }\n\n if (!Number.isFinite(fraction)) return 0;\n return Math.min(1, Math.max(0, fraction));\n}\n","/** Configuration for a value constrained to a stepped numeric range. */\nexport interface SteppedRange {\n /** Inclusive lower endpoint. May be infinite for an unbounded control. */\n readonly min: number;\n /** Inclusive upper endpoint. May be infinite for an unbounded control. */\n readonly max: number;\n /** Requested step. Non-finite and non-positive values fall back to `1`. */\n readonly step: number;\n /** Step-grid origin. Defaults to a finite `min`, otherwise `0`. */\n readonly base?: number;\n}\n\n/** The positive finite step used at runtime and by keyboard stepping. */\nexport function effectiveStep(step: number): number {\n return Number.isFinite(step) && step > 0 ? step : 1;\n}\n\n/**\n * Clamps a raw value and selects its nearest allowed value.\n *\n * The allowed set is the step grid plus each finite range endpoint. Keeping the\n * endpoints in that set makes an authored `aria-valuemin`/`aria-valuemax`\n * truthful even when the upper endpoint is not aligned to the grid. A value\n * exactly between two allowed values resolves upward.\n */\nexport function snapSteppedValue(raw: number, range: SteppedRange): number {\n if (!(range.min <= range.max)) return finiteFallback(range.min, range.max);\n\n const input = Number.isNaN(raw) ? finiteFallback(range.min, range.max) : raw;\n const clamped = Math.min(range.max, Math.max(range.min, input));\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (Number.isFinite(range.min)) candidates.push(range.min);\n if (Number.isFinite(range.max)) candidates.push(range.max);\n\n const gridPosition = (clamped - base) / step;\n if (Number.isFinite(gridPosition)) {\n addGridCandidate(candidates, Math.floor(gridPosition), range, base, step);\n addGridCandidate(candidates, Math.ceil(gridPosition), range, base, step);\n }\n\n if (candidates.length === 0) return clamped;\n let nearest = candidates[0] as number;\n let nearestDistance = Math.abs(clamped - nearest);\n for (const candidate of candidates.slice(1)) {\n const distance = Math.abs(clamped - candidate);\n if (\n distance < nearestDistance ||\n (nearlyEqual(distance, nearestDistance) && candidate > nearest)\n ) {\n nearest = candidate;\n nearestDistance = distance;\n }\n }\n return nearest;\n}\n\n/**\n * Moves through the ordered allowed-value set by an integer number of steps.\n *\n * This differs from adding `step * count` and snapping afterward at an\n * off-grid endpoint: with `max=94, step=10`, one decrement from `94` must land\n * on `90`, and one increment from `90` must reach the advertised maximum `94`.\n */\nexport function stepSteppedValue(current: number, count: number, range: SteppedRange): number {\n const value = snapSteppedValue(current, range);\n const distance = Math.abs(Math.trunc(count));\n if (!Number.isFinite(distance) || distance === 0) return value;\n const direction = Math.sign(count);\n const adjacent = adjacentSteppedValue(value, direction, range);\n\n // The first move accounts for a possibly off-grid endpoint. From there a\n // direct grid jump is equivalent to repeated adjacency, and avoids work that\n // grows with Page-step magnitudes or programmatic counts.\n const raw = adjacent + direction * (distance - 1) * effectiveStep(range.step);\n return snapSteppedValue(raw, range);\n}\n\n/** Returns the next member of the ordered endpoint-plus-grid set. */\nfunction adjacentSteppedValue(current: number, direction: number, range: SteppedRange): number {\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (direction > 0) {\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.floor(position) + 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate < current || nearlyEqual(candidate, current)) {\n gridIndex += 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate > current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.min(...candidates), range);\n }\n\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.ceil(position) - 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate > current || nearlyEqual(candidate, current)) {\n gridIndex -= 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate < current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.max(...candidates), range);\n}\n\n/** Adds one grid value when it falls inside the inclusive range. */\nfunction addGridCandidate(\n candidates: number[],\n index: number,\n range: SteppedRange,\n base: number,\n step: number,\n): void {\n const candidate = cleanGridValue(base + index * step, base, step);\n if (within(candidate, range.min, range.max)) candidates.push(clamp(candidate, range));\n}\n\n/** A finite authored base wins; otherwise the finite lower bound or zero does. */\nfunction stepBase(range: SteppedRange): number {\n if (range.base !== undefined && Number.isFinite(range.base)) return range.base;\n return Number.isFinite(range.min) ? range.min : 0;\n}\n\n/** Removes binary noise without discarding significant integer-place digits. */\nfunction cleanGridValue(value: number, base: number, step: number): number {\n const precision = Math.max(decimalPlaces(base), decimalPlaces(step));\n // `toFixed` accepts at most 100 fractional digits. Below that limit it rounds\n // according to the authored grid precision rather than an arbitrary total\n // significant-digit count, which keeps unit steps distinct at large bases.\n return precision <= 100 ? Number(value.toFixed(precision)) : value;\n}\n\n/** Number of fractional decimal places represented by a finite JS number. */\nfunction decimalPlaces(value: number): number {\n const [coefficient = \"\", exponentText] = Math.abs(value).toString().toLowerCase().split(\"e\");\n const fractionLength = coefficient.split(\".\")[1]?.length ?? 0;\n const exponent = exponentText === undefined ? 0 : Number(exponentText);\n return Math.max(0, fractionLength - exponent);\n}\n\n/** Inclusive range check tolerant only of arithmetic noise at an endpoint. */\nfunction within(value: number, min: number, max: number): boolean {\n return (value > min || nearlyEqual(value, min)) && (value < max || nearlyEqual(value, max));\n}\n\n/** Clamps a candidate whose only overshoot may be floating-point noise. */\nfunction clamp(value: number, range: SteppedRange): number {\n return Math.min(range.max, Math.max(range.min, value));\n}\n\n/** Relative comparison used only to collapse arithmetic noise, not real steps. */\nfunction nearlyEqual(left: number, right: number): boolean {\n const scale = Math.max(Math.abs(left), Math.abs(right));\n return (\n Number.isFinite(left) &&\n Number.isFinite(right) &&\n Math.abs(left - right) <= Number.EPSILON * scale\n );\n}\n\n/** Stable fallback for malformed ranges or `NaN` input. */\nfunction finiteFallback(min: number, max: number): number {\n if (Number.isFinite(min)) return min;\n if (Number.isFinite(max)) return max;\n return 0;\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { isRtl } from \"../utils/logical_scroll\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { OwnedPointerSession } from \"../utils/owned_pointer_session\";\nimport { rangeFraction } from \"../utils/range\";\nimport { type SteppedRange, snapSteppedValue, stepSteppedValue } from \"../utils/stepped_value\";\n\n/** CSS custom properties exposing each thumb's position (0..1) to the consumer. */\nconst START_PROPERTY = \"--stimeo--range-slider-start\";\nconst END_PROPERTY = \"--stimeo--range-slider-end\";\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\n\n/**\n * Headless, accessible **two-thumb range slider** behavior (APG Slider —\n * Multi-Thumb). A derivative of {@link SliderController}: it manages two thumbs\n * (`start` ≤ `end`) that constrain each other.\n *\n * Markup contract (identifier: `stimeo--range-slider`):\n * <div data-controller=\"stimeo--range-slider\"\n * data-stimeo--range-slider-min-value=\"0\"\n * data-stimeo--range-slider-max-value=\"100\"\n * data-stimeo--range-slider-step-value=\"1\"\n * data-stimeo--range-slider-start-value=\"20\"\n * data-stimeo--range-slider-end-value=\"80\">\n * <div data-stimeo--range-slider-target=\"track\"\n * data-action=\"pointerdown->stimeo--range-slider#onPointerDown\">\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Minimum\"\n * data-stimeo--range-slider-target=\"startThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Maximum\"\n * data-stimeo--range-slider-target=\"endThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * </div>\n * </div>\n *\n * @remarks\n * Behavior only — the consumer owns all layout (positioning the thumbs and the\n * selected range from the fractions). Only the horizontal orientation is handled.\n * Each thumb's movable range is bounded by the *other* thumb's current value,\n * reflected on its `aria-valuemin`/`aria-valuemax` so assistive tech announces the\n * live constraint.\n *\n * Behavior provided (per focused thumb):\n * - `ArrowRight`/`ArrowUp` increase and `ArrowLeft`/`ArrowDown` decrease by one\n * step; `Home`/`End` jump to that thumb's movable min/max; `PageUp`/`PageDown`\n * move by ten steps. A thumb never crosses the other.\n * - Pointer press/drag on the track moves the nearest thumb.\n * When the thumbs overlap, a press above their shared value selects `end`\n * and a press below selects `start`, so the pair remains expandable.\n * - `min`, `max`, `start`, and `end` must be finite. Invalid runtime endpoints\n * fall back to `0`/`100`; invalid thumb Values fall back to the corresponding\n * effective endpoint. A `max` below `min` collapses the range to `min`.\n * - `step` must be finite and positive; invalid runtime input falls back to `1`.\n * Finite movable endpoints remain allowed off the shared step grid.\n *\n * The fractions are value ratios, not positions, so only the consumer knows\n * whether their track mirrors under RTL. Set `logicalTrack` to declare that it\n * does: the pointer mapping and the horizontal arrow pair then follow the\n * writing direction. Left unset, nothing here reads `direction`.\n */\nexport class RangeSliderController extends Controller<HTMLElement> {\n static override targets = [\"track\", \"startThumb\", \"endThumb\"];\n static override values = {\n min: { type: Number, default: DEFAULT_MIN },\n max: { type: Number, default: DEFAULT_MAX },\n step: { type: Number, default: 1 },\n start: { type: Number, default: 0 },\n end: { type: Number, default: 100 },\n logicalTrack: { type: Boolean, default: false },\n };\n static actions = [\"onKeydown\", \"onPointerDown\"] as const;\n static events = [\"change\"] as const;\n\n declare readonly trackTarget: HTMLElement;\n declare readonly startThumbTarget: HTMLElement;\n declare readonly endThumbTarget: HTMLElement;\n declare readonly hasTrackTarget: boolean;\n declare readonly hasStartThumbTarget: boolean;\n declare readonly hasEndThumbTarget: boolean;\n declare minValue: number;\n declare maxValue: number;\n declare stepValue: number;\n declare startValue: number;\n declare endValue: number;\n declare logicalTrackValue: boolean;\n\n /** One initiating pointer owns each live drag and its stable target snapshot. */\n #drag: RangeSliderDrag | null = null;\n\n /** Whether the consumer declared a mirroring track and the direction mirrors it. */\n get #mirrored(): boolean {\n return this.logicalTrackValue && isRtl(this.element);\n }\n\n /**\n * Collapses a morph that swaps render inputs into one repaint, and refuses the\n * pass Stimulus delivers before `connect()`.\n */\n readonly #repaint = new MicrotaskCoalescer(() => this.#render());\n\n override connect(): void {\n this.#repaint.activate();\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#commit(pair.start, pair.end, null, false);\n }\n\n /** Cancels any active pointer drag so document listeners never leak. */\n override disconnect(): void {\n this.#repaint.cancel();\n this.#endDrag();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `min` at runtime. */\n minValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `max` at runtime. */\n maxValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `step` at runtime. */\n stepValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `start` at runtime. */\n startValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `end` at runtime. */\n endValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Hydrates a replacement start thumb and restores live-drag focus ownership. */\n startThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderStartThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Drops a stale start-thumb reference without orphaning the track gesture. */\n startThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Hydrates a replacement end thumb and restores live-drag focus ownership. */\n endThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderEndThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Drops a stale end-thumb reference without orphaning the track gesture. */\n endThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Ends a gesture whose geometry target disappeared or ceased being a target. */\n trackTargetDisconnected(track: HTMLElement): void {\n if (this.#drag?.track === track) this.#endDrag();\n }\n\n /** Keyboard stepping for whichever thumb is focused (the action's element). */\n onKeydown(event: KeyboardEvent): void {\n if (isReservedArrowChord(event)) return;\n const thumb = event.currentTarget as HTMLElement;\n const isStart = this.hasStartThumbTarget && thumb === this.startThumbTarget;\n const isEnd = this.hasEndThumbTarget && thumb === this.endThumbTarget;\n const effectiveRange = this.#effectiveRange;\n const pair = this.#currentPair(effectiveRange);\n let kind: RangeThumb;\n let current: number;\n let range: { min: number; max: number; step: number; base: number };\n if (isStart) {\n kind = \"start\";\n current = pair.start;\n range = {\n min: effectiveRange.min,\n max: pair.end,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n } else {\n if (!isEnd) return;\n kind = \"end\";\n current = pair.end;\n range = {\n min: pair.start,\n max: effectiveRange.max,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n }\n\n let next: number | null = null;\n // On a mirrored track the greater value sits at the visual left, so the\n // horizontal pair trades places; `Home`/`End` name bounds, not a direction.\n switch (this.#mirrored ? logicalArrowKey(event.key, this.element) : event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n next = stepSteppedValue(current, 1, range);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n next = stepSteppedValue(current, -1, range);\n break;\n case \"PageUp\":\n next = stepSteppedValue(current, 10, range);\n break;\n case \"PageDown\":\n next = stepSteppedValue(current, -10, range);\n break;\n case \"Home\":\n next = range.min;\n break;\n case \"End\":\n next = range.max;\n break;\n default:\n return;\n }\n event.preventDefault();\n this.#moveThumb(kind, next);\n }\n\n /** Begins a pointer drag on the track, moving the thumb nearest the press. */\n onPointerDown(event: PointerEvent): void {\n if (\n event.button !== 0 ||\n this.#drag ||\n !this.hasTrackTarget ||\n !this.hasStartThumbTarget ||\n !this.hasEndThumbTarget\n ) {\n return;\n }\n const track = this.trackTarget;\n // Resolve the direction once for the whole gesture: reading it per move\n // would query computed style on every frame, and a drag that flipped\n // mid-gesture would be incoherent anyway.\n const mirrored = this.#mirrored;\n const value = this.#valueFromClientX(event.clientX, mirrored, track);\n if (value === null) return;\n event.preventDefault();\n\n // Pick the nearer thumb. An ordinary midpoint tie stays deterministic on\n // start; an overlapped pair uses the press direction so it can expand.\n // Only read a target getter behind its has*Target guard — Stimulus throws\n // when an absent target is accessed.\n const pair = this.#currentPair(this.#effectiveRange);\n const kind = this.#nearestThumb(value, pair);\n let thumb: HTMLElement;\n if (kind === \"start\") thumb = this.startThumbTarget;\n else thumb = this.endThumbTarget;\n this.#moveThumb(kind, value);\n thumb.focus();\n\n const drag: RangeSliderDrag = { pointer: null, track, thumb, kind };\n drag.pointer = new OwnedPointerSession(event, track, {\n move: (move) => {\n if (!track.isConnected) {\n this.#endDrag();\n return;\n }\n const moved = this.#valueFromClientX(move.clientX, mirrored, track);\n if (moved !== null) this.#moveThumb(kind, moved);\n },\n end: () => {\n if (this.#drag === drag) this.#drag = null;\n },\n });\n this.#drag = drag;\n }\n\n /** Maps a pointer X coordinate to a raw value using the track geometry. */\n #valueFromClientX(clientX: number, mirrored: boolean, track: HTMLElement): number | null {\n const rect = track.getBoundingClientRect();\n if (rect.width === 0) return null;\n const offset = (clientX - rect.left) / rect.width;\n const fraction = mirrored ? 1 - offset : offset;\n const range = this.#effectiveRange;\n return range.min + fraction * (range.max - range.min);\n }\n\n /**\n * Chooses the closest thumb while keeping an overlapped pair expandable.\n * Ordinary midpoint ties stay deterministic on `start`; at an overlap, a\n * press above the shared value selects `end` and a press below selects\n * `start`.\n */\n #nearestThumb(value: number, pair: RangePair): RangeThumb {\n const startDistance = Math.abs(value - pair.start);\n const endDistance = Math.abs(value - pair.end);\n if (endDistance < startDistance) return \"end\";\n if (pair.start === pair.end && value > pair.start) return \"end\";\n return \"start\";\n }\n\n /** Moves one thumb to a new raw value, keeping the pair ordered. */\n #moveThumb(kind: RangeThumb, raw: number): void {\n const pair = this.#currentPair(this.#effectiveRange);\n if (kind === \"start\") {\n this.#commit(raw, pair.end, \"start\", true);\n } else {\n this.#commit(pair.start, raw, \"end\", true);\n }\n }\n\n /**\n * Clamps and snaps `start`/`end`, enforces `start ≤ end`, stores the pair, and\n * reflects it onto the thumbs' ARIA attributes and the range custom\n * properties. Dispatches `stimeo--range-slider:change` only when a\n * user-driven update changes the normalized pair, with\n * `{ start: number, end: number }` in `detail`.\n */\n #commit(start: number, end: number, moving: RangeThumb | null, notify: boolean): void {\n const range = this.#effectiveRange;\n const previous = this.#currentPair(range);\n let nextStart = snapSteppedValue(start, range);\n let nextEnd = snapSteppedValue(end, range);\n // Keep them ordered: a thumb pushed past its partner stops at the partner.\n if (nextStart > nextEnd) {\n if (moving === \"start\") nextStart = nextEnd;\n else if (moving === \"end\") nextEnd = nextStart;\n else [nextStart, nextEnd] = [nextEnd, nextStart];\n }\n\n if (!Object.is(this.startValue, nextStart)) this.startValue = nextStart;\n if (!Object.is(this.endValue, nextEnd)) this.endValue = nextEnd;\n const pair = { start: nextStart, end: nextEnd };\n this.#renderPair(pair, range);\n\n if (notify && (nextStart !== previous.start || nextEnd !== previous.end)) {\n this.dispatch(\"change\", { detail: { start: nextStart, end: nextEnd } });\n }\n }\n\n /**\n * Reflects morph-supplied Values without writing them back or dispatching.\n *\n * @stimeoRenderRoot\n */\n #render(): void {\n const range = this.#effectiveRange;\n this.#renderPair(this.#currentPair(range), range);\n }\n\n /** Reflects one normalized pair onto both thumbs and CSS properties. */\n #renderPair(pair: RangePair, range: SteppedRange): void {\n if (this.hasStartThumbTarget) {\n this.#renderStartThumb(this.startThumbTarget, pair, range);\n }\n if (this.hasEndThumbTarget) {\n this.#renderEndThumb(this.endThumbTarget, pair, range);\n }\n this.#renderFractions(pair, range);\n }\n\n /** Writes only changed ARIA for the lower thumb. */\n #renderStartThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", range.min);\n this.#setAria(thumb, \"aria-valuemax\", pair.end);\n this.#setAria(thumb, \"aria-valuenow\", pair.start);\n }\n\n /** Writes only changed ARIA for the upper thumb. */\n #renderEndThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", pair.start);\n this.#setAria(thumb, \"aria-valuemax\", range.max);\n this.#setAria(thumb, \"aria-valuenow\", pair.end);\n }\n\n /** Writes one numeric ARIA attribute only when its serialized value changed. */\n #setAria(thumb: HTMLElement, name: string, value: number): void {\n const next = String(value);\n if (thumb.getAttribute(name) !== next) thumb.setAttribute(name, next);\n }\n\n /** Writes the two behavior-only fraction hooks only when they changed. */\n #renderFractions(pair: RangePair, range: SteppedRange): void {\n const start = String(rangeFraction(pair.start, range.min, range.max));\n const end = String(rangeFraction(pair.end, range.min, range.max));\n if (this.element.style.getPropertyValue(START_PROPERTY) !== start) {\n this.element.style.setProperty(START_PROPERTY, start);\n }\n if (this.element.style.getPropertyValue(END_PROPERTY) !== end) {\n this.element.style.setProperty(END_PROPERTY, end);\n }\n }\n\n /** Current normalized and ordered pair derived from live declarative Values. */\n #currentPair(range: SteppedRange): RangePair {\n const rawStart = Number.isFinite(this.startValue) ? this.startValue : range.min;\n const rawEnd = Number.isFinite(this.endValue) ? this.endValue : range.max;\n const start = snapSteppedValue(rawStart, range);\n const end = snapSteppedValue(rawEnd, range);\n if (start <= end) return { start, end };\n return { start: end, end: start };\n }\n\n /**\n * Finite ordered range used by ARIA, keyboard, pointer, and CSS reflection.\n * Invalid endpoints fall back to the public defaults; an authored `max`\n * below `min` collapses to the finite minimum.\n */\n get #effectiveRange(): SteppedRange {\n const min = Number.isFinite(this.minValue) ? this.minValue : DEFAULT_MIN;\n const authoredMax = Number.isFinite(this.maxValue) ? this.maxValue : DEFAULT_MAX;\n return { min, max: Math.max(min, authoredMax), step: this.stepValue, base: min };\n }\n\n /** Ends the current pointer session without dispatching another change. */\n #endDrag(): void {\n const drag = this.#drag;\n this.#drag = null;\n drag?.pointer?.end();\n }\n}\n\n/** Which thumb owns a keyboard or pointer move. */\ntype RangeThumb = \"start\" | \"end\";\n\n/** One normalized pair reflected on the two public slider roles. */\ninterface RangePair {\n readonly start: number;\n readonly end: number;\n}\n\n/** Stable DOM and gesture state owned for the duration of one pointer drag. */\ninterface RangeSliderDrag {\n pointer: OwnedPointerSession | null;\n readonly track: HTMLElement;\n thumb: HTMLElement | null;\n readonly kind: RangeThumb;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/field_mirror.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/owned_pointer_session.ts","../../src/utils/range.ts","../../src/utils/stepped_value.ts","../../src/controllers/range_slider_controller.ts"],"names":["position"],"mappings":"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","file":"range_slider_controller.js","sourcesContent":["/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n\n/**\n * True when a press arrived carrying any modifier, for the keys the browser and\n * the OS own outright: return without calling `preventDefault()` and without\n * moving any state.\n *\n * `Control+Home` and `Control+End` jump the document to its ends, and a widget\n * that swallows them makes the shortcut work or not depending on where focus\n * happens to sit. {@link isReservedArrowChord} answers the same question for the\n * arrows, but returns `false` for every other key so that this one can decide.\n *\n * There is no `allow` list here on purpose. APG assigns no modifier chord to\n * `Home`/`End`, so a widget that wanted one would be claiming a combination the\n * pattern never gave it.\n *\n * @example\n * ```ts\n * case \"Home\":\n * case \"End\":\n * if (hasModifierChord(event)) return;\n * ```\n */\nexport function hasModifierChord(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\n}\n","/**\n * The hidden form fields a widget keeps in step with the state it owns.\n *\n * A widget whose value lives in ARIA attributes submits nothing on its own, so\n * it mirrors that value into `<input type=\"hidden\">` — one field for a single\n * value, a container of generated fields for a set. The mirror is one-way: the\n * widget's own state stays the source of truth and the field is what the form\n * reads.\n *\n * The write and the report are separate calls because they answer to different\n * rules. A mirror is refreshed on connect, after a morph, and whenever the\n * widget repairs itself — none of which a form should treat as an edit. Only\n * the user's own commit reports one, which is why {@link commitField} is never\n * folded into the writes.\n */\n\n/** How a widget's generated fields identify themselves to the form. */\nexport interface GeneratedFieldOptions {\n /** The `name` every generated input submits under. */\n readonly name: string;\n /** The `form` id, for a widget that sits outside the form it submits to. */\n readonly form?: string;\n}\n\n/**\n * Mirrors one value into a hidden field.\n *\n * @returns Whether the field's value moved.\n *\n * @example\n * ```ts\n * if (writeField(this.fieldTarget, String(value)) && userDriven) {\n * commitField(this.fieldTarget);\n * }\n * ```\n */\nexport function writeField(field: HTMLInputElement, value: string): boolean {\n if (field.value === value) return false;\n field.value = value;\n return true;\n}\n\n/**\n * Mirrors a set of values into `container` as generated hidden fields, in the\n * order given.\n *\n * A container that already submits exactly this set is left untouched, children\n * and all — the mirror is refreshed far more often than it moves (every connect,\n * morph and repair), and a rebuild that changes nothing is still a DOM mutation\n * a consumer's observer and a `:empty` rule can see.\n *\n * @returns Whether the submitted set moved — its values, their order, the\n * `name`, or the `form`.\n */\nexport function writeFields(\n container: HTMLElement,\n values: readonly string[],\n { name, form = \"\" }: GeneratedFieldOptions,\n): boolean {\n const current = [...container.children];\n const submits =\n current.length === values.length &&\n current.every(\n (child, index) =>\n child instanceof HTMLInputElement &&\n child.type === \"hidden\" &&\n child.value === values[index] &&\n child.name === name &&\n (child.getAttribute(\"form\") ?? \"\") === form,\n );\n if (submits) return false;\n\n container.replaceChildren(\n ...values.map((value) => {\n const input = document.createElement(\"input\");\n input.type = \"hidden\";\n input.name = name;\n input.value = value;\n if (form !== \"\") input.setAttribute(\"form\", form);\n return input;\n }),\n );\n return true;\n}\n\n/**\n * Reports a committed value from `target` the way a native form control does:\n * one bubbling, non-cancelable `change`.\n *\n * Call it only for a move the user made. Form-level behaviors listen for this —\n * validation re-checks, auto-submit — and a mirror refreshed by a morph or a\n * repair is not something the user submitted.\n *\n * `target` is the element that carries the value: the hidden field for a single\n * mirrored value, the container for a generated set (whose own inputs are\n * replaced on every write), or a widget's own native control where that is what\n * the form reads.\n */\nexport function commitField(target: HTMLElement): void {\n target.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n\n/**\n * Reports an edit a widget made on the user's behalf, the way the browser\n * reports its own: one bubbling `input`, then one bubbling `change`.\n *\n * This is for a widget that owns the stepping or picking its *own* native\n * control would otherwise do — writing `control.value` from script fires\n * nothing, so a form listening for either event never hears the edit. Use\n * {@link commitField} instead where the element is a mirror of state held\n * elsewhere: a hidden field has no native edit to imitate, so it reports the\n * commit alone.\n *\n * Call it only for a move the user made, and only where the widget really did\n * the writing — an edit the browser already reported would be doubled.\n */\nexport function commitEdit(control: HTMLElement): void {\n control.dispatchEvent(new Event(\"input\", { bubbles: true }));\n control.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","/** What ended an owned pointer session. */\nexport type OwnedPointerSessionEnd = \"up\" | \"cancel\" | \"teardown\";\n\n/** Callbacks driven by one owned pointer until it ends or is cancelled. */\nexport interface OwnedPointerSessionHandlers {\n /** Receives movement from the initiating pointer only. */\n readonly move: (event: PointerEvent) => void;\n /**\n * Runs once after every listener and pointer capture have been released,\n * naming what ended the session.\n */\n readonly end?: (kind: OwnedPointerSessionEnd) => void;\n}\n\n/**\n * Owns one pointer across document-level movement and termination events.\n *\n * A controller may have at most one instance at a time. The session filters\n * every event by the initiating `pointerId` and binds all document listeners to\n * one abort signal, so exactly one callback runs when the session ends.\n *\n * **Pointer capture is delivery, not lifetime.** It is taken when the DOM\n * implementation supports it, and losing it — a consumer re-inserting the owner\n * mid-gesture, another element claiming the pointer — never ends the session:\n * the document listeners receive the pointer either way, because a captured\n * event still bubbles to the document and an uncaptured one fires there anyway.\n * An owner that actually left the tree is the owner's own business; every\n * consumer already answers that question with its own detach probe, and a\n * second answer here would cut gestures the consumer means to keep.\n */\nexport class OwnedPointerSession {\n readonly #pointerId: number;\n readonly #owner: HTMLElement;\n readonly #handlers: OwnedPointerSessionHandlers;\n readonly #abort = new AbortController();\n #active = true;\n\n constructor(start: PointerEvent, owner: HTMLElement, handlers: OwnedPointerSessionHandlers) {\n this.#pointerId = start.pointerId;\n this.#owner = owner;\n this.#handlers = handlers;\n\n const { signal } = this.#abort;\n owner.ownerDocument.addEventListener(\"pointermove\", this.#onMove, { signal });\n owner.ownerDocument.addEventListener(\"pointerup\", this.#onEndEvent, { signal });\n owner.ownerDocument.addEventListener(\"pointercancel\", this.#onEndEvent, { signal });\n\n // Pointer capture is progressive here: happy-dom and older DOM shims may not\n // implement it, while the document listeners still preserve ownership.\n try {\n owner.setPointerCapture?.(this.#pointerId);\n } catch {\n // A synthetic or already-ended pointer cannot be captured; filtering and\n // AbortController teardown remain sufficient for that environment.\n }\n }\n\n /** Releases capture and listeners, then reports the end exactly once. */\n end(): void {\n this.#finish(\"teardown\");\n }\n\n #finish(kind: OwnedPointerSessionEnd): void {\n if (!this.#active) return;\n this.#active = false;\n this.#abort.abort();\n try {\n this.#owner.releasePointerCapture?.(this.#pointerId);\n } catch {\n // Losing capture because the owner detached is already an ended session.\n }\n this.#handlers.end?.(kind);\n }\n\n #owns(event: PointerEvent): boolean {\n return this.#active && event.pointerId === this.#pointerId;\n }\n\n readonly #onMove = (event: PointerEvent): void => {\n if (this.#owns(event)) this.#handlers.move(event);\n };\n\n readonly #onEndEvent = (event: PointerEvent): void => {\n if (this.#owns(event)) this.#finish(event.type === \"pointerup\" ? \"up\" : \"cancel\");\n };\n}\n","/**\n * Range normalization shared by the value-bearing controllers (progress, meter,\n * slider, range-slider).\n *\n * Each of them publishes \"where the value sits inside `[min, max]`\" as a CSS\n * custom property the consumer multiplies a track by, and each has to answer the\n * same degenerate cases: empty and inverted ranges cannot express progress, and\n * malformed Number Values can produce `NaN`. Keeping the rule in one place is\n * what makes those answers identical across the four.\n */\n\n/**\n * Fraction of `[min, max]` that `value` occupies, always within `[0, 1]`.\n *\n * `value` is clamped into the range first, so a value outside it reports a full\n * or empty track rather than pushing the fraction past the ends.\n *\n * An empty, inverted, or non-numeric range yields `0`. That is a deliberate\n * floor rather than a computed result: `min === max` would produce `NaN`, and\n * `min > max` would report a full track for a value that is really out of range.\n * Non-finite results are floored for the same reason. These results reach\n * assistive tech, because the same fraction drives the percentage substituted\n * into `aria-valuetext`.\n */\nexport function rangeFraction(value: number, min: number, max: number): number {\n const span = max - min;\n if (!(span > 0)) return 0;\n\n const clamped = Math.min(max, Math.max(min, value));\n let fraction: number;\n if (Number.isFinite(span)) {\n fraction = (clamped - min) / span;\n } else {\n // Scaling preserves the ratio when two finite endpoints straddle zero so\n // widely that their subtraction overflows to Infinity.\n const scale = Math.max(Math.abs(min), Math.abs(max));\n fraction = (clamped / scale - min / scale) / (max / scale - min / scale);\n }\n\n if (!Number.isFinite(fraction)) return 0;\n return Math.min(1, Math.max(0, fraction));\n}\n","/** Configuration for a value constrained to a stepped numeric range. */\nexport interface SteppedRange {\n /** Inclusive lower endpoint. May be infinite for an unbounded control. */\n readonly min: number;\n /** Inclusive upper endpoint. May be infinite for an unbounded control. */\n readonly max: number;\n /** Requested step. Non-finite and non-positive values fall back to `1`. */\n readonly step: number;\n /** Step-grid origin. Defaults to a finite `min`, otherwise `0`. */\n readonly base?: number;\n}\n\n/** The positive finite step used at runtime and by keyboard stepping. */\nexport function effectiveStep(step: number): number {\n return Number.isFinite(step) && step > 0 ? step : 1;\n}\n\n/**\n * Clamps a raw value and selects its nearest allowed value.\n *\n * The allowed set is the step grid plus each finite range endpoint. Keeping the\n * endpoints in that set makes an authored `aria-valuemin`/`aria-valuemax`\n * truthful even when the upper endpoint is not aligned to the grid. A value\n * exactly between two allowed values resolves upward.\n */\nexport function snapSteppedValue(raw: number, range: SteppedRange): number {\n if (!(range.min <= range.max)) return finiteFallback(range.min, range.max);\n\n const input = Number.isNaN(raw) ? finiteFallback(range.min, range.max) : raw;\n const clamped = Math.min(range.max, Math.max(range.min, input));\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (Number.isFinite(range.min)) candidates.push(range.min);\n if (Number.isFinite(range.max)) candidates.push(range.max);\n\n const gridPosition = (clamped - base) / step;\n if (Number.isFinite(gridPosition)) {\n addGridCandidate(candidates, Math.floor(gridPosition), range, base, step);\n addGridCandidate(candidates, Math.ceil(gridPosition), range, base, step);\n }\n\n if (candidates.length === 0) return clamped;\n let nearest = candidates[0] as number;\n let nearestDistance = Math.abs(clamped - nearest);\n for (const candidate of candidates.slice(1)) {\n const distance = Math.abs(clamped - candidate);\n if (\n distance < nearestDistance ||\n (nearlyEqual(distance, nearestDistance) && candidate > nearest)\n ) {\n nearest = candidate;\n nearestDistance = distance;\n }\n }\n return nearest;\n}\n\n/**\n * Moves through the ordered allowed-value set by an integer number of steps.\n *\n * This differs from adding `step * count` and snapping afterward at an\n * off-grid endpoint: with `max=94, step=10`, one decrement from `94` must land\n * on `90`, and one increment from `90` must reach the advertised maximum `94`.\n */\nexport function stepSteppedValue(current: number, count: number, range: SteppedRange): number {\n const value = snapSteppedValue(current, range);\n const distance = Math.abs(Math.trunc(count));\n if (!Number.isFinite(distance) || distance === 0) return value;\n const direction = Math.sign(count);\n const adjacent = adjacentSteppedValue(value, direction, range);\n\n // The first move accounts for a possibly off-grid endpoint. From there a\n // direct grid jump is equivalent to repeated adjacency, and avoids work that\n // grows with Page-step magnitudes or programmatic counts.\n const raw = adjacent + direction * (distance - 1) * effectiveStep(range.step);\n return snapSteppedValue(raw, range);\n}\n\n/** Returns the next member of the ordered endpoint-plus-grid set. */\nfunction adjacentSteppedValue(current: number, direction: number, range: SteppedRange): number {\n const step = effectiveStep(range.step);\n const base = stepBase(range);\n const candidates: number[] = [];\n\n if (direction > 0) {\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.floor(position) + 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate < current || nearlyEqual(candidate, current)) {\n gridIndex += 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate > current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.min(...candidates), range);\n }\n\n const position = (current - base) / step;\n if (Number.isFinite(position)) {\n let gridIndex = Math.ceil(position) - 1;\n let candidate = cleanGridValue(base + gridIndex * step, base, step);\n if (candidate > current || nearlyEqual(candidate, current)) {\n gridIndex -= 1;\n candidate = cleanGridValue(base + gridIndex * step, base, step);\n }\n if (\n candidate < current &&\n !nearlyEqual(candidate, current) &&\n within(candidate, range.min, range.max)\n ) {\n candidates.push(clamp(candidate, range));\n }\n }\n return clamp(Math.max(...candidates), range);\n}\n\n/** Adds one grid value when it falls inside the inclusive range. */\nfunction addGridCandidate(\n candidates: number[],\n index: number,\n range: SteppedRange,\n base: number,\n step: number,\n): void {\n const candidate = cleanGridValue(base + index * step, base, step);\n if (within(candidate, range.min, range.max)) candidates.push(clamp(candidate, range));\n}\n\n/** A finite authored base wins; otherwise the finite lower bound or zero does. */\nfunction stepBase(range: SteppedRange): number {\n if (range.base !== undefined && Number.isFinite(range.base)) return range.base;\n return Number.isFinite(range.min) ? range.min : 0;\n}\n\n/** Removes binary noise without discarding significant integer-place digits. */\nfunction cleanGridValue(value: number, base: number, step: number): number {\n const precision = Math.max(decimalPlaces(base), decimalPlaces(step));\n // `toFixed` accepts at most 100 fractional digits. Below that limit it rounds\n // according to the authored grid precision rather than an arbitrary total\n // significant-digit count, which keeps unit steps distinct at large bases.\n return precision <= 100 ? Number(value.toFixed(precision)) : value;\n}\n\n/** Number of fractional decimal places represented by a finite JS number. */\nfunction decimalPlaces(value: number): number {\n const [coefficient = \"\", exponentText] = Math.abs(value).toString().toLowerCase().split(\"e\");\n const fractionLength = coefficient.split(\".\")[1]?.length ?? 0;\n const exponent = exponentText === undefined ? 0 : Number(exponentText);\n return Math.max(0, fractionLength - exponent);\n}\n\n/** Inclusive range check tolerant only of arithmetic noise at an endpoint. */\nfunction within(value: number, min: number, max: number): boolean {\n return (value > min || nearlyEqual(value, min)) && (value < max || nearlyEqual(value, max));\n}\n\n/** Clamps a candidate whose only overshoot may be floating-point noise. */\nfunction clamp(value: number, range: SteppedRange): number {\n return Math.min(range.max, Math.max(range.min, value));\n}\n\n/** Relative comparison used only to collapse arithmetic noise, not real steps. */\nfunction nearlyEqual(left: number, right: number): boolean {\n const scale = Math.max(Math.abs(left), Math.abs(right));\n return (\n Number.isFinite(left) &&\n Number.isFinite(right) &&\n Math.abs(left - right) <= Number.EPSILON * scale\n );\n}\n\n/** Stable fallback for malformed ranges or `NaN` input. */\nfunction finiteFallback(min: number, max: number): number {\n if (Number.isFinite(min)) return min;\n if (Number.isFinite(max)) return max;\n return 0;\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { commitField, writeField } from \"../utils/field_mirror\";\nimport { isRtl } from \"../utils/logical_scroll\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { OwnedPointerSession } from \"../utils/owned_pointer_session\";\nimport { rangeFraction } from \"../utils/range\";\nimport { type SteppedRange, snapSteppedValue, stepSteppedValue } from \"../utils/stepped_value\";\n\n/** CSS custom properties exposing each thumb's position (0..1) to the consumer. */\nconst START_PROPERTY = \"--stimeo--range-slider-start\";\nconst END_PROPERTY = \"--stimeo--range-slider-end\";\nconst DEFAULT_MIN = 0;\nconst DEFAULT_MAX = 100;\n\n/**\n * Headless, accessible **two-thumb range slider** behavior (APG Slider —\n * Multi-Thumb). A derivative of {@link SliderController}: it manages two thumbs\n * (`start` ≤ `end`) that constrain each other.\n *\n * Markup contract (identifier: `stimeo--range-slider`):\n * <div data-controller=\"stimeo--range-slider\"\n * data-stimeo--range-slider-min-value=\"0\"\n * data-stimeo--range-slider-max-value=\"100\"\n * data-stimeo--range-slider-step-value=\"1\"\n * data-stimeo--range-slider-start-value=\"20\"\n * data-stimeo--range-slider-end-value=\"80\">\n * <input type=\"hidden\" name=\"price_min\" data-stimeo--range-slider-target=\"startField\" />\n * <input type=\"hidden\" name=\"price_max\" data-stimeo--range-slider-target=\"endField\" />\n * <div data-stimeo--range-slider-target=\"track\"\n * data-action=\"pointerdown->stimeo--range-slider#onPointerDown\">\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Minimum\"\n * data-stimeo--range-slider-target=\"startThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * <div role=\"slider\" tabindex=\"0\" aria-label=\"Maximum\"\n * data-stimeo--range-slider-target=\"endThumb\"\n * data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n * </div>\n * </div>\n *\n * @remarks\n * Behavior only — the consumer owns all layout (positioning the thumbs and the\n * selected range from the fractions). Only the horizontal orientation is handled.\n * Each thumb's movable range is bounded by the *other* thumb's current value,\n * reflected on its `aria-valuemin`/`aria-valuemax` so assistive tech announces the\n * live constraint.\n *\n * Behavior provided (per focused thumb):\n * - `ArrowRight`/`ArrowUp` increase and `ArrowLeft`/`ArrowDown` decrease by one\n * step; `Home`/`End` jump to that thumb's movable min/max; `PageUp`/`PageDown`\n * move by ten steps. A thumb never crosses the other.\n * - Pointer press/drag on the track moves the nearest thumb.\n * When the thumbs overlap, a press above their shared value selects `end`\n * and a press below selects `start`, so the pair remains expandable.\n * - `min`, `max`, `start`, and `end` must be finite. Invalid runtime endpoints\n * fall back to `0`/`100`; invalid thumb Values fall back to the corresponding\n * effective endpoint. A `max` below `min` collapses the range to `min`.\n * - `step` must be finite and positive; invalid runtime input falls back to `1`.\n * Finite movable endpoints remain allowed off the shared step grid.\n *\n * `change` and `reconcile` dispatch `{ start: number, end: number }`.\n *\n * The Values are inputs. A declared pair that is reversed, off the step grid or\n * outside the range stays in its attributes as the page wrote it; the thumbs'\n * ARIA, the fractions and the fields publish the normalized, ordered pair\n * instead, and only a move the user makes writes `start` / `end`. `change`\n * reports a move the user made that left the pair somewhere other than the pair\n * last published. When a Value the page changes at runtime — a Turbo morph or\n * application code — moves the published pair, `reconcile` reports it once per\n * batch with the same detail, so a consumer can tell its user's move from the\n * page's. Connecting reports neither. A move handled before a page write to\n * either end is repainted reads the written pair, so its `change` covers the\n * write as well, and a move that ends on the pair last published reports\n * nothing. An event dispatched from script runs every listener with no\n * microtask between them, so a write made just before it, or by a listener\n * that runs ahead of the range slider, is handled that way. An event the\n * browser dispatches runs microtasks between the listeners it calls\n * separately, so a write made by one called ahead of the range slider's — a\n * capture listener on an ancestor or on `document`, a `:capture` action, or a\n * listener added to a thumb or the track before the range slider's action was\n * bound — is repainted, and reported as `reconcile`, before the move is\n * measured from it. Stimulus calls the actions an element declares for one\n * event and one set of listener options from a single listener, in declaration\n * order, so a write made by an action declared before the range slider's own\n * on a thumb or the track is handled like a write within an event dispatched\n * from script.\n *\n * The optional `startField` / `endField` targets mirror the normalized pair so\n * the range can be submitted and read server-side. An end the user moved emits\n * a native bubbling `change` from its own field, the way a form control does,\n * so `stimeo--auto-submit` and form-level validation hear it; the end that did\n * not move stays quiet. Both mirrors are refreshed silently on connect, on a\n * replacement field, and whenever a morph or application code writes a Value.\n *\n * The fractions are value ratios, not positions, so only the consumer knows\n * whether their track mirrors under RTL. Set `logicalTrack` to declare that it\n * does: the pointer mapping and the horizontal arrow pair then follow the\n * writing direction. Left unset, nothing here reads `direction`.\n */\nexport class RangeSliderController extends Controller<HTMLElement> {\n static override targets = [\"track\", \"startThumb\", \"endThumb\", \"startField\", \"endField\"];\n static override values = {\n min: { type: Number, default: DEFAULT_MIN },\n max: { type: Number, default: DEFAULT_MAX },\n step: { type: Number, default: 1 },\n start: { type: Number, default: 0 },\n end: { type: Number, default: 100 },\n logicalTrack: { type: Boolean, default: false },\n };\n static actions = [\"onKeydown\", \"onPointerDown\"] as const;\n static events = [\"change\", \"reconcile\"] as const;\n\n declare readonly trackTarget: HTMLElement;\n declare readonly startThumbTarget: HTMLElement;\n declare readonly endThumbTarget: HTMLElement;\n declare readonly startFieldTarget: HTMLInputElement;\n declare readonly endFieldTarget: HTMLInputElement;\n declare readonly hasTrackTarget: boolean;\n declare readonly hasStartThumbTarget: boolean;\n declare readonly hasEndThumbTarget: boolean;\n declare readonly hasStartFieldTarget: boolean;\n declare readonly hasEndFieldTarget: boolean;\n declare minValue: number;\n declare maxValue: number;\n declare stepValue: number;\n declare startValue: number;\n declare endValue: number;\n declare logicalTrackValue: boolean;\n\n /** One initiating pointer owns each live drag and its stable target snapshot. */\n #drag: RangeSliderDrag | null = null;\n\n /**\n * The pair last published: taken on connect, then moved by each user commit\n * and by each repaint that reports a page-driven move.\n */\n #settled: RangePair = { start: DEFAULT_MIN, end: DEFAULT_MAX };\n\n /** Whether the consumer declared a mirroring track and the direction mirrors it. */\n get #mirrored(): boolean {\n return this.logicalTrackValue && isRtl(this.element);\n }\n\n /**\n * Collapses a morph that swaps render inputs into one repaint, and refuses the\n * pass Stimulus delivers before `connect()`.\n */\n readonly #repaint = new MicrotaskCoalescer(() => this.#render());\n\n /**\n * Renders the normalized, ordered pair without writing it back, and takes it\n * as the baseline, so connecting reports nothing.\n */\n override connect(): void {\n this.#repaint.activate();\n this.#settled = this.#currentPair(this.#effectiveRange);\n this.#render();\n }\n\n /** Cancels any active pointer drag so document listeners never leak. */\n override disconnect(): void {\n this.#repaint.cancel();\n this.#endDrag();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `min` at runtime. */\n minValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `max` at runtime. */\n maxValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `step` at runtime. */\n stepValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `start` at runtime. */\n startValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `end` at runtime. */\n endValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Hydrates a replacement start thumb and restores live-drag focus ownership. */\n startThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderStartThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Drops a stale start-thumb reference without orphaning the track gesture. */\n startThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"start\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Hydrates a replacement end thumb and restores live-drag focus ownership. */\n endThumbTargetConnected(thumb: HTMLElement): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderEndThumb(thumb, pair, range);\n this.#renderFractions(pair, range);\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === null) {\n this.#drag.thumb = thumb;\n thumb.focus();\n }\n this.#repaint.schedule();\n }\n\n /** Fills a start field inserted or replaced at runtime on the next repaint. */\n startFieldTargetConnected(): void {\n this.#repaint.schedule();\n }\n\n /** Fills an end field inserted or replaced at runtime on the next repaint. */\n endFieldTargetConnected(): void {\n this.#repaint.schedule();\n }\n\n /** Drops a stale end-thumb reference without orphaning the track gesture. */\n endThumbTargetDisconnected(thumb: HTMLElement): void {\n if (this.#drag?.kind === \"end\" && this.#drag.thumb === thumb) this.#drag.thumb = null;\n }\n\n /** Ends a gesture whose geometry target disappeared or ceased being a target. */\n trackTargetDisconnected(track: HTMLElement): void {\n if (this.#drag?.track === track) this.#endDrag();\n }\n\n /** Keyboard stepping for whichever thumb is focused (the action's element). */\n onKeydown(event: KeyboardEvent): void {\n if (isReservedArrowChord(event)) return;\n const thumb = event.currentTarget as HTMLElement;\n const isStart = this.hasStartThumbTarget && thumb === this.startThumbTarget;\n const isEnd = this.hasEndThumbTarget && thumb === this.endThumbTarget;\n const effectiveRange = this.#effectiveRange;\n const pair = this.#currentPair(effectiveRange);\n let kind: RangeThumb;\n let current: number;\n let range: { min: number; max: number; step: number; base: number };\n if (isStart) {\n kind = \"start\";\n current = pair.start;\n range = {\n min: effectiveRange.min,\n max: pair.end,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n } else {\n if (!isEnd) return;\n kind = \"end\";\n current = pair.end;\n range = {\n min: pair.start,\n max: effectiveRange.max,\n step: effectiveRange.step,\n base: effectiveRange.min,\n };\n }\n\n let next: number | null = null;\n // On a mirrored track the greater value sits at the visual left, so the\n // horizontal pair trades places; `Home`/`End` name bounds, not a direction.\n switch (this.#mirrored ? logicalArrowKey(event.key, this.element) : event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n next = stepSteppedValue(current, 1, range);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n next = stepSteppedValue(current, -1, range);\n break;\n case \"PageUp\":\n next = stepSteppedValue(current, 10, range);\n break;\n case \"PageDown\":\n next = stepSteppedValue(current, -10, range);\n break;\n case \"Home\":\n next = range.min;\n break;\n case \"End\":\n next = range.max;\n break;\n default:\n return;\n }\n event.preventDefault();\n this.#moveThumb(kind, next);\n }\n\n /** Begins a pointer drag on the track, moving the thumb nearest the press. */\n onPointerDown(event: PointerEvent): void {\n if (\n event.button !== 0 ||\n this.#drag ||\n !this.hasTrackTarget ||\n !this.hasStartThumbTarget ||\n !this.hasEndThumbTarget\n ) {\n return;\n }\n const track = this.trackTarget;\n // Resolve the direction once for the whole gesture: reading it per move\n // would query computed style on every frame, and a drag that flipped\n // mid-gesture would be incoherent anyway.\n const mirrored = this.#mirrored;\n const value = this.#valueFromClientX(event.clientX, mirrored, track);\n if (value === null) return;\n event.preventDefault();\n\n // Pick the nearer thumb. An ordinary midpoint tie stays deterministic on\n // start; an overlapped pair uses the press direction so it can expand.\n // Only read a target getter behind its has*Target guard — Stimulus throws\n // when an absent target is accessed.\n const pair = this.#currentPair(this.#effectiveRange);\n const kind = this.#nearestThumb(value, pair);\n let thumb: HTMLElement;\n if (kind === \"start\") thumb = this.startThumbTarget;\n else thumb = this.endThumbTarget;\n this.#moveThumb(kind, value);\n thumb.focus();\n\n const drag: RangeSliderDrag = { pointer: null, track, thumb, kind };\n drag.pointer = new OwnedPointerSession(event, track, {\n move: (move) => {\n if (!track.isConnected) {\n this.#endDrag();\n return;\n }\n const moved = this.#valueFromClientX(move.clientX, mirrored, track);\n if (moved !== null) this.#moveThumb(kind, moved);\n },\n end: () => {\n if (this.#drag === drag) this.#drag = null;\n },\n });\n this.#drag = drag;\n }\n\n /** Maps a pointer X coordinate to a raw value using the track geometry. */\n #valueFromClientX(clientX: number, mirrored: boolean, track: HTMLElement): number | null {\n const rect = track.getBoundingClientRect();\n if (rect.width === 0) return null;\n const offset = (clientX - rect.left) / rect.width;\n const fraction = mirrored ? 1 - offset : offset;\n const range = this.#effectiveRange;\n return range.min + fraction * (range.max - range.min);\n }\n\n /**\n * Chooses the closest thumb while keeping an overlapped pair expandable.\n * Ordinary midpoint ties stay deterministic on `start`; at an overlap, a\n * press above the shared value selects `end` and a press below selects\n * `start`.\n */\n #nearestThumb(value: number, pair: RangePair): RangeThumb {\n const startDistance = Math.abs(value - pair.start);\n const endDistance = Math.abs(value - pair.end);\n if (endDistance < startDistance) return \"end\";\n if (pair.start === pair.end && value > pair.start) return \"end\";\n return \"start\";\n }\n\n /** Moves one thumb to a new raw value, keeping the pair ordered. */\n #moveThumb(kind: RangeThumb, raw: number): void {\n const pair = this.#currentPair(this.#effectiveRange);\n if (kind === \"start\") {\n this.#commit(raw, pair.end, \"start\");\n } else {\n this.#commit(pair.start, raw, \"end\");\n }\n }\n\n /**\n * Clamps and snaps the pair a user's move of the `moving` thumb produced,\n * stops that thumb at its partner, stores the pair, and reflects it onto the\n * thumbs' ARIA attributes and the range custom properties. The pair is\n * reported as `change` when it differs from the pair last published — not from\n * the pair the move started from — so a page write no repaint has published\n * yet is reported once, as this change, and a move that ends on the pair last\n * published reports nothing. The baseline moves before any report goes out,\n * so the repaint the Value writes schedule — and any move a subscriber makes\n * while the report is dispatched — is measured from this pair.\n */\n #commit(start: number, end: number, moving: RangeThumb): void {\n const range = this.#effectiveRange;\n let nextStart = snapSteppedValue(start, range);\n let nextEnd = snapSteppedValue(end, range);\n // Keep them ordered: a thumb pushed past its partner stops at the partner.\n if (nextStart > nextEnd) {\n if (moving === \"start\") nextStart = nextEnd;\n else nextEnd = nextStart;\n }\n\n const pair = { start: nextStart, end: nextEnd };\n const reported = this.#settled;\n this.#settled = pair;\n if (!Object.is(this.startValue, nextStart)) this.startValue = nextStart;\n if (!Object.is(this.endValue, nextEnd)) this.endValue = nextEnd;\n this.#renderPair(pair, range);\n this.#mirrorFields(pair, true);\n\n if (nextStart !== reported.start || nextEnd !== reported.end) {\n this.dispatch(\"change\", { detail: { start: nextStart, end: nextEnd } });\n }\n }\n\n /**\n * Reflects the Values the page supplied without writing them back. A published\n * pair that moved from the last one is reported once as `reconcile`; the\n * fields follow without a native `change`.\n *\n * @stimeoRenderRoot\n */\n #render(): void {\n const range = this.#effectiveRange;\n const pair = this.#currentPair(range);\n this.#renderPair(pair, range);\n this.#mirrorFields(pair, false);\n const settled = this.#settled;\n if (pair.start === settled.start && pair.end === settled.end) return;\n this.#settled = pair;\n this.dispatch(\"reconcile\", { detail: { start: pair.start, end: pair.end } });\n }\n\n /**\n * Mirrors the pair into the optional form fields, reporting only a user's\n * move. Each end is compared on its own, so dragging one thumb never reports\n * a commit from the field the other thumb owns.\n */\n #mirrorFields(pair: RangePair, notify: boolean): void {\n if (this.hasStartFieldTarget) {\n const field = this.startFieldTarget;\n if (writeField(field, String(pair.start)) && notify) commitField(field);\n }\n if (this.hasEndFieldTarget) {\n const field = this.endFieldTarget;\n if (writeField(field, String(pair.end)) && notify) commitField(field);\n }\n }\n\n /** Reflects one normalized pair onto both thumbs and CSS properties. */\n #renderPair(pair: RangePair, range: SteppedRange): void {\n if (this.hasStartThumbTarget) {\n this.#renderStartThumb(this.startThumbTarget, pair, range);\n }\n if (this.hasEndThumbTarget) {\n this.#renderEndThumb(this.endThumbTarget, pair, range);\n }\n this.#renderFractions(pair, range);\n }\n\n /** Writes only changed ARIA for the lower thumb. */\n #renderStartThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", range.min);\n this.#setAria(thumb, \"aria-valuemax\", pair.end);\n this.#setAria(thumb, \"aria-valuenow\", pair.start);\n }\n\n /** Writes only changed ARIA for the upper thumb. */\n #renderEndThumb(thumb: HTMLElement, pair: RangePair, range: SteppedRange): void {\n this.#setAria(thumb, \"aria-valuemin\", pair.start);\n this.#setAria(thumb, \"aria-valuemax\", range.max);\n this.#setAria(thumb, \"aria-valuenow\", pair.end);\n }\n\n /** Writes one numeric ARIA attribute only when its serialized value changed. */\n #setAria(thumb: HTMLElement, name: string, value: number): void {\n const next = String(value);\n if (thumb.getAttribute(name) !== next) thumb.setAttribute(name, next);\n }\n\n /** Writes the two behavior-only fraction hooks only when they changed. */\n #renderFractions(pair: RangePair, range: SteppedRange): void {\n const start = String(rangeFraction(pair.start, range.min, range.max));\n const end = String(rangeFraction(pair.end, range.min, range.max));\n if (this.element.style.getPropertyValue(START_PROPERTY) !== start) {\n this.element.style.setProperty(START_PROPERTY, start);\n }\n if (this.element.style.getPropertyValue(END_PROPERTY) !== end) {\n this.element.style.setProperty(END_PROPERTY, end);\n }\n }\n\n /** Current normalized and ordered pair derived from live declarative Values. */\n #currentPair(range: SteppedRange): RangePair {\n const rawStart = Number.isFinite(this.startValue) ? this.startValue : range.min;\n const rawEnd = Number.isFinite(this.endValue) ? this.endValue : range.max;\n const start = snapSteppedValue(rawStart, range);\n const end = snapSteppedValue(rawEnd, range);\n if (start <= end) return { start, end };\n return { start: end, end: start };\n }\n\n /**\n * Finite ordered range used by ARIA, keyboard, pointer, and CSS reflection.\n * Invalid endpoints fall back to the public defaults; an authored `max`\n * below `min` collapses to the finite minimum.\n */\n get #effectiveRange(): SteppedRange {\n const min = Number.isFinite(this.minValue) ? this.minValue : DEFAULT_MIN;\n const authoredMax = Number.isFinite(this.maxValue) ? this.maxValue : DEFAULT_MAX;\n return { min, max: Math.max(min, authoredMax), step: this.stepValue, base: min };\n }\n\n /** Ends the current pointer session without dispatching another change. */\n #endDrag(): void {\n const drag = this.#drag;\n this.#drag = null;\n drag?.pointer?.end();\n }\n}\n\n/** Which thumb owns a keyboard or pointer move. */\ntype RangeThumb = \"start\" | \"end\";\n\n/** One normalized pair reflected on the two public slider roles. */\ninterface RangePair {\n readonly start: number;\n readonly end: number;\n}\n\n/** Stable DOM and gesture state owned for the duration of one pointer drag. */\ninterface RangeSliderDrag {\n pointer: OwnedPointerSession | null;\n readonly track: HTMLElement;\n thumb: HTMLElement | null;\n readonly kind: RangeThumb;\n}\n"]}
|
|
@@ -23,7 +23,11 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
23
23
|
* the last is N. Unlike a generic radio group, arrows deliberately clamp rather
|
|
24
24
|
* than wrap because the values have an ordered lower and upper bound.
|
|
25
25
|
*
|
|
26
|
-
* `change` and `reconcile` dispatch `{ value: number }`.
|
|
26
|
+
* `change` and `reconcile` dispatch `{ value: number }`. A rating the user set
|
|
27
|
+
* also emits a native bubbling `change` from the hidden `field`, the way a form
|
|
28
|
+
* control does, so `stimeo--auto-submit` and form-level validation hear it; a
|
|
29
|
+
* repaint driven by the `value` Value, by a replacement field, or by the
|
|
30
|
+
* controller's own normalization refreshes the mirror silently.
|
|
27
31
|
*
|
|
28
32
|
* @remarks
|
|
29
33
|
* Behavior only — consumers style `[aria-checked]` and `data-rating-hover`. In
|
|
@@ -32,9 +36,16 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
32
36
|
* a symbol when that mode begins lands on the root and returns to the Tab stop
|
|
33
37
|
* when it ends, so it is never left on a node outside the accessibility tree.
|
|
34
38
|
*
|
|
39
|
+
* The `value` Value is the page's request. The rating shown is that request
|
|
40
|
+
* normalized to the live scale, and normalizing never writes the Value back: a
|
|
41
|
+
* value clamped by a shorter scale or by `clearable` comes back once the scale
|
|
42
|
+
* or `clearable` allows it again. A value the user sets is written into it.
|
|
43
|
+
*
|
|
35
44
|
* `stimeo--rating:change` is reserved for a user operation that changes the
|
|
36
|
-
* committed value.
|
|
37
|
-
*
|
|
45
|
+
* committed value. Once connected, any other move of the rating shown — a
|
|
46
|
+
* `value` written by application code or a morph, a symbol added or removed, a
|
|
47
|
+
* `clearable` change — emits `stimeo--rating:reconcile` once per batch, measured
|
|
48
|
+
* from the rating last shown. Initial reflection emits neither.
|
|
38
49
|
*/
|
|
39
50
|
declare class RatingController extends Controller<HTMLElement> {
|
|
40
51
|
#private;
|