nuxt-ui-tools 1.16.10 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/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
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
ROW_ACTIONS_COLUMN_ID,
|
|
13
13
|
ROW_ACTIONS_COLUMN_WIDTH,
|
|
14
14
|
SELECT_COLUMN_ID,
|
|
15
|
-
SELECT_COLUMN_WIDTH
|
|
15
|
+
SELECT_COLUMN_WIDTH,
|
|
16
|
+
TREE_COLUMN_ID,
|
|
17
|
+
TREE_COLUMN_WIDTH
|
|
16
18
|
} from "./types.js";
|
|
17
19
|
const LABEL_CHAR_WIDTH = 7.2;
|
|
18
20
|
const LABEL_CHROME_WIDTH = 64;
|
|
@@ -21,7 +23,22 @@ function headerFloor(label, sortable) {
|
|
|
21
23
|
}
|
|
22
24
|
export function createColumnDefs(options) {
|
|
23
25
|
const defs = [];
|
|
24
|
-
if (options.params.
|
|
26
|
+
if (options.params.tree.enabled.value) {
|
|
27
|
+
defs.push({
|
|
28
|
+
enableResizing: false,
|
|
29
|
+
id: TREE_COLUMN_ID,
|
|
30
|
+
maxSize: MAX_COLUMN_SIZE,
|
|
31
|
+
meta: {
|
|
32
|
+
canHide: false,
|
|
33
|
+
internal: "tree",
|
|
34
|
+
label: "",
|
|
35
|
+
render: () => null,
|
|
36
|
+
sortable: false
|
|
37
|
+
},
|
|
38
|
+
minSize: TREE_COLUMN_WIDTH,
|
|
39
|
+
size: TREE_COLUMN_WIDTH
|
|
40
|
+
});
|
|
41
|
+
} else if (options.params.selection.selectionEnabled.value) {
|
|
25
42
|
const selection = createSelectionColumn({ params: options.params });
|
|
26
43
|
defs.push({
|
|
27
44
|
enableResizing: false,
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { ComputedRef, ShallowRef } from 'vue';
|
|
2
2
|
import type { UseTableDataReturn } from '../../composables/use-table-data.js';
|
|
3
3
|
import type { useTableState } from '../../composables/use-table-state.js';
|
|
4
|
+
import type { useTableTree } from '../../composables/use-table-tree.js';
|
|
4
5
|
import type { TableApi, TableColumnAlign, TableColumnPinned, GenericObject, TableLayout, TableSchemaView, TableRuntimeRecord, TableColumnSkeleton } from '../../types/index.js';
|
|
5
6
|
export declare const SELECT_COLUMN_ID = "__select";
|
|
6
7
|
export declare const SELECT_COLUMN_WIDTH = 44;
|
|
8
|
+
export declare const TREE_COLUMN_ID = "__tree";
|
|
9
|
+
/** The control column at depth zero; it grows from here by one gutter per level of depth. */
|
|
10
|
+
export declare const TREE_COLUMN_WIDTH: number;
|
|
7
11
|
export declare const ROW_ACTIONS_COLUMN_ID = "__row-actions";
|
|
8
12
|
export declare const ROW_ACTIONS_COLUMN_WIDTH = 56;
|
|
9
13
|
export type SchemaTableColumn = NonNullable<NonNullable<TableSchemaView['table']>['columns']>[number];
|
|
@@ -74,6 +78,7 @@ export interface UseTableColumnsParams {
|
|
|
74
78
|
selection: TableColumnsSelectionState;
|
|
75
79
|
tableLayout: ComputedRef<TableLayout>;
|
|
76
80
|
tableApi: ShallowRef<TableApi<unknown> | null>;
|
|
81
|
+
tree: ReturnType<typeof useTableTree>;
|
|
77
82
|
}
|
|
78
83
|
export interface TableColumnRenderParams {
|
|
79
84
|
column: SchemaTableColumn;
|
|
@@ -89,7 +94,7 @@ export interface TableCellRenderContext {
|
|
|
89
94
|
tableApi: TableApi<unknown>;
|
|
90
95
|
layout: TableLayout;
|
|
91
96
|
}
|
|
92
|
-
export type DataListColumnInternalKind = 'selection' | 'actions';
|
|
97
|
+
export type DataListColumnInternalKind = 'selection' | 'tree' | 'actions';
|
|
93
98
|
export interface DataListColumnMeta {
|
|
94
99
|
label: string;
|
|
95
100
|
icon?: string;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { TREE_CHECK_WIDTH, TREE_LEAD, getTreeColumnWidth } from "../tree.js";
|
|
1
2
|
export const SELECT_COLUMN_ID = "__select";
|
|
2
3
|
export const SELECT_COLUMN_WIDTH = 44;
|
|
4
|
+
export const TREE_COLUMN_ID = "__tree";
|
|
5
|
+
export const TREE_COLUMN_WIDTH = getTreeColumnWidth({
|
|
6
|
+
check: TREE_CHECK_WIDTH.md,
|
|
7
|
+
lead: TREE_LEAD,
|
|
8
|
+
maxDepth: 0
|
|
9
|
+
});
|
|
3
10
|
export const ROW_ACTIONS_COLUMN_ID = "__row-actions";
|
|
4
11
|
export const ROW_ACTIONS_COLUMN_WIDTH = 56;
|
|
5
12
|
export const DEFAULT_COLUMN_SIZE = 150;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { GenericObject, TableTreeIndex, TableTreeNode } from '../types/index.js';
|
|
2
|
+
/** Pixels one level of the tree adds: one rail gutter. The renderer hands the same number to CSS. */
|
|
3
|
+
export declare const TREE_GUTTER_WIDTH = 16;
|
|
4
|
+
/** The chevron's footprint, which a childless row keeps free so its rail lines up. */
|
|
5
|
+
export declare const TREE_TOGGLE_WIDTH = 16;
|
|
6
|
+
/** Between the chevron and the checkbox. */
|
|
7
|
+
export declare const TREE_GAP = 6;
|
|
8
|
+
/** Least space before the first gutter; the table's own left gutter wins when it is wider. */
|
|
9
|
+
export declare const TREE_LEAD = 6;
|
|
10
|
+
/** Clear space after the checkbox of the deepest row, so it never meets the column's edge. */
|
|
11
|
+
export declare const TREE_TRAIL = 6;
|
|
12
|
+
/** Width of a Nuxt UI checkbox box at each control size, which the tree cell always reserves. */
|
|
13
|
+
export declare const TREE_CHECK_WIDTH: {
|
|
14
|
+
readonly lg: 18;
|
|
15
|
+
readonly md: 16;
|
|
16
|
+
readonly sm: 14;
|
|
17
|
+
readonly xl: 20;
|
|
18
|
+
readonly xs: 12;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* The control column's width: lead, one gutter per level of the deepest loaded row, the chevron,
|
|
22
|
+
* the checkbox and a little room after it. Every row shares it, so the first data column starts at
|
|
23
|
+
* the same x on all of them and indentation happens inside the cell.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getTreeColumnWidth(params: {
|
|
26
|
+
lead: number;
|
|
27
|
+
maxDepth: number;
|
|
28
|
+
check: number;
|
|
29
|
+
}): number;
|
|
30
|
+
/** Every row under `rows`, the rows themselves first, however deep and whether open or not. */
|
|
31
|
+
export declare function flattenTreeRows(rows: readonly GenericObject[], childrenPath: string): GenericObject[];
|
|
32
|
+
/**
|
|
33
|
+
* Indexes the loaded rows once per data change: every node knows its depth, its parent and its
|
|
34
|
+
* children, so toggling a branch never walks the source again. A node holds no per-row arrays,
|
|
35
|
+
* which keeps the index linear however deep the tree goes.
|
|
36
|
+
*
|
|
37
|
+
* Built with an explicit stack, so a deep tree cannot overflow the call stack, and the nested
|
|
38
|
+
* source rows are left untouched: nothing is copied, mapped or tagged.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildTableTree(params: {
|
|
41
|
+
rows: readonly GenericObject[];
|
|
42
|
+
childrenPath: string;
|
|
43
|
+
getRowId: (row: GenericObject, index: number) => string;
|
|
44
|
+
}): TableTreeIndex;
|
|
45
|
+
/** The rows from the top level down to `node`, inclusive. */
|
|
46
|
+
export declare function getTreeLineage(node: TableTreeNode): TableTreeNode[];
|
|
47
|
+
/**
|
|
48
|
+
* One flag per gutter between the top level and the row's own: whether the ancestor that gutter
|
|
49
|
+
* belongs to still has a sibling below, so its rail runs through the row. A rail is only drawn
|
|
50
|
+
* through a row where the answer is yes, which is what stops a branch at its last child.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getTreeRails(node: TableTreeNode): boolean[];
|
|
53
|
+
/**
|
|
54
|
+
* The rows that are on screen: every top-level row, then the children of each open branch.
|
|
55
|
+
*
|
|
56
|
+
* This replaces TanStack's expanded row model on purpose. That model materialises every
|
|
57
|
+
* descendant before the virtualizer sees a row; here only the visible rows exist, so closed
|
|
58
|
+
* branches cost nothing however large they are.
|
|
59
|
+
*/
|
|
60
|
+
export declare function flattenVisibleTree(roots: readonly TableTreeNode[], isExpanded: (node: TableTreeNode) => boolean): TableTreeNode[];
|
|
61
|
+
/** The rows currently showing beneath `branch`, which follow it contiguously in `visible`. */
|
|
62
|
+
export declare function getVisibleDescendants(visible: readonly TableTreeNode[], branch: TableTreeNode, limit?: number): TableTreeNode[];
|
|
63
|
+
/** Whether `branch` starts open under a `defaultExpanded` setting. */
|
|
64
|
+
export declare function isOpenByDefault(defaultExpanded: boolean | number, depth: number): boolean;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { isObject } from "../../shared/utils/predicate.js";
|
|
2
|
+
import { getTableRowValue } from "./rows.js";
|
|
3
|
+
export const TREE_GUTTER_WIDTH = 16;
|
|
4
|
+
export const TREE_TOGGLE_WIDTH = 16;
|
|
5
|
+
export const TREE_GAP = 6;
|
|
6
|
+
export const TREE_LEAD = 6;
|
|
7
|
+
export const TREE_TRAIL = 6;
|
|
8
|
+
export const TREE_CHECK_WIDTH = { lg: 18, md: 16, sm: 14, xl: 20, xs: 12 };
|
|
9
|
+
export function getTreeColumnWidth(params) {
|
|
10
|
+
return params.lead + params.maxDepth * TREE_GUTTER_WIDTH + TREE_TOGGLE_WIDTH + TREE_GAP + params.check + TREE_TRAIL;
|
|
11
|
+
}
|
|
12
|
+
export function flattenTreeRows(rows, childrenPath) {
|
|
13
|
+
const flat = [];
|
|
14
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15
|
+
const stack = [...rows].reverse();
|
|
16
|
+
for (let row = stack.pop(); row; row = stack.pop()) {
|
|
17
|
+
if (seen.has(row)) continue;
|
|
18
|
+
seen.add(row);
|
|
19
|
+
flat.push(row);
|
|
20
|
+
const children = readChildren(row, childrenPath);
|
|
21
|
+
for (let position = children.length - 1; position >= 0; position -= 1) {
|
|
22
|
+
const child = children[position];
|
|
23
|
+
if (child) stack.push(child);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return flat;
|
|
27
|
+
}
|
|
28
|
+
function readChildren(row, childrenPath) {
|
|
29
|
+
const value = getTableRowValue({ path: childrenPath, row });
|
|
30
|
+
if (!Array.isArray(value)) return [];
|
|
31
|
+
const children = [];
|
|
32
|
+
for (const item of value) if (isObject(item)) children.push(item);
|
|
33
|
+
return children;
|
|
34
|
+
}
|
|
35
|
+
export function buildTableTree(params) {
|
|
36
|
+
const byId = /* @__PURE__ */ new Map();
|
|
37
|
+
const branches = [];
|
|
38
|
+
const duplicateIds = [];
|
|
39
|
+
const roots = [];
|
|
40
|
+
let maxDepth = 0;
|
|
41
|
+
const stack = [{ parent: null, rows: params.rows }];
|
|
42
|
+
for (let frame = stack.pop(); frame; frame = stack.pop()) {
|
|
43
|
+
const depth = frame.parent ? frame.parent.depth + 1 : 0;
|
|
44
|
+
const siblings = frame.parent ? frame.parent.childNodes : roots;
|
|
45
|
+
const created = [];
|
|
46
|
+
const rootIndexBase = frame.parent?.rootIndex;
|
|
47
|
+
for (const [index, row] of frame.rows.entries()) {
|
|
48
|
+
const id = params.getRowId(row, index);
|
|
49
|
+
if (byId.has(id)) {
|
|
50
|
+
duplicateIds.push(id);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const children = readChildren(row, params.childrenPath);
|
|
54
|
+
const node = {
|
|
55
|
+
childNodes: [],
|
|
56
|
+
depth,
|
|
57
|
+
hasChildren: children.length > 0,
|
|
58
|
+
id,
|
|
59
|
+
isLast: index === frame.rows.length - 1,
|
|
60
|
+
parent: frame.parent,
|
|
61
|
+
rootIndex: rootIndexBase ?? index,
|
|
62
|
+
row
|
|
63
|
+
};
|
|
64
|
+
byId.set(id, node);
|
|
65
|
+
created.push({ children, node });
|
|
66
|
+
siblings.push(node);
|
|
67
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
68
|
+
if (node.hasChildren) branches.push(node);
|
|
69
|
+
}
|
|
70
|
+
for (let position = created.length - 1; position >= 0; position -= 1) {
|
|
71
|
+
const entry = created[position];
|
|
72
|
+
if (entry?.node.hasChildren) stack.push({ parent: entry.node, rows: entry.children });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { branches, byId, duplicateIds, maxDepth, roots };
|
|
76
|
+
}
|
|
77
|
+
export function getTreeLineage(node) {
|
|
78
|
+
const lineage = [];
|
|
79
|
+
for (let current = node; current; current = current.parent)
|
|
80
|
+
lineage.unshift(current);
|
|
81
|
+
return lineage;
|
|
82
|
+
}
|
|
83
|
+
export function getTreeRails(node) {
|
|
84
|
+
return getTreeLineage(node).slice(1, -1).map((ancestor) => !ancestor.isLast);
|
|
85
|
+
}
|
|
86
|
+
export function flattenVisibleTree(roots, isExpanded) {
|
|
87
|
+
const visible = [];
|
|
88
|
+
const stack = [...roots].reverse();
|
|
89
|
+
for (let node = stack.pop(); node; node = stack.pop()) {
|
|
90
|
+
visible.push(node);
|
|
91
|
+
if (!node.hasChildren || !isExpanded(node)) continue;
|
|
92
|
+
for (let position = node.childNodes.length - 1; position >= 0; position -= 1) {
|
|
93
|
+
const child = node.childNodes[position];
|
|
94
|
+
if (child) stack.push(child);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return visible;
|
|
98
|
+
}
|
|
99
|
+
export function getVisibleDescendants(visible, branch, limit = Number.POSITIVE_INFINITY) {
|
|
100
|
+
const start = visible.indexOf(branch);
|
|
101
|
+
if (start === -1) return [];
|
|
102
|
+
const descendants = [];
|
|
103
|
+
for (let index = start + 1; index < visible.length && descendants.length < limit; index += 1) {
|
|
104
|
+
const node = visible[index];
|
|
105
|
+
if (!node || node.depth <= branch.depth) break;
|
|
106
|
+
descendants.push(node);
|
|
107
|
+
}
|
|
108
|
+
return descendants;
|
|
109
|
+
}
|
|
110
|
+
export function isOpenByDefault(defaultExpanded, depth) {
|
|
111
|
+
return defaultExpanded === true || defaultExpanded !== false && depth < defaultExpanded;
|
|
112
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-ui-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
4
4
|
"description": "Nuxt module and runtime toolkit for UI-heavy Nuxt applications",
|
|
5
5
|
"homepage": "https://github.com/ChronicStone/nuxt-ui-tools#readme",
|
|
6
6
|
"bugs": "https://github.com/ChronicStone/nuxt-ui-tools/issues",
|