@wix/agent-skills 1.23.0 → 1.24.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 (37) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +64 -50
  3. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +4 -3
  4. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +28 -25
  5. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +8 -2
  6. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +12 -14
  7. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +4 -3
  8. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +66 -9
  9. package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +25 -0
  10. package/skills/wix-app/references/editor-react-component/OVERFLOW.md +146 -0
  11. package/skills/wix-app/references/editor-react-component/PARTS.md +6 -0
  12. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +25 -1
  13. package/skills/{wix-headless-fast → wix-headless-kit}/SKILL.md +79 -60
  14. package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/bootstrap.mjs +2 -2
  15. package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/cold-start.md +26 -35
  16. package/skills/wix-headless-kit/guides/capabilities.md +76 -0
  17. package/skills/wix-headless-kit/guides/feedback.md +98 -0
  18. package/skills/{wix-headless-fast → wix-headless-kit}/guides/migration.md +20 -9
  19. package/skills/{wix-headless-fast → wix-headless-kit}/install/AGENTS.md +3 -0
  20. package/skills/{wix-headless-fast → wix-headless-kit}/install/attach.mjs +5 -2
  21. package/skills/{wix-headless-fast → wix-headless-kit}/install/check.mjs +1 -1
  22. package/skills/wix-headless-kit/install/context.mjs +169 -0
  23. package/skills/{wix-headless-fast → wix-headless-kit}/install/deploy.mjs +17 -4
  24. package/skills/{wix-headless-fast → wix-headless-kit}/install/setup.mjs +89 -55
  25. package/skills/{wix-headless-fast → wix-headless-kit}/install/templates.mjs +1 -1
  26. package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +2 -2
  27. package/skills/wix-manage/references/cms/cms-data-items-crud.md +16 -16
  28. package/skills/wix-manage/references/cms/cms-publishing-flow.md +15 -15
  29. package/skills/wix-manage/references/cms/cms-schema-management.md +6 -6
  30. package/skills/wix-manage/references/sites/query-sites.md +1 -8
  31. package/skills/wix-auth/SKILL.md +0 -12
  32. package/skills/wix-auth/references/device-flow.md +0 -140
  33. package/skills/wix-headless-fast/install/context.mjs +0 -126
  34. /package/skills/{wix-headless-fast → wix-headless-kit}/guides/existing-site.md +0 -0
  35. /package/skills/{wix-headless-fast → wix-headless-kit}/guides/reference-mode.md +0 -0
  36. /package/skills/{wix-headless-fast → wix-headless-kit}/install/agents-md.mjs +0 -0
  37. /package/skills/{wix-headless-fast → wix-headless-kit}/install/lock.mjs +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/agent-skills",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
4
4
  "description": "Wix Skills for AI coding agents — versioned npm distribution of the wix/skills content.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,13 +1,11 @@
1
1
  # Wix Editor React Component Builder
2
2
 
3
3
  Build Editor React Components for Harmony/Studio2 Wix CLI apps only. First
4
- determine **create vs edit**; for edits, inspect the existing component and
5
- never re-scaffold.
4
+ determine **create vs edit**; for edits, inspect the existing component.
6
5
 
7
6
  ## File Contract
8
7
 
9
- Use the Wix CLI scaffold as the source of truth. Do not replace it with a custom
10
- layout or a hand-written manifest. Preserve these file responsibilities:
8
+ Keep the Wix CLI scaffold and file roles:
11
9
 
12
10
  | File | Ownership | Purpose |
13
11
  | --- | --- | --- |
@@ -16,37 +14,55 @@ layout or a hand-written manifest. Preserve these file responsibilities:
16
14
  | `<component-name>.module.css` | Edit | Scoped component styles |
17
15
  | `component.tsx` | Keep generated | Wire component and `defaultProps` with `withDefaults` |
18
16
  | `component.preview.tsx` | Edit narrowly | Sync preview adapter, one crucial data field, root class |
19
- | `<component-name>.generated.ts` | NEVER edit | Generated manifest — do not edit |
17
+ | `<component-name>.generated.ts` | NEVER edit | Generated manifest |
20
18
  | `<component-name>.extension.ts` | Edit narrowly | Supported partial manifest overrides |
21
19
 
22
- Supplementary files (constants, hooks, sub-components) are allowed; keep scaffold
23
- roles intact.
20
+ Supplementary files are allowed; keep scaffold roles intact.
24
21
 
25
22
  ## Workflow
26
23
 
27
- 1. **Scaffold only when creating.** If the component folder does not exist, run
28
- inside the Wix app project (the folder with `wix.config.json`):
24
+ 1. **Scaffold only when creating.** Run in the Wix app (`wix.config.json`).
25
+ Check the current directory, then this workspace; never search the OS:
29
26
 
