@wix/interact 2.0.3 → 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.
Files changed (43) hide show
  1. package/dist/cjs/index.js +1 -1
  2. package/dist/cjs/react.js +1 -1
  3. package/dist/cjs/web.js +1 -1
  4. package/dist/es/index.js +1 -1
  5. package/dist/es/react.js +2 -2
  6. package/dist/es/web.js +2 -2
  7. package/dist/{index-BfcN_rkn.mjs → index-BP07b-Y1.mjs} +1202 -751
  8. package/dist/index-BP07b-Y1.mjs.map +1 -0
  9. package/dist/index-D4orAyUu.js +18 -0
  10. package/dist/index-D4orAyUu.js.map +1 -0
  11. package/dist/tsconfig.build.tsbuildinfo +1 -1
  12. package/dist/types/core/Interact.d.ts +12 -1
  13. package/dist/types/core/Interact.d.ts.map +1 -1
  14. package/dist/types/core/add.d.ts.map +1 -1
  15. package/dist/types/core/remove.d.ts.map +1 -1
  16. package/dist/types/handlers/animationEnd.d.ts +1 -1
  17. package/dist/types/handlers/animationEnd.d.ts.map +1 -1
  18. package/dist/types/handlers/effectHandlers.d.ts +2 -1
  19. package/dist/types/handlers/effectHandlers.d.ts.map +1 -1
  20. package/dist/types/handlers/eventTrigger.d.ts +1 -1
  21. package/dist/types/handlers/eventTrigger.d.ts.map +1 -1
  22. package/dist/types/handlers/viewEnter.d.ts +1 -1
  23. package/dist/types/handlers/viewEnter.d.ts.map +1 -1
  24. package/dist/types/types.d.ts +29 -2
  25. package/dist/types/types.d.ts.map +1 -1
  26. package/docs/api/types.md +114 -0
  27. package/docs/examples/README.md +10 -1
  28. package/docs/examples/list-patterns.md +148 -0
  29. package/docs/guides/README.md +5 -0
  30. package/docs/guides/sequences.md +421 -0
  31. package/package.json +2 -2
  32. package/rules/MASTER-CLEANUP-PLAN.md +286 -0
  33. package/rules/click.md +124 -32
  34. package/rules/full-lean.md +93 -7
  35. package/rules/hover.md +142 -153
  36. package/rules/integration.md +83 -82
  37. package/rules/pointermove.md +32 -57
  38. package/rules/scroll-list.md +82 -280
  39. package/rules/viewenter.md +158 -253
  40. package/rules/viewprogress.md +139 -845
  41. package/dist/index-BfcN_rkn.mjs.map +0 -1
  42. package/dist/index-HXLBEIjG.js +0 -18
  43. package/dist/index-HXLBEIjG.js.map +0 -1
@@ -499,21 +499,27 @@ Same as Rule 2
499
499
 
500
500
  ```typescript
501
501
  {
502
- key: 'responsive-element',
503
- trigger: 'viewEnter',
504
- params: {
505
- type: 'once',
506
- threshold: 0.3, // Good for mobile
507
- inset: '-100px' // Extra space for desktop
502
+ conditions: {
503
+ // Condition IDs are user-defined strings matched against these media predicates
504
+ 'desktop-only': { type: 'media', predicate: '(min-width: 768px)' },
508
505
  },
509
- conditions: ['desktop-only'],
510
- effects: [
506
+ interactions: [
511
507
  {
512
508
  key: 'responsive-element',
513
- namedEffect: {
514
- type: 'FadeIn'
509
+ trigger: 'viewEnter',
510
+ params: {
511
+ type: 'once',
512
+ threshold: 0.3,
513
+ inset: '-100px'
515
514
  },
516
- duration: 800
515
+ conditions: ['desktop-only'],
516
+ effects: [
517
+ {
518
+ key: 'responsive-element',
519
+ namedEffect: { type: 'FadeIn' },
520
+ duration: 800
521
+ }
522
+ ]
517
523
  }
518
524
  ]
519
525
  }
@@ -521,9 +527,9 @@ Same as Rule 2
521
527
 
522
528
  ---
523
529
 
524
- ## Rule 6: Staggered Entrance Animations
530
+ ## Rule 6: Staggered Entrance Animations (Sequences)
525
531
 
526
- **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)
527
533
 
528
534
  **When to Apply**:
529
535
 
@@ -532,196 +538,126 @@ Same as Rule 2
532
538
  - When animating lists, grids, or collections
533
539
  - For progressive content revelation
534
540
 
535
- **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`)**:
536
544
 
