@wix/interact 1.93.0 → 2.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/dist/cjs/index.js +2 -23
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/react.js +15 -0
  4. package/dist/cjs/react.js.map +1 -0
  5. package/dist/cjs/web.js +2 -0
  6. package/dist/cjs/web.js.map +1 -0
  7. package/dist/es/index.js +8 -0
  8. package/dist/es/index.js.map +1 -0
  9. package/dist/es/react.js +650 -0
  10. package/dist/es/react.js.map +1 -0
  11. package/dist/es/web.js +56 -0
  12. package/dist/es/web.js.map +1 -0
  13. package/dist/index-C8QxOkui.mjs +7940 -0
  14. package/dist/index-C8QxOkui.mjs.map +1 -0
  15. package/dist/index-DEPRHaUt.js +18 -0
  16. package/dist/index-DEPRHaUt.js.map +1 -0
  17. package/dist/tsconfig.build.tsbuildinfo +1 -0
  18. package/dist/types/core/Interact.d.ts +17 -7
  19. package/dist/types/core/Interact.d.ts.map +1 -0
  20. package/dist/types/core/InteractionController.d.ts +19 -0
  21. package/dist/types/core/InteractionController.d.ts.map +1 -0
  22. package/dist/types/core/add.d.ts +4 -3
  23. package/dist/types/core/add.d.ts.map +1 -0
  24. package/dist/types/core/css.d.ts +3 -0
  25. package/dist/types/core/css.d.ts.map +1 -0
  26. package/dist/types/core/remove.d.ts +3 -1
  27. package/dist/types/core/remove.d.ts.map +1 -0
  28. package/dist/types/core/utilities.d.ts +1 -0
  29. package/dist/types/core/utilities.d.ts.map +1 -0
  30. package/dist/types/dom/api.d.ts +3 -0
  31. package/dist/types/dom/api.d.ts.map +1 -0
  32. package/dist/types/handlers/animationEnd.d.ts +3 -2
  33. package/dist/types/handlers/animationEnd.d.ts.map +1 -0
  34. package/dist/types/handlers/click.d.ts +3 -2
  35. package/dist/types/handlers/click.d.ts.map +1 -0
  36. package/dist/types/handlers/hover.d.ts +3 -2
  37. package/dist/types/handlers/hover.d.ts.map +1 -0
  38. package/dist/types/handlers/index.d.ts +1 -0
  39. package/dist/types/handlers/index.d.ts.map +1 -0
  40. package/dist/types/handlers/pointerMove.d.ts +3 -2
  41. package/dist/types/handlers/pointerMove.d.ts.map +1 -0
  42. package/dist/types/handlers/utilities.d.ts +1 -0
  43. package/dist/types/handlers/utilities.d.ts.map +1 -0
  44. package/dist/types/handlers/viewEnter.d.ts +3 -2
  45. package/dist/types/handlers/viewEnter.d.ts.map +1 -0
  46. package/dist/types/handlers/viewProgress.d.ts +4 -3
  47. package/dist/types/handlers/viewProgress.d.ts.map +1 -0
  48. package/dist/types/index.d.ts +3 -2
  49. package/dist/types/index.d.ts.map +1 -0
  50. package/dist/types/react/Interaction.d.ts +10 -0
  51. package/dist/types/react/Interaction.d.ts.map +1 -0
  52. package/dist/types/react/index.d.ts +8 -0
  53. package/dist/types/react/index.d.ts.map +1 -0
  54. package/dist/types/react/interactRef.d.ts +3 -0
  55. package/dist/types/react/interactRef.d.ts.map +1 -0
  56. package/dist/types/types.d.ts +23 -10
  57. package/dist/types/types.d.ts.map +1 -0
  58. package/dist/types/utils.d.ts +2 -1
  59. package/dist/types/utils.d.ts.map +1 -0
  60. package/dist/types/{InteractElement.d.ts → web/InteractElement.d.ts} +115 -77
  61. package/dist/types/web/InteractElement.d.ts.map +1 -0
  62. package/dist/types/web/defineInteractElement.d.ts +2 -0
  63. package/dist/types/web/defineInteractElement.d.ts.map +1 -0
  64. package/dist/types/web/index.d.ts +6 -0
  65. package/dist/types/web/index.d.ts.map +1 -0
  66. package/docs/README.md +211 -0
  67. package/docs/advanced/README.md +164 -0
  68. package/docs/api/README.md +157 -0
  69. package/docs/api/element-selection.md +607 -0
  70. package/docs/api/functions.md +638 -0
  71. package/docs/api/interact-class.md +663 -0
  72. package/docs/api/interact-element.md +565 -0
  73. package/docs/api/interaction-controller.md +450 -0
  74. package/docs/api/types.md +957 -0
  75. package/docs/examples/README.md +212 -0
  76. package/docs/examples/click-interactions.md +977 -0
  77. package/docs/examples/entrance-animations.md +935 -0
  78. package/docs/examples/hover-effects.md +930 -0
  79. package/docs/examples/list-patterns.md +737 -0
  80. package/docs/guides/README.md +49 -0
  81. package/docs/guides/conditions-and-media-queries.md +1068 -0
  82. package/docs/guides/configuration-structure.md +726 -0
  83. package/docs/guides/custom-elements.md +327 -0
  84. package/docs/guides/effects-and-animations.md +634 -0
  85. package/docs/guides/getting-started.md +379 -0
  86. package/docs/guides/lists-and-dynamic-content.md +713 -0
  87. package/docs/guides/state-management.md +747 -0
  88. package/docs/guides/understanding-triggers.md +690 -0
  89. package/docs/integration/README.md +264 -0
  90. package/docs/integration/react.md +605 -0
  91. package/package.json +73 -56
  92. package/rules/Integration.md +255 -0
  93. package/rules/click-rules.md +533 -0
  94. package/rules/full-lean.md +346 -0
  95. package/rules/hover-rules.md +593 -0
  96. package/rules/pointermove-rules.md +1341 -0
  97. package/rules/scroll-list-rules.md +900 -0
  98. package/rules/viewenter-rules.md +1015 -0
  99. package/rules/viewprogress-rules.md +1044 -0
  100. package/dist/cjs/InteractElement.js +0 -163
  101. package/dist/cjs/InteractElement.js.map +0 -1
  102. package/dist/cjs/__tests__/interact.spec.js +0 -2094
  103. package/dist/cjs/__tests__/interact.spec.js.map +0 -1
  104. package/dist/cjs/__tests__/viewEnter.spec.js +0 -207
  105. package/dist/cjs/__tests__/viewEnter.spec.js.map +0 -1
  106. package/dist/cjs/core/Interact.js +0 -257
  107. package/dist/cjs/core/Interact.js.map +0 -1
  108. package/dist/cjs/core/add.js +0 -250
  109. package/dist/cjs/core/add.js.map +0 -1
  110. package/dist/cjs/core/remove.js +0 -35
  111. package/dist/cjs/core/remove.js.map +0 -1
  112. package/dist/cjs/core/utilities.js +0 -16
  113. package/dist/cjs/core/utilities.js.map +0 -1
  114. package/dist/cjs/external-types.d.js +0 -2
  115. package/dist/cjs/external-types.d.js.map +0 -1
  116. package/dist/cjs/handlers/animationEnd.js +0 -37
  117. package/dist/cjs/handlers/animationEnd.js.map +0 -1
  118. package/dist/cjs/handlers/click.js +0 -122
  119. package/dist/cjs/handlers/click.js.map +0 -1
  120. package/dist/cjs/handlers/hover.js +0 -147
  121. package/dist/cjs/handlers/hover.js.map +0 -1
  122. package/dist/cjs/handlers/index.js +0 -32
  123. package/dist/cjs/handlers/index.js.map +0 -1
  124. package/dist/cjs/handlers/pointerMove.js +0 -49
  125. package/dist/cjs/handlers/pointerMove.js.map +0 -1
  126. package/dist/cjs/handlers/utilities.js +0 -49
  127. package/dist/cjs/handlers/utilities.js.map +0 -1
  128. package/dist/cjs/handlers/viewEnter.js +0 -131
  129. package/dist/cjs/handlers/viewEnter.js.map +0 -1
  130. package/dist/cjs/handlers/viewProgress.js +0 -79
  131. package/dist/cjs/handlers/viewProgress.js.map +0 -1
  132. package/dist/cjs/test-types.d.js +0 -2
  133. package/dist/cjs/test-types.d.js.map +0 -1
  134. package/dist/cjs/types.js +0 -2
  135. package/dist/cjs/types.js.map +0 -1
  136. package/dist/cjs/utils.js +0 -98
  137. package/dist/cjs/utils.js.map +0 -1
  138. package/dist/esm/InteractElement.js +0 -157
  139. package/dist/esm/InteractElement.js.map +0 -1
  140. package/dist/esm/__tests__/interact.spec.js +0 -2102
  141. package/dist/esm/__tests__/interact.spec.js.map +0 -1
  142. package/dist/esm/__tests__/viewEnter.spec.js +0 -210
  143. package/dist/esm/__tests__/viewEnter.spec.js.map +0 -1
  144. package/dist/esm/core/Interact.js +0 -251
  145. package/dist/esm/core/Interact.js.map +0 -1
  146. package/dist/esm/core/add.js +0 -245
  147. package/dist/esm/core/add.js.map +0 -1
  148. package/dist/esm/core/remove.js +0 -30
  149. package/dist/esm/core/remove.js.map +0 -1
  150. package/dist/esm/core/utilities.js +0 -14
  151. package/dist/esm/core/utilities.js.map +0 -1
  152. package/dist/esm/external-types.d.js +0 -2
  153. package/dist/esm/external-types.d.js.map +0 -1
  154. package/dist/esm/handlers/animationEnd.js +0 -33
  155. package/dist/esm/handlers/animationEnd.js.map +0 -1
  156. package/dist/esm/handlers/click.js +0 -122
  157. package/dist/esm/handlers/click.js.map +0 -1
  158. package/dist/esm/handlers/hover.js +0 -147
  159. package/dist/esm/handlers/hover.js.map +0 -1
  160. package/dist/esm/handlers/index.js +0 -27
  161. package/dist/esm/handlers/index.js.map +0 -1
  162. package/dist/esm/handlers/pointerMove.js +0 -48
  163. package/dist/esm/handlers/pointerMove.js.map +0 -1
  164. package/dist/esm/handlers/utilities.js +0 -43
  165. package/dist/esm/handlers/utilities.js.map +0 -1
  166. package/dist/esm/handlers/viewEnter.js +0 -133
  167. package/dist/esm/handlers/viewEnter.js.map +0 -1
  168. package/dist/esm/handlers/viewProgress.js +0 -75
  169. package/dist/esm/handlers/viewProgress.js.map +0 -1
  170. package/dist/esm/index.js +0 -5
  171. package/dist/esm/index.js.map +0 -1
  172. package/dist/esm/test-types.d.js +0 -2
  173. package/dist/esm/test-types.d.js.map +0 -1
  174. package/dist/esm/types.js +0 -2
  175. package/dist/esm/types.js.map +0 -1
  176. package/dist/esm/utils.js +0 -92
  177. package/dist/esm/utils.js.map +0 -1
  178. package/dist/types/__tests__/interact.spec.d.ts +0 -1
  179. package/dist/types/__tests__/viewEnter.spec.d.ts +0 -0
