rytm-webflow 2.3.0 → 2.3.1

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.
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(git fetch:*)"
4
+ "Bash(git fetch:*)",
5
+ "mcp__metrum__get_task",
6
+ "Bash(git checkout:*)",
7
+ "mcp__metrum__set_subtask_status",
8
+ "Bash(npm run:*)"
5
9
  ]
6
- }
10
+ },
11
+ "enableAllProjectMcpServers": true,
12
+ "enabledMcpjsonServers": [
13
+ "metrum"
14
+ ]
7
15
  }
package/.mcp.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "metrum": {
4
+ "command": "node",
5
+ "args": ["/Users/rk/Sites/metrum.rytm.org/mcp/server.js"]
6
+ }
7
+ }
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rytm-webflow",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "rytm webflow pack - ASwap, ShowUp",
5
5
  "main": "scripts/index.js",
6
6
  "types": "scripts/index.d.ts",
@@ -1,6 +1,10 @@
1
+ import ScrollMagic from 'scrollmagic';
1
2
  import gsap from 'gsap';
2
3
  import View from './View';
4
+ import scrollController from './../showup/ScrollController';
3
5
  import { getWebflowAnimationProps, parseProps } from './../lib/dataTweenParser';
6
+ import { getScrollMagicSceneProps } from './../lib/dataScrollMagicParser';
7
+ import { elementIsVisibleInViewport } from '../lib/helpers';
4
8
  import { CLASS_NAME_WEBSCROLL_FIRED } from './WebflowView';
5
9
 
6
10
  // data-webscroll-... (scroll magic)
