stimeo-ui 0.15.0 → 0.17.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 +209 -0
- data/README.md +128 -1
- data/dist/cable/index.js +392 -417
- data/dist/controllers/accordion_controller.js +228 -28
- data/dist/controllers/alert_dialog_controller.js +862 -221
- data/dist/controllers/announcer_controller.js +135 -191
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +295 -110
- data/dist/controllers/avatar_controller.js +172 -106
- data/dist/controllers/breadcrumb_controller.js +0 -129
- data/dist/controllers/bulk_select_controller.js +264 -53
- data/dist/controllers/calendar_controller.js +346 -180
- data/dist/controllers/carousel_controller.js +587 -300
- data/dist/controllers/character_counter_controller.js +271 -143
- data/dist/controllers/checkbox_controller.js +77 -75
- data/dist/controllers/clipboard_controller.js +187 -108
- data/dist/controllers/collapsible_controller.js +374 -108
- data/dist/controllers/color_picker_controller.js +183 -127
- data/dist/controllers/combobox_controller.js +426 -109
- data/dist/controllers/command_palette_controller.js +994 -350
- data/dist/controllers/conditional_fields_controller.js +212 -125
- data/dist/controllers/confirm_controller.js +939 -245
- data/dist/controllers/context_menu_controller.js +275 -127
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +235 -97
- data/dist/controllers/currency_input_controller.js +241 -118
- data/dist/controllers/data_grid_controller.js +229 -135
- data/dist/controllers/date_range_picker_controller.js +359 -165
- data/dist/controllers/dialog_controller.js +887 -225
- data/dist/controllers/direct_upload_controller.js +80 -142
- data/dist/controllers/dirty_form_controller.js +26 -47
- data/dist/controllers/dismissible_controller.js +175 -20
- data/dist/controllers/drawer_controller.js +963 -336
- data/dist/controllers/dropdown_controller.js +342 -85
- data/dist/controllers/editable_controller.js +182 -58
- data/dist/controllers/empty_state_controller.js +67 -53
- data/dist/controllers/file_dropzone_controller.js +426 -229
- data/dist/controllers/filter_controller.js +78 -36
- data/dist/controllers/flash_controller.js +328 -211
- data/dist/controllers/focus_controller.js +654 -239
- data/dist/controllers/form_field_controller.js +153 -136
- data/dist/controllers/form_validation_controller.js +29 -96
- data/dist/controllers/frame_loading_controller.js +263 -198
- data/dist/controllers/highlight_controller.js +119 -70
- data/dist/controllers/hover_card_controller.js +335 -118
- data/dist/controllers/idle_controller.js +316 -65
- data/dist/controllers/input_mask_controller.js +116 -61
- data/dist/controllers/intersection_controller.js +147 -103
- data/dist/controllers/lazy_frame_controller.js +9 -56
- data/dist/controllers/listbox_controller.js +413 -153
- data/dist/controllers/local_time_controller.js +54 -64
- data/dist/controllers/masonry_controller.js +70 -95
- data/dist/controllers/menu_controller.js +254 -167
- data/dist/controllers/menubar_controller.js +206 -331
- data/dist/controllers/meter_controller.js +159 -71
- data/dist/controllers/multi_select_controller.js +797 -388
- data/dist/controllers/navigation_menu_controller.js +156 -231
- data/dist/controllers/nested_form_controller.js +373 -174
- data/dist/controllers/network_status_controller.js +241 -45
- data/dist/controllers/number_input_controller.js +387 -227
- data/dist/controllers/optimistic_controller.js +28 -75
- data/dist/controllers/otp_controller.js +344 -196
- data/dist/controllers/overflow_indicator_controller.js +167 -93
- data/dist/controllers/overflow_menu_controller.js +408 -277
- data/dist/controllers/pagination_controller.js +342 -120
- data/dist/controllers/password_reveal_controller.js +424 -99
- data/dist/controllers/password_strength_controller.js +99 -153
- data/dist/controllers/persist_controller.js +252 -96
- data/dist/controllers/pointer_drag_controller.js +263 -164
- data/dist/controllers/popover_controller.js +267 -94
- data/dist/controllers/portal_controller.js +209 -72
- data/dist/controllers/preview_guard_controller.js +243 -112
- data/dist/controllers/progress_controller.js +132 -59
- data/dist/controllers/radio_group_controller.js +138 -133
- data/dist/controllers/range_slider_controller.js +245 -112
- data/dist/controllers/rating_controller.js +429 -194
- data/dist/controllers/read_more_controller.js +185 -47
- data/dist/controllers/reading_progress_controller.js +147 -135
- data/dist/controllers/relative_time_controller.js +145 -110
- data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
- data/dist/controllers/resizable_controller.js +294 -118
- data/dist/controllers/roving_controller.js +39 -84
- data/dist/controllers/scroll_area_controller.js +428 -221
- data/dist/controllers/scroll_restore_controller.js +0 -53
- data/dist/controllers/scroll_visibility_controller.js +395 -146
- data/dist/controllers/scrollspy_controller.js +181 -236
- data/dist/controllers/separator_controller.js +288 -132
- data/dist/controllers/sidebar_controller.js +1071 -375
- data/dist/controllers/skeleton_controller.js +248 -92
- data/dist/controllers/slider_controller.js +211 -96
- data/dist/controllers/smart_sticky_header_controller.js +163 -54
- data/dist/controllers/sortable_controller.js +13 -110
- data/dist/controllers/spinner_controller.js +277 -161
- data/dist/controllers/step_indicator_controller.js +107 -53
- data/dist/controllers/stepper_controller.js +171 -48
- data/dist/controllers/stick_to_bottom_controller.js +310 -116
- data/dist/controllers/sticky_observer_controller.js +214 -49
- data/dist/controllers/submit_once_controller.js +294 -192
- data/dist/controllers/switch_controller.js +107 -43
- data/dist/controllers/tabs_controller.js +50 -25
- data/dist/controllers/tags_input_controller.js +290 -149
- data/dist/controllers/textarea_autosize_controller.js +71 -58
- data/dist/controllers/theme_controller.js +148 -80
- data/dist/controllers/time_picker_controller.js +162 -81
- data/dist/controllers/toast_controller.js +365 -193
- data/dist/controllers/toggle_group_controller.js +194 -99
- data/dist/controllers/toolbar_controller.js +92 -90
- data/dist/controllers/tooltip_controller.js +185 -125
- data/dist/controllers/transition_controller.js +123 -115
- data/dist/controllers/tree_view_controller.js +248 -290
- data/dist/index.js +8649 -8572
- data/dist/positioning/index.js +148 -45
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +3 -3
|
@@ -1,44 +1,164 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
|
|
4
|
+
var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
|
|
5
|
+
function stateReasonFor(event) {
|
|
6
|
+
if (!event) return "api";
|
|
7
|
+
if (FOCUS_EVENTS.has(event.type)) return "focus";
|
|
8
|
+
if (POINTER_EVENTS.has(event.type)) return "pointer";
|
|
9
|
+
return "user";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function actionSource(source) {
|
|
13
|
+
if (source instanceof HTMLElement) {
|
|
14
|
+
return { event: null, host: source, origin: source, reason: "api" };
|
|
15
|
+
}
|
|
16
|
+
const event = source ?? null;
|
|
17
|
+
return {
|
|
18
|
+
event,
|
|
19
|
+
host: event?.currentTarget instanceof Element ? event.currentTarget : null,
|
|
20
|
+
origin: event?.target instanceof Element ? event.target : null,
|
|
21
|
+
reason: stateReasonFor(event)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function ownerIndex(candidates, node) {
|
|
26
|
+
if (!(node instanceof Node)) return -1;
|
|
27
|
+
return candidates.findIndex((candidate) => candidate.contains(node));
|
|
28
|
+
}
|
|
29
|
+
function ownerOf(candidates, node) {
|
|
30
|
+
return candidates[ownerIndex(candidates, node)] ?? null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
var ListenerSet = class {
|
|
34
|
+
#abort = new AbortController();
|
|
35
|
+
add(target, type, handler, options) {
|
|
36
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
37
|
+
}
|
|
38
|
+
dispose() {
|
|
39
|
+
this.#abort.abort();
|
|
40
|
+
this.#abort = new AbortController();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
var MicrotaskCoalescer = class {
|
|
45
|
+
#run;
|
|
46
|
+
#queued = false;
|
|
47
|
+
#active = false;
|
|
48
|
+
#generation = 0;
|
|
49
|
+
constructor(run) {
|
|
50
|
+
this.#run = run;
|
|
51
|
+
}
|
|
52
|
+
activate() {
|
|
53
|
+
this.#active = true;
|
|
54
|
+
}
|
|
55
|
+
cancel() {
|
|
56
|
+
this.#active = false;
|
|
57
|
+
this.#queued = false;
|
|
58
|
+
this.#generation += 1;
|
|
59
|
+
}
|
|
60
|
+
schedule() {
|
|
61
|
+
if (!this.#active || this.#queued) return;
|
|
62
|
+
this.#queued = true;
|
|
63
|
+
const generation = this.#generation;
|
|
64
|
+
queueMicrotask(() => {
|
|
65
|
+
if (generation !== this.#generation || !this.#queued || !this.#active) return;
|
|
66
|
+
this.#queued = false;
|
|
67
|
+
this.#run();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
var MorphRenderWatcher = class {
|
|
73
|
+
#listeners = new ListenerSet();
|
|
74
|
+
#pass;
|
|
75
|
+
#element = null;
|
|
76
|
+
#onMorph = () => this.#pass.schedule();
|
|
77
|
+
constructor(run) {
|
|
78
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
79
|
+
}
|
|
80
|
+
observe(element) {
|
|
81
|
+
if (this.#element === element) return;
|
|
82
|
+
this.disconnect();
|
|
83
|
+
this.#element = element;
|
|
84
|
+
this.#pass.activate();
|
|
85
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
86
|
+
}
|
|
87
|
+
schedule() {
|
|
88
|
+
this.#pass.schedule();
|
|
89
|
+
}
|
|
90
|
+
disconnect() {
|
|
91
|
+
this.#listeners.dispose();
|
|
92
|
+
this.#pass.cancel();
|
|
93
|
+
this.#element = null;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
98
|
+
|
|
99
|
+
var NUMBER_BOUNDS = {
|
|
100
|
+
finite: { finite: true },
|
|
101
|
+
timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
|
|
102
|
+
function matchesNumberBounds(value, bounds) {
|
|
103
|
+
if (!Number.isFinite(value)) {
|
|
104
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
105
|
+
if (direction === null) return false;
|
|
106
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
107
|
+
}
|
|
108
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
109
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
110
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
111
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
112
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function readNumber(raw, fallback, bounds) {
|
|
117
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
var NumberValueReader = class {
|
|
121
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
122
|
+
read(owner, name, raw, fallback, bounds) {
|
|
123
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
124
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
125
|
+
this.#lastRejected.delete(name);
|
|
126
|
+
return resolved;
|
|
127
|
+
}
|
|
128
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
129
|
+
const literal = owner.element.getAttribute(attribute);
|
|
130
|
+
if (literal === null) {
|
|
131
|
+
this.#lastRejected.delete(name);
|
|
132
|
+
return resolved;
|
|
133
|
+
}
|
|
134
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
135
|
+
this.#lastRejected.set(name, literal);
|
|
136
|
+
console.warn(
|
|
137
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return resolved;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
4
143
|
|
|
5
|
-
// src/utils/safe_timeout.ts
|
|
6
144
|
var TimerRegistry = class {
|
|
7
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
8
145
|
ids = /* @__PURE__ */ new Set();
|
|
9
|
-
/**
|
|
10
|
-
* Cancels a single tracked timer.
|
|
11
|
-
*
|
|
12
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
13
|
-
* registry), so callers can clear defensively without guarding.
|
|
14
|
-
*/
|
|
15
146
|
clear(id) {
|
|
16
147
|
if (this.ids.delete(id)) {
|
|
17
148
|
this.cancel(id);
|
|
18
149
|
}
|
|
19
150
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
22
|
-
* to guarantee no timer outlives the element.
|
|
23
|
-
*/
|
|
24
151
|
clearAll() {
|
|
25
152
|
for (const id of this.ids) {
|
|
26
153
|
this.cancel(id);
|
|
27
154
|
}
|
|
28
155
|
this.ids.clear();
|
|
29
156
|
}
|
|
30
|
-
/** Number of timers currently tracked (pending). */
|
|
31
157
|
get size() {
|
|
32
158
|
return this.ids.size;
|
|
33
159
|
}
|
|
34
160
|
};
|
|
35
161
|
var SafeTimeout = class extends TimerRegistry {
|
|
36
|
-
/**
|
|
37
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
38
|
-
*
|
|
39
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
40
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
41
|
-
*/
|
|
42
162
|
set(callback, delay) {
|
|
43
163
|
const id = this.schedule(() => {
|
|
44
164
|
this.ids.delete(id);
|
|
@@ -55,16 +175,9 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
55
175
|
}
|
|
56
176
|
};
|
|
57
177
|
|
|
58
|
-
// src/utils/keyed_timers.ts
|
|
59
178
|
var KeyedTimers = class {
|
|
60
179
|
#timers = new SafeTimeout();
|
|
61
|
-
/** The pending timer of each key; an entry lives exactly as long as its timer. */
|
|
62
180
|
#pending = /* @__PURE__ */ new Map();
|
|
63
|
-
/**
|
|
64
|
-
* Arms `callback` after `delay` ms for `key`, cancelling the timer `key` had
|
|
65
|
-
* pending. The entry is dropped before the callback runs, so the callback sees
|
|
66
|
-
* the key unarmed and may arm it again for the next round.
|
|
67
|
-
*/
|
|
68
181
|
set(key, callback, delay) {
|
|
69
182
|
this.clear(key);
|
|
70
183
|
const id = this.#timers.set(() => {
|
|
@@ -73,104 +186,89 @@ var KeyedTimers = class {
|
|
|
73
186
|
}, delay);
|
|
74
187
|
this.#pending.set(key, id);
|
|
75
188
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Cancels `key`'s pending timer, if it has one.
|
|
78
|
-
*
|
|
79
|
-
* A timer id is a positive integer, so `-1` stands for "nothing pending" and
|
|
80
|
-
* the registry ignores an id it does not own — the unarmed case needs no
|
|
81
|
-
* branch of its own, and no other key's timer can be reached from here.
|
|
82
|
-
*/
|
|
83
189
|
clear(key) {
|
|
84
190
|
this.#timers.clear(this.#pending.get(key) ?? -1);
|
|
85
191
|
this.#pending.delete(key);
|
|
86
192
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Cancels every pending timer and forgets every key. Call this from a
|
|
89
|
-
* controller's `disconnect()` so no timer, and no entry, outlives the element.
|
|
90
|
-
*/
|
|
91
193
|
clearAll() {
|
|
92
194
|
this.#timers.clearAll();
|
|
93
195
|
this.#pending.clear();
|
|
94
196
|
}
|
|
95
|
-
/** Whether `key` has a timer pending. */
|
|
96
197
|
has(key) {
|
|
97
198
|
return this.#pending.has(key);
|
|
98
199
|
}
|
|
99
200
|
};
|
|
100
201
|
|
|
101
|
-
// src/utils/pausable_timers.ts
|
|
102
202
|
var PausableTimers = class {
|
|
103
203
|
#timers = new KeyedTimers();
|
|
104
|
-
/** Every key armed or held; an entry goes as its timer fires, or with the key. */
|
|
105
204
|
#entries = /* @__PURE__ */ new Map();
|
|
106
|
-
/**
|
|
107
|
-
* Arms `callback` after `delay` ms for `key`, replacing whatever `key` had.
|
|
108
|
-
* A held key stays held and banks `delay` for its resume.
|
|
109
|
-
*/
|
|
110
205
|
set(key, callback, delay) {
|
|
111
206
|
const reasons = this.#entries.get(key)?.reasons ?? /* @__PURE__ */ new Set();
|
|
112
207
|
const entry = { callback, startedAt: 0, remaining: delay, reasons };
|
|
113
208
|
this.#entries.set(key, entry);
|
|
114
|
-
if (reasons.size === 0) this.#arm(key, entry);
|
|
209
|
+
if (reasons.size === 0) this.#arm(key, entry, callback);
|
|
115
210
|
}
|
|
116
|
-
/**
|
|
117
|
-
* Holds `key` for `reason` and banks the time left, with a floor of one
|
|
118
|
-
* millisecond. Reports whether this call is the one that stopped a running
|
|
119
|
-
* timer, so the caller can write its held-state hook exactly once.
|
|
120
|
-
*/
|
|
121
211
|
pause(key, reason) {
|
|
122
|
-
|
|
123
|
-
if (entry === void 0)
|
|
212
|
+
let entry = this.#entries.get(key);
|
|
213
|
+
if (entry === void 0) {
|
|
214
|
+
entry = { callback: null, startedAt: 0, remaining: 0, reasons: /* @__PURE__ */ new Set() };
|
|
215
|
+
this.#entries.set(key, entry);
|
|
216
|
+
}
|
|
124
217
|
entry.reasons.add(reason);
|
|
125
218
|
if (!this.#timers.has(key)) return false;
|
|
126
219
|
this.#timers.clear(key);
|
|
127
220
|
entry.remaining = Math.max(1, entry.remaining - (Date.now() - entry.startedAt));
|
|
128
221
|
return true;
|
|
129
222
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Releases `reason` on `key`, arming the banked time again once no reason is
|
|
132
|
-
* left. Reports whether this call is the one that started the timer again.
|
|
133
|
-
*/
|
|
134
223
|
resume(key, reason) {
|
|
135
224
|
const entry = this.#entries.get(key);
|
|
136
225
|
if (entry === void 0) return false;
|
|
137
226
|
entry.reasons.delete(reason);
|
|
138
227
|
if (entry.reasons.size > 0 || this.#timers.has(key)) return false;
|
|
139
|
-
|
|
228
|
+
const { callback } = entry;
|
|
229
|
+
if (callback === null) {
|
|
230
|
+
this.#entries.delete(key);
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
this.#arm(key, entry, callback);
|
|
140
234
|
return true;
|
|
141
235
|
}
|
|
142
|
-
|
|
236
|
+
isHeld(key) {
|
|
237
|
+
return (this.#entries.get(key)?.reasons.size ?? 0) > 0;
|
|
238
|
+
}
|
|
143
239
|
tracks(key) {
|
|
144
240
|
return this.#entries.has(key);
|
|
145
241
|
}
|
|
146
|
-
/** Cancels `key`'s timer and drops its hold. */
|
|
147
242
|
clear(key) {
|
|
148
243
|
this.#timers.clear(key);
|
|
149
244
|
this.#entries.delete(key);
|
|
150
245
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Cancels every timer and forgets every key. Call this from a controller's
|
|
153
|
-
* `disconnect()` so neither a timer nor a hold outlives the element.
|
|
154
|
-
*/
|
|
155
246
|
clearAll() {
|
|
156
247
|
this.#timers.clearAll();
|
|
157
248
|
this.#entries.clear();
|
|
158
249
|
}
|
|
159
|
-
|
|
160
|
-
#arm(key, entry) {
|
|
250
|
+
#arm(key, entry, callback) {
|
|
161
251
|
entry.startedAt = Date.now();
|
|
162
252
|
this.#timers.set(
|
|
163
253
|
key,
|
|
164
254
|
() => {
|
|
165
255
|
this.#entries.delete(key);
|
|
166
|
-
|
|
256
|
+
callback();
|
|
167
257
|
},
|
|
168
258
|
entry.remaining
|
|
169
259
|
);
|
|
170
260
|
}
|
|
171
261
|
};
|
|
172
262
|
|
|
173
|
-
|
|
263
|
+
function targetSelector(identifier, name) {
|
|
264
|
+
return `[data-${identifier}-target~="${name}"]`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function cloneTemplateRoot(template) {
|
|
268
|
+
const root = template.content.firstElementChild;
|
|
269
|
+
return root instanceof HTMLElement ? root.cloneNode(true) : null;
|
|
270
|
+
}
|
|
271
|
+
|
|
174
272
|
function timeMs(value) {
|
|
175
273
|
const trimmed = value.trim();
|
|
176
274
|
const amount = Number.parseFloat(trimmed);
|
|
@@ -204,123 +302,136 @@ function maxTransitionTotalMs(style) {
|
|
|
204
302
|
return maxTotalMs(transitionTimings(style));
|
|
205
303
|
}
|
|
206
304
|
|
|
207
|
-
// src/controllers/toast_controller.ts
|
|
208
305
|
var DELEGATED_EVENTS = ["click", "focusin", "focusout", "keydown", "mouseover", "mouseout"];
|
|
209
|
-
var ToastController = class extends Controller {
|
|
306
|
+
var ToastController = class _ToastController extends Controller {
|
|
307
|
+
#numbers = new NumberValueReader();
|
|
210
308
|
static targets = ["list", "template", "item"];
|
|
211
309
|
static values = {
|
|
212
310
|
duration: { type: Number, default: 0 },
|
|
213
311
|
max: { type: Number, default: 3 }
|
|
214
312
|
};
|
|
313
|
+
static valueConstraints = {
|
|
314
|
+
duration: NUMBER_BOUNDS.timer,
|
|
315
|
+
max: NUMBER_BOUNDS.finite
|
|
316
|
+
};
|
|
215
317
|
static actions = ["dismiss", "onKeydown", "pause", "resume", "show"];
|
|
216
318
|
static events = ["dismiss", "show"];
|
|
217
|
-
/** Removal timers for the leaving transition; the auto-dismiss ones live below. */
|
|
218
319
|
#timers = new SafeTimeout();
|
|
219
|
-
/** Per-toast auto-dismiss, held open while the toast is hovered or focused. */
|
|
220
320
|
#dismiss = new PausableTimers();
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
321
|
+
#taken = /* @__PURE__ */ new Set();
|
|
322
|
+
#outside = /* @__PURE__ */ new WeakSet();
|
|
323
|
+
#phases = /* @__PURE__ */ new WeakMap();
|
|
324
|
+
#reapply = new MorphRenderWatcher(() => this.#reapplyLimit());
|
|
325
|
+
#spared = [];
|
|
326
|
+
#pointer = new ListenerSet();
|
|
327
|
+
#awaitingPointer = /* @__PURE__ */ new Set();
|
|
226
328
|
#rafHandles = /* @__PURE__ */ new Map();
|
|
227
|
-
/** The stable list that owns delegated listeners for dynamically added items. */
|
|
228
329
|
#delegatedList = null;
|
|
330
|
+
#connected = false;
|
|
331
|
+
#arrivals = /* @__PURE__ */ new Set();
|
|
332
|
+
#appliedMax = null;
|
|
229
333
|
connect() {
|
|
334
|
+
this.#connected = true;
|
|
335
|
+
const current = this.itemTargets;
|
|
336
|
+
for (const item of this.#arrivals) {
|
|
337
|
+
if (!current.includes(item)) this.#arrivals.delete(item);
|
|
338
|
+
}
|
|
339
|
+
this.#reapply.observe(this.element);
|
|
230
340
|
this.#connectDelegatedEvents();
|
|
231
|
-
this.enforceMaxLimit();
|
|
232
341
|
for (const item of this.itemTargets) {
|
|
233
342
|
if (!this.#dismiss.tracks(item) && item.dataset.state !== "leaving") {
|
|
234
343
|
this.#startTimer(item);
|
|
235
344
|
}
|
|
236
345
|
}
|
|
346
|
+
if (!Object.is(this.#appliedMax, this.#safeMax)) {
|
|
347
|
+
this.#appliedMax = this.#safeMax;
|
|
348
|
+
this.#enforceMax();
|
|
349
|
+
}
|
|
237
350
|
}
|
|
238
351
|
disconnect() {
|
|
352
|
+
this.#connected = false;
|
|
239
353
|
this.#disconnectDelegatedEvents();
|
|
240
354
|
this.#timers.clearAll();
|
|
241
355
|
this.#dismiss.clearAll();
|
|
356
|
+
this.#taken.clear();
|
|
357
|
+
this.#reapply.disconnect();
|
|
358
|
+
this.#spared = [];
|
|
359
|
+
this.#pointer.dispose();
|
|
360
|
+
this.#awaitingPointer.clear();
|
|
242
361
|
for (const handle of this.#rafHandles.values()) {
|
|
243
362
|
window.cancelAnimationFrame(handle);
|
|
244
363
|
}
|
|
245
364
|
this.#rafHandles.clear();
|
|
246
365
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (this.#delegatedList !== element) this.#connectDelegatedEvents(element);
|
|
366
|
+
listTargetConnected() {
|
|
367
|
+
if (this.#delegatedList !== this.listTarget) this.#connectDelegatedEvents();
|
|
250
368
|
}
|
|
251
|
-
/** Releases delegation only when the removed target is its current owner. */
|
|
252
369
|
listTargetDisconnected(element) {
|
|
253
370
|
if (this.#delegatedList === element) this.#disconnectDelegatedEvents();
|
|
254
|
-
|
|
255
|
-
|
|
371
|
+
if (!this.#connected || !this.hasListTarget || this.listTarget === element) return;
|
|
372
|
+
if (this.#delegatedList !== this.listTarget) this.#connectDelegatedEvents();
|
|
256
373
|
for (const item of this.itemTargets) {
|
|
257
|
-
if (item
|
|
258
|
-
if (this.durationValue <= 0) {
|
|
259
|
-
this.#dismiss.clear(item);
|
|
260
|
-
item.removeAttribute("data-paused");
|
|
261
|
-
} else {
|
|
262
|
-
this.#startTimer(item);
|
|
263
|
-
}
|
|
374
|
+
if (this.#outside.has(item)) this.#takeIn(item);
|
|
264
375
|
}
|
|
265
376
|
}
|
|
266
377
|
maxValueChanged() {
|
|
378
|
+
if (!this.#connected) return;
|
|
379
|
+
this.#appliedMax = this.#safeMax;
|
|
267
380
|
this.enforceMaxLimit();
|
|
268
381
|
}
|
|
269
|
-
/**
|
|
270
|
-
* Stimulus lifecycle callback triggered automatically when a new item target
|
|
271
|
-
* enters the DOM, from a client-side injection or a Turbo Stream append alike. An
|
|
272
|
-
* item already leaving, or parented outside `list`, is skipped.
|
|
273
|
-
*/
|
|
274
382
|
itemTargetConnected(element) {
|
|
275
|
-
this
|
|
276
|
-
|
|
383
|
+
if (this.#takeIn(element) && this.#connected) this.#enforceMax([element]);
|
|
384
|
+
}
|
|
385
|
+
#takeIn(element) {
|
|
386
|
+
if (this.#taken.has(element) || element.dataset.state === "leaving") return false;
|
|
387
|
+
if (element.parentNode !== this.listTarget) {
|
|
388
|
+
this.#outside.add(element);
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
this.#taken.add(element);
|
|
392
|
+
this.#arrivals.add(element);
|
|
393
|
+
this.#readHolds(element);
|
|
277
394
|
this.#startTimer(element);
|
|
278
|
-
element
|
|
279
|
-
this.#cancelAnimation(element);
|
|
395
|
+
this.#setPhase(element, "entering");
|
|
280
396
|
const handle = window.requestAnimationFrame(() => {
|
|
281
397
|
this.#rafHandles.delete(element);
|
|
282
398
|
if (element.parentNode !== this.listTarget || element.dataset.state === "leaving") return;
|
|
283
|
-
element
|
|
399
|
+
this.#setPhase(element, "visible");
|
|
284
400
|
});
|
|
285
401
|
this.#rafHandles.set(element, handle);
|
|
402
|
+
return true;
|
|
286
403
|
}
|
|
287
|
-
/** Clears any active timer when a toast is removed from the DOM. */
|
|
288
404
|
itemTargetDisconnected(element) {
|
|
289
|
-
this.#
|
|
405
|
+
const moved = this.#isShown(element) && element.matches(targetSelector(this.identifier, "item"));
|
|
406
|
+
if (moved) {
|
|
407
|
+
this.#afterMove(element);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
this.#taken.delete(element);
|
|
411
|
+
this.#phases.delete(element);
|
|
412
|
+
if (this.#connected) this.#arrivals.delete(element);
|
|
413
|
+
element.removeAttribute("data-paused");
|
|
414
|
+
this.#letGo(element);
|
|
290
415
|
this.#cancelAnimation(element);
|
|
291
416
|
}
|
|
292
|
-
/**
|
|
293
|
-
* Shows a new toast. Accepts its content from either a Stimulus action param
|
|
294
|
-
* (attribute-only trigger) or a programmatic `show` CustomEvent `detail`
|
|
295
|
-
* (remote / Turbo trigger); the action param wins when both are present.
|
|
296
|
-
*
|
|
297
|
-
* <button data-action="click->stimeo--toast#show"
|
|
298
|
-
* data-stimeo--toast-body-param="Saved"
|
|
299
|
-
* data-stimeo--toast-type-param="status">Show</button>
|
|
300
|
-
*
|
|
301
|
-
* element.dispatchEvent(new CustomEvent("show", { detail: { body, type } }))
|
|
302
|
-
*
|
|
303
|
-
* Clones the template slot, interpolates the body text, and appends to the list.
|
|
304
|
-
*/
|
|
305
417
|
show(event) {
|
|
306
418
|
if (!this.hasTemplateTarget || !this.hasListTarget) return;
|
|
307
|
-
const
|
|
308
|
-
if (!
|
|
309
|
-
const
|
|
310
|
-
const item =
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
419
|
+
const message = this.#readField(event, "message");
|
|
420
|
+
if (!message) return;
|
|
421
|
+
const template = this.templateTarget;
|
|
422
|
+
const item = cloneTemplateRoot(template);
|
|
423
|
+
if (template.content.children.length !== 1) return;
|
|
424
|
+
if (!item?.matches(targetSelector(this.identifier, "item"))) return;
|
|
425
|
+
const messageSlot = item.querySelector("[data-toast-slot='message']");
|
|
426
|
+
if (!messageSlot) return;
|
|
427
|
+
messageSlot.textContent = message;
|
|
428
|
+
messageSlot.setAttribute(
|
|
429
|
+
"role",
|
|
430
|
+
this.#readField(event, "type") === "alert" ? "alert" : "status"
|
|
431
|
+
);
|
|
316
432
|
this.listTarget.appendChild(item);
|
|
317
433
|
this.dispatch("show", { detail: { item } });
|
|
318
434
|
}
|
|
319
|
-
/**
|
|
320
|
-
* Reads a string field from a Stimulus action param or a CustomEvent `detail`,
|
|
321
|
-
* preferring the action param. Returns null unless a non-empty string is found,
|
|
322
|
-
* so untrusted runtime payloads cannot inject non-string values.
|
|
323
|
-
*/
|
|
324
435
|
#readField(event, key) {
|
|
325
436
|
const params = event.params;
|
|
326
437
|
const fromParams = params?.[key];
|
|
@@ -332,70 +443,126 @@ var ToastController = class extends Controller {
|
|
|
332
443
|
}
|
|
333
444
|
return null;
|
|
334
445
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const item = this.#
|
|
446
|
+
dismiss(input) {
|
|
447
|
+
const source = actionSource(input);
|
|
448
|
+
const item = this.#itemFromSource(source);
|
|
338
449
|
if (!item) return;
|
|
339
|
-
this.#removeWithTransition(item,
|
|
450
|
+
this.#removeWithTransition(item, source.reason);
|
|
340
451
|
}
|
|
341
|
-
/** Dismisses the focused toast when Escape is pressed. */
|
|
342
452
|
onKeydown(event) {
|
|
343
453
|
if (event.key === "Escape") {
|
|
344
454
|
if (event.defaultPrevented || event.isComposing) return;
|
|
345
|
-
const item = this.#
|
|
455
|
+
const item = this.#itemFromSource(actionSource(event));
|
|
346
456
|
if (!item) return;
|
|
347
457
|
event.preventDefault();
|
|
348
458
|
this.#removeWithTransition(item, "user");
|
|
349
459
|
}
|
|
350
460
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
* snapshotted on the first active reason, and only resumed once *every*
|
|
356
|
-
* reason has been released (see {@link resume}). This keeps a toast paused
|
|
357
|
-
* while it is still hovered *or* focused, per WCAG 2.2.1.
|
|
358
|
-
*/
|
|
359
|
-
pause(event) {
|
|
360
|
-
const item = this.#itemFromEvent(event);
|
|
361
|
-
if (item && this.#dismiss.pause(item, this.#pauseReason(event))) {
|
|
461
|
+
pause(input) {
|
|
462
|
+
const source = actionSource(input);
|
|
463
|
+
const item = this.#itemFromSource(source);
|
|
464
|
+
if (item && this.#dismiss.pause(item, this.#pauseReason(source.event))) {
|
|
362
465
|
item.setAttribute("data-paused", "true");
|
|
363
466
|
}
|
|
364
467
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const item = this.#
|
|
368
|
-
if (item
|
|
369
|
-
|
|
468
|
+
resume(input) {
|
|
469
|
+
const source = actionSource(input);
|
|
470
|
+
const item = this.#itemFromSource(source);
|
|
471
|
+
if (item) {
|
|
472
|
+
this.#release(
|
|
473
|
+
item,
|
|
474
|
+
this.#pauseReason(source.event),
|
|
475
|
+
ownerOf(this.itemTargets, source.event?.relatedTarget)
|
|
476
|
+
);
|
|
370
477
|
}
|
|
371
478
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
|
|
377
|
-
|
|
479
|
+
#release(item, reason, spare) {
|
|
480
|
+
const held = this.#dismiss.isHeld(item);
|
|
481
|
+
if (this.#dismiss.resume(item, reason)) item.removeAttribute("data-paused");
|
|
482
|
+
if (held && !this.#dismiss.isHeld(item)) this.#limitLater(spare);
|
|
483
|
+
}
|
|
484
|
+
#limitLater(spare) {
|
|
485
|
+
if (spare) this.#spared.push(spare);
|
|
486
|
+
this.#reapply.schedule();
|
|
487
|
+
}
|
|
488
|
+
#setPhase(item, phase) {
|
|
489
|
+
this.#phases.set(item, phase);
|
|
490
|
+
item.setAttribute("data-state", phase);
|
|
491
|
+
}
|
|
492
|
+
#reapplyLimit() {
|
|
493
|
+
for (const item of this.itemTargets) {
|
|
494
|
+
if (!this.#taken.has(item) || !this.hasListTarget || item.parentNode !== this.listTarget)
|
|
495
|
+
continue;
|
|
496
|
+
const phase = this.#phases.get(item);
|
|
497
|
+
if (item.dataset.state === "leaving") this.#phases.set(item, "leaving");
|
|
498
|
+
else if (phase) item.setAttribute("data-state", phase);
|
|
499
|
+
if (this.#dismiss.isHeld(item) && this.#dismiss.tracks(item))
|
|
500
|
+
item.setAttribute("data-paused", "true");
|
|
501
|
+
else item.removeAttribute("data-paused");
|
|
502
|
+
}
|
|
503
|
+
const spared = this.#spared;
|
|
504
|
+
this.#spared = [];
|
|
505
|
+
this.#enforceMax(spared);
|
|
506
|
+
}
|
|
507
|
+
#afterMove(item) {
|
|
508
|
+
if (!item.contains(document.activeElement)) this.#release(item, "focus", null);
|
|
509
|
+
if (this.#dismiss.isHeld(item)) this.#awaitPointer(item);
|
|
510
|
+
}
|
|
511
|
+
#readHolds(item) {
|
|
512
|
+
if (item.contains(document.activeElement)) this.#dismiss.pause(item, "focus");
|
|
513
|
+
if (!item.matches(":hover")) return;
|
|
514
|
+
this.#dismiss.pause(item, "hover");
|
|
515
|
+
this.#awaitPointer(item);
|
|
516
|
+
}
|
|
517
|
+
#awaitPointer(item) {
|
|
518
|
+
this.#awaitingPointer.add(item);
|
|
519
|
+
this.#pointer.add(document, "pointermove", this.#onPointerMove, {
|
|
520
|
+
capture: true,
|
|
521
|
+
passive: true
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
#onPointerMove = () => {
|
|
525
|
+
this.#pointer.dispose();
|
|
526
|
+
const waiting = [...this.#awaitingPointer];
|
|
527
|
+
this.#awaitingPointer.clear();
|
|
528
|
+
for (const item of waiting) {
|
|
529
|
+
if (!item.matches(":hover")) this.#release(item, "hover", null);
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
#letGo(item) {
|
|
533
|
+
if (this.#dismiss.isHeld(item)) this.#limitLater(null);
|
|
534
|
+
this.#dismiss.clear(item);
|
|
535
|
+
this.#awaitingPointer.delete(item);
|
|
536
|
+
if (this.#awaitingPointer.size === 0) this.#pointer.dispose();
|
|
537
|
+
}
|
|
538
|
+
#itemFromSource(source) {
|
|
539
|
+
const target = source.origin ?? source.host;
|
|
540
|
+
if (!target || !this.hasListTarget) return null;
|
|
541
|
+
if (target.closest(`[data-controller~="${this.identifier}"]`) !== this.element) return null;
|
|
542
|
+
const item = target.closest(targetSelector(this.identifier, "item"));
|
|
543
|
+
return item && this.itemTargets.includes(item) && this.listTarget.contains(item) ? item : null;
|
|
378
544
|
}
|
|
379
|
-
/** Classifies a pause/resume event as a hover or focus reason. */
|
|
380
545
|
#pauseReason(event) {
|
|
381
|
-
return event
|
|
546
|
+
return event?.type === "focusin" || event?.type === "focusout" ? "focus" : "hover";
|
|
382
547
|
}
|
|
383
|
-
/** Arms a toast's auto-dismiss; a non-positive `duration` means it never expires. */
|
|
384
548
|
#startTimer(element) {
|
|
385
|
-
if (
|
|
386
|
-
|
|
549
|
+
if (element.dataset.state === "leaving" || element.parentNode !== this.listTarget) return;
|
|
550
|
+
const armed = this.#safeDuration > 0;
|
|
551
|
+
if (armed) {
|
|
552
|
+
this.#dismiss.set(
|
|
553
|
+
element,
|
|
554
|
+
() => this.#removeWithTransition(element, "timeout"),
|
|
555
|
+
this.#safeDuration
|
|
556
|
+
);
|
|
387
557
|
}
|
|
388
|
-
this.#dismiss.
|
|
389
|
-
|
|
390
|
-
() => this.#removeWithTransition(element, "timeout"),
|
|
391
|
-
this.durationValue
|
|
392
|
-
);
|
|
558
|
+
if (armed && this.#dismiss.isHeld(element)) element.setAttribute("data-paused", "true");
|
|
559
|
+
else element.removeAttribute("data-paused");
|
|
393
560
|
}
|
|
394
561
|
#removeWithTransition(element, reason) {
|
|
395
562
|
if (element.dataset.state === "leaving" || element.parentNode !== this.listTarget) return;
|
|
396
|
-
this.#
|
|
563
|
+
this.#letGo(element);
|
|
397
564
|
this.#cancelAnimation(element);
|
|
398
|
-
element
|
|
565
|
+
this.#setPhase(element, "leaving");
|
|
399
566
|
const finalize = () => {
|
|
400
567
|
if (element.parentNode !== this.listTarget) return;
|
|
401
568
|
this.listTarget.removeChild(element);
|
|
@@ -408,26 +575,24 @@ var ToastController = class extends Controller {
|
|
|
408
575
|
finalize();
|
|
409
576
|
}
|
|
410
577
|
}
|
|
411
|
-
/**
|
|
412
|
-
* Removes the oldest toasts when the list exceeds `maxValue`.
|
|
413
|
-
*
|
|
414
|
-
* Public (not `#private`) as a deterministic seam: enforcement normally runs
|
|
415
|
-
* from `itemTargetConnected`, a Stimulus callback delivered through a
|
|
416
|
-
* MutationObserver, which a DOM-only environment does not reliably fire — so
|
|
417
|
-
* it can also be invoked directly. It is not a user-wired action.
|
|
418
|
-
*/
|
|
419
578
|
enforceMaxLimit() {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
579
|
+
this.#enforceMax();
|
|
580
|
+
}
|
|
581
|
+
#enforceMax(spared = []) {
|
|
582
|
+
if (this.#safeMax <= 0) return;
|
|
583
|
+
for (const item of [...this.#arrivals]) {
|
|
584
|
+
if (this.#shownCount() <= this.#safeMax) return;
|
|
585
|
+
if (this.#isShown(item) && !spared.includes(item) && !this.#dismiss.isHeld(item)) {
|
|
586
|
+
this.#removeWithTransition(item, "limit");
|
|
427
587
|
}
|
|
428
588
|
}
|
|
429
589
|
}
|
|
430
|
-
|
|
590
|
+
#shownCount() {
|
|
591
|
+
return this.itemTargets.filter((item) => this.#isShown(item)).length;
|
|
592
|
+
}
|
|
593
|
+
#isShown(item) {
|
|
594
|
+
return this.#taken.has(item) && this.hasListTarget && item.parentNode === this.listTarget && item.dataset.state !== "leaving";
|
|
595
|
+
}
|
|
431
596
|
#connectDelegatedEvents(list = this.hasListTarget ? this.listTarget : null) {
|
|
432
597
|
this.#disconnectDelegatedEvents();
|
|
433
598
|
if (!list) return;
|
|
@@ -436,7 +601,6 @@ var ToastController = class extends Controller {
|
|
|
436
601
|
this.#delegatedList.addEventListener(type, this.#onListEvent);
|
|
437
602
|
}
|
|
438
603
|
}
|
|
439
|
-
/** Releases every delegated listener from the exact list that owns it. */
|
|
440
604
|
#disconnectDelegatedEvents() {
|
|
441
605
|
if (!this.#delegatedList) return;
|
|
442
606
|
for (const type of DELEGATED_EVENTS) {
|
|
@@ -444,7 +608,6 @@ var ToastController = class extends Controller {
|
|
|
444
608
|
}
|
|
445
609
|
this.#delegatedList = null;
|
|
446
610
|
}
|
|
447
|
-
/** Routes every delegated item interaction from the stable list. */
|
|
448
611
|
#onListEvent = (event) => {
|
|
449
612
|
if (event.type === "click") {
|
|
450
613
|
const target = event.target instanceof Element ? event.target : null;
|
|
@@ -457,22 +620,31 @@ var ToastController = class extends Controller {
|
|
|
457
620
|
else this.resume(event);
|
|
458
621
|
}
|
|
459
622
|
};
|
|
460
|
-
/** Whether a bubbling focus/pointer event enters or leaves a toast boundary. */
|
|
461
623
|
#crossesItemBoundary(event) {
|
|
462
|
-
const item = this.#
|
|
624
|
+
const item = this.#itemFromSource(actionSource(event));
|
|
463
625
|
if (!item) return false;
|
|
464
626
|
const related = "relatedTarget" in event ? event.relatedTarget : null;
|
|
465
627
|
return !(related instanceof Node && item.contains(related));
|
|
466
628
|
}
|
|
467
|
-
/** Cancels the pending entering-to-visible frame owned by one item. */
|
|
468
629
|
#cancelAnimation(element) {
|
|
469
630
|
const handle = this.#rafHandles.get(element);
|
|
470
631
|
if (handle === void 0) return;
|
|
471
632
|
window.cancelAnimationFrame(handle);
|
|
472
633
|
this.#rafHandles.delete(element);
|
|
473
634
|
}
|
|
635
|
+
get #safeDuration() {
|
|
636
|
+
return this.#numbers.read(
|
|
637
|
+
this,
|
|
638
|
+
"duration",
|
|
639
|
+
this.durationValue,
|
|
640
|
+
_ToastController.values.duration.default,
|
|
641
|
+
_ToastController.valueConstraints.duration
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
get #safeMax() {
|
|
645
|
+
return this.#numbers.read(this, "max", this.maxValue, 0, _ToastController.valueConstraints.max);
|
|
646
|
+
}
|
|
474
647
|
};
|
|
475
648
|
|
|
476
649
|
export { ToastController };
|
|
477
|
-
//# sourceMappingURL=toast_controller.js.map
|
|
478
650
|
//# sourceMappingURL=toast_controller.js.map
|