@vectoriox/iox-ui 5.40.0 → 5.41.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/composite-core/index.d.ts +212 -12
  2. package/design-core/index.d.ts +694 -17
  3. package/fesm2022/vectoriox-iox-ui-actions-core.mjs +4 -3
  4. package/fesm2022/vectoriox-iox-ui-actions-core.mjs.map +1 -1
  5. package/fesm2022/vectoriox-iox-ui-composite-core.mjs +540 -124
  6. package/fesm2022/vectoriox-iox-ui-composite-core.mjs.map +1 -1
  7. package/fesm2022/vectoriox-iox-ui-design-core.mjs +843 -45
  8. package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
  9. package/fesm2022/vectoriox-iox-ui-generation-core.mjs +846 -17
  10. package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
  11. package/fesm2022/vectoriox-iox-ui.mjs +3945 -3914
  12. package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
  13. package/generation-core/index.d.ts +608 -4
  14. package/index.d.ts +22 -1
  15. package/package.json +1 -1
  16. package/src/actions-core/element-actions.ts +4 -3
  17. package/src/composite-core/accordion.ts +1 -0
  18. package/src/composite-core/card.ts +6 -4
  19. package/src/composite-core/composite-kinds.ts +42 -6
  20. package/src/composite-core/exclusive-runtime.ts +60 -10
  21. package/src/composite-core/exclusive.ts +64 -0
  22. package/src/composite-core/public-api.ts +5 -2
  23. package/src/composite-core/segmented.ts +351 -0
  24. package/src/composite-core/structure.ts +6 -1
  25. package/src/composite-core/tabs.ts +6 -3
  26. package/src/design-core/contrast-audit.ts +8 -3
  27. package/src/design-core/flavor-spec.generated.ts +832 -41
  28. package/src/generation-core/compose-site.ts +170 -12
  29. package/src/generation-core/node-baselines.generated.ts +49 -0
  30. package/src/generation-core/patterns.ts +21 -0
  31. package/src/generation-core/site-spec.generated.ts +639 -0
  32. package/styles/iox-design.css +19 -0
@@ -128,8 +128,9 @@ function removeFromComposite(root, node) {
128
128
  * The composites' kinds and roles. Two families:
129
129
  * - OPEN/CLOSE (CC2 Accordion, CC2.1 Disclosure — composite plan T9 / T21): a Disclosure is a one-item accordion whose
130
130
  * ROOT is its item, so both run the same state machine, attribute planners and runtime (`accordion-runtime.ts`);
131
- * - EXCLUSIVE (CC4 Tabs — composite T17; the Segmented control joins in CC4b): exactly one item is on, a trigger and
132
- * its panel paired by `itemKey` (`tabs.ts`, `exclusive-runtime.ts`).
131
+ * - EXCLUSIVE (CC4 Tabs — composite T17; CC4b the Segmented control — T32): exactly one item is on; a Tabs' trigger
132
+ * and its panel pair by `itemKey` (`tabs.ts`), a Segmented control's options have no panel (`segmented.ts`); both run
133
+ * `exclusive-runtime.ts`.
133
134
  * Every consumer that treats "an item", "a trigger" or "a panel" alike asks these predicates, never a role literal.
134
135
  */
135
136
  var CompositeKind;
@@ -137,6 +138,7 @@ var CompositeKind;
137
138
  CompositeKind["Accordion"] = "accordion";
138
139
  CompositeKind["Disclosure"] = "disclosure";
139
140
  CompositeKind["Tabs"] = "tabs";
141
+ CompositeKind["Segmented"] = "segmented";
140
142
  })(CompositeKind || (CompositeKind = {}));
141
143
  var AccordionRole;
142
144
  (function (AccordionRole) {
@@ -173,12 +175,24 @@ var TabsRole;
173
175
  TabsRole["Panels"] = "tabs.panels";
174
176
  TabsRole["Panel"] = "tabs.panel";
175
177
  })(TabsRole || (TabsRole = {}));
178
+ /**
179
+ * SEGMENTED (CC4b — composite T32; complex-components board 10). One of a few, always one on, FIXED options (R3): the
180
+ * root IS the radio group and holds the options directly — no list, no panels. An option may hold the optional saving
181
+ * badge (inside it, so its words join the option's accessible name).
182
+ */
183
+ var SegmentedRole;
184
+ (function (SegmentedRole) {
185
+ SegmentedRole["Segmented"] = "segmented";
186
+ SegmentedRole["Option"] = "segmented.option";
187
+ SegmentedRole["Badge"] = "segmented.badge";
188
+ })(SegmentedRole || (SegmentedRole = {}));
176
189
  const COMPOSITE_KIND_ROLES = {
177
190
  [CompositeKind.Accordion]: { root: AccordionRole.Accordion, item: AccordionRole.Item, trigger: AccordionRole.Trigger, panel: AccordionRole.Panel, icon: AccordionRole.Icon },
178
191
  [CompositeKind.Disclosure]: { root: DisclosureRole.Disclosure, item: DisclosureRole.Disclosure, trigger: DisclosureRole.Trigger, panel: DisclosureRole.Panel, icon: DisclosureRole.Icon },
179
192
  };
180
193
  const EXCLUSIVE_KIND_ROLES = {
181
194
  [CompositeKind.Tabs]: { root: TabsRole.Tabs, list: TabsRole.List, trigger: TabsRole.Trigger, panels: TabsRole.Panels, panel: TabsRole.Panel },
195
+ [CompositeKind.Segmented]: { root: SegmentedRole.Segmented, list: null, trigger: SegmentedRole.Option, panels: null, panel: null },
182
196
  };
183
197
  const KINDS = Object.values(CompositeKind);
184
198
  const TOGGLE_KINDS = Object.keys(COMPOSITE_KIND_ROLES);
@@ -282,6 +296,23 @@ function isExclusiveItemPart(node) {
282
296
  function isTabsPart(node) {
283
297
  return compositeKindOfRole(node?.role) === CompositeKind.Tabs;
284
298
  }
299
+ /** True for any part of a Segmented control (its root included). */
300
+ function isSegmentedPart(node) {
301
+ return compositeKindOfRole(node?.role) === CompositeKind.Segmented;
302
+ }
303
+ /** The exclusive kind a node's role belongs to (`segmented.option` → Segmented), or null. */
304
+ function exclusiveKindOf(node) {
305
+ const kind = compositeKindOfRole(node?.role);
306
+ return isExclusiveKind(kind) ? kind : null;
307
+ }
308
+ /** True when an exclusive root holds its triggers itself (a Segmented control), not in a list part. */
309
+ function exclusiveRootHoldsTriggers(kind) {
310
+ return EXCLUSIVE_KIND_ROLES[kind].list === null;
311
+ }
312
+ /** True when an exclusive kind's items show a panel (Tabs), so a trigger and its panel are a pair. */
313
+ function exclusiveKindHasPanels(kind) {
314
+ return !!kind && EXCLUSIVE_KIND_ROLES[kind].panel !== null;
315
+ }
285
316
  /** A root of either family — anything that runs a composite runtime. */
286
317
  function isAnyCompositeRoot(node) {
287
318
  return isCompositeRoot(node) || isExclusiveRoot(node);
@@ -368,7 +399,7 @@ const ACCORDION_WORDS = [
368
399
  { question: 'Write the third question', answer: 'Answer it plainly, in two or three short sentences.' },
369
400
  ];
370
401
  const ACCORDION_NEW_ITEM_WORDS = { question: 'Write a new question', answer: 'Answer it plainly, in two or three short sentences.' };
371
- var Type$4;
402
+ var Type$5;
372
403
  (function (Type) {
373
404
  Type["Container"] = "Container";
374
405
  Type["LinkedContainer"] = "LinkedContainer";
@@ -376,8 +407,8 @@ var Type$4;
376
407
  Type["Text"] = "Text";
377
408
  Type["Icon"] = "Icon";
378
409
  Type["Repeater"] = "Repeater";
379
- })(Type$4 || (Type$4 = {}));
380
- var Style$4;
410
+ })(Type$5 || (Type$5 = {}));
411
+ var Style$5;
381
412
  (function (Style) {
382
413
  Style["Root"] = "box";
383
414
  Style["Item"] = "accordion-item";
@@ -386,14 +417,14 @@ var Style$4;
386
417
  Style["Icon"] = "icon";
387
418
  Style["Panel"] = "accordion-panel";
388
419
  Style["Answer"] = "body";
389
- })(Style$4 || (Style$4 = {}));
390
- const ZERO_BOX$3 = '0px 0px 0px 0px';
420
+ })(Style$5 || (Style$5 = {}));
421
+ const ZERO_BOX$4 = '0px 0px 0px 0px';
391
422
  const HEADING_LEVELS = ['h2', 'h3', 'h4', 'h5', 'h6'];
392
423
  const DEFAULT_LEVEL = 'h3';
393
424
  /** A linked trait the header must never carry: it is a button, not a link. */
394
425
  const LINK_TYPE$1 = 'linkType';
395
426
  /** What each part holds in the recipe — layout only; its LOOK is its element style. */
