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,117 +1,98 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/optimistic_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/detach_gate.ts
|
|
6
3
|
var DetachGate = class _DetachGate {
|
|
7
|
-
/** Set while a probe is queued, waiting for a reconnect to cancel it. */
|
|
8
4
|
#pending = false;
|
|
9
|
-
/**
|
|
10
|
-
* True while a probe is queued — the last disconnect was ambiguous and no
|
|
11
|
-
* reconnect has cancelled it yet. Read it from `connect()` to tell the
|
|
12
|
-
* reconnect half of an in-page move from a first connect: a controller whose
|
|
13
|
-
* initialisation restarts a measurement (a min-duration floor, an elapsed
|
|
14
|
-
* counter) must skip it for the move, where nothing actually restarted.
|
|
15
|
-
*/
|
|
16
5
|
get pending() {
|
|
17
6
|
return this.#pending;
|
|
18
7
|
}
|
|
19
|
-
/**
|
|
20
|
-
* True when the disconnect is definitely a real detach — the element left
|
|
21
|
-
* the document, or `data-controller` no longer lists the identifier. False
|
|
22
|
-
* means ambiguous (in-page move or observed-root exit), NOT "alive".
|
|
23
|
-
*/
|
|
24
8
|
static isDetached(host) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return !tokens.includes(host.identifier);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Call from `disconnect()`: runs `teardown` synchronously on a definite
|
|
31
|
-
* detach (fast path), otherwise defers it one microtask — a reconnect
|
|
32
|
-
* ({@link cancel} from `connect()`) keeps the state, no reconnect runs it.
|
|
33
|
-
* One microtask is the whole probe window: Stimulus reconnects a moved
|
|
34
|
-
* element within the same mutation batch, before the checkpoint drains.
|
|
35
|
-
*/
|
|
9
|
+
return !host.element.isConnected || !_DetachGate.#listed(host);
|
|
10
|
+
}
|
|
36
11
|
disconnected(host, teardown) {
|
|
37
|
-
|
|
12
|
+
const carried = _DetachGate.#carried(host);
|
|
13
|
+
if (!carried && _DetachGate.isDetached(host)) {
|
|
38
14
|
this.#pending = false;
|
|
39
15
|
teardown();
|
|
40
16
|
return;
|
|
41
17
|
}
|
|
42
18
|
this.#pending = true;
|
|
43
|
-
|
|
19
|
+
const probe = () => {
|
|
44
20
|
if (!this.#pending) return;
|
|
45
21
|
this.#pending = false;
|
|
46
22
|
teardown();
|
|
47
|
-
}
|
|
23
|
+
};
|
|
24
|
+
if (carried) setTimeout(probe, 0);
|
|
25
|
+
else queueMicrotask(probe);
|
|
26
|
+
}
|
|
27
|
+
static #carried(host) {
|
|
28
|
+
const element = host.element;
|
|
29
|
+
return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
|
|
30
|
+
}
|
|
31
|
+
static #listed(host) {
|
|
32
|
+
const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
|
|
33
|
+
return tokens.includes(host.identifier);
|
|
48
34
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Disarms a pending probe. Call from `connect()` (the reconnect that proves
|
|
51
|
-
* an in-page move) and from the head of any teardown path not routed through
|
|
52
|
-
* {@link disconnected} (disabled-toggle, Escape), so an orphaned probe can
|
|
53
|
-
* never run the teardown a second time.
|
|
54
|
-
*/
|
|
55
35
|
cancel() {
|
|
56
36
|
this.#pending = false;
|
|
57
37
|
}
|
|
58
38
|
};
|
|
59
39
|
|
|
60
|
-
// src/utils/listener_set.ts
|
|
61
40
|
var ListenerSet = class {
|
|
62
|
-
/** The generation every `add` joins until the next `dispose()`. */
|
|
63
41
|
#abort = new AbortController();
|
|
64
|
-
/**
|
|
65
|
-
* Attaches `handler` to the open generation, exactly as the caller spelled it.
|
|
66
|
-
*
|
|
67
|
-
* The set supplies the signal, so `options` carries everything else the DOM
|
|
68
|
-
* accepts — `capture` included, which has to match at release time and no
|
|
69
|
-
* longer has a second place to drift from.
|
|
70
|
-
*/
|
|
71
42
|
add(target, type, handler, options) {
|
|
72
43
|
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
73
44
|
}
|
|
74
|
-
/**
|
|
75
|
-
* Releases every listener of the open generation, synchronously, and opens the
|
|
76
|
-
* next one. Idempotent, and safe before anything has been added.
|
|
77
|
-
*/
|
|
78
45
|
dispose() {
|
|
79
46
|
this.#abort.abort();
|
|
80
47
|
this.#abort = new AbortController();
|
|
81
48
|
}
|
|
82
49
|
};
|
|
83
50
|
|
|
84
|
-
|
|
51
|
+
var SubmissionOwner = class {
|
|
52
|
+
#synthetic = /* @__PURE__ */ Symbol("synthetic submission");
|
|
53
|
+
#active = null;
|
|
54
|
+
begin(event) {
|
|
55
|
+
this.#active = { source: event.target, token: this.#tokenOf(event) };
|
|
56
|
+
}
|
|
57
|
+
resolve(event) {
|
|
58
|
+
if (this.#active === null || this.#active.source !== event.target || this.#active.token !== this.#tokenOf(event)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
this.clear();
|
|
62
|
+
return this.#detailOf(event)?.success === true;
|
|
63
|
+
}
|
|
64
|
+
clear() {
|
|
65
|
+
this.#active = null;
|
|
66
|
+
}
|
|
67
|
+
#tokenOf(event) {
|
|
68
|
+
return this.#detailOf(event)?.formSubmission ?? this.#synthetic;
|
|
69
|
+
}
|
|
70
|
+
#detailOf(event) {
|
|
71
|
+
return event.detail;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
85
75
|
var TransientHooks = class {
|
|
86
76
|
#attributes;
|
|
87
77
|
constructor(options) {
|
|
88
78
|
this.#attributes = options.attributes;
|
|
89
79
|
}
|
|
90
|
-
/** Drops the declared hooks from `element`; what it carries besides stays. */
|
|
91
80
|
reset(element) {
|
|
92
81
|
for (const attribute of this.#attributes) element.removeAttribute(attribute);
|
|
93
82
|
}
|
|
94
83
|
};
|
|
95
84
|
|
|
96
|
-
// src/controllers/optimistic_controller.ts
|
|
97
85
|
var TRANSIENT = new TransientHooks({ attributes: ["data-optimistic"] });
|
|
98
86
|
var HIDDEN_MARKER = "data-optimistic-toggled";
|
|
99
87
|
var BUSY_MARKER = "data-optimistic-busy";
|
|
100
88
|
var AUTHORED_ABSENT = "absent";
|
|
101
89
|
var AUTHORED_VALUE = "value:";
|
|
102
|
-
var SYNTHETIC_SUBMISSION = {};
|
|
103
|
-
function submissionOf(event) {
|
|
104
|
-
const detail = event.detail;
|
|
105
|
-
return detail?.formSubmission ?? SYNTHETIC_SUBMISSION;
|
|
106
|
-
}
|
|
107
90
|
var OptimisticController = class extends Controller {
|
|
108
91
|
static targets = ["show", "hide"];
|
|
109
92
|
static events = ["commit", "rollback"];
|
|
110
|
-
|
|
111
|
-
#pending = null;
|
|
93
|
+
#submission = new SubmissionOwner();
|
|
112
94
|
#gate = new DetachGate();
|
|
113
95
|
#listeners = new ListenerSet();
|
|
114
|
-
/** True between `connect()` and `disconnect()`, so a repeat connect rewinds nothing. */
|
|
115
96
|
#connected = false;
|
|
116
97
|
connect() {
|
|
117
98
|
const restored = !this.#connected && !this.#gate.pending;
|
|
@@ -125,11 +106,11 @@ var OptimisticController = class extends Controller {
|
|
|
125
106
|
this.#connected = false;
|
|
126
107
|
this.#listeners.dispose();
|
|
127
108
|
this.#gate.disconnected(this, () => {
|
|
128
|
-
this.#
|
|
109
|
+
this.#submission.clear();
|
|
129
110
|
});
|
|
130
111
|
}
|
|
131
112
|
#onSubmitStart = (event) => {
|
|
132
|
-
this.#
|
|
113
|
+
this.#submission.begin(event);
|
|
133
114
|
if (this.element instanceof HTMLFormElement && !this.element.hasAttribute(BUSY_MARKER)) {
|
|
134
115
|
this.element.setAttribute(BUSY_MARKER, AUTHORED_ABSENT);
|
|
135
116
|
}
|
|
@@ -139,9 +120,8 @@ var OptimisticController = class extends Controller {
|
|
|
139
120
|
for (const target of this.hideTargets) this.#setHidden(target, true);
|
|
140
121
|
};
|
|
141
122
|
#onSubmitEnd = (event) => {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const success = event.detail?.success === true;
|
|
123
|
+
const success = this.#submission.resolve(event);
|
|
124
|
+
if (success === null) return;
|
|
145
125
|
if (success) {
|
|
146
126
|
this.element.removeAttribute("data-optimistic");
|
|
147
127
|
this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
|
|
@@ -154,12 +134,10 @@ var OptimisticController = class extends Controller {
|
|
|
154
134
|
this.dispatch("rollback");
|
|
155
135
|
}
|
|
156
136
|
};
|
|
157
|
-
/** Hides or reveals a target, recording the authored `hidden` on first write. */
|
|
158
137
|
#setHidden(target, hidden) {
|
|
159
138
|
if (target.hasAttribute("hidden") === hidden) return;
|
|
160
139
|
this.#write(target, "hidden", hidden ? "" : null, HIDDEN_MARKER);
|
|
161
140
|
}
|
|
162
|
-
/** Writes an attribute, recording what it displaced under `marker` once. */
|
|
163
141
|
#write(element, attribute, value, marker) {
|
|
164
142
|
if (!element.hasAttribute(marker)) {
|
|
165
143
|
const authored = element.getAttribute(attribute);
|
|
@@ -171,16 +149,6 @@ var OptimisticController = class extends Controller {
|
|
|
171
149
|
if (value === null) element.removeAttribute(attribute);
|
|
172
150
|
else element.setAttribute(attribute, value);
|
|
173
151
|
}
|
|
174
|
-
/**
|
|
175
|
-
* Puts back the value `marker` recorded and drops the record.
|
|
176
|
-
*
|
|
177
|
-
* `written` is what this controller last put in the attribute. Anything else
|
|
178
|
-
* there now belongs to whoever wrote it — Turbo owns `aria-busy` on a form and
|
|
179
|
-
* clears it before the terminal arrives, and a consumer may have moved a face
|
|
180
|
-
* mid-flight — so the record is dropped without touching the attribute. A
|
|
181
|
-
* marker this build did not write names no authored value, so the attribute
|
|
182
|
-
* goes back to being absent.
|
|
183
|
-
*/
|
|
184
152
|
#restore(element, attribute, marker, written) {
|
|
185
153
|
const recorded = element.getAttribute(marker);
|
|
186
154
|
if (recorded === null) return;
|
|
@@ -192,15 +160,6 @@ var OptimisticController = class extends Controller {
|
|
|
192
160
|
}
|
|
193
161
|
element.removeAttribute(attribute);
|
|
194
162
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Puts back exactly the markup this controller displaced (record-owned only).
|
|
197
|
-
*
|
|
198
|
-
* A face can be registered on both sides, and the hide pass runs last, so what
|
|
199
|
-
* this controller wrote there is `hidden` — matching it against the reveal's
|
|
200
|
-
* absent value instead would read as someone else's write and leave the face
|
|
201
|
-
* hidden. Each target is therefore restored once, against the write it last
|
|
202
|
-
* received.
|
|
203
|
-
*/
|
|
204
163
|
#revert() {
|
|
205
164
|
TRANSIENT.reset(this.element);
|
|
206
165
|
this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
|
|
@@ -212,5 +171,4 @@ var OptimisticController = class extends Controller {
|
|
|
212
171
|
};
|
|
213
172
|
|
|
214
173
|
export { OptimisticController };
|
|
215
|
-
//# sourceMappingURL=optimistic_controller.js.map
|
|
216
174
|
//# sourceMappingURL=optimistic_controller.js.map
|