@vectoriox/iox-builder 1.4.57 → 1.4.59

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.
@@ -309,6 +309,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
309
309
  type: Injectable
310
310
  }] });
311
311
 
312
+ /**
313
+ * SymbolRegistryService — in-memory store for org-level symbols.
314
+ *
315
+ * Loaded once per page by PageUiComponent alongside the page layout.
316
+ * Scoped to PageUiComponent.providers[] via IoxBuilderModule — one registry per builder instance.
317
+ */
318
+ class SymbolRegistryService {
319
+ constructor() {
320
+ this.symbols = new Map();
321
+ /** symbolIds that have a live reusable block in the DB — used to guard isDetachedSymbol. */
322
+ this.blockSymbolIds = new Set();
323
+ }
324
+ setSymbols(symbols) {
325
+ this.symbols.clear();
326
+ for (const s of symbols) {
327
+ this.symbols.set(s.id, s);
328
+ }
329
+ }
330
+ getSymbol(id) {
331
+ return this.symbols.get(id);
332
+ }
333
+ getAll() {
334
+ return Array.from(this.symbols.values());
335
+ }
336
+ upsert(symbol) {
337
+ this.symbols.set(symbol.id, symbol);
338
+ }
339
+ remove(id) {
340
+ this.symbols.delete(id);
341
+ }
342
+ /** Set the symbolIds that have a live reusable block. Called on page load. */
343
+ setBlockSymbolIds(ids) {
344
+ this.blockSymbolIds = new Set(ids);
345
+ }
346
+ /** Returns true only when the symbol has a live backing reusable block. */
347
+ isBlockSymbol(id) {
348
+ return this.blockSymbolIds.has(id);
349
+ }
350
+ /** Remove a symbolId from the block-backed set (called when a block is deleted). */
351
+ removeBlockSymbolId(id) {
352
+ this.blockSymbolIds.delete(id);
353
+ }
354
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
355
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService }); }
356
+ }
357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService, decorators: [{
358
+ type: Injectable
359
+ }] });
360
+
312
361
  function deepCloneNode(node) {
313
362
  const clone = JSON.parse(JSON.stringify(node));
314
363
  regenerateIds(clone);
@@ -320,8 +369,9 @@ function regenerateIds(node) {
320
369
  (node.children || []).forEach(regenerateIds);
321
370
  }
322
371
  class DragEngineService {
323
- constructor(registry) {
372
+ constructor(registry, symbolRegistry) {
324
373
  this.registry = registry;
374
+ this.symbolRegistry = symbolRegistry;
325
375
  // ── Drop-zone registry ────────────────────────────────────
326
376
  this.ids = [];
327
377
  this.elMap = new Map();
@@ -385,7 +435,9 @@ class DragEngineService {
385
435
  }
386
436
  else {
387
437
  // Full block object { node, symbolId, syncInstances } or bare ComponentNode.
388
- const nodeData = data.node ?? data;
438
+ // Prefer symbol.node (always up-to-date) over block.node (original snapshot).
439
+ const symbolNode = data.symbolId ? this.symbolRegistry.getSymbol(data.symbolId)?.node : null;
440
+ const nodeData = (symbolNode ?? data.node ?? data);
389
441
  const cloned = deepCloneNode(nodeData);
390
442
  if (data.syncInstances && data.symbolId) {
391
443
  cloned.symbolId = data.symbolId;
@@ -417,10 +469,13 @@ class DragEngineService {
417
469
  // produces a fully independent node, preventing shared CSS rules.
418
470
  // The panel may supply a bare ComponentNode OR a block wrapper object
419
471
  // { node, symbolId, syncInstances } — extract the node first.
420
- const nodeData = item.node ?? item;
472
+ // Prefer symbol.node (always up-to-date) over block.node (original snapshot).
473
+ const blk = item;
474
+ const symbolNode2 = blk.symbolId ? this.symbolRegistry.getSymbol(blk.symbolId)?.node : null;
475
+ const nodeData = (symbolNode2 ?? blk.node ?? item);
421
476
  const cloned = deepCloneNode(nodeData);
422
- if (item.syncInstances && item.symbolId) {
423
- cloned.symbolId = item.symbolId;
477
+ if (blk.syncInstances && blk.symbolId) {
478
+ cloned.symbolId = blk.symbolId;
424
479
  }
425
480
  children.splice(insertIndex, 0, cloned);
426
481
  cdr.detectChanges();
@@ -992,12 +1047,12 @@ class DragEngineService {
992
1047
  }
993
1048
  return children.length;
994
1049
  }
995
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DragEngineService, deps: [{ token: ComponentRegistryService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1050
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DragEngineService, deps: [{ token: ComponentRegistryService }, { token: SymbolRegistryService }], target: i0.ɵɵFactoryTarget.Injectable }); }
996
1051
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DragEngineService }); }
997
1052
  }
998
1053
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DragEngineService, decorators: [{
999
1054
  type: Injectable
1000
- }], ctorParameters: () => [{ type: ComponentRegistryService }] });
1055
+ }], ctorParameters: () => [{ type: ComponentRegistryService }, { type: SymbolRegistryService }] });
1001
1056
 