396
- const PART_BASE$2 = {
427
+ const PART_BASE$3 = {
397
428
  // The items are a column a token apart (`accordion-gap`: 0 for a divider list, 12px for cards).
398
429
  [AccordionRole.Accordion]: { display: 'flex', flexDirection: 'column', gap: 'var(--iox-accordion-gap)', width: '100%', minHeight: 'auto', height: 'auto' },
399
430
  [AccordionRole.Item]: { display: 'block', width: '100%', minHeight: 'auto', height: 'auto' },
@@ -404,16 +435,16 @@ const PART_BASE$2 = {
404
435
  };
405
436
  /** The question INHERITS the header's ink (board 4's wears table: the Question reads no colour token), so the
406
437
  * header's hover ink reaches the words; and it sits in the row with no margin of its own. */
407
- const QUESTION_BASE = { color: 'inherit', margin: ZERO_BOX$3, flexGrow: '1', minWidth: '0px' };
408
- const ANSWER_BASE = { margin: ZERO_BOX$3, padding: ZERO_BOX$3, minHeight: 'auto' };
409
- function make$3(create, key, type, role, style, props = {}, label) {
410
- return makeCompositePart(create, { key, type, props, elementStyle: style }, role, label, role ? PART_BASE$2[role] : undefined);
438
+ const QUESTION_BASE = { color: 'inherit', margin: ZERO_BOX$4, flexGrow: '1', minWidth: '0px' };
439
+ const ANSWER_BASE = { margin: ZERO_BOX$4, padding: ZERO_BOX$4, minHeight: 'auto' };
440
+ function make$4(create, key, type, role, style, props = {}, label) {
441
+ return makeCompositePart(create, { key, type, props, elementStyle: style }, role, label, role ? PART_BASE$3[role] : undefined);
411
442
  }
412
443
  /** The icon of an item (an accordion's, or a disclosure's — `role`); its Item-open state (the turn) is driven by
413
444
  * ITS item (`stateTriggers`). ONE builder for both kinds. */
414
445
  function buildCompositeIcon(create, key, icon, itemId, role = AccordionRole.Icon) {
415
446
  const glyph = ACCORDION_ICON_GLYPH[icon];
416
- const node = makeCompositePart(create, { key, type: Type$4.Icon, props: { iconClass: glyph.iconClass }, elementStyle: Style$4.Icon }, role, 'Icon', PART_BASE$2[AccordionRole.Icon]);
447
+ const node = makeCompositePart(create, { key, type: Type$5.Icon, props: { iconClass: glyph.iconClass }, elementStyle: Style$5.Icon }, role, 'Icon', PART_BASE$3[AccordionRole.Icon]);
417
448
  node.stateStyles = { ...(node.stateStyles ?? {}), [ITEM_OPEN_STATE]: { rotate: glyph.turn } };
418
449
  if (itemId)
419
450
  node.stateTriggers = { ...(node.stateTriggers ?? {}), [ITEM_OPEN_STATE]: itemId };
@@ -421,14 +452,14 @@ function buildCompositeIcon(create, key, icon, itemId, role = AccordionRole.Icon
421
452
  }
422
453
  /** One item: header (question + icon) and panel (answer). `key` makes every part's recipe key unique. */
423
454
  function buildAccordionItem(create, words, itemKey, icon = AccordionIcon.Chevron) {
424
- const item = make$3(create, `${itemKey}`, Type$4.Container, AccordionRole.Item, Style$4.Item, {}, 'Item');
455
+ const item = make$4(create, `${itemKey}`, Type$5.Container, AccordionRole.Item, Style$5.Item, {}, 'Item');
425
456
  item.itemKey = itemKey;
426
- const trigger = make$3(create, `${itemKey}-trigger`, Type$4.LinkedContainer, AccordionRole.Trigger, Style$4.Trigger, {}, 'Header');
427
- const question = make$3(create, `${itemKey}-question`, Type$4.Heading, null, Style$4.Question, { content: words.question, level: DEFAULT_LEVEL }, 'Heading');
457
+ const trigger = make$4(create, `${itemKey}-trigger`, Type$5.LinkedContainer, AccordionRole.Trigger, Style$5.Trigger, {}, 'Header');
458
+ const question = make$4(create, `${itemKey}-question`, Type$5.Heading, null, Style$5.Question, { content: words.question, level: DEFAULT_LEVEL }, 'Heading');
428
459
  writeStyles(question, QUESTION_BASE);
429
460
  trigger.children = [question, ...(icon === AccordionIcon.None ? [] : [buildCompositeIcon(create, `${itemKey}-icon`, icon, item.id)])];
430
- const panel = make$3(create, `${itemKey}-panel`, Type$4.Container, AccordionRole.Panel, Style$4.Panel, {}, 'Panel');
431
- const answer = make$3(create, `${itemKey}-answer`, Type$4.Text, null, Style$4.Answer, { content: words.answer, tag: 'p' }, 'Text');
461
+ const panel = make$4(create, `${itemKey}-panel`, Type$5.Container, AccordionRole.Panel, Style$5.Panel, {}, 'Panel');
462
+ const answer = make$4(create, `${itemKey}-answer`, Type$5.Text, null, Style$5.Answer, { content: words.answer, tag: 'p' }, 'Text');
432
463
  writeStyles(answer, ANSWER_BASE);
433
464
  panel.children = [answer];
434
465
  item.children = [trigger, panel];
@@ -436,7 +467,7 @@ function buildAccordionItem(create, words, itemKey, icon = AccordionIcon.Chevron
436
467
  }
437
468
  /** A fresh Accordion: three items, one open at a time, the first open by default (board 4). */
438
469
  function buildAccordionRecipe(create, options = {}) {
439
- const root = make$3(create, 'accordion', Type$4.Container, AccordionRole.Accordion, Style$4.Root, {}, 'Accordion');
470
+ const root = make$4(create, 'accordion', Type$5.Container, AccordionRole.Accordion, Style$5.Root, {}, 'Accordion');
440
471
  writeProp(root, CompositeBehaviourTrait.Multiple, options.multiple ?? false);
441
472
  writeProp(root, CompositeBehaviourTrait.DefaultOn, options.defaultOn ?? AccordionDefaultOn.First);
442
473
  const words = options.items ?? ACCORDION_WORDS;
@@ -475,7 +506,7 @@ function accordionItemOf(node, path) {
475
506
  }
476
507
  /** True when the root takes its items from content (a Repeater bound to a list, R3). */
477
508
  function isAccordionFromContent(root) {
478
- return !!root && root.type === Type$4.Repeater;
509
+ return !!root && root.type === Type$5.Repeater;
479
510
  }
480
511
  /** The root's items in order — every item (Manual), or the one template item (From content). */
481
512
  function accordionItems(root) {
@@ -522,9 +553,9 @@ function accordionQuestionOf(item) {
522
553
  let text;
523
554
  if (trigger)
524
555
  walkComposite(trigger, n => {
525
- if (!hit && n.type === Type$4.Heading)
556
+ if (!hit && n.type === Type$5.Heading)
526
557
  hit = n;
527
- if (!text && n.type === Type$4.Text)
558
+ if (!text && n.type === Type$5.Text)
528
559
  text = n;
529
560
  });
530
561
  return hit ?? text;
@@ -534,15 +565,15 @@ function accordionAnswerOf(item) {
534
565
  const panel = accordionPanelOf(item);
535
566
  let hit;
536
567
  if (panel)
537
- walkComposite(panel, n => { if (!hit && n.type === Type$4.Text)
568
+ walkComposite(panel, n => { if (!hit && n.type === Type$5.Text)
538
569
  hit = n; });
539
570
  return hit;
540
571
  }
541
- const stripTags$1 = (v) => String(v ?? '').replace(/<[^>]*>/g, '').trim();
572
+ const stripTags$2 = (v) => String(v ?? '').replace(/<[^>]*>/g, '').trim();
542
573
  /** An item's name in the Items list and the layer tree: its question's words. */
543
574
  function accordionItemLabel(item) {
544
575
  const q = accordionQuestionOf(item);
545
- return q ? stripTags$1(readProp(q, 'content')) : '';
576
+ return q ? stripTags$2(readProp(q, 'content')) : '';
546
577
  }
547
578
  /** Items ▸ rename: the question's words. */
548
579
  function renameAccordionItem(item, question) {
@@ -555,7 +586,7 @@ function accordionHeadingLevel(trigger) {
555
586
  const visit = (n) => {
556
587
  if (level !== undefined)
557
588
  return;
558
- if (n.type === Type$4.Heading) {
589
+ if (n.type === Type$5.Heading) {
559
590
  level = readProp(n, 'level');
560
591
  return;
561
592
  }
@@ -736,6 +767,7 @@ const DOM_ID_PREFIX = {
736
767
  [CompositeKind.Accordion]: 'iox-acc',
737
768
  [CompositeKind.Disclosure]: 'iox-dis',
738
769
  [CompositeKind.Tabs]: 'iox-tab',
770
+ [CompositeKind.Segmented]: 'iox-seg',
739
771
  };
740
772
  /** The ARIA pairing ids of an item: unique per composite (its SCOPE id — `compositeScopeId`) and per item (its key). */
741
773
  function accordionDomIds(rootId, itemKey, kind = CompositeKind.Accordion) {
@@ -1306,21 +1338,21 @@ const DISCLOSURE_WORDS = {
1306
1338
  };
1307
1339
  /** A disclosure's one item key — its root IS its item. */
1308
1340
  const DISCLOSURE_ITEM_KEY = 'k1';
1309
- var Type$3;
1341
+ var Type$4;
1310
1342
  (function (Type) {
1311
1343
  Type["Container"] = "Container";
1312
1344
  Type["LinkedContainer"] = "LinkedContainer";
1313
1345
  Type["Text"] = "Text";
1314
- })(Type$3 || (Type$3 = {}));
1315
- var Style$3;
1346
+ })(Type$4 || (Type$4 = {}));
1347
+ var Style$4;
1316
1348
  (function (Style) {
1317
1349
  Style["Root"] = "box";
1318
1350
  Style["Trigger"] = "accordion-trigger";
1319
1351
  Style["Word"] = "body";
1320
1352
  Style["Panel"] = "accordion-panel";
1321
1353
  Style["Body"] = "body";
1322
- })(Style$3 || (Style$3 = {}));
1323
- const ZERO_BOX$2 = '0px 0px 0px 0px';
1354
+ })(Style$4 || (Style$4 = {}));
1355
+ const ZERO_BOX$3 = '0px 0px 0px 0px';
1324
1356
  const HIDDEN = 'none';
1325
1357
  const INHERIT = 'inherit';
1326
1358
  /** A word is a flex item of the toggle — `block` (never `inline`: the compiler drops a value equal to the CSS initial,
@@ -1329,7 +1361,7 @@ const SHOWN = 'block';
1329
1361
  /** What each part holds — layout only; its LOOK is its element style. The trigger sizes to its words (a button in
1330
1362
  * the flow, not a full-width header row — `fit-content` keeps it from stretching) and the panel spans the root. The
1331
1363
  * trigger is `flex`, not `inline-flex`: it is a flex item of the root, which blockifies it on the site anyway. */
1332
- const PART_BASE$1 = {
1364
+ const PART_BASE$2 = {
1333
1365
  [DisclosureRole.Disclosure]: { display: 'flex', flexDirection: 'column', width: '100%', minHeight: 'auto', height: 'auto' },
1334
1366
  // The toggle reads the text around it (the page's body type, through the root) — a LinkedContainer is born with
1335
1367
  // its own literal font, which an accordion's heading masks and a disclosure's words would show.
@@ -1339,17 +1371,17 @@ const PART_BASE$1 = {
1339
1371
  },
1340
1372
  // A word is just its words: none of a Text's own box (its type's 10px padding, its full width) — the toggle's
1341
1373
  // padding is the click target.
1342
- [DisclosureRole.More]: { display: SHOWN, margin: ZERO_BOX$2, padding: ZERO_BOX$2, width: 'auto' },
1343
- [DisclosureRole.Less]: { display: HIDDEN, margin: ZERO_BOX$2, padding: ZERO_BOX$2, width: 'auto' },
1374
+ [DisclosureRole.More]: { display: SHOWN, margin: ZERO_BOX$3, padding: ZERO_BOX$3, width: 'auto' },
1375
+ [DisclosureRole.Less]: { display: HIDDEN, margin: ZERO_BOX$3, padding: ZERO_BOX$3, width: 'auto' },
1344
1376
  [DisclosureRole.Panel]: { display: 'block', width: '100%', minHeight: 'auto', height: 'auto' },
1345
1377
  };
1346
- const BODY_BASE$1 = { margin: ZERO_BOX$2, padding: ZERO_BOX$2, minHeight: 'auto' };
1347
- function make$2(create, key, type, role, style, props, label) {
1348
- return makeCompositePart(create, { key, type, props, elementStyle: style }, role, label, role ? PART_BASE$1[role] : undefined);
1378
+ const BODY_BASE$1 = { margin: ZERO_BOX$3, padding: ZERO_BOX$3, minHeight: 'auto' };
1379
+ function make$3(create, key, type, role, style, props, label) {
1380
+ return makeCompositePart(create, { key, type, props, elementStyle: style }, role, label, role ? PART_BASE$2[role] : undefined);
1349
1381
  }
1350
1382
  /** One of the trigger's two words: shown while the disclosure is closed (`more`) or open (`less`). */
1351
1383
  function buildWord(create, role, words, rootId) {
1352
- const node = make$2(create, role === DisclosureRole.More ? 'more' : 'less', Type$3.Text, role, Style$3.Word, { content: words, tag: 'span' }, 'Text');
1384
+ const node = make$3(create, role === DisclosureRole.More ? 'more' : 'less', Type$4.Text, role, Style$4.Word, { content: words, tag: 'span' }, 'Text');
1353
1385
  node.stateStyles = { ...(node.stateStyles ?? {}), [ITEM_OPEN_STATE]: { display: role === DisclosureRole.More ? HIDDEN : SHOWN } };
1354
1386
  if (rootId)
1355
1387
  node.stateTriggers = { ...(node.stateTriggers ?? {}), [ITEM_OPEN_STATE]: rootId };
@@ -1358,18 +1390,18 @@ function buildWord(create, role, words, rootId) {
1358
1390
  /** A fresh Disclosure: "Read more" opens the text below and reads "Read less" while it is open; closed by default. */
1359
1391
  function buildDisclosureRecipe(create, options = {}) {
1360
1392
  const words = { ...DISCLOSURE_WORDS, ...(options.words ?? {}) };
1361
- const root = make$2(create, 'disclosure', Type$3.Container, DisclosureRole.Disclosure, Style$3.Root, {}, 'Disclosure');
1393
+ const root = make$3(create, 'disclosure', Type$4.Container, DisclosureRole.Disclosure, Style$4.Root, {}, 'Disclosure');
1362
1394
  root.itemKey = DISCLOSURE_ITEM_KEY;
1363
1395
  writeProp(root, CompositeBehaviourTrait.DefaultOn, options.open ? AccordionDefaultOn.First : AccordionDefaultOn.None);
1364
1396
  const icon = options.icon ?? AccordionIcon.Chevron;
1365
- const trigger = make$2(create, 'trigger', Type$3.LinkedContainer, DisclosureRole.Trigger, Style$3.Trigger, {}, 'Toggle');
1397
+ const trigger = make$3(create, 'trigger', Type$4.LinkedContainer, DisclosureRole.Trigger, Style$4.Trigger, {}, 'Toggle');
1366
1398
  trigger.children = [
1367
1399
  buildWord(create, DisclosureRole.More, words.more, root.id),
1368
1400
  buildWord(create, DisclosureRole.Less, words.less, root.id),
1369
1401
  ...(icon === AccordionIcon.None ? [] : [buildCompositeIcon(create, 'icon', icon, root.id, DisclosureRole.Icon)]),
1370
1402
  ];
1371
- const panel = make$2(create, 'panel', Type$3.Container, DisclosureRole.Panel, Style$3.Panel, {}, 'Panel');
1372
- const body = make$2(create, 'body', Type$3.Text, null, Style$3.Body, { content: words.body, tag: 'p' }, 'Text');
1403
+ const panel = make$3(create, 'panel', Type$4.Container, DisclosureRole.Panel, Style$4.Panel, {}, 'Panel');
1404
+ const body = make$3(create, 'body', Type$4.Text, null, Style$4.Body, { content: words.body, tag: 'p' }, 'Text');
1373
1405
  writeStyles(body, BODY_BASE$1);
1374
1406
  panel.children = [body];
1375
1407
  root.children = [trigger, panel];
@@ -1532,7 +1564,7 @@ const CARD_WORDS = {
1532
1564
  };
1533
1565
  /** The breakpoint whose layer stacks an "Image side" card (Breakpoint.Mobile, ≤767px). */
1534
1566
  const CARD_STACK_BREAKPOINT = 'mobile';
1535
- var Type$2;
1567
+ var Type$3;
1536
1568
  (function (Type) {
1537
1569
  Type["Container"] = "Container";
1538
1570
  Type["Image"] = "Image";
@@ -1540,8 +1572,8 @@ var Type$2;
1540
1572
  Type["Text"] = "Text";
1541
1573
  Type["Icon"] = "Icon";
1542
1574
  Type["ButtonBlock"] = "ButtonBlock";
1543
- })(Type$2 || (Type$2 = {}));
1544
- var Style$2;
1575
+ })(Type$3 || (Type$3 = {}));
1576
+ var Style$3;
1545
1577
  (function (Style) {
1546
1578
  Style["Card"] = "card";
1547
1579
  Style["Box"] = "box";
@@ -1554,7 +1586,7 @@ var Style$2;
1554
1586
  Style["Ghost"] = "button-ghost";
1555
1587
  Style["Icon"] = "icon";
1556
1588
  Style["Scrim"] = "media-scrim";
1557
- })(Style$2 || (Style$2 = {}));
1589
+ })(Style$3 || (Style$3 = {}));
1558
1590
  var Scheme;
1559
1591
  (function (Scheme) {
1560
1592
  Scheme["Default"] = "default";
@@ -1564,11 +1596,11 @@ const LINK_TYPE = 'linkType';
1564
1596
  const SAVE_ICON = 'ph ph-bookmark-simple';
1565
1597
  /** A value an element style writes — read from the contract, never retyped. */
1566
1598
  const styleValue = (style, trait) => String(elementStyleById(style)?.base[trait] ?? '');
1567
- const CARD_PAD = styleValue(Style$2.Card, 'padding');
1568
- const IMAGE_RADIUS = styleValue(Style$2.Media, 'borderRadius');
1569
- const TITLE_SIZE = styleValue(Style$2.Title, 'fontSize');
1599
+ const CARD_PAD = styleValue(Style$3.Card, 'padding');
1600
+ const IMAGE_RADIUS = styleValue(Style$3.Media, 'borderRadius');
1601
+ const TITLE_SIZE = styleValue(Style$3.Title, 'fontSize');
1570
1602
  const LEAD_SIZE = 'var(--iox-size-lead)';
1571
- const ZERO_BOX$1 = '0px 0px 0px 0px';
1603
+ const ZERO_BOX$2 = '0px 0px 0px 0px';
1572
1604
  /** What every card part holds in every layout — the recipe's box. */
1573
1605
  const CARD_BASE = {
1574
1606
  // No height: a card is a grid or flex item, and the cell's stretch is what makes a row's cards equal.
@@ -1576,25 +1608,25 @@ const CARD_BASE = {
1576
1608
  [CardRole.Card]: { display: 'flex', gap: '14px', width: '100%', minWidth: '0px', overflow: 'hidden', position: 'relative' },
1577
1609
  [CardRole.Media]: { display: 'block', width: '100%', minHeight: 'auto', flexGrow: '0', flexShrink: '0' },
1578
1610
  [CardRole.Content]: { display: 'flex', flexDirection: 'column', gap: '8px', width: '100%', minWidth: '0px', minHeight: 'auto' },
1579
- [CardRole.Eyebrow]: { margin: ZERO_BOX$1, padding: ZERO_BOX$1, minHeight: 'auto' },
1580
- [CardRole.Title]: { margin: ZERO_BOX$1 },
1581
- [CardRole.Text]: { margin: ZERO_BOX$1, padding: ZERO_BOX$1, minHeight: 'auto' },
1611
+ [CardRole.Eyebrow]: { margin: ZERO_BOX$2, padding: ZERO_BOX$2, minHeight: 'auto' },
1612
+ [CardRole.Title]: { margin: ZERO_BOX$2 },
1613
+ [CardRole.Text]: { margin: ZERO_BOX$2, padding: ZERO_BOX$2, minHeight: 'auto' },
1582
1614
  // Buttons pinned to the bottom (board 8 Q: equal heights + buttons pinned): the content column grows,
1583
1615
  // and the row's auto top margin takes the slack.
1584
1616
  [CardRole.Actions]: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '8px', margin: 'auto 0px 0px 0px', padding: '6px 0px 0px 0px', width: '100%', minHeight: 'auto' },
1585
1617
  };
1586
1618
  const IMAGE_BASE$2 = { display: 'block', width: '100%', maxWidth: '100%' };
1587
1619
  /** A button's label and a pill's words: inherit the type and ink of what holds them. */
1588
- const LABEL_BASE$1 = { width: 'auto', minHeight: 'auto', padding: ZERO_BOX$1, margin: ZERO_BOX$1 };
1620
+ const LABEL_BASE$2 = { width: 'auto', minHeight: 'auto', padding: ZERO_BOX$2, margin: ZERO_BOX$2 };
1589
1621
  const INLINE_ICON = { fontSize: '1em' };
1590
1622
  const IN_FLOW = { position: 'relative', top: 'auto', right: 'auto', bottom: 'auto', left: 'auto' };
1591
- const GROWING_CONTENT = { position: 'static', flexGrow: '1', flexShrink: '1', flexBasis: '0%', padding: ZERO_BOX$1 };
1623
+ const GROWING_CONTENT = { position: 'static', flexGrow: '1', flexShrink: '1', flexBasis: '0%', padding: ZERO_BOX$2 };
1592
1624
  const LAYOUTS = {
1593
1625
  [CardLayout.Top]: {
1594
1626
  card: { flexDirection: 'column', alignItems: 'stretch', justifyContent: 'flex-start', minHeight: 'auto', padding: CARD_PAD },
1595
1627
  media: { ...IN_FLOW, flexBasis: 'auto' },
1596
1628
  image: { aspectRatio: '4 / 3', height: 'auto', minHeight: 'auto', borderRadius: IMAGE_RADIUS },
1597
- content: GROWING_CONTENT, contentStyle: Style$2.Box, contentScheme: Scheme.Default,
1629
+ content: GROWING_CONTENT, contentStyle: Style$3.Box, contentScheme: Scheme.Default,
1598
1630
  title: { fontSize: TITLE_SIZE },
1599
1631
  badgeOnMedia: true,
1600
1632
  },
@@ -1602,7 +1634,7 @@ const LAYOUTS = {
1602
1634
  card: { flexDirection: 'row', alignItems: 'stretch', justifyContent: 'flex-start', minHeight: 'auto', padding: CARD_PAD },
1603
1635
  media: { ...IN_FLOW, flexBasis: '42%' },
1604
1636
  image: { aspectRatio: 'auto', height: '100%', minHeight: '180px', borderRadius: IMAGE_RADIUS },
1605
- content: GROWING_CONTENT, contentStyle: Style$2.Box, contentScheme: Scheme.Default,
1637
+ content: GROWING_CONTENT, contentStyle: Style$3.Box, contentScheme: Scheme.Default,
1606
1638
  title: { fontSize: TITLE_SIZE },
1607
1639
  badgeOnMedia: true,
1608
1640
  stack: {
@@ -1612,11 +1644,11 @@ const LAYOUTS = {
1612
1644
  },
1613
1645
  },
1614
1646
  [CardLayout.Overlay]: {
1615
- card: { flexDirection: 'column', alignItems: 'stretch', justifyContent: 'flex-end', minHeight: '340px', padding: ZERO_BOX$1 },
1647
+ card: { flexDirection: 'column', alignItems: 'stretch', justifyContent: 'flex-end', minHeight: '340px', padding: ZERO_BOX$2 },
1616
1648
  media: { position: 'absolute', top: '0px', right: '0px', bottom: '0px', left: '0px', flexBasis: 'auto' },
1617
1649
  image: { aspectRatio: 'auto', height: '100%', minHeight: 'auto', borderRadius: '0px' },
1618
1650
  content: { position: 'relative', flexGrow: '0', flexShrink: '0', flexBasis: 'auto', padding: `72px ${CARD_PAD} ${CARD_PAD} ${CARD_PAD}` },
1619
- contentStyle: Style$2.Scrim, contentScheme: Scheme.Inverse,
1651
+ contentStyle: Style$3.Scrim, contentScheme: Scheme.Inverse,
1620
1652
  title: { fontSize: TITLE_SIZE },
1621
1653
  badgeOnMedia: false,
1622
1654
  },
@@ -1624,7 +1656,7 @@ const LAYOUTS = {
1624
1656
  card: { flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start', minHeight: 'auto', padding: CARD_PAD },
1625
1657
  media: { ...IN_FLOW, flexBasis: '72px' },
1626
1658
  image: { aspectRatio: '1 / 1', height: 'auto', minHeight: 'auto', borderRadius: IMAGE_RADIUS },
1627
- content: GROWING_CONTENT, contentStyle: Style$2.Box, contentScheme: Scheme.Default,
1659
+ content: GROWING_CONTENT, contentStyle: Style$3.Box, contentScheme: Scheme.Default,
1628
1660
  title: { fontSize: LEAD_SIZE },
1629
1661
  badgeOnMedia: false,
1630
1662
  partsOff: [CardPart.Text, CardPart.Actions],
@@ -1635,7 +1667,7 @@ const STACK_KEYS = {
1635
1667
  media: Object.keys(LAYOUTS[CardLayout.Side].stack.media),
1636
1668
  image: Object.keys(LAYOUTS[CardLayout.Side].stack.image),
1637
1669
  };
1638
- function make$1(create, key, type, role, elementStyle, props = {}, label) {
1670
+ function make$2(create, key, type, role, elementStyle, props = {}, label) {
1639
1671
  const node = create({ key, type, props, elementStyle });
1640
1672
  if (role)
1641
1673
  node.role = role;
@@ -1645,33 +1677,33 @@ function make$1(create, key, type, role, elementStyle, props = {}, label) {
1645
1677
  return node;
1646
1678
  }
1647
1679
  function buttonLabel(create, key, words) {
1648
- const label = make$1(create, key, Type$2.Text, null, Style$2.Label, { content: words, tag: 'span' });
1649
- writeStyles(label, LABEL_BASE$1);
1680
+ const label = make$2(create, key, Type$3.Text, null, Style$3.Label, { content: words, tag: 'span' });
1681
+ writeStyles(label, LABEL_BASE$2);
1650
1682
  return label;
1651
1683
  }
1652
1684
  /** Each optional part (and the locked title) as the recipe builds it. */
1653
1685
  const PART_BUILDERS = {
1654
1686
  [CardPart.Media]: (create) => {
1655
- const media = make$1(create, 'media', Type$2.Container, CardRole.Media, Style$2.Box, {}, 'Media');
1656
- const image = make$1(create, 'image', Type$2.Image, null, Style$2.Media, { src: '', alt: '' });
1687
+ const media = make$2(create, 'media', Type$3.Container, CardRole.Media, Style$3.Box, {}, 'Media');
1688
+ const image = make$2(create, 'image', Type$3.Image, null, Style$3.Media, { src: '', alt: '' });
1657
1689
  writeStyles(image, IMAGE_BASE$2);
1658
1690
  media.children = [image];
1659
1691
  return media;
1660
1692
  },
1661
- [CardPart.Badge]: (create, words, tone) => {
1662
- const badge = buildBadge(create, { tone, text: words.badge, key: 'badge' });
1693
+ [CardPart.Badge]: (create, words, tone, badgeIcon) => {
1694
+ const badge = buildBadge(create, { tone, text: words.badge, key: 'badge', ...(badgeIcon ? { icon: badgeIcon } : {}) });
1663
1695
  badge.role = CardRole.Badge;
1664
1696
  badge.label = 'Badge';
1665
1697
  return badge;
1666
1698
  },
1667
- [CardPart.Eyebrow]: (create, words) => make$1(create, 'eyebrow', Type$2.Text, CardRole.Eyebrow, Style$2.Eyebrow, { content: words.eyebrow, tag: 'p' }, 'Eyebrow'),
1668
- [CardPart.Text]: (create, words) => make$1(create, 'text', Type$2.Text, CardRole.Text, Style$2.Body, { content: words.text, tag: 'p' }, 'Text'),
1699
+ [CardPart.Eyebrow]: (create, words) => make$2(create, 'eyebrow', Type$3.Text, CardRole.Eyebrow, Style$3.Eyebrow, { content: words.eyebrow, tag: 'p' }, 'Eyebrow'),
1700
+ [CardPart.Text]: (create, words) => make$2(create, 'text', Type$3.Text, CardRole.Text, Style$3.Body, { content: words.text, tag: 'p' }, 'Text'),
1669
1701
  [CardPart.Actions]: (create, words) => {
1670
- const actions = make$1(create, 'actions', Type$2.Container, CardRole.Actions, Style$2.Box, {}, 'Buttons');
1671
- const primary = make$1(create, 'primary', Type$2.ButtonBlock, null, Style$2.Primary);
1702
+ const actions = make$2(create, 'actions', Type$3.Container, CardRole.Actions, Style$3.Box, {}, 'Buttons');
1703
+ const primary = make$2(create, 'primary', Type$3.ButtonBlock, null, Style$3.Primary);
1672
1704
  primary.children = [buttonLabel(create, 'primary-label', words.primary)];
1673
- const ghost = make$1(create, 'secondary', Type$2.ButtonBlock, null, Style$2.Ghost);
1674
- const icon = make$1(create, 'secondary-icon', Type$2.Icon, null, Style$2.Icon, { iconClass: SAVE_ICON });
1705
+ const ghost = make$2(create, 'secondary', Type$3.ButtonBlock, null, Style$3.Ghost);
1706
+ const icon = make$2(create, 'secondary-icon', Type$3.Icon, null, Style$3.Icon, { iconClass: SAVE_ICON });
1675
1707
  writeStyles(icon, INLINE_ICON);
1676
1708
  ghost.children = [icon, buttonLabel(create, 'secondary-label', words.secondary)];
1677
1709
  actions.children = [primary, ghost];
@@ -1679,15 +1711,15 @@ const PART_BUILDERS = {
1679
1711
  },
1680
1712
  };
1681
1713
  function buildTitle(create, words) {
1682
- return make$1(create, 'title', Type$2.Heading, CardRole.Title, Style$2.Title, { content: words.title, level: 'h3', [LINK_TYPE]: LinkType.None }, 'Title');
1714
+ return make$2(create, 'title', Type$3.Heading, CardRole.Title, Style$3.Title, { content: words.title, level: 'h3', [LINK_TYPE]: LinkType.None }, 'Title');
1683
1715
  }
1684
1716
  /** A fresh Card v2: every part a node with its role and element style, laid out by `options.layout`. */
1685
1717
  function buildCardRecipe(create, options = {}) {
1686
1718
  const words = { ...CARD_WORDS, ...(options.words ?? {}) };
1687
1719
  const tone = options.badgeTone ?? BadgeTone.Accent;
1688
1720
  const on = (part) => options.parts?.[part] !== false;
1689
- const card = make$1(create, 'card', Type$2.Container, CardRole.Card, Style$2.Card, {}, 'Card');
1690
- const content = make$1(create, 'content', Type$2.Container, CardRole.Content, Style$2.Box, {}, 'Content');
1721
+ const card = make$2(create, 'card', Type$3.Container, CardRole.Card, Style$3.Card, {}, 'Card');
1722
+ const content = make$2(create, 'content', Type$3.Container, CardRole.Content, Style$3.Box, {}, 'Content');
1691
1723
  content.children = [
1692
1724
  ...(on(CardPart.Eyebrow) ? [PART_BUILDERS[CardPart.Eyebrow](create, words, tone)] : []),
1693
1725
  buildTitle(create, words),
@@ -1696,7 +1728,7 @@ function buildCardRecipe(create, options = {}) {
1696
1728
  ];
1697
1729
  card.children = [...(on(CardPart.Media) ? [PART_BUILDERS[CardPart.Media](create, words, tone)] : []), content];
1698
1730
  if (on(CardPart.Badge))
1699
- placeBadge(card, PART_BUILDERS[CardPart.Badge](create, words, tone), true);
1731
+ placeBadge(card, PART_BUILDERS[CardPart.Badge](create, words, tone, options.badgeIcon), true);
1700
1732
  applyCardLayout(card, options.layout ?? CardLayout.Top, options);
1701
1733
  return card;
1702
1734
  }
@@ -1718,7 +1750,7 @@ function cardRootOf(node, path) {
1718
1750
  function cardPartsOf(card) {
1719
1751
  return Object.fromEntries(CARD_PARTS.map(part => [part, !!findByRole(card, CARD_PART_ROLE[part])]));
1720
1752
  }
1721
- const imageOf = (media) => media?.children?.find(c => c.type === Type$2.Image);
1753
+ const imageOf = (media) => media?.children?.find(c => c.type === Type$3.Image);
1722
1754
  /** Put the badge where the layout says: the Media's top corner, or the head of the content column
1723
1755
  * (Image behind text, Compact, or no Media at all). The corner's insets are logical, in iox-design.css
1724
1756
  * (mirrored in RTL); `position` is the node's own, because the editing canvas forces every node's
@@ -2001,17 +2033,17 @@ function sliderSlides(children) {
2001
2033
  return (children ?? []).filter(c => !isSliderPart(c));
2002
2034
  }
2003
2035
  // ── the parts' recipe ───────────────────────────────────────────────────────────────────────────────
2004
- var Type$1;
2036
+ var Type$2;
2005
2037
  (function (Type) {
2006
2038
  Type["ButtonBlock"] = "ButtonBlock";
2007
2039
  Type["Icon"] = "Icon";
2008
2040
  Type["Container"] = "Container";
2009
- })(Type$1 || (Type$1 = {}));
2010
- var Style$1;
2041
+ })(Type$2 || (Type$2 = {}));
2042
+ var Style$2;
2011
2043
  (function (Style) {
2012
2044
  Style["Control"] = "button-secondary";
2013
2045
  Style["Icon"] = "icon";
2014
- })(Style$1 || (Style$1 = {}));
2046
+ })(Style$2 || (Style$2 = {}));
2015
2047
  /** Each part's glyph (Phosphor) and its default accessible name. */
2016
2048
  const SLIDER_PART_GLYPH = {
2017
2049
  [SliderRole.Pause]: 'ph ph-pause',
@@ -2053,7 +2085,7 @@ function legacyLookOf(slider) {
2053
2085
  /** One part, from the recipe (board 6: `button-secondary` controls, token dots) or in a migrated slider's legacy look. */
2054
2086
  function buildSliderPart(create, role, legacy) {
2055
2087
  if (role === SliderRole.Pagination) {
2056
- const dots = makeCompositePart(create, { key: 'pagination', type: Type$1.Container, props: {}, elementStyle: NO_ELEMENT_STYLE }, role, PART_LABEL[role], legacy?.paginationColor ? { ...PAGINATION_BASE, color: legacy.paginationColor } : PAGINATION_BASE);
2088
+ const dots = makeCompositePart(create, { key: 'pagination', type: Type$2.Container, props: {}, elementStyle: NO_ELEMENT_STYLE }, role, PART_LABEL[role], legacy?.paginationColor ? { ...PAGINATION_BASE, color: legacy.paginationColor } : PAGINATION_BASE);
2057
2089
  dots.children = [];
2058
2090
  return dots;
2059
2091
  }
@@ -2069,9 +2101,9 @@ function buildSliderPart(create, role, legacy) {
2069
2101
  const props = { tag: 'button', type: 'button' };
2070
2102
  if (role !== SliderRole.Pause)
2071
2103
  props[SLIDER_NAME_TRAIT] = role === SliderRole.Prev ? SLIDER_WORDS.en.prev : SLIDER_WORDS.en.next;
2072
- const button = makeCompositePart(create, { key, type: Type$1.ButtonBlock, props, elementStyle: legacy ? NO_ELEMENT_STYLE : Style$1.Control }, role, PART_LABEL[role], base);
2104
+ const button = makeCompositePart(create, { key, type: Type$2.ButtonBlock, props, elementStyle: legacy ? NO_ELEMENT_STYLE : Style$2.Control }, role, PART_LABEL[role], base);
2073
2105
  const iconBase = legacy ? { ...ICON_BASE, fontSize: `${Math.round((legacy.navigationSize ?? 44) * 0.6)}px` } : ICON_BASE;
2074
- const icon = makeCompositePart(create, { key: `${key}-icon`, type: Type$1.Icon, props: { iconClass: SLIDER_PART_GLYPH[role] }, elementStyle: legacy ? NO_ELEMENT_STYLE : Style$1.Icon }, null, 'Icon', iconBase);
2106
+ const icon = makeCompositePart(create, { key: `${key}-icon`, type: Type$2.Icon, props: { iconClass: SLIDER_PART_GLYPH[role] }, elementStyle: legacy ? NO_ELEMENT_STYLE : Style$2.Icon }, null, 'Icon', iconBase);
2075
2107
  button.children = [icon];
2076
2108
  return button;
2077
2109
  }
@@ -2263,6 +2295,11 @@ const COMPOSITE_ROLE_SPECS = {
2263
2295
  [TabsRole.Panels]: { parent: TabsRole.Tabs, locked: true, accepts: [TabsRole.Panel] },
2264
2296
  [TabsRole.Trigger]: { parent: TabsRole.List, pinned: true },
2265
2297
  [TabsRole.Panel]: { parent: TabsRole.Panels, pinned: true },
2298
+ // CC4b — a Segmented control holds only its options (each may be deleted — two stay — but never moved out); an
2299
+ // option's saving badge is optional (Option ▸ Saving badge) and stays in its option.
2300
+ [SegmentedRole.Segmented]: { parent: null, accepts: [SegmentedRole.Option] },
2301
+ [SegmentedRole.Option]: { parent: SegmentedRole.Segmented, pinned: true },
2302
+ [SegmentedRole.Badge]: { parent: SegmentedRole.Option, pinned: true },
2266
2303
  // CC3 — a Slider's controls are its own direct children (Swiper is handed them). The pause control stays while
2267
2304
  // Autoplay is on (WCAG 2.2.2): the Autoplay switch removes it, never Delete. The arrows and the dots follow
2268
2305
  // their switches and may be deleted.
@@ -2480,7 +2517,7 @@ const SLIDE_TO_ROW = 'row';
2480
2517
  const ROW_INDEX_ATTRIBUTE = 'data-iox-row-idx';
2481
2518
  const LIGHTBOX_LABEL = 'Lightbox';
2482
2519
  const DIALOG = 'Dialog';
2483
- const REPEATER = 'Repeater';
2520
+ const REPEATER$1 = 'Repeater';
2484
2521
  const SOURCE = 'source';
2485
2522
  const SOURCE_PATH = 'sourcePath';
2486
2523
  const ZERO = '0px 0px 0px 0px';
@@ -2573,7 +2610,7 @@ function buildLightboxRecipe(create, options = {}) {
2573
2610
  const lastSegment = (path) => (path ? String(path).split('.').filter(Boolean).pop() ?? '' : '');
2574
2611
  /** What a Repeater (its `source` binding) or a bound Slider (its `source` / `sourcePath` traits) repeats over. */
2575
2612
  function repeatSourceOf(node) {
2576
- if (!node || (node.type !== REPEATER && node.type !== SLIDER_TYPE))
2613
+ if (!node || (node.type !== REPEATER$1 && node.type !== SLIDER_TYPE))
2577
2614
  return null;
2578
2615
  const binding = (node.bindings ?? []).find(b => b?.prop === SOURCE);
2579
2616
  if (binding?.source)
@@ -2674,15 +2711,15 @@ const TABS_WORDS = [
2674
2711
  { label: 'Third tab', text: 'Say what this tab is about in a sentence or two. Its picture sits beside it.' },
2675
2712
  ];
2676
2713
  const TABS_NEW_TAB_WORDS = { label: 'New tab', text: 'Say what this tab is about in a sentence or two. Its picture sits beside it.' };
2677
- var Type;
2714
+ var Type$1;
2678
2715
  (function (Type) {
2679
2716
  Type["Container"] = "Container";
2680
2717
  Type["ButtonBlock"] = "ButtonBlock";
2681
2718
  Type["Text"] = "Text";
2682
2719
  Type["Image"] = "Image";
2683
2720
  Type["Repeater"] = "Repeater";
2684
- })(Type || (Type = {}));
2685
- var Style;
2721
+ })(Type$1 || (Type$1 = {}));
2722
+ var Style$1;
2686
2723
  (function (Style) {
2687
2724
  Style["Root"] = "box";
2688
2725
  Style["List"] = "tab-list";
@@ -2692,12 +2729,12 @@ var Style;
2692
2729
  Style["Panel"] = "box";
2693
2730
  Style["Media"] = "media";
2694
2731
  Style["Body"] = "body";
2695
- })(Style || (Style = {}));
2696
- const ZERO_BOX = '0px 0px 0px 0px';
2732
+ })(Style$1 || (Style$1 = {}));
2733
+ const ZERO_BOX$1 = '0px 0px 0px 0px';
2697
2734
  /** The list's hairline, as its element style writes it — read from the contract, never retyped. */
2698
- const LIST_EDGE = String(elementStyleById(Style.List)?.base['borderWidth'] ?? ZERO_BOX);
2735
+ const LIST_EDGE = String(elementStyleById(Style$1.List)?.base['borderWidth'] ?? ZERO_BOX$1);
2699
2736
  /** What each part holds — layout only; its LOOK is its element style. The list WRAPS at narrow widths (board 3). */
2700
- const PART_BASE = {
2737
+ const PART_BASE$1 = {
2701
2738
  [TabsRole.Tabs]: { display: 'flex', width: '100%', minHeight: 'auto', height: 'auto' },
2702
2739
  [TabsRole.List]: { display: 'flex', gap: '4px', minHeight: 'auto', height: 'auto' },
2703
2740
  [TabsRole.Trigger]: { width: 'auto', minHeight: 'auto', height: 'auto', cursor: 'pointer' },
@@ -2705,9 +2742,9 @@ const PART_BASE = {
2705
2742
  // Board 3: a panel is any nodes at all — the recipe's is a picture beside its words.
2706
2743
  [TabsRole.Panel]: { display: 'grid', gridTemplateColumns: '1fr 1.2fr', gap: '24px', alignItems: 'center', width: '100%', minHeight: 'auto', height: 'auto' },
2707
2744
  };
2708
- const LABEL_BASE = { width: 'auto', minHeight: 'auto', padding: ZERO_BOX, margin: ZERO_BOX };
2745
+ const LABEL_BASE$1 = { width: 'auto', minHeight: 'auto', padding: ZERO_BOX$1, margin: ZERO_BOX$1 };
2709
2746
  const IMAGE_BASE = { display: 'block', width: '100%', maxWidth: '100%', aspectRatio: '4 / 3', height: 'auto', minHeight: 'auto' };
2710
- const BODY_BASE = { margin: ZERO_BOX, padding: ZERO_BOX, minHeight: 'auto' };
2747
+ const BODY_BASE = { margin: ZERO_BOX$1, padding: ZERO_BOX$1, minHeight: 'auto' };
2711
2748
  /** On a phone a panel's picture sits above its words. */
2712
2749
  const PANEL_STACK = { gridTemplateColumns: '1fr' };
2713
2750
  const ORIENTATION_LAYOUT = {
@@ -2717,42 +2754,42 @@ const ORIENTATION_LAYOUT = {
2717
2754
  },
2718
2755
  [TabsOrientation.Vertical]: {
2719
2756
  root: { flexDirection: 'row', alignItems: 'flex-start', gap: '24px' },
2720
- list: { flexDirection: 'column', flexWrap: 'nowrap', width: 'auto', flexShrink: '0', borderWidth: ZERO_BOX },
2757
+ list: { flexDirection: 'column', flexWrap: 'nowrap', width: 'auto', flexShrink: '0', borderWidth: ZERO_BOX$1 },
2721
2758
  rootStack: { flexDirection: 'column', alignItems: 'stretch', gap: '20px' },
2722
2759
  listStack: { width: '100%' },
2723
2760
  },
2724
2761
  };
2725
2762
  const ROOT_STACK_KEYS = ['flexDirection', 'alignItems', 'gap'];
2726
2763
  const LIST_STACK_KEYS = ['width'];
2727
- function make(create, key, type, role, style, props = {}, label) {
2728
- return makeCompositePart(create, { key, type, props, elementStyle: style }, role, label, role ? PART_BASE[role] : undefined);
2764
+ function make$1(create, key, type, role, style, props = {}, label) {
2765
+ return makeCompositePart(create, { key, type, props, elementStyle: style }, role, label, role ? PART_BASE$1[role] : undefined);
2729
2766
  }
2730
2767
  /** One tab and its panel, sharing `itemKey`. */
2731
2768
  function buildTabPair(create, words, itemKey) {
2732
- const tab = make(create, `${itemKey}-tab`, Type.ButtonBlock, TabsRole.Trigger, Style.Tab, {}, 'Tab');
2769
+ const tab = make$1(create, `${itemKey}-tab`, Type$1.ButtonBlock, TabsRole.Trigger, Style$1.Tab, {}, 'Tab');
2733
2770
  tab.itemKey = itemKey;
2734
- const label = make(create, `${itemKey}-label`, Type.Text, null, Style.Label, { content: words.label, tag: 'span' }, 'Text');
2735
- writeStyles(label, LABEL_BASE);
2771
+ const label = make$1(create, `${itemKey}-label`, Type$1.Text, null, Style$1.Label, { content: words.label, tag: 'span' }, 'Text');
2772
+ writeStyles(label, LABEL_BASE$1);
2736
2773
  tab.children = [label];
2737
- const panel = make(create, `${itemKey}-panel`, Type.Container, TabsRole.Panel, Style.Panel, {}, 'Panel');
2774
+ const panel = make$1(create, `${itemKey}-panel`, Type$1.Container, TabsRole.Panel, Style$1.Panel, {}, 'Panel');
2738
2775
  panel.itemKey = itemKey;
2739
2776
  writeLayerStyles(panel, TABS_STACK_BREAKPOINT, PANEL_STACK);
2740
- const image = make(create, `${itemKey}-image`, Type.Image, null, Style.Media, { src: '', alt: '' }, 'Image');
2777
+ const image = make$1(create, `${itemKey}-image`, Type$1.Image, null, Style$1.Media, { src: '', alt: '' }, 'Image');
2741
2778
  writeStyles(image, IMAGE_BASE);
2742
- const text = make(create, `${itemKey}-text`, Type.Text, null, Style.Body, { content: words.text, tag: 'p' }, 'Text');
2779
+ const text = make$1(create, `${itemKey}-text`, Type$1.Text, null, Style$1.Body, { content: words.text, tag: 'p' }, 'Text');
2743
2780
  writeStyles(text, BODY_BASE);
2744
2781
  panel.children = [image, text];
2745
2782
  return { tab, panel };
2746
2783
  }
2747
2784
  /** A fresh Tabs: three tabs, the first on, activated by a click, the list across the top (board 3). */
2748
2785
  function buildTabsRecipe(create, options = {}) {
2749
- const root = make(create, 'tabs', Type.Container, TabsRole.Tabs, Style.Root, {}, 'Tabs');
2786
+ const root = make$1(create, 'tabs', Type$1.Container, TabsRole.Tabs, Style$1.Root, {}, 'Tabs');
2750
2787
  writeProp(root, TabsBehaviourTrait.ActivateOn, options.activateOn ?? TabsActivateOn.Click);
2751
2788
  writeProp(root, TabsBehaviourTrait.Orientation, options.orientation ?? TabsOrientation.Horizontal);
2752
2789
  if (options.label)
2753
2790
  writeProp(root, TabsBehaviourTrait.Label, options.label);
2754
- const list = make(create, 'list', Type.Container, TabsRole.List, Style.List, {}, 'Tab list');
2755
- const panels = make(create, 'panels', Type.Container, TabsRole.Panels, Style.Panels, {}, 'Panels');
2791
+ const list = make$1(create, 'list', Type$1.Container, TabsRole.List, Style$1.List, {}, 'Tab list');
2792
+ const panels = make$1(create, 'panels', Type$1.Container, TabsRole.Panels, Style$1.Panels, {}, 'Panels');
2756
2793
  const pairs = (options.tabs ?? TABS_WORDS).map((w, i) => buildTabPair(create, w, `k${i + 1}`));
2757
2794
  list.children = pairs.map(p => p.tab);
2758
2795
  panels.children = pairs.map(p => p.panel);
@@ -2782,7 +2819,7 @@ function tabsPanels(root) {
2782
2819
  }
2783
2820
  /** True when the Tabs takes its tabs from content (its list is a Repeater, R3). */
2784
2821
  function isTabsFromContent(root) {
2785
- return !!root && tabsListOf(root)?.type === Type.Repeater;
2822
+ return !!root && tabsListOf(root)?.type === Type$1.Repeater;
2786
2823
  }
2787
2824
  /** The panel paired with `tab` (the same key), or undefined. From content the one template panel pairs the template tab. */
2788
2825
  function tabPanelOf(root, tab) {
@@ -2807,15 +2844,15 @@ function tabsPartnerOf(root, node) {
2807
2844
  /** The words a tab shows: its first Text's. */
2808
2845
  function tabLabelNodeOf(tab) {
2809
2846
  let hit;
2810
- walkComposite(tab, n => { if (!hit && n !== tab && n.type === Type.Text)
2847
+ walkComposite(tab, n => { if (!hit && n !== tab && n.type === Type$1.Text)
2811
2848
  hit = n; });
2812
2849
  return hit;
2813
2850
  }
2814
- const stripTags = (v) => String(v ?? '').replace(/<[^>]*>/g, '').trim();
2851
+ const stripTags$1 = (v) => String(v ?? '').replace(/<[^>]*>/g, '').trim();
2815
2852
  /** A tab's name in the Items list, the layer tree and the item-action picker: its words. */
2816
2853
  function tabLabel(tab) {
2817
2854
  const label = tabLabelNodeOf(tab);
2818
- return label ? stripTags(readProp(label, 'content')) : '';
2855
+ return label ? stripTags$1(readProp(label, 'content')) : '';
2819
2856
  }
2820
2857
  /** Items ▸ rename: the tab's words. */
2821
2858
  function renameTab(tab, words) {
@@ -2825,14 +2862,14 @@ function renameTab(tab, words) {
2825
2862
  /** The first Text inside a panel (the words From content binds to). */
2826
2863
  function tabPanelTextOf(panel) {
2827
2864
  let hit;
2828
- walkComposite(panel, n => { if (!hit && n !== panel && n.type === Type.Text)
2865
+ walkComposite(panel, n => { if (!hit && n !== panel && n.type === Type$1.Text)
2829
2866
  hit = n; });
2830
2867
  return hit;
2831
2868
  }
2832
2869
  /** The first Image inside a panel. */
2833
2870
  function tabPanelImageOf(panel) {
2834
2871
  let hit;
2835
- walkComposite(panel, n => { if (!hit && n.type === Type.Image)
2872
+ walkComposite(panel, n => { if (!hit && n.type === Type$1.Image)
2836
2873
  hit = n; });
2837
2874
  return hit;
2838
2875
  }
@@ -2970,7 +3007,7 @@ function tabsItemTriggerIds(root) {
2970
3007
  }
2971
3008
  }
2972
3009
  function tabsScope(rootId, behaviour, keys, label = '') {
2973
- return { rootId, behaviour, keys, active: keys[0] ?? null, label };
3010
+ return { kind: CompositeKind.Tabs, rootId, behaviour, keys, active: keys[0] ?? null, label };
2974
3011
  }
2975
3012
  /** The item keys a manual Tabs pairs by — its tabs' own keys, in order (a tab with none by its index). */
2976
3013
  function manualTabKeys(root) {
@@ -3148,6 +3185,351 @@ function tabsToManual(root, list, panels, rows, clone, resolve) {
3148
3185
  return pairs;
3149
3186
  }
3150
3187
 
3188
+ /**
3189
+ * THE SEGMENTED CONTROL (CC4b — composite K4 T32, pulled forward; complex-components board 10, APPROVED 2026-10-23 with
3190
+ * Q31–Q40 as recommended). One of a few, always one on, FIXED options (R3 / Q36). Not a component: a recipe of
3191
+ * ordinary nodes, each part carrying a role, so every option, its words and its optional badge are selectable on the
3192
+ * canvas, in the layer tree and the breadcrumb, and wear their own element styles (R2).
3193
+ *
3194
+ * Container `segmented` role segmented traits defaultOn (an option's key) · ariaLabel (its name)
3195
+ * └─ ButtonBlock `segmented-option` ×2–4 role segmented.option itemKey monthly · yearly … → <button role=radio>
3196
+ * ├─ Text `button-label` the words
3197
+ * └─ Container `badge-success` role segmented.badge (optional, off) › Icon + Text — a placeholder (a price claim)
3198
+ *
3199
+ * The ARIA shape is the APG RADIO GROUP (Q31): `role=radiogroup` + its accessible name on the root, `<button role=radio
3200
+ * aria-checked>` per option with a roving tabindex — one Tab stop; ← → follow the reading direction (mirrored under
3201
+ * RTL), ↑ ↓ the DOM order, every move wraps and turns the option on. It runs the EXCLUSIVE runtime the Tabs run
3202
+ * (`exclusive-runtime.ts`), on the builder canvas and both engine paths, from the attribute planners below. What follows
3203
+ * the control (a price) is an ordinary node OUTSIDE it styled "when its option is on" — the targeted `trigger-on`.
3204
+ */
3205
+ var SegmentedTrait;
3206
+ (function (SegmentedTrait) {
3207
+ /** The option on at first paint — an option's key. */
3208
+ SegmentedTrait["DefaultOn"] = "defaultOn";
3209
+ /** The radio group's accessible name (`aria-label` on the root). Empty → an audit finding. */
3210
+ SegmentedTrait["Label"] = "ariaLabel";
3211
+ })(SegmentedTrait || (SegmentedTrait = {}));
3212
+ /** Q40: two options at least, four at most (past four the words no longer fit a phone row — a Select or Tabs then). */
3213
+ const SEGMENTED_MIN_OPTIONS = 2;
3214
+ const SEGMENTED_MAX_OPTIONS = 4;
3215
+ /** A fresh Segmented control's options (board 10: a billing period) — generic words, the author's to rename. */
3216
+ const SEGMENTED_WORDS = [
3217
+ { key: 'monthly', label: 'Monthly' },
3218
+ { key: 'yearly', label: 'Yearly' },
3219
+ ];
3220
+ const SEGMENTED_NEW_OPTION_WORDS = 'New option';
3221
+ /** The name a fresh control carries (board 10). */
3222
+ const SEGMENTED_NAME = 'Billing period';
3223
+ /** Q33: the saving badge's words start as a PLACEHOLDER — a saving is a price claim, never invented. */
3224
+ const SEGMENTED_BADGE_WORDS = 'Yearly saving';
3225
+ const SEGMENTED_BADGE_TONE = BadgeTone.Success;
3226
+ var Type;
3227
+ (function (Type) {
3228
+ Type["Container"] = "Container";
3229
+ Type["ButtonBlock"] = "ButtonBlock";
3230
+ Type["Text"] = "Text";
3231
+ })(Type || (Type = {}));
3232
+ var Style;
3233
+ (function (Style) {
3234
+ Style["Root"] = "segmented";
3235
+ Style["Option"] = "segmented-option";
3236
+ Style["Label"] = "button-label";
3237
+ })(Style || (Style = {}));
3238
+ const ZERO_BOX = '0px 0px 0px 0px';
3239
+ /** What each part holds — layout only; its LOOK is its element style (the track's fill, border, radius and pad; the
3240
+ * option's ink, pad, radius and 44px target). The options sit in a flex row a gap token apart (board 10); each GROWS,
3241
+ * which changes nothing while the track hugs them and shares the row when the track is stretched (the pricing
3242
+ * pattern's phone layer: board 10's full-width control). */
3243
+ const PART_BASE = {
3244
+ [SegmentedRole.Segmented]: { display: 'inline-flex', flexDirection: 'row', alignItems: 'stretch', gap: 'var(--iox-segmented-gap)', width: 'auto', maxWidth: '100%', height: 'auto' },
3245
+ [SegmentedRole.Option]: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '8px', width: 'auto', height: 'auto', cursor: 'pointer', flexGrow: '1' },
3246
+ };
3247
+ const LABEL_BASE = { width: 'auto', minHeight: 'auto', padding: ZERO_BOX, margin: ZERO_BOX };
3248
+ /** The badge inside an option keeps to the option's row (never its own line). */
3249
+ const BADGE_IN_OPTION = { alignSelf: 'center' };
3250
+ function make(create, key, type, role, style, props = {}, label) {
3251
+ return makeCompositePart(create, { key, type, props, elementStyle: style }, role, label, role ? PART_BASE[role] : undefined);
3252
+ }
3253
+ /** One option: a ButtonBlock carrying its key, holding its words. */
3254
+ function buildSegmentedOption(create, words) {
3255
+ const option = make(create, `${words.key}-option`, Type.ButtonBlock, SegmentedRole.Option, Style.Option, {}, 'Option');
3256
+ option.itemKey = words.key;
3257
+ const label = make(create, `${words.key}-label`, Type.Text, null, Style.Label, { content: words.label, tag: 'span' }, 'Text');
3258
+ writeStyles(label, LABEL_BASE);
3259
+ option.children = [label];
3260
+ return option;
3261
+ }
3262
+ /** A fresh Segmented control: Monthly · Yearly, Monthly on, named "Billing period" (board 10 ▸ Palette). */
3263
+ function buildSegmentedRecipe(create, options = {}) {
3264
+ const words = options.options ?? SEGMENTED_WORDS;
3265
+ const root = make(create, 'segmented', Type.Container, SegmentedRole.Segmented, Style.Root, {}, 'Segmented');
3266
+ root.children = words.map(w => buildSegmentedOption(create, w));
3267
+ writeProp(root, SegmentedTrait.DefaultOn, options.defaultOn && words.some(w => w.key === options.defaultOn) ? options.defaultOn : words[0]?.key ?? '');
3268
+ writeProp(root, SegmentedTrait.Label, options.label ?? SEGMENTED_NAME);
3269
+ return root;
3270
+ }
3271
+ // ── reading a tree ──────────────────────────────────────────────────────────────────────────────
3272
+ function isSegmentedRoot(node) {
3273
+ return node?.role === SegmentedRole.Segmented;
3274
+ }
3275
+ /** The options in order. */
3276
+ function segmentedOptions(root) {
3277
+ return (root?.children ?? []).filter(c => c.role === SegmentedRole.Option);
3278
+ }
3279
+ /** The key an option renders with: its own key, else its index among the options. */
3280
+ function segmentedOptionKey(option, index) {
3281
+ return option.itemKey || `item-${index}`;
3282
+ }
3283
+ /** Every option's key, in order. */
3284
+ function segmentedKeys(root) {
3285
+ return segmentedOptions(root).map((o, i) => segmentedOptionKey(o, i));
3286
+ }
3287
+ /** The words an option shows: its first Text that is not inside its badge. */
3288
+ function segmentedOptionLabelNodeOf(option) {
3289
+ for (const child of option.children ?? []) {
3290
+ if (child.role === SegmentedRole.Badge)
3291
+ continue;
3292
+ if (child.type === Type.Text)
3293
+ return child;
3294
+ let hit;
3295
+ walkComposite(child, n => { if (!hit && n.type === Type.Text)
3296
+ hit = n; });
3297
+ if (hit)
3298
+ return hit;
3299
+ }
3300
+ return undefined;
3301
+ }
3302
+ const stripTags = (v) => String(v ?? '').replace(/<[^>]*>/g, '').trim();
3303
+ /** An option's name in the Options list, the layer tree, the item pickers and "Showing on canvas": its words. */
3304
+ function segmentedOptionLabel(option) {
3305
+ const label = segmentedOptionLabelNodeOf(option);
3306
+ return label ? stripTags(readProp(label, 'content')) : '';
3307
+ }
3308
+ /** Options ▸ rename: the option's words. */
3309
+ function renameSegmentedOption(option, words) {
3310
+ const label = segmentedOptionLabelNodeOf(option);
3311
+ return !!label && writeProp(label, 'content', words);
3312
+ }
3313
+ /** The radio group's accessible name (empty when unnamed). */
3314
+ function segmentedLabel(root) {
3315
+ return root ? String(readProp(root, SegmentedTrait.Label) ?? '').trim() : '';
3316
+ }
3317
+ /** The option on by default: the stored key when it still names an option, else the first option. */
3318
+ function segmentedDefaultOn(root) {
3319
+ const keys = segmentedKeys(root);
3320
+ const stored = root ? String(readProp(root, SegmentedTrait.DefaultOn) ?? '') : '';
3321
+ return keys.includes(stored) ? stored : keys[0] ?? null;
3322
+ }
3323
+ /** Behaviour ▸ On by default and Accessibility ▸ Name. False when the root has no such trait. */
3324
+ function setSegmentedBehaviour(root, patch) {
3325
+ let ok = true;
3326
+ if (patch.defaultOn !== undefined)
3327
+ ok = writeProp(root, SegmentedTrait.DefaultOn, patch.defaultOn) && ok;
3328
+ if (patch.label !== undefined)
3329
+ ok = writeProp(root, SegmentedTrait.Label, patch.label) && ok;
3330
+ return ok;
3331
+ }
3332
+ // ── editing (Options list, toolbar ▸ Add option, the structure guard) ───────────────────────────
3333
+ var SegmentedEditRefusal;
3334
+ (function (SegmentedEditRefusal) {
3335
+ /** Q40: a Segmented control keeps at least two options. */
3336
+ SegmentedEditRefusal["MinOptions"] = "min-options";
3337
+ /** Q40: a Segmented control holds four options at most. */
3338
+ SegmentedEditRefusal["MaxOptions"] = "max-options";
3339
+ })(SegmentedEditRefusal || (SegmentedEditRefusal = {}));
3340
+ /** Why adding an option to `root` is refused (four already), or null. */
3341
+ function segmentedAddRefusal(root) {
3342
+ return root && segmentedOptions(root).length >= SEGMENTED_MAX_OPTIONS ? SegmentedEditRefusal.MaxOptions : null;
3343
+ }
3344
+ /** Why removing an option from `root` is refused (two left), or null. */
3345
+ function segmentedRemovalRefusal(root, node) {
3346
+ if (!root || (node && node.role !== SegmentedRole.Option))
3347
+ return null;
3348
+ return segmentedOptions(root).length <= SEGMENTED_MIN_OPTIONS ? SegmentedEditRefusal.MinOptions : null;
3349
+ }
3350
+ /** A key no option of `root` holds yet (`k3`…). */
3351
+ function nextSegmentedKey(root) {
3352
+ const taken = new Set(segmentedOptions(root).map(o => o.itemKey).filter(Boolean));
3353
+ let n = segmentedOptions(root).length + 1;
3354
+ while (taken.has(`k${n}`))
3355
+ n++;
3356
+ return `k${n}`;
3357
+ }
3358
+ /** Options ▸ Add option (and the toolbar's "Add option"): a fresh option after `after` (or at the end). Null when
3359
+ * refused (four already). */
3360
+ function addSegmentedOption(root, create, after, words = SEGMENTED_NEW_OPTION_WORDS) {
3361
+ if (segmentedAddRefusal(root))
3362
+ return null;
3363
+ const option = buildSegmentedOption(create, { key: nextSegmentedKey(root), label: words });
3364
+ const children = [...(root.children ?? [])];
3365
+ const at = after ? children.indexOf(after) : -1;
3366
+ children.splice(at < 0 ? children.length : at + 1, 0, option);
3367
+ root.children = children;
3368
+ return option;
3369
+ }
3370
+ /** Options ▸ ✕: remove an option. False when refused (two left) or `option` is not one of the root's. A removed
3371
+ * default hands "On by default" to the first option left. */
3372
+ function removeSegmentedOption(root, option) {
3373
+ if (segmentedRemovalRefusal(root, option) || !segmentedOptions(root).includes(option))
3374
+ return false;
3375
+ const wasDefault = segmentedDefaultOn(root) === option.itemKey;
3376
+ root.children = (root.children ?? []).filter(c => c !== option);
3377
+ if (wasDefault)
3378
+ writeProp(root, SegmentedTrait.DefaultOn, segmentedKeys(root)[0] ?? '');
3379
+ return true;
3380
+ }
3381
+ /** Options ▸ drag to reorder: move an option to `toIndex` among the options. */
3382
+ function moveSegmentedOption(root, option, toIndex) {
3383
+ const children = [...(root.children ?? [])];
3384
+ const from = children.indexOf(option);
3385
+ if (from < 0 || option.role !== SegmentedRole.Option)
3386
+ return false;
3387
+ children.splice(from, 1);
3388
+ const options = children.filter(c => c.role === SegmentedRole.Option);
3389
+ const anchor = options[Math.max(0, Math.min(toIndex, options.length))];
3390
+ children.splice(anchor ? children.indexOf(anchor) : children.length, 0, option);
3391
+ root.children = children;
3392
+ return true;
3393
+ }
3394
+ /** The saving badge inside an option, or undefined. */
3395
+ function segmentedBadgeOf(option) {
3396
+ return (option?.children ?? []).find(c => c.role === SegmentedRole.Badge);
3397
+ }
3398
+ /** Option ▸ Saving badge (Q33): stamp the badge (`badge-success` › Icon + Text, the placeholder words) inside the
3399
+ * option, after its words — or remove it. Returns the badge stamped, or null (removed / nothing changed). */
3400
+ function setSegmentedBadge(option, on, create) {
3401
+ const existing = segmentedBadgeOf(option);
3402
+ if (!on) {
3403
+ if (existing)
3404
+ option.children = (option.children ?? []).filter(c => c !== existing);
3405
+ return null;
3406
+ }
3407
+ if (existing || !create)
3408
+ return null;
3409
+ const badge = buildBadge(create, { tone: SEGMENTED_BADGE_TONE, text: SEGMENTED_BADGE_WORDS, key: `${option.itemKey ?? 'option'}-badge` });
3410
+ badge.role = SegmentedRole.Badge;
3411
+ badge.label = 'Badge';
3412
+ writeStyles(badge, BADGE_IN_OPTION);
3413
+ option.children = [...(option.children ?? []), badge];
3414
+ return badge;
3415
+ }
3416
+ /** Every "Option on" (`trigger-on`) state inside an option points at ITS option — the part that carries
3417
+ * `data-iox-on` while it is on. */
3418
+ function segmentedItemTriggerIds(root) {
3419
+ for (const option of segmentedOptions(root)) {
3420
+ if (!option.id)
3421
+ continue;
3422
+ walkComposite(option, n => {
3423
+ if (n === option || !n.stateStyles?.[ITEM_OPEN_STATE])
3424
+ return;
3425
+ n.stateTriggers = { ...(n.stateTriggers ?? {}), [ITEM_OPEN_STATE]: option.id };
3426
+ });
3427
+ }
3428
+ }
3429
+ // ── state and attributes (both renderers, SSR included) ────────────────────────────────────────
3430
+ /** A Segmented control behaves like a horizontal Tabs activated by a click — only its keys and markup differ. */
3431
+ const SEGMENTED_BEHAVIOUR = { activateOn: TabsActivateOn.Click, orientation: TabsOrientation.Horizontal };
3432
+ /** The render scope of one Segmented control: its scope id, every option key in order, the one on at first paint (its
3433
+ * default) and its name — ONE decision for both engine paths. */
3434
+ function segmentedScopeFor(root, rootCssId, rowKeys = []) {
3435
+ const keys = segmentedKeys(root);
3436
+ return {
3437
+ kind: CompositeKind.Segmented,
3438
+ rootId: compositeScopeId(rootCssId, rowKeys),
3439
+ behaviour: SEGMENTED_BEHAVIOUR,
3440
+ keys,
3441
+ active: segmentedDefaultOn(root),
3442
+ label: segmentedLabel(root),
3443
+ };
3444
+ }
3445
+ /** The root: the radio group, named; its default and (inside repeated rows) its scope id ride on it. */
3446
+ function segmentedRootAttributes(label, defaultOn, scopeId) {
3447
+ return {
3448
+ [COMPOSITE_ATTRIBUTE]: CompositeKind.Segmented,
3449
+ role: 'radiogroup',
3450
+ ...(label ? { 'aria-label': label } : {}),
3451
+ ...(defaultOn ? { [DEFAULT_ON_ATTRIBUTE]: defaultOn } : {}),
3452
+ ...(scopeId ? { [SCOPE_ATTRIBUTE]: scopeId } : {}),
3453
+ };
3454
+ }
3455
+ /** The root's attributes read off the node itself (the engine writes a root's own attributes from its parent's scope). */
3456
+ function segmentedRootAttributesOf(root, scopeId) {
3457
+ return segmentedRootAttributes(segmentedLabel(root), segmentedDefaultOn(root), scopeId);
3458
+ }
3459
+ /** An option: a real button announced as a radio — checked = the one option in the Tab order (roving tabindex). */
3460
+ function segmentedOptionAttributes(key, on) {
3461
+ return {
3462
+ type: 'button',
3463
+ role: 'radio',
3464
+ 'aria-checked': on ? 'true' : 'false',
3465
+ tabindex: on ? '0' : '-1',
3466
+ [ITEM_KEY_ATTRIBUTE]: key,
3467
+ ...(on ? { [ON_ATTRIBUTE]: '' } : {}),
3468
+ };
3469
+ }
3470
+ /** The attributes a part of a Segmented control writes on its own element (both engine paths, SSR included). */
3471
+ function segmentedPartAttributes(node, scope, key, rowScoped = false) {
3472
+ switch (node.role) {
3473
+ case SegmentedRole.Segmented: return segmentedRootAttributes(scope.label, scope.active, rowScoped ? scope.rootId : undefined);
3474
+ case SegmentedRole.Option: return key ? segmentedOptionAttributes(key, scope.active === key) : {};
3475
+ default: return {};
3476
+ }
3477
+ }
3478
+ /**
3479
+ * The APG radio group's keys on an option: → / ↓ the next option, ← / ↑ the previous — ← and → follow the reading
3480
+ * direction (mirrored under RTL: ← is the next option), ↑ ↓ always the DOM order. Every move wraps and turns the option
3481
+ * on. Space / Enter are the button's own (a click: it turns on).
3482
+ */
3483
+ function segmentedKeyAction(key, rtl = false) {
3484
+ switch (key) {
3485
+ case 'ArrowDown': return AccordionKeyAction.Next;
3486
+ case 'ArrowUp': return AccordionKeyAction.Previous;
3487
+ case 'ArrowRight': return rtl ? AccordionKeyAction.Previous : AccordionKeyAction.Next;
3488
+ case 'ArrowLeft': return rtl ? AccordionKeyAction.Next : AccordionKeyAction.Previous;
3489
+ default: return null;
3490
+ }
3491
+ }
3492
+
3493
+ const REPEATER = 'Repeater';
3494
+ /** The scope an exclusive root renders its parts with: a Segmented control's options and default, or a Tabs' keys —
3495
+ * From content, the rows its list's Repeater resolved (`rowsOf`). `rowKeys` = the repeated rows around the root. */
3496
+ function exclusiveScopeFor(root, rootCssId, rowsOf, rowKeys = []) {
3497
+ if (isSegmentedRoot(root))
3498
+ return segmentedScopeFor(root, rootCssId, rowKeys);
3499
+ const list = tabsListOf(root);
3500
+ return tabsScopeFor(root, rootCssId, list?.type === REPEATER ? rowsOf(list) : null, rowKeys);
3501
+ }
3502
+ /** The attributes an exclusive ROOT writes on its own element, read off the node (its scope id when it sits in
3503
+ * repeated rows). */
3504
+ function exclusiveRootAttributesOf(root, scopeId) {
3505
+ return isSegmentedRoot(root) ? segmentedRootAttributesOf(root, scopeId) : tabsRootAttributes(tabsBehaviour(root), scopeId);
3506
+ }
3507
+ /** True when `node` is a part of the kind `scope` renders (a tab inside a Tabs' scope; an option inside a Segmented's). */
3508
+ function isPartOfExclusiveScope(node, scope) {
3509
+ const kind = exclusiveKindOf(node);
3510
+ return !!kind && kind === (scope.kind ?? CompositeKind.Tabs);
3511
+ }
3512
+ /** The attributes a part of an exclusive composite writes on its own element (both engine paths, SSR included). */
3513
+ function exclusivePartAttributes(node, scope, key, rowScoped = false) {
3514
+ return scope.kind === CompositeKind.Segmented ? segmentedPartAttributes(node, scope, key, rowScoped) : tabsPartAttributes(node, scope, key, rowScoped);
3515
+ }
3516
+ /** The behaviour an exclusive root runs with (a Segmented control: a click, a row — it has no Behaviour traits). */
3517
+ function exclusiveBehaviourOf(root) {
3518
+ return isSegmentedRoot(root) ? { ...SEGMENTED_BEHAVIOUR } : tabsBehaviour(root);
3519
+ }
3520
+ /** The accessible name an exclusive root gives its group (a Tabs' list, a Segmented control's radio group). */
3521
+ function exclusiveLabelOf(root) {
3522
+ return isSegmentedRoot(root) ? segmentedLabel(root) : tabsLabel(root);
3523
+ }
3524
+ /** The item an exclusive root shows with no other say (a Segmented control's On by default), or null (a Tabs: its first). */
3525
+ function exclusiveDefaultOf(root) {
3526
+ return isSegmentedRoot(root) ? segmentedDefaultOn(root) : null;
3527
+ }
3528
+ /** An exclusive item's words — a tab's, an option's (never its badge's) — for the pickers, the tree and the switchers. */
3529
+ function exclusiveItemLabel(part) {
3530
+ return exclusiveKindOf(part) === CompositeKind.Segmented ? segmentedOptionLabel(part) : tabLabel(part);
3531
+ }
3532
+
3151
3533
  const KIND_ROOT = (kind) => `[${COMPOSITE_ATTRIBUTE}="${kind}"]`;
3152
3534
  const EXCLUSIVE_KINDS = Object.keys(EXCLUSIVE_KIND_ROLES);
3153
3535
  const ROOT_SELECTOR = EXCLUSIVE_KINDS.map(KIND_ROOT).join(', ');
@@ -3226,7 +3608,7 @@ class ExclusiveRuntime {
3226
3608
  if (!trigger)
3227
3609
  return;
3228
3610
  const rtl = isRtl(trigger);
3229
- const action = tabsKeyAction(e.key, this.behaviourValue.orientation, rtl);
3611
+ const action = this.holdsTriggers ? segmentedKeyAction(e.key, rtl) : tabsKeyAction(e.key, this.behaviourValue.orientation, rtl);
3230
3612
  if (!action)
3231
3613
  return;
3232
3614
  const triggers = this.triggers();
@@ -3237,14 +3619,14 @@ class ExclusiveRuntime {
3237
3619
  target.focus();
3238
3620
  this.activate(this.keyOf(target));
3239
3621
  };
3240
- this.kind = kindOf(root);
3622
+ this.kind = options.kind ?? kindOf(root);
3241
3623
  this.behaviourValue = options.behaviour ?? behaviourOf(root);
3242
3624
  root.setAttribute(COMPOSITE_ATTRIBUTE, this.kind);
3243
3625
  EXCLUSIVE_RUNTIMES.set(root, this);
3244
- // The server rendered the first state (every trigger keyed, one on); with no server state the first is on.
3626
+ // The server rendered the first state (every trigger keyed, one on); with no server state the default is on.
3245
3627
  const triggers = this.triggers();
3246
3628
  const serverOn = !options.behaviour ? triggers.find(t => t.hasAttribute(ON_ATTRIBUTE) && t.hasAttribute(ITEM_KEY_ATTRIBUTE)) : undefined;
3247
- this.live = serverOn ? this.keyOf(serverOn) : (triggers[0] ? this.keyOf(triggers[0]) : null);
3629
+ this.live = serverOn ? this.keyOf(serverOn) : this.defaultKey();
3248
3630
  this.awaitingItems = !triggers.length;
3249
3631
  // Capture: on the builder canvas every part's own listener stops the click (it selects that part), and the tab
3250
3632
  // must still turn on — the canvas is a live runtime.
@@ -3329,6 +3711,16 @@ class ExclusiveRuntime {
3329
3711
  keys() {
3330
3712
  return this.triggers().map(t => this.keyOf(t));
3331
3713
  }
3714
+ /** The key on with no server state: the asked default when it names an item, else the first item. */
3715
+ defaultKey() {
3716
+ const keys = this.keys();
3717
+ const asked = this.options.defaultKey?.() ?? this.root.getAttribute(DEFAULT_ON_ATTRIBUTE);
3718
+ return asked && keys.includes(asked) ? asked : keys[0] ?? null;
3719
+ }
3720
+ /** True for a Segmented control: the root IS its radio group and holds its options. */
3721
+ get holdsTriggers() {
3722
+ return exclusiveRootHoldsTriggers(this.kind);
3723
+ }
3332
3724
  /** The element(s) that ARE the tablist: the ones a renderer already gave the role (the engine's component-path
3333
3725
  * Repeater puts it on its inner root, which holds the tabs), else the elements carrying the list's role class. */
3334
3726
  lists() {
@@ -3358,13 +3750,15 @@ class ExclusiveRuntime {
3358
3750
  const keys = triggers.map(t => this.keyOf(t));
3359
3751
  if (this.awaitingItems && keys.length) {
3360
3752
  this.awaitingItems = false;
3361
- this.live = keys[0];
3753
+ this.live = this.defaultKey();
3362
3754
  first = true;
3363
3755
  }
3364
3756
  if (this.live === null || !keys.includes(this.live))
3365
- this.live = keys[0] ?? null;
3757
+ this.live = this.defaultKey();
3366
3758
  const forced = this.options.forced?.() ?? null;
3367
3759
  const next = forced !== null && keys.includes(forced) ? forced : this.live;
3760
+ if (this.holdsTriggers)
3761
+ return this.stampRadioGroup(triggers, next, first);
3368
3762
  const rootId = this.rootId();
3369
3763
  const vertical = this.behaviourValue.orientation === TabsOrientation.Vertical;
3370
3764
  for (const list of this.lists()) {
@@ -3400,6 +3794,27 @@ class ExclusiveRuntime {
3400
3794
  setAttr(panel, ON_ATTRIBUTE, on ? '' : null);
3401
3795
  setAttr(panel, 'hidden', on ? null : '');
3402
3796
  }
3797
+ this.announce(triggers, next, first, panelOf);
3798
+ }
3799
+ /** A Segmented control's markup (CC4b): the root a named radio group, each option a radio, one checked. */
3800
+ stampRadioGroup(options, next, first) {
3801
+ setAttr(this.root, 'role', 'radiogroup');
3802
+ if (this.options.label)
3803
+ setAttr(this.root, 'aria-label', this.options.label() || null);
3804
+ for (const option of options) {
3805
+ const key = this.keyOf(option);
3806
+ const on = key === next;
3807
+ setAttr(option, ITEM_KEY_ATTRIBUTE, key);
3808
+ setAttr(option, 'type', option.tagName === 'BUTTON' ? 'button' : null);
3809
+ setAttr(option, 'role', 'radio');
3810
+ setAttr(option, 'aria-checked', on ? 'true' : 'false');
3811
+ setAttr(option, 'tabindex', on ? '0' : '-1');
3812
+ setAttr(option, ON_ATTRIBUTE, on ? '' : null);
3813
+ }
3814
+ this.announce(options, next, first);
3815
+ }
3816
+ /** Move the shown key; dispatch iox-item-off on what was on and iox-item-on on what is on now. */
3817
+ announce(triggers, next, first, panelOf = () => null) {
3403
3818
  const was = first ? null : this.shown;
3404
3819
  this.shown = next;
3405
3820
  if (was === next && !first)
@@ -3513,8 +3928,9 @@ function runCompositeItemAction(el, action) {
3513
3928
  * plan §3a). FRAMEWORK-FREE: the builder, the SSR engine and iox-cms (generation-core's composer, the site
3514
3929
  * build) read the same recipes, roles and structure rules. Card v2 + Badge / Chip (T23 / T25) are the
3515
3930
  * first; the Accordion (CC2) adds the first composite RUNTIME (accordion-runtime.ts — DOM only, no
3516
- * framework), which the Disclosure (CC2.1) runs too — a one-item accordion whose root is its item; Tabs (CC4a) run the
3517
- * EXCLUSIVE runtime (exclusive-runtime.ts — one item always on); composite-runtime.ts is the one door to both.
3931
+ * framework), which the Disclosure (CC2.1) runs too — a one-item accordion whose root is its item; Tabs (CC4a) and the
3932
+ * Segmented control (CC4b) run the EXCLUSIVE runtime (exclusive-runtime.ts — one item always on; exclusive.ts the one
3933
+ * render decision by kind); composite-runtime.ts is the one door to both families.
3518
3934
  * ⚠️ Consumers wire the usual trio — ng-package raw-ts assets, jest moduleNameMapper, tsconfig paths.
3519
3935
  */
3520
3936
 
@@ -3522,5 +3938,5 @@ function runCompositeItemAction(el, action) {
3522
3938
  * Generated bundle index. Do not edit.
3523
3939
  */
3524
3940
 
3525
- export { ACCORDION_BIND_PROP, ACCORDION_CONTENT_LIMIT, ACCORDION_DEFAULT_ONS, ACCORDION_ICONS, ACCORDION_ICON_GLYPH, ACCORDION_NEW_ITEM_WORDS, ACCORDION_WORDS, ACTIVATE_ON_ATTRIBUTE, AccordionClass, AccordionDefaultOn, AccordionEditRefusal, AccordionIcon, AccordionKeyAction, AccordionRole, AccordionRuntime, BADGE_TONES, BADGE_TONE_ICONS, BadgeTone, CARD_LAYOUTS, CARD_LAYOUT_CUSTOM, CARD_PARTS, CARD_PART_ROLE, CARD_STACK_BREAKPOINT, CARD_WORDS, CAROUSEL_QUOTES, CHIP_ICON, CHIP_STYLE, COMPOSITE_ATTRIBUTE, COMPOSITE_KIND_ROLES, COMPOSITE_ROLE_SPECS, CardLayout, CardPart, CardRole, CarouselA11y, CompositeBehaviourTrait, CompositeItemAction, CompositeKind, DEFAULT_ON_ATTRIBUTE, DISCLOSURE_ITEM_KEY, DISCLOSURE_WORDS, DisclosureRole, EXCLUSIVE_KIND_ROLES, ExclusiveRuntime, ITEM_KEY_ATTRIBUTE, ITEM_OFF_EVENT, ITEM_ON_EVENT, ITEM_OPEN_STATE, LIGHTBOX_ARROWS_HIDE_AT, LIGHTBOX_LABEL, MULTIPLE_ATTRIBUTE, NO_ELEMENT_STYLE, ON_ATTRIBUTE, ON_STATE, ORIENTATION_ATTRIBUTE, PILL_LABEL_STYLE, ROW_INDEX_ATTRIBUTE, SCOPE_ATTRIBUTE, SLIDER_NAME_TRAIT, SLIDER_PART_GLYPH, SLIDER_PART_ROLES, SLIDER_PLAY_GLYPH, SLIDER_TYPE, SLIDER_WORDS, SLIDE_TO_ROW, SLIDE_TYPE, SWIPER_THEME_COLOR, SliderFlag, SliderRole, StructureEdit, StructureRefusal, TABS_ACTIVATE_ONS, TABS_CONTENT_LIMIT, TABS_IMAGE_BIND_PROP, TABS_LABEL_BIND_PROP, TABS_NEW_TAB_WORDS, TABS_ORIENTATIONS, TABS_STACK_BREAKPOINT, TABS_TEXT_BIND_PROP, TABS_WORDS, TabsActivateOn, TabsBehaviourTrait, TabsEditRefusal, TabsOrientation, TabsRole, UNTIL_FOUND, acceptsRefusal, accordionAnswerOf, accordionBehaviour, accordionDomIds, accordionFocusIndex, accordionHeadingLevel, accordionItemAttributes, accordionItemLabel, accordionItemOf, accordionItemState, accordionItems, accordionKeyAction, accordionPanelAttributes, accordionPanelOf, accordionPartStyle, accordionQuestionOf, accordionRegionAttributes, accordionRemovalRefusal, accordionRootAttributes, accordionRootOf, accordionRootOfItem, accordionRuntimeOf, accordionScope, accordionToContent, accordionToManual, accordionTrackAttributes, accordionTriggerAttributes, accordionTriggerOf, addAccordionItem, addTabPair, applyCardLayout, attachAccordionAt, attachAccordions, attachCarouselA11y, attachCompositeAt, attachExclusiveAt, badgeStyleId, badgeToneOf, buildAccordionItem, buildAccordionRecipe, buildBadge, buildCardRecipe, buildCarouselRecipe, buildChip, buildCompositeIcon, buildDisclosureRecipe, buildLightboxRecipe, buildSliderPart, buildTabPair, buildTabsRecipe, canOpenAtClickedItem, cardPartsOf, cardRootOf, cardTitleOf, carouselOf, clearLayerStyles, closeAccordionItem, closestAccordion, closestAccordionItem, closestExclusive, closestExclusiveItemPart, compositeItemOf, compositeItems, compositeKindOfRole, compositeRootOf, compositeRowKeys, compositeScopeId, detachAccordion, detectAccordionIcon, detectCardLayout, disclosureOpenByDefault, domSafeKey, exclusiveItemPartOf, exclusiveRootOf, exclusiveRuntimeOf, findByRole, hasLabelledRegion, hasSliderParts, initialAccordionOpen, isAccordionFromContent, isAccordionItemOn, isAccordionPart, isAccordionRoot, isAnyCompositeRoot, isCardLinked, isCardRoot, isCompositeItem, isCompositeItemOn, isCompositePanel, isCompositeRoot, isCompositeTrigger, isDisclosurePart, isDisclosureRoot, isExclusiveItemOn, isExclusiveItemPart, isExclusiveKind, isExclusiveList, isExclusivePanel, isExclusivePanels, isExclusiveRoot, isExclusiveTrigger, isLockedPart, isPillNode, isSlider, isSliderPart, isTabsFromContent, isTabsPart, isTabsRoot, isToggleKind, itemOpenTriggerIds, lightboxSliderOf, makeCompositePart, manualTabKeys, migrateSliderControls, moveAccordionItem, moveTabPair, needsSliderMigration, nextAccordionState, nextItemKey, nextTabKey, onAccordionItemState, onCompositeItemState, onExclusiveItemState, openAccordionItem, parentInComposite, pickAccordionAutoBinds, pickTabsAutoBinds, readLayerStyle, readProp, readStyle, removeFromComposite, removeTabPair, renameAccordionItem, renameTab, repeatSourceOf, rowIndexOf, rowItemKey, rowSourceOf, runCompositeItemAction, sameRepeatSource, serializeDomAttributes, setAccordionBehaviour, setAccordionIcon, setBadgeTone, setCardLinked, setCardPart, setSliderFlag, setTabsBehaviour, shouldScrollToItem, slideIndexForRow, sliderLiveRegion, sliderPart, sliderPartElement, sliderPauseAttributes, sliderPauseGlyph, sliderSlides, sliderWords, splitSliderChildren, structureRefusal, syncSliderParts, tabLabel, tabLabelNodeOf, tabListAttributes, tabPanelAttributes, tabPanelImageOf, tabPanelOf, tabPanelTextOf, tabPartKey, tabTriggerAttributes, tabTriggerOf, tabsBehaviour, tabsItemState, tabsItemTriggerIds, tabsKeyAction, tabsLabel, tabsListOf, tabsPanels, tabsPanelsOf, tabsPartAttributes, tabsPartnerOf, tabsRemovalRefusal, tabsRootAttributes, tabsScope, tabsScopeFor, tabsToContent, tabsToManual, tabsTriggers, walkComposite, wantedSliderParts, writeLayerStyles, writeProp, writeStyles };
3941
+ export { ACCORDION_BIND_PROP, ACCORDION_CONTENT_LIMIT, ACCORDION_DEFAULT_ONS, ACCORDION_ICONS, ACCORDION_ICON_GLYPH, ACCORDION_NEW_ITEM_WORDS, ACCORDION_WORDS, ACTIVATE_ON_ATTRIBUTE, AccordionClass, AccordionDefaultOn, AccordionEditRefusal, AccordionIcon, AccordionKeyAction, AccordionRole, AccordionRuntime, BADGE_TONES, BADGE_TONE_ICONS, BadgeTone, CARD_LAYOUTS, CARD_LAYOUT_CUSTOM, CARD_PARTS, CARD_PART_ROLE, CARD_STACK_BREAKPOINT, CARD_WORDS, CAROUSEL_QUOTES, CHIP_ICON, CHIP_STYLE, COMPOSITE_ATTRIBUTE, COMPOSITE_KIND_ROLES, COMPOSITE_ROLE_SPECS, CardLayout, CardPart, CardRole, CarouselA11y, CompositeBehaviourTrait, CompositeItemAction, CompositeKind, DEFAULT_ON_ATTRIBUTE, DISCLOSURE_ITEM_KEY, DISCLOSURE_WORDS, DisclosureRole, EXCLUSIVE_KIND_ROLES, ExclusiveRuntime, ITEM_KEY_ATTRIBUTE, ITEM_OFF_EVENT, ITEM_ON_EVENT, ITEM_OPEN_STATE, LIGHTBOX_ARROWS_HIDE_AT, LIGHTBOX_LABEL, MULTIPLE_ATTRIBUTE, NO_ELEMENT_STYLE, ON_ATTRIBUTE, ON_STATE, ORIENTATION_ATTRIBUTE, PILL_LABEL_STYLE, ROW_INDEX_ATTRIBUTE, SCOPE_ATTRIBUTE, SEGMENTED_BADGE_TONE, SEGMENTED_BADGE_WORDS, SEGMENTED_BEHAVIOUR, SEGMENTED_MAX_OPTIONS, SEGMENTED_MIN_OPTIONS, SEGMENTED_NAME, SEGMENTED_NEW_OPTION_WORDS, SEGMENTED_WORDS, SLIDER_NAME_TRAIT, SLIDER_PART_GLYPH, SLIDER_PART_ROLES, SLIDER_PLAY_GLYPH, SLIDER_TYPE, SLIDER_WORDS, SLIDE_TO_ROW, SLIDE_TYPE, SWIPER_THEME_COLOR, SegmentedEditRefusal, SegmentedRole, SegmentedTrait, SliderFlag, SliderRole, StructureEdit, StructureRefusal, TABS_ACTIVATE_ONS, TABS_CONTENT_LIMIT, TABS_IMAGE_BIND_PROP, TABS_LABEL_BIND_PROP, TABS_NEW_TAB_WORDS, TABS_ORIENTATIONS, TABS_STACK_BREAKPOINT, TABS_TEXT_BIND_PROP, TABS_WORDS, TabsActivateOn, TabsBehaviourTrait, TabsEditRefusal, TabsOrientation, TabsRole, UNTIL_FOUND, acceptsRefusal, accordionAnswerOf, accordionBehaviour, accordionDomIds, accordionFocusIndex, accordionHeadingLevel, accordionItemAttributes, accordionItemLabel, accordionItemOf, accordionItemState, accordionItems, accordionKeyAction, accordionPanelAttributes, accordionPanelOf, accordionPartStyle, accordionQuestionOf, accordionRegionAttributes, accordionRemovalRefusal, accordionRootAttributes, accordionRootOf, accordionRootOfItem, accordionRuntimeOf, accordionScope, accordionToContent, accordionToManual, accordionTrackAttributes, accordionTriggerAttributes, accordionTriggerOf, addAccordionItem, addSegmentedOption, addTabPair, applyCardLayout, attachAccordionAt, attachAccordions, attachCarouselA11y, attachCompositeAt, attachExclusiveAt, badgeStyleId, badgeToneOf, buildAccordionItem, buildAccordionRecipe, buildBadge, buildCardRecipe, buildCarouselRecipe, buildChip, buildCompositeIcon, buildDisclosureRecipe, buildLightboxRecipe, buildSegmentedOption, buildSegmentedRecipe, buildSliderPart, buildTabPair, buildTabsRecipe, canOpenAtClickedItem, cardPartsOf, cardRootOf, cardTitleOf, carouselOf, clearLayerStyles, closeAccordionItem, closestAccordion, closestAccordionItem, closestExclusive, closestExclusiveItemPart, compositeItemOf, compositeItems, compositeKindOfRole, compositeRootOf, compositeRowKeys, compositeScopeId, detachAccordion, detectAccordionIcon, detectCardLayout, disclosureOpenByDefault, domSafeKey, exclusiveBehaviourOf, exclusiveDefaultOf, exclusiveItemLabel, exclusiveItemPartOf, exclusiveKindHasPanels, exclusiveKindOf, exclusiveLabelOf, exclusivePartAttributes, exclusiveRootAttributesOf, exclusiveRootHoldsTriggers, exclusiveRootOf, exclusiveRuntimeOf, exclusiveScopeFor, findByRole, hasLabelledRegion, hasSliderParts, initialAccordionOpen, isAccordionFromContent, isAccordionItemOn, isAccordionPart, isAccordionRoot, isAnyCompositeRoot, isCardLinked, isCardRoot, isCompositeItem, isCompositeItemOn, isCompositePanel, isCompositeRoot, isCompositeTrigger, isDisclosurePart, isDisclosureRoot, isExclusiveItemOn, isExclusiveItemPart, isExclusiveKind, isExclusiveList, isExclusivePanel, isExclusivePanels, isExclusiveRoot, isExclusiveTrigger, isLockedPart, isPartOfExclusiveScope, isPillNode, isSegmentedPart, isSegmentedRoot, isSlider, isSliderPart, isTabsFromContent, isTabsPart, isTabsRoot, isToggleKind, itemOpenTriggerIds, lightboxSliderOf, makeCompositePart, manualTabKeys, migrateSliderControls, moveAccordionItem, moveSegmentedOption, moveTabPair, needsSliderMigration, nextAccordionState, nextItemKey, nextSegmentedKey, nextTabKey, onAccordionItemState, onCompositeItemState, onExclusiveItemState, openAccordionItem, parentInComposite, pickAccordionAutoBinds, pickTabsAutoBinds, readLayerStyle, readProp, readStyle, removeFromComposite, removeSegmentedOption, removeTabPair, renameAccordionItem, renameSegmentedOption, renameTab, repeatSourceOf, rowIndexOf, rowItemKey, rowSourceOf, runCompositeItemAction, sameRepeatSource, segmentedAddRefusal, segmentedBadgeOf, segmentedDefaultOn, segmentedItemTriggerIds, segmentedKeyAction, segmentedKeys, segmentedLabel, segmentedOptionAttributes, segmentedOptionKey, segmentedOptionLabel, segmentedOptionLabelNodeOf, segmentedOptions, segmentedPartAttributes, segmentedRemovalRefusal, segmentedRootAttributes, segmentedRootAttributesOf, segmentedScopeFor, serializeDomAttributes, setAccordionBehaviour, setAccordionIcon, setBadgeTone, setCardLinked, setCardPart, setSegmentedBadge, setSegmentedBehaviour, setSliderFlag, setTabsBehaviour, shouldScrollToItem, slideIndexForRow, sliderLiveRegion, sliderPart, sliderPartElement, sliderPauseAttributes, sliderPauseGlyph, sliderSlides, sliderWords, splitSliderChildren, structureRefusal, syncSliderParts, tabLabel, tabLabelNodeOf, tabListAttributes, tabPanelAttributes, tabPanelImageOf, tabPanelOf, tabPanelTextOf, tabPartKey, tabTriggerAttributes, tabTriggerOf, tabsBehaviour, tabsItemState, tabsItemTriggerIds, tabsKeyAction, tabsLabel, tabsListOf, tabsPanels, tabsPanelsOf, tabsPartAttributes, tabsPartnerOf, tabsRemovalRefusal, tabsRootAttributes, tabsScope, tabsScopeFor, tabsToContent, tabsToManual, tabsTriggers, walkComposite, wantedSliderParts, writeLayerStyles, writeProp, writeStyles };
3526
3942
  //# sourceMappingURL=vectoriox-iox-ui-composite-core.mjs.map