@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.esm.js
CHANGED
|
@@ -267,6 +267,18 @@ function compactElement(compact, properties = null, content = null) {
|
|
|
267
267
|
return element;
|
|
268
268
|
}
|
|
269
269
|
var __ = compactElement;
|
|
270
|
+
function safeHref(value) {
|
|
271
|
+
if (typeof value !== "string") return null;
|
|
272
|
+
const href = value.trim();
|
|
273
|
+
if (!href) return null;
|
|
274
|
+
try {
|
|
275
|
+
const protocol = new URL(href, globalThis.location?.href ?? "https://zx.invalid/").protocol;
|
|
276
|
+
if (["javascript:", "data:", "vbscript:"].includes(protocol.toLowerCase())) return null;
|
|
277
|
+
} catch {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
return href;
|
|
281
|
+
}
|
|
270
282
|
function applyCompactProperties(element, properties) {
|
|
271
283
|
for (const name in properties ?? {}) {
|
|
272
284
|
const value = properties[name];
|
|
@@ -6617,7 +6629,18 @@ var PRIORITY_KEYS = [
|
|
|
6617
6629
|
"priority.high",
|
|
6618
6630
|
"priority.highest"
|
|
6619
6631
|
];
|
|
6620
|
-
var PRIORITY_FALLBACKS = ["Lowest", "Low", "
|
|
6632
|
+
var PRIORITY_FALLBACKS = ["Lowest", "Low", "Medium", "High", "Highest"];
|
|
6633
|
+
var DEFAULT_STATUSES = Object.freeze([
|
|
6634
|
+
["backlog", "status.backlog", "Backlog", "dotted", "muted"],
|
|
6635
|
+
["todo", "status.todo", "Todo", "ring", "neutral"],
|
|
6636
|
+
["in-progress", "status.inProgress", "In Progress", "progress", "warning"],
|
|
6637
|
+
["in-review", "status.inReview", "In Review", "review", "info"],
|
|
6638
|
+
["ready", "status.ready", "Ready to Merge", "ready", "accent"],
|
|
6639
|
+
["waiting", "status.waiting", "Waiting for feedback", "waiting", "warning"],
|
|
6640
|
+
["done", "status.done", "Done", "done", "info"],
|
|
6641
|
+
["canceled", "status.canceled", "Canceled", "canceled", "muted"],
|
|
6642
|
+
["duplicate", "status.duplicate", "Duplicate", "duplicate", "muted"]
|
|
6643
|
+
]);
|
|
6621
6644
|
var Select = class _Select extends Component {
|
|
6622
6645
|
static cssName = "select";
|
|
6623
6646
|
/** @type {SelectOptions} */
|
|
@@ -6628,6 +6651,10 @@ var Select = class _Select extends Component {
|
|
|
6628
6651
|
labelKey: "name",
|
|
6629
6652
|
renderItem: null,
|
|
6630
6653
|
renderValue: null,
|
|
6654
|
+
renderValueAdornment: null,
|
|
6655
|
+
renderNone: null,
|
|
6656
|
+
noneLabel: null,
|
|
6657
|
+
actions: [],
|
|
6631
6658
|
value: null,
|
|
6632
6659
|
disabled: false,
|
|
6633
6660
|
placeholder: "",
|
|
@@ -6645,6 +6672,7 @@ var Select = class _Select extends Component {
|
|
|
6645
6672
|
this._visibleItems = [];
|
|
6646
6673
|
this._fixedItems = [];
|
|
6647
6674
|
this._visibleFixed = [];
|
|
6675
|
+
this._actions = [];
|
|
6648
6676
|
this._selected = null;
|
|
6649
6677
|
this._optionEntries = [];
|
|
6650
6678
|
this._activeIndex = -1;
|
|
@@ -6683,6 +6711,12 @@ var Select = class _Select extends Component {
|
|
|
6683
6711
|
placeholder: String(this.options.placeholder ?? ""),
|
|
6684
6712
|
readOnly: !this.options.filter
|
|
6685
6713
|
});
|
|
6714
|
+
const valueAdornment = h("span", {
|
|
6715
|
+
ref: "valueAdornment",
|
|
6716
|
+
class: "zx-select__value-adornment",
|
|
6717
|
+
ariaHidden: "true",
|
|
6718
|
+
hidden: true
|
|
6719
|
+
});
|
|
6686
6720
|
const clear = h("button", {
|
|
6687
6721
|
ref: "clear",
|
|
6688
6722
|
class: "zx-icon-btn zx-select__clear",
|
|
@@ -6708,6 +6742,7 @@ var Select = class _Select extends Component {
|
|
|
6708
6742
|
const control = h(
|
|
6709
6743
|
"div",
|
|
6710
6744
|
{ ref: "control", class: "zx-select__control" },
|
|
6745
|
+
valueAdornment,
|
|
6711
6746
|
input,
|
|
6712
6747
|
clear,
|
|
6713
6748
|
loading,
|
|
@@ -6730,9 +6765,10 @@ var Select = class _Select extends Component {
|
|
|
6730
6765
|
this._visibleItems = this._items.slice();
|
|
6731
6766
|
this._fixedItems = Array.isArray(this.options.fixedItems) ? this.options.fixedItems.slice() : [];
|
|
6732
6767
|
this._visibleFixed = this._fixedItems.slice();
|
|
6768
|
+
this._actions = normalizeSelectActions(this.options.actions);
|
|
6733
6769
|
this._disabled = Boolean(this.options.disabled);
|
|
6734
6770
|
this._handleTypeahead = typeahead(
|
|
6735
|
-
() => this._optionEntries.filter((entry) => !entry.clear).map((entry) => entry.element),
|
|
6771
|
+
() => this._optionEntries.filter((entry) => !entry.clear && !entry.action).map((entry) => entry.element),
|
|
6736
6772
|
(_option, index) => {
|
|
6737
6773
|
if (!this._open) this.open();
|
|
6738
6774
|
this._setActive(this._itemEntryIndex(index));
|
|
@@ -6827,6 +6863,13 @@ var Select = class _Select extends Component {
|
|
|
6827
6863
|
this._position?.update();
|
|
6828
6864
|
return this;
|
|
6829
6865
|
}
|
|
6866
|
+
/** Replaces command rows without changing the selected value. @param {SelectAction[]} actions @returns {this} */
|
|
6867
|
+
setActions(actions2) {
|
|
6868
|
+
this._actions = normalizeSelectActions(actions2);
|
|
6869
|
+
this._renderOptions();
|
|
6870
|
+
this._position?.update();
|
|
6871
|
+
return this;
|
|
6872
|
+
}
|
|
6830
6873
|
/**
|
|
6831
6874
|
* Restores the configured initial value.
|
|
6832
6875
|
* @param {{silent?: boolean}} [options={}] Reset behavior.
|
|
@@ -6911,26 +6954,51 @@ var Select = class _Select extends Component {
|
|
|
6911
6954
|
value: null,
|
|
6912
6955
|
items: [],
|
|
6913
6956
|
renderItem(item) {
|
|
6914
|
-
return
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
class: "zx-select__priority-icon",
|
|
6919
|
-
dataset: { level: item.level },
|
|
6920
|
-
ariaHidden: "true"
|
|
6921
|
-
}),
|
|
6922
|
-
h("span", {}, String(item.name))
|
|
6923
|
-
);
|
|
6957
|
+
return priorityContent(item, true);
|
|
6958
|
+
},
|
|
6959
|
+
renderValueAdornment(item) {
|
|
6960
|
+
return priorityIndicator(item.level);
|
|
6924
6961
|
}
|
|
6925
6962
|
});
|
|
6926
|
-
select.setItems(PRIORITY_KEYS.map((key, level) =>
|
|
6927
|
-
|
|
6928
|
-
name
|
|
6929
|
-
level
|
|
6930
|
-
|
|
6963
|
+
select.setItems(PRIORITY_KEYS.map((key, level) => {
|
|
6964
|
+
let name = level === 2 ? select.msg("priority.medium") : key;
|
|
6965
|
+
if (name === "priority.medium") name = select._message(key, PRIORITY_FALLBACKS[level]);
|
|
6966
|
+
else if (level !== 2) name = select._message(key, PRIORITY_FALLBACKS[level]);
|
|
6967
|
+
return { ID: level, name, level };
|
|
6968
|
+
}));
|
|
6931
6969
|
select.set(requestedValue, { silent: true });
|
|
6932
6970
|
return select;
|
|
6933
6971
|
}
|
|
6972
|
+
/**
|
|
6973
|
+
* Creates a status picker with shape- and color-distinct workflow indicators.
|
|
6974
|
+
* @param {Element|string|null} target Component target.
|
|
6975
|
+
* @param {SelectOptions & {items?: Array<Record<string, any>>}} [options={}] Select overrides and status items.
|
|
6976
|
+
* @returns {Select}
|
|
6977
|
+
*/
|
|
6978
|
+
static status(target, options = {}) {
|
|
6979
|
+
const { items = null, value = null, ...rest } = options;
|
|
6980
|
+
const select = new _Select(target, {
|
|
6981
|
+
...rest,
|
|
6982
|
+
value: null,
|
|
6983
|
+
items: [],
|
|
6984
|
+
renderItem(item) {
|
|
6985
|
+
return statusContent(item);
|
|
6986
|
+
},
|
|
6987
|
+
renderValueAdornment(item) {
|
|
6988
|
+
return statusIndicator(item);
|
|
6989
|
+
}
|
|
6990
|
+
});
|
|
6991
|
+
const statuses = Array.isArray(items) ? items.map(normalizeStatusItem).filter(Boolean) : DEFAULT_STATUSES.map(([ID, key, fallback, indicator, tone], index) => ({
|
|
6992
|
+
ID,
|
|
6993
|
+
name: select._message(key, fallback),
|
|
6994
|
+
indicator,
|
|
6995
|
+
tone,
|
|
6996
|
+
shortcut: String(index + 1)
|
|
6997
|
+
}));
|
|
6998
|
+
select.setItems(statuses);
|
|
6999
|
+
select.set(value, { silent: true });
|
|
7000
|
+
return select;
|
|
7001
|
+
}
|
|
6934
7002
|
/**
|
|
6935
7003
|
* Creates the record-permission picker: the fixed Private and Public choices above the groups a
|
|
6936
7004
|
* record can be shared with. The value is the tri-state ZeyOS stores — `false` for private,
|
|
@@ -6943,12 +7011,21 @@ var Select = class _Select extends Component {
|
|
|
6943
7011
|
* @returns {Select}
|
|
6944
7012
|
*/
|
|
6945
7013
|
static permission(target, options = {}) {
|
|
6946
|
-
const {
|
|
7014
|
+
const {
|
|
7015
|
+
groups = [],
|
|
7016
|
+
value = true,
|
|
7017
|
+
valueKey = "ID",
|
|
7018
|
+
labelKey = "name",
|
|
7019
|
+
filter = "local",
|
|
7020
|
+
...rest
|
|
7021
|
+
} = options;
|
|
6947
7022
|
const loader = typeof groups === "function" ? groups : null;
|
|
6948
7023
|
const shareable = loader ? [] : groups;
|
|
6949
7024
|
const choices = [{ ID: false, name: "Private" }, { ID: true, name: "Public" }];
|
|
6950
7025
|
const select = new _Select(target, {
|
|
6951
|
-
|
|
7026
|
+
// An async group loader is the data source and cannot be disconnected by an incidental
|
|
7027
|
+
// `filter` override. Array-backed groups still honor local/disabled filtering.
|
|
7028
|
+
filter: loader ?? filter,
|
|
6952
7029
|
...rest,
|
|
6953
7030
|
value: null,
|
|
6954
7031
|
items: shareable,
|
|
@@ -6984,6 +7061,18 @@ var Select = class _Select extends Component {
|
|
|
6984
7061
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
6985
7062
|
_onKeydown(event) {
|
|
6986
7063
|
if (this._disabled) return;
|
|
7064
|
+
if (this._open && isPrintable(event)) {
|
|
7065
|
+
const shortcut = this._optionEntries.findIndex((entry) => !entry.clear && !entry.action && String(
|
|
7066
|
+
/** @type {Record<string, any>|null} */
|
|
7067
|
+
entry.item?.shortcut ?? ""
|
|
7068
|
+
) === event.key);
|
|
7069
|
+
if (shortcut >= 0) {
|
|
7070
|
+
event.preventDefault();
|
|
7071
|
+
this._setActive(shortcut);
|
|
7072
|
+
this._chooseEntry(this._optionEntries[shortcut]);
|
|
7073
|
+
return;
|
|
7074
|
+
}
|
|
7075
|
+
}
|
|
6987
7076
|
if (event.key === "ArrowDown") {
|
|
6988
7077
|
event.preventDefault();
|
|
6989
7078
|
if (!this._open) this.open();
|
|
@@ -7031,6 +7120,7 @@ var Select = class _Select extends Component {
|
|
|
7031
7120
|
/** @type {HTMLInputElement} */
|
|
7032
7121
|
this.refs.input.value
|
|
7033
7122
|
);
|
|
7123
|
+
this._syncValueAdornment();
|
|
7034
7124
|
if (!this._open) this.open();
|
|
7035
7125
|
if (this.options.filter === "local") {
|
|
7036
7126
|
this._visibleFixed = this._matchFixed(query);
|
|
@@ -7054,6 +7144,22 @@ var Select = class _Select extends Component {
|
|
|
7054
7144
|
/** @param {SelectOptionEntry|undefined} entry @returns {void} */
|
|
7055
7145
|
_chooseEntry(entry) {
|
|
7056
7146
|
if (!entry) return;
|
|
7147
|
+
if (entry.action) {
|
|
7148
|
+
const detail = {
|
|
7149
|
+
id: entry.action.id,
|
|
7150
|
+
action: entry.action,
|
|
7151
|
+
query: (
|
|
7152
|
+
/** @type {HTMLInputElement} */
|
|
7153
|
+
this.refs.input.value
|
|
7154
|
+
),
|
|
7155
|
+
select: this
|
|
7156
|
+
};
|
|
7157
|
+
const action = this.emit("action", detail);
|
|
7158
|
+
if (!action.defaultPrevented) entry.action.invoke?.(detail);
|
|
7159
|
+
this.close();
|
|
7160
|
+
this.focus();
|
|
7161
|
+
return;
|
|
7162
|
+
}
|
|
7057
7163
|
this.set(entry.clear ? null : entry.item);
|
|
7058
7164
|
this.close();
|
|
7059
7165
|
this.focus();
|
|
@@ -7087,7 +7193,7 @@ var Select = class _Select extends Component {
|
|
|
7087
7193
|
this._optionEntries = [];
|
|
7088
7194
|
let lastGroup = /* @__PURE__ */ Symbol("initial-group");
|
|
7089
7195
|
if (this.options.clearable) {
|
|
7090
|
-
this._appendOption(null, true, this.options.
|
|
7196
|
+
this._appendOption(null, true, this.options.noneLabel ?? this._message("select.none", "No selection"));
|
|
7091
7197
|
}
|
|
7092
7198
|
for (const item of this._visibleFixed) this._appendOption(item, false);
|
|
7093
7199
|
if (this._visibleFixed.length > 0 && this._visibleItems.length > 0 && !this.options.groupKey) {
|
|
@@ -7106,7 +7212,23 @@ var Select = class _Select extends Component {
|
|
|
7106
7212
|
}
|
|
7107
7213
|
this._appendOption(item, false);
|
|
7108
7214
|
}
|
|
7109
|
-
if (this.
|
|
7215
|
+
if (this._actions.length > 0) {
|
|
7216
|
+
if (this._visibleFixed.length > 0 || this._visibleItems.length > 0 || this.options.clearable) {
|
|
7217
|
+
list.append(h("div", { class: "zx-select__separator", role: "presentation" }));
|
|
7218
|
+
}
|
|
7219
|
+
let actionGroup = /* @__PURE__ */ Symbol("initial-action-group");
|
|
7220
|
+
for (const action of this._actions) {
|
|
7221
|
+
if (action.group && action.group !== actionGroup) {
|
|
7222
|
+
list.append(h("div", {
|
|
7223
|
+
class: "zx-select__group",
|
|
7224
|
+
role: "presentation"
|
|
7225
|
+
}, action.group));
|
|
7226
|
+
actionGroup = action.group;
|
|
7227
|
+
}
|
|
7228
|
+
this._appendAction(action);
|
|
7229
|
+
}
|
|
7230
|
+
}
|
|
7231
|
+
if (this._visibleItems.length === 0 && this._visibleFixed.length === 0 && this._actions.length === 0 && !this._loading) {
|
|
7110
7232
|
list.append(h("div", {
|
|
7111
7233
|
class: "zx-select__empty",
|
|
7112
7234
|
role: "status"
|
|
@@ -7118,7 +7240,7 @@ var Select = class _Select extends Component {
|
|
|
7118
7240
|
_appendOption(item, clear, label) {
|
|
7119
7241
|
const selected = clear ? this._selected === null : this._selected !== null && Object.is(this._itemValue(item), this.value);
|
|
7120
7242
|
const index = this._optionEntries.length;
|
|
7121
|
-
const content = clear ? String(label ?? "") : this._renderItem(item);
|
|
7243
|
+
const content = clear && typeof this.options.renderNone === "function" ? normalizeRenderedContent(this.options.renderNone(String(label ?? ""))) : clear ? String(label ?? "") : this._renderItem(item);
|
|
7122
7244
|
const option = h("div", {
|
|
7123
7245
|
class: "zx-select__option",
|
|
7124
7246
|
id: uid("zx-select-option"),
|
|
@@ -7128,16 +7250,37 @@ var Select = class _Select extends Component {
|
|
|
7128
7250
|
}, h("span", { class: "zx-select__option-content" }, content));
|
|
7129
7251
|
if (selected) option.append(icon("check", { size: 15 }));
|
|
7130
7252
|
this.refs.list.append(option);
|
|
7131
|
-
this._optionEntries.push({ item, clear, element: option });
|
|
7253
|
+
this._optionEntries.push({ item, clear, action: null, element: option });
|
|
7254
|
+
}
|
|
7255
|
+
/** @param {SelectAction} action @returns {void} */
|
|
7256
|
+
_appendAction(action) {
|
|
7257
|
+
const index = this._optionEntries.length;
|
|
7258
|
+
const visual = selectActionIcon(action.icon);
|
|
7259
|
+
const option = h("div", {
|
|
7260
|
+
class: "zx-select__option zx-select__action",
|
|
7261
|
+
id: uid("zx-select-option"),
|
|
7262
|
+
role: "option",
|
|
7263
|
+
ariaSelected: "false",
|
|
7264
|
+
dataset: { index, kind: "action" }
|
|
7265
|
+
}, h(
|
|
7266
|
+
"span",
|
|
7267
|
+
{ class: "zx-select__option-content zx-select__action-content" },
|
|
7268
|
+
visual ? h("span", { class: "zx-select__action-icon", ariaHidden: "true" }, visual) : null,
|
|
7269
|
+
h(
|
|
7270
|
+
"span",
|
|
7271
|
+
{ class: "zx-select__action-copy" },
|
|
7272
|
+
h("span", { class: "zx-select__action-label" }, action.label),
|
|
7273
|
+
action.description ? h("span", { class: "zx-select__action-description" }, action.description) : null
|
|
7274
|
+
)
|
|
7275
|
+
));
|
|
7276
|
+
this.refs.list.append(option);
|
|
7277
|
+
this._optionEntries.push({ item: null, clear: false, action, element: option });
|
|
7132
7278
|
}
|
|
7133
7279
|
/** @param {SelectItem|null} item @returns {Node|string} */
|
|
7134
7280
|
_renderItem(item) {
|
|
7135
7281
|
if (typeof this.options.renderItem === "function") {
|
|
7136
7282
|
const rendered = this.options.renderItem(item);
|
|
7137
|
-
return rendered
|
|
7138
|
-
/** @type {Node} */
|
|
7139
|
-
rendered
|
|
7140
|
-
) : String(rendered ?? "");
|
|
7283
|
+
return normalizeRenderedContent(rendered);
|
|
7141
7284
|
}
|
|
7142
7285
|
return this._itemLabel(item);
|
|
7143
7286
|
}
|
|
@@ -7208,9 +7351,29 @@ var Select = class _Select extends Component {
|
|
|
7208
7351
|
this.refs.input
|
|
7209
7352
|
);
|
|
7210
7353
|
input.value = this._selected === null ? "" : typeof this.options.renderValue === "function" ? String(this.options.renderValue(this._selected) ?? "") : this._itemLabel(this._selected);
|
|
7354
|
+
this._syncValueAdornment();
|
|
7211
7355
|
this.refs.clear.hidden = !this.options.clearable || this._selected === null;
|
|
7212
7356
|
}
|
|
7213
7357
|
/** @returns {void} */
|
|
7358
|
+
_syncValueAdornment() {
|
|
7359
|
+
const host = this.refs.valueAdornment;
|
|
7360
|
+
if (!host) return;
|
|
7361
|
+
const selectedLabel = this._selected === null ? "" : typeof this.options.renderValue === "function" ? String(this.options.renderValue(this._selected) ?? "") : this._itemLabel(this._selected);
|
|
7362
|
+
const query = String(
|
|
7363
|
+
/** @type {HTMLInputElement} */
|
|
7364
|
+
this.refs.input?.value ?? ""
|
|
7365
|
+
);
|
|
7366
|
+
if (this._selected === null || typeof this.options.renderValueAdornment !== "function" || Boolean(this.options.filter && query !== selectedLabel)) {
|
|
7367
|
+
host.replaceChildren();
|
|
7368
|
+
host.hidden = true;
|
|
7369
|
+
return;
|
|
7370
|
+
}
|
|
7371
|
+
const rendered = this.options.renderValueAdornment(this._selected);
|
|
7372
|
+
const content = normalizeRenderedContent(rendered);
|
|
7373
|
+
host.replaceChildren(content instanceof Node ? content : document.createTextNode(content));
|
|
7374
|
+
host.hidden = rendered == null || typeof content === "string" && content === "";
|
|
7375
|
+
}
|
|
7376
|
+
/** @returns {void} */
|
|
7214
7377
|
_syncDisabled() {
|
|
7215
7378
|
const input = (
|
|
7216
7379
|
/** @type {HTMLInputElement} */
|
|
@@ -7287,6 +7450,82 @@ var Select = class _Select extends Component {
|
|
|
7287
7450
|
return message === key ? fallback : message;
|
|
7288
7451
|
}
|
|
7289
7452
|
};
|
|
7453
|
+
function normalizeRenderedContent(rendered) {
|
|
7454
|
+
return rendered && typeof rendered === "object" && "nodeType" in rendered ? (
|
|
7455
|
+
/** @type {Node} */
|
|
7456
|
+
rendered
|
|
7457
|
+
) : String(rendered ?? "");
|
|
7458
|
+
}
|
|
7459
|
+
function normalizeSelectActions(actions2) {
|
|
7460
|
+
if (!Array.isArray(actions2)) return [];
|
|
7461
|
+
return actions2.filter((action) => action && typeof action === "object" && action.id != null && action.label != null).map((action) => ({
|
|
7462
|
+
...action,
|
|
7463
|
+
label: String(action.label),
|
|
7464
|
+
description: action.description == null ? void 0 : String(action.description),
|
|
7465
|
+
group: action.group == null ? void 0 : String(action.group)
|
|
7466
|
+
}));
|
|
7467
|
+
}
|
|
7468
|
+
function selectActionIcon(visual) {
|
|
7469
|
+
if (typeof visual === "string") return icon(visual);
|
|
7470
|
+
if (visual instanceof Node) return visual.cloneNode(true);
|
|
7471
|
+
return null;
|
|
7472
|
+
}
|
|
7473
|
+
function priorityContent(item, label) {
|
|
7474
|
+
return h(
|
|
7475
|
+
"span",
|
|
7476
|
+
{ class: "zx-select__priority" },
|
|
7477
|
+
priorityIndicator(item.level),
|
|
7478
|
+
label ? h("span", {}, String(item.name)) : null
|
|
7479
|
+
);
|
|
7480
|
+
}
|
|
7481
|
+
function priorityIndicator(level) {
|
|
7482
|
+
const normalized = Math.max(0, Math.min(4, Math.trunc(Number(level) || 0)));
|
|
7483
|
+
return h("span", {
|
|
7484
|
+
class: "zx-select__priority-icon",
|
|
7485
|
+
dataset: { level: normalized },
|
|
7486
|
+
ariaHidden: "true"
|
|
7487
|
+
}, Array.from({ length: 5 }, (_, index) => h("span", {
|
|
7488
|
+
dataset: { filled: String(index <= normalized) }
|
|
7489
|
+
})));
|
|
7490
|
+
}
|
|
7491
|
+
function normalizeStatusItem(input) {
|
|
7492
|
+
if (!input || typeof input !== "object" || input.ID == null || input.name == null) return null;
|
|
7493
|
+
const indicators = ["dotted", "ring", "progress", "review", "ready", "waiting", "done", "canceled", "duplicate"];
|
|
7494
|
+
const tones = ["muted", "neutral", "warning", "info", "accent", "success", "danger"];
|
|
7495
|
+
return {
|
|
7496
|
+
...input,
|
|
7497
|
+
name: String(input.name),
|
|
7498
|
+
indicator: indicators.includes(String(input.indicator)) ? String(input.indicator) : "ring",
|
|
7499
|
+
tone: tones.includes(String(input.tone)) ? String(input.tone) : "muted",
|
|
7500
|
+
description: input.description == null ? "" : String(input.description),
|
|
7501
|
+
shortcut: input.shortcut == null ? "" : String(input.shortcut)
|
|
7502
|
+
};
|
|
7503
|
+
}
|
|
7504
|
+
function statusContent(item) {
|
|
7505
|
+
return h(
|
|
7506
|
+
"span",
|
|
7507
|
+
{ class: "zx-select__status" },
|
|
7508
|
+
statusIndicator(item),
|
|
7509
|
+
h(
|
|
7510
|
+
"span",
|
|
7511
|
+
{ class: "zx-select__status-copy" },
|
|
7512
|
+
h("span", { class: "zx-select__status-label" }, String(item.name)),
|
|
7513
|
+
item.description ? h("span", { class: "zx-select__status-description" }, item.description) : null
|
|
7514
|
+
),
|
|
7515
|
+
item.shortcut ? h("kbd", { class: "zx-select__status-shortcut" }, item.shortcut) : null
|
|
7516
|
+
);
|
|
7517
|
+
}
|
|
7518
|
+
function statusIndicator(item) {
|
|
7519
|
+
const indicator = String(item.indicator ?? "ring");
|
|
7520
|
+
const marker = h("span", {
|
|
7521
|
+
class: "zx-select__status-indicator",
|
|
7522
|
+
dataset: { indicator, tone: String(item.tone ?? "muted") },
|
|
7523
|
+
ariaHidden: "true"
|
|
7524
|
+
});
|
|
7525
|
+
if (indicator === "done") marker.append(icon("check", { size: 8 }));
|
|
7526
|
+
if (indicator === "canceled") marker.append(icon("x", { size: 7 }));
|
|
7527
|
+
return marker;
|
|
7528
|
+
}
|
|
7290
7529
|
function readItem(item, reader) {
|
|
7291
7530
|
if (typeof reader === "function") return reader(item);
|
|
7292
7531
|
if (item === null || typeof item !== "object") return item;
|
|
@@ -7299,10 +7538,11 @@ function isPrintable(event) {
|
|
|
7299
7538
|
// src/components/select/field-adapter.js
|
|
7300
7539
|
function registerSelectFieldAdapter() {
|
|
7301
7540
|
Field.register("zxselect", (field, options) => {
|
|
7302
|
-
const
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7541
|
+
const props = options.props ?? {};
|
|
7542
|
+
const preset = props.preset;
|
|
7543
|
+
const selectOptions = { ...props, value: options.value };
|
|
7544
|
+
delete selectOptions.preset;
|
|
7545
|
+
const select = field.own(preset === "priority" ? Select.priority(null, selectOptions) : preset === "status" ? Select.status(null, selectOptions) : new Select(null, selectOptions));
|
|
7306
7546
|
field.listen(select.el, "change", (event) => event.stopImmediatePropagation());
|
|
7307
7547
|
select.on("change", (event) => field.emit("change", { value: event.detail.value }));
|
|
7308
7548
|
return {
|
|
@@ -11249,12 +11489,14 @@ var Table = class extends Component {
|
|
|
11249
11489
|
}
|
|
11250
11490
|
/** @returns {HTMLElement} Table root. */
|
|
11251
11491
|
render() {
|
|
11492
|
+
const created = this.el === null;
|
|
11252
11493
|
const root = (
|
|
11253
11494
|
/** @type {HTMLElement} */
|
|
11254
11495
|
this.el ?? h("div")
|
|
11255
11496
|
);
|
|
11256
11497
|
this.el = root;
|
|
11257
|
-
this.
|
|
11498
|
+
this._createdRoot = created;
|
|
11499
|
+
this._original = created ? null : snapshotTarget(root);
|
|
11258
11500
|
this._columns = Array.isArray(this.options.columns) ? this.options.columns.map((column) => ({ ...column })) : [];
|
|
11259
11501
|
this._data = Array.isArray(this.options.data) ? [...this.options.data] : [];
|
|
11260
11502
|
this._selected = /* @__PURE__ */ new Set();
|
|
@@ -11329,8 +11571,8 @@ var Table = class extends Component {
|
|
|
11329
11571
|
}
|
|
11330
11572
|
/**
|
|
11331
11573
|
* Toggles a loading state. While loading, the body is dimmed, an indeterminate progress bar is
|
|
11332
|
-
* shown, and `aria-busy` is set — a lightweight
|
|
11333
|
-
*
|
|
11574
|
+
* shown, and `aria-busy` is set — a lightweight enterprise-table busy and skeleton pattern.
|
|
11575
|
+
* Call `setLoading(false)` (or `setData`) when done.
|
|
11334
11576
|
* @param {boolean} [loading=true] Whether the table is loading.
|
|
11335
11577
|
* @returns {this}
|
|
11336
11578
|
*/
|
|
@@ -11879,9 +12121,8 @@ var Table = class extends Component {
|
|
|
11879
12121
|
this._teardownEdit();
|
|
11880
12122
|
this._width?.destroy();
|
|
11881
12123
|
this._width = null;
|
|
11882
|
-
if (this.
|
|
11883
|
-
|
|
11884
|
-
this.el.replaceChildren(...this._originalChildren);
|
|
12124
|
+
if (!this._restored && !this._createdRoot) {
|
|
12125
|
+
restoreTarget(this.el, this._original);
|
|
11885
12126
|
this._restored = true;
|
|
11886
12127
|
}
|
|
11887
12128
|
super.destroy();
|
|
@@ -15242,6 +15483,244 @@ function normalizeAlign2(value) {
|
|
|
15242
15483
|
) : "start";
|
|
15243
15484
|
}
|
|
15244
15485
|
|
|
15486
|
+
// src/components/card/card.js
|
|
15487
|
+
var Card = class extends Component {
|
|
15488
|
+
static cssName = "card";
|
|
15489
|
+
/** @type {Readonly<CardOptions>} */
|
|
15490
|
+
static defaults = {
|
|
15491
|
+
title: "",
|
|
15492
|
+
media: null,
|
|
15493
|
+
content: null,
|
|
15494
|
+
actions: [],
|
|
15495
|
+
footer: null,
|
|
15496
|
+
link: null,
|
|
15497
|
+
variant: "outlined",
|
|
15498
|
+
orientation: "vertical",
|
|
15499
|
+
headingLevel: 3
|
|
15500
|
+
};
|
|
15501
|
+
/**
|
|
15502
|
+
* Creates or enhances one card.
|
|
15503
|
+
* @param {Element|string|null} [target=null] Existing card container, selector, or null.
|
|
15504
|
+
* @param {CardOptions} [options={}] Card options.
|
|
15505
|
+
*/
|
|
15506
|
+
constructor(target = null, options = {}) {
|
|
15507
|
+
super(target, options);
|
|
15508
|
+
}
|
|
15509
|
+
/** @returns {HTMLElement} */
|
|
15510
|
+
render() {
|
|
15511
|
+
const created = !this.el;
|
|
15512
|
+
const root = (
|
|
15513
|
+
/** @type {HTMLElement} */
|
|
15514
|
+
this.el ?? h("article")
|
|
15515
|
+
);
|
|
15516
|
+
this.el = root;
|
|
15517
|
+
this._createdRoot = created;
|
|
15518
|
+
this._original = created ? null : snapshotTarget(root);
|
|
15519
|
+
this._cleaned = false;
|
|
15520
|
+
this._title = "";
|
|
15521
|
+
this._link = null;
|
|
15522
|
+
this._actionAbort = null;
|
|
15523
|
+
this._linkAbort = null;
|
|
15524
|
+
const originalContent = created ? [] : Array.from(root.childNodes);
|
|
15525
|
+
try {
|
|
15526
|
+
const headingLevel = normalizeHeadingLevel(this.options.headingLevel);
|
|
15527
|
+
const headingId = uid("zx-card-heading");
|
|
15528
|
+
const heading = h(`h${headingLevel}`, {
|
|
15529
|
+
ref: "heading",
|
|
15530
|
+
class: "zx-card__heading",
|
|
15531
|
+
id: headingId
|
|
15532
|
+
});
|
|
15533
|
+
const media = h("div", { ref: "media", class: "zx-card__media", hidden: true });
|
|
15534
|
+
const actions2 = h("div", {
|
|
15535
|
+
ref: "actions",
|
|
15536
|
+
class: "zx-card__actions",
|
|
15537
|
+
role: "group",
|
|
15538
|
+
ariaLabel: "Card actions",
|
|
15539
|
+
hidden: true
|
|
15540
|
+
});
|
|
15541
|
+
const content = h("div", { ref: "content", class: "zx-card__content", hidden: true });
|
|
15542
|
+
const footer = h("footer", { ref: "footer", class: "zx-card__footer", hidden: true });
|
|
15543
|
+
const header = h("header", { ref: "header", class: "zx-card__header" }, heading, actions2);
|
|
15544
|
+
root.replaceChildren(h(
|
|
15545
|
+
"div",
|
|
15546
|
+
{ class: "zx-card__layout" },
|
|
15547
|
+
media,
|
|
15548
|
+
h("div", { class: "zx-card__inner" }, header, content, footer)
|
|
15549
|
+
));
|
|
15550
|
+
root.dataset.variant = normalizeVariant2(this.options.variant);
|
|
15551
|
+
root.dataset.orientation = normalizeOrientation(this.options.orientation);
|
|
15552
|
+
this.setTitle(this.options.title);
|
|
15553
|
+
this.setMedia(this.options.media);
|
|
15554
|
+
if (this.options.content !== null) this.setContent(this.options.content);
|
|
15555
|
+
else if (originalContent.length) {
|
|
15556
|
+
content.replaceChildren(...originalContent);
|
|
15557
|
+
content.hidden = false;
|
|
15558
|
+
}
|
|
15559
|
+
this.setActions(this.options.actions);
|
|
15560
|
+
this.setFooter(this.options.footer);
|
|
15561
|
+
this.setLink(this.options.link);
|
|
15562
|
+
return root;
|
|
15563
|
+
} catch (error) {
|
|
15564
|
+
this._actionAbort?.abort();
|
|
15565
|
+
this._linkAbort?.abort();
|
|
15566
|
+
if (!created) restoreTarget(root, this._original);
|
|
15567
|
+
throw error;
|
|
15568
|
+
}
|
|
15569
|
+
}
|
|
15570
|
+
/** Replaces the card title. @param {string} title Next title. @returns {this} */
|
|
15571
|
+
setTitle(title) {
|
|
15572
|
+
const next = String(title ?? "");
|
|
15573
|
+
if (this._link && !next.trim()) throw new TypeError("A linked Card requires a non-empty title");
|
|
15574
|
+
this._title = next;
|
|
15575
|
+
this._renderHeading();
|
|
15576
|
+
return this;
|
|
15577
|
+
}
|
|
15578
|
+
/** Replaces or removes the media region. @param {CardContent} content Media. @returns {this} */
|
|
15579
|
+
setMedia(content) {
|
|
15580
|
+
replaceCardContent(this.refs.media, content, "Card media");
|
|
15581
|
+
this.refs.media.hidden = content === null;
|
|
15582
|
+
return this;
|
|
15583
|
+
}
|
|
15584
|
+
/** Replaces or clears the main content. @param {CardContent} content Content. @returns {this} */
|
|
15585
|
+
setContent(content) {
|
|
15586
|
+
replaceCardContent(this.refs.content, content, "Card content");
|
|
15587
|
+
this.refs.content.hidden = content === null;
|
|
15588
|
+
return this;
|
|
15589
|
+
}
|
|
15590
|
+
/** Replaces the secondary action controls. @param {CardAction[]} actions Actions. @returns {this} */
|
|
15591
|
+
setActions(actions2) {
|
|
15592
|
+
if (!Array.isArray(actions2)) throw new TypeError("Card actions must be an array");
|
|
15593
|
+
const nextAbort = new AbortController();
|
|
15594
|
+
let controls;
|
|
15595
|
+
try {
|
|
15596
|
+
controls = actions2.map((action) => {
|
|
15597
|
+
if (isElement(action)) return action;
|
|
15598
|
+
if (!action || typeof action !== "object" || Array.isArray(action)) {
|
|
15599
|
+
throw new TypeError("Card actions must be Elements or button descriptors");
|
|
15600
|
+
}
|
|
15601
|
+
const descriptor = { ...action };
|
|
15602
|
+
const onclick = descriptor.onclick;
|
|
15603
|
+
delete descriptor.onclick;
|
|
15604
|
+
const control = button(descriptor);
|
|
15605
|
+
if (onclick !== void 0 && typeof onclick !== "function") {
|
|
15606
|
+
throw new TypeError("Card action onclick must be a function");
|
|
15607
|
+
}
|
|
15608
|
+
if (onclick) control.addEventListener("click", onclick, { signal: nextAbort.signal });
|
|
15609
|
+
return control;
|
|
15610
|
+
});
|
|
15611
|
+
} catch (error) {
|
|
15612
|
+
nextAbort.abort();
|
|
15613
|
+
throw error;
|
|
15614
|
+
}
|
|
15615
|
+
this._actionAbort?.abort();
|
|
15616
|
+
this._actionAbort = nextAbort;
|
|
15617
|
+
this.refs.actions.replaceChildren(...controls);
|
|
15618
|
+
this.refs.actions.hidden = controls.length === 0;
|
|
15619
|
+
this._syncHeader();
|
|
15620
|
+
return this;
|
|
15621
|
+
}
|
|
15622
|
+
/** Replaces or removes the footer. @param {CardContent} content Footer. @returns {this} */
|
|
15623
|
+
setFooter(content) {
|
|
15624
|
+
replaceCardContent(this.refs.footer, content, "Card footer");
|
|
15625
|
+
this.refs.footer.hidden = content === null;
|
|
15626
|
+
return this;
|
|
15627
|
+
}
|
|
15628
|
+
/** Sets or removes the title's native primary link. @param {CardLink} link Link. @returns {this} */
|
|
15629
|
+
setLink(link) {
|
|
15630
|
+
const next = normalizeCardLink(link);
|
|
15631
|
+
if (next && !this._title.trim()) throw new TypeError("A linked Card requires a non-empty title");
|
|
15632
|
+
this._link = next;
|
|
15633
|
+
this.el.dataset.linked = next ? "true" : "false";
|
|
15634
|
+
this._renderHeading();
|
|
15635
|
+
return this;
|
|
15636
|
+
}
|
|
15637
|
+
/** Restores an enhanced target exactly, or removes an owned card. @returns {void} */
|
|
15638
|
+
destroy() {
|
|
15639
|
+
if (this._cleaned) return;
|
|
15640
|
+
this._cleaned = true;
|
|
15641
|
+
this._actionAbort?.abort();
|
|
15642
|
+
this._linkAbort?.abort();
|
|
15643
|
+
super.destroy();
|
|
15644
|
+
if (!this._createdRoot) restoreTarget(this.el, this._original);
|
|
15645
|
+
}
|
|
15646
|
+
/** @returns {void} */
|
|
15647
|
+
_renderHeading() {
|
|
15648
|
+
const title = this._title;
|
|
15649
|
+
const nextAbort = new AbortController();
|
|
15650
|
+
const node = this._link ? h("a", {
|
|
15651
|
+
class: "zx-card__primary",
|
|
15652
|
+
href: this._link.href,
|
|
15653
|
+
target: this._link.target,
|
|
15654
|
+
rel: this._link.rel
|
|
15655
|
+
}, title) : h("span", { class: "zx-card__title" }, title);
|
|
15656
|
+
if (this._link?.onclick) node.addEventListener("click", this._link.onclick, { signal: nextAbort.signal });
|
|
15657
|
+
this._linkAbort?.abort();
|
|
15658
|
+
this._linkAbort = nextAbort;
|
|
15659
|
+
this.refs.heading.replaceChildren(node);
|
|
15660
|
+
this.refs.heading.hidden = title === "";
|
|
15661
|
+
if (title) this.el.setAttribute("aria-labelledby", this.refs.heading.id);
|
|
15662
|
+
else this.el.removeAttribute("aria-labelledby");
|
|
15663
|
+
this._syncHeader();
|
|
15664
|
+
}
|
|
15665
|
+
/** @returns {void} */
|
|
15666
|
+
_syncHeader() {
|
|
15667
|
+
if (!this.refs.header) return;
|
|
15668
|
+
this.refs.header.hidden = this._title === "" && this.refs.actions.childElementCount === 0;
|
|
15669
|
+
}
|
|
15670
|
+
};
|
|
15671
|
+
function replaceCardContent(host, content, label) {
|
|
15672
|
+
if (content === null) {
|
|
15673
|
+
host.replaceChildren();
|
|
15674
|
+
return;
|
|
15675
|
+
}
|
|
15676
|
+
if (typeof content === "string") {
|
|
15677
|
+
host.textContent = content;
|
|
15678
|
+
return;
|
|
15679
|
+
}
|
|
15680
|
+
const node = content instanceof Component ? content.toElement() : content;
|
|
15681
|
+
if (node instanceof Node) {
|
|
15682
|
+
host.replaceChildren(node);
|
|
15683
|
+
return;
|
|
15684
|
+
}
|
|
15685
|
+
throw new TypeError(`${label} must be a string, Node, Component, or null`);
|
|
15686
|
+
}
|
|
15687
|
+
function normalizeCardLink(value) {
|
|
15688
|
+
if (value === null) return null;
|
|
15689
|
+
const descriptor = typeof value === "string" ? { href: value } : value;
|
|
15690
|
+
if (!descriptor || typeof descriptor !== "object" || Array.isArray(descriptor)) {
|
|
15691
|
+
throw new TypeError("Card link must be a URL string, descriptor, or null");
|
|
15692
|
+
}
|
|
15693
|
+
const href = safeHref(descriptor.href);
|
|
15694
|
+
if (href === null) {
|
|
15695
|
+
throw new TypeError("Card link requires a safe non-empty href");
|
|
15696
|
+
}
|
|
15697
|
+
if (descriptor.onclick !== void 0 && typeof descriptor.onclick !== "function") {
|
|
15698
|
+
throw new TypeError("Card link onclick must be a function");
|
|
15699
|
+
}
|
|
15700
|
+
const target = descriptor.target == null ? void 0 : String(descriptor.target);
|
|
15701
|
+
let rel = descriptor.rel == null ? "" : String(descriptor.rel).trim();
|
|
15702
|
+
if (target === "_blank" && !/(^|\s)noopener(\s|$)/i.test(rel)) {
|
|
15703
|
+
rel = `${rel} noopener`.trim();
|
|
15704
|
+
}
|
|
15705
|
+
return { href, target, rel: rel || void 0, onclick: descriptor.onclick };
|
|
15706
|
+
}
|
|
15707
|
+
function normalizeVariant2(value) {
|
|
15708
|
+
return ["raised", "filled"].includes(String(value)) ? (
|
|
15709
|
+
/** @type {'raised'|'filled'} */
|
|
15710
|
+
value
|
|
15711
|
+
) : "outlined";
|
|
15712
|
+
}
|
|
15713
|
+
function normalizeOrientation(value) {
|
|
15714
|
+
return value === "horizontal" ? "horizontal" : "vertical";
|
|
15715
|
+
}
|
|
15716
|
+
function normalizeHeadingLevel(value) {
|
|
15717
|
+
const level = Math.trunc(Number(value));
|
|
15718
|
+
return (
|
|
15719
|
+
/** @type {1|2|3|4|5|6} */
|
|
15720
|
+
level >= 1 && level <= 6 ? level : 3
|
|
15721
|
+
);
|
|
15722
|
+
}
|
|
15723
|
+
|
|
15245
15724
|
// src/components/panel/panel.js
|
|
15246
15725
|
var Panel = class extends Component {
|
|
15247
15726
|
static cssName = "panel";
|
|
@@ -18585,9 +19064,12 @@ var Launcher = class extends Component {
|
|
|
18585
19064
|
maxResults: 100,
|
|
18586
19065
|
placeholder: "Search applications and records",
|
|
18587
19066
|
label: "Launcher",
|
|
19067
|
+
closeLabel: "Close launcher",
|
|
19068
|
+
resultsLabel: "Launcher results",
|
|
18588
19069
|
emptyText: "No results",
|
|
18589
19070
|
loadingText: "Searching\u2026",
|
|
18590
|
-
shortcut: "mod+k"
|
|
19071
|
+
shortcut: "mod+k",
|
|
19072
|
+
hints: { move: "Move", open: "Open", close: "Close" }
|
|
18591
19073
|
};
|
|
18592
19074
|
/**
|
|
18593
19075
|
* Creates an owned launcher dialog or enhances an existing `<dialog>` target.
|
|
@@ -18616,6 +19098,7 @@ var Launcher = class extends Component {
|
|
|
18616
19098
|
this._sources = normalizeSources(this.options.sources);
|
|
18617
19099
|
this._sourceItems = /* @__PURE__ */ new Map();
|
|
18618
19100
|
this._query = String(this.options.query ?? "");
|
|
19101
|
+
this._renderedQuery = null;
|
|
18619
19102
|
this._results = [];
|
|
18620
19103
|
this._active = -1;
|
|
18621
19104
|
this._request = null;
|
|
@@ -18642,7 +19125,7 @@ var Launcher = class extends Component {
|
|
|
18642
19125
|
ref: "close",
|
|
18643
19126
|
class: "zx-icon-btn zx-launcher__close",
|
|
18644
19127
|
type: "button",
|
|
18645
|
-
ariaLabel:
|
|
19128
|
+
ariaLabel: this.options.closeLabel
|
|
18646
19129
|
}, icon("x"));
|
|
18647
19130
|
const status = h("div", {
|
|
18648
19131
|
ref: "status",
|
|
@@ -18655,16 +19138,25 @@ var Launcher = class extends Component {
|
|
|
18655
19138
|
class: "zx-launcher__results",
|
|
18656
19139
|
id: listId,
|
|
18657
19140
|
role: "listbox",
|
|
18658
|
-
ariaLabel:
|
|
19141
|
+
ariaLabel: this.options.resultsLabel
|
|
18659
19142
|
});
|
|
19143
|
+
const shortcut = this.options.shortcut === "mod+k" ? h("kbd", {
|
|
19144
|
+
class: "zx-launcher__shortcut",
|
|
19145
|
+
ariaHidden: "true"
|
|
19146
|
+
}, launcherShortcutLabel()) : null;
|
|
19147
|
+
const footer = launcherHints(this.options.hints);
|
|
18660
19148
|
dialog.setAttribute("aria-label", String(this.options.label));
|
|
18661
19149
|
dialog.replaceChildren(
|
|
18662
19150
|
h(
|
|
18663
19151
|
"div",
|
|
18664
19152
|
{ class: "zx-launcher__surface" },
|
|
18665
|
-
h("div", {
|
|
19153
|
+
h("div", {
|
|
19154
|
+
class: "zx-launcher__search",
|
|
19155
|
+
dataset: { shortcut: shortcut ? "true" : "false" }
|
|
19156
|
+
}, icon("search"), input, shortcut, close),
|
|
18666
19157
|
status,
|
|
18667
|
-
results
|
|
19158
|
+
results,
|
|
19159
|
+
footer
|
|
18668
19160
|
)
|
|
18669
19161
|
);
|
|
18670
19162
|
dialog.dataset.state = "closed";
|
|
@@ -18688,6 +19180,17 @@ var Launcher = class extends Component {
|
|
|
18688
19180
|
if (!option || !results.contains(option)) return;
|
|
18689
19181
|
this._activate(Number(option.getAttribute("data-launcher-index")), event);
|
|
18690
19182
|
});
|
|
19183
|
+
this.listen(results, "pointermove", (event) => {
|
|
19184
|
+
const option = (
|
|
19185
|
+
/** @type {Element|null} */
|
|
19186
|
+
event.target?.closest?.("[data-launcher-index]")
|
|
19187
|
+
);
|
|
19188
|
+
if (!option || !results.contains(option)) return;
|
|
19189
|
+
const index = Number(option.getAttribute("data-launcher-index"));
|
|
19190
|
+
if (!Number.isInteger(index) || this._results[index]?.disabled || index === this._active) return;
|
|
19191
|
+
this._active = index;
|
|
19192
|
+
this._syncActive();
|
|
19193
|
+
});
|
|
18691
19194
|
this.listen(dialog, "cancel", (event) => {
|
|
18692
19195
|
event.preventDefault();
|
|
18693
19196
|
this.close();
|
|
@@ -18757,6 +19260,13 @@ var Launcher = class extends Component {
|
|
|
18757
19260
|
this._renderResults();
|
|
18758
19261
|
return this;
|
|
18759
19262
|
}
|
|
19263
|
+
/** Marks one local item as the current destination. @param {string|number|null} id Item id. @returns {this} */
|
|
19264
|
+
setCurrent(id) {
|
|
19265
|
+
const key = id == null ? null : String(id);
|
|
19266
|
+
this._items = this._items.map((item) => ({ ...item, current: key !== null && String(item.id) === key }));
|
|
19267
|
+
this._renderResults();
|
|
19268
|
+
return this;
|
|
19269
|
+
}
|
|
18760
19270
|
/** Replaces asynchronous sources and aborts work from the old set. @param {LauncherSource[]} sources @returns {this} */
|
|
18761
19271
|
setSources(sources) {
|
|
18762
19272
|
this._abortRequest();
|
|
@@ -18792,7 +19302,7 @@ var Launcher = class extends Component {
|
|
|
18792
19302
|
async _loadSources() {
|
|
18793
19303
|
this._queryTimer = null;
|
|
18794
19304
|
const query = this._query.trim();
|
|
18795
|
-
const sources = this._sources.filter((source) => query.length >= Math.max(Number(this.options.minQuery) || 0, Number(source.minQuery) || 0));
|
|
19305
|
+
const sources = this._sources.filter((source) => visibleForQuery(source.when, query) && query.length >= Math.max(Number(this.options.minQuery) || 0, Number(source.minQuery) || 0));
|
|
18796
19306
|
if (sources.length === 0) return;
|
|
18797
19307
|
const request = new AbortController();
|
|
18798
19308
|
const sequence = ++this._requestSequence;
|
|
@@ -18802,10 +19312,12 @@ var Launcher = class extends Component {
|
|
|
18802
19312
|
try {
|
|
18803
19313
|
const loaded = await source.load(query, { signal: request.signal });
|
|
18804
19314
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
18805
|
-
this._sourceItems.set(source.id, normalizeItems2(loaded).map((item) => ({
|
|
19315
|
+
this._sourceItems.set(source.id, normalizeItems2(loaded).map((item, itemOrder) => ({
|
|
18806
19316
|
...item,
|
|
18807
19317
|
_source: source.id,
|
|
18808
|
-
|
|
19318
|
+
_sourceOrder: source.order === "source",
|
|
19319
|
+
group: item.group ?? source.label ?? "",
|
|
19320
|
+
itemOrder: item.itemOrder ?? (source.order === "source" ? itemOrder : void 0)
|
|
18809
19321
|
})));
|
|
18810
19322
|
this._renderResults();
|
|
18811
19323
|
} catch (error) {
|
|
@@ -18834,23 +19346,36 @@ var Launcher = class extends Component {
|
|
|
18834
19346
|
}
|
|
18835
19347
|
/** @returns {void} */
|
|
18836
19348
|
_renderResults() {
|
|
18837
|
-
const
|
|
19349
|
+
const queryKey = this._query;
|
|
19350
|
+
const activeId = this._renderedQuery === queryKey && this._active >= 0 && this._results[this._active] ? String(this._results[this._active].id) : null;
|
|
19351
|
+
const query = this._query.trim();
|
|
19352
|
+
const local = this._items.filter((item) => visibleForQuery(item.when, query));
|
|
19353
|
+
const rankedLocal = rankLauncherItems(local, query, this.options.maxResults);
|
|
19354
|
+
const remote = this._sources.flatMap((source) => {
|
|
19355
|
+
const loaded = this._sourceItems.get(String(source.id)) ?? [];
|
|
19356
|
+
return source.order === "source" ? loaded.filter((item) => visibleForQuery(item.when, query)) : rankLauncherItems(
|
|
19357
|
+
loaded.filter((item) => visibleForQuery(item.when, query)),
|
|
19358
|
+
query,
|
|
19359
|
+
this.options.maxResults
|
|
19360
|
+
);
|
|
19361
|
+
});
|
|
18838
19362
|
const seen = /* @__PURE__ */ new Set();
|
|
18839
|
-
const combined = [...
|
|
19363
|
+
const combined = [...rankedLocal.map((item) => ({ ...item, _source: null })), ...remote].filter((item) => {
|
|
18840
19364
|
const key = String(item.id);
|
|
18841
19365
|
if (seen.has(key)) return false;
|
|
18842
19366
|
seen.add(key);
|
|
18843
19367
|
return true;
|
|
18844
|
-
});
|
|
18845
|
-
const ranked = rankLauncherItems(combined, this._query, this.options.maxResults);
|
|
19368
|
+
}).slice(0, Math.max(0, Number(this.options.maxResults) || 0));
|
|
18846
19369
|
const groups = /* @__PURE__ */ new Map();
|
|
18847
|
-
for (const item of
|
|
19370
|
+
for (const item of combined) {
|
|
18848
19371
|
const group = String(item.group ?? "");
|
|
18849
19372
|
if (!groups.has(group)) groups.set(group, []);
|
|
18850
19373
|
groups.get(group).push(item);
|
|
18851
19374
|
}
|
|
18852
19375
|
this._results = [...groups.values()].flat();
|
|
18853
|
-
this.
|
|
19376
|
+
this._renderedQuery = queryKey;
|
|
19377
|
+
const preserved = activeId === null ? -1 : this._results.findIndex((item) => !item.disabled && String(item.id) === activeId);
|
|
19378
|
+
this._active = preserved >= 0 ? preserved : this._results.findIndex((item) => !item.disabled);
|
|
18854
19379
|
const nodes = [];
|
|
18855
19380
|
let index = 0;
|
|
18856
19381
|
for (const [group, items] of groups) {
|
|
@@ -18858,7 +19383,8 @@ var Launcher = class extends Component {
|
|
|
18858
19383
|
if (group) nodes.push(h("div", {
|
|
18859
19384
|
class: "zx-launcher__group",
|
|
18860
19385
|
role: "group",
|
|
18861
|
-
ariaLabel: group
|
|
19386
|
+
ariaLabel: group,
|
|
19387
|
+
dataset: { layout: items.every((item) => item.kind === "application") ? "grid" : "list" }
|
|
18862
19388
|
}, h("div", { class: "zx-launcher__group-label", ariaHidden: "true" }, group), options));
|
|
18863
19389
|
else nodes.push(...options);
|
|
18864
19390
|
}
|
|
@@ -18868,9 +19394,14 @@ var Launcher = class extends Component {
|
|
|
18868
19394
|
}
|
|
18869
19395
|
/** @param {RankedLauncherItem} item @param {number} index @returns {HTMLElement} */
|
|
18870
19396
|
_option(item, index) {
|
|
18871
|
-
const
|
|
19397
|
+
const href = safeHref(item.href);
|
|
19398
|
+
const tag = href ? "a" : "button";
|
|
18872
19399
|
const children = [];
|
|
18873
|
-
|
|
19400
|
+
const visual = launcherItemIcon(item);
|
|
19401
|
+
if (visual) children.push(h("span", {
|
|
19402
|
+
class: "zx-launcher__icon",
|
|
19403
|
+
ariaHidden: "true"
|
|
19404
|
+
}, visual));
|
|
18874
19405
|
children.push(h(
|
|
18875
19406
|
"span",
|
|
18876
19407
|
{ class: "zx-launcher__copy" },
|
|
@@ -18883,14 +19414,20 @@ var Launcher = class extends Component {
|
|
|
18883
19414
|
h(tag, {
|
|
18884
19415
|
class: "zx-launcher__option",
|
|
18885
19416
|
type: tag === "button" ? "button" : null,
|
|
18886
|
-
href
|
|
19417
|
+
href,
|
|
18887
19418
|
target: item.target ?? null,
|
|
19419
|
+
rel: tag === "a" ? "noopener" : null,
|
|
18888
19420
|
role: "option",
|
|
18889
19421
|
id: uid("zx-launcher-option"),
|
|
18890
19422
|
tabIndex: -1,
|
|
18891
19423
|
ariaSelected: "false",
|
|
18892
19424
|
ariaDisabled: item.disabled ? "true" : null,
|
|
18893
|
-
|
|
19425
|
+
ariaCurrent: item.current ? "page" : null,
|
|
19426
|
+
dataset: {
|
|
19427
|
+
launcherIndex: index,
|
|
19428
|
+
pinned: item.pinned !== void 0 && item.pinned !== false ? "true" : null,
|
|
19429
|
+
kind: normalizeLauncherKind(item.kind)
|
|
19430
|
+
}
|
|
18894
19431
|
}, children)
|
|
18895
19432
|
);
|
|
18896
19433
|
}
|
|
@@ -18927,6 +19464,17 @@ var Launcher = class extends Component {
|
|
|
18927
19464
|
}
|
|
18928
19465
|
const enabled = this._results.map((item, index) => item.disabled ? -1 : index).filter((index) => index >= 0);
|
|
18929
19466
|
if (enabled.length === 0) return;
|
|
19467
|
+
if (/^Arrow(?:Left|Right|Up|Down)$/.test(event.key)) {
|
|
19468
|
+
const next = this._spatialIndex(event.key, enabled);
|
|
19469
|
+
if (next !== null) {
|
|
19470
|
+
event.preventDefault();
|
|
19471
|
+
this._active = next;
|
|
19472
|
+
this._syncActive();
|
|
19473
|
+
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
19474
|
+
return;
|
|
19475
|
+
}
|
|
19476
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") return;
|
|
19477
|
+
}
|
|
18930
19478
|
let position2 = enabled.indexOf(this._active);
|
|
18931
19479
|
if (event.key === "Home" || event.key === "PageUp") position2 = 0;
|
|
18932
19480
|
else if (event.key === "End" || event.key === "PageDown") position2 = enabled.length - 1;
|
|
@@ -18938,6 +19486,15 @@ var Launcher = class extends Component {
|
|
|
18938
19486
|
this._syncActive();
|
|
18939
19487
|
this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`)?.scrollIntoView({ block: "nearest" });
|
|
18940
19488
|
}
|
|
19489
|
+
/** @param {string} direction @param {number[]} enabled @returns {number|null} */
|
|
19490
|
+
_spatialIndex(direction, enabled) {
|
|
19491
|
+
const current = this.refs.results.querySelector(`[data-launcher-index="${this._active}"]`);
|
|
19492
|
+
if (!(current instanceof HTMLElement)) return null;
|
|
19493
|
+
if ((direction === "ArrowLeft" || direction === "ArrowRight") && this._results[this._active]?.kind !== "application") return null;
|
|
19494
|
+
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"));
|
|
19495
|
+
const next = findSpatialLauncherOption(candidates, current, direction);
|
|
19496
|
+
return next ? Number(next.getAttribute("data-launcher-index")) : null;
|
|
19497
|
+
}
|
|
18941
19498
|
/** @param {number} index @param {Event} event @returns {void} */
|
|
18942
19499
|
_activate(index, event) {
|
|
18943
19500
|
const item = this._results[index];
|
|
@@ -18963,25 +19520,103 @@ var Launcher = class extends Component {
|
|
|
18963
19520
|
}
|
|
18964
19521
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
18965
19522
|
_onDocumentKeydown(event) {
|
|
18966
|
-
if (this.options.shortcut !== "mod+k" || event.isComposing || event.key.toLowerCase() !== "k" ||
|
|
19523
|
+
if (this.options.shortcut !== "mod+k" || event.isComposing || event.key.toLowerCase() !== "k" || Number(event.metaKey) + Number(event.ctrlKey) !== 1 || event.altKey || event.shiftKey) return;
|
|
18967
19524
|
const active = document.activeElement;
|
|
18968
|
-
if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable) return;
|
|
19525
|
+
if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLSelectElement || active instanceof HTMLElement && active.isContentEditable) return;
|
|
18969
19526
|
const modal = document.querySelector("dialog:modal");
|
|
18970
19527
|
if (modal && modal !== this.el) return;
|
|
18971
19528
|
event.preventDefault();
|
|
18972
19529
|
this.open();
|
|
18973
19530
|
}
|
|
18974
19531
|
};
|
|
19532
|
+
function launcherShortcutLabel() {
|
|
19533
|
+
const platform = String(
|
|
19534
|
+
/** @type {any} */
|
|
19535
|
+
navigator.userAgentData?.platform ?? navigator.platform ?? ""
|
|
19536
|
+
);
|
|
19537
|
+
return /mac|iphone|ipad/i.test(platform) ? "\u2318 K" : "Ctrl K";
|
|
19538
|
+
}
|
|
19539
|
+
function launcherHints(hints) {
|
|
19540
|
+
if (hints === false) return null;
|
|
19541
|
+
const labels = hints && typeof hints === "object" ? hints : {};
|
|
19542
|
+
return h(
|
|
19543
|
+
"footer",
|
|
19544
|
+
{ class: "zx-launcher__hints", ariaHidden: "true" },
|
|
19545
|
+
h("span", {}, h("kbd", {}, "\u2191\u2193\u2190\u2192"), labels.move ?? "Move"),
|
|
19546
|
+
h("span", {}, h("kbd", {}, "\u21B5"), labels.open ?? "Open"),
|
|
19547
|
+
h("span", {}, h("kbd", {}, "Esc"), labels.close ?? "Close")
|
|
19548
|
+
);
|
|
19549
|
+
}
|
|
19550
|
+
function launcherItemIcon(item) {
|
|
19551
|
+
let visual = item.icon;
|
|
19552
|
+
if (typeof visual === "function") visual = visual(item);
|
|
19553
|
+
if (typeof visual === "string") return icon(visual);
|
|
19554
|
+
if (visual instanceof Node) return visual.cloneNode(true);
|
|
19555
|
+
if (visual && typeof visual === "object" && typeof /** @type {any} */
|
|
19556
|
+
visual.toElement === "function") {
|
|
19557
|
+
const element = (
|
|
19558
|
+
/** @type {any} */
|
|
19559
|
+
visual.toElement()
|
|
19560
|
+
);
|
|
19561
|
+
return element instanceof Node ? element.cloneNode(true) : null;
|
|
19562
|
+
}
|
|
19563
|
+
return null;
|
|
19564
|
+
}
|
|
19565
|
+
function normalizeLauncherKind(kind) {
|
|
19566
|
+
return kind === "application" || kind === "record" ? kind : "action";
|
|
19567
|
+
}
|
|
19568
|
+
function visibleForQuery(when, query) {
|
|
19569
|
+
if (when === "empty") return query === "";
|
|
19570
|
+
if (when === "query") return query !== "";
|
|
19571
|
+
return true;
|
|
19572
|
+
}
|
|
19573
|
+
function findSpatialLauncherOption(options, current, direction) {
|
|
19574
|
+
const origin = current.getBoundingClientRect();
|
|
19575
|
+
if (origin.width === 0 && origin.height === 0) return null;
|
|
19576
|
+
const originX = origin.left + origin.width / 2;
|
|
19577
|
+
const originY = origin.top + origin.height / 2;
|
|
19578
|
+
let best = null;
|
|
19579
|
+
let bestScore = Infinity;
|
|
19580
|
+
for (const option of options) {
|
|
19581
|
+
if (option === current) continue;
|
|
19582
|
+
const rect = option.getBoundingClientRect();
|
|
19583
|
+
const dx = rect.left + rect.width / 2 - originX;
|
|
19584
|
+
const dy = rect.top + rect.height / 2 - originY;
|
|
19585
|
+
let valid = false;
|
|
19586
|
+
let score = Infinity;
|
|
19587
|
+
if (direction === "ArrowLeft") {
|
|
19588
|
+
valid = dx < -2 && Math.abs(dy) < Math.max(origin.height, rect.height) / 2;
|
|
19589
|
+
score = Math.abs(dx) + Math.abs(dy) * 4;
|
|
19590
|
+
} else if (direction === "ArrowRight") {
|
|
19591
|
+
valid = dx > 2 && Math.abs(dy) < Math.max(origin.height, rect.height) / 2;
|
|
19592
|
+
score = Math.abs(dx) + Math.abs(dy) * 4;
|
|
19593
|
+
} else if (direction === "ArrowUp") {
|
|
19594
|
+
valid = dy < -2;
|
|
19595
|
+
score = Math.abs(dy) * 10 + Math.abs(dx);
|
|
19596
|
+
} else if (direction === "ArrowDown") {
|
|
19597
|
+
valid = dy > 2;
|
|
19598
|
+
score = Math.abs(dy) * 10 + Math.abs(dx);
|
|
19599
|
+
}
|
|
19600
|
+
if (valid && score < bestScore) {
|
|
19601
|
+
best = option;
|
|
19602
|
+
bestScore = score;
|
|
19603
|
+
}
|
|
19604
|
+
}
|
|
19605
|
+
return best;
|
|
19606
|
+
}
|
|
18975
19607
|
function rankLauncherItems(items, query, limit = 100) {
|
|
18976
19608
|
const needle = searchable(query).trim();
|
|
18977
19609
|
const ranked = items.map((item, order) => ({ item, order, score: launcherScore(item, needle) })).filter(({ score }) => score < Infinity);
|
|
18978
19610
|
ranked.sort((a, b) => {
|
|
19611
|
+
const aGroup = finiteOrder(a.item.groupOrder);
|
|
19612
|
+
const bGroup = finiteOrder(b.item.groupOrder);
|
|
19613
|
+
if (aGroup !== bGroup) return aGroup - bGroup;
|
|
18979
19614
|
if (needle === "") {
|
|
18980
19615
|
const aPinned = pinOrder(a.item.pinned, a.order);
|
|
18981
19616
|
const bPinned = pinOrder(b.item.pinned, b.order);
|
|
18982
19617
|
if (aPinned !== bPinned) return aPinned - bPinned;
|
|
18983
19618
|
}
|
|
18984
|
-
return a.score - b.score || compareLauncherText(a.item.label, b.item.label) || a.order - b.order;
|
|
19619
|
+
return a.score - b.score || finiteOrder(a.item.itemOrder) - finiteOrder(b.item.itemOrder) || compareLauncherText(a.item.label, b.item.label) || a.order - b.order;
|
|
18985
19620
|
});
|
|
18986
19621
|
const maximum = Math.max(0, Number(limit) || 0);
|
|
18987
19622
|
return ranked.slice(0, maximum || 0).map(({ item, score }) => ({ ...item, _score: score }));
|
|
@@ -19005,6 +19640,9 @@ function pinOrder(pinned, order) {
|
|
|
19005
19640
|
if (pinned) return order;
|
|
19006
19641
|
return Number.MAX_SAFE_INTEGER;
|
|
19007
19642
|
}
|
|
19643
|
+
function finiteOrder(value) {
|
|
19644
|
+
return typeof value === "number" && Number.isFinite(value) ? value : Number.MAX_SAFE_INTEGER;
|
|
19645
|
+
}
|
|
19008
19646
|
function searchable(value) {
|
|
19009
19647
|
return String(value ?? "").normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase();
|
|
19010
19648
|
}
|
|
@@ -19019,15 +19657,23 @@ function compareLauncherText(left, right) {
|
|
|
19019
19657
|
}
|
|
19020
19658
|
function normalizeItems2(items) {
|
|
19021
19659
|
if (!Array.isArray(items)) return [];
|
|
19022
|
-
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) => (
|
|
19660
|
+
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) => normalizeLauncherItem(item));
|
|
19661
|
+
}
|
|
19662
|
+
function normalizeLauncherItem(item) {
|
|
19663
|
+
const normalized = { ...item, label: String(item.label) };
|
|
19664
|
+
if (item.href == null) return normalized;
|
|
19665
|
+
const href = safeHref(item.href);
|
|
19666
|
+
if (href !== null) normalized.href = href;
|
|
19667
|
+
else {
|
|
19668
|
+
delete normalized.href;
|
|
19669
|
+
if (typeof normalized.invoke !== "function") normalized.disabled = true;
|
|
19670
|
+
}
|
|
19671
|
+
return normalized;
|
|
19023
19672
|
}
|
|
19024
19673
|
function normalizeSources(sources) {
|
|
19025
19674
|
if (!Array.isArray(sources)) return [];
|
|
19026
19675
|
return sources.filter((source) => source && typeof source === "object" && source.id != null && typeof source.load === "function").map((source) => ({ ...source, id: String(source.id) }));
|
|
19027
19676
|
}
|
|
19028
|
-
function orderedLauncherSourceItems(sources, sourceItems) {
|
|
19029
|
-
return sources.flatMap((source) => sourceItems.get(String(source.id)) ?? []);
|
|
19030
|
-
}
|
|
19031
19677
|
|
|
19032
19678
|
// src/components/avatar/avatar.js
|
|
19033
19679
|
var Avatar = class extends Component {
|
|
@@ -19715,10 +20361,10 @@ function isFocusVisible(element) {
|
|
|
19715
20361
|
}
|
|
19716
20362
|
}
|
|
19717
20363
|
|
|
19718
|
-
// src/
|
|
19719
|
-
var
|
|
20364
|
+
// src/internal/app-rail.js
|
|
20365
|
+
var AppRailPresenter = class extends Component {
|
|
19720
20366
|
static cssName = "app-rail";
|
|
19721
|
-
/** @type {Readonly<
|
|
20367
|
+
/** @type {Readonly<AppRailPresenterOptions>} */
|
|
19722
20368
|
static defaults = {
|
|
19723
20369
|
items: [],
|
|
19724
20370
|
active: null,
|
|
@@ -19728,12 +20374,13 @@ var AppRail = class extends Component {
|
|
|
19728
20374
|
header: null,
|
|
19729
20375
|
footer: null,
|
|
19730
20376
|
openDelay: 80,
|
|
19731
|
-
closeDelay: 160
|
|
20377
|
+
closeDelay: 160,
|
|
20378
|
+
renderIcon: null
|
|
19732
20379
|
};
|
|
19733
20380
|
/**
|
|
19734
20381
|
* Creates or enhances a rail host.
|
|
19735
20382
|
* @param {Element|string|null} target Rail target.
|
|
19736
|
-
* @param {
|
|
20383
|
+
* @param {AppRailPresenterOptions} [options={}] Rail options.
|
|
19737
20384
|
*/
|
|
19738
20385
|
constructor(target = null, options = {}) {
|
|
19739
20386
|
super(target, options);
|
|
@@ -19883,7 +20530,14 @@ var AppRail = class extends Component {
|
|
|
19883
20530
|
index: String(item.id),
|
|
19884
20531
|
iconOnly: true,
|
|
19885
20532
|
disclosure: hasChildren,
|
|
19886
|
-
disclosureIcon: railDisclosureIcon(this.el.dataset.side)
|
|
20533
|
+
disclosureIcon: railDisclosureIcon(this.el.dataset.side),
|
|
20534
|
+
visual: appNavIcon(item, this.options.renderIcon, {
|
|
20535
|
+
orientation: this.el.dataset.orientation,
|
|
20536
|
+
collapsed: true,
|
|
20537
|
+
side: this.el.dataset.side,
|
|
20538
|
+
level: 1,
|
|
20539
|
+
location: "root"
|
|
20540
|
+
})
|
|
19887
20541
|
});
|
|
19888
20542
|
const row2 = h("li", { class: "zx-app-rail__row" }, control);
|
|
19889
20543
|
this.refs.list.append(row2);
|
|
@@ -19924,7 +20578,14 @@ var AppRail = class extends Component {
|
|
|
19924
20578
|
index: childKey,
|
|
19925
20579
|
iconOnly: false,
|
|
19926
20580
|
disclosure: hasChildren,
|
|
19927
|
-
disclosureIcon: nestedDisclosureIcon(this.el.dataset.side)
|
|
20581
|
+
disclosureIcon: nestedDisclosureIcon(this.el.dataset.side),
|
|
20582
|
+
visual: appNavIcon(child, this.options.renderIcon, {
|
|
20583
|
+
orientation: this.el.dataset.orientation,
|
|
20584
|
+
collapsed: true,
|
|
20585
|
+
side: this.el.dataset.side,
|
|
20586
|
+
level: childKey.split("/").length,
|
|
20587
|
+
location: "flyout"
|
|
20588
|
+
})
|
|
19928
20589
|
});
|
|
19929
20590
|
list.append(h("li", {}, control));
|
|
19930
20591
|
if (hasChildren) this._buildFlyout(child, control, childKey, key);
|
|
@@ -19978,7 +20639,6 @@ var AppRail = class extends Component {
|
|
|
19978
20639
|
this._interaction.listen(trigger, "click", (event) => {
|
|
19979
20640
|
event.preventDefault();
|
|
19980
20641
|
if (event instanceof MouseEvent && event.detail === 0) this.openFlyout(key, { focus: true });
|
|
19981
|
-
else if (dropdown.isOpen()) this.closeFlyout(key);
|
|
19982
20642
|
else this.openFlyout(key);
|
|
19983
20643
|
});
|
|
19984
20644
|
this._interaction.listen(actualPanel, "pointerenter", () => this._cancelFlyoutTimers(flyout, true));
|
|
@@ -20233,14 +20893,43 @@ var RailListenerScope = class extends Component {
|
|
|
20233
20893
|
};
|
|
20234
20894
|
function normalizeAppItems(items) {
|
|
20235
20895
|
if (!Array.isArray(items)) return [];
|
|
20236
|
-
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) =>
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20896
|
+
return items.filter((item) => item && typeof item === "object" && item.id != null && item.label != null).map((item) => {
|
|
20897
|
+
const normalized = {
|
|
20898
|
+
...item,
|
|
20899
|
+
label: String(item.label),
|
|
20900
|
+
children: Array.isArray(item.children) ? normalizeAppItems(item.children) : []
|
|
20901
|
+
};
|
|
20902
|
+
if (item.href == null) return normalized;
|
|
20903
|
+
const href = safeHref(item.href);
|
|
20904
|
+
if (href !== null) normalized.href = href;
|
|
20905
|
+
else {
|
|
20906
|
+
delete normalized.href;
|
|
20907
|
+
if (normalized.children.length === 0 && typeof normalized.invoke !== "function") {
|
|
20908
|
+
normalized.disabled = true;
|
|
20909
|
+
}
|
|
20910
|
+
}
|
|
20911
|
+
return normalized;
|
|
20912
|
+
});
|
|
20241
20913
|
}
|
|
20242
|
-
function
|
|
20243
|
-
|
|
20914
|
+
function appNavIcon(item, renderer, context) {
|
|
20915
|
+
let visual = typeof renderer === "function" ? renderer(item, context) : null;
|
|
20916
|
+
if (visual == null) visual = item.icon;
|
|
20917
|
+
if (typeof visual === "function") visual = visual(context, item);
|
|
20918
|
+
if (typeof visual === "string") return icon(visual);
|
|
20919
|
+
if (visual instanceof Node) return visual.cloneNode(true);
|
|
20920
|
+
if (visual && typeof visual === "object" && typeof /** @type {any} */
|
|
20921
|
+
visual.toElement === "function") {
|
|
20922
|
+
const element = (
|
|
20923
|
+
/** @type {any} */
|
|
20924
|
+
visual.toElement()
|
|
20925
|
+
);
|
|
20926
|
+
return element instanceof Node ? element.cloneNode(true) : null;
|
|
20927
|
+
}
|
|
20928
|
+
return null;
|
|
20929
|
+
}
|
|
20930
|
+
function navControl(item, { className, index, iconOnly, disclosure, disclosureIcon, visual }) {
|
|
20931
|
+
const href = safeHref(item.href);
|
|
20932
|
+
const tag = href && !disclosure ? "a" : "button";
|
|
20244
20933
|
return (
|
|
20245
20934
|
/** @type {HTMLElement} */
|
|
20246
20935
|
h(
|
|
@@ -20248,13 +20937,14 @@ function navControl(item, { className, index, iconOnly, disclosure, disclosureIc
|
|
|
20248
20937
|
{
|
|
20249
20938
|
class: className,
|
|
20250
20939
|
type: tag === "button" ? "button" : null,
|
|
20251
|
-
href: tag === "a" ?
|
|
20940
|
+
href: tag === "a" ? href : null,
|
|
20252
20941
|
target: tag === "a" ? item.target ?? null : null,
|
|
20942
|
+
rel: tag === "a" ? "noopener" : null,
|
|
20253
20943
|
ariaLabel: iconOnly ? item.label : null,
|
|
20254
20944
|
ariaDisabled: item.disabled ? "true" : null,
|
|
20255
20945
|
dataset: { appNavId: index, appNavValueId: String(item.id) }
|
|
20256
20946
|
},
|
|
20257
|
-
|
|
20947
|
+
visual ? h("span", { class: `${className}-icon`, ariaHidden: "true" }, visual) : null,
|
|
20258
20948
|
h("span", { class: `${className}-label` }, item.label),
|
|
20259
20949
|
item.badge != null ? h("span", { class: `${className}-badge` }, String(item.badge)) : null,
|
|
20260
20950
|
disclosure ? h("span", { class: `${className}-disclosure`, ariaHidden: "true" }, icon(disclosureIcon)) : null
|
|
@@ -20318,47 +21008,28 @@ var AppSidebar = class extends Component {
|
|
|
20318
21008
|
active: null,
|
|
20319
21009
|
expanded: [],
|
|
20320
21010
|
collapsed: false,
|
|
21011
|
+
collapsible: true,
|
|
21012
|
+
orientation: "vertical",
|
|
20321
21013
|
side: "left",
|
|
20322
21014
|
label: "Applications",
|
|
20323
21015
|
header: null,
|
|
20324
21016
|
footer: null,
|
|
20325
21017
|
railHeader: null,
|
|
20326
|
-
railFooter: null
|
|
21018
|
+
railFooter: null,
|
|
21019
|
+
openDelay: 80,
|
|
21020
|
+
closeDelay: 160,
|
|
21021
|
+
renderIcon: null
|
|
20327
21022
|
};
|
|
20328
21023
|
/**
|
|
20329
|
-
* Creates or enhances an application-
|
|
20330
|
-
* @param {Element|string|null} target
|
|
20331
|
-
* @param {AppSidebarOptions} [options={}]
|
|
21024
|
+
* Creates or enhances an application-navigation host.
|
|
21025
|
+
* @param {Element|string|null} [target=null] Navigation target.
|
|
21026
|
+
* @param {AppSidebarOptions} [options={}] Navigation options.
|
|
20332
21027
|
*/
|
|
20333
21028
|
constructor(target = null, options = {}) {
|
|
20334
21029
|
super(target, options);
|
|
20335
|
-
this.
|
|
20336
|
-
|
|
20337
|
-
|
|
20338
|
-
type: "button",
|
|
20339
|
-
ariaLabel: "Expand application sidebar"
|
|
20340
|
-
}, icon(this.el.dataset.side === "right" ? "chevron-left" : "chevron-right"));
|
|
20341
|
-
this._railExpandButton = expandButton;
|
|
20342
|
-
const railHeader = h("div", { class: "zx-app-sidebar__rail-header" }, expandButton);
|
|
20343
|
-
appendSlot2(railHeader, this.options.railHeader);
|
|
20344
|
-
this._rail = new AppRail(this.refs.rail, {
|
|
20345
|
-
items: this._items,
|
|
20346
|
-
active: this._active,
|
|
20347
|
-
orientation: "vertical",
|
|
20348
|
-
side: this.el.dataset.side,
|
|
20349
|
-
label: this.options.label,
|
|
20350
|
-
header: railHeader,
|
|
20351
|
-
footer: this.options.railFooter,
|
|
20352
|
-
onselect: (event) => {
|
|
20353
|
-
const selected = this.emit("select", event.detail);
|
|
20354
|
-
if (selected.defaultPrevented) event.preventDefault();
|
|
20355
|
-
}
|
|
20356
|
-
});
|
|
20357
|
-
this.listen(expandButton, "click", () => {
|
|
20358
|
-
this.expand();
|
|
20359
|
-
});
|
|
20360
|
-
this._renderTree();
|
|
20361
|
-
this.setCollapsed(Boolean(this.options.collapsed), { silent: true });
|
|
21030
|
+
this._rail = null;
|
|
21031
|
+
this._railExpandButton = null;
|
|
21032
|
+
this._renderMode();
|
|
20362
21033
|
}
|
|
20363
21034
|
/** @returns {HTMLElement} */
|
|
20364
21035
|
render() {
|
|
@@ -20376,57 +21047,39 @@ var AppSidebar = class extends Component {
|
|
|
20376
21047
|
this._active = this.options.active;
|
|
20377
21048
|
this._expanded = new Set(Array.isArray(this.options.expanded) ? this.options.expanded.map(String) : []);
|
|
20378
21049
|
this._collapsed = Boolean(this.options.collapsed);
|
|
20379
|
-
|
|
20380
|
-
|
|
20381
|
-
|
|
20382
|
-
|
|
20383
|
-
ref: "collapse",
|
|
20384
|
-
class: "zx-app-sidebar__collapse zx-icon-btn",
|
|
20385
|
-
type: "button",
|
|
20386
|
-
ariaLabel: "Minimize application sidebar"
|
|
20387
|
-
}, icon(root.dataset.side === "right" ? "chevron-right" : "chevron-left"));
|
|
20388
|
-
const footer = h("footer", { class: "zx-app-sidebar__footer" });
|
|
20389
|
-
appendSlot2(footer, this.options.footer);
|
|
20390
|
-
footer.hidden = !footer.hasChildNodes();
|
|
20391
|
-
const expanded = h(
|
|
20392
|
-
"div",
|
|
20393
|
-
{ ref: "expanded", class: "zx-app-sidebar__expanded" },
|
|
20394
|
-
h("header", { class: "zx-app-sidebar__header" }, headerContent, collapseButton),
|
|
20395
|
-
h(
|
|
20396
|
-
"nav",
|
|
20397
|
-
{ class: "zx-app-sidebar__nav", ariaLabel: this.options.label },
|
|
20398
|
-
h("ul", { ref: "list", class: "zx-app-sidebar__list" })
|
|
20399
|
-
),
|
|
20400
|
-
footer
|
|
20401
|
-
);
|
|
20402
|
-
const rail = h("div", { ref: "rail", class: "zx-app-sidebar__rail" });
|
|
20403
|
-
root.replaceChildren(expanded, rail);
|
|
20404
|
-
this.listen(collapseButton, "click", () => {
|
|
20405
|
-
this.collapse();
|
|
20406
|
-
});
|
|
20407
|
-
this.listen(this.refs.list, "click", (event) => this._onTreeClick(event));
|
|
21050
|
+
this._orientation = this.options.orientation === "horizontal" ? "horizontal" : "vertical";
|
|
21051
|
+
this._side = normalizeSide(this._orientation, this.options.side);
|
|
21052
|
+
this._modeAbort = null;
|
|
21053
|
+
root.replaceChildren();
|
|
20408
21054
|
return root;
|
|
20409
21055
|
}
|
|
20410
|
-
/** Replaces the navigation tree in
|
|
21056
|
+
/** Replaces the navigation tree in the active presentation. @param {AppNavItem[]} items @returns {this} */
|
|
20411
21057
|
setItems(items) {
|
|
20412
21058
|
this._items = normalizeAppItems(items);
|
|
20413
21059
|
this._reconcileExpanded();
|
|
20414
|
-
this.
|
|
20415
|
-
this.
|
|
21060
|
+
if (this._rail) this._rail.setItems(this._items);
|
|
21061
|
+
else this._renderTree();
|
|
20416
21062
|
return this;
|
|
20417
21063
|
}
|
|
20418
|
-
/**
|
|
21064
|
+
/** Returns a shallow copy of normalized items. @returns {AppNavItem[]} */
|
|
21065
|
+
getItems() {
|
|
21066
|
+
return this._items.map((item) => ({
|
|
21067
|
+
...item,
|
|
21068
|
+
children: item.children?.map((child) => ({ ...child }))
|
|
21069
|
+
}));
|
|
21070
|
+
}
|
|
21071
|
+
/** Sets the active id without routing. @param {string|number|null} id @returns {this} */
|
|
20419
21072
|
setActive(id) {
|
|
20420
21073
|
this._active = id;
|
|
20421
|
-
this.
|
|
20422
|
-
this.
|
|
21074
|
+
if (this._rail) this._rail.setActive(id);
|
|
21075
|
+
else this._syncActive();
|
|
20423
21076
|
return this;
|
|
20424
21077
|
}
|
|
20425
21078
|
/** Replaces expanded branch ids. @param {Array<string|number>} ids @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20426
21079
|
setExpanded(ids, { silent = false } = {}) {
|
|
20427
21080
|
this._expanded = new Set(Array.isArray(ids) ? ids.map(String) : []);
|
|
20428
21081
|
this._reconcileExpanded();
|
|
20429
|
-
this._renderTree();
|
|
21082
|
+
if (!this._rail) this._renderTree();
|
|
20430
21083
|
if (!silent) this.emit("branchchange", {
|
|
20431
21084
|
item: null,
|
|
20432
21085
|
id: null,
|
|
@@ -20451,47 +21104,105 @@ var AppSidebar = class extends Component {
|
|
|
20451
21104
|
const expanded = !this._expanded.has(key);
|
|
20452
21105
|
if (expanded) this._expanded.add(key);
|
|
20453
21106
|
else this._expanded.delete(key);
|
|
20454
|
-
this._renderTree();
|
|
20455
|
-
if (!silent) this.emit("branchchange", {
|
|
21107
|
+
if (!this._rail) this._renderTree();
|
|
21108
|
+
if (!silent) this.emit("branchchange", {
|
|
21109
|
+
item,
|
|
21110
|
+
id: item.id,
|
|
21111
|
+
expanded,
|
|
21112
|
+
ids: this.getExpanded()
|
|
21113
|
+
});
|
|
20456
21114
|
return this;
|
|
20457
21115
|
}
|
|
20458
|
-
/** Shows the expanded
|
|
21116
|
+
/** Shows the expanded vertical presentation. @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20459
21117
|
expand(options = {}) {
|
|
20460
21118
|
return this.setCollapsed(false, options);
|
|
20461
21119
|
}
|
|
20462
|
-
/** Shows the minimized
|
|
21120
|
+
/** Shows the minimized presentation. @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20463
21121
|
collapse(options = {}) {
|
|
20464
21122
|
return this.setCollapsed(true, options);
|
|
20465
21123
|
}
|
|
20466
|
-
/** Sets expanded/minimized
|
|
21124
|
+
/** Sets the saved vertical expanded/minimized state. @param {boolean} collapsed @param {{silent?: boolean}} [options={}] @returns {this} */
|
|
20467
21125
|
setCollapsed(collapsed, { silent = false } = {}) {
|
|
20468
|
-
const
|
|
20469
|
-
const changed = next !== this._collapsed;
|
|
21126
|
+
const previous = this.isCollapsed();
|
|
20470
21127
|
const active = document.activeElement;
|
|
20471
|
-
const
|
|
20472
|
-
|
|
20473
|
-
|
|
20474
|
-
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
20478
|
-
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
|
|
20483
|
-
|
|
21128
|
+
const outgoingOwnedFocus = Boolean(active && (this.el.contains(active) || this._rail?._containsNode(active)));
|
|
21129
|
+
this._collapsed = Boolean(collapsed);
|
|
21130
|
+
const next = this.isCollapsed();
|
|
21131
|
+
if (previous !== next) {
|
|
21132
|
+
this._renderMode();
|
|
21133
|
+
if (outgoingOwnedFocus) {
|
|
21134
|
+
if (next) this._railExpandButton?.focus();
|
|
21135
|
+
else this.refs.collapse?.focus();
|
|
21136
|
+
}
|
|
21137
|
+
if (!silent) this.emit("collapsechange", { collapsed: next });
|
|
21138
|
+
}
|
|
21139
|
+
return this;
|
|
21140
|
+
}
|
|
21141
|
+
/** Reports the effective presentation state; horizontal navigation is always minimized. @returns {boolean} */
|
|
20484
21142
|
isCollapsed() {
|
|
20485
|
-
return this._collapsed;
|
|
21143
|
+
return this._orientation === "horizontal" || this._collapsed;
|
|
20486
21144
|
}
|
|
20487
|
-
/**
|
|
20488
|
-
|
|
20489
|
-
|
|
21145
|
+
/**
|
|
21146
|
+
* Changes navigation flow/edge without replacing state.
|
|
21147
|
+
* @param {{orientation?: 'vertical'|'horizontal', side?: 'left'|'right'|'top'|'bottom'}} layout
|
|
21148
|
+
* @param {{silent?: boolean}} [options]
|
|
21149
|
+
* @returns {this}
|
|
21150
|
+
*/
|
|
21151
|
+
setLayout(layout = {}, { silent = false } = {}) {
|
|
21152
|
+
const orientation = layout.orientation === "horizontal" ? "horizontal" : layout.orientation === "vertical" ? "vertical" : this._orientation;
|
|
21153
|
+
const side = normalizeSide(orientation, layout.side ?? this._side);
|
|
21154
|
+
if (orientation === this._orientation && side === this._side) return this;
|
|
21155
|
+
const previous = this.isCollapsed();
|
|
21156
|
+
const active = document.activeElement;
|
|
21157
|
+
const outgoingOwnedFocus = Boolean(active && (this.el.contains(active) || this._rail?._containsNode(active)));
|
|
21158
|
+
const focusedId = outgoingOwnedFocus && active instanceof Element ? active.closest("[data-app-nav-id]")?.getAttribute("data-app-nav-id") ?? null : null;
|
|
21159
|
+
this._orientation = orientation;
|
|
21160
|
+
this._side = side;
|
|
21161
|
+
this._renderMode();
|
|
21162
|
+
const next = this.isCollapsed();
|
|
21163
|
+
if (outgoingOwnedFocus) {
|
|
21164
|
+
const replacement = focusedId === null ? null : [...this.el.querySelectorAll("[data-app-nav-id]")].find((control) => control.getAttribute("data-app-nav-id") === focusedId) ?? null;
|
|
21165
|
+
if (replacement instanceof HTMLElement) replacement.focus();
|
|
21166
|
+
else if (next) this.focus();
|
|
21167
|
+
else if (this.refs.collapse instanceof HTMLElement && !this.refs.collapse.hidden) {
|
|
21168
|
+
this.refs.collapse.focus();
|
|
21169
|
+
} else visibleTreeControls(this.refs.list)[0]?.focus();
|
|
21170
|
+
}
|
|
21171
|
+
if (previous !== next && !silent) this.emit("collapsechange", { collapsed: next });
|
|
21172
|
+
return this;
|
|
20490
21173
|
}
|
|
20491
|
-
/**
|
|
21174
|
+
/** Opens a minimized descendant flyout. @param {string|number} id @param {{focus?: boolean}} [options={}] @returns {this} */
|
|
21175
|
+
openFlyout(id, options = {}) {
|
|
21176
|
+
this._rail?.openFlyout(id, options);
|
|
21177
|
+
return this;
|
|
21178
|
+
}
|
|
21179
|
+
/** Closes a minimized descendant flyout. @param {string|number} id @returns {this} */
|
|
21180
|
+
closeFlyout(id) {
|
|
21181
|
+
this._rail?.closeFlyout(id);
|
|
21182
|
+
return this;
|
|
21183
|
+
}
|
|
21184
|
+
/** Closes every minimized flyout. @returns {this} */
|
|
21185
|
+
closeAllFlyouts() {
|
|
21186
|
+
this._rail?.closeAllFlyouts();
|
|
21187
|
+
return this;
|
|
21188
|
+
}
|
|
21189
|
+
/** Reports whether a minimized flyout is open. @param {string|number} id @returns {boolean} */
|
|
21190
|
+
isFlyoutOpen(id) {
|
|
21191
|
+
return this._rail?.isFlyoutOpen(id) ?? false;
|
|
21192
|
+
}
|
|
21193
|
+
/** Focuses the first navigation action. @returns {this} */
|
|
21194
|
+
focus() {
|
|
21195
|
+
if (this._rail) this._rail.focus();
|
|
21196
|
+
else visibleTreeControls(this.refs.list)[0]?.focus();
|
|
21197
|
+
return this;
|
|
21198
|
+
}
|
|
21199
|
+
/** Destroys flyouts and restores/removes the host. @returns {void} */
|
|
20492
21200
|
destroy() {
|
|
20493
21201
|
const original = this._original;
|
|
20494
|
-
this.
|
|
21202
|
+
this._modeAbort?.abort();
|
|
21203
|
+
this._modeAbort = null;
|
|
21204
|
+
this._rail?.destroy();
|
|
21205
|
+
this._rail = null;
|
|
20495
21206
|
super.destroy();
|
|
20496
21207
|
if (!this._createdRoot && original) {
|
|
20497
21208
|
for (const attribute of Array.from(this.el.attributes)) this.el.removeAttribute(attribute.name);
|
|
@@ -20499,8 +21210,99 @@ var AppSidebar = class extends Component {
|
|
|
20499
21210
|
this.el.replaceChildren(...original.children);
|
|
20500
21211
|
}
|
|
20501
21212
|
}
|
|
21213
|
+
/** Mounts exactly one expanded tree or minimized flyout presentation. @returns {void} */
|
|
21214
|
+
_renderMode() {
|
|
21215
|
+
this._modeAbort?.abort();
|
|
21216
|
+
this._modeAbort = new AbortController();
|
|
21217
|
+
this._rail?.destroy();
|
|
21218
|
+
this._rail = null;
|
|
21219
|
+
this._railExpandButton = null;
|
|
21220
|
+
for (const key of ["expanded", "list", "collapse", "rail"]) delete this.refs[key];
|
|
21221
|
+
this.el.replaceChildren();
|
|
21222
|
+
this.el.dataset.orientation = this._orientation;
|
|
21223
|
+
this.el.dataset.side = this._side;
|
|
21224
|
+
this.el.dataset.collapsed = String(this.isCollapsed());
|
|
21225
|
+
if (this.isCollapsed()) this._renderRail();
|
|
21226
|
+
else this._renderExpanded();
|
|
21227
|
+
}
|
|
21228
|
+
/** @returns {void} */
|
|
21229
|
+
_renderExpanded() {
|
|
21230
|
+
const headerContent = h("div", { class: "zx-app-sidebar__header-content" });
|
|
21231
|
+
appendSlot2(headerContent, this.options.header);
|
|
21232
|
+
const collapseButton = h("button", {
|
|
21233
|
+
class: "zx-app-sidebar__collapse zx-icon-btn",
|
|
21234
|
+
type: "button",
|
|
21235
|
+
ariaLabel: "Minimize application sidebar"
|
|
21236
|
+
}, icon(this._side === "right" ? "chevron-right" : "chevron-left"));
|
|
21237
|
+
collapseButton.hidden = !this.options.collapsible;
|
|
21238
|
+
const footer = h("footer", { class: "zx-app-sidebar__footer" });
|
|
21239
|
+
appendSlot2(footer, this.options.footer);
|
|
21240
|
+
footer.hidden = !footer.hasChildNodes();
|
|
21241
|
+
const list = h("ul", { class: "zx-app-sidebar__list" });
|
|
21242
|
+
const expanded = h(
|
|
21243
|
+
"div",
|
|
21244
|
+
{ class: "zx-app-sidebar__expanded" },
|
|
21245
|
+
h("header", { class: "zx-app-sidebar__header" }, headerContent, collapseButton),
|
|
21246
|
+
h("nav", { class: "zx-app-sidebar__nav", ariaLabel: this.options.label }, list),
|
|
21247
|
+
footer
|
|
21248
|
+
);
|
|
21249
|
+
this.refs.expanded = expanded;
|
|
21250
|
+
this.refs.list = list;
|
|
21251
|
+
this.refs.collapse = collapseButton;
|
|
21252
|
+
this.el.append(expanded);
|
|
21253
|
+
this._listenMode(collapseButton, "click", () => this.collapse());
|
|
21254
|
+
this._listenMode(list, "click", (event) => this._onTreeClick(event));
|
|
21255
|
+
this._listenMode(list, "keydown", (event) => this._onTreeKeydown(
|
|
21256
|
+
/** @type {KeyboardEvent} */
|
|
21257
|
+
event
|
|
21258
|
+
));
|
|
21259
|
+
this._renderTree();
|
|
21260
|
+
}
|
|
21261
|
+
/** @returns {void} */
|
|
21262
|
+
_renderRail() {
|
|
21263
|
+
const railHost = h("nav", { class: "zx-app-sidebar__rail" });
|
|
21264
|
+
this.el.append(railHost);
|
|
21265
|
+
this.refs.rail = railHost;
|
|
21266
|
+
const showToggle = this._orientation === "vertical" && Boolean(this.options.collapsible);
|
|
21267
|
+
const railHeader = h("div", { class: "zx-app-sidebar__rail-header" });
|
|
21268
|
+
if (showToggle) {
|
|
21269
|
+
const expandButton = h("button", {
|
|
21270
|
+
class: "zx-app-sidebar__rail-toggle zx-icon-btn",
|
|
21271
|
+
type: "button",
|
|
21272
|
+
ariaLabel: "Expand application sidebar"
|
|
21273
|
+
}, icon(this._side === "right" ? "chevron-left" : "chevron-right"));
|
|
21274
|
+
railHeader.append(expandButton);
|
|
21275
|
+
this._railExpandButton = expandButton;
|
|
21276
|
+
this._listenMode(expandButton, "click", () => this.expand());
|
|
21277
|
+
}
|
|
21278
|
+
appendSlot2(railHeader, this.options.railHeader);
|
|
21279
|
+
this._rail = new AppRailPresenter(railHost, {
|
|
21280
|
+
items: this._items,
|
|
21281
|
+
active: this._active,
|
|
21282
|
+
orientation: this._orientation,
|
|
21283
|
+
side: this._side,
|
|
21284
|
+
label: this.options.label,
|
|
21285
|
+
header: railHeader.hasChildNodes() ? railHeader : null,
|
|
21286
|
+
footer: this.options.railFooter,
|
|
21287
|
+
openDelay: this.options.openDelay,
|
|
21288
|
+
closeDelay: this.options.closeDelay,
|
|
21289
|
+
renderIcon: this.options.renderIcon,
|
|
21290
|
+
onselect: (event) => {
|
|
21291
|
+
const selected = this.emit("select", event.detail);
|
|
21292
|
+
if (selected.defaultPrevented) event.preventDefault();
|
|
21293
|
+
},
|
|
21294
|
+
onflyoutchange: (event) => this.emit("flyoutchange", event.detail)
|
|
21295
|
+
});
|
|
21296
|
+
this._listenMode(railHost, "zx-select", (event) => event.stopPropagation());
|
|
21297
|
+
this._listenMode(railHost, "zx-flyoutchange", (event) => event.stopPropagation());
|
|
21298
|
+
}
|
|
21299
|
+
/** @param {EventTarget} target @param {string} type @param {EventListener} listener @returns {void} */
|
|
21300
|
+
_listenMode(target, type, listener) {
|
|
21301
|
+
target.addEventListener(type, listener, { signal: this._modeAbort.signal });
|
|
21302
|
+
}
|
|
20502
21303
|
/** @returns {void} */
|
|
20503
21304
|
_renderTree() {
|
|
21305
|
+
if (!this.refs.list) return;
|
|
20504
21306
|
const focused = this.refs.list.contains(document.activeElement) ? (
|
|
20505
21307
|
/** @type {Element} */
|
|
20506
21308
|
document.activeElement.closest("[data-app-nav-id]")?.getAttribute("data-app-nav-id")
|
|
@@ -20519,7 +21321,14 @@ var AppSidebar = class extends Component {
|
|
|
20519
21321
|
const key = String(item.id);
|
|
20520
21322
|
const expanded = hasChildren && this._expanded.has(key);
|
|
20521
21323
|
const childId = hasChildren ? uid("zx-app-sidebar-branch") : null;
|
|
20522
|
-
const
|
|
21324
|
+
const visual = appNavIcon(item, this.options.renderIcon, {
|
|
21325
|
+
orientation: this._orientation,
|
|
21326
|
+
collapsed: false,
|
|
21327
|
+
side: this._side,
|
|
21328
|
+
level,
|
|
21329
|
+
location: level === 1 ? "root" : "inline"
|
|
21330
|
+
});
|
|
21331
|
+
const control = navControl2(item, hasChildren, expanded, childId, visual);
|
|
20523
21332
|
const row2 = h("li", {
|
|
20524
21333
|
class: "zx-app-sidebar__row",
|
|
20525
21334
|
dataset: { level }
|
|
@@ -20533,7 +21342,7 @@ var AppSidebar = class extends Component {
|
|
|
20533
21342
|
}
|
|
20534
21343
|
return row2;
|
|
20535
21344
|
}
|
|
20536
|
-
/**
|
|
21345
|
+
/** @param {Event} event @returns {void} */
|
|
20537
21346
|
_onTreeClick(event) {
|
|
20538
21347
|
const control = (
|
|
20539
21348
|
/** @type {Element|null} */
|
|
@@ -20548,6 +21357,45 @@ var AppSidebar = class extends Component {
|
|
|
20548
21357
|
if (item.children?.length) this.toggleBranch(item.id);
|
|
20549
21358
|
else this._select(item, event);
|
|
20550
21359
|
}
|
|
21360
|
+
/** @param {KeyboardEvent} event @returns {void} */
|
|
21361
|
+
_onTreeKeydown(event) {
|
|
21362
|
+
const current = (
|
|
21363
|
+
/** @type {Element|null} */
|
|
21364
|
+
event.target?.closest?.("[data-app-nav-id]")
|
|
21365
|
+
);
|
|
21366
|
+
if (!(current instanceof HTMLElement)) return;
|
|
21367
|
+
const item = findItem(this._items, current.getAttribute("data-app-nav-id"));
|
|
21368
|
+
const controls = visibleTreeControls(this.refs.list);
|
|
21369
|
+
const index = controls.indexOf(current);
|
|
21370
|
+
if (event.key === "ArrowRight" && item?.children?.length) {
|
|
21371
|
+
event.preventDefault();
|
|
21372
|
+
if (!this._expanded.has(String(item.id))) this.toggleBranch(item.id);
|
|
21373
|
+
else visibleTreeControls(current.parentElement?.querySelector(".zx-app-sidebar__sublist"))[0]?.focus();
|
|
21374
|
+
return;
|
|
21375
|
+
}
|
|
21376
|
+
if (event.key === "ArrowLeft") {
|
|
21377
|
+
if (item?.children?.length && this._expanded.has(String(item.id))) {
|
|
21378
|
+
event.preventDefault();
|
|
21379
|
+
this.toggleBranch(item.id);
|
|
21380
|
+
return;
|
|
21381
|
+
}
|
|
21382
|
+
const parentList = current.closest(".zx-app-sidebar__sublist");
|
|
21383
|
+
const parentControl = parentList?.parentElement?.querySelector(":scope > [data-app-nav-id]");
|
|
21384
|
+
if (parentControl instanceof HTMLElement) {
|
|
21385
|
+
event.preventDefault();
|
|
21386
|
+
parentControl.focus();
|
|
21387
|
+
}
|
|
21388
|
+
return;
|
|
21389
|
+
}
|
|
21390
|
+
let nextIndex;
|
|
21391
|
+
if (event.key === "Home") nextIndex = 0;
|
|
21392
|
+
else if (event.key === "End") nextIndex = controls.length - 1;
|
|
21393
|
+
else if (event.key === "ArrowDown") nextIndex = Math.min(controls.length - 1, index + 1);
|
|
21394
|
+
else if (event.key === "ArrowUp") nextIndex = Math.max(0, index - 1);
|
|
21395
|
+
else return;
|
|
21396
|
+
event.preventDefault();
|
|
21397
|
+
controls[nextIndex]?.focus();
|
|
21398
|
+
}
|
|
20551
21399
|
/** @param {AppNavItem} item @param {Event} event @returns {void} */
|
|
20552
21400
|
_select(item, event) {
|
|
20553
21401
|
if (item.disabled) {
|
|
@@ -20569,14 +21417,14 @@ var AppSidebar = class extends Component {
|
|
|
20569
21417
|
}
|
|
20570
21418
|
/** @returns {void} */
|
|
20571
21419
|
_syncActive() {
|
|
21420
|
+
if (!this.refs.list) return;
|
|
20572
21421
|
const activeId = this._active == null ? null : String(this._active);
|
|
20573
21422
|
for (const control of this.refs.list.querySelectorAll("[data-app-nav-id]")) {
|
|
20574
21423
|
const item = findItem(this._items, control.getAttribute("data-app-nav-id"));
|
|
20575
21424
|
const direct = activeId !== null && control.getAttribute("data-app-nav-id") === activeId;
|
|
20576
21425
|
const descendant = activeId !== null && item ? containsItemId2(item.children ?? [], activeId) : false;
|
|
20577
|
-
if (direct)
|
|
20578
|
-
|
|
20579
|
-
} else control.removeAttribute("aria-current");
|
|
21426
|
+
if (direct) control.setAttribute("aria-current", "page");
|
|
21427
|
+
else control.removeAttribute("aria-current");
|
|
20580
21428
|
if (descendant) control.dataset.activeDescendant = "true";
|
|
20581
21429
|
else delete control.dataset.activeDescendant;
|
|
20582
21430
|
}
|
|
@@ -20590,7 +21438,7 @@ var AppSidebar = class extends Component {
|
|
|
20590
21438
|
for (const id of this._expanded) if (!branchIds.has(id)) this._expanded.delete(id);
|
|
20591
21439
|
}
|
|
20592
21440
|
};
|
|
20593
|
-
function navControl2(item, disclosure, expanded, controls) {
|
|
21441
|
+
function navControl2(item, disclosure, expanded, controls, visual) {
|
|
20594
21442
|
const tag = item.href && !disclosure ? "a" : "button";
|
|
20595
21443
|
return (
|
|
20596
21444
|
/** @type {HTMLElement} */
|
|
@@ -20606,7 +21454,7 @@ function navControl2(item, disclosure, expanded, controls) {
|
|
|
20606
21454
|
ariaControls: controls,
|
|
20607
21455
|
dataset: { appNavId: String(item.id) }
|
|
20608
21456
|
},
|
|
20609
|
-
|
|
21457
|
+
visual ? h("span", { class: "zx-app-sidebar__item-icon", ariaHidden: "true" }, visual) : null,
|
|
20610
21458
|
h("span", { class: "zx-app-sidebar__item-label" }, item.label),
|
|
20611
21459
|
item.badge != null ? h("span", { class: "zx-app-sidebar__item-badge" }, String(item.badge)) : null,
|
|
20612
21460
|
disclosure ? h(
|
|
@@ -20617,6 +21465,13 @@ function navControl2(item, disclosure, expanded, controls) {
|
|
|
20617
21465
|
)
|
|
20618
21466
|
);
|
|
20619
21467
|
}
|
|
21468
|
+
function visibleTreeControls(root) {
|
|
21469
|
+
if (!root) return [];
|
|
21470
|
+
return (
|
|
21471
|
+
/** @type {HTMLElement[]} */
|
|
21472
|
+
[...root.querySelectorAll("[data-app-nav-id]")].filter((control) => !control.closest(".zx-app-sidebar__sublist[hidden]"))
|
|
21473
|
+
);
|
|
21474
|
+
}
|
|
20620
21475
|
function visibleTreeControl(control) {
|
|
20621
21476
|
let candidate = (
|
|
20622
21477
|
/** @type {HTMLElement|null} */
|
|
@@ -20649,12 +21504,17 @@ function containsItemId2(items, id) {
|
|
|
20649
21504
|
}
|
|
20650
21505
|
function appendSlot2(target, content) {
|
|
20651
21506
|
if (content == null) return;
|
|
20652
|
-
if (typeof content === "string" || typeof content === "number")
|
|
20653
|
-
|
|
21507
|
+
if (typeof content === "string" || typeof content === "number") {
|
|
21508
|
+
target.append(document.createTextNode(String(content)));
|
|
21509
|
+
} else if (typeof content === "object" && typeof content.toElement === "function") {
|
|
20654
21510
|
const element = content.toElement();
|
|
20655
21511
|
if (element) target.append(element);
|
|
20656
21512
|
} else if (typeof content === "object" && typeof content.nodeType === "number") target.append(content);
|
|
20657
21513
|
}
|
|
21514
|
+
function normalizeSide(orientation, side) {
|
|
21515
|
+
if (orientation === "horizontal") return side === "bottom" ? "bottom" : "top";
|
|
21516
|
+
return side === "right" ? "right" : "left";
|
|
21517
|
+
}
|
|
20658
21518
|
|
|
20659
21519
|
// src/components/message/message.js
|
|
20660
21520
|
var MessageQueue = class {
|
|
@@ -22022,9 +22882,9 @@ function billingItemsConfig(options = {}) {
|
|
|
22022
22882
|
} = options;
|
|
22023
22883
|
const fields = { ...DEFAULT_FIELDS, ...requestedFields };
|
|
22024
22884
|
const calculateLineTotal = typeof lineTotal === "function" ? lineTotal : (row2) => {
|
|
22025
|
-
const quantity =
|
|
22026
|
-
const price =
|
|
22027
|
-
return
|
|
22885
|
+
const quantity = billingNumber(row2?.[fields.quantity]);
|
|
22886
|
+
const price = billingNumber(row2?.[fields.unitPrice]);
|
|
22887
|
+
return quantity !== null && price !== null ? quantity * price : null;
|
|
22028
22888
|
};
|
|
22029
22889
|
const columns = Array.isArray(suppliedColumns) ? suppliedColumns.map((column) => ({ ...column })) : billingColumns(fields, { units, currencies, currency, locale, decimals, columnOverrides });
|
|
22030
22890
|
return {
|
|
@@ -22129,6 +22989,11 @@ function billingColumns(fields, { units, currencies, currency, locale, decimals,
|
|
|
22129
22989
|
function hasChoices(value) {
|
|
22130
22990
|
return Array.isArray(value) ? value.length > 0 : Boolean(value && typeof value === "object" && Object.keys(value).length);
|
|
22131
22991
|
}
|
|
22992
|
+
function billingNumber(value) {
|
|
22993
|
+
if (value == null || typeof value === "string" && value.trim() === "") return null;
|
|
22994
|
+
const number2 = Number(value);
|
|
22995
|
+
return Number.isFinite(number2) ? number2 : null;
|
|
22996
|
+
}
|
|
22132
22997
|
|
|
22133
22998
|
// src/components/chart/chart.js
|
|
22134
22999
|
var Chart = class extends Component {
|
|
@@ -22176,6 +23041,7 @@ var Chart = class extends Component {
|
|
|
22176
23041
|
this._chartOptions = cloneChartValue(this.options.chartOptions);
|
|
22177
23042
|
this._loading = Boolean(this.options.loading);
|
|
22178
23043
|
this._error = null;
|
|
23044
|
+
this._hasError = false;
|
|
22179
23045
|
this._handle = null;
|
|
22180
23046
|
this._destroyed = false;
|
|
22181
23047
|
const descriptionId = uid("zx-chart-description");
|
|
@@ -22221,6 +23087,7 @@ var Chart = class extends Component {
|
|
|
22221
23087
|
setData(data) {
|
|
22222
23088
|
this._data = normalizeChartData(data);
|
|
22223
23089
|
this._error = null;
|
|
23090
|
+
this._hasError = false;
|
|
22224
23091
|
this._loading = false;
|
|
22225
23092
|
this._renderSummary();
|
|
22226
23093
|
this._mountOrUpdate(true);
|
|
@@ -22256,6 +23123,7 @@ var Chart = class extends Component {
|
|
|
22256
23123
|
/** Shows an error and destroys the current engine. @param {unknown} error @returns {this} */
|
|
22257
23124
|
setError(error) {
|
|
22258
23125
|
this._error = error ?? new Error(String(this.options.errorText));
|
|
23126
|
+
this._hasError = true;
|
|
22259
23127
|
this._loading = false;
|
|
22260
23128
|
this._destroyHandle();
|
|
22261
23129
|
this._syncState();
|
|
@@ -22265,6 +23133,7 @@ var Chart = class extends Component {
|
|
|
22265
23133
|
/** Clears the error and remounts when data and an adapter are available. @returns {this} */
|
|
22266
23134
|
clearError() {
|
|
22267
23135
|
this._error = null;
|
|
23136
|
+
this._hasError = false;
|
|
22268
23137
|
this._mountOrUpdate(false);
|
|
22269
23138
|
return this;
|
|
22270
23139
|
}
|
|
@@ -22303,7 +23172,7 @@ var Chart = class extends Component {
|
|
|
22303
23172
|
/** @param {boolean} emitUpdate @returns {void} */
|
|
22304
23173
|
_mountOrUpdate(emitUpdate) {
|
|
22305
23174
|
this._syncState();
|
|
22306
|
-
if (this._loading || this.
|
|
23175
|
+
if (this._loading || this._hasError || isEmptyChartData(this._data)) {
|
|
22307
23176
|
this._destroyHandle();
|
|
22308
23177
|
return;
|
|
22309
23178
|
}
|
|
@@ -22358,7 +23227,7 @@ var Chart = class extends Component {
|
|
|
22358
23227
|
/** @returns {void} */
|
|
22359
23228
|
_syncState() {
|
|
22360
23229
|
const empty = isEmptyChartData(this._data);
|
|
22361
|
-
const state = this._loading ? "loading" : this.
|
|
23230
|
+
const state = this._loading ? "loading" : this._hasError ? "error" : empty ? "empty" : "ready";
|
|
22362
23231
|
this.el.dataset.state = state;
|
|
22363
23232
|
this.refs.viewport.hidden = state !== "ready";
|
|
22364
23233
|
let text4 = "";
|
|
@@ -22570,7 +23439,8 @@ function themeChartOptions(root) {
|
|
|
22570
23439
|
};
|
|
22571
23440
|
}
|
|
22572
23441
|
function errorMessage(error, fallback) {
|
|
22573
|
-
|
|
23442
|
+
const message = error && typeof error === "object" && "message" in error ? String(error.message) : "";
|
|
23443
|
+
return message.trim() ? message : String(fallback);
|
|
22574
23444
|
}
|
|
22575
23445
|
|
|
22576
23446
|
// src/components/tree/hierarchy.js
|
|
@@ -25669,10 +26539,10 @@ function registerFieldAdapters() {
|
|
|
25669
26539
|
registerFieldAdapters();
|
|
25670
26540
|
export {
|
|
25671
26541
|
AccountMenu,
|
|
25672
|
-
AppRail,
|
|
25673
26542
|
AppSidebar,
|
|
25674
26543
|
Avatar,
|
|
25675
26544
|
Breadcrumb,
|
|
26545
|
+
Card,
|
|
25676
26546
|
Chart,
|
|
25677
26547
|
ChartJsAdapter,
|
|
25678
26548
|
CheckButton,
|