Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions skills/wix-app/references/EDITOR_REACT_COMPONENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Topic-focused references (rules + patterns + common mistakes in one place):
- [`editor-react-component/DIRECTIONALITY.md`](editor-react-component/DIRECTIONALITY.md) — RTL/LTR rules and patterns
- [`editor-react-component/PROPS-VS-CSS.md`](editor-react-component/PROPS-VS-CSS.md) — What should be a React prop vs CSS
- [`editor-react-component/COMPONENT-API.md`](editor-react-component/COMPONENT-API.md) — Props structure, elementProps, data types, file splitting, containers, array props
- [`editor-react-component/FUNCTION-HANDLERS.md`](editor-react-component/FUNCTION-HANDLERS.md) — Standard SDK event handler props, DOM wiring, custom callbacks
- [`editor-react-component/REACT-PATTERNS.md`](editor-react-component/REACT-PATTERNS.md) — SSR-safe patterns, CSS rules, remaining common mistakes

## CSS guidelines
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ When creating TypeScript interfaces for component props, use types from `@wix/ed
import type { Link } from "@wix/editor-react-types"; // Reference at node_modules/@wix/react-component-schema/dist/editor-react-types.d.ts
```

For **function event handler props** (onClick, onDblClick, onChange, onFocus, onBlur, onMouseIn, onMouseOut) and custom callbacks, follow [`FUNCTION-HANDLERS.md`](FUNCTION-HANDLERS.md). Key rules:
- Use the exact SDK prop names from that file — the manifest system recognizes them
- Wire them to the correct DOM events (note: `onDblClick` → `onDoubleClick`, `onMouseIn` → `onMouseEnter`, `onMouseOut` → `onMouseLeave`)
- Custom callbacks not tied to DOM events use `() => void` (no React event parameter)

### External resources are forbidden

All resources rendered or fetched by the component (images, icons, fonts,
Expand Down
169 changes: 169 additions & 0 deletions skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Function Event Handlers

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.

---

## Rules

### Standard SDK Event Handlers

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.

| Prop name | React DOM event | Type |
| ------------ | --------------- | ------------------------------------- |
| `onClick` | `onClick` | `(event: React.MouseEvent) => void` |
| `onDblClick` | `onDoubleClick` | `(event: React.MouseEvent) => void` |
| `onChange` | `onChange` | `(event: React.ChangeEvent<HTMLElement>) => void` |
| `onFocus` | `onFocus` | `(event: React.FocusEvent) => void` |
| `onBlur` | `onBlur` | `(event: React.FocusEvent) => void` |
| `onMouseIn` | `onMouseEnter` | `(event: React.MouseEvent) => void` |
| `onMouseOut` | `onMouseLeave` | `(event: React.MouseEvent) => void` |

Three props have a **name mismatch** between the SDK prop and the DOM event: `onDblClick` → `onDoubleClick`, `onMouseIn` → `onMouseEnter`, `onMouseOut` → `onMouseLeave`.

### Declaring Standard Handler Props

Declare standard handlers inline with the exact SDK prop names and React event types:

```typescript
interface MyComponentProps {
label?: string;
onClick?: (event: React.MouseEvent) => void;
onDblClick?: (event: React.MouseEvent) => void;
onChange?: (event: React.ChangeEvent<HTMLElement>) => void;
onFocus?: (event: React.FocusEvent) => void;
onBlur?: (event: React.FocusEvent) => void;
onMouseIn?: (event: React.MouseEvent) => void;
onMouseOut?: (event: React.MouseEvent) => void;
}
```

Only declare handlers the component actually exposes. Do not add all seven if the component only handles two.

### Wiring Standard Handlers to DOM Events

Destructure the props and pass them to the correct DOM event — applying the name mappings:

```typescript
export const MyComponent = (props: MyComponentProps) => {
const { onClick, onDblClick, onFocus, onBlur, onMouseIn, onMouseOut } = props;
return (
<div
onClick={onClick}
onDoubleClick={onDblClick}
onFocus={onFocus}
onBlur={onBlur}
onMouseEnter={onMouseIn}
onMouseLeave={onMouseOut}
>
{/* ... */}
</div>
);
};
```

### Custom Callbacks

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:

```typescript
interface VideoPlayerProps {
onPlay?: () => void;
onPause?: () => void;
onEnded?: () => void;
}
```

Pass them directly to the underlying element — no name remapping needed:

```typescript
export const VideoPlayer = (props: VideoPlayerProps) => {
const { onPlay, onPause, onEnded } = props;
return (
<video onPlay={onPlay} onPause={onPause} onEnded={onEnded} />
);
};
```

---

## Common Mistakes

### Passing SDK prop name directly to DOM instead of remapping

**❌ Wrong:**

```typescript
export const MyComponent = (props: MyComponentProps) => {
const { onMouseIn, onMouseOut, onDblClick } = props;
return (
<div
onMouseIn={onMouseIn} // ❌ not a valid React DOM prop
onMouseOut={onMouseOut} // ❌ not a valid React DOM prop
onDblClick={onDblClick} // ❌ not a valid React DOM prop
/>
);
};
```

**✅ Correct:**

```typescript
export const MyComponent = (props: MyComponentProps) => {
const { onMouseIn, onMouseOut, onDblClick } = props;
return (
<div
onMouseEnter={onMouseIn} // ✅ onMouseIn → onMouseEnter
onMouseLeave={onMouseOut} // ✅ onMouseOut → onMouseLeave
onDoubleClick={onDblClick} // ✅ onDblClick → onDoubleClick
/>
);
};
```

### Adding a React event parameter to custom callbacks

**❌ Wrong:**

```typescript
interface VideoPlayerProps {
onPlay?: (event: React.SyntheticEvent) => void; // ❌ event param on custom callback
onEnded?: (event: React.SyntheticEvent) => void; // ❌ event param on custom callback
}
```

**✅ Correct:**

```typescript
interface VideoPlayerProps {
onPlay?: () => void; // ✅ no event param
onEnded?: () => void; // ✅ no event param
}
```

**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.

### Using the DOM event name as the SDK prop name

**❌ Wrong:**

```typescript
interface MyComponentProps {
onDoubleClick?: (event: React.MouseEvent) => void; // ❌ DOM name, not SDK name
onMouseEnter?: (event: React.MouseEvent) => void; // ❌ DOM name, not SDK name
onMouseLeave?: (event: React.MouseEvent) => void; // ❌ DOM name, not SDK name
}
```

**✅ Correct:**

```typescript
interface MyComponentProps {
onDblClick?: (event: React.MouseEvent) => void; // ✅ SDK prop name
onMouseIn?: (event: React.MouseEvent) => void; // ✅ SDK prop name
onMouseOut?: (event: React.MouseEvent) => void; // ✅ SDK prop name
}
```

**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.
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Unless explicitly specified as a component capability/API in the specification,
**External handlers (only when specified):**

- Only expose handlers that are explicitly listed as component capabilities
- Example: If specification says "onClick callback for external control", then add `onClick?: () => void` to props
- Use the standard SDK prop names and DOM wiring rules from [`FUNCTION-HANDLERS.md`](FUNCTION-HANDLERS.md)

**Child component handlers:**

Expand Down