stimeo-ui 0.16.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 +31 -0
- data/README.md +8 -1
- data/dist/cable/index.js +363 -436
- data/dist/controllers/accordion_controller.js +166 -55
- data/dist/controllers/alert_dialog_controller.js +862 -221
- data/dist/controllers/announcer_controller.js +135 -198
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +271 -127
- data/dist/controllers/avatar_controller.js +171 -105
- data/dist/controllers/breadcrumb_controller.js +0 -130
- data/dist/controllers/bulk_select_controller.js +262 -52
- data/dist/controllers/calendar_controller.js +175 -209
- data/dist/controllers/carousel_controller.js +461 -399
- data/dist/controllers/character_counter_controller.js +246 -156
- data/dist/controllers/checkbox_controller.js +32 -74
- data/dist/controllers/clipboard_controller.js +168 -147
- data/dist/controllers/collapsible_controller.js +301 -120
- data/dist/controllers/color_picker_controller.js +149 -139
- data/dist/controllers/combobox_controller.js +360 -133
- data/dist/controllers/command_palette_controller.js +970 -358
- data/dist/controllers/conditional_fields_controller.js +166 -124
- data/dist/controllers/confirm_controller.js +939 -248
- data/dist/controllers/context_menu_controller.js +256 -128
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +183 -148
- data/dist/controllers/currency_input_controller.js +134 -158
- data/dist/controllers/data_grid_controller.js +114 -186
- data/dist/controllers/date_range_picker_controller.js +288 -206
- data/dist/controllers/dialog_controller.js +858 -223
- data/dist/controllers/direct_upload_controller.js +73 -153
- data/dist/controllers/dirty_form_controller.js +14 -48
- data/dist/controllers/dismissible_controller.js +175 -21
- data/dist/controllers/drawer_controller.js +933 -341
- data/dist/controllers/dropdown_controller.js +312 -82
- data/dist/controllers/editable_controller.js +158 -68
- data/dist/controllers/empty_state_controller.js +67 -53
- data/dist/controllers/file_dropzone_controller.js +311 -207
- data/dist/controllers/filter_controller.js +67 -39
- data/dist/controllers/flash_controller.js +172 -314
- data/dist/controllers/focus_controller.js +654 -240
- data/dist/controllers/form_field_controller.js +147 -132
- data/dist/controllers/form_validation_controller.js +13 -86
- data/dist/controllers/frame_loading_controller.js +264 -213
- data/dist/controllers/highlight_controller.js +107 -75
- data/dist/controllers/hover_card_controller.js +309 -118
- data/dist/controllers/idle_controller.js +267 -101
- data/dist/controllers/input_mask_controller.js +71 -72
- data/dist/controllers/intersection_controller.js +147 -106
- data/dist/controllers/lazy_frame_controller.js +9 -65
- data/dist/controllers/listbox_controller.js +306 -204
- data/dist/controllers/local_time_controller.js +54 -64
- data/dist/controllers/masonry_controller.js +70 -93
- data/dist/controllers/menu_controller.js +214 -156
- data/dist/controllers/menubar_controller.js +170 -329
- data/dist/controllers/meter_controller.js +151 -67
- data/dist/controllers/multi_select_controller.js +593 -358
- data/dist/controllers/navigation_menu_controller.js +124 -232
- data/dist/controllers/nested_form_controller.js +352 -182
- data/dist/controllers/network_status_controller.js +242 -54
- data/dist/controllers/number_input_controller.js +320 -263
- data/dist/controllers/optimistic_controller.js +16 -76
- data/dist/controllers/otp_controller.js +198 -193
- data/dist/controllers/overflow_indicator_controller.js +116 -113
- data/dist/controllers/overflow_menu_controller.js +343 -283
- data/dist/controllers/pagination_controller.js +295 -119
- data/dist/controllers/password_reveal_controller.js +389 -121
- data/dist/controllers/password_strength_controller.js +99 -153
- data/dist/controllers/persist_controller.js +237 -103
- data/dist/controllers/pointer_drag_controller.js +185 -165
- data/dist/controllers/popover_controller.js +236 -97
- data/dist/controllers/portal_controller.js +209 -76
- data/dist/controllers/preview_guard_controller.js +232 -116
- data/dist/controllers/progress_controller.js +125 -56
- data/dist/controllers/radio_group_controller.js +117 -137
- data/dist/controllers/range_slider_controller.js +192 -105
- data/dist/controllers/rating_controller.js +418 -207
- data/dist/controllers/read_more_controller.js +134 -63
- 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 +255 -139
- data/dist/controllers/roving_controller.js +39 -84
- data/dist/controllers/scroll_area_controller.js +428 -225
- data/dist/controllers/scroll_restore_controller.js +0 -53
- data/dist/controllers/scroll_visibility_controller.js +395 -145
- data/dist/controllers/scrollspy_controller.js +181 -242
- data/dist/controllers/separator_controller.js +267 -140
- data/dist/controllers/sidebar_controller.js +1023 -386
- data/dist/controllers/skeleton_controller.js +248 -97
- data/dist/controllers/slider_controller.js +159 -79
- data/dist/controllers/smart_sticky_header_controller.js +162 -63
- data/dist/controllers/sortable_controller.js +0 -112
- data/dist/controllers/spinner_controller.js +277 -169
- data/dist/controllers/step_indicator_controller.js +99 -46
- data/dist/controllers/stepper_controller.js +114 -73
- data/dist/controllers/stick_to_bottom_controller.js +262 -138
- data/dist/controllers/sticky_observer_controller.js +214 -49
- data/dist/controllers/submit_once_controller.js +294 -205
- data/dist/controllers/switch_controller.js +33 -60
- data/dist/controllers/tabs_controller.js +35 -29
- data/dist/controllers/tags_input_controller.js +136 -145
- data/dist/controllers/textarea_autosize_controller.js +71 -58
- data/dist/controllers/theme_controller.js +130 -112
- data/dist/controllers/time_picker_controller.js +146 -80
- data/dist/controllers/toast_controller.js +186 -297
- data/dist/controllers/toggle_group_controller.js +95 -136
- data/dist/controllers/toolbar_controller.js +68 -98
- data/dist/controllers/tooltip_controller.js +158 -124
- data/dist/controllers/transition_controller.js +123 -119
- data/dist/controllers/tree_view_controller.js +150 -345
- data/dist/index.js +6370 -9346
- data/dist/positioning/index.js +148 -47
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +3 -3
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/roving_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/logical_scroll.ts
|
|
6
3
|
function isRtl(element) {
|
|
7
4
|
return window.getComputedStyle(element).direction === "rtl";
|
|
8
5
|
}
|
|
9
6
|
|
|
10
|
-
// src/utils/arrow_step.ts
|
|
11
7
|
function isReservedArrowChord(event, allow = []) {
|
|
12
8
|
if (!event.key.startsWith("Arrow")) return false;
|
|
13
9
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
@@ -16,13 +12,11 @@ function hasModifierChord(event) {
|
|
|
16
12
|
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
17
13
|
}
|
|
18
14
|
|
|
19
|
-
// src/utils/event_owner.ts
|
|
20
15
|
function ownerIndex(candidates, node) {
|
|
21
16
|
if (!(node instanceof Node)) return -1;
|
|
22
17
|
return candidates.findIndex((candidate) => candidate.contains(node));
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
// src/utils/focus_candidate.ts
|
|
26
20
|
function inheritsFieldsetDisabled(control) {
|
|
27
21
|
let fieldset = control.closest("fieldset[disabled]");
|
|
28
22
|
while (fieldset) {
|
|
@@ -33,27 +27,33 @@ function inheritsFieldsetDisabled(control) {
|
|
|
33
27
|
return false;
|
|
34
28
|
}
|
|
35
29
|
|
|
36
|
-
|
|
30
|
+
var ListenerSet = class {
|
|
31
|
+
#abort = new AbortController();
|
|
32
|
+
add(target, type, handler, options) {
|
|
33
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
34
|
+
}
|
|
35
|
+
dispose() {
|
|
36
|
+
this.#abort.abort();
|
|
37
|
+
this.#abort = new AbortController();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
37
41
|
var MicrotaskCoalescer = class {
|
|
38
42
|
#run;
|
|
39
43
|
#queued = false;
|
|
40
44
|
#active = false;
|
|
41
45
|
#generation = 0;
|
|
42
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
43
46
|
constructor(run) {
|
|
44
47
|
this.#run = run;
|
|
45
48
|
}
|
|
46
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
47
49
|
activate() {
|
|
48
50
|
this.#active = true;
|
|
49
51
|
}
|
|
50
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
51
52
|
cancel() {
|
|
52
53
|
this.#active = false;
|
|
53
54
|
this.#queued = false;
|
|
54
55
|
this.#generation += 1;
|
|
55
56
|
}
|
|
56
|
-
/** Requests one pass after the batch settles. Idempotent; inert outside the window. */
|
|
57
57
|
schedule() {
|
|
58
58
|
if (!this.#active || this.#queued) return;
|
|
59
59
|
this.#queued = true;
|
|
@@ -66,31 +66,39 @@ var MicrotaskCoalescer = class {
|
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
var MorphRenderWatcher = class {
|
|
70
|
+
#listeners = new ListenerSet();
|
|
71
|
+
#pass;
|
|
72
|
+
#element = null;
|
|
73
|
+
#onMorph = () => this.#pass.schedule();
|
|
74
|
+
constructor(run) {
|
|
75
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
76
|
+
}
|
|
77
|
+
observe(element) {
|
|
78
|
+
if (this.#element === element) return;
|
|
79
|
+
this.disconnect();
|
|
80
|
+
this.#element = element;
|
|
81
|
+
this.#pass.activate();
|
|
82
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
83
|
+
}
|
|
84
|
+
schedule() {
|
|
85
|
+
this.#pass.schedule();
|
|
86
|
+
}
|
|
87
|
+
disconnect() {
|
|
88
|
+
this.#listeners.dispose();
|
|
89
|
+
this.#pass.cancel();
|
|
90
|
+
this.#element = null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
70
94
|
var RovingTabindex = class {
|
|
71
|
-
/** Returns the current ordered item elements; called on every operation. */
|
|
72
95
|
#getItems;
|
|
73
|
-
/**
|
|
74
|
-
* @param getItems - Returns the current ordered item elements. Called on every
|
|
75
|
-
* operation so the live target list is always used.
|
|
76
|
-
*/
|
|
77
96
|
constructor(getItems) {
|
|
78
97
|
this.#getItems = getItems;
|
|
79
98
|
}
|
|
80
|
-
/** Index of the currently tabbable item (`tabindex="0"`), or `-1` if none. */
|
|
81
99
|
get activeIndex() {
|
|
82
100
|
return this.#getItems().findIndex((item) => item.tabIndex === 0);
|
|
83
101
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Makes exactly the item at `index` tabbable (`tabindex="0"`) and removes every
|
|
86
|
-
* other item from the Tab sequence (`tabindex="-1"`). An out-of-range `index`
|
|
87
|
-
* (e.g. `-1`) leaves all items at `-1`, which a controller can use to express
|
|
88
|
-
* "nothing is currently tabbable".
|
|
89
|
-
*
|
|
90
|
-
* @param index - Position of the item to make tabbable.
|
|
91
|
-
* @param options - Pass `{ focus: true }` to also move DOM focus to that item,
|
|
92
|
-
* and `items` to reuse an event-scoped collection snapshot.
|
|
93
|
-
*/
|
|
94
102
|
setActive(index, options = {}) {
|
|
95
103
|
const { focus = false } = options;
|
|
96
104
|
const items = options.items ?? this.#getItems();
|
|
@@ -107,7 +115,6 @@ function rovingMove(current, length, delta, wrap) {
|
|
|
107
115
|
return Math.min(length - 1, Math.max(0, next));
|
|
108
116
|
}
|
|
109
117
|
|
|
110
|
-
// src/controllers/roving_controller.ts
|
|
111
118
|
var STATE_ATTRIBUTES = ["disabled", "hidden"];
|
|
112
119
|
var RovingController = class extends Controller {
|
|
113
120
|
static targets = ["item"];
|
|
@@ -118,7 +125,7 @@ var RovingController = class extends Controller {
|
|
|
118
125
|
};
|
|
119
126
|
static events = ["change"];
|
|
120
127
|
#roving = new RovingTabindex(() => this.itemTargets);
|
|
121
|
-
#reconcile = new
|
|
128
|
+
#reconcile = new MorphRenderWatcher(() => this.#ensureTabStop(true));
|
|
122
129
|
#connected = false;
|
|
123
130
|
#observer = null;
|
|
124
131
|
connect() {
|
|
@@ -127,27 +134,24 @@ var RovingController = class extends Controller {
|
|
|
127
134
|
this.element.addEventListener("focusin", this.#onFocusin);
|
|
128
135
|
this.#watchState();
|
|
129
136
|
this.#connected = true;
|
|
130
|
-
this.#reconcile.
|
|
137
|
+
this.#reconcile.observe(this.element);
|
|
131
138
|
}
|
|
132
139
|
disconnect() {
|
|
133
140
|
this.#connected = false;
|
|
134
|
-
this.#reconcile.
|
|
141
|
+
this.#reconcile.disconnect();
|
|
135
142
|
this.element.removeEventListener("keydown", this.#onKeydown);
|
|
136
143
|
this.element.removeEventListener("focusin", this.#onFocusin);
|
|
137
144
|
this.#observer?.disconnect();
|
|
138
145
|
this.#observer = null;
|
|
139
146
|
}
|
|
140
|
-
/** Drops a runtime-added item from the Tab sequence before batch reconciliation. */
|
|
141
147
|
itemTargetConnected(item) {
|
|
142
148
|
if (!this.#connected) return;
|
|
143
149
|
item.tabIndex = -1;
|
|
144
150
|
this.#reconcile.schedule();
|
|
145
151
|
}
|
|
146
|
-
/** Re-establishes the single Tab stop after an item leaves the target set. */
|
|
147
152
|
itemTargetDisconnected() {
|
|
148
153
|
this.#reconcile.schedule();
|
|
149
154
|
}
|
|
150
|
-
/** Arrow keys move focus + the tab stop; Home/End jump to the ends. */
|
|
151
155
|
#onKeydown = (event) => {
|
|
152
156
|
if (event.defaultPrevented) return;
|
|
153
157
|
if (isReservedArrowChord(event)) return;
|
|
@@ -176,21 +180,14 @@ var RovingController = class extends Controller {
|
|
|
176
180
|
event.preventDefault();
|
|
177
181
|
this.#activate(next, true);
|
|
178
182
|
};
|
|
179
|
-
/**
|
|
180
|
-
* Syncs the single tab stop to an item that received focus by other means
|
|
181
|
-
* (click, programmatic `focus()`), so returning via Tab lands on it. The
|
|
182
|
-
* keyboard path's own `focus()` re-enters here but is a no-op (index unchanged).
|
|
183
|
-
*/
|
|
184
183
|
#onFocusin = (event) => {
|
|
185
184
|
const index = this.#indexOf(event.target);
|
|
186
185
|
if (index === -1 || !this.#reachable(index)) return;
|
|
187
186
|
this.#activate(index, false);
|
|
188
187
|
};
|
|
189
|
-
/** Resolves the item index owning an event target (the item or a descendant). */
|
|
190
188
|
#indexOf(target) {
|
|
191
189
|
return ownerIndex(this.itemTargets, target);
|
|
192
190
|
}
|
|
193
|
-
/** Makes `index` the tab stop (optionally focusing it), emitting `change` once. */
|
|
194
191
|
#activate(index, focus) {
|
|
195
192
|
const previous = this.#roving.activeIndex;
|
|
196
193
|
this.#roving.setActive(index, { focus });
|
|
@@ -198,16 +195,6 @@ var RovingController = class extends Controller {
|
|
|
198
195
|
this.dispatch("change", { detail: { index, item: this.itemTargets[index] } });
|
|
199
196
|
}
|
|
200
197
|
}
|
|
201
|
-
/**
|
|
202
|
-
* Keeps the Tab stop on a reachable item.
|
|
203
|
-
*
|
|
204
|
-
* `followFocus` is on for re-establishment only: an item added and focused in
|
|
205
|
-
* the same task has already claimed the stop through `focusin`, and the batch
|
|
206
|
-
* that follows must not hand it back to the first item. `connect()` passes it
|
|
207
|
-
* off so the authored DOM decides the initial stop. With nothing reachable the
|
|
208
|
-
* DOM is left as it is — a group inside a collapsed region gets its stop back
|
|
209
|
-
* when the region opens, instead of losing it for good.
|
|
210
|
-
*/
|
|
211
198
|
#ensureTabStop(followFocus) {
|
|
212
199
|
const items = this.itemTargets;
|
|
213
200
|
const focused = followFocus ? items.findIndex((item, i) => item === document.activeElement && this.#reachable(i)) : -1;
|
|
@@ -217,15 +204,6 @@ var RovingController = class extends Controller {
|
|
|
217
204
|
if (index === -1) return;
|
|
218
205
|
this.#roving.setActive(index);
|
|
219
206
|
}
|
|
220
|
-
/**
|
|
221
|
-
* Resolves the next reachable index in `delta`'s direction, honouring `wrap`.
|
|
222
|
-
*
|
|
223
|
-
* An arrow on the widget's own axis is the widget's to consume even when the
|
|
224
|
-
* position does not change, so a clamped end resolves to the current item
|
|
225
|
-
* rather than to nothing. An unreachable origin escapes to the first reachable
|
|
226
|
-
* item instead of sitting in a dead end, and `-1` is left for the one case that
|
|
227
|
-
* really is not ours: no reachable item anywhere.
|
|
228
|
-
*/
|
|
229
207
|
#step(current, delta, wrap) {
|
|
230
208
|
const length = this.itemTargets.length;
|
|
231
209
|
let index = current;
|
|
@@ -237,23 +215,15 @@ var RovingController = class extends Controller {
|
|
|
237
215
|
}
|
|
238
216
|
return this.#reachable(current) ? current : this.#firstReachable();
|
|
239
217
|
}
|
|
240
|
-
/** Index of the first reachable item, or `-1`. */
|
|
241
218
|
#firstReachable() {
|
|
242
219
|
return this.itemTargets.findIndex((_item, i) => this.#reachable(i));
|
|
243
220
|
}
|
|
244
|
-
/** Index of the last reachable item, or `-1`. */
|
|
245
221
|
#lastReachable() {
|
|
246
222
|
for (let i = this.itemTargets.length - 1; i >= 0; i -= 1) {
|
|
247
223
|
if (this.#reachable(i)) return i;
|
|
248
224
|
}
|
|
249
225
|
return -1;
|
|
250
226
|
}
|
|
251
|
-
/**
|
|
252
|
-
* Whether the item at `index` can hold the Tab stop and take focus.
|
|
253
|
-
*
|
|
254
|
-
* `aria-disabled` is deliberately not consulted: it keeps an item reachable and
|
|
255
|
-
* only suppresses activation, which this part does not own.
|
|
256
|
-
*/
|
|
257
227
|
#reachable(index) {
|
|
258
228
|
const item = this.itemTargets[index];
|
|
259
229
|
if (!item) return false;
|
|
@@ -262,14 +232,6 @@ var RovingController = class extends Controller {
|
|
|
262
232
|
if (item.disabled) return false;
|
|
263
233
|
return !inheritsFieldsetDisabled(item);
|
|
264
234
|
}
|
|
265
|
-
/**
|
|
266
|
-
* Whether `item`, or anything between it and the container, is `hidden`.
|
|
267
|
-
*
|
|
268
|
-
* The walk stops at the container on purpose: a group inside a hidden region is
|
|
269
|
-
* already out of the page's Tab order, and calling every item unreachable there
|
|
270
|
-
* would drop the stop with nothing left to restore it — the ancestor lies
|
|
271
|
-
* outside the subtree whose state attributes are watched.
|
|
272
|
-
*/
|
|
273
235
|
#hidden(item) {
|
|
274
236
|
let node = item;
|
|
275
237
|
while (node && node !== this.element) {
|
|
@@ -278,12 +240,6 @@ var RovingController = class extends Controller {
|
|
|
278
240
|
}
|
|
279
241
|
return false;
|
|
280
242
|
}
|
|
281
|
-
/**
|
|
282
|
-
* Watches the attributes that decide reachability, so disabling the item that
|
|
283
|
-
* holds the Tab stop hands it to another one instead of taking the whole set
|
|
284
|
-
* out of the Tab sequence. An enclosing `fieldset` disables items from outside
|
|
285
|
-
* the observed subtree, so each one's own `disabled` is watched too.
|
|
286
|
-
*/
|
|
287
243
|
#watchState() {
|
|
288
244
|
if (typeof MutationObserver === "undefined") return;
|
|
289
245
|
const observer = new MutationObserver(() => this.#reconcile.schedule());
|
|
@@ -300,5 +256,4 @@ var RovingController = class extends Controller {
|
|
|
300
256
|
};
|
|
301
257
|
|
|
302
258
|
export { RovingController };
|
|
303
|
-
//# sourceMappingURL=roving_controller.js.map
|
|
304
259
|
//# sourceMappingURL=roving_controller.js.map
|