@@ -14,6 +18,7 @@ class WebflowListView extends View {
14
18
 
15
19
  constructor(id) {
16
20
  super(id);
21
+ this.scenes = [];
17
22
  }
18
23
  /**
19
24
  * animate in (show)
@@ -25,8 +30,15 @@ class WebflowListView extends View {
25
30
  console.warn("Unknown selector for WebflowListView", this);
26
31
  return;
27
32
  }
28
- const list = [...container.querySelectorAll(this.webset.selector)].filter(this.elementBelongsToView);
29
- list.forEach(this.listElementShow.bind(this));
33
+ const items = [...container.querySelectorAll(this.webset.selector)].filter(this.elementBelongsToView);
34
+ // 1. Set initial state for ALL scroll elements (regardless of viewport)
35
+ this.hideAllScrollElements(items);
36
+ // 2. Stagger-animate in-viewport items (existing behavior)
37
+ items.forEach(this.listElementShow.bind(this));
38
+ // 3. Build ScrollMagic scenes for off-screen items
39
+ this.buildScrollScenesForOffscreenItems(items);
40
+ // 4. Listen for resize to refresh ScrollMagic
41
+ this.addEventListeners();
30
42
  }
31
43
  /**
32
44
  * animate out (hide)
@@ -40,6 +52,16 @@ class WebflowListView extends View {
40
52
  }
41
53
  const list = [...container.querySelectorAll(this.webset.selector)].filter(this.elementBelongsToView);
42
54
  list.forEach(this.listElementHide.bind(this));
55
+ // Also hide off-screen scroll elements that have ScrollMagic scenes
56
+ this.hideOffscreenScrollElements(container);
57
+ }
58
+ /**
59
+ * hidden (cleanup after hide animation)
60
+ **/
61
+ hidden(container) {
62
+ super.hidden(container);
63
+ this.removeEventListeners();
64
+ this.destroyScenes();
43
65
  }
44
66
  /**
45
67
  * ############
@@ -106,6 +128,122 @@ class WebflowListView extends View {
106
128
  });
107
129
  }
108
130
  }
131
+ /**
132
+ * ##################
133
+ * ### DOM events ###
134
+ * ##################
135
+ */
136
+ handleEvent(e) {
137
+ switch (e.type) {
138
+ case 'resize':
139
+ case 'DOMContentLoaded':
140
+ this.onWindowUpdate();
141
+ break;
142
+ }
143
+ }
144
+ addEventListeners() {
145
+ window.addEventListener('resize', this);
146
+ document.addEventListener('DOMContentLoaded', this);
147
+ }
148
+ removeEventListeners() {
149
+ window.removeEventListener('resize', this);
150
+ document.removeEventListener('DOMContentLoaded', this);
151
+ }
152
+ onWindowUpdate() {
153
+ if (this.scenes.length > 0) {
154
+ scrollController.refresh();
155
+ }
156
+ }
157
+ /**
158
+ * #####################
159
+ * ### SCROLL SCENES ###
160
+ * #####################
161
+ */
162
+ // set initial state for all scroll elements in list items
163
+ hideAllScrollElements(items) {
164
+ items.forEach((el) => {
165
+ const scrollEls = [...el.querySelectorAll('*[data-' + DATA_ATTR_WEBSCROLL_SHOW + ']')]
166
+ .filter(this.elementBelongsToView);
167
+ scrollEls.forEach((scrollEl) => {
168
+ const propsInitial = this.getTweenProps(scrollEl, DATA_ATTR_WEBSCROLL_INIT);
169
+ if (propsInitial) {
170
+ gsap.killTweensOf(scrollEl);
171
+ gsap.set(scrollEl, { ...propsInitial.tween });
172
+ }
173
+ });
174
+ });
175
+ }
176
+ // build ScrollMagic scenes for off-screen list items
177
+ buildScrollScenesForOffscreenItems(items) {
178
+ items.forEach((el) => {
179
+ if (this.isElementInViewport(el)) return;
180
+ const scrollEls = [...el.querySelectorAll('*[data-' + DATA_ATTR_WEBSCROLL_SHOW + ']')]
181
+ .filter(this.elementBelongsToView);
182
+ scrollEls.forEach((scrollEl) => {
183
+ this.buildScrollmagicScene(scrollEl);
184
+ });
185
+ });
186
+ }
187
+ // build a single ScrollMagic scene for a scroll element
188
+ buildScrollmagicScene(el) {
189
+ const propsInitial = this.getTweenProps(el, DATA_ATTR_WEBSCROLL_INIT);
190
+ const propsShow = this.getTweenProps(el, DATA_ATTR_WEBSCROLL_SHOW);
191
+ const setup = parseProps(el.dataset[DATA_ATTR_SETUP] || '');
192
+ if (propsInitial && propsShow) {
193
+ const smsp = getScrollMagicSceneProps(el, setup);
194
+ const scene = new ScrollMagic.Scene(smsp);
195
+ scene.on("start", (e) => {
196
+ if (el.classList.contains(CLASS_NAME_WEBSCROLL_FIRED)) return;
197
+ if (e.scrollDirection === "FORWARD") {
198
+ gsap.killTweensOf(el);
199
+ gsap.set(el, { ...propsInitial.tween });
200
+ gsap.to(el, {
201
+ duration: propsShow.time,
202
+ ...propsShow.tween,
203
+ onComplete: () => {
204
+ el.classList.add(CLASS_NAME_WEBSCROLL_FIRED);
205
+ }
206
+ });
207
+ }
208
+ });
209
+ scene.on("add", () => {
210
+ setTimeout(() => {
211
+ if (elementIsVisibleInViewport(el, true)) {
212
+ gsap.to(el, {
213
+ duration: propsShow.time,
214
+ ...propsShow.tween,
215
+ onComplete: () => {
216
+ el.classList.add(CLASS_NAME_WEBSCROLL_FIRED);
217
+ }
218
+ });
219
+ }
220
+ }, 10);
221
+ });
222
+ scene.addTo(scrollController.get());
223
+ this.scenes.push(scene);
224
+ }
225
+ }
226
+ // hide off-screen scroll elements during view hide
227
+ hideOffscreenScrollElements(container) {
228
+ const scrollEls = [...container.querySelectorAll('*[data-' + DATA_ATTR_WEBSCROLL_HIDE + ']')]
229
+ .filter(this.elementBelongsToView);
230
+ scrollEls.forEach((el) => {
231
+ if (this.isElementInViewport(el.closest(this.webset.selector))) return;
232
+ const propsHide = this.getTweenProps(el, DATA_ATTR_WEBSCROLL_HIDE);
233
+ if (propsHide) {
234
+ gsap.killTweensOf(el);
235
+ gsap.to(el, { duration: propsHide.time, ...propsHide.tween });
236
+ }
237
+ });
238
+ }
239
+ // destroy all ScrollMagic scenes
240
+ destroyScenes() {
241
+ this.scenes.forEach((scene) => {
242
+ scene.destroy();
243
+ scene = null;
244
+ });
245
+ this.scenes = [];
246
+ }
109
247
  /**
110
248
  * ###############
111
249
  * ### HELPERS ###