@zeyos/zx 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -0
- package/DESIGN-SYSTEM.md +136 -0
- package/MIGRATION.md +155 -4
- package/README.md +24 -13
- package/dist/types/compat/map/data.d.ts +3 -2
- package/dist/types/components/account-menu/account-menu.d.ts +144 -0
- package/dist/types/components/app-rail/app-rail.d.ts +250 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +169 -0
- package/dist/types/components/avatar/avatar.d.ts +100 -0
- package/dist/types/components/chart/chart.d.ts +321 -0
- package/dist/types/components/date-picker/month-picker.d.ts +6 -0
- package/dist/types/components/dialog/dialog.d.ts +9 -0
- package/dist/types/components/dock/dock.d.ts +495 -0
- package/dist/types/components/dropdown/dropdown.d.ts +2 -2
- package/dist/types/components/field/field.d.ts +14 -0
- package/dist/types/components/field-upload/field-upload.d.ts +37 -4
- package/dist/types/components/form/form.d.ts +25 -3
- package/dist/types/components/grid/grid.d.ts +172 -0
- package/dist/types/components/launcher/launcher.d.ts +300 -0
- package/dist/types/components/layout/layout.d.ts +4 -4
- package/dist/types/components/menu-button/menu-button.d.ts +10 -2
- package/dist/types/components/modal/modal.d.ts +25 -0
- package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +7 -1
- package/dist/types/components/questionnaire/items.d.ts +327 -0
- package/dist/types/components/questionnaire/questionnaire.d.ts +449 -0
- package/dist/types/components/sheet/sheet-stack.d.ts +167 -0
- package/dist/types/components/sheet/sheet.d.ts +294 -0
- package/dist/types/components/split-view/split-view.d.ts +2 -21
- package/dist/types/components/table/table.d.ts +219 -12
- package/dist/types/components/tooltip/tooltip.d.ts +2 -2
- package/dist/types/components/value-list/value-list.d.ts +24 -3
- package/dist/types/core/dom.d.ts +114 -0
- package/dist/types/core/drag-axis.d.ts +111 -0
- package/dist/types/core/position.d.ts +4 -2
- package/dist/types/index.d.ts +12 -2
- package/dist/zx-compat.esm.js +641 -277
- package/dist/zx-compat.esm.min.js +1 -1
- package/dist/zx-compat.global.js +7609 -2236
- package/dist/zx-compat.global.min.js +3 -3
- package/dist/zx-zeyos.esm.js +546 -87
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +1452 -101
- package/dist/zx.esm.js +7952 -2592
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +7952 -2592
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +2276 -337
- package/docs/llms.md +426 -30
- package/docs/llms.txt +21 -9
- package/package.json +4 -2
- package/src/compat/globals.js +3 -1
- package/src/compat/map/data.js +31 -9
- package/src/components/account-menu/account-menu.css +70 -0
- package/src/components/account-menu/account-menu.js +208 -0
- package/src/components/app-rail/app-rail.css +107 -0
- package/src/components/app-rail/app-rail.js +668 -0
- package/src/components/app-sidebar/app-sidebar.css +68 -0
- package/src/components/app-sidebar/app-sidebar.js +388 -0
- package/src/components/avatar/avatar.css +61 -0
- package/src/components/avatar/avatar.js +222 -0
- package/src/components/button/button.css +0 -1
- package/src/components/chart/chart.css +61 -0
- package/src/components/chart/chart.js +518 -0
- package/src/components/date-picker/month-picker.js +9 -0
- package/src/components/dialog/dialog.js +11 -4
- package/src/components/dock/dock.css +228 -0
- package/src/components/dock/dock.js +977 -0
- package/src/components/dropdown/dropdown.js +1 -1
- package/src/components/field/field.js +2 -0
- package/src/components/field-upload/field-upload.js +9 -4
- package/src/components/form/form.js +6 -3
- package/src/components/grid/grid.css +6 -0
- package/src/components/grid/grid.js +213 -0
- package/src/components/launcher/launcher.css +100 -0
- package/src/components/launcher/launcher.js +557 -0
- package/src/components/layout/layout.js +2 -2
- package/src/components/menu-button/menu-button.js +27 -2
- package/src/components/modal/modal.css +5 -1
- package/src/components/modal/modal.js +37 -2
- package/src/components/multi-value-editor/multi-value-editor.js +2 -1
- package/src/components/questionnaire/items.js +370 -0
- package/src/components/questionnaire/questionnaire.css +387 -0
- package/src/components/questionnaire/questionnaire.js +1033 -0
- package/src/components/select/select.css +0 -1
- package/src/components/sheet/sheet-stack.js +304 -0
- package/src/components/sheet/sheet.css +351 -0
- package/src/components/sheet/sheet.js +551 -0
- package/src/components/split-view/split-view.js +76 -161
- package/src/components/table/table.css +43 -0
- package/src/components/table/table.js +523 -45
- package/src/components/tooltip/tooltip.js +5 -2
- package/src/components/value-list/value-list.js +6 -3
- package/src/core/dom.js +302 -0
- package/src/core/drag-axis.js +203 -0
- package/src/core/position.js +68 -22
- package/src/index.js +19 -2
- package/styles/tokens/dark.css +2 -3
- package/styles/tokens/global.css +5 -5
- package/styles/tokens/semantic.css +5 -3
- package/styles/tokens/themes.css +1 -1
- package/styles/zx.css +10 -1
- package/dist/types/components/permission/permission.d.ts +0 -96
- package/src/components/permission/permission.css +0 -47
- package/src/components/permission/permission.js +0 -201
package/dist/zx-compat.esm.js
CHANGED
|
@@ -347,7 +347,7 @@ function parse(source) {
|
|
|
347
347
|
}
|
|
348
348
|
function installGlobals(host = globalThis) {
|
|
349
349
|
installElementStorage(host);
|
|
350
|
-
host.__ = parse;
|
|
350
|
+
if (host.__ === void 0) host.__ = parse;
|
|
351
351
|
const stringPrototype = host.String?.prototype;
|
|
352
352
|
if (stringPrototype && typeof stringPrototype.htmlSpecialChars !== "function") {
|
|
353
353
|
Object.defineProperty(stringPrototype, "htmlSpecialChars", {
|
|
@@ -2838,6 +2838,14 @@ var MonthPicker = class extends DatePicker {
|
|
|
2838
2838
|
static cssName = "month-picker";
|
|
2839
2839
|
/** @type {MonthPickerOptions} */
|
|
2840
2840
|
static defaults = { value: null, min: null, max: null };
|
|
2841
|
+
/**
|
|
2842
|
+
* Creates a month picker with its narrower month-based option contract.
|
|
2843
|
+
* @param {Element|string|null} target Existing element, selector, or null.
|
|
2844
|
+
* @param {MonthPickerOptions} [options={}] Month-picker options.
|
|
2845
|
+
*/
|
|
2846
|
+
constructor(target, options = {}) {
|
|
2847
|
+
super(target, options);
|
|
2848
|
+
}
|
|
2841
2849
|
/** @returns {HTMLElement} */
|
|
2842
2850
|
render() {
|
|
2843
2851
|
const root = (
|
|
@@ -3057,7 +3065,13 @@ var PLACEMENTS = /* @__PURE__ */ new Set([
|
|
|
3057
3065
|
"top-start",
|
|
3058
3066
|
"top-end",
|
|
3059
3067
|
"bottom",
|
|
3060
|
-
"top"
|
|
3068
|
+
"top",
|
|
3069
|
+
"right-start",
|
|
3070
|
+
"right-end",
|
|
3071
|
+
"left-start",
|
|
3072
|
+
"left-end",
|
|
3073
|
+
"right",
|
|
3074
|
+
"left"
|
|
3061
3075
|
]);
|
|
3062
3076
|
function position(anchor, floating, options = {}) {
|
|
3063
3077
|
if (!(anchor instanceof Element) || !(floating instanceof HTMLElement)) {
|
|
@@ -3085,13 +3099,15 @@ function position(anchor, floating, options = {}) {
|
|
|
3085
3099
|
floating.style.inset = "auto";
|
|
3086
3100
|
floating.style.margin = "0";
|
|
3087
3101
|
floating.style.setProperty("position-anchor", anchorName);
|
|
3088
|
-
|
|
3089
|
-
floating.style.setProperty("
|
|
3102
|
+
const area = positionArea(placement, getComputedStyle(anchor).direction === "rtl");
|
|
3103
|
+
floating.style.setProperty("position-area", area);
|
|
3104
|
+
floating.style.setProperty("inset-area", area);
|
|
3090
3105
|
floating.style.setProperty(
|
|
3091
3106
|
"position-try-fallbacks",
|
|
3092
3107
|
flip ? "flip-block, flip-inline, flip-block flip-inline" : "none"
|
|
3093
3108
|
);
|
|
3094
|
-
|
|
3109
|
+
const margin = placement.startsWith("top") ? "margin-bottom" : placement.startsWith("bottom") ? "margin-top" : placement.startsWith("left") ? "margin-right" : "margin-left";
|
|
3110
|
+
floating.style.setProperty(margin, `${offset}px`);
|
|
3095
3111
|
update = () => {
|
|
3096
3112
|
if (matchWidth) floating.style.minWidth = `${anchor.getBoundingClientRect().width}px`;
|
|
3097
3113
|
};
|
|
@@ -3135,14 +3151,20 @@ function position(anchor, floating, options = {}) {
|
|
|
3135
3151
|
}
|
|
3136
3152
|
};
|
|
3137
3153
|
}
|
|
3138
|
-
function positionArea(placement) {
|
|
3154
|
+
function positionArea(placement, rtl) {
|
|
3139
3155
|
return {
|
|
3140
|
-
"bottom-start": "
|
|
3141
|
-
"bottom-end": "
|
|
3142
|
-
"top-start": "
|
|
3143
|
-
"top-end": "
|
|
3144
|
-
|
|
3145
|
-
|
|
3156
|
+
"bottom-start": rtl ? "bottom span-left" : "bottom span-right",
|
|
3157
|
+
"bottom-end": rtl ? "bottom span-right" : "bottom span-left",
|
|
3158
|
+
"top-start": rtl ? "top span-left" : "top span-right",
|
|
3159
|
+
"top-end": rtl ? "top span-right" : "top span-left",
|
|
3160
|
+
"right-start": "right span-bottom",
|
|
3161
|
+
"right-end": "right span-top",
|
|
3162
|
+
"left-start": "left span-bottom",
|
|
3163
|
+
"left-end": "left span-top",
|
|
3164
|
+
bottom: "bottom",
|
|
3165
|
+
top: "top",
|
|
3166
|
+
right: "right",
|
|
3167
|
+
left: "left"
|
|
3146
3168
|
}[placement];
|
|
3147
3169
|
}
|
|
3148
3170
|
function updateFallback(anchor, floating, { placement, offset, flip, matchWidth }) {
|
|
@@ -3152,26 +3174,54 @@ function updateFallback(anchor, floating, { placement, offset, flip, matchWidth
|
|
|
3152
3174
|
const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
|
|
3153
3175
|
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
3154
3176
|
let actualPlacement = placement;
|
|
3155
|
-
const
|
|
3177
|
+
const side = placementSide(placement);
|
|
3156
3178
|
const bottomY = anchorRect.bottom + offset;
|
|
3157
3179
|
const topY = anchorRect.top - offset - floatingRect.height;
|
|
3180
|
+
const rightX = anchorRect.right + offset;
|
|
3181
|
+
const leftX = anchorRect.left - offset - floatingRect.width;
|
|
3158
3182
|
if (flip) {
|
|
3159
|
-
if (
|
|
3160
|
-
actualPlacement =
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
placement
|
|
3183
|
+
if (side === "bottom" && bottomY + floatingRect.height > viewportHeight && topY >= 0) {
|
|
3184
|
+
actualPlacement = flipPlacement(placement, "bottom", "top");
|
|
3185
|
+
} else if (side === "top" && topY < 0 && bottomY + floatingRect.height <= viewportHeight) {
|
|
3186
|
+
actualPlacement = flipPlacement(placement, "top", "bottom");
|
|
3187
|
+
} else if (side === "right" && rightX + floatingRect.width > viewportWidth && leftX >= 0) {
|
|
3188
|
+
actualPlacement = flipPlacement(placement, "right", "left");
|
|
3189
|
+
} else if (side === "left" && leftX < 0 && rightX + floatingRect.width <= viewportWidth) {
|
|
3190
|
+
actualPlacement = flipPlacement(placement, "left", "right");
|
|
3165
3191
|
}
|
|
3166
3192
|
}
|
|
3193
|
+
const actualSide = placementSide(actualPlacement);
|
|
3167
3194
|
let left;
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3195
|
+
let top;
|
|
3196
|
+
if (actualSide === "bottom" || actualSide === "top") {
|
|
3197
|
+
const rtl = getComputedStyle(anchor).direction === "rtl";
|
|
3198
|
+
if (actualPlacement.endsWith("-end")) {
|
|
3199
|
+
left = rtl ? anchorRect.left : anchorRect.right - floatingRect.width;
|
|
3200
|
+
} else if (actualPlacement.endsWith("-start")) {
|
|
3201
|
+
left = rtl ? anchorRect.right - floatingRect.width : anchorRect.left;
|
|
3202
|
+
} else left = anchorRect.left + (anchorRect.width - floatingRect.width) / 2;
|
|
3203
|
+
top = actualSide === "bottom" ? bottomY : topY;
|
|
3204
|
+
} else {
|
|
3205
|
+
left = actualSide === "right" ? rightX : leftX;
|
|
3206
|
+
if (actualPlacement.endsWith("-end")) top = anchorRect.bottom - floatingRect.height;
|
|
3207
|
+
else if (actualPlacement.endsWith("-start")) top = anchorRect.top;
|
|
3208
|
+
else top = anchorRect.top + (anchorRect.height - floatingRect.height) / 2;
|
|
3209
|
+
}
|
|
3172
3210
|
floating.style.left = `${Math.round(clamp(left, 0, Math.max(0, viewportWidth - floatingRect.width)))}px`;
|
|
3173
3211
|
floating.style.top = `${Math.round(clamp(top, 0, Math.max(0, viewportHeight - floatingRect.height)))}px`;
|
|
3174
3212
|
}
|
|
3213
|
+
function placementSide(placement) {
|
|
3214
|
+
return (
|
|
3215
|
+
/** @type {'top'|'bottom'|'left'|'right'} */
|
|
3216
|
+
placement.split("-")[0]
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3219
|
+
function flipPlacement(placement, from, to) {
|
|
3220
|
+
return (
|
|
3221
|
+
/** @type {Placement} */
|
|
3222
|
+
placement.replace(from, to)
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3175
3225
|
function showPopover(element) {
|
|
3176
3226
|
if (typeof element.showPopover !== "function") return;
|
|
3177
3227
|
try {
|
|
@@ -4004,31 +4054,31 @@ var PLACEHOLDER_TOKENS = {
|
|
|
4004
4054
|
"%Y": "YYYY",
|
|
4005
4055
|
"%y": "YY"
|
|
4006
4056
|
};
|
|
4007
|
-
function parseRangeText(text3,
|
|
4057
|
+
function parseRangeText(text3, format2, separator) {
|
|
4008
4058
|
const source = String(text3 ?? "").trim();
|
|
4009
4059
|
if (source === "") return { start: null, end: null };
|
|
4010
4060
|
const raw2 = String(separator ?? " \u2013 ");
|
|
4011
4061
|
const core = raw2.trim();
|
|
4012
|
-
const strict = core !== "" && String(
|
|
4062
|
+
const strict = core !== "" && String(format2).includes(core) && /^\s|\s$/.test(raw2);
|
|
4013
4063
|
const lead = strict ? "\\s+" : "\\s*";
|
|
4014
4064
|
const tail = strict ? "(?:\\s+|$)" : "\\s*";
|
|
4015
4065
|
const parts = core === "" ? [source] : source.split(new RegExp(`${lead}${escapeRegExp(core)}${tail}`));
|
|
4016
4066
|
if (parts.length > 2) return null;
|
|
4017
|
-
const first = parseDate(parts[0].trim(),
|
|
4067
|
+
const first = parseDate(parts[0].trim(), format2);
|
|
4018
4068
|
if (!first) return null;
|
|
4019
4069
|
if (parts.length === 1) return { start: first, end: new Date(first.getTime()) };
|
|
4020
4070
|
if (parts[1].trim() === "") return { start: first, end: null };
|
|
4021
|
-
const second = parseDate(parts[1].trim(),
|
|
4071
|
+
const second = parseDate(parts[1].trim(), format2);
|
|
4022
4072
|
if (!second) return null;
|
|
4023
4073
|
return normalizeRange(first, second);
|
|
4024
4074
|
}
|
|
4025
|
-
function formatRangeText(range,
|
|
4075
|
+
function formatRangeText(range, format2, separator) {
|
|
4026
4076
|
const start = range?.start ?? null;
|
|
4027
4077
|
const end = range?.end ?? null;
|
|
4028
4078
|
if (!start && !end) return "";
|
|
4029
|
-
if (!end) return formatDate(start,
|
|
4030
|
-
if (!start) return formatDate(end,
|
|
4031
|
-
return `${formatDate(start,
|
|
4079
|
+
if (!end) return formatDate(start, format2);
|
|
4080
|
+
if (!start) return formatDate(end, format2);
|
|
4081
|
+
return `${formatDate(start, format2)}${separator}${formatDate(end, format2)}`;
|
|
4032
4082
|
}
|
|
4033
4083
|
var DateRangeBox = class extends Component {
|
|
4034
4084
|
static cssName = "date-range-box";
|
|
@@ -4686,12 +4736,12 @@ var DateTimeBox = function DateTimeBox2(target, options = {}) {
|
|
|
4686
4736
|
function validDate4(value) {
|
|
4687
4737
|
return value instanceof Date && !Number.isNaN(value.getTime()) ? new Date(value.getTime()) : null;
|
|
4688
4738
|
}
|
|
4689
|
-
function effectiveFormat(
|
|
4690
|
-
const value = String(
|
|
4739
|
+
function effectiveFormat(format2, time) {
|
|
4740
|
+
const value = String(format2 || "%d.%m.%Y");
|
|
4691
4741
|
return time && !/%[HM]/.test(value) ? `${value} %H:%M` : value;
|
|
4692
4742
|
}
|
|
4693
|
-
function placeholderFromFormat(
|
|
4694
|
-
return
|
|
4743
|
+
function placeholderFromFormat(format2) {
|
|
4744
|
+
return format2.replace(/%[demYyHMS]/g, (token) => ({
|
|
4695
4745
|
"%d": "DD",
|
|
4696
4746
|
"%e": "D",
|
|
4697
4747
|
"%m": "MM",
|
|
@@ -8263,9 +8313,9 @@ var TagPicker = class extends Component {
|
|
|
8263
8313
|
function normalizeLabel(value) {
|
|
8264
8314
|
return String(value ?? "").trim().toLocaleLowerCase();
|
|
8265
8315
|
}
|
|
8266
|
-
function sameSelection(a, b,
|
|
8316
|
+
function sameSelection(a, b, read) {
|
|
8267
8317
|
if (a.length !== b.length) return false;
|
|
8268
|
-
return a.every((item, index) => Object.is(
|
|
8318
|
+
return a.every((item, index) => Object.is(read(item), read(b[index])));
|
|
8269
8319
|
}
|
|
8270
8320
|
|
|
8271
8321
|
// src/components/tag-picker/field-adapter.js
|
|
@@ -9235,6 +9285,82 @@ function isFileList(value) {
|
|
|
9235
9285
|
return typeof FileList === "function" && value instanceof FileList;
|
|
9236
9286
|
}
|
|
9237
9287
|
|
|
9288
|
+
// src/core/format.js
|
|
9289
|
+
var MIN_DIGITS = 0;
|
|
9290
|
+
var MAX_DIGITS = 20;
|
|
9291
|
+
var DEFAULT_MAX_DIGITS = 3;
|
|
9292
|
+
var numberFormatters = /* @__PURE__ */ new Map();
|
|
9293
|
+
function formatNumber(value, options = {}) {
|
|
9294
|
+
const number = toFiniteNumber(value);
|
|
9295
|
+
if (number === null) return "";
|
|
9296
|
+
const { locale = getLanguage(), decimals, minDecimals, maxDecimals, group = true } = options;
|
|
9297
|
+
return format(locale, digitOptions({ decimals, minDecimals, maxDecimals, group }), number);
|
|
9298
|
+
}
|
|
9299
|
+
function formatCurrency(value, currency, options = {}) {
|
|
9300
|
+
const number = toFiniteNumber(value);
|
|
9301
|
+
if (number === null) return "";
|
|
9302
|
+
const { locale = getLanguage(), decimals } = options;
|
|
9303
|
+
const code = currencyCode(currency);
|
|
9304
|
+
if (code === null) return formatNumber(number, { locale, decimals });
|
|
9305
|
+
const digits = digitOptions({ decimals, group: true });
|
|
9306
|
+
return format(locale, { ...digits, style: "currency", currency: code }, number);
|
|
9307
|
+
}
|
|
9308
|
+
function formatPercent(value, options = {}) {
|
|
9309
|
+
const number = toFiniteNumber(value);
|
|
9310
|
+
if (number === null) return "";
|
|
9311
|
+
const { locale = getLanguage(), decimals = 0 } = options;
|
|
9312
|
+
return format(locale, { ...digitOptions({ decimals, group: true }), style: "percent" }, number);
|
|
9313
|
+
}
|
|
9314
|
+
function format(locale, options, value) {
|
|
9315
|
+
const key = `${locale}\0${JSON.stringify(options)}`;
|
|
9316
|
+
let formatter = numberFormatters.get(key);
|
|
9317
|
+
if (formatter === void 0) {
|
|
9318
|
+
formatter = createNumberFormat(locale, options);
|
|
9319
|
+
numberFormatters.set(key, formatter);
|
|
9320
|
+
}
|
|
9321
|
+
return formatter.format(value);
|
|
9322
|
+
}
|
|
9323
|
+
function createNumberFormat(locale, options) {
|
|
9324
|
+
try {
|
|
9325
|
+
return new Intl.NumberFormat(locale, options);
|
|
9326
|
+
} catch {
|
|
9327
|
+
try {
|
|
9328
|
+
return new Intl.NumberFormat(void 0, options);
|
|
9329
|
+
} catch {
|
|
9330
|
+
return new Intl.NumberFormat();
|
|
9331
|
+
}
|
|
9332
|
+
}
|
|
9333
|
+
}
|
|
9334
|
+
function digitOptions({ decimals, minDecimals, maxDecimals, group = true }) {
|
|
9335
|
+
const result = { useGrouping: group !== false };
|
|
9336
|
+
const min = digitCount(minDecimals ?? decimals);
|
|
9337
|
+
const max = digitCount(maxDecimals ?? decimals);
|
|
9338
|
+
if (min !== null) result.minimumFractionDigits = min;
|
|
9339
|
+
if (max !== null) {
|
|
9340
|
+
result.maximumFractionDigits = max;
|
|
9341
|
+
if (min !== null && min > max) result.minimumFractionDigits = max;
|
|
9342
|
+
} else if (min !== null) {
|
|
9343
|
+
result.maximumFractionDigits = Math.max(min, DEFAULT_MAX_DIGITS);
|
|
9344
|
+
}
|
|
9345
|
+
return result;
|
|
9346
|
+
}
|
|
9347
|
+
function digitCount(value) {
|
|
9348
|
+
if (value == null) return null;
|
|
9349
|
+
const number = Number(value);
|
|
9350
|
+
if (!Number.isFinite(number)) return null;
|
|
9351
|
+
return Math.min(MAX_DIGITS, Math.max(MIN_DIGITS, Math.round(number)));
|
|
9352
|
+
}
|
|
9353
|
+
function toFiniteNumber(value) {
|
|
9354
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
9355
|
+
const number = typeof value === "number" ? value : Number(value);
|
|
9356
|
+
return Number.isFinite(number) ? number : null;
|
|
9357
|
+
}
|
|
9358
|
+
function currencyCode(value) {
|
|
9359
|
+
if (typeof value !== "string") return null;
|
|
9360
|
+
const code = value.trim().toUpperCase();
|
|
9361
|
+
return /^[A-Z]{3}$/.test(code) ? code : null;
|
|
9362
|
+
}
|
|
9363
|
+
|
|
9238
9364
|
// src/components/check-button/check-button.js
|
|
9239
9365
|
var CheckButton = class extends Component {
|
|
9240
9366
|
static cssName = "check-button";
|
|
@@ -9395,6 +9521,7 @@ var Modal = class extends Component {
|
|
|
9395
9521
|
if (!this.options.closable || cancelEvent.defaultPrevented) event.preventDefault();
|
|
9396
9522
|
});
|
|
9397
9523
|
this.listen(this.el, "close", () => {
|
|
9524
|
+
if (!this._isRealClose()) return;
|
|
9398
9525
|
this.el.dataset.state = "closed";
|
|
9399
9526
|
delete this.el.dataset.zxOverlayOrder;
|
|
9400
9527
|
const result = this.#hasPendingResult ? this.#pendingResult : this.el.returnValue || void 0;
|
|
@@ -9408,6 +9535,37 @@ var Modal = class extends Component {
|
|
|
9408
9535
|
this.close();
|
|
9409
9536
|
});
|
|
9410
9537
|
}
|
|
9538
|
+
/**
|
|
9539
|
+
* Element the owned dialog is appended to. Overridden by subclasses that live inside a host
|
|
9540
|
+
* rather than at the document level.
|
|
9541
|
+
*
|
|
9542
|
+
* Called from `render()`, which the base constructor runs before any subclass field
|
|
9543
|
+
* initializers, so an override may read `this.options` but must not touch instance state.
|
|
9544
|
+
* @returns {Element}
|
|
9545
|
+
*/
|
|
9546
|
+
mountTarget() {
|
|
9547
|
+
return document.body;
|
|
9548
|
+
}
|
|
9549
|
+
/**
|
|
9550
|
+
* Puts the dialog on screen. Overridden by subclasses that open non-modally.
|
|
9551
|
+
* @returns {void}
|
|
9552
|
+
*/
|
|
9553
|
+
_show() {
|
|
9554
|
+
this.el.showModal();
|
|
9555
|
+
}
|
|
9556
|
+
/**
|
|
9557
|
+
* Whether an incoming `close` event is a real dismissal.
|
|
9558
|
+
*
|
|
9559
|
+
* A dialog cannot move between the top layer and the page flow while it is open, so a subclass
|
|
9560
|
+
* that re-hosts itself has to close and immediately reopen. `close` is dispatched in a queued
|
|
9561
|
+
* task, not synchronously, so that stale event arrives once the dialog is already open again —
|
|
9562
|
+
* late enough to clobber `data-state`, fire a `close` nobody asked for, and trip
|
|
9563
|
+
* `destroyOnClose`. Returning false from an override drops it at the source instead.
|
|
9564
|
+
* @returns {boolean}
|
|
9565
|
+
*/
|
|
9566
|
+
_isRealClose() {
|
|
9567
|
+
return true;
|
|
9568
|
+
}
|
|
9411
9569
|
/**
|
|
9412
9570
|
* Creates the owned native dialog.
|
|
9413
9571
|
* @returns {HTMLDialogElement}
|
|
@@ -9420,7 +9578,7 @@ var Modal = class extends Component {
|
|
|
9420
9578
|
}, h("div", { class: "zx-modal__content", ref: "content" }))
|
|
9421
9579
|
);
|
|
9422
9580
|
dialog.dataset.state = "closed";
|
|
9423
|
-
|
|
9581
|
+
this.mountTarget().append(dialog);
|
|
9424
9582
|
return dialog;
|
|
9425
9583
|
}
|
|
9426
9584
|
/**
|
|
@@ -9433,7 +9591,7 @@ var Modal = class extends Component {
|
|
|
9433
9591
|
this.el.dataset.zxOverlayOrder = String(nextOverlayOrder());
|
|
9434
9592
|
this.el.returnValue = "";
|
|
9435
9593
|
try {
|
|
9436
|
-
this.
|
|
9594
|
+
this._show();
|
|
9437
9595
|
} catch (error) {
|
|
9438
9596
|
delete this.el.dataset.zxOverlayOrder;
|
|
9439
9597
|
throw error;
|
|
@@ -9548,7 +9706,7 @@ var Dialog = class _Dialog extends Modal {
|
|
|
9548
9706
|
*/
|
|
9549
9707
|
constructor(_target = null, options = {}) {
|
|
9550
9708
|
super(null, options);
|
|
9551
|
-
this
|
|
9709
|
+
this._applySize(this.options.size);
|
|
9552
9710
|
this.#baseTitle = String(this.options.title ?? "");
|
|
9553
9711
|
this.#applyTitle(this.#baseTitle);
|
|
9554
9712
|
this.#baseButtons = copyButtons(this.options.buttons);
|
|
@@ -9598,7 +9756,7 @@ var Dialog = class _Dialog extends Modal {
|
|
|
9598
9756
|
)
|
|
9599
9757
|
);
|
|
9600
9758
|
dialog.dataset.state = "closed";
|
|
9601
|
-
|
|
9759
|
+
this.mountTarget().append(dialog);
|
|
9602
9760
|
return dialog;
|
|
9603
9761
|
}
|
|
9604
9762
|
/**
|
|
@@ -9820,8 +9978,15 @@ var Dialog = class _Dialog extends Modal {
|
|
|
9820
9978
|
dialog.open();
|
|
9821
9979
|
});
|
|
9822
9980
|
}
|
|
9823
|
-
/**
|
|
9824
|
-
|
|
9981
|
+
/**
|
|
9982
|
+
* Applies the dialog width. Subclasses that size themselves on a different axis override this.
|
|
9983
|
+
*
|
|
9984
|
+
* Called from the constructor before any subclass field initializers have run, so an override
|
|
9985
|
+
* may only touch the DOM — reading an uninitialized private field here throws.
|
|
9986
|
+
* @param {'sm'|'md'|'lg'|number} size Preset or pixel width.
|
|
9987
|
+
* @returns {void}
|
|
9988
|
+
*/
|
|
9989
|
+
_applySize(size) {
|
|
9825
9990
|
const presets = { sm: 400, md: 600, lg: 840 };
|
|
9826
9991
|
const width = typeof size === "number" && Number.isFinite(size) ? size : presets[size] ?? presets.md;
|
|
9827
9992
|
this.el.style.inlineSize = `${Math.max(0, width)}px`;
|
|
@@ -10641,7 +10806,8 @@ var Table = class extends Component {
|
|
|
10641
10806
|
emptyText: null,
|
|
10642
10807
|
rowClass: null,
|
|
10643
10808
|
zebra: true,
|
|
10644
|
-
editMode: false
|
|
10809
|
+
editMode: false,
|
|
10810
|
+
hierarchy: false
|
|
10645
10811
|
};
|
|
10646
10812
|
/**
|
|
10647
10813
|
* Creates a table around a target or creates a new root when target is null.
|
|
@@ -10678,8 +10844,17 @@ var Table = class extends Component {
|
|
|
10678
10844
|
this._rovingKey = null;
|
|
10679
10845
|
this._rovingCell = null;
|
|
10680
10846
|
this._rovingMatched = false;
|
|
10847
|
+
this._hierarchy = normalizeHierarchy(this.options.hierarchy, this._columns);
|
|
10848
|
+
this._expanded = initialExpanded(this._hierarchy?.expanded);
|
|
10681
10849
|
if (this._sort && this.options.sortMode === "local") this._sortData();
|
|
10850
|
+
if (this._hierarchy?.expanded === true) {
|
|
10851
|
+
for (const id of hierarchyBranchIds(this._data, this.options.rowId, this._hierarchy.parentId)) {
|
|
10852
|
+
this._expanded.add(id);
|
|
10853
|
+
}
|
|
10854
|
+
}
|
|
10855
|
+
this._reconcileExpanded();
|
|
10682
10856
|
this._table = h("table", { class: "zx-table__table" });
|
|
10857
|
+
if (this._hierarchy) this._table.setAttribute("role", "treegrid");
|
|
10683
10858
|
this._colgroup = h("colgroup", { class: "zx-table__columns" });
|
|
10684
10859
|
this._thead = h("thead", { class: "zx-table__head" });
|
|
10685
10860
|
this._tbody = h("tbody", { class: "zx-table__body" });
|
|
@@ -10748,6 +10923,7 @@ var Table = class extends Component {
|
|
|
10748
10923
|
assertRows(rows);
|
|
10749
10924
|
this._data = [...rows];
|
|
10750
10925
|
if (this._sort && this.options.sortMode === "local") this._sortData();
|
|
10926
|
+
this._reconcileExpanded();
|
|
10751
10927
|
const selectionChanged = this._pruneSelection();
|
|
10752
10928
|
this._renderBody();
|
|
10753
10929
|
if (selectionChanged) this._emitSelectionChange();
|
|
@@ -10765,6 +10941,7 @@ var Table = class extends Component {
|
|
|
10765
10941
|
assertRows(rows);
|
|
10766
10942
|
this._data.push(...rows);
|
|
10767
10943
|
if (this._sort && this.options.sortMode === "local") this._sortData();
|
|
10944
|
+
this._reconcileExpanded();
|
|
10768
10945
|
this._renderBody();
|
|
10769
10946
|
this._emitDataChange();
|
|
10770
10947
|
return this;
|
|
@@ -10784,6 +10961,7 @@ var Table = class extends Component {
|
|
|
10784
10961
|
this._data[index] = row;
|
|
10785
10962
|
if (wasSelected) this._selected.add(this._idFor(row));
|
|
10786
10963
|
if (this._sort && this.options.sortMode === "local") this._sortData();
|
|
10964
|
+
this._reconcileExpanded();
|
|
10787
10965
|
this._renderBody();
|
|
10788
10966
|
if (wasSelected && !Object.is(id, this._idFor(row))) this._emitSelectionChange();
|
|
10789
10967
|
this._emitDataChange();
|
|
@@ -10801,6 +10979,7 @@ var Table = class extends Component {
|
|
|
10801
10979
|
const index = this._data.findIndex((candidate) => Object.is(this._idFor(candidate), id));
|
|
10802
10980
|
if (index < 0) return this;
|
|
10803
10981
|
this._data.splice(index, 1);
|
|
10982
|
+
this._reconcileExpanded();
|
|
10804
10983
|
const selectionChanged = this._selected.delete(id);
|
|
10805
10984
|
if (Object.is(this._selectionAnchorId, id)) this._selectionAnchorId = null;
|
|
10806
10985
|
this._renderBody();
|
|
@@ -10816,7 +10995,10 @@ var Table = class extends Component {
|
|
|
10816
10995
|
getRow(id) {
|
|
10817
10996
|
return this._data.find((row) => Object.is(this._idFor(row), id)) ?? null;
|
|
10818
10997
|
}
|
|
10819
|
-
/**
|
|
10998
|
+
/**
|
|
10999
|
+
* Returns a shallow copy of the current rows in display order.
|
|
11000
|
+
* @returns {TableRow[]} Current table rows.
|
|
11001
|
+
*/
|
|
10820
11002
|
getData() {
|
|
10821
11003
|
return [...this._data];
|
|
10822
11004
|
}
|
|
@@ -10830,6 +11012,7 @@ var Table = class extends Component {
|
|
|
10830
11012
|
empty() {
|
|
10831
11013
|
const selectionChanged = this._selected.size > 0;
|
|
10832
11014
|
this._data = [];
|
|
11015
|
+
this._expanded.clear();
|
|
10833
11016
|
this._selected.clear();
|
|
10834
11017
|
this._selectionAnchorId = null;
|
|
10835
11018
|
this._renderBody();
|
|
@@ -10864,7 +11047,10 @@ var Table = class extends Component {
|
|
|
10864
11047
|
if (!options.silent) this.emit("sort", { id, dir: direction });
|
|
10865
11048
|
return this;
|
|
10866
11049
|
}
|
|
10867
|
-
/**
|
|
11050
|
+
/**
|
|
11051
|
+
* Returns selected rows in current display order.
|
|
11052
|
+
* @returns {TableRow[]} Selected rows.
|
|
11053
|
+
*/
|
|
10868
11054
|
getSelection() {
|
|
10869
11055
|
return this._data.filter((row) => this._selected.has(this._idFor(row)));
|
|
10870
11056
|
}
|
|
@@ -10903,6 +11089,75 @@ var Table = class extends Component {
|
|
|
10903
11089
|
this._emitSelectionChange();
|
|
10904
11090
|
return this;
|
|
10905
11091
|
}
|
|
11092
|
+
/**
|
|
11093
|
+
* Toggles one hierarchy branch. A leaf or an id absent from the table is a no-op.
|
|
11094
|
+
* @param {unknown} id Row id.
|
|
11095
|
+
* @param {{silent?: boolean}} [options={}] Event behavior.
|
|
11096
|
+
* @returns {this}
|
|
11097
|
+
* @fires Table#rowtoggle
|
|
11098
|
+
*/
|
|
11099
|
+
toggleRow(id, options = {}) {
|
|
11100
|
+
return this._expanded.has(id) ? this.collapseRow(id, options) : this.expandRow(id, options);
|
|
11101
|
+
}
|
|
11102
|
+
/**
|
|
11103
|
+
* Expands one hierarchy branch.
|
|
11104
|
+
* @param {unknown} id Row id.
|
|
11105
|
+
* @param {{silent?: boolean}} [options={}] Event behavior.
|
|
11106
|
+
* @returns {this}
|
|
11107
|
+
* @fires Table#rowtoggle
|
|
11108
|
+
*/
|
|
11109
|
+
expandRow(id, options = {}) {
|
|
11110
|
+
return this._setRowExpanded(id, true, options);
|
|
11111
|
+
}
|
|
11112
|
+
/**
|
|
11113
|
+
* Collapses one hierarchy branch without discarding its descendants or their expansion state.
|
|
11114
|
+
* @param {unknown} id Row id.
|
|
11115
|
+
* @param {{silent?: boolean}} [options={}] Event behavior.
|
|
11116
|
+
* @returns {this}
|
|
11117
|
+
* @fires Table#rowtoggle
|
|
11118
|
+
*/
|
|
11119
|
+
collapseRow(id, options = {}) {
|
|
11120
|
+
return this._setRowExpanded(id, false, options);
|
|
11121
|
+
}
|
|
11122
|
+
/**
|
|
11123
|
+
* Expands every row that currently has children.
|
|
11124
|
+
* @param {{silent?: boolean}} [options={}] Event behavior. When not silent, one `rowtoggle`
|
|
11125
|
+
* event is emitted per branch whose state changed.
|
|
11126
|
+
* @returns {this}
|
|
11127
|
+
*/
|
|
11128
|
+
expandAll(options = {}) {
|
|
11129
|
+
if (!this._hierarchy) return this;
|
|
11130
|
+
const branchIds = hierarchyBranchIds(this._data, this.options.rowId, this._hierarchy.parentId);
|
|
11131
|
+
const changed = branchIds.filter((id) => !this._expanded.has(id));
|
|
11132
|
+
for (const id of changed) this._expanded.add(id);
|
|
11133
|
+
if (changed.length) this._renderBody();
|
|
11134
|
+
if (!options.silent) {
|
|
11135
|
+
for (const id of changed) this._emitRowToggle(id, true);
|
|
11136
|
+
}
|
|
11137
|
+
return this;
|
|
11138
|
+
}
|
|
11139
|
+
/**
|
|
11140
|
+
* Collapses every hierarchy branch.
|
|
11141
|
+
* @param {{silent?: boolean}} [options={}] Event behavior.
|
|
11142
|
+
* @returns {this}
|
|
11143
|
+
*/
|
|
11144
|
+
collapseAll(options = {}) {
|
|
11145
|
+
if (!this._hierarchy || this._expanded.size === 0) return this;
|
|
11146
|
+
const changed = [...this._expanded];
|
|
11147
|
+
this._expanded.clear();
|
|
11148
|
+
this._renderBody();
|
|
11149
|
+
if (!options.silent) {
|
|
11150
|
+
for (const id of changed) this._emitRowToggle(id, false);
|
|
11151
|
+
}
|
|
11152
|
+
return this;
|
|
11153
|
+
}
|
|
11154
|
+
/**
|
|
11155
|
+
* Returns expanded branch ids in current flat-data order.
|
|
11156
|
+
* @returns {unknown[]} Expanded branch ids.
|
|
11157
|
+
*/
|
|
11158
|
+
getExpanded() {
|
|
11159
|
+
return this._data.map((row) => this._idFor(row)).filter((id) => this._expanded.has(id));
|
|
11160
|
+
}
|
|
10906
11161
|
/**
|
|
10907
11162
|
* Opens the editor for a cell. No-op unless the table runs with `editMode` and the column
|
|
10908
11163
|
* resolves to an editable type for that row. In `'row'` mode every editable cell of the row is
|
|
@@ -11010,11 +11265,17 @@ var Table = class extends Component {
|
|
|
11010
11265
|
this._abortEdit({ focus: true });
|
|
11011
11266
|
return this;
|
|
11012
11267
|
}
|
|
11013
|
-
/**
|
|
11268
|
+
/**
|
|
11269
|
+
* Reports whether a cell or row is currently open for editing.
|
|
11270
|
+
* @returns {boolean} Whether an edit is open.
|
|
11271
|
+
*/
|
|
11014
11272
|
isEditing() {
|
|
11015
11273
|
return this._edit !== null;
|
|
11016
11274
|
}
|
|
11017
|
-
/**
|
|
11275
|
+
/**
|
|
11276
|
+
* Returns the row id and focused column id for the open edit.
|
|
11277
|
+
* @returns {{id: unknown, columnId: string}|null} Editing location, or null.
|
|
11278
|
+
*/
|
|
11018
11279
|
getEditing() {
|
|
11019
11280
|
return this._edit ? { id: this._edit.id, columnId: this._edit.columnId } : null;
|
|
11020
11281
|
}
|
|
@@ -11023,7 +11284,31 @@ var Table = class extends Component {
|
|
|
11023
11284
|
* @returns {TableRow[]}
|
|
11024
11285
|
*/
|
|
11025
11286
|
_visibleData() {
|
|
11026
|
-
return this.
|
|
11287
|
+
return this._visibleEntries().map((entry) => entry.row);
|
|
11288
|
+
}
|
|
11289
|
+
/** @returns {TableHierarchyEntry[]} Rows visible after hierarchy expansion, before growing. */
|
|
11290
|
+
_projectedData() {
|
|
11291
|
+
if (!this._hierarchy) {
|
|
11292
|
+
return this._data.map((row, index) => ({
|
|
11293
|
+
row,
|
|
11294
|
+
id: this._idFor(row),
|
|
11295
|
+
index,
|
|
11296
|
+
depth: 0,
|
|
11297
|
+
hasChildren: false,
|
|
11298
|
+
parentId: null
|
|
11299
|
+
}));
|
|
11300
|
+
}
|
|
11301
|
+
return projectHierarchyRows(
|
|
11302
|
+
this._data,
|
|
11303
|
+
this.options.rowId,
|
|
11304
|
+
this._hierarchy.parentId,
|
|
11305
|
+
this._expanded
|
|
11306
|
+
);
|
|
11307
|
+
}
|
|
11308
|
+
/** @returns {TableHierarchyEntry[]} Rows that currently have DOM entries. */
|
|
11309
|
+
_visibleEntries() {
|
|
11310
|
+
const projected = this._projectedData();
|
|
11311
|
+
return this._rendered === Infinity ? projected : projected.slice(0, this._rendered);
|
|
11027
11312
|
}
|
|
11028
11313
|
/**
|
|
11029
11314
|
* Renders the next batch of rows.
|
|
@@ -11035,10 +11320,11 @@ var Table = class extends Component {
|
|
|
11035
11320
|
if (!this._growStep) return this;
|
|
11036
11321
|
const step = Number(count) > 0 ? Math.trunc(Number(count)) : this._growStep;
|
|
11037
11322
|
const before = this._rendered;
|
|
11038
|
-
|
|
11323
|
+
const total = this._projectedData().length;
|
|
11324
|
+
this._rendered = Math.min(total, this._rendered + step);
|
|
11039
11325
|
if (this._rendered === before) return this;
|
|
11040
11326
|
this._renderBody();
|
|
11041
|
-
this.emit("grow", { rendered: this._rendered, total
|
|
11327
|
+
this.emit("grow", { rendered: this._rendered, total });
|
|
11042
11328
|
return this;
|
|
11043
11329
|
}
|
|
11044
11330
|
/**
|
|
@@ -11047,14 +11333,14 @@ var Table = class extends Component {
|
|
|
11047
11333
|
* @fires Table#grow
|
|
11048
11334
|
*/
|
|
11049
11335
|
showAll() {
|
|
11050
|
-
return this.growBy(this.
|
|
11336
|
+
return this.growBy(this._projectedData().length);
|
|
11051
11337
|
}
|
|
11052
11338
|
/**
|
|
11053
11339
|
* How many rows are currently rendered.
|
|
11054
11340
|
* @returns {number}
|
|
11055
11341
|
*/
|
|
11056
11342
|
getRenderedCount() {
|
|
11057
|
-
return Math.min(this._rendered, this.
|
|
11343
|
+
return Math.min(this._rendered, this._projectedData().length);
|
|
11058
11344
|
}
|
|
11059
11345
|
/**
|
|
11060
11346
|
* Keeps the "show more" control in step with what is rendered.
|
|
@@ -11066,7 +11352,7 @@ var Table = class extends Component {
|
|
|
11066
11352
|
*/
|
|
11067
11353
|
_syncGrowing() {
|
|
11068
11354
|
if (!this._growStep) return;
|
|
11069
|
-
const remaining = this.
|
|
11355
|
+
const remaining = this._projectedData().length - this.getRenderedCount();
|
|
11070
11356
|
if (remaining <= 0) {
|
|
11071
11357
|
this._more?.remove();
|
|
11072
11358
|
this._more = null;
|
|
@@ -11137,10 +11423,11 @@ var Table = class extends Component {
|
|
|
11137
11423
|
* @returns {void}
|
|
11138
11424
|
*/
|
|
11139
11425
|
_applyStackedRoles(stacked) {
|
|
11140
|
-
const parts = [[this._table, "table"], [this._thead, "rowgroup"], [this._tbody, "rowgroup"]];
|
|
11426
|
+
const parts = [[this._table, this._hierarchy ? "treegrid" : "table"], [this._thead, "rowgroup"], [this._tbody, "rowgroup"]];
|
|
11141
11427
|
for (const [element, role] of parts) {
|
|
11142
11428
|
if (!element) continue;
|
|
11143
11429
|
if (stacked) element.setAttribute("role", role);
|
|
11430
|
+
else if (element === this._table && this._hierarchy) element.setAttribute("role", "treegrid");
|
|
11144
11431
|
else element.removeAttribute("role");
|
|
11145
11432
|
}
|
|
11146
11433
|
for (const [selector, role] of [["tr", "row"], ["td", "cell"], ["th", "columnheader"]]) {
|
|
@@ -11217,7 +11504,8 @@ var Table = class extends Component {
|
|
|
11217
11504
|
this._headers = /* @__PURE__ */ new Map();
|
|
11218
11505
|
for (const column of this._columns) {
|
|
11219
11506
|
const th = h("th", { scope: "col" });
|
|
11220
|
-
|
|
11507
|
+
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
11508
|
+
if (align) th.dataset.align = align;
|
|
11221
11509
|
if (column.headerTitle) th.title = column.headerTitle;
|
|
11222
11510
|
if (column.sortable) {
|
|
11223
11511
|
const button2 = h("button", {
|
|
@@ -11246,6 +11534,8 @@ var Table = class extends Component {
|
|
|
11246
11534
|
this._rowElements = /* @__PURE__ */ new Map();
|
|
11247
11535
|
this._rovingCell = null;
|
|
11248
11536
|
this._rovingMatched = false;
|
|
11537
|
+
const projected = this._projectedData();
|
|
11538
|
+
this._hierarchyMeta = new Map(projected.map((entry) => [entry.id, entry]));
|
|
11249
11539
|
if (this._data.length === 0) {
|
|
11250
11540
|
fragment.append(h(
|
|
11251
11541
|
"tr",
|
|
@@ -11256,10 +11546,12 @@ var Table = class extends Component {
|
|
|
11256
11546
|
}, this._emptyContent())
|
|
11257
11547
|
));
|
|
11258
11548
|
} else {
|
|
11259
|
-
this.
|
|
11549
|
+
this._visibleEntries().forEach((entry, visibleIndex) => {
|
|
11550
|
+
fragment.append(this._createRow(entry.row, entry.index, { ...entry, visibleIndex }));
|
|
11551
|
+
});
|
|
11260
11552
|
}
|
|
11261
11553
|
this._tbody.replaceChildren(fragment);
|
|
11262
|
-
if (this._growStep) this._table.setAttribute("aria-rowcount", String(
|
|
11554
|
+
if (this._growStep) this._table.setAttribute("aria-rowcount", String(projected.length + 1));
|
|
11263
11555
|
this._syncSelectAll();
|
|
11264
11556
|
this._syncGrowing();
|
|
11265
11557
|
if (this._stacked) this._applyStackedRoles(true);
|
|
@@ -11278,18 +11570,27 @@ var Table = class extends Component {
|
|
|
11278
11570
|
if (empty == null) return this.msg("table.empty");
|
|
11279
11571
|
return typeof empty === "function" ? empty() : empty;
|
|
11280
11572
|
}
|
|
11281
|
-
/**
|
|
11282
|
-
|
|
11573
|
+
/**
|
|
11574
|
+
* @param {TableRow} row
|
|
11575
|
+
* @param {number} index
|
|
11576
|
+
* @param {TableHierarchyEntry & {visibleIndex: number}} tree
|
|
11577
|
+
* @returns {HTMLTableRowElement}
|
|
11578
|
+
*/
|
|
11579
|
+
_createRow(row, index, tree) {
|
|
11283
11580
|
const id = this._idFor(row);
|
|
11284
11581
|
const tr = (
|
|
11285
11582
|
/** @type {HTMLTableRowElement} */
|
|
11286
11583
|
h("tr", { dataset: { row: "" } })
|
|
11287
11584
|
);
|
|
11288
|
-
if (this._growStep) tr.setAttribute("aria-rowindex", String(
|
|
11585
|
+
if (this._growStep) tr.setAttribute("aria-rowindex", String(tree.visibleIndex + 2));
|
|
11289
11586
|
const rowClass = typeof this.options.rowClass === "function" ? this.options.rowClass(row) : "";
|
|
11290
11587
|
if (rowClass) tr.classList.add(...String(rowClass).split(/\s+/).filter(Boolean));
|
|
11291
11588
|
if (this.options.selectable !== false) tr.setAttribute("aria-selected", String(this._selected.has(id)));
|
|
11292
|
-
this.
|
|
11589
|
+
if (this._hierarchy) {
|
|
11590
|
+
tr.setAttribute("aria-level", String(tree.depth + 1));
|
|
11591
|
+
if (tree.hasChildren) tr.setAttribute("aria-expanded", String(this._expanded.has(id)));
|
|
11592
|
+
}
|
|
11593
|
+
this._rowMeta.set(tr, { row, id, index, visibleIndex: tree.visibleIndex });
|
|
11293
11594
|
const elements = this._rowElements.get(id) ?? [];
|
|
11294
11595
|
elements.push(tr);
|
|
11295
11596
|
this._rowElements.set(id, elements);
|
|
@@ -11307,7 +11608,8 @@ var Table = class extends Component {
|
|
|
11307
11608
|
/** @type {HTMLTableCellElement} */
|
|
11308
11609
|
h("td")
|
|
11309
11610
|
);
|
|
11310
|
-
|
|
11611
|
+
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
11612
|
+
if (align) cell.dataset.align = align;
|
|
11311
11613
|
cell.dataset.label = column.label;
|
|
11312
11614
|
if (column.popin === false) cell.dataset.popin = "false";
|
|
11313
11615
|
if (this._editMode !== false) {
|
|
@@ -11318,7 +11620,7 @@ var Table = class extends Component {
|
|
|
11318
11620
|
this._offerRovingCell(cell, id, column.id);
|
|
11319
11621
|
}
|
|
11320
11622
|
}
|
|
11321
|
-
this._renderCellContent(cell, column, row, index);
|
|
11623
|
+
this._renderCellContent(cell, column, row, index, tree);
|
|
11322
11624
|
tr.append(cell);
|
|
11323
11625
|
});
|
|
11324
11626
|
return tr;
|
|
@@ -11329,13 +11631,33 @@ var Table = class extends Component {
|
|
|
11329
11631
|
* @param {TableColumn} column Column definition.
|
|
11330
11632
|
* @param {TableRow} row Row data.
|
|
11331
11633
|
* @param {number} index Row index.
|
|
11634
|
+
* @param {TableHierarchyEntry} [tree] Hierarchy metadata for the row.
|
|
11332
11635
|
* @returns {void}
|
|
11333
11636
|
*/
|
|
11334
|
-
_renderCellContent(cell, column, row, index) {
|
|
11335
|
-
const value =
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
else
|
|
11637
|
+
_renderCellContent(cell, column, row, index, tree = this._hierarchyMeta?.get(this._idFor(row))) {
|
|
11638
|
+
const value = formatTableCell(column, row, index);
|
|
11639
|
+
const content = h("span", { class: "zx-table__cell-content" });
|
|
11640
|
+
if (value && typeof value === "object" && typeof value.nodeType === "number") content.append(value);
|
|
11641
|
+
else if (value != null) content.append(document.createTextNode(String(value)));
|
|
11642
|
+
if (!this._hierarchy || column.id !== this._hierarchy.column || !tree) {
|
|
11643
|
+
cell.replaceChildren(...content.childNodes);
|
|
11644
|
+
return;
|
|
11645
|
+
}
|
|
11646
|
+
const branch = h("span", { class: "zx-table__tree-cell" });
|
|
11647
|
+
branch.style.setProperty("--zx-table-depth", String(tree.depth));
|
|
11648
|
+
if (tree.hasChildren) {
|
|
11649
|
+
const expanded = this._expanded.has(tree.id);
|
|
11650
|
+
branch.append(h("button", {
|
|
11651
|
+
class: "zx-table__tree-toggle",
|
|
11652
|
+
type: "button",
|
|
11653
|
+
ariaExpanded: String(expanded),
|
|
11654
|
+
ariaLabel: `${expanded ? "Collapse" : "Expand"} row ${index + 1}`
|
|
11655
|
+
}, icon(expanded ? "chevron-down" : "chevron-right", { size: 14 })));
|
|
11656
|
+
} else {
|
|
11657
|
+
branch.append(h("span", { class: "zx-table__tree-spacer", ariaHidden: "true" }));
|
|
11658
|
+
}
|
|
11659
|
+
branch.append(content);
|
|
11660
|
+
cell.replaceChildren(branch);
|
|
11339
11661
|
}
|
|
11340
11662
|
/** @param {MouseEvent} event @returns {void} */
|
|
11341
11663
|
_handleBodyClick(event) {
|
|
@@ -11348,7 +11670,15 @@ var Table = class extends Component {
|
|
|
11348
11670
|
if (!rowElement || !this._tbody.contains(rowElement)) return;
|
|
11349
11671
|
const meta = this._rowMeta.get(rowElement);
|
|
11350
11672
|
if (!meta) return;
|
|
11351
|
-
if (this._edit)
|
|
11673
|
+
if (this._edit) {
|
|
11674
|
+
this.commitEdit();
|
|
11675
|
+
if (this._edit) return;
|
|
11676
|
+
}
|
|
11677
|
+
const disclosure = target.closest(".zx-table__tree-toggle");
|
|
11678
|
+
if (disclosure) {
|
|
11679
|
+
this.toggleRow(meta.id);
|
|
11680
|
+
return;
|
|
11681
|
+
}
|
|
11352
11682
|
const checkbox = target.closest(".zx-table__row-checkbox");
|
|
11353
11683
|
if (checkbox && this.options.selectable === "multi") {
|
|
11354
11684
|
this._toggleMultiSelection(
|
|
@@ -11444,7 +11774,15 @@ var Table = class extends Component {
|
|
|
11444
11774
|
return entry;
|
|
11445
11775
|
}
|
|
11446
11776
|
if (type === "number") {
|
|
11447
|
-
const
|
|
11777
|
+
const locale = resolveColumnOption(column.locale, row);
|
|
11778
|
+
const decimals = resolveColumnDecimals(column, row);
|
|
11779
|
+
const suffix = column.type === "currency" ? resolveColumnOption(column.currency, row) : column.type === "unit" ? resolveColumnOption(column.unit, row) : null;
|
|
11780
|
+
const inferred = {
|
|
11781
|
+
...locale != null && !Object.prototype.hasOwnProperty.call(props, "locale") ? { locale } : {},
|
|
11782
|
+
...decimals != null && !Object.prototype.hasOwnProperty.call(props, "precision") ? { precision: decimals } : {},
|
|
11783
|
+
...suffix != null && !Object.prototype.hasOwnProperty.call(props, "unit") ? { unit: String(suffix) } : {}
|
|
11784
|
+
};
|
|
11785
|
+
const field = new NumberField(null, { ...inferred, ...props, value: value ?? null });
|
|
11448
11786
|
host.append(field.el);
|
|
11449
11787
|
entry.component = field;
|
|
11450
11788
|
entry.control = field.getInput();
|
|
@@ -11675,9 +12013,12 @@ var Table = class extends Component {
|
|
|
11675
12013
|
_nextEditableCell(rowIndex, columnId, direction) {
|
|
11676
12014
|
const columnCount = this._columns.length;
|
|
11677
12015
|
if (rowIndex < 0 || columnCount === 0) return null;
|
|
11678
|
-
|
|
12016
|
+
const visible = this._visibleData();
|
|
12017
|
+
const startingId = this._idFor(this._data[rowIndex]);
|
|
12018
|
+
let row = visible.findIndex((candidate) => Object.is(this._idFor(candidate), startingId));
|
|
12019
|
+
if (row < 0) return null;
|
|
11679
12020
|
let column = this._columns.findIndex((candidate) => candidate.id === columnId);
|
|
11680
|
-
const limit =
|
|
12021
|
+
const limit = visible.length * columnCount + columnCount;
|
|
11681
12022
|
for (let step = 0; step < limit; step += 1) {
|
|
11682
12023
|
column += direction;
|
|
11683
12024
|
if (column >= columnCount) {
|
|
@@ -11687,11 +12028,15 @@ var Table = class extends Component {
|
|
|
11687
12028
|
row -= 1;
|
|
11688
12029
|
column = columnCount - 1;
|
|
11689
12030
|
}
|
|
11690
|
-
if (row < 0 || row >=
|
|
11691
|
-
const candidateRow =
|
|
12031
|
+
if (row < 0 || row >= visible.length) return null;
|
|
12032
|
+
const candidateRow = visible[row];
|
|
11692
12033
|
const candidateColumn = this._columns[column];
|
|
11693
12034
|
if (resolveEditable(candidateColumn, candidateRow) !== false) {
|
|
11694
|
-
return {
|
|
12035
|
+
return {
|
|
12036
|
+
id: this._idFor(candidateRow),
|
|
12037
|
+
columnId: candidateColumn.id,
|
|
12038
|
+
index: this._data.indexOf(candidateRow)
|
|
12039
|
+
};
|
|
11695
12040
|
}
|
|
11696
12041
|
}
|
|
11697
12042
|
return null;
|
|
@@ -11758,14 +12103,16 @@ var Table = class extends Component {
|
|
|
11758
12103
|
const message = this.msg(key);
|
|
11759
12104
|
return message === key ? fallback : message;
|
|
11760
12105
|
}
|
|
11761
|
-
/** @param {{row: TableRow, id: unknown, index: number}} meta @param {boolean} checked @param {boolean} shiftKey @returns {void} */
|
|
12106
|
+
/** @param {{row: TableRow, id: unknown, index: number, visibleIndex?: number}} meta @param {boolean} checked @param {boolean} shiftKey @returns {void} */
|
|
11762
12107
|
_toggleMultiSelection(meta, checked, shiftKey) {
|
|
11763
|
-
const
|
|
12108
|
+
const visible = this._visibleData();
|
|
12109
|
+
const anchorIndex = visible.findIndex((row) => Object.is(this._idFor(row), this._selectionAnchorId));
|
|
11764
12110
|
if (shiftKey && anchorIndex >= 0) {
|
|
11765
|
-
const
|
|
11766
|
-
const
|
|
12111
|
+
const currentIndex = meta.visibleIndex ?? visible.findIndex((row) => Object.is(this._idFor(row), meta.id));
|
|
12112
|
+
const start = Math.min(anchorIndex, currentIndex);
|
|
12113
|
+
const end = Math.max(anchorIndex, currentIndex);
|
|
11767
12114
|
for (let index = start; index <= end; index += 1) {
|
|
11768
|
-
const id = this._idFor(
|
|
12115
|
+
const id = this._idFor(visible[index]);
|
|
11769
12116
|
if (checked) this._selected.add(id);
|
|
11770
12117
|
else this._selected.delete(id);
|
|
11771
12118
|
}
|
|
@@ -11816,7 +12163,34 @@ var Table = class extends Component {
|
|
|
11816
12163
|
const column = this._columns.find((candidate) => candidate.id === this._sort.id);
|
|
11817
12164
|
if (!column) return;
|
|
11818
12165
|
const getValue = typeof column.sortValue === "function" ? column.sortValue : (row) => row?.[column.id];
|
|
11819
|
-
this._data = sortRows(this._data, getValue, this._sort.dir);
|
|
12166
|
+
this._data = this._hierarchy ? sortHierarchyRows(this._data, this.options.rowId, this._hierarchy.parentId, getValue, this._sort.dir) : sortRows(this._data, getValue, this._sort.dir);
|
|
12167
|
+
}
|
|
12168
|
+
/** @param {unknown} id @param {boolean} expanded @param {{silent?: boolean}} options @returns {this} */
|
|
12169
|
+
_setRowExpanded(id, expanded, options) {
|
|
12170
|
+
if (!this._hierarchy) return this;
|
|
12171
|
+
const branchIds = hierarchyBranchIds(this._data, this.options.rowId, this._hierarchy.parentId);
|
|
12172
|
+
if (!branchIds.some((candidate) => Object.is(candidate, id))) return this;
|
|
12173
|
+
if (this._expanded.has(id) === expanded) return this;
|
|
12174
|
+
if (expanded) this._expanded.add(id);
|
|
12175
|
+
else this._expanded.delete(id);
|
|
12176
|
+
this._renderBody();
|
|
12177
|
+
if (!options.silent) this._emitRowToggle(id, expanded);
|
|
12178
|
+
return this;
|
|
12179
|
+
}
|
|
12180
|
+
/** @param {unknown} id @param {boolean} expanded @returns {void} */
|
|
12181
|
+
_emitRowToggle(id, expanded) {
|
|
12182
|
+
const row = this.getRow(id);
|
|
12183
|
+
if (row) this.emit("rowtoggle", { row, id, expanded });
|
|
12184
|
+
}
|
|
12185
|
+
/** Keeps the reader's current expansion state limited to branches still present in the data. */
|
|
12186
|
+
_reconcileExpanded() {
|
|
12187
|
+
if (!this._hierarchy) {
|
|
12188
|
+
this._expanded.clear();
|
|
12189
|
+
return;
|
|
12190
|
+
}
|
|
12191
|
+
const branches = hierarchyBranchIds(this._data, this.options.rowId, this._hierarchy.parentId);
|
|
12192
|
+
const valid = new Set(branches);
|
|
12193
|
+
for (const id of this._expanded) if (!valid.has(id)) this._expanded.delete(id);
|
|
11820
12194
|
}
|
|
11821
12195
|
/** @returns {boolean} Whether selection changed. */
|
|
11822
12196
|
_pruneSelection() {
|
|
@@ -11840,6 +12214,65 @@ var Table = class extends Component {
|
|
|
11840
12214
|
this.emit("datachange", { rows: this.getData() });
|
|
11841
12215
|
}
|
|
11842
12216
|
};
|
|
12217
|
+
function formatTableCell(column, row, index = 0) {
|
|
12218
|
+
if (typeof column?.render === "function") return column.render(row, index);
|
|
12219
|
+
const value = row?.[column?.id];
|
|
12220
|
+
const type = column?.type ?? "text";
|
|
12221
|
+
if (type === "text") return value;
|
|
12222
|
+
const locale = resolveColumnOption(column.locale, row);
|
|
12223
|
+
const decimals = resolveColumnDecimals(column, row);
|
|
12224
|
+
const options = {
|
|
12225
|
+
...locale != null ? { locale: String(locale) } : {},
|
|
12226
|
+
...decimals != null ? { decimals } : {}
|
|
12227
|
+
};
|
|
12228
|
+
if (type === "number") return formatNumber(value, options);
|
|
12229
|
+
if (type === "currency") {
|
|
12230
|
+
const currency = resolveColumnOption(column.currency, row);
|
|
12231
|
+
return formatCurrency(value, currency == null ? null : String(currency), options);
|
|
12232
|
+
}
|
|
12233
|
+
if (type === "percent") return formatPercent(value, options);
|
|
12234
|
+
if (type === "unit") {
|
|
12235
|
+
const number = formatNumber(value, options);
|
|
12236
|
+
const unit = resolveColumnOption(column.unit, row);
|
|
12237
|
+
return number && unit != null && String(unit) !== "" ? `${number}\xA0${unit}` : number;
|
|
12238
|
+
}
|
|
12239
|
+
return value;
|
|
12240
|
+
}
|
|
12241
|
+
function projectHierarchyRows(rows, rowId, parentId, expanded = []) {
|
|
12242
|
+
const forest = hierarchyForest(rows, rowId, parentId);
|
|
12243
|
+
const open = expanded instanceof Set ? expanded : new Set(expanded);
|
|
12244
|
+
const result = [];
|
|
12245
|
+
const stack = forest.roots.slice().reverse().map((node) => ({ node, depth: 0 }));
|
|
12246
|
+
while (stack.length) {
|
|
12247
|
+
const { node, depth } = stack.pop();
|
|
12248
|
+
result.push({
|
|
12249
|
+
row: node.row,
|
|
12250
|
+
id: node.id,
|
|
12251
|
+
index: node.index,
|
|
12252
|
+
depth,
|
|
12253
|
+
hasChildren: node.children.length > 0,
|
|
12254
|
+
parentId: node.parent?.id ?? null
|
|
12255
|
+
});
|
|
12256
|
+
if (!open.has(node.id)) continue;
|
|
12257
|
+
for (let index = node.children.length - 1; index >= 0; index -= 1) {
|
|
12258
|
+
stack.push({ node: node.children[index], depth: depth + 1 });
|
|
12259
|
+
}
|
|
12260
|
+
}
|
|
12261
|
+
return result;
|
|
12262
|
+
}
|
|
12263
|
+
function sortHierarchyRows(rows, rowId, parentId, getValue, direction) {
|
|
12264
|
+
const forest = hierarchyForest(rows, rowId, parentId);
|
|
12265
|
+
const sorted = (nodes) => sortRows(nodes, (node) => getValue(node.row), direction);
|
|
12266
|
+
const result = [];
|
|
12267
|
+
const stack = sorted(forest.roots).reverse();
|
|
12268
|
+
while (stack.length) {
|
|
12269
|
+
const node = stack.pop();
|
|
12270
|
+
result.push(node.row);
|
|
12271
|
+
const children = sorted(node.children);
|
|
12272
|
+
for (let index = children.length - 1; index >= 0; index -= 1) stack.push(children[index]);
|
|
12273
|
+
}
|
|
12274
|
+
return result;
|
|
12275
|
+
}
|
|
11843
12276
|
function resolveEditable(column, row) {
|
|
11844
12277
|
if (!column || typeof column !== "object") return false;
|
|
11845
12278
|
if (typeof column.editor === "function") {
|
|
@@ -11847,7 +12280,7 @@ function resolveEditable(column, row) {
|
|
|
11847
12280
|
return "custom";
|
|
11848
12281
|
}
|
|
11849
12282
|
const declared = typeof column.editable === "function" ? column.editable(row) : column.editable;
|
|
11850
|
-
if (declared === true) return "text";
|
|
12283
|
+
if (declared === true) return isNumericColumn(column) ? "number" : "text";
|
|
11851
12284
|
if (typeof declared === "string" && EDITOR_TYPES.has(declared)) return (
|
|
11852
12285
|
/** @type {TableEditorType} */
|
|
11853
12286
|
declared
|
|
@@ -11896,6 +12329,71 @@ function firstValidationError(values, columns, row, fallbackMessage = "Invalid v
|
|
|
11896
12329
|
}
|
|
11897
12330
|
return null;
|
|
11898
12331
|
}
|
|
12332
|
+
function resolveColumnOption(option, row) {
|
|
12333
|
+
return typeof option === "function" ? option(row) : option;
|
|
12334
|
+
}
|
|
12335
|
+
function resolveColumnDecimals(column, row) {
|
|
12336
|
+
const value = resolveColumnOption(column?.decimals, row);
|
|
12337
|
+
if (value == null) return null;
|
|
12338
|
+
const number = Number(value);
|
|
12339
|
+
return Number.isFinite(number) ? Math.max(0, Math.trunc(number)) : null;
|
|
12340
|
+
}
|
|
12341
|
+
function isNumericColumn(column) {
|
|
12342
|
+
return ["number", "currency", "percent", "unit"].includes(column?.type);
|
|
12343
|
+
}
|
|
12344
|
+
function hierarchyForest(rows, rowId, parentId) {
|
|
12345
|
+
const nodes = (Array.isArray(rows) ? rows : []).map((row, index) => ({
|
|
12346
|
+
row,
|
|
12347
|
+
id: readRowValue(rowId, row),
|
|
12348
|
+
index,
|
|
12349
|
+
parent: null,
|
|
12350
|
+
children: []
|
|
12351
|
+
}));
|
|
12352
|
+
const byId = /* @__PURE__ */ new Map();
|
|
12353
|
+
for (const node of nodes) if (!byId.has(node.id)) byId.set(node.id, node);
|
|
12354
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
12355
|
+
for (const node of nodes) {
|
|
12356
|
+
const parent = byId.get(readRowValue(parentId, node.row)) ?? null;
|
|
12357
|
+
parentOf.set(node, parent === node ? null : parent);
|
|
12358
|
+
}
|
|
12359
|
+
for (const node of nodes) {
|
|
12360
|
+
const seen = /* @__PURE__ */ new Set([node]);
|
|
12361
|
+
let cursor = parentOf.get(node) ?? null;
|
|
12362
|
+
while (cursor) {
|
|
12363
|
+
if (seen.has(cursor)) {
|
|
12364
|
+
parentOf.set(cursor, null);
|
|
12365
|
+
break;
|
|
12366
|
+
}
|
|
12367
|
+
seen.add(cursor);
|
|
12368
|
+
cursor = parentOf.get(cursor) ?? null;
|
|
12369
|
+
}
|
|
12370
|
+
}
|
|
12371
|
+
const roots = [];
|
|
12372
|
+
for (const node of nodes) {
|
|
12373
|
+
node.parent = parentOf.get(node) ?? null;
|
|
12374
|
+
if (node.parent) node.parent.children.push(node);
|
|
12375
|
+
else roots.push(node);
|
|
12376
|
+
}
|
|
12377
|
+
return { roots, nodes };
|
|
12378
|
+
}
|
|
12379
|
+
function hierarchyBranchIds(rows, rowId, parentId) {
|
|
12380
|
+
return hierarchyForest(rows, rowId, parentId).nodes.filter((node) => node.children.length > 0).map((node) => node.id);
|
|
12381
|
+
}
|
|
12382
|
+
function readRowValue(accessor, row) {
|
|
12383
|
+
return typeof accessor === "function" ? accessor(row) : row?.[accessor];
|
|
12384
|
+
}
|
|
12385
|
+
function normalizeHierarchy(option, columns) {
|
|
12386
|
+
if (!option || typeof option !== "object") return null;
|
|
12387
|
+
const parentId = option.parentId;
|
|
12388
|
+
if (typeof parentId !== "string" && typeof parentId !== "function") return null;
|
|
12389
|
+
const requested = typeof option.column === "string" ? option.column : null;
|
|
12390
|
+
const column = columns.some((candidate) => candidate.id === requested) ? requested : columns[0]?.id;
|
|
12391
|
+
if (!column) return null;
|
|
12392
|
+
return { ...option, parentId, column };
|
|
12393
|
+
}
|
|
12394
|
+
function initialExpanded(option) {
|
|
12395
|
+
return new Set(Array.isArray(option) ? option : []);
|
|
12396
|
+
}
|
|
11899
12397
|
function normalizeEditMode(mode) {
|
|
11900
12398
|
if (mode === "cell" || mode === "row") return mode;
|
|
11901
12399
|
return mode === true ? "cell" : false;
|
|
@@ -12362,6 +12860,29 @@ var MenuButton = class extends Component {
|
|
|
12362
12860
|
isOpen() {
|
|
12363
12861
|
return this.#dropdown.isOpen();
|
|
12364
12862
|
}
|
|
12863
|
+
/** Returns the trigger button. @returns {HTMLElement} */
|
|
12864
|
+
getTrigger() {
|
|
12865
|
+
return (
|
|
12866
|
+
/** @type {HTMLElement} */
|
|
12867
|
+
this.el
|
|
12868
|
+
);
|
|
12869
|
+
}
|
|
12870
|
+
/** Returns the owned menu panel. @returns {HTMLElement} */
|
|
12871
|
+
getPanel() {
|
|
12872
|
+
return this.#panel;
|
|
12873
|
+
}
|
|
12874
|
+
/** Opens the menu and focuses its first enabled item. @returns {this} */
|
|
12875
|
+
focusFirst() {
|
|
12876
|
+
this.open();
|
|
12877
|
+
this.#roving.focusFirst();
|
|
12878
|
+
return this;
|
|
12879
|
+
}
|
|
12880
|
+
/** Opens the menu and focuses its last enabled item. @returns {this} */
|
|
12881
|
+
focusLast() {
|
|
12882
|
+
this.open();
|
|
12883
|
+
this.#roving.focusLast();
|
|
12884
|
+
return this;
|
|
12885
|
+
}
|
|
12365
12886
|
/**
|
|
12366
12887
|
* Sets the visible trigger label.
|
|
12367
12888
|
* @param {string} label Trigger label.
|
|
@@ -12421,7 +12942,8 @@ var MenuButton = class extends Component {
|
|
|
12421
12942
|
const index = Number(element.getAttribute("data-menu-item"));
|
|
12422
12943
|
const item = this.#items[index];
|
|
12423
12944
|
if (!item || item === "-" || item.disabled) return;
|
|
12424
|
-
this.emit("select", { value: item.value, item });
|
|
12945
|
+
const selected = this.emit("select", { value: item.value, item });
|
|
12946
|
+
if (selected.defaultPrevented) return;
|
|
12425
12947
|
try {
|
|
12426
12948
|
item.onselect?.(item.value, item, this);
|
|
12427
12949
|
} finally {
|
|
@@ -13671,177 +14193,6 @@ function restore9(element, state) {
|
|
|
13671
14193
|
element.replaceChildren(...state.children);
|
|
13672
14194
|
}
|
|
13673
14195
|
|
|
13674
|
-
// src/components/permission/permission.js
|
|
13675
|
-
var Permission = class extends Component {
|
|
13676
|
-
static cssName = "permission";
|
|
13677
|
-
/** @type {PermissionOptions} */
|
|
13678
|
-
static defaults = {
|
|
13679
|
-
value: true,
|
|
13680
|
-
groups: [],
|
|
13681
|
-
groupsValueKey: "ID",
|
|
13682
|
-
groupsLabelKey: "name"
|
|
13683
|
-
};
|
|
13684
|
-
/** @returns {HTMLElement} */
|
|
13685
|
-
render() {
|
|
13686
|
-
this._mode = "public";
|
|
13687
|
-
this._groupValue = null;
|
|
13688
|
-
this._groupSelect = null;
|
|
13689
|
-
this._createdRoot = false;
|
|
13690
|
-
this._originalChildren = [];
|
|
13691
|
-
this._root = null;
|
|
13692
|
-
this._originalState = null;
|
|
13693
|
-
this._createdRoot = this.el === null;
|
|
13694
|
-
const root = (
|
|
13695
|
-
/** @type {HTMLElement} */
|
|
13696
|
-
this.el ?? h("div")
|
|
13697
|
-
);
|
|
13698
|
-
this.el = root;
|
|
13699
|
-
this._root = root;
|
|
13700
|
-
if (!this._createdRoot) {
|
|
13701
|
-
this._originalChildren = Array.from(root.childNodes);
|
|
13702
|
-
this._originalState = root.getAttribute("data-state");
|
|
13703
|
-
}
|
|
13704
|
-
const name = uid("zx-permission");
|
|
13705
|
-
const choices = h("div", {
|
|
13706
|
-
class: "zx-permission__choices",
|
|
13707
|
-
role: "radiogroup",
|
|
13708
|
-
ariaLabel: this._message("permission.label", "Permission")
|
|
13709
|
-
});
|
|
13710
|
-
const privateChoice = this._choice(name, "private", this._message("permission.private", "Private"));
|
|
13711
|
-
const publicChoice = this._choice(name, "public", this._message("permission.public", "Public"));
|
|
13712
|
-
const groupChoice = this._choice(name, "group", this._message("permission.group", "Group"));
|
|
13713
|
-
const groupHost = h("div", { ref: "groupHost", class: "zx-permission__groups" });
|
|
13714
|
-
choices.append(privateChoice.label, publicChoice.label, groupChoice.label, groupHost);
|
|
13715
|
-
root.replaceChildren(choices);
|
|
13716
|
-
this.refs.private = privateChoice.input;
|
|
13717
|
-
this.refs.public = publicChoice.input;
|
|
13718
|
-
this.refs.group = groupChoice.input;
|
|
13719
|
-
this._groupSelect = new Select(groupHost, {
|
|
13720
|
-
items: Array.isArray(this.options.groups) ? this.options.groups : [],
|
|
13721
|
-
valueKey: this.options.groupsValueKey,
|
|
13722
|
-
labelKey: this.options.groupsLabelKey,
|
|
13723
|
-
placeholder: this._message("permission.group", "Group")
|
|
13724
|
-
});
|
|
13725
|
-
this._groupSelect.refs.input.setAttribute(
|
|
13726
|
-
"aria-label",
|
|
13727
|
-
this._message("permission.group", "Group")
|
|
13728
|
-
);
|
|
13729
|
-
for (const input of [privateChoice.input, publicChoice.input, groupChoice.input]) {
|
|
13730
|
-
this.listen(input, "change", () => {
|
|
13731
|
-
if (!input.checked) return;
|
|
13732
|
-
if (input.value === "group") this._selectGroupMode();
|
|
13733
|
-
else this.set(input.value);
|
|
13734
|
-
});
|
|
13735
|
-
}
|
|
13736
|
-
this.listen(groupHost, "zx-change", (event) => {
|
|
13737
|
-
event.stopPropagation();
|
|
13738
|
-
if (this._mode !== "group") return;
|
|
13739
|
-
const previous = this.get();
|
|
13740
|
-
this._groupValue = /** @type {CustomEvent} */
|
|
13741
|
-
event.detail.value;
|
|
13742
|
-
const value = this.get();
|
|
13743
|
-
if (!Object.is(previous, value)) this.emit("change", { value });
|
|
13744
|
-
});
|
|
13745
|
-
this.set(this.options.value, { silent: true });
|
|
13746
|
-
return root;
|
|
13747
|
-
}
|
|
13748
|
-
/** Returns the normalized permission value. @returns {'private'|'public'|unknown} */
|
|
13749
|
-
get() {
|
|
13750
|
-
if (this._mode === "private") return "private";
|
|
13751
|
-
if (this._mode === "public") return "public";
|
|
13752
|
-
return this._groupValue;
|
|
13753
|
-
}
|
|
13754
|
-
/**
|
|
13755
|
-
* Sets a public, private, or group permission.
|
|
13756
|
-
* @param {boolean|string|number|symbol|bigint|null} value Permission value.
|
|
13757
|
-
* @param {{silent?: boolean}} [options={}] Update behavior.
|
|
13758
|
-
* @returns {this}
|
|
13759
|
-
* @fires Permission#change
|
|
13760
|
-
*/
|
|
13761
|
-
set(value, { silent = false } = {}) {
|
|
13762
|
-
const previous = this.get();
|
|
13763
|
-
if (value === true || value === "public") {
|
|
13764
|
-
this._mode = "public";
|
|
13765
|
-
} else if (value === false || value === "private") {
|
|
13766
|
-
this._mode = "private";
|
|
13767
|
-
} else {
|
|
13768
|
-
this._mode = "group";
|
|
13769
|
-
this._groupValue = value;
|
|
13770
|
-
this._groupSelect?.set(value, { silent: true });
|
|
13771
|
-
}
|
|
13772
|
-
this._sync();
|
|
13773
|
-
const next = this.get();
|
|
13774
|
-
if (!silent && !Object.is(previous, next)) this.emit("change", { value: next });
|
|
13775
|
-
return this;
|
|
13776
|
-
}
|
|
13777
|
-
/** Destroys the embedded Select and restores an enhanced target. @returns {void} */
|
|
13778
|
-
destroy() {
|
|
13779
|
-
this._groupSelect?.destroy();
|
|
13780
|
-
this._groupSelect = null;
|
|
13781
|
-
if (!this._createdRoot && this.el) {
|
|
13782
|
-
this.el.replaceChildren(...this._originalChildren);
|
|
13783
|
-
if (this._originalState === null) this.el.removeAttribute("data-state");
|
|
13784
|
-
else this.el.setAttribute("data-state", this._originalState);
|
|
13785
|
-
}
|
|
13786
|
-
super.destroy();
|
|
13787
|
-
}
|
|
13788
|
-
/** @returns {void} */
|
|
13789
|
-
_selectGroupMode() {
|
|
13790
|
-
const previous = this.get();
|
|
13791
|
-
this._mode = "group";
|
|
13792
|
-
if (this._groupValue == null) {
|
|
13793
|
-
const first = Array.isArray(this.options.groups) ? this.options.groups[0] : null;
|
|
13794
|
-
this._groupValue = first == null ? null : read(first, this.options.groupsValueKey);
|
|
13795
|
-
}
|
|
13796
|
-
this._groupSelect?.set(this._groupValue, { silent: true });
|
|
13797
|
-
this._sync();
|
|
13798
|
-
const next = this.get();
|
|
13799
|
-
if (!Object.is(previous, next)) this.emit("change", { value: next });
|
|
13800
|
-
}
|
|
13801
|
-
/** @returns {void} */
|
|
13802
|
-
_sync() {
|
|
13803
|
-
this.refs.private.checked = this._mode === "private";
|
|
13804
|
-
this.refs.public.checked = this._mode === "public";
|
|
13805
|
-
this.refs.group.checked = this._mode === "group";
|
|
13806
|
-
if (this._mode === "group") this._groupSelect?.enable();
|
|
13807
|
-
else this._groupSelect?.disable();
|
|
13808
|
-
this._root?.setAttribute("data-state", this._mode);
|
|
13809
|
-
}
|
|
13810
|
-
/**
|
|
13811
|
-
* @param {string} name
|
|
13812
|
-
* @param {'private'|'public'|'group'} value
|
|
13813
|
-
* @param {string} text
|
|
13814
|
-
* @returns {{label: HTMLLabelElement, input: HTMLInputElement}}
|
|
13815
|
-
*/
|
|
13816
|
-
_choice(name, value, text3) {
|
|
13817
|
-
const input = (
|
|
13818
|
-
/** @type {HTMLInputElement} */
|
|
13819
|
-
h("input", {
|
|
13820
|
-
type: "radio",
|
|
13821
|
-
name,
|
|
13822
|
-
value
|
|
13823
|
-
})
|
|
13824
|
-
);
|
|
13825
|
-
const label = (
|
|
13826
|
-
/** @type {HTMLLabelElement} */
|
|
13827
|
-
h("label", {
|
|
13828
|
-
class: "zx-permission__choice"
|
|
13829
|
-
}, input, h("span", {}, text3))
|
|
13830
|
-
);
|
|
13831
|
-
return { label, input };
|
|
13832
|
-
}
|
|
13833
|
-
/** @param {string} key @param {string} fallback @returns {string} */
|
|
13834
|
-
_message(key, fallback) {
|
|
13835
|
-
const message = this.msg(key);
|
|
13836
|
-
return message === key ? fallback : message;
|
|
13837
|
-
}
|
|
13838
|
-
};
|
|
13839
|
-
function read(item, reader) {
|
|
13840
|
-
if (typeof reader === "function") return reader(item);
|
|
13841
|
-
if (item === null || typeof item !== "object") return item;
|
|
13842
|
-
return item[reader];
|
|
13843
|
-
}
|
|
13844
|
-
|
|
13845
14196
|
// src/components/data-filter/filter-core.js
|
|
13846
14197
|
function normalizeText(value) {
|
|
13847
14198
|
return String(value ?? "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLocaleLowerCase();
|
|
@@ -15425,9 +15776,9 @@ function translateChecklistOptions(options = {}) {
|
|
|
15425
15776
|
delete translated.onClick;
|
|
15426
15777
|
return translated;
|
|
15427
15778
|
}
|
|
15428
|
-
function translateDateboxFormat(
|
|
15429
|
-
if (typeof
|
|
15430
|
-
const parts = Array.isArray(
|
|
15779
|
+
function translateDateboxFormat(format2) {
|
|
15780
|
+
if (typeof format2 === "string") return format2.replaceAll(" ", " ");
|
|
15781
|
+
const parts = Array.isArray(format2) ? format2 : ["d", ".", "M", ".", "y"];
|
|
15431
15782
|
const tokens = {
|
|
15432
15783
|
d: "%d",
|
|
15433
15784
|
m: "%m",
|
|
@@ -15615,26 +15966,39 @@ var Checklist2 = class extends ChecklistBase {
|
|
|
15615
15966
|
var BootstrapChecklist = class extends ChecklistBase {
|
|
15616
15967
|
static legacyName = "gx.bootstrap.Checklist";
|
|
15617
15968
|
};
|
|
15618
|
-
|
|
15969
|
+
function toLegacyPermission(value) {
|
|
15970
|
+
if (value === false) return "private";
|
|
15971
|
+
if (value === true) return "public";
|
|
15972
|
+
return value;
|
|
15973
|
+
}
|
|
15974
|
+
function fromLegacyPermission(value) {
|
|
15975
|
+
if (value === false || value === "private") return false;
|
|
15976
|
+
if (value === true || value === "public") return true;
|
|
15977
|
+
return value;
|
|
15978
|
+
}
|
|
15979
|
+
var Permission = class extends GxWrapper {
|
|
15619
15980
|
static legacyName = "gx.zeyos.Permission";
|
|
15620
15981
|
/** @param {Element|string|null} display @param {Record<string, any>} [options={}] */
|
|
15621
15982
|
constructor(display, options = {}) {
|
|
15622
15983
|
super(options, { value: true, groups: [] });
|
|
15623
|
-
const component =
|
|
15624
|
-
value: options.value ?? true,
|
|
15984
|
+
const component = Select.permission(display, {
|
|
15985
|
+
value: fromLegacyPermission(options.value ?? true),
|
|
15625
15986
|
groups: options.groups ?? options.data ?? [],
|
|
15626
|
-
|
|
15627
|
-
|
|
15987
|
+
valueKey: options.groupsValueKey ?? options.elementIndex ?? "ID",
|
|
15988
|
+
labelKey: options.groupsLabelKey ?? options.elementLabel ?? "name"
|
|
15989
|
+
});
|
|
15990
|
+
this._attach(component, {
|
|
15991
|
+
events: { change: { type: "change", args: (detail) => [toLegacyPermission(detail.value)] } },
|
|
15992
|
+
setters: { value: "set" }
|
|
15628
15993
|
});
|
|
15629
|
-
this._attach(component, { events: { change: { type: "change", args: (detail) => [detail.value] } }, setters: { value: "set" } });
|
|
15630
15994
|
}
|
|
15631
15995
|
/** @returns {unknown} */
|
|
15632
15996
|
get() {
|
|
15633
|
-
return this._zx.
|
|
15997
|
+
return toLegacyPermission(this._zx.value);
|
|
15634
15998
|
}
|
|
15635
15999
|
/** @param {unknown} value @param {boolean} [silent=false] @returns {this} */
|
|
15636
16000
|
set(value, silent = false) {
|
|
15637
|
-
this._zx.set(value, { silent });
|
|
16001
|
+
this._zx.set(fromLegacyPermission(value), { silent });
|
|
15638
16002
|
return this;
|
|
15639
16003
|
}
|
|
15640
16004
|
};
|
|
@@ -15867,11 +16231,11 @@ var Datebox2 = class extends GxWrapper {
|
|
|
15867
16231
|
constructor(display, options = {}) {
|
|
15868
16232
|
super(options, { timestamp: 0, unit: "milliseconds", format: ["d", ".", "M", ".", "y", " ", "h", ":", "i"] });
|
|
15869
16233
|
const initial = options.timestamp == null || Number(options.timestamp) === 0 ? /* @__PURE__ */ new Date() : legacyDate(options.timestamp, options.unit ?? "milliseconds");
|
|
15870
|
-
const
|
|
16234
|
+
const format2 = translateDateboxFormat(options.format);
|
|
15871
16235
|
const component = new Datebox(display, {
|
|
15872
16236
|
value: initial,
|
|
15873
|
-
format,
|
|
15874
|
-
time: /%[HMS]/.test(
|
|
16237
|
+
format: format2,
|
|
16238
|
+
time: /%[HMS]/.test(format2),
|
|
15875
16239
|
disabled: Boolean(options.disabled)
|
|
15876
16240
|
});
|
|
15877
16241
|
this._attach(component, {
|
|
@@ -15937,13 +16301,13 @@ var PickerBase = class extends GxWrapper {
|
|
|
15937
16301
|
return this;
|
|
15938
16302
|
}
|
|
15939
16303
|
/** @param {string} [format] @returns {Date|number|string|null} */
|
|
15940
|
-
get(
|
|
16304
|
+
get(format2 = this.options.return_format) {
|
|
15941
16305
|
const date = this._readDate();
|
|
15942
16306
|
if (!date) return null;
|
|
15943
|
-
if (
|
|
15944
|
-
if (
|
|
15945
|
-
if (
|
|
15946
|
-
return formatDate(date, String(
|
|
16307
|
+
if (format2 == null) return date;
|
|
16308
|
+
if (format2 === "%s" || format2 === "seconds") return Math.floor(date.getTime() / 1e3);
|
|
16309
|
+
if (format2 === "date") return date;
|
|
16310
|
+
return formatDate(date, String(format2));
|
|
15947
16311
|
}
|
|
15948
16312
|
/** @returns {number|null} */
|
|
15949
16313
|
getSeconds() {
|
|
@@ -15956,8 +16320,8 @@ var PickerBase = class extends GxWrapper {
|
|
|
15956
16320
|
return this;
|
|
15957
16321
|
}
|
|
15958
16322
|
/** @param {string} format @param {boolean} [enableTimePicker] @returns {this} */
|
|
15959
|
-
setFormat(
|
|
15960
|
-
this.options.format =
|
|
16323
|
+
setFormat(format2, enableTimePicker) {
|
|
16324
|
+
this.options.format = format2;
|
|
15961
16325
|
this.options.timePicker = enableTimePicker;
|
|
15962
16326
|
return this;
|
|
15963
16327
|
}
|
|
@@ -17422,7 +17786,7 @@ var gx = {
|
|
|
17422
17786
|
SelectDyn,
|
|
17423
17787
|
SelectPrio,
|
|
17424
17788
|
Checklist: Checklist2,
|
|
17425
|
-
Permission
|
|
17789
|
+
Permission,
|
|
17426
17790
|
Table: Table2,
|
|
17427
17791
|
Tabbox: Tabbox2,
|
|
17428
17792
|
Panel: Panel2,
|