@vectoriox/iox-ui 5.35.0 → 5.37.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.
Files changed (36) hide show
  1. package/actions-core/index.d.ts +12 -3
  2. package/composite-core/index.d.ts +500 -2
  3. package/design-core/index.d.ts +417 -0
  4. package/fesm2022/vectoriox-iox-ui-actions-core.mjs +26 -2
  5. package/fesm2022/vectoriox-iox-ui-actions-core.mjs.map +1 -1
  6. package/fesm2022/vectoriox-iox-ui-composite-core.mjs +1205 -2
  7. package/fesm2022/vectoriox-iox-ui-composite-core.mjs.map +1 -1
  8. package/fesm2022/vectoriox-iox-ui-design-core.mjs +489 -0
  9. package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
  10. package/fesm2022/vectoriox-iox-ui-forms-core.mjs +2 -1
  11. package/fesm2022/vectoriox-iox-ui-forms-core.mjs.map +1 -1
  12. package/fesm2022/vectoriox-iox-ui-generation-core.mjs +113 -8
  13. package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
  14. package/fesm2022/vectoriox-iox-ui.mjs +94 -19
  15. package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
  16. package/generation-core/index.d.ts +53 -3
  17. package/index.d.ts +60 -10
  18. package/package.json +1 -1
  19. package/src/actions-core/action.model.ts +4 -2
  20. package/src/actions-core/element-actions.ts +29 -1
  21. package/src/composite-core/accordion-runtime.ts +443 -0
  22. package/src/composite-core/accordion.ts +694 -0
  23. package/src/composite-core/composite-kinds.ts +110 -0
  24. package/src/composite-core/composite-node.ts +16 -0
  25. package/src/composite-core/disclosure.ts +125 -0
  26. package/src/composite-core/public-api.ts +7 -1
  27. package/src/composite-core/structure.ts +14 -0
  28. package/src/design-core/flavor-spec.generated.ts +489 -0
  29. package/src/forms-core/nesting.ts +2 -1
  30. package/src/generation-core/compose-site.ts +49 -1
  31. package/src/generation-core/node-baselines.generated.ts +6 -2
  32. package/src/generation-core/patterns.ts +10 -0
  33. package/src/generation-core/serialized-node.ts +4 -0
  34. package/src/generation-core/site-spec.generated.ts +46 -1
  35. package/src/generation-core/validate-site-plan.ts +5 -4
  36. package/styles/iox-design.css +30 -0
@@ -1,3 +1,5 @@
1
+ import { CompositeItemAction } from '@vectoriox/iox-ui/composite-core';
2
+
1
3
  /**
2
4
  * The ONE descriptor shape for everything an author can put in an ordered action list —
3
5
  * a form's after-submit steps today, element behaviour actions (A1) next. Promoted out of
@@ -8,7 +10,7 @@
8
10
  /** How a step executes — decides which editor fields appear (timing only for `animated`). */
9
11
  type ActionKind = 'animated' | 'instant' | 'server';
10
12
  /** Picker grouping. Flat lists die at ~10 entries; the group is data, never a second list. */
11
- type ActionGroup = 'motion' | 'visibility' | 'navigate' | 'dialog' | 'form' | 'data' | 'consent' | 'service';
13
+ type ActionGroup = 'motion' | 'visibility' | 'navigate' | 'dialog' | 'item' | 'form' | 'data' | 'consent' | 'service';
12
14
  /**
13
15
  * What a step does inside the live builder canvas (the canvas RUNS interactions):
14
16
  * `run` for real (open the dialog), `simulate` announce-only (navigate), `inert` with a
@@ -26,10 +28,12 @@ interface ActionParamSpec {
26
28
  labelKey: string;
27
29
  }[];
28
30
  }
29
- /** Does this action point at another node — and may it be any node or only certain types? */
31
+ /** Does this action point at another node — and may it be any node, or only certain types / composite roles? */
30
32
  interface ActionTargetSpec {
31
33
  required: boolean;
32
34
  types?: string[];
35
+ /** Only nodes playing one of these composite roles (`openItem` targets an accordion item or a disclosure). */
36
+ roles?: string[];
33
37
  }
34
38
  /**
35
39
  * One row of an action catalog. Every field beyond `type`/`labelKey` is optional so the
@@ -105,6 +109,11 @@ declare const SERVER_ELEMENT_ACTION_TYPES: ReadonlySet<string>;
105
109
  /** The Tier-A behaviour executors' dispatch set (A1c) — the engines branch on it beside
106
110
  * DIALOG/SWIPER. Dialog actions have their own set; context/visibility stay in the legacy path. */
107
111
  declare const BEHAVIOUR_ACTION_TYPES: ReadonlySet<string>;
112
+ /** The item actions' dispatch set (T14) and what each does to its item — the engines branch on it beside
113
+ * DIALOG/BEHAVIOUR, and composite-core `runCompositeItemAction` runs it on the target item's own runtime. */
114
+ declare const ITEM_ACTION_TYPES: Readonly<Record<string, CompositeItemAction>>;
115
+ /** The item action an action type runs, or null when it is not one. */
116
+ declare function itemActionOf(type: string | null | undefined): CompositeItemAction | null;
108
117
  /** The consent actions' dispatch set (C3) — the engines branch on it beside DIALOG/BEHAVIOUR.
109
118
  * `openConsentPreferences` is dialog-opening by nature and included so ONE branch owns consent. */
110
119
  declare const CONSENT_ACTION_TYPES: ReadonlySet<string>;
