stimeo-ui 0.17.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 +106 -1
- data/README.md +19 -10
- data/dist/cable/index.js +22 -14
- data/dist/controllers/accordion_controller.js +14 -6
- data/dist/controllers/alert_dialog_controller.js +145 -118
- data/dist/controllers/announcer_controller.js +113 -17
- data/dist/controllers/auto_submit_controller.js +185 -60
- data/dist/controllers/avatar_controller.js +55 -43
- data/dist/controllers/bulk_select_controller.js +64 -50
- data/dist/controllers/calendar_controller.js +55 -53
- data/dist/controllers/carousel_controller.js +124 -86
- data/dist/controllers/character_counter_controller.js +291 -95
- data/dist/controllers/checkbox_controller.js +6 -0
- data/dist/controllers/clipboard_controller.js +118 -27
- data/dist/controllers/collapsible_controller.js +52 -49
- data/dist/controllers/color_picker_controller.js +29 -7
- data/dist/controllers/combobox_controller.js +210 -71
- data/dist/controllers/command_palette_controller.js +289 -140
- data/dist/controllers/conditional_fields_controller.js +145 -58
- data/dist/controllers/confirm_controller.js +145 -118
- data/dist/controllers/context_menu_controller.js +138 -73
- data/dist/controllers/countdown_controller.js +109 -21
- data/dist/controllers/currency_input_controller.js +446 -72
- data/dist/controllers/data_grid_controller.js +134 -28
- data/dist/controllers/date_range_picker_controller.js +93 -72
- data/dist/controllers/dialog_controller.js +145 -118
- data/dist/controllers/direct_upload_controller.js +24 -14
- data/dist/controllers/dirty_form_controller.js +68 -31
- data/dist/controllers/dismissible_controller.js +64 -46
- data/dist/controllers/drawer_controller.js +145 -118
- data/dist/controllers/dropdown_controller.js +76 -63
- data/dist/controllers/editable_controller.js +199 -62
- data/dist/controllers/empty_state_controller.js +13 -6
- data/dist/controllers/file_dropzone_controller.js +55 -48
- data/dist/controllers/filter_controller.js +9 -2
- data/dist/controllers/flash_controller.js +66 -33
- data/dist/controllers/focus_controller.js +39 -14
- data/dist/controllers/form_field_controller.js +52 -43
- data/dist/controllers/form_validation_controller.js +18 -11
- data/dist/controllers/frame_loading_controller.js +55 -48
- data/dist/controllers/hover_card_controller.js +67 -61
- data/dist/controllers/idle_controller.js +10 -6
- data/dist/controllers/input_mask_controller.js +411 -24
- data/dist/controllers/intersection_controller.js +3 -0
- data/dist/controllers/lazy_frame_controller.js +15 -3
- data/dist/controllers/listbox_controller.js +260 -79
- data/dist/controllers/local_time_controller.js +48 -13
- data/dist/controllers/masonry_controller.js +11 -4
- data/dist/controllers/menu_controller.js +138 -82
- data/dist/controllers/menubar_controller.js +65 -19
- data/dist/controllers/meter_controller.js +270 -24
- data/dist/controllers/multi_select_controller.js +251 -94
- data/dist/controllers/navigation_menu_controller.js +67 -19
- data/dist/controllers/nested_form_controller.js +98 -64
- data/dist/controllers/network_status_controller.js +70 -52
- data/dist/controllers/number_input_controller.js +344 -94
- data/dist/controllers/optimistic_controller.js +29 -11
- data/dist/controllers/otp_controller.js +502 -104
- data/dist/controllers/overflow_indicator_controller.js +6 -0
- data/dist/controllers/overflow_menu_controller.js +136 -21
- data/dist/controllers/pagination_controller.js +47 -14
- data/dist/controllers/password_reveal_controller.js +52 -49
- data/dist/controllers/password_strength_controller.js +13 -6
- data/dist/controllers/persist_controller.js +48 -128
- data/dist/controllers/pointer_drag_controller.js +249 -23
- data/dist/controllers/popover_controller.js +82 -65
- data/dist/controllers/portal_controller.js +6 -0
- data/dist/controllers/preview_guard_controller.js +14 -3
- data/dist/controllers/progress_controller.js +271 -27
- data/dist/controllers/radio_group_controller.js +167 -80
- data/dist/controllers/range_slider_controller.js +27 -7
- data/dist/controllers/rating_controller.js +93 -57
- data/dist/controllers/read_more_controller.js +10 -6
- data/dist/controllers/reading_progress_controller.js +22 -5
- data/dist/controllers/relative_time_controller.js +75 -11
- data/dist/controllers/reset_on_restore_controller.js +6 -0
- data/dist/controllers/resizable_controller.js +55 -22
- data/dist/controllers/roving_controller.js +10 -4
- data/dist/controllers/scroll_area_controller.js +129 -88
- data/dist/controllers/scroll_restore_controller.js +14 -2
- data/dist/controllers/scroll_visibility_controller.js +93 -60
- data/dist/controllers/scrollspy_controller.js +11 -5
- data/dist/controllers/separator_controller.js +59 -43
- data/dist/controllers/sidebar_controller.js +150 -122
- data/dist/controllers/skeleton_controller.js +55 -48
- data/dist/controllers/slider_controller.js +27 -6
- data/dist/controllers/smart_sticky_header_controller.js +13 -5
- data/dist/controllers/sortable_controller.js +27 -14
- data/dist/controllers/spinner_controller.js +55 -48
- data/dist/controllers/step_indicator_controller.js +6 -0
- data/dist/controllers/stepper_controller.js +6 -0
- data/dist/controllers/stick_to_bottom_controller.js +19 -8
- data/dist/controllers/sticky_observer_controller.js +49 -43
- data/dist/controllers/submit_once_controller.js +145 -85
- data/dist/controllers/switch_controller.js +172 -28
- data/dist/controllers/tabs_controller.js +6 -1
- data/dist/controllers/tags_input_controller.js +157 -28
- data/dist/controllers/textarea_autosize_controller.js +40 -19
- data/dist/controllers/theme_controller.js +10 -4
- data/dist/controllers/time_picker_controller.js +192 -54
- data/dist/controllers/toast_controller.js +58 -27
- data/dist/controllers/toggle_group_controller.js +158 -56
- data/dist/controllers/toolbar_controller.js +150 -21
- data/dist/controllers/tree_view_controller.js +134 -25
- data/dist/index.js +2451 -1312
- data/dist/positioning/index.js +6 -0
- 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 +2 -2
|
@@ -6,63 +6,182 @@ var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
|
6
6
|
"deleteCompositionText",
|
|
7
7
|
"deleteByComposition"
|
|
8
8
|
]);
|
|
9
|
+
function isCompositionInputType(inputType) {
|
|
10
|
+
return inputType !== void 0 && COMPOSITION_INPUT_TYPES.has(inputType);
|
|
11
|
+
}
|
|
12
|
+
var BEFORE_MORPH_ATTRIBUTE = "turbo:before-morph-attribute";
|
|
13
|
+
var textOf = (element) => element.value;
|
|
14
|
+
var holdsFocus = (element) => element instanceof Node && element.getRootNode().activeElement === element;
|
|
9
15
|
var CompositionTracker = class {
|
|
10
16
|
#observedTargets = /* @__PURE__ */ new Set();
|
|
11
|
-
#
|
|
17
|
+
#composition = null;
|
|
12
18
|
#onStart;
|
|
13
19
|
#onEnd;
|
|
20
|
+
#onAbandon;
|
|
14
21
|
#confirmedTarget = null;
|
|
22
|
+
#keyComposing = false;
|
|
23
|
+
#connected = false;
|
|
24
|
+
#abandoned = null;
|
|
15
25
|
constructor(options = {}) {
|
|
16
26
|
this.#onStart = options.onStart;
|
|
17
27
|
this.#onEnd = options.onEnd;
|
|
28
|
+
this.#onAbandon = options.onAbandon;
|
|
18
29
|
}
|
|
19
30
|
observe(target) {
|
|
31
|
+
this.#connected = true;
|
|
20
32
|
if (this.#observedTargets.has(target)) return;
|
|
21
33
|
target.addEventListener("compositionstart", this.#handleStart);
|
|
22
34
|
target.addEventListener("compositionend", this.#handleEnd);
|
|
23
|
-
target.addEventListener("keydown", this.#handleKeydown);
|
|
35
|
+
target.addEventListener("keydown", this.#handleKeydown, true);
|
|
36
|
+
target.addEventListener("beforeinput", this.#handleBeforeInput, true);
|
|
37
|
+
target.addEventListener("input", this.#handleInput, true);
|
|
38
|
+
target.addEventListener("blur", this.#handleBlur, true);
|
|
39
|
+
target.addEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
|
|
24
40
|
this.#observedTargets.add(target);
|
|
25
41
|
}
|
|
26
42
|
unobserve(target) {
|
|
27
43
|
if (!this.#observedTargets.delete(target)) return;
|
|
28
|
-
|
|
29
|
-
target
|
|
30
|
-
target.removeEventListener("keydown", this.#handleKeydown);
|
|
31
|
-
this.#activeTargets.delete(target);
|
|
44
|
+
this.#release(target);
|
|
45
|
+
if (this.#composition?.target === target) this.#letGo();
|
|
32
46
|
if (this.#confirmedTarget === target) this.#confirmedTarget = null;
|
|
33
47
|
}
|
|
34
48
|
disconnect() {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
target.removeEventListener("compositionend", this.#handleEnd);
|
|
38
|
-
target.removeEventListener("keydown", this.#handleKeydown);
|
|
39
|
-
}
|
|
49
|
+
this.#connected = false;
|
|
50
|
+
for (const target of this.#observedTargets) this.#release(target);
|
|
40
51
|
this.#observedTargets.clear();
|
|
41
|
-
this.#
|
|
52
|
+
this.#letGo();
|
|
42
53
|
this.#confirmedTarget = null;
|
|
54
|
+
this.#keyComposing = false;
|
|
55
|
+
this.#abandoned = null;
|
|
43
56
|
}
|
|
44
57
|
isComposing(event) {
|
|
45
|
-
|
|
58
|
+
this.#settle();
|
|
59
|
+
return event?.isComposing === true || this.#composition !== null;
|
|
60
|
+
}
|
|
61
|
+
composingElement() {
|
|
62
|
+
this.#settle();
|
|
63
|
+
return this.#composition?.element ?? null;
|
|
64
|
+
}
|
|
65
|
+
owns(event) {
|
|
66
|
+
const element = this.composingElement();
|
|
67
|
+
return event.isComposing === true || element !== null && element === event.target;
|
|
46
68
|
}
|
|
47
69
|
consumesConfirmedInput(event) {
|
|
48
70
|
const confirmed = this.#confirmedTarget;
|
|
49
71
|
this.#confirmedTarget = null;
|
|
50
72
|
if (confirmed === null || confirmed !== event.target) return false;
|
|
51
73
|
const inputType = event.inputType;
|
|
52
|
-
return !inputType ||
|
|
74
|
+
return !inputType || isCompositionInputType(inputType);
|
|
75
|
+
}
|
|
76
|
+
#release(target) {
|
|
77
|
+
target.removeEventListener("compositionstart", this.#handleStart);
|
|
78
|
+
target.removeEventListener("compositionend", this.#handleEnd);
|
|
79
|
+
target.removeEventListener("keydown", this.#handleKeydown, true);
|
|
80
|
+
target.removeEventListener("beforeinput", this.#handleBeforeInput, true);
|
|
81
|
+
target.removeEventListener("input", this.#handleInput, true);
|
|
82
|
+
target.removeEventListener("blur", this.#handleBlur, true);
|
|
83
|
+
target.removeEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
|
|
84
|
+
}
|
|
85
|
+
#letGo() {
|
|
86
|
+
const composition = this.#composition;
|
|
87
|
+
if (composition === null) return;
|
|
88
|
+
if (!holdsFocus(composition.element)) {
|
|
89
|
+
this.#composition = null;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
queueMicrotask(() => {
|
|
93
|
+
if (this.#composition !== composition || this.#observedTargets.has(composition.target)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.#composition = null;
|
|
97
|
+
if (!this.#connected) return;
|
|
98
|
+
this.#abandoned = { element: composition.element, inPlace: true };
|
|
99
|
+
this.#runAbandon();
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
#settle() {
|
|
103
|
+
const composition = this.#composition;
|
|
104
|
+
if (composition === null) return;
|
|
105
|
+
const { target, element, text } = composition;
|
|
106
|
+
if (target instanceof Node && element instanceof Node && !target.contains(element)) {
|
|
107
|
+
this.#composition = null;
|
|
108
|
+
} else if (textOf(element) !== text) {
|
|
109
|
+
this.#abandon(false);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
#abandon(inPlace) {
|
|
113
|
+
this.#owe(inPlace);
|
|
114
|
+
this.#composition = null;
|
|
115
|
+
queueMicrotask(this.#runAbandon);
|
|
116
|
+
}
|
|
117
|
+
#owe(inPlace) {
|
|
118
|
+
const composition = this.#composition;
|
|
119
|
+
if (composition !== null) this.#abandoned = { element: composition.element, inPlace };
|
|
53
120
|
}
|
|
121
|
+
#runAbandon = () => {
|
|
122
|
+
const abandoned = this.#abandoned;
|
|
123
|
+
if (abandoned === null) return;
|
|
124
|
+
this.#abandoned = null;
|
|
125
|
+
this.#onAbandon?.(abandoned.element, abandoned.inPlace);
|
|
126
|
+
};
|
|
54
127
|
#handleStart = (event) => {
|
|
55
128
|
this.#confirmedTarget = null;
|
|
56
|
-
|
|
129
|
+
this.#settle();
|
|
130
|
+
this.#owe(true);
|
|
131
|
+
const target = event.currentTarget;
|
|
132
|
+
const element = event.target;
|
|
133
|
+
this.#composition = { target, element, text: textOf(element) };
|
|
134
|
+
this.#runAbandon();
|
|
57
135
|
this.#onStart?.(event);
|
|
58
136
|
};
|
|
59
137
|
#handleEnd = (event) => {
|
|
60
|
-
|
|
138
|
+
this.#runAbandon();
|
|
139
|
+
if (this.#composition?.target === event.currentTarget) this.#composition = null;
|
|
61
140
|
this.#confirmedTarget = event.target;
|
|
62
141
|
this.#onEnd?.(event);
|
|
63
142
|
};
|
|
64
|
-
#handleKeydown = () => {
|
|
143
|
+
#handleKeydown = (event) => {
|
|
144
|
+
this.#settle();
|
|
145
|
+
this.#runAbandon();
|
|
65
146
|
this.#confirmedTarget = null;
|
|
147
|
+
this.#keyComposing = event.isComposing === true;
|
|
148
|
+
};
|
|
149
|
+
#handleBeforeInput = (event) => {
|
|
150
|
+
const keyComposing = this.#keyComposing;
|
|
151
|
+
this.#keyComposing = false;
|
|
152
|
+
this.#settle();
|
|
153
|
+
const { isComposing, inputType } = event;
|
|
154
|
+
if (this.#composition !== null && !keyComposing && !isComposing && inputType && !isCompositionInputType(inputType)) {
|
|
155
|
+
this.#abandon(true);
|
|
156
|
+
}
|
|
157
|
+
this.#runAbandon();
|
|
158
|
+
};
|
|
159
|
+
#handleInput = (event) => {
|
|
160
|
+
const composition = this.#composition;
|
|
161
|
+
const { isTrusted, isComposing, inputType } = event;
|
|
162
|
+
if (composition !== null && event.target === composition.element && (isTrusted || isComposing || isCompositionInputType(inputType))) {
|
|
163
|
+
composition.text = textOf(composition.element);
|
|
164
|
+
} else {
|
|
165
|
+
this.#settle();
|
|
166
|
+
}
|
|
167
|
+
this.#runAbandon();
|
|
168
|
+
};
|
|
169
|
+
#handleBlur = (event) => {
|
|
170
|
+
this.#settle();
|
|
171
|
+
this.#runAbandon();
|
|
172
|
+
const composition = this.#composition;
|
|
173
|
+
if (composition === null || composition.target === composition.element) return;
|
|
174
|
+
const { element } = composition;
|
|
175
|
+
if (!(element instanceof Node) || event.target !== element) return;
|
|
176
|
+
const root = element.getRootNode();
|
|
177
|
+
if (root.activeElement !== element) this.#composition = null;
|
|
178
|
+
};
|
|
179
|
+
#handleBeforeMorphAttribute = (event) => {
|
|
180
|
+
this.#settle();
|
|
181
|
+
const composition = this.#composition;
|
|
182
|
+
if (composition?.target !== event.currentTarget || event.target !== composition.element) return;
|
|
183
|
+
const detail = event.detail;
|
|
184
|
+
if (detail?.attributeName === "value") event.preventDefault();
|
|
66
185
|
};
|
|
67
186
|
};
|
|
68
187
|
|
|
@@ -89,6 +208,43 @@ function parseJsonObject(raw) {
|
|
|
89
208
|
return parsed;
|
|
90
209
|
}
|
|
91
210
|
|
|
211
|
+
var DetachGate = class _DetachGate {
|
|
212
|
+
#pending = false;
|
|
213
|
+
get pending() {
|
|
214
|
+
return this.#pending;
|
|
215
|
+
}
|
|
216
|
+
static isDetached(host) {
|
|
217
|
+
return !host.element.isConnected || !_DetachGate.#listed(host);
|
|
218
|
+
}
|
|
219
|
+
disconnected(host, teardown) {
|
|
220
|
+
const carried = _DetachGate.#carried(host);
|
|
221
|
+
if (!carried && _DetachGate.isDetached(host)) {
|
|
222
|
+
this.#pending = false;
|
|
223
|
+
teardown();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
this.#pending = true;
|
|
227
|
+
const probe = () => {
|
|
228
|
+
if (!this.#pending) return;
|
|
229
|
+
this.#pending = false;
|
|
230
|
+
teardown();
|
|
231
|
+
};
|
|
232
|
+
if (carried) setTimeout(probe, 0);
|
|
233
|
+
else queueMicrotask(probe);
|
|
234
|
+
}
|
|
235
|
+
static #carried(host) {
|
|
236
|
+
const element = host.element;
|
|
237
|
+
return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
|
|
238
|
+
}
|
|
239
|
+
static #listed(host) {
|
|
240
|
+
const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
|
|
241
|
+
return tokens.includes(host.identifier);
|
|
242
|
+
}
|
|
243
|
+
cancel() {
|
|
244
|
+
this.#pending = false;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
92
248
|
function inheritsFieldsetDisabled(control) {
|
|
93
249
|
let fieldset = control.closest("fieldset[disabled]");
|
|
94
250
|
while (fieldset) {
|
|
@@ -99,6 +255,120 @@ function inheritsFieldsetDisabled(control) {
|
|
|
99
255
|
return false;
|
|
100
256
|
}
|
|
101
257
|
|
|
258
|
+
function sharedRegistry(key, create) {
|
|
259
|
+
const symbol = Symbol.for(key);
|
|
260
|
+
const scope = globalThis;
|
|
261
|
+
const existing = scope[symbol];
|
|
262
|
+
if (existing !== void 0) return existing;
|
|
263
|
+
const registry = create();
|
|
264
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
265
|
+
return registry;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
var PREFIX = "__stimeo_raw_v1_";
|
|
269
|
+
var documents = sharedRegistry(
|
|
270
|
+
"stimeo-ui.form-data-projection.registry.v1",
|
|
271
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
272
|
+
);
|
|
273
|
+
function decodedName(key) {
|
|
274
|
+
if (!key.startsWith(PREFIX)) return null;
|
|
275
|
+
const separator = PREFIX.length + 32;
|
|
276
|
+
if (key[separator] !== ":") return null;
|
|
277
|
+
try {
|
|
278
|
+
const name = JSON.parse(key.slice(separator + 1));
|
|
279
|
+
return typeof name === "string" ? name : null;
|
|
280
|
+
} catch {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function projectedFieldName(name) {
|
|
285
|
+
return decodedName(name) ?? name;
|
|
286
|
+
}
|
|
287
|
+
function forDocument(document2) {
|
|
288
|
+
const existing = documents.get(document2);
|
|
289
|
+
if (existing) return existing;
|
|
290
|
+
const state = {
|
|
291
|
+
fields: /* @__PURE__ */ new Map(),
|
|
292
|
+
byField: /* @__PURE__ */ new WeakMap(),
|
|
293
|
+
handle: (event) => {
|
|
294
|
+
const data = event.formData;
|
|
295
|
+
if (!data) return;
|
|
296
|
+
const entries = [...data.entries()];
|
|
297
|
+
let changed = false;
|
|
298
|
+
const projected = entries.map(([key, value]) => {
|
|
299
|
+
const name = decodedName(key);
|
|
300
|
+
if (name === null) return [key, value];
|
|
301
|
+
changed = true;
|
|
302
|
+
const field = state.fields.get(key);
|
|
303
|
+
const live = field && field.field.name === key && field.field.form === event.target;
|
|
304
|
+
return [name, live ? field.project(value) : ""];
|
|
305
|
+
});
|
|
306
|
+
if (!changed) return;
|
|
307
|
+
for (const key of new Set(data.keys())) data.delete(key);
|
|
308
|
+
for (const [name, value] of projected) data.append(name, value);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
documents.set(document2, state);
|
|
312
|
+
document2.addEventListener("formdata", state.handle, { capture: true });
|
|
313
|
+
return state;
|
|
314
|
+
}
|
|
315
|
+
function prepareFormDataProjection(form) {
|
|
316
|
+
const state = forDocument(form.ownerDocument);
|
|
317
|
+
form.addEventListener("formdata", state.handle, { capture: true });
|
|
318
|
+
}
|
|
319
|
+
var FormDataProjection = class {
|
|
320
|
+
#held = null;
|
|
321
|
+
hold(field, project) {
|
|
322
|
+
const held = this.#held;
|
|
323
|
+
if (held?.field === field && held.key === field.name && held.document === field.ownerDocument) {
|
|
324
|
+
if (field.form) prepareFormDataProjection(field.form);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
this.release();
|
|
328
|
+
const name = projectedFieldName(field.name);
|
|
329
|
+
if (name === "" || field.type === "hidden" && name.toLowerCase() === "_charset_") return;
|
|
330
|
+
const state = forDocument(field.ownerDocument);
|
|
331
|
+
if (field.form) prepareFormDataProjection(field.form);
|
|
332
|
+
const previous = state.byField.get(field);
|
|
333
|
+
if (previous) {
|
|
334
|
+
state.fields.delete(previous.key);
|
|
335
|
+
field.removeEventListener("turbo:morph-element", previous.restore);
|
|
336
|
+
}
|
|
337
|
+
const nonce = Array.from(
|
|
338
|
+
crypto.getRandomValues(new Uint8Array(16)),
|
|
339
|
+
(value) => value.toString(16).padStart(2, "0")
|
|
340
|
+
).join("");
|
|
341
|
+
const key = `${PREFIX}${nonce}:${JSON.stringify(name)}`;
|
|
342
|
+
const projection = {
|
|
343
|
+
field,
|
|
344
|
+
key,
|
|
345
|
+
name,
|
|
346
|
+
project,
|
|
347
|
+
document: field.ownerDocument,
|
|
348
|
+
state,
|
|
349
|
+
restore: () => {
|
|
350
|
+
if (field.name === name) field.name = key;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
state.fields.set(key, projection);
|
|
354
|
+
state.byField.set(field, projection);
|
|
355
|
+
this.#held = projection;
|
|
356
|
+
field.name = key;
|
|
357
|
+
field.addEventListener("turbo:morph-element", projection.restore);
|
|
358
|
+
}
|
|
359
|
+
release() {
|
|
360
|
+
const held = this.#held;
|
|
361
|
+
this.#held = null;
|
|
362
|
+
if (held === null) return;
|
|
363
|
+
held.field.removeEventListener("turbo:morph-element", held.restore);
|
|
364
|
+
const state = held.state;
|
|
365
|
+
if (state.byField.get(held.field) !== held) return;
|
|
366
|
+
state.fields.delete(held.key);
|
|
367
|
+
state.byField.delete(held.field);
|
|
368
|
+
if (held.field.name === held.key) held.field.name = held.name;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
102
372
|
var FULL_WIDTH_SHIFT = 65248;
|
|
103
373
|
function halfWidthChar(char) {
|
|
104
374
|
if (char >= "\uFF01" && char <= "\uFF5E") {
|
|
@@ -134,6 +404,9 @@ var MicrotaskCoalescer = class {
|
|
|
134
404
|
this.#queued = false;
|
|
135
405
|
this.#generation += 1;
|
|
136
406
|
}
|
|
407
|
+
get pending() {
|
|
408
|
+
return this.#queued;
|
|
409
|
+
}
|
|
137
410
|
schedule() {
|
|
138
411
|
if (!this.#active || this.#queued) return;
|
|
139
412
|
this.#queued = true;
|
|
@@ -164,6 +437,9 @@ var MorphRenderWatcher = class {
|
|
|
164
437
|
schedule() {
|
|
165
438
|
this.#pass.schedule();
|
|
166
439
|
}
|
|
440
|
+
get pending() {
|
|
441
|
+
return this.#pass.pending;
|
|
442
|
+
}
|
|
167
443
|
disconnect() {
|
|
168
444
|
this.#listeners.dispose();
|
|
169
445
|
this.#pass.cancel();
|
|
@@ -171,12 +447,53 @@ var MorphRenderWatcher = class {
|
|
|
171
447
|
}
|
|
172
448
|
};
|
|
173
449
|
|
|
450
|
+
var TimerRegistry = class {
|
|
451
|
+
ids = /* @__PURE__ */ new Set();
|
|
452
|
+
clear(id) {
|
|
453
|
+
if (this.ids.delete(id)) {
|
|
454
|
+
this.cancel(id);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
clearAll() {
|
|
458
|
+
for (const id of this.ids) {
|
|
459
|
+
this.cancel(id);
|
|
460
|
+
}
|
|
461
|
+
this.ids.clear();
|
|
462
|
+
}
|
|
463
|
+
get size() {
|
|
464
|
+
return this.ids.size;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
var SafeTimeout = class extends TimerRegistry {
|
|
468
|
+
set(callback, delay) {
|
|
469
|
+
const id = this.schedule(() => {
|
|
470
|
+
this.ids.delete(id);
|
|
471
|
+
callback();
|
|
472
|
+
}, delay);
|
|
473
|
+
this.ids.add(id);
|
|
474
|
+
return id;
|
|
475
|
+
}
|
|
476
|
+
schedule(callback, delay) {
|
|
477
|
+
return window.setTimeout(callback, delay);
|
|
478
|
+
}
|
|
479
|
+
cancel(id) {
|
|
480
|
+
window.clearTimeout(id);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
function prepareInputMaskForm(form) {
|
|
485
|
+
prepareFormDataProjection(form);
|
|
486
|
+
}
|
|
174
487
|
var DEFAULT_TOKENS = {
|
|
175
488
|
"9": "\\d",
|
|
176
489
|
a: "[A-Za-z]",
|
|
177
490
|
"*": "[A-Za-z0-9]"
|
|
178
491
|
};
|
|
179
492
|
var UNMASK_ATTR = "unmask";
|
|
493
|
+
var rawWriters = sharedRegistry(
|
|
494
|
+
"stimeo-ui.input-mask-raw-writer.registry.v1",
|
|
495
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
496
|
+
);
|
|
180
497
|
function acceptedForm(regex, char) {
|
|
181
498
|
if (regex.test(char)) return char;
|
|
182
499
|
const half = halfWidthChar(char);
|
|
@@ -265,8 +582,14 @@ var InputMaskController = class extends Controller {
|
|
|
265
582
|
static events = ["change", "reconcile"];
|
|
266
583
|
#lastValue = null;
|
|
267
584
|
#started = false;
|
|
585
|
+
#rawSink = null;
|
|
586
|
+
#rawValue = "";
|
|
587
|
+
#rawSourceForm = null;
|
|
588
|
+
#submission = new FormDataProjection();
|
|
268
589
|
#tokens = compileTokens("");
|
|
269
590
|
#textBeforeComposition = "";
|
|
591
|
+
#formatted = null;
|
|
592
|
+
#shown = { result: null, empty: true };
|
|
270
593
|
#composition = new CompositionTracker({
|
|
271
594
|
onStart: () => {
|
|
272
595
|
this.#textBeforeComposition = this.element.value;
|
|
@@ -274,6 +597,9 @@ var InputMaskController = class extends Controller {
|
|
|
274
597
|
onEnd: () => {
|
|
275
598
|
const committedNothing = this.element.value === this.#textBeforeComposition;
|
|
276
599
|
this.#reformat(committedNothing ? "reconcile" : "edit");
|
|
600
|
+
},
|
|
601
|
+
onAbandon: () => {
|
|
602
|
+
if (this.#formatted !== this.#declared) this.#reformat("reconcile");
|
|
277
603
|
}
|
|
278
604
|
});
|
|
279
605
|
tokensValueChanged() {
|
|
@@ -285,34 +611,53 @@ var InputMaskController = class extends Controller {
|
|
|
285
611
|
}
|
|
286
612
|
unmaskToHiddenValueChanged() {
|
|
287
613
|
if (!this.#started) return;
|
|
288
|
-
if (!this.unmaskToHiddenValue)
|
|
289
|
-
const sink = this.#resolveSink();
|
|
290
|
-
if (sink) sink.value = "";
|
|
291
|
-
}
|
|
614
|
+
if (!this.unmaskToHiddenValue) this.#withdraw();
|
|
292
615
|
this.#reformat("reconcile");
|
|
293
616
|
}
|
|
617
|
+
#withdraw() {
|
|
618
|
+
if (this.#retractRaw() && this.#composition.isComposing()) this.#formatted = null;
|
|
619
|
+
}
|
|
294
620
|
#morph = new MorphRenderWatcher(() => this.#reformat("reconcile"));
|
|
621
|
+
#gate = new DetachGate();
|
|
622
|
+
#adoption = new SafeTimeout();
|
|
295
623
|
connect() {
|
|
624
|
+
this.#gate.cancel();
|
|
296
625
|
this.#morph.observe(this.element);
|
|
297
626
|
this.#started = true;
|
|
298
627
|
this.#composition.observe(this.element);
|
|
628
|
+
if (!this.unmaskToHiddenValue) this.#withdraw();
|
|
629
|
+
if (this.#composition.isComposing()) {
|
|
630
|
+
this.#reformat("reconcile");
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
299
633
|
this.#lastValue = this.element.value;
|
|
300
634
|
this.#reformat("reconcile");
|
|
635
|
+
if (this.unmaskToHiddenValue && this.#rawSink === null) {
|
|
636
|
+
this.#adoption.set(() => this.#adoptSink(), 0);
|
|
637
|
+
}
|
|
301
638
|
}
|
|
302
639
|
disconnect() {
|
|
303
640
|
this.#morph.disconnect();
|
|
304
641
|
this.#started = false;
|
|
305
642
|
this.#composition.disconnect();
|
|
643
|
+
this.#adoption.clearAll();
|
|
644
|
+
this.#gate.disconnected(this, () => this.#retractRaw());
|
|
306
645
|
}
|
|
307
646
|
format(event) {
|
|
308
647
|
if (this.#composition.isComposing(event)) return;
|
|
309
648
|
this.#reformat("edit", deletionOf(event));
|
|
310
649
|
}
|
|
311
650
|
#reformat(cause, deletion = null) {
|
|
312
|
-
if (this.#composition.isComposing())
|
|
651
|
+
if (this.#composition.isComposing()) {
|
|
652
|
+
this.#showAgain();
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
this.#formatted = this.#declared;
|
|
313
656
|
const input = this.element;
|
|
314
657
|
const raw = input.value;
|
|
315
658
|
if (this.patternValue === "") {
|
|
659
|
+
this.#retractRaw();
|
|
660
|
+
this.#shown = { result: null, empty: raw.length === 0 };
|
|
316
661
|
this.#flag("data-mask-complete", false);
|
|
317
662
|
this.#flag("data-mask-empty", raw.length === 0);
|
|
318
663
|
this.#lastValue = raw;
|
|
@@ -349,14 +694,56 @@ var InputMaskController = class extends Controller {
|
|
|
349
694
|
if (cause === "edit") this.dispatch("change", { detail });
|
|
350
695
|
else this.dispatch("reconcile", { detail });
|
|
351
696
|
}
|
|
697
|
+
get #declared() {
|
|
698
|
+
return JSON.stringify([this.patternValue, this.tokensValue, this.unmaskToHiddenValue]);
|
|
699
|
+
}
|
|
352
700
|
#publish(result, shown) {
|
|
701
|
+
this.#shown = { result, empty: shown.length === 0 };
|
|
353
702
|
if (this.unmaskToHiddenValue) {
|
|
354
703
|
const sink = this.#resolveSink();
|
|
355
|
-
if (sink
|
|
704
|
+
if (sink !== this.#rawSink) this.#retractRaw();
|
|
705
|
+
if (sink) {
|
|
706
|
+
sink.value = result.unmasked;
|
|
707
|
+
rawWriters.set(sink, this);
|
|
708
|
+
this.#rawSink = sink;
|
|
709
|
+
this.#rawValue = result.unmasked;
|
|
710
|
+
this.#rawSourceForm = this.element.form;
|
|
711
|
+
this.#submission.hold(sink, (value) => this.#submittedValue(sink, value));
|
|
712
|
+
}
|
|
356
713
|
}
|
|
357
714
|
this.#flag("data-mask-complete", result.complete);
|
|
358
715
|
this.#flag("data-mask-empty", shown.length === 0);
|
|
359
716
|
}
|
|
717
|
+
#showAgain() {
|
|
718
|
+
const shown = this.#shown;
|
|
719
|
+
const sink = this.#rawSink;
|
|
720
|
+
if (shown.result !== null && this.unmaskToHiddenValue && sink !== null && rawWriters.get(sink) === this && this.#resolveSink() === sink) {
|
|
721
|
+
sink.value = shown.result.unmasked;
|
|
722
|
+
}
|
|
723
|
+
this.#flag("data-mask-complete", shown.result?.complete ?? false);
|
|
724
|
+
this.#flag("data-mask-empty", shown.empty);
|
|
725
|
+
}
|
|
726
|
+
#retractRaw() {
|
|
727
|
+
const sink = this.#rawSink;
|
|
728
|
+
this.#rawSink = null;
|
|
729
|
+
this.#submission.release();
|
|
730
|
+
if (sink === null || rawWriters.get(sink) !== this) return false;
|
|
731
|
+
rawWriters.delete(sink);
|
|
732
|
+
if (sink.value === this.#rawValue) sink.value = "";
|
|
733
|
+
return true;
|
|
734
|
+
}
|
|
735
|
+
#submittedValue(sink, value) {
|
|
736
|
+
if (rawWriters.get(sink) !== this || sink.value !== this.#rawValue || value !== this.#rawValue)
|
|
737
|
+
return value;
|
|
738
|
+
const source = this.element;
|
|
739
|
+
const listed = (source.getAttribute("data-controller") ?? "").split(/\s+/).includes(this.identifier);
|
|
740
|
+
const associated = source.form === null ? this.#rawSourceForm === null : source.form === sink.form;
|
|
741
|
+
const eligible = source.isConnected && this.application.element.contains(source) && listed && this.unmaskToHiddenValue && associated;
|
|
742
|
+
return eligible ? value : "";
|
|
743
|
+
}
|
|
744
|
+
#adoptSink() {
|
|
745
|
+
if (this.#resolveSink() !== null) this.#reformat("reconcile");
|
|
746
|
+
}
|
|
360
747
|
#significantBefore(prefix) {
|
|
361
748
|
return applyMask(prefix, this.patternValue, this.#tokens).unmasked.length;
|
|
362
749
|
}
|
|
@@ -413,5 +800,5 @@ var InputMaskController = class extends Controller {
|
|
|
413
800
|
}
|
|
414
801
|
};
|
|
415
802
|
|
|
416
|
-
export { InputMaskController, applyMask };
|
|
803
|
+
export { InputMaskController, applyMask, prepareInputMaskForm };
|
|
417
804
|
//# sourceMappingURL=input_mask_controller.js.map
|
|
@@ -81,6 +81,17 @@ var IntersectionWatcher = class {
|
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
var ListenerSet = class {
|
|
85
|
+
#abort = new AbortController();
|
|
86
|
+
add(target, type, handler, options) {
|
|
87
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
88
|
+
}
|
|
89
|
+
dispose() {
|
|
90
|
+
this.#abort.abort();
|
|
91
|
+
this.#abort = new AbortController();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
84
95
|
var LazyFrameController = class extends Controller {
|
|
85
96
|
static values = {
|
|
86
97
|
url: { type: String, default: "" },
|
|
@@ -93,6 +104,7 @@ var LazyFrameController = class extends Controller {
|
|
|
93
104
|
#loaded = false;
|
|
94
105
|
#inside = null;
|
|
95
106
|
#onFocus = () => this.#load();
|
|
107
|
+
#focusListeners = new ListenerSet();
|
|
96
108
|
urlValueChanged() {
|
|
97
109
|
if (!this.#connected || this.#loaded) return;
|
|
98
110
|
if (this.urlValue) this.#arm();
|
|
@@ -123,7 +135,7 @@ var LazyFrameController = class extends Controller {
|
|
|
123
135
|
}
|
|
124
136
|
#arm() {
|
|
125
137
|
if (!this.urlValue) return;
|
|
126
|
-
if (!this.#loaded) this.element
|
|
138
|
+
if (!this.#loaded) this.#focusListeners.add(this.element, "focusin", this.#onFocus);
|
|
127
139
|
this.#observe();
|
|
128
140
|
}
|
|
129
141
|
#observe() {
|
|
@@ -154,7 +166,7 @@ var LazyFrameController = class extends Controller {
|
|
|
154
166
|
this.element.setAttribute("src", this.urlValue);
|
|
155
167
|
this.element.setAttribute("data-lazy-loaded", "true");
|
|
156
168
|
this.dispatch("load", { detail: { url: this.urlValue } });
|
|
157
|
-
this.
|
|
169
|
+
this.#focusListeners.dispose();
|
|
158
170
|
if (this.onceValue) this.#watcher.stop();
|
|
159
171
|
}
|
|
160
172
|
#reload() {
|
|
@@ -171,7 +183,7 @@ var LazyFrameController = class extends Controller {
|
|
|
171
183
|
}
|
|
172
184
|
#stopObserving() {
|
|
173
185
|
this.#watcher.stop();
|
|
174
|
-
this.
|
|
186
|
+
this.#focusListeners.dispose();
|
|
175
187
|
}
|
|
176
188
|
};
|
|
177
189
|
|