@wix/interact 2.0.4 → 2.1.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/rules/hover.md CHANGED
@@ -484,6 +484,80 @@ This document contains rules for generating hover trigger interactions in `@wix/
484
484
  }
485
485
  ```
486
486
 
487
+ ## Rule 6: Hover with Sequence (Staggered Multi-Target)
488
+
489
+ **Purpose**: Hover interactions that stagger animations across multiple targets using a sequence instead of manual delays.
490
+
491
+ **When to Apply**:
492
+
493
+ - When hovering a container should stagger-animate its children
494
+ - For list item hover effects with coordinated timing
495
+ - When you want easing-controlled stagger on hover
496
+
497
+ **Pattern**:
498
+
499
+ ```typescript
500
+ {
501
+ key: '[SOURCE_KEY]',
502
+ trigger: 'hover',
503
+ params: {
504
+ type: 'repeat'
505
+ },
506
+ sequences: [
507
+ {
508
+ offset: [OFFSET_MS],
509
+ offsetEasing: '[OFFSET_EASING]',
510
+ effects: [
511
+ {
512
+ effectId: '[EFFECT_ID]',
513
+ listContainer: '[LIST_CONTAINER_SELECTOR]'
514
+ }
515
+ ]
516
+ }
517
+ ]
518
+ }
519
+ ```
520
+
521
+ **Example - Hover Card Grid Stagger**:
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
+
487
561
  ## Best Practices for Hover Rules
488
562
 
489
563
  ### Timing and Pattern Guidelines
@@ -100,6 +100,7 @@ The `InteractConfig` object defines the behavior.
100
100
  type InteractConfig = {
101
101
  interactions: Interaction[]; // Required: Array of interaction definitions
102
102
  effects?: Record<string, Effect>; // Optional: Reusable named effects
103
+ sequences?: Record<string, SequenceConfig>; // Optional: Reusable sequence definitions
103
104
  conditions?: Record<string, Condition>; // Optional: Reusable conditions (media queries)
104
105
  };
105
106
  ```
@@ -115,7 +116,8 @@ type InteractConfig = {
115
116
  listItemSelector?: '.item', // Optional: CSS selector for items within listContainer
116
117
  params?: { ... }, // Trigger-specific parameters
117
118
  conditions?: ['cond-id'], // Array of condition IDs
118
- effects: [ ... ] // Array of effects to apply
119
+ effects?: [ ... ], // Array of effects to apply
120
+ sequences?: [ ... ] // Array of sequences (coordinated staggered effects)
119
121
  }
120
122
  ```
121
123
 
@@ -183,6 +185,38 @@ const html = `
183
185
  | `pointerMove` | Mouse movement | `hitArea`: 'self' (default) or 'root'; `axis`: 'x' or 'y' for keyframeEffect | `./pointermove.md` |
184
186
  | `animationEnd` | Chaining animations | `effectId`: ID of the previous effect | -- |
185
187
 
188
+ ## 5b. Sequences (Coordinated Stagger)
189
+
190
+ Sequences group multiple effects into a coordinated timeline with staggered timing. Instead of setting `delay` on each effect manually, define `offset` (ms between items) and `offsetEasing` (how offset is distributed).
191
+
192
+ ### Sequence Config
193
+
194
+ ```typescript
195
+ {
196
+ offset: 100, // ms between consecutive effects
197
+ offsetEasing: 'quadIn', // easing for stagger distribution (linear, quadIn, sineOut, etc.)
198
+ delay: 0, // base delay before the sequence starts
199
+ effects: [ // effects in the sequence, applied in order
200
+ { effectId: 'card-entrance', listContainer: '.card-grid' },
201
+ ],
202
+ }
203
+ ```
204
+
205
+ Effects in a sequence can target different elements via `key`, use `listContainer` to target list children, or reference the effects registry via `effectId`.
206
+
207
+ Reusable sequences can be defined in `InteractConfig.sequences` and referenced by `sequenceId`:
208
+
209
+ ```typescript
210
+ {
211
+ sequences: {
212
+ 'stagger-entrance': { offset: 80, offsetEasing: 'quadIn', effects: [{ effectId: 'fade-up', listContainer: '.items' }] },
213
+ },
214
+ interactions: [
215
+ { key: 'section', trigger: 'viewEnter', params: { type: 'once' }, sequences: [{ sequenceId: 'stagger-entrance' }] },
216
+ ],
217
+ }
218
+ ```
219
+
186
220
  ## 6. Named Effects & `registerEffects`
187
221
 
188
222
  To use `namedEffect` presets from `@wix/motion-presets`, register them before calling `Interact.create`. For full effect type syntax (`keyframeEffect`, `customEffect`, `TransitionEffect`, `ScrubEffect`), see `full-lean.md`.
@@ -272,6 +306,41 @@ const config = {
272
306
  };
273
307
  ```
