@wix/agent-skills 1.16.0 → 1.16.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.
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +72 -8
- package/skills/wix-app/references/CODE_QUALITY.md +0 -1
- package/skills/wix-app/references/DASHBOARD_MODAL.md +21 -14
- package/skills/wix-app/references/DASHBOARD_PAGE.md +30 -184
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +19 -3
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +172 -0
- package/skills/wix-app/references/dashboard-page/WDS_LAYOUT.md +187 -0
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +12 -7
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +31 -2
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +6 -1
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +60 -0
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +6 -6
- package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +167 -0
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +2 -2
- package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +187 -0
- package/skills/wix-app/scripts/scan-a11y-code.cjs +777 -0
- package/skills/wix-app/scripts/scan-a11y-eslint.cjs +201 -0
- package/skills/wix-base44-connector/SKILL.md +185 -0
- package/skills/wix-base44-connector/scripts/utils.js +212 -0
- package/skills/wix-design-system/SKILL.md +19 -15
- package/skills/wix-docs/SKILL.md +75 -1
- package/skills/wix-headless/references/CAPABILITIES.md +16 -3
- package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
- package/skills/wix-headless/references/SEED.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +560 -102
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +210 -143
- package/skills/wix-manage/SKILL.md +20 -17
- package/skills/wix-manage/references/accessibility/scan-site-accessibility.md +98 -0
- package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +1 -2
- package/skills/wix-manage/references/domains/domain-search-purchase-and-connect.md +2603 -0
- package/skills/wix-manage/references/events/create-wix-event.md +112 -90
- package/skills/wix-manage/references/events/manage-wix-events.md +33 -94
- package/skills/wix-manage/references/sites/create-headless-site.md +1 -0
- package/skills/wix-manage/references/sites/manage-oauth-apps.md +154 -0
- package/skills/wix-manage/references/sites/read-site-context.md +125 -0
- package/skills/wix-manage/references/sites/site-import.md +67 -15
- package/skills/wix-manage/references/stores/create-product-catalog-v3.md +273 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +1 -1
- package/skills/wix-vibe-headless/SKILL.md +2 -1
- package/skills/wix-vibe-headless/install/deploy.cjs +63 -3
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +104 -0
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +74 -0
- package/skills/wix-vibe-headless/platforms/base44.md +15 -40
- package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +7 -11
- package/skills/wix-vibe-headless/references/blog/seed/SEED.md +1 -1
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +7 -11
- package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +1 -1
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +1 -2
- package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +7 -12
- package/skills/wix-vibe-headless/references/events/seed/SEED.md +1 -1
- package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +7 -11
- package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +7 -11
- package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +1 -1
- package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +7 -11
- package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +1 -1
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +7 -11
- package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +1 -1
- package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +1 -1
- package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +5 -3
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +75 -13
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +29 -86
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +3 -8
- package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +78 -105
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductCard.js +92 -0
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useVariantOptions.js +76 -0
- package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +1 -1
- package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +44 -5
- package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +0 -326
- package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +0 -115
- package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +0 -264
- package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +0 -37
- package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +0 -86
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +0 -119
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +0 -103
- package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +0 -76
- package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +0 -82
- package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +0 -89
- package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +0 -124
- package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +0 -91
- package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +0 -71
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +0 -70
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +0 -73
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +0 -98
- package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +0 -278
- package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +0 -94
- package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +0 -43
- package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +0 -66
- package/skills/wix-app/references/auto-patterns-dashboard/views.md +0 -76
- package/skills/wix-app/scripts/generate-auto-patterns.js +0 -510
- package/skills/wix-manage/references/domains/domain-search-and-purchase.md +0 -437
- package/skills/wix-manage/references/stores/create-product-from-image.md +0 -1031
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +0 -623
- package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +0 -106
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Function Event Handlers
|
|
2
|
+
|
|
3
|
+
Rules and patterns for adding function event handler props to an Editor React component's TypeScript interface, wiring them to DOM events, and declaring custom callbacks.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### Standard SDK Event Handlers
|
|
10
|
+
|
|
11
|
+
These are the standard event handler props the editor SDK exposes to site owners. Use the exact prop names — ZeroConfig and the manifest system recognize them.
|
|
12
|
+
|
|
13
|
+
| Prop name | React DOM event | Type |
|
|
14
|
+
| ------------ | --------------- | ------------------------------------------------ |
|
|
15
|
+
| `onClick` | `onClick` | `(event: React.MouseEvent) => void` |
|
|
16
|
+
| `onDblClick` | `onDoubleClick` | `(event: React.MouseEvent) => void` |
|
|
17
|
+
| `onChange` | `onChange` | `(event: React.ChangeEvent<HTMLElement>) => void` |
|
|
18
|
+
| `onFocus` | `onFocus` | `(event: React.FocusEvent) => void` |
|
|
19
|
+
| `onBlur` | `onBlur` | `(event: React.FocusEvent) => void` |
|
|
20
|
+
| `onMouseIn` | `onMouseEnter` | `(event: React.MouseEvent) => void` |
|
|
21
|
+
| `onMouseOut` | `onMouseLeave` | `(event: React.MouseEvent) => void` |
|
|
22
|
+
|
|
23
|
+
Three props have a **name mismatch** between the SDK prop and the DOM event: `onDblClick` → `onDoubleClick`, `onMouseIn` → `onMouseEnter`, `onMouseOut` → `onMouseLeave`.
|
|
24
|
+
|
|
25
|
+
### Declaring Standard Handler Props
|
|
26
|
+
|
|
27
|
+
Declare standard handlers inline with the exact SDK prop names and React event types:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
interface MyComponentProps {
|
|
31
|
+
label?: string;
|
|
32
|
+
onClick?: (event: React.MouseEvent) => void;
|
|
33
|
+
onDblClick?: (event: React.MouseEvent) => void;
|
|
34
|
+
onChange?: (event: React.ChangeEvent<HTMLElement>) => void;
|
|
35
|
+
onFocus?: (event: React.FocusEvent) => void;
|
|
36
|
+
onBlur?: (event: React.FocusEvent) => void;
|
|
37
|
+
onMouseIn?: (event: React.MouseEvent) => void;
|
|
38
|
+
onMouseOut?: (event: React.MouseEvent) => void;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Only declare handlers the component actually exposes. Do not add all seven if the component only handles two.
|
|
43
|
+
|
|
44
|
+
### Wiring Standard Handlers to DOM Events
|
|
45
|
+
|
|
46
|
+
Destructure the props and pass them to the correct DOM event — applying the name mappings:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
export const MyComponent = (props: MyComponentProps) => {
|
|
50
|
+
const { onClick, onDblClick, onFocus, onBlur, onMouseIn, onMouseOut } = props;
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
onClick={onClick}
|
|
54
|
+
onDoubleClick={onDblClick}
|
|
55
|
+
onFocus={onFocus}
|
|
56
|
+
onBlur={onBlur}
|
|
57
|
+
onMouseEnter={onMouseIn}
|
|
58
|
+
onMouseLeave={onMouseOut}
|
|
59
|
+
>
|
|
60
|
+
{/* ... */}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Custom Callbacks
|
|
67
|
+
|
|
68
|
+
Component-specific callbacks that do not correspond to a DOM event (e.g., `onPlay`, `onPause`, `onEnded`, `onTimeupdate`) are **not** standard SDK event handlers. Type them as `() => void` — no React event parameter:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface VideoPlayerProps {
|
|
72
|
+
onPlay?: () => void;
|
|
73
|
+
onPause?: () => void;
|
|
74
|
+
onEnded?: () => void;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Pass them directly to the underlying element — no name remapping needed:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
export const VideoPlayer = (props: VideoPlayerProps) => {
|
|
82
|
+
const { onPlay, onPause, onEnded } = props;
|
|
83
|
+
return <video onPlay={onPlay} onPause={onPause} onEnded={onEnded} />;
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Common Mistakes
|
|
90
|
+
|
|
91
|
+
### Passing SDK prop name directly to DOM instead of remapping
|
|
92
|
+
|
|
93
|
+
**❌ Wrong:**
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
export const MyComponent = (props: MyComponentProps) => {
|
|
97
|
+
const { onMouseIn, onMouseOut, onDblClick } = props;
|
|
98
|
+
return (
|
|
99
|
+
<div
|
|
100
|
+
onMouseIn={onMouseIn} // ❌ not a valid React DOM prop
|
|
101
|
+
onMouseOut={onMouseOut} // ❌ not a valid React DOM prop
|
|
102
|
+
onDblClick={onDblClick} // ❌ not a valid React DOM prop
|
|
103
|
+
/>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**✅ Correct:**
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
export const MyComponent = (props: MyComponentProps) => {
|
|
112
|
+
const { onMouseIn, onMouseOut, onDblClick } = props;
|
|
113
|
+
return (
|
|
114
|
+
<div
|
|
115
|
+
onMouseEnter={onMouseIn} // ✅ onMouseIn → onMouseEnter
|
|
116
|
+
onMouseLeave={onMouseOut} // ✅ onMouseOut → onMouseLeave
|
|
117
|
+
onDoubleClick={onDblClick} // ✅ onDblClick → onDoubleClick
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Adding a React event parameter to custom callbacks
|
|
124
|
+
|
|
125
|
+
**❌ Wrong:**
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
interface VideoPlayerProps {
|
|
129
|
+
onPlay?: (event: React.SyntheticEvent) => void; // ❌ event param on custom callback
|
|
130
|
+
onEnded?: (event: React.SyntheticEvent) => void; // ❌ event param on custom callback
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**✅ Correct:**
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
interface VideoPlayerProps {
|
|
138
|
+
onPlay?: () => void; // ✅ no event param
|
|
139
|
+
onEnded?: () => void; // ✅ no event param
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Why:** Custom callbacks are component-level notifications to the site owner, not DOM event forwarders. They carry no event object — the SDK passes no event to them.
|
|
144
|
+
|
|
145
|
+
### Using the DOM event name as the SDK prop name
|
|
146
|
+
|
|
147
|
+
**❌ Wrong:**
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
interface MyComponentProps {
|
|
151
|
+
onDoubleClick?: (event: React.MouseEvent) => void; // ❌ DOM name, not SDK name
|
|
152
|
+
onMouseEnter?: (event: React.MouseEvent) => void; // ❌ DOM name, not SDK name
|
|
153
|
+
onMouseLeave?: (event: React.MouseEvent) => void; // ❌ DOM name, not SDK name
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**✅ Correct:**
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
interface MyComponentProps {
|
|
161
|
+
onDblClick?: (event: React.MouseEvent) => void; // ✅ SDK prop name
|
|
162
|
+
onMouseIn?: (event: React.MouseEvent) => void; // ✅ SDK prop name
|
|
163
|
+
onMouseOut?: (event: React.MouseEvent) => void; // ✅ SDK prop name
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Why:** The SDK prop names (`onDblClick`, `onMouseIn`, `onMouseOut`) are what ZeroConfig and the manifest system register. Using DOM names breaks the editor's event wiring.
|
|
@@ -9,6 +9,7 @@ This guide defines rules and guidance on **how to implement** production-quality
|
|
|
9
9
|
- [`DIRECTIONALITY.md`](DIRECTIONALITY.md) — RTL/LTR rules and patterns
|
|
10
10
|
- [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) — What should be a React prop vs CSS
|
|
11
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
|
|
12
13
|
- [`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md) — Play/pause control and autoplay for animated/playable components
|
|
13
14
|
- [`REACT-PATTERNS.md`](REACT-PATTERNS.md) — SSR-safe patterns, CSS rules, common mistakes
|
|
14
15
|
|
|
@@ -110,7 +111,7 @@ Unless explicitly specified as a component capability/API in the specification,
|
|
|
110
111
|
**External handlers (only when specified):**
|
|
111
112
|
|
|
112
113
|
- Only expose handlers that are explicitly listed as component capabilities
|
|
113
|
-
-
|
|
114
|
+
- Use the standard SDK prop names and DOM wiring rules from [`FUNCTION-HANDLERS.md`](FUNCTION-HANDLERS.md)
|
|
114
115
|
|
|
115
116
|
**Child component handlers:**
|
|
116
117
|
|
|
@@ -170,4 +171,3 @@ See [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) and [`COMPONENT-API.md`](COMPONENT-API.
|
|
|
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))
|
|
171
172
|
|
|
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.
|
|
173
|
-
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Site Context Hooks
|
|
2
|
+
|
|
3
|
+
Rules and patterns for reading **runtime site context** in Editor React
|
|
4
|
+
components — the site's page tree, the current URL, the language direction, and
|
|
5
|
+
editor mode. None of these can be carried by a prop.
|
|
6
|
+
|
|
7
|
+
All of them come from hooks in `@wix/react-component-utils`, already a base
|
|
8
|
+
dependency. No additional install is needed, but the hooks require
|
|
9
|
+
`@wix/react-component-utils` ≥ 1.12.0.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## When this applies
|
|
14
|
+
|
|
15
|
+
Apply only when the component genuinely needs live site context:
|
|
16
|
+
|
|
17
|
+
- **The component reflects where the visitor is in the site** — breadcrumbs,
|
|
18
|
+
"you are here" indicators. Not navigation menus: the site owner authors those,
|
|
19
|
+
and their items need not necessarily be site pages, so they take a
|
|
20
|
+
`MenuItems` prop
|
|
21
|
+
- **The component needs the page's own URL** — share buttons, copy-link,
|
|
22
|
+
canonical links, QR codes
|
|
23
|
+
- **Language direction drives JavaScript** — keyboard navigation, transform or
|
|
24
|
+
animation math, conditional rendering
|
|
25
|
+
- **Behavior must differ inside the editor** — suppressing autoplay, network
|
|
26
|
+
calls, or timers while the site owner is designing
|
|
27
|
+
|
|
28
|
+
The test is whether the site owner **authors** the data. A hook reports state the
|
|
29
|
+
owner cannot write — which page is being rendered, what the site's URL is. Data
|
|
30
|
+
the owner chooses belongs in props, even when it happens to point at site
|
|
31
|
+
pages — see [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) and
|
|
32
|
+
[`COMPONENT-API.md`](COMPONENT-API.md). Purely visual RTL needs no hook
|
|
33
|
+
either — use logical CSS properties, see
|
|
34
|
+
[`DIRECTIONALITY.md`](DIRECTIONALITY.md).
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Rules
|
|
39
|
+
|
|
40
|
+
### The Available Hooks
|
|
41
|
+
|
|
42
|
+
| Hook | Returns | Use for |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| `usePages()` | `Readonly<Record<string, PageConfig>>` | Every page on the site, keyed by page id |
|
|
45
|
+
| `useCurrentPageId()` | `string` | Id of the page being rendered |
|
|
46
|
+
| `useMainPageId()` | `string` | Id of the site's homepage |
|
|
47
|
+
| `useSiteUrl()` | `string` | The site's public base URL |
|
|
48
|
+
| `useCurrentUrl()` | `string` | Full URL of the page being rendered |
|
|
49
|
+
| `useLanguageDirection()` | `'ltr' \| 'rtl'` | The site's language direction |
|
|
50
|
+
| `useIsEditMode()` | `boolean` | `true` in editor design mode — see [`COMPONENT-PREVIEW.md`](COMPONENT-PREVIEW.md) |
|
|
51
|
+
| `useReducedMotion()` | `boolean` | `true` when the OS requests reduced motion — see [`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md) |
|
|
52
|
+
|
|
53
|
+
All import from the same place:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { usePages, useCurrentPageId, useSiteUrl } from '@wix/react-component-utils';
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Each returns a plain value, so there is nothing to unwrap or guard. They are
|
|
60
|
+
React hooks — call them at the top of the component or hook body, never at module
|
|
61
|
+
scope, inside a callback, or conditionally.
|
|
62
|
+
|
|
63
|
+
### Read Values During Render
|
|
64
|
+
|
|
65
|
+
Hook values are read on the server too, so their results are part of the server
|
|
66
|
+
markup — see [`SSR.md`](SSR.md). Use the value directly.
|
|
67
|
+
|
|
68
|
+
**✅ Correct:**
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
const siteUrl = useSiteUrl();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**❌ Wrong — empty on the server, then a hydration mismatch:**
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
const resolvedUrl = useSiteUrl();
|
|
78
|
+
const [siteUrl, setSiteUrl] = useState('');
|
|
79
|
+
useEffect(() => setSiteUrl(resolvedUrl), []);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Patterns
|
|
85
|
+
|
|
86
|
+
### Walking the Page Tree
|
|
87
|
+
|
|
88
|
+
`usePages()` returns a map keyed by page id. Three things to get right:
|
|
89
|
+
|
|
90
|
+
- **The map key is the page id** — the values carry no `id` field.
|
|
91
|
+
- **`parentPageId` is absent for top-level pages** — treat those as children of
|
|
92
|
+
`useMainPageId()` when walking upward.
|
|
93
|
+
- **`popup: true` pages are lightboxes**, not navigable pages. Filter them out of
|
|
94
|
+
breadcrumbs, menus, and page pickers.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { usePages, useCurrentPageId, useMainPageId } from '@wix/react-component-utils';
|
|
98
|
+
|
|
99
|
+
export const useBreadcrumbTrail = (): Array<{ id: string; label: string }> => {
|
|
100
|
+
const pages = usePages();
|
|
101
|
+
const currentPageId = useCurrentPageId();
|
|
102
|
+
const mainPageId = useMainPageId();
|
|
103
|
+
|
|
104
|
+
const trail: Array<{ id: string; label: string }> = [];
|
|
105
|
+
const visited = new Set<string>();
|
|
106
|
+
let pageId: string | undefined = currentPageId;
|
|
107
|
+
|
|
108
|
+
while (pageId && !visited.has(pageId) && pages[pageId]) {
|
|
109
|
+
visited.add(pageId);
|
|
110
|
+
const page = pages[pageId]!;
|
|
111
|
+
if (!page.popup) {
|
|
112
|
+
trail.push({ id: pageId, label: page.title });
|
|
113
|
+
}
|
|
114
|
+
// Pages without parentPageId are top-level children of the homepage.
|
|
115
|
+
pageId = pageId === mainPageId ? undefined : (page.parentPageId ?? mainPageId);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return trail.reverse();
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The `visited` set is not optional — a misconfigured site can produce a parent
|
|
123
|
+
cycle, and an unguarded walk hangs the render.
|
|
124
|
+
|
|
125
|
+
### Building a Link to a Page
|
|
126
|
+
|
|
127
|
+
Join a page's `path` onto `useSiteUrl()`. The base URL may or may not carry a
|
|
128
|
+
trailing slash, so normalize before joining:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const buildPageUrl = (path: string, siteUrl: string): string => {
|
|
132
|
+
const base = siteUrl.replace(/\/$/, '');
|
|
133
|
+
return path ? `${base}/${path}` : base;
|
|
134
|
+
};
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Direction-Dependent Logic
|
|
138
|
+
|
|
139
|
+
Resolve the component's own `direction` prop first, then fall back to the site:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import type { Direction } from '@wix/editor-react-types';
|
|
143
|
+
import { useLanguageDirection } from '@wix/react-component-utils';
|
|
144
|
+
|
|
145
|
+
export const useResolvedDirection = (direction?: Direction): Direction => {
|
|
146
|
+
// Call unconditionally — `direction ?? useLanguageDirection()` would
|
|
147
|
+
// short-circuit and skip the hook whenever the prop is set.
|
|
148
|
+
const siteDirection = useLanguageDirection() as Direction;
|
|
149
|
+
return direction ?? siteDirection;
|
|
150
|
+
};
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Use the resolved value for **logic only** — arrow-key handling, transform sign,
|
|
154
|
+
scroll direction:
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
const isRTL = useResolvedDirection(direction) === 'rtl';
|
|
158
|
+
|
|
159
|
+
const onKeyDown = (event: React.KeyboardEvent) => {
|
|
160
|
+
const forward = isRTL ? 'ArrowLeft' : 'ArrowRight';
|
|
161
|
+
if (event.key === forward) {
|
|
162
|
+
focusNext();
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Common Mistake: Direction Logic Instead of Logical CSS
|
|
170
|
+
|
|
171
|
+
Calling `useLanguageDirection()` to pick between physical CSS properties.
|
|
172
|
+
|
|
173
|
+
**❌ Wrong:**
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
const isRTL = useLanguageDirection() === 'rtl';
|
|
177
|
+
|
|
178
|
+
<div style={{ paddingLeft: isRTL ? 0 : 8, paddingRight: isRTL ? 8 : 0 }} />
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**✅ Correct:**
|
|
182
|
+
|
|
183
|
+
```scss
|
|
184
|
+
.element {
|
|
185
|
+
padding-inline-start: 8px; // Auto RTL/LTR, no hook needed
|
|
186
|
+
}
|
|
187
|
+
```
|