nuxt-ui-tools 1.16.10 → 1.17.1
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/module.json +1 -1
- package/dist/runtime/i18n/locales/en.js +8 -0
- package/dist/runtime/i18n/locales/fr.js +8 -0
- package/dist/runtime/i18n/types.d.ts +8 -0
- package/dist/runtime/table/components/table/table-layout.d.ts +2 -0
- package/dist/runtime/table/components/table/table-layout.js +1 -0
- package/dist/runtime/table/components/table/table-renderer.d.vue.ts +6 -6
- package/dist/runtime/table/components/table/table-renderer.vue +75 -11
- package/dist/runtime/table/components/table/table-renderer.vue.d.ts +6 -6
- package/dist/runtime/table/components/table/table-row.d.vue.ts +15 -2
- package/dist/runtime/table/components/table/table-row.vue +23 -2
- package/dist/runtime/table/components/table/table-row.vue.d.ts +15 -2
- package/dist/runtime/table/components/table/table-tree-control.d.vue.ts +19 -0
- package/dist/runtime/table/components/table/table-tree-control.vue +112 -0
- package/dist/runtime/table/components/table/table-tree-control.vue.d.ts +19 -0
- package/dist/runtime/table/components/table/table-tree-header.d.vue.ts +3 -0
- package/dist/runtime/table/components/table/table-tree-header.vue +66 -0
- package/dist/runtime/table/components/table/table-tree-header.vue.d.ts +3 -0
- package/dist/runtime/table/composables/use-table-api.d.ts +2 -0
- package/dist/runtime/table/composables/use-table-api.js +2 -0
- package/dist/runtime/table/composables/use-table-internals.d.ts +48 -0
- package/dist/runtime/table/composables/use-table-internals.js +13 -4
- package/dist/runtime/table/composables/use-table-selection.d.ts +2 -0
- package/dist/runtime/table/composables/use-table-selection.js +15 -6
- package/dist/runtime/table/composables/use-table-tree.d.ts +36 -0
- package/dist/runtime/table/composables/use-table-tree.js +199 -0
- package/dist/runtime/table/types/index.d.ts +1 -0
- package/dist/runtime/table/types/layout.d.ts +3 -2
- package/dist/runtime/table/types/source.d.ts +6 -1
- package/dist/runtime/table/types/table-api.d.ts +6 -0
- package/dist/runtime/table/types/tree.d.ts +100 -0
- package/dist/runtime/table/types/tree.js +0 -0
- package/dist/runtime/table/utils/columns/defs.js +19 -2
- package/dist/runtime/table/utils/columns/types.d.ts +6 -1
- package/dist/runtime/table/utils/columns/types.js +7 -0
- package/dist/runtime/table/utils/index.d.ts +1 -0
- package/dist/runtime/table/utils/index.js +1 -0
- package/dist/runtime/table/utils/tree.d.ts +64 -0
- package/dist/runtime/table/utils/tree.js +112 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -727,6 +727,14 @@ export default defineUiToolsLocale({
|
|
|
727
727
|
rowOther: "rows",
|
|
728
728
|
selection: "Selection",
|
|
729
729
|
total: "Total"
|
|
730
|
+
},
|
|
731
|
+
tree: {
|
|
732
|
+
collapse: "Collapse row",
|
|
733
|
+
collapseAll: "Collapse all rows",
|
|
734
|
+
expand: "Expand row",
|
|
735
|
+
expandAll: "Expand all rows",
|
|
736
|
+
selectAll: "Select all rows",
|
|
737
|
+
selectRow: "Select row"
|
|
730
738
|
}
|
|
731
739
|
}
|
|
732
740
|
},
|
|
@@ -727,6 +727,14 @@ export default defineUiToolsLocale({
|
|
|
727
727
|
rowOther: "lignes",
|
|
728
728
|
selection: "S\xE9lection",
|
|
729
729
|
total: "Total"
|
|
730
|
+
},
|
|
731
|
+
tree: {
|
|
732
|
+
collapse: "Replier la ligne",
|
|
733
|
+
collapseAll: "Replier toutes les lignes",
|
|
734
|
+
expand: "D\xE9plier la ligne",
|
|
735
|
+
expandAll: "D\xE9plier toutes les lignes",
|
|
736
|
+
selectAll: "S\xE9lectionner toutes les lignes",
|
|
737
|
+
selectRow: "S\xE9lectionner la ligne"
|
|
730
738
|
}
|
|
731
739
|
}
|
|
732
740
|
},
|
|
@@ -50,6 +50,14 @@ export interface UiToolsTableMessages {
|
|
|
50
50
|
rowOne: string;
|
|
51
51
|
rowOther: string;
|
|
52
52
|
};
|
|
53
|
+
tree: {
|
|
54
|
+
expand: string;
|
|
55
|
+
collapse: string;
|
|
56
|
+
expandAll: string;
|
|
57
|
+
collapseAll: string;
|
|
58
|
+
selectRow: string;
|
|
59
|
+
selectAll: string;
|
|
60
|
+
};
|
|
53
61
|
columnsMenu: {
|
|
54
62
|
sortAsc: string;
|
|
55
63
|
sortDesc: string;
|
|
@@ -24,6 +24,7 @@ export declare function columnCellLayout(params: {
|
|
|
24
24
|
}): {
|
|
25
25
|
class: import("vue").ClassValue[];
|
|
26
26
|
innerClass: string;
|
|
27
|
+
internal: import("../../utils/index.js").DataListColumnInternalKind | undefined;
|
|
27
28
|
render: ((params: {
|
|
28
29
|
row: import("../../types/index.js").GenericObject;
|
|
29
30
|
index: number;
|
|
@@ -45,6 +46,7 @@ export declare function tableRowCells(params: {
|
|
|
45
46
|
layout: {
|
|
46
47
|
class: import("vue").ClassValue[];
|
|
47
48
|
innerClass: string;
|
|
49
|
+
internal: import("../../utils/index.js").DataListColumnInternalKind | undefined;
|
|
48
50
|
render: ((params: {
|
|
49
51
|
row: import("../../types/index.js").GenericObject;
|
|
50
52
|
index: number;
|
|
@@ -12,6 +12,7 @@ export function columnCellLayout(params) {
|
|
|
12
12
|
params.tdClass
|
|
13
13
|
],
|
|
14
14
|
innerClass: meta?.align === "right" ? "justify-end" : meta?.align === "center" ? "justify-center" : "",
|
|
15
|
+
internal: meta?.internal,
|
|
15
16
|
render: meta?.render,
|
|
16
17
|
style: [params.offset, meta?.lines ? { "--nut-dl-lines": meta.lines } : void 0]
|
|
17
18
|
};
|
|
@@ -8,7 +8,7 @@ type __VLS_Props = {
|
|
|
8
8
|
ui?: DataListTableUi;
|
|
9
9
|
};
|
|
10
10
|
declare function refresh(): void;
|
|
11
|
-
declare var
|
|
11
|
+
declare var __VLS_41: {
|
|
12
12
|
columnSlots: TableColumnSlot[];
|
|
13
13
|
leafColumns: import("@tanstack/table-core").Column<{
|
|
14
14
|
columnPinningFeature: import("@tanstack/table-core").TableFeature;
|
|
@@ -18,16 +18,16 @@ declare var __VLS_33: {
|
|
|
18
18
|
coreRowModel: (table: import("@tanstack/table-core").Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
|
|
19
19
|
columnMeta: import("../../utils/index.js").DataListColumnMeta;
|
|
20
20
|
}, object, unknown>[];
|
|
21
|
-
},
|
|
21
|
+
}, __VLS_43: {
|
|
22
22
|
error: {};
|
|
23
23
|
retry: typeof refresh;
|
|
24
|
-
},
|
|
24
|
+
}, __VLS_52: {};
|
|
25
25
|
type __VLS_Slots = {} & {
|
|
26
|
-
footer?: (props: typeof
|
|
26
|
+
footer?: (props: typeof __VLS_41) => any;
|
|
27
27
|
} & {
|
|
28
|
-
error?: (props: typeof
|
|
28
|
+
error?: (props: typeof __VLS_43) => any;
|
|
29
29
|
} & {
|
|
30
|
-
empty?: (props: typeof
|
|
30
|
+
empty?: (props: typeof __VLS_52) => any;
|
|
31
31
|
};
|
|
32
32
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
33
33
|
resetColumnSizing: () => void;
|
|
@@ -10,8 +10,17 @@ import { mergeDataListUiClass } from "../../utils";
|
|
|
10
10
|
import {
|
|
11
11
|
ROW_ACTIONS_COLUMN_ID,
|
|
12
12
|
SELECT_COLUMN_ID,
|
|
13
|
-
SELECT_COLUMN_WIDTH
|
|
13
|
+
SELECT_COLUMN_WIDTH,
|
|
14
|
+
TREE_COLUMN_ID
|
|
14
15
|
} from "../../utils/columns/types";
|
|
16
|
+
import {
|
|
17
|
+
TREE_CHECK_WIDTH,
|
|
18
|
+
TREE_GAP,
|
|
19
|
+
TREE_GUTTER_WIDTH,
|
|
20
|
+
TREE_LEAD,
|
|
21
|
+
TREE_TOGGLE_WIDTH,
|
|
22
|
+
getTreeColumnWidth
|
|
23
|
+
} from "../../utils/tree";
|
|
15
24
|
import DataListErrorState from "../data-list/data-list-error-state.vue";
|
|
16
25
|
import ProgressLine from "../layout/progress-line.vue";
|
|
17
26
|
import TableCell from "./table-cell";
|
|
@@ -21,6 +30,7 @@ import { columnCellLayout, tableRowCells } from "./table-layout";
|
|
|
21
30
|
import TableOverlayScrollbars from "./table-overlay-scrollbars.vue";
|
|
22
31
|
import TableRow from "./table-row.vue";
|
|
23
32
|
import TableSkeletonCell from "./table-skeleton-cell";
|
|
33
|
+
import TableTreeHeader from "./table-tree-header.vue";
|
|
24
34
|
const LOAD_MORE_THRESHOLD = 6;
|
|
25
35
|
const PREFETCH_VIEWPORTS = 3;
|
|
26
36
|
const VIRTUALIZE_ROW_THRESHOLD = 40;
|
|
@@ -43,6 +53,7 @@ const props = defineProps({
|
|
|
43
53
|
ui: { type: Object, required: false }
|
|
44
54
|
});
|
|
45
55
|
const internals = useTableInternals();
|
|
56
|
+
const { tree } = internals;
|
|
46
57
|
const dataListUi = useDataListUi();
|
|
47
58
|
const { locale, t } = useUiToolsLocale();
|
|
48
59
|
const rows = computed(
|
|
@@ -76,21 +87,35 @@ const tokenStyle = computed(() => ({
|
|
|
76
87
|
"--nut-dl-foot-h": `${tokens.value.head - 2}px`,
|
|
77
88
|
"--nut-dl-gutter": `${gutter.value}px`,
|
|
78
89
|
"--nut-dl-head-h": `${tokens.value.head}px`,
|
|
79
|
-
"--nut-dl-row-h": `${tokens.value.row}px
|
|
90
|
+
"--nut-dl-row-h": `${tokens.value.row}px`,
|
|
91
|
+
"--nut-dl-tree-gutter": `${TREE_GUTTER_WIDTH}px`,
|
|
92
|
+
"--nut-dl-tree-toggle": `${TREE_TOGGLE_WIDTH}px`,
|
|
93
|
+
"--nut-dl-tree-gap": `${TREE_GAP}px`,
|
|
94
|
+
"--nut-dl-tree-check": `${treeCheckWidth.value}px`,
|
|
95
|
+
"--nut-dl-tree-lead": `${treeLead.value}px`
|
|
80
96
|
}));
|
|
81
97
|
const { columnDefs } = internals.tableColumns;
|
|
82
98
|
const columnState = internals.tableColumns.tableState;
|
|
99
|
+
const treeLead = computed(() => Math.max(TREE_LEAD, gutter.value - 2));
|
|
100
|
+
const treeCheckWidth = computed(() => TREE_CHECK_WIDTH[dataListUi.controlSize.value]);
|
|
83
101
|
const columnSizing = computed({
|
|
84
102
|
get: () => {
|
|
85
103
|
const sizing = columnState.value.columnSizing ?? {};
|
|
86
|
-
|
|
104
|
+
const ids = new Set(columnDefs.value.map((def) => def.id));
|
|
105
|
+
const hasTree = ids.has(TREE_COLUMN_ID);
|
|
106
|
+
if (!gutterExtra.value && !hasTree) {
|
|
87
107
|
return sizing;
|
|
88
108
|
}
|
|
89
|
-
const ids = new Set(columnDefs.value.map((def) => def.id));
|
|
90
109
|
const next = { ...sizing };
|
|
91
|
-
if (ids.has(SELECT_COLUMN_ID) && !(SELECT_COLUMN_ID in sizing)) {
|
|
110
|
+
if (ids.has(SELECT_COLUMN_ID) && !(SELECT_COLUMN_ID in sizing) && gutterExtra.value) {
|
|
92
111
|
next[SELECT_COLUMN_ID] = SELECT_COLUMN_WIDTH + gutterExtra.value;
|
|
93
112
|
}
|
|
113
|
+
if (hasTree)
|
|
114
|
+
next[TREE_COLUMN_ID] = getTreeColumnWidth({
|
|
115
|
+
check: treeCheckWidth.value,
|
|
116
|
+
lead: treeLead.value,
|
|
117
|
+
maxDepth: tree.index.value.maxDepth
|
|
118
|
+
});
|
|
94
119
|
return next;
|
|
95
120
|
},
|
|
96
121
|
set: (columnSizing2) => {
|
|
@@ -100,20 +125,27 @@ const columnSizing = computed({
|
|
|
100
125
|
const pinned = computed(() => {
|
|
101
126
|
const ids = new Set(columnDefs.value.map((def) => def.id));
|
|
102
127
|
const left = (columnState.value.columnPinning?.left ?? []).filter(
|
|
103
|
-
(id) => ids.has(id) && id !== SELECT_COLUMN_ID
|
|
128
|
+
(id) => ids.has(id) && id !== SELECT_COLUMN_ID && id !== TREE_COLUMN_ID
|
|
104
129
|
);
|
|
105
130
|
const right = (columnState.value.columnPinning?.right ?? []).filter(
|
|
106
131
|
(id) => ids.has(id) && id !== ROW_ACTIONS_COLUMN_ID
|
|
107
132
|
);
|
|
108
133
|
return {
|
|
109
134
|
end: ids.has(ROW_ACTIONS_COLUMN_ID) ? [...right, ROW_ACTIONS_COLUMN_ID] : right,
|
|
110
|
-
start:
|
|
135
|
+
start: [
|
|
136
|
+
...ids.has(SELECT_COLUMN_ID) ? [SELECT_COLUMN_ID] : [],
|
|
137
|
+
...ids.has(TREE_COLUMN_ID) ? [TREE_COLUMN_ID] : [],
|
|
138
|
+
...left
|
|
139
|
+
]
|
|
111
140
|
};
|
|
112
141
|
});
|
|
113
142
|
function getRowId(row, index) {
|
|
114
143
|
return internals.selection.getRowId({ index, row });
|
|
115
144
|
}
|
|
116
|
-
const
|
|
145
|
+
const sourceRows = computed(
|
|
146
|
+
() => tree.enabled.value && rows.value.length > 0 ? tree.visibleRows.value : rows.value
|
|
147
|
+
);
|
|
148
|
+
const renderRows = computed(() => rowsMounted.value ? sourceRows.value : []);
|
|
117
149
|
const virtualized = computed(
|
|
118
150
|
() => renderRows.value.length >= VIRTUALIZE_ROW_THRESHOLD || renderRows.value.length * columnDefs.value.length >= VIRTUALIZE_CELL_THRESHOLD
|
|
119
151
|
);
|
|
@@ -358,7 +390,7 @@ onBeforeUnmount(() => {
|
|
|
358
390
|
resizeObserver?.disconnect();
|
|
359
391
|
});
|
|
360
392
|
watch(
|
|
361
|
-
[totalWidth, () =>
|
|
393
|
+
[totalWidth, () => sourceRows.value.length],
|
|
362
394
|
() => nextTick().then(() => {
|
|
363
395
|
columnVirtualizer.value.measure();
|
|
364
396
|
scrollbarsRef.value?.measure();
|
|
@@ -512,6 +544,25 @@ watch(
|
|
|
512
544
|
}, APPEND_WINDOW);
|
|
513
545
|
}
|
|
514
546
|
);
|
|
547
|
+
function isAppended(rowId, flatIndex) {
|
|
548
|
+
return (tree.nodeOf(rowId)?.rootIndex ?? flatIndex) >= appendedFrom.value;
|
|
549
|
+
}
|
|
550
|
+
function hasCheckbox(rowId) {
|
|
551
|
+
const node = tree.nodeOf(rowId);
|
|
552
|
+
return internals.selection.selectionEnabled.value && node !== void 0 && tree.isSelectable(node);
|
|
553
|
+
}
|
|
554
|
+
function onSelectRow(rowId, event) {
|
|
555
|
+
internals.selection.toggleRowSelection({
|
|
556
|
+
rowId,
|
|
557
|
+
selected: !internals.selection.isRowSelected({ rowId }),
|
|
558
|
+
shiftKey: event.shiftKey
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
function onBodyPointerOver(event) {
|
|
562
|
+
if (!tree.enabled.value || event.pointerType === "touch") return;
|
|
563
|
+
const row = event.target instanceof Element ? event.target.closest("tr") : null;
|
|
564
|
+
tree.lightLineage(row?.dataset.rowId);
|
|
565
|
+
}
|
|
515
566
|
function skeletonColumn(columnId) {
|
|
516
567
|
const meta = headerByColumnId.value.get(columnId)?.column.columnDef.meta;
|
|
517
568
|
if (meta?.internal === "selection") return { align: meta.align, skeleton: "check" };
|
|
@@ -646,6 +697,11 @@ defineExpose({ resetColumnSizing });
|
|
|
646
697
|
:row="HEADER_ROW"
|
|
647
698
|
:index="-1"
|
|
648
699
|
/>
|
|
700
|
+
<TableTreeHeader
|
|
701
|
+
v-else-if="
|
|
702
|
+
headerByColumnId.get(slot.columnId).column.columnDef.meta?.internal === 'tree'
|
|
703
|
+
"
|
|
704
|
+
/>
|
|
649
705
|
</div>
|
|
650
706
|
</template>
|
|
651
707
|
<TableColumnHeader
|
|
@@ -662,6 +718,8 @@ defineExpose({ resetColumnSizing });
|
|
|
662
718
|
<tbody
|
|
663
719
|
:class="mergeDataListUiClass('nut-dl-table__body', void 0, ui?.tbody)"
|
|
664
720
|
:data-replacing="replacing"
|
|
721
|
+
@pointerover="onBodyPointerOver"
|
|
722
|
+
@pointerleave="tree.lightLineage()"
|
|
665
723
|
>
|
|
666
724
|
<tr
|
|
667
725
|
v-if="virtualPaddingTop"
|
|
@@ -681,8 +739,14 @@ defineExpose({ resetColumnSizing });
|
|
|
681
739
|
:index="virtual.index"
|
|
682
740
|
:cells="rowCells"
|
|
683
741
|
:selected="internals.selection.isRowSelected({ rowId: String(row.id) })"
|
|
684
|
-
:appended="virtual.index
|
|
742
|
+
:appended="isAppended(row.id, virtual.index)"
|
|
685
743
|
:row-class="rowClass"
|
|
744
|
+
:node="tree.nodeOf(row.id)"
|
|
745
|
+
:expanded="tree.isExpanded(row.id)"
|
|
746
|
+
:checkbox="hasCheckbox(row.id)"
|
|
747
|
+
:motion="tree.motionOf(row.id)"
|
|
748
|
+
@toggle="tree.toggleRow(row.id)"
|
|
749
|
+
@select="onSelectRow(row.id, $event)"
|
|
686
750
|
/>
|
|
687
751
|
|
|
688
752
|
<tr
|
|
@@ -870,5 +934,5 @@ defineExpose({ resetColumnSizing });
|
|
|
870
934
|
<style>
|
|
871
935
|
.nut-dl-table{--nut-dl-surface:var(--nut-dl-table-surface,var(--ui-bg-elevated));--nut-dl-line:var(--nut-dl-table-line,var(--ui-border));--nut-dl-line-soft:var(--nut-dl-table-line-soft,var(--ui-border-muted));--nut-dl-head-bg:var(--nut-dl-table-head-bg,var(--ui-bg-muted));--nut-dl-head-fg:var(--nut-dl-table-head-fg,var(--ui-text-muted));--nut-dl-head-font:var(--nut-dl-table-head-font,11px);--nut-dl-head-weight:var(--nut-dl-table-head-weight,600);--nut-dl-head-tracking:var(--nut-dl-table-head-tracking,0.04em);--nut-dl-head-transform:var(--nut-dl-table-head-transform,none);--nut-dl-row-hover:var(--nut-dl-table-row-hover,var(--ui-bg-muted));--nut-dl-row-selected:var(
|
|
872
936
|
--nut-dl-table-row-selected,color-mix(in srgb,var(--ui-primary) 10%,var(--nut-dl-surface))
|
|
873
|
-
);--nut-dl-accent:var(--ui-primary);--nut-dl-cell-fg:var(--nut-dl-table-cell-fg,var(--ui-text-toned));--nut-dl-pin-line:var(--nut-dl-table-pin-line,var(--nut-dl-line))}.nut-dl-table__scroll{overflow-anchor:none;scrollbar-width:none}.nut-dl-table__scroll::-webkit-scrollbar{display:none}.nut-dl-th{color:var(--nut-dl-head-fg);font-size:var(--nut-dl-head-font);font-weight:var(--nut-dl-head-weight);letter-spacing:var(--nut-dl-head-tracking);text-transform:var(--nut-dl-head-transform);-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.nut-dl-table__fill,.nut-dl-table__spacer,.nut-dl-th{background:var(--nut-dl-head-bg);border-bottom:1px solid var(--nut-dl-line)}.nut-dl-tf{background:var(--nut-dl-head-bg);border-top:1px solid var(--nut-dl-line);color:var(--ui-text-highlighted);font-weight:var(--nut-dl-table-foot-weight,500);white-space:nowrap}tfoot .nut-dl-table__fill,tfoot .nut-dl-table__spacer{border-bottom:0;border-top:1px solid var(--nut-dl-line)}.nut-dl-spinner{animation:nut-dl-spin .8s linear infinite}@keyframes nut-dl-spin{to{transform:rotate(1turn)}}tbody .nut-dl-table__spacer{background:var(--nut-dl-surface);border-bottom:1px solid var(--nut-dl-line-soft)}tbody .nut-dl-table__fill{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft)}.nut-dl-th__btn--open{background:color-mix(in srgb,var(--nut-dl-head-fg) 8%,transparent)}.nut-dl-rz:after{background:var(--ui-border-accented);bottom:10px;content:"";opacity:0;position:absolute;right:0;top:10px;transition:opacity .12s;width:1px}.nut-dl-rz:hover:after,.nut-dl-th:hover .nut-dl-rz:after{opacity:1}.nut-dl-rz--active:after,.nut-dl-rz:hover:after{background:var(--nut-dl-accent);bottom:6px;left:2.5px;opacity:1;top:6px;width:2px}.nut-dl-row{background:var(--nut-dl-surface);transition:background-color .1s}.nut-dl-row:hover{background:var(--nut-dl-row-hover)}.nut-dl-row--selected,.nut-dl-row--selected:hover{background:var(--nut-dl-row-selected)}.nut-dl-td,.nut-dl-tf[data-col],.nut-dl-th__btn,.nut-dl-th__static{padding-left:var(--nut-dl-cell-l,var(--nut-dl-cell-x));padding-right:var(--nut-dl-cell-r,var(--nut-dl-cell-x))}.nut-dl-row>.nut-dl-td:first-child,.nut-dl-table__foot-row>.nut-dl-tf:first-child,.nut-dl-table__head-row>.nut-dl-th:first-child{--nut-dl-cell-l:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td:last-child,.nut-dl-table__foot-row>.nut-dl-tf:last-child,.nut-dl-table__head-row>.nut-dl-th:last-child{--nut-dl-cell-r:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td--actions:last-child,.nut-dl-table__foot-row>.nut-dl-tf--actions:last-child,.nut-dl-table__head-row>.nut-dl-th--actions:last-child,.nut-dl-td--actions,.nut-dl-tf--actions{--nut-dl-cell-l:var(--nut-dl-cell-x);--nut-dl-cell-r:var(--nut-dl-cell-x)}.nut-dl-td--actions .nut-dl-td__inner{justify-content:flex-end}.nut-dl-td{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft);box-sizing:border-box;color:var(--nut-dl-cell-fg);overflow:hidden;overflow-wrap:anywhere;padding-block:var(--nut-dl-cell-y,6px);white-space:normal}.nut-dl-table__table tbody:has(+tfoot)>.nut-dl-row:last-child>.nut-dl-td{border-bottom:0}.nut-dl-td{contain:paint}.nut-dl-td__inner{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--nut-dl-lines,3);line-clamp:var(--nut-dl-lines,3);max-height:calc(var(--nut-dl-lines, 3)*1.5em);overflow:hidden}.nut-dl-td--ellipsis{--nut-dl-lines:1;white-space:nowrap}.nut-dl-td--ellipsis .nut-dl-td__inner{display:block;text-overflow:ellipsis}.nut-dl-td--actions .nut-dl-td__inner,.nut-dl-td--selection .nut-dl-td__inner{align-items:center;display:flex}.nut-dl-td--actions,.nut-dl-td--selection{white-space:nowrap}.nut-dl-td--actions .nut-dl-td__inner>*{opacity:.55;transition:opacity .12s}.nut-dl-row:hover .nut-dl-td--actions .nut-dl-td__inner>*{opacity:1}.nut-dl-pin{position:sticky}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-line);bottom:0;content:"";pointer-events:none;position:absolute;top:0;width:1px}.nut-dl-pin--last-start:after{right:0}.nut-dl-pin--first-end:before{left:0}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-pin-line)}.nut-dl-td--actions.nut-dl-pin--first-end:before,.nut-dl-th--actions.nut-dl-pin--first-end:before{display:none}.nut-dl-skeleton{animation:nut-dl-shimmer 1.6s ease-in-out infinite;animation-delay:calc(var(--nut-dl-i, 0)*-90ms);background:linear-gradient(90deg,var(--ui-bg-accented) 0,var(--ui-bg-muted) 45%,var(--ui-bg-accented) 100%);background-size:200% 100%}.nut-dl-row--skeleton{animation:nut-dl-fade-in .18s ease .12s both}.nut-dl-row--appended{animation:nut-dl-fade-in .2s ease both}.nut-dl-table__body{transition:opacity .16s ease-out}.nut-dl-table__body[data-replacing=true]{opacity:.55;transition:opacity .2s ease-in .18s}@keyframes nut-dl-fade-in{0%{opacity:0}to{opacity:1}}@keyframes nut-dl-shimmer{0%{background-position:100% 0}to{background-position:-100% 0}}@media (prefers-reduced-motion:reduce){.nut-dl-row,.nut-dl-table__body{transition:none}.nut-dl-row--appended,.nut-dl-row--skeleton,.nut-dl-skeleton{animation:none}}
|
|
937
|
+
);--nut-dl-accent:var(--ui-primary);--nut-dl-cell-fg:var(--nut-dl-table-cell-fg,var(--ui-text-toned));--nut-dl-pin-line:var(--nut-dl-table-pin-line,var(--nut-dl-line));--nut-dl-rail:var(--nut-dl-table-rail,var(--ui-border-accented));--nut-dl-rail-lit:var(--nut-dl-table-rail-lit,var(--ui-primary));--nut-dl-rail-radius:var(--nut-dl-table-rail-radius,calc(var(--ui-radius)*1.5));--nut-dl-toggle-hover:var(--nut-dl-table-toggle-hover,var(--ui-bg-accented));--nut-dl-tree-shift:var(--nut-dl-table-tree-shift,6px)}.nut-dl-table__scroll{overflow-anchor:none;scrollbar-width:none}.nut-dl-table__scroll::-webkit-scrollbar{display:none}.nut-dl-th{color:var(--nut-dl-head-fg);font-size:var(--nut-dl-head-font);font-weight:var(--nut-dl-head-weight);letter-spacing:var(--nut-dl-head-tracking);text-transform:var(--nut-dl-head-transform);-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.nut-dl-table__fill,.nut-dl-table__spacer,.nut-dl-th{background:var(--nut-dl-head-bg);border-bottom:1px solid var(--nut-dl-line)}.nut-dl-tf{background:var(--nut-dl-head-bg);border-top:1px solid var(--nut-dl-line);color:var(--ui-text-highlighted);font-weight:var(--nut-dl-table-foot-weight,500);white-space:nowrap}tfoot .nut-dl-table__fill,tfoot .nut-dl-table__spacer{border-bottom:0;border-top:1px solid var(--nut-dl-line)}.nut-dl-spinner{animation:nut-dl-spin .8s linear infinite}@keyframes nut-dl-spin{to{transform:rotate(1turn)}}tbody .nut-dl-table__spacer{background:var(--nut-dl-surface);border-bottom:1px solid var(--nut-dl-line-soft)}tbody .nut-dl-table__fill{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft)}.nut-dl-th__btn--open{background:color-mix(in srgb,var(--nut-dl-head-fg) 8%,transparent)}.nut-dl-rz:after{background:var(--ui-border-accented);bottom:10px;content:"";opacity:0;position:absolute;right:0;top:10px;transition:opacity .12s;width:1px}.nut-dl-rz:hover:after,.nut-dl-th:hover .nut-dl-rz:after{opacity:1}.nut-dl-rz--active:after,.nut-dl-rz:hover:after{background:var(--nut-dl-accent);bottom:6px;left:2.5px;opacity:1;top:6px;width:2px}.nut-dl-row{background:var(--nut-dl-surface);transition:background-color .1s}.nut-dl-row:hover{background:var(--nut-dl-row-hover)}.nut-dl-row--selected,.nut-dl-row--selected:hover{background:var(--nut-dl-row-selected)}.nut-dl-td,.nut-dl-tf[data-col],.nut-dl-th__btn,.nut-dl-th__static{padding-left:var(--nut-dl-cell-l,var(--nut-dl-cell-x));padding-right:var(--nut-dl-cell-r,var(--nut-dl-cell-x))}.nut-dl-row>.nut-dl-td:first-child,.nut-dl-table__foot-row>.nut-dl-tf:first-child,.nut-dl-table__head-row>.nut-dl-th:first-child{--nut-dl-cell-l:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td:last-child,.nut-dl-table__foot-row>.nut-dl-tf:last-child,.nut-dl-table__head-row>.nut-dl-th:last-child{--nut-dl-cell-r:var(--nut-dl-gutter)}.nut-dl-row>.nut-dl-td--actions:last-child,.nut-dl-table__foot-row>.nut-dl-tf--actions:last-child,.nut-dl-table__head-row>.nut-dl-th--actions:last-child,.nut-dl-td--actions,.nut-dl-tf--actions{--nut-dl-cell-l:var(--nut-dl-cell-x);--nut-dl-cell-r:var(--nut-dl-cell-x)}.nut-dl-td--actions .nut-dl-td__inner{justify-content:flex-end}.nut-dl-td{background:inherit;border-bottom:1px solid var(--nut-dl-line-soft);box-sizing:border-box;color:var(--nut-dl-cell-fg);overflow:hidden;overflow-wrap:anywhere;padding-block:var(--nut-dl-cell-y,6px);white-space:normal}.nut-dl-table__table tbody:has(+tfoot)>.nut-dl-row:last-child>.nut-dl-td{border-bottom:0}.nut-dl-td{contain:paint}.nut-dl-td__inner{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--nut-dl-lines,3);line-clamp:var(--nut-dl-lines,3);max-height:calc(var(--nut-dl-lines, 3)*1.5em);overflow:hidden}.nut-dl-td--ellipsis{--nut-dl-lines:1;white-space:nowrap}.nut-dl-td--ellipsis .nut-dl-td__inner{display:block;text-overflow:ellipsis}.nut-dl-td--actions .nut-dl-td__inner,.nut-dl-td--selection .nut-dl-td__inner{align-items:center;display:flex}.nut-dl-td--actions,.nut-dl-td--selection{white-space:nowrap}.nut-dl-td--actions .nut-dl-td__inner>*{opacity:.55;transition:opacity .12s}.nut-dl-row:hover .nut-dl-td--actions .nut-dl-td__inner>*{opacity:1}.nut-dl-pin{position:sticky}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-line);bottom:0;content:"";pointer-events:none;position:absolute;top:0;width:1px}.nut-dl-pin--last-start:after{right:0}.nut-dl-pin--first-end:before{left:0}.nut-dl-pin--first-end:before,.nut-dl-pin--last-start:after{background:var(--nut-dl-pin-line)}.nut-dl-td--actions.nut-dl-pin--first-end:before,.nut-dl-th--actions.nut-dl-pin--first-end:before{display:none}.nut-dl-skeleton{animation:nut-dl-shimmer 1.6s ease-in-out infinite;animation-delay:calc(var(--nut-dl-i, 0)*-90ms);background:linear-gradient(90deg,var(--ui-bg-accented) 0,var(--ui-bg-muted) 45%,var(--ui-bg-accented) 100%);background-size:200% 100%}.nut-dl-row--skeleton{animation:nut-dl-fade-in .18s ease .12s both}.nut-dl-row--appended{animation:nut-dl-fade-in .2s ease both}.nut-dl-table__body{transition:opacity .16s ease-out}.nut-dl-table__body[data-replacing=true]{opacity:.55;transition:opacity .2s ease-in .18s}@keyframes nut-dl-fade-in{0%{opacity:0}to{opacity:1}}@keyframes nut-dl-shimmer{0%{background-position:100% 0}to{background-position:-100% 0}}@media (prefers-reduced-motion:reduce){.nut-dl-row,.nut-dl-table__body{transition:none}.nut-dl-row--appended,.nut-dl-row--skeleton,.nut-dl-skeleton{animation:none}}
|
|
874
938
|
</style>
|
|
@@ -8,7 +8,7 @@ type __VLS_Props = {
|
|
|
8
8
|
ui?: DataListTableUi;
|
|
9
9
|
};
|
|
10
10
|
declare function refresh(): void;
|
|
11
|
-
declare var
|
|
11
|
+
declare var __VLS_41: {
|
|
12
12
|
columnSlots: TableColumnSlot[];
|
|
13
13
|
leafColumns: import("@tanstack/table-core").Column<{
|
|
14
14
|
columnPinningFeature: import("@tanstack/table-core").TableFeature;
|
|
@@ -18,16 +18,16 @@ declare var __VLS_33: {
|
|
|
18
18
|
coreRowModel: (table: import("@tanstack/table-core").Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
|
|
19
19
|
columnMeta: import("../../utils/index.js").DataListColumnMeta;
|
|
20
20
|
}, object, unknown>[];
|
|
21
|
-
},
|
|
21
|
+
}, __VLS_43: {
|
|
22
22
|
error: {};
|
|
23
23
|
retry: typeof refresh;
|
|
24
|
-
},
|
|
24
|
+
}, __VLS_52: {};
|
|
25
25
|
type __VLS_Slots = {} & {
|
|
26
|
-
footer?: (props: typeof
|
|
26
|
+
footer?: (props: typeof __VLS_41) => any;
|
|
27
27
|
} & {
|
|
28
|
-
error?: (props: typeof
|
|
28
|
+
error?: (props: typeof __VLS_43) => any;
|
|
29
29
|
} & {
|
|
30
|
-
empty?: (props: typeof
|
|
30
|
+
empty?: (props: typeof __VLS_52) => any;
|
|
31
31
|
};
|
|
32
32
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
33
33
|
resetColumnSizing: () => void;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* so rows that stay on screen while the virtual window slides keep their cells untouched.
|
|
4
4
|
*/
|
|
5
5
|
import type { HTMLAttributes } from 'vue';
|
|
6
|
-
import type { GenericObject } from '../../types/index.js';
|
|
6
|
+
import type { GenericObject, TableTreeMotion, TableTreeNode } from '../../types/index.js';
|
|
7
7
|
import type { tableRowCells } from './table-layout.js';
|
|
8
8
|
type __VLS_Props = {
|
|
9
9
|
rowId: string;
|
|
@@ -13,7 +13,20 @@ type __VLS_Props = {
|
|
|
13
13
|
selected: boolean;
|
|
14
14
|
appended: boolean;
|
|
15
15
|
rowClass?: HTMLAttributes['class'];
|
|
16
|
+
/** Where the row sits in the tree; absent unless the schema configures `table.tree`. */
|
|
17
|
+
node?: TableTreeNode;
|
|
18
|
+
expanded?: boolean;
|
|
19
|
+
/** Whether the tree cell carries a checkbox for this row. */
|
|
20
|
+
checkbox?: boolean;
|
|
21
|
+
/** The row is being revealed or concealed by a branch opening or closing. */
|
|
22
|
+
motion?: TableTreeMotion;
|
|
16
23
|
};
|
|
17
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
24
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
select: (event: MouseEvent) => any;
|
|
26
|
+
toggle: () => any;
|
|
27
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
28
|
+
onSelect?: ((event: MouseEvent) => any) | undefined;
|
|
29
|
+
onToggle?: (() => any) | undefined;
|
|
30
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
31
|
declare const _default: typeof __VLS_export;
|
|
19
32
|
export default _default;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import TableCell from "./table-cell";
|
|
3
|
+
import TableTreeControl from "./table-tree-control.vue";
|
|
3
4
|
defineProps({
|
|
4
5
|
rowId: { type: String, required: true },
|
|
5
6
|
original: { type: Object, required: true },
|
|
@@ -7,8 +8,13 @@ defineProps({
|
|
|
7
8
|
cells: { type: null, required: true },
|
|
8
9
|
selected: { type: Boolean, required: true },
|
|
9
10
|
appended: { type: Boolean, required: true },
|
|
10
|
-
rowClass: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true }
|
|
11
|
+
rowClass: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
|
|
12
|
+
node: { type: Object, required: false },
|
|
13
|
+
expanded: { type: Boolean, required: false },
|
|
14
|
+
checkbox: { type: Boolean, required: false },
|
|
15
|
+
motion: { type: Object, required: false }
|
|
11
16
|
});
|
|
17
|
+
const emit = defineEmits(["toggle", "select"]);
|
|
12
18
|
</script>
|
|
13
19
|
|
|
14
20
|
<template>
|
|
@@ -17,10 +23,13 @@ defineProps({
|
|
|
17
23
|
:class="[
|
|
18
24
|
selected ? 'nut-dl-row--selected' : '',
|
|
19
25
|
appended ? 'nut-dl-row--appended' : '',
|
|
26
|
+
motion ? `nut-dl-row--${motion.kind === 'enter' ? 'reveal' : 'conceal'}` : '',
|
|
20
27
|
rowClass
|
|
21
28
|
]"
|
|
29
|
+
:style="motion ? { '--nut-dl-tree-i': motion.order } : void 0"
|
|
22
30
|
:data-index="index"
|
|
23
31
|
:data-row-id="rowId"
|
|
32
|
+
:data-tree-depth="node?.depth"
|
|
24
33
|
>
|
|
25
34
|
<template v-for="slot in cells" :key="slot.key">
|
|
26
35
|
<td v-if="slot.kind === 'fill'" class="nut-dl-table__fill p-0" aria-hidden="true" />
|
|
@@ -37,7 +46,19 @@ defineProps({
|
|
|
37
46
|
:data-col="slot.columnId"
|
|
38
47
|
:style="slot.layout.style"
|
|
39
48
|
>
|
|
40
|
-
<
|
|
49
|
+
<template v-if="slot.layout.internal === 'tree'">
|
|
50
|
+
<TableTreeControl
|
|
51
|
+
v-if="node"
|
|
52
|
+
:node="node"
|
|
53
|
+
:expanded="expanded === true"
|
|
54
|
+
:index="index"
|
|
55
|
+
:selected="selected"
|
|
56
|
+
:checkbox="checkbox === true"
|
|
57
|
+
@toggle="emit('toggle')"
|
|
58
|
+
@select="emit('select', $event)"
|
|
59
|
+
/>
|
|
60
|
+
</template>
|
|
61
|
+
<div v-else class="nut-dl-td__inner min-w-0" :class="slot.layout.innerClass">
|
|
41
62
|
<TableCell
|
|
42
63
|
v-if="slot.layout.render"
|
|
43
64
|
:index="index"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* so rows that stay on screen while the virtual window slides keep their cells untouched.
|
|
4
4
|
*/
|
|
5
5
|
import type { HTMLAttributes } from 'vue';
|
|
6
|
-
import type { GenericObject } from '../../types/index.js';
|
|
6
|
+
import type { GenericObject, TableTreeMotion, TableTreeNode } from '../../types/index.js';
|
|
7
7
|
import type { tableRowCells } from './table-layout.js';
|
|
8
8
|
type __VLS_Props = {
|
|
9
9
|
rowId: string;
|
|
@@ -13,7 +13,20 @@ type __VLS_Props = {
|
|
|
13
13
|
selected: boolean;
|
|
14
14
|
appended: boolean;
|
|
15
15
|
rowClass?: HTMLAttributes['class'];
|
|
16
|
+
/** Where the row sits in the tree; absent unless the schema configures `table.tree`. */
|
|
17
|
+
node?: TableTreeNode;
|
|
18
|
+
expanded?: boolean;
|
|
19
|
+
/** Whether the tree cell carries a checkbox for this row. */
|
|
20
|
+
checkbox?: boolean;
|
|
21
|
+
/** The row is being revealed or concealed by a branch opening or closing. */
|
|
22
|
+
motion?: TableTreeMotion;
|
|
16
23
|
};
|
|
17
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
24
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
select: (event: MouseEvent) => any;
|
|
26
|
+
toggle: () => any;
|
|
27
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
28
|
+
onSelect?: ((event: MouseEvent) => any) | undefined;
|
|
29
|
+
onToggle?: (() => any) | undefined;
|
|
30
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
31
|
declare const _default: typeof __VLS_export;
|
|
19
32
|
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TableTreeNode } from '../../types/index.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
node: TableTreeNode;
|
|
4
|
+
expanded: boolean;
|
|
5
|
+
/** The row's position in the rendered list: a lit rail stops at the row under the pointer. */
|
|
6
|
+
index: number;
|
|
7
|
+
selected: boolean;
|
|
8
|
+
/** Whether the row carries a checkbox; its width is reserved either way. */
|
|
9
|
+
checkbox: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
select: (event: MouseEvent) => any;
|
|
13
|
+
toggle: () => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
onSelect?: ((event: MouseEvent) => any) | undefined;
|
|
16
|
+
onToggle?: (() => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useUiToolsLocale } from "#ui-tools/i18n";
|
|
4
|
+
import { useTableInternals } from "../../composables/use-table-internals";
|
|
5
|
+
import { getTreeLineage, getTreeRails } from "../../utils/tree";
|
|
6
|
+
import TableSelectionControl from "./table-selection-control.vue";
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
node: { type: Object, required: true },
|
|
9
|
+
expanded: { type: Boolean, required: true },
|
|
10
|
+
index: { type: Number, required: true },
|
|
11
|
+
selected: { type: Boolean, required: true },
|
|
12
|
+
checkbox: { type: Boolean, required: true }
|
|
13
|
+
});
|
|
14
|
+
const emit = defineEmits(["toggle", "select"]);
|
|
15
|
+
const { t } = useUiToolsLocale();
|
|
16
|
+
const { tree } = useTableInternals();
|
|
17
|
+
const lineage = computed(() => getTreeLineage(props.node));
|
|
18
|
+
const rails = computed(() => getTreeRails(props.node));
|
|
19
|
+
const lit = computed(() => {
|
|
20
|
+
let states = "";
|
|
21
|
+
for (let position = 0; position < props.node.depth; position += 1) {
|
|
22
|
+
const group = lineage.value[position];
|
|
23
|
+
const until = group === void 0 ? -1 : tree.litUntil(group.id);
|
|
24
|
+
states += props.index === until ? "t" : props.index < until ? "v" : "-";
|
|
25
|
+
}
|
|
26
|
+
return states;
|
|
27
|
+
});
|
|
28
|
+
const onPath = computed(() => tree.isOnPath(props.node.id));
|
|
29
|
+
const gutters = computed(
|
|
30
|
+
() => Array.from({ length: props.node.depth }, (_, position) => {
|
|
31
|
+
const own = position === props.node.depth - 1;
|
|
32
|
+
return {
|
|
33
|
+
/* This row's own level: down from the top, then a rounded turn toward the chevron. */
|
|
34
|
+
elbow: own,
|
|
35
|
+
lit: lit.value[position],
|
|
36
|
+
position,
|
|
37
|
+
/* An ancestor with a sibling still to come keeps its rail running through this row. */
|
|
38
|
+
rail: !own && rails.value[position] === true,
|
|
39
|
+
/* Siblings follow, so this row's own rail carries on below the turn. */
|
|
40
|
+
tail: own && !props.node.isLast
|
|
41
|
+
};
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
function onKeydown(event) {
|
|
45
|
+
const opens = event.key === "ArrowRight" && !props.expanded;
|
|
46
|
+
const closes = event.key === "ArrowLeft" && props.expanded;
|
|
47
|
+
if (!opens && !closes) return;
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
emit("toggle");
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<div class="nut-dl-tree" :class="{ 'nut-dl-tree--leaf': !node.hasChildren }">
|
|
55
|
+
<span class="nut-dl-tree__rule" aria-hidden="true" />
|
|
56
|
+
<span
|
|
57
|
+
v-for="gutter in gutters"
|
|
58
|
+
:key="gutter.position"
|
|
59
|
+
class="nut-dl-tree__gutter"
|
|
60
|
+
:class="{
|
|
61
|
+
'nut-dl-tree__gutter--elbow': gutter.elbow,
|
|
62
|
+
'nut-dl-tree__gutter--rail': gutter.rail,
|
|
63
|
+
'nut-dl-tree__gutter--tail': gutter.tail
|
|
64
|
+
}"
|
|
65
|
+
:data-lit="gutter.lit === '-' ? void 0 : gutter.lit"
|
|
66
|
+
aria-hidden="true"
|
|
67
|
+
/>
|
|
68
|
+
<span
|
|
69
|
+
class="nut-dl-tree__node"
|
|
70
|
+
:data-open="expanded || void 0"
|
|
71
|
+
:data-path="onPath || void 0"
|
|
72
|
+
>
|
|
73
|
+
<button
|
|
74
|
+
v-if="node.hasChildren"
|
|
75
|
+
type="button"
|
|
76
|
+
class="nut-dl-tree__toggle"
|
|
77
|
+
:aria-expanded="expanded"
|
|
78
|
+
:aria-label="expanded ? t('table.tree.collapse') : t('table.tree.expand')"
|
|
79
|
+
@click.stop="emit('toggle')"
|
|
80
|
+
@keydown="onKeydown"
|
|
81
|
+
>
|
|
82
|
+
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" aria-hidden="true">
|
|
83
|
+
<path
|
|
84
|
+
d="m9 18 6-6-6-6"
|
|
85
|
+
stroke="currentColor"
|
|
86
|
+
stroke-width="2.5"
|
|
87
|
+
stroke-linecap="round"
|
|
88
|
+
stroke-linejoin="round"
|
|
89
|
+
/>
|
|
90
|
+
</svg>
|
|
91
|
+
</button>
|
|
92
|
+
<!--
|
|
93
|
+
A childless row keeps the chevron's footprint empty, so every elbow and rail lines up with
|
|
94
|
+
its siblings that do have one. This branch and the shared width in `.nut-dl-tree__slot`
|
|
95
|
+
are the whole decision: drop both to let childless rows pull left instead.
|
|
96
|
+
-->
|
|
97
|
+
<span v-else class="nut-dl-tree__slot" aria-hidden="true" />
|
|
98
|
+
</span>
|
|
99
|
+
<span class="nut-dl-tree__check">
|
|
100
|
+
<TableSelectionControl
|
|
101
|
+
v-if="checkbox"
|
|
102
|
+
:model-value="selected"
|
|
103
|
+
:ariaLabel="t('table.tree.selectRow')"
|
|
104
|
+
@toggle="emit('select', $event)"
|
|
105
|
+
/>
|
|
106
|
+
</span>
|
|
107
|
+
</div>
|
|
108
|
+
</template>
|
|
109
|
+
|
|
110
|
+
<style>
|
|
111
|
+
.nut-dl-tree{align-items:stretch;display:flex;inset:0;padding-left:var(--nut-dl-tree-lead);position:absolute;--nut-dl-tree-axis:calc(var(--nut-dl-tree-toggle)/2);--nut-dl-tree-arm:calc(var(--nut-dl-tree-gutter) - var(--nut-dl-tree-axis) + 1px)}.nut-dl-tree--leaf{--nut-dl-tree-arm:var(--nut-dl-tree-gutter)}.nut-dl-tree__gutter{--nut-dl-tree-vertical:var(--nut-dl-rail);--nut-dl-tree-turn:var(--nut-dl-rail);--nut-dl-tree-tail:var(--nut-dl-rail);align-self:stretch;flex:none;position:relative;width:var(--nut-dl-tree-gutter)}.nut-dl-tree__gutter[data-lit=v]{--nut-dl-tree-vertical:var(--nut-dl-rail-lit);--nut-dl-tree-tail:var(--nut-dl-rail-lit)}.nut-dl-tree__gutter[data-lit=t]{--nut-dl-tree-vertical:var(--nut-dl-rail-lit);--nut-dl-tree-turn:var(--nut-dl-rail-lit)}.nut-dl-tree__gutter--rail:before,.nut-dl-tree__gutter--tail:after{content:"";left:var(--nut-dl-tree-axis);position:absolute;transition:background-color .14s ease;width:1px}.nut-dl-tree__gutter--rail:before{background:var(--nut-dl-tree-vertical)}.nut-dl-tree__gutter--tail:after{background:var(--nut-dl-tree-tail)}.nut-dl-tree__gutter--rail:before{bottom:0;top:0}.nut-dl-tree__gutter--tail:after{bottom:0;top:50%}.nut-dl-tree__gutter--elbow:before{border-bottom:1px solid var(--nut-dl-tree-turn);border-bottom-left-radius:var(--nut-dl-rail-radius);border-left:1px solid var(--nut-dl-tree-vertical);box-sizing:border-box;content:"";height:50%;left:var(--nut-dl-tree-axis);position:absolute;top:0;transition:border-color .14s ease;width:var(--nut-dl-tree-arm)}.nut-dl-tree__node{align-items:center;align-self:stretch;display:flex;flex:none;position:relative}.nut-dl-tree__node:after{background:var(--nut-dl-rail);bottom:0;content:"";left:var(--nut-dl-tree-axis);opacity:0;position:absolute;top:calc(50% + var(--nut-dl-tree-axis) + 1px);transition:opacity .16s ease,background-color .14s ease;width:1px}.nut-dl-tree__node[data-open]:after{opacity:1}.nut-dl-tree__node[data-path]:after{background:var(--nut-dl-rail-lit)}.nut-dl-tree__slot,.nut-dl-tree__toggle{flex:none;height:var(--nut-dl-tree-toggle);width:var(--nut-dl-tree-toggle)}.nut-dl-tree__toggle{background:transparent;border:0;border-radius:var(--nut-dl-rail-radius);color:var(--ui-text-dimmed);cursor:pointer;display:grid;outline:none;padding:0;place-items:center;position:relative;transition:background-color .12s ease,color .12s ease,transform .12s ease}.nut-dl-tree__toggle:before{content:"";inset:-8px -5px;position:absolute}.nut-dl-tree__toggle:hover{background:var(--nut-dl-toggle-hover);color:var(--ui-text-highlighted)}.nut-dl-tree__toggle:active{background:color-mix(in srgb,var(--ui-text) 10%,var(--nut-dl-toggle-hover));transform:scale(.9)}.nut-dl-tree__toggle:focus-visible{outline:2px solid var(--nut-dl-accent);outline-offset:1px}.nut-dl-tree__toggle[aria-expanded=true]{color:var(--ui-text-toned)}.nut-dl-tree__toggle svg{transition:transform .18s cubic-bezier(.2,.8,.2,1)}.nut-dl-tree__toggle[aria-expanded=true] svg{transform:rotate(90deg)}.nut-dl-tree__check{align-items:center;align-self:stretch;display:flex;flex:none;margin-left:var(--nut-dl-tree-gap);width:var(--nut-dl-tree-check)}.nut-dl-tree__rule{background:var(--nut-dl-line-soft);height:1px;inset:auto 0 0;position:absolute}.nut-dl-table__table tbody:has(+tfoot)>.nut-dl-row:last-child .nut-dl-tree__rule{display:none}.nut-dl-row>.nut-dl-td.nut-dl-td--tree,.nut-dl-row>.nut-dl-td.nut-dl-td--tree:first-child{border-bottom:0;padding:0}.nut-dl-td--tree:not(.nut-dl-pin){position:relative}.nut-dl-th--tree .nut-dl-th__static{padding-left:var(--nut-dl-tree-lead);padding-right:0}.nut-dl-row--reveal{animation:nut-dl-tree-reveal .19s cubic-bezier(.2,.8,.2,1) both;animation-delay:calc(var(--nut-dl-tree-i, 0)*24ms)}.nut-dl-row--conceal{animation:nut-dl-tree-conceal .12s ease-in both;pointer-events:none}@keyframes nut-dl-tree-reveal{0%{opacity:0;transform:translateY(calc(var(--nut-dl-tree-shift)*-1))}to{opacity:1;transform:none}}@keyframes nut-dl-tree-conceal{0%{opacity:1;transform:none}to{opacity:0;transform:translateY(calc(var(--nut-dl-tree-shift)*-1))}}@media (prefers-reduced-motion:reduce){.nut-dl-row--conceal,.nut-dl-row--reveal{animation:none}.nut-dl-tree__gutter--elbow:before,.nut-dl-tree__gutter--rail:before,.nut-dl-tree__gutter--tail:after,.nut-dl-tree__node:after,.nut-dl-tree__toggle,.nut-dl-tree__toggle svg{transition:none}}
|
|
112
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TableTreeNode } from '../../types/index.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
node: TableTreeNode;
|
|
4
|
+
expanded: boolean;
|
|
5
|
+
/** The row's position in the rendered list: a lit rail stops at the row under the pointer. */
|
|
6
|
+
index: number;
|
|
7
|
+
selected: boolean;
|
|
8
|
+
/** Whether the row carries a checkbox; its width is reserved either way. */
|
|
9
|
+
checkbox: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
select: (event: MouseEvent) => any;
|
|
13
|
+
toggle: () => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
onSelect?: ((event: MouseEvent) => any) | undefined;
|
|
16
|
+
onToggle?: (() => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|