@keenmate/svelte-treeview 1.0.0-beta.0 → 1.0.0-beta.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 +38 -38
- package/dist/Branch.svelte +126 -132
- package/dist/Checkbox.svelte +30 -52
- package/dist/Checkbox.svelte.d.ts +0 -2
- package/dist/TreeView.svelte +65 -69
- package/dist/TreeView.svelte.d.ts +12 -12
- package/dist/constants.js +2 -6
- package/dist/helpers/tree-helper.d.ts +12 -19
- package/dist/helpers/tree-helper.js +52 -54
- package/dist/menu/ContextMenu.svelte +27 -33
- package/dist/menu/ContextMenu.svelte.d.ts +8 -18
- package/dist/menu/Menu.svelte +51 -50
- package/dist/menu/MenuDivider.svelte +11 -10
- package/dist/menu/MenuOption.svelte +50 -49
- package/dist/menu/menu.js +2 -2
- package/dist/providers/drag-drop-provider.d.ts +0 -29
- package/dist/providers/drag-drop-provider.js +186 -163
- package/dist/providers/selection-provider.d.ts +4 -6
- package/dist/providers/selection-provider.js +43 -31
- package/dist/tree-styles.sass +105 -105
- package/dist/types.d.ts +29 -8
- package/package.json +71 -71
- package/dist/helpers/property-helper.d.ts +0 -31
- package/dist/helpers/property-helper.js +0 -94
- package/dist/stores/drag-and-drop-store.d.ts +0 -13
- package/dist/stores/drag-and-drop-store.js +0 -23
package/dist/TreeView.svelte
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
<script>import ContextMenu from './menu/ContextMenu.svelte';
|
|
1
|
+
<script generics="T">import ContextMenu from './menu/ContextMenu.svelte';
|
|
2
2
|
import { createEventDispatcher, onMount } from 'svelte';
|
|
3
3
|
import { defaultClasses, defaultPixelTreshold, defaultPropNames } from './constants.js';
|
|
4
4
|
import { SelectionModes as SelectionModes, VisualState } from './types.js';
|
|
5
5
|
import { TreeHelper } from './index.js';
|
|
6
6
|
import Branch from './Branch.svelte';
|
|
7
|
-
import { PropertyHelper } from './helpers/property-helper.js';
|
|
8
7
|
import { SelectionProvider } from './providers/selection-provider.js';
|
|
9
8
|
const dispatch = createEventDispatcher();
|
|
10
9
|
export let treeId;
|
|
@@ -86,7 +85,7 @@ export let customClasses = defaultClasses;
|
|
|
86
85
|
* If you want to only search leaf nodes,
|
|
87
86
|
* its your responsibility to check if its hasChildren property is false
|
|
88
87
|
*/
|
|
89
|
-
export let filter =
|
|
88
|
+
export let filter = null;
|
|
90
89
|
/**
|
|
91
90
|
* Log function that will be called when something happens in tree.
|
|
92
91
|
* Used mostly for debugging
|
|
@@ -104,34 +103,36 @@ let expandedIds = [];
|
|
|
104
103
|
// OLD variables, will be removed/changed in future
|
|
105
104
|
let draggedPath = null;
|
|
106
105
|
let highlightedNode = null;
|
|
107
|
-
let
|
|
108
|
-
let canNestPos = false;
|
|
109
|
-
let canNestTime = false;
|
|
110
|
-
let canNest;
|
|
111
|
-
let dragTimeout;
|
|
106
|
+
let canNest = false;
|
|
112
107
|
let validTarget = false;
|
|
113
108
|
let insPos;
|
|
114
109
|
$: dragAndDrop && console.warn('Drag and drop is not supported in this version');
|
|
115
|
-
|
|
116
|
-
$: tree, tree == null || tree == undefined ? (tree = []) : '';
|
|
117
|
-
$: propHelper = new PropertyHelper({ ...defaultPropNames, ...props });
|
|
118
|
-
$: helper = new TreeHelper(propHelper, {
|
|
119
|
-
recursive: recursiveSelection,
|
|
120
|
-
recalculateNodePath,
|
|
121
|
-
checkboxes: selectionMode,
|
|
110
|
+
$: helper = new TreeHelper({
|
|
122
111
|
separator
|
|
123
112
|
});
|
|
124
113
|
$: selectionProvider = new SelectionProvider(helper, recursiveSelection);
|
|
125
|
-
$: computedTree =
|
|
126
|
-
$:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
$: computedTree = computeTree(helper, selectionProvider, tree, filter, props, expandedIds, value);
|
|
115
|
+
$: debugLog('computedTree', computedTree);
|
|
116
|
+
export function changeAllExpansion(changeTo) {
|
|
117
|
+
debugLog('chaning expantion of every node to ', changeTo ? 'expanded' : 'collapsed');
|
|
118
|
+
expandedIds = computedTree.map((node) => node.id);
|
|
119
|
+
}
|
|
120
|
+
function computeTree(helper, selectionProvider, userProvidedTree, filter, props, expandedIds, value) {
|
|
121
|
+
if (!Array.isArray(userProvidedTree) || !Array.isArray(value)) {
|
|
122
|
+
console.error('value and tree must be arrays!!');
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
let mappedTree = helper.mapTree(userProvidedTree, filter, { ...defaultPropNames, ...props });
|
|
126
|
+
helper.markExpanded(mappedTree, expandedIds);
|
|
127
|
+
// TODO here we could save last value and only recompute visual state if value changed
|
|
128
|
+
// or use diff to only update affected nodes
|
|
129
|
+
selectionProvider.markSelected(mappedTree, value);
|
|
130
|
+
return mappedTree;
|
|
131
|
+
}
|
|
131
132
|
function onExpand(event) {
|
|
132
133
|
const { node, changeTo } = event.detail;
|
|
133
134
|
expandedIds = helper.changeExpansion(node, changeTo, expandedIds);
|
|
134
|
-
debugLog("changed expansion of node '",
|
|
135
|
+
debugLog("changed expansion of node '", node.id, "' to ", changeTo);
|
|
135
136
|
//trigger callback if it is present and node has useCallback property set to true
|
|
136
137
|
if (changeTo) {
|
|
137
138
|
handleCallback(node);
|
|
@@ -150,28 +151,23 @@ function onExpand(event) {
|
|
|
150
151
|
}
|
|
151
152
|
function handleCallback(node) {
|
|
152
153
|
// only call on nodes with children
|
|
153
|
-
if (
|
|
154
|
+
if (node.hasChildren !== true) {
|
|
154
155
|
return;
|
|
155
156
|
}
|
|
156
157
|
if (loadChildrenAsync == null) {
|
|
157
|
-
console.warn('loadChildrenAsync is not set, but useCallback is set to true on node with path',
|
|
158
|
+
console.warn('loadChildrenAsync is not set, but useCallback is set to true on node with path', node.path);
|
|
158
159
|
return;
|
|
159
160
|
}
|
|
160
161
|
debugLog('calling callback for node', node);
|
|
161
162
|
// TODO mark node as loaded and dont call callback again
|
|
162
163
|
loadChildrenAsync(node);
|
|
163
164
|
}
|
|
164
|
-
// TODO remove and expose function from package
|
|
165
|
-
export function changeAllExpansion(changeTo) {
|
|
166
|
-
debugLog('chaning expantion of every node to ', changeTo ? 'expanded' : 'collapsed');
|
|
167
|
-
tree = helper.changeEveryExpansion(tree, changeTo);
|
|
168
|
-
}
|
|
169
165
|
function onSelectionChanged(event) {
|
|
170
166
|
const { node } = event.detail;
|
|
171
|
-
const nodePath =
|
|
167
|
+
const nodePath = node.path;
|
|
172
168
|
const changeTo = !selectionProvider.isNodeSelected(node);
|
|
173
|
-
const newValue = selectionProvider.setSelection(
|
|
174
|
-
debugLog("changing selection of node '", nodePath, "' to ",
|
|
169
|
+
const newValue = selectionProvider.setSelection(computedTree, nodePath, changeTo, value);
|
|
170
|
+
debugLog("changing selection of node '", nodePath, "' to ", changeTo, ' returing value ', newValue);
|
|
175
171
|
dispatch('change', newValue);
|
|
176
172
|
dispatch('selection', {
|
|
177
173
|
node: node,
|
|
@@ -196,42 +192,42 @@ function debugLog(...data) {
|
|
|
196
192
|
logger(...data);
|
|
197
193
|
}
|
|
198
194
|
}
|
|
199
|
-
</script>
|
|
200
|
-
|
|
201
|
-
<Branch
|
|
202
|
-
branchRootNode={null}
|
|
203
|
-
{treeId}
|
|
204
|
-
checkboxes={selectionMode}
|
|
205
|
-
tree={computedTree}
|
|
206
|
-
recursive={recursiveSelection}
|
|
207
|
-
{onlyLeafCheckboxes}
|
|
208
|
-
{hideDisabledCheckboxes}
|
|
209
|
-
{expandTo}
|
|
210
|
-
{draggedPath}
|
|
211
|
-
{dragAndDrop}
|
|
212
|
-
{highlightedNode}
|
|
213
|
-
{readonly}
|
|
214
|
-
{helper}
|
|
215
|
-
classes={customClasses}
|
|
216
|
-
{verticalLines}
|
|
217
|
-
on:open-ctxmenu={openContextMenu}
|
|
218
|
-
on:internal-expand={onExpand}
|
|
219
|
-
on:internal-selectionChanged={onSelectionChanged}
|
|
220
|
-
let:node={nodeInSlot}
|
|
221
|
-
childDepth={0}
|
|
222
|
-
{canNest}
|
|
223
|
-
{validTarget}
|
|
224
|
-
{insPos}
|
|
225
|
-
>
|
|
226
|
-
<slot node={nodeInSlot} />
|
|
227
|
-
</Branch>
|
|
228
|
-
|
|
229
|
-
<ContextMenu bind:this={ctxMenu}>
|
|
230
|
-
<svelte:fragment let:node>
|
|
231
|
-
<slot name="context-menu" {node} />
|
|
232
|
-
</svelte:fragment>
|
|
233
|
-
</ContextMenu>
|
|
234
|
-
|
|
195
|
+
</script>
|
|
196
|
+
|
|
197
|
+
<Branch
|
|
198
|
+
branchRootNode={null}
|
|
199
|
+
{treeId}
|
|
200
|
+
checkboxes={selectionMode}
|
|
201
|
+
tree={computedTree}
|
|
202
|
+
recursive={recursiveSelection}
|
|
203
|
+
{onlyLeafCheckboxes}
|
|
204
|
+
{hideDisabledCheckboxes}
|
|
205
|
+
{expandTo}
|
|
206
|
+
{draggedPath}
|
|
207
|
+
{dragAndDrop}
|
|
208
|
+
{highlightedNode}
|
|
209
|
+
{readonly}
|
|
210
|
+
{helper}
|
|
211
|
+
classes={customClasses}
|
|
212
|
+
{verticalLines}
|
|
213
|
+
on:open-ctxmenu={openContextMenu}
|
|
214
|
+
on:internal-expand={onExpand}
|
|
215
|
+
on:internal-selectionChanged={onSelectionChanged}
|
|
216
|
+
let:node={nodeInSlot}
|
|
217
|
+
childDepth={0}
|
|
218
|
+
{canNest}
|
|
219
|
+
{validTarget}
|
|
220
|
+
{insPos}
|
|
221
|
+
>
|
|
222
|
+
<slot node={nodeInSlot} />
|
|
223
|
+
</Branch>
|
|
224
|
+
|
|
225
|
+
<ContextMenu bind:this={ctxMenu}>
|
|
226
|
+
<svelte:fragment let:node>
|
|
227
|
+
<slot name="context-menu" {node} />
|
|
228
|
+
</svelte:fragment>
|
|
229
|
+
</ContextMenu>
|
|
230
|
+
|
|
235
231
|
<style global>:global(.treeview) {
|
|
236
232
|
padding: 0;
|
|
237
233
|
}
|
|
@@ -343,4 +339,4 @@ function debugLog(...data) {
|
|
|
343
339
|
}
|
|
344
340
|
:global(.treeview) :global(.pointer-cursor) {
|
|
345
341
|
cursor: grab;
|
|
346
|
-
}</style>
|
|
342
|
+
}</style>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import { SelectionModes as SelectionModes, type
|
|
3
|
-
declare
|
|
4
|
-
props: {
|
|
2
|
+
import { SelectionModes as SelectionModes, type Props, type CustomizableClasses, type DragEnterCallback, type BeforeMovedCallback, type ExpandedCallback, type NodeId, type ProvidedTree, type FilterFunction } from './types.js';
|
|
3
|
+
declare class __sveltets_Render<T> {
|
|
4
|
+
props(): {
|
|
5
5
|
treeId: string;
|
|
6
6
|
/**
|
|
7
7
|
* Array of nodes that represent tree structure.
|
|
8
8
|
* Each node should have unique path
|
|
9
9
|
* All tree modifications are made by modifying this array, so you need to bind it to parent component
|
|
10
|
-
*/ tree:
|
|
10
|
+
*/ tree: ProvidedTree;
|
|
11
11
|
/**
|
|
12
12
|
* Node paths of selected nodes
|
|
13
13
|
*/ value?: NodeId[] | undefined;
|
|
@@ -65,7 +65,7 @@ declare const __propDef: {
|
|
|
65
65
|
* User Higher order functions for reactive search.
|
|
66
66
|
* If you want to only search leaf nodes,
|
|
67
67
|
* its your responsibility to check if its hasChildren property is false
|
|
68
|
-
*/ filter?:
|
|
68
|
+
*/ filter?: FilterFunction | null | undefined;
|
|
69
69
|
/**
|
|
70
70
|
* Log function that will be called when something happens in tree.
|
|
71
71
|
* Used mostly for debugging
|
|
@@ -78,7 +78,7 @@ declare const __propDef: {
|
|
|
78
78
|
beforeMovedCallback?: BeforeMovedCallback | null | undefined;
|
|
79
79
|
changeAllExpansion?: ((changeTo: boolean) => void) | undefined;
|
|
80
80
|
};
|
|
81
|
-
events: {
|
|
81
|
+
events(): {
|
|
82
82
|
expansion: CustomEvent<any>;
|
|
83
83
|
expanded: CustomEvent<any>;
|
|
84
84
|
closed: CustomEvent<any>;
|
|
@@ -89,7 +89,7 @@ declare const __propDef: {
|
|
|
89
89
|
} & {
|
|
90
90
|
[evt: string]: CustomEvent<any>;
|
|
91
91
|
};
|
|
92
|
-
slots: {
|
|
92
|
+
slots(): {
|
|
93
93
|
default: {
|
|
94
94
|
node: any;
|
|
95
95
|
};
|
|
@@ -97,11 +97,11 @@ declare const __propDef: {
|
|
|
97
97
|
node: any;
|
|
98
98
|
};
|
|
99
99
|
};
|
|
100
|
-
}
|
|
101
|
-
export type TreeViewProps =
|
|
102
|
-
export type TreeViewEvents =
|
|
103
|
-
export type TreeViewSlots =
|
|
104
|
-
export default class TreeView extends SvelteComponent<TreeViewProps
|
|
100
|
+
}
|
|
101
|
+
export type TreeViewProps<T> = ReturnType<__sveltets_Render<T>['props']>;
|
|
102
|
+
export type TreeViewEvents<T> = ReturnType<__sveltets_Render<T>['events']>;
|
|
103
|
+
export type TreeViewSlots<T> = ReturnType<__sveltets_Render<T>['slots']>;
|
|
104
|
+
export default class TreeView<T> extends SvelteComponent<TreeViewProps<T>, TreeViewEvents<T>, TreeViewSlots<T>> {
|
|
105
105
|
get changeAllExpansion(): (changeTo: boolean) => void;
|
|
106
106
|
}
|
|
107
107
|
export {};
|
package/dist/constants.js
CHANGED
|
@@ -3,15 +3,12 @@ export const defaultPropNames = {
|
|
|
3
3
|
nodePath: 'nodePath',
|
|
4
4
|
nodeId: 'nodePath',
|
|
5
5
|
hasChildren: 'hasChildren',
|
|
6
|
-
expanded: '__expanded',
|
|
7
|
-
selected: '__selected',
|
|
8
6
|
useCallback: '__useCallback',
|
|
9
7
|
priority: 'priority',
|
|
10
8
|
isDraggable: 'isDraggable',
|
|
11
9
|
insertDisabled: 'insertDisabled',
|
|
12
10
|
nestDisabled: 'nestDisabled',
|
|
13
|
-
checkbox: 'checkbox'
|
|
14
|
-
visualState: '__visual_state'
|
|
11
|
+
checkbox: 'checkbox'
|
|
15
12
|
};
|
|
16
13
|
export const defaultPixelTreshold = 50;
|
|
17
14
|
export const defaultClasses = {
|
|
@@ -25,6 +22,5 @@ export const defaultClasses = {
|
|
|
25
22
|
inserLineNestClass: ''
|
|
26
23
|
};
|
|
27
24
|
export const defaultConfig = {
|
|
28
|
-
separator: '.'
|
|
29
|
-
checkboxes: SelectionModes.none
|
|
25
|
+
separator: '.'
|
|
30
26
|
};
|
|
@@ -1,35 +1,28 @@
|
|
|
1
|
-
import { type Node, type NodePath, type HelperConfig, type Tree,
|
|
2
|
-
import type { PropertyHelper } from './property-helper.js';
|
|
1
|
+
import { type Node, type NodePath, type HelperConfig, type Tree, type NodeId, type Props, type FilterFunction } from '../types.js';
|
|
3
2
|
export declare class TreeHelper {
|
|
4
|
-
props: PropertyHelper;
|
|
5
3
|
config: HelperConfig;
|
|
6
|
-
constructor(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
[nodePath: string]: VisualState;
|
|
10
|
-
}): Tree;
|
|
4
|
+
constructor(config?: HelperConfig);
|
|
5
|
+
mapTree(tree: Tree, filter: FilterFunction | null, properties: Props): Node[];
|
|
6
|
+
markExpanded(tree: Tree, expandedNodeIds: NodeId[]): void;
|
|
11
7
|
getParentNodePath(nodePath: NodePath): NodePath;
|
|
12
8
|
isChildrenOf(parentNodePath: NodePath, childrenNodePath: NodePath): boolean | undefined;
|
|
13
|
-
hasChildren(tree: Tree, nodePath: NodePath):
|
|
9
|
+
hasChildren(tree: Tree, nodePath: NodePath): Node | undefined;
|
|
14
10
|
findNode(tree: Tree, nodePath: NodePath): Node | null;
|
|
15
11
|
nodePathIsChild(nodePath: NodePath): boolean | undefined;
|
|
16
12
|
getDirectChildren(tree: Tree, parentNodePath: NodePath): Tree;
|
|
17
|
-
allCHildren(tree: Tree, parentNodePath: NodePath):
|
|
18
|
-
getAllLeafNodes(tree: Tree):
|
|
19
|
-
joinTrees(filteredTree: Tree, tree: Tree):
|
|
20
|
-
mergeTrees(oldTree: Tree, addedTree: Tree, nodePath?: string):
|
|
13
|
+
allCHildren(tree: Tree, parentNodePath: NodePath): Node[];
|
|
14
|
+
getAllLeafNodes(tree: Tree): Node[];
|
|
15
|
+
joinTrees(filteredTree: Tree, tree: Tree): Node[];
|
|
16
|
+
mergeTrees(oldTree: Tree, addedTree: Tree, nodePath?: string): Node[];
|
|
21
17
|
/** toggles expansion on
|
|
22
18
|
*/
|
|
23
19
|
changeExpansion(node: Node, changeTo: boolean, oldExpandedNodeIds: NodeId[]): NodeId[];
|
|
24
|
-
/** changes expansion of every node that has this.hasChildren set to true
|
|
25
|
-
*/
|
|
26
|
-
changeEveryExpansion(tree: Tree, changeTo: boolean): object[];
|
|
27
20
|
/** changes expansion of every node that has this.hasChildren set to true if they are abose set level and expansion property isnt set
|
|
28
21
|
*/
|
|
29
|
-
expandToLevel(tree: Tree, level: number):
|
|
22
|
+
expandToLevel(tree: Tree, level: number): NodeId[];
|
|
30
23
|
getDepthLevel(nodePath: NodePath): number;
|
|
31
|
-
searchTree(tree: Tree, filter:
|
|
32
|
-
getParents(tree: Tree,
|
|
24
|
+
searchTree(tree: Tree, filter: FilterFunction | null): Tree;
|
|
25
|
+
getParents(tree: Tree, targetNode: Node): Node[];
|
|
33
26
|
/** orders nodes by priorityProp
|
|
34
27
|
*/
|
|
35
28
|
orderByPriority(tree: Tree): Tree;
|
|
@@ -3,28 +3,37 @@ import uniqueBy from 'lodash.uniqby'; // used by tree merge
|
|
|
3
3
|
import { VisualState } from '../types.js';
|
|
4
4
|
import { defaultConfig } from '../constants.js';
|
|
5
5
|
export class TreeHelper {
|
|
6
|
-
props;
|
|
7
6
|
config;
|
|
8
|
-
constructor(
|
|
9
|
-
this.props = props;
|
|
7
|
+
constructor(config = defaultConfig) {
|
|
10
8
|
this.config = config;
|
|
11
9
|
}
|
|
12
|
-
|
|
13
|
-
path(node) {
|
|
14
|
-
return this.props.path(node);
|
|
15
|
-
}
|
|
16
|
-
computeTree(tree, filter, expandedNodeIds, selectedNodeIds, visualStates) {
|
|
10
|
+
mapTree(tree, filter, properties) {
|
|
17
11
|
{
|
|
18
12
|
return this.searchTree(tree, filter).map((node) => {
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
// TODO maybe create class for nodes
|
|
14
|
+
const mappedNode = {
|
|
15
|
+
originalNode: node,
|
|
16
|
+
id: node[properties.nodeId],
|
|
17
|
+
path: node[properties.nodePath],
|
|
18
|
+
hasChildren: node[properties.hasChildren],
|
|
19
|
+
useCallback: node[properties.useCallback],
|
|
20
|
+
priority: node[properties.priority],
|
|
21
|
+
isDraggable: node[properties.isDraggable],
|
|
22
|
+
insertDisabled: node[properties.insertDisabled],
|
|
23
|
+
nestDisabled: node[properties.nestDisabled],
|
|
24
|
+
checkbox: node[properties.checkbox],
|
|
25
|
+
expanded: false,
|
|
26
|
+
selected: false,
|
|
27
|
+
visualState: VisualState.notSelected
|
|
28
|
+
};
|
|
29
|
+
return mappedNode;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
markExpanded(tree, expandedNodeIds) {
|
|
34
|
+
{
|
|
35
|
+
tree.forEach((node) => {
|
|
36
|
+
node.expanded = expandedNodeIds.includes(node.id ?? '');
|
|
28
37
|
});
|
|
29
38
|
}
|
|
30
39
|
}
|
|
@@ -32,7 +41,7 @@ export class TreeHelper {
|
|
|
32
41
|
getParentNodePath(nodePath) {
|
|
33
42
|
if (nodePath == null)
|
|
34
43
|
throw new Error('cannot get parent of root');
|
|
35
|
-
const separator = this.config.separator
|
|
44
|
+
const separator = this.config.separator;
|
|
36
45
|
const parentPath = nodePath?.substring(0, nodePath.lastIndexOf(separator));
|
|
37
46
|
if (parentPath === '')
|
|
38
47
|
return null;
|
|
@@ -44,34 +53,34 @@ export class TreeHelper {
|
|
|
44
53
|
return childrenNodePath?.startsWith(parentNodePath ?? '');
|
|
45
54
|
}
|
|
46
55
|
hasChildren(tree, nodePath) {
|
|
47
|
-
return tree?.find((x) => this.getParentNodePath(
|
|
56
|
+
return tree?.find((x) => this.getParentNodePath(x.path) === nodePath);
|
|
48
57
|
}
|
|
49
58
|
findNode(tree, nodePath) {
|
|
50
|
-
return tree.find((node) =>
|
|
59
|
+
return tree.find((node) => node.path === nodePath) ?? null;
|
|
51
60
|
}
|
|
52
61
|
nodePathIsChild(nodePath) {
|
|
53
|
-
const separator = this.config.separator
|
|
62
|
+
const separator = this.config.separator;
|
|
54
63
|
const includesSeparator = nodePath?.includes(separator);
|
|
55
64
|
return includesSeparator;
|
|
56
65
|
}
|
|
57
66
|
getDirectChildren(tree, parentNodePath) {
|
|
58
|
-
const children =
|
|
59
|
-
? !this.nodePathIsChild(
|
|
60
|
-
: this.getParentNodePath(
|
|
67
|
+
const children = tree.filter((node) => !parentNodePath
|
|
68
|
+
? !this.nodePathIsChild(node.path)
|
|
69
|
+
: this.getParentNodePath(node.path) === parentNodePath);
|
|
61
70
|
const ordered = this.orderByPriority(children);
|
|
62
71
|
return ordered;
|
|
63
72
|
}
|
|
64
73
|
allCHildren(tree, parentNodePath) {
|
|
65
|
-
const children = tree.filter((
|
|
74
|
+
const children = tree.filter((node) => this.isChildrenOf(parentNodePath, node.path));
|
|
66
75
|
return children;
|
|
67
76
|
}
|
|
68
77
|
getAllLeafNodes(tree) {
|
|
69
|
-
return tree.filter((
|
|
70
|
-
return
|
|
78
|
+
return tree.filter((node) => {
|
|
79
|
+
return node.hasChildren !== true;
|
|
71
80
|
});
|
|
72
81
|
}
|
|
73
82
|
joinTrees(filteredTree, tree) {
|
|
74
|
-
return tree.map((
|
|
83
|
+
return tree.map((node) => this.findNode(filteredTree, node.path) || node);
|
|
75
84
|
}
|
|
76
85
|
mergeTrees(oldTree, addedTree, nodePath = 'nodePath') {
|
|
77
86
|
return orderBy(addedTree, oldTree, nodePath);
|
|
@@ -79,44 +88,33 @@ export class TreeHelper {
|
|
|
79
88
|
/** toggles expansion on
|
|
80
89
|
*/
|
|
81
90
|
changeExpansion(node, changeTo, oldExpandedNodeIds) {
|
|
82
|
-
const nodeId =
|
|
91
|
+
const nodeId = node.id ?? '';
|
|
83
92
|
if (changeTo === true) {
|
|
84
93
|
return [...oldExpandedNodeIds, nodeId];
|
|
85
94
|
}
|
|
86
95
|
return oldExpandedNodeIds.filter((x) => x !== nodeId);
|
|
87
96
|
}
|
|
88
|
-
/** changes expansion of every node that has this.hasChildren set to true
|
|
89
|
-
*/
|
|
90
|
-
changeEveryExpansion(tree, changeTo) {
|
|
91
|
-
return tree.map((node) => {
|
|
92
|
-
if (this.props.hasChildren(node) == true) {
|
|
93
|
-
this.props.setExpanded(node, changeTo);
|
|
94
|
-
}
|
|
95
|
-
return node;
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
97
|
/** changes expansion of every node that has this.hasChildren set to true if they are abose set level and expansion property isnt set
|
|
99
98
|
*/
|
|
100
99
|
expandToLevel(tree, level) {
|
|
101
|
-
return tree
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
return n;
|
|
109
|
-
});
|
|
100
|
+
return tree
|
|
101
|
+
.filter((node) => node.expanded == undefined &&
|
|
102
|
+
node.expanded == null &&
|
|
103
|
+
node.useCallback != true &&
|
|
104
|
+
this.getDepthLevel(node.path) <= level)
|
|
105
|
+
.map((node) => node.id ?? '');
|
|
110
106
|
}
|
|
111
107
|
//based on number of dots
|
|
112
108
|
getDepthLevel(nodePath) {
|
|
113
109
|
if (nodePath == null)
|
|
114
110
|
return 0;
|
|
115
|
-
const separator = this.config.separator
|
|
111
|
+
const separator = this.config.separator;
|
|
116
112
|
return nodePath.split(separator).length - 1;
|
|
117
113
|
}
|
|
118
114
|
//#endregion
|
|
119
115
|
searchTree(tree, filter) {
|
|
116
|
+
if (!filter)
|
|
117
|
+
return tree;
|
|
120
118
|
const filteredNodes = tree.filter(filter);
|
|
121
119
|
const resultNodes = [];
|
|
122
120
|
// add all parents from each node
|
|
@@ -126,26 +124,26 @@ export class TreeHelper {
|
|
|
126
124
|
const parentNodes = this.getParents(tree, node);
|
|
127
125
|
resultNodes.push(...parentNodes);
|
|
128
126
|
});
|
|
129
|
-
const uniqueNodes = uniqueBy(resultNodes, (node) =>
|
|
127
|
+
const uniqueNodes = uniqueBy(resultNodes, (node) => node.path);
|
|
130
128
|
return uniqueNodes;
|
|
131
129
|
}
|
|
132
|
-
getParents(tree,
|
|
130
|
+
getParents(tree, targetNode) {
|
|
133
131
|
const parentsPaths = [];
|
|
134
|
-
let nodePath =
|
|
132
|
+
let nodePath = targetNode.path;
|
|
135
133
|
// get all parents
|
|
136
134
|
while (nodePath && nodePath.length > 0) {
|
|
137
135
|
nodePath = this.getParentNodePath(nodePath);
|
|
138
136
|
parentsPaths.push(nodePath);
|
|
139
137
|
}
|
|
140
138
|
//find nodes for given ids
|
|
141
|
-
const parentNodes = tree.filter((
|
|
139
|
+
const parentNodes = tree.filter((node) => parentsPaths.some((parentNodePath) => node.path === parentNodePath));
|
|
142
140
|
return parentNodes;
|
|
143
141
|
}
|
|
144
142
|
/** orders nodes by priorityProp
|
|
145
143
|
*/
|
|
146
144
|
orderByPriority(tree) {
|
|
147
145
|
// TODO investigata that it really works
|
|
148
|
-
tree.sort((a, b) =>
|
|
146
|
+
tree.sort((a, b) => (b.priority ? a.priority - b.priority : 1));
|
|
149
147
|
return tree;
|
|
150
148
|
}
|
|
151
149
|
}
|
|
@@ -1,33 +1,27 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
<Menu {...pos} on:click={closeMenu} on:clickoutside={closeMenu}>
|
|
29
|
-
<slot {node}>
|
|
30
|
-
<b> context menu openned from: {node?.nodePath}</b>
|
|
31
|
-
</slot>
|
|
32
|
-
</Menu>
|
|
33
|
-
{/if}
|
|
1
|
+
<script>import Menu from './Menu.svelte';
|
|
2
|
+
let pos = { x: 0, y: 0 };
|
|
3
|
+
let showMenu = false;
|
|
4
|
+
let clickedNode = null;
|
|
5
|
+
export async function onRightClick(event, node) {
|
|
6
|
+
if (showMenu) {
|
|
7
|
+
showMenu = false;
|
|
8
|
+
await new Promise((res) => setTimeout(res, 100));
|
|
9
|
+
}
|
|
10
|
+
clickedNode = node;
|
|
11
|
+
pos = { x: event.clientX, y: event.clientY };
|
|
12
|
+
showMenu = true;
|
|
13
|
+
}
|
|
14
|
+
function closeMenu() {
|
|
15
|
+
showMenu = false;
|
|
16
|
+
clickedNode = null;
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<svelte:window on:click={closeMenu} />
|
|
21
|
+
{#if showMenu}
|
|
22
|
+
<Menu {...pos} on:click={closeMenu} on:clickoutside={closeMenu}>
|
|
23
|
+
<slot node={clickedNode}>
|
|
24
|
+
<b> context menu openned from: {clickedNode?.path}</b>
|
|
25
|
+
</slot>
|
|
26
|
+
</Menu>
|
|
27
|
+
{/if}
|
|
@@ -1,24 +1,8 @@
|
|
|
1
|
-
/** @typedef {typeof __propDef.props} ContextMenuProps */
|
|
2
|
-
/** @typedef {typeof __propDef.events} ContextMenuEvents */
|
|
3
|
-
/** @typedef {typeof __propDef.slots} ContextMenuSlots */
|
|
4
|
-
export default class ContextMenu extends SvelteComponent<{
|
|
5
|
-
onRightClick?: ((e: any, n: any) => Promise<void>) | undefined;
|
|
6
|
-
}, {
|
|
7
|
-
[evt: string]: CustomEvent<any>;
|
|
8
|
-
}, {
|
|
9
|
-
default: {
|
|
10
|
-
node: null;
|
|
11
|
-
};
|
|
12
|
-
}> {
|
|
13
|
-
get onRightClick(): (e: any, n: any) => Promise<void>;
|
|
14
|
-
}
|
|
15
|
-
export type ContextMenuProps = typeof __propDef.props;
|
|
16
|
-
export type ContextMenuEvents = typeof __propDef.events;
|
|
17
|
-
export type ContextMenuSlots = typeof __propDef.slots;
|
|
18
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { Node } from '../types.js';
|
|
19
3
|
declare const __propDef: {
|
|
20
4
|
props: {
|
|
21
|
-
onRightClick?: ((
|
|
5
|
+
onRightClick?: ((event: MouseEvent, node: Node) => Promise<void>) | undefined;
|
|
22
6
|
};
|
|
23
7
|
events: {
|
|
24
8
|
[evt: string]: CustomEvent<any>;
|
|
@@ -29,4 +13,10 @@ declare const __propDef: {
|
|
|
29
13
|
};
|
|
30
14
|
};
|
|
31
15
|
};
|
|
16
|
+
export type ContextMenuProps = typeof __propDef.props;
|
|
17
|
+
export type ContextMenuEvents = typeof __propDef.events;
|
|
18
|
+
export type ContextMenuSlots = typeof __propDef.slots;
|
|
19
|
+
export default class ContextMenu extends SvelteComponent<ContextMenuProps, ContextMenuEvents, ContextMenuSlots> {
|
|
20
|
+
get onRightClick(): (event: MouseEvent, node: Node) => Promise<void>;
|
|
21
|
+
}
|
|
32
22
|
export {};
|