@keenmate/svelte-treeview 0.1.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 +249 -0
- package/dist/Checkbox.svelte +58 -0
- package/dist/Checkbox.svelte.d.ts +41 -0
- package/dist/TreeView.svelte +562 -0
- package/dist/TreeView.svelte.d.ts +65 -0
- package/dist/consts.d.ts +28 -0
- package/dist/consts.js +31 -0
- package/dist/helpers/drag-drop-helpers.d.ts +29 -0
- package/dist/helpers/drag-drop-helpers.js +193 -0
- package/dist/helpers/selection-helpers.d.ts +22 -0
- package/dist/helpers/selection-helpers.js +182 -0
- package/dist/helpers/tree-helper.d.ts +33 -0
- package/dist/helpers/tree-helper.js +169 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/menu/ContextMenu.svelte +33 -0
- package/dist/menu/ContextMenu.svelte.d.ts +32 -0
- package/dist/menu/Menu.svelte +50 -0
- package/dist/menu/Menu.svelte.d.ts +35 -0
- package/dist/menu/MenuDivider.svelte +10 -0
- package/dist/menu/MenuDivider.svelte.d.ts +23 -0
- package/dist/menu/MenuOption.svelte +49 -0
- package/dist/menu/MenuOption.svelte.d.ts +33 -0
- package/dist/menu/menu.d.ts +1 -0
- package/dist/menu/menu.js +3 -0
- package/package.json +63 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
<script>// TODO this is just temporary untill i finish migrating
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import ContextMenu from './menu/ContextMenu.svelte';
|
|
4
|
+
import { createEventDispatcher, onMount } from 'svelte';
|
|
5
|
+
import createTreeHelper from './helpers/tree-helper';
|
|
6
|
+
import { checkboxesType, defaultCurrentlyDraggedClass, defaultExpandClass, defaultPixelTreshold, defaultPropNames, defaultTreeClass } from './consts';
|
|
7
|
+
import Checkbox from './Checkbox.svelte';
|
|
8
|
+
const dispatch = createEventDispatcher();
|
|
9
|
+
//! required
|
|
10
|
+
export let tree; //array of nodes with nodePath
|
|
11
|
+
export let treeId; //string
|
|
12
|
+
//!user set
|
|
13
|
+
//tree that will be rendered(will be same as tree if null)
|
|
14
|
+
export let filteredTree = null; //array of nodes with nodePath
|
|
15
|
+
export let recursive = false; //bool
|
|
16
|
+
export let checkboxes = checkboxesType.none; //bool on of [all,perNode]
|
|
17
|
+
//if true, will show checkboxes to elements with children
|
|
18
|
+
//TODO make batter name
|
|
19
|
+
export let onlyLeafCheckboxes = false; //bool
|
|
20
|
+
//true = disabel hide = false
|
|
21
|
+
export let checkboxesDisabled = false; //bool
|
|
22
|
+
//will allow you to move nodes between nodes and reorder them
|
|
23
|
+
export let dragAndDrop = false; //bool
|
|
24
|
+
//will nest of at least one of them is meet
|
|
25
|
+
export let timeToNest = null;
|
|
26
|
+
export let pixelNestTreshold = defaultPixelTreshold;
|
|
27
|
+
//change to false when last segment of nodePath is Guaranteed to be unqiue
|
|
28
|
+
export let recalculateNodePath = true;
|
|
29
|
+
//callback for dynamically disabling drop on specific node
|
|
30
|
+
export let dragEnterCallback = null;
|
|
31
|
+
export let beforeMovedCallback = null;
|
|
32
|
+
export let showContexMenu = false;
|
|
33
|
+
export let enableVerticalLines = false;
|
|
34
|
+
export let readonly = false;
|
|
35
|
+
export let separator = '.';
|
|
36
|
+
export let expandedLevel = 0;
|
|
37
|
+
export let expandCallback = null;
|
|
38
|
+
//* classes for customization of tree
|
|
39
|
+
export let treeClass = defaultTreeClass;
|
|
40
|
+
export let nodeClass = null;
|
|
41
|
+
export let expandedToggleClass = null;
|
|
42
|
+
export let collapsedToggleClass = null;
|
|
43
|
+
export let expandClass = defaultExpandClass;
|
|
44
|
+
export let inserLineClass = null;
|
|
45
|
+
export let inserLineNestClass = null;
|
|
46
|
+
export let currentlyDraggedClass = defaultCurrentlyDraggedClass;
|
|
47
|
+
//* properties
|
|
48
|
+
export let props = {};
|
|
49
|
+
$: propNames = { ...defaultPropNames, ...props };
|
|
50
|
+
//! DONT SET ONLY USED INTERNALLY
|
|
51
|
+
//TODO use context instead
|
|
52
|
+
//path of currently dragged node
|
|
53
|
+
export let draggedPath = null;
|
|
54
|
+
export let highlightedNode = null;
|
|
55
|
+
export let childDepth = 0; //number
|
|
56
|
+
export let branchRootNode = undefined;
|
|
57
|
+
let dragenterTimestamp;
|
|
58
|
+
//
|
|
59
|
+
let canNestPos = false;
|
|
60
|
+
let canNestTime = false;
|
|
61
|
+
let canNest;
|
|
62
|
+
let dragTimeout;
|
|
63
|
+
let validTarget = false;
|
|
64
|
+
let insPos;
|
|
65
|
+
//if insert is disabled => nest right away and never nest if its disabled
|
|
66
|
+
$: canNest =
|
|
67
|
+
(highlightedNode?.[propNames.insertDisabled] || canNestPos || canNestTime) &&
|
|
68
|
+
highlightedNode?.[propNames.nestDisabled] !== true;
|
|
69
|
+
//
|
|
70
|
+
let ctxMenu;
|
|
71
|
+
const getNodeId = (node) => `${treeId}-${helper.path(node)}`;
|
|
72
|
+
// get new helper when propNames change
|
|
73
|
+
$: config = {
|
|
74
|
+
recursive,
|
|
75
|
+
recalculateNodePath,
|
|
76
|
+
checkboxes,
|
|
77
|
+
separator
|
|
78
|
+
};
|
|
79
|
+
$: helper = createTreeHelper(propNames, config);
|
|
80
|
+
// get children nodes
|
|
81
|
+
function getChildren() {
|
|
82
|
+
return helper.dragDrop.OrderByPriority(helper.getDirectChildren(filteredTree ?? tree, helper.path(branchRootNode)));
|
|
83
|
+
}
|
|
84
|
+
//#region expansions
|
|
85
|
+
function toggleExpansion(node, expanded) {
|
|
86
|
+
helper.changeExpansion(tree, node, !expanded);
|
|
87
|
+
//update expansion
|
|
88
|
+
tree = tree;
|
|
89
|
+
let val = node[propNames.expanded];
|
|
90
|
+
//trigger callback if it is present and node has useCallback
|
|
91
|
+
if (val && expandCallback !== null && node[propNames.useCallback] === true) {
|
|
92
|
+
//console.log("calling callback");
|
|
93
|
+
node[propNames.useCallback] = false;
|
|
94
|
+
expandCallback(node)
|
|
95
|
+
.then((val) => {
|
|
96
|
+
tree = tree.concat(val);
|
|
97
|
+
})
|
|
98
|
+
.catch((reason) => {
|
|
99
|
+
console.log('ERROR IN CALLBACK!!');
|
|
100
|
+
console.log(reason);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//expansion events
|
|
104
|
+
dispatch('expansion', {
|
|
105
|
+
node: node,
|
|
106
|
+
value: val
|
|
107
|
+
});
|
|
108
|
+
if (val) {
|
|
109
|
+
dispatch('expanded', node);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
dispatch('closed', node);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export function changeAllExpansion(changeTo) {
|
|
116
|
+
tree = helper.changeEveryExpansion(tree, changeTo);
|
|
117
|
+
}
|
|
118
|
+
function isExpanded(node, depth, expandTo) {
|
|
119
|
+
const nodeExpanded = node[propNames.expanded];
|
|
120
|
+
//if expanded prop is defined it has priority over expand to
|
|
121
|
+
if (nodeExpanded !== undefined && nodeExpanded !== null) {
|
|
122
|
+
return nodeExpanded;
|
|
123
|
+
}
|
|
124
|
+
return depth <= expandTo;
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region checkboxes
|
|
128
|
+
// TODO maybe optimize and only compute visual tree for changed branches
|
|
129
|
+
$: ComputeVisualTree(filteredTree);
|
|
130
|
+
function ComputeVisualTree(filteredTree) {
|
|
131
|
+
tree = helper.selection.computeInitialVisualStates(tree, filteredTree ?? tree);
|
|
132
|
+
}
|
|
133
|
+
//checkboxes
|
|
134
|
+
function selectionChanged(node) {
|
|
135
|
+
//console.log(nodePath);
|
|
136
|
+
tree = helper.selection.changeSelection(tree, helper.path(node), filteredTree ?? tree);
|
|
137
|
+
selectionEvents(node);
|
|
138
|
+
}
|
|
139
|
+
//fired when in recursive mode you click on Leaf node
|
|
140
|
+
function selectChildren(node, checked) {
|
|
141
|
+
tree = helper.selection.changeSelectedForChildren(tree, helper.path(node), !checked, filteredTree ?? tree);
|
|
142
|
+
selectionEvents(node);
|
|
143
|
+
}
|
|
144
|
+
function selectionEvents(node) {
|
|
145
|
+
let val = node[propNames.selected];
|
|
146
|
+
dispatch('selection', {
|
|
147
|
+
node: node,
|
|
148
|
+
value: val
|
|
149
|
+
});
|
|
150
|
+
if (val) {
|
|
151
|
+
dispatch('selected', node);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
dispatch('unselected', node);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region drag and drop
|
|
159
|
+
function handleDragStart(e, node) {
|
|
160
|
+
// dont allos drag if is draggable is false
|
|
161
|
+
if (node[propNames.isDraggable] === false) {
|
|
162
|
+
e.preventDefault();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
console.log('dragstart from: ' + helper.path(node));
|
|
166
|
+
e.dataTransfer.dropEffect = 'move';
|
|
167
|
+
e.dataTransfer.setData('node_id', helper.path(node));
|
|
168
|
+
draggedPath = helper.path(node);
|
|
169
|
+
}
|
|
170
|
+
function handleDragDrop(e, node, el) {
|
|
171
|
+
//should be necesary but just in case
|
|
172
|
+
highlightedNode = null;
|
|
173
|
+
if (readonly || !dragAndDrop)
|
|
174
|
+
return;
|
|
175
|
+
draggedPath = e.dataTransfer.getData('node_id');
|
|
176
|
+
console.log(draggedPath + ' dropped on: ' + helper.path(node));
|
|
177
|
+
//important to check if timetonest is set, otherwise you could spend 30 minutes fixing this shit :)
|
|
178
|
+
if (timeToNest) {
|
|
179
|
+
canNestTime = (dragenterTimestamp ? new Date() - dragenterTimestamp : 1) > timeToNest;
|
|
180
|
+
}
|
|
181
|
+
let newNode = helper.findNode(tree, draggedPath);
|
|
182
|
+
let oldNode = { ...newNode };
|
|
183
|
+
let oldParent = helper.findNode(tree, helper.getParentNodePath(draggedPath));
|
|
184
|
+
let insType = canNest ? 0 : helper.dragDrop.getInsertionPosition(e, el);
|
|
185
|
+
//cancel move if its not valid
|
|
186
|
+
if (insType == 0 && node[propNames.nestDisabled] === true)
|
|
187
|
+
return;
|
|
188
|
+
else if ((insType == -1 || insType == 1) && node[propNames.insertDisabled] === true)
|
|
189
|
+
return;
|
|
190
|
+
//callback can cancell move
|
|
191
|
+
if (beforeMovedCallback &&
|
|
192
|
+
beforeMovedCallback(oldNode, oldParent, node, helper.dragDrop.huminifyInsType(insType)) ===
|
|
193
|
+
false)
|
|
194
|
+
return;
|
|
195
|
+
tree = helper.dragDrop.moveNode(tree, draggedPath, helper.path(node), insType, recalculateNodePath);
|
|
196
|
+
let newParent = helper.findNode(tree, helper.getParentNodePath(helper.path(newNode))) ?? null;
|
|
197
|
+
dispatch('moved', {
|
|
198
|
+
oldParent: oldParent,
|
|
199
|
+
newParent: newParent,
|
|
200
|
+
oldNode: oldNode,
|
|
201
|
+
newNode: newNode,
|
|
202
|
+
targetNode: node,
|
|
203
|
+
insType: helper.dragDrop.huminifyInsType(insType)
|
|
204
|
+
});
|
|
205
|
+
//reset props
|
|
206
|
+
dragenterTimestamp = null;
|
|
207
|
+
draggedPath = null;
|
|
208
|
+
highlightedNode = null;
|
|
209
|
+
}
|
|
210
|
+
function handleDragOver(e, node, el) {
|
|
211
|
+
insPos = helper.dragDrop.getInsertionPosition(e, el);
|
|
212
|
+
//if you are further away from right then treshold allow nesting
|
|
213
|
+
let diff = e.x - e.target.getBoundingClientRect().x;
|
|
214
|
+
if (pixelNestTreshold && diff > pixelNestTreshold) {
|
|
215
|
+
canNestPos = true;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
canNestPos = false;
|
|
219
|
+
}
|
|
220
|
+
//allow drop if valid target
|
|
221
|
+
if (validTarget)
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
}
|
|
224
|
+
function handleDragEnter(e, node, el) {
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
insPos = helper.dragDrop.getInsertionPosition(e, el);
|
|
227
|
+
validTarget = true;
|
|
228
|
+
dragenterTimestamp = new Date();
|
|
229
|
+
// will cause flashing when moving wrom node to node while be able to nest
|
|
230
|
+
//* have to be here if you only use time
|
|
231
|
+
highlightedNode = node;
|
|
232
|
+
if (timeToNest) {
|
|
233
|
+
canNestTime = false;
|
|
234
|
+
//this is so that only one timeout is ticking at one time
|
|
235
|
+
clearTimeout(dragTimeout);
|
|
236
|
+
dragTimeout = setTimeout(() => {
|
|
237
|
+
canNestTime = true;
|
|
238
|
+
}, timeToNest);
|
|
239
|
+
}
|
|
240
|
+
//dont allow drop on child element and if both insertDisabled and nestDisabled to true
|
|
241
|
+
if (helper.path(node).startsWith(draggedPath) ||
|
|
242
|
+
(node[propNames.insertDisabled] === true && node[propNames.nestDisabled] === true)) {
|
|
243
|
+
validTarget = false;
|
|
244
|
+
}
|
|
245
|
+
//if defined calling callback
|
|
246
|
+
if (dragEnterCallback) {
|
|
247
|
+
//get node for event
|
|
248
|
+
let draggedNode = helper.findNode(tree, draggedPath);
|
|
249
|
+
let oldParent = helper.findNode(tree, helper.getParentNodePath(draggedPath));
|
|
250
|
+
//callback returning false means that it isnt valid target
|
|
251
|
+
if (dragEnterCallback(draggedNode, oldParent, node) === false) {
|
|
252
|
+
validTarget = false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}, 1);
|
|
256
|
+
e.preventDefault();
|
|
257
|
+
}
|
|
258
|
+
function handleDragEnd(e, node) {
|
|
259
|
+
//reset prop on next tick
|
|
260
|
+
setTimeout(() => {
|
|
261
|
+
draggedPath = null;
|
|
262
|
+
highlightedNode = null;
|
|
263
|
+
}, 1);
|
|
264
|
+
}
|
|
265
|
+
function handleDragleave(e, node) {
|
|
266
|
+
// highlightedNode = null;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
*check if this node is one being hovered over (highlited) and is valid target
|
|
270
|
+
*/
|
|
271
|
+
function highlighThisNode(node, highlitedNode, validTarget) {
|
|
272
|
+
return validTarget && helper.path(highlitedNode) == helper.path(node);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* returns true, it should highlight nesting on this node
|
|
276
|
+
* @param node node
|
|
277
|
+
* @param highlitedNode highlited node
|
|
278
|
+
* @param validTarget valid target
|
|
279
|
+
* @param canNest can nest
|
|
280
|
+
*/
|
|
281
|
+
function highlightNesting(node, highlitedNode, validTarget, canNest) {
|
|
282
|
+
return (canNest &&
|
|
283
|
+
highlighThisNode(node, highlitedNode, validTarget) &&
|
|
284
|
+
node[propNames.nestDisabled] !== true);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* returns true, it should highlight nesting on this node
|
|
288
|
+
* @param node node
|
|
289
|
+
* @param highlitedNode highlited node
|
|
290
|
+
* @param validTarget valid target
|
|
291
|
+
* @param canNest can nest
|
|
292
|
+
*/
|
|
293
|
+
function highlightInsert(node, highlitedNode, validTarget, canNest) {
|
|
294
|
+
return (!canNest &&
|
|
295
|
+
highlighThisNode(node, highlitedNode, validTarget) &&
|
|
296
|
+
node[propNames.insertDisabled] !== true);
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
//#region context menu
|
|
300
|
+
function openContextMenu(e, node) {
|
|
301
|
+
if (!showContexMenu)
|
|
302
|
+
return;
|
|
303
|
+
e.preventDefault();
|
|
304
|
+
ctxMenu.onRightClick(e, node);
|
|
305
|
+
}
|
|
306
|
+
//#endregion
|
|
307
|
+
//computes all visual states when component is first created
|
|
308
|
+
onMount(() => {
|
|
309
|
+
tree = helper.selection.computeInitialVisualStates(tree, filteredTree ?? tree);
|
|
310
|
+
});
|
|
311
|
+
$: tree, tree == null || tree == undefined ? (tree = []) : '';
|
|
312
|
+
let liElements = [];
|
|
313
|
+
</script>
|
|
314
|
+
|
|
315
|
+
<ul
|
|
316
|
+
class:show-lines={childDepth === 0 && enableVerticalLines}
|
|
317
|
+
class:child-menu={childDepth > 0}
|
|
318
|
+
class={childDepth === 0 ? treeClass : ''}
|
|
319
|
+
>
|
|
320
|
+
{#each getChildren(tree, filteredTree) as node (getNodeId(node))}
|
|
321
|
+
{@const nesthighlighed = highlightNesting(node, highlightedNode, validTarget, canNest)}
|
|
322
|
+
{@const insertHighlighted = highlightInsert(node, highlightedNode, validTarget, canNest)}
|
|
323
|
+
{@const expanded = isExpanded(node, childDepth, expandedLevel)}
|
|
324
|
+
{@const hasChildren = node[propNames.hasChildren]}
|
|
325
|
+
{@const draggable = !readonly && dragAndDrop && node[propNames.isDraggable] !== false}
|
|
326
|
+
<li
|
|
327
|
+
class:is-child={helper.nodePathIsChild(helper.path(node))}
|
|
328
|
+
class:has-children={hasChildren}
|
|
329
|
+
on:contextmenu|stopPropagation={(e) => {
|
|
330
|
+
childDepth == 0 ? openContextMenu(e, node) : dispatch('open-ctxmenu', { e: e, node: node });
|
|
331
|
+
}}
|
|
332
|
+
on:drop|stopPropagation={(e) => handleDragDrop(e, node, liElements[getNodeId(node)])}
|
|
333
|
+
on:dragover|stopPropagation={(e) => handleDragOver(e, node, liElements[getNodeId(node)])}
|
|
334
|
+
on:dragenter|stopPropagation={(e) => handleDragEnter(e, node, liElements[getNodeId(node)])}
|
|
335
|
+
on:dragleave|stopPropagation={(e) => handleDragleave(e, node, liElements[getNodeId(node)])}
|
|
336
|
+
bind:this={liElements[getNodeId(node)]}
|
|
337
|
+
>
|
|
338
|
+
{#if insPos == 1 && insertHighlighted}
|
|
339
|
+
<div class="insert-line-wrapper">
|
|
340
|
+
<div class="insert-line {inserLineClass}" />
|
|
341
|
+
</div>
|
|
342
|
+
{/if}
|
|
343
|
+
|
|
344
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
345
|
+
<div
|
|
346
|
+
class="tree-item
|
|
347
|
+
{nesthighlighed ? expandClass : ''}
|
|
348
|
+
{nodeClass} {draggedPath == helper.path(node) || helper.path(node)?.startsWith(draggedPath)
|
|
349
|
+
? currentlyDraggedClass
|
|
350
|
+
: ''}"
|
|
351
|
+
class:div-has-children={hasChildren}
|
|
352
|
+
class:hover={insertHighlighted || nesthighlighed}
|
|
353
|
+
{draggable}
|
|
354
|
+
on:dragstart={(e) => handleDragStart(e, node)}
|
|
355
|
+
on:dragend={(e) => handleDragEnd(e, node)}
|
|
356
|
+
>
|
|
357
|
+
{#if hasChildren}
|
|
358
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
359
|
+
<span on:click={() => toggleExpansion(node, expanded && !node[propNames.useCallback])}>
|
|
360
|
+
<!-- use callback overrides expanded -->
|
|
361
|
+
<i
|
|
362
|
+
class="far {expanded ? expandedToggleClass : collapsedToggleClass}"
|
|
363
|
+
class:fa-minus-square={expanded}
|
|
364
|
+
class:fa-plus-square={!expanded || node[propNames.useCallback]}
|
|
365
|
+
/>
|
|
366
|
+
</span>
|
|
367
|
+
{:else}
|
|
368
|
+
<span />
|
|
369
|
+
{/if}
|
|
370
|
+
|
|
371
|
+
<Checkbox
|
|
372
|
+
{checkboxes}
|
|
373
|
+
{helper}
|
|
374
|
+
{recursive}
|
|
375
|
+
{node}
|
|
376
|
+
{onlyLeafCheckboxes}
|
|
377
|
+
{checkboxesDisabled}
|
|
378
|
+
{readonly}
|
|
379
|
+
on:select-children={({ detail: { node, checked } }) => selectChildren(node, checked)}
|
|
380
|
+
on:select={({ detail: node }) => selectionChanged(node)}
|
|
381
|
+
/>
|
|
382
|
+
<span class:pointer-cursor={draggable}>
|
|
383
|
+
<slot {node} />
|
|
384
|
+
</span>
|
|
385
|
+
</div>
|
|
386
|
+
|
|
387
|
+
{#if nesthighlighed}
|
|
388
|
+
<div class="insert-line-wrapper">
|
|
389
|
+
<div class="insert-line insert-line-child {inserLineClass} {inserLineNestClass}" />
|
|
390
|
+
</div>
|
|
391
|
+
{/if}
|
|
392
|
+
{#if expanded && hasChildren}
|
|
393
|
+
<svelte:self
|
|
394
|
+
branchRootNode={node}
|
|
395
|
+
{treeId}
|
|
396
|
+
{checkboxes}
|
|
397
|
+
bind:tree
|
|
398
|
+
bind:filteredTree
|
|
399
|
+
{recursive}
|
|
400
|
+
childDepth={childDepth + 1}
|
|
401
|
+
let:node={nodeNested}
|
|
402
|
+
{onlyLeafCheckboxes}
|
|
403
|
+
{checkboxesDisabled}
|
|
404
|
+
{expandedLevel}
|
|
405
|
+
bind:draggedPath
|
|
406
|
+
bind:dragAndDrop
|
|
407
|
+
on:selection
|
|
408
|
+
on:selected
|
|
409
|
+
on:unselected
|
|
410
|
+
on:expansion
|
|
411
|
+
on:expanded
|
|
412
|
+
on:closed
|
|
413
|
+
{props}
|
|
414
|
+
{recalculateNodePath}
|
|
415
|
+
bind:highlightedNode
|
|
416
|
+
bind:timeToNest
|
|
417
|
+
bind:pixelNestTreshold
|
|
418
|
+
on:open-ctxmenu={(data) => {
|
|
419
|
+
childDepth == 0
|
|
420
|
+
? openContextMenu(data.detail.e, data.detail.node)
|
|
421
|
+
: dispatch('open-ctxmenu', data.detail);
|
|
422
|
+
}}
|
|
423
|
+
{expandCallback}
|
|
424
|
+
on:moved
|
|
425
|
+
{beforeMovedCallback}
|
|
426
|
+
{dragEnterCallback}
|
|
427
|
+
{readonly}
|
|
428
|
+
{separator}
|
|
429
|
+
>
|
|
430
|
+
<slot node={nodeNested} />
|
|
431
|
+
</svelte:self>
|
|
432
|
+
{/if}
|
|
433
|
+
{#if !expanded && hasChildren}
|
|
434
|
+
<ul class:child-menu={childDepth > 0} />
|
|
435
|
+
{/if}
|
|
436
|
+
<!-- Show line if insering -->
|
|
437
|
+
{#if insPos == -1 && insertHighlighted}
|
|
438
|
+
<div class="insert-line-wrapper">
|
|
439
|
+
<div class="insert-line {inserLineClass}" />
|
|
440
|
+
</div>
|
|
441
|
+
{/if}
|
|
442
|
+
</li>
|
|
443
|
+
{/each}
|
|
444
|
+
</ul>
|
|
445
|
+
|
|
446
|
+
<ContextMenu bind:this={ctxMenu}>
|
|
447
|
+
<svelte:fragment let:node>
|
|
448
|
+
<slot name="context-menu" {node} />
|
|
449
|
+
</svelte:fragment>
|
|
450
|
+
</ContextMenu>
|
|
451
|
+
|
|
452
|
+
<style>:global(.treeview) {
|
|
453
|
+
margin: 0;
|
|
454
|
+
padding: 0;
|
|
455
|
+
list-style: none;
|
|
456
|
+
}
|
|
457
|
+
:global(.treeview.show-lines) :global(ul:before) {
|
|
458
|
+
border-left: solid black 1px;
|
|
459
|
+
}
|
|
460
|
+
:global(.treeview.show-lines) :global(ul) :global(li:before) {
|
|
461
|
+
border-top: solid black 1px;
|
|
462
|
+
}
|
|
463
|
+
:global(.treeview) :global(ul), :global(.treeview) :global(li) {
|
|
464
|
+
margin: 0;
|
|
465
|
+
padding: 0;
|
|
466
|
+
list-style: none;
|
|
467
|
+
}
|
|
468
|
+
:global(.treeview) :global(ul) {
|
|
469
|
+
margin-left: 0.4em;
|
|
470
|
+
position: relative;
|
|
471
|
+
margin-left: 0.3em;
|
|
472
|
+
}
|
|
473
|
+
:global(.treeview) :global(ul:before) {
|
|
474
|
+
content: "";
|
|
475
|
+
display: block;
|
|
476
|
+
width: 0;
|
|
477
|
+
position: absolute;
|
|
478
|
+
top: 0;
|
|
479
|
+
bottom: 0;
|
|
480
|
+
left: 0;
|
|
481
|
+
}
|
|
482
|
+
:global(.treeview) :global(ul) :global(li:before) {
|
|
483
|
+
content: "";
|
|
484
|
+
display: block;
|
|
485
|
+
width: 10px;
|
|
486
|
+
height: 0;
|
|
487
|
+
margin-top: -1px;
|
|
488
|
+
position: absolute;
|
|
489
|
+
top: 0.8em;
|
|
490
|
+
left: 0;
|
|
491
|
+
}
|
|
492
|
+
:global(.treeview) :global(ul) :global(li:not(.has-children):before) {
|
|
493
|
+
width: 26px;
|
|
494
|
+
}
|
|
495
|
+
:global(.treeview) :global(ul) :global(li:last-child:before) {
|
|
496
|
+
background: #fff;
|
|
497
|
+
height: auto;
|
|
498
|
+
top: 1em;
|
|
499
|
+
bottom: 0;
|
|
500
|
+
}
|
|
501
|
+
:global(.treeview) :global(li) {
|
|
502
|
+
margin: 0;
|
|
503
|
+
padding: 0 0.8em;
|
|
504
|
+
color: #555;
|
|
505
|
+
font-weight: 700;
|
|
506
|
+
position: relative;
|
|
507
|
+
}
|
|
508
|
+
:global(.treeview) :global(li:not(.has-children)) :global(.tree-item) {
|
|
509
|
+
margin-left: 14px;
|
|
510
|
+
}
|
|
511
|
+
:global(.treeview) :global(.tree-item) {
|
|
512
|
+
display: flex;
|
|
513
|
+
column-gap: 0.4em;
|
|
514
|
+
align-items: center;
|
|
515
|
+
padding: 4px 0;
|
|
516
|
+
}
|
|
517
|
+
:global(.treeview) :global(.no-arrow) {
|
|
518
|
+
padding-left: 0.5rem;
|
|
519
|
+
}
|
|
520
|
+
:global(.treeview) :global(.arrow) {
|
|
521
|
+
cursor: pointer;
|
|
522
|
+
display: inline-block;
|
|
523
|
+
}
|
|
524
|
+
:global(.treeview) :global(.arrowDown) {
|
|
525
|
+
transform: rotate(90deg);
|
|
526
|
+
}
|
|
527
|
+
:global(.treeview) :global(.invisible) {
|
|
528
|
+
visibility: hidden;
|
|
529
|
+
}
|
|
530
|
+
:global(.treeview) :global(.inserting-highlighted) {
|
|
531
|
+
color: red;
|
|
532
|
+
}
|
|
533
|
+
:global(.treeview) :global(.hover) {
|
|
534
|
+
font-weight: bold;
|
|
535
|
+
}
|
|
536
|
+
:global(.treeview) :global(.insert-line) {
|
|
537
|
+
position: absolute;
|
|
538
|
+
left: 0;
|
|
539
|
+
z-index: 99;
|
|
540
|
+
height: 2px;
|
|
541
|
+
width: 200px;
|
|
542
|
+
background-color: blue;
|
|
543
|
+
display: block;
|
|
544
|
+
border-radius: 3px;
|
|
545
|
+
margin-left: 28px;
|
|
546
|
+
margin-bottom: -2px;
|
|
547
|
+
margin-top: -2px;
|
|
548
|
+
}
|
|
549
|
+
:global(.treeview) :global(.insert-line-child) {
|
|
550
|
+
margin-left: calc(28px + 5em);
|
|
551
|
+
background-color: red;
|
|
552
|
+
height: 6px;
|
|
553
|
+
}
|
|
554
|
+
:global(.treeview) :global(.insert-line-wrapper) {
|
|
555
|
+
position: relative;
|
|
556
|
+
}
|
|
557
|
+
:global(.treeview) :global(.currently-dragged) {
|
|
558
|
+
color: LightGray;
|
|
559
|
+
}
|
|
560
|
+
:global(.treeview) :global(.pointer-cursor) {
|
|
561
|
+
cursor: grab;
|
|
562
|
+
}</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
tree: any[];
|
|
5
|
+
treeId: string;
|
|
6
|
+
filteredTree?: null | undefined;
|
|
7
|
+
recursive?: boolean | undefined;
|
|
8
|
+
checkboxes?: string | undefined;
|
|
9
|
+
onlyLeafCheckboxes?: boolean | undefined;
|
|
10
|
+
checkboxesDisabled?: boolean | undefined;
|
|
11
|
+
dragAndDrop?: boolean | undefined;
|
|
12
|
+
timeToNest?: null | undefined;
|
|
13
|
+
pixelNestTreshold?: number | undefined;
|
|
14
|
+
recalculateNodePath?: boolean | undefined;
|
|
15
|
+
dragEnterCallback?: null | undefined;
|
|
16
|
+
beforeMovedCallback?: null | undefined;
|
|
17
|
+
showContexMenu?: boolean | undefined;
|
|
18
|
+
enableVerticalLines?: boolean | undefined;
|
|
19
|
+
readonly?: boolean | undefined;
|
|
20
|
+
separator?: string | undefined;
|
|
21
|
+
expandedLevel?: number | undefined;
|
|
22
|
+
expandCallback?: null | undefined;
|
|
23
|
+
treeClass?: string | undefined;
|
|
24
|
+
nodeClass?: null | undefined;
|
|
25
|
+
expandedToggleClass?: null | undefined;
|
|
26
|
+
collapsedToggleClass?: null | undefined;
|
|
27
|
+
expandClass?: string | undefined;
|
|
28
|
+
inserLineClass?: null | undefined;
|
|
29
|
+
inserLineNestClass?: null | undefined;
|
|
30
|
+
currentlyDraggedClass?: string | undefined;
|
|
31
|
+
props?: {} | undefined;
|
|
32
|
+
draggedPath?: null | undefined;
|
|
33
|
+
highlightedNode?: null | undefined;
|
|
34
|
+
childDepth?: number | undefined;
|
|
35
|
+
branchRootNode?: undefined;
|
|
36
|
+
changeAllExpansion?: ((changeTo: any) => void) | undefined;
|
|
37
|
+
};
|
|
38
|
+
events: {
|
|
39
|
+
'open-ctxmenu': CustomEvent<any>;
|
|
40
|
+
expansion: CustomEvent<any>;
|
|
41
|
+
expanded: CustomEvent<any>;
|
|
42
|
+
closed: CustomEvent<any>;
|
|
43
|
+
selection: CustomEvent<any>;
|
|
44
|
+
selected: CustomEvent<any>;
|
|
45
|
+
unselected: CustomEvent<any>;
|
|
46
|
+
moved: CustomEvent<any>;
|
|
47
|
+
} & {
|
|
48
|
+
[evt: string]: CustomEvent<any>;
|
|
49
|
+
};
|
|
50
|
+
slots: {
|
|
51
|
+
default: {
|
|
52
|
+
node: any;
|
|
53
|
+
};
|
|
54
|
+
'context-menu': {
|
|
55
|
+
node: any;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
export type TreeViewProps = typeof __propDef.props;
|
|
60
|
+
export type TreeViewEvents = typeof __propDef.events;
|
|
61
|
+
export type TreeViewSlots = typeof __propDef.slots;
|
|
62
|
+
export default class TreeView extends SvelteComponentTyped<TreeViewProps, TreeViewEvents, TreeViewSlots> {
|
|
63
|
+
get changeAllExpansion(): (changeTo: any) => void;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
package/dist/consts.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export namespace defaultPropNames {
|
|
2
|
+
let nodePath: string;
|
|
3
|
+
let hasChildren: string;
|
|
4
|
+
let expanded: string;
|
|
5
|
+
let selected: string;
|
|
6
|
+
let useCallback: string;
|
|
7
|
+
let priority: string;
|
|
8
|
+
let isDraggable: string;
|
|
9
|
+
let insertDisabled: string;
|
|
10
|
+
let nestDisabled: string;
|
|
11
|
+
let checkbox: string;
|
|
12
|
+
}
|
|
13
|
+
export const defaultPixelTreshold: 50;
|
|
14
|
+
export const defaultTreeClass: "treeview";
|
|
15
|
+
export const defaultExpandClass: "inserting-highlighted";
|
|
16
|
+
export const defaultCurrentlyDraggedClass: "currently-dragged";
|
|
17
|
+
export namespace checkboxesType {
|
|
18
|
+
let all: string;
|
|
19
|
+
let perNode: string;
|
|
20
|
+
let none: string;
|
|
21
|
+
let readonly: string;
|
|
22
|
+
}
|
|
23
|
+
export namespace visualStateType {
|
|
24
|
+
export let indeterminate: string;
|
|
25
|
+
let selected_1: string;
|
|
26
|
+
export { selected_1 as selected };
|
|
27
|
+
export let notSelected: string;
|
|
28
|
+
}
|
package/dist/consts.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const defaultPropNames = {
|
|
2
|
+
nodePath: "nodePath",
|
|
3
|
+
hasChildren: "hasChildren",
|
|
4
|
+
expanded: "__expanded",
|
|
5
|
+
selected: "__selected",
|
|
6
|
+
useCallback: "__useCallback",
|
|
7
|
+
priority: "priority",
|
|
8
|
+
isDraggable: "isDraggable",
|
|
9
|
+
insertDisabled: "insertDisabled",
|
|
10
|
+
nestDisabled: "nestDisabled",
|
|
11
|
+
checkbox: "checkbox",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const defaultPixelTreshold = 50;
|
|
15
|
+
|
|
16
|
+
export const defaultTreeClass = "treeview";
|
|
17
|
+
export const defaultExpandClass = "inserting-highlighted";
|
|
18
|
+
export const defaultCurrentlyDraggedClass = "currently-dragged";
|
|
19
|
+
|
|
20
|
+
export const checkboxesType = {
|
|
21
|
+
all: "all",
|
|
22
|
+
perNode: "perNode",
|
|
23
|
+
none: "none",
|
|
24
|
+
readonly: "readonly",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const visualStateType = {
|
|
28
|
+
indeterminate: "indeterminate",
|
|
29
|
+
selected: "true",
|
|
30
|
+
notSelected: "false",
|
|
31
|
+
};
|