@stonecrop/atable 0.4.24 → 0.4.26
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/README.md +47 -1
- package/dist/assets/index.css +1 -1
- package/dist/atable.d.ts +13 -67
- package/dist/atable.js +1148 -1102
- package/dist/atable.js.map +1 -1
- package/dist/atable.umd.cjs +2 -2
- package/dist/atable.umd.cjs.map +1 -1
- package/dist/src/stores/table.d.ts +12 -67
- package/dist/src/stores/table.d.ts.map +1 -1
- package/dist/stores/table.js +101 -37
- package/package.json +3 -3
- package/src/components/ATable.vue +29 -13
- package/src/stores/table.ts +116 -42
|
@@ -11,10 +11,6 @@ export declare const createTableStore: (initData: {
|
|
|
11
11
|
rows: TableRow[];
|
|
12
12
|
id?: string;
|
|
13
13
|
config?: TableConfig;
|
|
14
|
-
table?: {
|
|
15
|
-
[key: string]: any;
|
|
16
|
-
};
|
|
17
|
-
display?: TableDisplay[];
|
|
18
14
|
modal?: TableModal;
|
|
19
15
|
}) => import("pinia").Store<`table-${string}`, Pick<{
|
|
20
16
|
columns: import("vue").Ref<{
|
|
@@ -117,25 +113,7 @@ export declare const createTableStore: (initData: {
|
|
|
117
113
|
} | undefined;
|
|
118
114
|
label?: string | undefined;
|
|
119
115
|
}[]>;
|
|
120
|
-
display: import("vue").
|
|
121
|
-
expanded?: boolean | undefined;
|
|
122
|
-
childrenOpen?: boolean | undefined;
|
|
123
|
-
isParent?: boolean | undefined;
|
|
124
|
-
isRoot?: boolean | undefined;
|
|
125
|
-
open?: boolean | undefined;
|
|
126
|
-
indent?: number | undefined;
|
|
127
|
-
parent?: number | undefined;
|
|
128
|
-
rowModified?: boolean | undefined;
|
|
129
|
-
}[], TableDisplay[] | {
|
|
130
|
-
expanded?: boolean | undefined;
|
|
131
|
-
childrenOpen?: boolean | undefined;
|
|
132
|
-
isParent?: boolean | undefined;
|
|
133
|
-
isRoot?: boolean | undefined;
|
|
134
|
-
open?: boolean | undefined;
|
|
135
|
-
indent?: number | undefined;
|
|
136
|
-
parent?: number | undefined;
|
|
137
|
-
rowModified?: boolean | undefined;
|
|
138
|
-
}[]>;
|
|
116
|
+
display: import("vue").WritableComputedRef<TableDisplay[], TableDisplay[]>;
|
|
139
117
|
ganttBars: import("vue").Ref<{
|
|
140
118
|
id: string;
|
|
141
119
|
rowIndex: number;
|
|
@@ -207,7 +185,7 @@ export declare const createTableStore: (initData: {
|
|
|
207
185
|
colspan?: number | undefined;
|
|
208
186
|
} | undefined;
|
|
209
187
|
}[]>;
|
|
210
|
-
table: import("vue").
|
|
188
|
+
table: import("vue").ComputedRef<{}>;
|
|
211
189
|
updates: import("vue").Ref<Record<string, string>, Record<string, string>>;
|
|
212
190
|
hasPinnedColumns: import("vue").ComputedRef<boolean>;
|
|
213
191
|
isGanttView: import("vue").ComputedRef<boolean>;
|
|
@@ -265,7 +243,8 @@ export declare const createTableStore: (initData: {
|
|
|
265
243
|
unregisterConnectionHandle: (handleId: string) => void;
|
|
266
244
|
unregisterGanttBar: (barId: string) => void;
|
|
267
245
|
updateGanttBar: (event: GanttDragEvent) => void;
|
|
268
|
-
|
|
246
|
+
updateRows: (newRows: TableRow[]) => void;
|
|
247
|
+
}, "columns" | "config" | "connectionHandles" | "connectionPaths" | "ganttBars" | "modal" | "rows" | "updates">, Pick<{
|
|
269
248
|
columns: import("vue").Ref<{
|
|
270
249
|
name: string;
|
|
271
250
|
align?: CanvasTextAlign | undefined;
|
|
@@ -366,25 +345,7 @@ export declare const createTableStore: (initData: {
|
|
|
366
345
|
} | undefined;
|
|
367
346
|
label?: string | undefined;
|
|
368
347
|
}[]>;
|
|
369
|
-
display: import("vue").
|
|
370
|
-
expanded?: boolean | undefined;
|
|
371
|
-
childrenOpen?: boolean | undefined;
|
|
372
|
-
isParent?: boolean | undefined;
|
|
373
|
-
isRoot?: boolean | undefined;
|
|
374
|
-
open?: boolean | undefined;
|
|
375
|
-
indent?: number | undefined;
|
|
376
|
-
parent?: number | undefined;
|
|
377
|
-
rowModified?: boolean | undefined;
|
|
378
|
-
}[], TableDisplay[] | {
|
|
379
|
-
expanded?: boolean | undefined;
|
|
380
|
-
childrenOpen?: boolean | undefined;
|
|
381
|
-
isParent?: boolean | undefined;
|
|
382
|
-
isRoot?: boolean | undefined;
|
|
383
|
-
open?: boolean | undefined;
|
|
384
|
-
indent?: number | undefined;
|
|
385
|
-
parent?: number | undefined;
|
|
386
|
-
rowModified?: boolean | undefined;
|
|
387
|
-
}[]>;
|
|
348
|
+
display: import("vue").WritableComputedRef<TableDisplay[], TableDisplay[]>;
|
|
388
349
|
ganttBars: import("vue").Ref<{
|
|
389
350
|
id: string;
|
|
390
351
|
rowIndex: number;
|
|
@@ -456,7 +417,7 @@ export declare const createTableStore: (initData: {
|
|
|
456
417
|
colspan?: number | undefined;
|
|
457
418
|
} | undefined;
|
|
458
419
|
}[]>;
|
|
459
|
-
table: import("vue").
|
|
420
|
+
table: import("vue").ComputedRef<{}>;
|
|
460
421
|
updates: import("vue").Ref<Record<string, string>, Record<string, string>>;
|
|
461
422
|
hasPinnedColumns: import("vue").ComputedRef<boolean>;
|
|
462
423
|
isGanttView: import("vue").ComputedRef<boolean>;
|
|
@@ -514,7 +475,8 @@ export declare const createTableStore: (initData: {
|
|
|
514
475
|
unregisterConnectionHandle: (handleId: string) => void;
|
|
515
476
|
unregisterGanttBar: (barId: string) => void;
|
|
516
477
|
updateGanttBar: (event: GanttDragEvent) => void;
|
|
517
|
-
|
|
478
|
+
updateRows: (newRows: TableRow[]) => void;
|
|
479
|
+
}, "display" | "table" | "hasPinnedColumns" | "isGanttView" | "isTreeView" | "numberedRowWidth" | "zeroColumn">, Pick<{
|
|
518
480
|
columns: import("vue").Ref<{
|
|
519
481
|
name: string;
|
|
520
482
|
align?: CanvasTextAlign | undefined;
|
|
@@ -615,25 +577,7 @@ export declare const createTableStore: (initData: {
|
|
|
615
577
|
} | undefined;
|
|
616
578
|
label?: string | undefined;
|
|
617
579
|
}[]>;
|
|
618
|
-
display: import("vue").
|
|
619
|
-
expanded?: boolean | undefined;
|
|
620
|
-
childrenOpen?: boolean | undefined;
|
|
621
|
-
isParent?: boolean | undefined;
|
|
622
|
-
isRoot?: boolean | undefined;
|
|
623
|
-
open?: boolean | undefined;
|
|
624
|
-
indent?: number | undefined;
|
|
625
|
-
parent?: number | undefined;
|
|
626
|
-
rowModified?: boolean | undefined;
|
|
627
|
-
}[], TableDisplay[] | {
|
|
628
|
-
expanded?: boolean | undefined;
|
|
629
|
-
childrenOpen?: boolean | undefined;
|
|
630
|
-
isParent?: boolean | undefined;
|
|
631
|
-
isRoot?: boolean | undefined;
|
|
632
|
-
open?: boolean | undefined;
|
|
633
|
-
indent?: number | undefined;
|
|
634
|
-
parent?: number | undefined;
|
|
635
|
-
rowModified?: boolean | undefined;
|
|
636
|
-
}[]>;
|
|
580
|
+
display: import("vue").WritableComputedRef<TableDisplay[], TableDisplay[]>;
|
|
637
581
|
ganttBars: import("vue").Ref<{
|
|
638
582
|
id: string;
|
|
639
583
|
rowIndex: number;
|
|
@@ -705,7 +649,7 @@ export declare const createTableStore: (initData: {
|
|
|
705
649
|
colspan?: number | undefined;
|
|
706
650
|
} | undefined;
|
|
707
651
|
}[]>;
|
|
708
|
-
table: import("vue").
|
|
652
|
+
table: import("vue").ComputedRef<{}>;
|
|
709
653
|
updates: import("vue").Ref<Record<string, string>, Record<string, string>>;
|
|
710
654
|
hasPinnedColumns: import("vue").ComputedRef<boolean>;
|
|
711
655
|
isGanttView: import("vue").ComputedRef<boolean>;
|
|
@@ -763,5 +707,6 @@ export declare const createTableStore: (initData: {
|
|
|
763
707
|
unregisterConnectionHandle: (handleId: string) => void;
|
|
764
708
|
unregisterGanttBar: (barId: string) => void;
|
|
765
709
|
updateGanttBar: (event: GanttDragEvent) => void;
|
|
766
|
-
|
|
710
|
+
updateRows: (newRows: TableRow[]) => void;
|
|
711
|
+
}, "closeModal" | "createConnection" | "deleteConnection" | "getCellData" | "getCellDisplayValue" | "getConnectionsForBar" | "getFormattedValue" | "getHandlesForBar" | "getHeaderCellStyle" | "getIndent" | "getRowExpandSymbol" | "isRowGantt" | "isRowVisible" | "registerConnectionHandle" | "registerGanttBar" | "resizeColumn" | "setCellData" | "setCellText" | "toggleRowExpand" | "unregisterConnectionHandle" | "unregisterGanttBar" | "updateGanttBar" | "updateRows">>;
|
|
767
712
|
//# sourceMappingURL=table.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/stores/table.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,KAAK,CAAA;AAEvD,OAAO,KAAK,EACX,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,WAAW,EACX,WAAW,EACX,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,MAAM,UAAU,CAAA;AAGjB;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU;IAC1C,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,KAAK,CAAC,EAAE
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/stores/table.ts"],"names":[],"mappings":"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"}
|
package/dist/stores/table.js
CHANGED
|
@@ -10,28 +10,8 @@ import { generateHash } from '../utils';
|
|
|
10
10
|
export const createTableStore = (initData) => {
|
|
11
11
|
const id = initData.id || generateHash();
|
|
12
12
|
const createStore = defineStore(`table-${id}`, () => {
|
|
13
|
-
|
|
14
|
-
const createTableObject = () => {
|
|
15
|
-
const table = {};
|
|
16
|
-
for (const [colIndex, column] of columns.value.entries()) {
|
|
17
|
-
for (const [rowIndex, row] of rows.value.entries()) {
|
|
18
|
-
table[`${colIndex}:${rowIndex}`] = row[column.name];
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return table;
|
|
22
|
-
};
|
|
23
|
-
const createDisplayObject = (display) => {
|
|
13
|
+
const createDisplayObject = () => {
|
|
24
14
|
const defaultDisplay = [Object.assign({}, { rowModified: false })];
|
|
25
|
-
// TODO: (typing) what is the type of `display` here?
|
|
26
|
-
if (display) {
|
|
27
|
-
if ('0:0' in display) {
|
|
28
|
-
return display;
|
|
29
|
-
}
|
|
30
|
-
// else if ('default' in display) {
|
|
31
|
-
// // TODO: (typing) what is the possible input here for 'default'?
|
|
32
|
-
// defaultDisplay = display.default
|
|
33
|
-
// }
|
|
34
|
-
}
|
|
35
15
|
// TODO: (typing) is this type correct for the parent set?
|
|
36
16
|
const parents = new Set();
|
|
37
17
|
for (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {
|
|
@@ -59,8 +39,70 @@ export const createTableStore = (initData) => {
|
|
|
59
39
|
const columns = ref(initData.columns);
|
|
60
40
|
const rows = ref(initData.rows);
|
|
61
41
|
const config = ref(initData.config || {});
|
|
62
|
-
|
|
63
|
-
const
|
|
42
|
+
// Track row modifications and expand states separately from the computed display
|
|
43
|
+
const rowModifications = ref({});
|
|
44
|
+
const rowExpandStates = ref({});
|
|
45
|
+
const table = computed(() => {
|
|
46
|
+
const table = {};
|
|
47
|
+
for (const [colIndex, column] of columns.value.entries()) {
|
|
48
|
+
for (const [rowIndex, row] of rows.value.entries()) {
|
|
49
|
+
table[`${colIndex}:${rowIndex}`] = row[column.name];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return table;
|
|
53
|
+
});
|
|
54
|
+
const display = computed({
|
|
55
|
+
get: () => {
|
|
56
|
+
const baseDisplay = createDisplayObject();
|
|
57
|
+
// Apply persistent modifications and expand states
|
|
58
|
+
for (let i = 0; i < baseDisplay.length; i++) {
|
|
59
|
+
if (rowModifications.value[i]) {
|
|
60
|
+
baseDisplay[i].rowModified = rowModifications.value[i];
|
|
61
|
+
}
|
|
62
|
+
if (rowExpandStates.value[i]) {
|
|
63
|
+
if (rowExpandStates.value[i].childrenOpen !== undefined) {
|
|
64
|
+
baseDisplay[i].childrenOpen = rowExpandStates.value[i].childrenOpen;
|
|
65
|
+
}
|
|
66
|
+
if (rowExpandStates.value[i].expanded !== undefined) {
|
|
67
|
+
baseDisplay[i].expanded = rowExpandStates.value[i].expanded;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Calculate 'open' property for tree view based on parent's childrenOpen state
|
|
72
|
+
if (isTreeView.value) {
|
|
73
|
+
// Helper function to check if all ancestors are open
|
|
74
|
+
const isNodeOpen = (rowIndex, display) => {
|
|
75
|
+
const row = display[rowIndex];
|
|
76
|
+
if (row.isRoot) {
|
|
77
|
+
return true; // Root nodes are always open
|
|
78
|
+
}
|
|
79
|
+
if (row.parent === null || row.parent === undefined) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
const parentIndex = row.parent;
|
|
83
|
+
if (parentIndex < 0 || parentIndex >= display.length) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const parent = display[parentIndex];
|
|
87
|
+
// Node is open if parent's children are open AND parent itself is open
|
|
88
|
+
return (parent.childrenOpen || false) && isNodeOpen(parentIndex, display);
|
|
89
|
+
};
|
|
90
|
+
for (let i = 0; i < baseDisplay.length; i++) {
|
|
91
|
+
const row = baseDisplay[i];
|
|
92
|
+
if (!row.isRoot) {
|
|
93
|
+
baseDisplay[i].open = isNodeOpen(i, baseDisplay);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return baseDisplay;
|
|
98
|
+
},
|
|
99
|
+
set: (newDisplay) => {
|
|
100
|
+
// Only update if the new display is different from the current one; also avoids recursive updates
|
|
101
|
+
if (JSON.stringify(newDisplay) !== JSON.stringify(display.value)) {
|
|
102
|
+
display.value = newDisplay;
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
});
|
|
64
106
|
const modal = ref(initData.modal || { visible: false });
|
|
65
107
|
const updates = ref({});
|
|
66
108
|
const ganttBars = ref([]);
|
|
@@ -81,7 +123,7 @@ export const createTableStore = (initData) => {
|
|
|
81
123
|
const index = `${colIndex}:${rowIndex}`;
|
|
82
124
|
const col = columns.value[colIndex];
|
|
83
125
|
if (table.value[index] !== value) {
|
|
84
|
-
|
|
126
|
+
rowModifications.value[rowIndex] = true;
|
|
85
127
|
}
|
|
86
128
|
table.value[index] = value;
|
|
87
129
|
// Create a new row object to ensure reactivity
|
|
@@ -90,10 +132,13 @@ export const createTableStore = (initData) => {
|
|
|
90
132
|
[col.name]: value,
|
|
91
133
|
};
|
|
92
134
|
};
|
|
135
|
+
const updateRows = (newRows) => {
|
|
136
|
+
rows.value = newRows;
|
|
137
|
+
};
|
|
93
138
|
const setCellText = (colIndex, rowIndex, value) => {
|
|
94
139
|
const index = `${colIndex}:${rowIndex}`;
|
|
95
140
|
if (table.value[index] !== value) {
|
|
96
|
-
|
|
141
|
+
rowModifications.value[rowIndex] = true;
|
|
97
142
|
updates.value[index] = value;
|
|
98
143
|
}
|
|
99
144
|
};
|
|
@@ -143,21 +188,38 @@ export const createTableStore = (initData) => {
|
|
|
143
188
|
};
|
|
144
189
|
const toggleRowExpand = (rowIndex) => {
|
|
145
190
|
if (isTreeView.value) {
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
191
|
+
const currentState = rowExpandStates.value[rowIndex] || {};
|
|
192
|
+
const currentChildrenOpen = currentState.childrenOpen ?? display.value[rowIndex].childrenOpen;
|
|
193
|
+
const newChildrenOpen = !currentChildrenOpen;
|
|
194
|
+
rowExpandStates.value[rowIndex] = {
|
|
195
|
+
...currentState,
|
|
196
|
+
childrenOpen: newChildrenOpen,
|
|
197
|
+
};
|
|
198
|
+
// If we're closing, recursively close all descendant nodes
|
|
199
|
+
if (!newChildrenOpen) {
|
|
200
|
+
closeDescendants(rowIndex);
|
|
157
201
|
}
|
|
158
202
|
}
|
|
159
203
|
else if (config.value.view === 'list-expansion') {
|
|
160
|
-
|
|
204
|
+
const currentState = rowExpandStates.value[rowIndex] || {};
|
|
205
|
+
const currentExpanded = currentState.expanded ?? display.value[rowIndex].expanded;
|
|
206
|
+
rowExpandStates.value[rowIndex] = {
|
|
207
|
+
...currentState,
|
|
208
|
+
expanded: !currentExpanded,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
const closeDescendants = (parentRowIndex) => {
|
|
213
|
+
for (let index = 0; index < rows.value.length; index++) {
|
|
214
|
+
if (display.value[index].parent === parentRowIndex) {
|
|
215
|
+
const childState = rowExpandStates.value[index] || {};
|
|
216
|
+
rowExpandStates.value[index] = {
|
|
217
|
+
...childState,
|
|
218
|
+
childrenOpen: false,
|
|
219
|
+
};
|
|
220
|
+
// Recursively close this child's descendants
|
|
221
|
+
closeDescendants(index);
|
|
222
|
+
}
|
|
161
223
|
}
|
|
162
224
|
};
|
|
163
225
|
const getCellDisplayValue = (colIndex, rowIndex) => {
|
|
@@ -263,6 +325,7 @@ export const createTableStore = (initData) => {
|
|
|
263
325
|
const fromHandle = connectionHandles.value.find(h => h.id === fromHandleId);
|
|
264
326
|
const toHandle = connectionHandles.value.find(h => h.id === toHandleId);
|
|
265
327
|
if (!fromHandle || !toHandle) {
|
|
328
|
+
// eslint-disable-next-line no-console
|
|
266
329
|
console.warn('Cannot create connection: handle not found');
|
|
267
330
|
return null;
|
|
268
331
|
}
|
|
@@ -337,6 +400,7 @@ export const createTableStore = (initData) => {
|
|
|
337
400
|
unregisterConnectionHandle,
|
|
338
401
|
unregisterGanttBar,
|
|
339
402
|
updateGanttBar,
|
|
403
|
+
updateRows,
|
|
340
404
|
};
|
|
341
405
|
});
|
|
342
406
|
return createStore();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonecrop/atable",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.26",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"@vueuse/core": "^13.4.0",
|
|
39
39
|
"pinia": "^3.0.3",
|
|
40
40
|
"vue": "^3.5.17",
|
|
41
|
-
"@stonecrop/themes": "0.4.
|
|
42
|
-
"@stonecrop/utilities": "0.4.
|
|
41
|
+
"@stonecrop/themes": "0.4.26",
|
|
42
|
+
"@stonecrop/utilities": "0.4.26"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@microsoft/api-documenter": "^7.26.29",
|
|
@@ -86,15 +86,11 @@ import ATableModal from './ATableModal.vue'
|
|
|
86
86
|
import { createTableStore } from '../stores/table'
|
|
87
87
|
import type { ConnectionEvent, ConnectionPath, GanttDragEvent, TableColumn, TableConfig, TableRow } from '../types'
|
|
88
88
|
|
|
89
|
-
const
|
|
89
|
+
const rows = defineModel<TableRow[]>('rows', { required: true })
|
|
90
|
+
const columns = defineModel<TableColumn[]>('columns', { required: true })
|
|
90
91
|
|
|
91
|
-
const {
|
|
92
|
-
id,
|
|
93
|
-
columns,
|
|
94
|
-
config = new Object(),
|
|
95
|
-
} = defineProps<{
|
|
92
|
+
const { id, config = new Object() } = defineProps<{
|
|
96
93
|
id?: string
|
|
97
|
-
columns: TableColumn[]
|
|
98
94
|
config?: TableConfig
|
|
99
95
|
}>()
|
|
100
96
|
|
|
@@ -102,18 +98,19 @@ const emit = defineEmits<{
|
|
|
102
98
|
cellUpdate: [{ colIndex: number; rowIndex: number; newValue: any; oldValue: any }]
|
|
103
99
|
'gantt:drag': [event: GanttDragEvent]
|
|
104
100
|
'connection:event': [event: ConnectionEvent]
|
|
101
|
+
'columns:update': [columns: TableColumn[]]
|
|
105
102
|
}>()
|
|
106
103
|
|
|
107
104
|
const tableRef = useTemplateRef<HTMLTableElement>('table')
|
|
108
|
-
const store = createTableStore({ columns, rows:
|
|
105
|
+
const store = createTableStore({ columns: columns.value, rows: rows.value, id, config })
|
|
109
106
|
|
|
110
107
|
store.$onAction(({ name, store, args, after }) => {
|
|
111
108
|
if (name === 'setCellData' || name === 'setCellText') {
|
|
112
109
|
const [colIndex, rowIndex, newValue] = args
|
|
113
110
|
const oldValue = store.getCellData(colIndex, rowIndex)
|
|
114
111
|
after(() => {
|
|
115
|
-
// Update
|
|
116
|
-
|
|
112
|
+
// Update rows model to trigger update:rows event
|
|
113
|
+
rows.value = [...store.rows]
|
|
117
114
|
emit('cellUpdate', { colIndex, rowIndex, newValue, oldValue })
|
|
118
115
|
})
|
|
119
116
|
} else if (name === 'updateGanttBar') {
|
|
@@ -130,12 +127,18 @@ store.$onAction(({ name, store, args, after }) => {
|
|
|
130
127
|
emit('gantt:drag', event)
|
|
131
128
|
})
|
|
132
129
|
}
|
|
130
|
+
} else if (name === 'resizeColumn') {
|
|
131
|
+
after(() => {
|
|
132
|
+
// Update columns model
|
|
133
|
+
columns.value = [...store.columns]
|
|
134
|
+
emit('columns:update', [...store.columns])
|
|
135
|
+
})
|
|
133
136
|
}
|
|
134
137
|
})
|
|
135
138
|
|
|
136
|
-
// Watch for external changes to
|
|
139
|
+
// Watch for external changes to rows and sync to store
|
|
137
140
|
watch(
|
|
138
|
-
() =>
|
|
141
|
+
() => rows.value,
|
|
139
142
|
newRows => {
|
|
140
143
|
// Only update if the rows have actually changed (avoid infinite loops)
|
|
141
144
|
if (JSON.stringify(newRows) !== JSON.stringify(store.rows)) {
|
|
@@ -145,8 +148,21 @@ watch(
|
|
|
145
148
|
{ deep: true }
|
|
146
149
|
)
|
|
147
150
|
|
|
151
|
+
// Watch for changes to columns and sync to store
|
|
152
|
+
watch(
|
|
153
|
+
columns,
|
|
154
|
+
newColumns => {
|
|
155
|
+
// Only update if the columns have actually changed (avoid infinite loops)
|
|
156
|
+
if (JSON.stringify(newColumns) !== JSON.stringify(store.columns)) {
|
|
157
|
+
store.columns = [...newColumns]
|
|
158
|
+
emit('columns:update', [...newColumns] as TableColumn[])
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{ deep: true }
|
|
162
|
+
)
|
|
163
|
+
|
|
148
164
|
onMounted(() => {
|
|
149
|
-
if (columns.some(column => column.pinned)) {
|
|
165
|
+
if (columns.value.some(column => column.pinned)) {
|
|
150
166
|
assignStickyCellWidths()
|
|
151
167
|
|
|
152
168
|
// in tree views, also add a mutation observer to capture and adjust expanded rows
|
package/src/stores/table.ts
CHANGED
|
@@ -26,37 +26,13 @@ export const createTableStore = (initData: {
|
|
|
26
26
|
rows: TableRow[]
|
|
27
27
|
id?: string
|
|
28
28
|
config?: TableConfig
|
|
29
|
-
table?: { [key: string]: any }
|
|
30
|
-
display?: TableDisplay[]
|
|
31
29
|
modal?: TableModal
|
|
32
30
|
}) => {
|
|
33
31
|
const id = initData.id || generateHash()
|
|
34
32
|
const createStore = defineStore(`table-${id}`, () => {
|
|
35
|
-
|
|
36
|
-
const createTableObject = () => {
|
|
37
|
-
const table = {}
|
|
38
|
-
for (const [colIndex, column] of columns.value.entries()) {
|
|
39
|
-
for (const [rowIndex, row] of rows.value.entries()) {
|
|
40
|
-
table[`${colIndex}:${rowIndex}`] = row[column.name]
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return table
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const createDisplayObject = (display?: TableDisplay[]) => {
|
|
33
|
+
const createDisplayObject = () => {
|
|
47
34
|
const defaultDisplay: TableDisplay[] = [Object.assign({}, { rowModified: false })]
|
|
48
35
|
|
|
49
|
-
// TODO: (typing) what is the type of `display` here?
|
|
50
|
-
if (display) {
|
|
51
|
-
if ('0:0' in display) {
|
|
52
|
-
return display
|
|
53
|
-
}
|
|
54
|
-
// else if ('default' in display) {
|
|
55
|
-
// // TODO: (typing) what is the possible input here for 'default'?
|
|
56
|
-
// defaultDisplay = display.default
|
|
57
|
-
// }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
36
|
// TODO: (typing) is this type correct for the parent set?
|
|
61
37
|
const parents = new Set<string | number>()
|
|
62
38
|
for (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {
|
|
@@ -87,8 +63,81 @@ export const createTableStore = (initData: {
|
|
|
87
63
|
const columns = ref(initData.columns)
|
|
88
64
|
const rows = ref(initData.rows)
|
|
89
65
|
const config = ref(initData.config || {})
|
|
90
|
-
|
|
91
|
-
|
|
66
|
+
|
|
67
|
+
// Track row modifications and expand states separately from the computed display
|
|
68
|
+
const rowModifications = ref<Record<number, boolean>>({})
|
|
69
|
+
const rowExpandStates = ref<Record<number, { childrenOpen?: boolean; expanded?: boolean }>>({})
|
|
70
|
+
|
|
71
|
+
const table = computed(() => {
|
|
72
|
+
const table = {}
|
|
73
|
+
for (const [colIndex, column] of columns.value.entries()) {
|
|
74
|
+
for (const [rowIndex, row] of rows.value.entries()) {
|
|
75
|
+
table[`${colIndex}:${rowIndex}`] = row[column.name]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return table
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const display = computed({
|
|
82
|
+
get: () => {
|
|
83
|
+
const baseDisplay = createDisplayObject()
|
|
84
|
+
|
|
85
|
+
// Apply persistent modifications and expand states
|
|
86
|
+
for (let i = 0; i < baseDisplay.length; i++) {
|
|
87
|
+
if (rowModifications.value[i]) {
|
|
88
|
+
baseDisplay[i].rowModified = rowModifications.value[i]
|
|
89
|
+
}
|
|
90
|
+
if (rowExpandStates.value[i]) {
|
|
91
|
+
if (rowExpandStates.value[i].childrenOpen !== undefined) {
|
|
92
|
+
baseDisplay[i].childrenOpen = rowExpandStates.value[i].childrenOpen!
|
|
93
|
+
}
|
|
94
|
+
if (rowExpandStates.value[i].expanded !== undefined) {
|
|
95
|
+
baseDisplay[i].expanded = rowExpandStates.value[i].expanded!
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Calculate 'open' property for tree view based on parent's childrenOpen state
|
|
101
|
+
if (isTreeView.value) {
|
|
102
|
+
// Helper function to check if all ancestors are open
|
|
103
|
+
const isNodeOpen = (rowIndex: number, display: TableDisplay[]): boolean => {
|
|
104
|
+
const row = display[rowIndex]
|
|
105
|
+
if (row.isRoot) {
|
|
106
|
+
return true // Root nodes are always open
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (row.parent === null || row.parent === undefined) {
|
|
110
|
+
return true
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const parentIndex = row.parent
|
|
114
|
+
if (parentIndex < 0 || parentIndex >= display.length) {
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const parent = display[parentIndex]
|
|
119
|
+
// Node is open if parent's children are open AND parent itself is open
|
|
120
|
+
return (parent.childrenOpen || false) && isNodeOpen(parentIndex, display)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (let i = 0; i < baseDisplay.length; i++) {
|
|
124
|
+
const row = baseDisplay[i]
|
|
125
|
+
if (!row.isRoot) {
|
|
126
|
+
baseDisplay[i].open = isNodeOpen(i, baseDisplay)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return baseDisplay
|
|
132
|
+
},
|
|
133
|
+
set: (newDisplay: TableDisplay[]) => {
|
|
134
|
+
// Only update if the new display is different from the current one; also avoids recursive updates
|
|
135
|
+
if (JSON.stringify(newDisplay) !== JSON.stringify(display.value)) {
|
|
136
|
+
display.value = newDisplay
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
})
|
|
140
|
+
|
|
92
141
|
const modal = ref<TableModal>(initData.modal || { visible: false })
|
|
93
142
|
const updates = ref<Record<string, string>>({})
|
|
94
143
|
const ganttBars = ref<GanttBarInfo[]>([])
|
|
@@ -116,7 +165,7 @@ export const createTableStore = (initData: {
|
|
|
116
165
|
const col = columns.value[colIndex]
|
|
117
166
|
|
|
118
167
|
if (table.value[index] !== value) {
|
|
119
|
-
|
|
168
|
+
rowModifications.value[rowIndex] = true
|
|
120
169
|
}
|
|
121
170
|
|
|
122
171
|
table.value[index] = value
|
|
@@ -127,11 +176,15 @@ export const createTableStore = (initData: {
|
|
|
127
176
|
}
|
|
128
177
|
}
|
|
129
178
|
|
|
179
|
+
const updateRows = (newRows: TableRow[]) => {
|
|
180
|
+
rows.value = newRows
|
|
181
|
+
}
|
|
182
|
+
|
|
130
183
|
const setCellText = (colIndex: number, rowIndex: number, value: string) => {
|
|
131
184
|
const index = `${colIndex}:${rowIndex}`
|
|
132
185
|
|
|
133
186
|
if (table.value[index] !== value) {
|
|
134
|
-
|
|
187
|
+
rowModifications.value[rowIndex] = true
|
|
135
188
|
updates.value[index] = value
|
|
136
189
|
}
|
|
137
190
|
}
|
|
@@ -194,21 +247,40 @@ export const createTableStore = (initData: {
|
|
|
194
247
|
|
|
195
248
|
const toggleRowExpand = (rowIndex: number) => {
|
|
196
249
|
if (isTreeView.value) {
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
250
|
+
const currentState = rowExpandStates.value[rowIndex] || {}
|
|
251
|
+
const currentChildrenOpen = currentState.childrenOpen ?? display.value[rowIndex].childrenOpen
|
|
252
|
+
const newChildrenOpen = !currentChildrenOpen
|
|
253
|
+
|
|
254
|
+
rowExpandStates.value[rowIndex] = {
|
|
255
|
+
...currentState,
|
|
256
|
+
childrenOpen: newChildrenOpen,
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// If we're closing, recursively close all descendant nodes
|
|
260
|
+
if (!newChildrenOpen) {
|
|
261
|
+
closeDescendants(rowIndex)
|
|
209
262
|
}
|
|
210
263
|
} else if (config.value.view === 'list-expansion') {
|
|
211
|
-
|
|
264
|
+
const currentState = rowExpandStates.value[rowIndex] || {}
|
|
265
|
+
const currentExpanded = currentState.expanded ?? display.value[rowIndex].expanded
|
|
266
|
+
rowExpandStates.value[rowIndex] = {
|
|
267
|
+
...currentState,
|
|
268
|
+
expanded: !currentExpanded,
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const closeDescendants = (parentRowIndex: number) => {
|
|
274
|
+
for (let index = 0; index < rows.value.length; index++) {
|
|
275
|
+
if (display.value[index].parent === parentRowIndex) {
|
|
276
|
+
const childState = rowExpandStates.value[index] || {}
|
|
277
|
+
rowExpandStates.value[index] = {
|
|
278
|
+
...childState,
|
|
279
|
+
childrenOpen: false,
|
|
280
|
+
}
|
|
281
|
+
// Recursively close this child's descendants
|
|
282
|
+
closeDescendants(index)
|
|
283
|
+
}
|
|
212
284
|
}
|
|
213
285
|
}
|
|
214
286
|
|
|
@@ -323,6 +395,7 @@ export const createTableStore = (initData: {
|
|
|
323
395
|
const toHandle = connectionHandles.value.find(h => h.id === toHandleId)
|
|
324
396
|
|
|
325
397
|
if (!fromHandle || !toHandle) {
|
|
398
|
+
// eslint-disable-next-line no-console
|
|
326
399
|
console.warn('Cannot create connection: handle not found')
|
|
327
400
|
return null
|
|
328
401
|
}
|
|
@@ -405,6 +478,7 @@ export const createTableStore = (initData: {
|
|
|
405
478
|
unregisterConnectionHandle,
|
|
406
479
|
unregisterGanttBar,
|
|
407
480
|
updateGanttBar,
|
|
481
|
+
updateRows,
|
|
408
482
|
}
|
|
409
483
|
})
|
|
410
484
|
|