@vectoriox/iox-ui 5.31.2 → 5.32.1
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.
- package/actions-core/index.d.ts +52 -2
- package/design-core/index.d.ts +650 -6
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs +69 -1
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +791 -20
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +568 -22
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +365 -24
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/generation-core/index.d.ts +126 -6
- package/index.d.ts +245 -2
- package/package.json +1 -1
- package/src/actions-core/dialog-opener.ts +89 -0
- package/src/actions-core/public-api.ts +1 -0
- package/src/design-core/contrast-audit.ts +11 -2
- package/src/design-core/element-styles.ts +6 -3
- package/src/design-core/flavor-spec.generated.ts +737 -11
- package/src/design-core/node-classes.ts +39 -4
- package/src/generation-core/compose-site.ts +9 -1
- package/src/generation-core/nav-shape.ts +555 -0
- package/src/generation-core/node-baselines.generated.ts +23 -8
- package/src/generation-core/patterns.ts +9 -3
- package/src/generation-core/public-api.ts +1 -0
- package/src/generation-core/serialized-node.ts +2 -1
- package/src/generation-core/site-spec.generated.ts +8 -2
- package/styles/iox-design.css +94 -0
|
@@ -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 {
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
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
|
-
|
|
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
|