537
545
  ```typescript
538
- [
539
- {
540
- key: '[ELEMENT_1_SELECTOR]',
541
- trigger: 'viewEnter',
542
- params: {
543
- type: 'once',
544
- threshold: [SHARED_THRESHOLD],
545
- inset: '[SHARED_INSET]',
546
- },
547
- effects: [
548
- {
549
- [EFFECT_TYPE]: [SHARED_EFFECT_DEFINITION],
550
- duration: [SHARED_DURATION],
551
- easing: '[SHARED_EASING]',
552
- delay: [DELAY_1],
553
- },
554
- ],
555
- },
556
- {
557
- key: '[ELEMENT_2_SELECTOR]',
546
+ {
547
+ key: '[CONTAINER_KEY]',
558
548
  trigger: 'viewEnter',
559
549
  params: {
560
- type: 'once',
561
- threshold: [SHARED_THRESHOLD],
562
- inset: '[SHARED_INSET]',
550
+ type: '[BEHAVIOR_TYPE]',
551
+ threshold: [VISIBILITY_THRESHOLD]
563
552
  },
564
- effects: [
565
- {
566
- [EFFECT_TYPE]: [SHARED_EFFECT_DEFINITION],
567
- duration: [SHARED_DURATION],
568
- easing: '[SHARED_EASING]',
569
- delay: [DELAY_2],
570
- },
571
- ],
572
- },
573
- // ... additional elements with increasing delays
574
- ];
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
+ }
575
566
  ```
576
567
 
577
568
  **Variables**:
578
569
 
579
- - `[ELEMENT_N_KEY]`: Unique identifier for each individual element in sequence
580
- - `[DELAY_N]`: Progressive delay values (e.g., 0, 100, 200, 300ms)
581
- - `[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
582
574
  - Other variables same as Rule 1
583
575
 
584
- **Example - Card Grid Stagger**:
576
+ **Example - Card Grid Stagger (listContainer)**:
585
577
 
586
578
  ```typescript
587
- [
588
- {
589
- key: 'card-1',
590
- trigger: 'viewEnter',
591
- params: {
592
- type: 'once',
593
- threshold: 0.3,
594
- },
595
- effects: [
596
- {
597
- namedEffect: {
598
- type: 'SlideIn',
599
- direction: 'bottom',
600
- },
601
- duration: 600,
602
- easing: 'ease-out',
603
- fill: 'backwards',
604
- delay: 0,
605
- },
606
- ],
607
- },
608
- {
609
- key: 'card-2',
610
- trigger: 'viewEnter',
611
- params: {
612
- type: 'once',
613
- threshold: 0.3,
614
- },
615
- effects: [
616
- {
617
- namedEffect: {
618
- type: 'SlideIn',
619
- direction: 'bottom',
620
- },
621
- duration: 600,
622
- easing: 'ease-out',
623
- fill: 'backwards',
624
- delay: 150,
625
- },
626
- ],
627
- },
628
- {
629
- key: 'card-3',
579
+ {
580
+ key: 'card-grid-container',
630
581
  trigger: 'viewEnter',
631
582
  params: {
632
- type: 'once',
633
- threshold: 0.3,
583
+ type: 'once',
584
+ threshold: 0.3
634
585
  },
635
- effects: [
636
- {
637
- namedEffect: {
638
- type: 'SlideIn',
639
- direction: 'bottom',
640
- },
641
- duration: 600,
642
- easing: 'ease-out',
643
- fill: 'backwards',
644
- delay: 300,
645
- },
646
- ],
647
- },
648
- ];
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
+ }
649
599
  ```
650
600
 
651
- **Example - Feature List Cascade**:
601
+ With effect in the registry:
652
602
 
653
603
  ```typescript
