@wix/agent-skills 1.19.1 → 1.19.2

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 (32) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +1 -1
  3. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +7 -2
  4. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +46 -22
  5. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +17 -4
  6. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +71 -31
  7. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +3 -4
  8. package/skills/wix-base44-connector/SKILL.md +46 -24
  9. package/skills/wix-headless/SKILL.md +1 -0
  10. package/skills/wix-headless/references/CAPABILITIES.md +7 -2
  11. package/skills/wix-headless/references/SDK_HANDOFF.md +2 -1
  12. package/skills/wix-headless/references/inline-recipes/experience-store.md +48 -0
  13. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +350 -114
  14. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +1 -1
  15. package/skills/wix-headless/references/managed/CREATE.md +5 -0
  16. package/skills/wix-manage/SKILL.md +4 -4
  17. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +4 -1
  18. package/skills/wix-manage/references/bookings/create-appointment-service.md +3 -1
  19. package/skills/wix-manage/references/bookings/create-class-service.md +3 -1
  20. package/skills/wix-manage/references/bookings/create-course-service.md +4 -2
  21. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +68 -3
  22. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-seasonal-promotion.md +1 -1
  23. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +108 -14
  24. package/skills/wix-manage/references/seo/manage-content-plan.md +1 -1
  25. package/skills/wix-manage/references/sites/upload-static-site.md +264 -34
  26. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +68 -26
  27. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +32 -14
  28. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +14 -3
  29. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductCard.js +41 -35
  30. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +77 -30
  31. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +31 -2
  32. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +31 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/agent-skills",
3
- "version": "1.19.1",
3
+ "version": "1.19.2",
4
4
  "description": "Wix Skills for AI coding agents — versioned npm distribution of the wix/skills content.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -110,7 +110,7 @@ extension configuration, and supporting files.
110
110
  | Trigger | Read |
111
111
  | --- | --- |
112
112
  | Interactive/selectable part or custom state | [`DESIGN-STATES.md`](editor-react-component/DESIGN-STATES.md) |
113
- | Public event callbacks added or changed | [`FUNCTION-HANDLERS.md`](editor-react-component/FUNCTION-HANDLERS.md) |
113
+ | Creating interactive components or changing interactions/callbacks | [`FUNCTION-HANDLERS.md`](editor-react-component/FUNCTION-HANDLERS.md) |
114
114
  | Browser APIs, effects, or time-dependent output | [`SSR.md`](editor-react-component/SSR.md) |
115
115
  | Non-established CSS feature or DOM API, or user asks for one by name | [`BROWSER-SUPPORT.md`](editor-react-component/BROWSER-SUPPORT.md) |
116
116
  | `npx wix build` or manifest generation exits with an error | [`MANIFEST-ERRORS.md`](editor-react-component/MANIFEST-ERRORS.md) |
@@ -192,13 +192,18 @@ the `a11y` contract, and SSR safety. Verify what it cannot see:
192
192
  meaning stays in the accessibility tree.
193
193
  - State hidden through `--display` or transforms agrees with focusability and
194
194
  the accessibility tree; disabled and inert states behave consistently.
195
- - Custom widgets (tabs, menus, dialogs, sliders) implement their keyboard
196
- pattern: arrow keys, Home/End, Escape, roving `tabIndex`.
195
+ - Custom widgets (tabs, menus, dialogs, sliders) implement their full APG
196
+ keyboard pattern (arrow keys, Home/End, Escape, roving `tabIndex`) and
197
+ structural relationships, or use a plain native element instead of
198
+ borrowing the role.
197
199
  - Interactive controls have a hit area of at least 24×24 CSS px and visible
198
200
  focus.
199
201
  - The root implements the direction contract, and every `ReactNode` slot
200
202
  isolates nested content with `dir="ltr"`.
201
203
 
204
+ - An auto-rotating set of readable parallel items uses `aria-live="off"` while
205
+ it is rotating and `aria-live="polite"` while it is stopped.
206
+
202
207
  ## Pre-Fix Checks for Non-Interactive Controls
203
208
 
204
209
  Before adding `role="button"`, `tabIndex`, and keyboard handlers to a non-native
@@ -9,10 +9,12 @@ Every such component must ship an on-stage **play/pause button**.
9
9
 
