stimeo-ui 0.17.0 → 0.18.1
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 -2
- 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 +290 -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 +66 -46
- data/dist/controllers/drawer_controller.js +145 -118
- data/dist/controllers/dropdown_controller.js +76 -63
- data/dist/controllers/editable_controller.js +200 -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 +434 -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 +272 -95
- 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 +255 -24
- data/dist/controllers/popover_controller.js +91 -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 +2515 -1315
- 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);
|
|
53
116
|
}
|
|
117
|
+
#owe(inPlace) {
|
|
118
|
+
const composition = this.#composition;
|
|
119
|
+
if (composition !== null) this.#abandoned = { element: composition.element, inPlace };
|
|
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
|
|
|
@@ -103,10 +222,6 @@ function construct(factory, locale, options, fallbackLocale) {
|
|
|
103
222
|
}
|
|
104
223
|
}
|
|
105
224
|
|
|
106
|
-
function resolveLocale(element, declared = "") {
|
|
107
|
-
return declared || element.closest("[lang]")?.getAttribute("lang") || void 0;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
225
|
var ListenerSet = class {
|
|
111
226
|
#abort = new AbortController();
|
|
112
227
|
add(target, type, handler, options) {
|
|
@@ -118,6 +233,10 @@ var ListenerSet = class {
|
|
|
118
233
|
}
|
|
119
234
|
};
|
|
120
235
|
|
|
236
|
+
function resolveLocale(element, declared = "") {
|
|
237
|
+
return declared || element.closest("[lang]")?.getAttribute("lang") || void 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
121
240
|
var MicrotaskCoalescer = class {
|
|
122
241
|
#run;
|
|
123
242
|
#queued = false;
|
|
@@ -134,6 +253,9 @@ var MicrotaskCoalescer = class {
|
|
|
134
253
|
this.#queued = false;
|
|
135
254
|
this.#generation += 1;
|
|
136
255
|
}
|
|
256
|
+
get pending() {
|
|
257
|
+
return this.#queued;
|
|
258
|
+
}
|
|
137
259
|
schedule() {
|
|
138
260
|
if (!this.#active || this.#queued) return;
|
|
139
261
|
this.#queued = true;
|
|
@@ -164,6 +286,9 @@ var MorphRenderWatcher = class {
|
|
|
164
286
|
schedule() {
|
|
165
287
|
this.#pass.schedule();
|
|
166
288
|
}
|
|
289
|
+
get pending() {
|
|
290
|
+
return this.#pass.pending;
|
|
291
|
+
}
|
|
167
292
|
disconnect() {
|
|
168
293
|
this.#listeners.dispose();
|
|
169
294
|
this.#pass.cancel();
|
|
@@ -213,6 +338,94 @@ var NumberValueReader = class {
|
|
|
213
338
|
}
|
|
214
339
|
};
|
|
215
340
|
|
|
341
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
342
|
+
if (element.getAttribute(name) === value) return false;
|
|
343
|
+
if (value === null) element.removeAttribute(name);
|
|
344
|
+
else element.setAttribute(name, value);
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
var OwnedText = class {
|
|
349
|
+
#attribute;
|
|
350
|
+
#channel;
|
|
351
|
+
#guard;
|
|
352
|
+
#writes = /* @__PURE__ */ new WeakMap();
|
|
353
|
+
constructor(attribute, channel = "text", guard = () => true) {
|
|
354
|
+
this.#attribute = attribute;
|
|
355
|
+
this.#channel = channel;
|
|
356
|
+
this.#guard = guard;
|
|
357
|
+
}
|
|
358
|
+
hasRecord(element) {
|
|
359
|
+
return element.hasAttribute(this.#attribute);
|
|
360
|
+
}
|
|
361
|
+
read(element, evidence = {}) {
|
|
362
|
+
if (evidence.source === "live") return this.#writes.get(element) ?? null;
|
|
363
|
+
const raw = element.getAttribute(this.#attribute);
|
|
364
|
+
if (raw === null) return null;
|
|
365
|
+
try {
|
|
366
|
+
const record = JSON.parse(raw);
|
|
367
|
+
if (!Array.isArray(record) || record.length !== 3 || record[0] !== this.#channel || typeof record[1] !== "string" || typeof record[2] !== "string")
|
|
368
|
+
return null;
|
|
369
|
+
return { original: record[1], written: record[2] };
|
|
370
|
+
} catch {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
owns(element, evidence = {}) {
|
|
375
|
+
return this.#ownedRecord(element, evidence) !== null;
|
|
376
|
+
}
|
|
377
|
+
#ownedRecord(element, evidence) {
|
|
378
|
+
const record = this.read(element, evidence);
|
|
379
|
+
if (record === null || !this.#guard(element)) return null;
|
|
380
|
+
if (this.#channel === "text" && element.firstElementChild !== null) return null;
|
|
381
|
+
const current = this.#current(element);
|
|
382
|
+
return current === record.written || evidence.source === "live" && evidence.allowOriginal === true && current === record.original ? record : null;
|
|
383
|
+
}
|
|
384
|
+
write(element, written, original, force = false) {
|
|
385
|
+
const current = this.#current(element);
|
|
386
|
+
if (current === null) return;
|
|
387
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
388
|
+
if (force || current !== written) this.#put(element, written);
|
|
389
|
+
this.remember(element, written, before);
|
|
390
|
+
}
|
|
391
|
+
remember(element, written, original) {
|
|
392
|
+
const current = this.#current(element);
|
|
393
|
+
if (current === null) return;
|
|
394
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
395
|
+
this.#writes.set(element, { original: before, written });
|
|
396
|
+
setAttributeIfChanged(
|
|
397
|
+
element,
|
|
398
|
+
this.#attribute,
|
|
399
|
+
JSON.stringify([this.#channel, before, written])
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
clear(element, evidence = {}) {
|
|
403
|
+
if (!this.owns(element, evidence)) return false;
|
|
404
|
+
if (this.#current(element) !== "") this.#put(element, "");
|
|
405
|
+
this.forget(element);
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
restore(element, evidence = {}) {
|
|
409
|
+
const record = this.#ownedRecord(element, evidence);
|
|
410
|
+
if (record === null) return false;
|
|
411
|
+
if (this.#current(element) !== record.original) this.#put(element, record.original);
|
|
412
|
+
this.forget(element);
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
forget(element) {
|
|
416
|
+
setAttributeIfChanged(element, this.#attribute, null);
|
|
417
|
+
this.#writes.delete(element);
|
|
418
|
+
}
|
|
419
|
+
#current(element) {
|
|
420
|
+
if (this.#channel === "text") return element.textContent ?? "";
|
|
421
|
+
return element instanceof HTMLInputElement ? element.value : null;
|
|
422
|
+
}
|
|
423
|
+
#put(element, text) {
|
|
424
|
+
if (this.#channel === "text") element.textContent = text;
|
|
425
|
+
else if (element instanceof HTMLInputElement) element.value = text;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
216
429
|
var FALLBACK_LOCALE = "en-US";
|
|
217
430
|
var CurrencyInputController = class _CurrencyInputController extends Controller {
|
|
218
431
|
#numbers = new NumberValueReader();
|
|
@@ -229,9 +442,17 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
229
442
|
static events = ["change", "reconcile"];
|
|
230
443
|
#lastValue = null;
|
|
231
444
|
#started = false;
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
#
|
|
445
|
+
#unsettled = null;
|
|
446
|
+
#configured = false;
|
|
447
|
+
#listeners = new ListenerSet();
|
|
448
|
+
#declarationsHeld = false;
|
|
449
|
+
#displayText = new OwnedText(
|
|
450
|
+
`data-${this.identifier}-display-text`,
|
|
451
|
+
"value"
|
|
452
|
+
);
|
|
453
|
+
#renderedDisplay = null;
|
|
454
|
+
#departed = null;
|
|
455
|
+
#formatHeld = null;
|
|
235
456
|
#locale;
|
|
236
457
|
#currency = "";
|
|
237
458
|
#precision = 2;
|
|
@@ -242,13 +463,32 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
242
463
|
#decimal = ".";
|
|
243
464
|
#digits = /* @__PURE__ */ new Map();
|
|
244
465
|
#composition = new CompositionTracker({
|
|
245
|
-
|
|
246
|
-
|
|
466
|
+
onEnd: (event) => {
|
|
467
|
+
const display = event.currentTarget;
|
|
468
|
+
if (this.#unsettled === display) this.#unsettled = null;
|
|
469
|
+
const round2 = this.#takeFormatHeld(display);
|
|
470
|
+
if (this.#inCharge(display)) this.#reformat(round2, "edit");
|
|
471
|
+
if (this.#owed(display)) this.#applyValueChange();
|
|
472
|
+
if (round2 && !this.#inCharge(display)) this.#reformat(true, "edit");
|
|
247
473
|
},
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
474
|
+
onAbandon: (display, inPlace) => {
|
|
475
|
+
const next = this.#composition.composingElement();
|
|
476
|
+
if (inPlace && next !== null && next !== display) {
|
|
477
|
+
this.#endUntrackedComposition(display);
|
|
478
|
+
} else {
|
|
479
|
+
this.#formatHeld = null;
|
|
480
|
+
}
|
|
481
|
+
if (next === display && inPlace || !this.#owed(display)) return;
|
|
482
|
+
if (next !== null) {
|
|
483
|
+
this.#readPageText(next);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (inPlace) this.#endUntrackedComposition(display);
|
|
487
|
+
if (this.#owed(display)) this.#applyValueChange();
|
|
488
|
+
},
|
|
489
|
+
onStart: (event) => {
|
|
490
|
+
if (this.#unsettled === event.target) this.#unsettled = null;
|
|
491
|
+
if (this.#formatHeld?.heard === false) this.#formatHeld = null;
|
|
252
492
|
}
|
|
253
493
|
});
|
|
254
494
|
localeValueChanged() {
|
|
@@ -261,42 +501,56 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
261
501
|
this.#applyValueChange();
|
|
262
502
|
}
|
|
263
503
|
#applyValueChange() {
|
|
504
|
+
if (!this.#started) return;
|
|
505
|
+
if (this.#holdUnsettled(false)) return;
|
|
264
506
|
if (this.#composition.isComposing()) {
|
|
265
|
-
this.#
|
|
507
|
+
this.#declarationsHeld = this.#declarationsChanged();
|
|
508
|
+
this.#resync();
|
|
266
509
|
return;
|
|
267
510
|
}
|
|
268
|
-
if (!this
|
|
269
|
-
const scan = this.#readDisplay();
|
|
511
|
+
if (!this.hasDisplayTarget) return;
|
|
512
|
+
const { scan, anchor } = this.#readDisplay();
|
|
270
513
|
if (document.activeElement === this.displayTarget) {
|
|
271
514
|
const formatted = this.#render(scan.parts);
|
|
272
|
-
this.#
|
|
515
|
+
this.#showAtCaret(formatted, anchor);
|
|
273
516
|
this.#reflect(scan.value, formatted, "reconcile");
|
|
274
517
|
} else {
|
|
275
518
|
this.#renderFixed(scan.value, "reconcile");
|
|
276
519
|
}
|
|
277
520
|
}
|
|
278
|
-
#applyHeldChange() {
|
|
279
|
-
if (!this.#changeHeld) return;
|
|
280
|
-
this.#changeHeld = false;
|
|
281
|
-
this.#applyValueChange();
|
|
282
|
-
}
|
|
283
521
|
#readDisplay() {
|
|
284
522
|
const text = this.displayTarget.value;
|
|
285
|
-
const own =
|
|
286
|
-
this.#takeInDeclarations();
|
|
287
|
-
return own ?? this.#scan(text);
|
|
288
|
-
}
|
|
289
|
-
#takeInDeclarations() {
|
|
290
|
-
this.#changeHeld = false;
|
|
523
|
+
const own = this.#showsOwnRendering(this.displayTarget) ? this.#read(text) : null;
|
|
291
524
|
this.#revalidate();
|
|
525
|
+
return own ?? this.#read(text);
|
|
526
|
+
}
|
|
527
|
+
#showsOwnRendering(display) {
|
|
528
|
+
return display === this.#renderedDisplay && this.#displayText.owns(display, { source: "live" });
|
|
529
|
+
}
|
|
530
|
+
#inCharge(source) {
|
|
531
|
+
return source === null || this.hasDisplayTarget && source === this.displayTarget;
|
|
532
|
+
}
|
|
533
|
+
#read(text) {
|
|
534
|
+
return {
|
|
535
|
+
scan: this.#scan(text),
|
|
536
|
+
anchor: this.#significantBefore(text, this.displayTarget.selectionStart)
|
|
537
|
+
};
|
|
292
538
|
}
|
|
293
539
|
#morph = new MorphRenderWatcher(() => this.#applyValueChange());
|
|
294
540
|
connect() {
|
|
295
541
|
this.#morph.observe(this.element);
|
|
542
|
+
this.#listeners.add(this.element, "turbo:before-morph-attribute", this.#protectUnsettled);
|
|
296
543
|
this.#started = true;
|
|
297
|
-
this.#
|
|
544
|
+
if (!this.#configured) this.#revalidate();
|
|
545
|
+
if (this.#composition.isComposing()) {
|
|
546
|
+
this.#applyValueChange();
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
this.#formatHeld = null;
|
|
550
|
+
if (this.#holdUnsettled(true)) return;
|
|
551
|
+
this.#revalidate();
|
|
298
552
|
if (!this.hasDisplayTarget) return;
|
|
299
|
-
if (this.displayTarget
|
|
553
|
+
if (this.#showsOwnRendering(this.displayTarget)) {
|
|
300
554
|
this.#renderFixed(this.#lastValue, "reconcile");
|
|
301
555
|
return;
|
|
302
556
|
}
|
|
@@ -306,25 +560,37 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
306
560
|
}
|
|
307
561
|
disconnect() {
|
|
308
562
|
this.#morph.disconnect();
|
|
309
|
-
this.#
|
|
563
|
+
this.#listeners.dispose();
|
|
564
|
+
const composing = this.#composition.composingElement();
|
|
310
565
|
this.#composition.disconnect();
|
|
566
|
+
if (this.#composition.composingElement() !== composing) {
|
|
567
|
+
this.#endUntrackedComposition(composing);
|
|
568
|
+
}
|
|
311
569
|
this.#started = false;
|
|
312
570
|
}
|
|
313
571
|
displayTargetConnected(target) {
|
|
314
572
|
this.#composition.observe(target);
|
|
315
573
|
if (!this.#started || !this.hasDisplayTarget || this.displayTarget !== target) return;
|
|
316
|
-
this.#
|
|
574
|
+
this.#applyValueChange();
|
|
317
575
|
}
|
|
318
576
|
displayTargetDisconnected(target) {
|
|
577
|
+
if (target === this.#renderedDisplay && !(this.#started && this.hasDisplayTarget && this.displayTarget === target)) {
|
|
578
|
+
this.#departed = target;
|
|
579
|
+
}
|
|
580
|
+
const composing = this.#composition.composingElement() === target;
|
|
319
581
|
this.#composition.unobserve(target);
|
|
320
|
-
if (
|
|
582
|
+
if (composing && this.#composition.composingElement() !== target) {
|
|
583
|
+
this.#endUntrackedComposition(target);
|
|
584
|
+
}
|
|
585
|
+
if (this.#formatHeld?.display === target && this.#composition.composingElement() !== target) {
|
|
586
|
+
this.#formatHeld = null;
|
|
587
|
+
}
|
|
321
588
|
this.#applyValueChange();
|
|
322
589
|
}
|
|
323
|
-
#endUntrackedComposition() {
|
|
324
|
-
const
|
|
325
|
-
this.#composing = null;
|
|
590
|
+
#endUntrackedComposition(display) {
|
|
591
|
+
const round2 = this.#takeFormatHeld(display);
|
|
326
592
|
if (this.hasDisplayTarget && this.displayTarget === display) {
|
|
327
|
-
this.#reformat(
|
|
593
|
+
this.#reformat(round2, "reconcile");
|
|
328
594
|
}
|
|
329
595
|
}
|
|
330
596
|
fieldTargetConnected() {
|
|
@@ -340,14 +606,64 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
340
606
|
if (this.#started) this.#resync();
|
|
341
607
|
}
|
|
342
608
|
onInput(event) {
|
|
343
|
-
|
|
609
|
+
const source = event?.target ?? null;
|
|
610
|
+
if (!this.#inCharge(source)) return;
|
|
611
|
+
this.#holdUnsettled(false);
|
|
612
|
+
if (event && this.#composition.consumesConfirmedInput(event)) return;
|
|
613
|
+
const input = event;
|
|
614
|
+
if (this.#composition.isComposing(input) || isCompositionInputType(input?.inputType)) {
|
|
615
|
+
if (this.#composition.composingElement() === null && this.hasDisplayTarget) {
|
|
616
|
+
this.#beginUnsettled(this.displayTarget);
|
|
617
|
+
}
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
const unsettled = this.#unsettled !== null;
|
|
621
|
+
if (unsettled) {
|
|
622
|
+
if (source !== this.#unsettled || input?.isComposing !== false || !input.inputType) return;
|
|
623
|
+
this.#unsettled = null;
|
|
624
|
+
this.#formatHeld = null;
|
|
625
|
+
}
|
|
344
626
|
this.#reformat(false, "edit");
|
|
627
|
+
if (unsettled && this.#owed(source)) this.#applyValueChange();
|
|
628
|
+
}
|
|
629
|
+
format(event) {
|
|
630
|
+
if (!this.#inCharge(event?.target ?? null)) return;
|
|
631
|
+
const returned = this.hasDisplayTarget && this.displayTarget === this.#departed;
|
|
632
|
+
this.#holdUnsettled(false);
|
|
633
|
+
if (this.hasDisplayTarget && (this.displayTarget !== this.#renderedDisplay || returned && !this.#showsOwnRendering(this.displayTarget)) && (event?.type === "blur" || event?.type === "focusout") && this.#composition.composingElement() !== this.displayTarget) {
|
|
634
|
+
this.#beginUnsettled(this.displayTarget);
|
|
635
|
+
}
|
|
636
|
+
if (this.#unsettled !== null) {
|
|
637
|
+
this.#formatHeld = { display: this.#unsettled, heard: false };
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if (this.#composition.isComposing(event)) {
|
|
641
|
+
const composing = this.#composition.composingElement();
|
|
642
|
+
const display = composing ?? event?.target ?? (this.hasDisplayTarget ? this.displayTarget : null);
|
|
643
|
+
this.#formatHeld = display === null ? null : { display, heard: composing !== null };
|
|
644
|
+
if (composing === null && this.hasDisplayTarget && display === this.displayTarget) {
|
|
645
|
+
this.#beginUnsettled(this.displayTarget);
|
|
646
|
+
}
|
|
647
|
+
} else {
|
|
648
|
+
this.#formatHeld = null;
|
|
649
|
+
this.#reformat(true, "edit");
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
#takeFormatHeld(display) {
|
|
653
|
+
const held = this.#formatHeld;
|
|
654
|
+
this.#formatHeld = null;
|
|
655
|
+
return held !== null && held.display === display;
|
|
345
656
|
}
|
|
346
|
-
|
|
347
|
-
this.#
|
|
657
|
+
#readPageText(composing) {
|
|
658
|
+
if (this.#unsettled !== null || !this.#inCharge(composing) || this.#showsOwnRendering(this.displayTarget))
|
|
659
|
+
return;
|
|
660
|
+
const { scan } = this.#readDisplay();
|
|
661
|
+
this.#displayText.remember(this.displayTarget, this.displayTarget.value);
|
|
662
|
+
this.#renderedDisplay = this.displayTarget;
|
|
663
|
+
this.#reflect(scan.value, this.#render(scan.parts), "reconcile");
|
|
348
664
|
}
|
|
349
665
|
#reformat(fixedPrecision, cause) {
|
|
350
|
-
if (!this.hasDisplayTarget) return;
|
|
666
|
+
if (!this.hasDisplayTarget || this.#unsettled === this.displayTarget) return;
|
|
351
667
|
const raw = this.displayTarget.value;
|
|
352
668
|
const { parts, value } = this.#scan(raw);
|
|
353
669
|
if (fixedPrecision) {
|
|
@@ -355,14 +671,16 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
355
671
|
return;
|
|
356
672
|
}
|
|
357
673
|
const formatted = this.#render(parts);
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
674
|
+
this.#showAtCaret(formatted, this.#significantBefore(raw, this.displayTarget.selectionStart));
|
|
675
|
+
this.#reflect(value, formatted, cause);
|
|
676
|
+
}
|
|
677
|
+
#showAtCaret(formatted, anchor) {
|
|
678
|
+
if (formatted !== this.displayTarget.value) {
|
|
361
679
|
this.displayTarget.value = formatted;
|
|
362
680
|
if (anchor !== null) this.#restoreCaret(formatted, anchor);
|
|
363
681
|
}
|
|
364
|
-
this.#
|
|
365
|
-
this.#
|
|
682
|
+
this.#displayText.remember(this.displayTarget, formatted);
|
|
683
|
+
this.#renderedDisplay = this.displayTarget;
|
|
366
684
|
}
|
|
367
685
|
#renderFixed(value, cause) {
|
|
368
686
|
if (value === null) {
|
|
@@ -376,8 +694,8 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
376
694
|
this.#reflect(rounded, formatted, cause);
|
|
377
695
|
}
|
|
378
696
|
#show(text) {
|
|
379
|
-
|
|
380
|
-
this.#
|
|
697
|
+
this.#displayText.write(this.displayTarget, text);
|
|
698
|
+
this.#renderedDisplay = this.displayTarget;
|
|
381
699
|
}
|
|
382
700
|
#render(parts) {
|
|
383
701
|
const int = parts.int === "" ? "" : this.#grouping.format(BigInt(parts.int));
|
|
@@ -400,6 +718,7 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
400
718
|
}
|
|
401
719
|
}
|
|
402
720
|
#significantBefore(text, caret) {
|
|
721
|
+
if (caret === null) return null;
|
|
403
722
|
let count = 0;
|
|
404
723
|
let sawSign = false;
|
|
405
724
|
let sawDigit = false;
|
|
@@ -463,22 +782,77 @@ var CurrencyInputController = class _CurrencyInputController extends Controller
|
|
|
463
782
|
}
|
|
464
783
|
#resync() {
|
|
465
784
|
if (!this.hasDisplayTarget) return;
|
|
466
|
-
const
|
|
785
|
+
const unsettled = this.#trackUnsettled(false);
|
|
786
|
+
if (this.#renderedDisplay === null) return;
|
|
787
|
+
const value = unsettled || this.#composition.isComposing() ? this.#lastValue : this.#scan(this.displayTarget.value).value;
|
|
467
788
|
this.#write(value);
|
|
468
789
|
}
|
|
469
|
-
#
|
|
790
|
+
#holdUnsettled(arriving) {
|
|
791
|
+
if (!this.#trackUnsettled(arriving)) return false;
|
|
792
|
+
this.#declarationsHeld = this.#declarationsChanged();
|
|
793
|
+
this.#resync();
|
|
794
|
+
return true;
|
|
795
|
+
}
|
|
796
|
+
#trackUnsettled(arriving) {
|
|
797
|
+
this.#forgetUnsettledOwner();
|
|
798
|
+
if (!this.hasDisplayTarget) return false;
|
|
799
|
+
const display = this.displayTarget;
|
|
800
|
+
const returned = display === this.#departed;
|
|
801
|
+
if (returned) this.#departed = null;
|
|
802
|
+
if (this.#unsettled === null && document.activeElement === display && (arriving || display !== this.#renderedDisplay || returned && !this.#showsOwnRendering(display)) && this.#composition.composingElement() !== display) {
|
|
803
|
+
this.#beginUnsettled(display);
|
|
804
|
+
}
|
|
805
|
+
return this.#unsettled !== null;
|
|
806
|
+
}
|
|
807
|
+
#beginUnsettled(display) {
|
|
808
|
+
if (this.#unsettled === null && this.#renderedDisplay === null && this.#declarationsChanged()) {
|
|
809
|
+
this.#revalidate();
|
|
810
|
+
}
|
|
811
|
+
this.#unsettled = display;
|
|
812
|
+
}
|
|
813
|
+
#forgetUnsettledOwner() {
|
|
814
|
+
if (this.#unsettled !== null && this.hasDisplayTarget && this.#unsettled !== this.displayTarget) {
|
|
815
|
+
if (this.#formatHeld?.display === this.#unsettled) this.#formatHeld = null;
|
|
816
|
+
this.#unsettled = null;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
#protectUnsettled = (event) => {
|
|
820
|
+
this.#holdUnsettled(false);
|
|
821
|
+
if (this.#unsettled === null || event.target !== this.#unsettled) return;
|
|
822
|
+
const detail = event.detail;
|
|
823
|
+
if (detail?.attributeName === "value") event.preventDefault();
|
|
824
|
+
};
|
|
825
|
+
#declared() {
|
|
470
826
|
const resolved = resolveLocale(this.element, this.localeValue);
|
|
471
827
|
const usable = intlFormatter(Intl.NumberFormat, resolved, {});
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
this.#currency = "";
|
|
828
|
+
const locale = usable === null ? FALLBACK_LOCALE : resolved;
|
|
829
|
+
let currency = "";
|
|
475
830
|
if (this.currencyValue !== "") {
|
|
476
|
-
const declaredCurrency = intlFormatter(Intl.NumberFormat,
|
|
831
|
+
const declaredCurrency = intlFormatter(Intl.NumberFormat, locale, {
|
|
477
832
|
style: "currency",
|
|
478
833
|
currency: this.currencyValue
|
|
479
834
|
});
|
|
480
|
-
if (declaredCurrency !== null)
|
|
835
|
+
if (declaredCurrency !== null) currency = this.currencyValue;
|
|
481
836
|
}
|
|
837
|
+
return { locale, currency, precision: this.#safePrecision };
|
|
838
|
+
}
|
|
839
|
+
#owed(composed) {
|
|
840
|
+
if (this.#declarationsHeld) return true;
|
|
841
|
+
if (!this.hasDisplayTarget) return false;
|
|
842
|
+
const display = this.displayTarget;
|
|
843
|
+
return display !== this.#renderedDisplay || display !== composed && !this.#showsOwnRendering(display);
|
|
844
|
+
}
|
|
845
|
+
#declarationsChanged() {
|
|
846
|
+
const { locale, currency, precision } = this.#declared();
|
|
847
|
+
return locale !== this.#locale || currency !== this.#currency || precision !== this.#precision;
|
|
848
|
+
}
|
|
849
|
+
#revalidate() {
|
|
850
|
+
this.#configured = true;
|
|
851
|
+
this.#declarationsHeld = false;
|
|
852
|
+
const declared = this.#declared();
|
|
853
|
+
this.#locale = declared.locale;
|
|
854
|
+
this.#currency = declared.currency;
|
|
855
|
+
this.#precision = declared.precision;
|
|
482
856
|
this.#grouping = intlFormatter(
|
|
483
857
|
Intl.NumberFormat,
|
|
484
858
|
this.#locale,
|