@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.
- package/package.json +1 -1
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +134 -120
- package/skills/wix-app/references/EMBEDDED_SCRIPT.md +6 -0
- package/skills/wix-app/references/SITE_PLUGIN.md +2 -2
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +92 -47
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +15 -6
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +29 -42
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +153 -449
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +66 -19
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
- package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
- package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
- package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +27 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +45 -24
- package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
- package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
- package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
- package/skills/wix-base44-connector/SKILL.md +34 -17
- package/skills/wix-base44-connector/scripts/utils.js +33 -25
- package/skills/wix-headless/entry/bootstrap.mjs +9 -2
- package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +42 -23
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
- package/skills/wix-manage/SKILL.md +14 -2
- package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
- package/skills/wix-manage/references/bookings/create-class-service.md +1 -1
- package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
- package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
- package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +182 -5
- package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
- package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
- package/skills/wix-manage/references/sites/query-sites.md +72 -161
- package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +13 -9
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +10 -7
- package/skills/wix-vibe-headless/platforms/base44.md +13 -10
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +2 -0
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
- package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
- package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
- package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +15 -8
- package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
- package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -484
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
- package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
|
@@ -1,173 +1,89 @@
|
|
|
1
|
-
# React
|
|
1
|
+
# React Implementation Guide
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use this reference when planning or editing the component's React implementation.
|
|
4
|
+
The entry workflow remains authoritative; this file owns implementation decisions.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
- [`PARTS.md`](PARTS.md) — What qualifies as a named part (mandatory filter)
|
|
7
|
-
- [`DESIGN-STATES.md`](DESIGN-STATES.md) — Which design states a part supports, and how to author them
|
|
8
|
-
- [`ACCESSIBILITY.md`](ACCESSIBILITY.md) — ARIA/a11y rules and patterns
|
|
9
|
-
- [`DIRECTIONALITY.md`](DIRECTIONALITY.md) — RTL/LTR rules and patterns
|
|
10
|
-
- [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) — What should be a React prop vs CSS
|
|
11
|
-
- [`COMPONENT-API.md`](COMPONENT-API.md) — Props structure, elementProps, data types, file splitting, containers, array props
|
|
12
|
-
- [`FUNCTION-HANDLERS.md`](FUNCTION-HANDLERS.md) — Standard SDK event handler props, DOM wiring, custom callbacks
|
|
13
|
-
- [`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md) — Play/pause control and autoplay for animated/playable components
|
|
14
|
-
- [`REACT-PATTERNS.md`](REACT-PATTERNS.md) — SSR-safe patterns, CSS rules, common mistakes
|
|
6
|
+
## Plan the Component
|
|
15
7
|
|
|
16
|
-
|
|
8
|
+
For a new component, make every decision below. For an edit, revisit only the
|
|
9
|
+
contracts changed by the request:
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
1. Elect the best semantic root and identify independently editable inner parts.
|
|
12
|
+
2. Separate user-authored content and stable behavior from derived values and
|
|
13
|
+
visual styling.
|
|
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.
|
|
17
|
+
5. Identify runtime concerns such as browser APIs, autoplay, editor-only
|
|
18
|
+
behavior, or live site context before implementation.
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
## Implementation Rules
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
### Runtime Compatibility
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
4. **States** — For every part, decide which design states it supports (native: `hover`/`focus`/`disabled`/`invalid`; custom: `selected`/`active`/`open`/… ) by applying the heuristic in [`DESIGN-STATES.md`](DESIGN-STATES.md), and record them in the plan. These become the editor's per-element state styling controls.
|
|
30
|
-
|
|
31
|
-
**Understanding → implementation (checklist):** For every part, decide `elementProps` vs CSS-only and which design states it supports ([`DESIGN-STATES.md`](DESIGN-STATES.md)); build the props interface (data + behavior); wire interaction in React (`useState`, `useEffect`, refs, native event handlers); give every named inner element an `elementProps` entry and spread it + merge its `className` ([`COMPONENT-API.md`](COMPONENT-API.md)); generate TS + CSS. Infer reasonable defaults where anything is unspecified.
|
|
32
|
-
|
|
33
|
-
# Part 1: Standards & Conventions
|
|
34
|
-
|
|
35
|
-
These are the mandatory patterns and conventions for all components.
|
|
36
|
-
|
|
37
|
-
## 1.1 Mandatory Features
|
|
38
|
-
|
|
39
|
-
Every component MUST include:
|
|
40
|
-
|
|
41
|
-
### Direction Support (RTL/LTR)
|
|
42
|
-
|
|
43
|
-
Direction support is mandatory — see [`DIRECTIONALITY.md`](DIRECTIONALITY.md).
|
|
44
|
-
|
|
45
|
-
### Accessibility ARIA Support
|
|
46
|
-
|
|
47
|
-
See [`ACCESSIBILITY.md`](ACCESSIBILITY.md) for full rules and patterns.
|
|
24
|
+
- Use React 18-compatible APIs. Do not use React 19-only runtime features.
|
|
25
|
+
- Keep rendering SSR-safe and deterministic. Do not access browser globals
|
|
26
|
+
during render or derive initial output from time-dependent/generated values.
|
|
48
27
|
|
|
49
28
|
### TypeScript
|
|
50
29
|
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
**External handlers (only when specified):**
|
|
112
|
-
|
|
113
|
-
- Only expose handlers that are explicitly listed as component capabilities
|
|
114
|
-
- Use the standard SDK prop names and DOM wiring rules from [`FUNCTION-HANDLERS.md`](FUNCTION-HANDLERS.md)
|
|
115
|
-
|
|
116
|
-
**Child component handlers:**
|
|
117
|
-
|
|
118
|
-
- Internal sub-components receive handlers from parent via props
|
|
119
|
-
- These are still internal to the main component
|
|
120
|
-
|
|
121
|
-
## 1.3 Implementation Workflow
|
|
122
|
-
|
|
123
|
-
### Step 1: Analyze Component Parts
|
|
124
|
-
|
|
125
|
-
For each part of the component, decide:
|
|
126
|
-
|
|
127
|
-
**CSS class only if**:
|
|
128
|
-
|
|
129
|
-
- ✅ Purely visual/decorative
|
|
130
|
-
- ✅ No data or configuration needed
|
|
131
|
-
- ✅ No direction override needed
|
|
132
|
-
- ✅ No custom behavior needed
|
|
133
|
-
|
|
134
|
-
**Use elementProps if**:
|
|
135
|
-
|
|
136
|
-
- ✅ Needs data/content
|
|
137
|
-
- ✅ Needs direction override
|
|
138
|
-
- ✅ Has state or behavior
|
|
139
|
-
- ✅ Needs event handlers
|
|
140
|
-
|
|
141
|
-
For the same part, also decide which **design states** it supports (native + custom) per [`DESIGN-STATES.md`](DESIGN-STATES.md).
|
|
142
|
-
|
|
143
|
-
See [`COMPONENT-API.md`](COMPONENT-API.md) and [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) for the decision trees.
|
|
144
|
-
|
|
145
|
-
### Step 2: Build Props Interface
|
|
146
|
-
|
|
147
|
-
Combine:
|
|
148
|
-
|
|
149
|
-
1. Data/content props (from specification)
|
|
150
|
-
2. Behavior props (from specification)
|
|
151
|
-
3. Mandatory React props (direction, a11y, className, id)
|
|
152
|
-
4. elementProps (only for parts that need it)
|
|
153
|
-
|
|
154
|
-
### Step 3: Implement
|
|
155
|
-
|
|
156
|
-
Follow Part 2 templates with mandatory patterns applied. For each part's supported design states, author the interactive markup / class toggles and the state CSS per [`DESIGN-STATES.md`](DESIGN-STATES.md).
|
|
157
|
-
|
|
158
|
-
# Part 2: CSS Rules
|
|
159
|
-
|
|
160
|
-
All CSS authoring rules — root layout, naming, RTL, state styles,
|
|
161
|
-
transitions, etc. — live in [`CSS-GUIDELINES.md`](CSS-GUIDELINES.md).
|
|
162
|
-
|
|
163
|
-
See [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) and [`COMPONENT-API.md`](COMPONENT-API.md) for the prop vs CSS vs `elementProps` decision trees.
|
|
164
|
-
|
|
165
|
-
# Part 3: Examples & Reference
|
|
166
|
-
|
|
167
|
-
## 3.1 Implementation Checklist
|
|
168
|
-
|
|
169
|
-
**Phase 1: Analysis** — Parse information, map component structure and supported design states (see Part 0)
|
|
170
|
-
|
|
171
|
-
**Phase 2: Component File** — Apply all §1.1 mandatory features and §1.2 implementation standards; toggle custom-state classes from data ([`DESIGN-STATES.md`](DESIGN-STATES.md))
|
|
172
|
-
|
|
173
|
-
**Phase 3: Styles** — Apply Part 2 SCSS rules, including state styles ([`DESIGN-STATES.md`](DESIGN-STATES.md)). If the request uses the words **branded**, **themed**, or **brand-aware**, also apply [`BRANDED-COMPONENTS.md`](BRANDED-COMPONENTS.md) before writing CSS.
|
|
30
|
+
- Fully type component props and export the props type.
|
|
31
|
+
- Do not use `any`.
|
|
32
|
+
- Use `Array<T>` rather than `T[]`; exported array elements must be objects with
|
|
33
|
+
named keys.
|
|
34
|
+
- Export the component as an arrow function, accept `props` as its argument,
|
|
35
|
+
and destructure inside the function body.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
export const ProfileCard: React.FC<ProfileCardProps> = (props) => {
|
|
39
|
+
const { heading } = props;
|
|
40
|
+
return <article>{heading}</article>;
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Props and State
|
|
45
|
+
|
|
46
|
+
- Keep `id`, `className`, `direction`, and `a11y` in the public contract.
|
|
47
|
+
- Compute simple derived values during render instead of duplicating them in
|
|
48
|
+
props or state.
|
|
49
|
+
- When local state intentionally mirrors a prop, synchronize it when that prop
|
|
50
|
+
changes. Do not use effect-managed state for a value that can be derived
|
|
51
|
+
during render.
|
|
52
|
+
- Keep implementation-only handlers internal. Expose a callback only when the
|
|
53
|
+
specification makes it part of the component API.
|
|
54
|
+
|
|
55
|
+
### Structure and Parts
|
|
56
|
+
|
|
57
|
+
- Apply the root contract to the elected semantic root; do not add a wrapper
|
|
58
|
+
solely to hold `id`, `dir`, classes, or ARIA attributes.
|
|
59
|
+
- Give every named inner part a matching `elementProps` entry and spread it onto
|
|
60
|
+
that element. Merge its injected `className` on raw HTML elements.
|
|
61
|
+
- Keep structural wrappers and decorative elements module-class-only.
|
|
62
|
+
- Use semantic HTML for controls, lists, navigation, headings, and landmarks.
|
|
63
|
+
|
|
64
|
+
### Accessibility and Direction
|
|
65
|
+
|
|
66
|
+
- Route ARIA through the typed `a11y` contract.
|
|
67
|
+
- Put `dir={direction}` and the unconditional fallback-direction class on the
|
|
68
|
+
elected root. Use logical CSS properties; use runtime direction hooks only
|
|
69
|
+
when direction changes JavaScript behavior.
|
|
70
|
+
|
|
71
|
+
### Code Quality
|
|
72
|
+
|
|
73
|
+
- Leave no TypeScript errors, unused imports, TODO placeholders, or template
|
|
74
|
+
commentary in the final component.
|
|
75
|
+
- Prefer clear names and small internal components over long inline JSX blocks.
|
|
76
|
+
- Preserve useful comments that explain non-obvious behavior; remove comments
|
|
77
|
+
that merely narrate the code or were copied from examples.
|
|
78
|
+
|
|
79
|
+
## Implementation Checklist
|
|
80
|
+
|
|
81
|
+
- [ ] The semantic root owns the top-level component contract.
|
|
82
|
+
- [ ] Props contain content and behavior, not breakpoint styling decisions.
|
|
83
|
+
- [ ] Every named inner part has global/module classes and `elementProps` wiring.
|
|
84
|
+
- [ ] Native and custom design states in scope are wired to their affected parts.
|
|
85
|
+
- [ ] Render output is deterministic and SSR-safe.
|
|
86
|
+
- [ ] Direction and accessibility contracts are wired to the correct elements.
|
|
87
|
+
- [ ] Public handlers use supported SDK names; internal handlers stay internal.
|
|
88
|
+
- [ ] CSS changed by the request keeps editable selectors flat and scoped.
|
|
89
|
+
- [ ] The accessibility review runs after JSX edits.
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
# Site Context Hooks
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
editor mode
|
|
3
|
+
Use this reference when the component must read **live runtime context** that the
|
|
4
|
+
site owner cannot author as component data: the site page tree, current URL,
|
|
5
|
+
language direction, editor mode, or reduced-motion preference.
|
|
6
6
|
|
|
7
7
|
All of them come from hooks in `@wix/react-component-utils`, already a base
|
|
8
8
|
dependency. No additional install is needed, but the hooks require
|
|
9
9
|
`@wix/react-component-utils` ≥ 1.12.0.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Verify the installed version before using these hooks. If it is older than
|
|
12
|
+
1.12.0, report the version mismatch instead of writing code against unavailable
|
|
13
|
+
exports or silently upgrading the package.
|
|
12
14
|
|
|
13
|
-
## When
|
|
15
|
+
## Apply When
|
|
14
16
|
|
|
15
17
|
Apply only when the component genuinely needs live site context:
|
|
16
18
|
|
|
@@ -25,15 +27,24 @@ Apply only when the component genuinely needs live site context:
|
|
|
25
27
|
- **Behavior must differ inside the editor** — suppressing autoplay, network
|
|
26
28
|
calls, or timers while the site owner is designing
|
|
27
29
|
|
|
30
|
+
When behavior differs only in editor rendering, keep the main component's live
|
|
31
|
+
contract unchanged and add the editor-only gate to the generated
|
|
32
|
+
`component.preview.tsx` while preserving its wrappers.
|
|
33
|
+
|
|
28
34
|
The test is whether the site owner **authors** the data. A hook reports state the
|
|
29
35
|
owner cannot write — which page is being rendered, what the site's URL is. Data
|
|
30
36
|
the owner chooses belongs in props, even when it happens to point at site
|
|
31
|
-
pages
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
[`DIRECTIONALITY.md`](DIRECTIONALITY.md).
|
|
37
|
+
pages. Purely visual RTL needs no hook either; use logical CSS properties.
|
|
38
|
+
|
|
39
|
+
## Contents
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
- [Rules](#rules)
|
|
42
|
+
- [Read Values During Render](#read-values-during-render)
|
|
43
|
+
- [Walking the Page Tree](#walking-the-page-tree)
|
|
44
|
+
- [Building a Link to a Page](#building-a-link-to-a-page)
|
|
45
|
+
- [Direction-Dependent Logic](#direction-dependent-logic)
|
|
46
|
+
- [Avoid Direction Logic for Visual CSS](#avoid-direction-logic-for-visual-css)
|
|
47
|
+
- [Checklist](#checklist)
|
|
37
48
|
|
|
38
49
|
## Rules
|
|
39
50
|
|
|
@@ -47,8 +58,8 @@ either — use logical CSS properties, see
|
|
|
47
58
|
| `useSiteUrl()` | `string` | The site's public base URL |
|
|
48
59
|
| `useCurrentUrl()` | `string` | Full URL of the page being rendered |
|
|
49
60
|
| `useLanguageDirection()` | `'ltr' \| 'rtl'` | The site's language direction |
|
|
50
|
-
| `useIsEditMode()` | `boolean` | `true` in editor design mode
|
|
51
|
-
| `useReducedMotion()` | `boolean` | `true` when the OS requests reduced motion
|
|
61
|
+
| `useIsEditMode()` | `boolean` | `true` in editor design mode |
|
|
62
|
+
| `useReducedMotion()` | `boolean` | `true` when the OS requests reduced motion |
|
|
52
63
|
|
|
53
64
|
All import from the same place:
|
|
54
65
|
|
|
@@ -63,7 +74,7 @@ scope, inside a callback, or conditionally.
|
|
|
63
74
|
### Read Values During Render
|
|
64
75
|
|
|
65
76
|
Hook values are read on the server too, so their results are part of the server
|
|
66
|
-
markup
|
|
77
|
+
markup. Use the value directly.
|
|
67
78
|
|
|
68
79
|
**✅ Correct:**
|
|
69
80
|
|
|
@@ -79,8 +90,6 @@ const [siteUrl, setSiteUrl] = useState('');
|
|
|
79
90
|
useEffect(() => setSiteUrl(resolvedUrl), []);
|
|
80
91
|
```
|
|
81
92
|
|
|
82
|
-
---
|
|
83
|
-
|
|
84
93
|
## Patterns
|
|
85
94
|
|
|
86
95
|
### Walking the Page Tree
|
|
@@ -164,11 +173,9 @@ const onKeyDown = (event: React.KeyboardEvent) => {
|
|
|
164
173
|
};
|
|
165
174
|
```
|
|
166
175
|
|
|
167
|
-
|
|
176
|
+
## Avoid Direction Logic for Visual CSS
|
|
168
177
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Calling `useLanguageDirection()` to pick between physical CSS properties.
|
|
178
|
+
Do not call `useLanguageDirection()` to choose between physical CSS properties.
|
|
172
179
|
|
|
173
180
|
**❌ Wrong:**
|
|
174
181
|
|
|
@@ -180,8 +187,16 @@ const isRTL = useLanguageDirection() === 'rtl';
|
|
|
180
187
|
|
|
181
188
|
**✅ Correct:**
|
|
182
189
|
|
|
183
|
-
```
|
|
190
|
+
```css
|
|
184
191
|
.element {
|
|
185
|
-
padding-inline-start: 8px;
|
|
192
|
+
padding-inline-start: 8px;
|
|
186
193
|
}
|
|
187
194
|
```
|
|
195
|
+
|
|
196
|
+
## Checklist
|
|
197
|
+
|
|
198
|
+
- [ ] A hook supplies live context that cannot be represented by authored props.
|
|
199
|
+
- [ ] Hooks are called unconditionally inside a component or custom hook.
|
|
200
|
+
- [ ] Hook values are read during render rather than copied through an effect.
|
|
201
|
+
- [ ] Page-tree traversal filters popups and guards parent cycles.
|
|
202
|
+
- [ ] Direction hooks affect JavaScript behavior, not visual CSS choices.
|
|
@@ -1,119 +1,50 @@
|
|
|
1
|
-
# Server-Side Rendering
|
|
1
|
+
# Server-Side Rendering
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use this reference before introducing browser APIs, effects, time-dependent
|
|
4
|
+
output, or client-only enhancement. Editor React Components are server-rendered
|
|
5
|
+
and hydrated; the initial server and client markup must match.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
## Browser APIs
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
### No browser globals at module scope or during render
|
|
12
|
-
|
|
13
|
-
`window`, `document`, `navigator`, `localStorage`, `sessionStorage`, `matchMedia`, `IntersectionObserver`, `ResizeObserver`, and other DOM/BOM APIs do not exist on the server. Never touch them at module scope or in the render body. Access them only inside `useEffect`, optionally guarded with `typeof window !== 'undefined'`.
|
|
14
|
-
|
|
15
|
-
**❌ Wrong:**
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
const userAgent = window.navigator.userAgent;
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**✅ Correct:**
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (typeof window !== "undefined") {
|
|
26
|
-
const userAgent = window.navigator.userAgent;
|
|
27
|
-
}
|
|
28
|
-
}, []);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### First render must be complete
|
|
32
|
-
|
|
33
|
-
Render all parts unconditionally — never gate structural elements behind effect-set state. Initialize `useState` to a valid, server-renderable default so the first (server) render already shows the final structure. Element visibility is platform-managed; see [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) and [`REACT-PATTERNS.md`](REACT-PATTERNS.md) §1.2.
|
|
34
|
-
|
|
35
|
-
**❌ Wrong — content only appears after an effect runs (missing on the server):**
|
|
9
|
+
Do not access `window`, `document`, `navigator`, storage, observers, or other
|
|
10
|
+
DOM/BOM APIs at module scope or during render. Use them inside `useEffect` and
|
|
11
|
+
guard when needed.
|
|
36
12
|
|
|
37
13
|
```tsx
|
|
38
|
-
const [items, setItems] = useState<Array<Item>>([]);
|
|
39
14
|
useEffect(() => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
**✅ Correct — derive during render so it exists on the first pass:**
|
|
46
|
-
|
|
47
|
-
```tsx
|
|
48
|
-
const items = buildItems(props);
|
|
49
|
-
return <ul>{items.map(/* ... */)}</ul>;
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Deterministic render
|
|
53
|
-
|
|
54
|
-
The same props MUST produce the same markup on the server and the client. No `Math.random()`, `Date.now()`, `new Date()`, or locale/timezone-dependent output during render — these differ across environments and break hydration.
|
|
55
|
-
|
|
56
|
-
**❌ Wrong:**
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
<span>{new Date().toLocaleString()}</span>
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**✅ Correct — derive from props, or compute in an effect:**
|
|
63
|
-
|
|
64
|
-
```tsx
|
|
65
|
-
<span>{formatDate(props.timestamp)}</span>
|
|
15
|
+
if (typeof window === 'undefined') return;
|
|
16
|
+
const userAgent = window.navigator.userAgent;
|
|
17
|
+
// client-only enhancement
|
|
18
|
+
}, []);
|
|
66
19
|
```
|
|
67
20
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
When a component needs an internal id (ARIA wiring such as `aria-controls` / `aria-labelledby`, or `htmlFor`), generate it with `useStableId` from `@wix/react-component-utils`. Never use `Math.random()`, a manual counter, or a bare `React.useId()` — those break hydration or are not available across runtimes. Pass the component's `id` prop as the override so a caller-supplied id wins, then derive child ids from the result.
|
|
21
|
+
## Complete First Render
|
|
71
22
|
|
|
72
|
-
|
|
23
|
+
Derive renderable data directly from props when possible. Do not leave required
|
|
24
|
+
structure empty until an effect copies or transforms props.
|
|
73
25
|
|
|
74
26
|
```tsx
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const panelId = `${rootId}-panel`;
|
|
79
|
-
|
|
80
|
-
<button aria-controls={panelId}>{label}</button>
|
|
81
|
-
<div id={panelId} role="tabpanel">{content}</div>
|
|
27
|
+
// Correct: complete on the server and first client render.
|
|
28
|
+
const items = buildItems(props.items);
|
|
29
|
+
return <ul>{items.map(renderItem)}</ul>;
|
|
82
30
|
```
|
|
83
31
|
|
|
84
|
-
|
|
32
|
+
This does not require every data branch to render simultaneously. Empty,
|
|
33
|
+
loading, and error states may be conditional when their initial value is stable
|
|
34
|
+
and the same on server and client.
|
|
85
35
|
|
|
86
|
-
|
|
87
|
-
const panelId = `tab-${Math.random()}`; // ❌ differs every render
|
|
88
|
-
const panelId = React.useId(); // ❌ use the useStableId util instead
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### No `useLayoutEffect`
|
|
92
|
-
|
|
93
|
-
`useLayoutEffect` does nothing on the server and triggers a React warning. Use `useEffect` for client-only work.
|
|
94
|
-
|
|
95
|
-
**❌ Wrong:**
|
|
96
|
-
|
|
97
|
-
```tsx
|
|
98
|
-
useLayoutEffect(() => { measure(); }, []);
|
|
99
|
-
```
|
|
36
|
+
## Deterministic Output
|
|
100
37
|
|
|
101
|
-
|
|
38
|
+
Do not call `Math.random()`, `Date.now()`, `new Date()`, or environment-dependent
|
|
39
|
+
locale/timezone formatting during render. Use a prop, a fixed deterministic
|
|
40
|
+
format, or a client-only enhancement that does not replace the initial markup.
|
|
102
41
|
|
|
103
42
|
```tsx
|
|
104
|
-
|
|
43
|
+
<time dateTime={timestamp}>{formattedDate}</time>
|
|
105
44
|
```
|
|
106
45
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
`useEffect` runs only after hydration, never on the server. Use effects to enhance — not to produce the initial UI. The server-rendered default state must already look correct before any effect runs.
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## SSR Checklist
|
|
46
|
+
## Checklist
|
|
114
47
|
|
|
115
|
-
- [ ] No browser globals at module scope or
|
|
116
|
-
- [ ]
|
|
117
|
-
- [ ] Render output
|
|
118
|
-
- [ ] Internal ids come from `useStableId(id)`, never random values, counters, or bare `React.useId()`
|
|
119
|
-
- [ ] No `useLayoutEffect`
|
|
48
|
+
- [ ] No browser globals are accessed at module scope or during render.
|
|
49
|
+
- [ ] Initial server/client markup is complete and identical.
|
|
50
|
+
- [ ] Render output does not depend on random, clock, locale, or timezone state.
|
|
@@ -50,13 +50,13 @@ const wx = (() => { const m = { exports: {} };
|
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Results ≤ 4,000 chars come back inline (exec results clip at ~5,000); anything bigger is saved
|
|
53
|
-
under `.agents/skills/wix-base44-connector/
|
|
53
|
+
under `.agents/skills/wix-base44-connector/tmp/` and returns `{ path, bytes, lines, outline }` —
|
|
54
54
|
the outline is the map. Read a saved file the way you already know how:
|
|
55
55
|
`wx.bash("grep -n 'term' <path> | head -40")` to find (GNU grep/sed, awk is mawk, no rg;
|
|
56
|
-
across everything saved: `grep -rn 'term' .agents/skills/wix-base44-connector/
|
|
56
|
+
across everything saved: `grep -rn 'term' .agents/skills/wix-base44-connector/tmp/`), and
|
|
57
57
|
`read_file` to quote — a window via `offset`/`limit` at the lines grep named, or the whole
|
|
58
58
|
file when it fits read_file's 45K cap. **API responses are site data and never land in
|
|
59
|
-
|
|
59
|
+
never saved** — project them to facts. Fetch every URL inside exec with `fetch()` — website/browser
|
|
60
60
|
tools clip at 10,000 chars silently. One exec per round; timeout 10s, up to 120 via `{timeout}`.
|
|
61
61
|
|
|
62
62
|
## Gather context — the dynamic context report
|
|
@@ -74,13 +74,21 @@ An empty report = bad token, never an empty site.
|
|
|
74
74
|
|
|
75
75
|
```js
|
|
76
76
|
// know the product? browse is deterministic — menuUrl alone orients (children + counts);
|
|
77
|
-
// filter before listing methods
|
|
77
|
+
// filter before listing methods. browse works for both portals this skill uses — REST
|
|
78
|
+
// (api-reference) and WIX_HEADLESS (go-headless) — just pass that portal's menu URL.
|
|
78
79
|
await wx.browse("https://dev.wix.com/docs/api-reference/business-solutions/bookings/bookings",
|
|
79
80
|
{ include: ["METHOD"], filter: "resched", depth: 4 });
|
|
81
|
+
// non-REST portal — same call, that portal's menu URL:
|
|
82
|
+
await wx.browse("https://dev.wix.com/docs/go-headless/authentication", { depth: 2 });
|
|
80
83
|
|
|
81
84
|
// don't know where it lives? search ranks, never says "no match" — drop wrong-product hits
|
|
82
85
|
await wx.search("pause a pricing plan subscription and resume it");
|
|
83
86
|
// → { hits: [{ method, endpoint /* callable */, docsUrl, gist }] } — hits often ARE the answer
|
|
87
|
+
|
|
88
|
+
// { type } picks the portal (default "REST" — the HTTP APIs this skill calls). Same query,
|
|
89
|
+
// other corpus — search WIX_HEADLESS for headless/external client code (visitor auth,
|
|
90
|
+
// JS SDK, quick-starts). It returns article-style hits (method gists thin out) — read the saved path.
|
|
91
|
+
await wx.search("mint a visitor token and read the current cart", { type: "WIX_HEADLESS" });
|
|
84
92
|
```
|
|
85
93
|
|
|
86
94
|
Go deeper for fields, enums, or absence — only the spec index proves absence.
|
|
@@ -102,29 +110,39 @@ return wx.bash(`sed -n '/^## REST API/,/^## JavaScript SDK/p' ${pg.path} | grep
|
|
|
102
110
|
`search` also saves its raw content beside the inline hits — grep its `path` when a hit's six
|
|
103
111
|
lines weren't enough.
|
|
104
112
|
|
|
105
|
-
### The spec index
|
|
113
|
+
### The spec index — a located method's exact schema
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
only proof an API does NOT exist:
|
|
115
|
+
Read the schema of a method you already have a `docsUrl` for (from search/browse):
|
|
109
116
|
|
|
110
117
|
```js
|
|
111
118
|
await wx.spec(`
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
119
|
+
const url = "<docsUrl from search/browse>"; // API method page, not a skill/article page
|
|
120
|
+
const s = await getResourceSchemaByUrl(url);
|
|
121
|
+
const m = s.methods.find(x => x.docsUrl === url);
|
|
122
|
+
return {
|
|
123
|
+
call: m.publicUrl, // callable https://www.wixapis.com/… URL
|
|
124
|
+
body: m.requestBody?.content["application/json"].schema.properties,
|
|
125
|
+
responses: m.responses,
|
|
126
|
+
filterable: m.queryMethodData?.queryFieldsCapabilitiesMap // query methods
|
|
127
|
+
|| m.searchMethodData?.searchFieldsCapabilitiesMap, // search methods
|
|
128
|
+
example: m.legacyExamples?.[0]?.content,
|
|
129
|
+
};
|
|
130
|
+
// { $circular: "<name>" } types resolve via s.components.schemas["<name>"] — complete in this call
|
|
115
131
|
`);
|
|
116
|
-
// request fields next round: getResourceSchemaByUrl(docsUrl) →
|
|
117
|
-
// m.requestBody.content["application/json"].schema.properties — names and types, drill deeper
|
|
118
|
-
// per round; $circular stubs resolve via s.components.schemas["<name>"]
|
|
119
132
|
```
|
|
120
133
|
|
|
134
|
+
`filterable` maps each field to its allowed operators + sort — filter server-side only on what it
|
|
135
|
+
lists, else filter in code.
|
|
136
|
+
|
|
121
137
|
### Management recipes — check before composing admin flows
|
|
122
138
|
|
|
123
|
-
~100 curated multi-step
|
|
139
|
+
~100 curated multi-step management (admin) flows across 23 categories — the largest are
|
|
140
|
+
ecommerce (24), bookings (13), stores (9), cms (7), google-ads (7), sites (7), contacts (5),
|
|
141
|
+
then get-paid, marketing, pricing-plans, events, blog, forms, restaurants, domains, media, …:
|
|
124
142
|
|
|
125
143
|
```js
|
|
126
|
-
await wx.
|
|
127
|
-
await wx.
|
|
144
|
+
await wx.mgmtRecipes(); // categories with counts
|
|
145
|
+
await wx.mgmtRecipes("stores"); // a category's list — or any task word: wx.mgmtRecipes("coupon")
|
|
128
146
|
await wx.page(url); // read the chosen recipe — whole when small, saved + outline when
|
|
129
147
|
// big; then grep / read_file windows by the outline's line numbers
|
|
130
148
|
```
|
|
@@ -167,7 +185,6 @@ const mint = async (body) => {
|
|
|
167
185
|
};
|
|
168
186
|
// first visit: mint({ clientId: WIX_CLIENT_ID, grantType: "anonymous" });
|
|
169
187
|
// on expiry: mint({ refreshToken: sessionStorage.getItem("wixRefresh"), grantType: "refresh_token" });
|
|
170
|
-
// a fresh anonymous mint is a NEW visitor — the old one's cart goes with it
|
|
171
188
|
export const wix = (path, opts = {}) => fetch("https://www.wixapis.com" + path, { ...opts,
|
|
172
189
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" } });
|
|
173
190
|
```
|