274
308
 
309
+ ### Staggered List Entrance (Sequence)
310
+
311
+ ```typescript
312
+ const config = {
313
+ interactions: [
314
+ {
315
+ key: 'card-grid',
316
+ trigger: 'viewEnter',
317
+ params: { type: 'once', threshold: 0.3 },
318
+ sequences: [
319
+ {
320
+ offset: 100,
321
+ offsetEasing: 'quadIn',
322
+ effects: [{ effectId: 'card-entrance', listContainer: '.card-grid' }],
323
+ },
324
+ ],
325
+ },
326
+ ],
327
+ effects: {
328
+ 'card-entrance': {
329
+ duration: 500,
330
+ easing: 'ease-out',
331
+ keyframeEffect: {
332
+ name: 'card-fade-up',
333
+ keyframes: [
334
+ { transform: 'translateY(40px)', opacity: 0 },
335
+ { transform: 'translateY(0)', opacity: 1 },
336
+ ],
337
+ },
338
+ fill: 'both',
339
+ },
340
+ },
341
+ };
342
+ ```
343
+
275
344
  ### Interactive Toggle (Click)
276
345
 
277
346
  ```typescript
@@ -527,9 +527,9 @@ Same as Rule 2
527
527
 
528
528
  ---
529
529
 
530
- ## Rule 6: Staggered Entrance Animations
530
+ ## Rule 6: Staggered Entrance Animations (Sequences)
531
531
 
532
- **Use Case**: Sequential entrance animations where multiple elements animate with delays (e.g., card grids, list items, team member cards, feature sections)
532
+ **Use Case**: Sequential entrance animations where multiple elements animate with staggered timing (e.g., card grids, list items, team member cards, feature sections)
533
533
 
534
534
  **When to Apply**:
535
535
 
@@ -538,196 +538,126 @@ Same as Rule 2
538
538
  - When animating lists, grids, or collections
539
539
  - For progressive content revelation
540
540
 
541
- **Pattern**:
541
+ **Preferred approach: use `sequences`** on the interaction instead of manually setting `delay` on individual effects. Sequences automatically calculate stagger delays using `offset` and `offsetEasing`.
542
+
543
+ **Pattern (with `listContainer`)**:
542
544
 
543
545
  ```typescript
