@vectoriox/iox-builder 7.0.1 → 8.0.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.
@@ -16,7 +16,7 @@ import { SelectModule } from 'primeng/select';
16
16
  import { TooltipModule } from 'primeng/tooltip';
17
17
  import { DialogModule } from 'primeng/dialog';
18
18
  import * as i1 from '@vectoriox/iox-ui';
19
- import { VALIDATION_STATES as VALIDATION_STATES$1, VALIDATION_STATE_CLASS as VALIDATION_STATE_CLASS$1, DEFAULT_WIDTH_BY_TYPE, COLOR_SCHEME_TRAIT, COLOR_SCHEMES, ColorScheme, Breakpoint, BREAKPOINTS, countOverrides, setOverride, defaultElementStyleFor, applyElementStyle, stripSuppressedProps, DeclarationContext, buildPartSelector, planResponsiveRules, resolveStyleProps, buildTargetedStateSelector, statePseudoClass, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, wrapInBreakpointQuery, BreakpointQueryKind, breakpointDef, breakpointForWidth, FormRenderState, safeSetInput, ContextStore, ComponentInstanceRegistryService, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, declaredInputNames, emptyImagePlaceholder, syncNodeDesignClasses, composeVirtualTraits, withDefaultHoverTransition, stateNamesIn, partClassName, resolveInputs, setInputOverride, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, resolveBoundValue, IS_PREVIEW, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, IoxPageModule, PALETTE_PRESETS, elementStyleById, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
19
+ import { VALIDATION_STATES as VALIDATION_STATES$1, VALIDATION_STATE_CLASS as VALIDATION_STATE_CLASS$1, DEFAULT_WIDTH_BY_TYPE, COLOR_SCHEME_TRAIT, COLOR_SCHEMES, ColorScheme, Breakpoint, BREAKPOINTS, countOverrides, setOverride, NEW_NODE_STYLE_DEFAULTS, defaultElementStyleFor, applyElementStyle, stripSuppressedProps, DeclarationContext, buildPartSelector, planResponsiveRules, resolveStyleProps, buildTargetedStateSelector, statePseudoClass, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, wrapInBreakpointQuery, BreakpointQueryKind, breakpointDef, breakpointForWidth, FormRenderState, safeSetInput, ContextStore, ComponentInstanceRegistryService, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, declaredInputNames, emptyImagePlaceholder, syncNodeDesignClasses, composeVirtualTraits, withDefaultHoverTransition, stateNamesIn, partClassName, resolveInputs, setInputOverride, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, resolveBoundValue, IS_PREVIEW, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, IoxPageModule, PALETTE_PRESETS, elementStyleById, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
20
20
  export { ComponentInstanceRegistryService, VIRTUAL_TRAIT_KEYS, composeVirtualTraits } from '@vectoriox/iox-ui';
21
21
  import Lenis from 'lenis';
22
22
  import { Subject, BehaviorSubject, of, forkJoin } from 'rxjs';
@@ -1664,16 +1664,33 @@ class ComponentRegistryService {
1664
1664
  }
1665
1665
  /** The unstyled base style map of a NEW node of the type — `switchElementStyle`'s baseline. */
1666
1666
  baselineStyleProps(type) {
1667
+ const out = this.adoptionBaseline(type);
1668
+ for (const [name, value] of Object.entries(NEW_NODE_STYLE_DEFAULTS))
1669
+ if (name in out)
1670
+ out[name] = value;
1671
+ return out;
1672
+ }
1673
+ /** What an untouched SAVED node of the type holds — its constructor defaults, nothing on top.
1674
+ * Adopt (DS7) rewrites an owned trait only while it still holds this. */
1675
+ adoptionBaseline(type) {
1667
1676
  const out = {};
1668
1677
  for (const group of this.createBaseConfig(type)?.styleTraits ?? []) {
1669
1678
  for (const trait of group.traits ?? [])
1670
1679
  out[trait.name] = trait.default;
1671
1680
  }
1672
- for (const [name, value] of Object.entries(NEW_NODE_STYLE_DEFAULTS))
1673
- if (name in out)
1674
- out[name] = value;
1675
1681
  return out;
1676
1682
  }
1683
+ /** The context `adoptElementStyles` (design-core) reads baselines from. */
1684
+ adoptionContext() {
1685
+ const cache = new Map();
1686
+ return {
1687
+ baseline: type => {
1688
+ if (!cache.has(type))
1689
+ cache.set(type, this.adoptionBaseline(type));
1690
+ return cache.get(type);
1691
+ },
1692
+ };
1693
+ }
1677
1694
  register(type, component, config) {
1678
1695
  this.components[type] = { type, component, config };
1679
1696
  }
@@ -1686,13 +1703,6 @@ class ComponentRegistryService {
1686
1703
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: ComponentRegistryService, decorators: [{
1687
1704
  type: Injectable
1688
1705
  }] });
1689
- /**
1690
- * What a new node holds before its element style is written. `color: inherit` because a new node
1691
- * belongs to the section it is dropped into: running text inherits (contract `body`/`lead`), so a
1692
- * literal on any ancestor — a Form, a slide, a field group — would override the section's text.
1693
- * A style that owns a colour (headings, buttons, notices) writes its own over this.
1694
- */
1695
- const NEW_NODE_STYLE_DEFAULTS = { color: 'inherit' };
1696
1706
  /** A new node AND the default children its config builds (a palette Form's fields, submit and
1697
1707
  * notices) are all new elements: each wears its type's default style. */
1698
1708
  function wearDefaultStyles(node) {
@@ -5076,13 +5086,16 @@ class RenderDirective {
5076
5086
  // template node is selectable/editable. Skip overlay registration + interaction
5077
5087
  // wiring for them so they can't be hovered, selected, or edited on the canvas.
5078
5088
  const isPreviewClone = !!node.__previewClone;
5089
+ // WRAPPER-COLLAPSE (opt-in via ioxDragSourceId): the HOST is the flex/grid item, so it carries
5090
+ // `iox-outer-{id}` (margin, width, grid placement) IN ADDITION to `iox-node-{id}` (visual) — one
5091
+ // element, like the engine. A display-only clone (a repeater row, a design specimen) is laid out
5092
+ // the same way: it only skips drag and selection below. Without the class a clone lost every
5093
+ // OUTER prop — its width, margin and grid placement — on the canvas alone.
5094
+ if (nativeEl && this.ioxDragSourceId != null && cssId)
5095
+ nativeEl.classList.add(`iox-outer-${cssId}`);
5079
5096
  if (nativeEl && !isPreviewClone) {
5080
- // WRAPPER-COLLAPSE (opt-in via ioxDragSourceId): the HOST is the flex/grid item, so it
5081
- // carries `iox-outer-{id}` (margin/width) IN ADDITION to `iox-node-{id}` (visual) — one
5082
- // element, like the engine — and drag is registered on it (the wrapper is gone). The
5083
- // StyleRegistry's split still works: both classes are on this one host.
5097
+ // Drag is registered on the collapsed host (the wrapper is gone).
5084
5098
  if (this.ioxDragSourceId != null && cssId) {
5085
- nativeEl.classList.add(`iox-outer-${cssId}`);
5086
5099
  const sourceId = this.ioxDragSourceId;
5087
5100
  this.dragEngine.registerDraggable(nativeEl, () => ({
5088
5101
  type: 'internal',
@@ -9893,10 +9906,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
9893
9906
  }] } });
9894
9907
 
9895
9908
  const MAX_HISTORY = 50;
9909
+ const clone = (value) => (value === undefined ? value : JSON.parse(JSON.stringify(value)));
9896
9910
  /**
9897
9911
  * BuilderHistoryService — snapshot-based undo/redo for the page builder.
9898
9912
  *
9899
- * Snapshots are JSON deep-clones of the full layout array.
9913
+ * Snapshots are JSON deep-clones of the full layout array; a step that also changed state outside
9914
+ * the layout records that change, so one undo reverts both.
9900
9915
  * Session-only — not persisted to the backend.
9901
9916
  * Scoped to PageUiComponent.providers[] — one history stack per builder instance.
9902
9917
  */
@@ -9907,8 +9922,8 @@ class BuilderHistoryService {
9907
9922
  }
9908
9923
  get canUndo() { return this._past.length > 1; }
9909
9924
  get canRedo() { return this._future.length > 0; }
9910
- push(layout) {
9911
- this._past.push({ layout: JSON.parse(JSON.stringify(layout)), timestamp: Date.now() });
9925
+ push(layout, change) {
9926
+ this._past.push({ layout: clone(layout), timestamp: Date.now(), ...(change ? { change: clone(change) } : {}) });
9912
9927
  if (this._past.length > MAX_HISTORY) {
9913
9928
  this._past.shift();
9914
9929
  }
@@ -9919,19 +9934,22 @@ class BuilderHistoryService {
9919
9934
  return null;
9920
9935
  const current = this._past.pop();
9921
9936
  this._future.unshift(current);
9922
- return JSON.parse(JSON.stringify(this._past[this._past.length - 1].layout));
9937
+ return this.step(this._past[this._past.length - 1].layout, current.change?.before, !!current.change);
9923
9938
  }
9924
9939
  redo() {
9925
9940
  if (!this.canRedo)
9926
9941
  return null;
9927
9942
  const next = this._future.shift();
9928
9943
  this._past.push(next);
9929
- return JSON.parse(JSON.stringify(next.layout));
9944
+ return this.step(next.layout, next.change?.after, !!next.change);
9930
9945
  }
9931
9946
  clear() {
9932
9947
  this._past = [];
9933
9948
  this._future = [];
9934
9949
  }
9950
+ step(layout, restore, changed) {
9951
+ return changed ? { layout: clone(layout), restore: clone(restore) } : { layout: clone(layout) };
9952
+ }
9935
9953
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderHistoryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
9936
9954
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderHistoryService }); }
9937
9955
  }
@@ -10634,12 +10652,18 @@ function wearing(node, styleId) {
10634
10652
  applyElementStyle(node, styleId);
10635
10653
  return node;
10636
10654
  }
10655
+ /** A Text node: a new Text wears `body` and the palette's 10px padding; a specimen's text sits flush. */
10637
10656
  function text(content, createConfig, styleId, styles = {}) {
10638
10657
  const node = textNode(content, createConfig);
10639
10658
  if (styleId)
10640
10659
  wearing(node, styleId);
10641
- return styled(node, styles);
10660
+ return styled(node, { padding: '0', margin: '0', ...styles });
10642
10661
  }
10662
+ /** A button's label takes the BUTTON's type (the style's size, weight, case, tracking) — not body's. */
10663
+ const BUTTON_LABEL = {
10664
+ color: 'inherit', fontFamily: 'inherit', fontSize: 'inherit', fontWeight: 'inherit', lineHeight: 'inherit',
10665
+ letterSpacing: 'inherit', textTransform: 'inherit',
10666
+ };
10643
10667
  function withChildren(node, children) {
10644
10668
  if (!node || children.some(c => !c))
10645
10669
  return null;
@@ -10665,7 +10689,7 @@ function button(styleId, label, createConfig, styles = {}) {
10665
10689
  return null;
10666
10690
  setTrait(btn, 'tag', 'button');
10667
10691
  styled(btn, styles);
10668
- return withChildren(btn, [text(label, createConfig, undefined, { color: 'inherit' })]);
10692
+ return withChildren(btn, [text(label, createConfig, undefined, BUTTON_LABEL)]);
10669
10693
  }
10670
10694
  /** A Container sized by its content: the palette Container's 200px drop-zone min-height is canvas
10671
10695
  * furniture, and a specimen has no drop zone. */