fancoolo-fx 1.6.0 → 1.7.0

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/README.md CHANGED
@@ -159,6 +159,16 @@ All functions accept `(element, options)`:
159
159
 
160
160
  Set `trigger: 'scroll'` to enable ScrollTrigger. Pass `scrollTrigger: { trigger: someEl }` to use a different trigger element.
161
161
 
162
+ ### Utility Methods
163
+
164
+ | Method | Description |
165
+ |--------|-------------|
166
+ | `FX.init()` | Re-scan DOM and apply animations (for dynamic content) |
167
+ | `FX.refresh()` | Re-split text after layout change (sidebar toggle, font load) |
168
+ | `FX.config` | Global config object |
169
+
170
+ **Resize handling:** Text-based effects (`textReveal`, `typeWriter`, `splitWords`) automatically re-split when the browser width changes. After one-shot animations complete, the SplitText DOM is reverted so text reflows naturally.
171
+
162
172
  ## Using in a New Project
163
173
 
164
174
  1. Copy this repo (or `npm install`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fancoolo-fx",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "A class-driven GSAP animation wrapper for WordPress and static sites.",
5
5
  "main": "src/fx.js",
6
6
  "homepage": "https://krstivoja.github.io/fancoolo-fx/",
@@ -14,8 +14,8 @@
14
14
  "keywords": ["gsap", "animation", "scrolltrigger", "splittext", "wordpress", "gutenberg"],
15
15
  "author": "Fancoolo",
16
16
  "scripts": {
17
- "sync": "cp src/fx.js assets/fx.js && cp src/fx.js docs/vendor/fx.js",
18
- "build": "wp-scripts build src/editor/index.js --output-path=assets/editor",
17
+ "sync": "cp src/fx.js assets/fx.js && cp src/fx.js docs/vendor/fx.js && cp node_modules/gsap/dist/gsap.min.js assets/gsap.min.js && cp node_modules/gsap/dist/ScrollTrigger.min.js assets/ScrollTrigger.min.js && cp node_modules/gsap/dist/SplitText.min.js assets/SplitText.min.js && cp node_modules/gsap/dist/gsap.min.js docs/vendor/gsap.min.js && cp node_modules/gsap/dist/ScrollTrigger.min.js docs/vendor/ScrollTrigger.min.js && cp node_modules/gsap/dist/SplitText.min.js docs/vendor/SplitText.min.js",
18
+ "build": "wp-scripts build src/editor/index.js --output-path=assets/editor && npm run sync",
19
19
  "start": "wp-scripts start src/editor/index.js --output-path=assets/editor"
20
20
  },
21
21
  "license": "ISC",
package/readme.txt CHANGED
@@ -68,6 +68,12 @@ Yes. Use the `fx-start-[top center]` modifier class, or set `scrollStart` in the
68
68
 
69
69
  == Changelog ==
70
70
 
71
+ = 1.7.0 =
72
+ * Fix: Text-based effects (textReveal, typeWriter, splitWords) now re-split on browser resize — line breaks stay correct at every viewport width
73
+ * New: SplitText is reverted after one-shot animations complete — text reflows naturally without extra DOM wrappers
74
+ * New: FX.refresh() public method — manually re-split text after layout changes (sidebar toggle, font load)
75
+ * New: Automatic debounced resize handler (200ms, width-only) for pending scroll-triggered text animations
76
+
71
77
  = 1.0.0 =
72
78
  * Initial release
73
79
  * 5 animation effects
package/src/fx.js CHANGED
@@ -157,6 +157,49 @@
157
157
  return st;
158
158
  }
159
159
 
160
+ // ── SplitText resize handling ───────────────
161
+
162
+ var _splitRegistry = [];
163
+ var _lastWidth = window.innerWidth;
164
+ var _resizeTimer;
165
+
166
+ function registerSplit(entry) {
167
+ _splitRegistry.push(entry);
168
+ }
169
+
170
+ function unregisterSplit(entry) {
171
+ var idx = _splitRegistry.indexOf(entry);
172
+ if (idx > -1) _splitRegistry.splice(idx, 1);
173
+ }
174
+
175
+ function refreshSplits() {
176
+ if (_splitRegistry.length === 0) return;
177
+
178
+ var pending = [];
179
+
180
+ for (var i = _splitRegistry.length - 1; i >= 0; i--) {
181
+ var entry = _splitRegistry[i];
182
+ if (entry.tween) entry.tween.kill();
183
+ if (entry.split) entry.split.revert();
184
+ pending.push(entry);
185
+ }
186
+
187
+ _splitRegistry.length = 0;
188
+
189
+ pending.forEach(function (entry) {
190
+ entry.effectFn(entry.el, entry.opts);
191
+ });
192
+
193
+ ScrollTrigger.refresh();
194
+ }
195
+
196
+ window.addEventListener('resize', function () {
197
+ if (window.innerWidth === _lastWidth) return;
198
+ _lastWidth = window.innerWidth;
199
+ clearTimeout(_resizeTimer);
200
+ _resizeTimer = setTimeout(refreshSplits, 200);
201
+ });
202
+
160
203
  // ── Effects ──────────────────────────────────
