@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
@@ -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 (patternNeedsBinding(pattern)) {
371
- if (!binding) c.add(SitePlanIssueCode.Binding, `${sp}.binding`, `"${patternId}" repeats the section's binding — name a list source`);
372
- else {
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`);
@@ -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
+ }