654
- [
655
- {
656
- key: 'feature-item:nth-child(1)',
657
- trigger: 'viewEnter',
658
- params: {
659
- type: 'once',
660
- threshold: 0.4,
661
- },
662
- effects: [
663
- {
604
+ effects: {
605
+ 'card-entrance': {
606
+ duration: 500,
607
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
664
608
  keyframeEffect: {
665
- name: 'item-kf-1',
666
- keyframes: [
667
- { opacity: '0', transform: 'translateX(-30px)' },
668
- { opacity: '1', transform: 'translateX(0)' },
669
- ],
609
+ name: 'card-fade-up',
610
+ keyframes: [
611
+ { transform: 'translateY(40px)', opacity: 0 },
612
+ { transform: 'translateY(0)', opacity: 1 }
613
+ ]
670
614
  },
671
- duration: 500,
672
- easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
673
- fill: 'backwards',
674
- delay: 0,
675
- },
676
- ],
677
- },
678
- {
679
- 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',
680
627
  trigger: 'viewEnter',
681
628
  params: {
682
- type: 'once',
683
- threshold: 0.4,
629
+ type: 'once',
630
+ threshold: 0.4
684
631
  },
685
- effects: [
686
- {
687
- keyframeEffect: {
688
- name: 'item-kf-2',
689
- keyframes: [
690
- { opacity: '0', transform: 'translateX(-30px)' },
691
- { opacity: '1', transform: 'translateX(0)' },
692
- ],
693
- },
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': {
694
649
  duration: 500,
695
650
  easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
696
- fill: 'backwards',
697
- delay: 100,
698
- },
699
- ],
700
- },
701
- {
702
- key: 'feature-item:nth-child(3)',
703
- trigger: 'viewEnter',
704
- params: {
705
- type: 'once',
706
- threshold: 0.4,
707
- },
708
- effects: [
709
- {
710
651
  keyframeEffect: {
711
- name: 'item-kf-3',
712
- keyframes: [
713
- { opacity: '0', transform: 'translateX(-30px)' },
714
- { opacity: '1', transform: 'translateX(0)' },
715
- ],
652
+ name: 'feature-slide-in',
653
+ keyframes: [
654
+ { opacity: '0', transform: 'translateX(-30px)' },
655
+ { opacity: '1', transform: 'translateX(0)' }
656
+ ]
716
657
  },
717
- duration: 500,
718
- easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
719
- fill: 'backwards',
720
- delay: 200,
721
- },
722
- ],
723
- },
724
- ];
658
+ fill: 'backwards'
659
+ }
660
+ }
725
661
  ```
726
662
 
727
663
  ---
@@ -836,43 +772,42 @@ Animating multiple targets from single viewport trigger:
836
772
 
837
773
  ### Conditional ViewEnter Animations
838
774
 
839
- Combining with conditions for responsive behavior:
775
+ Use the `conditions` config map to guard interactions by device or motion preference. Condition IDs are user-defined strings — they must be declared in the top-level `conditions` map before being referenced in an interaction.
840
776
 
841
777
  ```typescript
