@vectoriox/iox-ui 5.35.0 → 5.36.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.
- package/composite-core/index.d.ts +348 -2
- package/design-core/index.d.ts +417 -0
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs +899 -2
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +489 -0
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-forms-core.mjs +2 -1
- package/fesm2022/vectoriox-iox-ui-forms-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +113 -8
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +92 -19
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/generation-core/index.d.ts +53 -3
- package/index.d.ts +58 -10
- package/package.json +1 -1
- package/src/composite-core/accordion-runtime.ts +354 -0
- package/src/composite-core/accordion.ts +650 -0
- package/src/composite-core/composite-node.ts +5 -0
- package/src/composite-core/public-api.ts +4 -1
- package/src/composite-core/structure.ts +7 -0
- package/src/design-core/flavor-spec.generated.ts +489 -0
- package/src/forms-core/nesting.ts +2 -1
- package/src/generation-core/compose-site.ts +49 -1
- package/src/generation-core/node-baselines.generated.ts +6 -2
- package/src/generation-core/patterns.ts +10 -0
- package/src/generation-core/serialized-node.ts +4 -0
- package/src/generation-core/site-spec.generated.ts +46 -1
- package/src/generation-core/validate-site-plan.ts +5 -4
- package/styles/iox-design.css +30 -0
|
@@ -58,6 +58,9 @@ export interface PatternNode {
|
|
|
58
58
|
/** The composite-core recipes a pattern may stamp (`recipe`). */
|
|
59
59
|
export enum PatternRecipe {
|
|
60
60
|
Card = 'card',
|
|
61
|
+
/** CC2: the Accordion — Manual (three placeholder items), or From content when the section names a list
|
|
62
|
+
* `binding` (`src: '$binding?'`): one template item bound to the type's question / answer fields. */
|
|
63
|
+
Accordion = 'accordion',
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
/** A recipe node's `binds` keys → the part each binds (Card v2). */
|
|
@@ -100,6 +103,8 @@ export enum PatternPlaceholder {
|
|
|
100
103
|
export enum PatternDirective {
|
|
101
104
|
/** A Repeater's source: the section's `binding`. */
|
|
102
105
|
Binding = '$binding',
|
|
106
|
+
/** The section MAY name a list `binding` (faq.accordion): with one, the recipe's items come from it. */
|
|
107
|
+
OptionalBinding = '$binding?',
|
|
103
108
|
/** `each`: one plain node per page of the plan that is in the navigation (`inNav`), in plan order —
|
|
104
109
|
* words and routes written in, editable on the canvas (W1.1). */
|
|
105
110
|
NavPages = '$navPages',
|
|
@@ -150,6 +155,11 @@ export function patternNeedsBinding(pattern: SitePattern): boolean {
|
|
|
150
155
|
return patternNodes(pattern).some(n => n.src === PatternDirective.Binding);
|
|
151
156
|
}
|
|
152
157
|
|
|
158
|
+
/** True when the pattern may take a section `binding` — it needs one, or names `$binding?` (CC2). */
|
|
159
|
+
export function patternTakesBinding(pattern: SitePattern): boolean {
|
|
160
|
+
return patternNeedsBinding(pattern) || patternNodes(pattern).some(n => n.src === PatternDirective.OptionalBinding);
|
|
161
|
+
}
|
|
162
|
+
|
|
153
163
|
const IMAGE_TYPE = 'Image';
|
|
154
164
|
|
|
155
165
|
/** The scopes whose ITEM a pattern's bound Images take their alt text from (an Image that names no `alt`
|
|
@@ -30,6 +30,10 @@ export interface SerializedNode {
|
|
|
30
30
|
/** The part this node plays in a composite (composite-core: `card.title`; a navigation's `nav.drawer`,
|
|
31
31
|
* written by `planNavShape`). Additive; a node without one is a plain node. */
|
|
32
32
|
role?: string;
|
|
33
|
+
/** An item's identity inside its composite (CC2: an Accordion item's `k1`…). Additive. */
|
|
34
|
+
itemKey?: string;
|
|
35
|
+
/** A targeted state's driving node (CC2: an icon's `trigger-on` → its item). */
|
|
36
|
+
stateTriggers?: Partial<Record<string, string>>;
|
|
33
37
|
bindings: SerializedBinding[];
|
|
34
38
|
interactions: unknown[];
|
|
35
39
|
isGlobal?: boolean;
|
|
@@ -89,7 +89,7 @@ export const SPEC_SITE_PLAN_SHAPE = {
|
|
|
89
89
|
"section": {
|
|
90
90
|
"pattern": "string — a non-global pattern id",
|
|
91
91
|
"slots?": "{ [slot]: string } — the pattern's declared slots",
|
|
92
|
-
"binding?": "string — the list source a pattern's $binding repeater iterates (exactly when it has one)",
|
|
92
|
+
"binding?": "string — the list source a pattern's $binding repeater iterates (exactly when it has one); a $binding? pattern (faq.accordion) MAY take one — then its items come from that content",
|
|
93
93
|
"without?": "string[] — the pattern's optional parts to leave out"
|
|
94
94
|
},
|
|
95
95
|
"globals": {
|
|
@@ -933,6 +933,51 @@ export const SPEC_SITE_PATTERNS = {
|
|
|
933
933
|
}
|
|
934
934
|
]
|
|
935
935
|
}
|
|
936
|
+
},
|
|
937
|
+
"faq.accordion": {
|
|
938
|
+
"family": "faq",
|
|
939
|
+
"label": "FAQ — questions that open",
|
|
940
|
+
"node": {
|
|
941
|
+
"t": "Section",
|
|
942
|
+
"es": "section",
|
|
943
|
+
"c": [
|
|
944
|
+
{
|
|
945
|
+
"t": "Container",
|
|
946
|
+
"es": "box",
|
|
947
|
+
"lay": {
|
|
948
|
+
"display": "flex",
|
|
949
|
+
"flexDirection": "column",
|
|
950
|
+
"gap": "14px",
|
|
951
|
+
"maxWidth": "860px",
|
|
952
|
+
"width": "100%",
|
|
953
|
+
"margin": "0px auto 0px auto"
|
|
954
|
+
},
|
|
955
|
+
"c": [
|
|
956
|
+
{
|
|
957
|
+
"t": "Text",
|
|
958
|
+
"es": "eyebrow",
|
|
959
|
+
"slot": "eyebrow",
|
|
960
|
+
"ph": "copy",
|
|
961
|
+
"text": "FAQ"
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
"t": "Heading",
|
|
965
|
+
"es": "h2",
|
|
966
|
+
"level": "h2",
|
|
967
|
+
"slot": "title",
|
|
968
|
+
"ph": "copy",
|
|
969
|
+
"text": "Questions people ask"
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
"t": "Container",
|
|
973
|
+
"recipe": "accordion",
|
|
974
|
+
"src": "$binding?",
|
|
975
|
+
"ph": "copy"
|
|
976
|
+
}
|
|
977
|
+
]
|
|
978
|
+
}
|
|
979
|
+
]
|
|
980
|
+
}
|
|
936
981
|
}
|
|
937
982
|
} as const;
|
|
938
983
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { flavorPackById, parseHexColor, SPEC_AXES } from '@vectoriox/iox-ui/design-core';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
altSourceScopes, BindScope, patternById, patternNeedsBinding, patternOptionalParts, patternScopes, patternSlots, PatternGlobalPosition,
|
|
4
|
+
altSourceScopes, BindScope, patternById, patternNeedsBinding, patternOptionalParts, patternTakesBinding, patternScopes, patternSlots, PatternGlobalPosition,
|
|
5
5
|
} from './patterns';
|
|
6
6
|
import {
|
|
7
7
|
FACT_KEYS, GlobalSlot, PlanDataSourceMode, PlanDataSourceType, RelativeOp, SitePlanSourceKind, SITE_PLAN_VERSION,
|
|
@@ -367,9 +367,10 @@ function validatePages(c: Collector, list: unknown[], types: Map<string, Content
|
|
|
367
367
|
});
|
|
368
368
|
}
|
|
369
369
|
const binding = c.string(s, 'binding', sp, false);
|
|
370
|
-
if (
|
|
371
|
-
if (!binding)
|
|
372
|
-
|
|
370
|
+
if (patternTakesBinding(pattern)) {
|
|
371
|
+
if (!binding) {
|
|
372
|
+
if (patternNeedsBinding(pattern)) c.add(SitePlanIssueCode.Binding, `${sp}.binding`, `"${patternId}" repeats the section's binding — name a list source`);
|
|
373
|
+
} else {
|
|
373
374
|
const src = sources.get(binding);
|
|
374
375
|
if (!src) c.add(SitePlanIssueCode.UnknownDataSource, `${sp}.binding`, `no data source "${binding}"`);
|
|
375
376
|
else if (src.type !== PlanDataSourceType.Cms || src.mode !== PlanDataSourceMode.Query) c.add(SitePlanIssueCode.Binding, `${sp}.binding`, `"${binding}" is not a list source`);
|
package/styles/iox-design.css
CHANGED
|
@@ -207,3 +207,33 @@ dialog[data-iox-dialog]:not([open]) {
|
|
|
207
207
|
--iox-heading-color: currentColor;
|
|
208
208
|
--iox-text-muted: currentColor;
|
|
209
209
|
}
|
|
210
|
+
|
|
211
|
+
/* ── CC2: the Accordion (complex-components boards 3–4; composite K1) ──────────────────────────────
|
|
212
|
+
The renderers write ONE markup (composite-core accordion.ts): the header is a <button> inside a heading of
|
|
213
|
+
its question's level; the panel sits in a region inside a TRACK. These rules are structural only — the look
|
|
214
|
+
is the parts' element styles (accordion-item / -trigger / -panel), on their own node rules. */
|
|
215
|
+
|
|
216
|
+
/* The heading wrapper carries the outline level and nothing of its own. */
|
|
217
|
+
.iox-accordion-heading { margin: 0; padding: 0; font: inherit; color: inherit; }
|
|
218
|
+
/* The header is a real button: its UA look is reset at zero specificity, so the node's own rule (the
|
|
219
|
+
accordion-trigger style and the recipe's row layout) always wins. */
|
|
220
|
+
:where(.iox-accordion-button) {
|
|
221
|
+
appearance: none; -webkit-appearance: none; background: none; border: 0; border-radius: 0; margin: 0;
|
|
222
|
+
font: inherit; color: inherit; text-align: start; cursor: pointer; box-sizing: border-box;
|
|
223
|
+
/* A <button> sizes to its content even as a block: the header is the whole row (its width, an OUTER
|
|
224
|
+
prop, lands on the canvas twin's host — the button fills it). */
|
|
225
|
+
width: 100%;
|
|
226
|
+
}
|
|
227
|
+
/* The ONE hiding rule (board 4, Q11): a closed item's panel track collapses to a 0 row. The region inside it
|
|
228
|
+
is `hidden="until-found"` while closed — content-visibility, not display:none — so find-in-page still
|
|
229
|
+
reaches the answer; it carries no padding (a hidden box keeps its own padding), the panel node inside it
|
|
230
|
+
does. Opening animates the row over dur-base (0ms under reduced motion: the motion tokens collapse). */
|
|
231
|
+
.iox-accordion-track {
|
|
232
|
+
display: grid; grid-template-rows: 0fr; min-width: 0;
|
|
233
|
+
transition: grid-template-rows var(--iox-dur-base) var(--iox-ease-standard);
|
|
234
|
+
}
|
|
235
|
+
.iox-accordion-track[data-iox-on] { grid-template-rows: 1fr; }
|
|
236
|
+
.iox-accordion-region { min-height: 0; min-width: 0; overflow: hidden; padding: 0; margin: 0; }
|
|
237
|
+
@media (prefers-reduced-motion: reduce) {
|
|
238
|
+
.iox-accordion-track { transition: none; }
|
|
239
|
+
}
|