@zeyos/zx 3.0.0 → 4.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 +51 -0
- package/DESIGN-SYSTEM.md +28 -68
- package/README.md +16 -37
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +106 -32
- package/dist/types/components/card/card.d.ts +128 -0
- package/dist/types/components/chart/chart.d.ts +1 -0
- package/dist/types/components/launcher/launcher.d.ts +65 -6
- package/dist/types/components/select/select.d.ts +51 -0
- package/dist/types/components/table/table.d.ts +4 -3
- package/dist/types/core/dom.d.ts +8 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/{components/app-rail → internal}/app-rail.d.ts +34 -19
- package/dist/types/zeyos/icons.d.ts +5 -0
- package/dist/types/zeyos/index.d.ts +2 -1
- package/dist/types/zeyos/launcher.d.ts +147 -0
- package/dist/types/zeyos/select.d.ts +39 -0
- package/dist/zx-zeyos.esm.js +1324 -46
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +400 -12
- package/dist/zx.esm.js +1059 -189
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +1059 -189
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +258 -145
- package/docs/llms.md +93 -112
- package/docs/llms.txt +16 -15
- package/package.json +8 -17
- package/src/components/app-sidebar/app-sidebar.css +12 -0
- package/src/components/app-sidebar/app-sidebar.js +310 -110
- package/src/components/card/card.css +149 -0
- package/src/components/card/card.js +285 -0
- package/src/components/chart/chart.js +8 -3
- package/src/components/grid/grid.js +10 -3
- package/src/components/launcher/launcher.css +113 -3
- package/src/components/launcher/launcher.js +234 -26
- package/src/components/select/field-adapter.js +9 -4
- package/src/components/select/select.css +144 -10
- package/src/components/select/select.js +259 -27
- package/src/components/table/table.js +8 -7
- package/src/core/dom.js +20 -0
- package/src/index.js +2 -1
- package/src/{components/app-rail → internal}/app-rail.js +80 -30
- package/src/zeyos/icons.js +8 -3
- package/src/zeyos/index.js +7 -1
- package/src/zeyos/launcher.js +338 -0
- package/src/zeyos/modules.js +1 -0
- package/src/zeyos/select.js +115 -1
- package/styles/tokens/global.css +1 -1
- package/styles/tokens/modules.css +1 -0
- package/styles/zx.css +1 -0
- package/MIGRATION.md +0 -749
- package/dist/types/compat/base.d.ts +0 -156
- package/dist/types/compat/globals.d.ts +0 -20
- package/dist/types/compat/index.d.ts +0 -128
- package/dist/types/compat/map/basic.d.ts +0 -175
- package/dist/types/compat/map/data.d.ts +0 -103
- package/dist/types/compat/map/date-time.d.ts +0 -80
- package/dist/types/compat/map/factory.d.ts +0 -9
- package/dist/types/compat/map/form.d.ts +0 -98
- package/dist/types/compat/map/helpers.d.ts +0 -12
- package/dist/types/compat/map/http.d.ts +0 -36
- package/dist/types/compat/map/layout.d.ts +0 -106
- package/dist/types/compat/map/options.d.ts +0 -80
- package/dist/types/compat/map/select.d.ts +0 -95
- package/dist/types/compat/map/stubs.d.ts +0 -32
- package/dist/types/compat/map/utilities.d.ts +0 -37
- package/dist/types/compat-entry.d.ts +0 -5
- package/dist/zx-compat.esm.js +0 -17848
- package/dist/zx-compat.esm.min.js +0 -1
- package/dist/zx-compat.global.js +0 -29008
- package/dist/zx-compat.global.min.js +0 -3
- package/src/compat/base.js +0 -291
- package/src/compat/globals.js +0 -167
- package/src/compat/index.js +0 -84
- package/src/compat/map/basic.js +0 -464
- package/src/compat/map/data.js +0 -254
- package/src/compat/map/date-time.js +0 -177
- package/src/compat/map/factory.js +0 -45
- package/src/compat/map/form.js +0 -330
- package/src/compat/map/helpers.js +0 -46
- package/src/compat/map/http.js +0 -117
- package/src/compat/map/layout.js +0 -256
- package/src/compat/map/options.js +0 -267
- package/src/compat/map/select.js +0 -198
- package/src/compat/map/stubs.js +0 -26
- package/src/compat/map/utilities.js +0 -113
- package/src/compat-entry.js +0 -11
package/dist/zx.global.js
CHANGED
|
@@ -21,10 +21,10 @@ var zx = (() => {
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AccountMenu: () => AccountMenu,
|
|
24
|
-
AppRail: () => AppRail,
|
|
25
24
|
AppSidebar: () => AppSidebar,
|
|
26
25
|
Avatar: () => Avatar,
|
|
27
26
|
Breadcrumb: () => Breadcrumb,
|
|
27
|
+
Card: () => Card,
|
|
28
28
|
Chart: () => Chart,
|
|
29
29
|
ChartJsAdapter: () => ChartJsAdapter,
|
|
30
30
|
CheckButton: () => CheckButton,
|
|
@@ -468,6 +468,18 @@ var zx = (() => {
|
|
|
468
468
|
return element;
|
|
469
469
|
}
|
|
470
470
|
var __ = compactElement;
|
|
471
|
+
function safeHref(value) {
|
|
472
|
+
if (typeof value !== "string") return null;
|
|
473
|
+
const href = value.trim();
|
|
474
|
+
if (!href) return null;
|
|
475
|
+
try {
|
|
476
|
+
const protocol = new URL(href, globalThis.location?.href ?? "https://zx.invalid/").protocol;
|
|
477
|
+
if (["javascript:", "data:", "vbscript:"].includes(protocol.toLowerCase())) return null;
|
|
478
|
+
} catch {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
return href;
|
|
482
|
+
}
|
|
471
483
|
function applyCompactProperties(element, properties) {
|
|
472
484
|
for (const name in properties ?? {}) {
|
|
473
485
|
const value = properties[name];
|
|
@@ -6818,7 +6830,18 @@ var zx = (() => {
|
|
|
6818
6830
|
"priority.high",
|
|
6819
6831
|
"priority.highest"
|
|
6820
6832
|
];
|
|
6821
|
-
var PRIORITY_FALLBACKS = ["Lowest", "Low", "
|
|
6833
|
+
var PRIORITY_FALLBACKS = ["Lowest", "Low", "Medium", "High", "Highest"];
|
|
6834
|
+
var DEFAULT_STATUSES = Object.freeze([
|
|
6835
|
+
["backlog", "status.backlog", "Backlog", "dotted", "muted"],
|
|
6836
|
+
["todo", "status.todo", "Todo", "ring", "neutral"],
|
|
6837
|
+
["in-progress", "status.inProgress", "In Progress", "progress", "warning"],
|
|
6838
|
+
["in-review", "status.inReview", "In Review", "review", "info"],
|
|
6839
|
+
["ready", "status.ready", "Ready to Merge", "ready", "accent"],
|
|
6840
|
+
["waiting", "status.waiting", "Waiting for feedback", "waiting", "warning"],
|
|
6841
|
+
["done", "status.done", "Done", "done", "info"],
|
|
6842
|
+
["canceled", "status.canceled", "Canceled", "canceled", "muted"],
|
|
6843
|
+
["duplicate", "status.duplicate", "Duplicate", "duplicate", "muted"]
|
|
6844
|
+
]);
|
|
6822
6845
|
var Select = class _Select extends Component {
|
|
6823
6846
|
static cssName = "select";
|
|
6824
6847
|
/** @type {SelectOptions} */
|
|
@@ -6829,6 +6852,10 @@ var zx = (() => {
|
|
|
6829
6852
|
labelKey: "name",
|
|
6830
6853
|
renderItem: null,
|
|
6831
6854
|
renderValue: null,
|
|
6855
|
+
renderValueAdornment: null,
|
|
6856
|
+
renderNone: null,
|
|
6857
|
+
noneLabel: null,
|
|
6858
|
+
actions: [],
|
|
6832
6859
|
value: null,
|
|
6833
6860
|
disabled: false,
|
|
6834
6861
|
placeholder: "",
|
|
@@ -6846,6 +6873,7 @@ var zx = (() => {
|
|
|
6846
6873
|
this._visibleItems = [];
|
|
6847
6874
|
this._fixedItems = [];
|
|
6848
6875
|
this._visibleFixed = [];
|
|
6876
|
+
this._actions = [];
|
|
6849
6877
|
this._selected = null;
|
|
6850
6878
|
this._optionEntries = [];
|
|
6851
6879
|
this._activeIndex = -1;
|
|
@@ -6884,6 +6912,12 @@ var zx = (() => {
|
|
|
6884
6912
|
placeholder: String(this.options.placeholder ?? ""),
|
|
6885
6913
|
readOnly: !this.options.filter
|
|
6886
6914
|
});
|
|
6915
|
+
const valueAdornment = h("span", {
|
|
6916
|
+
ref: "valueAdornment",
|
|
6917
|
+
class: "zx-select__value-adornment",
|
|
6918
|
+
ariaHidden: "true",
|
|
6919
|
+
hidden: true
|
|
6920
|
+
});
|
|
6887
6921
|
const clear = h("button", {
|
|
6888
6922
|
ref: "clear",
|
|
6889
6923
|
class: "zx-icon-btn zx-select__clear",
|
|
@@ -6909,6 +6943,7 @@ var zx = (() => {
|
|
|
6909
6943
|
const control = h(
|
|
6910
6944
|
"div",
|
|
6911
6945
|
{ ref: "control", class: "zx-select__control" },
|
|
6946
|
+
valueAdornment,
|
|
6912
6947
|
input,
|
|
6913
6948
|
clear,
|
|
6914
6949
|
loading,
|
|
@@ -6931,9 +6966,10 @@ var zx = (() => {
|
|
|
6931
6966
|
this._visibleItems = this._items.slice();
|
|
6932
6967
|
this._fixedItems = Array.isArray(this.options.fixedItems) ? this.options.fixedItems.slice() : [];
|
|
6933
6968
|
this._visibleFixed = this._fixedItems.slice();
|
|
6969
|
+
this._actions = normalizeSelectActions(this.options.actions);
|
|
6934
6970
|
this._disabled = Boolean(this.options.disabled);
|
|
6935
6971
|
this._handleTypeahead = typeahead(
|
|
6936
|
-
() => this._optionEntries.filter((entry) => !entry.clear).map((entry) => entry.element),
|
|
6972
|
+
() => this._optionEntries.filter((entry) => !entry.clear && !entry.action).map((entry) => entry.element),
|
|
6937
6973
|
(_option, index) => {
|
|
6938
6974
|
if (!this._open) this.open();
|
|
6939
6975
|
this._setActive(this._itemEntryIndex(index));
|
|
@@ -7028,6 +7064,13 @@ var zx = (() => {
|
|
|
7028
7064
|
this._position?.update();
|
|
7029
7065
|
return this;
|
|
7030
7066
|
}
|
|
7067
|
+
/** Replaces command rows without changing the selected value. @param {SelectAction[]} actions @returns {this} */
|
|
7068
|
+
setActions(actions2) {
|
|
7069
|
+
this._actions = normalizeSelectActions(actions2);
|
|
7070
|
+
this._renderOptions();
|
|
7071
|
+
this._position?.update();
|
|
7072
|
+
return this;
|
|
7073
|
+
}
|
|
7031
7074
|
/**
|
|
7032
7075
|
* Restores the configured initial value.
|
|
7033
7076
|
* @param {{silent?: boolean}} [options={}] Reset behavior.
|
|
@@ -7112,26 +7155,51 @@ var zx = (() => {
|
|
|
7112
7155
|
value: null,
|
|
7113
7156
|
items: [],
|
|
7114
7157
|
renderItem(item) {
|
|
7115
|
-
return
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
class: "zx-select__priority-icon",
|
|
7120
|
-
dataset: { level: item.level },
|
|
7121
|
-
ariaHidden: "true"
|
|
7122
|
-
}),
|
|
7123
|
-
h("span", {}, String(item.name))
|
|
7124
|
-
);
|
|
7158
|
+
return priorityContent(item, true);
|
|
7159
|
+
},
|
|
7160
|
+
renderValueAdornment(item) {
|
|
7161
|
+
return priorityIndicator(item.level);
|
|
7125
7162
|
}
|
|
7126
7163
|
});
|
|
7127
|
-
select.setItems(PRIORITY_KEYS.map((key, level) =>
|
|
7128
|
-
|
|
7129
|
-
name
|
|
7130
|
-
level
|
|
7131
|
-
|
|
7164
|
+
select.setItems(PRIORITY_KEYS.map((key, level) => {
|
|
7165
|
+
let name = level === 2 ? select.msg("priority.medium") : key;
|
|
7166
|
+
if (name === "priority.medium") name = select._message(key, PRIORITY_FALLBACKS[level]);
|
|
7167
|
+
else if (level !== 2) name = select._message(key, PRIORITY_FALLBACKS[level]);
|
|
7168
|
+
return { ID: level, name, level };
|
|
7169
|
+
}));
|
|
7132
7170
|
select.set(requestedValue, { silent: true });
|
|
7133
7171
|
return select;
|
|
7134
7172
|
}
|
|
7173
|
+
/**
|
|
7174
|
+
* Creates a status picker with shape- and color-distinct workflow indicators.
|
|
7175
|
+
* @param {Element|string|null} target Component target.
|
|
7176
|
+
* @param {SelectOptions & {items?: Array<Record<string, any>>}} [options={}] Select overrides and status items.
|
|
7177
|
+
* @returns {Select}
|
|
7178
|
+
*/
|
|
7179
|
+
static status(target, options = {}) {
|
|
7180
|
+
const { items = null, value = null, ...rest } = options;
|
|
7181
|
+
const select = new _Select(target, {
|
|
7182
|
+
...rest,
|
|
7183
|
+
value: null,
|
|
7184
|
+
items: [],
|
|
7185
|
+
renderItem(item) {
|
|
7186
|
+
return statusContent(item);
|
|
7187
|
+
},
|
|
7188
|
+
renderValueAdornment(item) {
|
|
7189
|
+
return statusIndicator(item);
|
|
7190
|
+
}
|
|
7191
|
+
});
|
|
7192
|
+
const statuses = Array.isArray(items) ? items.map(normalizeStatusItem).filter(Boolean) : DEFAULT_STATUSES.map(([ID, key, fallback, indicator, tone], index) => ({
|
|
7193
|
+
ID,
|
|
7194
|
+
name: select._message(key, fallback),
|
|
7195
|
+
indicator,
|
|
7196
|
+
tone,
|
|
7197
|
+
shortcut: String(index + 1)
|
|
7198
|
+
}));
|
|
7199
|
+
select.setItems(statuses);
|
|
7200
|
+
select.set(value, { silent: true });
|
|
7201
|
+
return select;
|
|
7202
|
+
}
|
|
7135
7203
|
/**
|
|
7136
7204
|
* Creates the record-permission picker: the fixed Private and Public choices above the groups a
|
|
7137
7205
|
* record can be shared with. The value is the tri-state ZeyOS stores — `false` for private,
|
|
@@ -7144,12 +7212,21 @@ var zx = (() => {
|
|
|
7144
7212
|
* @returns {Select}
|
|
7145
7213
|
*/
|
|
7146
7214
|
static permission(target, options = {}) {
|
|
7147
|
-
const {
|
|
7215
|
+
const {
|
|
7216
|
+
groups = [],
|
|
7217
|
+
value = true,
|
|
7218
|
+
valueKey = "ID",
|
|
7219
|
+
labelKey = "name",
|
|
7220
|
+
filter = "local",
|
|
7221
|
+
...rest
|
|
7222
|
+
} = options;
|
|
7148
7223
|
const loader = typeof groups === "function" ? groups : null;
|
|
7149
7224
|
const shareable = loader ? [] : groups;
|
|
7150
7225
|
const choices = [{ ID: false, name: "Private" }, { ID: true, name: "Public" }];
|
|
7151
7226
|
const select = new _Select(target, {
|
|
7152
|
-
|
|
7227
|
+
// An async group loader is the data source and cannot be disconnected by an incidental
|
|
7228
|
+
// `filter` override. Array-backed groups still honor local/disabled filtering.
|
|
7229
|
+
filter: loader ?? filter,
|
|
7153
7230
|
...rest,
|
|
7154
7231
|
value: null,
|
|
7155
7232
|
items: shareable,
|
|
@@ -7185,6 +7262,18 @@ var zx = (() => {
|
|
|
7185
7262
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
7186
7263
|
_onKeydown(event) {
|
|
7187
7264
|
if (this._disabled) return;
|
|
7265
|
+
if (this._open && isPrintable(event)) {
|
|
7266
|
+
const shortcut = this._optionEntries.findIndex((entry) => !entry.clear && !entry.action && String(
|
|
7267
|
+
/** @type {Record<string, any>|null} */
|
|
7268
|
+
entry.item?.shortcut ?? ""
|
|
7269
|
+
) === event.key);
|
|
7270
|
+
if (shortcut >= 0) {
|
|
7271
|
+
event.preventDefault();
|
|
7272
|
+
this._setActive(shortcut);
|
|
7273
|
+
this._chooseEntry(this._optionEntries[shortcut]);
|
|
7274
|
+
return;
|
|
7275
|
+
}
|
|
7276
|
+
}
|
|
7188
7277
|
if (event.key === "ArrowDown") {
|
|
7189
7278
|
event.preventDefault();
|
|
7190
7279
|
if (!this._open) this.open();
|
|
@@ -7232,6 +7321,7 @@ var zx = (() => {
|
|
|
7232
7321
|
/** @type {HTMLInputElement} */
|
|
7233
7322
|
this.refs.input.value
|
|
7234
7323
|
);
|
|
7324
|
+
this._syncValueAdornment();
|
|
7235
7325
|
if (!this._open) this.open();
|
|
7236
7326
|
if (this.options.filter === "local") {
|
|
7237
7327
|
this._visibleFixed = this._matchFixed(query);
|
|
@@ -7255,6 +7345,22 @@ var zx = (() => {
|
|
|
7255
7345
|
/** @param {SelectOptionEntry|undefined} entry @returns {void} */
|
|
7256
7346
|
_chooseEntry(entry) {
|
|
7257
7347
|
if (!entry) return;
|
|
7348
|
+
if (entry.action) {
|
|
7349
|
+
const detail = {
|
|
7350
|
+
id: entry.action.id,
|
|
7351
|
+
action: entry.action,
|
|
7352
|
+
query: (
|
|
7353
|
+
/** @type {HTMLInputElement} */
|
|
7354
|
+
this.refs.input.value
|
|
7355
|
+
),
|
|
7356
|
+
select: this
|
|
7357
|
+
};
|
|
7358
|
+
const action = this.emit("action", detail);
|
|
7359
|
+
if (!action.defaultPrevented) entry.action.invoke?.(detail);
|
|
7360
|
+
this.close();
|
|
7361
|
+
this.focus();
|
|
7362
|
+
return;
|
|
7363
|
+
}
|
|
7258
7364
|
this.set(entry.clear ? null : entry.item);
|
|
7259
7365
|
this.close();
|
|
7260
7366
|
this.focus();
|
|
@@ -7288,7 +7394,7 @@ var zx = (() => {
|
|
|
7288
7394
|
this._optionEntries = [];
|
|
7289
7395
|
let lastGroup = /* @__PURE__ */ Symbol("initial-group");
|
|
7290
7396
|
if (this.options.clearable) {
|
|
7291
|
-
this._appendOption(null, true, this.options.
|
|
7397
|
+
this._appendOption(null, true, this.options.noneLabel ?? this._message("select.none", "No selection"));
|
|
7292
7398
|
}
|
|
7293
7399
|
for (const item of this._visibleFixed) this._appendOption(item, false);
|
|
7294
7400
|
if (this._visibleFixed.length > 0 && this._visibleItems.length > 0 && !this.options.groupKey) {
|
|
@@ -7307,7 +7413,23 @@ var zx = (() => {
|
|
|
7307
7413
|
}
|
|
7308
7414
|
this._appendOption(item, false);
|
|
7309
7415
|
}
|
|
7310
|
-
if (this.
|
|
7416
|
+
if (this._actions.length > 0) {
|
|
7417
|
+
if (this._visibleFixed.length > 0 || this._visibleItems.length > 0 || this.options.clearable) {
|
|
7418
|
+
list.append(h("div", { class: "zx-select__separator", role: "presentation" }));
|
|
7419
|
+
}
|
|
7420
|
+
let actionGroup = /* @__PURE__ */ Symbol("initial-action-group");
|
|
7421
|
+
for (const action of this._actions) {
|
|
7422
|
+
if (action.group && action.group !== actionGroup) {
|
|
7423
|
+
list.append(h("div", {
|
|
7424
|
+
class: "zx-select__group",
|
|
7425
|
+
role: "presentation"
|
|
7426
|
+
}, action.group));
|
|
7427
|
+
actionGroup = action.group;
|
|
7428
|
+
}
|
|
7429
|
+
this._appendAction(action);
|
|
7430
|
+
}
|
|
7431
|
+
}
|
|
7432
|
+
if (this._visibleItems.length === 0 && this._visibleFixed.length === 0 && this._actions.length === 0 && !this._loading) {
|
|
7311
7433
|
list.append(h("div", {
|
|
7312
7434
|
class: "zx-select__empty",
|
|
7313
7435
|
role: "status"
|
|
@@ -7319,7 +7441,7 @@ var zx = (() => {
|
|
|
7319
7441
|
_appendOption(item, clear, label) {
|
|
7320
7442
|
const selected = clear ? this._selected === null : this._selected !== null && Object.is(this._itemValue(item), this.value);
|
|
7321
7443
|
const index = this._optionEntries.length;
|
|
7322
|
-
const content = clear ? String(label ?? "") : this._renderItem(item);
|
|
7444
|
+
const content = clear && typeof this.options.renderNone === "function" ? normalizeRenderedContent(this.options.renderNone(String(label ?? ""))) : clear ? String(label ?? "") : this._renderItem(item);
|
|
7323
7445
|
const option = h("div", {
|
|
7324
7446
|
class: "zx-select__option",
|
|
7325
7447
|
id: uid("zx-select-option"),
|
|
@@ -7329,16 +7451,37 @@ var zx = (() => {
|
|
|
7329
7451
|
}, h("span", { class: "zx-select__option-content" }, content));
|
|
7330
7452
|
if (selected) option.append(icon("check", { size: 15 }));
|
|
7331
7453
|
this.refs.list.append(option);
|
|
7332
|
-
this._optionEntries.push({ item, clear, element: option });
|
|
7454
|
+
this._optionEntries.push({ item, clear, action: null, element: option });
|
|
7455
|
+
}
|
|
7456
|
+
/** @param {SelectAction} action @returns {void} */
|
|
7457
|
+
_appendAction(action) {
|
|
7458
|
+
const index = this._optionEntries.length;
|
|
7459
|
+
const visual = selectActionIcon(action.icon);
|
|
7460
|
+
const option = h("div", {
|
|
7461
|
+
class: "zx-select__option zx-select__action",
|
|
7462
|
+
id: uid("zx-select-option"),
|
|
7463
|
+
role: "option",
|
|
7464
|
+
ariaSelected: "false",
|
|
7465
|
+
dataset: { index, kind: "action" }
|
|
7466
|
+
}, h(
|
|
7467
|
+
"span",
|
|
7468
|
+
{ class: "zx-select__option-content zx-select__action-content" },
|
|
7469
|
+
visual ? h("span", { class: "zx-select__action-icon", ariaHidden: "true" }, visual) : null,
|
|
7470
|
+
h(
|
|
7471
|
+
"span",
|
|
7472
|
+
{ class: "zx-select__action-copy" },
|
|
7473
|
+
h("span", { class: "zx-select__action-label" }, action.label),
|
|
7474
|
+
action.description ? h("span", { class: "zx-select__action-description" }, action.description) : null
|
|
7475
|
+
)
|
|
7476
|
+
));
|
|
7477
|
+
this.refs.list.append(option);
|
|
7478
|
+
this._optionEntries.push({ item: null, clear: false, action, element: option });
|
|
7333
7479
|
}
|
|
7334
7480
|
/** @param {SelectItem|null} item @returns {Node|string} */
|
|
7335
7481
|
_renderItem(item) {
|
|
7336
7482
|
if (typeof this.options.renderItem === "function") {
|
|
7337
7483
|
const rendered = this.options.renderItem(item);
|
|
7338
|
-
return rendered
|
|
7339
|
-
/** @type {Node} */
|
|
7340
|
-
rendered
|
|
7341
|
-
) : String(rendered ?? "");
|
|
7484
|
+
return normalizeRenderedContent(rendered);
|
|
7342
7485
|
}
|
|
7343
7486
|
return this._itemLabel(item);
|
|
7344
7487
|
}
|
|
@@ -7409,9 +7552,29 @@ var zx = (() => {
|
|
|
7409
7552
|
this.refs.input
|
|
7410
7553
|
);
|
|
7411
7554
|
input.value = this._selected === null ? "" : typeof this.options.renderValue === "function" ? String(this.options.renderValue(this._selected) ?? "") : this._itemLabel(this._selected);
|
|
7555
|
+
this._syncValueAdornment();
|
|
7412
7556
|
this.refs.clear.hidden = !this.options.clearable || this._selected === null;
|
|
7413
7557
|
}
|
|
7414
7558
|
/** @returns {void} */
|
|
7559
|
+
_syncValueAdornment() {
|
|
7560
|
+
const host = this.refs.valueAdornment;
|
|
7561
|
+
if (!host) return;
|
|
7562
|
+
const selectedLabel = this._selected === null ? "" : typeof this.options.renderValue === "function" ? String(this.options.renderValue(this._selected) ?? "") : this._itemLabel(this._selected);
|
|
7563
|
+
const query = String(
|
|
7564
|
+
/** @type {HTMLInputElement} */
|
|
7565
|
+
this.refs.input?.value ?? ""
|
|
7566
|
+
);
|
|
7567
|
+
if (this._selected === null || typeof this.options.renderValueAdornment !== "function" || Boolean(this.options.filter && query !== selectedLabel)) {
|
|
7568
|
+
host.replaceChildren();
|
|
7569
|
+
host.hidden = true;
|
|
7570
|
+
return;
|
|
7571
|
+
}
|
|
7572
|
+
const rendered = this.options.renderValueAdornment(this._selected);
|
|
7573
|
+
const content = normalizeRenderedContent(rendered);
|
|
7574
|
+
host.replaceChildren(content instanceof Node ? content : document.createTextNode(content));
|
|
7575
|
+
host.hidden = rendered == null || typeof content === "string" && content === "";
|
|
7576
|
+
}
|
|
7577
|
+
/** @returns {void} */
|
|
7415
7578
|
_syncDisabled() {
|
|
7416
7579
|
const input = (
|
|
7417
7580
|
/** @type {HTMLInputElement} */
|
|
@@ -7488,6 +7651,82 @@ var zx = (() => {
|
|
|
7488
7651
|
return message === key ? fallback : message;
|
|
7489
7652
|
}
|
|
7490
7653
|
};
|
|
7654
|
+
function normalizeRenderedContent(rendered) {
|
|
7655
|
+
return rendered && typeof rendered === "object" && "nodeType" in rendered ? (
|
|
7656
|
+
/** @type {Node} */
|
|
7657
|
+
rendered
|
|
7658
|
+
) : String(rendered ?? "");
|
|
7659
|
+
}
|
|
7660
|
+
function normalizeSelectActions(actions2) {
|
|
7661
|
+
if (!Array.isArray(actions2)) return [];
|
|
7662
|
+
return actions2.filter((action) => action && typeof action === "object" && action.id != null && action.label != null).map((action) => ({
|
|
7663
|
+
...action,
|
|
7664
|
+
label: String(action.label),
|
|
7665
|
+
description: action.description == null ? void 0 : String(action.description),
|
|
7666
|
+
group: action.group == null ? void 0 : String(action.group)
|
|
7667
|
+
}));
|
|
7668
|
+
}
|
|
7669
|
+
function selectActionIcon(visual) {
|
|
7670
|
+
if (typeof visual === "string") return icon(visual);
|
|
7671
|
+
if (visual instanceof Node) return visual.cloneNode(true);
|
|
7672
|
+
return null;
|
|
7673
|
+
}
|
|
7674
|
+
function priorityContent(item, label) {
|
|
7675
|
+
return h(
|
|
7676
|
+
"span",
|
|
7677
|
+
{ class: "zx-select__priority" },
|
|
7678
|
+
priorityIndicator(item.level),
|
|
7679
|
+
label ? h("span", {}, String(item.name)) : null
|
|
7680
|
+
);
|
|
7681
|
+
}
|
|
7682
|
+
function priorityIndicator(level) {
|
|
7683
|
+
const normalized = Math.max(0, Math.min(4, Math.trunc(Number(level) || 0)));
|
|
7684
|
+
return h("span", {
|
|
7685
|
+
class: "zx-select__priority-icon",
|
|
7686
|
+
dataset: { level: normalized },
|
|
7687
|
+
ariaHidden: "true"
|
|
7688
|
+
}, Array.from({ length: 5 }, (_, index) => h("span", {
|
|
7689
|
+
dataset: { filled: String(index <= normalized) }
|
|
7690
|
+
})));
|
|
7691
|
+
}
|
|
7692
|
+
function normalizeStatusItem(input) {
|
|
7693
|
+
if (!input || typeof input !== "object" || input.ID == null || input.name == null) return null;
|
|
7694
|
+
const indicators = ["dotted", "ring", "progress", "review", "ready", "waiting", "done", "canceled", "duplicate"];
|
|
7695
|
+
const tones = ["muted", "neutral", "warning", "info", "accent", "success", "danger"];
|
|
7696
|
+
return {
|
|
7697
|
+
...input,
|
|
7698
|
+
name: String(input.name),
|
|
7699
|
+
indicator: indicators.includes(String(input.indicator)) ? String(input.indicator) : "ring",
|
|
7700
|
+
tone: tones.includes(String(input.tone)) ? String(input.tone) : "muted",
|
|
7701
|
+
description: input.description == null ? "" : String(input.description),
|
|
7702
|
+
shortcut: input.shortcut == null ? "" : String(input.shortcut)
|
|
7703
|
+
};
|
|
7704
|
+
}
|
|
7705
|
+
function statusContent(item) {
|
|
7706
|
+
return h(
|
|
7707
|
+
"span",
|
|
7708
|
+
{ class: "zx-select__status" },
|
|
7709
|
+
statusIndicator(item),
|
|
7710
|
+
h(
|
|
7711
|
+
"span",
|
|
7712
|
+
{ class: "zx-select__status-copy" },
|
|
7713
|
+
h("span", { class: "zx-select__status-label" }, String(item.name)),
|
|
7714
|
+
item.description ? h("span", { class: "zx-select__status-description" }, item.description) : null
|
|
7715
|
+
),
|
|
7716
|
+
item.shortcut ? h("kbd", { class: "zx-select__status-shortcut" }, item.shortcut) : null
|
|
7717
|
+
);
|
|
7718
|
+
}
|
|
7719
|
+
function statusIndicator(item) {
|
|
7720
|
+
const indicator = String(item.indicator ?? "ring");
|
|
7721
|
+
const marker = h("span", {
|
|
7722
|
+
class: "zx-select__status-indicator",
|
|
7723
|
+
dataset: { indicator, tone: String(item.tone ?? "muted") },
|
|
7724
|
+
ariaHidden: "true"
|
|
7725
|
+
});
|
|
7726
|
+
if (indicator === "done") marker.append(icon("check", { size: 8 }));
|
|
7727
|
+
if (indicator === "canceled") marker.append(icon("x", { size: 7 }));
|
|
7728
|
+
return marker;
|
|
7729
|
+
}
|
|
7491
7730
|
function readItem(item, reader) {
|
|
7492
7731
|
if (typeof reader === "function") return reader(item);
|
|
7493
7732
|
if (item === null || typeof item !== "object") return item;
|
|
@@ -7500,10 +7739,11 @@ var zx = (() => {
|
|
|
7500
7739
|
// src/components/select/field-adapter.js
|
|
7501
7740
|
function registerSelectFieldAdapter() {
|
|
7502
7741
|
Field.register("zxselect", (field, options) => {
|
|
7503
|
-
const
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7742
|
+
const props = options.props ?? {};
|
|
7743
|
+
const preset = props.preset;
|
|
7744
|
+
const selectOptions = { ...props, value: options.value };
|
|
7745
|
+
delete selectOptions.preset;
|
|
7746
|
+
const select = field.own(preset === "priority" ? Select.priority(null, selectOptions) : preset === "status" ? Select.status(null, selectOptions) : new Select(null, selectOptions));
|
|
7507
7747
|
field.listen(select.el, "change", (event) => event.stopImmediatePropagation());
|
|
7508
7748
|
select.on("change", (event) => field.emit("change", { value: event.detail.value }));
|
|
7509
7749
|
return {
|
|
@@ -11450,12 +11690,14 @@ var zx = (() => {
|
|
|
11450
11690
|
}
|
|
11451
11691
|
/** @returns {HTMLElement} Table root. */
|
|
11452
11692
|
render() {
|
|
11693
|
+
const created = this.el === null;
|
|
11453
11694
|
const root = (
|
|
11454
11695
|
/** @type {HTMLElement} */
|
|
11455
11696
|
this.el ?? h("div")
|
|
11456
11697
|
);
|
|
11457
11698
|
this.el = root;
|
|
11458
|
-
this.
|
|
11699
|
+
this._createdRoot = created;
|
|
11700
|
+
this._original = created ? null : snapshotTarget(root);
|
|
11459
11701
|
this._columns = Array.isArray(this.options.columns) ? this.options.columns.map((column) => ({ ...column })) : [];
|
|
11460
11702
|
this._data = Array.isArray(this.options.data) ? [...this.options.data] : [];
|
|
11461
11703
|
this._selected = /* @__PURE__ */ new Set();
|
|
@@ -11530,8 +11772,8 @@ var zx = (() => {
|
|
|
11530
11772
|
}
|
|
11531
11773
|
/**
|
|
11532
11774
|
* Toggles a loading state. While loading, the body is dimmed, an indeterminate progress bar is
|
|
11533
|
-
* shown, and `aria-busy` is set — a lightweight
|
|
11534
|
-
*
|
|
11775
|
+
* shown, and `aria-busy` is set — a lightweight enterprise-table busy and skeleton pattern.
|
|
11776
|
+
* Call `setLoading(false)` (or `setData`) when done.
|
|
11535
11777
|
* @param {boolean} [loading=true] Whether the table is loading.
|
|
11536
11778
|
* @returns {this}
|
|
11537
11779
|
*/
|
|
@@ -12080,9 +12322,8 @@ var zx = (() => {
|
|
|
12080
12322
|
this._teardownEdit();
|
|
12081
12323
|
this._width?.destroy();
|
|
12082
12324
|
this._width = null;
|
|
12083
|
-
if (this.
|
|
12084
|
-
|
|
12085
|
-
this.el.replaceChildren(...this._originalChildren);
|
|
12325
|
+
if (!this._restored && !this._createdRoot) {
|
|
12326
|
+
restoreTarget(this.el, this._original);
|
|
12086
12327
|
this._restored = true;
|
|
12087
12328
|
}
|
|
12088
12329
|
super.destroy();
|
|
@@ -15443,6 +15684,244 @@ var zx = (() => {
|
|
|
15443
15684
|
) : "start";
|
|
15444
15685
|
}
|
|
15445
15686
|
|
|
15687
|
+
// src/components/card/card.js
|
|
15688
|
+
var Card = class extends Component {
|
|
15689
|
+
static cssName = "card";
|
|
15690
|
+
/** @type {Readonly<CardOptions>} */
|
|
15691
|
+
static defaults = {
|
|
15692
|
+
title: "",
|
|
15693
|
+
media: null,
|
|
15694
|
+
content: null,
|
|
15695
|
+
actions: [],
|
|
15696
|
+
footer: null,
|
|
15697
|
+
link: null,
|
|
15698
|
+
variant: "outlined",
|
|
15699
|
+
orientation: "vertical",
|
|
15700
|
+
headingLevel: 3
|
|
15701
|
+
};
|
|
15702
|
+
/**
|
|
15703
|
+
* Creates or enhances one card.
|
|
15704
|
+
* @param {Element|string|null} [target=null] Existing card container, selector, or null.
|
|
15705
|
+
* @param {CardOptions} [options={}] Card options.
|
|
15706
|
+
*/
|
|
15707
|
+
constructor(target = null, options = {}) {
|
|
15708
|
+
super(target, options);
|
|
15709
|
+
}
|
|
15710
|
+
/** @returns {HTMLElement} */
|
|
15711
|
+
render() {
|
|
15712
|
+
const created = !this.el;
|
|
15713
|
+
const root = (
|
|
15714
|
+
/** @type {HTMLElement} */
|
|
15715
|
+
this.el ?? h("article")
|
|
15716
|
+
);
|
|
15717
|
+
this.el = root;
|
|
15718
|
+
this._createdRoot = created;
|
|
15719
|
+
this._original = created ? null : snapshotTarget(root);
|
|
15720
|
+
this._cleaned = false;
|
|
15721
|
+
this._title = "";
|
|
15722
|
+
this._link = null;
|
|
15723
|
+
this._actionAbort = null;
|
|
15724
|
+
this._linkAbort = null;
|
|
15725
|
+
const originalContent = created ? [] : Array.from(root.childNodes);
|
|
15726
|
+
try {
|
|
15727
|
+
const headingLevel = normalizeHeadingLevel(this.options.headingLevel);
|
|
15728
|
+
const headingId = uid("zx-card-heading");
|
|
15729
|
+
const heading = h(`h${headingLevel}`, {
|
|
15730
|
+
ref: "heading",
|
|
15731
|
+
class: "zx-card__heading",
|
|
15732
|
+
id: headingId
|
|
15733
|
+
});
|
|
15734
|
+
const media = h("div", { ref: "media", class: "zx-card__media", hidden: true });
|
|
15735
|
+
const actions2 = h("div", {
|
|
15736
|
+
ref: "actions",
|
|
15737
|
+
class: "zx-card__actions",
|
|
15738
|
+
role: "group",
|
|
15739
|
+
ariaLabel: "Card actions",
|
|
15740
|
+
hidden: true
|
|
15741
|
+
});
|
|
15742
|
+
const content = h("div", { ref: "content", class: "zx-card__content", hidden: true });
|
|
15743
|
+
const footer = h("footer", { ref: "footer", class: "zx-card__footer", hidden: true });
|
|
15744
|
+
const header = h("header", { ref: "header", class: "zx-card__header" }, heading, actions2);
|
|
15745
|
+
root.replaceChildren(h(
|
|
15746
|
+
"div",
|
|
15747
|
+
{ class: "zx-card__layout" },
|
|
15748
|
+
media,
|
|
15749
|
+
h("div", { class: "zx-card__inner" }, header, content, footer)
|
|
15750
|
+
));
|
|
15751
|
+
root.dataset.variant = normalizeVariant2(this.options.variant);
|
|
15752
|
+
root.dataset.orientation = normalizeOrientation(this.options.orientation);
|
|
15753
|
+
this.setTitle(this.options.title);
|
|
15754
|
+
this.setMedia(this.options.media);
|
|
15755
|
+
if (this.options.content !== null) this.setContent(this.options.content);
|
|
15756
|
+
else if (originalContent.length) {
|
|
15757
|
+
content.replaceChildren(...originalContent);
|
|
15758
|
+
content.hidden = false;
|
|
15759
|
+
}
|
|
15760
|
+
this.setActions(this.options.actions);
|
|
15761
|
+
this.setFooter(this.options.footer);
|
|
15762
|
+
this.setLink(this.options.link);
|
|
15763
|
+
return root;
|
|
15764
|
+
} catch (error) {
|
|
15765
|
+
this._actionAbort?.abort();
|
|
15766
|
+
this._linkAbort?.abort();
|
|
15767
|
+
if (!created) restoreTarget(root, this._original);
|
|
15768
|
+
throw error;
|
|
15769
|
+
}
|
|
15770
|
+
}
|
|
15771
|
+
/** Replaces the card title. @param {string} title Next title. @returns {this} */
|
|
15772
|
+
setTitle(title) {
|
|
15773
|
+
const next = String(title ?? "");
|
|
15774
|
+
if (this._link && !next.trim()) throw new TypeError("A linked Card requires a non-empty title");
|
|
15775
|
+
this._title = next;
|
|
15776
|
+
this._renderHeading();
|
|
15777
|
+
return this;
|
|
15778
|
+
}
|
|
15779
|
+
/** Replaces or removes the media region. @param {CardContent} content Media. @returns {this} */
|
|
15780
|
+
setMedia(content) {
|
|
15781
|
+
replaceCardContent(this.refs.media, content, "Card media");
|
|
15782
|
+
this.refs.media.hidden = content === null;
|
|
15783
|
+
return this;
|
|
15784
|
+
}
|
|
15785
|
+
/** Replaces or clears the main content. @param {CardContent} content Content. @returns {this} */
|
|
15786
|
+
setContent(content) {
|
|
15787
|
+
replaceCardContent(this.refs.content, content, "Card content");
|
|
15788
|
+
this.refs.content.hidden = content === null;
|
|
15789
|
+
return this;
|
|
15790
|
+
}
|
|
15791
|
+
/** Replaces the secondary action controls. @param {CardAction[]} actions Actions. @returns {this} */
|
|
15792
|
+
setActions(actions2) {
|
|
15793
|
+
if (!Array.isArray(actions2)) throw new TypeError("Card actions must be an array");
|
|
15794
|
+
const nextAbort = new AbortController();
|
|
15795
|
+
let controls;
|
|
15796
|
+
try {
|
|
15797
|
+
controls = actions2.map((action) => {
|
|
15798
|
+
if (isElement(action)) return action;
|
|
15799
|
+
if (!action || typeof action !== "object" || Array.isArray(action)) {
|
|
15800
|
+
throw new TypeError("Card actions must be Elements or button descriptors");
|
|
15801
|
+
}
|
|
15802
|
+
const descriptor = { ...action };
|
|
15803
|
+
const onclick = descriptor.onclick;
|
|
15804
|
+
delete descriptor.onclick;
|
|
15805
|
+
const control = button(descriptor);
|
|
15806
|
+
if (onclick !== void 0 && typeof onclick !== "function") {
|
|
15807
|
+
throw new TypeError("Card action onclick must be a function");
|
|
15808
|
+
}
|
|
15809
|
+
if (onclick) control.addEventListener("click", onclick, { signal: nextAbort.signal });
|
|
15810
|
+
return control;
|
|
15811
|
+
});
|
|
15812
|
+
} catch (error) {
|
|
15813
|
+
nextAbort.abort();
|
|
15814
|
+
throw error;
|
|
15815
|
+
}
|
|
15816
|
+
this._actionAbort?.abort();
|
|
15817
|
+
this._actionAbort = nextAbort;
|
|
15818
|
+
this.refs.actions.replaceChildren(...controls);
|
|
15819
|
+
this.refs.actions.hidden = controls.length === 0;
|
|
15820
|
+
this._syncHeader();
|
|
15821
|
+
return this;
|
|
15822
|
+
}
|
|
15823
|
+
/** Replaces or removes the footer. @param {CardContent} content Footer. @returns {this} */
|
|
15824
|
+
setFooter(content) {
|
|
15825
|
+
replaceCardContent(this.refs.footer, content, "Card footer");
|
|
15826
|
+
this.refs.footer.hidden = content === null;
|
|
15827
|
+
return this;
|
|
15828
|
+
}
|
|
15829
|
+
/** Sets or removes the title's native primary link. @param {CardLink} link Link. @returns {this} */
|
|
15830
|
+
setLink(link) {
|
|
15831
|
+
const next = normalizeCardLink(link);
|
|
15832
|
+
if (next && !this._title.trim()) throw new TypeError("A linked Card requires a non-empty title");
|
|
15833
|
+
this._link = next;
|
|
15834
|
+
this.el.dataset.linked = next ? "true" : "false";
|
|
15835
|
+
this._renderHeading();
|
|
15836
|
+
return this;
|
|
15837
|
+
}
|
|
15838
|
+
/** Restores an enhanced target exactly, or removes an owned card. @returns {void} */
|
|
15839
|
+
destroy() {
|
|
15840
|
+
if (this._cleaned) return;
|
|
15841
|
+
this._cleaned = true;
|
|
15842
|
+
this._actionAbort?.abort();
|
|
15843
|
+
this._linkAbort?.abort();
|
|
15844
|
+
super.destroy();
|
|
15845
|
+
if (!this._createdRoot) restoreTarget(this.el, this._original);
|
|
15846
|
+
}
|
|
15847
|
+
/** @returns {void} */
|
|
15848
|
+
_renderHeading() {
|
|
15849
|
+
const title = this._title;
|
|
15850
|
+
const nextAbort = new AbortController();
|
|
15851
|
+
const node = this._link ? h("a", {
|
|
15852
|
+
class: "zx-card__primary",
|
|
15853
|
+
href: this._link.href,
|
|
15854
|
+
target: this._link.target,
|
|
15855
|
+
rel: this._link.rel
|
|
15856
|
+
}, title) : h("span", { class: "zx-card__title" }, title);
|
|
15857
|
+
if (this._link?.onclick) node.addEventListener("click", this._link.onclick, { signal: nextAbort.signal });
|
|
15858
|
+
this._linkAbort?.abort();
|
|
15859
|
+
this._linkAbort = nextAbort;
|
|
15860
|
+
this.refs.heading.replaceChildren(node);
|
|
15861
|
+
this.refs.heading.hidden = title === "";
|
|
15862
|
+
if (title) this.el.setAttribute("aria-labelledby", this.refs.heading.id);
|
|
15863
|
+
else this.el.removeAttribute("aria-labelledby");
|
|
15864
|
+
this._syncHeader();
|
|
15865
|
+
}
|
|
15866
|
+
/** @returns {void} */
|
|
15867
|
+
_syncHeader() {
|
|
15868
|
+
if (!this.refs.header) return;
|
|
15869
|
+
this.refs.header.hidden = this._title === "" && this.refs.actions.childElementCount === 0;
|
|
15870
|
+
}
|
|
15871
|
+
};
|
|
15872
|
+
function replaceCardContent(host, content, label) {
|
|
15873
|
+
if (content === null) {
|
|
15874
|
+
host.replaceChildren();
|
|
15875
|
+
return;
|
|
15876
|
+
}
|
|
15877
|
+
if (typeof content === "string") {
|
|
15878
|
+
host.textContent = content;
|
|
15879
|
+
return;
|
|
15880
|
+
}
|
|
15881
|
+
const node = content instanceof Component ? content.toElement() : content;
|
|
15882
|
+
if (node instanceof Node) {
|
|
15883
|
+
host.replaceChildren(node);
|
|
15884
|
+
return;
|
|
15885
|
+
}
|
|
15886
|
+
throw new TypeError(`${label} must be a string, Node, Component, or null`);
|
|
15887
|
+
}
|
|
15888
|
+
function normalizeCardLink(value) {
|
|
15889
|
+
if (value === null) return null;
|
|
15890
|
+
const descriptor = typeof value === "string" ? { href: value } : value;
|
|
15891
|
+
if (!descriptor || typeof descriptor !== "object" || Array.isArray(descriptor)) {
|
|
15892
|
+
throw new TypeError("Card link must be a URL string, descriptor, or null");
|
|
15893
|
+
}
|
|
15894
|
+
const href = safeHref(descriptor.href);
|
|
15895
|
+
if (href === null) {
|
|
15896
|
+
throw new TypeError("Card link requires a safe non-empty href");
|
|
15897
|
+
}
|
|
15898
|
+
if (descriptor.onclick !== void 0 && typeof descriptor.onclick !== "function") {
|
|
15899
|
+
throw new TypeError("Card link onclick must be a function");
|
|
15900
|
+
}
|
|
15901
|
+
const target = descriptor.target == null ? void 0 : String(descriptor.target);
|
|
15902
|
+
let rel = descriptor.rel == null ? "" : String(descriptor.rel).trim();
|
|
15903
|
+
if (target === "_blank" && !/(^|\s)noopener(\s|$)/i.test(rel)) {
|
|
15904
|
+
rel = `${rel} noopener`.trim();
|
|
15905
|
+
}
|
|
15906
|
+
return { href, target, rel: rel || void 0, onclick: descriptor.onclick };
|
|
15907
|
+
}
|
|
15908
|
+
function normalizeVariant2(value) {
|
|
15909
|
+
return ["raised", "filled"].includes(String(value)) ? (
|
|
15910
|
+
/** @type {'raised'|'filled'} */
|
|
15911
|
+
value
|
|
15912
|
+
) : "outlined";
|
|
15913
|
+
}
|
|
15914
|
+
function normalizeOrientation(value) {
|
|
15915
|
+
return value === "horizontal" ? "horizontal" : "vertical";
|
|
15916
|
+
}
|
|
15917
|
+
function normalizeHeadingLevel(value) {
|
|
15918
|
+
const level = Math.trunc(Number(value));
|
|
15919
|
+
return (
|
|
15920
|
+
/** @type {1|2|3|4|5|6} */
|
|
15921
|
+
level >= 1 && level <= 6 ? level : 3
|
|
15922
|
+
);
|
|
15923
|
+
}
|
|
15924
|
+
|
|
15446
15925
|
// src/components/panel/panel.js
|
|
15447
15926
|
var Panel = class extends Component {
|
|
15448
15927
|
static cssName = "panel";
|
|
@@ -18786,9 +19265,12 @@ var zx = (() => {
|
|
|
18786
19265
|
maxResults: 100,
|
|
18787
19266
|
placeholder: "Search applications and records",
|
|
18788
19267
|
label: "Launcher",
|
|
19268
|
+
closeLabel: "Close launcher",
|
|
19269
|
+
resultsLabel: "Launcher results",
|
|
18789
19270
|
emptyText: "No results",
|
|
18790
19271
|
loadingText: "Searching\u2026",
|
|
18791
|
-
shortcut: "mod+k"
|
|
19272
|
+
shortcut: "mod+k",
|
|
19273
|
+
hints: { move: "Move", open: "Open", close: "Close" }
|
|
18792
19274
|
};
|
|
18793
19275
|
/**
|
|
18794
19276
|
* Creates an owned launcher dialog or enhances an existing `<dialog>` target.
|
|
@@ -18817,6 +19299,7 @@ var zx = (() => {
|
|
|
18817
19299
|
this._sources = normalizeSources(this.options.sources);
|
|
18818
19300
|
this._sourceItems = /* @__PURE__ */ new Map();
|
|
18819
19301
|
this._query = String(this.options.query ?? "");
|
|
19302
|
+
this._renderedQuery = null;
|
|
18820
19303
|
this._results = [];
|
|
18821
19304
|
this._active = -1;
|
|
18822
19305
|
this._request = null;
|
|
@@ -18843,7 +19326,7 @@ var zx = (() => {
|
|
|
18843
19326
|
ref: "close",
|
|
18844
19327
|
class: "zx-icon-btn zx-launcher__close",
|
|
18845
19328
|
type: "button",
|
|
18846
|
-
ariaLabel:
|
|
19329
|
+
ariaLabel: this.options.closeLabel
|
|
18847
19330
|
}, icon("x"));
|
|
18848
19331
|
const status = h("div", {
|
|
18849
19332
|
ref: "status",
|
|
@@ -18856,16 +19339,25 @@ var zx = (() => {
|
|
|
18856
19339
|
class: "zx-launcher__results",
|
|
18857
19340
|
id: listId,
|
|
18858
19341
|
role: "listbox",
|
|
18859
|
-
ariaLabel:
|
|
19342
|
+
ariaLabel: this.options.resultsLabel
|
|
18860
19343
|
});
|
|
19344
|
+
const shortcut = this.options.shortcut === "mod+k" ? h("kbd", {
|
|
19345
|
+
class: "zx-launcher__shortcut",
|
|
19346
|
+
ariaHidden: "true"
|
|
19347
|
+
}, launcherShortcutLabel()) : null;
|
|
19348
|
+
const footer = launcherHints(this.options.hints);
|
|
18861
19349
|
dialog.setAttribute("aria-label", String(this.options.label));
|
|
18862
19350
|
dialog.replaceChildren(
|
|
18863
19351
|
h(
|
|
18864
19352
|
"div",
|
|
18865
19353
|
{ class: "zx-launcher__surface" },
|
|
18866
|
-
h("div", {
|
|
19354
|
+
h("div", {
|
|
19355
|
+
class: "zx-launcher__search",
|
|
19356
|
+
dataset: { shortcut: shortcut ? "true" : "false" }
|
|
19357
|
+
}, icon("search"), input, shortcut, close),
|
|
18867
19358
|
status,
|
|
18868
|
-
results
|
|
19359
|
+
results,
|
|
19360
|
+
footer
|
|
18869
19361
|
)
|
|
18870
19362
|
);
|
|
18871
19363
|
dialog.dataset.state = "closed";
|
|
@@ -18889,6 +19381,17 @@ var zx = (() => {
|
|
|
18889
19381
|
if (!option || !results.contains(option)) return;
|
|
18890
19382
|
this._activate(Number(option.getAttribute("data-launcher-index")), event);
|
|
18891
19383
|
});
|
|
19384
|
+
this.listen(results, "pointermove", (event) => {
|
|
19385
|
+
const option = (
|
|
19386
|
+
/** @type {Element|null} */
|
|
19387
|
+
event.target?.closest?.("[data-launcher-index]")
|
|
19388
|
+
);
|
|
19389
|
+
if (!option || !results.contains(option)) return;
|
|
19390
|
+
const index = Number(option.getAttribute("data-launcher-index"));
|
|
19391
|
+
if (!Number.isInteger(index) || this._results[index]?.disabled || index === this._active) return;
|
|
19392
|
+
this._active = index;
|
|
19393
|
+
this._syncActive();
|
|
19394
|
+
});
|
|
18892
19395
|
this.listen(dialog, "cancel", (event) => {
|
|
18893
19396
|
event.preventDefault();
|
|
18894
19397
|
this.close();
|
|
@@ -18958,6 +19461,13 @@ var zx = (() => {
|
|
|
18958
19461
|
this._renderResults();
|
|
18959
19462
|
return this;
|
|
18960
19463
|
}
|
|
19464
|
+
/** Marks one local item as the current destination. @param {string|number|null} id Item id. @returns {this} */
|
|
19465
|
+
setCurrent(id) {
|
|
19466
|
+
const key = id == null ? null : String(id);
|
|
19467
|
+
this._items = this._items.map((item) => ({ ...item, current: key !== null && String(item.id) === key }));
|
|
19468
|
+
this._renderResults();
|
|
19469
|
+
return this;
|
|
19470
|
+
}
|
|
18961
19471
|
/** Replaces asynchronous sources and aborts work from the old set. @param {LauncherSource[]} sources @returns {this} */
|
|
18962
19472
|
setSources(sources) {
|
|
18963
19473
|
this._abortRequest();
|
|
@@ -18993,7 +19503,7 @@ var zx = (() => {
|
|
|
18993
19503
|
async _loadSources() {
|
|
18994
19504
|
this._queryTimer = null;
|
|
18995
19505
|
const query = this._query.trim();
|
|
18996
|
-
const sources = this._sources.filter((source) => query.length >= Math.max(Number(this.options.minQuery) || 0, Number(source.minQuery) || 0));
|
|
19506
|
+
const sources = this._sources.filter((source) => visibleForQuery(source.when, query) && query.length >= Math.max(Number(this.options.minQuery) || 0, Number(source.minQuery) || 0));
|
|
18997
19507
|
if (sources.length === 0) return;
|
|
18998
19508
|
const request = new AbortController();
|
|
18999
19509
|
const sequence = ++this._requestSequence;
|
|
@@ -19003,10 +19513,12 @@ var zx = (() => {
|
|
|
19003
19513
|
try {
|
|
19004
19514
|
const loaded = await source.load(query, { signal: request.signal });
|
|
19005
19515
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
19006
|
-
this._sourceItems.set(source.id, normalizeItems2(loaded).map((item) => ({
|
|
19516
|
+
this._sourceItems.set(source.id, normalizeItems2(loaded).map((item, itemOrder) => ({
|
|
19007
19517
|
...item,
|
|
19008
19518
|
_source: source.id,
|
|
19009
|
-
|
|
19519
|
+
_sourceOrder: source.order === "source",
|
|
19520
|
+
group: item.group ?? source.label ?? "",
|
|
19521
|
+
itemOrder: item.itemOrder ?? (source.order === "source" ? itemOrder : void 0)
|
|
19010
19522
|
})));
|
|
19011
19523
|
this._renderResults();
|
|
19012
19524
|
} catch (error) {
|
|
@@ -19035,23 +19547,36 @@ var zx = (() => {
|
|
|
19035
19547
|
}
|
|
19036
19548
|
/** @returns {void} */
|
|
19037
19549
|
_renderResults() {
|
|
19038
|
-
const
|
|
19550
|
+
const queryKey = this._query;
|
|
19551
|
+
const activeId = this._renderedQuery === queryKey && this._active >= 0 && this._results[this._active] ? String(this._results[this._active].id) : null;
|
|
19552
|
+
const query = this._query.trim();
|
|
19553
|
+
const local = this._items.filter((item) => visibleForQuery(item.when, query));
|
|
19554
|
+
const rankedLocal = rankLauncherItems(local, query, this.options.maxResults);
|
|
19555
|
+
const remote = this._sources.flatMap((source) => {
|
|
19556
|
+
const loaded = this._sourceItems.get(String(source.id)) ?? [];
|
|
19557
|
+
return source.order === "source" ? loaded.filter((item) => visibleForQuery(item.when, query)) : rankLauncherItems(
|
|
19558
|
+
loaded.filter((item) => visibleForQuery(item.when, query)),
|
|
19559
|
+
query,
|
|
19560
|
+
this.options.maxResults
|
|
19561
|
+
);
|
|
19562
|
+
});
|
|
19039
19563
|
const seen = /* @__PURE__ */ new Set();
|
|
19040
|
-
const combined = [...
|
|
19564
|
+
const combined = [...rankedLocal.map((item) => ({ ...item, _source: null })), ...remote].filter((item) => {
|
|
19041
19565
|
const key = String(item.id);
|
|
19042
19566
|
if (seen.has(key)) return false;
|
|
19043
19567
|
seen.add(key);
|
|
19044
19568
|
return true;
|
|
19045
|
-
});
|
|
19046
|
-
const ranked = rankLauncherItems(combined, this._query, this.options.maxResults);
|
|
19569
|
+
}).slice(0, Math.max(0, Number(this.options.maxResults) || 0));
|
|
19047
19570
|
const groups = /* @__PURE__ */ new Map();
|
|
19048
|
-
for (const item of
|
|
19571
|
+
for (const item of combined) {
|
|
19049
19572
|
const group = String(item.group ?? "");
|
|
19050
19573
|
if (!groups.has(group)) groups.set(group, []);
|
|
19051
19574
|
groups.get(group).push(item);
|
|
19052
19575
|
}
|
|
19053
19576
|
this._results = [...groups.values()].flat();
|
|
19054
|
-
this.
|
|
19577
|
+
this._renderedQuery = queryKey;
|
|
19578
|
+
const preserved = activeId === null ? -1 : this._results.findIndex((item) => !item.disabled && String(item.id) === activeId);
|
|
19579
|
+
this._active = preserved >= 0 ? preserved : this._results.findIndex((item) => !item.disabled);
|
|
19055
19580
|
const nodes = [];
|
|
19056
19581
|
let index = 0;
|
|
19057
19582
|
for (const [group, items] of groups) {
|
|
@@ -19059,7 +19584,8 @@ var zx = (() => {
|
|
|
19059
19584
|
if (group) nodes.push(h("div", {
|
|
19060
19585
|
class: "zx-launcher__group",
|
|
19061
19586
|
role: "group",
|
|
19062
|
-
ariaLabel: group
|
|
19587
|
+
ariaLabel: group,
|
|
19588
|
+
dataset: { layout: items.every((item) => item.kind === "application") ? "grid" : "list" }
|
|
19063
19589
|
}, h("div", { class: "zx-launcher__group-label", ariaHidden: "true" }, group), options));
|
|
19064
19590
|
else nodes.push(...options);
|
|
19065
19591
|
}
|
|
@@ -19069,9 +19595,14 @@ var zx = (() => {
|
|
|
19069
19595
|
}
|
|
19070
19596
|
/** @param {RankedLauncherItem} item @param {number} index @returns {HTMLElement} */
|
|
19071
19597
|
_option(item, index) {
|
|
19072
|
-
const
|
|
19598
|
+
const href = safeHref(item.href);
|
|
19599
|
+
const tag = href ? "a" : "button";
|
|
19073
19600
|
const children = [];
|
|
19074
|
-
|
|
19601
|
+
const visual = launcherItemIcon(item);
|
|
19602
|
+
if (visual) children.push(h("span", {
|
|
19603
|
+
class: "zx-launcher__icon",
|
|
19604
|
+
ariaHidden: "true"
|
|
19605
|
+
}, visual));
|
|
19075
19606
|
children.push(h(
|
|
19076
19607
|
"span",
|
|
19077
19608
|
{ class: "zx-launcher__copy" },
|
|
@@ -19084,14 +19615,20 @@ var zx = (() => {
|
|
|
19084
19615
|
h(tag, {
|
|
19085
19616
|
class: "zx-launcher__option",
|
|
19086
19617
|
type: tag === "button" ? "button" : null,
|
|
19087
|
-
href
|
|
19618
|
+
href,
|
|
19088
19619
|
target: item.target ?? null,
|
|
19620
|
+
rel: tag === "a" ? "noopener" : null,
|
|
19089
19621
|
role: "option",
|
|
19090
19622
|
id: uid("zx-launcher-option"),
|
|
19091
19623
|
tabIndex: -1,
|
|
19092
19624
|
ariaSelected: "false",
|
|
19093
19625
|
ariaDisabled: item.disabled ? "true" : null,
|
|
19094
|
-
|
|
19626
|
+
ariaCurrent: item.current ? "page" : null,
|
|
19627
|
+
dataset: {
|
|
19628
|
+
launcherIndex: index,
|
|
19629
|
+
pinned: item.pinned !== void 0 && item.pinned !== false ? "true" : null,
|
|
19630
|
+
kind: normalizeLauncherKind(item.kind)
|
|
19631
|
+
}
|
|
19095
19632
|
}, children)
|
|
19096
19633
|
);
|
|
19097
19634
|
}
|
|
@@ -19128,6 +19665,17 @@ var zx = (() => {
|
|
|
19128
19665
|
}
|
|
19129
19666
|
const enabled = this._results.map((item, index) => item.disabled ? -1 : index).filter((index) => index >= 0);
|
|
19130
19667
|
if (enabled.length === 0) return;
|
|
19668
|
+
if (/^Arrow(?:Left|Right|Up|Down)$/.test(event.key)) {
|
|
19669
|
+
const next = this._spatialIndex(event.key, enabled);
|
|
19670
|
+
if (next !== null) {
|
|
19671
|
+
event.preventDefault();
|
|
19672
|
+
this._active = next;
|
|
19673
|
+
this._syncActive();
|
|
19674
|
+
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
19675
|
+
return;
|
|
19676
|
+
}
|
|
19677
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") return;
|
|
19678
|
+
}
|
|
19131
19679
|
let position2 = enabled.indexOf(this._active);
|
|
19132
19680
|
if (event.key === "Home" || event.key === "PageUp") position2 = 0;
|
|
19133
19681
|
else if (event.key === "End" || event.key === "PageDown") position2 = enabled.length - 1;
|
|
@@ -19139,6 +19687,15 @@ var zx = (() => {
|
|
|
19139
19687
|
this._syncActive();
|
|
19140
19688
|
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest" });
|
|
19141
19689
|
}
|
|
19690
|
+
/** @param {string} direction @param {number[]} enabled @returns {number|null} */
|
|
19691
|
+
_spatialIndex(direction, enabled) {
|
|
19692
|
+
const current = this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`);
|
|
19693
|
+
if (!(current instanceof HTMLElement)) return null;
|
|
19694
|
+
if ((direction === "ArrowLeft" || direction === "ArrowRight") && this._results[this._active]?.kind !== "application") return null;
|
|
19695
|
+
const candidates = [...this.refs.results.querySelectorAll("[data-launcher-index]")].filter((option) => enabled.includes(Number(option.getAttribute("data-launcher-index"))) && (direction !== "ArrowLeft" && direction !== "ArrowRight" || option.getAttribute("data-kind") === "application"));
|
|
19696
|
+
const next = findSpatialLauncherOption(candidates, current, direction);
|
|
19697
|
+
return next ? Number(next.getAttribute("data-launcher-index")) : null;
|
|
19698
|
+
}
|
|
19142
19699
|
/** @param {number} index @param {Event} event @returns {void} */
|
|
19143
19700
|
_activate(index, event) {
|
|
19144
19701
|
const item = this._results[index];
|
|
@@ -19164,25 +19721,103 @@ var zx = (() => {
|
|
|
19164
19721
|
}
|
|
19165
19722
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
19166
19723
|
_onDocumentKeydown(event) {
|
|
19167
|
-
if (this.options.shortcut !== "mod+k" || event.isComposing || event.key.toLowerCase() !== "k" ||
|
|
19724
|
+
if (this.options.shortcut !== "mod+k" || event.isComposing || event.key.toLowerCase() !== "k" || Number(event.metaKey) + Number(event.ctrlKey) !== 1 || event.altKey || event.shiftKey) return;
|
|
19168
19725
|
const active = document.activeElement;
|
|
19169
|
-
if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable) return;
|
|
19726
|
+
if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLSelectElement || active instanceof HTMLElement && active.isContentEditable) return;
|
|
19170
19727
|
const modal = document.querySelector("dialog:modal");
|
|
19171
19728
|
if (modal && modal !== this.el) return;
|
|
19172
19729
|
event.preventDefault();
|
|
19173
19730
|
this.open();
|
|
19174
19731
|
}
|
|
19175
19732
|
};
|
|
19733
|
+
function launcherShortcutLabel() {
|
|
19734
|
+
const platform = String(
|
|
19735
|
+
/** @type {any} */
|
|
19736
|
+
navigator.userAgentData?.platform ?? navigator.platform ?? ""
|
|
19737
|
+
);
|
|
19738
|
+
return /mac|iphone|ipad/i.test(platform) ? "\u2318 K" : "Ctrl K";
|
|
19739
|
+
}
|
|
19740
|
+
function launcherHints(hints) {
|
|
19741
|
+
if (hints === false) return null;
|
|
19742
|
+
const labels = hints && typeof hints === "object" ? hints : {};
|
|
19743
|
+
return h(
|
|
19744
|
+
"footer",
|
|
19745
|
+
{ class: "zx-launcher__hints", ariaHidden: "true" },
|
|
19746
|
+
h("span", {}, h("kbd", {}, "\u2191\u2193\u2190\u2192"), labels.move ?? "Move"),
|
|
19747
|
+
h("span", {}, h("kbd", {}, "\u21B5"), labels.open ?? "Open"),
|
|
19748
|
+
h("span", {}, h("kbd", {}, "Esc"), labels.close ?? "Close")
|
|
19749
|
+
);
|
|
19750
|
+
}
|
|
19751
|
+
function launcherItemIcon(item) {
|
|
19752
|
+
let visual = item.icon;
|
|
19753
|
+
if (typeof visual === "function") visual = visual(item);
|
|
19754
|
+
if (typeof visual === "string") return icon(visual);
|
|
19755
|
+
if (visual instanceof Node) return visual.cloneNode(true);
|
|
19756
|
+
if (visual && typeof visual === "object" && typeof /** @type {any} */
|
|
19757
|
+
visual.toElement === "function") {
|
|
19758
|
+
const element = (
|
|
19759
|
+
/** @type {any} */
|
|
19760
|
+
visual.toElement()
|
|
19761
|
+
);
|
|
19762
|
+
return element instanceof Node ? element.cloneNode(true) : null;
|
|
19763
|
+
}
|
|
19764
|
+
return null;
|
|
19765
|
+
}
|
|
19766
|
+
function normalizeLauncherKind(kind) {
|
|
19767
|
+
return kind === "application" || kind === "record" ? kind : "action";
|
|
19768
|
+
}
|
|
19769
|
+
function visibleForQuery(when, query) {
|
|
19770
|
+
if (when === "empty") return query === "";
|
|
19771
|
+
if (when === "query") return query !== "";
|
|
19772
|
+
return true;
|
|
19773
|
+
}
|
|
19774
|
+
function findSpatialLauncherOption(options, current, direction) {
|
|
19775
|
+
const origin = current.getBoundingClientRect();
|
|
19776
|
+
if (origin.width === 0 && origin.height === 0) return null;
|
|
19777
|
+
const originX = origin.left + origin.width / 2;
|
|
19778
|
+
const originY = origin.top + origin.height / 2;
|
|
19779
|
+
let best = null;
|
|
19780
|
+
let bestScore = Infinity;
|
|
19781
|
+
for (const option of options) {
|
|
19782
|
+
if (option === current) continue;
|
|
19783
|
+
const rect = option.getBoundingClientRect();
|
|
19784
|
+
const dx = rect.left + rect.width / 2 - originX;
|
|
19785
|
+
const dy = rect.top + rect.height / 2 - originY;
|
|
19786
|
+
let valid = false;
|
|
19787
|
+
let score = Infinity;
|
|
19788
|
+
if (direction === "ArrowLeft") {
|
|
19789
|
+
valid = dx < -2 && Math.abs(dy) < Math.max(origin.height, rect.height) / 2;
|
|
19790
|
+
score = Math.abs(dx) + Math.abs(dy) * 4;
|
|
19791
|
+
} else if (direction === "ArrowRight") {
|
|
19792
|
+
valid = dx > 2 && Math.abs(dy) < Math.max(origin.height, rect.height) / 2;
|
|
19793
|
+
score = Math.abs(dx) + Math.abs(dy) * 4;
|
|
19794
|
+
} else if (direction === "ArrowUp") {
|
|
19795
|
+
valid = dy < -2;
|
|
19796
|
+
score = Math.abs(dy) * 10 + Math.abs(dx);
|
|
19797
|
+
} else if (direction === "ArrowDown") {
|
|
19798
|
+
valid = dy > 2;
|
|
19799
|
+
score = Math.abs(dy) * 10 + Math.abs(dx);
|
|
19800
|
+
}
|
|
19801
|
+
if (valid && score < bestScore) {
|
|
19802
|
+
best = option;
|
|
19803
|
+
bestScore = score;
|
|
19804
|
+
}
|
|
19805
|
+
}
|
|
19806
|
+
return best;
|
|
19807
|
+
}
|
|
19176
19808
|
function rankLauncherItems(items, query, limit = 100) {
|
|
19177
19809
|
const needle = searchable(query).trim();
|
|
19178
19810
|
const ranked = items.map((item, order) => ({ item, order, score: launcherScore(item, needle) })).filter(({ score }) => score < Infinity);
|
|
19179
19811
|
ranked.sort((a, b) => {
|
|
19812
|
+
const aGroup = finiteOrder(a.item.groupOrder);
|
|
19813
|
+
const bGroup = finiteOrder(b.item.groupOrder);
|
|
19814
|
+
if (aGroup !== bGroup) return aGroup - bGroup;
|
|
19180
19815
|
if (needle === "") {
|
|
19181
19816
|
const aPinned = pinOrder(a.item.pinned, a.order);
|
|
19182
19817
|
const bPinned = pinOrder(b.item.pinned, b.order);
|
|
19183
19818
|
if (aPinned !== bPinned) return aPinned - bPinned;
|
|
19184
19819
|
}
|
|
19185
|
-
return a.score - b.score || compareLauncherText(a.item.label, b.item.label) || a.order - b.order;
|
|
19820
|
+
return a.score - b.score || finiteOrder(a.item.itemOrder) - finiteOrder(b.item.itemOrder) || compareLauncherText(a.item.label, b.item.label) || a.order - b.order;
|
|
19186
19821
|
});
|
|
19187
19822
|
const maximum = Math.max(0, Number(limit) || 0);
|
|
19188
19823
|
return ranked.slice(0, maximum || 0).map(({ item, score }) => ({ ...item, _score: score }));
|
|
@@ -19206,6 +19841,9 @@ var zx = (() => {
|
|
|
19206
19841
|
if (pinned) return order;
|
|
19207
19842
|
return Number.MAX_SAFE_INTEGER;
|
|
19208
19843
|
}
|
|
19844
|
+
function finiteOrder(value) {
|
|
19845
|
+
return typeof value === "number" && Number.isFinite(value) ? value : Number.MAX_SAFE_INTEGER;
|
|
19846
|
+
}
|
|
19209
19847
|
function searchable(value) {
|
|
19210
19848
|
return String(value ?? "").normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase();
|
|
19211
19849
|
}
|
|
@@ -19220,15 +19858,23 @@ var zx = (() => {
|
|
|
19220
19858
|
}
|
|
19221
19859
|
function normalizeItems2(items) {
|
|
19222
19860
|
if (!Array.isArray(items)) return [];
|
|
19223
|
-
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) => (
|
|
19861
|
+
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) => normalizeLauncherItem(item));
|
|
19862
|
+
}
|
|
19863
|
+
function normalizeLauncherItem(item) {
|
|
19864
|
+
const normalized = { ...item, label: String(item.label) };
|
|
19865
|
+
if (item.href == null) return normalized;
|
|
19866
|
+
const href = safeHref(item.href);
|
|
19867
|
+
if (href !== null) normalized.href = href;
|
|
19868
|
+
else {
|
|
19869
|
+
delete normalized.href;
|
|
19870
|
+
if (typeof normalized.invoke !== "function") normalized.disabled = true;
|
|
19871
|
+
}
|
|
19872
|
+
return normalized;
|
|
19224
19873
|
}
|
|
19225
19874
|
function normalizeSources(sources) {
|
|
19226
19875
|
if (!Array.isArray(sources)) return [];
|
|
19227
19876
|
return sources.filter((source) => source && typeof source === "object" && source.id != null && typeof source.load === "function").map((source) => ({ ...source, id: String(source.id) }));
|
|
19228
19877
|
}
|
|
19229
|
-
function orderedLauncherSourceItems(sources, sourceItems) {
|
|
19230
|
-
return sources.flatMap((source) => sourceItems.get(String(source.id)) ?? []);
|
|
19231
|
-
}
|
|
19232
19878
|
|
|
19233
19879
|
// src/components/avatar/avatar.js
|
|
19234
19880
|
var Avatar = class extends Component {
|
|
@@ -19916,10 +20562,10 @@ var zx = (() => {
|
|
|
19916
20562
|
}
|
|
19917
20563
|
}
|
|
19918
20564
|
|
|
19919
|
-
// src/
|
|
19920
|
-
var
|
|
20565
|
+
// src/internal/app-rail.js
|
|
20566
|
+
var AppRailPresenter = class extends Component {
|
|
19921
20567
|
static cssName = "app-rail";
|
|
19922
|
-
/** @type {Readonly<
|
|
20568
|
+
/** @type {Readonly<AppRailPresenterOptions>} */
|
|
19923
20569
|
static defaults = {
|
|
19924
20570
|
items: [],
|
|
19925
20571
|
active: null,
|
|
@@ -19929,12 +20575,13 @@ var zx = (() => {
|
|
|
19929
20575
|
header: null,
|
|
19930
20576
|
footer: null,
|
|
19931
20577
|
openDelay: 80,
|
|
19932
|
-
closeDelay: 160
|
|
20578
|
+
closeDelay: 160,
|
|
20579
|
+
renderIcon: null
|
|
19933
20580
|
};
|
|
19934
20581
|
/**
|
|
19935
20582
|
* Creates or enhances a rail host.
|
|
19936
20583
|
* @param {Element|string|null} target Rail target.
|
|
19937
|
-
* @param {
|
|
20584
|
+
* @param {AppRailPresenterOptions} [options={}] Rail options.
|
|
19938
20585
|
*/
|
|
19939
20586
|
constructor(target = null, options = {}) {
|
|
19940
20587
|
super(target, options);
|
|
@@ -20084,7 +20731,14 @@ var zx = (() => {
|
|
|
20084
20731
|
index: String(item.id),
|
|
20085
20732
|
iconOnly: true,
|
|
20086
20733
|
disclosure: hasChildren,
|
|
20087
|
-
disclosureIcon: railDisclosureIcon(this.el.dataset.side)
|
|
20734
|
+
disclosureIcon: railDisclosureIcon(this.el.dataset.side),
|
|
20735
|
+
visual: appNavIcon(item, this.options.renderIcon, {
|
|
20736
|
+
orientation: this.el.dataset.orientation,
|
|
20737
|
+
collapsed: true,
|
|
20738
|
+
side: this.el.dataset.side,
|
|
20739
|
+
level: 1,
|
|
20740
|
+
location: "root"
|
|
20741
|
+
})
|
|
20088
20742
|
});
|
|
20089
20743
|
const row2 = h("li", { class: "zx-app-rail__row" }, control);
|
|
20090
20744
|
this.refs.list.append(row2);
|
|
@@ -20125,7 +20779,14 @@ var zx = (() => {
|
|
|
20125
20779
|
index: childKey,
|
|
20126
20780
|
iconOnly: false,
|
|
20127
20781
|
disclosure: hasChildren,
|
|
20128
|
-
disclosureIcon: nestedDisclosureIcon(this.el.dataset.side)
|
|
20782
|
+
disclosureIcon: nestedDisclosureIcon(this.el.dataset.side),
|
|
20783
|
+
visual: appNavIcon(child, this.options.renderIcon, {
|
|
20784
|
+
orientation: this.el.dataset.orientation,
|
|
20785
|
+
collapsed: true,
|
|
20786
|
+
side: this.el.dataset.side,
|
|
20787
|
+
level: childKey.split("/").length,
|
|
20788
|
+
location: "flyout"
|
|
20789
|
+
})
|
|
20129
20790
|
});
|
|
20130
20791
|
list.append(h("li", {}, control));
|
|
20131
20792
|
if (hasChildren) this._buildFlyout(child, control, childKey, key);
|
|
@@ -20179,7 +20840,6 @@ var zx = (() => {
|
|
|
20179
20840
|
this._interaction.listen(trigger, "click", (event) => {
|
|
20180
20841
|
event.preventDefault();
|
|
20181
20842
|
if (event instanceof MouseEvent && event.detail === 0) this.openFlyout(key, { focus: true });
|
|
20182
|
-
else if (dropdown.isOpen()) this.closeFlyout(key);
|
|
20183
20843
|
else this.openFlyout(key);
|
|
20184
20844
|
});
|
|
20185
20845
|
this._interaction.listen(actualPanel, "pointerenter", () => this._cancelFlyoutTimers(flyout, true));
|
|
@@ -20434,14 +21094,43 @@ var zx = (() => {
|
|
|
20434
21094
|
};
|
|
20435
21095
|
function normalizeAppItems(items) {
|
|
20436
21096
|
if (!Array.isArray(items)) return [];
|
|
20437
|
-
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) =>
|
|
20438
|
-
|
|
20439
|
-
|
|
20440
|
-
|
|
20441
|
-
|
|
21097
|
+
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) => {
|
|
21098
|
+
const normalized = {
|
|
21099
|
+
...item,
|
|
21100
|
+
label: String(item.label),
|
|
21101
|
+
children: Array.isArray(item.children) ? normalizeAppItems(item.children) : []
|
|
21102
|
+
};
|
|
21103
|
+
if (item.href == null) return normalized;
|
|
21104
|
+
const href = safeHref(item.href);
|
|
21105
|
+
if (href !== null) normalized.href = href;
|
|
21106
|
+
else {
|
|
21107
|
+
delete normalized.href;
|
|
21108
|
+
if (normalized.children.length === 0 && typeof normalized.invoke !== "function") {
|
|
21109
|
+
normalized.disabled = true;
|
|
21110
|
+
}
|
|
21111
|
+
}
|
|
21112
|
+
return normalized;
|
|
21113
|
+
});
|
|
20442
21114
|
}
|
|
20443
|
-
function
|
|
20444
|
-
|
|
21115
|
+
function appNavIcon(item, renderer, context) {
|
|
21116
|
+
let visual = typeof renderer === "function" ? renderer(item, context) : null;
|
|
21117
|
+
if (visual == null) visual = item.icon;
|
|
21118
|
+
if (typeof visual === "function") visual = visual(context, item);
|
|
21119
|
+
if (typeof visual === "string") return icon(visual);
|
|
21120
|
+
if (visual instanceof Node) return visual.cloneNode(true);
|
|
21121
|
+
if (visual && typeof visual === "object" && typeof /** @type {any} */
|
|
21122
|
+
visual.toElement === "function") {
|
|
21123
|
+
const element = (
|
|
21124
|
+
/** @type {any} */
|
|
21125
|
+
visual.toElement()
|
|
21126
|
+
);
|
|
21127
|
+
return element instanceof Node ? element.cloneNode(true) : null;
|
|
21128
|
+
}
|
|
21129
|
+
return null;
|
|
21130
|
+
}
|
|
21131
|
+
function navControl(item, { className, index, iconOnly, disclosure, disclosureIcon, visual }) {
|
|
21132
|
+
const href = safeHref(item.href);
|
|
21133
|
+
const tag = href && !disclosure ? "a" : "button";
|
|
20445
21134
|
return (
|
|
20446
21135
|
/** @type {HTMLElement} */
|
|
20447
21136
|
h(
|
|
@@ -20449,13 +21138,14 @@ var zx = (() => {
|
|
|
20449
21138
|
{
|
|
20450
21139
|
class: className,
|
|
20451
21140
|
type: tag === "button" ? "button" : null,
|
|
20452
|
-
href: tag === "a" ?
|
|
21141
|
+
href: tag === "a" ? href : null,
|
|
20453
21142
|
target: tag === "a" ? item.target ?? null : null,
|
|
21143
|
+
rel: tag === "a" ? "noopener" : null,
|
|
20454
21144
|
ariaLabel: iconOnly ? item.label : null,
|
|
20455
21145
|
ariaDisabled: item.disabled ? "true" : null,
|
|
20456
21146
|
dataset: { appNavId: index, appNavValueId: String(item.id) }
|
|
20457
21147
|
},
|
|
20458
|
-
|
|
21148
|
+
visual ? h("span", { class: `${className}-icon`, ariaHidden: "true" }, visual) : null,
|
|
20459
21149
|
h("span", { class: `${className}-label` }, item.label),
|
|
20460
21150
|
item.badge != null ? h("span", { class: `${className}-badge` }, String(item.badge)) : null,
|
|
20461
21151
|
disclosure ? h("span", { class: `${className}-disclosure`, ariaHidden: "true" }, icon(disclosureIcon)) : null
|
|
@@ -20519,47 +21209,28 @@ var zx = (() => {
|
|
|
20519
21209
|
active: null,
|
|
20520
21210
|
expanded: [],
|
|
20521
21211
|
collapsed: false,
|
|
21212
|
+
collapsible: true,
|
|
21213
|
+
orientation: "vertical",
|
|
20522
21214
|
side: "left",
|
|
20523
21215
|
label: "Applications",
|
|
20524
21216
|
header: null,
|
|
20525
21217
|
footer: null,
|
|
20526
21218
|
railHeader: null,
|
|
20527
|
-
railFooter: null
|
|
21219
|
+
railFooter: null,
|
|
21220
|
+
openDelay: 80,
|
|
21221
|
+
closeDelay: 160,
|
|
21222
|
+
renderIcon: null
|
|
20528
21223
|
};
|
|
20529
21224
|
/**
|
|
20530
|
-
* Creates or enhances an application-
|
|
20531
|
-
* @param {Element|string|null} target
|
|
20532
|
-
* @param {AppSidebarOptions} [options={}]
|
|
21225
|
+
* Creates or enhances an application-navigation host.
|
|
21226
|
+
* @param {Element|string|null} [target=null] Navigation target.
|
|
21227
|
+
* @param {AppSidebarOptions} [options={}] Navigation options.
|
|
20533
21228
|
*/
|
|
20534
21229
|
constructor(target = null, options = {}) {
|
|
20535
21230
|
super(target, options);
|
|
20536
|
-
this.
|
|
20537
|
-
|
|
20538
|
-
|
|
20539
|
-
type: "button",
|
|
20540
|
-
ariaLabel: "Expand application sidebar"
|
|
20541
|
-
}, icon(this.el.dataset.side === "right" ? "chevron-left" : "chevron-right"));
|
|
20542
|
-
this._railExpandButton = expandButton;
|
|
20543
|
-
const railHeader = h("div", { class: "zx-app-sidebar__rail-header" }, expandButton);
|
|
20544
|
-
appendSlot2(railHeader, this.options.railHeader);
|
|
20545
|
-
this._rail = new AppRail(this.refs.rail, {
|
|
20546
|
-
items: this._items,
|
|
20547
|
-
active: this._active,
|
|
20548
|
-
orientation: "vertical",
|
|
20549
|
-
side: this.el.dataset.side,
|
|
20550
|
-
label: this.options.label,
|
|
20551
|
-
header: railHeader,
|
|
20552
|
-
footer: this.options.railFooter,
|
|
20553
|
-
onselect: (event) => {
|
|
20554
|
-
const selected = this.emit("select", event.detail);
|
|
20555
|
-
if (selected.defaultPrevented) event.preventDefault();
|
|
20556
|
-
}
|
|
20557
|
-
});
|
|
20558
|
-
this.listen(expandButton, "click", () => {
|
|
20559
|
-
this.expand();
|
|
20560
|
-
});
|
|
20561
|
-
this._renderTree();
|
|
20562
|
-
this.setCollapsed(Boolean(this.options.collapsed), { silent: true });
|
|
21231
|
+
this._rail = null;
|
|
21232
|
+
this._railExpandButton = null;
|
|
21233
|
+
this._renderMode();
|
|
20563
21234
|
}
|
|
20564
21235
|
/** @returns {HTMLElement} */
|
|
20565
21236
|
render() {
|
|
@@ -20577,57 +21248,39 @@ var zx = (() => {
|
|
|
20577
21248
|
this._active = this.options.active;
|
|
20578
21249
|
this._expanded = new Set(Array.isArray(this.options.expanded) ? this.options.expanded.map(String) : []);
|
|
20579
21250
|
this._collapsed = Boolean(this.options.collapsed);
|
|
20580
|
-
|
|
20581
|
-
|
|
20582
|
-
|
|
20583
|
-
|
|
20584
|
-
ref: "collapse",
|
|
20585
|
-
class: "zx-app-sidebar__collapse zx-icon-btn",
|
|
20586
|
-
type: "button",
|
|
20587
|
-
ariaLabel: "Minimize application sidebar"
|
|
20588
|
-
}, icon(root.dataset.side === "right" ? "chevron-right" : "chevron-left"));
|
|
20589
|
-
const footer = h("footer", { class: "zx-app-sidebar__footer" });
|
|
20590
|
-
appendSlot2(footer, this.options.footer);
|
|
20591
|
-
footer.hidden = !footer.hasChildNodes();
|
|
20592
|
-
const expanded = h(
|
|
20593
|
-
"div",
|
|
20594
|
-
{ ref: "expanded", class: "zx-app-sidebar__expanded" },
|
|
20595
|
-
h("header", { class: "zx-app-sidebar__header" }, headerContent, collapseButton),
|
|
20596
|
-
h(
|
|
20597
|
-
"nav",
|
|
20598
|
-
{ class: "zx-app-sidebar__nav", ariaLabel: this.options.label },
|
|
20599
|
-
h("ul", { ref: "list", class: "zx-app-sidebar__list" })
|
|
20600
|
-
),
|
|
20601
|
-
footer
|
|
20602
|
-
);
|
|
20603
|
-
const rail = h("div", { ref: "rail", class: "zx-app-sidebar__rail" });
|
|
20604
|
-
root.replaceChildren(expanded, rail);
|
|
20605
|
-
this.listen(collapseButton, "click", () => {
|
|
20606
|
-
this.collapse();
|
|
20607
|
-
});
|
|
20608
|
-
this.listen(this.refs.list, "click", (event) => this._onTreeClick(event));
|
|
21251
|
+
this._orientation = this.options.orientation === "horizontal" ? "horizontal" : "vertical";
|
|
21252
|
+
this._side = normalizeSide(this._orientation, this.options.side);
|
|
21253
|
+
this._modeAbort = null;
|
|
21254
|
+
root.replaceChildren();
|
|
20609
21255
|
return root;
|
|
20610
21256
|
}
|
|
20611
|
-
/** Replaces the navigation tree in
|
|
21257
|
+
/** Replaces the navigation tree in the active presentation. @param {AppNavItem[]} items @returns {this} */
|
|
20612
21258
|
setItems(items) {
|
|
20613
21259
|
this._items = normalizeAppItems(items);
|
|
20614
21260
|
this._reconcileExpanded();
|
|
20615
|
-
this.
|
|
20616
|
-
this.
|
|
21261
|
+
if (this._rail) this._rail.setItems(this._items);
|
|
21262
|
+
else this._renderTree();
|
|
20617
21263
|
return this;
|
|
20618
21264
|
}
|
|
20619
|
-
/**
|
|
21265
|
+
/** Returns a shallow copy of normalized items. @returns {AppNavItem[]} */
|
|
21266
|
+
getItems() {
|
|
21267
|
+
return this._items.map((item) => ({
|
|
21268
|
+
...item,
|
|
21269
|
+
children: item.children?.map((child) => ({ ...child }))
|
|
21270
|
+
}));
|
|
21271
|
+
}
|
|
21272
|
+
/** Sets the active id without routing. @param {string|number|null} id @returns {this} */
|
|
20620
21273
|
setActive(id) {
|
|
20621
21274
|
this._active = id;
|
|
20622
|
-
this.
|
|
20623
|
-
this.
|
|
21275
|
+
if (this._rail) this._rail.setActive(id);
|
|
21276
|
+
else this._syncActive();
|
|
20624
21277
|
return this;
|
|
20625
21278
|
}
|
|
20626
21279
|
/** Replaces expanded branch ids. @param {Array<string|number>} ids @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20627
21280
|
setExpanded(ids, { silent = false } = {}) {
|
|
20628
21281
|
this._expanded = new Set(Array.isArray(ids) ? ids.map(String) : []);
|
|
20629
21282
|
this._reconcileExpanded();
|
|
20630
|
-
this._renderTree();
|
|
21283
|
+
if (!this._rail) this._renderTree();
|
|
20631
21284
|
if (!silent) this.emit("branchchange", {
|
|
20632
21285
|
item: null,
|
|
20633
21286
|
id: null,
|
|
@@ -20652,47 +21305,105 @@ var zx = (() => {
|
|
|
20652
21305
|
const expanded = !this._expanded.has(key);
|
|
20653
21306
|
if (expanded) this._expanded.add(key);
|
|
20654
21307
|
else this._expanded.delete(key);
|
|
20655
|
-
this._renderTree();
|
|
20656
|
-
if (!silent) this.emit("branchchange", {
|
|
21308
|
+
if (!this._rail) this._renderTree();
|
|
21309
|
+
if (!silent) this.emit("branchchange", {
|
|
21310
|
+
item,
|
|
21311
|
+
id: item.id,
|
|
21312
|
+
expanded,
|
|
21313
|
+
ids: this.getExpanded()
|
|
21314
|
+
});
|
|
20657
21315
|
return this;
|
|
20658
21316
|
}
|
|
20659
|
-
/** Shows the expanded
|
|
21317
|
+
/** Shows the expanded vertical presentation. @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20660
21318
|
expand(options = {}) {
|
|
20661
21319
|
return this.setCollapsed(false, options);
|
|
20662
21320
|
}
|
|
20663
|
-
/** Shows the minimized
|
|
21321
|
+
/** Shows the minimized presentation. @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20664
21322
|
collapse(options = {}) {
|
|
20665
21323
|
return this.setCollapsed(true, options);
|
|
20666
21324
|
}
|
|
20667
|
-
/** Sets expanded/minimized
|
|
21325
|
+
/** Sets the saved vertical expanded/minimized state. @param {boolean} collapsed @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20668
21326
|
setCollapsed(collapsed, { silent = false } = {}) {
|
|
20669
|
-
const
|
|
20670
|
-
const changed = next !== this._collapsed;
|
|
21327
|
+
const previous = this.isCollapsed();
|
|
20671
21328
|
const active = document.activeElement;
|
|
20672
|
-
const
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
|
|
20677
|
-
|
|
20678
|
-
|
|
20679
|
-
|
|
20680
|
-
|
|
20681
|
-
|
|
20682
|
-
|
|
20683
|
-
|
|
20684
|
-
|
|
21329
|
+
const outgoingOwnedFocus = Boolean(active && (this.el.contains(active) || this._rail?._containsNode(active)));
|
|
21330
|
+
this._collapsed = Boolean(collapsed);
|
|
21331
|
+
const next = this.isCollapsed();
|
|
21332
|
+
if (previous !== next) {
|
|
21333
|
+
this._renderMode();
|
|
21334
|
+
if (outgoingOwnedFocus) {
|
|
21335
|
+
if (next) this._railExpandButton?.focus();
|
|
21336
|
+
else this.refs.collapse?.focus();
|
|
21337
|
+
}
|
|
21338
|
+
if (!silent) this.emit("collapsechange", { collapsed: next });
|
|
21339
|
+
}
|
|
21340
|
+
return this;
|
|
21341
|
+
}
|
|
21342
|
+
/** Reports the effective presentation state; horizontal navigation is always minimized. @returns {boolean} */
|
|
20685
21343
|
isCollapsed() {
|
|
20686
|
-
return this._collapsed;
|
|
21344
|
+
return this._orientation === "horizontal" || this._collapsed;
|
|
20687
21345
|
}
|
|
20688
|
-
/**
|
|
20689
|
-
|
|
20690
|
-
|
|
21346
|
+
/**
|
|
21347
|
+
* Changes navigation flow/edge without replacing state.
|
|
21348
|
+
* @param {{orientation?: 'vertical'|'horizontal', side?: 'left'|'right'|'top'|'bottom'}} layout
|
|
21349
|
+
* @param {{silent?: boolean}} [options]
|
|
21350
|
+
* @returns {this}
|
|
21351
|
+
*/
|
|
21352
|
+
setLayout(layout = {}, { silent = false } = {}) {
|
|
21353
|
+
const orientation = layout.orientation === "horizontal" ? "horizontal" : layout.orientation === "vertical" ? "vertical" : this._orientation;
|
|
21354
|
+
const side = normalizeSide(orientation, layout.side ?? this._side);
|
|
21355
|
+
if (orientation === this._orientation && side === this._side) return this;
|
|
21356
|
+
const previous = this.isCollapsed();
|
|
21357
|
+
const active = document.activeElement;
|
|
21358
|
+
const outgoingOwnedFocus = Boolean(active && (this.el.contains(active) || this._rail?._containsNode(active)));
|
|
21359
|
+
const focusedId = outgoingOwnedFocus && active instanceof Element ? active.closest("[data-app-nav-id]")?.getAttribute("data-app-nav-id") ?? null : null;
|
|
21360
|
+
this._orientation = orientation;
|
|
21361
|
+
this._side = side;
|
|
21362
|
+
this._renderMode();
|
|
21363
|
+
const next = this.isCollapsed();
|
|
21364
|
+
if (outgoingOwnedFocus) {
|
|
21365
|
+
const replacement = focusedId === null ? null : [...this.el.querySelectorAll("[data-app-nav-id]")].find((control) => control.getAttribute("data-app-nav-id") === focusedId) ?? null;
|
|
21366
|
+
if (replacement instanceof HTMLElement) replacement.focus();
|
|
21367
|
+
else if (next) this.focus();
|
|
21368
|
+
else if (this.refs.collapse instanceof HTMLElement && !this.refs.collapse.hidden) {
|
|
21369
|
+
this.refs.collapse.focus();
|
|
21370
|
+
} else visibleTreeControls(this.refs.list)[0]?.focus();
|
|
21371
|
+
}
|
|
21372
|
+
if (previous !== next && !silent) this.emit("collapsechange", { collapsed: next });
|
|
21373
|
+
return this;
|
|
20691
21374
|
}
|
|
20692
|
-
/**
|
|
21375
|
+
/** Opens a minimized descendant flyout. @param {string|number} id @param {{focus?: boolean}} [options={}] @returns {this} */
|
|
21376
|
+
openFlyout(id, options = {}) {
|
|
21377
|
+
this._rail?.openFlyout(id, options);
|
|
21378
|
+
return this;
|
|
21379
|
+
}
|
|
21380
|
+
/** Closes a minimized descendant flyout. @param {string|number} id @returns {this} */
|
|
21381
|
+
closeFlyout(id) {
|
|
21382
|
+
this._rail?.closeFlyout(id);
|
|
21383
|
+
return this;
|
|
21384
|
+
}
|
|
21385
|
+
/** Closes every minimized flyout. @returns {this} */
|
|
21386
|
+
closeAllFlyouts() {
|
|
21387
|
+
this._rail?.closeAllFlyouts();
|
|
21388
|
+
return this;
|
|
21389
|
+
}
|
|
21390
|
+
/** Reports whether a minimized flyout is open. @param {string|number} id @returns {boolean} */
|
|
21391
|
+
isFlyoutOpen(id) {
|
|
21392
|
+
return this._rail?.isFlyoutOpen(id) ?? false;
|
|
21393
|
+
}
|
|
21394
|
+
/** Focuses the first navigation action. @returns {this} */
|
|
21395
|
+
focus() {
|
|
21396
|
+
if (this._rail) this._rail.focus();
|
|
21397
|
+
else visibleTreeControls(this.refs.list)[0]?.focus();
|
|
21398
|
+
return this;
|
|
21399
|
+
}
|
|
21400
|
+
/** Destroys flyouts and restores/removes the host. @returns {void} */
|
|
20693
21401
|
destroy() {
|
|
20694
21402
|
const original = this._original;
|
|
20695
|
-
this.
|
|
21403
|
+
this._modeAbort?.abort();
|
|
21404
|
+
this._modeAbort = null;
|
|
21405
|
+
this._rail?.destroy();
|
|
21406
|
+
this._rail = null;
|
|
20696
21407
|
super.destroy();
|
|
20697
21408
|
if (!this._createdRoot && original) {
|
|
20698
21409
|
for (const attribute of Array.from(this.el.attributes)) this.el.removeAttribute(attribute.name);
|
|
@@ -20700,8 +21411,99 @@ var zx = (() => {
|
|
|
20700
21411
|
this.el.replaceChildren(...original.children);
|
|
20701
21412
|
}
|
|
20702
21413
|
}
|
|
21414
|
+
/** Mounts exactly one expanded tree or minimized flyout presentation. @returns {void} */
|
|
21415
|
+
_renderMode() {
|
|
21416
|
+
this._modeAbort?.abort();
|
|
21417
|
+
this._modeAbort = new AbortController();
|
|
21418
|
+
this._rail?.destroy();
|
|
21419
|
+
this._rail = null;
|
|
21420
|
+
this._railExpandButton = null;
|
|
21421
|
+
for (const key of ["expanded", "list", "collapse", "rail"]) delete this.refs[key];
|
|
21422
|
+
this.el.replaceChildren();
|
|
21423
|
+
this.el.dataset.orientation = this._orientation;
|
|
21424
|
+
this.el.dataset.side = this._side;
|
|
21425
|
+
this.el.dataset.collapsed = String(this.isCollapsed());
|
|
21426
|
+
if (this.isCollapsed()) this._renderRail();
|
|
21427
|
+
else this._renderExpanded();
|
|
21428
|
+
}
|
|
21429
|
+
/** @returns {void} */
|
|
21430
|
+
_renderExpanded() {
|
|
21431
|
+
const headerContent = h("div", { class: "zx-app-sidebar__header-content" });
|
|
21432
|
+
appendSlot2(headerContent, this.options.header);
|
|
21433
|
+
const collapseButton = h("button", {
|
|
21434
|
+
class: "zx-app-sidebar__collapse zx-icon-btn",
|
|
21435
|
+
type: "button",
|
|
21436
|
+
ariaLabel: "Minimize application sidebar"
|
|
21437
|
+
}, icon(this._side === "right" ? "chevron-right" : "chevron-left"));
|
|
21438
|
+
collapseButton.hidden = !this.options.collapsible;
|
|
21439
|
+
const footer = h("footer", { class: "zx-app-sidebar__footer" });
|
|
21440
|
+
appendSlot2(footer, this.options.footer);
|
|
21441
|
+
footer.hidden = !footer.hasChildNodes();
|
|
21442
|
+
const list = h("ul", { class: "zx-app-sidebar__list" });
|
|
21443
|
+
const expanded = h(
|
|
21444
|
+
"div",
|
|
21445
|
+
{ class: "zx-app-sidebar__expanded" },
|
|
21446
|
+
h("header", { class: "zx-app-sidebar__header" }, headerContent, collapseButton),
|
|
21447
|
+
h("nav", { class: "zx-app-sidebar__nav", ariaLabel: this.options.label }, list),
|
|
21448
|
+
footer
|
|
21449
|
+
);
|
|
21450
|
+
this.refs.expanded = expanded;
|
|
21451
|
+
this.refs.list = list;
|
|
21452
|
+
this.refs.collapse = collapseButton;
|
|
21453
|
+
this.el.append(expanded);
|
|
21454
|
+
this._listenMode(collapseButton, "click", () => this.collapse());
|
|
21455
|
+
this._listenMode(list, "click", (event) => this._onTreeClick(event));
|
|
21456
|
+
this._listenMode(list, "keydown", (event) => this._onTreeKeydown(
|
|
21457
|
+
/** @type {KeyboardEvent} */
|
|
21458
|
+
event
|
|
21459
|
+
));
|
|
21460
|
+
this._renderTree();
|
|
21461
|
+
}
|
|
21462
|
+
/** @returns {void} */
|
|
21463
|
+
_renderRail() {
|
|
21464
|
+
const railHost = h("nav", { class: "zx-app-sidebar__rail" });
|
|
21465
|
+
this.el.append(railHost);
|
|
21466
|
+
this.refs.rail = railHost;
|
|
21467
|
+
const showToggle = this._orientation === "vertical" && Boolean(this.options.collapsible);
|
|
21468
|
+
const railHeader = h("div", { class: "zx-app-sidebar__rail-header" });
|
|
21469
|
+
if (showToggle) {
|
|
21470
|
+
const expandButton = h("button", {
|
|
21471
|
+
class: "zx-app-sidebar__rail-toggle zx-icon-btn",
|
|
21472
|
+
type: "button",
|
|
21473
|
+
ariaLabel: "Expand application sidebar"
|
|
21474
|
+
}, icon(this._side === "right" ? "chevron-left" : "chevron-right"));
|
|
21475
|
+
railHeader.append(expandButton);
|
|
21476
|
+
this._railExpandButton = expandButton;
|
|
21477
|
+
this._listenMode(expandButton, "click", () => this.expand());
|
|
21478
|
+
}
|
|
21479
|
+
appendSlot2(railHeader, this.options.railHeader);
|
|
21480
|
+
this._rail = new AppRailPresenter(railHost, {
|
|
21481
|
+
items: this._items,
|
|
21482
|
+
active: this._active,
|
|
21483
|
+
orientation: this._orientation,
|
|
21484
|
+
side: this._side,
|
|
21485
|
+
label: this.options.label,
|
|
21486
|
+
header: railHeader.hasChildNodes() ? railHeader : null,
|
|
21487
|
+
footer: this.options.railFooter,
|
|
21488
|
+
openDelay: this.options.openDelay,
|
|
21489
|
+
closeDelay: this.options.closeDelay,
|
|
21490
|
+
renderIcon: this.options.renderIcon,
|
|
21491
|
+
onselect: (event) => {
|
|
21492
|
+
const selected = this.emit("select", event.detail);
|
|
21493
|
+
if (selected.defaultPrevented) event.preventDefault();
|
|
21494
|
+
},
|
|
21495
|
+
onflyoutchange: (event) => this.emit("flyoutchange", event.detail)
|
|
21496
|
+
});
|
|
21497
|
+
this._listenMode(railHost, "zx-select", (event) => event.stopPropagation());
|
|
21498
|
+
this._listenMode(railHost, "zx-flyoutchange", (event) => event.stopPropagation());
|
|
21499
|
+
}
|
|
21500
|
+
/** @param {EventTarget} target @param {string} type @param {EventListener} listener @returns {void} */
|
|
21501
|
+
_listenMode(target, type, listener) {
|
|
21502
|
+
target.addEventListener(type, listener, { signal: this._modeAbort.signal });
|
|
21503
|
+
}
|
|
20703
21504
|
/** @returns {void} */
|
|
20704
21505
|
_renderTree() {
|
|
21506
|
+
if (!this.refs.list) return;
|
|
20705
21507
|
const focused = this.refs.list.contains(document.activeElement) ? (
|
|
20706
21508
|
/** @type {Element} */
|
|
20707
21509
|
document.activeElement.closest("[data-app-nav-id]")?.getAttribute("data-app-nav-id")
|
|
@@ -20720,7 +21522,14 @@ var zx = (() => {
|
|
|
20720
21522
|
const key = String(item.id);
|
|
20721
21523
|
const expanded = hasChildren && this._expanded.has(key);
|
|
20722
21524
|
const childId = hasChildren ? uid("zx-app-sidebar-branch") : null;
|
|
20723
|
-
const
|
|
21525
|
+
const visual = appNavIcon(item, this.options.renderIcon, {
|
|
21526
|
+
orientation: this._orientation,
|
|
21527
|
+
collapsed: false,
|
|
21528
|
+
side: this._side,
|
|
21529
|
+
level,
|
|
21530
|
+
location: level === 1 ? "root" : "inline"
|
|
21531
|
+
});
|
|
21532
|
+
const control = navControl2(item, hasChildren, expanded, childId, visual);
|
|
20724
21533
|
const row2 = h("li", {
|
|
20725
21534
|
class: "zx-app-sidebar__row",
|
|
20726
21535
|
dataset: { level }
|
|
@@ -20734,7 +21543,7 @@ var zx = (() => {
|
|
|
20734
21543
|
}
|
|
20735
21544
|
return row2;
|
|
20736
21545
|
}
|
|
20737
|
-
/**
|
|
21546
|
+
/** @param {Event} event @returns {void} */
|
|
20738
21547
|
_onTreeClick(event) {
|
|
20739
21548
|
const control = (
|
|
20740
21549
|
/** @type {Element|null} */
|
|
@@ -20749,6 +21558,45 @@ var zx = (() => {
|
|
|
20749
21558
|
if (item.children?.length) this.toggleBranch(item.id);
|
|
20750
21559
|
else this._select(item, event);
|
|
20751
21560
|
}
|
|
21561
|
+
/** @param {KeyboardEvent} event @returns {void} */
|
|
21562
|
+
_onTreeKeydown(event) {
|
|
21563
|
+
const current = (
|
|
21564
|
+
/** @type {Element|null} */
|
|
21565
|
+
event.target?.closest?.("[data-app-nav-id]")
|
|
21566
|
+
);
|
|
21567
|
+
if (!(current instanceof HTMLElement)) return;
|
|
21568
|
+
const item = findItem(this._items, current.getAttribute("data-app-nav-id"));
|
|
21569
|
+
const controls = visibleTreeControls(this.refs.list);
|
|
21570
|
+
const index = controls.indexOf(current);
|
|
21571
|
+
if (event.key === "ArrowRight" && item?.children?.length) {
|
|
21572
|
+
event.preventDefault();
|
|
21573
|
+
if (!this._expanded.has(String(item.id))) this.toggleBranch(item.id);
|
|
21574
|
+
else visibleTreeControls(current.parentElement?.querySelector(".zx-app-sidebar__sublist"))[0]?.focus();
|
|
21575
|
+
return;
|
|
21576
|
+
}
|
|
21577
|
+
if (event.key === "ArrowLeft") {
|
|
21578
|
+
if (item?.children?.length && this._expanded.has(String(item.id))) {
|
|
21579
|
+
event.preventDefault();
|
|
21580
|
+
this.toggleBranch(item.id);
|
|
21581
|
+
return;
|
|
21582
|
+
}
|
|
21583
|
+
const parentList = current.closest(".zx-app-sidebar__sublist");
|
|
21584
|
+
const parentControl = parentList?.parentElement?.querySelector(":scope > [data-app-nav-id]");
|
|
21585
|
+
if (parentControl instanceof HTMLElement) {
|
|
21586
|
+
event.preventDefault();
|
|
21587
|
+
parentControl.focus();
|
|
21588
|
+
}
|
|
21589
|
+
return;
|
|
21590
|
+
}
|
|
21591
|
+
let nextIndex;
|
|
21592
|
+
if (event.key === "Home") nextIndex = 0;
|
|
21593
|
+
else if (event.key === "End") nextIndex = controls.length - 1;
|
|
21594
|
+
else if (event.key === "ArrowDown") nextIndex = Math.min(controls.length - 1, index + 1);
|
|
21595
|
+
else if (event.key === "ArrowUp") nextIndex = Math.max(0, index - 1);
|
|
21596
|
+
else return;
|
|
21597
|
+
event.preventDefault();
|
|
21598
|
+
controls[nextIndex]?.focus();
|
|
21599
|
+
}
|
|
20752
21600
|
/** @param {AppNavItem} item @param {Event} event @returns {void} */
|
|
20753
21601
|
_select(item, event) {
|
|
20754
21602
|
if (item.disabled) {
|
|
@@ -20770,14 +21618,14 @@ var zx = (() => {
|
|
|
20770
21618
|
}
|
|
20771
21619
|
/** @returns {void} */
|
|
20772
21620
|
_syncActive() {
|
|
21621
|
+
if (!this.refs.list) return;
|
|
20773
21622
|
const activeId = this._active == null ? null : String(this._active);
|
|
20774
21623
|
for (const control of this.refs.list.querySelectorAll("[data-app-nav-id]")) {
|
|
20775
21624
|
const item = findItem(this._items, control.getAttribute("data-app-nav-id"));
|
|
20776
21625
|
const direct = activeId !== null && control.getAttribute("data-app-nav-id") === activeId;
|
|
20777
21626
|
const descendant = activeId !== null && item ? containsItemId2(item.children ?? [], activeId) : false;
|
|
20778
|
-
if (direct)
|
|
20779
|
-
|
|
20780
|
-
} else control.removeAttribute("aria-current");
|
|
21627
|
+
if (direct) control.setAttribute("aria-current", "page");
|
|
21628
|
+
else control.removeAttribute("aria-current");
|
|
20781
21629
|
if (descendant) control.dataset.activeDescendant = "true";
|
|
20782
21630
|
else delete control.dataset.activeDescendant;
|
|
20783
21631
|
}
|
|
@@ -20791,7 +21639,7 @@ var zx = (() => {
|
|
|
20791
21639
|
for (const id of this._expanded) if (!branchIds.has(id)) this._expanded.delete(id);
|
|
20792
21640
|
}
|
|
20793
21641
|
};
|
|
20794
|
-
function navControl2(item, disclosure, expanded, controls) {
|
|
21642
|
+
function navControl2(item, disclosure, expanded, controls, visual) {
|
|
20795
21643
|
const tag = item.href && !disclosure ? "a" : "button";
|
|
20796
21644
|
return (
|
|
20797
21645
|
/** @type {HTMLElement} */
|
|
@@ -20807,7 +21655,7 @@ var zx = (() => {
|
|
|
20807
21655
|
ariaControls: controls,
|
|
20808
21656
|
dataset: { appNavId: String(item.id) }
|
|
20809
21657
|
},
|
|
20810
|
-
|
|
21658
|
+
visual ? h("span", { class: "zx-app-sidebar__item-icon", ariaHidden: "true" }, visual) : null,
|
|
20811
21659
|
h("span", { class: "zx-app-sidebar__item-label" }, item.label),
|
|
20812
21660
|
item.badge != null ? h("span", { class: "zx-app-sidebar__item-badge" }, String(item.badge)) : null,
|
|
20813
21661
|
disclosure ? h(
|
|
@@ -20818,6 +21666,13 @@ var zx = (() => {
|
|
|
20818
21666
|
)
|
|
20819
21667
|
);
|
|
20820
21668
|
}
|
|
21669
|
+
function visibleTreeControls(root) {
|
|
21670
|
+
if (!root) return [];
|
|
21671
|
+
return (
|
|
21672
|
+
/** @type {HTMLElement[]} */
|
|
21673
|
+
[...root.querySelectorAll("[data-app-nav-id]")].filter((control) => !control.closest(".zx-app-sidebar__sublist[hidden]"))
|
|
21674
|
+
);
|
|
21675
|
+
}
|
|
20821
21676
|
function visibleTreeControl(control) {
|
|
20822
21677
|
let candidate = (
|
|
20823
21678
|
/** @type {HTMLElement|null} */
|
|
@@ -20850,12 +21705,17 @@ var zx = (() => {
|
|
|
20850
21705
|
}
|
|
20851
21706
|
function appendSlot2(target, content) {
|
|
20852
21707
|
if (content == null) return;
|
|
20853
|
-
if (typeof content === "string" || typeof content === "number")
|
|
20854
|
-
|
|
21708
|
+
if (typeof content === "string" || typeof content === "number") {
|
|
21709
|
+
target.append(document.createTextNode(String(content)));
|
|
21710
|
+
} else if (typeof content === "object" && typeof content.toElement === "function") {
|
|
20855
21711
|
const element = content.toElement();
|
|
20856
21712
|
if (element) target.append(element);
|
|
20857
21713
|
} else if (typeof content === "object" && typeof content.nodeType === "number") target.append(content);
|
|
20858
21714
|
}
|
|
21715
|
+
function normalizeSide(orientation, side) {
|
|
21716
|
+
if (orientation === "horizontal") return side === "bottom" ? "bottom" : "top";
|
|
21717
|
+
return side === "right" ? "right" : "left";
|
|
21718
|
+
}
|
|
20859
21719
|
|
|
20860
21720
|
// src/components/message/message.js
|
|
20861
21721
|
var MessageQueue = class {
|
|
@@ -22223,9 +23083,9 @@ var zx = (() => {
|
|
|
22223
23083
|
} = options;
|
|
22224
23084
|
const fields = { ...DEFAULT_FIELDS, ...requestedFields };
|
|
22225
23085
|
const calculateLineTotal = typeof lineTotal === "function" ? lineTotal : (row2) => {
|
|
22226
|
-
const quantity =
|
|
22227
|
-
const price =
|
|
22228
|
-
return
|
|
23086
|
+
const quantity = billingNumber(row2?.[fields.quantity]);
|
|
23087
|
+
const price = billingNumber(row2?.[fields.unitPrice]);
|
|
23088
|
+
return quantity !== null && price !== null ? quantity * price : null;
|
|
22229
23089
|
};
|
|
22230
23090
|
const columns = Array.isArray(suppliedColumns) ? suppliedColumns.map((column) => ({ ...column })) : billingColumns(fields, { units, currencies, currency, locale, decimals, columnOverrides });
|
|
22231
23091
|
return {
|
|
@@ -22330,6 +23190,11 @@ var zx = (() => {
|
|
|
22330
23190
|
function hasChoices(value) {
|
|
22331
23191
|
return Array.isArray(value) ? value.length > 0 : Boolean(value && typeof value === "object" && Object.keys(value).length);
|
|
22332
23192
|
}
|
|
23193
|
+
function billingNumber(value) {
|
|
23194
|
+
if (value == null || typeof value === "string" && value.trim() === "") return null;
|
|
23195
|
+
const number2 = Number(value);
|
|
23196
|
+
return Number.isFinite(number2) ? number2 : null;
|
|
23197
|
+
}
|
|
22333
23198
|
|
|
22334
23199
|
// src/components/chart/chart.js
|
|
22335
23200
|
var Chart = class extends Component {
|
|
@@ -22377,6 +23242,7 @@ var zx = (() => {
|
|
|
22377
23242
|
this._chartOptions = cloneChartValue(this.options.chartOptions);
|
|
22378
23243
|
this._loading = Boolean(this.options.loading);
|
|
22379
23244
|
this._error = null;
|
|
23245
|
+
this._hasError = false;
|
|
22380
23246
|
this._handle = null;
|
|
22381
23247
|
this._destroyed = false;
|
|
22382
23248
|
const descriptionId = uid("zx-chart-description");
|
|
@@ -22422,6 +23288,7 @@ var zx = (() => {
|
|
|
22422
23288
|
setData(data) {
|
|
22423
23289
|
this._data = normalizeChartData(data);
|
|
22424
23290
|
this._error = null;
|
|
23291
|
+
this._hasError = false;
|
|
22425
23292
|
this._loading = false;
|
|
22426
23293
|
this._renderSummary();
|
|
22427
23294
|
this._mountOrUpdate(true);
|
|
@@ -22457,6 +23324,7 @@ var zx = (() => {
|
|
|
22457
23324
|
/** Shows an error and destroys the current engine. @param {unknown} error @returns {this} */
|
|
22458
23325
|
setError(error) {
|
|
22459
23326
|
this._error = error ?? new Error(String(this.options.errorText));
|
|
23327
|
+
this._hasError = true;
|
|
22460
23328
|
this._loading = false;
|
|
22461
23329
|
this._destroyHandle();
|
|
22462
23330
|
this._syncState();
|
|
@@ -22466,6 +23334,7 @@ var zx = (() => {
|
|
|
22466
23334
|
/** Clears the error and remounts when data and an adapter are available. @returns {this} */
|
|
22467
23335
|
clearError() {
|
|
22468
23336
|
this._error = null;
|
|
23337
|
+
this._hasError = false;
|
|
22469
23338
|
this._mountOrUpdate(false);
|
|
22470
23339
|
return this;
|
|
22471
23340
|
}
|
|
@@ -22504,7 +23373,7 @@ var zx = (() => {
|
|
|
22504
23373
|
/** @param {boolean} emitUpdate @returns {void} */
|
|
22505
23374
|
_mountOrUpdate(emitUpdate) {
|
|
22506
23375
|
this._syncState();
|
|
22507
|
-
if (this._loading || this.
|
|
23376
|
+
if (this._loading || this._hasError || isEmptyChartData(this._data)) {
|
|
22508
23377
|
this._destroyHandle();
|
|
22509
23378
|
return;
|
|
22510
23379
|
}
|
|
@@ -22559,7 +23428,7 @@ var zx = (() => {
|
|
|
22559
23428
|
/** @returns {void} */
|
|
22560
23429
|
_syncState() {
|
|
22561
23430
|
const empty = isEmptyChartData(this._data);
|
|
22562
|
-
const state = this._loading ? "loading" : this.
|
|
23431
|
+
const state = this._loading ? "loading" : this._hasError ? "error" : empty ? "empty" : "ready";
|
|
22563
23432
|
this.el.dataset.state = state;
|
|
22564
23433
|
this.refs.viewport.hidden = state !== "ready";
|
|
22565
23434
|
let text4 = "";
|
|
@@ -22771,7 +23640,8 @@ var zx = (() => {
|
|
|
22771
23640
|
};
|
|
22772
23641
|
}
|
|
22773
23642
|
function errorMessage(error, fallback) {
|
|
22774
|
-
|
|
23643
|
+
const message = error && typeof error === "object" && "message" in error ? String(error.message) : "";
|
|
23644
|
+
return message.trim() ? message : String(fallback);
|
|
22775
23645
|
}
|
|
22776
23646
|
|
|
22777
23647
|
// src/components/tree/hierarchy.js
|