@vectoriox/iox-builder 6.1.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,7 +16,7 @@ import { SelectModule } from 'primeng/select';
16
16
  import { TooltipModule } from 'primeng/tooltip';
17
17
  import { DialogModule } from 'primeng/dialog';
18
18
  import * as i1 from '@vectoriox/iox-ui';
19
- import { VALIDATION_STATES as VALIDATION_STATES$1, VALIDATION_STATE_CLASS as VALIDATION_STATE_CLASS$1, DEFAULT_WIDTH_BY_TYPE, COLOR_SCHEME_TRAIT, COLOR_SCHEMES, ColorScheme, Breakpoint, BREAKPOINTS, countOverrides, setOverride, defaultElementStyleFor, applyElementStyle, stripSuppressedProps, DeclarationContext, buildPartSelector, planResponsiveRules, resolveStyleProps, buildTargetedStateSelector, statePseudoClass, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, wrapInBreakpointQuery, BreakpointQueryKind, breakpointDef, breakpointForWidth, FormRenderState, safeSetInput, ContextStore, ComponentInstanceRegistryService, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, declaredInputNames, emptyImagePlaceholder, syncNodeDesignClasses, composeVirtualTraits, withDefaultHoverTransition, stateNamesIn, partClassName, resolveInputs, setInputOverride, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, resolveBoundValue, IS_PREVIEW, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, IoxPageModule, PALETTE_PRESETS, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
19
+ import { VALIDATION_STATES as VALIDATION_STATES$1, VALIDATION_STATE_CLASS as VALIDATION_STATE_CLASS$1, DEFAULT_WIDTH_BY_TYPE, COLOR_SCHEME_TRAIT, COLOR_SCHEMES, ColorScheme, Breakpoint, BREAKPOINTS, countOverrides, setOverride, defaultElementStyleFor, applyElementStyle, stripSuppressedProps, DeclarationContext, buildPartSelector, planResponsiveRules, resolveStyleProps, buildTargetedStateSelector, statePseudoClass, compileTokenCssBlocks, catalogFontId, fontsForTokens, GOOGLE_FONTS_FILE_ORIGIN, googleFontHref, compileDeclarations, wrapInBreakpointQuery, BreakpointQueryKind, breakpointDef, breakpointForWidth, FormRenderState, safeSetInput, ContextStore, ComponentInstanceRegistryService, isActionEnabled, isContextAction, contextActionEffect, resolveContextValue, declaredInputNames, emptyImagePlaceholder, syncNodeDesignClasses, composeVirtualTraits, withDefaultHoverTransition, stateNamesIn, partClassName, resolveInputs, setInputOverride, collectContextSlotKeys, withContextSlots, compilePageStyle, nodeUsesContext, resolveBoundValue, IS_PREVIEW, planDataSource, dataSourcePlanToRequest, normalizeCollectionResult, resolveRepeaterItems, getByPath, computeRelative, IoxPageModule, PALETTE_PRESETS, elementStyleById, PART_CLASS_NAMES } from '@vectoriox/iox-ui';
20
20
  export { ComponentInstanceRegistryService, VIRTUAL_TRAIT_KEYS, composeVirtualTraits } from '@vectoriox/iox-ui';
21
21
  import Lenis from 'lenis';
22
22
  import { Subject, BehaviorSubject, of, forkJoin } from 'rxjs';
@@ -2314,11 +2314,19 @@ class StyleRegistryService {
2314
2314
  * Poppins. Links stay for the session: a trial that switches back costs no refetch.
2315
2315
  */
2316
2316
  loadTokenFonts(nodeCss) {
2317
- const head = this.styleEl?.ownerDocument?.head;
2318
- if (!head)
2319
- return;
2320
- const ids = fontsForTokens(this.tokenRows, { usedCss: nodeCss, uploaded: this.uploadedFamilies });
2321
- if (!ids.length)
2317
+ this.linkFonts(fontsForTokens(this.tokenRows, { usedCss: nodeCss, uploaded: this.uploadedFamilies }));
2318
+ }
2319
+ /**
2320
+ * Link the Google families OTHER rows name — a specimen wearing another look (the Design side-card's
2321
+ * Look tiles and pairing cards). The same catalog, URL and dedupe as the canvas's own fonts, so a
2322
+ * look that is later tried or applied costs no second fetch. Never touches the canvas's tokens.
2323
+ */
2324
+ loadFontsFor(tokens) {
2325
+ this.linkFonts(fontsForTokens(tokens ?? [], { uploaded: this.uploadedFamilies }));
2326
+ }
2327
+ linkFonts(ids) {
2328
+ const head = this.styleEl?.ownerDocument?.head ?? (typeof document !== 'undefined' ? document.head : null);
2329
+ if (!head || !ids.length)
2322
2330
  return;
2323
2331
  const doc = head.ownerDocument;
2324
2332
  if (!head.querySelector(`link[rel="preconnect"][${BUILDER_FONT_LINK_ATTR}]`)) {
@@ -10425,8 +10433,8 @@ const click = (actions) => ({
10425
10433
  target: 'self', duration: 0, delay: 0, easing: 'ease', ...a,
10426
10434
  })),
10427
10435
  });
10428
- const TOKEN$1 = (name, fallback) => `var(--iox-${name}, ${fallback})`;
10429
- function button(label, createConfig, interaction, styles = {}) {
10436
+ const TOKEN = (name, fallback) => `var(--iox-${name}, ${fallback})`;
10437
+ function button$1(label, createConfig, interaction, styles = {}) {
10430
10438
  const btn = createConfig('ButtonBlock');
10431
10439
  const text = textNode(label, createConfig);
10432
10440
  if (!btn || !text)
@@ -10445,20 +10453,20 @@ function button(label, createConfig, interaction, styles = {}) {
10445
10453
  // width:'auto' + flexShrink:'0' on every voice: a consent button never stretches to its row's
10446
10454
  // height nor shrinks until its label wraps — both happened on the canvas (Rule 0, 2026-10-10).
10447
10455
  const SOLID = {
10448
- backgroundColor: TOKEN$1('brand-500', '#1f1d1b'), color: TOKEN$1('brandInk', '#ffffff'),
10456
+ backgroundColor: TOKEN('brand-500', '#1f1d1b'), color: TOKEN('brandInk', '#ffffff'),
10449
10457
  fontSize: '12px', fontWeight: '600', padding: '9px 16px',
10450
- borderRadius: TOKEN$1('radius-control', '4px'),
10458
+ borderRadius: TOKEN('radius-control', '4px'),
10451
10459
  width: 'auto', flexShrink: '0',
10452
10460
  };
10453
10461
  const OUTLINED = {
10454
- backgroundColor: 'transparent', color: TOKEN$1('ink', '#1f1d1b'),
10455
- borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('ink', '#1f1d1b'),
10462
+ backgroundColor: 'transparent', color: TOKEN('ink', '#1f1d1b'),
10463
+ borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN('ink', '#1f1d1b'),
10456
10464
  fontSize: '12px', fontWeight: '600', padding: '8px 16px',
10457
- borderRadius: TOKEN$1('radius-control', '4px'),
10465
+ borderRadius: TOKEN('radius-control', '4px'),
10458
10466
  width: 'auto', flexShrink: '0',
10459
10467
  };
10460
10468
  const QUIET = {
10461
- backgroundColor: 'transparent', color: TOKEN$1('inkMuted', '#4a453f'),
10469
+ backgroundColor: 'transparent', color: TOKEN('inkMuted', '#4a453f'),
10462
10470
  fontSize: '11px', fontWeight: '400', padding: '2px 4px', textDecoration: 'underline',
10463
10471
  width: 'auto', flexShrink: '0',
10464
10472
  };
@@ -10491,26 +10499,26 @@ function buildConsentPreset(createConfig) {
10491
10499
  setStyleTrait(banner, 'width', '100%');
10492
10500
  setStyleTrait(banner, 'borderRadius', '0px');
10493
10501
  setStyleTrait(banner, 'padding', '14px 20px');
10494
- setStyleTrait(banner, 'backgroundColor', TOKEN$1('surface', '#ffffff'));
10502
+ setStyleTrait(banner, 'backgroundColor', TOKEN('surface', '#ffffff'));
10495
10503
  setStyleTrait(banner, 'borderWidth', '1px');
10496
10504
  setStyleTrait(banner, 'borderStyle', 'solid');
10497
- setStyleTrait(banner, 'borderColor', TOKEN$1('ink', '#1f1d1b'));
10505
+ setStyleTrait(banner, 'borderColor', TOKEN('ink', '#1f1d1b'));
10498
10506
  setStyleTrait(banner, 'boxShadow', 'none');
10499
- const heading = text$1('Cookies on this site', { fontSize: '13px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
10507
+ const heading = text$1('Cookies on this site', { fontSize: '13px', fontWeight: '600', color: TOKEN('ink', '#1f1d1b') }, createConfig);
10500
10508
  // The first layer NAMES the three categories (plan §7) — the board does it in the copy.
10501
- const body = text$1('We use analytics and marketing cookies only if you allow them. Necessary ones always run.', { fontSize: '11px', color: TOKEN$1('inkMuted', '#4a453f'), lineHeight: '1.5', maxWidth: '330px' }, createConfig);
10509
+ const body = text$1('We use analytics and marketing cookies only if you allow them. Necessary ones always run.', { fontSize: '11px', color: TOKEN('inkMuted', '#4a453f'), lineHeight: '1.5', maxWidth: '330px' }, createConfig);
10502
10510
  // width:'auto' throughout — the Container default is 100%, and two 100%-wide columns
10503
10511
  // cannot share the bar's row (they wrap into a stack; Rule 0 catch, 2026-10-10).
10504
10512
  const textCol = row(createConfig, { display: 'flex', flexDirection: 'column', gap: '4px', flexGrow: '1', width: 'auto' }, [heading, body]);
10505
- const accept = button('Accept all', createConfig, click([
10513
+ const accept = button$1('Accept all', createConfig, click([
10506
10514
  { type: 'grantConsent' },
10507
10515
  { type: 'closeDialog', target: banner.id },
10508
10516
  ]), SOLID);
10509
- const reject = button('Reject all', createConfig, click([
10517
+ const reject = button$1('Reject all', createConfig, click([
10510
10518
  { type: 'denyConsent' },
10511
10519
  { type: 'closeDialog', target: banner.id },
10512
10520
  ]), OUTLINED);
10513
- const prefs = button('Preferences', createConfig, click([
10521
+ const prefs = button$1('Preferences', createConfig, click([
10514
10522
  { type: 'openConsentPreferences', target: preferences.id },
10515
10523
  ]), QUIET);
10516
10524
  const acceptRejectRow = row(createConfig, { display: 'flex', gap: '7px', alignItems: 'center', width: 'auto' }, [accept, reject]);
@@ -10528,19 +10536,19 @@ function buildConsentPreset(createConfig) {
10528
10536
  setStyleTrait(preferences, 'display', 'flex');
10529
10537
  setStyleTrait(preferences, 'flexDirection', 'column');
10530
10538
  setStyleTrait(preferences, 'gap', '12px');
10531
- const prefsHeading = text$1('Your privacy choices', { fontSize: '16px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
10532
- const prefsSub = text$1('Change these any time from “Cookie settings” in the footer.', { fontSize: '12px', color: TOKEN$1('inkMuted', '#6b6560') }, createConfig);
10539
+ const prefsHeading = text$1('Your privacy choices', { fontSize: '16px', fontWeight: '600', color: TOKEN('ink', '#1f1d1b') }, createConfig);
10540
+ const prefsSub = text$1('Change these any time from “Cookie settings” in the footer.', { fontSize: '12px', color: TOKEN('inkMuted', '#6b6560') }, createConfig);
10533
10541
  const CARD = {
10534
10542
  display: 'flex', gap: '12px', alignItems: 'flex-start',
10535
- borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('line', '#e6e3e1'),
10536
- borderRadius: TOKEN$1('radius-surface', '8px'), padding: '12px 14px',
10543
+ borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN('line', '#e6e3e1'),
10544
+ borderRadius: TOKEN('radius-surface', '8px'), padding: '12px 14px',
10537
10545
  };
10538
- const nameText = (s) => text$1(s, { fontSize: '13px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
10539
- const descText = (s) => text$1(s, { fontSize: '11px', color: TOKEN$1('inkMuted', '#6b6560'), lineHeight: '1.5' }, createConfig);
10546
+ const nameText = (s) => text$1(s, { fontSize: '13px', fontWeight: '600', color: TOKEN('ink', '#1f1d1b') }, createConfig);
10547
+ const descText = (s) => text$1(s, { fontSize: '11px', color: TOKEN('inkMuted', '#6b6560'), lineHeight: '1.5' }, createConfig);
10540
10548
  const textColOf = (name, desc) => row(createConfig, { display: 'flex', flexDirection: 'column', gap: '2px', flexGrow: '1', width: 'auto' }, [nameText(name), descText(desc)]);
10541
10549
  const alwaysOn = text$1('ALWAYS ON', {
10542
- fontSize: '10px', fontWeight: '600', color: TOKEN$1('inkMuted', '#6b6560'),
10543
- borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('line', '#e6e3e1'),
10550
+ fontSize: '10px', fontWeight: '600', color: TOKEN('inkMuted', '#6b6560'),
10551
+ borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN('line', '#e6e3e1'),
10544
10552
  borderRadius: '999px', padding: '3px 8px',
10545
10553
  width: 'auto', flexShrink: '0', // a chip hugs its word (Text defaults to 100%)
10546
10554
  }, createConfig);
@@ -10566,14 +10574,14 @@ function buildConsentPreset(createConfig) {
10566
10574
  const analyticsCard = categoryCard('analytics', 'Analytics', 'Anonymous counts of visits and pages. Off means the analytics script never loads.');
10567
10575
  const marketingCard = categoryCard('marketing', 'Marketing', 'Ads measurement and remarketing. Off means no ad cookies and no data shared.');
10568
10576
  // Board C2's footer: bulk exits live here too — Reject | (grow) | Done | Accept.
10569
- const prefsReject = button('Reject all', createConfig, click([
10577
+ const prefsReject = button$1('Reject all', createConfig, click([
10570
10578
  { type: 'denyConsent' },
10571
10579
  { type: 'closeDialog', target: preferences.id },
10572
10580
  ]), OUTLINED);
10573
- const prefsDone = button('Done', createConfig, click([
10581
+ const prefsDone = button$1('Done', createConfig, click([
10574
10582
  { type: 'closeDialog', target: preferences.id },
10575
- ]), { ...OUTLINED, color: TOKEN$1('inkMuted', '#3d3833'), borderColor: TOKEN$1('line', '#d8d4d1') });
10576
- const prefsAccept = button('Accept all', createConfig, click([
10583
+ ]), { ...OUTLINED, color: TOKEN('inkMuted', '#3d3833'), borderColor: TOKEN('line', '#d8d4d1') });
10584
+ const prefsAccept = button$1('Accept all', createConfig, click([
10577
10585
  { type: 'grantConsent' },
10578
10586
  { type: 'closeDialog', target: preferences.id },
10579
10587
  ]), SOLID);
@@ -10586,7 +10594,7 @@ function buildConsentPreset(createConfig) {
10586
10594
  return null;
10587
10595
  preferences.children = [prefsHeading, prefsSub, necessaryCard, analyticsCard, marketingCard, footer];
10588
10596
  // ── the withdrawal path (§7.3) ───────────────────────────────────────────
10589
- const withdrawal = button('Cookie settings', createConfig, click([
10597
+ const withdrawal = button$1('Cookie settings', createConfig, click([
10590
10598
  { type: 'openConsentPreferences', target: preferences.id },
10591
10599
  ]), QUIET);
10592
10600
  if (!withdrawal)
@@ -10596,17 +10604,23 @@ function buildConsentPreset(createConfig) {
10596
10604
  }
10597
10605
 
10598
10606
  /**
10599
- * THE FLAVOR SAMPLER (flavors plan §7, F2) — the fixed tree the picker renders through the REAL
10600
- * builder pipeline with candidate tokens applied. Never a screenshot, never a second renderer:
10601
- * `render-parity.md` is the record of what a convenience renderer costs.
10607
+ * THE DESIGN SPECIMENS (design-system plan §5, Board 6) — the small trees the Design side-card
10608
+ * renders through the REAL builder pipeline (`[ioxRender]`), never a hand-drawn HTML mock: a look's
10609
+ * tile on the Look tab, and one specimen per element style on the Element styles tab. Every node is
10610
+ * a real config wearing a real element style, so what the author sees is what the style renders.
10611
+ *
10612
+ * Specimens are display-only: every node is marked like a repeater's preview clone, so the canvas
10613
+ * never registers, selects or drags one (RenderDirective skips overlay wiring for them).
10602
10614
  *
10603
- * Every colour in it is a token REFERENCE with a Swiss-neutral fallback — so before a brand is
10604
- * chosen the sampler is the monochrome study the F1 board shows, and the moment candidate tokens
10605
- * are upserted it recolours live (the F2 board), proving the exact mechanism a later re-theme
10606
- * uses on a built site: nothing moves, only tokens change.
10615
+ * The words come from the host (translated); the only sizes set here are the board's specimen
10616
+ * scale-downs (a Display heading at 24px fits a 36%-wide card; the live style does not).
10607
10617
  */
10608
- const BRAND = (step, fallback) => `var(--iox-brand-${step}, ${fallback})`;
10609
- const TOKEN = (name, fallback) => `var(--iox-${name}, ${fallback})`;
10618
+ /** What a specimen node is marked with — RenderDirective's "display only" flag. */
10619
+ const SPECIMEN_FLAG = '__previewClone';
10620
+ /** Board 6's specimen font sizes for the heading styles — the live sizes do not fit the card. */
10621
+ const HEADING_SPECIMEN_SIZE = { display: '24px', h1: '21px', h2: '18px', h3: '15px' };
10622
+ /** The four dots on a look's tile, left to right (Board 6 `TILE`). */
10623
+ const TILE_DOTS = ['accent', 'text', 'surface-2', 'line-strong'];
10610
10624
  function styled(node, styles) {
10611
10625
  if (!node)
10612
10626
  return null;
@@ -10614,90 +10628,149 @@ function styled(node, styles) {
10614
10628
  setStyleTrait(node, prop, value);
10615
10629
  return node;
10616
10630
  }
10617
- function text(content, styles, createConfig) {
10618
- return styled(textNode(content, createConfig), styles);
10631
+ function wearing(node, styleId) {
10632
+ if (!node)
10633
+ return null;
10634
+ applyElementStyle(node, styleId);
10635
+ return node;
10636
+ }
10637
+ function text(content, createConfig, styleId, styles = {}) {
10638
+ const node = textNode(content, createConfig);
10639
+ if (styleId)
10640
+ wearing(node, styleId);
10641
+ return styled(node, styles);
10619
10642
  }
10620
- function sampleCard(title, meta, createConfig) {
10621
- const card = createConfig('Card');
10622
- if (!card)
10643
+ function withChildren(node, children) {
10644
+ if (!node || children.some(c => !c))
10623
10645
  return null;
10624
- styled(card, {
10625
- backgroundColor: TOKEN('surface', '#ffffff'),
10626
- borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN('line', '#949494'),
10627
- padding: '10px', display: 'flex', flexDirection: 'column', gap: '8px', width: '150px',
10628
- });
10629
- const media = styled(createConfig('Container'), {
10630
- height: '48px', width: '100%', backgroundColor: BRAND(50, '#ebe8e5'),
10631
- });
10632
- const name = text(title, { fontSize: '12px', fontWeight: '600', color: TOKEN('ink', '#1f1d1b') }, createConfig);
10633
- const sub = text(meta, { fontSize: '11px', color: TOKEN('inkMuted', '#6b6560') }, createConfig);
10634
- if (!media || !name || !sub)
10646
+ node.children = children;
10647
+ return node;
10648
+ }
10649
+ /** Mark a tree display-only (not selectable, not draggable). Returns the root. */
10650
+ function markSpecimen(root) {
10651
+ if (!root)
10652
+ return root;
10653
+ root[SPECIMEN_FLAG] = true;
10654
+ for (const child of root.children ?? [])
10655
+ markSpecimen(child);
10656
+ return root;
10657
+ }
10658
+ /** Whether a node was built as a specimen. */
10659
+ function isSpecimen(node) {
10660
+ return !!node?.[SPECIMEN_FLAG];
10661
+ }
10662
+ function button(styleId, label, createConfig, styles = {}) {
10663
+ const btn = wearing(createConfig('ButtonBlock'), styleId);
10664
+ if (!btn)
10635
10665
  return null;
10636
- card.children = [media, name, sub];
10637
- return card;
10666
+ setTrait(btn, 'tag', 'button');
10667
+ styled(btn, styles);
10668
+ return withChildren(btn, [text(label, createConfig, undefined, { color: 'inherit' })]);
10669
+ }
10670
+ function boxed(styleId, createConfig, children, styles) {
10671
+ return withChildren(styled(wearing(createConfig('Container'), styleId), styles), children);
10638
10672
  }
10639
10673
  /**
10640
- * Build the sampler tree (the F1/F2 boards' hero + two cards). Null when a type is missing —
10641
- * a picker that previews half a sampler would be lying about the flavor.
10674
+ * The specimen for one element style (Board 6, Element styles tab). Null for an unknown id or a
10675
+ * missing type — a list that shows half a specimen would be lying about the style.
10642
10676
  */
10643
- function buildFlavorSampler(createConfig) {
10644
- const root = styled(createConfig('Container'), {
10645
- display: 'flex', gap: '20px', alignItems: 'stretch', width: '100%',
10646
- padding: '18px 22px', backgroundColor: TOKEN('surface', '#ffffff'),
10647
- });
10648
- if (!root)
10677
+ function buildElementStyleSpecimen(id, createConfig, copy) {
10678
+ const style = elementStyleById(id);
10679
+ if (!style)
10649
10680
  return null;
10650
- root.label = 'Flavor sampler';
10651
- const hero = styled(createConfig('Container'), {
10652
- display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: '10px', flexGrow: '1',
10653
- });
10654
- // Rendered already-uppercase: textTransform is not in the style-trait vocabulary, and the
10655
- // sampler only uses traits that LAND (asserted in the spec — setStyleTrait no-ops silently).
10656
- const badge = text('STUDIO', {
10657
- fontSize: '10px', letterSpacing: '0.14em',
10658
- fontWeight: '600', color: BRAND(600, '#6b6560'),
10659
- }, createConfig);
10660
- const heading = text('Interiors, measured twice.', {
10661
- fontSize: '30px', fontWeight: '600', lineHeight: '1.05', letterSpacing: '-0.02em',
10662
- maxWidth: '320px', color: TOKEN('ink', '#1f1d1b'),
10663
- }, createConfig);
10664
- const button = (label, styles) => {
10665
- const btn = createConfig('ButtonBlock');
10666
- const inner = text(label, { fontSize: '12px', fontWeight: '600', color: 'inherit' }, createConfig);
10667
- if (!btn || !inner)
10668
- return null;
10669
- setTrait(btn, 'tag', 'button');
10670
- styled(btn, styles);
10671
- btn.children = [inner];
10672
- return btn;
10673
- };
10674
- const primary = button('Book a visit', {
10675
- backgroundColor: BRAND(500, '#1f1d1b'), color: TOKEN('brandInk', '#ffffff'),
10676
- });
10677
- const secondary = button('Our work', {
10678
- backgroundColor: 'transparent', color: TOKEN('ink', '#1f1d1b'),
10679
- borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN('ink', '#1f1d1b'),
10681
+ let root = null;
10682
+ switch (style.group) {
10683
+ case 'Buttons':
10684
+ root = button(id, copy.label, createConfig);
10685
+ break;
10686
+ case 'Headings':
10687
+ if (id === 'eyebrow') {
10688
+ root = text(copy.eyebrow, createConfig, id, {});
10689
+ }
10690
+ else {
10691
+ const heading = wearing(createConfig('Heading'), id);
10692
+ if (heading) {
10693
+ setTrait(heading, 'content', copy.heading);
10694
+ setTrait(heading, 'level', id === 'display' ? 'h1' : id);
10695
+ styled(heading, { fontSize: HEADING_SPECIMEN_SIZE[id] ?? '18px', margin: '0' });
10696
+ }
10697
+ root = heading;
10698
+ }
10699
+ break;
10700
+ case 'Text':
10701
+ if (id === 'link') {
10702
+ const link = wearing(createConfig('Link'), id);
10703
+ if (link) {
10704
+ setTrait(link, 'label', copy.link);
10705
+ setTrait(link, 'url', '');
10706
+ }
10707
+ root = link;
10708
+ }
10709
+ else {
10710
+ root = text(copy.body, createConfig, id, { margin: '0' });
10711
+ }
10712
+ break;
10713
+ default:
10714
+ root = layoutSpecimen(id, createConfig, copy);
10715
+ }
10716
+ return markSpecimen(root);
10717
+ }
10718
+ function layoutSpecimen(id, createConfig, copy) {
10719
+ switch (id) {
10720
+ case 'section':
10721
+ case 'box':
10722
+ return text(copy.note, createConfig, 'small', { margin: '0' });
10723
+ case 'card':
10724
+ case 'panel':
10725
+ case 'dialog':
10726
+ return boxed(id, createConfig, [text(copy.label, createConfig, 'small', { margin: '0' })], { padding: '10px 12px', display: 'inline-block', minWidth: '120px', width: 'auto', maxWidth: '100%' });
10727
+ case 'nav':
10728
+ return boxed(id, createConfig, [
10729
+ text(copy.brand, createConfig, undefined, { fontWeight: '700', fontSize: '11px', margin: '0' }),
10730
+ text(copy.navLink, createConfig, undefined, { fontSize: '11px', margin: '0' }),
10731
+ ], { padding: '6px 10px', display: 'flex', gap: '10px', alignItems: 'center' });
10732
+ case 'media':
10733
+ return styled(wearing(createConfig('Image'), id), { width: '80px', aspectRatio: '4 / 3', height: 'auto' });
10734
+ case 'rule':
10735
+ return styled(wearing(createConfig('Divider'), id), { width: '120px' });
10736
+ case 'icon': {
10737
+ const icon = wearing(createConfig('Icon'), id);
10738
+ if (icon)
10739
+ setTrait(icon, 'iconClass', 'ph-thin ph-sparkle');
10740
+ return styled(icon, { fontSize: '20px', display: 'inline-flex' });
10741
+ }
10742
+ default:
10743
+ return boxed(id, createConfig, [text(copy.label, createConfig, undefined, { fontSize: '12px', margin: '0' })], { padding: '6px 10px' });
10744
+ }
10745
+ }
10746
+ /**
10747
+ * A look's tile (Board 6, Look tab — the board's `TILE`): four token dots, a Primary button and a
10748
+ * Card holding "Aa" in the display face beside the look's name. Every colour is a token reference,
10749
+ * so the tile wears whichever look's tokens its wrapper declares.
10750
+ */
10751
+ function buildFlavorSpecimen(name, createConfig, copy) {
10752
+ const dots = styled(createConfig('Container'), { display: 'flex', gap: '4px', alignSelf: 'start', width: 'auto' });
10753
+ const dotNodes = TILE_DOTS.map(token => styled(createConfig('Container'), {
10754
+ width: '14px', height: '14px', borderRadius: '50%', backgroundColor: `var(--iox-${token})`,
10755
+ borderWidth: '1px', borderStyle: 'solid', borderColor: 'rgba(127, 127, 127, 0.25)', flexShrink: '0',
10756
+ }));
10757
+ const primary = button('button-primary', copy.bookNow, createConfig, { padding: '4px 9px', fontSize: '11px', justifySelf: 'end' });
10758
+ const aa = text('Aa', createConfig, undefined, {
10759
+ fontFamily: 'var(--iox-font-display)', fontWeight: 'var(--iox-weight-display)', fontSize: '20px',
10760
+ letterSpacing: 'var(--iox-tracking-display)', lineHeight: '1', color: 'var(--iox-text)', margin: '0',
10680
10761
  });
10681
- const buttonsRow = styled(createConfig('Container'), { display: 'flex', gap: '8px' });
10682
- if (!badge || !heading || !primary || !secondary || !buttonsRow || !hero)
10683
- return null;
10684
- buttonsRow.children = [primary, secondary];
10685
- hero.children = [badge, heading, buttonsRow];
10686
- // The F1 board's hero/cards separator — a 1px Container, because the border-inline traits
10687
- // do not exist in the vocabulary and a physical border side would break RTL anyway.
10688
- const divider = styled(createConfig('Container'), {
10689
- width: '1px', backgroundColor: TOKEN('line', '#e6e3e1'),
10762
+ const label = text(name, createConfig, 'small', { margin: '0' });
10763
+ const card = boxed('card', createConfig, [aa, label], {
10764
+ gridColumn: '1 / -1', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
10765
+ gap: '10px', padding: '7px 9px', width: 'auto',
10690
10766
  });
10691
- const cards = styled(createConfig('Container'), {
10692
- display: 'grid', gridTemplateColumns: 'repeat(2, 150px)', gap: '12px', alignContent: 'center',
10767
+ const root = styled(createConfig('Container'), {
10768
+ display: 'grid', gridTemplateColumns: '1fr auto', gap: '6px', alignContent: 'space-between',
10769
+ height: '96px', padding: '10px', width: '100%',
10693
10770
  });
10694
- const cardA = sampleCard('Kitchen, Jaffa', '2025', createConfig);
10695
- const cardB = sampleCard('Loft, Florentin', '2024', createConfig);
10696
- if (!divider || !cards || !cardA || !cardB)
10697
- return null;
10698
- cards.children = [cardA, cardB];
10699
- root.children = [hero, divider, cards];
10700
- return root;
10771
+ if (root)
10772
+ root.label = 'Look specimen';
10773
+ return markSpecimen(withChildren(root, [withChildren(dots, dotNodes), primary, card]));
10701
10774
  }
10702
10775
 
10703
10776
  /**
@@ -11571,5 +11644,5 @@ class BuilderSpacerComponentConfig extends ComponentConfig {
11571
11644
  * Generated bundle index. Do not edit.
11572
11645
  */
11573
11646
 
11574
- export { ACTION_TYPE_OPTIONS, AuditCode, AuditPanelComponent, AuditSeverity, BODY_CRUMB_LABEL, 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, CardComponentConfig, ChildLayoutGroupStyleConfig, ComponentConfig, ComponentRegistryService, DEFAULT_ESSENTIAL_TRAITS, DRAG_HANDLE_ATTR, 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_PRESETS, FORM_TYPE, FieldComponentConfig, FieldGroupComponentConfig, FormComponentConfig, FormErrorComponentConfig, FormStateService, FormSuccessComponentConfig, GalleryConfig, GroupStyleConfig, INTERACTION_STATES, INVERSE_ACTION, IOX_BUILDER_CANVAS, IOX_BUILDER_LABELS, IOX_DATA_SOURCE_ENDPOINTS, 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, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, SCREEN_WIDTH_OPTIONS, STRUCTURAL_STATES, SUPPORTED_STATES, SectionComponent, SectionComponentConfig, SizeGroupStyleConfig, SliderContainerComponent, SliderContainerConfig, SliderSlideComponent, SliderSlideConfig, SpacingGroupStyleConfig, 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, buildConsentPreset, buildFieldKindPreset, buildFlavorSampler, buildFormPreset, buildFullStyleTraits, buildLayoutPreset, buildPalettePreset, buildPresetStyleTraits, canFluidise, canvasEmptyImageLabel, collapseColumnsProps, columnCountOf, defaultBuilderLabels, defaultPageSettings, dropTargetLabel, essentialTraitsFor, findNodeLocation, findParentOf, flattenSchemaFields, fluidiseProps, generateNodeId, isHiddenAt, matchesControlSearch, nearestFormNode, nodeAncestorPath, nodeAncestorPathInEither, reorderProps, resolveInsertTarget, resolveTraitControllerType, resolveTraitOptions, setStyleTrait, setTrait, stackChildrenProps, summarise, syncEmptyImagePlaceholder, syncNodeDesign, textNode, visibilityProps, wrapNode };
11647
+ export { ACTION_TYPE_OPTIONS, AuditCode, AuditPanelComponent, AuditSeverity, BODY_CRUMB_LABEL, 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, CardComponentConfig, ChildLayoutGroupStyleConfig, ComponentConfig, ComponentRegistryService, DEFAULT_ESSENTIAL_TRAITS, DRAG_HANDLE_ATTR, 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_PRESETS, FORM_TYPE, FieldComponentConfig, FieldGroupComponentConfig, FormComponentConfig, FormErrorComponentConfig, FormStateService, FormSuccessComponentConfig, GalleryConfig, GroupStyleConfig, INTERACTION_STATES, INVERSE_ACTION, IOX_BUILDER_CANVAS, IOX_BUILDER_LABELS, IOX_DATA_SOURCE_ENDPOINTS, 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, ROUTE_ANIMATION_OPTIONS, RenderDirective, RepeaterComponentConfig, SCREEN_WIDTH_OPTIONS, STRUCTURAL_STATES, SUPPORTED_STATES, SectionComponent, SectionComponentConfig, SizeGroupStyleConfig, SliderContainerComponent, SliderContainerConfig, SliderSlideComponent, SliderSlideConfig, SpacingGroupStyleConfig, 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, buildConsentPreset, buildElementStyleSpecimen, buildFieldKindPreset, buildFlavorSpecimen, buildFormPreset, buildFullStyleTraits, buildLayoutPreset, buildPalettePreset, buildPresetStyleTraits, canFluidise, canvasEmptyImageLabel, collapseColumnsProps, columnCountOf, defaultBuilderLabels, defaultPageSettings, dropTargetLabel, essentialTraitsFor, findNodeLocation, findParentOf, flattenSchemaFields, fluidiseProps, generateNodeId, isHiddenAt, isSpecimen, markSpecimen, matchesControlSearch, nearestFormNode, nodeAncestorPath, nodeAncestorPathInEither, reorderProps, resolveInsertTarget, resolveTraitControllerType, resolveTraitOptions, setStyleTrait, setTrait, stackChildrenProps, summarise, syncEmptyImagePlaceholder, syncNodeDesign, textNode, visibilityProps, wrapNode };
11575
11648
  //# sourceMappingURL=vectoriox-iox-builder.mjs.map