@vectoriox/iox-builder 1.0.8 → 1.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.
@@ -31,6 +31,10 @@ var PanelEventTypes;
31
31
  PanelEventTypes["PANEL_CLOSE"] = "panelclose";
32
32
  PanelEventTypes["BINDING_CHANGED"] = "bindingchanged";
33
33
  PanelEventTypes["NODE_RENDERED"] = "noderendered";
34
+ /** Open the Style panel in preset-edit mode for the given preset ID. */
35
+ PanelEventTypes["PRESET_EDIT"] = "presetedit";
36
+ /** Fired after a preset is created, updated, or deleted so panels refresh their list. */
37
+ PanelEventTypes["PRESETS_CHANGED"] = "presetschanged";
34
38
  })(PanelEventTypes || (PanelEventTypes = {}));
35
39
  class PanelEventService {
36
40
  constructor() {
@@ -109,6 +113,7 @@ var ToolbarAction;
109
113
  ToolbarAction["SaveAsBlock"] = "save-as-block";
110
114
  ToolbarAction["MakeGlobal"] = "make-global";
111
115
  ToolbarAction["RemoveGlobal"] = "remove-global";
116
+ ToolbarAction["EditPreset"] = "edit-preset";
112
117
  })(ToolbarAction || (ToolbarAction = {}));
113
118
  var NodeAction;
114
119
  (function (NodeAction) {
@@ -929,13 +934,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
929
934
  type: Injectable
930
935
  }] });
931
936
 