30
27
  ```bash
31
- npx wix generate --params '{"extensionType":"EDITOR_REACT_COMPONENT","name":"ComponentName","folder":"component-name","description":"A brief description"}'
28
+ npx wix generate --params '{"extensionType":"EDITOR_REACT_COMPONENT","name":"ComponentName","folder":"component-name","description":"A meaningful description of component's intent and functionality"}'
32
29
  ```
33
30
 
34
- Creates `src/extensions/site/components/<component-name>/` and registers the
35
- extension in `src/extensions.ts`. Do not rerun for an existing component.
31
+ Never rerun the scaffold for an existing component.
32
+ Write a meaningful `description` in 1-2 plain sentences (max 300 chars): what
33
+ the user sees, when to use it, and capabilities that affect that choice.
34
+ Don't repeat the component name or add implementation details.
36
35
 
37
- 2. **Run the dependency preflight.** Verify that all component creation and
38
- accessibility-review dependencies are installed:
36
+ 2. **Run the dependency preflight.** Check required packages:
39
37
 
40
38
  ```bash
41
- node -e "const fs=require('fs'),path=require('path'),ps=['@wix/react-component-schema','@wix/react-component-utils','@wix/editor-react-types','@babel/parser','@babel/traverse','@babel/types','eslint','eslint-plugin-jsx-a11y','@typescript-eslint/parser','typescript','@types/eslint-plugin-jsx-a11y','jsdom','axe-core'];const missing=ps.filter(p=>!(require.resolve.paths(p)||[]).some(d=>fs.existsSync(path.join(d,p,'package.json'))));if(missing.length){console.error('Missing dependencies: '+missing.join(', '));process.exit(1)}" || { d="$PWD"; while [ "$d" != "/" ] && [ ! -f "$d/yarn.lock" ]; do d="${d%/*}"; done; if [ -f "$d/yarn.lock" ]; then yarn add @wix/react-component-schema @wix/react-component-utils @wix/editor-react-types && yarn add -D @babel/parser @babel/traverse @babel/types eslint eslint-plugin-jsx-a11y @typescript-eslint/parser 'typescript@<7' @types/eslint-plugin-jsx-a11y jsdom axe-core; else npm install @wix/react-component-schema @wix/react-component-utils @wix/editor-react-types && npm install --save-dev @babel/parser @babel/traverse @babel/types eslint eslint-plugin-jsx-a11y @typescript-eslint/parser 'typescript@<7' @types/eslint-plugin-jsx-a11y jsdom axe-core; fi; }
39
+ deps=(@wix/react-component-schema @wix/react-component-utils @wix/editor-react-types)
40
+ dev=(@babel/parser @babel/traverse @babel/types eslint eslint-plugin-jsx-a11y @typescript-eslint/parser 'typescript@<7' @types/eslint-plugin-jsx-a11y jsdom axe-core)
41
+
42
+ node - "${deps[@]}" "${dev[@]}" <<'JS' || {
43
+ const fs = require('fs'), path = require('path');
44
+ const missing = process.argv.slice(2)
45
+ .map(p => p.replace(/@<7$/, ''))
46
+ .filter(p => !require.resolve.paths(p)?.some(d => fs.existsSync(path.join(d, p, 'package.json'))));
47
+ if (missing.length) {
48
+ console.error(`Missing dependencies: ${missing.join(', ')}`);
49
+ process.exit(1);
50
+ }
51
+ JS
52
+ d="$PWD"
53
+ while [[ "$d" != / && ! -f "$d/yarn.lock" ]]; do d="$(dirname "$d")"; done
54
+ if [[ -f "$d/yarn.lock" ]]; then install=(yarn add); else install=(npm install); fi
55
+ "${install[@]}" "${deps[@]}" && "${install[@]}" -D "${dev[@]}"
56
+ }
42
57
  ```
43
58
 
44
- 3. **Plan the contract and structure.** Identify props, semantic root, named
45
- parts, and design states; read routed references below before writing code.
59
+ 3. **Plan.** Identify props, root, parts, and states; read routed references.
60
+ Use the scaffold and references before package declarations; probe an API
61
+ only when undocumented or a typecheck fails.
46
62
 
47
- 4. **Implement the editable sources.** Preserve the scaffold contract: props in
48
- the props file, logic in TSX, styles in the CSS Module. Do not edit
49
- `*.generated.ts`.
63
+ 4. **Implement.** Keep props, logic, and styles in their scaffolded editable
64
+ files. Format edited source files with the app's configured formatter before
65
+ checking formatting. Never edit or format `*.generated.ts`.
50
66
 
51
67
  5. **Run the accessibility review.** Once the JSX is complete, run from the
52
68
  same folder (`<SKILL_ROOT>` is the directory containing the active `SKILL.md`):
@@ -55,42 +71,36 @@ roles intact.
55
71
  node <SKILL_ROOT>/scripts/scan-a11y-review.cjs src/extensions/site/components/<component-name>
