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
|
@@ -22,13 +22,18 @@ function actionSource(source) {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
26
|
+
if (element.getAttribute(name) === value) return false;
|
|
27
|
+
if (value === null) element.removeAttribute(name);
|
|
28
|
+
else element.setAttribute(name, value);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
25
32
|
function syncActiveOption(options, active) {
|
|
26
33
|
let written = 0;
|
|
27
34
|
for (const option of options) {
|
|
28
35
|
const next = option === active ? "true" : "false";
|
|
29
|
-
if (option
|
|
30
|
-
option.setAttribute("aria-selected", next);
|
|
31
|
-
written += 1;
|
|
36
|
+
if (setAttributeIfChanged(option, "aria-selected", next)) written += 1;
|
|
32
37
|
}
|
|
33
38
|
return written;
|
|
34
39
|
}
|
|
@@ -37,17 +42,24 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
37
42
|
if (!event.key.startsWith("Arrow")) return false;
|
|
38
43
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
39
44
|
}
|
|
45
|
+
function hasModifierChord(event) {
|
|
46
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
47
|
+
}
|
|
40
48
|
|
|
41
49
|
function sharedRegistry(key, create) {
|
|
42
50
|
const symbol = Symbol.for(key);
|
|
43
51
|
const scope = globalThis;
|
|
44
52
|
const existing = scope[symbol];
|
|
45
53
|
if (existing !== void 0) return existing;
|
|
46
|
-
const
|
|
47
|
-
Object.defineProperty(globalThis, symbol, { value:
|
|
48
|
-
return
|
|
54
|
+
const registry2 = create();
|
|
55
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
56
|
+
return registry2;
|
|
49
57
|
}
|
|
50
58
|
|
|
59
|
+
var registry = sharedRegistry(
|
|
60
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
61
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
62
|
+
);
|
|
51
63
|
function isAttributeValue(value) {
|
|
52
64
|
return value === null || typeof value === "string";
|
|
53
65
|
}
|
|
@@ -64,24 +76,46 @@ function readLeaseRecord(element, record) {
|
|
|
64
76
|
return void 0;
|
|
65
77
|
}
|
|
66
78
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
);
|
|
79
|
+
function attributeStack(element, attribute) {
|
|
80
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
81
|
+
registry.stacks.set(element, byAttribute);
|
|
82
|
+
const known = byAttribute.get(attribute);
|
|
83
|
+
if (known) return known;
|
|
84
|
+
const found = [];
|
|
85
|
+
for (const record of registry.names.get(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
|
+
const stack = 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
|
+
byAttribute.set(attribute, stack);
|
|
98
|
+
return stack;
|
|
99
|
+
}
|
|
100
|
+
function findHold(stack, lease, record) {
|
|
101
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
102
|
+
}
|
|
103
|
+
var AttributeLease = class {
|
|
72
104
|
#attribute;
|
|
73
105
|
#record;
|
|
74
106
|
#base;
|
|
107
|
+
#preserveAuthor;
|
|
75
108
|
#held = /* @__PURE__ */ new Set();
|
|
76
109
|
constructor(attribute, owner, options = {}) {
|
|
77
110
|
this.#attribute = attribute;
|
|
78
111
|
this.#record = `data-${owner}-${attribute}-lease`;
|
|
79
112
|
this.#base = options.base === true;
|
|
80
|
-
|
|
113
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
114
|
+
const names = registry.names;
|
|
81
115
|
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
82
116
|
}
|
|
83
117
|
write(element, value) {
|
|
84
|
-
const stack = this.#
|
|
118
|
+
const stack = attributeStack(element, this.#attribute);
|
|
85
119
|
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
86
120
|
this.#held.add(element);
|
|
87
121
|
const shows = !this.#covered(element, stack, hold);
|
|
@@ -91,8 +125,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
91
125
|
}
|
|
92
126
|
return(element) {
|
|
93
127
|
const held = this.#held.delete(element);
|
|
94
|
-
const known =
|
|
95
|
-
const stack = held || known || element.hasAttribute(this.#record) ? this.#
|
|
128
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
129
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
96
130
|
const hold = this.#take(stack);
|
|
97
131
|
if (!hold) return false;
|
|
98
132
|
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
@@ -110,31 +144,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
110
144
|
returnAll() {
|
|
111
145
|
for (const element of Array.from(this.#held)) this.return(element);
|
|
112
146
|
}
|
|
113
|
-
#stack(element) {
|
|
114
|
-
const stacks = _AttributeLease.#registry.stacks;
|
|
115
|
-
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
116
|
-
stacks.set(element, byAttribute);
|
|
117
|
-
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
118
|
-
byAttribute.set(this.#attribute, stack);
|
|
119
|
-
return stack;
|
|
120
|
-
}
|
|
121
|
-
#seed(element) {
|
|
122
|
-
const found = [];
|
|
123
|
-
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
124
|
-
const read = readLeaseRecord(element, record);
|
|
125
|
-
if (read) found.push({ ...read, record });
|
|
126
|
-
}
|
|
127
|
-
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
128
|
-
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
129
|
-
lease: null,
|
|
130
|
-
record,
|
|
131
|
-
written,
|
|
132
|
-
original,
|
|
133
|
-
linked: linked && index > 0
|
|
134
|
-
}));
|
|
135
|
-
}
|
|
136
147
|
#take(stack) {
|
|
137
|
-
const hold = stack
|
|
148
|
+
const hold = findHold(stack, this, this.#record);
|
|
138
149
|
if (hold) hold.lease = this;
|
|
139
150
|
return hold;
|
|
140
151
|
}
|
|
@@ -143,7 +154,7 @@ var AttributeLease = class _AttributeLease {
|
|
|
143
154
|
const top = stack.at(-1);
|
|
144
155
|
const bottom = stack[0];
|
|
145
156
|
const over = top?.written === current ? top : void 0;
|
|
146
|
-
const from = this.#base ? bottom : over;
|
|
157
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
147
158
|
const hold = {
|
|
148
159
|
lease: this,
|
|
149
160
|
record: this.#record,
|
|
@@ -173,15 +184,11 @@ var AttributeLease = class _AttributeLease {
|
|
|
173
184
|
);
|
|
174
185
|
});
|
|
175
186
|
for (const [name, recorded] of records) {
|
|
176
|
-
|
|
177
|
-
if (recorded === null) element.removeAttribute(name);
|
|
178
|
-
else element.setAttribute(name, recorded);
|
|
187
|
+
setAttributeIfChanged(element, name, recorded);
|
|
179
188
|
}
|
|
180
189
|
}
|
|
181
190
|
#reflect(element, value) {
|
|
182
|
-
|
|
183
|
-
if (value === null) element.removeAttribute(this.#attribute);
|
|
184
|
-
else element.setAttribute(this.#attribute, value);
|
|
191
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
185
192
|
}
|
|
186
193
|
};
|
|
187
194
|
|
|
@@ -191,63 +198,182 @@ var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
|
191
198
|
"deleteCompositionText",
|
|
192
199
|
"deleteByComposition"
|
|
193
200
|
]);
|
|
201
|
+
function isCompositionInputType(inputType) {
|
|
202
|
+
return inputType !== void 0 && COMPOSITION_INPUT_TYPES.has(inputType);
|
|
203
|
+
}
|
|
204
|
+
var BEFORE_MORPH_ATTRIBUTE = "turbo:before-morph-attribute";
|
|
205
|
+
var textOf = (element) => element.value;
|
|
206
|
+
var holdsFocus = (element) => element instanceof Node && element.getRootNode().activeElement === element;
|
|
194
207
|
var CompositionTracker = class {
|
|
195
208
|
#observedTargets = /* @__PURE__ */ new Set();
|
|
196
|
-
#
|
|
209
|
+
#composition = null;
|
|
197
210
|
#onStart;
|
|
198
211
|
#onEnd;
|
|
212
|
+
#onAbandon;
|
|
199
213
|
#confirmedTarget = null;
|
|
214
|
+
#keyComposing = false;
|
|
215
|
+
#connected = false;
|
|
216
|
+
#abandoned = null;
|
|
200
217
|
constructor(options = {}) {
|
|
201
218
|
this.#onStart = options.onStart;
|
|
202
219
|
this.#onEnd = options.onEnd;
|
|
220
|
+
this.#onAbandon = options.onAbandon;
|
|
203
221
|
}
|
|
204
222
|
observe(target) {
|
|
223
|
+
this.#connected = true;
|
|
205
224
|
if (this.#observedTargets.has(target)) return;
|
|
206
225
|
target.addEventListener("compositionstart", this.#handleStart);
|
|
207
226
|
target.addEventListener("compositionend", this.#handleEnd);
|
|
208
|
-
target.addEventListener("keydown", this.#handleKeydown);
|
|
227
|
+
target.addEventListener("keydown", this.#handleKeydown, true);
|
|
228
|
+
target.addEventListener("beforeinput", this.#handleBeforeInput, true);
|
|
229
|
+
target.addEventListener("input", this.#handleInput, true);
|
|
230
|
+
target.addEventListener("blur", this.#handleBlur, true);
|
|
231
|
+
target.addEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
|
|
209
232
|
this.#observedTargets.add(target);
|
|
210
233
|
}
|
|
211
234
|
unobserve(target) {
|
|
212
235
|
if (!this.#observedTargets.delete(target)) return;
|
|
213
|
-
|
|
214
|
-
target
|
|
215
|
-
target.removeEventListener("keydown", this.#handleKeydown);
|
|
216
|
-
this.#activeTargets.delete(target);
|
|
236
|
+
this.#release(target);
|
|
237
|
+
if (this.#composition?.target === target) this.#letGo();
|
|
217
238
|
if (this.#confirmedTarget === target) this.#confirmedTarget = null;
|
|
218
239
|
}
|
|
219
240
|
disconnect() {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
target.removeEventListener("compositionend", this.#handleEnd);
|
|
223
|
-
target.removeEventListener("keydown", this.#handleKeydown);
|
|
224
|
-
}
|
|
241
|
+
this.#connected = false;
|
|
242
|
+
for (const target of this.#observedTargets) this.#release(target);
|
|
225
243
|
this.#observedTargets.clear();
|
|
226
|
-
this.#
|
|
244
|
+
this.#letGo();
|
|
227
245
|
this.#confirmedTarget = null;
|
|
246
|
+
this.#keyComposing = false;
|
|
247
|
+
this.#abandoned = null;
|
|
228
248
|
}
|
|
229
249
|
isComposing(event) {
|
|
230
|
-
|
|
250
|
+
this.#settle();
|
|
251
|
+
return event?.isComposing === true || this.#composition !== null;
|
|
252
|
+
}
|
|
253
|
+
composingElement() {
|
|
254
|
+
this.#settle();
|
|
255
|
+
return this.#composition?.element ?? null;
|
|
256
|
+
}
|
|
257
|
+
owns(event) {
|
|
258
|
+
const element = this.composingElement();
|
|
259
|
+
return event.isComposing === true || element !== null && element === event.target;
|
|
231
260
|
}
|
|
232
261
|
consumesConfirmedInput(event) {
|
|
233
262
|
const confirmed = this.#confirmedTarget;
|
|
234
263
|
this.#confirmedTarget = null;
|
|
235
264
|
if (confirmed === null || confirmed !== event.target) return false;
|
|
236
265
|
const inputType = event.inputType;
|
|
237
|
-
return !inputType ||
|
|
266
|
+
return !inputType || isCompositionInputType(inputType);
|
|
267
|
+
}
|
|
268
|
+
#release(target) {
|
|
269
|
+
target.removeEventListener("compositionstart", this.#handleStart);
|
|
270
|
+
target.removeEventListener("compositionend", this.#handleEnd);
|
|
271
|
+
target.removeEventListener("keydown", this.#handleKeydown, true);
|
|
272
|
+
target.removeEventListener("beforeinput", this.#handleBeforeInput, true);
|
|
273
|
+
target.removeEventListener("input", this.#handleInput, true);
|
|
274
|
+
target.removeEventListener("blur", this.#handleBlur, true);
|
|
275
|
+
target.removeEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
|
|
276
|
+
}
|
|
277
|
+
#letGo() {
|
|
278
|
+
const composition = this.#composition;
|
|
279
|
+
if (composition === null) return;
|
|
280
|
+
if (!holdsFocus(composition.element)) {
|
|
281
|
+
this.#composition = null;
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
queueMicrotask(() => {
|
|
285
|
+
if (this.#composition !== composition || this.#observedTargets.has(composition.target)) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
this.#composition = null;
|
|
289
|
+
if (!this.#connected) return;
|
|
290
|
+
this.#abandoned = { element: composition.element, inPlace: true };
|
|
291
|
+
this.#runAbandon();
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
#settle() {
|
|
295
|
+
const composition = this.#composition;
|
|
296
|
+
if (composition === null) return;
|
|
297
|
+
const { target, element, text } = composition;
|
|
298
|
+
if (target instanceof Node && element instanceof Node && !target.contains(element)) {
|
|
299
|
+
this.#composition = null;
|
|
300
|
+
} else if (textOf(element) !== text) {
|
|
301
|
+
this.#abandon(false);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
#abandon(inPlace) {
|
|
305
|
+
this.#owe(inPlace);
|
|
306
|
+
this.#composition = null;
|
|
307
|
+
queueMicrotask(this.#runAbandon);
|
|
308
|
+
}
|
|
309
|
+
#owe(inPlace) {
|
|
310
|
+
const composition = this.#composition;
|
|
311
|
+
if (composition !== null) this.#abandoned = { element: composition.element, inPlace };
|
|
238
312
|
}
|
|
313
|
+
#runAbandon = () => {
|
|
314
|
+
const abandoned = this.#abandoned;
|
|
315
|
+
if (abandoned === null) return;
|
|
316
|
+
this.#abandoned = null;
|
|
317
|
+
this.#onAbandon?.(abandoned.element, abandoned.inPlace);
|
|
318
|
+
};
|
|
239
319
|
#handleStart = (event) => {
|
|
240
320
|
this.#confirmedTarget = null;
|
|
241
|
-
|
|
321
|
+
this.#settle();
|
|
322
|
+
this.#owe(true);
|
|
323
|
+
const target = event.currentTarget;
|
|
324
|
+
const element = event.target;
|
|
325
|
+
this.#composition = { target, element, text: textOf(element) };
|
|
326
|
+
this.#runAbandon();
|
|
242
327
|
this.#onStart?.(event);
|
|
243
328
|
};
|
|
244
329
|
#handleEnd = (event) => {
|
|
245
|
-
|
|
330
|
+
this.#runAbandon();
|
|
331
|
+
if (this.#composition?.target === event.currentTarget) this.#composition = null;
|
|
246
332
|
this.#confirmedTarget = event.target;
|
|
247
333
|
this.#onEnd?.(event);
|
|
248
334
|
};
|
|
249
|
-
#handleKeydown = () => {
|
|
335
|
+
#handleKeydown = (event) => {
|
|
336
|
+
this.#settle();
|
|
337
|
+
this.#runAbandon();
|
|
250
338
|
this.#confirmedTarget = null;
|
|
339
|
+
this.#keyComposing = event.isComposing === true;
|
|
340
|
+
};
|
|
341
|
+
#handleBeforeInput = (event) => {
|
|
342
|
+
const keyComposing = this.#keyComposing;
|
|
343
|
+
this.#keyComposing = false;
|
|
344
|
+
this.#settle();
|
|
345
|
+
const { isComposing, inputType } = event;
|
|
346
|
+
if (this.#composition !== null && !keyComposing && !isComposing && inputType && !isCompositionInputType(inputType)) {
|
|
347
|
+
this.#abandon(true);
|
|
348
|
+
}
|
|
349
|
+
this.#runAbandon();
|
|
350
|
+
};
|
|
351
|
+
#handleInput = (event) => {
|
|
352
|
+
const composition = this.#composition;
|
|
353
|
+
const { isTrusted, isComposing, inputType } = event;
|
|
354
|
+
if (composition !== null && event.target === composition.element && (isTrusted || isComposing || isCompositionInputType(inputType))) {
|
|
355
|
+
composition.text = textOf(composition.element);
|
|
356
|
+
} else {
|
|
357
|
+
this.#settle();
|
|
358
|
+
}
|
|
359
|
+
this.#runAbandon();
|
|
360
|
+
};
|
|
361
|
+
#handleBlur = (event) => {
|
|
362
|
+
this.#settle();
|
|
363
|
+
this.#runAbandon();
|
|
364
|
+
const composition = this.#composition;
|
|
365
|
+
if (composition === null || composition.target === composition.element) return;
|
|
366
|
+
const { element } = composition;
|
|
367
|
+
if (!(element instanceof Node) || event.target !== element) return;
|
|
368
|
+
const root = element.getRootNode();
|
|
369
|
+
if (root.activeElement !== element) this.#composition = null;
|
|
370
|
+
};
|
|
371
|
+
#handleBeforeMorphAttribute = (event) => {
|
|
372
|
+
this.#settle();
|
|
373
|
+
const composition = this.#composition;
|
|
374
|
+
if (composition?.target !== event.currentTarget || event.target !== composition.element) return;
|
|
375
|
+
const detail = event.detail;
|
|
376
|
+
if (detail?.attributeName === "value") event.preventDefault();
|
|
251
377
|
};
|
|
252
378
|
};
|
|
253
379
|
|
|
@@ -255,6 +381,17 @@ function commitField(target) {
|
|
|
255
381
|
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
256
382
|
}
|
|
257
383
|
|
|
384
|
+
var ListenerSet = class {
|
|
385
|
+
#abort = new AbortController();
|
|
386
|
+
add(target, type, handler, options) {
|
|
387
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
388
|
+
}
|
|
389
|
+
dispose() {
|
|
390
|
+
this.#abort.abort();
|
|
391
|
+
this.#abort = new AbortController();
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
258
395
|
var MicrotaskCoalescer = class {
|
|
259
396
|
#run;
|
|
260
397
|
#queued = false;
|
|
@@ -271,6 +408,9 @@ var MicrotaskCoalescer = class {
|
|
|
271
408
|
this.#queued = false;
|
|
272
409
|
this.#generation += 1;
|
|
273
410
|
}
|
|
411
|
+
get pending() {
|
|
412
|
+
return this.#queued;
|
|
413
|
+
}
|
|
274
414
|
schedule() {
|
|
275
415
|
if (!this.#active || this.#queued) return;
|
|
276
416
|
this.#queued = true;
|
|
@@ -349,9 +489,8 @@ var StateRegions = class _StateRegions {
|
|
|
349
489
|
const below = hold.linked ? stack[index - 1] : void 0;
|
|
350
490
|
if (below) {
|
|
351
491
|
if (region.hidden !== below.written) region.hidden = below.written;
|
|
352
|
-
} else
|
|
353
|
-
|
|
354
|
-
else region.setAttribute("hidden", hold.authored);
|
|
492
|
+
} else {
|
|
493
|
+
setAttributeIfChanged(region, "hidden", hold.authored);
|
|
355
494
|
}
|
|
356
495
|
}
|
|
357
496
|
this.#mark(region, stack);
|
|
@@ -426,9 +565,7 @@ var StateRegions = class _StateRegions {
|
|
|
426
565
|
);
|
|
427
566
|
});
|
|
428
567
|
for (const [name, recorded] of records) {
|
|
429
|
-
|
|
430
|
-
if (recorded === null) region.removeAttribute(name);
|
|
431
|
-
else region.setAttribute(name, recorded);
|
|
568
|
+
setAttributeIfChanged(region, name, recorded);
|
|
432
569
|
}
|
|
433
570
|
}
|
|
434
571
|
#recorded(region, name) {
|
|
@@ -473,11 +610,12 @@ var ComboboxController = class extends Controller {
|
|
|
473
610
|
#reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());
|
|
474
611
|
#suppressOpen = false;
|
|
475
612
|
#composition = new CompositionTracker({ onEnd: () => this.filter() });
|
|
613
|
+
#listeners = new ListenerSet();
|
|
476
614
|
connect() {
|
|
477
615
|
if (this.hasInputTarget) this.#composition.observe(this.inputTarget);
|
|
478
616
|
this.close();
|
|
479
617
|
this.#list = this.hasListTarget ? this.listTarget : null;
|
|
480
|
-
|
|
618
|
+
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
481
619
|
this.#connected = true;
|
|
482
620
|
this.#reconcile.activate();
|
|
483
621
|
}
|
|
@@ -485,7 +623,7 @@ var ComboboxController = class extends Controller {
|
|
|
485
623
|
this.#connected = false;
|
|
486
624
|
this.#reconcile.cancel();
|
|
487
625
|
this.#composition.disconnect();
|
|
488
|
-
|
|
626
|
+
this.#listeners.dispose();
|
|
489
627
|
}
|
|
490
628
|
inputTargetConnected(input) {
|
|
491
629
|
this.#composition.observe(input);
|
|
@@ -547,6 +685,7 @@ var ComboboxController = class extends Controller {
|
|
|
547
685
|
if (this.#composition.isComposing(event)) return;
|
|
548
686
|
if (event.defaultPrevented) return;
|
|
549
687
|
if (isReservedArrowChord(event, ["alt"])) return;
|
|
688
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
550
689
|
if (event.altKey && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
|
|
551
690
|
if (event.key === "ArrowDown" ? !this.#isClosed : this.#isClosed) return;
|
|
552
691
|
event.preventDefault();
|