rytm-webflow 2.2.4 → 2.2.5
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 +363 -0
- package/package.json +1 -1
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# rytm-webflow
|
|
2
|
+
|
|
3
|
+
AJAX view-swapping engine and scroll-triggered animation framework for tuki CMS projects.
|
|
4
|
+
Built on GSAP + ScrollMagic. Transforms server-rendered pages into pseudo-SPAs.
|
|
5
|
+
|
|
6
|
+
**Version**: 2.2.4 | **Entry**: `scripts/index.js` | **Deps**: gsap, imagesloaded, scrollmagic
|
|
7
|
+
|
|
8
|
+
## Exports
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
import RytmWebflow from 'rytm-webflow'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Export | Type | Purpose |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `aswap` | Singleton | AJAX page swap engine |
|
|
17
|
+
| `Controller` | Class | Base controller — view lifecycle & event management |
|
|
18
|
+
| `ControllerImgLoad` | Class | Controller that waits for images before showing view |
|
|
19
|
+
| `View` | Class | Base view — animation hooks |
|
|
20
|
+
| `WebflowView` | Class | View with declarative animations via data attributes |
|
|
21
|
+
| `WebflowListView` | Class | Staggered list animations with scroll triggers |
|
|
22
|
+
| `bootsrap5` | Object | Bootstrap 5 modal/offcanvas close helpers |
|
|
23
|
+
| `scrollController` | Singleton | ScrollMagic controller manager |
|
|
24
|
+
| `showUp` | Singleton | Standalone scroll-triggered animations (no ASwap needed) |
|
|
25
|
+
| `getWebflowProps(str)` | Function | Parse webflow show/hide syntax |
|
|
26
|
+
| `getWebflowAnimationProps(str)` | Function | Parse single animation string |
|
|
27
|
+
| `getParallaxProps(str)` | Function | Parse parallax syntax |
|
|
28
|
+
| `parseProps(str)` | Function | Parse `key:value` comma-separated pairs |
|
|
29
|
+
| `getScrollMagicSceneProps(el, setup)` | Function | Generate ScrollMagic scene config |
|
|
30
|
+
| `elementIsVisibleInViewport(el, partial)` | Function | Viewport visibility check |
|
|
31
|
+
| `CLASS_NAME_WEBSCROLL_FIRED` | Constant | `'webflow-scroll-fired'` |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ASwap — AJAX page swap engine
|
|
36
|
+
|
|
37
|
+
### Init
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
RytmWebflow.aswap.init(params, events)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**params** (all optional, shown with defaults):
|
|
44
|
+
|
|
45
|
+
| Param | Default | Description |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `animationTimeHide` | `800` | Hide transition duration (ms) |
|
|
48
|
+
| `animationTimeShow` | `800` | Show transition duration (ms) |
|
|
49
|
+
| `routes` | `{}` | Route definitions — `{ viewName: { controller, view } }` |
|
|
50
|
+
| `swapSelector` | `'#stage'` | Container selector for swapped content |
|
|
51
|
+
| `cacheOn` | `true` | Cache AJAX responses |
|
|
52
|
+
| `noCacheClassName` | `'no-as-cache'` | Link class to skip cache |
|
|
53
|
+
| `noSwapClassName` | `'no-as'` | Link class to skip ASwap entirely |
|
|
54
|
+
| `noScrollClassName` | `'no-as-scroll'` | Link class to keep scroll position |
|
|
55
|
+
| `resetScrollOn` | `true` | Reset scroll on navigation |
|
|
56
|
+
| `preloadOnHover` | `false` | Preload pages on link hover |
|
|
57
|
+
| `formsEnabled` | `true` | AJAX form submission |
|
|
58
|
+
| `formsSelector` | `'form'` | Form selector |
|
|
59
|
+
| `swipeEnabled` | `true` | Swipe navigation on mobile |
|
|
60
|
+
| `historyEnabled` | `true` | Use History API |
|
|
61
|
+
| `refreshOnSameUrl` | `true` | Reload on same-URL click |
|
|
62
|
+
| `defaultDocumentScrollBehavior` | `'smooth'` | Scroll animation |
|
|
63
|
+
| `trace` | `() => {}` | Debug logging function |
|
|
64
|
+
|
|
65
|
+
**events** (all optional):
|
|
66
|
+
|
|
67
|
+
| Event | When |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `onInited` | ASwap initialized |
|
|
70
|
+
| `onRequestUrl` | URL navigation started |
|
|
71
|
+
| `onRequestLoad` | AJAX loading started |
|
|
72
|
+
| `onRequestLoaded` | Response received |
|
|
73
|
+
| `onRequestSameUrl` | Same URL re-requested |
|
|
74
|
+
| `onViewHide` | Hide animation starting |
|
|
75
|
+
| `onViewHidden` | Hide animation complete |
|
|
76
|
+
| `onViewSwapStart` | Before DOM swap |
|
|
77
|
+
| `onViewSwapComplete` | After DOM swap |
|
|
78
|
+
| `onViewShow` | Show animation starting |
|
|
79
|
+
| `onViewShown` | Show animation complete |
|
|
80
|
+
|
|
81
|
+
### Methods
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
RytmWebflow.aswap.openURL(url, noHistory?, useCache?) // Navigate programmatically
|
|
85
|
+
RytmWebflow.aswap.clearCache(url?) // Clear all or specific cache
|
|
86
|
+
RytmWebflow.aswap.formSubmit(formElement) // Submit form via AJAX
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### HTML requirements
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<body data-html-classes="optional-classes">
|
|
93
|
+
<div id="stage">
|
|
94
|
+
<div data-as-view="viewname" data-as-id="unique-id">
|
|
95
|
+
<!-- swapped content -->
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</body>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Link classes
|
|
102
|
+
|
|
103
|
+
| Class | Effect |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `no-as` | Skip ASwap — regular navigation |
|
|
106
|
+
| `no-as-cache` | Skip response cache |
|
|
107
|
+
| `no-as-scroll` | Don't reset scroll position |
|
|
108
|
+
|
|
109
|
+
### Swipe navigation
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<div data-as-swipe-left="/next" data-as-swipe-right="/prev">
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Controller
|
|
118
|
+
|
|
119
|
+
Base class for view lifecycle management. One instance per `data-as-id`.
|
|
120
|
+
|
|
121
|
+
### Key properties
|
|
122
|
+
|
|
123
|
+
| Property | Type | Description |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| `id` | string | Unique identifier from `data-as-id` |
|
|
126
|
+
| `name` | string | Route name from `data-as-view` |
|
|
127
|
+
| `active` | boolean | Whether view is currently visible |
|
|
128
|
+
| `view` | View\|false | Associated View instance |
|
|
129
|
+
|
|
130
|
+
### Lifecycle (override in subclass)
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
class MyController extends RytmWebflow.Controller {
|
|
134
|
+
addEventListeners() {
|
|
135
|
+
super.addEventListeners()
|
|
136
|
+
// Add DOM listeners — called when view becomes visible
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
removeEventListeners() {
|
|
140
|
+
super.removeEventListeners()
|
|
141
|
+
// Remove DOM listeners — called when view hides
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Event handler sequence
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
Click link → onRequestUrl → onRequestLoad → onRequestLoaded
|
|
150
|
+
→ onViewHide (removeEventListeners + view.hide)
|
|
151
|
+
→ onViewHidden
|
|
152
|
+
→ DOM swap (onViewSwapStart → onViewSwapComplete)
|
|
153
|
+
→ onViewShow (view.show)
|
|
154
|
+
→ onViewShown (addEventListeners + view.shown)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Utility methods
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
controller.getViewContainer(wrapper) // Find this controller's DOM container
|
|
161
|
+
controller.getContainerSelector() // Returns '[data-as-id="..."]'
|
|
162
|
+
controller.isActive() // Check if visible
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## ControllerImgLoad
|
|
168
|
+
|
|
169
|
+
Extends `Controller`. Delays show animation until all images in container are loaded.
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
class GalleryCtrl extends RytmWebflow.ControllerImgLoad {
|
|
173
|
+
loadImagesComplete() {
|
|
174
|
+
super.loadImagesComplete()
|
|
175
|
+
// All images loaded — safe for layout-dependent operations
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
CSS class `as-images-loading` is on container while images load.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## View
|
|
185
|
+
|
|
186
|
+
Base class for show/hide animations.
|
|
187
|
+
|
|
188
|
+
### Lifecycle methods (override in subclass)
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
class MyView extends RytmWebflow.View {
|
|
192
|
+
prepare(container) { super.prepare(container) } // Before show, set initial state
|
|
193
|
+
show(container) { super.show(container) } // Animate in
|
|
194
|
+
shown(container) { } // Show complete
|
|
195
|
+
hide(container) { super.hide(container) } // Animate out
|
|
196
|
+
hidden(container) { } // Hide complete
|
|
197
|
+
|
|
198
|
+
// Only with ControllerImgLoad:
|
|
199
|
+
loadImagesStart(container) { }
|
|
200
|
+
loadImagesComplete(container) { }
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Utility
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
// Filter elements to exclude nested views
|
|
208
|
+
const items = [...container.querySelectorAll('.item')].filter(this.elementBelongsToView)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## WebflowView — declarative animations
|
|
214
|
+
|
|
215
|
+
Extends `View`. Reads animation config from data attributes — no manual animation code needed.
|
|
216
|
+
|
|
217
|
+
### ASwap view animations (show/hide on page transition)
|
|
218
|
+
|
|
219
|
+
```html
|
|
220
|
+
<div data-webview-initial="o:0"
|
|
221
|
+
data-webview-show="o:1,t:.5,e:power3.out"
|
|
222
|
+
data-webview-hide="o:0,t:.3">
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Scroll-triggered animations
|
|
226
|
+
|
|
227
|
+
```html
|
|
228
|
+
<div data-webscroll-initial="o:0,y:100"
|
|
229
|
+
data-webscroll-show="o:1,y:0,t:.5,e:power3.out"
|
|
230
|
+
data-webscroll-hide="o:0,t:.3">
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Stagger animations (lists)
|
|
234
|
+
|
|
235
|
+
```html
|
|
236
|
+
<ul data-stagger-initial="o:0,y:20"
|
|
237
|
+
data-stagger-show="o:1,y:0,t:.5,stagger:.08"
|
|
238
|
+
data-stagger-hide="o:0,t:.3,stagger:.04"
|
|
239
|
+
data-webset="selector:li">
|
|
240
|
+
<li>Item 1</li>
|
|
241
|
+
<li>Item 2</li>
|
|
242
|
+
</ul>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Webflow syntax reference
|
|
246
|
+
|
|
247
|
+
| Code | CSS Property | Example |
|
|
248
|
+
|---|---|---|
|
|
249
|
+
| `o` | opacity | `o:0` → `o:1` |
|
|
250
|
+
| `x` | translateX | `x:100` (px, supports `vw`/`vh`) |
|
|
251
|
+
| `y` | translateY | `y:-50` |
|
|
252
|
+
| `s` | scale | `s:1.2` |
|
|
253
|
+
| `r` | rotation | `r:90` (degrees) |
|
|
254
|
+
| `w` | width | `w:500` (px) |
|
|
255
|
+
| `h` | height | `h:300` (px) |
|
|
256
|
+
| `t` | duration | `t:.5` (seconds) |
|
|
257
|
+
| `d` | delay | `d:.2` (seconds) |
|
|
258
|
+
| `e` | ease | `e:power3.out` (GSAP v3 syntax) |
|
|
259
|
+
| `stagger` | item delay | `stagger:.1` (seconds, for lists) |
|
|
260
|
+
|
|
261
|
+
### data-webset options
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<div data-webset="trigger:parent,offset:center,fireOnce:false,duration:100%">
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
| Option | Values | Default | Description |
|
|
268
|
+
|---|---|---|---|
|
|
269
|
+
| `trigger` | `parent`, CSS selector | element itself | What triggers the animation |
|
|
270
|
+
| `offset` | `top`, `center`, px value | bottom of viewport | Viewport trigger position |
|
|
271
|
+
| `fireOnce` | `true`, `false` | `true` | Animate only once |
|
|
272
|
+
| `duration` | `%`, `vh` | — | Parallax-style animation over scroll distance |
|
|
273
|
+
| `selector` | CSS selector | — | Required for stagger: selects list items |
|
|
274
|
+
| `stagger` | seconds | `0.05` | Delay between stagger items |
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## WebflowListView
|
|
279
|
+
|
|
280
|
+
Extends `View`. Applies scroll-triggered stagger animations to list items.
|
|
281
|
+
|
|
282
|
+
```html
|
|
283
|
+
<div data-as-view="list" data-as-id="products" data-webset="selector:.item,stagger:.15">
|
|
284
|
+
<div class="item">
|
|
285
|
+
<div data-webscroll-initial="o:0" data-webscroll-show="o:1,t:.5">Content</div>
|
|
286
|
+
</div>
|
|
287
|
+
<!-- more items... -->
|
|
288
|
+
</div>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Each item's delay = `index × stagger + original delay`.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## ShowUp — standalone scroll animations
|
|
296
|
+
|
|
297
|
+
Works without ASwap. For elements that animate on scroll across all pages.
|
|
298
|
+
|
|
299
|
+
```javascript
|
|
300
|
+
RytmWebflow.showUp.init() // Build all scroll scenes from DOM
|
|
301
|
+
RytmWebflow.showUp.rebuild() // Destroy and reinit (call after DOM changes)
|
|
302
|
+
RytmWebflow.showUp.hide() // Trigger all hide animations
|
|
303
|
+
RytmWebflow.showUp.destroy() // Clean up all scenes
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### HTML syntax
|
|
307
|
+
|
|
308
|
+
```html
|
|
309
|
+
<!-- Show;Hide separated by semicolon -->
|
|
310
|
+
<div data-webflow="o:0,t:.5,e:power3.out;o:0,y:-50,t:.3">
|
|
311
|
+
Animate on scroll
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<!-- Parallax -->
|
|
315
|
+
<div data-webpara="y:-100" data-webset="duration:100%,trigger:parent">
|
|
316
|
+
Parallax effect
|
|
317
|
+
</div>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### ASwap integration (required)
|
|
321
|
+
|
|
322
|
+
```javascript
|
|
323
|
+
const aswapEvents = {
|
|
324
|
+
onViewSwapComplete: () => RytmWebflow.showUp.rebuild(),
|
|
325
|
+
onViewHide: () => RytmWebflow.showUp.hide()
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Bootstrap 5 helpers
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
RytmWebflow.bootsrap5.hideFlyovers() // Close all modals + offcanvases
|
|
335
|
+
RytmWebflow.bootsrap5.hideModals() // Close modals only
|
|
336
|
+
RytmWebflow.bootsrap5.hideOffcanvases() // Close offcanvases only
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Note: the export name has a typo (`bootsrap5`, not `bootstrap5`).
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## scrollController
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
RytmWebflow.scrollController.get() // Get/create ScrollMagic.Controller
|
|
347
|
+
RytmWebflow.scrollController.refresh() // Update all scenes
|
|
348
|
+
RytmWebflow.scrollController.destroy() // Clean up
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Common pitfalls
|
|
354
|
+
|
|
355
|
+
1. **ShowUp not updating after page swap** — call `showUp.rebuild()` in `onViewSwapComplete`
|
|
356
|
+
2. **Layout shifts from images** — use `ControllerImgLoad` for image-heavy pages
|
|
357
|
+
3. **Nested view element leaks** — filter with `elementBelongsToView()` when querying elements
|
|
358
|
+
4. **ScrollMagic memory leaks** — WebflowView handles cleanup automatically; manual scenes need explicit `destroy()`
|
|
359
|
+
5. **Bootstrap modals persist on navigation** — call `bootsrap5.hideFlyovers()` in `onViewHide`
|
|
360
|
+
6. **Event listener accumulation** — always clean up in `removeEventListeners()`
|
|
361
|
+
7. **Stagger not working** — requires `data-webset="selector:..."` attribute
|
|
362
|
+
8. **Easing not applied** — use GSAP v3 syntax: `e:power3.out` (not `e:Power3.easeOut`)
|
|
363
|
+
9. **Cache causes stale content** — add `no-as-cache` class to forms or dynamic links
|