56
72
  ```
57
73
 
58
- Then follow [`editor-react-component/ACCESSIBILITY.md`](editor-react-component/ACCESSIBILITY.md):
59
- fix confirmed findings, rerun after each fix pass (at most two), and report
60
- what remains.
74
+ Follow [`editor-react-component/ACCESSIBILITY.md`](editor-react-component/ACCESSIBILITY.md); fix and
75
+ rerun at most twice, then report remaining findings.
61
76
 
62
- 6. **Configure the editor extension when required.** For a new component or a
63
- requested sizing, installation, or manifest change, apply
77
+ 6. **Configure the editor extension.** For creation or a requested sizing,
78
+ installation, or manifest change, apply
64
79
  [`editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md`](editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md)
65
- to `<component-name>.extension.ts`. Otherwise leave the file unchanged.
66
- Synchronize `requiredDataFields` and `rootClassName` in
67
- `component.preview.tsx`.
80
+ to the extension; otherwise leave it unchanged. Synchronize preview
81
+ `requiredDataFields` and `rootClassName`.
68
82
 
69
- 7. **Generate and validate.** Run:
83
+ 7. **Generate and validate.** Batch implementation edits, then build and
84
+ generate the manifest once:
70
85
 
71
86
  ```bash
72
87
  npx wix build && npx wix generate manifest
