fancoolo-fx 1.7.1 → 1.8.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/CHANGELOG.md +74 -0
- package/package.json +1 -1
- package/readme.txt +15 -0
- package/src/fx.js +133 -132
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Fancoolo FX — Changelog
|
|
2
|
+
|
|
3
|
+
## 1.8.3
|
|
4
|
+
_(current release)_
|
|
5
|
+
|
|
6
|
+
## 1.8.2
|
|
7
|
+
- **Fix:** `textReveal` now detects containers with block-level children (divs, sections, forms) and only splits text-bearing elements (h1–h6, p, blockquote, etc.) — prevents breakage of interactive widgets like accordions, tabs, and sliders
|
|
8
|
+
|
|
9
|
+
## 1.8.1
|
|
10
|
+
- **Fix:** Removed `split.revert()` calls from `textReveal`, `typeWriter`, and `splitWords` — revert destroys JS state (event listeners, injected DOM) added after SplitText ran
|
|
11
|
+
- **Fix:** `textReveal` resize re-splitting fully handled by `autoSplit`, no manual revert needed
|
|
12
|
+
|
|
13
|
+
## 1.8.0
|
|
14
|
+
- **Refactor:** `textReveal` uses native SplitText `autoSplit`, `mask: "lines"`, and `onSplit` — removes manual overflow wrappers and resize handler
|
|
15
|
+
- **Refactor:** Responsive and reduced-motion handling via `gsap.matchMedia()` — animations auto-revert when conditions change
|
|
16
|
+
- **Refactor:** Idempotent `init()` using persistent WeakSet — safe to call multiple times without double-animating
|
|
17
|
+
- **Refactor:** Scrub effects (`tiltIn`, `parallax`, `drawSVG` scrub) routed through `buildScrollTrigger()` — now support debug markers and `fx-start-[...]` overrides
|
|
18
|
+
- **Removed:** Manual resize listener, `_splitRegistry`, `document.fonts.ready` blocking — all handled natively by GSAP
|
|
19
|
+
- **Enhancement:** `FX.refresh()` simplified to `ScrollTrigger.refresh()`
|
|
20
|
+
|
|
21
|
+
## 1.7.1
|
|
22
|
+
- **Fix:** FOUC prevention — all effects now use `autoAlpha` instead of `opacity`; elements start with `visibility:hidden` and are revealed by GSAP
|
|
23
|
+
- **New:** WordPress plugin injects `visibility:hidden` CSS automatically in the head
|
|
24
|
+
- **New:** Text-based effects set parent visibility before animating children to prevent flash
|
|
25
|
+
- **Enhancement:** `clipUp`/`clipDown` now include `autoAlpha` for consistent FOUC handling
|
|
26
|
+
|
|
27
|
+
## 1.7.0
|
|
28
|
+
- **Fix:** Text-based effects (`textReveal`, `typeWriter`, `splitWords`) now re-split on browser resize — line breaks stay correct at every viewport width
|
|
29
|
+
- **New:** SplitText is reverted after one-shot animations complete — text reflows naturally without extra DOM wrappers
|
|
30
|
+
- **New:** `FX.refresh()` public method — manually re-split text after layout changes (sidebar toggle, font load)
|
|
31
|
+
- **New:** Automatic debounced resize handler (200ms, width-only) for pending scroll-triggered text animations
|
|
32
|
+
|
|
33
|
+
## 1.6.1
|
|
34
|
+
- **Refactor:** Split plugin into namespaced classes under `inc/` with `FancooloFX` namespace
|
|
35
|
+
- `Settings.php`, `Frontend.php`, `Editor.php`, `Admin.php`, `AdminPage.php`, `SaveHandler.php`
|
|
36
|
+
- **New:** Integrated dPlugins self-hoster update checker
|
|
37
|
+
- Updated release workflow to use `rsync` + `.distignore` pattern
|
|
38
|
+
|
|
39
|
+
## 1.6.0
|
|
40
|
+
- **New:** Gutenberg inspector panel — "FX Animation" added to every block's sidebar
|
|
41
|
+
- Effect dropdown with all 15 effects
|
|
42
|
+
- Trigger toggle: Item (scroll) / Trigger (section) / Page (load)
|
|
43
|
+
- Duration, delay, ease, start position modifiers
|
|
44
|
+
- Parallax Y-shift and `drawSVG` scrub options
|
|
45
|
+
- Copy/Paste FX between blocks (sidebar + context menu)
|
|
46
|
+
- **New:** Gutenberg integration toggle in plugin settings
|
|
47
|
+
- Build workflow updated to compile editor assets on release
|
|
48
|
+
|
|
49
|
+
## 1.5.0
|
|
50
|
+
- **New:** 5 additional animation effects (fade-in, blur-in, clip-up, clip-down, slide-left/right, draw-svg, parallax, split-words, type-writer, tilt-in)
|
|
51
|
+
- **New:** Plugin settings page with import/export
|
|
52
|
+
|
|
53
|
+
## 1.3.0
|
|
54
|
+
- **New:** Settings sidebar in the editor tab
|
|
55
|
+
|
|
56
|
+
## 1.2.0
|
|
57
|
+
- **New:** `tiltIn` 3D perspective effect (scrub-based)
|
|
58
|
+
|
|
59
|
+
## 1.1.0
|
|
60
|
+
- **Fix:** Syntax error — `stagger-all` block was outside `init()`
|
|
61
|
+
|
|
62
|
+
## 1.0.2
|
|
63
|
+
- **Fix:** `-st` scroll trigger
|
|
64
|
+
|
|
65
|
+
## 1.0.1
|
|
66
|
+
- Version bump
|
|
67
|
+
|
|
68
|
+
## 1.0.0
|
|
69
|
+
- Initial release
|
|
70
|
+
- 5 animation effects (text-reveal, reveal, spin-reveal, bg-reveal, scale-in)
|
|
71
|
+
- Page load, scroll trigger, and section trigger modes
|
|
72
|
+
- Modifier classes for timing overrides
|
|
73
|
+
- Custom JavaScript editor with CodeMirror
|
|
74
|
+
- Built-in quick reference table
|
package/package.json
CHANGED
package/readme.txt
CHANGED
|
@@ -68,6 +68,21 @@ Yes. Use the `fx-start-[top center]` modifier class, or set `scrollStart` in the
|
|
|
68
68
|
|
|
69
69
|
== Changelog ==
|
|
70
70
|
|
|
71
|
+
= 1.8.2 =
|
|
72
|
+
* Fix: textReveal now detects containers with block-level children (divs, sections, forms) and only splits text-bearing elements (h1-h6, p, blockquote, etc.) — prevents breakage of interactive widgets like accordions, tabs, and sliders
|
|
73
|
+
|
|
74
|
+
= 1.8.1 =
|
|
75
|
+
* Fix: Removed split.revert() calls from textReveal, typeWriter, and splitWords — revert destroys JS state (event listeners, injected DOM) added after SplitText ran
|
|
76
|
+
* Fix: textReveal resize re-splitting fully handled by autoSplit, no manual revert needed
|
|
77
|
+
|
|
78
|
+
= 1.8.0 =
|
|
79
|
+
* Refactor: textReveal uses native SplitText `autoSplit`, `mask: "lines"`, and `onSplit` — removes manual overflow wrappers and resize handler
|
|
80
|
+
* Refactor: Responsive and reduced-motion handling via `gsap.matchMedia()` — animations auto-revert when conditions change
|
|
81
|
+
* Refactor: Idempotent `init()` using persistent WeakSet — safe to call multiple times without double-animating
|
|
82
|
+
* Refactor: Scrub effects (tiltIn, parallax, drawSVG scrub) routed through `buildScrollTrigger()` — now support debug markers and `fx-start-[...]` overrides
|
|
83
|
+
* Removed: Manual resize listener, `_splitRegistry`, `document.fonts.ready` blocking — all handled natively by GSAP
|
|
84
|
+
* Enhancement: `FX.refresh()` simplified to `ScrollTrigger.refresh()`
|
|
85
|
+
|
|
71
86
|
= 1.7.1 =
|
|
72
87
|
* Fix: FOUC prevention — all effects now use autoAlpha instead of opacity, elements start with visibility:hidden and are revealed by GSAP
|
|
73
88
|
* New: WordPress plugin injects visibility:hidden CSS automatically in the head
|
package/src/fx.js
CHANGED
|
@@ -109,6 +109,11 @@
|
|
|
109
109
|
slideIn: { duration: 1, ease: 'power3.out' },
|
|
110
110
|
};
|
|
111
111
|
|
|
112
|
+
// ── State ───────────────────────────────────
|
|
113
|
+
|
|
114
|
+
var _animated = new WeakSet();
|
|
115
|
+
var _mm = gsap.matchMedia();
|
|
116
|
+
|
|
112
117
|
// ── Helpers ──────────────────────────────────
|
|
113
118
|
|
|
114
119
|
function getClassModifier(el, name, fallback) {
|
|
@@ -157,90 +162,85 @@
|
|
|
157
162
|
return st;
|
|
158
163
|
}
|
|
159
164
|
|
|
160
|
-
// ──
|
|
161
|
-
|
|
162
|
-
var _splitRegistry = [];
|
|
163
|
-
var _lastWidth = window.innerWidth;
|
|
164
|
-
var _resizeTimer;
|
|
165
|
-
|
|
166
|
-
function registerSplit(entry) {
|
|
167
|
-
_splitRegistry.push(entry);
|
|
168
|
-
}
|
|
165
|
+
// ── Effects ──────────────────────────────────
|
|
169
166
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
167
|
+
// Exclude an element from TranslatePress's dynamic (DOM-change) re-translation.
|
|
168
|
+
// SplitText restructures text into line/word/char spans; TranslatePress's
|
|
169
|
+
// MutationObserver (trp-translate-dom-changes.js) sees those mutations and
|
|
170
|
+
// re-translates the fragments, racing with SplitText and flickering the text
|
|
171
|
+
// between languages. The server already renders the translated text, so the
|
|
172
|
+
// dynamic pass is redundant here. `data-no-dynamic-translation` is in
|
|
173
|
+
// TranslatePress's own skip-selector list; it's an inert data attribute when
|
|
174
|
+
// TranslatePress isn't present.
|
|
175
|
+
function markNoDynamicTranslation(el) {
|
|
176
|
+
if (el && el.setAttribute) {
|
|
177
|
+
el.setAttribute('data-no-dynamic-translation', '');
|
|
178
|
+
}
|
|
173
179
|
}
|
|
174
180
|
|
|
175
|
-
function
|
|
176
|
-
|
|
181
|
+
function splitTextReveal(target, o, isScroll, triggerEl, opts) {
|
|
182
|
+
markNoDynamicTranslation(target);
|
|
183
|
+
SplitText.create(target, {
|
|
184
|
+
type: 'lines',
|
|
185
|
+
mask: 'lines',
|
|
186
|
+
autoSplit: true,
|
|
187
|
+
onSplit: function (self) {
|
|
188
|
+
var tweenVars = {
|
|
189
|
+
y: '100%',
|
|
190
|
+
autoAlpha: 0,
|
|
191
|
+
duration: o.duration,
|
|
192
|
+
ease: o.ease,
|
|
193
|
+
stagger: o.stagger,
|
|
194
|
+
delay: o.delay,
|
|
195
|
+
};
|
|
177
196
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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;
|
|
197
|
+
if (isScroll) {
|
|
198
|
+
tweenVars.scrollTrigger = buildScrollTrigger(triggerEl, opts.scrollTrigger || {});
|
|
199
|
+
}
|
|
188
200
|
|
|
189
|
-
|
|
190
|
-
|
|
201
|
+
return gsap.from(self.lines, tweenVars);
|
|
202
|
+
},
|
|
191
203
|
});
|
|
192
|
-
|
|
193
|
-
ScrollTrigger.refresh();
|
|
194
204
|
}
|
|
195
205
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// ── Effects ──────────────────────────────────
|
|
206
|
+
// Block-level tags whose presence signals a container with interactive children.
|
|
207
|
+
// When these are found as direct children, SplitText is applied only to
|
|
208
|
+
// text-bearing siblings to avoid restructuring interactive widgets.
|
|
209
|
+
var CONTAINER_CHILD_TAGS = /^(DIV|SECTION|ARTICLE|ASIDE|NAV|HEADER|FOOTER|MAIN|FORM|TABLE|DETAILS|FIELDSET)$/;
|
|
210
|
+
var TEXT_CHILD_TAGS = /^(H[1-6]|P|BLOCKQUOTE|FIGCAPTION|PRE|LABEL)$/;
|
|
204
211
|
|
|
205
212
|
function textReveal(el, opts) {
|
|
206
213
|
opts = opts || {};
|
|
207
214
|
var o = resolveOptions(el, 'textReveal', opts);
|
|
215
|
+
var isScroll = opts.trigger === 'scroll' || opts.scrollTrigger;
|
|
208
216
|
|
|
209
217
|
gsap.set(el, { visibility: 'inherit' });
|
|
210
|
-
var split = new SplitText(el, { type: 'lines', linesClass: 'line-wrapper' });
|
|
211
|
-
|
|
212
|
-
split.lines.forEach(function (line) {
|
|
213
|
-
var wrapper = document.createElement('div');
|
|
214
|
-
wrapper.style.overflow = 'hidden';
|
|
215
|
-
line.parentNode.insertBefore(wrapper, line);
|
|
216
|
-
wrapper.appendChild(line);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
var isOneShot = !(opts.trigger === 'scroll' || opts.scrollTrigger) || config.scrollOnce;
|
|
220
|
-
var entry = { el: el, split: split, tween: null, effectFn: textReveal, opts: opts };
|
|
221
|
-
|
|
222
|
-
var tweenVars = {
|
|
223
|
-
y: '100%',
|
|
224
|
-
autoAlpha: 0,
|
|
225
|
-
duration: o.duration,
|
|
226
|
-
ease: o.ease,
|
|
227
|
-
stagger: o.stagger,
|
|
228
|
-
delay: o.delay,
|
|
229
|
-
};
|
|
230
218
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
219
|
+
// If the element contains block-level children (divs, sections, etc.),
|
|
220
|
+
// only split text-bearing children to avoid breaking interactive widgets
|
|
221
|
+
// like accordions, tabs, or sliders inside the same container.
|
|
222
|
+
var hasBlockChild = false;
|
|
223
|
+
for (var c = 0; c < el.children.length; c++) {
|
|
224
|
+
if (CONTAINER_CHILD_TAGS.test(el.children[c].tagName)) {
|
|
225
|
+
hasBlockChild = true;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
236
228
|
}
|
|
237
229
|
|
|
238
|
-
if (
|
|
239
|
-
|
|
230
|
+
if (hasBlockChild) {
|
|
231
|
+
var targets = [];
|
|
232
|
+
for (var t = 0; t < el.children.length; t++) {
|
|
233
|
+
if (TEXT_CHILD_TAGS.test(el.children[t].tagName)) {
|
|
234
|
+
targets.push(el.children[t]);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
targets.forEach(function (textEl) {
|
|
238
|
+
splitTextReveal(textEl, o, isScroll, el, opts);
|
|
239
|
+
});
|
|
240
|
+
return;
|
|
240
241
|
}
|
|
241
242
|
|
|
242
|
-
|
|
243
|
-
registerSplit(entry);
|
|
243
|
+
splitTextReveal(el, o, isScroll, el, opts);
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
function reveal(el, opts) {
|
|
@@ -400,6 +400,11 @@
|
|
|
400
400
|
opts = opts || {};
|
|
401
401
|
var o = resolveOptions(el, 'tiltIn', opts);
|
|
402
402
|
|
|
403
|
+
var st = buildScrollTrigger(el, opts.scrollTrigger || {});
|
|
404
|
+
st.end = opts.end || 'top 20%';
|
|
405
|
+
st.scrub = opts.scrub != null ? opts.scrub : 0.6;
|
|
406
|
+
delete st.once;
|
|
407
|
+
|
|
403
408
|
gsap.fromTo(el, {
|
|
404
409
|
rotationX: opts.rotationX != null ? opts.rotationX : 45,
|
|
405
410
|
scale: opts.scale != null ? opts.scale : 0.8,
|
|
@@ -412,12 +417,7 @@
|
|
|
412
417
|
autoAlpha: 1,
|
|
413
418
|
transformPerspective: 1000,
|
|
414
419
|
ease: o.ease,
|
|
415
|
-
scrollTrigger:
|
|
416
|
-
trigger: (opts.scrollTrigger && opts.scrollTrigger.trigger) || el,
|
|
417
|
-
start: config.scrollStart || 'top 85%',
|
|
418
|
-
end: opts.end || 'top 20%',
|
|
419
|
-
scrub: opts.scrub != null ? opts.scrub : 0.6,
|
|
420
|
-
},
|
|
420
|
+
scrollTrigger: st,
|
|
421
421
|
});
|
|
422
422
|
}
|
|
423
423
|
|
|
@@ -426,12 +426,10 @@
|
|
|
426
426
|
var o = resolveOptions(el, 'typeWriter', opts);
|
|
427
427
|
|
|
428
428
|
gsap.set(el, { visibility: 'inherit' });
|
|
429
|
+
markNoDynamicTranslation(el);
|
|
429
430
|
var split = new SplitText(el, { type: 'chars' });
|
|
430
431
|
gsap.set(split.chars, { autoAlpha: 0 });
|
|
431
432
|
|
|
432
|
-
var isOneShot = !(opts.trigger === 'scroll' || opts.scrollTrigger) || config.scrollOnce;
|
|
433
|
-
var entry = { el: el, split: split, tween: null, effectFn: typeWriter, opts: opts };
|
|
434
|
-
|
|
435
433
|
var tweenVars = {
|
|
436
434
|
autoAlpha: 1,
|
|
437
435
|
duration: o.duration,
|
|
@@ -440,19 +438,11 @@
|
|
|
440
438
|
delay: o.delay,
|
|
441
439
|
};
|
|
442
440
|
|
|
443
|
-
if (isOneShot) {
|
|
444
|
-
tweenVars.onComplete = function () {
|
|
445
|
-
split.revert();
|
|
446
|
-
unregisterSplit(entry);
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
|
|
450
441
|
if (opts.trigger === 'scroll' || opts.scrollTrigger) {
|
|
451
442
|
tweenVars.scrollTrigger = buildScrollTrigger(el, opts.scrollTrigger || {});
|
|
452
443
|
}
|
|
453
444
|
|
|
454
|
-
|
|
455
|
-
registerSplit(entry);
|
|
445
|
+
gsap.to(split.chars, tweenVars);
|
|
456
446
|
}
|
|
457
447
|
|
|
458
448
|
function drawSVG(el, opts) {
|
|
@@ -476,15 +466,15 @@
|
|
|
476
466
|
// Scrub mode: SVG draws as user scrolls (class fx-scrub-[0.6] or opts.scrub)
|
|
477
467
|
var scrubVal = getClassModifier(el, 'scrub', opts.scrub != null ? opts.scrub : null);
|
|
478
468
|
if (scrubVal !== null) {
|
|
469
|
+
var st = buildScrollTrigger(el, opts.scrollTrigger || {});
|
|
470
|
+
st.end = opts.end || 'top 20%';
|
|
471
|
+
st.scrub = scrubVal === true || scrubVal === 'true' ? true : scrubVal;
|
|
472
|
+
delete st.once;
|
|
473
|
+
|
|
479
474
|
gsap.to(paths, {
|
|
480
475
|
strokeDashoffset: 0,
|
|
481
476
|
ease: o.ease,
|
|
482
|
-
scrollTrigger:
|
|
483
|
-
trigger: (opts.scrollTrigger && opts.scrollTrigger.trigger) || el,
|
|
484
|
-
start: config.scrollStart || 'top 85%',
|
|
485
|
-
end: opts.end || 'top 20%',
|
|
486
|
-
scrub: scrubVal === true || scrubVal === 'true' ? true : scrubVal,
|
|
487
|
-
},
|
|
477
|
+
scrollTrigger: st,
|
|
488
478
|
});
|
|
489
479
|
return;
|
|
490
480
|
}
|
|
@@ -508,17 +498,17 @@
|
|
|
508
498
|
// Read y from modifier class fx-y-[80] or opts or default 50
|
|
509
499
|
var yShift = getClassModifier(el, 'y', opts.y != null ? opts.y : 50);
|
|
510
500
|
|
|
501
|
+
var st = buildScrollTrigger(el, opts.scrollTrigger || {});
|
|
502
|
+
st.end = opts.end || 'bottom top';
|
|
503
|
+
st.scrub = opts.scrub != null ? opts.scrub : true;
|
|
504
|
+
delete st.once;
|
|
505
|
+
|
|
511
506
|
gsap.fromTo(el, {
|
|
512
507
|
y: -yShift,
|
|
513
508
|
}, {
|
|
514
509
|
y: yShift,
|
|
515
510
|
ease: 'none',
|
|
516
|
-
scrollTrigger:
|
|
517
|
-
trigger: (opts.scrollTrigger && opts.scrollTrigger.trigger) || el,
|
|
518
|
-
start: config.scrollStart || 'top 85%',
|
|
519
|
-
end: opts.end || 'bottom top',
|
|
520
|
-
scrub: opts.scrub != null ? opts.scrub : true,
|
|
521
|
-
},
|
|
511
|
+
scrollTrigger: st,
|
|
522
512
|
});
|
|
523
513
|
}
|
|
524
514
|
|
|
@@ -527,11 +517,9 @@
|
|
|
527
517
|
var o = resolveOptions(el, 'splitWords', opts);
|
|
528
518
|
|
|
529
519
|
gsap.set(el, { visibility: 'inherit' });
|
|
520
|
+
markNoDynamicTranslation(el);
|
|
530
521
|
var split = new SplitText(el, { type: 'words' });
|
|
531
522
|
|
|
532
|
-
var isOneShot = !(opts.trigger === 'scroll' || opts.scrollTrigger) || config.scrollOnce;
|
|
533
|
-
var entry = { el: el, split: split, tween: null, effectFn: splitWords, opts: opts };
|
|
534
|
-
|
|
535
523
|
var tweenVars = {
|
|
536
524
|
y: opts.y != null ? opts.y : 30,
|
|
537
525
|
autoAlpha: 0,
|
|
@@ -541,19 +529,11 @@
|
|
|
541
529
|
delay: o.delay,
|
|
542
530
|
};
|
|
543
531
|
|
|
544
|
-
if (isOneShot) {
|
|
545
|
-
tweenVars.onComplete = function () {
|
|
546
|
-
split.revert();
|
|
547
|
-
unregisterSplit(entry);
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
|
|
551
532
|
if (opts.trigger === 'scroll' || opts.scrollTrigger) {
|
|
552
533
|
tweenVars.scrollTrigger = buildScrollTrigger(el, opts.scrollTrigger || {});
|
|
553
534
|
}
|
|
554
535
|
|
|
555
|
-
|
|
556
|
-
registerSplit(entry);
|
|
536
|
+
gsap.from(split.words, tweenVars);
|
|
557
537
|
}
|
|
558
538
|
|
|
559
539
|
function slideIn(el, opts) {
|
|
@@ -650,7 +630,6 @@
|
|
|
650
630
|
// ── Init ────────────────────────────────────
|
|
651
631
|
|
|
652
632
|
function init() {
|
|
653
|
-
var processed = new Set();
|
|
654
633
|
|
|
655
634
|
Object.keys(effects).forEach(function (name) {
|
|
656
635
|
var fn = effects[name];
|
|
@@ -660,8 +639,9 @@
|
|
|
660
639
|
plGroups.forEach(function (group) {
|
|
661
640
|
group = group.filter(function (el) { return !isExcluded(el); });
|
|
662
641
|
group.forEach(function (el, i) {
|
|
642
|
+
if (_animated.has(el)) return;
|
|
663
643
|
fn(el, { delay: i * 0.15 });
|
|
664
|
-
|
|
644
|
+
_animated.add(el);
|
|
665
645
|
});
|
|
666
646
|
});
|
|
667
647
|
|
|
@@ -673,12 +653,13 @@
|
|
|
673
653
|
stGroups.forEach(function (group) {
|
|
674
654
|
group = group.filter(function (el) { return !isExcluded(el); });
|
|
675
655
|
group.forEach(function (el, i) {
|
|
656
|
+
if (_animated.has(el)) return;
|
|
676
657
|
fn(el, {
|
|
677
658
|
trigger: 'scroll',
|
|
678
659
|
delay: i * 0.15,
|
|
679
660
|
scrollTrigger: { trigger: el },
|
|
680
661
|
});
|
|
681
|
-
|
|
662
|
+
_animated.add(el);
|
|
682
663
|
});
|
|
683
664
|
});
|
|
684
665
|
|
|
@@ -688,18 +669,19 @@
|
|
|
688
669
|
if (config.sectionSelector) {
|
|
689
670
|
document.querySelectorAll(config.sectionSelector).forEach(function (section) {
|
|
690
671
|
var bareEls = Array.from(section.querySelectorAll('.' + name))
|
|
691
|
-
.filter(function (el) { return !
|
|
672
|
+
.filter(function (el) { return !_animated.has(el) && !isExcluded(el); });
|
|
692
673
|
if (bareEls.length === 0) return;
|
|
693
674
|
|
|
694
675
|
var groups = groupByParent(bareEls);
|
|
695
676
|
groups.forEach(function (group) {
|
|
696
677
|
group.forEach(function (el, i) {
|
|
678
|
+
if (_animated.has(el)) return;
|
|
697
679
|
fn(el, {
|
|
698
680
|
trigger: 'scroll',
|
|
699
681
|
delay: i * 0.15,
|
|
700
682
|
scrollTrigger: { trigger: el },
|
|
701
683
|
});
|
|
702
|
-
|
|
684
|
+
_animated.add(el);
|
|
703
685
|
});
|
|
704
686
|
});
|
|
705
687
|
});
|
|
@@ -708,21 +690,21 @@
|
|
|
708
690
|
|
|
709
691
|
// 4. Scrub-based effects — always scroll-linked, processed before tagMap.
|
|
710
692
|
document.querySelectorAll('.fx-tilt-in-st, .fx-tilt-in-pl, .fx-tilt-in').forEach(function (el) {
|
|
711
|
-
if (!
|
|
693
|
+
if (!_animated.has(el) && !isExcluded(el)) {
|
|
712
694
|
tiltIn(el);
|
|
713
|
-
|
|
695
|
+
_animated.add(el);
|
|
714
696
|
}
|
|
715
697
|
});
|
|
716
698
|
document.querySelectorAll('.fx-parallax-st, .fx-parallax-pl, .fx-parallax').forEach(function (el) {
|
|
717
|
-
if (!
|
|
699
|
+
if (!_animated.has(el) && !isExcluded(el)) {
|
|
718
700
|
parallax(el);
|
|
719
|
-
|
|
701
|
+
_animated.add(el);
|
|
720
702
|
}
|
|
721
703
|
});
|
|
722
704
|
document.querySelectorAll('.fx-draw-svg-scrub').forEach(function (el) {
|
|
723
|
-
if (!
|
|
705
|
+
if (!_animated.has(el) && !isExcluded(el)) {
|
|
724
706
|
drawSVG(el, { scrub: getClassModifier(el, 'scrub', 0.6) });
|
|
725
|
-
|
|
707
|
+
_animated.add(el);
|
|
726
708
|
}
|
|
727
709
|
});
|
|
728
710
|
|
|
@@ -735,18 +717,19 @@
|
|
|
735
717
|
if (!fn) return;
|
|
736
718
|
|
|
737
719
|
var els = Array.from(section.querySelectorAll(selector))
|
|
738
|
-
.filter(function (el) { return !
|
|
720
|
+
.filter(function (el) { return !_animated.has(el) && !isExcluded(el); });
|
|
739
721
|
if (els.length === 0) return;
|
|
740
722
|
|
|
741
723
|
var groups = groupByParent(els);
|
|
742
724
|
groups.forEach(function (group) {
|
|
743
725
|
applyScrollGroup(fn, group, section);
|
|
744
|
-
group.forEach(function (el) {
|
|
726
|
+
group.forEach(function (el) { _animated.add(el); });
|
|
745
727
|
});
|
|
746
728
|
});
|
|
747
729
|
});
|
|
748
730
|
}
|
|
749
|
-
|
|
731
|
+
|
|
732
|
+
// 6. fx-stagger-all-[selector] — target children, effect from sibling class
|
|
750
733
|
// Requires an effect class on the same element (e.g. fx-reveal-st).
|
|
751
734
|
document.querySelectorAll('[class*="fx-stagger-all-"]').forEach(function (container) {
|
|
752
735
|
// Parse selector from fx-stagger-all-[img,p]
|
|
@@ -776,7 +759,7 @@
|
|
|
776
759
|
var isScroll = container.classList.contains(effectName + '-st') ||
|
|
777
760
|
container.classList.contains(effectName);
|
|
778
761
|
var children = Array.from(container.querySelectorAll(childSelector))
|
|
779
|
-
.filter(function (el) { return !
|
|
762
|
+
.filter(function (el) { return !_animated.has(el); });
|
|
780
763
|
if (children.length === 0) return;
|
|
781
764
|
|
|
782
765
|
children.forEach(function (child, i) {
|
|
@@ -786,7 +769,7 @@
|
|
|
786
769
|
opts.scrollTrigger = { trigger: child };
|
|
787
770
|
}
|
|
788
771
|
effectFn(child, opts);
|
|
789
|
-
|
|
772
|
+
_animated.add(child);
|
|
790
773
|
});
|
|
791
774
|
});
|
|
792
775
|
|
|
@@ -808,20 +791,38 @@
|
|
|
808
791
|
if (pre.excludeSelectors !== undefined) config.excludeSelectors = pre.excludeSelectors;
|
|
809
792
|
}
|
|
810
793
|
|
|
794
|
+
// Detect the TranslatePress translation editor. It loads the page inside an
|
|
795
|
+
// iframe with a `trp-edit-translation` URL param. FX must stand down there:
|
|
796
|
+
// SplitText fragments text into spans (the real string survives only in
|
|
797
|
+
// aria-label), and its autoSplit ResizeObserver fights TranslatePress's DOM
|
|
798
|
+
// rewriting — producing an endless re-split flicker and untranslatable blocks.
|
|
799
|
+
function isTranslationEditor() {
|
|
800
|
+
try {
|
|
801
|
+
return /[?&]trp-edit-translation=/.test(window.location.search);
|
|
802
|
+
} catch (e) {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
811
807
|
function boot() {
|
|
808
|
+
if (isTranslationEditor()) return;
|
|
809
|
+
|
|
812
810
|
applyPreConfig();
|
|
813
811
|
|
|
814
|
-
//
|
|
815
|
-
|
|
816
|
-
|
|
812
|
+
// Build media query from config — animations auto-revert when conditions stop matching
|
|
813
|
+
var parts = [];
|
|
814
|
+
if (config.disableMobile) {
|
|
815
|
+
parts.push('(min-width: ' + (config.mobileBreakpoint + 1) + 'px)');
|
|
817
816
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
if (config.disableMobile && window.innerWidth <= config.mobileBreakpoint) {
|
|
821
|
-
return;
|
|
817
|
+
if (config.respectReducedMotion) {
|
|
818
|
+
parts.push('(prefers-reduced-motion: no-preference)');
|
|
822
819
|
}
|
|
820
|
+
var conditions = parts.length > 0 ? parts.join(' and ') : 'all';
|
|
823
821
|
|
|
824
|
-
|
|
822
|
+
_mm.add(conditions, function () {
|
|
823
|
+
_animated = new WeakSet();
|
|
824
|
+
init();
|
|
825
|
+
});
|
|
825
826
|
}
|
|
826
827
|
|
|
827
828
|
if (document.readyState === 'loading') {
|
|
@@ -850,6 +851,6 @@
|
|
|
850
851
|
splitWords: splitWords,
|
|
851
852
|
slideIn: slideIn,
|
|
852
853
|
init: init,
|
|
853
|
-
refresh:
|
|
854
|
+
refresh: function () { ScrollTrigger.refresh(); },
|
|
854
855
|
};
|
|
855
856
|
})();
|