@vectoriox/iox-ui 5.30.0 → 5.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/composite-core/index.d.ts +270 -0
- package/composite-core/package.json +3 -0
- package/design-core/index.d.ts +870 -41
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs +704 -0
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs.map +1 -0
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +1090 -82
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +110 -30
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +134 -31
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/generation-core/index.d.ts +35 -23
- package/index.d.ts +41 -15
- package/package.json +5 -1
- package/src/composite-core/badge.ts +103 -0
- package/src/composite-core/card.ts +530 -0
- package/src/composite-core/composite-node.ts +143 -0
- package/src/composite-core/public-api.ts +11 -0
- package/src/composite-core/structure.ts +58 -0
- package/src/design-core/contrast-audit.ts +38 -5
- package/src/design-core/flavor-fixtures.generated.ts +144 -144
- package/src/design-core/flavor-spec.generated.ts +970 -26
- package/src/design-core/node-classes.ts +16 -4
- package/src/design-core/node-links.ts +29 -0
- package/src/generation-core/compose-site.ts +55 -1
- package/src/generation-core/node-baselines.generated.ts +14 -2
- package/src/generation-core/patterns.ts +29 -2
- package/src/generation-core/serialized-node.ts +2 -0
- package/src/generation-core/site-spec.generated.ts +13 -26
- package/styles/iox-design.css +63 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { ElementStyleTarget } from '@vectoriox/iox-ui/design-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The node shape composite-core reads and writes — both a builder `ComponentNode` (values in
|
|
5
|
+
* `traits[].default` / `styleTraits`) and a saved layout node (flat `props` / `styleProps`), the same
|
|
6
|
+
* dual shape design-core's element styles already speak. A composite is a tree of ORDINARY nodes
|
|
7
|
+
* (composite-components plan §1): this module only adds the `role` each part carries.
|
|
8
|
+
*/
|
|
9
|
+
interface CompositeTrait {
|
|
10
|
+
name: string;
|
|
11
|
+
default?: unknown;
|
|
12
|
+
}
|
|
13
|
+
interface CompositeLayer {
|
|
14
|
+
styleProps?: Record<string, unknown>;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface CompositeNode extends ElementStyleTarget {
|
|
18
|
+
id?: string;
|
|
19
|
+
/** The part this node plays in its composite (`card.title`). Additive; saved; read by the shared CSS
|
|
20
|
+
* (`iox-role-<role>`), the structure guard and the composite's own editors. */
|
|
21
|
+
role?: string;
|
|
22
|
+
label?: string;
|
|
23
|
+
props?: Record<string, unknown>;
|
|
24
|
+
traits?: CompositeTrait[];
|
|
25
|
+
responsive?: Partial<Record<string, CompositeLayer>>;
|
|
26
|
+
children?: CompositeNode[];
|
|
27
|
+
}
|
|
28
|
+
/** What a recipe asks its consumer to create: a NEW node of `type`, the way that consumer creates one
|
|
29
|
+
* (the builder's `createConfig`, generation-core's `createSerializedNode`), with these props and this
|
|
30
|
+
* element style. `key` is stable per recipe node — a consumer that needs deterministic ids builds them
|
|
31
|
+
* from it (generation-core: `<root id>-<key>`). */
|
|
32
|
+
interface CompositeNodeSpec {
|
|
33
|
+
key: string;
|
|
34
|
+
type: string;
|
|
35
|
+
props?: Readonly<Record<string, unknown>>;
|
|
36
|
+
elementStyle?: string | null;
|
|
37
|
+
}
|
|
38
|
+
type CompositeNodeFactory = (spec: CompositeNodeSpec) => CompositeNode;
|
|
39
|
+
/** A content trait's value — `traits[].default` on a builder node, `props[name]` on a saved one. */
|
|
40
|
+
declare function readProp(node: CompositeNode, name: string): unknown;
|
|
41
|
+
/** Write a content trait. False when a builder node has no such trait (the value would be dropped). */
|
|
42
|
+
declare function writeProp(node: CompositeNode, name: string, value: unknown): boolean;
|
|
43
|
+
/** A base style value (the node's own, either shape). */
|
|
44
|
+
declare function readStyle(node: CompositeNode, name: string): unknown;
|
|
45
|
+
/** Write base style values; returns the names the node has no slot for (a builder node drops them). */
|
|
46
|
+
declare function writeStyles(node: CompositeNode, values: Readonly<Record<string, string>>): string[];
|
|
47
|
+
/** Set style values in one breakpoint layer (`responsive[bp].styleProps`, the shape both renderers'
|
|
48
|
+
* shared `planResponsiveRules` reads). */
|
|
49
|
+
declare function writeLayerStyles(node: CompositeNode, breakpoint: string, values: Readonly<Record<string, string>>): void;
|
|
50
|
+
/** Remove style keys from one breakpoint layer; an emptied layer (and an emptied map) is dropped. */
|
|
51
|
+
declare function clearLayerStyles(node: CompositeNode, breakpoint: string, names: ReadonlyArray<string>): void;
|
|
52
|
+
/** A breakpoint layer's own value for one style key. */
|
|
53
|
+
declare function readLayerStyle(node: CompositeNode, breakpoint: string, name: string): unknown;
|
|
54
|
+
/** Depth-first: `node`, then every descendant. */
|
|
55
|
+
declare function walkComposite(node: CompositeNode, visit: (node: CompositeNode, parent: CompositeNode | null) => void, parent?: CompositeNode | null): void;
|
|
56
|
+
/**
|
|
57
|
+
* The first descendant of `root` playing `role`. Never descends into a NESTED composite of the same
|
|
58
|
+
* root role (a card inside a card's content keeps its own parts).
|
|
59
|
+
*/
|
|
60
|
+
declare function findByRole(root: CompositeNode, role: string): CompositeNode | undefined;
|
|
61
|
+
/** The node's parent inside `root`, or null. */
|
|
62
|
+
declare function parentInComposite(root: CompositeNode, node: CompositeNode): CompositeNode | null;
|
|
63
|
+
/** Detach `node` from its parent inside `root`. True when it was found. */
|
|
64
|
+
declare function removeFromComposite(root: CompositeNode, node: CompositeNode): boolean;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* BADGE + CHIP (composite T25; complex-components board 8). A Badge is a Container wearing
|
|
68
|
+
* `badge-<tone>` › Icon + Text; its TONE is its element style, so Badge ▸ Tone writes the style and
|
|
69
|
+
* nothing else, and a re-theme restyles every badge. A Chip is the outlined static style only (no
|
|
70
|
+
* behaviour until the K5 Data view). Inside a card the badge plays `card.badge`; anywhere else it is
|
|
71
|
+
* recognised by its style.
|
|
72
|
+
*/
|
|
73
|
+
declare enum BadgeTone {
|
|
74
|
+
Neutral = "neutral",
|
|
75
|
+
Success = "success",
|
|
76
|
+
Warning = "warning",
|
|
77
|
+
Accent = "accent"
|
|
78
|
+
}
|
|
79
|
+
declare const BADGE_TONES: ReadonlyArray<BadgeTone>;
|
|
80
|
+
/** The tone's element style (`badge-<tone>`, the contract's). */
|
|
81
|
+
declare function badgeStyleId(tone: BadgeTone): string;
|
|
82
|
+
declare const CHIP_STYLE = "chip";
|
|
83
|
+
/** The glyph a fresh badge of each tone shows (the board's tone grid). */
|
|
84
|
+
declare const BADGE_TONE_ICONS: Readonly<Record<BadgeTone, string>>;
|
|
85
|
+
declare const CHIP_ICON = "ph ph-tag";
|
|
86
|
+
/** The badge tone a node wears, or null when it is no badge. */
|
|
87
|
+
declare function badgeToneOf(node: {
|
|
88
|
+
elementStyle?: string | null;
|
|
89
|
+
} | null | undefined): BadgeTone | null;
|
|
90
|
+
/** True for a node wearing a badge tone or the chip style — the pills (their Icon reads their ink). */
|
|
91
|
+
declare function isPillNode(node: {
|
|
92
|
+
elementStyle?: string | null;
|
|
93
|
+
} | null | undefined): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Badge ▸ Tone: move the badge to another tone's element style (an edit the author made to the old
|
|
96
|
+
* tone's look is kept, design-core's switch rule). Nothing else changes — not the icon, not the words.
|
|
97
|
+
*/
|
|
98
|
+
declare function setBadgeTone(node: CompositeNode, tone: BadgeTone, baseline?: Readonly<Record<string, unknown>>): boolean;
|
|
99
|
+
interface PillOptions {
|
|
100
|
+
text?: string;
|
|
101
|
+
icon?: string;
|
|
102
|
+
/** Key prefix for the consumer's ids (`badge` → `badge`, `badge-icon`, `badge-text`). */
|
|
103
|
+
key?: string;
|
|
104
|
+
}
|
|
105
|
+
/** A fresh Badge: Container `badge-<tone>` › Icon + Text. */
|
|
106
|
+
declare function buildBadge(create: CompositeNodeFactory, options?: PillOptions & {
|
|
107
|
+
tone?: BadgeTone;
|
|
108
|
+
}): CompositeNode;
|
|
109
|
+
/** A fresh Chip: Container `chip` › Icon + Text (outlined, static). */
|
|
110
|
+
declare function buildChip(create: CompositeNodeFactory, options?: PillOptions): CompositeNode;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* CARD v2 (composite T23; complex-components board 8, APPROVED 2026-10-20). Not a component: a recipe of
|
|
114
|
+
* ordinary nodes, each part carrying a role, so every part is selectable on the canvas, in the layer tree
|
|
115
|
+
* and the breadcrumb, wears its own element style and is edited on its own (R2). No runtime and no design
|
|
116
|
+
* state — nothing is hidden at rest.
|
|
117
|
+
*
|
|
118
|
+
* Container `card` role card
|
|
119
|
+
* ├─ Container `box` role card.media (optional: Image)
|
|
120
|
+
* │ ├─ Image `media`
|
|
121
|
+
* │ └─ Container `badge-accent` role card.badge (optional) › Icon + Text
|
|
122
|
+
* └─ Container `box` role card.content (locked)
|
|
123
|
+
* ├─ Text `eyebrow` role card.eyebrow (optional)
|
|
124
|
+
* ├─ Heading h3 `h3` role card.title (locked — the card's link when linked)
|
|
125
|
+
* ├─ Text `body` role card.text (optional)
|
|
126
|
+
* └─ Container `box` role card.actions (optional) › ButtonBlock primary + ghost
|
|
127
|
+
*
|
|
128
|
+
* One recipe for every consumer: the builder's palette (its `createConfig`), generation-core's composer
|
|
129
|
+
* (its `createSerializedNode`) and the site build — each passes its own node factory.
|
|
130
|
+
*/
|
|
131
|
+
declare enum CardRole {
|
|
132
|
+
Card = "card",
|
|
133
|
+
Media = "card.media",
|
|
134
|
+
Badge = "card.badge",
|
|
135
|
+
Content = "card.content",
|
|
136
|
+
Eyebrow = "card.eyebrow",
|
|
137
|
+
Title = "card.title",
|
|
138
|
+
Text = "card.text",
|
|
139
|
+
Actions = "card.actions"
|
|
140
|
+
}
|
|
141
|
+
/** The optional parts — Card ▸ Parts, one switch each, in the board's order. Title and Content are locked. */
|
|
142
|
+
declare enum CardPart {
|
|
143
|
+
Media = "media",
|
|
144
|
+
Badge = "badge",
|
|
145
|
+
Eyebrow = "eyebrow",
|
|
146
|
+
Text = "text",
|
|
147
|
+
Actions = "actions"
|
|
148
|
+
}
|
|
149
|
+
declare const CARD_PARTS: ReadonlyArray<CardPart>;
|
|
150
|
+
declare const CARD_PART_ROLE: Readonly<Record<CardPart, CardRole>>;
|
|
151
|
+
/** Card ▸ Layout — a preset, never a stored trait: `applyCardLayout` writes the card's layout styles. */
|
|
152
|
+
declare enum CardLayout {
|
|
153
|
+
Top = "top",
|
|
154
|
+
Side = "side",
|
|
155
|
+
Overlay = "overlay",
|
|
156
|
+
Compact = "compact"
|
|
157
|
+
}
|
|
158
|
+
declare const CARD_LAYOUTS: ReadonlyArray<CardLayout>;
|
|
159
|
+
/** What Card ▸ Layout shows once the author has changed the layout styles by hand. */
|
|
160
|
+
declare const CARD_LAYOUT_CUSTOM = "custom";
|
|
161
|
+
type CardLayoutState = CardLayout | typeof CARD_LAYOUT_CUSTOM;
|
|
162
|
+
/** The words a fresh card starts with — the author's to replace (or a bound field's). */
|
|
163
|
+
interface CardWords {
|
|
164
|
+
eyebrow: string;
|
|
165
|
+
title: string;
|
|
166
|
+
text: string;
|
|
167
|
+
primary: string;
|
|
168
|
+
secondary: string;
|
|
169
|
+
badge: string;
|
|
170
|
+
}
|
|
171
|
+
declare const CARD_WORDS: Readonly<CardWords>;
|
|
172
|
+
/** The breakpoint whose layer stacks an "Image side" card (Breakpoint.Mobile, ≤767px). */
|
|
173
|
+
declare const CARD_STACK_BREAKPOINT = "mobile";
|
|
174
|
+
/** What a type's UNSTYLED node holds — passed so a style switch (Content ⇄ the scrim) hands the old
|
|
175
|
+
* style's values back to the type, never to `undefined`. */
|
|
176
|
+
type BaselineStyles = (type: string) => Readonly<Record<string, unknown>>;
|
|
177
|
+
interface CardEditOptions {
|
|
178
|
+
baselineStyles?: BaselineStyles;
|
|
179
|
+
}
|
|
180
|
+
interface CardOptions extends CardEditOptions {
|
|
181
|
+
layout?: CardLayout;
|
|
182
|
+
/** Which optional parts the card starts with (all, by default). */
|
|
183
|
+
parts?: Partial<Record<CardPart, boolean>>;
|
|
184
|
+
words?: Partial<CardWords>;
|
|
185
|
+
badgeTone?: BadgeTone;
|
|
186
|
+
}
|
|
187
|
+
/** A fresh Card v2: every part a node with its role and element style, laid out by `options.layout`. */
|
|
188
|
+
declare function buildCardRecipe(create: CompositeNodeFactory, options?: CardOptions): CompositeNode;
|
|
189
|
+
/** True when `node` is a Card v2 root. */
|
|
190
|
+
declare function isCardRoot(node: CompositeNode | null | undefined): boolean;
|
|
191
|
+
/** The Card a part belongs to: the nearest ancestor (or the node itself) playing `card`. `path` = the
|
|
192
|
+
* node's ancestors, root first. */
|
|
193
|
+
declare function cardRootOf(node: CompositeNode, path: ReadonlyArray<CompositeNode>): CompositeNode | null;
|
|
194
|
+
/** Card ▸ Parts: which optional parts the card holds now. */
|
|
195
|
+
declare function cardPartsOf(card: CompositeNode): Record<CardPart, boolean>;
|
|
196
|
+
interface CardLayoutResult {
|
|
197
|
+
layout: CardLayout;
|
|
198
|
+
/** Parts the preset switched off (Compact: Text and Buttons). */
|
|
199
|
+
removed: CardPart[];
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Card ▸ Layout. Rewrites the card's LAYOUT styles for `layout` — the card's direction and box, the
|
|
203
|
+
* Media's placement, the Image's aspect, the content block (Image behind text: the `media-scrim` style +
|
|
204
|
+
* the Inverse scheme), the title size (Compact) and, for Image side, a Mobile layer that stacks it — and
|
|
205
|
+
* moves the badge to where the layout puts it. Nothing else on any part. One undo step for the caller.
|
|
206
|
+
*/
|
|
207
|
+
declare function applyCardLayout(card: CompositeNode, layout: CardLayout, options?: CardEditOptions): CardLayoutResult;
|
|
208
|
+
/** The layout the card's styles hold now, or `custom` once they were changed by hand (Card ▸ Layout). */
|
|
209
|
+
declare function detectCardLayout(card: CompositeNode): CardLayoutState;
|
|
210
|
+
interface CardPartChange {
|
|
211
|
+
part: CardPart;
|
|
212
|
+
/** The node removed (off) or stamped (on); null when there was nothing to do. */
|
|
213
|
+
node: CompositeNode | null;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Card ▸ Parts. Off removes the part (the badge first moves out of a removed Media); on stamps it back
|
|
217
|
+
* from the recipe into its role's slot, wearing its element style and laid out like the rest of the card
|
|
218
|
+
* (the card's current layout; Image top when it is Custom). Returns the node touched, or null when the
|
|
219
|
+
* card already was that way. Title and Content are not parts: they are locked (structure guard).
|
|
220
|
+
*/
|
|
221
|
+
declare function setCardPart(card: CompositeNode, part: CardPart, on: boolean, create?: CompositeNodeFactory, options?: CardOptions): CompositeNode | null;
|
|
222
|
+
/** The card's title — what "Link the whole card" makes the link (its words are the link's name). */
|
|
223
|
+
declare function cardTitleOf(card: CompositeNode): CompositeNode | undefined;
|
|
224
|
+
/** True when the card links as a whole: its title carries a link (the stretched link renders from it). */
|
|
225
|
+
declare function isCardLinked(card: CompositeNode): boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Card ▸ Link ▸ "Link the whole card". On: the title links (to a website page, unless it already pointed
|
|
228
|
+
* at a URL — the target it held is kept); off: the title links nowhere (its target is kept for the next
|
|
229
|
+
* time). The stretched link itself is the shared CSS (iox-design.css), keyed on the title's anchor.
|
|
230
|
+
*/
|
|
231
|
+
declare function setCardLinked(card: CompositeNode, on: boolean): boolean;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* The structure every composite declares (composite-components plan §3a `RoleSpec`): where a role may
|
|
235
|
+
* live and whether it is LOCKED (a structural part that cannot be deleted or moved out — a card always
|
|
236
|
+
* has its content column and its title). Optional parts carry the Parts switch that re-adds them.
|
|
237
|
+
* The builder's delete paths and its drop/paste rule ask `structureRefusal` — ONE answer for all of them.
|
|
238
|
+
*/
|
|
239
|
+
interface CompositeRoleSpec {
|
|
240
|
+
/** The role of the part's parent; null for a composite root. */
|
|
241
|
+
readonly parent: string | null;
|
|
242
|
+
readonly locked?: boolean;
|
|
243
|
+
readonly part?: CardPart;
|
|
244
|
+
}
|
|
245
|
+
declare const COMPOSITE_ROLE_SPECS: Readonly<Record<string, CompositeRoleSpec>>;
|
|
246
|
+
declare enum StructureEdit {
|
|
247
|
+
Delete = "delete",
|
|
248
|
+
/** A drop, paste or wrap that would put the node somewhere new. */
|
|
249
|
+
Move = "move"
|
|
250
|
+
}
|
|
251
|
+
declare enum StructureRefusal {
|
|
252
|
+
/** A locked part cannot be deleted (the card's Content and Title). */
|
|
253
|
+
LockedPart = "locked-part",
|
|
254
|
+
/** A locked part can only live directly inside its own parent role. */
|
|
255
|
+
LockedPlacement = "locked-placement"
|
|
256
|
+
}
|
|
257
|
+
interface RoleLike {
|
|
258
|
+
role?: string | null;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Why the structure guard refuses `edit` on `node`, or null when it is allowed. `ancestors` (Move only) =
|
|
262
|
+
* the new parent chain, root first, the direct parent last.
|
|
263
|
+
*/
|
|
264
|
+
declare function structureRefusal(node: RoleLike | null | undefined, edit: StructureEdit, ancestors?: ReadonlyArray<RoleLike>): StructureRefusal | null;
|
|
265
|
+
/** True when `node` is a locked part (shown with a lock and no delete in the layer tree). Deleting a whole
|
|
266
|
+
* composite is always allowed — only its locked parts are refused. */
|
|
267
|
+
declare function isLockedPart(node: RoleLike | null | undefined): boolean;
|
|
268
|
+
|
|
269
|
+
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, 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 };
|
|
270
|
+
export type { BaselineStyles, CardEditOptions, CardLayoutResult, CardLayoutState, CardOptions, CardPartChange, CardWords, CompositeLayer, CompositeNode, CompositeNodeFactory, CompositeNodeSpec, CompositeRoleSpec, CompositeTrait, PillOptions };
|