73
- npx tsc --noEmit
74
88
  ```
75
89
 
76
- Run relevant tests and lint when available. Inspect the regenerated manifest;
77
- never repair it by hand. On failure, diagnose with
90
+ Run `npx tsc --noEmit`, relevant tests/lint, and the accessibility review.
91
+ If later edits affect a check, rerun that
92
+ check. Inspect the manifest when generated; never hand-repair it. Diagnose
93
+ failures with
78
94
  [`editor-react-component/MANIFEST-ERRORS.md`](editor-react-component/MANIFEST-ERRORS.md).
79
95
 
80
- 8. **Report the result.** Summarize edited files and checks. Call out any
81
- unresolved conflict, missing dependency, unsupported CLI version, or check
82
- that could not run.
96
+ For creation/layout changes, complete the routed overflow resize review.
83
97
 
84
- ## Reference Policy
98
+ 8. **Report.** Summarize files, checks, blockers, and checks that could not run.
85
99
 
86
- - Read **only** matching required + triggered optional rows; optional triggers
87
- become required when they match.
88
- - References refine the active step; they do not restart workflow or expand scope.
89
- - Never re-scaffold an existing component or edit `*.generated.ts`.
100
+ ## Reference Policy
90
101
 
91
- `SKILL.md` is the only reference router; reference files are self-contained
92
- leaves. For existing components, preserve out-of-scope public props, styling,
93
- extension configuration, and supporting files.
102
+ Read only matched references. Preserve unrelated behavior. `SKILL.md` routes;
103
+ references are leaves.
94
104
 
95
105
  ### Required References
96
106
 
@@ -102,6 +112,7 @@ extension configuration, and supporting files.
102
112
  | Changing public data props or elected root global class | [`COMPONENT-PREVIEW.md`](editor-react-component/COMPONENT-PREVIEW.md) |
103
113
  | Item array where only one body is visible | [`COMPONENT-CONTRACT.md`](editor-react-component/COMPONENT-CONTRACT.md), [`PROPS-VS-CSS.md`](editor-react-component/PROPS-VS-CSS.md), [`ACCESSIBILITY.md`](editor-react-component/ACCESSIBILITY.md), [`DESIGN-STATES.md`](editor-react-component/DESIGN-STATES.md) |
104
114
  | Creating or changing CSS | [`CSS-GUIDELINES.md`](editor-react-component/CSS-GUIDELINES.md) |
115
+ | Creating or changing layout/content | [`OVERFLOW.md`](editor-react-component/OVERFLOW.md) |
105
116
  | Root direction contract, direction-sensitive behavior, or `ReactNode` slot | [`DIRECTIONALITY.md`](editor-react-component/DIRECTIONALITY.md) |
106
117
  | Sizing, installation, or manifest overrides | [`EDITOR-EXTENSION-CONFIGURATION.md`](editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md) |
107
118
 
@@ -109,7 +120,7 @@ extension configuration, and supporting files.
109
120
 
110
121
  | Trigger | Read |
111
122
  | --- | --- |
112
- | Interactive/selectable part or custom state | [`DESIGN-STATES.md`](editor-react-component/DESIGN-STATES.md) |
123
+ | Interactive/selectable part, custom state, or open/collapse toggle | [`DESIGN-STATES.md`](editor-react-component/DESIGN-STATES.md) |
113
124
  | Creating interactive components or changing interactions/callbacks | [`FUNCTION-HANDLERS.md`](editor-react-component/FUNCTION-HANDLERS.md) |
114
125
  | Browser APIs, effects, or time-dependent output | [`SSR.md`](editor-react-component/SSR.md) |
115
126
  | Non-established CSS feature or DOM API, or user asks for one by name | [`BROWSER-SUPPORT.md`](editor-react-component/BROWSER-SUPPORT.md) |
@@ -135,14 +146,17 @@ extension configuration, and supporting files.
135
146
  top-level props).
136
147
  - Native design states: pair selectors with injected modifiers; keep non-input
137
148
  `:focus-visible` standalone unless editable focus is requested; toggle custom
138
- state classes from data.
149
+ state classes from data, each with a matching `:global()` rule.
150
+ - Open/collapse components: expose a props-only `isOpen: ElementState<boolean>`
151
+ root state and sync internal state from it.
139
152
  - Single-visible-body arrays: `name` per item, `ActiveItemIndex<'prop'>`, render
140
153
  all bodies, hide inactive accessibly.
141
154
  - Autoplay/loop: play/pause control, honor reduced motion, suppress autoplay in
142
155
  editor design mode.
143
- - `component.preview.tsx`: preserve this outer-to-inner composition, inline or
144
- through component variables:
156
+ - Resizable layout: keep required content usable at 320px. Reflow visible
157
+ groups inside their page and cap track minima with
158
+ `minmax(min(100%, <minimum>), 1fr)`. Follow [`OVERFLOW.md`](editor-react-component/OVERFLOW.md).
159
+ - Preview composition, inline or through variables:
145
160
  `withDefaults(withFallbackPlaceholder(PreviewOrComponent, options), defaultProps)`.
146
- Keep `withDefaults` outermost, wrap the preview adapter when present, use one
147
- crucial `requiredDataFields` entry, and match `rootClassName` to the root
148
- global class.
161
+ Keep `withDefaults` outermost; use one crucial data field and match the root
162
+ class.
@@ -1,7 +1,6 @@
1
1
  # Accessibility Implementation and Review
2
2
 
3
- Use this reference while authoring Editor React Component props and JSX, then
4
- run the review command once the JSX is complete.
3
+ Use while authoring; run the review after JSX is complete.
5
4
 
6
5
  ## Contents
7
6
 
@@ -41,7 +40,9 @@ function Toggle({ elementProps }: ToggleProps) {
41
40
 
42
41
  return (
43
42
  <button {...toggleProps} aria-label={toggleA11y?.ariaLabel ?? ARIA_LABELS.toggle}>
44
- <ChevronIcon aria-hidden="true" />
43
+ <svg aria-hidden="true" viewBox="0 0 16 16">
44
+ <path d="m3 6 5 5 5-5" fill="none" stroke="currentColor" />
45
+ </svg>
45
46
  </button>
46
47
  );
47
48
  }
@@ -5,23 +5,9 @@ Use this reference when the component's primary content **auto-advances or plays
5
5
 
6
6
  Every such component must ship an on-stage **play/pause button**.
7
7
 
8
- ## Contents
9
-
10
- - [Apply When](#apply-when)
11
- - [Required Contract](#required-contract)
12
- - [Announce Manually Selected Parallel Content](#announce-manually-selected-parallel-content)
13
- - [Define Props](#1-define-props)
14
- - [Manage Playback State](#2-manage-playback-state)
15
- - [Add the Play/Pause Button](#3-add-the-playpause-button)
16
- - [Suppress Autoplay in `component.preview.tsx`](#4-suppress-autoplay-in-componentpreviewtsx)
17
- - [Edit the generated `component.preview.tsx`](#edit-the-generated-componentpreviewtsx)
18
- - [Checklist](#checklist)
19
-
20
8
  ## Apply When
21
9
 
22
- Apply automatically — without being asked — whenever the component has an
23
- `autoPlay` prop **or** its primary content is a **startable / loopable**
24
- animation a visitor would reasonably want to start or stop:
10
+ Apply whenever the component has `autoPlay` or startable/loopable primary content:
25
11
 
26
12
  - Slideshow, carousel, slider, or gallery that advances slides/cards
27
13
  - Lottie / JSON vector animations
@@ -94,8 +80,20 @@ export interface MyAnimationProps {
94
80
  }
95
81
  ```
96
82
 
97
- The example shows a looping animation. Omit `loop` when the component does not
98
- support repeat behavior; do not add it only to match the example.
83
+ Omit `loop` when repeat is unsupported.
84
+
85
+ ### Lottie / JSON source
86
+
87
+ For Lottie, `animationUrl?: string` is a JSON URL, not `VectorArt` (SVG).
88
+ This and its renderer are exceptions to the generic media/dependency rules in
89
+ `COMPONENT-CONTRACT.md`. Check `package.json`: use `lottie-web` if present,
90
+ otherwise add it as a runtime dependency. Import `lottie` and
91
+ `type AnimationItem` from it. In an effect, call
92
+ `lottie.loadAnimation({ container, renderer: 'svg', path: animationUrl,
93
+ loop, autoplay: false })`; keep the item in a ref, destroy it on cleanup,
94
+ and use `play()` / `pause()` when `isPlaying` changes. Browser work belongs in
95
+ effects. If no URL is supplied, bundle a valid local Lottie JSON asset and
96
+ import it with `?url` as the component default; a placeholder URL renders blank.
99
97
 
