stimeo-ui 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +178 -0
- package/README.md +120 -0
- package/dist/cable/index.js +63 -15
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +30 -3
- package/dist/controllers/accordion_controller.js +98 -9
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +8 -7
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +3 -2
- package/dist/controllers/announcer_controller.js +8 -1
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js +43 -2
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +1 -1
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +9 -8
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +4 -4
- package/dist/controllers/bulk_select_controller.js +7 -6
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +85 -23
- package/dist/controllers/calendar_controller.js +323 -123
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +67 -22
- package/dist/controllers/carousel_controller.js +263 -38
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +1 -1
- package/dist/controllers/character_counter_controller.js +40 -2
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.js +54 -10
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +28 -2
- package/dist/controllers/clipboard_controller.js +63 -5
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +25 -1
- package/dist/controllers/collapsible_controller.js +99 -14
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +29 -8
- package/dist/controllers/color_picker_controller.js +80 -34
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +10 -1
- package/dist/controllers/combobox_controller.js +106 -16
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +3 -3
- package/dist/controllers/command_palette_controller.js +35 -3
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js +56 -11
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.js +3 -0
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +6 -0
- package/dist/controllers/context_menu_controller.js +32 -12
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +30 -1
- package/dist/controllers/countdown_controller.js +129 -26
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +74 -15
- package/dist/controllers/currency_input_controller.js +205 -58
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +63 -18
- package/dist/controllers/data_grid_controller.js +195 -29
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +34 -6
- package/dist/controllers/date_range_picker_controller.js +139 -27
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +10 -3
- package/dist/controllers/dialog_controller.js +35 -8
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.js +22 -4
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +2 -2
- package/dist/controllers/dirty_form_controller.js +14 -1
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js +1 -0
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +18 -10
- package/dist/controllers/drawer_controller.js +54 -19
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +9 -3
- package/dist/controllers/dropdown_controller.js +36 -9
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.js +34 -0
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js +144 -51
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +10 -4
- package/dist/controllers/filter_controller.js +20 -6
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +26 -6
- package/dist/controllers/flash_controller.js +305 -46
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.js +1 -0
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +7 -5
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +19 -13
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.js +16 -2
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js +19 -2
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +10 -2
- package/dist/controllers/hover_card_controller.js +40 -14
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +16 -3
- package/dist/controllers/idle_controller.js +90 -5
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +5 -2
- package/dist/controllers/input_mask_controller.js +65 -9
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.js +3 -0
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.js +11 -2
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +50 -8
- package/dist/controllers/listbox_controller.js +203 -45
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.js +0 -2
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +9 -3
- package/dist/controllers/menu_controller.js +45 -16
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +11 -0
- package/dist/controllers/menubar_controller.js +58 -24
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.js +9 -5
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +18 -3
- package/dist/controllers/multi_select_controller.js +278 -104
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +11 -0
- package/dist/controllers/navigation_menu_controller.js +48 -15
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js +37 -8
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.js +9 -1
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +36 -8
- package/dist/controllers/number_input_controller.js +124 -21
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +14 -1
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +22 -7
- package/dist/controllers/otp_controller.js +198 -55
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
- package/dist/controllers/overflow_indicator_controller.js +84 -13
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +26 -6
- package/dist/controllers/overflow_menu_controller.js +112 -41
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +19 -11
- package/dist/controllers/pagination_controller.js +74 -28
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +15 -1
- package/dist/controllers/password_reveal_controller.js +59 -2
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/persist_controller.js +30 -8
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +131 -52
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +9 -3
- package/dist/controllers/popover_controller.js +45 -11
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +1 -1
- package/dist/controllers/portal_controller.js +6 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.js +16 -1
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.js +8 -4
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +6 -4
- package/dist/controllers/radio_group_controller.js +42 -17
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +49 -1
- package/dist/controllers/range_slider_controller.js +88 -42
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +14 -3
- package/dist/controllers/rating_controller.js +39 -15
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +24 -2
- package/dist/controllers/read_more_controller.js +69 -2
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +16 -2
- package/dist/controllers/resizable_controller.js +82 -22
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js +5 -1
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.js +0 -1
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +3 -2
- package/dist/controllers/scrollspy_controller.js +6 -0
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +41 -14
- package/dist/controllers/separator_controller.js +66 -37
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +20 -3
- package/dist/controllers/sidebar_controller.js +77 -18
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.js +6 -1
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +45 -7
- package/dist/controllers/slider_controller.js +82 -47
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.js +11 -1
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +17 -2
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.js +10 -2
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +19 -17
- package/dist/controllers/step_indicator_controller.js +18 -17
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +34 -9
- package/dist/controllers/stepper_controller.js +101 -19
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
- package/dist/controllers/stick_to_bottom_controller.js +75 -5
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +3 -2
- package/dist/controllers/submit_once_controller.js +16 -3
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +29 -7
- package/dist/controllers/switch_controller.js +101 -10
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +12 -0
- package/dist/controllers/tabs_controller.js +21 -2
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +15 -3
- package/dist/controllers/tags_input_controller.js +209 -59
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +20 -3
- package/dist/controllers/theme_controller.js +64 -14
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.js +23 -8
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +52 -15
- package/dist/controllers/toast_controller.js +337 -54
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +49 -7
- package/dist/controllers/toggle_group_controller.js +159 -23
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +32 -0
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +8 -0
- package/dist/controllers/tooltip_controller.js +39 -13
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.js +4 -0
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +39 -8
- package/dist/controllers/tree_view_controller.js +169 -16
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +4588 -1535
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +72 -6
- package/dist/inspector/cli.js +262 -51
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +309 -51
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +40 -40
- package/dist/inspector/manifest.json +525 -59
- package/dist/positioning/index.js +2 -0
- package/dist/positioning/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -35,6 +35,25 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
35
35
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// src/utils/element_part.ts
|
|
39
|
+
function matchingPart(root, selector) {
|
|
40
|
+
return root.matches(selector) ? root : root.querySelector(selector);
|
|
41
|
+
}
|
|
42
|
+
function writeLabel(slot, text) {
|
|
43
|
+
if (slot.childElementCount === 0) {
|
|
44
|
+
slot.textContent = text;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let first = null;
|
|
48
|
+
for (const node of Array.from(slot.childNodes)) {
|
|
49
|
+
if (node.nodeType !== Node.TEXT_NODE) continue;
|
|
50
|
+
if (first) node.remove();
|
|
51
|
+
else first = node;
|
|
52
|
+
}
|
|
53
|
+
if (first) first.nodeValue = text;
|
|
54
|
+
else slot.prepend(text);
|
|
55
|
+
}
|
|
56
|
+
|
|
38
57
|
// src/utils/roving_tabindex.ts
|
|
39
58
|
var RovingTabindex = class {
|
|
40
59
|
/** Returns the current ordered item elements; called on every operation. */
|
|
@@ -82,7 +101,7 @@ var ChipRow = class {
|
|
|
82
101
|
constructor(options) {
|
|
83
102
|
this.#directionElement = options.directionElement;
|
|
84
103
|
this.#getItems = options.getItems;
|
|
85
|
-
this.#getButton = options.getButton ?? ((item) => item
|
|
104
|
+
this.#getButton = options.getButton ?? ((item) => matchingPart(item, "button"));
|
|
86
105
|
this.#onRemove = options.onRemove;
|
|
87
106
|
this.#focusAfterEnd = options.focusAfterEnd;
|
|
88
107
|
}
|
|
@@ -207,11 +226,19 @@ var ChipRow = class {
|
|
|
207
226
|
};
|
|
208
227
|
|
|
209
228
|
// src/utils/composition_tracker.ts
|
|
229
|
+
var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
230
|
+
"insertCompositionText",
|
|
231
|
+
"insertFromComposition",
|
|
232
|
+
"deleteCompositionText",
|
|
233
|
+
"deleteByComposition"
|
|
234
|
+
]);
|
|
210
235
|
var CompositionTracker = class {
|
|
211
236
|
#observedTargets = /* @__PURE__ */ new Set();
|
|
212
237
|
#activeTargets = /* @__PURE__ */ new Set();
|
|
213
238
|
#onStart;
|
|
214
239
|
#onEnd;
|
|
240
|
+
/** The field whose confirming `input` is still owed, while the window is open. */
|
|
241
|
+
#confirmedTarget = null;
|
|
215
242
|
constructor(options = {}) {
|
|
216
243
|
this.#onStart = options.onStart;
|
|
217
244
|
this.#onEnd = options.onEnd;
|
|
@@ -221,6 +248,7 @@ var CompositionTracker = class {
|
|
|
221
248
|
if (this.#observedTargets.has(target)) return;
|
|
222
249
|
target.addEventListener("compositionstart", this.#handleStart);
|
|
223
250
|
target.addEventListener("compositionend", this.#handleEnd);
|
|
251
|
+
target.addEventListener("keydown", this.#handleKeydown);
|
|
224
252
|
this.#observedTargets.add(target);
|
|
225
253
|
}
|
|
226
254
|
/** Stops tracking one target and clears any active composition it owned. */
|
|
@@ -228,31 +256,77 @@ var CompositionTracker = class {
|
|
|
228
256
|
if (!this.#observedTargets.delete(target)) return;
|
|
229
257
|
target.removeEventListener("compositionstart", this.#handleStart);
|
|
230
258
|
target.removeEventListener("compositionend", this.#handleEnd);
|
|
259
|
+
target.removeEventListener("keydown", this.#handleKeydown);
|
|
231
260
|
this.#activeTargets.delete(target);
|
|
261
|
+
if (this.#confirmedTarget === target) this.#confirmedTarget = null;
|
|
232
262
|
}
|
|
233
263
|
/** Releases every listener and clears state so reconnect starts cleanly. */
|
|
234
264
|
disconnect() {
|
|
235
265
|
for (const target of this.#observedTargets) {
|
|
236
266
|
target.removeEventListener("compositionstart", this.#handleStart);
|
|
237
267
|
target.removeEventListener("compositionend", this.#handleEnd);
|
|
268
|
+
target.removeEventListener("keydown", this.#handleKeydown);
|
|
238
269
|
}
|
|
239
270
|
this.#observedTargets.clear();
|
|
240
271
|
this.#activeTargets.clear();
|
|
272
|
+
this.#confirmedTarget = null;
|
|
241
273
|
}
|
|
242
274
|
/** True when lifecycle tracking or the current event reports composition. */
|
|
243
275
|
isComposing(event) {
|
|
244
276
|
return this.#activeTargets.size > 0 || event?.isComposing === true;
|
|
245
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Whether `event` is the `input` echoing the composition just confirmed.
|
|
280
|
+
*
|
|
281
|
+
* Asking closes the window either way, so one confirmation is folded at most
|
|
282
|
+
* once and a consumer asks once per `input`.
|
|
283
|
+
*/
|
|
284
|
+
consumesConfirmedInput(event) {
|
|
285
|
+
const confirmed = this.#confirmedTarget;
|
|
286
|
+
this.#confirmedTarget = null;
|
|
287
|
+
if (confirmed === null || confirmed !== event.target) return false;
|
|
288
|
+
const inputType = event.inputType;
|
|
289
|
+
return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);
|
|
290
|
+
}
|
|
246
291
|
#handleStart = (event) => {
|
|
292
|
+
this.#confirmedTarget = null;
|
|
247
293
|
if (event.currentTarget) this.#activeTargets.add(event.currentTarget);
|
|
248
294
|
this.#onStart?.(event);
|
|
249
295
|
};
|
|
250
296
|
#handleEnd = (event) => {
|
|
251
297
|
if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);
|
|
298
|
+
this.#confirmedTarget = event.target;
|
|
252
299
|
this.#onEnd?.(event);
|
|
253
300
|
};
|
|
301
|
+
/** A key on an observed field opens an edit of its own, so no echo is owed. */
|
|
302
|
+
#handleKeydown = () => {
|
|
303
|
+
this.#confirmedTarget = null;
|
|
304
|
+
};
|
|
254
305
|
};
|
|
255
306
|
|
|
307
|
+
// src/utils/field_mirror.ts
|
|
308
|
+
function writeFields(container, values, { name, form = "" }) {
|
|
309
|
+
const current = [...container.children];
|
|
310
|
+
const submits = current.length === values.length && current.every(
|
|
311
|
+
(child, index) => child instanceof HTMLInputElement && child.type === "hidden" && child.value === values[index] && child.name === name && (child.getAttribute("form") ?? "") === form
|
|
312
|
+
);
|
|
313
|
+
if (submits) return false;
|
|
314
|
+
container.replaceChildren(
|
|
315
|
+
...values.map((value) => {
|
|
316
|
+
const input = document.createElement("input");
|
|
317
|
+
input.type = "hidden";
|
|
318
|
+
input.name = name;
|
|
319
|
+
input.value = value;
|
|
320
|
+
if (form !== "") input.setAttribute("form", form);
|
|
321
|
+
return input;
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
function commitField(target) {
|
|
327
|
+
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
328
|
+
}
|
|
329
|
+
|
|
256
330
|
// src/utils/microtask_coalescer.ts
|
|
257
331
|
var MicrotaskCoalescer = class {
|
|
258
332
|
#run;
|
|
@@ -286,6 +360,85 @@ var MicrotaskCoalescer = class {
|
|
|
286
360
|
}
|
|
287
361
|
};
|
|
288
362
|
|
|
363
|
+
// src/utils/target_selector.ts
|
|
364
|
+
function targetSelector(identifier, name) {
|
|
365
|
+
return `[data-${identifier}-target~="${name}"]`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/utils/template_row.ts
|
|
369
|
+
function cloneTemplateRoot(template) {
|
|
370
|
+
const root = template.content.firstElementChild;
|
|
371
|
+
return root instanceof HTMLElement ? root.cloneNode(true) : null;
|
|
372
|
+
}
|
|
373
|
+
var TemplateRow = class {
|
|
374
|
+
#options;
|
|
375
|
+
#warned = false;
|
|
376
|
+
constructor(options) {
|
|
377
|
+
this.#options = options;
|
|
378
|
+
}
|
|
379
|
+
/** The attribute selector for one declared part, in this controller's namespace. */
|
|
380
|
+
selector(name) {
|
|
381
|
+
return targetSelector(this.#options.identifier, name);
|
|
382
|
+
}
|
|
383
|
+
/** Re-arms the once-per-connection diagnostic. */
|
|
384
|
+
connect() {
|
|
385
|
+
this.#warned = false;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Names one missing part on the console, at most once per connection, and
|
|
389
|
+
* returns `null` so a caller can hand it straight back.
|
|
390
|
+
*/
|
|
391
|
+
report(missing) {
|
|
392
|
+
return this.#say(`lacks ${missing}`);
|
|
393
|
+
}
|
|
394
|
+
/** Writes one diagnostic per connection, saying what the template got wrong. */
|
|
395
|
+
#say(problem) {
|
|
396
|
+
if (this.#warned) return null;
|
|
397
|
+
this.#warned = true;
|
|
398
|
+
const { identifier, outcome, noun } = this.#options;
|
|
399
|
+
console.warn(`Stimeo UI: "${identifier}" ${outcome} because its ${noun} ${problem}.`);
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Clones the row and resolves its parts, or names what the template got wrong
|
|
404
|
+
* and returns `null`. `values` fills the button's authored `aria-label`.
|
|
405
|
+
*/
|
|
406
|
+
instantiate(template, values) {
|
|
407
|
+
const { root: rootName, required, optional, button: buttonName } = this.#options;
|
|
408
|
+
const root = cloneTemplateRoot(template);
|
|
409
|
+
if (!root?.matches(this.selector(rootName))) {
|
|
410
|
+
return this.report(`${this.#article(rootName)} "${rootName}" root`);
|
|
411
|
+
}
|
|
412
|
+
const count = template.content.children.length;
|
|
413
|
+
if (count !== 1) {
|
|
414
|
+
return this.#say(`holds ${count} elements, and the row has to be its only one`);
|
|
415
|
+
}
|
|
416
|
+
const slots = {};
|
|
417
|
+
for (const name2 of required) {
|
|
418
|
+
const part = this.#resolve(root, name2);
|
|
419
|
+
if (!part) return this.report(`${this.#article(name2)} "${name2}" target`);
|
|
420
|
+
slots[name2] = part;
|
|
421
|
+
}
|
|
422
|
+
for (const name2 of optional ?? []) slots[name2] = this.#resolve(root, name2);
|
|
423
|
+
const named = this.#resolve(root, buttonName);
|
|
424
|
+
if (!(named instanceof HTMLButtonElement)) {
|
|
425
|
+
return this.report(`${this.#article(buttonName)} "${buttonName}" target <button>`);
|
|
426
|
+
}
|
|
427
|
+
const button = named;
|
|
428
|
+
const name = button.getAttribute("aria-label")?.trim() ?? "";
|
|
429
|
+
if (name === "") return this.report(`a non-empty aria-label on its "${buttonName}" target`);
|
|
430
|
+
button.setAttribute("aria-label", fillTemplate(name, values));
|
|
431
|
+
return { root, slots, button };
|
|
432
|
+
}
|
|
433
|
+
/** The row may be its own part; otherwise the first descendant carrying the target. */
|
|
434
|
+
#resolve(root, name) {
|
|
435
|
+
return matchingPart(root, this.selector(name));
|
|
436
|
+
}
|
|
437
|
+
#article(name) {
|
|
438
|
+
return /^[aeiou]/i.test(name) ? "an" : "a";
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
289
442
|
// src/controllers/tags_input_controller.ts
|
|
290
443
|
var TagsInputController = class extends Controller {
|
|
291
444
|
static targets = ["input", "tags", "tag", "tagTemplate", "label", "remove", "fields"];
|
|
@@ -294,6 +447,7 @@ var TagsInputController = class extends Controller {
|
|
|
294
447
|
max: { type: Number, default: 0 },
|
|
295
448
|
allowDuplicates: { type: Boolean, default: false },
|
|
296
449
|
name: { type: String, default: "tags[]" },
|
|
450
|
+
form: { type: String, default: "" },
|
|
297
451
|
announceText: { type: String, default: "" },
|
|
298
452
|
announceRemovedText: { type: String, default: "" }
|
|
299
453
|
};
|
|
@@ -301,14 +455,21 @@ var TagsInputController = class extends Controller {
|
|
|
301
455
|
static events = ["change", "reconcile", "reject"];
|
|
302
456
|
/** Last reconciled tag order, separating user edits from DOM/Turbo repair. */
|
|
303
457
|
#tagValues = [];
|
|
304
|
-
/**
|
|
305
|
-
#
|
|
458
|
+
/** Builds one chip from the authored template and owns its diagnostic. */
|
|
459
|
+
#rows = new TemplateRow({
|
|
460
|
+
identifier: this.identifier,
|
|
461
|
+
root: "tag",
|
|
462
|
+
required: ["label"],
|
|
463
|
+
button: "remove",
|
|
464
|
+
outcome: "added no tag",
|
|
465
|
+
noun: "chip template"
|
|
466
|
+
});
|
|
306
467
|
/** Collapses one target/Value mutation batch into one final-DOM repair pass. */
|
|
307
468
|
#reconcile = new MicrotaskCoalescer(() => this.#reconcileTags());
|
|
308
469
|
#chipRow = new ChipRow({
|
|
309
470
|
directionElement: this.element,
|
|
310
471
|
getItems: () => this.tagTargets,
|
|
311
|
-
getButton: (tag) => tag.
|
|
472
|
+
getButton: (tag) => matchingPart(tag, `button${this.#rows.selector("remove")}`),
|
|
312
473
|
onRemove: (index) => this.#removeAt(index),
|
|
313
474
|
focusAfterEnd: () => this.#focusInput()
|
|
314
475
|
});
|
|
@@ -316,7 +477,7 @@ var TagsInputController = class extends Controller {
|
|
|
316
477
|
#composition = new CompositionTracker();
|
|
317
478
|
/** Wires tag-list keyboard navigation and removal, and seeds the single Tab stop. */
|
|
318
479
|
connect() {
|
|
319
|
-
this.#
|
|
480
|
+
this.#rows.connect();
|
|
320
481
|
if (this.hasInputTarget) this.#composition.observe(this.inputTarget);
|
|
321
482
|
if (this.hasTagsTarget) this.#chipRow.connect(this.tagsTarget);
|
|
322
483
|
const tags = this.#values;
|
|
@@ -363,6 +524,10 @@ var TagsInputController = class extends Controller {
|
|
|
363
524
|
nameValueChanged() {
|
|
364
525
|
this.#reconcile.schedule();
|
|
365
526
|
}
|
|
527
|
+
/** Repoints submitted fields when the owning form changes at runtime. */
|
|
528
|
+
formValueChanged() {
|
|
529
|
+
this.#reconcile.schedule();
|
|
530
|
+
}
|
|
366
531
|
/** Recomputes the full hook when the cap changes at runtime. */
|
|
367
532
|
maxValueChanged() {
|
|
368
533
|
this.#reconcile.schedule();
|
|
@@ -393,7 +558,11 @@ var TagsInputController = class extends Controller {
|
|
|
393
558
|
}
|
|
394
559
|
}
|
|
395
560
|
}
|
|
396
|
-
/**
|
|
561
|
+
/**
|
|
562
|
+
* Validates and adds the current input value as a tag, then clears the input.
|
|
563
|
+
*
|
|
564
|
+
* @stimeoRuntimeOnly `max` and `allowDuplicates` decide whether this one entry is taken.
|
|
565
|
+
*/
|
|
397
566
|
#commitInput() {
|
|
398
567
|
const value = this.inputTarget.value.trim();
|
|
399
568
|
if (value === "") {
|
|
@@ -411,53 +580,31 @@ var TagsInputController = class extends Controller {
|
|
|
411
580
|
if (!this.#appendTag(value)) return;
|
|
412
581
|
this.inputTarget.value = "";
|
|
413
582
|
const tags = this.#values;
|
|
414
|
-
this.#syncState(tags);
|
|
583
|
+
this.#syncState(tags, true);
|
|
415
584
|
this.#tagValues = tags;
|
|
416
585
|
this.#announceTransition(true, value, tags.length);
|
|
417
586
|
this.dispatch("change", { detail: { tags } });
|
|
418
587
|
}
|
|
419
|
-
/** Builds one chip from the template and appends it to the tag list. */
|
|
420
|
-
#appendTag(value) {
|
|
421
|
-
if (!this.hasTagsTarget) return false;
|
|
422
|
-
if (!this.hasTagTemplateTarget) return this.#warnTemplate('a "tagTemplate" target');
|
|
423
|
-
const fragment = this.tagTemplateTarget.content.cloneNode(true);
|
|
424
|
-
const tag = fragment.querySelector('[data-stimeo--tags-input-target~="tag"]');
|
|
425
|
-
const label = fragment.querySelector('[data-stimeo--tags-input-target~="label"]');
|
|
426
|
-
const button = fragment.querySelector(
|
|
427
|
-
'button[data-stimeo--tags-input-target~="remove"]'
|
|
428
|
-
);
|
|
429
|
-
const removeName = button?.getAttribute("aria-label")?.trim() ?? "";
|
|
430
|
-
if (!tag) return this.#warnTemplate('a "tag" target');
|
|
431
|
-
if (!label) return this.#warnTemplate('a "label" target');
|
|
432
|
-
if (!button) return this.#warnTemplate('a "remove" target <button>');
|
|
433
|
-
if (removeName === "") {
|
|
434
|
-
return this.#warnTemplate('a non-empty aria-label on its "remove" target');
|
|
435
|
-
}
|
|
436
|
-
tag.dataset.value = value;
|
|
437
|
-
label.textContent = value;
|
|
438
|
-
button.setAttribute("aria-label", fillTemplate(removeName, { label: value, value }));
|
|
439
|
-
button.tabIndex = -1;
|
|
440
|
-
this.tagsTarget.appendChild(fragment);
|
|
441
|
-
return true;
|
|
442
|
-
}
|
|
443
588
|
/**
|
|
444
|
-
*
|
|
589
|
+
* Builds one chip from the template and appends it to the tag list.
|
|
445
590
|
*
|
|
446
|
-
*
|
|
447
|
-
* hidden fields, the announcement, or the events changes
|
|
448
|
-
*
|
|
449
|
-
* the Inspector cannot see statically (a name that renders empty from a
|
|
450
|
-
* missing translation, a server-rendered template) would have no diagnostic
|
|
451
|
-
* anywhere.
|
|
591
|
+
* A refused row leaves the commit a no-op — nothing about the input, the tag
|
|
592
|
+
* set, the hidden fields, the announcement, or the events changes — and the
|
|
593
|
+
* row reports why on the console once per connection.
|
|
452
594
|
*/
|
|
453
|
-
#
|
|
454
|
-
if (!this
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
);
|
|
595
|
+
#appendTag(value) {
|
|
596
|
+
if (!this.hasTagsTarget) return false;
|
|
597
|
+
if (!this.hasTagTemplateTarget) {
|
|
598
|
+
this.#rows.report('a "tagTemplate" target');
|
|
599
|
+
return false;
|
|
459
600
|
}
|
|
460
|
-
|
|
601
|
+
const row = this.#rows.instantiate(this.tagTemplateTarget, { label: value, value });
|
|
602
|
+
if (!row) return false;
|
|
603
|
+
row.root.dataset.value = value;
|
|
604
|
+
writeLabel(row.slots.label, value);
|
|
605
|
+
row.button.tabIndex = -1;
|
|
606
|
+
this.tagsTarget.appendChild(row.root);
|
|
607
|
+
return true;
|
|
461
608
|
}
|
|
462
609
|
/** Removes the tag at `index`, then applies the interaction-origin focus policy. */
|
|
463
610
|
#removeAt(index, focus = "neighbor") {
|
|
@@ -466,7 +613,7 @@ var TagsInputController = class extends Controller {
|
|
|
466
613
|
const value = tag.dataset.value ?? "";
|
|
467
614
|
tag.remove();
|
|
468
615
|
const tags = this.#values;
|
|
469
|
-
this.#syncState(tags);
|
|
616
|
+
this.#syncState(tags, true);
|
|
470
617
|
this.#tagValues = tags;
|
|
471
618
|
this.#announceTransition(false, value, tags.length);
|
|
472
619
|
this.dispatch("change", { detail: { tags } });
|
|
@@ -480,21 +627,20 @@ var TagsInputController = class extends Controller {
|
|
|
480
627
|
#focusInput() {
|
|
481
628
|
if (this.hasInputTarget) this.inputTarget.focus();
|
|
482
629
|
}
|
|
483
|
-
/**
|
|
484
|
-
|
|
630
|
+
/**
|
|
631
|
+
* Rebuilds the hidden form fields, the `full` flag, and the roving Tab stop.
|
|
632
|
+
*
|
|
633
|
+
* @stimeoRenderRoot
|
|
634
|
+
*/
|
|
635
|
+
#syncState(values, notify = false) {
|
|
485
636
|
if (this.hasFieldsTarget) {
|
|
486
|
-
this.
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
input.name = this.nameValue;
|
|
491
|
-
input.value = value;
|
|
492
|
-
return input;
|
|
493
|
-
})
|
|
494
|
-
);
|
|
637
|
+
const options = { name: this.nameValue, form: this.formValue };
|
|
638
|
+
if (writeFields(this.fieldsTarget, values, options) && notify) {
|
|
639
|
+
commitField(this.fieldsTarget);
|
|
640
|
+
}
|
|
495
641
|
}
|
|
496
642
|
const full = this.maxValue > 0 && values.length >= this.maxValue;
|
|
497
|
-
this.element.toggleAttribute(
|
|
643
|
+
this.element.toggleAttribute(`data-${this.identifier}-full`, full);
|
|
498
644
|
this.#chipRow.ensureTabStop();
|
|
499
645
|
}
|
|
500
646
|
/** Repairs derived state after DOM/Turbo changes and reports a changed tag order. */
|
|
@@ -507,7 +653,11 @@ var TagsInputController = class extends Controller {
|
|
|
507
653
|
this.#tagValues = tags;
|
|
508
654
|
if (changed) this.dispatch("reconcile", { detail: { tags } });
|
|
509
655
|
}
|
|
510
|
-
/**
|
|
656
|
+
/**
|
|
657
|
+
* Sends one localized tag transition through the page's shared announcer.
|
|
658
|
+
*
|
|
659
|
+
* @stimeoRuntimeOnly The texts word the one announcement of this change.
|
|
660
|
+
*/
|
|
511
661
|
#announceTransition(added, value, count) {
|
|
512
662
|
const template = added ? this.announceTextValue : this.announceRemovedTextValue;
|
|
513
663
|
announce(fillTemplate(template, { label: value, value, count }));
|