@keenmate/svelte-treeview 4.0.1 → 4.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 CHANGED
@@ -625,6 +625,28 @@ interface NodeData {
625
625
  - Second level: `"1.1"`, `"1.2"`, `"2.1"`
626
626
  - Third level: `"1.1.1"`, `"1.2.1"`, `"2.1.1"`
627
627
 
628
+ ### Sorting Requirements
629
+
630
+ **Important:** For proper tree construction, your `sortCallback` must sort by **level first** to ensure parent nodes are inserted before their children:
631
+
632
+ ```typescript
633
+ const sortCallback = (items: LTreeNode<T>[]) => {
634
+ return items.sort((a, b) => {
635
+ // First, sort by level (shallower levels first)
636
+ const aLevel = a.path.split('.').length;
637
+ const bLevel = b.path.split('.').length;
638
+ if (aLevel !== bLevel) {
639
+ return aLevel - bLevel;
640
+ }
641
+
642
+ // Then sort by your custom criteria
643
+ return a.data.name.localeCompare(b.data.name);
644
+ });
645
+ };
646
+ ```
647
+
648
+ **Why this matters:** If deeper level nodes are processed before their parents, you'll get "Could not find parent node" errors during tree construction. Level-first sorting ensures hierarchical integrity and enables progressive rendering for large datasets.
649
+
628
650
  ### Insert Result Information
629
651
 
630
652
  The tree provides detailed information about data insertion through the `insertResult` bindable property:
@@ -222,8 +222,9 @@
222
222
 
223
223
  treeId = treeId || generateTreeId();
224
224
 
225
- // svelte-ignore non_reactive_update
226
- // let trie: Ltree<T> | null = null
225
+ if (shouldDisplayDebugInformation)
226
+ console.log("Tree treePathSeparator:", treePathSeparator)
227
+
227
228
  // svelte-ignore non_reactive_update
228
229
  const tree: Ltree<T> = createLTree<T>(
229
230
  idMember,
@@ -257,6 +258,11 @@
257
258
  }
258
259
  );
259
260
 
261
+ // Update tree separator when prop changes
262
+ $effect(() => {
263
+ tree.treePathSeparator = treePathSeparator;
264
+ });
265
+
260
266
  setContext('Ltree', tree);
261
267
 