100
98
  ## 2. Manage Playback State
101
99
 
@@ -109,20 +107,22 @@ const reducedMotion = useReducedMotion();
109
107
 
110
108
  const [isPlayOn, setIsPlayOn] = React.useState(() => (autoPlay ?? true) && !reducedMotion);
111
109
 
112
- const skipInitialAutoPlaySync = React.useRef(true);
110
+ const previousAutoPlay = React.useRef(autoPlay);
113
111
  React.useEffect(() => {
114
- if (skipInitialAutoPlaySync.current) {
115
- skipInitialAutoPlaySync.current = false;
116
- return;
112
+ if (previousAutoPlay.current !== autoPlay) {
113
+ setIsPlayOn((autoPlay ?? true) && !reducedMotion);
114
+ } else if (reducedMotion) {
115
+ setIsPlayOn(false);
117
116
  }
118
- setIsPlayOn(autoPlay ?? true);
119
- }, [autoPlay]);
117
+ previousAutoPlay.current = autoPlay;
118
+ }, [autoPlay, reducedMotion]);
120
119
 
121
120
  const handlePause = () => setIsPlayOn(false);
122
121
  const handleResume = () => setIsPlayOn(true);
123
122
  ```
124
123
 
125
- `reducedMotion` is a runtime signal, not a manifest/data prop.
124
+ `reducedMotion` is runtime-only. Pause when the OS turns reduced motion on, but
125
+ do not restart when it turns off. Resume can still override the preference.
126
126
 
127
127
  Derive runtime playback from `isPlayOn` plus only needed conditions. Without
128
128
  another condition, use `const isPlaying = isPlayOn`. A carousel, slideshow,
@@ -140,7 +140,10 @@ clears `isStoppedByFocus`.
140
140
 
141
141
  ## 3. Add the Play/Pause Button
142
142
 
143
- Create play/pause icons that visually match the component's style. Use simple recognizable shapes — a triangle for play, two rectangles for pause — implemented as inline SVG so there is no external icon dependency. Size and color of SVG should be controlled by CSS variables declared on the button level: --icon-size and --icon-color.
143
+ Use inline SVG icons: a triangle for play and two bars for pause. Declare
144
+ `--icon-size` and `--icon-color` on the button. Apply `var(--icon-size)` to the
145
+ SVG's CSS `width` and `height` (or React `style`), not raw SVG attributes;
146
+ set button `color: var(--icon-color)` and SVG `fill: currentColor`.
144
147
 
145
148
  Position the button absolutely so it overlays the content without pushing other elements out of place:
146
149
 
@@ -28,8 +28,14 @@ using CSS Modules `@value`, then consume with `var()`.
28
28
  - Do not use `var(--wst-*)` directly; import the `@value` alias first.
29
29
  - Do not pass a fallback as `var()`'s second argument
30
30
  - Do not use `@import`; CSS Modules resolves theme aliases through `@value`.
31
- - Do not use `wst-base-1-color` for text. Prefer heading/paragraph color tokens,
32
- or `wst-base-2-color` when a base contrast color is required.
31
+ - Do not use `wst-base-1-color` for text on a light surface. Prefer
32
+ heading/paragraph color tokens for body text.
33
+ - Use matching control tokens: pair `wst-button-primary-background-color` with
34
+ `wst-button-primary-color` for a primary CTA (or the secondary pair for a
35
+ secondary CTA). Do not mix `wst-links-and-actions-color` with
36
+ `wst-base-2-color` as button background and text: they are unrelated tokens
37
+ and may fail contrast. Check the rendered contrast of every state, and choose
38
+ a different token pair or design if it fails.
33
39
 
34
40
  ## Checklist
35
41
 
@@ -3,17 +3,6 @@
3
3
  Use this reference when defining props, defaults, named-part wiring, complex data,
4
4
  or internal file boundaries.
5
5
 
6
- ## Contents
7
-
8
- - [Public Props Contract](#public-props-contract)
9
- - [Numeric Range Constraints](#numeric-range-constraints)
10
- - [Named Parts and `elementProps`](#named-parts-and-elementprops)
11
- - [Content and Data](#content-and-data)
12
- - [Active-Item Components](#active-item-components)
13
- - [Defaults and Resources](#defaults-and-resources)
14
- - [Internal File Splitting](#internal-file-splitting)
15
- - [Checklist](#checklist)
16
-
17
6
  ## Public Props Contract
18
7
 
19
8
  Keep identity and platform contracts together with component-specific data and
@@ -54,6 +43,9 @@ Rules:
54
43
  - Default to common optional SDK callbacks by capability; add specialized ones
55
44
  when requested. Keep implementation handlers internal.
56
45
  - Use `Array<T>`, not `T[]`, for exported arrays.
46
+ - A CTA with a real destination is a native link with that `href`. If it only
47
+ performs an action, use a native button. Never use `href="#"` as a fallback;
48
+ it creates a focusable link without a meaningful destination.
57
49
 
58
50
  ## Numeric Range Constraints
59
51
 
@@ -153,6 +145,7 @@ slides, steps). Skip for always-visible lists, multi-select, or multi-expand.
153
145
  `@wix/react-component-utils`. The type argument must match the array prop name
154
146
  exactly, and `defaultProps` must set the index to `0`.
155
147
  - Render all bodies with `.map()`. Active body gets --active; inactive bodies get functional CSS visibility, aria-hidden, and inert.
148
+ - With React 18 types, spread `...(!isActive ? { inert: 'true' } : {})` onto an inactive body; this emits the boolean HTML attribute without a TypeScript prop error. Use the app's typecheck instead of a scratch TypeScript project.
156
149
  - Provide keyboard navigation and the matching ARIA pattern.
157
150
 
158
151
  ```ts
