@keenmate/svelte-treeview 4.8.0 → 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.
Files changed (51) hide show
  1. package/README.md +106 -117
  2. package/ai/INDEX.txt +310 -0
  3. package/ai/advanced-patterns.txt +506 -0
  4. package/ai/basic-setup.txt +336 -0
  5. package/ai/context-menu.txt +349 -0
  6. package/ai/data-handling.txt +390 -0
  7. package/ai/drag-drop.txt +397 -0
  8. package/ai/events-callbacks.txt +382 -0
  9. package/ai/import-patterns.txt +271 -0
  10. package/ai/performance.txt +349 -0
  11. package/ai/search-features.txt +359 -0
  12. package/ai/styling-theming.txt +354 -0
  13. package/ai/tree-editing.txt +423 -0
  14. package/ai/typescript-types.txt +357 -0
  15. package/dist/components/Node.svelte +47 -40
  16. package/dist/components/Node.svelte.d.ts +1 -1
  17. package/dist/components/Tree.svelte +384 -1479
  18. package/dist/components/Tree.svelte.d.ts +30 -28
  19. package/dist/components/TreeProvider.svelte +28 -0
  20. package/dist/components/TreeProvider.svelte.d.ts +28 -0
  21. package/dist/constants.generated.d.ts +1 -1
  22. package/dist/constants.generated.js +1 -1
  23. package/dist/core/TreeController.svelte.d.ts +353 -0
  24. package/dist/core/TreeController.svelte.js +1503 -0
  25. package/dist/core/createTreeController.d.ts +9 -0
  26. package/dist/core/createTreeController.js +11 -0
  27. package/dist/global-api.d.ts +1 -1
  28. package/dist/global-api.js +5 -5
  29. package/dist/index.d.ts +10 -6
  30. package/dist/index.js +7 -3
  31. package/dist/logger.d.ts +7 -6
  32. package/dist/logger.js +0 -2
  33. package/dist/ltree/indexer.js +2 -4
  34. package/dist/ltree/ltree-node.svelte.d.ts +2 -1
  35. package/dist/ltree/ltree-node.svelte.js +1 -0
  36. package/dist/ltree/ltree.svelte.d.ts +1 -1
  37. package/dist/ltree/ltree.svelte.js +168 -175
  38. package/dist/ltree/types.d.ts +12 -8
  39. package/dist/perf-logger.d.ts +2 -1
  40. package/dist/perf-logger.js +0 -2
  41. package/dist/styles/main.scss +78 -78
  42. package/dist/styles.css +41 -41
  43. package/dist/styles.css.map +1 -1
  44. package/dist/vendor/loglevel/index.d.ts +55 -2
  45. package/dist/vendor/loglevel/prefix.d.ts +23 -2
  46. package/package.json +96 -95
  47. package/dist/ltree/ltree-demo.d.ts +0 -2
  48. package/dist/ltree/ltree-demo.js +0 -90
  49. package/dist/vendor/loglevel/loglevel-esm.d.ts +0 -2
  50. package/dist/vendor/loglevel/loglevel-plugin-prefix-esm.d.ts +0 -7
  51. package/dist/vendor/loglevel/loglevel-plugin-prefix.d.ts +0 -2
@@ -1,6 +1,6 @@
1
1
  import type { SearchOptions } from 'flexsearch';
2
- import type { LTreeNode, DropPosition } from './ltree-node.svelte';
3
- export type { LTreeNode, DropPosition } from './ltree-node.svelte';
2
+ import type { LTreeNode, DropPosition } from './ltree-node.svelte.js';
3
+ export type { LTreeNode, DropPosition } from './ltree-node.svelte.js';
4
4
  export type Tuple<T, U> = [T, U];
5
5
  export type DragDropMode = 'none' | 'self' | 'cross' | 'both';
6
6
  export type DropZoneLayout = 'around' | 'above' | 'below' | 'wave' | 'wave2';
