@wix/interact 1.92.0 → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +2 -23
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react.js +15 -0
- package/dist/cjs/react.js.map +1 -0
- package/dist/cjs/web.js +2 -0
- package/dist/cjs/web.js.map +1 -0
- package/dist/es/index.js +8 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/react.js +650 -0
- package/dist/es/react.js.map +1 -0
- package/dist/es/web.js +56 -0
- package/dist/es/web.js.map +1 -0
- package/dist/index-C8QxOkui.mjs +7940 -0
- package/dist/index-C8QxOkui.mjs.map +1 -0
- package/dist/index-DEPRHaUt.js +18 -0
- package/dist/index-DEPRHaUt.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types/core/Interact.d.ts +17 -7
- package/dist/types/core/Interact.d.ts.map +1 -0
- package/dist/types/core/InteractionController.d.ts +19 -0
- package/dist/types/core/InteractionController.d.ts.map +1 -0
- package/dist/types/core/add.d.ts +4 -3
- package/dist/types/core/add.d.ts.map +1 -0
- package/dist/types/core/css.d.ts +3 -0
- package/dist/types/core/css.d.ts.map +1 -0
- package/dist/types/core/remove.d.ts +3 -1
- package/dist/types/core/remove.d.ts.map +1 -0
- package/dist/types/core/utilities.d.ts +1 -0
- package/dist/types/core/utilities.d.ts.map +1 -0
- package/dist/types/dom/api.d.ts +3 -0
- package/dist/types/dom/api.d.ts.map +1 -0
- package/dist/types/handlers/animationEnd.d.ts +3 -2
- package/dist/types/handlers/animationEnd.d.ts.map +1 -0
- package/dist/types/handlers/click.d.ts +3 -2
- package/dist/types/handlers/click.d.ts.map +1 -0
- package/dist/types/handlers/hover.d.ts +3 -2
- package/dist/types/handlers/hover.d.ts.map +1 -0
- package/dist/types/handlers/index.d.ts +1 -0
- package/dist/types/handlers/index.d.ts.map +1 -0
- package/dist/types/handlers/pointerMove.d.ts +3 -2
- package/dist/types/handlers/pointerMove.d.ts.map +1 -0
- package/dist/types/handlers/utilities.d.ts +1 -0
- package/dist/types/handlers/utilities.d.ts.map +1 -0
- package/dist/types/handlers/viewEnter.d.ts +3 -2
- package/dist/types/handlers/viewEnter.d.ts.map +1 -0
- package/dist/types/handlers/viewProgress.d.ts +4 -3
- package/dist/types/handlers/viewProgress.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/react/Interaction.d.ts +10 -0
- package/dist/types/react/Interaction.d.ts.map +1 -0
- package/dist/types/react/index.d.ts +8 -0
- package/dist/types/react/index.d.ts.map +1 -0
- package/dist/types/react/interactRef.d.ts +3 -0
- package/dist/types/react/interactRef.d.ts.map +1 -0
- package/dist/types/types.d.ts +25 -10
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils.d.ts +4 -2
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/{InteractElement.d.ts → web/InteractElement.d.ts} +115 -77
- package/dist/types/web/InteractElement.d.ts.map +1 -0
- package/dist/types/web/defineInteractElement.d.ts +2 -0
- package/dist/types/web/defineInteractElement.d.ts.map +1 -0
- package/dist/types/web/index.d.ts +6 -0
- package/dist/types/web/index.d.ts.map +1 -0
- package/docs/README.md +211 -0
- package/docs/advanced/README.md +164 -0
- package/docs/api/README.md +157 -0
- package/docs/api/element-selection.md +607 -0
- package/docs/api/functions.md +638 -0
- package/docs/api/interact-class.md +663 -0
- package/docs/api/interact-element.md +565 -0
- package/docs/api/interaction-controller.md +450 -0
- package/docs/api/types.md +957 -0
- package/docs/examples/README.md +212 -0
- package/docs/examples/click-interactions.md +977 -0
- package/docs/examples/entrance-animations.md +935 -0
- package/docs/examples/hover-effects.md +930 -0
- package/docs/examples/list-patterns.md +737 -0
- package/docs/guides/README.md +49 -0
- package/docs/guides/conditions-and-media-queries.md +1068 -0
- package/docs/guides/configuration-structure.md +726 -0
- package/docs/guides/custom-elements.md +327 -0
- package/docs/guides/effects-and-animations.md +634 -0
- package/docs/guides/getting-started.md +379 -0
- package/docs/guides/lists-and-dynamic-content.md +713 -0
- package/docs/guides/state-management.md +747 -0
- package/docs/guides/understanding-triggers.md +690 -0
- package/docs/integration/README.md +264 -0
- package/docs/integration/react.md +605 -0
- package/package.json +73 -56
- package/rules/Integration.md +255 -0
- package/rules/click-rules.md +533 -0
- package/rules/full-lean.md +346 -0
- package/rules/hover-rules.md +593 -0
- package/rules/pointermove-rules.md +1341 -0
- package/rules/scroll-list-rules.md +900 -0
- package/rules/viewenter-rules.md +1015 -0
- package/rules/viewprogress-rules.md +1044 -0
- package/dist/cjs/InteractElement.js +0 -162
- package/dist/cjs/InteractElement.js.map +0 -1
- package/dist/cjs/__tests__/interact.spec.js +0 -1930
- package/dist/cjs/__tests__/interact.spec.js.map +0 -1
- package/dist/cjs/__tests__/viewEnter.spec.js +0 -207
- package/dist/cjs/__tests__/viewEnter.spec.js.map +0 -1
- package/dist/cjs/core/Interact.js +0 -257
- package/dist/cjs/core/Interact.js.map +0 -1
- package/dist/cjs/core/add.js +0 -246
- package/dist/cjs/core/add.js.map +0 -1
- package/dist/cjs/core/remove.js +0 -35
- package/dist/cjs/core/remove.js.map +0 -1
- package/dist/cjs/core/utilities.js +0 -16
- package/dist/cjs/core/utilities.js.map +0 -1
- package/dist/cjs/external-types.d.js +0 -2
- package/dist/cjs/external-types.d.js.map +0 -1
- package/dist/cjs/handlers/animationEnd.js +0 -33
- package/dist/cjs/handlers/animationEnd.js.map +0 -1
- package/dist/cjs/handlers/click.js +0 -116
- package/dist/cjs/handlers/click.js.map +0 -1
- package/dist/cjs/handlers/hover.js +0 -141
- package/dist/cjs/handlers/hover.js.map +0 -1
- package/dist/cjs/handlers/index.js +0 -32
- package/dist/cjs/handlers/index.js.map +0 -1
- package/dist/cjs/handlers/pointerMove.js +0 -49
- package/dist/cjs/handlers/pointerMove.js.map +0 -1
- package/dist/cjs/handlers/utilities.js +0 -49
- package/dist/cjs/handlers/utilities.js.map +0 -1
- package/dist/cjs/handlers/viewEnter.js +0 -127
- package/dist/cjs/handlers/viewEnter.js.map +0 -1
- package/dist/cjs/handlers/viewProgress.js +0 -65
- package/dist/cjs/handlers/viewProgress.js.map +0 -1
- package/dist/cjs/test-types.d.js +0 -2
- package/dist/cjs/test-types.d.js.map +0 -1
- package/dist/cjs/types.js +0 -2
- package/dist/cjs/types.js.map +0 -1
- package/dist/cjs/utils.js +0 -68
- package/dist/cjs/utils.js.map +0 -1
- package/dist/esm/InteractElement.js +0 -156
- package/dist/esm/InteractElement.js.map +0 -1
- package/dist/esm/__tests__/interact.spec.js +0 -1937
- package/dist/esm/__tests__/interact.spec.js.map +0 -1
- package/dist/esm/__tests__/viewEnter.spec.js +0 -210
- package/dist/esm/__tests__/viewEnter.spec.js.map +0 -1
- package/dist/esm/core/Interact.js +0 -251
- package/dist/esm/core/Interact.js.map +0 -1
- package/dist/esm/core/add.js +0 -241
- package/dist/esm/core/add.js.map +0 -1
- package/dist/esm/core/remove.js +0 -30
- package/dist/esm/core/remove.js.map +0 -1
- package/dist/esm/core/utilities.js +0 -14
- package/dist/esm/core/utilities.js.map +0 -1
- package/dist/esm/external-types.d.js +0 -2
- package/dist/esm/external-types.d.js.map +0 -1
- package/dist/esm/handlers/animationEnd.js +0 -29
- package/dist/esm/handlers/animationEnd.js.map +0 -1
- package/dist/esm/handlers/click.js +0 -116
- package/dist/esm/handlers/click.js.map +0 -1
- package/dist/esm/handlers/hover.js +0 -141
- package/dist/esm/handlers/hover.js.map +0 -1
- package/dist/esm/handlers/index.js +0 -27
- package/dist/esm/handlers/index.js.map +0 -1
- package/dist/esm/handlers/pointerMove.js +0 -48
- package/dist/esm/handlers/pointerMove.js.map +0 -1
- package/dist/esm/handlers/utilities.js +0 -43
- package/dist/esm/handlers/utilities.js.map +0 -1
- package/dist/esm/handlers/viewEnter.js +0 -129
- package/dist/esm/handlers/viewEnter.js.map +0 -1
- package/dist/esm/handlers/viewProgress.js +0 -61
- package/dist/esm/handlers/viewProgress.js.map +0 -1
- package/dist/esm/index.js +0 -5
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/test-types.d.js +0 -2
- package/dist/esm/test-types.d.js.map +0 -1
- package/dist/esm/types.js +0 -2
- package/dist/esm/types.js.map +0 -1
- package/dist/esm/utils.js +0 -63
- package/dist/esm/utils.js.map +0 -1
- package/dist/types/__tests__/interact.spec.d.ts +0 -1
- package/dist/types/__tests__/viewEnter.spec.d.ts +0 -0
|
@@ -1,1937 +0,0 @@
|
|
|
1
|
-
import { Interact } from '../core/Interact';
|
|
2
|
-
import { add, addListItems } from '../core/add';
|
|
3
|
-
import { remove } from '../core/remove';
|
|
4
|
-
import { effectToAnimationOptions } from '../handlers/utilities';
|
|
5
|
-
import TRIGGER_TO_HANDLER_MODULE_MAP from '../handlers';
|
|
6
|
-
|
|
7
|
-
// Mock @wix/motion module
|
|
8
|
-
jest.mock('@wix/motion', () => {
|
|
9
|
-
const mock = {
|
|
10
|
-
getWebAnimation: jest.fn().mockReturnValue({
|
|
11
|
-
play: jest.fn(),
|
|
12
|
-
cancel: jest.fn(),
|
|
13
|
-
onFinish: jest.fn()
|
|
14
|
-
}),
|
|
15
|
-
getScrubScene: jest.fn().mockReturnValue({}),
|
|
16
|
-
getEasing: jest.fn().mockImplementation(v => v),
|
|
17
|
-
getAnimation: jest.fn().mockImplementation((target, options, trigger, reducedMotion) => {
|
|
18
|
-
return mock.getWebAnimation(target, options, trigger, {
|
|
19
|
-
reducedMotion
|
|
20
|
-
});
|
|
21
|
-
})
|
|
22
|
-
};
|
|
23
|
-
return mock;
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// Mock kuliso module
|
|
27
|
-
jest.mock('kuliso', () => ({
|
|
28
|
-
Pointer: jest.fn().mockImplementation(() => ({
|
|
29
|
-
start: jest.fn(),
|
|
30
|
-
destroy: jest.fn()
|
|
31
|
-
}))
|
|
32
|
-
}));
|
|
33
|
-
|
|
34
|
-
// Mock fizban module
|
|
35
|
-
jest.mock('fizban', () => ({
|
|
36
|
-
Scroll: jest.fn().mockImplementation(() => ({
|
|
37
|
-
start: jest.fn(),
|
|
38
|
-
end: jest.fn()
|
|
39
|
-
}))
|
|
40
|
-
}));
|
|
41
|
-
describe('interact', () => {
|
|
42
|
-
let element;
|
|
43
|
-
let mockConfig;
|
|
44
|
-
const getMockConfig = () => ({
|
|
45
|
-
interactions: [{
|
|
46
|
-
trigger: 'viewEnter',
|
|
47
|
-
key: 'logo-entrance',
|
|
48
|
-
params: {
|
|
49
|
-
threshold: 0.2
|
|
50
|
-
},
|
|
51
|
-
effects: [{
|
|
52
|
-
key: 'logo-entrance',
|
|
53
|
-
effectId: 'logo-arc-in'
|
|
54
|
-
}, {
|
|
55
|
-
key: 'logo-click',
|
|
56
|
-
effectId: 'logo-bounce'
|
|
57
|
-
}]
|
|
58
|
-
}, {
|
|
59
|
-
trigger: 'pageVisible',
|
|
60
|
-
key: 'logo-loop',
|
|
61
|
-
effects: [{
|
|
62
|
-
key: 'logo-loop',
|
|
63
|
-
effectId: 'logo-poke'
|
|
64
|
-
}]
|
|
65
|
-
}, {
|
|
66
|
-
trigger: 'animationEnd',
|
|
67
|
-
key: 'logo-animation-end',
|
|
68
|
-
params: {
|
|
69
|
-
effectId: 'logo-arc-in'
|
|
70
|
-
},
|
|
71
|
-
effects: [{
|
|
72
|
-
key: 'logo-animation-end',
|
|
73
|
-
effectId: 'logo-poke'
|
|
74
|
-
}]
|
|
75
|
-
}, {
|
|
76
|
-
trigger: 'pointerMove',
|
|
77
|
-
key: 'logo-mouse',
|
|
78
|
-
params: {
|
|
79
|
-
hitArea: 'root'
|
|
80
|
-
},
|
|
81
|
-
effects: [{
|
|
82
|
-
key: 'logo-mouse',
|
|
83
|
-
effectId: 'logo-track-mouse'
|
|
84
|
-
}]
|
|
85
|
-
}, {
|
|
86
|
-
trigger: 'click',
|
|
87
|
-
key: 'logo-click',
|
|
88
|
-
params: {
|
|
89
|
-
type: 'alternate'
|
|
90
|
-
},
|
|
91
|
-
effects: [{
|
|
92
|
-
key: 'logo-click',
|
|
93
|
-
effectId: 'logo-bounce'
|
|
94
|
-
}]
|
|
95
|
-
}, {
|
|
96
|
-
trigger: 'click',
|
|
97
|
-
key: 'logo-click',
|
|
98
|
-
params: {
|
|
99
|
-
method: 'toggle'
|
|
100
|
-
},
|
|
101
|
-
effects: [{
|
|
102
|
-
key: 'logo-click',
|
|
103
|
-
effectId: 'logo-transition-hover'
|
|
104
|
-
}]
|
|
105
|
-
}, {
|
|
106
|
-
trigger: 'hover',
|
|
107
|
-
key: 'logo-hover',
|
|
108
|
-
params: {
|
|
109
|
-
type: 'alternate'
|
|
110
|
-
},
|
|
111
|
-
effects: [{
|
|
112
|
-
key: 'logo-hover',
|
|
113
|
-
effectId: 'logo-arc-in'
|
|
114
|
-
}, {
|
|
115
|
-
key: 'logo-hover',
|
|
116
|
-
effectId: 'logo-arc-in',
|
|
117
|
-
namedEffect: {
|
|
118
|
-
type: 'ArcIn',
|
|
119
|
-
direction: 'left',
|
|
120
|
-
power: 'hard'
|
|
121
|
-
}
|
|
122
|
-
}]
|
|
123
|
-
}, {
|
|
124
|
-
trigger: 'hover',
|
|
125
|
-
key: 'logo-hover',
|
|
126
|
-
params: {
|
|
127
|
-
method: 'toggle'
|
|
128
|
-
},
|
|
129
|
-
effects: [{
|
|
130
|
-
key: 'logo-hover',
|
|
131
|
-
effectId: 'logo-transition-hover'
|
|
132
|
-
}]
|
|
133
|
-
}, {
|
|
134
|
-
trigger: 'viewProgress',
|
|
135
|
-
key: 'logo-scroll',
|
|
136
|
-
effects: [{
|
|
137
|
-
key: 'logo-scroll',
|
|
138
|
-
effectId: 'logo-fade-scroll'
|
|
139
|
-
}]
|
|
140
|
-
}, {
|
|
141
|
-
trigger: 'click',
|
|
142
|
-
key: 'logo-click-container',
|
|
143
|
-
listContainer: '#logo-list',
|
|
144
|
-
effects: [{
|
|
145
|
-
effectId: 'logo-bounce'
|
|
146
|
-
}]
|
|
147
|
-
}, {
|
|
148
|
-
trigger: 'viewEnter',
|
|
149
|
-
key: 'logo-view-container',
|
|
150
|
-
effects: [{
|
|
151
|
-
listContainer: '#logo-list',
|
|
152
|
-
effectId: 'logo-bounce'
|
|
153
|
-
}]
|
|
154
|
-
}, {
|
|
155
|
-
trigger: 'viewProgress',
|
|
156
|
-
key: 'logo-scroll-container',
|
|
157
|
-
listContainer: '#logo-scroll-list',
|
|
158
|
-
effects: [{
|
|
159
|
-
listContainer: '#logo-scroll-list',
|
|
160
|
-
effectId: 'logo-fade-scroll'
|
|
161
|
-
}]
|
|
162
|
-
}, {
|
|
163
|
-
trigger: 'viewProgress',
|
|
164
|
-
key: 'logo-scroll-container',
|
|
165
|
-
effects: [{
|
|
166
|
-
key: 'logo-scroll-items',
|
|
167
|
-
listContainer: '#logo-scroll-list',
|
|
168
|
-
effectId: 'logo-fade-scroll'
|
|
169
|
-
}]
|
|
170
|
-
}],
|
|
171
|
-
effects: {
|
|
172
|
-
'logo-arc-in': {
|
|
173
|
-
namedEffect: {
|
|
174
|
-
type: 'ArcIn',
|
|
175
|
-
direction: 'right',
|
|
176
|
-
power: 'medium'
|
|
177
|
-
},
|
|
178
|
-
duration: 1200
|
|
179
|
-
},
|
|
180
|
-
'logo-arc-in-with-target': {
|
|
181
|
-
key: 'logo-hover',
|
|
182
|
-
namedEffect: {
|
|
183
|
-
type: 'ArcIn',
|
|
184
|
-
direction: 'right',
|
|
185
|
-
power: 'medium'
|
|
186
|
-
},
|
|
187
|
-
duration: 1200
|
|
188
|
-
},
|
|
189
|
-
'logo-track-mouse': {
|
|
190
|
-
namedEffect: {
|
|
191
|
-
type: 'TrackMouse',
|
|
192
|
-
distance: {
|
|
193
|
-
value: 20,
|
|
194
|
-
type: 'px'
|
|
195
|
-
},
|
|
196
|
-
axis: 'both',
|
|
197
|
-
power: 'medium'
|
|
198
|
-
},
|
|
199
|
-
transitionDuration: 300,
|
|
200
|
-
transitionEasing: 'easeOut',
|
|
201
|
-
centeredToTarget: true
|
|
202
|
-
},
|
|
203
|
-
'logo-bounce': {
|
|
204
|
-
namedEffect: {
|
|
205
|
-
type: 'BounceIn',
|
|
206
|
-
power: 'hard',
|
|
207
|
-
direction: 'center',
|
|
208
|
-
distanceFactor: 1.2
|
|
209
|
-
},
|
|
210
|
-
duration: 500
|
|
211
|
-
},
|
|
212
|
-
'logo-fade-scroll': {
|
|
213
|
-
namedEffect: {
|
|
214
|
-
type: 'FadeScroll',
|
|
215
|
-
range: 'in',
|
|
216
|
-
opacity: 0
|
|
217
|
-
},
|
|
218
|
-
rangeStart: {
|
|
219
|
-
name: 'contain',
|
|
220
|
-
offset: {
|
|
221
|
-
value: -10,
|
|
222
|
-
type: 'percentage'
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
rangeEnd: {
|
|
226
|
-
name: 'contain',
|
|
227
|
-
offset: {
|
|
228
|
-
value: 110,
|
|
229
|
-
type: 'percentage'
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
},
|
|
233
|
-
'logo-transition-hover': {
|
|
234
|
-
transition: {
|
|
235
|
-
duration: 300,
|
|
236
|
-
styleProperties: [{
|
|
237
|
-
name: 'opacity',
|
|
238
|
-
value: '0'
|
|
239
|
-
}]
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
'logo-poke': {
|
|
243
|
-
namedEffect: {
|
|
244
|
-
type: 'Poke',
|
|
245
|
-
direction: 'left',
|
|
246
|
-
power: 'medium'
|
|
247
|
-
},
|
|
248
|
-
duration: 500
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
beforeEach(() => {
|
|
253
|
-
element = document.createElement('interact-element');
|
|
254
|
-
const div = document.createElement('div');
|
|
255
|
-
element.append(div);
|
|
256
|
-
|
|
257
|
-
// Mock Web Animations API
|
|
258
|
-
window.KeyframeEffect = class KeyframeEffect {
|
|
259
|
-
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
260
|
-
constructor(element, keyframes, options) {
|
|
261
|
-
return {
|
|
262
|
-
element,
|
|
263
|
-
keyframes,
|
|
264
|
-
options
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
// Mock ViewTimeline
|
|
270
|
-
window.ViewTimeline = class ViewTimeline {
|
|
271
|
-
constructor(options) {
|
|
272
|
-
return {
|
|
273
|
-
...options
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
// Mock Animation
|
|
279
|
-
window.Animation = class Animation {
|
|
280
|
-
constructor(effect, timeline) {
|
|
281
|
-
return {
|
|
282
|
-
effect,
|
|
283
|
-
timeline,
|
|
284
|
-
play: jest.fn()
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
// Mock IntersectionObserver
|
|
290
|
-
window.IntersectionObserver = class IntersectionObserver {
|
|
291
|
-
constructor(callback, options) {
|
|
292
|
-
return {
|
|
293
|
-
callback,
|
|
294
|
-
options,
|
|
295
|
-
observe: jest.fn(),
|
|
296
|
-
unobserve: jest.fn()
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
// Mock CSSStyleSheet
|
|
302
|
-
window.CSSStyleSheet = class CSSStyleSheet {
|
|
303
|
-
constructor(_) {
|
|
304
|
-
return {
|
|
305
|
-
replace: jest.fn(),
|
|
306
|
-
insertRule: jest.fn()
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
// Mock adoptedStyleSheets
|
|
312
|
-
if (!document.adoptedStyleSheets) {
|
|
313
|
-
document.adoptedStyleSheets = [];
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Mock matchMedia for condition testing
|
|
317
|
-
mockMatchMedia();
|
|
318
|
-
});
|
|
319
|
-
function mockMatchMedia(matchingQueries) {
|
|
320
|
-
if (matchingQueries === void 0) {
|
|
321
|
-
matchingQueries = [];
|
|
322
|
-
}
|
|
323
|
-
const queryRule = `(${matchingQueries.join(') and (')})`;
|
|
324
|
-
const mockMQL = query => {
|
|
325
|
-
return {
|
|
326
|
-
matches: queryRule === query,
|
|
327
|
-
media: query,
|
|
328
|
-
onchange: null,
|
|
329
|
-
addEventListener: jest.fn(),
|
|
330
|
-
removeEventListener: jest.fn(),
|
|
331
|
-
dispatchEvent: jest.fn()
|
|
332
|
-
};
|
|
333
|
-
};
|
|
334
|
-
Object.defineProperty(window, 'matchMedia', {
|
|
335
|
-
writable: true,
|
|
336
|
-
value: jest.fn().mockImplementation(mockMQL)
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
function createCascadingTestConfig(conditions, matchingConditions) {
|
|
340
|
-
if (conditions === void 0) {
|
|
341
|
-
conditions = {};
|
|
342
|
-
}
|
|
343
|
-
if (matchingConditions === void 0) {
|
|
344
|
-
matchingConditions = [];
|
|
345
|
-
}
|
|
346
|
-
mockMatchMedia(matchingConditions);
|
|
347
|
-
return {
|
|
348
|
-
conditions: {
|
|
349
|
-
desktop: {
|
|
350
|
-
type: 'media',
|
|
351
|
-
predicate: 'min-width: 1024px'
|
|
352
|
-
},
|
|
353
|
-
mobile: {
|
|
354
|
-
type: 'media',
|
|
355
|
-
predicate: 'max-width: 767px'
|
|
356
|
-
},
|
|
357
|
-
tablet: {
|
|
358
|
-
type: 'media',
|
|
359
|
-
predicate: '(min-width: 768px) and (max-width: 1023px)'
|
|
360
|
-
},
|
|
361
|
-
...conditions
|
|
362
|
-
},
|
|
363
|
-
interactions: [{
|
|
364
|
-
trigger: 'click',
|
|
365
|
-
key: 'cascade-source',
|
|
366
|
-
effects: [{
|
|
367
|
-
key: 'cascade-target',
|
|
368
|
-
effectId: 'default-effect'
|
|
369
|
-
}, {
|
|
370
|
-
key: 'cascade-target',
|
|
371
|
-
effectId: 'default-effect',
|
|
372
|
-
conditions: ['desktop'],
|
|
373
|
-
namedEffect: {
|
|
374
|
-
type: 'SlideIn',
|
|
375
|
-
direction: 'right',
|
|
376
|
-
power: 'medium'
|
|
377
|
-
},
|
|
378
|
-
duration: 800
|
|
379
|
-
}, {
|
|
380
|
-
key: 'cascade-target',
|
|
381
|
-
effectId: 'default-effect',
|
|
382
|
-
conditions: ['mobile'],
|
|
383
|
-
namedEffect: {
|
|
384
|
-
type: 'BounceIn',
|
|
385
|
-
direction: 'center',
|
|
386
|
-
power: 'hard'
|
|
387
|
-
},
|
|
388
|
-
duration: 600
|
|
389
|
-
}]
|
|
390
|
-
}],
|
|
391
|
-
effects: {
|
|
392
|
-
'default-effect': {
|
|
393
|
-
namedEffect: {
|
|
394
|
-
type: 'FadeIn',
|
|
395
|
-
power: 'medium'
|
|
396
|
-
},
|
|
397
|
-
duration: 500
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
afterEach(() => {
|
|
403
|
-
jest.clearAllMocks();
|
|
404
|
-
// Clear Interact instances to ensure test isolation
|
|
405
|
-
Interact.destroy();
|
|
406
|
-
// Reset static flags to default
|
|
407
|
-
Interact.forceReducedMotion = false;
|
|
408
|
-
Interact.allowA11yTriggers = false;
|
|
409
|
-
});
|
|
410
|
-
describe('init Interact instance', () => {
|
|
411
|
-
it('should initialize with valid config', () => {
|
|
412
|
-
Interact.create({});
|
|
413
|
-
expect(customElements.get('interact-element')).toBeDefined();
|
|
414
|
-
});
|
|
415
|
-
});
|
|
416
|
-
describe('destroy Interact instance', () => {
|
|
417
|
-
it('should clear an instance entire cache', () => {
|
|
418
|
-
const instance = Interact.create(getMockConfig());
|
|
419
|
-
element = document.createElement('interact-element');
|
|
420
|
-
element.dataset.interactKey = 'logo-entrance';
|
|
421
|
-
const div = document.createElement('div');
|
|
422
|
-
element.append(div);
|
|
423
|
-
add(element, 'logo-entrance');
|
|
424
|
-
expect(Object.keys(instance.dataCache.interactions).length).toBe(11);
|
|
425
|
-
expect(instance.elements.size).toBe(1);
|
|
426
|
-
expect(Interact.instances.length).toBe(1);
|
|
427
|
-
instance.destroy();
|
|
428
|
-
expect(Object.keys(instance.dataCache.interactions).length).toBe(0);
|
|
429
|
-
expect(instance.elements.size).toBe(0);
|
|
430
|
-
expect(Interact.instances.length).toBe(0);
|
|
431
|
-
expect(Interact.elementCache.size).toBe(0);
|
|
432
|
-
});
|
|
433
|
-
});
|
|
434
|
-
describe('destroy Interact', () => {
|
|
435
|
-
it('should clear all instances', () => {
|
|
436
|
-
Interact.create(getMockConfig());
|
|
437
|
-
Interact.create(getMockConfig());
|
|
438
|
-
expect(Interact.instances.length).toBe(2);
|
|
439
|
-
Interact.destroy();
|
|
440
|
-
expect(Interact.instances.length).toBe(0);
|
|
441
|
-
});
|
|
442
|
-
it('should clear all elements from cache', () => {
|
|
443
|
-
Interact.create(getMockConfig());
|
|
444
|
-
element = document.createElement('interact-element');
|
|
445
|
-
const div = document.createElement('div');
|
|
446
|
-
element.append(div);
|
|
447
|
-
add(element, 'logo-hover');
|
|
448
|
-
expect(Interact.elementCache.size).toBeGreaterThan(0);
|
|
449
|
-
Interact.destroy();
|
|
450
|
-
expect(Interact.elementCache.size).toBe(0);
|
|
451
|
-
});
|
|
452
|
-
it('should call disconnect on all cached elements', () => {
|
|
453
|
-
Interact.create(getMockConfig());
|
|
454
|
-
const element1 = document.createElement('interact-element');
|
|
455
|
-
const div1 = document.createElement('div');
|
|
456
|
-
element1.append(div1);
|
|
457
|
-
const element2 = document.createElement('interact-element');
|
|
458
|
-
const div2 = document.createElement('div');
|
|
459
|
-
element2.append(div2);
|
|
460
|
-
add(element1, 'logo-hover');
|
|
461
|
-
add(element2, 'logo-click');
|
|
462
|
-
const disconnectSpy1 = jest.spyOn(element1, 'disconnect');
|
|
463
|
-
const disconnectSpy2 = jest.spyOn(element2, 'disconnect');
|
|
464
|
-
Interact.destroy();
|
|
465
|
-
expect(disconnectSpy1).toHaveBeenCalled();
|
|
466
|
-
expect(disconnectSpy2).toHaveBeenCalled();
|
|
467
|
-
});
|
|
468
|
-
it('should clean up interactions after destroy', () => {
|
|
469
|
-
Interact.create(getMockConfig());
|
|
470
|
-
element = document.createElement('interact-element');
|
|
471
|
-
const div = document.createElement('div');
|
|
472
|
-
element.append(div);
|
|
473
|
-
add(element, 'logo-click');
|
|
474
|
-
Interact.destroy();
|
|
475
|
-
|
|
476
|
-
// After destroy, getInstance should return undefined
|
|
477
|
-
expect(Interact.getInstance('logo-click')).toBeUndefined();
|
|
478
|
-
|
|
479
|
-
// Re-create instance and verify it works independently
|
|
480
|
-
Interact.create(getMockConfig());
|
|
481
|
-
const newElement = document.createElement('interact-element');
|
|
482
|
-
const newDiv = document.createElement('div');
|
|
483
|
-
newElement.append(newDiv);
|
|
484
|
-
const newAddEventListenerSpy = jest.spyOn(newDiv, 'addEventListener');
|
|
485
|
-
add(newElement, 'logo-click');
|
|
486
|
-
expect(newAddEventListenerSpy).toHaveBeenCalled();
|
|
487
|
-
expect(Interact.getInstance('logo-click')).toBeDefined();
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
// TODO: fix this test - when adding this test it causes 2 other tests to fail
|
|
491
|
-
// it('should remove event listeners and styles when disconnect is called', () => {
|
|
492
|
-
// Interact.create(mockConfig);
|
|
493
|
-
|
|
494
|
-
// element = document.createElement(
|
|
495
|
-
// 'interact-element',
|
|
496
|
-
// ) as IInteractElement;
|
|
497
|
-
// element.dataset.interactKey = 'logo-click';
|
|
498
|
-
// const div = document.createElement('div');
|
|
499
|
-
// element.append(div);
|
|
500
|
-
|
|
501
|
-
// add(element, 'logo-click');
|
|
502
|
-
|
|
503
|
-
// const removeEventListenerSpy = jest.spyOn(div, 'removeEventListener');
|
|
504
|
-
|
|
505
|
-
// Interact.destroy();
|
|
506
|
-
|
|
507
|
-
// expect(removeEventListenerSpy).toHaveBeenCalled();
|
|
508
|
-
// expect(removeEventListenerSpy).toHaveBeenCalledWith(
|
|
509
|
-
// 'click',
|
|
510
|
-
// expect.any(Function),
|
|
511
|
-
// );
|
|
512
|
-
// });
|
|
513
|
-
});
|
|
514
|
-
describe('reduced motion', () => {
|
|
515
|
-
it('should pass reducedMotion=true to getWebAnimation when forceReducedMotion is true', () => {
|
|
516
|
-
const {
|
|
517
|
-
getWebAnimation
|
|
518
|
-
} = require('@wix/motion');
|
|
519
|
-
Interact.forceReducedMotion = true;
|
|
520
|
-
Interact.create({
|
|
521
|
-
interactions: [{
|
|
522
|
-
trigger: 'hover',
|
|
523
|
-
key: 'logo-hover',
|
|
524
|
-
effects: [{
|
|
525
|
-
key: 'logo-hover',
|
|
526
|
-
effectId: 'logo-arc-in'
|
|
527
|
-
}]
|
|
528
|
-
}],
|
|
529
|
-
effects: {
|
|
530
|
-
'logo-arc-in': {
|
|
531
|
-
namedEffect: {
|
|
532
|
-
type: 'ArcIn',
|
|
533
|
-
direction: 'right',
|
|
534
|
-
power: 'medium'
|
|
535
|
-
},
|
|
536
|
-
duration: 1200
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
element = document.createElement('interact-element');
|
|
541
|
-
const div = document.createElement('div');
|
|
542
|
-
element.append(div);
|
|
543
|
-
add(element, 'logo-hover');
|
|
544
|
-
expect(getWebAnimation).toHaveBeenCalledWith(div, expect.any(Object), undefined, {
|
|
545
|
-
reducedMotion: true
|
|
546
|
-
});
|
|
547
|
-
Interact.forceReducedMotion = false;
|
|
548
|
-
Interact.destroy();
|
|
549
|
-
});
|
|
550
|
-
});
|
|
551
|
-
describe('add interaction', () => {
|
|
552
|
-
beforeEach(() => {
|
|
553
|
-
mockConfig = getMockConfig();
|
|
554
|
-
Interact.create(mockConfig);
|
|
555
|
-
});
|
|
556
|
-
afterEach(() => {
|
|
557
|
-
Interact.destroy();
|
|
558
|
-
jest.clearAllMocks();
|
|
559
|
-
});
|
|
560
|
-
describe('hover', () => {
|
|
561
|
-
it('should add handler for hover trigger with alternate type', () => {
|
|
562
|
-
const {
|
|
563
|
-
getWebAnimation
|
|
564
|
-
} = require('@wix/motion');
|
|
565
|
-
element = document.createElement('interact-element');
|
|
566
|
-
const div = document.createElement('div');
|
|
567
|
-
element.append(div);
|
|
568
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
569
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(0);
|
|
570
|
-
add(element, 'logo-hover');
|
|
571
|
-
expect(addEventListenerSpy).toHaveBeenCalledTimes(4);
|
|
572
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.objectContaining({
|
|
573
|
-
passive: true
|
|
574
|
-
}));
|
|
575
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('mouseleave', expect.any(Function), expect.objectContaining({
|
|
576
|
-
passive: true
|
|
577
|
-
}));
|
|
578
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
579
|
-
expect(getWebAnimation).toHaveBeenCalledWith(div, expect.objectContaining({
|
|
580
|
-
namedEffect: expect.objectContaining({
|
|
581
|
-
type: 'ArcIn',
|
|
582
|
-
direction: 'left',
|
|
583
|
-
power: 'hard'
|
|
584
|
-
})
|
|
585
|
-
}), undefined, {
|
|
586
|
-
reducedMotion: false
|
|
587
|
-
});
|
|
588
|
-
});
|
|
589
|
-
});
|
|
590
|
-
describe('click', () => {
|
|
591
|
-
it('should add handler for click trigger', () => {
|
|
592
|
-
element = document.createElement('interact-element');
|
|
593
|
-
const div = document.createElement('div');
|
|
594
|
-
element.append(div);
|
|
595
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
596
|
-
add(element, 'logo-click');
|
|
597
|
-
expect(addEventListenerSpy).toHaveBeenCalledTimes(2);
|
|
598
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
599
|
-
passive: true
|
|
600
|
-
}));
|
|
601
|
-
});
|
|
602
|
-
});
|
|
603
|
-
describe('viewEnter', () => {
|
|
604
|
-
it('should add handler for viewEnter trigger', () => {
|
|
605
|
-
const {
|
|
606
|
-
getWebAnimation
|
|
607
|
-
} = require('@wix/motion');
|
|
608
|
-
element = document.createElement('interact-element');
|
|
609
|
-
const div = document.createElement('div');
|
|
610
|
-
element.append(div);
|
|
611
|
-
add(element, 'logo-entrance');
|
|
612
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
613
|
-
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
|
|
614
|
-
reducedMotion: false
|
|
615
|
-
});
|
|
616
|
-
});
|
|
617
|
-
it('should add handler for viewEnter trigger when target is added before source', () => {
|
|
618
|
-
const {
|
|
619
|
-
getWebAnimation
|
|
620
|
-
} = require('@wix/motion');
|
|
621
|
-
element = document.createElement('interact-element');
|
|
622
|
-
const div = document.createElement('div');
|
|
623
|
-
div.id = 'logo-entrance';
|
|
624
|
-
element.dataset.interactKey = 'logo-entrance';
|
|
625
|
-
element.append(div);
|
|
626
|
-
const elementClick = document.createElement('interact-element');
|
|
627
|
-
const divClick = document.createElement('div');
|
|
628
|
-
divClick.id = 'logo-click';
|
|
629
|
-
elementClick.dataset.interactKey = 'logo-click';
|
|
630
|
-
elementClick.append(divClick);
|
|
631
|
-
add(elementClick, 'logo-click');
|
|
632
|
-
add(element, 'logo-entrance');
|
|
633
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(3);
|
|
634
|
-
expect(getWebAnimation.mock.calls[0][0]).toBe(divClick);
|
|
635
|
-
expect(getWebAnimation.mock.calls[1][0]).toBe(divClick);
|
|
636
|
-
expect(getWebAnimation.mock.calls[2][0]).toBe(div);
|
|
637
|
-
expect(getWebAnimation.mock.calls[0][3]).toMatchObject({
|
|
638
|
-
reducedMotion: false
|
|
639
|
-
});
|
|
640
|
-
expect(getWebAnimation.mock.calls[1][3]).toMatchObject({
|
|
641
|
-
reducedMotion: false
|
|
642
|
-
});
|
|
643
|
-
expect(getWebAnimation.mock.calls[2][3]).toMatchObject({
|
|
644
|
-
reducedMotion: false
|
|
645
|
-
});
|
|
646
|
-
});
|
|
647
|
-
});
|
|
648
|
-
describe('pageVisible', () => {
|
|
649
|
-
it('should add handler for pageVisible trigger', () => {
|
|
650
|
-
const {
|
|
651
|
-
getWebAnimation
|
|
652
|
-
} = require('@wix/motion');
|
|
653
|
-
element = document.createElement('interact-element');
|
|
654
|
-
const div = document.createElement('div');
|
|
655
|
-
element.append(div);
|
|
656
|
-
add(element, 'logo-loop');
|
|
657
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
658
|
-
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
|
|
659
|
-
reducedMotion: false
|
|
660
|
-
});
|
|
661
|
-
});
|
|
662
|
-
});
|
|
663
|
-
describe('animationEnd', () => {
|
|
664
|
-
it('should add handler for animationEnd trigger', () => {
|
|
665
|
-
const {
|
|
666
|
-
getWebAnimation
|
|
667
|
-
} = require('@wix/motion');
|
|
668
|
-
element = document.createElement('interact-element');
|
|
669
|
-
const div = document.createElement('div');
|
|
670
|
-
element.append(div);
|
|
671
|
-
add(element, 'logo-animation-end');
|
|
672
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
673
|
-
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.any(Object), undefined, {
|
|
674
|
-
reducedMotion: false
|
|
675
|
-
});
|
|
676
|
-
});
|
|
677
|
-
});
|
|
678
|
-
describe('pointerMove', () => {
|
|
679
|
-
it('should add handler for pointerMove trigger', () => {
|
|
680
|
-
const {
|
|
681
|
-
getScrubScene
|
|
682
|
-
} = require('@wix/motion');
|
|
683
|
-
const {
|
|
684
|
-
Pointer
|
|
685
|
-
} = require('kuliso');
|
|
686
|
-
const pointerInstance = {
|
|
687
|
-
start: jest.fn(),
|
|
688
|
-
destroy: jest.fn()
|
|
689
|
-
};
|
|
690
|
-
Pointer.mockImplementation(() => pointerInstance);
|
|
691
|
-
element = document.createElement('interact-element');
|
|
692
|
-
const div = document.createElement('div');
|
|
693
|
-
element.append(div);
|
|
694
|
-
add(element, 'logo-mouse');
|
|
695
|
-
expect(getScrubScene).toHaveBeenCalledTimes(1);
|
|
696
|
-
expect(getScrubScene).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining(effectToAnimationOptions(getMockConfig().effects['logo-track-mouse'])), expect.objectContaining({
|
|
697
|
-
trigger: 'pointer-move'
|
|
698
|
-
}));
|
|
699
|
-
expect(pointerInstance.start).toHaveBeenCalled();
|
|
700
|
-
});
|
|
701
|
-
});
|
|
702
|
-
describe('viewProgress', () => {
|
|
703
|
-
it('should add handler for viewProgress trigger with native ViewTimeline support', () => {
|
|
704
|
-
const {
|
|
705
|
-
getWebAnimation
|
|
706
|
-
} = require('@wix/motion');
|
|
707
|
-
element = document.createElement('interact-element');
|
|
708
|
-
const div = document.createElement('div');
|
|
709
|
-
element.append(div);
|
|
710
|
-
add(element, 'logo-scroll');
|
|
711
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
712
|
-
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining(effectToAnimationOptions(getMockConfig().effects['logo-fade-scroll'])), expect.objectContaining({
|
|
713
|
-
trigger: 'view-progress'
|
|
714
|
-
}));
|
|
715
|
-
});
|
|
716
|
-
it('should add handler for viewProgress trigger with fizban polyfill', () => {
|
|
717
|
-
// Remove ViewTimeline support
|
|
718
|
-
delete window.ViewTimeline;
|
|
719
|
-
const {
|
|
720
|
-
getScrubScene
|
|
721
|
-
} = require('@wix/motion');
|
|
722
|
-
const {
|
|
723
|
-
Scroll
|
|
724
|
-
} = require('fizban');
|
|
725
|
-
const scrollInstance = {
|
|
726
|
-
start: jest.fn(),
|
|
727
|
-
destroy: jest.fn()
|
|
728
|
-
};
|
|
729
|
-
Scroll.mockImplementation(() => scrollInstance);
|
|
730
|
-
element = document.createElement('interact-element');
|
|
731
|
-
const div = document.createElement('div');
|
|
732
|
-
element.append(div);
|
|
733
|
-
add(element, 'logo-scroll');
|
|
734
|
-
expect(getScrubScene).toHaveBeenCalledTimes(1);
|
|
735
|
-
expect(getScrubScene).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining(effectToAnimationOptions(getMockConfig().effects['logo-fade-scroll'])), expect.objectContaining({
|
|
736
|
-
trigger: 'view-progress'
|
|
737
|
-
}));
|
|
738
|
-
setTimeout(() => {
|
|
739
|
-
expect(scrollInstance.start).toHaveBeenCalled();
|
|
740
|
-
}, 0);
|
|
741
|
-
});
|
|
742
|
-
});
|
|
743
|
-
describe('listContainer', () => {
|
|
744
|
-
it('should add a handler per list item for click trigger with listContainer', () => {
|
|
745
|
-
element = document.createElement('interact-element');
|
|
746
|
-
const div = document.createElement('div');
|
|
747
|
-
const ul = document.createElement('ul');
|
|
748
|
-
ul.id = 'logo-list';
|
|
749
|
-
div.append(ul);
|
|
750
|
-
const li = document.createElement('li');
|
|
751
|
-
const li2 = li.cloneNode(true);
|
|
752
|
-
ul.append(li);
|
|
753
|
-
ul.append(li2);
|
|
754
|
-
element.append(div);
|
|
755
|
-
const addEventListenerSpy = jest.spyOn(li, 'addEventListener');
|
|
756
|
-
const addEventListenerSpy2 = jest.spyOn(li2, 'addEventListener');
|
|
757
|
-
add(element, 'logo-click-container');
|
|
758
|
-
expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
|
|
759
|
-
expect(addEventListenerSpy2).toHaveBeenCalledTimes(1);
|
|
760
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
761
|
-
passive: true
|
|
762
|
-
}));
|
|
763
|
-
expect(addEventListenerSpy2).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
764
|
-
passive: true
|
|
765
|
-
}));
|
|
766
|
-
});
|
|
767
|
-
it('should add a handler per list item for viewEnter trigger with listContainer in effect', () => {
|
|
768
|
-
const {
|
|
769
|
-
getWebAnimation
|
|
770
|
-
} = require('@wix/motion');
|
|
771
|
-
element = document.createElement('interact-element');
|
|
772
|
-
const div = document.createElement('div');
|
|
773
|
-
const ul = document.createElement('ul');
|
|
774
|
-
ul.id = 'logo-list';
|
|
775
|
-
div.append(ul);
|
|
776
|
-
const li = document.createElement('li');
|
|
777
|
-
const li2 = li.cloneNode(true);
|
|
778
|
-
ul.append(li);
|
|
779
|
-
ul.append(li2);
|
|
780
|
-
element.append(div);
|
|
781
|
-
add(element, 'logo-view-container');
|
|
782
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(2);
|
|
783
|
-
expect(getWebAnimation.mock.calls[0][0]).toBe(li);
|
|
784
|
-
expect(getWebAnimation.mock.calls[1][0]).toBe(li2);
|
|
785
|
-
});
|
|
786
|
-
it('should add a handler per newly added list item for click trigger with listContainer', () => {
|
|
787
|
-
element = document.createElement('interact-element');
|
|
788
|
-
const div = document.createElement('div');
|
|
789
|
-
const ul = document.createElement('ul');
|
|
790
|
-
ul.id = 'logo-list';
|
|
791
|
-
div.append(ul);
|
|
792
|
-
const li = document.createElement('li');
|
|
793
|
-
const li2 = li.cloneNode(true);
|
|
794
|
-
ul.append(li);
|
|
795
|
-
ul.append(li2);
|
|
796
|
-
element.append(div);
|
|
797
|
-
const addEventListenerSpy = jest.spyOn(li, 'addEventListener');
|
|
798
|
-
const addEventListenerSpy2 = jest.spyOn(li2, 'addEventListener');
|
|
799
|
-
add(element, 'logo-click-container');
|
|
800
|
-
expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
|
|
801
|
-
expect(addEventListenerSpy2).toHaveBeenCalledTimes(1);
|
|
802
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
803
|
-
passive: true
|
|
804
|
-
}));
|
|
805
|
-
expect(addEventListenerSpy2).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
806
|
-
passive: true
|
|
807
|
-
}));
|
|
808
|
-
const li3 = document.createElement('li');
|
|
809
|
-
ul.append(li3);
|
|
810
|
-
const addEventListenerSpy3 = jest.spyOn(li3, 'addEventListener');
|
|
811
|
-
addListItems(element, 'logo-click-container', '#logo-list', [li3]);
|
|
812
|
-
expect(addEventListenerSpy3).toHaveBeenCalledTimes(1);
|
|
813
|
-
expect(addEventListenerSpy3).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
814
|
-
passive: true
|
|
815
|
-
}));
|
|
816
|
-
});
|
|
817
|
-
it('should add a handler per newly added list item for viewProgress trigger but not add same interaction twice', () => {
|
|
818
|
-
const {
|
|
819
|
-
getWebAnimation
|
|
820
|
-
} = require('@wix/motion');
|
|
821
|
-
element = document.createElement('interact-element');
|
|
822
|
-
const div = document.createElement('div');
|
|
823
|
-
const targetElement = document.createElement('interact-element');
|
|
824
|
-
const divTarget = document.createElement('div');
|
|
825
|
-
const ul = document.createElement('ul');
|
|
826
|
-
ul.id = 'logo-scroll-list';
|
|
827
|
-
divTarget.append(ul);
|
|
828
|
-
const li = document.createElement('li');
|
|
829
|
-
const li2 = li.cloneNode(true);
|
|
830
|
-
ul.append(li);
|
|
831
|
-
ul.append(li2);
|
|
832
|
-
element.append(div);
|
|
833
|
-
targetElement.append(divTarget);
|
|
834
|
-
add(element, 'logo-scroll-container');
|
|
835
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(0);
|
|
836
|
-
add(targetElement, 'logo-scroll-items');
|
|
837
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(2);
|
|
838
|
-
expect(getWebAnimation).toHaveBeenCalledWith(li, expect.objectContaining(effectToAnimationOptions(getMockConfig().effects['logo-fade-scroll'])), expect.objectContaining({
|
|
839
|
-
trigger: 'view-progress'
|
|
840
|
-
}));
|
|
841
|
-
expect(getWebAnimation).toHaveBeenCalledWith(li2, expect.objectContaining(effectToAnimationOptions(getMockConfig().effects['logo-fade-scroll'])), expect.objectContaining({
|
|
842
|
-
trigger: 'view-progress'
|
|
843
|
-
}));
|
|
844
|
-
const li3 = document.createElement('li');
|
|
845
|
-
ul.append(li3);
|
|
846
|
-
addListItems(targetElement, 'logo-scroll-items', '#logo-scroll-list', [li3]);
|
|
847
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(3);
|
|
848
|
-
expect(getWebAnimation).toHaveBeenCalledWith(li3, expect.objectContaining(effectToAnimationOptions(getMockConfig().effects['logo-fade-scroll'])), expect.objectContaining({
|
|
849
|
-
trigger: 'view-progress'
|
|
850
|
-
}));
|
|
851
|
-
});
|
|
852
|
-
});
|
|
853
|
-
});
|
|
854
|
-
describe('remove interaction', () => {
|
|
855
|
-
beforeEach(() => {
|
|
856
|
-
Interact.create(getMockConfig());
|
|
857
|
-
});
|
|
858
|
-
afterEach(() => {
|
|
859
|
-
Interact.destroy();
|
|
860
|
-
});
|
|
861
|
-
it('should remove event listeners', () => {
|
|
862
|
-
element = document.createElement('interact-element');
|
|
863
|
-
const div = document.createElement('div');
|
|
864
|
-
element.append(div);
|
|
865
|
-
const removeEventListenerSpy = jest.spyOn(div, 'removeEventListener');
|
|
866
|
-
add(element, 'logo-click');
|
|
867
|
-
remove('logo-click');
|
|
868
|
-
expect(removeEventListenerSpy).toHaveBeenCalledTimes(2);
|
|
869
|
-
expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function));
|
|
870
|
-
});
|
|
871
|
-
it('should do nothing if key does not exist', () => {
|
|
872
|
-
expect(() => remove('non-existent-key')).not.toThrow();
|
|
873
|
-
});
|
|
874
|
-
it('should cleanup pointer effects', () => {
|
|
875
|
-
const {
|
|
876
|
-
Pointer
|
|
877
|
-
} = require('kuliso');
|
|
878
|
-
const pointerInstance = {
|
|
879
|
-
start: jest.fn(),
|
|
880
|
-
destroy: jest.fn()
|
|
881
|
-
};
|
|
882
|
-
Pointer.mockImplementation(() => pointerInstance);
|
|
883
|
-
element = document.createElement('interact-element');
|
|
884
|
-
const div = document.createElement('div');
|
|
885
|
-
element.append(div);
|
|
886
|
-
add(element, 'logo-mouse');
|
|
887
|
-
remove('logo-mouse');
|
|
888
|
-
expect(pointerInstance.destroy).toHaveBeenCalledTimes(1);
|
|
889
|
-
});
|
|
890
|
-
});
|
|
891
|
-
describe('effect cascading logic', () => {
|
|
892
|
-
describe('basic cascading behavior', () => {
|
|
893
|
-
it('should apply only first matching effect for same target', () => {
|
|
894
|
-
const {
|
|
895
|
-
getWebAnimation
|
|
896
|
-
} = require('@wix/motion');
|
|
897
|
-
const config = createCascadingTestConfig({}, ['min-width: 1024px']);
|
|
898
|
-
Interact.create(config);
|
|
899
|
-
const sourceElement = document.createElement('interact-element');
|
|
900
|
-
const sourceDiv = document.createElement('div');
|
|
901
|
-
sourceElement.append(sourceDiv);
|
|
902
|
-
const targetElement = document.createElement('interact-element');
|
|
903
|
-
const targetDiv = document.createElement('div');
|
|
904
|
-
targetElement.append(targetDiv);
|
|
905
|
-
const addEventListenerSpy = jest.spyOn(sourceDiv, 'addEventListener');
|
|
906
|
-
add(sourceElement, 'cascade-source');
|
|
907
|
-
add(targetElement, 'cascade-target');
|
|
908
|
-
expect(addEventListenerSpy).toHaveBeenCalledTimes(1);
|
|
909
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.objectContaining({
|
|
910
|
-
passive: true
|
|
911
|
-
}));
|
|
912
|
-
|
|
913
|
-
// Should create animation with desktop effect (first matching condition)
|
|
914
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
915
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
916
|
-
namedEffect: expect.objectContaining({
|
|
917
|
-
type: 'SlideIn',
|
|
918
|
-
direction: 'right'
|
|
919
|
-
})
|
|
920
|
-
}), undefined, {
|
|
921
|
-
reducedMotion: false
|
|
922
|
-
});
|
|
923
|
-
});
|
|
924
|
-
it('should apply default effect when no conditions match', () => {
|
|
925
|
-
const {
|
|
926
|
-
getWebAnimation
|
|
927
|
-
} = require('@wix/motion');
|
|
928
|
-
const config = createCascadingTestConfig({}, []); // No matching conditions
|
|
929
|
-
|
|
930
|
-
Interact.create(config);
|
|
931
|
-
const sourceElement = document.createElement('interact-element');
|
|
932
|
-
const sourceDiv = document.createElement('div');
|
|
933
|
-
sourceElement.append(sourceDiv);
|
|
934
|
-
const targetElement = document.createElement('interact-element');
|
|
935
|
-
const targetDiv = document.createElement('div');
|
|
936
|
-
targetElement.append(targetDiv);
|
|
937
|
-
add(sourceElement, 'cascade-source');
|
|
938
|
-
add(targetElement, 'cascade-target');
|
|
939
|
-
|
|
940
|
-
// Should create animation with default effect
|
|
941
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
942
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
943
|
-
namedEffect: expect.objectContaining({
|
|
944
|
-
type: 'FadeIn',
|
|
945
|
-
power: 'medium'
|
|
946
|
-
})
|
|
947
|
-
}), undefined, {
|
|
948
|
-
reducedMotion: false
|
|
949
|
-
});
|
|
950
|
-
});
|
|
951
|
-
it('should apply mobile effect when mobile condition matches', () => {
|
|
952
|
-
const {
|
|
953
|
-
getWebAnimation
|
|
954
|
-
} = require('@wix/motion');
|
|
955
|
-
const config = createCascadingTestConfig({}, ['max-width: 767px']);
|
|
956
|
-
Interact.create(config);
|
|
957
|
-
const sourceElement = document.createElement('interact-element');
|
|
958
|
-
const sourceDiv = document.createElement('div');
|
|
959
|
-
sourceElement.append(sourceDiv);
|
|
960
|
-
const targetElement = document.createElement('interact-element');
|
|
961
|
-
const targetDiv = document.createElement('div');
|
|
962
|
-
targetElement.append(targetDiv);
|
|
963
|
-
add(sourceElement, 'cascade-source');
|
|
964
|
-
add(targetElement, 'cascade-target');
|
|
965
|
-
|
|
966
|
-
// Should create animation with mobile effect
|
|
967
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
968
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
969
|
-
namedEffect: expect.objectContaining({
|
|
970
|
-
type: 'BounceIn',
|
|
971
|
-
direction: 'center'
|
|
972
|
-
})
|
|
973
|
-
}), undefined, {
|
|
974
|
-
reducedMotion: false
|
|
975
|
-
});
|
|
976
|
-
});
|
|
977
|
-
});
|
|
978
|
-
describe('element addition order', () => {
|
|
979
|
-
it('should work when source is added before target', () => {
|
|
980
|
-
const {
|
|
981
|
-
getWebAnimation
|
|
982
|
-
} = require('@wix/motion');
|
|
983
|
-
const config = createCascadingTestConfig({}, ['min-width: 1024px']);
|
|
984
|
-
Interact.create(config);
|
|
985
|
-
const sourceElement = document.createElement('interact-element');
|
|
986
|
-
const sourceDiv = document.createElement('div');
|
|
987
|
-
sourceElement.append(sourceDiv);
|
|
988
|
-
const targetElement = document.createElement('interact-element');
|
|
989
|
-
const targetDiv = document.createElement('div');
|
|
990
|
-
targetElement.append(targetDiv);
|
|
991
|
-
|
|
992
|
-
// Add source first
|
|
993
|
-
add(sourceElement, 'cascade-source');
|
|
994
|
-
// Add target second
|
|
995
|
-
add(targetElement, 'cascade-target');
|
|
996
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
997
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
998
|
-
namedEffect: expect.objectContaining({
|
|
999
|
-
type: 'SlideIn'
|
|
1000
|
-
})
|
|
1001
|
-
}), undefined, {
|
|
1002
|
-
reducedMotion: false
|
|
1003
|
-
});
|
|
1004
|
-
});
|
|
1005
|
-
it('should work when target is added before source', () => {
|
|
1006
|
-
const {
|
|
1007
|
-
getWebAnimation
|
|
1008
|
-
} = require('@wix/motion');
|
|
1009
|
-
const config = createCascadingTestConfig({}, ['min-width: 1024px']);
|
|
1010
|
-
Interact.create(config);
|
|
1011
|
-
const sourceElement = document.createElement('interact-element');
|
|
1012
|
-
const sourceDiv = document.createElement('div');
|
|
1013
|
-
sourceElement.append(sourceDiv);
|
|
1014
|
-
const targetElement = document.createElement('interact-element');
|
|
1015
|
-
const targetDiv = document.createElement('div');
|
|
1016
|
-
targetElement.append(targetDiv);
|
|
1017
|
-
|
|
1018
|
-
// Add target first
|
|
1019
|
-
add(targetElement, 'cascade-target');
|
|
1020
|
-
// Add source second
|
|
1021
|
-
add(sourceElement, 'cascade-source');
|
|
1022
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
1023
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
1024
|
-
namedEffect: expect.objectContaining({
|
|
1025
|
-
type: 'SlideIn'
|
|
1026
|
-
})
|
|
1027
|
-
}), undefined, {
|
|
1028
|
-
reducedMotion: false
|
|
1029
|
-
});
|
|
1030
|
-
});
|
|
1031
|
-
});
|
|
1032
|
-
describe('complex cascading scenarios', () => {
|
|
1033
|
-
it('should handle multiple targets with different conditions', () => {
|
|
1034
|
-
const {
|
|
1035
|
-
getWebAnimation
|
|
1036
|
-
} = require('@wix/motion');
|
|
1037
|
-
const complexConfig = {
|
|
1038
|
-
conditions: {
|
|
1039
|
-
desktop: {
|
|
1040
|
-
type: 'media',
|
|
1041
|
-
predicate: 'min-width: 1024px'
|
|
1042
|
-
},
|
|
1043
|
-
mobile: {
|
|
1044
|
-
type: 'media',
|
|
1045
|
-
predicate: 'max-width: 767px'
|
|
1046
|
-
}
|
|
1047
|
-
},
|
|
1048
|
-
interactions: [{
|
|
1049
|
-
trigger: 'click',
|
|
1050
|
-
key: 'multi-source-1',
|
|
1051
|
-
effects: [{
|
|
1052
|
-
key: 'cascade-target-1',
|
|
1053
|
-
effectId: 'desktop-effect',
|
|
1054
|
-
conditions: ['desktop']
|
|
1055
|
-
}, {
|
|
1056
|
-
key: 'cascade-target-2',
|
|
1057
|
-
effectId: 'mobile-effect',
|
|
1058
|
-
conditions: ['mobile']
|
|
1059
|
-
}]
|
|
1060
|
-
}],
|
|
1061
|
-
effects: {
|
|
1062
|
-
'desktop-effect': {
|
|
1063
|
-
namedEffect: {
|
|
1064
|
-
type: 'SlideIn',
|
|
1065
|
-
direction: 'right',
|
|
1066
|
-
power: 'medium'
|
|
1067
|
-
},
|
|
1068
|
-
duration: 800
|
|
1069
|
-
},
|
|
1070
|
-
'mobile-effect': {
|
|
1071
|
-
namedEffect: {
|
|
1072
|
-
type: 'BounceIn',
|
|
1073
|
-
direction: 'center',
|
|
1074
|
-
power: 'hard'
|
|
1075
|
-
},
|
|
1076
|
-
duration: 600
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
};
|
|
1080
|
-
mockMatchMedia(['min-width: 1024px']); // Only desktop matches
|
|
1081
|
-
Interact.create(complexConfig);
|
|
1082
|
-
const sourceElement = document.createElement('interact-element');
|
|
1083
|
-
const sourceDiv = document.createElement('div');
|
|
1084
|
-
sourceElement.append(sourceDiv);
|
|
1085
|
-
const target1Element = document.createElement('interact-element');
|
|
1086
|
-
const target1Div = document.createElement('div');
|
|
1087
|
-
target1Element.append(target1Div);
|
|
1088
|
-
const target2Element = document.createElement('interact-element');
|
|
1089
|
-
const target2Div = document.createElement('div');
|
|
1090
|
-
target2Element.append(target2Div);
|
|
1091
|
-
add(sourceElement, 'multi-source-1');
|
|
1092
|
-
add(target1Element, 'cascade-target-1');
|
|
1093
|
-
add(target2Element, 'cascade-target-2');
|
|
1094
|
-
|
|
1095
|
-
// Only desktop effect should be applied (mobile condition doesn't match)
|
|
1096
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
1097
|
-
expect(getWebAnimation).toHaveBeenCalledWith(target1Element.firstElementChild, expect.objectContaining({
|
|
1098
|
-
namedEffect: expect.objectContaining({
|
|
1099
|
-
type: 'SlideIn'
|
|
1100
|
-
})
|
|
1101
|
-
}), undefined, {
|
|
1102
|
-
reducedMotion: false
|
|
1103
|
-
});
|
|
1104
|
-
|
|
1105
|
-
// Should not be called for mobile effect since condition doesn't match
|
|
1106
|
-
expect(getWebAnimation).not.toHaveBeenCalledWith(target2Element.firstElementChild, expect.objectContaining({
|
|
1107
|
-
namedEffect: expect.objectContaining({
|
|
1108
|
-
type: 'BounceIn'
|
|
1109
|
-
})
|
|
1110
|
-
}), undefined, {
|
|
1111
|
-
reducedMotion: false
|
|
1112
|
-
});
|
|
1113
|
-
});
|
|
1114
|
-
it('should handle effects with multiple conditions', () => {
|
|
1115
|
-
const {
|
|
1116
|
-
getWebAnimation
|
|
1117
|
-
} = require('@wix/motion');
|
|
1118
|
-
const multiConditionConfig = {
|
|
1119
|
-
conditions: {
|
|
1120
|
-
desktop: {
|
|
1121
|
-
type: 'media',
|
|
1122
|
-
predicate: 'min-width: 1024px'
|
|
1123
|
-
},
|
|
1124
|
-
'high-res': {
|
|
1125
|
-
type: 'media',
|
|
1126
|
-
predicate: 'min-resolution: 2dppx'
|
|
1127
|
-
}
|
|
1128
|
-
},
|
|
1129
|
-
interactions: [{
|
|
1130
|
-
trigger: 'click',
|
|
1131
|
-
key: 'cascade-source',
|
|
1132
|
-
effects: [{
|
|
1133
|
-
key: 'cascade-target',
|
|
1134
|
-
effectId: 'premium-effect'
|
|
1135
|
-
}, {
|
|
1136
|
-
key: 'cascade-target',
|
|
1137
|
-
effectId: 'premium-effect',
|
|
1138
|
-
conditions: ['desktop', 'high-res']
|
|
1139
|
-
}]
|
|
1140
|
-
}],
|
|
1141
|
-
effects: {
|
|
1142
|
-
'premium-effect': {
|
|
1143
|
-
namedEffect: {
|
|
1144
|
-
type: 'Poke',
|
|
1145
|
-
direction: 'left',
|
|
1146
|
-
power: 'hard'
|
|
1147
|
-
},
|
|
1148
|
-
duration: 1000
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
};
|
|
1152
|
-
|
|
1153
|
-
// Both conditions match
|
|
1154
|
-
mockMatchMedia(['min-width: 1024px', 'min-resolution: 2dppx']);
|
|
1155
|
-
Interact.create(multiConditionConfig);
|
|
1156
|
-
const sourceElement = document.createElement('interact-element');
|
|
1157
|
-
const sourceDiv = document.createElement('div');
|
|
1158
|
-
sourceElement.append(sourceDiv);
|
|
1159
|
-
const targetElement = document.createElement('interact-element');
|
|
1160
|
-
const targetDiv = document.createElement('div');
|
|
1161
|
-
targetElement.append(targetDiv);
|
|
1162
|
-
add(sourceElement, 'cascade-source');
|
|
1163
|
-
add(targetElement, 'cascade-target');
|
|
1164
|
-
|
|
1165
|
-
// Premium effect should be applied since both conditions match
|
|
1166
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
1167
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
1168
|
-
namedEffect: expect.objectContaining({
|
|
1169
|
-
type: 'Poke'
|
|
1170
|
-
})
|
|
1171
|
-
}), undefined, {
|
|
1172
|
-
reducedMotion: false
|
|
1173
|
-
});
|
|
1174
|
-
});
|
|
1175
|
-
});
|
|
1176
|
-
describe('condition matching edge cases', () => {
|
|
1177
|
-
it('should handle missing conditions gracefully', () => {
|
|
1178
|
-
const {
|
|
1179
|
-
getWebAnimation
|
|
1180
|
-
} = require('@wix/motion');
|
|
1181
|
-
const configWithMissingCondition = {
|
|
1182
|
-
conditions: {
|
|
1183
|
-
desktop: {
|
|
1184
|
-
type: 'media',
|
|
1185
|
-
predicate: 'min-width: 1024px'
|
|
1186
|
-
}
|
|
1187
|
-
},
|
|
1188
|
-
interactions: [{
|
|
1189
|
-
trigger: 'click',
|
|
1190
|
-
key: 'cascade-source',
|
|
1191
|
-
effects: [{
|
|
1192
|
-
key: 'cascade-target',
|
|
1193
|
-
effectId: 'default-effect'
|
|
1194
|
-
}, {
|
|
1195
|
-
key: 'cascade-target',
|
|
1196
|
-
effectId: 'default-effect',
|
|
1197
|
-
conditions: ['nonexistent-condition']
|
|
1198
|
-
}]
|
|
1199
|
-
}],
|
|
1200
|
-
effects: {
|
|
1201
|
-
'default-effect': {
|
|
1202
|
-
namedEffect: {
|
|
1203
|
-
type: 'FadeIn',
|
|
1204
|
-
power: 'medium'
|
|
1205
|
-
},
|
|
1206
|
-
duration: 500
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
};
|
|
1210
|
-
mockMatchMedia(['min-width: 1024px']);
|
|
1211
|
-
Interact.create(configWithMissingCondition);
|
|
1212
|
-
const sourceElement = document.createElement('interact-element');
|
|
1213
|
-
const sourceDiv = document.createElement('div');
|
|
1214
|
-
sourceElement.append(sourceDiv);
|
|
1215
|
-
const targetElement = document.createElement('interact-element');
|
|
1216
|
-
const targetDiv = document.createElement('div');
|
|
1217
|
-
targetElement.append(targetDiv);
|
|
1218
|
-
add(sourceElement, 'cascade-source');
|
|
1219
|
-
add(targetElement, 'cascade-target');
|
|
1220
|
-
|
|
1221
|
-
// Should fall back to default effect since condition doesn't exist
|
|
1222
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
1223
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetElement.firstElementChild, expect.objectContaining({
|
|
1224
|
-
namedEffect: expect.objectContaining({
|
|
1225
|
-
type: 'FadeIn'
|
|
1226
|
-
})
|
|
1227
|
-
}), undefined, {
|
|
1228
|
-
reducedMotion: false
|
|
1229
|
-
});
|
|
1230
|
-
});
|
|
1231
|
-
it('should handle empty conditions array', () => {
|
|
1232
|
-
const {
|
|
1233
|
-
getWebAnimation
|
|
1234
|
-
} = require('@wix/motion');
|
|
1235
|
-
const configWithEmptyConditions = {
|
|
1236
|
-
conditions: {},
|
|
1237
|
-
interactions: [{
|
|
1238
|
-
trigger: 'click',
|
|
1239
|
-
key: 'cascade-source',
|
|
1240
|
-
effects: [{
|
|
1241
|
-
key: 'cascade-target',
|
|
1242
|
-
effectId: 'always-applied-effect',
|
|
1243
|
-
conditions: []
|
|
1244
|
-
}]
|
|
1245
|
-
}],
|
|
1246
|
-
effects: {
|
|
1247
|
-
'always-applied-effect': {
|
|
1248
|
-
namedEffect: {
|
|
1249
|
-
type: 'Spin',
|
|
1250
|
-
direction: 'clockwise',
|
|
1251
|
-
power: 'medium'
|
|
1252
|
-
},
|
|
1253
|
-
duration: 1000
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
};
|
|
1257
|
-
mockMatchMedia([]);
|
|
1258
|
-
Interact.create(configWithEmptyConditions);
|
|
1259
|
-
const sourceElement = document.createElement('interact-element');
|
|
1260
|
-
const sourceDiv = document.createElement('div');
|
|
1261
|
-
sourceElement.append(sourceDiv);
|
|
1262
|
-
const targetElement = document.createElement('interact-element');
|
|
1263
|
-
const targetDiv = document.createElement('div');
|
|
1264
|
-
targetElement.append(targetDiv);
|
|
1265
|
-
add(sourceElement, 'cascade-source');
|
|
1266
|
-
add(targetElement, 'cascade-target');
|
|
1267
|
-
|
|
1268
|
-
// Effect should be applied since empty conditions array should always match
|
|
1269
|
-
expect(getWebAnimation).toHaveBeenCalledTimes(1);
|
|
1270
|
-
expect(getWebAnimation).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining({
|
|
1271
|
-
namedEffect: expect.objectContaining({
|
|
1272
|
-
type: 'Spin'
|
|
1273
|
-
})
|
|
1274
|
-
}), undefined, {
|
|
1275
|
-
reducedMotion: false
|
|
1276
|
-
});
|
|
1277
|
-
});
|
|
1278
|
-
});
|
|
1279
|
-
});
|
|
1280
|
-
describe('selector functionality', () => {
|
|
1281
|
-
let sourceElement;
|
|
1282
|
-
let targetElement;
|
|
1283
|
-
beforeEach(() => {
|
|
1284
|
-
// Create source element with multiple child elements
|
|
1285
|
-
sourceElement = document.createElement('interact-element');
|
|
1286
|
-
sourceElement.innerHTML = `
|
|
1287
|
-
<div class="first-child">First Child</div>
|
|
1288
|
-
<button class="trigger-button">Click Me</button>
|
|
1289
|
-
<div class="other-element">Other</div>
|
|
1290
|
-
<div class="list-container">
|
|
1291
|
-
<div class="list-item">Item 1</div>
|
|
1292
|
-
<div class="list-item">Item 2</div>
|
|
1293
|
-
<div class="list-item">Item 3</div>
|
|
1294
|
-
</div>
|
|
1295
|
-
`;
|
|
1296
|
-
|
|
1297
|
-
// Create target element with multiple child elements
|
|
1298
|
-
targetElement = document.createElement('interact-element');
|
|
1299
|
-
targetElement.innerHTML = `
|
|
1300
|
-
<div class="first-child">Target First</div>
|
|
1301
|
-
<div class="animation-target">Animation Target</div>
|
|
1302
|
-
<div class="overlay">Overlay</div>
|
|
1303
|
-
<div class="nested">
|
|
1304
|
-
<span class="deep-target">Deep Target</span>
|
|
1305
|
-
</div>
|
|
1306
|
-
`;
|
|
1307
|
-
});
|
|
1308
|
-
describe('basic selector functionality', () => {
|
|
1309
|
-
it('should use selector instead of firstElementChild for source', () => {
|
|
1310
|
-
const config = {
|
|
1311
|
-
effects: {
|
|
1312
|
-
'test-effect': {
|
|
1313
|
-
keyframeEffect: {
|
|
1314
|
-
name: 'test',
|
|
1315
|
-
keyframes: [{
|
|
1316
|
-
opacity: '0'
|
|
1317
|
-
}, {
|
|
1318
|
-
opacity: '1'
|
|
1319
|
-
}]
|
|
1320
|
-
},
|
|
1321
|
-
duration: 300
|
|
1322
|
-
}
|
|
1323
|
-
},
|
|
1324
|
-
interactions: [{
|
|
1325
|
-
key: 'selector-source',
|
|
1326
|
-
selector: '.trigger-button',
|
|
1327
|
-
trigger: 'click',
|
|
1328
|
-
effects: [{
|
|
1329
|
-
key: 'selector-target',
|
|
1330
|
-
effectId: 'test-effect'
|
|
1331
|
-
}]
|
|
1332
|
-
}]
|
|
1333
|
-
};
|
|
1334
|
-
Interact.create(config);
|
|
1335
|
-
const triggerButton = sourceElement.querySelector('.trigger-button');
|
|
1336
|
-
const firstChild = sourceElement.querySelector('.first-child');
|
|
1337
|
-
const triggerSpy = jest.spyOn(triggerButton, 'addEventListener');
|
|
1338
|
-
const firstChildSpy = jest.spyOn(firstChild, 'addEventListener');
|
|
1339
|
-
add(sourceElement, 'selector-source');
|
|
1340
|
-
add(targetElement, 'selector-target');
|
|
1341
|
-
|
|
1342
|
-
// Should add event listener to the selected element, not firstElementChild
|
|
1343
|
-
expect(triggerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1344
|
-
expect(firstChildSpy).not.toHaveBeenCalled();
|
|
1345
|
-
});
|
|
1346
|
-
it('should use selector instead of firstElementChild for target', () => {
|
|
1347
|
-
const {
|
|
1348
|
-
getWebAnimation
|
|
1349
|
-
} = require('@wix/motion');
|
|
1350
|
-
const config = {
|
|
1351
|
-
effects: {
|
|
1352
|
-
'test-effect': {
|
|
1353
|
-
keyframeEffect: {
|
|
1354
|
-
name: 'test',
|
|
1355
|
-
keyframes: [{
|
|
1356
|
-
opacity: '0'
|
|
1357
|
-
}, {
|
|
1358
|
-
opacity: '1'
|
|
1359
|
-
}]
|
|
1360
|
-
},
|
|
1361
|
-
duration: 300
|
|
1362
|
-
}
|
|
1363
|
-
},
|
|
1364
|
-
interactions: [{
|
|
1365
|
-
key: 'selector-source',
|
|
1366
|
-
trigger: 'click',
|
|
1367
|
-
effects: [{
|
|
1368
|
-
key: 'selector-target',
|
|
1369
|
-
selector: '.animation-target',
|
|
1370
|
-
effectId: 'test-effect'
|
|
1371
|
-
}]
|
|
1372
|
-
}]
|
|
1373
|
-
};
|
|
1374
|
-
Interact.create(config);
|
|
1375
|
-
add(sourceElement, 'selector-source');
|
|
1376
|
-
add(targetElement, 'selector-target');
|
|
1377
|
-
const animationTarget = targetElement.querySelector('.animation-target');
|
|
1378
|
-
|
|
1379
|
-
// Should create animation on the selected element, not firstElementChild
|
|
1380
|
-
expect(getWebAnimation).toHaveBeenCalledWith(animationTarget, expect.any(Object), undefined, {
|
|
1381
|
-
reducedMotion: false
|
|
1382
|
-
});
|
|
1383
|
-
});
|
|
1384
|
-
it('should fall back to firstElementChild when no selector is provided', () => {
|
|
1385
|
-
const config = {
|
|
1386
|
-
effects: {
|
|
1387
|
-
'test-effect': {
|
|
1388
|
-
keyframeEffect: {
|
|
1389
|
-
name: 'test',
|
|
1390
|
-
keyframes: [{
|
|
1391
|
-
opacity: '0'
|
|
1392
|
-
}, {
|
|
1393
|
-
opacity: '1'
|
|
1394
|
-
}]
|
|
1395
|
-
},
|
|
1396
|
-
duration: 300
|
|
1397
|
-
}
|
|
1398
|
-
},
|
|
1399
|
-
interactions: [{
|
|
1400
|
-
key: 'fallback-source',
|
|
1401
|
-
trigger: 'click',
|
|
1402
|
-
effects: [{
|
|
1403
|
-
key: 'fallback-target',
|
|
1404
|
-
effectId: 'test-effect'
|
|
1405
|
-
}]
|
|
1406
|
-
}]
|
|
1407
|
-
};
|
|
1408
|
-
Interact.create(config);
|
|
1409
|
-
const firstChild = sourceElement.querySelector('.first-child');
|
|
1410
|
-
const firstChildSpy = jest.spyOn(firstChild, 'addEventListener');
|
|
1411
|
-
add(sourceElement, 'fallback-source');
|
|
1412
|
-
add(targetElement, 'fallback-target');
|
|
1413
|
-
|
|
1414
|
-
// Should fall back to firstElementChild
|
|
1415
|
-
expect(firstChildSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1416
|
-
});
|
|
1417
|
-
});
|
|
1418
|
-
describe('selector with listContainer', () => {
|
|
1419
|
-
it('should use selector within listContainer items', () => {
|
|
1420
|
-
const config = {
|
|
1421
|
-
effects: {
|
|
1422
|
-
'list-effect': {
|
|
1423
|
-
keyframeEffect: {
|
|
1424
|
-
name: 'list-test',
|
|
1425
|
-
keyframes: [{
|
|
1426
|
-
transform: 'scale(1)'
|
|
1427
|
-
}, {
|
|
1428
|
-
transform: 'scale(1.1)'
|
|
1429
|
-
}]
|
|
1430
|
-
},
|
|
1431
|
-
duration: 200
|
|
1432
|
-
}
|
|
1433
|
-
},
|
|
1434
|
-
interactions: [{
|
|
1435
|
-
key: 'list-source',
|
|
1436
|
-
listContainer: '.list-container',
|
|
1437
|
-
selector: '.list-item',
|
|
1438
|
-
trigger: 'hover',
|
|
1439
|
-
effects: [{
|
|
1440
|
-
listContainer: '.list-container',
|
|
1441
|
-
selector: '.list-item',
|
|
1442
|
-
effectId: 'list-effect'
|
|
1443
|
-
}]
|
|
1444
|
-
}]
|
|
1445
|
-
};
|
|
1446
|
-
Interact.create(config);
|
|
1447
|
-
|
|
1448
|
-
// Set up spies before adding interactions
|
|
1449
|
-
const listItems = Array.from(sourceElement.querySelectorAll('.list-item'));
|
|
1450
|
-
const spies = listItems.map(item => jest.spyOn(item, 'addEventListener'));
|
|
1451
|
-
add(sourceElement, 'list-source');
|
|
1452
|
-
|
|
1453
|
-
// Should add event listeners to each list item
|
|
1454
|
-
spies.forEach(spy => {
|
|
1455
|
-
expect(spy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.any(Object));
|
|
1456
|
-
});
|
|
1457
|
-
});
|
|
1458
|
-
it('should handle listContainer without selector (all children)', () => {
|
|
1459
|
-
var _sourceElement$queryS;
|
|
1460
|
-
const config = {
|
|
1461
|
-
effects: {
|
|
1462
|
-
'container-effect': {
|
|
1463
|
-
keyframeEffect: {
|
|
1464
|
-
name: 'container-test',
|
|
1465
|
-
keyframes: [{
|
|
1466
|
-
opacity: '0.5'
|
|
1467
|
-
}, {
|
|
1468
|
-
opacity: '1'
|
|
1469
|
-
}]
|
|
1470
|
-
},
|
|
1471
|
-
duration: 150
|
|
1472
|
-
}
|
|
1473
|
-
},
|
|
1474
|
-
interactions: [{
|
|
1475
|
-
key: 'container-source',
|
|
1476
|
-
listContainer: '.list-container',
|
|
1477
|
-
trigger: 'click',
|
|
1478
|
-
effects: [{
|
|
1479
|
-
listContainer: '.list-container',
|
|
1480
|
-
effectId: 'container-effect'
|
|
1481
|
-
}]
|
|
1482
|
-
}]
|
|
1483
|
-
};
|
|
1484
|
-
Interact.create(config);
|
|
1485
|
-
|
|
1486
|
-
// Set up spies before adding interactions
|
|
1487
|
-
const containerChildren = Array.from(((_sourceElement$queryS = sourceElement.querySelector('.list-container')) == null ? void 0 : _sourceElement$queryS.children) || []);
|
|
1488
|
-
const spies = containerChildren.map(child => jest.spyOn(child, 'addEventListener'));
|
|
1489
|
-
add(sourceElement, 'container-source');
|
|
1490
|
-
|
|
1491
|
-
// Should add event listeners to all children of the container
|
|
1492
|
-
spies.forEach(spy => {
|
|
1493
|
-
expect(spy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1494
|
-
});
|
|
1495
|
-
});
|
|
1496
|
-
});
|
|
1497
|
-
describe('selector error handling', () => {
|
|
1498
|
-
let consoleSpy;
|
|
1499
|
-
beforeEach(() => {
|
|
1500
|
-
consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
1501
|
-
});
|
|
1502
|
-
afterEach(() => {
|
|
1503
|
-
consoleSpy.mockRestore();
|
|
1504
|
-
});
|
|
1505
|
-
it('should warn when selector does not match any elements', () => {
|
|
1506
|
-
const config = {
|
|
1507
|
-
effects: {
|
|
1508
|
-
'test-effect': {
|
|
1509
|
-
keyframeEffect: {
|
|
1510
|
-
name: 'test',
|
|
1511
|
-
keyframes: [{
|
|
1512
|
-
opacity: '0'
|
|
1513
|
-
}, {
|
|
1514
|
-
opacity: '1'
|
|
1515
|
-
}]
|
|
1516
|
-
},
|
|
1517
|
-
duration: 300
|
|
1518
|
-
}
|
|
1519
|
-
},
|
|
1520
|
-
interactions: [{
|
|
1521
|
-
key: 'invalid-source',
|
|
1522
|
-
selector: '.non-existent-element',
|
|
1523
|
-
trigger: 'click',
|
|
1524
|
-
effects: [{
|
|
1525
|
-
key: 'invalid-target',
|
|
1526
|
-
effectId: 'test-effect'
|
|
1527
|
-
}]
|
|
1528
|
-
}]
|
|
1529
|
-
};
|
|
1530
|
-
Interact.create(config);
|
|
1531
|
-
add(sourceElement, 'invalid-source');
|
|
1532
|
-
add(targetElement, 'invalid-target');
|
|
1533
|
-
expect(consoleSpy).toHaveBeenCalledWith('Interact: No element found for selector ".non-existent-element"');
|
|
1534
|
-
});
|
|
1535
|
-
it('should warn when listContainer selector does not match', () => {
|
|
1536
|
-
const config = {
|
|
1537
|
-
effects: {
|
|
1538
|
-
'test-effect': {
|
|
1539
|
-
keyframeEffect: {
|
|
1540
|
-
name: 'test',
|
|
1541
|
-
keyframes: [{
|
|
1542
|
-
opacity: '0'
|
|
1543
|
-
}, {
|
|
1544
|
-
opacity: '1'
|
|
1545
|
-
}]
|
|
1546
|
-
},
|
|
1547
|
-
duration: 300
|
|
1548
|
-
}
|
|
1549
|
-
},
|
|
1550
|
-
interactions: [{
|
|
1551
|
-
key: 'invalid-container-source',
|
|
1552
|
-
listContainer: '.non-existent-container',
|
|
1553
|
-
trigger: 'click',
|
|
1554
|
-
effects: [{
|
|
1555
|
-
key: 'invalid-container-target',
|
|
1556
|
-
effectId: 'test-effect'
|
|
1557
|
-
}]
|
|
1558
|
-
}]
|
|
1559
|
-
};
|
|
1560
|
-
Interact.create(config);
|
|
1561
|
-
add(sourceElement, 'invalid-container-source');
|
|
1562
|
-
add(targetElement, 'invalid-container-target');
|
|
1563
|
-
expect(consoleSpy).toHaveBeenCalledWith('Interact: No container found for list container ".non-existent-container"');
|
|
1564
|
-
});
|
|
1565
|
-
it('should gracefully handle invalid selectors without breaking interactions', () => {
|
|
1566
|
-
const config = {
|
|
1567
|
-
effects: {
|
|
1568
|
-
'valid-effect': {
|
|
1569
|
-
keyframeEffect: {
|
|
1570
|
-
name: 'valid',
|
|
1571
|
-
keyframes: [{
|
|
1572
|
-
opacity: '0'
|
|
1573
|
-
}, {
|
|
1574
|
-
opacity: '1'
|
|
1575
|
-
}]
|
|
1576
|
-
},
|
|
1577
|
-
duration: 300
|
|
1578
|
-
}
|
|
1579
|
-
},
|
|
1580
|
-
interactions: [{
|
|
1581
|
-
key: 'mixed-source',
|
|
1582
|
-
selector: '.non-existent',
|
|
1583
|
-
trigger: 'click',
|
|
1584
|
-
effects: [{
|
|
1585
|
-
key: 'mixed-target',
|
|
1586
|
-
effectId: 'valid-effect'
|
|
1587
|
-
}]
|
|
1588
|
-
}, {
|
|
1589
|
-
key: 'valid-source',
|
|
1590
|
-
selector: '.trigger-button',
|
|
1591
|
-
trigger: 'click',
|
|
1592
|
-
effects: [{
|
|
1593
|
-
key: 'valid-target',
|
|
1594
|
-
effectId: 'valid-effect'
|
|
1595
|
-
}]
|
|
1596
|
-
}]
|
|
1597
|
-
};
|
|
1598
|
-
Interact.create(config);
|
|
1599
|
-
|
|
1600
|
-
// Set up spy before adding interactions
|
|
1601
|
-
const triggerButton = sourceElement.querySelector('.trigger-button');
|
|
1602
|
-
const spy = jest.spyOn(triggerButton, 'addEventListener');
|
|
1603
|
-
|
|
1604
|
-
// This should not throw and should allow other interactions to work
|
|
1605
|
-
expect(() => {
|
|
1606
|
-
add(sourceElement, 'mixed-source');
|
|
1607
|
-
add(sourceElement, 'valid-source');
|
|
1608
|
-
add(targetElement, 'mixed-target');
|
|
1609
|
-
add(targetElement, 'valid-target');
|
|
1610
|
-
}).not.toThrow();
|
|
1611
|
-
|
|
1612
|
-
// Valid interaction should still work
|
|
1613
|
-
expect(spy).toHaveBeenCalled();
|
|
1614
|
-
});
|
|
1615
|
-
});
|
|
1616
|
-
describe('complex selector scenarios', () => {
|
|
1617
|
-
it('should handle nested selectors', () => {
|
|
1618
|
-
const {
|
|
1619
|
-
getWebAnimation
|
|
1620
|
-
} = require('@wix/motion');
|
|
1621
|
-
const config = {
|
|
1622
|
-
effects: {
|
|
1623
|
-
'nested-effect': {
|
|
1624
|
-
keyframeEffect: {
|
|
1625
|
-
name: 'nested',
|
|
1626
|
-
keyframes: [{
|
|
1627
|
-
color: 'black'
|
|
1628
|
-
}, {
|
|
1629
|
-
color: 'blue'
|
|
1630
|
-
}]
|
|
1631
|
-
},
|
|
1632
|
-
duration: 200
|
|
1633
|
-
}
|
|
1634
|
-
},
|
|
1635
|
-
interactions: [{
|
|
1636
|
-
key: 'nested-source',
|
|
1637
|
-
selector: '.other-element',
|
|
1638
|
-
trigger: 'click',
|
|
1639
|
-
effects: [{
|
|
1640
|
-
key: 'nested-target',
|
|
1641
|
-
selector: '.nested .deep-target',
|
|
1642
|
-
effectId: 'nested-effect'
|
|
1643
|
-
}]
|
|
1644
|
-
}]
|
|
1645
|
-
};
|
|
1646
|
-
Interact.create(config);
|
|
1647
|
-
const addEventListenerSpy = jest.spyOn(sourceElement.querySelector('.other-element'), 'addEventListener');
|
|
1648
|
-
add(sourceElement, 'nested-source');
|
|
1649
|
-
add(targetElement, 'nested-target');
|
|
1650
|
-
const deepTarget = targetElement.querySelector('.nested .deep-target');
|
|
1651
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1652
|
-
expect(getWebAnimation).toHaveBeenCalledWith(deepTarget, expect.any(Object), undefined, {
|
|
1653
|
-
reducedMotion: false
|
|
1654
|
-
});
|
|
1655
|
-
});
|
|
1656
|
-
it('should handle attribute selectors', () => {
|
|
1657
|
-
// Add data attributes to test elements
|
|
1658
|
-
const buttonWithData = sourceElement.querySelector('.trigger-button');
|
|
1659
|
-
buttonWithData.setAttribute('data-interactive', 'true');
|
|
1660
|
-
buttonWithData.setAttribute('data-category', 'primary');
|
|
1661
|
-
const config = {
|
|
1662
|
-
effects: {
|
|
1663
|
-
'attr-effect': {
|
|
1664
|
-
keyframeEffect: {
|
|
1665
|
-
name: 'attr',
|
|
1666
|
-
keyframes: [{
|
|
1667
|
-
backgroundColor: 'white'
|
|
1668
|
-
}, {
|
|
1669
|
-
backgroundColor: 'lightblue'
|
|
1670
|
-
}]
|
|
1671
|
-
},
|
|
1672
|
-
duration: 300
|
|
1673
|
-
}
|
|
1674
|
-
},
|
|
1675
|
-
interactions: [{
|
|
1676
|
-
key: 'attr-source',
|
|
1677
|
-
selector: '[data-interactive="true"][data-category="primary"]',
|
|
1678
|
-
trigger: 'click',
|
|
1679
|
-
effects: [{
|
|
1680
|
-
key: 'attr-target',
|
|
1681
|
-
selector: '[class*="animation"]',
|
|
1682
|
-
effectId: 'attr-effect'
|
|
1683
|
-
}]
|
|
1684
|
-
}]
|
|
1685
|
-
};
|
|
1686
|
-
Interact.create(config);
|
|
1687
|
-
|
|
1688
|
-
// Set up spy before adding interactions
|
|
1689
|
-
const spy = jest.spyOn(buttonWithData, 'addEventListener');
|
|
1690
|
-
add(sourceElement, 'attr-source');
|
|
1691
|
-
add(targetElement, 'attr-target');
|
|
1692
|
-
expect(spy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1693
|
-
});
|
|
1694
|
-
});
|
|
1695
|
-
describe('selector inheritance and priority', () => {
|
|
1696
|
-
it('should not inherit selector from interaction to effect', () => {
|
|
1697
|
-
const {
|
|
1698
|
-
getWebAnimation
|
|
1699
|
-
} = require('@wix/motion');
|
|
1700
|
-
const config = {
|
|
1701
|
-
effects: {
|
|
1702
|
-
'inherit-effect': {
|
|
1703
|
-
keyframeEffect: {
|
|
1704
|
-
name: 'inherit',
|
|
1705
|
-
keyframes: [{
|
|
1706
|
-
opacity: '0'
|
|
1707
|
-
}, {
|
|
1708
|
-
opacity: '1'
|
|
1709
|
-
}]
|
|
1710
|
-
},
|
|
1711
|
-
duration: 300
|
|
1712
|
-
}
|
|
1713
|
-
},
|
|
1714
|
-
interactions: [{
|
|
1715
|
-
key: 'inherit-source',
|
|
1716
|
-
selector: '.trigger-button',
|
|
1717
|
-
// Interaction has selector
|
|
1718
|
-
trigger: 'click',
|
|
1719
|
-
effects: [{
|
|
1720
|
-
key: 'inherit-target',
|
|
1721
|
-
// Effect has no selector - should use firstElementChild, not inherit
|
|
1722
|
-
effectId: 'inherit-effect'
|
|
1723
|
-
}]
|
|
1724
|
-
}]
|
|
1725
|
-
};
|
|
1726
|
-
Interact.create(config);
|
|
1727
|
-
add(sourceElement, 'inherit-source');
|
|
1728
|
-
add(targetElement, 'inherit-target');
|
|
1729
|
-
|
|
1730
|
-
// Effect should target firstElementChild, not the interaction's selector
|
|
1731
|
-
const targetFirstChild = targetElement.firstElementChild;
|
|
1732
|
-
expect(getWebAnimation).toHaveBeenCalledWith(targetFirstChild, expect.any(Object), undefined, {
|
|
1733
|
-
reducedMotion: false
|
|
1734
|
-
});
|
|
1735
|
-
});
|
|
1736
|
-
});
|
|
1737
|
-
describe('selector cleanup', () => {
|
|
1738
|
-
it('should clean up selector-based interactions on remove', () => {
|
|
1739
|
-
const config = {
|
|
1740
|
-
effects: {
|
|
1741
|
-
'cleanup-effect': {
|
|
1742
|
-
keyframeEffect: {
|
|
1743
|
-
name: 'cleanup',
|
|
1744
|
-
keyframes: [{
|
|
1745
|
-
opacity: '0'
|
|
1746
|
-
}, {
|
|
1747
|
-
opacity: '1'
|
|
1748
|
-
}]
|
|
1749
|
-
},
|
|
1750
|
-
duration: 300
|
|
1751
|
-
}
|
|
1752
|
-
},
|
|
1753
|
-
interactions: [{
|
|
1754
|
-
key: 'cleanup-source',
|
|
1755
|
-
selector: '.trigger-button',
|
|
1756
|
-
trigger: 'click',
|
|
1757
|
-
effects: [{
|
|
1758
|
-
key: 'cleanup-target',
|
|
1759
|
-
selector: '.animation-target',
|
|
1760
|
-
effectId: 'cleanup-effect'
|
|
1761
|
-
}]
|
|
1762
|
-
}]
|
|
1763
|
-
};
|
|
1764
|
-
Interact.create(config);
|
|
1765
|
-
const triggerButton = sourceElement.querySelector('.trigger-button');
|
|
1766
|
-
const removeEventListenerSpy = jest.spyOn(triggerButton, 'removeEventListener');
|
|
1767
|
-
add(sourceElement, 'cleanup-source');
|
|
1768
|
-
add(targetElement, 'cleanup-target');
|
|
1769
|
-
remove('cleanup-source');
|
|
1770
|
-
|
|
1771
|
-
// Should remove event listeners from the selected element
|
|
1772
|
-
expect(removeEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function));
|
|
1773
|
-
});
|
|
1774
|
-
});
|
|
1775
|
-
});
|
|
1776
|
-
describe('element caching', () => {
|
|
1777
|
-
it('should cache element in elementCache even when no instance was found for it', () => {
|
|
1778
|
-
const keyWithoutInstance = 'key-without-instance';
|
|
1779
|
-
add(element, keyWithoutInstance);
|
|
1780
|
-
expect(Interact.elementCache.has(keyWithoutInstance)).toBe(true);
|
|
1781
|
-
expect(Interact.elementCache.get(keyWithoutInstance)).toBe(element);
|
|
1782
|
-
});
|
|
1783
|
-
});
|
|
1784
|
-
describe('setup', () => {
|
|
1785
|
-
afterEach(() => {
|
|
1786
|
-
Interact.setup({
|
|
1787
|
-
scrollOptionsGetter: () => ({}),
|
|
1788
|
-
pointerOptionsGetter: () => ({})
|
|
1789
|
-
});
|
|
1790
|
-
});
|
|
1791
|
-
it('should register scroll options getter', () => {
|
|
1792
|
-
const scrollOptionsGetter = jest.fn().mockReturnValue({});
|
|
1793
|
-
const spy = jest.spyOn(TRIGGER_TO_HANDLER_MODULE_MAP.viewProgress, 'registerOptionsGetter');
|
|
1794
|
-
Interact.setup({
|
|
1795
|
-
scrollOptionsGetter
|
|
1796
|
-
});
|
|
1797
|
-
expect(spy).toHaveBeenCalledWith(scrollOptionsGetter);
|
|
1798
|
-
});
|
|
1799
|
-
it('should register pointer options getter', () => {
|
|
1800
|
-
const pointerOptionsGetter = jest.fn().mockReturnValue({});
|
|
1801
|
-
const spy = jest.spyOn(TRIGGER_TO_HANDLER_MODULE_MAP.pointerMove, 'registerOptionsGetter');
|
|
1802
|
-
Interact.setup({
|
|
1803
|
-
pointerOptionsGetter
|
|
1804
|
-
});
|
|
1805
|
-
expect(spy).toHaveBeenCalledWith(pointerOptionsGetter);
|
|
1806
|
-
});
|
|
1807
|
-
});
|
|
1808
|
-
describe('a11y - accessible triggers', () => {
|
|
1809
|
-
let a11yElement;
|
|
1810
|
-
function getA11yConfig(trigger, key) {
|
|
1811
|
-
return {
|
|
1812
|
-
interactions: [{
|
|
1813
|
-
trigger,
|
|
1814
|
-
key,
|
|
1815
|
-
effects: [{
|
|
1816
|
-
effectId: 'test-effect'
|
|
1817
|
-
}]
|
|
1818
|
-
}],
|
|
1819
|
-
effects: {
|
|
1820
|
-
'test-effect': {
|
|
1821
|
-
namedEffect: {
|
|
1822
|
-
type: 'BounceIn',
|
|
1823
|
-
power: 'medium'
|
|
1824
|
-
},
|
|
1825
|
-
duration: 500
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
};
|
|
1829
|
-
}
|
|
1830
|
-
afterEach(() => {
|
|
1831
|
-
Interact.destroy();
|
|
1832
|
-
});
|
|
1833
|
-
describe('activate trigger', () => {
|
|
1834
|
-
it('should add both click and keydown listeners', () => {
|
|
1835
|
-
Interact.create(getA11yConfig('activate', 'activate-div'));
|
|
1836
|
-
a11yElement = document.createElement('interact-element');
|
|
1837
|
-
const div = document.createElement('div');
|
|
1838
|
-
a11yElement.append(div);
|
|
1839
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
1840
|
-
add(a11yElement, 'activate-div');
|
|
1841
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1842
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('keydown', expect.any(Function), expect.any(Object));
|
|
1843
|
-
});
|
|
1844
|
-
it('should not double-invoke handler when Enter triggers both keydown and click', () => {
|
|
1845
|
-
const {
|
|
1846
|
-
getWebAnimation
|
|
1847
|
-
} = require('@wix/motion');
|
|
1848
|
-
const mockPlay = getWebAnimation().play;
|
|
1849
|
-
mockPlay.mockClear();
|
|
1850
|
-
Interact.create(getA11yConfig('activate', 'activate-handler-test'));
|
|
1851
|
-
a11yElement = document.createElement('interact-element');
|
|
1852
|
-
const button = document.createElement('button');
|
|
1853
|
-
a11yElement.append(button);
|
|
1854
|
-
add(a11yElement, 'activate-handler-test');
|
|
1855
|
-
|
|
1856
|
-
// Simulate browser behavior: Enter key triggers keydown AND synthesized click with no pointerType
|
|
1857
|
-
button.dispatchEvent(new KeyboardEvent('keydown', {
|
|
1858
|
-
code: 'Enter',
|
|
1859
|
-
bubbles: true
|
|
1860
|
-
}));
|
|
1861
|
-
button.dispatchEvent(new MouseEvent('click', {
|
|
1862
|
-
bubbles: true
|
|
1863
|
-
}));
|
|
1864
|
-
expect(mockPlay).toHaveBeenCalledTimes(1);
|
|
1865
|
-
});
|
|
1866
|
-
});
|
|
1867
|
-
describe('interest trigger', () => {
|
|
1868
|
-
it('should add focusin listener alongside mouseenter', () => {
|
|
1869
|
-
Interact.create(getA11yConfig('interest', 'interest-test'));
|
|
1870
|
-
a11yElement = document.createElement('interact-element');
|
|
1871
|
-
const div = document.createElement('div');
|
|
1872
|
-
a11yElement.append(div);
|
|
1873
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
1874
|
-
add(a11yElement, 'interest-test');
|
|
1875
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.any(Object));
|
|
1876
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('focusin', expect.any(Function), expect.any(Object));
|
|
1877
|
-
});
|
|
1878
|
-
});
|
|
1879
|
-
describe('click trigger with allowA11yTriggers flag', () => {
|
|
1880
|
-
it('should NOT add keydown listener when flag is false', () => {
|
|
1881
|
-
Interact.create(getA11yConfig('click', 'click-no-flag'));
|
|
1882
|
-
Interact.setup({
|
|
1883
|
-
allowA11yTriggers: false
|
|
1884
|
-
});
|
|
1885
|
-
a11yElement = document.createElement('interact-element');
|
|
1886
|
-
const div = document.createElement('div');
|
|
1887
|
-
a11yElement.append(div);
|
|
1888
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
1889
|
-
add(a11yElement, 'click-no-flag');
|
|
1890
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1891
|
-
expect(addEventListenerSpy).not.toHaveBeenCalledWith('keydown', expect.any(Function), expect.any(Object));
|
|
1892
|
-
});
|
|
1893
|
-
it('should add keydown listener when flag is true', () => {
|
|
1894
|
-
Interact.setup({
|
|
1895
|
-
allowA11yTriggers: true
|
|
1896
|
-
});
|
|
1897
|
-
Interact.create(getA11yConfig('click', 'click-with-flag'));
|
|
1898
|
-
a11yElement = document.createElement('interact-element');
|
|
1899
|
-
const div = document.createElement('div');
|
|
1900
|
-
a11yElement.append(div);
|
|
1901
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
1902
|
-
add(a11yElement, 'click-with-flag');
|
|
1903
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('click', expect.any(Function), expect.any(Object));
|
|
1904
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('keydown', expect.any(Function), expect.any(Object));
|
|
1905
|
-
});
|
|
1906
|
-
});
|
|
1907
|
-
describe('hover trigger with allowA11yTriggers flag', () => {
|
|
1908
|
-
it('should NOT add focusin listener when flag is false', () => {
|
|
1909
|
-
Interact.setup({
|
|
1910
|
-
allowA11yTriggers: false
|
|
1911
|
-
});
|
|
1912
|
-
Interact.create(getA11yConfig('hover', 'hover-no-flag'));
|
|
1913
|
-
a11yElement = document.createElement('interact-element');
|
|
1914
|
-
const div = document.createElement('div');
|
|
1915
|
-
a11yElement.append(div);
|
|
1916
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
1917
|
-
add(a11yElement, 'hover-no-flag');
|
|
1918
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.any(Object));
|
|
1919
|
-
expect(addEventListenerSpy).not.toHaveBeenCalledWith('focusin', expect.any(Function), expect.any(Object));
|
|
1920
|
-
});
|
|
1921
|
-
it('should add focusin listener when flag is true', () => {
|
|
1922
|
-
Interact.setup({
|
|
1923
|
-
allowA11yTriggers: true
|
|
1924
|
-
});
|
|
1925
|
-
Interact.create(getA11yConfig('hover', 'hover-with-flag'));
|
|
1926
|
-
a11yElement = document.createElement('interact-element');
|
|
1927
|
-
const div = document.createElement('div');
|
|
1928
|
-
a11yElement.append(div);
|
|
1929
|
-
const addEventListenerSpy = jest.spyOn(div, 'addEventListener');
|
|
1930
|
-
add(a11yElement, 'hover-with-flag');
|
|
1931
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('mouseenter', expect.any(Function), expect.any(Object));
|
|
1932
|
-
expect(addEventListenerSpy).toHaveBeenCalledWith('focusin', expect.any(Function), expect.any(Object));
|
|
1933
|
-
});
|
|
1934
|
-
});
|
|
1935
|
-
});
|
|
1936
|
-
});
|
|
1937
|
-
//# sourceMappingURL=interact.spec.js.map
|