@@ -184,11 +177,16 @@ media type, whether it is a top-level prop or a field in an array item. Name
184
177
  the field for the media itself (`image`, `video`, `audio`, and so on), not for
185
178
  one representation of it.
186
179
 
180
+ Common fields in the installed types: `Image` has required `url: string` and
181
+ optional `uri`, `alt`, `width`, `height`; `Link` has optional `href`, `target`
182
+ (`'_self' | '_blank'`), and `rel`. Use `image.url` for `<img src>`,
183
+ `image.alt` for its alternative text, and `link.href` for `<a href>`.
184
+
187
185
  Do not represent media as a URL/source string or split its metadata across
188
186
  primitive props. Preserve the media object through the public contract so the
189
- component can consume all of its supported data. See
190
- `node_modules/@wix/react-component-schema/dist/editor-react-types.d.ts` for the
191
- full list.
187
+ component can consume all of its supported data. Inspect the installed media
188
+ type declaration only if a needed field is not covered here or a typecheck
189
+ reports an error.
192
190
 
193
191
  ## Defaults and Resources
194
192
 
@@ -56,6 +56,7 @@ that semantic element is the root. Do not wrap it just to host root props.
56
56
 
57
57
  Use flat, top-level selectors. Each selector must target one class plus an
58
58
  optional state pseudo-class or global state modifier.
59
+ Put state overrides before bare classes so the manifest keeps resting defaults.
59
60
 
60
61
  ```css
61
62
  .heading {
@@ -103,7 +104,7 @@ Choose the simplest root shape that fits the component:
103
104
 
104
105
  - column: `--display: flex; flex-direction: column`
105
106
  - row: `--display: flex; flex-direction: row`
106
- - split layout: `--display: grid; grid-template-columns: 1fr 1fr`
107
+ - split layout: `--display: grid; grid-template-columns: repeat(2, minmax(0, 1fr))`
107
108
  - responsive collection: `--display: grid; grid-template-columns: repeat(auto-fit, minmax(...))`
108
109
 
109
110
  Do not hardcode the root's pixel dimensions. Installation defaults belong in
@@ -136,7 +137,7 @@ the extension file.
136
137
  ## Responsiveness and Direction
137
138
 
138
139
  Respond to the component container, not the browser viewport. Prefer intrinsic
139
- flex/grid sizing, `minmax()`, `auto-fit`, `1fr`, and `clamp()`. Do not add
140
+ flex/grid sizing and tracks that can shrink below content size. Do not add
140
141
  viewport `@media` rules; Wix owns page breakpoints.
141
142
 
142
143
  Use logical inline-axis properties so layout flips automatically in RTL:
@@ -171,7 +172,7 @@ Use this pattern:
171
172
 
172
173
  .grid {
173
174
  --columns: 3;
174
- grid-template-columns: repeat(var(--columns), 1fr);
175
+ grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
175
176
  }
176
177
  ```
177
178
 
