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
|
@@ -15,9 +15,9 @@ function sharedRegistry(key, create) {
|
|
|
15
15
|
const scope = globalThis;
|
|
16
16
|
const existing = scope[symbol];
|
|
17
17
|
if (existing !== void 0) return existing;
|
|
18
|
-
const
|
|
19
|
-
Object.defineProperty(globalThis, symbol, { value:
|
|
20
|
-
return
|
|
18
|
+
const registry2 = create();
|
|
19
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
20
|
+
return registry2;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
var ids = sharedRegistry("stimeo-ui.aria-ids.registry.v1", () => ({ counter: 0 }));
|
|
@@ -36,6 +36,17 @@ function ensureId(element, prefix = "stimeo") {
|
|
|
36
36
|
return id;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
40
|
+
if (element.getAttribute(name) === value) return false;
|
|
41
|
+
if (value === null) element.removeAttribute(name);
|
|
42
|
+
else element.setAttribute(name, value);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var registry = sharedRegistry(
|
|
47
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
48
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
49
|
+
);
|
|
39
50
|
function isAttributeValue(value) {
|
|
40
51
|
return value === null || typeof value === "string";
|
|
41
52
|
}
|
|
@@ -52,24 +63,46 @@ function readLeaseRecord(element, record) {
|
|
|
52
63
|
return void 0;
|
|
53
64
|
}
|
|
54
65
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
);
|
|
66
|
+
function attributeStack(element, attribute) {
|
|
67
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
68
|
+
registry.stacks.set(element, byAttribute);
|
|
69
|
+
const known = byAttribute.get(attribute);
|
|
70
|
+
if (known) return known;
|
|
71
|
+
const found = [];
|
|
72
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
73
|
+
const read = readLeaseRecord(element, record);
|
|
74
|
+
if (read) found.push({ ...read, record });
|
|
75
|
+
}
|
|
76
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
77
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
78
|
+
lease: null,
|
|
79
|
+
record,
|
|
80
|
+
written,
|
|
81
|
+
original,
|
|
82
|
+
linked: linked && index > 0
|
|
83
|
+
}));
|
|
84
|
+
byAttribute.set(attribute, stack);
|
|
85
|
+
return stack;
|
|
86
|
+
}
|
|
87
|
+
function findHold(stack, lease, record) {
|
|
88
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
89
|
+
}
|
|
90
|
+
var AttributeLease = class {
|
|
60
91
|
#attribute;
|
|
61
92
|
#record;
|
|
62
93
|
#base;
|
|
94
|
+
#preserveAuthor;
|
|
63
95
|
#held = /* @__PURE__ */ new Set();
|
|
64
96
|
constructor(attribute, owner, options = {}) {
|
|
65
97
|
this.#attribute = attribute;
|
|
66
98
|
this.#record = `data-${owner}-${attribute}-lease`;
|
|
67
99
|
this.#base = options.base === true;
|
|
68
|
-
|
|
100
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
101
|
+
const names = registry.names;
|
|
69
102
|
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
70
103
|
}
|
|
71
104
|
write(element, value) {
|
|
72
|
-
const stack = this.#
|
|
105
|
+
const stack = attributeStack(element, this.#attribute);
|
|
73
106
|
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
74
107
|
this.#held.add(element);
|
|
75
108
|
const shows = !this.#covered(element, stack, hold);
|
|
@@ -79,8 +112,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
79
112
|
}
|
|
80
113
|
return(element) {
|
|
81
114
|
const held = this.#held.delete(element);
|
|
82
|
-
const known =
|
|
83
|
-
const stack = held || known || element.hasAttribute(this.#record) ? this.#
|
|
115
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
116
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
84
117
|
const hold = this.#take(stack);
|
|
85
118
|
if (!hold) return false;
|
|
86
119
|
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
@@ -98,31 +131,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
98
131
|
returnAll() {
|
|
99
132
|
for (const element of Array.from(this.#held)) this.return(element);
|
|
100
133
|
}
|
|
101
|
-
#stack(element) {
|
|
102
|
-
const stacks = _AttributeLease.#registry.stacks;
|
|
103
|
-
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
104
|
-
stacks.set(element, byAttribute);
|
|
105
|
-
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
106
|
-
byAttribute.set(this.#attribute, stack);
|
|
107
|
-
return stack;
|
|
108
|
-
}
|
|
109
|
-
#seed(element) {
|
|
110
|
-
const found = [];
|
|
111
|
-
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
112
|
-
const read = readLeaseRecord(element, record);
|
|
113
|
-
if (read) found.push({ ...read, record });
|
|
114
|
-
}
|
|
115
|
-
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
116
|
-
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
117
|
-
lease: null,
|
|
118
|
-
record,
|
|
119
|
-
written,
|
|
120
|
-
original,
|
|
121
|
-
linked: linked && index > 0
|
|
122
|
-
}));
|
|
123
|
-
}
|
|
124
134
|
#take(stack) {
|
|
125
|
-
const hold = stack
|
|
135
|
+
const hold = findHold(stack, this, this.#record);
|
|
126
136
|
if (hold) hold.lease = this;
|
|
127
137
|
return hold;
|
|
128
138
|
}
|
|
@@ -131,7 +141,7 @@ var AttributeLease = class _AttributeLease {
|
|
|
131
141
|
const top = stack.at(-1);
|
|
132
142
|
const bottom = stack[0];
|
|
133
143
|
const over = top?.written === current ? top : void 0;
|
|
134
|
-
const from = this.#base ? bottom : over;
|
|
144
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
135
145
|
const hold = {
|
|
136
146
|
lease: this,
|
|
137
147
|
record: this.#record,
|
|
@@ -161,15 +171,11 @@ var AttributeLease = class _AttributeLease {
|
|
|
161
171
|
);
|
|
162
172
|
});
|
|
163
173
|
for (const [name, recorded] of records) {
|
|
164
|
-
|
|
165
|
-
if (recorded === null) element.removeAttribute(name);
|
|
166
|
-
else element.setAttribute(name, recorded);
|
|
174
|
+
setAttributeIfChanged(element, name, recorded);
|
|
167
175
|
}
|
|
168
176
|
}
|
|
169
177
|
#reflect(element, value) {
|
|
170
|
-
|
|
171
|
-
if (value === null) element.removeAttribute(this.#attribute);
|
|
172
|
-
else element.setAttribute(this.#attribute, value);
|
|
178
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
173
179
|
}
|
|
174
180
|
};
|
|
175
181
|
|
|
@@ -194,6 +200,9 @@ var MicrotaskCoalescer = class {
|
|
|
194
200
|
this.#queued = false;
|
|
195
201
|
this.#generation += 1;
|
|
196
202
|
}
|
|
203
|
+
get pending() {
|
|
204
|
+
return this.#queued;
|
|
205
|
+
}
|
|
197
206
|
schedule() {
|
|
198
207
|
if (!this.#active || this.#queued) return;
|
|
199
208
|
this.#queued = true;
|
|
@@ -91,6 +91,17 @@ function firstTabStop(root) {
|
|
|
91
91
|
return null;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
var ListenerSet = class {
|
|
95
|
+
#abort = new AbortController();
|
|
96
|
+
add(target, type, handler, options) {
|
|
97
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
98
|
+
}
|
|
99
|
+
dispose() {
|
|
100
|
+
this.#abort.abort();
|
|
101
|
+
this.#abort = new AbortController();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
94
105
|
var CONSTRAINT_MESSAGE_KEYS = [
|
|
95
106
|
["valueMissing", "value-missing"],
|
|
96
107
|
["typeMismatch", "type-mismatch"],
|
|
@@ -127,7 +138,7 @@ var FormValidationController = class _FormValidationController extends Controlle
|
|
|
127
138
|
#touchedRadioGroups = /* @__PURE__ */ new Set();
|
|
128
139
|
#ownedCustomErrors = /* @__PURE__ */ new Map();
|
|
129
140
|
#reportedErrors = /* @__PURE__ */ new WeakMap();
|
|
130
|
-
#
|
|
141
|
+
#listeners = new ListenerSet();
|
|
131
142
|
#onSubmit = (event) => {
|
|
132
143
|
if (event.target !== this.element) return;
|
|
133
144
|
const invalid = this.#validateAll();
|
|
@@ -169,18 +180,14 @@ var FormValidationController = class _FormValidationController extends Controlle
|
|
|
169
180
|
if (setDefaultAttribute(this.element, "novalidate", "")) {
|
|
170
181
|
this.element.setAttribute(this.#novalidateMarker, "");
|
|
171
182
|
}
|
|
172
|
-
|
|
173
|
-
this.#
|
|
174
|
-
this.#
|
|
175
|
-
this.#
|
|
176
|
-
this.#
|
|
183
|
+
const { ownerDocument } = this.element;
|
|
184
|
+
this.#listeners.add(ownerDocument, "submit", this.#onSubmit, { capture: true });
|
|
185
|
+
this.#listeners.add(ownerDocument, "focusout", this.#onFocusOut);
|
|
186
|
+
this.#listeners.add(ownerDocument, "input", this.#onInput);
|
|
187
|
+
this.#listeners.add(ownerDocument, "change", this.#onChange);
|
|
177
188
|
}
|
|
178
189
|
disconnect() {
|
|
179
|
-
this.#
|
|
180
|
-
this.#listenerDocument?.removeEventListener("focusout", this.#onFocusOut);
|
|
181
|
-
this.#listenerDocument?.removeEventListener("input", this.#onInput);
|
|
182
|
-
this.#listenerDocument?.removeEventListener("change", this.#onChange);
|
|
183
|
-
this.#listenerDocument = null;
|
|
190
|
+
this.#listeners.dispose();
|
|
184
191
|
for (const [control, message] of this.#ownedCustomErrors) {
|
|
185
192
|
if (control.validationMessage === message) control.setCustomValidity("");
|
|
186
193
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
+
function fillTemplate(template, values) {
|
|
4
|
+
return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
|
|
5
|
+
const replacement = Object.hasOwn(values, name) ? values[name] : void 0;
|
|
6
|
+
return replacement === void 0 ? match : String(replacement);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
function announce(message, options = {}) {
|
|
4
11
|
const text = message.trim();
|
|
5
12
|
if (text.length === 0) return;
|
|
@@ -9,11 +16,12 @@ function announce(message, options = {}) {
|
|
|
9
16
|
})
|
|
10
17
|
);
|
|
11
18
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
function sharedRegistry(key, create) {
|
|
@@ -21,11 +29,15 @@ function sharedRegistry(key, create) {
|
|
|
21
29
|
const scope = globalThis;
|
|
22
30
|
const existing = scope[symbol];
|
|
23
31
|
if (existing !== void 0) return existing;
|
|
24
|
-
const
|
|
25
|
-
Object.defineProperty(globalThis, symbol, { value:
|
|
26
|
-
return
|
|
32
|
+
const registry2 = create();
|
|
33
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
34
|
+
return registry2;
|
|
27
35
|
}
|
|
28
36
|
|
|
37
|
+
var registry = sharedRegistry(
|
|
38
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
39
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
40
|
+
);
|
|
29
41
|
function isAttributeValue(value) {
|
|
30
42
|
return value === null || typeof value === "string";
|
|
31
43
|
}
|
|
@@ -42,24 +54,46 @@ function readLeaseRecord(element, record) {
|
|
|
42
54
|
return void 0;
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
57
|
+
function attributeStack(element, attribute) {
|
|
58
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
59
|
+
registry.stacks.set(element, byAttribute);
|
|
60
|
+
const known = byAttribute.get(attribute);
|
|
61
|
+
if (known) return known;
|
|
62
|
+
const found = [];
|
|
63
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
64
|
+
const read = readLeaseRecord(element, record);
|
|
65
|
+
if (read) found.push({ ...read, record });
|
|
66
|
+
}
|
|
67
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
68
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
69
|
+
lease: null,
|
|
70
|
+
record,
|
|
71
|
+
written,
|
|
72
|
+
original,
|
|
73
|
+
linked: linked && index > 0
|
|
74
|
+
}));
|
|
75
|
+
byAttribute.set(attribute, stack);
|
|
76
|
+
return stack;
|
|
77
|
+
}
|
|
78
|
+
function findHold(stack, lease, record) {
|
|
79
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
80
|
+
}
|
|
81
|
+
var AttributeLease = class {
|
|
50
82
|
#attribute;
|
|
51
83
|
#record;
|
|
52
84
|
#base;
|
|
85
|
+
#preserveAuthor;
|
|
53
86
|
#held = /* @__PURE__ */ new Set();
|
|
54
87
|
constructor(attribute, owner, options = {}) {
|
|
55
88
|
this.#attribute = attribute;
|
|
56
89
|
this.#record = `data-${owner}-${attribute}-lease`;
|
|
57
90
|
this.#base = options.base === true;
|
|
58
|
-
|
|
91
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
92
|
+
const names = registry.names;
|
|
59
93
|
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
60
94
|
}
|
|
61
95
|
write(element, value) {
|
|
62
|
-
const stack = this.#
|
|
96
|
+
const stack = attributeStack(element, this.#attribute);
|
|
63
97
|
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
64
98
|
this.#held.add(element);
|
|
65
99
|
const shows = !this.#covered(element, stack, hold);
|
|
@@ -69,8 +103,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
69
103
|
}
|
|
70
104
|
return(element) {
|
|
71
105
|
const held = this.#held.delete(element);
|
|
72
|
-
const known =
|
|
73
|
-
const stack = held || known || element.hasAttribute(this.#record) ? this.#
|
|
106
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
107
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
74
108
|
const hold = this.#take(stack);
|
|
75
109
|
if (!hold) return false;
|
|
76
110
|
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
@@ -88,31 +122,8 @@ var AttributeLease = class _AttributeLease {
|
|
|
88
122
|
returnAll() {
|
|
89
123
|
for (const element of Array.from(this.#held)) this.return(element);
|
|
90
124
|
}
|
|
91
|
-
#stack(element) {
|
|
92
|
-
const stacks = _AttributeLease.#registry.stacks;
|
|
93
|
-
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
94
|
-
stacks.set(element, byAttribute);
|
|
95
|
-
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
96
|
-
byAttribute.set(this.#attribute, stack);
|
|
97
|
-
return stack;
|
|
98
|
-
}
|
|
99
|
-
#seed(element) {
|
|
100
|
-
const found = [];
|
|
101
|
-
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
102
|
-
const read = readLeaseRecord(element, record);
|
|
103
|
-
if (read) found.push({ ...read, record });
|
|
104
|
-
}
|
|
105
|
-
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
106
|
-
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
107
|
-
lease: null,
|
|
108
|
-
record,
|
|
109
|
-
written,
|
|
110
|
-
original,
|
|
111
|
-
linked: linked && index > 0
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
125
|
#take(stack) {
|
|
115
|
-
const hold = stack
|
|
126
|
+
const hold = findHold(stack, this, this.#record);
|
|
116
127
|
if (hold) hold.lease = this;
|
|
117
128
|
return hold;
|
|
118
129
|
}
|
|
@@ -121,7 +132,7 @@ var AttributeLease = class _AttributeLease {
|
|
|
121
132
|
const top = stack.at(-1);
|
|
122
133
|
const bottom = stack[0];
|
|
123
134
|
const over = top?.written === current ? top : void 0;
|
|
124
|
-
const from = this.#base ? bottom : over;
|
|
135
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
125
136
|
const hold = {
|
|
126
137
|
lease: this,
|
|
127
138
|
record: this.#record,
|
|
@@ -151,15 +162,11 @@ var AttributeLease = class _AttributeLease {
|
|
|
151
162
|
);
|
|
152
163
|
});
|
|
153
164
|
for (const [name, recorded] of records) {
|
|
154
|
-
|
|
155
|
-
if (recorded === null) element.removeAttribute(name);
|
|
156
|
-
else element.setAttribute(name, recorded);
|
|
165
|
+
setAttributeIfChanged(element, name, recorded);
|
|
157
166
|
}
|
|
158
167
|
}
|
|
159
168
|
#reflect(element, value) {
|
|
160
|
-
|
|
161
|
-
if (value === null) element.removeAttribute(this.#attribute);
|
|
162
|
-
else element.setAttribute(this.#attribute, value);
|
|
169
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
163
170
|
}
|
|
164
171
|
};
|
|
165
172
|
|
|
@@ -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
|
|
|
@@ -155,25 +161,25 @@ var EscapeLayer = class _EscapeLayer {
|
|
|
155
161
|
#active = null;
|
|
156
162
|
activate(ownerDocument = document, options) {
|
|
157
163
|
this.deactivate();
|
|
158
|
-
let
|
|
159
|
-
if (!
|
|
160
|
-
|
|
161
|
-
_EscapeLayer.#registries.set(ownerDocument,
|
|
162
|
-
ownerDocument.addEventListener("keydown",
|
|
164
|
+
let registry2 = _EscapeLayer.#registries.get(ownerDocument);
|
|
165
|
+
if (!registry2) {
|
|
166
|
+
registry2 = _EscapeLayer.#createRegistry();
|
|
167
|
+
_EscapeLayer.#registries.set(ownerDocument, registry2);
|
|
168
|
+
ownerDocument.addEventListener("keydown", registry2.onKeydown);
|
|
163
169
|
}
|
|
164
170
|
const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
|
|
165
|
-
|
|
171
|
+
registry2.stack.push(entry);
|
|
166
172
|
this.#active = { document: ownerDocument, entry };
|
|
167
173
|
}
|
|
168
174
|
deactivate() {
|
|
169
175
|
const active = this.#active;
|
|
170
176
|
if (!active) return;
|
|
171
|
-
const
|
|
172
|
-
if (
|
|
173
|
-
const index =
|
|
174
|
-
if (index >= 0)
|
|
175
|
-
if (
|
|
176
|
-
active.document.removeEventListener("keydown",
|
|
177
|
+
const registry2 = _EscapeLayer.#registries.get(active.document);
|
|
178
|
+
if (registry2) {
|
|
179
|
+
const index = registry2.stack.lastIndexOf(active.entry);
|
|
180
|
+
if (index >= 0) registry2.stack.splice(index, 1);
|
|
181
|
+
if (registry2.stack.length === 0) {
|
|
182
|
+
active.document.removeEventListener("keydown", registry2.onKeydown);
|
|
177
183
|
_EscapeLayer.#registries.delete(active.document);
|
|
178
184
|
}
|
|
179
185
|
}
|
|
@@ -182,22 +188,22 @@ var EscapeLayer = class _EscapeLayer {
|
|
|
182
188
|
get ownsEscape() {
|
|
183
189
|
const active = this.#active;
|
|
184
190
|
if (!active) return false;
|
|
185
|
-
const
|
|
186
|
-
if (!
|
|
187
|
-
return _EscapeLayer.#resolveOwner(
|
|
191
|
+
const registry2 = _EscapeLayer.#registries.get(active.document);
|
|
192
|
+
if (!registry2) return false;
|
|
193
|
+
return _EscapeLayer.#resolveOwner(registry2.stack) === active.entry;
|
|
188
194
|
}
|
|
189
195
|
static #createRegistry() {
|
|
190
|
-
const
|
|
196
|
+
const registry2 = {
|
|
191
197
|
stack: [],
|
|
192
198
|
onKeydown: (event) => {
|
|
193
199
|
if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
|
|
194
|
-
const owner = _EscapeLayer.#resolveOwner(
|
|
200
|
+
const owner = _EscapeLayer.#resolveOwner(registry2.stack);
|
|
195
201
|
if (!owner) return;
|
|
196
202
|
event.preventDefault();
|
|
197
203
|
owner.onDismiss();
|
|
198
204
|
}
|
|
199
205
|
};
|
|
200
|
-
return
|
|
206
|
+
return registry2;
|
|
201
207
|
}
|
|
202
208
|
static #resolveOwner(stack) {
|
|
203
209
|
for (let index = stack.length - 1; index >= 0; index--) {
|
|
@@ -93,6 +93,13 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
93
93
|
}
|
|
94
94
|
};
|
|
95
95
|
|
|
96
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
97
|
+
if (element.getAttribute(name) === value) return false;
|
|
98
|
+
if (value === null) element.removeAttribute(name);
|
|
99
|
+
else element.setAttribute(name, value);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
96
103
|
function sharedRegistry(key, create) {
|
|
97
104
|
const symbol = Symbol.for(key);
|
|
98
105
|
const scope = globalThis;
|
|
@@ -147,9 +154,8 @@ var StateRegions = class _StateRegions {
|
|
|
147
154
|
const below = hold.linked ? stack[index - 1] : void 0;
|
|
148
155
|
if (below) {
|
|
149
156
|
if (region.hidden !== below.written) region.hidden = below.written;
|
|
150
|
-
} else
|
|
151
|
-
|
|
152
|
-
else region.setAttribute("hidden", hold.authored);
|
|
157
|
+
} else {
|
|
158
|
+
setAttributeIfChanged(region, "hidden", hold.authored);
|
|
153
159
|
}
|
|
154
160
|
}
|
|
155
161
|
this.#mark(region, stack);
|
|
@@ -224,9 +230,7 @@ var StateRegions = class _StateRegions {
|
|
|
224
230
|
);
|
|
225
231
|
});
|
|
226
232
|
for (const [name, recorded] of records) {
|
|
227
|
-
|
|
228
|
-
if (recorded === null) region.removeAttribute(name);
|
|
229
|
-
else region.setAttribute(name, recorded);
|
|
233
|
+
setAttributeIfChanged(region, name, recorded);
|
|
230
234
|
}
|
|
231
235
|
}
|
|
232
236
|
#recorded(region, name) {
|