@splicetree/adapter-vue 3.0.1 → 3.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.
Files changed (2) hide show
  1. package/dist/index.js +121 -9
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -318,6 +318,36 @@ function moveNode(ctx, id, newParentId, beforeId) {
318
318
  setLevelRecursively(node, ctx.childrenCache, node.level);
319
319
  ctx.notify();
320
320
  }
321
+ function removeNodes(ctx, ids) {
322
+ const list = Array.isArray(ids) ? ids : [ids];
323
+ const toRemove = /* @__PURE__ */ new Set();
324
+ const collect = (id) => {
325
+ if (toRemove.has(id)) return;
326
+ toRemove.add(id);
327
+ const children = ctx.childrenCache.get(id) ?? [];
328
+ for (const c of children) collect(c.id);
329
+ };
330
+ for (const id of list) if (ctx.map.has(id)) collect(id);
331
+ for (const id of toRemove) {
332
+ const parent = ctx.parentCache.get(id);
333
+ if (parent) {
334
+ const arr = ctx.childrenCache.get(parent.id) ?? [];
335
+ const idx = arr.findIndex((n) => n.id === id);
336
+ if (idx >= 0) arr.splice(idx, 1);
337
+ } else {
338
+ const idx = ctx.roots.findIndex((n) => n.id === id);
339
+ if (idx >= 0) ctx.roots.splice(idx, 1);
340
+ }
341
+ }
342
+ for (const id of toRemove) {
343
+ ctx.childrenCache.delete(id);
344
+ ctx.parentCache.delete(id);
345
+ ctx.map.delete(id);
346
+ ctx.expandedKeys.delete(id);
347
+ }
348
+ for (const r of ctx.roots) setLevelRecursively(r, ctx.childrenCache, 0);
349
+ ctx.notify();
350
+ }
321
351
  /**
322
352
  * 创建 SpliceTree 树实例
323
353
  * - 构建缓存结构
@@ -325,6 +355,7 @@ function moveNode(ctx, id, newParentId, beforeId) {
325
355
  * - 提供插件扩展点(setup/extendNode)
326
356
  */
327
357
  function createSpliceTree(data, options = {}) {
358
+ let pluginCtx;
328
359
  const cfg = options.configuration ?? {};
329
360
  const keyField = cfg.keyField ?? "id";
330
361
  const parentField = cfg.parentField ?? "parent";
@@ -394,7 +425,10 @@ function createSpliceTree(data, options = {}) {
394
425
  parentCache,
395
426
  childrenCache,
396
427
  expandedKeys,
397
- notify: emitVisibility
428
+ notify: () => {
429
+ applyNodeExtensions();
430
+ emitVisibility();
431
+ }
398
432
  }, parentId, children);
399
433
  },
400
434
  moveNode(id, newParentId, beforeId) {
@@ -409,6 +443,31 @@ function createSpliceTree(data, options = {}) {
409
443
  notify: emitVisibility
410
444
  }, id, newParentId, beforeId);
411
445
  },
446
+ remove(ids) {
447
+ removeNodes({
448
+ map,
449
+ tree,
450
+ roots,
451
+ keyField,
452
+ parentCache,
453
+ childrenCache,
454
+ expandedKeys,
455
+ notify: emitVisibility
456
+ }, ids);
457
+ },
458
+ updateOriginal(id, patch) {
459
+ const node = map.get(id);
460
+ if (!node) return false;
461
+ if (Object.prototype.hasOwnProperty.call(patch, keyField)) return false;
462
+ if (Object.prototype.hasOwnProperty.call(patch, parentField)) {
463
+ const nextParent = patch[parentField];
464
+ if (nextParent !== node.getParent()?.id) tree.moveNode(id, nextParent);
465
+ delete patch[parentField];
466
+ }
467
+ Object.assign(node.original, patch);
468
+ emitVisibility();
469
+ return true;
470
+ },
412
471
  syncData(next) {
413
472
  tree.data = next;
414
473
  const built = buildTree(next, keyField, parentField, expandedKeys);
@@ -423,13 +482,21 @@ function createSpliceTree(data, options = {}) {
423
482
  });
424
483
  for (const id of toDelete) expandedKeys.delete(id);
425
484
  applyNodeExtensions();
485
+ pluginCtx.roots = roots;
486
+ pluginCtx.map = map;
487
+ pluginCtx.parentCache = parentCache;
488
+ pluginCtx.childrenCache = childrenCache;
426
489
  emitVisibility();