937
+ const STORAGE_KEY = 'iox_builder_viewport';
932
938
  class ViewportService {
933
939
  constructor() {
934
- this.state = {
935
- device: DeviceMode.Desktop,
936
- width: DEVICE_OPTIONS[0].width,
937
- scale: 0.75,
938
- };
940
+ this.state = this.loadFromStorage();
939
941
  this.stateSubject = new BehaviorSubject(this.state);
940
942
  this.state$ = this.stateSubject.asObservable();
941
943
  }
@@ -949,16 +951,13 @@ class ViewportService {
949
951
  const option = DEVICE_OPTIONS.find(d => d.mode === device);
950
952
  if (!option)
951
953
  return;
952
- this.state = { ...this.state, device, width: option.width };
953
- this.stateSubject.next(this.state);
954
+ this.update({ device, width: option.width });
954
955
  }
955
956
  setScale(scale) {
956
- this.state = { ...this.state, scale: Math.max(0.1, Math.min(2, scale)) };
957
- this.stateSubject.next(this.state);
957
+ this.update({ scale: Math.max(0.1, Math.min(2, scale)) });
958
958
  }
959
959
  setWidth(width) {
960
- this.state = { ...this.state, width };
961
- this.stateSubject.next(this.state);
960
+ this.update({ width });
962
961
  }
963
962
  /**
964
963
  * Calculate the scale that makes the canvas fit inside the available editor width.
@@ -982,6 +981,42 @@ class ViewportService {
982
981
  y: (screenY - canvasRect.top) / this.state.scale,
983
982
  };
984
983
  }
984
+ update(partial) {
985
+ this.state = { ...this.state, ...partial };
986
+ this.stateSubject.next(this.state);
987
+ this.saveToStorage();
988
+ }
989
+ saveToStorage() {
990
+ try {
991
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state));
992
+ }
993
+ catch { }
994
+ }
995
+ loadFromStorage() {
996
+ const defaults = {
997
+ device: DeviceMode.Desktop,
998
+ width: DEVICE_OPTIONS[0].width,
999
+ scale: 0.75,
1000
+ };
1001
+ try {
1002
+ const raw = localStorage.getItem(STORAGE_KEY);
1003
+ if (!raw)
1004
+ return defaults;
1005
+ const saved = JSON.parse(raw);
1006
+ const device = Object.values(DeviceMode).includes(saved.device)
1007
+ ? saved.device
1008
+ : defaults.device;
1009
+ const option = DEVICE_OPTIONS.find(d => d.mode === device) ?? DEVICE_OPTIONS[0];
1010
+ return {
1011
+ device,
1012
+ width: typeof saved.width === 'number' && saved.width > 0 ? saved.width : option.width,
1013
+ scale: typeof saved.scale === 'number' ? Math.max(0.1, Math.min(2, saved.scale)) : defaults.scale,
1014
+ };
1015
+ }
1016
+ catch {
1017
+ return defaults;
1018
+ }
1019
+ }
985
1020
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
986
1021
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ViewportService }); }
987
1022
  }
@@ -1531,10 +1566,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
1531
1566
  type: Input
1532
1567
  }] } });
1533
1568
 
1569
+ /**
1570
+ * PresetRegistryService — in-memory store for org-level style presets.
1571
+ *
1572
+ * Loaded once per page by PageUiComponent (alongside the page layout) and
1573
+ * injected into the overlay (for badge labels) and style panel (for apply /
1574
+ * create / edit / detach flows).
1575
+ *
1576
+ * Scoped to PageUiComponent.providers[] — one registry per builder instance.
1577
+ */
1578
+ class PresetRegistryService {
1579
+ constructor() {
1580
+ this.presets = new Map();
1581
+ }
1582
+ setPresets(presets) {
1583
+ this.presets.clear();
1584
+ for (const p of presets) {
1585
+ this.presets.set(p.id, p);
1586
+ }
1587
+ }
1588
+ getPreset(id) {
1589
+ return this.presets.get(id);
1590
+ }
1591
+ getAll() {
1592
+ return Array.from(this.presets.values());
1593
+ }
1594
+ upsert(preset) {
1595
+ this.presets.set(preset.id, preset);
1596
+ }
1597
+ remove(id) {
1598
+ this.presets.delete(id);
1599
+ }
1600
+ /**
1601
+ * Resolve the effective style map for a node that references a preset.
1602
+ * Merges preset base styles with the node's local overrides so that
1603
+ * element-level values always win.
1604
+ *
1605
+ * @param presetId ID of the applied preset.
1606
+ * @param overrides The node's `styleOverrides` record (may be empty).
1607
+ */
1608
+ resolveStyles(presetId, overrides) {
1609
+ const preset = this.presets.get(presetId);
1610
+ if (!preset)
1611
+ return { ...overrides };
1612
+ return { ...preset.styleProps, ...overrides };
1613
+ }
1614
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: PresetRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1615
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: PresetRegistryService }); }
1616
+ }
1617
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: PresetRegistryService, decorators: [{
1618
+ type: Injectable
1619
+ }] });
1620
+
1534
1621
  class OverlayComponent {
1535
- constructor(overlayService, viewportService, cdr) {
1622
+ constructor(overlayService, viewportService, presetRegistry, cdr) {
1536
1623
  this.overlayService = overlayService;
1537
1624
  this.viewportService = viewportService;
1625
+ this.presetRegistry = presetRegistry;
1538
1626
  this.cdr = cdr;
1539
1627
  this.toolbarAction = new EventEmitter();
1540
1628
  this.hoverEntry = null;
@@ -1672,6 +1760,17 @@ class OverlayComponent {
1672
1760
  get selectedNodeIsGlobal() {
1673
1761
  return !!this.selectEntry?.node?.isGlobal;
1674
1762
  }
1763
+ get selectedPresetName() {
1764
+ const id = this.selectEntry?.node?.stylePresetId;
1765
+ if (!id)
1766
+ return null;
1767
+ return this.presetRegistry.getPreset(id)?.name ?? null;
1768
+ }
1769
+ onEditPreset(event) {
1770
+ event.stopPropagation();
1771
+ if (this.selectEntry)
1772
+ this.toolbarAction.emit({ action: ToolbarAction.EditPreset, entry: this.selectEntry });
1773
+ }
1675
1774
  observeSelectElement() {
1676
1775
  this.resizeObserver?.disconnect();
1677
1776
  this.mutationObserver?.disconnect();
@@ -1779,13 +1878,13 @@ class OverlayComponent {
1779
1878
  // is a zero-area line — prevents diagonal edge triangle artifacts.
1780
1879
  return `polygon(evenodd, 0px 0px, ${w}px 0px, ${w}px ${h}px, 0px ${h}px, 0px 0px, ${x1}px ${y1}px, ${x2}px ${y1}px, ${x2}px ${y2}px, ${x1}px ${y2}px, ${x1}px ${y1}px)`;
1781
1880
  }
1782
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OverlayComponent, deps: [{ token: OverlayService }, { token: ViewportService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1783
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: OverlayComponent, isStandalone: false, selector: "app-overlay", outputs: { toolbarAction: "toolbarAction" }, ngImport: i0, template: "<div class=\"overlay-root\">\n\n <!-- HOVER \u2014 Chrome DevTools-style rings (content area stays transparent) -->\n <ng-container *ngIf=\"hoverEntry\">\n <div class=\"hi-outline\" [ngStyle]=\"hiOutlineStyle\"></div>\n <div class=\"hi-margin\" [ngStyle]=\"hiMarginStyle\"></div>\n <div class=\"hi-padding\" [ngStyle]=\"hiPaddingStyle\"></div>\n </ng-container>\n\n <!-- SELECT \u2014 IOX pink outline + toolbar -->\n <div class=\"select-outline\" *ngIf=\"selectEntry\" [ngStyle]=\"selectOutlineStyle\"\n (contextmenu)=\"onContextMenu($event)\">\n\n <div class=\"select-toolbar\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n\n <!-- Component name -->\n <span class=\"toolbar-name\">{{ selectEntry?.componentName }}</span>\n <span class=\"toolbar-sep\"></span>\n\n <!-- Quick actions -->\n <button class=\"toolbar-btn\" title=\"Duplicate\" (mousedown)=\"onDuplicate($event)\">\n <i class=\"ph-thin ph-copy\"></i>\n </button>\n <button *ngIf=\"hasInteractions\" class=\"toolbar-btn toolbar-btn--play\" title=\"Play animations\" (mousedown)=\"onPlay($event)\">\n <i class=\"ph-thin ph-play\"></i>\n </button>\n <button class=\"toolbar-btn toolbar-btn--danger\" title=\"Delete\" (mousedown)=\"onDelete($event)\">\n <i class=\"ph-thin ph-trash\"></i>\n </button>\n <span class=\"toolbar-sep\"></span>\n <button class=\"toolbar-btn\" title=\"Select parent\" (mousedown)=\"onSelectParent($event)\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n </button>\n\n <!-- More menu trigger \u2014 last -->\n <button class=\"toolbar-btn toolbar-btn--more\" title=\"More actions\" (mousedown)=\"onToggleMore($event)\">\n <i class=\"ph-thin ph-dots-three\"></i>\n </button>\n\n <!-- More dropdown (inline, positioned from toolbar) -->\n <div *ngIf=\"moreMenuVisible\" class=\"toolbar-more-dropdown\" (click)=\"$event.stopPropagation()\">\n <button class=\"more-item\" (mousedown)=\"onSelectParent($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n Select parent\n </button>\n <button class=\"more-item\" (mousedown)=\"onDuplicate($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-copy\"></i>\n Duplicate\n </button>\n <button class=\"more-item more-item--danger\" (mousedown)=\"onDelete($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-trash\"></i>\n Delete\n </button>\n <div class=\"more-divider\"></div>\n <button class=\"more-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n <button *ngIf=\"hasInteractions\" class=\"more-item more-item--play\" (mousedown)=\"onPlay($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-play\"></i>\n Play animations\n </button>\n <div class=\"more-divider\"></div>\n <ng-container *ngIf=\"!selectedNodeIsGlobal; else removeGlobalItem\">\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'before')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (Before Content)\n </button>\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'after')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (After Content)\n </button>\n </ng-container>\n <ng-template #removeGlobalItem>\n <button class=\"more-item\" (mousedown)=\"onRemoveGlobal($event)\">\n <i class=\"ph-thin ph-globe\"></i>\n Remove from Global\n </button>\n </ng-template>\n </div>\n </div>\n </div>\n\n <!-- Backdrop to close more menu or context menu -->\n <div *ngIf=\"moreMenuVisible || contextMenuVisible\" class=\"overlay-context-backdrop\"\n (mousedown)=\"closeMoreMenu(); closeContextMenu()\">\n </div>\n\n <!-- Right-click context menu -->\n <div *ngIf=\"contextMenuVisible\" class=\"overlay-context-menu\"\n [ngStyle]=\"contextMenuStyle\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"context-menu-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n </div>\n\n</div>\n", styles: [":host{display:block;position:absolute;inset:0;pointer-events:none;z-index:12;overflow:visible}.hi-outline,.hi-margin,.hi-padding{position:fixed;pointer-events:none;transition:none;box-sizing:border-box}.hi-outline{box-shadow:inset 0 0 0 1.5px #cb9090}.hi-margin{background:#f6b23361}.hi-padding{background:#60c38366}.select-outline{position:fixed;z-index:999;box-shadow:inset 0 0 0 1px #cb9090;pointer-events:none;transition:none;overflow:visible;will-change:transform;box-sizing:border-box}.select-toolbar{position:absolute;top:0;left:0;transform:translateY(-100%);display:flex;align-items:center;background:#cb9090;border-radius:3px 3px 0 0;pointer-events:all;white-space:nowrap;overflow:visible}.select-toolbar .toolbar-name{padding:0 8px;font-size:11px;font-weight:500;color:#fff;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:22px}.select-toolbar .toolbar-sep{width:1px;height:14px;background:#ffffff59;margin:0 2px;flex-shrink:0}.select-toolbar .toolbar-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;padding:0;border:none;background:transparent;color:#fff;font-size:13px;cursor:pointer;transition:background .15s;flex-shrink:0}.select-toolbar .toolbar-btn:hover{background:#ffffff2e}.select-toolbar .toolbar-btn--danger:hover{background:#c8323259}.select-toolbar .toolbar-btn--more{border-radius:0 3px 0 0}.select-toolbar .toolbar-more-dropdown{position:absolute;top:100%;right:0;left:auto;z-index:1000;background:#fff;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all;margin-top:2px}.select-toolbar .toolbar-more-dropdown .more-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left;white-space:nowrap}.select-toolbar .toolbar-more-dropdown .more-item i{font-size:14px}.select-toolbar .toolbar-more-dropdown .more-item:hover{background:var(--p-surface-100, #f5f5f5)}.select-toolbar .toolbar-more-dropdown .more-item--danger{color:#c84040}.select-toolbar .toolbar-more-dropdown .more-item--danger:hover{background:#c8404014}.select-toolbar .toolbar-more-dropdown .more-item--play{color:var(--p-text-color, #333)}.select-toolbar .toolbar-more-dropdown .more-divider{height:1px;background:var(--p-surface-200, #e5e7eb);margin:4px 0}.overlay-context-backdrop{position:fixed;inset:0;z-index:998;pointer-events:all}.overlay-context-menu{position:fixed;z-index:999;background:#fff;border:1px solid var(--p-surface-200);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all}.overlay-context-menu .context-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left}.overlay-context-menu .context-menu-item i{font-size:14px}.overlay-context-menu .context-menu-item:hover{background:var(--p-surface-100, #f5f5f5)}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1881
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OverlayComponent, deps: [{ token: OverlayService }, { token: ViewportService }, { token: PresetRegistryService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1882
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: OverlayComponent, isStandalone: false, selector: "app-overlay", outputs: { toolbarAction: "toolbarAction" }, ngImport: i0, template: "<div class=\"overlay-root\">\n\n <!-- HOVER \u2014 Chrome DevTools-style rings (content area stays transparent) -->\n <ng-container *ngIf=\"hoverEntry\">\n <div class=\"hi-outline\" [ngStyle]=\"hiOutlineStyle\"></div>\n <div class=\"hi-margin\" [ngStyle]=\"hiMarginStyle\"></div>\n <div class=\"hi-padding\" [ngStyle]=\"hiPaddingStyle\"></div>\n </ng-container>\n\n <!-- SELECT \u2014 IOX pink outline + toolbar -->\n <div class=\"select-outline\" *ngIf=\"selectEntry\" [ngStyle]=\"selectOutlineStyle\"\n (contextmenu)=\"onContextMenu($event)\">\n\n <!-- Preset badge \u2014 centered below the outline, shown when a preset is applied -->\n <div *ngIf=\"selectedPresetName\" class=\"preset-badge\" (mousedown)=\"onEditPreset($event)\">\n <i class=\"ph-fill ph-paint-bucket\"></i>\n <span>{{ selectedPresetName }}</span>\n </div>\n\n <div class=\"select-toolbar\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n\n <!-- Component name -->\n <span class=\"toolbar-name\">{{ selectEntry?.componentName }}</span>\n <span class=\"toolbar-sep\"></span>\n\n <!-- Quick actions -->\n <button class=\"toolbar-btn\" title=\"Duplicate\" (mousedown)=\"onDuplicate($event)\">\n <i class=\"ph-thin ph-copy\"></i>\n </button>\n <button *ngIf=\"hasInteractions\" class=\"toolbar-btn toolbar-btn--play\" title=\"Play animations\" (mousedown)=\"onPlay($event)\">\n <i class=\"ph-thin ph-play\"></i>\n </button>\n <button class=\"toolbar-btn toolbar-btn--danger\" title=\"Delete\" (mousedown)=\"onDelete($event)\">\n <i class=\"ph-thin ph-trash\"></i>\n </button>\n <span class=\"toolbar-sep\"></span>\n <button class=\"toolbar-btn\" title=\"Select parent\" (mousedown)=\"onSelectParent($event)\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n </button>\n\n <!-- More menu trigger \u2014 last -->\n <button class=\"toolbar-btn toolbar-btn--more\" title=\"More actions\" (mousedown)=\"onToggleMore($event)\">\n <i class=\"ph-thin ph-dots-three\"></i>\n </button>\n\n <!-- More dropdown (inline, positioned from toolbar) -->\n <div *ngIf=\"moreMenuVisible\" class=\"toolbar-more-dropdown\" (click)=\"$event.stopPropagation()\">\n <button class=\"more-item\" (mousedown)=\"onSelectParent($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n Select parent\n </button>\n <button class=\"more-item\" (mousedown)=\"onDuplicate($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-copy\"></i>\n Duplicate\n </button>\n <button class=\"more-item more-item--danger\" (mousedown)=\"onDelete($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-trash\"></i>\n Delete\n </button>\n <div class=\"more-divider\"></div>\n <button class=\"more-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n <button *ngIf=\"hasInteractions\" class=\"more-item more-item--play\" (mousedown)=\"onPlay($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-play\"></i>\n Play animations\n </button>\n <div class=\"more-divider\"></div>\n <ng-container *ngIf=\"!selectedNodeIsGlobal; else removeGlobalItem\">\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'before')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (Before Content)\n </button>\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'after')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (After Content)\n </button>\n </ng-container>\n <ng-template #removeGlobalItem>\n <button class=\"more-item\" (mousedown)=\"onRemoveGlobal($event)\">\n <i class=\"ph-thin ph-globe\"></i>\n Remove from Global\n </button>\n </ng-template>\n </div>\n </div>\n </div>\n\n <!-- Backdrop to close more menu or context menu -->\n <div *ngIf=\"moreMenuVisible || contextMenuVisible\" class=\"overlay-context-backdrop\"\n (mousedown)=\"closeMoreMenu(); closeContextMenu()\">\n </div>\n\n <!-- Right-click context menu -->\n <div *ngIf=\"contextMenuVisible\" class=\"overlay-context-menu\"\n [ngStyle]=\"contextMenuStyle\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"context-menu-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n </div>\n\n</div>\n", styles: [":host{display:block;position:absolute;inset:0;pointer-events:none;z-index:12;overflow:visible}.hi-outline,.hi-margin,.hi-padding{position:fixed;pointer-events:none;transition:none;box-sizing:border-box}.hi-outline{box-shadow:inset 0 0 0 1.5px #cb9090}.hi-margin{background:#f6b23361}.hi-padding{background:#60c38366}.select-outline{position:fixed;z-index:999;box-shadow:inset 0 0 0 1px #cb9090;pointer-events:none;transition:none;overflow:visible;will-change:transform;box-sizing:border-box}.select-toolbar{position:absolute;top:0;left:0;transform:translateY(-100%);display:flex;align-items:center;background:#cb9090;border-radius:3px 3px 0 0;pointer-events:all;white-space:nowrap;overflow:visible}.select-toolbar .toolbar-name{padding:0 8px;font-size:11px;font-weight:500;color:#fff;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:22px}.select-toolbar .toolbar-sep{width:1px;height:14px;background:#ffffff59;margin:0 2px;flex-shrink:0}.select-toolbar .toolbar-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;padding:0;border:none;background:transparent;color:#fff;font-size:13px;cursor:pointer;transition:background .15s;flex-shrink:0}.select-toolbar .toolbar-btn:hover{background:#ffffff2e}.select-toolbar .toolbar-btn--danger:hover{background:#c8323259}.select-toolbar .toolbar-btn--more{border-radius:0 3px 0 0}.select-toolbar .toolbar-more-dropdown{position:absolute;top:100%;right:0;left:auto;z-index:1000;background:#fff;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all;margin-top:2px}.select-toolbar .toolbar-more-dropdown .more-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left;white-space:nowrap}.select-toolbar .toolbar-more-dropdown .more-item i{font-size:14px}.select-toolbar .toolbar-more-dropdown .more-item:hover{background:var(--p-surface-100, #f5f5f5)}.select-toolbar .toolbar-more-dropdown .more-item--danger{color:#c84040}.select-toolbar .toolbar-more-dropdown .more-item--danger:hover{background:#c8404014}.select-toolbar .toolbar-more-dropdown .more-item--play{color:var(--p-text-color, #333)}.select-toolbar .toolbar-more-dropdown .more-divider{height:1px;background:var(--p-surface-200, #e5e7eb);margin:4px 0}.preset-badge{position:absolute;bottom:-26px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:5px;padding:3px 9px;background:#cb9090;color:#fff;font-size:11px;font-weight:500;border-radius:20px;white-space:nowrap;pointer-events:all;cursor:pointer;box-shadow:0 2px 6px #0000002e;transition:background .15s}.preset-badge i{font-size:12px}.preset-badge:hover{background:#be7474}.overlay-context-backdrop{position:fixed;inset:0;z-index:998;pointer-events:all}.overlay-context-menu{position:fixed;z-index:999;background:#fff;border:1px solid var(--p-surface-200);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all}.overlay-context-menu .context-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left}.overlay-context-menu .context-menu-item i{font-size:14px}.overlay-context-menu .context-menu-item:hover{background:var(--p-surface-100, #f5f5f5)}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1784
1883
  }
1785
1884
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OverlayComponent, decorators: [{
1786
1885
  type: Component,
1787
- args: [{ selector: 'app-overlay', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"overlay-root\">\n\n <!-- HOVER \u2014 Chrome DevTools-style rings (content area stays transparent) -->\n <ng-container *ngIf=\"hoverEntry\">\n <div class=\"hi-outline\" [ngStyle]=\"hiOutlineStyle\"></div>\n <div class=\"hi-margin\" [ngStyle]=\"hiMarginStyle\"></div>\n <div class=\"hi-padding\" [ngStyle]=\"hiPaddingStyle\"></div>\n </ng-container>\n\n <!-- SELECT \u2014 IOX pink outline + toolbar -->\n <div class=\"select-outline\" *ngIf=\"selectEntry\" [ngStyle]=\"selectOutlineStyle\"\n (contextmenu)=\"onContextMenu($event)\">\n\n <div class=\"select-toolbar\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n\n <!-- Component name -->\n <span class=\"toolbar-name\">{{ selectEntry?.componentName }}</span>\n <span class=\"toolbar-sep\"></span>\n\n <!-- Quick actions -->\n <button class=\"toolbar-btn\" title=\"Duplicate\" (mousedown)=\"onDuplicate($event)\">\n <i class=\"ph-thin ph-copy\"></i>\n </button>\n <button *ngIf=\"hasInteractions\" class=\"toolbar-btn toolbar-btn--play\" title=\"Play animations\" (mousedown)=\"onPlay($event)\">\n <i class=\"ph-thin ph-play\"></i>\n </button>\n <button class=\"toolbar-btn toolbar-btn--danger\" title=\"Delete\" (mousedown)=\"onDelete($event)\">\n <i class=\"ph-thin ph-trash\"></i>\n </button>\n <span class=\"toolbar-sep\"></span>\n <button class=\"toolbar-btn\" title=\"Select parent\" (mousedown)=\"onSelectParent($event)\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n </button>\n\n <!-- More menu trigger \u2014 last -->\n <button class=\"toolbar-btn toolbar-btn--more\" title=\"More actions\" (mousedown)=\"onToggleMore($event)\">\n <i class=\"ph-thin ph-dots-three\"></i>\n </button>\n\n <!-- More dropdown (inline, positioned from toolbar) -->\n <div *ngIf=\"moreMenuVisible\" class=\"toolbar-more-dropdown\" (click)=\"$event.stopPropagation()\">\n <button class=\"more-item\" (mousedown)=\"onSelectParent($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n Select parent\n </button>\n <button class=\"more-item\" (mousedown)=\"onDuplicate($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-copy\"></i>\n Duplicate\n </button>\n <button class=\"more-item more-item--danger\" (mousedown)=\"onDelete($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-trash\"></i>\n Delete\n </button>\n <div class=\"more-divider\"></div>\n <button class=\"more-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n <button *ngIf=\"hasInteractions\" class=\"more-item more-item--play\" (mousedown)=\"onPlay($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-play\"></i>\n Play animations\n </button>\n <div class=\"more-divider\"></div>\n <ng-container *ngIf=\"!selectedNodeIsGlobal; else removeGlobalItem\">\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'before')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (Before Content)\n </button>\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'after')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (After Content)\n </button>\n </ng-container>\n <ng-template #removeGlobalItem>\n <button class=\"more-item\" (mousedown)=\"onRemoveGlobal($event)\">\n <i class=\"ph-thin ph-globe\"></i>\n Remove from Global\n </button>\n </ng-template>\n </div>\n </div>\n </div>\n\n <!-- Backdrop to close more menu or context menu -->\n <div *ngIf=\"moreMenuVisible || contextMenuVisible\" class=\"overlay-context-backdrop\"\n (mousedown)=\"closeMoreMenu(); closeContextMenu()\">\n </div>\n\n <!-- Right-click context menu -->\n <div *ngIf=\"contextMenuVisible\" class=\"overlay-context-menu\"\n [ngStyle]=\"contextMenuStyle\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"context-menu-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n </div>\n\n</div>\n", styles: [":host{display:block;position:absolute;inset:0;pointer-events:none;z-index:12;overflow:visible}.hi-outline,.hi-margin,.hi-padding{position:fixed;pointer-events:none;transition:none;box-sizing:border-box}.hi-outline{box-shadow:inset 0 0 0 1.5px #cb9090}.hi-margin{background:#f6b23361}.hi-padding{background:#60c38366}.select-outline{position:fixed;z-index:999;box-shadow:inset 0 0 0 1px #cb9090;pointer-events:none;transition:none;overflow:visible;will-change:transform;box-sizing:border-box}.select-toolbar{position:absolute;top:0;left:0;transform:translateY(-100%);display:flex;align-items:center;background:#cb9090;border-radius:3px 3px 0 0;pointer-events:all;white-space:nowrap;overflow:visible}.select-toolbar .toolbar-name{padding:0 8px;font-size:11px;font-weight:500;color:#fff;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:22px}.select-toolbar .toolbar-sep{width:1px;height:14px;background:#ffffff59;margin:0 2px;flex-shrink:0}.select-toolbar .toolbar-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;padding:0;border:none;background:transparent;color:#fff;font-size:13px;cursor:pointer;transition:background .15s;flex-shrink:0}.select-toolbar .toolbar-btn:hover{background:#ffffff2e}.select-toolbar .toolbar-btn--danger:hover{background:#c8323259}.select-toolbar .toolbar-btn--more{border-radius:0 3px 0 0}.select-toolbar .toolbar-more-dropdown{position:absolute;top:100%;right:0;left:auto;z-index:1000;background:#fff;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all;margin-top:2px}.select-toolbar .toolbar-more-dropdown .more-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left;white-space:nowrap}.select-toolbar .toolbar-more-dropdown .more-item i{font-size:14px}.select-toolbar .toolbar-more-dropdown .more-item:hover{background:var(--p-surface-100, #f5f5f5)}.select-toolbar .toolbar-more-dropdown .more-item--danger{color:#c84040}.select-toolbar .toolbar-more-dropdown .more-item--danger:hover{background:#c8404014}.select-toolbar .toolbar-more-dropdown .more-item--play{color:var(--p-text-color, #333)}.select-toolbar .toolbar-more-dropdown .more-divider{height:1px;background:var(--p-surface-200, #e5e7eb);margin:4px 0}.overlay-context-backdrop{position:fixed;inset:0;z-index:998;pointer-events:all}.overlay-context-menu{position:fixed;z-index:999;background:#fff;border:1px solid var(--p-surface-200);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all}.overlay-context-menu .context-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left}.overlay-context-menu .context-menu-item i{font-size:14px}.overlay-context-menu .context-menu-item:hover{background:var(--p-surface-100, #f5f5f5)}\n"] }]
1788
- }], ctorParameters: () => [{ type: OverlayService }, { type: ViewportService }, { type: i0.ChangeDetectorRef }], propDecorators: { toolbarAction: [{
1886
+ args: [{ selector: 'app-overlay', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"overlay-root\">\n\n <!-- HOVER \u2014 Chrome DevTools-style rings (content area stays transparent) -->\n <ng-container *ngIf=\"hoverEntry\">\n <div class=\"hi-outline\" [ngStyle]=\"hiOutlineStyle\"></div>\n <div class=\"hi-margin\" [ngStyle]=\"hiMarginStyle\"></div>\n <div class=\"hi-padding\" [ngStyle]=\"hiPaddingStyle\"></div>\n </ng-container>\n\n <!-- SELECT \u2014 IOX pink outline + toolbar -->\n <div class=\"select-outline\" *ngIf=\"selectEntry\" [ngStyle]=\"selectOutlineStyle\"\n (contextmenu)=\"onContextMenu($event)\">\n\n <!-- Preset badge \u2014 centered below the outline, shown when a preset is applied -->\n <div *ngIf=\"selectedPresetName\" class=\"preset-badge\" (mousedown)=\"onEditPreset($event)\">\n <i class=\"ph-fill ph-paint-bucket\"></i>\n <span>{{ selectedPresetName }}</span>\n </div>\n\n <div class=\"select-toolbar\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n\n <!-- Component name -->\n <span class=\"toolbar-name\">{{ selectEntry?.componentName }}</span>\n <span class=\"toolbar-sep\"></span>\n\n <!-- Quick actions -->\n <button class=\"toolbar-btn\" title=\"Duplicate\" (mousedown)=\"onDuplicate($event)\">\n <i class=\"ph-thin ph-copy\"></i>\n </button>\n <button *ngIf=\"hasInteractions\" class=\"toolbar-btn toolbar-btn--play\" title=\"Play animations\" (mousedown)=\"onPlay($event)\">\n <i class=\"ph-thin ph-play\"></i>\n </button>\n <button class=\"toolbar-btn toolbar-btn--danger\" title=\"Delete\" (mousedown)=\"onDelete($event)\">\n <i class=\"ph-thin ph-trash\"></i>\n </button>\n <span class=\"toolbar-sep\"></span>\n <button class=\"toolbar-btn\" title=\"Select parent\" (mousedown)=\"onSelectParent($event)\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n </button>\n\n <!-- More menu trigger \u2014 last -->\n <button class=\"toolbar-btn toolbar-btn--more\" title=\"More actions\" (mousedown)=\"onToggleMore($event)\">\n <i class=\"ph-thin ph-dots-three\"></i>\n </button>\n\n <!-- More dropdown (inline, positioned from toolbar) -->\n <div *ngIf=\"moreMenuVisible\" class=\"toolbar-more-dropdown\" (click)=\"$event.stopPropagation()\">\n <button class=\"more-item\" (mousedown)=\"onSelectParent($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-arrow-up\"></i>\n Select parent\n </button>\n <button class=\"more-item\" (mousedown)=\"onDuplicate($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-copy\"></i>\n Duplicate\n </button>\n <button class=\"more-item more-item--danger\" (mousedown)=\"onDelete($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-trash\"></i>\n Delete\n </button>\n <div class=\"more-divider\"></div>\n <button class=\"more-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n <button *ngIf=\"hasInteractions\" class=\"more-item more-item--play\" (mousedown)=\"onPlay($event); closeMoreMenu()\">\n <i class=\"ph-thin ph-play\"></i>\n Play animations\n </button>\n <div class=\"more-divider\"></div>\n <ng-container *ngIf=\"!selectedNodeIsGlobal; else removeGlobalItem\">\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'before')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (Before Content)\n </button>\n <button class=\"more-item\" (mousedown)=\"onMakeGlobal($event, 'after')\">\n <i class=\"ph-thin ph-globe\"></i>\n Make Global (After Content)\n </button>\n </ng-container>\n <ng-template #removeGlobalItem>\n <button class=\"more-item\" (mousedown)=\"onRemoveGlobal($event)\">\n <i class=\"ph-thin ph-globe\"></i>\n Remove from Global\n </button>\n </ng-template>\n </div>\n </div>\n </div>\n\n <!-- Backdrop to close more menu or context menu -->\n <div *ngIf=\"moreMenuVisible || contextMenuVisible\" class=\"overlay-context-backdrop\"\n (mousedown)=\"closeMoreMenu(); closeContextMenu()\">\n </div>\n\n <!-- Right-click context menu -->\n <div *ngIf=\"contextMenuVisible\" class=\"overlay-context-menu\"\n [ngStyle]=\"contextMenuStyle\"\n (click)=\"$event.stopPropagation()\">\n <button class=\"context-menu-item\" (mousedown)=\"onContextSaveAsBlock($event)\">\n <i class=\"ph-thin ph-bookmark\"></i>\n Save as reusable block\n </button>\n </div>\n\n</div>\n", styles: [":host{display:block;position:absolute;inset:0;pointer-events:none;z-index:12;overflow:visible}.hi-outline,.hi-margin,.hi-padding{position:fixed;pointer-events:none;transition:none;box-sizing:border-box}.hi-outline{box-shadow:inset 0 0 0 1.5px #cb9090}.hi-margin{background:#f6b23361}.hi-padding{background:#60c38366}.select-outline{position:fixed;z-index:999;box-shadow:inset 0 0 0 1px #cb9090;pointer-events:none;transition:none;overflow:visible;will-change:transform;box-sizing:border-box}.select-toolbar{position:absolute;top:0;left:0;transform:translateY(-100%);display:flex;align-items:center;background:#cb9090;border-radius:3px 3px 0 0;pointer-events:all;white-space:nowrap;overflow:visible}.select-toolbar .toolbar-name{padding:0 8px;font-size:11px;font-weight:500;color:#fff;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:22px}.select-toolbar .toolbar-sep{width:1px;height:14px;background:#ffffff59;margin:0 2px;flex-shrink:0}.select-toolbar .toolbar-btn{display:flex;align-items:center;justify-content:center;width:24px;height:22px;padding:0;border:none;background:transparent;color:#fff;font-size:13px;cursor:pointer;transition:background .15s;flex-shrink:0}.select-toolbar .toolbar-btn:hover{background:#ffffff2e}.select-toolbar .toolbar-btn--danger:hover{background:#c8323259}.select-toolbar .toolbar-btn--more{border-radius:0 3px 0 0}.select-toolbar .toolbar-more-dropdown{position:absolute;top:100%;right:0;left:auto;z-index:1000;background:#fff;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all;margin-top:2px}.select-toolbar .toolbar-more-dropdown .more-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left;white-space:nowrap}.select-toolbar .toolbar-more-dropdown .more-item i{font-size:14px}.select-toolbar .toolbar-more-dropdown .more-item:hover{background:var(--p-surface-100, #f5f5f5)}.select-toolbar .toolbar-more-dropdown .more-item--danger{color:#c84040}.select-toolbar .toolbar-more-dropdown .more-item--danger:hover{background:#c8404014}.select-toolbar .toolbar-more-dropdown .more-item--play{color:var(--p-text-color, #333)}.select-toolbar .toolbar-more-dropdown .more-divider{height:1px;background:var(--p-surface-200, #e5e7eb);margin:4px 0}.preset-badge{position:absolute;bottom:-26px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:5px;padding:3px 9px;background:#cb9090;color:#fff;font-size:11px;font-weight:500;border-radius:20px;white-space:nowrap;pointer-events:all;cursor:pointer;box-shadow:0 2px 6px #0000002e;transition:background .15s}.preset-badge i{font-size:12px}.preset-badge:hover{background:#be7474}.overlay-context-backdrop{position:fixed;inset:0;z-index:998;pointer-events:all}.overlay-context-menu{position:fixed;z-index:999;background:#fff;border:1px solid var(--p-surface-200);border-radius:6px;box-shadow:0 4px 16px #0000001f;padding:4px 0;min-width:200px;pointer-events:all}.overlay-context-menu .context-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;border:none;background:transparent;font-size:13px;color:var(--p-text-color, #333);cursor:pointer;text-align:left}.overlay-context-menu .context-menu-item i{font-size:14px}.overlay-context-menu .context-menu-item:hover{background:var(--p-surface-100, #f5f5f5)}\n"] }]
1887
+ }], ctorParameters: () => [{ type: OverlayService }, { type: ViewportService }, { type: PresetRegistryService }, { type: i0.ChangeDetectorRef }], propDecorators: { toolbarAction: [{
1789
1888
  type: Output
1790
1889
  }] } });
1791
1890
 
@@ -2617,6 +2716,11 @@ class BuilderComponent {
2617
2716
  }
2618
2717
  break;
2619
2718
  }
2719
+ case ToolbarAction.EditPreset: {
2720
+ this.panelEventService.emit(PanelEventTypes.PRESET_EDIT, node.stylePresetId);
2721
+ this.panelEventService.emit(this.isPanelOpen ? PanelEventTypes.PANEL_SELECTED : PanelEventTypes.PANEL_OPEN, PanelTypes.STYLES);
2722
+ break;
2723
+ }
2620
2724
  }
2621
2725
  }
2622
2726
  confirmSaveBlock() {
@@ -3560,6 +3664,30 @@ const ACTION_TYPE_OPTIONS = [
3560
3664
  { value: 'toggleVisibility', label: 'Toggle visibility' },
3561
3665
  ];
3562
3666
  const EASING_OPTIONS = ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out'];
3667
+ /**
3668
+ * Build a full StyleTraitGroup[] schema populated with values from a flat
3669
+ * styleProps map. Used when editing a preset in the Style panel — the panel
3670
+ * receives the same `StyleTraitGroup[]` shape regardless of context.
3671
+ */
3672
+ function buildPresetStyleTraits(styleProps) {
3673
+ const allGroups = [
3674
+ new LayoutGroupStyleConfig(),
3675
+ new SizeGroupStyleConfig(),
3676
+ new BackgroundGroupStyleConfig(),
3677
+ new SpacingGroupStyleConfig(),
3678
+ new BorderGroupStyleConfig(),
3679
+ new TypographyGroupStyleConfig(),
3680
+ new EffectsGroupStyleConfig(),
3681
+ new PositionGroupStyleConfig(),
3682
+ ];
3683
+ return allGroups.map(group => ({
3684
+ ...group,
3685
+ traits: group.traits.map(trait => ({
3686
+ ...trait,
3687
+ default: styleProps[trait.name] !== undefined ? styleProps[trait.name] : trait.default,
3688
+ })),
3689
+ }));
3690
+ }
3563
3691
  var TraitInputType;
3564
3692
  (function (TraitInputType) {
3565
3693
  TraitInputType["Text"] = "text";
@@ -4034,6 +4162,7 @@ class IoxBuilderModule {
4034
4162
  ViewportService,
4035
4163
  StyleRegistryService,
4036
4164
  PanelEventService,
4165
+ PresetRegistryService,
4037
4166
  ], imports: [CommonModule,
4038
4167
  FormsModule,
4039
4168
  DragDropModule,
@@ -4084,6 +4213,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
4084
4213
  ViewportService,
4085
4214
  StyleRegistryService,
4086
4215
  PanelEventService,
4216
+ PresetRegistryService,
4087
4217
  ],
4088
4218
  exports: [
4089
4219
  // Angular/PrimeNG modules re-exported so consumers can use them
@@ -4477,5 +4607,5 @@ class TextBlockComponentConfig extends ComponentConfig {
4477
4607
  * Generated bundle index. Do not edit.
4478
4608
  */
4479
4609
 
4480
- export { ACTION_TYPE_OPTIONS, BuilderButtonComponentConfig, BuilderComponent, BuilderContainerComponent, BuilderContainerComponentConfig, BuilderDividerComponentConfig, BuilderHeadingComponentConfig, BuilderIconComponentConfig, BuilderImageComponentConfig, BuilderLinkComponentConfig, BuilderLinkedContainerComponent, BuilderLinkedContainerConfig, BuilderMode, BuilderRepeaterComponent, BuilderSpacerComponentConfig, CardComponentConfig, ComponentConfig, ComponentRegistryService, DEVICE_OPTIONS, DataSourceRegistryService, DeviceMode, DragEngineService, EASING_OPTIONS$1 as EASING_OPTIONS, GroupStyleConfig, IOX_CONTENT_SERVICE, IOX_FONT_MANAGER, InteractionEngineService, InteractionsPanelComponent, IoxBuilderModule, IoxDraggableDirective, IoxDropzoneDirective, LayerTreeComponent, NodeAction, OverlayComponent, OverlayService, PanelChildComponent, PanelComponent, PanelEventService, PanelEventTypes, PanelTypes, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, SCREEN_WIDTH_OPTIONS, SectionComponent, SectionComponentConfig, StyleCategory, StyleRegistryService, TraitConfig as StyleTraitConfig, TRIGGER_OPTIONS, TextBlockComponentConfig, ToolbarAction, ToolbarComponent, TraitConfig, TraitInputType, UNITS_ALL, UNITS_DEG, UNITS_FIXED, UNITS_NO_VW, ViewportService, ZOOM_OPTIONS, defaultPageSettings, generateNodeId, resolveTraitControllerType, resolveTraitOptions };
4610
+ export { ACTION_TYPE_OPTIONS, BuilderButtonComponentConfig, BuilderComponent, BuilderContainerComponent, BuilderContainerComponentConfig, BuilderDividerComponentConfig, BuilderHeadingComponentConfig, BuilderIconComponentConfig, BuilderImageComponentConfig, BuilderLinkComponentConfig, BuilderLinkedContainerComponent, BuilderLinkedContainerConfig, BuilderMode, BuilderRepeaterComponent, BuilderSpacerComponentConfig, CardComponentConfig, ComponentConfig, ComponentRegistryService, DEVICE_OPTIONS, DataSourceRegistryService, DeviceMode, DragEngineService, EASING_OPTIONS$1 as EASING_OPTIONS, GroupStyleConfig, IOX_CONTENT_SERVICE, IOX_FONT_MANAGER, InteractionEngineService, InteractionsPanelComponent, IoxBuilderModule, IoxDraggableDirective, IoxDropzoneDirective, LayerTreeComponent, NodeAction, OverlayComponent, OverlayService, PanelChildComponent, PanelComponent, PanelEventService, PanelEventTypes, PanelTypes, PresetRegistryService, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, SCREEN_WIDTH_OPTIONS, SectionComponent, SectionComponentConfig, StyleCategory, StyleRegistryService, TraitConfig as StyleTraitConfig, TRIGGER_OPTIONS, TextBlockComponentConfig, ToolbarAction, ToolbarComponent, TraitConfig, TraitInputType, UNITS_ALL, UNITS_DEG, UNITS_FIXED, UNITS_NO_VW, ViewportService, ZOOM_OPTIONS, buildPresetStyleTraits, defaultPageSettings, generateNodeId, resolveTraitControllerType, resolveTraitOptions };
4481
4611
  //# sourceMappingURL=vectoriox-iox-builder.mjs.map