544
- [
545
- {
546
- key: '[ELEMENT_1_SELECTOR]',
547
- trigger: 'viewEnter',
548
- params: {
549
- type: 'once',
550
- threshold: [SHARED_THRESHOLD],
551
- inset: '[SHARED_INSET]',
552
- },
553
- effects: [
554
- {
555
- [EFFECT_TYPE]: [SHARED_EFFECT_DEFINITION],
556
- duration: [SHARED_DURATION],
557
- easing: '[SHARED_EASING]',
558
- delay: [DELAY_1],
559
- },
560
- ],
561
- },
562
- {
563
- key: '[ELEMENT_2_SELECTOR]',
546
+ {
547
+ key: '[CONTAINER_KEY]',
564
548
  trigger: 'viewEnter',
565
549
  params: {
566
- type: 'once',
567
- threshold: [SHARED_THRESHOLD],
568
- inset: '[SHARED_INSET]',
550
+ type: '[BEHAVIOR_TYPE]',
551
+ threshold: [VISIBILITY_THRESHOLD]
569
552
  },
570
- effects: [
571
- {
572
- [EFFECT_TYPE]: [SHARED_EFFECT_DEFINITION],
573
- duration: [SHARED_DURATION],
574
- easing: '[SHARED_EASING]',
575
- delay: [DELAY_2],
576
- },
577
- ],
578
- },
579
- // ... additional elements with increasing delays
580
- ];
553
+ sequences: [
554
+ {
555
+ offset: [OFFSET_MS],
556
+ offsetEasing: '[OFFSET_EASING]',
557
+ effects: [
558
+ {
559
+ effectId: '[EFFECT_ID]',
560
+ listContainer: '[LIST_CONTAINER_SELECTOR]'
561
+ }
562
+ ]
563
+ }
564
+ ]
565
+ }
581
566
  ```
582
567
 
583
568
  **Variables**:
584
569
 
585
- - `[ELEMENT_N_KEY]`: Unique identifier for each individual element in sequence
586
- - `[DELAY_N]`: Progressive delay values (e.g., 0, 100, 200, 300ms)
587
- - `[SHARED_*]`: Common values used across all elements in the sequence
570
+ - `[CONTAINER_KEY]`: Unique identifier for the container element
571
+ - `[OFFSET_MS]`: Stagger offset in ms between consecutive items (e.g., 80, 100, 120)
572
+ - `[OFFSET_EASING]`: How the offset is distributed `'linear'` (equal spacing), `'quadIn'` (accelerating), `'sineOut'` (decelerating), etc.
573
+ - `[LIST_CONTAINER_SELECTOR]`: CSS selector for the list container whose children become sequence items
588
574
  - Other variables same as Rule 1
589
575
 
590
- **Example - Card Grid Stagger**:
576
+ **Example - Card Grid Stagger (listContainer)**:
591
577
 
592
578
  ```typescript
593
- [
594
- {
595
- key: 'card-1',
596
- trigger: 'viewEnter',
597
- params: {
598
- type: 'once',
599
- threshold: 0.3,
600
- },
601
- effects: [
602
- {
603
- namedEffect: {
604
- type: 'SlideIn',
605
- direction: 'bottom',
606
- },
607
- duration: 600,
608
- easing: 'ease-out',
609
- fill: 'backwards',
610
- delay: 0,
611
- },
612
- ],
613
- },
614
- {
615
- key: 'card-2',
616
- trigger: 'viewEnter',
617
- params: {
618
- type: 'once',
619
- threshold: 0.3,
620
- },
621
- effects: [
622
- {
623
- namedEffect: {
624
- type: 'SlideIn',
625
- direction: 'bottom',
626
- },
627
- duration: 600,
628
- easing: 'ease-out',
629
- fill: 'backwards',
630
- delay: 150,
631
- },
632
- ],
633
- },
634
- {
635
- key: 'card-3',
579
+ {
580
+ key: 'card-grid-container',
636
581
  trigger: 'viewEnter',
637
582
  params: {
638
- type: 'once',
639
- threshold: 0.3,
583
+ type: 'once',
584
+ threshold: 0.3
640
585
  },
641
- effects: [
642
- {
643
- namedEffect: {
644
- type: 'SlideIn',
645
- direction: 'bottom',
646
- },
647
- duration: 600,
648
- easing: 'ease-out',
649
- fill: 'backwards',
650
- delay: 300,
651
- },
652
- ],
653
- },
654
- ];
586
+ sequences: [
587
+ {
588
+ offset: 100,
589
+ offsetEasing: 'quadIn',
590
+ effects: [
591
+ {
592
+ effectId: 'card-entrance',
593
+ listContainer: '.card-grid'
594
+ }
595
+ ]
596
+ }
597
+ ]
598
+ }
655
599
  ```
656
600
 
657
- **Example - Feature List Cascade**:
601
+ With effect in the registry:
658
602
 
659
603
  ```typescript