427
490
  }
428
491
  };
429
- const pluginCtx = {
492
+ pluginCtx = {
430
493
  tree,
431
494
  options,
432
- events
495
+ events,
496
+ roots,
497
+ map,
498
+ parentCache,
499
+ childrenCache
433
500
  };
434
501
  options?.plugins?.forEach((plugin) => {
435
502
  const api = plugin.setup?.(pluginCtx);
@@ -444,12 +511,56 @@ function createSpliceTree(data, options = {}) {
444
511
  else if (expand) tree.expand(node.id);
445
512
  else tree.collapse(node.id);
446
513
  };
514
+ node.updateOriginal = (patch) => {
515
+ tree.updateOriginal(node.id, patch);
516
+ };
447
517
  }
448
518
  }
449
519
  applyNodeExtensions();
450
520
  return tree;
451
521
  }
452
522
 
523
+ //#endregion
524
+ //#region src/utils.ts
525
+ function isStructuralChange(prev, next, keyField, parentField) {
526
+ const prevMap = /* @__PURE__ */ new Map();
527
+ for (const it of prev ?? []) {
528
+ const id = String(Reflect.get(it, keyField));
529
+ prevMap.set(id, it);
530
+ }
531
+ let structural = false;
532
+ const nextMap = /* @__PURE__ */ new Map();
533
+ for (const it of next ?? []) {
534
+ const id = String(Reflect.get(it, keyField));
535
+ nextMap.set(id, it);
536
+ const old = prevMap.get(id);
537
+ if (!old) {
538
+ structural = true;
539
+ continue;
540
+ }
541
+ if (Reflect.get(it, parentField) !== Reflect.get(old, parentField)) structural = true;
542
+ }
543
+ for (const id of prevMap.keys()) if (!nextMap.has(id)) {
544
+ structural = true;
545
+ break;
546
+ }
547
+ return structural;
548
+ }
549
+ function applyFieldPatches(api, next, keyField, parentField) {
550
+ for (const it of next ?? []) {
551
+ const id = String(Reflect.get(it, keyField));
552
+ const node = api.getNode(id);
553
+ if (!node) continue;
554
+ const patch = {};
555
+ for (const k of Object.keys(it)) {
556
+ if (k === keyField || k === parentField) continue;
557
+ const nv = it[k];
558
+ if (nv !== node.original?.[k]) patch[k] = nv;
559
+ }
560
+ if (Object.keys(patch).length) api.updateOriginal(id, patch);
561
+ }
562
+ }
563
+
453
564
  //#endregion
454
565
  //#region src/index.ts
455
566
  /**
@@ -488,13 +599,14 @@ function useSpliceTree(data, options = {}) {
488
599
  applyExpandedKeys(options?.expandedKeys ? toValue(options.expandedKeys) : void 0);
489
600
  };
490
601
  createTree();
491
- watch(() => toValue(data), () => {
492
- api.value.syncData(toValue(data));
602
+ watch(() => toValue(data), (next) => {
603
+ const cfg = options?.configuration ?? {};
604
+ const keyField = cfg.keyField ?? "id";
605
+ const parentField = cfg.parentField ?? "parent";
606
+ if (isStructuralChange(api.value?.data ?? [], next, keyField, parentField)) api.value.syncData(next);
607
+ else applyFieldPatches(api.value, next, keyField, parentField);
493
608
  applyExpandedKeys(options?.expandedKeys ? toValue(options.expandedKeys) : void 0);
494
- }, {
495
- deep: true,
496
- immediate: false
497
- });
609
+ }, { immediate: false });
498
610
  watch(() => options?.expandedKeys ? toValue(options.expandedKeys) : void 0, (val) => {
499
611
  applyExpandedKeys(val);
500
612
  }, {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@splicetree/adapter-vue",
3
3
  "type": "module",
4
- "version": "3.0.1",
4
+ "version": "3.1.0",
5
5
  "author": {
6
6
  "email": "michael.cocova@gmail.com",
7
7
  "name": "Michael Cocova"
@@ -30,7 +30,7 @@
30
30
  "unplugin-vue": "^7.1.0",
31
31
  "vue": "^3.0.0",
32
32
  "vue-tsc": "^3.1.5",
33
- "@splicetree/core": "3.0.1"
33
+ "@splicetree/core": "3.1.0"
34
34
  },
35
35
  "publishConfig": {
36
36
  "access": "public"