@wix/agent-skills 1.16.2 → 1.17.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 (58) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +134 -120
  3. package/skills/wix-app/references/EMBEDDED_SCRIPT.md +6 -0
  4. package/skills/wix-app/references/SITE_PLUGIN.md +2 -2
  5. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
  6. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
  7. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +92 -47
  8. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +15 -6
  9. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
  10. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +29 -42
  11. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +153 -449
  12. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +66 -19
  13. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
  14. package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
  15. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
  16. package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +27 -0
  17. package/skills/wix-app/references/editor-react-component/PARTS.md +45 -24
  18. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
  19. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
  20. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
  21. package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
  22. package/skills/wix-base44-connector/SKILL.md +34 -17
  23. package/skills/wix-base44-connector/scripts/utils.js +33 -25
  24. package/skills/wix-headless/entry/bootstrap.mjs +9 -2
  25. package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
  26. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +42 -23
  27. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
  28. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
  29. package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
  30. package/skills/wix-manage/SKILL.md +14 -2
  31. package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
  32. package/skills/wix-manage/references/bookings/create-class-service.md +1 -1
  33. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
  34. package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
  35. package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +182 -5
  36. package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
  37. package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
  38. package/skills/wix-manage/references/sites/query-sites.md +72 -161
  39. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
  40. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +13 -9
  41. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +10 -7
  42. package/skills/wix-vibe-headless/platforms/base44.md +13 -10
  43. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +2 -0
  44. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
  45. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
  46. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
  47. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
  48. package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
  49. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +15 -8
  50. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
  51. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
  52. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
  53. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
  54. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
  55. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -484
  56. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
  57. package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
  58. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
@@ -1,139 +1,222 @@
1
- # Accessibility (ARIA)
1
+ # Accessibility Implementation and Review
2
2
 
3
- Rules and patterns for ARIA accessibility support in Editor React components.
3
+ Use this reference while authoring Editor React Component props and JSX and
4
+ after every JSX edit.
4
5
 
5
- ---
6
+ ## Contents
6
7
 
