@wix/interact 2.2.2 → 2.4.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/README.md +322 -246
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/react.js +1 -1
- package/dist/cjs/web.js +1 -1
- package/dist/es/index.js +1 -1
- package/dist/es/react.js +2 -2
- package/dist/es/web.js +2 -2
- package/dist/index-C6u4q815.mjs +3291 -0
- package/dist/index-C6u4q815.mjs.map +1 -0
- package/dist/index-Qg46rn0Y.js +21 -0
- package/dist/index-Qg46rn0Y.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/core/add.d.ts.map +1 -1
- package/dist/types/core/css.d.ts +17 -2
- package/dist/types/core/css.d.ts.map +1 -1
- package/dist/types/core/cssUtils.d.ts +8 -0
- package/dist/types/core/cssUtils.d.ts.map +1 -0
- package/dist/types/core/resolvers.d.ts +4 -0
- package/dist/types/core/resolvers.d.ts.map +1 -0
- package/dist/types/core/utilities.d.ts +6 -0
- package/dist/types/core/utilities.d.ts.map +1 -1
- package/dist/types/handlers/animationEnd.d.ts +1 -1
- package/dist/types/handlers/animationEnd.d.ts.map +1 -1
- package/dist/types/handlers/viewProgress.d.ts.map +1 -1
- package/dist/types/types/config.d.ts +23 -2
- package/dist/types/types/config.d.ts.map +1 -1
- package/dist/types/types/css.d.ts +26 -0
- package/dist/types/types/css.d.ts.map +1 -0
- package/dist/types/types/effects.d.ts +12 -0
- package/dist/types/types/effects.d.ts.map +1 -1
- package/dist/types/types/external.d.ts +3 -3
- package/dist/types/types/external.d.ts.map +1 -1
- package/dist/types/types/handlers.d.ts +2 -1
- package/dist/types/types/handlers.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/types/internal.d.ts +1 -1
- package/dist/types/types/internal.d.ts.map +1 -1
- package/dist/types/utils.d.ts +11 -2
- package/dist/types/utils.d.ts.map +1 -1
- package/docs/README.md +1 -1
- package/docs/api/README.md +4 -4
- package/docs/api/functions.md +157 -42
- package/docs/examples/entrance-animations.md +7 -5
- package/docs/guides/getting-started.md +1 -1
- package/docs/integration/react.md +8 -8
- package/package.json +6 -3
- package/rules/full-lean.md +24 -15
- package/rules/integration.md +23 -17
- package/rules/viewenter.md +4 -2
- package/rules/viewprogress.md +52 -0
- package/dist/index-A2Q0e94t.js +0 -18
- package/dist/index-A2Q0e94t.js.map +0 -1
- package/dist/index-HeFaJMEX.mjs +0 -2839
- package/dist/index-HeFaJMEX.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,383 +1,459 @@
|
|
|
1
|
+
<!-- AI: full docs index at https://wix.github.io/interact/llms.txt -->
|
|
2
|
+
|
|
1
3
|
# @wix/interact
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
Declarative, configuration-driven interaction library — web-native, AI-ready, and framework-agnostic.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@wix/interact)
|
|
8
|
+
[](https://bundlephobia.com/package/@wix/interact)
|
|
9
|
+
[](https://github.com/wix/interact/blob/master/LICENSE)
|
|
10
|
+
[](https://www.npmjs.com/package/@wix/interact)
|
|
4
11
|
|
|
5
|
-
##
|
|
12
|
+
## Why Interact?
|
|
6
13
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
+
- **Declarative** — Define trigger-to-effect bindings in JSON; no imperative event wiring
|
|
15
|
+
- **Web-native** — Built on CSS, WAAPI, ViewTimeline, and DOM APIs; supports DOM management via Custom Elements
|
|
16
|
+
- **Framework-agnostic** — Web Components and vanilla JS integrations; React integration included
|
|
17
|
+
- **AI-ready** — JSON configs are machine-readable and provide guardrails; LLMs can generate and agents can validate them
|
|
18
|
+
- **CSS generation** — `generate(config)` emits complete CSS for the whole config (`@keyframes`, `view-timeline`, transitions, FOUC rules)
|
|
19
|
+
- **Preset ecosystem** — Plug in [`@wix/motion-presets`](https://github.com/wix/interact/tree/master/packages/motion-presets) for 75+ ready-made effects.
|
|
20
|
+
- **Accessible** — Built-in `activate` (click + keyboard) and `interest` (hover + focus) trigger variants
|
|
14
21
|
|
|
15
|
-
##
|
|
22
|
+
## Install
|
|
16
23
|
|
|
17
24
|
```bash
|
|
18
25
|
npm install @wix/interact
|
|
19
26
|
```
|
|
20
27
|
|
|
28
|
+
### Use pre-made presets
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @wix/motion-presets
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`@wix/motion-presets` is optional but recommended — it provides the `namedEffect` library used in most examples below.
|
|
35
|
+
|
|
21
36
|
## Quick Start
|
|
22
37
|
|
|
23
|
-
### Using
|
|
38
|
+
### Using Web Components (recommended)
|
|
24
39
|
|
|
25
|
-
|
|
40
|
+
**Web Components** — wrap the target element with `<interact-element>`:
|
|
26
41
|
|
|
27
|
-
```
|
|
28
|
-
import { Interact } from '@wix/interact/web';
|
|
42
|
+
```ts
|
|
43
|
+
import { Interact, generate, type InteractConfig } from '@wix/interact/web';
|
|
44
|
+
import * as presets from '@wix/motion-presets'; // required when using namedEffect
|
|
29
45
|
|
|
30
|
-
//
|
|
31
|
-
|
|
46
|
+
Interact.registerEffects(presets); // required when using namedEffect
|
|
47
|
+
|
|
48
|
+
const config: InteractConfig = {
|
|
32
49
|
interactions: [
|
|
33
50
|
{
|
|
51
|
+
key: 'hero',
|
|
34
52
|
trigger: 'viewEnter',
|
|
35
|
-
|
|
36
|
-
effects: [
|
|
37
|
-
{
|
|
38
|
-
effectId: 'fade-in',
|
|
39
|
-
},
|
|
40
|
-
],
|
|
53
|
+
effects: [{ effectId: 'hero-in' }],
|
|
41
54
|
},
|
|
42
55
|
],
|
|
43
56
|
effects: {
|
|
44
|
-
'
|
|
45
|
-
duration:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
},
|
|
57
|
+
'hero-in': {
|
|
58
|
+
duration: 800,
|
|
59
|
+
easing: 'ease-out',
|
|
60
|
+
namedEffect: { type: 'FadeIn' }, // requires motion-presets
|
|
61
|
+
triggerType: 'once',
|
|
50
62
|
},
|
|
51
63
|
},
|
|
52
64
|
};
|
|
53
65
|
|
|
54
|
-
//
|
|
55
|
-
const
|
|
66
|
+
// render styles - e.g. for SSR
|
|
67
|
+
const interactCSS = generate(config, true);
|
|
68
|
+
|
|
69
|
+
// run on client - e.g. on pagereveal event
|
|
70
|
+
const instance = Interact.create(config);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
In `<head>` add:
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<style>
|
|
77
|
+
${interactCSS}
|
|
78
|
+
/* Optional — keep the custom element from affecting layout */
|
|
79
|
+
interact-element {
|
|
80
|
+
display: contents;
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
56
83
|
```
|
|
57
84
|
|
|
58
|
-
|
|
85
|
+
In the `<body>` add:
|
|
59
86
|
|
|
60
87
|
```html
|
|
61
|
-
|
|
62
|
-
<
|
|
63
|
-
<div>This will fade in when it enters the viewport!</div>
|
|
88
|
+
<interact-element data-interact-key="hero">
|
|
89
|
+
<section class="hero">Hello, animated world!</section>
|
|
64
90
|
</interact-element>
|
|
65
91
|
```
|
|
66
92
|
|
|
67
93
|
### Using React
|
|
68
94
|
|
|
69
|
-
|
|
95
|
+
A complete React example: register presets, generate CSS, mount the component, clean up on unmount.
|
|
70
96
|
|
|
71
|
-
```
|
|
72
|
-
import {
|
|
97
|
+
```tsx
|
|
98
|
+
import { useEffect } from 'react';
|
|
99
|
+
import type { InteractConfig } from '@wix/interact';
|
|
100
|
+
import { Interact, Interaction, generate } from '@wix/interact/react';
|
|
101
|
+
import * as presets from '@wix/motion-presets'; // optional
|
|
73
102
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
trigger: 'viewEnter',
|
|
79
|
-
key: '#my-element',
|
|
80
|
-
effects: [
|
|
81
|
-
{
|
|
82
|
-
effectId: 'fade-in',
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
effects: {
|
|
88
|
-
'fade-in': {
|
|
89
|
-
duration: 1000,
|
|
90
|
-
keyframeEffect: {
|
|
91
|
-
name: 'fade',
|
|
92
|
-
keyframes: { opacity: [0, 1] },
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
},
|
|
103
|
+
Interact.registerEffects(presets); // optional
|
|
104
|
+
|
|
105
|
+
const config: InteractConfig = {
|
|
106
|
+
//...
|
|
96
107
|
};
|
|
97
108
|
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
109
|
+
export function App () {
|
|
110
|
+
const interactCSS = generate(config, false);
|
|
111
|
+
// rest of App logic ...
|
|
101
112
|
|
|
102
|
-
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
const instance = Interact.create(config);
|
|
115
|
+
return () => instance.destroy();
|
|
116
|
+
}, []);
|
|
103
117
|
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
return (
|
|
119
|
+
// can go to <head>
|
|
120
|
+
<style>{interactCSS}</style>
|
|
121
|
+
// ...
|
|
122
|
+
<Hero/>
|
|
123
|
+
// ...
|
|
124
|
+
)
|
|
125
|
+
}
|
|
106
126
|
|
|
107
|
-
|
|
127
|
+
// in components/Hero.jsx
|
|
128
|
+
export function Hero() {
|
|
108
129
|
return (
|
|
109
|
-
<Interaction tagName="
|
|
130
|
+
<Interaction tagName="section" interactKey="hero">
|
|
110
131
|
Hello, animated world!
|
|
111
132
|
</Interaction>
|
|
112
133
|
);
|
|
113
134
|
}
|
|
114
135
|
```
|
|
115
136
|
|
|
116
|
-
### Vanilla
|
|
137
|
+
### Using Vanilla JS (you manage element lifecycle)
|
|
117
138
|
|
|
118
|
-
|
|
139
|
+
**Vanilla JS** — bind elements after they exist in the DOM:
|
|
119
140
|
|
|
120
|
-
```
|
|
141
|
+
```ts
|
|
142
|
+
import type { InteractConfig } from '@wix/interact';
|
|
121
143
|
import { Interact, add } from '@wix/interact';
|
|
122
144
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
interactions: [
|
|
126
|
-
{
|
|
127
|
-
trigger: 'viewEnter',
|
|
128
|
-
key: '#my-element',
|
|
129
|
-
effects: [
|
|
130
|
-
{
|
|
131
|
-
effectId: 'fade-in',
|
|
132
|
-
},
|
|
133
|
-
],
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
effects: {
|
|
137
|
-
'fade-in': {
|
|
138
|
-
duration: 1000,
|
|
139
|
-
keyframeEffect: {
|
|
140
|
-
name: 'fade',
|
|
141
|
-
keyframes: { opacity: [0, 1] },
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
+
const config: InteractConfig = {
|
|
146
|
+
//...
|
|
145
147
|
};
|
|
146
148
|
|
|
147
|
-
|
|
148
|
-
add(document.querySelector('[data-interact-key="my-element"]'), 'my-element');
|
|
149
|
+
const instance = Interact.create(config);
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
const interact = Interact.create(config);
|
|
151
|
+
add(document.querySelector('#hero'), 'hero');
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
## Entry Points
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
### Triggers
|
|
163
|
-
|
|
164
|
-
Define when interactions should occur:
|
|
156
|
+
| Import | Use When |
|
|
157
|
+
| --------------------- | ----------------------------------------------------------- |
|
|
158
|
+
| `@wix/interact` | Vanilla JS — manual element binding via `add()`/`remove()`. |
|
|
159
|
+
| `@wix/interact/web` | Web Components — `<interact-element>` custom element. |
|
|
160
|
+
| `@wix/interact/react` | React — `<Interaction>` component with lifecycle. |
|
|
165
161
|
|
|
166
|
-
|
|
167
|
-
- `click` - On element click
|
|
168
|
-
- `hover` - On element hover
|
|
169
|
-
- `viewProgress` - Scroll-driven animations based on progress of element in viewport
|
|
170
|
-
- `pointerMove` - On pointer/mouse movement over an element or viewport
|
|
171
|
-
- `animationEnd` - When another animation completes
|
|
162
|
+
All three entry points export the same `Interact` class, `generate()` function, and types.
|
|
172
163
|
|
|
173
|
-
|
|
164
|
+
## How It Works
|
|
174
165
|
|
|
175
|
-
|
|
166
|
+
```
|
|
167
|
+
Config ─┬─► Interact.create() ─► Trigger Observers ─► Effect Engine ─► Animation (via @wix/motion)
|
|
168
|
+
└─► generate() ────────► CSS (@keyframes, view-timeline, animations, transitions) ─► <head>
|
|
169
|
+
```
|
|
176
170
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
- **Pointer-driven animations** - Progress-based effects linked to pointer position
|
|
180
|
-
- **CSS transitions** - Style property transitions
|
|
181
|
-
- **Custom effects** - Integration with `@wix/motion`
|
|
171
|
+
`generate(config)` runs at build time or on the server to emit complete CSS for the entire config — maximizing offload of effect creation, binding, and running to the browser.
|
|
172
|
+
Interact also generates native `view-timeline` CSS declarations, so browsers that support it can drive scroll animations entirely without JS.
|
|
182
173
|
|
|
183
|
-
|
|
174
|
+
The `InteractConfig` shape:
|
|
184
175
|
|
|
185
|
-
```
|
|
186
|
-
{
|
|
187
|
-
interactions: [
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
],
|
|
194
|
-
effects: { // Define reusable effect definitions
|
|
195
|
-
'my-effect': {
|
|
196
|
-
duration: 1000,
|
|
197
|
-
keyframeEffect: {
|
|
198
|
-
name: 'fade',
|
|
199
|
-
keyframes: { opacity: [0, 1] }
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
conditions: { // Define conditional logic
|
|
204
|
-
'mobile-only': {
|
|
205
|
-
type: 'media',
|
|
206
|
-
predicate: '(max-width: 768px)'
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
176
|
+
```ts
|
|
177
|
+
type InteractConfig = {
|
|
178
|
+
interactions: Interaction[]; // trigger → effect bindings
|
|
179
|
+
effects?: Record<string, Effect>; // reusable effect definitions
|
|
180
|
+
sequences?: Record<string, SequenceConfig>; // staggered multi-effect timelines
|
|
181
|
+
conditions?: Record<string, Condition>; // media / selector gates
|
|
182
|
+
};
|
|
210
183
|
```
|
|
211
184
|
|
|
212
|
-
##
|
|
185
|
+
## Triggers
|
|
213
186
|
|
|
214
|
-
|
|
187
|
+
| Trigger | Fires On | Params |
|
|
188
|
+
| -------------- | -------------------------------------------- | --------------------------------------- |
|
|
189
|
+
| `viewEnter` | Element enters viewport | `threshold?`, `inset?` |
|
|
190
|
+
| `viewProgress` | While element scrolls through viewport | (use `rangeStart`/`rangeEnd` on effect) |
|
|
191
|
+
| `hover` | Pointer enters/leaves element | — |
|
|
192
|
+
| `click` | Element is clicked | — |
|
|
193
|
+
| `activate` | Click + keyboard (a11y variant of `click`) | — |
|
|
194
|
+
| `interest` | Hover + focus (a11y variant of `hover`) | — |
|
|
195
|
+
| `pointerMove` | While pointer moves over element or viewport | `hitArea?`, `axis?` |
|
|
196
|
+
| `animationEnd` | Another specified effect is finished | `effectId` |
|
|
215
197
|
|
|
216
|
-
|
|
198
|
+
## Effects
|
|
217
199
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
200
|
+
| Effect Type | Use For |
|
|
201
|
+
| ------------------------------------- | -------------------------------------------------------------------------- |
|
|
202
|
+
| `keyframeEffect` | Inline keyframes — self-contained, no preset needed. |
|
|
203
|
+
| `namedEffect` | Registered presets from `@wix/motion-presets` (e.g. `{ type: 'FadeIn' }`). |
|
|
204
|
+
| `customEffect` | Programmatic `(element, progress) => void` callback. |
|
|
205
|
+
| `transition` / `transitionProperties` | CSS state changes driven by `stateAction` (`add`/`remove`/`toggle`). |
|
|
222
206
|
|
|
223
|
-
|
|
207
|
+
## Recipes
|
|
224
208
|
|
|
225
|
-
|
|
226
|
-
// Add interactions to an element
|
|
227
|
-
add(element: IInteractElement, key: string): boolean
|
|
209
|
+
Each example is a complete `InteractConfig` — pass it to `Interact.create(config)`.
|
|
228
210
|
|
|
229
|
-
|
|
230
|
-
remove(key: string): void
|
|
231
|
-
```
|
|
211
|
+
### Entrance animation
|
|
232
212
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
### Entrance Animation
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
213
|
+
```ts
|
|
238
214
|
{
|
|
239
215
|
interactions: [{
|
|
240
|
-
trigger: 'viewEnter',
|
|
241
216
|
key: 'hero',
|
|
242
|
-
|
|
217
|
+
trigger: 'viewEnter',
|
|
218
|
+
effects: [{ effectId: 'float-in' }],
|
|
243
219
|
}],
|
|
244
220
|
effects: {
|
|
245
|
-
'
|
|
221
|
+
'float-in': {
|
|
246
222
|
duration: 800,
|
|
247
223
|
easing: 'ease-out',
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
transform: ['translateY(20px)', 'translateY(0)'],
|
|
252
|
-
opacity: [0, 1]
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
224
|
+
namedEffect: { type: 'FloatIn', direction: 'bottom' },
|
|
225
|
+
},
|
|
226
|
+
},
|
|
257
227
|
}
|
|
258
228
|
```
|
|
259
229
|
|
|
260
|
-
### Click
|
|
230
|
+
### Click effect
|
|
261
231
|
|
|
262
|
-
```
|
|
232
|
+
```ts
|
|
263
233
|
{
|
|
264
234
|
interactions: [{
|
|
235
|
+
key: 'cta',
|
|
265
236
|
trigger: 'click',
|
|
266
|
-
|
|
267
|
-
effects: [{ effectId: 'bounce' }]
|
|
237
|
+
effects: [{ effectId: 'pulse' }],
|
|
268
238
|
}],
|
|
269
239
|
effects: {
|
|
270
|
-
'
|
|
271
|
-
duration:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
240
|
+
'pulse': {
|
|
241
|
+
duration: 300,
|
|
242
|
+
keyframeEffect: {
|
|
243
|
+
name: 'pulse',
|
|
244
|
+
keyframes: [
|
|
245
|
+
{ transform: 'scale(1.08)', offset: 0.5 }
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
triggerType: 'repeat',
|
|
249
|
+
},
|
|
250
|
+
},
|
|
277
251
|
}
|
|
278
252
|
```
|
|
279
253
|
|
|
280
|
-
### Scroll-driven
|
|
254
|
+
### Scroll-driven animations
|
|
281
255
|
|
|
282
|
-
```
|
|
256
|
+
```ts
|
|
283
257
|
{
|
|
284
258
|
interactions: [{
|
|
259
|
+
key: 'card',
|
|
285
260
|
trigger: 'viewProgress',
|
|
286
|
-
|
|
287
|
-
effects: [{ effectId: 'parallax-scroll' }]
|
|
261
|
+
effects: [{ effectId: 'parallax' }],
|
|
288
262
|
}],
|
|
289
263
|
effects: {
|
|
290
|
-
'parallax
|
|
264
|
+
'parallax': {
|
|
291
265
|
keyframeEffect: {
|
|
292
|
-
name: 'parallax
|
|
266
|
+
name: 'parallax',
|
|
293
267
|
keyframes: [
|
|
294
|
-
{ transform: 'translateY(
|
|
295
|
-
{ transform: 'translateY(
|
|
296
|
-
]
|
|
268
|
+
{ transform: 'translateY(-120px)' },
|
|
269
|
+
{ transform: 'translateY(120px)' },
|
|
270
|
+
],
|
|
297
271
|
},
|
|
298
272
|
rangeStart: { name: 'cover', offset: { value: 0, unit: 'percentage' } },
|
|
299
273
|
rangeEnd: { name: 'cover', offset: { value: 100, unit: 'percentage' } },
|
|
300
274
|
fill: 'both',
|
|
301
|
-
easing: 'linear'
|
|
302
|
-
}
|
|
303
|
-
}
|
|
275
|
+
easing: 'linear',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
304
278
|
}
|
|
305
279
|
```
|
|
306
280
|
|
|
307
|
-
###
|
|
281
|
+
### Hover toggle
|
|
282
|
+
|
|
283
|
+
#### CSS transition
|
|
308
284
|
|
|
309
|
-
```
|
|
285
|
+
```ts
|
|
310
286
|
{
|
|
311
287
|
interactions: [{
|
|
312
|
-
trigger: 'hover',
|
|
313
288
|
key: 'card',
|
|
314
|
-
|
|
315
|
-
effects: [{ effectId: 'lift' }]
|
|
289
|
+
trigger: 'hover',
|
|
290
|
+
effects: [{ effectId: 'lift', selector: '.card-figure' }],
|
|
316
291
|
}],
|
|
317
|
-
|
|
318
|
-
'
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
292
|
+
effects: {
|
|
293
|
+
'lift': {
|
|
294
|
+
transition: {
|
|
295
|
+
duration: 200,
|
|
296
|
+
easing: 'ease-out',
|
|
297
|
+
styleProperties: [
|
|
298
|
+
{ name: 'transform', value: 'scale(1.08)' },
|
|
299
|
+
{ name: 'box-shadow', value: '0 8px 16px rgb(0 0 0 / 0.15)' },
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
},
|
|
322
303
|
},
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### CSS Animation
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
{
|
|
311
|
+
interactions: [{
|
|
312
|
+
key: 'card',
|
|
313
|
+
trigger: 'hover',
|
|
314
|
+
effects: [{ effectId: 'lift', selector: '.card-figure' }],
|
|
315
|
+
}],
|
|
323
316
|
effects: {
|
|
324
317
|
'lift': {
|
|
325
|
-
duration: 200,
|
|
326
318
|
keyframeEffect: {
|
|
327
319
|
name: 'lift',
|
|
328
|
-
keyframes:
|
|
329
|
-
transform:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
320
|
+
keyframes: [
|
|
321
|
+
{ transform: 'translateY(-80px)', boxShadow: '0 8px 16px rgb(0 0 0 / 0.15)' },
|
|
322
|
+
],
|
|
323
|
+
},
|
|
324
|
+
duration: 200,
|
|
325
|
+
easing: 'ease-out',
|
|
326
|
+
},
|
|
327
|
+
},
|
|
335
328
|
}
|
|
336
329
|
```
|
|
337
330
|
|
|
338
|
-
|
|
331
|
+
### Pointer-tracking
|
|
339
332
|
|
|
340
|
-
|
|
341
|
-
- [Guides and Tutorials](https://wix.github.io/interact/docs/guides)
|
|
342
|
-
- [Examples and Patterns](https://wix.github.io/interact/docs/examples)
|
|
343
|
-
- [Integration Guides](https://wix.github.io/interact/docs/integration)
|
|
333
|
+
#### Keyframe effect
|
|
344
334
|
|
|
345
|
-
|
|
335
|
+
```ts
|
|
336
|
+
{
|
|
337
|
+
interactions: [{
|
|
338
|
+
key: 'card-wrapper',
|
|
339
|
+
trigger: 'pointerMove',
|
|
340
|
+
params: { hitArea: 'root', axis: 'x' },
|
|
341
|
+
effects: [{ effectId: 'follow-x', key: 'card' }],
|
|
342
|
+
}, {
|
|
343
|
+
key: 'card-wrapper',
|
|
344
|
+
trigger: 'pointerMove',
|
|
345
|
+
params: { hitArea: 'root', axis: 'y' },
|
|
346
|
+
effects: [{ effectId: 'follow-y', key: 'card' }],
|
|
347
|
+
}],
|
|
348
|
+
effects: {
|
|
349
|
+
'follow-x': {
|
|
350
|
+
keyframeEffect: {
|
|
351
|
+
name: 'follow-x',
|
|
352
|
+
keyframes: [
|
|
353
|
+
{ transform: 'rotateY(-45deg)' },
|
|
354
|
+
{ transform: 'rotateY(0px)' },
|
|
355
|
+
{ transform: 'rotateY(45deg)' },
|
|
356
|
+
],
|
|
357
|
+
},
|
|
358
|
+
easing: 'linear',
|
|
359
|
+
centeredToTarget: true,
|
|
360
|
+
},
|
|
361
|
+
'follow-y': {
|
|
362
|
+
keyframeEffect: {
|
|
363
|
+
name: 'follow-y',
|
|
364
|
+
keyframes: [
|
|
365
|
+
{ transform: 'rotateX(45deg)' },
|
|
366
|
+
{ transform: 'rotateX(0px)' },
|
|
367
|
+
{ transform: 'rotateX(-45deg)' },
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
easing: 'linear',
|
|
371
|
+
composite: 'add',
|
|
372
|
+
centeredToTarget: true,
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
}
|
|
376
|
+
```
|
|
346
377
|
|
|
347
|
-
|
|
348
|
-
- [Rules for integration](https://wix.github.io/interact/rules/integration.md)
|
|
349
|
-
- [Rules for view entrance interactions](https://wix.github.io/interact/rules/viewenter.md)
|
|
350
|
-
- [Rules for click interactions](https://wix.github.io/interact/rules/click.md)
|
|
351
|
-
- [Rules for hover interactions](https://wix.github.io/interact/rules/click.md)
|
|
352
|
-
- [Rules for scroll interactions](https://wix.github.io/interact/rules/viewprogress.md)
|
|
353
|
-
- [Rules for pointer-move interactions](https://wix.github.io/interact/rules/pointermove.md)
|
|
378
|
+
#### Custom effect
|
|
354
379
|
|
|
355
|
-
|
|
380
|
+
```ts
|
|
381
|
+
{
|
|
382
|
+
interactions: [{
|
|
383
|
+
key: 'spotlight',
|
|
384
|
+
trigger: 'pointerMove',
|
|
385
|
+
params: { hitArea: 'root' },
|
|
386
|
+
effects: [{ effectId: 'follow' }],
|
|
387
|
+
}],
|
|
388
|
+
effects: {
|
|
389
|
+
'follow': {
|
|
390
|
+
customEffect: (element: HTMLElement, progress: { x: number, y: number }) => {
|
|
391
|
+
element.style.setProperty('--x', `${progress.x * 100}%`);
|
|
392
|
+
element.style.setProperty('--y', `${progress.y * 100}%`);
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
}
|
|
397
|
+
```
|
|
356
398
|
|
|
357
|
-
|
|
358
|
-
# Install dependencies
|
|
359
|
-
yarn install
|
|
399
|
+
## Common Pitfalls
|
|
360
400
|
|
|
361
|
-
|
|
362
|
-
|
|
401
|
+
- **`overflow: hidden` breaks `viewProgress`** — Use `overflow: clip` on all ancestors between the source and the scroll container.
|
|
402
|
+
- **Same element as source and target with `viewEnter`** — Must use `triggerType: 'once'`. Other types cause re-entry loops.
|
|
403
|
+
- **Hit-area shift on `hover` / `pointerMove`** — Animating size/position of the hovered element shifts the hit area and causes jitter. Instead, animate a child via `selector` or a different `key`.
|
|
404
|
+
- **`registerEffects()` must run before `Interact.create()`/`generate()`** when using `namedEffect`.
|
|
405
|
+
- **FOUC prevention** — requires injecting the output of `generate(config)` into `<head>`.
|
|
406
|
+
- **`generate(config, useFirstChild)`** — Pass `true` for `<interact-element>` (web), `false` for vanilla and React `<Interaction>`.
|
|
407
|
+
- **`<interact-element>` must wrap exactly one child** — the library targets `:first-child` by default.
|
|
363
408
|
|
|
364
|
-
|
|
365
|
-
yarn playground
|
|
409
|
+
## AI & Agent Support
|
|
366
410
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
411
|
+
Interact's JSON-config surface is the differentiator: configs are serializable, schema-typed, and validate-able (guardrails) — no imperative DOM logic for an LLM to hallucinate.
|
|
412
|
+
|
|
413
|
+
AI agents can discover @wix/interact documentation through:
|
|
414
|
+
|
|
415
|
+
- **[llms.txt](https://wix.github.io/interact/llms.txt)** — structured docs index ([llms.txt standard](https://llmstxt.org/))
|
|
416
|
+
- **[llms-full.txt](https://wix.github.io/interact/llms-full.txt)** — all rules in a single file
|
|
417
|
+
|
|
418
|
+
**Rules files** ship with the package under [`rules/`](https://github.com/wix/interact/tree/master/packages/interact/rules) — point your agent at them:
|
|
419
|
+
|
|
420
|
+
- [`rules/full-lean.md`](https://wix.github.io/interact/rules/full-lean.md) — complete config spec, pitfalls, and constraints
|
|
421
|
+
- [`rules/integration.md`](https://wix.github.io/interact/rules/integration.md) — integration entry points, lifecycle, style generation
|
|
422
|
+
- [`rules/viewenter.md`](https://wix.github.io/interact/rules/viewenter.md) — viewport entrance triggers (scroll-triggered animations)
|
|
423
|
+
- [`rules/viewprogress.md`](https://wix.github.io/interact/rules/viewprogress.md) — scroll-driven animations
|
|
424
|
+
- [`rules/click.md`](https://wix.github.io/interact/rules/click.md) — click and activate triggers
|
|
425
|
+
- [`rules/hover.md`](https://wix.github.io/interact/rules/hover.md) — hover and interest triggers
|
|
426
|
+
- [`rules/pointermove.md`](https://wix.github.io/interact/rules/pointermove.md) — pointer-driven animations
|
|
427
|
+
|
|
428
|
+
**Generation constraints** for agents producing configs:
|
|
429
|
+
|
|
430
|
+
- Do not invent `namedEffect` types — use only registered presets.
|
|
431
|
+
- Do not attach DOM event listeners manually — use triggers.
|
|
432
|
+
- Do not use `overflow: hidden` on scroll-tracked ancestors — use `overflow: clip`.
|
|
433
|
+
- Always pre-render CSS with `generate(config)` and inject into `<head>`.
|
|
434
|
+
- Always call `Interact.registerEffects(presets)` before `generate()` and `Interact.create()` when using `namedEffect`.
|
|
370
435
|
|
|
371
436
|
## Browser Support
|
|
372
437
|
|
|
373
|
-
-
|
|
374
|
-
-
|
|
438
|
+
- Modern browsers with the Web Animations API (Baseline).
|
|
439
|
+
- `adoptedStyleSheets` (used by `transition` / `transitionProperties`): Chrome 73+, Firefox 101+, Safari 16.4+, Edge 79+.
|
|
440
|
+
- ViewTimeline: Chrome 115+; polyfilled via [`fizban`](https://github.com/wix-incubator/fizban) elsewhere.
|
|
375
441
|
|
|
376
442
|
## Related Packages
|
|
377
443
|
|
|
378
|
-
- [`@wix/motion`](
|
|
379
|
-
- [`
|
|
380
|
-
- [`
|
|
444
|
+
- [`@wix/motion`](https://github.com/wix/interact/tree/master/packages/motion) — low-level animation engine underneath Interact.
|
|
445
|
+
- [`@wix/motion-presets`](https://github.com/wix/interact/tree/master/packages/motion-presets) — ready-made effect catalog (entrance, scroll, hover, pointer).
|
|
446
|
+
- [`fizban`](https://github.com/wix-incubator/fizban) — scroll-driven animation polyfill (bundled dependency).
|
|
447
|
+
- [`kuliso`](https://github.com/wix-incubator/kuliso) — pointer-driven animation polyfill (bundled dependency).
|
|
448
|
+
|
|
449
|
+
## Documentation
|
|
450
|
+
|
|
451
|
+
- [**Getting Started**](https://wix.github.io/interact/docs/#/guides/getting-started)
|
|
452
|
+
- [**API Reference**](https://wix.github.io/interact/docs/#/api) — `Interact` class, `InteractionController`, standalone functions, types
|
|
453
|
+
- [**Guides**](https://wix.github.io/interact/docs/#/guides) — triggers, effects, configuration, state, conditions, sequences
|
|
454
|
+
- [**Examples**](https://wix.github.io/interact/docs/#/examples) — entrance, click, hover, list patterns
|
|
455
|
+
- [**Web Components**](https://wix.github.io/interact/docs/#/guides/custom-elements) — integration via custom elements
|
|
456
|
+
- [**React Integration**](https://wix.github.io/interact/docs/#/integration/react) — React integration
|
|
381
457
|
|
|
382
458
|
## License
|
|
383
459
|
|