stimeo-ui 0.17.0 → 0.18.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +106 -1
- 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 +289 -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 +64 -46
- data/dist/controllers/drawer_controller.js +145 -118
- data/dist/controllers/dropdown_controller.js +76 -63
- data/dist/controllers/editable_controller.js +199 -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 +411 -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 +251 -94
- 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 +249 -23
- data/dist/controllers/popover_controller.js +82 -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 +2451 -1312
- 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
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
4
|
+
if (element.getAttribute(name) === value) return false;
|
|
5
|
+
if (value === null) element.removeAttribute(name);
|
|
6
|
+
else element.setAttribute(name, value);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
function sharedRegistry(key, create) {
|
|
4
11
|
const symbol = Symbol.for(key);
|
|
5
12
|
const scope = globalThis;
|
|
6
13
|
const existing = scope[symbol];
|
|
7
14
|
if (existing !== void 0) return existing;
|
|
8
|
-
const
|
|
9
|
-
Object.defineProperty(globalThis, symbol, { value:
|
|
10
|
-
return
|
|
15
|
+
const registry2 = create();
|
|
16
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
17
|
+
return registry2;
|
|
11
18
|
}
|
|
12
19
|
|
|
20
|
+
var registry = sharedRegistry(
|
|
21
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
22
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
23
|
+
);
|
|
13
24
|
function isAttributeValue(value) {
|
|
14
25
|
return value === null || typeof value === "string";
|
|
15
26
|
}
|
|
@@ -26,24 +37,46 @@ function readLeaseRecord(element, record) {
|
|
|
26
37
|
return void 0;
|
|
27
38
|
}
|
|
28
39
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
);
|
|
40
|
+
function attributeStack(element, attribute) {
|
|
41
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
42
|
+
registry.stacks.set(element, byAttribute);
|
|
43
|
+
const known = byAttribute.get(attribute);
|
|
44
|
+
if (known) return known;
|
|
45
|
+
const found = [];
|
|
46
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
47
|
+
const read = readLeaseRecord(element, record);
|
|
48
|
+
if (read) found.push({ ...read, record });
|
|
49
|
+
}
|
|
50
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
51
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
52
|
+
lease: null,
|
|
53
|
+
record,
|
|
54
|
+
written,
|
|
55
|
+
original,
|
|
56
|
+
linked: linked && index > 0
|
|
57
|
+
}));
|
|
58
|
+
byAttribute.set(attribute, stack);
|
|
59
|
+
return stack;
|
|
60
|
+
}
|
|
61
|
+
function findHold(stack, lease, record) {
|
|
62
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
63
|
+
}
|
|
64
|
+
var AttributeLease = class {
|
|
34
65
|
#attribute;
|
|
35
66
|
#record;
|
|
36
67
|
#base;
|
|
68
|
+
#preserveAuthor;
|
|
37
69
|
#held = /* @__PURE__ */ new Set();
|
|
38
70
|
constructor(attribute, owner, options = {}) {
|
|
39
71
|
this.#attribute = attribute;
|
|
40
72
|
this.#record = `data-${owner}-${attribute}-lease`;
|
|
41
73
|
this.#base = options.base === true;
|
|
42
|
-
|
|
74
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
75
|
+
const names = registry.names;
|
|
43
76
|
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
44
77
|
}
|
|
45
78
|
write(element, value) {
|
|
46
|
-
const stack = this.#
|
|
79
|
+
const stack = attributeStack(element, this.#attribute);
|
|
47
80
|
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
48
81
|
this.#held.add(element);
|
|
49
82
|
const shows = !this.#covered(element, stack, hold);
|
|
@@ -53,8 +86,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
53
86
|
}
|
|
54
87
|
return(element) {
|
|
55
88
|
const held = this.#held.delete(element);
|
|
56
|
-
const known =
|
|
57
|
-
const stack = held || known || element.hasAttribute(this.#record) ? this.#
|
|
89
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
90
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
58
91
|
const hold = this.#take(stack);
|
|
59
92
|
if (!hold) return false;
|
|
60
93
|
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
@@ -72,31 +105,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
72
105
|
returnAll() {
|
|
73
106
|
for (const element of Array.from(this.#held)) this.return(element);
|
|
74
107
|
}
|
|
75
|
-
#stack(element) {
|
|
76
|
-
const stacks = _AttributeLease.#registry.stacks;
|
|
77
|
-
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
78
|
-
stacks.set(element, byAttribute);
|
|
79
|
-
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
80
|
-
byAttribute.set(this.#attribute, stack);
|
|
81
|
-
return stack;
|
|
82
|
-
}
|
|
83
|
-
#seed(element) {
|
|
84
|
-
const found = [];
|
|
85
|
-
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
86
|
-
const read = readLeaseRecord(element, record);
|
|
87
|
-
if (read) found.push({ ...read, record });
|
|
88
|
-
}
|
|
89
|
-
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
90
|
-
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
91
|
-
lease: null,
|
|
92
|
-
record,
|
|
93
|
-
written,
|
|
94
|
-
original,
|
|
95
|
-
linked: linked && index > 0
|
|
96
|
-
}));
|
|
97
|
-
}
|
|
98
108
|
#take(stack) {
|
|
99
|
-
const hold = stack
|
|
109
|
+
const hold = findHold(stack, this, this.#record);
|
|
100
110
|
if (hold) hold.lease = this;
|
|
101
111
|
return hold;
|
|
102
112
|
}
|
|
@@ -105,7 +115,7 @@ var AttributeLease = class _AttributeLease {
|
|
|
105
115
|
const top = stack.at(-1);
|
|
106
116
|
const bottom = stack[0];
|
|
107
117
|
const over = top?.written === current ? top : void 0;
|
|
108
|
-
const from = this.#base ? bottom : over;
|
|
118
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
109
119
|
const hold = {
|
|
110
120
|
lease: this,
|
|
111
121
|
record: this.#record,
|
|
@@ -135,15 +145,11 @@ var AttributeLease = class _AttributeLease {
|
|
|
135
145
|
);
|
|
136
146
|
});
|
|
137
147
|
for (const [name, recorded] of records) {
|
|
138
|
-
|
|
139
|
-
if (recorded === null) element.removeAttribute(name);
|
|
140
|
-
else element.setAttribute(name, recorded);
|
|
148
|
+
setAttributeIfChanged(element, name, recorded);
|
|
141
149
|
}
|
|
142
150
|
}
|
|
143
151
|
#reflect(element, value) {
|
|
144
|
-
|
|
145
|
-
if (value === null) element.removeAttribute(this.#attribute);
|
|
146
|
-
else element.setAttribute(this.#attribute, value);
|
|
152
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
147
153
|
}
|
|
148
154
|
};
|
|
149
155
|
|
|
@@ -252,6 +258,9 @@ var MicrotaskCoalescer = class {
|
|
|
252
258
|
this.#queued = false;
|
|
253
259
|
this.#generation += 1;
|
|
254
260
|
}
|
|
261
|
+
get pending() {
|
|
262
|
+
return this.#queued;
|
|
263
|
+
}
|
|
255
264
|
schedule() {
|
|
256
265
|
if (!this.#active || this.#queued) return;
|
|
257
266
|
this.#queued = true;
|
|
@@ -282,6 +291,9 @@ var MorphRenderWatcher = class {
|
|
|
282
291
|
schedule() {
|
|
283
292
|
this.#pass.schedule();
|
|
284
293
|
}
|
|
294
|
+
get pending() {
|
|
295
|
+
return this.#pass.pending;
|
|
296
|
+
}
|
|
285
297
|
disconnect() {
|
|
286
298
|
this.#listeners.dispose();
|
|
287
299
|
this.#pass.cancel();
|
|
@@ -347,6 +359,11 @@ function resolveScrollSource(selector) {
|
|
|
347
359
|
function scrollOffset(source) {
|
|
348
360
|
return source === window ? window.scrollY ?? window.pageYOffset ?? 0 : source.scrollTop;
|
|
349
361
|
}
|
|
362
|
+
function deepActiveElement(ownerDocument) {
|
|
363
|
+
let active = ownerDocument.activeElement;
|
|
364
|
+
while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
|
|
365
|
+
return active;
|
|
366
|
+
}
|
|
350
367
|
|
|
351
368
|
function queryOpenDescendants(root, selector) {
|
|
352
369
|
const matches = [];
|
|
@@ -364,6 +381,9 @@ function queryOpenDescendants(root, selector) {
|
|
|
364
381
|
return matches;
|
|
365
382
|
}
|
|
366
383
|
|
|
384
|
+
function holdsFocus(element) {
|
|
385
|
+
return element.matches(":focus") || deepActiveElement(element.ownerDocument) === element;
|
|
386
|
+
}
|
|
367
387
|
var TabindexLoan = class _TabindexLoan {
|
|
368
388
|
static #registry = sharedRegistry(
|
|
369
389
|
"stimeo-ui.tabindex-loan.registry.v1",
|
|
@@ -371,19 +391,22 @@ var TabindexLoan = class _TabindexLoan {
|
|
|
371
391
|
);
|
|
372
392
|
#value;
|
|
373
393
|
#record;
|
|
394
|
+
#preserveFocus;
|
|
374
395
|
#lent = /* @__PURE__ */ new Set();
|
|
375
|
-
constructor(value, owner) {
|
|
396
|
+
constructor(value, owner, options = {}) {
|
|
376
397
|
this.#value = value;
|
|
377
398
|
this.#record = `data-${owner}-tabindex-loan`;
|
|
399
|
+
this.#preserveFocus = options.preserveFocus === true;
|
|
378
400
|
_TabindexLoan.#registry.names.add(this.#record);
|
|
379
401
|
}
|
|
380
|
-
lend(element) {
|
|
402
|
+
lend(element, options = {}) {
|
|
381
403
|
const stack = this.#stack(element);
|
|
382
404
|
const current = element.getAttribute("tabindex");
|
|
383
405
|
const held = stack.find((hold) => hold.loan === this) ?? stack.find(
|
|
384
406
|
(hold) => hold.loan === null && hold.record === this.#record && hold.value === this.#value
|
|
385
407
|
);
|
|
386
408
|
const linked = stack.at(-1)?.value === current;
|
|
409
|
+
if (!held && options.onlyIfUnfocusable && (current !== null || element.tabIndex >= 0)) return;
|
|
387
410
|
if (!held && current !== null && !linked) return;
|
|
388
411
|
this.#lent.add(element);
|
|
389
412
|
if (held) held.loan = this;
|
|
@@ -393,19 +416,28 @@ var TabindexLoan = class _TabindexLoan {
|
|
|
393
416
|
element.setAttribute("tabindex", this.#value);
|
|
394
417
|
}
|
|
395
418
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
419
|
+
return(element) {
|
|
420
|
+
const stack = this.#stack(element);
|
|
421
|
+
const hold = stack.find((held) => held.loan === this) ?? stack.find(
|
|
422
|
+
(held) => held.loan === null && held.record === this.#record && held.value === this.#value
|
|
423
|
+
);
|
|
424
|
+
if (!hold) return false;
|
|
425
|
+
if (!this.#release(element, stack, hold, this.#preserveFocus)) {
|
|
426
|
+
hold.loan = this;
|
|
427
|
+
this.#lent.add(element);
|
|
428
|
+
return false;
|
|
401
429
|
}
|
|
402
|
-
this.#lent.
|
|
430
|
+
this.#lent.delete(element);
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
returnAll() {
|
|
434
|
+
for (const element of Array.from(this.#lent)) this.return(element);
|
|
403
435
|
}
|
|
404
436
|
reclaim(element) {
|
|
405
437
|
if (element.getAttribute(this.#record) !== this.#value) return;
|
|
406
438
|
const stack = this.#stack(element);
|
|
407
439
|
const hold = stack.find((held) => held.loan === null && held.record === this.#record);
|
|
408
|
-
if (hold && !element
|
|
440
|
+
if (hold && !holdsFocus(element)) this.#release(element, stack, hold);
|
|
409
441
|
}
|
|
410
442
|
reclaimWithin(root) {
|
|
411
443
|
for (const element of queryOpenDescendants(root, `[${this.#record}]`)) {
|
|
@@ -429,26 +461,26 @@ var TabindexLoan = class _TabindexLoan {
|
|
|
429
461
|
for (const [index, hold] of holds.entries()) hold.linked = index > 0;
|
|
430
462
|
return holds;
|
|
431
463
|
}
|
|
432
|
-
#release(element, stack, hold) {
|
|
464
|
+
#release(element, stack, hold, preserveFocus = false) {
|
|
433
465
|
const current = element.getAttribute("tabindex");
|
|
434
466
|
const index = stack.indexOf(hold);
|
|
435
467
|
const owns = current === hold.value && !stack.slice(index + 1).some((above2) => above2.value === current);
|
|
468
|
+
if (owns && preserveFocus && holdsFocus(element)) return false;
|
|
436
469
|
stack.splice(index, 1);
|
|
437
470
|
const above = stack[index];
|
|
438
471
|
if (above) above.linked &&= hold.linked;
|
|
439
472
|
this.#mark(element, stack);
|
|
440
|
-
if (!owns) return;
|
|
473
|
+
if (!owns) return true;
|
|
441
474
|
const below = hold.linked ? stack[index - 1] : void 0;
|
|
442
475
|
if (!below) element.removeAttribute("tabindex");
|
|
443
476
|
else if (below.value !== current) element.setAttribute("tabindex", below.value);
|
|
477
|
+
return true;
|
|
444
478
|
}
|
|
445
479
|
#mark(element, stack) {
|
|
446
480
|
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
447
481
|
for (const hold of stack) records.set(hold.record, hold.value);
|
|
448
482
|
for (const [name, recorded] of records) {
|
|
449
|
-
|
|
450
|
-
if (recorded === null) element.removeAttribute(name);
|
|
451
|
-
else element.setAttribute(name, recorded);
|
|
483
|
+
setAttributeIfChanged(element, name, recorded);
|
|
452
484
|
}
|
|
453
485
|
}
|
|
454
486
|
};
|
|
@@ -472,6 +504,7 @@ var ScrollVisibilityController = class _ScrollVisibilityController extends Contr
|
|
|
472
504
|
#lastScrollY = 0;
|
|
473
505
|
#visible = null;
|
|
474
506
|
#scrollSource = window;
|
|
507
|
+
#scrollListeners = new ListenerSet();
|
|
475
508
|
#connected = false;
|
|
476
509
|
#offset = DEFAULT_OFFSET;
|
|
477
510
|
#rootSelector = "";
|
|
@@ -496,7 +529,7 @@ var ScrollVisibilityController = class _ScrollVisibilityController extends Contr
|
|
|
496
529
|
disconnect() {
|
|
497
530
|
this.#morphRender.disconnect();
|
|
498
531
|
this.#connected = false;
|
|
499
|
-
this.#
|
|
532
|
+
this.#scrollListeners.dispose();
|
|
500
533
|
this.#frames.cancel();
|
|
501
534
|
this.#pendingHide.releaseAll();
|
|
502
535
|
this.#tabindex.returnAll();
|
|
@@ -540,13 +573,13 @@ var ScrollVisibilityController = class _ScrollVisibilityController extends Contr
|
|
|
540
573
|
#followSource() {
|
|
541
574
|
const source = resolveScrollSource(this.#rootSelector);
|
|
542
575
|
if (source === this.#scrollSource) return;
|
|
543
|
-
this.#
|
|
576
|
+
this.#scrollListeners.dispose();
|
|
544
577
|
this.#listenTo(source);
|
|
545
578
|
}
|
|
546
579
|
#listenTo(source) {
|
|
547
580
|
this.#scrollSource = source;
|
|
548
581
|
this.#lastScrollY = scrollOffset(source);
|
|
549
|
-
|
|
582
|
+
this.#scrollListeners.add(source, "scroll", this.#onScroll, { passive: true });
|
|
550
583
|
}
|
|
551
584
|
#evaluate(notify = true) {
|
|
552
585
|
const y = scrollOffset(this.#scrollSource);
|
|
@@ -157,6 +157,9 @@ var MicrotaskCoalescer = class {
|
|
|
157
157
|
this.#queued = false;
|
|
158
158
|
this.#generation += 1;
|
|
159
159
|
}
|
|
160
|
+
get pending() {
|
|
161
|
+
return this.#queued;
|
|
162
|
+
}
|
|
160
163
|
schedule() {
|
|
161
164
|
if (!this.#active || this.#queued) return;
|
|
162
165
|
this.#queued = true;
|
|
@@ -187,6 +190,9 @@ var MorphRenderWatcher = class {
|
|
|
187
190
|
schedule() {
|
|
188
191
|
this.#pass.schedule();
|
|
189
192
|
}
|
|
193
|
+
get pending() {
|
|
194
|
+
return this.#pass.pending;
|
|
195
|
+
}
|
|
190
196
|
disconnect() {
|
|
191
197
|
this.#listeners.dispose();
|
|
192
198
|
this.#pass.cancel();
|
|
@@ -277,7 +283,7 @@ var ScrollspyController = class _ScrollspyController extends Controller {
|
|
|
277
283
|
#intersectionStates = /* @__PURE__ */ new Map();
|
|
278
284
|
#activeSectionId = "";
|
|
279
285
|
#rootElement = null;
|
|
280
|
-
#
|
|
286
|
+
#scrollListeners = new ListenerSet();
|
|
281
287
|
#frames = new FrameCoalescer();
|
|
282
288
|
#rootSelector = "";
|
|
283
289
|
#anchorObserver = null;
|
|
@@ -389,12 +395,12 @@ var ScrollspyController = class _ScrollspyController extends Controller {
|
|
|
389
395
|
#onScroll = () => this.#frames.schedule(() => this.#evaluateActiveSection());
|
|
390
396
|
#syncScrollListener() {
|
|
391
397
|
this.#detachScrollListener();
|
|
392
|
-
this.#
|
|
393
|
-
|
|
398
|
+
this.#scrollListeners.add(this.#rootElement ?? window, "scroll", this.#onScroll, {
|
|
399
|
+
passive: true
|
|
400
|
+
});
|
|
394
401
|
}
|
|
395
402
|
#detachScrollListener() {
|
|
396
|
-
this.#
|
|
397
|
-
this.#scrollSource = null;
|
|
403
|
+
this.#scrollListeners.dispose();
|
|
398
404
|
}
|
|
399
405
|
#initializeObserver(retainStates = false) {
|
|
400
406
|
this.#watcher.stop();
|
|
@@ -4,17 +4,31 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
4
4
|
if (!event.key.startsWith("Arrow")) return false;
|
|
5
5
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
6
6
|
}
|
|
7
|
+
function hasModifierChord(event) {
|
|
8
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
12
|
+
if (element.getAttribute(name) === value) return false;
|
|
13
|
+
if (value === null) element.removeAttribute(name);
|
|
14
|
+
else element.setAttribute(name, value);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
7
17
|
|
|
8
18
|
function sharedRegistry(key, create) {
|
|
9
19
|
const symbol = Symbol.for(key);
|
|
10
20
|
const scope = globalThis;
|
|
11
21
|
const existing = scope[symbol];
|
|
12
22
|
if (existing !== void 0) return existing;
|
|
13
|
-
const
|
|
14
|
-
Object.defineProperty(globalThis, symbol, { value:
|
|
15
|
-
return
|
|
23
|
+
const registry2 = create();
|
|
24
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
25
|
+
return registry2;
|
|
16
26
|
}
|
|
17
27
|
|
|
28
|
+
var registry = sharedRegistry(
|
|
29
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
30
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
31
|
+
);
|
|
18
32
|
function isAttributeValue(value) {
|
|
19
33
|
return value === null || typeof value === "string";
|
|
20
34
|
}
|
|
@@ -31,24 +45,46 @@ function readLeaseRecord(element, record) {
|
|
|
31
45
|
return void 0;
|
|
32
46
|
}
|
|
33
47
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
);
|
|
48
|
+
function attributeStack(element, attribute) {
|
|
49
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
50
|
+
registry.stacks.set(element, byAttribute);
|
|
51
|
+
const known = byAttribute.get(attribute);
|
|
52
|
+
if (known) return known;
|
|
53
|
+
const found = [];
|
|
54
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
55
|
+
const read = readLeaseRecord(element, record);
|
|
56
|
+
if (read) found.push({ ...read, record });
|
|
57
|
+
}
|
|
58
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
59
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
60
|
+
lease: null,
|
|
61
|
+
record,
|
|
62
|
+
written,
|
|
63
|
+
original,
|
|
64
|
+
linked: linked && index > 0
|
|
65
|
+
}));
|
|
66
|
+
byAttribute.set(attribute, stack);
|
|
67
|
+
return stack;
|
|
68
|
+
}
|
|
69
|
+
function findHold(stack, lease, record) {
|
|
70
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
71
|
+
}
|
|
72
|
+
var AttributeLease = class {
|
|
39
73
|
#attribute;
|
|
40
74
|
#record;
|
|
41
75
|
#base;
|
|
76
|
+
#preserveAuthor;
|
|
42
77
|
#held = /* @__PURE__ */ new Set();
|
|
43
78
|
constructor(attribute, owner, options = {}) {
|
|
44
79
|
this.#attribute = attribute;
|
|
45
80
|
this.#record = `data-${owner}-${attribute}-lease`;
|
|
46
81
|
this.#base = options.base === true;
|
|
47
|
-
|
|
82
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
83
|
+
const names = registry.names;
|
|
48
84
|
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
49
85
|
}
|
|
50
86
|
write(element, value) {
|
|
51
|
-
const stack = this.#
|
|
87
|
+
const stack = attributeStack(element, this.#attribute);
|
|
52
88
|
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
53
89
|
this.#held.add(element);
|
|
54
90
|
const shows = !this.#covered(element, stack, hold);
|
|
@@ -58,8 +94,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
58
94
|
}
|
|
59
95
|
return(element) {
|
|
60
96
|
const held = this.#held.delete(element);
|
|
61
|
-
const known =
|
|
62
|
-
const stack = held || known || element.hasAttribute(this.#record) ? this.#
|
|
97
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
98
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
63
99
|
const hold = this.#take(stack);
|
|
64
100
|
if (!hold) return false;
|
|
65
101
|
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
@@ -77,31 +113,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
77
113
|
returnAll() {
|
|
78
114
|
for (const element of Array.from(this.#held)) this.return(element);
|
|
79
115
|
}
|
|
80
|
-
#stack(element) {
|
|
81
|
-
const stacks = _AttributeLease.#registry.stacks;
|
|
82
|
-
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
83
|
-
stacks.set(element, byAttribute);
|
|
84
|
-
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
85
|
-
byAttribute.set(this.#attribute, stack);
|
|
86
|
-
return stack;
|
|
87
|
-
}
|
|
88
|
-
#seed(element) {
|
|
89
|
-
const found = [];
|
|
90
|
-
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
91
|
-
const read = readLeaseRecord(element, record);
|
|
92
|
-
if (read) found.push({ ...read, record });
|
|
93
|
-
}
|
|
94
|
-
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
95
|
-
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
96
|
-
lease: null,
|
|
97
|
-
record,
|
|
98
|
-
written,
|
|
99
|
-
original,
|
|
100
|
-
linked: linked && index > 0
|
|
101
|
-
}));
|
|
102
|
-
}
|
|
103
116
|
#take(stack) {
|
|
104
|
-
const hold = stack
|
|
117
|
+
const hold = findHold(stack, this, this.#record);
|
|
105
118
|
if (hold) hold.lease = this;
|
|
106
119
|
return hold;
|
|
107
120
|
}
|
|
@@ -110,7 +123,7 @@ var AttributeLease = class _AttributeLease {
|
|
|
110
123
|
const top = stack.at(-1);
|
|
111
124
|
const bottom = stack[0];
|
|
112
125
|
const over = top?.written === current ? top : void 0;
|
|
113
|
-
const from = this.#base ? bottom : over;
|
|
126
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
114
127
|
const hold = {
|
|
115
128
|
lease: this,
|
|
116
129
|
record: this.#record,
|
|
@@ -140,15 +153,11 @@ var AttributeLease = class _AttributeLease {
|
|
|
140
153
|
);
|
|
141
154
|
});
|
|
142
155
|
for (const [name, recorded] of records) {
|
|
143
|
-
|
|
144
|
-
if (recorded === null) element.removeAttribute(name);
|
|
145
|
-
else element.setAttribute(name, recorded);
|
|
156
|
+
setAttributeIfChanged(element, name, recorded);
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
#reflect(element, value) {
|
|
149
|
-
|
|
150
|
-
if (value === null) element.removeAttribute(this.#attribute);
|
|
151
|
-
else element.setAttribute(this.#attribute, value);
|
|
160
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
152
161
|
}
|
|
153
162
|
};
|
|
154
163
|
|
|
@@ -179,6 +188,9 @@ var MicrotaskCoalescer = class {
|
|
|
179
188
|
this.#queued = false;
|
|
180
189
|
this.#generation += 1;
|
|
181
190
|
}
|
|
191
|
+
get pending() {
|
|
192
|
+
return this.#queued;
|
|
193
|
+
}
|
|
182
194
|
schedule() {
|
|
183
195
|
if (!this.#active || this.#queued) return;
|
|
184
196
|
this.#queued = true;
|
|
@@ -209,6 +221,9 @@ var MorphRenderWatcher = class {
|
|
|
209
221
|
schedule() {
|
|
210
222
|
this.#pass.schedule();
|
|
211
223
|
}
|
|
224
|
+
get pending() {
|
|
225
|
+
return this.#pass.pending;
|
|
226
|
+
}
|
|
212
227
|
disconnect() {
|
|
213
228
|
this.#listeners.dispose();
|
|
214
229
|
this.#pass.cancel();
|
|
@@ -424,6 +439,7 @@ var SeparatorController = class _SeparatorController extends Controller {
|
|
|
424
439
|
}
|
|
425
440
|
onKeydown(event) {
|
|
426
441
|
if (isReservedArrowChord(event) || !this.focusableValue) return;
|
|
442
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
427
443
|
const horizontal = this.#effectiveOrientation === "horizontal";
|
|
428
444
|
const range = this.#effectiveRange;
|
|
429
445
|
const declared = this.#safeValue;
|