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
|
@@ -43,6 +43,9 @@ var MicrotaskCoalescer = class {
|
|
|
43
43
|
this.#queued = false;
|
|
44
44
|
this.#generation += 1;
|
|
45
45
|
}
|
|
46
|
+
get pending() {
|
|
47
|
+
return this.#queued;
|
|
48
|
+
}
|
|
46
49
|
schedule() {
|
|
47
50
|
if (!this.#active || this.#queued) return;
|
|
48
51
|
this.#queued = true;
|
|
@@ -73,6 +76,9 @@ var MorphRenderWatcher = class {
|
|
|
73
76
|
schedule() {
|
|
74
77
|
this.#pass.schedule();
|
|
75
78
|
}
|
|
79
|
+
get pending() {
|
|
80
|
+
return this.#pass.pending;
|
|
81
|
+
}
|
|
76
82
|
disconnect() {
|
|
77
83
|
this.#listeners.dispose();
|
|
78
84
|
this.#pass.cancel();
|
|
@@ -126,6 +132,94 @@ var NumberValueReader = class {
|
|
|
126
132
|
}
|
|
127
133
|
};
|
|
128
134
|
|
|
135
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
136
|
+
if (element.getAttribute(name) === value) return false;
|
|
137
|
+
if (value === null) element.removeAttribute(name);
|
|
138
|
+
else element.setAttribute(name, value);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
var OwnedText = class {
|
|
143
|
+
#attribute;
|
|
144
|
+
#channel;
|
|
145
|
+
#guard;
|
|
146
|
+
#writes = /* @__PURE__ */ new WeakMap();
|
|
147
|
+
constructor(attribute, channel = "text", guard = () => true) {
|
|
148
|
+
this.#attribute = attribute;
|
|
149
|
+
this.#channel = channel;
|
|
150
|
+
this.#guard = guard;
|
|
151
|
+
}
|
|
152
|
+
hasRecord(element) {
|
|
153
|
+
return element.hasAttribute(this.#attribute);
|
|
154
|
+
}
|
|
155
|
+
read(element, evidence = {}) {
|
|
156
|
+
if (evidence.source === "live") return this.#writes.get(element) ?? null;
|
|
157
|
+
const raw = element.getAttribute(this.#attribute);
|
|
158
|
+
if (raw === null) return null;
|
|
159
|
+
try {
|
|
160
|
+
const record = JSON.parse(raw);
|
|
161
|
+
if (!Array.isArray(record) || record.length !== 3 || record[0] !== this.#channel || typeof record[1] !== "string" || typeof record[2] !== "string")
|
|
162
|
+
return null;
|
|
163
|
+
return { original: record[1], written: record[2] };
|
|
164
|
+
} catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
owns(element, evidence = {}) {
|
|
169
|
+
return this.#ownedRecord(element, evidence) !== null;
|
|
170
|
+
}
|
|
171
|
+
#ownedRecord(element, evidence) {
|
|
172
|
+
const record = this.read(element, evidence);
|
|
173
|
+
if (record === null || !this.#guard(element)) return null;
|
|
174
|
+
if (this.#channel === "text" && element.firstElementChild !== null) return null;
|
|
175
|
+
const current = this.#current(element);
|
|
176
|
+
return current === record.written || evidence.source === "live" && evidence.allowOriginal === true && current === record.original ? record : null;
|
|
177
|
+
}
|
|
178
|
+
write(element, written, original, force = false) {
|
|
179
|
+
const current = this.#current(element);
|
|
180
|
+
if (current === null) return;
|
|
181
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
182
|
+
if (force || current !== written) this.#put(element, written);
|
|
183
|
+
this.remember(element, written, before);
|
|
184
|
+
}
|
|
185
|
+
remember(element, written, original) {
|
|
186
|
+
const current = this.#current(element);
|
|
187
|
+
if (current === null) return;
|
|
188
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
189
|
+
this.#writes.set(element, { original: before, written });
|
|
190
|
+
setAttributeIfChanged(
|
|
191
|
+
element,
|
|
192
|
+
this.#attribute,
|
|
193
|
+
JSON.stringify([this.#channel, before, written])
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
clear(element, evidence = {}) {
|
|
197
|
+
if (!this.owns(element, evidence)) return false;
|
|
198
|
+
if (this.#current(element) !== "") this.#put(element, "");
|
|
199
|
+
this.forget(element);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
restore(element, evidence = {}) {
|
|
203
|
+
const record = this.#ownedRecord(element, evidence);
|
|
204
|
+
if (record === null) return false;
|
|
205
|
+
if (this.#current(element) !== record.original) this.#put(element, record.original);
|
|
206
|
+
this.forget(element);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
forget(element) {
|
|
210
|
+
setAttributeIfChanged(element, this.#attribute, null);
|
|
211
|
+
this.#writes.delete(element);
|
|
212
|
+
}
|
|
213
|
+
#current(element) {
|
|
214
|
+
if (this.#channel === "text") return element.textContent ?? "";
|
|
215
|
+
return element instanceof HTMLInputElement ? element.value : null;
|
|
216
|
+
}
|
|
217
|
+
#put(element, text) {
|
|
218
|
+
if (this.#channel === "text") element.textContent = text;
|
|
219
|
+
else if (element instanceof HTMLInputElement) element.value = text;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
129
223
|
var TimerRegistry = class {
|
|
130
224
|
ids = /* @__PURE__ */ new Set();
|
|
131
225
|
clear(id) {
|
|
@@ -181,17 +275,14 @@ var ClipboardController = class _ClipboardController extends Controller {
|
|
|
181
275
|
#connected = false;
|
|
182
276
|
#result = null;
|
|
183
277
|
#feedback = null;
|
|
184
|
-
#
|
|
278
|
+
#feedbackText = new OwnedText(`data-${this.identifier}-feedback-text`);
|
|
279
|
+
#written = /* @__PURE__ */ new Set();
|
|
185
280
|
#morphRender = new MorphRenderWatcher(() => this.#renderResult());
|
|
186
281
|
connect() {
|
|
187
282
|
this.#connected = true;
|
|
188
283
|
this.#adopt();
|
|
189
284
|
this.#result = null;
|
|
190
|
-
this.#feedback = this.hasFeedbackTarget ? {
|
|
191
|
-
element: this.feedbackTarget,
|
|
192
|
-
original: this.feedbackTarget.textContent ?? "",
|
|
193
|
-
text: this.feedbackTarget.textContent ?? ""
|
|
194
|
-
} : null;
|
|
285
|
+
this.#feedback = this.hasFeedbackTarget ? { element: this.feedbackTarget, original: this.feedbackTarget.textContent ?? "" } : null;
|
|
195
286
|
this.#morphRender.observe(this.element);
|
|
196
287
|
}
|
|
197
288
|
disconnect() {
|
|
@@ -230,9 +321,8 @@ var ClipboardController = class _ClipboardController extends Controller {
|
|
|
230
321
|
}
|
|
231
322
|
#adopt() {
|
|
232
323
|
if (this.#inTransientState()) {
|
|
233
|
-
const restored = this.#written.size === 0;
|
|
234
324
|
this.#reset();
|
|
235
|
-
|
|
325
|
+
for (const element of this.feedbackTargets) this.#feedbackText.clear(element);
|
|
236
326
|
return;
|
|
237
327
|
}
|
|
238
328
|
setDefaultAttribute(this.element, "data-state", "idle");
|
|
@@ -255,17 +345,15 @@ var ClipboardController = class _ClipboardController extends Controller {
|
|
|
255
345
|
this.element.setAttribute("data-state", this.#result ? "copied" : "error");
|
|
256
346
|
if (!this.hasFeedbackTarget) return;
|
|
257
347
|
const element = this.feedbackTarget;
|
|
258
|
-
|
|
259
|
-
if (!force && (!held || element !== held.element || element.firstElementChild !== null || element.textContent !== held.text && element.textContent !== held.original))
|
|
260
|
-
return;
|
|
348
|
+
if (!force && (element !== this.#feedback?.element || !this.#ownsFeedback(element))) return;
|
|
261
349
|
const text = this.#result ? this.copiedLabelValue : this.errorLabelValue;
|
|
262
|
-
this.#feedback
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
this.#
|
|
350
|
+
const original = element === this.#feedback?.element ? this.#feedback.original : element.textContent ?? "";
|
|
351
|
+
this.#feedback = { element, original };
|
|
352
|
+
this.#feedbackText.write(element, text, original, force);
|
|
353
|
+
this.#written.add(element);
|
|
354
|
+
}
|
|
355
|
+
#ownsFeedback(element) {
|
|
356
|
+
return this.#feedbackText.owns(element) || !this.#feedbackText.hasRecord(element) && this.#feedbackText.owns(element, { source: "live", allowOriginal: true });
|
|
269
357
|
}
|
|
270
358
|
#announceResult(success) {
|
|
271
359
|
announce(success ? this.announceCopiedTextValue : this.announceErrorTextValue);
|
|
@@ -279,19 +367,22 @@ var ClipboardController = class _ClipboardController extends Controller {
|
|
|
279
367
|
#followLabel(state, label, previous) {
|
|
280
368
|
if (!this.#connected) return;
|
|
281
369
|
if (this.element.getAttribute("data-state") !== state || !this.hasFeedbackTarget) return;
|
|
282
|
-
|
|
283
|
-
this.
|
|
284
|
-
|
|
285
|
-
|
|
370
|
+
const element = this.feedbackTarget;
|
|
371
|
+
if (element !== this.#feedback?.element || element.textContent !== previous || !this.#ownsFeedback(element))
|
|
372
|
+
return;
|
|
373
|
+
this.#feedbackText.write(element, label);
|
|
374
|
+
this.#written.add(element);
|
|
286
375
|
}
|
|
287
376
|
#reset() {
|
|
288
377
|
this.#result = null;
|
|
289
378
|
this.element.setAttribute("data-state", "idle");
|
|
290
|
-
for (const
|
|
291
|
-
if (
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
379
|
+
for (const element of this.#written) {
|
|
380
|
+
if (this.feedbackTargets.includes(element))
|
|
381
|
+
this.#feedbackText.clear(
|
|
382
|
+
element,
|
|
383
|
+
this.#feedbackText.hasRecord(element) ? {} : { source: "live" }
|
|
384
|
+
);
|
|
385
|
+
this.#feedbackText.forget(element);
|
|
295
386
|
}
|
|
296
387
|
this.#written.clear();
|
|
297
388
|
}
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
4
|
+
if (element.getAttribute(name) === value) return false;
|
|
5
|
+
if (value === null) element.removeAttribute(name);
|
|
6
|
+
else element.setAttribute(name, value);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
function sharedRegistry(key, create) {
|
|
4
11
|
const symbol = Symbol.for(key);
|
|
5
12
|
const scope = globalThis;
|
|
6
13
|
const existing = scope[symbol];
|
|
7
14
|
if (existing !== void 0) return existing;
|
|
8
|
-
const
|
|
9
|
-
Object.defineProperty(globalThis, symbol, { value:
|
|
10
|
-
return
|
|
15
|
+
const registry2 = create();
|
|
16
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
17
|
+
return registry2;
|
|
11
18
|
}
|
|
12
19
|
|
|
20
|
+
var registry = sharedRegistry(
|
|
21
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
22
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
23
|
+
);
|
|
13
24
|
function isAttributeValue(value) {
|
|
14
25
|
return value === null || typeof value === "string";
|
|
15
26
|
}
|
|
@@ -26,24 +37,46 @@ function readLeaseRecord(element, record) {
|
|
|
26
37
|
return void 0;
|
|
27
38
|
}
|
|
28
39
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
);
|
|
40
|
+
function attributeStack(element, attribute) {
|
|
41
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
42
|
+
registry.stacks.set(element, byAttribute);
|
|
43
|
+
const known = byAttribute.get(attribute);
|
|
44
|
+
if (known) return known;
|
|
45
|
+
const found = [];
|
|
46
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
47
|
+
const read = readLeaseRecord(element, record);
|
|
48
|
+
if (read) found.push({ ...read, record });
|
|
49
|
+
}
|
|
50
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
51
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
52
|
+
lease: null,
|
|
53
|
+
record,
|
|
54
|
+
written,
|
|
55
|
+
original,
|
|
56
|
+
linked: linked && index > 0
|
|
57
|
+
}));
|
|
58
|
+
byAttribute.set(attribute, stack);
|
|
59
|
+
return stack;
|
|
60
|
+
}
|
|
61
|
+
function findHold(stack, lease, record) {
|
|
62
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
63
|
+
}
|
|
64
|
+
var AttributeLease = class {
|
|
34
65
|
#attribute;
|
|
35
66
|
#record;
|
|
36
67
|
#base;
|
|
68
|
+
#preserveAuthor;
|
|
37
69
|
#held = /* @__PURE__ */ new Set();
|
|
38
70
|
constructor(attribute, owner, options = {}) {
|
|
39
71
|
this.#attribute = attribute;
|
|
40
72
|
this.#record = `data-${owner}-${attribute}-lease`;
|
|
41
73
|
this.#base = options.base === true;
|
|
42
|
-
|
|
74
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
75
|
+
const names = registry.names;
|
|
43
76
|
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
44
77
|
}
|
|
45
78
|
write(element, value) {
|
|
46
|
-
const stack = this.#
|
|
79
|
+
const stack = attributeStack(element, this.#attribute);
|
|
47
80
|
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
48
81
|
this.#held.add(element);
|
|
49
82
|
const shows = !this.#covered(element, stack, hold);
|
|
@@ -53,8 +86,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
53
86
|
}
|
|
54
87
|
return(element) {
|
|
55
88
|
const held = this.#held.delete(element);
|
|
56
|
-
const known =
|
|
57
|
-
const stack = held || known || element.hasAttribute(this.#record) ? this.#
|
|
89
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
90
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
58
91
|
const hold = this.#take(stack);
|
|
59
92
|
if (!hold) return false;
|
|
60
93
|
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
@@ -72,31 +105,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
72
105
|
returnAll() {
|
|
73
106
|
for (const element of Array.from(this.#held)) this.return(element);
|
|
74
107
|
}
|
|
75
|
-
#stack(element) {
|
|
76
|
-
const stacks = _AttributeLease.#registry.stacks;
|
|
77
|
-
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
78
|
-
stacks.set(element, byAttribute);
|
|
79
|
-
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
80
|
-
byAttribute.set(this.#attribute, stack);
|
|
81
|
-
return stack;
|
|
82
|
-
}
|
|
83
|
-
#seed(element) {
|
|
84
|
-
const found = [];
|
|
85
|
-
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
86
|
-
const read = readLeaseRecord(element, record);
|
|
87
|
-
if (read) found.push({ ...read, record });
|
|
88
|
-
}
|
|
89
|
-
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
90
|
-
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
91
|
-
lease: null,
|
|
92
|
-
record,
|
|
93
|
-
written,
|
|
94
|
-
original,
|
|
95
|
-
linked: linked && index > 0
|
|
96
|
-
}));
|
|
97
|
-
}
|
|
98
108
|
#take(stack) {
|
|
99
|
-
const hold = stack
|
|
109
|
+
const hold = findHold(stack, this, this.#record);
|
|
100
110
|
if (hold) hold.lease = this;
|
|
101
111
|
return hold;
|
|
102
112
|
}
|
|
@@ -105,7 +115,7 @@ var AttributeLease = class _AttributeLease {
|
|
|
105
115
|
const top = stack.at(-1);
|
|
106
116
|
const bottom = stack[0];
|
|
107
117
|
const over = top?.written === current ? top : void 0;
|
|
108
|
-
const from = this.#base ? bottom : over;
|
|
118
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
109
119
|
const hold = {
|
|
110
120
|
lease: this,
|
|
111
121
|
record: this.#record,
|
|
@@ -135,15 +145,11 @@ var AttributeLease = class _AttributeLease {
|
|
|
135
145
|
);
|
|
136
146
|
});
|
|
137
147
|
for (const [name, recorded] of records) {
|
|
138
|
-
|
|
139
|
-
if (recorded === null) element.removeAttribute(name);
|
|
140
|
-
else element.setAttribute(name, recorded);
|
|
148
|
+
setAttributeIfChanged(element, name, recorded);
|
|
141
149
|
}
|
|
142
150
|
}
|
|
143
151
|
#reflect(element, value) {
|
|
144
|
-
|
|
145
|
-
if (value === null) element.removeAttribute(this.#attribute);
|
|
146
|
-
else element.setAttribute(this.#attribute, value);
|
|
152
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
147
153
|
}
|
|
148
154
|
};
|
|
149
155
|
|
|
@@ -200,9 +206,8 @@ var StateRegions = class _StateRegions {
|
|
|
200
206
|
const below = hold.linked ? stack[index - 1] : void 0;
|
|
201
207
|
if (below) {
|
|
202
208
|
if (region.hidden !== below.written) region.hidden = below.written;
|
|
203
|
-
} else
|
|
204
|
-
|
|
205
|
-
else region.setAttribute("hidden", hold.authored);
|
|
209
|
+
} else {
|
|
210
|
+
setAttributeIfChanged(region, "hidden", hold.authored);
|
|
206
211
|
}
|
|
207
212
|
}
|
|
208
213
|
this.#mark(region, stack);
|
|
@@ -277,9 +282,7 @@ var StateRegions = class _StateRegions {
|
|
|
277
282
|
);
|
|
278
283
|
});
|
|
279
284
|
for (const [name, recorded] of records) {
|
|
280
|
-
|
|
281
|
-
if (recorded === null) region.removeAttribute(name);
|
|
282
|
-
else region.setAttribute(name, recorded);
|
|
285
|
+
setAttributeIfChanged(region, name, recorded);
|
|
283
286
|
}
|
|
284
287
|
}
|
|
285
288
|
#recorded(region, name) {
|
|
@@ -13,6 +13,16 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
13
13
|
if (!event.key.startsWith("Arrow")) return false;
|
|
14
14
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
15
15
|
}
|
|
16
|
+
function hasModifierChord(event) {
|
|
17
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
21
|
+
if (element.getAttribute(name) === value) return false;
|
|
22
|
+
if (value === null) element.removeAttribute(name);
|
|
23
|
+
else element.setAttribute(name, value);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
16
26
|
|
|
17
27
|
function toFiniteNumber(raw) {
|
|
18
28
|
if (typeof raw !== "number" && typeof raw !== "string") return null;
|
|
@@ -65,6 +75,9 @@ var MicrotaskCoalescer = class {
|
|
|
65
75
|
this.#queued = false;
|
|
66
76
|
this.#generation += 1;
|
|
67
77
|
}
|
|
78
|
+
get pending() {
|
|
79
|
+
return this.#queued;
|
|
80
|
+
}
|
|
68
81
|
schedule() {
|
|
69
82
|
if (!this.#active || this.#queued) return;
|
|
70
83
|
this.#queued = true;
|
|
@@ -95,6 +108,9 @@ var MorphRenderWatcher = class {
|
|
|
95
108
|
schedule() {
|
|
96
109
|
this.#pass.schedule();
|
|
97
110
|
}
|
|
111
|
+
get pending() {
|
|
112
|
+
return this.#pass.pending;
|
|
113
|
+
}
|
|
98
114
|
disconnect() {
|
|
99
115
|
this.#listeners.dispose();
|
|
100
116
|
this.#pass.cancel();
|
|
@@ -156,6 +172,13 @@ var OwnedPointerSession = class {
|
|
|
156
172
|
};
|
|
157
173
|
};
|
|
158
174
|
|
|
175
|
+
function fillTemplate(template, values) {
|
|
176
|
+
return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
|
|
177
|
+
const replacement = Object.hasOwn(values, name) ? values[name] : void 0;
|
|
178
|
+
return replacement === void 0 ? match : String(replacement);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
159
182
|
var COLOR_PROPERTY = "--stimeo--color";
|
|
160
183
|
var VALUE_TEXT_ATTRIBUTE = "data-value-text";
|
|
161
184
|
var CHANNEL_RANGE = {
|
|
@@ -179,9 +202,6 @@ var ColorPickerController = class extends Controller {
|
|
|
179
202
|
};
|
|
180
203
|
static actions = ["onHexInput", "onKeydown", "onPointerDown"];
|
|
181
204
|
static events = ["change", "reconcile"];
|
|
182
|
-
get #mirrored() {
|
|
183
|
-
return this.logicalTrackValue && isRtl(this.element);
|
|
184
|
-
}
|
|
185
205
|
#color = { hue: 0, saturation: 0, lightness: 0, alpha: 100 };
|
|
186
206
|
#drag = null;
|
|
187
207
|
#committedHex = null;
|
|
@@ -225,6 +245,8 @@ var ColorPickerController = class extends Controller {
|
|
|
225
245
|
}
|
|
226
246
|
onKeydown(event) {
|
|
227
247
|
if (isReservedArrowChord(event)) return;
|
|
248
|
+
if ((event.key === "Home" || event.key === "End" || event.key === "PageUp" || event.key === "PageDown") && hasModifierChord(event))
|
|
249
|
+
return;
|
|
228
250
|
const slider = event.currentTarget;
|
|
229
251
|
const channel = this.#editableChannel(slider);
|
|
230
252
|
if (!channel) return;
|
|
@@ -232,7 +254,7 @@ var ColorPickerController = class extends Controller {
|
|
|
232
254
|
const [min, max] = this.#rangeOf(slider, channel);
|
|
233
255
|
const value = this.#color[channel];
|
|
234
256
|
let next = null;
|
|
235
|
-
switch (this
|
|
257
|
+
switch (this.logicalTrackValue ? logicalArrowKey(event.key, slider) : event.key) {
|
|
236
258
|
case "ArrowRight":
|
|
237
259
|
case "ArrowUp":
|
|
238
260
|
next = value + 1;
|
|
@@ -265,7 +287,7 @@ var ColorPickerController = class extends Controller {
|
|
|
265
287
|
const channel = this.#editableChannel(slider);
|
|
266
288
|
if (!channel) return;
|
|
267
289
|
const [min, max] = this.#rangeOf(slider, channel);
|
|
268
|
-
const mirrored = this
|
|
290
|
+
const mirrored = this.logicalTrackValue && isRtl(slider);
|
|
269
291
|
const update = (clientX) => {
|
|
270
292
|
const rect = slider.getBoundingClientRect();
|
|
271
293
|
if (rect.width === 0) return false;
|
|
@@ -380,7 +402,7 @@ var ColorPickerController = class extends Controller {
|
|
|
380
402
|
"aria-valuetext": this.#valueText(slider, channel, value)
|
|
381
403
|
};
|
|
382
404
|
for (const [name, next] of Object.entries(attributes)) {
|
|
383
|
-
|
|
405
|
+
setAttributeIfChanged(slider, name, next);
|
|
384
406
|
}
|
|
385
407
|
}
|
|
386
408
|
#writeHex(input, hex) {
|
|
@@ -439,7 +461,7 @@ var ColorPickerController = class extends Controller {
|
|
|
439
461
|
}
|
|
440
462
|
#valueText(slider, channel, value) {
|
|
441
463
|
const template = slider.getAttribute(VALUE_TEXT_ATTRIBUTE);
|
|
442
|
-
return template ? template
|
|
464
|
+
return template ? fillTemplate(template, { value }) : defaultValueText(channel, value);
|
|
443
465
|
}
|
|
444
466
|
#endDrag() {
|
|
445
467
|
const drag = this.#drag;
|