@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,39 +1,63 @@
|
|
|
1
1
|
# Design States
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
(`
|
|
6
|
-
|
|
3
|
+
Use this reference when a named part changes appearance through interaction or
|
|
4
|
+
a selectable value. A design state styles an element differently for an
|
|
5
|
+
eligible interaction (`hover`, `focus`, `disabled`, `invalid`) or per a
|
|
6
|
+
selectable value in its data (`selected`, `active`, `open`, …). Author states
|
|
7
|
+
in the component's `.tsx` and `.module.css`.
|
|
7
8
|
|
|
8
|
-
##
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
- [Choose Supported States](#1-choose-supported-states)
|
|
12
|
+
- [Name the State Class](#2-name-the-state-class)
|
|
13
|
+
- [Author CSS](#3-author-css)
|
|
14
|
+
- [Wire React](#4-wire-react)
|
|
15
|
+
- [Use Prop-Triggered States on the Root Only](#5-use-prop-triggered-states-on-the-root-only)
|
|
16
|
+
- [Checklist](#checklist)
|
|
17
|
+
|
|
18
|
+
## 1. Choose Supported States
|
|
9
19
|
|
|
10
20
|
| Element | Author these states |
|
|
11
21
|
|---|---|
|
|
12
|
-
| Interactive — `button`/`a`/`input`/`select`/`textarea`/`summary`, an interactive `role
|
|
22
|
+
| Interactive — `button`/`a`/`input`/`select`/`textarea`/`summary`, an interactive `role`, or an interactive handler (`onClick`/`onMouseEnter`/`onFocus`/…) | `hover` |
|
|
23
|
+
| Input field — `select`/`textarea`; `input` except `hidden`/`button`/`submit`/`reset`/`image`; or an input-widget `role` (`checkbox`/`radio`/`switch`/`slider`/`spinbutton`/`textbox`/`searchbox`/`combobox`/`listbox`) | `focus` |
|
|
24
|
+
| Other interactive element whose editable focus appearance the user explicitly requests | `focus` |
|
|
13
25
|
| Disableable — `button`/`input`/`select`/`textarea`/`fieldset` or a disableable role | `disabled` (+ `invalid` for `input`/`select`/`textarea`) |
|
|
14
26
|
| Has a selectable/variant value in its data — `selected`/`active`/`current`/`open`/`expanded`/`checked`/`featured` | that custom state |
|
|
15
27
|
| None of the above | no states — resting style only |
|
|
16
28
|
|
|
29
|
+
An explicit `role` overrides the tag's implicit semantics: `<input role="button">`
|
|
30
|
+
is a non-input control, while `<div role="checkbox">` is an input field.
|
|
31
|
+
|
|
32
|
+
A `focus` design state is an editor styling control, not the keyboard focus
|
|
33
|
+
indicator itself. Do not add a global `--focus` modifier to a non-input control
|
|
34
|
+
unless the user explicitly requests editable focus styling. A control that
|
|
35
|
+
restyles its own outline, background, or border must still carry a standalone
|
|
36
|
+
`:focus-visible` rule as its keyboard affordance.
|
|
37
|
+
|
|
17
38
|
A custom state may also be driven by a root-level boolean prop (e.g.
|
|
18
|
-
`isFeatured`) instead of by markup or item data — see §5.
|
|
39
|
+
`isFeatured`) instead of by markup or item data — see §5. For an active-item
|
|
40
|
+
component, drive each item's `--active` class by comparing its index with the
|
|
41
|
+
active-index prop rather than storing a per-item boolean.
|
|
19
42
|
|
|
20
|
-
## 2. Name the
|
|
43
|
+
## 2. Name the State Class
|
|
21
44
|
|
|
22
45
|
Flat: the element's own global class + `--<state>`. Because inner-part
|
|
23
|
-
global classes are prefixed with the component name
|
|
24
|
-
[`CSS-GUIDELINES.md`](CSS-GUIDELINES.md)), the state class is prefixed too —
|
|
46
|
+
global classes are prefixed with the component name, the state class is prefixed too —
|
|
25
47
|
e.g. `pricing-card-cta--hover`, `pricing-card-plan-row--selected`. Never bare
|
|
26
48
|
(`cta--hover` would collide with other components on the page) and never
|
|
27
49
|
nested (`card__row--selected`).
|
|
28
50
|
|
|
29
|
-
## 3. CSS
|
|
51
|
+
## 3. Author CSS
|
|
30
52
|
|
|
31
53
|
Put the resting value in the bare class; put only the state override in the
|
|
32
54
|
state selector.
|
|
33
55
|
|
|
34
|
-
- **Native** — pair the pseudo-class with the `:global` modifier.
|
|
35
|
-
state needs both selectors in the same rule; do not
|
|
36
|
-
|
|
56
|
+
- **Native design state** — pair the pseudo-class with the `:global` modifier.
|
|
57
|
+
Every exposed native state needs both selectors in the same rule; do not
|
|
58
|
+
split the pair across states. A standalone `:focus-visible` accessibility
|
|
59
|
+
rule on a non-input control is not an editor design state and has no global
|
|
60
|
+
modifier.
|
|
37
61
|
- **Custom** — the `:global` modifier alone.
|
|
38
62
|
|
|
39
63
|
The bare selector is the short **module** class (`.cta`); the `:global(...)`
|
|
@@ -51,15 +75,19 @@ state class is the **prefixed** global one.
|
|
|
51
75
|
.cta:disabled {
|
|
52
76
|
opacity: 0.5;
|
|
53
77
|
}
|
|
78
|
+
.cta:focus-visible {
|
|
79
|
+
outline: 2px solid currentColor;
|
|
80
|
+
} /* keyboard indicator only; not an editor design state */
|
|
54
81
|
.plan-row:global(.pricing-card-plan-row--selected) {
|
|
55
82
|
border-color: #6366f1;
|
|
56
83
|
}
|
|
57
84
|
```
|
|
58
85
|
|
|
59
|
-
## 4. React
|
|
86
|
+
## 4. Wire React
|
|
60
87
|
|
|
61
88
|
- **Native** — render the correct interactive element (`<button>`, an
|
|
62
|
-
interactive `role`, or a handler).
|
|
89
|
+
interactive `role`, or a handler). No custom state class is needed, but the
|
|
90
|
+
element must still satisfy the accessibility contract for its semantics.
|
|
63
91
|
- **Custom** — toggle the global state class from the element's data.
|
|
64
92
|
- **Inner elements** — every named inner element gets an `elementProps` entry;
|
|
65
93
|
spread it so editor-driven states reach it. On a raw HTML element also merge
|
|
@@ -67,7 +95,8 @@ state class is the **prefixed** global one.
|
|
|
67
95
|
spread alone suffices (it merges `className` itself). The `elementProps` key
|
|
68
96
|
stays the **short** part name (`cta`) even though the element's global class
|
|
69
97
|
is prefixed (`pricing-card-cta`) — don't rename the key to match the class.
|
|
70
|
-
|
|
98
|
+
|
|
99
|
+
Wire native and custom states as follows:
|
|
71
100
|
|
|
72
101
|
```tsx
|
|
73
102
|
<button
|
|
@@ -78,12 +107,20 @@ state class is the **prefixed** global one.
|
|
|
78
107
|
{label}
|
|
79
108
|
</button>
|
|
80
109
|
|
|
81
|
-
<li
|
|
110
|
+
<li
|
|
111
|
+
{...elementProps?.planRow}
|
|
112
|
+
className={classNames(
|
|
113
|
+
'pricing-card-plan-row',
|
|
114
|
+
styles.planRow,
|
|
115
|
+
row.selected && 'pricing-card-plan-row--selected',
|
|
116
|
+
elementProps?.planRow?.className,
|
|
117
|
+
)}
|
|
118
|
+
>
|
|
82
119
|
{row.label}
|
|
83
120
|
</li>
|
|
84
121
|
```
|
|
85
122
|
|
|
86
|
-
## 5. Prop-
|
|
123
|
+
## 5. Use Prop-Triggered States on the Root Only
|
|
87
124
|
|
|
88
125
|
A **prop-triggered** state is a custom state switched by a single boolean
|
|
89
126
|
**prop**, rather than by interactive markup (native) or a per-item data flag
|
|
@@ -127,3 +164,13 @@ Rules:
|
|
|
127
164
|
Prefer a native state (interactive markup) or a class trigger (per-item data
|
|
128
165
|
such as `row.selected`) whenever one fits — those are the common cases and work
|
|
129
166
|
at any depth. Reach for a prop trigger only for a root-level boolean switch.
|
|
167
|
+
|
|
168
|
+
## Checklist
|
|
169
|
+
|
|
170
|
+
- [ ] Each named part declares only states its semantics or data supports.
|
|
171
|
+
- [ ] Eligible native design-state selectors pair the pseudo-class with the
|
|
172
|
+
prefixed global modifier.
|
|
173
|
+
- [ ] Non-input controls retain a standalone `:focus-visible` keyboard indicator.
|
|
174
|
+
- [ ] Custom state classes are flat, global, and prefixed by component and part.
|
|
175
|
+
- [ ] Named inner parts spread and merge their `elementProps` entry.
|
|
176
|
+
- [ ] `ElementState<boolean>` is used only for a component-level root state.
|
|
@@ -1,187 +1,82 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Directionality (RTL/LTR)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use these rules for component direction, logical layout, nested content, and
|
|
4
|
+
direction-dependent JavaScript.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## Contents
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
- [Root Contract](#root-contract)
|
|
9
|
+
- [Logical CSS](#logical-css)
|
|
10
|
+
- [Direction-Dependent Transforms](#direction-dependent-transforms)
|
|
11
|
+
- [Direction-Dependent JavaScript](#direction-dependent-javascript)
|
|
12
|
+
- [Nested `ReactNode` Content](#nested-reactnode-content)
|
|
13
|
+
- [Checklist](#checklist)
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
## Root Contract
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
Every component accepts `direction?: Direction`. Put `dir={direction}` and the
|
|
18
|
+
fallback class on the elected root; do not add a wrapper for them. Apply the
|
|
19
|
+
fallback class unconditionally so it works whenever `dir` is absent. Preserve
|
|
20
|
+
the scaffolded `dir`, root class, and `.fallbackDirection:not([dir])` wiring;
|
|
21
|
+
the generated component already demonstrates this contract.
|
|
12
22
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
- Sub-component directions only applied when explicitly set (to override inherited direction)
|
|
18
|
-
- When undefined: inherits direction from parent via CSS inheritance
|
|
19
|
-
- Root component always gets fallback class
|
|
20
|
-
|
|
21
|
-
### Direction Anti-Patterns
|
|
22
|
-
|
|
23
|
-
```scss
|
|
24
|
-
/* ❌ Don't use CSS variables for direction */
|
|
25
|
-
.component { direction: var(--component-direction, ltr); }
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
/* ❌ Don't use conditional logic for fallback class */
|
|
30
|
-
className={classNames({
|
|
31
|
-
[styles.fallbackDirection]: !direction
|
|
32
|
-
})}
|
|
33
|
-
```
|
|
23
|
+
Do not set fallback direction with a React condition or a custom direction CSS
|
|
24
|
+
variable.
|
|
34
25
|
|
|
35
|
-
|
|
26
|
+
## Logical CSS
|
|
36
27
|
|
|
37
|
-
Use logical
|
|
28
|
+
Use logical inline-axis properties instead of physical left/right properties:
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Apply on main component only. `dir` and the fallback class go on whatever element is the root — never add a wrapper `<div>` to host them (see [`PARTS.md`](PARTS.md) Step 0).
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
<div
|
|
49
|
-
id={id}
|
|
50
|
-
dir={direction}
|
|
51
|
-
className={classNames(
|
|
52
|
-
'profile-card',
|
|
53
|
-
styles.root,
|
|
54
|
-
className,
|
|
55
|
-
styles.fallbackDirection,
|
|
56
|
-
)}
|
|
57
|
-
>
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
/* Root is the component's own semantic element — same attribute, same classes */
|
|
62
|
-
<button
|
|
63
|
-
type="button"
|
|
64
|
-
id={id}
|
|
65
|
-
dir={direction}
|
|
66
|
-
className={classNames(
|
|
67
|
-
'like-button',
|
|
68
|
-
styles.root,
|
|
69
|
-
className,
|
|
70
|
-
styles.fallbackDirection,
|
|
71
|
-
)}
|
|
72
|
-
>
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
```scss
|
|
76
|
-
.fallbackDirection:not([dir]) {
|
|
77
|
-
direction: var(--wix-opt-in-direction);
|
|
30
|
+
```css
|
|
31
|
+
.element {
|
|
32
|
+
inset-inline-start: 0;
|
|
33
|
+
padding-inline-start: 8px;
|
|
34
|
+
margin-inline-end: 4px;
|
|
35
|
+
border-inline-end: 1px solid currentColor;
|
|
78
36
|
}
|
|
79
37
|
```
|
|
80
38
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import type { Direction } from '@wix/editor-react-types';
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Child Element Direction
|
|
88
|
-
|
|
89
|
-
Only when explicitly specified:
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
const labelDirection = elementProps?.label?.direction;
|
|
93
|
-
|
|
94
|
-
<span
|
|
95
|
-
dir={labelDirection}
|
|
96
|
-
>
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Runtime Direction Checking
|
|
100
|
-
|
|
101
|
-
**Site direction hook:**
|
|
102
|
-
|
|
103
|
-
Use the hook **only** when direction drives JavaScript behavior (keyboard navigation, animation logic, conditional rendering). For purely visual RTL, use logical CSS properties instead — see below.
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
import { useLanguageDirection } from '@wix/react-component-utils';
|
|
107
|
-
|
|
108
|
-
const siteDirection = useLanguageDirection();
|
|
109
|
-
const isRTL = siteDirection === 'rtl';
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
See [`SITE-CONTEXT-HOOKS.md`](SITE-CONTEXT-HOOKS.md) for the full set of site context hooks.
|
|
39
|
+
Block-axis properties such as `top`, `bottom`, and `padding-block` do not need
|
|
40
|
+
directional conversion.
|
|
113
41
|
|
|
114
|
-
|
|
42
|
+
## Direction-Dependent Transforms
|
|
115
43
|
|
|
116
|
-
|
|
117
|
-
const isRTL = (direction || parentDirection || siteDirection) === 'rtl';
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
**CSS Variable**
|
|
44
|
+
For directional transforms, use the platform multiplier:
|
|
121
45
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```scss
|
|
125
|
-
.scrollButton {
|
|
46
|
+
```css
|
|
47
|
+
.arrow {
|
|
126
48
|
scale: var(--wix-opt-in-direction-multiplier, 1) 1;
|
|
127
49
|
}
|
|
128
50
|
```
|
|
129
51
|
|
|
130
|
-
|
|
52
|
+
## Direction-Dependent JavaScript
|
|
131
53
|
|
|
132
|
-
|
|
54
|
+
Use `useLanguageDirection()` only when direction changes JavaScript behavior,
|
|
55
|
+
such as arrow-key order, scroll math, animation direction, or conditional
|
|
56
|
+
rendering. Purely visual direction belongs in logical CSS.
|
|
133
57
|
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
inset-inline-start: 0; // Instead of left
|
|
137
|
-
inset-inline-end: 0; // Instead of right
|
|
138
|
-
padding-inline-start: 8px; // Instead of padding-left
|
|
139
|
-
margin-inline-end: 4px; // Instead of margin-right
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**❌ Wrong:**
|
|
58
|
+
```tsx
|
|
59
|
+
import { useLanguageDirection } from '@wix/react-component-utils';
|
|
144
60
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
[dir='rtl'] & {
|
|
149
|
-
padding-right: 8px; // Manual RTL - avoid
|
|
150
|
-
}
|
|
151
|
-
}
|
|
61
|
+
const siteDirection = useLanguageDirection();
|
|
62
|
+
const resolvedDirection = direction ?? siteDirection;
|
|
63
|
+
const isRtl = resolvedDirection === 'rtl';
|
|
152
64
|
```
|
|
153
65
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Common Mistake: Manual RTL Handling
|
|
159
|
-
|
|
160
|
-
**❌ Wrong:**
|
|
161
|
-
|
|
162
|
-
```scss
|
|
163
|
-
.element {
|
|
164
|
-
padding-left: 8px;
|
|
165
|
-
[dir='rtl'] & {
|
|
166
|
-
padding-right: 8px; // Manual overrides
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
66
|
+
## Nested `ReactNode` Content
|
|
170
67
|
|
|
171
|
-
|
|
68
|
+
Put `dir="ltr"` on the element that renders a `ReactNode` content prop. This
|
|
69
|
+
isolates arbitrary nested content from the parent component's direction so each
|
|
70
|
+
nested component can resolve its own contract.
|
|
172
71
|
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
padding-inline-start: 8px; // Auto RTL/LTR
|
|
176
|
-
}
|
|
72
|
+
```tsx
|
|
73
|
+
<div dir="ltr">{item.content}</div>
|
|
177
74
|
```
|
|
178
75
|
|
|
179
|
-
##
|
|
76
|
+
## Checklist
|
|
180
77
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
</Accordion.Content>
|
|
187
|
-
```
|
|
78
|
+
- [ ] Root props include `direction?: Direction`.
|
|
79
|
+
- [ ] The elected root has `dir={direction}` and the unconditional fallback class.
|
|
80
|
+
- [ ] Direction-sensitive CSS uses logical properties.
|
|
81
|
+
- [ ] Runtime direction hooks are used only for JavaScript behavior.
|
|
82
|
+
- [ ] Every `ReactNode` content slot renders under `dir="ltr"`.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Editor Extension Configuration
|
|
2
|
+
|
|
3
|
+
Use this reference to edit `<component-name>.extension.ts` after scaffolding and
|
|
4
|
+
before the final build. Preserve the scaffold's generated editor element,
|
|
5
|
+
client and editor resources, merge order, and defaults wiring. Manifest
|
|
6
|
+
generation rewrites
|
|
7
|
+
`<component-name>.generated.ts`; it does not rewrite the extension file.
|
|
8
|
+
|
|
9
|
+
For a new component, complete the scaffolded installation and layout fields.
|
|
10
|
+
For an existing component, change only the sizing, installation, or manifest
|
|
11
|
+
behavior requested by the user; preserve every other extension field.
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- [Preserve the Extension Shape](#preserve-the-extension-shape)
|
|
16
|
+
- [Choose Initial Height](#choose-initial-height)
|
|
17
|
+
- [Choose Resize Direction](#choose-resize-direction)
|
|
18
|
+
- [Checklist](#checklist)
|
|
19
|
+
|
|
20
|
+
## Preserve the Extension Shape
|
|
21
|
+
|
|
22
|
+
For a new component, the extension should continue to:
|
|
23
|
+
|
|
24
|
+
- import `editorElement` from `<component-name>.generated.ts`
|
|
25
|
+
- load `component.tsx?url` for the client and `component.preview.tsx?url` for
|
|
26
|
+
the editor
|
|
27
|
+
- apply `defaultProps` from `<component-name>.props.ts` through
|
|
28
|
+
`withEditorElementDefaults`
|
|
29
|
+
- merge layout overrides into the editor element after applying defaults
|
|
30
|
+
|
|
31
|
+
For an existing component, preserve its generated export shape. Older
|
|
32
|
+
extensions may import and spread `manifest.editorElement` and
|
|
33
|
+
`manifest.resources`; do not migrate that wiring during an unrelated edit.
|
|
34
|
+
|
|
35
|
+
Preserve the generated `defaultProps` import from `./<component-name>.props`.
|
|
36
|
+
That file remains the single source of truth.
|
|
37
|
+
|
|
38
|
+
## Choose Initial Height
|
|
39
|
+
|
|
40
|
+
Determine from the component contract whether its own content decides its
|
|
41
|
+
height. Ask the user only when the requested behavior leaves this materially
|
|
42
|
+
ambiguous.
|
|
43
|
+
|
|
44
|
+
| Answer | Sizing type |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| Text or nested content should grow the component | `LAYOUT.SIZING_TYPE.content`; omit `pixels` |
|
|
47
|
+
| The component is a framed visual/control with a natural fixed height | `LAYOUT.SIZING_TYPE.pixels`; provide `pixels` |
|
|
48
|
+
|
|
49
|
+
Tiebreaker: if a designer should drag a height handle, use `pixels`; if height
|
|
50
|
+
should fit content, use `content`.
|
|
51
|
+
|
|
52
|
+
## Choose Resize Direction
|
|
53
|
+
|
|
54
|
+
Allow an axis only when dragging it produces a meaningful result.
|
|
55
|
+
|
|
56
|
+
| Value | Use when |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `horizontalAndVertical` | Content meaningfully fills both axes; default for framed visuals and most layouts |
|
|
59
|
+
| `horizontal` | Height is intrinsic or intentionally rigid |
|
|
60
|
+
| `vertical` | Width is intrinsic or intentionally rigid |
|
|
61
|
+
| `aspectRatio` | Distortion would break the component's identity |
|
|
62
|
+
| `none` | A parent fully owns size; do not use for a top-level component |
|
|
63
|
+
|
|
64
|
+
Edit the scaffolded `layout`, `installation`, and `resources` fields in place;
|
|
65
|
+
do not reconstruct the extension from an example. For a new component, add
|
|
66
|
+
`staticContainer: 'HOMEPAGE'`. For an existing component, preserve its current
|
|
67
|
+
`staticContainer` value unless the request explicitly changes installation
|
|
68
|
+
behavior.
|
|
69
|
+
|
|
70
|
+
## Checklist
|
|
71
|
+
|
|
72
|
+
- [ ] Defaults are applied to the generated editor element before layout
|
|
73
|
+
overrides are merged.
|
|
74
|
+
- [ ] Client and editor resources still point to their generated entry files.
|
|
75
|
+
- [ ] The extension and `component.tsx` consume the same `defaultProps` source.
|
|
76
|
+
- [ ] Initial sizing and resize axes match component behavior.
|
|
77
|
+
- [ ] A new component has `staticContainer: 'HOMEPAGE'`; an existing
|
|
78
|
+
component keeps its prior installation behavior unless explicitly changed.
|
|
@@ -1,167 +1,75 @@
|
|
|
1
|
-
# Function
|
|
1
|
+
# Function Handlers
|
|
2
2
|
|
|
3
|
-
|
|
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.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## Standard SDK Handlers
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Use the exact SDK prop name and wire it to the matching React DOM event.
|
|
8
9
|
|
|
9
|
-
|
|
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` |
|
|
10
19
|
|
|
11
|
-
|
|
20
|
+
Declare only the handlers the component actually exposes.
|
|
12
21
|
|
|
13
|
-
|
|
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;
|
|
22
|
+
```tsx
|
|
23
|
+
export type ActionProps = {
|
|
32
24
|
onClick?: (event: React.MouseEvent) => void;
|
|
33
25
|
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
26
|
onMouseIn?: (event: React.MouseEvent) => void;
|
|
38
27
|
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
|
|
28
|
+
};
|
|
45
29
|
|
|
46
|
-
|
|
30
|
+
export const Action: React.FC<ActionProps> = (props) => {
|
|
31
|
+
const { onClick, onDblClick, onMouseIn, onMouseOut } = props;
|
|
47
32
|
|
|
48
|
-
```typescript
|
|
49
|
-
export const MyComponent = (props: MyComponentProps) => {
|
|
50
|
-
const { onClick, onDblClick, onFocus, onBlur, onMouseIn, onMouseOut } = props;
|
|
51
33
|
return (
|
|
52
|
-
<
|
|
34
|
+
<button
|
|
35
|
+
type="button"
|
|
53
36
|
onClick={onClick}
|
|
54
37
|
onDoubleClick={onDblClick}
|
|
55
|
-
onFocus={onFocus}
|
|
56
|
-
onBlur={onBlur}
|
|
57
38
|
onMouseEnter={onMouseIn}
|
|
58
39
|
onMouseLeave={onMouseOut}
|
|
59
|
-
|
|
60
|
-
{/* ... */}
|
|
61
|
-
</div>
|
|
40
|
+
/>
|
|
62
41
|
);
|
|
63
42
|
};
|
|
64
43
|
```
|
|
65
44
|
|
|
66
|
-
|
|
45
|
+
Do not expose DOM names such as `onDoubleClick`, `onMouseEnter`, or
|
|
46
|
+
`onMouseLeave` in the component API; zero config recognizes the SDK names.
|
|
67
47
|
|
|
68
|
-
|
|
48
|
+
## Custom Callbacks
|
|
69
49
|
|
|
70
|
-
|
|
71
|
-
|
|
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:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
export type VideoPlayerProps = {
|
|
72
58
|
onPlay?: () => void;
|
|
73
59
|
onPause?: () => void;
|
|
74
60
|
onEnded?: () => void;
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Pass them directly to the underlying element — no name remapping needed:
|
|
61
|
+
};
|
|
79
62
|
|
|
80
|
-
|
|
81
|
-
export const VideoPlayer = (props: VideoPlayerProps) => {
|
|
63
|
+
export const VideoPlayer: React.FC<VideoPlayerProps> = (props) => {
|
|
82
64
|
const { onPlay, onPause, onEnded } = props;
|
|
83
65
|
return <video onPlay={onPlay} onPause={onPause} onEnded={onEnded} />;
|
|
84
66
|
};
|
|
85
67
|
```
|
|
86
68
|
|
|
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
|
-
```
|
|
69
|
+
## Checklist
|
|
166
70
|
|
|
167
|
-
|
|
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.
|