@wix/interact 1.93.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.
Files changed (179) hide show
  1. package/dist/cjs/index.js +2 -23
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/react.js +15 -0
  4. package/dist/cjs/react.js.map +1 -0
  5. package/dist/cjs/web.js +2 -0
  6. package/dist/cjs/web.js.map +1 -0
  7. package/dist/es/index.js +8 -0
  8. package/dist/es/index.js.map +1 -0
  9. package/dist/es/react.js +650 -0
  10. package/dist/es/react.js.map +1 -0
  11. package/dist/es/web.js +56 -0
  12. package/dist/es/web.js.map +1 -0
  13. package/dist/index-C8QxOkui.mjs +7940 -0
  14. package/dist/index-C8QxOkui.mjs.map +1 -0
  15. package/dist/index-DEPRHaUt.js +18 -0
  16. package/dist/index-DEPRHaUt.js.map +1 -0
  17. package/dist/tsconfig.build.tsbuildinfo +1 -0
  18. package/dist/types/core/Interact.d.ts +17 -7
  19. package/dist/types/core/Interact.d.ts.map +1 -0
  20. package/dist/types/core/InteractionController.d.ts +19 -0
  21. package/dist/types/core/InteractionController.d.ts.map +1 -0
  22. package/dist/types/core/add.d.ts +4 -3
  23. package/dist/types/core/add.d.ts.map +1 -0
  24. package/dist/types/core/css.d.ts +3 -0
  25. package/dist/types/core/css.d.ts.map +1 -0
  26. package/dist/types/core/remove.d.ts +3 -1
  27. package/dist/types/core/remove.d.ts.map +1 -0
  28. package/dist/types/core/utilities.d.ts +1 -0
  29. package/dist/types/core/utilities.d.ts.map +1 -0
  30. package/dist/types/dom/api.d.ts +3 -0
  31. package/dist/types/dom/api.d.ts.map +1 -0
  32. package/dist/types/handlers/animationEnd.d.ts +3 -2
  33. package/dist/types/handlers/animationEnd.d.ts.map +1 -0
  34. package/dist/types/handlers/click.d.ts +3 -2
  35. package/dist/types/handlers/click.d.ts.map +1 -0
  36. package/dist/types/handlers/hover.d.ts +3 -2
  37. package/dist/types/handlers/hover.d.ts.map +1 -0
  38. package/dist/types/handlers/index.d.ts +1 -0
  39. package/dist/types/handlers/index.d.ts.map +1 -0
  40. package/dist/types/handlers/pointerMove.d.ts +3 -2
  41. package/dist/types/handlers/pointerMove.d.ts.map +1 -0
  42. package/dist/types/handlers/utilities.d.ts +1 -0
  43. package/dist/types/handlers/utilities.d.ts.map +1 -0
  44. package/dist/types/handlers/viewEnter.d.ts +3 -2
  45. package/dist/types/handlers/viewEnter.d.ts.map +1 -0
  46. package/dist/types/handlers/viewProgress.d.ts +4 -3
  47. package/dist/types/handlers/viewProgress.d.ts.map +1 -0
  48. package/dist/types/index.d.ts +3 -2
  49. package/dist/types/index.d.ts.map +1 -0
  50. package/dist/types/react/Interaction.d.ts +10 -0
  51. package/dist/types/react/Interaction.d.ts.map +1 -0
  52. package/dist/types/react/index.d.ts +8 -0
  53. package/dist/types/react/index.d.ts.map +1 -0
  54. package/dist/types/react/interactRef.d.ts +3 -0
  55. package/dist/types/react/interactRef.d.ts.map +1 -0
  56. package/dist/types/types.d.ts +23 -10
  57. package/dist/types/types.d.ts.map +1 -0
  58. package/dist/types/utils.d.ts +2 -1
  59. package/dist/types/utils.d.ts.map +1 -0
  60. package/dist/types/{InteractElement.d.ts → web/InteractElement.d.ts} +115 -77
  61. package/dist/types/web/InteractElement.d.ts.map +1 -0
  62. package/dist/types/web/defineInteractElement.d.ts +2 -0
  63. package/dist/types/web/defineInteractElement.d.ts.map +1 -0
  64. package/dist/types/web/index.d.ts +6 -0
  65. package/dist/types/web/index.d.ts.map +1 -0
  66. package/docs/README.md +211 -0
  67. package/docs/advanced/README.md +164 -0
  68. package/docs/api/README.md +157 -0
  69. package/docs/api/element-selection.md +607 -0
  70. package/docs/api/functions.md +638 -0
  71. package/docs/api/interact-class.md +663 -0
  72. package/docs/api/interact-element.md +565 -0
  73. package/docs/api/interaction-controller.md +450 -0
  74. package/docs/api/types.md +957 -0
  75. package/docs/examples/README.md +212 -0
  76. package/docs/examples/click-interactions.md +977 -0
  77. package/docs/examples/entrance-animations.md +935 -0
  78. package/docs/examples/hover-effects.md +930 -0
  79. package/docs/examples/list-patterns.md +737 -0
  80. package/docs/guides/README.md +49 -0
  81. package/docs/guides/conditions-and-media-queries.md +1068 -0
  82. package/docs/guides/configuration-structure.md +726 -0
  83. package/docs/guides/custom-elements.md +327 -0
  84. package/docs/guides/effects-and-animations.md +634 -0
  85. package/docs/guides/getting-started.md +379 -0
  86. package/docs/guides/lists-and-dynamic-content.md +713 -0
  87. package/docs/guides/state-management.md +747 -0
  88. package/docs/guides/understanding-triggers.md +690 -0
  89. package/docs/integration/README.md +264 -0
  90. package/docs/integration/react.md +605 -0
  91. package/package.json +73 -56
  92. package/rules/Integration.md +255 -0
  93. package/rules/click-rules.md +533 -0
  94. package/rules/full-lean.md +346 -0
  95. package/rules/hover-rules.md +593 -0
  96. package/rules/pointermove-rules.md +1341 -0
  97. package/rules/scroll-list-rules.md +900 -0
  98. package/rules/viewenter-rules.md +1015 -0
  99. package/rules/viewprogress-rules.md +1044 -0
  100. package/dist/cjs/InteractElement.js +0 -163
  101. package/dist/cjs/InteractElement.js.map +0 -1
  102. package/dist/cjs/__tests__/interact.spec.js +0 -2094
  103. package/dist/cjs/__tests__/interact.spec.js.map +0 -1
  104. package/dist/cjs/__tests__/viewEnter.spec.js +0 -207
  105. package/dist/cjs/__tests__/viewEnter.spec.js.map +0 -1
  106. package/dist/cjs/core/Interact.js +0 -257
  107. package/dist/cjs/core/Interact.js.map +0 -1
  108. package/dist/cjs/core/add.js +0 -250
  109. package/dist/cjs/core/add.js.map +0 -1
  110. package/dist/cjs/core/remove.js +0 -35
  111. package/dist/cjs/core/remove.js.map +0 -1
  112. package/dist/cjs/core/utilities.js +0 -16
  113. package/dist/cjs/core/utilities.js.map +0 -1
  114. package/dist/cjs/external-types.d.js +0 -2
  115. package/dist/cjs/external-types.d.js.map +0 -1
  116. package/dist/cjs/handlers/animationEnd.js +0 -37
  117. package/dist/cjs/handlers/animationEnd.js.map +0 -1
  118. package/dist/cjs/handlers/click.js +0 -122
  119. package/dist/cjs/handlers/click.js.map +0 -1
  120. package/dist/cjs/handlers/hover.js +0 -147
  121. package/dist/cjs/handlers/hover.js.map +0 -1
  122. package/dist/cjs/handlers/index.js +0 -32
  123. package/dist/cjs/handlers/index.js.map +0 -1
  124. package/dist/cjs/handlers/pointerMove.js +0 -49
  125. package/dist/cjs/handlers/pointerMove.js.map +0 -1
  126. package/dist/cjs/handlers/utilities.js +0 -49
  127. package/dist/cjs/handlers/utilities.js.map +0 -1
  128. package/dist/cjs/handlers/viewEnter.js +0 -131
  129. package/dist/cjs/handlers/viewEnter.js.map +0 -1
  130. package/dist/cjs/handlers/viewProgress.js +0 -79
  131. package/dist/cjs/handlers/viewProgress.js.map +0 -1
  132. package/dist/cjs/test-types.d.js +0 -2
  133. package/dist/cjs/test-types.d.js.map +0 -1
  134. package/dist/cjs/types.js +0 -2
  135. package/dist/cjs/types.js.map +0 -1
  136. package/dist/cjs/utils.js +0 -98
  137. package/dist/cjs/utils.js.map +0 -1
  138. package/dist/esm/InteractElement.js +0 -157
  139. package/dist/esm/InteractElement.js.map +0 -1
  140. package/dist/esm/__tests__/interact.spec.js +0 -2102
  141. package/dist/esm/__tests__/interact.spec.js.map +0 -1
  142. package/dist/esm/__tests__/viewEnter.spec.js +0 -210
  143. package/dist/esm/__tests__/viewEnter.spec.js.map +0 -1
  144. package/dist/esm/core/Interact.js +0 -251
  145. package/dist/esm/core/Interact.js.map +0 -1
  146. package/dist/esm/core/add.js +0 -245
  147. package/dist/esm/core/add.js.map +0 -1
  148. package/dist/esm/core/remove.js +0 -30
  149. package/dist/esm/core/remove.js.map +0 -1
  150. package/dist/esm/core/utilities.js +0 -14
  151. package/dist/esm/core/utilities.js.map +0 -1
  152. package/dist/esm/external-types.d.js +0 -2
  153. package/dist/esm/external-types.d.js.map +0 -1
  154. package/dist/esm/handlers/animationEnd.js +0 -33
  155. package/dist/esm/handlers/animationEnd.js.map +0 -1
  156. package/dist/esm/handlers/click.js +0 -122
  157. package/dist/esm/handlers/click.js.map +0 -1
  158. package/dist/esm/handlers/hover.js +0 -147
  159. package/dist/esm/handlers/hover.js.map +0 -1
  160. package/dist/esm/handlers/index.js +0 -27
  161. package/dist/esm/handlers/index.js.map +0 -1
  162. package/dist/esm/handlers/pointerMove.js +0 -48
  163. package/dist/esm/handlers/pointerMove.js.map +0 -1
  164. package/dist/esm/handlers/utilities.js +0 -43
  165. package/dist/esm/handlers/utilities.js.map +0 -1
  166. package/dist/esm/handlers/viewEnter.js +0 -133
  167. package/dist/esm/handlers/viewEnter.js.map +0 -1
  168. package/dist/esm/handlers/viewProgress.js +0 -75
  169. package/dist/esm/handlers/viewProgress.js.map +0 -1
  170. package/dist/esm/index.js +0 -5
  171. package/dist/esm/index.js.map +0 -1
  172. package/dist/esm/test-types.d.js +0 -2
  173. package/dist/esm/test-types.d.js.map +0 -1
  174. package/dist/esm/types.js +0 -2
  175. package/dist/esm/types.js.map +0 -1
  176. package/dist/esm/utils.js +0 -92
  177. package/dist/esm/utils.js.map +0 -1
  178. package/dist/types/__tests__/interact.spec.d.ts +0 -1
  179. package/dist/types/__tests__/viewEnter.spec.d.ts +0 -0