262
268
  $effect(() => {
@@ -284,7 +290,6 @@
284
290
  if (selectedNode) {
285
291
  const previousNode = tree.getNodeByPath(selectedNode.path);
286
292
  if (previousNode) {
287
- console.log('🚀 ~ _onNodeClicked ~ previousNode:', previousNode);
288
293
  previousNode.isSelected = false;
289
294
  } else selectedNode = null;
290
295
  }
@@ -325,8 +330,6 @@
325
330
  // event.dataTransfer.effectAllowed = "move";
326
331
  // event.dataTransfer.setData("text/plain", node.path);
327
332
  // }
328
-
329
- console.log('🚀 ~ _onNodeDragStart ~ draggedNode:', draggedNode, event);
330
333
  }
331
334
 
332
335
  function _onNodeDragOver(node: LTreeNode<T>, event: DragEvent) {
@@ -464,8 +467,8 @@
464
467
  </div>
465
468
  {/if}
466
469
  </div>
467
-
468
- {@render treeFooter?.()}
470
+
471
+ {@render treeFooter?.()}
469
472
 
470
473
  <!-- Context Menu -->
471
474
  {#if contextMenuVisible && contextMenu && contextMenuNode}
@@ -137,6 +137,7 @@ export function createLTree(_idMember, _pathMember, _parentPathMember, _levelMem
137
137
  const itemsToIndex = [];
138
138
  let realIndex = 0; // this is used to avoid scenario, when node cannot found a parent
139
139
  let successfulCount = 0;
140
+ let hasRenderedExpandLevel = false;
140
141
  mappedData.forEach((node, index) => {
141
142
  const result = this.insertTreeNode(node.parentPath, node, true);
142
143
  if (result) {
@@ -154,6 +155,23 @@ export function createLTree(_idMember, _pathMember, _parentPathMember, _levelMem
154
155
  itemsToIndex.push({ node, index: realIndex });
155
156
  realIndex++;
156
157
  }
158
+ // Progressive rendering: emit changes when we complete expandLevel
159
+ if (!noEmitChanges && !hasRenderedExpandLevel && _expandLevel && node.level && node.level <= _expandLevel) {
160
+ // Check if this might be the last node at expandLevel by looking ahead
161
+ const remainingNodes = mappedData.slice(index + 1);
162
+ const hasMoreAtExpandLevel = remainingNodes.some(futureNode => {
163
+ const futureLevel = futureNode.level || getLevel(futureNode.path, this.treePathSeparator);
164
+ return futureLevel <= _expandLevel;
165
+ });
166
+ if (!hasMoreAtExpandLevel) {
167
+ // We've processed all nodes up to expandLevel - render now!
168
+ hasRenderedExpandLevel = true;
169
+ this._emitTreeChanged();
170
+ if (this.shouldDisplayDebugInformation) {
171
+ console.log(`[Tree ${_treeId}] Progressive render: Displayed levels 1-${_expandLevel} (${successfulCount} nodes processed so far)`);
172
+ }
173
+ }
174
+ }
157
175
  }
158
176
  });
159
177
  // Log errors for backward compatibility and debugging
@@ -172,8 +190,22 @@ export function createLTree(_idMember, _pathMember, _parentPathMember, _levelMem
172
190
  });
173
191
  indexer.addToQueue(itemsToIndex);
174
192
  }
193
+ // Final render (only if we haven't already rendered progressively)
175
194
  if (!noEmitChanges) {
176
- this._emitTreeChanged();
195
+ if (hasRenderedExpandLevel) {
196
+ // We already rendered expandLevel, now render the complete tree
197
+ this._emitTreeChanged();
198
+ if (this.shouldDisplayDebugInformation) {
199
+ console.log(`[Tree ${_treeId}] Final render: Complete tree with all ${successfulCount} nodes`);
200
+ }
201
+ }
202
+ else {
203
+ // No progressive rendering occurred, render everything at once
204
+ this._emitTreeChanged();
205
+ if (this.shouldDisplayDebugInformation) {
206
+ console.log(`[Tree ${_treeId}] Single render: All ${successfulCount} nodes (no expandLevel or progressive render conditions met)`);
207
+ }
208
+ }
177
209
  }
178
210
  performance.mark('insert-end');
179
211
  performance.measure('sort-duration', 'sort-start', 'sort-end');
@@ -425,6 +457,13 @@ export function createLTree(_idMember, _pathMember, _parentPathMember, _levelMem
425
457
  },
426
458
  _defaultSort: function (self, items) {
427
459
  return items.sort((a, b) => {
460
+ // First, sort by level (shallower levels first)
461
+ const aLevel = a.level || 0;
462
+ const bLevel = b.level || 0;
463
+ if (aLevel !== bLevel) {
464
+ return aLevel - bLevel;
465
+ }
466
+ // Then sort by parent path
428
467
  if (a.parentPath !== b.parentPath) {
429
468
  if (a.parentPath === '')
430
469
  return -1;
@@ -432,13 +471,8 @@ export function createLTree(_idMember, _pathMember, _parentPathMember, _levelMem
432
471
  return 1;
433
472
  return a.parentPath.localeCompare(b.parentPath);
434
473
  }
435
- // console.log(
436
- // 'a.name, b.name, comparison',
437
- // self.getNodeDisplayValue(a),
438
- // self.getNodeDisplayValue(b),
439
- // self.getNodeDisplayValue(a).localeCompare(this.getNodeDisplayValue(b))
440
- // );
441
- return self.getNodeDisplayValue(a).localeCompare(this.getNodeDisplayValue(b));
474
+ // Finally sort by display value
475
+ return self.getNodeDisplayValue(a).localeCompare(self.getNodeDisplayValue(b));
442
476
  });
443
477
  },
444
478
  _emitTreeChanged: function () {
package/dist/styles.scss CHANGED
@@ -1,2 +1,2 @@
1
1
  // CSS entry point for the library
2
- @import './styles/main.scss';
2
+ @use './styles/main.scss';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keenmate/svelte-treeview",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev --port 17777",
6
6
  "build": "vite build && npm run prepack",