@wix/interact 2.1.4 → 2.2.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/dist/cjs/index.js +1 -1
- package/dist/cjs/react.js +1 -1
- package/dist/cjs/web.js +1 -1
- package/dist/cjs/web.js.map +1 -1
- package/dist/es/index.js +1 -1
- package/dist/es/react.js +2 -2
- package/dist/es/web.js +15 -15
- package/dist/es/web.js.map +1 -1
- package/dist/{index-DHqlFmW8.mjs → index-ByLXasWO.mjs} +491 -485
- package/dist/index-ByLXasWO.mjs.map +1 -0
- package/dist/index-CzRuJxn8.js +18 -0
- package/dist/index-CzRuJxn8.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/core/Interact.d.ts +2 -2
- package/dist/types/core/InteractionController.d.ts +2 -2
- package/dist/types/core/InteractionController.d.ts.map +1 -1
- package/dist/types/core/add.d.ts.map +1 -1
- package/dist/types/core/css.d.ts.map +1 -1
- package/dist/types/handlers/effectHandlers.d.ts +4 -4
- package/dist/types/handlers/effectHandlers.d.ts.map +1 -1
- package/dist/types/handlers/eventTrigger.d.ts +2 -2
- package/dist/types/handlers/eventTrigger.d.ts.map +1 -1
- package/dist/types/handlers/index.d.ts.map +1 -1
- package/dist/types/handlers/viewEnter.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/react/index.d.ts +1 -1
- package/dist/types/react/index.d.ts.map +1 -1
- package/dist/types/types/config.d.ts +47 -0
- package/dist/types/types/config.d.ts.map +1 -0
- package/dist/types/types/controller.d.ts +34 -0
- package/dist/types/types/controller.d.ts.map +1 -0
- package/dist/types/types/effects.d.ts +75 -0
- package/dist/types/types/effects.d.ts.map +1 -0
- package/dist/types/types/external.d.ts +6 -0
- package/dist/types/types/external.d.ts.map +1 -0
- package/dist/types/types/global.d.ts +11 -0
- package/dist/types/types/global.d.ts.map +1 -0
- package/dist/types/types/handlers.d.ts +41 -0
- package/dist/types/types/handlers.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +8 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/types/internal.d.ts +36 -0
- package/dist/types/types/internal.d.ts.map +1 -0
- package/dist/types/types/triggers.d.ts +28 -0
- package/dist/types/types/triggers.d.ts.map +1 -0
- package/dist/types/web/InteractElement.d.ts +2 -2
- package/dist/types/web/InteractElement.d.ts.map +1 -1
- package/dist/types/web/index.d.ts +1 -1
- package/dist/types/web/index.d.ts.map +1 -1
- package/docs/api/README.md +2 -3
- package/docs/api/functions.md +4 -4
- package/docs/api/interact-class.md +2 -3
- package/docs/api/interact-element.md +2 -2
- package/docs/api/interaction-controller.md +4 -4
- package/docs/api/types.md +38 -69
- package/docs/examples/README.md +1 -1
- package/docs/examples/click-interactions.md +0 -7
- package/docs/examples/entrance-animations.md +28 -27
- package/docs/examples/list-patterns.md +17 -16
- package/docs/guides/conditions-and-media-queries.md +2 -3
- package/docs/guides/configuration-structure.md +5 -7
- package/docs/guides/effects-and-animations.md +2 -4
- package/docs/guides/getting-started.md +0 -1
- package/docs/guides/lists-and-dynamic-content.md +10 -9
- package/docs/guides/sequences.md +3 -4
- package/docs/guides/state-management.md +0 -2
- package/docs/guides/understanding-triggers.md +9 -13
- package/package.json +2 -2
- package/rules/click.md +96 -560
- package/rules/full-lean.md +536 -360
- package/rules/hover.md +107 -530
- package/rules/integration.md +212 -261
- package/rules/pointermove.md +154 -1407
- package/rules/viewenter.md +128 -863
- package/rules/viewprogress.md +88 -322
- package/dist/index-DHqlFmW8.mjs.map +0 -1
- package/dist/index-DYEvpIGz.js +0 -18
- package/dist/index-DYEvpIGz.js.map +0 -1
- package/dist/types/types.d.ts +0 -256
- package/dist/types/types.d.ts.map +0 -1
- package/rules/MASTER-CLEANUP-PLAN.md +0 -286
- package/rules/scroll-list.md +0 -748
package/rules/hover.md
CHANGED
|
@@ -1,614 +1,191 @@
|
|
|
1
1
|
# Hover Trigger Rules for @wix/interact
|
|
2
2
|
|
|
3
|
-
This document contains rules for generating hover
|
|
3
|
+
This document contains rules for generating hover-triggered interactions in `@wix/interact`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**CRITICAL — Accessible hover**: Use `trigger: 'interest'` instead of `trigger: 'hover'` to also respond to keyboard focus.
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
- **CRITICAL**: MUST AVOID using the same element as both trigger source and effect target with effects that change size or position (e.g. `transform: translate(…)`, `scale(…)`). The transform shifts the hit area, causing jittery re-entry cycles. Instead, use `selector` to target a child element for the animation.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Table of Contents
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
effects: [
|
|
16
|
-
{
|
|
17
|
-
key: '[TARGET_KEY]',
|
|
18
|
-
[EFFECT_TYPE]: [EFFECT_DEFINITION],
|
|
19
|
-
fill: 'both',
|
|
20
|
-
duration: [DURATION_MS],
|
|
21
|
-
easing: '[EASING_FUNCTION]'
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
**Variables**:
|
|
28
|
-
|
|
29
|
-
- `[SOURCE_KEY]`: Unique identifier for hoverable element. Should equal the value of the `data-interact-key` attribute on the wrapping `<interact-element>`.
|
|
30
|
-
- `[TARGET_KEY]`: Unique identifier for animated element (can be same as `[SOURCE_KEY]` for self-targeting, or different for cross-targeting).
|
|
31
|
-
- `[EFFECT_TYPE]`: Either `namedEffect` or `keyframeEffect`
|
|
32
|
-
- `[EFFECT_DEFINITION]`: Named effect object (e.g., { type: 'SlideIn', ...params }, { type: 'FadeIn', ...params }) or keyframe object (e.g., { name: 'custom-fade', keyframes: [{ opacity: 0 }, { opacity: 1 }] }, { name: 'custom-slide', keyframes: [{ transform: 'translateX(-100%)' }, { transform: 'translateX(0)' }] })
|
|
33
|
-
- `[DURATION_MS]`: Animation duration in milliseconds (typically 200-500ms for micro-interactions)
|
|
34
|
-
- `[EASING_FUNCTION]`: Timing function ('ease-out', 'ease-in-out', or cubic-bezier)
|
|
35
|
-
- `[UNIQUE_EFFECT_ID]`: Optional unique identifier for animation chaining
|
|
11
|
+
- [Rule 1: keyframeEffect / namedEffect (TimeEffect)](#rule-1-keyframeeffect--namedeffect-timeeffect)
|
|
12
|
+
- [Rule 2: transition / transitionProperties (StateEffect)](#rule-2-transition--transitionproperties-stateeffect)
|
|
13
|
+
- [Rule 3: customEffect (TimeEffect)](#rule-3-customeffect-timeeffect)
|
|
14
|
+
- [Rule 4: Sequences](#rule-4-sequences)
|
|
36
15
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- `DURATION_MS`: 300 (for micro-interactions)
|
|
40
|
-
- `EASING_FUNCTION`: 'ease-out' (for smooth feel)
|
|
41
|
-
- `[TARGET_KEY]`: Same as `[SOURCE_KEY]` for self-targeting
|
|
42
|
-
|
|
43
|
-
**Common Use Cases**:
|
|
44
|
-
|
|
45
|
-
- Button hover states
|
|
46
|
-
- Card lift effects
|
|
47
|
-
- Image zoom effects
|
|
48
|
-
- Color/opacity changes
|
|
49
|
-
|
|
50
|
-
**Example Generations**:
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
// Button hover
|
|
54
|
-
{
|
|
55
|
-
key: 'primary-button',
|
|
56
|
-
trigger: 'hover',
|
|
57
|
-
effects: [
|
|
58
|
-
{
|
|
59
|
-
key: 'primary-button',
|
|
60
|
-
keyframeEffect: {
|
|
61
|
-
name: 'button-shadow',
|
|
62
|
-
keyframes: [
|
|
63
|
-
{ transform: 'scale(1)', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' },
|
|
64
|
-
{ transform: 'scale(1.05)', boxShadow: '0 8px 16px rgba(0,0,0,0.15)' }
|
|
65
|
-
]
|
|
66
|
-
},
|
|
67
|
-
fill: 'both',
|
|
68
|
-
duration: 200,
|
|
69
|
-
easing: 'ease-out'
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
}
|
|
16
|
+
---
|
|
73
17
|
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
key: 'product-image',
|
|
77
|
-
trigger: 'hover',
|
|
78
|
-
effects: [
|
|
79
|
-
{
|
|
80
|
-
key: 'product-image-media',
|
|
81
|
-
keyframeEffect: {
|
|
82
|
-
name: 'image-scale',
|
|
83
|
-
keyframes: [
|
|
84
|
-
{ transform: 'scale(1)' },
|
|
85
|
-
{ transform: 'scale(1.1)' }
|
|
86
|
-
]
|
|
87
|
-
},
|
|
88
|
-
fill: 'both',
|
|
89
|
-
duration: 400,
|
|
90
|
-
easing: 'ease-out'
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
```
|
|
18
|
+
## Rule 1: keyframeEffect / namedEffect (TimeEffect)
|
|
95
19
|
|
|
96
|
-
|
|
20
|
+
Use `keyframeEffect` or `namedEffect` when the hover should play an animation (CSS or WAAPI). Set `triggerType` on each effect to control playback behavior.
|
|
97
21
|
|
|
98
|
-
**
|
|
22
|
+
**CRITICAL:** Always include `fill: 'both'` for `triggerType: 'alternate'`, `'repeat'` — keeps the effect applied while hovering and prevents garbage-collection. For `triggerType: 'once'` use `fill: 'backwards'`.
|
|
99
23
|
|
|
100
|
-
**
|
|
24
|
+
**Multiple effects:** The `effects` array can contain multiple effects — all share the same hover trigger and fire together. Use this to animate different targets from a single hover event.
|
|
101
25
|
|
|
102
26
|
```typescript
|
|
103
27
|
{
|
|
104
28
|
key: '[SOURCE_KEY]',
|
|
105
29
|
trigger: 'hover',
|
|
106
|
-
params: {
|
|
107
|
-
type: 'alternate'
|
|
108
|
-
},
|
|
109
30
|
effects: [
|
|
110
31
|
{
|
|
111
32
|
key: '[TARGET_KEY]',
|
|
112
|
-
|
|
113
|
-
namedEffect: { type: '[NAMED_EFFECT_TYPE]' },
|
|
114
|
-
// keyframeEffect: { name: '[EFFECT_NAME]', keyframes: [{ ... }, { ... }] },
|
|
115
|
-
fill: 'both',
|
|
116
|
-
reversed: [REVERSED_BOOL],
|
|
117
|
-
duration: [DURATION_MS],
|
|
118
|
-
easing: '[EASING_FUNCTION]'
|
|
119
|
-
}
|
|
120
|
-
]
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
**Variables**:
|
|
125
|
-
|
|
126
|
-
- `[REVERSED_BOOL]`: Optional. `true` to reverse the enter direction (mouse enter plays backwards, leave plays forwards).
|
|
127
|
-
- `[NAMED_EFFECT_TYPE]`: Pre-built effect from `@wix/motion-presets`. Available hover presets:
|
|
128
|
-
- Size: `ExpandIn`, `Pulse`, `GrowIn`
|
|
129
|
-
- Fade/Blur: `FadeIn`, `Flash`, `BlurIn`
|
|
130
|
-
- Translate: `SlideIn`, `GlideIn`, `FloatIn`, `BounceIn`, `GlitchIn`
|
|
131
|
-
- Rotate: `SpinIn`, `TiltIn`, `ArcIn`, `TurnIn`, `FlipIn`, `Spin`, `Swing`
|
|
132
|
-
- Attention: `Bounce`, `DropIn`, `Rubber`, `Jello`, `Cross`, `Wiggle`, `Poke`
|
|
133
|
-
- Other variables same as Rule 1
|
|
134
|
-
|
|
135
|
-
**Important**: Spatial effects (translation, rotation) that change the hit-area considerably should use different source and target keys to avoid flickering on enter/leave.
|
|
136
|
-
|
|
137
|
-
**Default Values**:
|
|
138
|
-
|
|
139
|
-
- `DURATION_MS`: 250–300
|
|
140
|
-
- `EASING_FUNCTION`: 'ease-out'
|
|
141
|
-
|
|
142
|
-
**Example — namedEffect (card scale)**:
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
{
|
|
146
|
-
key: 'feature-card',
|
|
147
|
-
trigger: 'hover',
|
|
148
|
-
params: { type: 'alternate' },
|
|
149
|
-
effects: [
|
|
150
|
-
{
|
|
151
|
-
key: 'feature-card',
|
|
152
|
-
namedEffect: { type: 'Pulse' },
|
|
153
|
-
fill: 'both',
|
|
154
|
-
duration: 250,
|
|
155
|
-
easing: 'ease-out'
|
|
156
|
-
}
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
**Example — keyframeEffect (card lift)**:
|
|
33
|
+
triggerType: '[TRIGGER_TYPE]',
|
|
162
34
|
|
|
163
|
-
|
|
164
|
-
{
|
|
165
|
-
key: 'portfolio-item',
|
|
166
|
-
trigger: 'hover',
|
|
167
|
-
params: { type: 'alternate' },
|
|
168
|
-
effects: [
|
|
169
|
-
{
|
|
170
|
-
key: 'portfolio-item',
|
|
35
|
+
// --- pick ONE of the two effect types ---
|
|
171
36
|
keyframeEffect: {
|
|
172
|
-
name: '
|
|
173
|
-
keyframes: [
|
|
174
|
-
{ transform: 'translateY(0)', boxShadow: '0 4px 6px rgba(0,0,0,0.1)' },
|
|
175
|
-
{ transform: 'translateY(-8px)', boxShadow: '0 20px 25px rgba(0,0,0,0.15)' }
|
|
176
|
-
]
|
|
37
|
+
name: '[EFFECT_NAME]',
|
|
38
|
+
keyframes: [KEYFRAMES],
|
|
177
39
|
},
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
easing: 'ease-out'
|
|
181
|
-
}
|
|
182
|
-
]
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
## Rule 3: Hover Interactions with Repeat Pattern
|
|
40
|
+
// OR
|
|
41
|
+
namedEffect: [NAMED_EFFECT_DEFINITION],
|
|
187
42
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
**Pattern**:
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
{
|
|
194
|
-
key: '[SOURCE_KEY]',
|
|
195
|
-
trigger: 'hover',
|
|
196
|
-
params: {
|
|
197
|
-
type: 'repeat'
|
|
198
|
-
},
|
|
199
|
-
effects: [
|
|
200
|
-
{
|
|
201
|
-
key: '[TARGET_KEY]',
|
|
202
|
-
[EFFECT_TYPE]: [EFFECT_DEFINITION],
|
|
43
|
+
fill: '[FILL_MODE]',
|
|
203
44
|
duration: [DURATION_MS],
|
|
204
|
-
easing: '[EASING_FUNCTION]'
|
|
205
|
-
|
|
45
|
+
easing: '[EASING_FUNCTION]',
|
|
46
|
+
delay: [DELAY_MS],
|
|
47
|
+
iterations: [ITERATIONS],
|
|
48
|
+
alternate: [ALTERNATE_BOOL]
|
|
49
|
+
},
|
|
50
|
+
// additional effects targeting other elements can be added here
|
|
206
51
|
]
|
|
207
52
|
}
|
|
208
53
|
```
|
|
209
54
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
- Same as Rule 1
|
|
213
|
-
|
|
214
|
-
**Use Cases for Repeat Pattern**:
|
|
55
|
+
### Variables
|
|
215
56
|
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
-
-
|
|
219
|
-
-
|
|
57
|
+
- `[SOURCE_KEY]` — identifier matching the element's key (`data-interact-key` for web, `interactKey` for React). The element that listens for hover.
|
|
58
|
+
- `[TARGET_KEY]` — identifier matching the element's key on the element that animates. Use a different key from `[SOURCE_KEY]` when source and target must be separated (see hit-area shift above).
|
|
59
|
+
- `[TRIGGER_TYPE]` — `triggerType` on the effect. One of:
|
|
60
|
+
- `'alternate'` — plays forward on enter, reverses on leave. Default. Most common for hover.
|
|
61
|
+
- `'repeat'` — restarts the animation from the beginning on each enter. On leave, jumps to the beginning and pauses.
|
|
62
|
+
- `'once'` — plays once on the first enter and never again.
|
|
63
|
+
- `'state'` — resumes on enter, pauses on leave. Useful for continuous loops (`iterations: Infinity`).
|
|
64
|
+
- `[KEYFRAMES]` — array of keyframe objects (e.g. `[{ opacity: 0 }, { opacity: 1 }]`). Property names in camelCase.
|
|
65
|
+
- `[EFFECT_NAME]` — unique string identifier for a `keyframeEffect`.
|
|
66
|
+
- `[NAMED_EFFECT_DEFINITION]` — object with properties of pre-built effect from `@wix/motion-presets`. Refer to motion-presets rules for available presets and their options.
|
|
67
|
+
- `[DURATION_MS]` — animation duration in milliseconds.
|
|
68
|
+
- `[EASING_FUNCTION]` — CSS easing string (e.g. `'ease-out'`, `'ease-in-out'`, `'cubic-bezier(0.4, 0, 0.2, 1)'`), or named easing from `@wix/motion`.
|
|
69
|
+
- `[DELAY_MS]` — optional delay before the effect starts, in milliseconds.
|
|
70
|
+
- `[ITERATIONS]` — optional. Number of iterations, or `Infinity` for continuous loops. Primarily useful with `triggerType: 'state'`.
|
|
71
|
+
- `[ALTERNATE_BOOL]` — optional. `true` to alternate direction on every other iteration (within a single playback).
|
|
72
|
+
- `[FILL_MODE]` — usually `'both'`. Keeps the final state applied while hovering, and prevents garbage-collection of animation when finished.
|
|
220
73
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
- `type`: 'repeat'
|
|
224
|
-
- `DURATION_MS`: 600 (longer for noticeable repeat)
|
|
225
|
-
- `EASING_FUNCTION`: 'ease-in-out'
|
|
226
|
-
|
|
227
|
-
**Example Generations**:
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
// Button pulse effect
|
|
231
|
-
{
|
|
232
|
-
key: 'cta-button',
|
|
233
|
-
trigger: 'hover',
|
|
234
|
-
params: {
|
|
235
|
-
type: 'repeat'
|
|
236
|
-
},
|
|
237
|
-
effects: [
|
|
238
|
-
{
|
|
239
|
-
key: 'cta-button',
|
|
240
|
-
namedEffect: {
|
|
241
|
-
type: 'Breath'
|
|
242
|
-
},
|
|
243
|
-
duration: 600,
|
|
244
|
-
easing: 'ease-in-out'
|
|
245
|
-
}
|
|
246
|
-
]
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Icon shake effect
|
|
250
|
-
{
|
|
251
|
-
key: 'notification-bell',
|
|
252
|
-
trigger: 'hover',
|
|
253
|
-
params: {
|
|
254
|
-
type: 'repeat'
|
|
255
|
-
},
|
|
256
|
-
effects: [
|
|
257
|
-
{
|
|
258
|
-
key: 'notification-bell',
|
|
259
|
-
keyframeEffect: {
|
|
260
|
-
name: 'shake',
|
|
261
|
-
keyframes: [
|
|
262
|
-
{ transform: 'rotate(0deg)' },
|
|
263
|
-
{ transform: 'rotate(15deg)' },
|
|
264
|
-
{ transform: 'rotate(-15deg)' },
|
|
265
|
-
{ transform: 'rotate(0deg)' }
|
|
266
|
-
]
|
|
267
|
-
},
|
|
268
|
-
duration: 500,
|
|
269
|
-
easing: 'ease-in-out'
|
|
270
|
-
}
|
|
271
|
-
]
|
|
272
|
-
}
|
|
273
|
-
```
|
|
74
|
+
---
|
|
274
75
|
|
|
275
|
-
## Rule
|
|
76
|
+
## Rule 2: transition / transitionProperties (StateEffect)
|
|
276
77
|
|
|
277
|
-
|
|
78
|
+
Use `transition` or `transitionProperties` when the hover should toggle styles via DOM attribute change and CSS transitions rather than keyframe animations. Set `stateAction` on the effect to control how the style is applied.
|
|
278
79
|
|
|
279
|
-
|
|
80
|
+
Use `transition` when all properties share timing. Use `transitionProperties` when each property needs independent `duration`, `delay`, or `easing`.
|
|
280
81
|
|
|
281
82
|
```typescript
|
|
282
83
|
{
|
|
283
84
|
key: '[SOURCE_KEY]',
|
|
284
85
|
trigger: 'hover',
|
|
285
|
-
params: {
|
|
286
|
-
type: 'state'
|
|
287
|
-
},
|
|
288
86
|
effects: [
|
|
289
87
|
{
|
|
290
88
|
key: '[TARGET_KEY]',
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
- Same as Rule 1
|
|
303
|
-
|
|
304
|
-
**Use Cases for State Pattern**:
|
|
305
|
-
|
|
306
|
-
- Controlling loop animations
|
|
307
|
-
- Pausing video effects
|
|
308
|
-
- Interactive loading spinners
|
|
309
|
-
- Continuous animation control
|
|
310
|
-
|
|
311
|
-
**Default Values**:
|
|
312
|
-
|
|
313
|
-
- `type`: 'state'
|
|
314
|
-
- `iterations`: Infinity
|
|
315
|
-
- `DURATION_MS`: 2000 (longer for smooth loops)
|
|
316
|
-
- `EASING_FUNCTION`: 'linear' (for continuous motion)
|
|
317
|
-
|
|
318
|
-
**Example Generations**:
|
|
319
|
-
|
|
320
|
-
```typescript
|
|
321
|
-
// Rotating loader that plays on hover and pauses on mouse leave
|
|
322
|
-
{
|
|
323
|
-
key: 'loading-spinner',
|
|
324
|
-
trigger: 'hover',
|
|
325
|
-
params: {
|
|
326
|
-
type: 'state'
|
|
327
|
-
},
|
|
328
|
-
effects: [
|
|
329
|
-
{
|
|
330
|
-
key: 'loading-spinner',
|
|
331
|
-
keyframeEffect: {
|
|
332
|
-
name: 'spin',
|
|
333
|
-
keyframes: [
|
|
334
|
-
{ transform: 'rotate(0deg)' },
|
|
335
|
-
{ transform: 'rotate(360deg)' }
|
|
89
|
+
stateAction: '[STATE_ACTION]',
|
|
90
|
+
|
|
91
|
+
// --- pick ONE of the two transition forms ---
|
|
92
|
+
transition: {
|
|
93
|
+
duration: [DURATION_MS],
|
|
94
|
+
delay: [DELAY_MS],
|
|
95
|
+
easing: '[EASING_FUNCTION]',
|
|
96
|
+
styleProperties: [
|
|
97
|
+
{ name: '[CSS_PROP]', value: '[VALUE]' },
|
|
98
|
+
// ... more properties
|
|
336
99
|
]
|
|
337
100
|
},
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
params: {
|
|
350
|
-
type: 'state'
|
|
351
|
-
},
|
|
352
|
-
effects: [
|
|
353
|
-
{
|
|
354
|
-
key: 'live-indicator',
|
|
355
|
-
namedEffect: {
|
|
356
|
-
type: 'Pulse'
|
|
357
|
-
},
|
|
358
|
-
duration: 1500,
|
|
359
|
-
iterations: Infinity,
|
|
360
|
-
easing: 'ease-in-out'
|
|
361
|
-
}
|
|
362
|
-
]
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
## Rule 5: Multi-Target Hover Effects
|
|
367
|
-
|
|
368
|
-
**Purpose**: Generate hover interactions that affect multiple elements from a single source
|
|
369
|
-
|
|
370
|
-
**Pattern**:
|
|
371
|
-
|
|
372
|
-
```typescript
|
|
373
|
-
{
|
|
374
|
-
key: '[SOURCE_KEY]',
|
|
375
|
-
trigger: 'hover',
|
|
376
|
-
params: {
|
|
377
|
-
type: '[BEHAVIOR_TYPE]'
|
|
378
|
-
},
|
|
379
|
-
effects: [
|
|
380
|
-
{
|
|
381
|
-
key: '[TARGET_1]',
|
|
382
|
-
[EFFECT_TYPE]: [EFFECT_DEFINITION_1],
|
|
383
|
-
fill: [FILL_1],
|
|
384
|
-
reversed: [REVERSED_BOOL_1],
|
|
385
|
-
duration: [DURATION_1],
|
|
386
|
-
delay: [DELAY_1]
|
|
101
|
+
// OR (when each property needs its own timing)
|
|
102
|
+
transitionProperties: [
|
|
103
|
+
{
|
|
104
|
+
name: '[CSS_PROP]',
|
|
105
|
+
value: '[VALUE]',
|
|
106
|
+
duration: [DURATION_MS],
|
|
107
|
+
delay: [DELAY_MS],
|
|
108
|
+
easing: '[EASING_FUNCTION]'
|
|
109
|
+
},
|
|
110
|
+
// ... more properties
|
|
111
|
+
]
|
|
387
112
|
},
|
|
388
|
-
|
|
389
|
-
key: '[TARGET_2]',
|
|
390
|
-
[EFFECT_TYPE]: [EFFECT_DEFINITION_2],
|
|
391
|
-
fill: [FILL_2],
|
|
392
|
-
reversed: [REVERSED_BOOL_2],
|
|
393
|
-
duration: [DURATION_2],
|
|
394
|
-
delay: [DELAY_2]
|
|
395
|
-
}
|
|
113
|
+
// additional effects targeting other elements can be added here
|
|
396
114
|
]
|
|
397
115
|
}
|
|
398
116
|
```
|
|
399
117
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
- `[BEHAVIOR_TYPE]`: type of behavior for the effect. use `alternate`, `repeat`, or `state` according to the previous rules.
|
|
403
|
-
- `[FILL_N]`: Optional fill value for the Nth effect - same as CSS animation-fill-mode (e.g. 'both', 'forwards', 'backwards').
|
|
404
|
-
- `[REVERSED_BOOL_N]`: Same as `[REVERSED_BOOL]` from Rule 2 only for the Nth effect.
|
|
405
|
-
- `[DURATION_N]`: Same as `[DURATION_MS]` from Rule 1 only for the Nth effect.
|
|
406
|
-
- `[DELAY_N]`: Delay in milliseconds of the Nth effect.
|
|
118
|
+
### Variables
|
|
407
119
|
|
|
408
|
-
|
|
120
|
+
- `[SOURCE_KEY]` / `[TARGET_KEY]` — same as Rule 1.
|
|
121
|
+
- `[STATE_ACTION]` — `stateAction` on the effect. One of:
|
|
122
|
+
- `'toggle'` — applies the style state on enter, removes on leave. Default.
|
|
123
|
+
- `'add'` — applies the style state on enter. Leave does NOT remove it.
|
|
124
|
+
- `'remove'` — removes a previously applied style state on enter. Use with provided `effectId` to map to a matching interaction with `add` and effect with same `effectId`.
|
|
125
|
+
- `'clear'` — clears all previously applied style states on enter. Use to reset multiple stacked `'add'` style changes at once (e.g. a "reset" hover area that undoes several accumulated states).
|
|
126
|
+
- `[CSS_PROP]` — CSS property name as a string in camelCase format (e.g. `'backgroundColor'`, `'borderRadius'`, `'opacity'`).
|
|
127
|
+
- `[VALUE]` — target CSS value for the property.
|
|
128
|
+
- `[DURATION_MS]` — transition duration in milliseconds.
|
|
129
|
+
- `[DELAY_MS]` — optional transition delay in milliseconds.
|
|
130
|
+
- `[EASING_FUNCTION]` — CSS easing string, or named easing from `@wix/motion`.
|
|
409
131
|
|
|
410
|
-
|
|
411
|
-
- Navigation item hover affecting icon and text
|
|
412
|
-
- Complex component state changes
|
|
413
|
-
|
|
414
|
-
**Timing Strategies**:
|
|
132
|
+
---
|
|
415
133
|
|
|
416
|
-
|
|
417
|
-
- Staggered: Incrementing delays (0, 50, 100ms)
|
|
418
|
-
- Sequential: Non-overlapping delays
|
|
134
|
+
## Rule 3: customEffect (TimeEffect)
|
|
419
135
|
|
|
420
|
-
|
|
136
|
+
Use `customEffect` when you need imperative control over the animation (e.g. counters, canvas drawing, custom DOM manipulation). The callback receives the target element and a `progress` value (0–1) driven by the animation timeline.
|
|
421
137
|
|
|
422
138
|
```typescript
|
|
423
|
-
// Product card with multiple targets
|
|
424
139
|
{
|
|
425
|
-
key: '
|
|
140
|
+
key: '[SOURCE_KEY]',
|
|
426
141
|
trigger: 'hover',
|
|
427
|
-
params: {
|
|
428
|
-
type: 'alternate'
|
|
429
|
-
},
|
|
430
142
|
effects: [
|
|
431
143
|
{
|
|
432
|
-
key: '
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
{ transform: 'translateY(-8px)' }
|
|
438
|
-
]
|
|
439
|
-
},
|
|
440
|
-
fill: 'both',
|
|
441
|
-
duration: 200,
|
|
442
|
-
delay: 0
|
|
443
|
-
},
|
|
444
|
-
{
|
|
445
|
-
key: 'product-image',
|
|
446
|
-
keyframeEffect: {
|
|
447
|
-
name: 'product-image-scale',
|
|
448
|
-
keyframes: [
|
|
449
|
-
{ transform: 'scale(1)' },
|
|
450
|
-
{ transform: 'scale(1.05)' }
|
|
451
|
-
]
|
|
452
|
-
},
|
|
453
|
-
fill: 'both',
|
|
454
|
-
duration: 300,
|
|
455
|
-
delay: 50
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
key: 'product-title',
|
|
459
|
-
keyframeEffect: {
|
|
460
|
-
name: 'product-title-color',
|
|
461
|
-
keyframes: [
|
|
462
|
-
{ color: '#374151' },
|
|
463
|
-
{ color: '#2563eb' }
|
|
464
|
-
]
|
|
465
|
-
},
|
|
466
|
-
fill: 'both',
|
|
467
|
-
duration: 150,
|
|
468
|
-
delay: 100
|
|
144
|
+
key: '[TARGET_KEY]',
|
|
145
|
+
triggerType: '[TRIGGER_TYPE]',
|
|
146
|
+
customEffect: [CUSTOM_EFFECT_CALLBACK],
|
|
147
|
+
duration: [DURATION_MS],
|
|
148
|
+
easing: '[EASING_FUNCTION]'
|
|
469
149
|
},
|
|
470
|
-
|
|
471
|
-
key: 'add-to-cart-btn',
|
|
472
|
-
keyframeEffect: {
|
|
473
|
-
name: 'button-fade',
|
|
474
|
-
keyframes: [
|
|
475
|
-
{ opacity: '0', transform: 'translateY(10px)' },
|
|
476
|
-
{ opacity: '1', transform: 'translateY(0)' }
|
|
477
|
-
]
|
|
478
|
-
},
|
|
479
|
-
fill: 'both',
|
|
480
|
-
duration: 200,
|
|
481
|
-
delay: 150
|
|
482
|
-
}
|
|
150
|
+
// additional effects targeting other elements can be added here
|
|
483
151
|
]
|
|
484
152
|
}
|
|
485
153
|
```
|
|
486
154
|
|
|
487
|
-
|
|
155
|
+
### Variables
|
|
488
156
|
|
|
489
|
-
|
|
157
|
+
- `[SOURCE_KEY]` / `[TARGET_KEY]` / `[TRIGGER_TYPE]` — same as Rule 1.
|
|
158
|
+
- `[CUSTOM_EFFECT_CALLBACK]` — function with signature `(target: HTMLElement, progress: number) => void`. Called on each animation frame with the target element and `progress` from 0 to 1.
|
|
159
|
+
- `[DURATION_MS]` — animation duration in milliseconds.
|
|
160
|
+
- `[EASING_FUNCTION]` — CSS easing string, or named easing from `@wix/motion`.
|
|
490
161
|
|
|
491
|
-
|
|
162
|
+
---
|
|
492
163
|
|
|
493
|
-
|
|
494
|
-
- For list item hover effects with coordinated timing
|
|
495
|
-
- When you want easing-controlled stagger on hover
|
|
164
|
+
## Rule 4: Sequences
|
|
496
165
|
|
|
497
|
-
|
|
166
|
+
Use sequences when a hover should sync/stagger animations across multiple elements. Set `triggerType` on the sequence config to control playback behavior.
|
|
498
167
|
|
|
499
168
|
```typescript
|
|
500
169
|
{
|
|
501
170
|
key: '[SOURCE_KEY]',
|
|
502
171
|
trigger: 'hover',
|
|
503
|
-
params: {
|
|
504
|
-
type: 'repeat'
|
|
505
|
-
},
|
|
506
172
|
sequences: [
|
|
507
173
|
{
|
|
174
|
+
triggerType: '[TRIGGER_TYPE]',
|
|
508
175
|
offset: [OFFSET_MS],
|
|
509
176
|
offsetEasing: '[OFFSET_EASING]',
|
|
510
177
|
effects: [
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
listContainer: '[LIST_CONTAINER_SELECTOR]'
|
|
514
|
-
}
|
|
178
|
+
[EFFECT_DEFINTION],
|
|
179
|
+
// .. more effects as necessary
|
|
515
180
|
]
|
|
516
181
|
}
|
|
517
182
|
]
|
|
518
183
|
}
|
|
519
184
|
```
|
|
520
185
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
```typescript
|
|
524
|
-
{
|
|
525
|
-
key: 'card-grid',
|
|
526
|
-
trigger: 'hover',
|
|
527
|
-
params: { type: 'repeat' },
|
|
528
|
-
sequences: [
|
|
529
|
-
{
|
|
530
|
-
offset: 80,
|
|
531
|
-
offsetEasing: 'sineOut',
|
|
532
|
-
effects: [
|
|
533
|
-
{
|
|
534
|
-
effectId: 'item-pop',
|
|
535
|
-
listContainer: '.card-grid-items'
|
|
536
|
-
}
|
|
537
|
-
]
|
|
538
|
-
}
|
|
539
|
-
]
|
|
540
|
-
}
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
```typescript
|
|
544
|
-
effects: {
|
|
545
|
-
'item-pop': {
|
|
546
|
-
duration: 400,
|
|
547
|
-
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
548
|
-
keyframeEffect: {
|
|
549
|
-
name: 'item-pop',
|
|
550
|
-
keyframes: [
|
|
551
|
-
{ transform: 'translateY(16px) scale(0.95)', opacity: 0 },
|
|
552
|
-
{ transform: 'translateY(0) scale(1)', opacity: 1 }
|
|
553
|
-
]
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
---
|
|
560
|
-
|
|
561
|
-
## Best Practices for Hover Rules
|
|
562
|
-
|
|
563
|
-
### Timing and Pattern Guidelines
|
|
564
|
-
|
|
565
|
-
1. **Keep durations short** (100-400ms) for responsiveness
|
|
566
|
-
|
|
567
|
-
### User Experience Guidelines
|
|
568
|
-
|
|
569
|
-
1. **Use 'alternate' type** for most hover effects (natural enter/leave)
|
|
570
|
-
2. **Use 'repeat' sparingly** - can be annoying if overused
|
|
571
|
-
3. **Use 'state' for controlling** ongoing animations
|
|
572
|
-
4. **Stagger multi-target effects** for more polished feel
|
|
573
|
-
|
|
574
|
-
### Timing Recommendations
|
|
575
|
-
|
|
576
|
-
- **Micro-interactions**: 100-200ms
|
|
577
|
-
- **Button hovers**: 200-300ms
|
|
578
|
-
- **Card/image effects**: 300-400ms
|
|
579
|
-
- **Complex multi-target**: 200-500ms total
|
|
580
|
-
|
|
581
|
-
### Easing Recommendations
|
|
582
|
-
|
|
583
|
-
- **Enter animations**: 'ease-out' (quick start, slow end)
|
|
584
|
-
- **Interactive elements**: 'ease-in-out' (smooth both ways)
|
|
585
|
-
- **Attention effects**: 'ease-in-out' (natural feel)
|
|
586
|
-
- **Continuous motion**: 'linear' (consistent speed)
|
|
587
|
-
|
|
588
|
-
## Accessibility
|
|
589
|
-
|
|
590
|
-
Use `@wix/interact`'s `conditions` API to skip hover animations for users who prefer reduced motion. Define a `prefers-motion` condition and reference it on any interaction that should be suppressed:
|
|
591
|
-
|
|
592
|
-
```typescript
|
|
593
|
-
{
|
|
594
|
-
conditions: {
|
|
595
|
-
'prefers-motion': { type: 'media', predicate: '(prefers-reduced-motion: no-preference)' }
|
|
596
|
-
},
|
|
597
|
-
interactions: [
|
|
598
|
-
{
|
|
599
|
-
key: 'card',
|
|
600
|
-
trigger: 'hover',
|
|
601
|
-
conditions: ['prefers-motion'], // skipped when reduced-motion is preferred
|
|
602
|
-
effects: [/* ... */]
|
|
603
|
-
}
|
|
604
|
-
]
|
|
605
|
-
}
|
|
606
|
-
```
|
|
607
|
-
|
|
608
|
-
For pointer-primary devices only, also consider adding a `hover-capable` condition:
|
|
609
|
-
|
|
610
|
-
```typescript
|
|
611
|
-
'hover-capable': { type: 'media', predicate: '(hover: hover)' }
|
|
612
|
-
```
|
|
186
|
+
### Variables
|
|
613
187
|
|
|
614
|
-
|
|
188
|
+
- `[SOURCE_KEY]` / `[TRIGGER_TYPE]` — same as Rule 1. `triggerType` is set on the sequence config, not on individual effects within the sequence.
|
|
189
|
+
- `[OFFSET_MS]` — time offset for staggering each child's animation start, in milliseconds.
|
|
190
|
+
- `[OFFSET_EASING]` — easing curve for the offset staggering distribution. CSS easing string, or named easing from `@wix/motion`. Defaults to `'linear'`.
|
|
191
|
+
- `[EFFECT_DEFINTION]` — a definition of or a reference to a time-based animation effect.
|