@vectoriox/iox-builder 9.8.0 → 9.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,18 +16,20 @@ import { SelectModule } from 'primeng/select';
16
16
  import { TooltipModule } from 'primeng/tooltip';
17
17
  import { DialogModule } from 'primeng/dialog';
18
18
  import * as i1$1 from '@vectoriox/iox-ui';
19
- import { resolveBoundValue, 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, buildPartSelector, planResponsiveRules, resolveStyleProps, targetedStateSelector, stateSelectorSuffix, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, wrapInBreakpointQuery, BreakpointQueryKind, NEW_NODE_STYLE_DEFAULTS, defaultElementStyleFor, applyElementStyle, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, ContextStore, ENTRANCE_ACTION_TYPES, EXIT_ACTION_TYPES, ComponentInstanceRegistryService, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, effectiveActionType, INTERACTION_HIDDEN_ATTRIBUTE, motionAllowed, finalKeyframe, keyframeStyleEntries, buildInteractionKeyframes, declaredInputNames, emptyImagePlaceholder, syncNodeDesignClasses, nodeTraitValue, syncNodeA11yAttributes, nodeA11yAttributes, safeSetInput, colorSchemeOf, composeVirtualTraits, withDefaultHoverTransition, stateNamesIn, partClassName, switchElementStyle, countOverrides, setOverride, breakpointDef, breakpointForWidth, FormRenderState, needsAccessibleName, resolveInputs, setInputOverride, barReserveClass, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, IS_PREVIEW, buttonBlockHref, IoxPageModule, PALETTE_PRESETS, elementStyleById, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
19
+ import { resolveBoundValue, 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, buildPartSelector, planResponsiveRules, resolveStyleProps, targetedStateSelector, stateSelectorSuffix, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, wrapInBreakpointQuery, BreakpointQueryKind, NEW_NODE_STYLE_DEFAULTS, defaultElementStyleFor, applyElementStyle, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, ContextStore, ENTRANCE_ACTION_TYPES, EXIT_ACTION_TYPES, ComponentInstanceRegistryService, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, effectiveActionType, INTERACTION_HIDDEN_ATTRIBUTE, motionAllowed, finalKeyframe, keyframeStyleEntries, buildInteractionKeyframes, 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, IS_PREVIEW, buttonBlockHref, bootSlider, IoxPageModule, PALETTE_PRESETS, elementStyleById, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
20
20
  export { ComponentInstanceRegistryService, VIRTUAL_TRAIT_KEYS, composeVirtualTraits } from '@vectoriox/iox-ui';
21
- import { structureRefusal, StructureEdit, isAccordionPart, AccordionRole, CompositeBehaviourTrait, ACCORDION_DEFAULT_ONS, onAccordionItemState, isAccordionItemOn, AccordionRuntime, accordionBehaviour, closestAccordionItem, isAccordionRoot, buildCardRecipe, buildBadge, buildChip, buildAccordionRecipe, accordionItemLabel, isLockedPart, accordionRootOf, isAccordionFromContent, accordionItemOf, addAccordionItem, accordionHeadingLevel } from '@vectoriox/iox-ui/composite-core';
21
+ import { StructureEdit, isAccordionPart, isDisclosurePart, isSliderPart, structureRefusal, AccordionRole, CompositeBehaviourTrait, ACCORDION_DEFAULT_ONS, onAccordionItemState, isAccordionItemOn, runCompositeItemAction, shouldScrollToItem, rowIndexOf as rowIndexOf$1, slideIndexForRow, DisclosureRole, AccordionRuntime, accordionBehaviour, compositeScopeId, compositeRowKeys, compositeKindOfRole, closestAccordionItem, isCompositeRoot, isAccordionRoot, buildCardRecipe, buildBadge, buildChip, buildAccordionRecipe, buildDisclosureRecipe, buildLightboxRecipe, NO_ELEMENT_STYLE, CompositeKind, SliderRole, accordionItemLabel, isLockedPart, accordionRootOf, isAccordionFromContent, accordionItemOf, addAccordionItem, isCompositeItem, accordionHeadingLevel, isCompositePanel, isCompositeTrigger, splitSliderChildren, hasSliderParts } from '@vectoriox/iox-ui/composite-core';
22
22
  import { Subject, BehaviorSubject, of, forkJoin } from 'rxjs';
23
23
  import interact from 'interactjs';
24
24
  import { formContentInHost, isInteractiveHost, findFormContentInHosts } from '@vectoriox/iox-ui/forms-core';
25
25
  import { map, catchError } from 'rxjs/operators';
26
26
  import * as i1 from '@angular/common/http';
27
- import { BEHAVIOUR_ACTION_TYPES, SERVER_ELEMENT_ACTION_TYPES, CONSENT_ACTION_TYPES } from '@vectoriox/iox-ui/actions-core';
27
+ import { itemActionOf, BEHAVIOUR_ACTION_TYPES, SERVER_ELEMENT_ACTION_TYPES, CONSENT_ACTION_TYPES, opensAtClickedItem } from '@vectoriox/iox-ui/actions-core';
28
28
  import Lenis from 'lenis';
29
29
  import Moveable from 'moveable';
30
30
  import Selecto from 'selecto';
31
+ import { planVideo, VideoSource, VIDEO_PROVIDER_LABEL, VideoTrait, VideoMode } from '@vectoriox/iox-ui/media-core';
32
+ import { ConsentCategory } from '@vectoriox/iox-ui/consent-core';
31
33
 
32
34
  var PanelEventTypes;
33
35
  (function (PanelEventTypes) {
@@ -176,6 +178,10 @@ const IOX_BUILDER_LABELS = new InjectionToken('IOX_BUILDER_LABELS', {
176
178
  providedIn: 'root',
177
179
  factory: () => defaultBuilderLabels,
178
180
  });
181
+ const IOX_CONTENT_TYPE_LABELS = new InjectionToken('IOX_CONTENT_TYPE_LABELS', {
182
+ providedIn: 'root',
183
+ factory: () => () => null,
184
+ });
179
185
  /** Standalone behaviour: the English text the library ships with. */
180
186
  const defaultBuilderLabels = (_key, fallback) => fallback;
181
187
  /**
@@ -207,11 +213,20 @@ const BUILDER_CHROME_EN = Object.freeze({
207
213
  'builder.chrome.compositeRole': 'Composite role',
208
214
  'builder.chrome.kindCard': 'Card',
209
215
  'builder.chrome.kindAccordion': 'Accordion',
216
+ 'builder.chrome.kindDisclosure': 'Disclosure',
217
+ 'builder.chrome.kindSlider': 'Slider',
218
+ 'builder.chrome.kindVideo': 'Video',
219
+ 'builder.chrome.videoPosterOnly': 'poster only',
220
+ 'builder.chrome.videoFile': 'Uploaded file',
221
+ 'builder.chrome.refuseLockedSliderPartMove': 'This control belongs to its slider — it can’t be moved out.',
222
+ 'builder.chrome.refuseLockedSliderPause': 'The pause button stays while Autoplay is on — moving content must be pausable. Turn Autoplay off in the slider’s Bindings to remove it.',
223
+ 'builder.chrome.refuseLockedDisclosurePart': 'A disclosure keeps its toggle and its panel. Delete the whole disclosure instead.',
224
+ 'builder.chrome.refuseLockedDisclosurePartMove': 'This part belongs to its disclosure — it can’t be moved out.',
210
225
  'builder.chrome.refuseLockedItemPart': 'An item keeps its header and its panel. Delete the whole item, or the accordion.',
211
226
  'builder.chrome.refuseLockedItemPartMove': 'This part belongs to its item — it can’t be moved out.',
212
227
  'builder.chrome.refuseLastItem': 'An accordion keeps at least one item. Delete the whole accordion instead.',
213
228
  'builder.chrome.addItem': 'Add item',
214
- 'builder.chrome.fromContent': 'From {alias} · {count} rows',
229
+ 'builder.chrome.fromContent': 'From {source} · {count} rows',
215
230
  'builder.chrome.emptySource': 'No rows in “{alias}”.',
216
231
  'builder.chrome.emptySourceHint': 'The {type} content type has no published items that match this source’s filters. Add items in Content ▸ {type}, or change the source.',
217
232
  'builder.chrome.fromRow': 'row {row} — every row wears this part',
@@ -244,6 +259,20 @@ const CANVAS_EMPTY_IMAGE_LABEL_EN = BUILDER_CHROME_EN[CANVAS_EMPTY_IMAGE_LABEL_K
244
259
  */
245
260
  const EDITOR_CHROME_ATTRIBUTE = 'data-iox-chrome';
246
261
 
262
+ /** The content type a data source reads (`faqs`), or '' for a source that reads none (external, static). */
263
+ function sourceContentType(ds) {
264
+ return ds?.request?.cms?.contentType || ds?.request?.shop?.contentType || '';
265
+ }
266
+ /**
267
+ * What the builder's chrome calls the list a source reads — the CONTENT TYPE's label ("From FAQ", board 3), as the
268
+ * host knows it (`IOX_CONTENT_TYPE_LABELS`), else the source's alias. ONE answer for the layer tree's
269
+ * "From FAQ · 3 rows", the Repeater's empty-source hint and the Items section's source options.
270
+ */
271
+ function sourceTypeLabel(alias, ds, resolve) {
272
+ const type = sourceContentType(ds);
273
+ return (type && resolve(type)) || alias;
274
+ }
275
+
247
276
  const freshId = () => Math.random().toString(36).substr(2, 9);
248
277
  /**
249
278
  * Assign fresh ids to a cloned ComponentNode subtree AND remap intra-subtree references to the
@@ -445,6 +474,14 @@ var InsertRefusal;
445
474
  InsertRefusal["LockedItemPart"] = "lockedItemPart";
446
475
  /** An accordion's LAST item (composite plan T11): it keeps at least one. */
447
476
  InsertRefusal["LastItem"] = "lastItem";
477
+ /** A disclosure's toggle or panel (CC2.1) moved out of it. */
478
+ InsertRefusal["LockedDisclosurePartMove"] = "lockedDisclosurePartMove";
479
+ /** A disclosure's toggle or panel (CC2.1) deleted on its own. */
480
+ InsertRefusal["LockedDisclosurePart"] = "lockedDisclosurePart";
481
+ /** A Slider's control (CC3) works only as its own direct child. */
482
+ InsertRefusal["LockedSliderPartMove"] = "lockedSliderPartMove";
483
+ /** The pause control stays while Autoplay is on (WCAG 2.2.2) — the Autoplay switch removes it. */
484
+ InsertRefusal["LockedSliderPause"] = "lockedSliderPause";
448
485
  })(InsertRefusal || (InsertRefusal = {}));
449
486
  const FORM_STATE_BLOCK_TYPES = new Set(['FormSuccess', 'FormError']);
450
487
  /** The builder-chrome label that says each refusal on screen (English in `BUILDER_CHROME_EN`). */
@@ -457,7 +494,22 @@ const INSERT_REFUSAL_LABEL_KEYS = Object.freeze({
457
494
  [InsertRefusal.LockedItemPartMove]: 'builder.chrome.refuseLockedItemPartMove',
458
495
  [InsertRefusal.LockedItemPart]: 'builder.chrome.refuseLockedItemPart',
459
496
  [InsertRefusal.LastItem]: 'builder.chrome.refuseLastItem',
497
+ [InsertRefusal.LockedDisclosurePartMove]: 'builder.chrome.refuseLockedDisclosurePartMove',
498
+ [InsertRefusal.LockedDisclosurePart]: 'builder.chrome.refuseLockedDisclosurePart',
499
+ [InsertRefusal.LockedSliderPartMove]: 'builder.chrome.refuseLockedSliderPartMove',
500
+ [InsertRefusal.LockedSliderPause]: 'builder.chrome.refuseLockedSliderPause',
460
501
  });
502
+ /** Which refusal says a locked part's move / delete, by the composite it belongs to (a card's is the default). */
503
+ function lockedRefusal(node, edit) {
504
+ const move = edit === StructureEdit.Move;
505
+ if (isAccordionPart(node))
506
+ return move ? InsertRefusal.LockedItemPartMove : InsertRefusal.LockedItemPart;
507
+ if (isDisclosurePart(node))
508
+ return move ? InsertRefusal.LockedDisclosurePartMove : InsertRefusal.LockedDisclosurePart;
509
+ if (isSliderPart(node))
510
+ return move ? InsertRefusal.LockedSliderPartMove : InsertRefusal.LockedSliderPause;
511
+ return move ? InsertRefusal.LockedPartMove : InsertRefusal.LockedPart;
512
+ }
461
513
  /** The refusal in the host's language (the library's English when no host resolver is provided). */
462
514
  function insertRefusalLabel(reason, labels = defaultBuilderLabels) {
463
515
  const key = INSERT_REFUSAL_LABEL_KEYS[reason];
@@ -484,7 +536,7 @@ function insertRefusal(node, ancestors) {
484
536
  if (formContentInHost(node, ancestors.some(isInteractiveHost)))
485
537
  return InsertRefusal.FormInInteractive;
486
538
  if (structureRefusal(node, StructureEdit.Move, ancestors))
487
- return isAccordionPart(node) ? InsertRefusal.LockedItemPartMove : InsertRefusal.LockedPartMove;
539
+ return lockedRefusal(node, StructureEdit.Move);
488
540
  return null;
489
541
  }
490
542
  /** Why `node` may not be REMOVED from where it is (deleted, cut, made global), or null when it may: a
@@ -492,7 +544,7 @@ function insertRefusal(node, ancestors) {
492
544
  * accordion keeps its last item. `siblings` = the list `node` sits in (where the caller has it). */
493
545
  function removalRefusal(node, siblings) {
494
546
  if (structureRefusal(node, StructureEdit.Delete))
495
- return isAccordionPart(node) ? InsertRefusal.LockedItemPart : InsertRefusal.LockedPart;
547
+ return lockedRefusal(node, StructureEdit.Delete);
496
548
  if (node?.role === AccordionRole.Item && siblings && siblings.filter(s => s?.role === AccordionRole.Item).length <= 1)
497
549
  return InsertRefusal.LastItem;
498
550
  return null;
@@ -600,6 +652,8 @@ const INVERSE_ACTION = {
600
652
  clearContext: 'setContext',
601
653
  openDialog: 'closeDialog',
602
654
  closeDialog: 'openDialog',
655
+ openItem: 'closeItem',
656
+ closeItem: 'openItem',
603
657
  };
604
658
  const TRIGGER_OPTIONS = [
605
659
  { value: 'pageLoad', label: 'Page load', icon: 'ph-thin ph-play' },
@@ -3679,8 +3733,11 @@ class InteractionEngineService {
3679
3733
  this.runActions(node, ix.actions, element);
3680
3734
  }
3681
3735
  };
3682
- element.addEventListener('click', handler);
3683
- return () => element.removeEventListener('click', handler);
3736
+ // CAPTURE, like the composite runtime: on the canvas every part's own listener stops the click to select
3737
+ // that part, so a click on a button's LABEL never bubbled to the button's click interaction — the live
3738
+ // site runs it (CC2.1: "Open an item" on a ButtonBlock did nothing on the canvas).
3739
+ element.addEventListener('click', handler, true);
3740
+ return () => element.removeEventListener('click', handler, true);
3684
3741
  }
3685
3742
  attachHover(node, ix, element) {
3686
3743
  const enterHandler = () => this.runActions(node, ix.actions, element);
@@ -3721,7 +3778,14 @@ class InteractionEngineService {
3721
3778
  // impossible. The canvas twin registered open/close/toggle under its nodeId, exactly
3722
3779
  // the Swiper-method pattern; a missing/mistargeted id is a silent no-op, never a throw.
3723
3780
  if (DIALOG_ACTION_TYPES.has(action.type)) {
3724
- this.executeDialogAction(action);
3781
+ this.executeDialogAction(action, selfEl);
3782
+ continue;
3783
+ }
3784
+ // Item actions (CC2.1 — composite T14): the canvas RUNS them on the target item's own runtime — the
3785
+ // one the live site runs — and brings an item that opened out of view into it.
3786
+ const itemAction = itemActionOf(action.type);
3787
+ if (itemAction) {
3788
+ this.executeItemAction(node, action, itemAction, selfEl);
3725
3789
  continue;
3726
3790
  }
3727
3791
  // Tier-A behaviour (A1c). The canvas-is-live rules are catalog DATA
@@ -3819,6 +3883,14 @@ class InteractionEngineService {
3819
3883
  }
3820
3884
  }
3821
3885
  }
3886
+ executeItemAction(node, action, itemAction, selfEl) {
3887
+ const target = this.resolveTarget(node, action, selfEl);
3888
+ const open = runCompositeItemAction(target, itemAction);
3889
+ if (!open || !target)
3890
+ return;
3891
+ if (shouldScrollToItem(target.getBoundingClientRect().top, window.innerHeight))
3892
+ target.scrollIntoView({ behavior: 'smooth', block: 'start' });
3893
+ }
3822
3894
  executeConsentAction(action) {
3823
3895
  if (action.type === 'openConsentPreferences') {
3824
3896
  const dialog = action.target && action.target !== 'self' ? this.instanceRegistry.get(action.target) : null;
@@ -3828,13 +3900,17 @@ class InteractionEngineService {
3828
3900
  const detail = { type: action.type, params: action.params ?? {}, target: action.target };
3829
3901
  window.dispatchEvent(new CustomEvent('iox-action-simulated', { detail }));
3830
3902
  }
3831
- executeDialogAction(action) {
3903
+ executeDialogAction(action, selfEl) {
3832
3904
  const dialog = action.target && action.target !== 'self' ? this.instanceRegistry.get(action.target) : null;
3833
3905
  if (!dialog)
3834
3906
  return;
3835
3907
  switch (action.type) {
3836
3908
  case 'openDialog':
3837
3909
  dialog.open?.();
3910
+ // CC3 "Open at the clicked item": the lightbox's slider goes to the clicked row's slide — the same
3911
+ // rule the live site runs (composite-core `slideIndexForRow`), once the canvas twin has rendered it.
3912
+ if (opensAtClickedItem(action))
3913
+ this.slideDialogToRow(action.target, rowIndexOf$1(selfEl));
3838
3914
  break;
3839
3915
  case 'closeDialog':
3840
3916
  dialog.close?.();
@@ -3844,6 +3920,22 @@ class InteractionEngineService {
3844
3920
  break;
3845
3921
  }
3846
3922
  }
3923
+ /** The slider inside the opened dialog (its canvas twin renders on the next passes) → the row's slide. */
3924
+ slideDialogToRow(dialogId, row) {
3925
+ let tries = 0;
3926
+ const attempt = () => {
3927
+ const host = document.querySelector(`.iox-node-${CSS.escape(dialogId)}`);
3928
+ const swiper = host?.querySelector('.swiper')?.swiper;
3929
+ if (swiper?.slides?.length) {
3930
+ swiper.update?.();
3931
+ swiper.slideTo(slideIndexForRow(row, swiper.slides.length), 0);
3932
+ return;
3933
+ }
3934
+ if (++tries < 40)
3935
+ requestAnimationFrame(attempt);
3936
+ };
3937
+ requestAnimationFrame(attempt);
3938
+ }
3847
3939
  executeSwiperAction(action) {
3848
3940
  // Target is the nodeId of the SliderContainer to control.
3849
3941
  const swiper = this.instanceRegistry.get(action.target);
@@ -4006,10 +4098,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
4006
4098
  * screen until something opens them, so on the canvas they show only while selected into or switched
4007
4099
  * open ("Showing on canvas"). The layer tree marks them with the eye-slash glyph. A Dialog (the mobile
4008
4100
  * menu's drawer, a consent banner) by its type; an Accordion's PANEL by its role (CC2 — closed until its
4009
- * item opens). An inactive tab joins in CC4.
4101
+ * item opens); a Disclosure's panel and its "Read less" word (CC2.1 — shown only while it is open). An inactive
4102
+ * tab joins in CC4.
4010
4103
  */
4011
4104
  const HIDDEN_AT_REST_TYPES = ['Dialog'];
4012
- const HIDDEN_AT_REST_ROLES = [AccordionRole.Panel];
4105
+ const HIDDEN_AT_REST_ROLES = [AccordionRole.Panel, DisclosureRole.Panel, DisclosureRole.Less];
4013
4106
  function isHiddenAtRest(node) {
4014
4107
  return (!!node?.type && HIDDEN_AT_REST_TYPES.includes(node.type)) || (!!node?.role && HIDDEN_AT_REST_ROLES.includes(node.role));
4015
4108
  }
@@ -4025,8 +4118,14 @@ var SelectionReveal;
4025
4118
  SelectionReveal["WhileSelected"] = "while-selected";
4026
4119
  SelectionReveal["UntilClosed"] = "until-closed";
4027
4120
  })(SelectionReveal || (SelectionReveal = {}));
4121
+ /**
4122
+ * Parts hidden at rest that live in a composite's TOGGLE, not in its panel (CC2.1 follow-up, approved 2026-10-21): a
4123
+ * click on one on the canvas toggles the composite live — selecting it never forces the reveal, so "Read less"
4124
+ * closes the disclosure it was clicked in. Only a part inside a PANEL is revealed by the selection.
4125
+ */
4126
+ const TOGGLE_PART_ROLES = [DisclosureRole.Less];
4028
4127
  function selectionRevealOf(node) {
4029
- if (!isHiddenAtRest(node))
4128
+ if (!isHiddenAtRest(node) || (!!node?.role && TOGGLE_PART_ROLES.includes(node.role)))
4030
4129
  return null;
4031
4130
  return node?.role ? SelectionReveal.WhileSelected : SelectionReveal.UntilClosed;
4032
4131
  }
@@ -4145,10 +4244,17 @@ function sameSet(a, b) {
4145
4244
  return a.size === b.size && [...a].every(id => b.has(id));
4146
4245
  }
4147
4246
 
4247
+ /** The node whose "Showing on canvas" choice a rendered root follows: itself, or — a preview row's copy — its
4248
+ * template (a copy shares its template's style id). */
4249
+ function designIdOf(node) {
4250
+ return node.__previewClone ? (node.styleId ?? node.id) : node.id;
4251
+ }
4148
4252
  /**
4149
- * The composites' runtime ON THE CANVAS (CC2) — the canvas is a live runtime, so an Accordion opens and
4150
- * closes on the canvas exactly as on the site: the SAME composite-core `AccordionRuntime` the live engine
4151
- * attaches. On top of the live state it shows what the author is designing (R2, CC1's design state):
4253
+ * The composites' runtime ON THE CANVAS (CC2) — the canvas is a live runtime, so an Accordion (and a Disclosure,
4254
+ * CC2.1) opens and closes on the canvas exactly as on the site: the SAME composite-core `AccordionRuntime` the live
4255
+ * engine attaches. A composite repeated in a Repeater's preview rows runs one per row, each with its own ARIA ids
4256
+ * (its row folded into the scope id — vectoriox/iox-ui#20). On top of the live state it shows what the author is
4257
+ * designing (R2, CC1's design state):
4152
4258
  * - selecting anything inside a CLOSED panel (canvas, tree, crumb, an Items row, SELECT_NODE) opens its item
4153
4259
  * while it is selected, and deselecting closes it again;
4154
4260
  * - "Showing on canvas ▸ All open" opens every item; "As saved" goes back to the saved default.
@@ -4166,18 +4272,21 @@ class CompositeCanvasService {
4166
4272
  for (const id of [...this.attached.keys()])
4167
4273
  this.detach(id);
4168
4274
  }
4169
- /** An accordion root rendered on the canvas: run it. `element` is the root's rendered element. */
4275
+ /** A composite root rendered on the canvas (the template, or a preview row's copy): run it. `element` is the
4276
+ * root's rendered element. Its ARIA ids are scoped by the preview rows it sits in. */
4170
4277
  attach(node, element) {
4171
4278
  if (!node.id)
4172
4279
  return;
4173
4280
  this.detach(node.id);
4281
+ const cssId = node.styleId ?? node.id;
4174
4282
  const runtime = this.zone.runOutsideAngular(() => new AccordionRuntime(element, {
4175
- rootId: node.styleId ?? node.id,
4283
+ kind: compositeKindOfRole(node.role) ?? undefined,
4284
+ rootId: () => compositeScopeId(cssId, compositeRowKeys(element)),
4176
4285
  behaviour: accordionBehaviour(node),
4177
4286
  observe: true,
4178
4287
  forced: () => this.forcedFor(node, element),
4179
4288
  }));
4180
- this.attached.set(node.id, { node, runtime, shown: this.designState?.shownState(node.id) ?? CanvasShowState.Closed });
4289
+ this.attached.set(node.id, { node, runtime, shown: this.designState?.shownState(designIdOf(node)) ?? CanvasShowState.Closed });
4181
4290
  }
4182
4291
  detach(nodeId) {
4183
4292
  if (!nodeId)
@@ -4195,8 +4304,8 @@ class CompositeCanvasService {
4195
4304
  return (nodeId && this.attached.get(nodeId)?.runtime) || null;
4196
4305
  }
4197
4306
  applyDesignState() {
4198
- for (const [id, entry] of this.attached) {
4199
- const shown = this.designState?.shownState(id) ?? CanvasShowState.Closed;
4307
+ for (const entry of this.attached.values()) {
4308
+ const shown = this.designState?.shownState(designIdOf(entry.node)) ?? CanvasShowState.Closed;
4200
4309
  // Back to "As saved": the saved default, whatever the author clicked open meanwhile (board 3).
4201
4310
  if (shown !== entry.shown && shown === CanvasShowState.Closed)
4202
4311
  entry.runtime.resetLive();
@@ -4206,7 +4315,8 @@ class CompositeCanvasService {
4206
4315
  }
4207
4316
  }
4208
4317
  /** The keys the design state holds open: every item ("All open"), or the items whose hidden part the
4209
- * selection sits in. A preview row shares its template's classes, so the template (row 1) answers. */
4318
+ * selection sits in. A preview row shares its template's classes, so the template (row 1) answers — and a
4319
+ * composite copied into a preview row follows its template's choice. */
4210
4320
  forcedFor(node, root) {
4211
4321
  const forced = new Set();
4212
4322
  const state = this.designState;
@@ -4214,7 +4324,7 @@ class CompositeCanvasService {
4214
4324
  return forced;
4215
4325
  const runtime = this.attached.get(node.id)?.runtime;
4216
4326
  const items = runtime?.items() ?? [];
4217
- if (state.shownState(node.id) === CanvasShowState.Open) {
4327
+ if (state.shownState(designIdOf(node)) === CanvasShowState.Open) {
4218
4328
  for (const item of items)
4219
4329
  forced.add(runtime.keyOf(item, items));
4220
4330
  return forced;
@@ -4735,8 +4845,10 @@ class RenderDirective {
4735
4845
  this.overlayService.triggerContextMenu(event.clientX, event.clientY);
4736
4846
  });
4737
4847
  }
4738
- // A composite root runs its behaviour on the canvas — the live site's runtime (CC2).
4739
- if (nativeEl && !isPreviewClone && node.id && isAccordionRoot(node) && this.compositeCanvas) {
4848
+ // A composite root runs its behaviour on the canvas — the live site's runtime (CC2; the Disclosure, CC2.1).
4849
+ // A preview row's copy runs too, scoped by its row (vectoriox/iox-ui#20): its ids are its own and it shows
4850
+ // the saved default, as every row does on the live site.
4851
+ if (nativeEl && node.id && isCompositeRoot(node) && this.compositeCanvas) {
4740
4852
  this.compositeCanvas.attach(node, nativeEl);
4741
4853
  this.compositeRootId = node.id;
4742
4854
  }
@@ -4859,6 +4971,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
4859
4971
 
4860
4972
  const EMPTY_SOURCE_KEY = 'builder.chrome.emptySource';
4861
4973
  const EMPTY_SOURCE_HINT_KEY = 'builder.chrome.emptySourceHint';
4974
+ const NO_TYPE_LABELS = () => null;
4862
4975
  class BuilderRepeaterComponent {
4863
4976
  get children() { return this._children; }
4864
4977
  /** RenderDirective sets `source` (→ fetchData) BEFORE `children`. With an async source the response
@@ -4880,8 +4993,9 @@ class BuilderRepeaterComponent {
4880
4993
  get emptySourceTitle() {
4881
4994
  return this.label(EMPTY_SOURCE_KEY).replace('{alias}', this._source);
4882
4995
  }
4996
+ /** "The FAQ content type has no published items…" — the type's LABEL (board 4), else the alias. */
4883
4997
  get emptySourceHint() {
4884
- const type = this.dsRegistry.findByAlias(this._source)?.request?.cms?.contentType ?? this._source;
4998
+ const type = sourceTypeLabel(this._source, this.dsRegistry.findByAlias(this._source), this.typeLabels ?? NO_TYPE_LABELS);
4885
4999
  return this.label(EMPTY_SOURCE_HINT_KEY).split('{type}').join(type);
4886
5000
  }
4887
5001
  label(key) {
@@ -4921,7 +5035,7 @@ class BuilderRepeaterComponent {
4921
5035
  this.fetchData();
4922
5036
  }
4923
5037
  }
4924
- constructor(dragEngine, overlayService, dataSourceService, dsRegistry, panelEventService, cdr, interactionEngine, labels) {
5038
+ constructor(dragEngine, overlayService, dataSourceService, dsRegistry, panelEventService, cdr, interactionEngine, labels, typeLabels) {
4925
5039
  this.dragEngine = dragEngine;
4926
5040
  this.overlayService = overlayService;
4927
5041
  this.dataSourceService = dataSourceService;
@@ -4930,6 +5044,7 @@ class BuilderRepeaterComponent {
4930
5044
  this.cdr = cdr;
4931
5045
  this.interactionEngine = interactionEngine;
4932
5046
  this.labels = labels;
5047
+ this.typeLabels = typeLabels;
4933
5048
  this._children = [];
4934
5049
  this.style = {};
4935
5050
  this.nodeId = '';
@@ -5070,7 +5185,7 @@ class BuilderRepeaterComponent {
5070
5185
  if (this.items.length)
5071
5186
  setTimeout(() => this.refreshPreviews());
5072
5187
  }
5073
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderRepeaterComponent, deps: [{ token: DragEngineService }, { token: OverlayService }, { token: BuilderDataSourceService }, { token: DataSourceRegistryService }, { token: PanelEventService }, { token: i0.ChangeDetectorRef }, { token: InteractionEngineService }, { token: IOX_BUILDER_LABELS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
5188
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: BuilderRepeaterComponent, deps: [{ token: DragEngineService }, { token: OverlayService }, { token: BuilderDataSourceService }, { token: DataSourceRegistryService }, { token: PanelEventService }, { token: i0.ChangeDetectorRef }, { token: InteractionEngineService }, { token: IOX_BUILDER_LABELS, optional: true }, { token: IOX_CONTENT_TYPE_LABELS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
5074
5189
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: BuilderRepeaterComponent, isStandalone: false, selector: "app-builder-repeater", inputs: { children: "children", style: "style", nodeId: "nodeId", dropListId: "dropListId", source: "source", sourcePath: "sourcePath", limit: "limit" }, outputs: { childClick: "childClick", childMouseEnter: "childMouseEnter", childMouseLeave: "childMouseLeave" }, ngImport: i0, template: `
5075
5190
  <ng-template #badgeContent>
5076
5191
  <i class="ph-thin ph-repeat"></i>
@@ -5261,6 +5376,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
5261
5376
  }, {
5262
5377
  type: Inject,
5263
5378
  args: [IOX_BUILDER_LABELS]
5379
+ }] }, { type: undefined, decorators: [{
5380
+ type: Optional
5381
+ }, {
5382
+ type: Inject,
5383
+ args: [IOX_CONTENT_TYPE_LABELS]
5264
5384
  }] }], propDecorators: { children: [{
5265
5385
  type: Input
5266
5386
  }], style: [{
@@ -5294,9 +5414,11 @@ var CompositePresetId;
5294
5414
  CompositePresetId["Badge"] = "badge";
5295
5415
  CompositePresetId["Chip"] = "chip";
5296
5416
  CompositePresetId["Accordion"] = "accordion";
5417
+ CompositePresetId["Disclosure"] = "disclosure";
5418
+ CompositePresetId["Lightbox"] = "lightbox";
5297
5419
  })(CompositePresetId || (CompositePresetId = {}));
5298
5420
  /** Where a composite sits in the Components panel (composite plan §6d): content blocks, or the interactive
5299
- * composites (the Accordion — CC2; Tabs and the floating family later). */
5421
+ * composites (the Accordion — CC2, the Disclosure — CC2.1; Tabs and the floating family later). */
5300
5422
  var CompositePaletteGroup;
5301
5423
  (function (CompositePaletteGroup) {
5302
5424
  CompositePaletteGroup["ContentBlocks"] = "content-blocks";
@@ -5323,6 +5445,16 @@ const COMPOSITE_PRESETS = Object.freeze([
5323
5445
  description: 'Questions that open — three items, one open at a time. Every header, icon and panel is its own element.',
5324
5446
  build: create => buildAccordionRecipe(create),
5325
5447
  },
5448
+ {
5449
+ id: CompositePresetId.Disclosure, group: CompositePaletteGroup.Interactive, name: 'Disclosure', icon: 'ph-thin ph-caret-circle-down',
5450
+ description: '"Read more" — a button that reveals the text below it and reads "Read less" while it is open.',
5451
+ build: create => buildDisclosureRecipe(create),
5452
+ },
5453
+ {
5454
+ id: CompositePresetId.Lightbox, group: CompositePaletteGroup.Interactive, name: 'Lightbox', icon: 'ph-thin ph-frame-corners',
5455
+ description: 'A full-screen dialog with a slider — bind its slider to your gallery\'s source, and each thumbnail opens it at its own image.',
5456
+ build: create => buildLightboxRecipe(create),
5457
+ },
5326
5458
  ]);
5327
5459
  /**
5328
5460
  * The builder's node factory for composite-core recipes: a NEW node as the palette creates one
@@ -5342,6 +5474,11 @@ function builderCompositeFactory(createConfig, baselineStyles) {
5342
5474
  if (spec.elementStyle && spec.elementStyle !== node.elementStyle) {
5343
5475
  switchElementStyle(node, node.elementStyle, spec.elementStyle, baselineStyles(spec.type));
5344
5476
  }
5477
+ else if (spec.elementStyle === NO_ELEMENT_STYLE && node.elementStyle) {
5478
+ // NO_ELEMENT_STYLE asks for no style (undefined / null keep the type's default): a migrated slider's bare
5479
+ // chevrons, a lightbox's slide (CC3).
5480
+ releaseElementStyle(node, node.elementStyle, baselineStyles(spec.type));
5481
+ }
5345
5482
  if (node.children)
5346
5483
  node.children = [];
5347
5484
  return node;
@@ -6768,13 +6905,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
6768
6905
  * breadcrumb and the tree row's sub-label share these, so the four surfaces never disagree (board 3: "The
6769
6906
  * four surfaces, all driven by the same selection").
6770
6907
  *
6771
- * An accordion's parts are named by the part alone (`trigger`, "Accordion · trigger", board 3); a card keeps
6772
- * its full role (`card.title`, "Card · card.title", board 8).
6908
+ * An accordion's and a disclosure's parts are named by the part alone (`trigger`, "Accordion · trigger", board 3);
6909
+ * a card keeps its full role (`card.title`, "Card · card.title", board 8).
6773
6910
  */
6774
- const SHORT_ROLE_KINDS = new Set(['accordion']);
6911
+ const SHORT_ROLE_KINDS = new Set([CompositeKind.Accordion, CompositeKind.Disclosure]);
6775
6912
  /** A composite kind's glyph (Phosphor, weight-less): the badge, the root's crumb and its tree row carry it
6776
6913
  * (board 3: "the composite root carrying its kind icon"). A card keeps the generic stack glyph. */
6777
- const KIND_GLYPHS = { accordion: 'ph-rows' };
6914
+ const KIND_GLYPHS = { [CompositeKind.Accordion]: 'ph-rows', [CompositeKind.Disclosure]: 'ph-caret-circle-down', slider: 'ph-slideshow' };
6778
6915
  const DEFAULT_KIND_GLYPH = 'ph-stack';
6779
6916
  /** The tree icon of an accordion's structural parts (board 3): rows on the root, a stack on an item and a
6780
6917
  * panel, a cursor on the header, a sparkle on the icon. Other parts keep their type's icon. */
@@ -6784,6 +6921,17 @@ const PART_ICONS = {
6784
6921
  [AccordionRole.Trigger]: 'ph-thin ph-cursor',
6785
6922
  [AccordionRole.Panel]: 'ph-thin ph-stack',
6786
6923
  [AccordionRole.Icon]: 'ph-thin ph-sparkle',
6924
+ // CC2.1 — the disclosure follows the accordion's drawn conventions (board 3): its kind glyph on the root, a
6925
+ // cursor on its toggle, a stack on its panel, a sparkle on its icon; its two words keep the Text icon.
6926
+ [DisclosureRole.Disclosure]: 'ph-thin ph-caret-circle-down',
6927
+ [DisclosureRole.Trigger]: 'ph-thin ph-cursor',
6928
+ [DisclosureRole.Panel]: 'ph-thin ph-stack',
6929
+ [DisclosureRole.Icon]: 'ph-thin ph-sparkle',
6930
+ // CC3 — a Slider's controls (board 6): a cursor on the buttons, six dots on the pagination.
6931
+ [SliderRole.Pause]: 'ph-thin ph-cursor',
6932
+ [SliderRole.Prev]: 'ph-thin ph-cursor',
6933
+ [SliderRole.Next]: 'ph-thin ph-cursor',
6934
+ [SliderRole.Pagination]: 'ph-thin ph-dots-six',
6787
6935
  };
6788
6936
  /** The glyph of a role's composite kind (`ph-rows` for an accordion and its parts). */
6789
6937
  function compositeKindGlyph(role) {
@@ -6868,7 +7016,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
6868
7016
  const FROM_ROW_KEY = 'builder.chrome.fromRow';
6869
7017
  const ADD_ITEM_KEY = 'builder.chrome.addItem';
6870
7018
  /** The kind label a composite part's selection badge shows (Card v2: "Card · card.title"). */
6871
- const COMPOSITE_KIND_KEYS = { card: 'builder.chrome.kindCard', accordion: 'builder.chrome.kindAccordion' };
7019
+ const COMPOSITE_KIND_KEYS = { card: 'builder.chrome.kindCard', accordion: 'builder.chrome.kindAccordion', disclosure: 'builder.chrome.kindDisclosure', slider: 'builder.chrome.kindSlider' };
7020
+ const VIDEO_TYPE = 'Video';
7021
+ const VIDEO_KIND_KEY = 'builder.chrome.kindVideo';
7022
+ const VIDEO_POSTER_ONLY_KEY = 'builder.chrome.videoPosterOnly';
7023
+ const VIDEO_FILE_KEY = 'builder.chrome.videoFile';
6872
7024
  /** The parts that offer "Add item" on the selection toolbar (board 3: the "Add slide" pattern). */
6873
7025
  const ADD_ITEM_ROLES = new Set([AccordionRole.Accordion, AccordionRole.Item, AccordionRole.Trigger, AccordionRole.Panel]);
6874
7026
  class OverlayComponent {
@@ -7085,11 +7237,17 @@ class OverlayComponent {
7085
7237
  }
7086
7238
  /** The kind badge's glyph: the composite's kind icon (board 9: "kind icon + 'Accordion · trigger'"). */
7087
7239
  get selectedRoleIcon() {
7240
+ if (this.selectEntry?.node?.type === VIDEO_TYPE && !this.selectEntry.node.role)
7241
+ return 'ph-fill ph-film-strip';
7088
7242
  return `ph-fill ${compositeKindGlyph(this.selectEntry?.node?.role ?? '')}`;
7089
7243
  }
7090
- /** A composite part's kind + role under the selection (board 3/8 "Selection kind badge"), or null. */
7244
+ /** A composite part's kind + role under the selection (board 3/8 "Selection kind badge"), or null. A Video says
7245
+ * where it plays from and that the canvas shows its poster only (board 5: "Video · YouTube · poster only"). */
7091
7246
  get selectedRoleBadge() {
7092
- const role = this.selectEntry?.node?.role;
7247
+ const node = this.selectEntry?.node;
7248
+ if (node?.type === VIDEO_TYPE && !node.role)
7249
+ return this.videoBadge(node);
7250
+ const role = node?.role;
7093
7251
  if (!role)
7094
7252
  return null;
7095
7253
  const prefix = role.split('.')[0];
@@ -7099,6 +7257,13 @@ class OverlayComponent {
7099
7257
  const row = this.overlayService.selectedRow;
7100
7258
  return row ? `${badge} · ${this.builderLabels(FROM_ROW_KEY, BUILDER_CHROME_EN[FROM_ROW_KEY]).replace('{row}', String(row))}` : badge;
7101
7259
  }
7260
+ videoBadge(node) {
7261
+ const plan = planVideo(node, null);
7262
+ const where = plan.source === VideoSource.File
7263
+ ? this.builderLabels(VIDEO_FILE_KEY, BUILDER_CHROME_EN[VIDEO_FILE_KEY])
7264
+ : VIDEO_PROVIDER_LABEL[plan.source];
7265
+ return `${this.builderLabels(VIDEO_KIND_KEY, BUILDER_CHROME_EN[VIDEO_KIND_KEY])} · ${where} · ${this.builderLabels(VIDEO_POSTER_ONLY_KEY, BUILDER_CHROME_EN[VIDEO_POSTER_ONLY_KEY])}`;
7266
+ }
7102
7267
  /** The selection toolbar's name: the part's LAYER name (board 3 — "Header", "Accordion"), else its type. */
7103
7268
  get toolbarName() {
7104
7269
  return this.selectEntry?.node?.label || this.selectEntry?.componentName || '';
@@ -7737,7 +7902,7 @@ function walk(nodes, depth, out, ctx, inTemplate, templateOf) {
7737
7902
  }
7738
7903
  }
7739
7904
 
7740
- /** An Accordion from content's root row (CC2, board 9): "From faqs · 6 rows". */
7905
+ /** An Accordion from content's root row (CC2, board 3 / 9): "From FAQ · 6 rows" — the content type's label. */
7741
7906
  const FROM_CONTENT_KEY = 'builder.chrome.fromContent';
7742
7907
  const LOCKED_PART_KEY = 'builder.chrome.lockedPart';
7743
7908
  const COMPOSITE_ROLE_KEY = 'builder.chrome.compositeRole';
@@ -7775,6 +7940,8 @@ class LayerTreeComponent {
7775
7940
  this.activeSection = 'page';
7776
7941
  this.labels = inject(IOX_BUILDER_LABELS);
7777
7942
  this.panelEvents = inject(PanelEventService);
7943
+ this.typeLabels = inject(IOX_CONTENT_TYPE_LABELS);
7944
+ this.dataSources = inject(DataSourceRegistryService, { optional: true });
7778
7945
  this.lockedPartTitle = this.labels(LOCKED_PART_KEY, BUILDER_CHROME_EN[LOCKED_PART_KEY]);
7779
7946
  this.roleTitle = this.labels(COMPOSITE_ROLE_KEY, BUILDER_CHROME_EN[COMPOSITE_ROLE_KEY]);
7780
7947
  this.templateLabel = this.labels(TEMPLATE_KEY, BUILDER_CHROME_EN[TEMPLATE_KEY]);
@@ -7946,7 +8113,9 @@ class LayerTreeComponent {
7946
8113
  isExpanded: (node) => (node.id ? (this.expandedState.get(node.id) ?? true) : true),
7947
8114
  repeaterRows: (node) => this.repeaterRows(node),
7948
8115
  fromContentLabel: (rows) => rows.alias
7949
- ? this.labels(FROM_CONTENT_KEY, BUILDER_CHROME_EN[FROM_CONTENT_KEY]).replace('{alias}', rows.alias).replace('{count}', String(rows.count))
8116
+ ? this.labels(FROM_CONTENT_KEY, BUILDER_CHROME_EN[FROM_CONTENT_KEY])
8117
+ .replace('{source}', sourceTypeLabel(rows.alias, this.dataSources?.findByAlias(rows.alias), this.typeLabels))
8118
+ .replace('{count}', String(rows.count))
7950
8119
  : null,
7951
8120
  };
7952
8121
  this.flatTree = flattenLayerTree(this.layout, ctx);
@@ -8019,7 +8188,7 @@ class BreadcrumbBarComponent {
8019
8188
  ...nodes.map((node, i) => ({
8020
8189
  node,
8021
8190
  label: crumbLabel(node),
8022
- icon: isAccordionRoot(node) ? `ph-thin ${compositeKindGlyph(node.role)}` : null,
8191
+ icon: isCompositeRoot(node) ? `ph-thin ${compositeKindGlyph(node.role)}` : null,
8023
8192
  isCurrent: i === last,
8024
8193
  key: node,
8025
8194
  })),
@@ -9883,13 +10052,14 @@ const ACCORDION_TRACK_WRAPPER = 'track';
9883
10052
  * See moveable-migration.md.
9884
10053
  */
9885
10054
  class BuilderContainerComponent {
9886
- /** The wrapper a child renders in: an Accordion item's header → its heading level, its panel → the track. */
10055
+ /** The wrapper a child renders in: an Accordion item's header → its heading level; an item's panel (either
10056
+ * kind) → the track. A disclosure's toggle has no heading — it is a button in the flow. */
9887
10057
  wrapperOf(child) {
9888
- if (this.node?.role !== AccordionRole.Item)
10058
+ if (!isCompositeItem(this.node))
9889
10059
  return null;
9890
- if (child.role === AccordionRole.Trigger)
10060
+ if (child.role === AccordionRole.Trigger && this.node?.role === AccordionRole.Item)
9891
10061
  return accordionHeadingLevel(child);
9892
- if (child.role === AccordionRole.Panel)
10062
+ if (isCompositePanel(child))
9893
10063
  return ACCORDION_TRACK_WRAPPER;
9894
10064
  return null;
9895
10065
  }
@@ -9962,7 +10132,8 @@ class BuilderContainerComponent {
9962
10132
  </ng-template>
9963
10133
  <!-- An Accordion ITEM (CC2) wraps its parts in the markup every renderer writes: the header inside a
9964
10134
  heading of its question's level, the panel inside the track + region the ONE hiding rule collapses
9965
- (iox-design.css). Structural only — the runtime stamps their state. -->
10135
+ (iox-design.css). A Disclosure (CC2.1) is its own item: its toggle stays a bare button, its panel
10136
+ takes the same track. Structural only — the runtime stamps their state. -->
9966
10137
  @for (child of children; track child) {
9967
10138
  @switch (wrapperOf(child)) {
9968
10139
  @case ('h2') { <h2 class="iox-accordion-heading"><ng-container *ngTemplateOutlet="childTpl; context: { $implicit: child }"></ng-container></h2> }
@@ -10003,7 +10174,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
10003
10174
  </ng-template>
10004
10175
  <!-- An Accordion ITEM (CC2) wraps its parts in the markup every renderer writes: the header inside a
10005
10176
  heading of its question's level, the panel inside the track + region the ONE hiding rule collapses
10006
- (iox-design.css). Structural only — the runtime stamps their state. -->
10177
+ (iox-design.css). A Disclosure (CC2.1) is its own item: its toggle stays a bare button, its panel
10178
+ takes the same track. Structural only — the runtime stamps their state. -->
10007
10179
  @for (child of children; track child) {
10008
10180
  @switch (wrapperOf(child)) {
10009
10181
  @case ('h2') { <h2 class="iox-accordion-heading"><ng-container *ngTemplateOutlet="childTpl; context: { $implicit: child }"></ng-container></h2> }
@@ -10024,7 +10196,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
10024
10196
  '[attr.data-iox-state]': 'formClass === "iox-form" ? formState : null',
10025
10197
  '[attr.start]': "htmlTag === 'ol' && start !== 1 ? start : null",
10026
10198
  '[attr.reversed]': "htmlTag === 'ol' && reversed ? '' : null",
10027
- // An accordion item's identity — the runtime pairs its header and panel ids from it (CC2).
10199
+ // An item's identity (an accordion item, or a disclosure) — the runtime pairs its header and panel ids from it.
10028
10200
  '[attr.data-iox-item-key]': 'node?.itemKey ?? null',
10029
10201
  }, standalone: false, styles: [":host{position:relative;box-sizing:border-box}.container-placeholder{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:0;opacity:0;transition:opacity .15s}:host(:hover) .container-placeholder,:host(.iox-drag-over) .container-placeholder{opacity:1}.container-placeholder i{font-size:18px}:host ::ng-deep>[class*=iox-outer-]{min-width:0}\n"] }]
10030
10202
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: DragEngineService }, { type: i0.ChangeDetectorRef }], propDecorators: { children: [{
@@ -10056,9 +10228,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
10056
10228
  /** `click` covers plain and modified clicks; a middle click opens a tab through `auxclick` alone. */
10057
10229
  const NAVIGATING_CLICKS = ['click', 'auxclick'];
10058
10230
  class BuilderLinkedContainerComponent {
10059
- /** An Accordion's header renders a <button> (CC2). */
10231
+ /** An Accordion's header (CC2) or a Disclosure's toggle (CC2.1) renders a <button>. */
10060
10232
  get isTrigger() {
10061
- return this.node?.role === AccordionRole.Trigger;
10233
+ return isCompositeTrigger(this.node);
10062
10234
  }
10063
10235
  constructor(dragEngine, cdr, elRef, isPreview) {
10064
10236
  this.dragEngine = dragEngine;
@@ -10557,7 +10729,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
10557
10729
  type: Output
10558
10730
  }] } });
10559
10731
 
10732
+ /** Swiper's event → the interaction trigger it replays (componentEvents). */
10733
+ const SWIPER_TRIGGER = {
10734
+ slideChange: 'swiperSlideChange', reachBeginning: 'swiperReachBeginning', reachEnd: 'swiperReachEnd',
10735
+ autoplayStart: 'swiperAutoplayStart', autoplayStop: 'swiperAutoplayStop',
10736
+ };
10560
10737
  class SliderContainerComponent {
10738
+ /** Every child — the slides AND the control parts (CC3). Split once per change, never in a getter. */
10739
+ set children(value) {
10740
+ this._children = value ?? [];
10741
+ const { lead, slides, trail } = splitSliderChildren(this._children);
10742
+ this.leadParts = lead;
10743
+ this.slides = slides;
10744
+ this.trailParts = trail;
10745
+ this.controlParts = hasSliderParts({ children: this._children });
10746
+ }
10747
+ get children() { return this._children; }
10748
+ /** A saved slider whose controls are not parts yet keeps Swiper-drawn ones. */
10749
+ get legacyControls() { return !this.controlParts; }
10561
10750
  set style(v) {
10562
10751
  if (v === this._style)
10563
10752
  return;
@@ -10604,7 +10793,14 @@ class SliderContainerComponent {
10604
10793
  this.dataSourceService = dataSourceService;
10605
10794
  this.dsRegistry = dsRegistry;
10606
10795
  this.panelEventService = panelEventService;
10607
- this.children = [];
10796
+ this._children = [];
10797
+ /** The slides (into `.swiper-wrapper`); the template slide of a bound slider is `slides[0]`. */
10798
+ this.slides = [];
10799
+ /** Control parts before the first slide / after it — rendered beside the wrapper, inside `.swiper`. */
10800
+ this.leadParts = [];
10801
+ this.trailParts = [];
10802
+ /** The controls are parts: Swiper draws none of its own. */
10803
+ this.controlParts = false;
10608
10804
  this._style = {};
10609
10805
  this._previewStyle = {};
10610
10806
  this._editShellStyle = { position: 'relative' };
@@ -10755,7 +10951,7 @@ class SliderContainerComponent {
10755
10951
  });
10756
10952
  }
10757
10953
  refreshPreviews() {
10758
- if (!this.items.length || !this.children.length) {
10954
+ if (!this.items.length || !this.slides.length) {
10759
10955
  this.previewSlides = [];
10760
10956
  this.cdr.markForCheck();
10761
10957
  this._scheduleReinit();
@@ -10763,16 +10959,16 @@ class SliderContainerComponent {
10763
10959
  }
10764
10960
  this.applyFirstItemToTemplate();
10765
10961
  // Each preview slide = one cloned SliderSlide node with item data resolved
10766
- this.previewSlides = this.items.slice(1).map(item => cloneNodesForItem([this.children[0]], item)[0]);
10962
+ this.previewSlides = this.items.slice(1).map(item => cloneNodesForItem([this.slides[0]], item)[0]);
10767
10963
  this.cdr.markForCheck();
10768
10964
  this._scheduleReinit();
10769
10965
  }
10770
10966
  applyFirstItemToTemplate() {
10771
10967
  const item = this.items[0];
10772
- if (!item || !this.children.length || !this.overlayService)
10968
+ if (!item || !this.slides.length || !this.overlayService)
10773
10969
  return;
10774
10970
  // Bindings live on leaf nodes inside the template slide, so recurse into the tree
10775
- this.applyItemToNodes([this.children[0]], item);
10971
+ this.applyItemToNodes([this.slides[0]], item);
10776
10972
  }
10777
10973
  applyItemToNodes(nodes, item) {
10778
10974
  for (const node of nodes) {
@@ -10798,7 +10994,7 @@ class SliderContainerComponent {
10798
10994
  _isInTemplate(target) {
10799
10995
  const search = (nodes) => nodes.some(c => c === target || c.id === target.id ||
10800
10996
  (c.children?.length ? search(c.children) : false));
10801
- return this.children.length > 0 && search([this.children[0]]);
10997
+ return this.slides.length > 0 && search([this.slides[0]]);
10802
10998
  }
10803
10999
  _scheduleReinit() {
10804
11000
  this._destroySwiper();
@@ -10811,123 +11007,31 @@ class SliderContainerComponent {
10811
11007
  const el = this.isPreview ? this.swiperEl?.nativeElement : this.editSwiperEl?.nativeElement;
10812
11008
  if (!el)
10813
11009
  return;
10814
- const [{ default: Swiper }, swiperModules] = await Promise.all([
10815
- import('swiper'),
10816
- import('swiper/modules'),
10817
- ]);
10818
- const { Navigation, Pagination, Scrollbar, Autoplay, Keyboard, Mousewheel, Zoom, Grid, Parallax, FreeMode, EffectFade, EffectCube, EffectFlip, EffectCoverflow, EffectCards, EffectCreative, } = swiperModules;
10819
- const modules = [];
10820
- if (this.enableNavigation)
10821
- modules.push(Navigation);
10822
- if (this.enablePagination)
10823
- modules.push(Pagination);
10824
- if (this.enableScrollbar)
10825
- modules.push(Scrollbar);
10826
- const config = {
10827
- modules,
10828
- direction: this.direction,
10829
- slidesPerView: this.slidesPerView,
10830
- slidesPerGroup: this.slidesPerGroup > 1 ? this.slidesPerGroup : 1,
10831
- spaceBetween: this.spaceBetween,
10832
- speed: this.isPreview ? this.speed : 300,
10833
- // Always slide effect in edit mode — fade/cube etc. hide all but active slide
10834
- effect: this.isPreview ? this.effect : 'slide',
10835
- centeredSlides: this.centeredSlides,
10836
- initialSlide: this.initialSlide,
10837
- autoHeight: this.autoHeight,
10838
- };
10839
- if (this.isPreview) {
10840
- // Full interactive config for preview
10841
- config['grabCursor'] = this.grabCursor;
10842
- config['slideToClickedSlide'] = this.slideToClickedSlide;
10843
- config['loop'] = this.loop === 'loop';
10844
- config['rewind'] = this.loop === 'rewind';
10845
- if (this.freeMode) {
10846
- modules.push(FreeMode);
10847
- config['freeMode'] = true;
10848
- }
10849
- if (this.enableAutoplay) {
10850
- modules.push(Autoplay);
10851
- }
10852
- if (this.enableKeyboard) {
10853
- modules.push(Keyboard);
10854
- }
10855
- if (this.enableMousewheel) {
10856
- modules.push(Mousewheel);
10857
- }
10858
- if (this.enableZoom) {
10859
- modules.push(Zoom);
10860
- }
10861
- if (this.enableGrid) {
10862
- modules.push(Grid);
10863
- }
10864
- if (this.enableParallax) {
10865
- modules.push(Parallax);
10866
- }
10867
- const effectMap = {
10868
- fade: EffectFade, cube: EffectCube, flip: EffectFlip,
10869
- coverflow: EffectCoverflow, cards: EffectCards, creative: EffectCreative,
10870
- };
10871
- if (this.effect !== 'slide' && effectMap[this.effect]) {
10872
- modules.push(effectMap[this.effect]);
10873
- }
10874
- if (this.enableNavigation) {
10875
- config['navigation'] = { prevEl: '.swiper-button-prev', nextEl: '.swiper-button-next' };
10876
- }
10877
- if (this.enablePagination) {
10878
- config['pagination'] = {
10879
- el: '.swiper-pagination',
10880
- type: this.paginationType,
10881
- clickable: this.paginationClickable,
10882
- dynamicBullets: this.paginationDynamicBullets,
10883
- };
10884
- }
10885
- if (this.enableScrollbar)
10886
- config['scrollbar'] = { el: '.swiper-scrollbar', draggable: true };
10887
- if (this.enableAutoplay) {
10888
- config['autoplay'] = {
10889
- delay: this.autoplayDelay,
10890
- pauseOnMouseEnter: this.autoplayPauseOnMouseEnter,
10891
- disableOnInteraction: this.autoplayDisableOnInteraction,
10892
- };
10893
- }
10894
- if (this.enableGrid && this.gridRows > 1)
10895
- config['grid'] = { rows: this.gridRows };
10896
- if (this.breakpoints) {
10897
- try {
10898
- config['breakpoints'] = JSON.parse(this.breakpoints);
10899
- }
10900
- catch { /* ignore */ }
10901
- }
10902
- config['on'] = {
10903
- slideChange: (swiper) => this._onSwiperEvent('swiperSlideChange', swiper),
10904
- reachBeginning: (swiper) => this._onSwiperEvent('swiperReachBeginning', swiper),
10905
- reachEnd: (swiper) => this._onSwiperEvent('swiperReachEnd', swiper),
10906
- autoplayStart: (swiper) => this._onSwiperEvent('swiperAutoplayStart', swiper),
10907
- autoplayStop: (swiper) => this._onSwiperEvent('swiperAutoplayStop', swiper),
10908
- };
10909
- }
10910
- else {
10911
- // Edit mode: disable touch/swipe so builder click handlers work normally
10912
- config['allowTouchMove'] = false;
10913
- config['simulateTouch'] = false;
10914
- if (this.enableNavigation) {
10915
- config['navigation'] = { prevEl: '.swiper-button-prev', nextEl: '.swiper-button-next' };
10916
- }
10917
- if (this.enablePagination) {
10918
- config['pagination'] = {
10919
- el: '.swiper-pagination',
10920
- type: this.paginationType,
10921
- clickable: this.paginationClickable,
10922
- dynamicBullets: this.paginationDynamicBullets,
10923
- };
10924
- }
10925
- if (this.enableScrollbar)
10926
- config['scrollbar'] = { el: '.swiper-scrollbar', draggable: false };
10927
- }
10928
- this._swiper = new Swiper(el, config);
11010
+ // The ONE Swiper decision (iox-ui `bootSlider` → `planSwiperOptions`): the EDIT canvas is tamed (no touch,
11011
+ // loop or autoplay; the parts still navigate); Preview is the live site's — the A11y module, the pause
11012
+ // control, the live region (CC3; Preview used to build its own config and skipped A11y).
11013
+ const swiper = await bootSlider(el, this.swiperInputs(), {
11014
+ edit: !this.isPreview,
11015
+ onEvent: this.isPreview ? (event, sw) => this._onSwiperEvent(SWIPER_TRIGGER[event] ?? event, sw) : undefined,
11016
+ });
11017
+ if (!swiper)
11018
+ return;
11019
+ this._swiper = swiper;
10929
11020
  this.instanceRegistry.register(this.nodeId, this._swiper);
10930
11021
  }
11022
+ swiperInputs() {
11023
+ return {
11024
+ dir: this.dir, direction: this.direction, loop: this.loop, slidesPerView: this.slidesPerView, slidesPerGroup: this.slidesPerGroup,
11025
+ spaceBetween: this.spaceBetween, speed: this.speed, effect: this.effect, grabCursor: this.grabCursor, centeredSlides: this.centeredSlides,
11026
+ initialSlide: this.initialSlide, autoHeight: this.autoHeight, slideToClickedSlide: this.slideToClickedSlide, freeMode: this.freeMode,
11027
+ enableNavigation: this.enableNavigation, enablePagination: this.enablePagination, enableScrollbar: this.enableScrollbar,
11028
+ enableAutoplay: this.enableAutoplay, enableKeyboard: this.enableKeyboard, enableMousewheel: this.enableMousewheel,
11029
+ enableZoom: this.enableZoom, enableGrid: this.enableGrid, enableParallax: this.enableParallax, autoplayDelay: this.autoplayDelay,
11030
+ autoplayPauseOnMouseEnter: this.autoplayPauseOnMouseEnter, autoplayDisableOnInteraction: this.autoplayDisableOnInteraction,
11031
+ paginationType: this.paginationType, paginationClickable: this.paginationClickable, paginationDynamicBullets: this.paginationDynamicBullets,
11032
+ gridRows: this.gridRows, breakpoints: this.breakpoints,
11033
+ };
11034
+ }
10931
11035
  _destroySwiper() {
10932
11036
  if (this._swiper) {
10933
11037
  this._swiper.destroy(true, true);
@@ -10940,7 +11044,7 @@ class SliderContainerComponent {
10940
11044
  if (eventName === 'swiperSlideChange') {
10941
11045
  const prevIdx = swiper.previousIndex;
10942
11046
  const activeIdx = swiper.activeIndex;
10943
- const allSlides = this._source ? [this.children[0], ...this.previewSlides] : this.children;
11047
+ const allSlides = this._source ? [this.slides[0], ...this.previewSlides] : this.slides;
10944
11048
  if (prevIdx !== undefined && allSlides[prevIdx]) {
10945
11049
  this.interactionEngine.replayTrigger(allSlides[prevIdx].id, 'swiperSlideInactive');
10946
11050
  }
@@ -10970,11 +11074,17 @@ class SliderContainerComponent {
10970
11074
  </div>
10971
11075
 
10972
11076
  <div #editSwiperEl class="swiper swiper-edit" [attr.dir]="dir" [style.direction]="dir">
11077
+ <!-- CC3: the control PARTS (Pause, Previous, Next, Pagination) render inside .swiper, beside the
11078
+ wrapper (never in it — slider.md); selectable and styled on their own (R2). -->
11079
+ <ng-container *ngFor="let part of leadParts; trackBy: trackByNodeId">
11080
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11081
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11082
+ </ng-container>
10973
11083
  <div class="swiper-wrapper">
10974
11084
 
10975
- <!-- NORMAL MODE: all children as draggable slides -->
11085
+ <!-- NORMAL MODE: all slides draggable -->
10976
11086
  <ng-container *ngIf="!source">
10977
- <div *ngFor="let child of children"
11087
+ <div *ngFor="let child of slides; trackBy: trackByNodeId"
10978
11088
  class="swiper-slide"
10979
11089
  [ngClass]="['iox-outer-' + (child.styleId ?? child.id)]"
10980
11090
  ioxDraggable
@@ -10992,22 +11102,24 @@ class SliderContainerComponent {
10992
11102
  <!-- REPEAT MODE: template slide (item 0) + dimmed preview slides (items 1..N) -->
10993
11103
  <ng-container *ngIf="source">
10994
11104
  <!-- Template slide — draggable/editable, receives item[0] data -->
10995
- <div *ngIf="children.length"
11105
+ <div *ngIf="slides.length"
10996
11106
  class="swiper-slide"
10997
- [ngClass]="['iox-outer-' + (children[0].styleId ?? children[0].id)]"
11107
+ [ngClass]="['iox-outer-' + (slides[0].styleId ?? slides[0].id)]"
11108
+ [attr.data-iox-row-idx]="0"
10998
11109
  ioxDraggable
10999
- [ioxDragData]="children[0]"
11110
+ [ioxDragData]="slides[0]"
11000
11111
  [ioxDragSourceId]="dropListId">
11001
11112
  <ng-container
11002
- [ioxRender]="children[0]"
11113
+ [ioxRender]="slides[0]"
11003
11114
  (onClick)="childClick.emit($event)"
11004
11115
  (onMouseEnter)="childMouseEnter.emit($event)"
11005
11116
  (onMouseLeave)="childMouseLeave.emit()">
11006
11117
  </ng-container>
11007
11118
  </div>
11008
11119
  <!-- Preview slides — dimmed, non-interactive, data resolved from items 1..N -->
11009
- <div *ngFor="let slide of previewSlides; trackBy: trackByNodeId"
11120
+ <div *ngFor="let slide of previewSlides; let i = index; trackBy: trackByNodeId"
11010
11121
  class="swiper-slide slider-preview-slide"
11122
+ [attr.data-iox-row-idx]="i + 1"
11011
11123
  [ngClass]="['iox-outer-' + (slide.styleId ?? slide.id)]">
11012
11124
  <ng-container
11013
11125
  [ioxRender]="slide"
@@ -11019,23 +11131,28 @@ class SliderContainerComponent {
11019
11131
  </ng-container>
11020
11132
 
11021
11133
  </div>
11134
+ <ng-container *ngFor="let part of trailParts; trackBy: trackByNodeId">
11135
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11136
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11137
+ </ng-container>
11022
11138
 
11023
- <div *ngIf="!source && !children.length" class="slider-edit-placeholder" data-iox-chrome>
11139
+ <div *ngIf="!source && !slides.length" class="slider-edit-placeholder" data-iox-chrome>
11024
11140
  <i class="ph-thin ph-sliders-horizontal"></i>
11025
11141
  <span>Click + in toolbar to add a slide</span>
11026
11142
  </div>
11027
11143
 
11028
- <div *ngIf="enablePagination" class="swiper-pagination"></div>
11144
+ <div *ngIf="legacyControls && enablePagination" class="swiper-pagination"></div>
11029
11145
  <div *ngIf="enableScrollbar" class="swiper-scrollbar"></div>
11030
11146
  </div>
11031
11147
 
11032
- <!-- Nav buttons live on the shell, not inside .swiper, so overflow:hidden never clips them
11033
- and top:50%+transform always centers on the real slide height -->
11034
- <button *ngIf="enableNavigation" class="slider-edit-nav slider-edit-nav--prev" data-iox-chrome
11148
+ <!-- Legacy (Swiper-drawn) nav buttons live on the shell, not inside .swiper, so overflow:hidden never
11149
+ clips them and top:50%+transform always centers on the real slide height. A slider whose controls
11150
+ are PARTS (CC3) draws none: the parts are the controls. -->
11151
+ <button *ngIf="legacyControls && enableNavigation" class="slider-edit-nav slider-edit-nav--prev" data-iox-chrome
11035
11152
  (click)="_swiper?.slidePrev()" type="button" title="Previous slide">
11036
11153
  <i class="ph-thin ph-caret-left"></i>
11037
11154
  </button>
11038
- <button *ngIf="enableNavigation" class="slider-edit-nav slider-edit-nav--next" data-iox-chrome
11155
+ <button *ngIf="legacyControls && enableNavigation" class="slider-edit-nav slider-edit-nav--next" data-iox-chrome
11039
11156
  (click)="_swiper?.slideNext()" type="button" title="Next slide">
11040
11157
  <i class="ph-thin ph-caret-right"></i>
11041
11158
  </button>
@@ -11052,12 +11169,16 @@ class SliderContainerComponent {
11052
11169
  [style.--swiper-navigation-color]="navigationColor || null"
11053
11170
  [style.--swiper-navigation-size.px]="navigationSize || null"
11054
11171
  [style.--swiper-pagination-color]="paginationColor || null">
11172
+ <ng-container *ngFor="let part of leadParts; trackBy: trackByNodeId">
11173
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11174
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11175
+ </ng-container>
11055
11176
  <div class="swiper-wrapper">
11056
11177
  <!-- Swiper requires .swiper-slide as a DIRECT child of .swiper-wrapper.
11057
11178
  Wrap each rendered slide in one (same structure as edit mode) so the
11058
11179
  app-slider-slide host sits INSIDE the slide, not between it and the wrapper. -->
11059
11180
  <ng-container *ngIf="!source">
11060
- <div *ngFor="let child of children"
11181
+ <div *ngFor="let child of slides; trackBy: trackByNodeId"
11061
11182
  class="swiper-slide"
11062
11183
  [ngClass]="['iox-outer-' + (child.styleId ?? child.id)]">
11063
11184
  <ng-container
@@ -11068,20 +11189,22 @@ class SliderContainerComponent {
11068
11189
  </ng-container>
11069
11190
  </div>
11070
11191
  </ng-container>
11071
- <!-- REPEAT: template slide + preview slides -->
11192
+ <!-- REPEAT: template slide + preview slides; each is a row (a lightbox opens at the clicked one) -->
11072
11193
  <ng-container *ngIf="source">
11073
- <div *ngIf="children.length"
11194
+ <div *ngIf="slides.length"
11074
11195
  class="swiper-slide"
11075
- [ngClass]="['iox-outer-' + (children[0].styleId ?? children[0].id)]">
11196
+ [attr.data-iox-row-idx]="0"
11197
+ [ngClass]="['iox-outer-' + (slides[0].styleId ?? slides[0].id)]">
11076
11198
  <ng-container
11077
- [ioxRender]="children[0]"
11199
+ [ioxRender]="slides[0]"
11078
11200
  (onClick)="childClick.emit($event)"
11079
11201
  (onMouseEnter)="childMouseEnter.emit($event)"
11080
11202
  (onMouseLeave)="childMouseLeave.emit()">
11081
11203
  </ng-container>
11082
11204
  </div>
11083
- <div *ngFor="let slide of previewSlides; trackBy: trackByNodeId"
11205
+ <div *ngFor="let slide of previewSlides; let i = index; trackBy: trackByNodeId"
11084
11206
  class="swiper-slide"
11207
+ [attr.data-iox-row-idx]="i + 1"
11085
11208
  [ngClass]="['iox-outer-' + (slide.styleId ?? slide.id)]">
11086
11209
  <ng-container
11087
11210
  [ioxRender]="slide"
@@ -11092,9 +11215,13 @@ class SliderContainerComponent {
11092
11215
  </div>
11093
11216
  </ng-container>
11094
11217
  </div>
11095
- <div *ngIf="enableNavigation" class="swiper-button-prev"></div>
11096
- <div *ngIf="enableNavigation" class="swiper-button-next"></div>
11097
- <div *ngIf="enablePagination" class="swiper-pagination"></div>
11218
+ <ng-container *ngFor="let part of trailParts; trackBy: trackByNodeId">
11219
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11220
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11221
+ </ng-container>
11222
+ <div *ngIf="legacyControls && enableNavigation" class="swiper-button-prev"></div>
11223
+ <div *ngIf="legacyControls && enableNavigation" class="swiper-button-next"></div>
11224
+ <div *ngIf="legacyControls && enablePagination" class="swiper-pagination"></div>
11098
11225
  <div *ngIf="enableScrollbar" class="swiper-scrollbar"></div>
11099
11226
  </div>
11100
11227
  `, isInline: true, styles: [":host{display:block}.swiper-wrapper{height:auto}.slider-edit-shell{position:relative;display:block}.swiper-edit{width:100%}.swiper-edit .swiper-slide{position:relative}.slider-edit-nav{position:absolute;top:50%;transform:translateY(-50%);width:32px;height:32px;border-radius:50%;border:1px solid rgba(255,255,255,.5);background:#00000038;color:#fff;font-size:16px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:10;transition:background .15s}.slider-edit-nav:hover{background:#00000073}.slider-edit-nav--prev{left:8px}.slider-edit-nav--next{right:8px}.slider-edit-placeholder{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none}.slider-edit-placeholder i{font-size:22px}.slider-repeat-badge{position:absolute;top:0;left:0;z-index:10;display:flex;align-items:center;gap:.4rem;padding:4px 8px;font-size:11px;color:#cb9090;background:#cb909014;border:1px solid rgba(203,144,144,.5);border-radius:0 0 4px;opacity:0;transition:opacity .15s;-webkit-user-select:none;user-select:none;pointer-events:none}.slider-edit-shell:hover .slider-repeat-badge{opacity:1}.slider-repeat-badge-count{font-weight:600}.slider-badge-spin{animation:slider-badge-spin 1s linear infinite}@keyframes slider-badge-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.slider-preview-slide{opacity:.55;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: RenderDirective, selector: "[ioxRender]", inputs: ["ioxRender", "ioxDragSourceId", "ioxPhrasing"], outputs: ["onClick", "onMouseEnter", "onMouseLeave"] }, { kind: "directive", type: IoxDraggableDirective, selector: "[ioxDraggable]", inputs: ["ioxDragData", "ioxDragSourceId", "ioxDragDisabled"] }, { kind: "directive", type: IoxDropzoneDirective, selector: "[ioxDropzone]", inputs: ["ioxDropzoneId", "ioxDropzoneData", "ioxDropzonePostDrop"], outputs: ["ioxDrop"] }] }); }
@@ -11121,11 +11248,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
11121
11248
  </div>
11122
11249
 
11123
11250
  <div #editSwiperEl class="swiper swiper-edit" [attr.dir]="dir" [style.direction]="dir">
11251
+ <!-- CC3: the control PARTS (Pause, Previous, Next, Pagination) render inside .swiper, beside the
11252
+ wrapper (never in it — slider.md); selectable and styled on their own (R2). -->
11253
+ <ng-container *ngFor="let part of leadParts; trackBy: trackByNodeId">
11254
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11255
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11256
+ </ng-container>
11124
11257
  <div class="swiper-wrapper">
11125
11258
 
11126
- <!-- NORMAL MODE: all children as draggable slides -->
11259
+ <!-- NORMAL MODE: all slides draggable -->
11127
11260
  <ng-container *ngIf="!source">
11128
- <div *ngFor="let child of children"
11261
+ <div *ngFor="let child of slides; trackBy: trackByNodeId"
11129
11262
  class="swiper-slide"
11130
11263
  [ngClass]="['iox-outer-' + (child.styleId ?? child.id)]"
11131
11264
  ioxDraggable
@@ -11143,22 +11276,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
11143
11276
  <!-- REPEAT MODE: template slide (item 0) + dimmed preview slides (items 1..N) -->
11144
11277
  <ng-container *ngIf="source">
11145
11278
  <!-- Template slide — draggable/editable, receives item[0] data -->
11146
- <div *ngIf="children.length"
11279
+ <div *ngIf="slides.length"
11147
11280
  class="swiper-slide"
11148
- [ngClass]="['iox-outer-' + (children[0].styleId ?? children[0].id)]"
11281
+ [ngClass]="['iox-outer-' + (slides[0].styleId ?? slides[0].id)]"
11282
+ [attr.data-iox-row-idx]="0"
11149
11283
  ioxDraggable
11150
- [ioxDragData]="children[0]"
11284
+ [ioxDragData]="slides[0]"
11151
11285
  [ioxDragSourceId]="dropListId">
11152
11286
  <ng-container
11153
- [ioxRender]="children[0]"
11287
+ [ioxRender]="slides[0]"
11154
11288
  (onClick)="childClick.emit($event)"
11155
11289
  (onMouseEnter)="childMouseEnter.emit($event)"
11156
11290
  (onMouseLeave)="childMouseLeave.emit()">
11157
11291
  </ng-container>
11158
11292
  </div>
11159
11293
  <!-- Preview slides — dimmed, non-interactive, data resolved from items 1..N -->
11160
- <div *ngFor="let slide of previewSlides; trackBy: trackByNodeId"
11294
+ <div *ngFor="let slide of previewSlides; let i = index; trackBy: trackByNodeId"
11161
11295
  class="swiper-slide slider-preview-slide"
11296
+ [attr.data-iox-row-idx]="i + 1"
11162
11297
  [ngClass]="['iox-outer-' + (slide.styleId ?? slide.id)]">
11163
11298
  <ng-container
11164
11299
  [ioxRender]="slide"
@@ -11170,23 +11305,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
11170
11305
  </ng-container>
11171
11306
 
11172
11307
  </div>
11308
+ <ng-container *ngFor="let part of trailParts; trackBy: trackByNodeId">
11309
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11310
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11311
+ </ng-container>
11173
11312
 
11174
- <div *ngIf="!source && !children.length" class="slider-edit-placeholder" data-iox-chrome>
11313
+ <div *ngIf="!source && !slides.length" class="slider-edit-placeholder" data-iox-chrome>
11175
11314
  <i class="ph-thin ph-sliders-horizontal"></i>
11176
11315
  <span>Click + in toolbar to add a slide</span>
11177
11316
  </div>
11178
11317
 
11179
- <div *ngIf="enablePagination" class="swiper-pagination"></div>
11318
+ <div *ngIf="legacyControls && enablePagination" class="swiper-pagination"></div>
11180
11319
  <div *ngIf="enableScrollbar" class="swiper-scrollbar"></div>
11181
11320
  </div>
11182
11321
 
11183
- <!-- Nav buttons live on the shell, not inside .swiper, so overflow:hidden never clips them
11184
- and top:50%+transform always centers on the real slide height -->
11185
- <button *ngIf="enableNavigation" class="slider-edit-nav slider-edit-nav--prev" data-iox-chrome
11322
+ <!-- Legacy (Swiper-drawn) nav buttons live on the shell, not inside .swiper, so overflow:hidden never
11323
+ clips them and top:50%+transform always centers on the real slide height. A slider whose controls
11324
+ are PARTS (CC3) draws none: the parts are the controls. -->
11325
+ <button *ngIf="legacyControls && enableNavigation" class="slider-edit-nav slider-edit-nav--prev" data-iox-chrome
11186
11326
  (click)="_swiper?.slidePrev()" type="button" title="Previous slide">
11187
11327
  <i class="ph-thin ph-caret-left"></i>
11188
11328
  </button>
11189
- <button *ngIf="enableNavigation" class="slider-edit-nav slider-edit-nav--next" data-iox-chrome
11329
+ <button *ngIf="legacyControls && enableNavigation" class="slider-edit-nav slider-edit-nav--next" data-iox-chrome
11190
11330
  (click)="_swiper?.slideNext()" type="button" title="Next slide">
11191
11331
  <i class="ph-thin ph-caret-right"></i>
11192
11332
  </button>
@@ -11203,12 +11343,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
11203
11343
  [style.--swiper-navigation-color]="navigationColor || null"
11204
11344
  [style.--swiper-navigation-size.px]="navigationSize || null"
11205
11345
  [style.--swiper-pagination-color]="paginationColor || null">
11346
+ <ng-container *ngFor="let part of leadParts; trackBy: trackByNodeId">
11347
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11348
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11349
+ </ng-container>
11206
11350
  <div class="swiper-wrapper">
11207
11351
  <!-- Swiper requires .swiper-slide as a DIRECT child of .swiper-wrapper.
11208
11352
  Wrap each rendered slide in one (same structure as edit mode) so the
11209
11353
  app-slider-slide host sits INSIDE the slide, not between it and the wrapper. -->
11210
11354
  <ng-container *ngIf="!source">
11211
- <div *ngFor="let child of children"
11355
+ <div *ngFor="let child of slides; trackBy: trackByNodeId"
11212
11356
  class="swiper-slide"
11213
11357
  [ngClass]="['iox-outer-' + (child.styleId ?? child.id)]">
11214
11358
  <ng-container
@@ -11219,20 +11363,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
11219
11363
  </ng-container>
11220
11364
  </div>
11221
11365
  </ng-container>
11222
- <!-- REPEAT: template slide + preview slides -->
11366
+ <!-- REPEAT: template slide + preview slides; each is a row (a lightbox opens at the clicked one) -->
11223
11367
  <ng-container *ngIf="source">
11224
- <div *ngIf="children.length"
11368
+ <div *ngIf="slides.length"
11225
11369
  class="swiper-slide"
11226
- [ngClass]="['iox-outer-' + (children[0].styleId ?? children[0].id)]">
11370
+ [attr.data-iox-row-idx]="0"
11371
+ [ngClass]="['iox-outer-' + (slides[0].styleId ?? slides[0].id)]">
11227
11372
  <ng-container
11228
- [ioxRender]="children[0]"
11373
+ [ioxRender]="slides[0]"
11229
11374
  (onClick)="childClick.emit($event)"
11230
11375
  (onMouseEnter)="childMouseEnter.emit($event)"
11231
11376
  (onMouseLeave)="childMouseLeave.emit()">
11232
11377
  </ng-container>
11233
11378
  </div>
11234
- <div *ngFor="let slide of previewSlides; trackBy: trackByNodeId"
11379
+ <div *ngFor="let slide of previewSlides; let i = index; trackBy: trackByNodeId"
11235
11380
  class="swiper-slide"
11381
+ [attr.data-iox-row-idx]="i + 1"
11236
11382
  [ngClass]="['iox-outer-' + (slide.styleId ?? slide.id)]">
11237
11383
  <ng-container
11238
11384
  [ioxRender]="slide"
@@ -11243,9 +11389,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
11243
11389
  </div>
11244
11390
  </ng-container>
11245
11391
  </div>
11246
- <div *ngIf="enableNavigation" class="swiper-button-prev"></div>
11247
- <div *ngIf="enableNavigation" class="swiper-button-next"></div>
11248
- <div *ngIf="enablePagination" class="swiper-pagination"></div>
11392
+ <ng-container *ngFor="let part of trailParts; trackBy: trackByNodeId">
11393
+ <ng-container [ioxRender]="part" (onClick)="childClick.emit($event)"
11394
+ (onMouseEnter)="childMouseEnter.emit($event)" (onMouseLeave)="childMouseLeave.emit()"></ng-container>
11395
+ </ng-container>
11396
+ <div *ngIf="legacyControls && enableNavigation" class="swiper-button-prev"></div>
11397
+ <div *ngIf="legacyControls && enableNavigation" class="swiper-button-next"></div>
11398
+ <div *ngIf="legacyControls && enablePagination" class="swiper-pagination"></div>
11249
11399
  <div *ngIf="enableScrollbar" class="swiper-scrollbar"></div>
11250
11400
  </div>
11251
11401
  `, standalone: false, styles: [":host{display:block}.swiper-wrapper{height:auto}.slider-edit-shell{position:relative;display:block}.swiper-edit{width:100%}.swiper-edit .swiper-slide{position:relative}.slider-edit-nav{position:absolute;top:50%;transform:translateY(-50%);width:32px;height:32px;border-radius:50%;border:1px solid rgba(255,255,255,.5);background:#00000038;color:#fff;font-size:16px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:10;transition:background .15s}.slider-edit-nav:hover{background:#00000073}.slider-edit-nav--prev{left:8px}.slider-edit-nav--next{right:8px}.slider-edit-placeholder{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:1.5px dashed rgba(100,116,139,.35);border-radius:4px;color:#64748b80;font-size:12px;pointer-events:none;-webkit-user-select:none;user-select:none}.slider-edit-placeholder i{font-size:22px}.slider-repeat-badge{position:absolute;top:0;left:0;z-index:10;display:flex;align-items:center;gap:.4rem;padding:4px 8px;font-size:11px;color:#cb9090;background:#cb909014;border:1px solid rgba(203,144,144,.5);border-radius:0 0 4px;opacity:0;transition:opacity .15s;-webkit-user-select:none;user-select:none;pointer-events:none}.slider-edit-shell:hover .slider-repeat-badge{opacity:1}.slider-repeat-badge-count{font-weight:600}.slider-badge-spin{animation:slider-badge-spin 1s linear infinite}@keyframes slider-badge-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.slider-preview-slide{opacity:.55;pointer-events:none}\n"] }]
@@ -12404,6 +12554,7 @@ class DialogComponentConfig extends ComponentConfig {
12404
12554
  showCloseButton: 'checkbox',
12405
12555
  consentRole: 'checkbox',
12406
12556
  closeAbove: 'select',
12557
+ colorScheme: 'select',
12407
12558
  ariaLabel: 'text',
12408
12559
  };
12409
12560
  this.traits = [
@@ -12416,6 +12567,8 @@ class DialogComponentConfig extends ComponentConfig {
12416
12567
  new TraitConfig('consentRole', 'Consent banner role', TraitInputType.Checkbox, undefined, false),
12417
12568
  ...buildDialogCloseAboveTraits(),
12418
12569
  ...buildAccessibleNameTraits(),
12570
+ // CC3 (board 6): a dialog may wear a section colour scheme — the Lightbox is Inverse.
12571
+ buildColorSchemeTrait(),
12419
12572
  ];
12420
12573
  this.styleTraits = buildFullStyleTraits();
12421
12574
  this.applyStyleDefaults({
@@ -12610,6 +12763,64 @@ class GalleryConfig extends ComponentConfig {
12610
12763
  }
12611
12764
  }
12612
12765
 
12766
+ /**
12767
+ * Video (CC3 — complex-components plan §7b, board 5): a LEAF. The RENDER component is the shared `iox-video`
12768
+ * (`IoxVideoComponent` in @vectoriox/iox-ui) — the canvas shows its poster only; Preview and the live site run the
12769
+ * media-core runtime (the YouTube / Vimeo facade behind consent, the background video's pause button).
12770
+ *
12771
+ * Bindings ▸ Media · Behaviour · Accessibility · Privacy (boards 5 and 9). The address and the poster are bindable (a
12772
+ * project's video field) and work inside a Repeater. Background mode and autoplay act on an uploaded file; a YouTube
12773
+ * or Vimeo video is always the facade (D5) and plays on a click, after consent — the panel says so.
12774
+ */
12775
+ class VideoConfig extends ComponentConfig {
12776
+ constructor() {
12777
+ super('Video', 'iox-video', 'ph-thin ph-film-strip', 'Media');
12778
+ const embed = { trait: VideoTrait.Source, values: [VideoSource.YouTube, VideoSource.Vimeo] };
12779
+ const file = { trait: VideoTrait.Source, values: VideoSource.File };
12780
+ this.traits = [
12781
+ // ── Media ─────────────────────────────────────────────────────
12782
+ new TraitConfig('__mediaLabel', 'Media', TraitInputType.SectionLabel),
12783
+ new TraitConfig(VideoTrait.Source, 'Source', TraitInputType.Select, [
12784
+ { label: 'YouTube', value: VideoSource.YouTube },
12785
+ { label: 'Vimeo', value: VideoSource.Vimeo },
12786
+ { label: 'Uploaded file', value: VideoSource.File },
12787
+ ], VideoSource.YouTube),
12788
+ new TraitConfig(VideoTrait.Src, 'Video address', TraitInputType.Media, { mode: 'compact' }, ''),
12789
+ new TraitConfig(VideoTrait.Poster, 'Poster', TraitInputType.Media, { mode: 'compact' }, ''),
12790
+ // ── Behaviour ─────────────────────────────────────────────────
12791
+ new TraitConfig('__behaviourLabel', 'Behaviour', TraitInputType.SectionLabel),
12792
+ new TraitConfig(VideoTrait.Mode, 'Mode', TraitInputType.Select, [
12793
+ { label: 'Inline · with controls', value: VideoMode.Inline },
12794
+ { label: 'Background · muted loop', value: VideoMode.Background },
12795
+ ], VideoMode.Inline),
12796
+ new TraitConfig(VideoTrait.Autoplay, 'Autoplay (muted)', TraitInputType.Checkbox, undefined, false),
12797
+ // ── Accessibility ─────────────────────────────────────────────
12798
+ new TraitConfig('__accessibilityLabel', 'Accessibility', TraitInputType.SectionLabel),
12799
+ new TraitConfig(VideoTrait.Title, 'Title (names the play button)', TraitInputType.Text, undefined, ''),
12800
+ new TraitConfig(VideoTrait.Captions, 'Captions (.vtt)', TraitInputType.Media, { mode: 'compact' }, '', undefined, file),
12801
+ new TraitConfig(VideoTrait.CaptionsLang, 'Captions language', TraitInputType.Text, undefined, 'en', undefined, file),
12802
+ // ── Privacy ───────────────────────────────────────────────────
12803
+ new TraitConfig('__privacyLabel', 'Privacy', TraitInputType.SectionLabel),
12804
+ new TraitConfig(VideoTrait.Consent, 'Consent', TraitInputType.Select, [
12805
+ { label: 'Marketing', value: ConsentCategory.Marketing },
12806
+ ], ConsentCategory.Marketing, undefined, embed),
12807
+ ];
12808
+ // A media frame: size, spacing, border (radius), effects (the `media` style's transition and hover scale).
12809
+ this.styleTraits = [
12810
+ new PositionGroupStyleConfig(),
12811
+ new SizeGroupStyleConfig(),
12812
+ new SpacingGroupStyleConfig(),
12813
+ new BorderGroupStyleConfig(),
12814
+ new EffectsGroupStyleConfig(),
12815
+ ];
12816
+ // A 16 / 9 frame that fills its column — the size the poster and the player take.
12817
+ this.applyStyleDefaults({
12818
+ width: '100%',
12819
+ aspectRatio: '16 / 9',
12820
+ });
12821
+ }
12822
+ }
12823
+
12613
12824
  /**
12614
12825
  * Field's styleable sub-elements (board 7 — "the failure design"), for the Style panel's picker.
12615
12826
  * Class names come from the SHARED `PART_CLASS_NAMES` (`@vectoriox/iox-ui`) — the same map the
@@ -13232,6 +13443,11 @@ class SliderContainerConfig extends ComponentConfig {
13232
13443
  // ── Responsive ────────────────────────────────────────────────────
13233
13444
  new TraitConfig('__responsiveLabel', 'Responsive', TraitInputType.SectionLabel),
13234
13445
  new TraitConfig('breakpoints', 'Breakpoints (JSON)', TraitInputType.Textarea, undefined, ''),
13446
+ // ── Accessibility (CC3, board 6) ──────────────────────────────────
13447
+ // The carousel's name: a named carousel is a `region` landmark ("What clients say"). The pause control
13448
+ // is a part added while Autoplay is on (WCAG 2.2.2) — the panel says so under this group.
13449
+ new TraitConfig('__accessibilityLabel', 'Accessibility', TraitInputType.SectionLabel),
13450
+ new TraitConfig(A11yTrait.AccessibleName, 'Carousel name', TraitInputType.Text, undefined, ''),
13235
13451
  ];
13236
13452
  this.styleTraits = [
13237
13453
  new PositionGroupStyleConfig(),
@@ -13265,5 +13481,5 @@ class BuilderSpacerComponentConfig extends ComponentConfig {
13265
13481
  * Generated bundle index. Do not edit.
13266
13482
  */
13267
13483
 
13268
- export { ACTION_TYPE_OPTIONS, AuditCode, AuditPanelComponent, AuditSeverity, BODY_CRUMB_LABEL, BOUND_ICON, BREAKPOINT_PRESENTATION, BUILDER_CANVAS_CONTAINER, BUILDER_CHROME_EN, BUILDER_FONT_LINK_ATTR, BUILDER_TOKEN_SCOPE_CLASS, BackgroundGroupStyleConfig, BorderGroupStyleConfig, BreadcrumbBarComponent, BuilderButtonBlockComponent, BuilderButtonComponentConfig, BuilderClipboardService, BuilderComponent, BuilderContainerComponent, BuilderContainerComponentConfig, BuilderDataSourceService, BuilderDialogComponent, BuilderDividerComponentConfig, BuilderHeadingComponentConfig, BuilderHistoryService, BuilderIconComponentConfig, BuilderImageComponentConfig, BuilderLinkComponentConfig, BuilderLinkedContainerComponent, BuilderLinkedContainerConfig, BuilderListComponentConfig, BuilderListItemComponentConfig, BuilderMode, BuilderRepeaterComponent, BuilderSpacerComponentConfig, ButtonBlockComponentConfig, CANVAS_EMPTY_IMAGE_LABEL_EN, CANVAS_EMPTY_IMAGE_LABEL_KEY, CANVAS_ROOT_RESET_CSS, COMPOSITE_PRESETS, CanvasDesignStateService, CanvasShowState, CardComponentConfig, ChildLayoutGroupStyleConfig, ComponentConfig, ComponentRegistryService, CompositeCanvasService, CompositePaletteGroup, CompositePresetId, DEFAULT_ESSENTIAL_TRAITS, DESCRIPTOR_MAX_LENGTH, DRAG_HANDLE_ATTR, DROP_REFUSED_CLASS, DataSourceRegistryService, DataSourceType, DialogComponentConfig, DimensionsGroupStyleConfig, DragEngineService, EASING_OPTIONS$1 as EASING_OPTIONS, EDITOR_CHROME_ATTRIBUTE, ESSENTIAL_TRAITS_BY_TYPE, EffectsGroupStyleConfig, FIELD_KIND_PRESETS, FIELD_PARTS, FORM_STATE_BLOCK_TYPES, FORM_TYPE, FieldComponentConfig, FieldGroupComponentConfig, FormComponentConfig, FormErrorComponentConfig, FormStateService, FormSuccessComponentConfig, GLOBALS_AFTER_CLASS, GalleryConfig, GlobalCanvasLayer, GroupStyleConfig, HIDDEN_AT_REST_LABEL_KEY, HIDDEN_AT_REST_ROLES, HIDDEN_AT_REST_TYPES, INSERT_REFUSAL_LABEL_KEYS, INTERACTION_STATES, INVERSE_ACTION, IOX_BUILDER_CANVAS, IOX_BUILDER_LABELS, IOX_DATA_SOURCE_ENDPOINTS, InsertRefusal, InteractionEngineService, InteractionPresetRegistryService, IoxBuilderModule, IoxDraggableDirective, IoxDropzoneDirective, LAYOUT_PRESETS, LayerTreeComponent, LayoutGroupStyleConfig, ListGroupStyleConfig, NodeAction, OverlayComponent, OverlayService, PALETTE_PRESET_DEFS, PanelChildComponent, PanelComponent, PanelEventService, PanelEventTypes, PanelTypes, PositionGroupStyleConfig, PresetRegistryService, RELATIONAL_STATES, RELATIONAL_STATE_BASE, REPEATER_SOURCE_PROP, REPEATER_TYPE, ROOT_ESCAPE_PX, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, RootZone, SCREEN_WIDTH_OPTIONS, STRUCTURAL_STATES, SUPPORTED_STATES, SectionComponent, SectionComponentConfig, SelectionReveal, SizeGroupStyleConfig, SliderContainerComponent, SliderContainerConfig, SliderSlideComponent, SliderSlideConfig, SpacingGroupStyleConfig, StructureFix, StyleCategory, StyleRegistryService, TraitConfig as StyleTraitConfig, SubmitButtonComponentConfig, SymbolRegistryService, TARGETED_STATES, TARGETED_STATE_BASE, TRIGGER_OPTIONS, TextBlockComponentConfig, ToolbarAction, ToolbarComponent, TraitConfig, TraitInputType, TypographyGroupStyleConfig, UNITS_ALL, UNITS_DEG, UNITS_FIXED, UNITS_NO_VW, VALIDATION_STATES, VALIDATION_STATE_CLASS, ViewportService, ZOOM_OPTIONS, arrayItemSchemaFields, arraySchemaFields, auditNodes, bindingLabel, bindingLabels, buildCompositePreset, buildConsentPreset, buildElementStyleSpecimen, buildFieldKindPreset, buildFlavorSpecimen, buildFormPreset, buildFullStyleTraits, buildLayoutPreset, buildPalettePreset, buildPresetStyleTraits, builderCompositeFactory, canFluidise, canvasEmptyImageLabel, collapseColumnsProps, columnCountOf, defaultBuilderLabels, defaultPageSettings, dropChildren, dropTargetLabel, escapesRoot, essentialTraitsFor, findNodeLocation, findParentOf, flattenLayerTree, flattenSchemaFields, fluidiseProps, generateNodeId, globalCanvasLayer, insertRefusal, insertRefusalLabel, isHiddenAt, isHiddenAtRest, isPinnedGlobal, isSpecimen, markSpecimen, matchesControlSearch, nearestFormNode, nodeAncestorPath, nodeAncestorPathInEither, nodeDescriptor, nodeStyleMap, overlayGlobals, pathToNode, refreshSubtree, regenerateNodeIds, removalRefusal, reorderProps, repeaterSourceAlias, repeaterSubLabel, resolveInsertTarget, resolveTraitControllerType, resolveTraitOptions, retypeNode, rootEscapeBand, rootZone, selectionRevealOf, setStyleTrait, setTrait, shortDescriptor, stackChildrenProps, summarise, syncEmptyImagePlaceholder, syncNodeDesign, syncNodeInputs, textNode, upsertNodeStyles, visibilityProps, walkNodes, wrapNode };
13484
+ export { ACTION_TYPE_OPTIONS, AuditCode, AuditPanelComponent, AuditSeverity, BODY_CRUMB_LABEL, BOUND_ICON, BREAKPOINT_PRESENTATION, BUILDER_CANVAS_CONTAINER, BUILDER_CHROME_EN, BUILDER_FONT_LINK_ATTR, BUILDER_TOKEN_SCOPE_CLASS, BackgroundGroupStyleConfig, BorderGroupStyleConfig, BreadcrumbBarComponent, BuilderButtonBlockComponent, BuilderButtonComponentConfig, BuilderClipboardService, BuilderComponent, BuilderContainerComponent, BuilderContainerComponentConfig, BuilderDataSourceService, BuilderDialogComponent, BuilderDividerComponentConfig, BuilderHeadingComponentConfig, BuilderHistoryService, BuilderIconComponentConfig, BuilderImageComponentConfig, BuilderLinkComponentConfig, BuilderLinkedContainerComponent, BuilderLinkedContainerConfig, BuilderListComponentConfig, BuilderListItemComponentConfig, BuilderMode, BuilderRepeaterComponent, BuilderSpacerComponentConfig, ButtonBlockComponentConfig, CANVAS_EMPTY_IMAGE_LABEL_EN, CANVAS_EMPTY_IMAGE_LABEL_KEY, CANVAS_ROOT_RESET_CSS, COMPOSITE_PRESETS, CanvasDesignStateService, CanvasShowState, CardComponentConfig, ChildLayoutGroupStyleConfig, ComponentConfig, ComponentRegistryService, CompositeCanvasService, CompositePaletteGroup, CompositePresetId, DEFAULT_ESSENTIAL_TRAITS, DESCRIPTOR_MAX_LENGTH, DRAG_HANDLE_ATTR, DROP_REFUSED_CLASS, DataSourceRegistryService, DataSourceType, DialogComponentConfig, DimensionsGroupStyleConfig, DragEngineService, EASING_OPTIONS$1 as EASING_OPTIONS, EDITOR_CHROME_ATTRIBUTE, ESSENTIAL_TRAITS_BY_TYPE, EffectsGroupStyleConfig, FIELD_KIND_PRESETS, FIELD_PARTS, FORM_STATE_BLOCK_TYPES, FORM_TYPE, FieldComponentConfig, FieldGroupComponentConfig, FormComponentConfig, FormErrorComponentConfig, FormStateService, FormSuccessComponentConfig, GLOBALS_AFTER_CLASS, GalleryConfig, GlobalCanvasLayer, GroupStyleConfig, HIDDEN_AT_REST_LABEL_KEY, HIDDEN_AT_REST_ROLES, HIDDEN_AT_REST_TYPES, INSERT_REFUSAL_LABEL_KEYS, INTERACTION_STATES, INVERSE_ACTION, IOX_BUILDER_CANVAS, IOX_BUILDER_LABELS, IOX_CONTENT_TYPE_LABELS, IOX_DATA_SOURCE_ENDPOINTS, InsertRefusal, InteractionEngineService, InteractionPresetRegistryService, IoxBuilderModule, IoxDraggableDirective, IoxDropzoneDirective, LAYOUT_PRESETS, LayerTreeComponent, LayoutGroupStyleConfig, ListGroupStyleConfig, NodeAction, OverlayComponent, OverlayService, PALETTE_PRESET_DEFS, PanelChildComponent, PanelComponent, PanelEventService, PanelEventTypes, PanelTypes, PositionGroupStyleConfig, PresetRegistryService, RELATIONAL_STATES, RELATIONAL_STATE_BASE, REPEATER_SOURCE_PROP, REPEATER_TYPE, ROOT_ESCAPE_PX, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, RootZone, SCREEN_WIDTH_OPTIONS, STRUCTURAL_STATES, SUPPORTED_STATES, SectionComponent, SectionComponentConfig, SelectionReveal, SizeGroupStyleConfig, SliderContainerComponent, SliderContainerConfig, SliderSlideComponent, SliderSlideConfig, SpacingGroupStyleConfig, StructureFix, StyleCategory, StyleRegistryService, TraitConfig as StyleTraitConfig, SubmitButtonComponentConfig, SymbolRegistryService, TARGETED_STATES, TARGETED_STATE_BASE, TOGGLE_PART_ROLES, TRIGGER_OPTIONS, TextBlockComponentConfig, ToolbarAction, ToolbarComponent, TraitConfig, TraitInputType, TypographyGroupStyleConfig, UNITS_ALL, UNITS_DEG, UNITS_FIXED, UNITS_NO_VW, VALIDATION_STATES, VALIDATION_STATE_CLASS, VideoConfig, ViewportService, ZOOM_OPTIONS, arrayItemSchemaFields, arraySchemaFields, auditNodes, bindingLabel, bindingLabels, buildCompositePreset, buildConsentPreset, buildElementStyleSpecimen, buildFieldKindPreset, buildFlavorSpecimen, buildFormPreset, buildFullStyleTraits, buildLayoutPreset, buildPalettePreset, buildPresetStyleTraits, builderCompositeFactory, canFluidise, canvasEmptyImageLabel, collapseColumnsProps, columnCountOf, defaultBuilderLabels, defaultPageSettings, dropChildren, dropTargetLabel, escapesRoot, essentialTraitsFor, findNodeLocation, findParentOf, flattenLayerTree, flattenSchemaFields, fluidiseProps, generateNodeId, globalCanvasLayer, insertRefusal, insertRefusalLabel, isHiddenAt, isHiddenAtRest, isPinnedGlobal, isSpecimen, markSpecimen, matchesControlSearch, nearestFormNode, nodeAncestorPath, nodeAncestorPathInEither, nodeDescriptor, nodeStyleMap, overlayGlobals, pathToNode, refreshSubtree, regenerateNodeIds, removalRefusal, reorderProps, repeaterSourceAlias, repeaterSubLabel, resolveInsertTarget, resolveTraitControllerType, resolveTraitOptions, retypeNode, rootEscapeBand, rootZone, selectionRevealOf, setStyleTrait, setTrait, shortDescriptor, sourceContentType, sourceTypeLabel, stackChildrenProps, summarise, syncEmptyImagePlaceholder, syncNodeDesign, syncNodeInputs, textNode, upsertNodeStyles, visibilityProps, walkNodes, wrapNode };
13269
13485
  //# sourceMappingURL=vectoriox-iox-builder.mjs.map