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,8 +1,152 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function sharedRegistry(key, create) {
|
|
4
|
+
const symbol = Symbol.for(key);
|
|
5
|
+
const scope = globalThis;
|
|
6
|
+
const existing = scope[symbol];
|
|
7
|
+
if (existing !== void 0) return existing;
|
|
8
|
+
const registry = create();
|
|
9
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
10
|
+
return registry;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isAttributeValue(value) {
|
|
14
|
+
return value === null || typeof value === "string";
|
|
15
|
+
}
|
|
16
|
+
function readLeaseRecord(element, record) {
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
19
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
20
|
+
const [original, written, ...rest] = parsed;
|
|
21
|
+
const linked = rest[0] !== false;
|
|
22
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
23
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
24
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
25
|
+
} catch {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var AttributeLease = class _AttributeLease {
|
|
30
|
+
static #registry = sharedRegistry(
|
|
31
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
32
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
33
|
+
);
|
|
34
|
+
#attribute;
|
|
35
|
+
#record;
|
|
36
|
+
#base;
|
|
37
|
+
#held = /* @__PURE__ */ new Set();
|
|
38
|
+
constructor(attribute, owner, options = {}) {
|
|
39
|
+
this.#attribute = attribute;
|
|
40
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
41
|
+
this.#base = options.base === true;
|
|
42
|
+
const names = _AttributeLease.#registry.names;
|
|
43
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
44
|
+
}
|
|
45
|
+
write(element, value) {
|
|
46
|
+
const stack = this.#stack(element);
|
|
47
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
48
|
+
this.#held.add(element);
|
|
49
|
+
const shows = !this.#covered(element, stack, hold);
|
|
50
|
+
hold.written = value;
|
|
51
|
+
this.#mark(element, stack);
|
|
52
|
+
if (shows) this.#reflect(element, value);
|
|
53
|
+
}
|
|
54
|
+
return(element) {
|
|
55
|
+
const held = this.#held.delete(element);
|
|
56
|
+
const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
|
|
57
|
+
const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
|
|
58
|
+
const hold = this.#take(stack);
|
|
59
|
+
if (!hold) return false;
|
|
60
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
61
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
62
|
+
const index = stack.indexOf(hold);
|
|
63
|
+
stack.splice(index, 1);
|
|
64
|
+
const above = stack[index];
|
|
65
|
+
if (above) above.linked &&= hold.linked;
|
|
66
|
+
this.#mark(element, stack);
|
|
67
|
+
if (!owns) return true;
|
|
68
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
69
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
returnAll() {
|
|
73
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
74
|
+
}
|
|
75
|
+
#stack(element) {
|
|
76
|
+
const stacks = _AttributeLease.#registry.stacks;
|
|
77
|
+
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
78
|
+
stacks.set(element, byAttribute);
|
|
79
|
+
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
80
|
+
byAttribute.set(this.#attribute, stack);
|
|
81
|
+
return stack;
|
|
82
|
+
}
|
|
83
|
+
#seed(element) {
|
|
84
|
+
const found = [];
|
|
85
|
+
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
86
|
+
const read = readLeaseRecord(element, record);
|
|
87
|
+
if (read) found.push({ ...read, record });
|
|
88
|
+
}
|
|
89
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
90
|
+
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
91
|
+
lease: null,
|
|
92
|
+
record,
|
|
93
|
+
written,
|
|
94
|
+
original,
|
|
95
|
+
linked: linked && index > 0
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
#take(stack) {
|
|
99
|
+
const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
|
|
100
|
+
if (hold) hold.lease = this;
|
|
101
|
+
return hold;
|
|
102
|
+
}
|
|
103
|
+
#acquire(element, stack) {
|
|
104
|
+
const current = element.getAttribute(this.#attribute);
|
|
105
|
+
const top = stack.at(-1);
|
|
106
|
+
const bottom = stack[0];
|
|
107
|
+
const over = top?.written === current ? top : void 0;
|
|
108
|
+
const from = this.#base ? bottom : over;
|
|
109
|
+
const hold = {
|
|
110
|
+
lease: this,
|
|
111
|
+
record: this.#record,
|
|
112
|
+
written: current,
|
|
113
|
+
original: from ? from.original : current,
|
|
114
|
+
linked: !this.#base && over !== void 0
|
|
115
|
+
};
|
|
116
|
+
if (this.#base && bottom) {
|
|
117
|
+
bottom.linked = true;
|
|
118
|
+
stack.unshift(hold);
|
|
119
|
+
} else stack.push(hold);
|
|
120
|
+
return hold;
|
|
121
|
+
}
|
|
122
|
+
#covered(element, stack, hold) {
|
|
123
|
+
const current = element.getAttribute(this.#attribute);
|
|
124
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
125
|
+
}
|
|
126
|
+
#mark(element, stack) {
|
|
127
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
128
|
+
stack.forEach((hold, index) => {
|
|
129
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
130
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
131
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
132
|
+
records.set(
|
|
133
|
+
hold.record,
|
|
134
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
for (const [name, recorded] of records) {
|
|
138
|
+
if (element.getAttribute(name) === recorded) continue;
|
|
139
|
+
if (recorded === null) element.removeAttribute(name);
|
|
140
|
+
else element.setAttribute(name, recorded);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
#reflect(element, value) {
|
|
144
|
+
if (element.getAttribute(this.#attribute) === value) return;
|
|
145
|
+
if (value === null) element.removeAttribute(this.#attribute);
|
|
146
|
+
else element.setAttribute(this.#attribute, value);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
4
149
|
|
|
5
|
-
// src/utils/focus_candidate.ts
|
|
6
150
|
function inheritsFieldsetDisabled(control) {
|
|
7
151
|
let fieldset = control.closest("fieldset[disabled]");
|
|
8
152
|
while (fieldset) {
|
|
@@ -12,8 +156,19 @@ function inheritsFieldsetDisabled(control) {
|
|
|
12
156
|
}
|
|
13
157
|
return false;
|
|
14
158
|
}
|
|
159
|
+
function unslotted(element) {
|
|
160
|
+
return element.assignedSlot === null && element.parentElement?.shadowRoot != null;
|
|
161
|
+
}
|
|
162
|
+
function flatTreeParent(element) {
|
|
163
|
+
if (unslotted(element)) return null;
|
|
164
|
+
const parent = element.assignedSlot ?? element.parentNode;
|
|
165
|
+
if (parent instanceof ShadowRoot) return parent.host;
|
|
166
|
+
return parent instanceof Element ? parent : null;
|
|
167
|
+
}
|
|
15
168
|
function canTakeFocus(element) {
|
|
16
|
-
|
|
169
|
+
for (let node = element; node; node = flatTreeParent(node)) {
|
|
170
|
+
if (unslotted(node) || node.matches("[hidden], [inert]")) return false;
|
|
171
|
+
}
|
|
17
172
|
if (element instanceof HTMLInputElement && element.type === "hidden") return false;
|
|
18
173
|
if (!("disabled" in element)) return true;
|
|
19
174
|
if (element.disabled) return false;
|
|
@@ -76,7 +231,6 @@ function tabStopsWithin(root) {
|
|
|
76
231
|
);
|
|
77
232
|
}
|
|
78
233
|
|
|
79
|
-
// src/controllers/dismissible_controller.ts
|
|
80
234
|
var DismissibleController = class extends Controller {
|
|
81
235
|
static targets = ["root", "fallback"];
|
|
82
236
|
static values = {
|
|
@@ -85,25 +239,32 @@ var DismissibleController = class extends Controller {
|
|
|
85
239
|
};
|
|
86
240
|
static actions = ["dismiss"];
|
|
87
241
|
static events = ["dismiss"];
|
|
242
|
+
#openDefault = new AttributeLease("data-state", this.identifier);
|
|
243
|
+
#connected = false;
|
|
88
244
|
connect() {
|
|
89
|
-
|
|
90
|
-
if (!root.hasAttribute("data-state")) {
|
|
91
|
-
root.setAttribute("data-state", "open");
|
|
92
|
-
}
|
|
245
|
+
this.#establishOpen(this.#root);
|
|
93
246
|
this.#syncEscapeListener();
|
|
247
|
+
this.#connected = true;
|
|
94
248
|
}
|
|
95
249
|
disconnect() {
|
|
250
|
+
this.#connected = false;
|
|
96
251
|
this.element.removeEventListener("keydown", this.#onKeydown);
|
|
97
252
|
}
|
|
98
|
-
|
|
253
|
+
rootTargetConnected(root) {
|
|
254
|
+
if (!this.#connected) return;
|
|
255
|
+
if (!this.rootTargets.includes(this.element)) this.#openDefault.return(this.element);
|
|
256
|
+
this.#establishOpen(root);
|
|
257
|
+
}
|
|
258
|
+
rootTargetDisconnected(root) {
|
|
259
|
+
if (!this.rootTargets.includes(root)) this.#openDefault.return(root);
|
|
260
|
+
if (this.#connected && this.hasRootTarget) this.#establishOpen(this.rootTarget);
|
|
261
|
+
}
|
|
99
262
|
closeOnEscapeValueChanged() {
|
|
100
263
|
this.#syncEscapeListener();
|
|
101
264
|
}
|
|
102
|
-
/** Dismisses the element. Bound via `data-action` (click on the close button). */
|
|
103
265
|
dismiss() {
|
|
104
266
|
this.#performDismiss();
|
|
105
267
|
}
|
|
106
|
-
/** Dismisses on Escape when `closeOnEscape` is set and focus is inside. */
|
|
107
268
|
#onKeydown = (event) => {
|
|
108
269
|
if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
|
|
109
270
|
if (!this.closeOnEscapeValue) return;
|
|
@@ -112,18 +273,18 @@ var DismissibleController = class extends Controller {
|
|
|
112
273
|
event.preventDefault();
|
|
113
274
|
this.#performDismiss();
|
|
114
275
|
};
|
|
115
|
-
/** Adds or removes the one stable listener reference without duplicating it. */
|
|
116
276
|
#syncEscapeListener() {
|
|
117
277
|
this.element.removeEventListener("keydown", this.#onKeydown);
|
|
118
278
|
if (this.closeOnEscapeValue) {
|
|
119
279
|
this.element.addEventListener("keydown", this.#onKeydown);
|
|
120
280
|
}
|
|
121
281
|
}
|
|
122
|
-
|
|
282
|
+
#establishOpen(root) {
|
|
283
|
+
if (!root.hasAttribute("data-state")) this.#openDefault.write(root, "open");
|
|
284
|
+
}
|
|
123
285
|
get #root() {
|
|
124
286
|
return this.hasRootTarget ? this.rootTarget : this.element;
|
|
125
287
|
}
|
|
126
|
-
/** @stimeoRuntimeOnly `mode` decides how this one dismissal takes the element away. */
|
|
127
288
|
#performDismiss() {
|
|
128
289
|
const root = this.#root;
|
|
129
290
|
const mode = this.modeValue === "hide" ? "hide" : "remove";
|
|
@@ -136,10 +297,6 @@ var DismissibleController = class extends Controller {
|
|
|
136
297
|
root.remove();
|
|
137
298
|
}
|
|
138
299
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Moves focus out of `root` *before* it is removed, but only when focus is
|
|
141
|
-
* actually inside it — otherwise the user's place elsewhere is left undisturbed.
|
|
142
|
-
*/
|
|
143
300
|
#retreatFocus(root) {
|
|
144
301
|
const active = document.activeElement;
|
|
145
302
|
if (!(active instanceof HTMLElement) || !root.contains(active)) return;
|
|
@@ -149,7 +306,6 @@ var DismissibleController = class extends Controller {
|
|
|
149
306
|
}
|
|
150
307
|
document.body.focus();
|
|
151
308
|
}
|
|
152
|
-
/** Yields available focus fallbacks in precedence order, stopping after focus succeeds. */
|
|
153
309
|
*#focusFallbacks(root) {
|
|
154
310
|
const explicitFallback = this.hasFallbackTarget ? this.fallbackTarget : null;
|
|
155
311
|
if (explicitFallback && !root.contains(explicitFallback) && this.#isExplicitFocusAvailable(explicitFallback)) {
|
|
@@ -171,7 +327,6 @@ var DismissibleController = class extends Controller {
|
|
|
171
327
|
yield element;
|
|
172
328
|
}
|
|
173
329
|
}
|
|
174
|
-
/** Whether an explicit fallback can receive programmatic focus right now. */
|
|
175
330
|
#isExplicitFocusAvailable(element) {
|
|
176
331
|
const programmaticallyFocusable = element.hasAttribute("tabindex") || isTabStop(element);
|
|
177
332
|
return programmaticallyFocusable && canTakeFocus(element) && isRenderedForFocus(element);
|
|
@@ -179,5 +334,4 @@ var DismissibleController = class extends Controller {
|
|
|
179
334
|
};
|
|
180
335
|
|
|
181
336
|
export { DismissibleController };
|
|
182
|
-
//# sourceMappingURL=dismissible_controller.js.map
|
|
183
337
|
//# sourceMappingURL=dismissible_controller.js.map
|