660
- [
661
- {
662
- key: 'feature-item:nth-child(1)',
663
- trigger: 'viewEnter',
664
- params: {
665
- type: 'once',
666
- threshold: 0.4,
667
- },
668
- effects: [
669
- {
604
+ effects: {
605
+ 'card-entrance': {
606
+ duration: 500,
607
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
670
608
  keyframeEffect: {
671
- name: 'item-kf-1',
672
- keyframes: [
673
- { opacity: '0', transform: 'translateX(-30px)' },
674
- { opacity: '1', transform: 'translateX(0)' },
675
- ],
609
+ name: 'card-fade-up',
610
+ keyframes: [
611
+ { transform: 'translateY(40px)', opacity: 0 },
612
+ { transform: 'translateY(0)', opacity: 1 }
613
+ ]
676
614
  },
677
- duration: 500,
678
- easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
679
- fill: 'backwards',
680
- delay: 0,
681
- },
682
- ],
683
- },
684
- {
685
- key: 'feature-item:nth-child(2)',
615
+ fill: 'both'
616
+ }
617
+ }
618
+ ```
619
+
620
+ **Example - Feature List Cascade (per-key effects)**:
621
+
622
+ When items have individual keys rather than a shared container, list each as a separate effect in the sequence:
623
+
624
+ ```typescript
625
+ {
626
+ key: 'features-section',
686
627
  trigger: 'viewEnter',
687
628
  params: {
688
- type: 'once',
689
- threshold: 0.4,
629
+ type: 'once',
630
+ threshold: 0.4
690
631
  },
691
- effects: [
692
- {
693
- keyframeEffect: {
694
- name: 'item-kf-2',
695
- keyframes: [
696
- { opacity: '0', transform: 'translateX(-30px)' },
697
- { opacity: '1', transform: 'translateX(0)' },
698
- ],
699
- },
632
+ sequences: [
633
+ {
634
+ offset: 100,
635
+ offsetEasing: 'linear',
636
+ effects: [
637
+ { effectId: 'feature-slide', key: 'feature-1' },
638
+ { effectId: 'feature-slide', key: 'feature-2' },
639
+ { effectId: 'feature-slide', key: 'feature-3' }
640
+ ]
641
+ }
642
+ ]
643
+ }
644
+ ```
645
+
646
+ ```typescript
647
+ effects: {
648
+ 'feature-slide': {
700
649
  duration: 500,
701
650
  easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
702
- fill: 'backwards',
703
- delay: 100,
704
- },
705
- ],
706
- },
707
- {
708
- key: 'feature-item:nth-child(3)',
709
- trigger: 'viewEnter',
710
- params: {
711
- type: 'once',
712
- threshold: 0.4,
713
- },
714
- effects: [
715
- {
716
651
  keyframeEffect: {
717
- name: 'item-kf-3',
718
- keyframes: [
719
- { opacity: '0', transform: 'translateX(-30px)' },
720
- { opacity: '1', transform: 'translateX(0)' },
721
- ],
652
+ name: 'feature-slide-in',
653
+ keyframes: [
654
+ { opacity: '0', transform: 'translateX(-30px)' },
655
+ { opacity: '1', transform: 'translateX(0)' }
656
+ ]
722
657
  },
723
- duration: 500,
724
- easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
725
- fill: 'backwards',
726
- delay: 200,
727
- },
728
- ],
729
- },
730
- ];
658
+ fill: 'backwards'
659
+ }
660
+ }
731
661
  ```
732
662
 
733
663
  ---