@keenmate/svelte-treeview 1.1.7 → 1.2.7

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 CHANGED
@@ -1,98 +1,98 @@
1
- # Svelte Treeview
2
-
3
- The most elaborate treeview for svelte on earth (or even in our galaxy).
4
-
5
- ## Features
6
-
7
- - load new nodes when expanding
8
- - choose what object properties to use to get necessary information (id, path, ...)
9
- - enable checkboxes on whole tree or just per node
10
- - recursive seletion mode, where leafes can be selected
11
- - build-in support for search
12
- - drag and drop functionality controlable per node
13
- - context menu
14
- - keyboard navigation
15
-
16
- ## Instalation
17
-
18
- install the package `@keenmate/svelte-treeview` using your favourite package manager.
19
-
20
- > [!warning]
21
- > **Font awesome is required for expand/collapse icons.**
22
- > If you wish to not use FA, you need to change all icons in classes properties
23
-
24
- ## Minimal usage
25
-
26
- Tree and treeId are only mandatory attributes.
27
- Tree has to be list of nodes. Only mandatory property of node is nodePath.
28
- You can specify which keys to use for what properties by setting **props**.
29
-
30
- ```svelte
31
- <script lang="ts">
32
- import { TreeView } from '$lib/index.js';
33
-
34
- let tree = [
35
- { nodePath: 'animals', title: 'Animals', hasChildren: true },
36
- //...
37
- { nodePath: 'animals.insects.butterflies', title: 'Butterflies' }
38
- ];
39
- </script>
40
-
41
- <TreeView {tree} treeId="my-tree" let:node>
42
- {node.title}
43
- </TreeView>
44
-
45
- ```
46
-
47
- For more examples see `src/routes/`
48
-
49
- > [!note]
50
- > Both **id** and **path** is required for tree to work.
51
- > By default tree uses nodePath property for both.
52
- > So if you change propery fro path, you need to also change id property.
53
- > You can change both using props attribute.
54
-
55
- ## Properties
56
-
57
- | Name | Type | Default | Description |
58
- | ---------------------- | ------------------------------------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------- |
59
- | treeId | string | | value used to generate ids of nodes |
60
- | tree | array of nodes | | represents tree strucuture |
61
- | value | array of selected nodeIds | [] | |
62
- | verticalLines | bool | false | show vertical guide lines |
63
- | readonly | bool | false | dont allow selection and drag and drop |
64
- | separator | string | "." | |
65
- | recursiveSelection | bool | false | changes behavior of selection, see [Selection](#selection) |
66
- | selectionMode | SelectionModes | none | changes selection mode, see [Selection](#selection) |
67
- | onlyLeafCheckboxes | bool | false | hides non leaf checkboxed, see [Selection](#selection) |
68
- | hideDisabledCheckboxes | bool | false | hides checkboxes instead of disabling, see [Selection](#selection) |
69
- | loadChildrenAsync | ExpandedCallback | null | function that is called when node is expanded, see [Async loading](#async-loading) |
70
- | showContextMenu | bool | false | On right click dispaly context menu defined in `context-menu` slot, see [Context menu](#context-menu) |
71
- | expansionThreshold | number | 0 | Expand all nodes when there is less than number provided |
72
- | customClasses | Partial<CustomizableClasses> | {} | changes classes used on same elements, see [Custom classes](#custom-classes) |
73
- | filter | (node: Node) => boolean or null | null | function that is used for fitlering. It is called on every node |
74
- | dragAndDrop | bool | false | enables drag and drop, see [Drag and drop](#drag-and-drop) |
75
- | dropDisabledCallback | (draggendNode: Node, targetNode: Node) => Promise<boolean> or null | null | function called when draging over new node, see [Drag and drop](#drag-and-drop) |
76
- | useKeyboardNavigation | bool | false | enables keyboard navigation , see [Keyboard navigation](#keyboard-navigation) |
77
- | logger | ((...data: any[]) => void) or null | null | function that acts as logger for tree, mostly used for debugging |
78
-
79
- ## Selection
80
-
81
- ## Async loading
82
-
83
- ## Context menu
84
-
85
- ## Custom classes
86
-
87
- ## Drag and drop
88
- > [!NOTE]
89
- > In memory drag and drop is not yet supported. Tree just dispatches `moved` event with dragged node(`node`), target node (`target`) and insertion type (`insertType`).
90
- > In future, this package will export function, that will allow you to easily compute new tree on frontend.
91
-
92
-
93
- ## Keyboard navigation
94
-
95
- Enable keyboard navigation by setting `useKeyboardNavigation` to true.
96
-
97
- Use arrows to navigata tree. First you need to focus some node,
98
- you can use `focusNode` to do that. Use Enter or Space to select checkbox.
1
+ # Svelte Treeview
2
+
3
+ The most elaborate treeview for svelte on earth (or even in our galaxy).
4
+
5
+ ## Features
6
+
7
+ - load new nodes when expanding
8
+ - choose what object properties to use to get necessary information (id, path, ...)
9
+ - enable checkboxes on whole tree or just per node
10
+ - recursive seletion mode, where leafes can be selected
11
+ - build-in support for search
12
+ - drag and drop functionality controlable per node
13
+ - context menu
14
+ - keyboard navigation
15
+
16
+ ## Instalation
17
+
18
+ install the package `@keenmate/svelte-treeview` using your favourite package manager.
19
+
20
+ > [!warning]
21
+ > **Font awesome is required for expand/collapse icons.**
22
+ > If you wish to not use FA, you need to change all icons in classes properties
23
+
24
+ ## Minimal usage
25
+
26
+ Tree and treeId are only mandatory attributes.
27
+ Tree has to be list of nodes. Only mandatory property of node is nodePath.
28
+ You can specify which keys to use for what properties by setting **props**.
29
+
30
+ ```svelte
31
+ <script lang="ts">
32
+ import { TreeView } from '$lib/index.js';
33
+
34
+ let tree = [
35
+ { nodePath: 'animals', title: 'Animals', hasChildren: true },
36
+ //...
37
+ { nodePath: 'animals.insects.butterflies', title: 'Butterflies' }
38
+ ];
39
+ </script>
40
+
41
+ <TreeView {tree} treeId="my-tree" let:node>
42
+ {node.title}
43
+ </TreeView>
44
+
45
+ ```
46
+
47
+ For more examples see `src/routes/`
48
+
49
+ > [!note]
50
+ > Both **id** and **path** is required for tree to work.
51
+ > By default tree uses nodePath property for both.
52
+ > So if you change propery fro path, you need to also change id property.
53
+ > You can change both using props attribute.
54
+
55
+ ## Properties
56
+
57
+ | Name | Type | Default | Description |
58
+ | ---------------------- | ------------------------------------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------- |
59
+ | treeId | string | | value used to generate ids of nodes |
60
+ | tree | array of nodes | | represents tree strucuture |
61
+ | value | array of selected nodeIds | [] | |
62
+ | verticalLines | bool | false | show vertical guide lines |
63
+ | readonly | bool | false | dont allow selection and drag and drop |
64
+ | separator | string | "." | |
65
+ | recursiveSelection | bool | false | changes behavior of selection, see [Selection](#selection) |
66
+ | selectionMode | SelectionModes | none | changes selection mode, see [Selection](#selection) |
67
+ | onlyLeafCheckboxes | bool | false | hides non leaf checkboxed, see [Selection](#selection) |
68
+ | hideDisabledCheckboxes | bool | false | hides checkboxes instead of disabling, see [Selection](#selection) |
69
+ | loadChildrenAsync | ExpandedCallback | null | function that is called when node is expanded, see [Async loading](#async-loading) |
70
+ | showContextMenu | bool | false | On right click dispaly context menu defined in `context-menu` slot, see [Context menu](#context-menu) |
71
+ | expansionThreshold | number | 0 | Expand all nodes when there is less than number provided |
72
+ | customClasses | Partial<CustomizableClasses> | {} | changes classes used on same elements, see [Custom classes](#custom-classes) |
73
+ | filter | (node: Node) => boolean or null | null | function that is used for fitlering. It is called on every node |
74
+ | dragAndDrop | bool | false | enables drag and drop, see [Drag and drop](#drag-and-drop) |
75
+ | dropDisabledCallback | (draggendNode: Node, targetNode: Node) => Promise<boolean> or null | null | function called when draging over new node, see [Drag and drop](#drag-and-drop) |
76
+ | useKeyboardNavigation | bool | false | enables keyboard navigation , see [Keyboard navigation](#keyboard-navigation) |
77
+ | logger | ((...data: any[]) => void) or null | null | function that acts as logger for tree, mostly used for debugging |
78
+
79
+ ## Selection
80
+
81
+ ## Async loading
82
+
83
+ ## Context menu
84
+
85
+ ## Custom classes
86
+
87
+ ## Drag and drop
88
+ > [!NOTE]
89
+ > In memory drag and drop is not yet supported. Tree just dispatches `moved` event with dragged node(`node`), target node (`target`) and insertion type (`insertType`).
90
+ > In future, this package will export function, that will allow you to easily compute new tree on frontend.
91
+
92
+
93
+ ## Keyboard navigation
94
+
95
+ Enable keyboard navigation by setting `useKeyboardNavigation` to true.
96
+
97
+ Use arrows to navigata tree. First you need to focus some node,
98
+ you can use `focusNode` to do that. Use Enter or Space to select checkbox.
@@ -76,140 +76,140 @@ function getHighlighMode(node, highlightedNode, insertionType) {
76
76
  return InsertionType.none;
77
77
  return insertionType;
78
78
  }
79
- </script>
80
-
81
- <ul
82
- class:show-lines={childDepth === 0 && verticalLines}
83
- class:child-menu={childDepth > 0}
84
- class={childDepth === 0 ? classes.treeClass : ''}
85
- >
86
- <!-- TODO fix accessibility -->
87
- <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
88
- {#each directChildren as node (getNodeId(node))}
89
- {@const expanded = isExpanded(node, childDepth, expandTo)}
90
- {@const draggable = !readonly && dragAndDrop && !node.dragDisabled}
91
- {@const isCurrentlyDragged = draggedNode && node.path.startsWith(draggedNode?.path)}
92
- {@const effectiveHighlight = getHighlighMode(node, highlightedNode, insertionType)}
93
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
94
- <li
95
- class:is-child={helper.nodePathIsChild(node.path)}
96
- class:has-children={node.hasChildren}
97
- on:contextmenu|stopPropagation={(e) => {
98
- dispatch('open-ctxmenu', { e, node });
99
- }}
100
- on:drop|stopPropagation={(e) => handleDragDrop(e, node, liElements[getNodeId(node)])}
101
- on:dragover|stopPropagation={(e) =>
102
- handleDragOver(e, node, liElements[getNodeId(node)], false)}
103
- on:dragenter|stopPropagation={(e) => handleDragEnter(e, node, liElements[getNodeId(node)])}
104
- on:dragleave|stopPropagation={(e) => handleDragLeave(e, node, liElements[getNodeId(node)])}
105
- bind:this={liElements[getNodeId(node)]}
106
- on:keydown={(e) => handleKeyPress(e, node)}
107
- tabindex={allowKeyboardNavigation ? 1 : -1}
108
- >
109
- {#if effectiveHighlight == InsertionType.insertAbove}
110
- <div class="insert-line-wrapper">
111
- <div class="insert-line {classes.insertLineClass}" />
112
- </div>
113
- {/if}
114
-
115
- <!-- svelte-ignore a11y-no-static-element-interactions -->
116
- <div
117
- class="tree-item
118
- {effectiveHighlight === InsertionType.nest ? classes.expandClass : ''}
119
- {classes.nodeClass} {isCurrentlyDragged ? classes.currentlyDraggedClass : ''}"
120
- class:div-has-children={node.hasChildren}
121
- class:hover={effectiveHighlight !== InsertionType.none}
122
- {draggable}
123
- on:dragstart={(e) => handleDragStart(e, node)}
124
- on:dragend={(e) => handleDragEnd(e, node)}
125
- >
126
- {#if node.hasChildren}
127
- <button
128
- class="expansion-button arrow"
129
- on:click={() => setExpansion(node, !expanded)}
130
- type="button"
131
- tabindex="-1"
132
- >
133
- <i class="fixed-icon arrow {expanded ? classes.collapseIcon : classes.expandIcon}" />
134
- </button>
135
- {:else}
136
- <span class="fixed-icon" />
137
- {/if}
138
-
139
- <Checkbox
140
- {checkboxes}
141
- {recursive}
142
- {node}
143
- {onlyLeafCheckboxes}
144
- {hideDisabledCheckboxes}
145
- {readonly}
146
- on:select={({ detail: { node } }) => selectionChanged(node)}
147
- />
148
- <span class:pointer-cursor={draggable}>
149
- <slot node={node.originalNode} />
150
- </span>
151
-
152
- {#if dragAndDrop && node.nestAllowed}
153
- <span
154
- on:dragover|stopPropagation={(e) =>
155
- handleDragOver(e, node, liElements[getNodeId(node)], true)}
156
- >
157
- <i class="fixed-icon {classes.nestIcon}" />
158
-
159
- {#if effectiveHighlight === InsertionType.nest}
160
- <slot name="nest-highlight" />
161
- {/if}
162
- </span>
163
- {/if}
164
- </div>
165
- {#if expanded && node.hasChildren}
166
- <svelte:self
167
- branchRootNode={node}
168
- childDepth={childDepth + 1}
169
- {treeId}
170
- {checkboxes}
171
- {tree}
172
- {recursive}
173
- {helper}
174
- {classes}
175
- {readonly}
176
- {onlyLeafCheckboxes}
177
- {hideDisabledCheckboxes}
178
- {expandTo}
179
- {dragAndDrop}
180
- {verticalLines}
181
- {draggedNode}
182
- {highlightedNode}
183
- {insertionType}
184
- {focusedNode}
185
- {allowKeyboardNavigation}
186
- on:open-ctxmenu
187
- on:internal-expand
188
- on:internal-selectionChanged
189
- on:internal-handleDragStart
190
- on:internal-handleDragDrop
191
- on:internal-handleDragOver
192
- on:internal-handleDragEnter
193
- on:internal-handleDragEnd
194
- on:internal-handleDragLeave
195
- on:internal-keypress
196
- let:node={nodeNested}
197
- >
198
- <slot node={nodeNested} />
199
- <svelte:fragment slot="nest-highlight">
200
- <slot name="nest-highlight" />
201
- </svelte:fragment>
202
- </svelte:self>
203
- {/if}
204
- {#if !expanded && node.hasChildren}
205
- <ul class:child-menu={childDepth > 0} />
206
- {/if}
207
- <!-- Show line if insering -->
208
- {#if effectiveHighlight === InsertionType.insertBelow}
209
- <div class="insert-line-wrapper">
210
- <div class="insert-line {classes.insertLineClass}" />
211
- </div>
212
- {/if}
213
- </li>
214
- {/each}
215
- </ul>
79
+ </script>
80
+
81
+ <ul
82
+ class:show-lines={childDepth === 0 && verticalLines}
83
+ class:child-menu={childDepth > 0}
84
+ class={childDepth === 0 ? classes.treeClass : ''}
85
+ >
86
+ <!-- TODO fix accessibility -->
87
+ <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
88
+ {#each directChildren as node (getNodeId(node))}
89
+ {@const expanded = isExpanded(node, childDepth, expandTo)}
90
+ {@const draggable = !readonly && dragAndDrop && !node.dragDisabled}
91
+ {@const isCurrentlyDragged = draggedNode && node.path.startsWith(draggedNode?.path)}
92
+ {@const effectiveHighlight = getHighlighMode(node, highlightedNode, insertionType)}
93
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
94
+ <li
95
+ class:is-child={helper.nodePathIsChild(node.path)}
96
+ class:has-children={node.hasChildren}
97
+ on:contextmenu|stopPropagation={(e) => {
98
+ dispatch('open-ctxmenu', { e, node });
99
+ }}
100
+ on:drop|stopPropagation={(e) => handleDragDrop(e, node, liElements[getNodeId(node)])}
101
+ on:dragover|stopPropagation={(e) =>
102
+ handleDragOver(e, node, liElements[getNodeId(node)], false)}
103
+ on:dragenter|stopPropagation={(e) => handleDragEnter(e, node, liElements[getNodeId(node)])}
104
+ on:dragleave|stopPropagation={(e) => handleDragLeave(e, node, liElements[getNodeId(node)])}
105
+ bind:this={liElements[getNodeId(node)]}
106
+ on:keydown={(e) => handleKeyPress(e, node)}
107
+ tabindex={allowKeyboardNavigation ? 1 : -1}
108
+ >
109
+ {#if effectiveHighlight == InsertionType.insertAbove}
110
+ <div class="insert-line-wrapper">
111
+ <div class="insert-line {classes.insertLineClass}" />
112
+ </div>
113
+ {/if}
114
+
115
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
116
+ <div
117
+ class="tree-item
118
+ {effectiveHighlight === InsertionType.nest ? classes.expandClass : ''}
119
+ {classes.nodeClass} {isCurrentlyDragged ? classes.currentlyDraggedClass : ''}"
120
+ class:div-has-children={node.hasChildren}
121
+ class:hover={effectiveHighlight !== InsertionType.none}
122
+ {draggable}
123
+ on:dragstart={(e) => handleDragStart(e, node)}
124
+ on:dragend={(e) => handleDragEnd(e, node)}
125
+ >
126
+ {#if node.hasChildren}
127
+ <button
128
+ class="expansion-button arrow"
129
+ on:click={() => setExpansion(node, !expanded)}
130
+ type="button"
131
+ tabindex="-1"
132
+ >
133
+ <i class="fixed-icon arrow {expanded ? classes.collapseIcon : classes.expandIcon}" />
134
+ </button>
135
+ {:else}
136
+ <span class="fixed-icon" />
137
+ {/if}
138
+
139
+ <Checkbox
140
+ {checkboxes}
141
+ {recursive}
142
+ {node}
143
+ {onlyLeafCheckboxes}
144
+ {hideDisabledCheckboxes}
145
+ {readonly}
146
+ on:select={({ detail: { node } }) => selectionChanged(node)}
147
+ />
148
+ <span class:pointer-cursor={draggable}>
149
+ <slot node={node.originalNode} />
150
+ </span>
151
+
152
+ {#if dragAndDrop && node.nestAllowed}
153
+ <span
154
+ on:dragover|stopPropagation={(e) =>
155
+ handleDragOver(e, node, liElements[getNodeId(node)], true)}
156
+ >
157
+ <i class="fixed-icon {classes.nestIcon}" />
158
+
159
+ {#if effectiveHighlight === InsertionType.nest}
160
+ <slot name="nest-highlight" />
161
+ {/if}
162
+ </span>
163
+ {/if}
164
+ </div>
165
+ {#if expanded && node.hasChildren}
166
+ <svelte:self
167
+ branchRootNode={node}
168
+ childDepth={childDepth + 1}
169
+ {treeId}
170
+ {checkboxes}
171
+ {tree}
172
+ {recursive}
173
+ {helper}
174
+ {classes}
175
+ {readonly}
176
+ {onlyLeafCheckboxes}
177
+ {hideDisabledCheckboxes}
178
+ {expandTo}
179
+ {dragAndDrop}
180
+ {verticalLines}
181
+ {draggedNode}
182
+ {highlightedNode}
183
+ {insertionType}
184
+ {focusedNode}
185
+ {allowKeyboardNavigation}
186
+ on:open-ctxmenu
187
+ on:internal-expand
188
+ on:internal-selectionChanged
189
+ on:internal-handleDragStart
190
+ on:internal-handleDragDrop
191
+ on:internal-handleDragOver
192
+ on:internal-handleDragEnter
193
+ on:internal-handleDragEnd
194
+ on:internal-handleDragLeave
195
+ on:internal-keypress
196
+ let:node={nodeNested}
197
+ >
198
+ <slot node={nodeNested} />
199
+ <svelte:fragment slot="nest-highlight">
200
+ <slot name="nest-highlight" />
201
+ </svelte:fragment>
202
+ </svelte:self>
203
+ {/if}
204
+ {#if !expanded && node.hasChildren}
205
+ <ul class:child-menu={childDepth > 0} />
206
+ {/if}
207
+ <!-- Show line if insering -->
208
+ {#if effectiveHighlight === InsertionType.insertBelow}
209
+ <div class="insert-line-wrapper">
210
+ <div class="insert-line {classes.insertLineClass}" />
211
+ </div>
212
+ {/if}
213
+ </li>
214
+ {/each}
215
+ </ul>
@@ -13,39 +13,39 @@ function onSelect(e, node) {
13
13
  dispatch('select', { node });
14
14
  return false;
15
15
  }
16
- </script>
17
-
18
- {#if checkboxes == SelectionModes.perNode || checkboxes == SelectionModes.all}
19
- {#if isSelectable(node, checkboxes)}
20
- {#if !recursive || (recursive && !node.hasChildren) || !onlyLeafCheckboxes}
21
- <input
22
- tabindex="-1"
23
- type="checkbox"
24
- class="arrow"
25
- on:click={(e) => onSelect(e, node)}
26
- on:keypress={(e) => e.key === 'Enter' && onSelect(e, node)}
27
- checked={node.visualState === VisualState.selected}
28
- indeterminate={node.visualState === VisualState.indeterminate}
29
- disabled={readonly}
30
- />
31
- {:else}
32
- <input
33
- tabindex="-1"
34
- class="arrow"
35
- type="checkbox"
36
- on:click={null}
37
- disabled={true}
38
- class:invisible={hideDisabledCheckboxes}
39
- />
40
- {/if}
41
- {:else}
42
- <input
43
- tabindex="-1"
44
- class="arrow"
45
- type="checkbox"
46
- on:click|preventDefault|stopPropagation
47
- disabled={true}
48
- class:invisible={hideDisabledCheckboxes}
49
- />
50
- {/if}
51
- {/if}
16
+ </script>
17
+
18
+ {#if checkboxes == SelectionModes.perNode || checkboxes == SelectionModes.all}
19
+ {#if isSelectable(node, checkboxes)}
20
+ {#if !recursive || (recursive && !node.hasChildren) || !onlyLeafCheckboxes}
21
+ <input
22
+ tabindex="-1"
23
+ type="checkbox"
24
+ class="arrow"
25
+ on:click={(e) => onSelect(e, node)}
26
+ on:keypress={(e) => e.key === 'Enter' && onSelect(e, node)}
27
+ checked={node.visualState === VisualState.selected}
28
+ indeterminate={node.visualState === VisualState.indeterminate}
29
+ disabled={readonly}
30
+ />
31
+ {:else}
32
+ <input
33
+ tabindex="-1"
34
+ class="arrow"
35
+ type="checkbox"
36
+ on:click={null}
37
+ disabled={true}
38
+ class:invisible={hideDisabledCheckboxes}
39
+ />
40
+ {/if}
41
+ {:else}
42
+ <input
43
+ tabindex="-1"
44
+ class="arrow"
45
+ type="checkbox"
46
+ on:click|preventDefault|stopPropagation
47
+ disabled={true}
48
+ class:invisible={hideDisabledCheckboxes}
49
+ />
50
+ {/if}
51
+ {/if}
@@ -364,51 +364,51 @@ function debugLog(...data) {
364
364
  logger(...data);
365
365
  }
366
366
  }
367
- </script>
368
-
369
- <Branch
370
- branchRootNode={null}
371
- {treeId}
372
- checkboxes={selectionMode}
373
- tree={computedTree}
374
- recursive={recursiveSelection}
375
- {onlyLeafCheckboxes}
376
- {hideDisabledCheckboxes}
377
- {expandTo}
378
- {dragAndDrop}
379
- {readonly}
380
- {helper}
381
- classes={computedClasses}
382
- {verticalLines}
383
- let:node={nodeInSlot}
384
- childDepth={0}
385
- {insertionType}
386
- {highlightedNode}
387
- {draggedNode}
388
- {focusedNode}
389
- {allowKeyboardNavigation}
390
- on:internal-handleDragStart={onDragStart}
391
- on:internal-handleDragDrop={onDragDrop}
392
- on:internal-handleDragOver={onDragOver}
393
- on:internal-handleDragEnter={onDragEnter}
394
- on:internal-handleDragEnd={onDragEnd}
395
- on:internal-handleDragLeave={onDragLeave}
396
- on:internal-keypress={(e) => onKeyPress(e.detail)}
397
- on:open-ctxmenu={openContextMenu}
398
- on:internal-expand={(e) => onExpand(e.detail)}
399
- on:internal-selectionChanged={(e) => onSelectionChanged(e.detail)}
400
- >
401
- <slot node={nodeInSlot} />
402
- <svelte:fragment slot="nest-highlight">
403
- <slot name="nest-highlight" />
404
- </svelte:fragment>
405
- </Branch>
406
- <ContextMenu bind:this={ctxMenu}>
407
- <svelte:fragment let:node>
408
- <slot name="context-menu" {node} />
409
- </svelte:fragment>
410
- </ContextMenu>
411
-
367
+ </script>
368
+
369
+ <Branch
370
+ branchRootNode={null}
371
+ {treeId}
372
+ checkboxes={selectionMode}
373
+ tree={computedTree}
374
+ recursive={recursiveSelection}
375
+ {onlyLeafCheckboxes}
376
+ {hideDisabledCheckboxes}
377
+ {expandTo}
378
+ {dragAndDrop}
379
+ {readonly}
380
+ {helper}
381
+ classes={computedClasses}
382
+ {verticalLines}
383
+ let:node={nodeInSlot}
384
+ childDepth={0}
385
+ {insertionType}
386
+ {highlightedNode}
387
+ {draggedNode}
388
+ {focusedNode}
389
+ {allowKeyboardNavigation}
390
+ on:internal-handleDragStart={onDragStart}
391
+ on:internal-handleDragDrop={onDragDrop}
392
+ on:internal-handleDragOver={onDragOver}
393
+ on:internal-handleDragEnter={onDragEnter}
394
+ on:internal-handleDragEnd={onDragEnd}
395
+ on:internal-handleDragLeave={onDragLeave}
396
+ on:internal-keypress={(e) => onKeyPress(e.detail)}
397
+ on:open-ctxmenu={openContextMenu}
398
+ on:internal-expand={(e) => onExpand(e.detail)}
399
+ on:internal-selectionChanged={(e) => onSelectionChanged(e.detail)}
400
+ >
401
+ <slot node={nodeInSlot} />
402
+ <svelte:fragment slot="nest-highlight">
403
+ <slot name="nest-highlight" />
404
+ </svelte:fragment>
405
+ </Branch>
406
+ <ContextMenu bind:this={ctxMenu}>
407
+ <svelte:fragment let:node>
408
+ <slot name="context-menu" {node} />
409
+ </svelte:fragment>
410
+ </ContextMenu>
411
+
412
412
  <style global>:global(.treeview) {
413
413
  padding: 0;
414
414
  }
@@ -524,4 +524,4 @@ function debugLog(...data) {
524
524
  text-align: center;
525
525
  width: 1.25em;
526
526
  min-width: 1.25em;
527
- }</style>
527
+ }</style>
@@ -15,13 +15,13 @@ function closeMenu() {
15
15
  showMenu = false;
16
16
  clickedNode = null;
17
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}
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,50 +1,50 @@
1
- <!-- component from https://svelte.dev/repl/3a33725c3adb4f57b46b597f9dade0c1?version=3.25.0 -->
2
-
3
- <script>
4
- // @ts-nocheck
5
-
6
- import { onMount, setContext, createEventDispatcher } from 'svelte';
7
- import { fade } from 'svelte/transition';
8
- import { key } from './menu.js';
9
-
10
- export let x;
11
- export let y;
12
-
13
- // whenever x and y is changed, restrict box to be within bounds
14
- $: (() => {
15
- if (!menuEl) return;
16
-
17
- const rect = menuEl.getBoundingClientRect();
18
- x = Math.min(window.innerWidth - rect.width, x);
19
- if (y > window.innerHeight - rect.height) y -= rect.height;
20
- })(x, y);
21
-
22
- const dispatch = createEventDispatcher();
23
-
24
- setContext(key, {
25
- dispatchClick: () => dispatch('click')
26
- });
27
-
28
- let menuEl;
29
- function onPageClick(e) {
30
- if (e.target === menuEl || menuEl.contains(e.target)) return;
31
- dispatch('clickoutside');
32
- }
33
- </script>
34
-
35
- <svelte:body on:click={onPageClick} />
36
-
37
- <div transition:fade={{ duration: 100 }} bind:this={menuEl} style="top: {y}px; left: {x}px;">
38
- <slot />
39
- </div>
40
-
41
- <style>
42
- div {
43
- position: fixed;
44
- display: grid;
45
- border: 1px solid #0003;
46
- box-shadow: 2px 2px 5px 0px #0002;
47
- background: white;
48
- z-index: 999;
49
- }
50
- </style>
1
+ <!-- component from https://svelte.dev/repl/3a33725c3adb4f57b46b597f9dade0c1?version=3.25.0 -->
2
+
3
+ <script>
4
+ // @ts-nocheck
5
+
6
+ import { onMount, setContext, createEventDispatcher } from 'svelte';
7
+ import { fade } from 'svelte/transition';
8
+ import { key } from './menu.js';
9
+
10
+ export let x;
11
+ export let y;
12
+
13
+ // whenever x and y is changed, restrict box to be within bounds
14
+ $: (() => {
15
+ if (!menuEl) return;
16
+
17
+ const rect = menuEl.getBoundingClientRect();
18
+ x = Math.min(window.innerWidth - rect.width, x);
19
+ if (y > window.innerHeight - rect.height) y -= rect.height;
20
+ })(x, y);
21
+
22
+ const dispatch = createEventDispatcher();
23
+
24
+ setContext(key, {
25
+ dispatchClick: () => dispatch('click')
26
+ });
27
+
28
+ let menuEl;
29
+ function onPageClick(e) {
30
+ if (e.target === menuEl || menuEl.contains(e.target)) return;
31
+ dispatch('clickoutside');
32
+ }
33
+ </script>
34
+
35
+ <svelte:body on:click={onPageClick} />
36
+
37
+ <div transition:fade={{ duration: 100 }} bind:this={menuEl} style="top: {y}px; left: {x}px;">
38
+ <slot />
39
+ </div>
40
+
41
+ <style>
42
+ div {
43
+ position: fixed;
44
+ display: grid;
45
+ border: 1px solid #0003;
46
+ box-shadow: 2px 2px 5px 0px #0002;
47
+ background: white;
48
+ z-index: 999;
49
+ }
50
+ </style>
@@ -1,10 +1,10 @@
1
- <style>
2
- hr {
3
- border-top: 1px solid #0003;
4
- width: 100%;
5
- margin: 2px 0;
6
- }
7
- </style>
8
-
9
-
10
- <hr />
1
+ <style>
2
+ hr {
3
+ border-top: 1px solid #0003;
4
+ width: 100%;
5
+ margin: 2px 0;
6
+ }
7
+ </style>
8
+
9
+
10
+ <hr />
@@ -1,49 +1,49 @@
1
- <script>
2
- // @ts-nocheck
3
-
4
- import { onMount, getContext } from 'svelte';
5
- import { key } from './menu.js';
6
-
7
- export let isDisabled = false;
8
- export let text = '';
9
-
10
- import { createEventDispatcher } from 'svelte';
11
- const dispatch = createEventDispatcher();
12
-
13
- const { dispatchClick } = getContext(key);
14
-
15
- const handleClick = (e) => {
16
- if (isDisabled) return;
17
-
18
- dispatch('click');
19
- dispatchClick();
20
- };
21
- </script>
22
-
23
- <div class:disabled={isDisabled} on:click={handleClick} on:keydown={handleClick} role="button" tabindex="">
24
- {#if text}
25
- {text}
26
- {:else}
27
- <slot />
28
- {/if}
29
- </div>
30
-
31
- <style>
32
- div {
33
- padding: 4px 15px;
34
- cursor: default;
35
- font-size: 14px;
36
- display: flex;
37
- align-items: center;
38
- grid-gap: 5px;
39
- }
40
- div:hover {
41
- background: #0002;
42
- }
43
- div.disabled {
44
- color: #0006;
45
- }
46
- div.disabled:hover {
47
- background: white;
48
- }
49
- </style>
1
+ <script>
2
+ // @ts-nocheck
3
+
4
+ import { onMount, getContext } from 'svelte';
5
+ import { key } from './menu.js';
6
+
7
+ export let isDisabled = false;
8
+ export let text = '';
9
+
10
+ import { createEventDispatcher } from 'svelte';
11
+ const dispatch = createEventDispatcher();
12
+
13
+ const { dispatchClick } = getContext(key);
14
+
15
+ const handleClick = (e) => {
16
+ if (isDisabled) return;
17
+
18
+ dispatch('click');
19
+ dispatchClick();
20
+ };
21
+ </script>
22
+
23
+ <div class:disabled={isDisabled} on:click={handleClick} on:keydown={handleClick} role="button" tabindex="">
24
+ {#if text}
25
+ {text}
26
+ {:else}
27
+ <slot />
28
+ {/if}
29
+ </div>
30
+
31
+ <style>
32
+ div {
33
+ padding: 4px 15px;
34
+ cursor: default;
35
+ font-size: 14px;
36
+ display: flex;
37
+ align-items: center;
38
+ grid-gap: 5px;
39
+ }
40
+ div:hover {
41
+ background: #0002;
42
+ }
43
+ div.disabled {
44
+ color: #0006;
45
+ }
46
+ div.disabled:hover {
47
+ background: white;
48
+ }
49
+ </style>
package/dist/menu/menu.js CHANGED
@@ -1,3 +1,3 @@
1
- const key = {};
2
-
1
+ const key = {};
2
+
3
3
  export { key };
@@ -1,110 +1,110 @@
1
-
2
- $treeview-lines: solid black 1px
3
- .treeview
4
- padding: 0
5
- //will show lines if you set show-lines to root element
6
- &.show-lines
7
- ul
8
- &:before
9
- border-left: $treeview-lines
10
- li:before
11
- border-top: $treeview-lines
12
- margin: 0
13
- padding: 0
14
- list-style: none
15
- ul, li
16
- margin: 0
17
- padding: 0
18
- list-style: none
19
- ul
20
- margin-left: 0.4em
21
- position: relative
22
- margin-left: .3em
23
- &:before
24
- content: ""
25
- display: block
26
- width: 0
27
- position: absolute
28
- top: 0
29
- bottom: 0
30
- left: 0
31
- li:before
32
- content: ""
33
- display: block
34
- width: 10px
35
- height: 0
36
- margin-top: -1px
37
- position: absolute
38
- top: 0.8em
39
- left: 0
40
- li:not(.has-children):before
41
- width: 26px
42
-
43
- li:last-child:before
44
- background: #fff
45
- height: auto
46
- top: 1em
47
- bottom: 0
48
-
49
- li
50
- margin: 0
51
- padding: 0 0.8em
52
- color: #555
53
- font-weight: 700
54
- position: relative
55
-
56
- .tree-item
57
- display: flex
58
- column-gap: 0.4em
59
- align-items: center
60
- padding: 4px 0
61
-
62
- .no-arrow
63
- padding-left: .5rem
64
-
65
- .arrow
66
- cursor: pointer
67
- display: inline-block
68
-
69
- .arrowDown
70
- transform: rotate(90deg)
71
-
72
- .invisible
73
- visibility: hidden
74
-
75
- .inserting-highlighted
76
- color: red
77
- .hover
78
- font-weight: bold
79
- .insert-line
80
- position: absolute
81
- left: 0
82
- z-index: 99
83
- height: 2px
84
- width: 200px
85
- background-color: blue
86
- display: block
87
- border-radius: 3px
88
- margin-left: 28px
89
- pointer-events: none //! this is needed to fix flickering issue
90
- // margin-bottom: -2px
91
- // margin-top: -2px
92
- .insert-line-child
93
- margin-left: calc( 28px + 5em )
94
- background-color: red
95
- height: 6px
96
-
97
- .insert-line-wrapper
98
- position: relative
99
-
100
- .currently-dragged
101
- color: LightGray
102
- .pointer-cursor
103
- cursor: grab
104
- .expansion-button
105
- all: unset
106
- .fixed-icon
107
- text-align: center
108
- width: 1.25em
109
- // fix deformation on small screens
110
- min-width: 1.25em
1
+
2
+ $treeview-lines: solid black 1px
3
+ .treeview
4
+ padding: 0
5
+ //will show lines if you set show-lines to root element
6
+ &.show-lines
7
+ ul
8
+ &:before
9
+ border-left: $treeview-lines
10
+ li:before
11
+ border-top: $treeview-lines
12
+ margin: 0
13
+ padding: 0
14
+ list-style: none
15
+ ul, li
16
+ margin: 0
17
+ padding: 0
18
+ list-style: none
19
+ ul
20
+ margin-left: 0.4em
21
+ position: relative
22
+ margin-left: .3em
23
+ &:before
24
+ content: ""
25
+ display: block
26
+ width: 0
27
+ position: absolute
28
+ top: 0
29
+ bottom: 0
30
+ left: 0
31
+ li:before
32
+ content: ""
33
+ display: block
34
+ width: 10px
35
+ height: 0
36
+ margin-top: -1px
37
+ position: absolute
38
+ top: 0.8em
39
+ left: 0
40
+ li:not(.has-children):before
41
+ width: 26px
42
+
43
+ li:last-child:before
44
+ background: #fff
45
+ height: auto
46
+ top: 1em
47
+ bottom: 0
48
+
49
+ li
50
+ margin: 0
51
+ padding: 0 0.8em
52
+ color: #555
53
+ font-weight: 700
54
+ position: relative
55
+
56
+ .tree-item
57
+ display: flex
58
+ column-gap: 0.4em
59
+ align-items: center
60
+ padding: 4px 0
61
+
62
+ .no-arrow
63
+ padding-left: .5rem
64
+
65
+ .arrow
66
+ cursor: pointer
67
+ display: inline-block
68
+
69
+ .arrowDown
70
+ transform: rotate(90deg)
71
+
72
+ .invisible
73
+ visibility: hidden
74
+
75
+ .inserting-highlighted
76
+ color: red
77
+ .hover
78
+ font-weight: bold
79
+ .insert-line
80
+ position: absolute
81
+ left: 0
82
+ z-index: 99
83
+ height: 2px
84
+ width: 200px
85
+ background-color: blue
86
+ display: block
87
+ border-radius: 3px
88
+ margin-left: 28px
89
+ pointer-events: none //! this is needed to fix flickering issue
90
+ // margin-bottom: -2px
91
+ // margin-top: -2px
92
+ .insert-line-child
93
+ margin-left: calc( 28px + 5em )
94
+ background-color: red
95
+ height: 6px
96
+
97
+ .insert-line-wrapper
98
+ position: relative
99
+
100
+ .currently-dragged
101
+ color: LightGray
102
+ .pointer-cursor
103
+ cursor: grab
104
+ .expansion-button
105
+ all: unset
106
+ .fixed-icon
107
+ text-align: center
108
+ width: 1.25em
109
+ // fix deformation on small screens
110
+ min-width: 1.25em
package/package.json CHANGED
@@ -1,73 +1,76 @@
1
- {
2
- "name": "@keenmate/svelte-treeview",
3
- "version": "1.1.7",
4
- "scripts": {
5
- "dev": "vite dev",
6
- "build": "vite build && npm run package",
7
- "preview": "vite preview",
8
- "package": "svelte-kit sync && svelte-package && publint",
9
- "prepublishOnly": "npm run package",
10
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
11
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12
- "lint": "prettier --plugin-search-dir . --check . && eslint .",
13
- "format": "prettier --plugin-search-dir . --write .",
14
- "test": "vitest",
15
- "test:loud": "vitest --silent=false",
16
- "coverage": "vitest run --coverage"
17
- },
18
- "exports": {
19
- ".": {
20
- "types": "./dist/index.d.ts",
21
- "svelte": "./dist/index.js"
22
- }
23
- },
24
- "files": [
25
- "dist",
26
- "!dist/**/*.test.*",
27
- "!dist/**/*.spec.*"
28
- ],
29
- "peerDependencies": {
30
- "svelte": "^4.0.0"
31
- },
32
- "devDependencies": {
33
- "@keenmate/svelte-adminlte": "^1.1.3",
34
- "@sveltejs/adapter-auto": "^2.0.0",
35
- "@sveltejs/kit": "^1.20.4",
36
- "@sveltejs/package": "^2.0.0",
37
- "@types/marked": "^5.0.0",
38
- "@types/node": "^20.3.3",
39
- "@typescript-eslint/eslint-plugin": "^5.45.0",
40
- "@typescript-eslint/parser": "^5.45.0",
41
- "@vitest/coverage-v8": "^1.4.0",
42
- "eslint": "^8.28.0",
43
- "eslint-config-prettier": "^8.5.0",
44
- "eslint-plugin-svelte": "^2.30.0",
45
- "marked": "^5.1.0",
46
- "prettier": "^2.8.0",
47
- "prettier-plugin-svelte": "^2.10.1",
48
- "publint": "^0.1.9",
49
- "rollup-plugin-string": "^3.0.0",
50
- "sass": "^1.49.0",
51
- "svelte": "^4.0.0",
52
- "svelte-check": "^3.4.3",
53
- "svelte-multiselect": "github:KeenMate/svelte-multiselect",
54
- "svelte-preprocess": "^5.0.4",
55
- "tslib": "^2.4.1",
56
- "typescript": "^5.4.4",
57
- "vite": "^4.3.6",
58
- "vitest": "^1.4.0"
59
- },
60
- "svelte": "./dist/index.js",
61
- "types": "./dist/index.d.ts",
62
- "type": "module",
63
- "dependencies": {
64
- "@keenmate/js-common-helpers": "^1.2.0",
65
- "@types/lodash.unionby": "^4.8.9",
66
- "@types/lodash.uniq": "^4.5.9",
67
- "@types/lodash.uniqby": "^4.7.9",
68
- "lodash.unionby": "^4.8.0",
69
- "lodash.uniq": "^4.5.0",
70
- "lodash.uniqby": "^4.7.0",
71
- "svelte-highlight": "^7.6.1"
72
- }
73
- }
1
+ {
2
+ "name": "@keenmate/svelte-treeview",
3
+ "version": "1.2.7",
4
+ "repository": {
5
+ "url": "https://github.com/keenmate/svelte-treeview"
6
+ },
7
+ "scripts": {
8
+ "dev": "vite dev",
9
+ "build": "vite build && npm run package",
10
+ "preview": "vite preview",
11
+ "package": "svelte-kit sync && svelte-package && publint",
12
+ "prepublishOnly": "npm run package",
13
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
14
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
15
+ "lint": "prettier --plugin-search-dir . --check . && eslint .",
16
+ "format": "prettier --plugin-search-dir . --write .",
17
+ "test": "vitest",
18
+ "test:loud": "vitest --silent=false",
19
+ "coverage": "vitest run --coverage"
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "svelte": "./dist/index.js"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "!dist/**/*.test.*",
30
+ "!dist/**/*.spec.*"
31
+ ],
32
+ "peerDependencies": {
33
+ "svelte": "^4.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@keenmate/svelte-adminlte": "^1.1.3",
37
+ "@sveltejs/adapter-auto": "^2.0.0",
38
+ "@sveltejs/kit": "^1.20.4",
39
+ "@sveltejs/package": "^2.0.0",
40
+ "@types/marked": "^5.0.0",
41
+ "@types/node": "^20.3.3",
42
+ "@typescript-eslint/eslint-plugin": "^5.45.0",
43
+ "@typescript-eslint/parser": "^5.45.0",
44
+ "@vitest/coverage-v8": "^1.4.0",
45
+ "eslint": "^8.28.0",
46
+ "eslint-config-prettier": "^8.5.0",
47
+ "eslint-plugin-svelte": "^2.30.0",
48
+ "marked": "^5.1.0",
49
+ "prettier": "^2.8.0",
50
+ "prettier-plugin-svelte": "^2.10.1",
51
+ "publint": "^0.1.9",
52
+ "rollup-plugin-string": "^3.0.0",
53
+ "sass": "^1.49.0",
54
+ "svelte": "^4.0.0",
55
+ "svelte-check": "^3.4.3",
56
+ "svelte-multiselect": "github:KeenMate/svelte-multiselect",
57
+ "svelte-preprocess": "^5.0.4",
58
+ "tslib": "^2.4.1",
59
+ "typescript": "^5.4.4",
60
+ "vite": "^4.3.6",
61
+ "vitest": "^1.4.0"
62
+ },
63
+ "svelte": "./dist/index.js",
64
+ "types": "./dist/index.d.ts",
65
+ "type": "module",
66
+ "dependencies": {
67
+ "@keenmate/js-common-helpers": "^1.2.0",
68
+ "@types/lodash.unionby": "^4.8.9",
69
+ "@types/lodash.uniq": "^4.5.9",
70
+ "@types/lodash.uniqby": "^4.7.9",
71
+ "lodash.unionby": "^4.8.0",
72
+ "lodash.uniq": "^4.5.0",
73
+ "lodash.uniqby": "^4.7.0",
74
+ "svelte-highlight": "^7.6.1"
75
+ }
76
+ }