@keenmate/svelte-treeview 0.2.1 → 0.3.2
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 +7 -243
- package/dist/Branch.svelte +218 -0
- package/dist/Branch.svelte.d.ts +49 -0
- package/dist/Checkbox.svelte +34 -31
- package/dist/Checkbox.svelte.d.ts +15 -29
- package/dist/TreeView.svelte +250 -288
- package/dist/TreeView.svelte.d.ts +72 -33
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +24 -0
- package/dist/helpers/drag-drop-helpers.d.ts +17 -14
- package/dist/helpers/drag-drop-helpers.js +164 -193
- package/dist/helpers/property-helper.d.ts +29 -0
- package/dist/helpers/property-helper.js +82 -0
- package/dist/helpers/selection-helpers.d.ts +28 -20
- package/dist/helpers/selection-helpers.js +148 -182
- package/dist/helpers/tree-helper.d.ts +25 -24
- package/dist/helpers/tree-helper.js +129 -169
- package/dist/index.d.ts +6 -5
- package/dist/index.js +3 -2
- package/dist/menu/ContextMenu.svelte.d.ts +2 -2
- package/dist/menu/Menu.svelte.d.ts +2 -2
- package/dist/menu/MenuDivider.svelte.d.ts +2 -2
- package/dist/menu/MenuOption.svelte +1 -1
- package/dist/menu/MenuOption.svelte.d.ts +2 -2
- package/dist/tree-styles.sass +0 -2
- package/dist/types.d.ts +46 -0
- package/dist/types.js +12 -0
- package/package.json +71 -63
- package/dist/consts.d.ts +0 -28
- package/dist/consts.js +0 -31
package/README.md
CHANGED
|
@@ -1,249 +1,13 @@
|
|
|
1
1
|
# Svelte Treeview
|
|
2
2
|
|
|
3
|
-
The most elaborate treeview for svelte on earth (or even in our galaxy).
|
|
4
|
-
[DEMO](https://dev.phoenix-svelte-adminlte.demo.keenmate.com/#/tree)
|
|
3
|
+
The most elaborate treeview for svelte on earth (or even in our galaxy).
|
|
5
4
|
|
|
6
|
-
##
|
|
5
|
+
## Features
|
|
7
6
|
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- [function on component](#function-on-component)
|
|
12
|
-
- [Helper functions](#helper-functions)
|
|
13
|
-
- [basic usage](#basic-usage)
|
|
14
|
-
- [callbacks](#callbacks)
|
|
15
|
-
- [selection](#selection)
|
|
16
|
-
- [search](#search)
|
|
17
|
-
- [drag and drop](#drag-and-drop)
|
|
18
|
-
- [context menu](#context-menu)
|
|
7
|
+
- automatically expanding to given depth
|
|
8
|
+
- customization of all object properties
|
|
9
|
+
-
|
|
19
10
|
|
|
20
|
-
##
|
|
11
|
+
## Current state
|
|
21
12
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## Props
|
|
25
|
-
|
|
26
|
-
- ***tree*** (array of nodes, default: *null*)
|
|
27
|
-
tree itself.
|
|
28
|
-
- ***treeId*** (string, default: *null*)
|
|
29
|
-
you HAVE to set this to unique string
|
|
30
|
-
- ***maxExpandedDepth*** (number, default: *3*)
|
|
31
|
-
- ***filteredTree*** (array of nodes, default: *null*)
|
|
32
|
-
Nodes that should be rendered (same as tree if null)
|
|
33
|
-
- ***checkboxes*** (string "none"|"perNode"|"All", default: *false*)
|
|
34
|
-
When all checkboxes will be shown if **checkboxVisible** isnt false,whe perNode only nodes with **checkboxVisible** set to true will be shown. None will override **checkboxVisible** .When click on checkbox it will toggle selected on clicked node. You can specify this behavior with **recursive**, **onlyLeafCheckboxes** and **checkboxesDisabled**.
|
|
35
|
-
- ***recursive*** (bool, default: *false*)
|
|
36
|
-
When true, you can only select "leaf nodes" (nodes when **hasChildren** isnt true). When clicking other nodes, it will tooggle all children. Non leaf children will have wont have **selected**, instead, __visual_state will be calculated automatically ( all true => true, at least one true => indeterminate, all false => false).
|
|
37
|
-
- ***onlyLeafCheckboxes*** ( bool, default: *false*)
|
|
38
|
-
you wont be able to click on any other checkboxes that on leaf nodes.
|
|
39
|
-
- ***checkboxesDisabled*** (bool, default: *false*)
|
|
40
|
-
will only disable checkboxes, instead of not showing them.
|
|
41
|
-
- ***dragAndDrop*** (bool, default: *false*)
|
|
42
|
-
will enable drag and drop behavior viz drag and drop section
|
|
43
|
-
- ***timeToNest*** (number in ms, default: *null*)
|
|
44
|
-
after that time hovering over one node, it will nest.
|
|
45
|
-
- ***pixelNestTreshold*** (number in px, default: *150*)
|
|
46
|
-
when you move cursor to then left by x pixels will nest
|
|
47
|
-
- ***expandCallback*** (function that takes node as argument, default: *null*)
|
|
48
|
-
called when node with **useCallback** set to true is expanded. Only called once.
|
|
49
|
-
- ***showContexMenu*** (bool, default: false)
|
|
50
|
-
Will show context menu you defined in context-menu slot when you right click any node
|
|
51
|
-
- ***beforeMovedCallback*** (function with params: (movedNode,oldParent,TargetNode,insType: ("before","inside","after")), default: null )
|
|
52
|
-
Called when you droped node before any recalculation takes place. You can cancel move by returning false
|
|
53
|
-
- ***dragEnterCallback*** (function with params: (movedNode,oldParent,TargetNode), default: null )
|
|
54
|
-
Called when dragged nodes enters different node. By returnting false, it will set that node as nonvalid target so you wont be able to it and it doesnt show guide lines. Dont do any expensive operations here and dont modify tree.
|
|
55
|
-
- ***enableVerticalLines*** (bool, default: false)
|
|
56
|
-
This property controls if vertical lines are displayed in front of each node for easier use
|
|
57
|
-
- ***recalculateNodePath*** (bool,default: true)
|
|
58
|
-
If true, will not change last part of nodePath of moved node. Use this is=f last part of your nodePath is **unique!**.
|
|
59
|
-
- ***expandedLevel*** (number,default:0)
|
|
60
|
-
will expand all nodes until this specific level(starting from 0). Set it to -1 to disable it. **expanded** has priority over this. It wont modify **expanded** on nodes so you can dynamicly change this and tree will rerender
|
|
61
|
-
- ***props***
|
|
62
|
-
property names used to store stuff in node objects
|
|
63
|
-
- ***readonly***(bool,false)
|
|
64
|
-
when true it will disable all expansion
|
|
65
|
-
- ***separator***(string,default: ".")
|
|
66
|
-
separator in nodePath
|
|
67
|
-
|
|
68
|
-
```js
|
|
69
|
-
const defaultProps = {
|
|
70
|
-
nodePath: "nodePath",
|
|
71
|
-
hasChildren: "hasChildren",
|
|
72
|
-
expanded: "__expanded",
|
|
73
|
-
selected: "__selected",
|
|
74
|
-
useCallback: "__useCallback",
|
|
75
|
-
priority: "priority",
|
|
76
|
-
isDraggable: "isDraggable",
|
|
77
|
-
insertDisabled: "insertDisabled",
|
|
78
|
-
nestDisabled: "nestDisabled",
|
|
79
|
-
checkbox: "checkbox",
|
|
80
|
-
};
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
- ***treeClass*** (string css class, default: *"treeview"*)
|
|
84
|
-
Setting this to anything else that default value will disable all styling so you can set everything yourself
|
|
85
|
-
- ***nodeClass*** (string css class, default: *""*)
|
|
86
|
-
- ***expandedToggleClass*** (string css class, default: *""*)
|
|
87
|
-
- ***collapsedToggleClass*** (string css class, default: *""*)
|
|
88
|
-
- ***currentlyDraggedClass*** (string css class, default: *"currently-dragged"*)
|
|
89
|
-
- ***expandClass*** (string css class, default: *"inserting-highlighted"*)
|
|
90
|
-
- ***inserLineClass*** (string css class, default: *""*)
|
|
91
|
-
- ***inserLineNestClass*** (string css class, default: *""*)
|
|
92
|
-
- ***currentlyDraggedClass*** (string css class, default: *"currently-dragged"*)
|
|
93
|
-
|
|
94
|
-
## Events
|
|
95
|
-
|
|
96
|
-
- **expansion** { node: node,value: bool } = fired when user clicks on plus/minus icon
|
|
97
|
-
- **expanded** { node }
|
|
98
|
-
- **closed** { node }
|
|
99
|
-
- **moved** { oldParent: Node,newParent:Node oldNode: Node, newNode: Node,targetNode: Node,insType: ("before","inside","after")} = fires when user moved node with drag and drop. Target is element you dropped node at.
|
|
100
|
-
- **selection** { node: node,value: bool } = fired when user clicks on checkbox
|
|
101
|
-
- **selected** {node }
|
|
102
|
-
- **unselected** {node }
|
|
103
|
-
|
|
104
|
-
## function on component
|
|
105
|
-
|
|
106
|
-
you call them on binded component
|
|
107
|
-
|
|
108
|
-
- **changeAllExpansion(changeTo)** = changes expansionn status of every that hasChildren to value you specify
|
|
109
|
-
|
|
110
|
-
example:
|
|
111
|
-
|
|
112
|
-
```js
|
|
113
|
-
let thisTree
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
//...
|
|
117
|
-
<button on:click={thisTree.changeAllExpansion(true)} >expand All</button>
|
|
118
|
-
<button on:click={thisTree.changeAllExpansion(false)} >colapse All</button>
|
|
119
|
-
|
|
120
|
-
<TreeView
|
|
121
|
-
bind:this={thisTree}
|
|
122
|
-
bind:tree
|
|
123
|
-
treeId="tree"
|
|
124
|
-
let:node
|
|
125
|
-
>
|
|
126
|
-
{node.nodePath}
|
|
127
|
-
</TreeView>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Helper functions
|
|
131
|
-
|
|
132
|
-
- **searchTree(tree, filterFunction, recursive,propNames)** = function that will filter tree using filterFunction and adds all parent so that it can render. If recursive is true, it will only search through "lef nodes" (nodes that dont have children)
|
|
133
|
-
- **mergeTrees(oldTree,addedTree,nodePath="nodePath")** = will merge new tree into old one, so that expanded, etc. wont be reseted.
|
|
134
|
-
|
|
135
|
-
usage:
|
|
136
|
-
|
|
137
|
-
```js
|
|
138
|
-
import {TreeView,mergeTrees,searchTree} from "../index.js";
|
|
139
|
-
//will merger treeToAdd into tree, so expansion etc wont be effected
|
|
140
|
-
tree = mergeTrees(tree,treeToAdd);
|
|
141
|
-
//searches tree
|
|
142
|
-
filteredTree = searchTree(tree, filterFunction, recursive,propNames)
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## basic usage
|
|
146
|
-
|
|
147
|
-
You need to provide treeId and tree, that is array of node where every node has nodepath defined. Parent nodes have to have hasChildren set to true. Next you have to set a default slot with how you want you nodes to be rendered.You can add your own props to nodes and used them here in events, contextmenus and callbacks. Treeview uses **expanded** to determine expansion.
|
|
148
|
-
|
|
149
|
-
example:
|
|
150
|
-
|
|
151
|
-
```js
|
|
152
|
-
import {TreeView} from "svelte-treeview"
|
|
153
|
-
let tree = [
|
|
154
|
-
{ nodePath: "1"},
|
|
155
|
-
{ nodePath: "2"},
|
|
156
|
-
{ nodePath: "3", hasChildren: true},
|
|
157
|
-
{ nodePath: "3.1"},
|
|
158
|
-
{ nodePath: "3.2", hasChildren: true},
|
|
159
|
-
{ nodePath: "3.2.1"},
|
|
160
|
-
{ nodePath: "3.2.2"},
|
|
161
|
-
{ nodePath: "3.2.3" },
|
|
162
|
-
{ nodePath: "3.2.4"},
|
|
163
|
-
{ nodePath: "3.3"}
|
|
164
|
-
]
|
|
165
|
-
//...
|
|
166
|
-
|
|
167
|
-
<TreeView
|
|
168
|
-
bind:tree
|
|
169
|
-
treeId="tree"
|
|
170
|
-
let:node
|
|
171
|
-
>
|
|
172
|
-
{node.nodePath}
|
|
173
|
-
</TreeView>
|
|
174
|
-
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## callbacks
|
|
178
|
-
|
|
179
|
-
To dynamicly load data, you have to have hasChildren(to show + icon) and **useCallback** set to true on nodes you want to use callback on. Then expandCallback will be called with expanded node as parametr. Function should return Promise or array of nodes, that will be added to tree. **useCallback** will be then set to false, so that callback will only be called once.
|
|
180
|
-
|
|
181
|
-
example:
|
|
182
|
-
|
|
183
|
-
```js
|
|
184
|
-
let tree = [
|
|
185
|
-
{ nodePath: "1",__useCallback: true,},
|
|
186
|
-
{ nodePath: "2",__useCallback: true,},
|
|
187
|
-
{ nodePath: "3", hasChildren: true},
|
|
188
|
-
{ nodePath: "3.1"},
|
|
189
|
-
{ nodePath: "3.2", hasChildren: true},
|
|
190
|
-
{ nodePath: "3.2.1"},
|
|
191
|
-
{ nodePath: "3.2.2"},
|
|
192
|
-
{ nodePath: "3.2.3" },
|
|
193
|
-
{ nodePath: "3.2.4"},
|
|
194
|
-
{ nodePath: "3.3",__useCallback: true,}
|
|
195
|
-
]
|
|
196
|
-
let num =0
|
|
197
|
-
//...
|
|
198
|
-
<TreeView
|
|
199
|
-
bind:tree
|
|
200
|
-
treeId="tree"
|
|
201
|
-
let:node
|
|
202
|
-
expandCallback={(n) => {
|
|
203
|
-
return [
|
|
204
|
-
{nodePath: n.nodePath + "." + ++num,
|
|
205
|
-
__useCallback: true,hasChildren: true,}
|
|
206
|
-
]
|
|
207
|
-
}}
|
|
208
|
-
>
|
|
209
|
-
{node.nodePath}
|
|
210
|
-
|
|
211
|
-
</TreeView>
|
|
212
|
-
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## selection
|
|
216
|
-
|
|
217
|
-
## search
|
|
218
|
-
|
|
219
|
-
## drag and drop
|
|
220
|
-
|
|
221
|
-
After setting dragAndDrop to true, you will be able to change order of nodes and moving them between nodes by dragging.When **isDraggable** on node is set to false you wont be able to grab it. You can enable nesting by setting timeToNest of pixerNestTreshold. Node will be inserted as child of targeted note after *at least one* of tresholds is met. Before node will be moved, **beforeMovedCallback** fill be fired and if it returns false, move will be cancelled.
|
|
222
|
-
New id will be computed as biggest id of childred in targeted node +1 and new priority as 0 when nest or if not as priority of target +1. Then it recomputes all priorities so there wont be conficts. After this **moved** event will be fired with old parent, old node (copy of dragged node before changes to id, priority, etc.),new node (dragged node after changes), and target node (node you drop it at).
|
|
223
|
-
You can also customize line show when dragging by changing **inserLineNestClass** and **inserLineClass**
|
|
224
|
-
|
|
225
|
-
**dragEnterCallback** is called when you enter new node while dragging. If it return false, node wont be valid node location
|
|
226
|
-
|
|
227
|
-
TODO add note about insertDisabled and nestDisabled
|
|
228
|
-
|
|
229
|
-
## context menu
|
|
230
|
-
|
|
231
|
-
To enable context menu you first need to add your desired context menu to slot named context-menu. you can accest clicked node with let:node. You can use MenuDivider and MenuOption from this package to easy creation of ctxmenu.Then just set **showContexMenu** to true and context menu will now be showen when you right click on node.
|
|
232
|
-
|
|
233
|
-
example:
|
|
234
|
-
|
|
235
|
-
```js
|
|
236
|
-
|
|
237
|
-
<TreeView
|
|
238
|
-
//...
|
|
239
|
-
showContexMenu
|
|
240
|
-
//...
|
|
241
|
-
>
|
|
242
|
-
//...
|
|
243
|
-
<svelte:fragment slot="context-menu" let:node>
|
|
244
|
-
<MenuOption text={node.nodePath} isDisabled />
|
|
245
|
-
<MenuDivider />
|
|
246
|
-
<MenuOption text="do stuff" on:click={(node) => doStuff(node)} />
|
|
247
|
-
</svelte:fragment>
|
|
248
|
-
<TreeView>
|
|
249
|
-
```
|
|
13
|
+
svelte-treeview is undergoing big upgrade righ now, so docs will be added later.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
<script>import { createEventDispatcher } from 'svelte';
|
|
2
|
+
import Checkbox from './Checkbox.svelte';
|
|
3
|
+
import { SelectionModes } from './types.js';
|
|
4
|
+
const dispatch = createEventDispatcher();
|
|
5
|
+
export let tree;
|
|
6
|
+
export let treeId;
|
|
7
|
+
export let recursive = false;
|
|
8
|
+
export let checkboxes = SelectionModes.none;
|
|
9
|
+
export let onlyLeafCheckboxes;
|
|
10
|
+
export let hideDisabledCheckboxes;
|
|
11
|
+
export let dragAndDrop;
|
|
12
|
+
export let verticalLines;
|
|
13
|
+
export let readonly;
|
|
14
|
+
export let expandTo;
|
|
15
|
+
export let classes;
|
|
16
|
+
export let helper;
|
|
17
|
+
export let draggedPath;
|
|
18
|
+
export let highlightedNode;
|
|
19
|
+
export let childDepth;
|
|
20
|
+
export let branchRootNode;
|
|
21
|
+
export let canNest;
|
|
22
|
+
export let validTarget;
|
|
23
|
+
export let insPos;
|
|
24
|
+
const getNodeId = (node) => `${treeId}-${helper.path(node)}`;
|
|
25
|
+
// get children nodes
|
|
26
|
+
function getChildren(tree) {
|
|
27
|
+
const directChildren = helper.getDirectChildren(tree, helper.path(branchRootNode));
|
|
28
|
+
const orderedChildren = helper.dragDrop.OrderByPriority(directChildren);
|
|
29
|
+
return orderedChildren;
|
|
30
|
+
}
|
|
31
|
+
function toggleExpansion(node) {
|
|
32
|
+
dispatch('internal-expand', { node: node });
|
|
33
|
+
}
|
|
34
|
+
function isExpanded(node, depth, expandToDepth) {
|
|
35
|
+
const nodeExpanded = helper.props.expanded(node);
|
|
36
|
+
//if expanded prop is defined it has priority over expand to
|
|
37
|
+
if (nodeExpanded === null) {
|
|
38
|
+
return depth <= expandToDepth;
|
|
39
|
+
}
|
|
40
|
+
return nodeExpanded;
|
|
41
|
+
}
|
|
42
|
+
//checkboxes
|
|
43
|
+
function selectionChanged(node) {
|
|
44
|
+
dispatch('internal-selectionChanged', { node: node });
|
|
45
|
+
}
|
|
46
|
+
// drag and drop
|
|
47
|
+
function handleDragStart(e, node) {
|
|
48
|
+
dispatch('internal-handleDragStart', { node: node, e: e });
|
|
49
|
+
}
|
|
50
|
+
function handleDragDrop(e, node, el) {
|
|
51
|
+
dispatch('internal-handleDragStart', { node: node, event: e, element: el });
|
|
52
|
+
}
|
|
53
|
+
function handleDragOver(e, node, el) {
|
|
54
|
+
dispatch('internal-handleDragOver', { node: node, event: e, element: el });
|
|
55
|
+
}
|
|
56
|
+
function handleDragEnter(e, node, el) {
|
|
57
|
+
dispatch('internal-handleDragEnter', { node: node, event: e, element: el });
|
|
58
|
+
}
|
|
59
|
+
function handleDragEnd(e, node) {
|
|
60
|
+
dispatch('internal-handleDragEnd', { node: node, event: e });
|
|
61
|
+
}
|
|
62
|
+
function handleDragLeave(e, node, el) {
|
|
63
|
+
dispatch('internal-handleDragLeave', { node: node, event: e, element: el });
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
*check if this node is one being hovered over (highlited) and is valid target
|
|
67
|
+
*/
|
|
68
|
+
function highlighThisNode(node, highlitedNode, validTarget) {
|
|
69
|
+
return validTarget && helper.path(highlitedNode) == helper.path(node);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* returns true, it should highlight nesting on this node
|
|
73
|
+
* @param node node
|
|
74
|
+
* @param highlitedNode highlited node
|
|
75
|
+
* @param validTarget valid target
|
|
76
|
+
* @param canNest can nest
|
|
77
|
+
*/
|
|
78
|
+
function highlightNesting(node, highlitedNode, validTarget, canNest) {
|
|
79
|
+
return (canNest &&
|
|
80
|
+
highlighThisNode(node, highlitedNode, validTarget) &&
|
|
81
|
+
helper.props.nestDisabled(node) !== true);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* returns true, it should highlight nesting on this node
|
|
85
|
+
* @param node node
|
|
86
|
+
* @param highlitedNode highlited node
|
|
87
|
+
* @param validTarget valid target
|
|
88
|
+
* @param canNest can nest
|
|
89
|
+
*/
|
|
90
|
+
function highlightInsert(node, highlitedNode, validTarget, canNest) {
|
|
91
|
+
return (!canNest &&
|
|
92
|
+
highlighThisNode(node, highlitedNode, validTarget) &&
|
|
93
|
+
helper.props.nestDisabled(node) !== true);
|
|
94
|
+
}
|
|
95
|
+
let liElements = {};
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<ul
|
|
99
|
+
class:show-lines={childDepth === 0 && verticalLines}
|
|
100
|
+
class:child-menu={childDepth > 0}
|
|
101
|
+
class={childDepth === 0 ? classes.treeClass : ''}
|
|
102
|
+
>
|
|
103
|
+
{#each getChildren(tree) as node (getNodeId(node))}
|
|
104
|
+
{@const nesthighlighed = highlightNesting(node, highlightedNode, validTarget, canNest)}
|
|
105
|
+
{@const insertHighlighted = highlightInsert(node, highlightedNode, validTarget, canNest)}
|
|
106
|
+
{@const expanded = isExpanded(node, childDepth, expandTo)}
|
|
107
|
+
{@const hasChildren = helper.props.hasChildren(node)}
|
|
108
|
+
{@const draggable = !readonly && dragAndDrop && helper.props.isDraggable(node)}
|
|
109
|
+
{@const isCurrentlyDragged =
|
|
110
|
+
draggedPath == helper.path(node) ||
|
|
111
|
+
(draggedPath && helper.path(node)?.startsWith(draggedPath))}
|
|
112
|
+
|
|
113
|
+
<li
|
|
114
|
+
class:is-child={helper.nodePathIsChild(helper.path(node))}
|
|
115
|
+
class:has-children={hasChildren}
|
|
116
|
+
on:contextmenu|stopPropagation={(e) => {
|
|
117
|
+
dispatch('open-ctxmenu', { e: e, node: Node });
|
|
118
|
+
}}
|
|
119
|
+
on:drop|stopPropagation={(e) => handleDragDrop(e, node, liElements[getNodeId(node)])}
|
|
120
|
+
on:dragover|stopPropagation={(e) => handleDragOver(e, node, liElements[getNodeId(node)])}
|
|
121
|
+
on:dragenter|stopPropagation={(e) => handleDragEnter(e, node, liElements[getNodeId(node)])}
|
|
122
|
+
on:dragleave|stopPropagation={(e) => handleDragLeave(e, node, liElements[getNodeId(node)])}
|
|
123
|
+
bind:this={liElements[getNodeId(node)]}
|
|
124
|
+
>
|
|
125
|
+
{#if insPos == 1 && insertHighlighted}
|
|
126
|
+
<div class="insert-line-wrapper">
|
|
127
|
+
<div class="insert-line {classes.inserLineClass}" />
|
|
128
|
+
</div>
|
|
129
|
+
{/if}
|
|
130
|
+
|
|
131
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
132
|
+
<div
|
|
133
|
+
class="tree-item
|
|
134
|
+
{nesthighlighed ? classes.expandClass : ''}
|
|
135
|
+
{classes.nodeClass} {isCurrentlyDragged ? classes.currentlyDraggedClass : ''}"
|
|
136
|
+
class:div-has-children={hasChildren}
|
|
137
|
+
class:hover={insertHighlighted || nesthighlighed}
|
|
138
|
+
{draggable}
|
|
139
|
+
on:dragstart={(e) => handleDragStart(e, node)}
|
|
140
|
+
on:dragend={(e) => handleDragEnd(e, node)}
|
|
141
|
+
>
|
|
142
|
+
{#if hasChildren}
|
|
143
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
144
|
+
<span on:click={() => toggleExpansion(node)}>
|
|
145
|
+
<!-- use callback overrides expanded -->
|
|
146
|
+
<i
|
|
147
|
+
class="far {expanded ? classes.expandedToggleClass : classes.collapsedToggleClass}"
|
|
148
|
+
class:fa-minus-square={expanded}
|
|
149
|
+
class:fa-plus-square={!expanded || helper.props.useCallback(node)}
|
|
150
|
+
/>
|
|
151
|
+
</span>
|
|
152
|
+
{:else}
|
|
153
|
+
<span />
|
|
154
|
+
{/if}
|
|
155
|
+
|
|
156
|
+
<Checkbox
|
|
157
|
+
{checkboxes}
|
|
158
|
+
{helper}
|
|
159
|
+
{recursive}
|
|
160
|
+
{node}
|
|
161
|
+
{onlyLeafCheckboxes}
|
|
162
|
+
{hideDisabledCheckboxes}
|
|
163
|
+
{readonly}
|
|
164
|
+
on:select={({ detail: { node } }) => selectionChanged(node)}
|
|
165
|
+
/>
|
|
166
|
+
<span class:pointer-cursor={draggable}>
|
|
167
|
+
<slot {node} />
|
|
168
|
+
</span>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{#if nesthighlighed}
|
|
172
|
+
<div class="insert-line-wrapper">
|
|
173
|
+
<div
|
|
174
|
+
class="insert-line insert-line-child {classes.inserLineClass} {classes.inserLineNestClass}"
|
|
175
|
+
/>
|
|
176
|
+
</div>
|
|
177
|
+
{/if}
|
|
178
|
+
{#if expanded && hasChildren}
|
|
179
|
+
<svelte:self
|
|
180
|
+
branchRootNode={node}
|
|
181
|
+
childDepth={childDepth + 1}
|
|
182
|
+
{treeId}
|
|
183
|
+
{checkboxes}
|
|
184
|
+
{tree}
|
|
185
|
+
{recursive}
|
|
186
|
+
{helper}
|
|
187
|
+
{classes}
|
|
188
|
+
{readonly}
|
|
189
|
+
{onlyLeafCheckboxes}
|
|
190
|
+
{hideDisabledCheckboxes}
|
|
191
|
+
{expandTo}
|
|
192
|
+
{draggedPath}
|
|
193
|
+
{dragAndDrop}
|
|
194
|
+
{verticalLines}
|
|
195
|
+
{canNest}
|
|
196
|
+
{insPos}
|
|
197
|
+
{validTarget}
|
|
198
|
+
{highlightedNode}
|
|
199
|
+
on:open-ctxmenu
|
|
200
|
+
on:internal-expand
|
|
201
|
+
on:internal-selectionChanged
|
|
202
|
+
let:node={nodeNested}
|
|
203
|
+
>
|
|
204
|
+
<slot node={nodeNested} />
|
|
205
|
+
</svelte:self>
|
|
206
|
+
{/if}
|
|
207
|
+
{#if !expanded && hasChildren}
|
|
208
|
+
<ul class:child-menu={childDepth > 0} />
|
|
209
|
+
{/if}
|
|
210
|
+
<!-- Show line if insering -->
|
|
211
|
+
{#if insPos == -1 && insertHighlighted}
|
|
212
|
+
<div class="insert-line-wrapper">
|
|
213
|
+
<div class="insert-line {classes.inserLineClass}" />
|
|
214
|
+
</div>
|
|
215
|
+
{/if}
|
|
216
|
+
</li>
|
|
217
|
+
{/each}
|
|
218
|
+
</ul>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { SelectionModes, type InsertionType, type Node } from './types.js';
|
|
3
|
+
import type { CustomizableClasses, TreeHelper } from './index.js';
|
|
4
|
+
declare const __propDef: {
|
|
5
|
+
props: {
|
|
6
|
+
tree: Node[];
|
|
7
|
+
treeId: string;
|
|
8
|
+
recursive?: boolean | undefined;
|
|
9
|
+
checkboxes?: SelectionModes | undefined;
|
|
10
|
+
onlyLeafCheckboxes: boolean;
|
|
11
|
+
hideDisabledCheckboxes: boolean;
|
|
12
|
+
dragAndDrop: boolean;
|
|
13
|
+
verticalLines: boolean;
|
|
14
|
+
readonly: boolean;
|
|
15
|
+
expandTo: number;
|
|
16
|
+
classes: CustomizableClasses;
|
|
17
|
+
helper: TreeHelper;
|
|
18
|
+
draggedPath: string | null;
|
|
19
|
+
highlightedNode: Node;
|
|
20
|
+
childDepth: number;
|
|
21
|
+
branchRootNode: Node | null;
|
|
22
|
+
canNest: boolean;
|
|
23
|
+
validTarget: boolean;
|
|
24
|
+
insPos: InsertionType;
|
|
25
|
+
};
|
|
26
|
+
events: {
|
|
27
|
+
'open-ctxmenu': CustomEvent<any>;
|
|
28
|
+
'internal-expand': CustomEvent<any>;
|
|
29
|
+
'internal-selectionChanged': CustomEvent<any>;
|
|
30
|
+
'internal-handleDragStart': CustomEvent<any>;
|
|
31
|
+
'internal-handleDragOver': CustomEvent<any>;
|
|
32
|
+
'internal-handleDragEnter': CustomEvent<any>;
|
|
33
|
+
'internal-handleDragEnd': CustomEvent<any>;
|
|
34
|
+
'internal-handleDragLeave': CustomEvent<any>;
|
|
35
|
+
} & {
|
|
36
|
+
[evt: string]: CustomEvent<any>;
|
|
37
|
+
};
|
|
38
|
+
slots: {
|
|
39
|
+
default: {
|
|
40
|
+
node: any;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export type BranchProps = typeof __propDef.props;
|
|
45
|
+
export type BranchEvents = typeof __propDef.events;
|
|
46
|
+
export type BranchSlots = typeof __propDef.slots;
|
|
47
|
+
export default class Branch extends SvelteComponent<BranchProps, BranchEvents, BranchSlots> {
|
|
48
|
+
}
|
|
49
|
+
export {};
|
package/dist/Checkbox.svelte
CHANGED
|
@@ -1,58 +1,61 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
<script>import { createEventDispatcher } from 'svelte';
|
|
2
|
+
import { SelectionModes } from './types.js';
|
|
3
|
+
export let checkboxes;
|
|
4
|
+
export let helper;
|
|
5
|
+
export let recursive;
|
|
6
|
+
export let node;
|
|
7
|
+
export let onlyLeafCheckboxes;
|
|
8
|
+
export let hideDisabledCheckboxes;
|
|
9
|
+
export let readonly = false;
|
|
10
|
+
let indeterminate;
|
|
11
|
+
$: {
|
|
12
|
+
if (helper.props.visualState(node) == 'indeterminate') {
|
|
13
|
+
indeterminate = true;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
indeterminate = false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const dispatch = createEventDispatcher();
|
|
20
|
+
function onSelect(node) {
|
|
21
|
+
dispatch('select', { node });
|
|
22
|
+
}
|
|
16
23
|
</script>
|
|
17
24
|
|
|
18
|
-
{#if checkboxes ==
|
|
25
|
+
{#if checkboxes == SelectionModes.perNode || checkboxes == SelectionModes.all}
|
|
19
26
|
{#if helper.selection.isSelectable(node, checkboxes)}
|
|
20
27
|
<!-- select node -->
|
|
21
|
-
{#if !recursive || (recursive && !
|
|
28
|
+
{#if !recursive || (recursive && !helper.props.hasChildren(node))}
|
|
22
29
|
<input
|
|
23
30
|
type="checkbox"
|
|
24
|
-
on:change={() =>
|
|
25
|
-
checked={
|
|
31
|
+
on:change={() => onSelect(node)}
|
|
32
|
+
checked={helper.props.selected(node)}
|
|
26
33
|
disabled={readonly}
|
|
27
34
|
/>
|
|
28
35
|
<!-- select children-->
|
|
29
36
|
{:else if !onlyLeafCheckboxes}
|
|
37
|
+
<!-- @ts-ingore -->
|
|
30
38
|
<input
|
|
31
39
|
type="checkbox"
|
|
32
|
-
on:click={() =>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
checked: node.__visual_state == 'true'
|
|
36
|
-
});
|
|
37
|
-
}}
|
|
38
|
-
checked={node.__visual_state == 'true' ? 'false' : ''}
|
|
39
|
-
indeterminate={node.__visual_state == 'indeterminate'}
|
|
40
|
+
on:click={() => onSelect(node)}
|
|
41
|
+
checked={helper.props.visualState(node) == 'true'}
|
|
42
|
+
bind:indeterminate
|
|
40
43
|
disabled={readonly}
|
|
41
44
|
/>
|
|
42
45
|
{:else}
|
|
43
46
|
<input
|
|
44
47
|
type="checkbox"
|
|
45
|
-
|
|
48
|
+
on:click|preventDefault={null}
|
|
46
49
|
disabled={true}
|
|
47
|
-
class:invisible={
|
|
50
|
+
class:invisible={hideDisabledCheckboxes}
|
|
48
51
|
/>
|
|
49
52
|
{/if}
|
|
50
53
|
{:else}
|
|
51
54
|
<input
|
|
52
55
|
type="checkbox"
|
|
53
|
-
|
|
56
|
+
on:click|preventDefault|stopPropagation
|
|
54
57
|
disabled={true}
|
|
55
|
-
class:invisible={
|
|
58
|
+
class:invisible={hideDisabledCheckboxes}
|
|
56
59
|
/>
|
|
57
60
|
{/if}
|
|
58
61
|
{/if}
|
|
@@ -1,41 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export default class Checkbox extends SvelteComponentTyped<{
|
|
5
|
-
checkboxes: any;
|
|
6
|
-
helper: any;
|
|
7
|
-
recursive: any;
|
|
8
|
-
node: any;
|
|
9
|
-
onlyLeafCheckboxes: any;
|
|
10
|
-
checkboxesDisabled: any;
|
|
11
|
-
readonly?: boolean | undefined;
|
|
12
|
-
}, {
|
|
13
|
-
select: CustomEvent<any>;
|
|
14
|
-
'select-children': CustomEvent<any>;
|
|
15
|
-
} & {
|
|
16
|
-
[evt: string]: CustomEvent<any>;
|
|
17
|
-
}, {}> {
|
|
18
|
-
}
|
|
19
|
-
export type CheckboxProps = typeof __propDef.props;
|
|
20
|
-
export type CheckboxEvents = typeof __propDef.events;
|
|
21
|
-
export type CheckboxSlots = typeof __propDef.slots;
|
|
22
|
-
import { SvelteComponentTyped } from "svelte";
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { SelectionModes, type Node } from './types.js';
|
|
3
|
+
import type { TreeHelper } from './index.js';
|
|
23
4
|
declare const __propDef: {
|
|
24
5
|
props: {
|
|
25
|
-
checkboxes:
|
|
26
|
-
helper:
|
|
27
|
-
recursive:
|
|
28
|
-
node:
|
|
29
|
-
onlyLeafCheckboxes:
|
|
30
|
-
|
|
6
|
+
checkboxes: SelectionModes;
|
|
7
|
+
helper: TreeHelper;
|
|
8
|
+
recursive: boolean;
|
|
9
|
+
node: Node;
|
|
10
|
+
onlyLeafCheckboxes: boolean;
|
|
11
|
+
hideDisabledCheckboxes: boolean;
|
|
31
12
|
readonly?: boolean | undefined;
|
|
32
13
|
};
|
|
33
14
|
events: {
|
|
15
|
+
click: MouseEvent;
|
|
34
16
|
select: CustomEvent<any>;
|
|
35
|
-
'select-children': CustomEvent<any>;
|
|
36
17
|
} & {
|
|
37
18
|
[evt: string]: CustomEvent<any>;
|
|
38
19
|
};
|
|
39
20
|
slots: {};
|
|
40
21
|
};
|
|
22
|
+
export type CheckboxProps = typeof __propDef.props;
|
|
23
|
+
export type CheckboxEvents = typeof __propDef.events;
|
|
24
|
+
export type CheckboxSlots = typeof __propDef.slots;
|
|
25
|
+
export default class Checkbox extends SvelteComponent<CheckboxProps, CheckboxEvents, CheckboxSlots> {
|
|
26
|
+
}
|
|
41
27
|
export {};
|