@@ -0,0 +1,1068 @@
1
+ # Conditions and Media Queries
2
+
3
+ Conditions allow you to create responsive interactions that adapt to different screen sizes, user preferences, and environmental factors. This guide explains how to build adaptive interactions using media queries and container queries.
4
+
5
+ ## Overview of Conditions
6
+
7
+ Conditions in `@wix/interact` act as filters that determine when interactions should be active. They enable you to:
8
+
9
+ - **Create responsive animations** that work across devices
10
+ - **Respect user preferences** like reduced motion
11
+ - **Adapt to container sizes** with container queries
12
+ - **Build progressive enhancement** for different capabilities
13
+
14
+ ## Types of Conditions
15
+
16
+ ### Media Conditions
17
+ Use CSS media queries to target device characteristics:
18
+
19
+ ```typescript
20
+ {
21
+ conditions: {
22
+ 'desktop-only': {
23
+ type: 'media',
24
+ predicate: '(min-width: 768px)'
25
+ },
26
+ 'mobile-only': {
27
+ type: 'media',
28
+ predicate: '(max-width: 767px)'
29
+ },
30
+ 'prefers-motion': {
31
+ type: 'media',
32
+ predicate: '(prefers-reduced-motion: no-preference)'
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### Container Conditions
39
+ Use container queries to respond to element size:
40
+
41
+ ```typescript
42
+ {
43
+ conditions: {
44
+ 'large-card': {
45
+ type: 'container',
46
+ predicate: '(min-width: 400px)'
47
+ },
48
+ 'tall-container': {
49
+ type: 'container',
50
+ predicate: '(min-height: 300px)'
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## Cascading of effects
57
+
58
+ Interact allows you to apply multiple effects on the same target and have them cascade, just like they do in CSS.
59
+ This allows you to have different variations of effects for different `media`/`contianer` `conditions` and have only one of them apply, base on the current environment of the user.
60
+
61
+ **Important**: In order to use this cascading behavior, `conditions` need to be set on the Effect-level, and not on the Interaction-level.
62
+
63
+ The cascading logic works as follows:
64
+
65
+ 1. Effects that are grouped in the same `effects` array under the same interaction
66
+ 2. Effects that share the same `key`
67
+ 3. Last effect in the `effects` array wins - just like in CSS
68
+
69
+ ### Example
70
+
71
+ Here is a mobile-first example for a slide effect of a card:
72
+
73
+ ```typescript
74
+ const responsiveConfig: InteractConfig = {
75
+ conditions: {
76
+ 'desktop': {
77
+ type: 'media',
78
+ predicate: '(min-width: 1024px)'
79
+ },
80
+ 'tablet': {
81
+ type: 'media',
82
+ predicate: '(min-width: 768px) and (max-width: 1023px)'
83
+ },
84
+ 'mobile': {
85
+ type: 'media',
86
+ predicate: '(max-width: 767px)'
87
+ }
88
+ },
89
+ effects: {
90
+ 'light-slide': {
91
+ keyframeEffect: {
92
+ name: 'light-slide',
93
+ keyframes: [
94
+ { transform: 'translateY(-100px)' },
95
+ { transform: 'translateY(0)' }
96
+ ]
97
+ },
98
+ duration: 400,
99
+ easing: 'ease-out'
100
+ },
101
+ 'medium-slide': {
102
+ keyframeEffect: {
103
+ name: 'medium-slide',
104
+ keyframes: [
105
+ { transform: 'translateY(-50%)' },
106
+ { transform: 'translateY(0)' }
107
+ ]
108
+ },
109
+ duration: 400,
110
+ easing: 'ease-in-out'
111
+ },
112
+ 'hard-slide': {
113
+ keyframeEffect: {
114
+ name: 'hard-slide',
115
+ keyframes: [
116
+ { transform: 'translateY(-100%)' },
117
+ { transform: 'translateY(0)' }
118
+ ]
119
+ },
120
+ duration: 600,
121
+ easing: 'backOut'
122
+ }
123
+ },
124
+ interactions: [
125
+ {
126
+ key: '.product-card',
127
+ trigger: 'viewEnter',
128
+ effects: [
129
+ {
130
+ conditions: ['desktop'],
131
+ effectId: 'light-slide'
132
+ },
133
+ {
134
+ conditions: ['tablet'],
135
+ effectId: 'medium-slide'
136
+ },
137
+ {
138
+ conditions: ['mobile'],
139
+ effectId: 'hard-slide'
140
+ }
141
+ ]
142
+ },
143
+ ]
144
+ };
145
+ ```
146
+
147
+ ## Responsive Interaction Patterns
148
+
149
+ ### Desktop vs Mobile Interactions
150
+
151
+ ```typescript
152
+ const responsiveConfig: InteractConfig = {
153
+ conditions: {
154
+ 'desktop': {
155
+ type: 'media',
156
+ predicate: '(min-width: 1024px)'
157
+ },
158
+ 'tablet': {
159
+ type: 'media',
160
+ predicate: '(min-width: 768px) and (max-width: 1023px)'
161
+ },
162
+ 'mobile': {
163
+ type: 'media',
164
+ predicate: '(max-width: 767px)'
165
+ }
166
+ },
167
+
168
+ interactions: [
169
+ // Desktop: Hover effects
170
+ {
171
+ key: 'product-card',
172
+ trigger: 'hover',
173
+ conditions: ['desktop'],
174
+ effects: [
175
+ {
176
+ key: 'product-card',
177
+ keyframeEffect: {
178
+ name: 'product-card-kf-desktop',
179
+ keyframes: [
180
+ { transform: 'translateY(0)', boxShadow: '0 4px 6px rgba(0,0,0,0.1)' },
181
+ { transform: 'translateY(-8px)', boxShadow: '0 20px 25px rgba(0,0,0,0.15)' }
182
+ ]
183
+ },
184
+ duration: 200,
185
+ easing: 'ease-out'
186
+ }
187
+ ]
188
+ },
189
+
190
+ // Mobile: Touch feedback
191
+ {
192
+ key: 'product-card',
193
+ trigger: 'click',
194
+ conditions: ['mobile'],
195
+ effects: [
196
+ {
197
+ key: 'product-card',
198
+ keyframeEffect: {
199
+ name: 'product-card-kf-mobile',
200
+ keyframes: [
201
+ { transform: 'scale(1)' },
202
+ { transform: 'scale(0.98)' },
203
+ { transform: 'scale(1)' }
204
+ ]
205
+ },
206
+ duration: 150,
207
+ easing: 'ease-in-out'
208
+ }
209
+ ]
210
+ }
211
+ ]
212
+ };
213
+ ```
214
+
215
+ ### Accessibility-Aware Animations
216
+
217
+ ```typescript
218
+ const accessibleConfig: InteractConfig = {
219
+ conditions: {
220
+ 'motion-ok': {
221
+ type: 'media',
222
+ predicate: '(prefers-reduced-motion: no-preference)'
223
+ },
224
+ 'motion-reduced': {
225
+ type: 'media',
226
+ predicate: '(prefers-reduced-motion: reduce)'
227
+ },
228
+ 'high-contrast': {
229
+ type: 'media',
230
+ predicate: '(prefers-contrast: high)'
231
+ }
232
+ },
233
+
234
+ interactions: [
235
+ // Full animation for users who prefer motion
236
+ {
237
+ key: 'hero-title',
238
+ trigger: 'viewEnter',
239
+ conditions: ['motion-ok'],
240
+ params: { type: 'once', threshold: 0.3 },
241
+ effects: [
242
+ {
243
+ key: 'hero-title',
244
+ keyframeEffect: {
245
+ name: 'fade-move',
246
+ keyframes: [
247
+ { opacity: '0', transform: 'translateY(50px) rotate(-2deg)' },
248
+ { opacity: '1', transform: 'translateY(0) rotate(0deg)' }
249
+ ]
250
+ },
251
+ duration: 800,
252
+ easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
253
+ }
254
+ ]
255
+ },
256
+
257
+ // Subtle animation for reduced motion users
258
+ {
259
+ key: 'hero-title',
260
+ trigger: 'viewEnter',
261
+ conditions: ['motion-reduced'],
262
+ params: { type: 'once', threshold: 0.3 },
263
+ effects: [
264
+ {
265
+ key: 'hero-title',
266
+ keyframeEffect: {
267
+ name: 'fade',
268
+ keyframes: [
269
+ { opacity: '0' },
270
+ { opacity: '1' }
271
+ ]
272
+ },
273
+ duration: 300,
274
+ easing: 'ease-out'
275
+ }
276
+ ]
277
+ }
278
+ ]
279
+ };
280
+ ```
281
+
282
+ ## Device-Specific Patterns
283
+
284
+ ### Touch vs Mouse Devices
285
+
286
+ ```typescript
287
+ const deviceConfig: InteractConfig = {
288
+ conditions: {
289
+ 'touch-device': {
290
+ type: 'media',
291
+ predicate: '(hover: none) and (pointer: coarse)'
292
+ },
293
+ 'mouse-device': {
294
+ type: 'media',
295
+ predicate: '(hover: hover) and (pointer: fine)'
296
+ },
297
+ 'stylus-device': {
298
+ type: 'media',
299
+ predicate: '(hover: hover) and (pointer: coarse)'
300
+ }
301
+ },
302
+
303
+ interactions: [
304
+ // Mouse: Hover interactions
305
+ {
306
+ key: 'interactive-button',
307
+ trigger: 'hover',
308
+ conditions: ['mouse-device'],
309
+ effects: [
310
+ {
311
+ key: 'interactive-button',
312
+ namedEffect: {
313
+ type: 'Scale'
314
+ },
315
+ duration: 200
316
+ }
317
+ ]
318
+ },
319
+
320
+ // Touch: Press feedback
321
+ {
322
+ key: 'interactive-button',
323
+ trigger: 'click',
324
+ conditions: ['touch-device'],
325
+ effects: [
326
+ {
327
+ key: 'interactive-button',
328
+ keyframeEffect: {
329
+ name: 'touch-feedback',
330
+ keyframes: [
331
+ { transform: 'scale(1)', opacity: '1' },
332
+ { transform: 'scale(0.95)', opacity: '0.8' }
333
+ ]
334
+ },
335
+ duration: 100
336
+ }
337
+ ]
338
+ }
339
+ ]
340
+ };
341
+ ```
342
+
343
+ ### Screen Size Breakpoints
344
+
345
+ ```typescript
346
+ const breakpointConfig: InteractConfig = {
347
+ conditions: {
348
+ 'xs': {
349
+ type: 'media',
350
+ predicate: '(max-width: 475px)'
351
+ },
352
+ 'sm': {
353
+ type: 'media',
354
+ predicate: '(min-width: 476px) and (max-width: 640px)'
355
+ },
356
+ 'md': {
357
+ type: 'media',
358
+ predicate: '(min-width: 641px) and (max-width: 768px)'
359
+ },
360
+ 'lg': {
361
+ type: 'media',
362
+ predicate: '(min-width: 769px) and (max-width: 1024px)'
363
+ },
364
+ 'xl': {
365
+ type: 'media',
366
+ predicate: '(min-width: 1025px)'
367
+ }
368
+ },
369
+
370
+ interactions: [
371
+ // Extra small: Minimal animations
372
+ {
373
+ key: 'card',
374
+ trigger: 'viewEnter',
375
+ conditions: ['xs'],
376
+ effects: [
377
+ {
378
+ key: 'card',
379
+ namedEffect: 'FadeIn',
380
+ duration: 400
381
+ }
382
+ ]
383
+ },
384
+
385
+ // Large screens: Full animations
386
+ {
387
+ key: 'card',
388
+ trigger: 'viewEnter',
389
+ conditions: ['lg', 'xl'],
390
+ effects: [
391
+ {
392
+ key: 'card',
393
+ keyframeEffect: {
394
+ name: 'fade-move',
395
+ keyframes: [
396
+ { opacity: '0', transform: 'translateY(60px) scale(0.9)' },
397
+ { opacity: '1', transform: 'translateY(0) scale(1)' }
398
+ ]
399
+ },
400
+ duration: 800,
401
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)'
402
+ }
403
+ ]
404
+ }
405
+ ]
406
+ };
407
+ ```
408
+
409
+ ## Container Query Patterns
410
+
411
+ ### Responsive Cards
412
+
413
+ ```typescript
414
+ const containerConfig: InteractConfig = {
415
+ conditions: {
416
+ 'card-large': {
417
+ type: 'container',
418
+ predicate: '(min-width: 350px)'
419
+ },
420
+ 'card-small': {
421
+ type: 'container',
422
+ predicate: '(max-width: 349px)'
423
+ },
424
+ 'card-tall': {
425
+ type: 'container',
426
+ predicate: '(min-height: 400px)'
427
+ }
428
+ },
429
+
430
+ interactions: [
431
+ // Large cards: Complex hover effect
432
+ {
433
+ key: 'adaptive-card',
434
+ trigger: 'hover',
435
+ conditions: ['card-large'],
436
+ effects: [
437
+ {
438
+ key: 'card-image',
439
+ keyframeEffect: {
440
+ name: 'large-image-kf',
441
+ keyframes: [
442
+ { transform: 'scale(1)', filter: 'brightness(1)' },
443
+ { transform: 'scale(1.1)', filter: 'brightness(1.1)' }
444
+ ]
445
+ },
446
+ duration: 300
447
+ },
448
+ {
449
+ key: 'card-overlay',
450
+ keyframeEffect: {
451
+ name: 'large-overlay-kf',
452
+ keyframes: [
453
+ { opacity: '0', transform: 'translateY(100%)' },
454
+ { opacity: '1', transform: 'translateY(0)' }
455
+ ]
456
+ },
457
+ duration: 250,
458
+ delay: 50
459
+ }
460
+ ]
461
+ },
462
+
463
+ // Small cards: Simple effect
464
+ {
465
+ key: 'adaptive-card',
466
+ trigger: 'hover',
467
+ conditions: ['card-small'],
468
+ effects: [
469
+ {
470
+ key: 'adaptive-card',
471
+ keyframeEffect: {
472
+ name: 'small-kf',
473
+ keyframes: [
474
+ { boxShadow: '0 2px 4px rgba(0,0,0,0.1)' },
475
+ { boxShadow: '0 8px 16px rgba(0,0,0,0.15)' }
476
+ ]
477
+ },
478
+ duration: 200
479
+ }
480
+ ]
481
+ }
482
+ ]
483
+ };
484
+ ```
485
+
486
+ ### Layout-Aware Animations
487
+
488
+ ```typescript
489
+ const layoutConfig: InteractConfig = {
490
+ conditions: {
491
+ 'sidebar-layout': {
492
+ type: 'container',
493
+ predicate: '(min-width: 1200px)'
494
+ },
495
+ 'stack-layout': {
496
+ type: 'container',
497
+ predicate: '(max-width: 1199px)'
498
+ }
499
+ },
500
+
501
+ interactions: [
502
+ // Sidebar layout: Slide from side
503
+ {
504
+ key: 'content-panel',
505
+ trigger: 'viewEnter',
506
+ conditions: ['sidebar-layout'],
507
+ effects: [
508
+ {
509
+ key: 'content-panel',
510
+ keyframeEffect: {
511
+ name: 'slide-from-left',
512
+ keyframes: [
513
+ { transform: 'translateX(-50px)', opacity: '0' },
514
+ { transform: 'translateX(0)', opacity: '1' }
515
+ ]
516
+ },
517
+ duration: 600
518
+ }
519
+ ]
520
+ },
521
+
522
+ // Stack layout: Slide from bottom
523
+ {
524
+ key: 'content-panel',
525
+ trigger: 'viewEnter',
526
+ conditions: ['stack-layout'],
527
+ effects: [
528
+ {
529
+ key: 'content-panel',
530
+ keyframeEffect: {
531
+ name: 'slide-from-bottom',
532
+ keyframes: [
533
+ { transform: 'translateY(30px)', opacity: '0' },
534
+ { transform: 'translateY(0)', opacity: '1' }
535
+ ]
536
+ },
537
+ duration: 600
538
+ }
539
+ ]
540
+ }
541
+ ]
542
+ };
543
+ ```
544
+
545
+ ## Advanced Condition Patterns
546
+
547
+ ### Combining Multiple Conditions
548
+
549
+ ```typescript
550
+ const complexConfig: InteractConfig = {
551
+ conditions: {
552
+ 'desktop': {
553
+ type: 'media',
554
+ predicate: '(min-width: 1024px)'
555
+ },
556
+ 'motion-ok': {
557
+ type: 'media',
558
+ predicate: '(prefers-reduced-motion: no-preference)'
559
+ },
560
+ 'high-res': {
561
+ type: 'media',
562
+ predicate: '(min-resolution: 144dpi)'
563
+ },
564
+ 'wide-container': {
565
+ type: 'container',
566
+ predicate: '(min-width: 600px)'
567
+ }
568
+ },
569
+
570
+ interactions: [
571
+ // Complex animation: desktop + motion ok + wide container
572
+ {
573
+ key: 'hero-animation',
574
+ trigger: 'viewEnter',
575
+ conditions: ['desktop', 'motion-ok', 'wide-container'],
576
+ effects: [
577
+ {
578
+ key: 'hero-background',
579
+ keyframeEffect: {
580
+ name: 'focus-background',
581
+ keyframes: [
582
+ { transform: 'scale(1.1)', filter: 'blur(2px)' },
583
+ { transform: 'scale(1)', filter: 'blur(0)' }
584
+ ]
585
+ },
586
+ duration: 1200,
587
+ easing: 'ease-out'
588
+ },
589
+ {
590
+ key: 'hero-content',
591
+ keyframeEffect: {
592
+ name: 'slide-content',
593
+ keyframes: [
594
+ { opacity: '0', transform: 'translateY(80px)' },
595
+ { opacity: '1', transform: 'translateY(0)' }
596
+ ]
597
+ },
598
+ duration: 800,
599
+ delay: 400
600
+ }
601
+ ]
602
+ }
603
+ ]
604
+ };
605
+ ```
606
+
607
+ ### Orientation-Based Interactions
608
+
609
+ ```typescript
610
+ const orientationConfig: InteractConfig = {
611
+ conditions: {
612
+ 'portrait': {
613
+ type: 'media',
614
+ predicate: '(orientation: portrait)'
615
+ },
616
+ 'landscape': {
617
+ type: 'media',
618
+ predicate: '(orientation: landscape)'
619
+ },
620
+ 'mobile-portrait': {
621
+ type: 'media',
622
+ predicate: '(max-width: 767px) and (orientation: portrait)'
623
+ }
624
+ },
625
+
626
+ interactions: [
627
+ // Portrait: Vertical animations
628
+ {
629
+ key: 'gallery-item',
630
+ trigger: 'viewEnter',
631
+ conditions: ['portrait'],
632
+ effects: [
633
+ {
634
+ key: 'gallery-item',
635
+ keyframeEffect: {
636
+ name: 'vertical-move',
637
+ keyframes: [
638
+ { transform: 'translateY(50px)' },
639
+ { transform: 'translateY(0)' }
640
+ ]
641
+ },
642
+ duration: 500
643
+ }
644
+ ]
645
+ },
646
+
647
+ // Landscape: Horizontal animations
648
+ {
649
+ key: 'gallery-item',
650
+ trigger: 'viewEnter',
651
+ conditions: ['landscape'],
652
+ effects: [
653
+ {
654
+ key: 'gallery-item',
655
+ keyframeEffect: {
656
+ name: 'horizontal-move',
657
+ keyframes: [
658
+ { transform: 'translateX(-50px)' },
659
+ { transform: 'translateX(0)' }
660
+ ]
661
+ },
662
+ duration: 500
663
+ }
664
+ ]
665
+ }
666
+ ]
667
+ };
668
+ ```
669
+
670
+ ## Environment-Based Conditions
671
+
672
+ ### Dark Mode Support
673
+
674
+ ```typescript
675
+ const themeConfig: InteractConfig = {
676
+ conditions: {
677
+ 'dark-mode': {
678
+ type: 'media',
679
+ predicate: '(prefers-color-scheme: dark)'
680
+ },
681
+ 'light-mode': {
682
+ type: 'media',
683
+ predicate: '(prefers-color-scheme: light)'
684
+ }
685
+ },
686
+
687
+ interactions: [
688
+ // Dark mode: Subtle glow effects
689
+ {
690
+ key: 'interactive-element',
691
+ trigger: 'hover',
692
+ conditions: ['dark-mode'],
693
+ effects: [
694
+ {
695
+ key: 'interactive-element',
696
+ keyframeEffect: {
697
+ name: 'glow',
698
+ keyframes: [
699
+ { boxShadow: 'none', borderColor: 'transparent' },
700
+ { boxShadow: '0 0 20px rgba(255,255,255,0.1)', borderColor: 'rgba(255,255,255,0.2)' }
701
+ ]
702
+ },
703
+ duration: 300
704
+ }
705
+ ]
706
+ },
707
+
708
+ // Light mode: Shadow effects
709
+ {
710
+ key: 'interactive-element',
711
+ trigger: 'hover',
712
+ conditions: ['light-mode'],
713
+ effects: [
714
+ {
715
+ key: 'interactive-element',
716
+ keyframeEffect: {
717
+ name: 'shadow',
718
+ keyframes: [
719
+ { boxShadow: '0 2px 4px rgba(0,0,0,0.1)', transform: 'translateY(0)' },
720
+ { boxShadow: '0 8px 16px rgba(0,0,0,0.15)', transform: 'translateY(-2px)' }
721
+ ]
722
+ },
723
+ duration: 300
724
+ }
725
+ ]
726
+ }
727
+ ]
728
+ };
729
+ ```
730
+
731
+ ### Performance-Based Conditions
732
+
733
+ ```typescript
734
+ const performanceConfig: InteractConfig = {
735
+ conditions: {
736
+ 'high-performance': {
737
+ type: 'media',
738
+ predicate: '(prefers-reduced-motion: no-preference) and (min-resolution: 96dpi)'
739
+ },
740
+ 'low-performance': {
741
+ type: 'media',
742
+ predicate: '(prefers-reduced-motion: reduce) or (max-resolution: 95dpi)'
743
+ }
744
+ },
745
+
746
+ interactions: [
747
+ // High performance: Rich animations
748
+ {
749
+ key: 'feature-card',
750
+ trigger: 'viewEnter',
751
+ conditions: ['high-performance'],
752
+ effects: [
753
+ {
754
+ key: 'feature-icon',
755
+ keyframeEffect: {
756
+ name: 'twist',
757
+ keyframes: [
758
+ { transform: 'scale(0.5) rotate(-180deg)', filter: 'blur(10px)' },
759
+ { transform: 'scale(1) rotate(0deg)', filter: 'blur(0)' }
760
+ ]
761
+ },
762
+ duration: 800,
763
+ easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
764
+ }
765
+ ]
766
+ },
767
+
768
+ // Low performance: Simple fade
769
+ {
770
+ key: 'feature-card',
771
+ trigger: 'viewEnter',
772
+ conditions: ['low-performance'],
773
+ effects: [
774
+ {
775
+ key: 'feature-card',
776
+ namedEffect: {
777
+ type: 'FadeIn'
778
+ },
779
+ duration: 400
780
+ }
781
+ ]
782
+ }
783
+ ]
784
+ };
785
+ ```
786
+
787
+ ## Real-World Examples
788
+
789
+ ### E-commerce Product Grid
790
+
791
+ ```typescript
792
+ const productGridConfig: InteractConfig = {
793
+ conditions: {
794
+ 'desktop': {
795
+ type: 'media',
796
+ predicate: '(min-width: 1024px)'
797
+ },
798
+ 'tablet': {
799
+ type: 'media',
800
+ predicate: '(min-width: 768px) and (max-width: 1023px)'
801
+ },
802
+ 'mobile': {
803
+ type: 'media',
804
+ predicate: '(max-width: 767px)'
805
+ },
806
+ 'large-product-card': {
807
+ type: 'container',
808
+ predicate: '(min-width: 300px)'
809
+ },
810
+ 'motion-ok': {
811
+ type: 'media',
812
+ predicate: '(prefers-reduced-motion: no-preference)'
813
+ }
814
+ },
815
+
816
+ interactions: [
817
+ // Desktop: Full hover experience
818
+ {
819
+ key: 'product-card',
820
+ trigger: 'hover',
821
+ conditions: ['desktop', 'large-product-card', 'motion-ok'],
822
+ effects: [
823
+ {
824
+ key: 'product-image',
825
+ keyframeEffect: {
826
+ name: 'scale-light',
827
+ keyframes: [
828
+ { transform: 'scale(1)' },
829
+ { transform: 'scale(1.05)' }
830
+ ]
831
+ },
832
+ duration: 300
833
+ },
834
+ {
835
+ key: 'product-overlay',
836
+ keyframeEffect: {
837
+ name: 'slide-from-bottom',
838
+ keyframes: [
839
+ { opacity: '0', transform: 'translateY(100%)' },
840
+ { opacity: '1', transform: 'translateY(0)' }
841
+ ]
842
+ },
843
+ duration: 250,
844
+ delay: 50
845
+ },
846
+ {
847
+ key: 'quick-view-button',
848
+ keyframeEffect: {
849
+ name: 'scale-medium',
850
+ keyframes: [
851
+ { opacity: '0', transform: 'scale(0.8)' },
852
+ { opacity: '1', transform: 'scale(1)' }
853
+ ]
854
+ },
855
+ duration: 200,
856
+ delay: 150
857
+ }
858
+ ]
859
+ },
860
+
861
+ // Mobile: Touch feedback only
862
+ {
863
+ key: 'product-card',
864
+ trigger: 'click',
865
+ conditions: ['mobile'],
866
+ effects: [
867
+ {
868
+ key: 'product-card',
869
+ keyframeEffect: {
870
+ name: 'touch-feedback',
871
+ keyframes: [
872
+ { transform: 'scale(1)' },
873
+ { transform: 'scale(0.98)' },
874
+ { transform: 'scale(1)' }
875
+ ]
876
+ },
877
+ duration: 150
878
+ }
879
+ ]
880
+ },
881
+
882
+ // Tablet: Intermediate experience
883
+ {
884
+ key: 'product-card',
885
+ trigger: 'click',
886
+ conditions: ['tablet'],
887
+ effects: [
888
+ {
889
+ key: 'product-overlay',
890
+ keyframeEffect: {
891
+ name: 'fade',
892
+ keyframes: [
893
+ { opacity: '0' },
894
+ { opacity: '1' }
895
+ ]
896
+ },
897
+ duration: 200
898
+ }
899
+ ]
900
+ }
901
+ ]
902
+ };
903
+ ```
904
+
905
+ ### Responsive Navigation
906
+
907
+ ```typescript
908
+ const navigationConfig: InteractConfig = {
909
+ conditions: {
910
+ 'mobile': {
911
+ type: 'media',
912
+ predicate: '(max-width: 767px)'
913
+ },
914
+ 'desktop': {
915
+ type: 'media',
916
+ predicate: '(min-width: 768px)'
917
+ },
918
+ 'narrow-header': {
919
+ type: 'container',
920
+ predicate: '(max-width: 800px)'
921
+ }
922
+ },
923
+
924
+ interactions: [
925
+ // Mobile: Slide menu
926
+ {
927
+ key: 'mobile-menu-toggle',
928
+ trigger: 'click',
929
+ conditions: ['mobile'],
930
+ params: { type: 'alternate' },
931
+ effects: [
932
+ {
933
+ key: 'mobile-menu',
934
+ keyframeEffect: {
935
+ name: 'slide',
936
+ keyframes: [
937
+ { transform: 'translateX(-100%)' },
938
+ { transform: 'translateX(0)' }
939
+ ]
940
+ },
941
+ duration: 300,
942
+ easing: 'ease-out'
943
+ },
944
+ {
945
+ key: 'menu-overlay',
946
+ keyframeEffect: {
947
+ name: 'fade',
948
+ keyframes: [
949
+ { opacity: '0' },
950
+ { opacity: '0.5' }
951
+ ]
952
+ },
953
+ duration: 300
954
+ }
955
+ ]
956
+ },
957
+
958
+ // Desktop: Dropdown menus
959
+ {
960
+ key: 'nav-item',
961
+ trigger: 'hover',
962
+ conditions: ['desktop'],
963
+ effects: [
964
+ {
965
+ key: 'dropdown-menu',
966
+ keyframeEffect: {
967
+ name: 'hover-desktop-kf',
968
+ keyframes: [
969
+ { opacity: '0', transform: 'translateY(-10px)' },
970
+ { opacity: '1', transform: 'translateY(0)' }
971
+ ]
972
+ },
973
+ duration: 200
974
+ }
975
+ ]
976
+ }
977
+ ]
978
+ };
979
+ ```
980
+
981
+ ## Best Practices
982
+
983
+ ### Condition Naming
984
+ Use descriptive, semantic names:
985
+
986
+ ```typescript
987
+ // Good
988
+ 'desktop-large': { type: 'media', predicate: '(min-width: 1200px)' }
989
+ 'touch-primary': { type: 'media', predicate: '(pointer: coarse)' }
990
+ 'motion-safe': { type: 'media', predicate: '(prefers-reduced-motion: no-preference)' }
991
+
992
+ // Avoid
993
+ 'condition1': { type: 'media', predicate: '(min-width: 1200px)' }
994
+ 'big': { type: 'media', predicate: '(min-width: 1200px)' }
995
+ ```
996
+
997
+ ### Progressive Enhancement
998
+ Start with basic functionality and enhance:
999
+
1000
+ ```typescript
1001
+ const progressiveConfig: InteractConfig = {
1002
+ interactions: [
1003
+ // Base interaction - works everywhere
1004
+ {
1005
+ key: 'button',
1006
+ trigger: 'click',
1007
+ effects: [
1008
+ {
1009
+ key: 'button',
1010
+ namedEffect: 'Pulse',
1011
+ duration: 200
1012
+ }
1013
+ ]
1014
+ },
1015
+
1016
+ // Enhanced interaction - only on capable devices
1017
+ {
1018
+ key: 'button',
1019
+ trigger: 'hover',
1020
+ conditions: ['desktop', 'motion-ok'],
1021
+ effects: [
1022
+ {
1023
+ key: 'button',
1024
+ keyframeEffect: {
1025
+ name: 'shadow',
1026
+ keyframes: [
1027
+ { transform: 'translateY(0)', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' },
1028
+ { transform: 'translateY(-2px)', boxShadow: '0 8px 16px rgba(0,0,0,0.15)' }
1029
+ ]
1030
+ },
1031
+ duration: 250
1032
+ }
1033
+ ]
1034
+ }
1035
+ ]
1036
+ };
1037
+ ```
1038
+
1039
+ ### Accessibility First
1040
+ Always provide accessible alternatives:
1041
+
1042
+ ```typescript
1043
+ // Always provide a motion-safe version
1044
+ {
1045
+ key: 'animated-element',
1046
+ trigger: 'viewEnter',
1047
+ conditions: ['motion-ok'],
1048
+ effects: [/* complex animation */]
1049
+ },
1050
+ {
1051
+ key: 'animated-element',
1052
+ trigger: 'viewEnter',
1053
+ conditions: ['motion-reduced'],
1054
+ effects: [/* simple fade or no animation */]
1055
+ }
1056
+ ```
1057
+
1058
+ ## Debugging Conditions
1059
+
1060
+ TBD
1061
+
1062
+ ## Next Steps
1063
+
1064
+ You've completed the concept guides! Here's what to explore next:
1065
+
1066
+ - **[API Reference](../api/README.md)** - Detailed documentation of all classes and methods
1067
+ - **[Examples](../examples/README.md)** - Practical examples and patterns
1068
+ - **[Integration Guide](../integration/README.md)** - Framework-specific integration guides