@@ -0,0 +1,713 @@
1
+ # Lists and Dynamic Content
2
+
3
+ Working with dynamic lists is one of the most powerful features of `@wix/interact`. This guide explains how to create animations for lists, handle dynamic content, and optimize performance for large datasets.
4
+
5
+ ## Overview
6
+
7
+ When working with lists, you have two main approaches:
8
+
9
+ 1. **Individual Elements** - Treat each list item as a separate interaction
10
+ 2. **List Container** - Use `listContainer` to target all items in a collection
11
+
12
+ The `listContainer` approach is **highly recommended** for:
13
+ - Dynamic lists that change (items added/removed)
14
+ - Large lists (100+ items)
15
+ - Staggered animations
16
+ - Consistent behavior across all items
17
+
18
+ ## Basic List Animations
19
+
20
+ ### Using listContainer
21
+
22
+ The `listContainer` property tells `@wix/interact` to:
23
+ 1. Find the container element
24
+ 2. Automatically track all its child elements
25
+ 3. Apply interactions to each child
26
+ 4. Watch for DOM additions/removals of direct children
27
+
28
+ ```typescript
29
+ import { Interact } from '@wix/interact';
30
+
31
+ const config = {
32
+ interactions: [{
33
+ key: 'product-grid',
34
+ listContainer: '.grid', // Container selector
35
+ trigger: 'viewEnter',
36
+ params: { type: 'once', threshold: 0.1 },
37
+ effects: [{
38
+ key: 'product-grid',
39
+ listContainer: '.grid', // Target the same container
40
+ keyframeEffect: {
41
+ name: 'fade-slide',
42
+ keyframes: [
43
+ { opacity: '0', transform: 'translateY(20px)' },
44
+ { opacity: '1', transform: 'translateY(0)' }
45
+ ]
46
+ },
47
+ duration: 600,
48
+ easing: 'ease-out'
49
+ }]
50
+ }]
51
+ };
52
+
53
+ Interact.create(config);
54
+ ```
55
+
56
+ ```html
57
+ <interact-element data-interact-key="product-grid">
58
+ <div class="grid">
59
+ <div class="item">Product 1</div>
60
+ <div class="item">Product 2</div>
61
+ <div class="item">Product 3</div>
62
+ <!-- More items... -->
63
+ </div>
64
+ </interact-element>
65
+ ```
66
+
67
+ ### Combining listContainer with selector
68
+
69
+ Use both properties to target specific elements within each list item:
70
+
71
+ ```typescript
72
+ {
73
+ key: 'gallery',
74
+ listContainer: '.gallery-grid', // Container with items
75
+ selector: '.gallery-item img', // Image in each item
76
+ trigger: 'hover',
77
+ effects: [{
78
+ key: 'gallery',
79
+ listContainer: '.gallery-grid',
80
+ selector: '.gallery-item .overlay', // Different target within item
81
+ keyframeEffect: {
82
+ name: 'reveal-overlay',
83
+ keyframes: [
84
+ { opacity: '0', transform: 'translateY(100%)' },
85
+ { opacity: '1', transform: 'translateY(0)' }
86
+ ]
87
+ },
88
+ duration: 300
89
+ }]
90
+ }
91
+ ```
92
+
93
+ ```html
94
+ <interact-element data-interact-key="gallery">
95
+ <div class="gallery-grid">
96
+ <div class="gallery-item">
97
+ <img src="image1.jpg" />
98
+ <div class="overlay">View Details</div>
99
+ </div>
100
+ <div class="gallery-item">
101
+ <img src="image2.jpg" />
102
+ <div class="overlay">View Details</div>
103
+ </div>
104
+ <!-- More items... -->
105
+ </div>
106
+ </interact-element>
107
+ ```
108
+
109
+ ## Staggered Animations
110
+
111
+ Create sequential entrance animations for list items using delays:
112
+
113
+ ### CSS-Based Stagger
114
+
115
+ ```typescript
116
+ {
117
+ key: 'feature-list',
118
+ listContainer: '.features',
119
+ trigger: 'viewEnter',
120
+ params: { type: 'once', threshold: 0.2 },
121
+ effects: [{
122
+ key: 'feature-list',
123
+ listContainer: '.features',
124
+ keyframeEffect: {
125
+ name: 'stagger-fade',
126
+ keyframes: [
127
+ { opacity: '0', transform: 'translateX(-30px)' },
128
+ { opacity: '1', transform: 'translateX(0)' }
129
+ ]
130
+ },
131
+ duration: 500,
132
+ easing: 'ease-out'
133
+ }]
134
+ }
135
+ ```
136
+
137
+ ```css
138
+ /* Add stagger delay via CSS */
139
+ .features > *:nth-child(1) { animation-delay: 0ms; }
140
+ .features > *:nth-child(2) { animation-delay: 100ms; }
141
+ .features > *:nth-child(3) { animation-delay: 200ms; }
142
+ .features > *:nth-child(4) { animation-delay: 300ms; }
143
+ .features > *:nth-child(5) { animation-delay: 400ms; }
144
+
145
+ /* Or use a formula for unlimited items */
146
+ .features > * {
147
+ animation-delay: calc(var(--stagger-index, 0) * 100ms);
148
+ }
149
+ ```
150
+
151
+ ### Programmatic Stagger
152
+
153
+ For more control, use data attributes:
154
+
155
+ ```html
156
+ <interact-element data-interact-key="animated-list">
157
+ <ul class="list">
158
+ <li data-delay="0">Item 1</li>
159
+ <li data-delay="100">Item 2</li>
160
+ <li data-delay="200">Item 3</li>
161
+ </ul>
162
+ </interact-element>
163
+ ```
164
+
165
+ ```typescript
166
+ {
167
+ key: 'animated-list',
168
+ listContainer: '.list',
169
+ trigger: 'viewEnter',
170
+ effects: [{
171
+ key: 'animated-list',
172
+ listContainer: '.list',
173
+ customEffect: (element) => {
174
+ const delay = parseInt(element.dataset.delay || '0');
175
+ return element.animate([
176
+ { opacity: 0, transform: 'scale(0.8)' },
177
+ { opacity: 1, transform: 'scale(1)' }
178
+ ], {
179
+ duration: 400,
180
+ delay,
181
+ fill: 'both',
182
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)'
183
+ });
184
+ }
185
+ }]
186
+ }
187
+ ```
188
+
189
+ ## Dynamic List Management
190
+
191
+ ### Automatic Mutation Tracking
192
+
193
+ `@wix/interact` automatically watches for changes in list containers:
194
+
195
+ ```typescript
196
+ // Configuration
197
+ const config = {
198
+ interactions: [{
199
+ key: 'todo-list',
200
+ listContainer: '.todos',
201
+ trigger: 'viewEnter',
202
+ effects: [{
203
+ key: 'todo-list',
204
+ listContainer: '.todos',
205
+ keyframeEffect: {
206
+ name: 'slide-in',
207
+ keyframes: [
208
+ { opacity: '0', transform: 'translateX(-20px)' },
209
+ { opacity: '1', transform: 'translateX(0)' }
210
+ ]
211
+ },
212
+ duration: 300
213
+ }]
214
+ }]
215
+ };
216
+
217
+ Interact.create(config);
218
+ ```
219
+
220
+ ```javascript
221
+ // Add new item - animation applies automatically
222
+ function addTodoItem(text) {
223
+ const todoList = document.querySelector('.todos');
224
+ const newItem = document.createElement('div');
225
+ newItem.className = 'todo-item';
226
+ newItem.textContent = text;
227
+
228
+ todoList.appendChild(newItem); // Automatically triggers animation
229
+ }
230
+
231
+ // Remove item - cleanup happens automatically
232
+ function removeTodoItem(item) {
233
+ item.remove(); // Automatically cleaned up
234
+ }
235
+ ```
236
+
237
+ ### Manual List Item Management
238
+
239
+ For advanced use cases, use the list management API:
240
+
241
+ ```typescript
242
+ import { addListItems, removeListItems } from '@wix/interact';
243
+
244
+ // Add specific items
245
+ function addItems(containerElement, items) {
246
+ const root = document.querySelector('interact-element[data-interact-key="my-list"]');
247
+ addListItems(root, 'my-list', '.list-container', items);
248
+ }
249
+
250
+ // Remove specific items
251
+ function removeItems(items) {
252
+ removeListItems(items);
253
+ }
254
+ ```
255
+
256
+ ### watchChildList Method
257
+
258
+ The custom element's `watchChildList` method sets up mutation observers:
259
+
260
+ ```typescript
261
+ const element = document.querySelector('interact-element');
262
+
263
+ // Start watching for changes in a container
264
+ element.watchChildList('.dynamic-list');
265
+
266
+ // Now any DOM changes in .dynamic-list will be tracked
267
+ ```
268
+
269
+ **How it works:**
270
+ 1. Creates a `MutationObserver` for the container
271
+ 2. Tracks `childList` mutations (additions/removals)
272
+ 3. Automatically calls `addListItems` for new elements
273
+ 4. Automatically calls `removeListItems` for removed elements
274
+ 5. Applies interactions to new items
275
+ 6. Cleans up removed items
276
+
277
+ ## List Animation Patterns
278
+
279
+ ### Entrance Animations
280
+
281
+ #### Fade In Sequence
282
+ ```typescript
283
+ {
284
+ key: 'cards',
285
+ listContainer: '.card-grid',
286
+ trigger: 'viewEnter',
287
+ params: { type: 'once', threshold: 0.1 },
288
+ effects: [{
289
+ key: 'cards',
290
+ listContainer: '.card-grid',
291
+ keyframeEffect: {
292
+ name: 'fade-in',
293
+ keyframes: [
294
+ { opacity: '0' },
295
+ { opacity: '1' }
296
+ ]
297
+ },
298
+ duration: 600,
299
+ easing: 'ease-out'
300
+ }]
301
+ }
302
+ ```
303
+
304
+ #### Slide Up Cascade
305
+ ```typescript
306
+ {
307
+ key: 'features',
308
+ listContainer: '.feature-list',
309
+ trigger: 'viewEnter',
310
+ params: { type: 'once', threshold: 0.2 },
311
+ effects: [{
312
+ key: 'features',
313
+ listContainer: '.feature-list',
314
+ keyframeEffect: {
315
+ name: 'slide-up',
316
+ keyframes: [
317
+ { opacity: '0', transform: 'translateY(40px)' },
318
+ { opacity: '1', transform: 'translateY(0)' }
319
+ ]
320
+ },
321
+ duration: 700,
322
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)'
323
+ }]
324
+ }
325
+ ```
326
+
327
+ #### Scale and Rotate
328
+ ```typescript
329
+ {
330
+ key: 'photos',
331
+ listContainer: '.photo-grid',
332
+ trigger: 'viewEnter',
333
+ params: { type: 'once', threshold: 0.15 },
334
+ effects: [{
335
+ key: 'photos',
336
+ listContainer: '.photo-grid',
337
+ keyframeEffect: {
338
+ name: 'scale-rotate',
339
+ keyframes: [
340
+ { opacity: '0', transform: 'scale(0.5) rotate(-10deg)' },
341
+ { opacity: '1', transform: 'scale(1) rotate(0deg)' }
342
+ ]
343
+ },
344
+ duration: 800,
345
+ easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' // Elastic
346
+ }]
347
+ }
348
+ ```
349
+
350
+ ### Hover Effects on Lists
351
+
352
+ ```typescript
353
+ {
354
+ key: 'product-grid',
355
+ listContainer: '.products',
356
+ trigger: 'hover',
357
+ effects: [
358
+ // Lift the product card
359
+ {
360
+ key: 'product-grid',
361
+ listContainer: '.products',
362
+ keyframeEffect: {
363
+ name: 'lift',
364
+ keyframes: [
365
+ { transform: 'translateY(0)', boxShadow: '0 2px 8px rgb(0 0 0 / 0.1)' },
366
+ { transform: 'translateY(-8px)', boxShadow: '0 12px 24px rgb(0 0 0 / 0.15)' }
367
+ ]
368
+ },
369
+ duration: 250
370
+ },
371
+ // Zoom the image
372
+ {
373
+ key: 'product-grid',
374
+ listContainer: '.products',
375
+ selector: '.product-image img',
376
+ keyframeEffect: {
377
+ name: 'zoom',
378
+ keyframes: [
379
+ { transform: 'scale(1)' },
380
+ { transform: 'scale(1.1)' }
381
+ ]
382
+ },
383
+ duration: 300
384
+ }
385
+ ]
386
+ }
387
+ ```
388
+
389
+ ### Infinite Scroll Integration
390
+
391
+ ```typescript
392
+ {
393
+ key: 'infinite-list',
394
+ listContainer: '.items',
395
+ trigger: 'viewEnter',
396
+ params: { type: 'repeat', threshold: 0.1 },
397
+ effects: [{
398
+ key: 'infinite-list',
399
+ listContainer: '.items',
400
+ keyframeEffect: {
401
+ name: 'fade-slide',
402
+ keyframes: [
403
+ { opacity: '0', transform: 'translateY(30px)' },
404
+ { opacity: '1', transform: 'translateY(0)' }
405
+ ]
406
+ },
407
+ duration: 500
408
+ }]
409
+ }
410
+ ```
411
+
412
+ ```javascript
413
+ // Infinite scroll implementation
414
+ const observer = new IntersectionObserver((entries) => {
415
+ entries.forEach(entry => {
416
+ if (entry.isIntersecting) {
417
+ loadMoreItems(); // New items automatically get animations
418
+ }
419
+ });
420
+ });
421
+
422
+ observer.observe(document.querySelector('.loading-sentinel'));
423
+
424
+ function loadMoreItems() {
425
+ const container = document.querySelector('.items');
426
+
427
+ // Fetch and add new items
428
+ fetchItems().then(items => {
429
+ items.forEach(item => {
430
+ const element = createItemElement(item);
431
+ container.appendChild(element);
432
+ // Animation triggers automatically via mutation observer
433
+ });
434
+ });
435
+ }
436
+ ```
437
+
438
+ ## Performance Optimization
439
+
440
+ ### When to Use listContainer
441
+
442
+ **✅ Use listContainer for:**
443
+ - Lists with 2+ items
444
+ - Dynamic lists (items added/removed)
445
+ - Consistent interactions across all items
446
+ - Staggered entrance effects
447
+ - Lists that grow (infinite scroll, pagination)
448
+
449
+ ### Performance Best Practices
450
+
451
+ #### Efficient Animations
452
+ ```typescript
453
+ // ✅ Good - GPU-accelerated properties
454
+ {
455
+ keyframeEffect: {
456
+ name: 'efficient',
457
+ keyframes: [
458
+ { opacity: '0', transform: 'translateY(20px)' },
459
+ { opacity: '1', transform: 'translateY(0)' }
460
+ ]
461
+ }
462
+ }
463
+
464
+ // ❌ Avoid - causes reflows
465
+ {
466
+ keyframeEffect: {
467
+ name: 'inefficient',
468
+ keyframes: [
469
+ { height: '0px', marginTop: '0px' },
470
+ { height: '200px', marginTop: '20px' }
471
+ ]
472
+ }
473
+ }
474
+ ```
475
+
476
+ #### Limit Active Observers
477
+ ```typescript
478
+ // ✅ Good - One container for all items
479
+ {
480
+ listContainer: '.products' // One observer
481
+ }
482
+
483
+ // ❌ Avoid - Multiple containers
484
+ {
485
+ listContainer: '.product-1' // Creates many observers
486
+ }
487
+ ```
488
+
489
+ ## Advanced Patterns
490
+
491
+ ### Grid-to-List Layout Transitions
492
+
493
+ ```typescript
494
+ const layoutConfig = {
495
+ conditions: {
496
+ 'grid-view': {
497
+ type: 'media',
498
+ predicate: '(min-width: 768px)'
499
+ },
500
+ 'list-view': {
501
+ type: 'media',
502
+ predicate: '(max-width: 767px)'
503
+ }
504
+ },
505
+ interactions: [
506
+ {
507
+ key: 'adaptive-items',
508
+ listContainer: '.items',
509
+ trigger: 'viewEnter',
510
+ conditions: ['grid-view'],
511
+ effects: [{
512
+ key: 'adaptive-items',
513
+ listContainer: '.items',
514
+ keyframeEffect: {
515
+ name: 'grid-fade',
516
+ keyframes: [
517
+ { opacity: '0', transform: 'scale(0.9)' },
518
+ { opacity: '1', transform: 'scale(1)' }
519
+ ]
520
+ },
521
+ duration: 500
522
+ }]
523
+ },
524
+ {
525
+ key: 'adaptive-items',
526
+ listContainer: '.items',
527
+ trigger: 'viewEnter',
528
+ conditions: ['list-view'],
529
+ effects: [{
530
+ key: 'adaptive-items',
531
+ listContainer: '.items',
532
+ keyframeEffect: {
533
+ name: 'list-slide',
534
+ keyframes: [
535
+ { opacity: '0', transform: 'translateX(-20px)' },
536
+ { opacity: '1', transform: 'translateX(0)' }
537
+ ]
538
+ },
539
+ duration: 400
540
+ }]
541
+ }
542
+ ]
543
+ };
544
+ ```
545
+
546
+ ## Real-World Examples
547
+
548
+ ### E-commerce Product Grid
549
+
550
+ ```typescript
551
+ const productGridConfig = {
552
+ interactions: [
553
+ // Entrance animation
554
+ {
555
+ key: 'products',
556
+ listContainer: '.product-grid',
557
+ trigger: 'viewEnter',
558
+ params: { type: 'once', threshold: 0.1 },
559
+ effects: [{
560
+ key: 'products',
561
+ listContainer: '.product-grid',
562
+ keyframeEffect: {
563
+ name: 'product-entrance',
564
+ keyframes: [
565
+ { opacity: '0', transform: 'translateY(40px) scale(0.95)' },
566
+ { opacity: '1', transform: 'translateY(0) scale(1)' }
567
+ ]
568
+ },
569
+ duration: 700,
570
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)'
571
+ }]
572
+ },
573
+ // Hover effect
574
+ {
575
+ key: 'products',
576
+ listContainer: '.product-grid',
577
+ selector: '.product-card',
578
+ trigger: 'hover',
579
+ effects: [
580
+ {
581
+ key: 'products',
582
+ listContainer: '.product-grid',
583
+ selector: '.product-card',
584
+ keyframeEffect: {
585
+ name: 'card-lift',
586
+ keyframes: [
587
+ { transform: 'translateY(0)', boxShadow: '0 4px 12px rgb(0 0 0 / 0.1)' },
588
+ { transform: 'translateY(-8px)', boxShadow: '0 16px 32px rgb(0 0 0 / 0.15)' }
589
+ ]
590
+ },
591
+ duration: 250
592
+ },
593
+ {
594
+ key: 'products',
595
+ listContainer: '.product-grid',
596
+ selector: '.product-image img',
597
+ keyframeEffect: {
598
+ name: 'image-zoom',
599
+ keyframes: [
600
+ { transform: 'scale(1)' },
601
+ { transform: 'scale(1.05)' }
602
+ ]
603
+ },
604
+ duration: 300
605
+ }
606
+ ]
607
+ }
608
+ ]
609
+ };
610
+ ```
611
+
612
+ ### Dynamic To-Do List
613
+
614
+ ```typescript
615
+ const todoConfig = {
616
+ interactions: [
617
+ // New item animation
618
+ {
619
+ key: 'todos',
620
+ listContainer: '.todo-list',
621
+ trigger: 'viewEnter',
622
+ params: { type: 'repeat' },
623
+ effects: [{
624
+ key: 'todos',
625
+ listContainer: '.todo-list',
626
+ keyframeEffect: {
627
+ name: 'todo-add',
628
+ keyframes: [
629
+ { opacity: '0', transform: 'translateX(-30px) scale(0.9)' },
630
+ { opacity: '1', transform: 'translateX(0) scale(1)' }
631
+ ]
632
+ },
633
+ duration: 400,
634
+ easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
635
+ }]
636
+ },
637
+ // Complete animation
638
+ {
639
+ key: 'todos',
640
+ listContainer: '.todo-list',
641
+ selector: '.todo-checkbox',
642
+ trigger: 'click',
643
+ effects: [{
644
+ key: 'todos',
645
+ listContainer: '.todo-list',
646
+ selector: '.todo-item',
647
+ transition: {
648
+ duration: 300,
649
+ styleProperties: [
650
+ { name: 'opacity', value: '0.5' },
651
+ { name: 'text-decoration', value: 'line-through' }
652
+ ]
653
+ }
654
+ }]
655
+ }
656
+ ]
657
+ };
658
+ ```
659
+
660
+ ### Image Gallery with Lightbox
661
+
662
+ ```typescript
663
+ const galleryConfig = {
664
+ interactions: [
665
+ // Grid entrance
666
+ {
667
+ key: 'gallery',
668
+ listContainer: '.gallery-grid',
669
+ trigger: 'viewEnter',
670
+ params: { type: 'once', threshold: 0.1 },
671
+ effects: [{
672
+ key: 'gallery',
673
+ listContainer: '.gallery-grid',
674
+ keyframeEffect: {
675
+ name: 'gallery-fade',
676
+ keyframes: [
677
+ { opacity: '0', filter: 'blur(10px)' },
678
+ { opacity: '1', filter: 'blur(0)' }
679
+ ]
680
+ },
681
+ duration: 800
682
+ }]
683
+ },
684
+ // Hover overlay
685
+ {
686
+ key: 'gallery',
687
+ listContainer: '.gallery-grid',
688
+ selector: '.gallery-item',
689
+ trigger: 'hover',
690
+ effects: [{
691
+ key: 'gallery',
692
+ listContainer: '.gallery-grid',
693
+ selector: '.gallery-overlay',
694
+ keyframeEffect: {
695
+ name: 'overlay-reveal',
696
+ keyframes: [
697
+ { opacity: '0' },
698
+ { opacity: '1' }
699
+ ]
700
+ },
701
+ duration: 250
702
+ }]
703
+ }
704
+ ]
705
+ };
706
+ ```
707
+
708
+ ## Next Steps
709
+
710
+ - **[Element Selection](../api/element-selection.md)** - Understand selector priority
711
+ - **[Performance Guide](./performance.md)** - Optimize animations
712
+ - **[API Reference](../api/functions.md)** - List management functions
713
+ - **[Examples](../examples/list-patterns.md)** - More list patterns