@iris-ui-kit/vue 0.2.28 → 0.2.29
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/dist/admin.cjs +3 -3
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.js +3 -3
- package/dist/behaviors.d.cts +2 -2
- package/dist/behaviors.d.ts +2 -2
- package/dist/{chunk-IAG64CHL.js → chunk-BVKOOTXG.js} +3 -3
- package/dist/chunk-BVKOOTXG.js.map +1 -0
- package/dist/{chunk-AMNHDYFY.js → chunk-EZUDM4TM.js} +5 -5
- package/dist/chunk-EZUDM4TM.js.map +1 -0
- package/dist/{chunk-UPC4GN3F.js → chunk-KAOPZNZF.js} +3 -3
- package/dist/chunk-KAOPZNZF.js.map +1 -0
- package/dist/{chunk-MO7AAXA6.js → chunk-KSJZLFAT.js} +6 -6
- package/dist/chunk-KSJZLFAT.js.map +1 -0
- package/dist/{chunk-XCNCIG2I.js → chunk-LQ2YAOYR.js} +11 -10
- package/dist/chunk-LQ2YAOYR.js.map +1 -0
- package/dist/{chunk-ZTPIXL7Q.js → chunk-OH4YSGFK.js} +3 -3
- package/dist/chunk-OH4YSGFK.js.map +1 -0
- package/dist/{chunk-TCAXRWT6.js → chunk-W3JMJVEK.js} +3 -3
- package/dist/chunk-W3JMJVEK.js.map +1 -0
- package/dist/{chunk-LWABTQCB.js → chunk-X5UOY4IV.js} +13 -9
- package/dist/chunk-X5UOY4IV.js.map +1 -0
- package/dist/{chunk-3547J6IN.js → chunk-X7Y35UUL.js} +3 -3
- package/dist/{chunk-3547J6IN.js.map → chunk-X7Y35UUL.js.map} +1 -1
- package/dist/error-boundary.cjs +1 -1
- package/dist/error-boundary.cjs.map +1 -1
- package/dist/error-boundary.js +2 -2
- package/dist/form.cjs +1 -1
- package/dist/form.cjs.map +1 -1
- package/dist/form.js +1 -1
- package/dist/i18n.cjs +1 -1
- package/dist/i18n.cjs.map +1 -1
- package/dist/i18n.js +1 -1
- package/dist/index.cjs +3456 -861
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +723 -283
- package/dist/index.d.ts +723 -283
- package/dist/index.js +3432 -846
- package/dist/index.js.map +1 -1
- package/dist/modal-utils.cjs +9 -8
- package/dist/modal-utils.cjs.map +1 -1
- package/dist/modal-utils.js +1 -1
- package/dist/provider.cjs +4 -4
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.js +4 -4
- package/dist/skeletons.cjs +11 -7
- package/dist/skeletons.cjs.map +1 -1
- package/dist/skeletons.d.cts +1 -1
- package/dist/skeletons.d.ts +1 -1
- package/dist/skeletons.js +2 -2
- package/dist/skins.cjs +1 -1
- package/dist/skins.cjs.map +1 -1
- package/dist/skins.js +1 -1
- package/dist/theme.cjs +1 -1
- package/dist/theme.cjs.map +1 -1
- package/dist/theme.js +1 -1
- package/package.json +11 -11
- package/dist/chunk-AMNHDYFY.js.map +0 -1
- package/dist/chunk-IAG64CHL.js.map +0 -1
- package/dist/chunk-LWABTQCB.js.map +0 -1
- package/dist/chunk-MO7AAXA6.js.map +0 -1
- package/dist/chunk-TCAXRWT6.js.map +0 -1
- package/dist/chunk-UPC4GN3F.js.map +0 -1
- package/dist/chunk-XCNCIG2I.js.map +0 -1
- package/dist/chunk-ZTPIXL7Q.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -55,7 +55,7 @@ function useDisposableScope() {
|
|
|
55
55
|
});
|
|
56
56
|
return scope;
|
|
57
57
|
}
|
|
58
|
-
var IrisThemeKey =
|
|
58
|
+
var IrisThemeKey = Symbol("IrisTheme");
|
|
59
59
|
var ThemeProvider = vue.defineComponent({
|
|
60
60
|
name: "IrisThemeProvider",
|
|
61
61
|
props: {
|
|
@@ -164,7 +164,7 @@ function useColorScheme() {
|
|
|
164
164
|
vue.onBeforeUnmount(stop);
|
|
165
165
|
return scheme;
|
|
166
166
|
}
|
|
167
|
-
var IrisSkinKey =
|
|
167
|
+
var IrisSkinKey = Symbol("IrisSkin");
|
|
168
168
|
var SkinProvider = vue.defineComponent({
|
|
169
169
|
name: "IrisSkinProvider",
|
|
170
170
|
props: {
|
|
@@ -243,7 +243,7 @@ function useMachine(machine, options = {}) {
|
|
|
243
243
|
);
|
|
244
244
|
return { state, send: machine.send };
|
|
245
245
|
}
|
|
246
|
-
var FormInjectionKey =
|
|
246
|
+
var FormInjectionKey = Symbol("IrisForm");
|
|
247
247
|
function useFormContext() {
|
|
248
248
|
const form = vue.inject(FormInjectionKey, null);
|
|
249
249
|
if (!form) {
|
|
@@ -367,7 +367,7 @@ function useFieldArray(name) {
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
// src/i18n/context.ts
|
|
370
|
-
var I18nInjectionKey =
|
|
370
|
+
var I18nInjectionKey = Symbol("IrisI18n");
|
|
371
371
|
|
|
372
372
|
// src/i18n/I18nProvider.ts
|
|
373
373
|
var IrisI18nProvider = vue.defineComponent({
|
|
@@ -2013,7 +2013,7 @@ function useTabsNav(nav) {
|
|
|
2013
2013
|
}
|
|
2014
2014
|
|
|
2015
2015
|
// src/primitives/dropdown/context.ts
|
|
2016
|
-
var DropdownContextKey =
|
|
2016
|
+
var DropdownContextKey = Symbol("IrisDropdown");
|
|
2017
2017
|
|
|
2018
2018
|
// src/primitives/dropdown/Dropdown.ts
|
|
2019
2019
|
var IrisDropdown = vue.defineComponent({
|
|
@@ -3430,7 +3430,7 @@ function useUndoStack(options) {
|
|
|
3430
3430
|
}
|
|
3431
3431
|
|
|
3432
3432
|
// src/provider/context.ts
|
|
3433
|
-
var PluginStoreContextKey =
|
|
3433
|
+
var PluginStoreContextKey = Symbol("IrisPluginStore");
|
|
3434
3434
|
|
|
3435
3435
|
// src/provider/IrisProvider.ts
|
|
3436
3436
|
var DEFAULT_LOCALE = "en-US";
|
|
@@ -3691,15 +3691,18 @@ function installButtonStyles() {
|
|
|
3691
3691
|
var SIZE_STYLES = {
|
|
3692
3692
|
sm: {
|
|
3693
3693
|
padding: "var(--iris-padding-sm) var(--iris-padding-md)",
|
|
3694
|
-
fontSize: "var(--iris-font-size-xs, 12px)"
|
|
3694
|
+
fontSize: "var(--iris-font-size-xs, 12px)",
|
|
3695
|
+
minHeight: "var(--iris-control-height-sm, 28px)"
|
|
3695
3696
|
},
|
|
3696
3697
|
md: {
|
|
3697
3698
|
padding: "var(--iris-padding-sm) var(--iris-padding-lg)",
|
|
3698
|
-
fontSize: "var(--iris-font-size-md, 14px)"
|
|
3699
|
+
fontSize: "var(--iris-font-size-md, 14px)",
|
|
3700
|
+
minHeight: "var(--iris-control-height-md, 34px)"
|
|
3699
3701
|
},
|
|
3700
3702
|
lg: {
|
|
3701
3703
|
padding: "var(--iris-padding-md) var(--iris-padding-lg)",
|
|
3702
|
-
fontSize: "var(--iris-font-size-lg, 16px)"
|
|
3704
|
+
fontSize: "var(--iris-font-size-lg, 16px)",
|
|
3705
|
+
minHeight: "var(--iris-control-height-lg, 40px)"
|
|
3703
3706
|
}
|
|
3704
3707
|
};
|
|
3705
3708
|
var VARIANT_STYLES = {
|
|
@@ -3734,6 +3737,7 @@ function buildInlineStyle(variant, size) {
|
|
|
3734
3737
|
const base = { ...SIZE_STYLES[size], ...VARIANT_STYLES[variant] };
|
|
3735
3738
|
if (variant === "link") {
|
|
3736
3739
|
base.padding = "0";
|
|
3740
|
+
delete base.minHeight;
|
|
3737
3741
|
}
|
|
3738
3742
|
return base;
|
|
3739
3743
|
}
|
|
@@ -3835,7 +3839,7 @@ var IrisButton = vue.defineComponent({
|
|
|
3835
3839
|
});
|
|
3836
3840
|
|
|
3837
3841
|
// src/primitives/popover/context.ts
|
|
3838
|
-
var PopoverContextKey =
|
|
3842
|
+
var PopoverContextKey = Symbol("IrisPopover");
|
|
3839
3843
|
|
|
3840
3844
|
// src/primitives/popover/Popover.ts
|
|
3841
3845
|
var IrisPopover = vue.defineComponent({
|
|
@@ -3956,42 +3960,18 @@ var ANIM_DIALOG = "var(--iris-anim-dialog)";
|
|
|
3956
3960
|
var ANIM_POPOVER = "var(--iris-anim-popover)";
|
|
3957
3961
|
var ANIM_TOAST = "var(--iris-anim-toast)";
|
|
3958
3962
|
var ANIM_TOOLTIP = "var(--iris-anim-tooltip)";
|
|
3959
|
-
|
|
3960
|
-
if (installed4 || typeof document === "undefined") return;
|
|
3961
|
-
installed4 = true;
|
|
3962
|
-
if (document.getElementById(STYLE_ID2)) return;
|
|
3963
|
-
const style = document.createElement("style");
|
|
3964
|
-
style.id = STYLE_ID2;
|
|
3965
|
-
style.textContent = `
|
|
3963
|
+
var ANIMATION_CSS = `
|
|
3966
3964
|
:root {
|
|
3967
3965
|
--iris-anim-dialog: iris-dialog-in 150ms ease-out;
|
|
3968
3966
|
--iris-anim-popover: iris-popover-in 150ms ease-out;
|
|
3969
3967
|
--iris-anim-toast: iris-toast-in 200ms ease-out;
|
|
3970
3968
|
--iris-anim-tooltip: iris-tooltip-in 120ms ease-out;
|
|
3971
3969
|
}
|
|
3972
|
-
/*
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
* Fade-only keeps the entrance motion without touching positioning.
|
|
3978
|
-
*/
|
|
3979
|
-
@keyframes iris-dialog-in {
|
|
3980
|
-
from { opacity: 0; }
|
|
3981
|
-
to { opacity: 1; }
|
|
3982
|
-
}
|
|
3983
|
-
@keyframes iris-popover-in {
|
|
3984
|
-
from { opacity: 0; }
|
|
3985
|
-
to { opacity: 1; }
|
|
3986
|
-
}
|
|
3987
|
-
@keyframes iris-toast-in {
|
|
3988
|
-
from { opacity: 0; }
|
|
3989
|
-
to { opacity: 1; }
|
|
3990
|
-
}
|
|
3991
|
-
@keyframes iris-tooltip-in {
|
|
3992
|
-
from { opacity: 0; }
|
|
3993
|
-
to { opacity: 1; }
|
|
3994
|
-
}
|
|
3970
|
+
/* Fade-only keyframes preserve Floating UI's inline translate3d position. */
|
|
3971
|
+
@keyframes iris-dialog-in { from { opacity: 0; } to { opacity: 1; } }
|
|
3972
|
+
@keyframes iris-popover-in { from { opacity: 0; } to { opacity: 1; } }
|
|
3973
|
+
@keyframes iris-toast-in { from { opacity: 0; } to { opacity: 1; } }
|
|
3974
|
+
@keyframes iris-tooltip-in { from { opacity: 0; } to { opacity: 1; } }
|
|
3995
3975
|
@media (prefers-reduced-motion: reduce) {
|
|
3996
3976
|
:root {
|
|
3997
3977
|
--iris-anim-dialog: none;
|
|
@@ -4000,7 +3980,6 @@ function installFloatingAnimations() {
|
|
|
4000
3980
|
--iris-anim-tooltip: none;
|
|
4001
3981
|
}
|
|
4002
3982
|
}
|
|
4003
|
-
/* P4: global focus-visible ring for interactive controls */
|
|
4004
3983
|
[data-iris-tabs-trigger]:focus-visible,
|
|
4005
3984
|
[data-iris-switch]:focus-visible,
|
|
4006
3985
|
[data-iris-checkbox]:focus-visible,
|
|
@@ -4012,6 +3991,13 @@ function installFloatingAnimations() {
|
|
|
4012
3991
|
outline-offset: 2px;
|
|
4013
3992
|
}
|
|
4014
3993
|
`;
|
|
3994
|
+
function installFloatingAnimations() {
|
|
3995
|
+
if (installed4 || typeof document === "undefined") return;
|
|
3996
|
+
installed4 = true;
|
|
3997
|
+
if (document.getElementById(STYLE_ID2)) return;
|
|
3998
|
+
const style = document.createElement("style");
|
|
3999
|
+
style.id = STYLE_ID2;
|
|
4000
|
+
style.textContent = ANIMATION_CSS;
|
|
4015
4001
|
document.head.appendChild(style);
|
|
4016
4002
|
}
|
|
4017
4003
|
|
|
@@ -4184,12 +4170,12 @@ var IrisTooltip = vue.defineComponent({
|
|
|
4184
4170
|
const triggerListeners = {
|
|
4185
4171
|
onPointerenter: handleEnter,
|
|
4186
4172
|
onPointerleave: handleLeave,
|
|
4187
|
-
onFocus: (
|
|
4173
|
+
onFocus: () => {
|
|
4188
4174
|
if (!props.disabled) hi.open();
|
|
4189
|
-
}
|
|
4190
|
-
onBlur: (
|
|
4175
|
+
},
|
|
4176
|
+
onBlur: () => {
|
|
4191
4177
|
if (!props.disabled) hi.close();
|
|
4192
|
-
}
|
|
4178
|
+
}
|
|
4193
4179
|
};
|
|
4194
4180
|
const captureTriggerRef = (el) => {
|
|
4195
4181
|
triggerRef.value = el ?? null;
|
|
@@ -4258,7 +4244,7 @@ var IrisTooltip = vue.defineComponent({
|
|
|
4258
4244
|
});
|
|
4259
4245
|
|
|
4260
4246
|
// src/primitives/dialog/context.ts
|
|
4261
|
-
var DialogContextKey =
|
|
4247
|
+
var DialogContextKey = Symbol("IrisDialog");
|
|
4262
4248
|
|
|
4263
4249
|
// src/primitives/dialog/Dialog.ts
|
|
4264
4250
|
var IrisDialog = vue.defineComponent({
|
|
@@ -4384,9 +4370,8 @@ function getFocusable(root) {
|
|
|
4384
4370
|
(el) => !el.hasAttribute("disabled") && el.tabIndex !== -1
|
|
4385
4371
|
);
|
|
4386
4372
|
}
|
|
4387
|
-
function
|
|
4388
|
-
|
|
4389
|
-
const onKeyDown = (event) => {
|
|
4373
|
+
function createFocusTrapKeyHandler(options) {
|
|
4374
|
+
return (event) => {
|
|
4390
4375
|
if (!options.active.value || event.key !== "Tab") return;
|
|
4391
4376
|
const root = options.container.value;
|
|
4392
4377
|
if (!root) return;
|
|
@@ -4404,13 +4389,15 @@ function useFocusTrap(options) {
|
|
|
4404
4389
|
event.preventDefault();
|
|
4405
4390
|
last.focus();
|
|
4406
4391
|
}
|
|
4407
|
-
} else {
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
first.focus();
|
|
4411
|
-
}
|
|
4392
|
+
} else if (active === last || !root.contains(active)) {
|
|
4393
|
+
event.preventDefault();
|
|
4394
|
+
first.focus();
|
|
4412
4395
|
}
|
|
4413
4396
|
};
|
|
4397
|
+
}
|
|
4398
|
+
function useFocusTrap(options) {
|
|
4399
|
+
let previouslyFocused = null;
|
|
4400
|
+
const onKeyDown = createFocusTrapKeyHandler(options);
|
|
4414
4401
|
const activate = () => {
|
|
4415
4402
|
if (typeof document === "undefined") return;
|
|
4416
4403
|
previouslyFocused = document.activeElement ?? null;
|
|
@@ -4715,7 +4702,7 @@ var IrisDialogClose = vue.defineComponent({
|
|
|
4715
4702
|
});
|
|
4716
4703
|
|
|
4717
4704
|
// src/primitives/drawer/context.ts
|
|
4718
|
-
var DrawerContextKey =
|
|
4705
|
+
var DrawerContextKey = Symbol("IrisDrawer");
|
|
4719
4706
|
|
|
4720
4707
|
// src/primitives/drawer/Drawer.ts
|
|
4721
4708
|
var IrisDrawer = vue.defineComponent({
|
|
@@ -5099,11 +5086,11 @@ var IrisInput = vue.defineComponent({
|
|
|
5099
5086
|
display: "inline-flex",
|
|
5100
5087
|
alignItems: "center",
|
|
5101
5088
|
gap: "var(--iris-gap-sm)",
|
|
5102
|
-
background: "var(--iris-background)",
|
|
5089
|
+
background: props.readonly ? "var(--iris-surface)" : "var(--iris-background)",
|
|
5103
5090
|
color: "var(--iris-foreground)",
|
|
5104
5091
|
border: `1px solid ${borderColor}`,
|
|
5105
5092
|
borderRadius: "var(--iris-radius-md)",
|
|
5106
|
-
cursor: props.disabled ? "not-allowed" : "text",
|
|
5093
|
+
cursor: props.disabled ? "not-allowed" : props.readonly ? "default" : "text",
|
|
5107
5094
|
opacity: props.disabled ? "0.6" : "1",
|
|
5108
5095
|
transition: "border-color 120ms ease, box-shadow 120ms ease",
|
|
5109
5096
|
boxShadow,
|
|
@@ -5143,7 +5130,7 @@ var IrisInput = vue.defineComponent({
|
|
|
5143
5130
|
...attrs,
|
|
5144
5131
|
"data-iris-input": "",
|
|
5145
5132
|
"data-iris-input-size": props.size,
|
|
5146
|
-
"data-state": props.invalid ? "invalid" : focused.value ? "focused" : "idle",
|
|
5133
|
+
"data-state": props.invalid ? "invalid" : focused.value ? "focused" : props.readonly ? "readonly" : "idle",
|
|
5147
5134
|
style: {
|
|
5148
5135
|
...wrapperStyle.value,
|
|
5149
5136
|
...attrs.style ?? {}
|
|
@@ -6725,7 +6712,7 @@ var IrisCheckbox = vue.defineComponent({
|
|
|
6725
6712
|
);
|
|
6726
6713
|
}
|
|
6727
6714
|
});
|
|
6728
|
-
var RadioGroupKey =
|
|
6715
|
+
var RadioGroupKey = Symbol("IrisRadioGroup");
|
|
6729
6716
|
var IrisRadioGroup = vue.defineComponent({
|
|
6730
6717
|
name: "IrisRadioGroup",
|
|
6731
6718
|
props: {
|
|
@@ -7099,6 +7086,152 @@ var IrisList = vue.defineComponent({
|
|
|
7099
7086
|
);
|
|
7100
7087
|
}
|
|
7101
7088
|
});
|
|
7089
|
+
function renderVirtualSelectListbox({
|
|
7090
|
+
items,
|
|
7091
|
+
translate,
|
|
7092
|
+
listboxRef,
|
|
7093
|
+
onListKeyDown,
|
|
7094
|
+
virtualizer,
|
|
7095
|
+
state,
|
|
7096
|
+
activeIndex,
|
|
7097
|
+
multiple,
|
|
7098
|
+
selectedValues,
|
|
7099
|
+
currentValue,
|
|
7100
|
+
onSelect,
|
|
7101
|
+
rowHeight
|
|
7102
|
+
}) {
|
|
7103
|
+
const optionStyle = (selected, active, disabled) => ({
|
|
7104
|
+
display: "flex",
|
|
7105
|
+
alignItems: "center",
|
|
7106
|
+
gap: "var(--iris-gap-sm)",
|
|
7107
|
+
padding: "var(--iris-padding-sm, 6px) var(--iris-padding-md)",
|
|
7108
|
+
borderRadius: "var(--iris-radius-sm)",
|
|
7109
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
7110
|
+
opacity: disabled ? "0.5" : "1",
|
|
7111
|
+
fontSize: "var(--iris-font-size-md, 14px)",
|
|
7112
|
+
background: selected ? "var(--iris-surface-selected, rgba(99, 102, 241, 0.12))" : active ? "var(--iris-surface-hover)" : "transparent",
|
|
7113
|
+
color: "var(--iris-foreground)",
|
|
7114
|
+
fontWeight: selected ? "600" : "400",
|
|
7115
|
+
outline: "none"
|
|
7116
|
+
});
|
|
7117
|
+
const check = () => vue.h(
|
|
7118
|
+
"svg",
|
|
7119
|
+
{
|
|
7120
|
+
"aria-hidden": "true",
|
|
7121
|
+
width: "14",
|
|
7122
|
+
height: "14",
|
|
7123
|
+
viewBox: "0 0 24 24",
|
|
7124
|
+
fill: "none",
|
|
7125
|
+
stroke: "var(--iris-primary)",
|
|
7126
|
+
"stroke-width": "2.5",
|
|
7127
|
+
"stroke-linecap": "round",
|
|
7128
|
+
"stroke-linejoin": "round"
|
|
7129
|
+
},
|
|
7130
|
+
[vue.h("path", { d: "M20 6 9 17l-5-5" })]
|
|
7131
|
+
);
|
|
7132
|
+
return vue.h(
|
|
7133
|
+
"ul",
|
|
7134
|
+
{
|
|
7135
|
+
role: "listbox",
|
|
7136
|
+
"aria-label": translate("select.options"),
|
|
7137
|
+
"data-iris-list": "",
|
|
7138
|
+
ref: (el) => {
|
|
7139
|
+
listboxRef.value = el ?? null;
|
|
7140
|
+
},
|
|
7141
|
+
onKeydown: onListKeyDown,
|
|
7142
|
+
onScroll: (event) => {
|
|
7143
|
+
virtualizer?.setScroll(event.currentTarget.scrollTop);
|
|
7144
|
+
},
|
|
7145
|
+
style: {
|
|
7146
|
+
listStyle: "none",
|
|
7147
|
+
margin: "0",
|
|
7148
|
+
padding: "var(--iris-padding-sm)",
|
|
7149
|
+
display: "flex",
|
|
7150
|
+
flexDirection: "column",
|
|
7151
|
+
outline: "none",
|
|
7152
|
+
maxHeight: "240px",
|
|
7153
|
+
overflowY: "auto"
|
|
7154
|
+
}
|
|
7155
|
+
},
|
|
7156
|
+
items.length === 0 ? [
|
|
7157
|
+
vue.h(
|
|
7158
|
+
"li",
|
|
7159
|
+
{
|
|
7160
|
+
role: "presentation",
|
|
7161
|
+
"data-iris-list-state": "empty",
|
|
7162
|
+
"aria-live": "polite",
|
|
7163
|
+
style: {
|
|
7164
|
+
listStyle: "none",
|
|
7165
|
+
padding: "12px",
|
|
7166
|
+
textAlign: "center",
|
|
7167
|
+
color: "var(--iris-muted)",
|
|
7168
|
+
fontSize: "var(--iris-font-size-md, 14px)"
|
|
7169
|
+
}
|
|
7170
|
+
},
|
|
7171
|
+
translate("list.empty")
|
|
7172
|
+
)
|
|
7173
|
+
] : [
|
|
7174
|
+
vue.h("li", {
|
|
7175
|
+
role: "presentation",
|
|
7176
|
+
"aria-hidden": "true",
|
|
7177
|
+
"data-iris-select-spacer": "",
|
|
7178
|
+
"data-iris-select-spacer-type": "top",
|
|
7179
|
+
style: { height: `${state.value.offsetBefore}px` }
|
|
7180
|
+
}),
|
|
7181
|
+
...state.value.items.map((item) => {
|
|
7182
|
+
const option = items[item.index];
|
|
7183
|
+
if (!option) return null;
|
|
7184
|
+
const active = item.index === activeIndex.value;
|
|
7185
|
+
const selected = multiple ? selectedValues.value.includes(option.value) : option.value === currentValue.value;
|
|
7186
|
+
return vue.h(
|
|
7187
|
+
"li",
|
|
7188
|
+
{
|
|
7189
|
+
key: String(option.value ?? item.index),
|
|
7190
|
+
role: "option",
|
|
7191
|
+
tabindex: active ? 0 : -1,
|
|
7192
|
+
"aria-selected": selected ? "true" : "false",
|
|
7193
|
+
"aria-disabled": option.disabled ? "true" : void 0,
|
|
7194
|
+
"aria-setsize": items.length,
|
|
7195
|
+
"aria-posinset": item.index + 1,
|
|
7196
|
+
"data-iris-list-index": item.index,
|
|
7197
|
+
"data-iris-list-item": "",
|
|
7198
|
+
"data-state": selected ? "selected" : active ? "active" : "idle",
|
|
7199
|
+
onClick: option.disabled ? void 0 : () => {
|
|
7200
|
+
activeIndex.value = item.index;
|
|
7201
|
+
onSelect(option);
|
|
7202
|
+
},
|
|
7203
|
+
onFocus: () => {
|
|
7204
|
+
activeIndex.value = item.index;
|
|
7205
|
+
},
|
|
7206
|
+
onMouseenter: () => {
|
|
7207
|
+
activeIndex.value = item.index;
|
|
7208
|
+
},
|
|
7209
|
+
style: optionStyle(selected, active, !!option.disabled)
|
|
7210
|
+
},
|
|
7211
|
+
[
|
|
7212
|
+
vue.h(
|
|
7213
|
+
"span",
|
|
7214
|
+
{ style: { flex: "1", minWidth: "0" } },
|
|
7215
|
+
option.label ?? String(option.value)
|
|
7216
|
+
),
|
|
7217
|
+
selected ? check() : null
|
|
7218
|
+
]
|
|
7219
|
+
);
|
|
7220
|
+
}),
|
|
7221
|
+
vue.h("li", {
|
|
7222
|
+
role: "presentation",
|
|
7223
|
+
"aria-hidden": "true",
|
|
7224
|
+
"data-iris-select-spacer": "",
|
|
7225
|
+
"data-iris-select-spacer-type": "bottom",
|
|
7226
|
+
style: {
|
|
7227
|
+
height: `${state.value.totalSize - state.value.offsetBefore - state.value.items.length * rowHeight}px`
|
|
7228
|
+
}
|
|
7229
|
+
})
|
|
7230
|
+
]
|
|
7231
|
+
);
|
|
7232
|
+
}
|
|
7233
|
+
|
|
7234
|
+
// src/primitives/select/Select.ts
|
|
7102
7235
|
var IrisSelect = vue.defineComponent({
|
|
7103
7236
|
name: "IrisSelect",
|
|
7104
7237
|
inheritAttrs: false,
|
|
@@ -7336,138 +7469,6 @@ var IrisSelect = vue.defineComponent({
|
|
|
7336
7469
|
})
|
|
7337
7470
|
]
|
|
7338
7471
|
);
|
|
7339
|
-
const renderVirtualListbox = () => {
|
|
7340
|
-
const list = props.items;
|
|
7341
|
-
const optionStyle = (selected, active, disabled) => ({
|
|
7342
|
-
display: "flex",
|
|
7343
|
-
alignItems: "center",
|
|
7344
|
-
gap: "var(--iris-gap-sm)",
|
|
7345
|
-
padding: "var(--iris-padding-sm, 6px) var(--iris-padding-md)",
|
|
7346
|
-
borderRadius: "var(--iris-radius-sm)",
|
|
7347
|
-
cursor: disabled ? "not-allowed" : "pointer",
|
|
7348
|
-
opacity: disabled ? "0.5" : "1",
|
|
7349
|
-
fontSize: "var(--iris-font-size-md, 14px)",
|
|
7350
|
-
background: selected ? "var(--iris-surface-selected, rgba(99, 102, 241, 0.12))" : active ? "var(--iris-surface-hover)" : "transparent",
|
|
7351
|
-
color: "var(--iris-foreground)",
|
|
7352
|
-
fontWeight: selected ? "600" : "400",
|
|
7353
|
-
outline: "none"
|
|
7354
|
-
});
|
|
7355
|
-
const check = () => vue.h(
|
|
7356
|
-
"svg",
|
|
7357
|
-
{
|
|
7358
|
-
"aria-hidden": "true",
|
|
7359
|
-
width: "14",
|
|
7360
|
-
height: "14",
|
|
7361
|
-
viewBox: "0 0 24 24",
|
|
7362
|
-
fill: "none",
|
|
7363
|
-
stroke: "var(--iris-primary)",
|
|
7364
|
-
"stroke-width": "2.5",
|
|
7365
|
-
"stroke-linecap": "round",
|
|
7366
|
-
"stroke-linejoin": "round"
|
|
7367
|
-
},
|
|
7368
|
-
[vue.h("path", { d: "M20 6 9 17l-5-5" })]
|
|
7369
|
-
);
|
|
7370
|
-
return vue.h(
|
|
7371
|
-
"ul",
|
|
7372
|
-
{
|
|
7373
|
-
role: "listbox",
|
|
7374
|
-
"aria-label": t("select.options"),
|
|
7375
|
-
"data-iris-list": "",
|
|
7376
|
-
ref: (el) => {
|
|
7377
|
-
listboxRef.value = el ?? null;
|
|
7378
|
-
},
|
|
7379
|
-
onKeydown: onListKeyDown,
|
|
7380
|
-
onScroll: (e) => {
|
|
7381
|
-
v?.setScroll(e.currentTarget.scrollTop);
|
|
7382
|
-
},
|
|
7383
|
-
style: {
|
|
7384
|
-
listStyle: "none",
|
|
7385
|
-
margin: "0",
|
|
7386
|
-
padding: "var(--iris-padding-sm)",
|
|
7387
|
-
display: "flex",
|
|
7388
|
-
flexDirection: "column",
|
|
7389
|
-
outline: "none",
|
|
7390
|
-
maxHeight: "240px",
|
|
7391
|
-
overflowY: "auto"
|
|
7392
|
-
}
|
|
7393
|
-
},
|
|
7394
|
-
list.length === 0 ? [
|
|
7395
|
-
vue.h(
|
|
7396
|
-
"li",
|
|
7397
|
-
{
|
|
7398
|
-
role: "presentation",
|
|
7399
|
-
"data-iris-list-state": "empty",
|
|
7400
|
-
"aria-live": "polite",
|
|
7401
|
-
style: {
|
|
7402
|
-
listStyle: "none",
|
|
7403
|
-
padding: "12px",
|
|
7404
|
-
textAlign: "center",
|
|
7405
|
-
color: "var(--iris-muted)",
|
|
7406
|
-
fontSize: "var(--iris-font-size-md, 14px)"
|
|
7407
|
-
}
|
|
7408
|
-
},
|
|
7409
|
-
t("list.empty")
|
|
7410
|
-
)
|
|
7411
|
-
] : [
|
|
7412
|
-
vue.h("li", {
|
|
7413
|
-
role: "presentation",
|
|
7414
|
-
"aria-hidden": "true",
|
|
7415
|
-
"data-iris-select-spacer": "",
|
|
7416
|
-
"data-iris-select-spacer-type": "top",
|
|
7417
|
-
style: { height: `${vstate.value.offsetBefore}px` }
|
|
7418
|
-
}),
|
|
7419
|
-
...vstate.value.items.map((item) => {
|
|
7420
|
-
const opt = list[item.index];
|
|
7421
|
-
if (!opt) return null;
|
|
7422
|
-
const active = item.index === activeIndex.value;
|
|
7423
|
-
const selected = props.multiple ? selectedValues.value.includes(opt.value) : opt.value === currentValue.value;
|
|
7424
|
-
return vue.h(
|
|
7425
|
-
"li",
|
|
7426
|
-
{
|
|
7427
|
-
key: String(opt.value ?? item.index),
|
|
7428
|
-
role: "option",
|
|
7429
|
-
tabindex: active ? 0 : -1,
|
|
7430
|
-
"aria-selected": selected ? "true" : "false",
|
|
7431
|
-
"aria-disabled": opt.disabled ? "true" : void 0,
|
|
7432
|
-
"aria-setsize": list.length,
|
|
7433
|
-
"aria-posinset": item.index + 1,
|
|
7434
|
-
"data-iris-list-index": item.index,
|
|
7435
|
-
"data-iris-list-item": "",
|
|
7436
|
-
"data-state": selected ? "selected" : active ? "active" : "idle",
|
|
7437
|
-
onClick: opt.disabled ? void 0 : () => {
|
|
7438
|
-
activeIndex.value = item.index;
|
|
7439
|
-
onSelect(opt);
|
|
7440
|
-
},
|
|
7441
|
-
onFocus: () => {
|
|
7442
|
-
activeIndex.value = item.index;
|
|
7443
|
-
},
|
|
7444
|
-
onMouseenter: () => {
|
|
7445
|
-
activeIndex.value = item.index;
|
|
7446
|
-
},
|
|
7447
|
-
style: optionStyle(selected, active, !!opt.disabled)
|
|
7448
|
-
},
|
|
7449
|
-
[
|
|
7450
|
-
vue.h(
|
|
7451
|
-
"span",
|
|
7452
|
-
{ style: { flex: "1", minWidth: "0" } },
|
|
7453
|
-
opt.label ?? String(opt.value)
|
|
7454
|
-
),
|
|
7455
|
-
selected ? check() : null
|
|
7456
|
-
]
|
|
7457
|
-
);
|
|
7458
|
-
}),
|
|
7459
|
-
vue.h("li", {
|
|
7460
|
-
role: "presentation",
|
|
7461
|
-
"aria-hidden": "true",
|
|
7462
|
-
"data-iris-select-spacer": "",
|
|
7463
|
-
"data-iris-select-spacer-type": "bottom",
|
|
7464
|
-
style: {
|
|
7465
|
-
height: `${vstate.value.totalSize - vstate.value.offsetBefore - vstate.value.items.length * ROW_HEIGHT3}px`
|
|
7466
|
-
}
|
|
7467
|
-
})
|
|
7468
|
-
]
|
|
7469
|
-
);
|
|
7470
|
-
};
|
|
7471
7472
|
return () => vue.h(
|
|
7472
7473
|
IrisPopover,
|
|
7473
7474
|
{
|
|
@@ -7514,7 +7515,20 @@ var IrisSelect = vue.defineComponent({
|
|
|
7514
7515
|
style: { padding: "var(--iris-padding-sm)", minWidth: "180px" },
|
|
7515
7516
|
...props.teleport !== void 0 ? { teleport: props.teleport } : {}
|
|
7516
7517
|
},
|
|
7517
|
-
() => props.virtual ?
|
|
7518
|
+
() => props.virtual ? renderVirtualSelectListbox({
|
|
7519
|
+
items: props.items,
|
|
7520
|
+
translate: t,
|
|
7521
|
+
listboxRef,
|
|
7522
|
+
onListKeyDown,
|
|
7523
|
+
virtualizer: v,
|
|
7524
|
+
state: vstate,
|
|
7525
|
+
activeIndex,
|
|
7526
|
+
multiple: props.multiple,
|
|
7527
|
+
selectedValues,
|
|
7528
|
+
currentValue,
|
|
7529
|
+
onSelect,
|
|
7530
|
+
rowHeight: ROW_HEIGHT3
|
|
7531
|
+
}) : vue.h(IrisList, {
|
|
7518
7532
|
items: props.items,
|
|
7519
7533
|
modelValue: currentValue.value,
|
|
7520
7534
|
onSelect,
|
|
@@ -7976,8 +7990,8 @@ var IrisSkeleton = vue.defineComponent({
|
|
|
7976
7990
|
vue.onMounted(installSkeletonStyles);
|
|
7977
7991
|
const style = vue.computed(() => {
|
|
7978
7992
|
const w = props.width !== void 0 ? toCss(props.width) : defaultWidth(props.shape);
|
|
7979
|
-
const
|
|
7980
|
-
return { width: w, height:
|
|
7993
|
+
const h136 = props.height !== void 0 ? toCss(props.height) : defaultHeight(props.shape, props.width);
|
|
7994
|
+
return { width: w, height: h136 };
|
|
7981
7995
|
});
|
|
7982
7996
|
return () => vue.h("div", {
|
|
7983
7997
|
...attrs,
|
|
@@ -9088,7 +9102,7 @@ var IrisChip = vue.defineComponent({
|
|
|
9088
9102
|
});
|
|
9089
9103
|
|
|
9090
9104
|
// src/primitives/accordion/context.ts
|
|
9091
|
-
var AccordionContextKey =
|
|
9105
|
+
var AccordionContextKey = Symbol("IrisAccordion");
|
|
9092
9106
|
|
|
9093
9107
|
// src/primitives/accordion/Accordion.ts
|
|
9094
9108
|
var IrisAccordion = vue.defineComponent({
|
|
@@ -9326,7 +9340,7 @@ var IrisAccordionItem = vue.defineComponent({
|
|
|
9326
9340
|
});
|
|
9327
9341
|
|
|
9328
9342
|
// src/primitives/stepper/context.ts
|
|
9329
|
-
var StepperContextKey =
|
|
9343
|
+
var StepperContextKey = Symbol("IrisStepper");
|
|
9330
9344
|
|
|
9331
9345
|
// src/primitives/stepper/Stepper.ts
|
|
9332
9346
|
var IrisStepper = vue.defineComponent({
|
|
@@ -9574,7 +9588,7 @@ var IrisStepperStep = vue.defineComponent({
|
|
|
9574
9588
|
});
|
|
9575
9589
|
|
|
9576
9590
|
// src/primitives/toggle-group/context.ts
|
|
9577
|
-
var ToggleGroupContextKey =
|
|
9591
|
+
var ToggleGroupContextKey = Symbol("IrisToggleGroup");
|
|
9578
9592
|
var SIZE_PADDING = {
|
|
9579
9593
|
sm: "4px 10px",
|
|
9580
9594
|
md: "6px 14px",
|
|
@@ -10504,35 +10518,287 @@ var tableControlProps = {
|
|
|
10504
10518
|
default: void 0
|
|
10505
10519
|
}
|
|
10506
10520
|
};
|
|
10521
|
+
|
|
10522
|
+
// src/primitives/table/props.ts
|
|
10523
|
+
var tableProps = {
|
|
10524
|
+
columns: {
|
|
10525
|
+
type: Array,
|
|
10526
|
+
required: true
|
|
10527
|
+
},
|
|
10528
|
+
data: {
|
|
10529
|
+
type: Array,
|
|
10530
|
+
required: false,
|
|
10531
|
+
default: void 0
|
|
10532
|
+
},
|
|
10533
|
+
rowKey: { type: String, default: "id" },
|
|
10534
|
+
...tableControlProps,
|
|
10535
|
+
/** Multi-column sort (vxe sort-config.multiple parity). */
|
|
10536
|
+
multiSort: { type: Boolean, default: false },
|
|
10537
|
+
multiSortState: {
|
|
10538
|
+
type: Array,
|
|
10539
|
+
default: void 0
|
|
10540
|
+
},
|
|
10541
|
+
defaultMultiSort: {
|
|
10542
|
+
type: Array,
|
|
10543
|
+
default: void 0
|
|
10544
|
+
},
|
|
10545
|
+
striped: { type: Boolean, default: false },
|
|
10546
|
+
editConfig: {
|
|
10547
|
+
type: Object,
|
|
10548
|
+
default: void 0
|
|
10549
|
+
},
|
|
10550
|
+
bordered: { type: Boolean, default: true },
|
|
10551
|
+
/** Row-density preset; invalid runtime values fail closed to comfortable. */
|
|
10552
|
+
density: {
|
|
10553
|
+
type: String,
|
|
10554
|
+
default: "comfortable"
|
|
10555
|
+
},
|
|
10556
|
+
/** Show the local density cycle button in the table toolbar. */
|
|
10557
|
+
densityToggle: { type: Boolean, default: false },
|
|
10558
|
+
/** Show a live formatter preview while an editor is open. */
|
|
10559
|
+
editPreview: { type: Boolean, default: false },
|
|
10560
|
+
/** Highlight committed cells matching the active inline draft. */
|
|
10561
|
+
pattern: { type: Boolean, default: false },
|
|
10562
|
+
/** Alias for pattern feedback. */
|
|
10563
|
+
patternFill: { type: Boolean, default: false },
|
|
10564
|
+
/** Named snapshots available in the table toolbar. */
|
|
10565
|
+
views: { type: Object, default: void 0 },
|
|
10566
|
+
/** Controlled active named view notification. */
|
|
10567
|
+
onActiveViewChange: {
|
|
10568
|
+
type: Function,
|
|
10569
|
+
default: void 0
|
|
10570
|
+
},
|
|
10571
|
+
/** Optional tab strip; tab clicks apply listed view names in order. */
|
|
10572
|
+
tableTabs: { type: Array, default: void 0 },
|
|
10573
|
+
/** Show a draggable boundary for the leading left-pinned columns. */
|
|
10574
|
+
pinnedDrag: { type: Boolean, default: false },
|
|
10575
|
+
/** Called for each column whose pin side changes. */
|
|
10576
|
+
onColumnPinnedChange: {
|
|
10577
|
+
type: Function,
|
|
10578
|
+
default: void 0
|
|
10579
|
+
},
|
|
10580
|
+
/** Called once after a pinned-boundary commit. */
|
|
10581
|
+
onPinnedCountChange: { type: Function, default: void 0 },
|
|
10582
|
+
/** Infer leaf-column value kinds from the first non-empty data arrival and
|
|
10583
|
+
* fill only missing alignment defaults. Disabled by default. */
|
|
10584
|
+
autoDetectTypes: { type: Boolean, default: false },
|
|
10585
|
+
/** Below 480px, greedily hide the lowest-priority top-level columns until
|
|
10586
|
+
* the natural width fits; pinned columns survive. */
|
|
10587
|
+
responsive: { type: Boolean, default: false },
|
|
10588
|
+
/** Extra bare row sets appended as named CSV segments by the imperative handle. */
|
|
10589
|
+
exportNames: {
|
|
10590
|
+
type: Array,
|
|
10591
|
+
default: void 0
|
|
10592
|
+
},
|
|
10593
|
+
resizableColumns: { type: Boolean, default: false },
|
|
10594
|
+
columnWidths: {
|
|
10595
|
+
type: Object,
|
|
10596
|
+
default: void 0
|
|
10597
|
+
},
|
|
10598
|
+
virtualScroll: {
|
|
10599
|
+
type: Object,
|
|
10600
|
+
default: void 0
|
|
10601
|
+
},
|
|
10602
|
+
loading: { type: Boolean, default: false },
|
|
10603
|
+
error: { type: Boolean, default: false },
|
|
10604
|
+
/** Print-friendly mode: marks the root so toolbar/form chrome is hidden by print CSS. */
|
|
10605
|
+
printable: { type: Boolean, default: false },
|
|
10606
|
+
/** Show a confirmation preview before the toolbar CSV import callback. */
|
|
10607
|
+
importPreview: { type: Boolean, default: false },
|
|
10608
|
+
onRetry: { type: Function, default: void 0 },
|
|
10609
|
+
columnVirtualization: { type: Boolean, default: false },
|
|
10610
|
+
keyboardNavigation: { type: Boolean, default: false },
|
|
10611
|
+
cellRange: { type: Boolean, default: false },
|
|
10612
|
+
/** Range clipboard copy; copyWithFormat uses column formatter output. */
|
|
10613
|
+
clipConfig: { type: Object, default: void 0 },
|
|
10614
|
+
renderDetail: {
|
|
10615
|
+
type: Function,
|
|
10616
|
+
default: void 0
|
|
10617
|
+
},
|
|
10618
|
+
rowExpandable: {
|
|
10619
|
+
type: Function,
|
|
10620
|
+
default: void 0
|
|
10621
|
+
},
|
|
10622
|
+
defaultExpandedRowKeys: {
|
|
10623
|
+
type: Array,
|
|
10624
|
+
default: void 0
|
|
10625
|
+
},
|
|
10626
|
+
getSubRows: {
|
|
10627
|
+
type: Function,
|
|
10628
|
+
default: void 0
|
|
10629
|
+
},
|
|
10630
|
+
treeSelectionCascade: { type: Boolean, default: false },
|
|
10631
|
+
proxyConfig: {
|
|
10632
|
+
type: Object,
|
|
10633
|
+
default: void 0
|
|
10634
|
+
},
|
|
10635
|
+
formConfig: {
|
|
10636
|
+
type: Object,
|
|
10637
|
+
default: void 0
|
|
10638
|
+
},
|
|
10639
|
+
toolbar: {
|
|
10640
|
+
type: Object,
|
|
10641
|
+
default: void 0
|
|
10642
|
+
},
|
|
10643
|
+
columnVisibility: {
|
|
10644
|
+
type: Object,
|
|
10645
|
+
default: void 0
|
|
10646
|
+
},
|
|
10647
|
+
filters: {
|
|
10648
|
+
type: Object,
|
|
10649
|
+
default: void 0
|
|
10650
|
+
},
|
|
10651
|
+
filterValues: {
|
|
10652
|
+
type: Object,
|
|
10653
|
+
default: void 0
|
|
10654
|
+
},
|
|
10655
|
+
onFilterValuesChange: {
|
|
10656
|
+
type: Function,
|
|
10657
|
+
default: void 0
|
|
10658
|
+
},
|
|
10659
|
+
contextMenu: {
|
|
10660
|
+
type: Object,
|
|
10661
|
+
default: void 0
|
|
10662
|
+
},
|
|
10663
|
+
lazyLoad: {
|
|
10664
|
+
type: Function,
|
|
10665
|
+
default: void 0
|
|
10666
|
+
},
|
|
10667
|
+
seq: { type: Boolean, default: false },
|
|
10668
|
+
seqStartIndex: { type: Number, default: 1 },
|
|
10669
|
+
spanMethod: {
|
|
10670
|
+
type: Function,
|
|
10671
|
+
default: void 0
|
|
10672
|
+
},
|
|
10673
|
+
columnDrag: {
|
|
10674
|
+
type: Object,
|
|
10675
|
+
default: void 0
|
|
10676
|
+
},
|
|
10677
|
+
rowDrag: {
|
|
10678
|
+
type: Object,
|
|
10679
|
+
default: void 0
|
|
10680
|
+
},
|
|
10681
|
+
onDataChange: {
|
|
10682
|
+
type: Function,
|
|
10683
|
+
default: void 0
|
|
10684
|
+
}
|
|
10685
|
+
};
|
|
10686
|
+
var SELECTION_COL_WIDTH = 40;
|
|
10687
|
+
var EXPAND_COL_WIDTH = 40;
|
|
10688
|
+
var SEQ_COL_WIDTH = 40;
|
|
10689
|
+
var DRAG_COL_WIDTH = 40;
|
|
10690
|
+
var DEFAULT_COL_WIDTH = 140;
|
|
10691
|
+
var DEFAULT_MIN_WIDTH = 60;
|
|
10692
|
+
var RESIZE_STEP = 16;
|
|
10507
10693
|
function getCellValue(row, column) {
|
|
10508
10694
|
const key = column.dataIndex ?? column.key;
|
|
10509
10695
|
return row[key];
|
|
10510
10696
|
}
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
const
|
|
10516
|
-
const
|
|
10697
|
+
function resolveSpan(occupied, rowIndex, columnIndex, method) {
|
|
10698
|
+
if (!method) return { rowspan: 1, colspan: 1 };
|
|
10699
|
+
const key = `${rowIndex}:${columnIndex}`;
|
|
10700
|
+
if (occupied.has(key)) return null;
|
|
10701
|
+
const span = method({ rowIndex, columnIndex });
|
|
10702
|
+
const rowspan = span?.rowspan ?? 1;
|
|
10703
|
+
const colspan = span?.colspan ?? 1;
|
|
10704
|
+
if (rowspan > 1) {
|
|
10705
|
+
for (let row = 1; row < rowspan; row += 1) occupied.add(`${rowIndex + row}:${columnIndex}`);
|
|
10706
|
+
}
|
|
10707
|
+
if (colspan > 1) {
|
|
10708
|
+
for (let column = 1; column < colspan; column += 1) {
|
|
10709
|
+
occupied.add(`${rowIndex}:${columnIndex + column}`);
|
|
10710
|
+
}
|
|
10711
|
+
}
|
|
10712
|
+
return { rowspan, colspan };
|
|
10713
|
+
}
|
|
10714
|
+
function resolveInitialWidth(col) {
|
|
10715
|
+
if (typeof col.width === "number") return col.width;
|
|
10716
|
+
if (typeof col.width === "string") {
|
|
10717
|
+
const match = col.width.match(/^(\d+(?:\.\d+)?)px$/);
|
|
10718
|
+
if (match) return Number(match[1]);
|
|
10719
|
+
}
|
|
10720
|
+
return DEFAULT_COL_WIDTH;
|
|
10721
|
+
}
|
|
10722
|
+
function computeVisibleColSet(enabled, columns, scrollLeft, viewportWidth, widths) {
|
|
10723
|
+
if (!enabled) return null;
|
|
10724
|
+
const range = core.computeVirtualRange({
|
|
10725
|
+
itemCount: columns.length,
|
|
10726
|
+
scrollTop: scrollLeft,
|
|
10727
|
+
viewportSize: viewportWidth,
|
|
10728
|
+
itemSize: (index) => widths[columns[index].key] ?? resolveInitialWidth(columns[index]),
|
|
10729
|
+
buffer: 2
|
|
10730
|
+
});
|
|
10731
|
+
const visible = /* @__PURE__ */ new Set();
|
|
10732
|
+
for (let index = range.startIndex; index <= range.endIndex; index += 1) visible.add(index);
|
|
10733
|
+
columns.forEach((column, index) => {
|
|
10734
|
+
if (column.pinned) visible.add(index);
|
|
10735
|
+
});
|
|
10736
|
+
return visible;
|
|
10737
|
+
}
|
|
10738
|
+
function cellId(rowIdent, columnKey) {
|
|
10739
|
+
return `${rowIdent}::${columnKey}`;
|
|
10740
|
+
}
|
|
10741
|
+
|
|
10742
|
+
// src/primitives/table/useTableSort.ts
|
|
10743
|
+
function buildSorter(col) {
|
|
10744
|
+
if (col.sorter) return col.sorter;
|
|
10745
|
+
return (a, b) => core.compareValues(getCellValue(a, col), getCellValue(b, col));
|
|
10746
|
+
}
|
|
10747
|
+
function buildMultiSortComparator(leafColumns, state) {
|
|
10748
|
+
if (state.length === 0) return null;
|
|
10749
|
+
const colMap = new Map(leafColumns.map((c) => [c.key, c]));
|
|
10750
|
+
const chain = [];
|
|
10751
|
+
for (const s of state) {
|
|
10752
|
+
const col = colMap.get(s.key);
|
|
10753
|
+
if (!col) continue;
|
|
10754
|
+
chain.push({ dir: s.direction === "asc" ? 1 : -1, sorter: buildSorter(col) });
|
|
10755
|
+
}
|
|
10756
|
+
if (chain.length === 0) return null;
|
|
10757
|
+
return (a, b) => {
|
|
10758
|
+
for (const step of chain) {
|
|
10759
|
+
const cmp = step.sorter(a, b);
|
|
10760
|
+
if (cmp !== 0) return cmp * step.dir;
|
|
10761
|
+
}
|
|
10762
|
+
return 0;
|
|
10763
|
+
};
|
|
10764
|
+
}
|
|
10765
|
+
function useTableSort(data, options) {
|
|
10766
|
+
const sortProp = vue.computed(() => options.sort === void 0 ? void 0 : vue.toValue(options.sort));
|
|
10767
|
+
const internalSortValue = vue.ref(options.defaultSort ?? null);
|
|
10768
|
+
const sortState = vue.computed({
|
|
10517
10769
|
get: () => sortProp.value === void 0 ? internalSortValue.value : sortProp.value ?? null,
|
|
10518
10770
|
set: (val) => {
|
|
10519
10771
|
if (sortProp.value === void 0) internalSortValue.value = val;
|
|
10520
10772
|
options.onSortChange?.(val);
|
|
10521
10773
|
}
|
|
10522
10774
|
});
|
|
10775
|
+
const multiEnabled = vue.computed(() => vue.toValue(options.multiSort) === true);
|
|
10776
|
+
const multiSortProp = vue.computed(
|
|
10777
|
+
() => options.multiSortState === void 0 ? void 0 : vue.toValue(options.multiSortState)
|
|
10778
|
+
);
|
|
10779
|
+
const internalMultiSort = vue.ref(options.defaultMultiSort ?? []);
|
|
10780
|
+
const multiSortState = vue.computed({
|
|
10781
|
+
get: () => multiSortProp.value === void 0 ? internalMultiSort.value : multiSortProp.value,
|
|
10782
|
+
set: (val) => {
|
|
10783
|
+
if (multiSortProp.value === void 0) internalMultiSort.value = val;
|
|
10784
|
+
options.onMultiSortChange?.(val);
|
|
10785
|
+
}
|
|
10786
|
+
});
|
|
10523
10787
|
const sortComparator = vue.computed(() => {
|
|
10524
10788
|
const s = sortState.value;
|
|
10525
10789
|
if (!s) return null;
|
|
10526
10790
|
const col = vue.toValue(options.leafColumns).find((c) => c.key === s.key);
|
|
10527
10791
|
if (!col) return null;
|
|
10528
10792
|
const dir = s.direction === "asc" ? 1 : -1;
|
|
10529
|
-
|
|
10530
|
-
return (a, b) => sorter(a, b) * dir;
|
|
10793
|
+
return (a, b) => buildSorter(col)(a, b) * dir;
|
|
10531
10794
|
});
|
|
10795
|
+
const multiSortComparator = vue.computed(
|
|
10796
|
+
() => buildMultiSortComparator(vue.toValue(options.leafColumns), multiSortState.value)
|
|
10797
|
+
);
|
|
10532
10798
|
const sortedData = vue.computed(() => {
|
|
10533
|
-
const
|
|
10534
|
-
if (!
|
|
10535
|
-
return [...data.value].sort(
|
|
10799
|
+
const comparator = multiEnabled.value ? multiSortComparator.value : sortComparator.value;
|
|
10800
|
+
if (!comparator) return data.value;
|
|
10801
|
+
return [...data.value].sort(comparator);
|
|
10536
10802
|
});
|
|
10537
10803
|
function setSort(next) {
|
|
10538
10804
|
if (sortProp.value === void 0) internalSortValue.value = next;
|
|
@@ -10549,172 +10815,1991 @@ function useTableSort(data, options) {
|
|
|
10549
10815
|
setSort({ key: col.key, direction: "desc" });
|
|
10550
10816
|
return;
|
|
10551
10817
|
}
|
|
10552
|
-
setSort(null);
|
|
10818
|
+
setSort(null);
|
|
10819
|
+
}
|
|
10820
|
+
function setMultiSort(next) {
|
|
10821
|
+
if (multiSortProp.value === void 0) internalMultiSort.value = next;
|
|
10822
|
+
options.onMultiSortChange?.(next);
|
|
10823
|
+
}
|
|
10824
|
+
function cycleMultiSort(col) {
|
|
10825
|
+
if (!col.sortable) return;
|
|
10826
|
+
const idx = multiSortState.value.findIndex((s) => s.key === col.key);
|
|
10827
|
+
if (idx < 0) {
|
|
10828
|
+
setMultiSort([...multiSortState.value, { key: col.key, direction: "asc" }]);
|
|
10829
|
+
return;
|
|
10830
|
+
}
|
|
10831
|
+
const next = [...multiSortState.value];
|
|
10832
|
+
if (next[idx].direction === "asc") {
|
|
10833
|
+
next[idx] = { key: col.key, direction: "desc" };
|
|
10834
|
+
setMultiSort(next);
|
|
10835
|
+
return;
|
|
10836
|
+
}
|
|
10837
|
+
next.splice(idx, 1);
|
|
10838
|
+
setMultiSort(next);
|
|
10839
|
+
}
|
|
10840
|
+
return {
|
|
10841
|
+
sortState,
|
|
10842
|
+
cycleSort,
|
|
10843
|
+
setSort,
|
|
10844
|
+
sortComparator,
|
|
10845
|
+
sortedData,
|
|
10846
|
+
multiSortState,
|
|
10847
|
+
cycleMultiSort,
|
|
10848
|
+
setMultiSort,
|
|
10849
|
+
multiSortComparator
|
|
10850
|
+
};
|
|
10851
|
+
}
|
|
10852
|
+
function mergeFilterValues(filters, filterValues) {
|
|
10853
|
+
const next = { ...filters };
|
|
10854
|
+
for (const [key, values] of Object.entries(filterValues)) {
|
|
10855
|
+
if (values.length > 0) next[key] = values.join(",");
|
|
10856
|
+
}
|
|
10857
|
+
return next;
|
|
10858
|
+
}
|
|
10859
|
+
function useTableProxy(options) {
|
|
10860
|
+
const cfg = vue.computed(() => vue.toValue(options.proxyConfig));
|
|
10861
|
+
const queryRef = vue.ref(void 0);
|
|
10862
|
+
vue.watch(
|
|
10863
|
+
() => cfg.value?.query,
|
|
10864
|
+
(query) => {
|
|
10865
|
+
queryRef.value = query;
|
|
10866
|
+
},
|
|
10867
|
+
{ immediate: true }
|
|
10868
|
+
);
|
|
10869
|
+
const proxy = vue.shallowRef(null);
|
|
10870
|
+
const state = vue.shallowRef({
|
|
10871
|
+
data: [],
|
|
10872
|
+
total: 0,
|
|
10873
|
+
loading: false,
|
|
10874
|
+
error: null,
|
|
10875
|
+
params: { page: 1, pageSize: 10, sort: null, filters: {} }
|
|
10876
|
+
});
|
|
10877
|
+
let unsubscribe = null;
|
|
10878
|
+
let mounted = false;
|
|
10879
|
+
const attach = (ctrl) => {
|
|
10880
|
+
unsubscribe?.();
|
|
10881
|
+
proxy.value = ctrl;
|
|
10882
|
+
state.value = ctrl.getState();
|
|
10883
|
+
unsubscribe = ctrl.subscribe((snapshot) => {
|
|
10884
|
+
state.value = snapshot;
|
|
10885
|
+
});
|
|
10886
|
+
};
|
|
10887
|
+
const detach = () => {
|
|
10888
|
+
unsubscribe?.();
|
|
10889
|
+
unsubscribe = null;
|
|
10890
|
+
proxy.value?.destroy();
|
|
10891
|
+
proxy.value = null;
|
|
10892
|
+
state.value = {
|
|
10893
|
+
data: [],
|
|
10894
|
+
total: 0,
|
|
10895
|
+
loading: false,
|
|
10896
|
+
error: null,
|
|
10897
|
+
params: { page: 1, pageSize: 10, sort: null, filters: {} }
|
|
10898
|
+
};
|
|
10899
|
+
};
|
|
10900
|
+
vue.watch(
|
|
10901
|
+
() => cfg.value === void 0,
|
|
10902
|
+
(absent) => {
|
|
10903
|
+
if (absent) {
|
|
10904
|
+
detach();
|
|
10905
|
+
return;
|
|
10906
|
+
}
|
|
10907
|
+
if (proxy.value) return;
|
|
10908
|
+
const config = cfg.value;
|
|
10909
|
+
const remoteSort = vue.toValue(options.remoteSort) === true;
|
|
10910
|
+
const remoteFilter = vue.toValue(options.remoteFilter) === true;
|
|
10911
|
+
const multiSort = vue.toValue(options.multiSort) === true;
|
|
10912
|
+
const ctrl = core.createRemoteTableSource({
|
|
10913
|
+
query: (params) => queryRef.value(params),
|
|
10914
|
+
autoLoad: false,
|
|
10915
|
+
initialParams: {
|
|
10916
|
+
page: config.defaultPage ?? 1,
|
|
10917
|
+
pageSize: config.pageSize ?? 10,
|
|
10918
|
+
sort: remoteSort ? vue.toValue(options.sort) ?? options.defaultSort ?? null : null,
|
|
10919
|
+
sorts: remoteSort && multiSort ? vue.toValue(options.multiSortState) ?? options.defaultMultiSort ?? [] : void 0,
|
|
10920
|
+
filters: remoteFilter ? mergeFilterValues(vue.toValue(options.filters) ?? {}, vue.toValue(options.filterValues) ?? {}) : {}
|
|
10921
|
+
}
|
|
10922
|
+
});
|
|
10923
|
+
attach(ctrl);
|
|
10924
|
+
if (mounted && config.autoLoad !== false) void ctrl.request();
|
|
10925
|
+
},
|
|
10926
|
+
{ immediate: true }
|
|
10927
|
+
);
|
|
10928
|
+
vue.onScopeDispose(detach);
|
|
10929
|
+
vue.onMounted(() => {
|
|
10930
|
+
mounted = true;
|
|
10931
|
+
const config = cfg.value;
|
|
10932
|
+
if (config && proxy.value && config.autoLoad !== false) void proxy.value.request();
|
|
10933
|
+
});
|
|
10934
|
+
const liveData = vue.shallowRef([]);
|
|
10935
|
+
vue.watch(
|
|
10936
|
+
state,
|
|
10937
|
+
(snapshot) => {
|
|
10938
|
+
liveData.value = snapshot.data;
|
|
10939
|
+
},
|
|
10940
|
+
{ immediate: true }
|
|
10941
|
+
);
|
|
10942
|
+
return {
|
|
10943
|
+
proxy: vue.computed(() => proxy.value),
|
|
10944
|
+
state: vue.computed(() => state.value),
|
|
10945
|
+
liveData,
|
|
10946
|
+
setParams: (partial) => proxy.value ? proxy.value.setParams(partial) : false,
|
|
10947
|
+
refetch: () => proxy.value ? proxy.value.refetch() : Promise.resolve()
|
|
10948
|
+
};
|
|
10949
|
+
}
|
|
10950
|
+
function exportCsv(rows, columns) {
|
|
10951
|
+
return core.toCsv(
|
|
10952
|
+
rows,
|
|
10953
|
+
columns.map((column) => ({
|
|
10954
|
+
key: column.key,
|
|
10955
|
+
title: column.title,
|
|
10956
|
+
dataIndex: typeof column.dataIndex === "string" ? column.dataIndex : void 0
|
|
10957
|
+
}))
|
|
10958
|
+
);
|
|
10959
|
+
}
|
|
10960
|
+
async function downloadCsv(filename, csv) {
|
|
10961
|
+
const BOM = String.fromCharCode(65279);
|
|
10962
|
+
await core.downloadFile({
|
|
10963
|
+
filename,
|
|
10964
|
+
content: BOM + csv,
|
|
10965
|
+
mimeType: "text/csv;charset=utf-8;"
|
|
10966
|
+
});
|
|
10967
|
+
}
|
|
10968
|
+
function renderFormSection(ctx) {
|
|
10969
|
+
const fc = ctx.formConfig;
|
|
10970
|
+
if (!fc) return null;
|
|
10971
|
+
return vue.h(
|
|
10972
|
+
"form",
|
|
10973
|
+
{
|
|
10974
|
+
"data-iris-table-form": "",
|
|
10975
|
+
onSubmit: (e) => {
|
|
10976
|
+
e.preventDefault();
|
|
10977
|
+
ctx.handleFormSubmit();
|
|
10978
|
+
},
|
|
10979
|
+
onReset: (e) => {
|
|
10980
|
+
e.preventDefault();
|
|
10981
|
+
ctx.handleFormReset();
|
|
10982
|
+
},
|
|
10983
|
+
style: {
|
|
10984
|
+
display: "flex",
|
|
10985
|
+
flexWrap: "wrap",
|
|
10986
|
+
alignItems: "flex-end",
|
|
10987
|
+
gap: "var(--iris-space-sm, 12px)",
|
|
10988
|
+
padding: "var(--iris-space-sm, 12px)",
|
|
10989
|
+
border: "1px solid var(--iris-border)",
|
|
10990
|
+
borderBottom: "none",
|
|
10991
|
+
background: "var(--iris-surface)",
|
|
10992
|
+
fontSize: "var(--iris-font-size-sm, 13px)"
|
|
10993
|
+
}
|
|
10994
|
+
},
|
|
10995
|
+
[
|
|
10996
|
+
...fc.fields.map(
|
|
10997
|
+
(field) => vue.h(
|
|
10998
|
+
"div",
|
|
10999
|
+
{
|
|
11000
|
+
key: field.key,
|
|
11001
|
+
"data-iris-table-form-field": field.key,
|
|
11002
|
+
style: { minWidth: 180 }
|
|
11003
|
+
},
|
|
11004
|
+
[
|
|
11005
|
+
vue.h(
|
|
11006
|
+
IrisFormField,
|
|
11007
|
+
{ label: field.label, size: "sm" },
|
|
11008
|
+
{
|
|
11009
|
+
default: () => field.type === "select" ? vue.h(IrisSelect, {
|
|
11010
|
+
items: (field.options ?? []).map((o) => ({
|
|
11011
|
+
value: o.value,
|
|
11012
|
+
label: o.label
|
|
11013
|
+
})),
|
|
11014
|
+
modelValue: ctx.formDraft.value[field.key] ?? "",
|
|
11015
|
+
placeholder: field.placeholder ?? ctx.t("select.placeholder"),
|
|
11016
|
+
size: "sm",
|
|
11017
|
+
"onUpdate:modelValue": (v) => ctx.setFormValue(field.key, String(v ?? ""))
|
|
11018
|
+
}) : vue.h(IrisInput, {
|
|
11019
|
+
modelValue: ctx.formDraft.value[field.key] ?? "",
|
|
11020
|
+
placeholder: field.placeholder,
|
|
11021
|
+
size: "sm",
|
|
11022
|
+
"onUpdate:modelValue": (v) => ctx.setFormValue(field.key, String(v ?? ""))
|
|
11023
|
+
})
|
|
11024
|
+
}
|
|
11025
|
+
)
|
|
11026
|
+
]
|
|
11027
|
+
)
|
|
11028
|
+
),
|
|
11029
|
+
vue.h("div", { style: { display: "flex", gap: "var(--iris-space-xs, 8px)" } }, [
|
|
11030
|
+
vue.h(
|
|
11031
|
+
IrisButton,
|
|
11032
|
+
{ type: "submit", size: "sm", "data-iris-table-form-submit": "" },
|
|
11033
|
+
{ default: () => fc.submitText ?? ctx.t("table.formSubmit") }
|
|
11034
|
+
),
|
|
11035
|
+
vue.h(
|
|
11036
|
+
IrisButton,
|
|
11037
|
+
{
|
|
11038
|
+
type: "reset",
|
|
11039
|
+
variant: "outline",
|
|
11040
|
+
size: "sm",
|
|
11041
|
+
"data-iris-table-form-reset": ""
|
|
11042
|
+
},
|
|
11043
|
+
{ default: () => fc.resetText ?? ctx.t("table.formReset") }
|
|
11044
|
+
)
|
|
11045
|
+
])
|
|
11046
|
+
]
|
|
11047
|
+
);
|
|
11048
|
+
}
|
|
11049
|
+
var toolbarBtnStyle = {
|
|
11050
|
+
border: "none",
|
|
11051
|
+
background: "transparent",
|
|
11052
|
+
cursor: "pointer",
|
|
11053
|
+
color: "var(--iris-muted)",
|
|
11054
|
+
fontSize: "var(--iris-font-size-md, 14px)"
|
|
11055
|
+
};
|
|
11056
|
+
function renderToolbarSection(ctx) {
|
|
11057
|
+
const tb = ctx.toolbar;
|
|
11058
|
+
if (!tb && !ctx.densityToggle) return null;
|
|
11059
|
+
const toolChildren = [];
|
|
11060
|
+
if (tb?.title) {
|
|
11061
|
+
toolChildren.push(
|
|
11062
|
+
vue.h("span", { style: { fontWeight: 600, color: "var(--iris-foreground)" } }, tb.title)
|
|
11063
|
+
);
|
|
11064
|
+
}
|
|
11065
|
+
toolChildren.push(vue.h("div", { style: { flex: "1" } }));
|
|
11066
|
+
if (tb?.onRefresh) {
|
|
11067
|
+
toolChildren.push(
|
|
11068
|
+
vue.h(
|
|
11069
|
+
"button",
|
|
11070
|
+
{
|
|
11071
|
+
type: "button",
|
|
11072
|
+
"data-iris-table-toolbar-refresh": "",
|
|
11073
|
+
"aria-label": ctx.t("table.refresh"),
|
|
11074
|
+
title: ctx.t("table.refresh"),
|
|
11075
|
+
onClick: () => {
|
|
11076
|
+
tb.onRefresh?.();
|
|
11077
|
+
void ctx.proxyCtrl.refetch();
|
|
11078
|
+
},
|
|
11079
|
+
style: toolbarBtnStyle
|
|
11080
|
+
},
|
|
11081
|
+
"\u21BB"
|
|
11082
|
+
)
|
|
11083
|
+
);
|
|
11084
|
+
}
|
|
11085
|
+
if (tb?.onExport) {
|
|
11086
|
+
toolChildren.push(
|
|
11087
|
+
vue.h(
|
|
11088
|
+
"button",
|
|
11089
|
+
{
|
|
11090
|
+
type: "button",
|
|
11091
|
+
"data-iris-table-toolbar-export": "",
|
|
11092
|
+
"aria-label": ctx.t("table.export"),
|
|
11093
|
+
title: ctx.t("table.export"),
|
|
11094
|
+
onClick: () => tb?.onExport?.(),
|
|
11095
|
+
style: toolbarBtnStyle
|
|
11096
|
+
},
|
|
11097
|
+
"\u21E9"
|
|
11098
|
+
)
|
|
11099
|
+
);
|
|
11100
|
+
}
|
|
11101
|
+
if (tb?.onImport) {
|
|
11102
|
+
toolChildren.push(
|
|
11103
|
+
vue.h("input", {
|
|
11104
|
+
ref: (el) => {
|
|
11105
|
+
ctx.importFileInput.value = el ?? null;
|
|
11106
|
+
},
|
|
11107
|
+
type: "file",
|
|
11108
|
+
accept: ".csv,text/csv",
|
|
11109
|
+
"data-iris-table-import-input": "",
|
|
11110
|
+
onChange: ctx.onImportFile,
|
|
11111
|
+
style: { display: "none" }
|
|
11112
|
+
}),
|
|
11113
|
+
vue.h(
|
|
11114
|
+
"button",
|
|
11115
|
+
{
|
|
11116
|
+
type: "button",
|
|
11117
|
+
"data-iris-table-toolbar-import": "",
|
|
11118
|
+
"aria-label": ctx.t("table.import"),
|
|
11119
|
+
title: ctx.t("table.import"),
|
|
11120
|
+
onClick: () => ctx.importFileInput.value?.click(),
|
|
11121
|
+
style: toolbarBtnStyle
|
|
11122
|
+
},
|
|
11123
|
+
"\u21EA"
|
|
11124
|
+
)
|
|
11125
|
+
);
|
|
11126
|
+
}
|
|
11127
|
+
if (tb?.batch && ctx.selectable === "multi" && ctx.displaySelection.value.length > 0) {
|
|
11128
|
+
toolChildren.push(
|
|
11129
|
+
vue.h(
|
|
11130
|
+
"button",
|
|
11131
|
+
{
|
|
11132
|
+
type: "button",
|
|
11133
|
+
"data-iris-table-toolbar-batch": "",
|
|
11134
|
+
"aria-label": tb.batch.label,
|
|
11135
|
+
title: tb.batch.label,
|
|
11136
|
+
onClick: () => tb.batch.onClick([...ctx.displaySelection.value]),
|
|
11137
|
+
style: {
|
|
11138
|
+
border: "none",
|
|
11139
|
+
cursor: "pointer",
|
|
11140
|
+
background: "var(--iris-primary)",
|
|
11141
|
+
color: "var(--iris-primary-foreground)",
|
|
11142
|
+
fontSize: "var(--iris-font-size-md, 14px)",
|
|
11143
|
+
display: "inline-flex",
|
|
11144
|
+
alignItems: "center",
|
|
11145
|
+
gap: "var(--iris-space-xxs, 4px)",
|
|
11146
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-xs, 8px)",
|
|
11147
|
+
borderRadius: "var(--iris-radius-sm, 4px)"
|
|
11148
|
+
}
|
|
11149
|
+
},
|
|
11150
|
+
[
|
|
11151
|
+
tb.batch.icon ? vue.h(
|
|
11152
|
+
"span",
|
|
11153
|
+
{ "aria-hidden": "true", style: { fontSize: "var(--iris-font-size-sm, 13px)" } },
|
|
11154
|
+
tb.batch.icon
|
|
11155
|
+
) : null,
|
|
11156
|
+
tb.batch.label
|
|
11157
|
+
]
|
|
11158
|
+
)
|
|
11159
|
+
);
|
|
11160
|
+
}
|
|
11161
|
+
if (tb?.buttons && tb.buttons.length > 0) {
|
|
11162
|
+
for (const btn of tb.buttons) {
|
|
11163
|
+
toolChildren.push(
|
|
11164
|
+
vue.h(
|
|
11165
|
+
"button",
|
|
11166
|
+
{
|
|
11167
|
+
key: btn.key,
|
|
11168
|
+
type: "button",
|
|
11169
|
+
"data-iris-table-toolbar-button": btn.key,
|
|
11170
|
+
[`data-iris-table-toolbar-button-${btn.key}`]: "",
|
|
11171
|
+
"aria-label": btn.label,
|
|
11172
|
+
title: btn.label,
|
|
11173
|
+
onClick: btn.onClick,
|
|
11174
|
+
style: {
|
|
11175
|
+
...toolbarBtnStyle,
|
|
11176
|
+
color: "var(--iris-foreground)",
|
|
11177
|
+
display: "inline-flex",
|
|
11178
|
+
alignItems: "center",
|
|
11179
|
+
gap: "var(--iris-space-xxs, 4px)",
|
|
11180
|
+
padding: "0 var(--iris-space-xxs, 4px)"
|
|
11181
|
+
}
|
|
11182
|
+
},
|
|
11183
|
+
[
|
|
11184
|
+
btn.icon ? vue.h(
|
|
11185
|
+
"span",
|
|
11186
|
+
{ "aria-hidden": "true", style: { fontSize: "var(--iris-font-size-sm, 13px)" } },
|
|
11187
|
+
btn.icon
|
|
11188
|
+
) : null,
|
|
11189
|
+
btn.label
|
|
11190
|
+
]
|
|
11191
|
+
)
|
|
11192
|
+
);
|
|
11193
|
+
}
|
|
11194
|
+
}
|
|
11195
|
+
if (ctx.densityToggle) {
|
|
11196
|
+
toolChildren.push(
|
|
11197
|
+
vue.h(
|
|
11198
|
+
"button",
|
|
11199
|
+
{
|
|
11200
|
+
type: "button",
|
|
11201
|
+
"data-iris-density-toggle": "",
|
|
11202
|
+
"data-iris-density": ctx.effectiveDensity,
|
|
11203
|
+
"aria-label": `${ctx.t("table.density")}: ${ctx.t(`table.density.${ctx.effectiveDensity}`)}`,
|
|
11204
|
+
title: `${ctx.t("table.density")}: ${ctx.t(`table.density.${ctx.effectiveDensity}`)}`,
|
|
11205
|
+
onClick: ctx.onDensityToggle,
|
|
11206
|
+
style: toolbarBtnStyle
|
|
11207
|
+
},
|
|
11208
|
+
ctx.t(`table.density.${ctx.effectiveDensity}`)
|
|
11209
|
+
)
|
|
11210
|
+
);
|
|
11211
|
+
}
|
|
11212
|
+
return vue.h(
|
|
11213
|
+
"div",
|
|
11214
|
+
{
|
|
11215
|
+
"data-iris-table-toolbar": "",
|
|
11216
|
+
style: {
|
|
11217
|
+
display: "flex",
|
|
11218
|
+
alignItems: "center",
|
|
11219
|
+
gap: "var(--iris-space-sm, 12px)",
|
|
11220
|
+
padding: "var(--iris-space-xs, 8px) var(--iris-space-sm, 12px)",
|
|
11221
|
+
border: "1px solid var(--iris-border)",
|
|
11222
|
+
borderBottom: "none",
|
|
11223
|
+
borderTopLeftRadius: "var(--iris-radius-md, 6px)",
|
|
11224
|
+
borderTopRightRadius: "var(--iris-radius-md, 6px)",
|
|
11225
|
+
background: "var(--iris-surface)",
|
|
11226
|
+
fontSize: "var(--iris-font-size-sm, 13px)"
|
|
11227
|
+
}
|
|
11228
|
+
},
|
|
11229
|
+
toolChildren
|
|
11230
|
+
);
|
|
11231
|
+
}
|
|
11232
|
+
function renderPagerSection(ctx) {
|
|
11233
|
+
if (!ctx.proxyCtrl.proxy.value) return null;
|
|
11234
|
+
const st = ctx.proxyCtrl.state.value;
|
|
11235
|
+
return vue.h(
|
|
11236
|
+
"div",
|
|
11237
|
+
{
|
|
11238
|
+
"data-iris-table-pager": "",
|
|
11239
|
+
style: {
|
|
11240
|
+
display: "flex",
|
|
11241
|
+
justifyContent: "flex-end",
|
|
11242
|
+
alignItems: "center",
|
|
11243
|
+
padding: "var(--iris-space-xs, 8px) var(--iris-space-sm, 12px)",
|
|
11244
|
+
borderTop: "1px solid var(--iris-border)",
|
|
11245
|
+
background: "var(--iris-surface)"
|
|
11246
|
+
}
|
|
11247
|
+
},
|
|
11248
|
+
[
|
|
11249
|
+
vue.h(IrisPagination, {
|
|
11250
|
+
modelValue: st.params.page,
|
|
11251
|
+
total: st.total,
|
|
11252
|
+
pageSize: st.params.pageSize,
|
|
11253
|
+
size: "sm",
|
|
11254
|
+
"onUpdate:modelValue": (page) => {
|
|
11255
|
+
ctx.proxyCtrl.setParams({ page });
|
|
11256
|
+
ctx.proxyConfig?.onPageChange?.(page, ctx.proxyCtrl.state.value.params.pageSize);
|
|
11257
|
+
}
|
|
11258
|
+
})
|
|
11259
|
+
]
|
|
11260
|
+
);
|
|
11261
|
+
}
|
|
11262
|
+
function renderContextMenuSection(ctx) {
|
|
11263
|
+
const st = ctx.state.value;
|
|
11264
|
+
if (!st || !st.open) return null;
|
|
11265
|
+
const node = vue.h(
|
|
11266
|
+
"div",
|
|
11267
|
+
{
|
|
11268
|
+
ref: (el) => {
|
|
11269
|
+
ctx.menuRef.value = el ?? null;
|
|
11270
|
+
},
|
|
11271
|
+
role: "menu",
|
|
11272
|
+
"data-iris-table-context-menu": "",
|
|
11273
|
+
style: {
|
|
11274
|
+
...ctx.styles.value,
|
|
11275
|
+
zIndex: "var(--iris-z-popover, 1000)",
|
|
11276
|
+
background: "var(--iris-surface-floating, var(--iris-surface))",
|
|
11277
|
+
color: "var(--iris-foreground)",
|
|
11278
|
+
border: "1px solid var(--iris-border)",
|
|
11279
|
+
borderRadius: "var(--iris-radius-md, 6px)",
|
|
11280
|
+
boxShadow: "var(--iris-shadow-lg)",
|
|
11281
|
+
padding: "var(--iris-space-xxs, 4px)",
|
|
11282
|
+
minWidth: "160px",
|
|
11283
|
+
display: "flex",
|
|
11284
|
+
flexDirection: "column"
|
|
11285
|
+
}
|
|
11286
|
+
},
|
|
11287
|
+
st.items.map(
|
|
11288
|
+
(item) => vue.h(
|
|
11289
|
+
"button",
|
|
11290
|
+
{
|
|
11291
|
+
key: item.key,
|
|
11292
|
+
type: "button",
|
|
11293
|
+
role: "menuitem",
|
|
11294
|
+
"data-iris-table-context-menu-item": item.key,
|
|
11295
|
+
disabled: item.disabled,
|
|
11296
|
+
"aria-disabled": item.disabled ? "true" : void 0,
|
|
11297
|
+
onClick: () => {
|
|
11298
|
+
ctx.contextMenu.onSelect(item.key, st.params);
|
|
11299
|
+
ctx.close();
|
|
11300
|
+
},
|
|
11301
|
+
style: {
|
|
11302
|
+
border: "none",
|
|
11303
|
+
background: "transparent",
|
|
11304
|
+
cursor: item.disabled ? "default" : "pointer",
|
|
11305
|
+
color: item.disabled ? "var(--iris-muted)" : "var(--iris-foreground)",
|
|
11306
|
+
font: "inherit",
|
|
11307
|
+
textAlign: "start",
|
|
11308
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-sm, 12px)",
|
|
11309
|
+
borderRadius: "var(--iris-radius-sm, 4px)"
|
|
11310
|
+
}
|
|
11311
|
+
},
|
|
11312
|
+
item.label
|
|
11313
|
+
)
|
|
11314
|
+
)
|
|
11315
|
+
);
|
|
11316
|
+
return vue.h(vue.Teleport, { to: "body" }, [node]);
|
|
11317
|
+
}
|
|
11318
|
+
function renderFilterPanelSection(ctx) {
|
|
11319
|
+
const st = ctx.state.value;
|
|
11320
|
+
if (!st || !st.open) return null;
|
|
11321
|
+
const col = ctx.columns.find((c) => c.key === st.colKey);
|
|
11322
|
+
if (!col || !col.filterable) return null;
|
|
11323
|
+
const options = col.filterOptions ?? [];
|
|
11324
|
+
const node = vue.h(
|
|
11325
|
+
"div",
|
|
11326
|
+
{
|
|
11327
|
+
ref: (el) => {
|
|
11328
|
+
ctx.panelRef.value = el ?? null;
|
|
11329
|
+
},
|
|
11330
|
+
role: "dialog",
|
|
11331
|
+
"aria-label": ctx.t("table.filter"),
|
|
11332
|
+
"data-iris-table-filter-panel": "",
|
|
11333
|
+
"data-iris-table-filter-column": st.colKey,
|
|
11334
|
+
style: {
|
|
11335
|
+
...ctx.styles.value,
|
|
11336
|
+
zIndex: "var(--iris-z-popover, 1000)",
|
|
11337
|
+
background: "var(--iris-surface-floating, var(--iris-surface))",
|
|
11338
|
+
color: "var(--iris-foreground)",
|
|
11339
|
+
border: "1px solid var(--iris-border)",
|
|
11340
|
+
borderRadius: "var(--iris-radius-md, 6px)",
|
|
11341
|
+
boxShadow: "var(--iris-shadow-lg)",
|
|
11342
|
+
padding: "var(--iris-space-sm, 12px)",
|
|
11343
|
+
minWidth: "180px",
|
|
11344
|
+
display: "flex",
|
|
11345
|
+
flexDirection: "column",
|
|
11346
|
+
gap: "var(--iris-space-xxs, 4px)"
|
|
11347
|
+
}
|
|
11348
|
+
},
|
|
11349
|
+
[
|
|
11350
|
+
...options.map(
|
|
11351
|
+
(opt) => vue.h(
|
|
11352
|
+
"div",
|
|
11353
|
+
{
|
|
11354
|
+
key: opt.value,
|
|
11355
|
+
"data-iris-filter-option": opt.value,
|
|
11356
|
+
style: { display: "flex", alignItems: "center" }
|
|
11357
|
+
},
|
|
11358
|
+
[
|
|
11359
|
+
vue.h(
|
|
11360
|
+
IrisCheckbox,
|
|
11361
|
+
{
|
|
11362
|
+
modelValue: ctx.filterDraft.value.includes(opt.value),
|
|
11363
|
+
size: "sm",
|
|
11364
|
+
"onUpdate:modelValue": () => ctx.toggle(opt.value)
|
|
11365
|
+
},
|
|
11366
|
+
{ default: () => opt.label }
|
|
11367
|
+
)
|
|
11368
|
+
]
|
|
11369
|
+
)
|
|
11370
|
+
),
|
|
11371
|
+
vue.h(
|
|
11372
|
+
"div",
|
|
11373
|
+
{
|
|
11374
|
+
style: {
|
|
11375
|
+
display: "flex",
|
|
11376
|
+
justifyContent: "flex-end",
|
|
11377
|
+
gap: "var(--iris-space-xs, 8px)",
|
|
11378
|
+
marginTop: "var(--iris-space-xs, 8px)"
|
|
11379
|
+
}
|
|
11380
|
+
},
|
|
11381
|
+
[
|
|
11382
|
+
vue.h(
|
|
11383
|
+
"button",
|
|
11384
|
+
{
|
|
11385
|
+
type: "button",
|
|
11386
|
+
"data-iris-filter-clear": "",
|
|
11387
|
+
onClick: () => {
|
|
11388
|
+
ctx.clear(st.colKey);
|
|
11389
|
+
ctx.close();
|
|
11390
|
+
},
|
|
11391
|
+
style: {
|
|
11392
|
+
border: "1px solid var(--iris-border)",
|
|
11393
|
+
background: "transparent",
|
|
11394
|
+
color: "var(--iris-foreground)",
|
|
11395
|
+
cursor: "pointer",
|
|
11396
|
+
font: "inherit",
|
|
11397
|
+
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
11398
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-sm, 12px)",
|
|
11399
|
+
borderRadius: "var(--iris-radius-sm, 4px)"
|
|
11400
|
+
}
|
|
11401
|
+
},
|
|
11402
|
+
ctx.t("table.filterClear")
|
|
11403
|
+
),
|
|
11404
|
+
vue.h(
|
|
11405
|
+
"button",
|
|
11406
|
+
{
|
|
11407
|
+
type: "button",
|
|
11408
|
+
"data-iris-filter-confirm": "",
|
|
11409
|
+
onClick: () => {
|
|
11410
|
+
ctx.apply(st.colKey, ctx.filterDraft.value);
|
|
11411
|
+
ctx.close();
|
|
11412
|
+
},
|
|
11413
|
+
style: {
|
|
11414
|
+
border: "1px solid var(--iris-primary)",
|
|
11415
|
+
background: "var(--iris-primary)",
|
|
11416
|
+
color: "var(--iris-primary-foreground, #fff)",
|
|
11417
|
+
cursor: "pointer",
|
|
11418
|
+
font: "inherit",
|
|
11419
|
+
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
11420
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-sm, 12px)",
|
|
11421
|
+
borderRadius: "var(--iris-radius-sm, 4px)"
|
|
11422
|
+
}
|
|
11423
|
+
},
|
|
11424
|
+
ctx.t("table.filterConfirm")
|
|
11425
|
+
)
|
|
11426
|
+
]
|
|
11427
|
+
)
|
|
11428
|
+
]
|
|
11429
|
+
);
|
|
11430
|
+
return vue.h(vue.Teleport, { to: "body" }, [node]);
|
|
11431
|
+
}
|
|
11432
|
+
function renderImportPreviewSection(ctx) {
|
|
11433
|
+
if (!ctx.rows) return null;
|
|
11434
|
+
const columns = core.previewColumnsFromRows(ctx.rows);
|
|
11435
|
+
const cellStyle = {
|
|
11436
|
+
border: "1px solid var(--iris-border)",
|
|
11437
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-xs, 8px)",
|
|
11438
|
+
whiteSpace: "nowrap"
|
|
11439
|
+
};
|
|
11440
|
+
const table = columns.length ? vue.h(
|
|
11441
|
+
"table",
|
|
11442
|
+
{
|
|
11443
|
+
"data-iris-import-preview-table": "",
|
|
11444
|
+
style: { borderCollapse: "collapse", fontSize: "var(--iris-font-size-sm, 13px)" }
|
|
11445
|
+
},
|
|
11446
|
+
[
|
|
11447
|
+
vue.h("thead", [
|
|
11448
|
+
vue.h(
|
|
11449
|
+
"tr",
|
|
11450
|
+
columns.map(
|
|
11451
|
+
(column) => vue.h(
|
|
11452
|
+
"th",
|
|
11453
|
+
{
|
|
11454
|
+
key: column,
|
|
11455
|
+
"data-iris-import-preview-header": column,
|
|
11456
|
+
style: {
|
|
11457
|
+
...cellStyle,
|
|
11458
|
+
background: "var(--iris-surface)",
|
|
11459
|
+
color: "var(--iris-foreground)",
|
|
11460
|
+
textAlign: "start",
|
|
11461
|
+
fontWeight: 600
|
|
11462
|
+
}
|
|
11463
|
+
},
|
|
11464
|
+
column
|
|
11465
|
+
)
|
|
11466
|
+
)
|
|
11467
|
+
)
|
|
11468
|
+
]),
|
|
11469
|
+
vue.h(
|
|
11470
|
+
"tbody",
|
|
11471
|
+
ctx.rows.slice(0, 5).map(
|
|
11472
|
+
(row, rowIndex) => vue.h(
|
|
11473
|
+
"tr",
|
|
11474
|
+
{ key: rowIndex },
|
|
11475
|
+
columns.map(
|
|
11476
|
+
(column) => vue.h(
|
|
11477
|
+
"td",
|
|
11478
|
+
{
|
|
11479
|
+
key: column,
|
|
11480
|
+
"data-iris-import-preview-cell": `${rowIndex}:${column}`,
|
|
11481
|
+
style: { ...cellStyle, color: "var(--iris-foreground)" }
|
|
11482
|
+
},
|
|
11483
|
+
String(row[column] ?? "")
|
|
11484
|
+
)
|
|
11485
|
+
)
|
|
11486
|
+
)
|
|
11487
|
+
)
|
|
11488
|
+
)
|
|
11489
|
+
]
|
|
11490
|
+
) : null;
|
|
11491
|
+
const node = vue.h(
|
|
11492
|
+
"div",
|
|
11493
|
+
{
|
|
11494
|
+
"data-iris-import-preview-backdrop": "",
|
|
11495
|
+
onPointerdown: (event) => {
|
|
11496
|
+
if (event.target === event.currentTarget) ctx.onCancel();
|
|
11497
|
+
},
|
|
11498
|
+
style: {
|
|
11499
|
+
position: "fixed",
|
|
11500
|
+
inset: 0,
|
|
11501
|
+
background: "var(--iris-backdrop, rgba(0, 0, 0, 0.5))",
|
|
11502
|
+
zIndex: "var(--iris-z-modal, 1200)",
|
|
11503
|
+
display: "flex",
|
|
11504
|
+
alignItems: "center",
|
|
11505
|
+
justifyContent: "center",
|
|
11506
|
+
padding: "var(--iris-space-lg, 24px)"
|
|
11507
|
+
}
|
|
11508
|
+
},
|
|
11509
|
+
[
|
|
11510
|
+
vue.h(
|
|
11511
|
+
"div",
|
|
11512
|
+
{
|
|
11513
|
+
"data-iris-import-preview": "",
|
|
11514
|
+
role: "dialog",
|
|
11515
|
+
"aria-modal": "true",
|
|
11516
|
+
"aria-label": ctx.t("table.importPreview.title"),
|
|
11517
|
+
style: {
|
|
11518
|
+
background: "var(--iris-surface-floating, var(--iris-surface))",
|
|
11519
|
+
color: "var(--iris-foreground)",
|
|
11520
|
+
border: "1px solid var(--iris-border)",
|
|
11521
|
+
borderRadius: "var(--iris-radius-lg, 8px)",
|
|
11522
|
+
boxShadow: "var(--iris-shadow-xl)",
|
|
11523
|
+
padding: "var(--iris-space-lg, 24px)",
|
|
11524
|
+
maxWidth: "90vw",
|
|
11525
|
+
maxHeight: "85vh",
|
|
11526
|
+
overflow: "auto",
|
|
11527
|
+
display: "flex",
|
|
11528
|
+
flexDirection: "column",
|
|
11529
|
+
gap: "var(--iris-space-sm, 12px)",
|
|
11530
|
+
fontSize: "var(--iris-font-size-md, 14px)"
|
|
11531
|
+
}
|
|
11532
|
+
},
|
|
11533
|
+
[
|
|
11534
|
+
vue.h("div", { style: { fontWeight: 600 } }, ctx.t("table.importPreview.title")),
|
|
11535
|
+
table,
|
|
11536
|
+
ctx.rows.length > 5 ? vue.h(
|
|
11537
|
+
"div",
|
|
11538
|
+
{
|
|
11539
|
+
"data-iris-import-preview-total": "",
|
|
11540
|
+
style: { color: "var(--iris-muted)", fontSize: "var(--iris-font-size-xs, 12px)" }
|
|
11541
|
+
},
|
|
11542
|
+
ctx.t("table.total", { total: ctx.rows.length })
|
|
11543
|
+
) : null,
|
|
11544
|
+
vue.h(
|
|
11545
|
+
"div",
|
|
11546
|
+
{
|
|
11547
|
+
style: {
|
|
11548
|
+
display: "flex",
|
|
11549
|
+
justifyContent: "flex-end",
|
|
11550
|
+
gap: "var(--iris-space-xs, 8px)"
|
|
11551
|
+
}
|
|
11552
|
+
},
|
|
11553
|
+
[
|
|
11554
|
+
vue.h(
|
|
11555
|
+
"button",
|
|
11556
|
+
{
|
|
11557
|
+
type: "button",
|
|
11558
|
+
"data-iris-import-preview-cancel": "",
|
|
11559
|
+
onClick: ctx.onCancel,
|
|
11560
|
+
style: {
|
|
11561
|
+
border: "1px solid var(--iris-border)",
|
|
11562
|
+
cursor: "pointer",
|
|
11563
|
+
background: "var(--iris-surface)",
|
|
11564
|
+
color: "var(--iris-foreground)",
|
|
11565
|
+
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
11566
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-xs, 8px)",
|
|
11567
|
+
borderRadius: "var(--iris-radius-sm, 4px)"
|
|
11568
|
+
}
|
|
11569
|
+
},
|
|
11570
|
+
ctx.t("table.importPreview.cancel")
|
|
11571
|
+
),
|
|
11572
|
+
vue.h(
|
|
11573
|
+
"button",
|
|
11574
|
+
{
|
|
11575
|
+
type: "button",
|
|
11576
|
+
"data-iris-import-preview-confirm": "",
|
|
11577
|
+
onClick: ctx.onConfirm,
|
|
11578
|
+
style: {
|
|
11579
|
+
border: "none",
|
|
11580
|
+
cursor: "pointer",
|
|
11581
|
+
background: "var(--iris-primary)",
|
|
11582
|
+
color: "var(--iris-primary-foreground)",
|
|
11583
|
+
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
11584
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-xs, 8px)",
|
|
11585
|
+
borderRadius: "var(--iris-radius-sm, 4px)"
|
|
11586
|
+
}
|
|
11587
|
+
},
|
|
11588
|
+
ctx.t("table.importPreview.confirm")
|
|
11589
|
+
)
|
|
11590
|
+
]
|
|
11591
|
+
)
|
|
11592
|
+
]
|
|
11593
|
+
)
|
|
11594
|
+
]
|
|
11595
|
+
);
|
|
11596
|
+
return vue.h(vue.Teleport, { to: "body" }, [node]);
|
|
11597
|
+
}
|
|
11598
|
+
function renderTableSummaryRow(ctx) {
|
|
11599
|
+
if (ctx.bodyData.length === 0 || !ctx.leafColumns.some((column) => column.summary)) return null;
|
|
11600
|
+
const summaryCells = [...ctx.leadingCells];
|
|
11601
|
+
for (let columnIndex = 0; columnIndex < ctx.leafColumns.length; columnIndex += 1) {
|
|
11602
|
+
const column = ctx.leafColumns[columnIndex];
|
|
11603
|
+
if (ctx.visibleColSet && !ctx.visibleColSet.has(columnIndex)) continue;
|
|
11604
|
+
const align = column.align ?? "left";
|
|
11605
|
+
const operation = column.summary;
|
|
11606
|
+
const value = operation ? core.aggregate(ctx.bodyData, (row) => ctx.getCellValue(row, column), operation) : null;
|
|
11607
|
+
const content = operation != null && value != null ? column.renderSummary ? column.renderSummary(value, ctx.bodyData) : String(value) : "";
|
|
11608
|
+
summaryCells.push(
|
|
11609
|
+
vue.h(
|
|
11610
|
+
"div",
|
|
11611
|
+
{
|
|
11612
|
+
key: column.key,
|
|
11613
|
+
role: "cell",
|
|
11614
|
+
"data-iris-table-cell": column.key,
|
|
11615
|
+
"data-iris-table-summary-cell": operation ? "" : void 0,
|
|
11616
|
+
"data-iris-table-pinned": column.pinned,
|
|
11617
|
+
style: {
|
|
11618
|
+
display: "flex",
|
|
11619
|
+
alignItems: "center",
|
|
11620
|
+
justifyContent: align === "right" ? "flex-end" : align === "center" ? "center" : "flex-start",
|
|
11621
|
+
padding: "var(--iris-space-xs, 8px) var(--iris-padding-md)",
|
|
11622
|
+
fontSize: "var(--iris-font-size-md, 14px)",
|
|
11623
|
+
whiteSpace: "nowrap",
|
|
11624
|
+
overflow: "hidden",
|
|
11625
|
+
textOverflow: "ellipsis",
|
|
11626
|
+
...ctx.visibleColSet ? { gridColumnStart: String(ctx.colTrack(columnIndex)) } : {},
|
|
11627
|
+
...ctx.pinnedStyle(column.key)
|
|
11628
|
+
}
|
|
11629
|
+
},
|
|
11630
|
+
content
|
|
11631
|
+
)
|
|
11632
|
+
);
|
|
11633
|
+
}
|
|
11634
|
+
return vue.h(
|
|
11635
|
+
"div",
|
|
11636
|
+
{
|
|
11637
|
+
role: "row",
|
|
11638
|
+
"data-iris-table-row": "summary",
|
|
11639
|
+
style: {
|
|
11640
|
+
display: "grid",
|
|
11641
|
+
gridTemplateColumns: ctx.gridTemplate,
|
|
11642
|
+
fontWeight: "600",
|
|
11643
|
+
borderTop: "2px solid var(--iris-border)",
|
|
11644
|
+
background: "var(--iris-surface)"
|
|
11645
|
+
}
|
|
11646
|
+
},
|
|
11647
|
+
summaryCells
|
|
11648
|
+
);
|
|
11649
|
+
}
|
|
11650
|
+
function renderTableStateRow(ctx) {
|
|
11651
|
+
if (ctx.error) {
|
|
11652
|
+
return vue.h("div", { role: "row", "data-iris-table-row": "error", style: ctx.stateRowStyle }, [
|
|
11653
|
+
vue.h(
|
|
11654
|
+
"span",
|
|
11655
|
+
{ style: { marginInlineEnd: ctx.onRetry ? "var(--iris-space-sm, 12px)" : "0px" } },
|
|
11656
|
+
ctx.errorContent ?? ""
|
|
11657
|
+
),
|
|
11658
|
+
ctx.retry ? vue.h(
|
|
11659
|
+
"button",
|
|
11660
|
+
{
|
|
11661
|
+
type: "button",
|
|
11662
|
+
"data-iris-table-retry": "",
|
|
11663
|
+
onClick: ctx.retry,
|
|
11664
|
+
style: {
|
|
11665
|
+
border: "1px solid var(--iris-border)",
|
|
11666
|
+
background: "var(--iris-surface)",
|
|
11667
|
+
color: "var(--iris-foreground)",
|
|
11668
|
+
borderRadius: "var(--iris-radius-sm, 4px)",
|
|
11669
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-xs, 8px)",
|
|
11670
|
+
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
11671
|
+
cursor: "pointer"
|
|
11672
|
+
}
|
|
11673
|
+
},
|
|
11674
|
+
ctx.retryLabel
|
|
11675
|
+
) : null
|
|
11676
|
+
]);
|
|
11677
|
+
}
|
|
11678
|
+
if (ctx.loading) {
|
|
11679
|
+
return vue.h(
|
|
11680
|
+
"div",
|
|
11681
|
+
{
|
|
11682
|
+
role: "row",
|
|
11683
|
+
"aria-busy": "true",
|
|
11684
|
+
"data-iris-table-row": "loading",
|
|
11685
|
+
style: ctx.stateRowStyle
|
|
11686
|
+
},
|
|
11687
|
+
ctx.loadingContent ?? ""
|
|
11688
|
+
);
|
|
11689
|
+
}
|
|
11690
|
+
if (ctx.rowCount === 0) {
|
|
11691
|
+
return vue.h(
|
|
11692
|
+
"div",
|
|
11693
|
+
{ role: "row", "data-iris-table-row": "empty", style: ctx.stateRowStyle },
|
|
11694
|
+
ctx.emptyContent ?? ""
|
|
11695
|
+
);
|
|
11696
|
+
}
|
|
11697
|
+
return null;
|
|
11698
|
+
}
|
|
11699
|
+
function createTableKeyboard(options) {
|
|
11700
|
+
const gridKeys = /* @__PURE__ */ new Set([
|
|
11701
|
+
"ArrowUp",
|
|
11702
|
+
"ArrowDown",
|
|
11703
|
+
"ArrowLeft",
|
|
11704
|
+
"ArrowRight",
|
|
11705
|
+
"Home",
|
|
11706
|
+
"End",
|
|
11707
|
+
"PageUp",
|
|
11708
|
+
"PageDown"
|
|
11709
|
+
]);
|
|
11710
|
+
const handleGridKey = (event) => {
|
|
11711
|
+
if (!options.keyboardNavigation() || !gridKeys.has(event.key)) return;
|
|
11712
|
+
const target = event.target;
|
|
11713
|
+
if (target.dataset.gridRow === void 0) return;
|
|
11714
|
+
event.preventDefault();
|
|
11715
|
+
const next = core.nextGridCell(
|
|
11716
|
+
options.focused.value ?? { row: 0, col: 0 },
|
|
11717
|
+
event.key,
|
|
11718
|
+
{ rowCount: options.rows().length, colCount: options.columns().length, pageSize: 10 }
|
|
11719
|
+
);
|
|
11720
|
+
options.focused.value = next;
|
|
11721
|
+
options.root()?.querySelector(`[data-grid-row="${next.row}"][data-grid-col="${next.col}"]`)?.focus();
|
|
11722
|
+
};
|
|
11723
|
+
const handleCellRangeKey = (event) => {
|
|
11724
|
+
if (!options.cellRange()) return;
|
|
11725
|
+
if (event.key === "Escape") {
|
|
11726
|
+
options.range.clearRange();
|
|
11727
|
+
return;
|
|
11728
|
+
}
|
|
11729
|
+
const arrows = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"]);
|
|
11730
|
+
if (!event.shiftKey || !arrows.has(event.key)) return;
|
|
11731
|
+
const target = event.target;
|
|
11732
|
+
const row = target.dataset.irisCellRow;
|
|
11733
|
+
const col = target.dataset.irisCellCol;
|
|
11734
|
+
if (row === void 0 || col === void 0) return;
|
|
11735
|
+
event.preventDefault();
|
|
11736
|
+
const current = options.range.getState().active ?? { row: Number(row), col: Number(col) };
|
|
11737
|
+
const nextRow = event.key === "ArrowUp" ? Math.max(0, current.row - 1) : event.key === "ArrowDown" ? Math.min(options.rows().length - 1, current.row + 1) : current.row;
|
|
11738
|
+
const nextCol = event.key === "ArrowLeft" ? Math.max(0, current.col - 1) : event.key === "ArrowRight" ? Math.min(options.columns().length - 1, current.col + 1) : current.col;
|
|
11739
|
+
options.range.extendRange(nextRow, nextCol);
|
|
11740
|
+
};
|
|
11741
|
+
const isInRange = (row, col) => {
|
|
11742
|
+
const { anchor, active } = options.rangeState.value;
|
|
11743
|
+
return Boolean(
|
|
11744
|
+
anchor && active && row >= Math.min(anchor.row, active.row) && row <= Math.max(anchor.row, active.row) && col >= Math.min(anchor.col, active.col) && col <= Math.max(anchor.col, active.col)
|
|
11745
|
+
);
|
|
11746
|
+
};
|
|
11747
|
+
const activeCellRange = () => {
|
|
11748
|
+
const { anchor, active } = options.rangeState.value;
|
|
11749
|
+
if (!anchor || !active) return null;
|
|
11750
|
+
return {
|
|
11751
|
+
start: { row: Math.min(anchor.row, active.row), col: Math.min(anchor.col, active.col) },
|
|
11752
|
+
end: { row: Math.max(anchor.row, active.row), col: Math.max(anchor.col, active.col) }
|
|
11753
|
+
};
|
|
11754
|
+
};
|
|
11755
|
+
const copyActiveRange = () => {
|
|
11756
|
+
const range = activeCellRange();
|
|
11757
|
+
const clip = options.clipConfig();
|
|
11758
|
+
if (!range || clip?.copy === false) return;
|
|
11759
|
+
void core.writeClipboardText(
|
|
11760
|
+
core.serializeTableRange(
|
|
11761
|
+
options.rows(),
|
|
11762
|
+
options.columns(),
|
|
11763
|
+
range,
|
|
11764
|
+
clip?.copyFormat,
|
|
11765
|
+
clip?.copyWithFormat === true
|
|
11766
|
+
)
|
|
11767
|
+
);
|
|
11768
|
+
};
|
|
11769
|
+
const handleClipboardKey = (event) => {
|
|
11770
|
+
const clip = options.clipConfig();
|
|
11771
|
+
if (!options.cellRange() || !clip || event.defaultPrevented) return;
|
|
11772
|
+
if (event.key.toLowerCase() !== "c" || !event.ctrlKey && !event.metaKey) return;
|
|
11773
|
+
if (clip.copy === false || !activeCellRange()) return;
|
|
11774
|
+
event.preventDefault();
|
|
11775
|
+
copyActiveRange();
|
|
11776
|
+
};
|
|
11777
|
+
return {
|
|
11778
|
+
handleRootKeyDown: (event) => {
|
|
11779
|
+
handleGridKey(event);
|
|
11780
|
+
handleCellRangeKey(event);
|
|
11781
|
+
handleClipboardKey(event);
|
|
11782
|
+
},
|
|
11783
|
+
isInRange,
|
|
11784
|
+
activeCellRange,
|
|
11785
|
+
copyActiveRange
|
|
11786
|
+
};
|
|
11787
|
+
}
|
|
11788
|
+
function computeResponsiveTableColumns(columns, containerWidth, leadingWidth, widthOf) {
|
|
11789
|
+
if (containerWidth <= 0 || containerWidth >= core.RESPONSIVE_NARROW_WIDTH) {
|
|
11790
|
+
return { columns, overflow: false };
|
|
11791
|
+
}
|
|
11792
|
+
const isPinned = (column) => column.children && column.children.length > 0 ? column.children.some(isPinned) : column.pinned !== void 0;
|
|
11793
|
+
const fitted = core.computeResponsiveColumns(columns, Math.max(1, containerWidth - leadingWidth), {
|
|
11794
|
+
widthOf: (column) => widthOf(column),
|
|
11795
|
+
isPinned: (column) => isPinned(column),
|
|
11796
|
+
narrowWidth: core.RESPONSIVE_NARROW_WIDTH - leadingWidth
|
|
11797
|
+
});
|
|
11798
|
+
const natural = fitted.reduce(
|
|
11799
|
+
(sum, column) => sum + (column.children && column.children.length > 0 ? core.flattenLeafColumns([column]).reduce((nested, leaf) => nested + widthOf(leaf), 0) : widthOf(column)),
|
|
11800
|
+
leadingWidth
|
|
11801
|
+
);
|
|
11802
|
+
return { columns: fitted, overflow: natural > containerWidth };
|
|
11803
|
+
}
|
|
11804
|
+
|
|
11805
|
+
// src/primitives/table/table-styles.ts
|
|
11806
|
+
var TABLE_STYLE_ID = "iris-table-row-styles";
|
|
11807
|
+
var TABLE_STYLES = `
|
|
11808
|
+
[data-iris-table] [role="row"]:hover {
|
|
11809
|
+
--iris-cell-bg: var(--iris-surface-hover);
|
|
11810
|
+
}
|
|
11811
|
+
[data-iris-table-row-selected="true"] {
|
|
11812
|
+
--iris-cell-bg: var(--iris-surface-selected);
|
|
11813
|
+
}
|
|
11814
|
+
@media print { [data-iris-table-tabs], [data-iris-table-toolbar], [data-iris-table-form], [data-iris-scroll-hint] { display: none !important; } [data-iris-table][data-printable="true"] { border: none !important; box-shadow: var(--iris-shadow-none, none) !important; } }
|
|
11815
|
+
[data-iris-table][data-density="compact"] [data-iris-table-cell],
|
|
11816
|
+
[data-iris-table][data-density="compact"] [data-iris-table-header],
|
|
11817
|
+
[data-iris-table][data-density="compact"] [data-iris-table-summary-cell],
|
|
11818
|
+
[data-iris-table][data-density="compact"] [data-iris-table-footer-cell] { padding-block: 6px !important; }
|
|
11819
|
+
[data-iris-table][data-density="cozy"] [data-iris-table-cell],
|
|
11820
|
+
[data-iris-table][data-density="cozy"] [data-iris-table-header],
|
|
11821
|
+
[data-iris-table][data-density="cozy"] [data-iris-table-summary-cell],
|
|
11822
|
+
[data-iris-table][data-density="cozy"] [data-iris-table-footer-cell] { padding-block: 4px !important; }
|
|
11823
|
+
[data-iris-row-target="true"] {
|
|
11824
|
+
--iris-cell-bg: color-mix(in srgb, var(--iris-primary) 18%, var(--iris-background));
|
|
11825
|
+
background: color-mix(in srgb, var(--iris-primary) 18%, var(--iris-background));
|
|
11826
|
+
}
|
|
11827
|
+
`;
|
|
11828
|
+
function ensureTableStyles() {
|
|
11829
|
+
if (typeof document === "undefined" || document.getElementById(TABLE_STYLE_ID)) return;
|
|
11830
|
+
const style = document.createElement("style");
|
|
11831
|
+
style.id = TABLE_STYLE_ID;
|
|
11832
|
+
style.textContent = TABLE_STYLES;
|
|
11833
|
+
document.head.appendChild(style);
|
|
11834
|
+
}
|
|
11835
|
+
|
|
11836
|
+
// src/primitives/table/table-columns.ts
|
|
11837
|
+
function applyDetectedTableTypes(columns, detectedTypes) {
|
|
11838
|
+
const apply = (column) => {
|
|
11839
|
+
const kind = detectedTypes[column.key];
|
|
11840
|
+
const next = kind ? {
|
|
11841
|
+
...column,
|
|
11842
|
+
...kind === "number" ? column.align === void 0 ? { align: "right" } : null : column.align === void 0 ? { align: "left" } : null
|
|
11843
|
+
} : column;
|
|
11844
|
+
return next.children && next.children.length > 0 ? { ...next, children: next.children.map(apply) } : next;
|
|
11845
|
+
};
|
|
11846
|
+
return columns.map(apply);
|
|
11847
|
+
}
|
|
11848
|
+
function renderTableFilterTrigger(options) {
|
|
11849
|
+
const { column, leaf, active, open, label, onOpen } = options;
|
|
11850
|
+
if (!leaf || !column.filterable) return null;
|
|
11851
|
+
return vue.h(
|
|
11852
|
+
"button",
|
|
11853
|
+
{
|
|
11854
|
+
type: "button",
|
|
11855
|
+
"data-iris-filter-trigger": column.key,
|
|
11856
|
+
"aria-label": label,
|
|
11857
|
+
"aria-haspopup": "true",
|
|
11858
|
+
"aria-expanded": open ? "true" : void 0,
|
|
11859
|
+
"data-iris-filter-active": active ? "true" : void 0,
|
|
11860
|
+
onClick: (event) => onOpen(event, column.key),
|
|
11861
|
+
onKeydown: (event) => event.stopPropagation(),
|
|
11862
|
+
style: {
|
|
11863
|
+
border: "none",
|
|
11864
|
+
background: "transparent",
|
|
11865
|
+
cursor: "pointer",
|
|
11866
|
+
padding: "0",
|
|
11867
|
+
marginInlineStart: "var(--iris-space-xxs, 4px)",
|
|
11868
|
+
fontSize: "var(--iris-font-size-xs, 12px)",
|
|
11869
|
+
lineHeight: "1",
|
|
11870
|
+
color: active ? "var(--iris-primary)" : "var(--iris-muted)"
|
|
11871
|
+
}
|
|
11872
|
+
},
|
|
11873
|
+
"\u23F7"
|
|
11874
|
+
);
|
|
11875
|
+
}
|
|
11876
|
+
function renderTableSortIndicator(column, options) {
|
|
11877
|
+
if (!column.sortable) return null;
|
|
11878
|
+
const state = options.multiSort ? options.multiSortState.find((item) => item.key === column.key) ?? null : options.sort;
|
|
11879
|
+
const isActive = state?.key === column.key;
|
|
11880
|
+
const direction = isActive ? state.direction : null;
|
|
11881
|
+
const color = isActive ? "var(--iris-primary)" : "var(--iris-muted)";
|
|
11882
|
+
return vue.h(
|
|
11883
|
+
"span",
|
|
11884
|
+
{
|
|
11885
|
+
"aria-hidden": "true",
|
|
11886
|
+
style: {
|
|
11887
|
+
display: "inline-flex",
|
|
11888
|
+
flexDirection: "column",
|
|
11889
|
+
marginInlineStart: "var(--iris-space-xxs, 4px)",
|
|
11890
|
+
lineHeight: "0.6",
|
|
11891
|
+
fontSize: "var(--iris-font-size-xs, 12px)",
|
|
11892
|
+
color
|
|
11893
|
+
}
|
|
11894
|
+
},
|
|
11895
|
+
[
|
|
11896
|
+
vue.h("span", { style: { opacity: direction === "asc" ? "1" : "0.45" } }, "\u25B2"),
|
|
11897
|
+
vue.h("span", { style: { opacity: direction === "desc" ? "1" : "0.45" } }, "\u25BC")
|
|
11898
|
+
]
|
|
11899
|
+
);
|
|
11900
|
+
}
|
|
11901
|
+
|
|
11902
|
+
// src/primitives/table/table-row-target.ts
|
|
11903
|
+
function createTableRowTarget(root) {
|
|
11904
|
+
let timer = null;
|
|
11905
|
+
const find = (key) => {
|
|
11906
|
+
const element = root();
|
|
11907
|
+
if (!element) return null;
|
|
11908
|
+
const keyString = String(key);
|
|
11909
|
+
return Array.from(element.querySelectorAll("[data-iris-table-row-key]")).find(
|
|
11910
|
+
(node) => node.getAttribute("data-iris-table-row-key") === keyString
|
|
11911
|
+
) ?? null;
|
|
11912
|
+
};
|
|
11913
|
+
const scrollTo = (key) => {
|
|
11914
|
+
find(key)?.scrollIntoView?.({ block: "nearest" });
|
|
11915
|
+
};
|
|
11916
|
+
const goTo = (key) => {
|
|
11917
|
+
const row = find(key);
|
|
11918
|
+
if (!row) return;
|
|
11919
|
+
row.scrollIntoView?.({ block: "nearest" });
|
|
11920
|
+
root()?.querySelector('[data-iris-row-target="true"]')?.removeAttribute("data-iris-row-target");
|
|
11921
|
+
row.setAttribute("data-iris-row-target", "true");
|
|
11922
|
+
if (timer !== null) clearTimeout(timer);
|
|
11923
|
+
timer = setTimeout(() => {
|
|
11924
|
+
timer = null;
|
|
11925
|
+
row.removeAttribute("data-iris-row-target");
|
|
11926
|
+
}, 2e3);
|
|
11927
|
+
};
|
|
11928
|
+
const dispose = () => {
|
|
11929
|
+
if (timer !== null) clearTimeout(timer);
|
|
11930
|
+
timer = null;
|
|
11931
|
+
};
|
|
11932
|
+
return { find, scrollTo, goTo, dispose };
|
|
11933
|
+
}
|
|
11934
|
+
function createTablePinnedDrag(options) {
|
|
11935
|
+
const firstRightPinnedIndex = vue.computed(() => {
|
|
11936
|
+
const index = options.columns().findIndex((column) => column.pinned === "right");
|
|
11937
|
+
return index < 0 ? options.columns().length : index;
|
|
11938
|
+
});
|
|
11939
|
+
const pinnedBoundaryColumn = vue.computed(() => {
|
|
11940
|
+
if (!options.enabled()) return null;
|
|
11941
|
+
for (let index = firstRightPinnedIndex.value - 1; index >= 0; index -= 1) {
|
|
11942
|
+
const column = options.columns()[index];
|
|
11943
|
+
if (column?.pinned === "left") return column;
|
|
11944
|
+
}
|
|
11945
|
+
return null;
|
|
11946
|
+
});
|
|
11947
|
+
const handleRefs = /* @__PURE__ */ new Map();
|
|
11948
|
+
const wiredKeys = /* @__PURE__ */ new Set();
|
|
11949
|
+
const activeKey = vue.ref(null);
|
|
11950
|
+
const dragDx = vue.ref(0);
|
|
11951
|
+
const getHandleRef = (key) => {
|
|
11952
|
+
let handle = handleRefs.get(key);
|
|
11953
|
+
if (!handle) {
|
|
11954
|
+
handle = vue.ref(null);
|
|
11955
|
+
handleRefs.set(key, handle);
|
|
11956
|
+
}
|
|
11957
|
+
return handle;
|
|
11958
|
+
};
|
|
11959
|
+
const resolvePinnedCount = (dx) => {
|
|
11960
|
+
const columns = options.columns();
|
|
11961
|
+
const cap = firstRightPinnedIndex.value;
|
|
11962
|
+
const current = core.leftPinnedCount(columns, cap);
|
|
11963
|
+
let currentWidth = 0;
|
|
11964
|
+
for (let index = 0; index < current; index += 1) {
|
|
11965
|
+
const column = columns[index];
|
|
11966
|
+
if (column) currentWidth += options.widthOf(column);
|
|
11967
|
+
}
|
|
11968
|
+
return core.pinnedCountFromBudget(
|
|
11969
|
+
columns,
|
|
11970
|
+
(column) => options.widthOf(column),
|
|
11971
|
+
currentWidth + dx,
|
|
11972
|
+
cap
|
|
11973
|
+
);
|
|
11974
|
+
};
|
|
11975
|
+
const commitPinnedCount = (count) => {
|
|
11976
|
+
if (!options.enabled()) return;
|
|
11977
|
+
const columns = options.columns();
|
|
11978
|
+
const cap = firstRightPinnedIndex.value;
|
|
11979
|
+
const clamped = Math.max(0, Math.min(cap, count));
|
|
11980
|
+
const current = core.leftPinnedCount(columns, cap);
|
|
11981
|
+
if (clamped === current) return;
|
|
11982
|
+
for (let index = 0; index < cap; index += 1) {
|
|
11983
|
+
const column = columns[index];
|
|
11984
|
+
if (!column) continue;
|
|
11985
|
+
const target = index < clamped ? "left" : null;
|
|
11986
|
+
if (column.pinned === target) continue;
|
|
11987
|
+
options.onColumnPinnedChange?.(column.key, target);
|
|
11988
|
+
}
|
|
11989
|
+
options.onPinnedCountChange?.(clamped);
|
|
11990
|
+
};
|
|
11991
|
+
const wire = (key) => {
|
|
11992
|
+
if (wiredKeys.has(key)) return;
|
|
11993
|
+
wiredKeys.add(key);
|
|
11994
|
+
const handle = getHandleRef(key);
|
|
11995
|
+
useDrag({
|
|
11996
|
+
handle,
|
|
11997
|
+
disabled: vue.computed(() => !options.enabled()),
|
|
11998
|
+
onStart: () => {
|
|
11999
|
+
activeKey.value = key;
|
|
12000
|
+
dragDx.value = 0;
|
|
12001
|
+
},
|
|
12002
|
+
onDrag: ({ dx }) => {
|
|
12003
|
+
activeKey.value = key;
|
|
12004
|
+
dragDx.value = dx;
|
|
12005
|
+
},
|
|
12006
|
+
onEnd: ({ dx }) => {
|
|
12007
|
+
commitPinnedCount(resolvePinnedCount(dx));
|
|
12008
|
+
activeKey.value = null;
|
|
12009
|
+
dragDx.value = 0;
|
|
12010
|
+
}
|
|
12011
|
+
});
|
|
12012
|
+
};
|
|
12013
|
+
for (const column of options.columns()) wire(column.key);
|
|
12014
|
+
return (column) => {
|
|
12015
|
+
const boundary = pinnedBoundaryColumn.value;
|
|
12016
|
+
if (!options.enabled() || !boundary || boundary.key !== column.key) return null;
|
|
12017
|
+
const handle = getHandleRef(column.key);
|
|
12018
|
+
return vue.h(
|
|
12019
|
+
"span",
|
|
12020
|
+
{
|
|
12021
|
+
ref: (element) => {
|
|
12022
|
+
handle.value = element ?? null;
|
|
12023
|
+
},
|
|
12024
|
+
role: "separator",
|
|
12025
|
+
"aria-orientation": "vertical",
|
|
12026
|
+
"aria-label": `Adjust pinned column count at ${column.title}`,
|
|
12027
|
+
tabindex: 0,
|
|
12028
|
+
"data-iris-pinned-drag-handle": "",
|
|
12029
|
+
"data-column-key": column.key,
|
|
12030
|
+
"data-iris-pinned-drag-active": activeKey.value === column.key && dragDx.value !== 0 ? "true" : void 0,
|
|
12031
|
+
onPointerdown: (event) => event.stopPropagation(),
|
|
12032
|
+
onKeydown: (event) => {
|
|
12033
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
12034
|
+
event.preventDefault();
|
|
12035
|
+
event.stopPropagation();
|
|
12036
|
+
commitPinnedCount(resolvePinnedCount(0) + (event.key === "ArrowRight" ? 1 : -1));
|
|
12037
|
+
},
|
|
12038
|
+
style: {
|
|
12039
|
+
position: "absolute",
|
|
12040
|
+
top: "0",
|
|
12041
|
+
right: "0",
|
|
12042
|
+
bottom: "0",
|
|
12043
|
+
width: "8px",
|
|
12044
|
+
cursor: "col-resize",
|
|
12045
|
+
touchAction: "none",
|
|
12046
|
+
userSelect: "none",
|
|
12047
|
+
zIndex: "2",
|
|
12048
|
+
transform: activeKey.value === column.key && dragDx.value !== 0 ? `translateX(${dragDx.value}px)` : void 0
|
|
12049
|
+
}
|
|
12050
|
+
},
|
|
12051
|
+
vue.h("span", {
|
|
12052
|
+
"aria-hidden": "true",
|
|
12053
|
+
"data-iris-pinned-drag-line": "",
|
|
12054
|
+
style: {
|
|
12055
|
+
position: "absolute",
|
|
12056
|
+
top: "0",
|
|
12057
|
+
bottom: "0",
|
|
12058
|
+
insetInlineStart: "50%",
|
|
12059
|
+
width: "2px",
|
|
12060
|
+
background: "var(--iris-primary)",
|
|
12061
|
+
transform: "translateX(-50%)"
|
|
12062
|
+
}
|
|
12063
|
+
})
|
|
12064
|
+
);
|
|
12065
|
+
};
|
|
12066
|
+
}
|
|
12067
|
+
function useTableImport(isPreviewEnabled, getOnImport) {
|
|
12068
|
+
const importFileInput = vue.ref(null);
|
|
12069
|
+
const importPreviewRows = vue.ref(null);
|
|
12070
|
+
const handleImportFile = (event) => {
|
|
12071
|
+
const input = event.target;
|
|
12072
|
+
const file = input?.files?.[0];
|
|
12073
|
+
if (!file || !getOnImport() || typeof FileReader === "undefined") return;
|
|
12074
|
+
const reader = new FileReader();
|
|
12075
|
+
reader.onload = () => {
|
|
12076
|
+
const rows = core.rowsFromCsv(String(reader.result ?? ""));
|
|
12077
|
+
if (rows.length === 0) return;
|
|
12078
|
+
if (isPreviewEnabled()) importPreviewRows.value = rows;
|
|
12079
|
+
else getOnImport()?.(rows);
|
|
12080
|
+
};
|
|
12081
|
+
reader.readAsText(file);
|
|
12082
|
+
if (input) input.value = "";
|
|
12083
|
+
};
|
|
12084
|
+
const confirmImportPreview = () => {
|
|
12085
|
+
if (!importPreviewRows.value) return;
|
|
12086
|
+
getOnImport()?.(importPreviewRows.value);
|
|
12087
|
+
importPreviewRows.value = null;
|
|
12088
|
+
};
|
|
12089
|
+
const cancelImportPreview = () => {
|
|
12090
|
+
importPreviewRows.value = null;
|
|
12091
|
+
};
|
|
12092
|
+
vue.watch(importPreviewRows, (rows, _previous, onCleanup) => {
|
|
12093
|
+
if (!rows || typeof window === "undefined") return;
|
|
12094
|
+
const closeOnEscape = (event) => {
|
|
12095
|
+
if (event.key === "Escape") cancelImportPreview();
|
|
12096
|
+
};
|
|
12097
|
+
window.addEventListener("keydown", closeOnEscape);
|
|
12098
|
+
onCleanup(() => window.removeEventListener("keydown", closeOnEscape));
|
|
12099
|
+
});
|
|
12100
|
+
return {
|
|
12101
|
+
importFileInput,
|
|
12102
|
+
importPreviewRows,
|
|
12103
|
+
handleImportFile,
|
|
12104
|
+
confirmImportPreview,
|
|
12105
|
+
cancelImportPreview
|
|
12106
|
+
};
|
|
12107
|
+
}
|
|
12108
|
+
var editorInputStyle = (error) => ({
|
|
12109
|
+
width: "100%",
|
|
12110
|
+
border: `1px solid ${error ? "var(--iris-danger)" : "var(--iris-primary)"}`,
|
|
12111
|
+
borderRadius: "var(--iris-radius-sm)",
|
|
12112
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-padding-sm, 6px)",
|
|
12113
|
+
font: "inherit",
|
|
12114
|
+
background: "var(--iris-background)",
|
|
12115
|
+
color: "var(--iris-foreground)",
|
|
12116
|
+
outline: "none",
|
|
12117
|
+
boxShadow: "0 0 0 3px color-mix(in srgb, var(--iris-primary) 18%, transparent)"
|
|
12118
|
+
});
|
|
12119
|
+
function editorErrorVNode(editCellId, error) {
|
|
12120
|
+
return vue.h(
|
|
12121
|
+
"div",
|
|
12122
|
+
{
|
|
12123
|
+
id: `${editCellId}-error`,
|
|
12124
|
+
role: "alert",
|
|
12125
|
+
"data-iris-table-editor-error": "",
|
|
12126
|
+
style: {
|
|
12127
|
+
marginTop: "var(--iris-space-xxs, 4px)",
|
|
12128
|
+
fontSize: "var(--iris-font-size-xs, 12px)",
|
|
12129
|
+
color: "var(--iris-danger)"
|
|
12130
|
+
}
|
|
12131
|
+
},
|
|
12132
|
+
error
|
|
12133
|
+
);
|
|
12134
|
+
}
|
|
12135
|
+
var editPreviewStyle = {
|
|
12136
|
+
flexBasis: "100%",
|
|
12137
|
+
minWidth: "0",
|
|
12138
|
+
marginTop: "var(--iris-space-xxs, 4px)",
|
|
12139
|
+
fontSize: "var(--iris-font-size-xs, 12px)",
|
|
12140
|
+
color: "var(--iris-muted)"
|
|
12141
|
+
};
|
|
12142
|
+
function previewVNode(ctx, row, col, draft) {
|
|
12143
|
+
if (!ctx.editPreview || !col.formatter) return null;
|
|
12144
|
+
return vue.h(
|
|
12145
|
+
"div",
|
|
12146
|
+
{ "data-iris-edit-preview": "", style: editPreviewStyle },
|
|
12147
|
+
ctx.previewValue(row, col, draft)
|
|
12148
|
+
);
|
|
12149
|
+
}
|
|
12150
|
+
function renderRowSessionContent(ctx, row, col, index, key, editCellId, session) {
|
|
12151
|
+
const error = session.error;
|
|
12152
|
+
const input = vue.h("input", {
|
|
12153
|
+
ref: (el) => {
|
|
12154
|
+
ctx.rowEditorRefs.set(col.key, el ?? null);
|
|
12155
|
+
},
|
|
12156
|
+
type: col.editor === "number" ? "number" : "text",
|
|
12157
|
+
value: session.draft,
|
|
12158
|
+
"data-iris-table-editor": "",
|
|
12159
|
+
"aria-invalid": error ? "true" : void 0,
|
|
12160
|
+
"aria-describedby": error ? `${editCellId}-error` : void 0,
|
|
12161
|
+
onInput: (e) => {
|
|
12162
|
+
session.draft = e.target.value;
|
|
12163
|
+
},
|
|
12164
|
+
onKeydown: (e) => {
|
|
12165
|
+
if (e.key === "Enter") {
|
|
12166
|
+
e.preventDefault();
|
|
12167
|
+
ctx.commitRowSession(key, col, index, editCellId);
|
|
12168
|
+
} else if (e.key === "Escape") {
|
|
12169
|
+
e.preventDefault();
|
|
12170
|
+
ctx.cancelRowEdit();
|
|
12171
|
+
}
|
|
12172
|
+
},
|
|
12173
|
+
onBlur: () => ctx.commitRowSession(key, col, index, editCellId),
|
|
12174
|
+
onClick: (e) => e.stopPropagation(),
|
|
12175
|
+
onDblclick: (e) => e.stopPropagation(),
|
|
12176
|
+
style: editorInputStyle(error)
|
|
12177
|
+
});
|
|
12178
|
+
const preview = previewVNode(ctx, row, col, session.draft);
|
|
12179
|
+
const children = [input, preview, error ? editorErrorVNode(editCellId, error) : null].filter(
|
|
12180
|
+
(node) => node !== null
|
|
12181
|
+
);
|
|
12182
|
+
return children.length === 1 ? children[0] : children;
|
|
12183
|
+
}
|
|
12184
|
+
function renderCellEditContent(ctx, row, col, index, editCellId) {
|
|
12185
|
+
const error = ctx.editError.value;
|
|
12186
|
+
const input = vue.h("input", {
|
|
12187
|
+
ref: (el) => {
|
|
12188
|
+
ctx.editorInputRef.value = el ?? null;
|
|
12189
|
+
},
|
|
12190
|
+
type: col.editor === "number" ? "number" : "text",
|
|
12191
|
+
value: ctx.editingDraft.value,
|
|
12192
|
+
"data-iris-table-editor": "",
|
|
12193
|
+
"aria-invalid": error ? "true" : void 0,
|
|
12194
|
+
"aria-describedby": error ? `${editCellId}-error` : void 0,
|
|
12195
|
+
onInput: (e) => {
|
|
12196
|
+
ctx.editingDraft.value = e.target.value;
|
|
12197
|
+
},
|
|
12198
|
+
onKeydown: (e) => {
|
|
12199
|
+
if (e.key === "Enter") {
|
|
12200
|
+
e.preventDefault();
|
|
12201
|
+
ctx.commitEdit(row, col, index);
|
|
12202
|
+
} else if (e.key === "Escape") {
|
|
12203
|
+
e.preventDefault();
|
|
12204
|
+
ctx.cancelEdit();
|
|
12205
|
+
}
|
|
12206
|
+
},
|
|
12207
|
+
onBlur: () => ctx.commitEdit(row, col, index),
|
|
12208
|
+
onClick: (e) => e.stopPropagation(),
|
|
12209
|
+
onDblclick: (e) => e.stopPropagation(),
|
|
12210
|
+
style: editorInputStyle(error)
|
|
12211
|
+
});
|
|
12212
|
+
const preview = previewVNode(ctx, row, col, ctx.editingDraft.value);
|
|
12213
|
+
const children = [input, preview, error ? editorErrorVNode(editCellId, error) : null].filter(
|
|
12214
|
+
(node) => node !== null
|
|
12215
|
+
);
|
|
12216
|
+
return children.length === 1 ? children[0] : children;
|
|
12217
|
+
}
|
|
12218
|
+
function renderGroupedHeader(ctx, matrix) {
|
|
12219
|
+
const lead = (ctx.showDrag ? 1 : 0) + (ctx.showSeq ? 1 : 0) + (ctx.showDetail ? 1 : 0) + (ctx.showSelection ? 1 : 0);
|
|
12220
|
+
const cells = [];
|
|
12221
|
+
if (ctx.showDrag) {
|
|
12222
|
+
cells.push(
|
|
12223
|
+
vue.h("div", {
|
|
12224
|
+
key: "__drag__",
|
|
12225
|
+
role: "columnheader",
|
|
12226
|
+
"data-iris-table-header": "__drag",
|
|
12227
|
+
style: { gridColumn: "1", gridRow: "1 / -1" }
|
|
12228
|
+
})
|
|
12229
|
+
);
|
|
12230
|
+
}
|
|
12231
|
+
if (ctx.showSeq) {
|
|
12232
|
+
cells.push(
|
|
12233
|
+
vue.h("div", {
|
|
12234
|
+
key: "__seq__",
|
|
12235
|
+
role: "columnheader",
|
|
12236
|
+
"data-iris-table-header": "__seq",
|
|
12237
|
+
style: { gridColumn: ctx.showDrag ? "2" : "1", gridRow: "1 / -1" }
|
|
12238
|
+
})
|
|
12239
|
+
);
|
|
12240
|
+
}
|
|
12241
|
+
if (ctx.showDetail) {
|
|
12242
|
+
cells.push(
|
|
12243
|
+
vue.h("div", {
|
|
12244
|
+
key: "__expand__",
|
|
12245
|
+
role: "columnheader",
|
|
12246
|
+
style: {
|
|
12247
|
+
gridColumn: `${(ctx.showDrag ? 1 : 0) + (ctx.showSeq ? 1 : 0) + 1}`,
|
|
12248
|
+
gridRow: "1 / -1"
|
|
12249
|
+
}
|
|
12250
|
+
})
|
|
12251
|
+
);
|
|
12252
|
+
}
|
|
12253
|
+
if (ctx.showSelection) {
|
|
12254
|
+
cells.push(
|
|
12255
|
+
vue.h(
|
|
12256
|
+
"div",
|
|
12257
|
+
{
|
|
12258
|
+
key: "__select__",
|
|
12259
|
+
role: "columnheader",
|
|
12260
|
+
"data-iris-table-header": "",
|
|
12261
|
+
style: {
|
|
12262
|
+
gridColumn: `${(ctx.showDrag ? 1 : 0) + (ctx.showSeq ? 1 : 0) + (ctx.showDetail ? 1 : 0) + 1}`,
|
|
12263
|
+
gridRow: "1 / -1",
|
|
12264
|
+
display: "flex",
|
|
12265
|
+
alignItems: "center",
|
|
12266
|
+
justifyContent: "center",
|
|
12267
|
+
padding: "8px 12px",
|
|
12268
|
+
background: "var(--iris-surface)",
|
|
12269
|
+
borderBottom: "1px solid var(--iris-border)"
|
|
12270
|
+
}
|
|
12271
|
+
},
|
|
12272
|
+
ctx.selectable === "multi" ? [
|
|
12273
|
+
[
|
|
12274
|
+
vue.h(IrisCheckbox, {
|
|
12275
|
+
modelValue: ctx.allSelected.value ? true : ctx.someSelected.value ? "indeterminate" : false,
|
|
12276
|
+
size: "sm",
|
|
12277
|
+
ariaLabel: ctx.t("table.selectAll"),
|
|
12278
|
+
"onUpdate:modelValue": ctx.toggleAll
|
|
12279
|
+
}),
|
|
12280
|
+
ctx.selection && ctx.selection.length > 0 ? vue.h(
|
|
12281
|
+
"span",
|
|
12282
|
+
{
|
|
12283
|
+
"data-iris-table-selected-count": "",
|
|
12284
|
+
style: {
|
|
12285
|
+
marginInlineStart: "var(--iris-space-xs, 8px)",
|
|
12286
|
+
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
12287
|
+
color: "var(--iris-muted)",
|
|
12288
|
+
whiteSpace: "nowrap"
|
|
12289
|
+
}
|
|
12290
|
+
},
|
|
12291
|
+
ctx.t("table.selectedCount", { count: String(ctx.selection.length) })
|
|
12292
|
+
) : null
|
|
12293
|
+
]
|
|
12294
|
+
] : ""
|
|
12295
|
+
)
|
|
12296
|
+
);
|
|
12297
|
+
}
|
|
12298
|
+
for (const rowCells of matrix) {
|
|
12299
|
+
for (const cell of rowCells) {
|
|
12300
|
+
const col = cell.column;
|
|
12301
|
+
const isLeaf = !col.children || col.children.length === 0;
|
|
12302
|
+
const sortable = isLeaf && col.sortable;
|
|
12303
|
+
const align = col.align ?? "left";
|
|
12304
|
+
const headerSlot = ctx.slots[`header.${col.key}`];
|
|
12305
|
+
const title = headerSlot?.({ column: col }) ?? col.title;
|
|
12306
|
+
cells.push(
|
|
12307
|
+
vue.h(
|
|
12308
|
+
"div",
|
|
12309
|
+
{
|
|
12310
|
+
key: `${col.key}-${cell.level}`,
|
|
12311
|
+
role: "columnheader",
|
|
12312
|
+
"data-iris-table-header": col.key,
|
|
12313
|
+
"data-iris-table-header-group": isLeaf ? void 0 : "",
|
|
12314
|
+
"aria-colspan": cell.colSpan,
|
|
12315
|
+
onClick: sortable ? () => ctx.onHeaderClick(col) : void 0,
|
|
12316
|
+
"aria-sort": sortable ? ctx.ariaSortFor(col) : void 0,
|
|
12317
|
+
style: {
|
|
12318
|
+
gridColumn: `${lead + cell.colStart} / span ${cell.colSpan}`,
|
|
12319
|
+
gridRow: `${cell.level + 1} / span ${cell.rowSpan}`,
|
|
12320
|
+
display: "flex",
|
|
12321
|
+
alignItems: "center",
|
|
12322
|
+
justifyContent: isLeaf ? align === "right" ? "flex-end" : align === "center" ? "center" : "flex-start" : "center",
|
|
12323
|
+
padding: "8px var(--iris-padding-md)",
|
|
12324
|
+
cursor: sortable ? "pointer" : "default",
|
|
12325
|
+
userSelect: sortable ? "none" : "auto",
|
|
12326
|
+
background: "var(--iris-surface)",
|
|
12327
|
+
borderBottom: "1px solid var(--iris-border)",
|
|
12328
|
+
fontWeight: "600",
|
|
12329
|
+
fontSize: "var(--iris-font-size-md, 14px)",
|
|
12330
|
+
color: "var(--iris-foreground)",
|
|
12331
|
+
whiteSpace: "nowrap",
|
|
12332
|
+
overflow: "hidden",
|
|
12333
|
+
textOverflow: "ellipsis"
|
|
12334
|
+
}
|
|
12335
|
+
},
|
|
12336
|
+
[
|
|
12337
|
+
title,
|
|
12338
|
+
sortable ? ctx.sortIndicator(col) : null,
|
|
12339
|
+
ctx.multiSortSeq(col),
|
|
12340
|
+
ctx.renderFilterTrigger(col, isLeaf),
|
|
12341
|
+
isLeaf ? ctx.pinnedDragHandle?.(col) ?? null : null
|
|
12342
|
+
]
|
|
12343
|
+
)
|
|
12344
|
+
);
|
|
12345
|
+
}
|
|
10553
12346
|
}
|
|
12347
|
+
return vue.h(
|
|
12348
|
+
"div",
|
|
12349
|
+
{
|
|
12350
|
+
role: "row",
|
|
12351
|
+
"data-iris-table-row": "header",
|
|
12352
|
+
"data-iris-table-header-row": "",
|
|
12353
|
+
"data-iris-table-header-grouped": "",
|
|
12354
|
+
style: {
|
|
12355
|
+
display: "grid",
|
|
12356
|
+
gridTemplateColumns: ctx.gridTemplate.value,
|
|
12357
|
+
gridTemplateRows: `repeat(${matrix.length}, auto)`
|
|
12358
|
+
}
|
|
12359
|
+
},
|
|
12360
|
+
cells
|
|
12361
|
+
);
|
|
12362
|
+
}
|
|
12363
|
+
function createTableViewsController(options) {
|
|
12364
|
+
const views = vue.ref(core.readTableViews(options.config()));
|
|
12365
|
+
const internalActiveKey = vue.ref(null);
|
|
12366
|
+
const activeKey = vue.computed(() => {
|
|
12367
|
+
const config = options.config();
|
|
12368
|
+
return config?.activeKey !== void 0 ? config.activeKey ?? null : internalActiveKey.value;
|
|
12369
|
+
});
|
|
12370
|
+
const saveOpen = vue.ref(false);
|
|
12371
|
+
const draft = vue.ref("");
|
|
12372
|
+
const activeTab = vue.ref(null);
|
|
12373
|
+
const persist = (next) => {
|
|
12374
|
+
views.value = next;
|
|
12375
|
+
core.writeTableViews(options.config(), next);
|
|
12376
|
+
};
|
|
12377
|
+
const applySnapshot = (snapshot) => {
|
|
12378
|
+
if (Object.prototype.hasOwnProperty.call(snapshot, "sort"))
|
|
12379
|
+
options.setSort(snapshot.sort ?? null);
|
|
12380
|
+
};
|
|
12381
|
+
const select = (key) => {
|
|
12382
|
+
const view = views.value.find((candidate) => candidate.name === key);
|
|
12383
|
+
if (!view) return;
|
|
12384
|
+
applySnapshot(view.snapshot);
|
|
12385
|
+
internalActiveKey.value = key;
|
|
12386
|
+
options.onActiveViewChange(key);
|
|
12387
|
+
};
|
|
12388
|
+
const save = (name) => {
|
|
12389
|
+
const trimmed = name.trim();
|
|
12390
|
+
if (!trimmed) return;
|
|
12391
|
+
const currentSort = options.sort.value;
|
|
12392
|
+
const entry = {
|
|
12393
|
+
name: trimmed,
|
|
12394
|
+
snapshot: { sort: currentSort ? { ...currentSort } : null }
|
|
12395
|
+
};
|
|
12396
|
+
const index = views.value.findIndex((view) => view.name === trimmed);
|
|
12397
|
+
persist(
|
|
12398
|
+
index < 0 ? [...views.value, entry] : views.value.map((view, i) => i === index ? entry : view)
|
|
12399
|
+
);
|
|
12400
|
+
internalActiveKey.value = trimmed;
|
|
12401
|
+
options.onActiveViewChange(trimmed);
|
|
12402
|
+
};
|
|
12403
|
+
const remove = (key) => {
|
|
12404
|
+
persist(views.value.filter((view) => view.name !== key));
|
|
12405
|
+
if (activeKey.value === key) {
|
|
12406
|
+
internalActiveKey.value = null;
|
|
12407
|
+
options.onActiveViewChange(null);
|
|
12408
|
+
}
|
|
12409
|
+
};
|
|
12410
|
+
const applyTab = (tab) => {
|
|
12411
|
+
activeTab.value = tab.key;
|
|
12412
|
+
for (const name of tab.views ?? []) select(name);
|
|
12413
|
+
};
|
|
10554
12414
|
return {
|
|
10555
|
-
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
12415
|
+
activeKey,
|
|
12416
|
+
views,
|
|
12417
|
+
saveOpen,
|
|
12418
|
+
draft,
|
|
12419
|
+
renderTabs: (tabs) => renderTableTabs(tabs, activeTab, applyTab),
|
|
12420
|
+
renderViews: () => renderTableViews({
|
|
12421
|
+
config: options.config(),
|
|
12422
|
+
views,
|
|
12423
|
+
activeKey,
|
|
12424
|
+
saveOpen,
|
|
12425
|
+
draft,
|
|
12426
|
+
onSelect: select,
|
|
12427
|
+
onSave: save,
|
|
12428
|
+
onDelete: remove
|
|
12429
|
+
})
|
|
10560
12430
|
};
|
|
10561
12431
|
}
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
12432
|
+
function renderTableViews(ctx) {
|
|
12433
|
+
if (!ctx.config) return null;
|
|
12434
|
+
return vue.h(
|
|
12435
|
+
"div",
|
|
12436
|
+
{
|
|
12437
|
+
"data-iris-table-views-bar": "",
|
|
12438
|
+
style: {
|
|
12439
|
+
display: "flex",
|
|
12440
|
+
alignItems: "center",
|
|
12441
|
+
gap: "var(--iris-space-xxs, 4px)",
|
|
12442
|
+
padding: "var(--iris-space-xxs, 4px) 0"
|
|
12443
|
+
}
|
|
12444
|
+
},
|
|
12445
|
+
[
|
|
12446
|
+
vue.h(
|
|
12447
|
+
"select",
|
|
12448
|
+
{
|
|
12449
|
+
"data-iris-table-views": "",
|
|
12450
|
+
value: ctx.saveOpen.value ? core.TABLE_VIEWS_SAVE_ITEM : ctx.activeKey.value ?? "",
|
|
12451
|
+
"aria-label": "Table views",
|
|
12452
|
+
onChange: (event) => {
|
|
12453
|
+
const value = event.target.value;
|
|
12454
|
+
if (value === core.TABLE_VIEWS_SAVE_ITEM) {
|
|
12455
|
+
ctx.draft.value = "";
|
|
12456
|
+
ctx.saveOpen.value = true;
|
|
12457
|
+
} else if (value !== "") {
|
|
12458
|
+
ctx.onSelect(value);
|
|
12459
|
+
}
|
|
12460
|
+
},
|
|
12461
|
+
style: {
|
|
12462
|
+
border: "1px solid var(--iris-border)",
|
|
12463
|
+
borderRadius: "var(--iris-radius-sm, 4px)",
|
|
12464
|
+
background: "var(--iris-surface)",
|
|
12465
|
+
color: "var(--iris-foreground)",
|
|
12466
|
+
font: "inherit",
|
|
12467
|
+
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
12468
|
+
padding: "0 var(--iris-space-xxs, 4px)",
|
|
12469
|
+
maxWidth: "180px"
|
|
12470
|
+
}
|
|
12471
|
+
},
|
|
12472
|
+
[
|
|
12473
|
+
ctx.activeKey.value === null && !ctx.saveOpen.value ? vue.h("option", { value: "", disabled: true }, "Select view") : null,
|
|
12474
|
+
...ctx.views.value.map(
|
|
12475
|
+
(view) => vue.h(
|
|
12476
|
+
"option",
|
|
12477
|
+
{ key: view.name, value: view.name },
|
|
12478
|
+
ctx.config?.label?.(view.name) ?? view.name
|
|
12479
|
+
)
|
|
12480
|
+
),
|
|
12481
|
+
vue.h("option", { value: core.TABLE_VIEWS_SAVE_ITEM }, "\uFF0B Save view")
|
|
12482
|
+
]
|
|
12483
|
+
),
|
|
12484
|
+
ctx.saveOpen.value ? vue.h("input", {
|
|
12485
|
+
"data-iris-views-save": "",
|
|
12486
|
+
type: "text",
|
|
12487
|
+
value: ctx.draft.value,
|
|
12488
|
+
placeholder: "View name",
|
|
12489
|
+
"aria-label": "Save view",
|
|
12490
|
+
onInput: (event) => {
|
|
12491
|
+
ctx.draft.value = event.target.value;
|
|
12492
|
+
},
|
|
12493
|
+
onKeydown: (event) => {
|
|
12494
|
+
if (event.key === "Enter") {
|
|
12495
|
+
event.preventDefault();
|
|
12496
|
+
if (ctx.draft.value.trim()) ctx.onSave(ctx.draft.value);
|
|
12497
|
+
ctx.saveOpen.value = false;
|
|
12498
|
+
} else if (event.key === "Escape") {
|
|
12499
|
+
ctx.saveOpen.value = false;
|
|
12500
|
+
}
|
|
12501
|
+
},
|
|
12502
|
+
onBlur: () => {
|
|
12503
|
+
ctx.saveOpen.value = false;
|
|
12504
|
+
},
|
|
12505
|
+
style: {
|
|
12506
|
+
border: "1px solid var(--iris-border)",
|
|
12507
|
+
borderRadius: "var(--iris-radius-sm, 4px)",
|
|
12508
|
+
padding: "var(--iris-space-xxs, 4px)",
|
|
12509
|
+
width: "120px",
|
|
12510
|
+
font: "inherit"
|
|
12511
|
+
}
|
|
12512
|
+
}) : null,
|
|
12513
|
+
ctx.activeKey.value !== null ? vue.h(
|
|
12514
|
+
"button",
|
|
12515
|
+
{
|
|
12516
|
+
type: "button",
|
|
12517
|
+
"data-iris-table-views-delete": "",
|
|
12518
|
+
"aria-label": "Delete view",
|
|
12519
|
+
onClick: () => ctx.onDelete(ctx.activeKey.value),
|
|
12520
|
+
style: {
|
|
12521
|
+
border: "none",
|
|
12522
|
+
background: "transparent",
|
|
12523
|
+
cursor: "pointer",
|
|
12524
|
+
color: "var(--iris-muted)",
|
|
12525
|
+
font: "inherit",
|
|
12526
|
+
padding: "0 var(--iris-space-xxs, 4px)"
|
|
12527
|
+
}
|
|
12528
|
+
},
|
|
12529
|
+
"\xD7"
|
|
12530
|
+
) : null
|
|
12531
|
+
]
|
|
12532
|
+
);
|
|
10567
12533
|
}
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
12534
|
+
function renderTableTabs(tabs, activeTab, onApply) {
|
|
12535
|
+
const unique = core.uniqueTableTabs(tabs ?? []);
|
|
12536
|
+
if (unique.length === 0) return null;
|
|
12537
|
+
return vue.h(
|
|
12538
|
+
"div",
|
|
12539
|
+
{
|
|
12540
|
+
role: "tablist",
|
|
12541
|
+
"data-iris-table-tabs": "",
|
|
12542
|
+
style: {
|
|
12543
|
+
display: "flex",
|
|
12544
|
+
alignItems: "center",
|
|
12545
|
+
gap: "var(--iris-space-xs, 8px)",
|
|
12546
|
+
padding: "var(--iris-space-xs, 8px) var(--iris-space-sm, 12px)",
|
|
12547
|
+
border: "1px solid var(--iris-border)",
|
|
12548
|
+
borderBottom: "none",
|
|
12549
|
+
borderTopLeftRadius: "var(--iris-radius-md, 6px)",
|
|
12550
|
+
borderTopRightRadius: "var(--iris-radius-md, 6px)",
|
|
12551
|
+
background: "var(--iris-surface)"
|
|
12552
|
+
}
|
|
12553
|
+
},
|
|
12554
|
+
unique.map(
|
|
12555
|
+
(tab) => vue.h(
|
|
12556
|
+
"button",
|
|
12557
|
+
{
|
|
12558
|
+
key: tab.key,
|
|
12559
|
+
type: "button",
|
|
12560
|
+
role: "tab",
|
|
12561
|
+
"data-iris-table-tab": tab.key,
|
|
12562
|
+
"aria-selected": activeTab.value === tab.key ? "true" : "false",
|
|
12563
|
+
onClick: () => onApply(tab),
|
|
12564
|
+
style: {
|
|
12565
|
+
border: "none",
|
|
12566
|
+
background: "transparent",
|
|
12567
|
+
color: activeTab.value === tab.key ? "var(--iris-primary)" : "var(--iris-foreground)",
|
|
12568
|
+
cursor: "pointer",
|
|
12569
|
+
font: "inherit",
|
|
12570
|
+
fontWeight: activeTab.value === tab.key ? "600" : "400",
|
|
12571
|
+
padding: "0 var(--iris-space-xxs, 4px)"
|
|
12572
|
+
}
|
|
12573
|
+
},
|
|
12574
|
+
tab.label
|
|
12575
|
+
)
|
|
12576
|
+
)
|
|
12577
|
+
);
|
|
10580
12578
|
}
|
|
12579
|
+
|
|
12580
|
+
// src/primitives/table/Table.ts
|
|
10581
12581
|
var IrisTable = vue.defineComponent({
|
|
10582
12582
|
name: "IrisTable",
|
|
10583
12583
|
inheritAttrs: false,
|
|
10584
|
-
props:
|
|
10585
|
-
columns: {
|
|
10586
|
-
type: Array,
|
|
10587
|
-
required: true
|
|
10588
|
-
},
|
|
10589
|
-
data: {
|
|
10590
|
-
type: Array,
|
|
10591
|
-
required: false,
|
|
10592
|
-
default: void 0
|
|
10593
|
-
},
|
|
10594
|
-
rowKey: { type: String, default: "id" },
|
|
10595
|
-
...tableControlProps,
|
|
10596
|
-
striped: { type: Boolean, default: false },
|
|
10597
|
-
editConfig: {
|
|
10598
|
-
type: Object,
|
|
10599
|
-
default: void 0
|
|
10600
|
-
},
|
|
10601
|
-
bordered: { type: Boolean, default: true },
|
|
10602
|
-
/** Enable per-column resize handles. Combine with `v-model:columnWidths` for persistence. */
|
|
10603
|
-
resizableColumns: { type: Boolean, default: false },
|
|
10604
|
-
/** Controlled column widths in px. */
|
|
10605
|
-
columnWidths: {
|
|
10606
|
-
type: Object,
|
|
10607
|
-
default: void 0
|
|
10608
|
-
},
|
|
10609
|
-
/** Enable virtual scrolling for the body. */
|
|
10610
|
-
virtualScroll: {
|
|
10611
|
-
type: Object,
|
|
10612
|
-
default: void 0
|
|
10613
|
-
},
|
|
10614
|
-
/** Show the loading state instead of rows. */
|
|
10615
|
-
loading: { type: Boolean, default: false },
|
|
10616
|
-
/** Show the error state instead of rows (takes precedence over loading). */
|
|
10617
|
-
error: { type: Boolean, default: false },
|
|
10618
|
-
onRetry: { type: Function, default: void 0 },
|
|
10619
|
-
/** Render only the horizontally-visible columns (+ pinned + overscan) for wide tables. */
|
|
10620
|
-
columnVirtualization: { type: Boolean, default: false },
|
|
10621
|
-
/**
|
|
10622
|
-
* Enable WAI-ARIA grid keyboard navigation: the table becomes `role="grid"`
|
|
10623
|
-
* and Arrow / Home / End / Page Up·Down move a roving cell focus across the
|
|
10624
|
-
* data cells. Off by default; opt-in and additive (no effect on mouse / Tab
|
|
10625
|
-
* behavior). Pairs best without virtualization (the focused cell must be
|
|
10626
|
-
* rendered) and does not hijack keystrokes while a cell is being edited.
|
|
10627
|
-
*/
|
|
10628
|
-
keyboardNavigation: { type: Boolean, default: false },
|
|
10629
|
-
/**
|
|
10630
|
-
* Enable rectangular cell-range selection (Excel-style). Click starts a
|
|
10631
|
-
* range; Shift+Click or Shift+Arrow extends it; Escape clears it.
|
|
10632
|
-
* Cells within the range get `data-iris-cell-selected="true"`.
|
|
10633
|
-
*/
|
|
10634
|
-
cellRange: { type: Boolean, default: false },
|
|
10635
|
-
/**
|
|
10636
|
-
* Render an expandable detail panel beneath a row. Providing this adds a
|
|
10637
|
-
* leading expand-toggle column; clicking it reveals a full-width detail row.
|
|
10638
|
-
* (Not applied in the virtual-scroll path.)
|
|
10639
|
-
*/
|
|
10640
|
-
renderDetail: {
|
|
10641
|
-
type: Function,
|
|
10642
|
-
default: void 0
|
|
10643
|
-
},
|
|
10644
|
-
/** Which rows can expand a detail panel. Defaults to all rows when `renderDetail` is set. */
|
|
10645
|
-
rowExpandable: {
|
|
10646
|
-
type: Function,
|
|
10647
|
-
default: void 0
|
|
10648
|
-
},
|
|
10649
|
-
/** Initially-expanded row keys (uncontrolled). */
|
|
10650
|
-
defaultExpandedRowKeys: {
|
|
10651
|
-
type: Array,
|
|
10652
|
-
default: void 0
|
|
10653
|
-
},
|
|
10654
|
-
/**
|
|
10655
|
-
* Read a row's child rows to render the table as a TREE. Providing this
|
|
10656
|
-
* enables tree mode: `data` is treated as the root rows, each row's first
|
|
10657
|
-
* cell gains a depth indent + an expand/collapse toggle (when it has
|
|
10658
|
-
* children), and the expand state reuses `defaultExpandedRowKeys` /
|
|
10659
|
-
* `expandedRowsChange`. Column sort reorders siblings hierarchically (each
|
|
10660
|
-
* level sorted, structure kept), and tree rows virtualize like flat rows
|
|
10661
|
-
* when `virtualScroll` is set (unless `renderDetail` is also used, since
|
|
10662
|
-
* detail panels are variable-height).
|
|
10663
|
-
*/
|
|
10664
|
-
getSubRows: {
|
|
10665
|
-
type: Function,
|
|
10666
|
-
default: void 0
|
|
10667
|
-
},
|
|
10668
|
-
/**
|
|
10669
|
-
* Cascade multi-row selection through the complete tree supplied by
|
|
10670
|
-
* `getSubRows`. Selecting a branch selects every descendant (including
|
|
10671
|
-
* collapsed rows); partially selected branches render indeterminate.
|
|
10672
|
-
* Ignored outside tree mode and for non-multi selection.
|
|
10673
|
-
*/
|
|
10674
|
-
treeSelectionCascade: { type: Boolean, default: false }
|
|
10675
|
-
},
|
|
12584
|
+
props: tableProps,
|
|
10676
12585
|
emits: {
|
|
10677
12586
|
"update:selection": (_value) => true,
|
|
10678
12587
|
"update:sort": (_value) => true,
|
|
12588
|
+
"update:multiSortState": (_value) => true,
|
|
12589
|
+
multiSortChange: (_value) => true,
|
|
10679
12590
|
"update:columnWidths": (_value) => true,
|
|
12591
|
+
/** Controlled columnVisibility channel (parent owns the map). */
|
|
12592
|
+
"update:columnVisibility": (_value) => true,
|
|
10680
12593
|
rowClick: (_row, _index) => true,
|
|
10681
12594
|
rowDblclick: (_row, _index) => true,
|
|
10682
12595
|
cellEdit: (_payload) => true,
|
|
10683
12596
|
expandedRowsChange: (_keys) => true
|
|
10684
12597
|
},
|
|
10685
|
-
setup(props, { slots, attrs, emit }) {
|
|
10686
|
-
|
|
10687
|
-
const style = document.createElement("style");
|
|
10688
|
-
style.id = "iris-table-row-styles";
|
|
10689
|
-
style.textContent = `
|
|
10690
|
-
[data-iris-table] [role="row"]:hover {
|
|
10691
|
-
--iris-cell-bg: var(--iris-surface-hover);
|
|
10692
|
-
}
|
|
10693
|
-
[data-iris-table-row-selected="true"] {
|
|
10694
|
-
--iris-cell-bg: var(--iris-surface-selected);
|
|
10695
|
-
}
|
|
10696
|
-
`;
|
|
10697
|
-
document.head.appendChild(style);
|
|
10698
|
-
}
|
|
12598
|
+
setup(props, { slots, attrs, emit, expose }) {
|
|
12599
|
+
ensureTableStyles();
|
|
10699
12600
|
const { t } = useI18n();
|
|
10700
|
-
const
|
|
12601
|
+
const densityState = vue.ref("comfortable");
|
|
12602
|
+
const effectiveDensity = vue.computed(() => {
|
|
12603
|
+
if (props.densityToggle) return densityState.value;
|
|
12604
|
+
return props.density === "compact" || props.density === "cozy" ? props.density : "comfortable";
|
|
12605
|
+
});
|
|
12606
|
+
const cycleDensity = () => {
|
|
12607
|
+
densityState.value = densityState.value === "comfortable" ? "compact" : densityState.value === "compact" ? "cozy" : "comfortable";
|
|
12608
|
+
};
|
|
12609
|
+
const importController = useTableImport(
|
|
12610
|
+
() => props.importPreview,
|
|
12611
|
+
() => props.toolbar?.onImport
|
|
12612
|
+
);
|
|
12613
|
+
const responsiveWidth = vue.ref(0);
|
|
12614
|
+
const internalWidths = vue.ref({});
|
|
12615
|
+
const effectiveWidths = vue.computed(() => {
|
|
12616
|
+
if (props.columnWidths) return props.columnWidths;
|
|
12617
|
+
return internalWidths.value;
|
|
12618
|
+
});
|
|
12619
|
+
const sourceDisplayColumns = vue.computed(() => {
|
|
12620
|
+
const vis = props.columnVisibility;
|
|
12621
|
+
if (!vis) return props.columns;
|
|
12622
|
+
return props.columns.filter((c) => vis[c.key] !== false);
|
|
12623
|
+
});
|
|
12624
|
+
const detectedTypes = vue.ref({});
|
|
12625
|
+
const detectTypesDone = vue.ref(false);
|
|
12626
|
+
const detectedDisplayColumns = vue.computed(() => {
|
|
12627
|
+
if (!props.autoDetectTypes || Object.keys(detectedTypes.value).length === 0) {
|
|
12628
|
+
return sourceDisplayColumns.value;
|
|
12629
|
+
}
|
|
12630
|
+
return applyDetectedTableTypes(sourceDisplayColumns.value, detectedTypes.value);
|
|
12631
|
+
});
|
|
12632
|
+
const responsiveLeadingWidth = vue.computed(
|
|
12633
|
+
() => (props.rowDrag ? DRAG_COL_WIDTH : 0) + (props.seq ? SEQ_COL_WIDTH : 0) + (props.renderDetail !== void 0 ? EXPAND_COL_WIDTH : 0) + (props.selectable !== "none" ? SELECTION_COL_WIDTH : 0)
|
|
12634
|
+
);
|
|
12635
|
+
const responsiveWidthOf = (column) => {
|
|
12636
|
+
const width = effectiveWidths.value[column.key] ?? resolveInitialWidth(column);
|
|
12637
|
+
return Number.isFinite(width) && width >= 0 ? width : resolveInitialWidth(column);
|
|
12638
|
+
};
|
|
12639
|
+
const responsiveResult = vue.computed(
|
|
12640
|
+
() => props.responsive ? computeResponsiveTableColumns(
|
|
12641
|
+
detectedDisplayColumns.value,
|
|
12642
|
+
responsiveWidth.value,
|
|
12643
|
+
responsiveLeadingWidth.value,
|
|
12644
|
+
responsiveWidthOf
|
|
12645
|
+
) : { columns: detectedDisplayColumns.value, overflow: false }
|
|
12646
|
+
);
|
|
12647
|
+
const responsiveDisplayColumns = vue.computed(
|
|
12648
|
+
() => responsiveResult.value.columns
|
|
12649
|
+
);
|
|
12650
|
+
const responsiveOverflow = vue.computed(() => responsiveResult.value.overflow);
|
|
12651
|
+
const displayColumns = vue.computed(
|
|
12652
|
+
() => responsiveDisplayColumns.value
|
|
12653
|
+
);
|
|
12654
|
+
const grouped = vue.computed(
|
|
12655
|
+
() => displayColumns.value.some((c) => c.children && c.children.length > 0)
|
|
12656
|
+
);
|
|
10701
12657
|
const leafColumns = vue.computed(
|
|
10702
|
-
() => grouped.value ? core.flattenLeafColumns(
|
|
12658
|
+
() => grouped.value ? core.flattenLeafColumns(displayColumns.value) : displayColumns.value
|
|
12659
|
+
);
|
|
12660
|
+
const headerMatrix = vue.computed(
|
|
12661
|
+
() => grouped.value ? core.buildHeaderMatrix(displayColumns.value) : null
|
|
12662
|
+
);
|
|
12663
|
+
const remoteSort = vue.computed(() => props.proxyConfig?.remoteSort === true);
|
|
12664
|
+
const remoteFilter = vue.computed(() => props.proxyConfig?.remoteFilter === true);
|
|
12665
|
+
const proxyCtrl = useTableProxy({
|
|
12666
|
+
proxyConfig: () => props.proxyConfig,
|
|
12667
|
+
remoteSort,
|
|
12668
|
+
remoteFilter,
|
|
12669
|
+
multiSort: () => props.multiSort,
|
|
12670
|
+
sort: () => props.sort,
|
|
12671
|
+
defaultSort: props.defaultSort,
|
|
12672
|
+
multiSortState: () => props.multiSortState,
|
|
12673
|
+
defaultMultiSort: props.defaultMultiSort,
|
|
12674
|
+
filters: () => props.filters,
|
|
12675
|
+
filterValues: () => props.filterValues
|
|
12676
|
+
});
|
|
12677
|
+
const tableLoading = vue.computed(
|
|
12678
|
+
() => proxyCtrl.proxy.value ? proxyCtrl.state.value.loading : props.loading
|
|
12679
|
+
);
|
|
12680
|
+
const tableError = vue.computed(
|
|
12681
|
+
() => proxyCtrl.proxy.value ? proxyCtrl.state.value.error !== null : props.error
|
|
12682
|
+
);
|
|
12683
|
+
const handleRetry = () => {
|
|
12684
|
+
if (proxyCtrl.proxy.value) void proxyCtrl.proxy.value.refetch();
|
|
12685
|
+
props.onRetry?.();
|
|
12686
|
+
};
|
|
12687
|
+
const retry = vue.computed(() => proxyCtrl.proxy.value ? handleRetry : props.onRetry);
|
|
12688
|
+
const localRowsOverride = vue.ref(null);
|
|
12689
|
+
vue.watch(
|
|
12690
|
+
() => props.data,
|
|
12691
|
+
() => {
|
|
12692
|
+
if (localRowsOverride.value !== null) localRowsOverride.value = null;
|
|
12693
|
+
}
|
|
12694
|
+
);
|
|
12695
|
+
const tableData = vue.computed(
|
|
12696
|
+
() => proxyCtrl.proxy.value ? proxyCtrl.liveData.value : localRowsOverride.value ?? props.data ?? []
|
|
12697
|
+
);
|
|
12698
|
+
vue.watch(
|
|
12699
|
+
[() => props.autoDetectTypes, tableData, () => props.columns],
|
|
12700
|
+
() => {
|
|
12701
|
+
if (!props.autoDetectTypes || detectTypesDone.value || tableData.value.length === 0) return;
|
|
12702
|
+
detectTypesDone.value = true;
|
|
12703
|
+
const next = {};
|
|
12704
|
+
for (const column of core.flattenLeafColumns(props.columns)) {
|
|
12705
|
+
const candidate = column;
|
|
12706
|
+
if (candidate.formula) continue;
|
|
12707
|
+
next[column.key] = core.detectColumnType(
|
|
12708
|
+
tableData.value.map((row) => getCellValue(row, candidate))
|
|
12709
|
+
);
|
|
12710
|
+
}
|
|
12711
|
+
detectedTypes.value = next;
|
|
12712
|
+
},
|
|
12713
|
+
{ immediate: true }
|
|
10703
12714
|
);
|
|
10704
|
-
const headerMatrix = vue.computed(() => grouped.value ? core.buildHeaderMatrix(props.columns) : null);
|
|
10705
12715
|
const {
|
|
10706
12716
|
sortState: internalSort,
|
|
10707
12717
|
cycleSort,
|
|
12718
|
+
setSort,
|
|
10708
12719
|
sortComparator,
|
|
10709
|
-
sortedData: sortedRows
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
12720
|
+
sortedData: sortedRows,
|
|
12721
|
+
multiSortState,
|
|
12722
|
+
cycleMultiSort
|
|
12723
|
+
} = useTableSort(tableData, {
|
|
12724
|
+
leafColumns,
|
|
12725
|
+
sort: vue.computed(() => props.sort),
|
|
12726
|
+
defaultSort: props.defaultSort,
|
|
12727
|
+
onSortChange: (next) => {
|
|
12728
|
+
emit("update:sort", next);
|
|
12729
|
+
if (remoteSort.value) proxyCtrl.setParams({ sort: next });
|
|
12730
|
+
},
|
|
12731
|
+
multiSort: () => props.multiSort,
|
|
12732
|
+
multiSortState: () => props.multiSortState,
|
|
12733
|
+
defaultMultiSort: props.defaultMultiSort,
|
|
12734
|
+
onMultiSortChange: (next) => {
|
|
12735
|
+
emit("update:multiSortState", next);
|
|
12736
|
+
emit("multiSortChange", next);
|
|
12737
|
+
if (remoteSort.value) proxyCtrl.setParams({ sorts: next });
|
|
12738
|
+
}
|
|
12739
|
+
});
|
|
12740
|
+
const tableViews = createTableViewsController({
|
|
12741
|
+
config: () => props.views,
|
|
12742
|
+
sort: internalSort,
|
|
12743
|
+
setSort,
|
|
12744
|
+
onActiveViewChange: (key) => props.onActiveViewChange?.(key)
|
|
12745
|
+
});
|
|
12746
|
+
const sortedData = vue.computed(() => remoteSort.value ? tableData.value : sortedRows.value);
|
|
12747
|
+
vue.watch([internalSort, () => props.multiSort, remoteSort, () => proxyCtrl.proxy.value], () => {
|
|
12748
|
+
if (!proxyCtrl.proxy.value || !remoteSort.value || props.multiSort) return;
|
|
12749
|
+
proxyCtrl.setParams({ sort: internalSort.value });
|
|
12750
|
+
});
|
|
12751
|
+
vue.watch([multiSortState, () => props.multiSort, remoteSort, () => proxyCtrl.proxy.value], () => {
|
|
12752
|
+
if (!proxyCtrl.proxy.value || !remoteSort.value || !props.multiSort) return;
|
|
12753
|
+
proxyCtrl.setParams({ sorts: multiSortState.value });
|
|
12754
|
+
});
|
|
12755
|
+
const formDraft = vue.ref({});
|
|
12756
|
+
const formApplied = vue.ref({});
|
|
12757
|
+
const formFieldSignature = vue.computed(
|
|
12758
|
+
() => (props.formConfig?.fields ?? []).map((f) => `${f.key}=${f.defaultValue ?? ""}`).join("\0")
|
|
12759
|
+
);
|
|
12760
|
+
vue.watch(
|
|
12761
|
+
formFieldSignature,
|
|
12762
|
+
() => {
|
|
12763
|
+
formDraft.value = core.seedFormValues(props.formConfig?.fields);
|
|
12764
|
+
formApplied.value = {};
|
|
12765
|
+
},
|
|
12766
|
+
{ immediate: true }
|
|
12767
|
+
);
|
|
12768
|
+
const setFormValue = (key, value) => {
|
|
12769
|
+
if (formDraft.value[key] === value) return;
|
|
12770
|
+
formDraft.value = { ...formDraft.value, [key]: value };
|
|
12771
|
+
};
|
|
12772
|
+
const mergedProxyFilters = (form) => mergeFilterValues(core.mergeFormFilters(props.filters ?? {}, form), props.filterValues ?? {});
|
|
12773
|
+
const handleFormSubmit = () => {
|
|
12774
|
+
const values = core.buildFormValues(props.formConfig?.fields, formDraft.value);
|
|
12775
|
+
props.formConfig?.onSearch?.(values);
|
|
12776
|
+
formApplied.value = values;
|
|
12777
|
+
if (proxyCtrl.proxy.value) {
|
|
12778
|
+
proxyCtrl.setParams({ filters: mergedProxyFilters(values), page: 1 });
|
|
12779
|
+
}
|
|
12780
|
+
};
|
|
12781
|
+
const handleFormReset = () => {
|
|
12782
|
+
const defaults = core.seedFormValues(props.formConfig?.fields);
|
|
12783
|
+
formDraft.value = defaults;
|
|
12784
|
+
const values = core.buildFormValues(props.formConfig?.fields, defaults);
|
|
12785
|
+
formApplied.value = values;
|
|
12786
|
+
props.formConfig?.onReset?.(values);
|
|
12787
|
+
if (proxyCtrl.proxy.value) {
|
|
12788
|
+
if (!proxyCtrl.setParams({ filters: mergedProxyFilters(values), page: 1 })) {
|
|
12789
|
+
void proxyCtrl.refetch();
|
|
12790
|
+
}
|
|
10717
12791
|
}
|
|
12792
|
+
};
|
|
12793
|
+
vue.watch(
|
|
12794
|
+
[formApplied, () => props.filters, () => props.filterValues],
|
|
12795
|
+
() => {
|
|
12796
|
+
if (proxyCtrl.proxy.value && remoteFilter.value) {
|
|
12797
|
+
proxyCtrl.setParams({
|
|
12798
|
+
filters: mergedProxyFilters(formApplied.value)
|
|
12799
|
+
});
|
|
12800
|
+
}
|
|
12801
|
+
},
|
|
12802
|
+
{ immediate: true }
|
|
10718
12803
|
);
|
|
10719
12804
|
const selControlled = vue.computed(() => props.selection !== void 0);
|
|
10720
12805
|
const selectionModel = core.createSelectionModel({
|
|
@@ -10757,18 +12842,56 @@ var IrisTable = vue.defineComponent({
|
|
|
10757
12842
|
if (typeof v === "string" || typeof v === "number") return v;
|
|
10758
12843
|
return index;
|
|
10759
12844
|
};
|
|
10760
|
-
const treeMode = vue.computed(() => props.getSubRows !== void 0);
|
|
12845
|
+
const treeMode = vue.computed(() => props.getSubRows !== void 0 || props.lazyLoad !== void 0);
|
|
12846
|
+
const lazyChildren = vue.ref(/* @__PURE__ */ new Map());
|
|
12847
|
+
const lazyLoading = vue.ref(/* @__PURE__ */ new Set());
|
|
12848
|
+
let lazyEpoch = 0;
|
|
12849
|
+
vue.watch(
|
|
12850
|
+
() => proxyCtrl.proxy.value ? proxyCtrl.state.value.data : props.data,
|
|
12851
|
+
() => {
|
|
12852
|
+
lazyChildren.value = /* @__PURE__ */ new Map();
|
|
12853
|
+
lazyLoading.value = /* @__PURE__ */ new Set();
|
|
12854
|
+
lazyEpoch += 1;
|
|
12855
|
+
}
|
|
12856
|
+
);
|
|
12857
|
+
const lazyChildrenOf = (row) => {
|
|
12858
|
+
const key = String(row[props.rowKey]);
|
|
12859
|
+
return lazyChildren.value.get(key) ?? props.getSubRows?.(row);
|
|
12860
|
+
};
|
|
10761
12861
|
const flatTree = vue.computed(
|
|
10762
|
-
() => treeMode.value ? core.flattenTree(
|
|
12862
|
+
() => treeMode.value ? core.flattenTree(sortedData.value, {
|
|
10763
12863
|
getKey: (r) => String(r[props.rowKey]),
|
|
10764
12864
|
// With an active sort, sort each level's children by the same
|
|
10765
|
-
// comparator so the whole tree reorders hierarchically.
|
|
10766
|
-
|
|
12865
|
+
// comparator so the whole tree reorders hierarchically. Lazy-loaded
|
|
12866
|
+
// children win over `getSubRows` and still participate.
|
|
12867
|
+
getChildren: sortComparator.value ? core.withSortedChildren(lazyChildrenOf, sortComparator.value) : lazyChildrenOf,
|
|
10767
12868
|
isExpanded: (k) => expandedKeys.value.includes(k)
|
|
10768
12869
|
}) : null
|
|
10769
12870
|
);
|
|
12871
|
+
const filteredData = vue.computed(() => {
|
|
12872
|
+
if (remoteFilter.value) return sortedData.value;
|
|
12873
|
+
const merged = proxyCtrl.proxy.value ? props.filters ?? {} : core.mergeFormFilters(props.filters ?? {}, formApplied.value);
|
|
12874
|
+
const active = Object.entries(merged).filter(([, v]) => v != null && v !== "");
|
|
12875
|
+
const checkedEntries = Object.entries(props.filterValues ?? {}).filter(
|
|
12876
|
+
([, values]) => values.length > 0
|
|
12877
|
+
);
|
|
12878
|
+
if (active.length === 0 && checkedEntries.length === 0) return sortedData.value;
|
|
12879
|
+
return sortedData.value.filter((row) => {
|
|
12880
|
+
const textOk = active.every(([key, value]) => {
|
|
12881
|
+
const col = displayColumns.value.find((c) => c.key === key);
|
|
12882
|
+
if (!col) return true;
|
|
12883
|
+
return String(getCellValue(row, col) ?? "").toLowerCase().includes(value.toLowerCase());
|
|
12884
|
+
});
|
|
12885
|
+
const setsOk = checkedEntries.every(([key, values]) => {
|
|
12886
|
+
const col = displayColumns.value.find((c) => c.key === key);
|
|
12887
|
+
if (!col) return true;
|
|
12888
|
+
return values.includes(String(getCellValue(row, col) ?? ""));
|
|
12889
|
+
});
|
|
12890
|
+
return textOk && setsOk;
|
|
12891
|
+
});
|
|
12892
|
+
});
|
|
10770
12893
|
const bodyData = vue.computed(
|
|
10771
|
-
() => flatTree.value ? flatTree.value.map((t2) => t2.row) :
|
|
12894
|
+
() => flatTree.value ? flatTree.value.map((t2) => t2.row) : filteredData.value
|
|
10772
12895
|
);
|
|
10773
12896
|
const cascadingTreeSelection = vue.computed(
|
|
10774
12897
|
() => props.treeSelectionCascade && props.selectable === "multi" && treeMode.value
|
|
@@ -10790,7 +12913,7 @@ var IrisTable = vue.defineComponent({
|
|
|
10790
12913
|
if (children && children.length > 0) walk(children, key);
|
|
10791
12914
|
}
|
|
10792
12915
|
};
|
|
10793
|
-
walk(
|
|
12916
|
+
walk(sortedData.value);
|
|
10794
12917
|
return nodes;
|
|
10795
12918
|
});
|
|
10796
12919
|
const compactTreeSelectionSeed = (keys) => {
|
|
@@ -10863,25 +12986,27 @@ var IrisTable = vue.defineComponent({
|
|
|
10863
12986
|
selectionModel.set([...allRowIds.value]);
|
|
10864
12987
|
};
|
|
10865
12988
|
const editingCellId = vue.ref(null);
|
|
12989
|
+
const editingColumnKey = vue.ref(null);
|
|
10866
12990
|
const editingDraft = vue.ref("");
|
|
10867
12991
|
const editError = vue.ref(null);
|
|
10868
12992
|
const editorInputRef = vue.ref(null);
|
|
10869
|
-
const cellId = (rowIdent, colKey) => `${rowIdent}::${colKey}`;
|
|
10870
12993
|
const beginEdit = (row, column, rowIdent) => {
|
|
10871
12994
|
if (!column.editable) return;
|
|
10872
12995
|
editingCellId.value = cellId(rowIdent, column.key);
|
|
10873
|
-
|
|
12996
|
+
editingColumnKey.value = column.key;
|
|
12997
|
+
const current = getCellValue(row, column);
|
|
10874
12998
|
editingDraft.value = current == null ? "" : String(current);
|
|
10875
12999
|
editError.value = null;
|
|
10876
13000
|
void vue.nextTick(() => editorInputRef.value?.focus());
|
|
10877
13001
|
};
|
|
10878
13002
|
const commitEdit = (row, column, rowIndex) => {
|
|
10879
13003
|
if (editingCellId.value === null) return;
|
|
10880
|
-
const oldValue =
|
|
13004
|
+
const oldValue = getCellValue(row, column);
|
|
10881
13005
|
const draft = editingDraft.value;
|
|
10882
13006
|
const newValue = column.editor === "number" ? draft === "" || Number.isNaN(Number(draft)) ? oldValue : Number(draft) : draft;
|
|
10883
13007
|
if (column.editRules && column.editRules.length > 0) {
|
|
10884
|
-
|
|
13008
|
+
const context = { rows: tableData.value, columnKey: column.key };
|
|
13009
|
+
core.validateEditRulesAsync(column.editRules, draft, row, false, context).then((r) => {
|
|
10885
13010
|
if (!r.valid) {
|
|
10886
13011
|
editError.value = r.messages[0] ?? null;
|
|
10887
13012
|
return;
|
|
@@ -10904,67 +13029,272 @@ var IrisTable = vue.defineComponent({
|
|
|
10904
13029
|
emit("cellEdit", { row, column, oldValue, newValue, rowIndex });
|
|
10905
13030
|
}
|
|
10906
13031
|
};
|
|
13032
|
+
const writeCellValue = (row, column, rowIndex, oldValue, newValue) => {
|
|
13033
|
+
if (newValue === oldValue) return;
|
|
13034
|
+
emit("cellEdit", { row, column, oldValue, newValue, rowIndex });
|
|
13035
|
+
if (proxyCtrl.proxy.value) {
|
|
13036
|
+
const id = rowId(row, rowIndex);
|
|
13037
|
+
const idx = proxyCtrl.liveData.value.findIndex((r, i) => rowId(r, i) === id);
|
|
13038
|
+
if (idx >= 0) {
|
|
13039
|
+
const key = column.dataIndex ?? column.key;
|
|
13040
|
+
const next = { ...proxyCtrl.liveData.value[idx], [key]: newValue };
|
|
13041
|
+
proxyCtrl.liveData.value = [
|
|
13042
|
+
...proxyCtrl.liveData.value.slice(0, idx),
|
|
13043
|
+
next,
|
|
13044
|
+
...proxyCtrl.liveData.value.slice(idx + 1)
|
|
13045
|
+
];
|
|
13046
|
+
}
|
|
13047
|
+
}
|
|
13048
|
+
};
|
|
10907
13049
|
const finishCommit = (row, column, rowIndex, oldValue, newValue) => {
|
|
10908
13050
|
editError.value = null;
|
|
10909
13051
|
editingCellId.value = null;
|
|
10910
|
-
|
|
10911
|
-
|
|
13052
|
+
editingColumnKey.value = null;
|
|
13053
|
+
writeCellValue(row, column, rowIndex, oldValue, newValue);
|
|
13054
|
+
};
|
|
13055
|
+
const cancelEdit = () => {
|
|
13056
|
+
editError.value = null;
|
|
13057
|
+
editingCellId.value = null;
|
|
13058
|
+
editingColumnKey.value = null;
|
|
13059
|
+
};
|
|
13060
|
+
const rowMode = vue.computed(() => props.editConfig?.mode === "row");
|
|
13061
|
+
const rowSessions = vue.ref(/* @__PURE__ */ new Map());
|
|
13062
|
+
const rowEditing = vue.ref(null);
|
|
13063
|
+
const rowEditorRefs = /* @__PURE__ */ new Map();
|
|
13064
|
+
const currentRowFor = (k) => bodyData.value.find((r, i) => rowId(r, i) === k);
|
|
13065
|
+
const beginRowEdit = (row, rowIndex, focusColKey) => {
|
|
13066
|
+
const k = rowId(row, rowIndex);
|
|
13067
|
+
const editableCols = leafColumns.value.filter((c) => c.editable);
|
|
13068
|
+
if (editableCols.length === 0) return;
|
|
13069
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
13070
|
+
for (const col of editableCols) {
|
|
13071
|
+
const current = getCellValue(row, col);
|
|
13072
|
+
sessions.set(cellId(k, col.key), {
|
|
13073
|
+
draft: current == null ? "" : String(current),
|
|
13074
|
+
error: null
|
|
13075
|
+
});
|
|
13076
|
+
}
|
|
13077
|
+
rowSessions.value = sessions;
|
|
13078
|
+
rowEditing.value = { k, idx: rowIndex };
|
|
13079
|
+
const focusKey = focusColKey && editableCols.some((c) => c.key === focusColKey) ? focusColKey : editableCols[0].key;
|
|
13080
|
+
void vue.nextTick(() => rowEditorRefs.get(focusKey)?.focus());
|
|
13081
|
+
};
|
|
13082
|
+
const commitRowSession = (k, column, rowIndex, id) => {
|
|
13083
|
+
const session = rowSessions.value.get(id);
|
|
13084
|
+
if (!session) return;
|
|
13085
|
+
const row = currentRowFor(k);
|
|
13086
|
+
if (!row) return;
|
|
13087
|
+
const oldValue = getCellValue(row, column);
|
|
13088
|
+
const draft = session.draft;
|
|
13089
|
+
const newValue = column.editor === "number" ? draft === "" || Number.isNaN(Number(draft)) ? oldValue : Number(draft) : draft;
|
|
13090
|
+
if (column.editRules && column.editRules.length > 0) {
|
|
13091
|
+
const context = { rows: tableData.value, columnKey: column.key };
|
|
13092
|
+
core.validateEditRulesAsync(column.editRules, draft, row, false, context).then((r) => {
|
|
13093
|
+
if (!rowSessions.value.has(id)) return;
|
|
13094
|
+
if (!r.valid) {
|
|
13095
|
+
const s = rowSessions.value.get(id);
|
|
13096
|
+
if (s) s.error = r.messages[0] ?? null;
|
|
13097
|
+
return;
|
|
13098
|
+
}
|
|
13099
|
+
finishRowCommit(row, column, rowIndex, oldValue, newValue, id);
|
|
13100
|
+
});
|
|
13101
|
+
return;
|
|
13102
|
+
}
|
|
13103
|
+
if (column.validate) {
|
|
13104
|
+
const error = column.validate(newValue, row);
|
|
13105
|
+
if (error) {
|
|
13106
|
+
const s = rowSessions.value.get(id);
|
|
13107
|
+
if (s) s.error = error;
|
|
13108
|
+
return;
|
|
13109
|
+
}
|
|
13110
|
+
}
|
|
13111
|
+
finishRowCommit(row, column, rowIndex, oldValue, newValue, id);
|
|
13112
|
+
};
|
|
13113
|
+
const finishRowCommit = (row, column, rowIndex, oldValue, newValue, id) => {
|
|
13114
|
+
rowSessions.value.delete(id);
|
|
13115
|
+
if (rowSessions.value.size === 0) rowEditing.value = null;
|
|
13116
|
+
writeCellValue(row, column, rowIndex, oldValue, newValue);
|
|
13117
|
+
};
|
|
13118
|
+
const cancelRowEdit = () => {
|
|
13119
|
+
rowSessions.value = /* @__PURE__ */ new Map();
|
|
13120
|
+
rowEditing.value = null;
|
|
13121
|
+
};
|
|
13122
|
+
const switchRowEdit = (row, rowIndex, focusColKey) => {
|
|
13123
|
+
const editing = rowEditing.value;
|
|
13124
|
+
if (editing !== null) {
|
|
13125
|
+
for (const [id] of rowSessions.value) {
|
|
13126
|
+
const colKey = id.slice(id.indexOf("::") + 2);
|
|
13127
|
+
const col = leafColumns.value.find((c) => c.key === colKey);
|
|
13128
|
+
if (!col) continue;
|
|
13129
|
+
commitRowSession(editing.k, col, editing.idx, id);
|
|
13130
|
+
if (rowSessions.value.get(id)?.error != null) return;
|
|
13131
|
+
}
|
|
13132
|
+
}
|
|
13133
|
+
beginRowEdit(row, rowIndex, focusColKey);
|
|
13134
|
+
};
|
|
13135
|
+
const handleRowModeCellClick = (row, col, index, k) => {
|
|
13136
|
+
if (rowEditing.value?.k === k) {
|
|
13137
|
+
const id = cellId(k, col.key);
|
|
13138
|
+
if (col.editable && !rowSessions.value.has(id)) {
|
|
13139
|
+
const current = getCellValue(row, col);
|
|
13140
|
+
rowSessions.value.set(id, {
|
|
13141
|
+
draft: current == null ? "" : String(current),
|
|
13142
|
+
error: null
|
|
13143
|
+
});
|
|
13144
|
+
void vue.nextTick(() => rowEditorRefs.get(col.key)?.focus());
|
|
13145
|
+
}
|
|
13146
|
+
} else {
|
|
13147
|
+
switchRowEdit(row, index, col.key);
|
|
10912
13148
|
}
|
|
10913
13149
|
};
|
|
10914
|
-
const
|
|
10915
|
-
|
|
10916
|
-
|
|
13150
|
+
const editorRenderContext = {
|
|
13151
|
+
rowEditorRefs,
|
|
13152
|
+
editorInputRef,
|
|
13153
|
+
editingDraft,
|
|
13154
|
+
editError,
|
|
13155
|
+
commitEdit,
|
|
13156
|
+
cancelEdit,
|
|
13157
|
+
commitRowSession,
|
|
13158
|
+
cancelRowEdit,
|
|
13159
|
+
editPreview: props.editPreview,
|
|
13160
|
+
previewValue: (row, col, draft) => {
|
|
13161
|
+
const raw = col.editor === "number" ? draft === "" || Number.isNaN(Number(draft)) ? getCellValue(row, col) : Number(draft) : draft;
|
|
13162
|
+
return col.formatter?.(core.applyTableMask(raw, col), row) ?? "";
|
|
13163
|
+
}
|
|
10917
13164
|
};
|
|
10918
|
-
const
|
|
13165
|
+
const buildRowSessionContent = (row, col, index, k, editCellId, session) => renderRowSessionContent(editorRenderContext, row, col, index, k, editCellId, session);
|
|
13166
|
+
const buildCellEditContent = (row, col, index, editCellId) => renderCellEditContent(editorRenderContext, row, col, index, editCellId);
|
|
13167
|
+
const buildTreeIndent = (treeMeta, row) => vue.h(
|
|
13168
|
+
"span",
|
|
13169
|
+
{
|
|
13170
|
+
"data-iris-table-tree-indent": "",
|
|
13171
|
+
style: {
|
|
13172
|
+
display: "inline-flex",
|
|
13173
|
+
alignItems: "center",
|
|
13174
|
+
flex: "none",
|
|
13175
|
+
paddingLeft: `${treeMeta.depth * 16}px`
|
|
13176
|
+
}
|
|
13177
|
+
},
|
|
13178
|
+
treeMeta.hasChildren || props.lazyLoad !== void 0 && !lazyChildren.value.has(treeMeta.key) ? [
|
|
13179
|
+
vue.h(
|
|
13180
|
+
"button",
|
|
13181
|
+
{
|
|
13182
|
+
type: "button",
|
|
13183
|
+
"data-iris-table-tree-toggle": "",
|
|
13184
|
+
"data-iris-tree-loading": lazyLoading.value.has(treeMeta.key) ? "" : void 0,
|
|
13185
|
+
"aria-expanded": treeMeta.expanded ? "true" : "false",
|
|
13186
|
+
"aria-label": t(treeMeta.expanded ? "treeSelect.collapse" : "treeSelect.expand"),
|
|
13187
|
+
onClick: (e) => {
|
|
13188
|
+
e.stopPropagation();
|
|
13189
|
+
if (treeMeta.hasChildren) {
|
|
13190
|
+
expansion.toggle(treeMeta.key);
|
|
13191
|
+
return;
|
|
13192
|
+
}
|
|
13193
|
+
if (lazyLoading.value.has(treeMeta.key)) return;
|
|
13194
|
+
lazyLoading.value = new Set(lazyLoading.value).add(treeMeta.key);
|
|
13195
|
+
const clearLoading = () => {
|
|
13196
|
+
const next = new Set(lazyLoading.value);
|
|
13197
|
+
next.delete(treeMeta.key);
|
|
13198
|
+
lazyLoading.value = next;
|
|
13199
|
+
};
|
|
13200
|
+
try {
|
|
13201
|
+
const epoch = lazyEpoch;
|
|
13202
|
+
props.lazyLoad(row, (children) => {
|
|
13203
|
+
if (epoch !== lazyEpoch) return;
|
|
13204
|
+
lazyChildren.value.set(treeMeta.key, children);
|
|
13205
|
+
if (children && children.length > 0) {
|
|
13206
|
+
expansion.toggle(treeMeta.key);
|
|
13207
|
+
}
|
|
13208
|
+
clearLoading();
|
|
13209
|
+
});
|
|
13210
|
+
} catch {
|
|
13211
|
+
clearLoading();
|
|
13212
|
+
}
|
|
13213
|
+
},
|
|
13214
|
+
style: {
|
|
13215
|
+
border: "none",
|
|
13216
|
+
background: "transparent",
|
|
13217
|
+
cursor: "pointer",
|
|
13218
|
+
padding: "0",
|
|
13219
|
+
marginRight: "4px",
|
|
13220
|
+
font: "inherit",
|
|
13221
|
+
color: "var(--iris-foreground)",
|
|
13222
|
+
transform: treeMeta.expanded ? "rotate(90deg)" : "none",
|
|
13223
|
+
transition: "transform 150ms"
|
|
13224
|
+
}
|
|
13225
|
+
},
|
|
13226
|
+
"\u25B6"
|
|
13227
|
+
)
|
|
13228
|
+
] : [
|
|
13229
|
+
vue.h("span", {
|
|
13230
|
+
"aria-hidden": "true",
|
|
13231
|
+
style: { display: "inline-block", width: "16px" }
|
|
13232
|
+
})
|
|
13233
|
+
]
|
|
13234
|
+
);
|
|
10919
13235
|
vue.watch(
|
|
10920
13236
|
() => leafColumns.value,
|
|
10921
13237
|
(cols) => {
|
|
10922
13238
|
const seeded = { ...internalWidths.value };
|
|
13239
|
+
let changed = false;
|
|
10923
13240
|
for (const col of cols) {
|
|
10924
|
-
if (seeded[col.key] === void 0)
|
|
13241
|
+
if (seeded[col.key] === void 0) {
|
|
13242
|
+
seeded[col.key] = resolveInitialWidth(col);
|
|
13243
|
+
changed = true;
|
|
13244
|
+
}
|
|
10925
13245
|
}
|
|
10926
|
-
internalWidths.value = seeded;
|
|
13246
|
+
if (changed) internalWidths.value = seeded;
|
|
10927
13247
|
},
|
|
10928
13248
|
{ immediate: true, deep: false }
|
|
10929
13249
|
);
|
|
10930
|
-
const effectiveWidths = vue.computed(() => {
|
|
10931
|
-
if (props.columnWidths) return props.columnWidths;
|
|
10932
|
-
return internalWidths.value;
|
|
10933
|
-
});
|
|
10934
13250
|
const setColumnWidths = (next) => {
|
|
10935
13251
|
if (props.columnWidths === void 0) internalWidths.value = next;
|
|
10936
13252
|
emit("update:columnWidths", next);
|
|
10937
13253
|
};
|
|
10938
13254
|
const onHeaderClick = (column) => {
|
|
10939
|
-
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
const
|
|
10945
|
-
|
|
10946
|
-
const color = isActive ? "var(--iris-primary)" : "var(--iris-muted)";
|
|
13255
|
+
if (props.multiSort) cycleMultiSort(column);
|
|
13256
|
+
else cycleSort(column);
|
|
13257
|
+
};
|
|
13258
|
+
const multiSortSeq = (col) => {
|
|
13259
|
+
if (!props.multiSort) return null;
|
|
13260
|
+
const idx = multiSortState.value.findIndex((s) => s.key === col.key);
|
|
13261
|
+
if (idx <= 0) return null;
|
|
10947
13262
|
return vue.h(
|
|
10948
13263
|
"span",
|
|
10949
13264
|
{
|
|
10950
|
-
"
|
|
13265
|
+
"data-iris-sort-seq": "",
|
|
10951
13266
|
style: {
|
|
10952
|
-
display: "inline-flex",
|
|
10953
|
-
flexDirection: "column",
|
|
10954
13267
|
marginInlineStart: "var(--iris-space-xxs, 4px)",
|
|
10955
|
-
lineHeight: "0.6",
|
|
10956
13268
|
fontSize: "var(--iris-font-size-xs, 12px)",
|
|
10957
|
-
color
|
|
13269
|
+
color: "var(--iris-muted)"
|
|
10958
13270
|
}
|
|
10959
13271
|
},
|
|
10960
|
-
|
|
10961
|
-
vue.h("span", { style: { opacity: direction === "asc" ? "1" : "0.45" } }, "\u25B2"),
|
|
10962
|
-
vue.h("span", { style: { opacity: direction === "desc" ? "1" : "0.45" } }, "\u25BC")
|
|
10963
|
-
]
|
|
13272
|
+
String(idx + 1)
|
|
10964
13273
|
);
|
|
10965
13274
|
};
|
|
13275
|
+
const ariaSortFor = (col) => {
|
|
13276
|
+
const state = props.multiSort ? multiSortState.value.find((s) => s.key === col.key) ?? null : internalSort.value;
|
|
13277
|
+
if (state?.key === col.key) return state.direction === "asc" ? "ascending" : "descending";
|
|
13278
|
+
return col.sortable ? "none" : void 0;
|
|
13279
|
+
};
|
|
13280
|
+
const sortIndicator = (col) => renderTableSortIndicator(col, {
|
|
13281
|
+
multiSort: props.multiSort,
|
|
13282
|
+
multiSortState: multiSortState.value,
|
|
13283
|
+
sort: internalSort.value
|
|
13284
|
+
});
|
|
13285
|
+
const renderFilterTrigger = (col, leaf) => renderTableFilterTrigger({
|
|
13286
|
+
column: col,
|
|
13287
|
+
leaf,
|
|
13288
|
+
active: (props.filterValues?.[col.key]?.length ?? 0) > 0,
|
|
13289
|
+
open: filterPanelState.value?.open === true && filterPanelState.value.colKey === col.key,
|
|
13290
|
+
label: t("table.filter"),
|
|
13291
|
+
onOpen: openFilterPanel
|
|
13292
|
+
});
|
|
13293
|
+
const leadTrackCount = () => (props.rowDrag ? 1 : 0) + (props.seq ? 1 : 0) + (hasDetail.value ? 1 : 0) + (props.selectable !== "none" ? 1 : 0);
|
|
10966
13294
|
const gridTemplate = vue.computed(() => {
|
|
10967
13295
|
const parts = [];
|
|
13296
|
+
if (props.rowDrag) parts.push(`${DRAG_COL_WIDTH}px`);
|
|
13297
|
+
if (props.seq) parts.push(`${SEQ_COL_WIDTH}px`);
|
|
10968
13298
|
if (hasDetail.value) parts.push(`${EXPAND_COL_WIDTH}px`);
|
|
10969
13299
|
if (props.selectable !== "none") parts.push(`${SELECTION_COL_WIDTH}px`);
|
|
10970
13300
|
for (const col of leafColumns.value) {
|
|
@@ -10979,70 +13309,45 @@ var IrisTable = vue.defineComponent({
|
|
|
10979
13309
|
cellRangeState.value = s;
|
|
10980
13310
|
})
|
|
10981
13311
|
);
|
|
10982
|
-
const isInRange = (row, col) => {
|
|
10983
|
-
const { anchor, active } = cellRangeState.value;
|
|
10984
|
-
if (!anchor || !active) return false;
|
|
10985
|
-
const minRow = Math.min(anchor.row, active.row);
|
|
10986
|
-
const maxRow = Math.max(anchor.row, active.row);
|
|
10987
|
-
const minCol = Math.min(anchor.col, active.col);
|
|
10988
|
-
const maxCol = Math.max(anchor.col, active.col);
|
|
10989
|
-
return row >= minRow && row <= maxRow && col >= minCol && col <= maxCol;
|
|
10990
|
-
};
|
|
10991
13312
|
const rootRef = vue.ref(null);
|
|
13313
|
+
let responsiveObserver = null;
|
|
13314
|
+
const measureResponsiveWidth = () => {
|
|
13315
|
+
responsiveWidth.value = props.responsive && rootRef.value ? rootRef.value.clientWidth : 0;
|
|
13316
|
+
};
|
|
13317
|
+
const updateResponsiveObserver = () => {
|
|
13318
|
+
responsiveObserver?.disconnect();
|
|
13319
|
+
responsiveObserver = null;
|
|
13320
|
+
responsiveWidth.value = 0;
|
|
13321
|
+
if (!props.responsive || !rootRef.value || typeof ResizeObserver === "undefined") return;
|
|
13322
|
+
measureResponsiveWidth();
|
|
13323
|
+
responsiveObserver = new ResizeObserver(measureResponsiveWidth);
|
|
13324
|
+
responsiveObserver.observe(rootRef.value);
|
|
13325
|
+
};
|
|
13326
|
+
vue.onMounted(updateResponsiveObserver);
|
|
13327
|
+
vue.watch(() => props.responsive, updateResponsiveObserver);
|
|
13328
|
+
vue.onBeforeUnmount(() => {
|
|
13329
|
+
responsiveObserver?.disconnect();
|
|
13330
|
+
responsiveObserver = null;
|
|
13331
|
+
});
|
|
13332
|
+
const rowTarget = createTableRowTarget(() => rootRef.value);
|
|
13333
|
+
const { scrollTo: scrollToRow, goTo: goToRow } = rowTarget;
|
|
13334
|
+
vue.onBeforeUnmount(rowTarget.dispose);
|
|
10992
13335
|
const focusedCell = vue.ref(null);
|
|
10993
|
-
const
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
const target = e.target;
|
|
11006
|
-
if (target.dataset.gridRow === void 0) return;
|
|
11007
|
-
e.preventDefault();
|
|
11008
|
-
const current = focusedCell.value ?? { row: 0, col: 0 };
|
|
11009
|
-
const next = core.nextGridCell(current, e.key, {
|
|
11010
|
-
rowCount: bodyData.value.length,
|
|
11011
|
-
colCount: leafColumns.value.length,
|
|
11012
|
-
pageSize: 10
|
|
11013
|
-
});
|
|
11014
|
-
focusedCell.value = next;
|
|
11015
|
-
const cell = rootRef.value?.querySelector(
|
|
11016
|
-
`[data-grid-row="${next.row}"][data-grid-col="${next.col}"]`
|
|
11017
|
-
);
|
|
11018
|
-
cell?.focus();
|
|
11019
|
-
};
|
|
11020
|
-
const CELL_RANGE_ARROW_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"]);
|
|
11021
|
-
const handleCellRangeKey = (e) => {
|
|
11022
|
-
if (!props.cellRange) return;
|
|
11023
|
-
if (e.key === "Escape") {
|
|
11024
|
-
cellRangeCtrl.clearRange();
|
|
11025
|
-
return;
|
|
11026
|
-
}
|
|
11027
|
-
if (!e.shiftKey || !CELL_RANGE_ARROW_KEYS.has(e.key)) return;
|
|
11028
|
-
const target = e.target;
|
|
11029
|
-
const rowAttr = target.dataset.irisCellRow;
|
|
11030
|
-
const colAttr = target.dataset.irisCellCol;
|
|
11031
|
-
if (rowAttr === void 0 || colAttr === void 0) return;
|
|
11032
|
-
e.preventDefault();
|
|
11033
|
-
const anchor = cellRangeCtrl.getState().anchor;
|
|
11034
|
-
const active = anchor ? cellRangeCtrl.getState().active ?? { row: Number(rowAttr), col: Number(colAttr) } : { row: Number(rowAttr), col: Number(colAttr) };
|
|
11035
|
-
let nextRow = active.row;
|
|
11036
|
-
let nextCol = active.col;
|
|
11037
|
-
if (e.key === "ArrowUp") nextRow = Math.max(0, nextRow - 1);
|
|
11038
|
-
else if (e.key === "ArrowDown") nextRow = Math.min(bodyData.value.length - 1, nextRow + 1);
|
|
11039
|
-
else if (e.key === "ArrowLeft") nextCol = Math.max(0, nextCol - 1);
|
|
11040
|
-
else nextCol = Math.min(leafColumns.value.length - 1, nextCol + 1);
|
|
11041
|
-
cellRangeCtrl.extendRange(nextRow, nextCol);
|
|
11042
|
-
};
|
|
13336
|
+
const keyboard = createTableKeyboard({
|
|
13337
|
+
keyboardNavigation: () => props.keyboardNavigation,
|
|
13338
|
+
cellRange: () => props.cellRange,
|
|
13339
|
+
clipConfig: () => props.clipConfig,
|
|
13340
|
+
rows: () => bodyData.value,
|
|
13341
|
+
columns: () => leafColumns.value,
|
|
13342
|
+
root: () => rootRef.value,
|
|
13343
|
+
focused: focusedCell,
|
|
13344
|
+
range: cellRangeCtrl,
|
|
13345
|
+
rangeState: cellRangeState
|
|
13346
|
+
});
|
|
13347
|
+
const { handleRootKeyDown, isInRange, activeCellRange, copyActiveRange } = keyboard;
|
|
11043
13348
|
const scrollLeft = vue.ref(0);
|
|
11044
13349
|
const viewportWidth = vue.ref(0);
|
|
11045
|
-
const colTrack = (i) => (
|
|
13350
|
+
const colTrack = (i) => leadTrackCount() + 1 + i;
|
|
11046
13351
|
if (typeof ResizeObserver !== "undefined") {
|
|
11047
13352
|
let ro = null;
|
|
11048
13353
|
vue.onMounted(() => {
|
|
@@ -11059,27 +13364,19 @@ var IrisTable = vue.defineComponent({
|
|
|
11059
13364
|
ro = null;
|
|
11060
13365
|
});
|
|
11061
13366
|
}
|
|
11062
|
-
const visibleColSet = vue.computed(
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
});
|
|
11072
|
-
const set = /* @__PURE__ */ new Set();
|
|
11073
|
-
for (let i = w.startIndex; i <= w.endIndex; i += 1) set.add(i);
|
|
11074
|
-
cols.forEach((col, i) => {
|
|
11075
|
-
if (col.pinned) set.add(i);
|
|
11076
|
-
});
|
|
11077
|
-
return set;
|
|
11078
|
-
});
|
|
13367
|
+
const visibleColSet = vue.computed(
|
|
13368
|
+
() => computeVisibleColSet(
|
|
13369
|
+
props.columnVirtualization,
|
|
13370
|
+
leafColumns.value,
|
|
13371
|
+
scrollLeft.value,
|
|
13372
|
+
viewportWidth.value,
|
|
13373
|
+
effectiveWidths.value
|
|
13374
|
+
)
|
|
13375
|
+
);
|
|
11079
13376
|
const pinnedOffsets = vue.computed(() => {
|
|
11080
13377
|
const map = {};
|
|
11081
13378
|
const widthOf = (col) => effectiveWidths.value[col.key] ?? resolveInitialWidth(col);
|
|
11082
|
-
let left = (hasDetail.value ? EXPAND_COL_WIDTH : 0) + (props.selectable !== "none" ? SELECTION_COL_WIDTH : 0);
|
|
13379
|
+
let left = (props.rowDrag ? DRAG_COL_WIDTH : 0) + (props.seq ? SEQ_COL_WIDTH : 0) + (hasDetail.value ? EXPAND_COL_WIDTH : 0) + (props.selectable !== "none" ? SELECTION_COL_WIDTH : 0);
|
|
11083
13380
|
for (const col of leafColumns.value) {
|
|
11084
13381
|
if (col.pinned === "left") {
|
|
11085
13382
|
map[col.key] = { side: "left", offset: left };
|
|
@@ -11135,126 +13432,449 @@ var IrisTable = vue.defineComponent({
|
|
|
11135
13432
|
}
|
|
11136
13433
|
});
|
|
11137
13434
|
};
|
|
13435
|
+
const pinnedDragHandle = createTablePinnedDrag({
|
|
13436
|
+
enabled: () => props.pinnedDrag === true,
|
|
13437
|
+
columns: () => leafColumns.value,
|
|
13438
|
+
widthOf: (column) => effectiveWidths.value[column.key] ?? resolveInitialWidth(column),
|
|
13439
|
+
onColumnPinnedChange: props.onColumnPinnedChange,
|
|
13440
|
+
onPinnedCountChange: props.onPinnedCountChange
|
|
13441
|
+
});
|
|
13442
|
+
const rowDragCtrl = core.createSortable();
|
|
13443
|
+
const rowDragState = vue.shallowRef(rowDragCtrl.getState());
|
|
13444
|
+
vue.onBeforeUnmount(
|
|
13445
|
+
rowDragCtrl.subscribe((s) => {
|
|
13446
|
+
rowDragState.value = s;
|
|
13447
|
+
})
|
|
13448
|
+
);
|
|
13449
|
+
const colDragCtrl = core.createSortable();
|
|
13450
|
+
const colDragState = vue.shallowRef(colDragCtrl.getState());
|
|
13451
|
+
vue.onBeforeUnmount(
|
|
13452
|
+
colDragCtrl.subscribe((s) => {
|
|
13453
|
+
colDragState.value = s;
|
|
13454
|
+
})
|
|
13455
|
+
);
|
|
13456
|
+
const rowRectsRef = vue.ref([]);
|
|
13457
|
+
const colRectsRef = vue.ref([]);
|
|
13458
|
+
const handleRowDragPointerDown = (e, rowId2) => {
|
|
13459
|
+
if (!props.rowDrag || e.button !== 0) return;
|
|
13460
|
+
e.preventDefault();
|
|
13461
|
+
rowDragCtrl.press(rowId2, e.clientX, e.clientY);
|
|
13462
|
+
};
|
|
13463
|
+
const handleRowDragPointerMove = (e) => {
|
|
13464
|
+
if (!props.rowDrag) return;
|
|
13465
|
+
if (rowDragCtrl.isPending()) {
|
|
13466
|
+
const started = rowDragCtrl.tryStart(e.clientX, e.clientY);
|
|
13467
|
+
if (started) {
|
|
13468
|
+
const rects = [];
|
|
13469
|
+
rootRef.value?.querySelectorAll("[data-iris-row-drag-handle]").forEach((el) => {
|
|
13470
|
+
const r = el.getBoundingClientRect();
|
|
13471
|
+
const id = el.getAttribute("data-iris-row-drag-handle");
|
|
13472
|
+
if (id) rects.push({ id, left: r.left, top: r.top, width: r.width, height: r.height });
|
|
13473
|
+
});
|
|
13474
|
+
rowRectsRef.value = rects;
|
|
13475
|
+
}
|
|
13476
|
+
}
|
|
13477
|
+
if (rowDragCtrl.getState().activeId !== null) {
|
|
13478
|
+
rowDragCtrl.moveOver({ x: e.clientX, y: e.clientY }, rowRectsRef.value);
|
|
13479
|
+
}
|
|
13480
|
+
};
|
|
13481
|
+
const handleRowDragPointerUp = () => {
|
|
13482
|
+
if (!props.rowDrag) return;
|
|
13483
|
+
if (rowDragCtrl.isPending()) {
|
|
13484
|
+
rowDragCtrl.cancel();
|
|
13485
|
+
return;
|
|
13486
|
+
}
|
|
13487
|
+
const { activeId, overId } = rowDragCtrl.end();
|
|
13488
|
+
if (activeId !== null && overId !== null && activeId !== overId) {
|
|
13489
|
+
const rows = [...bodyData.value];
|
|
13490
|
+
const from = rows.findIndex((r, i) => String(rowId(r, i)) === activeId);
|
|
13491
|
+
const to = rows.findIndex((r, i) => String(rowId(r, i)) === overId);
|
|
13492
|
+
if (from >= 0 && to >= 0 && from !== to) {
|
|
13493
|
+
const [moved] = rows.splice(from, 1);
|
|
13494
|
+
rows.splice(to, 0, moved);
|
|
13495
|
+
if (proxyCtrl.proxy.value) proxyCtrl.liveData.value = rows;
|
|
13496
|
+
else localRowsOverride.value = rows;
|
|
13497
|
+
props.onDataChange?.(rows);
|
|
13498
|
+
props.rowDrag.onReorder(rows);
|
|
13499
|
+
}
|
|
13500
|
+
}
|
|
13501
|
+
rowRectsRef.value = [];
|
|
13502
|
+
};
|
|
13503
|
+
const handleRowDragPointerLeave = () => {
|
|
13504
|
+
if (props.rowDrag && rowDragCtrl.getState().activeId !== null) {
|
|
13505
|
+
rowDragCtrl.cancel();
|
|
13506
|
+
}
|
|
13507
|
+
};
|
|
13508
|
+
const handleColDragPointerDown = (e, colKey) => {
|
|
13509
|
+
if (!props.columnDrag || e.button !== 0) return;
|
|
13510
|
+
e.preventDefault();
|
|
13511
|
+
e.stopPropagation();
|
|
13512
|
+
colDragCtrl.press(colKey, e.clientX, e.clientY);
|
|
13513
|
+
};
|
|
13514
|
+
const handleColDragPointerMove = (e) => {
|
|
13515
|
+
if (!props.columnDrag) return;
|
|
13516
|
+
if (colDragCtrl.isPending()) {
|
|
13517
|
+
const started = colDragCtrl.tryStart(e.clientX, e.clientY);
|
|
13518
|
+
if (started) {
|
|
13519
|
+
const rects = [];
|
|
13520
|
+
rootRef.value?.querySelectorAll("[data-iris-table-header]").forEach((el) => {
|
|
13521
|
+
const r = el.getBoundingClientRect();
|
|
13522
|
+
const id = el.getAttribute("data-iris-table-header");
|
|
13523
|
+
if (id) rects.push({ id, left: r.left, top: r.top, width: r.width, height: r.height });
|
|
13524
|
+
});
|
|
13525
|
+
colRectsRef.value = rects;
|
|
13526
|
+
}
|
|
13527
|
+
}
|
|
13528
|
+
if (colDragCtrl.getState().activeId !== null) {
|
|
13529
|
+
colDragCtrl.moveOver({ x: e.clientX, y: e.clientY }, colRectsRef.value);
|
|
13530
|
+
}
|
|
13531
|
+
};
|
|
13532
|
+
const handleColDragPointerUp = () => {
|
|
13533
|
+
if (!props.columnDrag) return;
|
|
13534
|
+
if (colDragCtrl.isPending()) {
|
|
13535
|
+
colDragCtrl.cancel();
|
|
13536
|
+
return;
|
|
13537
|
+
}
|
|
13538
|
+
const { activeId, overId } = colDragCtrl.end();
|
|
13539
|
+
if (activeId !== null && overId !== null && activeId !== overId) {
|
|
13540
|
+
const next = [...leafColumns.value];
|
|
13541
|
+
const from = next.findIndex((c) => c.key === activeId);
|
|
13542
|
+
const to = next.findIndex((c) => c.key === overId);
|
|
13543
|
+
if (from >= 0 && to >= 0 && from !== to) {
|
|
13544
|
+
const [moved] = next.splice(from, 1);
|
|
13545
|
+
next.splice(to, 0, moved);
|
|
13546
|
+
props.columnDrag.onReorder(next);
|
|
13547
|
+
}
|
|
13548
|
+
}
|
|
13549
|
+
colRectsRef.value = [];
|
|
13550
|
+
};
|
|
13551
|
+
const spanOccupy = /* @__PURE__ */ new Set();
|
|
13552
|
+
const tableExpose = {
|
|
13553
|
+
loadData: (rows) => {
|
|
13554
|
+
if (proxyCtrl.proxy.value) proxyCtrl.liveData.value = rows;
|
|
13555
|
+
else localRowsOverride.value = rows;
|
|
13556
|
+
props.onDataChange?.(rows);
|
|
13557
|
+
},
|
|
13558
|
+
reloadData: () => {
|
|
13559
|
+
void proxyCtrl.refetch();
|
|
13560
|
+
},
|
|
13561
|
+
commitProxy: (overrides) => {
|
|
13562
|
+
proxyCtrl.setParams(overrides);
|
|
13563
|
+
},
|
|
13564
|
+
getProxyInfo: () => {
|
|
13565
|
+
if (!proxyCtrl.proxy.value) return null;
|
|
13566
|
+
const s = proxyCtrl.state.value;
|
|
13567
|
+
return { page: s.params.page, pageSize: s.params.pageSize, total: s.total };
|
|
13568
|
+
},
|
|
13569
|
+
removeRows: (keys) => {
|
|
13570
|
+
const { rows, removedKeys } = core.removeRowsFromList(tableData.value, props.rowKey, keys);
|
|
13571
|
+
if (removedKeys.size === 0) return;
|
|
13572
|
+
if (proxyCtrl.proxy.value) proxyCtrl.liveData.value = rows;
|
|
13573
|
+
else localRowsOverride.value = rows;
|
|
13574
|
+
const selected = displaySelection.value;
|
|
13575
|
+
const nextSelection = selected.filter((key) => !removedKeys.has(key));
|
|
13576
|
+
if (nextSelection.length !== selected.length) {
|
|
13577
|
+
rebaseToProp();
|
|
13578
|
+
selectionModel.set(nextSelection);
|
|
13579
|
+
}
|
|
13580
|
+
props.onDataChange?.(rows);
|
|
13581
|
+
},
|
|
13582
|
+
getFilteredData: () => [...bodyData.value],
|
|
13583
|
+
exportCurrentViewCsv: () => exportCsv(bodyData.value, leafColumns.value),
|
|
13584
|
+
exportMultiCsv: () => {
|
|
13585
|
+
const current = exportCsv(bodyData.value, leafColumns.value);
|
|
13586
|
+
const names = props.exportNames;
|
|
13587
|
+
if (!names || names.length === 0) return current;
|
|
13588
|
+
const segments = [`# current${current ? `
|
|
13589
|
+
${current}` : ""}`];
|
|
13590
|
+
for (const entry of names) {
|
|
13591
|
+
if (!entry.key) continue;
|
|
13592
|
+
const refCsv = core.toCsvRows(entry.ref());
|
|
13593
|
+
segments.push(`# ${entry.key}${refCsv ? `
|
|
13594
|
+
${refCsv}` : ""}`);
|
|
13595
|
+
}
|
|
13596
|
+
return segments.join("\n\n");
|
|
13597
|
+
},
|
|
13598
|
+
compareStates: core.compareStates,
|
|
13599
|
+
scrollToRow,
|
|
13600
|
+
goToRow
|
|
13601
|
+
};
|
|
13602
|
+
expose(tableExpose);
|
|
13603
|
+
const buildFormSection = () => renderFormSection({
|
|
13604
|
+
formConfig: props.formConfig,
|
|
13605
|
+
t,
|
|
13606
|
+
formDraft,
|
|
13607
|
+
setFormValue,
|
|
13608
|
+
handleFormSubmit,
|
|
13609
|
+
handleFormReset
|
|
13610
|
+
});
|
|
13611
|
+
const buildToolbarSection = () => renderToolbarSection({
|
|
13612
|
+
toolbar: props.toolbar,
|
|
13613
|
+
selectable: props.selectable,
|
|
13614
|
+
displaySelection,
|
|
13615
|
+
proxyCtrl,
|
|
13616
|
+
t,
|
|
13617
|
+
importFileInput: importController.importFileInput,
|
|
13618
|
+
onImportFile: importController.handleImportFile,
|
|
13619
|
+
densityToggle: props.densityToggle,
|
|
13620
|
+
effectiveDensity: effectiveDensity.value,
|
|
13621
|
+
onDensityToggle: cycleDensity
|
|
13622
|
+
});
|
|
13623
|
+
const buildPagerSection = () => renderPagerSection({ proxyCtrl, proxyConfig: props.proxyConfig });
|
|
13624
|
+
const contextMenuState = vue.ref(null);
|
|
13625
|
+
const contextAnchorRef = vue.ref(null);
|
|
13626
|
+
const contextMenuRef = vue.ref(null);
|
|
13627
|
+
const closeContextMenu = () => {
|
|
13628
|
+
if (contextMenuState.value) contextMenuState.value.open = false;
|
|
13629
|
+
};
|
|
13630
|
+
const handleContextMenu = (e, row, col, idx, ci) => {
|
|
13631
|
+
if (!props.contextMenu) return;
|
|
13632
|
+
e.preventDefault();
|
|
13633
|
+
contextAnchorRef.value = {
|
|
13634
|
+
getBoundingClientRect: () => ({
|
|
13635
|
+
left: e.clientX,
|
|
13636
|
+
top: e.clientY,
|
|
13637
|
+
right: e.clientX,
|
|
13638
|
+
bottom: e.clientY,
|
|
13639
|
+
width: 0,
|
|
13640
|
+
height: 0,
|
|
13641
|
+
x: e.clientX,
|
|
13642
|
+
y: e.clientY,
|
|
13643
|
+
toJSON() {
|
|
13644
|
+
}
|
|
13645
|
+
})
|
|
13646
|
+
};
|
|
13647
|
+
const params = {
|
|
13648
|
+
row,
|
|
13649
|
+
column: col,
|
|
13650
|
+
rowIndex: idx,
|
|
13651
|
+
columnIndex: ci
|
|
13652
|
+
};
|
|
13653
|
+
contextMenuState.value = { open: true, items: props.contextMenu.items(params), params };
|
|
13654
|
+
};
|
|
13655
|
+
const contextMenuOpen = vue.computed(() => contextMenuState.value?.open === true);
|
|
13656
|
+
const { floatingStyles: contextMenuStyles } = useFloating({
|
|
13657
|
+
anchor: contextAnchorRef,
|
|
13658
|
+
floating: contextMenuRef,
|
|
13659
|
+
open: contextMenuOpen,
|
|
13660
|
+
placement: "bottom-start",
|
|
13661
|
+
// Cursor-anchored menu, vxe parity: with a zero-size anchor at the
|
|
13662
|
+
// viewport edge, flip/shift would clamp the coordinates away from the
|
|
13663
|
+
// cursor (React parity — deliberately disabled).
|
|
13664
|
+
flip: false,
|
|
13665
|
+
shift: false
|
|
13666
|
+
});
|
|
13667
|
+
useDismiss({
|
|
13668
|
+
enabled: contextMenuOpen,
|
|
13669
|
+
exclude: [contextMenuRef],
|
|
13670
|
+
onDismiss: closeContextMenu
|
|
13671
|
+
});
|
|
13672
|
+
vue.watch(contextMenuOpen, (open) => {
|
|
13673
|
+
if (typeof document === "undefined") return;
|
|
13674
|
+
if (open) document.addEventListener("scroll", closeContextMenu, true);
|
|
13675
|
+
else document.removeEventListener("scroll", closeContextMenu, true);
|
|
13676
|
+
});
|
|
13677
|
+
vue.onScopeDispose(() => {
|
|
13678
|
+
if (typeof document === "undefined") return;
|
|
13679
|
+
document.removeEventListener("scroll", closeContextMenu, true);
|
|
13680
|
+
});
|
|
13681
|
+
const buildContextMenuSection = () => renderContextMenuSection({
|
|
13682
|
+
state: contextMenuState,
|
|
13683
|
+
styles: contextMenuStyles,
|
|
13684
|
+
menuRef: contextMenuRef,
|
|
13685
|
+
close: closeContextMenu,
|
|
13686
|
+
contextMenu: props.contextMenu
|
|
13687
|
+
});
|
|
13688
|
+
const filterPanelState = vue.ref(null);
|
|
13689
|
+
const filterAnchorRef = vue.ref(null);
|
|
13690
|
+
const filterPanelRef = vue.ref(null);
|
|
13691
|
+
const filterDraft = vue.ref([]);
|
|
13692
|
+
const closeFilterPanel = () => {
|
|
13693
|
+
if (filterPanelState.value) filterPanelState.value.open = false;
|
|
13694
|
+
};
|
|
13695
|
+
const openFilterPanel = (e, colKey) => {
|
|
13696
|
+
e.stopPropagation();
|
|
13697
|
+
filterAnchorRef.value = e.currentTarget;
|
|
13698
|
+
filterDraft.value = [...props.filterValues?.[colKey] ?? []];
|
|
13699
|
+
filterPanelState.value = { open: true, colKey };
|
|
13700
|
+
};
|
|
13701
|
+
const filterPanelOpen = vue.computed(() => filterPanelState.value?.open === true);
|
|
13702
|
+
const { floatingStyles: filterPanelStyles } = useFloating({
|
|
13703
|
+
anchor: filterAnchorRef,
|
|
13704
|
+
floating: filterPanelRef,
|
|
13705
|
+
open: filterPanelOpen,
|
|
13706
|
+
placement: "bottom-start"
|
|
13707
|
+
});
|
|
13708
|
+
useDismiss({
|
|
13709
|
+
enabled: filterPanelOpen,
|
|
13710
|
+
exclude: [filterPanelRef, filterAnchorRef],
|
|
13711
|
+
onDismiss: closeFilterPanel
|
|
13712
|
+
});
|
|
13713
|
+
vue.watch(filterPanelOpen, (open) => {
|
|
13714
|
+
if (typeof document === "undefined") return;
|
|
13715
|
+
if (open) document.addEventListener("scroll", closeFilterPanel, true);
|
|
13716
|
+
else document.removeEventListener("scroll", closeFilterPanel, true);
|
|
13717
|
+
});
|
|
13718
|
+
vue.onScopeDispose(() => {
|
|
13719
|
+
if (typeof document === "undefined") return;
|
|
13720
|
+
document.removeEventListener("scroll", closeFilterPanel, true);
|
|
13721
|
+
});
|
|
13722
|
+
const applyFilterValues = (colKey, values) => {
|
|
13723
|
+
props.onFilterValuesChange?.({ ...props.filterValues ?? {}, [colKey]: values });
|
|
13724
|
+
};
|
|
13725
|
+
const clearFilterValues = (colKey) => {
|
|
13726
|
+
const next = { ...props.filterValues ?? {} };
|
|
13727
|
+
delete next[colKey];
|
|
13728
|
+
props.onFilterValuesChange?.(next);
|
|
13729
|
+
};
|
|
13730
|
+
const toggleFilterDraft = (value) => {
|
|
13731
|
+
filterDraft.value = filterDraft.value.includes(value) ? filterDraft.value.filter((v) => v !== value) : [...filterDraft.value, value];
|
|
13732
|
+
};
|
|
13733
|
+
const buildFilterPanelSection = () => renderFilterPanelSection({
|
|
13734
|
+
state: filterPanelState,
|
|
13735
|
+
styles: filterPanelStyles,
|
|
13736
|
+
panelRef: filterPanelRef,
|
|
13737
|
+
filterDraft,
|
|
13738
|
+
columns: displayColumns.value,
|
|
13739
|
+
filterValues: props.filterValues,
|
|
13740
|
+
t,
|
|
13741
|
+
close: closeFilterPanel,
|
|
13742
|
+
toggle: toggleFilterDraft,
|
|
13743
|
+
apply: applyFilterValues,
|
|
13744
|
+
clear: clearFilterValues
|
|
13745
|
+
});
|
|
11138
13746
|
return () => {
|
|
11139
13747
|
const showSelection = props.selectable !== "none";
|
|
11140
13748
|
const showDetail = hasDetail.value;
|
|
11141
|
-
const
|
|
11142
|
-
|
|
13749
|
+
const showDrag = props.rowDrag !== void 0;
|
|
13750
|
+
const showSeq = props.seq === true;
|
|
13751
|
+
spanOccupy.clear();
|
|
13752
|
+
const leadFlatHeaderCells = () => {
|
|
11143
13753
|
const cells = [];
|
|
11144
|
-
if (
|
|
13754
|
+
if (showDrag) {
|
|
11145
13755
|
cells.push(
|
|
11146
13756
|
vue.h("div", {
|
|
11147
|
-
key: "__expand__",
|
|
11148
13757
|
role: "columnheader",
|
|
11149
|
-
|
|
13758
|
+
key: "__drag__",
|
|
13759
|
+
"data-iris-table-header": "__drag",
|
|
13760
|
+
style: {
|
|
13761
|
+
display: "flex",
|
|
13762
|
+
alignItems: "center",
|
|
13763
|
+
justifyContent: "center",
|
|
13764
|
+
padding: "8px",
|
|
13765
|
+
background: "var(--iris-surface)",
|
|
13766
|
+
borderBottom: "1px solid var(--iris-border)"
|
|
13767
|
+
}
|
|
11150
13768
|
})
|
|
11151
13769
|
);
|
|
11152
13770
|
}
|
|
11153
|
-
if (
|
|
13771
|
+
if (showSeq) {
|
|
11154
13772
|
cells.push(
|
|
11155
|
-
vue.h(
|
|
11156
|
-
"
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
background: "var(--iris-surface)",
|
|
11169
|
-
borderBottom: "1px solid var(--iris-border)"
|
|
11170
|
-
}
|
|
11171
|
-
},
|
|
11172
|
-
props.selectable === "multi" ? [
|
|
11173
|
-
[
|
|
11174
|
-
vue.h(IrisCheckbox, {
|
|
11175
|
-
modelValue: allSelected.value ? true : someSelected.value ? "indeterminate" : false,
|
|
11176
|
-
size: "sm",
|
|
11177
|
-
ariaLabel: t("table.selectAll"),
|
|
11178
|
-
"onUpdate:modelValue": toggleAll
|
|
11179
|
-
}),
|
|
11180
|
-
props.selection && props.selection.length > 0 ? vue.h(
|
|
11181
|
-
"span",
|
|
11182
|
-
{
|
|
11183
|
-
"data-iris-table-selected-count": "",
|
|
11184
|
-
style: {
|
|
11185
|
-
marginInlineStart: "var(--iris-space-xs, 8px)",
|
|
11186
|
-
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
11187
|
-
color: "var(--iris-muted)",
|
|
11188
|
-
whiteSpace: "nowrap"
|
|
11189
|
-
}
|
|
11190
|
-
},
|
|
11191
|
-
t("table.selectedCount", { count: String(props.selection.length) })
|
|
11192
|
-
) : null
|
|
11193
|
-
]
|
|
11194
|
-
] : ""
|
|
11195
|
-
)
|
|
13773
|
+
vue.h("div", {
|
|
13774
|
+
role: "columnheader",
|
|
13775
|
+
key: "__seq__",
|
|
13776
|
+
"data-iris-table-header": "__seq",
|
|
13777
|
+
style: {
|
|
13778
|
+
display: "flex",
|
|
13779
|
+
alignItems: "center",
|
|
13780
|
+
justifyContent: "center",
|
|
13781
|
+
padding: "8px",
|
|
13782
|
+
background: "var(--iris-surface)",
|
|
13783
|
+
borderBottom: "1px solid var(--iris-border)"
|
|
13784
|
+
}
|
|
13785
|
+
})
|
|
11196
13786
|
);
|
|
11197
13787
|
}
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
"aria-sort": sortable ? internalSort.value?.key === col.key ? internalSort.value.direction === "asc" ? "ascending" : "descending" : "none" : void 0,
|
|
11217
|
-
style: {
|
|
11218
|
-
gridColumn: `${lead + cell.colStart} / span ${cell.colSpan}`,
|
|
11219
|
-
gridRow: `${cell.level + 1} / span ${cell.rowSpan}`,
|
|
11220
|
-
display: "flex",
|
|
11221
|
-
alignItems: "center",
|
|
11222
|
-
justifyContent: isLeaf ? align === "right" ? "flex-end" : align === "center" ? "center" : "flex-start" : "center",
|
|
11223
|
-
padding: "8px var(--iris-padding-md)",
|
|
11224
|
-
cursor: sortable ? "pointer" : "default",
|
|
11225
|
-
userSelect: sortable ? "none" : "auto",
|
|
11226
|
-
background: "var(--iris-surface)",
|
|
11227
|
-
borderBottom: "1px solid var(--iris-border)",
|
|
11228
|
-
fontWeight: "600",
|
|
11229
|
-
fontSize: "var(--iris-font-size-md, 14px)",
|
|
11230
|
-
color: "var(--iris-foreground)",
|
|
11231
|
-
whiteSpace: "nowrap",
|
|
11232
|
-
overflow: "hidden",
|
|
11233
|
-
textOverflow: "ellipsis"
|
|
11234
|
-
}
|
|
11235
|
-
},
|
|
11236
|
-
[title, sortable ? sortIndicator(col) : null]
|
|
11237
|
-
)
|
|
11238
|
-
);
|
|
11239
|
-
}
|
|
13788
|
+
return cells;
|
|
13789
|
+
};
|
|
13790
|
+
const leadSummaryCells = () => {
|
|
13791
|
+
const cells = [];
|
|
13792
|
+
if (showDrag) {
|
|
13793
|
+
cells.push(
|
|
13794
|
+
vue.h("div", {
|
|
13795
|
+
key: "__drag",
|
|
13796
|
+
role: "cell",
|
|
13797
|
+
"data-iris-table-cell": "__drag",
|
|
13798
|
+
style: {
|
|
13799
|
+
display: "flex",
|
|
13800
|
+
alignItems: "center",
|
|
13801
|
+
justifyContent: "center",
|
|
13802
|
+
padding: "8px 12px"
|
|
13803
|
+
}
|
|
13804
|
+
})
|
|
13805
|
+
);
|
|
11240
13806
|
}
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
13807
|
+
if (showSeq) {
|
|
13808
|
+
cells.push(
|
|
13809
|
+
vue.h("div", {
|
|
13810
|
+
key: "__seq",
|
|
13811
|
+
role: "cell",
|
|
13812
|
+
"data-iris-table-cell": "__seq",
|
|
13813
|
+
style: {
|
|
13814
|
+
display: "flex",
|
|
13815
|
+
alignItems: "center",
|
|
13816
|
+
justifyContent: "center",
|
|
13817
|
+
padding: "8px 12px"
|
|
13818
|
+
}
|
|
13819
|
+
})
|
|
13820
|
+
);
|
|
13821
|
+
}
|
|
13822
|
+
if (showDetail) {
|
|
13823
|
+
cells.push(
|
|
13824
|
+
vue.h("div", {
|
|
13825
|
+
key: "__expand",
|
|
13826
|
+
role: "cell",
|
|
13827
|
+
"data-iris-table-cell": "__expand",
|
|
13828
|
+
style: {
|
|
13829
|
+
display: "flex",
|
|
13830
|
+
alignItems: "center",
|
|
13831
|
+
justifyContent: "center",
|
|
13832
|
+
padding: "8px 12px"
|
|
13833
|
+
}
|
|
13834
|
+
})
|
|
13835
|
+
);
|
|
13836
|
+
}
|
|
13837
|
+
if (showSelection) {
|
|
13838
|
+
cells.push(
|
|
13839
|
+
vue.h("div", {
|
|
13840
|
+
key: "__selection",
|
|
13841
|
+
role: "cell",
|
|
13842
|
+
"data-iris-table-cell": "__selection",
|
|
13843
|
+
style: {
|
|
13844
|
+
display: "flex",
|
|
13845
|
+
alignItems: "center",
|
|
13846
|
+
justifyContent: "center",
|
|
13847
|
+
padding: "8px 12px"
|
|
13848
|
+
}
|
|
13849
|
+
})
|
|
13850
|
+
);
|
|
13851
|
+
}
|
|
13852
|
+
return cells;
|
|
11256
13853
|
};
|
|
11257
|
-
const
|
|
13854
|
+
const buildGroupedHeader = (matrix) => renderGroupedHeader(
|
|
13855
|
+
{
|
|
13856
|
+
showDrag,
|
|
13857
|
+
showSeq,
|
|
13858
|
+
showDetail,
|
|
13859
|
+
showSelection,
|
|
13860
|
+
selectable: props.selectable,
|
|
13861
|
+
selection: props.selection,
|
|
13862
|
+
allSelected,
|
|
13863
|
+
someSelected,
|
|
13864
|
+
toggleAll,
|
|
13865
|
+
t,
|
|
13866
|
+
slots,
|
|
13867
|
+
onHeaderClick,
|
|
13868
|
+
ariaSortFor,
|
|
13869
|
+
sortIndicator,
|
|
13870
|
+
multiSortSeq,
|
|
13871
|
+
renderFilterTrigger,
|
|
13872
|
+
pinnedDragHandle,
|
|
13873
|
+
gridTemplate
|
|
13874
|
+
},
|
|
13875
|
+
matrix
|
|
13876
|
+
);
|
|
13877
|
+
const headerCells = leadFlatHeaderCells();
|
|
11258
13878
|
if (showDetail) {
|
|
11259
13879
|
headerCells.push(
|
|
11260
13880
|
vue.h("div", {
|
|
@@ -11299,14 +13919,15 @@ var IrisTable = vue.defineComponent({
|
|
|
11299
13919
|
)
|
|
11300
13920
|
);
|
|
11301
13921
|
}
|
|
11302
|
-
for (let ci = 0; ci <
|
|
11303
|
-
const col =
|
|
13922
|
+
for (let ci = 0; ci < leafColumns.value.length; ci += 1) {
|
|
13923
|
+
const col = leafColumns.value[ci];
|
|
11304
13924
|
if (visibleColSet.value && !visibleColSet.value.has(ci)) continue;
|
|
11305
13925
|
const align = col.align ?? "left";
|
|
11306
13926
|
const headerSlot = slots[`header.${col.key}`];
|
|
11307
13927
|
const title = headerSlot?.({ column: col }) ?? col.title;
|
|
11308
13928
|
wireResize(col);
|
|
11309
|
-
const
|
|
13929
|
+
const pinnedHandle = pinnedDragHandle(col);
|
|
13930
|
+
const handle = props.resizableColumns && !pinnedHandle ? vue.h("span", {
|
|
11310
13931
|
ref: (el) => {
|
|
11311
13932
|
getHandleRef(col.key).value = el ?? null;
|
|
11312
13933
|
},
|
|
@@ -11350,6 +13971,13 @@ var IrisTable = vue.defineComponent({
|
|
|
11350
13971
|
role: "columnheader",
|
|
11351
13972
|
"data-iris-table-header": col.key,
|
|
11352
13973
|
"data-iris-table-pinned": col.pinned,
|
|
13974
|
+
// Column drag-sort (vxe columnDragConfig parity, batch Y): the
|
|
13975
|
+
// header cell is the press target; grouped headers are NOT
|
|
13976
|
+
// supported (documented simplification — the reorder maps leaf
|
|
13977
|
+
// columns back to the parent, which a group column cannot do).
|
|
13978
|
+
"data-iris-col-drag-active": props.columnDrag && colDragState.value.activeId === col.key ? "true" : void 0,
|
|
13979
|
+
"data-iris-col-drag-over": props.columnDrag && colDragState.value.overId === col.key ? "true" : void 0,
|
|
13980
|
+
onPointerdown: props.columnDrag && !grouped.value ? (e) => handleColDragPointerDown(e, col.key) : void 0,
|
|
11353
13981
|
onClick: () => onHeaderClick(col),
|
|
11354
13982
|
style: {
|
|
11355
13983
|
position: "relative",
|
|
@@ -11370,9 +13998,16 @@ var IrisTable = vue.defineComponent({
|
|
|
11370
13998
|
...visibleColSet.value ? { gridColumnStart: String(colTrack(ci)) } : {},
|
|
11371
13999
|
...col.pinned ? { ...pinnedStyle(col.key), background: "var(--iris-surface)" } : {}
|
|
11372
14000
|
},
|
|
11373
|
-
"aria-sort":
|
|
14001
|
+
"aria-sort": ariaSortFor(col)
|
|
11374
14002
|
},
|
|
11375
|
-
[
|
|
14003
|
+
[
|
|
14004
|
+
title,
|
|
14005
|
+
sortIndicator(col),
|
|
14006
|
+
multiSortSeq(col),
|
|
14007
|
+
renderFilterTrigger(col, true),
|
|
14008
|
+
pinnedHandle,
|
|
14009
|
+
handle
|
|
14010
|
+
]
|
|
11376
14011
|
)
|
|
11377
14012
|
);
|
|
11378
14013
|
}
|
|
@@ -11392,6 +14027,69 @@ var IrisTable = vue.defineComponent({
|
|
|
11392
14027
|
const id = rowId(row, index);
|
|
11393
14028
|
const selected = isSelected(id);
|
|
11394
14029
|
const cells = [];
|
|
14030
|
+
if (showDrag) {
|
|
14031
|
+
const rowDragActive = rowDragState.value.activeId === String(id);
|
|
14032
|
+
const rowDragOver = rowDragState.value.overId === String(id);
|
|
14033
|
+
cells.push(
|
|
14034
|
+
vue.h(
|
|
14035
|
+
"div",
|
|
14036
|
+
{
|
|
14037
|
+
key: "__drag",
|
|
14038
|
+
role: "cell",
|
|
14039
|
+
"data-iris-table-cell": "__drag",
|
|
14040
|
+
// The drag handle carries the row's id as its attribute VALUE
|
|
14041
|
+
// (rect collection for closestCenter reads it back).
|
|
14042
|
+
"data-iris-row-drag-handle": String(id),
|
|
14043
|
+
"data-iris-row-drag-active": rowDragActive ? "true" : void 0,
|
|
14044
|
+
"data-iris-row-drag-over": rowDragOver ? "true" : void 0,
|
|
14045
|
+
onPointerdown: (e) => handleRowDragPointerDown(e, String(id)),
|
|
14046
|
+
onClick: (e) => e.stopPropagation(),
|
|
14047
|
+
style: {
|
|
14048
|
+
display: "flex",
|
|
14049
|
+
alignItems: "center",
|
|
14050
|
+
justifyContent: "center",
|
|
14051
|
+
padding: "8px 12px",
|
|
14052
|
+
borderBottom: "1px solid var(--iris-border)",
|
|
14053
|
+
cursor: "grab",
|
|
14054
|
+
color: "var(--iris-muted)",
|
|
14055
|
+
background: rowDragActive ? "var(--iris-surface-hover)" : rowDragOver ? "var(--iris-surface-selected, rgba(99,102,241,0.12))" : "transparent"
|
|
14056
|
+
}
|
|
14057
|
+
},
|
|
14058
|
+
[
|
|
14059
|
+
vue.h(
|
|
14060
|
+
"span",
|
|
14061
|
+
{
|
|
14062
|
+
"aria-hidden": "true",
|
|
14063
|
+
style: { fontSize: "var(--iris-font-size-sm, 13px)" }
|
|
14064
|
+
},
|
|
14065
|
+
"\u283F"
|
|
14066
|
+
)
|
|
14067
|
+
]
|
|
14068
|
+
)
|
|
14069
|
+
);
|
|
14070
|
+
}
|
|
14071
|
+
if (showSeq) {
|
|
14072
|
+
cells.push(
|
|
14073
|
+
vue.h(
|
|
14074
|
+
"div",
|
|
14075
|
+
{
|
|
14076
|
+
key: "__seq",
|
|
14077
|
+
role: "cell",
|
|
14078
|
+
"data-iris-table-cell": "__seq",
|
|
14079
|
+
style: {
|
|
14080
|
+
display: "flex",
|
|
14081
|
+
alignItems: "center",
|
|
14082
|
+
justifyContent: "center",
|
|
14083
|
+
padding: "8px 12px",
|
|
14084
|
+
borderBottom: "1px solid var(--iris-border)",
|
|
14085
|
+
color: "var(--iris-muted)",
|
|
14086
|
+
userSelect: "none"
|
|
14087
|
+
}
|
|
14088
|
+
},
|
|
14089
|
+
String(index + props.seqStartIndex)
|
|
14090
|
+
)
|
|
14091
|
+
);
|
|
14092
|
+
}
|
|
11395
14093
|
if (showDetail) {
|
|
11396
14094
|
const rowExpandable = isRowExpandable(row, index);
|
|
11397
14095
|
const isExpanded = expandedKeys.value.includes(String(id));
|
|
@@ -11468,115 +14166,30 @@ var IrisTable = vue.defineComponent({
|
|
|
11468
14166
|
for (let ci = 0; ci < leafColumns.value.length; ci += 1) {
|
|
11469
14167
|
const col = leafColumns.value[ci];
|
|
11470
14168
|
if (visibleColSet.value && !visibleColSet.value.has(ci)) continue;
|
|
14169
|
+
const span = resolveSpan(spanOccupy, index, ci, props.spanMethod);
|
|
14170
|
+
if (span === null) continue;
|
|
14171
|
+
const rowspan = span.rowspan;
|
|
14172
|
+
const colspan = span.colspan;
|
|
11471
14173
|
const align = col.align ?? "left";
|
|
11472
14174
|
const cellSlot = slots[`cell.${col.key}`];
|
|
11473
|
-
const
|
|
14175
|
+
const isRowEditing = rowMode.value && rowEditing.value !== null && rowEditing.value.k === id && rowSessions.value.has(cellId(id, col.key));
|
|
14176
|
+
const isEditing = isRowEditing || editingCellId.value === cellId(id, col.key);
|
|
14177
|
+
const patternHint = (props.pattern || props.patternFill) && !rowMode.value && editingColumnKey.value === col.key && !isEditing && editingDraft.value !== "" && String(getCellValue(row, col) ?? "") === editingDraft.value;
|
|
11474
14178
|
let content;
|
|
11475
14179
|
if (isEditing) {
|
|
11476
14180
|
const editCellId = cellId(id, col.key);
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
value
|
|
11484
|
-
|
|
11485
|
-
"aria-invalid": error ? "true" : void 0,
|
|
11486
|
-
"aria-describedby": error ? `${editCellId}-error` : void 0,
|
|
11487
|
-
onInput: (e) => {
|
|
11488
|
-
editingDraft.value = e.target.value;
|
|
11489
|
-
},
|
|
11490
|
-
onKeydown: (e) => {
|
|
11491
|
-
if (e.key === "Enter") {
|
|
11492
|
-
e.preventDefault();
|
|
11493
|
-
commitEdit(row, col, index);
|
|
11494
|
-
} else if (e.key === "Escape") {
|
|
11495
|
-
e.preventDefault();
|
|
11496
|
-
cancelEdit();
|
|
11497
|
-
}
|
|
11498
|
-
},
|
|
11499
|
-
onBlur: () => commitEdit(row, col, index),
|
|
11500
|
-
onClick: (e) => e.stopPropagation(),
|
|
11501
|
-
onDblclick: (e) => e.stopPropagation(),
|
|
11502
|
-
style: {
|
|
11503
|
-
width: "100%",
|
|
11504
|
-
border: `1px solid ${error ? "var(--iris-danger)" : "var(--iris-primary)"}`,
|
|
11505
|
-
borderRadius: "var(--iris-radius-sm)",
|
|
11506
|
-
padding: "var(--iris-space-xxs, 4px) var(--iris-padding-sm, 6px)",
|
|
11507
|
-
font: "inherit",
|
|
11508
|
-
background: "var(--iris-background)",
|
|
11509
|
-
color: "var(--iris-foreground)",
|
|
11510
|
-
outline: "none",
|
|
11511
|
-
boxShadow: "0 0 0 3px color-mix(in srgb, var(--iris-primary) 18%, transparent)"
|
|
11512
|
-
}
|
|
11513
|
-
});
|
|
11514
|
-
content = error ? [
|
|
11515
|
-
input,
|
|
11516
|
-
vue.h(
|
|
11517
|
-
"div",
|
|
11518
|
-
{
|
|
11519
|
-
id: `${editCellId}-error`,
|
|
11520
|
-
role: "alert",
|
|
11521
|
-
"data-iris-table-editor-error": "",
|
|
11522
|
-
style: {
|
|
11523
|
-
marginTop: "var(--iris-space-xxs, 4px)",
|
|
11524
|
-
fontSize: "var(--iris-font-size-xs, 12px)",
|
|
11525
|
-
color: "var(--iris-danger)"
|
|
11526
|
-
}
|
|
11527
|
-
},
|
|
11528
|
-
error
|
|
11529
|
-
)
|
|
11530
|
-
] : input;
|
|
14181
|
+
content = isRowEditing ? buildRowSessionContent(
|
|
14182
|
+
row,
|
|
14183
|
+
col,
|
|
14184
|
+
index,
|
|
14185
|
+
id,
|
|
14186
|
+
editCellId,
|
|
14187
|
+
rowSessions.value.get(editCellId)
|
|
14188
|
+
) : buildCellEditContent(row, col, index, editCellId);
|
|
11531
14189
|
} else {
|
|
11532
|
-
content = cellSlot?.({ row, index, value:
|
|
14190
|
+
content = cellSlot?.({ row, index, value: getCellValue(row, col) }) ?? core.tableDisplayText(row, col);
|
|
11533
14191
|
}
|
|
11534
|
-
const treeIndent = treeMeta && ci === 0 ?
|
|
11535
|
-
"span",
|
|
11536
|
-
{
|
|
11537
|
-
"data-iris-table-tree-indent": "",
|
|
11538
|
-
style: {
|
|
11539
|
-
display: "inline-flex",
|
|
11540
|
-
alignItems: "center",
|
|
11541
|
-
flex: "none",
|
|
11542
|
-
paddingLeft: `${treeMeta.depth * 16}px`
|
|
11543
|
-
}
|
|
11544
|
-
},
|
|
11545
|
-
treeMeta.hasChildren ? [
|
|
11546
|
-
vue.h(
|
|
11547
|
-
"button",
|
|
11548
|
-
{
|
|
11549
|
-
type: "button",
|
|
11550
|
-
"data-iris-table-tree-toggle": "",
|
|
11551
|
-
"aria-expanded": treeMeta.expanded ? "true" : "false",
|
|
11552
|
-
"aria-label": t(
|
|
11553
|
-
treeMeta.expanded ? "treeSelect.collapse" : "treeSelect.expand"
|
|
11554
|
-
),
|
|
11555
|
-
onClick: (e) => {
|
|
11556
|
-
e.stopPropagation();
|
|
11557
|
-
expansion.toggle(treeMeta.key);
|
|
11558
|
-
},
|
|
11559
|
-
style: {
|
|
11560
|
-
border: "none",
|
|
11561
|
-
background: "transparent",
|
|
11562
|
-
cursor: "pointer",
|
|
11563
|
-
padding: "0",
|
|
11564
|
-
marginRight: "4px",
|
|
11565
|
-
font: "inherit",
|
|
11566
|
-
color: "var(--iris-foreground)",
|
|
11567
|
-
transform: treeMeta.expanded ? "rotate(90deg)" : "none",
|
|
11568
|
-
transition: "transform 150ms"
|
|
11569
|
-
}
|
|
11570
|
-
},
|
|
11571
|
-
"\u25B6"
|
|
11572
|
-
)
|
|
11573
|
-
] : [
|
|
11574
|
-
vue.h("span", {
|
|
11575
|
-
"aria-hidden": "true",
|
|
11576
|
-
style: { display: "inline-block", width: "16px" }
|
|
11577
|
-
})
|
|
11578
|
-
]
|
|
11579
|
-
) : null;
|
|
14192
|
+
const treeIndent = treeMeta && ci === 0 ? buildTreeIndent(treeMeta, row) : null;
|
|
11580
14193
|
const cellChildren = treeIndent ? [treeIndent, ...Array.isArray(content) ? content : [content]] : content;
|
|
11581
14194
|
cells.push(
|
|
11582
14195
|
vue.h(
|
|
@@ -11588,6 +14201,7 @@ var IrisTable = vue.defineComponent({
|
|
|
11588
14201
|
"data-iris-table-pinned": col.pinned,
|
|
11589
14202
|
"data-editable": col.editable ? "" : void 0,
|
|
11590
14203
|
"data-editing": isEditing ? "" : void 0,
|
|
14204
|
+
"data-iris-input-hint": patternHint ? "true" : void 0,
|
|
11591
14205
|
// Grid keyboard navigation (opt-in): grid coords + roving tabindex
|
|
11592
14206
|
// (exactly one cell is 0) + an onFocus that syncs the focused cell.
|
|
11593
14207
|
...props.keyboardNavigation ? {
|
|
@@ -11611,14 +14225,19 @@ var IrisTable = vue.defineComponent({
|
|
|
11611
14225
|
}
|
|
11612
14226
|
}
|
|
11613
14227
|
} : {},
|
|
11614
|
-
onDblclick: col.editable ? () => beginEdit(row, col, id) : void 0,
|
|
11615
|
-
onClick:
|
|
14228
|
+
onDblclick: rowMode.value ? () => switchRowEdit(row, index, col.key) : col.editable ? () => beginEdit(row, col, id) : void 0,
|
|
14229
|
+
onClick: rowMode.value ? () => handleRowModeCellClick(row, col, index, id) : props.cellRange ? (e) => {
|
|
14230
|
+
if (e.shiftKey) cellRangeCtrl.extendRange(index, ci);
|
|
14231
|
+
else cellRangeCtrl.startRange(index, ci);
|
|
14232
|
+
} : col.editable && props.editConfig?.trigger === "click" ? () => beginEdit(row, col, id) : void 0,
|
|
14233
|
+
onContextmenu: props.contextMenu ? (e) => handleContextMenu(e, row, col, index, ci) : void 0,
|
|
11616
14234
|
style: {
|
|
11617
14235
|
display: "flex",
|
|
11618
14236
|
alignItems: "center",
|
|
11619
14237
|
justifyContent: align === "right" ? "flex-end" : align === "center" ? "center" : "flex-start",
|
|
11620
14238
|
background: "var(--iris-cell-bg, transparent)",
|
|
11621
14239
|
padding: isEditing ? "var(--iris-space-xxs, 4px)" : "var(--iris-space-xs, 8px) var(--iris-padding-md)",
|
|
14240
|
+
...isEditing ? { flexWrap: "wrap" } : {},
|
|
11622
14241
|
borderBottom: "1px solid var(--iris-border)",
|
|
11623
14242
|
fontSize: "var(--iris-font-size-md, 14px)",
|
|
11624
14243
|
whiteSpace: "nowrap",
|
|
@@ -11627,6 +14246,11 @@ var IrisTable = vue.defineComponent({
|
|
|
11627
14246
|
cursor: col.editable ? "cell" : "default",
|
|
11628
14247
|
...props.cellRange && isInRange(index, ci) ? { background: "var(--iris-surface-selected, rgba(99,102,241,0.12))" } : {},
|
|
11629
14248
|
...visibleColSet.value ? { gridColumnStart: String(colTrack(ci)) } : {},
|
|
14249
|
+
...colspan > 1 ? { gridColumnEnd: `span ${colspan}` } : {},
|
|
14250
|
+
...rowspan > 1 ? { gridRowEnd: `span ${rowspan}` } : {},
|
|
14251
|
+
...patternHint ? {
|
|
14252
|
+
backgroundImage: "linear-gradient(var(--iris-input-hint, rgba(251, 191, 36, 0.16)), var(--iris-input-hint, rgba(251, 191, 36, 0.16)))"
|
|
14253
|
+
} : {},
|
|
11630
14254
|
...pinnedStyle(col.key)
|
|
11631
14255
|
}
|
|
11632
14256
|
},
|
|
@@ -11648,6 +14272,8 @@ var IrisTable = vue.defineComponent({
|
|
|
11648
14272
|
"aria-setsize": treeMeta ? treeMeta.setSize : void 0,
|
|
11649
14273
|
"aria-posinset": treeMeta ? treeMeta.posInset : void 0,
|
|
11650
14274
|
"data-iris-table-row": "",
|
|
14275
|
+
"data-iris-table-row-key": String(id),
|
|
14276
|
+
"data-iris-row-editing": rowMode.value && rowEditing.value?.k === id ? "true" : void 0,
|
|
11651
14277
|
"data-state": selected ? "selected" : void 0,
|
|
11652
14278
|
onClick: () => emit("rowClick", row, index),
|
|
11653
14279
|
onDblclick: () => emit("rowDblclick", row, index),
|
|
@@ -11668,50 +14294,21 @@ var IrisTable = vue.defineComponent({
|
|
|
11668
14294
|
textAlign: "center",
|
|
11669
14295
|
color: "var(--iris-muted)"
|
|
11670
14296
|
};
|
|
14297
|
+
const stateNode = renderTableStateRow({
|
|
14298
|
+
error: tableError.value,
|
|
14299
|
+
loading: tableLoading.value,
|
|
14300
|
+
rowCount: bodyData.value.length,
|
|
14301
|
+
stateRowStyle,
|
|
14302
|
+
errorContent: slots.error ? slots.error() : t("table.error"),
|
|
14303
|
+
loadingContent: slots.loading ? slots.loading() : t("table.loading"),
|
|
14304
|
+
emptyContent: slots.empty ? slots.empty() : t("table.empty"),
|
|
14305
|
+
retry: retry.value,
|
|
14306
|
+
onRetry: props.onRetry,
|
|
14307
|
+
retryLabel: t("table.retry")
|
|
14308
|
+
});
|
|
11671
14309
|
let bodyNode;
|
|
11672
|
-
if (
|
|
11673
|
-
bodyNode =
|
|
11674
|
-
vue.h(
|
|
11675
|
-
"span",
|
|
11676
|
-
{ style: { marginInlineEnd: props.onRetry ? "var(--iris-space-sm, 12px)" : "0px" } },
|
|
11677
|
-
slots.error ? slots.error() : t("table.error")
|
|
11678
|
-
),
|
|
11679
|
-
props.onRetry ? vue.h(
|
|
11680
|
-
"button",
|
|
11681
|
-
{
|
|
11682
|
-
type: "button",
|
|
11683
|
-
"data-iris-table-retry": "",
|
|
11684
|
-
onClick: props.onRetry,
|
|
11685
|
-
style: {
|
|
11686
|
-
border: "1px solid var(--iris-border)",
|
|
11687
|
-
background: "var(--iris-surface)",
|
|
11688
|
-
color: "var(--iris-foreground)",
|
|
11689
|
-
borderRadius: "var(--iris-radius-sm, 4px)",
|
|
11690
|
-
padding: "var(--iris-space-xxs, 4px) var(--iris-space-xs, 8px)",
|
|
11691
|
-
fontSize: "var(--iris-font-size-sm, 13px)",
|
|
11692
|
-
cursor: "pointer"
|
|
11693
|
-
}
|
|
11694
|
-
},
|
|
11695
|
-
t("table.retry")
|
|
11696
|
-
) : null
|
|
11697
|
-
]);
|
|
11698
|
-
} else if (props.loading) {
|
|
11699
|
-
bodyNode = vue.h(
|
|
11700
|
-
"div",
|
|
11701
|
-
{
|
|
11702
|
-
role: "row",
|
|
11703
|
-
"aria-busy": "true",
|
|
11704
|
-
"data-iris-table-row": "loading",
|
|
11705
|
-
style: stateRowStyle
|
|
11706
|
-
},
|
|
11707
|
-
slots.loading ? slots.loading() : t("table.loading")
|
|
11708
|
-
);
|
|
11709
|
-
} else if (bodyData.value.length === 0) {
|
|
11710
|
-
bodyNode = vue.h(
|
|
11711
|
-
"div",
|
|
11712
|
-
{ role: "row", "data-iris-table-row": "empty", style: stateRowStyle },
|
|
11713
|
-
slots.empty ? slots.empty() : t("table.empty")
|
|
11714
|
-
);
|
|
14310
|
+
if (stateNode) {
|
|
14311
|
+
bodyNode = stateNode;
|
|
11715
14312
|
} else if (props.virtualScroll && (!treeMode.value || !hasDetail.value)) {
|
|
11716
14313
|
bodyNode = vue.h(
|
|
11717
14314
|
IrisVirtualScroll,
|
|
@@ -11775,127 +14372,105 @@ var IrisTable = vue.defineComponent({
|
|
|
11775
14372
|
bodyChildren
|
|
11776
14373
|
);
|
|
11777
14374
|
}
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
|
|
11790
|
-
|
|
11791
|
-
|
|
11792
|
-
|
|
11793
|
-
|
|
11794
|
-
|
|
11795
|
-
|
|
11796
|
-
|
|
11797
|
-
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
|
|
11801
|
-
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
"div",
|
|
11806
|
-
{
|
|
11807
|
-
key: col.key,
|
|
11808
|
-
role: "cell",
|
|
11809
|
-
"data-iris-table-cell": col.key,
|
|
11810
|
-
"data-iris-table-summary-cell": op ? "" : void 0,
|
|
11811
|
-
"data-iris-table-pinned": col.pinned,
|
|
11812
|
-
style: {
|
|
11813
|
-
display: "flex",
|
|
11814
|
-
alignItems: "center",
|
|
11815
|
-
justifyContent: align === "right" ? "flex-end" : align === "center" ? "center" : "flex-start",
|
|
11816
|
-
padding: "var(--iris-space-xs, 8px) var(--iris-padding-md)",
|
|
11817
|
-
fontSize: "var(--iris-font-size-md, 14px)",
|
|
11818
|
-
whiteSpace: "nowrap",
|
|
11819
|
-
overflow: "hidden",
|
|
11820
|
-
textOverflow: "ellipsis",
|
|
11821
|
-
...visibleColSet.value ? { gridColumnStart: String(colTrack(ci)) } : {},
|
|
11822
|
-
...pinnedStyle(col.key)
|
|
11823
|
-
}
|
|
11824
|
-
},
|
|
11825
|
-
summaryContent
|
|
11826
|
-
)
|
|
11827
|
-
);
|
|
11828
|
-
}
|
|
11829
|
-
summaryRow = vue.h(
|
|
14375
|
+
const summaryRow = !tableError.value && !tableLoading.value ? renderTableSummaryRow({
|
|
14376
|
+
bodyData: bodyData.value,
|
|
14377
|
+
leafColumns: leafColumns.value,
|
|
14378
|
+
visibleColSet: visibleColSet.value,
|
|
14379
|
+
gridTemplate: gridTemplate.value,
|
|
14380
|
+
leadingCells: leadSummaryCells(),
|
|
14381
|
+
colTrack,
|
|
14382
|
+
getCellValue,
|
|
14383
|
+
pinnedStyle
|
|
14384
|
+
}) : null;
|
|
14385
|
+
const rootNodes = [
|
|
14386
|
+
tableViews.renderTabs(props.tableTabs),
|
|
14387
|
+
tableViews.renderViews(),
|
|
14388
|
+
buildFormSection(),
|
|
14389
|
+
buildToolbarSection(),
|
|
14390
|
+
props.clipConfig && props.clipConfig.copy !== false && activeCellRange() ? vue.h(
|
|
14391
|
+
"button",
|
|
14392
|
+
{ type: "button", "data-iris-table-range-copy": "", onClick: copyActiveRange },
|
|
14393
|
+
t("table.range.copy")
|
|
14394
|
+
) : null,
|
|
14395
|
+
renderImportPreviewSection({
|
|
14396
|
+
rows: importController.importPreviewRows.value,
|
|
14397
|
+
t,
|
|
14398
|
+
onConfirm: importController.confirmImportPreview,
|
|
14399
|
+
onCancel: importController.cancelImportPreview
|
|
14400
|
+
}),
|
|
14401
|
+
vue.h(
|
|
11830
14402
|
"div",
|
|
11831
14403
|
{
|
|
11832
|
-
|
|
11833
|
-
|
|
14404
|
+
...attrs,
|
|
14405
|
+
ref: (el) => {
|
|
14406
|
+
rootRef.value = el ?? null;
|
|
14407
|
+
},
|
|
14408
|
+
// A keyboard-navigable hierarchical table is a `treegrid`; otherwise the
|
|
14409
|
+
// grid/table role as before (treegrid implies managed cell focus).
|
|
14410
|
+
role: props.keyboardNavigation ? treeMode.value ? "treegrid" : "grid" : "table",
|
|
14411
|
+
"data-iris-table": "",
|
|
14412
|
+
"data-density": effectiveDensity.value,
|
|
14413
|
+
"data-printable": props.printable ? "true" : void 0,
|
|
14414
|
+
"data-virtual": props.virtualScroll ? "" : void 0,
|
|
14415
|
+
"data-column-virtualized": props.columnVirtualization ? "true" : void 0,
|
|
14416
|
+
onKeydown: props.keyboardNavigation || props.cellRange || props.clipConfig ? (e) => handleRootKeyDown(e) : void 0,
|
|
14417
|
+
onScroll: props.columnVirtualization ? (e) => {
|
|
14418
|
+
scrollLeft.value = e.currentTarget.scrollLeft;
|
|
14419
|
+
} : void 0,
|
|
14420
|
+
// Row/column drag-sort (batch Y): container-level pointer handling
|
|
14421
|
+
// for both reorders (React parity) — press happens on the row
|
|
14422
|
+
// handle / header cell, move/up resolve at the container.
|
|
14423
|
+
onPointermove: props.rowDrag || props.columnDrag ? (e) => {
|
|
14424
|
+
handleRowDragPointerMove(e);
|
|
14425
|
+
handleColDragPointerMove(e);
|
|
14426
|
+
} : void 0,
|
|
14427
|
+
onPointerup: props.rowDrag || props.columnDrag ? () => {
|
|
14428
|
+
handleRowDragPointerUp();
|
|
14429
|
+
handleColDragPointerUp();
|
|
14430
|
+
} : void 0,
|
|
14431
|
+
onPointerleave: props.rowDrag ? handleRowDragPointerLeave : void 0,
|
|
11834
14432
|
style: {
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
14433
|
+
background: "var(--iris-background)",
|
|
14434
|
+
color: "var(--iris-foreground)",
|
|
14435
|
+
fontSize: "var(--iris-font-size-md, 14px)",
|
|
14436
|
+
border: props.bordered ? "1px solid var(--iris-border)" : "none",
|
|
14437
|
+
borderRadius: "var(--iris-radius-md)",
|
|
14438
|
+
// Column virtualization and responsive overflow turn the table
|
|
14439
|
+
// into a horizontal scroll container.
|
|
14440
|
+
overflow: props.columnVirtualization || responsiveOverflow.value ? "auto" : "hidden",
|
|
14441
|
+
...responsiveOverflow.value ? { overflowX: "auto" } : {},
|
|
14442
|
+
...attrs.style ?? {}
|
|
11840
14443
|
}
|
|
11841
14444
|
},
|
|
11842
|
-
|
|
11843
|
-
)
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
14445
|
+
[headerRow, bodyNode, summaryRow, buildPagerSection()]
|
|
14446
|
+
),
|
|
14447
|
+
props.responsive && responsiveOverflow.value && !props.printable ? vue.h(
|
|
14448
|
+
"div",
|
|
14449
|
+
{
|
|
14450
|
+
"data-iris-scroll-hint": "",
|
|
14451
|
+
role: "status",
|
|
14452
|
+
"aria-live": "polite",
|
|
14453
|
+
style: {
|
|
14454
|
+
display: "flex",
|
|
14455
|
+
alignItems: "center",
|
|
14456
|
+
gap: "var(--iris-space-xxs, 4px)",
|
|
14457
|
+
padding: "var(--iris-space-xxs, 4px) var(--iris-space-sm, 12px)",
|
|
14458
|
+
color: "var(--iris-muted)",
|
|
14459
|
+
background: "var(--iris-surface)",
|
|
14460
|
+
borderInline: "1px solid var(--iris-border)",
|
|
14461
|
+
borderBottom: "1px solid var(--iris-border)",
|
|
14462
|
+
fontSize: "var(--iris-font-size-sm, 13px)"
|
|
14463
|
+
}
|
|
11851
14464
|
},
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
onKeydown: props.keyboardNavigation || props.cellRange ? (e) => {
|
|
11859
|
-
if (props.keyboardNavigation) handleGridKey(e);
|
|
11860
|
-
if (props.cellRange) handleCellRangeKey(e);
|
|
11861
|
-
} : void 0,
|
|
11862
|
-
onScroll: props.columnVirtualization ? (e) => {
|
|
11863
|
-
scrollLeft.value = e.currentTarget.scrollLeft;
|
|
11864
|
-
} : void 0,
|
|
11865
|
-
style: {
|
|
11866
|
-
background: "var(--iris-background)",
|
|
11867
|
-
color: "var(--iris-foreground)",
|
|
11868
|
-
fontSize: "var(--iris-font-size-md, 14px)",
|
|
11869
|
-
border: props.bordered ? "1px solid var(--iris-border)" : "none",
|
|
11870
|
-
borderRadius: "var(--iris-radius-md)",
|
|
11871
|
-
// Column virtualization turns the table into a horizontal scroll container.
|
|
11872
|
-
overflow: props.columnVirtualization ? "auto" : "hidden",
|
|
11873
|
-
...attrs.style ?? {}
|
|
11874
|
-
}
|
|
11875
|
-
},
|
|
11876
|
-
[headerRow, bodyNode, summaryRow]
|
|
11877
|
-
);
|
|
14465
|
+
[vue.h("span", { "aria-hidden": "true" }, "\u21C6"), vue.h("span", t("table.scrollHint"))]
|
|
14466
|
+
) : null,
|
|
14467
|
+
buildContextMenuSection(),
|
|
14468
|
+
buildFilterPanelSection()
|
|
14469
|
+
].filter((n) => n !== null);
|
|
14470
|
+
return rootNodes.length === 1 ? rootNodes[0] : rootNodes;
|
|
11878
14471
|
};
|
|
11879
14472
|
}
|
|
11880
14473
|
});
|
|
11881
|
-
function exportCsv(rows, columns) {
|
|
11882
|
-
return core.toCsv(
|
|
11883
|
-
rows,
|
|
11884
|
-
columns.map((column) => ({
|
|
11885
|
-
key: column.key,
|
|
11886
|
-
title: column.title,
|
|
11887
|
-
dataIndex: typeof column.dataIndex === "string" ? column.dataIndex : void 0
|
|
11888
|
-
}))
|
|
11889
|
-
);
|
|
11890
|
-
}
|
|
11891
|
-
async function downloadCsv(filename, csv) {
|
|
11892
|
-
const BOM = String.fromCharCode(65279);
|
|
11893
|
-
await core.downloadFile({
|
|
11894
|
-
filename,
|
|
11895
|
-
content: BOM + csv,
|
|
11896
|
-
mimeType: "text/csv;charset=utf-8;"
|
|
11897
|
-
});
|
|
11898
|
-
}
|
|
11899
14474
|
function exportExcel(rows, columns, options) {
|
|
11900
14475
|
return core.toSpreadsheetXml(
|
|
11901
14476
|
rows,
|
|
@@ -11916,7 +14491,7 @@ async function downloadExcel(filename, xml) {
|
|
|
11916
14491
|
}
|
|
11917
14492
|
|
|
11918
14493
|
// src/primitives/tabs/context.ts
|
|
11919
|
-
var TabsContextKey =
|
|
14494
|
+
var TabsContextKey = Symbol("IrisTabs");
|
|
11920
14495
|
|
|
11921
14496
|
// src/primitives/tabs/Tabs.ts
|
|
11922
14497
|
var IrisTabs = vue.defineComponent({
|
|
@@ -12216,7 +14791,7 @@ var IrisTabsContent = vue.defineComponent({
|
|
|
12216
14791
|
});
|
|
12217
14792
|
|
|
12218
14793
|
// src/primitives/menu/context.ts
|
|
12219
|
-
var MenuContextKey =
|
|
14794
|
+
var MenuContextKey = Symbol("IrisMenu");
|
|
12220
14795
|
|
|
12221
14796
|
// src/primitives/menu/Menu.ts
|
|
12222
14797
|
var IrisMenu = vue.defineComponent({
|
|
@@ -13063,6 +15638,29 @@ var TREE_STATE_STYLE = {
|
|
|
13063
15638
|
color: "var(--iris-muted)",
|
|
13064
15639
|
fontSize: "var(--iris-font-size-md, 14px)"
|
|
13065
15640
|
};
|
|
15641
|
+
function renderTreeState({
|
|
15642
|
+
state,
|
|
15643
|
+
stateKey,
|
|
15644
|
+
stateProps,
|
|
15645
|
+
slots,
|
|
15646
|
+
translate
|
|
15647
|
+
}) {
|
|
15648
|
+
const content = state === "error" ? slots.error ? slots.error() : translate("tree.error") : state === "loading" ? slots.loading ? slots.loading() : translate("tree.loading") : slots.empty ? slots.empty() : translate("tree.empty");
|
|
15649
|
+
return vue.h(
|
|
15650
|
+
"div",
|
|
15651
|
+
{
|
|
15652
|
+
key: stateKey,
|
|
15653
|
+
role: "presentation",
|
|
15654
|
+
"data-iris-tree-state": state,
|
|
15655
|
+
"aria-live": "polite",
|
|
15656
|
+
...stateProps,
|
|
15657
|
+
style: TREE_STATE_STYLE
|
|
15658
|
+
},
|
|
15659
|
+
content
|
|
15660
|
+
);
|
|
15661
|
+
}
|
|
15662
|
+
|
|
15663
|
+
// src/primitives/tree/Tree.ts
|
|
13066
15664
|
var IrisTree = vue.defineComponent({
|
|
13067
15665
|
name: "IrisTree",
|
|
13068
15666
|
inheritAttrs: false,
|
|
@@ -13292,21 +15890,6 @@ var IrisTree = vue.defineComponent({
|
|
|
13292
15890
|
break;
|
|
13293
15891
|
}
|
|
13294
15892
|
}
|
|
13295
|
-
const renderStateNode = () => {
|
|
13296
|
-
const content = state.value === "error" ? slots.error ? slots.error() : t("tree.error") : state.value === "loading" ? slots.loading ? slots.loading() : t("tree.loading") : slots.empty ? slots.empty() : t("tree.empty");
|
|
13297
|
-
return vue.h(
|
|
13298
|
-
"div",
|
|
13299
|
-
{
|
|
13300
|
-
key: stateKey.value,
|
|
13301
|
-
role: "presentation",
|
|
13302
|
-
"data-iris-tree-state": state.value,
|
|
13303
|
-
"aria-live": "polite",
|
|
13304
|
-
...stateProps.value,
|
|
13305
|
-
style: TREE_STATE_STYLE
|
|
13306
|
-
},
|
|
13307
|
-
content
|
|
13308
|
-
);
|
|
13309
|
-
};
|
|
13310
15893
|
const renderItems = () => {
|
|
13311
15894
|
void checkedKeys.value;
|
|
13312
15895
|
return flat.value.map((entry) => {
|
|
@@ -13439,7 +16022,15 @@ var IrisTree = vue.defineComponent({
|
|
|
13439
16022
|
...attrs.style ?? {}
|
|
13440
16023
|
}
|
|
13441
16024
|
},
|
|
13442
|
-
isContent.value ? renderItems() : [
|
|
16025
|
+
isContent.value ? renderItems() : [
|
|
16026
|
+
renderTreeState({
|
|
16027
|
+
state: state.value,
|
|
16028
|
+
stateKey: stateKey.value,
|
|
16029
|
+
stateProps: stateProps.value,
|
|
16030
|
+
slots,
|
|
16031
|
+
translate: t
|
|
16032
|
+
})
|
|
16033
|
+
]
|
|
13443
16034
|
);
|
|
13444
16035
|
}
|
|
13445
16036
|
});
|
|
@@ -18672,12 +21263,12 @@ function defaultFilter(query, item) {
|
|
|
18672
21263
|
if (!q) return 0;
|
|
18673
21264
|
const haystacks = [item.label, ...item.keywords ?? []].map((s) => s.toLowerCase());
|
|
18674
21265
|
let best = null;
|
|
18675
|
-
for (const
|
|
21266
|
+
for (const h136 of haystacks) {
|
|
18676
21267
|
let qi = 0;
|
|
18677
21268
|
let lastIdx = -1;
|
|
18678
21269
|
let score = 0;
|
|
18679
|
-
for (let i = 0; i <
|
|
18680
|
-
if (
|
|
21270
|
+
for (let i = 0; i < h136.length && qi < q.length; i += 1) {
|
|
21271
|
+
if (h136[i] === q[qi]) {
|
|
18681
21272
|
score += lastIdx === -1 ? i : i - lastIdx - 1;
|
|
18682
21273
|
lastIdx = i;
|
|
18683
21274
|
qi += 1;
|
|
@@ -19043,8 +21634,8 @@ var IrisTimePicker = vue.defineComponent({
|
|
|
19043
21634
|
if (props.format === "24h") {
|
|
19044
21635
|
return { h: value.value.hours, m: value.value.minutes };
|
|
19045
21636
|
}
|
|
19046
|
-
const
|
|
19047
|
-
return { h:
|
|
21637
|
+
const h1210 = value.value.hours % 12 === 0 ? 12 : value.value.hours % 12;
|
|
21638
|
+
return { h: h1210, m: value.value.minutes };
|
|
19048
21639
|
});
|
|
19049
21640
|
const emitNew = (next) => {
|
|
19050
21641
|
emit("update:modelValue", next);
|
|
@@ -19060,16 +21651,16 @@ var IrisTimePicker = vue.defineComponent({
|
|
|
19060
21651
|
};
|
|
19061
21652
|
const toggleMeridiem = () => {
|
|
19062
21653
|
const isPM = meridiem.value === "PM";
|
|
19063
|
-
const
|
|
19064
|
-
const newH24 = isPM ?
|
|
21654
|
+
const h1210 = value.value.hours % 12;
|
|
21655
|
+
const newH24 = isPM ? h1210 : h1210 + 12;
|
|
19065
21656
|
emitNew({ hours: newH24, minutes: value.value.minutes });
|
|
19066
21657
|
};
|
|
19067
21658
|
const onHoursInput = (e) => {
|
|
19068
21659
|
const v = parseInt(e.target.value || "0", 10);
|
|
19069
21660
|
if (Number.isNaN(v)) return;
|
|
19070
21661
|
if (props.format === "12h") {
|
|
19071
|
-
const
|
|
19072
|
-
const wrap =
|
|
21662
|
+
const h1210 = clamp5(v, 1, 12);
|
|
21663
|
+
const wrap = h1210 === 12 ? 0 : h1210;
|
|
19073
21664
|
const newH24 = meridiem.value === "PM" ? wrap + 12 : wrap;
|
|
19074
21665
|
setHours24(newH24);
|
|
19075
21666
|
} else {
|
|
@@ -20590,6 +23181,10 @@ Object.defineProperty(exports, "nodeAllowsRoles", {
|
|
|
20590
23181
|
enumerable: true,
|
|
20591
23182
|
get: function () { return core.nodeAllowsRoles; }
|
|
20592
23183
|
});
|
|
23184
|
+
Object.defineProperty(exports, "parseCsv", {
|
|
23185
|
+
enumerable: true,
|
|
23186
|
+
get: function () { return core.parseCsv; }
|
|
23187
|
+
});
|
|
20593
23188
|
Object.defineProperty(exports, "rgbToHex", {
|
|
20594
23189
|
enumerable: true,
|
|
20595
23190
|
get: function () { return core.rgbToHex; }
|