virtual-tree-canvas 0.6.0 → 0.7.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/CHANGELOG.md +32 -0
- package/README.md +90 -3
- package/docs/icon-catalog.html +68 -66
- package/docs/icon-catalog.json +12 -0
- package/docs/icon-catalog.md +111 -107
- package/docs/performance/dynamic-updates-0.7.1.md +38 -0
- package/package.json +3 -2
- package/resources/icons/star-filled.svg +1 -0
- package/resources/icons/trash.svg +1 -0
- package/src/assets/icons.js +12 -4
- package/src/core/dynamic-state.js +19 -29
- package/src/core/patch-batcher.js +4 -0
- package/src/core/theme-manager.js +238 -61
- package/src/core/tree-cell-layout.js +11 -0
- package/src/core/tree-column-model.js +81 -22
- package/src/core/tree-model.js +4 -2
- package/src/core/types.js +1 -0
- package/src/core/view-options.js +98 -18
- package/src/core/visible-row-model.js +51 -21
- package/src/index.d.ts +70 -1
- package/src/input/row-actions.js +248 -0
- package/src/input/row-reorder-input.js +134 -36
- package/src/input/tree-tooltip.js +39 -5
- package/src/input/tree-view-input-controller.js +35 -10
- package/src/inspector/cell-editor-manager.js +128 -35
- package/src/inspector/pane-layout.js +20 -0
- package/src/renderers/checkbox.js +13 -0
- package/src/renderers/tree-row-renderer.js +356 -107
- package/src/tree-view-controller.js +968 -236
- package/src/tree-view.js +218 -54
- package/src/view/styles.js +83 -12
|
@@ -3,7 +3,8 @@ export const darkTheme = {
|
|
|
3
3
|
indentWidth: 18,
|
|
4
4
|
font: '12px Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
5
5
|
unitFont: '11px ui-monospace, SFMono-Regular, Consolas, monospace',
|
|
6
|
-
monoFont:
|
|
6
|
+
monoFont:
|
|
7
|
+
'12px "JetBrains Mono", "Cascadia Mono", "Fira Code", ui-monospace, SFMono-Regular, Consolas, monospace',
|
|
7
8
|
colors: {
|
|
8
9
|
background: '#0a0f1c',
|
|
9
10
|
row: '#0a0f1c',
|
|
@@ -30,44 +31,146 @@ export const darkTheme = {
|
|
|
30
31
|
badgeText: '#ffffff',
|
|
31
32
|
border: '#1b2637',
|
|
32
33
|
borderStrong: '#2b3b52',
|
|
33
|
-
shadow: 'rgba(0,0,0,.24)'
|
|
34
|
+
shadow: 'rgba(0,0,0,.24)'
|
|
35
|
+
},
|
|
36
|
+
valueColors: {
|
|
37
|
+
number: '#8bd5ee',
|
|
38
|
+
bigint: '#8bd5ee',
|
|
39
|
+
string: '#dde5ef',
|
|
40
|
+
boolean: '#86d6b5',
|
|
41
|
+
enum: '#c4b5fd',
|
|
42
|
+
null: '#9aa9bc',
|
|
43
|
+
undefined: '#9aa9bc'
|
|
34
44
|
},
|
|
35
45
|
types: {
|
|
36
|
-
root: {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
root: {
|
|
47
|
+
icon: 'folder',
|
|
48
|
+
color: '#38bdf8'
|
|
49
|
+
},
|
|
50
|
+
system: {
|
|
51
|
+
icon: 'folder',
|
|
52
|
+
color: '#818cf8'
|
|
53
|
+
},
|
|
54
|
+
platform: {
|
|
55
|
+
icon: 'aircraft',
|
|
56
|
+
color: '#60a5fa'
|
|
57
|
+
},
|
|
58
|
+
air: {
|
|
59
|
+
icon: 'aircraft',
|
|
60
|
+
color: '#60a5fa'
|
|
61
|
+
},
|
|
62
|
+
ground: {
|
|
63
|
+
icon: 'ground',
|
|
64
|
+
color: '#a3e635'
|
|
65
|
+
},
|
|
66
|
+
surface: {
|
|
67
|
+
icon: 'surface',
|
|
68
|
+
color: '#22d3ee'
|
|
69
|
+
},
|
|
70
|
+
subsurface: {
|
|
71
|
+
icon: 'subsurface',
|
|
72
|
+
color: '#38bdf8'
|
|
73
|
+
},
|
|
74
|
+
space: {
|
|
75
|
+
icon: 'space',
|
|
76
|
+
color: '#c084fc'
|
|
77
|
+
},
|
|
78
|
+
munition: {
|
|
79
|
+
icon: 'munition',
|
|
80
|
+
color: '#fb7185'
|
|
81
|
+
},
|
|
82
|
+
sensor: {
|
|
83
|
+
icon: 'radar',
|
|
84
|
+
color: '#34d399'
|
|
85
|
+
},
|
|
86
|
+
track: {
|
|
87
|
+
icon: 'track',
|
|
88
|
+
color: '#a78bfa'
|
|
89
|
+
},
|
|
90
|
+
geometry: {
|
|
91
|
+
icon: 'point',
|
|
92
|
+
color: '#38bdf8'
|
|
93
|
+
},
|
|
94
|
+
control: {
|
|
95
|
+
icon: 'control',
|
|
96
|
+
color: '#f59e0b'
|
|
97
|
+
},
|
|
98
|
+
situation: {
|
|
99
|
+
icon: 'situation',
|
|
100
|
+
color: '#2dd4bf'
|
|
101
|
+
},
|
|
102
|
+
damage: {
|
|
103
|
+
icon: 'damage',
|
|
104
|
+
color: '#fb7185'
|
|
105
|
+
},
|
|
106
|
+
warning: {
|
|
107
|
+
icon: 'warning',
|
|
108
|
+
color: '#facc15'
|
|
109
|
+
},
|
|
110
|
+
error: {
|
|
111
|
+
icon: 'error',
|
|
112
|
+
color: '#ef4444'
|
|
113
|
+
},
|
|
114
|
+
task: {
|
|
115
|
+
icon: 'task',
|
|
116
|
+
color: '#f97316'
|
|
117
|
+
},
|
|
118
|
+
bus: {
|
|
119
|
+
icon: 'data-bus',
|
|
120
|
+
color: '#22d3ee'
|
|
121
|
+
},
|
|
122
|
+
object: {
|
|
123
|
+
icon: 'inspector-object',
|
|
124
|
+
color: '#7dd3fc'
|
|
125
|
+
},
|
|
126
|
+
array: {
|
|
127
|
+
icon: 'inspector-array',
|
|
128
|
+
color: '#a78bfa'
|
|
129
|
+
},
|
|
130
|
+
string: {
|
|
131
|
+
icon: 'inspector-value',
|
|
132
|
+
color: '#94a3b8'
|
|
133
|
+
},
|
|
134
|
+
number: {
|
|
135
|
+
icon: 'inspector-value',
|
|
136
|
+
color: '#34d399'
|
|
137
|
+
},
|
|
138
|
+
boolean: {
|
|
139
|
+
icon: 'inspector-value',
|
|
140
|
+
color: '#22c55e'
|
|
141
|
+
},
|
|
142
|
+
null: {
|
|
143
|
+
icon: 'inspector-value',
|
|
144
|
+
color: '#64748b'
|
|
145
|
+
}
|
|
61
146
|
},
|
|
62
147
|
statuses: {
|
|
63
|
-
0: {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
148
|
+
0: {
|
|
149
|
+
label: 'OK',
|
|
150
|
+
color: '#22c55e'
|
|
151
|
+
},
|
|
152
|
+
1: {
|
|
153
|
+
label: 'WARN',
|
|
154
|
+
color: '#facc15'
|
|
155
|
+
},
|
|
156
|
+
2: {
|
|
157
|
+
label: 'ERR',
|
|
158
|
+
color: '#ef4444'
|
|
159
|
+
}
|
|
160
|
+
}
|
|
67
161
|
};
|
|
68
162
|
|
|
69
163
|
export const lightTheme = {
|
|
70
164
|
...darkTheme,
|
|
165
|
+
valueColors: {
|
|
166
|
+
number: '#075985',
|
|
167
|
+
bigint: '#075985',
|
|
168
|
+
string: '#182438',
|
|
169
|
+
boolean: '#176249',
|
|
170
|
+
enum: '#6b3fa0',
|
|
171
|
+
null: '#576579',
|
|
172
|
+
undefined: '#576579'
|
|
173
|
+
},
|
|
71
174
|
colors: {
|
|
72
175
|
background: '#f8fafc',
|
|
73
176
|
row: '#ffffff',
|
|
@@ -94,8 +197,8 @@ export const lightTheme = {
|
|
|
94
197
|
badgeFill: '#e2e8f0',
|
|
95
198
|
border: '#e2e8f0',
|
|
96
199
|
borderStrong: '#cbd5e1',
|
|
97
|
-
shadow: 'rgba(15,23,42,.1)'
|
|
98
|
-
}
|
|
200
|
+
shadow: 'rgba(15,23,42,.1)'
|
|
201
|
+
}
|
|
99
202
|
};
|
|
100
203
|
|
|
101
204
|
export const tacticalTheme = {
|
|
@@ -123,34 +226,85 @@ export const tacticalTheme = {
|
|
|
123
226
|
badgeFill: '#102217',
|
|
124
227
|
border: '#183321',
|
|
125
228
|
borderStrong: '#295337',
|
|
126
|
-
shadow: 'rgba(0,0,0,.3)'
|
|
229
|
+
shadow: 'rgba(0,0,0,.3)'
|
|
127
230
|
},
|
|
128
231
|
types: {
|
|
129
232
|
...darkTheme.types,
|
|
130
|
-
root: {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
233
|
+
root: {
|
|
234
|
+
icon: 'folder',
|
|
235
|
+
color: '#7ddc92'
|
|
236
|
+
},
|
|
237
|
+
platform: {
|
|
238
|
+
icon: 'aircraft',
|
|
239
|
+
color: '#93c572'
|
|
240
|
+
},
|
|
241
|
+
air: {
|
|
242
|
+
icon: 'aircraft',
|
|
243
|
+
color: '#93c572'
|
|
244
|
+
},
|
|
245
|
+
ground: {
|
|
246
|
+
icon: 'ground',
|
|
247
|
+
color: '#c7f36f'
|
|
248
|
+
},
|
|
249
|
+
surface: {
|
|
250
|
+
icon: 'surface',
|
|
251
|
+
color: '#67e8f9'
|
|
252
|
+
},
|
|
253
|
+
subsurface: {
|
|
254
|
+
icon: 'subsurface',
|
|
255
|
+
color: '#7dd3fc'
|
|
256
|
+
},
|
|
257
|
+
space: {
|
|
258
|
+
icon: 'space',
|
|
259
|
+
color: '#d8b4fe'
|
|
260
|
+
},
|
|
261
|
+
munition: {
|
|
262
|
+
icon: 'munition',
|
|
263
|
+
color: '#ff8fab'
|
|
264
|
+
},
|
|
265
|
+
sensor: {
|
|
266
|
+
icon: 'radar',
|
|
267
|
+
color: '#45d483'
|
|
268
|
+
},
|
|
269
|
+
track: {
|
|
270
|
+
icon: 'track',
|
|
271
|
+
color: '#d6f264'
|
|
272
|
+
},
|
|
273
|
+
geometry: {
|
|
274
|
+
icon: 'point',
|
|
275
|
+
color: '#7ddc92'
|
|
276
|
+
},
|
|
277
|
+
control: {
|
|
278
|
+
icon: 'control',
|
|
279
|
+
color: '#ffd166'
|
|
280
|
+
},
|
|
281
|
+
situation: {
|
|
282
|
+
icon: 'situation',
|
|
283
|
+
color: '#8be9d9'
|
|
284
|
+
},
|
|
285
|
+
damage: {
|
|
286
|
+
icon: 'damage',
|
|
287
|
+
color: '#ff8fab'
|
|
288
|
+
},
|
|
289
|
+
warning: {
|
|
290
|
+
icon: 'warning',
|
|
291
|
+
color: '#ffd166'
|
|
292
|
+
},
|
|
293
|
+
error: {
|
|
294
|
+
icon: 'error',
|
|
295
|
+
color: '#ff5c5c'
|
|
296
|
+
},
|
|
297
|
+
bus: {
|
|
298
|
+
icon: 'data-bus',
|
|
299
|
+
color: '#67e8f9'
|
|
300
|
+
}
|
|
301
|
+
}
|
|
148
302
|
};
|
|
149
303
|
|
|
150
304
|
export const themes = {
|
|
151
305
|
dark: darkTheme,
|
|
152
306
|
light: lightTheme,
|
|
153
|
-
tactical: tacticalTheme
|
|
307
|
+
tactical: tacticalTheme
|
|
154
308
|
};
|
|
155
309
|
|
|
156
310
|
export class ThemeManager extends EventTarget {
|
|
@@ -168,7 +322,10 @@ export class ThemeManager extends EventTarget {
|
|
|
168
322
|
return this.theme;
|
|
169
323
|
}
|
|
170
324
|
|
|
171
|
-
/**
|
|
325
|
+
/**
|
|
326
|
+
* @param {import('./types.js').TreeNode} node
|
|
327
|
+
* @param {import('./types.js').NodeDynamicState} state
|
|
328
|
+
*/
|
|
172
329
|
resolveNodeStyle(node, state = {}) {
|
|
173
330
|
const typeRule = this.theme.types[node?.type ?? ''] ?? {};
|
|
174
331
|
const statusRule = this.resolveStatus(state.status);
|
|
@@ -178,14 +335,20 @@ export class ThemeManager extends EventTarget {
|
|
|
178
335
|
typeColor: typeRule.color ?? this.theme.colors.progressFill,
|
|
179
336
|
status: statusRule,
|
|
180
337
|
font: this.theme.font,
|
|
181
|
-
colors: this.theme.colors
|
|
338
|
+
colors: this.theme.colors
|
|
182
339
|
};
|
|
183
340
|
}
|
|
184
341
|
|
|
185
342
|
resolveStatus(status) {
|
|
186
343
|
const key = status ?? 0;
|
|
187
|
-
return
|
|
344
|
+
return (
|
|
345
|
+
this.theme.statuses[key] ?? {
|
|
346
|
+
label: String(key),
|
|
347
|
+
color: this.theme.colors.textMuted
|
|
348
|
+
}
|
|
349
|
+
);
|
|
188
350
|
}
|
|
351
|
+
|
|
189
352
|
}
|
|
190
353
|
|
|
191
354
|
export function resolveTheme(theme = {}) {
|
|
@@ -193,7 +356,8 @@ export function resolveTheme(theme = {}) {
|
|
|
193
356
|
if (!Object.hasOwn(themes, theme)) throw new TypeError(`Unknown virtual tree theme: ${theme}`);
|
|
194
357
|
return themes[theme];
|
|
195
358
|
}
|
|
196
|
-
if (!theme || typeof theme !== 'object' || Array.isArray(theme))
|
|
359
|
+
if (!theme || typeof theme !== 'object' || Array.isArray(theme))
|
|
360
|
+
throw new TypeError('theme must be a theme name or object');
|
|
197
361
|
return theme;
|
|
198
362
|
}
|
|
199
363
|
|
|
@@ -219,7 +383,7 @@ function normalizeTheme(theme = {}) {
|
|
|
219
383
|
indentGuide: base.colors.guide,
|
|
220
384
|
chevron: base.colors.chevron,
|
|
221
385
|
chevronMuted: base.colors.textMuted,
|
|
222
|
-
progress: base.colors.progressFill
|
|
386
|
+
progress: base.colors.progressFill
|
|
223
387
|
};
|
|
224
388
|
}
|
|
225
389
|
|
|
@@ -227,8 +391,21 @@ function mergeTheme(base, override) {
|
|
|
227
391
|
return {
|
|
228
392
|
...base,
|
|
229
393
|
...override,
|
|
230
|
-
colors: {
|
|
231
|
-
|
|
232
|
-
|
|
394
|
+
colors: {
|
|
395
|
+
...base.colors,
|
|
396
|
+
...(override.colors ?? {})
|
|
397
|
+
},
|
|
398
|
+
valueColors: {
|
|
399
|
+
...base.valueColors,
|
|
400
|
+
...(override.valueColors ?? {})
|
|
401
|
+
},
|
|
402
|
+
types: {
|
|
403
|
+
...base.types,
|
|
404
|
+
...(override.types ?? {})
|
|
405
|
+
},
|
|
406
|
+
statuses: {
|
|
407
|
+
...base.statuses,
|
|
408
|
+
...(override.statuses ?? {})
|
|
409
|
+
}
|
|
233
410
|
};
|
|
234
411
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Share tree-cell positions between painting, hit testing and tooltips.
|
|
3
|
+
*/
|
|
4
|
+
export function treeCellLayout(depth, indentWidth, hasHierarchy) {
|
|
5
|
+
const indent = depth * indentWidth;
|
|
6
|
+
return {
|
|
7
|
+
chevronX: hasHierarchy ? indent + 10 : null,
|
|
8
|
+
iconX: indent + (hasHierarchy ? 27 : 8),
|
|
9
|
+
labelX: indent + (hasHierarchy ? 50 : 31)
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -6,7 +6,7 @@ export const builtInColumns = {
|
|
|
6
6
|
minWidth: 160,
|
|
7
7
|
align: 'left',
|
|
8
8
|
kind: 'tree',
|
|
9
|
-
value: (node) => node.label ?? node.id
|
|
9
|
+
value: (node) => node.label ?? node.id
|
|
10
10
|
},
|
|
11
11
|
status: {
|
|
12
12
|
id: 'status',
|
|
@@ -15,7 +15,7 @@ export const builtInColumns = {
|
|
|
15
15
|
minWidth: 64,
|
|
16
16
|
align: 'center',
|
|
17
17
|
kind: 'status',
|
|
18
|
-
value: (_node, state) => state.status ?? 0
|
|
18
|
+
value: (_node, state) => state.status ?? 0
|
|
19
19
|
},
|
|
20
20
|
value: {
|
|
21
21
|
id: 'value',
|
|
@@ -24,7 +24,7 @@ export const builtInColumns = {
|
|
|
24
24
|
minWidth: 56,
|
|
25
25
|
align: 'right',
|
|
26
26
|
kind: 'value',
|
|
27
|
-
value: (_node, state) => state.value ?? ''
|
|
27
|
+
value: (_node, state) => state.value ?? ''
|
|
28
28
|
},
|
|
29
29
|
progress: {
|
|
30
30
|
id: 'progress',
|
|
@@ -33,7 +33,7 @@ export const builtInColumns = {
|
|
|
33
33
|
minWidth: 80,
|
|
34
34
|
align: 'left',
|
|
35
35
|
kind: 'progress',
|
|
36
|
-
value: (_node, state) => state.progress ?? ''
|
|
36
|
+
value: (_node, state) => state.progress ?? ''
|
|
37
37
|
},
|
|
38
38
|
type: {
|
|
39
39
|
id: 'type',
|
|
@@ -42,7 +42,7 @@ export const builtInColumns = {
|
|
|
42
42
|
minWidth: 70,
|
|
43
43
|
align: 'left',
|
|
44
44
|
kind: 'type',
|
|
45
|
-
value: (node) => node.type ?? ''
|
|
45
|
+
value: (node) => node.type ?? ''
|
|
46
46
|
},
|
|
47
47
|
updated: {
|
|
48
48
|
id: 'updated',
|
|
@@ -51,15 +51,18 @@ export const builtInColumns = {
|
|
|
51
51
|
minWidth: 84,
|
|
52
52
|
align: 'right',
|
|
53
53
|
kind: 'updated',
|
|
54
|
-
value: (_node, state) => state.updatedAt ?? ''
|
|
55
|
-
}
|
|
54
|
+
value: (_node, state) => state.updatedAt ?? ''
|
|
55
|
+
}
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
export class TreeColumnModel {
|
|
59
59
|
constructor(columns = [builtInColumns.tree]) {
|
|
60
60
|
this.columns = [];
|
|
61
61
|
this.contentWidth = 0;
|
|
62
|
-
this.sort = {
|
|
62
|
+
this.sort = {
|
|
63
|
+
columnId: null,
|
|
64
|
+
direction: null
|
|
65
|
+
};
|
|
63
66
|
this.setColumns(columns);
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -69,21 +72,57 @@ export class TreeColumnModel {
|
|
|
69
72
|
if (!this.columns.some((column) => column.kind === 'tree' || column.kind === 'inspectorPane')) {
|
|
70
73
|
this.columns.unshift(normalizeColumn(builtInColumns.tree, 0));
|
|
71
74
|
}
|
|
75
|
+
this.setRowActions(this.rowActionCount ?? 0);
|
|
72
76
|
this.setRowReorder(this.rowReorder);
|
|
73
77
|
this.#layout();
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
setRowReorder(enabled) {
|
|
77
81
|
this.rowReorder = Boolean(enabled);
|
|
78
|
-
this.columns = this.columns.filter(column => column.id !== '__vtc_row_order');
|
|
79
|
-
if (this.rowReorder)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
this.columns = this.columns.filter((column) => column.id !== '__vtc_row_order');
|
|
83
|
+
if (this.rowReorder)
|
|
84
|
+
this.columns.unshift(
|
|
85
|
+
normalizeColumn(
|
|
86
|
+
{
|
|
87
|
+
id: '__vtc_row_order',
|
|
88
|
+
label: '',
|
|
89
|
+
kind: 'rowOrder',
|
|
90
|
+
width: 72,
|
|
91
|
+
minWidth: 72,
|
|
92
|
+
sortable: false,
|
|
93
|
+
resizable: false
|
|
94
|
+
},
|
|
95
|
+
0
|
|
96
|
+
)
|
|
97
|
+
);
|
|
83
98
|
this.#layout();
|
|
84
99
|
}
|
|
85
100
|
|
|
86
|
-
|
|
101
|
+
setRowActions(count) {
|
|
102
|
+
this.rowActionCount = count;
|
|
103
|
+
this.columns = this.columns.filter((column) => column.id !== '__vtc_actions');
|
|
104
|
+
if (count)
|
|
105
|
+
this.columns.push(
|
|
106
|
+
normalizeColumn(
|
|
107
|
+
{
|
|
108
|
+
id: '__vtc_actions',
|
|
109
|
+
label: '',
|
|
110
|
+
kind: 'text',
|
|
111
|
+
width: count * 28,
|
|
112
|
+
minWidth: count * 28,
|
|
113
|
+
sortable: false,
|
|
114
|
+
resizable: false,
|
|
115
|
+
value: () => ''
|
|
116
|
+
},
|
|
117
|
+
0
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
this.#layout();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {number} x
|
|
125
|
+
*/
|
|
87
126
|
getColumnAt(x) {
|
|
88
127
|
return this.columns.find((column) => x >= column.x && x < column.x + column.width) ?? null;
|
|
89
128
|
}
|
|
@@ -101,25 +140,37 @@ export class TreeColumnModel {
|
|
|
101
140
|
}
|
|
102
141
|
|
|
103
142
|
moveColumn(id, targetIndex) {
|
|
104
|
-
if (id === '__vtc_row_order') return false;
|
|
143
|
+
if (id === '__vtc_row_order' || id === '__vtc_actions') return false;
|
|
105
144
|
const currentIndex = this.columns.findIndex((column) => column.id === id);
|
|
106
145
|
if (currentIndex === -1) return false;
|
|
107
146
|
const [column] = this.columns.splice(currentIndex, 1);
|
|
108
|
-
const nextIndex = Math.max(
|
|
147
|
+
const nextIndex = Math.max(
|
|
148
|
+
this.rowReorder ? 1 : 0,
|
|
149
|
+
Math.min(this.columns.length - (this.rowActionCount ? 1 : 0), targetIndex)
|
|
150
|
+
);
|
|
109
151
|
this.columns.splice(nextIndex, 0, column);
|
|
110
|
-
if (!this.columns.some((item) => item.kind === 'tree'))
|
|
152
|
+
if (!this.columns.some((item) => item.kind === 'tree'))
|
|
153
|
+
this.columns.unshift(normalizeColumn(builtInColumns.tree, 0));
|
|
111
154
|
this.#layout();
|
|
112
155
|
return true;
|
|
113
156
|
}
|
|
114
157
|
|
|
115
158
|
setSort(columnId, direction) {
|
|
116
159
|
if (columnId !== null && !this.getColumn(columnId)) return false;
|
|
117
|
-
this.sort = {
|
|
160
|
+
this.sort = {
|
|
161
|
+
columnId,
|
|
162
|
+
direction
|
|
163
|
+
};
|
|
118
164
|
return true;
|
|
119
165
|
}
|
|
120
166
|
|
|
121
167
|
getResizeHandleAt(x, tolerance = 5) {
|
|
122
|
-
return
|
|
168
|
+
return (
|
|
169
|
+
this.columns.find(
|
|
170
|
+
(column) =>
|
|
171
|
+
column.resizable !== false && Math.abs(x - (column.x + column.width)) <= tolerance
|
|
172
|
+
) ?? null
|
|
173
|
+
);
|
|
123
174
|
}
|
|
124
175
|
|
|
125
176
|
#layout() {
|
|
@@ -130,16 +181,22 @@ export class TreeColumnModel {
|
|
|
130
181
|
}
|
|
131
182
|
this.contentWidth = x;
|
|
132
183
|
}
|
|
184
|
+
|
|
133
185
|
}
|
|
134
186
|
|
|
135
187
|
export function defaultTreeTableColumns() {
|
|
136
188
|
return [
|
|
137
|
-
{
|
|
189
|
+
{
|
|
190
|
+
...builtInColumns.tree,
|
|
191
|
+
id: 'name',
|
|
192
|
+
label: 'Name',
|
|
193
|
+
width: 340
|
|
194
|
+
},
|
|
138
195
|
builtInColumns.type,
|
|
139
196
|
builtInColumns.status,
|
|
140
197
|
builtInColumns.value,
|
|
141
198
|
builtInColumns.progress,
|
|
142
|
-
builtInColumns.updated
|
|
199
|
+
builtInColumns.updated
|
|
143
200
|
];
|
|
144
201
|
}
|
|
145
202
|
|
|
@@ -158,7 +215,9 @@ function normalizeColumn(column, index) {
|
|
|
158
215
|
sortable: source.sortable ?? true,
|
|
159
216
|
resizable: source.resizable ?? true,
|
|
160
217
|
value: source.value ?? ((node) => node[source.id] ?? ''),
|
|
218
|
+
format: source.format,
|
|
219
|
+
valueType: source.valueType,
|
|
161
220
|
render: source.render,
|
|
162
|
-
x: 0
|
|
221
|
+
x: 0
|
|
163
222
|
};
|
|
164
223
|
}
|
package/src/core/tree-model.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TreeIndex } from './tree-index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { mergeDynamicStateChanged } from './dynamic-state.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Owns structural nodes, expanded state, and per-node dynamic state.
|
|
@@ -86,11 +86,13 @@ export class TreeModel extends EventTarget {
|
|
|
86
86
|
* @param {Array<import('./types.js').DynamicPatch>} patches
|
|
87
87
|
*/
|
|
88
88
|
applyDynamicPatches(patches) {
|
|
89
|
+
const changedIds = new Set();
|
|
89
90
|
for (const patch of patches) {
|
|
90
91
|
const current = this.dynamicState.get(patch.id);
|
|
91
92
|
if (!current) continue;
|
|
92
|
-
|
|
93
|
+
if (mergeDynamicStateChanged(current, patch.state)) changedIds.add(patch.id);
|
|
93
94
|
}
|
|
95
|
+
return changedIds;
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
/** @param {string} id */
|