@keenmate/svelte-treeview 4.7.0 → 4.8.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/README.md +148 -205
- package/dist/components/Node.svelte +39 -67
- package/dist/components/Node.svelte.d.ts +1 -1
- package/dist/components/Tree.svelte +416 -171
- package/dist/components/Tree.svelte.d.ts +31 -13
- package/dist/constants.generated.d.ts +1 -1
- package/dist/constants.generated.js +1 -1
- package/dist/ltree/indexer.js +3 -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.js +104 -72
- package/dist/ltree/types.d.ts +4 -0
- package/dist/styles/main.scss +53 -6
- package/dist/styles.css +43 -6
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
A high-performance, feature-rich hierarchical tree view component for Svelte 5 with drag & drop support, search functionality, and flexible data structures using LTree.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Live Demo
|
|
6
|
+
|
|
7
|
+
Browse interactive code examples and the full API reference at **[svelte-treeview.keenmate.dev](https://svelte-treeview.keenmate.dev)**
|
|
8
|
+
|
|
9
|
+
## New in v4.8: Virtual Scroll & Unified Rendering
|
|
10
|
+
|
|
11
|
+
> [!NOTE]
|
|
12
|
+
> **New virtual scroll mode renders only visible nodes — handle 50,000+ items without DOM bloat.**
|
|
13
|
+
|
|
14
|
+
Three rendering modes, one consistent look:
|
|
15
|
+
|
|
16
|
+
| Mode | Best for | How it works |
|
|
17
|
+
|------|----------|-------------|
|
|
18
|
+
| **Recursive** | Small trees (<500 nodes) | Traditional nested Svelte components |
|
|
19
|
+
| **Progressive** (default) | Medium trees (500–10,000) | Flat rendering with exponential batching |
|
|
20
|
+
| **Virtual Scroll** | Large trees (10,000+) | Only visible rows + overscan are in the DOM |
|
|
21
|
+
|
|
22
|
+
```svelte
|
|
23
|
+
<Tree
|
|
24
|
+
{data}
|
|
25
|
+
virtualScroll={true}
|
|
26
|
+
virtualRowHeight={28}
|
|
27
|
+
virtualOverscan={5}
|
|
28
|
+
virtualContainerHeight="600px"
|
|
29
|
+
/>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Also in this release:**
|
|
33
|
+
- **Search result navigation** — dual-mode filter/search with result counter, prev/next (Enter/Shift+Enter), round-robin cycling
|
|
34
|
+
- **Floating drop zones auto-expand** when positions are restricted — pure CSS `:not(:has())`, zero JS overhead
|
|
35
|
+
- **Cross-tree drop positioning fixed** — above/below placement now works correctly between trees
|
|
36
|
+
- **Unified indentation & gaps** across all three rendering modes
|
|
37
|
+
- **Drag & drop disabled by default** — set `dragDropMode="both"` to enable
|
|
38
|
+
|
|
39
|
+
## v4.7: Per-Node Drop Position Restrictions
|
|
6
40
|
|
|
7
41
|
> [!NOTE]
|
|
8
42
|
> **You can now restrict which drop positions (above/below/child) are allowed per node.**
|
|
@@ -17,7 +51,7 @@ function getAllowedDropPositions(node) {
|
|
|
17
51
|
}
|
|
18
52
|
```
|
|
19
53
|
|
|
20
|
-
##
|
|
54
|
+
## v4.6: Progressive Flat Rendering
|
|
21
55
|
|
|
22
56
|
> [!NOTE]
|
|
23
57
|
> **The tree now uses progressive flat rendering by default for significantly improved performance.**
|
|
@@ -51,7 +85,7 @@ function getAllowedDropPositions(node) {
|
|
|
51
85
|
|
|
52
86
|
Recursive mode may be preferred for very small trees or when you need the `{#key changeTracker}` behavior that recreates all nodes on any change.
|
|
53
87
|
|
|
54
|
-
##
|
|
88
|
+
## Features
|
|
55
89
|
|
|
56
90
|
- **Svelte 5 Native**: Built specifically for Svelte 5 with full support for runes and modern Svelte patterns
|
|
57
91
|
- **High Performance**: Flat rendering mode with progressive loading for 5000+ nodes
|
|
@@ -64,77 +98,34 @@ Recursive mode may be preferred for very small trees or when you need the `{#key
|
|
|
64
98
|
- **TypeScript Support**: Full TypeScript support with comprehensive type definitions
|
|
65
99
|
- **Accessibility**: Built with accessibility in mind
|
|
66
100
|
|
|
67
|
-
##
|
|
101
|
+
## Installation
|
|
68
102
|
|
|
69
103
|
```bash
|
|
70
104
|
npm install @keenmate/svelte-treeview
|
|
71
105
|
```
|
|
72
106
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
For developers working on the project, you can use either standard npm commands or the provided Makefile (which provides a unified interface for all contributors):
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
# Using Makefile (recommended for consistency)
|
|
79
|
-
make setup # or make install
|
|
80
|
-
make dev
|
|
81
|
-
|
|
82
|
-
# Or using standard npm commands
|
|
83
|
-
npm install
|
|
84
|
-
npm run dev
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## 🎨 Importing Styles
|
|
107
|
+
### Importing Styles
|
|
88
108
|
|
|
89
109
|
The component requires CSS to display correctly. Import the styles in your app:
|
|
90
110
|
|
|
91
|
-
|
|
111
|
+
**JavaScript import** (in your main.js/main.ts or Vite/Webpack entry):
|
|
92
112
|
```javascript
|
|
93
|
-
// In your main.js or main.ts
|
|
94
113
|
import '@keenmate/svelte-treeview/styles.scss';
|
|
95
114
|
```
|
|
96
115
|
|
|
97
|
-
|
|
116
|
+
**Svelte component import:**
|
|
98
117
|
```svelte
|
|
99
118
|
<style>
|
|
100
119
|
@import '@keenmate/svelte-treeview/styles.scss';
|
|
101
120
|
</style>
|
|
102
121
|
```
|
|
103
122
|
|
|
104
|
-
|
|
105
|
-
If using Vite, Webpack, or similar, you can import the SCSS:
|
|
106
|
-
```javascript
|
|
107
|
-
import '@keenmate/svelte-treeview/styles.scss';
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## ⚠️ Performance Warning: Use `$state.raw()` for Large Datasets
|
|
111
|
-
|
|
112
|
-
> [!WARNING]
|
|
113
|
-
> **When passing large arrays (1000+ items) to the Tree component, use `$state.raw()` instead of `$state()` to avoid severe performance issues.**
|
|
114
|
-
|
|
115
|
-
Svelte 5's `$state()` creates deep proxies for all nested objects. With thousands of items, this causes massive overhead during tree operations.
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
// ❌ SLOW - Each item becomes a Proxy (5000x slower with large datasets)
|
|
119
|
-
let treeData = $state<TreeNode[]>([])
|
|
120
|
-
|
|
121
|
-
// ✅ FAST - Items remain plain objects
|
|
122
|
-
let treeData = $state.raw<TreeNode[]>([])
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Symptoms of this issue:**
|
|
126
|
-
- Tree takes 15-90+ seconds to render with thousands of items
|
|
127
|
-
- Console shows `[Violation] 'message' handler took XXXXms`
|
|
128
|
-
- Same data loads instantly in isolated test
|
|
129
|
-
|
|
130
|
-
The array itself remains reactive - only individual items lose deep reactivity (which Tree doesn't need).
|
|
131
|
-
|
|
132
|
-
## 🎯 Quick Start
|
|
123
|
+
## Quick Start
|
|
133
124
|
|
|
134
125
|
```svelte
|
|
135
126
|
<script lang="ts">
|
|
136
127
|
import { Tree } from '@keenmate/svelte-treeview';
|
|
137
|
-
|
|
128
|
+
|
|
138
129
|
const data = [
|
|
139
130
|
{ path: '1', name: 'Documents', type: 'folder' },
|
|
140
131
|
{ path: '1.1', name: 'Projects', type: 'folder' },
|
|
@@ -153,14 +144,24 @@ The array itself remains reactive - only individual items lose deep reactivity (
|
|
|
153
144
|
/>
|
|
154
145
|
```
|
|
155
146
|
|
|
156
|
-
|
|
147
|
+
> [!TIP]
|
|
148
|
+
> **Performance tip:** When passing large arrays (1000+ items) to the Tree component, use `$state.raw()` instead of `$state()` to avoid severe performance issues. Svelte 5's `$state()` creates deep proxies — with thousands of items this causes up to 5,000x slowdown. The array itself remains reactive; only individual items lose deep reactivity (which Tree doesn't need).
|
|
149
|
+
> ```typescript
|
|
150
|
+
> // BAD - Each item becomes a Proxy
|
|
151
|
+
> let treeData = $state<TreeNode[]>([])
|
|
152
|
+
>
|
|
153
|
+
> // GOOD - Items remain plain objects
|
|
154
|
+
> let treeData = $state.raw<TreeNode[]>([])
|
|
155
|
+
> ```
|
|
156
|
+
|
|
157
|
+
## Advanced Usage
|
|
157
158
|
|
|
158
159
|
### With Custom Node Templates
|
|
159
160
|
|
|
160
161
|
```svelte
|
|
161
162
|
<script lang="ts">
|
|
162
163
|
import { Tree } from '@keenmate/svelte-treeview';
|
|
163
|
-
|
|
164
|
+
|
|
164
165
|
const fileData = [
|
|
165
166
|
{ path: '1', name: 'Documents', type: 'folder', icon: '📁' },
|
|
166
167
|
{ path: '1.1', name: 'report.pdf', type: 'file', icon: '📄', size: '2.3 MB' },
|
|
@@ -193,15 +194,15 @@ The array itself remains reactive - only individual items lose deep reactivity (
|
|
|
193
194
|
```svelte
|
|
194
195
|
<script lang="ts">
|
|
195
196
|
import { Tree } from '@keenmate/svelte-treeview';
|
|
196
|
-
|
|
197
|
+
|
|
197
198
|
let searchText = $state('');
|
|
198
199
|
const data = [/* your data */];
|
|
199
200
|
</script>
|
|
200
201
|
|
|
201
|
-
<input
|
|
202
|
-
type="text"
|
|
203
|
-
placeholder="Search..."
|
|
204
|
-
bind:value={searchText}
|
|
202
|
+
<input
|
|
203
|
+
type="text"
|
|
204
|
+
placeholder="Search..."
|
|
205
|
+
bind:value={searchText}
|
|
205
206
|
/>
|
|
206
207
|
|
|
207
208
|
<Tree
|
|
@@ -220,29 +221,29 @@ The array itself remains reactive - only individual items lose deep reactivity (
|
|
|
220
221
|
<script lang="ts">
|
|
221
222
|
import { Tree } from '@keenmate/svelte-treeview';
|
|
222
223
|
import type { SearchOptions } from 'flexsearch';
|
|
223
|
-
|
|
224
|
+
|
|
224
225
|
let treeRef;
|
|
225
226
|
const data = [/* your data */];
|
|
226
|
-
|
|
227
|
+
|
|
227
228
|
// Programmatic search with FlexSearch options
|
|
228
229
|
function performAdvancedSearch(searchTerm: string) {
|
|
229
230
|
const searchOptions: SearchOptions = {
|
|
230
231
|
suggest: true, // Enable suggestions for typos
|
|
231
|
-
limit: 10, // Limit results to 10 items
|
|
232
|
+
limit: 10, // Limit results to 10 items
|
|
232
233
|
bool: "and" // Use AND logic for multiple terms
|
|
233
234
|
};
|
|
234
|
-
|
|
235
|
+
|
|
235
236
|
const results = treeRef.searchNodes(searchTerm, searchOptions);
|
|
236
237
|
console.log('Advanced search results:', results);
|
|
237
238
|
}
|
|
238
|
-
|
|
239
|
+
|
|
239
240
|
// Programmatic filtering with options
|
|
240
241
|
function filterWithOptions(searchTerm: string) {
|
|
241
242
|
const searchOptions: SearchOptions = {
|
|
242
243
|
threshold: 0.8, // Similarity threshold
|
|
243
244
|
depth: 2 // Search depth
|
|
244
245
|
};
|
|
245
|
-
|
|
246
|
+
|
|
246
247
|
treeRef.filterNodes(searchTerm, searchOptions);
|
|
247
248
|
}
|
|
248
249
|
</script>
|
|
@@ -281,6 +282,8 @@ For complete FlexSearch documentation, visit: [FlexSearch Options](https://githu
|
|
|
281
282
|
|
|
282
283
|
### With Drag & Drop
|
|
283
284
|
|
|
285
|
+
**Note:** Drag and drop is disabled by default. Set `dragDropMode` to enable it.
|
|
286
|
+
|
|
284
287
|
```svelte
|
|
285
288
|
<script lang="ts">
|
|
286
289
|
import { Tree } from '@keenmate/svelte-treeview';
|
|
@@ -288,9 +291,9 @@ For complete FlexSearch documentation, visit: [FlexSearch Options](https://githu
|
|
|
288
291
|
let treeRef: Tree<MyNode>;
|
|
289
292
|
|
|
290
293
|
const data = [
|
|
291
|
-
{ path: '1', name: 'Folder 1'
|
|
292
|
-
{ path: '1.1', name: 'Item 1'
|
|
293
|
-
{ path: '2', name: 'Folder 2'
|
|
294
|
+
{ path: '1', name: 'Folder 1' },
|
|
295
|
+
{ path: '1.1', name: 'Item 1' },
|
|
296
|
+
{ path: '2', name: 'Folder 2' }
|
|
294
297
|
];
|
|
295
298
|
|
|
296
299
|
function onDragStart(node, event) {
|
|
@@ -310,6 +313,7 @@ For complete FlexSearch documentation, visit: [FlexSearch Options](https://githu
|
|
|
310
313
|
{data}
|
|
311
314
|
idMember="path"
|
|
312
315
|
pathMember="path"
|
|
316
|
+
dragDropMode="both"
|
|
313
317
|
orderMember="sortOrder"
|
|
314
318
|
dragOverNodeClass="ltree-dragover-highlight"
|
|
315
319
|
onNodeDragStart={onDragStart}
|
|
@@ -539,7 +543,7 @@ The tree supports context menus with two approaches: callback-based (recommended
|
|
|
539
543
|
- **Auto-close**: Closes on scroll, click outside, or programmatically
|
|
540
544
|
- **Type safety**: Full TypeScript support with `ContextMenuItem` interface
|
|
541
545
|
|
|
542
|
-
##
|
|
546
|
+
## Styling and Customization
|
|
543
547
|
|
|
544
548
|
The component comes with default styles that provide a clean, modern look. You can customize it extensively:
|
|
545
549
|
|
|
@@ -609,7 +613,7 @@ The component includes several pre-built classes for styling selected nodes:
|
|
|
609
613
|
|-------|-------------|---------------|
|
|
610
614
|
| `ltree-selected-bold` | Bold text with primary color | **Bold text** in theme primary color |
|
|
611
615
|
| `ltree-selected-border` | Border and background highlight | Solid border with light background |
|
|
612
|
-
| `ltree-selected-brackets` | Decorative brackets around text |
|
|
616
|
+
| `ltree-selected-brackets` | Decorative brackets around text | > **Node Text** < |
|
|
613
617
|
|
|
614
618
|
**Available Drag-over Node Classes:**
|
|
615
619
|
|
|
@@ -631,17 +635,17 @@ The component includes several pre-built classes for styling selected nodes:
|
|
|
631
635
|
/>
|
|
632
636
|
```
|
|
633
637
|
|
|
634
|
-
##
|
|
638
|
+
## API Reference
|
|
635
639
|
|
|
636
640
|
### Tree Component Props
|
|
637
641
|
|
|
638
|
-
#### Core
|
|
639
|
-
| Prop | Type |
|
|
640
|
-
|
|
641
|
-
| `data` | `T[]` |
|
|
642
|
-
| `idMember` | `string` |
|
|
643
|
-
| `pathMember` | `string` |
|
|
644
|
-
| `sortCallback` | `(items: T[]) => T[]` |
|
|
642
|
+
#### Core Properties
|
|
643
|
+
| Prop | Type | Default | Description |
|
|
644
|
+
|------|------|---------|-------------|
|
|
645
|
+
| `data` | `T[]` | **required** | Array of data objects |
|
|
646
|
+
| `idMember` | `string` | **required** | Property name for unique identifiers |
|
|
647
|
+
| `pathMember` | `string` | **required** | Property name for hierarchical paths |
|
|
648
|
+
| `sortCallback` | `(items: T[]) => T[]` | default sort | Function to sort items (optional) |
|
|
645
649
|
|
|
646
650
|
#### Data Mapping Properties
|
|
647
651
|
| Prop | Type | Default | Description |
|
|
@@ -670,13 +674,13 @@ The component includes several pre-built classes for styling selected nodes:
|
|
|
670
674
|
|
|
671
675
|
**Note**: When `shouldUseInternalSearchIndex` is enabled, node indexing is performed asynchronously using `requestIdleCallback` (with fallback to `setTimeout`). This ensures the tree renders immediately while search indexing happens during browser idle time, providing better performance for large datasets.
|
|
672
676
|
|
|
673
|
-
|
|
677
|
+
**Important**: For internal search indexing to work, you must:
|
|
674
678
|
1. Set `shouldUseInternalSearchIndex={true}`
|
|
675
679
|
2. Provide either `searchValueMember` (property name) or `getSearchValueCallback` (function)
|
|
676
680
|
|
|
677
681
|
Without both requirements, no search indexing will occur.
|
|
678
682
|
|
|
679
|
-
**Performance Tuning**:
|
|
683
|
+
**Performance Tuning**:
|
|
680
684
|
- `indexerBatchSize` controls how many nodes are processed per idle callback. Lower values (10-25) provide smoother UI performance but slower indexing, while higher values (50-100) index faster but may cause brief UI pauses. Default: 25.
|
|
681
685
|
- `indexerTimeout` sets the maximum wait time before forcing indexing when the browser is busy. Lower values (25-50ms) ensure more responsive indexing, while higher values (100-200ms) give more time for genuine idle periods. Default: 50ms.
|
|
682
686
|
|
|
@@ -693,24 +697,41 @@ Without both requirements, no search indexing will occur.
|
|
|
693
697
|
|------|------|---------|-------------|
|
|
694
698
|
| `expandLevel` | `number \| null` | `2` | Automatically expand nodes up to this level |
|
|
695
699
|
| `shouldToggleOnNodeClick` | `boolean` | `true` | Toggle expansion on node click |
|
|
696
|
-
| `useFlatRendering` | `boolean` | `true` | Use flat rendering mode (faster for large trees) |
|
|
697
|
-
| `progressiveRender` | `boolean` | `true` | Progressively render nodes in batches |
|
|
698
|
-
| `renderBatchSize` | `number` | `50` | Number of nodes to render per batch |
|
|
699
700
|
| `orderMember` | `string \| null` | `null` | Property name for sort order (enables above/below positioning in drag-drop) |
|
|
700
701
|
| `indexerBatchSize` | `number \| null` | `25` | Number of nodes to process per batch during search indexing |
|
|
701
702
|
| `indexerTimeout` | `number \| null` | `50` | Maximum time (ms) to wait for idle callback before forcing indexing |
|
|
702
|
-
| `shouldDisplayDebugInformation` | `boolean` | `false` | Show debug information panel with tree statistics and enable console debug logging
|
|
703
|
+
| `shouldDisplayDebugInformation` | `boolean` | `false` | Show debug information panel with tree statistics and enable console debug logging |
|
|
703
704
|
| `shouldDisplayContextMenuInDebugMode` | `boolean` | `false` | Display persistent context menu at fixed position for styling development |
|
|
704
705
|
|
|
706
|
+
#### Rendering Properties
|
|
707
|
+
| Prop | Type | Default | Description |
|
|
708
|
+
|------|------|---------|-------------|
|
|
709
|
+
| `useFlatRendering` | `boolean` | `true` | Use flat rendering mode (faster for large trees) |
|
|
710
|
+
| `progressiveRender` | `boolean` | `true` | Progressively render nodes in batches |
|
|
711
|
+
| `initialBatchSize` | `number` | `20` | First batch size for progressive rendering |
|
|
712
|
+
| `maxBatchSize` | `number` | `500` | Maximum batch size cap |
|
|
713
|
+
|
|
714
|
+
#### Drag & Drop Properties
|
|
715
|
+
| Prop | Type | Default | Description |
|
|
716
|
+
|------|------|---------|-------------|
|
|
717
|
+
| `dragDropMode` | `DragDropMode` | `'none'` | Controls allowed drag operations: `'none'`, `'self'`, `'cross'`, `'both'` |
|
|
718
|
+
| `dropZoneMode` | `string` | `'glow'` | Drop indicator style: `'floating'` or `'glow'` |
|
|
719
|
+
| `dropZoneLayout` | `string` | `'around'` | Zone arrangement: `'around'`, `'above'`, `'below'`, `'wave'`, `'wave2'` |
|
|
720
|
+
| `dropZoneStart` | `number \| string` | `33` | Where zones start horizontally (number=%, string=CSS value) |
|
|
721
|
+
| `dropZoneMaxWidth` | `number` | `120` | Max width in pixels for wave layouts |
|
|
722
|
+
| `allowCopy` | `boolean` | `false` | Enable Ctrl+drag to copy instead of move |
|
|
723
|
+
| `autoHandleCopy` | `boolean` | `true` | Auto-handle same-tree copies (false for external DB/API) |
|
|
724
|
+
| `allowedDropPositionsMember` | `string \| null` | `null` | Property name for allowed drop positions array |
|
|
725
|
+
| `getAllowedDropPositionsCallback` | `(node) => DropPosition[] \| null` | `undefined` | Callback returning allowed drop positions per node |
|
|
726
|
+
| `beforeDropCallback` | `(dropNode, draggedNode, position, event, operation) => ...` | `undefined` | Async-capable callback to validate/modify drops |
|
|
727
|
+
|
|
705
728
|
#### Event Handler Properties
|
|
706
729
|
| Prop | Type | Default | Description |
|
|
707
730
|
|------|------|---------|-------------|
|
|
708
731
|
| `onNodeClicked` | `(node) => void` | `undefined` | Node click event handler |
|
|
709
732
|
| `onNodeDragStart` | `(node, event) => void` | `undefined` | Drag start event handler |
|
|
710
733
|
| `onNodeDragOver` | `(node, event) => void` | `undefined` | Drag over event handler |
|
|
711
|
-
| `
|
|
712
|
-
| `beforeDropCallback` | `(dropNode, draggedNode, position, event, operation) => boolean \| { position?, operation? } \| Promise<...>` | `undefined` | Async-capable callback to validate/modify drops before they happen |
|
|
713
|
-
| `onNodeDrop` | `(dropNode, draggedNode, position, event, operation) => void` | `undefined` | Drop event handler. Position is 'above', 'below', or 'child'. Operation is 'move' or 'copy' |
|
|
734
|
+
| `onNodeDrop` | `(dropNode, draggedNode, position, event, operation) => void` | `undefined` | Drop event handler. Position is `'above'`, `'below'`, or `'child'`. Operation is `'move'` or `'copy'` |
|
|
714
735
|
|
|
715
736
|
#### Visual Styling Properties
|
|
716
737
|
| Prop | Type | Default | Description |
|
|
@@ -724,15 +745,15 @@ Without both requirements, no search indexing will occur.
|
|
|
724
745
|
| `scrollHighlightTimeout` | `number \| null` | `4000` | Duration (ms) for scroll highlight animation |
|
|
725
746
|
| `scrollHighlightClass` | `string \| null` | `'ltree-scroll-highlight'` | CSS class to apply for scroll highlight effect |
|
|
726
747
|
|
|
727
|
-
####
|
|
728
|
-
|
|
|
729
|
-
|
|
730
|
-
| `nodeTemplate` | Custom node template |
|
|
731
|
-
| `treeHeader` | Tree header content |
|
|
732
|
-
| `treeBody` | Tree body content |
|
|
733
|
-
| `treeFooter` | Tree footer content |
|
|
734
|
-
| `noDataFound` | No data template |
|
|
735
|
-
| `contextMenu` | Context menu template |
|
|
748
|
+
#### Snippets
|
|
749
|
+
| Snippet | Parameters | Description |
|
|
750
|
+
|---------|------------|-------------|
|
|
751
|
+
| `nodeTemplate` | `(node)` | Custom node template |
|
|
752
|
+
| `treeHeader` | | Tree header content |
|
|
753
|
+
| `treeBody` | | Tree body content |
|
|
754
|
+
| `treeFooter` | | Tree footer content |
|
|
755
|
+
| `noDataFound` | | No data template |
|
|
756
|
+
| `contextMenu` | `(node, closeMenu)` | Context menu template |
|
|
736
757
|
|
|
737
758
|
#### Public Methods
|
|
738
759
|
| Method | Parameters | Description |
|
|
@@ -905,99 +926,7 @@ When enabled, the component will log detailed information to the browser console
|
|
|
905
926
|
|
|
906
927
|
This provides valuable insights for performance optimization and troubleshooting, especially when working with large datasets or complex search operations.
|
|
907
928
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
#### onNodeClicked(node)
|
|
911
|
-
Triggered when a node is clicked.
|
|
912
|
-
|
|
913
|
-
#### onNodeDragStart(node, event)
|
|
914
|
-
Triggered when drag operation starts.
|
|
915
|
-
|
|
916
|
-
#### onNodeDragOver(node, event)
|
|
917
|
-
Triggered when dragging over a potential drop target.
|
|
918
|
-
|
|
919
|
-
#### beforeDropCallback(dropNode, draggedNode, position, event, operation)
|
|
920
|
-
Called before a drop is processed. Can be async for showing dialogs.
|
|
921
|
-
- Return `false` to cancel the drop
|
|
922
|
-
- Return `{ position: 'above'|'below'|'child' }` to override position
|
|
923
|
-
- Return `{ operation: 'move'|'copy' }` to override operation
|
|
924
|
-
- Return `true` or `undefined` to proceed normally
|
|
925
|
-
|
|
926
|
-
#### onNodeDrop(dropNode, draggedNode, position, event, operation)
|
|
927
|
-
Triggered when a node is dropped. For same-tree moves, the tree auto-handles the move and this callback is for notification.
|
|
928
|
-
- `position`: 'above', 'below', or 'child'
|
|
929
|
-
- `operation`: 'move' or 'copy' (Ctrl+drag)
|
|
930
|
-
|
|
931
|
-
### Slots
|
|
932
|
-
|
|
933
|
-
#### nodeTemplate
|
|
934
|
-
Custom template for rendering node content.
|
|
935
|
-
|
|
936
|
-
```svelte
|
|
937
|
-
{#snippet nodeTemplate(node)}
|
|
938
|
-
<!-- Your custom node content -->
|
|
939
|
-
{/snippet}
|
|
940
|
-
```
|
|
941
|
-
|
|
942
|
-
#### contextMenu
|
|
943
|
-
Custom context menu template (snippet-based approach).
|
|
944
|
-
|
|
945
|
-
```svelte
|
|
946
|
-
{#snippet contextMenu(node, closeMenu)}
|
|
947
|
-
<button onclick={() => { /* action */ closeMenu(); }}>
|
|
948
|
-
Action
|
|
949
|
-
</button>
|
|
950
|
-
{/snippet}
|
|
951
|
-
```
|
|
952
|
-
|
|
953
|
-
### Context Menu Properties
|
|
954
|
-
|
|
955
|
-
#### contextMenuCallback
|
|
956
|
-
Function that generates context menu items dynamically.
|
|
957
|
-
|
|
958
|
-
```typescript
|
|
959
|
-
contextMenuCallback: (node: LTreeNode<T>) => ContextMenuItem[]
|
|
960
|
-
```
|
|
961
|
-
|
|
962
|
-
Where `ContextMenuItem` is:
|
|
963
|
-
```typescript
|
|
964
|
-
interface ContextMenuItem {
|
|
965
|
-
icon?: string; // Optional icon (emoji or text)
|
|
966
|
-
title: string; // Menu item text
|
|
967
|
-
isDisabled?: boolean; // Whether item is disabled
|
|
968
|
-
callback: () => void; // Action to perform
|
|
969
|
-
isDivider?: boolean; // Render as divider instead of item
|
|
970
|
-
}
|
|
971
|
-
```
|
|
972
|
-
|
|
973
|
-
#### contextMenuXOffset
|
|
974
|
-
Horizontal offset from cursor position (default: 8px).
|
|
975
|
-
|
|
976
|
-
#### contextMenuYOffset
|
|
977
|
-
Vertical offset from cursor position (default: 0px).
|
|
978
|
-
|
|
979
|
-
#### shouldDisplayContextMenuInDebugMode
|
|
980
|
-
When enabled, displays a persistent context menu at a fixed position for styling development (default: false).
|
|
981
|
-
|
|
982
|
-
```svelte
|
|
983
|
-
<Tree
|
|
984
|
-
{data}
|
|
985
|
-
contextMenuCallback={createContextMenu}
|
|
986
|
-
shouldDisplayContextMenuInDebugMode={true}
|
|
987
|
-
shouldDisplayDebugInformation={true}
|
|
988
|
-
contextMenuXOffset={10}
|
|
989
|
-
contextMenuYOffset={5}
|
|
990
|
-
/>
|
|
991
|
-
```
|
|
992
|
-
|
|
993
|
-
**Debug Mode Features:**
|
|
994
|
-
- Shows context menu for the second node (or first if only one exists)
|
|
995
|
-
- Positions menu 200px right and 100px down from tree's top-left corner
|
|
996
|
-
- Persistent display - no need to right-click repeatedly
|
|
997
|
-
- Perfect for CSS styling and position testing
|
|
998
|
-
- Works with both callback-based and snippet-based context menus
|
|
999
|
-
|
|
1000
|
-
## 🏗️ Data Structure
|
|
929
|
+
## Data Structure
|
|
1001
930
|
|
|
1002
931
|
The component expects hierarchical data with path-based organization:
|
|
1003
932
|
|
|
@@ -1057,21 +986,21 @@ interface InsertArrayResult<T> {
|
|
|
1057
986
|
```svelte
|
|
1058
987
|
<script lang="ts">
|
|
1059
988
|
import { Tree } from '@keenmate/svelte-treeview';
|
|
1060
|
-
|
|
989
|
+
|
|
1061
990
|
let insertResult = $state();
|
|
1062
|
-
|
|
991
|
+
|
|
1063
992
|
const data = [
|
|
1064
993
|
{ id: '1', path: '1', name: 'Root' },
|
|
1065
994
|
{ id: '1.2', path: '1.2', name: 'Child' }, // Missing parent "1.1"
|
|
1066
995
|
{ id: '1.1.1', path: '1.1.1', name: 'Deep' } // Missing parent "1.1"
|
|
1067
996
|
];
|
|
1068
|
-
|
|
997
|
+
|
|
1069
998
|
// Check results after tree processes data
|
|
1070
999
|
$effect(() => {
|
|
1071
1000
|
if (insertResult) {
|
|
1072
|
-
console.log(
|
|
1073
|
-
console.log(
|
|
1074
|
-
|
|
1001
|
+
console.log(`${insertResult.successful} nodes inserted successfully`);
|
|
1002
|
+
console.log(`${insertResult.failed.length} nodes failed to insert`);
|
|
1003
|
+
|
|
1075
1004
|
insertResult.failed.forEach(failure => {
|
|
1076
1005
|
console.log(`Failed: ${failure.originalData.name} - ${failure.error}`);
|
|
1077
1006
|
});
|
|
@@ -1079,10 +1008,10 @@ interface InsertArrayResult<T> {
|
|
|
1079
1008
|
});
|
|
1080
1009
|
</script>
|
|
1081
1010
|
|
|
1082
|
-
<Tree
|
|
1083
|
-
{data}
|
|
1084
|
-
idMember="id"
|
|
1085
|
-
pathMember="path"
|
|
1011
|
+
<Tree
|
|
1012
|
+
{data}
|
|
1013
|
+
idMember="id"
|
|
1014
|
+
pathMember="path"
|
|
1086
1015
|
displayValueMember="name"
|
|
1087
1016
|
bind:insertResult
|
|
1088
1017
|
/>
|
|
@@ -1096,7 +1025,7 @@ interface InsertArrayResult<T> {
|
|
|
1096
1025
|
- **Search Accuracy**: Failed nodes are excluded from search index, ensuring search results match visible tree
|
|
1097
1026
|
- **User Feedback**: Inform users about data issues with detailed failure information
|
|
1098
1027
|
|
|
1099
|
-
##
|
|
1028
|
+
## Performance
|
|
1100
1029
|
|
|
1101
1030
|
The component is optimized for large datasets:
|
|
1102
1031
|
|
|
@@ -1138,20 +1067,34 @@ enablePerfLogging();
|
|
|
1138
1067
|
window.components['svelte-treeview'].perf.enable()
|
|
1139
1068
|
```
|
|
1140
1069
|
|
|
1141
|
-
**Important**: See the [$state.raw()
|
|
1070
|
+
**Important**: See the [$state.raw() tip](#quick-start) above - using `$state()` instead of `$state.raw()` for tree data can cause 5,000x slowdown!
|
|
1071
|
+
|
|
1072
|
+
## Development Setup & Contributing
|
|
1142
1073
|
|
|
1143
|
-
|
|
1074
|
+
For developers working on the project, you can use either standard npm commands or the provided Makefile:
|
|
1075
|
+
|
|
1076
|
+
```bash
|
|
1077
|
+
# Using Makefile (recommended for consistency)
|
|
1078
|
+
make setup # or make install
|
|
1079
|
+
make dev
|
|
1080
|
+
|
|
1081
|
+
# Or using standard npm commands
|
|
1082
|
+
npm install
|
|
1083
|
+
npm run dev
|
|
1084
|
+
```
|
|
1144
1085
|
|
|
1145
1086
|
We welcome contributions! Please see our contributing guidelines for details.
|
|
1146
1087
|
|
|
1147
|
-
|
|
1088
|
+
> **For AI Agents / LLMs**: Comprehensive documentation is available in the `ai/` folder with topic-specific files (basic-setup.txt, drag-drop.txt, performance.txt, etc.). Start with `ai/INDEX.txt` for navigation.
|
|
1089
|
+
|
|
1090
|
+
## License
|
|
1148
1091
|
|
|
1149
1092
|
MIT License - see LICENSE file for details.
|
|
1150
1093
|
|
|
1151
|
-
##
|
|
1094
|
+
## Support
|
|
1152
1095
|
|
|
1153
1096
|
- **GitHub Issues**: [Report bugs or request features](https://github.com/keenmate/svelte-treeview/issues)
|
|
1154
|
-
- **
|
|
1097
|
+
- **Live demo & docs**: [svelte-treeview.keenmate.dev](https://svelte-treeview.keenmate.dev)
|
|
1155
1098
|
|
|
1156
1099
|
---
|
|
1157
1100
|
|