@zeyos/zx 4.3.4 → 5.0.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.
- package/CHANGELOG.md +438 -0
- package/README.md +49 -10
- package/dist/types/components/activity-item/activity-item.d.ts +351 -0
- package/dist/types/components/activity-list/activity-list.d.ts +217 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +33 -3
- package/dist/types/components/avatar/avatar.d.ts +46 -7
- package/dist/types/components/badge/badge.d.ts +21 -1
- package/dist/types/components/button/button.d.ts +23 -0
- package/dist/types/components/calendar/calendar.d.ts +19 -0
- package/dist/types/components/card/card.d.ts +7 -0
- package/dist/types/components/card-view/card-view.d.ts +11 -3
- package/dist/types/components/card-view/record-card.d.ts +7 -1
- package/dist/types/components/chart/chart.d.ts +10 -0
- package/dist/types/components/checklist/checklist.d.ts +9 -0
- package/dist/types/components/code-editor/code-editor.d.ts +149 -0
- package/dist/types/components/code-editor/field-adapter.d.ts +5 -0
- package/dist/types/components/context-menu/context-menu.d.ts +18 -2
- package/dist/types/components/date-picker/date-picker.d.ts +8 -0
- package/dist/types/components/date-picker/time-picker.d.ts +7 -0
- package/dist/types/components/datebox/date-range-box.d.ts +5 -1
- package/dist/types/components/datebox/datebox.d.ts +7 -2
- package/dist/types/components/dialog/dialog.d.ts +75 -6
- package/dist/types/components/dropdown/dropdown.d.ts +2 -2
- package/dist/types/components/entity-ref/entity-ref.d.ts +331 -0
- package/dist/types/components/field/field.d.ts +24 -2
- package/dist/types/components/fieldset/fieldset.d.ts +19 -1
- package/dist/types/components/file-item/file-item.d.ts +262 -0
- package/dist/types/components/file-list/file-list.d.ts +171 -0
- package/dist/types/components/filter/filter.d.ts +91 -36
- package/dist/types/components/filter-panel/filter-panel.d.ts +449 -0
- package/dist/types/components/form/form.d.ts +12 -1
- package/dist/types/components/kanban-view/kanban-card.d.ts +146 -0
- package/dist/types/components/kanban-view/kanban-view.d.ts +170 -4
- package/dist/types/components/launcher/launcher.d.ts +278 -26
- package/dist/types/components/list-toolbar/list-toolbar.d.ts +599 -0
- package/dist/types/components/menu-button/menu-button.d.ts +37 -42
- package/dist/types/components/message/message.d.ts +126 -17
- package/dist/types/components/modal/modal.d.ts +61 -2
- package/dist/types/components/navigation-bar/navigation-bar.d.ts +105 -21
- package/dist/types/components/panel/panel.d.ts +7 -0
- package/dist/types/components/search/search.d.ts +7 -0
- package/dist/types/components/select/color.d.ts +12 -0
- package/dist/types/components/select/glyphs.d.ts +124 -0
- package/dist/types/components/select/select.d.ts +15 -3
- package/dist/types/components/sort-control/sort-control.d.ts +105 -0
- package/dist/types/components/stat-tile/stat-tile.d.ts +288 -0
- package/dist/types/components/tabbox/tabbox.d.ts +16 -0
- package/dist/types/components/table/table.d.ts +190 -1
- package/dist/types/components/table-view/table-view.d.ts +11 -5
- package/dist/types/components/tag-picker/tag-picker.d.ts +21 -4
- package/dist/types/components/timebox/timebox.d.ts +7 -0
- package/dist/types/components/tree/tree.d.ts +13 -0
- package/dist/types/components/value-list/value-list.d.ts +8 -0
- package/dist/types/components/view/record-view.d.ts +96 -5
- package/dist/types/core/breakpoint.d.ts +1 -1
- package/dist/types/core/icons.d.ts +37 -22
- package/dist/types/core/motion.d.ts +59 -0
- package/dist/types/core/overlay-host.d.ts +15 -1
- package/dist/types/index.d.ts +16 -3
- package/dist/types/internal/app-rail.d.ts +10 -0
- package/dist/types/internal/menu-items.d.ts +134 -0
- package/dist/types/zeyos/connect.d.ts +6 -0
- package/dist/types/zeyos/form.d.ts +50 -9
- package/dist/types/zeyos/index.d.ts +1 -1
- package/dist/types/zeyos/query.d.ts +79 -0
- package/dist/types/zeyos/schema.d.ts +24 -1
- package/dist/types/zeyos/table.d.ts +100 -14
- package/dist/types/zeyos/view.d.ts +10 -0
- package/dist/zx-zeyos.esm.js +2206 -489
- package/dist/zx-zeyos.esm.min.js +56 -1
- package/dist/zx.css +3322 -724
- package/dist/zx.esm.js +12244 -5809
- package/dist/zx.esm.min.js +58 -3
- package/dist/zx.global.js +12246 -5811
- package/dist/zx.global.min.js +58 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +1683 -146
- package/docs/llms.md +777 -110
- package/docs/llms.txt +14 -8
- package/package.json +1 -1
- package/src/components/account-menu/account-menu.css +35 -10
- package/src/components/activity-item/activity-item.css +137 -0
- package/src/components/activity-item/activity-item.js +602 -0
- package/src/components/activity-list/activity-list.css +99 -0
- package/src/components/activity-list/activity-list.js +409 -0
- package/src/components/app-icon/app-icon.css +1 -1
- package/src/components/app-rail/app-rail.css +191 -22
- package/src/components/app-sidebar/app-sidebar.css +349 -24
- package/src/components/app-sidebar/app-sidebar.js +86 -11
- package/src/components/aurora/aurora.css +5 -3
- package/src/components/avatar/avatar.css +32 -7
- package/src/components/avatar/avatar.js +72 -8
- package/src/components/badge/badge.css +54 -2
- package/src/components/badge/badge.js +29 -2
- package/src/components/button/button.css +74 -8
- package/src/components/button/button.js +44 -1
- package/src/components/calendar/calendar.css +46 -46
- package/src/components/calendar/calendar.js +33 -3
- package/src/components/card/card.css +2 -2
- package/src/components/card/card.js +12 -1
- package/src/components/card-view/card-view.css +10 -7
- package/src/components/card-view/card-view.js +25 -9
- package/src/components/card-view/record-card.js +7 -3
- package/src/components/chart/chart.css +4 -1
- package/src/components/chart/chart.js +12 -0
- package/src/components/check-button/check-button.css +10 -2
- package/src/components/checklist/checklist.css +9 -2
- package/src/components/checklist/checklist.js +11 -5
- package/src/components/checklist/field-adapter.js +3 -1
- package/src/components/code-editor/code-editor.css +68 -0
- package/src/components/code-editor/code-editor.js +306 -0
- package/src/components/code-editor/field-adapter.js +34 -0
- package/src/components/context-menu/context-menu.css +87 -5
- package/src/components/context-menu/context-menu.js +22 -30
- package/src/components/copy/copy-button.css +6 -0
- package/src/components/copy/copy-input.css +8 -3
- package/src/components/data-filter/data-filter.css +5 -4
- package/src/components/date-picker/date-picker.css +6 -6
- package/src/components/date-picker/date-picker.js +22 -8
- package/src/components/date-picker/date-range-picker.css +3 -3
- package/src/components/date-picker/month-picker.js +3 -3
- package/src/components/date-picker/time-picker.css +1 -1
- package/src/components/date-picker/time-picker.js +20 -8
- package/src/components/datebox/date-range-box.css +79 -2
- package/src/components/datebox/date-range-box.js +13 -2
- package/src/components/datebox/datebox.css +79 -2
- package/src/components/datebox/datebox.js +13 -2
- package/src/components/dialog/dialog.css +26 -0
- package/src/components/dialog/dialog.js +174 -70
- package/src/components/dropdown/dropdown.css +1 -1
- package/src/components/dropdown/dropdown.js +7 -5
- package/src/components/empty-state/empty-state.css +2 -2
- package/src/components/entity-ref/entity-ref.css +182 -0
- package/src/components/entity-ref/entity-ref.js +496 -0
- package/src/components/field/field.css +28 -9
- package/src/components/field/field.js +68 -26
- package/src/components/field-upload/field-upload.css +1 -1
- package/src/components/fieldset/fieldset.css +5 -3
- package/src/components/fieldset/fieldset.js +28 -5
- package/src/components/file-item/file-item.css +88 -0
- package/src/components/file-item/file-item.js +505 -0
- package/src/components/file-list/file-list.css +51 -0
- package/src/components/file-list/file-list.js +320 -0
- package/src/components/filter/filter.css +27 -1
- package/src/components/filter/filter.js +205 -47
- package/src/components/filter-panel/filter-panel.css +104 -0
- package/src/components/filter-panel/filter-panel.js +964 -0
- package/src/components/finder/finder.css +15 -13
- package/src/components/form/form.css +5 -4
- package/src/components/form/form.js +11 -2
- package/src/components/grid/grid.css +1 -1
- package/src/components/groupbox/groupbox.css +1 -1
- package/src/components/kanban-view/kanban-card.js +247 -0
- package/src/components/kanban-view/kanban-view.css +226 -8
- package/src/components/kanban-view/kanban-view.js +255 -12
- package/src/components/launcher/launcher.css +107 -25
- package/src/components/launcher/launcher.js +557 -63
- package/src/components/list-toolbar/list-toolbar.css +194 -0
- package/src/components/list-toolbar/list-toolbar.js +851 -0
- package/src/components/master-panel/master-panel.css +2 -0
- package/src/components/menu-button/menu-button.css +87 -5
- package/src/components/menu-button/menu-button.js +86 -46
- package/src/components/message/message.css +38 -5
- package/src/components/message/message.js +230 -17
- package/src/components/modal/modal.css +15 -0
- package/src/components/modal/modal.js +159 -3
- package/src/components/navigation-bar/navigation-bar.css +95 -11
- package/src/components/navigation-bar/navigation-bar.js +171 -4
- package/src/components/number-field/field-adapter.js +1 -0
- package/src/components/number-field/number-field.css +70 -0
- package/src/components/number-field/number-field.js +2 -0
- package/src/components/pagination/pagination.css +8 -6
- package/src/components/panel/panel.css +1 -1
- package/src/components/panel/panel.js +13 -2
- package/src/components/rating/rating.css +7 -0
- package/src/components/search/search.js +17 -5
- package/src/components/select/color.js +22 -0
- package/src/components/select/field-adapter.js +6 -1
- package/src/components/select/glyphs.js +165 -0
- package/src/components/select/select.css +138 -45
- package/src/components/select/select.js +86 -47
- package/src/components/sheet/sheet.css +11 -8
- package/src/components/slider/slider.css +16 -2
- package/src/components/slider/slider.js +1 -1
- package/src/components/sort-control/sort-control.css +20 -0
- package/src/components/sort-control/sort-control.js +140 -0
- package/src/components/stat-tile/stat-tile.css +208 -0
- package/src/components/stat-tile/stat-tile.js +601 -0
- package/src/components/tabbox/tabbox.css +32 -27
- package/src/components/tabbox/tabbox.js +17 -2
- package/src/components/table/table.css +155 -31
- package/src/components/table/table.js +386 -33
- package/src/components/table-view/table-view.css +8 -2
- package/src/components/table-view/table-view.js +21 -6
- package/src/components/tag-picker/tag-picker.css +86 -6
- package/src/components/tag-picker/tag-picker.js +25 -8
- package/src/components/timebox/timebox.css +22 -2
- package/src/components/timebox/timebox.js +18 -5
- package/src/components/toggle/toggle.css +12 -1
- package/src/components/toolbar/toolbar.js +2 -2
- package/src/components/tooltip/tooltip.css +4 -0
- package/src/components/tooltip/tooltip.js +10 -3
- package/src/components/tree/tree.css +25 -16
- package/src/components/tree/tree.js +31 -0
- package/src/components/value-list/value-list.css +3 -3
- package/src/components/value-list/value-list.js +22 -6
- package/src/components/view/record-view.css +5 -0
- package/src/components/view/record-view.js +100 -7
- package/src/core/breakpoint.js +1 -1
- package/src/core/icons.js +259 -57
- package/src/core/motion.js +147 -0
- package/src/core/overlay-host.js +21 -2
- package/src/index.js +30 -3
- package/src/internal/app-rail.js +18 -1
- package/src/internal/menu-items.js +142 -0
- package/src/zeyos/connect.js +6 -2
- package/src/zeyos/form.js +67 -27
- package/src/zeyos/index.js +1 -1
- package/src/zeyos/query.js +153 -0
- package/src/zeyos/schema.js +144 -27
- package/src/zeyos/table.js +68 -5
- package/src/zeyos/view.js +6 -0
- package/styles/base.css +56 -0
- package/styles/icons.css +11 -1
- package/styles/print.css +192 -0
- package/styles/tokens/dark.css +113 -37
- package/styles/tokens/global.css +121 -27
- package/styles/tokens/semantic.css +100 -31
- package/styles/tokens/themes.css +7 -6
- package/styles/zx.css +11 -1
- package/styles/tokens/density.css +0 -9
package/dist/zx-zeyos.esm.js
CHANGED
|
@@ -12,6 +12,95 @@ function unixSecondsToDate(seconds) {
|
|
|
12
12
|
if (!Number.isFinite(value)) throw new TypeError("Expected finite Unix seconds");
|
|
13
13
|
return new Date(value * 1e3);
|
|
14
14
|
}
|
|
15
|
+
function unixSecondsToCalendarDay(seconds, timeZone) {
|
|
16
|
+
if (seconds == null || seconds === "") return null;
|
|
17
|
+
const value = Number(seconds);
|
|
18
|
+
if (!Number.isFinite(value)) throw new TypeError("Expected finite Unix seconds");
|
|
19
|
+
const { year, month, day } = calendarZone(timeZone).dayOf(value * 1e3);
|
|
20
|
+
return localMidnight(year, month, day);
|
|
21
|
+
}
|
|
22
|
+
function calendarDayToUnixSeconds(date, timeZone) {
|
|
23
|
+
if (date == null) return null;
|
|
24
|
+
if (!(date instanceof Date)) throw new TypeError("Expected a Date");
|
|
25
|
+
if (!Number.isFinite(date.getTime())) throw new RangeError("Invalid Date");
|
|
26
|
+
const midnight = calendarZone(timeZone).midnightOf(date.getFullYear(), date.getMonth(), date.getDate());
|
|
27
|
+
return Math.floor(midnight / 1e3);
|
|
28
|
+
}
|
|
29
|
+
function normalizeTimeZone(timeZone) {
|
|
30
|
+
if (timeZone == null || timeZone === "") return void 0;
|
|
31
|
+
try {
|
|
32
|
+
return new Intl.DateTimeFormat("en-US", { timeZone: String(timeZone) }).resolvedOptions().timeZone;
|
|
33
|
+
} catch {
|
|
34
|
+
throw new RangeError(`Unknown time zone "${String(timeZone)}"`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function calendarZone(timeZone) {
|
|
38
|
+
const zone = normalizeTimeZone(timeZone);
|
|
39
|
+
if (!zone) {
|
|
40
|
+
return {
|
|
41
|
+
timeZone: void 0,
|
|
42
|
+
dayOf: (milliseconds) => {
|
|
43
|
+
const date = new Date(milliseconds);
|
|
44
|
+
return { year: date.getFullYear(), month: date.getMonth(), day: date.getDate() };
|
|
45
|
+
},
|
|
46
|
+
midnightOf: (year, month, day) => localMidnight(year, month, day).getTime()
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
50
|
+
timeZone: zone,
|
|
51
|
+
hourCycle: "h23",
|
|
52
|
+
year: "numeric",
|
|
53
|
+
month: "numeric",
|
|
54
|
+
day: "numeric",
|
|
55
|
+
hour: "numeric",
|
|
56
|
+
minute: "numeric",
|
|
57
|
+
second: "numeric"
|
|
58
|
+
});
|
|
59
|
+
const wallClock = (milliseconds) => {
|
|
60
|
+
const parts = {};
|
|
61
|
+
for (const part of formatter.formatToParts(new Date(milliseconds))) parts[part.type] = Number(part.value);
|
|
62
|
+
return {
|
|
63
|
+
year: parts.year,
|
|
64
|
+
month: parts.month - 1,
|
|
65
|
+
day: parts.day,
|
|
66
|
+
seconds: parts.hour % 24 * 3600 + parts.minute * 60 + parts.second
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const offsetAt = (milliseconds) => {
|
|
70
|
+
const wall = wallClock(milliseconds);
|
|
71
|
+
return utcMidnight(wall.year, wall.month, wall.day) + wall.seconds * 1e3 - Math.floor(milliseconds / 1e3) * 1e3;
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
timeZone: zone,
|
|
75
|
+
dayOf: (milliseconds) => {
|
|
76
|
+
const { year, month, day } = wallClock(milliseconds);
|
|
77
|
+
return { year, month, day };
|
|
78
|
+
},
|
|
79
|
+
midnightOf: (year, month, day) => {
|
|
80
|
+
const target = utcMidnight(year, month, day);
|
|
81
|
+
const first = target - offsetAt(target);
|
|
82
|
+
const second = target - offsetAt(first);
|
|
83
|
+
let best = null;
|
|
84
|
+
for (const candidate of [second, first]) {
|
|
85
|
+
const wall = wallClock(candidate);
|
|
86
|
+
if (wall.year !== year || wall.month !== month || wall.day !== day) continue;
|
|
87
|
+
if (!best || wall.seconds < best.seconds) best = { candidate, seconds: wall.seconds };
|
|
88
|
+
}
|
|
89
|
+
return best ? best.candidate : second;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function localMidnight(year, month, day) {
|
|
94
|
+
const date = new Date(2e3, 0, 1);
|
|
95
|
+
date.setFullYear(year, month, day);
|
|
96
|
+
date.setHours(0, 0, 0, 0);
|
|
97
|
+
return date;
|
|
98
|
+
}
|
|
99
|
+
function utcMidnight(year, month, day) {
|
|
100
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
101
|
+
date.setUTCFullYear(year, month, day);
|
|
102
|
+
return date.getTime();
|
|
103
|
+
}
|
|
15
104
|
function tableSortToQuery(sort) {
|
|
16
105
|
const entries = Array.isArray(sort) ? sort : sort ? [sort] : [];
|
|
17
106
|
return entries.flatMap((entry) => {
|
|
@@ -119,6 +208,37 @@ function mapSortAliases(sort, fields) {
|
|
|
119
208
|
|
|
120
209
|
// src/zeyos/schema.js
|
|
121
210
|
var TYPE_MAP = /* @__PURE__ */ Object.create(null);
|
|
211
|
+
var DATE_ONLY_FIELDS = /* @__PURE__ */ new Set(["date", "duedate", "birthdate", "datefrom", "dateto", "datecancel", "lastbilling"]);
|
|
212
|
+
var INSTANT_FIELDS = /* @__PURE__ */ new Set([
|
|
213
|
+
"appointments.datefrom",
|
|
214
|
+
"appointments.dateto",
|
|
215
|
+
"events.datefrom",
|
|
216
|
+
"events.dateto",
|
|
217
|
+
"comments.date",
|
|
218
|
+
"documentversions.date",
|
|
219
|
+
"records.date"
|
|
220
|
+
]);
|
|
221
|
+
var ENUM_WORDS = Object.freeze({
|
|
222
|
+
AWAITINGACCEPTANCE: "awaiting acceptance",
|
|
223
|
+
AWAITINGAPPROVAL: "awaiting approval",
|
|
224
|
+
BILLINGONLY: "billing only",
|
|
225
|
+
CUSTOMERANDSUPPLIER: "customer and supplier",
|
|
226
|
+
FEEDBACKREQUIRED: "feedback required",
|
|
227
|
+
INEVALUATION: "in evaluation",
|
|
228
|
+
INNEGOTIATION: "in negotiation",
|
|
229
|
+
INREVISION: "in revision",
|
|
230
|
+
NOSTOCK: "no stock",
|
|
231
|
+
NOTSTARTED: "not started",
|
|
232
|
+
PARTLYDELIVERED: "partly delivered",
|
|
233
|
+
PARTLYINVOICED: "partly invoiced",
|
|
234
|
+
PARTLYORDERED: "partly ordered",
|
|
235
|
+
PARTLYPAID: "partly paid",
|
|
236
|
+
PROCUREMENTONLY: "procurement only",
|
|
237
|
+
REMOTECALL: "remote call",
|
|
238
|
+
SERIALSANDCHARGES: "serials and charges"
|
|
239
|
+
});
|
|
240
|
+
var PRIORITY_LABELS = Object.freeze({ 0: "Lowest", 1: "Low", 2: "Medium", 3: "High", 4: "Highest" });
|
|
241
|
+
var ENUM_CONSTANT = /^[A-Z][A-Z\d]*(?:_[A-Z\d]+)*$/;
|
|
122
242
|
var warnedUnknownTypes = /* @__PURE__ */ new Set();
|
|
123
243
|
function registerFieldType(typeOrFormat, strategy) {
|
|
124
244
|
const key = normalizeType(typeOrFormat);
|
|
@@ -180,6 +300,8 @@ function resolveFields(client, resource, opts = {}) {
|
|
|
180
300
|
const requested = Array.isArray(opts.fields) ? opts.fields.map(String) : [...available.keys()];
|
|
181
301
|
const excluded = new Set(Array.isArray(opts.exclude) ? opts.exclude.map(String) : []);
|
|
182
302
|
const labels = opts.labels && typeof opts.labels === "object" ? opts.labels : {};
|
|
303
|
+
const formats = opts.formats && typeof opts.formats === "object" ? opts.formats : {};
|
|
304
|
+
const timeZone = normalizeTimeZone(opts.timeZone);
|
|
183
305
|
const result = [];
|
|
184
306
|
for (const id of requested) {
|
|
185
307
|
if (excluded.has(id) || !available.has(id)) continue;
|
|
@@ -191,6 +313,8 @@ function resolveFields(client, resource, opts = {}) {
|
|
|
191
313
|
if (meta.enum == null) meta.enum = enumValues;
|
|
192
314
|
}
|
|
193
315
|
if (Object.prototype.hasOwnProperty.call(labels, id)) meta.label = String(labels[id]);
|
|
316
|
+
if (Object.prototype.hasOwnProperty.call(formats, id) && formats[id]) meta.format = String(formats[id]);
|
|
317
|
+
if (timeZone) meta.timeZone = timeZone;
|
|
194
318
|
result.push(meta);
|
|
195
319
|
}
|
|
196
320
|
return result;
|
|
@@ -223,7 +347,7 @@ var enumColumn = {
|
|
|
223
347
|
};
|
|
224
348
|
var priorityColumn = {
|
|
225
349
|
field: { type: "zxselect", props: { preset: "priority" } },
|
|
226
|
-
column: (meta) => ({ render: enumRenderer(meta,
|
|
350
|
+
column: (meta) => ({ render: enumRenderer(meta, PRIORITY_LABELS) })
|
|
227
351
|
};
|
|
228
352
|
var percentColumn = {
|
|
229
353
|
field: { type: "float", props: { min: 0, max: 100 } },
|
|
@@ -266,10 +390,13 @@ for (const type of ["email", "tel", "url", "uri"]) {
|
|
|
266
390
|
function dateStrategy(type) {
|
|
267
391
|
return {
|
|
268
392
|
field: { type },
|
|
269
|
-
column: (meta) =>
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
393
|
+
column: (meta) => {
|
|
394
|
+
const format2 = type === "datetime" ? instantFormatter() : calendarDayFormatter(meta.timeZone);
|
|
395
|
+
return {
|
|
396
|
+
render: (row) => format2(rowValue(row, meta)),
|
|
397
|
+
sortValue: (row) => unixSortValue(rowValue(row, meta))
|
|
398
|
+
};
|
|
399
|
+
}
|
|
273
400
|
};
|
|
274
401
|
}
|
|
275
402
|
function strategyFor(meta) {
|
|
@@ -290,9 +417,8 @@ function strategyKey(meta) {
|
|
|
290
417
|
if (meta.enums != null || meta.enum != null) return "enum";
|
|
291
418
|
const raw2 = normalizeType(meta.type);
|
|
292
419
|
if (raw2 === "bigint" || raw2 === "int64") {
|
|
293
|
-
const
|
|
294
|
-
if (
|
|
295
|
-
if (/(?:date|time)$/.test(id)) return "datetime";
|
|
420
|
+
const temporal = timestampKind(meta);
|
|
421
|
+
if (temporal) return temporal;
|
|
296
422
|
}
|
|
297
423
|
if (isLongText(meta, raw2)) return "longtext";
|
|
298
424
|
if (raw2 && TYPE_MAP[raw2]) return raw2;
|
|
@@ -301,6 +427,15 @@ function strategyKey(meta) {
|
|
|
301
427
|
if (/^character varying(?:\(\d+\))?$/.test(raw2)) return "character varying";
|
|
302
428
|
return raw2 || semantic;
|
|
303
429
|
}
|
|
430
|
+
function timestampKind(meta) {
|
|
431
|
+
const id = String(meta.id).toLowerCase();
|
|
432
|
+
const resource = String(meta.resource ?? "").toLowerCase();
|
|
433
|
+
if (DATE_ONLY_FIELDS.has(id) && !INSTANT_FIELDS.has(`${resource}.${id}`)) {
|
|
434
|
+
if (id !== "date" || meta.indexed) return "date";
|
|
435
|
+
}
|
|
436
|
+
if (INSTANT_FIELDS.has(`${resource}.${id}`) || /(?:date|time)$|^lastmodified$/.test(id)) return "datetime";
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
304
439
|
function normalizeMeta(meta) {
|
|
305
440
|
if (!meta || typeof meta !== "object" || Array.isArray(meta)) throw new TypeError("Field metadata must be an object");
|
|
306
441
|
const id = meta.id ?? meta.name ?? meta.field ?? meta.identifier ?? meta.reference;
|
|
@@ -382,26 +517,29 @@ function normalizeEnumOptions(values) {
|
|
|
382
517
|
return Object.fromEntries(values.map((entry, index) => {
|
|
383
518
|
if (Array.isArray(entry)) {
|
|
384
519
|
const [value = index, label = value] = entry;
|
|
385
|
-
return [String(value),
|
|
520
|
+
return [String(value), enumLabel(label)];
|
|
386
521
|
}
|
|
387
522
|
if (entry && typeof entry === "object") {
|
|
388
523
|
const value = entry.value ?? entry.id ?? index;
|
|
389
|
-
return [String(value), String(entry.label
|
|
524
|
+
return [String(value), entry.label != null ? String(entry.label) : enumLabel(entry.name ?? value)];
|
|
390
525
|
}
|
|
391
|
-
return [String(index),
|
|
526
|
+
return [String(index), enumLabel(entry)];
|
|
392
527
|
}));
|
|
393
528
|
}
|
|
394
529
|
if (values && typeof values === "object") {
|
|
395
|
-
return Object.fromEntries(Object.entries(values).map(([value, label]) => [value,
|
|
530
|
+
return Object.fromEntries(Object.entries(values).map(([value, label]) => [value, enumLabel(label)]));
|
|
396
531
|
}
|
|
397
532
|
return {};
|
|
398
533
|
}
|
|
534
|
+
function enumLabel(name2) {
|
|
535
|
+
const text3 = String(name2 ?? "");
|
|
536
|
+
if (!ENUM_CONSTANT.test(text3)) return text3;
|
|
537
|
+
const words = text3.split("_").map((part) => ENUM_WORDS[part] ?? part.toLowerCase()).join(" ");
|
|
538
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
539
|
+
}
|
|
399
540
|
function enumFieldType(meta) {
|
|
400
541
|
return Object.keys(enumOptions(meta)).length <= 5 ? "optionlist" : "select";
|
|
401
542
|
}
|
|
402
|
-
function priorityOptions() {
|
|
403
|
-
return { "0": "LOWEST", "1": "LOW", "2": "MEDIUM", "3": "HIGH", "4": "HIGHEST" };
|
|
404
|
-
}
|
|
405
543
|
function enumRenderer(meta, fallback = {}) {
|
|
406
544
|
const labels = { ...fallback, ...enumOptions(meta) };
|
|
407
545
|
return (row) => {
|
|
@@ -431,17 +569,38 @@ function formatPercent(value) {
|
|
|
431
569
|
const number = finiteNumber(value);
|
|
432
570
|
return number == null ? "" : `${new Intl.NumberFormat().format(number)}%`;
|
|
433
571
|
}
|
|
434
|
-
function
|
|
435
|
-
|
|
572
|
+
function instantFormatter() {
|
|
573
|
+
const formatter = new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" });
|
|
574
|
+
return (value) => {
|
|
575
|
+
const date = timestampDate(value);
|
|
576
|
+
return date ? formatter.format(date) : "";
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
function calendarDayFormatter(timeZone) {
|
|
580
|
+
const zone = calendarZone(
|
|
581
|
+
/** @type {string|undefined} */
|
|
582
|
+
timeZone ?? void 0
|
|
583
|
+
);
|
|
584
|
+
const formatter = new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeZone: "UTC" });
|
|
585
|
+
return (value) => {
|
|
586
|
+
const date = timestampDate(value);
|
|
587
|
+
if (!date) return "";
|
|
588
|
+
const { year, month, day } = value instanceof Date ? { year: date.getFullYear(), month: date.getMonth(), day: date.getDate() } : zone.dayOf(date.getTime());
|
|
589
|
+
const utc = /* @__PURE__ */ new Date(0);
|
|
590
|
+
utc.setUTCFullYear(year, month, day);
|
|
591
|
+
return formatter.format(utc);
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
function timestampDate(value) {
|
|
595
|
+
if (value == null || value === "") return null;
|
|
436
596
|
try {
|
|
437
597
|
const date = value instanceof Date ? value : unixSecondsToDate(
|
|
438
598
|
/** @type {number|string} */
|
|
439
599
|
value
|
|
440
600
|
);
|
|
441
|
-
|
|
442
|
-
return new Intl.DateTimeFormat(void 0, includeTime ? { dateStyle: "medium", timeStyle: "short" } : { dateStyle: "medium" }).format(date);
|
|
601
|
+
return date && Number.isFinite(date.getTime()) ? date : null;
|
|
443
602
|
} catch {
|
|
444
|
-
return
|
|
603
|
+
return null;
|
|
445
604
|
}
|
|
446
605
|
}
|
|
447
606
|
function unixSortValue(value) {
|
|
@@ -589,7 +748,7 @@ function snapshotTarget(element) {
|
|
|
589
748
|
function restoreTarget(element, snapshot3) {
|
|
590
749
|
if (!snapshot3) return;
|
|
591
750
|
for (const attribute of Array.from(element.attributes)) element.removeAttribute(attribute.name);
|
|
592
|
-
for (const [
|
|
751
|
+
for (const [name2, value] of snapshot3.attributes) element.setAttribute(name2, value);
|
|
593
752
|
element.replaceChildren(...snapshot3.children);
|
|
594
753
|
}
|
|
595
754
|
function resolveElement(target) {
|
|
@@ -634,9 +793,9 @@ function applyProperty(element, key, value) {
|
|
|
634
793
|
return;
|
|
635
794
|
}
|
|
636
795
|
if (key === "dataset" && value && typeof value === "object") {
|
|
637
|
-
for (const [
|
|
638
|
-
if (datasetValue == null) delete element.dataset[
|
|
639
|
-
else element.dataset[
|
|
796
|
+
for (const [name2, datasetValue] of Object.entries(value)) {
|
|
797
|
+
if (datasetValue == null) delete element.dataset[name2];
|
|
798
|
+
else element.dataset[name2] = String(datasetValue);
|
|
640
799
|
}
|
|
641
800
|
return;
|
|
642
801
|
}
|
|
@@ -966,12 +1125,12 @@ function mergeOptions(constructor, options) {
|
|
|
966
1125
|
const result = {};
|
|
967
1126
|
let messages = {};
|
|
968
1127
|
let hasMessages = false;
|
|
969
|
-
for (const
|
|
970
|
-
if (!
|
|
971
|
-
Object.assign(result,
|
|
972
|
-
if (
|
|
1128
|
+
for (const defaults4 of chain) {
|
|
1129
|
+
if (!defaults4 || typeof defaults4 !== "object") continue;
|
|
1130
|
+
Object.assign(result, defaults4);
|
|
1131
|
+
if (defaults4.msg && typeof defaults4.msg === "object") {
|
|
973
1132
|
hasMessages = true;
|
|
974
|
-
messages = deepMerge(messages,
|
|
1133
|
+
messages = deepMerge(messages, defaults4.msg);
|
|
975
1134
|
}
|
|
976
1135
|
}
|
|
977
1136
|
Object.assign(result, options && typeof options === "object" ? options : {});
|
|
@@ -1000,6 +1159,7 @@ var Field = class _Field extends Component {
|
|
|
1000
1159
|
/** @type {FieldOptions & {msg: Record<string, string>}} */
|
|
1001
1160
|
static defaults = {
|
|
1002
1161
|
id: null,
|
|
1162
|
+
name: null,
|
|
1003
1163
|
type: "text",
|
|
1004
1164
|
label: "",
|
|
1005
1165
|
description: "",
|
|
@@ -1025,10 +1185,10 @@ var Field = class _Field extends Component {
|
|
|
1025
1185
|
* @returns {typeof Field}
|
|
1026
1186
|
*/
|
|
1027
1187
|
static register(type, adapter) {
|
|
1028
|
-
const
|
|
1029
|
-
if (!
|
|
1188
|
+
const name2 = String(type).trim().toLowerCase();
|
|
1189
|
+
if (!name2) throw new TypeError("Field adapter type must not be empty");
|
|
1030
1190
|
if (typeof adapter !== "function") throw new TypeError("Field adapter must be a function");
|
|
1031
|
-
_Field.#adapters.set(
|
|
1191
|
+
_Field.#adapters.set(name2, adapter);
|
|
1032
1192
|
return this;
|
|
1033
1193
|
}
|
|
1034
1194
|
/**
|
|
@@ -1039,9 +1199,10 @@ var Field = class _Field extends Component {
|
|
|
1039
1199
|
static has(type) {
|
|
1040
1200
|
return _Field.#adapters.has(String(type).trim().toLowerCase());
|
|
1041
1201
|
}
|
|
1042
|
-
// `adapter` (FieldAdapter), `initialValue`,
|
|
1043
|
-
//
|
|
1044
|
-
// constructor (which calls render())
|
|
1202
|
+
// `adapter` (FieldAdapter), `initialValue`, `controlId` (the control's DOM id), and `name` (the
|
|
1203
|
+
// field name, '' when there is none) are assigned in render(); declaring them as class fields
|
|
1204
|
+
// would re-initialize them to undefined after the base constructor (which calls render())
|
|
1205
|
+
// returns — see AGENTS.md.
|
|
1045
1206
|
/** @returns {HTMLElement} */
|
|
1046
1207
|
render() {
|
|
1047
1208
|
const root = (
|
|
@@ -1057,6 +1218,7 @@ var Field = class _Field extends Component {
|
|
|
1057
1218
|
root.dataset.layout = layout;
|
|
1058
1219
|
root.dataset.fieldType = type;
|
|
1059
1220
|
this.controlId = this.options.id ? String(this.options.id) : uid("zx-field");
|
|
1221
|
+
this.name = String(this.options.name ?? this.options.id ?? "");
|
|
1060
1222
|
const labelId = `${this.controlId}-label`;
|
|
1061
1223
|
const descriptionId = `${this.controlId}-description`;
|
|
1062
1224
|
const highlightId = `${this.controlId}-highlight`;
|
|
@@ -1102,9 +1264,12 @@ var Field = class _Field extends Component {
|
|
|
1102
1264
|
}
|
|
1103
1265
|
const control = this.adapter.el;
|
|
1104
1266
|
if (!control.id) control.id = this.controlId;
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1267
|
+
const labelled = this.adapter.labelTarget ?? (isLabelable(control) ? control : unnamedControlWithin(control)) ?? control;
|
|
1268
|
+
this._labelled = labelled;
|
|
1269
|
+
if (labelled !== control && isLabelable(labelled) && !labelled.id) labelled.id = `${this.controlId}-input`;
|
|
1270
|
+
label.htmlFor = isLabelable(labelled) ? labelled.id : control.id;
|
|
1271
|
+
if (!isLabelable(labelled)) labelled.setAttribute("aria-labelledby", labelId);
|
|
1272
|
+
this._baseDescribedBy = labelled.getAttribute("aria-describedby") ?? "";
|
|
1108
1273
|
controlSlot.append(control);
|
|
1109
1274
|
this._descriptionId = String(this.options.description ?? "") ? descriptionId : "";
|
|
1110
1275
|
this._highlightId = highlightId;
|
|
@@ -1179,11 +1344,11 @@ var Field = class _Field extends Component {
|
|
|
1179
1344
|
this._highlight.hidden = !message;
|
|
1180
1345
|
if (normalizedKind === "danger" && message) {
|
|
1181
1346
|
this._highlight.setAttribute("role", "alert");
|
|
1182
|
-
this.
|
|
1347
|
+
this._labelled.setAttribute("aria-invalid", "true");
|
|
1183
1348
|
this.emit("invalid", { message: String(message) });
|
|
1184
1349
|
} else {
|
|
1185
1350
|
this._highlight.removeAttribute("role");
|
|
1186
|
-
this.
|
|
1351
|
+
this._labelled.removeAttribute("aria-invalid");
|
|
1187
1352
|
}
|
|
1188
1353
|
this._syncDescription(Boolean(message));
|
|
1189
1354
|
return this;
|
|
@@ -1197,7 +1362,7 @@ var Field = class _Field extends Component {
|
|
|
1197
1362
|
this._highlight.textContent = "";
|
|
1198
1363
|
this._highlight.hidden = true;
|
|
1199
1364
|
this._highlight.removeAttribute("role");
|
|
1200
|
-
this.
|
|
1365
|
+
this._labelled.removeAttribute("aria-invalid");
|
|
1201
1366
|
this._syncDescription(false);
|
|
1202
1367
|
return this;
|
|
1203
1368
|
}
|
|
@@ -1222,8 +1387,8 @@ var Field = class _Field extends Component {
|
|
|
1222
1387
|
/** @param {boolean} [highlighted=false] @returns {void} */
|
|
1223
1388
|
_syncDescription(highlighted = false) {
|
|
1224
1389
|
const ids = [this._baseDescribedBy, this._descriptionId, highlighted ? this._highlightId : ""].flatMap((value) => value.split(/\s+/)).filter(Boolean);
|
|
1225
|
-
if (ids.length) this.
|
|
1226
|
-
else this.
|
|
1390
|
+
if (ids.length) this._labelled.setAttribute("aria-describedby", [...new Set(ids)].join(" "));
|
|
1391
|
+
else this._labelled.removeAttribute("aria-describedby");
|
|
1227
1392
|
}
|
|
1228
1393
|
/** @returns {void} */
|
|
1229
1394
|
destroy() {
|
|
@@ -1319,25 +1484,35 @@ function errorAdapter(message, id) {
|
|
|
1319
1484
|
function isLabelable(element) {
|
|
1320
1485
|
return ["BUTTON", "INPUT", "METER", "OUTPUT", "PROGRESS", "SELECT", "TEXTAREA"].includes(element.tagName);
|
|
1321
1486
|
}
|
|
1487
|
+
function unnamedControlWithin(root) {
|
|
1488
|
+
for (const candidate of root.querySelectorAll('input:not([type="hidden"]), select, textarea')) {
|
|
1489
|
+
if (candidate.hasAttribute("aria-label") || candidate.hasAttribute("aria-labelledby")) continue;
|
|
1490
|
+
const labels = [.../** @type {HTMLInputElement} */
|
|
1491
|
+
candidate.labels ?? []];
|
|
1492
|
+
if (labels.some((label) => label.textContent?.trim())) continue;
|
|
1493
|
+
return candidate;
|
|
1494
|
+
}
|
|
1495
|
+
return null;
|
|
1496
|
+
}
|
|
1322
1497
|
function rememberAttributes(element, names) {
|
|
1323
|
-
return new Map(names.map((
|
|
1498
|
+
return new Map(names.map((name2) => [name2, element.getAttribute(name2)]));
|
|
1324
1499
|
}
|
|
1325
1500
|
function restoreAttributes(element, attributes) {
|
|
1326
|
-
for (const [
|
|
1327
|
-
if (value === null) element.removeAttribute(
|
|
1328
|
-
else element.setAttribute(
|
|
1501
|
+
for (const [name2, value] of attributes) {
|
|
1502
|
+
if (value === null) element.removeAttribute(name2);
|
|
1503
|
+
else element.setAttribute(name2, value);
|
|
1329
1504
|
}
|
|
1330
1505
|
}
|
|
1331
|
-
function controlProps(options, base) {
|
|
1506
|
+
function controlProps(field, options, base) {
|
|
1332
1507
|
const props = { ...options.props ?? {} };
|
|
1333
1508
|
for (const key of Object.keys(props)) {
|
|
1334
1509
|
if (/^on[a-z]/i.test(key) || key === "content") delete props[key];
|
|
1335
1510
|
}
|
|
1336
|
-
return { ...props, ...base };
|
|
1511
|
+
return { name: field.name || void 0, ...props, ...base };
|
|
1337
1512
|
}
|
|
1338
1513
|
function textAdapter(tag, type) {
|
|
1339
|
-
return (
|
|
1340
|
-
const el = h(tag, controlProps(options, {
|
|
1514
|
+
return (field, options) => {
|
|
1515
|
+
const el = h(tag, controlProps(field, options, {
|
|
1341
1516
|
type: tag === "input" ? type : void 0,
|
|
1342
1517
|
placeholder: options.placeholder,
|
|
1343
1518
|
required: options.required,
|
|
@@ -1362,7 +1537,7 @@ function elementValueAdapter(el) {
|
|
|
1362
1537
|
function numericAdapter(kind) {
|
|
1363
1538
|
return (field, options) => {
|
|
1364
1539
|
const coerce = kind === "int" ? coerceInteger : coerceFloat;
|
|
1365
|
-
const input = h("input", controlProps(options, {
|
|
1540
|
+
const input = h("input", controlProps(field, options, {
|
|
1366
1541
|
type: "text",
|
|
1367
1542
|
inputMode: kind === "int" ? "numeric" : "decimal",
|
|
1368
1543
|
placeholder: options.placeholder,
|
|
@@ -1384,8 +1559,8 @@ function numericAdapter(kind) {
|
|
|
1384
1559
|
};
|
|
1385
1560
|
};
|
|
1386
1561
|
}
|
|
1387
|
-
var checkboxAdapter = (
|
|
1388
|
-
const input = h("input", controlProps(options, {
|
|
1562
|
+
var checkboxAdapter = (field, options) => {
|
|
1563
|
+
const input = h("input", controlProps(field, options, {
|
|
1389
1564
|
type: "checkbox",
|
|
1390
1565
|
required: options.required,
|
|
1391
1566
|
disabled: options.disabled
|
|
@@ -1402,8 +1577,8 @@ var checkboxAdapter = (_field, options) => {
|
|
|
1402
1577
|
}
|
|
1403
1578
|
};
|
|
1404
1579
|
};
|
|
1405
|
-
var selectAdapter = (
|
|
1406
|
-
const select = h("select", controlProps(options, {
|
|
1580
|
+
var selectAdapter = (field, options) => {
|
|
1581
|
+
const select = h("select", controlProps(field, options, {
|
|
1407
1582
|
required: options.required,
|
|
1408
1583
|
disabled: options.disabled
|
|
1409
1584
|
}));
|
|
@@ -1412,16 +1587,16 @@ var selectAdapter = (_field, options) => {
|
|
|
1412
1587
|
}
|
|
1413
1588
|
return elementValueAdapter(select);
|
|
1414
1589
|
};
|
|
1415
|
-
var optionListAdapter = (
|
|
1590
|
+
var optionListAdapter = (field, options) => {
|
|
1416
1591
|
const root = h("div", {
|
|
1417
1592
|
class: "zx-field__option-list",
|
|
1418
1593
|
role: "radiogroup"
|
|
1419
1594
|
});
|
|
1420
|
-
const
|
|
1595
|
+
const name2 = field.controlId;
|
|
1421
1596
|
const radios = normalizeOptions(options.options).map(([value, label], index) => {
|
|
1422
1597
|
const input = h("input", {
|
|
1423
1598
|
type: "radio",
|
|
1424
|
-
name,
|
|
1599
|
+
name: name2,
|
|
1425
1600
|
value,
|
|
1426
1601
|
required: Boolean(options.required) && index === 0,
|
|
1427
1602
|
disabled: options.disabled
|
|
@@ -1442,8 +1617,8 @@ var optionListAdapter = (_field, options) => {
|
|
|
1442
1617
|
}
|
|
1443
1618
|
};
|
|
1444
1619
|
};
|
|
1445
|
-
var htmlAdapter = (
|
|
1446
|
-
const el = h("div", controlProps(options, { class: "zx-field__static" }));
|
|
1620
|
+
var htmlAdapter = (field, options) => {
|
|
1621
|
+
const el = h("div", controlProps(field, options, { class: "zx-field__static", name: void 0 }));
|
|
1447
1622
|
let adopted = null;
|
|
1448
1623
|
const set = (value) => {
|
|
1449
1624
|
restoreAdopted(adopted);
|
|
@@ -1528,6 +1703,7 @@ var Checklist = class extends Component {
|
|
|
1528
1703
|
search: true,
|
|
1529
1704
|
height: 280,
|
|
1530
1705
|
defaultChecked: false,
|
|
1706
|
+
hideLabel: false,
|
|
1531
1707
|
load: null
|
|
1532
1708
|
};
|
|
1533
1709
|
/** @returns {HTMLElement} */
|
|
@@ -1548,14 +1724,15 @@ var Checklist = class extends Component {
|
|
|
1548
1724
|
);
|
|
1549
1725
|
this.el = root;
|
|
1550
1726
|
if (!this._createdRoot) this._originalChildren = Array.from(root.childNodes);
|
|
1551
|
-
for (const
|
|
1552
|
-
this._originalAttributes.set(
|
|
1727
|
+
for (const name2 of ["role", "aria-label", "aria-labelledby", "data-state"]) {
|
|
1728
|
+
this._originalAttributes.set(name2, root.getAttribute(name2));
|
|
1553
1729
|
}
|
|
1730
|
+
const labelText = this._message("checklist.label", "Checklist");
|
|
1554
1731
|
const labelId = uid("zx-checklist-label");
|
|
1555
|
-
const title = h("div", {
|
|
1732
|
+
const title = this.options.hideLabel ? null : h("div", {
|
|
1556
1733
|
class: "zx-checklist__label",
|
|
1557
1734
|
id: labelId
|
|
1558
|
-
},
|
|
1735
|
+
}, labelText);
|
|
1559
1736
|
const search = h("input", {
|
|
1560
1737
|
ref: "search",
|
|
1561
1738
|
class: "zx-checklist__search",
|
|
@@ -1570,9 +1747,10 @@ var Checklist = class extends Component {
|
|
|
1570
1747
|
class: "zx-checklist__list"
|
|
1571
1748
|
});
|
|
1572
1749
|
list.style.maxBlockSize = `${Math.max(0, Number(this.options.height) || 0)}px`;
|
|
1573
|
-
root.replaceChildren(title, search, list);
|
|
1750
|
+
root.replaceChildren(...[title, search, list].filter(Boolean));
|
|
1574
1751
|
root.setAttribute("role", "group");
|
|
1575
|
-
root.setAttribute("aria-labelledby", labelId);
|
|
1752
|
+
if (title) root.setAttribute("aria-labelledby", labelId);
|
|
1753
|
+
else root.setAttribute("aria-label", labelText);
|
|
1576
1754
|
this.listen(search, "input", () => this.search(
|
|
1577
1755
|
/** @type {HTMLInputElement} */
|
|
1578
1756
|
search.value
|
|
@@ -1683,9 +1861,9 @@ var Checklist = class extends Component {
|
|
|
1683
1861
|
);
|
|
1684
1862
|
if (!this._createdRoot && root) {
|
|
1685
1863
|
root.replaceChildren(...this._originalChildren);
|
|
1686
|
-
for (const [
|
|
1687
|
-
if (value === null) root.removeAttribute(
|
|
1688
|
-
else root.setAttribute(
|
|
1864
|
+
for (const [name2, value] of this._originalAttributes) {
|
|
1865
|
+
if (value === null) root.removeAttribute(name2);
|
|
1866
|
+
else root.setAttribute(name2, value);
|
|
1689
1867
|
}
|
|
1690
1868
|
}
|
|
1691
1869
|
super.destroy();
|
|
@@ -1762,7 +1940,7 @@ function setsEqual(left, right) {
|
|
|
1762
1940
|
// src/components/checklist/field-adapter.js
|
|
1763
1941
|
function registerChecklistFieldAdapter() {
|
|
1764
1942
|
Field.register("checklist", (field, options) => {
|
|
1765
|
-
const checklist = field.own(new Checklist(null, { ...options.props ?? {} }));
|
|
1943
|
+
const checklist = field.own(new Checklist(null, { hideLabel: true, ...options.props ?? {} }));
|
|
1766
1944
|
let disabled = false;
|
|
1767
1945
|
let setting = false;
|
|
1768
1946
|
const syncDisabled = () => {
|
|
@@ -1800,6 +1978,283 @@ function registerChecklistFieldAdapter() {
|
|
|
1800
1978
|
});
|
|
1801
1979
|
}
|
|
1802
1980
|
|
|
1981
|
+
// src/components/code-editor/code-editor.js
|
|
1982
|
+
var MODIFIER_KEYS = /* @__PURE__ */ new Set(["Shift", "Control", "Alt", "Meta", "AltGraph", "CapsLock", "Fn", "OS"]);
|
|
1983
|
+
var CodeEditor = class extends Component {
|
|
1984
|
+
static cssName = "code-editor";
|
|
1985
|
+
/** @type {CodeEditorOptions} */
|
|
1986
|
+
static defaults = {
|
|
1987
|
+
value: "",
|
|
1988
|
+
name: "",
|
|
1989
|
+
language: "text",
|
|
1990
|
+
label: "Code editor",
|
|
1991
|
+
placeholder: "",
|
|
1992
|
+
rows: 12,
|
|
1993
|
+
indent: " ",
|
|
1994
|
+
wrap: "off",
|
|
1995
|
+
spellcheck: false,
|
|
1996
|
+
readOnly: false,
|
|
1997
|
+
disabled: false,
|
|
1998
|
+
status: true
|
|
1999
|
+
};
|
|
2000
|
+
/** @returns {HTMLElement} */
|
|
2001
|
+
render() {
|
|
2002
|
+
this._createdRoot = this.el === null;
|
|
2003
|
+
const root = (
|
|
2004
|
+
/** @type {HTMLElement} */
|
|
2005
|
+
this.el ?? h("div")
|
|
2006
|
+
);
|
|
2007
|
+
this.el = root;
|
|
2008
|
+
this._initialChildren = this._createdRoot ? [] : [...root.childNodes];
|
|
2009
|
+
this._initialAttributes = new Map(["data-language", "data-readonly", "data-disabled"].map((name2) => [name2, root.getAttribute(name2)]));
|
|
2010
|
+
this._language = normalizeLanguage(this.options.language);
|
|
2011
|
+
this._languageLabel = h("span", { class: "zx-code-editor__language" }, this._language);
|
|
2012
|
+
this._position = h("span", {
|
|
2013
|
+
class: "zx-code-editor__position",
|
|
2014
|
+
role: "status",
|
|
2015
|
+
ariaLive: "polite"
|
|
2016
|
+
});
|
|
2017
|
+
this._header = h(
|
|
2018
|
+
"div",
|
|
2019
|
+
{ class: "zx-code-editor__header" },
|
|
2020
|
+
this._languageLabel,
|
|
2021
|
+
this.options.status ? this._position : null
|
|
2022
|
+
);
|
|
2023
|
+
this._input = /** @type {HTMLTextAreaElement} */
|
|
2024
|
+
h("textarea", {
|
|
2025
|
+
class: "zx-code-editor__input",
|
|
2026
|
+
name: this.options.name ? String(this.options.name) : void 0,
|
|
2027
|
+
ariaLabel: String(this.options.label ?? "Code editor"),
|
|
2028
|
+
placeholder: String(this.options.placeholder ?? ""),
|
|
2029
|
+
rows: normalizeRows(this.options.rows),
|
|
2030
|
+
wrap: normalizeWrap(this.options.wrap),
|
|
2031
|
+
spellcheck: Boolean(this.options.spellcheck),
|
|
2032
|
+
readOnly: Boolean(this.options.readOnly),
|
|
2033
|
+
disabled: Boolean(this.options.disabled),
|
|
2034
|
+
autocomplete: "off",
|
|
2035
|
+
autocapitalize: "off"
|
|
2036
|
+
});
|
|
2037
|
+
this._input.value = String(this.options.value ?? "");
|
|
2038
|
+
root.dataset.language = this._language;
|
|
2039
|
+
root.dataset.readonly = String(Boolean(this.options.readOnly));
|
|
2040
|
+
root.dataset.disabled = String(Boolean(this.options.disabled));
|
|
2041
|
+
root.replaceChildren(this._header, this._input);
|
|
2042
|
+
this._tabReleased = false;
|
|
2043
|
+
this.listen(this._input, "keydown", (event) => this._handleKeydown(event));
|
|
2044
|
+
this.listen(this._input, "blur", () => {
|
|
2045
|
+
this._tabReleased = false;
|
|
2046
|
+
});
|
|
2047
|
+
this.listen(this._input, "input", () => {
|
|
2048
|
+
this._updatePosition();
|
|
2049
|
+
this.emit("input", { value: this.getValue() });
|
|
2050
|
+
});
|
|
2051
|
+
this.listen(this._input, "change", () => this.emit("change", { value: this.getValue() }));
|
|
2052
|
+
for (const type of ["click", "keyup", "select", "focus"]) {
|
|
2053
|
+
this.listen(this._input, type, () => this._updatePosition());
|
|
2054
|
+
}
|
|
2055
|
+
this._updatePosition();
|
|
2056
|
+
return root;
|
|
2057
|
+
}
|
|
2058
|
+
/** @returns {string} */
|
|
2059
|
+
getValue() {
|
|
2060
|
+
return this._input.value;
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Replaces the editor text.
|
|
2064
|
+
* @param {unknown} value New value.
|
|
2065
|
+
* @param {{silent?:boolean}} [options={}] Suppress the `change` event.
|
|
2066
|
+
* @returns {this}
|
|
2067
|
+
*/
|
|
2068
|
+
setValue(value, { silent = false } = {}) {
|
|
2069
|
+
const next = String(value ?? "");
|
|
2070
|
+
if (this._input.value === next) return this;
|
|
2071
|
+
this._input.value = next;
|
|
2072
|
+
this._updatePosition();
|
|
2073
|
+
if (!silent) this.emit("change", { value: next });
|
|
2074
|
+
return this;
|
|
2075
|
+
}
|
|
2076
|
+
/** @param {unknown} language New language identifier. @returns {this} */
|
|
2077
|
+
setLanguage(language2) {
|
|
2078
|
+
this._language = normalizeLanguage(language2);
|
|
2079
|
+
this.el.dataset.language = this._language;
|
|
2080
|
+
this._languageLabel.textContent = this._language;
|
|
2081
|
+
return this;
|
|
2082
|
+
}
|
|
2083
|
+
/** @returns {this} */
|
|
2084
|
+
focus() {
|
|
2085
|
+
this._input.focus();
|
|
2086
|
+
return this;
|
|
2087
|
+
}
|
|
2088
|
+
/** @returns {this} */
|
|
2089
|
+
enable() {
|
|
2090
|
+
this._input.disabled = false;
|
|
2091
|
+
this.el.dataset.disabled = "false";
|
|
2092
|
+
return this;
|
|
2093
|
+
}
|
|
2094
|
+
/** @returns {this} */
|
|
2095
|
+
disable() {
|
|
2096
|
+
this._input.disabled = true;
|
|
2097
|
+
this.el.dataset.disabled = "true";
|
|
2098
|
+
return this;
|
|
2099
|
+
}
|
|
2100
|
+
/** @param {boolean} value Read-only state. @returns {this} */
|
|
2101
|
+
setReadOnly(value) {
|
|
2102
|
+
this._input.readOnly = Boolean(value);
|
|
2103
|
+
this.el.dataset.readonly = String(Boolean(value));
|
|
2104
|
+
return this;
|
|
2105
|
+
}
|
|
2106
|
+
/** @param {KeyboardEvent} event @returns {void} */
|
|
2107
|
+
_handleKeydown(event) {
|
|
2108
|
+
if (event.isComposing || MODIFIER_KEYS.has(event.key)) return;
|
|
2109
|
+
if (event.key === "Escape") {
|
|
2110
|
+
this._tabReleased = true;
|
|
2111
|
+
return;
|
|
2112
|
+
}
|
|
2113
|
+
const released = this._tabReleased;
|
|
2114
|
+
this._tabReleased = false;
|
|
2115
|
+
if (released || event.key !== "Tab" || event.altKey || event.ctrlKey || event.metaKey || this._input.readOnly || this._input.disabled) return;
|
|
2116
|
+
const indent = String(this.options.indent ?? " ");
|
|
2117
|
+
if (!indent) return;
|
|
2118
|
+
event.preventDefault();
|
|
2119
|
+
const result = indentSelection(
|
|
2120
|
+
this._input.value,
|
|
2121
|
+
this._input.selectionStart ?? 0,
|
|
2122
|
+
this._input.selectionEnd ?? 0,
|
|
2123
|
+
indent,
|
|
2124
|
+
event.shiftKey
|
|
2125
|
+
);
|
|
2126
|
+
if (result.value === this._input.value) return;
|
|
2127
|
+
this._input.value = result.value;
|
|
2128
|
+
this._input.setSelectionRange(result.start, result.end);
|
|
2129
|
+
this._updatePosition();
|
|
2130
|
+
this.emit("input", { value: this.getValue() });
|
|
2131
|
+
}
|
|
2132
|
+
/** @returns {void} */
|
|
2133
|
+
_updatePosition() {
|
|
2134
|
+
if (!this.options.status) return;
|
|
2135
|
+
const position2 = editorPosition(
|
|
2136
|
+
this._input.value,
|
|
2137
|
+
this._input.selectionStart ?? 0,
|
|
2138
|
+
this._input.selectionEnd ?? 0
|
|
2139
|
+
);
|
|
2140
|
+
this._position.textContent = position2.lines > 1 ? `Ln ${position2.line}, Col ${position2.column} \xB7 ${position2.lines} lines selected` : `Ln ${position2.line}, Col ${position2.column}`;
|
|
2141
|
+
}
|
|
2142
|
+
/** @returns {void} */
|
|
2143
|
+
destroy() {
|
|
2144
|
+
if (!this._createdRoot) {
|
|
2145
|
+
this.el.replaceChildren(...this._initialChildren);
|
|
2146
|
+
for (const [name2, value] of this._initialAttributes) {
|
|
2147
|
+
if (value === null) this.el.removeAttribute(name2);
|
|
2148
|
+
else this.el.setAttribute(name2, value);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
super.destroy();
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
function indentSelection(value, start, end, indent = " ", outdent = false) {
|
|
2155
|
+
const source = String(value ?? "");
|
|
2156
|
+
const unit = String(indent ?? "");
|
|
2157
|
+
const from = clampIndex(start, source.length);
|
|
2158
|
+
const to = clampIndex(end, source.length);
|
|
2159
|
+
if (!unit) return { value: source, start: from, end: to };
|
|
2160
|
+
if (from === to && !outdent) {
|
|
2161
|
+
return {
|
|
2162
|
+
value: source.slice(0, from) + unit + source.slice(to),
|
|
2163
|
+
start: from + unit.length,
|
|
2164
|
+
end: from + unit.length
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
const lineStart = source.lastIndexOf("\n", Math.max(0, from - 1)) + 1;
|
|
2168
|
+
let lineEnd = source.indexOf("\n", to);
|
|
2169
|
+
if (lineEnd < 0) lineEnd = source.length;
|
|
2170
|
+
const block = source.slice(lineStart, lineEnd);
|
|
2171
|
+
const lines = block.split("\n");
|
|
2172
|
+
let removedFirst = 0;
|
|
2173
|
+
let delta = 0;
|
|
2174
|
+
const transformed = lines.map((line, index) => {
|
|
2175
|
+
if (!outdent) {
|
|
2176
|
+
delta += unit.length;
|
|
2177
|
+
return unit + line;
|
|
2178
|
+
}
|
|
2179
|
+
const removed = removableIndent(line, unit);
|
|
2180
|
+
if (index === 0) removedFirst = removed;
|
|
2181
|
+
delta -= removed;
|
|
2182
|
+
return line.slice(removed);
|
|
2183
|
+
}).join("\n");
|
|
2184
|
+
const nextStart = outdent ? Math.max(lineStart, from - Math.min(removedFirst, from - lineStart)) : from + unit.length;
|
|
2185
|
+
return {
|
|
2186
|
+
value: source.slice(0, lineStart) + transformed + source.slice(lineEnd),
|
|
2187
|
+
start: nextStart,
|
|
2188
|
+
end: Math.max(nextStart, to + delta)
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
function editorPosition(value, start, end = start) {
|
|
2192
|
+
const source = String(value ?? "");
|
|
2193
|
+
const from = clampIndex(start, source.length);
|
|
2194
|
+
const to = clampIndex(end, source.length);
|
|
2195
|
+
const before = source.slice(0, from);
|
|
2196
|
+
return {
|
|
2197
|
+
line: before.split("\n").length,
|
|
2198
|
+
column: from - before.lastIndexOf("\n"),
|
|
2199
|
+
lines: source.slice(from, to).split("\n").length
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
function removableIndent(line, indent) {
|
|
2203
|
+
if (line.startsWith(indent)) return indent.length;
|
|
2204
|
+
if (indent === " ") return line.startsWith(" ") ? 1 : Math.min(/^ +/.exec(line)?.[0].length ?? 0, 2);
|
|
2205
|
+
return Math.min(/^\s+/.exec(line)?.[0].length ?? 0, indent.length);
|
|
2206
|
+
}
|
|
2207
|
+
function normalizeLanguage(value) {
|
|
2208
|
+
const language2 = String(value ?? "text").trim().toLowerCase();
|
|
2209
|
+
return /^[a-z0-9][a-z0-9+_.-]*$/.test(language2) ? language2 : "text";
|
|
2210
|
+
}
|
|
2211
|
+
function normalizeRows(value) {
|
|
2212
|
+
const rows = Number(value);
|
|
2213
|
+
return Number.isFinite(rows) ? Math.max(2, Math.min(100, Math.round(rows))) : 12;
|
|
2214
|
+
}
|
|
2215
|
+
function normalizeWrap(value) {
|
|
2216
|
+
return ["off", "soft", "hard"].includes(String(value)) ? (
|
|
2217
|
+
/** @type {'off'|'soft'|'hard'} */
|
|
2218
|
+
value
|
|
2219
|
+
) : "off";
|
|
2220
|
+
}
|
|
2221
|
+
function clampIndex(value, length) {
|
|
2222
|
+
const number = Number(value);
|
|
2223
|
+
return Math.max(0, Math.min(length, Number.isFinite(number) ? Math.round(number) : 0));
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
// src/components/code-editor/field-adapter.js
|
|
2227
|
+
function registerCodeEditorFieldAdapter() {
|
|
2228
|
+
Field.register("code", (field, options) => {
|
|
2229
|
+
const editor = field.own(new CodeEditor(null, {
|
|
2230
|
+
label: options.label ? String(options.label) : "Code editor",
|
|
2231
|
+
placeholder: options.placeholder,
|
|
2232
|
+
readOnly: Boolean(options.props?.readOnly),
|
|
2233
|
+
disabled: Boolean(options.disabled),
|
|
2234
|
+
...options.props ?? {},
|
|
2235
|
+
value: options.value
|
|
2236
|
+
}));
|
|
2237
|
+
let setting = false;
|
|
2238
|
+
editor.on("input", (event) => {
|
|
2239
|
+
if (!setting) field.emit("change", { value: event.detail.value });
|
|
2240
|
+
});
|
|
2241
|
+
return {
|
|
2242
|
+
el: editor.el,
|
|
2243
|
+
get: () => editor.getValue(),
|
|
2244
|
+
set: (value) => {
|
|
2245
|
+
setting = true;
|
|
2246
|
+
try {
|
|
2247
|
+
editor.setValue(value, { silent: true });
|
|
2248
|
+
} finally {
|
|
2249
|
+
setting = false;
|
|
2250
|
+
}
|
|
2251
|
+
},
|
|
2252
|
+
focus: () => editor.focus(),
|
|
2253
|
+
setDisabled: (value) => value ? editor.disable() : editor.enable()
|
|
2254
|
+
};
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
|
|
1803
2258
|
// src/core/date.js
|
|
1804
2259
|
var MONTHS = [
|
|
1805
2260
|
"January",
|
|
@@ -2025,19 +2480,19 @@ function parseIconSpec(spec) {
|
|
|
2025
2480
|
const separator = text3.indexOf(":");
|
|
2026
2481
|
if (separator > 0) {
|
|
2027
2482
|
const prefix = text3.slice(0, separator).toLowerCase();
|
|
2028
|
-
const
|
|
2483
|
+
const name2 = text3.slice(separator + 1);
|
|
2029
2484
|
if (prefix === "builtin" || prefix === "zx") {
|
|
2030
|
-
return { provider: "builtin", name, style: null, classes: null };
|
|
2485
|
+
return { provider: "builtin", name: name2, style: null, classes: null };
|
|
2031
2486
|
}
|
|
2032
2487
|
if (Object.hasOwn(stylePrefixes, prefix)) {
|
|
2033
|
-
return { provider: "fa", name, style: stylePrefixes[prefix], classes: null };
|
|
2488
|
+
return { provider: "fa", name: name2, style: stylePrefixes[prefix], classes: null };
|
|
2034
2489
|
}
|
|
2035
2490
|
}
|
|
2036
2491
|
return { provider: null, name: text3, style: null, classes: null };
|
|
2037
2492
|
}
|
|
2038
|
-
function faIconClasses(
|
|
2493
|
+
function faIconClasses(name2, options = {}) {
|
|
2039
2494
|
const { style = "solid", family = "classic", fixedWidth = false, translate: translate2 = true } = options;
|
|
2040
|
-
const bare = String(
|
|
2495
|
+
const bare = String(name2).replace(/^fa-/, "");
|
|
2041
2496
|
const resolved = translate2 ? faNames[bare] ?? bare : bare;
|
|
2042
2497
|
const classes = [];
|
|
2043
2498
|
const familyClass = faFamilies[family];
|
|
@@ -2084,42 +2539,61 @@ function loadFontAwesomeKit(kit) {
|
|
|
2084
2539
|
|
|
2085
2540
|
// src/core/icons.js
|
|
2086
2541
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
2542
|
+
var VIEW_BOX = "0 0 24 24";
|
|
2543
|
+
var STROKE_WIDTH = 1.75;
|
|
2544
|
+
var MIN_STROKE_PX = 1;
|
|
2545
|
+
var outline = (path) => [VIEW_BOX, path, "stroke"];
|
|
2087
2546
|
var icons = Object.freeze({
|
|
2088
|
-
|
|
2089
|
-
"
|
|
2090
|
-
|
|
2091
|
-
"
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2547
|
+
// <lucide-glyphs>
|
|
2548
|
+
"arrow-up-wide-short": outline("M3 8l4-4 4 4M7 4v16M11 12h10M11 16h7M11 20h4"),
|
|
2549
|
+
// arrow-up-wide-narrow
|
|
2550
|
+
"arrow-down-wide-short": outline("M3 16l4 4 4-4M7 20V4M11 4h10M11 8h7M11 12h4"),
|
|
2551
|
+
// arrow-down-wide-narrow
|
|
2552
|
+
"chevron-down": outline("M6 9l6 6 6-6"),
|
|
2553
|
+
"chevron-up": outline("M18 15l-6-6-6 6"),
|
|
2554
|
+
"chevron-left": outline("M15 18l-6-6 6-6"),
|
|
2555
|
+
"chevron-right": outline("M9 18l6-6-6-6"),
|
|
2556
|
+
check: outline("M20 6 9 17l-5-5"),
|
|
2557
|
+
x: outline("M18 6 6 18M6 6l12 12"),
|
|
2558
|
+
plus: outline("M5 12h14M12 5v14"),
|
|
2559
|
+
minus: outline("M5 12h14"),
|
|
2560
|
+
search: outline("M21 21l-4.34-4.34M3 11a8 8 0 1 0 16 0a8 8 0 1 0-16 0z"),
|
|
2561
|
+
calendar: outline("M8 2v3M16 2v3M5 3h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-14a2 2 0 0 1-2-2v-14a2 2 0 0 1 2-2zM3 9h18"),
|
|
2562
|
+
clock: outline("M2 12a10 10 0 1 0 20 0a10 10 0 1 0-20 0zM12 6v6l4 2"),
|
|
2563
|
+
trash: outline("M10 11v6M14 11v6M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"),
|
|
2564
|
+
gear: outline("M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915M9 12a3 3 0 1 0 6 0a3 3 0 1 0-6 0z"),
|
|
2565
|
+
// settings
|
|
2566
|
+
eye: outline("M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0M9 12a3 3 0 1 0 6 0a3 3 0 1 0-6 0z"),
|
|
2567
|
+
lock: outline("M5 11h14a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-14a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2zM7 11V7a5 5 0 0 1 10 0v4"),
|
|
2568
|
+
reload: outline("M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8M21 3v5h-5"),
|
|
2569
|
+
// rotate-cw
|
|
2570
|
+
list: outline("M3 5h.01M3 12h.01M3 19h.01M8 5h13M8 12h13M8 19h13"),
|
|
2571
|
+
filter: outline("M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z"),
|
|
2572
|
+
// funnel
|
|
2573
|
+
dots: outline("M11 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0zM18 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0zM4 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0z"),
|
|
2574
|
+
// ellipsis
|
|
2575
|
+
info: outline("M2 12a10 10 0 1 0 20 0a10 10 0 1 0-20 0zM12 16v-4M12 8h.01"),
|
|
2576
|
+
warning: outline("M21.73 18l-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3M12 9v4M12 17h.01"),
|
|
2577
|
+
// triangle-alert
|
|
2578
|
+
error: outline("M2 12a10 10 0 1 0 20 0a10 10 0 1 0-20 0zM12 8V12M12 16H12.01"),
|
|
2579
|
+
// circle-alert
|
|
2580
|
+
success: outline("M2 12a10 10 0 1 0 20 0a10 10 0 1 0-20 0zM16 9l-5.5 5.5L8 12"),
|
|
2581
|
+
// circle-check
|
|
2582
|
+
upload: outline("M12 3v12M17 8l-5-5-5 5M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"),
|
|
2583
|
+
drag: outline("M8 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0zM8 5a1 1 0 1 0 2 0a1 1 0 1 0-2 0zM8 19a1 1 0 1 0 2 0a1 1 0 1 0-2 0zM14 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0zM14 5a1 1 0 1 0 2 0a1 1 0 1 0-2 0zM14 19a1 1 0 1 0 2 0a1 1 0 1 0-2 0z"),
|
|
2584
|
+
// grip-vertical
|
|
2585
|
+
star: outline("M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"),
|
|
2586
|
+
heart: outline("M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"),
|
|
2587
|
+
tag: outline("M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42zM7 7.5a.5 .5 0 1 0 1 0a.5 .5 0 1 0-1 0z"),
|
|
2588
|
+
folder: outline("M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"),
|
|
2589
|
+
"folder-open": outline("M6 14l1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2"),
|
|
2590
|
+
file: outline("M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2zM14 2v5a1 1 0 0 0 1 1h5"),
|
|
2591
|
+
copy: outline("M10 8h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2v-10a2 2 0 0 1 2-2zM4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"),
|
|
2592
|
+
square: outline("M5 3h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-14a2 2 0 0 1-2-2v-14a2 2 0 0 1 2-2z"),
|
|
2593
|
+
code: outline("M18 16l4-4-4-4M6 8l-4 4 4 4M14.5 4l-5 16"),
|
|
2594
|
+
// code-xml
|
|
2595
|
+
book: outline("M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20")
|
|
2596
|
+
// </lucide-glyphs>
|
|
2123
2597
|
});
|
|
2124
2598
|
var aliases = Object.freeze({
|
|
2125
2599
|
settings: "gear",
|
|
@@ -2157,8 +2631,8 @@ async function loadFontAwesome(options) {
|
|
|
2157
2631
|
await loadFontAwesomeKit(kit);
|
|
2158
2632
|
return activate ? useFontAwesome() : getIconConfig();
|
|
2159
2633
|
}
|
|
2160
|
-
function icon(
|
|
2161
|
-
const spec = parseIconSpec(
|
|
2634
|
+
function icon(name2, options = {}) {
|
|
2635
|
+
const spec = parseIconSpec(name2);
|
|
2162
2636
|
if (spec.classes) return faIcon(spec.classes, options);
|
|
2163
2637
|
const resolved = aliases[spec.name] ?? spec.name;
|
|
2164
2638
|
if (spec.provider === "builtin") return builtinIcon(resolved, options);
|
|
@@ -2178,24 +2652,60 @@ function icon(name, options = {}) {
|
|
|
2178
2652
|
}
|
|
2179
2653
|
return builtinIcon(resolved, options);
|
|
2180
2654
|
}
|
|
2181
|
-
function builtinIcon(
|
|
2182
|
-
const entry = extraGlyphs[
|
|
2183
|
-
if (!entry)
|
|
2184
|
-
|
|
2655
|
+
function builtinIcon(name2, options) {
|
|
2656
|
+
const entry = extraGlyphs[name2] ?? icons[name2];
|
|
2657
|
+
if (!entry) {
|
|
2658
|
+
if (options.strict) throw new RangeError(`Unknown icon: ${name2}`);
|
|
2659
|
+
warnMissingIcon(name2);
|
|
2660
|
+
return missingIcon(name2, options);
|
|
2661
|
+
}
|
|
2662
|
+
const [viewBox, pathData, paint = "fill"] = entry;
|
|
2663
|
+
const svg = iconSvg(viewBox, paint, options);
|
|
2664
|
+
const path = document.createElementNS(SVG_NS, "path");
|
|
2665
|
+
path.setAttribute("d", pathData);
|
|
2666
|
+
svg.append(path);
|
|
2667
|
+
return svg;
|
|
2668
|
+
}
|
|
2669
|
+
function iconSvg(viewBox, paint, options) {
|
|
2185
2670
|
const { size = 16 } = options;
|
|
2186
2671
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
2187
|
-
const path = document.createElementNS(SVG_NS, "path");
|
|
2188
2672
|
svg.setAttribute("class", classList("zx-icon", options.class));
|
|
2189
2673
|
svg.setAttribute("viewBox", viewBox);
|
|
2190
2674
|
svg.setAttribute("width", String(size));
|
|
2191
2675
|
svg.setAttribute("height", String(size));
|
|
2192
|
-
|
|
2676
|
+
if (paint === "stroke") {
|
|
2677
|
+
svg.setAttribute("fill", "none");
|
|
2678
|
+
svg.setAttribute("stroke", "currentColor");
|
|
2679
|
+
svg.setAttribute("stroke-width", strokeWidth(viewBox, size));
|
|
2680
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
2681
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
2682
|
+
} else {
|
|
2683
|
+
svg.setAttribute("fill", "currentColor");
|
|
2684
|
+
}
|
|
2193
2685
|
svg.setAttribute("focusable", "false");
|
|
2194
2686
|
applyLabel(svg, options.label ?? null);
|
|
2195
|
-
path.setAttribute("d", pathData);
|
|
2196
|
-
svg.append(path);
|
|
2197
2687
|
return svg;
|
|
2198
2688
|
}
|
|
2689
|
+
function strokeWidth(viewBox, size) {
|
|
2690
|
+
const [, , width, height] = viewBox.trim().split(/[\s,]+/).map(Number);
|
|
2691
|
+
const extent = Math.max(width, height) || 24;
|
|
2692
|
+
let units = STROKE_WIDTH * extent / 24;
|
|
2693
|
+
const pixels = typeof size === "number" ? size : /^\d*\.?\d+(px)?$/.test(String(size).trim()) ? parseFloat(String(size)) : NaN;
|
|
2694
|
+
if (pixels > 0) units = Math.max(units, MIN_STROKE_PX * extent / pixels);
|
|
2695
|
+
return String(Math.round(units * 1e3) / 1e3);
|
|
2696
|
+
}
|
|
2697
|
+
var PLACEHOLDER_VIEW_BOX = VIEW_BOX;
|
|
2698
|
+
function missingIcon(name2, options) {
|
|
2699
|
+
const svg = iconSvg(PLACEHOLDER_VIEW_BOX, "stroke", options);
|
|
2700
|
+
svg.setAttribute("data-zx-icon-missing", name2);
|
|
2701
|
+
return svg;
|
|
2702
|
+
}
|
|
2703
|
+
var warnedMissing = /* @__PURE__ */ new Set();
|
|
2704
|
+
function warnMissingIcon(name2) {
|
|
2705
|
+
if (warnedMissing.has(name2)) return;
|
|
2706
|
+
warnedMissing.add(name2);
|
|
2707
|
+
console.warn(`[zx.icon] Unknown icon "${name2}" \u2014 rendered an empty placeholder. Add it with registerIcons(), or render Font Awesome with useFontAwesome().`);
|
|
2708
|
+
}
|
|
2199
2709
|
function faIcon(classes, options) {
|
|
2200
2710
|
const { size = 16 } = options;
|
|
2201
2711
|
const element = document.createElement("i");
|
|
@@ -2239,15 +2749,15 @@ var TimePicker = class extends Component {
|
|
|
2239
2749
|
const content = h("div", {
|
|
2240
2750
|
class: "zx-time-picker__segments",
|
|
2241
2751
|
role: "group",
|
|
2242
|
-
ariaLabel: "Time"
|
|
2752
|
+
ariaLabel: this._message("timePicker.label", "Time")
|
|
2243
2753
|
});
|
|
2244
2754
|
this._content = content;
|
|
2245
|
-
this._addSpin(content, "h", "Hour", 23);
|
|
2755
|
+
this._addSpin(content, "h", this._message("timePicker.hour", "Hour"), 23);
|
|
2246
2756
|
content.append(h("span", { class: "zx-time-picker__separator", ariaHidden: "true" }, ":"));
|
|
2247
|
-
this._addSpin(content, "m", "Minute", 59);
|
|
2757
|
+
this._addSpin(content, "m", this._message("timePicker.minute", "Minute"), 59);
|
|
2248
2758
|
if (this.options.seconds) {
|
|
2249
2759
|
content.append(h("span", { class: "zx-time-picker__separator", ariaHidden: "true" }, ":"));
|
|
2250
|
-
this._addSpin(content, "s", "Second", 59);
|
|
2760
|
+
this._addSpin(content, "s", this._message("timePicker.second", "Second"), 59);
|
|
2251
2761
|
}
|
|
2252
2762
|
root.append(content);
|
|
2253
2763
|
if (this.options.clock) {
|
|
@@ -2256,7 +2766,7 @@ var TimePicker = class extends Component {
|
|
|
2256
2766
|
ref: "clockToggle",
|
|
2257
2767
|
class: "zx-icon-btn zx-time-picker__clock-toggle",
|
|
2258
2768
|
type: "button",
|
|
2259
|
-
ariaLabel: "Pick the time on a clock",
|
|
2769
|
+
ariaLabel: this._message("timePicker.clock", "Pick the time on a clock"),
|
|
2260
2770
|
ariaExpanded: "false",
|
|
2261
2771
|
ariaControls: clockId
|
|
2262
2772
|
}, icon("clock", { size: 15 })));
|
|
@@ -2403,7 +2913,7 @@ var TimePicker = class extends Component {
|
|
|
2403
2913
|
ref: "headHour",
|
|
2404
2914
|
class: "zx-time-picker__clock-unit",
|
|
2405
2915
|
type: "button",
|
|
2406
|
-
ariaLabel: "Select the hour",
|
|
2916
|
+
ariaLabel: this._message("timePicker.selectHour", "Select the hour"),
|
|
2407
2917
|
dataset: { unit: "h" }
|
|
2408
2918
|
}),
|
|
2409
2919
|
h("span", { class: "zx-time-picker__clock-colon", ariaHidden: "true" }, ":"),
|
|
@@ -2411,7 +2921,7 @@ var TimePicker = class extends Component {
|
|
|
2411
2921
|
ref: "headMinute",
|
|
2412
2922
|
class: "zx-time-picker__clock-unit",
|
|
2413
2923
|
type: "button",
|
|
2414
|
-
ariaLabel: "Select the minutes",
|
|
2924
|
+
ariaLabel: this._message("timePicker.selectMinutes", "Select the minutes"),
|
|
2415
2925
|
dataset: { unit: "m" }
|
|
2416
2926
|
})
|
|
2417
2927
|
),
|
|
@@ -2469,7 +2979,7 @@ var TimePicker = class extends Component {
|
|
|
2469
2979
|
this.refs.headMinute.textContent = pad2(this._display.m);
|
|
2470
2980
|
this.refs.headHour.setAttribute("aria-pressed", String(hours));
|
|
2471
2981
|
this.refs.headMinute.setAttribute("aria-pressed", String(!hours));
|
|
2472
|
-
this.refs.dial.setAttribute("aria-label", hours ? "Hour" : "Minutes");
|
|
2982
|
+
this.refs.dial.setAttribute("aria-label", hours ? this._message("timePicker.hour", "Hour") : this._message("timePicker.minutes", "Minutes"));
|
|
2473
2983
|
if (!this._clockOpen) return;
|
|
2474
2984
|
const selected = hours ? this._display.h : this._display.m;
|
|
2475
2985
|
const marks = hours ? hourMarks() : minuteMarks();
|
|
@@ -2504,6 +3014,16 @@ var TimePicker = class extends Component {
|
|
|
2504
3014
|
element.setAttribute("aria-checked", String(checked));
|
|
2505
3015
|
element.tabIndex = checked ? 0 : -1;
|
|
2506
3016
|
}
|
|
3017
|
+
/**
|
|
3018
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
3019
|
+
* @param {string} key Message key.
|
|
3020
|
+
* @param {string} fallback English default.
|
|
3021
|
+
* @returns {string}
|
|
3022
|
+
*/
|
|
3023
|
+
_message(key, fallback) {
|
|
3024
|
+
const message = this.msg(key);
|
|
3025
|
+
return message === key ? fallback : message;
|
|
3026
|
+
}
|
|
2507
3027
|
};
|
|
2508
3028
|
function hourMarks() {
|
|
2509
3029
|
const marks = [];
|
|
@@ -2590,7 +3110,7 @@ var DatePicker = class extends Component {
|
|
|
2590
3110
|
ref: "previous",
|
|
2591
3111
|
class: "zx-date-picker__nav",
|
|
2592
3112
|
type: "button",
|
|
2593
|
-
ariaLabel: "Previous month"
|
|
3113
|
+
ariaLabel: this._message("datePicker.previousMonth", "Previous month")
|
|
2594
3114
|
}, icon("chevron-left")),
|
|
2595
3115
|
h("button", {
|
|
2596
3116
|
ref: "heading",
|
|
@@ -2603,7 +3123,7 @@ var DatePicker = class extends Component {
|
|
|
2603
3123
|
ref: "next",
|
|
2604
3124
|
class: "zx-date-picker__nav",
|
|
2605
3125
|
type: "button",
|
|
2606
|
-
ariaLabel: "Next month"
|
|
3126
|
+
ariaLabel: this._message("datePicker.nextMonth", "Next month")
|
|
2607
3127
|
}, icon("chevron-right"))
|
|
2608
3128
|
),
|
|
2609
3129
|
h(
|
|
@@ -2620,14 +3140,14 @@ var DatePicker = class extends Component {
|
|
|
2620
3140
|
ref: "quickPrevious",
|
|
2621
3141
|
class: "zx-date-picker__nav",
|
|
2622
3142
|
type: "button",
|
|
2623
|
-
ariaLabel: "Previous year"
|
|
3143
|
+
ariaLabel: this._message("datePicker.previousYear", "Previous year")
|
|
2624
3144
|
}, icon("chevron-left")),
|
|
2625
3145
|
h("span", { ref: "quickYear", class: "zx-date-picker__quick-year", ariaLive: "polite" }),
|
|
2626
3146
|
h("button", {
|
|
2627
3147
|
ref: "quickNext",
|
|
2628
3148
|
class: "zx-date-picker__nav",
|
|
2629
3149
|
type: "button",
|
|
2630
|
-
ariaLabel: "Next year"
|
|
3150
|
+
ariaLabel: this._message("datePicker.nextYear", "Next year")
|
|
2631
3151
|
}, icon("chevron-right"))
|
|
2632
3152
|
),
|
|
2633
3153
|
h("div", { ref: "quickGrid", class: "zx-date-picker__quick-grid", role: "grid" })
|
|
@@ -2638,7 +3158,7 @@ var DatePicker = class extends Component {
|
|
|
2638
3158
|
ref: "grid",
|
|
2639
3159
|
class: "zx-date-picker__grid",
|
|
2640
3160
|
role: "grid",
|
|
2641
|
-
ariaLabel: "Calendar"
|
|
3161
|
+
ariaLabel: this._message("datePicker.calendar", "Calendar")
|
|
2642
3162
|
},
|
|
2643
3163
|
h("thead", { ref: "weekdays" }),
|
|
2644
3164
|
h("tbody", { ref: "days" })
|
|
@@ -2703,8 +3223,8 @@ var DatePicker = class extends Component {
|
|
|
2703
3223
|
*/
|
|
2704
3224
|
focus() {
|
|
2705
3225
|
this._closeQuickPick();
|
|
2706
|
-
const
|
|
2707
|
-
|
|
3226
|
+
const button2 = this._buttonForDate(this._focused);
|
|
3227
|
+
button2?.focus();
|
|
2708
3228
|
return this;
|
|
2709
3229
|
}
|
|
2710
3230
|
/** Cleans up an appended time picker and generated host content. @returns {void} */
|
|
@@ -2736,7 +3256,7 @@ var DatePicker = class extends Component {
|
|
|
2736
3256
|
row.append(h("th", {
|
|
2737
3257
|
class: "zx-date-picker__week-heading",
|
|
2738
3258
|
scope: "col",
|
|
2739
|
-
ariaLabel: "Week number"
|
|
3259
|
+
ariaLabel: this._message("datePicker.weekNumber", "Week number")
|
|
2740
3260
|
}, "#"));
|
|
2741
3261
|
}
|
|
2742
3262
|
const sunday = new Date(2023, 0, 1);
|
|
@@ -2756,7 +3276,10 @@ var DatePicker = class extends Component {
|
|
|
2756
3276
|
const offset = (first.getDay() - this._weekStart + 7) % 7;
|
|
2757
3277
|
const start = addDays(first, -offset);
|
|
2758
3278
|
this.refs.heading.textContent = formatDate(first, "%B %Y");
|
|
2759
|
-
this.refs.heading.setAttribute(
|
|
3279
|
+
this.refs.heading.setAttribute(
|
|
3280
|
+
"aria-label",
|
|
3281
|
+
this._message("datePicker.chooseMonthYear", "Choose month and year, %1", formatDate(first, "%B %Y"))
|
|
3282
|
+
);
|
|
2760
3283
|
const rows = [];
|
|
2761
3284
|
for (let week = 0; week < 6; week += 1) {
|
|
2762
3285
|
const rowStart = addDays(start, week * 7);
|
|
@@ -2765,14 +3288,14 @@ var DatePicker = class extends Component {
|
|
|
2765
3288
|
row.append(h("th", {
|
|
2766
3289
|
class: "zx-date-picker__week",
|
|
2767
3290
|
scope: "row",
|
|
2768
|
-
ariaLabel:
|
|
3291
|
+
ariaLabel: this._message("datePicker.week", "Week %1", isoWeekNumber(rowStart))
|
|
2769
3292
|
}, String(isoWeekNumber(rowStart))));
|
|
2770
3293
|
}
|
|
2771
3294
|
for (let column = 0; column < 7; column += 1) {
|
|
2772
3295
|
const date = addDays(rowStart, column);
|
|
2773
3296
|
const selected = Boolean(this._value && isSameDay(date, this._value));
|
|
2774
3297
|
const unavailable = !this._inRange(date);
|
|
2775
|
-
const
|
|
3298
|
+
const button2 = h("button", {
|
|
2776
3299
|
class: "zx-date-picker__day",
|
|
2777
3300
|
type: "button",
|
|
2778
3301
|
role: "gridcell",
|
|
@@ -2786,7 +3309,7 @@ var DatePicker = class extends Component {
|
|
|
2786
3309
|
otherMonth: date.getMonth() === this._viewMonth ? null : "true"
|
|
2787
3310
|
}
|
|
2788
3311
|
}, formatDate(date, "%e"));
|
|
2789
|
-
row.append(h("td", { role: "presentation" },
|
|
3312
|
+
row.append(h("td", { role: "presentation" }, button2));
|
|
2790
3313
|
}
|
|
2791
3314
|
rows.push(row);
|
|
2792
3315
|
}
|
|
@@ -2795,16 +3318,16 @@ var DatePicker = class extends Component {
|
|
|
2795
3318
|
}
|
|
2796
3319
|
/** @param {Event} event @returns {void} */
|
|
2797
3320
|
_onDayClick(event) {
|
|
2798
|
-
const
|
|
2799
|
-
if (!
|
|
2800
|
-
const date = parseDate(
|
|
3321
|
+
const button2 = event.target?.closest?.("[data-date]");
|
|
3322
|
+
if (!button2 || !this.refs.days.contains(button2)) return;
|
|
3323
|
+
const date = parseDate(button2.dataset.date, "%Y-%m-%d");
|
|
2801
3324
|
if (date && this._inRange(date)) this._selectDate(date);
|
|
2802
3325
|
}
|
|
2803
3326
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
2804
3327
|
_onDayKeydown(event) {
|
|
2805
|
-
const
|
|
2806
|
-
if (!
|
|
2807
|
-
const current = parseDate(
|
|
3328
|
+
const button2 = event.target?.closest?.("[data-date]");
|
|
3329
|
+
if (!button2 || !this.refs.days.contains(button2)) return;
|
|
3330
|
+
const current = parseDate(button2.dataset.date, "%Y-%m-%d");
|
|
2808
3331
|
if (!current) return;
|
|
2809
3332
|
let next = null;
|
|
2810
3333
|
if (event.key === "ArrowLeft") next = addDays(current, -1);
|
|
@@ -2915,15 +3438,15 @@ var DatePicker = class extends Component {
|
|
|
2915
3438
|
}
|
|
2916
3439
|
/** @param {Event} event @returns {void} */
|
|
2917
3440
|
_onQuickClick(event) {
|
|
2918
|
-
const
|
|
2919
|
-
if (!
|
|
2920
|
-
this._chooseQuickMonth(Number(
|
|
3441
|
+
const button2 = event.target?.closest?.("[data-month]");
|
|
3442
|
+
if (!button2 || !this.refs.quickGrid.contains(button2)) return;
|
|
3443
|
+
this._chooseQuickMonth(Number(button2.dataset.month));
|
|
2921
3444
|
}
|
|
2922
3445
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
2923
3446
|
_onQuickKeydown(event) {
|
|
2924
|
-
const
|
|
2925
|
-
if (!
|
|
2926
|
-
const month = Number(
|
|
3447
|
+
const button2 = event.target?.closest?.("[data-month]");
|
|
3448
|
+
if (!button2 || !this.refs.quickGrid.contains(button2)) return;
|
|
3449
|
+
const month = Number(button2.dataset.month);
|
|
2927
3450
|
let next = null;
|
|
2928
3451
|
if (event.key === "ArrowLeft") next = month - 1;
|
|
2929
3452
|
else if (event.key === "ArrowRight") next = month + 1;
|
|
@@ -2970,6 +3493,17 @@ var DatePicker = class extends Component {
|
|
|
2970
3493
|
_buttonForDate(date) {
|
|
2971
3494
|
return this.refs.days.querySelector(`[data-date="${formatDate(date, "%Y-%m-%d")}"]`);
|
|
2972
3495
|
}
|
|
3496
|
+
/**
|
|
3497
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
3498
|
+
* @param {string} key Message key.
|
|
3499
|
+
* @param {string} fallback Built-in text, with `%1`-style placeholders.
|
|
3500
|
+
* @param {...unknown} args Interpolation values.
|
|
3501
|
+
* @returns {string}
|
|
3502
|
+
*/
|
|
3503
|
+
_message(key, fallback, ...args) {
|
|
3504
|
+
const message = this.msg(key, ...args);
|
|
3505
|
+
return message === key ? printf(fallback, args) : message;
|
|
3506
|
+
}
|
|
2973
3507
|
};
|
|
2974
3508
|
function validDate(value) {
|
|
2975
3509
|
return value instanceof Date && !Number.isNaN(value.getTime()) ? new Date(value.getTime()) : null;
|
|
@@ -3031,21 +3565,21 @@ var MonthPicker = class extends DatePicker {
|
|
|
3031
3565
|
ref: "previousYear",
|
|
3032
3566
|
class: "zx-month-picker__nav",
|
|
3033
3567
|
type: "button",
|
|
3034
|
-
ariaLabel: "Previous year"
|
|
3568
|
+
ariaLabel: this._message("monthPicker.previousYear", "Previous year")
|
|
3035
3569
|
}, icon("chevron-left")),
|
|
3036
3570
|
h("span", { ref: "year", class: "zx-month-picker__year", ariaLive: "polite" }),
|
|
3037
3571
|
h("button", {
|
|
3038
3572
|
ref: "nextYear",
|
|
3039
3573
|
class: "zx-month-picker__nav",
|
|
3040
3574
|
type: "button",
|
|
3041
|
-
ariaLabel: "Next year"
|
|
3575
|
+
ariaLabel: this._message("monthPicker.nextYear", "Next year")
|
|
3042
3576
|
}, icon("chevron-right"))
|
|
3043
3577
|
),
|
|
3044
3578
|
h("div", {
|
|
3045
3579
|
ref: "grid",
|
|
3046
3580
|
class: "zx-month-picker__grid",
|
|
3047
3581
|
role: "grid",
|
|
3048
|
-
ariaLabel: "Choose month"
|
|
3582
|
+
ariaLabel: this._message("monthPicker.chooseMonth", "Choose month")
|
|
3049
3583
|
})
|
|
3050
3584
|
);
|
|
3051
3585
|
this._content = content;
|
|
@@ -3124,15 +3658,15 @@ var MonthPicker = class extends DatePicker {
|
|
|
3124
3658
|
}
|
|
3125
3659
|
/** @param {Event} event @returns {void} */
|
|
3126
3660
|
_onMonthClick(event) {
|
|
3127
|
-
const
|
|
3128
|
-
if (!
|
|
3129
|
-
this._selectMonth(Number(
|
|
3661
|
+
const button2 = event.target?.closest?.("[data-month]");
|
|
3662
|
+
if (!button2 || !this.refs.grid.contains(button2)) return;
|
|
3663
|
+
this._selectMonth(Number(button2.dataset.month));
|
|
3130
3664
|
}
|
|
3131
3665
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
3132
3666
|
_onMonthKeydown(event) {
|
|
3133
|
-
const
|
|
3134
|
-
if (!
|
|
3135
|
-
const current = Number(
|
|
3667
|
+
const button2 = event.target?.closest?.("[data-month]");
|
|
3668
|
+
if (!button2 || !this.refs.grid.contains(button2)) return;
|
|
3669
|
+
const current = Number(button2.dataset.month);
|
|
3136
3670
|
let delta = null;
|
|
3137
3671
|
if (event.key === "ArrowLeft") delta = -1;
|
|
3138
3672
|
else if (event.key === "ArrowRight") delta = 1;
|
|
@@ -3201,7 +3735,7 @@ function registerDatePickerFieldAdapters() {
|
|
|
3201
3735
|
let disabled = false;
|
|
3202
3736
|
const syncDisabled = () => {
|
|
3203
3737
|
picker.el.setAttribute("aria-disabled", String(disabled));
|
|
3204
|
-
for (const
|
|
3738
|
+
for (const button2 of picker.el.querySelectorAll("button")) button2.disabled = disabled;
|
|
3205
3739
|
};
|
|
3206
3740
|
field.listen(picker.el, "change", (event) => event.stopImmediatePropagation());
|
|
3207
3741
|
picker.on("change", (event) => field.emit("change", { value: event.detail.date }));
|
|
@@ -3399,9 +3933,9 @@ function hidePopover(element) {
|
|
|
3399
3933
|
} catch {
|
|
3400
3934
|
}
|
|
3401
3935
|
}
|
|
3402
|
-
function restoreAttribute(element,
|
|
3403
|
-
if (value === null) element.removeAttribute(
|
|
3404
|
-
else element.setAttribute(
|
|
3936
|
+
function restoreAttribute(element, name2, value) {
|
|
3937
|
+
if (value === null) element.removeAttribute(name2);
|
|
3938
|
+
else element.setAttribute(name2, value);
|
|
3405
3939
|
}
|
|
3406
3940
|
|
|
3407
3941
|
// src/components/date-picker/date-range-picker.js
|
|
@@ -3784,12 +4318,12 @@ var DateRangePicker = class extends Component {
|
|
|
3784
4318
|
/* ---------------------------------------------------------------------- events -- */
|
|
3785
4319
|
/** @param {Event} event @returns {void} */
|
|
3786
4320
|
_onPresetClick(event) {
|
|
3787
|
-
const
|
|
4321
|
+
const button2 = (
|
|
3788
4322
|
/** @type {Element} */
|
|
3789
4323
|
event.target?.closest?.("[data-preset]")
|
|
3790
4324
|
);
|
|
3791
|
-
if (!
|
|
3792
|
-
const preset = this._presets.find((entry) => entry.name ===
|
|
4325
|
+
if (!button2 || this._disabled) return;
|
|
4326
|
+
const preset = this._presets.find((entry) => entry.name === button2.dataset.preset);
|
|
3793
4327
|
if (!preset) return;
|
|
3794
4328
|
const range = preset.range();
|
|
3795
4329
|
this.set({ start: range?.start ?? null, end: range?.end ?? null }, { silent: true });
|
|
@@ -3892,15 +4426,15 @@ var DateRangePicker = class extends Component {
|
|
|
3892
4426
|
const date = addDays(rowStart, column);
|
|
3893
4427
|
const cell = h("td", { role: "presentation" });
|
|
3894
4428
|
if (date.getMonth() === first.getMonth() && date.getFullYear() === first.getFullYear()) {
|
|
3895
|
-
const
|
|
4429
|
+
const button2 = h("button", {
|
|
3896
4430
|
class: "zx-date-range-picker__day",
|
|
3897
4431
|
type: "button",
|
|
3898
4432
|
role: "gridcell",
|
|
3899
4433
|
tabindex: -1,
|
|
3900
4434
|
dataset: { date: formatDate(date, "%Y-%m-%d") }
|
|
3901
4435
|
}, formatDate(date, "%e"));
|
|
3902
|
-
cell.append(
|
|
3903
|
-
this._dayCells.push({ date, cell, button });
|
|
4436
|
+
cell.append(button2);
|
|
4437
|
+
this._dayCells.push({ date, cell, button: button2 });
|
|
3904
4438
|
}
|
|
3905
4439
|
row.append(cell);
|
|
3906
4440
|
}
|
|
@@ -3971,17 +4505,17 @@ var DateRangePicker = class extends Component {
|
|
|
3971
4505
|
}
|
|
3972
4506
|
if (!roving) roving = this._dayCells[0] ?? null;
|
|
3973
4507
|
for (const entry of this._dayCells) {
|
|
3974
|
-
const { date, cell, button } = entry;
|
|
4508
|
+
const { date, cell, button: button2 } = entry;
|
|
3975
4509
|
const state = this._dayState(date);
|
|
3976
4510
|
setDataset(cell, "range", state.range);
|
|
3977
4511
|
setDataset(cell, "rangeEdge", state.edge);
|
|
3978
|
-
setDataset(
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
if (isSameDay(date, today2))
|
|
3984
|
-
else
|
|
4512
|
+
setDataset(button2, "range", state.range);
|
|
4513
|
+
button2.tabIndex = entry === roving ? 0 : -1;
|
|
4514
|
+
button2.setAttribute("aria-selected", String(state.range !== null && state.range !== "preview"));
|
|
4515
|
+
button2.setAttribute("aria-disabled", String(!this._selectable(date)));
|
|
4516
|
+
button2.setAttribute("aria-label", this._dayLabel(date, state.range));
|
|
4517
|
+
if (isSameDay(date, today2)) button2.setAttribute("aria-current", "date");
|
|
4518
|
+
else button2.removeAttribute("aria-current");
|
|
3985
4519
|
}
|
|
3986
4520
|
}
|
|
3987
4521
|
/**
|
|
@@ -4032,7 +4566,7 @@ var DateRangePicker = class extends Component {
|
|
|
4032
4566
|
/** @returns {void} */
|
|
4033
4567
|
_syncDisabled() {
|
|
4034
4568
|
this.el.setAttribute("aria-disabled", String(this._disabled));
|
|
4035
|
-
for (const
|
|
4569
|
+
for (const button2 of this.el.querySelectorAll("button")) button2.disabled = this._disabled;
|
|
4036
4570
|
}
|
|
4037
4571
|
/** Writes the current selection into the visually hidden live region. @returns {void} */
|
|
4038
4572
|
_announce() {
|
|
@@ -4055,9 +4589,9 @@ var DateRangePicker = class extends Component {
|
|
|
4055
4589
|
}
|
|
4056
4590
|
/** @param {Element|null} target @returns {{date: Date, cell: Element, button: Element}|null} */
|
|
4057
4591
|
_cellFor(target) {
|
|
4058
|
-
const
|
|
4059
|
-
if (!
|
|
4060
|
-
return this._dayCells.find((cell) => cell.button ===
|
|
4592
|
+
const button2 = target?.closest?.("[data-date]");
|
|
4593
|
+
if (!button2) return null;
|
|
4594
|
+
return this._dayCells.find((cell) => cell.button === button2) ?? null;
|
|
4061
4595
|
}
|
|
4062
4596
|
/** @param {Date} date @returns {HTMLButtonElement|null} */
|
|
4063
4597
|
_buttonForDate(date) {
|
|
@@ -4195,17 +4729,17 @@ function isoWeekNumber2(date) {
|
|
|
4195
4729
|
const yearStart = new Date(Date.UTC(utc.getUTCFullYear(), 0, 1));
|
|
4196
4730
|
return Math.ceil(((utc.getTime() - yearStart.getTime()) / DAY_MS + 1) / 7);
|
|
4197
4731
|
}
|
|
4198
|
-
function setDataset(element,
|
|
4199
|
-
if (value === null || value === void 0) delete element.dataset[
|
|
4200
|
-
else element.dataset[
|
|
4732
|
+
function setDataset(element, name2, value) {
|
|
4733
|
+
if (value === null || value === void 0) delete element.dataset[name2];
|
|
4734
|
+
else element.dataset[name2] = value;
|
|
4201
4735
|
}
|
|
4202
4736
|
function rememberAttributes2(element, names) {
|
|
4203
|
-
return new Map(names.map((
|
|
4737
|
+
return new Map(names.map((name2) => [name2, element.getAttribute(name2)]));
|
|
4204
4738
|
}
|
|
4205
4739
|
function restoreAttributes2(element, attributes) {
|
|
4206
|
-
for (const [
|
|
4207
|
-
if (value === null) element.removeAttribute(
|
|
4208
|
-
else element.setAttribute(
|
|
4740
|
+
for (const [name2, value] of attributes) {
|
|
4741
|
+
if (value === null) element.removeAttribute(name2);
|
|
4742
|
+
else element.setAttribute(name2, value);
|
|
4209
4743
|
}
|
|
4210
4744
|
}
|
|
4211
4745
|
|
|
@@ -4274,6 +4808,8 @@ var DateRangeBox = class extends Component {
|
|
|
4274
4808
|
this.el = root;
|
|
4275
4809
|
this._originalState = root.getAttribute("data-state");
|
|
4276
4810
|
this._originalAriaDisabled = root.getAttribute("aria-disabled");
|
|
4811
|
+
this._originalClearable = root.getAttribute("data-clearable");
|
|
4812
|
+
root.toggleAttribute("data-clearable", Boolean(this.options.clearable));
|
|
4277
4813
|
this._format = String(this.options.format || "%d.%m.%Y");
|
|
4278
4814
|
this._separator = String(this.options.separator ?? " \u2013 ");
|
|
4279
4815
|
this._disabled = Boolean(this.options.disabled);
|
|
@@ -4466,6 +5002,7 @@ var DateRangeBox = class extends Component {
|
|
|
4466
5002
|
this._content?.remove();
|
|
4467
5003
|
restoreAttribute2(this.el, "data-state", this._originalState);
|
|
4468
5004
|
restoreAttribute2(this.el, "aria-disabled", this._originalAriaDisabled);
|
|
5005
|
+
restoreAttribute2(this.el, "data-clearable", this._originalClearable);
|
|
4469
5006
|
super.destroy();
|
|
4470
5007
|
}
|
|
4471
5008
|
/* --------------------------------------------------------------------- internals -- */
|
|
@@ -4562,7 +5099,11 @@ var DateRangeBox = class extends Component {
|
|
|
4562
5099
|
/** @returns {void} */
|
|
4563
5100
|
_syncDisplay() {
|
|
4564
5101
|
this.refs.input.value = formatRangeText(this._range, this._format, this._separator);
|
|
4565
|
-
this.
|
|
5102
|
+
this._syncClear();
|
|
5103
|
+
}
|
|
5104
|
+
/** A disabled box offers no clear button: there is nothing it could do. @returns {void} */
|
|
5105
|
+
_syncClear() {
|
|
5106
|
+
this.refs.clear.hidden = !this.options.clearable || !(this._range.start || this._range.end) || this._disabled;
|
|
4566
5107
|
}
|
|
4567
5108
|
/** @returns {void} */
|
|
4568
5109
|
_syncDisabled() {
|
|
@@ -4570,6 +5111,7 @@ var DateRangeBox = class extends Component {
|
|
|
4570
5111
|
this.refs.toggle.disabled = this._disabled;
|
|
4571
5112
|
this.refs.clear.disabled = this._disabled;
|
|
4572
5113
|
this.el.setAttribute("aria-disabled", String(this._disabled));
|
|
5114
|
+
this._syncClear();
|
|
4573
5115
|
if (this._disabled) this._picker?.disable();
|
|
4574
5116
|
else this._picker?.enable();
|
|
4575
5117
|
}
|
|
@@ -4579,7 +5121,7 @@ var DateRangeBox = class extends Component {
|
|
|
4579
5121
|
this.refs.input.removeAttribute("aria-invalid");
|
|
4580
5122
|
}
|
|
4581
5123
|
/** @param {boolean} returnFocus @returns {void} */
|
|
4582
|
-
_close(
|
|
5124
|
+
_close(returnFocus2) {
|
|
4583
5125
|
if (!this._open) return;
|
|
4584
5126
|
this._position?.destroy();
|
|
4585
5127
|
this._position = null;
|
|
@@ -4587,7 +5129,7 @@ var DateRangeBox = class extends Component {
|
|
|
4587
5129
|
this.refs.popover.dataset.state = "closed";
|
|
4588
5130
|
this.refs.input.setAttribute("aria-expanded", "false");
|
|
4589
5131
|
this.refs.toggle.setAttribute("aria-expanded", "false");
|
|
4590
|
-
if (
|
|
5132
|
+
if (returnFocus2) this.focus();
|
|
4591
5133
|
this.emit("close");
|
|
4592
5134
|
}
|
|
4593
5135
|
};
|
|
@@ -4595,9 +5137,9 @@ function text2(key, fallback, args) {
|
|
|
4595
5137
|
const translated = translate(key);
|
|
4596
5138
|
return printf(translated === key ? fallback : translated, args);
|
|
4597
5139
|
}
|
|
4598
|
-
function restoreAttribute2(element,
|
|
4599
|
-
if (value === null) element.removeAttribute(
|
|
4600
|
-
else element.setAttribute(
|
|
5140
|
+
function restoreAttribute2(element, name2, value) {
|
|
5141
|
+
if (value === null) element.removeAttribute(name2);
|
|
5142
|
+
else element.setAttribute(name2, value);
|
|
4601
5143
|
}
|
|
4602
5144
|
|
|
4603
5145
|
// src/components/date-picker/range-field-adapter.js
|
|
@@ -4646,6 +5188,8 @@ var Datebox = class extends Component {
|
|
|
4646
5188
|
this.el = root;
|
|
4647
5189
|
this._originalState = root.getAttribute("data-state");
|
|
4648
5190
|
this._originalAriaDisabled = root.getAttribute("aria-disabled");
|
|
5191
|
+
this._originalClearable = root.getAttribute("data-clearable");
|
|
5192
|
+
root.toggleAttribute("data-clearable", Boolean(this.options.clearable));
|
|
4649
5193
|
this._format = effectiveFormat(this.options.format, this.options.time);
|
|
4650
5194
|
this._disabled = Boolean(this.options.disabled);
|
|
4651
5195
|
this._open = false;
|
|
@@ -4815,6 +5359,8 @@ var Datebox = class extends Component {
|
|
|
4815
5359
|
else this.el.setAttribute("data-state", this._originalState);
|
|
4816
5360
|
if (this._originalAriaDisabled === null) this.el.removeAttribute("aria-disabled");
|
|
4817
5361
|
else this.el.setAttribute("aria-disabled", this._originalAriaDisabled);
|
|
5362
|
+
if (this._originalClearable === null) this.el.removeAttribute("data-clearable");
|
|
5363
|
+
else this.el.setAttribute("data-clearable", this._originalClearable);
|
|
4818
5364
|
super.destroy();
|
|
4819
5365
|
}
|
|
4820
5366
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
@@ -4859,7 +5405,11 @@ var Datebox = class extends Component {
|
|
|
4859
5405
|
/** @returns {void} */
|
|
4860
5406
|
_syncDisplay() {
|
|
4861
5407
|
this.refs.input.value = this._value ? formatDate(this._value, this._format) : "";
|
|
4862
|
-
this.
|
|
5408
|
+
this._syncClear();
|
|
5409
|
+
}
|
|
5410
|
+
/** A disabled box offers no clear button: there is nothing it could do. @returns {void} */
|
|
5411
|
+
_syncClear() {
|
|
5412
|
+
this.refs.clear.hidden = !this.options.clearable || !this._value || this._disabled;
|
|
4863
5413
|
}
|
|
4864
5414
|
/** @returns {void} */
|
|
4865
5415
|
_syncDisabled() {
|
|
@@ -4867,6 +5417,7 @@ var Datebox = class extends Component {
|
|
|
4867
5417
|
this.refs.toggle.disabled = this._disabled;
|
|
4868
5418
|
this.refs.clear.disabled = this._disabled;
|
|
4869
5419
|
this.el.setAttribute("aria-disabled", String(this._disabled));
|
|
5420
|
+
this._syncClear();
|
|
4870
5421
|
}
|
|
4871
5422
|
/** @returns {void} */
|
|
4872
5423
|
_setValid() {
|
|
@@ -4877,7 +5428,7 @@ var Datebox = class extends Component {
|
|
|
4877
5428
|
this.refs.input.removeAttribute("aria-invalid");
|
|
4878
5429
|
}
|
|
4879
5430
|
/** @param {boolean} returnFocus @returns {void} */
|
|
4880
|
-
_close(
|
|
5431
|
+
_close(returnFocus2) {
|
|
4881
5432
|
if (!this._open) return;
|
|
4882
5433
|
this._position?.destroy();
|
|
4883
5434
|
this._position = null;
|
|
@@ -4885,7 +5436,7 @@ var Datebox = class extends Component {
|
|
|
4885
5436
|
this.refs.popover.dataset.state = "closed";
|
|
4886
5437
|
this.refs.input.setAttribute("aria-expanded", "false");
|
|
4887
5438
|
this.refs.toggle.setAttribute("aria-expanded", "false");
|
|
4888
|
-
if (
|
|
5439
|
+
if (returnFocus2) this.focus();
|
|
4889
5440
|
this.emit("close");
|
|
4890
5441
|
}
|
|
4891
5442
|
/** @returns {Date|null} */
|
|
@@ -5187,7 +5738,7 @@ var FieldUpload = class extends Component {
|
|
|
5187
5738
|
const xhr = new XMLHttpRequest();
|
|
5188
5739
|
this._xhr = xhr;
|
|
5189
5740
|
xhr.open("POST", String(this.options.url));
|
|
5190
|
-
for (const [
|
|
5741
|
+
for (const [name2, value] of Object.entries(this.options.headers ?? {})) xhr.setRequestHeader(name2, String(value));
|
|
5191
5742
|
this.listen(xhr.upload, "progress", (event) => {
|
|
5192
5743
|
if (event.lengthComputable) this._setProgress(event.loaded / event.total * 100);
|
|
5193
5744
|
});
|
|
@@ -5286,18 +5837,18 @@ function matchesAccept(file, accept) {
|
|
|
5286
5837
|
function createFormData(files, paramName, params) {
|
|
5287
5838
|
const form = new FormData();
|
|
5288
5839
|
for (const file of files) form.append(paramName, file);
|
|
5289
|
-
for (const [
|
|
5840
|
+
for (const [name2, value] of Object.entries(params ?? {})) appendFormValue(form, name2, value);
|
|
5290
5841
|
return form;
|
|
5291
5842
|
}
|
|
5292
|
-
function appendFormValue(form,
|
|
5843
|
+
function appendFormValue(form, name2, value) {
|
|
5293
5844
|
if (value == null) return;
|
|
5294
5845
|
if (Array.isArray(value)) {
|
|
5295
|
-
for (const item of value) appendFormValue(form,
|
|
5846
|
+
for (const item of value) appendFormValue(form, name2, item);
|
|
5296
5847
|
return;
|
|
5297
5848
|
}
|
|
5298
5849
|
const isBlob = typeof Blob === "function" && value instanceof Blob;
|
|
5299
|
-
if (isBlob) form.append(
|
|
5300
|
-
else form.append(
|
|
5850
|
+
if (isBlob) form.append(name2, value);
|
|
5851
|
+
else form.append(name2, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
5301
5852
|
}
|
|
5302
5853
|
function parseResponse(text3) {
|
|
5303
5854
|
if (!text3) return null;
|
|
@@ -5478,11 +6029,11 @@ var MultiValueEditor = class extends Component {
|
|
|
5478
6029
|
}
|
|
5479
6030
|
/** @param {MouseEvent} event @returns {void} */
|
|
5480
6031
|
_handleClick(event) {
|
|
5481
|
-
const
|
|
5482
|
-
if (!
|
|
5483
|
-
if (
|
|
5484
|
-
const action =
|
|
5485
|
-
const index = Number(
|
|
6032
|
+
const button2 = event.target instanceof Element ? event.target.closest("[data-action]") : null;
|
|
6033
|
+
if (!button2 || !this.el.contains(button2)) return;
|
|
6034
|
+
if (button2.getAttribute("aria-disabled") === "true") return;
|
|
6035
|
+
const action = button2.dataset.action;
|
|
6036
|
+
const index = Number(button2.dataset.index);
|
|
5486
6037
|
if (action === "add") {
|
|
5487
6038
|
const choices = normalizeOptions2(this.options.options);
|
|
5488
6039
|
this._values.push(this.options.options === null ? "" : choices[0]?.[0] ?? "");
|
|
@@ -5969,6 +6520,7 @@ var NumberField = class extends Component {
|
|
|
5969
6520
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
5970
6521
|
_onKeydown(event) {
|
|
5971
6522
|
if (this._disabled || this._readonly) return;
|
|
6523
|
+
if (event.altKey || event.ctrlKey || event.metaKey) return;
|
|
5972
6524
|
const large = Math.max(1, Math.trunc(Number(this.options.largeStep) || 1));
|
|
5973
6525
|
const actions = {
|
|
5974
6526
|
ArrowUp: () => this._stepBy(1),
|
|
@@ -6122,6 +6674,7 @@ function registerNumberFieldAdapter() {
|
|
|
6122
6674
|
label: options.label ? String(options.label) : void 0,
|
|
6123
6675
|
placeholder: options.placeholder,
|
|
6124
6676
|
required: options.required,
|
|
6677
|
+
name: field.name || null,
|
|
6125
6678
|
...options.props ?? {}
|
|
6126
6679
|
}));
|
|
6127
6680
|
let setting = false;
|
|
@@ -6316,7 +6869,7 @@ var Rating = class extends Component {
|
|
|
6316
6869
|
* @returns {HTMLButtonElement}
|
|
6317
6870
|
*/
|
|
6318
6871
|
_radio(value, part) {
|
|
6319
|
-
const
|
|
6872
|
+
const button2 = (
|
|
6320
6873
|
/** @type {HTMLButtonElement} */
|
|
6321
6874
|
h("button", {
|
|
6322
6875
|
class: "zx-rating__radio",
|
|
@@ -6328,18 +6881,18 @@ var Rating = class extends Component {
|
|
|
6328
6881
|
dataset: { value: String(value), part }
|
|
6329
6882
|
})
|
|
6330
6883
|
);
|
|
6331
|
-
this.listen(
|
|
6884
|
+
this.listen(button2, "click", (event) => {
|
|
6332
6885
|
this._choose(
|
|
6333
6886
|
value,
|
|
6334
6887
|
/** @type {MouseEvent} */
|
|
6335
6888
|
event.detail > 0
|
|
6336
6889
|
);
|
|
6337
6890
|
});
|
|
6338
|
-
this.listen(
|
|
6339
|
-
this.listen(
|
|
6340
|
-
this.listen(
|
|
6341
|
-
this._radios.push(
|
|
6342
|
-
return
|
|
6891
|
+
this.listen(button2, "pointerenter", () => this._setPreview(value));
|
|
6892
|
+
this.listen(button2, "focus", () => this._setPreview(value));
|
|
6893
|
+
this.listen(button2, "blur", () => this._setPreview(null));
|
|
6894
|
+
this._radios.push(button2);
|
|
6895
|
+
return button2;
|
|
6343
6896
|
}
|
|
6344
6897
|
/**
|
|
6345
6898
|
* @param {number} value Step value.
|
|
@@ -6556,15 +7109,36 @@ function itemText(item) {
|
|
|
6556
7109
|
return String(item ?? "").trim().toLocaleLowerCase();
|
|
6557
7110
|
}
|
|
6558
7111
|
|
|
6559
|
-
// src/components/select/
|
|
6560
|
-
var
|
|
6561
|
-
|
|
6562
|
-
"
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
7112
|
+
// src/components/select/color.js
|
|
7113
|
+
var TOKEN_REFERENCE = /^var\(\s*--[\w-]+\s*\)$/;
|
|
7114
|
+
function itemColor(value) {
|
|
7115
|
+
if (typeof value !== "string") return null;
|
|
7116
|
+
const text3 = value.trim();
|
|
7117
|
+
if (TOKEN_REFERENCE.test(text3)) return text3;
|
|
7118
|
+
return isCssColor(text3) ? text3 : null;
|
|
7119
|
+
}
|
|
7120
|
+
|
|
7121
|
+
// src/components/select/glyphs.js
|
|
7122
|
+
var STATUS_INDICATORS = Object.freeze([
|
|
7123
|
+
"dotted",
|
|
7124
|
+
"ring",
|
|
7125
|
+
"progress",
|
|
7126
|
+
"review",
|
|
7127
|
+
"ready",
|
|
7128
|
+
"waiting",
|
|
7129
|
+
"done",
|
|
7130
|
+
"canceled",
|
|
7131
|
+
"duplicate"
|
|
7132
|
+
]);
|
|
7133
|
+
var STATUS_TONES = Object.freeze([
|
|
7134
|
+
"muted",
|
|
7135
|
+
"neutral",
|
|
7136
|
+
"warning",
|
|
7137
|
+
"info",
|
|
7138
|
+
"accent",
|
|
7139
|
+
"success",
|
|
7140
|
+
"danger"
|
|
7141
|
+
]);
|
|
6568
7142
|
var DEFAULT_STATUSES = Object.freeze([
|
|
6569
7143
|
["backlog", "status.backlog", "Backlog", "dotted", "muted"],
|
|
6570
7144
|
["todo", "status.todo", "Todo", "ring", "neutral"],
|
|
@@ -6576,6 +7150,79 @@ var DEFAULT_STATUSES = Object.freeze([
|
|
|
6576
7150
|
["canceled", "status.canceled", "Canceled", "canceled", "muted"],
|
|
6577
7151
|
["duplicate", "status.duplicate", "Duplicate", "duplicate", "muted"]
|
|
6578
7152
|
]);
|
|
7153
|
+
var STATUS_ALIASES = Object.freeze({ review: "in-review", cancelled: "canceled" });
|
|
7154
|
+
var PRIORITY_URGENT = 4;
|
|
7155
|
+
function resolveStatusGlyph(status, options = {}) {
|
|
7156
|
+
const item = status && typeof status === "object" ? status : null;
|
|
7157
|
+
const id = normalizeStatusId(item ? item.ID ?? item.id : status);
|
|
7158
|
+
const preset = DEFAULT_STATUSES.find(([key]) => key === id);
|
|
7159
|
+
const indicator = String(options.indicator ?? item?.indicator ?? preset?.[3] ?? "ring");
|
|
7160
|
+
const tone = String(options.tone ?? item?.tone ?? preset?.[4] ?? "muted");
|
|
7161
|
+
return {
|
|
7162
|
+
indicator: (
|
|
7163
|
+
/** @type {StatusIndicator} */
|
|
7164
|
+
STATUS_INDICATORS.includes(indicator) ? indicator : "ring"
|
|
7165
|
+
),
|
|
7166
|
+
tone: (
|
|
7167
|
+
/** @type {StatusTone} */
|
|
7168
|
+
STATUS_TONES.includes(tone) ? tone : "muted"
|
|
7169
|
+
)
|
|
7170
|
+
};
|
|
7171
|
+
}
|
|
7172
|
+
function normalizeStatusId(id) {
|
|
7173
|
+
const key = String(id ?? "").trim().toLowerCase();
|
|
7174
|
+
return STATUS_ALIASES[key] ?? key;
|
|
7175
|
+
}
|
|
7176
|
+
function normalizePriorityLevel(level) {
|
|
7177
|
+
if (level === null || level === void 0 || level === "") return null;
|
|
7178
|
+
return Math.max(0, Math.min(PRIORITY_URGENT, Math.trunc(Number(level) || 0)));
|
|
7179
|
+
}
|
|
7180
|
+
function statusIcon(status, options = {}) {
|
|
7181
|
+
const { indicator, tone } = resolveStatusGlyph(status, options ?? {});
|
|
7182
|
+
const marker = (
|
|
7183
|
+
/** @type {HTMLSpanElement} */
|
|
7184
|
+
h("span", {
|
|
7185
|
+
class: "zx-status-icon",
|
|
7186
|
+
dataset: { indicator, tone }
|
|
7187
|
+
})
|
|
7188
|
+
);
|
|
7189
|
+
if (indicator === "done") marker.append(icon("check", { size: 8 }));
|
|
7190
|
+
if (indicator === "canceled") marker.append(icon("x", { size: 7 }));
|
|
7191
|
+
return name(marker, options?.label);
|
|
7192
|
+
}
|
|
7193
|
+
function priorityIcon(level, options = {}) {
|
|
7194
|
+
const normalized = normalizePriorityLevel(level);
|
|
7195
|
+
const glyph = (
|
|
7196
|
+
/** @type {HTMLSpanElement} */
|
|
7197
|
+
h("span", {
|
|
7198
|
+
class: "zx-priority-icon",
|
|
7199
|
+
dataset: { level: normalized === null ? "none" : normalized }
|
|
7200
|
+
}, normalized === PRIORITY_URGENT ? null : Array.from({ length: PRIORITY_URGENT }, (_, index) => h("span", {
|
|
7201
|
+
dataset: { filled: String(normalized !== null && index <= normalized) }
|
|
7202
|
+
})))
|
|
7203
|
+
);
|
|
7204
|
+
return name(glyph, options?.label);
|
|
7205
|
+
}
|
|
7206
|
+
function name(glyph, label) {
|
|
7207
|
+
const text3 = label == null ? "" : String(label).trim();
|
|
7208
|
+
if (text3) {
|
|
7209
|
+
glyph.setAttribute("role", "img");
|
|
7210
|
+
glyph.setAttribute("aria-label", text3);
|
|
7211
|
+
} else {
|
|
7212
|
+
glyph.setAttribute("aria-hidden", "true");
|
|
7213
|
+
}
|
|
7214
|
+
return glyph;
|
|
7215
|
+
}
|
|
7216
|
+
|
|
7217
|
+
// src/components/select/select.js
|
|
7218
|
+
var PRIORITY_KEYS = [
|
|
7219
|
+
"priority.lowest",
|
|
7220
|
+
"priority.low",
|
|
7221
|
+
"priority.normal",
|
|
7222
|
+
"priority.high",
|
|
7223
|
+
"priority.highest"
|
|
7224
|
+
];
|
|
7225
|
+
var PRIORITY_FALLBACKS = ["Lowest", "Low", "Medium", "High", "Highest"];
|
|
6579
7226
|
var Select = class _Select extends Component {
|
|
6580
7227
|
static cssName = "select";
|
|
6581
7228
|
/** @type {SelectOptions} */
|
|
@@ -6594,6 +7241,7 @@ var Select = class _Select extends Component {
|
|
|
6594
7241
|
value: null,
|
|
6595
7242
|
disabled: false,
|
|
6596
7243
|
placeholder: "",
|
|
7244
|
+
label: "",
|
|
6597
7245
|
clearable: false,
|
|
6598
7246
|
filter: false,
|
|
6599
7247
|
searchKeys: null,
|
|
@@ -6621,6 +7269,7 @@ var Select = class _Select extends Component {
|
|
|
6621
7269
|
this._createdRoot = false;
|
|
6622
7270
|
this._root = null;
|
|
6623
7271
|
this._snapshot = null;
|
|
7272
|
+
this._pointerModality = false;
|
|
6624
7273
|
this._createdRoot = this.el === null;
|
|
6625
7274
|
const root = (
|
|
6626
7275
|
/** @type {HTMLElement} */
|
|
@@ -6635,6 +7284,7 @@ var Select = class _Select extends Component {
|
|
|
6635
7284
|
class: "zx-select__input",
|
|
6636
7285
|
type: "text",
|
|
6637
7286
|
role: "combobox",
|
|
7287
|
+
ariaLabel: String(this.options.label || this.options.placeholder || "Select"),
|
|
6638
7288
|
autocomplete: "off",
|
|
6639
7289
|
spellcheck: false,
|
|
6640
7290
|
ariaExpanded: "false",
|
|
@@ -6708,10 +7358,29 @@ var Select = class _Select extends Component {
|
|
|
6708
7358
|
);
|
|
6709
7359
|
this.listen(input, "click", () => this.open());
|
|
6710
7360
|
this.listen(input, "input", () => this._onInput());
|
|
6711
|
-
this.listen(input, "keydown", (event) =>
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
7361
|
+
this.listen(input, "keydown", (event) => {
|
|
7362
|
+
if (!isModifierKey(
|
|
7363
|
+
/** @type {KeyboardEvent} */
|
|
7364
|
+
event
|
|
7365
|
+
)) root.removeAttribute("data-focus-origin");
|
|
7366
|
+
this._onKeydown(
|
|
7367
|
+
/** @type {KeyboardEvent} */
|
|
7368
|
+
event
|
|
7369
|
+
);
|
|
7370
|
+
});
|
|
7371
|
+
this.listen(input, "focus", () => {
|
|
7372
|
+
if (this._pointerModality && /** @type {HTMLInputElement} */
|
|
7373
|
+
input.readOnly) {
|
|
7374
|
+
root.setAttribute("data-focus-origin", "pointer");
|
|
7375
|
+
} else root.removeAttribute("data-focus-origin");
|
|
7376
|
+
});
|
|
7377
|
+
this.listen(input, "blur", () => root.removeAttribute("data-focus-origin"));
|
|
7378
|
+
this.listen(document, "keydown", (event) => {
|
|
7379
|
+
if (!isModifierKey(
|
|
7380
|
+
/** @type {KeyboardEvent} */
|
|
7381
|
+
event
|
|
7382
|
+
)) this._pointerModality = false;
|
|
7383
|
+
}, { capture: true });
|
|
6715
7384
|
this.listen(toggle, "click", () => {
|
|
6716
7385
|
this.focus();
|
|
6717
7386
|
if (this._open) this.close();
|
|
@@ -6724,6 +7393,7 @@ var Select = class _Select extends Component {
|
|
|
6724
7393
|
this.listen(panel, "pointerdown", (event) => event.preventDefault());
|
|
6725
7394
|
this.listen(panel, "click", (event) => this._onOptionClick(event));
|
|
6726
7395
|
this.listen(document, "pointerdown", (event) => {
|
|
7396
|
+
this._pointerModality = true;
|
|
6727
7397
|
if (this._open && !root.contains(
|
|
6728
7398
|
/** @type {Node} */
|
|
6729
7399
|
event.target
|
|
@@ -6874,29 +7544,43 @@ var Select = class _Select extends Component {
|
|
|
6874
7544
|
return this;
|
|
6875
7545
|
}
|
|
6876
7546
|
/**
|
|
6877
|
-
* Creates the five-level priority preset
|
|
7547
|
+
* Creates the five-level priority preset: values 0 (lowest) to 4 (highest), each drawn as grey
|
|
7548
|
+
* signal bars filled to its level, except the highest, which is the one coloured level — a
|
|
7549
|
+
* danger square with an exclamation mark. A "No priority" row (value null, a row of dashes)
|
|
7550
|
+
* heads the list and labels the empty control; `clearable: false` removes it.
|
|
6878
7551
|
* @param {Element|string|null} target Component target.
|
|
6879
|
-
* @param {SelectOptions} [options={}] Select overrides other than
|
|
7552
|
+
* @param {SelectOptions} [options={}] Select overrides other than items and renderers.
|
|
7553
|
+
* `clearable` defaults to true here; `noneLabel` and `placeholder` default to the
|
|
7554
|
+
* `priority.none` message ("No priority").
|
|
6880
7555
|
* @returns {Select}
|
|
6881
7556
|
*/
|
|
6882
7557
|
static priority(target, options = {}) {
|
|
6883
7558
|
const requestedValue = options.value ?? null;
|
|
6884
|
-
const
|
|
7559
|
+
const clearable = options.clearable ?? true;
|
|
7560
|
+
let select = null;
|
|
7561
|
+
const noneLabel = () => options.noneLabel ?? (select ? select._message("priority.none", "No priority") : "No priority");
|
|
7562
|
+
select = new _Select(target, {
|
|
6885
7563
|
...options,
|
|
7564
|
+
clearable,
|
|
6886
7565
|
value: null,
|
|
6887
7566
|
items: [],
|
|
6888
7567
|
renderItem(item) {
|
|
6889
7568
|
return priorityContent(item, true);
|
|
6890
7569
|
},
|
|
7570
|
+
renderNone: options.renderNone ?? (() => priorityContent({ level: null, name: noneLabel() }, true)),
|
|
6891
7571
|
renderValueAdornment(item) {
|
|
6892
7572
|
return priorityIndicator(item.level);
|
|
6893
7573
|
}
|
|
6894
7574
|
});
|
|
7575
|
+
if (clearable && !options.placeholder) {
|
|
7576
|
+
select.refs.input.placeholder = noneLabel();
|
|
7577
|
+
}
|
|
7578
|
+
const preset = select;
|
|
6895
7579
|
select.setItems(PRIORITY_KEYS.map((key, level) => {
|
|
6896
|
-
let
|
|
6897
|
-
if (
|
|
6898
|
-
else if (level !== 2)
|
|
6899
|
-
return { ID: level, name, level };
|
|
7580
|
+
let name2 = level === 2 ? preset.msg("priority.medium") : key;
|
|
7581
|
+
if (name2 === "priority.medium") name2 = preset._message(key, PRIORITY_FALLBACKS[level]);
|
|
7582
|
+
else if (level !== 2) name2 = preset._message(key, PRIORITY_FALLBACKS[level]);
|
|
7583
|
+
return { ID: level, name: name2, level };
|
|
6900
7584
|
}));
|
|
6901
7585
|
select.set(requestedValue, { silent: true });
|
|
6902
7586
|
return select;
|
|
@@ -6957,10 +7641,10 @@ var Select = class _Select extends Component {
|
|
|
6957
7641
|
const value = readSelectItem(item, iconKey);
|
|
6958
7642
|
if (value && typeof value === "object" && typeof value.nodeType === "number") return value.cloneNode(true);
|
|
6959
7643
|
if (typeof value !== "string" || !value) return null;
|
|
6960
|
-
const color = readSelectItem(item, colorKey);
|
|
7644
|
+
const color = itemColor(readSelectItem(item, colorKey));
|
|
6961
7645
|
return h("span", {
|
|
6962
7646
|
class: "zx-select__entity-glyph",
|
|
6963
|
-
style:
|
|
7647
|
+
style: color ? { "--zx-select-entity-color": color } : null,
|
|
6964
7648
|
ariaHidden: "true"
|
|
6965
7649
|
}, icon(value, { size: 14 }));
|
|
6966
7650
|
};
|
|
@@ -7492,24 +8176,20 @@ function priorityContent(item, label) {
|
|
|
7492
8176
|
);
|
|
7493
8177
|
}
|
|
7494
8178
|
function priorityIndicator(level) {
|
|
7495
|
-
const
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
dataset: { filled: String(index <= normalized) }
|
|
7502
|
-
})));
|
|
8179
|
+
const glyph = priorityIcon(
|
|
8180
|
+
/** @type {number|null} */
|
|
8181
|
+
normalizePriorityLevel(level)
|
|
8182
|
+
);
|
|
8183
|
+
glyph.classList.add("zx-select__priority-icon");
|
|
8184
|
+
return glyph;
|
|
7503
8185
|
}
|
|
7504
8186
|
function normalizeStatusItem(input) {
|
|
7505
8187
|
if (!input || typeof input !== "object" || input.ID == null || input.name == null) return null;
|
|
7506
|
-
const indicators = ["dotted", "ring", "progress", "review", "ready", "waiting", "done", "canceled", "duplicate"];
|
|
7507
|
-
const tones = ["muted", "neutral", "warning", "info", "accent", "success", "danger"];
|
|
7508
8188
|
return {
|
|
7509
8189
|
...input,
|
|
7510
8190
|
name: String(input.name),
|
|
7511
|
-
indicator:
|
|
7512
|
-
tone:
|
|
8191
|
+
indicator: STATUS_INDICATORS.includes(String(input.indicator)) ? String(input.indicator) : "ring",
|
|
8192
|
+
tone: STATUS_TONES.includes(String(input.tone)) ? String(input.tone) : "muted",
|
|
7513
8193
|
description: input.description == null ? "" : String(input.description),
|
|
7514
8194
|
shortcut: input.shortcut == null ? "" : String(input.shortcut)
|
|
7515
8195
|
};
|
|
@@ -7529,21 +8209,18 @@ function statusContent(item) {
|
|
|
7529
8209
|
);
|
|
7530
8210
|
}
|
|
7531
8211
|
function statusIndicator(item) {
|
|
7532
|
-
const
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
dataset: { indicator, tone: String(item.tone ?? "muted") },
|
|
7536
|
-
ariaHidden: "true"
|
|
7537
|
-
});
|
|
7538
|
-
if (indicator === "done") marker.append(icon("check", { size: 8 }));
|
|
7539
|
-
if (indicator === "canceled") marker.append(icon("x", { size: 7 }));
|
|
7540
|
-
return marker;
|
|
8212
|
+
const glyph = statusIcon({ indicator: item.indicator ?? "ring", tone: item.tone ?? "muted" });
|
|
8213
|
+
glyph.classList.add("zx-select__status-indicator");
|
|
8214
|
+
return glyph;
|
|
7541
8215
|
}
|
|
7542
8216
|
function readItem(item, reader) {
|
|
7543
8217
|
if (typeof reader === "function") return reader(item);
|
|
7544
8218
|
if (item === null || typeof item !== "object") return item;
|
|
7545
8219
|
return item[reader];
|
|
7546
8220
|
}
|
|
8221
|
+
function isModifierKey(event) {
|
|
8222
|
+
return ["Shift", "Control", "Alt", "Meta", "CapsLock"].includes(event.key) || event.ctrlKey || event.metaKey;
|
|
8223
|
+
}
|
|
7547
8224
|
function isPrintable(event) {
|
|
7548
8225
|
return event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
7549
8226
|
}
|
|
@@ -7553,8 +8230,12 @@ function registerSelectFieldAdapter() {
|
|
|
7553
8230
|
Field.register("zxselect", (field, options) => {
|
|
7554
8231
|
const props = options.props ?? {};
|
|
7555
8232
|
const preset = props.preset;
|
|
7556
|
-
const selectOptions = { ...props, value: options.value };
|
|
8233
|
+
const selectOptions = { ...props, value: options.value, label: options.label || props.label, placeholder: props.placeholder ?? options.placeholder };
|
|
8234
|
+
field.listen(field.el, "click", (event) => {
|
|
8235
|
+
if (event.target.closest?.(".zx-field__label")) field.adapter.focus();
|
|
8236
|
+
});
|
|
7557
8237
|
delete selectOptions.preset;
|
|
8238
|
+
if (preset === "priority" && props.clearable === void 0) selectOptions.clearable = !options.required;
|
|
7558
8239
|
const select = field.own(preset === "priority" ? Select.priority(null, selectOptions) : preset === "status" ? Select.status(null, selectOptions) : new Select(null, selectOptions));
|
|
7559
8240
|
field.listen(select.el, "change", (event) => event.stopImmediatePropagation());
|
|
7560
8241
|
select.on("change", (event) => field.emit("change", { value: event.detail.value }));
|
|
@@ -7804,7 +8485,7 @@ var Slider = class extends Component {
|
|
|
7804
8485
|
const label = typeof mark === "number" ? this._format(value) : String(mark.label ?? this._format(value));
|
|
7805
8486
|
element.append(h("span", {
|
|
7806
8487
|
class: "zx-slider__mark",
|
|
7807
|
-
style: { "--zx-slider-mark":
|
|
8488
|
+
style: { "--zx-slider-mark": String(this._ratio(value)) }
|
|
7808
8489
|
}, label));
|
|
7809
8490
|
}
|
|
7810
8491
|
return element;
|
|
@@ -7930,6 +8611,29 @@ function registerSliderFieldAdapter() {
|
|
|
7930
8611
|
});
|
|
7931
8612
|
}
|
|
7932
8613
|
|
|
8614
|
+
// src/components/badge/badge.js
|
|
8615
|
+
var KINDS = Object.freeze(["neutral", "accent", "success", "warning", "danger", "info"]);
|
|
8616
|
+
var VARIANTS = Object.freeze(["soft", "solid", "outline"]);
|
|
8617
|
+
var BADGE_TONES = Object.freeze(["blue", "teal", "green", "amber", "orange", "red", "pink", "violet", "slate"]);
|
|
8618
|
+
var defaults = Object.freeze({
|
|
8619
|
+
label: "",
|
|
8620
|
+
icon: null,
|
|
8621
|
+
kind: "neutral",
|
|
8622
|
+
tone: null,
|
|
8623
|
+
variant: "soft",
|
|
8624
|
+
size: "md",
|
|
8625
|
+
dot: false
|
|
8626
|
+
});
|
|
8627
|
+
function normalizeBadgeTone(value) {
|
|
8628
|
+
return BADGE_TONES.includes(
|
|
8629
|
+
/** @type {BadgeTone} */
|
|
8630
|
+
value
|
|
8631
|
+
) ? (
|
|
8632
|
+
/** @type {BadgeTone} */
|
|
8633
|
+
value
|
|
8634
|
+
) : null;
|
|
8635
|
+
}
|
|
8636
|
+
|
|
7933
8637
|
// src/components/tag-picker/tag-picker.js
|
|
7934
8638
|
var TagPicker = class extends Component {
|
|
7935
8639
|
static cssName = "tag-picker";
|
|
@@ -7941,6 +8645,7 @@ var TagPicker = class extends Component {
|
|
|
7941
8645
|
labelKey: "name",
|
|
7942
8646
|
iconKey: "icon",
|
|
7943
8647
|
colorKey: "color",
|
|
8648
|
+
toneKey: "tone",
|
|
7944
8649
|
searchKeys: null,
|
|
7945
8650
|
filter: "local",
|
|
7946
8651
|
minQuery: 0,
|
|
@@ -8281,11 +8986,12 @@ var TagPicker = class extends Component {
|
|
|
8281
8986
|
_renderTags() {
|
|
8282
8987
|
const tags = this._selected.map((item) => {
|
|
8283
8988
|
const label = this._labelOf(item);
|
|
8284
|
-
const
|
|
8989
|
+
const tone = this._toneOf(item);
|
|
8990
|
+
const color = tone ? null : this._colorOf(item);
|
|
8285
8991
|
const content = this.options.renderTag ? this.options.renderTag(item) : [this._iconOf(item), h("span", { class: "zx-tag-picker__tag-label" }, label)];
|
|
8286
8992
|
const tag = h("span", {
|
|
8287
8993
|
class: "zx-tag-picker__tag",
|
|
8288
|
-
dataset: { colored: String(Boolean(color)) },
|
|
8994
|
+
dataset: { colored: String(Boolean(color)), tone: tone ?? void 0 },
|
|
8289
8995
|
style: color ? { "--zx-tag-color": color } : null
|
|
8290
8996
|
}, content);
|
|
8291
8997
|
if (!this._readonly && !this._disabled) {
|
|
@@ -8654,16 +9360,22 @@ var TagPicker = class extends Component {
|
|
|
8654
9360
|
value.cloneNode(true)
|
|
8655
9361
|
) : typeof value === "string" && value.trim() ? icon(value, { size: 12 }) : null;
|
|
8656
9362
|
if (!visual) return null;
|
|
9363
|
+
const tone = this._toneOf(item);
|
|
9364
|
+
const color = tone ? null : this._colorOf(item);
|
|
8657
9365
|
return h("span", {
|
|
8658
9366
|
class: "zx-tag-picker__visual",
|
|
8659
|
-
|
|
9367
|
+
dataset: { tone: tone ?? void 0 },
|
|
9368
|
+
style: color ? { "--zx-tag-color": color } : null,
|
|
8660
9369
|
ariaHidden: "true"
|
|
8661
9370
|
}, visual);
|
|
8662
9371
|
}
|
|
8663
9372
|
/** @param {unknown} item @returns {string|null} */
|
|
8664
9373
|
_colorOf(item) {
|
|
8665
|
-
|
|
8666
|
-
|
|
9374
|
+
return itemColor(this._readItem(item, this.options.colorKey));
|
|
9375
|
+
}
|
|
9376
|
+
/** @param {unknown} item @returns {string|null} */
|
|
9377
|
+
_toneOf(item) {
|
|
9378
|
+
return normalizeBadgeTone(this._readItem(item, this.options.toneKey));
|
|
8667
9379
|
}
|
|
8668
9380
|
/** @param {unknown} item @param {unknown} reader @returns {unknown} */
|
|
8669
9381
|
_readItem(item, reader) {
|
|
@@ -8793,7 +9505,7 @@ var Timebox = class extends Component {
|
|
|
8793
9505
|
const content = h("div", {
|
|
8794
9506
|
class: "zx-timebox__content",
|
|
8795
9507
|
role: "group",
|
|
8796
|
-
ariaLabel: this.options.seconds ? "Duration in hours, minutes, and seconds" : "Duration in hours and minutes"
|
|
9508
|
+
ariaLabel: this.options.seconds ? this._message("timebox.durationWithSeconds", "Duration in hours, minutes, and seconds") : this._message("timebox.duration", "Duration in hours and minutes")
|
|
8797
9509
|
});
|
|
8798
9510
|
this._content = content;
|
|
8799
9511
|
if (this.options.signed) {
|
|
@@ -8801,7 +9513,7 @@ var Timebox = class extends Component {
|
|
|
8801
9513
|
ref: "sign",
|
|
8802
9514
|
class: "zx-timebox__sign",
|
|
8803
9515
|
type: "button",
|
|
8804
|
-
ariaLabel: "Toggle duration sign",
|
|
9516
|
+
ariaLabel: this._message("timebox.toggleSign", "Toggle duration sign"),
|
|
8805
9517
|
ariaPressed: "false"
|
|
8806
9518
|
}, "+"));
|
|
8807
9519
|
this.listen(this.refs.sign, "click", () => {
|
|
@@ -8811,12 +9523,12 @@ var Timebox = class extends Component {
|
|
|
8811
9523
|
this._emitChange();
|
|
8812
9524
|
});
|
|
8813
9525
|
}
|
|
8814
|
-
this._addSegment(content, "hours", "Hours", false);
|
|
9526
|
+
this._addSegment(content, "hours", this._message("timebox.hours", "Hours"), false);
|
|
8815
9527
|
content.append(h("span", { class: "zx-timebox__separator", ariaHidden: "true" }, ":"));
|
|
8816
|
-
this._addSegment(content, "minutes", "Minutes", true);
|
|
9528
|
+
this._addSegment(content, "minutes", this._message("timebox.minutes", "Minutes"), true);
|
|
8817
9529
|
if (this.options.seconds) {
|
|
8818
9530
|
content.append(h("span", { class: "zx-timebox__separator", ariaHidden: "true" }, ":"));
|
|
8819
|
-
this._addSegment(content, "seconds", "Seconds", true);
|
|
9531
|
+
this._addSegment(content, "seconds", this._message("timebox.seconds", "Seconds"), true);
|
|
8820
9532
|
}
|
|
8821
9533
|
root.append(content);
|
|
8822
9534
|
this.set(this.options.value, this.options.unit, { silent: true });
|
|
@@ -8876,7 +9588,7 @@ var Timebox = class extends Component {
|
|
|
8876
9588
|
super.destroy();
|
|
8877
9589
|
}
|
|
8878
9590
|
/** @param {HTMLElement} parent @param {'hours'|'minutes'|'seconds'} name @param {string} label @param {boolean} bounded @returns {void} */
|
|
8879
|
-
_addSegment(parent,
|
|
9591
|
+
_addSegment(parent, name2, label, bounded) {
|
|
8880
9592
|
const input = h("input", {
|
|
8881
9593
|
class: "zx-timebox__segment",
|
|
8882
9594
|
type: "text",
|
|
@@ -8884,13 +9596,13 @@ var Timebox = class extends Component {
|
|
|
8884
9596
|
autocomplete: "off",
|
|
8885
9597
|
ariaLabel: label,
|
|
8886
9598
|
maxLength: bounded ? 2 : null,
|
|
8887
|
-
dataset: { segment:
|
|
9599
|
+
dataset: { segment: name2, bounded: String(bounded) }
|
|
8888
9600
|
});
|
|
8889
9601
|
this._inputs.push(input);
|
|
8890
9602
|
parent.append(input);
|
|
8891
9603
|
this.listen(input, "focus", () => input.select());
|
|
8892
9604
|
this.listen(input, "input", () => {
|
|
8893
|
-
if (
|
|
9605
|
+
if (name2 === "hours" && this.options.signed && input.value.trim().startsWith("-")) {
|
|
8894
9606
|
this._parts.negative = true;
|
|
8895
9607
|
}
|
|
8896
9608
|
const digits = input.value.replace(/\D/g, "");
|
|
@@ -8908,9 +9620,9 @@ var Timebox = class extends Component {
|
|
|
8908
9620
|
_readParts() {
|
|
8909
9621
|
const parts = { ...this._parts };
|
|
8910
9622
|
for (const input of this._inputs) {
|
|
8911
|
-
const
|
|
9623
|
+
const name2 = input.dataset.segment;
|
|
8912
9624
|
const maximum = input.dataset.bounded === "true" ? 59 : Number.MAX_SAFE_INTEGER;
|
|
8913
|
-
parts[
|
|
9625
|
+
parts[name2] = Math.max(0, Math.min(maximum, Math.trunc(finiteNumber2(input.value))));
|
|
8914
9626
|
}
|
|
8915
9627
|
return parts;
|
|
8916
9628
|
}
|
|
@@ -8923,8 +9635,8 @@ var Timebox = class extends Component {
|
|
|
8923
9635
|
/** @returns {void} */
|
|
8924
9636
|
_writeParts() {
|
|
8925
9637
|
for (const input of this._inputs) {
|
|
8926
|
-
const
|
|
8927
|
-
input.value =
|
|
9638
|
+
const name2 = input.dataset.segment;
|
|
9639
|
+
input.value = name2 === "hours" ? String(this._parts[name2]) : pad3(this._parts[name2]);
|
|
8928
9640
|
}
|
|
8929
9641
|
if (this.refs.sign) {
|
|
8930
9642
|
this.refs.sign.textContent = this._parts.negative ? "-" : "+";
|
|
@@ -8942,6 +9654,16 @@ var Timebox = class extends Component {
|
|
|
8942
9654
|
_emitChange() {
|
|
8943
9655
|
this.emit("change", { value: this.get(this.options.unit) });
|
|
8944
9656
|
}
|
|
9657
|
+
/**
|
|
9658
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
9659
|
+
* @param {string} key Message key.
|
|
9660
|
+
* @param {string} fallback English default.
|
|
9661
|
+
* @returns {string}
|
|
9662
|
+
*/
|
|
9663
|
+
_message(key, fallback) {
|
|
9664
|
+
const message = this.msg(key);
|
|
9665
|
+
return message === key ? fallback : message;
|
|
9666
|
+
}
|
|
8945
9667
|
};
|
|
8946
9668
|
function finiteNumber2(value) {
|
|
8947
9669
|
const number = Number(value);
|
|
@@ -9103,7 +9825,7 @@ function snapshot(element) {
|
|
|
9103
9825
|
}
|
|
9104
9826
|
function restore(element, state) {
|
|
9105
9827
|
for (const attribute of Array.from(element.attributes)) element.removeAttribute(attribute.name);
|
|
9106
|
-
for (const [
|
|
9828
|
+
for (const [name2, value] of state.attributes) element.setAttribute(name2, value);
|
|
9107
9829
|
element.replaceChildren(...state.children);
|
|
9108
9830
|
}
|
|
9109
9831
|
|
|
@@ -9154,14 +9876,14 @@ var ValueList = class extends Component {
|
|
|
9154
9876
|
this._list = h("ul", {
|
|
9155
9877
|
class: "zx-value-list__list",
|
|
9156
9878
|
role: "listbox",
|
|
9157
|
-
ariaLabel: "Values",
|
|
9879
|
+
ariaLabel: this._message("valueList.values", "Values"),
|
|
9158
9880
|
ariaOrientation: "horizontal"
|
|
9159
9881
|
});
|
|
9160
9882
|
this._input = h("input", {
|
|
9161
9883
|
class: "zx-value-list__input",
|
|
9162
9884
|
type: "text",
|
|
9163
9885
|
placeholder: String(this.options.placeholder ?? ""),
|
|
9164
|
-
ariaLabel: "Add value",
|
|
9886
|
+
ariaLabel: this._message("valueList.add", "Add value"),
|
|
9165
9887
|
ariaDescribedby: instructionsId
|
|
9166
9888
|
});
|
|
9167
9889
|
this._status = h("div", {
|
|
@@ -9172,7 +9894,10 @@ var ValueList = class extends Component {
|
|
|
9172
9894
|
this._instructions = h("span", {
|
|
9173
9895
|
class: "zx-value-list__instructions",
|
|
9174
9896
|
id: instructionsId
|
|
9175
|
-
},
|
|
9897
|
+
}, this._message(
|
|
9898
|
+
"valueList.instructions",
|
|
9899
|
+
"Press Enter to add. Focus a value and press Ctrl plus Left or Right to reorder."
|
|
9900
|
+
));
|
|
9176
9901
|
this._ownedNodes.push(this._list, this._input, this._status, this._instructions);
|
|
9177
9902
|
root.append(this._list, this._input, this._status, this._instructions);
|
|
9178
9903
|
this.listen(this._input, "keydown", (event) => this._handleInputKeydown(event));
|
|
@@ -9221,13 +9946,13 @@ var ValueList = class extends Component {
|
|
|
9221
9946
|
const normalized = String(value ?? "").trim();
|
|
9222
9947
|
if (!normalized) return false;
|
|
9223
9948
|
if (this.options.unique && this._values.includes(normalized)) {
|
|
9224
|
-
this._showError("This value already exists.");
|
|
9949
|
+
this._showError(this._message("valueList.duplicate", "This value already exists."));
|
|
9225
9950
|
return false;
|
|
9226
9951
|
}
|
|
9227
9952
|
if (typeof this.options.validate === "function") {
|
|
9228
9953
|
const result = this.options.validate(normalized);
|
|
9229
9954
|
if (result !== true) {
|
|
9230
|
-
this._showError(typeof result === "string" ? result : "This value is not valid.");
|
|
9955
|
+
this._showError(typeof result === "string" ? result : this._message("valueList.invalid", "This value is not valid."));
|
|
9231
9956
|
return false;
|
|
9232
9957
|
}
|
|
9233
9958
|
}
|
|
@@ -9292,7 +10017,7 @@ var ValueList = class extends Component {
|
|
|
9292
10017
|
draggable: Boolean(this.options.sortable) && !this._disabled,
|
|
9293
10018
|
ariaSelected: "false",
|
|
9294
10019
|
ariaDisabled: String(this._disabled),
|
|
9295
|
-
ariaLabel: this.options.deletable ?
|
|
10020
|
+
ariaLabel: this.options.deletable ? this._message("valueList.removable", "%1. Press Delete to remove.", value) : value,
|
|
9296
10021
|
dataset: { index }
|
|
9297
10022
|
}, h("span", { class: "zx-value-list__value" }, value), this.options.deletable ? h("span", {
|
|
9298
10023
|
class: "zx-value-list__remove",
|
|
@@ -9388,6 +10113,17 @@ var ValueList = class extends Component {
|
|
|
9388
10113
|
this._status.textContent = message;
|
|
9389
10114
|
this._input.setAttribute("aria-invalid", "true");
|
|
9390
10115
|
}
|
|
10116
|
+
/**
|
|
10117
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
10118
|
+
* @param {string} key Message key.
|
|
10119
|
+
* @param {string} fallback Built-in text, with `%1`-style placeholders.
|
|
10120
|
+
* @param {...unknown} args Interpolation values.
|
|
10121
|
+
* @returns {string}
|
|
10122
|
+
*/
|
|
10123
|
+
_message(key, fallback, ...args) {
|
|
10124
|
+
const message = this.msg(key, ...args);
|
|
10125
|
+
return message === key ? printf(fallback, args) : message;
|
|
10126
|
+
}
|
|
9391
10127
|
/** @returns {void} */
|
|
9392
10128
|
destroy() {
|
|
9393
10129
|
for (const node of this._ownedNodes ?? []) node.remove();
|
|
@@ -9432,8 +10168,8 @@ var ORDER = (
|
|
|
9432
10168
|
function breakpointOf(width) {
|
|
9433
10169
|
const value = Number(width);
|
|
9434
10170
|
if (!Number.isFinite(value)) return "xs";
|
|
9435
|
-
for (const
|
|
9436
|
-
if (value >= breakpoints[
|
|
10171
|
+
for (const name2 of ORDER) {
|
|
10172
|
+
if (value >= breakpoints[name2]) return name2;
|
|
9437
10173
|
}
|
|
9438
10174
|
return "xs";
|
|
9439
10175
|
}
|
|
@@ -9449,7 +10185,7 @@ function onBreakpoint(handler, options = {}) {
|
|
|
9449
10185
|
/** @type {Element} */
|
|
9450
10186
|
target
|
|
9451
10187
|
) : null;
|
|
9452
|
-
let
|
|
10188
|
+
let name2 = (
|
|
9453
10189
|
/** @type {BreakpointName|null} */
|
|
9454
10190
|
null
|
|
9455
10191
|
);
|
|
@@ -9461,9 +10197,9 @@ function onBreakpoint(handler, options = {}) {
|
|
|
9461
10197
|
const width = measure();
|
|
9462
10198
|
if (element && width === 0) return;
|
|
9463
10199
|
const next = breakpointOf(width);
|
|
9464
|
-
if (next ===
|
|
9465
|
-
|
|
9466
|
-
handler(
|
|
10200
|
+
if (next === name2) return;
|
|
10201
|
+
name2 = next;
|
|
10202
|
+
handler(name2, width);
|
|
9467
10203
|
};
|
|
9468
10204
|
update();
|
|
9469
10205
|
let frame = 0;
|
|
@@ -9481,7 +10217,7 @@ function onBreakpoint(handler, options = {}) {
|
|
|
9481
10217
|
globalThis.addEventListener?.("resize", update, { passive: true });
|
|
9482
10218
|
}
|
|
9483
10219
|
return {
|
|
9484
|
-
current: () =>
|
|
10220
|
+
current: () => name2 ?? breakpointOf(measure()),
|
|
9485
10221
|
destroy: () => {
|
|
9486
10222
|
if (destroyed) return;
|
|
9487
10223
|
destroyed = true;
|
|
@@ -9569,13 +10305,119 @@ function currencyCode(value) {
|
|
|
9569
10305
|
}
|
|
9570
10306
|
|
|
9571
10307
|
// src/core/overlay-host.js
|
|
9572
|
-
var SCOPE_SELECTOR = ".zx-scope, [data-zx-theme], [data-zx-
|
|
10308
|
+
var SCOPE_SELECTOR = ".zx-scope, [data-zx-theme], [data-zx-preset]";
|
|
9573
10309
|
function overlayHost(source = null) {
|
|
9574
10310
|
const context = source == null ? document.activeElement instanceof Element ? document.activeElement : null : resolveElement(source);
|
|
9575
10311
|
const scope2 = context?.closest?.(SCOPE_SELECTOR) ?? null;
|
|
9576
10312
|
if (!scope2 || scope2 === document.documentElement || scope2 === document.body) return document.body;
|
|
9577
10313
|
return scope2;
|
|
9578
10314
|
}
|
|
10315
|
+
function connectedOverlayHost(source = null) {
|
|
10316
|
+
if (source == null) return overlayHost(null);
|
|
10317
|
+
const context = resolveElement(source);
|
|
10318
|
+
return context?.isConnected ? overlayHost(context) : null;
|
|
10319
|
+
}
|
|
10320
|
+
|
|
10321
|
+
// src/components/loading/spinner.js
|
|
10322
|
+
var defaults2 = Object.freeze({
|
|
10323
|
+
size: "md",
|
|
10324
|
+
label: "",
|
|
10325
|
+
showLabel: false,
|
|
10326
|
+
kind: "accent"
|
|
10327
|
+
});
|
|
10328
|
+
var SIZES2 = Object.freeze({ sm: true, md: true, lg: true });
|
|
10329
|
+
function spinner(opts = {}) {
|
|
10330
|
+
const options = { ...defaults2, ...opts };
|
|
10331
|
+
const label = String(options.label ?? "");
|
|
10332
|
+
const element = (
|
|
10333
|
+
/** @type {HTMLSpanElement} */
|
|
10334
|
+
h("span", {
|
|
10335
|
+
class: "zx-spinner",
|
|
10336
|
+
dataset: {
|
|
10337
|
+
size: SIZES2[options.size] ? options.size : "md",
|
|
10338
|
+
kind: options.kind === "current" ? "current" : "accent"
|
|
10339
|
+
}
|
|
10340
|
+
}, h("span", { class: "zx-spinner__ring", ariaHidden: "true" }))
|
|
10341
|
+
);
|
|
10342
|
+
if (label) {
|
|
10343
|
+
element.setAttribute("role", "status");
|
|
10344
|
+
element.append(h("span", {
|
|
10345
|
+
class: "zx-spinner__label",
|
|
10346
|
+
dataset: { visible: options.showLabel ? "true" : null }
|
|
10347
|
+
}, label));
|
|
10348
|
+
} else {
|
|
10349
|
+
element.setAttribute("aria-hidden", "true");
|
|
10350
|
+
}
|
|
10351
|
+
return element;
|
|
10352
|
+
}
|
|
10353
|
+
|
|
10354
|
+
// src/components/button/button.js
|
|
10355
|
+
var defaults3 = Object.freeze({
|
|
10356
|
+
label: "",
|
|
10357
|
+
icon: null,
|
|
10358
|
+
kind: "default",
|
|
10359
|
+
size: "md",
|
|
10360
|
+
disabled: false
|
|
10361
|
+
});
|
|
10362
|
+
function button(opts = {}) {
|
|
10363
|
+
const options = { ...defaults3, ...opts };
|
|
10364
|
+
const element = (
|
|
10365
|
+
/** @type {HTMLButtonElement} */
|
|
10366
|
+
h("button", {
|
|
10367
|
+
class: "zx-btn",
|
|
10368
|
+
type: "button",
|
|
10369
|
+
disabled: Boolean(options.disabled),
|
|
10370
|
+
title: options.title ?? (options.shortcut ? `${options.label} (${options.shortcut.label})` : void 0),
|
|
10371
|
+
ariaKeyshortcuts: options.shortcut?.keys,
|
|
10372
|
+
dataset: {
|
|
10373
|
+
kind: normalizeKind(options.kind),
|
|
10374
|
+
size: normalizeSize(options.size)
|
|
10375
|
+
}
|
|
10376
|
+
})
|
|
10377
|
+
);
|
|
10378
|
+
if (options.icon) {
|
|
10379
|
+
element.append(icon(options.icon, { size: 16 }));
|
|
10380
|
+
}
|
|
10381
|
+
if (options.label !== "") {
|
|
10382
|
+
element.append(h("span", { class: "zx-btn__label" }, String(options.label)));
|
|
10383
|
+
}
|
|
10384
|
+
if (options.shortcut) element.append(h("kbd", { class: "zx-btn__shortcut", ariaHidden: "true" }, options.shortcut.label));
|
|
10385
|
+
if (!options.label && options.title) element.setAttribute("aria-label", options.title);
|
|
10386
|
+
if (typeof options.onclick === "function") element.onclick = options.onclick;
|
|
10387
|
+
if (options.busy) setButtonBusy(element, true);
|
|
10388
|
+
return element;
|
|
10389
|
+
}
|
|
10390
|
+
function setButtonBusy(element, busy) {
|
|
10391
|
+
if (!element.hasAttribute("data-busy-guard")) {
|
|
10392
|
+
element.setAttribute("data-busy-guard", "");
|
|
10393
|
+
element.addEventListener("click", (event) => {
|
|
10394
|
+
if (element.getAttribute("aria-busy") !== "true") return;
|
|
10395
|
+
event.preventDefault();
|
|
10396
|
+
event.stopImmediatePropagation();
|
|
10397
|
+
}, { capture: true });
|
|
10398
|
+
}
|
|
10399
|
+
element.querySelector(":scope > .zx-btn__spinner")?.remove();
|
|
10400
|
+
if (busy) {
|
|
10401
|
+
element.setAttribute("aria-busy", "true");
|
|
10402
|
+
element.setAttribute("aria-disabled", "true");
|
|
10403
|
+
const ring = spinner({ size: "sm", kind: "current" });
|
|
10404
|
+
ring.classList.add("zx-btn__spinner");
|
|
10405
|
+
element.prepend(ring);
|
|
10406
|
+
} else {
|
|
10407
|
+
element.removeAttribute("aria-busy");
|
|
10408
|
+
element.removeAttribute("aria-disabled");
|
|
10409
|
+
}
|
|
10410
|
+
return element;
|
|
10411
|
+
}
|
|
10412
|
+
function normalizeKind(value) {
|
|
10413
|
+
return ["primary", "danger", "ghost"].includes(String(value)) ? (
|
|
10414
|
+
/** @type {'primary'|'danger'|'ghost'} */
|
|
10415
|
+
value
|
|
10416
|
+
) : "default";
|
|
10417
|
+
}
|
|
10418
|
+
function normalizeSize(value) {
|
|
10419
|
+
return value === "sm" ? "sm" : "md";
|
|
10420
|
+
}
|
|
9579
10421
|
|
|
9580
10422
|
// src/components/table/sort.js
|
|
9581
10423
|
function compareStrings(left, right) {
|
|
@@ -9631,7 +10473,10 @@ var Table = class extends Component {
|
|
|
9631
10473
|
height: null,
|
|
9632
10474
|
emptyText: null,
|
|
9633
10475
|
rowClass: null,
|
|
10476
|
+
rowKind: null,
|
|
10477
|
+
rowKinds: null,
|
|
9634
10478
|
zebra: true,
|
|
10479
|
+
variant: "default",
|
|
9635
10480
|
editMode: false,
|
|
9636
10481
|
editTrigger: "double",
|
|
9637
10482
|
hierarchy: false,
|
|
@@ -9660,6 +10505,10 @@ var Table = class extends Component {
|
|
|
9660
10505
|
this._original = created ? null : snapshotTarget(root);
|
|
9661
10506
|
this._columns = normalizeTableColumns(this.options.columns);
|
|
9662
10507
|
this._data = Array.isArray(this.options.data) ? [...this.options.data] : [];
|
|
10508
|
+
this._rowKind = normalizeRowKind(this.options.rowKind);
|
|
10509
|
+
this._rowKinds = normalizeRowKinds(this.options.rowKinds);
|
|
10510
|
+
this._spanning = this._hasSpanningRow();
|
|
10511
|
+
this._sortWarned = false;
|
|
9663
10512
|
this._selected = /* @__PURE__ */ new Set();
|
|
9664
10513
|
this._selectionAnchorId = null;
|
|
9665
10514
|
this._sort = normalizeSort(this.options.sort, this._columns);
|
|
@@ -9693,6 +10542,7 @@ var Table = class extends Component {
|
|
|
9693
10542
|
}
|
|
9694
10543
|
}
|
|
9695
10544
|
this._reconcileExpanded();
|
|
10545
|
+
if (normalizeTableVariant(this.options.variant) === "plain") root.dataset.variant = "plain";
|
|
9696
10546
|
this._table = h("table", { class: "zx-table__table" });
|
|
9697
10547
|
if (this._hierarchy) this._table.setAttribute("role", "treegrid");
|
|
9698
10548
|
this._colgroup = h("colgroup", { class: "zx-table__columns" });
|
|
@@ -9976,7 +10826,7 @@ var Table = class extends Component {
|
|
|
9976
10826
|
const column = this._columns.find((candidate) => candidate.id === String(id));
|
|
9977
10827
|
const index = this.getColumnOrder().indexOf(String(id));
|
|
9978
10828
|
if (column && index >= 0) {
|
|
9979
|
-
this._columnStatus.textContent = `Moved ${column
|
|
10829
|
+
this._columnStatus.textContent = `Moved ${tableColumnName(column)} to position ${index + 1} of ${this._columns.length}.`;
|
|
9980
10830
|
}
|
|
9981
10831
|
}
|
|
9982
10832
|
return this;
|
|
@@ -10035,6 +10885,7 @@ var Table = class extends Component {
|
|
|
10035
10885
|
const row = this.getRow(id);
|
|
10036
10886
|
const target = this.getRow(targetId);
|
|
10037
10887
|
if (!row || !target || Object.is(id, targetId)) return this;
|
|
10888
|
+
if (this._isSpanningRow(row)) return this;
|
|
10038
10889
|
const next = reorderTableRows(this._data, this.options.rowId, id, targetId, position2, this._hierarchy?.parentId);
|
|
10039
10890
|
if (!next) return this;
|
|
10040
10891
|
const event = this.emit("rowmove", { row, id, target, targetId, position: position2 });
|
|
@@ -10071,6 +10922,10 @@ var Table = class extends Component {
|
|
|
10071
10922
|
/**
|
|
10072
10923
|
* Activates a column sort. Local mode stably reorders data; server mode only updates the
|
|
10073
10924
|
* header state and emits the request event.
|
|
10925
|
+
*
|
|
10926
|
+
* Inert while the data holds a spanning row: a sort would scatter the positions out of the
|
|
10927
|
+
* sections that group them, in either sort mode. The header withholds its controls for the same
|
|
10928
|
+
* reason, so nothing on screen invites the call.
|
|
10074
10929
|
* @param {string} id Column id.
|
|
10075
10930
|
* @param {TableSortDirection} [dir] Direction; omitted toggles the current column.
|
|
10076
10931
|
* @param {{silent?: boolean}} [options={}] Event options.
|
|
@@ -10079,6 +10934,13 @@ var Table = class extends Component {
|
|
|
10079
10934
|
* @fires Table#editcancel
|
|
10080
10935
|
*/
|
|
10081
10936
|
setSort(id, dir, options = {}) {
|
|
10937
|
+
if (this._spanning) {
|
|
10938
|
+
if (!this._sortWarned) {
|
|
10939
|
+
this._sortWarned = true;
|
|
10940
|
+
console.warn("[zx.Table] setSort() is inert while the data contains spanning rowKinds rows: sorting would scatter the rows out of the sections that group them.");
|
|
10941
|
+
}
|
|
10942
|
+
return this;
|
|
10943
|
+
}
|
|
10082
10944
|
this._abortEdit({ focus: false });
|
|
10083
10945
|
const column = this._columns.find((candidate) => candidate.id === id);
|
|
10084
10946
|
if (!column) throw new RangeError(`Unknown table column: ${id}`);
|
|
@@ -10130,7 +10992,7 @@ var Table = class extends Component {
|
|
|
10130
10992
|
*/
|
|
10131
10993
|
setSelection(ids) {
|
|
10132
10994
|
if (!Array.isArray(ids)) throw new TypeError("Table selection must be an array of row ids");
|
|
10133
|
-
const valid =
|
|
10995
|
+
const valid = this._selectableIds();
|
|
10134
10996
|
const next = /* @__PURE__ */ new Set();
|
|
10135
10997
|
if (this.options.selectable !== false) {
|
|
10136
10998
|
for (const id of ids) {
|
|
@@ -10242,6 +11104,7 @@ var Table = class extends Component {
|
|
|
10242
11104
|
if (!requested) return this;
|
|
10243
11105
|
const current = this._data.find((candidate) => Object.is(this._idFor(candidate), rowId));
|
|
10244
11106
|
if (current === void 0) return this;
|
|
11107
|
+
if (this._isSpanningRow(current)) return this;
|
|
10245
11108
|
const column = this._editMode === "row" && this._hiddenColumns.has(requested.id) ? this._visibleColumns().find((candidate) => resolveEditable(candidate, current) !== false) ?? null : requested;
|
|
10246
11109
|
if (!column || resolveEditable(column, current) === false) return this;
|
|
10247
11110
|
const activeColumnId = column.id;
|
|
@@ -10530,6 +11393,41 @@ var Table = class extends Component {
|
|
|
10530
11393
|
_visibleColumns() {
|
|
10531
11394
|
return this._columns.filter((column) => !this._hiddenColumns.has(column.id));
|
|
10532
11395
|
}
|
|
11396
|
+
/**
|
|
11397
|
+
* Whether a row draws as one cell across the table instead of as a record.
|
|
11398
|
+
* @param {TableRow} row Row to classify.
|
|
11399
|
+
* @returns {boolean}
|
|
11400
|
+
*/
|
|
11401
|
+
_isSpanningRow(row) {
|
|
11402
|
+
if (this._rowKind === null || this._rowKinds === null) return false;
|
|
11403
|
+
return isSpanningRow(row, this._rowKind, this._rowKinds);
|
|
11404
|
+
}
|
|
11405
|
+
/**
|
|
11406
|
+
* Whether any row in the current data — not only the rendered prefix — spans. This is what
|
|
11407
|
+
* withholds the sort controls, and the reader must not be offered a control that the next
|
|
11408
|
+
* `growBy()` would have to take away again.
|
|
11409
|
+
* @returns {boolean}
|
|
11410
|
+
*/
|
|
11411
|
+
_hasSpanningRow() {
|
|
11412
|
+
return hasSpanningRow(this._data, this._rowKind, this._rowKinds);
|
|
11413
|
+
}
|
|
11414
|
+
/**
|
|
11415
|
+
* How many cells one row occupies: every visible column plus the structural columns the table
|
|
11416
|
+
* renders beside them. Shared by the spanning cell and the empty-state cell so the two can never
|
|
11417
|
+
* disagree about the table's width.
|
|
11418
|
+
* @returns {number}
|
|
11419
|
+
*/
|
|
11420
|
+
_spanColspan() {
|
|
11421
|
+
return tableSpanColspan(this._visibleColumns().length, {
|
|
11422
|
+
selectable: this.options.selectable,
|
|
11423
|
+
rowReorder: this.options.rowReorder
|
|
11424
|
+
});
|
|
11425
|
+
}
|
|
11426
|
+
/** @returns {TableRow[]} Rendered rows that can carry a selection; spanning rows cannot. */
|
|
11427
|
+
_selectableData() {
|
|
11428
|
+
const visible = this._visibleData();
|
|
11429
|
+
return this._rowKind === null ? visible : visible.filter((row) => !this._isSpanningRow(row));
|
|
11430
|
+
}
|
|
10533
11431
|
/** @returns {HTMLElement} */
|
|
10534
11432
|
_createColumnControls() {
|
|
10535
11433
|
const list = h("div", { class: "zx-table__column-list" });
|
|
@@ -10542,7 +11440,12 @@ var Table = class extends Component {
|
|
|
10542
11440
|
const details = h(
|
|
10543
11441
|
"details",
|
|
10544
11442
|
{ class: "zx-table__column-controls" },
|
|
10545
|
-
h(
|
|
11443
|
+
h(
|
|
11444
|
+
"summary",
|
|
11445
|
+
{ class: "zx-btn", dataset: { size: "sm" } },
|
|
11446
|
+
icon("fields"),
|
|
11447
|
+
this._message("table.columns", "Columns", [])
|
|
11448
|
+
),
|
|
10546
11449
|
list
|
|
10547
11450
|
);
|
|
10548
11451
|
this._renderColumnControls();
|
|
@@ -10571,26 +11474,27 @@ var Table = class extends Component {
|
|
|
10571
11474
|
disabled: checked && visible.length === 1,
|
|
10572
11475
|
dataset: { columnId: column.id, columnAction: "toggle" }
|
|
10573
11476
|
}) : null;
|
|
10574
|
-
const
|
|
11477
|
+
const name2 = tableColumnName(column);
|
|
11478
|
+
const label = toggle ? h("label", { for: controlId }, toggle, h("span", {}, name2)) : h("span", { class: "zx-table__column-label" }, name2);
|
|
10575
11479
|
const order = this.options.columnReorder ? h(
|
|
10576
11480
|
"span",
|
|
10577
11481
|
{
|
|
10578
11482
|
class: "zx-table__column-order",
|
|
10579
11483
|
role: "group",
|
|
10580
|
-
ariaLabel:
|
|
11484
|
+
ariaLabel: this._message("table.moveColumn", "Move %1", [name2])
|
|
10581
11485
|
},
|
|
10582
11486
|
h("button", {
|
|
10583
11487
|
class: "zx-table__column-move",
|
|
10584
11488
|
type: "button",
|
|
10585
11489
|
disabled: index === 0,
|
|
10586
|
-
ariaLabel: `Move ${
|
|
11490
|
+
ariaLabel: `Move ${name2} earlier`,
|
|
10587
11491
|
dataset: { columnId: column.id, columnAction: "up" }
|
|
10588
11492
|
}, icon("chevron-up", { size: 11 })),
|
|
10589
11493
|
h("button", {
|
|
10590
11494
|
class: "zx-table__column-move",
|
|
10591
11495
|
type: "button",
|
|
10592
11496
|
disabled: index === this._columns.length - 1,
|
|
10593
|
-
ariaLabel: `Move ${
|
|
11497
|
+
ariaLabel: `Move ${name2} later`,
|
|
10594
11498
|
dataset: { columnId: column.id, columnAction: "down" }
|
|
10595
11499
|
}, icon("chevron-down", { size: 11 }))
|
|
10596
11500
|
) : null;
|
|
@@ -10641,18 +11545,18 @@ var Table = class extends Component {
|
|
|
10641
11545
|
}
|
|
10642
11546
|
/** @param {Event} event @returns {void} */
|
|
10643
11547
|
_handleColumnControlClick(event) {
|
|
10644
|
-
const
|
|
11548
|
+
const button2 = (
|
|
10645
11549
|
/** @type {Element|null} */
|
|
10646
11550
|
event.target?.closest?.(".zx-table__column-move")
|
|
10647
11551
|
);
|
|
10648
|
-
if (!
|
|
11552
|
+
if (!button2 || !this._columnList?.contains(button2)) return;
|
|
10649
11553
|
const id = (
|
|
10650
11554
|
/** @type {HTMLElement} */
|
|
10651
|
-
|
|
11555
|
+
button2.dataset.columnId
|
|
10652
11556
|
);
|
|
10653
11557
|
const action = (
|
|
10654
11558
|
/** @type {HTMLElement} */
|
|
10655
|
-
|
|
11559
|
+
button2.dataset.columnAction
|
|
10656
11560
|
);
|
|
10657
11561
|
const index = this.getColumnOrder().indexOf(String(id));
|
|
10658
11562
|
if (action === "up" && index > 0) this.moveColumn(String(id), this._columns[index - 1].id, "before");
|
|
@@ -10850,9 +11754,9 @@ var Table = class extends Component {
|
|
|
10850
11754
|
row.append(selectionHeader);
|
|
10851
11755
|
this.listen(this._selectAll, "click", () => {
|
|
10852
11756
|
if (this._selectAll.checked) {
|
|
10853
|
-
for (const dataRow of this.
|
|
11757
|
+
for (const dataRow of this._selectableData()) this._selected.add(this._idFor(dataRow));
|
|
10854
11758
|
} else {
|
|
10855
|
-
for (const dataRow of this.
|
|
11759
|
+
for (const dataRow of this._selectableData()) this._selected.delete(this._idFor(dataRow));
|
|
10856
11760
|
}
|
|
10857
11761
|
this._selectionAnchorId = null;
|
|
10858
11762
|
this._syncSelection();
|
|
@@ -10862,21 +11766,25 @@ var Table = class extends Component {
|
|
|
10862
11766
|
this._selectAll = null;
|
|
10863
11767
|
}
|
|
10864
11768
|
this._headers = /* @__PURE__ */ new Map();
|
|
11769
|
+
this._headerSpanning = this._spanning;
|
|
10865
11770
|
for (const column of this._visibleColumns()) {
|
|
10866
|
-
const th = h("th", { scope: "col" });
|
|
11771
|
+
const th = h("th", { scope: "col", dataset: { column: column.id } });
|
|
10867
11772
|
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
10868
11773
|
if (align) th.dataset.align = align;
|
|
10869
11774
|
if (column.headerTitle) th.title = column.headerTitle;
|
|
10870
|
-
|
|
10871
|
-
|
|
11775
|
+
const name2 = tableHeaderName(column);
|
|
11776
|
+
if (name2 !== null) th.setAttribute("aria-label", name2);
|
|
11777
|
+
if (column.sortable && !this._spanning) {
|
|
11778
|
+
const button2 = h("button", {
|
|
10872
11779
|
class: "zx-table__sort-button",
|
|
10873
|
-
type: "button"
|
|
11780
|
+
type: "button",
|
|
11781
|
+
ariaLabel: name2 ?? void 0
|
|
10874
11782
|
}, h("span", { class: "zx-table__header-label" }, column.label));
|
|
10875
|
-
this.listen(
|
|
11783
|
+
this.listen(button2, "click", () => {
|
|
10876
11784
|
const direction = this._sort?.id === column.id && this._sort.dir === "asc" ? "desc" : "asc";
|
|
10877
11785
|
this.setSort(column.id, direction);
|
|
10878
11786
|
});
|
|
10879
|
-
th.append(
|
|
11787
|
+
th.append(button2);
|
|
10880
11788
|
} else {
|
|
10881
11789
|
th.append(h("span", { class: "zx-table__header-label" }, column.label));
|
|
10882
11790
|
}
|
|
@@ -10889,6 +11797,8 @@ var Table = class extends Component {
|
|
|
10889
11797
|
/** @returns {void} @fires Table#editcancel */
|
|
10890
11798
|
_renderBody() {
|
|
10891
11799
|
this._abortEdit({ focus: false });
|
|
11800
|
+
this._spanning = this._hasSpanningRow();
|
|
11801
|
+
if (this._headers && this._spanning !== this._headerSpanning) this._renderHeader();
|
|
10892
11802
|
const fragment2 = document.createDocumentFragment();
|
|
10893
11803
|
this._rowMeta = /* @__PURE__ */ new WeakMap();
|
|
10894
11804
|
this._rowElements = /* @__PURE__ */ new Map();
|
|
@@ -10900,10 +11810,7 @@ var Table = class extends Component {
|
|
|
10900
11810
|
fragment2.append(h(
|
|
10901
11811
|
"tr",
|
|
10902
11812
|
{ class: "zx-table__empty-row" },
|
|
10903
|
-
h("td", {
|
|
10904
|
-
class: "zx-table__empty",
|
|
10905
|
-
colspan: this._visibleColumns().length + (this.options.selectable === "multi" ? 1 : 0) + (this.options.rowReorder ? 1 : 0)
|
|
10906
|
-
}, this._emptyContent())
|
|
11813
|
+
h("td", { class: "zx-table__empty", colspan: this._spanColspan() }, this._emptyContent())
|
|
10907
11814
|
));
|
|
10908
11815
|
} else {
|
|
10909
11816
|
this._visibleEntries().forEach((entry, visibleIndex) => {
|
|
@@ -10946,7 +11853,14 @@ var Table = class extends Component {
|
|
|
10946
11853
|
if (this._growStep) tr.setAttribute("aria-rowindex", String(tree.visibleIndex + 2));
|
|
10947
11854
|
const rowClass = typeof this.options.rowClass === "function" ? this.options.rowClass(row) : "";
|
|
10948
11855
|
if (rowClass) tr.classList.add(...String(rowClass).split(/\s+/).filter(Boolean));
|
|
10949
|
-
|
|
11856
|
+
const kind = this._rowKind === null ? null : resolveRowKind(row, this._rowKind);
|
|
11857
|
+
const kindSpec = kind === null ? null : resolveRowKindSpec(this._rowKinds, kind);
|
|
11858
|
+
const spanning = Boolean(kindSpec?.span);
|
|
11859
|
+
if (kind !== null) tr.dataset.rowKind = kind;
|
|
11860
|
+
if (kindSpec?.class) tr.classList.add(...String(kindSpec.class).split(/\s+/).filter(Boolean));
|
|
11861
|
+
if (this.options.selectable !== false && !spanning) {
|
|
11862
|
+
tr.setAttribute("aria-selected", String(this._selected.has(id)));
|
|
11863
|
+
}
|
|
10950
11864
|
if (this._hierarchy) {
|
|
10951
11865
|
tr.setAttribute("aria-level", String(tree.depth + 1));
|
|
10952
11866
|
if (tree.hasChildren) tr.setAttribute("aria-expanded", String(this._expanded.has(id)));
|
|
@@ -10955,6 +11869,23 @@ var Table = class extends Component {
|
|
|
10955
11869
|
const elements = this._rowElements.get(id) ?? [];
|
|
10956
11870
|
elements.push(tr);
|
|
10957
11871
|
this._rowElements.set(id, elements);
|
|
11872
|
+
if (spanning) {
|
|
11873
|
+
tr.dataset.span = "true";
|
|
11874
|
+
const cell = (
|
|
11875
|
+
/** @type {HTMLTableCellElement} */
|
|
11876
|
+
h("th", {
|
|
11877
|
+
class: "zx-table__section-cell",
|
|
11878
|
+
scope: "colgroup",
|
|
11879
|
+
colspan: this._spanColspan()
|
|
11880
|
+
})
|
|
11881
|
+
);
|
|
11882
|
+
const content = spanRowContent(row, kindSpec, this._visibleColumns(), index);
|
|
11883
|
+
if (content && typeof content === "object" && typeof content.nodeType === "number") {
|
|
11884
|
+
cell.append(content);
|
|
11885
|
+
} else if (content != null) cell.append(document.createTextNode(String(content)));
|
|
11886
|
+
tr.append(cell);
|
|
11887
|
+
return tr;
|
|
11888
|
+
}
|
|
10958
11889
|
if (this.options.rowReorder) {
|
|
10959
11890
|
const handle = h("button", {
|
|
10960
11891
|
class: "zx-table__row-handle",
|
|
@@ -10985,9 +11916,9 @@ var Table = class extends Component {
|
|
|
10985
11916
|
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
10986
11917
|
if (align) cell.dataset.align = align;
|
|
10987
11918
|
cell.dataset.label = column.label;
|
|
11919
|
+
cell.dataset.column = column.id;
|
|
10988
11920
|
if (column.popin === false) cell.dataset.popin = "false";
|
|
10989
11921
|
if (this._editMode !== false) {
|
|
10990
|
-
cell.dataset.column = column.id;
|
|
10991
11922
|
if (resolveEditable(column, row) !== false) {
|
|
10992
11923
|
cell.dataset.editable = "true";
|
|
10993
11924
|
cell.tabIndex = -1;
|
|
@@ -11064,7 +11995,7 @@ var Table = class extends Component {
|
|
|
11064
11995
|
);
|
|
11065
11996
|
return;
|
|
11066
11997
|
}
|
|
11067
|
-
if (isInteractiveCellContent(target)) return;
|
|
11998
|
+
if (this._editMode !== false && isInteractiveCellContent(target)) return;
|
|
11068
11999
|
if (this._editMode !== false && this._editTrigger === "single") {
|
|
11069
12000
|
const cell = target?.closest('td[data-editable="true"]');
|
|
11070
12001
|
if (cell && this._tbody.contains(cell)) {
|
|
@@ -11073,7 +12004,7 @@ var Table = class extends Component {
|
|
|
11073
12004
|
}
|
|
11074
12005
|
}
|
|
11075
12006
|
this.emit("rowclick", { ...meta, event });
|
|
11076
|
-
if (this.options.selectable === "single" && !this._selected.has(meta.id)) {
|
|
12007
|
+
if (this.options.selectable === "single" && !this._selected.has(meta.id) && !this._isSpanningRow(meta.row)) {
|
|
11077
12008
|
this._selected = /* @__PURE__ */ new Set([meta.id]);
|
|
11078
12009
|
this._selectionAnchorId = meta.id;
|
|
11079
12010
|
this._syncSelection();
|
|
@@ -11092,7 +12023,7 @@ var Table = class extends Component {
|
|
|
11092
12023
|
if (!rowElement || !this._tbody.contains(rowElement)) return;
|
|
11093
12024
|
const meta = this._rowMeta.get(rowElement);
|
|
11094
12025
|
if (!meta) return;
|
|
11095
|
-
if (isInteractiveCellContent(target)) return;
|
|
12026
|
+
if (this._editMode !== false && isInteractiveCellContent(target)) return;
|
|
11096
12027
|
if (this._editMode !== false && this._editTrigger === "double") {
|
|
11097
12028
|
const cell = target?.closest('td[data-editable="true"]');
|
|
11098
12029
|
if (cell && this._tbody.contains(cell)) {
|
|
@@ -11228,7 +12159,7 @@ var Table = class extends Component {
|
|
|
11228
12159
|
...props,
|
|
11229
12160
|
class: textarea ? "zx-table__editor-input zx-table__editor-textarea" : "zx-table__editor-input",
|
|
11230
12161
|
...textarea ? {} : { type: "text" },
|
|
11231
|
-
ariaLabel: props.ariaLabel ?? `${column
|
|
12162
|
+
ariaLabel: props.ariaLabel ?? `${tableColumnName(column)} row ${index + 1}`,
|
|
11232
12163
|
value: formatCellValue(column, value, row)
|
|
11233
12164
|
})
|
|
11234
12165
|
);
|
|
@@ -11247,7 +12178,7 @@ var Table = class extends Component {
|
|
|
11247
12178
|
const control = entry?.control;
|
|
11248
12179
|
if (!control || typeof control.focus !== "function") return;
|
|
11249
12180
|
control.focus();
|
|
11250
|
-
if (entry.type
|
|
12181
|
+
if (editorSelectsOnEntry(entry.type) && typeof control.select === "function") control.select();
|
|
11251
12182
|
}
|
|
11252
12183
|
/**
|
|
11253
12184
|
* Moves focus back onto a cell.
|
|
@@ -11416,6 +12347,7 @@ var Table = class extends Component {
|
|
|
11416
12347
|
if (row < 0 || row >= visible.length) return null;
|
|
11417
12348
|
const candidateRow = visible[row];
|
|
11418
12349
|
const candidateColumn = columns[column];
|
|
12350
|
+
if (this._isSpanningRow(candidateRow)) continue;
|
|
11419
12351
|
if (resolveEditable(candidateColumn, candidateRow) !== false) {
|
|
11420
12352
|
return {
|
|
11421
12353
|
id: this._idFor(candidateRow),
|
|
@@ -11497,6 +12429,7 @@ var Table = class extends Component {
|
|
|
11497
12429
|
const start = Math.min(anchorIndex, currentIndex);
|
|
11498
12430
|
const end = Math.max(anchorIndex, currentIndex);
|
|
11499
12431
|
for (let index = start; index <= end; index += 1) {
|
|
12432
|
+
if (this._isSpanningRow(visible[index])) continue;
|
|
11500
12433
|
const id = this._idFor(visible[index]);
|
|
11501
12434
|
if (checked) this._selected.add(id);
|
|
11502
12435
|
else this._selected.delete(id);
|
|
@@ -11515,6 +12448,7 @@ var Table = class extends Component {
|
|
|
11515
12448
|
for (const [id, rows] of this._rowElements) {
|
|
11516
12449
|
const selected = this._selected.has(id);
|
|
11517
12450
|
for (const row of rows) {
|
|
12451
|
+
if (row.hasAttribute("data-span")) continue;
|
|
11518
12452
|
row.setAttribute("aria-selected", String(selected));
|
|
11519
12453
|
const checkbox = row.querySelector(".zx-table__row-checkbox");
|
|
11520
12454
|
if (checkbox) checkbox.checked = selected;
|
|
@@ -11525,7 +12459,7 @@ var Table = class extends Component {
|
|
|
11525
12459
|
/** @returns {void} */
|
|
11526
12460
|
_syncSelectAll() {
|
|
11527
12461
|
if (!this._selectAll) return;
|
|
11528
|
-
const visible = this.
|
|
12462
|
+
const visible = this._selectableData();
|
|
11529
12463
|
const selectedRows = visible.reduce(
|
|
11530
12464
|
(count, row) => count + Number(this._selected.has(this._idFor(row))),
|
|
11531
12465
|
0
|
|
@@ -11538,13 +12472,15 @@ var Table = class extends Component {
|
|
|
11538
12472
|
_syncSortHeader() {
|
|
11539
12473
|
if (!this._headers) return;
|
|
11540
12474
|
for (const [id, header] of this._headers) {
|
|
11541
|
-
if (this._sort?.id === id)
|
|
11542
|
-
|
|
12475
|
+
if (!this._spanning && this._sort?.id === id) {
|
|
12476
|
+
header.setAttribute("aria-sort", this._sort.dir === "asc" ? "ascending" : "descending");
|
|
12477
|
+
} else header.removeAttribute("aria-sort");
|
|
11543
12478
|
}
|
|
11544
12479
|
}
|
|
11545
12480
|
/** @returns {void} */
|
|
11546
12481
|
_sortData() {
|
|
11547
|
-
|
|
12482
|
+
this._spanning = this._hasSpanningRow();
|
|
12483
|
+
if (!this._sort || this._spanning) return;
|
|
11548
12484
|
const column = this._columns.find((candidate) => candidate.id === this._sort.id);
|
|
11549
12485
|
if (!column) return;
|
|
11550
12486
|
const getValue = typeof column.sortValue === "function" ? column.sortValue : (row) => row?.[column.id];
|
|
@@ -11577,9 +12513,17 @@ var Table = class extends Component {
|
|
|
11577
12513
|
const valid = new Set(branches);
|
|
11578
12514
|
for (const id of this._expanded) if (!valid.has(id)) this._expanded.delete(id);
|
|
11579
12515
|
}
|
|
12516
|
+
/** @returns {Set<unknown>} Ids of every row in the data that may hold a selection. */
|
|
12517
|
+
_selectableIds() {
|
|
12518
|
+
const ids = /* @__PURE__ */ new Set();
|
|
12519
|
+
for (const row of this._data) {
|
|
12520
|
+
if (!this._isSpanningRow(row)) ids.add(this._idFor(row));
|
|
12521
|
+
}
|
|
12522
|
+
return ids;
|
|
12523
|
+
}
|
|
11580
12524
|
/** @returns {boolean} Whether selection changed. */
|
|
11581
12525
|
_pruneSelection() {
|
|
11582
|
-
const valid =
|
|
12526
|
+
const valid = this._selectableIds();
|
|
11583
12527
|
const previousSize = this._selected.size;
|
|
11584
12528
|
for (const id of this._selected) if (!valid.has(id)) this._selected.delete(id);
|
|
11585
12529
|
if (!valid.has(this._selectionAnchorId)) this._selectionAnchorId = null;
|
|
@@ -11599,6 +12543,34 @@ var Table = class extends Component {
|
|
|
11599
12543
|
this.emit("datachange", { rows: this.getData() });
|
|
11600
12544
|
}
|
|
11601
12545
|
};
|
|
12546
|
+
function resolveRowKind(row, rowKind) {
|
|
12547
|
+
if (rowKind == null || rowKind === "") return null;
|
|
12548
|
+
const raw2 = typeof rowKind === "function" ? rowKind(row) : row?.[rowKind];
|
|
12549
|
+
return raw2 == null ? null : String(raw2);
|
|
12550
|
+
}
|
|
12551
|
+
function resolveRowKindSpec(rowKinds, kind) {
|
|
12552
|
+
if (kind === null || rowKinds == null || typeof rowKinds !== "object") return null;
|
|
12553
|
+
if (!Object.prototype.hasOwnProperty.call(rowKinds, kind)) return null;
|
|
12554
|
+
const spec = rowKinds[kind];
|
|
12555
|
+
return spec && typeof spec === "object" ? spec : null;
|
|
12556
|
+
}
|
|
12557
|
+
function isSpanningRow(row, rowKind, rowKinds) {
|
|
12558
|
+
return Boolean(resolveRowKindSpec(rowKinds, resolveRowKind(row, rowKind))?.span);
|
|
12559
|
+
}
|
|
12560
|
+
function hasSpanningRow(rows, rowKind, rowKinds) {
|
|
12561
|
+
if (!Array.isArray(rows) || rowKind == null || rowKinds == null) return false;
|
|
12562
|
+
return rows.some((row) => isSpanningRow(row, rowKind, rowKinds));
|
|
12563
|
+
}
|
|
12564
|
+
function tableSpanColspan(columnCount, structure = {}) {
|
|
12565
|
+
const columns = Number.isFinite(Number(columnCount)) ? Math.max(0, Math.trunc(Number(columnCount))) : 0;
|
|
12566
|
+
const extras = (structure.selectable === "multi" ? 1 : 0) + (structure.rowReorder ? 1 : 0);
|
|
12567
|
+
return Math.max(1, columns + extras);
|
|
12568
|
+
}
|
|
12569
|
+
function spanRowContent(row, spec, visibleColumns, index = 0) {
|
|
12570
|
+
if (typeof spec?.render === "function") return spec.render(row, index);
|
|
12571
|
+
const first = visibleColumns?.[0];
|
|
12572
|
+
return first ? row?.[first.id] : null;
|
|
12573
|
+
}
|
|
11602
12574
|
function formatTableCell(column, row, index = 0) {
|
|
11603
12575
|
if (typeof column?.render === "function") return column.render(row, index);
|
|
11604
12576
|
const value = row?.[column?.id];
|
|
@@ -11827,9 +12799,26 @@ function normalizeHierarchy(option, columns) {
|
|
|
11827
12799
|
if (!column) return null;
|
|
11828
12800
|
return { ...option, parentId, column };
|
|
11829
12801
|
}
|
|
12802
|
+
function normalizeRowKind(option) {
|
|
12803
|
+
if (typeof option === "function") return (
|
|
12804
|
+
/** @type {(row: TableRow) => unknown} */
|
|
12805
|
+
option
|
|
12806
|
+
);
|
|
12807
|
+
return typeof option === "string" && option !== "" ? option : null;
|
|
12808
|
+
}
|
|
12809
|
+
function normalizeRowKinds(option) {
|
|
12810
|
+
if (!option || typeof option !== "object" || Array.isArray(option)) return null;
|
|
12811
|
+
return (
|
|
12812
|
+
/** @type {Record<string, TableRowKind>} */
|
|
12813
|
+
option
|
|
12814
|
+
);
|
|
12815
|
+
}
|
|
11830
12816
|
function initialExpanded(option) {
|
|
11831
12817
|
return new Set(Array.isArray(option) ? option : []);
|
|
11832
12818
|
}
|
|
12819
|
+
function normalizeTableVariant(value) {
|
|
12820
|
+
return value === "plain" ? "plain" : "default";
|
|
12821
|
+
}
|
|
11833
12822
|
function normalizeEditMode(mode) {
|
|
11834
12823
|
if (mode === "cell" || mode === "row") return mode;
|
|
11835
12824
|
return mode === true ? "cell" : false;
|
|
@@ -11872,6 +12861,22 @@ function normalizeTableColumns(columns) {
|
|
|
11872
12861
|
return { ...column, id, label: String(column.label ?? id) };
|
|
11873
12862
|
});
|
|
11874
12863
|
}
|
|
12864
|
+
function tableColumnName(column) {
|
|
12865
|
+
for (const candidate of [column?.ariaLabel, column?.label]) {
|
|
12866
|
+
const text3 = candidate == null ? "" : String(candidate).trim();
|
|
12867
|
+
if (text3) return text3;
|
|
12868
|
+
}
|
|
12869
|
+
return String(column?.id ?? "");
|
|
12870
|
+
}
|
|
12871
|
+
function tableHeaderName(column) {
|
|
12872
|
+
const label = column?.label == null ? "" : String(column.label).trim();
|
|
12873
|
+
const explicit = column?.ariaLabel == null ? "" : String(column.ariaLabel).trim();
|
|
12874
|
+
if (explicit) return explicit;
|
|
12875
|
+
return label ? null : tableColumnName(column) || null;
|
|
12876
|
+
}
|
|
12877
|
+
function editorSelectsOnEntry(type) {
|
|
12878
|
+
return type === "text" || type === "number" || type === "date";
|
|
12879
|
+
}
|
|
11875
12880
|
function reconcileTableColumnOrder(columns, order) {
|
|
11876
12881
|
const available = columns.map((column) => column.id);
|
|
11877
12882
|
const allowed = new Set(available);
|
|
@@ -12048,8 +13053,8 @@ function normalizeGlass(value) {
|
|
|
12048
13053
|
function normalizeShape(value) {
|
|
12049
13054
|
return value === "circle" ? "circle" : "tile";
|
|
12050
13055
|
}
|
|
12051
|
-
function originalAttribute(snapshot3,
|
|
12052
|
-
return snapshot3?.attributes.find(([attribute]) => attribute ===
|
|
13056
|
+
function originalAttribute(snapshot3, name2) {
|
|
13057
|
+
return snapshot3?.attributes.find(([attribute]) => attribute === name2)?.[1] ?? null;
|
|
12053
13058
|
}
|
|
12054
13059
|
|
|
12055
13060
|
// src/components/launcher/launcher.js
|
|
@@ -12063,14 +13068,20 @@ var Launcher = class extends Component {
|
|
|
12063
13068
|
debounce: 250,
|
|
12064
13069
|
minQuery: 0,
|
|
12065
13070
|
maxResults: 100,
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
13071
|
+
/*
|
|
13072
|
+
* The six labels default to null rather than to their English text so that an application
|
|
13073
|
+
* which installs a translator and passes no labels still gets a translated launcher. The
|
|
13074
|
+
* documented default is what `_message()` falls back to, so an untranslated application
|
|
13075
|
+
* renders exactly the same words as before.
|
|
13076
|
+
*/
|
|
13077
|
+
placeholder: null,
|
|
13078
|
+
label: null,
|
|
13079
|
+
closeLabel: null,
|
|
13080
|
+
resultsLabel: null,
|
|
13081
|
+
emptyText: null,
|
|
13082
|
+
loadingText: null,
|
|
12072
13083
|
shortcut: "mod+k",
|
|
12073
|
-
hints:
|
|
13084
|
+
hints: null,
|
|
12074
13085
|
scope: null
|
|
12075
13086
|
};
|
|
12076
13087
|
/**
|
|
@@ -12107,8 +13118,17 @@ var Launcher = class extends Component {
|
|
|
12107
13118
|
this._requestSequence = 0;
|
|
12108
13119
|
this._queryTimer = null;
|
|
12109
13120
|
this._busy = false;
|
|
13121
|
+
this._settled = true;
|
|
13122
|
+
this._pages = [];
|
|
13123
|
+
this._restoreActiveId = null;
|
|
13124
|
+
this._announcePending = false;
|
|
13125
|
+
this._announceToggle = false;
|
|
12110
13126
|
this._destroyed = false;
|
|
12111
13127
|
const listId = uid("zx-launcher-results");
|
|
13128
|
+
const label = String(this.options.label ?? this._message("launcher.label", "Launcher"));
|
|
13129
|
+
const placeholder = String(this.options.placeholder ?? this._message("launcher.placeholder", "Search applications and records"));
|
|
13130
|
+
this._label = label;
|
|
13131
|
+
this._placeholder = placeholder;
|
|
12112
13132
|
const input = h("input", {
|
|
12113
13133
|
ref: "input",
|
|
12114
13134
|
class: "zx-launcher__input",
|
|
@@ -12119,15 +13139,26 @@ var Launcher = class extends Component {
|
|
|
12119
13139
|
ariaAutocomplete: "list",
|
|
12120
13140
|
ariaControls: listId,
|
|
12121
13141
|
ariaExpanded: "false",
|
|
12122
|
-
ariaLabel:
|
|
12123
|
-
placeholder
|
|
13142
|
+
ariaLabel: label,
|
|
13143
|
+
placeholder,
|
|
12124
13144
|
value: this._query
|
|
12125
13145
|
});
|
|
13146
|
+
const scopeBack = h("button", {
|
|
13147
|
+
ref: "scopeBack",
|
|
13148
|
+
class: "zx-icon-btn zx-launcher__scope-back",
|
|
13149
|
+
type: "button"
|
|
13150
|
+
}, icon("x"));
|
|
13151
|
+
const scope2 = h(
|
|
13152
|
+
"span",
|
|
13153
|
+
{ ref: "scope", class: "zx-launcher__scope", hidden: true },
|
|
13154
|
+
h("span", { ref: "scopeLabel", class: "zx-launcher__scope-label" }),
|
|
13155
|
+
scopeBack
|
|
13156
|
+
);
|
|
12126
13157
|
const close = h("button", {
|
|
12127
13158
|
ref: "close",
|
|
12128
13159
|
class: "zx-icon-btn zx-launcher__close",
|
|
12129
13160
|
type: "button",
|
|
12130
|
-
ariaLabel: this.options.closeLabel
|
|
13161
|
+
ariaLabel: this.options.closeLabel ?? this._message("launcher.close", "Close launcher")
|
|
12131
13162
|
}, icon("x"));
|
|
12132
13163
|
const status = h("div", {
|
|
12133
13164
|
ref: "status",
|
|
@@ -12135,19 +13166,31 @@ var Launcher = class extends Component {
|
|
|
12135
13166
|
role: "status",
|
|
12136
13167
|
ariaLive: "polite"
|
|
12137
13168
|
});
|
|
13169
|
+
const announce = h("div", {
|
|
13170
|
+
ref: "announce",
|
|
13171
|
+
class: "zx-launcher__announce",
|
|
13172
|
+
role: "status",
|
|
13173
|
+
ariaLive: "polite",
|
|
13174
|
+
ariaAtomic: "true"
|
|
13175
|
+
});
|
|
12138
13176
|
const results = h("div", {
|
|
12139
13177
|
ref: "results",
|
|
12140
13178
|
class: "zx-launcher__results",
|
|
12141
13179
|
id: listId,
|
|
12142
13180
|
role: "listbox",
|
|
12143
|
-
ariaLabel: this.options.resultsLabel
|
|
13181
|
+
ariaLabel: this.options.resultsLabel ?? this._message("launcher.results", "Launcher results")
|
|
12144
13182
|
});
|
|
12145
13183
|
const shortcut = this.options.shortcut === "mod+k" ? h("kbd", {
|
|
12146
13184
|
class: "zx-launcher__shortcut",
|
|
12147
13185
|
ariaHidden: "true"
|
|
12148
13186
|
}, launcherShortcutLabel()) : null;
|
|
12149
|
-
const footer = launcherHints(this.options.hints
|
|
12150
|
-
|
|
13187
|
+
const footer = launcherHints(this.options.hints, {
|
|
13188
|
+
move: this._message("launcher.hintMove", "Move"),
|
|
13189
|
+
open: this._message("launcher.hintOpen", "Open"),
|
|
13190
|
+
back: this._message("launcher.hintBack", "Back"),
|
|
13191
|
+
close: this._message("launcher.hintClose", "Close")
|
|
13192
|
+
});
|
|
13193
|
+
dialog.setAttribute("aria-label", label);
|
|
12151
13194
|
dialog.replaceChildren(
|
|
12152
13195
|
h(
|
|
12153
13196
|
"div",
|
|
@@ -12155,17 +13198,19 @@ var Launcher = class extends Component {
|
|
|
12155
13198
|
h("div", {
|
|
12156
13199
|
class: "zx-launcher__search",
|
|
12157
13200
|
dataset: { shortcut: shortcut ? "true" : "false" }
|
|
12158
|
-
}, icon("search"), input, shortcut, close),
|
|
13201
|
+
}, icon("search"), scope2, input, shortcut, close),
|
|
12159
13202
|
status,
|
|
12160
13203
|
results,
|
|
12161
|
-
footer
|
|
13204
|
+
footer,
|
|
13205
|
+
announce
|
|
12162
13206
|
)
|
|
12163
13207
|
);
|
|
12164
13208
|
dialog.dataset.state = "closed";
|
|
12165
|
-
if (this._createdRoot)
|
|
13209
|
+
if (this._createdRoot) connectedOverlayHost(this.options.scope)?.append(dialog);
|
|
12166
13210
|
this.listen(input, "input", () => {
|
|
12167
13211
|
this._query = /** @type {HTMLInputElement} */
|
|
12168
13212
|
input.value;
|
|
13213
|
+
this._announcePending = false;
|
|
12169
13214
|
this.emit("query", { query: this._query.trim() });
|
|
12170
13215
|
this._refresh();
|
|
12171
13216
|
});
|
|
@@ -12173,6 +13218,10 @@ var Launcher = class extends Component {
|
|
|
12173
13218
|
/** @type {KeyboardEvent} */
|
|
12174
13219
|
event
|
|
12175
13220
|
));
|
|
13221
|
+
this.listen(scopeBack, "click", () => {
|
|
13222
|
+
this.back();
|
|
13223
|
+
input.focus();
|
|
13224
|
+
});
|
|
12176
13225
|
this.listen(close, "click", () => this.close());
|
|
12177
13226
|
this.listen(results, "click", (event) => {
|
|
12178
13227
|
const option = (
|
|
@@ -12201,6 +13250,13 @@ var Launcher = class extends Component {
|
|
|
12201
13250
|
dialog.dataset.state = "closed";
|
|
12202
13251
|
input.setAttribute("aria-expanded", "false");
|
|
12203
13252
|
this._abortRequest();
|
|
13253
|
+
if (this._pages.length && !dialog.open) {
|
|
13254
|
+
this._unwind();
|
|
13255
|
+
this._announcePending = false;
|
|
13256
|
+
this._syncPage();
|
|
13257
|
+
this._renderResults();
|
|
13258
|
+
this._emitPage();
|
|
13259
|
+
}
|
|
12204
13260
|
this.emit("close");
|
|
12205
13261
|
});
|
|
12206
13262
|
this.listen(document, "keydown", (event) => this._onDocumentKeydown(
|
|
@@ -12210,25 +13266,60 @@ var Launcher = class extends Component {
|
|
|
12210
13266
|
this._renderResults();
|
|
12211
13267
|
return dialog;
|
|
12212
13268
|
}
|
|
12213
|
-
/**
|
|
12214
|
-
|
|
12215
|
-
|
|
13269
|
+
/**
|
|
13270
|
+
* Opens the launcher and focuses/selects its query. It opens on the root unless `page` names one;
|
|
13271
|
+
* already open, `page` navigates there.
|
|
13272
|
+
* @param {LauncherOpenOptions} [options={}] Open options.
|
|
13273
|
+
* @returns {this}
|
|
13274
|
+
* @fires Launcher#open
|
|
13275
|
+
* @fires Launcher#page
|
|
13276
|
+
*/
|
|
13277
|
+
open(options = {}) {
|
|
13278
|
+
if (this._destroyed) return this;
|
|
13279
|
+
const target = options && typeof options === "object" ? options.page : void 0;
|
|
13280
|
+
if (this.isOpen()) {
|
|
13281
|
+
const path = target == null ? [] : this._pagePath(target);
|
|
13282
|
+
if (path.length) this._goTo(path);
|
|
13283
|
+
return this;
|
|
13284
|
+
}
|
|
12216
13285
|
if (this._createdRoot) {
|
|
12217
13286
|
const host = overlayHost(this.options.scope);
|
|
12218
13287
|
if (this.el.parentElement !== host) host.append(this.el);
|
|
12219
13288
|
}
|
|
13289
|
+
const before = this._pages.map((entry) => entry.page);
|
|
12220
13290
|
this.el.showModal();
|
|
12221
13291
|
this.el.dataset.state = "open";
|
|
12222
13292
|
this.refs.input.setAttribute("aria-expanded", "true");
|
|
12223
|
-
this.
|
|
13293
|
+
this._goTo(target == null ? [] : this._pagePath(target), { emit: false });
|
|
12224
13294
|
queueMicrotask(() => {
|
|
12225
13295
|
if (!this.isOpen()) return;
|
|
12226
13296
|
this.refs.input.focus();
|
|
12227
13297
|
this.refs.input.select();
|
|
12228
13298
|
});
|
|
12229
13299
|
this.emit("open");
|
|
13300
|
+
if (!samePath(before, this._pages.map((entry) => entry.page))) this._emitPage();
|
|
12230
13301
|
return this;
|
|
12231
13302
|
}
|
|
13303
|
+
/**
|
|
13304
|
+
* Goes back one page, restoring the level beneath with its query and highlighted option. Does
|
|
13305
|
+
* nothing on the root.
|
|
13306
|
+
* @returns {this}
|
|
13307
|
+
* @fires Launcher#page
|
|
13308
|
+
*/
|
|
13309
|
+
back() {
|
|
13310
|
+
if (!this._pages.length) return this;
|
|
13311
|
+
const settled = this._popPage();
|
|
13312
|
+
this._syncPage();
|
|
13313
|
+
this._announcePending = this.isOpen();
|
|
13314
|
+
if (settled) this._renderResults();
|
|
13315
|
+
else this._refresh(true);
|
|
13316
|
+
this._emitPage();
|
|
13317
|
+
return this;
|
|
13318
|
+
}
|
|
13319
|
+
/** Returns the page shown, or null on the root. @returns {LauncherItem|null} */
|
|
13320
|
+
getPage() {
|
|
13321
|
+
return this._pages.at(-1)?.page ?? null;
|
|
13322
|
+
}
|
|
12232
13323
|
/** Closes the launcher. @returns {this} */
|
|
12233
13324
|
close() {
|
|
12234
13325
|
if (this.isOpen()) this.el.close();
|
|
@@ -12252,6 +13343,7 @@ var Launcher = class extends Component {
|
|
|
12252
13343
|
setQuery(query) {
|
|
12253
13344
|
this._query = String(query ?? "");
|
|
12254
13345
|
this.refs.input.value = this._query;
|
|
13346
|
+
this._announcePending = false;
|
|
12255
13347
|
this.emit("query", { query: this._query.trim() });
|
|
12256
13348
|
this._refresh();
|
|
12257
13349
|
return this;
|
|
@@ -12260,7 +13352,7 @@ var Launcher = class extends Component {
|
|
|
12260
13352
|
getQuery() {
|
|
12261
13353
|
return this._query;
|
|
12262
13354
|
}
|
|
12263
|
-
/** Replaces local catalogue items. @param {LauncherItem[]} items @returns {this} */
|
|
13355
|
+
/** Replaces the root's local catalogue items; an open page keeps its own. @param {LauncherItem[]} items @returns {this} */
|
|
12264
13356
|
setItems(items) {
|
|
12265
13357
|
this._items = normalizeItems(items);
|
|
12266
13358
|
this._renderResults();
|
|
@@ -12273,10 +13365,14 @@ var Launcher = class extends Component {
|
|
|
12273
13365
|
this._renderResults();
|
|
12274
13366
|
return this;
|
|
12275
13367
|
}
|
|
12276
|
-
/** Replaces asynchronous sources and aborts work from the old set. @param {LauncherSource[]} sources @returns {this} */
|
|
13368
|
+
/** Replaces the root's asynchronous sources and aborts work from the old set; on a page they load once the root is back. @param {LauncherSource[]} sources @returns {this} */
|
|
12277
13369
|
setSources(sources) {
|
|
12278
|
-
this._abortRequest();
|
|
12279
13370
|
this._sources = normalizeSources(sources);
|
|
13371
|
+
if (this._pages.length) {
|
|
13372
|
+
this._pages[0].parent.sourceItems = null;
|
|
13373
|
+
return this;
|
|
13374
|
+
}
|
|
13375
|
+
this._abortRequest();
|
|
12280
13376
|
this._sourceItems.clear();
|
|
12281
13377
|
this._refresh();
|
|
12282
13378
|
return this;
|
|
@@ -12291,16 +13387,24 @@ var Launcher = class extends Component {
|
|
|
12291
13387
|
super.destroy();
|
|
12292
13388
|
if (!this._createdRoot && original) {
|
|
12293
13389
|
for (const attribute of Array.from(this.el.attributes)) this.el.removeAttribute(attribute.name);
|
|
12294
|
-
for (const [
|
|
13390
|
+
for (const [name2, value] of original.attributes) this.el.setAttribute(name2, value);
|
|
12295
13391
|
this.el.replaceChildren(...original.children);
|
|
12296
13392
|
}
|
|
12297
13393
|
}
|
|
12298
|
-
/**
|
|
12299
|
-
|
|
13394
|
+
/**
|
|
13395
|
+
* Re-renders the current level and reloads its sources: debounced while typing, at once when a
|
|
13396
|
+
* page opens (so its loading state shows instead of a passing "No results").
|
|
13397
|
+
* @param {boolean} [immediate=false] Load without the debounce.
|
|
13398
|
+
* @returns {void}
|
|
13399
|
+
*/
|
|
13400
|
+
_refresh(immediate = false) {
|
|
13401
|
+
this._abortRequest();
|
|
12300
13402
|
this._sourceItems.clear();
|
|
13403
|
+
const { sources } = this._level();
|
|
13404
|
+
this._settled = sources.length === 0;
|
|
13405
|
+
if (immediate && sources.length) void this._loadSources();
|
|
12301
13406
|
this._renderResults();
|
|
12302
|
-
|
|
12303
|
-
if (this._sources.length === 0) return;
|
|
13407
|
+
if (immediate || sources.length === 0) return;
|
|
12304
13408
|
const delay = Math.max(0, Number(this.options.debounce) || 0);
|
|
12305
13409
|
this._queryTimer = setTimeout(() => this._loadSources(), delay);
|
|
12306
13410
|
}
|
|
@@ -12308,8 +13412,15 @@ var Launcher = class extends Component {
|
|
|
12308
13412
|
async _loadSources() {
|
|
12309
13413
|
this._queryTimer = null;
|
|
12310
13414
|
const query = this._query.trim();
|
|
12311
|
-
const
|
|
12312
|
-
|
|
13415
|
+
const page = this._pages?.at(-1)?.page ?? null;
|
|
13416
|
+
const sources = this._level().sources.filter((source) => visibleForQuery(source.when, query) && query.length >= Math.max(
|
|
13417
|
+
source._page ? 0 : Number(this.options.minQuery) || 0,
|
|
13418
|
+
Number(source.minQuery) || 0
|
|
13419
|
+
));
|
|
13420
|
+
if (sources.length === 0) {
|
|
13421
|
+
this._settled = true;
|
|
13422
|
+
return;
|
|
13423
|
+
}
|
|
12313
13424
|
const request = new AbortController();
|
|
12314
13425
|
const sequence = ++this._requestSequence;
|
|
12315
13426
|
this._request = request;
|
|
@@ -12320,7 +13431,7 @@ var Launcher = class extends Component {
|
|
|
12320
13431
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
12321
13432
|
this._sourceItems.set(source.id, normalizeItems(loaded).map((item, itemOrder) => ({
|
|
12322
13433
|
...item,
|
|
12323
|
-
_source: source.id,
|
|
13434
|
+
_source: source._page ? null : source.id,
|
|
12324
13435
|
_sourceOrder: source.order === "source",
|
|
12325
13436
|
group: item.group ?? source.label ?? "",
|
|
12326
13437
|
itemOrder: item.itemOrder ?? (source.order === "source" ? itemOrder : void 0)
|
|
@@ -12328,13 +13439,157 @@ var Launcher = class extends Component {
|
|
|
12328
13439
|
this._renderResults();
|
|
12329
13440
|
} catch (error) {
|
|
12330
13441
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
12331
|
-
this.emit("error", { source, error });
|
|
13442
|
+
this.emit("error", { source, error, page });
|
|
12332
13443
|
}
|
|
12333
13444
|
}));
|
|
12334
13445
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
12335
13446
|
this._request = null;
|
|
13447
|
+
this._settled = true;
|
|
12336
13448
|
this._setBusy(false);
|
|
12337
13449
|
}
|
|
13450
|
+
/**
|
|
13451
|
+
* The level on screen: the root's items and sources, or the open page's.
|
|
13452
|
+
* @returns {{items: LauncherItem[], sources: LevelSource[]}}
|
|
13453
|
+
*/
|
|
13454
|
+
_level() {
|
|
13455
|
+
return this._pages?.at(-1) ?? { items: this._items, sources: this._sources };
|
|
13456
|
+
}
|
|
13457
|
+
/**
|
|
13458
|
+
* Opens a page on top of the current level: what the user activated, or ArrowRight on its row.
|
|
13459
|
+
* @param {LauncherItem} item Page item.
|
|
13460
|
+
* @returns {void}
|
|
13461
|
+
*/
|
|
13462
|
+
_openPage(item) {
|
|
13463
|
+
this._pushPage(item);
|
|
13464
|
+
this._syncPage();
|
|
13465
|
+
this._announcePending = this.isOpen();
|
|
13466
|
+
this._refresh(true);
|
|
13467
|
+
this._emitPage();
|
|
13468
|
+
}
|
|
13469
|
+
/**
|
|
13470
|
+
* Replaces the whole stack with `path` (empty for the root) and refreshes what it lands on.
|
|
13471
|
+
* @param {LauncherItem[]} path Pages from the root down.
|
|
13472
|
+
* @param {{emit?: boolean}} [options={}] Whether to report a change through `page`.
|
|
13473
|
+
* @returns {void}
|
|
13474
|
+
*/
|
|
13475
|
+
_goTo(path, { emit = true } = {}) {
|
|
13476
|
+
const before = this._pages.map((entry) => entry.page);
|
|
13477
|
+
this._unwind();
|
|
13478
|
+
if (path.length) {
|
|
13479
|
+
this._abortRequest();
|
|
13480
|
+
this._sourceItems.clear();
|
|
13481
|
+
this._settled = false;
|
|
13482
|
+
for (const item of path) this._pushPage(item);
|
|
13483
|
+
}
|
|
13484
|
+
this._syncPage();
|
|
13485
|
+
this._announcePending = this.isOpen() && path.length > 0;
|
|
13486
|
+
this._refresh(path.length > 0);
|
|
13487
|
+
if (emit && !samePath(before, path)) this._emitPage();
|
|
13488
|
+
}
|
|
13489
|
+
/** Pops every page, restoring the root's query, without rendering. @returns {void} */
|
|
13490
|
+
_unwind() {
|
|
13491
|
+
while (this._pages.length) this._popPage();
|
|
13492
|
+
}
|
|
13493
|
+
/**
|
|
13494
|
+
* Pushes a page, remembering the level beneath, and clears the query for it.
|
|
13495
|
+
* @param {LauncherItem} item Page item.
|
|
13496
|
+
* @returns {void}
|
|
13497
|
+
*/
|
|
13498
|
+
_pushPage(item) {
|
|
13499
|
+
const active = this._active >= 0 ? this._results[this._active] : null;
|
|
13500
|
+
this._pages.push({
|
|
13501
|
+
page: item,
|
|
13502
|
+
items: Array.isArray(item.items) ? normalizeItems(item.items) : [],
|
|
13503
|
+
sources: typeof item.items === "function" ? [launcherPageSource(item)] : [],
|
|
13504
|
+
parent: {
|
|
13505
|
+
query: this._query,
|
|
13506
|
+
activeId: active ? String(active.id) : null,
|
|
13507
|
+
sourceItems: this._settled ? new Map(this._sourceItems) : null
|
|
13508
|
+
}
|
|
13509
|
+
});
|
|
13510
|
+
this._setInputQuery("");
|
|
13511
|
+
}
|
|
13512
|
+
/**
|
|
13513
|
+
* Pops the top page and restores the level beneath.
|
|
13514
|
+
* @returns {boolean} Whether that level's results came back complete (no reload needed).
|
|
13515
|
+
*/
|
|
13516
|
+
_popPage() {
|
|
13517
|
+
const entry = this._pages.pop();
|
|
13518
|
+
if (!entry) return true;
|
|
13519
|
+
this._announcePending = false;
|
|
13520
|
+
this._abortRequest();
|
|
13521
|
+
const { parent } = entry;
|
|
13522
|
+
this._setInputQuery(parent.query);
|
|
13523
|
+
this._sourceItems = parent.sourceItems ? new Map(parent.sourceItems) : /* @__PURE__ */ new Map();
|
|
13524
|
+
this._settled = parent.sourceItems !== null;
|
|
13525
|
+
this._restoreActiveId = parent.activeId;
|
|
13526
|
+
return this._settled;
|
|
13527
|
+
}
|
|
13528
|
+
/** @param {string} query @returns {void} */
|
|
13529
|
+
_setInputQuery(query) {
|
|
13530
|
+
this._query = query;
|
|
13531
|
+
this.refs.input.value = query;
|
|
13532
|
+
this._renderedQuery = null;
|
|
13533
|
+
}
|
|
13534
|
+
/**
|
|
13535
|
+
* Shows the open page in the search row: the chip, the combobox name and placeholder, and the
|
|
13536
|
+
* footer's Back hint.
|
|
13537
|
+
* @returns {void}
|
|
13538
|
+
*/
|
|
13539
|
+
_syncPage() {
|
|
13540
|
+
const page = this.getPage();
|
|
13541
|
+
const { input, scope: scope2, scopeLabel, scopeBack, backHint } = this.refs;
|
|
13542
|
+
scope2.hidden = page === null;
|
|
13543
|
+
if (backHint) backHint.hidden = page === null;
|
|
13544
|
+
this.el.toggleAttribute("data-page", page !== null);
|
|
13545
|
+
if (page === null) {
|
|
13546
|
+
input.setAttribute("aria-label", this._label);
|
|
13547
|
+
input.setAttribute("placeholder", this._placeholder);
|
|
13548
|
+
scopeLabel.textContent = "";
|
|
13549
|
+
return;
|
|
13550
|
+
}
|
|
13551
|
+
const parent = this._pages.at(-2)?.page.label ?? this._label;
|
|
13552
|
+
scopeLabel.textContent = page.label;
|
|
13553
|
+
scopeBack.setAttribute("aria-label", this._message("launcher.back", "Back to %1", parent));
|
|
13554
|
+
input.setAttribute("aria-label", this._message("launcher.pageLabel", "Search %1", page.label));
|
|
13555
|
+
input.setAttribute("placeholder", page.placeholder != null ? String(page.placeholder) : this._message("launcher.pagePlaceholder", "Search"));
|
|
13556
|
+
}
|
|
13557
|
+
/** @returns {void} @fires Launcher#page */
|
|
13558
|
+
_emitPage() {
|
|
13559
|
+
const path = this._pages.map((entry) => entry.page);
|
|
13560
|
+
this.emit("page", { page: path.at(-1) ?? null, path });
|
|
13561
|
+
}
|
|
13562
|
+
/**
|
|
13563
|
+
* Resolves `open({ page })`: a page item as given, or the path to a local page by id.
|
|
13564
|
+
* @param {string|number|LauncherItem} target Page id or item.
|
|
13565
|
+
* @returns {LauncherItem[]}
|
|
13566
|
+
*/
|
|
13567
|
+
_pagePath(target) {
|
|
13568
|
+
if (target && typeof target === "object") {
|
|
13569
|
+
const item = (
|
|
13570
|
+
/** @type {Record<string, any>} */
|
|
13571
|
+
target
|
|
13572
|
+
);
|
|
13573
|
+
if (!isLauncherPage(item) || item.label == null) return [];
|
|
13574
|
+
return [normalizeLauncherItem({ ...item, id: item.id ?? item.label })];
|
|
13575
|
+
}
|
|
13576
|
+
return findLauncherPage(
|
|
13577
|
+
this._items,
|
|
13578
|
+
/** @type {string|number} */
|
|
13579
|
+
target
|
|
13580
|
+
);
|
|
13581
|
+
}
|
|
13582
|
+
/**
|
|
13583
|
+
* The polite line a page change ends on: where the user is and how much is there.
|
|
13584
|
+
* @returns {string}
|
|
13585
|
+
*/
|
|
13586
|
+
_pageStatus() {
|
|
13587
|
+
const label = this.getPage()?.label ?? this._label;
|
|
13588
|
+
const count = this._results.length;
|
|
13589
|
+
if (count === 0) return this._message("launcher.pageEmpty", "%1, no results", label);
|
|
13590
|
+
if (count === 1) return this._message("launcher.pageResult", "%1, 1 result", label);
|
|
13591
|
+
return this._message("launcher.pageResults", "%1, %2 results", label, count);
|
|
13592
|
+
}
|
|
12338
13593
|
/** @param {boolean} busy @returns {void} */
|
|
12339
13594
|
_setBusy(busy) {
|
|
12340
13595
|
this._busy = busy;
|
|
@@ -12353,11 +13608,14 @@ var Launcher = class extends Component {
|
|
|
12353
13608
|
/** @returns {void} */
|
|
12354
13609
|
_renderResults() {
|
|
12355
13610
|
const queryKey = this._query;
|
|
12356
|
-
const
|
|
13611
|
+
const restored = this._restoreActiveId ?? null;
|
|
13612
|
+
this._restoreActiveId = null;
|
|
13613
|
+
const activeId = restored ?? (this._renderedQuery === queryKey && this._active >= 0 && this._results[this._active] ? String(this._results[this._active].id) : null);
|
|
12357
13614
|
const query = this._query.trim();
|
|
12358
|
-
const
|
|
13615
|
+
const level = this._level();
|
|
13616
|
+
const local = level.items.filter((item) => visibleForQuery(item.when, query));
|
|
12359
13617
|
const rankedLocal = rankLauncherItems(local, query, this.options.maxResults);
|
|
12360
|
-
const remote =
|
|
13618
|
+
const remote = level.sources.flatMap((source) => {
|
|
12361
13619
|
const loaded = this._sourceItems.get(String(source.id)) ?? [];
|
|
12362
13620
|
return source.order === "source" ? loaded.filter((item) => visibleForQuery(item.when, query)) : rankLauncherItems(
|
|
12363
13621
|
loaded.filter((item) => visibleForQuery(item.when, query)),
|
|
@@ -12400,7 +13658,8 @@ var Launcher = class extends Component {
|
|
|
12400
13658
|
}
|
|
12401
13659
|
/** @param {RankedLauncherItem} item @param {number} index @returns {HTMLElement} */
|
|
12402
13660
|
_option(item, index) {
|
|
12403
|
-
const
|
|
13661
|
+
const page = isLauncherPage(item);
|
|
13662
|
+
const href = page ? null : safeHref(item.href);
|
|
12404
13663
|
const tag = href ? "a" : "button";
|
|
12405
13664
|
const children = [];
|
|
12406
13665
|
const visual = launcherItemIcon(item);
|
|
@@ -12415,6 +13674,17 @@ var Launcher = class extends Component {
|
|
|
12415
13674
|
item.description ? h("span", { class: "zx-launcher__description" }, item.description) : null
|
|
12416
13675
|
));
|
|
12417
13676
|
if (item.badge != null) children.push(h("span", { class: "zx-launcher__badge" }, String(item.badge)));
|
|
13677
|
+
if (item.hint != null && item.hint !== "") {
|
|
13678
|
+
children.push(h("span", { class: "zx-launcher__hint" }, String(item.hint)));
|
|
13679
|
+
}
|
|
13680
|
+
const keys = launcherShortcutKeys(item);
|
|
13681
|
+
const caps = launcherShortcutCaps(item.shortcut);
|
|
13682
|
+
if (caps.length) children.push(h(
|
|
13683
|
+
"span",
|
|
13684
|
+
{ class: "zx-launcher__keys", ariaHidden: keys ? "true" : null },
|
|
13685
|
+
caps.map((cap) => h("kbd", { class: "zx-launcher__key" }, cap))
|
|
13686
|
+
));
|
|
13687
|
+
if (page) children.push(h("span", { class: "zx-launcher__chevron", ariaHidden: "true" }, icon("chevron-right")));
|
|
12418
13688
|
return (
|
|
12419
13689
|
/** @type {HTMLElement} */
|
|
12420
13690
|
h(tag, {
|
|
@@ -12429,20 +13699,31 @@ var Launcher = class extends Component {
|
|
|
12429
13699
|
ariaSelected: "false",
|
|
12430
13700
|
ariaDisabled: item.disabled ? "true" : null,
|
|
12431
13701
|
ariaCurrent: item.current ? "page" : null,
|
|
13702
|
+
ariaKeyShortcuts: keys,
|
|
12432
13703
|
dataset: {
|
|
12433
13704
|
launcherIndex: index,
|
|
12434
13705
|
pinned: item.pinned !== void 0 && item.pinned !== false ? "true" : null,
|
|
12435
|
-
kind: normalizeLauncherKind(item.kind)
|
|
13706
|
+
kind: normalizeLauncherKind(item.kind),
|
|
13707
|
+
page: page ? "true" : null
|
|
12436
13708
|
}
|
|
12437
13709
|
}, children)
|
|
12438
13710
|
);
|
|
12439
13711
|
}
|
|
12440
13712
|
/** @returns {void} */
|
|
12441
13713
|
_renderStatus() {
|
|
12442
|
-
if (this._busy)
|
|
12443
|
-
|
|
12444
|
-
else this.
|
|
13714
|
+
if (this._busy) {
|
|
13715
|
+
this.refs.status.textContent = String(this.options.loadingText ?? this._message("launcher.loading", "Searching\u2026"));
|
|
13716
|
+
} else if (this._results.length === 0) {
|
|
13717
|
+
this.refs.status.textContent = String(this.options.emptyText ?? this._message("launcher.empty", "No results"));
|
|
13718
|
+
} else {
|
|
13719
|
+
this.refs.status.textContent = "";
|
|
13720
|
+
}
|
|
12445
13721
|
this.refs.status.hidden = !this.refs.status.textContent;
|
|
13722
|
+
if (this._announcePending && !this._busy && this._renderedQuery === this._query) {
|
|
13723
|
+
this._announcePending = false;
|
|
13724
|
+
this._announceToggle = !this._announceToggle;
|
|
13725
|
+
this.refs.announce.textContent = this._pageStatus() + (this._announceToggle ? "\xA0" : "");
|
|
13726
|
+
}
|
|
12446
13727
|
}
|
|
12447
13728
|
/** @returns {void} */
|
|
12448
13729
|
_syncActive() {
|
|
@@ -12461,6 +13742,12 @@ var Launcher = class extends Component {
|
|
|
12461
13742
|
this.close();
|
|
12462
13743
|
return;
|
|
12463
13744
|
}
|
|
13745
|
+
const plain = !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey;
|
|
13746
|
+
if (event.key === "Backspace" && plain && !event.repeat && this._pages.length && this._query === "") {
|
|
13747
|
+
event.preventDefault();
|
|
13748
|
+
this.back();
|
|
13749
|
+
return;
|
|
13750
|
+
}
|
|
12464
13751
|
if (event.key === "Enter") {
|
|
12465
13752
|
if (this._active < 0) return;
|
|
12466
13753
|
event.preventDefault();
|
|
@@ -12469,9 +13756,8 @@ var Launcher = class extends Component {
|
|
|
12469
13756
|
return;
|
|
12470
13757
|
}
|
|
12471
13758
|
const enabled = this._results.map((item, index) => item.disabled ? -1 : index).filter((index) => index >= 0);
|
|
12472
|
-
if (enabled.length === 0) return;
|
|
12473
13759
|
if (/^Arrow(?:Left|Right|Up|Down)$/.test(event.key)) {
|
|
12474
|
-
const next = this._spatialIndex(event.key, enabled);
|
|
13760
|
+
const next = enabled.length ? this._spatialIndex(event.key, enabled) : null;
|
|
12475
13761
|
if (next !== null) {
|
|
12476
13762
|
event.preventDefault();
|
|
12477
13763
|
this._active = next;
|
|
@@ -12479,8 +13765,12 @@ var Launcher = class extends Component {
|
|
|
12479
13765
|
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
12480
13766
|
return;
|
|
12481
13767
|
}
|
|
12482
|
-
if (event.key === "ArrowLeft" || event.key === "ArrowRight")
|
|
13768
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
13769
|
+
if (plain && !event.repeat && this._pageKey(event.key)) event.preventDefault();
|
|
13770
|
+
return;
|
|
13771
|
+
}
|
|
12483
13772
|
}
|
|
13773
|
+
if (enabled.length === 0) return;
|
|
12484
13774
|
let position2 = enabled.indexOf(this._active);
|
|
12485
13775
|
if (event.key === "Home" || event.key === "PageUp") position2 = 0;
|
|
12486
13776
|
else if (event.key === "End" || event.key === "PageDown") position2 = enabled.length - 1;
|
|
@@ -12492,6 +13782,30 @@ var Launcher = class extends Component {
|
|
|
12492
13782
|
this._syncActive();
|
|
12493
13783
|
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest" });
|
|
12494
13784
|
}
|
|
13785
|
+
/**
|
|
13786
|
+
* ArrowRight on a page row opens it once the caret is at the end of the query (before that it
|
|
13787
|
+
* moves the caret); ArrowLeft on an empty query goes back. Application tiles keep both arrows
|
|
13788
|
+
* for moving through their grid, which the caller tries first.
|
|
13789
|
+
* @param {string} key ArrowLeft or ArrowRight.
|
|
13790
|
+
* @returns {boolean} Whether the key navigated.
|
|
13791
|
+
*/
|
|
13792
|
+
_pageKey(key) {
|
|
13793
|
+
if (key === "ArrowLeft") {
|
|
13794
|
+
if (!this._pages.length || this._query !== "") return false;
|
|
13795
|
+
this.back();
|
|
13796
|
+
return true;
|
|
13797
|
+
}
|
|
13798
|
+
const item = this._active >= 0 ? this._results[this._active] : null;
|
|
13799
|
+
if (!item || item.disabled || !isLauncherPage(item) || item.kind === "application") return false;
|
|
13800
|
+
const input = (
|
|
13801
|
+
/** @type {HTMLInputElement} */
|
|
13802
|
+
this.refs.input
|
|
13803
|
+
);
|
|
13804
|
+
const end = input.value.length;
|
|
13805
|
+
if (input.selectionStart !== end || input.selectionEnd !== end) return false;
|
|
13806
|
+
this._openPage(item);
|
|
13807
|
+
return true;
|
|
13808
|
+
}
|
|
12495
13809
|
/** @param {string} direction @param {number[]} enabled @returns {number|null} */
|
|
12496
13810
|
_spatialIndex(direction, enabled) {
|
|
12497
13811
|
const current = this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`);
|
|
@@ -12508,21 +13822,28 @@ var Launcher = class extends Component {
|
|
|
12508
13822
|
event.preventDefault();
|
|
12509
13823
|
return;
|
|
12510
13824
|
}
|
|
13825
|
+
if (isLauncherPage(item)) {
|
|
13826
|
+
event.preventDefault();
|
|
13827
|
+
this._openPage(item);
|
|
13828
|
+
this.refs.input.focus();
|
|
13829
|
+
return;
|
|
13830
|
+
}
|
|
12511
13831
|
const selected = this.emit("select", {
|
|
12512
13832
|
item,
|
|
12513
13833
|
value: item.value ?? item.id,
|
|
12514
13834
|
source: item._source ?? null,
|
|
12515
|
-
query: this._query.trim()
|
|
13835
|
+
query: this._query.trim(),
|
|
13836
|
+
page: this.getPage()
|
|
12516
13837
|
});
|
|
12517
13838
|
if (selected.defaultPrevented) {
|
|
12518
13839
|
event.preventDefault();
|
|
12519
13840
|
return;
|
|
12520
13841
|
}
|
|
13842
|
+
this.close();
|
|
12521
13843
|
if (!item.href) {
|
|
12522
13844
|
event.preventDefault();
|
|
12523
13845
|
item.invoke?.();
|
|
12524
13846
|
}
|
|
12525
|
-
this.close();
|
|
12526
13847
|
}
|
|
12527
13848
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
12528
13849
|
_onDocumentKeydown(event) {
|
|
@@ -12534,6 +13855,17 @@ var Launcher = class extends Component {
|
|
|
12534
13855
|
event.preventDefault();
|
|
12535
13856
|
this.open();
|
|
12536
13857
|
}
|
|
13858
|
+
/**
|
|
13859
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
13860
|
+
* @param {string} key Message key.
|
|
13861
|
+
* @param {string} fallback English default.
|
|
13862
|
+
* @param {...unknown} args Positional `%1`, `%2` values.
|
|
13863
|
+
* @returns {string}
|
|
13864
|
+
*/
|
|
13865
|
+
_message(key, fallback, ...args) {
|
|
13866
|
+
const message = this.msg(key, ...args);
|
|
13867
|
+
return message === key ? printf(fallback, args) : message;
|
|
13868
|
+
}
|
|
12537
13869
|
};
|
|
12538
13870
|
function launcherShortcutLabel() {
|
|
12539
13871
|
const platform = String(
|
|
@@ -12542,16 +13874,73 @@ function launcherShortcutLabel() {
|
|
|
12542
13874
|
);
|
|
12543
13875
|
return /mac|iphone|ipad/i.test(platform) ? "\u2318 K" : "Ctrl K";
|
|
12544
13876
|
}
|
|
12545
|
-
function launcherHints(hints) {
|
|
13877
|
+
function launcherHints(hints, defaults4) {
|
|
12546
13878
|
if (hints === false) return null;
|
|
12547
13879
|
const labels = hints && typeof hints === "object" ? hints : {};
|
|
12548
13880
|
return h(
|
|
12549
13881
|
"footer",
|
|
12550
13882
|
{ class: "zx-launcher__hints", ariaHidden: "true" },
|
|
12551
|
-
h("span", {}, h("kbd", {}, "\u2191\u2193\u2190\u2192"), labels.move ??
|
|
12552
|
-
h("span", {}, h("kbd", {}, "\u21B5"), labels.open ??
|
|
12553
|
-
|
|
13883
|
+
h("span", {}, h("kbd", {}, "\u2191\u2193\u2190\u2192"), labels.move ?? defaults4.move),
|
|
13884
|
+
h("span", {}, h("kbd", {}, "\u21B5"), labels.open ?? defaults4.open),
|
|
13885
|
+
// Shown only on a page (`_syncPage()`).
|
|
13886
|
+
h("span", { ref: "backHint", hidden: true }, h("kbd", {}, "\u232B"), labels.back ?? defaults4.back),
|
|
13887
|
+
h("span", {}, h("kbd", {}, "Esc"), labels.close ?? defaults4.close)
|
|
13888
|
+
);
|
|
13889
|
+
}
|
|
13890
|
+
function isLauncherPage(item) {
|
|
13891
|
+
const items = (
|
|
13892
|
+
/** @type {Record<string, any>|null} */
|
|
13893
|
+
item?.items
|
|
12554
13894
|
);
|
|
13895
|
+
return Boolean(item) && typeof item === "object" && (Array.isArray(items) || typeof items === "function");
|
|
13896
|
+
}
|
|
13897
|
+
function findLauncherPage(items, id) {
|
|
13898
|
+
if (id == null) return [];
|
|
13899
|
+
const key = String(id);
|
|
13900
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13901
|
+
const visit = (list, trail) => {
|
|
13902
|
+
if (!Array.isArray(list) || seen.has(list)) return null;
|
|
13903
|
+
seen.add(list);
|
|
13904
|
+
for (const item of normalizeItems(list)) {
|
|
13905
|
+
if (!isLauncherPage(item)) continue;
|
|
13906
|
+
const path = [...trail, item];
|
|
13907
|
+
if (String(item.id) === key) return path;
|
|
13908
|
+
const found = visit(item.items, path);
|
|
13909
|
+
if (found) return found;
|
|
13910
|
+
}
|
|
13911
|
+
return null;
|
|
13912
|
+
};
|
|
13913
|
+
return visit(items, []) ?? [];
|
|
13914
|
+
}
|
|
13915
|
+
function launcherShortcutCaps(shortcut) {
|
|
13916
|
+
const labels = shortcut && typeof shortcut === "object" && !Array.isArray(shortcut) ? (
|
|
13917
|
+
/** @type {{label?: unknown}} */
|
|
13918
|
+
shortcut.label
|
|
13919
|
+
) : shortcut;
|
|
13920
|
+
const caps = Array.isArray(labels) ? labels : labels == null ? [] : [labels];
|
|
13921
|
+
return caps.filter((cap) => cap != null && String(cap).trim() !== "").map((cap) => String(cap).trim());
|
|
13922
|
+
}
|
|
13923
|
+
function launcherShortcutKeys(item) {
|
|
13924
|
+
const shortcut = (
|
|
13925
|
+
/** @type {any} */
|
|
13926
|
+
item.shortcut
|
|
13927
|
+
);
|
|
13928
|
+
const keys = item.keys ?? (shortcut && typeof shortcut === "object" && !Array.isArray(shortcut) ? shortcut.keys : null);
|
|
13929
|
+
return typeof keys === "string" && keys.trim() ? keys.trim() : null;
|
|
13930
|
+
}
|
|
13931
|
+
function launcherPageSource(item) {
|
|
13932
|
+
return {
|
|
13933
|
+
id: `page:${String(item.id)}`,
|
|
13934
|
+
load: (
|
|
13935
|
+
/** @type {LauncherPageLoader} */
|
|
13936
|
+
item.items
|
|
13937
|
+
),
|
|
13938
|
+
order: item.order === "source" ? "source" : "rank",
|
|
13939
|
+
_page: true
|
|
13940
|
+
};
|
|
13941
|
+
}
|
|
13942
|
+
function samePath(left, right) {
|
|
13943
|
+
return left.length === right.length && left.every((item, index) => item === right[index] || String(item.id) === String(right[index].id));
|
|
12555
13944
|
}
|
|
12556
13945
|
function launcherItemIcon(item) {
|
|
12557
13946
|
let visual = item.icon;
|
|
@@ -12672,7 +14061,7 @@ function normalizeLauncherItem(item) {
|
|
|
12672
14061
|
if (href !== null) normalized.href = href;
|
|
12673
14062
|
else {
|
|
12674
14063
|
delete normalized.href;
|
|
12675
|
-
if (typeof normalized.invoke !== "function") normalized.disabled = true;
|
|
14064
|
+
if (typeof normalized.invoke !== "function" && !isLauncherPage(normalized)) normalized.disabled = true;
|
|
12676
14065
|
}
|
|
12677
14066
|
return normalized;
|
|
12678
14067
|
}
|
|
@@ -12682,6 +14071,7 @@ function normalizeSources(sources) {
|
|
|
12682
14071
|
}
|
|
12683
14072
|
|
|
12684
14073
|
// src/components/message/message.js
|
|
14074
|
+
var MESSAGE_ACTION_MIN_TIMEOUT = 8e3;
|
|
12685
14075
|
var MessageQueue = class {
|
|
12686
14076
|
#limit;
|
|
12687
14077
|
#active = [];
|
|
@@ -12772,7 +14162,7 @@ var Message = class _Message extends Component {
|
|
|
12772
14162
|
closable: true,
|
|
12773
14163
|
maxVisible: 5
|
|
12774
14164
|
};
|
|
12775
|
-
/** @type {WeakMap<Element, Message>} */
|
|
14165
|
+
/** @type {WeakMap<Element, Message>} Floating region per overlay host. */
|
|
12776
14166
|
static #floating = /* @__PURE__ */ new WeakMap();
|
|
12777
14167
|
/** @returns {HTMLElement} */
|
|
12778
14168
|
render() {
|
|
@@ -12784,6 +14174,7 @@ var Message = class _Message extends Component {
|
|
|
12784
14174
|
this._createdRoot = created;
|
|
12785
14175
|
this._original = created ? null : snapshot2(root);
|
|
12786
14176
|
this._entries = /* @__PURE__ */ new Set();
|
|
14177
|
+
this._floatingHost = null;
|
|
12787
14178
|
this._queue = new MessageQueue(normalizeLimit(this.options.maxVisible), (entry) => {
|
|
12788
14179
|
this._activate(entry);
|
|
12789
14180
|
});
|
|
@@ -12799,10 +14190,13 @@ var Message = class _Message extends Component {
|
|
|
12799
14190
|
* @returns {MessageHandle}
|
|
12800
14191
|
*/
|
|
12801
14192
|
show(msg, options = {}) {
|
|
14193
|
+
const action = normalizeMessageAction(options.action);
|
|
12802
14194
|
const settings = {
|
|
12803
|
-
kind:
|
|
12804
|
-
timeout:
|
|
12805
|
-
closable: options.closable ?? Boolean(this.options.closable)
|
|
14195
|
+
kind: normalizeKind2(options.kind ?? this.options.kind),
|
|
14196
|
+
timeout: messageTimeout(options.timeout ?? this.options.timeout, action !== null),
|
|
14197
|
+
closable: options.closable ?? Boolean(this.options.closable),
|
|
14198
|
+
action,
|
|
14199
|
+
leading: resolveLeading(options.leading)
|
|
12806
14200
|
};
|
|
12807
14201
|
const entry = this._createEntry(msg, settings);
|
|
12808
14202
|
this._entries.add(entry);
|
|
@@ -12863,10 +14257,32 @@ var Message = class _Message extends Component {
|
|
|
12863
14257
|
static progress(text3, options = {}) {
|
|
12864
14258
|
return this.#floatingRegion(options.scope)._progress(text3);
|
|
12865
14259
|
}
|
|
14260
|
+
/**
|
|
14261
|
+
* Removes a floating region at once, toasts and all, without waiting for them to time out.
|
|
14262
|
+
*
|
|
14263
|
+
* A region already removes itself when its last toast closes, and one whose host has left the
|
|
14264
|
+
* document is replaced on the next toast, so this is only for a host being torn down while
|
|
14265
|
+
* toasts are still showing — an application view unmounting its themed shell, say.
|
|
14266
|
+
* @param {Element|string} scope Element or selector whose nearest Zx theme scope owns the region,
|
|
14267
|
+
* as passed to `show()`.
|
|
14268
|
+
* @returns {boolean} Whether there was a region to remove.
|
|
14269
|
+
*/
|
|
14270
|
+
static disposeRegion(scope2) {
|
|
14271
|
+
if (scope2 == null) return false;
|
|
14272
|
+
const context = resolveElement(scope2);
|
|
14273
|
+
if (!context) return false;
|
|
14274
|
+
const host = overlayHost(context);
|
|
14275
|
+
const region = _Message.#floating.get(host);
|
|
14276
|
+
if (!region) return false;
|
|
14277
|
+
_Message.#floating.delete(host);
|
|
14278
|
+
region._disposeFloating();
|
|
14279
|
+
return true;
|
|
14280
|
+
}
|
|
12866
14281
|
/** @returns {void} */
|
|
12867
14282
|
destroy() {
|
|
12868
14283
|
if (this._cleaned) return;
|
|
12869
14284
|
this._cleaned = true;
|
|
14285
|
+
this._floatingHost = null;
|
|
12870
14286
|
for (const entry of this._entries) {
|
|
12871
14287
|
clearEntryTimers(entry);
|
|
12872
14288
|
entry.node.remove();
|
|
@@ -12918,7 +14334,7 @@ var Message = class _Message extends Component {
|
|
|
12918
14334
|
}
|
|
12919
14335
|
/**
|
|
12920
14336
|
* @param {string|Node} msg
|
|
12921
|
-
* @param {{kind: MessageKind, timeout: number, closable: boolean}} settings
|
|
14337
|
+
* @param {{kind: MessageKind, timeout: number, closable: boolean, action?: MessageAction|null, leading?: Node|null}} settings
|
|
12922
14338
|
* @param {{pct: number, text: string}|null} [progress=null]
|
|
12923
14339
|
* @returns {any}
|
|
12924
14340
|
*/
|
|
@@ -12926,7 +14342,7 @@ var Message = class _Message extends Component {
|
|
|
12926
14342
|
const iconHost = h(
|
|
12927
14343
|
"span",
|
|
12928
14344
|
{ class: "zx-message__icon", ariaHidden: "true" },
|
|
12929
|
-
icon(settings.kind, { size: 18 })
|
|
14345
|
+
settings.leading ?? icon(settings.kind, { size: 18 })
|
|
12930
14346
|
);
|
|
12931
14347
|
const content = h("div", { class: "zx-message__content" });
|
|
12932
14348
|
if (isNode(msg)) content.append(msg);
|
|
@@ -12947,9 +14363,13 @@ var Message = class _Message extends Component {
|
|
|
12947
14363
|
timer: null,
|
|
12948
14364
|
exitTimer: null,
|
|
12949
14365
|
closed: false,
|
|
14366
|
+
hovered: false,
|
|
14367
|
+
focused: false,
|
|
14368
|
+
returnFocus: null,
|
|
12950
14369
|
progressBar: null,
|
|
12951
14370
|
progressFill: null
|
|
12952
14371
|
};
|
|
14372
|
+
if (settings.leading) node.dataset.leading = "";
|
|
12953
14373
|
if (progress) {
|
|
12954
14374
|
node.dataset.progress = "";
|
|
12955
14375
|
const fill = h("span", { class: "zx-message__progress-fill" });
|
|
@@ -12966,18 +14386,67 @@ var Message = class _Message extends Component {
|
|
|
12966
14386
|
entry.progressFill = fill;
|
|
12967
14387
|
syncProgress(entry, progress);
|
|
12968
14388
|
}
|
|
14389
|
+
if (settings.action) {
|
|
14390
|
+
const { label, kind, onclick } = settings.action;
|
|
14391
|
+
const control = button({ label, kind, size: "sm" });
|
|
14392
|
+
control.classList.add("zx-message__action");
|
|
14393
|
+
node.append(control);
|
|
14394
|
+
this.listen(control, "click", (event) => {
|
|
14395
|
+
if (entry.closed) return;
|
|
14396
|
+
try {
|
|
14397
|
+
onclick?.(
|
|
14398
|
+
/** @type {MouseEvent} */
|
|
14399
|
+
event
|
|
14400
|
+
);
|
|
14401
|
+
} finally {
|
|
14402
|
+
this._close(entry);
|
|
14403
|
+
}
|
|
14404
|
+
});
|
|
14405
|
+
}
|
|
12969
14406
|
if (settings.closable) {
|
|
12970
14407
|
const close = h("button", {
|
|
12971
14408
|
class: "zx-icon-btn zx-message__close",
|
|
12972
14409
|
type: "button",
|
|
12973
|
-
ariaLabel: "Close message",
|
|
12974
|
-
title: "Close"
|
|
14410
|
+
ariaLabel: this._message("message.close", "Close message"),
|
|
14411
|
+
title: this._message("message.closeTitle", "Close")
|
|
12975
14412
|
}, icon("x", { size: 14 }));
|
|
12976
14413
|
node.append(close);
|
|
12977
14414
|
this.listen(close, "click", () => this._close(entry));
|
|
12978
14415
|
}
|
|
12979
|
-
this.listen(node, "mouseenter", () =>
|
|
12980
|
-
|
|
14416
|
+
this.listen(node, "mouseenter", () => {
|
|
14417
|
+
entry.hovered = true;
|
|
14418
|
+
this._pause(entry);
|
|
14419
|
+
});
|
|
14420
|
+
this.listen(node, "mouseleave", () => {
|
|
14421
|
+
entry.hovered = false;
|
|
14422
|
+
this._resume(entry);
|
|
14423
|
+
});
|
|
14424
|
+
this.listen(node, "focusin", (event) => {
|
|
14425
|
+
if (!entry.focused) {
|
|
14426
|
+
const from = (
|
|
14427
|
+
/** @type {FocusEvent} */
|
|
14428
|
+
event.relatedTarget
|
|
14429
|
+
);
|
|
14430
|
+
entry.returnFocus = isNode(from) && !node.contains(
|
|
14431
|
+
/** @type {Node} */
|
|
14432
|
+
from
|
|
14433
|
+
) ? from : null;
|
|
14434
|
+
}
|
|
14435
|
+
entry.focused = true;
|
|
14436
|
+
this._pause(entry);
|
|
14437
|
+
});
|
|
14438
|
+
this.listen(node, "focusout", (event) => {
|
|
14439
|
+
const to = (
|
|
14440
|
+
/** @type {FocusEvent} */
|
|
14441
|
+
event.relatedTarget
|
|
14442
|
+
);
|
|
14443
|
+
if (isNode(to) && node.contains(
|
|
14444
|
+
/** @type {Node} */
|
|
14445
|
+
to
|
|
14446
|
+
)) return;
|
|
14447
|
+
entry.focused = false;
|
|
14448
|
+
this._resume(entry);
|
|
14449
|
+
});
|
|
12981
14450
|
return entry;
|
|
12982
14451
|
}
|
|
12983
14452
|
/** @param {any} entry @returns {void} */
|
|
@@ -12989,7 +14458,7 @@ var Message = class _Message extends Component {
|
|
|
12989
14458
|
}
|
|
12990
14459
|
/** @param {any} entry @returns {void} */
|
|
12991
14460
|
_schedule(entry) {
|
|
12992
|
-
if (entry.closed || entry.remaining <= 0) return;
|
|
14461
|
+
if (entry.closed || entry.remaining <= 0 || entry.hovered || entry.focused) return;
|
|
12993
14462
|
entry.startedAt = Date.now();
|
|
12994
14463
|
entry.timer = setTimeout(() => this._close(entry), entry.remaining);
|
|
12995
14464
|
}
|
|
@@ -13002,7 +14471,7 @@ var Message = class _Message extends Component {
|
|
|
13002
14471
|
}
|
|
13003
14472
|
/** @param {any} entry @returns {void} */
|
|
13004
14473
|
_resume(entry) {
|
|
13005
|
-
if (entry.closed || entry.timer !== null) return;
|
|
14474
|
+
if (entry.closed || entry.timer !== null || entry.hovered || entry.focused) return;
|
|
13006
14475
|
if (entry.remaining <= 0) {
|
|
13007
14476
|
this._close(entry);
|
|
13008
14477
|
return;
|
|
@@ -13014,10 +14483,12 @@ var Message = class _Message extends Component {
|
|
|
13014
14483
|
if (entry.closed) return;
|
|
13015
14484
|
entry.closed = true;
|
|
13016
14485
|
clearEntryTimers(entry);
|
|
14486
|
+
returnFocus(entry);
|
|
13017
14487
|
if (!this._queue.isActive(entry)) {
|
|
13018
14488
|
this._queue.remove(entry);
|
|
13019
14489
|
entry.node.remove();
|
|
13020
14490
|
this._entries.delete(entry);
|
|
14491
|
+
this._releaseIfEmpty();
|
|
13021
14492
|
return;
|
|
13022
14493
|
}
|
|
13023
14494
|
entry.node.dataset.state = "closing";
|
|
@@ -13038,12 +14509,52 @@ var Message = class _Message extends Component {
|
|
|
13038
14509
|
entry.node.remove();
|
|
13039
14510
|
this._entries.delete(entry);
|
|
13040
14511
|
this._queue.remove(entry);
|
|
14512
|
+
this._releaseIfEmpty();
|
|
14513
|
+
}
|
|
14514
|
+
/**
|
|
14515
|
+
* Takes a floating region out of the document once its last toast has gone, so an emptied host
|
|
14516
|
+
* is not left holding a region nobody uses. Inline areas stay: their element is the caller's.
|
|
14517
|
+
* @returns {void}
|
|
14518
|
+
*/
|
|
14519
|
+
_releaseIfEmpty() {
|
|
14520
|
+
if (!this._floatingHost || this._entries.size > 0) return;
|
|
14521
|
+
_Message.#release(this);
|
|
14522
|
+
}
|
|
14523
|
+
/**
|
|
14524
|
+
* Destroys a floating region and removes its element.
|
|
14525
|
+
* @returns {void}
|
|
14526
|
+
*/
|
|
14527
|
+
_disposeFloating() {
|
|
14528
|
+
const region = this.el;
|
|
14529
|
+
this.destroy();
|
|
14530
|
+
region.remove();
|
|
14531
|
+
}
|
|
14532
|
+
/**
|
|
14533
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
14534
|
+
* @param {string} key Message key.
|
|
14535
|
+
* @param {string} fallback English default.
|
|
14536
|
+
* @returns {string}
|
|
14537
|
+
*/
|
|
14538
|
+
_message(key, fallback) {
|
|
14539
|
+
const message = this.msg(key);
|
|
14540
|
+
return message === key ? fallback : message;
|
|
13041
14541
|
}
|
|
13042
|
-
/**
|
|
14542
|
+
/**
|
|
14543
|
+
* Finds or creates the floating region for a scope. A cached region is reused only while it is
|
|
14544
|
+
* still where it was put: a host emptied by `replaceChildren()` would otherwise keep receiving
|
|
14545
|
+
* toasts in a node nobody can see.
|
|
14546
|
+
* @param {Element|string|null|undefined} scope
|
|
14547
|
+
* @returns {Message}
|
|
14548
|
+
*/
|
|
13043
14549
|
static #floatingRegion(scope2) {
|
|
13044
|
-
|
|
14550
|
+
let host = overlayHost(scope2 ?? null);
|
|
14551
|
+
if (!host.isConnected) host = overlayHost(null);
|
|
13045
14552
|
const existing = this.#floating.get(host);
|
|
13046
|
-
if (existing) return existing;
|
|
14553
|
+
if (existing && existing.el.isConnected && existing.el.parentElement === host) return existing;
|
|
14554
|
+
if (existing) {
|
|
14555
|
+
this.#floating.delete(host);
|
|
14556
|
+
existing._disposeFloating();
|
|
14557
|
+
}
|
|
13047
14558
|
const region = h("div", {
|
|
13048
14559
|
class: "zx-message-region",
|
|
13049
14560
|
popover: "manual",
|
|
@@ -13052,12 +14563,19 @@ var Message = class _Message extends Component {
|
|
|
13052
14563
|
});
|
|
13053
14564
|
host.append(region);
|
|
13054
14565
|
const floating = new _Message(region);
|
|
14566
|
+
floating._floatingHost = host;
|
|
13055
14567
|
this.#floating.set(host, floating);
|
|
13056
14568
|
if (typeof region.showPopover === "function") region.showPopover();
|
|
13057
14569
|
return floating;
|
|
13058
14570
|
}
|
|
14571
|
+
/** @param {Message} region Floating region whose last toast closed. @returns {void} */
|
|
14572
|
+
static #release(region) {
|
|
14573
|
+
const host = region._floatingHost;
|
|
14574
|
+
if (host && _Message.#floating.get(host) === region) _Message.#floating.delete(host);
|
|
14575
|
+
region._disposeFloating();
|
|
14576
|
+
}
|
|
13059
14577
|
};
|
|
13060
|
-
function
|
|
14578
|
+
function normalizeKind2(value) {
|
|
13061
14579
|
if (value === "danger") return "error";
|
|
13062
14580
|
return ["success", "warning", "error"].includes(String(value)) ? (
|
|
13063
14581
|
/** @type {MessageKind} */
|
|
@@ -13068,6 +14586,50 @@ function normalizeTimeout(value) {
|
|
|
13068
14586
|
const timeout = Number(value);
|
|
13069
14587
|
return Number.isFinite(timeout) ? Math.max(0, timeout) : 4e3;
|
|
13070
14588
|
}
|
|
14589
|
+
function messageTimeout(timeout, hasAction = false) {
|
|
14590
|
+
const settled = normalizeTimeout(timeout);
|
|
14591
|
+
return hasAction && settled > 0 ? Math.max(settled, MESSAGE_ACTION_MIN_TIMEOUT) : settled;
|
|
14592
|
+
}
|
|
14593
|
+
function normalizeMessageAction(value) {
|
|
14594
|
+
if (!value || typeof value !== "object") return null;
|
|
14595
|
+
const action = (
|
|
14596
|
+
/** @type {Record<string, unknown>} */
|
|
14597
|
+
value
|
|
14598
|
+
);
|
|
14599
|
+
const label = action.label == null ? "" : String(action.label).trim();
|
|
14600
|
+
if (!label) return null;
|
|
14601
|
+
const kind = ["primary", "danger", "ghost"].includes(String(action.kind)) ? (
|
|
14602
|
+
/** @type {'primary'|'danger'|'ghost'} */
|
|
14603
|
+
action.kind
|
|
14604
|
+
) : "default";
|
|
14605
|
+
return {
|
|
14606
|
+
label,
|
|
14607
|
+
kind,
|
|
14608
|
+
onclick: typeof action.onclick === "function" ? (
|
|
14609
|
+
/** @type {(event: MouseEvent) => void} */
|
|
14610
|
+
action.onclick
|
|
14611
|
+
) : null
|
|
14612
|
+
};
|
|
14613
|
+
}
|
|
14614
|
+
function resolveLeading(value) {
|
|
14615
|
+
if (isNode(value)) return (
|
|
14616
|
+
/** @type {Node} */
|
|
14617
|
+
value
|
|
14618
|
+
);
|
|
14619
|
+
if (value && typeof value === "object" && typeof value.toElement === "function") {
|
|
14620
|
+
const element = value.toElement();
|
|
14621
|
+
return isNode(element) ? element : null;
|
|
14622
|
+
}
|
|
14623
|
+
return null;
|
|
14624
|
+
}
|
|
14625
|
+
function returnFocus(entry) {
|
|
14626
|
+
const root = entry.node.getRootNode?.();
|
|
14627
|
+
const active = root?.activeElement ?? globalThis.document?.activeElement;
|
|
14628
|
+
if (!active || !entry.node.contains(active)) return;
|
|
14629
|
+
const target = entry.returnFocus;
|
|
14630
|
+
entry.returnFocus = null;
|
|
14631
|
+
if (target?.isConnected && typeof target.focus === "function") target.focus({ preventScroll: true });
|
|
14632
|
+
}
|
|
13071
14633
|
function normalizeLimit(value) {
|
|
13072
14634
|
const limit = Number(value);
|
|
13073
14635
|
return Number.isInteger(limit) && limit > 0 ? limit : 5;
|
|
@@ -13103,7 +14665,7 @@ function snapshot2(element) {
|
|
|
13103
14665
|
}
|
|
13104
14666
|
function restore2(element, state) {
|
|
13105
14667
|
for (const attribute of Array.from(element.attributes)) element.removeAttribute(attribute.name);
|
|
13106
|
-
for (const [
|
|
14668
|
+
for (const [name2, value] of state.attributes) element.setAttribute(name2, value);
|
|
13107
14669
|
element.replaceChildren(...state.children);
|
|
13108
14670
|
}
|
|
13109
14671
|
|
|
@@ -13472,7 +15034,7 @@ var Calendar = class extends Component {
|
|
|
13472
15034
|
if (!this.el) this.el = root;
|
|
13473
15035
|
this._createdRoot = createdRoot;
|
|
13474
15036
|
this._original = this._createdRoot ? null : {
|
|
13475
|
-
attributes: Array.from(root.attributes).map(({ name, value }) => [
|
|
15037
|
+
attributes: Array.from(root.attributes).map(({ name: name2, value }) => [name2, value]),
|
|
13476
15038
|
children: Array.from(root.childNodes)
|
|
13477
15039
|
};
|
|
13478
15040
|
this._views = normalizeViews(this.options.views);
|
|
@@ -13506,7 +15068,7 @@ var Calendar = class extends Component {
|
|
|
13506
15068
|
ref: "views",
|
|
13507
15069
|
class: "zx-calendar__views",
|
|
13508
15070
|
role: "group",
|
|
13509
|
-
ariaLabel: "Calendar view"
|
|
15071
|
+
ariaLabel: this._message("calendar.viewSwitch", "Calendar view")
|
|
13510
15072
|
}, this._views.map((view) => h("button", {
|
|
13511
15073
|
type: "button",
|
|
13512
15074
|
class: "zx-calendar__view-button",
|
|
@@ -13682,7 +15244,7 @@ var Calendar = class extends Component {
|
|
|
13682
15244
|
super.destroy();
|
|
13683
15245
|
if (!this._createdRoot && original) {
|
|
13684
15246
|
for (const attribute of Array.from(this.el.attributes)) this.el.removeAttribute(attribute.name);
|
|
13685
|
-
for (const [
|
|
15247
|
+
for (const [name2, value] of original.attributes) this.el.setAttribute(name2, value);
|
|
13686
15248
|
this.el.replaceChildren(...original.children);
|
|
13687
15249
|
}
|
|
13688
15250
|
}
|
|
@@ -13724,8 +15286,8 @@ var Calendar = class extends Component {
|
|
|
13724
15286
|
});
|
|
13725
15287
|
this._range = range;
|
|
13726
15288
|
this.refs.heading.textContent = this._rangeTitle(range);
|
|
13727
|
-
for (const
|
|
13728
|
-
|
|
15289
|
+
for (const button2 of this.refs.views.querySelectorAll("[data-view]")) {
|
|
15290
|
+
button2.setAttribute("aria-pressed", String(button2.dataset.view === this._view));
|
|
13729
15291
|
}
|
|
13730
15292
|
const content = this._view === "agenda" ? this._renderAgenda(range) : this._view === "day" || this._view === "week" ? this._renderTimeGrid(range) : this._view === "month" ? this._renderMonth(range) : this._renderYear(range);
|
|
13731
15293
|
this.refs.body.replaceChildren(content);
|
|
@@ -13954,7 +15516,7 @@ var Calendar = class extends Component {
|
|
|
13954
15516
|
eventCount: String(count)
|
|
13955
15517
|
},
|
|
13956
15518
|
ariaCurrent: sameCalendarDay(day, this._now()) ? "date" : null,
|
|
13957
|
-
ariaLabel:
|
|
15519
|
+
ariaLabel: this._dayCountLabel(day, count),
|
|
13958
15520
|
disabled: this.options.disabled
|
|
13959
15521
|
}, this._format(day, { day: "numeric" })));
|
|
13960
15522
|
}
|
|
@@ -14024,7 +15586,7 @@ var Calendar = class extends Component {
|
|
|
14024
15586
|
activity: String(Math.min(3, count))
|
|
14025
15587
|
},
|
|
14026
15588
|
ariaCurrent: sameCalendarDay(day, this._now()) ? "date" : null,
|
|
14027
|
-
ariaLabel:
|
|
15589
|
+
ariaLabel: this._dayCountLabel(day, count),
|
|
14028
15590
|
disabled: this.options.disabled
|
|
14029
15591
|
}, String(day.getDate())));
|
|
14030
15592
|
}
|
|
@@ -14049,7 +15611,7 @@ var Calendar = class extends Component {
|
|
|
14049
15611
|
},
|
|
14050
15612
|
style: event.color ? { "--zx-calendar-event-color": event.color } : null
|
|
14051
15613
|
});
|
|
14052
|
-
const
|
|
15614
|
+
const button2 = h("button", {
|
|
14053
15615
|
type: "button",
|
|
14054
15616
|
class: "zx-calendar__event-action",
|
|
14055
15617
|
dataset: { eventAction: "activate", eventId: key },
|
|
@@ -14057,15 +15619,15 @@ var Calendar = class extends Component {
|
|
|
14057
15619
|
disabled: this.options.disabled
|
|
14058
15620
|
});
|
|
14059
15621
|
const custom = typeof this.options.renderEvent === "function" ? this.options.renderEvent(cloneCalendarEvent(event)) : null;
|
|
14060
|
-
if (custom instanceof Node)
|
|
14061
|
-
else if (typeof custom === "string")
|
|
15622
|
+
if (custom instanceof Node) button2.append(custom);
|
|
15623
|
+
else if (typeof custom === "string") button2.append(document.createTextNode(custom));
|
|
14062
15624
|
else {
|
|
14063
15625
|
const time = h("span", { class: "zx-calendar__event-time" }, this._eventTime(event, context.day));
|
|
14064
15626
|
const title = h("span", { class: "zx-calendar__event-title" }, event.title);
|
|
14065
|
-
|
|
14066
|
-
if (event.location)
|
|
15627
|
+
button2.append(time, title);
|
|
15628
|
+
if (event.location) button2.append(h("span", { class: "zx-calendar__event-location" }, event.location));
|
|
14067
15629
|
}
|
|
14068
|
-
wrapper.append(
|
|
15630
|
+
wrapper.append(button2);
|
|
14069
15631
|
if (context.resizable && this._canResize(event)) {
|
|
14070
15632
|
wrapper.append(h("button", {
|
|
14071
15633
|
type: "button",
|
|
@@ -14755,6 +16317,31 @@ var Calendar = class extends Component {
|
|
|
14755
16317
|
if (!this._destroyed) this.refs.status.textContent = message;
|
|
14756
16318
|
});
|
|
14757
16319
|
}
|
|
16320
|
+
/**
|
|
16321
|
+
* Names a month or year cell by its date and how many events it holds. Singular and plural are
|
|
16322
|
+
* separate keys because a language that inflects the noun cannot reach it from one template.
|
|
16323
|
+
* @param {Date} day Day the cell stands for.
|
|
16324
|
+
* @param {number} count Events on that day.
|
|
16325
|
+
* @returns {string}
|
|
16326
|
+
*/
|
|
16327
|
+
_dayCountLabel(day, count) {
|
|
16328
|
+
const date = this._format(day, { dateStyle: "full" });
|
|
16329
|
+
return count === 1 ? this._message("calendar.dayEvent", "%1, %2 event", date, count) : this._message("calendar.dayEvents", "%1, %2 events", date, count);
|
|
16330
|
+
}
|
|
16331
|
+
/**
|
|
16332
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
16333
|
+
*
|
|
16334
|
+
* Distinct from `msg()`: the built-in `msg` option answers the calendar's own vocabulary, so a
|
|
16335
|
+
* dotted key falls past it to the host translator, which is what these strings never had.
|
|
16336
|
+
* @param {string} key Message key.
|
|
16337
|
+
* @param {string} fallback Built-in text, with `%1`-style placeholders.
|
|
16338
|
+
* @param {...unknown} args Interpolation values.
|
|
16339
|
+
* @returns {string}
|
|
16340
|
+
*/
|
|
16341
|
+
_message(key, fallback, ...args) {
|
|
16342
|
+
const message = this.msg(key, ...args);
|
|
16343
|
+
return message === key ? printf(fallback, args) : message;
|
|
16344
|
+
}
|
|
14758
16345
|
};
|
|
14759
16346
|
function normalizeViews(value) {
|
|
14760
16347
|
if (!Array.isArray(value) || value.length === 0) throw new TypeError("Calendar views must be a non-empty array");
|
|
@@ -14867,7 +16454,7 @@ function cssEscape(value) {
|
|
|
14867
16454
|
var Fieldset = class extends Component {
|
|
14868
16455
|
static cssName = "fieldset";
|
|
14869
16456
|
/** @type {FieldsetOptions} */
|
|
14870
|
-
static defaults = { title: "", columns: 1, fields: {} };
|
|
16457
|
+
static defaults = { title: "", columns: 1, fields: {}, idPrefix: null };
|
|
14871
16458
|
/** @returns {HTMLElement} */
|
|
14872
16459
|
render() {
|
|
14873
16460
|
const root = (
|
|
@@ -14879,6 +16466,7 @@ var Fieldset = class extends Component {
|
|
|
14879
16466
|
this._origins = /* @__PURE__ */ new Map();
|
|
14880
16467
|
this._fieldIdAttributes = /* @__PURE__ */ new Map();
|
|
14881
16468
|
this._ownedNodes = [];
|
|
16469
|
+
this._idPrefix = this.options.idPrefix ? String(this.options.idPrefix) : uid("zx-fieldset");
|
|
14882
16470
|
this._columnAttribute = root.getAttribute("data-columns");
|
|
14883
16471
|
const columns = [1, 2, 3].includes(Number(this.options.columns)) ? Number(this.options.columns) : 1;
|
|
14884
16472
|
root.dataset.columns = String(columns);
|
|
@@ -14895,7 +16483,9 @@ var Fieldset = class extends Component {
|
|
|
14895
16483
|
return root;
|
|
14896
16484
|
}
|
|
14897
16485
|
/**
|
|
14898
|
-
* Adds a field from options, an existing field, an element, or a component.
|
|
16486
|
+
* Adds a field from options, an existing field, an element, or a component. The key becomes the
|
|
16487
|
+
* field's `name` and its `data-field-id`; the control's DOM id is `<idPrefix>-<key>`, unless the
|
|
16488
|
+
* field options give an `id` of their own that differs from the key.
|
|
14899
16489
|
* @param {string} id Logical field identifier.
|
|
14900
16490
|
* @param {FieldOptions|Field|Element|Component} field Field source.
|
|
14901
16491
|
* @returns {Field}
|
|
@@ -14910,7 +16500,8 @@ var Fieldset = class extends Component {
|
|
|
14910
16500
|
} else if (isElement(field) || field instanceof Component) {
|
|
14911
16501
|
const source = field;
|
|
14912
16502
|
instance = new Field(null, {
|
|
14913
|
-
id: key,
|
|
16503
|
+
id: this._controlId(key),
|
|
16504
|
+
name: key,
|
|
14914
16505
|
type: "custom",
|
|
14915
16506
|
label: key,
|
|
14916
16507
|
value: readExternalValue(source),
|
|
@@ -14920,7 +16511,12 @@ var Fieldset = class extends Component {
|
|
|
14920
16511
|
owned = true;
|
|
14921
16512
|
} else {
|
|
14922
16513
|
const options = field && typeof field === "object" ? field : {};
|
|
14923
|
-
|
|
16514
|
+
const explicit = options.id != null && String(options.id) !== "" && String(options.id) !== key;
|
|
16515
|
+
instance = new Field(null, {
|
|
16516
|
+
...options,
|
|
16517
|
+
id: explicit ? String(options.id) : this._controlId(key),
|
|
16518
|
+
name: options.name ?? key
|
|
16519
|
+
});
|
|
14924
16520
|
owned = true;
|
|
14925
16521
|
}
|
|
14926
16522
|
if (!owned) {
|
|
@@ -15050,6 +16646,14 @@ var Fieldset = class extends Component {
|
|
|
15050
16646
|
for (const field of this._fields.values()) field.clearHighlight();
|
|
15051
16647
|
return this;
|
|
15052
16648
|
}
|
|
16649
|
+
/**
|
|
16650
|
+
* The DOM id generated for a field key: unique per instance unless `idPrefix` was given.
|
|
16651
|
+
* @param {string} key Field key.
|
|
16652
|
+
* @returns {string}
|
|
16653
|
+
*/
|
|
16654
|
+
_controlId(key) {
|
|
16655
|
+
return `${this._idPrefix}-${key.trim().replace(/\s+/g, "-")}`;
|
|
16656
|
+
}
|
|
15053
16657
|
/** @param {Field} field @returns {void} */
|
|
15054
16658
|
_releaseField(field) {
|
|
15055
16659
|
const fieldId = this._fieldIdAttributes.get(field);
|
|
@@ -15082,7 +16686,7 @@ function externalAdapter(source) {
|
|
|
15082
16686
|
const el = isElement(source) ? source : source.toElement();
|
|
15083
16687
|
const parent = el.parentNode;
|
|
15084
16688
|
const next = el.nextSibling;
|
|
15085
|
-
const attributes = new Map(["id", "aria-labelledby", "aria-describedby", "aria-disabled", "aria-invalid"].map((
|
|
16689
|
+
const attributes = new Map(["id", "aria-labelledby", "aria-describedby", "aria-disabled", "aria-invalid"].map((name2) => [name2, el.getAttribute(name2)]));
|
|
15086
16690
|
const originalDisabled = "disabled" in el ? el.disabled : void 0;
|
|
15087
16691
|
const originalValue = "value" in el ? el.value : void 0;
|
|
15088
16692
|
return {
|
|
@@ -15108,9 +16712,9 @@ function externalAdapter(source) {
|
|
|
15108
16712
|
else el.setAttribute("aria-disabled", String(disabled));
|
|
15109
16713
|
},
|
|
15110
16714
|
destroy: () => {
|
|
15111
|
-
for (const [
|
|
15112
|
-
if (value === null) el.removeAttribute(
|
|
15113
|
-
else el.setAttribute(
|
|
16715
|
+
for (const [name2, value] of attributes) {
|
|
16716
|
+
if (value === null) el.removeAttribute(name2);
|
|
16717
|
+
else el.setAttribute(name2, value);
|
|
15114
16718
|
}
|
|
15115
16719
|
if (originalDisabled !== void 0) el.disabled = originalDisabled;
|
|
15116
16720
|
if (originalValue !== void 0) el.value = originalValue;
|
|
@@ -15138,6 +16742,7 @@ var Form = class extends Component {
|
|
|
15138
16742
|
fieldsets: [],
|
|
15139
16743
|
actions: [],
|
|
15140
16744
|
novalidate: true,
|
|
16745
|
+
idPrefix: null,
|
|
15141
16746
|
msg: {
|
|
15142
16747
|
"form.required": "This field is required.",
|
|
15143
16748
|
"form.int": "Enter a whole number.",
|
|
@@ -15154,6 +16759,7 @@ var Form = class extends Component {
|
|
|
15154
16759
|
this._ownedFieldsets = /* @__PURE__ */ new Set();
|
|
15155
16760
|
this._origins = /* @__PURE__ */ new Map();
|
|
15156
16761
|
this._ownedNodes = [];
|
|
16762
|
+
this._idPrefix = this.options.idPrefix ? String(this.options.idPrefix) : uid("zx-form");
|
|
15157
16763
|
this._novalidateAttribute = root.getAttribute("novalidate");
|
|
15158
16764
|
root.toggleAttribute("novalidate", Boolean(this.options.novalidate));
|
|
15159
16765
|
this._body = h("div", { class: "zx-form__body" });
|
|
@@ -15175,13 +16781,14 @@ var Form = class extends Component {
|
|
|
15175
16781
|
return root;
|
|
15176
16782
|
}
|
|
15177
16783
|
/**
|
|
15178
|
-
* Adds an existing fieldset or constructs one from options.
|
|
16784
|
+
* Adds an existing fieldset or constructs one from options. A constructed fieldset generates its
|
|
16785
|
+
* field ids from the form's `idPrefix` unless its options carry their own.
|
|
15179
16786
|
* @param {Fieldset|import('../fieldset/fieldset.js').FieldsetOptions} fieldset Fieldset source.
|
|
15180
16787
|
* @returns {Fieldset}
|
|
15181
16788
|
*/
|
|
15182
16789
|
addFieldset(fieldset) {
|
|
15183
16790
|
const owned = !(fieldset instanceof Fieldset);
|
|
15184
|
-
const instance = owned ? new Fieldset(null, fieldset ?? {}) : fieldset;
|
|
16791
|
+
const instance = owned ? new Fieldset(null, { ...fieldset ?? {}, idPrefix: fieldset?.idPrefix ?? this._idPrefix }) : fieldset;
|
|
15185
16792
|
if (this._fieldsets.includes(instance)) return instance;
|
|
15186
16793
|
if (owned) this._ownedFieldsets.add(instance);
|
|
15187
16794
|
else this._origins.set(instance, { parent: instance.el.parentNode, next: instance.el.nextSibling });
|
|
@@ -15339,9 +16946,9 @@ var Form = class extends Component {
|
|
|
15339
16946
|
}
|
|
15340
16947
|
/** @param {Event} event @returns {void} */
|
|
15341
16948
|
_handleAction(event) {
|
|
15342
|
-
const
|
|
15343
|
-
if (!
|
|
15344
|
-
const action = this._actionDescriptors[Number(
|
|
16949
|
+
const button2 = event.target instanceof Element ? event.target.closest("[data-action-index]") : null;
|
|
16950
|
+
if (!button2 || !this._actions.contains(button2)) return;
|
|
16951
|
+
const action = this._actionDescriptors[Number(button2.dataset.actionIndex)];
|
|
15345
16952
|
const callback = action?.onClick ?? action?.onclick ?? action?.handler;
|
|
15346
16953
|
if (typeof callback === "function") callback(event, this);
|
|
15347
16954
|
}
|
|
@@ -15373,6 +16980,7 @@ function isEmpty(value) {
|
|
|
15373
16980
|
function registerFieldAdapters() {
|
|
15374
16981
|
registerSelectFieldAdapter();
|
|
15375
16982
|
registerChecklistFieldAdapter();
|
|
16983
|
+
registerCodeEditorFieldAdapter();
|
|
15376
16984
|
registerDateboxFieldAdapters();
|
|
15377
16985
|
registerDatePickerFieldAdapters();
|
|
15378
16986
|
registerDateRangeFieldAdapter();
|
|
@@ -15433,16 +17041,16 @@ function deriveLocale(client) {
|
|
|
15433
17041
|
return client.locale ?? client.language ?? client.config?.locale ?? client.metadata?.locale ?? null;
|
|
15434
17042
|
}
|
|
15435
17043
|
function operationFor(client, action, resource) {
|
|
15436
|
-
const
|
|
15437
|
-
if (!
|
|
15438
|
-
const resourceOperations = typeof client.schema?.operations === "function" ? client.schema.operations(
|
|
17044
|
+
const name2 = String(resource ?? "").trim();
|
|
17045
|
+
if (!name2) throw new TypeError("ZeyOS resource must not be empty");
|
|
17046
|
+
const resourceOperations = typeof client.schema?.operations === "function" ? client.schema.operations(name2) : [];
|
|
15439
17047
|
if (Array.isArray(resourceOperations) && resourceOperations.length) {
|
|
15440
17048
|
const exactResourceMatches = resourceOperations.filter((operation) => typeof operation === "string" && operation.toLowerCase().startsWith(action)).sort((left, right) => left.length - right.length);
|
|
15441
17049
|
if (exactResourceMatches.length) return exactResourceMatches[0];
|
|
15442
17050
|
}
|
|
15443
17051
|
const known = Array.isArray(resourceOperations) && resourceOperations.length ? resourceOperations : typeof client.schema?.operationIds === "function" ? client.schema.operationIds() : Object.keys(client.api);
|
|
15444
|
-
if (known.includes(
|
|
15445
|
-
const normalizedResource = normalizeResource(
|
|
17052
|
+
if (known.includes(name2) && name2.toLowerCase().startsWith(action)) return name2;
|
|
17053
|
+
const normalizedResource = normalizeResource(name2);
|
|
15446
17054
|
const singular = singularize(normalizedResource);
|
|
15447
17055
|
const matches = known.filter((operation) => {
|
|
15448
17056
|
if (typeof operation !== "string" || !operation.toLowerCase().startsWith(action)) return false;
|
|
@@ -15450,11 +17058,11 @@ function operationFor(client, action, resource) {
|
|
|
15450
17058
|
return suffix === normalizedResource || suffix === singular || singularize(suffix) === singular;
|
|
15451
17059
|
});
|
|
15452
17060
|
if (matches.length) return matches.sort((left, right) => left.length - right.length)[0];
|
|
15453
|
-
const candidates = action === "list" ? [`list${pascalCase(
|
|
17061
|
+
const candidates = action === "list" ? [`list${pascalCase(name2)}`] : [`${action}${pascalCase(singularizeName(name2))}`, `${action}${pascalCase(name2)}`];
|
|
15454
17062
|
const apiKeys = new Set(Object.keys(client.api));
|
|
15455
17063
|
const fallback = candidates.find((candidate) => apiKeys.has(candidate));
|
|
15456
17064
|
if (fallback) return fallback;
|
|
15457
|
-
throw new RangeError(`No ${action} operation found for ZeyOS resource "${
|
|
17065
|
+
throw new RangeError(`No ${action} operation found for ZeyOS resource "${name2}"`);
|
|
15458
17066
|
}
|
|
15459
17067
|
function isRecord(value) {
|
|
15460
17068
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -15590,31 +17198,31 @@ var moduleAliases = Object.freeze({
|
|
|
15590
17198
|
});
|
|
15591
17199
|
var glyphColors = Object.freeze({ light: "#ffffff", dark: "#141414" });
|
|
15592
17200
|
var overrides = /* @__PURE__ */ Object.create(null);
|
|
15593
|
-
function normalizeModuleName(
|
|
15594
|
-
const key = String(
|
|
17201
|
+
function normalizeModuleName(name2) {
|
|
17202
|
+
const key = String(name2 ?? "").trim().toLowerCase().replaceAll(/[._\s]+/g, "-");
|
|
15595
17203
|
if (!key) return "default";
|
|
15596
17204
|
if (Object.hasOwn(overrides, key) || Object.hasOwn(zeyosModules, key)) return key;
|
|
15597
17205
|
const alias = moduleAliases[key];
|
|
15598
17206
|
if (alias) return alias;
|
|
15599
17207
|
return "default";
|
|
15600
17208
|
}
|
|
15601
|
-
function moduleInfo(
|
|
15602
|
-
const key = normalizeModuleName(
|
|
17209
|
+
function moduleInfo(name2) {
|
|
17210
|
+
const key = normalizeModuleName(name2);
|
|
15603
17211
|
return overrides[key] ?? zeyosModules[key] ?? zeyosModules.default;
|
|
15604
17212
|
}
|
|
15605
|
-
function moduleColor(
|
|
15606
|
-
return moduleInfo(
|
|
17213
|
+
function moduleColor(name2) {
|
|
17214
|
+
return moduleInfo(name2).color;
|
|
15607
17215
|
}
|
|
15608
|
-
function moduleIconName(
|
|
15609
|
-
const info = moduleInfo(
|
|
17216
|
+
function moduleIconName(name2, { standard = false } = {}) {
|
|
17217
|
+
const info = moduleInfo(name2);
|
|
15610
17218
|
return standard ? info.fa : info.icon;
|
|
15611
17219
|
}
|
|
15612
17220
|
function moduleKeys() {
|
|
15613
17221
|
return [.../* @__PURE__ */ new Set([...Object.keys(zeyosModules), ...Object.keys(overrides)])].sort();
|
|
15614
17222
|
}
|
|
15615
17223
|
function registerModules(modules) {
|
|
15616
|
-
for (const [
|
|
15617
|
-
const key = String(
|
|
17224
|
+
for (const [name2, value] of Object.entries(modules)) {
|
|
17225
|
+
const key = String(name2).trim().toLowerCase().replaceAll(/[._\s]+/g, "-");
|
|
15618
17226
|
const patch = typeof value === "string" ? { color: value } : value;
|
|
15619
17227
|
const base = overrides[key] ?? zeyosModules[key] ?? zeyosModules.default;
|
|
15620
17228
|
overrides[key] = Object.freeze({
|
|
@@ -15651,12 +17259,12 @@ var ZEYOS_ICON_KIT = "https://kit.fontawesome.com/ae8320b210.js";
|
|
|
15651
17259
|
function useZeyosIcons(options = {}) {
|
|
15652
17260
|
return loadFontAwesome({ kit: ZEYOS_ICON_KIT, ...options });
|
|
15653
17261
|
}
|
|
15654
|
-
function moduleIcon(
|
|
17262
|
+
function moduleIcon(name2, options = {}) {
|
|
15655
17263
|
const { standard = false, ...rest } = options;
|
|
15656
|
-
const info = moduleInfo(
|
|
17264
|
+
const info = moduleInfo(name2);
|
|
15657
17265
|
return icon(standard ? `fa:${info.fa}` : `kit:${info.icon}`, rest);
|
|
15658
17266
|
}
|
|
15659
|
-
function moduleChip(
|
|
17267
|
+
function moduleChip(name2, options = {}) {
|
|
15660
17268
|
const {
|
|
15661
17269
|
size = 24,
|
|
15662
17270
|
iconSize = "52%",
|
|
@@ -15667,13 +17275,13 @@ function moduleChip(name, options = {}) {
|
|
|
15667
17275
|
badge = null,
|
|
15668
17276
|
selected = false
|
|
15669
17277
|
} = options;
|
|
15670
|
-
const key = normalizeModuleName(
|
|
15671
|
-
const info = moduleInfo(
|
|
17278
|
+
const key = normalizeModuleName(name2);
|
|
17279
|
+
const info = moduleInfo(name2);
|
|
15672
17280
|
const background = isCssColor(color) ? color : info.color;
|
|
15673
17281
|
const chip = appIcon({
|
|
15674
17282
|
// AppIcon owns glyph sizing. Keep the provider glyph at 1em so the percentage is not applied
|
|
15675
17283
|
// once to the wrapper and a second time to a Font Awesome <i>.
|
|
15676
|
-
icon: options.icon ?? moduleIcon(
|
|
17284
|
+
icon: options.icon ?? moduleIcon(name2, { size: "1em", standard }),
|
|
15677
17285
|
size,
|
|
15678
17286
|
iconSize,
|
|
15679
17287
|
color: background,
|
|
@@ -15691,8 +17299,8 @@ function moduleChip(name, options = {}) {
|
|
|
15691
17299
|
if (title) chip.title = info.label;
|
|
15692
17300
|
return chip;
|
|
15693
17301
|
}
|
|
15694
|
-
function zeyosAppIcon(
|
|
15695
|
-
return moduleChip(
|
|
17302
|
+
function zeyosAppIcon(name2, options = {}) {
|
|
17303
|
+
return moduleChip(name2, { shape: "circle", ...options });
|
|
15696
17304
|
}
|
|
15697
17305
|
|
|
15698
17306
|
// src/zeyos/launcher.js
|
|
@@ -16193,8 +17801,12 @@ function buildZeyosFormConfig(client, resource, opts = {}) {
|
|
|
16193
17801
|
const fieldMeta = resolveFields(client, resource, opts);
|
|
16194
17802
|
const fields = {};
|
|
16195
17803
|
const entityFields = [];
|
|
17804
|
+
const dateKinds = /* @__PURE__ */ new Map();
|
|
16196
17805
|
for (const meta of fieldMeta) {
|
|
16197
17806
|
const descriptor = fieldToZxField(meta);
|
|
17807
|
+
if (descriptor.type === "date" || descriptor.type === "datetime") {
|
|
17808
|
+
dateKinds.set(String(meta.id), descriptor.type);
|
|
17809
|
+
}
|
|
16198
17810
|
const referencedResource2 = descriptor.type === "zxselect" && typeof descriptor.props?.entity === "string" ? descriptor.props.entity : null;
|
|
16199
17811
|
if (referencedResource2) {
|
|
16200
17812
|
entityFields.push({ id: String(meta.id), resource: referencedResource2 });
|
|
@@ -16218,16 +17830,20 @@ function buildZeyosFormConfig(client, resource, opts = {}) {
|
|
|
16218
17830
|
fields
|
|
16219
17831
|
}]
|
|
16220
17832
|
},
|
|
16221
|
-
mapFromRecord: (record) => mapFromRecord(record, fieldMeta),
|
|
16222
|
-
mapToRecord: (values) => mapToRecord(values, fieldMeta)
|
|
17833
|
+
mapFromRecord: (record) => mapFromRecord(record, fieldMeta, dateKinds),
|
|
17834
|
+
mapToRecord: (values) => mapToRecord(values, fieldMeta, dateKinds)
|
|
16223
17835
|
};
|
|
16224
17836
|
}
|
|
16225
17837
|
function zeyosForm(client, resource, opts = {}) {
|
|
16226
17838
|
if (opts.onSaved != null && typeof opts.onSaved !== "function") {
|
|
16227
17839
|
throw new TypeError("zeyosForm onSaved must be a function");
|
|
16228
17840
|
}
|
|
17841
|
+
const notify = opts.notify !== false;
|
|
16229
17842
|
const config2 = buildZeyosFormConfig(client, resource, opts);
|
|
16230
|
-
const
|
|
17843
|
+
const toastScope = () => opts.scope ?? form.el;
|
|
17844
|
+
const facade = connect(client, {
|
|
17845
|
+
onError: (error) => notify ? Message.error(errorMessage(error), { scope: toastScope() }) : void 0
|
|
17846
|
+
});
|
|
16231
17847
|
const form = new Form(null, config2.formOptions);
|
|
16232
17848
|
let currentId = opts.value?.ID ?? opts.id ?? null;
|
|
16233
17849
|
let destroyed = false;
|
|
@@ -16257,6 +17873,7 @@ function zeyosForm(client, resource, opts = {}) {
|
|
|
16257
17873
|
if (destroyed) return Promise.reject(new Error("Cannot save a destroyed ZeyOS form"));
|
|
16258
17874
|
if (savePending) return savePending;
|
|
16259
17875
|
if (!form.submit()) return Promise.resolve(null);
|
|
17876
|
+
const host = notify ? overlayHost(toastScope()) : null;
|
|
16260
17877
|
savePending = (async () => {
|
|
16261
17878
|
let payload;
|
|
16262
17879
|
try {
|
|
@@ -16277,7 +17894,7 @@ function zeyosForm(client, resource, opts = {}) {
|
|
|
16277
17894
|
throw error;
|
|
16278
17895
|
}
|
|
16279
17896
|
}
|
|
16280
|
-
Message.success(`${recordLabel(record, resource)} saved successfully
|
|
17897
|
+
if (host) Message.success(`${recordLabel(record, resource)} saved successfully.`, { scope: host });
|
|
16281
17898
|
return record;
|
|
16282
17899
|
})().finally(() => {
|
|
16283
17900
|
savePending = null;
|
|
@@ -16298,25 +17915,39 @@ function zeyosForm(client, resource, opts = {}) {
|
|
|
16298
17915
|
}
|
|
16299
17916
|
};
|
|
16300
17917
|
}
|
|
16301
|
-
function mapFromRecord(record, meta) {
|
|
17918
|
+
function mapFromRecord(record, meta, dateKinds) {
|
|
16302
17919
|
const values = {};
|
|
16303
17920
|
for (const field of meta) {
|
|
16304
17921
|
const id = String(field.id);
|
|
16305
17922
|
const value = record[id];
|
|
16306
|
-
|
|
17923
|
+
const kind = dateKinds.get(id);
|
|
17924
|
+
if (!kind || value == null || value === "") values[id] = value;
|
|
17925
|
+
else if (kind === "date") values[id] = unixSecondsToCalendarDay(
|
|
17926
|
+
/** @type {number|string} */
|
|
17927
|
+
value,
|
|
17928
|
+
field.timeZone
|
|
17929
|
+
);
|
|
17930
|
+
else values[id] = unixSecondsToDate(
|
|
16307
17931
|
/** @type {number|string} */
|
|
16308
17932
|
value
|
|
16309
|
-
)
|
|
17933
|
+
);
|
|
16310
17934
|
}
|
|
16311
17935
|
return values;
|
|
16312
17936
|
}
|
|
16313
|
-
function mapToRecord(values, meta) {
|
|
17937
|
+
function mapToRecord(values, meta, dateKinds) {
|
|
16314
17938
|
const record = {};
|
|
16315
17939
|
for (const field of meta) {
|
|
16316
17940
|
const id = String(field.id);
|
|
16317
17941
|
let value = values[id];
|
|
16318
|
-
|
|
16319
|
-
|
|
17942
|
+
const kind = dateKinds.get(id);
|
|
17943
|
+
if (kind) {
|
|
17944
|
+
if (value == null || value === "") value = null;
|
|
17945
|
+
else if (kind === "date") value = calendarDayToUnixSeconds(
|
|
17946
|
+
/** @type {Date} */
|
|
17947
|
+
value,
|
|
17948
|
+
field.timeZone
|
|
17949
|
+
);
|
|
17950
|
+
else value = dateToUnixSeconds(
|
|
16320
17951
|
/** @type {Date} */
|
|
16321
17952
|
value
|
|
16322
17953
|
);
|
|
@@ -16328,10 +17959,6 @@ function mapToRecord(values, meta) {
|
|
|
16328
17959
|
}
|
|
16329
17960
|
return record;
|
|
16330
17961
|
}
|
|
16331
|
-
function isDateField(meta) {
|
|
16332
|
-
const descriptor = fieldToZxField(meta);
|
|
16333
|
-
return descriptor.type === "date" || descriptor.type === "datetime";
|
|
16334
|
-
}
|
|
16335
17962
|
function hasEnum(meta) {
|
|
16336
17963
|
return meta.enums != null || meta.enum != null;
|
|
16337
17964
|
}
|
|
@@ -16361,10 +17988,34 @@ function recordLabel(record, resource) {
|
|
|
16361
17988
|
}
|
|
16362
17989
|
|
|
16363
17990
|
// src/zeyos/table.js
|
|
17991
|
+
var TABLE_OPTION_KEYS = [
|
|
17992
|
+
"variant",
|
|
17993
|
+
"zebra",
|
|
17994
|
+
"stickyHeader",
|
|
17995
|
+
"responsive",
|
|
17996
|
+
"growing",
|
|
17997
|
+
"emptyText",
|
|
17998
|
+
"rowClass",
|
|
17999
|
+
"rowKind",
|
|
18000
|
+
"rowKinds",
|
|
18001
|
+
"columnVisibility",
|
|
18002
|
+
"columnReorder",
|
|
18003
|
+
"hiddenColumns",
|
|
18004
|
+
"onrowdblclick",
|
|
18005
|
+
"onsort",
|
|
18006
|
+
"onselectionchange",
|
|
18007
|
+
"ondatachange",
|
|
18008
|
+
"onstackedchange",
|
|
18009
|
+
"ongrow",
|
|
18010
|
+
"oncolumnvisibilitychange",
|
|
18011
|
+
"oncolumnorderchange"
|
|
18012
|
+
];
|
|
16364
18013
|
function buildZeyosTableConfig(client, resource, opts = {}) {
|
|
16365
18014
|
const fieldMeta = resolveFields(client, resource, {
|
|
16366
18015
|
fields: opts.fields,
|
|
16367
|
-
labels: opts.labels
|
|
18016
|
+
labels: opts.labels,
|
|
18017
|
+
formats: opts.formats,
|
|
18018
|
+
timeZone: opts.timeZone
|
|
16368
18019
|
});
|
|
16369
18020
|
const projection = {};
|
|
16370
18021
|
const columns = fieldMeta.map((sourceMeta) => {
|
|
@@ -16388,11 +18039,16 @@ function buildZeyosTableConfig(client, resource, opts = {}) {
|
|
|
16388
18039
|
if (typeof rowId === "string" && !Object.prototype.hasOwnProperty.call(projection, rowId)) {
|
|
16389
18040
|
projection[rowId] = rowId;
|
|
16390
18041
|
}
|
|
18042
|
+
const passed = {};
|
|
18043
|
+
for (const key of TABLE_OPTION_KEYS) {
|
|
18044
|
+
if (opts[key] !== void 0) passed[key] = opts[key];
|
|
18045
|
+
}
|
|
16391
18046
|
return {
|
|
16392
18047
|
fieldMeta,
|
|
16393
18048
|
columns,
|
|
16394
18049
|
projection,
|
|
16395
18050
|
tableOptions: {
|
|
18051
|
+
...passed,
|
|
16396
18052
|
columns,
|
|
16397
18053
|
data: [],
|
|
16398
18054
|
rowId,
|
|
@@ -16400,7 +18056,7 @@ function buildZeyosTableConfig(client, resource, opts = {}) {
|
|
|
16400
18056
|
sortMode: "server",
|
|
16401
18057
|
selectable: opts.selectable ?? false,
|
|
16402
18058
|
height: opts.height ?? null,
|
|
16403
|
-
onrowclick:
|
|
18059
|
+
onrowclick: rowClickListener(opts)
|
|
16404
18060
|
}
|
|
16405
18061
|
};
|
|
16406
18062
|
}
|
|
@@ -16486,6 +18142,15 @@ function zeyosTable(client, resource, opts = {}) {
|
|
|
16486
18142
|
});
|
|
16487
18143
|
return binding;
|
|
16488
18144
|
}
|
|
18145
|
+
function rowClickListener(opts) {
|
|
18146
|
+
const listener = typeof opts.onrowclick === "function" ? opts.onrowclick : null;
|
|
18147
|
+
const callback = typeof opts.onRowClick === "function" ? opts.onRowClick : null;
|
|
18148
|
+
if (!listener && !callback) return void 0;
|
|
18149
|
+
return (event) => {
|
|
18150
|
+
listener?.(event);
|
|
18151
|
+
callback?.(event.detail.row, event);
|
|
18152
|
+
};
|
|
18153
|
+
}
|
|
16489
18154
|
function referencedResourceFor(meta) {
|
|
16490
18155
|
for (const value of [meta.entity, meta.fk, meta.relation, meta.reference, meta.references]) {
|
|
16491
18156
|
if (typeof value === "string" && value) return value;
|
|
@@ -16551,8 +18216,8 @@ function zeyosAppointmentToEvent(record) {
|
|
|
16551
18216
|
const end = unixSecondsToDate(record.dateto ?? record.datefrom);
|
|
16552
18217
|
if (!(start instanceof Date) || !(end instanceof Date)) throw new TypeError("ZeyOS appointment requires datefrom and dateto");
|
|
16553
18218
|
const association = String(record.assoc_name ?? "").trim();
|
|
16554
|
-
const
|
|
16555
|
-
const title = record.entity && association ? `${association}: ${
|
|
18219
|
+
const name2 = String(record.name ?? "").trim() || "Untitled appointment";
|
|
18220
|
+
const title = record.entity && association ? `${association}: ${name2}` : name2;
|
|
16556
18221
|
const allDay = record.allDay != null ? Boolean(record.allDay) : isMidnight(start) && isMidnight(end) && calendarDayDifference(start, end) >= 1;
|
|
16557
18222
|
return {
|
|
16558
18223
|
id: String(record.occurrenceid ?? `${baseId}@${record.datefrom}`),
|
|
@@ -16621,8 +18286,8 @@ var FORBIDDEN_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
16621
18286
|
]);
|
|
16622
18287
|
var SavedViewDuplicateNameError = class extends Error {
|
|
16623
18288
|
/** @param {string} name Duplicate display name. */
|
|
16624
|
-
constructor(
|
|
16625
|
-
super(`A saved view named "${
|
|
18289
|
+
constructor(name2) {
|
|
18290
|
+
super(`A saved view named "${name2}" already exists`);
|
|
16626
18291
|
this.name = "SavedViewDuplicateNameError";
|
|
16627
18292
|
}
|
|
16628
18293
|
};
|
|
@@ -16713,15 +18378,15 @@ var SavedViewRegistry = class {
|
|
|
16713
18378
|
*/
|
|
16714
18379
|
async save(input, options = {}) {
|
|
16715
18380
|
return this._mutate(async (document2) => {
|
|
16716
|
-
const
|
|
18381
|
+
const name2 = normalizeName(input?.name);
|
|
16717
18382
|
const policy = normalizeDuplicatePolicy(options.onDuplicate ?? this.options.duplicateNames);
|
|
16718
18383
|
const requestedId = input?.id == null ? null : normalizeId(input.id);
|
|
16719
18384
|
const byId = requestedId ? document2.views.find((entry2) => entry2.id === requestedId) ?? null : null;
|
|
16720
|
-
const byName = document2.views.find((entry2) => nameKey(entry2.name) === nameKey(
|
|
18385
|
+
const byName = document2.views.find((entry2) => nameKey(entry2.name) === nameKey(name2)) ?? null;
|
|
16721
18386
|
if (byId && byName && byId !== byName && policy === "reject") {
|
|
16722
|
-
throw new SavedViewDuplicateNameError(
|
|
18387
|
+
throw new SavedViewDuplicateNameError(name2);
|
|
16723
18388
|
}
|
|
16724
|
-
if (!byId && byName && policy === "reject") throw new SavedViewDuplicateNameError(
|
|
18389
|
+
if (!byId && byName && policy === "reject") throw new SavedViewDuplicateNameError(name2);
|
|
16725
18390
|
const existing = byId ?? (policy === "replace" ? byName : null);
|
|
16726
18391
|
const replaced = policy === "replace" && byId && byName !== byId ? byName : null;
|
|
16727
18392
|
const now = this._now();
|
|
@@ -16731,8 +18396,8 @@ var SavedViewRegistry = class {
|
|
|
16731
18396
|
const filters = Object.prototype.hasOwnProperty.call(input ?? {}, "filters") ? normalizeFilters(input.filters) : existing ? cloneJsonObject(existing.filters, "Saved view filters") : {};
|
|
16732
18397
|
const search = Object.prototype.hasOwnProperty.call(input ?? {}, "search") ? normalizeSearch(input.search) : existing?.search ?? "";
|
|
16733
18398
|
const createdAt = existing?.createdAt ?? now;
|
|
16734
|
-
const id = existing?.id ?? requestedId ?? this._createId(document2, { name, type, createdAt });
|
|
16735
|
-
const entry = { id, name, type, state, filters, search, createdAt, updatedAt: now };
|
|
18399
|
+
const id = existing?.id ?? requestedId ?? this._createId(document2, { name: name2, type, createdAt });
|
|
18400
|
+
const entry = { id, name: name2, type, state, filters, search, createdAt, updatedAt: now };
|
|
16736
18401
|
const views = document2.views.filter((candidate) => candidate !== existing && candidate !== replaced && candidate.id !== id);
|
|
16737
18402
|
views.push(entry);
|
|
16738
18403
|
document2.views = sortEntries(views);
|
|
@@ -16748,11 +18413,11 @@ var SavedViewRegistry = class {
|
|
|
16748
18413
|
* @param {{onDuplicate?:SavedViewDuplicatePolicy}} [options={}] Duplicate policy.
|
|
16749
18414
|
* @returns {Promise<SavedViewEntry|null>} Updated entry, or null when absent.
|
|
16750
18415
|
*/
|
|
16751
|
-
async rename(idOrName,
|
|
18416
|
+
async rename(idOrName, name2, options = {}) {
|
|
16752
18417
|
return this._mutate(async (document2) => {
|
|
16753
18418
|
const entry = resolveEntry(document2, idOrName);
|
|
16754
18419
|
if (!entry) return { changed: false, result: null };
|
|
16755
|
-
const nextName = normalizeName(
|
|
18420
|
+
const nextName = normalizeName(name2);
|
|
16756
18421
|
if (entry.name === nextName) return { changed: false, result: entry };
|
|
16757
18422
|
const duplicate = document2.views.find((candidate) => candidate !== entry && nameKey(candidate.name) === nameKey(nextName)) ?? null;
|
|
16758
18423
|
const policy = normalizeDuplicatePolicy(options.onDuplicate ?? this.options.duplicateNames);
|
|
@@ -17015,7 +18680,7 @@ function normalizePersistedEntry(value, index, scope2) {
|
|
|
17015
18680
|
/** @type {Record<string,unknown>} */
|
|
17016
18681
|
value
|
|
17017
18682
|
);
|
|
17018
|
-
const
|
|
18683
|
+
const name2 = normalizeName(entry.name);
|
|
17019
18684
|
const type = normalizeType2(entry.type);
|
|
17020
18685
|
const state = normalizeRecordViewState(entry.state ?? {});
|
|
17021
18686
|
const filters = normalizeFilters(entry.filters ?? {});
|
|
@@ -17023,8 +18688,8 @@ function normalizePersistedEntry(value, index, scope2) {
|
|
|
17023
18688
|
const createdAt = normalizeTimestamp(entry.createdAt);
|
|
17024
18689
|
const requestedUpdated = normalizeTimestamp(entry.updatedAt ?? createdAt);
|
|
17025
18690
|
const updatedAt = requestedUpdated < createdAt ? createdAt : requestedUpdated;
|
|
17026
|
-
const id = entry.id == null || String(entry.id).trim() === "" ? `legacy-${hashString(`${scopeKey(scope2)}\0${
|
|
17027
|
-
return { id, name, type, state, filters, search, createdAt, updatedAt };
|
|
18691
|
+
const id = entry.id == null || String(entry.id).trim() === "" ? `legacy-${hashString(`${scopeKey(scope2)}\0${name2}\0${type}\0${index}`)}` : normalizeId(entry.id);
|
|
18692
|
+
return { id, name: name2, type, state, filters, search, createdAt, updatedAt };
|
|
17028
18693
|
}
|
|
17029
18694
|
function deduplicateEntries(entries) {
|
|
17030
18695
|
const ranked = [...entries].sort((left, right) => compareText(right.updatedAt, left.updatedAt) || compareText(left.id, right.id));
|
|
@@ -17112,10 +18777,10 @@ function normalizeType2(value) {
|
|
|
17112
18777
|
}
|
|
17113
18778
|
function normalizeName(value) {
|
|
17114
18779
|
if (typeof value !== "string") throw new TypeError("Saved view name must be a string");
|
|
17115
|
-
const
|
|
17116
|
-
if (!
|
|
17117
|
-
if (
|
|
17118
|
-
return
|
|
18780
|
+
const name2 = value.normalize("NFKC").trim().replace(/\s+/g, " ");
|
|
18781
|
+
if (!name2) throw new TypeError("Saved view name cannot be empty");
|
|
18782
|
+
if (name2.length > 160) throw new RangeError("Saved view name cannot exceed 160 characters");
|
|
18783
|
+
return name2;
|
|
17119
18784
|
}
|
|
17120
18785
|
function nameKey(value) {
|
|
17121
18786
|
return value.normalize("NFKC").toLocaleLowerCase("en-US");
|
|
@@ -17284,6 +18949,8 @@ function buildZeyosViewConfig(client, resource, opts = {}) {
|
|
|
17284
18949
|
const table = buildZeyosTableConfig(client, resource, {
|
|
17285
18950
|
fields: requested,
|
|
17286
18951
|
labels: opts.labels,
|
|
18952
|
+
formats: opts.formats,
|
|
18953
|
+
timeZone: opts.timeZone,
|
|
17287
18954
|
rowId: opts.recordId ?? "ID",
|
|
17288
18955
|
sort: opts.sort ?? null
|
|
17289
18956
|
});
|
|
@@ -17616,10 +19283,10 @@ function presentationType(View) {
|
|
|
17616
19283
|
cssName
|
|
17617
19284
|
);
|
|
17618
19285
|
}
|
|
17619
|
-
const
|
|
17620
|
-
return ["table", "card", "kanban"].includes(
|
|
19286
|
+
const name2 = String(View.name ?? "").toLowerCase().replace(/view$/, "");
|
|
19287
|
+
return ["table", "card", "kanban"].includes(name2) ? (
|
|
17621
19288
|
/** @type {'table'|'card'|'kanban'} */
|
|
17622
|
-
|
|
19289
|
+
name2
|
|
17623
19290
|
) : null;
|
|
17624
19291
|
}
|
|
17625
19292
|
function normalizePresentationType(value) {
|
|
@@ -17712,7 +19379,7 @@ function findReservedDocument(response, recordName) {
|
|
|
17712
19379
|
if (!Array.isArray(response) || !Array.isArray(response[0]) || !Array.isArray(response[1])) {
|
|
17713
19380
|
return null;
|
|
17714
19381
|
}
|
|
17715
|
-
const index = response[0].findIndex((
|
|
19382
|
+
const index = response[0].findIndex((name2) => String(name2) === recordName);
|
|
17716
19383
|
return index < 0 ? null : response[1][index];
|
|
17717
19384
|
}
|
|
17718
19385
|
function normalizeNonEmpty(value, fallback, label) {
|
|
@@ -17757,6 +19424,7 @@ export {
|
|
|
17757
19424
|
buildZeyosLauncherConfig,
|
|
17758
19425
|
buildZeyosSelectConfig,
|
|
17759
19426
|
buildZeyosViewConfig,
|
|
19427
|
+
calendarDayToUnixSeconds,
|
|
17760
19428
|
calendarEventToZeyosPatch,
|
|
17761
19429
|
connect,
|
|
17762
19430
|
createLegacySavedViewTransport,
|
|
@@ -17784,6 +19452,7 @@ export {
|
|
|
17784
19452
|
registerModules,
|
|
17785
19453
|
resolveFields,
|
|
17786
19454
|
tableSortToQuery,
|
|
19455
|
+
unixSecondsToCalendarDay,
|
|
17787
19456
|
unixSecondsToDate,
|
|
17788
19457
|
useZeyosIcons,
|
|
17789
19458
|
zeyosActiveIdentifier,
|
|
@@ -17799,3 +19468,51 @@ export {
|
|
|
17799
19468
|
zeyosTable,
|
|
17800
19469
|
zeyosView
|
|
17801
19470
|
};
|
|
19471
|
+
/*
|
|
19472
|
+
* @license Lucide 1.53.0 (ISC), including icons derived from Feather (MIT) — notices below.
|
|
19473
|
+
*
|
|
19474
|
+
* The bundled glyphs are Lucide 1.53.0 (https://lucide.dev), outline icons drawn on a 24-unit grid.
|
|
19475
|
+
* Each Lucide icon is stored as one path: its circles, rectangles, lines, and polylines are
|
|
19476
|
+
* rewritten as equivalent path data, which renders identically because every part shares the same
|
|
19477
|
+
* stroke. Where a Zx name differs from the Lucide one, the Lucide name is noted beside the glyph.
|
|
19478
|
+
*
|
|
19479
|
+
* ISC License
|
|
19480
|
+
*
|
|
19481
|
+
* Copyright (c) 2026 Lucide Icons and Contributors
|
|
19482
|
+
*
|
|
19483
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
19484
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
19485
|
+
* copyright notice and this permission notice appear in all copies.
|
|
19486
|
+
*
|
|
19487
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
19488
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
19489
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
19490
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
19491
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
19492
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
19493
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
19494
|
+
*
|
|
19495
|
+
* Lucide icons derived from the Feather project (Lucide's LICENSE lists them) are also covered by:
|
|
19496
|
+
*
|
|
19497
|
+
* The MIT License (MIT)
|
|
19498
|
+
*
|
|
19499
|
+
* Copyright (c) 2013-present Cole Bemis
|
|
19500
|
+
*
|
|
19501
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19502
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
19503
|
+
* in the Software without restriction, including without limitation the rights
|
|
19504
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19505
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
19506
|
+
* furnished to do so, subject to the following conditions:
|
|
19507
|
+
*
|
|
19508
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
19509
|
+
* copies or substantial portions of the Software.
|
|
19510
|
+
*
|
|
19511
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19512
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19513
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19514
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19515
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19516
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19517
|
+
* SOFTWARE.
|
|
19518
|
+
*/
|