@vectoriox/iox-ui 5.31.1 → 5.32.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.
@@ -7,7 +7,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
7
7
  import * as i1 from '@angular/common';
8
8
  import { CommonModule, isPlatformBrowser } from '@angular/common';
9
9
  import Lenis from 'lenis';
10
- import '@vectoriox/iox-ui/actions-core';
10
+ import { dialogOpenerAttributes, dialogDomId } from '@vectoriox/iox-ui/actions-core';
11
11
  export * from '@vectoriox/iox-ui/design-core';
12
12
 
13
13
  class ViewPositionDirective {
@@ -2117,6 +2117,79 @@ function sameValues(a, b) {
2117
2117
  return true;
2118
2118
  }
2119
2119
 
2120
+ /**
2121
+ * Reduced motion (CC1, R1 — complex-components plan §2d). The token sheet already collapses the
2122
+ * motion tokens under `prefers-reduced-motion`; everything that moves through SCRIPT must ask the
2123
+ * same question, and ask it HERE: the interaction engines (builder canvas + live site), the Slider's
2124
+ * autoplay and the Gallery's crossfade loop. Publishable gate #6: reduced motion = motion dial 0.
2125
+ */
2126
+ const REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';
2127
+ function defaultHost() {
2128
+ return typeof window !== 'undefined' ? window : null;
2129
+ }
2130
+ /** True when the visitor asked their system for reduced motion. No `matchMedia` (SSR) → false. */
2131
+ function prefersReducedMotion(host = defaultHost()) {
2132
+ try {
2133
+ return !!host?.matchMedia?.(REDUCED_MOTION_QUERY)?.matches;
2134
+ }
2135
+ catch {
2136
+ return false;
2137
+ }
2138
+ }
2139
+ /** True when script may animate. The ONE question every runtime asks before moving anything. */
2140
+ function motionAllowed(host = defaultHost()) {
2141
+ return !prefersReducedMotion(host);
2142
+ }
2143
+
2144
+ /**
2145
+ * Which Swiper modules a Slider loads, and how its autoplay boots — a pure decision, so the module list
2146
+ * is unit-tested (CC1 R1/R2 floor; complex-components plan §7c). Swiper's A11y module is ALWAYS loaded:
2147
+ * it gives the container `aria-roledescription="carousel"`, every slide "slide" and an "n of m" label, and
2148
+ * keeps the live region quiet while it rotates. Autoplay never boots under reduced motion (Publishable
2149
+ * gate #6). The rotation pause control and the slider parts as nodes are CC3.
2150
+ */
2151
+ var SwiperModuleName;
2152
+ (function (SwiperModuleName) {
2153
+ SwiperModuleName["A11y"] = "A11y";
2154
+ SwiperModuleName["Navigation"] = "Navigation";
2155
+ SwiperModuleName["Pagination"] = "Pagination";
2156
+ SwiperModuleName["Scrollbar"] = "Scrollbar";
2157
+ SwiperModuleName["Autoplay"] = "Autoplay";
2158
+ SwiperModuleName["Keyboard"] = "Keyboard";
2159
+ SwiperModuleName["Mousewheel"] = "Mousewheel";
2160
+ SwiperModuleName["Zoom"] = "Zoom";
2161
+ SwiperModuleName["Grid"] = "Grid";
2162
+ SwiperModuleName["Parallax"] = "Parallax";
2163
+ })(SwiperModuleName || (SwiperModuleName = {}));
2164
+ const FLAGGED = [
2165
+ ['enableNavigation', SwiperModuleName.Navigation],
2166
+ ['enablePagination', SwiperModuleName.Pagination],
2167
+ ['enableScrollbar', SwiperModuleName.Scrollbar],
2168
+ ['enableAutoplay', SwiperModuleName.Autoplay],
2169
+ ['enableKeyboard', SwiperModuleName.Keyboard],
2170
+ ['enableMousewheel', SwiperModuleName.Mousewheel],
2171
+ ['enableZoom', SwiperModuleName.Zoom],
2172
+ ['enableGrid', SwiperModuleName.Grid],
2173
+ ['enableParallax', SwiperModuleName.Parallax],
2174
+ ];
2175
+ /** True when the Slider's autoplay may start: on, and the visitor has not asked for reduced motion. */
2176
+ function swiperAutoplayAllowed(enableAutoplay, motionAllowed) {
2177
+ return !!enableAutoplay && motionAllowed;
2178
+ }
2179
+ /** The modules to load, A11y first. */
2180
+ function swiperModuleNames(flags, motionAllowed) {
2181
+ return [SwiperModuleName.A11y, ...FLAGGED
2182
+ .filter(([flag, name]) => flags[flag] && (name !== SwiperModuleName.Autoplay || swiperAutoplayAllowed(flags.enableAutoplay, motionAllowed)))
2183
+ .map(([, name]) => name)];
2184
+ }
2185
+ /** Swiper's A11y options: carousel / slide role descriptions and an "n of m" slide label. */
2186
+ const SWIPER_A11Y_OPTIONS = {
2187
+ enabled: true,
2188
+ containerRoleDescriptionMessage: 'carousel',
2189
+ itemRoleDescriptionMessage: 'slide',
2190
+ slideLabelMessage: '{{index}} of {{slidesLength}}',
2191
+ };
2192
+
2120
2193
  class ClientSliderContainerComponent {
2121
2194
  /** The base (Base-breakpoint) values of the traits Swiper reads per width. Read from the live
2122
2195
  * inputs rather than the node, so the builder's direct-assignment edits are picked up too. */
@@ -2197,26 +2270,10 @@ class ClientSliderContainerComponent {
2197
2270
  import('swiper'),
2198
2271
  import('swiper/modules'),
2199
2272
  ]);
2200
- const { Navigation, Pagination, Scrollbar, Autoplay, Keyboard, Mousewheel, Zoom, Grid, Parallax, EffectFade, EffectCube, EffectFlip, EffectCoverflow, EffectCards, EffectCreative, } = swiperModules;
2201
- const modules = [];
2202
- if (this.enableNavigation)
2203
- modules.push(Navigation);
2204
- if (this.enablePagination)
2205
- modules.push(Pagination);
2206
- if (this.enableScrollbar)
2207
- modules.push(Scrollbar);
2208
- if (this.enableAutoplay)
2209
- modules.push(Autoplay);
2210
- if (this.enableKeyboard)
2211
- modules.push(Keyboard);
2212
- if (this.enableMousewheel)
2213
- modules.push(Mousewheel);
2214
- if (this.enableZoom)
2215
- modules.push(Zoom);
2216
- if (this.enableGrid)
2217
- modules.push(Grid);
2218
- if (this.enableParallax)
2219
- modules.push(Parallax);
2273
+ const { EffectFade, EffectCube, EffectFlip, EffectCoverflow, EffectCards, EffectCreative, } = swiperModules;
2274
+ // The module list is the shared, tested decision: A11y always; Autoplay never under reduced motion.
2275
+ const motion = motionAllowed();
2276
+ const modules = swiperModuleNames(this, motion).map(name => swiperModules[name]);
2220
2277
  const effectMap = {
2221
2278
  fade: EffectFade, cube: EffectCube, flip: EffectFlip,
2222
2279
  coverflow: EffectCoverflow, cards: EffectCards, creative: EffectCreative,
@@ -2246,7 +2303,8 @@ class ClientSliderContainerComponent {
2246
2303
  config['pagination'] = { el: '.swiper-pagination', type: this.paginationType, clickable: this.paginationClickable };
2247
2304
  if (this.enableScrollbar)
2248
2305
  config['scrollbar'] = { el: '.swiper-scrollbar', draggable: true };
2249
- if (this.enableAutoplay)
2306
+ config['a11y'] = { ...SWIPER_A11Y_OPTIONS };
2307
+ if (swiperAutoplayAllowed(this.enableAutoplay, motion))
2250
2308
  config['autoplay'] = { delay: this.autoplayDelay, pauseOnMouseEnter: this.autoplayPauseOnMouseEnter, disableOnInteraction: this.autoplayDisableOnInteraction };
2251
2309
  if (this.enableGrid && this.gridRows > 1)
2252
2310
  config['grid'] = { rows: this.gridRows };
@@ -2877,6 +2935,7 @@ class GalleryLoop {
2877
2935
  this.showMs = opts.showMs;
2878
2936
  this.fadeMs = opts.fadeMs;
2879
2937
  this.onChange = opts.onChange;
2938
+ this.motionAllowed = opts.motionAllowed !== false;
2880
2939
  }
2881
2940
  get state() {
2882
2941
  return {
@@ -2905,7 +2964,7 @@ class GalleryLoop {
2905
2964
  return;
2906
2965
  this.firstCycleActive = true;
2907
2966
  this.emit();
2908
- if (this.count > 1)
2967
+ if (this.count > 1 && this.motionAllowed)
2909
2968
  this.scheduleCycle(token);
2910
2969
  });
2911
2970
  }
@@ -3041,6 +3100,8 @@ class ClientGalleryComponent {
3041
3100
  this.loop = new GalleryLoop({
3042
3101
  showMs: this.showDuration,
3043
3102
  fadeMs: this.fadeDuration,
3103
+ // Reduced motion (CC1 R1): the first image, standing still.
3104
+ motionAllowed: motionAllowed(),
3044
3105
  onChange: state => {
3045
3106
  this.currentIndex = state.currentIndex;
3046
3107
  this.fadingOutIndex = state.fadingOutIndex;
@@ -5166,6 +5227,23 @@ function styleKeyToKebab(key) {
5166
5227
  return key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);
5167
5228
  }
5168
5229
 
5230
+ /**
5231
+ * The content traits the accessibility attributes are read from (CC1). Import-free on purpose: the
5232
+ * builder's component configs declare these traits, and the node-baseline generator bundles those
5233
+ * configs against this file directly.
5234
+ */
5235
+ var A11yTrait;
5236
+ (function (A11yTrait) {
5237
+ /** "Accessibility ▸ Accessible name" — the name of an icon-only control (and of a Dialog). */
5238
+ A11yTrait["AccessibleName"] = "ariaLabel";
5239
+ /** A Dialog's "Close when wider than": a breakpoint id, or empty = never. */
5240
+ A11yTrait["CloseAbove"] = "closeAbove";
5241
+ })(A11yTrait || (A11yTrait = {}));
5242
+ /** The types that carry an Accessible name trait. */
5243
+ const ACCESSIBLE_NAME_TYPES = ['ButtonBlock', 'LinkedContainer', 'Link', 'Dialog'];
5244
+ /** The types that link to a page and can therefore be the current page's link. */
5245
+ const CURRENT_LINK_TYPES = ['Link', 'LinkedContainer', 'ButtonBlock'];
5246
+
5169
5247
  /**
5170
5248
  * style-compiler — the SINGLE source of truth for turning a node's style map into
5171
5249
  * CSS declarations. Framework-agnostic (no Angular): consumed by both renderers.
@@ -5318,6 +5396,31 @@ const STATE_PSEUDO_CLASS = { focus: 'focus-visible' };
5318
5396
  function statePseudoClass(state) {
5319
5397
  return STATE_PSEUDO_CLASS[state] ?? state;
5320
5398
  }
5399
+ /**
5400
+ * Component states (CC1 N2; composite plan T12): states a node is IN because of what it is, not where
5401
+ * the pointer is — so they compile to an ATTRIBUTE the renderers write, never a pseudo-class. `current`
5402
+ * is the link to the page the visitor is on (`aria-current="page"`, written by `nodeA11yAttributes`),
5403
+ * so the look and the announcement are one fact.
5404
+ */
5405
+ var ComponentState;
5406
+ (function (ComponentState) {
5407
+ ComponentState["Current"] = "current";
5408
+ })(ComponentState || (ComponentState = {}));
5409
+ /** The attribute selector each component state compiles to. */
5410
+ const COMPONENT_STATE_SELECTOR = {
5411
+ [ComponentState.Current]: '[aria-current="page"]',
5412
+ };
5413
+ /** The component states a type offers in the Style panel's "Component state" group. */
5414
+ function componentStatesFor(type) {
5415
+ return type && CURRENT_LINK_TYPES.includes(type) ? [ComponentState.Current] : [];
5416
+ }
5417
+ /**
5418
+ * What follows `.iox-node-<id>` in a stored state's rule: `:hover`, `:focus-visible`, or a component
5419
+ * state's attribute selector (`[aria-current="page"]`). Shared by the builder canvas and both engine paths.
5420
+ */
5421
+ function stateSelectorSuffix(state) {
5422
+ return COMPONENT_STATE_SELECTOR[state] ?? `:${statePseudoClass(state)}`;
5423
+ }
5321
5424
  /** The states driven by a pointer hovering something — each earns the default hover transition. */
5322
5425
  const HOVER_STATES = ['hover', 'parent-hover', 'trigger-hover'];
5323
5426
  /** True when the node restyles on hover (its own, its parent's or a chosen trigger's). */
@@ -5599,6 +5702,244 @@ function partClassName(type, partKey) {
5599
5702
  return PART_CLASS_NAMES[type]?.[partKey];
5600
5703
  }
5601
5704
 
5705
+ /**
5706
+ * "This link is the page you're on" (CC1, N2). ONE decision for the builder canvas and both engine
5707
+ * paths: a link whose target is the current page renders `aria-current="page"` — in the raw SSR too —
5708
+ * and the `current` style state compiles to that attribute (`[aria-current="page"]`), so the look and
5709
+ * the announcement can never disagree.
5710
+ *
5711
+ * Paths are compared APP-relative: the engine's string path writes base-relative hrefs (`work`, `./`
5712
+ * for home), the canvas writes the route (`/work`), and a browser hands back an absolute pathname
5713
+ * under the tenant's `<base href="/<org>/">` — `baseHref` strips that.
5714
+ */
5715
+ /** The value a current link carries. */
5716
+ const ARIA_CURRENT_PAGE = 'page';
5717
+ const EXTERNAL = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
5718
+ /** True for an href that leaves the site (a scheme, protocol-relative) or stays on the page (`#…`, empty). */
5719
+ function isExternalOrFragment(href) {
5720
+ const h = String(href ?? '').trim();
5721
+ return !h || h.startsWith('#') || EXTERNAL.test(h);
5722
+ }
5723
+ /**
5724
+ * An app path in one comparable form: no query or hash, no base, no leading `./` or slashes, no
5725
+ * trailing slash. Home is `''`.
5726
+ */
5727
+ function normalizeAppPath(path, baseHref) {
5728
+ let p = String(path ?? '').trim().replace(/[?#].*$/, '');
5729
+ const base = String(baseHref ?? '').trim().replace(/\/+$/, '');
5730
+ if (base && base !== '/' && (p === base || p.startsWith(`${base}/`)))
5731
+ p = p.slice(base.length);
5732
+ p = p.replace(/^(?:\.\/)+/, '').replace(/\/{2,}/g, '/').replace(/^\/+/, '').replace(/\/+$/, '');
5733
+ return p === '.' ? '' : p;
5734
+ }
5735
+ /** Whether `href` points at the page at `currentPath` (both app-relative, or absolute under `baseHref`). */
5736
+ function isCurrentLink(href, currentPath, options = {}) {
5737
+ if (currentPath == null || isExternalOrFragment(href))
5738
+ return false;
5739
+ const target = normalizeAppPath(href, options.baseHref);
5740
+ const here = normalizeAppPath(currentPath, options.baseHref);
5741
+ if (target === here)
5742
+ return true;
5743
+ return !!options.prefix && target !== '' && here.startsWith(`${target}/`);
5744
+ }
5745
+
5746
+ /**
5747
+ * The accessibility attributes a node renders (CC1: N2 current page, N3 dialog openers, N4 a drawer
5748
+ * that closes when the window widens, N6 accessible names). ONE function decides them and every
5749
+ * renderer applies the answer with its own transport: the engine's string path serialises it, the
5750
+ * engine's component path and the builder canvas set it on the node's element. A node that wants
5751
+ * none of it gets `{}` and renders exactly as before.
5752
+ */
5753
+ /** The types that are pure decoration to assistive technology (an Icon has no name of its own). */
5754
+ const DECORATIVE_TYPES = ['Icon'];
5755
+ const DIALOG_NODE_TYPE = 'Dialog';
5756
+ /** Carries the min-width (px) at which an open dialog closes itself; the engine listens on it. */
5757
+ const DIALOG_CLOSE_ABOVE_ATTRIBUTE = 'data-iox-dialog-close-above';
5758
+ var A11yAttribute;
5759
+ (function (A11yAttribute) {
5760
+ A11yAttribute["Label"] = "aria-label";
5761
+ A11yAttribute["Hidden"] = "aria-hidden";
5762
+ A11yAttribute["Current"] = "aria-current";
5763
+ A11yAttribute["Id"] = "id";
5764
+ })(A11yAttribute || (A11yAttribute = {}));
5765
+ /** Every attribute this module may set — what `syncNodeA11yAttributes` owns on an element. */
5766
+ const MANAGED_A11Y_ATTRIBUTES = [
5767
+ A11yAttribute.Label, A11yAttribute.Hidden, A11yAttribute.Current, A11yAttribute.Id,
5768
+ 'aria-haspopup', 'aria-expanded', 'aria-controls', DIALOG_CLOSE_ABOVE_ATTRIBUTE,
5769
+ ];
5770
+ /** A content trait's value from `props` (serialized) or `traits[]` (builder). */
5771
+ function nodeTraitValue(node, name) {
5772
+ if (!node)
5773
+ return undefined;
5774
+ if (node.props && name in node.props)
5775
+ return node.props[name];
5776
+ const traits = node.traits ? (Array.isArray(node.traits) ? node.traits : Object.values(node.traits)) : [];
5777
+ return traits.find(t => t?.name === name)?.default;
5778
+ }
5779
+ /** The min-width (CSS px) above a breakpoint — where a dialog set to "close when wider than" it closes. */
5780
+ function dialogCloseAboveMinWidth(breakpoint) {
5781
+ const max = typeof breakpoint === 'string' ? breakpointDef(breakpoint)?.maxWidth : null;
5782
+ return max == null ? null : max + 1;
5783
+ }
5784
+ /** `(min-width: 768px)` for a min-width carried in `data-iox-dialog-close-above`. */
5785
+ function closeAboveMediaQuery(minWidth) {
5786
+ return `(min-width: ${Number(minWidth)}px)`;
5787
+ }
5788
+ function trimmed$1(v) {
5789
+ return typeof v === 'string' ? v.trim() : '';
5790
+ }
5791
+ /** The attributes a node renders. */
5792
+ function nodeA11yAttributes(node, ctx = {}) {
5793
+ if (!node?.type)
5794
+ return {};
5795
+ const out = {};
5796
+ const name = ACCESSIBLE_NAME_TYPES.includes(node.type) ? trimmed$1(nodeTraitValue(node, A11yTrait.AccessibleName)) : '';
5797
+ if (name)
5798
+ out[A11yAttribute.Label] = name;
5799
+ if (DECORATIVE_TYPES.includes(node.type))
5800
+ out[A11yAttribute.Hidden] = 'true';
5801
+ if (CURRENT_LINK_TYPES.includes(node.type) && isCurrentLink(ctx.href, ctx.currentPath, ctx.currentLink)) {
5802
+ out[A11yAttribute.Current] = ARIA_CURRENT_PAGE;
5803
+ }
5804
+ Object.assign(out, dialogOpenerAttributes(node));
5805
+ if (node.type === DIALOG_NODE_TYPE) {
5806
+ const id = node.styleId ?? node.id;
5807
+ if (id)
5808
+ out[A11yAttribute.Id] = dialogDomId(id);
5809
+ const minWidth = dialogCloseAboveMinWidth(nodeTraitValue(node, A11yTrait.CloseAbove));
5810
+ if (minWidth !== null)
5811
+ out[DIALOG_CLOSE_ABOVE_ATTRIBUTE] = String(minWidth);
5812
+ }
5813
+ return out;
5814
+ }
5815
+ /** The attributes as an HTML string fragment (` name="value"`…) for a string renderer. */
5816
+ function serializeA11yAttributes(attrs, escape) {
5817
+ return Object.entries(attrs).map(([k, v]) => ` ${k}="${escape(v)}"`).join('');
5818
+ }
5819
+ const applied = new WeakMap();
5820
+ /**
5821
+ * Make an element's managed attributes match `attrs` — set what is there, remove what this function
5822
+ * set before and is gone now. An attribute it never set (a component's own `aria-*`) is left alone.
5823
+ */
5824
+ function syncNodeA11yAttributes(el, attrs) {
5825
+ if (!el)
5826
+ return;
5827
+ for (const name of applied.get(el) ?? [])
5828
+ if (!(name in attrs))
5829
+ el.removeAttribute(name);
5830
+ for (const [name, value] of Object.entries(attrs))
5831
+ el.setAttribute(name, value);
5832
+ applied.set(el, Object.keys(attrs).filter(n => MANAGED_A11Y_ATTRIBUTES.includes(n)));
5833
+ }
5834
+ /** The types whose words are the node's own (`content` / `label`), not its children's. */
5835
+ const OWN_WORDS = { Text: 'content', Heading: 'content', Link: 'label', SubmitButton: 'label' };
5836
+ const ICON_TYPE = 'Icon';
5837
+ function scanNames(node, acc) {
5838
+ const prop = node.type ? OWN_WORDS[node.type] : undefined;
5839
+ if (prop && trimmed$1(nodeTraitValue(node, prop)))
5840
+ acc.words = true;
5841
+ if (node.type === ICON_TYPE)
5842
+ acc.icon = true;
5843
+ for (const child of (node.children ?? []))
5844
+ scanNames(child, acc);
5845
+ }
5846
+ /**
5847
+ * True for a control that shows ONLY an icon and has no Accessible name — announced as an unnamed
5848
+ * button or link (WCAG 4.1.2, CC1 N6). The responsive audit flags it; an Icon on its own is decoration.
5849
+ */
5850
+ function needsAccessibleName(node) {
5851
+ if (!node?.type || !ACCESSIBLE_NAME_TYPES.includes(node.type) || node.type === DIALOG_NODE_TYPE)
5852
+ return false;
5853
+ if (trimmed$1(nodeTraitValue(node, A11yTrait.AccessibleName)))
5854
+ return false;
5855
+ const acc = { words: false, icon: false };
5856
+ scanNames(node, acc);
5857
+ return acc.icon && !acc.words;
5858
+ }
5859
+
5860
+ /**
5861
+ * THE interaction keyframes (composite plan T2 · CC1 N5). Both runtimes — the builder's
5862
+ * InteractionEngineService and the live site's ClientInteractionService — animate an element action
5863
+ * from this ONE table. Before it, each kept its own copy and they drifted: `show`/`hide` animated
5864
+ * `visibility` on the canvas and not on the site, and `toggleVisibility` ran 0→1 on the canvas and
5865
+ * 1→0 on the site, so the same hamburger opened on one and closed on the other.
5866
+ *
5867
+ * `toggleVisibility` is stateful: it HIDES a visible element and SHOWS a hidden one
5868
+ * (`resolveToggleVisibility`), and its frames are then exactly `hide`'s or `show`'s. Hidden ends at
5869
+ * `visibility: hidden`, so a hidden element leaves the tab order and the accessibility tree too.
5870
+ * It is still visual-only — the element keeps its box — which is why the actions picker says so and
5871
+ * why the mobile-nav pattern uses a Dialog instead (D9).
5872
+ */
5873
+ /** The attribute a runtime puts on an element an interaction has hidden (and removes on reveal). */
5874
+ const INTERACTION_HIDDEN_ATTRIBUTE = 'data-iox-hidden';
5875
+ var VisibilityActionType;
5876
+ (function (VisibilityActionType) {
5877
+ VisibilityActionType["Show"] = "show";
5878
+ VisibilityActionType["Hide"] = "hide";
5879
+ VisibilityActionType["Toggle"] = "toggleVisibility";
5880
+ })(VisibilityActionType || (VisibilityActionType = {}));
5881
+ /** Actions that reveal an element (hidden → visible). Their FIRST frame is the pre-state. */
5882
+ const ENTRANCE_ACTION_TYPES = new Set(['fadeIn', 'moveUp', 'moveDown', 'moveLeft', 'moveRight', 'scaleIn', VisibilityActionType.Show]);
5883
+ /** Actions that hide an element (visible → hidden). */
5884
+ const EXIT_ACTION_TYPES = new Set(['fadeOut', 'scaleOut', VisibilityActionType.Hide]);
5885
+ const DEFAULT_DISTANCE = 20;
5886
+ const DEFAULT_DEGREES = 360;
5887
+ const SHOWN = { opacity: 1, visibility: 'visible' };
5888
+ const HIDDEN = { opacity: 0, visibility: 'hidden' };
5889
+ /** What `toggleVisibility` does to an element: show it when hidden, hide it when visible. */
5890
+ function resolveToggleVisibility(isHidden) {
5891
+ return isHidden ? VisibilityActionType.Show : VisibilityActionType.Hide;
5892
+ }
5893
+ /** The action a runtime actually plays: `toggleVisibility` resolved against the element's state. */
5894
+ function effectiveActionType(type, isHidden) {
5895
+ return type === VisibilityActionType.Toggle ? resolveToggleVisibility(isHidden) : type;
5896
+ }
5897
+ /**
5898
+ * The keyframes of an animation action, or null for a type that is not an animation (dialogs,
5899
+ * context, navigation…). `toggleVisibility` must be resolved first (`effectiveActionType`); asked
5900
+ * directly it answers with `hide`'s frames, the toggle of an element that starts visible.
5901
+ */
5902
+ function buildInteractionKeyframes(type, params) {
5903
+ const dist = Number(params?.['distance'] ?? DEFAULT_DISTANCE);
5904
+ const deg = Number(params?.['degrees'] ?? DEFAULT_DEGREES);
5905
+ switch (type) {
5906
+ case 'fadeIn': return [{ opacity: 0 }, { opacity: 1 }];
5907
+ case 'fadeOut': return [{ opacity: 1 }, { opacity: 0 }];
5908
+ case 'moveUp': return [{ opacity: 0, transform: `translateY(${dist}px)` }, { opacity: 1, transform: 'translateY(0)' }];
5909
+ case 'moveDown': return [{ opacity: 0, transform: `translateY(-${dist}px)` }, { opacity: 1, transform: 'translateY(0)' }];
5910
+ case 'moveLeft': return [{ opacity: 0, transform: `translateX(${dist}px)` }, { opacity: 1, transform: 'translateX(0)' }];
5911
+ case 'moveRight': return [{ opacity: 0, transform: `translateX(-${dist}px)` }, { opacity: 1, transform: 'translateX(0)' }];
5912
+ case 'scaleIn': return [{ opacity: 0, transform: 'scale(0.8)' }, { opacity: 1, transform: 'scale(1)' }];
5913
+ case 'scaleOut': return [{ opacity: 1, transform: 'scale(1)' }, { opacity: 0, transform: 'scale(0.8)' }];
5914
+ case 'rotate': return [{ transform: 'rotate(0deg)' }, { transform: `rotate(${deg}deg)` }];
5915
+ case VisibilityActionType.Show: return [HIDDEN, SHOWN];
5916
+ case VisibilityActionType.Hide:
5917
+ case VisibilityActionType.Toggle: return [SHOWN, HIDDEN];
5918
+ default: return null;
5919
+ }
5920
+ }
5921
+ /** `translateX` → `translate-x`, `opacity` → `opacity`: the CSS property name of a keyframe key. */
5922
+ function keyframePropertyName(key) {
5923
+ return key.replace(/([A-Z])/g, '-$1').toLowerCase();
5924
+ }
5925
+ /** A keyframe as `[css-property, value]` pairs — what a runtime writes inline. */
5926
+ function keyframeStyleEntries(frame) {
5927
+ return Object.entries(frame ?? {}).map(([k, v]) => [keyframePropertyName(k), String(v)]);
5928
+ }
5929
+ /**
5930
+ * The inline pre-state an ENTRANCE action puts on its element before it plays — its first frame as
5931
+ * CSS — so the server render ships it already hidden (no visible→hidden flash). `{}` for anything else.
5932
+ */
5933
+ function entrancePreStateStyle(type, params) {
5934
+ if (!ENTRANCE_ACTION_TYPES.has(type))
5935
+ return {};
5936
+ return Object.fromEntries(keyframeStyleEntries(buildInteractionKeyframes(type, params)?.[0]));
5937
+ }
5938
+ /** The frame an animation comes to rest on (what reduced motion applies at once). */
5939
+ function finalKeyframe(frames) {
5940
+ return frames?.length ? frames[frames.length - 1] : null;
5941
+ }
5942
+
5602
5943
  /**
5603
5944
  * page-style — the ONE compiler that turns a page's style settings into CSS.
5604
5945
  *
@@ -7523,5 +7864,5 @@ function effectiveTransitionId(anim) {
7523
7864
  * Generated bundle index. Do not edit.
7524
7865
  */
7525
7866
 
7526
- export { AOSService, BACKDROP_TWIN_KEY, BACKDROP_WHOLE_KEY, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CONTAINER_HTML_TAGS, CONTEXT_ACTION_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ContainerComponent, ContextStore, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_PHOSPHOR_WEIGHT, DEFAULT_WIDTH_BY_TYPE, DeclarationContext, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, HOVER_DEFAULT_TRANSITION, HOVER_STATES, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxDialogComponent, IoxFieldComponent, IoxFormComponent, IoxFormErrorComponent, IoxFormSuccessComponent, IoxPageComponent, IoxPageModule, IoxSubmitButtonComponent, IoxUiModule, LEGACY_HOVER_TRANSITION, LinkedContainerComponent, MAX_LINES_KEY, PAGE_STYLE_TOKENS, PAGE_TOKEN_FALLBACKS, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, PageStyleField, PageStyleSource, RESERVED_ALIAS_PREFIX, STATE_PSEUDO_CLASS, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_RESPONSIVE_TRAITS, SectionComponent, TRANSITION_FEELS, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, activeActions, applyBindingPipes, applyFeel, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, composeVirtualTraits, computeRelative, containerHtmlTag, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, decomposeBackdropFilter, defaultHoverTransition, defaultMessageResolver, deriveSeoFromContent, describePageStyle, describeSeoFields, effectiveTransitionId, excludeSelf, feelFor, getByPath, getSeoValue, hasHoverState, hasOwnTransition, initialSlotValues, isActionEnabled, isContextAction, isGradientPaint, isInputOverriddenAt, isOverriddenAt, isReservedAlias, isValidSlotKey, isWholeBackdropSet, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, nearestCommonAncestorId, nodeCssId, nodeUsesContext, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, parentBreakpoint, parseUrlList, partClassName, planDataSource, planResponsiveRules, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resetPageStyleField, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveValueChain, rewriteViewportUnits, safeSetInput, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, stateNamesIn, statePseudoClass, stripSuppressedProps, variableAliases, variableItemsFrom, withContextSlots, withDefaultHoverTransition, wrapInBreakpointQuery, wrapInMediaQuery };
7867
+ export { A11yAttribute, A11yTrait, ACCESSIBLE_NAME_TYPES, AOSService, ARIA_CURRENT_PAGE, BACKDROP_TWIN_KEY, BACKDROP_WHOLE_KEY, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, COMPONENT_STATE_SELECTOR, CONTAINER_HTML_TAGS, CONTEXT_ACTION_TYPES, CURRENT_LINK_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ComponentState, ContainerComponent, ContextStore, DECORATIVE_TYPES, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_PHOSPHOR_WEIGHT, DEFAULT_WIDTH_BY_TYPE, DIALOG_CLOSE_ABOVE_ATTRIBUTE, DIALOG_NODE_TYPE, DeclarationContext, ENTRANCE_ACTION_TYPES, EXIT_ACTION_TYPES, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, HOVER_DEFAULT_TRANSITION, HOVER_STATES, INTERACTION_HIDDEN_ATTRIBUTE, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxDialogComponent, IoxFieldComponent, IoxFormComponent, IoxFormErrorComponent, IoxFormSuccessComponent, IoxPageComponent, IoxPageModule, IoxSubmitButtonComponent, IoxUiModule, LEGACY_HOVER_TRANSITION, LinkedContainerComponent, MANAGED_A11Y_ATTRIBUTES, MAX_LINES_KEY, PAGE_STYLE_TOKENS, PAGE_TOKEN_FALLBACKS, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, PageStyleField, PageStyleSource, REDUCED_MOTION_QUERY, RESERVED_ALIAS_PREFIX, STATE_PSEUDO_CLASS, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_A11Y_OPTIONS, SWIPER_RESPONSIVE_TRAITS, SectionComponent, SwiperModuleName, TRANSITION_FEELS, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, VisibilityActionType, activeActions, applyBindingPipes, applyFeel, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildInteractionKeyframes, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, closeAboveMediaQuery, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, componentStatesFor, composeVirtualTraits, computeRelative, containerHtmlTag, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, decomposeBackdropFilter, defaultHoverTransition, defaultMessageResolver, deriveSeoFromContent, describePageStyle, describeSeoFields, dialogCloseAboveMinWidth, effectiveActionType, effectiveTransitionId, entrancePreStateStyle, excludeSelf, feelFor, finalKeyframe, getByPath, getSeoValue, hasHoverState, hasOwnTransition, initialSlotValues, isActionEnabled, isContextAction, isCurrentLink, isExternalOrFragment, isGradientPaint, isInputOverriddenAt, isOverriddenAt, isReservedAlias, isValidSlotKey, isWholeBackdropSet, keyframePropertyName, keyframeStyleEntries, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, motionAllowed, nearestCommonAncestorId, needsAccessibleName, nodeA11yAttributes, nodeCssId, nodeTraitValue, nodeUsesContext, normalizeAppPath, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, parentBreakpoint, parseUrlList, partClassName, planDataSource, planResponsiveRules, prefersReducedMotion, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resetPageStyleField, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveToggleVisibility, resolveValueChain, rewriteViewportUnits, safeSetInput, serializeA11yAttributes, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, stateNamesIn, statePseudoClass, stateSelectorSuffix, stripSuppressedProps, swiperAutoplayAllowed, swiperModuleNames, syncNodeA11yAttributes, variableAliases, variableItemsFrom, withContextSlots, withDefaultHoverTransition, wrapInBreakpointQuery, wrapInMediaQuery };
7527
7868
  //# sourceMappingURL=vectoriox-iox-ui.mjs.map