@keenmate/svelte-treeview 5.0.0-rc01 → 5.0.0-rc02
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 +99 -121
- package/ai/INDEX.txt +310 -0
- package/ai/advanced-patterns.txt +506 -0
- package/ai/basic-setup.txt +336 -0
- package/ai/context-menu.txt +349 -0
- package/ai/data-handling.txt +390 -0
- package/ai/drag-drop.txt +397 -0
- package/ai/events-callbacks.txt +382 -0
- package/ai/import-patterns.txt +271 -0
- package/ai/performance.txt +349 -0
- package/ai/search-features.txt +359 -0
- package/ai/styling-theming.txt +354 -0
- package/ai/tree-editing.txt +423 -0
- package/ai/typescript-types.txt +357 -0
- package/dist/components/Node.svelte +30 -54
- package/dist/components/Node.svelte.d.ts +2 -2
- package/dist/components/Tree.svelte +136 -11
- package/dist/components/Tree.svelte.d.ts +28 -10
- package/dist/constants.generated.d.ts +1 -1
- package/dist/constants.generated.js +1 -1
- package/dist/core/TreeController.svelte.d.ts +47 -3
- package/dist/core/TreeController.svelte.js +202 -23
- package/dist/global-api.d.ts +1 -1
- package/dist/global-api.js +5 -5
- package/dist/index.d.ts +5 -10
- package/dist/index.js +3 -8
- package/dist/logger.d.ts +7 -6
- package/dist/logger.js +0 -2
- package/dist/ltree/indexer.js +1 -1
- package/dist/ltree/ltree-node.svelte.d.ts +1 -0
- package/dist/ltree/ltree-node.svelte.js +1 -0
- package/dist/ltree/ltree.svelte.d.ts +1 -1
- package/dist/ltree/ltree.svelte.js +94 -59
- package/dist/ltree/types.d.ts +5 -2
- package/dist/perf-logger.d.ts +2 -1
- package/dist/perf-logger.js +0 -2
- package/dist/styles/main.scss +52 -5
- package/dist/styles.css +42 -5
- package/dist/styles.css.map +1 -1
- package/dist/vendor/loglevel/index.d.ts +55 -2
- package/dist/vendor/loglevel/prefix.d.ts +23 -2
- package/package.json +96 -95
- package/dist/canvas/CanvasTree.svelte +0 -1657
- package/dist/canvas/CanvasTree.svelte.d.ts +0 -148
- package/dist/canvas/canvas-interaction.d.ts +0 -67
- package/dist/canvas/canvas-interaction.js +0 -590
- package/dist/canvas/canvas-layout-balanced.d.ts +0 -18
- package/dist/canvas/canvas-layout-balanced.js +0 -212
- package/dist/canvas/canvas-layout-box.d.ts +0 -10
- package/dist/canvas/canvas-layout-box.js +0 -194
- package/dist/canvas/canvas-layout-fishbone.d.ts +0 -11
- package/dist/canvas/canvas-layout-fishbone.js +0 -349
- package/dist/canvas/canvas-layout-radial.d.ts +0 -21
- package/dist/canvas/canvas-layout-radial.js +0 -233
- package/dist/canvas/canvas-layout-sunburst.d.ts +0 -27
- package/dist/canvas/canvas-layout-sunburst.js +0 -457
- package/dist/canvas/canvas-layout.d.ts +0 -11
- package/dist/canvas/canvas-layout.js +0 -509
- package/dist/canvas/canvas-renderer.d.ts +0 -46
- package/dist/canvas/canvas-renderer.js +0 -828
- package/dist/canvas/canvas-text.d.ts +0 -11
- package/dist/canvas/canvas-text.js +0 -64
- package/dist/canvas/canvas-theme.d.ts +0 -58
- package/dist/canvas/canvas-theme.js +0 -128
- package/dist/canvas/types.d.ts +0 -187
- package/dist/canvas/types.js +0 -1
- package/dist/ltree/ltree-demo.d.ts +0 -2
- package/dist/ltree/ltree-demo.js +0 -90
- package/dist/vendor/loglevel/loglevel-esm.d.ts +0 -2
- package/dist/vendor/loglevel/loglevel-plugin-prefix-esm.d.ts +0 -7
- package/dist/vendor/loglevel/loglevel-plugin-prefix.d.ts +0 -2
package/README.md
CHANGED
|
@@ -6,70 +6,38 @@ A high-performance, feature-rich hierarchical tree view component for Svelte 5 w
|
|
|
6
6
|
|
|
7
7
|
Browse interactive code examples and the full API reference at **[svelte-treeview.keenmate.dev](https://svelte-treeview.keenmate.dev)**
|
|
8
8
|
|
|
9
|
-
## v5.0: Core/Renderer Split
|
|
9
|
+
## v5.0: Core/Renderer Split + Virtual Scroll
|
|
10
10
|
|
|
11
11
|
> [!IMPORTANT]
|
|
12
|
-
> **In version 5, the tree core (data structure, expand/collapse, search, drag & drop logic) has been completely separated from the renderer.** The
|
|
12
|
+
> **In version 5, the tree core (data structure, expand/collapse, search, drag & drop logic) has been completely separated from the renderer.** The architecture is open for you to build your own custom renderers on top of the same core via `TreeProvider` and `TreeController`.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- Use the built-in
|
|
16
|
-
-
|
|
17
|
-
-
|
|
14
|
+
**Key changes in v5:**
|
|
15
|
+
- **Core/Renderer split**: Use the built-in HTML `Tree` renderer, or create custom visualizations (Canvas, WebGL, SVG) via `TreeProvider` + `TreeController`
|
|
16
|
+
- **Virtual scroll**: Render 50,000+ node trees smoothly with `virtualScroll={true}` — only ~50 DOM nodes at any time
|
|
17
|
+
- **Canvas companion**: For canvas rendering, install [`@keenmate/svelte-treeview-canvas`](https://github.com/keenmate/svelte-treeview-canvas)
|
|
18
|
+
- **Drop position naming**: `'above'`/`'below'` renamed to `'before'`/`'after'` (CSS classes and events updated accordingly)
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
### Rendering Modes
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
| Mode | Props | DOM Nodes | Best For |
|
|
23
|
+
|------|-------|-----------|----------|
|
|
24
|
+
| Recursive | `useFlatRendering={false}` | All | Small trees (<100 nodes) |
|
|
25
|
+
| Flat (default) | `useFlatRendering={true}` | All | Medium trees (100–10K) |
|
|
26
|
+
| Virtual | `virtualScroll={true}` | ~50 | Large trees (10K+) |
|
|
23
27
|
|
|
24
|
-
Use `getAllowedDropPositionsCallback` for dynamic logic or `allowedDropPositionsMember` for server data:
|
|
25
|
-
```typescript
|
|
26
|
-
// Files can only have siblings, trash only accepts children
|
|
27
|
-
function getAllowedDropPositions(node) {
|
|
28
|
-
if (node.data?.type === 'file') return ['above', 'below'];
|
|
29
|
-
if (node.data?.type === 'trash') return ['child'];
|
|
30
|
-
return undefined; // all positions allowed (default)
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## v4.6: Progressive Flat Rendering
|
|
35
|
-
|
|
36
|
-
> [!NOTE]
|
|
37
|
-
> **The tree now uses progressive flat rendering by default for significantly improved performance.**
|
|
38
|
-
|
|
39
|
-
**What this means:**
|
|
40
|
-
- The tree renders immediately with the first batch of nodes (~20 by default)
|
|
41
|
-
- Remaining nodes are rendered progressively in subsequent frames
|
|
42
|
-
- For large trees (5000+ nodes), you'll see nodes appear over ~100-500ms instead of a single long freeze
|
|
43
|
-
- The UI remains responsive during rendering
|
|
44
|
-
|
|
45
|
-
**Configuration options:**
|
|
46
28
|
```svelte
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
useFlatRendering={true} <!-- Default: true (flat mode) -->
|
|
50
|
-
progressiveRender={true} <!-- Default: true (batched rendering) -->
|
|
51
|
-
initialBatchSize={20} <!-- First batch size (default: 20) -->
|
|
52
|
-
maxBatchSize={500} <!-- Maximum batch size cap (default: 500) -->
|
|
53
|
-
/>
|
|
54
|
-
```
|
|
29
|
+
<!-- Virtual scroll for large trees -->
|
|
30
|
+
<Tree {data} virtualScroll={true} virtualContainerHeight="500px" />
|
|
55
31
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
**To use the legacy recursive rendering:**
|
|
59
|
-
```svelte
|
|
60
|
-
<Tree
|
|
61
|
-
{data}
|
|
62
|
-
useFlatRendering={false} <!-- Uses recursive Node components -->
|
|
63
|
-
/>
|
|
32
|
+
<!-- Flat mode (default) with progressive batching -->
|
|
33
|
+
<Tree {data} progressiveRender={true} initialBatchSize={20} maxBatchSize={500} />
|
|
64
34
|
```
|
|
65
35
|
|
|
66
|
-
Recursive mode may be preferred for very small trees or when you need the `{#key changeTracker}` behavior that recreates all nodes on any change.
|
|
67
|
-
|
|
68
36
|
## Features
|
|
69
37
|
|
|
70
38
|
- **Svelte 5 Native**: Built specifically for Svelte 5 with full support for runes and modern Svelte patterns
|
|
71
|
-
- **High Performance**: Flat rendering
|
|
72
|
-
- **Drag & Drop**: Built-in drag and drop with position control (
|
|
39
|
+
- **High Performance**: Flat rendering with progressive loading, virtual scroll for 50,000+ nodes
|
|
40
|
+
- **Drag & Drop**: Built-in drag and drop with position control (before/after/child), touch support, and async validation
|
|
73
41
|
- **Tree Editing**: Built-in methods for add, move, remove operations with automatic path management
|
|
74
42
|
- **Search & Filter**: Integrated FlexSearch for fast, full-text search capabilities
|
|
75
43
|
- **Flexible Data Sources**: Works with any hierarchical data structure
|
|
@@ -155,14 +123,14 @@ import '@keenmate/svelte-treeview/styles.scss';
|
|
|
155
123
|
idMember="path"
|
|
156
124
|
pathMember="path"
|
|
157
125
|
selectedNodeClass="ltree-selected-bold"
|
|
158
|
-
onNodeClicked={(node) => console.log('Clicked:', node.data
|
|
126
|
+
onNodeClicked={(node) => console.log('Clicked:', node.data?.name)}
|
|
159
127
|
>
|
|
160
128
|
{#snippet nodeTemplate(node)}
|
|
161
129
|
<div class="d-flex align-items-center">
|
|
162
|
-
<span class="me-2">{node.data
|
|
163
|
-
<strong>{node.data
|
|
164
|
-
{#if node.data
|
|
165
|
-
<small class="text-muted ms-2">({node.data
|
|
130
|
+
<span class="me-2">{node.data?.icon}</span>
|
|
131
|
+
<strong>{node.data?.name}</strong>
|
|
132
|
+
{#if node.data?.size}
|
|
133
|
+
<small class="text-muted ms-2">({node.data?.size})</small>
|
|
166
134
|
{/if}
|
|
167
135
|
</div>
|
|
168
136
|
{/snippet}
|
|
@@ -277,13 +245,13 @@ For complete FlexSearch documentation, visit: [FlexSearch Options](https://githu
|
|
|
277
245
|
];
|
|
278
246
|
|
|
279
247
|
function onDragStart(node, event) {
|
|
280
|
-
console.log('Dragging:', node.data
|
|
248
|
+
console.log('Dragging:', node.data?.name);
|
|
281
249
|
}
|
|
282
250
|
|
|
283
251
|
// Same-tree moves are auto-handled - this callback is for notification/custom logic
|
|
284
252
|
function onDrop(dropNode, draggedNode, position, event, operation) {
|
|
285
|
-
console.log(`Dropped ${draggedNode.data
|
|
286
|
-
// position is '
|
|
253
|
+
console.log(`Dropped ${draggedNode.data?.name} ${position} ${dropNode?.data?.name}`);
|
|
254
|
+
// position is 'before', 'after', or 'child'
|
|
287
255
|
// operation is 'move' or 'copy' (Ctrl+drag)
|
|
288
256
|
}
|
|
289
257
|
</script>
|
|
@@ -303,16 +271,16 @@ For complete FlexSearch documentation, visit: [FlexSearch Options](https://githu
|
|
|
303
271
|
|
|
304
272
|
#### Drop Position Control
|
|
305
273
|
|
|
306
|
-
When using `dropZoneMode="floating"
|
|
307
|
-
- **
|
|
308
|
-
- **
|
|
274
|
+
When using `dropZoneMode="floating"`, users can choose where to drop:
|
|
275
|
+
- **Before**: Insert as sibling before the target node
|
|
276
|
+
- **After**: Insert as sibling after the target node
|
|
309
277
|
- **Child**: Insert as child of the target node
|
|
310
278
|
|
|
311
279
|
#### Per-Node Drop Position Restrictions
|
|
312
280
|
|
|
313
281
|
You can restrict which drop positions are allowed per node. This is useful for:
|
|
314
|
-
- **Trash/Recycle Bin**: Only allow dropping INTO (child), not
|
|
315
|
-
- **Files**: Only allow
|
|
282
|
+
- **Trash/Recycle Bin**: Only allow dropping INTO (child), not before/after
|
|
283
|
+
- **Files**: Only allow before/after (can't drop INTO a file)
|
|
316
284
|
- **Folders**: Allow all positions (default)
|
|
317
285
|
|
|
318
286
|
```svelte
|
|
@@ -321,7 +289,7 @@ You can restrict which drop positions are allowed per node. This is useful for:
|
|
|
321
289
|
|
|
322
290
|
// Dynamic callback approach
|
|
323
291
|
function getAllowedDropPositions(node: LTreeNode<MyItem>): DropPosition[] | null {
|
|
324
|
-
if (node.data?.type === 'file') return ['
|
|
292
|
+
if (node.data?.type === 'file') return ['before', 'after'];
|
|
325
293
|
if (node.data?.type === 'trash') return ['child'];
|
|
326
294
|
return undefined; // all positions allowed
|
|
327
295
|
}
|
|
@@ -363,7 +331,7 @@ Use `beforeDropCallback` to validate or modify drops, including async operations
|
|
|
363
331
|
if (position === 'child' && !dropNode.data.isFolder) {
|
|
364
332
|
const confirmed = await showConfirmDialog('Drop as sibling instead?');
|
|
365
333
|
if (!confirmed) return false;
|
|
366
|
-
return { position: '
|
|
334
|
+
return { position: 'after' }; // Override position
|
|
367
335
|
}
|
|
368
336
|
|
|
369
337
|
// Proceed normally
|
|
@@ -404,7 +372,7 @@ The tree provides built-in methods for programmatic editing:
|
|
|
404
372
|
const siblings = treeRef.getSiblings(selectedNode.path);
|
|
405
373
|
const index = siblings.findIndex(s => s.path === selectedNode.path);
|
|
406
374
|
if (index > 0) {
|
|
407
|
-
treeRef.moveNode(selectedNode.path, siblings[index - 1].path, '
|
|
375
|
+
treeRef.moveNode(selectedNode.path, siblings[index - 1].path, 'before');
|
|
408
376
|
}
|
|
409
377
|
}
|
|
410
378
|
|
|
@@ -423,7 +391,7 @@ The tree provides built-in methods for programmatic editing:
|
|
|
423
391
|
/>
|
|
424
392
|
```
|
|
425
393
|
|
|
426
|
-
**Note**: When using `orderMember`, the tree automatically calculates sort order values when moving nodes with '
|
|
394
|
+
**Note**: When using `orderMember`, the tree automatically calculates sort order values when moving nodes with 'before' or 'after' positions.
|
|
427
395
|
|
|
428
396
|
### With Context Menus
|
|
429
397
|
|
|
@@ -442,30 +410,30 @@ The tree supports context menus with two approaches: callback-based (recommended
|
|
|
442
410
|
{ path: '2', name: 'Images', type: 'folder', canEdit: false, canDelete: true }
|
|
443
411
|
];
|
|
444
412
|
|
|
445
|
-
function createContextMenu(node): ContextMenuItem[] {
|
|
413
|
+
function createContextMenu(node, closeMenu: () => void): ContextMenuItem[] {
|
|
446
414
|
const items: ContextMenuItem[] = [];
|
|
447
415
|
|
|
448
416
|
// Always available
|
|
449
417
|
items.push({
|
|
450
418
|
icon: '📂',
|
|
451
419
|
title: 'Open',
|
|
452
|
-
callback: () => alert(`Opening ${node.data
|
|
420
|
+
callback: () => alert(`Opening ${node.data?.name}`)
|
|
453
421
|
});
|
|
454
422
|
|
|
455
423
|
// Conditional actions based on node data
|
|
456
|
-
if (node.data
|
|
424
|
+
if (node.data?.canEdit) {
|
|
457
425
|
items.push({
|
|
458
426
|
icon: '✏️',
|
|
459
427
|
title: 'Edit',
|
|
460
|
-
callback: () => alert(`Editing ${node.data
|
|
428
|
+
callback: () => alert(`Editing ${node.data?.name}`)
|
|
461
429
|
});
|
|
462
430
|
}
|
|
463
431
|
|
|
464
|
-
if (node.data
|
|
432
|
+
if (node.data?.canDelete) {
|
|
465
433
|
items.push({
|
|
466
434
|
icon: '🗑️',
|
|
467
435
|
title: 'Delete',
|
|
468
|
-
callback: () => confirm(`Delete ${node.data
|
|
436
|
+
callback: () => confirm(`Delete ${node.data?.name}?`) && alert('Deleted!')
|
|
469
437
|
});
|
|
470
438
|
}
|
|
471
439
|
|
|
@@ -503,11 +471,11 @@ The tree supports context menus with two approaches: callback-based (recommended
|
|
|
503
471
|
pathMember="path"
|
|
504
472
|
>
|
|
505
473
|
{#snippet contextMenu(node, closeMenu)}
|
|
506
|
-
<div class="context-menu-item" onclick={() => { alert(`Open ${node.data
|
|
474
|
+
<div class="context-menu-item" onclick={() => { alert(`Open ${node.data?.name}`); closeMenu(); }}>
|
|
507
475
|
📂 Open
|
|
508
476
|
</div>
|
|
509
477
|
<div class="context-menu-divider"></div>
|
|
510
|
-
<div class="context-menu-item" onclick={() => { alert(`Delete ${node.data
|
|
478
|
+
<div class="context-menu-item" onclick={() => { alert(`Delete ${node.data?.name}`); closeMenu(); }}>
|
|
511
479
|
🗑️ Delete
|
|
512
480
|
</div>
|
|
513
481
|
{/snippet}
|
|
@@ -625,12 +593,11 @@ The component includes several pre-built classes for styling selected nodes:
|
|
|
625
593
|
| `data` | `T[]` | **required** | Array of data objects |
|
|
626
594
|
| `idMember` | `string` | **required** | Property name for unique identifiers |
|
|
627
595
|
| `pathMember` | `string` | **required** | Property name for hierarchical paths |
|
|
628
|
-
| `sortCallback` | `(items: T[]) => T[]` |
|
|
596
|
+
| `sortCallback` | `(items: LTreeNode<T>[]) => LTreeNode<T>[]` | `undefined` | Function to sort tree nodes |
|
|
629
597
|
|
|
630
598
|
#### Data Mapping Properties
|
|
631
599
|
| Prop | Type | Default | Description |
|
|
632
600
|
|------|------|---------|-------------|
|
|
633
|
-
| `treeId` | `string \| null` | `null` | Unique identifier for the tree |
|
|
634
601
|
| `parentPathMember` | `string \| null` | `null` | Property name for parent path references |
|
|
635
602
|
| `levelMember` | `string \| null` | `null` | Property name for node level |
|
|
636
603
|
| `isExpandedMember` | `string \| null` | `null` | Property name for expanded state |
|
|
@@ -638,6 +605,9 @@ The component includes several pre-built classes for styling selected nodes:
|
|
|
638
605
|
| `isDraggableMember` | `string \| null` | `null` | Property name for draggable state |
|
|
639
606
|
| `isDropAllowedMember` | `string \| null` | `null` | Property name for drop allowed state |
|
|
640
607
|
| `allowedDropPositionsMember` | `string \| null` | `null` | Property name for allowed drop positions array |
|
|
608
|
+
| `isCollapsibleMember` | `string \| null` | `null` | Property name for collapsible state |
|
|
609
|
+
| `getIsCollapsibleCallback` | `(node) => boolean` | `undefined` | Callback to determine if a node is collapsible |
|
|
610
|
+
| `getIsDraggableCallback` | `(node) => boolean` | `undefined` | Callback to determine if a node is draggable |
|
|
641
611
|
| `hasChildrenMember` | `string \| null` | `null` | Property name for children existence |
|
|
642
612
|
| `isSorted` | `boolean \| null` | `null` | Whether items should be sorted |
|
|
643
613
|
|
|
@@ -648,7 +618,7 @@ The component includes several pre-built classes for styling selected nodes:
|
|
|
648
618
|
| `getDisplayValueCallback` | `(node) => string` | `undefined` | Function to get display value |
|
|
649
619
|
| `searchValueMember` | `string \| null` | `null` | Property name for search indexing |
|
|
650
620
|
| `getSearchValueCallback` | `(node) => string` | `undefined` | Function to get search value |
|
|
651
|
-
| `shouldUseInternalSearchIndex` | `boolean` | `
|
|
621
|
+
| `shouldUseInternalSearchIndex` | `boolean` | `true` | Enable built-in search functionality |
|
|
652
622
|
| `initializeIndexCallback` | `() => Index` | `undefined` | Function to initialize search index |
|
|
653
623
|
| `searchText` | `string` (bindable) | `undefined` | Current search text |
|
|
654
624
|
|
|
@@ -677,9 +647,10 @@ Without both requirements, no search indexing will occur.
|
|
|
677
647
|
|------|------|---------|-------------|
|
|
678
648
|
| `expandLevel` | `number \| null` | `2` | Automatically expand nodes up to this level |
|
|
679
649
|
| `shouldToggleOnNodeClick` | `boolean` | `true` | Toggle expansion on node click |
|
|
680
|
-
| `orderMember` | `string \| null` | `null` | Property name for sort order (enables
|
|
650
|
+
| `orderMember` | `string \| null` | `null` | Property name for sort order (enables before/after positioning in drag-drop) |
|
|
681
651
|
| `indexerBatchSize` | `number \| null` | `25` | Number of nodes to process per batch during search indexing |
|
|
682
652
|
| `indexerTimeout` | `number \| null` | `50` | Maximum time (ms) to wait for idle callback before forcing indexing |
|
|
653
|
+
| `isLoading` | `boolean` | `false` | Show loading placeholder instead of tree content |
|
|
683
654
|
| `shouldDisplayDebugInformation` | `boolean` | `false` | Show debug information panel with tree statistics and enable console debug logging |
|
|
684
655
|
| `shouldDisplayContextMenuInDebugMode` | `boolean` | `false` | Display persistent context menu at fixed position for styling development |
|
|
685
656
|
|
|
@@ -690,7 +661,14 @@ Without both requirements, no search indexing will occur.
|
|
|
690
661
|
| `progressiveRender` | `boolean` | `true` | Progressively render nodes in batches |
|
|
691
662
|
| `initialBatchSize` | `number` | `20` | First batch size for progressive rendering |
|
|
692
663
|
| `maxBatchSize` | `number` | `500` | Maximum batch size cap |
|
|
693
|
-
| `
|
|
664
|
+
| `virtualScroll` | `boolean` | `false` | Enable virtual scrolling (flat mode only, renders visible + overscan rows) |
|
|
665
|
+
| `virtualRowHeight` | `number` | auto | Explicit row height in px (auto-measured from first row if not set) |
|
|
666
|
+
| `virtualOverscan` | `number` | `5` | Extra rows rendered above/below viewport |
|
|
667
|
+
| `virtualContainerHeight` | `string` | auto/`'400px'` | CSS height for scroll container (auto-detected from parent if not set) |
|
|
668
|
+
| `isRendering` | `boolean` (bindable) | `false` | Whether the tree is currently rendering (useful for progress indicators) |
|
|
669
|
+
| `onRenderStart` | `() => void` | `undefined` | Called when progressive rendering begins |
|
|
670
|
+
| `onRenderProgress` | `(rendered: number, total: number) => void` | `undefined` | Called after each batch with progress info |
|
|
671
|
+
| `onRenderComplete` | `() => void` | `undefined` | Called when progressive rendering finishes |
|
|
694
672
|
|
|
695
673
|
#### Drag & Drop Properties
|
|
696
674
|
| Prop | Type | Default | Description |
|
|
@@ -712,7 +690,7 @@ Without both requirements, no search indexing will occur.
|
|
|
712
690
|
| `onNodeClicked` | `(node) => void` | `undefined` | Node click event handler |
|
|
713
691
|
| `onNodeDragStart` | `(node, event) => void` | `undefined` | Drag start event handler |
|
|
714
692
|
| `onNodeDragOver` | `(node, event) => void` | `undefined` | Drag over event handler |
|
|
715
|
-
| `onNodeDrop` | `(dropNode, draggedNode, position, event, operation) => void` | `undefined` | Drop event handler. Position is `'
|
|
693
|
+
| `onNodeDrop` | `(dropNode, draggedNode, position, event, operation) => void` | `undefined` | Drop event handler. `dropNode` can be `null` (e.g., drop on empty tree). Position is `'before'`, `'after'`, or `'child'`. Operation is `'move'` or `'copy'` |
|
|
716
694
|
|
|
717
695
|
#### Visual Styling Properties
|
|
718
696
|
| Prop | Type | Default | Description |
|
|
@@ -731,9 +709,10 @@ Without both requirements, no search indexing will occur.
|
|
|
731
709
|
|---------|------------|-------------|
|
|
732
710
|
| `nodeTemplate` | `(node)` | Custom node template |
|
|
733
711
|
| `treeHeader` | | Tree header content |
|
|
734
|
-
| `treeBody` | | Tree body content |
|
|
735
712
|
| `treeFooter` | | Tree footer content |
|
|
736
|
-
| `noDataFound` | |
|
|
713
|
+
| `noDataFound` | | Content shown when tree has no data |
|
|
714
|
+
| `dropPlaceholder` | | Content shown in empty drop target tree |
|
|
715
|
+
| `loadingPlaceholder` | | Content shown while `isLoading` is true |
|
|
737
716
|
| `contextMenu` | `(node, closeMenu)` | Context menu template |
|
|
738
717
|
|
|
739
718
|
#### Public Methods
|
|
@@ -748,19 +727,31 @@ Without both requirements, no search indexing will occur.
|
|
|
748
727
|
| `scrollToPath` | `path: string, options?: ScrollToPathOptions` | Scroll to and highlight a specific node |
|
|
749
728
|
| `update` | `updates: Partial<Props>` | Programmatically update component props from external JavaScript |
|
|
750
729
|
| `addNode` | `parentPath: string, data: T, pathSegment?: string` | Add a new node under the specified parent |
|
|
751
|
-
| `moveNode` | `sourcePath: string, targetPath: string, position: '
|
|
730
|
+
| `moveNode` | `sourcePath: string, targetPath: string, position: 'before' \| 'after' \| 'child'` | Move a node to a new location |
|
|
752
731
|
| `removeNode` | `path: string, includeDescendants?: boolean` | Remove a node (and optionally its descendants) |
|
|
753
732
|
| `getNodeByPath` | `path: string` | Get a node by its path |
|
|
754
733
|
| `getChildren` | `parentPath: string` | Get direct children of a node |
|
|
755
734
|
| `getSiblings` | `path: string` | Get siblings of a node (including itself) |
|
|
735
|
+
| `updateNode` | `path: string, data: Partial<T>` | Update a node's data properties |
|
|
736
|
+
| `copyNodeWithDescendants` | `sourcePath: string, targetPath: string, position: DropPosition` | Copy a node and its subtree to a new location |
|
|
737
|
+
| `refreshNode` | `path: string` | Force re-render of a specific node |
|
|
738
|
+
| `refreshSiblings` | `path: string` | Force re-render of a node's siblings |
|
|
739
|
+
| `getExpandedPaths` | | Get array of all currently expanded node paths |
|
|
740
|
+
| `setExpandedPaths` | `paths: string[]` | Restore expanded state from saved paths |
|
|
741
|
+
| `getAllData` | | Get all tree data as a flat array |
|
|
742
|
+
| `applyChanges` | | Apply pending changes and refresh the tree |
|
|
743
|
+
| `closeContextMenu` | | Programmatically close the context menu |
|
|
756
744
|
|
|
757
745
|
#### ScrollToPath Options
|
|
758
746
|
|
|
759
747
|
| Option | Type | Default | Description |
|
|
760
748
|
|--------|------|---------|-------------|
|
|
761
749
|
| `expand` | `boolean` | `true` | Automatically expand parent nodes to make target visible |
|
|
750
|
+
| `expandTarget` | `boolean` | `false` | Also expand the target node itself (not just its ancestors) |
|
|
762
751
|
| `highlight` | `boolean` | `true` | Apply temporary highlight animation to the target node |
|
|
763
752
|
| `scrollOptions` | `ScrollIntoViewOptions` | `{ behavior: 'smooth', block: 'center' }` | Native browser scroll options |
|
|
753
|
+
| `containerScroll` | `boolean` | `false` | Scroll only within nearest scrollable ancestor (prevents page scroll) |
|
|
754
|
+
| `containerElement` | `HTMLElement` | `undefined` | Explicit scrollable container element to use for scrolling |
|
|
764
755
|
|
|
765
756
|
**Usage Example:**
|
|
766
757
|
```typescript
|
|
@@ -776,6 +767,9 @@ await tree.scrollToPath('1.2.3', {
|
|
|
776
767
|
block: 'start'
|
|
777
768
|
}
|
|
778
769
|
});
|
|
770
|
+
|
|
771
|
+
// Scroll within a scrollable container (prevents page scroll)
|
|
772
|
+
await tree.scrollToPath('1.2.3', { containerScroll: true });
|
|
779
773
|
```
|
|
780
774
|
|
|
781
775
|
**Highlight Classes Example:**
|
|
@@ -939,7 +933,7 @@ const sortCallback = (items: LTreeNode<T>[]) => {
|
|
|
939
933
|
}
|
|
940
934
|
|
|
941
935
|
// Then sort by your custom criteria
|
|
942
|
-
return a.data
|
|
936
|
+
return (a.data?.name ?? '').localeCompare(b.data?.name ?? '');
|
|
943
937
|
});
|
|
944
938
|
};
|
|
945
939
|
```
|
|
@@ -1010,36 +1004,40 @@ interface InsertArrayResult<T> {
|
|
|
1010
1004
|
|
|
1011
1005
|
The component is optimized for large datasets:
|
|
1012
1006
|
|
|
1007
|
+
- **Virtual Scroll**: Renders only visible rows (~50 DOM nodes) for trees with 50,000+ nodes
|
|
1013
1008
|
- **Flat Rendering Mode**: Single `{#each}` loop instead of recursive components (default, ~12x faster initial render)
|
|
1014
1009
|
- **Progressive Rendering**: Batched rendering prevents UI freeze during initial load
|
|
1015
|
-
- **Context-Based Callbacks**: Stable function references eliminate unnecessary re-renders
|
|
1016
|
-
- **LTree**: Efficient hierarchical data structure
|
|
1017
1010
|
- **Async Search Indexing**: Uses `requestIdleCallback` for non-blocking search index building
|
|
1018
|
-
- **
|
|
1019
|
-
- **Search Indexing**: Uses FlexSearch for fast search operations
|
|
1011
|
+
- **LTree**: Efficient hierarchical data structure with FlexSearch integration
|
|
1020
1012
|
|
|
1021
1013
|
### Performance Benchmarks (5500 nodes)
|
|
1022
1014
|
|
|
1023
1015
|
| Operation | Time |
|
|
1024
1016
|
|-----------|------|
|
|
1025
|
-
| Initial render | ~25ms |
|
|
1017
|
+
| Initial render (flat) | ~25ms |
|
|
1018
|
+
| Initial render (virtual) | ~5ms |
|
|
1026
1019
|
| Expand/collapse | ~100-150ms |
|
|
1027
1020
|
| Search filtering | <50ms |
|
|
1021
|
+
| insertArray | <100ms |
|
|
1028
1022
|
|
|
1029
|
-
###
|
|
1023
|
+
### Virtual Scroll
|
|
1024
|
+
|
|
1025
|
+
For trees with 10,000+ nodes, enable virtual scroll to keep DOM size constant:
|
|
1030
1026
|
|
|
1031
|
-
**Flat Rendering Mode** (default) - Renders all visible nodes in a single loop:
|
|
1032
1027
|
```svelte
|
|
1033
1028
|
<Tree
|
|
1034
1029
|
{data}
|
|
1035
|
-
|
|
1036
|
-
|
|
1030
|
+
virtualScroll={true}
|
|
1031
|
+
virtualContainerHeight="500px"
|
|
1032
|
+
virtualOverscan={5}
|
|
1037
1033
|
/>
|
|
1038
1034
|
```
|
|
1039
1035
|
|
|
1040
|
-
|
|
1036
|
+
Virtual scroll auto-measures row height from the first rendered node. Override with `virtualRowHeight={32}` if needed. Requires flat rendering mode (the default).
|
|
1037
|
+
|
|
1038
|
+
### Performance Logging
|
|
1041
1039
|
|
|
1042
|
-
|
|
1040
|
+
Built-in performance measurement for debugging:
|
|
1043
1041
|
```typescript
|
|
1044
1042
|
import { enablePerfLogging } from '@keenmate/svelte-treeview';
|
|
1045
1043
|
enablePerfLogging();
|
|
@@ -1052,32 +1050,12 @@ window.components['svelte-treeview'].perf.enable()
|
|
|
1052
1050
|
|
|
1053
1051
|
## CanvasTree (Canvas-Based Rendering)
|
|
1054
1052
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
### Layout Modes
|
|
1053
|
+
Canvas rendering is available as a separate companion package: [`@keenmate/svelte-treeview-canvas`](https://github.com/keenmate/svelte-treeview-canvas)
|
|
1058
1054
|
|
|
1059
|
-
|
|
1060
|
-
|------|-------------|
|
|
1061
|
-
| `tree` | Standard hierarchical tree (default) |
|
|
1062
|
-
| `balanced` | Root centered with two symmetric arms |
|
|
1063
|
-
| `fishbone` | Spine with alternating branches above/below |
|
|
1064
|
-
| `radial` | Star / concentric rings from center |
|
|
1065
|
-
| `box` | Space-filling treemap |
|
|
1055
|
+
It renders trees on HTML5 Canvas for high-performance visualization with multiple layout modes (tree, balanced, fishbone, radial, box), keyboard navigation, drag & drop, and custom node rendering. Install it separately:
|
|
1066
1056
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
In fishbone layout, keyboard navigation follows the fishbone structure:
|
|
1070
|
-
|
|
1071
|
-
- **Left/Right**: Navigate between same-side nodes along the spine axis. Spine nodes stay on their side; branch nodes traverse same-depth peers across all spine branches.
|
|
1072
|
-
- **Up/Down**: Navigate parent/child within a branch. From spine nodes, enters branch children on the pressed side.
|
|
1073
|
-
- **Cross-spine** (optional): When `fishboneCrossNav={true}`, Up/Down crosses to the opposite side of the spine when no more nodes exist in the current direction.
|
|
1074
|
-
|
|
1075
|
-
```svelte
|
|
1076
|
-
<CanvasTree
|
|
1077
|
-
{data}
|
|
1078
|
-
layoutMode="fishbone"
|
|
1079
|
-
fishboneCrossNav={false} <!-- default: stops at spine boundary -->
|
|
1080
|
-
/>
|
|
1057
|
+
```bash
|
|
1058
|
+
npm install @keenmate/svelte-treeview-canvas
|
|
1081
1059
|
```
|
|
1082
1060
|
|
|
1083
1061
|
## Development Setup & Contributing
|