@vectoriox/iox-builder 1.4.56 → 1.4.58

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,41 @@ 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
+ }
322
+ setSymbols(symbols) {
323
+ this.symbols.clear();
324
+ for (const s of symbols) {
325
+ this.symbols.set(s.id, s);
326
+ }
327
+ }
328
+ getSymbol(id) {
329
+ return this.symbols.get(id);
330
+ }
331
+ getAll() {
332
+ return Array.from(this.symbols.values());
333
+ }
334
+ upsert(symbol) {
335
+ this.symbols.set(symbol.id, symbol);
336
+ }
337
+ remove(id) {
338
+ this.symbols.delete(id);
339
+ }
340
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
341
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService }); }
342
+ }
343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: SymbolRegistryService, decorators: [{
344
+ type: Injectable
345
+ }] });
346
+
312
347
  function deepCloneNode(node) {
313
348
  const clone = JSON.parse(JSON.stringify(node));
314
349
  regenerateIds(clone);
@@ -320,8 +355,9 @@ function regenerateIds(node) {
320
355
  (node.children || []).forEach(regenerateIds);
321
356
  }
322
357
  class DragEngineService {
323
- constructor(registry) {
358
+ constructor(registry, symbolRegistry) {
324
359
  this.registry = registry;
360
+ this.symbolRegistry = symbolRegistry;
325
361
  // ── Drop-zone registry ────────────────────────────────────
326
362
  this.ids = [];
327
363
  this.elMap = new Map();
@@ -385,7 +421,9 @@ class DragEngineService {
385
421
  }
386
422
  else {
387
423
  // Full block object { node, symbolId, syncInstances } or bare ComponentNode.
388
- const nodeData = data.node ?? data;
424
+ // Prefer symbol.node (always up-to-date) over block.node (original snapshot).
425
+ const symbolNode = data.symbolId ? this.symbolRegistry.getSymbol(data.symbolId)?.node : null;
426
+ const nodeData = (symbolNode ?? data.node ?? data);
389
427
  const cloned = deepCloneNode(nodeData);
390
428
  if (data.syncInstances && data.symbolId) {
391
429
  cloned.symbolId = data.symbolId;
@@ -417,10 +455,13 @@ class DragEngineService {
417
455
  // produces a fully independent node, preventing shared CSS rules.
418
456
  // The panel may supply a bare ComponentNode OR a block wrapper object
419
457
  // { node, symbolId, syncInstances } — extract the node first.
420
- const nodeData = item.node ?? item;
458
+ // Prefer symbol.node (always up-to-date) over block.node (original snapshot).
459
+ const blk = item;
460
+ const symbolNode2 = blk.symbolId ? this.symbolRegistry.getSymbol(blk.symbolId)?.node : null;
461
+ const nodeData = (symbolNode2 ?? blk.node ?? item);
421
462
  const cloned = deepCloneNode(nodeData);
422
- if (item.syncInstances && item.symbolId) {
423
- cloned.symbolId = item.symbolId;
463
+ if (blk.syncInstances && blk.symbolId) {
464
+ cloned.symbolId = blk.symbolId;
424
465
  }
425
466
  children.splice(insertIndex, 0, cloned);
426
467
  cdr.detectChanges();
@@ -992,12 +1033,12 @@ class DragEngineService {
992
1033
  }
993
1034
  return children.length;
994
1035
  }
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 }); }
1036
+ 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
1037
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DragEngineService }); }
997
1038
  }
998
1039
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DragEngineService, decorators: [{
999
1040
  type: Injectable
1000
- }], ctorParameters: () => [{ type: ComponentRegistryService }] });
1041
+ }], ctorParameters: () => [{ type: ComponentRegistryService }, { type: SymbolRegistryService }] });
1001
1042
 
