stimeo-ui 0.17.0 → 0.18.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +136 -2
- data/README.md +19 -10
- data/dist/cable/index.js +22 -14
- data/dist/controllers/accordion_controller.js +14 -6
- data/dist/controllers/alert_dialog_controller.js +145 -118
- data/dist/controllers/announcer_controller.js +113 -17
- data/dist/controllers/auto_submit_controller.js +185 -60
- data/dist/controllers/avatar_controller.js +55 -43
- data/dist/controllers/bulk_select_controller.js +64 -50
- data/dist/controllers/calendar_controller.js +55 -53
- data/dist/controllers/carousel_controller.js +124 -86
- data/dist/controllers/character_counter_controller.js +291 -95
- data/dist/controllers/checkbox_controller.js +6 -0
- data/dist/controllers/clipboard_controller.js +118 -27
- data/dist/controllers/collapsible_controller.js +52 -49
- data/dist/controllers/color_picker_controller.js +29 -7
- data/dist/controllers/combobox_controller.js +210 -71
- data/dist/controllers/command_palette_controller.js +290 -140
- data/dist/controllers/conditional_fields_controller.js +145 -58
- data/dist/controllers/confirm_controller.js +145 -118
- data/dist/controllers/context_menu_controller.js +138 -73
- data/dist/controllers/countdown_controller.js +109 -21
- data/dist/controllers/currency_input_controller.js +446 -72
- data/dist/controllers/data_grid_controller.js +134 -28
- data/dist/controllers/date_range_picker_controller.js +93 -72
- data/dist/controllers/dialog_controller.js +145 -118
- data/dist/controllers/direct_upload_controller.js +24 -14
- data/dist/controllers/dirty_form_controller.js +68 -31
- data/dist/controllers/dismissible_controller.js +66 -46
- data/dist/controllers/drawer_controller.js +145 -118
- data/dist/controllers/dropdown_controller.js +76 -63
- data/dist/controllers/editable_controller.js +200 -62
- data/dist/controllers/empty_state_controller.js +13 -6
- data/dist/controllers/file_dropzone_controller.js +55 -48
- data/dist/controllers/filter_controller.js +9 -2
- data/dist/controllers/flash_controller.js +66 -33
- data/dist/controllers/focus_controller.js +39 -14
- data/dist/controllers/form_field_controller.js +52 -43
- data/dist/controllers/form_validation_controller.js +18 -11
- data/dist/controllers/frame_loading_controller.js +55 -48
- data/dist/controllers/hover_card_controller.js +67 -61
- data/dist/controllers/idle_controller.js +10 -6
- data/dist/controllers/input_mask_controller.js +434 -24
- data/dist/controllers/intersection_controller.js +3 -0
- data/dist/controllers/lazy_frame_controller.js +15 -3
- data/dist/controllers/listbox_controller.js +260 -79
- data/dist/controllers/local_time_controller.js +48 -13
- data/dist/controllers/masonry_controller.js +11 -4
- data/dist/controllers/menu_controller.js +138 -82
- data/dist/controllers/menubar_controller.js +65 -19
- data/dist/controllers/meter_controller.js +270 -24
- data/dist/controllers/multi_select_controller.js +272 -95
- data/dist/controllers/navigation_menu_controller.js +67 -19
- data/dist/controllers/nested_form_controller.js +98 -64
- data/dist/controllers/network_status_controller.js +70 -52
- data/dist/controllers/number_input_controller.js +344 -94
- data/dist/controllers/optimistic_controller.js +29 -11
- data/dist/controllers/otp_controller.js +502 -104
- data/dist/controllers/overflow_indicator_controller.js +6 -0
- data/dist/controllers/overflow_menu_controller.js +136 -21
- data/dist/controllers/pagination_controller.js +47 -14
- data/dist/controllers/password_reveal_controller.js +52 -49
- data/dist/controllers/password_strength_controller.js +13 -6
- data/dist/controllers/persist_controller.js +48 -128
- data/dist/controllers/pointer_drag_controller.js +255 -24
- data/dist/controllers/popover_controller.js +91 -65
- data/dist/controllers/portal_controller.js +6 -0
- data/dist/controllers/preview_guard_controller.js +14 -3
- data/dist/controllers/progress_controller.js +271 -27
- data/dist/controllers/radio_group_controller.js +167 -80
- data/dist/controllers/range_slider_controller.js +27 -7
- data/dist/controllers/rating_controller.js +93 -57
- data/dist/controllers/read_more_controller.js +10 -6
- data/dist/controllers/reading_progress_controller.js +22 -5
- data/dist/controllers/relative_time_controller.js +75 -11
- data/dist/controllers/reset_on_restore_controller.js +6 -0
- data/dist/controllers/resizable_controller.js +55 -22
- data/dist/controllers/roving_controller.js +10 -4
- data/dist/controllers/scroll_area_controller.js +129 -88
- data/dist/controllers/scroll_restore_controller.js +14 -2
- data/dist/controllers/scroll_visibility_controller.js +93 -60
- data/dist/controllers/scrollspy_controller.js +11 -5
- data/dist/controllers/separator_controller.js +59 -43
- data/dist/controllers/sidebar_controller.js +150 -122
- data/dist/controllers/skeleton_controller.js +55 -48
- data/dist/controllers/slider_controller.js +27 -6
- data/dist/controllers/smart_sticky_header_controller.js +13 -5
- data/dist/controllers/sortable_controller.js +27 -14
- data/dist/controllers/spinner_controller.js +55 -48
- data/dist/controllers/step_indicator_controller.js +6 -0
- data/dist/controllers/stepper_controller.js +6 -0
- data/dist/controllers/stick_to_bottom_controller.js +19 -8
- data/dist/controllers/sticky_observer_controller.js +49 -43
- data/dist/controllers/submit_once_controller.js +145 -85
- data/dist/controllers/switch_controller.js +172 -28
- data/dist/controllers/tabs_controller.js +6 -1
- data/dist/controllers/tags_input_controller.js +157 -28
- data/dist/controllers/textarea_autosize_controller.js +40 -19
- data/dist/controllers/theme_controller.js +10 -4
- data/dist/controllers/time_picker_controller.js +192 -54
- data/dist/controllers/toast_controller.js +58 -27
- data/dist/controllers/toggle_group_controller.js +158 -56
- data/dist/controllers/toolbar_controller.js +150 -21
- data/dist/controllers/tree_view_controller.js +134 -25
- data/dist/index.js +2515 -1315
- data/dist/positioning/index.js +6 -0
- data/lib/generators/stimeo/install/install_generator.rb +7 -2
- data/lib/generators/stimeo/install/templates/stimeo.js +19 -6
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +2 -2
|
@@ -37,6 +37,107 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
37
37
|
if (!event.key.startsWith("Arrow")) return false;
|
|
38
38
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
39
39
|
}
|
|
40
|
+
function hasModifierChord(event) {
|
|
41
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
45
|
+
if (element.getAttribute(name) === value) return false;
|
|
46
|
+
beforeWrite?.();
|
|
47
|
+
if (value === null) element.removeAttribute(name);
|
|
48
|
+
else element.setAttribute(name, value);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var AuthoredMutationWatcher = class {
|
|
53
|
+
#onAuthored;
|
|
54
|
+
#claims = null;
|
|
55
|
+
#observer = null;
|
|
56
|
+
constructor(onAuthored) {
|
|
57
|
+
this.#onAuthored = onAuthored;
|
|
58
|
+
}
|
|
59
|
+
observe(root, options) {
|
|
60
|
+
this.disconnect();
|
|
61
|
+
const observer = new MutationObserver((records) => {
|
|
62
|
+
if (this.#observer !== observer) return;
|
|
63
|
+
const authored = this.#filter(records);
|
|
64
|
+
if (authored.length > 0) this.#onAuthored(authored);
|
|
65
|
+
});
|
|
66
|
+
this.#observer = observer;
|
|
67
|
+
this.#claims = { attributes: /* @__PURE__ */ new Map(), children: /* @__PURE__ */ new Map() };
|
|
68
|
+
observer.observe(root, {
|
|
69
|
+
attributes: true,
|
|
70
|
+
attributeFilter: [...options.attributes],
|
|
71
|
+
subtree: options.subtree ?? false,
|
|
72
|
+
childList: options.childList ?? false
|
|
73
|
+
});
|
|
74
|
+
if (options.ancestorAttributes) {
|
|
75
|
+
let ancestor = root.parentElement;
|
|
76
|
+
while (ancestor) {
|
|
77
|
+
observer.observe(ancestor, {
|
|
78
|
+
attributes: true,
|
|
79
|
+
attributeFilter: [...options.ancestorAttributes]
|
|
80
|
+
});
|
|
81
|
+
ancestor = ancestor.parentElement;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
claim(target, name, value) {
|
|
86
|
+
const claims = this.#claims?.attributes;
|
|
87
|
+
let attributes = claims?.get(target);
|
|
88
|
+
if (!attributes) {
|
|
89
|
+
attributes = /* @__PURE__ */ new Map();
|
|
90
|
+
claims?.set(target, attributes);
|
|
91
|
+
}
|
|
92
|
+
const pending = attributes.get(name);
|
|
93
|
+
attributes.set(name, { value, count: (pending?.count ?? 0) + 1 });
|
|
94
|
+
}
|
|
95
|
+
claimCurrent(target, name) {
|
|
96
|
+
this.claim(target, name, target.getAttribute(name));
|
|
97
|
+
}
|
|
98
|
+
claimChildList(target, added, removed) {
|
|
99
|
+
const claims = this.#claims?.children;
|
|
100
|
+
const pending = claims?.get(target) ?? { added: /* @__PURE__ */ new Map(), removed: /* @__PURE__ */ new Map() };
|
|
101
|
+
for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) + 1);
|
|
102
|
+
for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) + 1);
|
|
103
|
+
claims?.set(target, pending);
|
|
104
|
+
}
|
|
105
|
+
take() {
|
|
106
|
+
return this.#filter(this.#observer?.takeRecords() ?? []);
|
|
107
|
+
}
|
|
108
|
+
disconnect() {
|
|
109
|
+
this.#observer?.disconnect();
|
|
110
|
+
this.#observer = null;
|
|
111
|
+
this.#claims = null;
|
|
112
|
+
}
|
|
113
|
+
#filter(records) {
|
|
114
|
+
const authored = records.filter((record) => !this.#consume(record));
|
|
115
|
+
this.#claims?.attributes.clear();
|
|
116
|
+
this.#claims?.children.clear();
|
|
117
|
+
return authored;
|
|
118
|
+
}
|
|
119
|
+
#consume(record) {
|
|
120
|
+
if (record.type === "attributes") {
|
|
121
|
+
const target = record.target;
|
|
122
|
+
const pending2 = this.#claims?.attributes.get(target)?.get(record.attributeName);
|
|
123
|
+
if (!pending2 || pending2.count === 0 || target.getAttribute(record.attributeName) !== pending2.value) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
pending2.count -= 1;
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
const pending = this.#claims?.children.get(record.target);
|
|
130
|
+
if (!pending) return false;
|
|
131
|
+
const added = [...record.addedNodes];
|
|
132
|
+
const removed = [...record.removedNodes];
|
|
133
|
+
if (added.some((node) => !pending.added.get(node)) || removed.some((node) => !pending.removed.get(node))) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) - 1);
|
|
137
|
+
for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) - 1);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
40
141
|
|
|
41
142
|
function ownerIndex(candidates, node) {
|
|
42
143
|
if (!(node instanceof Node)) return -1;
|
|
@@ -108,6 +209,9 @@ var MicrotaskCoalescer = class {
|
|
|
108
209
|
this.#queued = false;
|
|
109
210
|
this.#generation += 1;
|
|
110
211
|
}
|
|
212
|
+
get pending() {
|
|
213
|
+
return this.#queued;
|
|
214
|
+
}
|
|
111
215
|
schedule() {
|
|
112
216
|
if (!this.#active || this.#queued) return;
|
|
113
217
|
this.#queued = true;
|
|
@@ -138,6 +242,9 @@ var MorphRenderWatcher = class {
|
|
|
138
242
|
schedule() {
|
|
139
243
|
this.#pass.schedule();
|
|
140
244
|
}
|
|
245
|
+
get pending() {
|
|
246
|
+
return this.#pass.pending;
|
|
247
|
+
}
|
|
141
248
|
disconnect() {
|
|
142
249
|
this.#listeners.dispose();
|
|
143
250
|
this.#pass.cancel();
|
|
@@ -197,9 +304,9 @@ var OBSERVED_ATTRIBUTES = [
|
|
|
197
304
|
"type",
|
|
198
305
|
"value"
|
|
199
306
|
];
|
|
200
|
-
var hasModifier = (event) => event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
201
307
|
var RadioGroupController = class extends Controller {
|
|
202
308
|
#moves = new MoveCounter();
|
|
309
|
+
#connectionGeneration = 0;
|
|
203
310
|
#moveToken = 0;
|
|
204
311
|
static targets = ["radio", "field"];
|
|
205
312
|
static actions = ["onKeydown", "select"];
|
|
@@ -209,17 +316,20 @@ var RadioGroupController = class extends Controller {
|
|
|
209
316
|
#handledEvents = /* @__PURE__ */ new WeakSet();
|
|
210
317
|
#managedRadios = /* @__PURE__ */ new Set();
|
|
211
318
|
#originalTabindex = /* @__PURE__ */ new Map();
|
|
212
|
-
#ownedChecked = /* @__PURE__ */ new
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
|
|
319
|
+
#ownedChecked = /* @__PURE__ */ new Map();
|
|
320
|
+
#writtenTabindex = /* @__PURE__ */ new WeakMap();
|
|
321
|
+
#observer = new AuthoredMutationWatcher(
|
|
322
|
+
(records) => this.#handleMutationRecords(records)
|
|
323
|
+
);
|
|
216
324
|
#committed = NO_SELECTION;
|
|
217
325
|
#connected = false;
|
|
218
326
|
#lastOrder = [];
|
|
219
327
|
#focusedRadio = null;
|
|
220
328
|
#pendingFocusIndex = null;
|
|
221
329
|
#preferChecked = false;
|
|
330
|
+
#listeners = new ListenerSet();
|
|
222
331
|
connect() {
|
|
332
|
+
this.#releaseDefaultsRewrittenWhileAway();
|
|
223
333
|
const currentRadios = new Set(this.radioTargets);
|
|
224
334
|
for (const radio of this.#managedRadios) {
|
|
225
335
|
if (!currentRadios.has(radio)) this.#releaseRadio(radio);
|
|
@@ -230,30 +340,23 @@ var RadioGroupController = class extends Controller {
|
|
|
230
340
|
this.#reflectField(this.#selectedRadio);
|
|
231
341
|
this.#committed = this.#settled;
|
|
232
342
|
this.#lastOrder = this.#managedTargets;
|
|
233
|
-
this.element
|
|
234
|
-
this.element
|
|
235
|
-
this.element
|
|
236
|
-
this.element
|
|
237
|
-
this.element
|
|
238
|
-
this.element
|
|
343
|
+
this.#listeners.add(this.element, "click", this.#onClickCapture, { capture: true });
|
|
344
|
+
this.#listeners.add(this.element, "keydown", this.#onKeydownCapture, { capture: true });
|
|
345
|
+
this.#listeners.add(this.element, "click", this.#onClick);
|
|
346
|
+
this.#listeners.add(this.element, "keydown", this.#onKeydown);
|
|
347
|
+
this.#listeners.add(this.element, "focusin", this.#onFocusin);
|
|
348
|
+
this.#listeners.add(this.element, "focusout", this.#onFocusout);
|
|
239
349
|
this.#connected = true;
|
|
240
350
|
this.#preferChecked = false;
|
|
241
|
-
this.#internalCheckedValues.clear();
|
|
242
|
-
this.#internalTabindexValues.clear();
|
|
243
351
|
this.#reconcile.observe(this.element);
|
|
244
352
|
this.#observeMutations();
|
|
245
353
|
}
|
|
246
354
|
disconnect() {
|
|
355
|
+
this.#connectionGeneration += 1;
|
|
247
356
|
this.#connected = false;
|
|
248
357
|
this.#reconcile.disconnect();
|
|
249
|
-
this.
|
|
250
|
-
this.
|
|
251
|
-
this.element.removeEventListener("click", this.#onClick);
|
|
252
|
-
this.element.removeEventListener("keydown", this.#onKeydown);
|
|
253
|
-
this.element.removeEventListener("focusin", this.#onFocusin);
|
|
254
|
-
this.element.removeEventListener("focusout", this.#onFocusout);
|
|
255
|
-
this.#observer?.disconnect();
|
|
256
|
-
this.#observer = null;
|
|
358
|
+
this.#listeners.dispose();
|
|
359
|
+
this.#observer.disconnect();
|
|
257
360
|
this.#focusedRadio = null;
|
|
258
361
|
this.#pendingFocusIndex = null;
|
|
259
362
|
this.#committed = NO_SELECTION;
|
|
@@ -338,7 +441,7 @@ var RadioGroupController = class extends Controller {
|
|
|
338
441
|
#handleKeydown(event, radio) {
|
|
339
442
|
if (event.defaultPrevented || !this.#isSupportedHost(radio)) return;
|
|
340
443
|
if (event.isComposing || isReservedArrowChord(event)) return;
|
|
341
|
-
if ((event.key === "Home" || event.key === "End") &&
|
|
444
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
342
445
|
if (event.key === " ") {
|
|
343
446
|
if (this.#isActivationDisabled(radio)) {
|
|
344
447
|
event.preventDefault();
|
|
@@ -374,6 +477,7 @@ var RadioGroupController = class extends Controller {
|
|
|
374
477
|
}
|
|
375
478
|
#selectRadio(radio, { focus }, reason = "user") {
|
|
376
479
|
if (!this.#isSupportedHost(radio) || this.#isActivationDisabled(radio)) return;
|
|
480
|
+
const generation = this.#connectionGeneration;
|
|
377
481
|
const value = this.#radioValue(radio);
|
|
378
482
|
const changed = this.#committed.radio !== radio || this.#committed.value !== value;
|
|
379
483
|
for (const item of this.#managedTargets) this.#setChecked(item, item === radio);
|
|
@@ -381,17 +485,18 @@ var RadioGroupController = class extends Controller {
|
|
|
381
485
|
if (changed) this.#moveToken = this.#moves.record();
|
|
382
486
|
const token = this.#moveToken;
|
|
383
487
|
this.#setActive(radio);
|
|
384
|
-
const fieldChanged = this
|
|
488
|
+
const fieldChanged = this.#writeField(value);
|
|
489
|
+
this.#handleMutationRecords(this.#observer.take());
|
|
385
490
|
if (focus) radio.focus();
|
|
386
|
-
if (!this.#connected || !this.#moves.isLatest(token))
|
|
491
|
+
if (generation !== this.#connectionGeneration || !this.#connected || !this.#moves.isLatest(token))
|
|
492
|
+
return;
|
|
387
493
|
if (changed && fieldChanged) commitField(this.fieldTarget);
|
|
388
|
-
if (changed && this.#moves.isLatest(token)) {
|
|
494
|
+
if (changed && generation === this.#connectionGeneration && this.#connected && this.#moves.isLatest(token)) {
|
|
389
495
|
this.dispatch("change", { detail: { value, radio, reason } });
|
|
390
496
|
}
|
|
391
497
|
}
|
|
392
498
|
#reconcileDom() {
|
|
393
|
-
|
|
394
|
-
this.#handleMutationRecords(observer?.takeRecords() ?? []);
|
|
499
|
+
this.#handleMutationRecords(this.#observer.take());
|
|
395
500
|
for (const radio of this.radioTargets) this.#reconcileHost(radio, true);
|
|
396
501
|
this.#normalizeSelection();
|
|
397
502
|
const pendingFocusIndex = this.#pendingFocusIndex;
|
|
@@ -406,9 +511,7 @@ var RadioGroupController = class extends Controller {
|
|
|
406
511
|
this.#reflectField(this.#selectedRadio);
|
|
407
512
|
this.#lastOrder = this.#managedTargets;
|
|
408
513
|
this.#preferChecked = false;
|
|
409
|
-
observer
|
|
410
|
-
this.#internalCheckedValues.clear();
|
|
411
|
-
this.#internalTabindexValues.clear();
|
|
514
|
+
this.#handleMutationRecords(this.#observer.take());
|
|
412
515
|
const settled = this.#settled;
|
|
413
516
|
const committed = this.#committed;
|
|
414
517
|
const changed = settled.radio !== committed.radio || settled.value !== committed.value;
|
|
@@ -436,22 +539,19 @@ var RadioGroupController = class extends Controller {
|
|
|
436
539
|
this.#managedRadios.delete(radio);
|
|
437
540
|
const original = this.#originalTabindex.get(radio);
|
|
438
541
|
if (original === null) {
|
|
439
|
-
this.#
|
|
440
|
-
radio.removeAttribute("tabindex");
|
|
542
|
+
this.#writeAttribute(radio, "tabindex", null);
|
|
441
543
|
} else if (original !== void 0) {
|
|
442
|
-
this.#
|
|
443
|
-
radio.setAttribute("tabindex", original);
|
|
544
|
+
this.#writeAttribute(radio, "tabindex", original);
|
|
444
545
|
}
|
|
445
546
|
this.#originalTabindex.delete(radio);
|
|
446
547
|
if (this.#ownedChecked.delete(radio)) {
|
|
447
|
-
this.#
|
|
448
|
-
radio.removeAttribute("aria-checked");
|
|
548
|
+
this.#writeAttribute(radio, "aria-checked", null);
|
|
449
549
|
}
|
|
450
550
|
}
|
|
451
551
|
#normalizeChecked(radio) {
|
|
452
552
|
const value = radio.getAttribute("aria-checked");
|
|
453
553
|
if (value === null) {
|
|
454
|
-
this.#ownedChecked.
|
|
554
|
+
this.#ownedChecked.set(radio, "false");
|
|
455
555
|
this.#setChecked(radio, false);
|
|
456
556
|
} else if (value !== "true" && value !== "false") {
|
|
457
557
|
this.#setChecked(radio, false);
|
|
@@ -506,7 +606,8 @@ var RadioGroupController = class extends Controller {
|
|
|
506
606
|
const index = items.indexOf(radio);
|
|
507
607
|
this.#roving.setActive(index);
|
|
508
608
|
for (const item of items) {
|
|
509
|
-
this.#
|
|
609
|
+
this.#observer.claimCurrent(item, "tabindex");
|
|
610
|
+
this.#writtenTabindex.set(item, item.getAttribute("tabindex"));
|
|
510
611
|
}
|
|
511
612
|
if (focus) radio?.focus();
|
|
512
613
|
}
|
|
@@ -549,58 +650,36 @@ var RadioGroupController = class extends Controller {
|
|
|
549
650
|
const target = record.target;
|
|
550
651
|
const attribute = record.attributeName;
|
|
551
652
|
if (attribute === "aria-checked") {
|
|
552
|
-
const value = target.getAttribute(attribute);
|
|
553
|
-
if (this.#matchesInternal(this.#internalCheckedValues, target, value)) continue;
|
|
554
653
|
this.#ownedChecked.delete(target);
|
|
555
654
|
this.#preferChecked = true;
|
|
556
655
|
external = true;
|
|
557
656
|
} else if (attribute === "tabindex") {
|
|
558
657
|
const value = target.getAttribute(attribute);
|
|
559
|
-
if (this.#matchesInternal(this.#internalTabindexValues, target, value)) continue;
|
|
560
658
|
if (this.#managedRadios.has(target)) this.#originalTabindex.set(target, value);
|
|
561
659
|
external = true;
|
|
562
660
|
} else {
|
|
563
661
|
external = true;
|
|
564
662
|
}
|
|
565
663
|
}
|
|
566
|
-
this.#internalTabindexValues.clear();
|
|
567
664
|
if (external) this.#reconcile.schedule();
|
|
568
665
|
}
|
|
569
|
-
#markInternal(values, target, value) {
|
|
570
|
-
const pending = values.get(target);
|
|
571
|
-
if (pending) {
|
|
572
|
-
pending.value = value;
|
|
573
|
-
pending.count += 1;
|
|
574
|
-
} else {
|
|
575
|
-
values.set(target, { value, count: 1 });
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
#matchesInternal(values, target, value) {
|
|
579
|
-
const pending = values.get(target);
|
|
580
|
-
if (!pending || pending.value !== value) return false;
|
|
581
|
-
pending.count -= 1;
|
|
582
|
-
if (pending.count === 0) values.delete(target);
|
|
583
|
-
return true;
|
|
584
|
-
}
|
|
585
666
|
#observeMutations() {
|
|
586
|
-
|
|
587
|
-
this.#observer = observer;
|
|
588
|
-
this.#observeWith(observer);
|
|
589
|
-
}
|
|
590
|
-
#observeWith(observer) {
|
|
591
|
-
observer.observe(this.element, {
|
|
667
|
+
this.#observer.observe(this.element, {
|
|
592
668
|
subtree: true,
|
|
593
669
|
childList: true,
|
|
594
|
-
attributes:
|
|
595
|
-
|
|
670
|
+
attributes: OBSERVED_ATTRIBUTES,
|
|
671
|
+
ancestorAttributes: ["contenteditable", "disabled"]
|
|
596
672
|
});
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
673
|
+
}
|
|
674
|
+
#releaseDefaultsRewrittenWhileAway() {
|
|
675
|
+
for (const [radio, written] of this.#ownedChecked) {
|
|
676
|
+
const current = radio.getAttribute("aria-checked");
|
|
677
|
+
if (current !== null && current !== written) this.#ownedChecked.delete(radio);
|
|
678
|
+
}
|
|
679
|
+
for (const radio of this.#managedRadios) {
|
|
680
|
+
const written = this.#writtenTabindex.get(radio);
|
|
681
|
+
const current = radio.getAttribute("tabindex");
|
|
682
|
+
if (current !== written) this.#originalTabindex.set(radio, current);
|
|
604
683
|
}
|
|
605
684
|
}
|
|
606
685
|
get #managedTargets() {
|
|
@@ -621,23 +700,31 @@ var RadioGroupController = class extends Controller {
|
|
|
621
700
|
}
|
|
622
701
|
#setChecked(radio, checked) {
|
|
623
702
|
const value = checked ? "true" : "false";
|
|
624
|
-
if (
|
|
625
|
-
this.#
|
|
626
|
-
radio.setAttribute("aria-checked", value);
|
|
703
|
+
if (this.#ownedChecked.has(radio)) this.#ownedChecked.set(radio, value);
|
|
704
|
+
this.#writeAttribute(radio, "aria-checked", value);
|
|
627
705
|
}
|
|
628
706
|
#writeTabindex(radio, value) {
|
|
629
707
|
const serialized = String(value);
|
|
630
|
-
this.#
|
|
631
|
-
radio
|
|
708
|
+
this.#writtenTabindex.set(radio, serialized);
|
|
709
|
+
this.#writeAttribute(radio, "tabindex", serialized);
|
|
710
|
+
}
|
|
711
|
+
#writeAttribute(target, name, value) {
|
|
712
|
+
setAttributeIfChanged(target, name, value, () => this.#observer.claim(target, name, value));
|
|
632
713
|
}
|
|
633
714
|
#reflectField(radio) {
|
|
634
|
-
if (!this.hasFieldTarget) return;
|
|
635
715
|
const value = radio ? this.#radioValue(radio) : "";
|
|
636
|
-
writeField(
|
|
716
|
+
this.#writeField(value);
|
|
637
717
|
}
|
|
638
718
|
#radioValue(radio) {
|
|
639
719
|
return radio.getAttribute("data-value") ?? "";
|
|
640
720
|
}
|
|
721
|
+
#writeField(value) {
|
|
722
|
+
if (!this.hasFieldTarget) return false;
|
|
723
|
+
const changed = writeField(this.fieldTarget, value);
|
|
724
|
+
if (changed && this.fieldTarget.type === "hidden")
|
|
725
|
+
this.#observer.claimCurrent(this.fieldTarget, "value");
|
|
726
|
+
return changed;
|
|
727
|
+
}
|
|
641
728
|
};
|
|
642
729
|
|
|
643
730
|
export { RadioGroupController };
|
|
@@ -13,6 +13,16 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
13
13
|
if (!event.key.startsWith("Arrow")) return false;
|
|
14
14
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
15
15
|
}
|
|
16
|
+
function hasModifierChord(event) {
|
|
17
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
21
|
+
if (element.getAttribute(name) === value) return false;
|
|
22
|
+
if (value === null) element.removeAttribute(name);
|
|
23
|
+
else element.setAttribute(name, value);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
16
26
|
|
|
17
27
|
function writeField(field, value) {
|
|
18
28
|
if (field.value === value) return false;
|
|
@@ -50,6 +60,9 @@ var MicrotaskCoalescer = class {
|
|
|
50
60
|
this.#queued = false;
|
|
51
61
|
this.#generation += 1;
|
|
52
62
|
}
|
|
63
|
+
get pending() {
|
|
64
|
+
return this.#queued;
|
|
65
|
+
}
|
|
53
66
|
schedule() {
|
|
54
67
|
if (!this.#active || this.#queued) return;
|
|
55
68
|
this.#queued = true;
|
|
@@ -80,6 +93,9 @@ var MorphRenderWatcher = class {
|
|
|
80
93
|
schedule() {
|
|
81
94
|
this.#pass.schedule();
|
|
82
95
|
}
|
|
96
|
+
get pending() {
|
|
97
|
+
return this.#pass.pending;
|
|
98
|
+
}
|
|
83
99
|
disconnect() {
|
|
84
100
|
this.#listeners.dispose();
|
|
85
101
|
this.#pass.cancel();
|
|
@@ -189,7 +205,7 @@ var OwnedPointerSession = class {
|
|
|
189
205
|
function rangeFraction(value, min, max) {
|
|
190
206
|
const span = max - min;
|
|
191
207
|
if (!(span > 0)) return 0;
|
|
192
|
-
const clamped =
|
|
208
|
+
const clamped = clampRange(value, min, max);
|
|
193
209
|
let fraction;
|
|
194
210
|
if (Number.isFinite(span)) {
|
|
195
211
|
fraction = (clamped - min) / span;
|
|
@@ -200,6 +216,9 @@ function rangeFraction(value, min, max) {
|
|
|
200
216
|
if (!Number.isFinite(fraction)) return 0;
|
|
201
217
|
return Math.min(1, Math.max(0, fraction));
|
|
202
218
|
}
|
|
219
|
+
function clampRange(value, min, max) {
|
|
220
|
+
return Math.min(max, Math.max(min, value));
|
|
221
|
+
}
|
|
203
222
|
|
|
204
223
|
function effectiveStep(step) {
|
|
205
224
|
return Number.isFinite(step) && step > 0 ? step : 1;
|
|
@@ -335,8 +354,8 @@ var RangeSliderController = class _RangeSliderController extends Controller {
|
|
|
335
354
|
static events = ["change", "reconcile"];
|
|
336
355
|
#drag = null;
|
|
337
356
|
#settled = { start: DEFAULT_MIN, end: DEFAULT_MAX };
|
|
338
|
-
get #
|
|
339
|
-
return this.
|
|
357
|
+
get #directionElement() {
|
|
358
|
+
return this.hasTrackTarget ? this.trackTarget : this.element;
|
|
340
359
|
}
|
|
341
360
|
#repaint = new MorphRenderWatcher(() => this.#render());
|
|
342
361
|
connect() {
|
|
@@ -410,6 +429,8 @@ var RangeSliderController = class _RangeSliderController extends Controller {
|
|
|
410
429
|
}
|
|
411
430
|
onKeydown(event) {
|
|
412
431
|
if (isReservedArrowChord(event)) return;
|
|
432
|
+
if ((event.key === "Home" || event.key === "End" || event.key === "PageUp" || event.key === "PageDown") && hasModifierChord(event))
|
|
433
|
+
return;
|
|
413
434
|
const thumb = event.currentTarget;
|
|
414
435
|
const isStart = this.startThumbTargets.includes(thumb);
|
|
415
436
|
const isEnd = this.endThumbTargets.includes(thumb);
|
|
@@ -439,7 +460,7 @@ var RangeSliderController = class _RangeSliderController extends Controller {
|
|
|
439
460
|
};
|
|
440
461
|
}
|
|
441
462
|
let next = null;
|
|
442
|
-
switch (this
|
|
463
|
+
switch (this.logicalTrackValue ? logicalArrowKey(event.key, this.#directionElement) : event.key) {
|
|
443
464
|
case "ArrowRight":
|
|
444
465
|
case "ArrowUp":
|
|
445
466
|
next = stepSteppedValue(current, 1, range);
|
|
@@ -471,7 +492,7 @@ var RangeSliderController = class _RangeSliderController extends Controller {
|
|
|
471
492
|
return;
|
|
472
493
|
}
|
|
473
494
|
const track = this.trackTarget;
|
|
474
|
-
const mirrored = this
|
|
495
|
+
const mirrored = this.logicalTrackValue && isRtl(track);
|
|
475
496
|
const value = this.#valueFromClientX(event.clientX, mirrored, track);
|
|
476
497
|
if (value === null) return;
|
|
477
498
|
event.preventDefault();
|
|
@@ -599,8 +620,7 @@ var RangeSliderController = class _RangeSliderController extends Controller {
|
|
|
599
620
|
this.#setAria(thumb, "aria-valuenow", pair.end);
|
|
600
621
|
}
|
|
601
622
|
#setAria(thumb, name, value) {
|
|
602
|
-
|
|
603
|
-
if (thumb.getAttribute(name) !== next) thumb.setAttribute(name, next);
|
|
623
|
+
setAttributeIfChanged(thumb, name, String(value));
|
|
604
624
|
}
|
|
605
625
|
#renderFractions(pair, range) {
|
|
606
626
|
const start = String(rangeFraction(pair.start, range.min, range.max));
|