stimeo-ui 0.14.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 +212 -0
- data/README.md +120 -0
- data/dist/cable/index.js +123 -29
- data/dist/controllers/accordion_controller.js +98 -9
- data/dist/controllers/announcer_controller.js +96 -62
- data/dist/controllers/auto_submit_controller.js +83 -7
- data/dist/controllers/avatar_controller.js +1 -1
- data/dist/controllers/breadcrumb_controller.js +38 -11
- data/dist/controllers/bulk_select_controller.js +7 -6
- data/dist/controllers/calendar_controller.js +340 -123
- data/dist/controllers/carousel_controller.js +263 -38
- data/dist/controllers/character_counter_controller.js +40 -2
- data/dist/controllers/checkbox_controller.js +81 -12
- 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 +85 -17
- 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 +221 -67
- data/dist/controllers/data_grid_controller.js +195 -29
- data/dist/controllers/date_range_picker_controller.js +151 -30
- data/dist/controllers/dialog_controller.js +35 -8
- data/dist/controllers/direct_upload_controller.js +22 -4
- data/dist/controllers/dirty_form_controller.js +46 -13
- 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 +432 -71
- 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 +45 -8
- data/dist/controllers/highlight_controller.js +82 -25
- 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/local_time_controller.js +10 -5
- data/dist/controllers/masonry_controller.js +31 -15
- 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 +42 -5
- data/dist/controllers/otp_controller.js +198 -55
- data/dist/controllers/overflow_indicator_controller.js +115 -21
- data/dist/controllers/overflow_menu_controller.js +141 -44
- 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 +100 -7
- data/dist/controllers/reading_progress_controller.js +65 -19
- data/dist/controllers/relative_time_controller.js +10 -5
- data/dist/controllers/resizable_controller.js +82 -22
- data/dist/controllers/scroll_area_controller.js +75 -27
- data/dist/controllers/scroll_restore_controller.js +37 -16
- data/dist/controllers/scroll_visibility_controller.js +49 -30
- data/dist/controllers/scrollspy_controller.js +71 -26
- 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 +60 -26
- 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 +104 -8
- data/dist/controllers/submit_once_controller.js +45 -9
- 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/textarea_autosize_controller.js +29 -3
- data/dist/controllers/theme_controller.js +64 -14
- data/dist/controllers/time_picker_controller.js +23 -8
- data/dist/controllers/toast_controller.js +451 -105
- 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 +5002 -1911
- data/dist/positioning/index.js +2 -0
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +2 -2
|
@@ -99,7 +99,12 @@ var SafeInterval = class extends TimerRegistry {
|
|
|
99
99
|
|
|
100
100
|
// src/controllers/countdown_controller.ts
|
|
101
101
|
var SECOND_MS = 1e3;
|
|
102
|
+
var OWNED_STATUS = "owns-status";
|
|
102
103
|
var CountdownController = class extends Controller {
|
|
104
|
+
/** The status marker, in the namespace this controller is registered under. */
|
|
105
|
+
get #ownedStatus() {
|
|
106
|
+
return `data-${this.identifier}-${OWNED_STATUS}`;
|
|
107
|
+
}
|
|
103
108
|
static targets = ["days", "hours", "minutes", "seconds", "status"];
|
|
104
109
|
static values = {
|
|
105
110
|
deadline: { type: String, default: "" },
|
|
@@ -115,6 +120,12 @@ var CountdownController = class extends Controller {
|
|
|
115
120
|
#intervalId = null;
|
|
116
121
|
/** Collapses a morph that swaps several render inputs at once into one re-derive. */
|
|
117
122
|
#resync = new MicrotaskCoalescer(() => this.#resyncToValues());
|
|
123
|
+
/**
|
|
124
|
+
* Whether `connect()` has run for this connection. Stimulus delivers Value
|
|
125
|
+
* callbacks ahead of it, while the run state is still the markup's own and not
|
|
126
|
+
* yet settled; `connect()` brings the status up to date once it is.
|
|
127
|
+
*/
|
|
128
|
+
#connected = false;
|
|
118
129
|
/** Epoch-ms anchor: the deadline (down) or the count-up origin (up). */
|
|
119
130
|
#reference = 0;
|
|
120
131
|
/** Amount (ms) captured at pause, so resume can restore the same display. */
|
|
@@ -127,28 +138,25 @@ var CountdownController = class extends Controller {
|
|
|
127
138
|
*/
|
|
128
139
|
#renderedAmount = 0;
|
|
129
140
|
connect() {
|
|
141
|
+
this.#connected = true;
|
|
130
142
|
this.#resync.activate();
|
|
131
143
|
this.#initReference();
|
|
132
144
|
const amount = this.#currentAmount();
|
|
133
145
|
this.#render(amount);
|
|
134
146
|
this.#pausedAmount = this.#renderedAmount;
|
|
135
147
|
const authored = this.element.getAttribute("data-state");
|
|
148
|
+
const settled = authored === "complete" && this.#isSettled(amount);
|
|
136
149
|
if (authored === null) {
|
|
137
|
-
if (this.autostartValue && this.#isValidDeadline)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
150
|
+
if (this.autostartValue && this.#isValidDeadline) this.start();
|
|
151
|
+
else this.element.setAttribute("data-state", "paused");
|
|
152
|
+
} else if (!settled) {
|
|
141
153
|
this.element.setAttribute("data-state", "paused");
|
|
142
|
-
|
|
154
|
+
if (authored === "running") this.start();
|
|
143
155
|
}
|
|
144
|
-
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
const wasRunning = authored === "running";
|
|
148
|
-
this.element.setAttribute("data-state", "paused");
|
|
149
|
-
if (wasRunning) this.start();
|
|
156
|
+
this.#syncStatus();
|
|
150
157
|
}
|
|
151
158
|
disconnect() {
|
|
159
|
+
this.#connected = false;
|
|
152
160
|
this.#resync.cancel();
|
|
153
161
|
this.#intervals.clearAll();
|
|
154
162
|
this.#intervalId = null;
|
|
@@ -161,6 +169,31 @@ var CountdownController = class extends Controller {
|
|
|
161
169
|
directionValueChanged() {
|
|
162
170
|
this.#resync.schedule();
|
|
163
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Follows a completion label swapped in place by a morph.
|
|
174
|
+
*
|
|
175
|
+
* Render only: `complete` is neither dispatched nor announced again. The status
|
|
176
|
+
* changes only after the countdown has completed, and only while it still shows
|
|
177
|
+
* the text this controller wrote there and nothing else, so text or an element
|
|
178
|
+
* the consumer put in the slot stays. A change delivered ahead of `connect()` is
|
|
179
|
+
* left to `connect()`.
|
|
180
|
+
*/
|
|
181
|
+
completeLabelValueChanged() {
|
|
182
|
+
if (this.#connected) this.#syncStatus();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Keeps a status that still shows this controller's text, and nothing else, on
|
|
186
|
+
* what the run state calls for: the label in force while complete; otherwise the
|
|
187
|
+
* text is taken back, marker and all. A status holding anything else is the
|
|
188
|
+
* consumer's and is left alone, marker included.
|
|
189
|
+
*
|
|
190
|
+
* @stimeoRenderRoot
|
|
191
|
+
*/
|
|
192
|
+
#syncStatus() {
|
|
193
|
+
if (!this.hasStatusTarget || !this.#ownsStatus(this.statusTarget)) return;
|
|
194
|
+
if (this.#state === "complete") this.#writeStatus(this.statusTarget, this.completeLabelValue);
|
|
195
|
+
else this.#releaseStatus(this.statusTarget);
|
|
196
|
+
}
|
|
164
197
|
/**
|
|
165
198
|
* Points the anchor at the current `deadline` / `direction` and repaints.
|
|
166
199
|
*
|
|
@@ -168,13 +201,27 @@ var CountdownController = class extends Controller {
|
|
|
168
201
|
* paused timer run or replay a milestone. A running one needs no restart either —
|
|
169
202
|
* every tick reads the anchor, so moving it is enough. While paused the stored
|
|
170
203
|
* amount follows the new reading, or resume would continue from the old deadline.
|
|
204
|
+
* A completion the new reading no longer settles (a deadline moved forward, or a
|
|
205
|
+
* count turned `up`) is handed back paused, as `connect()` hands back a restored
|
|
206
|
+
* one, so `resume()` counts again; the completion text this controller wrote goes
|
|
207
|
+
* with it, from a status slot that still shows it and nothing else.
|
|
208
|
+
*
|
|
209
|
+
* @stimeoRenderRoot
|
|
171
210
|
*/
|
|
172
211
|
#resyncToValues() {
|
|
173
212
|
this.#initReference();
|
|
174
|
-
this.#
|
|
213
|
+
const amount = this.#currentAmount();
|
|
214
|
+
this.#render(amount);
|
|
215
|
+
if (this.#state === "complete" && !this.#isSettled(amount)) {
|
|
216
|
+
this.element.setAttribute("data-state", "paused");
|
|
217
|
+
this.#syncStatus();
|
|
218
|
+
}
|
|
175
219
|
if (this.#state !== "running") this.#pausedAmount = this.#renderedAmount;
|
|
176
220
|
}
|
|
177
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* Starts (or restarts after pause) ticking toward the deadline. Counting on from a
|
|
223
|
+
* completion takes this controller's completion text back out of the status.
|
|
224
|
+
*/
|
|
178
225
|
start() {
|
|
179
226
|
if (this.#state === "running" || !this.#isValidDeadline) return;
|
|
180
227
|
if (this.#isDown && this.#currentAmount() <= 0) {
|
|
@@ -212,10 +259,8 @@ var CountdownController = class extends Controller {
|
|
|
212
259
|
this.#initReference();
|
|
213
260
|
const amount = this.#currentAmount();
|
|
214
261
|
this.#render(amount);
|
|
215
|
-
if (this.hasStatusTarget && this.statusTarget.textContent === this.completeLabelValue) {
|
|
216
|
-
this.statusTarget.textContent = "";
|
|
217
|
-
}
|
|
218
262
|
this.element.setAttribute("data-state", "paused");
|
|
263
|
+
this.#syncStatus();
|
|
219
264
|
if (wasRunning && this.#isValidDeadline) {
|
|
220
265
|
this.#pausedAmount = 0;
|
|
221
266
|
this.start();
|
|
@@ -223,9 +268,19 @@ var CountdownController = class extends Controller {
|
|
|
223
268
|
this.#pausedAmount = this.#renderedAmount;
|
|
224
269
|
}
|
|
225
270
|
}
|
|
226
|
-
/**
|
|
271
|
+
/**
|
|
272
|
+
* Schedules the repeating tick and marks the timer running. This is the one way
|
|
273
|
+
* into `running`, and a running timer keeps none of this controller's completion
|
|
274
|
+
* text in the status, so the status is settled here as on every other way out of
|
|
275
|
+
* `complete`: `start()` leaves a completion directly when `direction` flips to
|
|
276
|
+
* `up` and `start()` runs in the same task, ahead of the direction callback.
|
|
277
|
+
*
|
|
278
|
+
* @stimeoRuntimeOnly `interval` is the period of the one timer this call arms; the running state
|
|
279
|
+
* it writes does not depend on a Value.
|
|
280
|
+
*/
|
|
227
281
|
#runInterval() {
|
|
228
282
|
this.element.setAttribute("data-state", "running");
|
|
283
|
+
this.#syncStatus();
|
|
229
284
|
this.#intervalId = this.#intervals.set(() => this.#tick(), this.intervalValue);
|
|
230
285
|
}
|
|
231
286
|
/** Cancels the repeating tick, if any. */
|
|
@@ -246,21 +301,73 @@ var CountdownController = class extends Controller {
|
|
|
246
301
|
this.#complete();
|
|
247
302
|
}
|
|
248
303
|
}
|
|
249
|
-
/**
|
|
304
|
+
/**
|
|
305
|
+
* Stops at zero, marks completion, writes the completion label, emits `complete`,
|
|
306
|
+
* and announces it.
|
|
307
|
+
*
|
|
308
|
+
* @stimeoRenderRoot
|
|
309
|
+
*/
|
|
250
310
|
#complete() {
|
|
251
311
|
this.#teardownInterval();
|
|
252
312
|
this.#render(0);
|
|
253
313
|
this.element.setAttribute("data-state", "complete");
|
|
254
|
-
|
|
255
|
-
this.statusTarget.textContent = this.completeLabelValue;
|
|
256
|
-
}
|
|
314
|
+
this.#claimStatus();
|
|
257
315
|
this.dispatch("complete", { detail: {} });
|
|
316
|
+
this.#announceCompletion();
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Writes the label in force into the status slot as this controller's text. An
|
|
320
|
+
* empty label puts no text there: it claims a slot that is already empty — no
|
|
321
|
+
* text and no element — empties one that is still this controller's, and leaves
|
|
322
|
+
* any other slot, the consumer's, alone.
|
|
323
|
+
*/
|
|
324
|
+
#claimStatus() {
|
|
325
|
+
if (!this.hasStatusTarget) return;
|
|
326
|
+
const status = this.statusTarget;
|
|
327
|
+
const label = this.completeLabelValue;
|
|
328
|
+
if (label === "" && !this.#isEmpty(status) && !this.#ownsStatus(status)) return;
|
|
329
|
+
this.#writeStatus(status, label);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Whether the status slot shows the text this controller wrote there and nothing
|
|
333
|
+
* else: the text matches the marker, and the slot holds no element. Writing the
|
|
334
|
+
* slot's text replaces every child node, so an element the consumer puts in the
|
|
335
|
+
* slot makes it theirs even while the text still matches. An empty marker
|
|
336
|
+
* matches the slot whenever it is empty.
|
|
337
|
+
*/
|
|
338
|
+
#ownsStatus(status) {
|
|
339
|
+
return status.getAttribute(this.#ownedStatus) === status.textContent && status.firstElementChild === null;
|
|
340
|
+
}
|
|
341
|
+
/** Whether the status slot holds nothing at all: no text and no element. */
|
|
342
|
+
#isEmpty(status) {
|
|
343
|
+
return status.textContent === "" && status.firstElementChild === null;
|
|
344
|
+
}
|
|
345
|
+
/** Puts `text` into the status slot and records it as this controller's. */
|
|
346
|
+
#writeStatus(status, text) {
|
|
347
|
+
if (status.textContent !== text) status.textContent = text;
|
|
348
|
+
status.setAttribute(this.#ownedStatus, text);
|
|
349
|
+
}
|
|
350
|
+
/** Takes this controller's text out of the status slot, marker and all. */
|
|
351
|
+
#releaseStatus(status) {
|
|
352
|
+
status.textContent = "";
|
|
353
|
+
status.removeAttribute(this.#ownedStatus);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Reads the completion out through the shared announcer.
|
|
357
|
+
*
|
|
358
|
+
* @stimeoRuntimeOnly `announceText` words the one announcement a completion makes.
|
|
359
|
+
*/
|
|
360
|
+
#announceCompletion() {
|
|
258
361
|
announce(fillTemplate(this.announceTextValue, {}));
|
|
259
362
|
}
|
|
260
363
|
/** Sets the time anchor from the `deadline` value. */
|
|
261
364
|
#initReference() {
|
|
262
365
|
this.#reference = Date.parse(this.deadlineValue);
|
|
263
366
|
}
|
|
367
|
+
/** Whether a reading of `amount` leaves nothing to count: only a countdown at zero. */
|
|
368
|
+
#isSettled(amount) {
|
|
369
|
+
return this.#isDown && amount <= 0;
|
|
370
|
+
}
|
|
264
371
|
/** Remaining (down) or elapsed (up) ms, never negative. */
|
|
265
372
|
#currentAmount() {
|
|
266
373
|
if (!this.#isValidDeadline) return 0;
|
|
@@ -268,11 +375,7 @@ var CountdownController = class extends Controller {
|
|
|
268
375
|
const raw = this.#isDown ? this.#reference - now : now - this.#reference;
|
|
269
376
|
return Math.max(0, raw);
|
|
270
377
|
}
|
|
271
|
-
/**
|
|
272
|
-
* Writes the amount into the day/hour/minute/second slots.
|
|
273
|
-
*
|
|
274
|
-
* @stimeoRenderRoot
|
|
275
|
-
*/
|
|
378
|
+
/** Writes the amount into the day/hour/minute/second slots. */
|
|
276
379
|
#render(amount) {
|
|
277
380
|
const totalSeconds = Math.floor(amount / SECOND_MS);
|
|
278
381
|
this.#renderedAmount = totalSeconds * SECOND_MS;
|