161
204
 
162
205
  function textReveal(el, opts) {
@@ -172,6 +215,9 @@
172
215
  wrapper.appendChild(line);
173
216
  });
174
217
 
218
+ var isOneShot = !(opts.trigger === 'scroll' || opts.scrollTrigger) || config.scrollOnce;
219
+ var entry = { el: el, split: split, tween: null, effectFn: textReveal, opts: opts };
220
+
175
221
  var tweenVars = {
176
222
  y: '100%',
177
223
  opacity: 0,
@@ -179,19 +225,21 @@
179
225
  ease: o.ease,
180
226
  stagger: o.stagger,
181
227
  delay: o.delay,
182
- onComplete: function () {
183
- split.lines.forEach(function (line) {
184
- line.style.transform = '';
185
- line.style.opacity = '';
186
- });
187
- },
188
228
  };
189
229
 
230
+ if (isOneShot) {
231
+ tweenVars.onComplete = function () {
232
+ split.revert();
233
+ unregisterSplit(entry);
234
+ };
235
+ }
236
+
190
237
  if (opts.trigger === 'scroll' || opts.scrollTrigger) {
191
238
  tweenVars.scrollTrigger = buildScrollTrigger(el, opts.scrollTrigger || {});
192
239
  }
193
240
 
194
- gsap.from(split.lines, tweenVars);
241
+ entry.tween = gsap.from(split.lines, tweenVars);
242
+ registerSplit(entry);
195
243
  }
196
244
 
197
245
  function reveal(el, opts) {
@@ -377,6 +425,9 @@
377
425
  var split = new SplitText(el, { type: 'chars' });
378
426
  gsap.set(split.chars, { opacity: 0 });
379
427
 
428
+ var isOneShot = !(opts.trigger === 'scroll' || opts.scrollTrigger) || config.scrollOnce;
429
+ var entry = { el: el, split: split, tween: null, effectFn: typeWriter, opts: opts };
430
+
380
431
  var tweenVars = {
381
432
  opacity: 1,
382
433
  duration: o.duration,
@@ -385,11 +436,19 @@
385
436
  delay: o.delay,
386
437
  };
387
438
 
439
+ if (isOneShot) {
440
+ tweenVars.onComplete = function () {
441
+ split.revert();
442
+ unregisterSplit(entry);
443
+ };
444
+ }
445
+
388
446
  if (opts.trigger === 'scroll' || opts.scrollTrigger) {
389
447
  tweenVars.scrollTrigger = buildScrollTrigger(el, opts.scrollTrigger || {});
390
448
  }
391
449
 
392
- gsap.to(split.chars, tweenVars);
450
+ entry.tween = gsap.to(split.chars, tweenVars);
451
+ registerSplit(entry);
393
452
  }
394
453
 
395
454
  function drawSVG(el, opts) {
@@ -464,6 +523,9 @@
464
523
 
465
524
  var split = new SplitText(el, { type: 'words' });
466
525
 
526
+ var isOneShot = !(opts.trigger === 'scroll' || opts.scrollTrigger) || config.scrollOnce;
527
+ var entry = { el: el, split: split, tween: null, effectFn: splitWords, opts: opts };
528
+
467
529
  var tweenVars = {
468
530
  y: opts.y != null ? opts.y : 30,
469
531
  opacity: 0,
@@ -473,11 +535,19 @@
473
535
  delay: o.delay,
474
536
  };
475
537
 
538
+ if (isOneShot) {
539
+ tweenVars.onComplete = function () {
540
+ split.revert();
541
+ unregisterSplit(entry);
542
+ };
543
+ }
544
+
476
545
  if (opts.trigger === 'scroll' || opts.scrollTrigger) {
477
546
  tweenVars.scrollTrigger = buildScrollTrigger(el, opts.scrollTrigger || {});
478
547
  }
479
548
 
480
- gsap.from(split.words, tweenVars);
549
+ entry.tween = gsap.from(split.words, tweenVars);
550
+ registerSplit(entry);
481
551
  }
482
552
 
483
553
  function slideIn(el, opts) {
@@ -774,5 +844,6 @@
774
844
  splitWords: splitWords,
775
845
  slideIn: slideIn,
776
846
  init: init,
847
+ refresh: refreshSplits,
777
848
  };
778
849
  })();
package/.distignore DELETED
@@ -1,15 +0,0 @@
1
- src/
2
- docs/
3
- skills/
4
- node_modules/
5
- package.json
6
- package-lock.json
7
- .npmignore
8
- .gitignore
9
- .distignore
10
- .github/
11
- .claude/
12
- .nojekyll
13
- .git/
14
- CLAUDE.md
15
- README.md