@zeyos/zx 4.0.0 → 4.1.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 +44 -0
- package/DESIGN-SYSTEM.md +59 -3
- package/dist/types/components/app-icon/app-icon.d.ts +88 -0
- package/dist/types/components/filter/filter-model.d.ts +87 -0
- package/dist/types/components/filter/filter.d.ts +331 -0
- package/dist/types/components/select/select.d.ts +46 -4
- package/dist/types/components/table/table.d.ts +103 -0
- package/dist/types/components/tag-picker/tag-picker.d.ts +16 -0
- package/dist/types/core/dom.d.ts +1 -1
- package/dist/types/core/util.d.ts +9 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/types/zeyos/icons.d.ts +19 -2
- package/dist/types/zeyos/index.d.ts +1 -1
- package/dist/types/zeyos/select.d.ts +2 -0
- package/dist/zx-zeyos.esm.js +702 -75
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +415 -4
- package/dist/zx.esm.js +1568 -115
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +1568 -115
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +379 -0
- package/docs/llms.md +93 -16
- package/docs/llms.txt +11 -9
- package/package.json +1 -1
- package/src/components/app-icon/app-icon.css +105 -0
- package/src/components/app-icon/app-icon.js +134 -0
- package/src/components/filter/filter-model.js +226 -0
- package/src/components/filter/filter.css +147 -0
- package/src/components/filter/filter.js +554 -0
- package/src/components/grid/grid.css +1 -1
- package/src/components/grid/grid.js +4 -1
- package/src/components/message/message.css +36 -3
- package/src/components/select/select.css +17 -0
- package/src/components/select/select.js +105 -24
- package/src/components/table/table.css +85 -0
- package/src/components/table/table.js +418 -24
- package/src/components/tag-picker/tag-picker.css +19 -0
- package/src/components/tag-picker/tag-picker.js +42 -5
- package/src/core/dom.js +1 -1
- package/src/core/util.js +20 -0
- package/src/index.js +7 -1
- package/src/zeyos/icons.js +34 -21
- package/src/zeyos/index.js +1 -1
- package/src/zeyos/select.js +6 -5
- package/styles/tokens/semantic.css +9 -0
- package/styles/tokens/themes.css +2 -2
- package/styles/zx.css +2 -0
package/dist/zx.esm.js
CHANGED
|
@@ -73,6 +73,20 @@ function isElement(value) {
|
|
|
73
73
|
return Boolean(value && typeof value === "object" && /** @type {{nodeType?: unknown}} */
|
|
74
74
|
value.nodeType === 1);
|
|
75
75
|
}
|
|
76
|
+
function isCssColor(value) {
|
|
77
|
+
if (typeof value !== "string") return false;
|
|
78
|
+
const text4 = value.trim();
|
|
79
|
+
if (!text4 || text4.length > 256 || /[;{}\u0000-\u001f\u007f]/.test(text4) || /(?:url|image|image-set|cross-fade|element|var)\s*\(/i.test(text4)) return false;
|
|
80
|
+
const supports = globalThis.CSS?.supports;
|
|
81
|
+
if (typeof supports === "function") {
|
|
82
|
+
try {
|
|
83
|
+
return supports.call(globalThis.CSS, "color", text4);
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return /^(?:#[\da-f]{3,8}|[a-z]+|(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color|color-mix)\([^;{}]+\))$/i.test(text4);
|
|
89
|
+
}
|
|
76
90
|
function clamp(n, min, max) {
|
|
77
91
|
return Math.min(max, Math.max(min, n));
|
|
78
92
|
}
|
|
@@ -710,9 +724,9 @@ var Component = class extends EventTarget {
|
|
|
710
724
|
let rendered;
|
|
711
725
|
try {
|
|
712
726
|
rendered = h.scope(this.refs, () => this.render());
|
|
713
|
-
} catch (
|
|
727
|
+
} catch (error2) {
|
|
714
728
|
this.#abort.abort();
|
|
715
|
-
throw
|
|
729
|
+
throw error2;
|
|
716
730
|
}
|
|
717
731
|
if (this.#created) {
|
|
718
732
|
const root = isElement(rendered) ? rendered : this.el;
|
|
@@ -1003,8 +1017,8 @@ var Field = class _Field extends Component {
|
|
|
1003
1017
|
/** @type {Readonly<FieldOptions>} */
|
|
1004
1018
|
this.options
|
|
1005
1019
|
));
|
|
1006
|
-
} catch (
|
|
1007
|
-
const message =
|
|
1020
|
+
} catch (error2) {
|
|
1021
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
1008
1022
|
console.warn(`[zx.Field] Adapter "${type}" failed: ${message}`);
|
|
1009
1023
|
this.adapter = errorAdapter(message, this.controlId);
|
|
1010
1024
|
}
|
|
@@ -4987,8 +5001,8 @@ var FieldUpload = class extends Component {
|
|
|
4987
5001
|
return response;
|
|
4988
5002
|
} catch (caught) {
|
|
4989
5003
|
if (runId !== this._runId) return null;
|
|
4990
|
-
const
|
|
4991
|
-
if (
|
|
5004
|
+
const error2 = caught instanceof Error ? caught : new Error(String(caught));
|
|
5005
|
+
if (error2.name === "AbortError") {
|
|
4992
5006
|
this._finishAbort();
|
|
4993
5007
|
return null;
|
|
4994
5008
|
}
|
|
@@ -4997,8 +5011,8 @@ var FieldUpload = class extends Component {
|
|
|
4997
5011
|
this._transportController = null;
|
|
4998
5012
|
this._abort.hidden = true;
|
|
4999
5013
|
this._setState("error");
|
|
5000
|
-
this._status.textContent =
|
|
5001
|
-
this.emit("error", { error });
|
|
5014
|
+
this._status.textContent = error2.message;
|
|
5015
|
+
this.emit("error", { error: error2 });
|
|
5002
5016
|
return null;
|
|
5003
5017
|
}
|
|
5004
5018
|
}
|
|
@@ -5146,10 +5160,10 @@ var FieldUpload = class extends Component {
|
|
|
5146
5160
|
this.emit("abort", {});
|
|
5147
5161
|
}
|
|
5148
5162
|
/** @param {Error} error @returns {void} */
|
|
5149
|
-
_selectionError(
|
|
5163
|
+
_selectionError(error2) {
|
|
5150
5164
|
this._setState("error");
|
|
5151
|
-
this._status.textContent =
|
|
5152
|
-
this.emit("error", { error });
|
|
5165
|
+
this._status.textContent = error2.message;
|
|
5166
|
+
this.emit("error", { error: error2 });
|
|
5153
5167
|
}
|
|
5154
5168
|
/** @returns {void} */
|
|
5155
5169
|
_renderPreview() {
|
|
@@ -5232,9 +5246,9 @@ function parseResponse(text4) {
|
|
|
5232
5246
|
}
|
|
5233
5247
|
function abortError() {
|
|
5234
5248
|
if (typeof DOMException === "function") return new DOMException("Upload aborted", "AbortError");
|
|
5235
|
-
const
|
|
5236
|
-
|
|
5237
|
-
return
|
|
5249
|
+
const error2 = new Error("Upload aborted");
|
|
5250
|
+
error2.name = "AbortError";
|
|
5251
|
+
return error2;
|
|
5238
5252
|
}
|
|
5239
5253
|
|
|
5240
5254
|
// src/components/field-upload/field-adapter.js
|
|
@@ -6360,8 +6374,8 @@ var Rating = class extends Component {
|
|
|
6360
6374
|
const shown = this._preview ?? this._value;
|
|
6361
6375
|
const symbols = this.refs.symbols.querySelectorAll(".zx-rating__symbol");
|
|
6362
6376
|
symbols.forEach((symbol, index) => {
|
|
6363
|
-
const
|
|
6364
|
-
symbol.style.setProperty("--zx-rating-fill", `${
|
|
6377
|
+
const filled2 = Math.min(1, Math.max(0, shown - index));
|
|
6378
|
+
symbol.style.setProperty("--zx-rating-fill", `${filled2 * 100}%`);
|
|
6365
6379
|
symbol.toggleAttribute("data-preview", this._preview !== null);
|
|
6366
6380
|
});
|
|
6367
6381
|
this.el.dataset.value = String(shown);
|
|
@@ -6647,6 +6661,7 @@ var Select = class _Select extends Component {
|
|
|
6647
6661
|
static defaults = {
|
|
6648
6662
|
items: [],
|
|
6649
6663
|
fixedItems: [],
|
|
6664
|
+
fixedLabel: null,
|
|
6650
6665
|
valueKey: "ID",
|
|
6651
6666
|
labelKey: "name",
|
|
6652
6667
|
renderItem: null,
|
|
@@ -6684,8 +6699,7 @@ var Select = class _Select extends Component {
|
|
|
6684
6699
|
this._position = null;
|
|
6685
6700
|
this._createdRoot = false;
|
|
6686
6701
|
this._root = null;
|
|
6687
|
-
this.
|
|
6688
|
-
this._originalAttributes = /* @__PURE__ */ new Map();
|
|
6702
|
+
this._snapshot = null;
|
|
6689
6703
|
this._createdRoot = this.el === null;
|
|
6690
6704
|
const root = (
|
|
6691
6705
|
/** @type {HTMLElement} */
|
|
@@ -6693,10 +6707,7 @@ var Select = class _Select extends Component {
|
|
|
6693
6707
|
);
|
|
6694
6708
|
this.el = root;
|
|
6695
6709
|
this._root = root;
|
|
6696
|
-
|
|
6697
|
-
this._rememberAttribute(root, "data-state");
|
|
6698
|
-
this._rememberAttribute(root, "data-loading");
|
|
6699
|
-
this._rememberAttribute(root, "aria-disabled");
|
|
6710
|
+
this._snapshot = this._createdRoot ? null : snapshotTarget(root);
|
|
6700
6711
|
const listId = uid("zx-select-list");
|
|
6701
6712
|
const input = h("input", {
|
|
6702
6713
|
ref: "input",
|
|
@@ -6999,6 +7010,66 @@ var Select = class _Select extends Component {
|
|
|
6999
7010
|
select.set(value, { silent: true });
|
|
7000
7011
|
return select;
|
|
7001
7012
|
}
|
|
7013
|
+
/**
|
|
7014
|
+
* Creates a rich entity picker with optional Recent choices and a create command.
|
|
7015
|
+
* @param {Element|string|null} target Component target.
|
|
7016
|
+
* @param {SelectOptions & EntitySelectOptions} [options={}] Entity-preset options.
|
|
7017
|
+
* @returns {Select}
|
|
7018
|
+
*/
|
|
7019
|
+
static entity(target, options = {}) {
|
|
7020
|
+
const {
|
|
7021
|
+
recent = [],
|
|
7022
|
+
recentLabel = "Recent",
|
|
7023
|
+
create = false,
|
|
7024
|
+
iconKey = "icon",
|
|
7025
|
+
colorKey = "color",
|
|
7026
|
+
subtitleKey = "description",
|
|
7027
|
+
renderIcon = null,
|
|
7028
|
+
fixedItems = [],
|
|
7029
|
+
actions: actions2 = [],
|
|
7030
|
+
renderItem = null,
|
|
7031
|
+
renderValueAdornment = null,
|
|
7032
|
+
...rest
|
|
7033
|
+
} = options;
|
|
7034
|
+
const visual = (item, selected = false) => {
|
|
7035
|
+
if (typeof renderIcon === "function") return renderIcon(item, { selected });
|
|
7036
|
+
const value = readSelectItem(item, iconKey);
|
|
7037
|
+
if (value && typeof value === "object" && typeof value.nodeType === "number") return value.cloneNode(true);
|
|
7038
|
+
if (typeof value !== "string" || !value) return null;
|
|
7039
|
+
const color = readSelectItem(item, colorKey);
|
|
7040
|
+
return h("span", {
|
|
7041
|
+
class: "zx-select__entity-glyph",
|
|
7042
|
+
style: isCssColor(color) ? { "--zx-select-entity-color": String(color) } : null,
|
|
7043
|
+
ariaHidden: "true"
|
|
7044
|
+
}, icon(value, { size: 14 }));
|
|
7045
|
+
};
|
|
7046
|
+
const createAction = create ? normalizeEntityCreateAction(create) : null;
|
|
7047
|
+
const select = new _Select(target, {
|
|
7048
|
+
...rest,
|
|
7049
|
+
fixedItems: [...Array.isArray(recent) ? recent : [], ...Array.isArray(fixedItems) ? fixedItems : []],
|
|
7050
|
+
fixedLabel: Array.isArray(recent) && recent.length ? recentLabel : rest.fixedLabel ?? null,
|
|
7051
|
+
actions: [...Array.isArray(actions2) ? actions2 : [], ...createAction ? [createAction] : []],
|
|
7052
|
+
renderItem: renderItem ?? ((item) => {
|
|
7053
|
+
const decoration = visual(item, false);
|
|
7054
|
+
const subtitle = readSelectItem(item, subtitleKey);
|
|
7055
|
+
const copy = h(
|
|
7056
|
+
"span",
|
|
7057
|
+
{ class: "zx-select__entity-copy" },
|
|
7058
|
+
h("span", { class: "zx-select__entity-label" }, String(readSelectItem(item, rest.labelKey ?? "name") ?? "")),
|
|
7059
|
+
subtitle == null || subtitle === "" ? null : h("span", { class: "zx-select__entity-subtitle" }, String(subtitle))
|
|
7060
|
+
);
|
|
7061
|
+
return h(
|
|
7062
|
+
"span",
|
|
7063
|
+
{ class: "zx-select__entity" },
|
|
7064
|
+
decoration ? h("span", { class: "zx-select__entity-icon", ariaHidden: "true" }, decoration) : null,
|
|
7065
|
+
copy
|
|
7066
|
+
);
|
|
7067
|
+
}),
|
|
7068
|
+
renderValueAdornment: renderValueAdornment ?? ((item) => visual(item, true))
|
|
7069
|
+
});
|
|
7070
|
+
select.el.dataset.preset = "entity";
|
|
7071
|
+
return select;
|
|
7072
|
+
}
|
|
7002
7073
|
/**
|
|
7003
7074
|
* Creates the record-permission picker: the fixed Private and Public choices above the groups a
|
|
7004
7075
|
* record can be shared with. The value is the tri-state ZeyOS stores — `false` for private,
|
|
@@ -7049,13 +7120,7 @@ var Select = class _Select extends Component {
|
|
|
7049
7120
|
/** @type {HTMLElement} */
|
|
7050
7121
|
this.el
|
|
7051
7122
|
);
|
|
7052
|
-
if (!this._createdRoot && root)
|
|
7053
|
-
root.replaceChildren(...this._originalChildren);
|
|
7054
|
-
for (const [name, value] of this._originalAttributes) {
|
|
7055
|
-
if (value === null) root.removeAttribute(name);
|
|
7056
|
-
else root.setAttribute(name, value);
|
|
7057
|
-
}
|
|
7058
|
-
}
|
|
7123
|
+
if (!this._createdRoot && root) restoreTarget(root, this._snapshot);
|
|
7059
7124
|
super.destroy();
|
|
7060
7125
|
}
|
|
7061
7126
|
/** @param {KeyboardEvent} event @returns {void} */
|
|
@@ -7192,14 +7257,19 @@ var Select = class _Select extends Component {
|
|
|
7192
7257
|
list.replaceChildren();
|
|
7193
7258
|
this._optionEntries = [];
|
|
7194
7259
|
let lastGroup = /* @__PURE__ */ Symbol("initial-group");
|
|
7260
|
+
const fixed = this._uniqueItems(this._visibleFixed);
|
|
7261
|
+
const items = this._uniqueItems(this._visibleItems, fixed);
|
|
7195
7262
|
if (this.options.clearable) {
|
|
7196
7263
|
this._appendOption(null, true, this.options.noneLabel ?? this._message("select.none", "No selection"));
|
|
7197
7264
|
}
|
|
7198
|
-
|
|
7199
|
-
|
|
7265
|
+
if (fixed.length > 0 && this.options.fixedLabel) {
|
|
7266
|
+
list.append(h("div", { class: "zx-select__group", role: "presentation" }, String(this.options.fixedLabel)));
|
|
7267
|
+
}
|
|
7268
|
+
for (const item of fixed) this._appendOption(item, false);
|
|
7269
|
+
if (fixed.length > 0 && items.length > 0 && !this.options.groupKey) {
|
|
7200
7270
|
list.append(h("div", { class: "zx-select__separator", role: "presentation" }));
|
|
7201
7271
|
}
|
|
7202
|
-
for (const item of
|
|
7272
|
+
for (const item of items) {
|
|
7203
7273
|
if (this.options.groupKey) {
|
|
7204
7274
|
const group = this._read(item, this.options.groupKey);
|
|
7205
7275
|
if (!Object.is(group, lastGroup)) {
|
|
@@ -7213,7 +7283,7 @@ var Select = class _Select extends Component {
|
|
|
7213
7283
|
this._appendOption(item, false);
|
|
7214
7284
|
}
|
|
7215
7285
|
if (this._actions.length > 0) {
|
|
7216
|
-
if (
|
|
7286
|
+
if (fixed.length > 0 || items.length > 0 || this.options.clearable) {
|
|
7217
7287
|
list.append(h("div", { class: "zx-select__separator", role: "presentation" }));
|
|
7218
7288
|
}
|
|
7219
7289
|
let actionGroup = /* @__PURE__ */ Symbol("initial-action-group");
|
|
@@ -7228,7 +7298,7 @@ var Select = class _Select extends Component {
|
|
|
7228
7298
|
this._appendAction(action);
|
|
7229
7299
|
}
|
|
7230
7300
|
}
|
|
7231
|
-
if (
|
|
7301
|
+
if (items.length === 0 && fixed.length === 0 && this._actions.length === 0 && !this._loading) {
|
|
7232
7302
|
list.append(h("div", {
|
|
7233
7303
|
class: "zx-select__empty",
|
|
7234
7304
|
role: "status"
|
|
@@ -7429,6 +7499,16 @@ var Select = class _Select extends Component {
|
|
|
7429
7499
|
_matchFixed(query) {
|
|
7430
7500
|
return matchItems(this._fixedItems, query, this._searchKeys());
|
|
7431
7501
|
}
|
|
7502
|
+
/** De-duplicates choices by public value while preserving caller order. @param {SelectItem[]} items @param {SelectItem[]} [excluded=[]] @returns {SelectItem[]} */
|
|
7503
|
+
_uniqueItems(items, excluded = []) {
|
|
7504
|
+
const values = excluded.map((item) => this._itemValue(item));
|
|
7505
|
+
return items.filter((item) => {
|
|
7506
|
+
const value = this._itemValue(item);
|
|
7507
|
+
if (values.some((candidate) => Object.is(candidate, value))) return false;
|
|
7508
|
+
values.push(value);
|
|
7509
|
+
return true;
|
|
7510
|
+
});
|
|
7511
|
+
}
|
|
7432
7512
|
/** @returns {number} */
|
|
7433
7513
|
_selectedEntryIndex() {
|
|
7434
7514
|
if (this._selected === null) return this.options.clearable ? 0 : -1;
|
|
@@ -7440,16 +7520,28 @@ var Select = class _Select extends Component {
|
|
|
7440
7520
|
_itemEntryIndex(itemIndex) {
|
|
7441
7521
|
return itemIndex + (this.options.clearable ? 1 : 0);
|
|
7442
7522
|
}
|
|
7443
|
-
/** @param {string} name @returns {void} */
|
|
7444
|
-
_rememberAttribute(element, name) {
|
|
7445
|
-
this._originalAttributes.set(name, element.getAttribute(name));
|
|
7446
|
-
}
|
|
7447
7523
|
/** @param {string} key @param {string} fallback @returns {string} */
|
|
7448
7524
|
_message(key, fallback) {
|
|
7449
7525
|
const message = this.msg(key);
|
|
7450
7526
|
return message === key ? fallback : message;
|
|
7451
7527
|
}
|
|
7452
7528
|
};
|
|
7529
|
+
function readSelectItem(item, reader) {
|
|
7530
|
+
if (typeof reader === "function") return reader(item);
|
|
7531
|
+
if (item !== null && typeof item === "object" && typeof reader === "string") return item[reader];
|
|
7532
|
+
return null;
|
|
7533
|
+
}
|
|
7534
|
+
function normalizeEntityCreateAction(value) {
|
|
7535
|
+
const descriptor = value === true ? {} : value;
|
|
7536
|
+
return {
|
|
7537
|
+
id: descriptor.id ?? "create",
|
|
7538
|
+
label: descriptor.label ?? "Create new\u2026",
|
|
7539
|
+
description: descriptor.description,
|
|
7540
|
+
group: descriptor.group ?? "New",
|
|
7541
|
+
icon: descriptor.icon ?? "plus",
|
|
7542
|
+
invoke: descriptor.invoke
|
|
7543
|
+
};
|
|
7544
|
+
}
|
|
7453
7545
|
function normalizeRenderedContent(rendered) {
|
|
7454
7546
|
return rendered && typeof rendered === "object" && "nodeType" in rendered ? (
|
|
7455
7547
|
/** @type {Node} */
|
|
@@ -7926,6 +8018,8 @@ var TagPicker = class extends Component {
|
|
|
7926
8018
|
values: [],
|
|
7927
8019
|
valueKey: "ID",
|
|
7928
8020
|
labelKey: "name",
|
|
8021
|
+
iconKey: "icon",
|
|
8022
|
+
colorKey: "color",
|
|
7929
8023
|
searchKeys: null,
|
|
7930
8024
|
filter: "local",
|
|
7931
8025
|
minQuery: 0,
|
|
@@ -8266,12 +8360,13 @@ var TagPicker = class extends Component {
|
|
|
8266
8360
|
_renderTags() {
|
|
8267
8361
|
const tags = this._selected.map((item) => {
|
|
8268
8362
|
const label = this._labelOf(item);
|
|
8269
|
-
const
|
|
8270
|
-
const
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8363
|
+
const color = this._colorOf(item);
|
|
8364
|
+
const content = this.options.renderTag ? this.options.renderTag(item) : [this._iconOf(item), h("span", { class: "zx-tag-picker__tag-label" }, label)];
|
|
8365
|
+
const tag = h("span", {
|
|
8366
|
+
class: "zx-tag-picker__tag",
|
|
8367
|
+
dataset: { colored: String(Boolean(color)) },
|
|
8368
|
+
style: color ? { "--zx-tag-color": color } : null
|
|
8369
|
+
}, content);
|
|
8275
8370
|
if (!this._readonly && !this._disabled) {
|
|
8276
8371
|
tag.append(h("button", {
|
|
8277
8372
|
class: "zx-icon-btn zx-tag-picker__remove",
|
|
@@ -8309,7 +8404,7 @@ var TagPicker = class extends Component {
|
|
|
8309
8404
|
h(
|
|
8310
8405
|
"span",
|
|
8311
8406
|
{ class: "zx-tag-picker__option-label" },
|
|
8312
|
-
this.options.renderItem ? this.options.renderItem(item) : this._labelOf(item)
|
|
8407
|
+
this.options.renderItem ? this.options.renderItem(item) : [this._iconOf(item), h("span", {}, this._labelOf(item))]
|
|
8313
8408
|
)
|
|
8314
8409
|
);
|
|
8315
8410
|
if (!selected && this.isFull()) option.setAttribute("aria-disabled", "true");
|
|
@@ -8534,10 +8629,10 @@ var TagPicker = class extends Component {
|
|
|
8534
8629
|
if (sequence !== this._requestSequence) return;
|
|
8535
8630
|
this._items = Array.isArray(result) ? result.slice() : [];
|
|
8536
8631
|
this._visible = this._items.slice();
|
|
8537
|
-
} catch (
|
|
8632
|
+
} catch (error2) {
|
|
8538
8633
|
if (sequence !== this._requestSequence) return;
|
|
8539
8634
|
this._visible = [];
|
|
8540
|
-
this.emit("error", { error });
|
|
8635
|
+
this.emit("error", { error: error2 });
|
|
8541
8636
|
} finally {
|
|
8542
8637
|
if (sequence === this._requestSequence) {
|
|
8543
8638
|
this._setLoading(false);
|
|
@@ -8630,6 +8725,34 @@ var TagPicker = class extends Component {
|
|
|
8630
8725
|
if (item !== null && typeof item === "object") return String(item[key] ?? "");
|
|
8631
8726
|
return String(item ?? "");
|
|
8632
8727
|
}
|
|
8728
|
+
/** @param {unknown} item @returns {Node|null} */
|
|
8729
|
+
_iconOf(item) {
|
|
8730
|
+
const value = this._readItem(item, this.options.iconKey);
|
|
8731
|
+
const visual = value && typeof value === "object" && typeof value.nodeType === "number" ? (
|
|
8732
|
+
/** @type {Node} */
|
|
8733
|
+
value.cloneNode(true)
|
|
8734
|
+
) : typeof value === "string" && value.trim() ? icon(value, { size: 12 }) : null;
|
|
8735
|
+
if (!visual) return null;
|
|
8736
|
+
return h("span", {
|
|
8737
|
+
class: "zx-tag-picker__visual",
|
|
8738
|
+
style: this._colorOf(item) ? { "--zx-tag-color": this._colorOf(item) } : null,
|
|
8739
|
+
ariaHidden: "true"
|
|
8740
|
+
}, visual);
|
|
8741
|
+
}
|
|
8742
|
+
/** @param {unknown} item @returns {string|null} */
|
|
8743
|
+
_colorOf(item) {
|
|
8744
|
+
const value = this._readItem(item, this.options.colorKey);
|
|
8745
|
+
return isCssColor(value) ? value : null;
|
|
8746
|
+
}
|
|
8747
|
+
/** @param {unknown} item @param {unknown} reader @returns {unknown} */
|
|
8748
|
+
_readItem(item, reader) {
|
|
8749
|
+
if (typeof reader === "function") return reader(
|
|
8750
|
+
/** @type {TagItem} */
|
|
8751
|
+
item
|
|
8752
|
+
);
|
|
8753
|
+
if (item !== null && typeof item === "object" && typeof reader === "string") return item[reader];
|
|
8754
|
+
return null;
|
|
8755
|
+
}
|
|
8633
8756
|
/** @returns {void} */
|
|
8634
8757
|
_emitChange() {
|
|
8635
8758
|
this.emit("change", { values: this.getValues(), items: this.getItems() });
|
|
@@ -9514,38 +9637,38 @@ var Http = class {
|
|
|
9514
9637
|
try {
|
|
9515
9638
|
json2 = JSON.parse(text4);
|
|
9516
9639
|
} catch (cause) {
|
|
9517
|
-
const
|
|
9640
|
+
const error2 = (
|
|
9518
9641
|
/** @type {Error & {response?: Response}} */
|
|
9519
9642
|
new Error("Invalid JSON response", { cause })
|
|
9520
9643
|
);
|
|
9521
|
-
|
|
9522
|
-
throw
|
|
9644
|
+
error2.response = response;
|
|
9645
|
+
throw error2;
|
|
9523
9646
|
}
|
|
9524
9647
|
}
|
|
9525
9648
|
if (!response.ok) {
|
|
9526
9649
|
try {
|
|
9527
9650
|
parseResult(json2);
|
|
9528
|
-
} catch (
|
|
9529
|
-
|
|
9530
|
-
throw
|
|
9651
|
+
} catch (error3) {
|
|
9652
|
+
error3.response = response;
|
|
9653
|
+
throw error3;
|
|
9531
9654
|
}
|
|
9532
|
-
const
|
|
9655
|
+
const error2 = (
|
|
9533
9656
|
/** @type {Error & {response?: Response}} */
|
|
9534
9657
|
new Error(`HTTP ${response.status} ${response.statusText}`.trim())
|
|
9535
9658
|
);
|
|
9536
|
-
|
|
9537
|
-
throw
|
|
9659
|
+
error2.response = response;
|
|
9660
|
+
throw error2;
|
|
9538
9661
|
}
|
|
9539
9662
|
return parseResult(json2);
|
|
9540
9663
|
} catch (caught) {
|
|
9541
|
-
const
|
|
9664
|
+
const error2 = caught instanceof Error ? caught : new Error(String(caught));
|
|
9542
9665
|
if (this.onError) {
|
|
9543
9666
|
try {
|
|
9544
|
-
this.onError(
|
|
9667
|
+
this.onError(error2, { path, options });
|
|
9545
9668
|
} catch {
|
|
9546
9669
|
}
|
|
9547
9670
|
}
|
|
9548
|
-
throw
|
|
9671
|
+
throw error2;
|
|
9549
9672
|
} finally {
|
|
9550
9673
|
if (timeoutId !== null) clearTimeout(timeoutId);
|
|
9551
9674
|
}
|
|
@@ -10262,9 +10385,9 @@ var Modal = class extends Component {
|
|
|
10262
10385
|
this.el.returnValue = "";
|
|
10263
10386
|
try {
|
|
10264
10387
|
this._show();
|
|
10265
|
-
} catch (
|
|
10388
|
+
} catch (error2) {
|
|
10266
10389
|
delete this.el.dataset.zxOverlayOrder;
|
|
10267
|
-
throw
|
|
10390
|
+
throw error2;
|
|
10268
10391
|
}
|
|
10269
10392
|
this.el.dataset.state = "open";
|
|
10270
10393
|
this.emit("open");
|
|
@@ -10747,9 +10870,9 @@ var Groupbox = class extends Component {
|
|
|
10747
10870
|
}
|
|
10748
10871
|
try {
|
|
10749
10872
|
super(normalizedTarget, options);
|
|
10750
|
-
} catch (
|
|
10873
|
+
} catch (error2) {
|
|
10751
10874
|
if (adoption) restoreAdoption(adoption);
|
|
10752
|
-
throw
|
|
10875
|
+
throw error2;
|
|
10753
10876
|
}
|
|
10754
10877
|
this._adoption = adoption;
|
|
10755
10878
|
}
|
|
@@ -11477,7 +11600,11 @@ var Table = class extends Component {
|
|
|
11477
11600
|
rowClass: null,
|
|
11478
11601
|
zebra: true,
|
|
11479
11602
|
editMode: false,
|
|
11480
|
-
|
|
11603
|
+
editTrigger: "double",
|
|
11604
|
+
hierarchy: false,
|
|
11605
|
+
rowReorder: false,
|
|
11606
|
+
columnVisibility: false,
|
|
11607
|
+
hiddenColumns: []
|
|
11481
11608
|
};
|
|
11482
11609
|
/**
|
|
11483
11610
|
* Creates a table around a target or creates a new root when target is null.
|
|
@@ -11506,6 +11633,7 @@ var Table = class extends Component {
|
|
|
11506
11633
|
this._rowElements = /* @__PURE__ */ new Map();
|
|
11507
11634
|
this._restored = false;
|
|
11508
11635
|
this._editMode = normalizeEditMode(this.options.editMode);
|
|
11636
|
+
this._editTrigger = this.options.editTrigger === "single" ? "single" : "double";
|
|
11509
11637
|
this._edit = null;
|
|
11510
11638
|
this._editMessage = null;
|
|
11511
11639
|
this._stacked = false;
|
|
@@ -11517,6 +11645,10 @@ var Table = class extends Component {
|
|
|
11517
11645
|
this._rovingCell = null;
|
|
11518
11646
|
this._rovingMatched = false;
|
|
11519
11647
|
this._hierarchy = normalizeHierarchy(this.options.hierarchy, this._columns);
|
|
11648
|
+
this._hiddenColumns = new Set((Array.isArray(this.options.hiddenColumns) ? this.options.hiddenColumns : []).map(String).filter((id) => this._columns.some((column) => column.id === id)));
|
|
11649
|
+
if (this._hiddenColumns.size >= this._columns.length && this._columns[0]) this._hiddenColumns.delete(this._columns[0].id);
|
|
11650
|
+
this._dragId = null;
|
|
11651
|
+
this._grabbedId = null;
|
|
11520
11652
|
this._expanded = initialExpanded(this._hierarchy?.expanded);
|
|
11521
11653
|
if (this._sort && this.options.sortMode === "local") this._sortData();
|
|
11522
11654
|
if (this._hierarchy?.expanded === true) {
|
|
@@ -11538,11 +11670,17 @@ var Table = class extends Component {
|
|
|
11538
11670
|
zebra: String(Boolean(this.options.zebra))
|
|
11539
11671
|
}
|
|
11540
11672
|
}, this._table);
|
|
11673
|
+
this._rowMoveMessage = this.options.rowReorder ? h("div", {
|
|
11674
|
+
class: "zx-table__reorder-status",
|
|
11675
|
+
role: "status",
|
|
11676
|
+
ariaLive: "polite"
|
|
11677
|
+
}) : null;
|
|
11541
11678
|
if (this.options.height != null) {
|
|
11542
11679
|
this._scroll.style.blockSize = typeof this.options.height === "number" ? `${this.options.height}px` : String(this.options.height);
|
|
11543
11680
|
}
|
|
11681
|
+
this._columnControls = this.options.columnVisibility ? this._createColumnControls() : null;
|
|
11544
11682
|
if (this._editMode === false) {
|
|
11545
|
-
root.replaceChildren(this._scroll);
|
|
11683
|
+
root.replaceChildren(...[this._columnControls, this._scroll, this._rowMoveMessage].filter(Boolean));
|
|
11546
11684
|
} else {
|
|
11547
11685
|
root.dataset.editMode = this._editMode;
|
|
11548
11686
|
this._editMessage = h("div", {
|
|
@@ -11551,7 +11689,7 @@ var Table = class extends Component {
|
|
|
11551
11689
|
role: "status",
|
|
11552
11690
|
ariaLive: "polite"
|
|
11553
11691
|
});
|
|
11554
|
-
root.replaceChildren(this._scroll, this._editMessage);
|
|
11692
|
+
root.replaceChildren(...[this._columnControls, this._scroll, this._editMessage, this._rowMoveMessage].filter(Boolean));
|
|
11555
11693
|
}
|
|
11556
11694
|
this._renderColumns();
|
|
11557
11695
|
this._renderHeader();
|
|
@@ -11559,6 +11697,34 @@ var Table = class extends Component {
|
|
|
11559
11697
|
this._watchWidth();
|
|
11560
11698
|
this.listen(this._tbody, "click", (event) => this._handleBodyClick(event));
|
|
11561
11699
|
this.listen(this._tbody, "dblclick", (event) => this._handleBodyDoubleClick(event));
|
|
11700
|
+
if (this.options.rowReorder) {
|
|
11701
|
+
this.listen(this._tbody, "dragstart", (event) => this._handleRowDragStart(
|
|
11702
|
+
/** @type {DragEvent} */
|
|
11703
|
+
event
|
|
11704
|
+
));
|
|
11705
|
+
this.listen(this._tbody, "dragover", (event) => this._handleRowDragOver(
|
|
11706
|
+
/** @type {DragEvent} */
|
|
11707
|
+
event
|
|
11708
|
+
));
|
|
11709
|
+
this.listen(this._tbody, "drop", (event) => this._handleRowDrop(
|
|
11710
|
+
/** @type {DragEvent} */
|
|
11711
|
+
event
|
|
11712
|
+
));
|
|
11713
|
+
this.listen(this._tbody, "dragend", () => this._clearRowDrag());
|
|
11714
|
+
this.listen(this._tbody, "keydown", (event) => this._handleRowHandleKeydown(
|
|
11715
|
+
/** @type {KeyboardEvent} */
|
|
11716
|
+
event
|
|
11717
|
+
));
|
|
11718
|
+
}
|
|
11719
|
+
if (this._columnControls) {
|
|
11720
|
+
this.listen(this._columnControls, "change", (event) => {
|
|
11721
|
+
const input = (
|
|
11722
|
+
/** @type {HTMLInputElement|null} */
|
|
11723
|
+
event.target
|
|
11724
|
+
);
|
|
11725
|
+
if (input?.classList.contains("zx-table__column-toggle")) this.setColumnVisible(input.value, input.checked);
|
|
11726
|
+
});
|
|
11727
|
+
}
|
|
11562
11728
|
if (this._editMode !== false) {
|
|
11563
11729
|
this.listen(this._tbody, "keydown", (event) => this._handleEditKeydown(
|
|
11564
11730
|
/** @type {KeyboardEvent} */
|
|
@@ -11674,6 +11840,81 @@ var Table = class extends Component {
|
|
|
11674
11840
|
getData() {
|
|
11675
11841
|
return [...this._data];
|
|
11676
11842
|
}
|
|
11843
|
+
/** Returns visible column IDs in caller order. @returns {string[]} */
|
|
11844
|
+
getVisibleColumns() {
|
|
11845
|
+
return this._visibleColumns().map((column) => column.id);
|
|
11846
|
+
}
|
|
11847
|
+
/** Returns hidden column IDs in caller order. @returns {string[]} */
|
|
11848
|
+
getHiddenColumns() {
|
|
11849
|
+
return this._columns.filter((column) => this._hiddenColumns.has(column.id)).map((column) => column.id);
|
|
11850
|
+
}
|
|
11851
|
+
/**
|
|
11852
|
+
* Shows or hides one column. The final visible column cannot be hidden.
|
|
11853
|
+
* @param {string} id Column ID.
|
|
11854
|
+
* @param {boolean} [visible=true] Desired visibility.
|
|
11855
|
+
* @param {{silent?:boolean}} [options={}] Event behavior.
|
|
11856
|
+
* @returns {this}
|
|
11857
|
+
*/
|
|
11858
|
+
setColumnVisible(id, visible = true, options = {}) {
|
|
11859
|
+
const column = this._columns.find((candidate) => candidate.id === id);
|
|
11860
|
+
if (!column) throw new RangeError(`Unknown table column: ${id}`);
|
|
11861
|
+
const active = (
|
|
11862
|
+
/** @type {HTMLElement|null} */
|
|
11863
|
+
document.activeElement
|
|
11864
|
+
);
|
|
11865
|
+
const restoreFocus = active?.classList.contains("zx-table__column-toggle") && this._columnList?.contains(active) ? (
|
|
11866
|
+
/** @type {HTMLInputElement} */
|
|
11867
|
+
active.value
|
|
11868
|
+
) : null;
|
|
11869
|
+
if (!visible && !this._hiddenColumns.has(id) && this._visibleColumns().length <= 1) {
|
|
11870
|
+
this._renderColumnControls(restoreFocus);
|
|
11871
|
+
return this;
|
|
11872
|
+
}
|
|
11873
|
+
const changed = visible ? this._hiddenColumns.delete(id) : !this._hiddenColumns.has(id);
|
|
11874
|
+
if (!visible && changed) this._hiddenColumns.add(id);
|
|
11875
|
+
if (!changed) return this;
|
|
11876
|
+
this._renderColumns();
|
|
11877
|
+
this._renderHeader();
|
|
11878
|
+
this._renderBody();
|
|
11879
|
+
this._renderColumnControls(restoreFocus);
|
|
11880
|
+
if (!options.silent) this.emit("columnvisibilitychange", {
|
|
11881
|
+
visible: this.getVisibleColumns(),
|
|
11882
|
+
hidden: this.getHiddenColumns()
|
|
11883
|
+
});
|
|
11884
|
+
return this;
|
|
11885
|
+
}
|
|
11886
|
+
/** Toggles one column. @param {string} id @param {{silent?:boolean}} [options={}] @returns {this} */
|
|
11887
|
+
toggleColumn(id, options = {}) {
|
|
11888
|
+
return this.setColumnVisible(id, this._hiddenColumns.has(id), options);
|
|
11889
|
+
}
|
|
11890
|
+
/**
|
|
11891
|
+
* Reorders one row relative to another and emits a cancelable `rowmove` before committing.
|
|
11892
|
+
* Hierarchical rows may only move among siblings; an active local sort disables manual order.
|
|
11893
|
+
* @param {unknown} id Moving row ID.
|
|
11894
|
+
* @param {unknown} targetId Target row ID.
|
|
11895
|
+
* @param {'before'|'after'} [position='before'] Target edge.
|
|
11896
|
+
* @returns {this}
|
|
11897
|
+
*/
|
|
11898
|
+
moveRow(id, targetId, position2 = "before") {
|
|
11899
|
+
if (!this.options.rowReorder || this._sort && this.options.sortMode === "local") return this;
|
|
11900
|
+
const row2 = this.getRow(id);
|
|
11901
|
+
const target = this.getRow(targetId);
|
|
11902
|
+
if (!row2 || !target || Object.is(id, targetId)) return this;
|
|
11903
|
+
const next = reorderTableRows(this._data, this.options.rowId, id, targetId, position2, this._hierarchy?.parentId);
|
|
11904
|
+
if (!next) return this;
|
|
11905
|
+
const event = this.emit("rowmove", { row: row2, id, target, targetId, position: position2 });
|
|
11906
|
+
if (event.defaultPrevented) return this;
|
|
11907
|
+
this._data = next;
|
|
11908
|
+
this._renderBody();
|
|
11909
|
+
if (this._rowMoveMessage) {
|
|
11910
|
+
const siblings = this._siblingIds(id);
|
|
11911
|
+
const index = siblings.findIndex((candidate) => Object.is(candidate, id));
|
|
11912
|
+
this._rowMoveMessage.textContent = `Moved row to position ${index + 1} of ${siblings.length}.`;
|
|
11913
|
+
}
|
|
11914
|
+
this._emitDataChange();
|
|
11915
|
+
queueMicrotask(() => this._rowHandle(id)?.focus());
|
|
11916
|
+
return this;
|
|
11917
|
+
}
|
|
11677
11918
|
/**
|
|
11678
11919
|
* Removes all rows.
|
|
11679
11920
|
* @returns {this}
|
|
@@ -11842,14 +12083,17 @@ var Table = class extends Component {
|
|
|
11842
12083
|
*/
|
|
11843
12084
|
startEdit(rowId, columnId) {
|
|
11844
12085
|
if (this._editMode === false) return this;
|
|
11845
|
-
const
|
|
11846
|
-
if (!
|
|
12086
|
+
const requested = this._columns.find((candidate) => candidate.id === columnId);
|
|
12087
|
+
if (!requested) return this;
|
|
11847
12088
|
const current = this._data.find((candidate) => Object.is(this._idFor(candidate), rowId));
|
|
11848
|
-
if (current === void 0
|
|
12089
|
+
if (current === void 0) return this;
|
|
12090
|
+
const column = this._editMode === "row" && this._hiddenColumns.has(requested.id) ? this._visibleColumns().find((candidate) => resolveEditable(candidate, current) !== false) ?? null : requested;
|
|
12091
|
+
if (!column || resolveEditable(column, current) === false) return this;
|
|
12092
|
+
const activeColumnId = column.id;
|
|
11849
12093
|
if (this._edit) {
|
|
11850
|
-
if (Object.is(this._edit.id, rowId) && this._edit.cells.has(
|
|
11851
|
-
this._edit.columnId =
|
|
11852
|
-
this._focusEditor(
|
|
12094
|
+
if (Object.is(this._edit.id, rowId) && this._edit.cells.has(activeColumnId)) {
|
|
12095
|
+
this._edit.columnId = activeColumnId;
|
|
12096
|
+
this._focusEditor(activeColumnId);
|
|
11853
12097
|
return this;
|
|
11854
12098
|
}
|
|
11855
12099
|
this.commitEdit();
|
|
@@ -11860,7 +12104,7 @@ var Table = class extends Component {
|
|
|
11860
12104
|
const row2 = this._data[index];
|
|
11861
12105
|
const tr = this._rowElements.get(rowId)?.[0];
|
|
11862
12106
|
if (!tr) return this;
|
|
11863
|
-
const targets = this._editMode === "row" ? this.
|
|
12107
|
+
const targets = this._editMode === "row" ? this._visibleColumns().filter((candidate) => resolveEditable(candidate, row2) !== false) : [column];
|
|
11864
12108
|
const cells = /* @__PURE__ */ new Map();
|
|
11865
12109
|
for (const target of targets) {
|
|
11866
12110
|
const td = cellIn(tr, target.id);
|
|
@@ -11869,10 +12113,10 @@ var Table = class extends Component {
|
|
|
11869
12113
|
if (entry) cells.set(target.id, entry);
|
|
11870
12114
|
}
|
|
11871
12115
|
if (cells.size === 0) return this;
|
|
11872
|
-
this._edit = { id: rowId, columnId, row: row2, cells, tr };
|
|
12116
|
+
this._edit = { id: rowId, columnId: activeColumnId, row: row2, cells, tr };
|
|
11873
12117
|
tr.dataset.editing = "true";
|
|
11874
|
-
this.emit("editstart", { row: row2, id: rowId, column, columnId, value: row2?.[
|
|
11875
|
-
this._focusEditor(
|
|
12118
|
+
this.emit("editstart", { row: row2, id: rowId, column, columnId: activeColumnId, value: row2?.[activeColumnId] });
|
|
12119
|
+
this._focusEditor(activeColumnId);
|
|
11876
12120
|
return this;
|
|
11877
12121
|
}
|
|
11878
12122
|
/**
|
|
@@ -12127,16 +12371,197 @@ var Table = class extends Component {
|
|
|
12127
12371
|
}
|
|
12128
12372
|
super.destroy();
|
|
12129
12373
|
}
|
|
12374
|
+
/** @returns {TableColumn[]} */
|
|
12375
|
+
_visibleColumns() {
|
|
12376
|
+
return this._columns.filter((column) => !this._hiddenColumns.has(column.id));
|
|
12377
|
+
}
|
|
12378
|
+
/** @returns {HTMLElement} */
|
|
12379
|
+
_createColumnControls() {
|
|
12380
|
+
const list = h("div", { class: "zx-table__column-list" });
|
|
12381
|
+
this._columnList = list;
|
|
12382
|
+
const details = h(
|
|
12383
|
+
"details",
|
|
12384
|
+
{ class: "zx-table__column-controls" },
|
|
12385
|
+
h("summary", { class: "zx-button zx-button--sm" }, icon("fields", { size: 13 }), "Columns"),
|
|
12386
|
+
list
|
|
12387
|
+
);
|
|
12388
|
+
this._renderColumnControls();
|
|
12389
|
+
return details;
|
|
12390
|
+
}
|
|
12391
|
+
/** @param {string|null} [focusColumn=null] Column checkbox that keeps focus. @returns {void} */
|
|
12392
|
+
_renderColumnControls(focusColumn = null) {
|
|
12393
|
+
if (!this._columnList) return;
|
|
12394
|
+
const visible = this._visibleColumns();
|
|
12395
|
+
const current = [...this._columnList.querySelectorAll(".zx-table__column-toggle")];
|
|
12396
|
+
const reusable = current.length === this._columns.length && current.every((control, index) => (
|
|
12397
|
+
/** @type {HTMLInputElement} */
|
|
12398
|
+
control.value === this._columns[index].id
|
|
12399
|
+
));
|
|
12400
|
+
if (reusable) {
|
|
12401
|
+
current.forEach((control, index) => {
|
|
12402
|
+
const input = (
|
|
12403
|
+
/** @type {HTMLInputElement} */
|
|
12404
|
+
control
|
|
12405
|
+
);
|
|
12406
|
+
const checked = !this._hiddenColumns.has(this._columns[index].id);
|
|
12407
|
+
input.checked = checked;
|
|
12408
|
+
input.disabled = checked && visible.length === 1;
|
|
12409
|
+
});
|
|
12410
|
+
return;
|
|
12411
|
+
}
|
|
12412
|
+
this._columnList.replaceChildren(...this._columns.map((column) => {
|
|
12413
|
+
const checked = !this._hiddenColumns.has(column.id);
|
|
12414
|
+
return h(
|
|
12415
|
+
"label",
|
|
12416
|
+
{ class: "zx-table__column-option" },
|
|
12417
|
+
h("input", {
|
|
12418
|
+
class: "zx-table__column-toggle",
|
|
12419
|
+
type: "checkbox",
|
|
12420
|
+
value: column.id,
|
|
12421
|
+
checked,
|
|
12422
|
+
disabled: checked && visible.length === 1
|
|
12423
|
+
}),
|
|
12424
|
+
h("span", {}, column.label)
|
|
12425
|
+
);
|
|
12426
|
+
}));
|
|
12427
|
+
if (focusColumn !== null) {
|
|
12428
|
+
const control = [...this._columnList.querySelectorAll(".zx-table__column-toggle")].find((candidate) => (
|
|
12429
|
+
/** @type {HTMLInputElement} */
|
|
12430
|
+
candidate.value === focusColumn
|
|
12431
|
+
));
|
|
12432
|
+
queueMicrotask(() => {
|
|
12433
|
+
if (control?.isConnected) control.focus();
|
|
12434
|
+
});
|
|
12435
|
+
}
|
|
12436
|
+
}
|
|
12437
|
+
/** @param {DragEvent} event @returns {void} */
|
|
12438
|
+
_handleRowDragStart(event) {
|
|
12439
|
+
const handle = (
|
|
12440
|
+
/** @type {Element|null} */
|
|
12441
|
+
event.target?.closest?.(".zx-table__row-handle")
|
|
12442
|
+
);
|
|
12443
|
+
const rowElement = handle?.closest("tr[data-row]");
|
|
12444
|
+
const meta = rowElement ? this._rowMeta.get(rowElement) : null;
|
|
12445
|
+
if (!handle || !meta || this._sort && this.options.sortMode === "local") {
|
|
12446
|
+
event.preventDefault();
|
|
12447
|
+
return;
|
|
12448
|
+
}
|
|
12449
|
+
this._dragId = meta.id;
|
|
12450
|
+
rowElement.dataset.dragging = "true";
|
|
12451
|
+
event.dataTransfer?.setData("text/plain", "zx-table-row");
|
|
12452
|
+
if (event.dataTransfer) event.dataTransfer.effectAllowed = "move";
|
|
12453
|
+
}
|
|
12454
|
+
/** @param {DragEvent} event @returns {void} */
|
|
12455
|
+
_handleRowDragOver(event) {
|
|
12456
|
+
if (this._dragId == null) return;
|
|
12457
|
+
const rowElement = (
|
|
12458
|
+
/** @type {Element|null} */
|
|
12459
|
+
event.target?.closest?.("tr[data-row]")
|
|
12460
|
+
);
|
|
12461
|
+
const meta = rowElement ? this._rowMeta.get(rowElement) : null;
|
|
12462
|
+
if (!meta || Object.is(meta.id, this._dragId) || !this._canMoveTogether(this._dragId, meta.id)) return;
|
|
12463
|
+
event.preventDefault();
|
|
12464
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
|
|
12465
|
+
this._clearDropMarkers();
|
|
12466
|
+
const rectangle = rowElement.getBoundingClientRect();
|
|
12467
|
+
rowElement.dataset.drop = event.clientY >= rectangle.top + rectangle.height / 2 ? "after" : "before";
|
|
12468
|
+
}
|
|
12469
|
+
/** @param {DragEvent} event @returns {void} */
|
|
12470
|
+
_handleRowDrop(event) {
|
|
12471
|
+
if (this._dragId == null) return;
|
|
12472
|
+
const rowElement = (
|
|
12473
|
+
/** @type {Element|null} */
|
|
12474
|
+
event.target?.closest?.("tr[data-row]")
|
|
12475
|
+
);
|
|
12476
|
+
const meta = rowElement ? this._rowMeta.get(rowElement) : null;
|
|
12477
|
+
const position2 = rowElement?.dataset.drop === "after" ? "after" : "before";
|
|
12478
|
+
if (meta && this._canMoveTogether(this._dragId, meta.id)) {
|
|
12479
|
+
event.preventDefault();
|
|
12480
|
+
this.moveRow(this._dragId, meta.id, position2);
|
|
12481
|
+
}
|
|
12482
|
+
this._clearRowDrag();
|
|
12483
|
+
}
|
|
12484
|
+
/** @param {KeyboardEvent} event @returns {void} */
|
|
12485
|
+
_handleRowHandleKeydown(event) {
|
|
12486
|
+
const handle = (
|
|
12487
|
+
/** @type {Element|null} */
|
|
12488
|
+
event.target?.closest?.(".zx-table__row-handle")
|
|
12489
|
+
);
|
|
12490
|
+
const rowElement = handle?.closest("tr[data-row]");
|
|
12491
|
+
const meta = rowElement ? this._rowMeta.get(rowElement) : null;
|
|
12492
|
+
if (!handle || !meta) return;
|
|
12493
|
+
if (event.key === " " || event.key === "Enter") {
|
|
12494
|
+
event.preventDefault();
|
|
12495
|
+
this._grabbedId = Object.is(this._grabbedId, meta.id) ? null : meta.id;
|
|
12496
|
+
handle.setAttribute("aria-pressed", String(this._grabbedId != null));
|
|
12497
|
+
const status = this._rowMoveMessage ?? this._editMessage;
|
|
12498
|
+
if (status) status.textContent = this._grabbedId == null ? "Row dropped" : "Row grabbed. Use the arrow keys to move it.";
|
|
12499
|
+
return;
|
|
12500
|
+
}
|
|
12501
|
+
if (event.key === "Escape" && this._grabbedId != null) {
|
|
12502
|
+
event.preventDefault();
|
|
12503
|
+
this._grabbedId = null;
|
|
12504
|
+
handle.setAttribute("aria-pressed", "false");
|
|
12505
|
+
return;
|
|
12506
|
+
}
|
|
12507
|
+
if (!Object.is(this._grabbedId, meta.id) || !["ArrowUp", "ArrowDown"].includes(event.key)) return;
|
|
12508
|
+
event.preventDefault();
|
|
12509
|
+
const siblings = this._siblingIds(meta.id);
|
|
12510
|
+
const index = siblings.findIndex((id) => Object.is(id, meta.id));
|
|
12511
|
+
const targetId = siblings[index + (event.key === "ArrowUp" ? -1 : 1)];
|
|
12512
|
+
if (targetId !== void 0) this.moveRow(meta.id, targetId, event.key === "ArrowUp" ? "before" : "after");
|
|
12513
|
+
}
|
|
12514
|
+
/** @param {unknown} id @returns {unknown[]} */
|
|
12515
|
+
_siblingIds(id) {
|
|
12516
|
+
const row2 = this.getRow(id);
|
|
12517
|
+
if (!row2) return [];
|
|
12518
|
+
const parent = this._hierarchy ? readRowValue(this._hierarchy.parentId, row2) : null;
|
|
12519
|
+
return this._data.filter((candidate) => !this._hierarchy || sameHierarchyParent(readRowValue(this._hierarchy.parentId, candidate), parent)).map((candidate) => this._idFor(candidate));
|
|
12520
|
+
}
|
|
12521
|
+
/** @param {unknown} left @param {unknown} right @returns {boolean} */
|
|
12522
|
+
_canMoveTogether(left, right) {
|
|
12523
|
+
if (!this._hierarchy) return true;
|
|
12524
|
+
const a = this.getRow(left);
|
|
12525
|
+
const b = this.getRow(right);
|
|
12526
|
+
return Boolean(a && b && sameHierarchyParent(
|
|
12527
|
+
readRowValue(this._hierarchy.parentId, a),
|
|
12528
|
+
readRowValue(this._hierarchy.parentId, b)
|
|
12529
|
+
));
|
|
12530
|
+
}
|
|
12531
|
+
/** @param {unknown} id @returns {HTMLElement|null} */
|
|
12532
|
+
_rowHandle(id) {
|
|
12533
|
+
return (
|
|
12534
|
+
/** @type {HTMLElement|null} */
|
|
12535
|
+
this._rowElements.get(id)?.[0]?.querySelector(".zx-table__row-handle") ?? null
|
|
12536
|
+
);
|
|
12537
|
+
}
|
|
12538
|
+
/** @returns {void} */
|
|
12539
|
+
_clearDropMarkers() {
|
|
12540
|
+
for (const row2 of this._tbody.querySelectorAll("tr[data-drop]")) delete row2.dataset.drop;
|
|
12541
|
+
}
|
|
12542
|
+
/** @returns {void} */
|
|
12543
|
+
_clearRowDrag() {
|
|
12544
|
+
for (const row2 of this._tbody.querySelectorAll("tr[data-dragging]")) delete row2.dataset.dragging;
|
|
12545
|
+
this._clearDropMarkers();
|
|
12546
|
+
this._dragId = null;
|
|
12547
|
+
}
|
|
12548
|
+
/** @returns {string|null} */
|
|
12549
|
+
_hierarchyColumn() {
|
|
12550
|
+
if (!this._hierarchy) return null;
|
|
12551
|
+
return this._visibleColumns().some((column) => column.id === this._hierarchy.column) ? this._hierarchy.column : this._visibleColumns()[0]?.id ?? null;
|
|
12552
|
+
}
|
|
12130
12553
|
/** @returns {void} */
|
|
12131
12554
|
_renderColumns() {
|
|
12132
12555
|
const fragment2 = document.createDocumentFragment();
|
|
12556
|
+
if (this.options.rowReorder) fragment2.append(h("col", { class: "zx-table__reorder-column" }));
|
|
12133
12557
|
if (this.options.selectable === "multi") {
|
|
12134
12558
|
fragment2.append(h("col", { class: "zx-table__selection-column" }));
|
|
12135
12559
|
}
|
|
12136
|
-
const
|
|
12560
|
+
const columns = this._visibleColumns();
|
|
12561
|
+
const fractions = columns.map((column) => parseFraction(column.width));
|
|
12137
12562
|
const total = fractions.reduce((sum, value) => sum + value, 0);
|
|
12138
12563
|
this._table.dataset.layout = total > 0 ? "fixed" : "auto";
|
|
12139
|
-
|
|
12564
|
+
columns.forEach((column, index) => {
|
|
12140
12565
|
const col = h("col");
|
|
12141
12566
|
if (fractions[index] > 0) col.style.width = `${fractions[index] / total * 100}%`;
|
|
12142
12567
|
else if (column.width && column.width !== "auto") col.style.width = String(column.width);
|
|
@@ -12148,6 +12573,11 @@ var Table = class extends Component {
|
|
|
12148
12573
|
_renderHeader() {
|
|
12149
12574
|
const row2 = h("tr", { class: "zx-table__header-row" });
|
|
12150
12575
|
if (this._growStep) row2.setAttribute("aria-rowindex", "1");
|
|
12576
|
+
if (this.options.rowReorder) row2.append(h("th", {
|
|
12577
|
+
class: "zx-table__reorder-header",
|
|
12578
|
+
scope: "col",
|
|
12579
|
+
ariaLabel: "Row order"
|
|
12580
|
+
}));
|
|
12151
12581
|
if (this.options.selectable === "multi") {
|
|
12152
12582
|
this._selectAll = h("input", {
|
|
12153
12583
|
class: "zx-table__checkbox zx-table__select-all",
|
|
@@ -12173,7 +12603,7 @@ var Table = class extends Component {
|
|
|
12173
12603
|
this._selectAll = null;
|
|
12174
12604
|
}
|
|
12175
12605
|
this._headers = /* @__PURE__ */ new Map();
|
|
12176
|
-
for (const column of this.
|
|
12606
|
+
for (const column of this._visibleColumns()) {
|
|
12177
12607
|
const th = h("th", { scope: "col" });
|
|
12178
12608
|
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
12179
12609
|
if (align) th.dataset.align = align;
|
|
@@ -12213,7 +12643,7 @@ var Table = class extends Component {
|
|
|
12213
12643
|
{ class: "zx-table__empty-row" },
|
|
12214
12644
|
h("td", {
|
|
12215
12645
|
class: "zx-table__empty",
|
|
12216
|
-
colspan: this.
|
|
12646
|
+
colspan: this._visibleColumns().length + (this.options.selectable === "multi" ? 1 : 0) + (this.options.rowReorder ? 1 : 0)
|
|
12217
12647
|
}, this._emptyContent())
|
|
12218
12648
|
));
|
|
12219
12649
|
} else {
|
|
@@ -12222,6 +12652,7 @@ var Table = class extends Component {
|
|
|
12222
12652
|
});
|
|
12223
12653
|
}
|
|
12224
12654
|
this._tbody.replaceChildren(fragment2);
|
|
12655
|
+
this._table.setAttribute("aria-colcount", String(this._visibleColumns().length + (this.options.selectable === "multi" ? 1 : 0) + (this.options.rowReorder ? 1 : 0)));
|
|
12225
12656
|
if (this._growStep) this._table.setAttribute("aria-rowcount", String(projected.length + 1));
|
|
12226
12657
|
this._syncSelectAll();
|
|
12227
12658
|
this._syncGrowing();
|
|
@@ -12265,6 +12696,19 @@ var Table = class extends Component {
|
|
|
12265
12696
|
const elements = this._rowElements.get(id) ?? [];
|
|
12266
12697
|
elements.push(tr);
|
|
12267
12698
|
this._rowElements.set(id, elements);
|
|
12699
|
+
if (this.options.rowReorder) {
|
|
12700
|
+
const handle = h("button", {
|
|
12701
|
+
class: "zx-table__row-handle",
|
|
12702
|
+
type: "button",
|
|
12703
|
+
draggable: true,
|
|
12704
|
+
dataset: { rowHandle: "" },
|
|
12705
|
+
ariaLabel: `Move row ${index + 1}`,
|
|
12706
|
+
ariaPressed: String(Object.is(this._grabbedId, id)),
|
|
12707
|
+
disabled: Boolean(this._sort && this.options.sortMode === "local"),
|
|
12708
|
+
title: this._sort && this.options.sortMode === "local" ? "Clear sorting to reorder rows" : null
|
|
12709
|
+
}, icon("drag", { size: 14 }));
|
|
12710
|
+
tr.append(h("td", { class: "zx-table__reorder-cell" }, handle));
|
|
12711
|
+
}
|
|
12268
12712
|
if (this.options.selectable === "multi") {
|
|
12269
12713
|
const checkbox = h("input", {
|
|
12270
12714
|
class: "zx-table__checkbox zx-table__row-checkbox",
|
|
@@ -12274,7 +12718,7 @@ var Table = class extends Component {
|
|
|
12274
12718
|
});
|
|
12275
12719
|
tr.append(h("td", { class: "zx-table__selection-cell" }, checkbox));
|
|
12276
12720
|
}
|
|
12277
|
-
this.
|
|
12721
|
+
this._visibleColumns().forEach((column) => {
|
|
12278
12722
|
const cell = (
|
|
12279
12723
|
/** @type {HTMLTableCellElement} */
|
|
12280
12724
|
h("td")
|
|
@@ -12310,7 +12754,7 @@ var Table = class extends Component {
|
|
|
12310
12754
|
const content = h("span", { class: "zx-table__cell-content" });
|
|
12311
12755
|
if (value && typeof value === "object" && typeof value.nodeType === "number") content.append(value);
|
|
12312
12756
|
else if (value != null) content.append(document.createTextNode(String(value)));
|
|
12313
|
-
if (!this._hierarchy || column.id !== this.
|
|
12757
|
+
if (!this._hierarchy || column.id !== this._hierarchyColumn() || !tree) {
|
|
12314
12758
|
cell.replaceChildren(...content.childNodes);
|
|
12315
12759
|
return;
|
|
12316
12760
|
}
|
|
@@ -12341,6 +12785,7 @@ var Table = class extends Component {
|
|
|
12341
12785
|
if (!rowElement || !this._tbody.contains(rowElement)) return;
|
|
12342
12786
|
const meta = this._rowMeta.get(rowElement);
|
|
12343
12787
|
if (!meta) return;
|
|
12788
|
+
if (target.closest(".zx-table__row-handle")) return;
|
|
12344
12789
|
if (this._edit) {
|
|
12345
12790
|
this.commitEdit();
|
|
12346
12791
|
if (this._edit) return;
|
|
@@ -12360,6 +12805,14 @@ var Table = class extends Component {
|
|
|
12360
12805
|
);
|
|
12361
12806
|
return;
|
|
12362
12807
|
}
|
|
12808
|
+
if (isInteractiveCellContent(target)) return;
|
|
12809
|
+
if (this._editMode !== false && this._editTrigger === "single") {
|
|
12810
|
+
const cell = target?.closest('td[data-editable="true"]');
|
|
12811
|
+
if (cell && this._tbody.contains(cell)) {
|
|
12812
|
+
this.startEdit(meta.id, String(cell.dataset.column));
|
|
12813
|
+
return;
|
|
12814
|
+
}
|
|
12815
|
+
}
|
|
12363
12816
|
this.emit("rowclick", { ...meta, event });
|
|
12364
12817
|
if (this.options.selectable === "single" && !this._selected.has(meta.id)) {
|
|
12365
12818
|
this._selected = /* @__PURE__ */ new Set([meta.id]);
|
|
@@ -12380,7 +12833,8 @@ var Table = class extends Component {
|
|
|
12380
12833
|
if (!rowElement || !this._tbody.contains(rowElement)) return;
|
|
12381
12834
|
const meta = this._rowMeta.get(rowElement);
|
|
12382
12835
|
if (!meta) return;
|
|
12383
|
-
if (
|
|
12836
|
+
if (isInteractiveCellContent(target)) return;
|
|
12837
|
+
if (this._editMode !== false && this._editTrigger === "double") {
|
|
12384
12838
|
const cell = target?.closest('td[data-editable="true"]');
|
|
12385
12839
|
if (cell && this._tbody.contains(cell)) {
|
|
12386
12840
|
this.startEdit(meta.id, String(cell.dataset.column));
|
|
@@ -12682,13 +13136,14 @@ var Table = class extends Component {
|
|
|
12682
13136
|
* @returns {{id: unknown, columnId: string, index: number}|null} Next cell, or null at the end.
|
|
12683
13137
|
*/
|
|
12684
13138
|
_nextEditableCell(rowIndex, columnId, direction) {
|
|
12685
|
-
const
|
|
13139
|
+
const columns = this._visibleColumns();
|
|
13140
|
+
const columnCount = columns.length;
|
|
12686
13141
|
if (rowIndex < 0 || columnCount === 0) return null;
|
|
12687
13142
|
const visible = this._visibleData();
|
|
12688
13143
|
const startingId = this._idFor(this._data[rowIndex]);
|
|
12689
13144
|
let row2 = visible.findIndex((candidate) => Object.is(this._idFor(candidate), startingId));
|
|
12690
13145
|
if (row2 < 0) return null;
|
|
12691
|
-
let column =
|
|
13146
|
+
let column = columns.findIndex((candidate) => candidate.id === columnId);
|
|
12692
13147
|
const limit = visible.length * columnCount + columnCount;
|
|
12693
13148
|
for (let step = 0; step < limit; step += 1) {
|
|
12694
13149
|
column += direction;
|
|
@@ -12701,7 +13156,7 @@ var Table = class extends Component {
|
|
|
12701
13156
|
}
|
|
12702
13157
|
if (row2 < 0 || row2 >= visible.length) return null;
|
|
12703
13158
|
const candidateRow = visible[row2];
|
|
12704
|
-
const candidateColumn =
|
|
13159
|
+
const candidateColumn = columns[column];
|
|
12705
13160
|
if (resolveEditable(candidateColumn, candidateRow) !== false) {
|
|
12706
13161
|
return {
|
|
12707
13162
|
id: this._idFor(candidateRow),
|
|
@@ -12944,6 +13399,53 @@ function sortHierarchyRows(rows, rowId, parentId, getValue, direction) {
|
|
|
12944
13399
|
}
|
|
12945
13400
|
return result;
|
|
12946
13401
|
}
|
|
13402
|
+
function reorderTableRows(rows, rowId, id, targetId, position2 = "before", parentId = null) {
|
|
13403
|
+
if (!Array.isArray(rows) || Object.is(id, targetId)) return null;
|
|
13404
|
+
const from = rows.findIndex((row2) => Object.is(readRowValue(rowId, row2), id));
|
|
13405
|
+
const target = rows.findIndex((row2) => Object.is(readRowValue(rowId, row2), targetId));
|
|
13406
|
+
if (from < 0 || target < 0) return null;
|
|
13407
|
+
if (parentId && !sameHierarchyParent(
|
|
13408
|
+
readRowValue(parentId, rows[from]),
|
|
13409
|
+
readRowValue(parentId, rows[target])
|
|
13410
|
+
)) return null;
|
|
13411
|
+
if (parentId) {
|
|
13412
|
+
const forest = hierarchyForest(rows, rowId, parentId);
|
|
13413
|
+
const movingNode = forest.nodes[from];
|
|
13414
|
+
const targetNode = forest.nodes[target];
|
|
13415
|
+
if (!movingNode || !targetNode || movingNode.parent !== targetNode.parent) return null;
|
|
13416
|
+
const branchNodes = (root) => {
|
|
13417
|
+
const result = [];
|
|
13418
|
+
const stack2 = [root];
|
|
13419
|
+
while (stack2.length) {
|
|
13420
|
+
const node = (
|
|
13421
|
+
/** @type {TableHierarchyNode} */
|
|
13422
|
+
stack2.pop()
|
|
13423
|
+
);
|
|
13424
|
+
result.push(node);
|
|
13425
|
+
for (let index = node.children.length - 1; index >= 0; index -= 1) stack2.push(node.children[index]);
|
|
13426
|
+
}
|
|
13427
|
+
return result;
|
|
13428
|
+
};
|
|
13429
|
+
const moving2 = new Set(branchNodes(movingNode).map((node) => node.index));
|
|
13430
|
+
const targetBranch = new Set(branchNodes(targetNode).map((node) => node.index));
|
|
13431
|
+
const block = rows.filter((_row, index) => moving2.has(index));
|
|
13432
|
+
const remaining = rows.filter((_row, index) => !moving2.has(index));
|
|
13433
|
+
const remainingSourceIndexes = rows.map((_row, index) => index).filter((index) => !moving2.has(index));
|
|
13434
|
+
let insertion = remainingSourceIndexes.findIndex((index) => index === target);
|
|
13435
|
+
if (position2 === "after") {
|
|
13436
|
+
const targetPositions = remainingSourceIndexes.map((sourceIndex, index) => targetBranch.has(sourceIndex) ? index : -1).filter((index) => index >= 0);
|
|
13437
|
+
insertion = Math.max(...targetPositions) + 1;
|
|
13438
|
+
}
|
|
13439
|
+
if (insertion < 0) return null;
|
|
13440
|
+
remaining.splice(insertion, 0, ...block);
|
|
13441
|
+
return remaining;
|
|
13442
|
+
}
|
|
13443
|
+
const next = [...rows];
|
|
13444
|
+
const [moving] = next.splice(from, 1);
|
|
13445
|
+
const adjustedTarget = next.findIndex((row2) => Object.is(readRowValue(rowId, row2), targetId));
|
|
13446
|
+
next.splice(adjustedTarget + (position2 === "after" ? 1 : 0), 0, moving);
|
|
13447
|
+
return next;
|
|
13448
|
+
}
|
|
12947
13449
|
function resolveEditable(column, row2) {
|
|
12948
13450
|
if (!column || typeof column !== "object") return false;
|
|
12949
13451
|
if (typeof column.editor === "function") {
|
|
@@ -13024,7 +13526,8 @@ function hierarchyForest(rows, rowId, parentId) {
|
|
|
13024
13526
|
for (const node of nodes) if (!byId.has(node.id)) byId.set(node.id, node);
|
|
13025
13527
|
const parentOf = /* @__PURE__ */ new Map();
|
|
13026
13528
|
for (const node of nodes) {
|
|
13027
|
-
const
|
|
13529
|
+
const parentValue = readRowValue(parentId, node.row);
|
|
13530
|
+
const parent = parentValue == null ? null : byId.get(parentValue) ?? null;
|
|
13028
13531
|
parentOf.set(node, parent === node ? null : parent);
|
|
13029
13532
|
}
|
|
13030
13533
|
for (const node of nodes) {
|
|
@@ -13053,6 +13556,9 @@ function hierarchyBranchIds(rows, rowId, parentId) {
|
|
|
13053
13556
|
function readRowValue(accessor, row2) {
|
|
13054
13557
|
return typeof accessor === "function" ? accessor(row2) : row2?.[accessor];
|
|
13055
13558
|
}
|
|
13559
|
+
function sameHierarchyParent(left, right) {
|
|
13560
|
+
return left == null && right == null || Object.is(left, right);
|
|
13561
|
+
}
|
|
13056
13562
|
function normalizeHierarchy(option, columns) {
|
|
13057
13563
|
if (!option || typeof option !== "object") return null;
|
|
13058
13564
|
const parentId = option.parentId;
|
|
@@ -13072,6 +13578,23 @@ function normalizeEditMode(mode) {
|
|
|
13072
13578
|
function isInsideEditor(target) {
|
|
13073
13579
|
return Boolean(target?.closest?.(".zx-table__editor"));
|
|
13074
13580
|
}
|
|
13581
|
+
function isInteractiveCellContent(target) {
|
|
13582
|
+
const cell = target?.closest?.("td[data-column]");
|
|
13583
|
+
const interactive = target?.closest?.([
|
|
13584
|
+
"a[href]",
|
|
13585
|
+
"button",
|
|
13586
|
+
"input",
|
|
13587
|
+
"select",
|
|
13588
|
+
"textarea",
|
|
13589
|
+
"summary",
|
|
13590
|
+
'[contenteditable="true"]',
|
|
13591
|
+
'[role="button"]',
|
|
13592
|
+
'[role="link"]',
|
|
13593
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
13594
|
+
"[data-zx-table-no-edit]"
|
|
13595
|
+
].join(","));
|
|
13596
|
+
return Boolean(cell && interactive && interactive !== cell && cell.contains(interactive));
|
|
13597
|
+
}
|
|
13075
13598
|
function deferToEditor(target) {
|
|
13076
13599
|
if (target.closest("[popover]")) return true;
|
|
13077
13600
|
return target.getAttribute?.("aria-expanded") === "true";
|
|
@@ -15560,11 +16083,11 @@ var Card = class extends Component {
|
|
|
15560
16083
|
this.setFooter(this.options.footer);
|
|
15561
16084
|
this.setLink(this.options.link);
|
|
15562
16085
|
return root;
|
|
15563
|
-
} catch (
|
|
16086
|
+
} catch (error2) {
|
|
15564
16087
|
this._actionAbort?.abort();
|
|
15565
16088
|
this._linkAbort?.abort();
|
|
15566
16089
|
if (!created) restoreTarget(root, this._original);
|
|
15567
|
-
throw
|
|
16090
|
+
throw error2;
|
|
15568
16091
|
}
|
|
15569
16092
|
}
|
|
15570
16093
|
/** Replaces the card title. @param {string} title Next title. @returns {this} */
|
|
@@ -15608,9 +16131,9 @@ var Card = class extends Component {
|
|
|
15608
16131
|
if (onclick) control.addEventListener("click", onclick, { signal: nextAbort.signal });
|
|
15609
16132
|
return control;
|
|
15610
16133
|
});
|
|
15611
|
-
} catch (
|
|
16134
|
+
} catch (error2) {
|
|
15612
16135
|
nextAbort.abort();
|
|
15613
|
-
throw
|
|
16136
|
+
throw error2;
|
|
15614
16137
|
}
|
|
15615
16138
|
this._actionAbort?.abort();
|
|
15616
16139
|
this._actionAbort = nextAbort;
|
|
@@ -19051,6 +19574,106 @@ function count(value) {
|
|
|
19051
19574
|
return value.toLocaleString();
|
|
19052
19575
|
}
|
|
19053
19576
|
|
|
19577
|
+
// src/components/app-icon/app-icon.js
|
|
19578
|
+
var AppIcon = class extends Component {
|
|
19579
|
+
static cssName = "app-icon";
|
|
19580
|
+
/** @type {Readonly<AppIconOptions>} */
|
|
19581
|
+
static defaults = {
|
|
19582
|
+
icon: null,
|
|
19583
|
+
color: null,
|
|
19584
|
+
size: 36,
|
|
19585
|
+
iconSize: "52%",
|
|
19586
|
+
label: null,
|
|
19587
|
+
badge: null,
|
|
19588
|
+
selected: false,
|
|
19589
|
+
glass: "subtle",
|
|
19590
|
+
class: []
|
|
19591
|
+
};
|
|
19592
|
+
/** @returns {HTMLElement} */
|
|
19593
|
+
render() {
|
|
19594
|
+
this._createdRoot = this.el === null;
|
|
19595
|
+
const root = (
|
|
19596
|
+
/** @type {HTMLElement} */
|
|
19597
|
+
this.el ?? h("span")
|
|
19598
|
+
);
|
|
19599
|
+
this.el = root;
|
|
19600
|
+
this._snapshot = this._createdRoot ? null : snapshotTarget(root);
|
|
19601
|
+
this._state = { ...this.options };
|
|
19602
|
+
this._appliedClasses = [];
|
|
19603
|
+
this._sync();
|
|
19604
|
+
return root;
|
|
19605
|
+
}
|
|
19606
|
+
/** Updates identity or presentation without replacing the root. @param {Partial<AppIconOptions>} values @returns {this} */
|
|
19607
|
+
set(values = {}) {
|
|
19608
|
+
if (!values || typeof values !== "object") return this;
|
|
19609
|
+
Object.assign(this._state, values);
|
|
19610
|
+
this._sync();
|
|
19611
|
+
return this;
|
|
19612
|
+
}
|
|
19613
|
+
/** Restores an enhanced target. @returns {void} */
|
|
19614
|
+
destroy() {
|
|
19615
|
+
const root = this.el;
|
|
19616
|
+
const snapshot10 = this._snapshot;
|
|
19617
|
+
super.destroy();
|
|
19618
|
+
if (!this._createdRoot && root) restoreTarget(root, snapshot10);
|
|
19619
|
+
}
|
|
19620
|
+
/** @returns {void} */
|
|
19621
|
+
_sync() {
|
|
19622
|
+
const state = this._state;
|
|
19623
|
+
this.el.classList.remove(...this._appliedClasses);
|
|
19624
|
+
this._appliedClasses = [state.class].flat().flatMap((value) => String(value ?? "").split(/\s+/)).filter(Boolean);
|
|
19625
|
+
this.el.classList.add(...this._appliedClasses);
|
|
19626
|
+
const size2 = cssLength2(state.size, "36px");
|
|
19627
|
+
const glyphSize = cssLength2(state.iconSize, "52%");
|
|
19628
|
+
this.el.style.setProperty("--zx-app-icon-size", size2);
|
|
19629
|
+
this.el.style.setProperty("--zx-app-icon-glyph-size", glyphSize);
|
|
19630
|
+
if (isCssColor(state.color)) this.el.style.setProperty("--zx-app-icon-color", String(state.color));
|
|
19631
|
+
else this.el.style.removeProperty("--zx-app-icon-color");
|
|
19632
|
+
this.el.dataset.glass = normalizeGlass(state.glass);
|
|
19633
|
+
this.el.toggleAttribute("data-selected", Boolean(state.selected));
|
|
19634
|
+
const label = state.label == null ? "" : String(state.label).trim();
|
|
19635
|
+
if (label) {
|
|
19636
|
+
this.el.setAttribute("role", "img");
|
|
19637
|
+
this.el.setAttribute("aria-label", label);
|
|
19638
|
+
this.el.removeAttribute("aria-hidden");
|
|
19639
|
+
} else {
|
|
19640
|
+
this.el.removeAttribute("role");
|
|
19641
|
+
this.el.removeAttribute("aria-label");
|
|
19642
|
+
this.el.setAttribute("aria-hidden", "true");
|
|
19643
|
+
}
|
|
19644
|
+
const visual = resolveVisual(state.icon);
|
|
19645
|
+
const badge2 = state.badge == null || state.badge === "" ? null : h("span", {
|
|
19646
|
+
class: "zx-app-icon__badge",
|
|
19647
|
+
ariaHidden: "true"
|
|
19648
|
+
}, String(state.badge));
|
|
19649
|
+
this.el.replaceChildren(
|
|
19650
|
+
h("span", { class: "zx-app-icon__shine", ariaHidden: "true" }),
|
|
19651
|
+
h("span", { class: "zx-app-icon__glyph", ariaHidden: "true" }, visual),
|
|
19652
|
+
badge2
|
|
19653
|
+
);
|
|
19654
|
+
}
|
|
19655
|
+
};
|
|
19656
|
+
function appIcon(options = {}) {
|
|
19657
|
+
return new AppIcon(null, options).toElement();
|
|
19658
|
+
}
|
|
19659
|
+
function resolveVisual(value) {
|
|
19660
|
+
const resolved = typeof value === "function" ? value() : value;
|
|
19661
|
+
if (typeof resolved === "string") return icon(resolved, { size: "1em" });
|
|
19662
|
+
return resolved && typeof resolved === "object" && typeof resolved.nodeType === "number" ? (
|
|
19663
|
+
/** @type {Node} */
|
|
19664
|
+
resolved
|
|
19665
|
+
) : null;
|
|
19666
|
+
}
|
|
19667
|
+
function cssLength2(value, fallback) {
|
|
19668
|
+
if (typeof value === "number" && Number.isFinite(value)) return `${Math.max(1, value)}px`;
|
|
19669
|
+
const text4 = String(value ?? "").trim();
|
|
19670
|
+
return text4 && !/[;{}]/.test(text4) ? text4 : fallback;
|
|
19671
|
+
}
|
|
19672
|
+
function normalizeGlass(value) {
|
|
19673
|
+
if (value === false || value === "none") return "none";
|
|
19674
|
+
return value === "strong" ? "strong" : "subtle";
|
|
19675
|
+
}
|
|
19676
|
+
|
|
19054
19677
|
// src/components/launcher/launcher.js
|
|
19055
19678
|
var Launcher = class extends Component {
|
|
19056
19679
|
static cssName = "launcher";
|
|
@@ -19320,9 +19943,9 @@ var Launcher = class extends Component {
|
|
|
19320
19943
|
itemOrder: item.itemOrder ?? (source.order === "source" ? itemOrder : void 0)
|
|
19321
19944
|
})));
|
|
19322
19945
|
this._renderResults();
|
|
19323
|
-
} catch (
|
|
19946
|
+
} catch (error2) {
|
|
19324
19947
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
19325
|
-
this.emit("error", { source, error });
|
|
19948
|
+
this.emit("error", { source, error: error2 });
|
|
19326
19949
|
}
|
|
19327
19950
|
}));
|
|
19328
19951
|
if (request.signal.aborted || sequence !== this._requestSequence) return;
|
|
@@ -20092,7 +20715,7 @@ var Tooltip = class extends Component {
|
|
|
20092
20715
|
this.#content = this.options.content;
|
|
20093
20716
|
this.#disabled = Boolean(this.options.disabled);
|
|
20094
20717
|
this.#describedBy = resolved.getAttribute("aria-describedby");
|
|
20095
|
-
this.el.style.setProperty("--zx-tooltip-max-inline-size",
|
|
20718
|
+
this.el.style.setProperty("--zx-tooltip-max-inline-size", cssLength3(this.options.maxWidth));
|
|
20096
20719
|
const trigger = TRIGGERS.has(this.options.trigger) ? this.options.trigger : "both";
|
|
20097
20720
|
if (trigger === "manual") return;
|
|
20098
20721
|
if (trigger === "hover" || trigger === "both") {
|
|
@@ -20350,7 +20973,7 @@ function appendToken(list, token) {
|
|
|
20350
20973
|
if (!tokens.includes(token)) tokens.push(token);
|
|
20351
20974
|
return tokens.join(" ");
|
|
20352
20975
|
}
|
|
20353
|
-
function
|
|
20976
|
+
function cssLength3(value) {
|
|
20354
20977
|
return typeof value === "number" && Number.isFinite(value) ? `${value}px` : String(value);
|
|
20355
20978
|
}
|
|
20356
20979
|
function isFocusVisible(element) {
|
|
@@ -22851,7 +23474,7 @@ var Grid = class _Grid extends Table {
|
|
|
22851
23474
|
* @param {GridOptions & import('../table/table.js').TableOptions} [options={}] Grid/Table options.
|
|
22852
23475
|
*/
|
|
22853
23476
|
constructor(target = null, options = {}) {
|
|
22854
|
-
super(target, options);
|
|
23477
|
+
super(target, { editTrigger: "single", ...options });
|
|
22855
23478
|
}
|
|
22856
23479
|
/**
|
|
22857
23480
|
* Creates an editable hierarchical billing-line grid.
|
|
@@ -22890,6 +23513,9 @@ function billingItemsConfig(options = {}) {
|
|
|
22890
23513
|
return {
|
|
22891
23514
|
rowId: fields.id,
|
|
22892
23515
|
editMode: "cell",
|
|
23516
|
+
editTrigger: "single",
|
|
23517
|
+
rowReorder: true,
|
|
23518
|
+
columnVisibility: true,
|
|
22893
23519
|
hierarchy: { parentId: fields.parent, column: fields.item, expanded: true },
|
|
22894
23520
|
responsive: "sm",
|
|
22895
23521
|
...tableOptions,
|
|
@@ -23121,8 +23747,8 @@ var Chart = class extends Component {
|
|
|
23121
23747
|
return this;
|
|
23122
23748
|
}
|
|
23123
23749
|
/** Shows an error and destroys the current engine. @param {unknown} error @returns {this} */
|
|
23124
|
-
setError(
|
|
23125
|
-
this._error =
|
|
23750
|
+
setError(error2) {
|
|
23751
|
+
this._error = error2 ?? new Error(String(this.options.errorText));
|
|
23126
23752
|
this._hasError = true;
|
|
23127
23753
|
this._loading = false;
|
|
23128
23754
|
this._destroyHandle();
|
|
@@ -23141,8 +23767,8 @@ var Chart = class extends Component {
|
|
|
23141
23767
|
resize() {
|
|
23142
23768
|
try {
|
|
23143
23769
|
this._handle?.resize?.();
|
|
23144
|
-
} catch (
|
|
23145
|
-
this.setError(
|
|
23770
|
+
} catch (error2) {
|
|
23771
|
+
this.setError(error2);
|
|
23146
23772
|
}
|
|
23147
23773
|
return this;
|
|
23148
23774
|
}
|
|
@@ -23195,8 +23821,8 @@ var Chart = class extends Component {
|
|
|
23195
23821
|
this.emit("ready", { instance: this.getInstance() });
|
|
23196
23822
|
}
|
|
23197
23823
|
if (emitUpdate) this.emit("update", { data: this._data, type: this._type });
|
|
23198
|
-
} catch (
|
|
23199
|
-
this.setError(
|
|
23824
|
+
} catch (error2) {
|
|
23825
|
+
this.setError(error2);
|
|
23200
23826
|
}
|
|
23201
23827
|
}
|
|
23202
23828
|
/** @returns {ChartSpec} */
|
|
@@ -23438,8 +24064,8 @@ function themeChartOptions(root) {
|
|
|
23438
24064
|
borderColor: borderColor || void 0
|
|
23439
24065
|
};
|
|
23440
24066
|
}
|
|
23441
|
-
function errorMessage(
|
|
23442
|
-
const message =
|
|
24067
|
+
function errorMessage(error2, fallback) {
|
|
24068
|
+
const message = error2 && typeof error2 === "object" && "message" in error2 ? String(error2.message) : "";
|
|
23443
24069
|
return message.trim() ? message : String(fallback);
|
|
23444
24070
|
}
|
|
23445
24071
|
|
|
@@ -24078,8 +24704,8 @@ var TreeView = class extends Component {
|
|
|
24078
24704
|
node[this._childrenKey] = Array.isArray(children) ? children : [];
|
|
24079
24705
|
if (node[this._childrenKey].length === 0) node.hasChildren = false;
|
|
24080
24706
|
return true;
|
|
24081
|
-
} catch (
|
|
24082
|
-
this.emit("error", { error, node, id });
|
|
24707
|
+
} catch (error2) {
|
|
24708
|
+
this.emit("error", { error: error2, node, id });
|
|
24083
24709
|
return false;
|
|
24084
24710
|
} finally {
|
|
24085
24711
|
this._loading.delete(id);
|
|
@@ -24567,9 +25193,9 @@ var Finder = class extends Component {
|
|
|
24567
25193
|
const children = await this.options.load(node);
|
|
24568
25194
|
node[this._childrenKey] = Array.isArray(children) ? children : [];
|
|
24569
25195
|
if (node[this._childrenKey].length === 0) node.hasChildren = false;
|
|
24570
|
-
} catch (
|
|
25196
|
+
} catch (error2) {
|
|
24571
25197
|
node[this._childrenKey] = [];
|
|
24572
|
-
this.emit("error", { error, node, id });
|
|
25198
|
+
this.emit("error", { error: error2, node, id });
|
|
24573
25199
|
} finally {
|
|
24574
25200
|
this._loading.delete(id);
|
|
24575
25201
|
}
|
|
@@ -24999,6 +25625,821 @@ function restoreCustomElements(origins) {
|
|
|
24999
25625
|
}
|
|
25000
25626
|
}
|
|
25001
25627
|
|
|
25628
|
+
// src/components/filter/filter-model.js
|
|
25629
|
+
var filterOperators = Object.freeze([
|
|
25630
|
+
op("contains", "contains", "single", ["text"]),
|
|
25631
|
+
op("notContains", "does not contain", "single", ["text"]),
|
|
25632
|
+
op("eq", "is", "single", ["text", "number", "money", "boolean", "enum", "status", "priority", "country", "currency", "unit", "entity", "date", "datetime"]),
|
|
25633
|
+
op("neq", "is not", "single", ["text", "number", "money", "boolean", "enum", "status", "priority", "country", "currency", "unit", "entity", "date", "datetime"]),
|
|
25634
|
+
op("startsWith", "starts with", "single", ["text"]),
|
|
25635
|
+
op("endsWith", "ends with", "single", ["text"]),
|
|
25636
|
+
op("lt", "is less than", "single", ["number", "money"]),
|
|
25637
|
+
op("lte", "is at most", "single", ["number", "money"]),
|
|
25638
|
+
op("gt", "is greater than", "single", ["number", "money"]),
|
|
25639
|
+
op("gte", "is at least", "single", ["number", "money"]),
|
|
25640
|
+
op("on", "is on", "single", ["date", "datetime"]),
|
|
25641
|
+
op("notOn", "is not on", "single", ["date", "datetime"]),
|
|
25642
|
+
op("before", "is before", "single", ["date", "datetime"]),
|
|
25643
|
+
op("onOrBefore", "is on or before", "single", ["date", "datetime"]),
|
|
25644
|
+
op("after", "is after", "single", ["date", "datetime"]),
|
|
25645
|
+
op("onOrAfter", "is on or after", "single", ["date", "datetime"]),
|
|
25646
|
+
op("between", "is between", "pair", ["number", "money", "date", "datetime"]),
|
|
25647
|
+
op("notBetween", "is not between", "pair", ["number", "money", "date", "datetime"]),
|
|
25648
|
+
op("withinLast", "is within the last", "pair", ["date", "datetime"]),
|
|
25649
|
+
op("withinNext", "is within the next", "pair", ["date", "datetime"]),
|
|
25650
|
+
op("anyOf", "is any of", "many", ["enum", "status", "priority", "country", "currency", "unit", "entity"]),
|
|
25651
|
+
op("noneOf", "is none of", "many", ["enum", "status", "priority", "country", "currency", "unit", "entity"]),
|
|
25652
|
+
op("containsAny", "contains any", "many", ["tags"]),
|
|
25653
|
+
op("containsAll", "contains all", "many", ["tags"]),
|
|
25654
|
+
op("containsNone", "contains none", "many", ["tags"]),
|
|
25655
|
+
op("isEmpty", "is empty", "none", ["text", "number", "money", "date", "datetime", "boolean", "enum", "status", "priority", "country", "currency", "unit", "entity", "tags"]),
|
|
25656
|
+
op("isNotEmpty", "is not empty", "none", ["text", "number", "money", "date", "datetime", "boolean", "enum", "status", "priority", "country", "currency", "unit", "entity", "tags"])
|
|
25657
|
+
]);
|
|
25658
|
+
function emptyFilterAst() {
|
|
25659
|
+
return { version: 1, root: { kind: "group", id: uid("filter-root"), logic: "and", children: [] } };
|
|
25660
|
+
}
|
|
25661
|
+
function filterCondition(initial = {}) {
|
|
25662
|
+
return {
|
|
25663
|
+
kind: "condition",
|
|
25664
|
+
id: String(initial.id || uid("filter-condition")),
|
|
25665
|
+
field: String(initial.field ?? ""),
|
|
25666
|
+
operator: String(initial.operator ?? ""),
|
|
25667
|
+
value: cloneFilterValue(initial.value ?? null)
|
|
25668
|
+
};
|
|
25669
|
+
}
|
|
25670
|
+
function cloneFilterValue(value) {
|
|
25671
|
+
return cloneJson(value);
|
|
25672
|
+
}
|
|
25673
|
+
function filterGroup(logic = "and", children = []) {
|
|
25674
|
+
return { kind: "group", id: uid("filter-group"), logic, children };
|
|
25675
|
+
}
|
|
25676
|
+
function parseFilterAst(value, limits = {}) {
|
|
25677
|
+
const maxDepth = finiteLimit(limits.maxDepth, 3);
|
|
25678
|
+
const maxConditions = finiteLimit(limits.maxConditions, 50);
|
|
25679
|
+
if (!plainObject(value) || value.version !== 1 || !plainObject(value.root)) {
|
|
25680
|
+
throw new TypeError("Filter AST must have version 1 and a root group");
|
|
25681
|
+
}
|
|
25682
|
+
const ids = /* @__PURE__ */ new Set();
|
|
25683
|
+
let conditions = 0;
|
|
25684
|
+
const visit = (raw2, depth, root2 = false) => {
|
|
25685
|
+
if (!plainObject(raw2)) throw new TypeError("Filter nodes must be plain objects");
|
|
25686
|
+
const id = String(raw2.id ?? "").trim();
|
|
25687
|
+
if (!id || ids.has(id)) throw new TypeError("Filter node IDs must be non-empty and unique");
|
|
25688
|
+
ids.add(id);
|
|
25689
|
+
if (raw2.kind === "group") {
|
|
25690
|
+
if (depth > maxDepth) throw new RangeError("Filter group depth exceeds maxDepth");
|
|
25691
|
+
if (raw2.logic !== "and" && raw2.logic !== "or") throw new TypeError("Filter group logic must be and or or");
|
|
25692
|
+
if (!Array.isArray(raw2.children)) throw new TypeError("Filter group children must be an array");
|
|
25693
|
+
return {
|
|
25694
|
+
kind: "group",
|
|
25695
|
+
id,
|
|
25696
|
+
logic: raw2.logic,
|
|
25697
|
+
children: raw2.children.map((child) => visit(child, depth + 1, false))
|
|
25698
|
+
};
|
|
25699
|
+
}
|
|
25700
|
+
if (root2 || raw2.kind !== "condition") throw new TypeError("Filter root must be a group");
|
|
25701
|
+
conditions += 1;
|
|
25702
|
+
if (conditions > maxConditions) throw new RangeError("Filter condition count exceeds maxConditions");
|
|
25703
|
+
return {
|
|
25704
|
+
kind: "condition",
|
|
25705
|
+
id,
|
|
25706
|
+
field: String(raw2.field ?? ""),
|
|
25707
|
+
operator: String(raw2.operator ?? ""),
|
|
25708
|
+
value: cloneJson(raw2.value)
|
|
25709
|
+
};
|
|
25710
|
+
};
|
|
25711
|
+
const root = visit(value.root, 0, true);
|
|
25712
|
+
if (root.kind !== "group") throw new TypeError("Filter root must be a group");
|
|
25713
|
+
return (
|
|
25714
|
+
/** @type {FilterAst} */
|
|
25715
|
+
{ version: 1, root }
|
|
25716
|
+
);
|
|
25717
|
+
}
|
|
25718
|
+
function cloneFilterAst(value) {
|
|
25719
|
+
return parseFilterAst(value, { maxDepth: Infinity, maxConditions: Infinity });
|
|
25720
|
+
}
|
|
25721
|
+
function stringifyFilterAst(value) {
|
|
25722
|
+
return JSON.stringify(cloneFilterAst(value));
|
|
25723
|
+
}
|
|
25724
|
+
function validateFilterAst(ast, fields, operators = filterOperators) {
|
|
25725
|
+
const errors = [];
|
|
25726
|
+
const fieldMap = new Map((Array.isArray(fields) ? fields : []).map((field) => [String(field.id), field]));
|
|
25727
|
+
const operatorMap = new Map((Array.isArray(operators) ? operators : []).map((operator) => [String(operator.id), operator]));
|
|
25728
|
+
const visit = (node, root = false) => {
|
|
25729
|
+
if (node.kind === "group") {
|
|
25730
|
+
if (!root && node.children.length === 0) errors.push(error(node.id, "empty-group", "Nested groups need at least one condition"));
|
|
25731
|
+
node.children.forEach((child) => visit(child));
|
|
25732
|
+
return;
|
|
25733
|
+
}
|
|
25734
|
+
const field = fieldMap.get(node.field);
|
|
25735
|
+
if (!field) errors.push(error(node.id, "unknown-field", node.field ? `Unavailable field: ${node.field}` : "Choose a field"));
|
|
25736
|
+
const operator = operatorMap.get(node.operator);
|
|
25737
|
+
if (!operator) {
|
|
25738
|
+
errors.push(error(node.id, "unknown-operator", node.operator ? `Unavailable operator: ${node.operator}` : "Choose an operator"));
|
|
25739
|
+
return;
|
|
25740
|
+
}
|
|
25741
|
+
if (field) {
|
|
25742
|
+
const allowed = Array.isArray(field.operators) && field.operators.length ? field.operators : operators.filter((candidate) => candidate.types.includes(field.type)).map((candidate) => candidate.id);
|
|
25743
|
+
if (!allowed.includes(operator.id) || !operator.types.includes(field.type)) {
|
|
25744
|
+
errors.push(error(node.id, "operator-type", `${operator.label} is not available for ${field.label}`));
|
|
25745
|
+
}
|
|
25746
|
+
}
|
|
25747
|
+
if (!validArity(operator.arity, node.value)) {
|
|
25748
|
+
errors.push(error(node.id, "value", operator.arity === "pair" ? "Enter both values" : operator.arity === "many" ? "Choose at least one value" : operator.arity === "none" ? "This operator does not accept a value" : "Enter a value"));
|
|
25749
|
+
}
|
|
25750
|
+
};
|
|
25751
|
+
visit(ast.root, true);
|
|
25752
|
+
return { valid: errors.length === 0, errors };
|
|
25753
|
+
}
|
|
25754
|
+
function op(id, label, arity, types) {
|
|
25755
|
+
return Object.freeze({ id, label, arity, types: Object.freeze(types) });
|
|
25756
|
+
}
|
|
25757
|
+
function error(nodeId, code, message) {
|
|
25758
|
+
return { nodeId, code, message };
|
|
25759
|
+
}
|
|
25760
|
+
function validArity(arity, value) {
|
|
25761
|
+
if (arity === "none") return value === null;
|
|
25762
|
+
if (arity === "pair") return Array.isArray(value) && value.length === 2 && value.every(filled);
|
|
25763
|
+
if (arity === "many") return Array.isArray(value) && value.length > 0 && value.every(filled);
|
|
25764
|
+
return filled(value);
|
|
25765
|
+
}
|
|
25766
|
+
function filled(value) {
|
|
25767
|
+
return value !== null && value !== void 0 && !(typeof value === "string" && value.trim() === "");
|
|
25768
|
+
}
|
|
25769
|
+
function cloneJson(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
25770
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
25771
|
+
if (typeof value === "number") {
|
|
25772
|
+
if (!Number.isFinite(value)) throw new TypeError("Filter values cannot contain non-finite numbers");
|
|
25773
|
+
return value;
|
|
25774
|
+
}
|
|
25775
|
+
if (typeof value !== "object" || value instanceof Date || typeof value.nodeType === "number") {
|
|
25776
|
+
throw new TypeError("Filter values must be JSON-safe");
|
|
25777
|
+
}
|
|
25778
|
+
if (seen.has(value)) throw new TypeError("Filter values cannot contain cycles");
|
|
25779
|
+
seen.add(value);
|
|
25780
|
+
if (Array.isArray(value)) {
|
|
25781
|
+
const result2 = value.map((item) => cloneJson(item, seen));
|
|
25782
|
+
seen.delete(value);
|
|
25783
|
+
return result2;
|
|
25784
|
+
}
|
|
25785
|
+
if (!plainObject(value)) throw new TypeError("Filter values must be plain JSON objects");
|
|
25786
|
+
const result = {};
|
|
25787
|
+
for (const [key, item] of Object.entries(value)) {
|
|
25788
|
+
Object.defineProperty(result, key, {
|
|
25789
|
+
value: cloneJson(item, seen),
|
|
25790
|
+
enumerable: true,
|
|
25791
|
+
configurable: true,
|
|
25792
|
+
writable: true
|
|
25793
|
+
});
|
|
25794
|
+
}
|
|
25795
|
+
seen.delete(value);
|
|
25796
|
+
return result;
|
|
25797
|
+
}
|
|
25798
|
+
function plainObject(value) {
|
|
25799
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
25800
|
+
const prototype = Object.getPrototypeOf(value);
|
|
25801
|
+
return prototype === Object.prototype || prototype === null;
|
|
25802
|
+
}
|
|
25803
|
+
function finiteLimit(value, fallback) {
|
|
25804
|
+
if (value === Infinity) return Infinity;
|
|
25805
|
+
const number2 = Number(value);
|
|
25806
|
+
return Number.isFinite(number2) && number2 >= 0 ? Math.floor(number2) : fallback;
|
|
25807
|
+
}
|
|
25808
|
+
|
|
25809
|
+
// src/components/filter/filter.js
|
|
25810
|
+
var Filter = class extends Component {
|
|
25811
|
+
static cssName = "filter";
|
|
25812
|
+
/** @type {Readonly<FilterOptions>} */
|
|
25813
|
+
static defaults = {
|
|
25814
|
+
fields: [],
|
|
25815
|
+
value: null,
|
|
25816
|
+
operators: [],
|
|
25817
|
+
allowGroups: true,
|
|
25818
|
+
maxDepth: 3,
|
|
25819
|
+
maxConditions: 50,
|
|
25820
|
+
autoApply: false,
|
|
25821
|
+
readonly: false,
|
|
25822
|
+
disabled: false,
|
|
25823
|
+
applyLabel: "Apply filters",
|
|
25824
|
+
clearLabel: "Clear"
|
|
25825
|
+
};
|
|
25826
|
+
/** @returns {HTMLElement} */
|
|
25827
|
+
render() {
|
|
25828
|
+
this._createdRoot = this.el === null;
|
|
25829
|
+
const root = (
|
|
25830
|
+
/** @type {HTMLElement} */
|
|
25831
|
+
this.el ?? h("div")
|
|
25832
|
+
);
|
|
25833
|
+
this.el = root;
|
|
25834
|
+
this._snapshot = this._createdRoot ? null : snapshotTarget(root);
|
|
25835
|
+
this._fields = (Array.isArray(this.options.fields) ? this.options.fields : []).map((field) => ({ ...field }));
|
|
25836
|
+
this._operators = mergeOperators(filterOperators, this.options.operators);
|
|
25837
|
+
this._readonly = Boolean(this.options.readonly);
|
|
25838
|
+
this._disabled = Boolean(this.options.disabled);
|
|
25839
|
+
this._async = /* @__PURE__ */ new Map();
|
|
25840
|
+
this._customEditors = [];
|
|
25841
|
+
this._value = this.options.value == null ? emptyFilterAst() : parseFilterAst(this.options.value, this._limits());
|
|
25842
|
+
this.listen(root, "change", (event) => this._handleChange(event));
|
|
25843
|
+
this.listen(root, "input", (event) => this._handleInput(event));
|
|
25844
|
+
this.listen(root, "click", (event) => this._handleClick(event));
|
|
25845
|
+
this._render();
|
|
25846
|
+
return root;
|
|
25847
|
+
}
|
|
25848
|
+
/** Returns a defensive AST copy. @returns {FilterAst} */
|
|
25849
|
+
getValue() {
|
|
25850
|
+
return cloneFilterAst(this._value);
|
|
25851
|
+
}
|
|
25852
|
+
/** Atomically replaces the AST. @param {unknown} value @param {{silent?:boolean}} [options={}] @returns {this} */
|
|
25853
|
+
setValue(value, { silent = false } = {}) {
|
|
25854
|
+
const parsed = parseFilterAst(value, this._limits());
|
|
25855
|
+
this._abortAll();
|
|
25856
|
+
this._value = parsed;
|
|
25857
|
+
this._render();
|
|
25858
|
+
if (!silent) this._changed("set", this._value.root.id);
|
|
25859
|
+
return this;
|
|
25860
|
+
}
|
|
25861
|
+
/** Adds a condition to a group. @param {string|null} [parentId=null] @param {Record<string,unknown>} [initial={}] @returns {string|null} */
|
|
25862
|
+
addCondition(parentId = null, initial = {}) {
|
|
25863
|
+
if (!this._canMutate() || conditionCount(this._value.root) >= Number(this.options.maxConditions)) return null;
|
|
25864
|
+
const parent = findGroup(this._value.root, parentId ?? this._value.root.id);
|
|
25865
|
+
if (!parent) return null;
|
|
25866
|
+
const first = this._fields[0];
|
|
25867
|
+
const field = String(initial.field ?? first?.id ?? "");
|
|
25868
|
+
const definition = this._field(field);
|
|
25869
|
+
const node = filterCondition({
|
|
25870
|
+
...initial,
|
|
25871
|
+
field,
|
|
25872
|
+
operator: String(initial.operator ?? this._defaultOperator(definition) ?? "")
|
|
25873
|
+
});
|
|
25874
|
+
parent.children.push(node);
|
|
25875
|
+
this._render();
|
|
25876
|
+
this._changed("add", node.id);
|
|
25877
|
+
this.focus(node.id);
|
|
25878
|
+
return node.id;
|
|
25879
|
+
}
|
|
25880
|
+
/** Adds a nested group. @param {string|null} [parentId=null] @param {'and'|'or'} [logic='and'] @returns {string|null} */
|
|
25881
|
+
addGroup(parentId = null, logic = "and") {
|
|
25882
|
+
if (!this._canMutate() || !this.options.allowGroups) return null;
|
|
25883
|
+
const parent = findGroup(this._value.root, parentId ?? this._value.root.id);
|
|
25884
|
+
if (!parent || groupDepth(this._value.root, parent.id) >= Number(this.options.maxDepth)) return null;
|
|
25885
|
+
const group = filterGroup(logic === "or" ? "or" : "and");
|
|
25886
|
+
parent.children.push(group);
|
|
25887
|
+
this._render();
|
|
25888
|
+
this._changed("add", group.id);
|
|
25889
|
+
this.focus(group.id);
|
|
25890
|
+
return group.id;
|
|
25891
|
+
}
|
|
25892
|
+
/** Updates a node by stable ID. @param {string} id @param {Record<string,unknown>} patch @returns {this} */
|
|
25893
|
+
update(id, patch = {}) {
|
|
25894
|
+
if (!this._canMutate()) return this;
|
|
25895
|
+
const node = findNode2(this._value.root, id);
|
|
25896
|
+
if (!node) return this;
|
|
25897
|
+
if (node.kind === "group") {
|
|
25898
|
+
if (patch.logic === "and" || patch.logic === "or") node.logic = patch.logic;
|
|
25899
|
+
} else {
|
|
25900
|
+
if (Object.hasOwn(patch, "field")) node.field = String(patch.field ?? "");
|
|
25901
|
+
if (Object.hasOwn(patch, "operator")) node.operator = String(patch.operator ?? "");
|
|
25902
|
+
if (Object.hasOwn(patch, "value")) node.value = parseValueJson(patch.value);
|
|
25903
|
+
}
|
|
25904
|
+
this._abort(id);
|
|
25905
|
+
this._render();
|
|
25906
|
+
this._changed("update", id);
|
|
25907
|
+
return this;
|
|
25908
|
+
}
|
|
25909
|
+
/** Removes a non-root node. @param {string} id @returns {this} */
|
|
25910
|
+
remove(id) {
|
|
25911
|
+
if (!this._canMutate() || id === this._value.root.id) return this;
|
|
25912
|
+
const parent = findParent(this._value.root, id);
|
|
25913
|
+
if (!parent) return this;
|
|
25914
|
+
const index = parent.children.findIndex((child) => child.id === id);
|
|
25915
|
+
const focusId = parent.children[index + 1]?.id ?? parent.children[index - 1]?.id ?? parent.id;
|
|
25916
|
+
const removed = removeNode(this._value.root, id);
|
|
25917
|
+
if (!removed) return this;
|
|
25918
|
+
this._abortTree(removed);
|
|
25919
|
+
this._render();
|
|
25920
|
+
const label = removed.kind === "condition" ? this._field(removed.field)?.label ?? "Filter" : "Filter group";
|
|
25921
|
+
this._announce(`${label} removed`);
|
|
25922
|
+
this._changed("remove", id);
|
|
25923
|
+
this.focus(focusId);
|
|
25924
|
+
return this;
|
|
25925
|
+
}
|
|
25926
|
+
/** Moves a node into a group while preserving its identity. @param {string} id @param {string} parentId @param {number} index @returns {this} */
|
|
25927
|
+
move(id, parentId, index) {
|
|
25928
|
+
const node = findNode2(this._value.root, id);
|
|
25929
|
+
const parent = findGroup(this._value.root, parentId);
|
|
25930
|
+
const previous = findParent(this._value.root, id);
|
|
25931
|
+
if (!this._canMutate() || id === this._value.root.id || !node || !parent || !previous || containsNode(node, parentId)) return this;
|
|
25932
|
+
const previousIndex = previous.children.findIndex((child) => child.id === id);
|
|
25933
|
+
const removed = previous.children.splice(previousIndex, 1)[0];
|
|
25934
|
+
parent.children.splice(Math.max(0, Math.min(parent.children.length, Number(index) || 0)), 0, removed);
|
|
25935
|
+
try {
|
|
25936
|
+
parseFilterAst(this._value, this._limits());
|
|
25937
|
+
} catch {
|
|
25938
|
+
parent.children.splice(parent.children.indexOf(removed), 1);
|
|
25939
|
+
previous.children.splice(previousIndex, 0, removed);
|
|
25940
|
+
return this;
|
|
25941
|
+
}
|
|
25942
|
+
this._render();
|
|
25943
|
+
this._changed("move", id);
|
|
25944
|
+
return this;
|
|
25945
|
+
}
|
|
25946
|
+
/** Returns semantic validity and errors. @returns {{valid:boolean,errors:Array<Record<string,string>>}} */
|
|
25947
|
+
validate() {
|
|
25948
|
+
return validateFilterAst(this._value, this._fields, this._operators);
|
|
25949
|
+
}
|
|
25950
|
+
/** Applies only a valid AST. @returns {FilterAst|null} */
|
|
25951
|
+
apply() {
|
|
25952
|
+
if (this._disabled) return null;
|
|
25953
|
+
const result = this.validate();
|
|
25954
|
+
if (!result.valid) {
|
|
25955
|
+
this.emit("invalid", { errors: result.errors });
|
|
25956
|
+
this.focus(result.errors[0]?.nodeId);
|
|
25957
|
+
return null;
|
|
25958
|
+
}
|
|
25959
|
+
const value = this.getValue();
|
|
25960
|
+
this.emit("apply", { value });
|
|
25961
|
+
return value;
|
|
25962
|
+
}
|
|
25963
|
+
/** Clears all conditions. @param {{silent?:boolean}} [options={}] @returns {this} */
|
|
25964
|
+
clear({ silent = false } = {}) {
|
|
25965
|
+
if (!this._canMutate()) return this;
|
|
25966
|
+
this._abortAll();
|
|
25967
|
+
this._value.root.children = [];
|
|
25968
|
+
this._render();
|
|
25969
|
+
if (!silent) this._changed("clear", this._value.root.id);
|
|
25970
|
+
this.refs.add?.focus();
|
|
25971
|
+
return this;
|
|
25972
|
+
}
|
|
25973
|
+
/** Focuses a condition's field or the Add button. @param {string|null} [id=null] @returns {this} */
|
|
25974
|
+
focus(id = null) {
|
|
25975
|
+
const selector = id ? `[data-node-id="${cssEscape(id)}"] :is([data-filter-field], [data-filter-logic], [data-filter-action="add"])` : '[data-filter-action="add"]';
|
|
25976
|
+
queueMicrotask(() => (
|
|
25977
|
+
/** @type {HTMLElement|null} */
|
|
25978
|
+
this.el.querySelector(selector)?.focus()
|
|
25979
|
+
));
|
|
25980
|
+
return this;
|
|
25981
|
+
}
|
|
25982
|
+
/** @param {boolean} readonly @returns {this} */
|
|
25983
|
+
setReadonly(readonly) {
|
|
25984
|
+
this._readonly = Boolean(readonly);
|
|
25985
|
+
this._render();
|
|
25986
|
+
return this;
|
|
25987
|
+
}
|
|
25988
|
+
/** @returns {this} */
|
|
25989
|
+
enable() {
|
|
25990
|
+
this._disabled = false;
|
|
25991
|
+
this._render();
|
|
25992
|
+
return this;
|
|
25993
|
+
}
|
|
25994
|
+
/** @returns {this} */
|
|
25995
|
+
disable() {
|
|
25996
|
+
this._disabled = true;
|
|
25997
|
+
this._abortAll();
|
|
25998
|
+
this._render();
|
|
25999
|
+
return this;
|
|
26000
|
+
}
|
|
26001
|
+
/** @returns {void} */
|
|
26002
|
+
destroy() {
|
|
26003
|
+
this._abortAll();
|
|
26004
|
+
this._destroyEditors();
|
|
26005
|
+
const root = this.el;
|
|
26006
|
+
const snapshot10 = this._snapshot;
|
|
26007
|
+
super.destroy();
|
|
26008
|
+
if (!this._createdRoot && root) restoreTarget(root, snapshot10);
|
|
26009
|
+
}
|
|
26010
|
+
/** @returns {void} */
|
|
26011
|
+
_render() {
|
|
26012
|
+
this._destroyEditors();
|
|
26013
|
+
this._renderVersion = (this._renderVersion ?? 0) + 1;
|
|
26014
|
+
const status = h("div", { ref: "status", class: "zx-filter__status", role: "status", ariaLive: "polite" });
|
|
26015
|
+
const tree = this._renderGroup(this._value.root, 0, true);
|
|
26016
|
+
const actions2 = h(
|
|
26017
|
+
"div",
|
|
26018
|
+
{ class: "zx-filter__actions" },
|
|
26019
|
+
actionButton("add", this._value.root.id, "plus", "Add filter", { ref: "add", disabled: this._blocked() }),
|
|
26020
|
+
this.options.allowGroups ? actionButton("add-group", this._value.root.id, "folder", "Add group", { disabled: this._blocked() }) : null,
|
|
26021
|
+
actionButton("clear", "", "x", String(this.options.clearLabel), { disabled: this._blocked() }),
|
|
26022
|
+
actionButton("apply", "", "check", String(this.options.applyLabel), { class: "zx-button--primary", disabled: this._disabled })
|
|
26023
|
+
);
|
|
26024
|
+
this.el.replaceChildren(status, tree, actions2);
|
|
26025
|
+
this.refs.status = status;
|
|
26026
|
+
this.refs.add = /** @type {HTMLElement} */
|
|
26027
|
+
this.el.querySelector('[data-filter-action="add"]');
|
|
26028
|
+
this.el.toggleAttribute("data-readonly", this._readonly);
|
|
26029
|
+
this.el.toggleAttribute("data-disabled", this._disabled);
|
|
26030
|
+
const result = this.validate();
|
|
26031
|
+
this.el.dataset.valid = String(result.valid);
|
|
26032
|
+
for (const error2 of result.errors) this.el.querySelector(`[data-node-id="${cssEscape(error2.nodeId)}"]`)?.setAttribute("data-invalid", "");
|
|
26033
|
+
}
|
|
26034
|
+
/** @param {any} group @param {number} depth @param {boolean} root @returns {HTMLElement} */
|
|
26035
|
+
_renderGroup(group, depth, root) {
|
|
26036
|
+
const children = h(
|
|
26037
|
+
"ol",
|
|
26038
|
+
{ class: "zx-filter__children" },
|
|
26039
|
+
group.children.map((node) => node.kind === "group" ? this._renderGroup(node, depth + 1, false) : this._renderCondition(node))
|
|
26040
|
+
);
|
|
26041
|
+
const logic = h(
|
|
26042
|
+
"select",
|
|
26043
|
+
{
|
|
26044
|
+
class: "zx-filter__logic",
|
|
26045
|
+
dataset: { filterLogic: "", nodeId: group.id },
|
|
26046
|
+
ariaLabel: root ? "Root filter logic" : "Group filter logic",
|
|
26047
|
+
disabled: this._blocked()
|
|
26048
|
+
},
|
|
26049
|
+
h("option", { value: "and", selected: group.logic === "and" }, "Match all"),
|
|
26050
|
+
h("option", { value: "or", selected: group.logic === "or" }, "Match any")
|
|
26051
|
+
);
|
|
26052
|
+
const legend = h("legend", { class: "zx-filter__legend" }, logic, h("span", {}, root ? "conditions" : "in this group"));
|
|
26053
|
+
const controls = h(
|
|
26054
|
+
"div",
|
|
26055
|
+
{ class: "zx-filter__group-actions" },
|
|
26056
|
+
actionButton("add", group.id, "plus", "Add filter", { disabled: this._blocked() }),
|
|
26057
|
+
this.options.allowGroups && depth < Number(this.options.maxDepth) ? actionButton("add-group", group.id, "folder", "Add subgroup", { disabled: this._blocked() }) : null,
|
|
26058
|
+
root ? null : actionButton("remove", group.id, "trash", "Remove group", { disabled: this._blocked() })
|
|
26059
|
+
);
|
|
26060
|
+
return h(root ? "fieldset" : "li", {
|
|
26061
|
+
class: "zx-filter__group",
|
|
26062
|
+
dataset: { nodeId: group.id, depth: String(depth) }
|
|
26063
|
+
}, root ? legend : h("fieldset", {}, legend, children, controls), root ? children : null, root ? controls : null);
|
|
26064
|
+
}
|
|
26065
|
+
/** @param {any} node @returns {HTMLElement} */
|
|
26066
|
+
_renderCondition(node) {
|
|
26067
|
+
const field = this._field(node.field);
|
|
26068
|
+
const operators = this._operatorsFor(field);
|
|
26069
|
+
const operator = this._operator(node.operator);
|
|
26070
|
+
const fieldSelect = h(
|
|
26071
|
+
"select",
|
|
26072
|
+
{
|
|
26073
|
+
class: "zx-filter__field",
|
|
26074
|
+
dataset: { filterField: "", nodeId: node.id },
|
|
26075
|
+
ariaLabel: "Filter field",
|
|
26076
|
+
disabled: this._blocked()
|
|
26077
|
+
},
|
|
26078
|
+
h("option", { value: "", selected: !node.field }, "Choose a field\u2026"),
|
|
26079
|
+
this._fields.map((candidate) => h("option", { value: candidate.id, selected: candidate.id === node.field }, candidate.label)),
|
|
26080
|
+
node.field && !field ? h("option", { value: node.field, selected: true }, `Unavailable: ${node.field}`) : null
|
|
26081
|
+
);
|
|
26082
|
+
const operatorSelect = h(
|
|
26083
|
+
"select",
|
|
26084
|
+
{
|
|
26085
|
+
class: "zx-filter__operator",
|
|
26086
|
+
dataset: { filterOperator: "", nodeId: node.id },
|
|
26087
|
+
ariaLabel: "Filter operator",
|
|
26088
|
+
disabled: this._blocked()
|
|
26089
|
+
},
|
|
26090
|
+
h("option", { value: "", selected: !node.operator }, "Choose an operator\u2026"),
|
|
26091
|
+
operators.map((candidate) => h("option", { value: candidate.id, selected: candidate.id === node.operator }, candidate.label)),
|
|
26092
|
+
node.operator && !operators.some((candidate) => candidate.id === node.operator) ? h("option", { value: node.operator, selected: true }, `Unavailable: ${node.operator}`) : null
|
|
26093
|
+
);
|
|
26094
|
+
return h(
|
|
26095
|
+
"li",
|
|
26096
|
+
{ class: "zx-filter__condition", dataset: { nodeId: node.id } },
|
|
26097
|
+
fieldSelect,
|
|
26098
|
+
operatorSelect,
|
|
26099
|
+
this._renderValue(node, field, operator),
|
|
26100
|
+
actionButton("remove", node.id, "trash", `Remove ${field?.label ?? "filter"}`, { disabled: this._blocked() })
|
|
26101
|
+
);
|
|
26102
|
+
}
|
|
26103
|
+
/** @param {any} node @param {FilterField|null} field @param {any} operator @returns {HTMLElement} */
|
|
26104
|
+
_renderValue(node, field, operator) {
|
|
26105
|
+
const host = h("div", { class: "zx-filter__value" });
|
|
26106
|
+
if (!field || !operator) return host;
|
|
26107
|
+
if (operator.arity === "none") return h("div", { class: "zx-filter__value zx-filter__value--empty" }, "No value");
|
|
26108
|
+
if (field.type === "custom" && typeof field.editor === "function") {
|
|
26109
|
+
const renderVersion = this._renderVersion;
|
|
26110
|
+
queueMicrotask(() => {
|
|
26111
|
+
if (renderVersion !== this._renderVersion || !this.el.contains(host)) return;
|
|
26112
|
+
const handle = field.editor(host, {
|
|
26113
|
+
value: node.value,
|
|
26114
|
+
field,
|
|
26115
|
+
conditionId: node.id,
|
|
26116
|
+
setValue: (value) => this._setNodeValue(node.id, parseValueJson(value))
|
|
26117
|
+
});
|
|
26118
|
+
if (handle && typeof handle.destroy === "function") this._customEditors.push(handle);
|
|
26119
|
+
});
|
|
26120
|
+
return host;
|
|
26121
|
+
}
|
|
26122
|
+
const values = operator.arity === "pair" ? Array.isArray(node.value) ? node.value : [null, null] : [node.value];
|
|
26123
|
+
if (operator.arity === "many") {
|
|
26124
|
+
const control = choiceSelect(field, node, values[0], true, this._blocked());
|
|
26125
|
+
if (control) return h("div", { class: "zx-filter__value" }, control);
|
|
26126
|
+
return h("div", { class: "zx-filter__value" }, valueInput(field, node.id, Array.isArray(node.value) ? node.value.join(", ") : "", 0, this._blocked(), true));
|
|
26127
|
+
}
|
|
26128
|
+
const controls = values.map((value, index) => choiceSelect(field, node, value, false, this._blocked(), index) ?? valueInput(field, node.id, value, index, this._blocked()));
|
|
26129
|
+
return h("div", { class: "zx-filter__value", dataset: { arity: operator.arity } }, controls);
|
|
26130
|
+
}
|
|
26131
|
+
/** @param {Event} event @returns {void} */
|
|
26132
|
+
_handleChange(event) {
|
|
26133
|
+
if (!this._canMutate()) return;
|
|
26134
|
+
const target = (
|
|
26135
|
+
/** @type {HTMLInputElement|HTMLSelectElement|null} */
|
|
26136
|
+
event.target
|
|
26137
|
+
);
|
|
26138
|
+
const id = target?.dataset.nodeId;
|
|
26139
|
+
if (!target || !id) return;
|
|
26140
|
+
if (target.dataset.filterField !== void 0) {
|
|
26141
|
+
const node = findNode2(this._value.root, id);
|
|
26142
|
+
if (node?.kind !== "condition") return;
|
|
26143
|
+
node.field = target.value;
|
|
26144
|
+
const field = this._field(node.field);
|
|
26145
|
+
node.operator = this._defaultOperator(field) ?? "";
|
|
26146
|
+
node.value = null;
|
|
26147
|
+
this._abort(id);
|
|
26148
|
+
this._render();
|
|
26149
|
+
this._changed("update", id);
|
|
26150
|
+
this.focus(id);
|
|
26151
|
+
} else if (target.dataset.filterOperator !== void 0) {
|
|
26152
|
+
const node = findNode2(this._value.root, id);
|
|
26153
|
+
if (node?.kind !== "condition") return;
|
|
26154
|
+
node.operator = target.value;
|
|
26155
|
+
node.value = null;
|
|
26156
|
+
this._abort(id);
|
|
26157
|
+
this._render();
|
|
26158
|
+
this._changed("update", id);
|
|
26159
|
+
queueMicrotask(() => (
|
|
26160
|
+
/** @type {HTMLElement|null} */
|
|
26161
|
+
this.el.querySelector(`[data-node-id="${cssEscape(id)}"] [data-filter-value]`)?.focus()
|
|
26162
|
+
));
|
|
26163
|
+
} else if (target.dataset.filterLogic !== void 0) {
|
|
26164
|
+
const node = findNode2(this._value.root, id);
|
|
26165
|
+
if (node?.kind === "group") node.logic = target.value === "or" ? "or" : "and";
|
|
26166
|
+
this._changed("update", id);
|
|
26167
|
+
} else if (target.dataset.filterValue !== void 0) this._valueInput(target);
|
|
26168
|
+
}
|
|
26169
|
+
/** @param {Event} event @returns {void} */
|
|
26170
|
+
_handleInput(event) {
|
|
26171
|
+
if (!this._canMutate()) return;
|
|
26172
|
+
const target = (
|
|
26173
|
+
/** @type {HTMLInputElement|null} */
|
|
26174
|
+
event.target
|
|
26175
|
+
);
|
|
26176
|
+
if (!target || target.dataset.filterValue === void 0) return;
|
|
26177
|
+
this._valueInput(target);
|
|
26178
|
+
const id = target.dataset.nodeId;
|
|
26179
|
+
const node = findNode2(this._value.root, id);
|
|
26180
|
+
const field = node?.kind === "condition" ? this._field(node.field) : null;
|
|
26181
|
+
if (field?.loadChoices) this._scheduleChoices(node.id, field, target.value);
|
|
26182
|
+
}
|
|
26183
|
+
/** @param {HTMLInputElement|HTMLSelectElement} target @returns {void} */
|
|
26184
|
+
_valueInput(target) {
|
|
26185
|
+
const node = findNode2(this._value.root, target.dataset.nodeId);
|
|
26186
|
+
if (node?.kind !== "condition") return;
|
|
26187
|
+
const operator = this._operator(node.operator);
|
|
26188
|
+
const field = this._field(node.field);
|
|
26189
|
+
if (!operator || !field) return;
|
|
26190
|
+
let value;
|
|
26191
|
+
if (target instanceof HTMLSelectElement && target.multiple) {
|
|
26192
|
+
value = Array.from(target.selectedOptions, (option) => parseScalar(option.value, field.type));
|
|
26193
|
+
} else if (operator.arity === "many") {
|
|
26194
|
+
value = target.value.split(",").map((item) => item.trim()).filter(Boolean).map((item) => parseScalar(item, field.type));
|
|
26195
|
+
} else if (operator.arity === "pair") {
|
|
26196
|
+
const pair = Array.isArray(node.value) ? [...node.value] : [null, null];
|
|
26197
|
+
pair[Number(target.dataset.valueIndex) || 0] = parseScalar(target.value, field.type);
|
|
26198
|
+
value = pair;
|
|
26199
|
+
} else value = parseScalar(target.value, field.type);
|
|
26200
|
+
this._setNodeValue(
|
|
26201
|
+
node.id,
|
|
26202
|
+
/** @type {any} */
|
|
26203
|
+
value
|
|
26204
|
+
);
|
|
26205
|
+
}
|
|
26206
|
+
/** @param {MouseEvent} event @returns {void} */
|
|
26207
|
+
_handleClick(event) {
|
|
26208
|
+
const button2 = (
|
|
26209
|
+
/** @type {HTMLElement|null} */
|
|
26210
|
+
event.target?.closest?.("[data-filter-action]")
|
|
26211
|
+
);
|
|
26212
|
+
if (!button2 || !this.el.contains(button2)) return;
|
|
26213
|
+
const action = button2.dataset.filterAction;
|
|
26214
|
+
const id = button2.dataset.nodeId || null;
|
|
26215
|
+
if (action === "add") this.addCondition(id);
|
|
26216
|
+
else if (action === "add-group") this.addGroup(id);
|
|
26217
|
+
else if (action === "remove" && id) this.remove(id);
|
|
26218
|
+
else if (action === "clear") this.clear();
|
|
26219
|
+
else if (action === "apply") this.apply();
|
|
26220
|
+
}
|
|
26221
|
+
/** @param {string} id @param {any} value @returns {void} */
|
|
26222
|
+
_setNodeValue(id, value) {
|
|
26223
|
+
const node = findNode2(this._value.root, id);
|
|
26224
|
+
if (node?.kind !== "condition") return;
|
|
26225
|
+
node.value = value;
|
|
26226
|
+
const result = this.validate();
|
|
26227
|
+
this.el.dataset.valid = String(result.valid);
|
|
26228
|
+
const row2 = this.el.querySelector(`[data-node-id="${cssEscape(id)}"]`);
|
|
26229
|
+
row2?.toggleAttribute("data-invalid", result.errors.some((candidate) => candidate.nodeId === id));
|
|
26230
|
+
this._changed("update", id);
|
|
26231
|
+
}
|
|
26232
|
+
/** @param {string} reason @param {string} nodeId @returns {void} */
|
|
26233
|
+
_changed(reason, nodeId) {
|
|
26234
|
+
const result = this.validate();
|
|
26235
|
+
const value = this.getValue();
|
|
26236
|
+
this.emit("change", { value, valid: result.valid, errors: result.errors, reason, nodeId });
|
|
26237
|
+
if (this.options.autoApply && result.valid) this.emit("apply", { value });
|
|
26238
|
+
}
|
|
26239
|
+
/** @param {string} id @param {FilterField} field @param {string} query @returns {void} */
|
|
26240
|
+
_scheduleChoices(id, field, query) {
|
|
26241
|
+
this._abort(id);
|
|
26242
|
+
if (query.length < Number(field.minQuery ?? 0)) return;
|
|
26243
|
+
const controller = new AbortController();
|
|
26244
|
+
this._setAsyncBusy(id, true);
|
|
26245
|
+
const entry = { controller, timer: setTimeout(async () => {
|
|
26246
|
+
this.emit("query", { conditionId: id, fieldId: field.id, query });
|
|
26247
|
+
try {
|
|
26248
|
+
const choices = await field.loadChoices({ query, signal: controller.signal, conditionId: id, field });
|
|
26249
|
+
if (controller.signal.aborted || this._async.get(id)?.controller !== controller) return;
|
|
26250
|
+
const input = this.el.querySelector(`[data-node-id="${cssEscape(id)}"] [data-filter-value]`);
|
|
26251
|
+
const listId = input?.getAttribute("list");
|
|
26252
|
+
const list = listId ? this.el.querySelector(`#${cssEscape(listId)}`) : null;
|
|
26253
|
+
if (list) list.replaceChildren(...(Array.isArray(choices) ? choices : []).map((choice) => h("option", { value: choice.value }, choice.label)));
|
|
26254
|
+
this.emit("loaded", { conditionId: id, fieldId: field.id, query, choices });
|
|
26255
|
+
} catch (error2) {
|
|
26256
|
+
if (!controller.signal.aborted) this.emit("error", { conditionId: id, fieldId: field.id, query, error: error2 instanceof Error ? error2 : new Error(String(error2)) });
|
|
26257
|
+
} finally {
|
|
26258
|
+
if (this._async.get(id)?.controller === controller) {
|
|
26259
|
+
this._async.delete(id);
|
|
26260
|
+
this._setAsyncBusy(id, false);
|
|
26261
|
+
}
|
|
26262
|
+
}
|
|
26263
|
+
}, Math.max(0, Number(field.debounce ?? 200))) };
|
|
26264
|
+
this._async.set(id, entry);
|
|
26265
|
+
}
|
|
26266
|
+
/** @param {string} id @returns {void} */
|
|
26267
|
+
_abort(id) {
|
|
26268
|
+
const entry = this._async.get(id);
|
|
26269
|
+
if (entry) {
|
|
26270
|
+
clearTimeout(entry.timer);
|
|
26271
|
+
entry.controller.abort();
|
|
26272
|
+
this._async.delete(id);
|
|
26273
|
+
this._setAsyncBusy(id, false);
|
|
26274
|
+
}
|
|
26275
|
+
}
|
|
26276
|
+
/** @param {string} id @param {boolean} busy @returns {void} */
|
|
26277
|
+
_setAsyncBusy(id, busy) {
|
|
26278
|
+
const input = this.el.querySelector(`[data-node-id="${cssEscape(id)}"] [data-filter-value]`);
|
|
26279
|
+
if (busy) input?.setAttribute("aria-busy", "true");
|
|
26280
|
+
else input?.removeAttribute("aria-busy");
|
|
26281
|
+
}
|
|
26282
|
+
/** @param {any} node @returns {void} */
|
|
26283
|
+
_abortTree(node) {
|
|
26284
|
+
if (node.kind === "condition") this._abort(node.id);
|
|
26285
|
+
else node.children.forEach((child) => this._abortTree(child));
|
|
26286
|
+
}
|
|
26287
|
+
/** @returns {void} */
|
|
26288
|
+
_abortAll() {
|
|
26289
|
+
for (const id of [...this._async.keys()]) this._abort(id);
|
|
26290
|
+
}
|
|
26291
|
+
/** @returns {void} */
|
|
26292
|
+
_destroyEditors() {
|
|
26293
|
+
for (const editor of this._customEditors ?? []) editor.destroy?.();
|
|
26294
|
+
this._customEditors = [];
|
|
26295
|
+
}
|
|
26296
|
+
/** @returns {boolean} */
|
|
26297
|
+
_blocked() {
|
|
26298
|
+
return this._readonly || this._disabled;
|
|
26299
|
+
}
|
|
26300
|
+
/** @returns {boolean} */
|
|
26301
|
+
_canMutate() {
|
|
26302
|
+
return !this._blocked();
|
|
26303
|
+
}
|
|
26304
|
+
/** @returns {{maxDepth:number,maxConditions:number}} */
|
|
26305
|
+
_limits() {
|
|
26306
|
+
return { maxDepth: Number(this.options.maxDepth), maxConditions: Number(this.options.maxConditions) };
|
|
26307
|
+
}
|
|
26308
|
+
/** @param {string} id @returns {FilterField|null} */
|
|
26309
|
+
_field(id) {
|
|
26310
|
+
return this._fields.find((field) => field.id === id) ?? null;
|
|
26311
|
+
}
|
|
26312
|
+
/** @param {string} id @returns {any} */
|
|
26313
|
+
_operator(id) {
|
|
26314
|
+
return this._operators.find((operator) => operator.id === id) ?? null;
|
|
26315
|
+
}
|
|
26316
|
+
/** @param {FilterField|null} field @returns {any[]} */
|
|
26317
|
+
_operatorsFor(field) {
|
|
26318
|
+
if (!field) return [];
|
|
26319
|
+
const ids = field.operators?.length ? field.operators : null;
|
|
26320
|
+
return this._operators.filter((operator) => ids ? ids.includes(operator.id) : operator.types.includes(field.type));
|
|
26321
|
+
}
|
|
26322
|
+
/** @param {FilterField|null} field @returns {string|null} */
|
|
26323
|
+
_defaultOperator(field) {
|
|
26324
|
+
return field?.defaultOperator && this._operatorsFor(field).some((operator) => operator.id === field.defaultOperator) ? field.defaultOperator : this._operatorsFor(field)[0]?.id ?? null;
|
|
26325
|
+
}
|
|
26326
|
+
/** @param {string} text @returns {void} */
|
|
26327
|
+
_announce(text4) {
|
|
26328
|
+
if (this.refs.status) this.refs.status.textContent = text4;
|
|
26329
|
+
}
|
|
26330
|
+
};
|
|
26331
|
+
function actionButton(action, id, iconName, label, props = {}) {
|
|
26332
|
+
return h("button", { type: "button", class: ["zx-button", "zx-button--sm", props.class].filter(Boolean), ...props, dataset: { filterAction: action, nodeId: id } }, icon(iconName, { size: 13 }), h("span", {}, label));
|
|
26333
|
+
}
|
|
26334
|
+
function choiceSelect(field, node, value, multiple, disabled, index = 0) {
|
|
26335
|
+
const choices = Array.isArray(field.choices) && field.choices.length ? field.choices : field.type === "boolean" ? [{ value: true, label: "True" }, { value: false, label: "False" }] : null;
|
|
26336
|
+
if (!choices) return null;
|
|
26337
|
+
const values = new Set(Array.isArray(value) ? value.map(String) : [String(value ?? "")]);
|
|
26338
|
+
return (
|
|
26339
|
+
/** @type {HTMLSelectElement} */
|
|
26340
|
+
h(
|
|
26341
|
+
"select",
|
|
26342
|
+
{
|
|
26343
|
+
dataset: { filterValue: "", nodeId: node.id, valueIndex: String(index) },
|
|
26344
|
+
ariaLabel: `${field.label} value`,
|
|
26345
|
+
multiple,
|
|
26346
|
+
disabled
|
|
26347
|
+
},
|
|
26348
|
+
!multiple ? h("option", { value: "", selected: !values.has(String(value)) || value == null }, "Choose\u2026") : null,
|
|
26349
|
+
choices.map((choice) => h("option", { value: choice.value, selected: values.has(String(choice.value)) }, choice.label))
|
|
26350
|
+
)
|
|
26351
|
+
);
|
|
26352
|
+
}
|
|
26353
|
+
function valueInput(field, id, value, index, disabled, many = false) {
|
|
26354
|
+
const type = many ? "text" : ["number", "money"].includes(field.type) ? "number" : field.type === "date" ? "date" : field.type === "datetime" ? "datetime-local" : "text";
|
|
26355
|
+
const listId = field.loadChoices ? `zx-filter-choices-${id}-${index}` : null;
|
|
26356
|
+
const input = (
|
|
26357
|
+
/** @type {HTMLInputElement} */
|
|
26358
|
+
h("input", {
|
|
26359
|
+
type,
|
|
26360
|
+
value: value ?? "",
|
|
26361
|
+
dataset: { filterValue: "", nodeId: id, valueIndex: String(index) },
|
|
26362
|
+
ariaLabel: `${field.label} value${index ? ` ${index + 1}` : ""}`,
|
|
26363
|
+
disabled,
|
|
26364
|
+
placeholder: many ? "Comma-separated values" : "",
|
|
26365
|
+
list: listId
|
|
26366
|
+
})
|
|
26367
|
+
);
|
|
26368
|
+
return h(
|
|
26369
|
+
"span",
|
|
26370
|
+
{ class: "zx-filter__value-control" },
|
|
26371
|
+
input,
|
|
26372
|
+
listId ? h("datalist", { id: listId }) : null
|
|
26373
|
+
);
|
|
26374
|
+
}
|
|
26375
|
+
function parseScalar(value, type) {
|
|
26376
|
+
if (value === "") return null;
|
|
26377
|
+
if (["number", "money"].includes(type)) {
|
|
26378
|
+
const number2 = Number(value);
|
|
26379
|
+
return Number.isFinite(number2) ? number2 : null;
|
|
26380
|
+
}
|
|
26381
|
+
if (type === "boolean") return value === "true";
|
|
26382
|
+
return value;
|
|
26383
|
+
}
|
|
26384
|
+
function parseValueJson(value) {
|
|
26385
|
+
return cloneFilterValue(value === void 0 ? null : value);
|
|
26386
|
+
}
|
|
26387
|
+
function findNode2(root, id) {
|
|
26388
|
+
if (!root || root.id === id) return root ?? null;
|
|
26389
|
+
if (root.kind === "group") for (const child of root.children) {
|
|
26390
|
+
const match = findNode2(child, id);
|
|
26391
|
+
if (match) return match;
|
|
26392
|
+
}
|
|
26393
|
+
return null;
|
|
26394
|
+
}
|
|
26395
|
+
function findGroup(root, id) {
|
|
26396
|
+
const node = findNode2(root, id);
|
|
26397
|
+
return node?.kind === "group" ? node : null;
|
|
26398
|
+
}
|
|
26399
|
+
function findParent(root, id) {
|
|
26400
|
+
if (root?.kind !== "group") return null;
|
|
26401
|
+
if (root.children.some((child) => child.id === id)) return root;
|
|
26402
|
+
for (const child of root.children) {
|
|
26403
|
+
const parent = findParent(child, id);
|
|
26404
|
+
if (parent) return parent;
|
|
26405
|
+
}
|
|
26406
|
+
return null;
|
|
26407
|
+
}
|
|
26408
|
+
function removeNode(root, id) {
|
|
26409
|
+
if (root.kind !== "group") return null;
|
|
26410
|
+
const index = root.children.findIndex((child) => child.id === id);
|
|
26411
|
+
if (index >= 0) return root.children.splice(index, 1)[0];
|
|
26412
|
+
for (const child of root.children) {
|
|
26413
|
+
const found = removeNode(child, id);
|
|
26414
|
+
if (found) return found;
|
|
26415
|
+
}
|
|
26416
|
+
return null;
|
|
26417
|
+
}
|
|
26418
|
+
function containsNode(node, id) {
|
|
26419
|
+
return Boolean(node && findNode2(node, id));
|
|
26420
|
+
}
|
|
26421
|
+
function conditionCount(node) {
|
|
26422
|
+
return node.kind === "condition" ? 1 : node.children.reduce((sum, child) => sum + conditionCount(child), 0);
|
|
26423
|
+
}
|
|
26424
|
+
function groupDepth(root, id, depth = 0) {
|
|
26425
|
+
if (root.id === id) return depth;
|
|
26426
|
+
if (root.kind === "group") for (const child of root.children) {
|
|
26427
|
+
if (child.kind === "group") {
|
|
26428
|
+
const found = groupDepth(child, id, depth + 1);
|
|
26429
|
+
if (found >= 0) return found;
|
|
26430
|
+
}
|
|
26431
|
+
}
|
|
26432
|
+
return -1;
|
|
26433
|
+
}
|
|
26434
|
+
function mergeOperators(base, extra) {
|
|
26435
|
+
const map = new Map(base.map((item) => [item.id, { ...item, types: [...item.types] }]));
|
|
26436
|
+
for (const item of Array.isArray(extra) ? extra : []) if (item?.id) map.set(String(item.id), { ...item, id: String(item.id), types: Array.isArray(item.types) ? [...item.types] : [] });
|
|
26437
|
+
return [...map.values()];
|
|
26438
|
+
}
|
|
26439
|
+
function cssEscape(value) {
|
|
26440
|
+
return globalThis.CSS?.escape ? CSS.escape(value) : String(value).replaceAll(/[^a-zA-Z0-9_-]/g, "\\$&");
|
|
26441
|
+
}
|
|
26442
|
+
|
|
25002
26443
|
// src/components/fieldset/fieldset.js
|
|
25003
26444
|
var Fieldset = class extends Component {
|
|
25004
26445
|
static cssName = "fieldset";
|
|
@@ -26166,8 +27607,8 @@ var Questionnaire = class extends Component {
|
|
|
26166
27607
|
this._setBusy(true);
|
|
26167
27608
|
try {
|
|
26168
27609
|
message = await item.validate(answer, this.getAnswers());
|
|
26169
|
-
} catch (
|
|
26170
|
-
message =
|
|
27610
|
+
} catch (error2) {
|
|
27611
|
+
message = error2 instanceof Error ? error2.message : String(error2);
|
|
26171
27612
|
} finally {
|
|
26172
27613
|
if (!this._destroyed) this._setBusy(false);
|
|
26173
27614
|
}
|
|
@@ -26305,10 +27746,10 @@ var Questionnaire = class extends Component {
|
|
|
26305
27746
|
}
|
|
26306
27747
|
/** @param {NormalizedItem} item @returns {void} */
|
|
26307
27748
|
_paintError(item) {
|
|
26308
|
-
const
|
|
26309
|
-
if (
|
|
26310
|
-
|
|
26311
|
-
|
|
27749
|
+
const error2 = this._itemHost.querySelector(".zx-questionnaire__error");
|
|
27750
|
+
if (error2 instanceof HTMLElement) {
|
|
27751
|
+
error2.textContent = this._error;
|
|
27752
|
+
error2.hidden = !this._error;
|
|
26312
27753
|
}
|
|
26313
27754
|
if (this._error) this._itemHost.setAttribute("aria-invalid", "true");
|
|
26314
27755
|
else this._itemHost.removeAttribute("aria-invalid");
|
|
@@ -26316,7 +27757,7 @@ var Questionnaire = class extends Component {
|
|
|
26316
27757
|
if (field) {
|
|
26317
27758
|
if (this._error) field.setHighlight(this._error, "danger");
|
|
26318
27759
|
else field.clearHighlight();
|
|
26319
|
-
if (
|
|
27760
|
+
if (error2 instanceof HTMLElement) error2.hidden = true;
|
|
26320
27761
|
}
|
|
26321
27762
|
}
|
|
26322
27763
|
/** @returns {void} */
|
|
@@ -26539,6 +27980,7 @@ function registerFieldAdapters() {
|
|
|
26539
27980
|
registerFieldAdapters();
|
|
26540
27981
|
export {
|
|
26541
27982
|
AccountMenu,
|
|
27983
|
+
AppIcon,
|
|
26542
27984
|
AppSidebar,
|
|
26543
27985
|
Avatar,
|
|
26544
27986
|
Breadcrumb,
|
|
@@ -26562,6 +28004,7 @@ export {
|
|
|
26562
28004
|
Field,
|
|
26563
28005
|
FieldUpload,
|
|
26564
28006
|
Fieldset,
|
|
28007
|
+
Filter,
|
|
26565
28008
|
Finder,
|
|
26566
28009
|
Form,
|
|
26567
28010
|
Grid,
|
|
@@ -26602,6 +28045,7 @@ export {
|
|
|
26602
28045
|
__,
|
|
26603
28046
|
addDays,
|
|
26604
28047
|
addMonths,
|
|
28048
|
+
appIcon,
|
|
26605
28049
|
appendCompact,
|
|
26606
28050
|
appendCompactChild,
|
|
26607
28051
|
appendContent,
|
|
@@ -26621,6 +28065,7 @@ export {
|
|
|
26621
28065
|
clampRange,
|
|
26622
28066
|
clampSize,
|
|
26623
28067
|
cloneChartValue,
|
|
28068
|
+
cloneFilterAst,
|
|
26624
28069
|
compactElement,
|
|
26625
28070
|
configureIcons,
|
|
26626
28071
|
copyButton,
|
|
@@ -26631,12 +28076,16 @@ export {
|
|
|
26631
28076
|
defineElements,
|
|
26632
28077
|
describe,
|
|
26633
28078
|
downloadBlob,
|
|
28079
|
+
emptyFilterAst,
|
|
26634
28080
|
emptyState,
|
|
26635
28081
|
escapeRegExp,
|
|
26636
28082
|
faFamilies,
|
|
26637
28083
|
faIconClasses,
|
|
26638
28084
|
faNames,
|
|
26639
28085
|
faStyles,
|
|
28086
|
+
filterCondition,
|
|
28087
|
+
filterGroup,
|
|
28088
|
+
filterOperators,
|
|
26640
28089
|
fireCompactEvent,
|
|
26641
28090
|
focusTrap,
|
|
26642
28091
|
formatCurrency,
|
|
@@ -26676,6 +28125,7 @@ export {
|
|
|
26676
28125
|
paginationRange,
|
|
26677
28126
|
parseCompactTag,
|
|
26678
28127
|
parseDate,
|
|
28128
|
+
parseFilterAst,
|
|
26679
28129
|
parseIconSpec,
|
|
26680
28130
|
parseNumber,
|
|
26681
28131
|
parseRangeText,
|
|
@@ -26687,6 +28137,7 @@ export {
|
|
|
26687
28137
|
rankLauncherItems,
|
|
26688
28138
|
registerFieldAdapters,
|
|
26689
28139
|
registerIcons,
|
|
28140
|
+
reorderTableRows,
|
|
26690
28141
|
resolveElement,
|
|
26691
28142
|
resolveSize,
|
|
26692
28143
|
rovingTabindex,
|
|
@@ -26703,6 +28154,7 @@ export {
|
|
|
26703
28154
|
stack,
|
|
26704
28155
|
stepPrecision,
|
|
26705
28156
|
storage,
|
|
28157
|
+
stringifyFilterAst,
|
|
26706
28158
|
throttle,
|
|
26707
28159
|
toArray,
|
|
26708
28160
|
toCsv,
|
|
@@ -26714,5 +28166,6 @@ export {
|
|
|
26714
28166
|
uniqueBy,
|
|
26715
28167
|
useBuiltinIcons,
|
|
26716
28168
|
useFontAwesome,
|
|
28169
|
+
validateFilterAst,
|
|
26717
28170
|
zeyosService
|
|
26718
28171
|
};
|