@@ -13,6 +13,7 @@ in the component's `.tsx` and `.module.css`.
13
13
  - [Author CSS](#3-author-css)
14
14
  - [Wire React](#4-wire-react)
15
15
  - [Use Prop-Triggered States on the Root Only](#5-use-prop-triggered-states-on-the-root-only)
16
+ - [Expose Open/Collapsed Toggles](#6-expose-opencollapsed-toggles)
16
17
  - [Checklist](#checklist)
17
18
 
18
19
  ## 1. Choose Supported States
@@ -24,6 +25,7 @@ in the component's `.tsx` and `.module.css`.
24
25
  | Other interactive element whose editable focus appearance the user explicitly requests | `focus` |
25
26
  | Disableable — `button`/`input`/`select`/`textarea`/`fieldset` or a disableable role | `disabled` (+ `invalid` for `input`/`select`/`textarea`) |
26
27
  | Has a selectable/variant value in its data — `selected`/`active`/`current`/`open`/`expanded`/`checked`/`featured` | that custom state |
28
+ | Whole component opens/collapses (expandable panel, disclosure, dropdown, drawer), even when a click toggles it | root `isOpen` prop state — see §6 |
27
29
  | None of the above | no states — resting style only |
28
30
 
29
31
  An explicit `role` overrides the tag's implicit semantics: `<input role="button">`
@@ -51,7 +53,10 @@ nested (`card__row--selected`).
51
53
  ## 3. Author CSS
52
54
 
53
55
  Put the resting value in the bare class; put only the state override in the
54
- state selector.
56
+ state selector. When both set the same property, write the state selector
57
+ **before** the bare class. Manifest generation can otherwise record the state
58
+ value as the part's resting `defaultValue`, even though runtime CSS renders
59
+ correctly. The state selector still wins at runtime through its specificity.
55
60
 
56
61
  - **Native design state** — pair the pseudo-class with the `:global` modifier.
57
62
  Every exposed native state needs both selectors in the same rule; do not
@@ -63,17 +68,22 @@ state selector.
63
68
  The bare selector is the short **module** class (`.cta`); the `:global(...)`
64
69
  state class is the **prefixed** global one.
65
70
 
71
+ Check text contrast against every background it appears on, including resting,
72
+ hover, and selected states. Normal text needs at least 4.5:1; large text needs
73
+ 3:1. Pale gray small text on white or a tinted selected row commonly fails.
74
+ The local static accessibility scan cannot measure rendered color contrast.
75
+
66
76
  ```css
77
+ .cta:global(.pricing-card-cta--hover),
78
+ .cta:hover {
79
+ background: #4f46e5;
80
+ }
67
81
  .cta {
68
82
  background: #6366f1;
69
83
  font-family: 'Inter', sans-serif;
70
84
  font-size: 14px;
71
85
  color: #ffffff;
72
86
  } /* resting */
73
- .cta:global(.pricing-card-cta--hover),
74
- .cta:hover {
75
- background: #4f46e5;
76
- }
77
87
  .cta:global(.pricing-card-cta--disabled),
78
88
  .cta:disabled {
79
89
  opacity: 0.5;
@@ -91,7 +101,9 @@ state class is the **prefixed** global one.
91
101
  - **Native** — render the correct interactive element (`<button>`, an
92
102
  interactive `role`, or a handler). No custom state class is needed, but the
93
103
  element must still satisfy the accessibility contract for its semantics.
94
- - **Custom** — toggle the global state class from the element's data.
104
+ - **Custom** — toggle the global state class from the element's data. Every
105
+ state class toggled in TSX needs a matching `:global()` rule in §3; without
106
+ one the manifest generator silently drops the state.
95
107
  - **Inner elements** — every named inner element gets an `elementProps` entry;
96
108
  spread it so editor-driven states reach it. On a raw HTML element also merge
97
109
  `elementProps?.<key>.className` inline; on a skill-built sub-component the
@@ -155,8 +167,9 @@ Rules:
155
167
  `props: { isFeatured: true }` as the trigger.
156
168
  - To give the state styling, pair the root's **module** class with a prefixed
157
169
  `:global(.<component-name>--<state>)` rule. With a matching class the manifest
158
- entry carries that `className`; with none it is props-only (the editor still
159
- toggles the prop, but nothing restyles).
170
+ entry carries that `className` and the editor lists it with the design-panel
171
+ states; with none it is props-only and appears in the on-stage state picker,
172
+ which sets the prop. An open/collapsed toggle must stay props-only (§6).
160
173
 
161
174
  ```css
162
175
  .pricingCard:global(.pricing-card--is-featured) {
@@ -166,7 +179,48 @@ Rules:
166
179
 
167
180
  Prefer a native state (interactive markup) or a class trigger (per-item data
168
181
  such as `row.selected`) whenever one fits — those are the common cases and work
169
- at any depth. Reach for a prop trigger only for a root-level boolean switch.
182
+ at any depth. Reach for a prop trigger only for a root-level boolean switch
183
+ or an open/collapsed toggle (§6).
184
+
185
+ ## 6. Expose Open/Collapsed Toggles
186
+
187
+ For a component that opens or collapses, expose its state to the editor even
188
+ when a click toggles it. `useState` alone gives the manifest no state picker.
189
+ For one-of-many item bodies, use the active-item contract instead.
190
+
191
+ - Add `isOpen?: ElementState<boolean>` and set `isOpen: false` in
192
+ `defaultProps`.
193
+ - Seed and resync internal state from the prop; clicks update internal state.
194
+ - Always render the collapsible content; hide it with CSS plus `aria-hidden`
195
+ and `inert` when closed. Never mount it with `open && …`.
196
+ - Style the open state with inner-part classes
197
+ (`<component-name>-content--open`) and matching `:global()` rules, not only
198
+ inline styles or refs measured during render.
199
+ - Keep the root state props-only for the on-stage picker (§5).
200
+
201
+ ```tsx
202
+ const [open, setOpen] = React.useState(Boolean(isOpen));
203
+ React.useEffect(() => setOpen(Boolean(isOpen)), [isOpen]);
204
+
205
+ <div
206
+ {...elementProps?.content}
207
+ aria-hidden={!open}
208
+ {...(!open && { inert: '' })}
209
+ className={classNames(
210
+ 'info-panel-content',
211
+ styles.content,
212
+ open && 'info-panel-content--open',
213
+ elementProps?.content?.className,
214
+ )}
215
+ >
216
+ <p>{text}</p>
217
+ </div>
218
+ ```
219
+
220
+ ```css
221
+ .content { display: none; }
222
+ .content:global(.info-panel-content--open) { display: block; }
223
+ ```
170
224
 
171
225
  ## Checklist
172
226
 
@@ -176,4 +230,7 @@ at any depth. Reach for a prop trigger only for a root-level boolean switch.
176
230
  - [ ] Non-input controls retain a standalone `:focus-visible` keyboard indicator.
177
231
  - [ ] Custom state classes are flat, global, and prefixed by component and part.
178
232
  - [ ] Named inner parts spread and merge their `elementProps` entry.
233
+ - [ ] Every state class toggled in TSX has a matching `:global()` CSS rule.
179
234
  - [ ] `ElementState<boolean>` is used only for a component-level root state.
235
+ - [ ] An open/collapsed component exposes a props-only `isOpen` root state,
236
+ syncs internal state from it, and always renders its content.
@@ -9,12 +9,17 @@ generation rewrites
9
9
  For a new component, complete the scaffolded installation and layout fields.
10
10
  For an existing component, change only the sizing, installation, or manifest
11
11
  behavior requested by the user; preserve every other extension field.
12
+ Use the current scaffold's field shape and the values below. Inspect installed
13
+ `@wix/astro` or schema types only if a related typecheck or build error requires it.
14
+ Normal component setup needs no `ELEMENT_TYPE` or `DATA_TYPE` lookup: the
15
+ generated `editorElement` and props manifest supply those details.
12
16
 
13
17
  ## Contents
14
18
 
15
19
  - [Preserve the Extension Shape](#preserve-the-extension-shape)
16
20
  - [Choose Initial Height](#choose-initial-height)
17
21
  - [Choose Resize Direction](#choose-resize-direction)
22
+ - [Values](#values)
18
23
  - [Checklist](#checklist)
19
24
 
20
25
  ## Preserve the Extension Shape
@@ -53,6 +58,12 @@ should fit content, use `content`.
53
58
 
54
59
  Allow an axis only when dragging it produces a meaningful result.
55
60
 
61
+ For each allowed axis, implement what happens when content no longer fits.
62
+ Content height must grow after wrapping or changing items. A bounded height
63
+ needs a fitting layout or a deliberate accessible scroll region. Installation
64
+ defaults alone do not prevent overflow after resizing. Do not rely on native
65
+ container overflow controls for a custom component's internal DOM.
66
+
56
67
  | Value | Use when |
57
68
  | --- | --- |
58
69
  | `horizontalAndVertical` | Content meaningfully fills both axes; default for framed visuals and most layouts |
@@ -61,11 +72,25 @@ Allow an axis only when dragging it produces a meaningful result.
61
72
  | `aspectRatio` | Distortion would break the component's identity |
62
73
  | `none` | A parent fully owns size; do not use for a top-level component |
63
74
 
75
+ ## Values
76
+
77
+ Every value the scaffold uses comes from `LAYOUT` in
78
+ `@wix/react-component-schema`; do not search `node_modules` for them.
79
+
80
+ | Field | Values |
81
+ | --- | --- |
82
+ | `layout.resizeDirection` (`LAYOUT.RESIZE_DIRECTION`) | `horizontal`, `vertical`, `horizontalAndVertical`, `aspectRatio`, `none` |
83
+ | `layout.contentResizeDirection` (`LAYOUT.CONTENT_RESIZE_DIRECTION`) | `horizontal`, `vertical`, `horizontalAndVertical`, `none`: the axes along which content growth resizes the component |
84
+ | `initialSize.{width,height}.sizingType` (`LAYOUT.SIZING_TYPE`) | `content`, `pixels`, `stretched` |
85
+ | `installation.staticContainer` | `'HOMEPAGE'`, `'GLOBAL_PAGE'` |
86
+
64
87
  Edit the scaffolded `layout`, `installation`, and `resources` fields in place;
65
88
  do not reconstruct the extension from an example. For a new component, add
66
89
  `staticContainer: 'HOMEPAGE'`. For an existing component, preserve its current
67
90
  `staticContainer` value unless the request explicitly changes installation
68
91
  behavior.
92
+ The scaffold's `installation` object accepts `staticContainer` next to
93
+ `initialSize`; add the literal above without searching `@wix/astro` types.
69
94
 
70
95
  ## Checklist
71
96