@@ -67,17 +67,25 @@ export interface Ltree<T> {
67
67
  isFiltered: boolean;
68
68
  isSelectableMember: string | null | undefined;
69
69
  isDraggableMember: string | null | undefined;
70
+ getIsDraggableCallback?: (node: LTreeNode<T>) => boolean;
70
71
  isDropAllowedMember: string | null | undefined;
71
72
  allowedDropPositionsMember: string | null | undefined;
72
73
  getAllowedDropPositionsCallback?: (node: LTreeNode<T>) => DropPosition[] | null | undefined;
74
+ isCollapsibleMember: string | null | undefined;
75
+ getIsCollapsibleCallback?: (node: LTreeNode<T>) => boolean;
73
76
  shouldDisplayDebugInformation: boolean | null | undefined;
74
77
  getNodeAllowedDropPositions(node: LTreeNode<T>): DropPosition[] | null | undefined;
78
+ getNodeIsDraggable(node: LTreeNode<T>): boolean;
79
+ getNodeIsCollapsible(node: LTreeNode<T>): boolean;
75
80
  get tree(): LTreeNode<T>[];
76
81
  /** Flat array of all visible nodes in render order (depth-first, respects isExpanded) */
77
82
  get visibleFlatNodes(): LTreeNode<T>[];
78
83
  get statistics(): {
79
84
  nodeCount: number;
80
85
  maxLevel: number;
86
+ filteredNodeCount: number;
87
+ isIndexing: boolean;
88
+ pendingIndexCount: number;
81
89
  };
82
90
  insertArray(data: T[]): InsertArrayResult<T>;
83
91
  insertTreeNode(parentPath: string, newNode: LTreeNode<T>, noEmitChanges?: boolean): string | null;
@@ -100,11 +108,7 @@ export interface Ltree<T> {
100
108
  getSiblings(path: string): LTreeNode<T>[];
101
109
  refreshSiblings(parentPath: string): void;
102
110
  refreshNode(path: string): void;
103
- bumpNodeRev(node: LTreeNode<T>): void;
104
- getNodeSignal(id: string): {
105
- readonly value: number;
106
- } | undefined;
107
- moveNode(sourcePath: string, targetPath: string, position: 'above' | 'below' | 'child'): {
111
+ moveNode(sourcePath: string, targetPath: string, position: 'before' | 'after' | 'child'): {
108
112
  success: boolean;
109
113
  error?: string;
110
114
  };
@@ -124,7 +128,7 @@ export interface Ltree<T> {
124
128
  error?: string;
125
129
  };
126
130
  applyChanges(changes: TreeChange<T>[]): ApplyChangesResult;
127
- copyNodeWithDescendants(sourceNode: LTreeNode<T>, targetParentPath: string, transformData: (data: T) => T, siblingPath?: string, position?: 'above' | 'below'): {
131
+ copyNodeWithDescendants(sourceNode: LTreeNode<T>, targetParentPath: string, transformData: (data: T) => T, siblingPath?: string, position?: 'before' | 'after'): {
128
132
  success: boolean;
129
133
  rootNode?: LTreeNode<T>;
130
134
  count: number;
@@ -17,7 +17,8 @@
17
17
  * // Or set minimum threshold (only log operations slower than X ms)
18
18
  * setPerfThreshold(10); // Only log operations taking >10ms
19
19
  */
20
- export declare const perfLogger: any;
20
+ import type { Logger } from './vendor/loglevel/index.js';
21
+ export declare const perfLogger: Logger;
21
22
  /**
22
23
  * Start a performance timer
23
24
  * @param label - Unique label for the timer
@@ -17,9 +17,7 @@
17
17
  * // Or set minimum threshold (only log operations slower than X ms)
18
18
  * setPerfThreshold(10); // Only log operations taking >10ms
19
19
  */
20
- // @ts-ignore - Vendored library without type definitions
21
20
  import log from './vendor/loglevel/index.js';
22
- // @ts-ignore - Vendored library without type definitions
23
21
  import prefix from './vendor/loglevel/prefix.js';
24
22
  // Performance logger instance
25
23
  export const perfLogger = log.getLogger('LTREE:PERF');
@@ -25,19 +25,19 @@ $tree-children-margin-top: 2px !default;
25
25
  // Drop Zone Variables
26
26
  $drop-zone-border-radius: 0 !default;
27
27
 
28
- // Above zone (soft sage green)
29
- $drop-zone-above-bg: rgba(134, 179, 152, 0.25) !default;
30
- $drop-zone-above-color: rgba(62, 89, 72, 0.7) !default;
31
- $drop-zone-above-active-bg: rgba(134, 179, 152, 0.85) !default;
32
- $drop-zone-above-active-color: rgb(32, 54, 40) !default;
33
- $drop-zone-above-active-shadow: 0 2px 12px rgba(134, 179, 152, 0.4) !default;
34
-
35
- // Below zone (soft peach/coral)
36
- $drop-zone-below-bg: rgba(242, 182, 158, 0.25) !default;
37
- $drop-zone-below-color: rgba(120, 70, 50, 0.7) !default;
38
- $drop-zone-below-active-bg: rgba(242, 182, 158, 0.85) !default;
39
- $drop-zone-below-active-color: rgb(80, 45, 30) !default;
40
- $drop-zone-below-active-shadow: 0 2px 12px rgba(242, 182, 158, 0.4) !default;
28
+ // Before zone (soft sage green)
29
+ $drop-zone-before-bg: rgba(134, 179, 152, 0.25) !default;
30
+ $drop-zone-before-color: rgba(62, 89, 72, 0.7) !default;
31
+ $drop-zone-before-active-bg: rgba(134, 179, 152, 0.85) !default;
32
+ $drop-zone-before-active-color: rgb(32, 54, 40) !default;
33
+ $drop-zone-before-active-shadow: 0 2px 12px rgba(134, 179, 152, 0.4) !default;
34
+
35
+ // After zone (soft peach/coral)
36
+ $drop-zone-after-bg: rgba(242, 182, 158, 0.25) !default;
37
+ $drop-zone-after-color: rgba(120, 70, 50, 0.7) !default;
38
+ $drop-zone-after-active-bg: rgba(242, 182, 158, 0.85) !default;
39
+ $drop-zone-after-active-color: rgb(80, 45, 30) !default;
40
+ $drop-zone-after-active-shadow: 0 2px 12px rgba(242, 182, 158, 0.4) !default;
41
41
 
42
42
  // Child zone (soft lavender)
43
43
  $drop-zone-child-bg: rgba(167, 155, 198, 0.25) !default;
@@ -47,20 +47,20 @@ $drop-zone-child-active-color: rgb(45, 38, 62) !default;
47
47
  $drop-zone-child-active-shadow: 0 2px 12px rgba(167, 155, 198, 0.4) !default;
48
48
 
49
49
  // Border glow drop indicators (for glow mode)
50
- $drop-glow-above-color: rgba(134, 179, 152, 0.8) !default;
51
- $drop-glow-below-color: rgba(242, 182, 158, 0.8) !default;
50
+ $drop-glow-before-color: rgba(134, 179, 152, 0.8) !default;
51
+ $drop-glow-after-color: rgba(242, 182, 158, 0.8) !default;
52
52
  $drop-glow-child-color: rgba(167, 155, 198, 0.8) !default;
53
53
  $drop-glow-child-bg: rgba(167, 155, 198, 0.15) !default;
54
54
  $drop-glow-size: 3px !default;
55
55
 
56
56
  // Drop indicator arrows (Lucide icons as data URIs)
57
- $drop-arrow-above: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2386b398' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 13a1 1 0 0 0-1-1H5.061a1 1 0 0 1-.75-1.811l6.836-6.835a1.207 1.207 0 0 1 1.707 0l6.835 6.835a1 1 0 0 1-.75 1.811H16a1 1 0 0 0-1 1v6a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1z'/%3E%3C/svg%3E") !default;
58
- $drop-arrow-below: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23f2b69e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 11a1 1 0 0 0 1 1h2.939a1 1 0 0 1 .75 1.811l-6.835 6.836a1.207 1.207 0 0 1-1.707 0L4.31 13.81a1 1 0 0 1 .75-1.811H8a1 1 0 0 0 1-1V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1z'/%3E%3C/svg%3E") !default;
57
+ $drop-arrow-before: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2386b398' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 13a1 1 0 0 0-1-1H5.061a1 1 0 0 1-.75-1.811l6.836-6.835a1.207 1.207 0 0 1 1.707 0l6.835 6.835a1 1 0 0 1-.75 1.811H16a1 1 0 0 0-1 1v6a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1z'/%3E%3C/svg%3E") !default;
58
+ $drop-arrow-after: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23f2b69e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 11a1 1 0 0 0 1 1h2.939a1 1 0 0 1 .75 1.811l-6.835 6.836a1.207 1.207 0 0 1-1.707 0L4.31 13.81a1 1 0 0 1 .75-1.811H8a1 1 0 0 0 1-1V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1z'/%3E%3C/svg%3E") !default;
59
59
  $drop-arrow-child: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23a79bc6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11 9a1 1 0 0 0 1-1V5.061a1 1 0 0 1 1.811-.75l6.836 6.836a1.207 1.207 0 0 1 0 1.707l-6.836 6.835a1 1 0 0 1-1.811-.75V16a1 1 0 0 0-1-1H9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1z'/%3E%3Cpath d='M4 9v6'/%3E%3C/svg%3E") !default;
60
60
  $drop-arrow-size: 24px !default;
61
61
  $drop-arrow-position: 66% !default;
62
- $drop-arrow-above-rotation: 0deg !default;
63
- $drop-arrow-below-rotation: 0deg !default;
62
+ $drop-arrow-before-rotation: 0deg !default;
63
+ $drop-arrow-after-rotation: 0deg !default;
64
64
  $drop-arrow-child-rotation: 45deg !default;
65
65
 
66
66
  // Color variables for selected states and drag/drop
@@ -77,27 +77,27 @@ $body-color: #212529 !default;
77
77
  // Mixin: expand horizontal zone layout when zones are hidden (used by "above" and "below" layouts)
78
78
  @mixin zone-horizontal-expansion {
79
79
  // Two zones: first present zone gets left half
80
- &:not(:has(.ltree-drop-child)) .ltree-drop-above,
81
- &:not(:has(.ltree-drop-below)) .ltree-drop-above,
82
- &:not(:has(.ltree-drop-above)) .ltree-drop-below {
80
+ &:not(:has(.ltree-drop-child)) .ltree-drop-before,
81
+ &:not(:has(.ltree-drop-after)) .ltree-drop-before,
82
+ &:not(:has(.ltree-drop-before)) .ltree-drop-after {
83
83
  left: var(--drop-zone-start, 33%);
84
84
  right: calc((100% - var(--drop-zone-start, 33%)) / 2);
85
85
  border-radius: $drop-zone-border-radius 0 0 $drop-zone-border-radius;
86
86
  }
87
87
 
88
88
  // Two zones: second present zone gets right half
89
- &:not(:has(.ltree-drop-child)) .ltree-drop-below,
90
- &:not(:has(.ltree-drop-below)) .ltree-drop-child,
91
- &:not(:has(.ltree-drop-above)) .ltree-drop-child {
89
+ &:not(:has(.ltree-drop-child)) .ltree-drop-after,
90
+ &:not(:has(.ltree-drop-after)) .ltree-drop-child,
91
+ &:not(:has(.ltree-drop-before)) .ltree-drop-child {
92
92
  left: calc(var(--drop-zone-start, 33%) + (100% - var(--drop-zone-start, 33%)) / 2);
93
93
  right: 0;
94
94
  border-radius: 0 $drop-zone-border-radius $drop-zone-border-radius 0;
95
95
  }
96
96
 
97
97
  // Single zone: full width
98
- &:not(:has(.ltree-drop-below)):not(:has(.ltree-drop-child)) .ltree-drop-above,
99
- &:not(:has(.ltree-drop-above)):not(:has(.ltree-drop-child)) .ltree-drop-below,
100
- &:not(:has(.ltree-drop-above)):not(:has(.ltree-drop-below)) .ltree-drop-child {
98
+ &:not(:has(.ltree-drop-after)):not(:has(.ltree-drop-child)) .ltree-drop-before,
99
+ &:not(:has(.ltree-drop-before)):not(:has(.ltree-drop-child)) .ltree-drop-after,
100
+ &:not(:has(.ltree-drop-before)):not(:has(.ltree-drop-after)) .ltree-drop-child {
101
101
  left: var(--drop-zone-start, 33%);
102
102
  right: 0;
103
103
  border-radius: $drop-zone-border-radius;
@@ -133,15 +133,8 @@ $body-color: #212529 !default;
133
133
  }
134
134
  }
135
135
 
136
- // Virtual scroll container
137
- .ltree-virtual-scroll {
138
- overflow-y: auto !important;
139
- overflow-x: visible;
140
- overscroll-behavior: contain;
141
- }
142
-
143
136
  // Ensure all tree ancestors allow overflow for drop zones
144
- .ltree-tree:not(.ltree-virtual-scroll),
137
+ .ltree-tree,
145
138
  .ltree-node,
146
139
  .ltree-node-row,
147
140
  .ltree-children {
@@ -181,9 +174,9 @@ $body-color: #212529 !default;
181
174
  }
182
175
 
183
176
  // Border glow drop indicators (glow mode)
184
- &.ltree-glow-above {
177
+ &.ltree-glow-before {
185
178
  border-radius: 0 !important;
186
- box-shadow: inset 0 $drop-glow-size 0 0 $drop-glow-above-color;
179
+ box-shadow: inset 0 $drop-glow-size 0 0 $drop-glow-before-color;
187
180
 
188
181
  // Arrow indicator
189
182
  &::after {
@@ -191,10 +184,10 @@ $body-color: #212529 !default;
191
184
  position: absolute;
192
185
  left: $drop-arrow-position;
193
186
  top: 50%;
194
- transform: translate(-50%, -50%) rotate($drop-arrow-above-rotation);
187
+ transform: translate(-50%, -50%) rotate($drop-arrow-before-rotation);
195
188
  width: $drop-arrow-size;
196
189
  height: $drop-arrow-size;
197
- background-image: $drop-arrow-above;
190
+ background-image: $drop-arrow-before;
198
191
  background-repeat: no-repeat;
199
192
  background-size: contain;
200
193
  pointer-events: none;
@@ -202,9 +195,9 @@ $body-color: #212529 !default;
202
195
  }
203
196
  }
204
197
 
205
- &.ltree-glow-below {
198
+ &.ltree-glow-after {
206
199
  border-radius: 0 !important;
207
- box-shadow: inset 0 (-$drop-glow-size) 0 0 $drop-glow-below-color;
200
+ box-shadow: inset 0 (-$drop-glow-size) 0 0 $drop-glow-after-color;
208
201
 
209
202
  // Arrow indicator
210
203
  &::after {
@@ -212,10 +205,10 @@ $body-color: #212529 !default;
212
205
  position: absolute;
213
206
  left: $drop-arrow-position;
214
207
  top: 50%;
215
- transform: translate(-50%, -50%) rotate($drop-arrow-below-rotation);
208
+ transform: translate(-50%, -50%) rotate($drop-arrow-after-rotation);
216
209
  width: $drop-arrow-size;
217
210
  height: $drop-arrow-size;
218
- background-image: $drop-arrow-below;
211
+ background-image: $drop-arrow-after;
219
212
  background-repeat: no-repeat;
220
213
  background-size: contain;
221
214
  pointer-events: none;
@@ -616,7 +609,7 @@ $body-color: #212529 !default;
616
609
  }
617
610
 
618
611
  // Drop Zone Container - wraps all zones with CSS variable for start position
619
- // Position is set inline (fixed) by Tree.svelte for the floating overlay
612
+ // Positioning is handled by inline styles (position:fixed from Tree.svelte)
620
613
  .ltree-drop-zones {
621
614
  pointer-events: none; // Let children handle pointer events
622
615
  overflow: visible;
@@ -638,26 +631,26 @@ $body-color: #212529 !default;
638
631
  border-radius: $drop-zone-border-radius;
639
632
 
640
633
  // Above zone (green)
641
- &.ltree-drop-above {
642
- background: $drop-zone-above-bg;
643
- color: $drop-zone-above-color;
634
+ &.ltree-drop-before {
635
+ background: $drop-zone-before-bg;
636
+ color: $drop-zone-before-color;
644
637
 
645
638
  &.ltree-drop-zone-active {
646
- background: $drop-zone-above-active-bg;
647
- color: $drop-zone-above-active-color;
648
- box-shadow: $drop-zone-above-active-shadow;
639
+ background: $drop-zone-before-active-bg;
640
+ color: $drop-zone-before-active-color;
641
+ box-shadow: $drop-zone-before-active-shadow;
649
642
  }
650
643
  }
651
644
 
652
645
  // Below zone (yellow)
653
- &.ltree-drop-below {
654
- background: $drop-zone-below-bg;
655
- color: $drop-zone-below-color;
646
+ &.ltree-drop-after {
647
+ background: $drop-zone-after-bg;
648
+ color: $drop-zone-after-color;
656
649
 
657
650
  &.ltree-drop-zone-active {
658
- background: $drop-zone-below-active-bg;
659
- color: $drop-zone-below-active-color;
660
- box-shadow: $drop-zone-below-active-shadow;
651
+ background: $drop-zone-after-active-bg;
652
+ color: $drop-zone-after-active-color;
653
+ box-shadow: $drop-zone-after-active-shadow;
661
654
  }
662
655
  }
663
656
 
@@ -676,7 +669,7 @@ $body-color: #212529 !default;
676
669
 
677
670
  // Layout: "around" - Above on top, Below/Child on bottom (default)
678
671
  .ltree-drop-zones-around {
679
- .ltree-drop-above {
672
+ .ltree-drop-before {
680
673
  top: 0;
681
674
  left: var(--drop-zone-start, 33%);
682
675
  right: 0;
@@ -684,7 +677,7 @@ $body-color: #212529 !default;
684
677
  // border-radius: 4px 4px 0 0;
685
678
  }
686
679
 
687
- .ltree-drop-below {
680
+ .ltree-drop-after {
688
681
  bottom: 0;
689
682
  left: var(--drop-zone-start, 33%);
690
683
  // Middle third of available space
@@ -703,30 +696,30 @@ $body-color: #212529 !default;
703
696
  }
704
697
 
705
698
  // Zone expansion: when a zone is hidden, remaining zones fill the gap
706
- &:not(:has(.ltree-drop-child)) .ltree-drop-below {
699
+ &:not(:has(.ltree-drop-child)) .ltree-drop-after {
707
700
  right: 0;
708
701
  }
709
- &:not(:has(.ltree-drop-below)) .ltree-drop-child {
702
+ &:not(:has(.ltree-drop-after)) .ltree-drop-child {
710
703
  left: var(--drop-zone-start, 33%);
711
704
  }
712
705
  }
713
706
 
714
707
  // Layout: "above" - All 3 zones in a row above the node
715
708
  .ltree-drop-zones-above {
716
- .ltree-drop-above,
717
- .ltree-drop-below,
709
+ .ltree-drop-before,
710
+ .ltree-drop-after,
718
711
  .ltree-drop-child {
719
712
  top: 0;
720
713
  transform: translateY(-100%);
721
714
  }
722
715
 
723
- .ltree-drop-above {
716
+ .ltree-drop-before {
724
717
  left: var(--drop-zone-start, 33%);
725
718
  right: calc((100% - var(--drop-zone-start, 33%)) * 2 / 3);
726
719
  border-radius: $drop-zone-border-radius 0 0 $drop-zone-border-radius;
727
720
  }
728
721
 
729
- .ltree-drop-below {
722
+ .ltree-drop-after {
730
723
  left: calc(var(--drop-zone-start, 33%) + (100% - var(--drop-zone-start, 33%)) / 3);
731
724
  right: calc((100% - var(--drop-zone-start, 33%)) / 3);
732
725
  border-radius: 0;
@@ -744,20 +737,20 @@ $body-color: #212529 !default;
744
737
 
745
738
  // Layout: "below" - All 3 zones in a row below the node
746
739
  .ltree-drop-zones-below {
747
- .ltree-drop-above,
748
- .ltree-drop-below,
740
+ .ltree-drop-before,
741
+ .ltree-drop-after,
749
742
  .ltree-drop-child {
750
743
  bottom: 0;
751
744
  transform: translateY(100%);
752
745
  }
753
746
 
754
- .ltree-drop-above {
747
+ .ltree-drop-before {
755
748
  left: var(--drop-zone-start, 33%);
756
749
  right: calc((100% - var(--drop-zone-start, 33%)) * 2 / 3);
757
750
  border-radius: $drop-zone-border-radius 0 0 $drop-zone-border-radius;
758
751
  }
759
752
 
760
- .ltree-drop-below {
753
+ .ltree-drop-after {
761
754
  left: calc(var(--drop-zone-start, 33%) + (100% - var(--drop-zone-start, 33%)) / 3);
762
755
  right: calc((100% - var(--drop-zone-start, 33%)) / 3);
763
756
  border-radius: 0;
@@ -773,10 +766,10 @@ $body-color: #212529 !default;
773
766
  @include zone-horizontal-expansion;
774
767
  }
775
768
 
776
- // Layout: "wave" - Zones stacked vertically (above/child/below)
769
+ // Layout: "wave" - Zones stacked vertically (before/child/after)
777
770
  .ltree-drop-zones-wave {
778
- .ltree-drop-above,
779
- .ltree-drop-below,
771
+ .ltree-drop-before,
772
+ .ltree-drop-after,
780
773
  .ltree-drop-child {
781
774
  left: var(--drop-zone-start, 33%);
782
775
  right: auto;
@@ -786,7 +779,7 @@ $body-color: #212529 !default;
786
779
  transform: none;
787
780
  }
788
781
 
789
- .ltree-drop-above {
782
+ .ltree-drop-before {
790
783
  top: 0;
791
784
  bottom: auto;
792
785
  transform: translateY(-100%);
@@ -799,7 +792,7 @@ $body-color: #212529 !default;
799
792
  border-radius: 0;
800
793
  }
801
794
 
802
- .ltree-drop-below {
795
+ .ltree-drop-after {
803
796
  top: auto;
804
797
  bottom: 0;
805
798
  transform: translateY(100%);
@@ -810,8 +803,8 @@ $body-color: #212529 !default;
810
803
  // Layout: "wave2" - Diagonal wave pattern
811
804
  // Above and Below are offset 7% to the left, Child stays at dropZoneStart
812
805
  .ltree-drop-zones-wave2 {
813
- .ltree-drop-above,
814
- .ltree-drop-below,
806
+ .ltree-drop-before,
807
+ .ltree-drop-after,
815
808
  .ltree-drop-child {
816
809
  right: auto;
817
810
  width: var(--drop-zone-max-width, 120px);
@@ -819,7 +812,7 @@ $body-color: #212529 !default;
819
812
  height: auto;
820
813
  }
821
814
 
822
- .ltree-drop-above {
815
+ .ltree-drop-before {
823
816
  left: calc(var(--drop-zone-start, 33%) - 7%);
824
817
  top: 10%;
825
818
  bottom: auto;
@@ -835,7 +828,7 @@ $body-color: #212529 !default;
835
828
  border-radius: 0;
836
829
  }
837
830
 
838
- .ltree-drop-below {
831
+ .ltree-drop-after {
839
832
  left: calc(var(--drop-zone-start, 33%) - 7%);
840
833
  top: auto;
841
834
  bottom: 10%;
@@ -856,6 +849,13 @@ $body-color: #212529 !default;
856
849
  color: var(--ltree-body-color);
857
850
  }
858
851
 
852
+ // Virtual scroll container
853
+ .ltree-virtual-scroll {
854
+ overflow-y: auto !important;
855
+ overflow-x: visible;
856
+ overscroll-behavior: contain;
857
+ }
858
+
859
859
  // Tree Container
860
860
  .ltree-container {
861
861
  position: relative;