@keenmate/svelte-treeview 4.2.0 → 4.3.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/README.md +22 -0
- package/dist/components/Tree.svelte +32 -20
- package/dist/components/Tree.svelte.d.ts +3 -1
- package/dist/ltree/types.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -512,6 +512,7 @@ Without both requirements, no search indexing will occur.
|
|
|
512
512
|
| `indexerBatchSize` | `number \| null` | `25` | Number of nodes to process per batch during search indexing |
|
|
513
513
|
| `indexerTimeout` | `number \| null` | `50` | Maximum time (ms) to wait for idle callback before forcing indexing |
|
|
514
514
|
| `shouldDisplayDebugInformation` | `boolean` | `false` | Show debug information panel with tree statistics and enable console debug logging for tree operations and async search indexing |
|
|
515
|
+
| `shouldDisplayContextMenuInDebugMode` | `boolean` | `false` | Display persistent context menu at fixed position for styling development |
|
|
515
516
|
|
|
516
517
|
#### Event Handler Properties
|
|
517
518
|
| Prop | Type | Default | Description |
|
|
@@ -732,6 +733,27 @@ Horizontal offset from cursor position (default: 8px).
|
|
|
732
733
|
#### contextMenuYOffset
|
|
733
734
|
Vertical offset from cursor position (default: 0px).
|
|
734
735
|
|
|
736
|
+
#### shouldDisplayContextMenuInDebugMode
|
|
737
|
+
When enabled, displays a persistent context menu at a fixed position for styling development (default: false).
|
|
738
|
+
|
|
739
|
+
```svelte
|
|
740
|
+
<Tree
|
|
741
|
+
{data}
|
|
742
|
+
contextMenuCallback={createContextMenu}
|
|
743
|
+
shouldDisplayContextMenuInDebugMode={true}
|
|
744
|
+
shouldDisplayDebugInformation={true}
|
|
745
|
+
contextMenuXOffset={10}
|
|
746
|
+
contextMenuYOffset={5}
|
|
747
|
+
/>
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**Debug Mode Features:**
|
|
751
|
+
- Shows context menu for the second node (or first if only one exists)
|
|
752
|
+
- Positions menu 200px right and 100px down from tree's top-left corner
|
|
753
|
+
- Persistent display - no need to right-click repeatedly
|
|
754
|
+
- Perfect for CSS styling and position testing
|
|
755
|
+
- Works with both callback-based and snippet-based context menus
|
|
756
|
+
|
|
735
757
|
## 🏗️ Data Structure
|
|
736
758
|
|
|
737
759
|
The component expects hierarchical data with path-based organization:
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
onNodeDragStart?: (node: LTreeNode<T>, event: DragEvent) => void;
|
|
70
70
|
onNodeDragOver?: (node: LTreeNode<T>, event: DragEvent) => void;
|
|
71
71
|
onNodeDrop?: (node: LTreeNode<T>, draggedNode: LTreeNode<T>, event: DragEvent) => void;
|
|
72
|
-
contextMenuCallback?: (node: LTreeNode<T
|
|
72
|
+
contextMenuCallback?: (node: LTreeNode<T>, closeMenuCallback: () => void) => ContextMenuItem[];
|
|
73
73
|
|
|
74
74
|
// VISUALS
|
|
75
75
|
bodyClass?: string | null | undefined;
|
|
@@ -178,6 +178,13 @@
|
|
|
178
178
|
return tree?.searchNodes(searchText, searchOptions) || [];
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
// svelte-ignore non_reactive_update
|
|
182
|
+
export function closeContextMenu() {
|
|
183
|
+
contextMenuVisible = false;
|
|
184
|
+
contextMenuNode = null;
|
|
185
|
+
isDebugMenuActive = false;
|
|
186
|
+
}
|
|
187
|
+
|
|
181
188
|
export async function scrollToPath(
|
|
182
189
|
path: string,
|
|
183
190
|
options?: { expand?: boolean; highlight?: boolean; scrollOptions?: ScrollIntoViewOptions }
|
|
@@ -325,11 +332,6 @@
|
|
|
325
332
|
isDebugMenuActive = false; // This is a user-triggered menu, not debug menu
|
|
326
333
|
}
|
|
327
334
|
|
|
328
|
-
function closeContextMenu() {
|
|
329
|
-
contextMenuVisible = false;
|
|
330
|
-
contextMenuNode = null;
|
|
331
|
-
isDebugMenuActive = false;
|
|
332
|
-
}
|
|
333
335
|
|
|
334
336
|
function _onNodeDragStart(node: LTreeNode<T>, event: DragEvent) {
|
|
335
337
|
draggedNode = node;
|
|
@@ -410,7 +412,7 @@
|
|
|
410
412
|
|
|
411
413
|
const handleGlobalScroll = (event?: Event) => {
|
|
412
414
|
if (shouldDisplayDebugInformation) {
|
|
413
|
-
console.log(
|
|
415
|
+
console.log(`[Tree ${treeId}] Scroll/wheel event detected, closing context menu`, event?.type);
|
|
414
416
|
}
|
|
415
417
|
closeContextMenu();
|
|
416
418
|
};
|
|
@@ -436,21 +438,23 @@
|
|
|
436
438
|
|
|
437
439
|
// Debug context menu - show context menu on second node for styling development
|
|
438
440
|
let isDebugMenuActive = $state(false);
|
|
441
|
+
let treeContainerRef: HTMLDivElement;
|
|
439
442
|
|
|
440
443
|
$effect(() => {
|
|
441
|
-
if (shouldDisplayContextMenuInDebugMode && (contextMenu || contextMenuCallback) && tree?.tree && tree.tree.length >
|
|
442
|
-
//
|
|
443
|
-
const
|
|
444
|
-
if (
|
|
445
|
-
// Position the context menu
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
444
|
+
if (shouldDisplayContextMenuInDebugMode && (contextMenu || contextMenuCallback) && tree?.tree && tree.tree.length > 0) {
|
|
445
|
+
// Use the first available node for the context menu data
|
|
446
|
+
const targetNode = tree.tree.length > 1 ? tree.tree[1] : tree.tree[0];
|
|
447
|
+
if (targetNode && treeContainerRef) {
|
|
448
|
+
// Position the context menu relative to the tree container
|
|
449
|
+
const treeRect = treeContainerRef.getBoundingClientRect();
|
|
450
|
+
contextMenuNode = targetNode;
|
|
451
|
+
contextMenuX = treeRect.left + 200; // 200px from tree's left edge
|
|
452
|
+
contextMenuY = treeRect.top + 100; // 100px from tree's top edge
|
|
449
453
|
contextMenuVisible = true;
|
|
450
454
|
isDebugMenuActive = true;
|
|
451
455
|
|
|
452
456
|
if (shouldDisplayDebugInformation) {
|
|
453
|
-
console.log(
|
|
457
|
+
console.log(`[Tree ${treeId}] Debug context menu displayed for node:`, targetNode.data, `at position (${contextMenuX}, ${contextMenuY})`);
|
|
454
458
|
}
|
|
455
459
|
}
|
|
456
460
|
} else if (!shouldDisplayContextMenuInDebugMode && isDebugMenuActive) {
|
|
@@ -462,7 +466,7 @@
|
|
|
462
466
|
});
|
|
463
467
|
</script>
|
|
464
468
|
|
|
465
|
-
<div>
|
|
469
|
+
<div bind:this={treeContainerRef}>
|
|
466
470
|
{#if shouldDisplayDebugInformation}
|
|
467
471
|
<div class="ltree-debug-info">
|
|
468
472
|
<details>
|
|
@@ -527,15 +531,23 @@
|
|
|
527
531
|
{#if contextMenuVisible && contextMenuNode}
|
|
528
532
|
<div class="ltree-context-menu" style="left: {contextMenuX}px; top: {contextMenuY}px;">
|
|
529
533
|
{#if contextMenuCallback}
|
|
530
|
-
{@const menuItems = contextMenuCallback(contextMenuNode)}
|
|
534
|
+
{@const menuItems = contextMenuCallback(contextMenuNode, closeContextMenu)}
|
|
531
535
|
{#each menuItems as item}
|
|
532
536
|
{#if item.isDivider}
|
|
533
537
|
<div class="ltree-context-menu-divider"></div>
|
|
534
538
|
{:else}
|
|
535
539
|
<div
|
|
536
|
-
class="ltree-context-menu-item"
|
|
540
|
+
class="ltree-context-menu-item {item.className || ''}"
|
|
537
541
|
class:ltree-context-menu-item-disabled={item.isDisabled}
|
|
538
|
-
onclick={() =>
|
|
542
|
+
onclick={async () => {
|
|
543
|
+
if (!item.isDisabled) {
|
|
544
|
+
try {
|
|
545
|
+
await item.callback();
|
|
546
|
+
} catch (error) {
|
|
547
|
+
console.error('Context menu callback error:', error);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}}
|
|
539
551
|
>
|
|
540
552
|
{#if item.icon}
|
|
541
553
|
<span class="ltree-context-menu-icon">{item.icon}</span>
|
|
@@ -43,7 +43,7 @@ declare function $$render<T>(): {
|
|
|
43
43
|
onNodeDragStart?: (node: LTreeNode<T>, event: DragEvent) => void;
|
|
44
44
|
onNodeDragOver?: (node: LTreeNode<T>, event: DragEvent) => void;
|
|
45
45
|
onNodeDrop?: (node: LTreeNode<T>, draggedNode: LTreeNode<T>, event: DragEvent) => void;
|
|
46
|
-
contextMenuCallback?: (node: LTreeNode<T
|
|
46
|
+
contextMenuCallback?: (node: LTreeNode<T>, closeMenuCallback: () => void) => ContextMenuItem[];
|
|
47
47
|
bodyClass?: string | null | undefined;
|
|
48
48
|
selectedNodeClass?: string | null | undefined;
|
|
49
49
|
dragOverNodeClass?: string | null | undefined;
|
|
@@ -62,6 +62,7 @@ declare function $$render<T>(): {
|
|
|
62
62
|
collapseAll: (nodePath?: string | null | undefined) => void;
|
|
63
63
|
filterNodes: (searchText: string, searchOptions?: SearchOptions) => void;
|
|
64
64
|
searchNodes: (searchText: string | null | undefined, searchOptions?: SearchOptions) => LTreeNode<T>[];
|
|
65
|
+
closeContextMenu: () => void;
|
|
65
66
|
scrollToPath: (path: string, options?: {
|
|
66
67
|
expand?: boolean;
|
|
67
68
|
highlight?: boolean;
|
|
@@ -84,6 +85,7 @@ declare class __sveltets_Render<T> {
|
|
|
84
85
|
collapseAll: (nodePath?: string | null | undefined) => void;
|
|
85
86
|
filterNodes: (searchText: string, searchOptions?: SearchOptions) => void;
|
|
86
87
|
searchNodes: (searchText: string | null | undefined, searchOptions?: SearchOptions) => LTreeNode<T>[];
|
|
88
|
+
closeContextMenu: () => void;
|
|
87
89
|
scrollToPath: (path: string, options?: {
|
|
88
90
|
expand?: boolean;
|
|
89
91
|
highlight?: boolean;
|
package/dist/ltree/types.d.ts
CHANGED
|
@@ -5,8 +5,9 @@ export interface ContextMenuItem {
|
|
|
5
5
|
icon?: string;
|
|
6
6
|
title: string;
|
|
7
7
|
isDisabled?: boolean;
|
|
8
|
-
callback: () => void
|
|
8
|
+
callback: () => void | Promise<void>;
|
|
9
9
|
isDivider?: boolean;
|
|
10
|
+
className?: string;
|
|
10
11
|
}
|
|
11
12
|
export interface InsertArrayResult<T> {
|
|
12
13
|
successful: number;
|