842
778
  {
843
- key: 'responsive-section',
844
- trigger: 'viewEnter',
845
- params: {
846
- type: 'once',
847
- threshold: 0.5
779
+ conditions: {
780
+ 'desktop-only': { type: 'media', predicate: '(min-width: 768px)' },
781
+ 'prefers-motion': { type: 'media', predicate: '(prefers-reduced-motion: no-preference)' },
782
+ 'mobile-only': { type: 'media', predicate: '(max-width: 767px)' },
848
783
  },
849
- conditions: ['desktop-only', 'prefers-motion'],
850
- effects: [
784
+ interactions: [
851
785
  {
852
786
  key: 'responsive-section',
853
- namedEffect: {
854
- type: 'ComplexEntrance'
855
- },
856
- duration: 1000
857
- }
858
- ]
859
- },
860
- // Simplified version for mobile/reduced motion
861
- {
862
- key: 'responsive-section',
863
- trigger: 'viewEnter',
864
- params: {
865
- type: 'once',
866
- threshold: 0.7
867
- },
868
- conditions: ['mobile-only'],
869
- effects: [
787
+ trigger: 'viewEnter',
788
+ params: { type: 'once', threshold: 0.5 },
789
+ conditions: ['desktop-only', 'prefers-motion'],
790
+ effects: [
791
+ {
792
+ key: 'responsive-section',
793
+ namedEffect: { type: 'SlideIn' },
794
+ duration: 1000
795
+ }
796
+ ]
797
+ },
798
+ // Simplified fallback for mobile or reduced-motion users
870
799
  {
871
800
  key: 'responsive-section',
872
- namedEffect: {
873
- type: 'FadeIn'
874
- },
875
- duration: 400
801
+ trigger: 'viewEnter',
802
+ params: { type: 'once', threshold: 0.7 },
803
+ conditions: ['mobile-only'],
804
+ effects: [
805
+ {
806
+ key: 'responsive-section',
807
+ namedEffect: { type: 'FadeIn' },
808
+ duration: 400
809
+ }
810
+ ]
876
811
  }
877
812
  ]
878
813
  }
@@ -882,11 +817,14 @@ Combining with conditions for responsive behavior:
882
817
 
883
818
  ## Preventing Flash of Unstyled Content (FOUC)
884
819
 
885
- When using `viewEnter` for entrance animations, elements may briefly appear in their final state before the animation plays. Use the `generate` function to create critical CSS that prevents this.
820
+ Use `generate(config)` from `@wix/interact/web` server-side or at build time to produce critical CSS that hides entrance elements until their animation plays.
886
821
 
887
- ### Using the `generate` Function
822
+ **Constraints:**
888
823
 
889
- **Import and generate CSS:**
824
+ - MUST be called server-side or at build time — not client-side
825
+ - MUST set `data-interact-initial="true"` on the `<interact-element>` whose first child should be hidden
826
+ - Only valid for `viewEnter` + `params.type: 'once'` where source and target are the same element
827
+ - Do NOT use for `hover`, `click`, or `viewEnter` with `repeat`/`alternate`/`state` types
890
828
 
891
829
  ```typescript
892
830
  import { generate } from '@wix/interact/web';
@@ -894,56 +832,35 @@ import { generate } from '@wix/interact/web';
894
832
  const config: InteractConfig = {
895
833
  interactions: [
896
834
  {
897
- key: 'hero-section',
835
+ key: 'hero',
898
836
  trigger: 'viewEnter',
899
- params: { type: 'once', threshold: 0.3 },
900
- effects: [
901
- {
902
- namedEffect: { type: 'FadeIn' },
903
- duration: 800,
904
- fill: 'backwards',
905
- },
906
- ],
837
+ params: { type: 'once', threshold: 0.2 },
838
+ effects: [{ namedEffect: { type: 'FadeIn' }, duration: 800 }],
907
839
  },
908
840
  ],
909
841
  };
910
842
 
911
- // Generate CSS at build time or on server
843
+ // Called at build time or on the server
912
844
  const css = generate(config);
913
845
 
914
- // Include in your HTML template
846
+ // Inject into <head> before the page renders
915
847
  const html = `
916
- <!DOCTYPE html>
917
- <html>
918
848
  <head>
919
- <style>${css}</style>
849
+ <style>${css}</style>
920
850
  </head>
921
851
  <body>
922
- <interact-element data-interact-key="hero" data-interact-initial="true">
923
- <section class="hero">
924
- <h1>Welcome to Our Site</h1>
925
- <p>This content fades in smoothly without flash</p>
926
- </section>
927
- </interact-element>
928
- <script type="module" src="./main.js"></script>
852
+ <interact-element data-interact-key="hero" data-interact-initial="true">
853
+ <section class="hero">...</section>
854
+ </interact-element>
929
855
  </body>
930
- </html>
931
856
  `;
932
857
  ```
933
858
 
934
- ### Generated CSS Behavior
935
-
936
- The `generate` function produces CSS that:
937
-
938
- 1. **Hides marked elements** until their entrance animation completes
939
- 2. **Resets transforms** to allow `IntersectionObserver` to trigger entrance using the element's original layout and position
940
- 3. **Respects reduced motion preferences** - users with `prefers-reduced-motion: reduce` see elements immediately
941
-
942
859
  ---
943
860
 
944
861
  ## Best Practices for ViewEnter Interactions
945
862
 
946
- ### Behavior Guildelines
863
+ ### Behavior Guidelines
947
864
 
948
865
  1. **Use `alternate` and `repeat` types only with a separate source `key` and target `key`** to avoid re-triggering when animation starts or not triggering at all if animated target is out of viewport or clipped
949
866
 
@@ -953,23 +870,15 @@ The `generate` function produces CSS that:
953
870
  2. **Be careful with separate source/target patterns** - ensure source doesn't get clipped
954
871
  3. **Use appropriate thresholds** - avoid triggering too early or too late
955
872
 
956
- ### User Experience Guidelines
873
+ ### Threshold and Timing Guidelines
957
874
 
958
875
  1. **Use realistic thresholds** (0.1-0.5) for natural timing
959
- 2. **Use tiny thresholds for huge elements** 0.01-0.05 for elements much larger than viewport
876
+ 2. **Use tiny thresholds for huge elements** (0.01-0.05) for elements much larger than viewport
960
877
  3. **Provide adequate inset margins** for mobile viewports
961
878
  4. **Keep entrance animations moderate** (500-1200ms)
962
879
  5. **Use staggered delays thoughtfully** (50-200ms intervals)
963
- 6. **Ensure content is readable** during animations
964
880
 
965
- ### Accessibility Considerations
966
-
967
- 1. **Respect `prefers-reduced-motion`** for all entrance animations
968
- 2. **Don't rely solely on animations** to convey important information
969
- 3. **Ensure sufficient contrast** during fade-in effects
970
- 4. **Provide alternative content loading** for users who disable animations
971
-
972
- ### Threshold and Timing Guidelines
881
+ ### Threshold and Timing Reference
973
882
 
974
883
  **Recommended Thresholds by Content Type**:
975
884
 
@@ -977,7 +886,7 @@ The `generate` function produces CSS that:
977
886
  - **Content blocks**: 0.3-0.5 (balanced trigger)
978
887
  - **Small elements**: 0.5-0.8 (late trigger)
979
888
  - **Tall sections**: 0.1-0.2 (early trigger)
980
- - **HUge sections**: 0.01-0.05 (ensure trigger)
889
+ - **Huge sections**: 0.01-0.05 (ensure trigger)
981
890
 
982
891
  **Recommended Insets by Device**:
983
892
 
@@ -1048,7 +957,3 @@ The `generate` function produces CSS that:
1048
957
  - Use hardware-accelerated properties
1049
958
  - Avoid animating layout properties
1050
959
  - Consider using `will-change` for complex animations
1051
-
1052
- ---
1053
-
1054
- These rules provide comprehensive coverage for ViewEnter trigger interactions in `@wix/interact`, supporting all four behavior types and various intersection observer configurations as outlined in the development plan.