7
- ## Rules
8
+ - [Implementation Contract](#implementation-contract)
9
+ - [Review Scope](#review-scope)
10
+ - [Automated Scanners](#automated-scanners)
11
+ - [Finding Triage](#finding-triage)
12
+ - [Manual Review](#manual-review)
13
+ - [Pre-Fix Checks for Non-Interactive Controls](#pre-fix-checks-for-non-interactive-controls)
14
+ - [Completion Criteria](#completion-criteria)
8
15
 
9
- ### All ARIA Attributes Through the `a11y` Prop
16
+ ## Implementation Contract
10
17
 
11
- - **NEVER** add individual ARIA properties like `ariaLabel?: string`, `ariaDescribedBy?: string`, `role?: string`, etc. to a component's props interface.
12
- - **ALL** accessibility attributes MUST come through the `a11y?: A11y` prop.
13
- - The `A11y` type includes: `ariaLabel`, `ariaDescribedBy`, `ariaLabelledBy`, `role`, `ariaHidden`, `ariaLive`, and all other ARIA attributes.
14
- - Users provide ARIA values through the `a11y` prop: `<Component a11y={{ ariaLabel: "..." }} />`
18
+ ### Route ARIA Through `a11y`
15
19
 
16
- ### ARIA Label Rules
20
+ Do not add individual public props such as `ariaLabel`, `ariaDescribedBy`, or
21
+ `role`. Use the platform `A11y` type and convert it at the semantic target.
17
22
 
18
- ARIA labels are user-facing content and must NEVER be hardcoded as string literals in JSX.
23
+ ```tsx
24
+ import type { A11y, Direction } from '@wix/editor-react-types';
25
+ import { convertA11yKeysToHtmlFormat } from '@wix/react-component-utils';
19
26
 
20
- **Three patterns (in order of preference):**
27
+ export type TabsProps = {
28
+ id?: string;
29
+ className?: string;
30
+ direction?: Direction;
31
+ a11y?: A11y;
32
+ };
21
33
 
22
- 1. **No aria-label (preferred)** — Visible text content is sufficient:
34
+ <nav {...(a11y && convertA11yKeysToHtmlFormat(a11y))}>{tabs}</nav>;
35
+ ```
23
36
 
24
- ```tsx
25
- <Button>Play</Button> // Visible text ✅
26
- ```
37
+ Apply root accessibility to the elected root. If requirements assign
38
+ accessibility to a named inner part, route it through that part's
39
+ `elementProps.<name>.a11y` contract and convert it on the actual semantic
40
+ element.
27
41
 
28
- 2. **User-configurable** — Via a11y prop (for root or element-specific labels, per requirements):
42
+ ### Provide Accessible Names
29
43
 
30
- ```tsx
31
- // User provides: <ComponentName a11y={{ ariaLabel: "Background music" }} />
32
- // Component applies to root (using the a11y-to-HTML conversion utility):
33
- {...(a11y && convertA11yKeysToHtmlFormat(a11y))}
44
+ Use this priority order:
34
45
 
35
- // Or for inner elements (if requirements specify):
36
- // elementProps.button.a11y gets passed to the button element
37
- ```
46
+ 1. Prefer visible text that already names the control.
47
+ 2. Use user-configurable `a11y` when the name depends on site-owner content.
48
+ 3. Use the project's translation mechanism or a `constants.ts` value only for a
49
+ stable system-owned label required by the component contract.
38
50
 
39
- 3. **System-required** — Via constants.ts (when requirements specify non-configurable label):
51
+ Never hardcode an `aria-label` string directly in JSX.
40
52
 
41
- ```tsx
42
- // constants.ts
43
- export const ARIA_LABELS = {
44
- playButton: 'Play audio',
45
- muteButton: 'Mute audio',
46
- } as const;
53
+ ```tsx
54
+ // constants.ts
55
+ export const ARIA_LABELS = {
56
+ playButton: 'Play animation',
57
+ pauseButton: 'Pause animation',
58
+ } as const;
47
59
 
48
- // component.tsx
49
- import { ARIA_LABELS } from './constants';
50
- <Button aria-label={ARIA_LABELS.playButton}>▶</Button>;
51
- ```
60
+ // component JSX
61
+ <button
62
+ aria-label={isPlaying ? ARIA_LABELS.pauseButton : ARIA_LABELS.playButton}
63
+ >
64
+ {isPlaying ? <PauseIcon /> : <PlayIcon />}
65
+ </button>;
66
+ ```
52
67
 
53
- **❌ NEVER hardcode string literals:**
68
+ Icon-only controls require an accessible name. Controls with visible text,
69
+ including an icon plus visible text, usually do not need another ARIA label.
54
70
 
55
- ```tsx
56
- // ❌ WRONG - hardcoded strings
57
- <Button aria-label="Play">▶</Button>
58
- <Button aria-label={isPlaying ? "Pause" : "Play"}>▶</Button>
59
- <Slider aria-label="Volume" />
71
+ ### Preserve Semantic Ownership
72
+
73
+ - Put roles, labels, descriptions, keyboard handling, and focusability on the
74
+ element that owns the behavior, not on a layout wrapper.
75
+ - Prefer native elements over recreating their semantics with `role`.
76
+ - Hide decorative-only output with `aria-hidden="true"` when appropriate.
77
+ - Preserve heading, list, navigation, and landmark semantics through wrappers.
78
+ - Keep hidden or collapsed state consistent across visuals, focusability, and
79
+ the accessibility tree.
80
+
81
+ ## Review Scope
82
+
83
+ Run this review after creating or editing JSX.
84
+
85
+ | Request | Scan and inspect |
86
+ | --- | --- |
87
+ | Specific file | That file and rendered wrappers or shared components it imports |
88
+ | A component name or "this component" | All hand-edited files in its component folder plus relevant shared imports |
89
+ | Full audit | Every component under `src/extensions/site/components/` plus relevant shared imports |
90
+
91
+ Exclude `*.generated.ts`; it is regenerated from JSX and CSS.
92
+ Imported shared components are inspection context, not automatic edit scope.
93
+ Report a confirmed shared-component issue instead of changing a broadly reused
94
+ primitive unless the requested fix requires that shared change and its impact is
95
+ understood.
96
+
97
+ ## Automated Scanners
98
+
99
+ `<SKILL_ROOT>` is the absolute directory containing the active `SKILL.md`. Run
100
+ both commands from the consumer Wix package so dependencies resolve from that
101
+ project. Pass `.tsx` or `.jsx` paths relative to the current directory.
102
+
103
+ ```bash
104
+ node <SKILL_ROOT>/scripts/scan-a11y-eslint.cjs <file1> [file2] ...
105
+ node <SKILL_ROOT>/scripts/scan-a11y-code.cjs <file1> [file2] ...
60
106
  ```
61
107
 
62
- **Why this matters:**
108
+ Do not treat scanner startup failure as a clean result. The ESLint scanner
109
+ reports JSX accessibility rules. The semantic scanner follows imports up to
110
+ four levels and emits resolution evidence and confidence. Neither scanner
111
+ covers every Editor React Component contract, so complete the manual review
112
+ even when both return zero findings.
63
113
 
64
- - Hardcoded strings cannot be translated or customized
65
- - User-provided labels take precedence when available
66
- - Constants allow centralized management and potential future translation
114
+ ## Finding Triage
67
115
 
68
- ### Detecting Icon-Only Interactive Elements
116
+ For every finding:
69
117
 
70
- **Icon-only elements require aria-labels.** Detect with this checklist:
118
+ 1. Trace the rendered semantic element through local and shared components.
119
+ 2. Deduplicate findings for the same issue and location; keep the finding with
120
+ stronger evidence.
121
+ 3. Assign `confirmed`, `false-positive`, or `not-relevant`.
122
+ 4. Fix only confirmed findings.
71
123
 
72
- | Element Content | Needs aria-label? | Example |
73
- | --------------------- | ----------------- | ----------------------------------------- |
74
- | Visible text only | ❌ No | `<Button>Play</Button>` |
75
- | Icon component + text | ❌ No | `<Button><PlayIcon />Play</Button>` |
76
- | Icon/emoji only | ✅ YES | `<Button>▶</Button>` |
77
- | Image only | ✅ YES | `<Button><img src="play.png" /></Button>` |
78
- | SVG only | ✅ YES | `<Button><svg>...</svg></Button>` |
124
+ Scanner output is a lead, not permission to edit blindly.
79
125
 
80
- **Critical:** If button/link contains ONLY visual elements (icons, emojis, images, SVG) with NO text node, it MUST have aria-label from constants.
126
+ ### Confidence and Action
81
127
 
82
- **Pattern for dynamic labels:**
128
+ | Confidence | Evidence | Action |
129
+ | --- | --- | --- |
130
+ | High | The rendered element and static props directly establish the issue. | Confirm and fix when the change is safe and local. |
131
+ | Medium | Props or partial component resolution strongly imply the semantics. | Inspect surrounding code, then confirm or discard. |
132
+ | Low | Heuristics or unresolved runtime spreads are the main evidence. | Trace further and fix only after confirmation. |
133
+ | Unknown | The semantic target cannot be resolved. | Leave unchanged and report the ambiguity when material. |
83
134
 
84
- ```tsx
85
- // constants.ts
86
- export const ARIA_LABELS = {
87
- playButton: 'Play audio',
88
- pauseButton: 'Pause audio',
89
- } as const;
135
+ Confidence establishes whether a finding is real, not whether its fix is safe.
136
+ Apply confirmed local, behavior-preserving fixes. Leave a confirmed issue
137
+ unchanged only when product intent is unknowable or the fix requires risky,
138
+ non-local behavior changes.
90
139
 
91
- // component.tsx
92
- <Button
93
- aria-label={isPlaying ? ARIA_LABELS.pauseButton : ARIA_LABELS.playButton}
94
- >
95
- {isPlaying ? '⏸' : '▶'}
96
- </Button>;
97
- ```
140
+ ### Semantic Resolution Order
98
141
 
99
- ---
142
+ Resolve rendered behavior in this order:
100
143
 
101
- ## Common Mistake: Individual ARIA Properties Instead of A11y Type
144
+ 1. Flagged JSX element and static props
145
+ 2. Explicit polymorphic props such as `as="a"` or `component="button"`
146
+ 3. Local component implementation
147
+ 4. Installed package source or declarations
148
+ 5. Prop evidence such as `href`, `to`, `src`, `alt`, and `role`
149
+ 6. Component-name heuristics
102
150
 
103
- **❌ Wrong:**
151
+ Follow local imports to their rendered root. For package imports, inspect the
152
+ resolved package entry when available. Do not assign more confidence than the
153
+ evidence supports.
104
154
 
105
- ```typescript
106
- import type { Direction } from '@wix/editor-react-types';
155
+ ## Manual Review
107
156
 
108
- export interface TabsProps {
109
- id?: string;
110
- className?: string;
111
- direction?: Direction;
112
- ariaLabel?: string; // ❌ Individual ARIA prop
113
- ariaDescribedBy?: string; // ❌ Individual ARIA prop
114
- role?: string; // ❌ Individual ARIA prop
115
- }
116
- ```
157
+ Verify all of the following after triaging scanner output.
117
158
 
118
- **✅ Correct:**
159
+ ### Semantic Targeting
119
160
 
120
- ```typescript
121
- import type { A11y, Direction } from '@wix/editor-react-types';
122
- import { convertA11yKeysToHtmlFormat } from '@wix/react-component-utils';
161
+ - `a11y` is typed and converted on the correct semantic element.
162
+ - Wrappers and polymorphic components preserve their documented semantics.
163
+ - Configurable heading or tag choices reach the rendered element.
164
+ - Extension overrides preserve generated accessibility fields.
123
165
 
124
- export interface TabsProps {
125
- id?: string;
126
- className?: string;
127
- direction?: Direction;
128
- a11y?: A11y; // ✅ All ARIA attributes through this prop
129
- }
166
+ ### Names and Visual Content
130
167
 
131
- // Usage:
132
- <Tabs a11y={{ ariaLabel: "Navigation", role: "navigation" }} />
168
+ - Icon-only controls have configurable or stable system-owned names.
169
+ - Visually hidden text remains in the accessibility tree when needed.
170
+ - Meaningful images and icons are named; decorative repetitions are hidden.
171
+ - Accessibility strings are not hardcoded directly in JSX.
133
172
 
134
- // In component:
135
- {...(a11y && convertA11yKeysToHtmlFormat(a11y))}
136
- ```
173
+ ### Hidden Content and Focus
174
+
175
+ - Hidden or collapsed state agrees across visuals, focusability, and the
176
+ accessibility tree.
177
+ - Invisible content cannot receive focus unless the interaction requires it.
178
+ - Disabled and inert states behave consistently for keyboard and assistive
179
+ technology users.
180
+
181
+ ### Interaction and Structure
182
+
183
+ - Interactive-looking elements use native semantics or complete role, focus,
184
+ and keyboard behavior.
185
+ - `onClick` on a non-interactive tag is checked, including conditional spreads.
186
+ - Nested interactive children and existing focus management are inspected
187
+ before semantics are added to a wrapper.
188
+ - Lists, headings, landmarks, tabs, menus, dialogs, and breadcrumbs keep their
189
+ intended structure.
190
+ - The root implements the direction contract, and every `ReactNode` slot
191
+ isolates nested content with `dir="ltr"`.
192
+
193
+ ## Pre-Fix Checks for Non-Interactive Controls
194
+
195
+ Before adding `role="button"`, `tabIndex`, and keyboard handlers to a non-native
196
+ control, verify:
197
+
198
+ 1. **Interactive children:** it cannot contain a link, button, input, or another
199
+ interactive component in the active branch.
200
+ 2. **Focus ownership:** existing `tabIndex` or accessibility spreads have a
201
+ clear merge order and one authoritative source.
202
+ 3. **Interaction condition:** the same condition gates pointer, focus, and
203
+ keyboard behavior and excludes disabled or editor-controlled states when
204
+ needed.
205
+ 4. **Accessible-name scope:** the label intentionally names the component or
206
+ action and persists in every state where it is needed.
207
+
208
+ Prefer a native element when it preserves product behavior.
209
+
210
+ ## Completion Criteria
211
+
212
+ The accessibility review is complete only when:
137
213
 
138
- **Why:** The `A11y` type from `@wix/editor-react-types` provides a standardized way to handle ALL ARIA attributes (ariaLabel, ariaDescribedBy, ariaLabelledBy, role, ariaHidden, ariaLive, etc.). Individual ARIA props fragment the API and make it harder to use.
214
+ - both scanners start successfully;
215
+ - every finding is triaged;
216
+ - confirmed issues are fixed when safe;
217
+ - the manual review is complete; and
218
+ - both scanners are rerun on every changed `.tsx` or `.jsx` file.
139
219
 
220
+ Preserve visual and runtime behavior. Fix the semantic owner: root, named inner
221
+ part, shared primitive, or call site. Then return to the main workflow for the
222
+ Wix build, manifest generation, TypeScript check, and relevant project tests.
@@ -1,14 +1,22 @@
1
- # Animated Components (Play/Pause Control)
1
+ # Animated Components
2
2
 
3
- Rules and patterns for components whose primary content is a **playable
4
- animation** — a Lottie/JSON animation, an animated GIF/SVG, a canvas/WebGL
5
- loop, or a video-like surface.
3
+ Use this reference when the component's primary content is a **playable
4
+ animation**—a Lottie/JSON animation, an animated GIF/SVG, a canvas/WebGL loop,
5
+ or a video-like surface.
6
6
 
7
- Every such component MUST ship an on-stage **play/pause button**.
7
+ Every such component must ship an on-stage **play/pause button**.
8
8
 
9
- ---
9
+ ## Contents
10
10
 
11
- ## When this applies
11
+ - [Apply When](#apply-when)
12
+ - [Required Contract](#required-contract)
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
+ - [Checklist](#checklist)
18
+
19
+ ## Apply When
12
20
 
13
21
  Apply automatically — without being asked — whenever the component has an
14
22
  `autoPlay` prop **or** its primary content is a **startable / loopable**
@@ -22,25 +30,28 @@ animation a visitor would reasonably want to start or stop:
22
30
 
23
31
  **Key rule:** If the component accepts an `autoPlay` prop — even if the
24
32
  underlying mechanism is a `setInterval` advancing an index rather than a media
25
- player — it MUST expose a play/pause button so visitors can stop the
33
+ player, it must expose a play/pause button so visitors can stop the
26
34
  auto-advancing behavior. "Autoplay" is a behavior contract, not an
27
35
  implementation detail.
28
36
 
29
- ---
30
-
31
- ## What to add (checklist)
37
+ ## Required Contract
32
38
 
33
- 1. **Props** — `autoPlay`, `loop`, `pauseButtonVisibility`
39
+ 1. **Props** — for a new component, use `autoPlay` when it can start
40
+ automatically, `loop` only when repeat behavior is supported, and
41
+ `pauseButtonVisibility` for the on-stage control. When editing, preserve
42
+ existing playback prop names and add only the missing safety contract.
34
43
  2. **Playback state** — `isPlaying` + `handlePause` / `handleResume`
35
- 3. **Play/pause button** — overlay `<button>` with inline SVG icon + CSS positioning and optional hover-only visibility; **must be a named part** (`classNames('component-name-play-button', styles.playButton)`) with hover/focus design-state selectors
44
+ 3. **Play/pause button** — overlay `<button>` with inline SVG icon and CSS
45
+ positioning; it must be a named part with `elementProps` wiring, a hover
46
+ design state, and a standalone `:focus-visible` keyboard indicator
36
47
  4. **Modify `component.preview.tsx`** — suppress autoplay in editor design mode
37
48
  5. **Respect `prefers-reduced-motion`** — suppress autoplay when the OS requests reduced motion
38
49
 
39
- ---
40
-
41
- ## 1. Props
50
+ ## 1. Define Props
42
51
 
43
- Playback controls are **behavior** props (see [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md)):
52
+ Playback controls are behavior props. `pauseButtonVisibility` is the documented
53
+ exception to the usual visual-visibility rule because editor preview must be
54
+ able to force the safety control visible.
44
55
 
45
56
  ```typescript
46
57
  import type { A11y, Direction } from '@wix/editor-react-types';
@@ -59,12 +70,17 @@ export interface MyAnimationProps {
59
70
 
60
71
  /** Show play/pause button. Default `'showOnHover'`. */
61
72
  pauseButtonVisibility?: 'showAlways' | 'showOnHover';
73
+
74
+ elementProps?: {
75
+ playButton?: { className?: string };
76
+ };
62
77
  }
63
78
  ```
64
79
 
65
- ---
80
+ The example shows a looping animation. Omit `loop` when the component does not
81
+ support repeat behavior; do not add it only to match the example.
66
82
 
67
- ## 2. Playback state
83
+ ## 2. Manage Playback State
68
84
 
69
85
  Track play/pause state with `useState`. Initialize it from `autoPlay` and the OS reduced-motion preference — when the visitor has requested reduced motion, the animation starts paused:
70
86
 
@@ -97,9 +113,7 @@ const handleResume = () => setIsPlaying(true);
97
113
 
98
114
  Pass `isPlaying` to the animation renderer and toggle between `handlePause` / `handleResume` on button click.
99
115
 
100
- ---
101
-
102
- ## 3. Play/pause button
116
+ ## 3. Add the Play/Pause Button
103
117
 
104
118
  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, stroke, and fill should feel native to the component's design.
105
119
 
@@ -126,30 +140,54 @@ Position the button absolutely so it overlays the content without pushing other
126
140
  /* e.g. background: rgba(255, 255, 255, 1); */
127
141
  }
128
142
 
129
- .playButton:global(.my-animation-play-button--focus),
143
+ /* Keyboard indicator only: focus is not an editor design state on a non-input
144
+ control unless editable focus styling was explicitly requested. */
130
145
  .playButton:focus-visible {
131
146
  outline: 2px solid currentColor;
132
147
  outline-offset: 2px;
133
148
  }
134
149
  ```
135
150
 
151
+ Define stable system-owned labels outside JSX:
152
+
153
+ ```ts
154
+ // constants.ts
155
+ export const ARIA_LABELS = {
156
+ playButton: 'Play animation',
157
+ pauseButton: 'Pause animation',
158
+ } as const;
159
+ ```
160
+
161
+ Set the visibility data attribute on the existing elected root, preserving its
162
+ full root contract:
163
+
164
+ ```tsx
165
+ data-pause-button-visibility={pauseButtonVisibility ?? 'showOnHover'}
166
+ ```
167
+
168
+ Wire the named part completely:
169
+
136
170
  ```tsx
137
- {/* ✅ Named part: play/pause is always a named part — site owners can style it independently */}
138
171
  <button
139
172
  type="button"
140
- className={classNames('my-animation-play-button', styles.playButton)}
173
+ {...elementProps?.playButton}
174
+ className={classNames(
175
+ 'my-animation-play-button',
176
+ styles.playButton,
177
+ elementProps?.playButton?.className,
178
+ )}
141
179
  onClick={isPlaying ? handlePause : handleResume}
142
- aria-label={isPlaying ? 'Pause' : 'Play'}
180
+ aria-label={
181
+ isPlaying ? ARIA_LABELS.pauseButton : ARIA_LABELS.playButton
182
+ }
143
183
  >
144
184
  {isPlaying ? <PauseIcon /> : <PlayIcon />}
145
185
  </button>
146
186
  ```
147
187
 
148
188
  ```css
149
- /* pauseButtonVisibility visibility behavior — descendant CSS is allowed here
150
- because these rules control the button's *visibility*, not its styling surface.
151
- The button itself is a named part (classNames('...-play-button', styles.playButton))
152
- and must carry both a global class and design-state selectors (see above). */
189
+ /* Narrow behavior-only exception documented in CSS-GUIDELINES.md. Keep editable
190
+ appearance on .playButton and use this relationship only for visibility. */
153
191
 
154
192
  /* showOnHover (default) */
155
193
  .root[data-pause-button-visibility="showOnHover"] .playButton {
@@ -165,37 +203,44 @@ Position the button absolutely so it overlays the content without pushing other
165
203
  /* showAlways — no extra CSS needed; button is visible by default */
166
204
  ```
167
205
 
168
- ---
169
-
170
- ## 4. Modify `component.preview.tsx` for autoplay suppression
206
+ ## 4. Suppress Autoplay in `component.preview.tsx`
171
207
 
172
- For animated components, modify the generated `component.preview.tsx` to suppress autoplay in editor design mode. See [`COMPONENT-PREVIEW.md`](COMPONENT-PREVIEW.md) for how the preview file works.
208
+ The Wix CLI scaffold generates `component.preview.tsx`. For animated components,
209
+ modify its passthrough preview component without replacing the generated
210
+ defaults or fallback-placeholder wiring.
173
211
 
174
- ### Target state of `component.preview.tsx`
212
+ ### Adapt the generated `component.preview.tsx`
175
213
 
176
- Replace the generated passthrough with the following. Replace `MyComponent` with the real component name.
214
+ Add `useIsEditMode` to the existing `@wix/react-component-utils` import. In the
215
+ generated preview component, replace only the passthrough return with the gated
216
+ props below. Keep the generated `withFallbackPlaceholder`, required-data fields,
217
+ root class, and `withDefaults` export unchanged.
177
218
 
178
219
  ```tsx
179
- import React from 'react';
180
- import MyComponent from './component';
181
- import { useIsEditMode } from '@wix/react-component-utils';
182
-
183
- export default function MyComponentPreview(
184
- props: React.ComponentProps<typeof MyComponent>,
185
- ) {
220
+ const MyAnimationPreview: FC<ComponentProps<typeof Component>> = (props) => {
186
221
  const isEditMode = useIsEditMode();
187
222
 
188
223
  return (
189
- <MyComponent
224
+ <Component
190
225
  {...props}
191
226
  autoPlay={isEditMode ? false : props.autoPlay}
192
227
  pauseButtonVisibility={isEditMode ? 'showAlways' : props.pauseButtonVisibility}
193
228
  />
194
229
  );
195
- }
230
+ };
196
231
  ```
197
232
 
198
- In editor design mode (`isEditMode` is `true`) → `autoPlay` is forced to `false` and `pauseButtonVisibility` is forced to `'showAlways'` so the site owner can always see and interact with the button.
233
+ In editor design mode (`isEditMode` is `true`) → `autoPlay` is forced to `false` and `pauseButtonVisibility` is forced to `'showAlways'` so the site owner can always see and interact with the button.
199
234
  In preview mode (`isEditMode` is `false`) → both use the user's configured values.
200
235
 
201
- ---
236
+ ## Checklist
237
+
238
+ - [ ] Autoplaying or loopable primary content has an on-stage play/pause control.
239
+ - [ ] Autoplay and pause-control props use the documented contract; `loop` is
240
+ present only when repeat behavior is supported.
241
+ - [ ] Reduced motion starts paused and never restarts playback automatically.
242
+ - [ ] The play/pause button is a fully wired named part with a stable accessible name.
243
+ - [ ] Hover has a paired editor design state; `:focus-visible` remains a
244
+ standalone keyboard indicator.
245
+ - [ ] Hover-only visibility changes behavior, not the button's editable styling surface.
246
+ - [ ] The preview preserves generated wrappers and forces autoplay off in design mode.
@@ -1,9 +1,10 @@
1
1
  # Branded / Themed Components
2
2
 
3
- Apply automatically — without being asked — whenever the user requests a
4
- **branded**, **themed**, or **brand-aware** component.
3
+ Use this reference only when the prompt explicitly requests a **branded**,
4
+ **themed**, or **brand-aware** component. Do not infer this requirement from a
5
+ generic request for polished styling.
5
6
 
6
- ---
7
+ ## Rules
7
8
 
8
9
  Import theme tokens from `@wix/react-component-schema/theme-variables.module.css`
9
10
  using CSS Modules `@value`, then consume with `var()`.
@@ -24,6 +25,14 @@ using CSS Modules `@value`, then consume with `var()`.
24
25
 
25
26
  **Body:** `wst-paragraph-1..3-font` / `wst-paragraph-1..3-color`
26
27
 
27
- ❌ Don't use `var(--wst-*)` directly — import the `@value` alias first.
28
- ❌ Don't use `@import` — CSS Modules doesn't process `@value` aliases from `@import`; `@value` is the only mechanism that resolves them at build time.
29
- ❌ Don't use `wst-base-1-color` for text — it typically resolves to white and is invisible on the default white background. Use `wst-heading-*-color` / `wst-paragraph-*-color` for text, or `wst-base-2-color` if you need a base contrast color.
28
+ - Do not use `var(--wst-*)` directly; import the `@value` alias first.
29
+ - Do not use `@import`; CSS Modules resolves theme aliases through `@value`.
30
+ - Do not use `wst-base-1-color` for text. Prefer heading/paragraph color tokens,
31
+ or `wst-base-2-color` when a base contrast color is required.
32
+
33
+ ## Checklist
34
+
35
+ - [ ] Theme values are imported from `theme-variables.module.css` with `@value`.
36
+ - [ ] Imported aliases are consumed through `var()`.
37
+ - [ ] Typography uses heading/paragraph font and color token pairs.
38
+ - [ ] Text colors remain legible on the selected background token.