@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.
- package/README.md +33 -21
- package/dist/cjs/WixInteractElement.js +61 -17
- package/dist/cjs/WixInteractElement.js.map +1 -1
- package/dist/cjs/__tests__/interact.spec.js +761 -109
- package/dist/cjs/__tests__/interact.spec.js.map +1 -1
- package/dist/cjs/core/Interact.js +190 -0
- package/dist/cjs/core/Interact.js.map +1 -0
- package/dist/cjs/core/add.js +231 -0
- package/dist/cjs/core/add.js.map +1 -0
- package/dist/cjs/core/remove.js +37 -0
- package/dist/cjs/core/remove.js.map +1 -0
- package/dist/cjs/handlers/click.js +1 -1
- package/dist/cjs/handlers/click.js.map +1 -1
- package/dist/cjs/handlers/hover.js +1 -1
- package/dist/cjs/handlers/hover.js.map +1 -1
- package/dist/cjs/index.js +6 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils.js +12 -10
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/WixInteractElement.js +61 -17
- package/dist/esm/WixInteractElement.js.map +1 -1
- package/dist/esm/__tests__/interact.spec.js +743 -91
- package/dist/esm/__tests__/interact.spec.js.map +1 -1
- package/dist/esm/core/Interact.js +186 -0
- package/dist/esm/core/Interact.js.map +1 -0
- package/dist/esm/core/add.js +226 -0
- package/dist/esm/core/add.js.map +1 -0
- package/dist/esm/core/remove.js +32 -0
- package/dist/esm/core/remove.js.map +1 -0
- package/dist/esm/handlers/click.js +1 -1
- package/dist/esm/handlers/click.js.map +1 -1
- package/dist/esm/handlers/hover.js +1 -1
- package/dist/esm/handlers/hover.js.map +1 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils.js +12 -10
- package/dist/esm/utils.js.map +1 -1
- package/dist/types/WixInteractElement.d.ts +5 -2
- package/dist/types/core/Interact.d.ts +24 -0
- package/dist/types/core/add.d.ts +6 -0
- package/dist/types/core/remove.d.ts +5 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/types.d.ts +22 -9
- package/dist/types/utils.d.ts +1 -1
- package/package.json +7 -6
- package/dist/cjs/interact.js +0 -308
- package/dist/cjs/interact.js.map +0 -1
- package/dist/esm/interact.js +0 -301
- package/dist/esm/interact.js.map +0 -1
- package/dist/types/interact.d.ts +0 -26
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { Interact
|
|
1
|
+
import { Interact } from '../core/Interact';
|
|
2
|
+
import { add, addListItems } from '../core/add';
|
|
3
|
+
import { remove } from '../core/remove';
|
|
2
4
|
import { effectToAnimationOptions } from '../handlers/utilities';
|
|
3
5
|
|
|
4
6
|
// Mock @wix/motion module
|
|
@@ -40,75 +42,75 @@ describe('interact', () => {
|
|
|
40
42
|
const mockConfig = {
|
|
41
43
|
interactions: [{
|
|
42
44
|
trigger: 'viewEnter',
|
|
43
|
-
|
|
45
|
+
key: 'logo-entrance',
|
|
44
46
|
params: {
|
|
45
47
|
threshold: 0.2
|
|
46
48
|
},
|
|
47
49
|
effects: [{
|
|
48
|
-
|
|
50
|
+
key: 'logo-entrance',
|
|
49
51
|
effectId: 'logo-arc-in'
|
|
50
52
|
}, {
|
|
51
|
-
|
|
53
|
+
key: 'logo-click',
|
|
52
54
|
effectId: 'logo-bounce'
|
|
53
55
|
}]
|
|
54
56
|
}, {
|
|
55
57
|
trigger: 'pageVisible',
|
|
56
|
-
|
|
58
|
+
key: 'logo-loop',
|
|
57
59
|
effects: [{
|
|
58
|
-
|
|
60
|
+
key: 'logo-loop',
|
|
59
61
|
effectId: 'logo-poke'
|
|
60
62
|
}]
|
|
61
63
|
}, {
|
|
62
64
|
trigger: 'animationEnd',
|
|
63
|
-
|
|
65
|
+
key: 'logo-animation-end',
|
|
64
66
|
params: {
|
|
65
67
|
effectId: 'logo-arc-in'
|
|
66
68
|
},
|
|
67
69
|
effects: [{
|
|
68
|
-
|
|
70
|
+
key: 'logo-animation-end',
|
|
69
71
|
effectId: 'logo-poke'
|
|
70
72
|
}]
|
|
71
73
|
}, {
|
|
72
74
|
trigger: 'pointerMove',
|
|
73
|
-
|
|
75
|
+
key: 'logo-mouse',
|
|
74
76
|
params: {
|
|
75
77
|
hitArea: 'root'
|
|
76
78
|
},
|
|
77
79
|
effects: [{
|
|
78
|
-
|
|
80
|
+
key: 'logo-mouse',
|
|
79
81
|
effectId: 'logo-track-mouse'
|
|
80
82
|
}]
|
|
81
83
|
}, {
|
|
82
84
|
trigger: 'click',
|
|
83
|
-
|
|
85
|
+
key: 'logo-click',
|
|
84
86
|
params: {
|
|
85
87
|
type: 'alternate'
|
|
86
88
|
},
|
|
87
89
|
effects: [{
|
|
88
|
-
|
|
90
|
+
key: 'logo-click',
|
|
89
91
|
effectId: 'logo-bounce'
|
|
90
92
|
}]
|
|
91
93
|
}, {
|
|
92
94
|
trigger: 'click',
|
|
93
|
-
|
|
95
|
+
key: 'logo-click',
|
|
94
96
|
params: {
|
|
95
97
|
method: 'toggle'
|
|
96
98
|
},
|
|
97
99
|
effects: [{
|
|
98
|
-
|
|
100
|
+
key: 'logo-click',
|
|
99
101
|
effectId: 'logo-transition-hover'
|
|
100
102
|
}]
|
|
101
103
|
}, {
|
|
102
104
|
trigger: 'hover',
|
|
103
|
-
|
|
105
|
+
key: 'logo-hover',
|
|
104
106
|
params: {
|
|
105
107
|
type: 'alternate'
|
|
106
108
|
},
|
|
107
109
|
effects: [{
|
|
108
|
-
|
|
110
|
+
key: 'logo-hover',
|
|
109
111
|
effectId: 'logo-arc-in'
|
|
110
112
|
}, {
|
|
111
|
-
|
|
113
|
+
key: 'logo-hover',
|
|
112
114
|
effectId: 'logo-arc-in',
|
|
113
115
|
namedEffect: {
|
|
114
116
|
type: 'ArcIn',
|
|
@@ -118,19 +120,49 @@ describe('interact', () => {
|
|
|
118
120
|
}]
|
|
119
121
|
}, {
|
|
120
122
|
trigger: 'hover',
|
|
121
|
-
|
|
123
|
+
key: 'logo-hover',
|
|
122
124
|
params: {
|
|
123
125
|
method: 'toggle'
|
|
124
126
|
},
|
|
125
127
|
effects: [{
|
|
126
|
-
|
|
128
|
+
key: 'logo-hover',
|
|
127
129
|
effectId: 'logo-transition-hover'
|
|
128
130
|
}]
|
|
129
131
|
}, {
|
|
130
132
|
trigger: 'viewProgress',
|
|
131
|
-
|
|
133
|
+
key: 'logo-scroll',
|
|
132
134
|
effects: [{
|
|
133
|
-
|
|
135
|
+
key: 'logo-scroll',
|
|
136
|
+
effectId: 'logo-fade-scroll'
|
|
137
|
+
}]
|
|
138
|
+
}, {
|
|
139
|
+
trigger: 'click',
|
|
140
|
+
key: 'logo-click-container',
|
|
141
|
+
listContainer: '#logo-list',
|
|
142
|
+
effects: [{
|
|
143
|
+
effectId: 'logo-bounce'
|
|
144
|
+
}]
|
|
145
|
+
}, {
|
|
146
|
+
trigger: 'viewEnter',
|
|
147
|
+
key: 'logo-view-container',
|
|
148
|
+
effects: [{
|
|
149
|
+
listContainer: '#logo-list',
|
|
150
|
+
effectId: 'logo-bounce'
|
|
151
|
+
}]
|
|
152
|
+
}, {
|
|
153
|
+
trigger: 'viewProgress',
|
|
154
|
+
key: 'logo-scroll-container',
|
|
155
|
+
listContainer: '#logo-scroll-list',
|
|
156
|
+
effects: [{
|
|
157
|
+
listContainer: '#logo-scroll-list',
|
|
158
|
+
effectId: 'logo-fade-scroll'
|
|
159
|
+
}]
|
|
160
|
+
}, {
|
|
161
|
+
trigger: 'viewProgress',
|
|
162
|
+
key: 'logo-scroll-container',
|
|
163
|
+
effects: [{
|
|
164
|
+
key: 'logo-scroll-items',
|
|
165
|
+
listContainer: '#logo-scroll-list',
|
|
134
166
|
effectId: 'logo-fade-scroll'
|
|
135
167
|
}]
|
|
136
168
|
}],
|
|
@@ -144,7 +176,7 @@ describe('interact', () => {
|
|
|
144
176
|
duration: 1200
|
|
145
177
|
},
|
|
146
178
|
'logo-arc-in-with-target': {
|
|
147
|
-
|
|
179
|
+
key: 'logo-hover',
|
|
148
180
|
namedEffect: {
|
|
149
181
|
type: 'ArcIn',
|
|
150
182
|
direction: 'right',
|
|
@@ -268,7 +300,8 @@ describe('interact', () => {
|
|
|
268
300
|
window.CSSStyleSheet = class CSSStyleSheet {
|
|
269
301
|
constructor(_) {
|
|
270
302
|
return {
|
|
271
|
-
replace: jest.fn()
|
|
303
|
+
replace: jest.fn(),
|
|
304
|
+
insertRule: jest.fn()
|
|
272
305
|
};
|
|
273
306
|
}
|
|
274
307
|
};
|
|
@@ -327,12 +360,12 @@ describe('interact', () => {
|
|
|
327
360
|
},
|
|
328
361
|
interactions: [{
|
|
329
362
|
trigger: 'click',
|
|
330
|
-
|
|
363
|
+
key: 'cascade-source',
|
|
331
364
|
effects: [{
|
|
332
|
-
|
|
365
|
+
key: 'cascade-target',
|
|
333
366
|
effectId: 'default-effect'
|
|
334
367
|
}, {
|
|
335
|
-
|
|
368
|
+
key: 'cascade-target',
|
|
336
369
|
effectId: 'default-effect',
|
|
337
370
|
conditions: ['desktop'],
|
|
338
371
|
namedEffect: {
|
|
@@ -342,7 +375,7 @@ describe('interact', () => {
|
|
|
342
375
|
},
|
|
343
376
|
duration: 800
|
|
344
377
|
}, {
|
|
345
|
-
|
|
378
|
+
key: 'cascade-target',
|
|
346
379
|
effectId: 'default-effect',
|
|
347
380
|
conditions: ['mobile'],
|
|
348
381
|
namedEffect: {
|
|
@@ -366,23 +399,25 @@ describe('interact', () => {
|
|
|
366
399
|
}
|
|
367
400
|
afterEach(() => {
|
|
368
401
|
jest.clearAllMocks();
|
|
369
|
-
remove('
|
|
370
|
-
remove('
|
|
371
|
-
remove('
|
|
372
|
-
remove('
|
|
373
|
-
remove('
|
|
374
|
-
remove('
|
|
375
|
-
remove('
|
|
402
|
+
remove('logo-entrance');
|
|
403
|
+
remove('logo-loop');
|
|
404
|
+
remove('logo-animation-end');
|
|
405
|
+
remove('logo-mouse');
|
|
406
|
+
remove('logo-click');
|
|
407
|
+
remove('logo-hover');
|
|
408
|
+
remove('logo-scroll');
|
|
376
409
|
// Clean up cascading test elements
|
|
377
|
-
remove('
|
|
378
|
-
remove('
|
|
379
|
-
remove('
|
|
380
|
-
remove('
|
|
381
|
-
remove('
|
|
382
|
-
remove('
|
|
410
|
+
remove('cascade-source');
|
|
411
|
+
remove('cascade-target');
|
|
412
|
+
remove('cascade-target-1');
|
|
413
|
+
remove('cascade-target-2');
|
|
414
|
+
remove('multi-source-1');
|
|
415
|
+
remove('multi-source-2');
|
|
383
416
|
// Clear Interact instances to ensure test isolation
|
|
384
417
|
Interact.instances.length = 0;
|
|
385
418
|
Interact.elementCache.clear();
|
|
419
|
+
// Reset forceReducedMotion to default
|
|
420
|
+
Interact.forceReducedMotion = false;
|
|
386
421
|
});
|
|
387
422
|
describe('init Interact', () => {
|
|
388
423
|
it('should initialize with valid config', () => {
|
|
@@ -399,9 +434,9 @@ describe('interact', () => {
|
|
|
399
434
|
Interact.create({
|
|
400
435
|
interactions: [{
|
|
401
436
|
trigger: 'hover',
|
|
402
|
-
|
|
437
|
+
key: 'logo-hover',
|
|
403
438
|
effects: [{
|
|
404
|
-
|
|
439
|
+
key: 'logo-hover',
|
|
405
440
|
effectId: 'logo-arc-in'
|
|
406
441
|
}]
|
|
407
442
|
}],
|
|
@@ -419,12 +454,12 @@ describe('interact', () => {
|
|
|
419
454
|
element = document.createElement('wix-interact-element');
|
|
420
455
|
const div = document.createElement('div');
|
|
421
456
|
element.append(div);
|
|
422
|
-
add(element, '
|
|
457
|
+
add(element, 'logo-hover');
|
|
423
458
|
expect(getWebAnimation).toHaveBeenCalledWith(div, expect.any(Object), undefined, {
|
|
424
459
|
reducedMotion: true
|
|
425
460
|
});
|
|
426
461
|
Interact.forceReducedMotion = false;
|
|
427
|
-
remove('
|
|
462
|
+
remove('logo-hover');
|
|
428
463
|
});
|
|
429
464
|
});
|
|
430
465
|
describe('add interaction', () => {
|
|
@@ -440,7 +475,7 @@ describe('interact', () => {
|
|
|
440
475
|
const div = document.createElement('div');
|
|
441
476
|
element.append(div);
|
|
442
477
|
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
443
|
-
add(element, '
|
|
478
|
+
add(element, 'logo-hover');
|
|
444
479
|
expect(addEventListenerSpy).toHaveBeenCalledTimes(4);
|
|
445
480
|
expect(addEventListenerSpy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.objectContaining({
|
|
446
481
|
passive: true
|
|
@@ -466,7 +501,7 @@ describe('interact', () => {
|
|
|
466
501
|
const div = document.createElement('div');
|
|
467
502
|
element.append(div);
|
|
468
503
|
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
469
|
-
add(element, '
|
|
504
|
+
add(element, 'logo-click');
|
|
470
505
|
expect(addEventListenerSpy).toHaveBeenCalledTimes(2);
|
|
471
506
|
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
472
507
|
passive: true
|
|
@@ -481,7 +516,7 @@ describe('interact', () => {
|
|
|
481
516
|
element = document.createElement('wix-interact-element');
|
|
482
517
|
const div = document.createElement('div');
|
|
483
518
|
element.append(div);
|
|
484
|
-
add(element, '
|
|
519
|
+
add(element, 'logo-entrance');
|
|
485
520
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
486
521
|
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
|
|
487
522
|
reducedMotion: false
|
|
@@ -493,14 +528,25 @@ describe('interact', () => {
|
|
|
493
528
|
} = require('@wix/motion');
|
|
494
529
|
element = document.createElement('wix-interact-element');
|
|
495
530
|
const div = document.createElement('div');
|
|
531
|
+
div.id = 'logo-entrance';
|
|
496
532
|
element.append(div);
|
|
497
533
|
const elementClick = document.createElement('wix-interact-element');
|
|
498
534
|
const divClick = document.createElement('div');
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
add(
|
|
502
|
-
|
|
503
|
-
expect(getWebAnimation).
|
|
535
|
+
divClick.id = 'logo-click';
|
|
536
|
+
elementClick.append(divClick);
|
|
537
|
+
add(elementClick, 'logo-click');
|
|
538
|
+
add(element, 'logo-entrance');
|
|
539
|
+
expect(getWebAnimation).toHaveBeenCalledTimes(3);
|
|
540
|
+
expect(getWebAnimation.mock.calls[0][0]).toBe(divClick);
|
|
541
|
+
expect(getWebAnimation.mock.calls[1][0]).toBe(div);
|
|
542
|
+
expect(getWebAnimation.mock.calls[2][0]).toBe(divClick);
|
|
543
|
+
expect(getWebAnimation.mock.calls[0][3]).toMatchObject({
|
|
544
|
+
reducedMotion: false
|
|
545
|
+
});
|
|
546
|
+
expect(getWebAnimation.mock.calls[1][3]).toMatchObject({
|
|
547
|
+
reducedMotion: false
|
|
548
|
+
});
|
|
549
|
+
expect(getWebAnimation.mock.calls[2][3]).toMatchObject({
|
|
504
550
|
reducedMotion: false
|
|
505
551
|
});
|
|
506
552
|
});
|
|
@@ -513,7 +559,7 @@ describe('interact', () => {
|
|
|
513
559
|
element = document.createElement('wix-interact-element');
|
|
514
560
|
const div = document.createElement('div');
|
|
515
561
|
element.append(div);
|
|
516
|
-
add(element, '
|
|
562
|
+
add(element, 'logo-loop');
|
|
517
563
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
518
564
|
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
|
|
519
565
|
reducedMotion: false
|
|
@@ -528,7 +574,7 @@ describe('interact', () => {
|
|
|
528
574
|
element = document.createElement('wix-interact-element');
|
|
529
575
|
const div = document.createElement('div');
|
|
530
576
|
element.append(div);
|
|
531
|
-
add(element, '
|
|
577
|
+
add(element, 'logo-animation-end');
|
|
532
578
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
533
579
|
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
|
|
534
580
|
reducedMotion: false
|
|
@@ -551,7 +597,7 @@ describe('interact', () => {
|
|
|
551
597
|
element = document.createElement('wix-interact-element');
|
|
552
598
|
const div = document.createElement('div');
|
|
553
599
|
element.append(div);
|
|
554
|
-
add(element, '
|
|
600
|
+
add(element, 'logo-mouse');
|
|
555
601
|
expect(getScrubScene).toHaveBeenCalledTimes(1);
|
|
556
602
|
expect(getScrubScene).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining(effectToAnimationOptions(mockConfig.effects['logo-track-mouse'])), expect.objectContaining({
|
|
557
603
|
trigger: 'pointer-move'
|
|
@@ -567,7 +613,7 @@ describe('interact', () => {
|
|
|
567
613
|
element = document.createElement('wix-interact-element');
|
|
568
614
|
const div = document.createElement('div');
|
|
569
615
|
element.append(div);
|
|
570
|
-
add(element, '
|
|
616
|
+
add(element, 'logo-scroll');
|
|
571
617
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
572
618
|
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining(effectToAnimationOptions(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
|
|
573
619
|
trigger: 'view-progress'
|
|
@@ -590,7 +636,7 @@ describe('interact', () => {
|
|
|
590
636
|
element = document.createElement('wix-interact-element');
|
|
591
637
|
const div = document.createElement('div');
|
|
592
638
|
element.append(div);
|
|
593
|
-
add(element, '
|
|
639
|
+
add(element, 'logo-scroll');
|
|
594
640
|
expect(getScrubScene).toHaveBeenCalledTimes(1);
|
|
595
641
|
expect(getScrubScene).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining(effectToAnimationOptions(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
|
|
596
642
|
trigger: 'view-progress'
|
|
@@ -600,6 +646,116 @@ describe('interact', () => {
|
|
|
600
646
|
}, 0);
|
|
601
647
|
});
|
|
602
648
|
});
|
|
649
|
+
describe('listContainer', () => {
|
|
650
|
+
it('should add a handler per list item for click trigger with listContainer', () => {
|
|
651
|
+
element = document.createElement('wix-interact-element');
|
|
652
|
+
const div = document.createElement('div');
|
|
653
|
+
const ul = document.createElement('ul');
|
|
654
|
+
ul.id = 'logo-list';
|
|
655
|
+
div.append(ul);
|
|
656
|
+
const li = document.createElement('li');
|
|
657
|
+
const li2 = li.cloneNode(true);
|
|
658
|
+
ul.append(li);
|
|
659
|
+
ul.append(li2);
|
|
660
|
+
element.append(div);
|
|
661
|
+
const addEventListenerSpy = jest.spyOn(li, 'addEventListener');
|
|
662
|
+
const addEventListenerSpy2 = jest.spyOn(li2, 'addEventListener');
|
|
663
|
+
add(element, 'logo-click-container');
|
|
664
|
+
expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
|
|
665
|
+
expect(addEventListenerSpy2).toHaveBeenCalledTimes(1);
|
|
666
|
+
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
667
|
+
passive: true
|
|
668
|
+
}));
|
|
669
|
+
expect(addEventListenerSpy2).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
670
|
+
passive: true
|
|
671
|
+
}));
|
|
672
|
+
});
|
|
673
|
+
it('should add a handler per list item for viewEnter trigger with listContainer in effect', () => {
|
|
674
|
+
const {
|
|
675
|
+
getWebAnimation
|
|
676
|
+
} = require('@wix/motion');
|
|
677
|
+
element = document.createElement('wix-interact-element');
|
|
678
|
+
const div = document.createElement('div');
|
|
679
|
+
const ul = document.createElement('ul');
|
|
680
|
+
ul.id = 'logo-list';
|
|
681
|
+
div.append(ul);
|
|
682
|
+
const li = document.createElement('li');
|
|
683
|
+
const li2 = li.cloneNode(true);
|
|
684
|
+
ul.append(li);
|
|
685
|
+
ul.append(li2);
|
|
686
|
+
element.append(div);
|
|
687
|
+
add(element, 'logo-view-container');
|
|
688
|
+
expect(getWebAnimation).toHaveBeenCalledTimes(2);
|
|
689
|
+
expect(getWebAnimation.mock.calls[0][0]).toBe(li);
|
|
690
|
+
expect(getWebAnimation.mock.calls[1][0]).toBe(li2);
|
|
691
|
+
});
|
|
692
|
+
it('should add a handler per newly added list item for click trigger with listContainer', () => {
|
|
693
|
+
element = document.createElement('wix-interact-element');
|
|
694
|
+
const div = document.createElement('div');
|
|
695
|
+
const ul = document.createElement('ul');
|
|
696
|
+
ul.id = 'logo-list';
|
|
697
|
+
div.append(ul);
|
|
698
|
+
const li = document.createElement('li');
|
|
699
|
+
const li2 = li.cloneNode(true);
|
|
700
|
+
ul.append(li);
|
|
701
|
+
ul.append(li2);
|
|
702
|
+
element.append(div);
|
|
703
|
+
const addEventListenerSpy = jest.spyOn(li, 'addEventListener');
|
|
704
|
+
const addEventListenerSpy2 = jest.spyOn(li2, 'addEventListener');
|
|
705
|
+
add(element, 'logo-click-container');
|
|
706
|
+
expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
|
|
707
|
+
expect(addEventListenerSpy2).toHaveBeenCalledTimes(1);
|
|
708
|
+
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
709
|
+
passive: true
|
|
710
|
+
}));
|
|
711
|
+
expect(addEventListenerSpy2).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
712
|
+
passive: true
|
|
713
|
+
}));
|
|
714
|
+
const li3 = document.createElement('li');
|
|
715
|
+
ul.append(li3);
|
|
716
|
+
const addEventListenerSpy3 = jest.spyOn(li3, 'addEventListener');
|
|
717
|
+
addListItems(element, 'logo-click-container', '#logo-list', [li3]);
|
|
718
|
+
expect(addEventListenerSpy3).toHaveBeenCalledTimes(1);
|
|
719
|
+
expect(addEventListenerSpy3).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
720
|
+
passive: true
|
|
721
|
+
}));
|
|
722
|
+
});
|
|
723
|
+
it('should add a handler per newly added list item for viewProgress trigger but not add same interaction twice', () => {
|
|
724
|
+
const {
|
|
725
|
+
getWebAnimation
|
|
726
|
+
} = require('@wix/motion');
|
|
727
|
+
element = document.createElement('wix-interact-element');
|
|
728
|
+
const div = document.createElement('div');
|
|
729
|
+
const targetElement = document.createElement('wix-interact-element');
|
|
730
|
+
const divTarget = document.createElement('div');
|
|
731
|
+
const ul = document.createElement('ul');
|
|
732
|
+
ul.id = 'logo-scroll-list';
|
|
733
|
+
divTarget.append(ul);
|
|
734
|
+
const li = document.createElement('li');
|
|
735
|
+
const li2 = li.cloneNode(true);
|
|
736
|
+
ul.append(li);
|
|
737
|
+
ul.append(li2);
|
|
738
|
+
element.append(div);
|
|
739
|
+
targetElement.append(divTarget);
|
|
740
|
+
add(element, 'logo-scroll-container');
|
|
741
|
+
expect(getWebAnimation).toHaveBeenCalledTimes(0);
|
|
742
|
+
add(targetElement, 'logo-scroll-items');
|
|
743
|
+
expect(getWebAnimation).toHaveBeenCalledTimes(2);
|
|
744
|
+
expect(getWebAnimation).toHaveBeenCalledWith(li, expect.objectContaining(effectToAnimationOptions(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
|
|
745
|
+
trigger: 'view-progress'
|
|
746
|
+
}));
|
|
747
|
+
expect(getWebAnimation).toHaveBeenCalledWith(li2, expect.objectContaining(effectToAnimationOptions(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
|
|
748
|
+
trigger: 'view-progress'
|
|
749
|
+
}));
|
|
750
|
+
const li3 = document.createElement('li');
|
|
751
|
+
ul.append(li3);
|
|
752
|
+
addListItems(targetElement, 'logo-scroll-items', '#logo-scroll-list', [li3]);
|
|
753
|
+
expect(getWebAnimation).toHaveBeenCalledTimes(3);
|
|
754
|
+
expect(getWebAnimation).toHaveBeenCalledWith(li3, expect.objectContaining(effectToAnimationOptions(mockConfig.effects['logo-fade-scroll'])), expect.objectContaining({
|
|
755
|
+
trigger: 'view-progress'
|
|
756
|
+
}));
|
|
757
|
+
});
|
|
758
|
+
});
|
|
603
759
|
});
|
|
604
760
|
describe('remove interaction', () => {
|
|
605
761
|
beforeEach(() => {
|
|
@@ -610,8 +766,8 @@ describe('interact', () => {
|
|
|
610
766
|
const div = document.createElement('div');
|
|
611
767
|
element.append(div);
|
|
612
768
|
const removeEventListenerSpy = jest.spyOn(div, 'removeEventListener');
|
|
613
|
-
add(element, '
|
|
614
|
-
remove('
|
|
769
|
+
add(element, 'logo-click');
|
|
770
|
+
remove('logo-click');
|
|
615
771
|
expect(removeEventListenerSpy).toHaveBeenCalledTimes(2);
|
|
616
772
|
expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function));
|
|
617
773
|
});
|
|
@@ -630,8 +786,8 @@ describe('interact', () => {
|
|
|
630
786
|
element = document.createElement('wix-interact-element');
|
|
631
787
|
const div = document.createElement('div');
|
|
632
788
|
element.append(div);
|
|
633
|
-
add(element, '
|
|
634
|
-
remove('
|
|
789
|
+
add(element, 'logo-mouse');
|
|
790
|
+
remove('logo-mouse');
|
|
635
791
|
expect(pointerInstance.destroy).toHaveBeenCalledTimes(1);
|
|
636
792
|
});
|
|
637
793
|
});
|
|
@@ -650,8 +806,8 @@ describe('interact', () => {
|
|
|
650
806
|
const targetDiv = document.createElement('div');
|
|
651
807
|
targetElement.append(targetDiv);
|
|
652
808
|
const addEventListenerSpy = jest.spyOn(sourceDiv, 'addEventListener');
|
|
653
|
-
add(sourceElement, '
|
|
654
|
-
add(targetElement, '
|
|
809
|
+
add(sourceElement, 'cascade-source');
|
|
810
|
+
add(targetElement, 'cascade-target');
|
|
655
811
|
expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
|
|
656
812
|
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
657
813
|
passive: true
|
|
@@ -681,8 +837,8 @@ describe('interact', () => {
|
|
|
681
837
|
const targetElement = document.createElement('wix-interact-element');
|
|
682
838
|
const targetDiv = document.createElement('div');
|
|
683
839
|
targetElement.append(targetDiv);
|
|
684
|
-
add(sourceElement, '
|
|
685
|
-
add(targetElement, '
|
|
840
|
+
add(sourceElement, 'cascade-source');
|
|
841
|
+
add(targetElement, 'cascade-target');
|
|
686
842
|
|
|
687
843
|
// Should create animation with default effect
|
|
688
844
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
@@ -707,8 +863,8 @@ describe('interact', () => {
|
|
|
707
863
|
const targetElement = document.createElement('wix-interact-element');
|
|
708
864
|
const targetDiv = document.createElement('div');
|
|
709
865
|
targetElement.append(targetDiv);
|
|
710
|
-
add(sourceElement, '
|
|
711
|
-
add(targetElement, '
|
|
866
|
+
add(sourceElement, 'cascade-source');
|
|
867
|
+
add(targetElement, 'cascade-target');
|
|
712
868
|
|
|
713
869
|
// Should create animation with mobile effect
|
|
714
870
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
@@ -737,9 +893,9 @@ describe('interact', () => {
|
|
|
737
893
|
targetElement.append(targetDiv);
|
|
738
894
|
|
|
739
895
|
// Add source first
|
|
740
|
-
add(sourceElement, '
|
|
896
|
+
add(sourceElement, 'cascade-source');
|
|
741
897
|
// Add target second
|
|
742
|
-
add(targetElement, '
|
|
898
|
+
add(targetElement, 'cascade-target');
|
|
743
899
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
744
900
|
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
745
901
|
namedEffect: expect.objectContaining({
|
|
@@ -763,9 +919,9 @@ describe('interact', () => {
|
|
|
763
919
|
targetElement.append(targetDiv);
|
|
764
920
|
|
|
765
921
|
// Add target first
|
|
766
|
-
add(targetElement, '
|
|
922
|
+
add(targetElement, 'cascade-target');
|
|
767
923
|
// Add source second
|
|
768
|
-
add(sourceElement, '
|
|
924
|
+
add(sourceElement, 'cascade-source');
|
|
769
925
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
770
926
|
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
771
927
|
namedEffect: expect.objectContaining({
|
|
@@ -794,13 +950,13 @@ describe('interact', () => {
|
|
|
794
950
|
},
|
|
795
951
|
interactions: [{
|
|
796
952
|
trigger: 'click',
|
|
797
|
-
|
|
953
|
+
key: 'multi-source-1',
|
|
798
954
|
effects: [{
|
|
799
|
-
|
|
955
|
+
key: 'cascade-target-1',
|
|
800
956
|
effectId: 'desktop-effect',
|
|
801
957
|
conditions: ['desktop']
|
|
802
958
|
}, {
|
|
803
|
-
|
|
959
|
+
key: 'cascade-target-2',
|
|
804
960
|
effectId: 'mobile-effect',
|
|
805
961
|
conditions: ['mobile']
|
|
806
962
|
}]
|
|
@@ -835,9 +991,9 @@ describe('interact', () => {
|
|
|
835
991
|
const target2Element = document.createElement('wix-interact-element');
|
|
836
992
|
const target2Div = document.createElement('div');
|
|
837
993
|
target2Element.append(target2Div);
|
|
838
|
-
add(sourceElement, '
|
|
839
|
-
add(target1Element, '
|
|
840
|
-
add(target2Element, '
|
|
994
|
+
add(sourceElement, 'multi-source-1');
|
|
995
|
+
add(target1Element, 'cascade-target-1');
|
|
996
|
+
add(target2Element, 'cascade-target-2');
|
|
841
997
|
|
|
842
998
|
// Only desktop effect should be applied (mobile condition doesn't match)
|
|
843
999
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
@@ -875,12 +1031,12 @@ describe('interact', () => {
|
|
|
875
1031
|
},
|
|
876
1032
|
interactions: [{
|
|
877
1033
|
trigger: 'click',
|
|
878
|
-
|
|
1034
|
+
key: 'cascade-source',
|
|
879
1035
|
effects: [{
|
|
880
|
-
|
|
1036
|
+
key: 'cascade-target',
|
|
881
1037
|
effectId: 'premium-effect'
|
|
882
1038
|
}, {
|
|
883
|
-
|
|
1039
|
+
key: 'cascade-target',
|
|
884
1040
|
effectId: 'premium-effect',
|
|
885
1041
|
conditions: ['desktop', 'high-res']
|
|
886
1042
|
}]
|
|
@@ -906,8 +1062,8 @@ describe('interact', () => {
|
|
|
906
1062
|
const targetElement = document.createElement('wix-interact-element');
|
|
907
1063
|
const targetDiv = document.createElement('div');
|
|
908
1064
|
targetElement.append(targetDiv);
|
|
909
|
-
add(sourceElement, '
|
|
910
|
-
add(targetElement, '
|
|
1065
|
+
add(sourceElement, 'cascade-source');
|
|
1066
|
+
add(targetElement, 'cascade-target');
|
|
911
1067
|
|
|
912
1068
|
// Premium effect should be applied since both conditions match
|
|
913
1069
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
@@ -934,12 +1090,12 @@ describe('interact', () => {
|
|
|
934
1090
|
},
|
|
935
1091
|
interactions: [{
|
|
936
1092
|
trigger: 'click',
|
|
937
|
-
|
|
1093
|
+
key: 'cascade-source',
|
|
938
1094
|
effects: [{
|
|
939
|
-
|
|
1095
|
+
key: 'cascade-target',
|
|
940
1096
|
effectId: 'default-effect'
|
|
941
1097
|
}, {
|
|
942
|
-
|
|
1098
|
+
key: 'cascade-target',
|
|
943
1099
|
effectId: 'default-effect',
|
|
944
1100
|
conditions: ['nonexistent-condition']
|
|
945
1101
|
}]
|
|
@@ -962,8 +1118,8 @@ describe('interact', () => {
|
|
|
962
1118
|
const targetElement = document.createElement('wix-interact-element');
|
|
963
1119
|
const targetDiv = document.createElement('div');
|
|
964
1120
|
targetElement.append(targetDiv);
|
|
965
|
-
add(sourceElement, '
|
|
966
|
-
add(targetElement, '
|
|
1121
|
+
add(sourceElement, 'cascade-source');
|
|
1122
|
+
add(targetElement, 'cascade-target');
|
|
967
1123
|
|
|
968
1124
|
// Should fall back to default effect since condition doesn't exist
|
|
969
1125
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
@@ -983,9 +1139,9 @@ describe('interact', () => {
|
|
|
983
1139
|
conditions: {},
|
|
984
1140
|
interactions: [{
|
|
985
1141
|
trigger: 'click',
|
|
986
|
-
|
|
1142
|
+
key: 'cascade-source',
|
|
987
1143
|
effects: [{
|
|
988
|
-
|
|
1144
|
+
key: 'cascade-target',
|
|
989
1145
|
effectId: 'always-applied-effect',
|
|
990
1146
|
conditions: []
|
|
991
1147
|
}]
|
|
@@ -1009,8 +1165,8 @@ describe('interact', () => {
|
|
|
1009
1165
|
const targetElement = document.createElement('wix-interact-element');
|
|
1010
1166
|
const targetDiv = document.createElement('div');
|
|
1011
1167
|
targetElement.append(targetDiv);
|
|
1012
|
-
add(sourceElement, '
|
|
1013
|
-
add(targetElement, '
|
|
1168
|
+
add(sourceElement, 'cascade-source');
|
|
1169
|
+
add(targetElement, 'cascade-target');
|
|
1014
1170
|
|
|
1015
1171
|
// Effect should be applied since empty conditions array should always match
|
|
1016
1172
|
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
@@ -1024,5 +1180,501 @@ describe('interact', () => {
|
|
|
1024
1180
|
});
|
|
1025
1181
|
});
|
|
1026
1182
|
});
|
|
1183
|
+
describe('selector functionality', () => {
|
|
1184
|
+
let sourceElement;
|
|
1185
|
+
let targetElement;
|
|
1186
|
+
beforeEach(() => {
|
|
1187
|
+
// Create source element with multiple child elements
|
|
1188
|
+
sourceElement = document.createElement('wix-interact-element');
|
|
1189
|
+
sourceElement.innerHTML = `
|
|
1190
|
+
<div class="first-child">First Child</div>
|
|
1191
|
+
<button class="trigger-button">Click Me</button>
|
|
1192
|
+
<div class="other-element">Other</div>
|
|
1193
|
+
<div class="list-container">
|
|
1194
|
+
<div class="list-item">Item 1</div>
|
|
1195
|
+
<div class="list-item">Item 2</div>
|
|
1196
|
+
<div class="list-item">Item 3</div>
|
|
1197
|
+
</div>
|
|
1198
|
+
`;
|
|
1199
|
+
|
|
1200
|
+
// Create target element with multiple child elements
|
|
1201
|
+
targetElement = document.createElement('wix-interact-element');
|
|
1202
|
+
targetElement.innerHTML = `
|
|
1203
|
+
<div class="first-child">Target First</div>
|
|
1204
|
+
<div class="animation-target">Animation Target</div>
|
|
1205
|
+
<div class="overlay">Overlay</div>
|
|
1206
|
+
<div class="nested">
|
|
1207
|
+
<span class="deep-target">Deep Target</span>
|
|
1208
|
+
</div>
|
|
1209
|
+
`;
|
|
1210
|
+
});
|
|
1211
|
+
describe('basic selector functionality', () => {
|
|
1212
|
+
it('should use selector instead of firstElementChild for source', () => {
|
|
1213
|
+
const config = {
|
|
1214
|
+
effects: {
|
|
1215
|
+
'test-effect': {
|
|
1216
|
+
keyframeEffect: {
|
|
1217
|
+
name: 'test',
|
|
1218
|
+
keyframes: [{
|
|
1219
|
+
opacity: '0'
|
|
1220
|
+
}, {
|
|
1221
|
+
opacity: '1'
|
|
1222
|
+
}]
|
|
1223
|
+
},
|
|
1224
|
+
duration: 300
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1227
|
+
interactions: [{
|
|
1228
|
+
key: 'selector-source',
|
|
1229
|
+
selector: '.trigger-button',
|
|
1230
|
+
trigger: 'click',
|
|
1231
|
+
effects: [{
|
|
1232
|
+
key: 'selector-target',
|
|
1233
|
+
effectId: 'test-effect'
|
|
1234
|
+
}]
|
|
1235
|
+
}]
|
|
1236
|
+
};
|
|
1237
|
+
Interact.create(config);
|
|
1238
|
+
const triggerButton = sourceElement.querySelector('.trigger-button');
|
|
1239
|
+
const firstChild = sourceElement.querySelector('.first-child');
|
|
1240
|
+
const triggerSpy = jest.spyOn(triggerButton, 'addEventListener');
|
|
1241
|
+
const firstChildSpy = jest.spyOn(firstChild, 'addEventListener');
|
|
1242
|
+
add(sourceElement, 'selector-source');
|
|
1243
|
+
add(targetElement, 'selector-target');
|
|
1244
|
+
|
|
1245
|
+
// Should add event listener to the selected element, not firstElementChild
|
|
1246
|
+
expect(triggerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1247
|
+
expect(firstChildSpy).not.toHaveBeenCalled();
|
|
1248
|
+
});
|
|
1249
|
+
it('should use selector instead of firstElementChild for target', () => {
|
|
1250
|
+
const {
|
|
1251
|
+
getWebAnimation
|
|
1252
|
+
} = require('@wix/motion');
|
|
1253
|
+
const config = {
|
|
1254
|
+
effects: {
|
|
1255
|
+
'test-effect': {
|
|
1256
|
+
keyframeEffect: {
|
|
1257
|
+
name: 'test',
|
|
1258
|
+
keyframes: [{
|
|
1259
|
+
opacity: '0'
|
|
1260
|
+
}, {
|
|
1261
|
+
opacity: '1'
|
|
1262
|
+
}]
|
|
1263
|
+
},
|
|
1264
|
+
duration: 300
|
|
1265
|
+
}
|
|
1266
|
+
},
|
|
1267
|
+
interactions: [{
|
|
1268
|
+
key: 'selector-source',
|
|
1269
|
+
trigger: 'click',
|
|
1270
|
+
effects: [{
|
|
1271
|
+
key: 'selector-target',
|
|
1272
|
+
selector: '.animation-target',
|
|
1273
|
+
effectId: 'test-effect'
|
|
1274
|
+
}]
|
|
1275
|
+
}]
|
|
1276
|
+
};
|
|
1277
|
+
Interact.create(config);
|
|
1278
|
+
add(sourceElement, 'selector-source');
|
|
1279
|
+
add(targetElement, 'selector-target');
|
|
1280
|
+
const animationTarget = targetElement.querySelector('.animation-target');
|
|
1281
|
+
|
|
1282
|
+
// Should create animation on the selected element, not firstElementChild
|
|
1283
|
+
expect(getWebAnimation).toHaveBeenCalledWith(animationTarget, expect.any(Object), undefined, {
|
|
1284
|
+
reducedMotion: false
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
it('should fall back to firstElementChild when no selector is provided', () => {
|
|
1288
|
+
const config = {
|
|
1289
|
+
effects: {
|
|
1290
|
+
'test-effect': {
|
|
1291
|
+
keyframeEffect: {
|
|
1292
|
+
name: 'test',
|
|
1293
|
+
keyframes: [{
|
|
1294
|
+
opacity: '0'
|
|
1295
|
+
}, {
|
|
1296
|
+
opacity: '1'
|
|
1297
|
+
}]
|
|
1298
|
+
},
|
|
1299
|
+
duration: 300
|
|
1300
|
+
}
|
|
1301
|
+
},
|
|
1302
|
+
interactions: [{
|
|
1303
|
+
key: 'fallback-source',
|
|
1304
|
+
trigger: 'click',
|
|
1305
|
+
effects: [{
|
|
1306
|
+
key: 'fallback-target',
|
|
1307
|
+
effectId: 'test-effect'
|
|
1308
|
+
}]
|
|
1309
|
+
}]
|
|
1310
|
+
};
|
|
1311
|
+
Interact.create(config);
|
|
1312
|
+
const firstChild = sourceElement.querySelector('.first-child');
|
|
1313
|
+
const firstChildSpy = jest.spyOn(firstChild, 'addEventListener');
|
|
1314
|
+
add(sourceElement, 'fallback-source');
|
|
1315
|
+
add(targetElement, 'fallback-target');
|
|
1316
|
+
|
|
1317
|
+
// Should fall back to firstElementChild
|
|
1318
|
+
expect(firstChildSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1319
|
+
});
|
|
1320
|
+
});
|
|
1321
|
+
describe('selector with listContainer', () => {
|
|
1322
|
+
it('should use selector within listContainer items', () => {
|
|
1323
|
+
const config = {
|
|
1324
|
+
effects: {
|
|
1325
|
+
'list-effect': {
|
|
1326
|
+
keyframeEffect: {
|
|
1327
|
+
name: 'list-test',
|
|
1328
|
+
keyframes: [{
|
|
1329
|
+
transform: 'scale(1)'
|
|
1330
|
+
}, {
|
|
1331
|
+
transform: 'scale(1.1)'
|
|
1332
|
+
}]
|
|
1333
|
+
},
|
|
1334
|
+
duration: 200
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
interactions: [{
|
|
1338
|
+
key: 'list-source',
|
|
1339
|
+
listContainer: '.list-container',
|
|
1340
|
+
selector: '.list-item',
|
|
1341
|
+
trigger: 'hover',
|
|
1342
|
+
effects: [{
|
|
1343
|
+
listContainer: '.list-container',
|
|
1344
|
+
selector: '.list-item',
|
|
1345
|
+
effectId: 'list-effect'
|
|
1346
|
+
}]
|
|
1347
|
+
}]
|
|
1348
|
+
};
|
|
1349
|
+
Interact.create(config);
|
|
1350
|
+
|
|
1351
|
+
// Set up spies before adding interactions
|
|
1352
|
+
const listItems = Array.from(sourceElement.querySelectorAll('.list-item'));
|
|
1353
|
+
const spies = listItems.map(item => jest.spyOn(item, 'addEventListener'));
|
|
1354
|
+
add(sourceElement, 'list-source');
|
|
1355
|
+
|
|
1356
|
+
// Should add event listeners to each list item
|
|
1357
|
+
spies.forEach(spy => {
|
|
1358
|
+
expect(spy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.any(Object));
|
|
1359
|
+
});
|
|
1360
|
+
});
|
|
1361
|
+
it('should handle listContainer without selector (all children)', () => {
|
|
1362
|
+
var _sourceElement$queryS;
|
|
1363
|
+
const config = {
|
|
1364
|
+
effects: {
|
|
1365
|
+
'container-effect': {
|
|
1366
|
+
keyframeEffect: {
|
|
1367
|
+
name: 'container-test',
|
|
1368
|
+
keyframes: [{
|
|
1369
|
+
opacity: '0.5'
|
|
1370
|
+
}, {
|
|
1371
|
+
opacity: '1'
|
|
1372
|
+
}]
|
|
1373
|
+
},
|
|
1374
|
+
duration: 150
|
|
1375
|
+
}
|
|
1376
|
+
},
|
|
1377
|
+
interactions: [{
|
|
1378
|
+
key: 'container-source',
|
|
1379
|
+
listContainer: '.list-container',
|
|
1380
|
+
trigger: 'click',
|
|
1381
|
+
effects: [{
|
|
1382
|
+
listContainer: '.list-container',
|
|
1383
|
+
effectId: 'container-effect'
|
|
1384
|
+
}]
|
|
1385
|
+
}]
|
|
1386
|
+
};
|
|
1387
|
+
Interact.create(config);
|
|
1388
|
+
|
|
1389
|
+
// Set up spies before adding interactions
|
|
1390
|
+
const containerChildren = Array.from(((_sourceElement$queryS = sourceElement.querySelector('.list-container')) == null ? void 0 : _sourceElement$queryS.children) || []);
|
|
1391
|
+
const spies = containerChildren.map(child => jest.spyOn(child, 'addEventListener'));
|
|
1392
|
+
add(sourceElement, 'container-source');
|
|
1393
|
+
|
|
1394
|
+
// Should add event listeners to all children of the container
|
|
1395
|
+
spies.forEach(spy => {
|
|
1396
|
+
expect(spy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1397
|
+
});
|
|
1398
|
+
});
|
|
1399
|
+
});
|
|
1400
|
+
describe('selector error handling', () => {
|
|
1401
|
+
let consoleSpy;
|
|
1402
|
+
beforeEach(() => {
|
|
1403
|
+
consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
1404
|
+
});
|
|
1405
|
+
afterEach(() => {
|
|
1406
|
+
consoleSpy.mockRestore();
|
|
1407
|
+
});
|
|
1408
|
+
it('should warn when selector does not match any elements', () => {
|
|
1409
|
+
const config = {
|
|
1410
|
+
effects: {
|
|
1411
|
+
'test-effect': {
|
|
1412
|
+
keyframeEffect: {
|
|
1413
|
+
name: 'test',
|
|
1414
|
+
keyframes: [{
|
|
1415
|
+
opacity: '0'
|
|
1416
|
+
}, {
|
|
1417
|
+
opacity: '1'
|
|
1418
|
+
}]
|
|
1419
|
+
},
|
|
1420
|
+
duration: 300
|
|
1421
|
+
}
|
|
1422
|
+
},
|
|
1423
|
+
interactions: [{
|
|
1424
|
+
key: 'invalid-source',
|
|
1425
|
+
selector: '.non-existent-element',
|
|
1426
|
+
trigger: 'click',
|
|
1427
|
+
effects: [{
|
|
1428
|
+
key: 'invalid-target',
|
|
1429
|
+
effectId: 'test-effect'
|
|
1430
|
+
}]
|
|
1431
|
+
}]
|
|
1432
|
+
};
|
|
1433
|
+
Interact.create(config);
|
|
1434
|
+
add(sourceElement, 'invalid-source');
|
|
1435
|
+
add(targetElement, 'invalid-target');
|
|
1436
|
+
expect(consoleSpy).toHaveBeenCalledWith('WixInteract: No element found for selector ".non-existent-element"');
|
|
1437
|
+
});
|
|
1438
|
+
it('should warn when listContainer selector does not match', () => {
|
|
1439
|
+
const config = {
|
|
1440
|
+
effects: {
|
|
1441
|
+
'test-effect': {
|
|
1442
|
+
keyframeEffect: {
|
|
1443
|
+
name: 'test',
|
|
1444
|
+
keyframes: [{
|
|
1445
|
+
opacity: '0'
|
|
1446
|
+
}, {
|
|
1447
|
+
opacity: '1'
|
|
1448
|
+
}]
|
|
1449
|
+
},
|
|
1450
|
+
duration: 300
|
|
1451
|
+
}
|
|
1452
|
+
},
|
|
1453
|
+
interactions: [{
|
|
1454
|
+
key: 'invalid-container-source',
|
|
1455
|
+
listContainer: '.non-existent-container',
|
|
1456
|
+
trigger: 'click',
|
|
1457
|
+
effects: [{
|
|
1458
|
+
key: 'invalid-container-target',
|
|
1459
|
+
effectId: 'test-effect'
|
|
1460
|
+
}]
|
|
1461
|
+
}]
|
|
1462
|
+
};
|
|
1463
|
+
Interact.create(config);
|
|
1464
|
+
add(sourceElement, 'invalid-container-source');
|
|
1465
|
+
add(targetElement, 'invalid-container-target');
|
|
1466
|
+
expect(consoleSpy).toHaveBeenCalledWith('WixInteract: No container found for list container ".non-existent-container"');
|
|
1467
|
+
});
|
|
1468
|
+
it('should gracefully handle invalid selectors without breaking interactions', () => {
|
|
1469
|
+
const config = {
|
|
1470
|
+
effects: {
|
|
1471
|
+
'valid-effect': {
|
|
1472
|
+
keyframeEffect: {
|
|
1473
|
+
name: 'valid',
|
|
1474
|
+
keyframes: [{
|
|
1475
|
+
opacity: '0'
|
|
1476
|
+
}, {
|
|
1477
|
+
opacity: '1'
|
|
1478
|
+
}]
|
|
1479
|
+
},
|
|
1480
|
+
duration: 300
|
|
1481
|
+
}
|
|
1482
|
+
},
|
|
1483
|
+
interactions: [{
|
|
1484
|
+
key: 'mixed-source',
|
|
1485
|
+
selector: '.non-existent',
|
|
1486
|
+
trigger: 'click',
|
|
1487
|
+
effects: [{
|
|
1488
|
+
key: 'mixed-target',
|
|
1489
|
+
effectId: 'valid-effect'
|
|
1490
|
+
}]
|
|
1491
|
+
}, {
|
|
1492
|
+
key: 'valid-source',
|
|
1493
|
+
selector: '.trigger-button',
|
|
1494
|
+
trigger: 'click',
|
|
1495
|
+
effects: [{
|
|
1496
|
+
key: 'valid-target',
|
|
1497
|
+
effectId: 'valid-effect'
|
|
1498
|
+
}]
|
|
1499
|
+
}]
|
|
1500
|
+
};
|
|
1501
|
+
Interact.create(config);
|
|
1502
|
+
|
|
1503
|
+
// Set up spy before adding interactions
|
|
1504
|
+
const triggerButton = sourceElement.querySelector('.trigger-button');
|
|
1505
|
+
const spy = jest.spyOn(triggerButton, 'addEventListener');
|
|
1506
|
+
|
|
1507
|
+
// This should not throw and should allow other interactions to work
|
|
1508
|
+
expect(() => {
|
|
1509
|
+
add(sourceElement, 'mixed-source');
|
|
1510
|
+
add(sourceElement, 'valid-source');
|
|
1511
|
+
add(targetElement, 'mixed-target');
|
|
1512
|
+
add(targetElement, 'valid-target');
|
|
1513
|
+
}).not.toThrow();
|
|
1514
|
+
|
|
1515
|
+
// Valid interaction should still work
|
|
1516
|
+
expect(spy).toHaveBeenCalled();
|
|
1517
|
+
});
|
|
1518
|
+
});
|
|
1519
|
+
describe('complex selector scenarios', () => {
|
|
1520
|
+
it('should handle nested selectors', () => {
|
|
1521
|
+
const {
|
|
1522
|
+
getWebAnimation
|
|
1523
|
+
} = require('@wix/motion');
|
|
1524
|
+
const config = {
|
|
1525
|
+
effects: {
|
|
1526
|
+
'nested-effect': {
|
|
1527
|
+
keyframeEffect: {
|
|
1528
|
+
name: 'nested',
|
|
1529
|
+
keyframes: [{
|
|
1530
|
+
color: 'black'
|
|
1531
|
+
}, {
|
|
1532
|
+
color: 'blue'
|
|
1533
|
+
}]
|
|
1534
|
+
},
|
|
1535
|
+
duration: 200
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
interactions: [{
|
|
1539
|
+
key: 'nested-source',
|
|
1540
|
+
selector: '.other-element',
|
|
1541
|
+
trigger: 'click',
|
|
1542
|
+
effects: [{
|
|
1543
|
+
key: 'nested-target',
|
|
1544
|
+
selector: '.nested .deep-target',
|
|
1545
|
+
effectId: 'nested-effect'
|
|
1546
|
+
}]
|
|
1547
|
+
}]
|
|
1548
|
+
};
|
|
1549
|
+
Interact.create(config);
|
|
1550
|
+
const addEventListenerSpy = jest.spyOn(sourceElement.querySelector('.other-element'), 'addEventListener');
|
|
1551
|
+
add(sourceElement, 'nested-source');
|
|
1552
|
+
add(targetElement, 'nested-target');
|
|
1553
|
+
const deepTarget = targetElement.querySelector('.nested .deep-target');
|
|
1554
|
+
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1555
|
+
expect(getWebAnimation).toHaveBeenCalledWith(deepTarget, expect.any(Object), undefined, {
|
|
1556
|
+
reducedMotion: false
|
|
1557
|
+
});
|
|
1558
|
+
});
|
|
1559
|
+
it('should handle attribute selectors', () => {
|
|
1560
|
+
// Add data attributes to test elements
|
|
1561
|
+
const buttonWithData = sourceElement.querySelector('.trigger-button');
|
|
1562
|
+
buttonWithData.setAttribute('data-interactive', 'true');
|
|
1563
|
+
buttonWithData.setAttribute('data-category', 'primary');
|
|
1564
|
+
const config = {
|
|
1565
|
+
effects: {
|
|
1566
|
+
'attr-effect': {
|
|
1567
|
+
keyframeEffect: {
|
|
1568
|
+
name: 'attr',
|
|
1569
|
+
keyframes: [{
|
|
1570
|
+
backgroundColor: 'white'
|
|
1571
|
+
}, {
|
|
1572
|
+
backgroundColor: 'lightblue'
|
|
1573
|
+
}]
|
|
1574
|
+
},
|
|
1575
|
+
duration: 300
|
|
1576
|
+
}
|
|
1577
|
+
},
|
|
1578
|
+
interactions: [{
|
|
1579
|
+
key: 'attr-source',
|
|
1580
|
+
selector: '[data-interactive="true"][data-category="primary"]',
|
|
1581
|
+
trigger: 'click',
|
|
1582
|
+
effects: [{
|
|
1583
|
+
key: 'attr-target',
|
|
1584
|
+
selector: '[class*="animation"]',
|
|
1585
|
+
effectId: 'attr-effect'
|
|
1586
|
+
}]
|
|
1587
|
+
}]
|
|
1588
|
+
};
|
|
1589
|
+
Interact.create(config);
|
|
1590
|
+
|
|
1591
|
+
// Set up spy before adding interactions
|
|
1592
|
+
const spy = jest.spyOn(buttonWithData, 'addEventListener');
|
|
1593
|
+
add(sourceElement, 'attr-source');
|
|
1594
|
+
add(targetElement, 'attr-target');
|
|
1595
|
+
expect(spy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1596
|
+
});
|
|
1597
|
+
});
|
|
1598
|
+
describe('selector inheritance and priority', () => {
|
|
1599
|
+
it('should not inherit selector from interaction to effect', () => {
|
|
1600
|
+
const {
|
|
1601
|
+
getWebAnimation
|
|
1602
|
+
} = require('@wix/motion');
|
|
1603
|
+
const config = {
|
|
1604
|
+
effects: {
|
|
1605
|
+
'inherit-effect': {
|
|
1606
|
+
keyframeEffect: {
|
|
1607
|
+
name: 'inherit',
|
|
1608
|
+
keyframes: [{
|
|
1609
|
+
opacity: '0'
|
|
1610
|
+
}, {
|
|
1611
|
+
opacity: '1'
|
|
1612
|
+
}]
|
|
1613
|
+
},
|
|
1614
|
+
duration: 300
|
|
1615
|
+
}
|
|
1616
|
+
},
|
|
1617
|
+
interactions: [{
|
|
1618
|
+
key: 'inherit-source',
|
|
1619
|
+
selector: '.trigger-button',
|
|
1620
|
+
// Interaction has selector
|
|
1621
|
+
trigger: 'click',
|
|
1622
|
+
effects: [{
|
|
1623
|
+
key: 'inherit-target',
|
|
1624
|
+
// Effect has no selector - should use firstElementChild, not inherit
|
|
1625
|
+
effectId: 'inherit-effect'
|
|
1626
|
+
}]
|
|
1627
|
+
}]
|
|
1628
|
+
};
|
|
1629
|
+
Interact.create(config);
|
|
1630
|
+
add(sourceElement, 'inherit-source');
|
|
1631
|
+
add(targetElement, 'inherit-target');
|
|
1632
|
+
|
|
1633
|
+
// Effect should target firstElementChild, not the interaction's selector
|
|
1634
|
+
const targetFirstChild = targetElement.firstElementChild;
|
|
1635
|
+
expect(getWebAnimation).toHaveBeenCalledWith(targetFirstChild, expect.any(Object), undefined, {
|
|
1636
|
+
reducedMotion: false
|
|
1637
|
+
});
|
|
1638
|
+
});
|
|
1639
|
+
});
|
|
1640
|
+
describe('selector cleanup', () => {
|
|
1641
|
+
it('should clean up selector-based interactions on remove', () => {
|
|
1642
|
+
const config = {
|
|
1643
|
+
effects: {
|
|
1644
|
+
'cleanup-effect': {
|
|
1645
|
+
keyframeEffect: {
|
|
1646
|
+
name: 'cleanup',
|
|
1647
|
+
keyframes: [{
|
|
1648
|
+
opacity: '0'
|
|
1649
|
+
}, {
|
|
1650
|
+
opacity: '1'
|
|
1651
|
+
}]
|
|
1652
|
+
},
|
|
1653
|
+
duration: 300
|
|
1654
|
+
}
|
|
1655
|
+
},
|
|
1656
|
+
interactions: [{
|
|
1657
|
+
key: 'cleanup-source',
|
|
1658
|
+
selector: '.trigger-button',
|
|
1659
|
+
trigger: 'click',
|
|
1660
|
+
effects: [{
|
|
1661
|
+
key: 'cleanup-target',
|
|
1662
|
+
selector: '.animation-target',
|
|
1663
|
+
effectId: 'cleanup-effect'
|
|
1664
|
+
}]
|
|
1665
|
+
}]
|
|
1666
|
+
};
|
|
1667
|
+
Interact.create(config);
|
|
1668
|
+
const triggerButton = sourceElement.querySelector('.trigger-button');
|
|
1669
|
+
const removeEventListenerSpy = jest.spyOn(triggerButton, 'removeEventListener');
|
|
1670
|
+
add(sourceElement, 'cleanup-source');
|
|
1671
|
+
add(targetElement, 'cleanup-target');
|
|
1672
|
+
remove('cleanup-source');
|
|
1673
|
+
|
|
1674
|
+
// Should remove event listeners from the selected element
|
|
1675
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function));
|
|
1676
|
+
});
|
|
1677
|
+
});
|
|
1678
|
+
});
|
|
1027
1679
|
});
|
|
1028
1680
|
//# sourceMappingURL=interact.spec.js.map
|