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
data/dist/positioning/index.js
CHANGED
|
@@ -1,7 +1,114 @@
|
|
|
1
1
|
import { computePosition, autoUpdate, offset, flip, shift } from '@floating-ui/dom';
|
|
2
2
|
import { Controller } from '@hotwired/stimulus';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
var ListenerSet = class {
|
|
5
|
+
#abort = new AbortController();
|
|
6
|
+
add(target, type, handler, options) {
|
|
7
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
8
|
+
}
|
|
9
|
+
dispose() {
|
|
10
|
+
this.#abort.abort();
|
|
11
|
+
this.#abort = new AbortController();
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
var MicrotaskCoalescer = class {
|
|
16
|
+
#run;
|
|
17
|
+
#queued = false;
|
|
18
|
+
#active = false;
|
|
19
|
+
#generation = 0;
|
|
20
|
+
constructor(run) {
|
|
21
|
+
this.#run = run;
|
|
22
|
+
}
|
|
23
|
+
activate() {
|
|
24
|
+
this.#active = true;
|
|
25
|
+
}
|
|
26
|
+
cancel() {
|
|
27
|
+
this.#active = false;
|
|
28
|
+
this.#queued = false;
|
|
29
|
+
this.#generation += 1;
|
|
30
|
+
}
|
|
31
|
+
schedule() {
|
|
32
|
+
if (!this.#active || this.#queued) return;
|
|
33
|
+
this.#queued = true;
|
|
34
|
+
const generation = this.#generation;
|
|
35
|
+
queueMicrotask(() => {
|
|
36
|
+
if (generation !== this.#generation || !this.#queued || !this.#active) return;
|
|
37
|
+
this.#queued = false;
|
|
38
|
+
this.#run();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
var MorphRenderWatcher = class {
|
|
44
|
+
#listeners = new ListenerSet();
|
|
45
|
+
#pass;
|
|
46
|
+
#element = null;
|
|
47
|
+
#onMorph = () => this.#pass.schedule();
|
|
48
|
+
constructor(run) {
|
|
49
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
50
|
+
}
|
|
51
|
+
observe(element) {
|
|
52
|
+
if (this.#element === element) return;
|
|
53
|
+
this.disconnect();
|
|
54
|
+
this.#element = element;
|
|
55
|
+
this.#pass.activate();
|
|
56
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
57
|
+
}
|
|
58
|
+
schedule() {
|
|
59
|
+
this.#pass.schedule();
|
|
60
|
+
}
|
|
61
|
+
disconnect() {
|
|
62
|
+
this.#listeners.dispose();
|
|
63
|
+
this.#pass.cancel();
|
|
64
|
+
this.#element = null;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
var NUMBER_BOUNDS = {
|
|
69
|
+
finite: { finite: true }};
|
|
70
|
+
function matchesNumberBounds(value, bounds) {
|
|
71
|
+
if (!Number.isFinite(value)) {
|
|
72
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
73
|
+
if (direction === null) return false;
|
|
74
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
75
|
+
}
|
|
76
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
77
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
78
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
79
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
80
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function readNumber(raw, fallback, bounds) {
|
|
85
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
var NumberValueReader = class {
|
|
89
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
90
|
+
read(owner, name, raw, fallback, bounds) {
|
|
91
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
92
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
93
|
+
this.#lastRejected.delete(name);
|
|
94
|
+
return resolved;
|
|
95
|
+
}
|
|
96
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
97
|
+
const literal = owner.element.getAttribute(attribute);
|
|
98
|
+
if (literal === null) {
|
|
99
|
+
this.#lastRejected.delete(name);
|
|
100
|
+
return resolved;
|
|
101
|
+
}
|
|
102
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
103
|
+
this.#lastRejected.set(name, literal);
|
|
104
|
+
console.warn(
|
|
105
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return resolved;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
5
112
|
var PLACEMENTS = /* @__PURE__ */ new Set([
|
|
6
113
|
"top",
|
|
7
114
|
"top-start",
|
|
@@ -16,7 +123,8 @@ var PLACEMENTS = /* @__PURE__ */ new Set([
|
|
|
16
123
|
"left-start",
|
|
17
124
|
"left-end"
|
|
18
125
|
]);
|
|
19
|
-
var AnchoredController = class extends Controller {
|
|
126
|
+
var AnchoredController = class _AnchoredController extends Controller {
|
|
127
|
+
#numbers = new NumberValueReader();
|
|
20
128
|
static targets = ["anchor", "floating"];
|
|
21
129
|
static values = {
|
|
22
130
|
placement: { type: String, default: "bottom" },
|
|
@@ -27,32 +135,29 @@ var AnchoredController = class extends Controller {
|
|
|
27
135
|
strategy: { type: String, default: "absolute" },
|
|
28
136
|
active: { type: Boolean, default: true }
|
|
29
137
|
};
|
|
138
|
+
static valueConstraints = {
|
|
139
|
+
offset: NUMBER_BOUNDS.finite,
|
|
140
|
+
padding: NUMBER_BOUNDS.finite
|
|
141
|
+
};
|
|
30
142
|
static events = ["position"];
|
|
31
|
-
/** `autoUpdate` cleanup while tracking; `null` when detached. */
|
|
32
143
|
#stop = null;
|
|
33
|
-
/** Identity of the live attach; `null` when detached — see {@link #onComputed}. */
|
|
34
144
|
#attachId = null;
|
|
35
|
-
/** True between connect and disconnect (Stimulus may fire value callbacks before connect). */
|
|
36
145
|
#connected = false;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* a value no serialization produces, so it can never match a real key.
|
|
40
|
-
*/
|
|
146
|
+
#position = null;
|
|
147
|
+
#morphRender = new MorphRenderWatcher(() => this.#sync());
|
|
41
148
|
#appliedKey = "";
|
|
42
|
-
/** Elements the live observer holds, or `null` when detached — see {@link #sync}. */
|
|
43
149
|
#appliedAnchor = null;
|
|
44
150
|
#appliedFloating = null;
|
|
45
151
|
connect() {
|
|
152
|
+
this.#morphRender.observe(this.element);
|
|
46
153
|
this.#connected = true;
|
|
47
154
|
this.#sync();
|
|
48
155
|
}
|
|
49
156
|
disconnect() {
|
|
157
|
+
this.#morphRender.disconnect();
|
|
50
158
|
this.#connected = false;
|
|
51
159
|
this.#sync();
|
|
52
160
|
}
|
|
53
|
-
// Every value change (active or an option) and every target arrival or
|
|
54
|
-
// departure re-syncs. `#sync` is idempotent and order-independent, so no Value
|
|
55
|
-
// has to be declared in a particular position.
|
|
56
161
|
anchorTargetConnected() {
|
|
57
162
|
this.#sync();
|
|
58
163
|
}
|
|
@@ -86,41 +191,23 @@ var AnchoredController = class extends Controller {
|
|
|
86
191
|
strategyValueChanged() {
|
|
87
192
|
this.#sync();
|
|
88
193
|
}
|
|
89
|
-
/** Current Values mapped to the positioning engine's options. */
|
|
90
194
|
get #options() {
|
|
91
195
|
return {
|
|
92
|
-
// Narrow every free-form Value to what the engine can use. A placement
|
|
93
|
-
// outside the set would be published on the hook as a resolved side it is
|
|
94
|
-
// not, and a non-finite distance poisons the coordinate it feeds until the
|
|
95
|
-
// browser drops the whole declaration and leaves that axis unplaced.
|
|
96
196
|
placement: PLACEMENTS.has(this.placementValue) ? this.placementValue : "bottom",
|
|
97
|
-
offset:
|
|
197
|
+
offset: this.#safeOffset,
|
|
98
198
|
flip: this.flipValue,
|
|
99
199
|
shift: this.shiftValue,
|
|
100
|
-
padding:
|
|
200
|
+
padding: this.#safePadding,
|
|
101
201
|
strategy: this.strategyValue === "fixed" ? "fixed" : "absolute"
|
|
102
202
|
};
|
|
103
203
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Reconciles the live observer with the desired state — track iff connected,
|
|
106
|
-
* `active`, and both targets exist — re-attaching only when that state, the
|
|
107
|
-
* options, or the elements actually changed. Stimulus fires the value-changed
|
|
108
|
-
* callbacks on connect in declaration order and may run them before or after
|
|
109
|
-
* `connect()`; keying on what is applied collapses that whole burst (in any
|
|
110
|
-
* order) to a single attach, while an option or target change at runtime
|
|
111
|
-
* re-attaches exactly once. So correctness never depends on `active` being
|
|
112
|
-
* declared last. The elements are part of the key because the engine holds the
|
|
113
|
-
* pair it was handed: a swap leaves the same options behind and would otherwise
|
|
114
|
-
* keep measuring the node that just left the document.
|
|
115
|
-
*
|
|
116
|
-
* @stimeoRenderRoot
|
|
117
|
-
*/
|
|
118
204
|
#sync() {
|
|
119
205
|
const shouldTrack = this.#connected && this.activeValue && this.hasAnchorTarget && this.hasFloatingTarget;
|
|
120
206
|
const anchor = shouldTrack ? this.anchorTarget : null;
|
|
121
207
|
const floating = shouldTrack ? this.floatingTarget : null;
|
|
122
208
|
const key = JSON.stringify(this.#options);
|
|
123
209
|
if (key === this.#appliedKey && anchor === this.#appliedAnchor && floating === this.#appliedFloating) {
|
|
210
|
+
if (floating && this.#position) this.#reflectPosition(floating, this.#position);
|
|
124
211
|
return;
|
|
125
212
|
}
|
|
126
213
|
this.#detach();
|
|
@@ -143,27 +230,42 @@ var AnchoredController = class extends Controller {
|
|
|
143
230
|
this.#stop?.();
|
|
144
231
|
this.#stop = null;
|
|
145
232
|
this.#attachId = null;
|
|
233
|
+
this.#position = null;
|
|
146
234
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Reflects the resolved side onto the CSS hook and announces the placement.
|
|
149
|
-
*
|
|
150
|
-
* The pass carries the attach that started it and the element it positioned,
|
|
151
|
-
* and lands only while that attach is still the live one: `autoUpdate`'s
|
|
152
|
-
* cleanup stops further updates but cannot cancel one already computing, so a
|
|
153
|
-
* pass superseded mid-flight would otherwise write and dispatch afterwards.
|
|
154
|
-
* The element cannot stand in for that identity — an option change re-attaches
|
|
155
|
-
* against the very same pair.
|
|
156
|
-
*/
|
|
157
235
|
#onComputed(id, floating, result) {
|
|
158
236
|
if (id !== this.#attachId) return;
|
|
159
|
-
|
|
237
|
+
this.#position = result;
|
|
238
|
+
this.#reflectPosition(floating, result);
|
|
160
239
|
this.dispatch("position", {
|
|
161
240
|
detail: { placement: result.placement, x: result.x, y: result.y }
|
|
162
241
|
});
|
|
163
242
|
}
|
|
243
|
+
#reflectPosition(floating, result) {
|
|
244
|
+
floating.setAttribute("data-anchored-placement", result.placement);
|
|
245
|
+
floating.style.position = this.#options.strategy ?? "absolute";
|
|
246
|
+
floating.style.left = `${result.x}px`;
|
|
247
|
+
floating.style.top = `${result.y}px`;
|
|
248
|
+
}
|
|
249
|
+
get #safeOffset() {
|
|
250
|
+
return this.#numbers.read(
|
|
251
|
+
this,
|
|
252
|
+
"offset",
|
|
253
|
+
this.offsetValue,
|
|
254
|
+
_AnchoredController.values.offset.default,
|
|
255
|
+
_AnchoredController.valueConstraints.offset
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
get #safePadding() {
|
|
259
|
+
return this.#numbers.read(
|
|
260
|
+
this,
|
|
261
|
+
"padding",
|
|
262
|
+
this.paddingValue,
|
|
263
|
+
_AnchoredController.values.padding.default,
|
|
264
|
+
_AnchoredController.valueConstraints.padding
|
|
265
|
+
);
|
|
266
|
+
}
|
|
164
267
|
};
|
|
165
268
|
|
|
166
|
-
// src/positioning/index.ts
|
|
167
269
|
function buildMiddleware(options) {
|
|
168
270
|
const padding = options.padding ?? 0;
|
|
169
271
|
const middleware = [];
|
|
@@ -202,5 +304,4 @@ function registerPositioning(application) {
|
|
|
202
304
|
}
|
|
203
305
|
|
|
204
306
|
export { AnchoredController, attachPositioning, position, positioningControllers, registerPositioning };
|
|
205
|
-
//# sourceMappingURL=index.js.map
|
|
206
307
|
//# sourceMappingURL=index.js.map
|
data/lib/stimeo/ui/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stimeo-ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stimeo Labs
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|
|
@@ -119,7 +119,7 @@ files:
|
|
|
119
119
|
- dist/controllers/read_more_controller.js
|
|
120
120
|
- dist/controllers/reading_progress_controller.js
|
|
121
121
|
- dist/controllers/relative_time_controller.js
|
|
122
|
-
- dist/controllers/
|
|
122
|
+
- dist/controllers/reset_on_restore_controller.js
|
|
123
123
|
- dist/controllers/resizable_controller.js
|
|
124
124
|
- dist/controllers/roving_controller.js
|
|
125
125
|
- dist/controllers/scroll_area_controller.js
|