rytm-webflow 2.3.1 → 2.3.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/CLAUDE.md +2 -1
- package/package.json +1 -1
- package/scripts/aswap/WebflowListView.js +45 -3
- package/scripts/aswap/WebflowView.js +47 -3
package/CLAUDE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
AJAX view-swapping engine and scroll-triggered animation framework for tuki CMS projects.
|
|
4
4
|
Built on GSAP + ScrollMagic. Transforms server-rendered pages into pseudo-SPAs.
|
|
5
5
|
|
|
6
|
-
**Version**: 2.2
|
|
6
|
+
**Version**: 2.3.2 | **Entry**: `scripts/index.js` | **Deps**: gsap, imagesloaded, scrollmagic
|
|
7
7
|
|
|
8
8
|
## Exports
|
|
9
9
|
|
|
@@ -361,3 +361,4 @@ RytmWebflow.scrollController.destroy() // Clean up
|
|
|
361
361
|
7. **Stagger not working** — requires `data-webset="selector:..."` attribute
|
|
362
362
|
8. **Easing not applied** — use GSAP v3 syntax: `e:power3.out` (not `e:Power3.easeOut`)
|
|
363
363
|
9. **Cache causes stale content** — add `no-as-cache` class to forms or dynamic links
|
|
364
|
+
10. **Webscroll elements and viewport growth** — since 2.3.2 `webscroll` elements that enter the viewport via a resize / devtools toggle / background-tab activation (no scroll) are revealed automatically; earlier versions only fired on a `FORWARD` scroll crossing
|
package/package.json
CHANGED
|
@@ -19,6 +19,7 @@ class WebflowListView extends View {
|
|
|
19
19
|
constructor(id) {
|
|
20
20
|
super(id);
|
|
21
21
|
this.scenes = [];
|
|
22
|
+
this._revealTimer = null;
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* animate in (show)
|
|
@@ -136,6 +137,7 @@ class WebflowListView extends View {
|
|
|
136
137
|
handleEvent(e) {
|
|
137
138
|
switch (e.type) {
|
|
138
139
|
case 'resize':
|
|
140
|
+
case 'pageshow':
|
|
139
141
|
case 'DOMContentLoaded':
|
|
140
142
|
this.onWindowUpdate();
|
|
141
143
|
break;
|
|
@@ -143,17 +145,58 @@ class WebflowListView extends View {
|
|
|
143
145
|
}
|
|
144
146
|
addEventListeners() {
|
|
145
147
|
window.addEventListener('resize', this);
|
|
148
|
+
window.addEventListener('pageshow', this);
|
|
146
149
|
document.addEventListener('DOMContentLoaded', this);
|
|
147
150
|
}
|
|
148
151
|
removeEventListeners() {
|
|
149
152
|
window.removeEventListener('resize', this);
|
|
153
|
+
window.removeEventListener('pageshow', this);
|
|
150
154
|
document.removeEventListener('DOMContentLoaded', this);
|
|
155
|
+
clearTimeout(this._revealTimer);
|
|
151
156
|
}
|
|
152
157
|
onWindowUpdate() {
|
|
153
158
|
if (this.scenes.length > 0) {
|
|
154
159
|
scrollController.refresh();
|
|
160
|
+
// viewport size changed - recompute viewport-dependent scene offsets
|
|
161
|
+
// (they are baked from window.innerHeight at scene-build time)
|
|
162
|
+
this.refreshSceneOffsets();
|
|
163
|
+
// reveal elements that entered the viewport without a scroll (debounced -
|
|
164
|
+
// resize fires in bursts while dragging / toggling devtools)
|
|
165
|
+
clearTimeout(this._revealTimer);
|
|
166
|
+
this._revealTimer = setTimeout(() => this.revealVisibleScrollElements(), 150);
|
|
155
167
|
}
|
|
156
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Recompute viewport-dependent scene offsets after a viewport change
|
|
171
|
+
*/
|
|
172
|
+
refreshSceneOffsets() {
|
|
173
|
+
this.scenes.forEach(({ scene, el, setup }) => {
|
|
174
|
+
scene.offset(getScrollMagicSceneProps(el, setup).offset);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Reveal scene elements that entered the viewport without a scroll
|
|
179
|
+
* (devtools toggle, window resize, background-tab activation) -
|
|
180
|
+
* resize-driven scene updates carry scrollDirection "PAUSED", so the
|
|
181
|
+
* FORWARD guard in the scene start handler never fires for them
|
|
182
|
+
*/
|
|
183
|
+
revealVisibleScrollElements() {
|
|
184
|
+
this.scenes.forEach(({ el, propsShow }) => {
|
|
185
|
+
if (el.classList.contains(CLASS_NAME_WEBSCROLL_FIRED)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (!elementIsVisibleInViewport(el, true)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
gsap.to(el, {
|
|
192
|
+
duration: propsShow.time,
|
|
193
|
+
...propsShow.tween,
|
|
194
|
+
onComplete: () => {
|
|
195
|
+
el.classList.add(CLASS_NAME_WEBSCROLL_FIRED);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
}
|
|
157
200
|
/**
|
|
158
201
|
* #####################
|
|
159
202
|
* ### SCROLL SCENES ###
|
|
@@ -220,7 +263,7 @@ class WebflowListView extends View {
|
|
|
220
263
|
}, 10);
|
|
221
264
|
});
|
|
222
265
|
scene.addTo(scrollController.get());
|
|
223
|
-
this.scenes.push(scene);
|
|
266
|
+
this.scenes.push({ scene, el, propsShow, setup });
|
|
224
267
|
}
|
|
225
268
|
}
|
|
226
269
|
// hide off-screen scroll elements during view hide
|
|
@@ -238,9 +281,8 @@ class WebflowListView extends View {
|
|
|
238
281
|
}
|
|
239
282
|
// destroy all ScrollMagic scenes
|
|
240
283
|
destroyScenes() {
|
|
241
|
-
this.scenes.forEach((scene) => {
|
|
284
|
+
this.scenes.forEach(({ scene }) => {
|
|
242
285
|
scene.destroy();
|
|
243
|
-
scene = null;
|
|
244
286
|
});
|
|
245
287
|
this.scenes = [];
|
|
246
288
|
}
|
|
@@ -28,6 +28,7 @@ class WebflowView extends View {
|
|
|
28
28
|
constructor(id) {
|
|
29
29
|
super(id);
|
|
30
30
|
this.scenes = [];
|
|
31
|
+
this._revealTimer = null;
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
34
|
* prepare (before show)
|
|
@@ -85,6 +86,9 @@ class WebflowView extends View {
|
|
|
85
86
|
case 'resize':
|
|
86
87
|
this.onWindowUpdate(e);
|
|
87
88
|
break;
|
|
89
|
+
case 'pageshow':
|
|
90
|
+
this.onWindowUpdate(e);
|
|
91
|
+
break;
|
|
88
92
|
case 'DOMContentLoaded':
|
|
89
93
|
this.onWindowUpdate(e);
|
|
90
94
|
break;
|
|
@@ -95,6 +99,7 @@ class WebflowView extends View {
|
|
|
95
99
|
*/
|
|
96
100
|
addEventListeners() {
|
|
97
101
|
window.addEventListener('resize', this);
|
|
102
|
+
window.addEventListener('pageshow', this);
|
|
98
103
|
document.addEventListener('DOMContentLoaded', this);
|
|
99
104
|
}
|
|
100
105
|
/**
|
|
@@ -102,13 +107,53 @@ class WebflowView extends View {
|
|
|
102
107
|
*/
|
|
103
108
|
removeEventListeners() {
|
|
104
109
|
window.removeEventListener('resize', this);
|
|
110
|
+
window.removeEventListener('pageshow', this);
|
|
105
111
|
document.removeEventListener('DOMContentLoaded', this);
|
|
112
|
+
clearTimeout(this._revealTimer);
|
|
106
113
|
}
|
|
107
114
|
onWindowUpdate(e) {
|
|
108
115
|
if (this.scenes.length > 0) {
|
|
109
116
|
scrollController.refresh();
|
|
117
|
+
// viewport size changed - recompute viewport-dependent scene offsets
|
|
118
|
+
// (they are baked from window.innerHeight at scene-build time)
|
|
119
|
+
this.refreshSceneOffsets();
|
|
120
|
+
// reveal elements that entered the viewport without a scroll (debounced -
|
|
121
|
+
// resize fires in bursts while dragging / toggling devtools)
|
|
122
|
+
clearTimeout(this._revealTimer);
|
|
123
|
+
this._revealTimer = setTimeout(() => this.revealVisibleScrollElements(), 150);
|
|
110
124
|
}
|
|
111
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Recompute viewport-dependent scene offsets after a viewport change
|
|
128
|
+
*/
|
|
129
|
+
refreshSceneOffsets() {
|
|
130
|
+
this.scenes.forEach(({ scene, el, setup }) => {
|
|
131
|
+
scene.offset(getScrollMagicSceneProps(el, setup).offset);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Reveal scene elements that entered the viewport without a scroll
|
|
136
|
+
* (devtools toggle, window resize, background-tab activation) -
|
|
137
|
+
* resize-driven scene updates carry scrollDirection "PAUSED", so the
|
|
138
|
+
* FORWARD guard in the scene start handler never fires for them
|
|
139
|
+
*/
|
|
140
|
+
revealVisibleScrollElements() {
|
|
141
|
+
this.scenes.forEach(({ el, propsShow }) => {
|
|
142
|
+
if (el.classList.contains(CLASS_NAME_WEBSCROLL_FIRED)) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (!elementIsVisibleInViewport(el, true)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
gsap.to(el, {
|
|
149
|
+
duration: propsShow.time,
|
|
150
|
+
...propsShow.tween,
|
|
151
|
+
onComplete: () => {
|
|
152
|
+
el.classList.add(CLASS_NAME_WEBSCROLL_FIRED);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
}
|
|
112
157
|
/**
|
|
113
158
|
* ############
|
|
114
159
|
* ### SHOW ###
|
|
@@ -234,7 +279,7 @@ class WebflowView extends View {
|
|
|
234
279
|
}, 10);
|
|
235
280
|
});
|
|
236
281
|
scene.addTo(scrollController.get());
|
|
237
|
-
this.scenes.push(scene);
|
|
282
|
+
this.scenes.push({ scene, el, propsShow, setup });
|
|
238
283
|
}
|
|
239
284
|
}
|
|
240
285
|
/**
|
|
@@ -310,9 +355,8 @@ class WebflowView extends View {
|
|
|
310
355
|
}
|
|
311
356
|
// ## Destroy scrollmagic scenes
|
|
312
357
|
destroyScenes() {
|
|
313
|
-
this.scenes.forEach((scene) => {
|
|
358
|
+
this.scenes.forEach(({ scene }) => {
|
|
314
359
|
scene.destroy();
|
|
315
|
-
scene = null;
|
|
316
360
|
})
|
|
317
361
|
this.scenes = [];
|
|
318
362
|
}
|