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,5 +1,12 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
+
function fillTemplate(template, values) {
|
|
4
|
+
return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
|
|
5
|
+
const replacement = Object.hasOwn(values, name) ? values[name] : void 0;
|
|
6
|
+
return replacement === void 0 ? match : String(replacement);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
function announce(message, options = {}) {
|
|
4
11
|
const text = message.trim();
|
|
5
12
|
if (text.length === 0) return;
|
|
@@ -9,12 +16,6 @@ function announce(message, options = {}) {
|
|
|
9
16
|
})
|
|
10
17
|
);
|
|
11
18
|
}
|
|
12
|
-
function fillTemplate(template, values) {
|
|
13
|
-
return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
|
|
14
|
-
const replacement = values[name];
|
|
15
|
-
return replacement === void 0 ? match : String(replacement);
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
19
|
|
|
19
20
|
var ListenerSet = class {
|
|
20
21
|
#abort = new AbortController();
|
|
@@ -43,6 +44,9 @@ var MicrotaskCoalescer = class {
|
|
|
43
44
|
this.#queued = false;
|
|
44
45
|
this.#generation += 1;
|
|
45
46
|
}
|
|
47
|
+
get pending() {
|
|
48
|
+
return this.#queued;
|
|
49
|
+
}
|
|
46
50
|
schedule() {
|
|
47
51
|
if (!this.#active || this.#queued) return;
|
|
48
52
|
this.#queued = true;
|
|
@@ -73,6 +77,9 @@ var MorphRenderWatcher = class {
|
|
|
73
77
|
schedule() {
|
|
74
78
|
this.#pass.schedule();
|
|
75
79
|
}
|
|
80
|
+
get pending() {
|
|
81
|
+
return this.#pass.pending;
|
|
82
|
+
}
|
|
76
83
|
disconnect() {
|
|
77
84
|
this.#listeners.dispose();
|
|
78
85
|
this.#pass.cancel();
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
+
function fillTemplate(template, values) {
|
|
4
|
+
return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
|
|
5
|
+
const replacement = Object.hasOwn(values, name) ? values[name] : void 0;
|
|
6
|
+
return replacement === void 0 ? match : String(replacement);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
function announce(message, options = {}) {
|
|
4
11
|
const text = message.trim();
|
|
5
12
|
if (text.length === 0) return;
|
|
@@ -9,11 +16,12 @@ function announce(message, options = {}) {
|
|
|
9
16
|
})
|
|
10
17
|
);
|
|
11
18
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
function sharedRegistry(key, create) {
|
|
@@ -21,11 +29,15 @@ function sharedRegistry(key, create) {
|
|
|
21
29
|
const scope = globalThis;
|
|
22
30
|
const existing = scope[symbol];
|
|
23
31
|
if (existing !== void 0) return existing;
|
|
24
|
-
const
|
|
25
|
-
Object.defineProperty(globalThis, symbol, { value:
|
|
26
|
-
return
|
|
32
|
+
const registry2 = create();
|
|
33
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
34
|
+
return registry2;
|
|
27
35
|
}
|
|
28
36
|
|
|
37
|
+
var registry = sharedRegistry(
|
|
38
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
39
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
40
|
+
);
|
|
29
41
|
function isAttributeValue(value) {
|
|
30
42
|
return value === null || typeof value === "string";
|
|
31
43
|
}
|
|
@@ -42,24 +54,46 @@ function readLeaseRecord(element, record) {
|
|
|
42
54
|
return void 0;
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
57
|
+
function attributeStack(element, attribute) {
|
|
58
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
59
|
+
registry.stacks.set(element, byAttribute);
|
|
60
|
+
const known = byAttribute.get(attribute);
|
|
61
|
+
if (known) return known;
|
|
62
|
+
const found = [];
|
|
63
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
64
|
+
const read = readLeaseRecord(element, record);
|
|
65
|
+
if (read) found.push({ ...read, record });
|
|
66
|
+
}
|
|
67
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
68
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
69
|
+
lease: null,
|
|
70
|
+
record,
|
|
71
|
+
written,
|
|
72
|
+
original,
|
|
73
|
+
linked: linked && index > 0
|
|
74
|
+
}));
|
|
75
|
+
byAttribute.set(attribute, stack);
|
|
76
|
+
return stack;
|
|
77
|
+
}
|
|
78
|
+
function findHold(stack, lease, record) {
|
|
79
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
80
|
+
}
|
|
81
|
+
var AttributeLease = class {
|
|
50
82
|
#attribute;
|
|
51
83
|
#record;
|
|
52
84
|
#base;
|
|
85
|
+
#preserveAuthor;
|
|
53
86
|
#held = /* @__PURE__ */ new Set();
|
|
54
87
|
constructor(attribute, owner, options = {}) {
|
|
55
88
|
this.#attribute = attribute;
|
|
56
89
|
this.#record = `data-${owner}-${attribute}-lease`;
|
|
57
90
|
this.#base = options.base === true;
|
|
58
|
-
|
|
91
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
92
|
+
const names = registry.names;
|
|
59
93
|
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
60
94
|
}
|
|
61
95
|
write(element, value) {
|
|
62
|
-
const stack = this.#
|
|
96
|
+
const stack = attributeStack(element, this.#attribute);
|
|
63
97
|
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
64
98
|
this.#held.add(element);
|
|
65
99
|
const shows = !this.#covered(element, stack, hold);
|
|
@@ -69,8 +103,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
69
103
|
}
|
|
70
104
|
return(element) {
|
|
71
105
|
const held = this.#held.delete(element);
|
|
72
|
-
const known =
|
|
73
|
-
const stack = held || known || element.hasAttribute(this.#record) ? this.#
|
|
106
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
107
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
74
108
|
const hold = this.#take(stack);
|
|
75
109
|
if (!hold) return false;
|
|
76
110
|
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
@@ -88,31 +122,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
88
122
|
returnAll() {
|
|
89
123
|
for (const element of Array.from(this.#held)) this.return(element);
|
|
90
124
|
}
|
|
91
|
-
#stack(element) {
|
|
92
|
-
const stacks = _AttributeLease.#registry.stacks;
|
|
93
|
-
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
94
|
-
stacks.set(element, byAttribute);
|
|
95
|
-
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
96
|
-
byAttribute.set(this.#attribute, stack);
|
|
97
|
-
return stack;
|
|
98
|
-
}
|
|
99
|
-
#seed(element) {
|
|
100
|
-
const found = [];
|
|
101
|
-
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
102
|
-
const read = readLeaseRecord(element, record);
|
|
103
|
-
if (read) found.push({ ...read, record });
|
|
104
|
-
}
|
|
105
|
-
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
106
|
-
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
107
|
-
lease: null,
|
|
108
|
-
record,
|
|
109
|
-
written,
|
|
110
|
-
original,
|
|
111
|
-
linked: linked && index > 0
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
125
|
#take(stack) {
|
|
115
|
-
const hold = stack
|
|
126
|
+
const hold = findHold(stack, this, this.#record);
|
|
116
127
|
if (hold) hold.lease = this;
|
|
117
128
|
return hold;
|
|
118
129
|
}
|
|
@@ -121,7 +132,7 @@ var AttributeLease = class _AttributeLease {
|
|
|
121
132
|
const top = stack.at(-1);
|
|
122
133
|
const bottom = stack[0];
|
|
123
134
|
const over = top?.written === current ? top : void 0;
|
|
124
|
-
const from = this.#base ? bottom : over;
|
|
135
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
125
136
|
const hold = {
|
|
126
137
|
lease: this,
|
|
127
138
|
record: this.#record,
|
|
@@ -151,15 +162,11 @@ var AttributeLease = class _AttributeLease {
|
|
|
151
162
|
);
|
|
152
163
|
});
|
|
153
164
|
for (const [name, recorded] of records) {
|
|
154
|
-
|
|
155
|
-
if (recorded === null) element.removeAttribute(name);
|
|
156
|
-
else element.setAttribute(name, recorded);
|
|
165
|
+
setAttributeIfChanged(element, name, recorded);
|
|
157
166
|
}
|
|
158
167
|
}
|
|
159
168
|
#reflect(element, value) {
|
|
160
|
-
|
|
161
|
-
if (value === null) element.removeAttribute(this.#attribute);
|
|
162
|
-
else element.setAttribute(this.#attribute, value);
|
|
169
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
163
170
|
}
|
|
164
171
|
};
|
|
165
172
|
|
|
@@ -27,6 +27,9 @@ var MicrotaskCoalescer = class {
|
|
|
27
27
|
this.#queued = false;
|
|
28
28
|
this.#generation += 1;
|
|
29
29
|
}
|
|
30
|
+
get pending() {
|
|
31
|
+
return this.#queued;
|
|
32
|
+
}
|
|
30
33
|
schedule() {
|
|
31
34
|
if (!this.#active || this.#queued) return;
|
|
32
35
|
this.#queued = true;
|
|
@@ -57,6 +60,9 @@ var MorphRenderWatcher = class {
|
|
|
57
60
|
schedule() {
|
|
58
61
|
this.#pass.schedule();
|
|
59
62
|
}
|
|
63
|
+
get pending() {
|
|
64
|
+
return this.#pass.pending;
|
|
65
|
+
}
|
|
60
66
|
disconnect() {
|
|
61
67
|
this.#listeners.dispose();
|
|
62
68
|
this.#pass.cancel();
|
|
@@ -75,17 +81,18 @@ var FilterController = class extends Controller {
|
|
|
75
81
|
#reported = null;
|
|
76
82
|
#connected = false;
|
|
77
83
|
#morphRender = new MorphRenderWatcher(() => this.#evaluate());
|
|
84
|
+
#listeners = new ListenerSet();
|
|
78
85
|
connect() {
|
|
79
86
|
this.#morphRender.observe(this.element);
|
|
80
87
|
this.#reported = null;
|
|
81
88
|
this.#evaluate();
|
|
82
|
-
this.element
|
|
89
|
+
this.#listeners.add(this.element, "change", this.#onChange);
|
|
83
90
|
this.#connected = true;
|
|
84
91
|
}
|
|
85
92
|
disconnect() {
|
|
86
93
|
this.#morphRender.disconnect();
|
|
87
94
|
this.#connected = false;
|
|
88
|
-
this.
|
|
95
|
+
this.#listeners.dispose();
|
|
89
96
|
}
|
|
90
97
|
matchValueChanged() {
|
|
91
98
|
if (!this.#connected) return;
|
|
@@ -40,6 +40,59 @@ function ownerOf(candidates, node) {
|
|
|
40
40
|
return candidates[ownerIndex(candidates, node)] ?? null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
var ListenerSet = class {
|
|
44
|
+
#abort = new AbortController();
|
|
45
|
+
add(target, type, handler, options) {
|
|
46
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
47
|
+
}
|
|
48
|
+
dispose() {
|
|
49
|
+
this.#abort.abort();
|
|
50
|
+
this.#abort = new AbortController();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
var HoverRecheck = class {
|
|
55
|
+
#document;
|
|
56
|
+
#release;
|
|
57
|
+
#listeners = new ListenerSet();
|
|
58
|
+
#pending = /* @__PURE__ */ new Set();
|
|
59
|
+
#tickets = /* @__PURE__ */ new WeakMap();
|
|
60
|
+
constructor(document2, release) {
|
|
61
|
+
this.#document = document2;
|
|
62
|
+
this.#release = release;
|
|
63
|
+
}
|
|
64
|
+
wait(element) {
|
|
65
|
+
this.#pending.add(element);
|
|
66
|
+
this.#tickets.set(element, /* @__PURE__ */ Symbol());
|
|
67
|
+
this.#listeners.add(this.#document, "pointermove", this.#onPointerMove, {
|
|
68
|
+
capture: true,
|
|
69
|
+
passive: true
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
cancel(element) {
|
|
73
|
+
this.#tickets.delete(element);
|
|
74
|
+
this.#pending.delete(element);
|
|
75
|
+
if (this.#pending.size === 0) this.#listeners.dispose();
|
|
76
|
+
}
|
|
77
|
+
dispose() {
|
|
78
|
+
this.#listeners.dispose();
|
|
79
|
+
this.#pending.clear();
|
|
80
|
+
this.#tickets = /* @__PURE__ */ new WeakMap();
|
|
81
|
+
}
|
|
82
|
+
#onPointerMove = () => {
|
|
83
|
+
this.#listeners.dispose();
|
|
84
|
+
const waiting = [...this.#pending].map(
|
|
85
|
+
(element) => [element, this.#tickets.get(element)]
|
|
86
|
+
);
|
|
87
|
+
this.#pending.clear();
|
|
88
|
+
for (const [element, ticket] of waiting) {
|
|
89
|
+
if (this.#tickets.get(element) !== ticket) continue;
|
|
90
|
+
if (element.matches(":hover")) continue;
|
|
91
|
+
this.#release(element);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
43
96
|
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
44
97
|
|
|
45
98
|
var TimerRegistry = class {
|
|
@@ -100,17 +153,6 @@ var KeyedTimers = class {
|
|
|
100
153
|
}
|
|
101
154
|
};
|
|
102
155
|
|
|
103
|
-
var ListenerSet = class {
|
|
104
|
-
#abort = new AbortController();
|
|
105
|
-
add(target, type, handler, options) {
|
|
106
|
-
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
107
|
-
}
|
|
108
|
-
dispose() {
|
|
109
|
-
this.#abort.abort();
|
|
110
|
-
this.#abort = new AbortController();
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
156
|
var MicrotaskCoalescer = class {
|
|
115
157
|
#run;
|
|
116
158
|
#queued = false;
|
|
@@ -127,6 +169,9 @@ var MicrotaskCoalescer = class {
|
|
|
127
169
|
this.#queued = false;
|
|
128
170
|
this.#generation += 1;
|
|
129
171
|
}
|
|
172
|
+
get pending() {
|
|
173
|
+
return this.#queued;
|
|
174
|
+
}
|
|
130
175
|
schedule() {
|
|
131
176
|
if (!this.#active || this.#queued) return;
|
|
132
177
|
this.#queued = true;
|
|
@@ -157,6 +202,9 @@ var MorphRenderWatcher = class {
|
|
|
157
202
|
schedule() {
|
|
158
203
|
this.#pass.schedule();
|
|
159
204
|
}
|
|
205
|
+
get pending() {
|
|
206
|
+
return this.#pass.pending;
|
|
207
|
+
}
|
|
160
208
|
disconnect() {
|
|
161
209
|
this.#listeners.dispose();
|
|
162
210
|
this.#pass.cancel();
|
|
@@ -332,8 +380,10 @@ var FlashController = class _FlashController extends Controller {
|
|
|
332
380
|
#fixedDismiss = new KeyedTimers();
|
|
333
381
|
#reapply = new MorphRenderWatcher(() => this.#reapplyCap());
|
|
334
382
|
#spared = [];
|
|
335
|
-
#pointer = new
|
|
336
|
-
|
|
383
|
+
#pointer = new HoverRecheck(
|
|
384
|
+
this.element.ownerDocument,
|
|
385
|
+
(message) => this.#resume(message, "hover", null)
|
|
386
|
+
);
|
|
337
387
|
#observer = null;
|
|
338
388
|
#connected = false;
|
|
339
389
|
#arrivals = /* @__PURE__ */ new Set();
|
|
@@ -376,7 +426,6 @@ var FlashController = class _FlashController extends Controller {
|
|
|
376
426
|
this.#reapply.disconnect();
|
|
377
427
|
this.#spared = [];
|
|
378
428
|
this.#pointer.dispose();
|
|
379
|
-
this.#awaitingPointer.clear();
|
|
380
429
|
for (const message of this.#order) this.#unbindPause(message);
|
|
381
430
|
this.#order.length = 0;
|
|
382
431
|
this.#leaving.clear();
|
|
@@ -534,29 +583,14 @@ var FlashController = class _FlashController extends Controller {
|
|
|
534
583
|
}
|
|
535
584
|
#afterMove(message) {
|
|
536
585
|
if (!message.contains(document.activeElement)) this.#resume(message, "focus", null);
|
|
537
|
-
if (this.#dismiss.isHeld(message)) this.#
|
|
586
|
+
if (this.#dismiss.isHeld(message)) this.#pointer.wait(message);
|
|
538
587
|
}
|
|
539
588
|
#readHolds(message) {
|
|
540
589
|
if (message.contains(document.activeElement)) this.#pause(message, "focus");
|
|
541
590
|
if (!message.matches(":hover")) return;
|
|
542
591
|
this.#pause(message, "hover");
|
|
543
|
-
this.#
|
|
544
|
-
}
|
|
545
|
-
#awaitPointer(message) {
|
|
546
|
-
this.#awaitingPointer.add(message);
|
|
547
|
-
this.#pointer.add(document, "pointermove", this.#onPointerMove, {
|
|
548
|
-
capture: true,
|
|
549
|
-
passive: true
|
|
550
|
-
});
|
|
592
|
+
this.#pointer.wait(message);
|
|
551
593
|
}
|
|
552
|
-
#onPointerMove = () => {
|
|
553
|
-
this.#pointer.dispose();
|
|
554
|
-
const waiting = [...this.#awaitingPointer];
|
|
555
|
-
this.#awaitingPointer.clear();
|
|
556
|
-
for (const message of waiting) {
|
|
557
|
-
if (!message.matches(":hover")) this.#resume(message, "hover", null);
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
594
|
#forget(message) {
|
|
561
595
|
if (this.#dismiss.isHeld(message)) this.#capLater(null);
|
|
562
596
|
this.#dismiss.clear(message);
|
|
@@ -564,8 +598,7 @@ var FlashController = class _FlashController extends Controller {
|
|
|
564
598
|
const index = this.#order.indexOf(message);
|
|
565
599
|
if (index !== -1) this.#order.splice(index, 1);
|
|
566
600
|
this.#unbindPause(message);
|
|
567
|
-
this.#
|
|
568
|
-
if (this.#awaitingPointer.size === 0) this.#pointer.dispose();
|
|
601
|
+
this.#pointer.cancel(message);
|
|
569
602
|
}
|
|
570
603
|
#beginDismiss(message, reason) {
|
|
571
604
|
if (!this.#order.includes(message)) return;
|
|
@@ -330,6 +330,9 @@ var MicrotaskCoalescer = class {
|
|
|
330
330
|
this.#queued = false;
|
|
331
331
|
this.#generation += 1;
|
|
332
332
|
}
|
|
333
|
+
get pending() {
|
|
334
|
+
return this.#queued;
|
|
335
|
+
}
|
|
333
336
|
schedule() {
|
|
334
337
|
if (!this.#active || this.#queued) return;
|
|
335
338
|
this.#queued = true;
|
|
@@ -358,6 +361,16 @@ function queryOpenDescendants(root, selector) {
|
|
|
358
361
|
return matches;
|
|
359
362
|
}
|
|
360
363
|
|
|
364
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
365
|
+
if (element.getAttribute(name) === value) return false;
|
|
366
|
+
if (value === null) element.removeAttribute(name);
|
|
367
|
+
else element.setAttribute(name, value);
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function holdsFocus(element) {
|
|
372
|
+
return element.matches(":focus") || deepActiveElement(element.ownerDocument) === element;
|
|
373
|
+
}
|
|
361
374
|
var TabindexLoan = class _TabindexLoan {
|
|
362
375
|
static #registry = sharedRegistry(
|
|
363
376
|
"stimeo-ui.tabindex-loan.registry.v1",
|
|
@@ -365,19 +378,22 @@ var TabindexLoan = class _TabindexLoan {
|
|
|
365
378
|
);
|
|
366
379
|
#value;
|
|
367
380
|
#record;
|
|
381
|
+
#preserveFocus;
|
|
368
382
|
#lent = /* @__PURE__ */ new Set();
|
|
369
|
-
constructor(value, owner) {
|
|
383
|
+
constructor(value, owner, options = {}) {
|
|
370
384
|
this.#value = value;
|
|
371
385
|
this.#record = `data-${owner}-tabindex-loan`;
|
|
386
|
+
this.#preserveFocus = options.preserveFocus === true;
|
|
372
387
|
_TabindexLoan.#registry.names.add(this.#record);
|
|
373
388
|
}
|
|
374
|
-
lend(element) {
|
|
389
|
+
lend(element, options = {}) {
|
|
375
390
|
const stack = this.#stack(element);
|
|
376
391
|
const current = element.getAttribute("tabindex");
|
|
377
392
|
const held = stack.find((hold) => hold.loan === this) ?? stack.find(
|
|
378
393
|
(hold) => hold.loan === null && hold.record === this.#record && hold.value === this.#value
|
|
379
394
|
);
|
|
380
395
|
const linked = stack.at(-1)?.value === current;
|
|
396
|
+
if (!held && options.onlyIfUnfocusable && (current !== null || element.tabIndex >= 0)) return;
|
|
381
397
|
if (!held && current !== null && !linked) return;
|
|
382
398
|
this.#lent.add(element);
|
|
383
399
|
if (held) held.loan = this;
|
|
@@ -387,19 +403,28 @@ var TabindexLoan = class _TabindexLoan {
|
|
|
387
403
|
element.setAttribute("tabindex", this.#value);
|
|
388
404
|
}
|
|
389
405
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
406
|
+
return(element) {
|
|
407
|
+
const stack = this.#stack(element);
|
|
408
|
+
const hold = stack.find((held) => held.loan === this) ?? stack.find(
|
|
409
|
+
(held) => held.loan === null && held.record === this.#record && held.value === this.#value
|
|
410
|
+
);
|
|
411
|
+
if (!hold) return false;
|
|
412
|
+
if (!this.#release(element, stack, hold, this.#preserveFocus)) {
|
|
413
|
+
hold.loan = this;
|
|
414
|
+
this.#lent.add(element);
|
|
415
|
+
return false;
|
|
395
416
|
}
|
|
396
|
-
this.#lent.
|
|
417
|
+
this.#lent.delete(element);
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
returnAll() {
|
|
421
|
+
for (const element of Array.from(this.#lent)) this.return(element);
|
|
397
422
|
}
|
|
398
423
|
reclaim(element) {
|
|
399
424
|
if (element.getAttribute(this.#record) !== this.#value) return;
|
|
400
425
|
const stack = this.#stack(element);
|
|
401
426
|
const hold = stack.find((held) => held.loan === null && held.record === this.#record);
|
|
402
|
-
if (hold && !element
|
|
427
|
+
if (hold && !holdsFocus(element)) this.#release(element, stack, hold);
|
|
403
428
|
}
|
|
404
429
|
reclaimWithin(root) {
|
|
405
430
|
for (const element of queryOpenDescendants(root, `[${this.#record}]`)) {
|
|
@@ -423,26 +448,26 @@ var TabindexLoan = class _TabindexLoan {
|
|
|
423
448
|
for (const [index, hold] of holds.entries()) hold.linked = index > 0;
|
|
424
449
|
return holds;
|
|
425
450
|
}
|
|
426
|
-
#release(element, stack, hold) {
|
|
451
|
+
#release(element, stack, hold, preserveFocus = false) {
|
|
427
452
|
const current = element.getAttribute("tabindex");
|
|
428
453
|
const index = stack.indexOf(hold);
|
|
429
454
|
const owns = current === hold.value && !stack.slice(index + 1).some((above2) => above2.value === current);
|
|
455
|
+
if (owns && preserveFocus && holdsFocus(element)) return false;
|
|
430
456
|
stack.splice(index, 1);
|
|
431
457
|
const above = stack[index];
|
|
432
458
|
if (above) above.linked &&= hold.linked;
|
|
433
459
|
this.#mark(element, stack);
|
|
434
|
-
if (!owns) return;
|
|
460
|
+
if (!owns) return true;
|
|
435
461
|
const below = hold.linked ? stack[index - 1] : void 0;
|
|
436
462
|
if (!below) element.removeAttribute("tabindex");
|
|
437
463
|
else if (below.value !== current) element.setAttribute("tabindex", below.value);
|
|
464
|
+
return true;
|
|
438
465
|
}
|
|
439
466
|
#mark(element, stack) {
|
|
440
467
|
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
441
468
|
for (const hold of stack) records.set(hold.record, hold.value);
|
|
442
469
|
for (const [name, recorded] of records) {
|
|
443
|
-
|
|
444
|
-
if (recorded === null) element.removeAttribute(name);
|
|
445
|
-
else element.setAttribute(name, recorded);
|
|
470
|
+
setAttributeIfChanged(element, name, recorded);
|
|
446
471
|
}
|
|
447
472
|
}
|
|
448
473
|
};
|