@vectoriox/iox-builder 11.11.1 → 11.12.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.
@@ -17,7 +17,7 @@ import { TooltipModule } from 'primeng/tooltip';
17
17
  import * as i20 from 'primeng/dialog';
18
18
  import { DialogModule } from 'primeng/dialog';
19
19
  import * as i1$1 from '@vectoriox/iox-ui';
20
- import { nodeCssId, needsGroupName, resolveBoundValue, STRUCTURAL_STATES as STRUCTURAL_STATES$1, VALIDATION_STATES as VALIDATION_STATES$1, VALIDATION_STATE_CLASS as VALIDATION_STATE_CLASS$1, DEFAULT_WIDTH_BY_TYPE, TEXT_DIRECTION_KEY, TEXT_ALIGN_KEY, TextAlign, COLOR_SCHEME_TRAIT, COLOR_SCHEMES, ColorScheme, LinkType, MAX_LINES_KEY, A11yTrait, BREAKPOINTS, Breakpoint, withSchemeInk, stripSuppressedProps, DeclarationContext, planPartRule, planResponsiveRules, resolveStyleProps, planStateRule, splitOuterProps, OUTER_STYLE_PROPS, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, isLastEmittedStateKey, wrapInBreakpointQuery, BreakpointQueryKind, NEW_NODE_STYLE_DEFAULTS, defaultElementStyleFor, applyElementStyle, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, ContextStore, ENTRANCE_ACTION_TYPES, EXIT_ACTION_TYPES, ComponentInstanceRegistryService, entranceStartsHidden, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, effectiveActionType, INTERACTION_HIDDEN_ATTRIBUTE, motionAllowed, settleInteraction, settleModeFor, playInteraction, entranceDelay, repeatedRowIndex, entrancePreStateStyle, buildInteractionKeyframes, cascadeChain, declaredInputNames, emptyImagePlaceholder, syncNodeDesignClasses, nodeTraitValue, syncNodeA11yAttributes, nodeA11yAttributes, safeSetInput, colorSchemeOf, composeVirtualTraits, withDefaultHoverTransition, stateNamesIn, partClassName, switchElementStyle, releaseElementStyle, countOverrides, setOverride, breakpointDef, breakpointForWidth, FormRenderState, needsAccessibleName, resolveInputs, setInputOverride, barReserveClass, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, syncSubmitButtons, IS_PREVIEW, buttonBlockHref, bootSlider, IoxPageModule, PALETTE_PRESETS, elementStyleById, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
20
+ import { nodeCssId, needsGroupName, resolveBoundValue, STRUCTURAL_STATES as STRUCTURAL_STATES$1, VALIDATION_STATES as VALIDATION_STATES$1, VALIDATION_STATE_CLASS as VALIDATION_STATE_CLASS$1, DEFAULT_WIDTH_BY_TYPE, TEXT_DIRECTION_KEY, TEXT_ALIGN_KEY, TextAlign, COLOR_SCHEME_TRAIT, COLOR_SCHEMES, ColorScheme, LinkType, MAX_LINES_KEY, A11yTrait, BREAKPOINTS, Breakpoint, withSchemeInk, stripSuppressedProps, DeclarationContext, planPartRule, gateHoverRule, planResponsiveRules, resolveStyleProps, planStateRule, splitOuterProps, OUTER_STYLE_PROPS, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, isLastEmittedStateKey, wrapInBreakpointQuery, BreakpointQueryKind, NEW_NODE_STYLE_DEFAULTS, defaultElementStyleFor, applyElementStyle, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, ContextStore, ENTRANCE_ACTION_TYPES, EXIT_ACTION_TYPES, ComponentInstanceRegistryService, entranceStartsHidden, isActionEnabled, splitPressFeedback, isHoverPointer, isContextAction, contextActionEffect, resolveContextValue, effectiveActionType, INTERACTION_HIDDEN_ATTRIBUTE, motionAllowed, settleInteraction, settleModeFor, playInteraction, resolveInteractionEasing, entranceDelay, repeatedRowIndex, entrancePreStateStyle, buildInteractionKeyframes, cascadeChain, declaredInputNames, emptyImagePlaceholder, syncNodeDesignClasses, nodeTraitValue, syncNodeA11yAttributes, nodeA11yAttributes, safeSetInput, colorSchemeOf, withStateTransitions, composeVirtualTraits, stateNamesIn, partClassName, switchElementStyle, releaseElementStyle, countOverrides, setOverride, breakpointDef, breakpointForWidth, FormRenderState, needsAccessibleName, resolveInputs, setInputOverride, barReserveClass, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, isScrolled, SCROLLED_ATTRIBUTE, syncSubmitButtons, IS_PREVIEW, buttonBlockHref, bootSlider, IoxPageModule, PALETTE_PRESETS, elementStyleById, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
21
21
  export { ComponentInstanceRegistryService, VIRTUAL_TRAIT_KEYS, composeVirtualTraits } from '@vectoriox/iox-ui';
22
22
  import { StructureEdit, isAccordionPart, isDisclosurePart, isSliderPart, isTabsPart, isSegmentedPart, structureRefusal, StructureRefusal, SegmentedRole, SEGMENTED_MAX_OPTIONS, AccordionRole, SEGMENTED_MIN_OPTIONS, isExclusiveItemPart, TabsRole, ITEM_OPEN_STATE, readStyle, isSegmentedRoot, segmentedDefaultOn, segmentedOptions, isTabsRoot, isTabsFromContent, tabsTriggers, isAccordionRoot, isAccordionFromContent, accordionItems, initialAccordionOpen, accordionBehaviour, exclusiveItemLabel, exclusiveRootOf, tabTriggerOf, tabLabel, removeTabPair, tabPanelOf, tabsListOf, tabsPanelsOf, nextTabKey, CompositeBehaviourTrait, ACCORDION_DEFAULT_ONS, TabsBehaviourTrait, TABS_ACTIVATE_ONS, TABS_ORIENTATIONS, onCompositeItemState, isCompositeItemOn, runCompositeItemAction, shouldScrollToItem, rowIndexOf as rowIndexOf$1, slideIndexForRow, DisclosureRole, isExclusiveTrigger, compositeScopeId, compositeRowKeys, isExclusiveRoot, ExclusiveRuntime, exclusiveDefaultOf, exclusiveLabelOf, exclusiveBehaviourOf, exclusiveKindOf, compositeKindOfRole, AccordionRuntime, isToggleKind, closestAccordionItem, isAnyCompositeRoot, SceneRole, isExclusiveList, buildCardRecipe, buildBadge, buildChip, buildAccordionRecipe, buildDisclosureRecipe, buildTabsRecipe, buildSegmentedRecipe, buildLightboxRecipe, NO_ELEMENT_STYLE, CompositeKind, SliderRole, accordionItemLabel, segmentedOptionLabel, isExclusivePanels, isLockedPart, accordionRootOf, accordionItemOf, addAccordionItem, addTabPair, segmentedAddRefusal, addSegmentedOption, isCompositeItem, accordionHeadingLevel, isCompositePanel, isCompositeTrigger, splitSliderChildren, hasSliderParts } from '@vectoriox/iox-ui/composite-core';
23
23
  import { formContentInHost, isInteractiveHost, findFormContentInHosts } from '@vectoriox/iox-ui/forms-core';
@@ -1346,6 +1346,7 @@ const ACTION_TYPE_OPTIONS = [
1346
1346
  ];
1347
1347
  /** Dialog actions, for the engines' dispatch branch (mirror of SWIPER's set). */
1348
1348
  const DIALOG_ACTION_TYPES = new Set(['openDialog', 'closeDialog', 'toggleDialog']);
1349
+ /** The keyword easings — the panel lists the look's easing tokens (iox-ui `EASING_TOKENS`) and a custom curve beside them. */
1349
1350
  const EASING_OPTIONS = ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out'];
1350
1351
  /** Interaction pseudo-classes — compiled to .iox-node-{id}:state */
1351
1352
  const INTERACTION_STATES = ['hover', 'active', 'focus'];
@@ -1398,7 +1399,7 @@ const VALIDATION_STATE_CLASS = VALIDATION_STATE_CLASS$1;
1398
1399
  * (`stateSelectorSuffix` in @vectoriox/iox-ui), never a pseudo-class. Offered per type by
1399
1400
  * `componentStatesFor`.
1400
1401
  */
1401
- const COMPONENT_STATES = ['current', 'on'];
1402
+ const COMPONENT_STATES = ['current', 'on', 'disabled', 'busy', 'selected', 'scrolled'];
1402
1403
  const SUPPORTED_STATES = [...INTERACTION_STATES, ...STRUCTURAL_STATES, ...RELATIONAL_STATES, ...TARGETED_STATES, ...VALIDATION_STATES, ...COMPONENT_STATES];
1403
1404
  /**
1404
1405
  * Build a full StyleTraitGroup[] schema populated with values from a flat
@@ -1828,6 +1829,19 @@ class EffectsGroupStyleConfig extends GroupStyleConfig {
1828
1829
  new TraitConfig('rotate', 'Rotate', TraitInputType.Scrub, { min: -360, max: 360, step: 1, units: UNITS_DEG }, '0deg', true),
1829
1830
  new TraitConfig('skewX', 'Skew X', TraitInputType.Scrub, { min: -180, max: 180, step: 1, units: UNITS_DEG }, '0deg', true),
1830
1831
  new TraitConfig('skewY', 'Skew Y', TraitInputType.Scrub, { min: -180, max: 180, step: 1, units: UNITS_DEG }, '0deg', true),
1832
+ // G3: where the element scales and turns FROM — a popover grows from its trigger (Emil 47). Physical
1833
+ // keywords: transform-origin has no logical ones. The default is the CSS initial (never emitted).
1834
+ new TraitConfig('transformOrigin', 'Origin', TraitInputType.Select, [
1835
+ { label: 'Center', value: 'center' },
1836
+ { label: 'Top', value: 'top' },
1837
+ { label: 'Bottom', value: 'bottom' },
1838
+ { label: 'Left', value: 'left' },
1839
+ { label: 'Right', value: 'right' },
1840
+ { label: 'Top left', value: 'top left' },
1841
+ { label: 'Top right', value: 'top right' },
1842
+ { label: 'Bottom left', value: 'bottom left' },
1843
+ { label: 'Bottom right', value: 'bottom right' },
1844
+ ], 'center'),
1831
1845
  // ── Filter (virtual — composed to CSS filter: …) ──────
1832
1846
  new TraitConfig('_sep_filter', 'Filter', TraitInputType.SectionLabel),
1833
1847
  new TraitConfig('filterBlur', 'Blur', TraitInputType.Scrub, { min: 0, max: 50, step: 1, units: ['px'] }, '0px', true),
@@ -1860,8 +1874,10 @@ class EffectsGroupStyleConfig extends GroupStyleConfig {
1860
1874
  { label: 'Hexagon', value: 'polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)' },
1861
1875
  { label: 'Chevron', value: 'polygon(0 0, 75% 0, 100% 50%, 75% 100%, 0 100%, 25% 50%)' },
1862
1876
  ], 'none'),
1863
- // ── Transition (virtual — composed to CSS transition: all …) ──
1877
+ // ── Transition (virtual — composed to one CSS transition entry per property, never `all`: G2) ──
1864
1878
  new TraitConfig('_sep_transition', 'Transition', TraitInputType.SectionLabel),
1879
+ // Empty: the properties the element's states change (the renderers fill them in); a list wins.
1880
+ new TraitConfig('transitionProperty', 'Properties', TraitInputType.Text, undefined, ''),
1865
1881
  new TraitConfig('transitionDuration', 'Duration', TraitInputType.Scrub, { min: 0, max: 3000, step: 50, units: ['ms'] }, '0ms', true),
1866
1882
  new TraitConfig('transitionDelay', 'Delay', TraitInputType.Scrub, { min: 0, max: 2000, step: 50, units: ['ms'] }, '0ms', true),
1867
1883
  new TraitConfig('transitionTimingFunction', 'Easing', TraitInputType.Select, [
@@ -2239,7 +2255,7 @@ class StyleRegistryService {
2239
2255
  // The shared planner the engine uses (iox-client-engine#14): a part's hover / focus is the PART's own pseudo-class
2240
2256
  // — before, any non-validation state compiled to the bare part selector and applied at all times.
2241
2257
  const selector = planPartRule(nodeId, partClassName, state);
2242
- const css = selector && Object.keys(styles).length ? this.compileSelector(selector, styles) : '';
2258
+ const css = selector && Object.keys(styles).length ? gateHoverRule(state, this.compileSelector(selector, styles)) : '';
2243
2259
  if (css)
2244
2260
  this.rules.set(key, css);
2245
2261
  else
@@ -2325,8 +2341,9 @@ class StyleRegistryService {
2325
2341
  if (!plan)
2326
2342
  return '';
2327
2343
  const { inner, outer } = plan.outer ? splitOuterProps(styles) : { inner: styles, outer: {} };
2328
- return [this.compileSelector(plan.inner, inner, context), plan.outer ? this.compileSelector(plan.outer, outer, context) : '']
2329
- .filter(Boolean).join('\n');
2344
+ // A hover state's rule only where there is a hover (G1) — the engine gates the same rules the same way.
2345
+ return gateHoverRule(state, [this.compileSelector(plan.inner, inner, context), plan.outer ? this.compileSelector(plan.outer, outer, context) : '']
2346
+ .filter(Boolean).join('\n'));
2330
2347
  }
2331
2348
  /**
2332
2349
  * The inner + outer rule (joined) and the `::marker` rule for one composed style map.
@@ -4411,6 +4428,9 @@ class InteractionEngineService {
4411
4428
  requestAnimationFrame(poll);
4412
4429
  }
4413
4430
  attachClick(node, ix, element) {
4431
+ // G7: press FEEDBACK (an animation of the pressed element that hides and shows nothing) lands on pointer-down,
4432
+ // at once; the rest commits on the click. A toggle keeps its whole list on the click (the shared split, iox-ui).
4433
+ const { onPress, onClick } = ix.reverseActions?.length ? { onPress: [], onClick: ix.actions } : splitPressFeedback(ix.actions);
4414
4434
  const handler = () => {
4415
4435
  if (ix.reverseActions?.length) {
4416
4436
  // Toggle: alternate between primary and reverse actions on each click.
@@ -4419,18 +4439,29 @@ class InteractionEngineService {
4419
4439
  this.toggleStates.set(ix.id, !isToggled);
4420
4440
  }
4421
4441
  else {
4422
- this.runActions(node, ix.actions, element);
4442
+ this.runActions(node, onClick, element);
4423
4443
  }
4424
4444
  };
4445
+ const press = (e) => { if (e.button === 0 || e.pointerType !== 'mouse')
4446
+ this.runActions(node, onPress, element); };
4425
4447
  // CAPTURE, like the composite runtime: on the canvas every part's own listener stops the click to select
4426
4448
  // that part, so a click on a button's LABEL never bubbled to the button's click interaction — the live
4427
4449
  // site runs it (CC2.1: "Open an item" on a ButtonBlock did nothing on the canvas).
4428
4450
  element.addEventListener('click', handler, true);
4429
- return () => element.removeEventListener('click', handler, true);
4451
+ if (onPress.length)
4452
+ element.addEventListener('pointerdown', press, true);
4453
+ return () => {
4454
+ element.removeEventListener('click', handler, true);
4455
+ element.removeEventListener('pointerdown', press, true);
4456
+ };
4430
4457
  }
4431
4458
  attachHover(node, ix, element) {
4432
- const enterHandler = () => this.runActions(node, ix.actions, element);
4433
- const leaveHandler = () => {
4459
+ // G7: a hover trigger answers a mouse or a pen — a finger's emulated hover stuck until the next tap elsewhere.
4460
+ const enterHandler = (e) => { if (isHoverPointer(e))
4461
+ this.runActions(node, ix.actions, element); };
4462
+ const leaveHandler = (e) => {
4463
+ if (!isHoverPointer(e))
4464
+ return;
4434
4465
  // Reverse animations on leave for hover triggers
4435
4466
  for (const action of ix.actions) {
4436
4467
  if (!isActionEnabled(action))
@@ -4447,11 +4478,11 @@ class InteractionEngineService {
4447
4478
  this.reverseAction(target, action);
4448
4479
  }
4449
4480
  };
4450
- element.addEventListener('mouseenter', enterHandler);
4451
- element.addEventListener('mouseleave', leaveHandler);
4481
+ element.addEventListener('pointerenter', enterHandler);
4482
+ element.addEventListener('pointerleave', leaveHandler);
4452
4483
  return () => {
4453
- element.removeEventListener('mouseenter', enterHandler);
4454
- element.removeEventListener('mouseleave', leaveHandler);
4484
+ element.removeEventListener('pointerenter', enterHandler);
4485
+ element.removeEventListener('pointerleave', leaveHandler);
4455
4486
  };
4456
4487
  }
4457
4488
  // ── Actions ──────────────────────────────────────────────
@@ -4686,7 +4717,8 @@ class InteractionEngineService {
4686
4717
  const anim = playInteraction(element, { type, params: action.params }, keyframes, {
4687
4718
  duration: action.duration,
4688
4719
  delay: entranceDelay(action, repeatedRowIndex(element)),
4689
- easing: action.easing,
4720
+ // A keyword, a curve, or the look's easing token as this element sees it (G6) — the live site's resolver.
4721
+ easing: resolveInteractionEasing(action.easing, element),
4690
4722
  }, this.settleOptions());
4691
4723
  anim.finished.then(() => this.settleAfter(element, type)).catch(() => { });
4692
4724
  }
@@ -4764,7 +4796,7 @@ class InteractionEngineService {
4764
4796
  }
4765
4797
  playInteraction(element, { type, params: action.params }, frames, {
4766
4798
  duration: action.duration,
4767
- easing: action.easing,
4799
+ easing: resolveInteractionEasing(action.easing, element),
4768
4800
  }, { ...this.settleOptions(), reverse: true });
4769
4801
  }
4770
4802
  /** The action's keyframes from the ONE shared table both runtimes animate from (composite T2). */
@@ -5678,7 +5710,9 @@ class RenderDirective {
5678
5710
  // The default hover transition (shared, marker-aware — the engine emits the same one):
5679
5711
  // without it a hovering node's base rule, re-upserted here on every render, dropped the
5680
5712
  // transition page-ui had added on load, and the canvas snapped where the site eased.
5681
- const composedBase = composeVirtualTraits(withDefaultHoverTransition(initialStyle, node.stateStyles, node.elementStyle));
5713
+ // The transition names what the node's states change (G2) — the engine composes the same, from the same call.
5714
+ const timedBase = withStateTransitions(initialStyle, node.stateStyles, node.elementStyle, node.responsive);
5715
+ const composedBase = composeVirtualTraits(timedBase);
5682
5716
  this.styleRegistry.upsert(cssId, composedBase);
5683
5717
  // Restore per-state overrides saved from a previous session.
5684
5718
  // Every state set at base OR at any breakpoint — so a breakpoint-only state (a Mobile-only
@@ -5725,7 +5759,7 @@ class RenderDirective {
5725
5759
  }
5726
5760
  }
5727
5761
  // Breakpoint layers — AFTER the state loop, so every scope resolved above is recorded.
5728
- this.styleRegistry.upsertResponsive(cssId, initialStyle, node.stateStyles, node.responsive);
5762
+ this.styleRegistry.upsertResponsive(cssId, timedBase, node.stateStyles, node.responsive);
5729
5763
  // Part styles (board 7 — "the failure design"). Simpler than the state loop above:
5730
5764
  // a part+state combo always compounds onto THIS node (no relational/targeted scope
5731
5765
  // to resolve), so every entry just needs its base plus each of its own state overrides.
@@ -6927,8 +6961,8 @@ function nodeStyleMap(node) {
6927
6961
  return base;
6928
6962
  }
6929
6963
  /**
6930
- * Re-register a node's compiled rules from its CURRENT style values — the base rule (with the default
6931
- * hover transition), its self-scoped state rules and its breakpoint layers — exactly as the
6964
+ * Re-register a node's compiled rules from its CURRENT style values — the base rule (its transition naming what its
6965
+ * states change, G2), its self-scoped state rules and its breakpoint layers — exactly as the
6932
6966
  * RenderDirective registers them at render. For edits that rewrite a node's styles from outside the Style
6933
6967
  * panel (a Card's layout preset, a reset to defaults).
6934
6968
  */
@@ -6938,13 +6972,14 @@ function upsertNodeStyles(styleRegistry, node) {
6938
6972
  return;
6939
6973
  const base = nodeStyleMap(node);
6940
6974
  styleRegistry.setNodeType(cssId, node.type, colorSchemeOf(node));
6941
- styleRegistry.upsert(cssId, composeVirtualTraits(withDefaultHoverTransition(base, node.stateStyles, node.elementStyle)));
6975
+ const timedBase = withStateTransitions(base, node.stateStyles, node.elementStyle, node.responsive);
6976
+ styleRegistry.upsert(cssId, composeVirtualTraits(timedBase));
6942
6977
  for (const [state, map] of Object.entries(node.stateStyles ?? {})) {
6943
6978
  if (DOM_SCOPED_STATES.has(state) || !map || !Object.keys(map).length)
6944
6979
  continue;
6945
6980
  styleRegistry.upsert(cssId, composeVirtualTraits(map, base), state);
6946
6981
  }
6947
- styleRegistry.upsertResponsive(cssId, base, node.stateStyles, node.responsive);
6982
+ styleRegistry.upsertResponsive(cssId, timedBase, node.stateStyles, node.responsive);
6948
6983
  }
6949
6984
  /** Push every content trait of a node to its rendered component (a Card title's link switched on). */
6950
6985
  function syncNodeInputs(ref, node) {
@@ -9972,6 +10007,15 @@ class BuilderComponent {
9972
10007
  this.globalOverlayRef?.nativeElement?.style.setProperty('--preview-vw', vwVal);
9973
10008
  this.canvasFrameHeight = Math.round(frameH);
9974
10009
  }
10010
+ /** Keep the Scrolled attribute (iox-ui SCROLLED_ATTRIBUTE) on the canvas page and the header overlay — written only
10011
+ * when it changes, so the overlay's mutation observers never wake for a scroll tick. */
10012
+ syncScrolled(offset) {
10013
+ const scrolled = isScrolled(offset);
10014
+ for (const el of [this.previewCanvas?.nativeElement, this.globalOverlayRef?.nativeElement]) {
10015
+ if (el && el.hasAttribute(SCROLLED_ATTRIBUTE) !== scrolled)
10016
+ el.toggleAttribute(SCROLLED_ATTRIBUTE, scrolled);
10017
+ }
10018
+ }
9975
10019
  initLenis() {
9976
10020
  this.destroyLenis();
9977
10021
  if (!this.previewScrollRef?.nativeElement || !this.lenisContentRef?.nativeElement)
@@ -9986,6 +10030,8 @@ class BuilderComponent {
9986
10030
  this.lenis.on('scroll', (instance) => {
9987
10031
  // A Scene's stage is held against this very scroll: a frame later, it would paint carried off its pin.
9988
10032
  this.sceneCanvas?.pinNow();
10033
+ // The Scrolled state (G4) on the canvas: the page and its header globals know the canvas has moved.
10034
+ this.syncScrolled(instance.scroll);
9989
10035
  const clientH = this.previewScrollRef.nativeElement.clientHeight;
9990
10036
  this.onPageScroll({
9991
10037
  scrollTop: instance.scroll,