1002
1043
  /**
1003
1044
  * Page-scoped registry that holds the current page's data sources.
@@ -1640,41 +1681,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
1640
1681
  type: Injectable
1641
1682
  }] });
1642
1683
 
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
1684
  // Virtual trait → composed CSS property helpers.
1679
1685
  //
1680
1686
  // Several style traits are "virtual" — they don't map 1:1 to a CSS property but
@@ -3878,8 +3884,10 @@ class BuilderComponent {
3878
3884
  if (payload.sourceId === 'blocks-panel') {
3879
3885
  // Reusable block from the palette — may be a bare ComponentNode or a
3880
3886
  // block wrapper { name, node, syncInstances, symbolId }. Extract the node.
3887
+ // Prefer symbol.node (always up-to-date) over block.node (original snapshot).
3881
3888
  const data = item;
3882
- const nodeData = data.node ?? data;
3889
+ const symbolNode = data.symbolId ? this.symbolRegistry.getSymbol(data.symbolId)?.node : null;
3890
+ const nodeData = (symbolNode ?? data.node ?? data);
3883
3891
  const clone = this.deepCloneWithNewIds(nodeData);
3884
3892
  if (data.syncInstances && data.symbolId) {
3885
3893
  clone.symbolId = data.symbolId;
@@ -3985,7 +3993,9 @@ class BuilderComponent {
3985
3993
  this.selectedItem = event.node;
3986
3994
  this.overlayService.setSelect(event.element, event.node.type, this.activeMode, event.node, event.componentRef);
3987
3995
  this.selectPanel(PanelTypes.STYLES);
3988
- this.panelEventService.emit(PanelEventTypes.ELEMENT_SELECT, { node: event.node, componentRef: event.componentRef });
3996
+ const symbolAncestor = this.findSymbolAncestorOf(event.node, this.layout)
3997
+ ?? this.findSymbolAncestorOf(event.node, this.globalElements);
3998
+ this.panelEventService.emit(PanelEventTypes.ELEMENT_SELECT, { node: event.node, componentRef: event.componentRef, symbolAncestor });
3989
3999
  }
3990
4000
  _selectAfterDrop(node) {
3991
4001
  // Wait one tick for Angular to render the new component and register it
@@ -3997,7 +4007,9 @@ class BuilderComponent {
3997
4007
  this.selectedItem = node;
3998
4008
  this.overlayService.setSelect(ref.element, node.type, this.activeMode, node, ref.componentRef);
3999
4009
  this.selectPanel(PanelTypes.STYLES);
4000
- this.panelEventService.emit(PanelEventTypes.ELEMENT_SELECT, { node, componentRef: ref.componentRef });
4010
+ const symbolAncestor = this.findSymbolAncestorOf(node, this.layout)
4011
+ ?? this.findSymbolAncestorOf(node, this.globalElements);
4012
+ this.panelEventService.emit(PanelEventTypes.ELEMENT_SELECT, { node, componentRef: ref.componentRef, symbolAncestor });
4001
4013
  });
4002
4014
  }
4003
4015
  handleMouseEnter(event) {
@@ -4021,7 +4033,9 @@ class BuilderComponent {
4021
4033
  this.selectedItem = node;
4022
4034
  const ref = this.overlayService.getNodeRef(node);
4023
4035
  if (ref) {
4024
- this.panelEventService.emit(PanelEventTypes.ELEMENT_SELECT, { node, componentRef: ref.componentRef });
4036
+ const symbolAncestor = this.findSymbolAncestorOf(node, this.layout)
4037
+ ?? this.findSymbolAncestorOf(node, this.globalElements);
4038
+ this.panelEventService.emit(PanelEventTypes.ELEMENT_SELECT, { node, componentRef: ref.componentRef, symbolAncestor });
4025
4039
  }
4026
4040
  this.selectPanel(PanelTypes.STYLES);
4027
4041
  }
@@ -4300,6 +4314,19 @@ class BuilderComponent {
4300
4314
  }
4301
4315
  return null;
4302
4316
  }
4317
+ /** Returns the closest ancestor (or self) of `target` that has a `symbolId`. */
4318
+ findSymbolAncestorOf(target, nodes) {
4319
+ for (const node of nodes) {
4320
+ if (node === target)
4321
+ return node.symbolId ? node : null;
4322
+ if (node.children?.length && this.findNodeInTree(target, node.children)) {
4323
+ if (node.symbolId)
4324
+ return node;
4325
+ return this.findSymbolAncestorOf(target, node.children);
4326
+ }
4327
+ }
4328
+ return null;
4329
+ }
4303
4330
  handlePanelEvents(panelEvent) {
4304
4331
  if (panelEvent.type === PanelEventTypes.PANEL_CLOSE) {
4305
4332
  this.isPanelOpen = false;