10
10
  - [Apply When](#apply-when)
11
11
  - [Required Contract](#required-contract)
12
+ - [Announce Manually Selected Parallel Content](#announce-manually-selected-parallel-content)
12
13
  - [Define Props](#1-define-props)
13
14
  - [Manage Playback State](#2-manage-playback-state)
14
15
  - [Add the Play/Pause Button](#3-add-the-playpause-button)
15
16
  - [Suppress Autoplay in `component.preview.tsx`](#4-suppress-autoplay-in-componentpreviewtsx)
17
+ - [Edit the generated `component.preview.tsx`](#edit-the-generated-componentpreviewtsx)
16
18
  - [Checklist](#checklist)
17
19
 
18
20
  ## Apply When
@@ -41,12 +43,26 @@ implementation detail.
41
43
  existing playback prop names and add only the missing safety contract.
42
44
  Carousels, sliders, slideshows, and galleries **must** define `autoPlay`
43
45
  (default `true`).
44
- 2. **Playback state** — `isPlaying` + `handlePause` / `handleResume`
46
+ 2. **Playback state** — play/pause toggle state, derived `isPlaying`, and
47
+ `handlePause` / `handleResume`
45
48
  3. **Play/pause button** — overlay `<button>` with inline SVG icon and CSS
46
49
  positioning; it must be a named part with `elementProps` wiring, a hover
47
50
  design state, and a standalone `:focus-visible` keyboard indicator
48
51
  4. **Modify `component.preview.tsx`** — suppress autoplay in editor design mode
49
- 5. **Respect `prefers-reduced-motion`** — suppress autoplay when the OS requests reduced motion
52
+ 5. **Respect `prefers-reduced-motion`** — start paused when the OS requests reduced motion
53
+
54
+ ### Announce Manually Selected Parallel Content
55
+
56
+ For carousel-like components that swap readable parallel items, make the item
57
+ wrapper a live region:
58
+
59
+ - Use `aria-live={isPlaying ? 'off' : 'polite'}` and `aria-atomic="false"`.
60
+ - `isPlaying = isPlayOn && !isHovered && !isStoppedByFocus`. Reduced motion
61
+ starts paused; editor mode, `autoPlay={false}`, and pause set it false.
62
+ Keyboard focus remains stopped until the rotation control restarts; hover
63
+ pauses temporarily.
64
+ - Previous/next changes items. Use root `onMouseEnter`/`onMouseLeave`;
65
+ leaving resumes unless focus has stopped rotation.
50
66
 
51
67
  ## 1. Define Props
52
68
 
@@ -83,36 +99,44 @@ support repeat behavior; do not add it only to match the example.
83
99
 
84
100
  ## 2. Manage Playback State
85
101
 
86
- 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:
102
+ Track play/pause button state with `useState`. Initialize it from `autoPlay`
103
+ and reduced motion; reduced motion starts paused, but a visitor can start it.
87
104
 
88
105
  ```tsx
89
106
  import { useReducedMotion } from '@wix/react-component-utils';
90
107
 
91
- // inside the component:
92
108
  const reducedMotion = useReducedMotion();
93
109
 
94
- const [isPlaying, setIsPlaying] = React.useState((autoPlay ?? true) && !reducedMotion);
95
-
96
- // when autoPlay prop changes, re-sync (but still respect reduced motion)
97
- React.useEffect(() => {
98
- setIsPlaying((autoPlay ?? true) && !reducedMotion);
99
- }, [autoPlay]);
110
+ const [isPlayOn, setIsPlayOn] = React.useState(() => (autoPlay ?? true) && !reducedMotion);
100
111
 
101
- // when reduced motion is enabled, suppress playback; never re-enable on its own
102
- // (visitor may have manually paused — don't restart against their will)
112
+ const skipInitialAutoPlaySync = React.useRef(true);
103
113
  React.useEffect(() => {
104
- if (reducedMotion) {
105
- setIsPlaying(false);
114
+ if (skipInitialAutoPlaySync.current) {
115
+ skipInitialAutoPlaySync.current = false;
116
+ return;
106
117
  }
107
- }, [reducedMotion]);
118
+ setIsPlayOn(autoPlay ?? true);
119
+ }, [autoPlay]);
108
120
 
109
- const handlePause = () => setIsPlaying(false);
110
- const handleResume = () => setIsPlaying(true);
121
+ const handlePause = () => setIsPlayOn(false);
122
+ const handleResume = () => setIsPlayOn(true);
111
123
  ```
112
124
 
113
- **`reducedMotion`** is `true` when the hook reports that reduced motion is enabled. When active, the animation starts paused — the visitor can still press the play button to start it manually. It is a runtime browser signal, not a manifest/data prop; never expose it as a component prop or in the manifest.
125
+ `reducedMotion` is a runtime signal, not a manifest/data prop.
126
+
127
+ Derive runtime playback from `isPlayOn` plus only needed conditions. Without
128
+ another condition, use `const isPlaying = isPlayOn`. A carousel, slideshow,
129
+ slider, or gallery also uses hover and focus-stop state:
130
+
131
+ ```tsx
132
+ const isPlaying = isPlayOn && !isHovered && !isStoppedByFocus;
133
+ ```
114
134
 
115
- Pass `isPlaying` to the animation renderer and toggle between `handlePause` / `handleResume` on button click.
135
+ Pass `isPlaying` to the renderer. The button uses `isPlayOn` and toggles
136
+ between `handlePause` / `handleResume` on click. In a carousel-like component,
137
+ focus entering anything except that button sets `isPlayOn` to `false` and
138
+ `isStoppedByFocus` to `true`; `handleResume` sets `isPlayOn` to `true` and
139
+ clears `isStoppedByFocus`.
116
140
 
117
141
  ## 3. Add the Play/Pause Button
118
142
 
@@ -177,12 +201,12 @@ Wire the named part completely:
177
201
  styles.playButton,
178
202
  elementProps?.playButton?.className,
179
203
  )}
180
- onClick={isPlaying ? handlePause : handleResume}
204
+ onClick={isPlayOn ? handlePause : handleResume}
181
205
  aria-label={
182
- isPlaying ? ARIA_LABELS.pauseButton : ARIA_LABELS.playButton
206
+ isPlayOn ? ARIA_LABELS.pauseButton : ARIA_LABELS.playButton
183
207
  }
184
208
  >
185
- {isPlaying ? <PauseIcon /> : <PlayIcon />}
209
+ {isPlayOn ? <PauseIcon /> : <PlayIcon />}
186
210
  </button>
187
211
  ```
188
212
 
@@ -33,6 +33,10 @@ export type PlanCardProps = {
33
33
  heading?: string;
34
34
  plans?: Array<Plan>;
35
35
  onClick?: (event: React.MouseEvent) => void;
36
+ onMouseIn?: (event: React.MouseEvent) => void;
37
+ onMouseOut?: (event: React.MouseEvent) => void;
38
+ onFocus?: (event: React.FocusEvent) => void;
39
+ onBlur?: (event: React.FocusEvent) => void;
36
40
 
37
41
  elementProps?: {
38
42
  cta?: { className?: string; href?: string };
@@ -47,9 +51,8 @@ Rules:
47
51
  code. Do not add one-off ARIA props or spread the whole object.
48
52
  - Expose only content and behavior that the site owner controls. Keep derived
49
53
  values internal.
50
- - Add only callbacks required by the component specification. Use supported SDK
51
- event names and types for public callbacks; keep implementation-only handlers
52
- internal.
54
+ - Default to common optional SDK callbacks by capability; add specialized ones
55
+ when requested. Keep implementation handlers internal.
53
56
  - Use `Array<T>`, not `T[]`, for exported arrays.
54
57
 
55
58
  ## Numeric Range Constraints
@@ -176,7 +179,16 @@ export const defaultProps = {
176
179
  ### Wix Data Types
177
180
 
178
181
  Use `Image`, `Link`, `Video`, `Audio`, `VectorArt`, `RichText` from
179
- `@wix/editor-react-types`. See `node_modules/@wix/react-component-schema/dist/editor-react-types.d.ts` for the full list.
182
+ `@wix/editor-react-types`. Model authored media with the corresponding Wix
183
+ media type, whether it is a top-level prop or a field in an array item. Name
184
+ the field for the media itself (`image`, `video`, `audio`, and so on), not for
185
+ one representation of it.
186
+
187
+ Do not represent media as a URL/source string or split its metadata across
188
+ 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.
180
192
 
181
193
  ## Defaults and Resources
182
194
 
@@ -242,5 +254,6 @@ Do not extract tiny fragments merely to satisfy a line-count threshold.
242
254
  - [ ] Named inner parts have `elementProps` wiring; leaf components avoid exported `children`.
243
255
  - [ ] One-body-visible arrays use the active-item contract and render all bodies.
244
256
  - [ ] Array elements are objects with semantic named fields. No separate `id` field added to item types; React keys use item fields (stable unique → slug → index), not a typed `id`.
257
+ - [ ] Authored media uses the corresponding Wix media type, not URL/source strings or flattened metadata.
245
258
  - [ ] Defaults live only in the props file (no JSX fallbacks).
246
259
  - [ ] Resources are Wix-hosted, prop-supplied, or locally bundled.
@@ -1,57 +1,92 @@
1
1
  # Function Handlers
2
2
 
3
- Use this reference only when the component specification exposes callbacks to
4
- site owners. Keep implementation-only handlers out of the public props type.
3
+ When creating a component or changing interactions, expose common optional
4
+ callbacks by capability, without requiring an explicit request.
5
+
6
+ ## Default Support
7
+
8
+ Apply defaults to the public interaction surface:
9
+
10
+ | Component capability | Default optional props |
11
+ | --- | --- |
12
+ | Pointer/click interaction, including native controls | `onClick`, `onMouseIn`, `onMouseOut` |
13
+ | Focusable control | `onFocus`, `onBlur` |
14
+ | Editable value, text, or selection | `onChange` |
15
+
16
+ Combine matching rows; leave decorative elements alone. Explicit API restrictions
17
+ override defaults. Specialized callbacks (`onDblClick`, `onPlay`, `onEnded`,
18
+ `onActivate`, etc.) require a request.
19
+
20
+ Classify composite controls by their interactive descendants. For example, a
21
+ radio-based rating input matches all three rows and exposes all six callbacks.
5
22
 
6
23
  ## Standard SDK Handlers
7
24
 
8
25
  Use the exact SDK prop name and wire it to the matching React DOM event.
9
26
 
10
- | SDK prop | React DOM prop | Type |
11
- | --- | --- | --- |
12
- | `onClick` | `onClick` | `(event: React.MouseEvent) => void` |
13
- | `onDblClick` | `onDoubleClick` | `(event: React.MouseEvent) => void` |
14
- | `onChange` | `onChange` | `(event: React.ChangeEvent<HTMLElement>) => void` |
15
- | `onFocus` | `onFocus` | `(event: React.FocusEvent) => void` |
16
- | `onBlur` | `onBlur` | `(event: React.FocusEvent) => void` |
17
- | `onMouseIn` | `onMouseEnter` | `(event: React.MouseEvent) => void` |
18
- | `onMouseOut` | `onMouseLeave` | `(event: React.MouseEvent) => void` |
19
-
20
- Declare only the handlers the component actually exposes.
27
+ | SDK prop | React DOM prop | Type | Zero config `domEvent` |
28
+ | --- | --- | --- | --- |
29
+ | `onClick` | `onClick` | `(event: React.MouseEvent) => void` | `POINTER` |
30
+ | `onDblClick` | `onDoubleClick` | `(event: React.MouseEvent) => void` | `POINTER` |
31
+ | `onChange` | `onChange` | `(event: React.ChangeEvent<HTMLElement>) => void` | `CHANGE` |
32
+ | `onFocus` | `onFocus` | `(event: React.FocusEvent) => void` | `FOCUS` |
33
+ | `onBlur` | `onBlur` | `(event: React.FocusEvent) => void` | `FOCUS` |
34
+ | `onMouseIn` | `onMouseEnter` | `(event: React.MouseEvent) => void` | `POINTER` |
35
+ | `onMouseOut` | `onMouseLeave` | `(event: React.MouseEvent) => void` | `POINTER` |
36
+
37
+ React `onChange` fires on live text edits and selection changes. Pass that
38
+ `ChangeEvent` directly. Do not synthesize a commit callback from blur or cast a
39
+ `FocusEvent` to `ChangeEvent`.
40
+
41
+ Callbacks only notify; they never enable controlled mode. Internal handlers run
42
+ component logic, then call the optional callback once, preserving event payloads
43
+ and disabled/read-only guards. Behavior must work without callbacks or consumer
44
+ prop updates. Forward directly when no internal logic is needed. Add controlled
45
+ state only when requested; preserve existing controlled APIs when editing.
21
46
 
22
47
  ```tsx
48
+ import * as React from 'react';
49
+
23
50
  export type ActionProps = {
24
51
  onClick?: (event: React.MouseEvent) => void;
25
- onDblClick?: (event: React.MouseEvent) => void;
26
52
  onMouseIn?: (event: React.MouseEvent) => void;
27
53
  onMouseOut?: (event: React.MouseEvent) => void;
54
+ onFocus?: (event: React.FocusEvent) => void;
55
+ onBlur?: (event: React.FocusEvent) => void;
28
56
  };
29
57
 
30
58
  export const Action: React.FC<ActionProps> = (props) => {
31
- const { onClick, onDblClick, onMouseIn, onMouseOut } = props;
59
+ const { onClick, onMouseIn, onMouseOut, onFocus, onBlur } = props;
60
+ const [count, setCount] = React.useState(0);
61
+
62
+ const handleClick = (event: React.MouseEvent) => {
63
+ setCount((value) => value + 1);
64
+ onClick?.(event);
65
+ };
32
66
 
33
67
  return (
34
68
  <button
35
69
  type="button"
36
- onClick={onClick}
37
- onDoubleClick={onDblClick}
70
+ onClick={handleClick}
38
71
  onMouseEnter={onMouseIn}
39
72
  onMouseLeave={onMouseOut}
40
- />
73
+ onFocus={onFocus}
74
+ onBlur={onBlur}
75
+ >
76
+ Clicked {count} times
77
+ </button>
41
78
  );
42
79
  };
43
80
  ```
44
81
 
45
- Do not expose DOM names such as `onDoubleClick`, `onMouseEnter`, or
46
- `onMouseLeave` in the component API; zero config recognizes the SDK names.
82
+ Zero config requires SDK names, not `onDoubleClick`, `onMouseEnter`, or
83
+ `onMouseLeave`, in public props.
47
84
 
48
85
  ## Custom Callbacks
49
86
 
50
- A component-level notification that is not one of the standard SDK DOM events
51
- uses `() => void` unless the component contract explicitly defines a serializable
52
- payload. Do not expose a React synthetic event for custom callbacks.
53
-
54
- Use this pattern:
87
+ Custom notifications use `() => void`; zero config emits no event parameter for
88
+ unrecognized callback names. Custom callbacks must not declare React event
89
+ parameters. Use a standard SDK handler above when the event is public:
55
90
 
56
91
  ```tsx
57
92
  export type VideoPlayerProps = {
@@ -62,14 +97,19 @@ export type VideoPlayerProps = {
62
97
 
63
98
  export const VideoPlayer: React.FC<VideoPlayerProps> = (props) => {
64
99
  const { onPlay, onPause, onEnded } = props;
65
- return <video onPlay={onPlay} onPause={onPause} onEnded={onEnded} />;
100
+ return (
101
+ <video
102
+ controls
103
+ onPlay={() => onPlay?.()}
104
+ onPause={() => onPause?.()}
105
+ onEnded={() => onEnded?.()}
106
+ />
107
+ );
66
108
  };
67
109
  ```
68
110
 
69
111
  ## Checklist
70
112
 
71
- - [ ] The specification explicitly requires each public callback.
72
- - [ ] Standard handler names match the SDK contract exactly.
73
- - [ ] Mismatched SDK/DOM names are mapped at the rendered element.
74
- - [ ] Custom callbacks do not leak React event objects.
75
- - [ ] Internal handlers remain implementation details.
113
+ - [ ] Defaults match capabilities; specialized callbacks are requested.
114
+ - [ ] SDK names, DOM mappings, and payloads match the contract.
115
+ - [ ] Internal behavior works independently and notifies callbacks once.
@@ -12,8 +12,7 @@ contracts changed by the request:
12
12
  2. Separate user-authored content and stable behavior from derived values and
13
13
  visual styling.
14
14
  3. Identify interaction and selectable states affected by the request.
15
- 4. Keep implementation behavior internal unless the component specification
16
- requests a public callback.
15
+ 4. Include common callbacks by capability; keep implementation handlers internal.
17
16
  5. Identify runtime concerns such as browser APIs, autoplay, editor-only
18
17
  behavior, or live site context before implementation.
19
18
 
@@ -49,8 +48,8 @@ export const ProfileCard: React.FC<ProfileCardProps> = (props) => {
49
48
  - When local state intentionally mirrors a prop, synchronize it when that prop
50
49
  changes. Do not use effect-managed state for a value that can be derived
51
50
  during render.
52
- - Keep implementation-only handlers internal. Expose a callback only when the
53
- specification makes it part of the component API.
51
+ - Internal handlers run component behavior, then notify optional callbacks.
52
+ Callback presence never enables controlled mode.
54
53
 
55
54
  ### Structure and Parts
56
55
 
@@ -23,8 +23,8 @@ they also surface from a search that began at the methods.
23
23
 
24
24
  In this skill:
25
25
 
26
- - **What are you building?** — route each feature to its identity: visitor token, admin token
27
- in a backend function, or admin ad hoc in exec_tool
26
+ - **What are you building?** — for visitors, for the owner, or management done for them —
27
+ decided per request from the user's intent, each on its own flow
28
28
  - **The helpers** — the `wx.*` loader every exec opens with
29
29
  - **Gather context** — `wx.context`, the report of what the site actually has
30
30
  - **Learn Wix** — find the APIs, learn their contracts
@@ -40,28 +40,41 @@ In this skill:
40
40
 
41
41
  ## What are you building?
42
42
 
43
- Choose the token by who the code acts for. A headless app can serve visitors, provide admin
44
- management tools, or do both.
45
-
46
- **A site for visitors** — use a visitor token for public reads and actions on behalf of the
47
- visitor, never the admin connector token. Call Wix directly from the browser through one shared
48
- visitor client (Write the code, below). Redirect sessions for Wix-hosted flows also require a
49
- visitor token minted for the headless OAuth app; see Visitor authentication and Wix-hosted flows below.
50
- **The OAuth app is a one-call prerequisite, not a dead end**: `wx.ensureOAuthApp` returns its
51
- `clientId`, creating the app when the site has none, so it is a visitor flow's first step — never
52
- a reason to move the flow onto the admin token or leave it for later.
53
- Anyone can mint an anonymous visitor token from the
54
- OAuth app's public `clientId`; no visitor login is required. APIs for the "current visitor"
55
- use that token to identify whose data and state to access. This applies both to a standalone
56
- headless frontend and to a frontend extending an existing Wix site.
57
-
58
- **An admin tool for the owner** — use the admin connector token in backend functions implementing
59
- admin logic; keep it secret and server-side. The frontend calls those functions, not Wix with
60
- visitor tokens. A custom headless management site extending the Wix back office follows this
61
- flow too. Ad hoc management calls in `exec_tool` also use the admin token. Backend functions
62
- also handle work requiring the owner's permissions, such as webhooks, scheduled jobs, and
63
- explicitly authorized elevated operations. For an app with both visitor and admin features,
64
- keep each feature on its corresponding flow.
43
+ Wix has two identities, visitor and admin, and each has its own flow. Decide which one every
44
+ request is for before acting on it — from what the user wants, not from the technology:
45
+
46
+ - **Visitor** — the people using the site: browsing, booking, buying, signing in as a member.
47
+ Visitor token, called from the browser through one shared visitor client.
48
+ - **Admin, built** — a management surface of the owner's own: a custom view, a bulk operation,
49
+ an internal tool. Admin connector token, server-side in backend functions the frontend calls.
50
+ - **Admin, done for them** — the user wants the business managed now, not an app: create the
51
+ products, change a setting, import the contacts. Admin token, ad hoc in exec_tool; nothing
52
+ ships in the app.
53
+
54
+ The owner already has a full Wix dashboard for running the business — orders, products,
55
+ bookings, settings, and more — so an admin build is a choice the user makes, not a gap to fill by
56
+ default. When a request has both visitor and admin parts, each keeps its own flow.
57
+
58
+ When the request doesn't say which, ask the user — in their terms (who the thing is for), not in
59
+ technical ones (identities, tokens, flows). When you decide without asking, tell them what you
60
+ chose the same way.
61
+
62
+ The rules that follow from the split:
63
+
64
+ - **Checkout runs on a visitor token, never the admin token** — including a checkout this app
65
+ creates for the visitor. The admin token *will* hand back a checkout URL, and that is the trap:
66
+ it belongs to the site rather than the buyer (no cart persistence, no abandoned-checkout
67
+ recovery, no attribution), and a redirect session refuses it outright (`403`). Returns reach
68
+ this app only from URLs in the OAuth app's redirect list (Visitor authentication and
69
+ Wix-hosted flows, below).
70
+ - **No OAuth app yet is not a reason to use the admin token.** `wx.ensureOAuthApp` returns the
71
+ `clientId`, creating the app when the site has none — a visitor flow's first step. Anyone can
72
+ mint an anonymous visitor token from that public `clientId`; no visitor login is required.
73
+ - **No login still means visitors.** `asServiceRole` governs this app's own data access and says
74
+ nothing about which identity Wix sees: a public page's Wix calls run on a visitor token. Reach
75
+ for the admin token because a feature is owner-side, never because nobody signs in.
76
+ - **Owner-side work beyond pages** — webhooks, scheduled jobs, explicitly authorized elevated
77
+ operations — is admin flow too, in backend functions.
65
78
 
66
79
  ```
67
80
  visitor pages ──(visitor token)────────────────────────► wixapis.com
@@ -69,6 +82,11 @@ admin pages ──► base44/functions/… ──(admin token)────►
69
82
  exec_tool ──(admin token, ad hoc management)────────► wixapis.com
70
83
  ```
71
84
 
85
+ **The connected site owns its payments.** Whatever the visitor buys is paid on the Wix-hosted page
86
+ this app hands them off to, with the provider the site already has. Base44's
87
+ `<available_payment_providers>` note is about checkout that Base44 hosts instead — it does not
88
+ apply to these flows, and asks nothing of them, whichever providers it names or rules out.
89
+
72
90
  ## The helpers
73
91
 
74
92
  Research and probing run in exec_tool, and one loader opens every exec (execs share no state —
@@ -118,6 +136,10 @@ One report: installed apps **with ids** (incl. Stores' catalog version — V1 vs
118
136
  endpoints), the OAuth app id (**also the visitor `clientId`**), locale, currency, CMS collections.
119
137
  An empty report = bad token, never an empty site.
120
138
 
139
+ No OAuth app in the report means the site has none **yet**. For anything a visitor operates,
140
+ create it with `wx.ensureOAuthApp` — one call, returns the `clientId` the frontend mints visitor
141
+ tokens from — and build the feature on the visitor flow.
142
+
121
143
  Reports over 4,000 characters are saved in full to a temporary Markdown file. The result includes
122
144
  its path, byte and line counts, and a heading outline. Read that file to inspect the site context.
123
145
 
@@ -124,6 +124,7 @@ Compute `<SKILL_ROOT>` from this file (`<SKILL_ROOT>/SKILL.md` — strip `/SKILL
124
124
  | Image generation (opt-in; agnostic) | `<SKILL_ROOT>/references/IMAGE_GENERATION.md` |
125
125
  | Design — fallback visual quality bar for the built frontend, when the user gave no design direction of their own (managed **create** only) | `<SKILL_ROOT>/references/DESIGN.md` |
126
126
  | Content — fallback copy quality bar for the built frontend, when the user gave no copy/voice direction of their own (managed **create** only) | `<SKILL_ROOT>/references/CONTENT.md` |
127
+ | Experience overlays — a vertical's own design + copy bar on top of DESIGN/CONTENT (optional per vertical; read when that vertical is loaded) | `<SKILL_ROOT>/references/inline-recipes/experience-<vertical>.md` (today: `experience-store.md`) |
127
128
  | AI features — text/chat + embeddings (opt-in; agnostic) | `<SKILL_ROOT>/references/AI_FEATURES.md` |
128
129
  | Feedback — relay the user's headless-experience feedback to Wix (opt-in; user-approved) | `<SKILL_ROOT>/references/FEEDBACK.md` |
129
130
  | **Authentication** — obtain `$TOKEN`/`$SITE_ID`/`clientId` (project-type-specific) | `<TYPE_DIR>/AUTHENTICATION.md` |
@@ -23,8 +23,13 @@ The verticals the skill operates end-to-end today: **stores · blog · cms · fo
23
23
 
24
24
  ### stores — sell products
25
25
  - **Intent:** sell / shop / products / catalog / merch / store.
26
- - **Required site features:** a product list or grid; a page per product; categories to browse by; a cart; a checkout.
27
- - **Implementation checklist:** show each product's image, name, and price; show options and variants (size, colour…) where they exist; show availability / out-of-stock; a quantity picker and an add-to-cart that updates a visible cart; the product description; link each product to its category.
26
+ - **Required site features:** a homepage that sells (what the store offers, real products, one clear shopping action); a shop / category gallery with sort, the filters the catalog supports, and paging; a page per product; categories to browse by; a cart the shopper can review and edit, opening as a side drawer after every add; checkout reachable directly from that cart.
27
+ - **Implementation checklist:**
28
+ - *Homepage:* say what the store sells in the first screen; real products from the catalog under truthful headings — never a repeat of the shop page, never a heading like "Best Sellers" without data behind it.
29
+ - *Gallery:* a real product — image, name, price, link — visible in the first screen before any scrolling; a result count; loading, empty-catalog, no-results-for-these-filters, and error states that look different from each other.
30
+ - *Product page:* in the first screen, the product image, name, price, the first choice to make, and the buy button — disabled with a plain reason until every choice is made; every ribbon the merchant set; the current price and, when there is one, the labelled original price; a gallery of every product image; options with unavailable choices marked; quantity; the full description and information sections; pre-order, subscriptions, and notify-me only when the catalog has them.
31
+ - *Cart:* each line's image, name, chosen options, quantity (editable) and price; subtotal and discounts as Wix calculates them; "shipping and taxes calculated at checkout" rather than invented numbers; survives a reload; checkout from the drawer.
32
+ - *Everywhere:* availability / out-of-stock shown truthfully; each product linked to its category; no reviews, ratings, scarcity, or delivery promises the merchant didn't supply; no Wix IDs or technical words in shopper-facing text.
28
33
 
29
34
  ### blog — publish posts
30
35
  - **Intent:** blog / posts / articles / publication / news.
@@ -36,7 +36,7 @@ Before implementing a capability, Read the local recipe linked in its row.
36
36
 
37
37
  | Capability | Package(s) | Required recipe |
38
38
  |---|---|---|
39
- | stores | `@wix/stores` (+ `@wix/ecom`, `@wix/redirects` for cart/checkout) | `how-to-code-a-store.md` — Catalog V3 read + cart/checkout. |
39
+ | stores | `@wix/stores` + `@wix/categories` (+ `@wix/ecom`, `@wix/redirects` for cart/checkout) | `how-to-code-a-store.md` — Catalog V3 gallery (sort/filter/paging), product page (variants, prices, ribbons), Cart V2 + checkout, and what a complete storefront shows. |
40
40
  | blog | `@wix/blog` (+ `@wix/ricos` to render `richContent`; **`@wix/comments` + `@wix/members`** when the blog has comments/members; `@wix/blog` `likes` when the site has members) | `how-to-code-a-blog.md` — Blog V3 read/render + member features (likes, comments). Supplement: <https://dev.wix.com/docs/sdk/business-solutions/blog.md>. |
41
41
  | cms | `@wix/data` | `how-to-code-cms.md` — `items.query` read contract. |
42
42
  | forms | `@wix/forms` | `how-to-code-forms.md` — schema-driven render (read the live form schema, visitor token/no elevate) + Form Submissions v4 write contract. |
@@ -77,6 +77,7 @@ Everything else the host resolves live from the queries in §3. (Static platform
77
77
  For each loaded capability, carry its **Required site features** and **Implementation checklist** from `references/CAPABILITIES.md` into the guide — in plain product language, lightly tailored to what was seeded. **This is the build spec, not optional polish:** the host should build every *required feature* and cover every *checklist* item. For example, a blog must show the **author** (name + photo), the publish date and reading time, the cover image, and the **full formatted content** (not flattened text) — a posts-list-plus-plain-text-body is incomplete. The host maps these onto its own components using the packages/docs in §3 and the seeded schema in §4.
78
78
 
79
79
  - State them as the *what* (product behaviour), not the *how* (no component code, no API calls) — the host owns the build.
80
+ - **When a loaded vertical ships an experience overlay** (`references/inline-recipes/experience-<vertical>.md`; today `experience-store.md`), point the host at it alongside the checklist — it is that vertical's design and copy bar (surfaces, first-viewport rules, truthful copy), read after the general `DESIGN.md`/`CONTENT.md`.
80
81
  - If a *required feature* depends on backend support that **Seed** enabled (e.g., comments), note it's available so the host wires it. If Seed could **not** enable it, say so plainly rather than implying the site is complete.
81
82
  - **When pricing-plans is loaded, `login / account / gated content` is a *required* feature, not optional polish** — a plans grid with no way to log in and subscribe is incomplete (subscribing requires a member; §5 member-auth note). Point the host at the matching `how-to-code-members-*.md` recipe. For the other verticals, a "my …" surface (my orders / my bookings / my registrations) is a member-gated *enhancement* — list it only if the run's intent calls for an account view, and flag it needs the same login mechanism.
82
83
  - **Curation / hero / nav must come from a LIVE query, never a pinned slug/id.** A "featured" or "latest" item, a hero, and every nav/category bar must be driven by a query — "next upcoming" (`queryEvents` filtered to `UPCOMING`/`STARTED`, sorted by start date), "newest" (`queryPosts`), `queryCategories`, etc. — resolved at request time. A pinned "featured event" slug not only fails to rotate as the owner adds content, it can go **stale/past**. Even a **single-item** site (one event, one product) must drive its homepage from the *listing query*, not a hardcoded lone slug — so a second item the owner adds later surfaces automatically instead of staying invisible.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: "Storefront Experience"
3
+ description: The storefront's own design and copy bar, on top of DESIGN.md and CONTENT.md — how to derive a store's direction from its catalog, what the homepage, gallery, product page, and cart must show, the overlay contract, truthful commerce copy, and image discipline. Read when building or wiring a store frontend; the API contract lives in how-to-code-a-store.md.
4
+ ---
5
+ **EXPERIENCE OVERLAY**: What makes a storefront good — read after `DESIGN.md` and `CONTENT.md`
6
+
7
+ `DESIGN.md` and `CONTENT.md` are the floor for every site. This file adds what is specific to a store. It is the *what* of a good storefront — the API *how* is `how-to-code-a-store.md`. The wiring is necessary, not sufficient: a store whose calls all work but whose homepage repeats the shop page, whose first screen shows no product, or whose cart hides checkout behind a page is not done.
8
+
9
+ **These are defaults for when the brief doesn't say otherwise.** Whatever the user asked for in their prompt — a layout, a page they don't want, a cart page instead of a drawer, a specific look — wins over any line here.
10
+
11
+ ## 1 · Design from the catalog, not from the category
12
+
13
+ Before choosing tokens, **look at the catalog**: the categories and their depth, the assortment size, the media (count, aspect ratios, background consistency, focal points), the options and price points, the ribbons and sales. Then write the store's direction as a few lines, held with the design tokens:
14
+
15
+ - a **one-sentence thesis** — the offer, the shopper, the character;
16
+ - **three traits**;
17
+ - an **avoid-list** of the stereotypes this store would fall into by default: "premium" does not mean dark, serif, minimal; "kids" does not mean primary colors; a bakery is not automatically cream and script. Keep the conventions of the store's own vertical that genuinely help shoppers compare and choose;
18
+ - one **signature decision** that makes the store recognizable with the logo hidden, backed by real content — a product form, a material, the category structure, a typographic move;
19
+ - a **media treatment** per placement (product, category, hero, fallback): frame ratio, `cover`/`contain`, focal behavior.
20
+
21
+ Two stores with the same vertical and different catalogs should look nothing alike. Never ask the user for a reference store; if they supply one, take only portable principles (hierarchy, image prominence, rhythm, density), never its layout, palette, typefaces, or taxonomy.
22
+
23
+ **Audit the media before giving it a role.** Never stretch an image, enlarge a thumbnail into a hero, or crop the product away; give every image a stable aspect ratio and `object-fit` so the grid doesn't jump. When hero-scale media is absent, compose the hero from typography, a product tile, or a collage of what exists. Product photography informs compatible backgrounds and contrast; it does not automatically dictate the UI's dominant color.
24
+
25
+ ## 2 · The surfaces and their bar
26
+
27
+ - **Global shell:** category navigation from the live tree (a curated menu is fine, but every product-bearing category stays reachable); a persistent cart control with a live count; a footer sized to the real destinations. Announcement, shipping, and returns text only from the merchant.
28
+ - **Homepage — a merchandising surface, not the shop page again.** Say what the store sells and give one dominant shopping action in the first viewport; real products from live queries under truthful headings; category discovery when the taxonomy is meaningful. Don't reuse the same first product as hero, first card, and feature. No section exists to fill space — a claim-dependent module with no truthful source is omitted.
29
+ - **Gallery — a discovery surface.** Title, result count, sort, the filters the catalog supports, paging; in its default state a **real product card — image, name, price, link — is inside the first viewport**, also on a short desktop window. Skeletons while loading, a distinct "no results for these filters" with a reset, an honest empty catalog, a recoverable error. Filters that stay visible with the results commit immediately; filters in a sheet stage changes until Apply.
30
+ - **Product page — a complete purchase decision.** In the first viewport at mobile, tablet, and desktop: a recognizable product image, name, price, the first required choice (or a control that jumps to it), and the buy action with its neutral disabled reason. Then every ribbon, the full description and info sections, a gallery of **every** image, quantity, and — when the catalog has them — subscriptions, preorder, group navigation, notify-me. A sticky buy region must never cover a control.
31
+ - **Cart — a side drawer by default**, opened after every successful add and from the header: image, name, the chosen options and text, quantity editing with pending and failure states, line prices, the calculated subtotal and discount, "shipping and taxes calculated at checkout", and checkout **from the drawer**. Persists across navigation and refresh. A separate cart page is optional, never a mandatory step before checkout.
32
+ - **Quick add** anchors to its card (an inline or attached panel; a bottom sheet on mobile); a centered dialog is the exception for a demonstrably large configuration, not the default. Its first view shows identity, price, the first required choice, and the action.
33
+
34
+ ## 3 · Overlays (cart drawer, quick add, mobile nav, filter sheet)
35
+
36
+ Mount at the document root — a `position: fixed` panel inside a header with a `transform`, `filter`, or `backdrop-filter` gets clipped. Full-viewport scrim; background scroll locked and inert; the panel scrolls independently with Close and the primary action always reachable; focus moves in and is trapped while modal; Escape closes; focus returns to the trigger on close (or moves to a successor surface when one overlay opens another). Verify this in the browser — CSS alone doesn't prove it.
37
+
38
+ ## 4 · Truthful commerce copy
39
+
40
+ - **Claims come from the merchant or the data, never from the page's need for a section.** No invented reviews, ratings, "X people bought this", scarcity, delivery promises, certifications, guarantees, or payment/trust badges.
41
+ - **Labels match their source.** "Best Sellers" needs sales data or a category the merchant named that way; the catalog's default order is not a ranking. "Featured" or the category's real name is always safe.
42
+ - **Write for shoppers, not implementers.** No Wix IDs, API names, "catalog", "current catalog", "headless", or integration words in headings, labels, buttons, or empty states.
43
+ - **Prices tell the truth.** A ribbon is a label, never proof of a discount; a struck price is labelled ("was") and shown only when it is real and higher; a range never gets a lone struck minimum; savings are never computed in the client.
44
+ - **Operational text is the merchant's.** A cart says "shipping and taxes calculated at checkout" rather than a number nobody configured.
45
+
46
+ ## 5 · Images
47
+
48
+ Responsive delivery (`srcset` + `sizes` from scaled Wix media candidates — `how-to-code-a-store.md` § Rendering product images), stable aspect ratios with `width`/`height`, lazy loading below the fold, meaningful `alt` text from the catalog's `altText` or the product name. Failed images get a visible fallback, never a broken icon.