fancoolo-fx 1.8.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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fancoolo-fx",
3
- "version": "1.8.1",
3
+ "version": "1.8.5",
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/",
package/readme.txt CHANGED
@@ -68,6 +68,9 @@ 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
+
71
74
  = 1.8.1 =
72
75
  * Fix: Removed split.revert() calls from textReveal, typeWriter, and splitWords — revert destroys JS state (event listeners, injected DOM) added after SplitText ran
73
76
  * Fix: textReveal resize re-splitting fully handled by autoSplit, no manual revert needed
package/src/fx.js CHANGED
@@ -164,14 +164,23 @@
164
164
 
165
165
  // ── Effects ──────────────────────────────────
166
166
 
167
- function textReveal(el, opts) {
168
- opts = opts || {};
169
- var o = resolveOptions(el, 'textReveal', opts);
170
- var isScroll = opts.trigger === 'scroll' || opts.scrollTrigger;
171
-
172
- gsap.set(el, { visibility: 'inherit' });
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
+ }
179
+ }
173
180
 
174
- SplitText.create(el, {
181
+ function splitTextReveal(target, o, isScroll, triggerEl, opts) {
182
+ markNoDynamicTranslation(target);
183
+ SplitText.create(target, {
175
184
  type: 'lines',
176
185
  mask: 'lines',
177
186
  autoSplit: true,
@@ -186,7 +195,7 @@
186
195
  };
187
196
 
188
197
  if (isScroll) {
189
- tweenVars.scrollTrigger = buildScrollTrigger(el, opts.scrollTrigger || {});
198
+ tweenVars.scrollTrigger = buildScrollTrigger(triggerEl, opts.scrollTrigger || {});
190
199
  }
191
200
 
192
201
  return gsap.from(self.lines, tweenVars);
@@ -194,6 +203,46 @@
194
203
  });
195
204
  }
196
205
 
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)$/;
211
+
212
+ function textReveal(el, opts) {
213
+ opts = opts || {};
214
+ var o = resolveOptions(el, 'textReveal', opts);
215
+ var isScroll = opts.trigger === 'scroll' || opts.scrollTrigger;
216
+
217
+ gsap.set(el, { visibility: 'inherit' });
218
+
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
+ }
228
+ }
229
+
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;
241
+ }
242
+
243
+ splitTextReveal(el, o, isScroll, el, opts);
244
+ }
245
+
197
246
  function reveal(el, opts) {
198
247
  opts = opts || {};
199
248
  var o = resolveOptions(el, 'reveal', opts);
@@ -377,6 +426,7 @@
377
426
  var o = resolveOptions(el, 'typeWriter', opts);
378
427
 
379
428
  gsap.set(el, { visibility: 'inherit' });
429
+ markNoDynamicTranslation(el);
380
430
  var split = new SplitText(el, { type: 'chars' });
381
431
  gsap.set(split.chars, { autoAlpha: 0 });
382
432
 
@@ -467,6 +517,7 @@
467
517
  var o = resolveOptions(el, 'splitWords', opts);
468
518
 
469
519
  gsap.set(el, { visibility: 'inherit' });
520
+ markNoDynamicTranslation(el);
470
521
  var split = new SplitText(el, { type: 'words' });
471
522
 
472
523
  var tweenVars = {
@@ -740,7 +791,22 @@
740
791
  if (pre.excludeSelectors !== undefined) config.excludeSelectors = pre.excludeSelectors;
741
792
  }
742
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
+
743
807
  function boot() {
808
+ if (isTranslationEditor()) return;
809
+
744
810
  applyPreConfig();
745
811
 
746
812
  // Build media query from config — animations auto-revert when conditions stop matching