@wix/interact 1.74.0 → 1.76.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 (52) hide show
  1. package/README.md +33 -21
  2. package/dist/cjs/WixInteractElement.js +61 -17
  3. package/dist/cjs/WixInteractElement.js.map +1 -1
  4. package/dist/cjs/__tests__/interact.spec.js +761 -109
  5. package/dist/cjs/__tests__/interact.spec.js.map +1 -1
  6. package/dist/cjs/core/Interact.js +190 -0
  7. package/dist/cjs/core/Interact.js.map +1 -0
  8. package/dist/cjs/core/add.js +231 -0
  9. package/dist/cjs/core/add.js.map +1 -0
  10. package/dist/cjs/core/remove.js +37 -0
  11. package/dist/cjs/core/remove.js.map +1 -0
  12. package/dist/cjs/handlers/click.js +1 -1
  13. package/dist/cjs/handlers/click.js.map +1 -1
  14. package/dist/cjs/handlers/hover.js +1 -1
  15. package/dist/cjs/handlers/hover.js.map +1 -1
  16. package/dist/cjs/index.js +6 -4
  17. package/dist/cjs/index.js.map +1 -1
  18. package/dist/cjs/types.js.map +1 -1
  19. package/dist/cjs/utils.js +12 -10
  20. package/dist/cjs/utils.js.map +1 -1
  21. package/dist/esm/WixInteractElement.js +61 -17
  22. package/dist/esm/WixInteractElement.js.map +1 -1
  23. package/dist/esm/__tests__/interact.spec.js +743 -91
  24. package/dist/esm/__tests__/interact.spec.js.map +1 -1
  25. package/dist/esm/core/Interact.js +186 -0
  26. package/dist/esm/core/Interact.js.map +1 -0
  27. package/dist/esm/core/add.js +226 -0
  28. package/dist/esm/core/add.js.map +1 -0
  29. package/dist/esm/core/remove.js +32 -0
  30. package/dist/esm/core/remove.js.map +1 -0
  31. package/dist/esm/handlers/click.js +1 -1
  32. package/dist/esm/handlers/click.js.map +1 -1
  33. package/dist/esm/handlers/hover.js +1 -1
  34. package/dist/esm/handlers/hover.js.map +1 -1
  35. package/dist/esm/index.js +3 -1
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/types.js.map +1 -1
  38. package/dist/esm/utils.js +12 -10
  39. package/dist/esm/utils.js.map +1 -1
  40. package/dist/types/WixInteractElement.d.ts +5 -2
  41. package/dist/types/core/Interact.d.ts +24 -0
  42. package/dist/types/core/add.d.ts +6 -0
  43. package/dist/types/core/remove.d.ts +5 -0
  44. package/dist/types/index.d.ts +3 -1
  45. package/dist/types/types.d.ts +22 -9
  46. package/dist/types/utils.d.ts +1 -1
  47. package/package.json +7 -6
  48. package/dist/cjs/interact.js +0 -308
  49. package/dist/cjs/interact.js.map +0 -1
  50. package/dist/esm/interact.js +0 -301
  51. package/dist/esm/interact.js.map +0 -1
  52. package/dist/types/interact.d.ts +0 -26
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
 
3
- var _interact = require("../interact");
3
+ var _Interact = require("../core/Interact");
4
+ var _add = require("../core/add");
5
+ var _remove = require("../core/remove");
4
6
  var _utilities = require("../handlers/utilities");
5
7
  // Mock @wix/motion module