1002
1057
  /**
1003
1058
  * Page-scoped registry that holds the current page's data sources.
@@ -1640,41 +1695,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
1640
1695
  type: Injectable
1641
1696
  }] });
1642
1697
 
1643
- /**
1644
- * SymbolRegistryService — in-memory store for org-level symbols.
1645
- *
1646
- * Loaded once per page by PageUiComponent alongside the page layout.
1647
- * Scoped to PageUiComponent.providers[] via IoxBuilderModule — one registry per builder instance.
1648
- */
1649
- class SymbolRegistryService {
1650
- constructor() {
1651
- this.symbols = new Map();
1652
- }
1653
- setSymbols(symbols) {
1654
- this.symbols.clear();
1655
- for (const s of symbols) {
1656
- this.symbols.set(s.id, s);
1657
- }
1658
- }
1659
- getSymbol(id) {
1660
- return this.symbols.get(id);
1661
- }
1662
- getAll() {
1663
- return Array.from(this.symbols.values());
1664
- }
1665
- upsert(symbol) {
1666
- this.symbols.set(symbol.id, symbol);
1667
- }
1668
- remove(id) {
1669
- this.symbols.delete(id);
1670
- }
1671
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1672
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService }); }
1673
- }
1674
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService, decorators: [{
1675
- type: Injectable
1676
- }] });
1677
-
1678
1698
  // Virtual trait → composed CSS property helpers.
1679
1699
  //
1680
1700
  // Several style traits are "virtual" — they don't map 1:1 to a CSS property but
@@ -2947,7 +2967,11 @@ class OverlayComponent {
2947
2967
  return !!this.selectEntry?.node?.symbolId;
2948
2968
  }
2949
2969
  get isDetachedSymbol() {
2950
- return !this.selectEntry?.node?.symbolId && !!this.selectEntry?.node?.detachedSymbolId;
2970
+ const node = this.selectEntry?.node;
2971
+ if (!node || node.symbolId || !node.detachedSymbolId)
2972
+ return false;
2973
+ // Only show the re-link button when the backing block still exists.
2974
+ return this.symbolRegistry.isBlockSymbol(node.detachedSymbolId);
2951
2975
  }
2952
2976
  get linkedSymbolName() {
2953
2977
  const id = this.selectEntry?.node?.symbolId;
@@ -3878,8 +3902,10 @@ class BuilderComponent {
3878
3902
  if (payload.sourceId === 'blocks-panel') {
3879
3903
  // Reusable block from the palette — may be a bare ComponentNode or a
3880
3904
  // block wrapper { name, node, syncInstances, symbolId }. Extract the node.
3905
+ // Prefer symbol.node (always up-to-date) over block.node (original snapshot).
3881
3906
  const data = item;
3882
- const nodeData = data.node ?? data;
3907
+ const symbolNode = data.symbolId ? this.symbolRegistry.getSymbol(data.symbolId)?.node : null;
3908
+ const nodeData = (symbolNode ?? data.node ?? data);
3883
3909
  const clone = this.deepCloneWithNewIds(nodeData);
3884
3910
  if (data.syncInstances && data.symbolId) {
3885
3911
  clone.symbolId = data.symbolId;