@zeyos/zx 4.4.0 → 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 +283 -0
- package/README.md +42 -10
- package/dist/types/components/activity-list/activity-list.d.ts +22 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +5 -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 +15 -0
- 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 +6 -17
- 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 +46 -6
- package/dist/types/components/dropdown/dropdown.d.ts +2 -2
- package/dist/types/components/entity-ref/entity-ref.d.ts +2 -2
- 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 +34 -6
- package/dist/types/components/form/form.d.ts +12 -1
- package/dist/types/components/kanban-view/kanban-card.d.ts +8 -0
- package/dist/types/components/launcher/launcher.d.ts +260 -15
- package/dist/types/components/list-toolbar/list-toolbar.d.ts +1 -1
- package/dist/types/components/menu-button/menu-button.d.ts +33 -5
- package/dist/types/components/message/message.d.ts +119 -17
- package/dist/types/components/modal/modal.d.ts +13 -2
- 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 +11 -3
- package/dist/types/components/stat-tile/stat-tile.d.ts +16 -5
- package/dist/types/components/tabbox/tabbox.d.ts +9 -0
- package/dist/types/components/table/table.d.ts +46 -1
- package/dist/types/components/tag-picker/tag-picker.d.ts +21 -4
- package/dist/types/components/tree/tree.d.ts +13 -0
- package/dist/types/core/breakpoint.d.ts +1 -1
- package/dist/types/core/icons.d.ts +23 -25
- 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 +5 -3
- 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 +1621 -443
- package/dist/zx-zeyos.esm.min.js +53 -5
- package/dist/zx.css +1411 -660
- package/dist/zx.esm.js +1976 -703
- package/dist/zx.esm.min.js +56 -8
- package/dist/zx.global.js +1978 -705
- package/dist/zx.global.min.js +56 -8
- package/dist/zx.min.css +1 -1
- package/docs/api.json +219 -34
- package/docs/llms.md +472 -110
- package/docs/llms.txt +3 -3
- package/package.json +1 -1
- package/src/components/account-menu/account-menu.css +35 -10
- package/src/components/activity-item/activity-item.css +1 -1
- package/src/components/activity-item/activity-item.js +3 -0
- package/src/components/activity-list/activity-list.css +38 -3
- package/src/components/activity-list/activity-list.js +34 -0
- package/src/components/app-icon/app-icon.css +1 -1
- package/src/components/app-rail/app-rail.css +40 -79
- package/src/components/app-sidebar/app-sidebar.css +109 -174
- package/src/components/app-sidebar/app-sidebar.js +21 -6
- 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 +67 -9
- package/src/components/button/button.js +38 -0
- package/src/components/calendar/calendar.css +46 -46
- package/src/components/card/card.css +2 -2
- package/src/components/card-view/card-view.css +9 -7
- 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 +6 -5
- package/src/components/code-editor/code-editor.js +19 -1
- package/src/components/context-menu/context-menu.css +9 -4
- 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-range-picker.css +3 -3
- package/src/components/date-picker/time-picker.css +1 -1
- 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 +99 -17
- package/src/components/dropdown/dropdown.css +1 -1
- package/src/components/dropdown/dropdown.js +5 -3
- package/src/components/empty-state/empty-state.css +2 -2
- package/src/components/entity-ref/entity-ref.css +1 -1
- package/src/components/entity-ref/entity-ref.js +1 -1
- 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.js +144 -10
- package/src/components/filter/filter.js +7 -3
- package/src/components/filter-panel/filter-panel.css +1 -1
- 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 +11 -3
- package/src/components/kanban-view/kanban-view.css +39 -15
- package/src/components/kanban-view/kanban-view.js +4 -4
- package/src/components/launcher/launcher.css +107 -25
- package/src/components/launcher/launcher.js +503 -41
- package/src/components/list-toolbar/list-toolbar.css +13 -8
- package/src/components/list-toolbar/list-toolbar.js +1 -1
- package/src/components/master-panel/master-panel.css +2 -0
- package/src/components/menu-button/menu-button.css +9 -4
- package/src/components/menu-button/menu-button.js +65 -9
- package/src/components/message/message.css +33 -3
- package/src/components/message/message.js +217 -15
- package/src/components/modal/modal.js +18 -3
- package/src/components/navigation-bar/navigation-bar.css +18 -9
- 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/rating/rating.css +7 -0
- package/src/components/select/color.js +22 -0
- package/src/components/select/field-adapter.js +2 -0
- package/src/components/select/glyphs.js +165 -0
- package/src/components/select/select.css +138 -45
- package/src/components/select/select.js +83 -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 +4 -1
- package/src/components/stat-tile/stat-tile.css +41 -46
- package/src/components/stat-tile/stat-tile.js +17 -6
- package/src/components/tabbox/tabbox.css +32 -27
- package/src/components/tabbox/tabbox.js +5 -1
- package/src/components/table/table.css +104 -29
- package/src/components/table/table.js +90 -16
- package/src/components/tag-picker/tag-picker.css +83 -5
- package/src/components/tag-picker/tag-picker.js +25 -8
- package/src/components/timebox/timebox.css +22 -2
- 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/view/record-view.js +1 -1
- package/src/core/breakpoint.js +1 -1
- package/src/core/icons.js +193 -60
- package/src/core/motion.js +147 -0
- package/src/core/overlay-host.js +21 -2
- package/src/index.js +5 -3
- package/src/internal/app-rail.js +1 -2
- 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/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 +0 -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 = () => {
|
|
@@ -1801,6 +1979,7 @@ function registerChecklistFieldAdapter() {
|
|
|
1801
1979
|
}
|
|
1802
1980
|
|
|
1803
1981
|
// src/components/code-editor/code-editor.js
|
|
1982
|
+
var MODIFIER_KEYS = /* @__PURE__ */ new Set(["Shift", "Control", "Alt", "Meta", "AltGraph", "CapsLock", "Fn", "OS"]);
|
|
1804
1983
|
var CodeEditor = class extends Component {
|
|
1805
1984
|
static cssName = "code-editor";
|
|
1806
1985
|
/** @type {CodeEditorOptions} */
|
|
@@ -1827,7 +2006,7 @@ var CodeEditor = class extends Component {
|
|
|
1827
2006
|
);
|
|
1828
2007
|
this.el = root;
|
|
1829
2008
|
this._initialChildren = this._createdRoot ? [] : [...root.childNodes];
|
|
1830
|
-
this._initialAttributes = new Map(["data-language", "data-readonly", "data-disabled"].map((
|
|
2009
|
+
this._initialAttributes = new Map(["data-language", "data-readonly", "data-disabled"].map((name2) => [name2, root.getAttribute(name2)]));
|
|
1831
2010
|
this._language = normalizeLanguage(this.options.language);
|
|
1832
2011
|
this._languageLabel = h("span", { class: "zx-code-editor__language" }, this._language);
|
|
1833
2012
|
this._position = h("span", {
|
|
@@ -1860,7 +2039,11 @@ var CodeEditor = class extends Component {
|
|
|
1860
2039
|
root.dataset.readonly = String(Boolean(this.options.readOnly));
|
|
1861
2040
|
root.dataset.disabled = String(Boolean(this.options.disabled));
|
|
1862
2041
|
root.replaceChildren(this._header, this._input);
|
|
2042
|
+
this._tabReleased = false;
|
|
1863
2043
|
this.listen(this._input, "keydown", (event) => this._handleKeydown(event));
|
|
2044
|
+
this.listen(this._input, "blur", () => {
|
|
2045
|
+
this._tabReleased = false;
|
|
2046
|
+
});
|
|
1864
2047
|
this.listen(this._input, "input", () => {
|
|
1865
2048
|
this._updatePosition();
|
|
1866
2049
|
this.emit("input", { value: this.getValue() });
|
|
@@ -1922,7 +2105,14 @@ var CodeEditor = class extends Component {
|
|
|
1922
2105
|
}
|
|
1923
2106
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
1924
2107
|
_handleKeydown(event) {
|
|
1925
|
-
if (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;
|
|
1926
2116
|
const indent = String(this.options.indent ?? " ");
|
|
1927
2117
|
if (!indent) return;
|
|
1928
2118
|
event.preventDefault();
|
|
@@ -1953,9 +2143,9 @@ var CodeEditor = class extends Component {
|
|
|
1953
2143
|
destroy() {
|
|
1954
2144
|
if (!this._createdRoot) {
|
|
1955
2145
|
this.el.replaceChildren(...this._initialChildren);
|
|
1956
|
-
for (const [
|
|
1957
|
-
if (value === null) this.el.removeAttribute(
|
|
1958
|
-
else this.el.setAttribute(
|
|
2146
|
+
for (const [name2, value] of this._initialAttributes) {
|
|
2147
|
+
if (value === null) this.el.removeAttribute(name2);
|
|
2148
|
+
else this.el.setAttribute(name2, value);
|
|
1959
2149
|
}
|
|
1960
2150
|
}
|
|
1961
2151
|
super.destroy();
|
|
@@ -2290,19 +2480,19 @@ function parseIconSpec(spec) {
|
|
|
2290
2480
|
const separator = text3.indexOf(":");
|
|
2291
2481
|
if (separator > 0) {
|
|
2292
2482
|
const prefix = text3.slice(0, separator).toLowerCase();
|
|
2293
|
-
const
|
|
2483
|
+
const name2 = text3.slice(separator + 1);
|
|
2294
2484
|
if (prefix === "builtin" || prefix === "zx") {
|
|
2295
|
-
return { provider: "builtin", name, style: null, classes: null };
|
|
2485
|
+
return { provider: "builtin", name: name2, style: null, classes: null };
|
|
2296
2486
|
}
|
|
2297
2487
|
if (Object.hasOwn(stylePrefixes, prefix)) {
|
|
2298
|
-
return { provider: "fa", name, style: stylePrefixes[prefix], classes: null };
|
|
2488
|
+
return { provider: "fa", name: name2, style: stylePrefixes[prefix], classes: null };
|
|
2299
2489
|
}
|
|
2300
2490
|
}
|
|
2301
2491
|
return { provider: null, name: text3, style: null, classes: null };
|
|
2302
2492
|
}
|
|
2303
|
-
function faIconClasses(
|
|
2493
|
+
function faIconClasses(name2, options = {}) {
|
|
2304
2494
|
const { style = "solid", family = "classic", fixedWidth = false, translate: translate2 = true } = options;
|
|
2305
|
-
const bare = String(
|
|
2495
|
+
const bare = String(name2).replace(/^fa-/, "");
|
|
2306
2496
|
const resolved = translate2 ? faNames[bare] ?? bare : bare;
|
|
2307
2497
|
const classes = [];
|
|
2308
2498
|
const familyClass = faFamilies[family];
|
|
@@ -2349,44 +2539,61 @@ function loadFontAwesomeKit(kit) {
|
|
|
2349
2539
|
|
|
2350
2540
|
// src/core/icons.js
|
|
2351
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"];
|
|
2352
2546
|
var icons = Object.freeze({
|
|
2353
|
-
|
|
2354
|
-
"arrow-
|
|
2355
|
-
|
|
2356
|
-
"
|
|
2357
|
-
|
|
2358
|
-
"chevron-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
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>
|
|
2390
2597
|
});
|
|
2391
2598
|
var aliases = Object.freeze({
|
|
2392
2599
|
settings: "gear",
|
|
@@ -2424,8 +2631,8 @@ async function loadFontAwesome(options) {
|
|
|
2424
2631
|
await loadFontAwesomeKit(kit);
|
|
2425
2632
|
return activate ? useFontAwesome() : getIconConfig();
|
|
2426
2633
|
}
|
|
2427
|
-
function icon(
|
|
2428
|
-
const spec = parseIconSpec(
|
|
2634
|
+
function icon(name2, options = {}) {
|
|
2635
|
+
const spec = parseIconSpec(name2);
|
|
2429
2636
|
if (spec.classes) return faIcon(spec.classes, options);
|
|
2430
2637
|
const resolved = aliases[spec.name] ?? spec.name;
|
|
2431
2638
|
if (spec.provider === "builtin") return builtinIcon(resolved, options);
|
|
@@ -2445,43 +2652,59 @@ function icon(name, options = {}) {
|
|
|
2445
2652
|
}
|
|
2446
2653
|
return builtinIcon(resolved, options);
|
|
2447
2654
|
}
|
|
2448
|
-
function builtinIcon(
|
|
2449
|
-
const entry = extraGlyphs[
|
|
2655
|
+
function builtinIcon(name2, options) {
|
|
2656
|
+
const entry = extraGlyphs[name2] ?? icons[name2];
|
|
2450
2657
|
if (!entry) {
|
|
2451
|
-
if (options.strict) throw new RangeError(`Unknown icon: ${
|
|
2452
|
-
warnMissingIcon(
|
|
2453
|
-
return missingIcon(
|
|
2658
|
+
if (options.strict) throw new RangeError(`Unknown icon: ${name2}`);
|
|
2659
|
+
warnMissingIcon(name2);
|
|
2660
|
+
return missingIcon(name2, options);
|
|
2454
2661
|
}
|
|
2455
|
-
const [viewBox, pathData] = entry;
|
|
2456
|
-
const svg = iconSvg(viewBox, options);
|
|
2662
|
+
const [viewBox, pathData, paint = "fill"] = entry;
|
|
2663
|
+
const svg = iconSvg(viewBox, paint, options);
|
|
2457
2664
|
const path = document.createElementNS(SVG_NS, "path");
|
|
2458
2665
|
path.setAttribute("d", pathData);
|
|
2459
2666
|
svg.append(path);
|
|
2460
2667
|
return svg;
|
|
2461
2668
|
}
|
|
2462
|
-
function iconSvg(viewBox, options) {
|
|
2669
|
+
function iconSvg(viewBox, paint, options) {
|
|
2463
2670
|
const { size = 16 } = options;
|
|
2464
2671
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
2465
2672
|
svg.setAttribute("class", classList("zx-icon", options.class));
|
|
2466
2673
|
svg.setAttribute("viewBox", viewBox);
|
|
2467
2674
|
svg.setAttribute("width", String(size));
|
|
2468
2675
|
svg.setAttribute("height", String(size));
|
|
2469
|
-
|
|
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
|
+
}
|
|
2470
2685
|
svg.setAttribute("focusable", "false");
|
|
2471
2686
|
applyLabel(svg, options.label ?? null);
|
|
2472
2687
|
return svg;
|
|
2473
2688
|
}
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
const
|
|
2477
|
-
|
|
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);
|
|
2478
2701
|
return svg;
|
|
2479
2702
|
}
|
|
2480
2703
|
var warnedMissing = /* @__PURE__ */ new Set();
|
|
2481
|
-
function warnMissingIcon(
|
|
2482
|
-
if (warnedMissing.has(
|
|
2483
|
-
warnedMissing.add(
|
|
2484
|
-
console.warn(`[zx.icon] Unknown icon "${
|
|
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().`);
|
|
2485
2708
|
}
|
|
2486
2709
|
function faIcon(classes, options) {
|
|
2487
2710
|
const { size = 16 } = options;
|
|
@@ -3000,8 +3223,8 @@ var DatePicker = class extends Component {
|
|
|
3000
3223
|
*/
|
|
3001
3224
|
focus() {
|
|
3002
3225
|
this._closeQuickPick();
|
|
3003
|
-
const
|
|
3004
|
-
|
|
3226
|
+
const button2 = this._buttonForDate(this._focused);
|
|
3227
|
+
button2?.focus();
|
|
3005
3228
|
return this;
|
|
3006
3229
|
}
|
|
3007
3230
|
/** Cleans up an appended time picker and generated host content. @returns {void} */
|
|
@@ -3072,7 +3295,7 @@ var DatePicker = class extends Component {
|
|
|
3072
3295
|
const date = addDays(rowStart, column);
|
|
3073
3296
|
const selected = Boolean(this._value && isSameDay(date, this._value));
|
|
3074
3297
|
const unavailable = !this._inRange(date);
|
|
3075
|
-
const
|
|
3298
|
+
const button2 = h("button", {
|
|
3076
3299
|
class: "zx-date-picker__day",
|
|
3077
3300
|
type: "button",
|
|
3078
3301
|
role: "gridcell",
|
|
@@ -3086,7 +3309,7 @@ var DatePicker = class extends Component {
|
|
|
3086
3309
|
otherMonth: date.getMonth() === this._viewMonth ? null : "true"
|
|
3087
3310
|
}
|
|
3088
3311
|
}, formatDate(date, "%e"));
|
|
3089
|
-
row.append(h("td", { role: "presentation" },
|
|
3312
|
+
row.append(h("td", { role: "presentation" }, button2));
|
|
3090
3313
|
}
|
|
3091
3314
|
rows.push(row);
|
|
3092
3315
|
}
|
|
@@ -3095,16 +3318,16 @@ var DatePicker = class extends Component {
|
|
|
3095
3318
|
}
|
|
3096
3319
|
/** @param {Event} event @returns {void} */
|
|
3097
3320
|
_onDayClick(event) {
|
|
3098
|
-
const
|
|
3099
|
-
if (!
|
|
3100
|
-
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");
|
|
3101
3324
|
if (date && this._inRange(date)) this._selectDate(date);
|
|
3102
3325
|
}
|
|
3103
3326
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
3104
3327
|
_onDayKeydown(event) {
|
|
3105
|
-
const
|
|
3106
|
-
if (!
|
|
3107
|
-
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");
|
|
3108
3331
|
if (!current) return;
|
|
3109
3332
|
let next = null;
|
|
3110
3333
|
if (event.key === "ArrowLeft") next = addDays(current, -1);
|
|
@@ -3215,15 +3438,15 @@ var DatePicker = class extends Component {
|
|
|
3215
3438
|
}
|
|
3216
3439
|
/** @param {Event} event @returns {void} */
|
|
3217
3440
|
_onQuickClick(event) {
|
|
3218
|
-
const
|
|
3219
|
-
if (!
|
|
3220
|
-
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));
|
|
3221
3444
|
}
|
|
3222
3445
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
3223
3446
|
_onQuickKeydown(event) {
|
|
3224
|
-
const
|
|
3225
|
-
if (!
|
|
3226
|
-
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);
|
|
3227
3450
|
let next = null;
|
|
3228
3451
|
if (event.key === "ArrowLeft") next = month - 1;
|
|
3229
3452
|
else if (event.key === "ArrowRight") next = month + 1;
|
|
@@ -3435,15 +3658,15 @@ var MonthPicker = class extends DatePicker {
|
|
|
3435
3658
|
}
|
|
3436
3659
|
/** @param {Event} event @returns {void} */
|
|
3437
3660
|
_onMonthClick(event) {
|
|
3438
|
-
const
|
|
3439
|
-
if (!
|
|
3440
|
-
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));
|
|
3441
3664
|
}
|
|
3442
3665
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
3443
3666
|
_onMonthKeydown(event) {
|
|
3444
|
-
const
|
|
3445
|
-
if (!
|
|
3446
|
-
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);
|
|
3447
3670
|
let delta = null;
|
|
3448
3671
|
if (event.key === "ArrowLeft") delta = -1;
|
|
3449
3672
|
else if (event.key === "ArrowRight") delta = 1;
|
|
@@ -3512,7 +3735,7 @@ function registerDatePickerFieldAdapters() {
|
|
|
3512
3735
|
let disabled = false;
|
|
3513
3736
|
const syncDisabled = () => {
|
|
3514
3737
|
picker.el.setAttribute("aria-disabled", String(disabled));
|
|
3515
|
-
for (const
|
|
3738
|
+
for (const button2 of picker.el.querySelectorAll("button")) button2.disabled = disabled;
|
|
3516
3739
|
};
|
|
3517
3740
|
field.listen(picker.el, "change", (event) => event.stopImmediatePropagation());
|
|
3518
3741
|
picker.on("change", (event) => field.emit("change", { value: event.detail.date }));
|
|
@@ -3710,9 +3933,9 @@ function hidePopover(element) {
|
|
|
3710
3933
|
} catch {
|
|
3711
3934
|
}
|
|
3712
3935
|
}
|
|
3713
|
-
function restoreAttribute(element,
|
|
3714
|
-
if (value === null) element.removeAttribute(
|
|
3715
|
-
else element.setAttribute(
|
|
3936
|
+
function restoreAttribute(element, name2, value) {
|
|
3937
|
+
if (value === null) element.removeAttribute(name2);
|
|
3938
|
+
else element.setAttribute(name2, value);
|
|
3716
3939
|
}
|
|
3717
3940
|
|
|
3718
3941
|
// src/components/date-picker/date-range-picker.js
|
|
@@ -4095,12 +4318,12 @@ var DateRangePicker = class extends Component {
|
|
|
4095
4318
|
/* ---------------------------------------------------------------------- events -- */
|
|
4096
4319
|
/** @param {Event} event @returns {void} */
|
|
4097
4320
|
_onPresetClick(event) {
|
|
4098
|
-
const
|
|
4321
|
+
const button2 = (
|
|
4099
4322
|
/** @type {Element} */
|
|
4100
4323
|
event.target?.closest?.("[data-preset]")
|
|
4101
4324
|
);
|
|
4102
|
-
if (!
|
|
4103
|
-
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);
|
|
4104
4327
|
if (!preset) return;
|
|
4105
4328
|
const range = preset.range();
|
|
4106
4329
|
this.set({ start: range?.start ?? null, end: range?.end ?? null }, { silent: true });
|
|
@@ -4203,15 +4426,15 @@ var DateRangePicker = class extends Component {
|
|
|
4203
4426
|
const date = addDays(rowStart, column);
|
|
4204
4427
|
const cell = h("td", { role: "presentation" });
|
|
4205
4428
|
if (date.getMonth() === first.getMonth() && date.getFullYear() === first.getFullYear()) {
|
|
4206
|
-
const
|
|
4429
|
+
const button2 = h("button", {
|
|
4207
4430
|
class: "zx-date-range-picker__day",
|
|
4208
4431
|
type: "button",
|
|
4209
4432
|
role: "gridcell",
|
|
4210
4433
|
tabindex: -1,
|
|
4211
4434
|
dataset: { date: formatDate(date, "%Y-%m-%d") }
|
|
4212
4435
|
}, formatDate(date, "%e"));
|
|
4213
|
-
cell.append(
|
|
4214
|
-
this._dayCells.push({ date, cell, button });
|
|
4436
|
+
cell.append(button2);
|
|
4437
|
+
this._dayCells.push({ date, cell, button: button2 });
|
|
4215
4438
|
}
|
|
4216
4439
|
row.append(cell);
|
|
4217
4440
|
}
|
|
@@ -4282,17 +4505,17 @@ var DateRangePicker = class extends Component {
|
|
|
4282
4505
|
}
|
|
4283
4506
|
if (!roving) roving = this._dayCells[0] ?? null;
|
|
4284
4507
|
for (const entry of this._dayCells) {
|
|
4285
|
-
const { date, cell, button } = entry;
|
|
4508
|
+
const { date, cell, button: button2 } = entry;
|
|
4286
4509
|
const state = this._dayState(date);
|
|
4287
4510
|
setDataset(cell, "range", state.range);
|
|
4288
4511
|
setDataset(cell, "rangeEdge", state.edge);
|
|
4289
|
-
setDataset(
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
if (isSameDay(date, today2))
|
|
4295
|
-
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");
|
|
4296
4519
|
}
|
|
4297
4520
|
}
|
|
4298
4521
|
/**
|
|
@@ -4343,7 +4566,7 @@ var DateRangePicker = class extends Component {
|
|
|
4343
4566
|
/** @returns {void} */
|
|
4344
4567
|
_syncDisabled() {
|
|
4345
4568
|
this.el.setAttribute("aria-disabled", String(this._disabled));
|
|
4346
|
-
for (const
|
|
4569
|
+
for (const button2 of this.el.querySelectorAll("button")) button2.disabled = this._disabled;
|
|
4347
4570
|
}
|
|
4348
4571
|
/** Writes the current selection into the visually hidden live region. @returns {void} */
|
|
4349
4572
|
_announce() {
|
|
@@ -4366,9 +4589,9 @@ var DateRangePicker = class extends Component {
|
|
|
4366
4589
|
}
|
|
4367
4590
|
/** @param {Element|null} target @returns {{date: Date, cell: Element, button: Element}|null} */
|
|
4368
4591
|
_cellFor(target) {
|
|
4369
|
-
const
|
|
4370
|
-
if (!
|
|
4371
|
-
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;
|
|
4372
4595
|
}
|
|
4373
4596
|
/** @param {Date} date @returns {HTMLButtonElement|null} */
|
|
4374
4597
|
_buttonForDate(date) {
|
|
@@ -4506,17 +4729,17 @@ function isoWeekNumber2(date) {
|
|
|
4506
4729
|
const yearStart = new Date(Date.UTC(utc.getUTCFullYear(), 0, 1));
|
|
4507
4730
|
return Math.ceil(((utc.getTime() - yearStart.getTime()) / DAY_MS + 1) / 7);
|
|
4508
4731
|
}
|
|
4509
|
-
function setDataset(element,
|
|
4510
|
-
if (value === null || value === void 0) delete element.dataset[
|
|
4511
|
-
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;
|
|
4512
4735
|
}
|
|
4513
4736
|
function rememberAttributes2(element, names) {
|
|
4514
|
-
return new Map(names.map((
|
|
4737
|
+
return new Map(names.map((name2) => [name2, element.getAttribute(name2)]));
|
|
4515
4738
|
}
|
|
4516
4739
|
function restoreAttributes2(element, attributes) {
|
|
4517
|
-
for (const [
|
|
4518
|
-
if (value === null) element.removeAttribute(
|
|
4519
|
-
else element.setAttribute(
|
|
4740
|
+
for (const [name2, value] of attributes) {
|
|
4741
|
+
if (value === null) element.removeAttribute(name2);
|
|
4742
|
+
else element.setAttribute(name2, value);
|
|
4520
4743
|
}
|
|
4521
4744
|
}
|
|
4522
4745
|
|
|
@@ -4585,6 +4808,8 @@ var DateRangeBox = class extends Component {
|
|
|
4585
4808
|
this.el = root;
|
|
4586
4809
|
this._originalState = root.getAttribute("data-state");
|
|
4587
4810
|
this._originalAriaDisabled = root.getAttribute("aria-disabled");
|
|
4811
|
+
this._originalClearable = root.getAttribute("data-clearable");
|
|
4812
|
+
root.toggleAttribute("data-clearable", Boolean(this.options.clearable));
|
|
4588
4813
|
this._format = String(this.options.format || "%d.%m.%Y");
|
|
4589
4814
|
this._separator = String(this.options.separator ?? " \u2013 ");
|
|
4590
4815
|
this._disabled = Boolean(this.options.disabled);
|
|
@@ -4777,6 +5002,7 @@ var DateRangeBox = class extends Component {
|
|
|
4777
5002
|
this._content?.remove();
|
|
4778
5003
|
restoreAttribute2(this.el, "data-state", this._originalState);
|
|
4779
5004
|
restoreAttribute2(this.el, "aria-disabled", this._originalAriaDisabled);
|
|
5005
|
+
restoreAttribute2(this.el, "data-clearable", this._originalClearable);
|
|
4780
5006
|
super.destroy();
|
|
4781
5007
|
}
|
|
4782
5008
|
/* --------------------------------------------------------------------- internals -- */
|
|
@@ -4873,7 +5099,11 @@ var DateRangeBox = class extends Component {
|
|
|
4873
5099
|
/** @returns {void} */
|
|
4874
5100
|
_syncDisplay() {
|
|
4875
5101
|
this.refs.input.value = formatRangeText(this._range, this._format, this._separator);
|
|
4876
|
-
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;
|
|
4877
5107
|
}
|
|
4878
5108
|
/** @returns {void} */
|
|
4879
5109
|
_syncDisabled() {
|
|
@@ -4881,6 +5111,7 @@ var DateRangeBox = class extends Component {
|
|
|
4881
5111
|
this.refs.toggle.disabled = this._disabled;
|
|
4882
5112
|
this.refs.clear.disabled = this._disabled;
|
|
4883
5113
|
this.el.setAttribute("aria-disabled", String(this._disabled));
|
|
5114
|
+
this._syncClear();
|
|
4884
5115
|
if (this._disabled) this._picker?.disable();
|
|
4885
5116
|
else this._picker?.enable();
|
|
4886
5117
|
}
|
|
@@ -4890,7 +5121,7 @@ var DateRangeBox = class extends Component {
|
|
|
4890
5121
|
this.refs.input.removeAttribute("aria-invalid");
|
|
4891
5122
|
}
|
|
4892
5123
|
/** @param {boolean} returnFocus @returns {void} */
|
|
4893
|
-
_close(
|
|
5124
|
+
_close(returnFocus2) {
|
|
4894
5125
|
if (!this._open) return;
|
|
4895
5126
|
this._position?.destroy();
|
|
4896
5127
|
this._position = null;
|
|
@@ -4898,7 +5129,7 @@ var DateRangeBox = class extends Component {
|
|
|
4898
5129
|
this.refs.popover.dataset.state = "closed";
|
|
4899
5130
|
this.refs.input.setAttribute("aria-expanded", "false");
|
|
4900
5131
|
this.refs.toggle.setAttribute("aria-expanded", "false");
|
|
4901
|
-
if (
|
|
5132
|
+
if (returnFocus2) this.focus();
|
|
4902
5133
|
this.emit("close");
|
|
4903
5134
|
}
|
|
4904
5135
|
};
|
|
@@ -4906,9 +5137,9 @@ function text2(key, fallback, args) {
|
|
|
4906
5137
|
const translated = translate(key);
|
|
4907
5138
|
return printf(translated === key ? fallback : translated, args);
|
|
4908
5139
|
}
|
|
4909
|
-
function restoreAttribute2(element,
|
|
4910
|
-
if (value === null) element.removeAttribute(
|
|
4911
|
-
else element.setAttribute(
|
|
5140
|
+
function restoreAttribute2(element, name2, value) {
|
|
5141
|
+
if (value === null) element.removeAttribute(name2);
|
|
5142
|
+
else element.setAttribute(name2, value);
|
|
4912
5143
|
}
|
|
4913
5144
|
|
|
4914
5145
|
// src/components/date-picker/range-field-adapter.js
|
|
@@ -4957,6 +5188,8 @@ var Datebox = class extends Component {
|
|
|
4957
5188
|
this.el = root;
|
|
4958
5189
|
this._originalState = root.getAttribute("data-state");
|
|
4959
5190
|
this._originalAriaDisabled = root.getAttribute("aria-disabled");
|
|
5191
|
+
this._originalClearable = root.getAttribute("data-clearable");
|
|
5192
|
+
root.toggleAttribute("data-clearable", Boolean(this.options.clearable));
|
|
4960
5193
|
this._format = effectiveFormat(this.options.format, this.options.time);
|
|
4961
5194
|
this._disabled = Boolean(this.options.disabled);
|
|
4962
5195
|
this._open = false;
|
|
@@ -5126,6 +5359,8 @@ var Datebox = class extends Component {
|
|
|
5126
5359
|
else this.el.setAttribute("data-state", this._originalState);
|
|
5127
5360
|
if (this._originalAriaDisabled === null) this.el.removeAttribute("aria-disabled");
|
|
5128
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);
|
|
5129
5364
|
super.destroy();
|
|
5130
5365
|
}
|
|
5131
5366
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
@@ -5170,7 +5405,11 @@ var Datebox = class extends Component {
|
|
|
5170
5405
|
/** @returns {void} */
|
|
5171
5406
|
_syncDisplay() {
|
|
5172
5407
|
this.refs.input.value = this._value ? formatDate(this._value, this._format) : "";
|
|
5173
|
-
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;
|
|
5174
5413
|
}
|
|
5175
5414
|
/** @returns {void} */
|
|
5176
5415
|
_syncDisabled() {
|
|
@@ -5178,6 +5417,7 @@ var Datebox = class extends Component {
|
|
|
5178
5417
|
this.refs.toggle.disabled = this._disabled;
|
|
5179
5418
|
this.refs.clear.disabled = this._disabled;
|
|
5180
5419
|
this.el.setAttribute("aria-disabled", String(this._disabled));
|
|
5420
|
+
this._syncClear();
|
|
5181
5421
|
}
|
|
5182
5422
|
/** @returns {void} */
|
|
5183
5423
|
_setValid() {
|
|
@@ -5188,7 +5428,7 @@ var Datebox = class extends Component {
|
|
|
5188
5428
|
this.refs.input.removeAttribute("aria-invalid");
|
|
5189
5429
|
}
|
|
5190
5430
|
/** @param {boolean} returnFocus @returns {void} */
|
|
5191
|
-
_close(
|
|
5431
|
+
_close(returnFocus2) {
|
|
5192
5432
|
if (!this._open) return;
|
|
5193
5433
|
this._position?.destroy();
|
|
5194
5434
|
this._position = null;
|
|
@@ -5196,7 +5436,7 @@ var Datebox = class extends Component {
|
|
|
5196
5436
|
this.refs.popover.dataset.state = "closed";
|
|
5197
5437
|
this.refs.input.setAttribute("aria-expanded", "false");
|
|
5198
5438
|
this.refs.toggle.setAttribute("aria-expanded", "false");
|
|
5199
|
-
if (
|
|
5439
|
+
if (returnFocus2) this.focus();
|
|
5200
5440
|
this.emit("close");
|
|
5201
5441
|
}
|
|
5202
5442
|
/** @returns {Date|null} */
|
|
@@ -5498,7 +5738,7 @@ var FieldUpload = class extends Component {
|
|
|
5498
5738
|
const xhr = new XMLHttpRequest();
|
|
5499
5739
|
this._xhr = xhr;
|
|
5500
5740
|
xhr.open("POST", String(this.options.url));
|
|
5501
|
-
for (const [
|
|
5741
|
+
for (const [name2, value] of Object.entries(this.options.headers ?? {})) xhr.setRequestHeader(name2, String(value));
|
|
5502
5742
|
this.listen(xhr.upload, "progress", (event) => {
|
|
5503
5743
|
if (event.lengthComputable) this._setProgress(event.loaded / event.total * 100);
|
|
5504
5744
|
});
|
|
@@ -5597,18 +5837,18 @@ function matchesAccept(file, accept) {
|
|
|
5597
5837
|
function createFormData(files, paramName, params) {
|
|
5598
5838
|
const form = new FormData();
|
|
5599
5839
|
for (const file of files) form.append(paramName, file);
|
|
5600
|
-
for (const [
|
|
5840
|
+
for (const [name2, value] of Object.entries(params ?? {})) appendFormValue(form, name2, value);
|
|
5601
5841
|
return form;
|
|
5602
5842
|
}
|
|
5603
|
-
function appendFormValue(form,
|
|
5843
|
+
function appendFormValue(form, name2, value) {
|
|
5604
5844
|
if (value == null) return;
|
|
5605
5845
|
if (Array.isArray(value)) {
|
|
5606
|
-
for (const item of value) appendFormValue(form,
|
|
5846
|
+
for (const item of value) appendFormValue(form, name2, item);
|
|
5607
5847
|
return;
|
|
5608
5848
|
}
|
|
5609
5849
|
const isBlob = typeof Blob === "function" && value instanceof Blob;
|
|
5610
|
-
if (isBlob) form.append(
|
|
5611
|
-
else form.append(
|
|
5850
|
+
if (isBlob) form.append(name2, value);
|
|
5851
|
+
else form.append(name2, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
5612
5852
|
}
|
|
5613
5853
|
function parseResponse(text3) {
|
|
5614
5854
|
if (!text3) return null;
|
|
@@ -5789,11 +6029,11 @@ var MultiValueEditor = class extends Component {
|
|
|
5789
6029
|
}
|
|
5790
6030
|
/** @param {MouseEvent} event @returns {void} */
|
|
5791
6031
|
_handleClick(event) {
|
|
5792
|
-
const
|
|
5793
|
-
if (!
|
|
5794
|
-
if (
|
|
5795
|
-
const action =
|
|
5796
|
-
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);
|
|
5797
6037
|
if (action === "add") {
|
|
5798
6038
|
const choices = normalizeOptions2(this.options.options);
|
|
5799
6039
|
this._values.push(this.options.options === null ? "" : choices[0]?.[0] ?? "");
|
|
@@ -6280,6 +6520,7 @@ var NumberField = class extends Component {
|
|
|
6280
6520
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
6281
6521
|
_onKeydown(event) {
|
|
6282
6522
|
if (this._disabled || this._readonly) return;
|
|
6523
|
+
if (event.altKey || event.ctrlKey || event.metaKey) return;
|
|
6283
6524
|
const large = Math.max(1, Math.trunc(Number(this.options.largeStep) || 1));
|
|
6284
6525
|
const actions = {
|
|
6285
6526
|
ArrowUp: () => this._stepBy(1),
|
|
@@ -6433,6 +6674,7 @@ function registerNumberFieldAdapter() {
|
|
|
6433
6674
|
label: options.label ? String(options.label) : void 0,
|
|
6434
6675
|
placeholder: options.placeholder,
|
|
6435
6676
|
required: options.required,
|
|
6677
|
+
name: field.name || null,
|
|
6436
6678
|
...options.props ?? {}
|
|
6437
6679
|
}));
|
|
6438
6680
|
let setting = false;
|
|
@@ -6627,7 +6869,7 @@ var Rating = class extends Component {
|
|
|
6627
6869
|
* @returns {HTMLButtonElement}
|
|
6628
6870
|
*/
|
|
6629
6871
|
_radio(value, part) {
|
|
6630
|
-
const
|
|
6872
|
+
const button2 = (
|
|
6631
6873
|
/** @type {HTMLButtonElement} */
|
|
6632
6874
|
h("button", {
|
|
6633
6875
|
class: "zx-rating__radio",
|
|
@@ -6639,18 +6881,18 @@ var Rating = class extends Component {
|
|
|
6639
6881
|
dataset: { value: String(value), part }
|
|
6640
6882
|
})
|
|
6641
6883
|
);
|
|
6642
|
-
this.listen(
|
|
6884
|
+
this.listen(button2, "click", (event) => {
|
|
6643
6885
|
this._choose(
|
|
6644
6886
|
value,
|
|
6645
6887
|
/** @type {MouseEvent} */
|
|
6646
6888
|
event.detail > 0
|
|
6647
6889
|
);
|
|
6648
6890
|
});
|
|
6649
|
-
this.listen(
|
|
6650
|
-
this.listen(
|
|
6651
|
-
this.listen(
|
|
6652
|
-
this._radios.push(
|
|
6653
|
-
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;
|
|
6654
6896
|
}
|
|
6655
6897
|
/**
|
|
6656
6898
|
* @param {number} value Step value.
|
|
@@ -6867,15 +7109,36 @@ function itemText(item) {
|
|
|
6867
7109
|
return String(item ?? "").trim().toLocaleLowerCase();
|
|
6868
7110
|
}
|
|
6869
7111
|
|
|
6870
|
-
// src/components/select/
|
|
6871
|
-
var
|
|
6872
|
-
|
|
6873
|
-
"
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
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
|
+
]);
|
|
6879
7142
|
var DEFAULT_STATUSES = Object.freeze([
|
|
6880
7143
|
["backlog", "status.backlog", "Backlog", "dotted", "muted"],
|
|
6881
7144
|
["todo", "status.todo", "Todo", "ring", "neutral"],
|
|
@@ -6887,6 +7150,79 @@ var DEFAULT_STATUSES = Object.freeze([
|
|
|
6887
7150
|
["canceled", "status.canceled", "Canceled", "canceled", "muted"],
|
|
6888
7151
|
["duplicate", "status.duplicate", "Duplicate", "duplicate", "muted"]
|
|
6889
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"];
|
|
6890
7226
|
var Select = class _Select extends Component {
|
|
6891
7227
|
static cssName = "select";
|
|
6892
7228
|
/** @type {SelectOptions} */
|
|
@@ -6933,6 +7269,7 @@ var Select = class _Select extends Component {
|
|
|
6933
7269
|
this._createdRoot = false;
|
|
6934
7270
|
this._root = null;
|
|
6935
7271
|
this._snapshot = null;
|
|
7272
|
+
this._pointerModality = false;
|
|
6936
7273
|
this._createdRoot = this.el === null;
|
|
6937
7274
|
const root = (
|
|
6938
7275
|
/** @type {HTMLElement} */
|
|
@@ -7021,10 +7358,29 @@ var Select = class _Select extends Component {
|
|
|
7021
7358
|
);
|
|
7022
7359
|
this.listen(input, "click", () => this.open());
|
|
7023
7360
|
this.listen(input, "input", () => this._onInput());
|
|
7024
|
-
this.listen(input, "keydown", (event) =>
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
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 });
|
|
7028
7384
|
this.listen(toggle, "click", () => {
|
|
7029
7385
|
this.focus();
|
|
7030
7386
|
if (this._open) this.close();
|
|
@@ -7037,6 +7393,7 @@ var Select = class _Select extends Component {
|
|
|
7037
7393
|
this.listen(panel, "pointerdown", (event) => event.preventDefault());
|
|
7038
7394
|
this.listen(panel, "click", (event) => this._onOptionClick(event));
|
|
7039
7395
|
this.listen(document, "pointerdown", (event) => {
|
|
7396
|
+
this._pointerModality = true;
|
|
7040
7397
|
if (this._open && !root.contains(
|
|
7041
7398
|
/** @type {Node} */
|
|
7042
7399
|
event.target
|
|
@@ -7187,29 +7544,43 @@ var Select = class _Select extends Component {
|
|
|
7187
7544
|
return this;
|
|
7188
7545
|
}
|
|
7189
7546
|
/**
|
|
7190
|
-
* 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.
|
|
7191
7551
|
* @param {Element|string|null} target Component target.
|
|
7192
|
-
* @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").
|
|
7193
7555
|
* @returns {Select}
|
|
7194
7556
|
*/
|
|
7195
7557
|
static priority(target, options = {}) {
|
|
7196
7558
|
const requestedValue = options.value ?? null;
|
|
7197
|
-
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, {
|
|
7198
7563
|
...options,
|
|
7564
|
+
clearable,
|
|
7199
7565
|
value: null,
|
|
7200
7566
|
items: [],
|
|
7201
7567
|
renderItem(item) {
|
|
7202
7568
|
return priorityContent(item, true);
|
|
7203
7569
|
},
|
|
7570
|
+
renderNone: options.renderNone ?? (() => priorityContent({ level: null, name: noneLabel() }, true)),
|
|
7204
7571
|
renderValueAdornment(item) {
|
|
7205
7572
|
return priorityIndicator(item.level);
|
|
7206
7573
|
}
|
|
7207
7574
|
});
|
|
7575
|
+
if (clearable && !options.placeholder) {
|
|
7576
|
+
select.refs.input.placeholder = noneLabel();
|
|
7577
|
+
}
|
|
7578
|
+
const preset = select;
|
|
7208
7579
|
select.setItems(PRIORITY_KEYS.map((key, level) => {
|
|
7209
|
-
let
|
|
7210
|
-
if (
|
|
7211
|
-
else if (level !== 2)
|
|
7212
|
-
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 };
|
|
7213
7584
|
}));
|
|
7214
7585
|
select.set(requestedValue, { silent: true });
|
|
7215
7586
|
return select;
|
|
@@ -7270,10 +7641,10 @@ var Select = class _Select extends Component {
|
|
|
7270
7641
|
const value = readSelectItem(item, iconKey);
|
|
7271
7642
|
if (value && typeof value === "object" && typeof value.nodeType === "number") return value.cloneNode(true);
|
|
7272
7643
|
if (typeof value !== "string" || !value) return null;
|
|
7273
|
-
const color = readSelectItem(item, colorKey);
|
|
7644
|
+
const color = itemColor(readSelectItem(item, colorKey));
|
|
7274
7645
|
return h("span", {
|
|
7275
7646
|
class: "zx-select__entity-glyph",
|
|
7276
|
-
style:
|
|
7647
|
+
style: color ? { "--zx-select-entity-color": color } : null,
|
|
7277
7648
|
ariaHidden: "true"
|
|
7278
7649
|
}, icon(value, { size: 14 }));
|
|
7279
7650
|
};
|
|
@@ -7805,24 +8176,20 @@ function priorityContent(item, label) {
|
|
|
7805
8176
|
);
|
|
7806
8177
|
}
|
|
7807
8178
|
function priorityIndicator(level) {
|
|
7808
|
-
const
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
dataset: { filled: String(index <= normalized) }
|
|
7815
|
-
})));
|
|
8179
|
+
const glyph = priorityIcon(
|
|
8180
|
+
/** @type {number|null} */
|
|
8181
|
+
normalizePriorityLevel(level)
|
|
8182
|
+
);
|
|
8183
|
+
glyph.classList.add("zx-select__priority-icon");
|
|
8184
|
+
return glyph;
|
|
7816
8185
|
}
|
|
7817
8186
|
function normalizeStatusItem(input) {
|
|
7818
8187
|
if (!input || typeof input !== "object" || input.ID == null || input.name == null) return null;
|
|
7819
|
-
const indicators = ["dotted", "ring", "progress", "review", "ready", "waiting", "done", "canceled", "duplicate"];
|
|
7820
|
-
const tones = ["muted", "neutral", "warning", "info", "accent", "success", "danger"];
|
|
7821
8188
|
return {
|
|
7822
8189
|
...input,
|
|
7823
8190
|
name: String(input.name),
|
|
7824
|
-
indicator:
|
|
7825
|
-
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",
|
|
7826
8193
|
description: input.description == null ? "" : String(input.description),
|
|
7827
8194
|
shortcut: input.shortcut == null ? "" : String(input.shortcut)
|
|
7828
8195
|
};
|
|
@@ -7842,21 +8209,18 @@ function statusContent(item) {
|
|
|
7842
8209
|
);
|
|
7843
8210
|
}
|
|
7844
8211
|
function statusIndicator(item) {
|
|
7845
|
-
const
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
dataset: { indicator, tone: String(item.tone ?? "muted") },
|
|
7849
|
-
ariaHidden: "true"
|
|
7850
|
-
});
|
|
7851
|
-
if (indicator === "done") marker.append(icon("check", { size: 8 }));
|
|
7852
|
-
if (indicator === "canceled") marker.append(icon("x", { size: 7 }));
|
|
7853
|
-
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;
|
|
7854
8215
|
}
|
|
7855
8216
|
function readItem(item, reader) {
|
|
7856
8217
|
if (typeof reader === "function") return reader(item);
|
|
7857
8218
|
if (item === null || typeof item !== "object") return item;
|
|
7858
8219
|
return item[reader];
|
|
7859
8220
|
}
|
|
8221
|
+
function isModifierKey(event) {
|
|
8222
|
+
return ["Shift", "Control", "Alt", "Meta", "CapsLock"].includes(event.key) || event.ctrlKey || event.metaKey;
|
|
8223
|
+
}
|
|
7860
8224
|
function isPrintable(event) {
|
|
7861
8225
|
return event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
7862
8226
|
}
|
|
@@ -7871,6 +8235,7 @@ function registerSelectFieldAdapter() {
|
|
|
7871
8235
|
if (event.target.closest?.(".zx-field__label")) field.adapter.focus();
|
|
7872
8236
|
});
|
|
7873
8237
|
delete selectOptions.preset;
|
|
8238
|
+
if (preset === "priority" && props.clearable === void 0) selectOptions.clearable = !options.required;
|
|
7874
8239
|
const select = field.own(preset === "priority" ? Select.priority(null, selectOptions) : preset === "status" ? Select.status(null, selectOptions) : new Select(null, selectOptions));
|
|
7875
8240
|
field.listen(select.el, "change", (event) => event.stopImmediatePropagation());
|
|
7876
8241
|
select.on("change", (event) => field.emit("change", { value: event.detail.value }));
|
|
@@ -8120,7 +8485,7 @@ var Slider = class extends Component {
|
|
|
8120
8485
|
const label = typeof mark === "number" ? this._format(value) : String(mark.label ?? this._format(value));
|
|
8121
8486
|
element.append(h("span", {
|
|
8122
8487
|
class: "zx-slider__mark",
|
|
8123
|
-
style: { "--zx-slider-mark":
|
|
8488
|
+
style: { "--zx-slider-mark": String(this._ratio(value)) }
|
|
8124
8489
|
}, label));
|
|
8125
8490
|
}
|
|
8126
8491
|
return element;
|
|
@@ -8246,6 +8611,29 @@ function registerSliderFieldAdapter() {
|
|
|
8246
8611
|
});
|
|
8247
8612
|
}
|
|
8248
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
|
+
|
|
8249
8637
|
// src/components/tag-picker/tag-picker.js
|
|
8250
8638
|
var TagPicker = class extends Component {
|
|
8251
8639
|
static cssName = "tag-picker";
|
|
@@ -8257,6 +8645,7 @@ var TagPicker = class extends Component {
|
|
|
8257
8645
|
labelKey: "name",
|
|
8258
8646
|
iconKey: "icon",
|
|
8259
8647
|
colorKey: "color",
|
|
8648
|
+
toneKey: "tone",
|
|
8260
8649
|
searchKeys: null,
|
|
8261
8650
|
filter: "local",
|
|
8262
8651
|
minQuery: 0,
|
|
@@ -8597,11 +8986,12 @@ var TagPicker = class extends Component {
|
|
|
8597
8986
|
_renderTags() {
|
|
8598
8987
|
const tags = this._selected.map((item) => {
|
|
8599
8988
|
const label = this._labelOf(item);
|
|
8600
|
-
const
|
|
8989
|
+
const tone = this._toneOf(item);
|
|
8990
|
+
const color = tone ? null : this._colorOf(item);
|
|
8601
8991
|
const content = this.options.renderTag ? this.options.renderTag(item) : [this._iconOf(item), h("span", { class: "zx-tag-picker__tag-label" }, label)];
|
|
8602
8992
|
const tag = h("span", {
|
|
8603
8993
|
class: "zx-tag-picker__tag",
|
|
8604
|
-
dataset: { colored: String(Boolean(color)) },
|
|
8994
|
+
dataset: { colored: String(Boolean(color)), tone: tone ?? void 0 },
|
|
8605
8995
|
style: color ? { "--zx-tag-color": color } : null
|
|
8606
8996
|
}, content);
|
|
8607
8997
|
if (!this._readonly && !this._disabled) {
|
|
@@ -8970,16 +9360,22 @@ var TagPicker = class extends Component {
|
|
|
8970
9360
|
value.cloneNode(true)
|
|
8971
9361
|
) : typeof value === "string" && value.trim() ? icon(value, { size: 12 }) : null;
|
|
8972
9362
|
if (!visual) return null;
|
|
9363
|
+
const tone = this._toneOf(item);
|
|
9364
|
+
const color = tone ? null : this._colorOf(item);
|
|
8973
9365
|
return h("span", {
|
|
8974
9366
|
class: "zx-tag-picker__visual",
|
|
8975
|
-
|
|
9367
|
+
dataset: { tone: tone ?? void 0 },
|
|
9368
|
+
style: color ? { "--zx-tag-color": color } : null,
|
|
8976
9369
|
ariaHidden: "true"
|
|
8977
9370
|
}, visual);
|
|
8978
9371
|
}
|
|
8979
9372
|
/** @param {unknown} item @returns {string|null} */
|
|
8980
9373
|
_colorOf(item) {
|
|
8981
|
-
|
|
8982
|
-
|
|
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));
|
|
8983
9379
|
}
|
|
8984
9380
|
/** @param {unknown} item @param {unknown} reader @returns {unknown} */
|
|
8985
9381
|
_readItem(item, reader) {
|
|
@@ -9192,7 +9588,7 @@ var Timebox = class extends Component {
|
|
|
9192
9588
|
super.destroy();
|
|
9193
9589
|
}
|
|
9194
9590
|
/** @param {HTMLElement} parent @param {'hours'|'minutes'|'seconds'} name @param {string} label @param {boolean} bounded @returns {void} */
|
|
9195
|
-
_addSegment(parent,
|
|
9591
|
+
_addSegment(parent, name2, label, bounded) {
|
|
9196
9592
|
const input = h("input", {
|
|
9197
9593
|
class: "zx-timebox__segment",
|
|
9198
9594
|
type: "text",
|
|
@@ -9200,13 +9596,13 @@ var Timebox = class extends Component {
|
|
|
9200
9596
|
autocomplete: "off",
|
|
9201
9597
|
ariaLabel: label,
|
|
9202
9598
|
maxLength: bounded ? 2 : null,
|
|
9203
|
-
dataset: { segment:
|
|
9599
|
+
dataset: { segment: name2, bounded: String(bounded) }
|
|
9204
9600
|
});
|
|
9205
9601
|
this._inputs.push(input);
|
|
9206
9602
|
parent.append(input);
|
|
9207
9603
|
this.listen(input, "focus", () => input.select());
|
|
9208
9604
|
this.listen(input, "input", () => {
|
|
9209
|
-
if (
|
|
9605
|
+
if (name2 === "hours" && this.options.signed && input.value.trim().startsWith("-")) {
|
|
9210
9606
|
this._parts.negative = true;
|
|
9211
9607
|
}
|
|
9212
9608
|
const digits = input.value.replace(/\D/g, "");
|
|
@@ -9224,9 +9620,9 @@ var Timebox = class extends Component {
|
|
|
9224
9620
|
_readParts() {
|
|
9225
9621
|
const parts = { ...this._parts };
|
|
9226
9622
|
for (const input of this._inputs) {
|
|
9227
|
-
const
|
|
9623
|
+
const name2 = input.dataset.segment;
|
|
9228
9624
|
const maximum = input.dataset.bounded === "true" ? 59 : Number.MAX_SAFE_INTEGER;
|
|
9229
|
-
parts[
|
|
9625
|
+
parts[name2] = Math.max(0, Math.min(maximum, Math.trunc(finiteNumber2(input.value))));
|
|
9230
9626
|
}
|
|
9231
9627
|
return parts;
|
|
9232
9628
|
}
|
|
@@ -9239,8 +9635,8 @@ var Timebox = class extends Component {
|
|
|
9239
9635
|
/** @returns {void} */
|
|
9240
9636
|
_writeParts() {
|
|
9241
9637
|
for (const input of this._inputs) {
|
|
9242
|
-
const
|
|
9243
|
-
input.value =
|
|
9638
|
+
const name2 = input.dataset.segment;
|
|
9639
|
+
input.value = name2 === "hours" ? String(this._parts[name2]) : pad3(this._parts[name2]);
|
|
9244
9640
|
}
|
|
9245
9641
|
if (this.refs.sign) {
|
|
9246
9642
|
this.refs.sign.textContent = this._parts.negative ? "-" : "+";
|
|
@@ -9429,7 +9825,7 @@ function snapshot(element) {
|
|
|
9429
9825
|
}
|
|
9430
9826
|
function restore(element, state) {
|
|
9431
9827
|
for (const attribute of Array.from(element.attributes)) element.removeAttribute(attribute.name);
|
|
9432
|
-
for (const [
|
|
9828
|
+
for (const [name2, value] of state.attributes) element.setAttribute(name2, value);
|
|
9433
9829
|
element.replaceChildren(...state.children);
|
|
9434
9830
|
}
|
|
9435
9831
|
|
|
@@ -9772,8 +10168,8 @@ var ORDER = (
|
|
|
9772
10168
|
function breakpointOf(width) {
|
|
9773
10169
|
const value = Number(width);
|
|
9774
10170
|
if (!Number.isFinite(value)) return "xs";
|
|
9775
|
-
for (const
|
|
9776
|
-
if (value >= breakpoints[
|
|
10171
|
+
for (const name2 of ORDER) {
|
|
10172
|
+
if (value >= breakpoints[name2]) return name2;
|
|
9777
10173
|
}
|
|
9778
10174
|
return "xs";
|
|
9779
10175
|
}
|
|
@@ -9789,7 +10185,7 @@ function onBreakpoint(handler, options = {}) {
|
|
|
9789
10185
|
/** @type {Element} */
|
|
9790
10186
|
target
|
|
9791
10187
|
) : null;
|
|
9792
|
-
let
|
|
10188
|
+
let name2 = (
|
|
9793
10189
|
/** @type {BreakpointName|null} */
|
|
9794
10190
|
null
|
|
9795
10191
|
);
|
|
@@ -9801,9 +10197,9 @@ function onBreakpoint(handler, options = {}) {
|
|
|
9801
10197
|
const width = measure();
|
|
9802
10198
|
if (element && width === 0) return;
|
|
9803
10199
|
const next = breakpointOf(width);
|
|
9804
|
-
if (next ===
|
|
9805
|
-
|
|
9806
|
-
handler(
|
|
10200
|
+
if (next === name2) return;
|
|
10201
|
+
name2 = next;
|
|
10202
|
+
handler(name2, width);
|
|
9807
10203
|
};
|
|
9808
10204
|
update();
|
|
9809
10205
|
let frame = 0;
|
|
@@ -9821,7 +10217,7 @@ function onBreakpoint(handler, options = {}) {
|
|
|
9821
10217
|
globalThis.addEventListener?.("resize", update, { passive: true });
|
|
9822
10218
|
}
|
|
9823
10219
|
return {
|
|
9824
|
-
current: () =>
|
|
10220
|
+
current: () => name2 ?? breakpointOf(measure()),
|
|
9825
10221
|
destroy: () => {
|
|
9826
10222
|
if (destroyed) return;
|
|
9827
10223
|
destroyed = true;
|
|
@@ -9909,13 +10305,119 @@ function currencyCode(value) {
|
|
|
9909
10305
|
}
|
|
9910
10306
|
|
|
9911
10307
|
// src/core/overlay-host.js
|
|
9912
|
-
var SCOPE_SELECTOR = ".zx-scope, [data-zx-theme], [data-zx-
|
|
10308
|
+
var SCOPE_SELECTOR = ".zx-scope, [data-zx-theme], [data-zx-preset]";
|
|
9913
10309
|
function overlayHost(source = null) {
|
|
9914
10310
|
const context = source == null ? document.activeElement instanceof Element ? document.activeElement : null : resolveElement(source);
|
|
9915
10311
|
const scope2 = context?.closest?.(SCOPE_SELECTOR) ?? null;
|
|
9916
10312
|
if (!scope2 || scope2 === document.documentElement || scope2 === document.body) return document.body;
|
|
9917
10313
|
return scope2;
|
|
9918
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
|
+
}
|
|
9919
10421
|
|
|
9920
10422
|
// src/components/table/sort.js
|
|
9921
10423
|
function compareStrings(left, right) {
|
|
@@ -9974,6 +10476,7 @@ var Table = class extends Component {
|
|
|
9974
10476
|
rowKind: null,
|
|
9975
10477
|
rowKinds: null,
|
|
9976
10478
|
zebra: true,
|
|
10479
|
+
variant: "default",
|
|
9977
10480
|
editMode: false,
|
|
9978
10481
|
editTrigger: "double",
|
|
9979
10482
|
hierarchy: false,
|
|
@@ -10039,6 +10542,7 @@ var Table = class extends Component {
|
|
|
10039
10542
|
}
|
|
10040
10543
|
}
|
|
10041
10544
|
this._reconcileExpanded();
|
|
10545
|
+
if (normalizeTableVariant(this.options.variant) === "plain") root.dataset.variant = "plain";
|
|
10042
10546
|
this._table = h("table", { class: "zx-table__table" });
|
|
10043
10547
|
if (this._hierarchy) this._table.setAttribute("role", "treegrid");
|
|
10044
10548
|
this._colgroup = h("colgroup", { class: "zx-table__columns" });
|
|
@@ -10322,7 +10826,7 @@ var Table = class extends Component {
|
|
|
10322
10826
|
const column = this._columns.find((candidate) => candidate.id === String(id));
|
|
10323
10827
|
const index = this.getColumnOrder().indexOf(String(id));
|
|
10324
10828
|
if (column && index >= 0) {
|
|
10325
|
-
this._columnStatus.textContent = `Moved ${column
|
|
10829
|
+
this._columnStatus.textContent = `Moved ${tableColumnName(column)} to position ${index + 1} of ${this._columns.length}.`;
|
|
10326
10830
|
}
|
|
10327
10831
|
}
|
|
10328
10832
|
return this;
|
|
@@ -10938,8 +11442,8 @@ var Table = class extends Component {
|
|
|
10938
11442
|
{ class: "zx-table__column-controls" },
|
|
10939
11443
|
h(
|
|
10940
11444
|
"summary",
|
|
10941
|
-
{ class: "zx-
|
|
10942
|
-
icon("fields"
|
|
11445
|
+
{ class: "zx-btn", dataset: { size: "sm" } },
|
|
11446
|
+
icon("fields"),
|
|
10943
11447
|
this._message("table.columns", "Columns", [])
|
|
10944
11448
|
),
|
|
10945
11449
|
list
|
|
@@ -10970,26 +11474,27 @@ var Table = class extends Component {
|
|
|
10970
11474
|
disabled: checked && visible.length === 1,
|
|
10971
11475
|
dataset: { columnId: column.id, columnAction: "toggle" }
|
|
10972
11476
|
}) : null;
|
|
10973
|
-
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);
|
|
10974
11479
|
const order = this.options.columnReorder ? h(
|
|
10975
11480
|
"span",
|
|
10976
11481
|
{
|
|
10977
11482
|
class: "zx-table__column-order",
|
|
10978
11483
|
role: "group",
|
|
10979
|
-
ariaLabel: this._message("table.moveColumn", "Move %1", [
|
|
11484
|
+
ariaLabel: this._message("table.moveColumn", "Move %1", [name2])
|
|
10980
11485
|
},
|
|
10981
11486
|
h("button", {
|
|
10982
11487
|
class: "zx-table__column-move",
|
|
10983
11488
|
type: "button",
|
|
10984
11489
|
disabled: index === 0,
|
|
10985
|
-
ariaLabel: `Move ${
|
|
11490
|
+
ariaLabel: `Move ${name2} earlier`,
|
|
10986
11491
|
dataset: { columnId: column.id, columnAction: "up" }
|
|
10987
11492
|
}, icon("chevron-up", { size: 11 })),
|
|
10988
11493
|
h("button", {
|
|
10989
11494
|
class: "zx-table__column-move",
|
|
10990
11495
|
type: "button",
|
|
10991
11496
|
disabled: index === this._columns.length - 1,
|
|
10992
|
-
ariaLabel: `Move ${
|
|
11497
|
+
ariaLabel: `Move ${name2} later`,
|
|
10993
11498
|
dataset: { columnId: column.id, columnAction: "down" }
|
|
10994
11499
|
}, icon("chevron-down", { size: 11 }))
|
|
10995
11500
|
) : null;
|
|
@@ -11040,18 +11545,18 @@ var Table = class extends Component {
|
|
|
11040
11545
|
}
|
|
11041
11546
|
/** @param {Event} event @returns {void} */
|
|
11042
11547
|
_handleColumnControlClick(event) {
|
|
11043
|
-
const
|
|
11548
|
+
const button2 = (
|
|
11044
11549
|
/** @type {Element|null} */
|
|
11045
11550
|
event.target?.closest?.(".zx-table__column-move")
|
|
11046
11551
|
);
|
|
11047
|
-
if (!
|
|
11552
|
+
if (!button2 || !this._columnList?.contains(button2)) return;
|
|
11048
11553
|
const id = (
|
|
11049
11554
|
/** @type {HTMLElement} */
|
|
11050
|
-
|
|
11555
|
+
button2.dataset.columnId
|
|
11051
11556
|
);
|
|
11052
11557
|
const action = (
|
|
11053
11558
|
/** @type {HTMLElement} */
|
|
11054
|
-
|
|
11559
|
+
button2.dataset.columnAction
|
|
11055
11560
|
);
|
|
11056
11561
|
const index = this.getColumnOrder().indexOf(String(id));
|
|
11057
11562
|
if (action === "up" && index > 0) this.moveColumn(String(id), this._columns[index - 1].id, "before");
|
|
@@ -11263,20 +11768,23 @@ var Table = class extends Component {
|
|
|
11263
11768
|
this._headers = /* @__PURE__ */ new Map();
|
|
11264
11769
|
this._headerSpanning = this._spanning;
|
|
11265
11770
|
for (const column of this._visibleColumns()) {
|
|
11266
|
-
const th = h("th", { scope: "col" });
|
|
11771
|
+
const th = h("th", { scope: "col", dataset: { column: column.id } });
|
|
11267
11772
|
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
11268
11773
|
if (align) th.dataset.align = align;
|
|
11269
11774
|
if (column.headerTitle) th.title = column.headerTitle;
|
|
11775
|
+
const name2 = tableHeaderName(column);
|
|
11776
|
+
if (name2 !== null) th.setAttribute("aria-label", name2);
|
|
11270
11777
|
if (column.sortable && !this._spanning) {
|
|
11271
|
-
const
|
|
11778
|
+
const button2 = h("button", {
|
|
11272
11779
|
class: "zx-table__sort-button",
|
|
11273
|
-
type: "button"
|
|
11780
|
+
type: "button",
|
|
11781
|
+
ariaLabel: name2 ?? void 0
|
|
11274
11782
|
}, h("span", { class: "zx-table__header-label" }, column.label));
|
|
11275
|
-
this.listen(
|
|
11783
|
+
this.listen(button2, "click", () => {
|
|
11276
11784
|
const direction = this._sort?.id === column.id && this._sort.dir === "asc" ? "desc" : "asc";
|
|
11277
11785
|
this.setSort(column.id, direction);
|
|
11278
11786
|
});
|
|
11279
|
-
th.append(
|
|
11787
|
+
th.append(button2);
|
|
11280
11788
|
} else {
|
|
11281
11789
|
th.append(h("span", { class: "zx-table__header-label" }, column.label));
|
|
11282
11790
|
}
|
|
@@ -11408,9 +11916,9 @@ var Table = class extends Component {
|
|
|
11408
11916
|
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
11409
11917
|
if (align) cell.dataset.align = align;
|
|
11410
11918
|
cell.dataset.label = column.label;
|
|
11919
|
+
cell.dataset.column = column.id;
|
|
11411
11920
|
if (column.popin === false) cell.dataset.popin = "false";
|
|
11412
11921
|
if (this._editMode !== false) {
|
|
11413
|
-
cell.dataset.column = column.id;
|
|
11414
11922
|
if (resolveEditable(column, row) !== false) {
|
|
11415
11923
|
cell.dataset.editable = "true";
|
|
11416
11924
|
cell.tabIndex = -1;
|
|
@@ -11487,7 +11995,7 @@ var Table = class extends Component {
|
|
|
11487
11995
|
);
|
|
11488
11996
|
return;
|
|
11489
11997
|
}
|
|
11490
|
-
if (isInteractiveCellContent(target)) return;
|
|
11998
|
+
if (this._editMode !== false && isInteractiveCellContent(target)) return;
|
|
11491
11999
|
if (this._editMode !== false && this._editTrigger === "single") {
|
|
11492
12000
|
const cell = target?.closest('td[data-editable="true"]');
|
|
11493
12001
|
if (cell && this._tbody.contains(cell)) {
|
|
@@ -11515,7 +12023,7 @@ var Table = class extends Component {
|
|
|
11515
12023
|
if (!rowElement || !this._tbody.contains(rowElement)) return;
|
|
11516
12024
|
const meta = this._rowMeta.get(rowElement);
|
|
11517
12025
|
if (!meta) return;
|
|
11518
|
-
if (isInteractiveCellContent(target)) return;
|
|
12026
|
+
if (this._editMode !== false && isInteractiveCellContent(target)) return;
|
|
11519
12027
|
if (this._editMode !== false && this._editTrigger === "double") {
|
|
11520
12028
|
const cell = target?.closest('td[data-editable="true"]');
|
|
11521
12029
|
if (cell && this._tbody.contains(cell)) {
|
|
@@ -11651,7 +12159,7 @@ var Table = class extends Component {
|
|
|
11651
12159
|
...props,
|
|
11652
12160
|
class: textarea ? "zx-table__editor-input zx-table__editor-textarea" : "zx-table__editor-input",
|
|
11653
12161
|
...textarea ? {} : { type: "text" },
|
|
11654
|
-
ariaLabel: props.ariaLabel ?? `${column
|
|
12162
|
+
ariaLabel: props.ariaLabel ?? `${tableColumnName(column)} row ${index + 1}`,
|
|
11655
12163
|
value: formatCellValue(column, value, row)
|
|
11656
12164
|
})
|
|
11657
12165
|
);
|
|
@@ -11670,7 +12178,7 @@ var Table = class extends Component {
|
|
|
11670
12178
|
const control = entry?.control;
|
|
11671
12179
|
if (!control || typeof control.focus !== "function") return;
|
|
11672
12180
|
control.focus();
|
|
11673
|
-
if (entry.type
|
|
12181
|
+
if (editorSelectsOnEntry(entry.type) && typeof control.select === "function") control.select();
|
|
11674
12182
|
}
|
|
11675
12183
|
/**
|
|
11676
12184
|
* Moves focus back onto a cell.
|
|
@@ -12308,6 +12816,9 @@ function normalizeRowKinds(option) {
|
|
|
12308
12816
|
function initialExpanded(option) {
|
|
12309
12817
|
return new Set(Array.isArray(option) ? option : []);
|
|
12310
12818
|
}
|
|
12819
|
+
function normalizeTableVariant(value) {
|
|
12820
|
+
return value === "plain" ? "plain" : "default";
|
|
12821
|
+
}
|
|
12311
12822
|
function normalizeEditMode(mode) {
|
|
12312
12823
|
if (mode === "cell" || mode === "row") return mode;
|
|
12313
12824
|
return mode === true ? "cell" : false;
|
|
@@ -12350,6 +12861,22 @@ function normalizeTableColumns(columns) {
|
|
|
12350
12861
|
return { ...column, id, label: String(column.label ?? id) };
|
|
12351
12862
|
});
|
|
12352
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
|
+
}
|
|
12353
12880
|
function reconcileTableColumnOrder(columns, order) {
|
|
12354
12881
|
const available = columns.map((column) => column.id);
|
|
12355
12882
|
const allowed = new Set(available);
|
|
@@ -12526,8 +13053,8 @@ function normalizeGlass(value) {
|
|
|
12526
13053
|
function normalizeShape(value) {
|
|
12527
13054
|
return value === "circle" ? "circle" : "tile";
|
|
12528
13055
|
}
|
|
12529
|
-
function originalAttribute(snapshot3,
|
|
12530
|
-
return snapshot3?.attributes.find(([attribute]) => attribute ===
|
|
13056
|
+
function originalAttribute(snapshot3, name2) {
|
|
13057
|
+
return snapshot3?.attributes.find(([attribute]) => attribute === name2)?.[1] ?? null;
|
|
12531
13058
|
}
|
|
12532
13059
|
|
|
12533
13060
|
// src/components/launcher/launcher.js
|
|
@@ -12591,9 +13118,17 @@ var Launcher = class extends Component {
|
|
|
12591
13118
|
this._requestSequence = 0;
|
|
12592
13119
|
this._queryTimer = null;
|
|
12593
13120
|
this._busy = false;
|
|
13121
|
+
this._settled = true;
|
|
13122
|
+
this._pages = [];
|
|
13123
|
+
this._restoreActiveId = null;
|
|
13124
|
+
this._announcePending = false;
|
|
13125
|
+
this._announceToggle = false;
|
|
12594
13126
|
this._destroyed = false;
|
|
12595
13127
|
const listId = uid("zx-launcher-results");
|
|
12596
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;
|
|
12597
13132
|
const input = h("input", {
|
|
12598
13133
|
ref: "input",
|
|
12599
13134
|
class: "zx-launcher__input",
|
|
@@ -12605,9 +13140,20 @@ var Launcher = class extends Component {
|
|
|
12605
13140
|
ariaControls: listId,
|
|
12606
13141
|
ariaExpanded: "false",
|
|
12607
13142
|
ariaLabel: label,
|
|
12608
|
-
placeholder
|
|
13143
|
+
placeholder,
|
|
12609
13144
|
value: this._query
|
|
12610
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
|
+
);
|
|
12611
13157
|
const close = h("button", {
|
|
12612
13158
|
ref: "close",
|
|
12613
13159
|
class: "zx-icon-btn zx-launcher__close",
|
|
@@ -12620,6 +13166,13 @@ var Launcher = class extends Component {
|
|
|
12620
13166
|
role: "status",
|
|
12621
13167
|
ariaLive: "polite"
|
|
12622
13168
|
});
|
|
13169
|
+
const announce = h("div", {
|
|
13170
|
+
ref: "announce",
|
|
13171
|
+
class: "zx-launcher__announce",
|
|
13172
|
+
role: "status",
|
|
13173
|
+
ariaLive: "polite",
|
|
13174
|
+
ariaAtomic: "true"
|
|
13175
|
+
});
|
|
12623
13176
|
const results = h("div", {
|
|
12624
13177
|
ref: "results",
|
|
12625
13178
|
class: "zx-launcher__results",
|
|
@@ -12634,6 +13187,7 @@ var Launcher = class extends Component {
|
|
|
12634
13187
|
const footer = launcherHints(this.options.hints, {
|
|
12635
13188
|
move: this._message("launcher.hintMove", "Move"),
|
|
12636
13189
|
open: this._message("launcher.hintOpen", "Open"),
|
|
13190
|
+
back: this._message("launcher.hintBack", "Back"),
|
|
12637
13191
|
close: this._message("launcher.hintClose", "Close")
|
|
12638
13192
|
});
|
|
12639
13193
|
dialog.setAttribute("aria-label", label);
|
|
@@ -12644,17 +13198,19 @@ var Launcher = class extends Component {
|
|
|
12644
13198
|
h("div", {
|
|
12645
13199
|
class: "zx-launcher__search",
|
|
12646
13200
|
dataset: { shortcut: shortcut ? "true" : "false" }
|
|
12647
|
-
}, icon("search"), input, shortcut, close),
|
|
13201
|
+
}, icon("search"), scope2, input, shortcut, close),
|
|
12648
13202
|
status,
|
|
12649
13203
|
results,
|
|
12650
|
-
footer
|
|
13204
|
+
footer,
|
|
13205
|
+
announce
|
|
12651
13206
|
)
|
|
12652
13207
|
);
|
|
12653
13208
|
dialog.dataset.state = "closed";
|
|
12654
|
-
if (this._createdRoot)
|
|
13209
|
+
if (this._createdRoot) connectedOverlayHost(this.options.scope)?.append(dialog);
|
|
12655
13210
|
this.listen(input, "input", () => {
|
|
12656
13211
|
this._query = /** @type {HTMLInputElement} */
|
|
12657
13212
|
input.value;
|
|
13213
|
+
this._announcePending = false;
|
|
12658
13214
|
this.emit("query", { query: this._query.trim() });
|
|
12659
13215
|
this._refresh();
|
|
12660
13216
|
});
|
|
@@ -12662,6 +13218,10 @@ var Launcher = class extends Component {
|
|
|
12662
13218
|
/** @type {KeyboardEvent} */
|
|
12663
13219
|
event
|
|
12664
13220
|
));
|
|
13221
|
+
this.listen(scopeBack, "click", () => {
|
|
13222
|
+
this.back();
|
|
13223
|
+
input.focus();
|
|
13224
|
+
});
|
|
12665
13225
|
this.listen(close, "click", () => this.close());
|
|
12666
13226
|
this.listen(results, "click", (event) => {
|
|
12667
13227
|
const option = (
|
|
@@ -12690,6 +13250,13 @@ var Launcher = class extends Component {
|
|
|
12690
13250
|
dialog.dataset.state = "closed";
|
|
12691
13251
|
input.setAttribute("aria-expanded", "false");
|
|
12692
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
|
+
}
|
|
12693
13260
|
this.emit("close");
|
|
12694
13261
|
});
|
|
12695
13262
|
this.listen(document, "keydown", (event) => this._onDocumentKeydown(
|
|
@@ -12699,25 +13266,60 @@ var Launcher = class extends Component {
|
|
|
12699
13266
|
this._renderResults();
|
|
12700
13267
|
return dialog;
|
|
12701
13268
|
}
|
|
12702
|
-
/**
|
|
12703
|
-
|
|
12704
|
-
|
|
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
|
+
}
|
|
12705
13285
|
if (this._createdRoot) {
|
|
12706
13286
|
const host = overlayHost(this.options.scope);
|
|
12707
13287
|
if (this.el.parentElement !== host) host.append(this.el);
|
|
12708
13288
|
}
|
|
13289
|
+
const before = this._pages.map((entry) => entry.page);
|
|
12709
13290
|
this.el.showModal();
|
|
12710
13291
|
this.el.dataset.state = "open";
|
|
12711
13292
|
this.refs.input.setAttribute("aria-expanded", "true");
|
|
12712
|
-
this.
|
|
13293
|
+
this._goTo(target == null ? [] : this._pagePath(target), { emit: false });
|
|
12713
13294
|
queueMicrotask(() => {
|
|
12714
13295
|
if (!this.isOpen()) return;
|
|
12715
13296
|
this.refs.input.focus();
|
|
12716
13297
|
this.refs.input.select();
|
|
12717
13298
|
});
|
|
12718
13299
|
this.emit("open");
|
|
13300
|
+
if (!samePath(before, this._pages.map((entry) => entry.page))) this._emitPage();
|
|
13301
|
+
return this;
|
|
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();
|
|
12719
13317
|
return this;
|
|
12720
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
|
+
}
|
|
12721
13323
|
/** Closes the launcher. @returns {this} */
|
|
12722
13324
|
close() {
|
|
12723
13325
|
if (this.isOpen()) this.el.close();
|
|
@@ -12741,6 +13343,7 @@ var Launcher = class extends Component {
|
|
|
12741
13343
|
setQuery(query) {
|
|
12742
13344
|
this._query = String(query ?? "");
|
|
12743
13345
|
this.refs.input.value = this._query;
|
|
13346
|
+
this._announcePending = false;
|
|
12744
13347
|
this.emit("query", { query: this._query.trim() });
|
|
12745
13348
|
this._refresh();
|
|
12746
13349
|
return this;
|
|
@@ -12749,7 +13352,7 @@ var Launcher = class extends Component {
|
|
|
12749
13352
|
getQuery() {
|
|
12750
13353
|
return this._query;
|
|
12751
13354
|
}
|
|
12752
|
-
/** 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} */
|
|
12753
13356
|
setItems(items) {
|
|
12754
13357
|
this._items = normalizeItems(items);
|
|
12755
13358
|
this._renderResults();
|
|
@@ -12762,10 +13365,14 @@ var Launcher = class extends Component {
|
|
|
12762
13365
|
this._renderResults();
|
|
12763
13366
|
return this;
|
|
12764
13367
|
}
|
|
12765
|
-
/** 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} */
|
|
12766
13369
|
setSources(sources) {
|
|
12767
|
-
this._abortRequest();
|
|
12768
13370
|
this._sources = normalizeSources(sources);
|
|
13371
|
+
if (this._pages.length) {
|
|
13372
|
+
this._pages[0].parent.sourceItems = null;
|
|
13373
|
+
return this;
|
|
13374
|
+
}
|
|
13375
|
+
this._abortRequest();
|
|
12769
13376
|
this._sourceItems.clear();
|
|
12770
13377
|
this._refresh();
|
|
12771
13378
|
return this;
|
|
@@ -12780,16 +13387,24 @@ var Launcher = class extends Component {
|
|
|
12780
13387
|
super.destroy();
|
|
12781
13388
|
if (!this._createdRoot && original) {
|
|
12782
13389
|
for (const attribute of Array.from(this.el.attributes)) this.el.removeAttribute(attribute.name);
|
|
12783
|
-
for (const [
|
|
13390
|
+
for (const [name2, value] of original.attributes) this.el.setAttribute(name2, value);
|
|
12784
13391
|
this.el.replaceChildren(...original.children);
|
|
12785
13392
|
}
|
|
12786
13393
|
}
|
|
12787
|
-
/**
|
|
12788
|
-
|
|
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();
|
|
12789
13402
|
this._sourceItems.clear();
|
|
13403
|
+
const { sources } = this._level();
|
|
13404
|
+
this._settled = sources.length === 0;
|
|
13405
|
+
if (immediate && sources.length) void this._loadSources();
|
|
12790
13406
|
this._renderResults();
|
|
12791
|
-
|
|
12792
|
-
if (this._sources.length === 0) return;
|
|
13407
|
+
if (immediate || sources.length === 0) return;
|
|
12793
13408
|
const delay = Math.max(0, Number(this.options.debounce) || 0);
|
|
12794
13409
|
this._queryTimer = setTimeout(() => this._loadSources(), delay);
|
|
12795
13410
|
}
|
|
@@ -12797,8 +13412,15 @@ var Launcher = class extends Component {
|
|
|
12797
13412
|
async _loadSources() {
|
|
12798
13413
|
this._queryTimer = null;
|
|
12799
13414
|
const query = this._query.trim();
|
|
12800
|
-
const
|
|
12801
|
-
|
|
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
|
+
}
|
|
12802
13424
|
const request = new AbortController();
|
|
12803
13425
|
const sequence = ++this._requestSequence;
|
|
12804
13426
|
this._request = request;
|
|
@@ -12809,7 +13431,7 @@ var Launcher = class extends Component {
|
|
|
12809
13431
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
12810
13432
|
this._sourceItems.set(source.id, normalizeItems(loaded).map((item, itemOrder) => ({
|
|
12811
13433
|
...item,
|
|
12812
|
-
_source: source.id,
|
|
13434
|
+
_source: source._page ? null : source.id,
|
|
12813
13435
|
_sourceOrder: source.order === "source",
|
|
12814
13436
|
group: item.group ?? source.label ?? "",
|
|
12815
13437
|
itemOrder: item.itemOrder ?? (source.order === "source" ? itemOrder : void 0)
|
|
@@ -12817,13 +13439,157 @@ var Launcher = class extends Component {
|
|
|
12817
13439
|
this._renderResults();
|
|
12818
13440
|
} catch (error) {
|
|
12819
13441
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
12820
|
-
this.emit("error", { source, error });
|
|
13442
|
+
this.emit("error", { source, error, page });
|
|
12821
13443
|
}
|
|
12822
13444
|
}));
|
|
12823
13445
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
12824
13446
|
this._request = null;
|
|
13447
|
+
this._settled = true;
|
|
12825
13448
|
this._setBusy(false);
|
|
12826
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
|
+
}
|
|
12827
13593
|
/** @param {boolean} busy @returns {void} */
|
|
12828
13594
|
_setBusy(busy) {
|
|
12829
13595
|
this._busy = busy;
|
|
@@ -12842,11 +13608,14 @@ var Launcher = class extends Component {
|
|
|
12842
13608
|
/** @returns {void} */
|
|
12843
13609
|
_renderResults() {
|
|
12844
13610
|
const queryKey = this._query;
|
|
12845
|
-
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);
|
|
12846
13614
|
const query = this._query.trim();
|
|
12847
|
-
const
|
|
13615
|
+
const level = this._level();
|
|
13616
|
+
const local = level.items.filter((item) => visibleForQuery(item.when, query));
|
|
12848
13617
|
const rankedLocal = rankLauncherItems(local, query, this.options.maxResults);
|
|
12849
|
-
const remote =
|
|
13618
|
+
const remote = level.sources.flatMap((source) => {
|
|
12850
13619
|
const loaded = this._sourceItems.get(String(source.id)) ?? [];
|
|
12851
13620
|
return source.order === "source" ? loaded.filter((item) => visibleForQuery(item.when, query)) : rankLauncherItems(
|
|
12852
13621
|
loaded.filter((item) => visibleForQuery(item.when, query)),
|
|
@@ -12889,7 +13658,8 @@ var Launcher = class extends Component {
|
|
|
12889
13658
|
}
|
|
12890
13659
|
/** @param {RankedLauncherItem} item @param {number} index @returns {HTMLElement} */
|
|
12891
13660
|
_option(item, index) {
|
|
12892
|
-
const
|
|
13661
|
+
const page = isLauncherPage(item);
|
|
13662
|
+
const href = page ? null : safeHref(item.href);
|
|
12893
13663
|
const tag = href ? "a" : "button";
|
|
12894
13664
|
const children = [];
|
|
12895
13665
|
const visual = launcherItemIcon(item);
|
|
@@ -12904,6 +13674,17 @@ var Launcher = class extends Component {
|
|
|
12904
13674
|
item.description ? h("span", { class: "zx-launcher__description" }, item.description) : null
|
|
12905
13675
|
));
|
|
12906
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")));
|
|
12907
13688
|
return (
|
|
12908
13689
|
/** @type {HTMLElement} */
|
|
12909
13690
|
h(tag, {
|
|
@@ -12918,10 +13699,12 @@ var Launcher = class extends Component {
|
|
|
12918
13699
|
ariaSelected: "false",
|
|
12919
13700
|
ariaDisabled: item.disabled ? "true" : null,
|
|
12920
13701
|
ariaCurrent: item.current ? "page" : null,
|
|
13702
|
+
ariaKeyShortcuts: keys,
|
|
12921
13703
|
dataset: {
|
|
12922
13704
|
launcherIndex: index,
|
|
12923
13705
|
pinned: item.pinned !== void 0 && item.pinned !== false ? "true" : null,
|
|
12924
|
-
kind: normalizeLauncherKind(item.kind)
|
|
13706
|
+
kind: normalizeLauncherKind(item.kind),
|
|
13707
|
+
page: page ? "true" : null
|
|
12925
13708
|
}
|
|
12926
13709
|
}, children)
|
|
12927
13710
|
);
|
|
@@ -12936,6 +13719,11 @@ var Launcher = class extends Component {
|
|
|
12936
13719
|
this.refs.status.textContent = "";
|
|
12937
13720
|
}
|
|
12938
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
|
+
}
|
|
12939
13727
|
}
|
|
12940
13728
|
/** @returns {void} */
|
|
12941
13729
|
_syncActive() {
|
|
@@ -12954,6 +13742,12 @@ var Launcher = class extends Component {
|
|
|
12954
13742
|
this.close();
|
|
12955
13743
|
return;
|
|
12956
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
|
+
}
|
|
12957
13751
|
if (event.key === "Enter") {
|
|
12958
13752
|
if (this._active < 0) return;
|
|
12959
13753
|
event.preventDefault();
|
|
@@ -12962,9 +13756,8 @@ var Launcher = class extends Component {
|
|
|
12962
13756
|
return;
|
|
12963
13757
|
}
|
|
12964
13758
|
const enabled = this._results.map((item, index) => item.disabled ? -1 : index).filter((index) => index >= 0);
|
|
12965
|
-
if (enabled.length === 0) return;
|
|
12966
13759
|
if (/^Arrow(?:Left|Right|Up|Down)$/.test(event.key)) {
|
|
12967
|
-
const next = this._spatialIndex(event.key, enabled);
|
|
13760
|
+
const next = enabled.length ? this._spatialIndex(event.key, enabled) : null;
|
|
12968
13761
|
if (next !== null) {
|
|
12969
13762
|
event.preventDefault();
|
|
12970
13763
|
this._active = next;
|
|
@@ -12972,8 +13765,12 @@ var Launcher = class extends Component {
|
|
|
12972
13765
|
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
12973
13766
|
return;
|
|
12974
13767
|
}
|
|
12975
|
-
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
|
+
}
|
|
12976
13772
|
}
|
|
13773
|
+
if (enabled.length === 0) return;
|
|
12977
13774
|
let position2 = enabled.indexOf(this._active);
|
|
12978
13775
|
if (event.key === "Home" || event.key === "PageUp") position2 = 0;
|
|
12979
13776
|
else if (event.key === "End" || event.key === "PageDown") position2 = enabled.length - 1;
|
|
@@ -12985,6 +13782,30 @@ var Launcher = class extends Component {
|
|
|
12985
13782
|
this._syncActive();
|
|
12986
13783
|
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest" });
|
|
12987
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
|
+
}
|
|
12988
13809
|
/** @param {string} direction @param {number[]} enabled @returns {number|null} */
|
|
12989
13810
|
_spatialIndex(direction, enabled) {
|
|
12990
13811
|
const current = this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`);
|
|
@@ -13001,21 +13822,28 @@ var Launcher = class extends Component {
|
|
|
13001
13822
|
event.preventDefault();
|
|
13002
13823
|
return;
|
|
13003
13824
|
}
|
|
13825
|
+
if (isLauncherPage(item)) {
|
|
13826
|
+
event.preventDefault();
|
|
13827
|
+
this._openPage(item);
|
|
13828
|
+
this.refs.input.focus();
|
|
13829
|
+
return;
|
|
13830
|
+
}
|
|
13004
13831
|
const selected = this.emit("select", {
|
|
13005
13832
|
item,
|
|
13006
13833
|
value: item.value ?? item.id,
|
|
13007
13834
|
source: item._source ?? null,
|
|
13008
|
-
query: this._query.trim()
|
|
13835
|
+
query: this._query.trim(),
|
|
13836
|
+
page: this.getPage()
|
|
13009
13837
|
});
|
|
13010
13838
|
if (selected.defaultPrevented) {
|
|
13011
13839
|
event.preventDefault();
|
|
13012
13840
|
return;
|
|
13013
13841
|
}
|
|
13842
|
+
this.close();
|
|
13014
13843
|
if (!item.href) {
|
|
13015
13844
|
event.preventDefault();
|
|
13016
13845
|
item.invoke?.();
|
|
13017
13846
|
}
|
|
13018
|
-
this.close();
|
|
13019
13847
|
}
|
|
13020
13848
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
13021
13849
|
_onDocumentKeydown(event) {
|
|
@@ -13031,11 +13859,12 @@ var Launcher = class extends Component {
|
|
|
13031
13859
|
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
13032
13860
|
* @param {string} key Message key.
|
|
13033
13861
|
* @param {string} fallback English default.
|
|
13862
|
+
* @param {...unknown} args Positional `%1`, `%2` values.
|
|
13034
13863
|
* @returns {string}
|
|
13035
13864
|
*/
|
|
13036
|
-
_message(key, fallback) {
|
|
13037
|
-
const message = this.msg(key);
|
|
13038
|
-
return message === key ? fallback : message;
|
|
13865
|
+
_message(key, fallback, ...args) {
|
|
13866
|
+
const message = this.msg(key, ...args);
|
|
13867
|
+
return message === key ? printf(fallback, args) : message;
|
|
13039
13868
|
}
|
|
13040
13869
|
};
|
|
13041
13870
|
function launcherShortcutLabel() {
|
|
@@ -13045,16 +13874,73 @@ function launcherShortcutLabel() {
|
|
|
13045
13874
|
);
|
|
13046
13875
|
return /mac|iphone|ipad/i.test(platform) ? "\u2318 K" : "Ctrl K";
|
|
13047
13876
|
}
|
|
13048
|
-
function launcherHints(hints,
|
|
13877
|
+
function launcherHints(hints, defaults4) {
|
|
13049
13878
|
if (hints === false) return null;
|
|
13050
13879
|
const labels = hints && typeof hints === "object" ? hints : {};
|
|
13051
13880
|
return h(
|
|
13052
13881
|
"footer",
|
|
13053
13882
|
{ class: "zx-launcher__hints", ariaHidden: "true" },
|
|
13054
|
-
h("span", {}, h("kbd", {}, "\u2191\u2193\u2190\u2192"), labels.move ??
|
|
13055
|
-
h("span", {}, h("kbd", {}, "\u21B5"), labels.open ??
|
|
13056
|
-
|
|
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
|
|
13057
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));
|
|
13058
13944
|
}
|
|
13059
13945
|
function launcherItemIcon(item) {
|
|
13060
13946
|
let visual = item.icon;
|
|
@@ -13175,7 +14061,7 @@ function normalizeLauncherItem(item) {
|
|
|
13175
14061
|
if (href !== null) normalized.href = href;
|
|
13176
14062
|
else {
|
|
13177
14063
|
delete normalized.href;
|
|
13178
|
-
if (typeof normalized.invoke !== "function") normalized.disabled = true;
|
|
14064
|
+
if (typeof normalized.invoke !== "function" && !isLauncherPage(normalized)) normalized.disabled = true;
|
|
13179
14065
|
}
|
|
13180
14066
|
return normalized;
|
|
13181
14067
|
}
|
|
@@ -13185,6 +14071,7 @@ function normalizeSources(sources) {
|
|
|
13185
14071
|
}
|
|
13186
14072
|
|
|
13187
14073
|
// src/components/message/message.js
|
|
14074
|
+
var MESSAGE_ACTION_MIN_TIMEOUT = 8e3;
|
|
13188
14075
|
var MessageQueue = class {
|
|
13189
14076
|
#limit;
|
|
13190
14077
|
#active = [];
|
|
@@ -13275,7 +14162,7 @@ var Message = class _Message extends Component {
|
|
|
13275
14162
|
closable: true,
|
|
13276
14163
|
maxVisible: 5
|
|
13277
14164
|
};
|
|
13278
|
-
/** @type {WeakMap<Element, Message>} */
|
|
14165
|
+
/** @type {WeakMap<Element, Message>} Floating region per overlay host. */
|
|
13279
14166
|
static #floating = /* @__PURE__ */ new WeakMap();
|
|
13280
14167
|
/** @returns {HTMLElement} */
|
|
13281
14168
|
render() {
|
|
@@ -13287,6 +14174,7 @@ var Message = class _Message extends Component {
|
|
|
13287
14174
|
this._createdRoot = created;
|
|
13288
14175
|
this._original = created ? null : snapshot2(root);
|
|
13289
14176
|
this._entries = /* @__PURE__ */ new Set();
|
|
14177
|
+
this._floatingHost = null;
|
|
13290
14178
|
this._queue = new MessageQueue(normalizeLimit(this.options.maxVisible), (entry) => {
|
|
13291
14179
|
this._activate(entry);
|
|
13292
14180
|
});
|
|
@@ -13302,10 +14190,13 @@ var Message = class _Message extends Component {
|
|
|
13302
14190
|
* @returns {MessageHandle}
|
|
13303
14191
|
*/
|
|
13304
14192
|
show(msg, options = {}) {
|
|
14193
|
+
const action = normalizeMessageAction(options.action);
|
|
13305
14194
|
const settings = {
|
|
13306
|
-
kind:
|
|
13307
|
-
timeout:
|
|
13308
|
-
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)
|
|
13309
14200
|
};
|
|
13310
14201
|
const entry = this._createEntry(msg, settings);
|
|
13311
14202
|
this._entries.add(entry);
|
|
@@ -13366,10 +14257,32 @@ var Message = class _Message extends Component {
|
|
|
13366
14257
|
static progress(text3, options = {}) {
|
|
13367
14258
|
return this.#floatingRegion(options.scope)._progress(text3);
|
|
13368
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
|
+
}
|
|
13369
14281
|
/** @returns {void} */
|
|
13370
14282
|
destroy() {
|
|
13371
14283
|
if (this._cleaned) return;
|
|
13372
14284
|
this._cleaned = true;
|
|
14285
|
+
this._floatingHost = null;
|
|
13373
14286
|
for (const entry of this._entries) {
|
|
13374
14287
|
clearEntryTimers(entry);
|
|
13375
14288
|
entry.node.remove();
|
|
@@ -13421,7 +14334,7 @@ var Message = class _Message extends Component {
|
|
|
13421
14334
|
}
|
|
13422
14335
|
/**
|
|
13423
14336
|
* @param {string|Node} msg
|
|
13424
|
-
* @param {{kind: MessageKind, timeout: number, closable: boolean}} settings
|
|
14337
|
+
* @param {{kind: MessageKind, timeout: number, closable: boolean, action?: MessageAction|null, leading?: Node|null}} settings
|
|
13425
14338
|
* @param {{pct: number, text: string}|null} [progress=null]
|
|
13426
14339
|
* @returns {any}
|
|
13427
14340
|
*/
|
|
@@ -13429,7 +14342,7 @@ var Message = class _Message extends Component {
|
|
|
13429
14342
|
const iconHost = h(
|
|
13430
14343
|
"span",
|
|
13431
14344
|
{ class: "zx-message__icon", ariaHidden: "true" },
|
|
13432
|
-
icon(settings.kind, { size: 18 })
|
|
14345
|
+
settings.leading ?? icon(settings.kind, { size: 18 })
|
|
13433
14346
|
);
|
|
13434
14347
|
const content = h("div", { class: "zx-message__content" });
|
|
13435
14348
|
if (isNode(msg)) content.append(msg);
|
|
@@ -13450,9 +14363,13 @@ var Message = class _Message extends Component {
|
|
|
13450
14363
|
timer: null,
|
|
13451
14364
|
exitTimer: null,
|
|
13452
14365
|
closed: false,
|
|
14366
|
+
hovered: false,
|
|
14367
|
+
focused: false,
|
|
14368
|
+
returnFocus: null,
|
|
13453
14369
|
progressBar: null,
|
|
13454
14370
|
progressFill: null
|
|
13455
14371
|
};
|
|
14372
|
+
if (settings.leading) node.dataset.leading = "";
|
|
13456
14373
|
if (progress) {
|
|
13457
14374
|
node.dataset.progress = "";
|
|
13458
14375
|
const fill = h("span", { class: "zx-message__progress-fill" });
|
|
@@ -13469,6 +14386,23 @@ var Message = class _Message extends Component {
|
|
|
13469
14386
|
entry.progressFill = fill;
|
|
13470
14387
|
syncProgress(entry, progress);
|
|
13471
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
|
+
}
|
|
13472
14406
|
if (settings.closable) {
|
|
13473
14407
|
const close = h("button", {
|
|
13474
14408
|
class: "zx-icon-btn zx-message__close",
|
|
@@ -13479,8 +14413,40 @@ var Message = class _Message extends Component {
|
|
|
13479
14413
|
node.append(close);
|
|
13480
14414
|
this.listen(close, "click", () => this._close(entry));
|
|
13481
14415
|
}
|
|
13482
|
-
this.listen(node, "mouseenter", () =>
|
|
13483
|
-
|
|
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
|
+
});
|
|
13484
14450
|
return entry;
|
|
13485
14451
|
}
|
|
13486
14452
|
/** @param {any} entry @returns {void} */
|
|
@@ -13492,7 +14458,7 @@ var Message = class _Message extends Component {
|
|
|
13492
14458
|
}
|
|
13493
14459
|
/** @param {any} entry @returns {void} */
|
|
13494
14460
|
_schedule(entry) {
|
|
13495
|
-
if (entry.closed || entry.remaining <= 0) return;
|
|
14461
|
+
if (entry.closed || entry.remaining <= 0 || entry.hovered || entry.focused) return;
|
|
13496
14462
|
entry.startedAt = Date.now();
|
|
13497
14463
|
entry.timer = setTimeout(() => this._close(entry), entry.remaining);
|
|
13498
14464
|
}
|
|
@@ -13505,7 +14471,7 @@ var Message = class _Message extends Component {
|
|
|
13505
14471
|
}
|
|
13506
14472
|
/** @param {any} entry @returns {void} */
|
|
13507
14473
|
_resume(entry) {
|
|
13508
|
-
if (entry.closed || entry.timer !== null) return;
|
|
14474
|
+
if (entry.closed || entry.timer !== null || entry.hovered || entry.focused) return;
|
|
13509
14475
|
if (entry.remaining <= 0) {
|
|
13510
14476
|
this._close(entry);
|
|
13511
14477
|
return;
|
|
@@ -13517,10 +14483,12 @@ var Message = class _Message extends Component {
|
|
|
13517
14483
|
if (entry.closed) return;
|
|
13518
14484
|
entry.closed = true;
|
|
13519
14485
|
clearEntryTimers(entry);
|
|
14486
|
+
returnFocus(entry);
|
|
13520
14487
|
if (!this._queue.isActive(entry)) {
|
|
13521
14488
|
this._queue.remove(entry);
|
|
13522
14489
|
entry.node.remove();
|
|
13523
14490
|
this._entries.delete(entry);
|
|
14491
|
+
this._releaseIfEmpty();
|
|
13524
14492
|
return;
|
|
13525
14493
|
}
|
|
13526
14494
|
entry.node.dataset.state = "closing";
|
|
@@ -13541,6 +14509,25 @@ var Message = class _Message extends Component {
|
|
|
13541
14509
|
entry.node.remove();
|
|
13542
14510
|
this._entries.delete(entry);
|
|
13543
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();
|
|
13544
14531
|
}
|
|
13545
14532
|
/**
|
|
13546
14533
|
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
@@ -13552,11 +14539,22 @@ var Message = class _Message extends Component {
|
|
|
13552
14539
|
const message = this.msg(key);
|
|
13553
14540
|
return message === key ? fallback : message;
|
|
13554
14541
|
}
|
|
13555
|
-
/**
|
|
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
|
+
*/
|
|
13556
14549
|
static #floatingRegion(scope2) {
|
|
13557
|
-
|
|
14550
|
+
let host = overlayHost(scope2 ?? null);
|
|
14551
|
+
if (!host.isConnected) host = overlayHost(null);
|
|
13558
14552
|
const existing = this.#floating.get(host);
|
|
13559
|
-
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
|
+
}
|
|
13560
14558
|
const region = h("div", {
|
|
13561
14559
|
class: "zx-message-region",
|
|
13562
14560
|
popover: "manual",
|
|
@@ -13565,12 +14563,19 @@ var Message = class _Message extends Component {
|
|
|
13565
14563
|
});
|
|
13566
14564
|
host.append(region);
|
|
13567
14565
|
const floating = new _Message(region);
|
|
14566
|
+
floating._floatingHost = host;
|
|
13568
14567
|
this.#floating.set(host, floating);
|
|
13569
14568
|
if (typeof region.showPopover === "function") region.showPopover();
|
|
13570
14569
|
return floating;
|
|
13571
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
|
+
}
|
|
13572
14577
|
};
|
|
13573
|
-
function
|
|
14578
|
+
function normalizeKind2(value) {
|
|
13574
14579
|
if (value === "danger") return "error";
|
|
13575
14580
|
return ["success", "warning", "error"].includes(String(value)) ? (
|
|
13576
14581
|
/** @type {MessageKind} */
|
|
@@ -13581,6 +14586,50 @@ function normalizeTimeout(value) {
|
|
|
13581
14586
|
const timeout = Number(value);
|
|
13582
14587
|
return Number.isFinite(timeout) ? Math.max(0, timeout) : 4e3;
|
|
13583
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
|
+
}
|
|
13584
14633
|
function normalizeLimit(value) {
|
|
13585
14634
|
const limit = Number(value);
|
|
13586
14635
|
return Number.isInteger(limit) && limit > 0 ? limit : 5;
|
|
@@ -13616,7 +14665,7 @@ function snapshot2(element) {
|
|
|
13616
14665
|
}
|
|
13617
14666
|
function restore2(element, state) {
|
|
13618
14667
|
for (const attribute of Array.from(element.attributes)) element.removeAttribute(attribute.name);
|
|
13619
|
-
for (const [
|
|
14668
|
+
for (const [name2, value] of state.attributes) element.setAttribute(name2, value);
|
|
13620
14669
|
element.replaceChildren(...state.children);
|
|
13621
14670
|
}
|
|
13622
14671
|
|
|
@@ -13985,7 +15034,7 @@ var Calendar = class extends Component {
|
|
|
13985
15034
|
if (!this.el) this.el = root;
|
|
13986
15035
|
this._createdRoot = createdRoot;
|
|
13987
15036
|
this._original = this._createdRoot ? null : {
|
|
13988
|
-
attributes: Array.from(root.attributes).map(({ name, value }) => [
|
|
15037
|
+
attributes: Array.from(root.attributes).map(({ name: name2, value }) => [name2, value]),
|
|
13989
15038
|
children: Array.from(root.childNodes)
|
|
13990
15039
|
};
|
|
13991
15040
|
this._views = normalizeViews(this.options.views);
|
|
@@ -14195,7 +15244,7 @@ var Calendar = class extends Component {
|
|
|
14195
15244
|
super.destroy();
|
|
14196
15245
|
if (!this._createdRoot && original) {
|
|
14197
15246
|
for (const attribute of Array.from(this.el.attributes)) this.el.removeAttribute(attribute.name);
|
|
14198
|
-
for (const [
|
|
15247
|
+
for (const [name2, value] of original.attributes) this.el.setAttribute(name2, value);
|
|
14199
15248
|
this.el.replaceChildren(...original.children);
|
|
14200
15249
|
}
|
|
14201
15250
|
}
|
|
@@ -14237,8 +15286,8 @@ var Calendar = class extends Component {
|
|
|
14237
15286
|
});
|
|
14238
15287
|
this._range = range;
|
|
14239
15288
|
this.refs.heading.textContent = this._rangeTitle(range);
|
|
14240
|
-
for (const
|
|
14241
|
-
|
|
15289
|
+
for (const button2 of this.refs.views.querySelectorAll("[data-view]")) {
|
|
15290
|
+
button2.setAttribute("aria-pressed", String(button2.dataset.view === this._view));
|
|
14242
15291
|
}
|
|
14243
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);
|
|
14244
15293
|
this.refs.body.replaceChildren(content);
|
|
@@ -14562,7 +15611,7 @@ var Calendar = class extends Component {
|
|
|
14562
15611
|
},
|
|
14563
15612
|
style: event.color ? { "--zx-calendar-event-color": event.color } : null
|
|
14564
15613
|
});
|
|
14565
|
-
const
|
|
15614
|
+
const button2 = h("button", {
|
|
14566
15615
|
type: "button",
|
|
14567
15616
|
class: "zx-calendar__event-action",
|
|
14568
15617
|
dataset: { eventAction: "activate", eventId: key },
|
|
@@ -14570,15 +15619,15 @@ var Calendar = class extends Component {
|
|
|
14570
15619
|
disabled: this.options.disabled
|
|
14571
15620
|
});
|
|
14572
15621
|
const custom = typeof this.options.renderEvent === "function" ? this.options.renderEvent(cloneCalendarEvent(event)) : null;
|
|
14573
|
-
if (custom instanceof Node)
|
|
14574
|
-
else if (typeof custom === "string")
|
|
15622
|
+
if (custom instanceof Node) button2.append(custom);
|
|
15623
|
+
else if (typeof custom === "string") button2.append(document.createTextNode(custom));
|
|
14575
15624
|
else {
|
|
14576
15625
|
const time = h("span", { class: "zx-calendar__event-time" }, this._eventTime(event, context.day));
|
|
14577
15626
|
const title = h("span", { class: "zx-calendar__event-title" }, event.title);
|
|
14578
|
-
|
|
14579
|
-
if (event.location)
|
|
15627
|
+
button2.append(time, title);
|
|
15628
|
+
if (event.location) button2.append(h("span", { class: "zx-calendar__event-location" }, event.location));
|
|
14580
15629
|
}
|
|
14581
|
-
wrapper.append(
|
|
15630
|
+
wrapper.append(button2);
|
|
14582
15631
|
if (context.resizable && this._canResize(event)) {
|
|
14583
15632
|
wrapper.append(h("button", {
|
|
14584
15633
|
type: "button",
|
|
@@ -15405,7 +16454,7 @@ function cssEscape(value) {
|
|
|
15405
16454
|
var Fieldset = class extends Component {
|
|
15406
16455
|
static cssName = "fieldset";
|
|
15407
16456
|
/** @type {FieldsetOptions} */
|
|
15408
|
-
static defaults = { title: "", columns: 1, fields: {} };
|
|
16457
|
+
static defaults = { title: "", columns: 1, fields: {}, idPrefix: null };
|
|
15409
16458
|
/** @returns {HTMLElement} */
|
|
15410
16459
|
render() {
|
|
15411
16460
|
const root = (
|
|
@@ -15417,6 +16466,7 @@ var Fieldset = class extends Component {
|
|
|
15417
16466
|
this._origins = /* @__PURE__ */ new Map();
|
|
15418
16467
|
this._fieldIdAttributes = /* @__PURE__ */ new Map();
|
|
15419
16468
|
this._ownedNodes = [];
|
|
16469
|
+
this._idPrefix = this.options.idPrefix ? String(this.options.idPrefix) : uid("zx-fieldset");
|
|
15420
16470
|
this._columnAttribute = root.getAttribute("data-columns");
|
|
15421
16471
|
const columns = [1, 2, 3].includes(Number(this.options.columns)) ? Number(this.options.columns) : 1;
|
|
15422
16472
|
root.dataset.columns = String(columns);
|
|
@@ -15433,7 +16483,9 @@ var Fieldset = class extends Component {
|
|
|
15433
16483
|
return root;
|
|
15434
16484
|
}
|
|
15435
16485
|
/**
|
|
15436
|
-
* 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.
|
|
15437
16489
|
* @param {string} id Logical field identifier.
|
|
15438
16490
|
* @param {FieldOptions|Field|Element|Component} field Field source.
|
|
15439
16491
|
* @returns {Field}
|
|
@@ -15448,7 +16500,8 @@ var Fieldset = class extends Component {
|
|
|
15448
16500
|
} else if (isElement(field) || field instanceof Component) {
|
|
15449
16501
|
const source = field;
|
|
15450
16502
|
instance = new Field(null, {
|
|
15451
|
-
id: key,
|
|
16503
|
+
id: this._controlId(key),
|
|
16504
|
+
name: key,
|
|
15452
16505
|
type: "custom",
|
|
15453
16506
|
label: key,
|
|
15454
16507
|
value: readExternalValue(source),
|
|
@@ -15458,7 +16511,12 @@ var Fieldset = class extends Component {
|
|
|
15458
16511
|
owned = true;
|
|
15459
16512
|
} else {
|
|
15460
16513
|
const options = field && typeof field === "object" ? field : {};
|
|
15461
|
-
|
|
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
|
+
});
|
|
15462
16520
|
owned = true;
|
|
15463
16521
|
}
|
|
15464
16522
|
if (!owned) {
|
|
@@ -15588,6 +16646,14 @@ var Fieldset = class extends Component {
|
|
|
15588
16646
|
for (const field of this._fields.values()) field.clearHighlight();
|
|
15589
16647
|
return this;
|
|
15590
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
|
+
}
|
|
15591
16657
|
/** @param {Field} field @returns {void} */
|
|
15592
16658
|
_releaseField(field) {
|
|
15593
16659
|
const fieldId = this._fieldIdAttributes.get(field);
|
|
@@ -15620,7 +16686,7 @@ function externalAdapter(source) {
|
|
|
15620
16686
|
const el = isElement(source) ? source : source.toElement();
|
|
15621
16687
|
const parent = el.parentNode;
|
|
15622
16688
|
const next = el.nextSibling;
|
|
15623
|
-
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)]));
|
|
15624
16690
|
const originalDisabled = "disabled" in el ? el.disabled : void 0;
|
|
15625
16691
|
const originalValue = "value" in el ? el.value : void 0;
|
|
15626
16692
|
return {
|
|
@@ -15646,9 +16712,9 @@ function externalAdapter(source) {
|
|
|
15646
16712
|
else el.setAttribute("aria-disabled", String(disabled));
|
|
15647
16713
|
},
|
|
15648
16714
|
destroy: () => {
|
|
15649
|
-
for (const [
|
|
15650
|
-
if (value === null) el.removeAttribute(
|
|
15651
|
-
else el.setAttribute(
|
|
16715
|
+
for (const [name2, value] of attributes) {
|
|
16716
|
+
if (value === null) el.removeAttribute(name2);
|
|
16717
|
+
else el.setAttribute(name2, value);
|
|
15652
16718
|
}
|
|
15653
16719
|
if (originalDisabled !== void 0) el.disabled = originalDisabled;
|
|
15654
16720
|
if (originalValue !== void 0) el.value = originalValue;
|
|
@@ -15676,6 +16742,7 @@ var Form = class extends Component {
|
|
|
15676
16742
|
fieldsets: [],
|
|
15677
16743
|
actions: [],
|
|
15678
16744
|
novalidate: true,
|
|
16745
|
+
idPrefix: null,
|
|
15679
16746
|
msg: {
|
|
15680
16747
|
"form.required": "This field is required.",
|
|
15681
16748
|
"form.int": "Enter a whole number.",
|
|
@@ -15692,6 +16759,7 @@ var Form = class extends Component {
|
|
|
15692
16759
|
this._ownedFieldsets = /* @__PURE__ */ new Set();
|
|
15693
16760
|
this._origins = /* @__PURE__ */ new Map();
|
|
15694
16761
|
this._ownedNodes = [];
|
|
16762
|
+
this._idPrefix = this.options.idPrefix ? String(this.options.idPrefix) : uid("zx-form");
|
|
15695
16763
|
this._novalidateAttribute = root.getAttribute("novalidate");
|
|
15696
16764
|
root.toggleAttribute("novalidate", Boolean(this.options.novalidate));
|
|
15697
16765
|
this._body = h("div", { class: "zx-form__body" });
|
|
@@ -15713,13 +16781,14 @@ var Form = class extends Component {
|
|
|
15713
16781
|
return root;
|
|
15714
16782
|
}
|
|
15715
16783
|
/**
|
|
15716
|
-
* 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.
|
|
15717
16786
|
* @param {Fieldset|import('../fieldset/fieldset.js').FieldsetOptions} fieldset Fieldset source.
|
|
15718
16787
|
* @returns {Fieldset}
|
|
15719
16788
|
*/
|
|
15720
16789
|
addFieldset(fieldset) {
|
|
15721
16790
|
const owned = !(fieldset instanceof Fieldset);
|
|
15722
|
-
const instance = owned ? new Fieldset(null, fieldset ?? {}) : fieldset;
|
|
16791
|
+
const instance = owned ? new Fieldset(null, { ...fieldset ?? {}, idPrefix: fieldset?.idPrefix ?? this._idPrefix }) : fieldset;
|
|
15723
16792
|
if (this._fieldsets.includes(instance)) return instance;
|
|
15724
16793
|
if (owned) this._ownedFieldsets.add(instance);
|
|
15725
16794
|
else this._origins.set(instance, { parent: instance.el.parentNode, next: instance.el.nextSibling });
|
|
@@ -15877,9 +16946,9 @@ var Form = class extends Component {
|
|
|
15877
16946
|
}
|
|
15878
16947
|
/** @param {Event} event @returns {void} */
|
|
15879
16948
|
_handleAction(event) {
|
|
15880
|
-
const
|
|
15881
|
-
if (!
|
|
15882
|
-
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)];
|
|
15883
16952
|
const callback = action?.onClick ?? action?.onclick ?? action?.handler;
|
|
15884
16953
|
if (typeof callback === "function") callback(event, this);
|
|
15885
16954
|
}
|
|
@@ -15972,16 +17041,16 @@ function deriveLocale(client) {
|
|
|
15972
17041
|
return client.locale ?? client.language ?? client.config?.locale ?? client.metadata?.locale ?? null;
|
|
15973
17042
|
}
|
|
15974
17043
|
function operationFor(client, action, resource) {
|
|
15975
|
-
const
|
|
15976
|
-
if (!
|
|
15977
|
-
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) : [];
|
|
15978
17047
|
if (Array.isArray(resourceOperations) && resourceOperations.length) {
|
|
15979
17048
|
const exactResourceMatches = resourceOperations.filter((operation) => typeof operation === "string" && operation.toLowerCase().startsWith(action)).sort((left, right) => left.length - right.length);
|
|
15980
17049
|
if (exactResourceMatches.length) return exactResourceMatches[0];
|
|
15981
17050
|
}
|
|
15982
17051
|
const known = Array.isArray(resourceOperations) && resourceOperations.length ? resourceOperations : typeof client.schema?.operationIds === "function" ? client.schema.operationIds() : Object.keys(client.api);
|
|
15983
|
-
if (known.includes(
|
|
15984
|
-
const normalizedResource = normalizeResource(
|
|
17052
|
+
if (known.includes(name2) && name2.toLowerCase().startsWith(action)) return name2;
|
|
17053
|
+
const normalizedResource = normalizeResource(name2);
|
|
15985
17054
|
const singular = singularize(normalizedResource);
|
|
15986
17055
|
const matches = known.filter((operation) => {
|
|
15987
17056
|
if (typeof operation !== "string" || !operation.toLowerCase().startsWith(action)) return false;
|
|
@@ -15989,11 +17058,11 @@ function operationFor(client, action, resource) {
|
|
|
15989
17058
|
return suffix === normalizedResource || suffix === singular || singularize(suffix) === singular;
|
|
15990
17059
|
});
|
|
15991
17060
|
if (matches.length) return matches.sort((left, right) => left.length - right.length)[0];
|
|
15992
|
-
const candidates = action === "list" ? [`list${pascalCase(
|
|
17061
|
+
const candidates = action === "list" ? [`list${pascalCase(name2)}`] : [`${action}${pascalCase(singularizeName(name2))}`, `${action}${pascalCase(name2)}`];
|
|
15993
17062
|
const apiKeys = new Set(Object.keys(client.api));
|
|
15994
17063
|
const fallback = candidates.find((candidate) => apiKeys.has(candidate));
|
|
15995
17064
|
if (fallback) return fallback;
|
|
15996
|
-
throw new RangeError(`No ${action} operation found for ZeyOS resource "${
|
|
17065
|
+
throw new RangeError(`No ${action} operation found for ZeyOS resource "${name2}"`);
|
|
15997
17066
|
}
|
|
15998
17067
|
function isRecord(value) {
|
|
15999
17068
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -16129,31 +17198,31 @@ var moduleAliases = Object.freeze({
|
|
|
16129
17198
|
});
|
|
16130
17199
|
var glyphColors = Object.freeze({ light: "#ffffff", dark: "#141414" });
|
|
16131
17200
|
var overrides = /* @__PURE__ */ Object.create(null);
|
|
16132
|
-
function normalizeModuleName(
|
|
16133
|
-
const key = String(
|
|
17201
|
+
function normalizeModuleName(name2) {
|
|
17202
|
+
const key = String(name2 ?? "").trim().toLowerCase().replaceAll(/[._\s]+/g, "-");
|
|
16134
17203
|
if (!key) return "default";
|
|
16135
17204
|
if (Object.hasOwn(overrides, key) || Object.hasOwn(zeyosModules, key)) return key;
|
|
16136
17205
|
const alias = moduleAliases[key];
|
|
16137
17206
|
if (alias) return alias;
|
|
16138
17207
|
return "default";
|
|
16139
17208
|
}
|
|
16140
|
-
function moduleInfo(
|
|
16141
|
-
const key = normalizeModuleName(
|
|
17209
|
+
function moduleInfo(name2) {
|
|
17210
|
+
const key = normalizeModuleName(name2);
|
|
16142
17211
|
return overrides[key] ?? zeyosModules[key] ?? zeyosModules.default;
|
|
16143
17212
|
}
|
|
16144
|
-
function moduleColor(
|
|
16145
|
-
return moduleInfo(
|
|
17213
|
+
function moduleColor(name2) {
|
|
17214
|
+
return moduleInfo(name2).color;
|
|
16146
17215
|
}
|
|
16147
|
-
function moduleIconName(
|
|
16148
|
-
const info = moduleInfo(
|
|
17216
|
+
function moduleIconName(name2, { standard = false } = {}) {
|
|
17217
|
+
const info = moduleInfo(name2);
|
|
16149
17218
|
return standard ? info.fa : info.icon;
|
|
16150
17219
|
}
|
|
16151
17220
|
function moduleKeys() {
|
|
16152
17221
|
return [.../* @__PURE__ */ new Set([...Object.keys(zeyosModules), ...Object.keys(overrides)])].sort();
|
|
16153
17222
|
}
|
|
16154
17223
|
function registerModules(modules) {
|
|
16155
|
-
for (const [
|
|
16156
|
-
const key = String(
|
|
17224
|
+
for (const [name2, value] of Object.entries(modules)) {
|
|
17225
|
+
const key = String(name2).trim().toLowerCase().replaceAll(/[._\s]+/g, "-");
|
|
16157
17226
|
const patch = typeof value === "string" ? { color: value } : value;
|
|
16158
17227
|
const base = overrides[key] ?? zeyosModules[key] ?? zeyosModules.default;
|
|
16159
17228
|
overrides[key] = Object.freeze({
|
|
@@ -16190,12 +17259,12 @@ var ZEYOS_ICON_KIT = "https://kit.fontawesome.com/ae8320b210.js";
|
|
|
16190
17259
|
function useZeyosIcons(options = {}) {
|
|
16191
17260
|
return loadFontAwesome({ kit: ZEYOS_ICON_KIT, ...options });
|
|
16192
17261
|
}
|
|
16193
|
-
function moduleIcon(
|
|
17262
|
+
function moduleIcon(name2, options = {}) {
|
|
16194
17263
|
const { standard = false, ...rest } = options;
|
|
16195
|
-
const info = moduleInfo(
|
|
17264
|
+
const info = moduleInfo(name2);
|
|
16196
17265
|
return icon(standard ? `fa:${info.fa}` : `kit:${info.icon}`, rest);
|
|
16197
17266
|
}
|
|
16198
|
-
function moduleChip(
|
|
17267
|
+
function moduleChip(name2, options = {}) {
|
|
16199
17268
|
const {
|
|
16200
17269
|
size = 24,
|
|
16201
17270
|
iconSize = "52%",
|
|
@@ -16206,13 +17275,13 @@ function moduleChip(name, options = {}) {
|
|
|
16206
17275
|
badge = null,
|
|
16207
17276
|
selected = false
|
|
16208
17277
|
} = options;
|
|
16209
|
-
const key = normalizeModuleName(
|
|
16210
|
-
const info = moduleInfo(
|
|
17278
|
+
const key = normalizeModuleName(name2);
|
|
17279
|
+
const info = moduleInfo(name2);
|
|
16211
17280
|
const background = isCssColor(color) ? color : info.color;
|
|
16212
17281
|
const chip = appIcon({
|
|
16213
17282
|
// AppIcon owns glyph sizing. Keep the provider glyph at 1em so the percentage is not applied
|
|
16214
17283
|
// once to the wrapper and a second time to a Font Awesome <i>.
|
|
16215
|
-
icon: options.icon ?? moduleIcon(
|
|
17284
|
+
icon: options.icon ?? moduleIcon(name2, { size: "1em", standard }),
|
|
16216
17285
|
size,
|
|
16217
17286
|
iconSize,
|
|
16218
17287
|
color: background,
|
|
@@ -16230,8 +17299,8 @@ function moduleChip(name, options = {}) {
|
|
|
16230
17299
|
if (title) chip.title = info.label;
|
|
16231
17300
|
return chip;
|
|
16232
17301
|
}
|
|
16233
|
-
function zeyosAppIcon(
|
|
16234
|
-
return moduleChip(
|
|
17302
|
+
function zeyosAppIcon(name2, options = {}) {
|
|
17303
|
+
return moduleChip(name2, { shape: "circle", ...options });
|
|
16235
17304
|
}
|
|
16236
17305
|
|
|
16237
17306
|
// src/zeyos/launcher.js
|
|
@@ -16732,8 +17801,12 @@ function buildZeyosFormConfig(client, resource, opts = {}) {
|
|
|
16732
17801
|
const fieldMeta = resolveFields(client, resource, opts);
|
|
16733
17802
|
const fields = {};
|
|
16734
17803
|
const entityFields = [];
|
|
17804
|
+
const dateKinds = /* @__PURE__ */ new Map();
|
|
16735
17805
|
for (const meta of fieldMeta) {
|
|
16736
17806
|
const descriptor = fieldToZxField(meta);
|
|
17807
|
+
if (descriptor.type === "date" || descriptor.type === "datetime") {
|
|
17808
|
+
dateKinds.set(String(meta.id), descriptor.type);
|
|
17809
|
+
}
|
|
16737
17810
|
const referencedResource2 = descriptor.type === "zxselect" && typeof descriptor.props?.entity === "string" ? descriptor.props.entity : null;
|
|
16738
17811
|
if (referencedResource2) {
|
|
16739
17812
|
entityFields.push({ id: String(meta.id), resource: referencedResource2 });
|
|
@@ -16757,16 +17830,20 @@ function buildZeyosFormConfig(client, resource, opts = {}) {
|
|
|
16757
17830
|
fields
|
|
16758
17831
|
}]
|
|
16759
17832
|
},
|
|
16760
|
-
mapFromRecord: (record) => mapFromRecord(record, fieldMeta),
|
|
16761
|
-
mapToRecord: (values) => mapToRecord(values, fieldMeta)
|
|
17833
|
+
mapFromRecord: (record) => mapFromRecord(record, fieldMeta, dateKinds),
|
|
17834
|
+
mapToRecord: (values) => mapToRecord(values, fieldMeta, dateKinds)
|
|
16762
17835
|
};
|
|
16763
17836
|
}
|
|
16764
17837
|
function zeyosForm(client, resource, opts = {}) {
|
|
16765
17838
|
if (opts.onSaved != null && typeof opts.onSaved !== "function") {
|
|
16766
17839
|
throw new TypeError("zeyosForm onSaved must be a function");
|
|
16767
17840
|
}
|
|
17841
|
+
const notify = opts.notify !== false;
|
|
16768
17842
|
const config2 = buildZeyosFormConfig(client, resource, opts);
|
|
16769
|
-
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
|
+
});
|
|
16770
17847
|
const form = new Form(null, config2.formOptions);
|
|
16771
17848
|
let currentId = opts.value?.ID ?? opts.id ?? null;
|
|
16772
17849
|
let destroyed = false;
|
|
@@ -16796,6 +17873,7 @@ function zeyosForm(client, resource, opts = {}) {
|
|
|
16796
17873
|
if (destroyed) return Promise.reject(new Error("Cannot save a destroyed ZeyOS form"));
|
|
16797
17874
|
if (savePending) return savePending;
|
|
16798
17875
|
if (!form.submit()) return Promise.resolve(null);
|
|
17876
|
+
const host = notify ? overlayHost(toastScope()) : null;
|
|
16799
17877
|
savePending = (async () => {
|
|
16800
17878
|
let payload;
|
|
16801
17879
|
try {
|
|
@@ -16816,7 +17894,7 @@ function zeyosForm(client, resource, opts = {}) {
|
|
|
16816
17894
|
throw error;
|
|
16817
17895
|
}
|
|
16818
17896
|
}
|
|
16819
|
-
Message.success(`${recordLabel(record, resource)} saved successfully
|
|
17897
|
+
if (host) Message.success(`${recordLabel(record, resource)} saved successfully.`, { scope: host });
|
|
16820
17898
|
return record;
|
|
16821
17899
|
})().finally(() => {
|
|
16822
17900
|
savePending = null;
|
|
@@ -16837,25 +17915,39 @@ function zeyosForm(client, resource, opts = {}) {
|
|
|
16837
17915
|
}
|
|
16838
17916
|
};
|
|
16839
17917
|
}
|
|
16840
|
-
function mapFromRecord(record, meta) {
|
|
17918
|
+
function mapFromRecord(record, meta, dateKinds) {
|
|
16841
17919
|
const values = {};
|
|
16842
17920
|
for (const field of meta) {
|
|
16843
17921
|
const id = String(field.id);
|
|
16844
17922
|
const value = record[id];
|
|
16845
|
-
|
|
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(
|
|
16846
17931
|
/** @type {number|string} */
|
|
16847
17932
|
value
|
|
16848
|
-
)
|
|
17933
|
+
);
|
|
16849
17934
|
}
|
|
16850
17935
|
return values;
|
|
16851
17936
|
}
|
|
16852
|
-
function mapToRecord(values, meta) {
|
|
17937
|
+
function mapToRecord(values, meta, dateKinds) {
|
|
16853
17938
|
const record = {};
|
|
16854
17939
|
for (const field of meta) {
|
|
16855
17940
|
const id = String(field.id);
|
|
16856
17941
|
let value = values[id];
|
|
16857
|
-
|
|
16858
|
-
|
|
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(
|
|
16859
17951
|
/** @type {Date} */
|
|
16860
17952
|
value
|
|
16861
17953
|
);
|
|
@@ -16867,10 +17959,6 @@ function mapToRecord(values, meta) {
|
|
|
16867
17959
|
}
|
|
16868
17960
|
return record;
|
|
16869
17961
|
}
|
|
16870
|
-
function isDateField(meta) {
|
|
16871
|
-
const descriptor = fieldToZxField(meta);
|
|
16872
|
-
return descriptor.type === "date" || descriptor.type === "datetime";
|
|
16873
|
-
}
|
|
16874
17962
|
function hasEnum(meta) {
|
|
16875
17963
|
return meta.enums != null || meta.enum != null;
|
|
16876
17964
|
}
|
|
@@ -16900,10 +17988,34 @@ function recordLabel(record, resource) {
|
|
|
16900
17988
|
}
|
|
16901
17989
|
|
|
16902
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
|
+
];
|
|
16903
18013
|
function buildZeyosTableConfig(client, resource, opts = {}) {
|
|
16904
18014
|
const fieldMeta = resolveFields(client, resource, {
|
|
16905
18015
|
fields: opts.fields,
|
|
16906
|
-
labels: opts.labels
|
|
18016
|
+
labels: opts.labels,
|
|
18017
|
+
formats: opts.formats,
|
|
18018
|
+
timeZone: opts.timeZone
|
|
16907
18019
|
});
|
|
16908
18020
|
const projection = {};
|
|
16909
18021
|
const columns = fieldMeta.map((sourceMeta) => {
|
|
@@ -16927,11 +18039,16 @@ function buildZeyosTableConfig(client, resource, opts = {}) {
|
|
|
16927
18039
|
if (typeof rowId === "string" && !Object.prototype.hasOwnProperty.call(projection, rowId)) {
|
|
16928
18040
|
projection[rowId] = rowId;
|
|
16929
18041
|
}
|
|
18042
|
+
const passed = {};
|
|
18043
|
+
for (const key of TABLE_OPTION_KEYS) {
|
|
18044
|
+
if (opts[key] !== void 0) passed[key] = opts[key];
|
|
18045
|
+
}
|
|
16930
18046
|
return {
|
|
16931
18047
|
fieldMeta,
|
|
16932
18048
|
columns,
|
|
16933
18049
|
projection,
|
|
16934
18050
|
tableOptions: {
|
|
18051
|
+
...passed,
|
|
16935
18052
|
columns,
|
|
16936
18053
|
data: [],
|
|
16937
18054
|
rowId,
|
|
@@ -16939,7 +18056,7 @@ function buildZeyosTableConfig(client, resource, opts = {}) {
|
|
|
16939
18056
|
sortMode: "server",
|
|
16940
18057
|
selectable: opts.selectable ?? false,
|
|
16941
18058
|
height: opts.height ?? null,
|
|
16942
|
-
onrowclick:
|
|
18059
|
+
onrowclick: rowClickListener(opts)
|
|
16943
18060
|
}
|
|
16944
18061
|
};
|
|
16945
18062
|
}
|
|
@@ -17025,6 +18142,15 @@ function zeyosTable(client, resource, opts = {}) {
|
|
|
17025
18142
|
});
|
|
17026
18143
|
return binding;
|
|
17027
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
|
+
}
|
|
17028
18154
|
function referencedResourceFor(meta) {
|
|
17029
18155
|
for (const value of [meta.entity, meta.fk, meta.relation, meta.reference, meta.references]) {
|
|
17030
18156
|
if (typeof value === "string" && value) return value;
|
|
@@ -17090,8 +18216,8 @@ function zeyosAppointmentToEvent(record) {
|
|
|
17090
18216
|
const end = unixSecondsToDate(record.dateto ?? record.datefrom);
|
|
17091
18217
|
if (!(start instanceof Date) || !(end instanceof Date)) throw new TypeError("ZeyOS appointment requires datefrom and dateto");
|
|
17092
18218
|
const association = String(record.assoc_name ?? "").trim();
|
|
17093
|
-
const
|
|
17094
|
-
const title = record.entity && association ? `${association}: ${
|
|
18219
|
+
const name2 = String(record.name ?? "").trim() || "Untitled appointment";
|
|
18220
|
+
const title = record.entity && association ? `${association}: ${name2}` : name2;
|
|
17095
18221
|
const allDay = record.allDay != null ? Boolean(record.allDay) : isMidnight(start) && isMidnight(end) && calendarDayDifference(start, end) >= 1;
|
|
17096
18222
|
return {
|
|
17097
18223
|
id: String(record.occurrenceid ?? `${baseId}@${record.datefrom}`),
|
|
@@ -17160,8 +18286,8 @@ var FORBIDDEN_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
17160
18286
|
]);
|
|
17161
18287
|
var SavedViewDuplicateNameError = class extends Error {
|
|
17162
18288
|
/** @param {string} name Duplicate display name. */
|
|
17163
|
-
constructor(
|
|
17164
|
-
super(`A saved view named "${
|
|
18289
|
+
constructor(name2) {
|
|
18290
|
+
super(`A saved view named "${name2}" already exists`);
|
|
17165
18291
|
this.name = "SavedViewDuplicateNameError";
|
|
17166
18292
|
}
|
|
17167
18293
|
};
|
|
@@ -17252,15 +18378,15 @@ var SavedViewRegistry = class {
|
|
|
17252
18378
|
*/
|
|
17253
18379
|
async save(input, options = {}) {
|
|
17254
18380
|
return this._mutate(async (document2) => {
|
|
17255
|
-
const
|
|
18381
|
+
const name2 = normalizeName(input?.name);
|
|
17256
18382
|
const policy = normalizeDuplicatePolicy(options.onDuplicate ?? this.options.duplicateNames);
|
|
17257
18383
|
const requestedId = input?.id == null ? null : normalizeId(input.id);
|
|
17258
18384
|
const byId = requestedId ? document2.views.find((entry2) => entry2.id === requestedId) ?? null : null;
|
|
17259
|
-
const byName = document2.views.find((entry2) => nameKey(entry2.name) === nameKey(
|
|
18385
|
+
const byName = document2.views.find((entry2) => nameKey(entry2.name) === nameKey(name2)) ?? null;
|
|
17260
18386
|
if (byId && byName && byId !== byName && policy === "reject") {
|
|
17261
|
-
throw new SavedViewDuplicateNameError(
|
|
18387
|
+
throw new SavedViewDuplicateNameError(name2);
|
|
17262
18388
|
}
|
|
17263
|
-
if (!byId && byName && policy === "reject") throw new SavedViewDuplicateNameError(
|
|
18389
|
+
if (!byId && byName && policy === "reject") throw new SavedViewDuplicateNameError(name2);
|
|
17264
18390
|
const existing = byId ?? (policy === "replace" ? byName : null);
|
|
17265
18391
|
const replaced = policy === "replace" && byId && byName !== byId ? byName : null;
|
|
17266
18392
|
const now = this._now();
|
|
@@ -17270,8 +18396,8 @@ var SavedViewRegistry = class {
|
|
|
17270
18396
|
const filters = Object.prototype.hasOwnProperty.call(input ?? {}, "filters") ? normalizeFilters(input.filters) : existing ? cloneJsonObject(existing.filters, "Saved view filters") : {};
|
|
17271
18397
|
const search = Object.prototype.hasOwnProperty.call(input ?? {}, "search") ? normalizeSearch(input.search) : existing?.search ?? "";
|
|
17272
18398
|
const createdAt = existing?.createdAt ?? now;
|
|
17273
|
-
const id = existing?.id ?? requestedId ?? this._createId(document2, { name, type, createdAt });
|
|
17274
|
-
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 };
|
|
17275
18401
|
const views = document2.views.filter((candidate) => candidate !== existing && candidate !== replaced && candidate.id !== id);
|
|
17276
18402
|
views.push(entry);
|
|
17277
18403
|
document2.views = sortEntries(views);
|
|
@@ -17287,11 +18413,11 @@ var SavedViewRegistry = class {
|
|
|
17287
18413
|
* @param {{onDuplicate?:SavedViewDuplicatePolicy}} [options={}] Duplicate policy.
|
|
17288
18414
|
* @returns {Promise<SavedViewEntry|null>} Updated entry, or null when absent.
|
|
17289
18415
|
*/
|
|
17290
|
-
async rename(idOrName,
|
|
18416
|
+
async rename(idOrName, name2, options = {}) {
|
|
17291
18417
|
return this._mutate(async (document2) => {
|
|
17292
18418
|
const entry = resolveEntry(document2, idOrName);
|
|
17293
18419
|
if (!entry) return { changed: false, result: null };
|
|
17294
|
-
const nextName = normalizeName(
|
|
18420
|
+
const nextName = normalizeName(name2);
|
|
17295
18421
|
if (entry.name === nextName) return { changed: false, result: entry };
|
|
17296
18422
|
const duplicate = document2.views.find((candidate) => candidate !== entry && nameKey(candidate.name) === nameKey(nextName)) ?? null;
|
|
17297
18423
|
const policy = normalizeDuplicatePolicy(options.onDuplicate ?? this.options.duplicateNames);
|
|
@@ -17554,7 +18680,7 @@ function normalizePersistedEntry(value, index, scope2) {
|
|
|
17554
18680
|
/** @type {Record<string,unknown>} */
|
|
17555
18681
|
value
|
|
17556
18682
|
);
|
|
17557
|
-
const
|
|
18683
|
+
const name2 = normalizeName(entry.name);
|
|
17558
18684
|
const type = normalizeType2(entry.type);
|
|
17559
18685
|
const state = normalizeRecordViewState(entry.state ?? {});
|
|
17560
18686
|
const filters = normalizeFilters(entry.filters ?? {});
|
|
@@ -17562,8 +18688,8 @@ function normalizePersistedEntry(value, index, scope2) {
|
|
|
17562
18688
|
const createdAt = normalizeTimestamp(entry.createdAt);
|
|
17563
18689
|
const requestedUpdated = normalizeTimestamp(entry.updatedAt ?? createdAt);
|
|
17564
18690
|
const updatedAt = requestedUpdated < createdAt ? createdAt : requestedUpdated;
|
|
17565
|
-
const id = entry.id == null || String(entry.id).trim() === "" ? `legacy-${hashString(`${scopeKey(scope2)}\0${
|
|
17566
|
-
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 };
|
|
17567
18693
|
}
|
|
17568
18694
|
function deduplicateEntries(entries) {
|
|
17569
18695
|
const ranked = [...entries].sort((left, right) => compareText(right.updatedAt, left.updatedAt) || compareText(left.id, right.id));
|
|
@@ -17651,10 +18777,10 @@ function normalizeType2(value) {
|
|
|
17651
18777
|
}
|
|
17652
18778
|
function normalizeName(value) {
|
|
17653
18779
|
if (typeof value !== "string") throw new TypeError("Saved view name must be a string");
|
|
17654
|
-
const
|
|
17655
|
-
if (!
|
|
17656
|
-
if (
|
|
17657
|
-
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;
|
|
17658
18784
|
}
|
|
17659
18785
|
function nameKey(value) {
|
|
17660
18786
|
return value.normalize("NFKC").toLocaleLowerCase("en-US");
|
|
@@ -17823,6 +18949,8 @@ function buildZeyosViewConfig(client, resource, opts = {}) {
|
|
|
17823
18949
|
const table = buildZeyosTableConfig(client, resource, {
|
|
17824
18950
|
fields: requested,
|
|
17825
18951
|
labels: opts.labels,
|
|
18952
|
+
formats: opts.formats,
|
|
18953
|
+
timeZone: opts.timeZone,
|
|
17826
18954
|
rowId: opts.recordId ?? "ID",
|
|
17827
18955
|
sort: opts.sort ?? null
|
|
17828
18956
|
});
|
|
@@ -18155,10 +19283,10 @@ function presentationType(View) {
|
|
|
18155
19283
|
cssName
|
|
18156
19284
|
);
|
|
18157
19285
|
}
|
|
18158
|
-
const
|
|
18159
|
-
return ["table", "card", "kanban"].includes(
|
|
19286
|
+
const name2 = String(View.name ?? "").toLowerCase().replace(/view$/, "");
|
|
19287
|
+
return ["table", "card", "kanban"].includes(name2) ? (
|
|
18160
19288
|
/** @type {'table'|'card'|'kanban'} */
|
|
18161
|
-
|
|
19289
|
+
name2
|
|
18162
19290
|
) : null;
|
|
18163
19291
|
}
|
|
18164
19292
|
function normalizePresentationType(value) {
|
|
@@ -18251,7 +19379,7 @@ function findReservedDocument(response, recordName) {
|
|
|
18251
19379
|
if (!Array.isArray(response) || !Array.isArray(response[0]) || !Array.isArray(response[1])) {
|
|
18252
19380
|
return null;
|
|
18253
19381
|
}
|
|
18254
|
-
const index = response[0].findIndex((
|
|
19382
|
+
const index = response[0].findIndex((name2) => String(name2) === recordName);
|
|
18255
19383
|
return index < 0 ? null : response[1][index];
|
|
18256
19384
|
}
|
|
18257
19385
|
function normalizeNonEmpty(value, fallback, label) {
|
|
@@ -18296,6 +19424,7 @@ export {
|
|
|
18296
19424
|
buildZeyosLauncherConfig,
|
|
18297
19425
|
buildZeyosSelectConfig,
|
|
18298
19426
|
buildZeyosViewConfig,
|
|
19427
|
+
calendarDayToUnixSeconds,
|
|
18299
19428
|
calendarEventToZeyosPatch,
|
|
18300
19429
|
connect,
|
|
18301
19430
|
createLegacySavedViewTransport,
|
|
@@ -18323,6 +19452,7 @@ export {
|
|
|
18323
19452
|
registerModules,
|
|
18324
19453
|
resolveFields,
|
|
18325
19454
|
tableSortToQuery,
|
|
19455
|
+
unixSecondsToCalendarDay,
|
|
18326
19456
|
unixSecondsToDate,
|
|
18327
19457
|
useZeyosIcons,
|
|
18328
19458
|
zeyosActiveIdentifier,
|
|
@@ -18338,3 +19468,51 @@ export {
|
|
|
18338
19468
|
zeyosTable,
|
|
18339
19469
|
zeyosView
|
|
18340
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
|
+
*/
|