6
8
  jest.mock('@wix/motion', () => {
@@ -41,75 +43,75 @@ describe('interact', () => {
41
43
  const mockConfig = {
42
44
  interactions: [{
43
45
  trigger: 'viewEnter',
44
- source: '#logo-entrance',
46
+ key: 'logo-entrance',
45
47
  params: {
46
48
  threshold: 0.2
47
49
  },
48
50
  effects: [{
49
- target: '#logo-entrance',
51
+ key: 'logo-entrance',
50
52
  effectId: 'logo-arc-in'
51
53
  }, {
52
- target: '#logo-click',
54
+ key: 'logo-click',
53
55
  effectId: 'logo-bounce'
54
56
  }]
55
57
  }, {
56
58
  trigger: 'pageVisible',
57
- source: '#logo-loop',
59
+ key: 'logo-loop',
58
60
  effects: [{
59
- target: '#logo-loop',
61
+ key: 'logo-loop',
60
62
  effectId: 'logo-poke'
61
63
  }]
62
64
  }, {
63
65
  trigger: 'animationEnd',
64
- source: '#logo-animation-end',
66
+ key: 'logo-animation-end',
65
67
  params: {
66
68
  effectId: 'logo-arc-in'
67
69
  },
68
70
  effects: [{
69
- target: '#logo-animation-end',
71
+ key: 'logo-animation-end',
70
72
  effectId: 'logo-poke'
71
73
  }]
72
74
  }, {
73
75
  trigger: 'pointerMove',
74
- source: '#logo-mouse',
76
+ key: 'logo-mouse',
75
77
  params: {
76
78
  hitArea: 'root'
77
79
  },
78
80
  effects: [{
79
- target: '#logo-mouse',
81
+ key: 'logo-mouse',
80
82
  effectId: 'logo-track-mouse'
81
83
  }]
82
84
  }, {
83
85
  trigger: 'click',
84
- source: '#logo-click',
86
+ key: 'logo-click',
85
87
  params: {
86
88
  type: 'alternate'
87
89
  },
88
90
  effects: [{
89
- target: '#logo-click',
91
+ key: 'logo-click',
90
92
  effectId: 'logo-bounce'
91
93
  }]
92
94
  }, {
93
95
  trigger: 'click',
94
- source: '#logo-click',
96
+ key: 'logo-click',
95
97
  params: {
96
98
  method: 'toggle'
97
99
  },
98
100
  effects: [{
99
- target: '#logo-click',
101
+ key: 'logo-click',
100
102
  effectId: 'logo-transition-hover'
101
103
  }]
102
104
  }, {
103
105
  trigger: 'hover',
104
- source: '#logo-hover',
106
+ key: 'logo-hover',
105
107
  params: {
106
108
  type: 'alternate'
107
109
  },
108
110
  effects: [{
109
- target: '#logo-hover',
111
+ key: 'logo-hover',
110
112
  effectId: 'logo-arc-in'
111
113
  }, {
112
- target: '#logo-hover',
114
+ key: 'logo-hover',
113
115
  effectId: 'logo-arc-in',
114
116
  namedEffect: {
115
117
  type: 'ArcIn',
@@ -119,19 +121,49 @@ describe('interact', () => {
119
121
  }]
120
122
  }, {
121
123
  trigger: 'hover',
122
- source: '#logo-hover',
124
+ key: 'logo-hover',
123
125
  params: {
124
126
  method: 'toggle'
125
127
  },
126
128
  effects: [{
127
- target: '#logo-hover',
129
+ key: 'logo-hover',
128
130
  effectId: 'logo-transition-hover'
129
131
  }]
130
132
  }, {
131
133
  trigger: 'viewProgress',
132
- source: '#logo-scroll',
134
+ key: 'logo-scroll',
133
135
  effects: [{
134
- target: '#logo-scroll',
136
+ key: 'logo-scroll',
137
+ effectId: 'logo-fade-scroll'
138
+ }]
139
+ }, {
140
+ trigger: 'click',
141
+ key: 'logo-click-container',
142
+ listContainer: '#logo-list',
143
+ effects: [{
144
+ effectId: 'logo-bounce'
145
+ }]
146
+ }, {
147
+ trigger: 'viewEnter',
148
+ key: 'logo-view-container',
149
+ effects: [{
150
+ listContainer: '#logo-list',
151
+ effectId: 'logo-bounce'
152
+ }]
153
+ }, {
154
+ trigger: 'viewProgress',
155
+ key: 'logo-scroll-container',
156
+ listContainer: '#logo-scroll-list',
157
+ effects: [{
158
+ listContainer: '#logo-scroll-list',
159
+ effectId: 'logo-fade-scroll'
160
+ }]
161
+ }, {
162
+ trigger: 'viewProgress',
163
+ key: 'logo-scroll-container',
164
+ effects: [{
165
+ key: 'logo-scroll-items',
166
+ listContainer: '#logo-scroll-list',
135
167
  effectId: 'logo-fade-scroll'
136
168
  }]
137
169
  }],
@@ -145,7 +177,7 @@ describe('interact', () => {
145
177
  duration: 1200
146
178
  },
147
179
  'logo-arc-in-with-target': {
148
- target: '#logo-hover',
180
+ key: 'logo-hover',
149
181
  namedEffect: {
150
182
  type: 'ArcIn',
151
183
  direction: 'right',
@@ -269,7 +301,8 @@ describe('interact', () => {
269
301
  window.CSSStyleSheet = class CSSStyleSheet {
270
302
  constructor(_) {
271
303
  return {
272
- replace: jest.fn()
304
+ replace: jest.fn(),
305
+ insertRule: jest.fn()
273
306
  };
274
307
  }
275
308
  };
@@ -319,12 +352,12 @@ describe('interact', () => {
319
352
  },
320
353
  interactions: [{
321
354
  trigger: 'click',
322
- source: '#cascade-source',
355
+ key: 'cascade-source',
323
356
  effects: [{
324
- target: '#cascade-target',
357
+ key: 'cascade-target',
325
358
  effectId: 'default-effect'
326
359
  }, {
327
- target: '#cascade-target',
360
+ key: 'cascade-target',
328
361
  effectId: 'default-effect',
329
362
  conditions: ['desktop'],
330
363
  namedEffect: {
@@ -334,7 +367,7 @@ describe('interact', () => {
334
367
  },
335
368
  duration: 800
336
369
  }, {
337
- target: '#cascade-target',
370
+ key: 'cascade-target',
338
371
  effectId: 'default-effect',
339
372
  conditions: ['mobile'],
340
373
  namedEffect: {
@@ -358,27 +391,29 @@ describe('interact', () => {
358
391
  }
359
392
  afterEach(() => {
360
393
  jest.clearAllMocks();
361
- (0, _interact.remove)('#logo-entrance');
362
- (0, _interact.remove)('#logo-loop');
363
- (0, _interact.remove)('#logo-animation-end');
364
- (0, _interact.remove)('#logo-mouse');
365
- (0, _interact.remove)('#logo-click');
366
- (0, _interact.remove)('#logo-hover');
367
- (0, _interact.remove)('#logo-scroll');
394
+ (0, _remove.remove)('logo-entrance');
395
+ (0, _remove.remove)('logo-loop');
396
+ (0, _remove.remove)('logo-animation-end');
397
+ (0, _remove.remove)('logo-mouse');
398
+ (0, _remove.remove)('logo-click');
399
+ (0, _remove.remove)('logo-hover');
400
+ (0, _remove.remove)('logo-scroll');
368
401
  // Clean up cascading test elements
369
- (0, _interact.remove)('#cascade-source');
370
- (0, _interact.remove)('#cascade-target');
371
- (0, _interact.remove)('#cascade-target-1');
372
- (0, _interact.remove)('#cascade-target-2');
373
- (0, _interact.remove)('#multi-source-1');
374
- (0, _interact.remove)('#multi-source-2');
402
+ (0, _remove.remove)('cascade-source');
403
+ (0, _remove.remove)('cascade-target');
404
+ (0, _remove.remove)('cascade-target-1');
405
+ (0, _remove.remove)('cascade-target-2');
406
+ (0, _remove.remove)('multi-source-1');
407
+ (0, _remove.remove)('multi-source-2');
375
408
  // Clear Interact instances to ensure test isolation
376
- _interact.Interact.instances.length = 0;
377
- _interact.Interact.elementCache.clear();
409
+ _Interact.Interact.instances.length = 0;
410
+ _Interact.Interact.elementCache.clear();
411
+ // Reset forceReducedMotion to default
412
+ _Interact.Interact.forceReducedMotion = false;
378
413
  });
379
414
  describe('init Interact', () => {
380
415
  it('should initialize with valid config', () => {
381
- _interact.Interact.create({});
416
+ _Interact.Interact.create({});
382
417
  expect(customElements.get('wix-interact-element')).toBeDefined();
383
418
  });
384
419
  });
@@ -387,13 +422,13 @@ describe('interact', () => {
387
422
  const {
388
423
  getWebAnimation
389
424
  } = require('@wix/motion');
390
- _interact.Interact.forceReducedMotion = true;
391
- _interact.Interact.create({
425
+ _Interact.Interact.forceReducedMotion = true;
426
+ _Interact.Interact.create({
392
427
  interactions: [{
393
428
  trigger: 'hover',
394
- source: '#logo-hover',
429
+ key: 'logo-hover',
395
430
  effects: [{
396
- target: '#logo-hover',
431
+ key: 'logo-hover',
397
432
  effectId: 'logo-arc-in'
398
433
  }]
399
434
  }],
@@ -411,17 +446,17 @@ describe('interact', () => {
411
446
  element = document.createElement('wix-interact-element');
412
447
  const div = document.createElement('div');
413
448
  element.append(div);
414
- (0, _interact.add)(element, '#logo-hover');
449
+ (0, _add.add)(element, 'logo-hover');
415
450
  expect(getWebAnimation).toHaveBeenCalledWith(div, expect.any(Object), undefined, {
416
451
  reducedMotion: true
417
452
  });
418
- _interact.Interact.forceReducedMotion = false;
419
- (0, _interact.remove)('#logo-hover');
453
+ _Interact.Interact.forceReducedMotion = false;
454
+ (0, _remove.remove)('logo-hover');
420
455
  });
421
456
  });
422
457
  describe('add interaction', () => {
423
458
  beforeEach(() => {
424
- _interact.Interact.create(mockConfig);
459
+ _Interact.Interact.create(mockConfig);
425
460
  });
426
461
  describe('hover', () => {
427
462
  it('should add handler for hover trigger with alternate type', () => {
@@ -432,7 +467,7 @@ describe('interact', () => {
432
467
  const div = document.createElement('div');
433
468
  element.append(div);
434
469
  const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
435
- (0, _interact.add)(element, '#logo-hover');
470
+ (0, _add.add)(element, 'logo-hover');
436
471
  expect(addEventListenerSpy).toHaveBeenCalledTimes(4);
437
472
  expect(addEventListenerSpy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.objectContaining({
438
473
  passive: true
@@ -458,7 +493,7 @@ describe('interact', () => {
458
493
  const div = document.createElement('div');
459
494
  element.append(div);
460
495
  const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
461
- (0, _interact.add)(element, '#logo-click');
496
+ (0, _add.add)(element, 'logo-click');
462
497
  expect(addEventListenerSpy).toHaveBeenCalledTimes(2);
463
498
  expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
464
499
  passive: true
@@ -473,7 +508,7 @@ describe('interact', () => {
473
508
  element = document.createElement('wix-interact-element');
474
509
  const div = document.createElement('div');
475
510
  element.append(div);
476
- (0, _interact.add)(element, '#logo-entrance');
511
+ (0, _add.add)(element, 'logo-entrance');
477
512
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
478
513
  expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
479
514
  reducedMotion: false
@@ -485,14 +520,25 @@ describe('interact', () => {
485
520
  } = require('@wix/motion');
486
521
  element = document.createElement('wix-interact-element');
487
522
  const div = document.createElement('div');
523
+ div.id = 'logo-entrance';
488
524
  element.append(div);
489
525
  const elementClick = document.createElement('wix-interact-element');
490
526
  const divClick = document.createElement('div');
491
- element.append(divClick);
492
- (0, _interact.add)(elementClick, '#logo-click');
493
- (0, _interact.add)(element, '#logo-entrance');
494
- expect(getWebAnimation).toHaveBeenCalledTimes(1);
495
- expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
527
+ divClick.id = 'logo-click';
528
+ elementClick.append(divClick);
529
+ (0, _add.add)(elementClick, 'logo-click');
530
+ (0, _add.add)(element, 'logo-entrance');
531
+ expect(getWebAnimation).toHaveBeenCalledTimes(3);
532
+ expect(getWebAnimation.mock.calls[0][0]).toBe(divClick);
533
+ expect(getWebAnimation.mock.calls[1][0]).toBe(div);
534
+ expect(getWebAnimation.mock.calls[2][0]).toBe(divClick);
535
+ expect(getWebAnimation.mock.calls[0][3]).toMatchObject({
536
+ reducedMotion: false
537
+ });
538
+ expect(getWebAnimation.mock.calls[1][3]).toMatchObject({
539
+ reducedMotion: false
540
+ });
541
+ expect(getWebAnimation.mock.calls[2][3]).toMatchObject({
496
542
  reducedMotion: false
497
543
  });
498
544
  });
@@ -505,7 +551,7 @@ describe('interact', () => {
505
551
  element = document.createElement('wix-interact-element');
506
552
  const div = document.createElement('div');
507
553
  element.append(div);
508
- (0, _interact.add)(element, '#logo-loop');
554
+ (0, _add.add)(element, 'logo-loop');
509
555
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
510
556
  expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
511
557
  reducedMotion: false
@@ -520,7 +566,7 @@ describe('interact', () => {
520
566
  element = document.createElement('wix-interact-element');
521
567
  const div = document.createElement('div');
522
568
  element.append(div);
523
- (0, _interact.add)(element, '#logo-animation-end');
569
+ (0, _add.add)(element, 'logo-animation-end');
524
570
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
525
571
  expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
526
572
  reducedMotion: false
@@ -543,7 +589,7 @@ describe('interact', () => {
543
589
  element = document.createElement('wix-interact-element');
544
590
  const div = document.createElement('div');
545
591
  element.append(div);
546
- (0, _interact.add)(element, '#logo-mouse');
592
+ (0, _add.add)(element, 'logo-mouse');
547
593
  expect(getScrubScene).toHaveBeenCalledTimes(1);
548
594
  expect(getScrubScene).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining((0, _utilities.effectToAnimationOptions)(mockConfig.effects['logo-track-mouse'])), expect.objectContaining({
549
595
  trigger: 'pointer-move'
@@ -559,7 +605,7 @@ describe('interact', () => {
559
605
  element = document.createElement('wix-interact-element');
560
606
  const div = document.createElement('div');
561
607
  element.append(div);
562
- (0, _interact.add)(element, '#logo-scroll');
608
+ (0, _add.add)(element, 'logo-scroll');
563
609
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
564
610
  expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining((0, _utilities.effectToAnimationOptions)(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
565
611
  trigger: 'view-progress'
@@ -582,7 +628,7 @@ describe('interact', () => {
582
628
  element = document.createElement('wix-interact-element');
583
629
  const div = document.createElement('div');
584
630
  element.append(div);
585
- (0, _interact.add)(element, '#logo-scroll');
631
+ (0, _add.add)(element, 'logo-scroll');
586
632
  expect(getScrubScene).toHaveBeenCalledTimes(1);
587
633
  expect(getScrubScene).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining((0, _utilities.effectToAnimationOptions)(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
588
634
  trigger: 'view-progress'
@@ -592,23 +638,133 @@ describe('interact', () => {
592
638
  }, 0);
593
639
  });
594
640
  });
641
+ describe('listContainer', () => {
642
+ it('should add a handler per list item for click trigger with listContainer', () => {
643
+ element = document.createElement('wix-interact-element');
644
+ const div = document.createElement('div');
645
+ const ul = document.createElement('ul');
646
+ ul.id = 'logo-list';
647
+ div.append(ul);
648
+ const li = document.createElement('li');
649
+ const li2 = li.cloneNode(true);
650
+ ul.append(li);
651
+ ul.append(li2);
652
+ element.append(div);
653
+ const addEventListenerSpy = jest.spyOn(li, 'addEventListener');
654
+ const addEventListenerSpy2 = jest.spyOn(li2, 'addEventListener');
655
+ (0, _add.add)(element, 'logo-click-container');
656
+ expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
657
+ expect(addEventListenerSpy2).toHaveBeenCalledTimes(1);
658
+ expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
659
+ passive: true
660
+ }));
661
+ expect(addEventListenerSpy2).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
662
+ passive: true
663
+ }));
664
+ });
665
+ it('should add a handler per list item for viewEnter trigger with listContainer in effect', () => {
666
+ const {
667
+ getWebAnimation
668
+ } = require('@wix/motion');
669
+ element = document.createElement('wix-interact-element');
670
+ const div = document.createElement('div');
671
+ const ul = document.createElement('ul');
672
+ ul.id = 'logo-list';
673
+ div.append(ul);
674
+ const li = document.createElement('li');
675
+ const li2 = li.cloneNode(true);
676
+ ul.append(li);
677
+ ul.append(li2);
678
+ element.append(div);
679
+ (0, _add.add)(element, 'logo-view-container');
680
+ expect(getWebAnimation).toHaveBeenCalledTimes(2);
681
+ expect(getWebAnimation.mock.calls[0][0]).toBe(li);
682
+ expect(getWebAnimation.mock.calls[1][0]).toBe(li2);
683
+ });
684
+ it('should add a handler per newly added list item for click trigger with listContainer', () => {
685
+ element = document.createElement('wix-interact-element');
686
+ const div = document.createElement('div');
687
+ const ul = document.createElement('ul');
688
+ ul.id = 'logo-list';
689
+ div.append(ul);
690
+ const li = document.createElement('li');
691
+ const li2 = li.cloneNode(true);
692
+ ul.append(li);
693
+ ul.append(li2);
694
+ element.append(div);
695
+ const addEventListenerSpy = jest.spyOn(li, 'addEventListener');
696
+ const addEventListenerSpy2 = jest.spyOn(li2, 'addEventListener');
697
+ (0, _add.add)(element, 'logo-click-container');
698
+ expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
699
+ expect(addEventListenerSpy2).toHaveBeenCalledTimes(1);
700
+ expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
701
+ passive: true
702
+ }));
703
+ expect(addEventListenerSpy2).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
704
+ passive: true
705
+ }));
706
+ const li3 = document.createElement('li');
707
+ ul.append(li3);
708
+ const addEventListenerSpy3 = jest.spyOn(li3, 'addEventListener');
709
+ (0, _add.addListItems)(element, 'logo-click-container', '#logo-list', [li3]);
710
+ expect(addEventListenerSpy3).toHaveBeenCalledTimes(1);
711
+ expect(addEventListenerSpy3).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
712
+ passive: true
713
+ }));
714
+ });
715
+ it('should add a handler per newly added list item for viewProgress trigger but not add same interaction twice', () => {
716
+ const {
717
+ getWebAnimation
718
+ } = require('@wix/motion');
719
+ element = document.createElement('wix-interact-element');
720
+ const div = document.createElement('div');
721
+ const targetElement = document.createElement('wix-interact-element');
722
+ const divTarget = document.createElement('div');
723
+ const ul = document.createElement('ul');
724
+ ul.id = 'logo-scroll-list';
725
+ divTarget.append(ul);
726
+ const li = document.createElement('li');
727
+ const li2 = li.cloneNode(true);
728
+ ul.append(li);
729
+ ul.append(li2);
730
+ element.append(div);
731
+ targetElement.append(divTarget);
732
+ (0, _add.add)(element, 'logo-scroll-container');
733
+ expect(getWebAnimation).toHaveBeenCalledTimes(0);
734
+ (0, _add.add)(targetElement, 'logo-scroll-items');
735
+ expect(getWebAnimation).toHaveBeenCalledTimes(2);
736
+ expect(getWebAnimation).toHaveBeenCalledWith(li, expect.objectContaining((0, _utilities.effectToAnimationOptions)(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
737
+ trigger: 'view-progress'
738
+ }));
739
+ expect(getWebAnimation).toHaveBeenCalledWith(li2, expect.objectContaining((0, _utilities.effectToAnimationOptions)(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
740
+ trigger: 'view-progress'
741
+ }));
742
+ const li3 = document.createElement('li');
743
+ ul.append(li3);
744
+ (0, _add.addListItems)(targetElement, 'logo-scroll-items', '#logo-scroll-list', [li3]);
745
+ expect(getWebAnimation).toHaveBeenCalledTimes(3);
746
+ expect(getWebAnimation).toHaveBeenCalledWith(li3, expect.objectContaining((0, _utilities.effectToAnimationOptions)(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
747
+ trigger: 'view-progress'
748
+ }));
749
+ });
750
+ });
595
751
  });
596
752
  describe('remove interaction', () => {
597
753
  beforeEach(() => {
598
- _interact.Interact.create(mockConfig);
754
+ _Interact.Interact.create(mockConfig);
599
755
  });
600
756
  it('should remove event listeners', () => {
601
757
  element = document.createElement('wix-interact-element');
602
758
  const div = document.createElement('div');
603
759
  element.append(div);
604
760
  const removeEventListenerSpy = jest.spyOn(div, 'removeEventListener');
605
- (0, _interact.add)(element, '#logo-click');
606
- (0, _interact.remove)('#logo-click');
761
+ (0, _add.add)(element, 'logo-click');
762
+ (0, _remove.remove)('logo-click');
607
763
  expect(removeEventListenerSpy).toHaveBeenCalledTimes(2);
608
764
  expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function));
609
765
  });
610
766
  it('should do nothing if key does not exist', () => {
611
- expect(() => (0, _interact.remove)('non-existent-key')).not.toThrow();
767
+ expect(() => (0, _remove.remove)('non-existent-key')).not.toThrow();
612
768
  });
613
769
  it('should cleanup pointer effects', () => {
614
770
  const {
@@ -622,8 +778,8 @@ describe('interact', () => {
622
778
  element = document.createElement('wix-interact-element');
623
779
  const div = document.createElement('div');
624
780
  element.append(div);
625
- (0, _interact.add)(element, '#logo-mouse');
626
- (0, _interact.remove)('#logo-mouse');
781
+ (0, _add.add)(element, 'logo-mouse');
782
+ (0, _remove.remove)('logo-mouse');
627
783
  expect(pointerInstance.destroy).toHaveBeenCalledTimes(1);
628
784
  });
629
785
  });
@@ -634,7 +790,7 @@ describe('interact', () => {
634
790
  getWebAnimation
635
791
  } = require('@wix/motion');
636
792
  const config = createCascadingTestConfig({}, ['min-width: 1024px']);
637
- _interact.Interact.create(config);
793
+ _Interact.Interact.create(config);
638
794
  const sourceElement = document.createElement('wix-interact-element');
639
795
  const sourceDiv = document.createElement('div');
640
796
  sourceElement.append(sourceDiv);
@@ -642,8 +798,8 @@ describe('interact', () => {
642
798
  const targetDiv = document.createElement('div');
643
799
  targetElement.append(targetDiv);
644
800
  const addEventListenerSpy = jest.spyOn(sourceDiv, 'addEventListener');
645
- (0, _interact.add)(sourceElement, '#cascade-source');
646
- (0, _interact.add)(targetElement, '#cascade-target');
801
+ (0, _add.add)(sourceElement, 'cascade-source');
802
+ (0, _add.add)(targetElement, 'cascade-target');
647
803
  expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
648
804
  expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
649
805
  passive: true
@@ -666,15 +822,15 @@ describe('interact', () => {
666
822
  } = require('@wix/motion');
667
823
  const config = createCascadingTestConfig({}, []); // No matching conditions
668
824
 
669
- _interact.Interact.create(config);
825
+ _Interact.Interact.create(config);
670
826
  const sourceElement = document.createElement('wix-interact-element');
671
827
  const sourceDiv = document.createElement('div');
672
828
  sourceElement.append(sourceDiv);
673
829
  const targetElement = document.createElement('wix-interact-element');
674
830
  const targetDiv = document.createElement('div');
675
831
  targetElement.append(targetDiv);
676
- (0, _interact.add)(sourceElement, '#cascade-source');
677
- (0, _interact.add)(targetElement, '#cascade-target');
832
+ (0, _add.add)(sourceElement, 'cascade-source');
833
+ (0, _add.add)(targetElement, 'cascade-target');
678
834
 
679
835
  // Should create animation with default effect
680
836
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
@@ -692,15 +848,15 @@ describe('interact', () => {
692
848
  getWebAnimation
693
849
  } = require('@wix/motion');
694
850
  const config = createCascadingTestConfig({}, ['max-width: 767px']);
695
- _interact.Interact.create(config);
851
+ _Interact.Interact.create(config);
696
852
  const sourceElement = document.createElement('wix-interact-element');
697
853
  const sourceDiv = document.createElement('div');
698
854
  sourceElement.append(sourceDiv);
699
855
  const targetElement = document.createElement('wix-interact-element');
700
856
  const targetDiv = document.createElement('div');
701
857
  targetElement.append(targetDiv);
702
- (0, _interact.add)(sourceElement, '#cascade-source');
703
- (0, _interact.add)(targetElement, '#cascade-target');
858
+ (0, _add.add)(sourceElement, 'cascade-source');
859
+ (0, _add.add)(targetElement, 'cascade-target');
704
860
 
705
861
  // Should create animation with mobile effect
706
862
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
@@ -720,7 +876,7 @@ describe('interact', () => {
720
876
  getWebAnimation
721
877
  } = require('@wix/motion');
722
878
  const config = createCascadingTestConfig({}, ['min-width: 1024px']);
723
- _interact.Interact.create(config);
879
+ _Interact.Interact.create(config);
724
880
  const sourceElement = document.createElement('wix-interact-element');
725
881
  const sourceDiv = document.createElement('div');
726
882
  sourceElement.append(sourceDiv);
@@ -729,9 +885,9 @@ describe('interact', () => {
729
885
  targetElement.append(targetDiv);
730
886
 
731
887
  // Add source first
732
- (0, _interact.add)(sourceElement, '#cascade-source');
888
+ (0, _add.add)(sourceElement, 'cascade-source');
733
889
  // Add target second
734
- (0, _interact.add)(targetElement, '#cascade-target');
890
+ (0, _add.add)(targetElement, 'cascade-target');
735
891
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
736
892
  expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
737
893
  namedEffect: expect.objectContaining({
@@ -746,7 +902,7 @@ describe('interact', () => {
746
902
  getWebAnimation
747
903
  } = require('@wix/motion');
748
904
  const config = createCascadingTestConfig({}, ['min-width: 1024px']);
749
- _interact.Interact.create(config);
905
+ _Interact.Interact.create(config);
750
906
  const sourceElement = document.createElement('wix-interact-element');
751
907
  const sourceDiv = document.createElement('div');
752
908
  sourceElement.append(sourceDiv);
@@ -755,9 +911,9 @@ describe('interact', () => {
755
911
  targetElement.append(targetDiv);
756
912
 
757
913
  // Add target first
758
- (0, _interact.add)(targetElement, '#cascade-target');
914
+ (0, _add.add)(targetElement, 'cascade-target');
759
915
  // Add source second
760
- (0, _interact.add)(sourceElement, '#cascade-source');
916
+ (0, _add.add)(sourceElement, 'cascade-source');
761
917
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
762
918
  expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
763
919
  namedEffect: expect.objectContaining({
@@ -786,13 +942,13 @@ describe('interact', () => {
786
942
  },
787
943
  interactions: [{
788
944
  trigger: 'click',
789
- source: '#multi-source-1',
945
+ key: 'multi-source-1',
790
946
  effects: [{
791
- target: '#cascade-target-1',
947
+ key: 'cascade-target-1',
792
948
  effectId: 'desktop-effect',
793
949
  conditions: ['desktop']
794
950
  }, {
795
- target: '#cascade-target-2',
951
+ key: 'cascade-target-2',
796
952
  effectId: 'mobile-effect',
797
953
  conditions: ['mobile']
798
954
  }]
@@ -817,7 +973,7 @@ describe('interact', () => {
817
973
  }
818
974
  };
819
975
  mockMatchMedia(['min-width: 1024px']); // Only desktop matches
820
- _interact.Interact.create(complexConfig);
976
+ _Interact.Interact.create(complexConfig);
821
977
  const sourceElement = document.createElement('wix-interact-element');
822
978
  const sourceDiv = document.createElement('div');
823
979
  sourceElement.append(sourceDiv);
@@ -827,9 +983,9 @@ describe('interact', () => {
827
983
  const target2Element = document.createElement('wix-interact-element');
828
984
  const target2Div = document.createElement('div');
829
985
  target2Element.append(target2Div);
830
- (0, _interact.add)(sourceElement, '#multi-source-1');
831
- (0, _interact.add)(target1Element, '#cascade-target-1');
832
- (0, _interact.add)(target2Element, '#cascade-target-2');
986
+ (0, _add.add)(sourceElement, 'multi-source-1');
987
+ (0, _add.add)(target1Element, 'cascade-target-1');
988
+ (0, _add.add)(target2Element, 'cascade-target-2');
833
989
 
834
990
  // Only desktop effect should be applied (mobile condition doesn't match)
835
991
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
@@ -867,12 +1023,12 @@ describe('interact', () => {
867
1023
  },
868
1024
  interactions: [{
869
1025
  trigger: 'click',
870
- source: '#cascade-source',
1026
+ key: 'cascade-source',
871
1027
  effects: [{
872
- target: '#cascade-target',
1028
+ key: 'cascade-target',
873
1029
  effectId: 'premium-effect'
874
1030
  }, {
875
- target: '#cascade-target',
1031
+ key: 'cascade-target',
876
1032
  effectId: 'premium-effect',
877
1033
  conditions: ['desktop', 'high-res']
878
1034
  }]
@@ -891,15 +1047,15 @@ describe('interact', () => {
891
1047
 
892
1048
  // Both conditions match
893
1049
  mockMatchMedia(['min-width: 1024px', 'min-resolution: 2dppx']);
894
- _interact.Interact.create(multiConditionConfig);
1050
+ _Interact.Interact.create(multiConditionConfig);
895
1051
  const sourceElement = document.createElement('wix-interact-element');
896
1052
  const sourceDiv = document.createElement('div');
897
1053
  sourceElement.append(sourceDiv);
898
1054
  const targetElement = document.createElement('wix-interact-element');
899
1055
  const targetDiv = document.createElement('div');
900
1056
  targetElement.append(targetDiv);
901
- (0, _interact.add)(sourceElement, '#cascade-source');
902
- (0, _interact.add)(targetElement, '#cascade-target');
1057
+ (0, _add.add)(sourceElement, 'cascade-source');
1058
+ (0, _add.add)(targetElement, 'cascade-target');
903
1059
 
904
1060
  // Premium effect should be applied since both conditions match
905
1061
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
@@ -926,12 +1082,12 @@ describe('interact', () => {
926
1082
  },
927
1083
  interactions: [{
928
1084
  trigger: 'click',
929
- source: '#cascade-source',
1085
+ key: 'cascade-source',
930
1086
  effects: [{
931
- target: '#cascade-target',
1087
+ key: 'cascade-target',
932
1088
  effectId: 'default-effect'
933
1089
  }, {
934
- target: '#cascade-target',
1090
+ key: 'cascade-target',
935
1091
  effectId: 'default-effect',
936
1092
  conditions: ['nonexistent-condition']
937
1093
  }]
@@ -947,15 +1103,15 @@ describe('interact', () => {
947
1103
  }
948
1104
  };
949
1105
  mockMatchMedia(['min-width: 1024px']);
950
- _interact.Interact.create(configWithMissingCondition);
1106
+ _Interact.Interact.create(configWithMissingCondition);
951
1107
  const sourceElement = document.createElement('wix-interact-element');
952
1108
  const sourceDiv = document.createElement('div');
953
1109
  sourceElement.append(sourceDiv);
954
1110
  const targetElement = document.createElement('wix-interact-element');
955
1111
  const targetDiv = document.createElement('div');
956
1112
  targetElement.append(targetDiv);
957
- (0, _interact.add)(sourceElement, '#cascade-source');
958
- (0, _interact.add)(targetElement, '#cascade-target');
1113
+ (0, _add.add)(sourceElement, 'cascade-source');
1114
+ (0, _add.add)(targetElement, 'cascade-target');
959
1115
 
960
1116
  // Should fall back to default effect since condition doesn't exist
961
1117
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
@@ -975,9 +1131,9 @@ describe('interact', () => {
975
1131
  conditions: {},
976
1132
  interactions: [{
977
1133
  trigger: 'click',
978
- source: '#cascade-source',
1134
+ key: 'cascade-source',
979
1135
  effects: [{
980
- target: '#cascade-target',
1136
+ key: 'cascade-target',
981
1137
  effectId: 'always-applied-effect',
982
1138
  conditions: []
983
1139
  }]
@@ -994,15 +1150,15 @@ describe('interact', () => {
994
1150
  }
995
1151
  };
996
1152
  mockMatchMedia([]);
997
- _interact.Interact.create(configWithEmptyConditions);
1153
+ _Interact.Interact.create(configWithEmptyConditions);
998
1154
  const sourceElement = document.createElement('wix-interact-element');
999
1155
  const sourceDiv = document.createElement('div');
1000
1156
  sourceElement.append(sourceDiv);
1001
1157
  const targetElement = document.createElement('wix-interact-element');
1002
1158
  const targetDiv = document.createElement('div');
1003
1159
  targetElement.append(targetDiv);
1004
- (0, _interact.add)(sourceElement, '#cascade-source');
1005
- (0, _interact.add)(targetElement, '#cascade-target');
1160
+ (0, _add.add)(sourceElement, 'cascade-source');
1161
+ (0, _add.add)(targetElement, 'cascade-target');
1006
1162
 
1007
1163
  // Effect should be applied since empty conditions array should always match
1008
1164
  expect(getWebAnimation).toHaveBeenCalledTimes(1);
@@ -1016,5 +1172,501 @@ describe('interact', () => {
1016
1172
  });
1017
1173
  });
1018
1174
  });
1175
+ describe('selector functionality', () => {
1176
+ let sourceElement;
1177
+ let targetElement;
1178
+ beforeEach(() => {
1179
+ // Create source element with multiple child elements
1180
+ sourceElement = document.createElement('wix-interact-element');
1181
+ sourceElement.innerHTML = `
1182
+ <div class="first-child">First Child</div>
1183
+ <button class="trigger-button">Click Me</button>
1184
+ <div class="other-element">Other</div>
1185
+ <div class="list-container">
1186
+ <div class="list-item">Item 1</div>
1187
+ <div class="list-item">Item 2</div>
1188
+ <div class="list-item">Item 3</div>
1189
+ </div>
1190
+ `;
1191
+
1192
+ // Create target element with multiple child elements
1193
+ targetElement = document.createElement('wix-interact-element');
1194
+ targetElement.innerHTML = `
1195
+ <div class="first-child">Target First</div>
1196
+ <div class="animation-target">Animation Target</div>
1197
+ <div class="overlay">Overlay</div>
1198
+ <div class="nested">
1199
+ <span class="deep-target">Deep Target</span>
1200
+ </div>
1201
+ `;
1202
+ });
1203
+ describe('basic selector functionality', () => {
1204
+ it('should use selector instead of firstElementChild for source', () => {
1205
+ const config = {
1206
+ effects: {
1207
+ 'test-effect': {
1208
+ keyframeEffect: {
1209
+ name: 'test',
1210
+ keyframes: [{
1211
+ opacity: '0'
1212
+ }, {
1213
+ opacity: '1'
1214
+ }]
1215
+ },
1216
+ duration: 300
1217
+ }
1218
+ },
1219
+ interactions: [{
1220
+ key: 'selector-source',
1221
+ selector: '.trigger-button',
1222
+ trigger: 'click',
1223
+ effects: [{
1224
+ key: 'selector-target',
1225
+ effectId: 'test-effect'
1226
+ }]
1227
+ }]
1228
+ };
1229
+ _Interact.Interact.create(config);
1230
+ const triggerButton = sourceElement.querySelector('.trigger-button');
1231
+ const firstChild = sourceElement.querySelector('.first-child');
1232
+ const triggerSpy = jest.spyOn(triggerButton, 'addEventListener');
1233
+ const firstChildSpy = jest.spyOn(firstChild, 'addEventListener');
1234
+ (0, _add.add)(sourceElement, 'selector-source');
1235
+ (0, _add.add)(targetElement, 'selector-target');
1236
+
1237
+ // Should add event listener to the selected element, not firstElementChild
1238
+ expect(triggerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
1239
+ expect(firstChildSpy).not.toHaveBeenCalled();
1240
+ });
1241
+ it('should use selector instead of firstElementChild for target', () => {
1242
+ const {
1243
+ getWebAnimation
1244
+ } = require('@wix/motion');
1245
+ const config = {
1246
+ effects: {
1247
+ 'test-effect': {
1248
+ keyframeEffect: {
1249
+ name: 'test',
1250
+ keyframes: [{
1251
+ opacity: '0'
1252
+ }, {
1253
+ opacity: '1'
1254
+ }]
1255
+ },
1256
+ duration: 300
1257
+ }
1258
+ },
1259
+ interactions: [{
1260
+ key: 'selector-source',
1261
+ trigger: 'click',
1262
+ effects: [{
1263
+ key: 'selector-target',
1264
+ selector: '.animation-target',
1265
+ effectId: 'test-effect'
1266
+ }]
1267
+ }]
1268
+ };
1269
+ _Interact.Interact.create(config);
1270
+ (0, _add.add)(sourceElement, 'selector-source');
1271
+ (0, _add.add)(targetElement, 'selector-target');
1272
+ const animationTarget = targetElement.querySelector('.animation-target');
1273
+
1274
+ // Should create animation on the selected element, not firstElementChild
1275
+ expect(getWebAnimation).toHaveBeenCalledWith(animationTarget, expect.any(Object), undefined, {
1276
+ reducedMotion: false
1277
+ });
1278
+ });
1279
+ it('should fall back to firstElementChild when no selector is provided', () => {
1280
+ const config = {
1281
+ effects: {
1282
+ 'test-effect': {
1283
+ keyframeEffect: {
1284
+ name: 'test',
1285
+ keyframes: [{
1286
+ opacity: '0'
1287
+ }, {
1288
+ opacity: '1'
1289
+ }]
1290
+ },
1291
+ duration: 300
1292
+ }
1293
+ },
1294
+ interactions: [{
1295
+ key: 'fallback-source',
1296
+ trigger: 'click',
1297
+ effects: [{
1298
+ key: 'fallback-target',
1299
+ effectId: 'test-effect'
1300
+ }]
1301
+ }]
1302
+ };
1303
+ _Interact.Interact.create(config);
1304
+ const firstChild = sourceElement.querySelector('.first-child');
1305
+ const firstChildSpy = jest.spyOn(firstChild, 'addEventListener');
1306
+ (0, _add.add)(sourceElement, 'fallback-source');
1307
+ (0, _add.add)(targetElement, 'fallback-target');
1308
+
1309
+ // Should fall back to firstElementChild
1310
+ expect(firstChildSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
1311
+ });
1312
+ });
1313
+ describe('selector with listContainer', () => {
1314
+ it('should use selector within listContainer items', () => {
1315
+ const config = {
1316
+ effects: {
1317
+ 'list-effect': {
1318
+ keyframeEffect: {
1319
+ name: 'list-test',
1320
+ keyframes: [{
1321
+ transform: 'scale(1)'
1322
+ }, {
1323
+ transform: 'scale(1.1)'
1324
+ }]
1325
+ },
1326
+ duration: 200
1327
+ }
1328
+ },
1329
+ interactions: [{
1330
+ key: 'list-source',
1331
+ listContainer: '.list-container',
1332
+ selector: '.list-item',
1333
+ trigger: 'hover',
1334
+ effects: [{
1335
+ listContainer: '.list-container',
1336
+ selector: '.list-item',
1337
+ effectId: 'list-effect'
1338
+ }]
1339
+ }]
1340
+ };
1341
+ _Interact.Interact.create(config);
1342
+
1343
+ // Set up spies before adding interactions
1344
+ const listItems = Array.from(sourceElement.querySelectorAll('.list-item'));
1345
+ const spies = listItems.map(item => jest.spyOn(item, 'addEventListener'));
1346
+ (0, _add.add)(sourceElement, 'list-source');
1347
+
1348
+ // Should add event listeners to each list item
1349
+ spies.forEach(spy => {
1350
+ expect(spy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.any(Object));
1351
+ });
1352
+ });
1353
+ it('should handle listContainer without selector (all children)', () => {
1354
+ var _sourceElement$queryS;
1355
+ const config = {
1356
+ effects: {
1357
+ 'container-effect': {
1358
+ keyframeEffect: {
1359
+ name: 'container-test',
1360
+ keyframes: [{
1361
+ opacity: '0.5'
1362
+ }, {
1363
+ opacity: '1'
1364
+ }]
1365
+ },
1366
+ duration: 150
1367
+ }
1368
+ },
1369
+ interactions: [{
1370
+ key: 'container-source',
1371
+ listContainer: '.list-container',
1372
+ trigger: 'click',
1373
+ effects: [{
1374
+ listContainer: '.list-container',
1375
+ effectId: 'container-effect'
1376
+ }]
1377
+ }]
1378
+ };
1379
+ _Interact.Interact.create(config);
1380
+
1381
+ // Set up spies before adding interactions
1382
+ const containerChildren = Array.from(((_sourceElement$queryS = sourceElement.querySelector('.list-container')) == null ? void 0 : _sourceElement$queryS.children) || []);
1383
+ const spies = containerChildren.map(child => jest.spyOn(child, 'addEventListener'));
1384
+ (0, _add.add)(sourceElement, 'container-source');
1385
+
1386
+ // Should add event listeners to all children of the container
1387
+ spies.forEach(spy => {
1388
+ expect(spy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
1389
+ });
1390
+ });
1391
+ });
1392
+ describe('selector error handling', () => {
1393
+ let consoleSpy;
1394
+ beforeEach(() => {
1395
+ consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
1396
+ });
1397
+ afterEach(() => {
1398
+ consoleSpy.mockRestore();
1399
+ });
1400
+ it('should warn when selector does not match any elements', () => {
1401
+ const config = {
1402
+ effects: {
1403
+ 'test-effect': {
1404
+ keyframeEffect: {
1405
+ name: 'test',
1406
+ keyframes: [{
1407
+ opacity: '0'
1408
+ }, {
1409
+ opacity: '1'
1410
+ }]
1411
+ },
1412
+ duration: 300
1413
+ }
1414
+ },
1415
+ interactions: [{
1416
+ key: 'invalid-source',
1417
+ selector: '.non-existent-element',
1418
+ trigger: 'click',
1419
+ effects: [{
1420
+ key: 'invalid-target',
1421
+ effectId: 'test-effect'
1422
+ }]
1423
+ }]
1424
+ };
1425
+ _Interact.Interact.create(config);
1426
+ (0, _add.add)(sourceElement, 'invalid-source');
1427
+ (0, _add.add)(targetElement, 'invalid-target');
1428
+ expect(consoleSpy).toHaveBeenCalledWith('WixInteract: No element found for selector ".non-existent-element"');
1429
+ });
1430
+ it('should warn when listContainer selector does not match', () => {
1431
+ const config = {
1432
+ effects: {
1433
+ 'test-effect': {
1434
+ keyframeEffect: {
1435
+ name: 'test',
1436
+ keyframes: [{
1437
+ opacity: '0'
1438
+ }, {
1439
+ opacity: '1'
1440
+ }]
1441
+ },
1442
+ duration: 300
1443
+ }
1444
+ },
1445
+ interactions: [{
1446
+ key: 'invalid-container-source',
1447
+ listContainer: '.non-existent-container',
1448
+ trigger: 'click',
1449
+ effects: [{
1450
+ key: 'invalid-container-target',
1451
+ effectId: 'test-effect'
1452
+ }]
1453
+ }]
1454
+ };
1455
+ _Interact.Interact.create(config);
1456
+ (0, _add.add)(sourceElement, 'invalid-container-source');
1457
+ (0, _add.add)(targetElement, 'invalid-container-target');
1458
+ expect(consoleSpy).toHaveBeenCalledWith('WixInteract: No container found for list container ".non-existent-container"');
1459
+ });
1460
+ it('should gracefully handle invalid selectors without breaking interactions', () => {
1461
+ const config = {
1462
+ effects: {
1463
+ 'valid-effect': {
1464
+ keyframeEffect: {
1465
+ name: 'valid',
1466
+ keyframes: [{
1467
+ opacity: '0'
1468
+ }, {
1469
+ opacity: '1'
1470
+ }]
1471
+ },
1472
+ duration: 300
1473
+ }
1474
+ },
1475
+ interactions: [{
1476
+ key: 'mixed-source',
1477
+ selector: '.non-existent',
1478
+ trigger: 'click',
1479
+ effects: [{
1480
+ key: 'mixed-target',
1481
+ effectId: 'valid-effect'
1482
+ }]
1483
+ }, {
1484
+ key: 'valid-source',
1485
+ selector: '.trigger-button',
1486
+ trigger: 'click',
1487
+ effects: [{
1488
+ key: 'valid-target',
1489
+ effectId: 'valid-effect'
1490
+ }]
1491
+ }]
1492
+ };
1493
+ _Interact.Interact.create(config);
1494
+
1495
+ // Set up spy before adding interactions
1496
+ const triggerButton = sourceElement.querySelector('.trigger-button');
1497
+ const spy = jest.spyOn(triggerButton, 'addEventListener');
1498
+
1499
+ // This should not throw and should allow other interactions to work
1500
+ expect(() => {
1501
+ (0, _add.add)(sourceElement, 'mixed-source');
1502
+ (0, _add.add)(sourceElement, 'valid-source');
1503
+ (0, _add.add)(targetElement, 'mixed-target');
1504
+ (0, _add.add)(targetElement, 'valid-target');
1505
+ }).not.toThrow();
1506
+
1507
+ // Valid interaction should still work
1508
+ expect(spy).toHaveBeenCalled();
1509
+ });
1510
+ });
1511
+ describe('complex selector scenarios', () => {
1512
+ it('should handle nested selectors', () => {
1513
+ const {
1514
+ getWebAnimation
1515
+ } = require('@wix/motion');
1516
+ const config = {
1517
+ effects: {
1518
+ 'nested-effect': {
1519
+ keyframeEffect: {
1520
+ name: 'nested',
1521
+ keyframes: [{
1522
+ color: 'black'
1523
+ }, {
1524
+ color: 'blue'
1525
+ }]
1526
+ },
1527
+ duration: 200
1528
+ }
1529
+ },
1530
+ interactions: [{
1531
+ key: 'nested-source',
1532
+ selector: '.other-element',
1533
+ trigger: 'click',
1534
+ effects: [{
1535
+ key: 'nested-target',
1536
+ selector: '.nested .deep-target',
1537
+ effectId: 'nested-effect'
1538
+ }]
1539
+ }]
1540
+ };
1541
+ _Interact.Interact.create(config);
1542
+ const addEventListenerSpy = jest.spyOn(sourceElement.querySelector('.other-element'), 'addEventListener');
1543
+ (0, _add.add)(sourceElement, 'nested-source');
1544
+ (0, _add.add)(targetElement, 'nested-target');
1545
+ const deepTarget = targetElement.querySelector('.nested .deep-target');
1546
+ expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
1547
+ expect(getWebAnimation).toHaveBeenCalledWith(deepTarget, expect.any(Object), undefined, {
1548
+ reducedMotion: false
1549
+ });
1550
+ });
1551
+ it('should handle attribute selectors', () => {
1552
+ // Add data attributes to test elements
1553
+ const buttonWithData = sourceElement.querySelector('.trigger-button');
1554
+ buttonWithData.setAttribute('data-interactive', 'true');
1555
+ buttonWithData.setAttribute('data-category', 'primary');
1556
+ const config = {
1557
+ effects: {
1558
+ 'attr-effect': {
1559
+ keyframeEffect: {
1560
+ name: 'attr',
1561
+ keyframes: [{
1562
+ backgroundColor: 'white'
1563
+ }, {
1564
+ backgroundColor: 'lightblue'
1565
+ }]
1566
+ },
1567
+ duration: 300
1568
+ }
1569
+ },
1570
+ interactions: [{
1571
+ key: 'attr-source',
1572
+ selector: '[data-interactive="true"][data-category="primary"]',
1573
+ trigger: 'click',
1574
+ effects: [{
1575
+ key: 'attr-target',
1576
+ selector: '[class*="animation"]',
1577
+ effectId: 'attr-effect'
1578
+ }]
1579
+ }]
1580
+ };
1581
+ _Interact.Interact.create(config);
1582
+
1583
+ // Set up spy before adding interactions
1584
+ const spy = jest.spyOn(buttonWithData, 'addEventListener');
1585
+ (0, _add.add)(sourceElement, 'attr-source');
1586
+ (0, _add.add)(targetElement, 'attr-target');
1587
+ expect(spy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
1588
+ });
1589
+ });
1590
+ describe('selector inheritance and priority', () => {
1591
+ it('should not inherit selector from interaction to effect', () => {
1592
+ const {
1593
+ getWebAnimation
1594
+ } = require('@wix/motion');
1595
+ const config = {
1596
+ effects: {
1597
+ 'inherit-effect': {
1598
+ keyframeEffect: {
1599
+ name: 'inherit',
1600
+ keyframes: [{
1601
+ opacity: '0'
1602
+ }, {
1603
+ opacity: '1'
1604
+ }]
1605
+ },
1606
+ duration: 300
1607
+ }
1608
+ },
1609
+ interactions: [{
1610
+ key: 'inherit-source',
1611
+ selector: '.trigger-button',
1612
+ // Interaction has selector
1613
+ trigger: 'click',
1614
+ effects: [{
1615
+ key: 'inherit-target',
1616
+ // Effect has no selector - should use firstElementChild, not inherit
1617
+ effectId: 'inherit-effect'
1618
+ }]
1619
+ }]
1620
+ };
1621
+ _Interact.Interact.create(config);
1622
+ (0, _add.add)(sourceElement, 'inherit-source');
1623
+ (0, _add.add)(targetElement, 'inherit-target');
1624
+
1625
+ // Effect should target firstElementChild, not the interaction's selector
1626
+ const targetFirstChild = targetElement.firstElementChild;
1627
+ expect(getWebAnimation).toHaveBeenCalledWith(targetFirstChild, expect.any(Object), undefined, {
1628
+ reducedMotion: false
1629
+ });
1630
+ });
1631
+ });
1632
+ describe('selector cleanup', () => {
1633
+ it('should clean up selector-based interactions on remove', () => {
1634
+ const config = {
1635
+ effects: {
1636
+ 'cleanup-effect': {
1637
+ keyframeEffect: {
1638
+ name: 'cleanup',
1639
+ keyframes: [{
1640
+ opacity: '0'
1641
+ }, {
1642
+ opacity: '1'
1643
+ }]
1644
+ },
1645
+ duration: 300
1646
+ }
1647
+ },
1648
+ interactions: [{
1649
+ key: 'cleanup-source',
1650
+ selector: '.trigger-button',
1651
+ trigger: 'click',
1652
+ effects: [{
1653
+ key: 'cleanup-target',
1654
+ selector: '.animation-target',
1655
+ effectId: 'cleanup-effect'
1656
+ }]
1657
+ }]
1658
+ };
1659
+ _Interact.Interact.create(config);
1660
+ const triggerButton = sourceElement.querySelector('.trigger-button');
1661
+ const removeEventListenerSpy = jest.spyOn(triggerButton, 'removeEventListener');
1662
+ (0, _add.add)(sourceElement, 'cleanup-source');
1663
+ (0, _add.add)(targetElement, 'cleanup-target');
1664
+ (0, _remove.remove)('cleanup-source');
1665
+
1666
+ // Should remove event listeners from the selected element
1667
+ expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function));
1668
+ });
1669
+ });
1670
+ });
1019
1671
  });
1020
1672
  //# sourceMappingURL=interact.spec.js.map