stimeo-ui 0.16.0 → 0.18.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 +136 -0
- data/README.md +27 -11
- data/dist/cable/index.js +384 -449
- data/dist/controllers/accordion_controller.js +174 -55
- data/dist/controllers/alert_dialog_controller.js +903 -235
- data/dist/controllers/announcer_controller.js +238 -205
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +414 -145
- data/dist/controllers/avatar_controller.js +185 -107
- data/dist/controllers/breadcrumb_controller.js +0 -130
- data/dist/controllers/bulk_select_controller.js +282 -58
- data/dist/controllers/calendar_controller.js +228 -260
- data/dist/controllers/carousel_controller.js +536 -436
- data/dist/controllers/character_counter_controller.js +493 -207
- data/dist/controllers/checkbox_controller.js +38 -74
- data/dist/controllers/clipboard_controller.js +261 -149
- data/dist/controllers/collapsible_controller.js +304 -120
- data/dist/controllers/color_picker_controller.js +178 -146
- data/dist/controllers/combobox_controller.js +522 -156
- data/dist/controllers/command_palette_controller.js +1156 -395
- data/dist/controllers/conditional_fields_controller.js +300 -171
- data/dist/controllers/confirm_controller.js +980 -262
- data/dist/controllers/context_menu_controller.js +346 -153
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +281 -158
- data/dist/controllers/currency_input_controller.js +575 -225
- data/dist/controllers/data_grid_controller.js +248 -214
- data/dist/controllers/date_range_picker_controller.js +338 -235
- data/dist/controllers/dialog_controller.js +899 -237
- data/dist/controllers/direct_upload_controller.js +97 -167
- data/dist/controllers/dirty_form_controller.js +72 -69
- data/dist/controllers/dismissible_controller.js +196 -24
- data/dist/controllers/drawer_controller.js +974 -355
- data/dist/controllers/dropdown_controller.js +339 -96
- data/dist/controllers/editable_controller.js +315 -88
- data/dist/controllers/empty_state_controller.js +79 -58
- data/dist/controllers/file_dropzone_controller.js +322 -211
- data/dist/controllers/filter_controller.js +77 -42
- data/dist/controllers/flash_controller.js +238 -347
- data/dist/controllers/focus_controller.js +679 -240
- data/dist/controllers/form_field_controller.js +156 -132
- data/dist/controllers/form_validation_controller.js +31 -97
- data/dist/controllers/frame_loading_controller.js +275 -217
- data/dist/controllers/highlight_controller.js +107 -75
- data/dist/controllers/hover_card_controller.js +327 -130
- data/dist/controllers/idle_controller.js +271 -101
- data/dist/controllers/input_mask_controller.js +483 -97
- data/dist/controllers/intersection_controller.js +150 -106
- data/dist/controllers/lazy_frame_controller.js +24 -68
- data/dist/controllers/listbox_controller.js +523 -240
- data/dist/controllers/local_time_controller.js +102 -77
- data/dist/controllers/masonry_controller.js +80 -96
- data/dist/controllers/menu_controller.js +302 -188
- data/dist/controllers/menubar_controller.js +232 -345
- data/dist/controllers/meter_controller.js +417 -87
- data/dist/controllers/multi_select_controller.js +785 -393
- data/dist/controllers/navigation_menu_controller.js +190 -250
- data/dist/controllers/nested_form_controller.js +396 -192
- data/dist/controllers/network_status_controller.js +268 -62
- data/dist/controllers/number_input_controller.js +610 -303
- data/dist/controllers/optimistic_controller.js +45 -87
- data/dist/controllers/otp_controller.js +658 -255
- data/dist/controllers/overflow_indicator_controller.js +122 -113
- data/dist/controllers/overflow_menu_controller.js +470 -295
- data/dist/controllers/pagination_controller.js +332 -123
- data/dist/controllers/password_reveal_controller.js +392 -121
- data/dist/controllers/password_strength_controller.js +111 -158
- data/dist/controllers/persist_controller.js +165 -111
- data/dist/controllers/pointer_drag_controller.js +434 -188
- data/dist/controllers/popover_controller.js +269 -113
- data/dist/controllers/portal_controller.js +215 -76
- data/dist/controllers/preview_guard_controller.js +243 -116
- data/dist/controllers/progress_controller.js +391 -78
- data/dist/controllers/radio_group_controller.js +278 -211
- data/dist/controllers/range_slider_controller.js +220 -113
- data/dist/controllers/rating_controller.js +458 -211
- data/dist/controllers/read_more_controller.js +138 -63
- data/dist/controllers/reading_progress_controller.js +166 -137
- data/dist/controllers/relative_time_controller.js +211 -112
- data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
- data/dist/controllers/resizable_controller.js +299 -150
- data/dist/controllers/roving_controller.js +49 -88
- data/dist/controllers/scroll_area_controller.js +490 -246
- data/dist/controllers/scroll_restore_controller.js +14 -55
- data/dist/controllers/scroll_visibility_controller.js +432 -149
- data/dist/controllers/scrollspy_controller.js +193 -248
- data/dist/controllers/separator_controller.js +285 -142
- data/dist/controllers/sidebar_controller.js +1069 -404
- data/dist/controllers/skeleton_controller.js +259 -101
- data/dist/controllers/slider_controller.js +187 -86
- data/dist/controllers/smart_sticky_header_controller.js +173 -66
- data/dist/controllers/sortable_controller.js +26 -125
- data/dist/controllers/spinner_controller.js +288 -173
- data/dist/controllers/step_indicator_controller.js +105 -46
- data/dist/controllers/stepper_controller.js +120 -73
- data/dist/controllers/stick_to_bottom_controller.js +275 -140
- data/dist/controllers/sticky_observer_controller.js +220 -49
- data/dist/controllers/submit_once_controller.js +376 -227
- data/dist/controllers/switch_controller.js +201 -84
- data/dist/controllers/tabs_controller.js +41 -30
- data/dist/controllers/tags_input_controller.js +293 -173
- data/dist/controllers/textarea_autosize_controller.js +108 -74
- data/dist/controllers/theme_controller.js +140 -116
- data/dist/controllers/time_picker_controller.js +331 -127
- data/dist/controllers/toast_controller.js +244 -324
- data/dist/controllers/toggle_group_controller.js +252 -191
- data/dist/controllers/toolbar_controller.js +219 -120
- data/dist/controllers/tooltip_controller.js +158 -124
- data/dist/controllers/transition_controller.js +123 -119
- data/dist/controllers/tree_view_controller.js +283 -369
- data/dist/index.js +8573 -10410
- data/dist/positioning/index.js +154 -47
- data/lib/generators/stimeo/install/install_generator.rb +7 -2
- data/lib/generators/stimeo/install/templates/stimeo.js +19 -6
- 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,36 @@ 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
|
-
|
|
57
|
+
get pending() {
|
|
58
|
+
return this.#queued;
|
|
59
|
+
}
|
|
57
60
|
schedule() {
|
|
58
61
|
if (!this.#active || this.#queued) return;
|
|
59
62
|
this.#queued = true;
|
|
@@ -66,31 +69,42 @@ var MicrotaskCoalescer = class {
|
|
|
66
69
|
}
|
|
67
70
|
};
|
|
68
71
|
|
|
69
|
-
|
|
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
|
+
get pending() {
|
|
91
|
+
return this.#pass.pending;
|
|
92
|
+
}
|
|
93
|
+
disconnect() {
|
|
94
|
+
this.#listeners.dispose();
|
|
95
|
+
this.#pass.cancel();
|
|
96
|
+
this.#element = null;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
70
100
|
var RovingTabindex = class {
|
|
71
|
-
/** Returns the current ordered item elements; called on every operation. */
|
|
72
101
|
#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
102
|
constructor(getItems) {
|
|
78
103
|
this.#getItems = getItems;
|
|
79
104
|
}
|
|
80
|
-
/** Index of the currently tabbable item (`tabindex="0"`), or `-1` if none. */
|
|
81
105
|
get activeIndex() {
|
|
82
106
|
return this.#getItems().findIndex((item) => item.tabIndex === 0);
|
|
83
107
|
}
|
|
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
108
|
setActive(index, options = {}) {
|
|
95
109
|
const { focus = false } = options;
|
|
96
110
|
const items = options.items ?? this.#getItems();
|
|
@@ -107,7 +121,6 @@ function rovingMove(current, length, delta, wrap) {
|
|
|
107
121
|
return Math.min(length - 1, Math.max(0, next));
|
|
108
122
|
}
|
|
109
123
|
|
|
110
|
-
// src/controllers/roving_controller.ts
|
|
111
124
|
var STATE_ATTRIBUTES = ["disabled", "hidden"];
|
|
112
125
|
var RovingController = class extends Controller {
|
|
113
126
|
static targets = ["item"];
|
|
@@ -118,36 +131,33 @@ var RovingController = class extends Controller {
|
|
|
118
131
|
};
|
|
119
132
|
static events = ["change"];
|
|
120
133
|
#roving = new RovingTabindex(() => this.itemTargets);
|
|
121
|
-
#reconcile = new
|
|
134
|
+
#reconcile = new MorphRenderWatcher(() => this.#ensureTabStop(true));
|
|
122
135
|
#connected = false;
|
|
123
136
|
#observer = null;
|
|
137
|
+
#listeners = new ListenerSet();
|
|
124
138
|
connect() {
|
|
125
139
|
this.#ensureTabStop(false);
|
|
126
|
-
this.element
|
|
127
|
-
this.element
|
|
140
|
+
this.#listeners.add(this.element, "keydown", this.#onKeydown);
|
|
141
|
+
this.#listeners.add(this.element, "focusin", this.#onFocusin);
|
|
128
142
|
this.#watchState();
|
|
129
143
|
this.#connected = true;
|
|
130
|
-
this.#reconcile.
|
|
144
|
+
this.#reconcile.observe(this.element);
|
|
131
145
|
}
|
|
132
146
|
disconnect() {
|
|
133
147
|
this.#connected = false;
|
|
134
|
-
this.#reconcile.
|
|
135
|
-
this.
|
|
136
|
-
this.element.removeEventListener("focusin", this.#onFocusin);
|
|
148
|
+
this.#reconcile.disconnect();
|
|
149
|
+
this.#listeners.dispose();
|
|
137
150
|
this.#observer?.disconnect();
|
|
138
151
|
this.#observer = null;
|
|
139
152
|
}
|
|
140
|
-
/** Drops a runtime-added item from the Tab sequence before batch reconciliation. */
|
|
141
153
|
itemTargetConnected(item) {
|
|
142
154
|
if (!this.#connected) return;
|
|
143
155
|
item.tabIndex = -1;
|
|
144
156
|
this.#reconcile.schedule();
|
|
145
157
|
}
|
|
146
|
-
/** Re-establishes the single Tab stop after an item leaves the target set. */
|
|
147
158
|
itemTargetDisconnected() {
|
|
148
159
|
this.#reconcile.schedule();
|
|
149
160
|
}
|
|
150
|
-
/** Arrow keys move focus + the tab stop; Home/End jump to the ends. */
|
|
151
161
|
#onKeydown = (event) => {
|
|
152
162
|
if (event.defaultPrevented) return;
|
|
153
163
|
if (isReservedArrowChord(event)) return;
|
|
@@ -176,21 +186,14 @@ var RovingController = class extends Controller {
|
|
|
176
186
|
event.preventDefault();
|
|
177
187
|
this.#activate(next, true);
|
|
178
188
|
};
|
|
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
189
|
#onFocusin = (event) => {
|
|
185
190
|
const index = this.#indexOf(event.target);
|
|
186
191
|
if (index === -1 || !this.#reachable(index)) return;
|
|
187
192
|
this.#activate(index, false);
|
|
188
193
|
};
|
|
189
|
-
/** Resolves the item index owning an event target (the item or a descendant). */
|
|
190
194
|
#indexOf(target) {
|
|
191
195
|
return ownerIndex(this.itemTargets, target);
|
|
192
196
|
}
|
|
193
|
-
/** Makes `index` the tab stop (optionally focusing it), emitting `change` once. */
|
|
194
197
|
#activate(index, focus) {
|
|
195
198
|
const previous = this.#roving.activeIndex;
|
|
196
199
|
this.#roving.setActive(index, { focus });
|
|
@@ -198,16 +201,6 @@ var RovingController = class extends Controller {
|
|
|
198
201
|
this.dispatch("change", { detail: { index, item: this.itemTargets[index] } });
|
|
199
202
|
}
|
|
200
203
|
}
|
|
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
204
|
#ensureTabStop(followFocus) {
|
|
212
205
|
const items = this.itemTargets;
|
|
213
206
|
const focused = followFocus ? items.findIndex((item, i) => item === document.activeElement && this.#reachable(i)) : -1;
|
|
@@ -217,15 +210,6 @@ var RovingController = class extends Controller {
|
|
|
217
210
|
if (index === -1) return;
|
|
218
211
|
this.#roving.setActive(index);
|
|
219
212
|
}
|
|
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
213
|
#step(current, delta, wrap) {
|
|
230
214
|
const length = this.itemTargets.length;
|
|
231
215
|
let index = current;
|
|
@@ -237,23 +221,15 @@ var RovingController = class extends Controller {
|
|
|
237
221
|
}
|
|
238
222
|
return this.#reachable(current) ? current : this.#firstReachable();
|
|
239
223
|
}
|
|
240
|
-
/** Index of the first reachable item, or `-1`. */
|
|
241
224
|
#firstReachable() {
|
|
242
225
|
return this.itemTargets.findIndex((_item, i) => this.#reachable(i));
|
|
243
226
|
}
|
|
244
|
-
/** Index of the last reachable item, or `-1`. */
|
|
245
227
|
#lastReachable() {
|
|
246
228
|
for (let i = this.itemTargets.length - 1; i >= 0; i -= 1) {
|
|
247
229
|
if (this.#reachable(i)) return i;
|
|
248
230
|
}
|
|
249
231
|
return -1;
|
|
250
232
|
}
|
|
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
233
|
#reachable(index) {
|
|
258
234
|
const item = this.itemTargets[index];
|
|
259
235
|
if (!item) return false;
|
|
@@ -262,14 +238,6 @@ var RovingController = class extends Controller {
|
|
|
262
238
|
if (item.disabled) return false;
|
|
263
239
|
return !inheritsFieldsetDisabled(item);
|
|
264
240
|
}
|
|
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
241
|
#hidden(item) {
|
|
274
242
|
let node = item;
|
|
275
243
|
while (node && node !== this.element) {
|
|
@@ -278,12 +246,6 @@ var RovingController = class extends Controller {
|
|
|
278
246
|
}
|
|
279
247
|
return false;
|
|
280
248
|
}
|
|
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
249
|
#watchState() {
|
|
288
250
|
if (typeof MutationObserver === "undefined") return;
|
|
289
251
|
const observer = new MutationObserver(() => this.#reconcile.schedule());
|
|
@@ -300,5 +262,4 @@ var RovingController = class extends Controller {
|
|
|
300
262
|
};
|
|
301
263
|
|
|
302
264
|
export { RovingController };
|
|
303
|
-
//# sourceMappingURL=roving_controller.js.map
|
|
304
265
|
//# sourceMappingURL=roving_controller.js.map
|