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
|
@@ -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
|
|
|
@@ -174,6 +180,9 @@ var MicrotaskCoalescer = class {
|
|
|
174
180
|
this.#queued = false;
|
|
175
181
|
this.#generation += 1;
|
|
176
182
|
}
|
|
183
|
+
get pending() {
|
|
184
|
+
return this.#queued;
|
|
185
|
+
}
|
|
177
186
|
schedule() {
|
|
178
187
|
if (!this.#active || this.#queued) return;
|
|
179
188
|
this.#queued = true;
|
|
@@ -204,6 +213,9 @@ var MorphRenderWatcher = class {
|
|
|
204
213
|
schedule() {
|
|
205
214
|
this.#pass.schedule();
|
|
206
215
|
}
|
|
216
|
+
get pending() {
|
|
217
|
+
return this.#pass.pending;
|
|
218
|
+
}
|
|
207
219
|
disconnect() {
|
|
208
220
|
this.#listeners.dispose();
|
|
209
221
|
this.#pass.cancel();
|
|
@@ -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
|
|
|
@@ -190,6 +197,9 @@ var MicrotaskCoalescer = class {
|
|
|
190
197
|
this.#queued = false;
|
|
191
198
|
this.#generation += 1;
|
|
192
199
|
}
|
|
200
|
+
get pending() {
|
|
201
|
+
return this.#queued;
|
|
202
|
+
}
|
|
193
203
|
schedule() {
|
|
194
204
|
if (!this.#active || this.#queued) return;
|
|
195
205
|
this.#queued = true;
|
|
@@ -220,6 +230,9 @@ var MorphRenderWatcher = class {
|
|
|
220
230
|
schedule() {
|
|
221
231
|
this.#pass.schedule();
|
|
222
232
|
}
|
|
233
|
+
get pending() {
|
|
234
|
+
return this.#pass.pending;
|
|
235
|
+
}
|
|
223
236
|
disconnect() {
|
|
224
237
|
this.#listeners.dispose();
|
|
225
238
|
this.#pass.cancel();
|
|
@@ -298,14 +311,15 @@ var BulkSelectController = class _BulkSelectController extends Controller {
|
|
|
298
311
|
this.#reportChange(this.#recompute());
|
|
299
312
|
}
|
|
300
313
|
};
|
|
314
|
+
#listeners = new ListenerSet();
|
|
301
315
|
connect() {
|
|
302
316
|
this.#allPagesMode = this.element.dataset.allPages === "true";
|
|
303
317
|
this.#reconcile.observe(this.element);
|
|
304
|
-
this.element
|
|
318
|
+
this.#listeners.add(this.element, "change", this.#onChange);
|
|
305
319
|
this.#recompute();
|
|
306
320
|
}
|
|
307
321
|
disconnect() {
|
|
308
|
-
this.
|
|
322
|
+
this.#listeners.dispose();
|
|
309
323
|
this.#reconcile.disconnect();
|
|
310
324
|
}
|
|
311
325
|
itemTargetConnected() {
|
|
@@ -31,10 +31,17 @@ function logicalArrowKey(key, element) {
|
|
|
31
31
|
if (!isRtl(element)) return key;
|
|
32
32
|
return key === "ArrowRight" ? "ArrowLeft" : "ArrowRight";
|
|
33
33
|
}
|
|
34
|
+
function gridDirectionElement(grid, root) {
|
|
35
|
+
const table = grid.closest("table");
|
|
36
|
+
return table !== null && root.contains(table) ? table : grid;
|
|
37
|
+
}
|
|
34
38
|
function isReservedArrowChord(event, allow = []) {
|
|
35
39
|
if (!event.key.startsWith("Arrow")) return false;
|
|
36
40
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
37
41
|
}
|
|
42
|
+
function hasModifierChord(event) {
|
|
43
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
44
|
+
}
|
|
38
45
|
|
|
39
46
|
var formatters = /* @__PURE__ */ new WeakMap();
|
|
40
47
|
function intlFormatter(factory, locale, options, fallbackLocale) {
|
|
@@ -96,6 +103,30 @@ function parseISOMonthString(monthStr) {
|
|
|
96
103
|
function toISOMonthString(date) {
|
|
97
104
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
|
|
98
105
|
}
|
|
106
|
+
function monthGridDays(year, month, weekStart) {
|
|
107
|
+
const first = new Date(year, month - 1, 1);
|
|
108
|
+
const offset = (first.getDay() - weekStart + 7) % 7;
|
|
109
|
+
const current = new Date(first);
|
|
110
|
+
current.setDate(first.getDate() - offset);
|
|
111
|
+
const days = [];
|
|
112
|
+
for (let i = 0; i < 42; i++) {
|
|
113
|
+
days.push(new Date(current));
|
|
114
|
+
current.setDate(current.getDate() + 1);
|
|
115
|
+
}
|
|
116
|
+
return days;
|
|
117
|
+
}
|
|
118
|
+
function dateInMonthClamped(date, year, month) {
|
|
119
|
+
const target = new Date(year, month - 1, 1);
|
|
120
|
+
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
121
|
+
target.setDate(Math.min(date.getDate(), lastDay));
|
|
122
|
+
return target;
|
|
123
|
+
}
|
|
124
|
+
function shiftMonthClamped(date, delta) {
|
|
125
|
+
return dateInMonthClamped(date, date.getFullYear(), date.getMonth() + 1 + delta);
|
|
126
|
+
}
|
|
127
|
+
function shiftYearClamped(date, delta) {
|
|
128
|
+
return dateInMonthClamped(date, date.getFullYear() + delta, date.getMonth() + 1);
|
|
129
|
+
}
|
|
99
130
|
var MONTH_LABEL_OPTIONS = { month: "long", year: "numeric" };
|
|
100
131
|
function monthLabelFormatter(locale) {
|
|
101
132
|
return intlFormatter(Intl.DateTimeFormat, locale, MONTH_LABEL_OPTIONS, "en");
|
|
@@ -130,6 +161,9 @@ var MicrotaskCoalescer = class {
|
|
|
130
161
|
this.#queued = false;
|
|
131
162
|
this.#generation += 1;
|
|
132
163
|
}
|
|
164
|
+
get pending() {
|
|
165
|
+
return this.#queued;
|
|
166
|
+
}
|
|
133
167
|
schedule() {
|
|
134
168
|
if (!this.#active || this.#queued) return;
|
|
135
169
|
this.#queued = true;
|
|
@@ -171,6 +205,9 @@ var MorphRenderWatcher = class {
|
|
|
171
205
|
schedule() {
|
|
172
206
|
this.#pass.schedule();
|
|
173
207
|
}
|
|
208
|
+
get pending() {
|
|
209
|
+
return this.#pass.pending;
|
|
210
|
+
}
|
|
174
211
|
disconnect() {
|
|
175
212
|
this.#listeners.dispose();
|
|
176
213
|
this.#pass.cancel();
|
|
@@ -253,7 +290,7 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
253
290
|
#monthMoves = 0;
|
|
254
291
|
#paintedDates = /* @__PURE__ */ new WeakMap();
|
|
255
292
|
#opened = false;
|
|
256
|
-
#
|
|
293
|
+
#ownMove = false;
|
|
257
294
|
#repaint = new MorphRenderWatcher(() => {
|
|
258
295
|
this.#repaintKeepingFocus();
|
|
259
296
|
});
|
|
@@ -319,6 +356,9 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
319
356
|
onKeydown(event) {
|
|
320
357
|
if (event.defaultPrevented) return;
|
|
321
358
|
if (isReservedArrowChord(event)) return;
|
|
359
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
360
|
+
if ((event.key === "PageUp" || event.key === "PageDown") && (event.ctrlKey || event.altKey || event.metaKey))
|
|
361
|
+
return;
|
|
322
362
|
const dayElement = event.target?.closest(
|
|
323
363
|
targetSelector(this.identifier, "day")
|
|
324
364
|
);
|
|
@@ -327,7 +367,8 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
327
367
|
if (!date) return;
|
|
328
368
|
let handled = true;
|
|
329
369
|
let nextDate = new Date(date);
|
|
330
|
-
|
|
370
|
+
const directionElement = this.hasGridTarget ? gridDirectionElement(this.gridTarget, this.element) : this.element;
|
|
371
|
+
switch (logicalArrowKey(event.key, directionElement)) {
|
|
331
372
|
case "ArrowLeft":
|
|
332
373
|
nextDate.setDate(nextDate.getDate() - 1);
|
|
333
374
|
break;
|
|
@@ -342,16 +383,16 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
342
383
|
break;
|
|
343
384
|
case "PageUp":
|
|
344
385
|
if (event.shiftKey) {
|
|
345
|
-
nextDate =
|
|
386
|
+
nextDate = shiftYearClamped(date, -1);
|
|
346
387
|
} else {
|
|
347
|
-
nextDate =
|
|
388
|
+
nextDate = shiftMonthClamped(date, -1);
|
|
348
389
|
}
|
|
349
390
|
break;
|
|
350
391
|
case "PageDown":
|
|
351
392
|
if (event.shiftKey) {
|
|
352
|
-
nextDate =
|
|
393
|
+
nextDate = shiftYearClamped(date, 1);
|
|
353
394
|
} else {
|
|
354
|
-
nextDate =
|
|
395
|
+
nextDate = shiftMonthClamped(date, 1);
|
|
355
396
|
}
|
|
356
397
|
break;
|
|
357
398
|
case "Home":
|
|
@@ -400,7 +441,7 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
400
441
|
const locale = resolveLocale(this.element, this.localeValue);
|
|
401
442
|
this.labelTarget.textContent = monthLabelFormatter(locale).format(monthStart);
|
|
402
443
|
}
|
|
403
|
-
const days =
|
|
444
|
+
const days = monthGridDays(year, month, this.#safeWeekStart);
|
|
404
445
|
const dayElements = this.dayTargets;
|
|
405
446
|
const consumerDisabled = /* @__PURE__ */ new Map();
|
|
406
447
|
for (const el of dayElements) {
|
|
@@ -513,8 +554,8 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
513
554
|
return true;
|
|
514
555
|
}
|
|
515
556
|
#mirrorFields(painted, selection, reconciled) {
|
|
516
|
-
const
|
|
517
|
-
this.#
|
|
557
|
+
const ownMove = this.#ownMove;
|
|
558
|
+
this.#ownMove = false;
|
|
518
559
|
const moved = [];
|
|
519
560
|
if (this.hasFieldTarget && this.#writeField(this.fieldTarget, selection) && !reconciled) {
|
|
520
561
|
moved.push([this.fieldTarget, selection, this.#fieldWrites.get(this.fieldTarget) ?? 0]);
|
|
@@ -526,7 +567,7 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
526
567
|
this.#fieldWrites.get(this.monthFieldTarget) ?? 0
|
|
527
568
|
]);
|
|
528
569
|
}
|
|
529
|
-
return
|
|
570
|
+
return ownMove ? moved : [];
|
|
530
571
|
}
|
|
531
572
|
#selectDay(dayElement, reason) {
|
|
532
573
|
if (dayElement.getAttribute("aria-disabled") === "true") return;
|
|
@@ -535,7 +576,7 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
535
576
|
this.selectedValue = dateStr;
|
|
536
577
|
const selected = parseISODateString(dateStr);
|
|
537
578
|
if (selected) this.focusedDate = selected;
|
|
538
|
-
this.#
|
|
579
|
+
this.#ownMove = true;
|
|
539
580
|
const changed = dateStr !== this.#published;
|
|
540
581
|
if (changed) this.#selectionMoves += 1;
|
|
541
582
|
const move = this.#selectionMoves;
|
|
@@ -547,7 +588,7 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
547
588
|
#focusAndNavigateToDate(date) {
|
|
548
589
|
this.focusedDate = date;
|
|
549
590
|
const targetMonthStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
|
|
550
|
-
this.#
|
|
591
|
+
this.#ownMove = true;
|
|
551
592
|
if (targetMonthStr !== this.#monthRequest) {
|
|
552
593
|
this.monthValue = targetMonthStr;
|
|
553
594
|
if (targetMonthStr !== this.#paintedMonth) return;
|
|
@@ -573,7 +614,7 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
573
614
|
#shiftMonth(delta) {
|
|
574
615
|
const monthInfo = parseISOMonthString(this.#monthRequest);
|
|
575
616
|
if (!monthInfo) return;
|
|
576
|
-
this.#
|
|
617
|
+
this.#ownMove = true;
|
|
577
618
|
const nextMonthDate = new Date(monthInfo.year, monthInfo.month - 1 + delta, 1);
|
|
578
619
|
this.monthValue = `${nextMonthDate.getFullYear()}-${String(nextMonthDate.getMonth() + 1).padStart(2, "0")}`;
|
|
579
620
|
if (this.monthValue === this.#paintedMonth) {
|
|
@@ -581,28 +622,6 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
581
622
|
this.#repaintKeepingFocus();
|
|
582
623
|
}
|
|
583
624
|
}
|
|
584
|
-
#calculateShiftedMonthDate(baseDate, delta) {
|
|
585
|
-
const targetDate = new Date(baseDate.getFullYear(), baseDate.getMonth() + delta, 1);
|
|
586
|
-
const lastDayInTarget = new Date(
|
|
587
|
-
targetDate.getFullYear(),
|
|
588
|
-
targetDate.getMonth() + 1,
|
|
589
|
-
0
|
|
590
|
-
).getDate();
|
|
591
|
-
const clampedDay = Math.min(baseDate.getDate(), lastDayInTarget);
|
|
592
|
-
targetDate.setDate(clampedDay);
|
|
593
|
-
return targetDate;
|
|
594
|
-
}
|
|
595
|
-
#calculateShiftedYearDate(baseDate, delta) {
|
|
596
|
-
const targetDate = new Date(baseDate.getFullYear() + delta, baseDate.getMonth(), 1);
|
|
597
|
-
const lastDayInTarget = new Date(
|
|
598
|
-
targetDate.getFullYear(),
|
|
599
|
-
targetDate.getMonth() + 1,
|
|
600
|
-
0
|
|
601
|
-
).getDate();
|
|
602
|
-
const clampedDay = Math.min(baseDate.getDate(), lastDayInTarget);
|
|
603
|
-
targetDate.setDate(clampedDay);
|
|
604
|
-
return targetDate;
|
|
605
|
-
}
|
|
606
625
|
#getStartOfWeekDate(date) {
|
|
607
626
|
const currentDay = date.getDay();
|
|
608
627
|
const shift = (currentDay - this.#safeWeekStart + 7) % 7;
|
|
@@ -640,27 +659,10 @@ var CalendarController = class _CalendarController extends Controller {
|
|
|
640
659
|
if (today.getFullYear() === monthInfo.year && today.getMonth() === monthInfo.month - 1) {
|
|
641
660
|
this.focusedDate = today;
|
|
642
661
|
} else {
|
|
643
|
-
|
|
644
|
-
const lastDayInTarget = new Date(monthInfo.year, monthInfo.month, 0).getDate();
|
|
645
|
-
const clampedDay = Math.min(this.focusedDate.getDate(), lastDayInTarget);
|
|
646
|
-
targetDate.setDate(clampedDay);
|
|
647
|
-
this.focusedDate = targetDate;
|
|
662
|
+
this.focusedDate = dateInMonthClamped(this.focusedDate, monthInfo.year, monthInfo.month);
|
|
648
663
|
}
|
|
649
664
|
}
|
|
650
665
|
}
|
|
651
|
-
#calculateGridDays(year, month) {
|
|
652
|
-
const firstDay = new Date(year, month - 1, 1);
|
|
653
|
-
const dayOfWeek = firstDay.getDay();
|
|
654
|
-
const offset = (dayOfWeek - this.#safeWeekStart + 7) % 7;
|
|
655
|
-
const days = [];
|
|
656
|
-
const current = new Date(firstDay);
|
|
657
|
-
current.setDate(firstDay.getDate() - offset);
|
|
658
|
-
for (let i = 0; i < 42; i++) {
|
|
659
|
-
days.push(new Date(current));
|
|
660
|
-
current.setDate(current.getDate() + 1);
|
|
661
|
-
}
|
|
662
|
-
return days;
|
|
663
|
-
}
|
|
664
666
|
get #safeWeekStart() {
|
|
665
667
|
return this.#numbers.read(
|
|
666
668
|
this,
|