@@ -166,5 +175,5 @@ declare function dialogOpenerAttributes(node: OpenerNodeLike | null | undefined,
166
175
  /** The selector of every opener of one dialog (by its DOM id) — what a runtime updates on open/close. */
167
176
  declare function dialogOpenersSelector(dialogDomIdValue: string): string;
168
177
 
169
- export { BEHAVIOUR_ACTION_TYPES, CONSENT_ACTION_TYPES, DIALOG_ACTION_TYPE_SET, DIALOG_OPENER_ACTION_TYPES, DIALOG_OPENER_TRIGGER, DIALOG_SELECTOR, ELEMENT_ACTION_DESCRIPTORS, ELEMENT_ACTION_GROUP_ORDER, FORM_SUBMIT_ACTION_DESCRIPTORS, OpenerAttribute, SERVER_ELEMENT_ACTION_TYPES, addableActions, dialogDomId, dialogOpenerAttributes, dialogOpenersSelector, groupedElementActions, nodeIdOfDialogDomId, openedDialogId, resolveActionAvailability };
178
+ export { BEHAVIOUR_ACTION_TYPES, CONSENT_ACTION_TYPES, DIALOG_ACTION_TYPE_SET, DIALOG_OPENER_ACTION_TYPES, DIALOG_OPENER_TRIGGER, DIALOG_SELECTOR, ELEMENT_ACTION_DESCRIPTORS, ELEMENT_ACTION_GROUP_ORDER, FORM_SUBMIT_ACTION_DESCRIPTORS, ITEM_ACTION_TYPES, OpenerAttribute, SERVER_ELEMENT_ACTION_TYPES, addableActions, dialogDomId, dialogOpenerAttributes, dialogOpenersSelector, groupedElementActions, itemActionOf, nodeIdOfDialogDomId, openedDialogId, resolveActionAvailability };
170
179
  export type { ActionAvailability, ActionAvailabilityContext, ActionAvailabilityState, ActionDescriptor, ActionGroup, ActionKind, ActionParamSpec, ActionTargetSpec, BuilderBehaviour, OpenerActionLike, OpenerInteractionLike, OpenerNodeLike };
@@ -19,6 +19,11 @@ interface CompositeNode extends ElementStyleTarget {
19
19
  /** The part this node plays in its composite (`card.title`). Additive; saved; read by the shared CSS
20
20
  * (`iox-role-<role>`), the structure guard and the composite's own editors. */
21
21
  role?: string;
22
+ /** An item's identity inside its composite (Accordion `k1`… — composite plan §3, `itemKey`). Additive; saved.
23
+ * From content, a row's key is the row's own id and the template carries none. */
24
+ itemKey?: string;
25
+ /** For a targeted state (`trigger-on`): the node whose state drives it. */
26
+ stateTriggers?: Partial<Record<string, string>>;
22
27
  label?: string;
23
28
  props?: Record<string, unknown>;
24
29
  traits?: CompositeTrait[];
@@ -36,6 +41,9 @@ interface CompositeNodeSpec {
36
41
  elementStyle?: string | null;
37
42
  }
38
43
  type CompositeNodeFactory = (spec: CompositeNodeSpec) => CompositeNode;
44
+ /** A recipe part: a NEW node (`create`) playing `role` under `label`, with the layout `base` styles its recipe
45
+ * gives it — its LOOK is its element style. Shared by every recipe (Accordion, Disclosure). */
46
+ declare function makeCompositePart(create: CompositeNodeFactory, spec: CompositeNodeSpec, role: string | null, label: string | undefined, base?: Readonly<Record<string, string>>): CompositeNode;
39
47
  /** A content trait's value — `traits[].default` on a builder node, `props[name]` on a saved one. */
40
48
  declare function readProp(node: CompositeNode, name: string): unknown;
41
49
  /** Write a content trait. False when a builder node has no such trait (the value would be dropped). */
@@ -63,6 +71,496 @@ declare function parentInComposite(root: CompositeNode, node: CompositeNode): Co
63
71
  /** Detach `node` from its parent inside `root`. True when it was found. */
64
72
  declare function removeFromComposite(root: CompositeNode, node: CompositeNode): boolean;
65
73
 
74
+ /**
75
+ * The open/close composites' kinds and roles (CC2 Accordion, CC2.1 Disclosure — composite plan T9 / T21). ONE
76
+ * family: a Disclosure is a one-item accordion whose ROOT is its item, so both run the same state machine, the
77
+ * same attribute planners and the same runtime (`accordion-runtime.ts`). Every consumer that treats "an item",
78
+ * "a header" or "a panel" alike asks these predicates, never a role literal.
79
+ */
80
+ declare enum CompositeKind {
81
+ Accordion = "accordion",
82
+ Disclosure = "disclosure"
83
+ }
84
+ declare enum AccordionRole {
85
+ Accordion = "accordion",
86
+ Item = "accordion.item",
87
+ Trigger = "accordion.trigger",
88
+ Icon = "accordion.icon",
89
+ Panel = "accordion.panel"
90
+ }
91
+ /**
92
+ * DISCLOSURE ("Read more") — one trigger, one panel. The root IS its item (it carries the item key and
93
+ * `data-iox-on`); the trigger holds two words, the one shown while closed (`more`) and the one shown while open
94
+ * (`less`), swapped by the Item open state — never by script.
95
+ */
96
+ declare enum DisclosureRole {
97
+ Disclosure = "disclosure",
98
+ Trigger = "disclosure.trigger",
99
+ More = "disclosure.more",
100
+ Less = "disclosure.less",
101
+ Icon = "disclosure.icon",
102
+ Panel = "disclosure.panel"
103
+ }
104
+ interface RoleLike$1 {
105
+ role?: string | null;
106
+ }
107
+ /** The roles each kind plays in the shared runtime. */
108
+ interface CompositeKindRoles {
109
+ root: string;
110
+ item: string;
111
+ trigger: string;
112
+ panel: string;
113
+ icon: string;
114
+ }
115
+ declare const COMPOSITE_KIND_ROLES: Readonly<Record<CompositeKind, CompositeKindRoles>>;
116
+ /** The kind a role belongs to (`disclosure.panel` → Disclosure), or null for any other role. */
117
+ declare function compositeKindOfRole(role: string | null | undefined): CompositeKind | null;
118
+ /** A root that runs the open/close runtime (an Accordion or a Disclosure). */
119
+ declare function isCompositeRoot(node: RoleLike$1 | null | undefined): boolean;
120
+ /** An ITEM — an accordion's item, or a disclosure (its own item). */
121
+ declare function isCompositeItem(node: RoleLike$1 | null | undefined): boolean;
122
+ /** A trigger — rendered as a `<button>` that opens its item, never a link. */
123
+ declare function isCompositeTrigger(node: RoleLike$1 | null | undefined): boolean;
124
+ /** A panel — rendered inside the track + region the one hiding rule collapses. */
125
+ declare function isCompositePanel(node: RoleLike$1 | null | undefined): boolean;
126
+ declare function isDisclosureRoot(node: RoleLike$1 | null | undefined): boolean;
127
+ /** True for any part of a disclosure (its root included). */
128
+ declare function isDisclosurePart(node: RoleLike$1 | null | undefined): boolean;
129
+ /** The composite root a node belongs to: the nearest ancestor (or the node itself) that is one. `path` = the
130
+ * node's ancestors, root first. */
131
+ declare function compositeRootOf<T extends RoleLike$1>(node: T, path: ReadonlyArray<T>): T | null;
132
+ /** The item a node sits in — the nearest item of either kind (itself when it is one) — or null. An accordion
133
+ * root ends the walk (its items are below it). */
134
+ declare function compositeItemOf<T extends RoleLike$1>(node: T, path: ReadonlyArray<T>): T | null;
135
+
136
+ /**
137
+ * ACCORDION (CC2 — composite K1; complex-components boards 3, 4 and 9, APPROVED 2026-10-20). Not a
138
+ * component: a recipe of ordinary nodes, each part carrying a role, so every part is selectable on the
139
+ * canvas, in the layer tree and the breadcrumb, and wears its own element style (R2).
140
+ *
141
+ * Container `box` role accordion traits multiple · defaultOn (Manual)
142
+ * — or a Repeater bound to a list role accordion ONE template item (From content, R3)
143
+ * └─ Container `accordion-item` role accordion.item itemKey k1 … (Manual) · the row's id (From content)
144
+ * ├─ LinkedContainer `accordion-trigger` role accordion.trigger → <hN><button> (the question's level)
145
+ * │ ├─ Heading `h3` the question (rendered as phrasing inside the button)
146
+ * │ └─ Icon `icon` role accordion.icon Item open → rotate
147
+ * └─ Container `accordion-panel` role accordion.panel inside a hidden="until-found" region
148
+ * └─ Text `body` the answer
149
+ *
150
+ * The behaviour is BUILT IN (composite plan D1 = B): which items are open is one state machine
151
+ * (`nextAccordionState`), the ARIA and DOM state one planner (`accordionItemState` and the attribute
152
+ * functions), the keyboard one key map — read by the builder canvas, both engine paths and the composer.
153
+ */
154
+ /** The behaviour options a composite root stores as ordinary TRAITS (composite plan §3). */
155
+ declare enum CompositeBehaviourTrait {
156
+ /** Several items may be open at once ("Allow several open"). */
157
+ Multiple = "multiple",
158
+ /** Which items open by default: first · none · all. */
159
+ DefaultOn = "defaultOn"
160
+ }
161
+ declare enum AccordionDefaultOn {
162
+ First = "first",
163
+ None = "none",
164
+ All = "all"
165
+ }
166
+ declare const ACCORDION_DEFAULT_ONS: ReadonlyArray<AccordionDefaultOn>;
167
+ /** Behaviour ▸ Icon — a preset over the items' icons, never a stored trait (detected from the icons). */
168
+ declare enum AccordionIcon {
169
+ Chevron = "chevron",
170
+ Plus = "plus",
171
+ None = "none"
172
+ }
173
+ declare const ACCORDION_ICONS: ReadonlyArray<AccordionIcon>;
174
+ /** Each icon's glyph and how far it turns when its item opens (board 4: a chevron flips, a plus becomes ×). */
175
+ declare const ACCORDION_ICON_GLYPH: Readonly<Record<Exclude<AccordionIcon, AccordionIcon.None>, {
176
+ iconClass: string;
177
+ turn: string;
178
+ }>>;
179
+ /** The item-open style state (a part INSIDE an item, styled by its item being open — board 9 "Item open"). */
180
+ declare const ITEM_OPEN_STATE = "trigger-on";
181
+ /** A part that IS on (an item, its header, its panel — board 9 "Open"). */
182
+ declare const ON_STATE = "on";
183
+ /** Items from content default to twenty rows (board 9 Q13). */
184
+ declare const ACCORDION_CONTENT_LIMIT = 20;
185
+ interface AccordionWords {
186
+ question: string;
187
+ answer: string;
188
+ }
189
+ /** The words a fresh accordion starts with — generic, the author's to replace (as Card v2's are). */
190
+ declare const ACCORDION_WORDS: ReadonlyArray<AccordionWords>;
191
+ declare const ACCORDION_NEW_ITEM_WORDS: Readonly<AccordionWords>;
192
+ interface AccordionOptions {
193
+ /** The items' words (three generic items by default). */
194
+ items?: ReadonlyArray<AccordionWords>;
195
+ multiple?: boolean;
196
+ defaultOn?: AccordionDefaultOn;
197
+ icon?: AccordionIcon;
198
+ }
199
+ /** The icon of an item (an accordion's, or a disclosure's — `role`); its Item-open state (the turn) is driven by
200
+ * ITS item (`stateTriggers`). ONE builder for both kinds. */
201
+ declare function buildCompositeIcon(create: CompositeNodeFactory, key: string, icon: Exclude<AccordionIcon, AccordionIcon.None>, itemId?: string, role?: string): CompositeNode;
202
+ /** One item: header (question + icon) and panel (answer). `key` makes every part's recipe key unique. */
203
+ declare function buildAccordionItem(create: CompositeNodeFactory, words: AccordionWords, itemKey: string, icon?: AccordionIcon): CompositeNode;
204
+ /** A fresh Accordion: three items, one open at a time, the first open by default (board 4). */
205
+ declare function buildAccordionRecipe(create: CompositeNodeFactory, options?: AccordionOptions): CompositeNode;
206
+ declare function isAccordionRoot(node: {
207
+ role?: string | null;
208
+ } | null | undefined): boolean;
209
+ /** True for any part of an accordion (its root included). */
210
+ declare function isAccordionPart(node: {
211
+ role?: string | null;
212
+ } | null | undefined): boolean;
213
+ /** The accordion a node belongs to: the nearest ancestor (or the node itself) playing `accordion`.
214
+ * `path` = the node's ancestors, root first. */
215
+ declare function accordionRootOf<T extends {
216
+ role?: string | null;
217
+ }>(node: T, path: ReadonlyArray<T>): T | null;
218
+ /** The item a node sits in (the node itself when it is one), or null. */
219
+ declare function accordionItemOf<T extends {
220
+ role?: string | null;
221
+ }>(node: T, path: ReadonlyArray<T>): T | null;
222
+ /** True when the root takes its items from content (a Repeater bound to a list, R3). */
223
+ declare function isAccordionFromContent(root: CompositeNode | null | undefined): boolean;
224
+ /** The root's items in order — every item (Manual), or the one template item (From content). */
225
+ declare function accordionItems(root: CompositeNode): CompositeNode[];
226
+ interface AccordionBehaviour {
227
+ multiple: boolean;
228
+ defaultOn: AccordionDefaultOn;
229
+ }
230
+ /** The root's behaviour (an unset trait reads its default: one at a time, the first open). */
231
+ declare function accordionBehaviour(root: CompositeNode | null | undefined): AccordionBehaviour;
232
+ /** Behaviour ▸ Allow several open / Open by default. False when the node has no such trait. */
233
+ declare function setAccordionBehaviour(root: CompositeNode, patch: Partial<AccordionBehaviour>): boolean;
234
+ /** The header of an item (either kind). */
235
+ declare function accordionTriggerOf(item: CompositeNode): CompositeNode | undefined;
236
+ /** The panel of an item (either kind). */
237
+ declare function accordionPanelOf(item: CompositeNode): CompositeNode | undefined;
238
+ /** A root's items — an accordion's (`accordionItems`), or a disclosure, which is its own one item. */
239
+ declare function compositeItems(root: CompositeNode): CompositeNode[];
240
+ /** The question: the first Heading inside the header — a disclosure's toggle holds no heading, so its first word
241
+ * (the Text shown while closed, "Read more"). */
242
+ declare function accordionQuestionOf(item: CompositeNode): CompositeNode | undefined;
243
+ /** The answer: the first Text inside the panel. */
244
+ declare function accordionAnswerOf(item: CompositeNode): CompositeNode | undefined;
245
+ /** An item's name in the Items list and the layer tree: its question's words. */
246
+ declare function accordionItemLabel(item: CompositeNode): string;
247
+ /** Items ▸ rename: the question's words. */
248
+ declare function renameAccordionItem(item: CompositeNode, question: string): boolean;
249
+ /** The heading level the header's wrapper renders (`<h3><button>`): its question's level. */
250
+ declare function accordionHeadingLevel(trigger: {
251
+ children?: ReadonlyArray<CompositeNode> | null;
252
+ } | null | undefined): string;
253
+ /** A key no item of `root` holds yet (`k4`…). */
254
+ declare function nextItemKey(root: CompositeNode): string;
255
+ /** Items ▸ Add item (and the toolbar's "Add item"): a fresh item after `after` (or at the end), wearing the
256
+ * accordion's current icon. Returns the new item. */
257
+ declare function addAccordionItem(root: CompositeNode, create: CompositeNodeFactory, after?: CompositeNode | null, words?: AccordionWords): CompositeNode;
258
+ /** Items ▸ drag to reorder: move an item to `toIndex` among the items. False when it is not an item of `root`. */
259
+ declare function moveAccordionItem(root: CompositeNode, item: CompositeNode, toIndex: number): boolean;
260
+ declare enum AccordionEditRefusal {
261
+ /** An accordion keeps at least one item (composite plan T11). */
262
+ LastItem = "last-item"
263
+ }
264
+ /** Why removing `item` from `root` is refused, or null. */
265
+ declare function accordionRemovalRefusal(root: CompositeNode | null | undefined, item: CompositeNode | null | undefined): AccordionEditRefusal | null;
266
+ /** The icon the composite's items wear now (the first item's; None when it has no icon). Either kind. */
267
+ declare function detectAccordionIcon(root: CompositeNode): AccordionIcon;
268
+ /**
269
+ * Behaviour ▸ Icon: every item's header shows the chevron, the plus, or no icon. A switch between glyphs
270
+ * keeps the icon NODE (its styles and interactions) and changes its glyph and turn; None removes it, and a
271
+ * glyph after None stamps it back from the recipe. Returns how many items changed.
272
+ */
273
+ declare function setAccordionIcon(root: CompositeNode, icon: AccordionIcon, create?: CompositeNodeFactory): number;
274
+ /** The node id every `trigger-on` state inside an item points at: its ITEM (`stateTriggers['trigger-on']`). */
275
+ declare function itemOpenTriggerIds(root: CompositeNode): void;
276
+ /** The keys open on first render: the first item, none, or all (From content: resolved against the rows). */
277
+ declare function initialAccordionOpen(keys: ReadonlyArray<string>, defaultOn: AccordionDefaultOn): Set<string>;
278
+ /** The open keys after toggling `key`: one at a time closes the others; several leaves them. */
279
+ declare function nextAccordionState(open: ReadonlySet<string>, key: string, behaviour: Pick<AccordionBehaviour, 'multiple'>): Set<string>;
280
+ /** The open keys after OPENING `key` (find-in-page, selecting into a closed panel, the `openItem` action). */
281
+ declare function openAccordionItem(open: ReadonlySet<string>, key: string, behaviour: Pick<AccordionBehaviour, 'multiple'>): Set<string>;
282
+ /** The open keys after CLOSING `key` (the `closeItem` action). */
283
+ declare function closeAccordionItem(open: ReadonlySet<string>, key: string): Set<string>;
284
+ declare enum AccordionKeyAction {
285
+ Next = "next",
286
+ Previous = "previous",
287
+ First = "first",
288
+ Last = "last"
289
+ }
290
+ declare function accordionKeyAction(key: string): AccordionKeyAction | null;
291
+ /** The header index `action` moves focus to, from `current` among `count` headers (↓ ↑ wrap). */
292
+ declare function accordionFocusIndex(action: AccordionKeyAction, current: number, count: number): number;
293
+ /** A key safe in an element id. */
294
+ declare function domSafeKey(raw: unknown): string;
295
+ /** A content row's identity: its own id (never its index — a reorder in the CMS must never pair a header with
296
+ * another row's panel, R3); the index only for a row that has none. */
297
+ declare function rowItemKey(row: unknown, index: number): string;
298
+ interface AccordionDomIds {
299
+ trigger: string;
300
+ panel: string;
301
+ }
302
+ /** The ARIA pairing ids of an item: unique per composite (its SCOPE id — `compositeScopeId`) and per item (its key). */
303
+ declare function accordionDomIds(rootId: string, itemKey: string, kind?: CompositeKind): AccordionDomIds;
304
+ /**
305
+ * The id a rendered composite's ARIA ids are built from: its node id, and — when it sits inside repeated rows —
306
+ * every enclosing row's identity, outermost first (vectoriox/iox-ui#20: an accordion repeated per card used to
307
+ * pair every row's header with the FIRST row's panel). The engine folds each row's `rowItemKey`; the builder
308
+ * canvas its preview row's index. Unrepeated, it is the node id unchanged.
309
+ */
310
+ declare function compositeScopeId(rootId: string, rowKeys?: ReadonlyArray<string>): string;
311
+ /** One item's render state: its identity, whether it is open, and its ARIA ids. */
312
+ interface AccordionItemState {
313
+ kind: CompositeKind;
314
+ key: string;
315
+ index: number;
316
+ on: boolean;
317
+ ids: AccordionDomIds;
318
+ }
319
+ /** The render scope of one composite: its kind, scope id, behaviour and every item key in order. */
320
+ interface AccordionScope {
321
+ kind: CompositeKind;
322
+ rootId: string;
323
+ behaviour: AccordionBehaviour;
324
+ keys: ReadonlyArray<string>;
325
+ open: ReadonlySet<string>;
326
+ }
327
+ declare function accordionScope(rootId: string, behaviour: AccordionBehaviour, keys: ReadonlyArray<string>, kind?: CompositeKind): AccordionScope;
328
+ declare function accordionItemState(scope: AccordionScope, index: number): AccordionItemState;
329
+ /** Attribute values: a string, or '' for a present boolean attribute. Absent attributes are left out. */
330
+ type DomAttributes = Record<string, string>;
331
+ /** `data-iox-on` — the ONE attribute every "on" style keys on (Open, Item open). */
332
+ declare const ON_ATTRIBUTE = "data-iox-on";
333
+ declare const ITEM_KEY_ATTRIBUTE = "data-iox-item-key";
334
+ declare const COMPOSITE_ATTRIBUTE = "data-iox-composite";
335
+ declare const MULTIPLE_ATTRIBUTE = "data-iox-multiple";
336
+ declare const DEFAULT_ON_ATTRIBUTE = "data-iox-default-on";
337
+ /** The scope id the ARIA ids are built from (`compositeScopeId`), written by the engine so the runtime re-stamps
338
+ * exactly the ids the server rendered. */
339
+ declare const SCOPE_ATTRIBUTE = "data-iox-scope";
340
+ /** The value a closed panel's region carries: find-in-page can still reveal it (D9, board 4). */
341
+ declare const UNTIL_FOUND = "until-found";
342
+ /** The structural classes the renderers write around an accordion's parts (no node owns them). */
343
+ declare enum AccordionClass {
344
+ Heading = "iox-accordion-heading",
345
+ Button = "iox-accordion-button",
346
+ Track = "iox-accordion-track",
347
+ Region = "iox-accordion-region"
348
+ }
349
+ declare function accordionRootAttributes(behaviour: AccordionBehaviour, kind?: CompositeKind, scopeId?: string): DomAttributes;
350
+ declare function accordionItemAttributes(state: AccordionItemState): DomAttributes;
351
+ declare function accordionTriggerAttributes(state: AccordionItemState): DomAttributes;
352
+ /** The track wrapping a panel: its row collapses to 0 while closed (the ONE hiding rule, iox-design.css). */
353
+ declare function accordionTrackAttributes(state: AccordionItemState): DomAttributes;
354
+ /** The region the panel sits in: `hidden="until-found"` while closed, so its words stay in the page. An accordion's
355
+ * is a labelled `region` (APG accordion); a disclosure's is a plain block (APG disclosure: the button names it). */
356
+ declare function accordionRegionAttributes(state: AccordionItemState): DomAttributes;
357
+ /** True when a region of this kind is a labelled `role=region`. */
358
+ declare function hasLabelledRegion(kind: CompositeKind): boolean;
359
+ declare function accordionPanelAttributes(state: AccordionItemState): DomAttributes;
360
+ /** `attrs` as an HTML attribute string (` a="b" c`), values escaped by `esc`. */
361
+ declare function serializeDomAttributes(attrs: DomAttributes, esc: (v: string) => string): string;
362
+ /** A field of a content type, as both the CMS schema and a site plan describe it. */
363
+ interface ContentFieldLike {
364
+ name: string;
365
+ type?: string;
366
+ controller?: string;
367
+ }
368
+ interface AccordionAutoBinds {
369
+ /** The first short-text field: the question. */
370
+ question: string | null;
371
+ /** The first long-text field: the answer. */
372
+ answer: string | null;
373
+ }
374
+ /** R3 (board 9 Q19): switching to From content binds the question to the first short-text field and the
375
+ * answer to the first long-text field. ONE rule for the builder's switch and the composer. */
376
+ declare function pickAccordionAutoBinds(fields: ReadonlyArray<ContentFieldLike>): AccordionAutoBinds;
377
+ /** The bound props of the question and the answer (each a content trait). */
378
+ declare const ACCORDION_BIND_PROP = "content";
379
+ /**
380
+ * Manual → From content (board 9 "Items: Manual · From content"): the root becomes `repeater` (a Repeater node
381
+ * the caller created with the same id, role, label, element style and styles — a type change is the
382
+ * consumer's), the FIRST item becomes the one template (its parts, styles and interactions kept; its key
383
+ * dropped — a row's key is its id) and the others are removed. Returns the removed items.
384
+ */
385
+ declare function accordionToContent(root: CompositeNode, repeater: CompositeNode): CompositeNode[];
386
+ /**
387
+ * From content → Manual: the rows come in as static items — each a copy of the template (`cloneItem`, which
388
+ * gives the copy fresh ids) whose bound words are written in as its own and whose bindings are dropped.
389
+ * `container` is the manual root the caller created. Returns the new items.
390
+ */
391
+ declare function accordionToManual(root: CompositeNode, container: CompositeNode, rows: ReadonlyArray<unknown>, cloneItem: (template: CompositeNode) => CompositeNode, resolve: (row: unknown, binding: CompositeBinding) => unknown): CompositeNode[];
392
+ interface CompositeBinding {
393
+ prop: string;
394
+ source: string;
395
+ path?: string;
396
+ pipes?: unknown[];
397
+ }
398
+ /** The style a part holds for `name` (both node shapes) — exported for the consumers' detectors. */
399
+ declare function accordionPartStyle(node: CompositeNode, name: string): unknown;
400
+
401
+ /**
402
+ * The Accordion's RUNTIME (CC2) — ONE copy, DOM only, for the builder canvas and the live site (both engine
403
+ * paths render the same markup). It reads the markup the renderers write (iox-design.css + accordion.ts's
404
+ * attribute planners), so the server's first paint and every later state agree:
405
+ *
406
+ * [root] data-iox-composite="accordion" data-iox-default-on [data-iox-multiple] [data-iox-scope] (the node's
407
+ * own element — its role class may sit on a wrapper host, as the engine's component-path Repeater draws it)
408
+ * .iox-role-accordion-item data-iox-item-key [data-iox-on]
409
+ * hN.iox-accordion-heading > button.iox-accordion-button id aria-expanded aria-controls
410
+ * .iox-accordion-track [data-iox-on] > .iox-accordion-region role=region [hidden=until-found]
411
+ * .iox-role-accordion-panel
412
+ *
413
+ * The DISCLOSURE (CC2.1) runs on this same runtime: `data-iox-composite="disclosure"` on a root that IS its one
414
+ * item (it carries the key and `data-iox-on`), its button straight inside it (no heading), its panel in the same
415
+ * track + region (a plain block — no `role=region`), and no arrow keys (one button).
416
+ *
417
+ * It owns: a click on a header toggles its item; ↓ ↑ Home End move between the headers of THIS accordion
418
+ * (a nested one keeps its own); find-in-page (`beforematch`) opens the item that holds the match; a closed
419
+ * panel gets `hidden="until-found"` after its track has collapsed (at once under reduced motion). Every
420
+ * change dispatches `iox-item-on` / `iox-item-off` on the item, the `itemOn` / `itemOff` interaction
421
+ * triggers. The open set is LIVE ∪ FORCED: the builder forces items open (a selection inside a closed panel,
422
+ * "All open"); the live site forces nothing.
423
+ */
424
+ declare const ITEM_ON_EVENT = "iox-item-on";
425
+ declare const ITEM_OFF_EVENT = "iox-item-off";
426
+ interface AccordionRuntimeOptions {
427
+ /** The composite's scope id — the ARIA ids' prefix (else the root's `data-iox-scope`, else its `iox-node-<id>`). A
428
+ * function is read at every stamp (the builder canvas: a preview row's index is known once it is in the page). */
429
+ rootId?: string | (() => string);
430
+ /** Accordion or Disclosure (else read from the root's `data-iox-composite`). */
431
+ kind?: CompositeKind;
432
+ /** The behaviour (else read from the root's data attributes). */
433
+ behaviour?: AccordionBehaviour;
434
+ /** Keys forced open on top of the live state (the builder's design state). */
435
+ forced?: () => ReadonlySet<string>;
436
+ /** Re-stamp when the markup under the root changes (the builder canvas re-renders parts). */
437
+ observe?: boolean;
438
+ /** True to stop motion (default: the visitor's reduced-motion setting). */
439
+ reducedMotion?: () => boolean;
440
+ }
441
+ /** The composite (accordion or disclosure) an element belongs to (the element itself when it is a root). */
442
+ declare function closestAccordion(el: Element | null | undefined): HTMLElement | null;
443
+ /** The item an element sits in (itself when it is one) — an accordion item, or a disclosure. */
444
+ declare function closestAccordionItem(el: Element | null | undefined): HTMLElement | null;
445
+ /** Subscribe to an item turning on / off — what the `itemOn` / `itemOff` interaction triggers listen to. The
446
+ * item is the element's own item (the element itself when it is one). Returns the unsubscribe. */
447
+ declare function onAccordionItemState(el: Element, on: boolean, handler: () => void): () => void;
448
+ /** True when the element's item is open now. */
449
+ declare function isAccordionItemOn(el: Element): boolean;
450
+ declare class AccordionRuntime {
451
+ readonly root: HTMLElement;
452
+ private readonly options;
453
+ private live;
454
+ private shown;
455
+ private readonly closing;
456
+ private observer;
457
+ private stampQueued;
458
+ private behaviourValue;
459
+ /** The builder attaches a root before its items render: the saved default is applied once they do. */
460
+ private awaitingItems;
461
+ readonly kind: CompositeKind;
462
+ constructor(root: HTMLElement, options?: AccordionRuntimeOptions);
463
+ get behaviour(): AccordionBehaviour;
464
+ /** The behaviour changed in the panel: re-read, and start from the new default. */
465
+ setBehaviour(behaviour: AccordionBehaviour): void;
466
+ /** THIS composite's items, in document order (a nested composite's items are its own); a disclosure's is itself. */
467
+ items(): HTMLElement[];
468
+ /** The open keys the live state holds (before anything forced). */
469
+ get liveKeys(): ReadonlySet<string>;
470
+ /** The keys showing open right now. */
471
+ get openKeys(): ReadonlySet<string>;
472
+ keyOf(item: Element, items?: HTMLElement[]): string;
473
+ toggle(key: string): void;
474
+ open(key: string): void;
475
+ close(key: string): void;
476
+ /** Run an item action (`openItem` / `closeItem` / `toggleItem`, T14) on `key`. True when it shows open after. */
477
+ run(action: CompositeItemAction, key: string): boolean;
478
+ /** Back to the saved default ("Showing on canvas ▸ As saved"). */
479
+ resetLive(): void;
480
+ /** The forced set changed (builder design state): show it. */
481
+ refresh(): void;
482
+ destroy(): void;
483
+ private queueStamp;
484
+ private reduced;
485
+ /** Write every item's state into its markup; announce what changed. */
486
+ private stamp;
487
+ private stampItem;
488
+ private closeDelay;
489
+ /** The element `selector` matches inside `item` that belongs to it, not to an item nested in it. */
490
+ private own;
491
+ private buttons;
492
+ private readonly onClick;
493
+ private readonly onKeydown;
494
+ private readonly onBeforeMatch;
495
+ }
496
+ /** Attach the runtime to one rendered composite root, unless it already runs one. Returns the NEW runtime, or
497
+ * null when the root already had one (so a caller destroys only what it created). */
498
+ declare function attachAccordionAt(root: HTMLElement, options?: Omit<AccordionRuntimeOptions, 'rootId' | 'behaviour'>): AccordionRuntime | null;
499
+ /** Attach the runtime to every accordion under `container` that has none yet. Returns the new runtimes. */
500
+ declare function attachAccordions(container: ParentNode, options?: Omit<AccordionRuntimeOptions, 'rootId' | 'behaviour'>): AccordionRuntime[];
501
+ /** Detach a runtime `attachAccordions` created. */
502
+ declare function detachAccordion(runtime: AccordionRuntime): void;
503
+ /** The repeated rows an element sits in, outermost first — each row's index as its row wrappers stamp it
504
+ * (`data-iox-row-idx`: the builder's Repeater rows, the engine's component path). The builder folds them into a
505
+ * composite's scope id (`compositeScopeId`, vectoriox/iox-ui#20); the element itself is not counted. */
506
+ declare function compositeRowKeys(el: Element | null | undefined): string[];
507
+ /** The runtime running a composite root, or null. */
508
+ declare function accordionRuntimeOf(root: Element | null | undefined): AccordionRuntime | null;
509
+ /** What an item action does to its target item (actions-core `openItem` / `closeItem` / `toggleItem`). */
510
+ declare enum CompositeItemAction {
511
+ Open = "open",
512
+ Close = "close",
513
+ Toggle = "toggle"
514
+ }
515
+ /**
516
+ * Run an item action on the element of an ITEM (an accordion item, or a disclosure) — the `openItem` /
517
+ * `closeItem` / `toggleItem` interaction actions, on the canvas and on the live site through this one function.
518
+ * Returns whether the item shows open afterwards, or null when `el` is in no running composite.
519
+ */
520
+ declare function runCompositeItemAction(el: Element | null | undefined, action: CompositeItemAction): boolean | null;
521
+ /** True when an item an action just opened is out of view and the page should scroll to it (T14: "opens that item
522
+ * and scrolls to it") — never when its head is already on screen, so a button beside it does not jolt the page. */
523
+ declare function shouldScrollToItem(top: number, viewportHeight: number): boolean;
524
+
525
+ /**
526
+ * DISCLOSURE / "Read more" (CC2.1 — composite T21). Not a component: a recipe of ordinary nodes on the
527
+ * ACCORDION's machinery — a disclosure is a one-item accordion whose root is its item, so it runs the same
528
+ * state machine, attribute planners and runtime (`accordion-runtime.ts`), on the canvas and on the live site.
529
+ *
530
+ * Container `box` role disclosure itemKey k1 · trait defaultOn (none | first)
531
+ * ├─ LinkedContainer `accordion-trigger` role disclosure.trigger → <button aria-expanded aria-controls>
532
+ * │ ├─ Text `body` (span) role disclosure.more "Read more" — hidden while open
533
+ * │ ├─ Text `body` (span) role disclosure.less "Read less" — shown only while open
534
+ * │ └─ Icon `icon` role disclosure.icon Item open → turns
535
+ * └─ Container `accordion-panel` role disclosure.panel inside a hidden="until-found" track
536
+ * └─ Text `body` the rest of the text
537
+ *
538
+ * The words swap through the ordinary Item open state (`trigger-on` → the root), so the label an author sees on
539
+ * the canvas is the one the visitor gets, with no script and nothing to break. The look is the accordion's own
540
+ * element styles (no `disclosure-*` contract: the boards draw none) — the header's ink, hover ink and focus ring;
541
+ * the panel's padding and muted ink — and the words are `body` text: the site's body type, with `color: inherit`, so
542
+ * the toggle's ink and its hover ink reach them.
543
+ */
544
+ interface DisclosureWords {
545
+ more: string;
546
+ less: string;
547
+ body: string;
548
+ }
549
+ /** The words a fresh disclosure starts with — generic, the author's to replace. */
550
+ declare const DISCLOSURE_WORDS: Readonly<DisclosureWords>;
551
+ interface DisclosureOptions {
552
+ words?: Partial<DisclosureWords>;
553
+ /** Open on first render (default: closed). */
554
+ open?: boolean;
555
+ icon?: AccordionIcon;
556
+ }
557
+ /** A disclosure's one item key — its root IS its item. */
558
+ declare const DISCLOSURE_ITEM_KEY = "k1";
559
+ /** A fresh Disclosure: "Read more" opens the text below and reads "Read less" while it is open; closed by default. */
560
+ declare function buildDisclosureRecipe(create: CompositeNodeFactory, options?: DisclosureOptions): CompositeNode;
561
+ /** Behaviour ▸ Open by default (a disclosure: on or off). */
562
+ declare function disclosureOpenByDefault(root: CompositeNode): boolean;
563
+
66
564
  /**
67
565
  * BADGE + CHIP (composite T25; complex-components board 8). A Badge is a Container wearing
68
566
  * `badge-<tone>` › Icon + Text; its TONE is its element style, so Badge ▸ Tone writes the style and
@@ -269,5 +767,5 @@ declare function structureRefusal(node: RoleLike | null | undefined, edit: Struc
269
767
  * composite is always allowed — only its locked parts are refused. */
270
768
  declare function isLockedPart(node: RoleLike | null | undefined): boolean;
271
769
 
272
- export { BADGE_TONES, BADGE_TONE_ICONS, BadgeTone, CARD_LAYOUTS, CARD_LAYOUT_CUSTOM, CARD_PARTS, CARD_PART_ROLE, CARD_STACK_BREAKPOINT, CARD_WORDS, CHIP_ICON, CHIP_STYLE, COMPOSITE_ROLE_SPECS, CardLayout, CardPart, CardRole, PILL_LABEL_STYLE, StructureEdit, StructureRefusal, applyCardLayout, badgeStyleId, badgeToneOf, buildBadge, buildCardRecipe, buildChip, cardPartsOf, cardRootOf, cardTitleOf, clearLayerStyles, detectCardLayout, findByRole, isCardLinked, isCardRoot, isLockedPart, isPillNode, parentInComposite, readLayerStyle, readProp, readStyle, removeFromComposite, setBadgeTone, setCardLinked, setCardPart, structureRefusal, walkComposite, writeLayerStyles, writeProp, writeStyles };
273
- export type { BaselineStyles, CardEditOptions, CardLayoutResult, CardLayoutState, CardOptions, CardPartChange, CardWords, CompositeLayer, CompositeNode, CompositeNodeFactory, CompositeNodeSpec, CompositeRoleSpec, CompositeTrait, PillOptions };
770
+ export { ACCORDION_BIND_PROP, ACCORDION_CONTENT_LIMIT, ACCORDION_DEFAULT_ONS, ACCORDION_ICONS, ACCORDION_ICON_GLYPH, ACCORDION_NEW_ITEM_WORDS, ACCORDION_WORDS, 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, CHIP_ICON, CHIP_STYLE, COMPOSITE_ATTRIBUTE, COMPOSITE_KIND_ROLES, COMPOSITE_ROLE_SPECS, CardLayout, CardPart, CardRole, CompositeBehaviourTrait, CompositeItemAction, CompositeKind, DEFAULT_ON_ATTRIBUTE, DISCLOSURE_ITEM_KEY, DISCLOSURE_WORDS, DisclosureRole, ITEM_KEY_ATTRIBUTE, ITEM_OFF_EVENT, ITEM_ON_EVENT, ITEM_OPEN_STATE, MULTIPLE_ATTRIBUTE, ON_ATTRIBUTE, ON_STATE, PILL_LABEL_STYLE, SCOPE_ATTRIBUTE, StructureEdit, StructureRefusal, UNTIL_FOUND, accordionAnswerOf, accordionBehaviour, accordionDomIds, accordionFocusIndex, accordionHeadingLevel, accordionItemAttributes, accordionItemLabel, accordionItemOf, accordionItemState, accordionItems, accordionKeyAction, accordionPanelAttributes, accordionPanelOf, accordionPartStyle, accordionQuestionOf, accordionRegionAttributes, accordionRemovalRefusal, accordionRootAttributes, accordionRootOf, accordionRuntimeOf, accordionScope, accordionToContent, accordionToManual, accordionTrackAttributes, accordionTriggerAttributes, accordionTriggerOf, addAccordionItem, applyCardLayout, attachAccordionAt, attachAccordions, badgeStyleId, badgeToneOf, buildAccordionItem, buildAccordionRecipe, buildBadge, buildCardRecipe, buildChip, buildCompositeIcon, buildDisclosureRecipe, cardPartsOf, cardRootOf, cardTitleOf, clearLayerStyles, closeAccordionItem, closestAccordion, closestAccordionItem, compositeItemOf, compositeItems, compositeKindOfRole, compositeRootOf, compositeRowKeys, compositeScopeId, detachAccordion, detectAccordionIcon, detectCardLayout, disclosureOpenByDefault, domSafeKey, findByRole, hasLabelledRegion, initialAccordionOpen, isAccordionFromContent, isAccordionItemOn, isAccordionPart, isAccordionRoot, isCardLinked, isCardRoot, isCompositeItem, isCompositePanel, isCompositeRoot, isCompositeTrigger, isDisclosurePart, isDisclosureRoot, isLockedPart, isPillNode, itemOpenTriggerIds, makeCompositePart, moveAccordionItem, nextAccordionState, nextItemKey, onAccordionItemState, openAccordionItem, parentInComposite, pickAccordionAutoBinds, readLayerStyle, readProp, readStyle, removeFromComposite, renameAccordionItem, rowItemKey, runCompositeItemAction, serializeDomAttributes, setAccordionBehaviour, setAccordionIcon, setBadgeTone, setCardLinked, setCardPart, shouldScrollToItem, structureRefusal, walkComposite, writeLayerStyles, writeProp, writeStyles };
771
+ export type { AccordionAutoBinds, AccordionBehaviour, AccordionDomIds, AccordionItemState, AccordionOptions, AccordionRuntimeOptions, AccordionScope, AccordionWords, BaselineStyles, CardEditOptions, CardLayoutResult, CardLayoutState, CardOptions, CardPartChange, CardWords, CompositeBinding, CompositeKindRoles, CompositeLayer, CompositeNode, CompositeNodeFactory, CompositeNodeSpec, CompositeRoleSpec, CompositeTrait, ContentFieldLike, DisclosureOptions, DisclosureWords, DomAttributes, PillOptions };