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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +178 -0
- data/README.md +120 -0
- data/dist/cable/index.js +63 -15
- data/dist/controllers/accordion_controller.js +98 -9
- data/dist/controllers/announcer_controller.js +8 -1
- data/dist/controllers/auto_submit_controller.js +43 -2
- data/dist/controllers/avatar_controller.js +1 -1
- data/dist/controllers/breadcrumb_controller.js +9 -8
- data/dist/controllers/bulk_select_controller.js +7 -6
- data/dist/controllers/calendar_controller.js +323 -123
- data/dist/controllers/carousel_controller.js +263 -38
- data/dist/controllers/character_counter_controller.js +40 -2
- data/dist/controllers/checkbox_controller.js +54 -10
- data/dist/controllers/clipboard_controller.js +63 -5
- data/dist/controllers/collapsible_controller.js +99 -14
- data/dist/controllers/color_picker_controller.js +80 -34
- data/dist/controllers/combobox_controller.js +106 -16
- data/dist/controllers/command_palette_controller.js +35 -3
- data/dist/controllers/conditional_fields_controller.js +56 -11
- data/dist/controllers/confirm_controller.js +3 -0
- data/dist/controllers/context_menu_controller.js +32 -12
- data/dist/controllers/countdown_controller.js +129 -26
- data/dist/controllers/currency_input_controller.js +205 -58
- data/dist/controllers/data_grid_controller.js +195 -29
- data/dist/controllers/date_range_picker_controller.js +139 -27
- data/dist/controllers/dialog_controller.js +35 -8
- data/dist/controllers/direct_upload_controller.js +22 -4
- data/dist/controllers/dirty_form_controller.js +14 -1
- data/dist/controllers/dismissible_controller.js +1 -0
- data/dist/controllers/drawer_controller.js +54 -19
- data/dist/controllers/dropdown_controller.js +36 -9
- data/dist/controllers/editable_controller.js +34 -0
- data/dist/controllers/file_dropzone_controller.js +144 -51
- data/dist/controllers/filter_controller.js +20 -6
- data/dist/controllers/flash_controller.js +305 -46
- data/dist/controllers/focus_controller.js +1 -0
- data/dist/controllers/form_field_controller.js +7 -5
- data/dist/controllers/form_validation_controller.js +19 -13
- data/dist/controllers/frame_loading_controller.js +16 -2
- data/dist/controllers/highlight_controller.js +19 -2
- data/dist/controllers/hover_card_controller.js +40 -14
- data/dist/controllers/idle_controller.js +90 -5
- data/dist/controllers/input_mask_controller.js +65 -9
- data/dist/controllers/intersection_controller.js +3 -0
- data/dist/controllers/lazy_frame_controller.js +11 -2
- data/dist/controllers/listbox_controller.js +203 -45
- data/dist/controllers/masonry_controller.js +0 -2
- data/dist/controllers/menu_controller.js +45 -16
- data/dist/controllers/menubar_controller.js +58 -24
- data/dist/controllers/meter_controller.js +9 -5
- data/dist/controllers/multi_select_controller.js +278 -104
- data/dist/controllers/navigation_menu_controller.js +48 -15
- data/dist/controllers/nested_form_controller.js +37 -8
- data/dist/controllers/network_status_controller.js +9 -1
- data/dist/controllers/number_input_controller.js +124 -21
- data/dist/controllers/optimistic_controller.js +14 -1
- data/dist/controllers/otp_controller.js +198 -55
- data/dist/controllers/overflow_indicator_controller.js +84 -13
- data/dist/controllers/overflow_menu_controller.js +112 -41
- data/dist/controllers/pagination_controller.js +74 -28
- data/dist/controllers/password_reveal_controller.js +59 -2
- data/dist/controllers/persist_controller.js +30 -8
- data/dist/controllers/pointer_drag_controller.js +131 -52
- data/dist/controllers/popover_controller.js +45 -11
- data/dist/controllers/portal_controller.js +6 -2
- data/dist/controllers/preview_guard_controller.js +16 -1
- data/dist/controllers/progress_controller.js +8 -4
- data/dist/controllers/radio_group_controller.js +42 -17
- data/dist/controllers/range_slider_controller.js +88 -42
- data/dist/controllers/rating_controller.js +39 -15
- data/dist/controllers/read_more_controller.js +69 -2
- data/dist/controllers/resizable_controller.js +82 -22
- data/dist/controllers/scroll_area_controller.js +5 -1
- data/dist/controllers/scroll_visibility_controller.js +0 -1
- data/dist/controllers/scrollspy_controller.js +6 -0
- data/dist/controllers/separator_controller.js +66 -37
- data/dist/controllers/sidebar_controller.js +77 -18
- data/dist/controllers/skeleton_controller.js +6 -1
- data/dist/controllers/slider_controller.js +82 -47
- data/dist/controllers/smart_sticky_header_controller.js +11 -1
- data/dist/controllers/sortable_controller.js +17 -2
- data/dist/controllers/spinner_controller.js +10 -2
- data/dist/controllers/step_indicator_controller.js +18 -17
- data/dist/controllers/stepper_controller.js +101 -19
- data/dist/controllers/stick_to_bottom_controller.js +75 -5
- data/dist/controllers/submit_once_controller.js +16 -3
- data/dist/controllers/switch_controller.js +101 -10
- data/dist/controllers/tabs_controller.js +21 -2
- data/dist/controllers/tags_input_controller.js +209 -59
- data/dist/controllers/theme_controller.js +64 -14
- data/dist/controllers/time_picker_controller.js +23 -8
- data/dist/controllers/toast_controller.js +337 -54
- data/dist/controllers/toggle_group_controller.js +159 -23
- data/dist/controllers/toolbar_controller.js +32 -0
- data/dist/controllers/tooltip_controller.js +39 -13
- data/dist/controllers/transition_controller.js +4 -0
- data/dist/controllers/tree_view_controller.js +169 -16
- data/dist/index.js +4588 -1535
- data/dist/positioning/index.js +2 -0
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +2 -2
|
@@ -8,36 +8,125 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
8
8
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
// src/utils/state_reason.ts
|
|
12
|
+
var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
|
|
13
|
+
var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
|
|
14
|
+
function stateReasonFor(event) {
|
|
15
|
+
if (!event) return "api";
|
|
16
|
+
if (FOCUS_EVENTS.has(event.type)) return "focus";
|
|
17
|
+
if (POINTER_EVENTS.has(event.type)) return "pointer";
|
|
18
|
+
return "user";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/utils/state_regions.ts
|
|
22
|
+
var StateRegions = class {
|
|
23
|
+
#whenTrue;
|
|
24
|
+
#whenFalse;
|
|
25
|
+
#taken = /* @__PURE__ */ new WeakSet();
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.#whenTrue = options.whenTrue;
|
|
28
|
+
this.#whenFalse = options.whenFalse ?? null;
|
|
29
|
+
}
|
|
30
|
+
/** Shows the regions inside `host` that belong to `isTrue` and hides the others. */
|
|
31
|
+
reflect(host, isTrue) {
|
|
32
|
+
const shown = this.#inside(host, this.#whenTrue());
|
|
33
|
+
if (!this.#whenFalse) {
|
|
34
|
+
for (const region of shown) this.#write(region, !isTrue);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const hiddenSide = this.#inside(host, this.#whenFalse());
|
|
38
|
+
if (shown.length === 0 || hiddenSide.length === 0) {
|
|
39
|
+
for (const region of shown) this.#give(region);
|
|
40
|
+
for (const region of hiddenSide) this.#give(region);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
for (const region of shown) this.#write(region, !isTrue);
|
|
44
|
+
for (const region of hiddenSide) this.#write(region, isTrue);
|
|
45
|
+
}
|
|
46
|
+
/** Writes `hidden` where it moves, noting which regions it takes out of view. */
|
|
47
|
+
#write(region, hidden) {
|
|
48
|
+
if (hidden) this.#taken.add(region);
|
|
49
|
+
else this.#taken.delete(region);
|
|
50
|
+
if (region.hidden !== hidden) region.hidden = hidden;
|
|
51
|
+
}
|
|
52
|
+
/** Returns a region this instance hid; one it never hid keeps what it carries. */
|
|
53
|
+
#give(region) {
|
|
54
|
+
if (this.#taken.delete(region)) region.hidden = false;
|
|
55
|
+
}
|
|
56
|
+
/** The declared regions that sit within `host`, which may be the host itself. */
|
|
57
|
+
#inside(host, regions) {
|
|
58
|
+
return regions.filter((region) => host.contains(region));
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
11
62
|
// src/controllers/accordion_controller.ts
|
|
12
63
|
var AccordionController = class extends Controller {
|
|
13
|
-
static targets = ["trigger", "panel"];
|
|
64
|
+
static targets = ["trigger", "panel", "expandedLabel", "collapsedLabel"];
|
|
14
65
|
static actions = ["collapseAll", "expandAll", "onKeydown", "toggle"];
|
|
66
|
+
static events = ["close", "open"];
|
|
67
|
+
/** Owns `hidden` on the label pair a header declares, narrowed to that header. */
|
|
68
|
+
#labels = new StateRegions({
|
|
69
|
+
whenTrue: () => this.expandedLabelTargets,
|
|
70
|
+
whenFalse: () => this.collapsedLabelTargets
|
|
71
|
+
});
|
|
72
|
+
/** Settles the label pair of a header as it joins the group. */
|
|
73
|
+
triggerTargetConnected(trigger) {
|
|
74
|
+
this.#reflectLabels(trigger);
|
|
75
|
+
}
|
|
76
|
+
/** Settles the pair of the header an arriving expanded half belongs to. */
|
|
77
|
+
expandedLabelTargetConnected(label) {
|
|
78
|
+
this.#settleLabelHost(label);
|
|
79
|
+
}
|
|
80
|
+
/** Settles the pair of the header an arriving collapsed half belongs to. */
|
|
81
|
+
collapsedLabelTargetConnected(label) {
|
|
82
|
+
this.#settleLabelHost(label);
|
|
83
|
+
}
|
|
84
|
+
/** Reflects the pair of the header a label half sits in, where a header holds it. */
|
|
85
|
+
#settleLabelHost(label) {
|
|
86
|
+
const trigger = this.triggerTargets.find((candidate) => candidate.contains(label));
|
|
87
|
+
if (trigger) this.#reflectLabels(trigger);
|
|
88
|
+
}
|
|
15
89
|
/** Toggles the panel controlled by the activated header. */
|
|
16
90
|
toggle(event) {
|
|
17
91
|
const trigger = event.currentTarget;
|
|
18
92
|
const panel = this.#panelFor(trigger);
|
|
19
93
|
if (!panel) return;
|
|
20
|
-
this.#setExpanded(
|
|
94
|
+
this.#setExpanded(
|
|
95
|
+
trigger,
|
|
96
|
+
panel,
|
|
97
|
+
trigger.getAttribute("aria-expanded") !== "true",
|
|
98
|
+
stateReasonFor(event)
|
|
99
|
+
);
|
|
21
100
|
}
|
|
22
101
|
/** Opens every panel. Bound via `data-action` on an "expand all" control. */
|
|
23
|
-
expandAll() {
|
|
24
|
-
this.#setAll(true);
|
|
102
|
+
expandAll(event) {
|
|
103
|
+
this.#setAll(true, stateReasonFor(event));
|
|
25
104
|
}
|
|
26
105
|
/** Closes every panel. Bound via `data-action` on a "collapse all" control. */
|
|
27
|
-
collapseAll() {
|
|
28
|
-
this.#setAll(false);
|
|
106
|
+
collapseAll(event) {
|
|
107
|
+
this.#setAll(false, stateReasonFor(event));
|
|
29
108
|
}
|
|
30
109
|
/** Drives every header/panel pair to the same expanded state. */
|
|
31
|
-
#setAll(open) {
|
|
110
|
+
#setAll(open, reason) {
|
|
32
111
|
for (const trigger of this.triggerTargets) {
|
|
33
112
|
const panel = this.#panelFor(trigger);
|
|
34
|
-
if (panel) this.#setExpanded(trigger, panel, open);
|
|
113
|
+
if (panel) this.#setExpanded(trigger, panel, open, reason);
|
|
35
114
|
}
|
|
36
115
|
}
|
|
37
116
|
/** Reflects one header/panel pair's state through `aria-expanded` + `hidden`. */
|
|
38
|
-
#setExpanded(trigger, panel, open) {
|
|
117
|
+
#setExpanded(trigger, panel, open, reason) {
|
|
118
|
+
const was = trigger.getAttribute("aria-expanded") === "true";
|
|
39
119
|
trigger.setAttribute("aria-expanded", open ? "true" : "false");
|
|
40
120
|
panel.hidden = !open;
|
|
121
|
+
this.#labels.reflect(trigger, open);
|
|
122
|
+
if (was === open) return;
|
|
123
|
+
const detail = { reason, index: this.triggerTargets.indexOf(trigger), trigger, panel };
|
|
124
|
+
if (open) this.dispatch("open", { detail, cancelable: false });
|
|
125
|
+
else this.dispatch("close", { detail, cancelable: false });
|
|
126
|
+
}
|
|
127
|
+
/** Shows the half of a header's label pair that belongs to its `aria-expanded`. */
|
|
128
|
+
#reflectLabels(trigger) {
|
|
129
|
+
this.#labels.reflect(trigger, trigger.getAttribute("aria-expanded") === "true");
|
|
41
130
|
}
|
|
42
131
|
/**
|
|
43
132
|
* Moves focus between headers per the APG keyboard model, skipping any header
|
|
@@ -346,6 +346,9 @@ var AnnouncerController = class extends Controller {
|
|
|
346
346
|
* region (it has to be in the accessibility tree before the text arrives) and
|
|
347
347
|
* emptying a region that already holds this exact text (an unchanged node is not
|
|
348
348
|
* re-read, so `dedupeReannounce` clears first and writes on the following pass).
|
|
349
|
+
*
|
|
350
|
+
* @stimeoRuntimeOnly `dedupeReannounce` decides whether one queued message is spoken again; the
|
|
351
|
+
* region's text is the message itself.
|
|
349
352
|
*/
|
|
350
353
|
#drain(level) {
|
|
351
354
|
const queue = this.#queues.get(level);
|
|
@@ -368,7 +371,11 @@ var AnnouncerController = class extends Controller {
|
|
|
368
371
|
this.#scheduleClear(region, message);
|
|
369
372
|
if (queue.length > 0) this.#scheduleDrain(level);
|
|
370
373
|
}
|
|
371
|
-
/**
|
|
374
|
+
/**
|
|
375
|
+
* Clears the region after `clearAfter` ms, unless a newer message replaced it.
|
|
376
|
+
*
|
|
377
|
+
* @stimeoRuntimeOnly `clearAfter` is the delay of the one clearing timer this call arms.
|
|
378
|
+
*/
|
|
372
379
|
#scheduleClear(region, message) {
|
|
373
380
|
if (this.clearAfterValue <= 0) return;
|
|
374
381
|
this.#regionTimers.set(
|
|
@@ -43,11 +43,19 @@ var BeforeCacheReset = class _BeforeCacheReset {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
// src/utils/composition_tracker.ts
|
|
46
|
+
var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
47
|
+
"insertCompositionText",
|
|
48
|
+
"insertFromComposition",
|
|
49
|
+
"deleteCompositionText",
|
|
50
|
+
"deleteByComposition"
|
|
51
|
+
]);
|
|
46
52
|
var CompositionTracker = class {
|
|
47
53
|
#observedTargets = /* @__PURE__ */ new Set();
|
|
48
54
|
#activeTargets = /* @__PURE__ */ new Set();
|
|
49
55
|
#onStart;
|
|
50
56
|
#onEnd;
|
|
57
|
+
/** The field whose confirming `input` is still owed, while the window is open. */
|
|
58
|
+
#confirmedTarget = null;
|
|
51
59
|
constructor(options = {}) {
|
|
52
60
|
this.#onStart = options.onStart;
|
|
53
61
|
this.#onEnd = options.onEnd;
|
|
@@ -57,6 +65,7 @@ var CompositionTracker = class {
|
|
|
57
65
|
if (this.#observedTargets.has(target)) return;
|
|
58
66
|
target.addEventListener("compositionstart", this.#handleStart);
|
|
59
67
|
target.addEventListener("compositionend", this.#handleEnd);
|
|
68
|
+
target.addEventListener("keydown", this.#handleKeydown);
|
|
60
69
|
this.#observedTargets.add(target);
|
|
61
70
|
}
|
|
62
71
|
/** Stops tracking one target and clears any active composition it owned. */
|
|
@@ -64,29 +73,52 @@ var CompositionTracker = class {
|
|
|
64
73
|
if (!this.#observedTargets.delete(target)) return;
|
|
65
74
|
target.removeEventListener("compositionstart", this.#handleStart);
|
|
66
75
|
target.removeEventListener("compositionend", this.#handleEnd);
|
|
76
|
+
target.removeEventListener("keydown", this.#handleKeydown);
|
|
67
77
|
this.#activeTargets.delete(target);
|
|
78
|
+
if (this.#confirmedTarget === target) this.#confirmedTarget = null;
|
|
68
79
|
}
|
|
69
80
|
/** Releases every listener and clears state so reconnect starts cleanly. */
|
|
70
81
|
disconnect() {
|
|
71
82
|
for (const target of this.#observedTargets) {
|
|
72
83
|
target.removeEventListener("compositionstart", this.#handleStart);
|
|
73
84
|
target.removeEventListener("compositionend", this.#handleEnd);
|
|
85
|
+
target.removeEventListener("keydown", this.#handleKeydown);
|
|
74
86
|
}
|
|
75
87
|
this.#observedTargets.clear();
|
|
76
88
|
this.#activeTargets.clear();
|
|
89
|
+
this.#confirmedTarget = null;
|
|
77
90
|
}
|
|
78
91
|
/** True when lifecycle tracking or the current event reports composition. */
|
|
79
92
|
isComposing(event) {
|
|
80
93
|
return this.#activeTargets.size > 0 || event?.isComposing === true;
|
|
81
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether `event` is the `input` echoing the composition just confirmed.
|
|
97
|
+
*
|
|
98
|
+
* Asking closes the window either way, so one confirmation is folded at most
|
|
99
|
+
* once and a consumer asks once per `input`.
|
|
100
|
+
*/
|
|
101
|
+
consumesConfirmedInput(event) {
|
|
102
|
+
const confirmed = this.#confirmedTarget;
|
|
103
|
+
this.#confirmedTarget = null;
|
|
104
|
+
if (confirmed === null || confirmed !== event.target) return false;
|
|
105
|
+
const inputType = event.inputType;
|
|
106
|
+
return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);
|
|
107
|
+
}
|
|
82
108
|
#handleStart = (event) => {
|
|
109
|
+
this.#confirmedTarget = null;
|
|
83
110
|
if (event.currentTarget) this.#activeTargets.add(event.currentTarget);
|
|
84
111
|
this.#onStart?.(event);
|
|
85
112
|
};
|
|
86
113
|
#handleEnd = (event) => {
|
|
87
114
|
if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);
|
|
115
|
+
this.#confirmedTarget = event.target;
|
|
88
116
|
this.#onEnd?.(event);
|
|
89
117
|
};
|
|
118
|
+
/** A key on an observed field opens an edit of its own, so no echo is owed. */
|
|
119
|
+
#handleKeydown = () => {
|
|
120
|
+
this.#confirmedTarget = null;
|
|
121
|
+
};
|
|
90
122
|
};
|
|
91
123
|
|
|
92
124
|
// src/utils/listener_set.ts
|
|
@@ -187,7 +219,12 @@ var AutoSubmitController = class extends Controller {
|
|
|
187
219
|
#boundForm = null;
|
|
188
220
|
/** Rewinds the transient state hooks just before Turbo snapshots the page. */
|
|
189
221
|
#beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
|
|
190
|
-
/**
|
|
222
|
+
/**
|
|
223
|
+
* Clears `aria-busy` and emits completion once Turbo finishes the submit.
|
|
224
|
+
*
|
|
225
|
+
* @stimeoRuntimeOnly `message` and `announce` shape the event and the announcement of one
|
|
226
|
+
* finished submit; the busy flag it clears does not depend on them.
|
|
227
|
+
*/
|
|
191
228
|
#onSubmitEnd = () => {
|
|
192
229
|
this.#boundForm?.removeAttribute("aria-busy");
|
|
193
230
|
const message = this.messageValue;
|
|
@@ -229,7 +266,11 @@ var AutoSubmitController = class extends Controller {
|
|
|
229
266
|
if (event.type === "input" && this.#composition.isComposing(event)) return;
|
|
230
267
|
this.#schedule(event.target ?? null);
|
|
231
268
|
}
|
|
232
|
-
/**
|
|
269
|
+
/**
|
|
270
|
+
* Schedules (and coalesces) the debounced submit for the given trigger.
|
|
271
|
+
*
|
|
272
|
+
* @stimeoRuntimeOnly `debounce` is the delay of the one submit timer this call arms.
|
|
273
|
+
*/
|
|
233
274
|
#schedule(trigger) {
|
|
234
275
|
const form = this.#boundForm;
|
|
235
276
|
if (!form) return;
|
|
@@ -224,7 +224,7 @@ var AvatarController = class extends Controller {
|
|
|
224
224
|
}
|
|
225
225
|
/** Applies Value precedence and returns the effective raw `src` attribute. */
|
|
226
226
|
#applySource(image) {
|
|
227
|
-
if (!this.element.hasAttribute(
|
|
227
|
+
if (!this.element.hasAttribute(`data-${this.identifier}-src-value`)) {
|
|
228
228
|
this.#src.return(image);
|
|
229
229
|
return image.getAttribute("src");
|
|
230
230
|
}
|
|
@@ -187,21 +187,24 @@ var BreadcrumbController = class extends Controller {
|
|
|
187
187
|
this.#resync();
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
|
-
* Re-measures when
|
|
191
|
-
* precondition for collapsing at all, so
|
|
192
|
-
* and items get: without
|
|
193
|
-
* set would only take effect at the next resize or
|
|
194
|
-
* never come.
|
|
190
|
+
* Re-measures when an `ellipsis` target arrives. The `ellipsis` and `trigger`
|
|
191
|
+
* targets form the disclosure set, a precondition for collapsing at all, so they
|
|
192
|
+
* need the same watching the list and items get: without their callbacks a swap
|
|
193
|
+
* that breaks or completes the set would only take effect at the next resize or
|
|
194
|
+
* list mutation, which may never come.
|
|
195
195
|
*/
|
|
196
196
|
ellipsisTargetConnected() {
|
|
197
197
|
this.#resync();
|
|
198
198
|
}
|
|
199
|
+
/** Re-measures when an `ellipsis` target leaves the disclosure set. */
|
|
199
200
|
ellipsisTargetDisconnected() {
|
|
200
201
|
this.#resync();
|
|
201
202
|
}
|
|
203
|
+
/** Re-measures when a `trigger` target joins the disclosure set. */
|
|
202
204
|
triggerTargetConnected() {
|
|
203
205
|
this.#resync();
|
|
204
206
|
}
|
|
207
|
+
/** Re-measures when a `trigger` target leaves the disclosure set. */
|
|
205
208
|
triggerTargetDisconnected() {
|
|
206
209
|
this.#resync();
|
|
207
210
|
}
|
|
@@ -210,7 +213,7 @@ var BreadcrumbController = class extends Controller {
|
|
|
210
213
|
*
|
|
211
214
|
* The marker is the source of truth for what may be collapsed, so an element
|
|
212
215
|
* that loses it while the controller is live is an always-visible item again —
|
|
213
|
-
* and
|
|
216
|
+
* and rendering only walks the *current* targets, so nothing else would ever
|
|
214
217
|
* clear the `hidden` this controller put there.
|
|
215
218
|
*
|
|
216
219
|
* The `#connected` guard is load-bearing, not defensive. Stimulus fires this
|
|
@@ -315,8 +318,6 @@ var BreadcrumbController = class extends Controller {
|
|
|
315
318
|
}
|
|
316
319
|
/**
|
|
317
320
|
* Applies the collapsed/expanded state to the items, ellipsis, and trigger.
|
|
318
|
-
*
|
|
319
|
-
* @stimeoRenderRoot
|
|
320
321
|
*/
|
|
321
322
|
#render() {
|
|
322
323
|
const collapsed = this.#overflowing && !this.#expanded;
|
|
@@ -108,12 +108,8 @@ var BulkSelectController = class extends Controller {
|
|
|
108
108
|
allTargetDisconnected() {
|
|
109
109
|
this.#reconcile.schedule();
|
|
110
110
|
}
|
|
111
|
-
/** Repaints the count for a total that changed at runtime
|
|
111
|
+
/** Repaints the count for a total that changed at runtime. */
|
|
112
112
|
totalCountValueChanged() {
|
|
113
|
-
if (!Number.isFinite(this.totalCountValue)) {
|
|
114
|
-
this.totalCountValue = 0;
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
113
|
this.#reconcile.schedule();
|
|
118
114
|
}
|
|
119
115
|
/** Repaints so wording changed at runtime is used by the next announcement. */
|
|
@@ -175,6 +171,11 @@ var BulkSelectController = class extends Controller {
|
|
|
175
171
|
#announce(detail) {
|
|
176
172
|
announce(fillTemplate(this.announceTextValue, { count: detail.count }));
|
|
177
173
|
}
|
|
174
|
+
/** The declared `totalCount`, or the default `0` in place of a non-finite one. */
|
|
175
|
+
get #totalCount() {
|
|
176
|
+
const declared = this.totalCountValue;
|
|
177
|
+
return Number.isFinite(declared) ? declared : 0;
|
|
178
|
+
}
|
|
178
179
|
/**
|
|
179
180
|
* Recomputes the count, the select-all checked/indeterminate state, and the bar
|
|
180
181
|
* visibility from the current DOM. Returns the figures when the emitted count or
|
|
@@ -191,7 +192,7 @@ var BulkSelectController = class extends Controller {
|
|
|
191
192
|
this.allTarget.checked = total > 0 && checked === total;
|
|
192
193
|
this.allTarget.indeterminate = checked > 0 && checked < total;
|
|
193
194
|
}
|
|
194
|
-
const count = allPages ? this
|
|
195
|
+
const count = allPages ? this.#totalCount : checked;
|
|
195
196
|
const show = allPages || checked > 0;
|
|
196
197
|
if (this.hasBarTarget) {
|
|
197
198
|
if (!show && this.hasAllTarget && this.barTarget.contains(document.activeElement)) {
|