gclass-anims 1.0.0-beta.23 → 1.0.0-beta.24
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/AnimToggle.js +23 -15
- package/Animations.js +33 -6
- package/CHANGELOG.md +45 -20
- package/Config.js +0 -1
- package/Listeners.js +421 -37
- package/README.md +27 -0
- package/dist/gclass.cjs +7 -3294
- package/dist/gclass.cjs.map +1 -0
- package/dist/gclass.esm.js +1818 -2440
- package/dist/gclass.esm.js.map +1 -0
- package/index.d.ts +58 -12
- package/package.json +2 -1
- package/vite.lib.config.js +35 -0
package/AnimToggle.js
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
import { defaults, animations } from './Config.js'
|
|
3
3
|
import { gsap } from 'gsap'
|
|
4
4
|
import { GSDevTools } from 'gsap/all'
|
|
5
|
-
|
|
5
|
+
// GSDevTools is intentionally NOT registered at module scope. This module is
|
|
6
|
+
// imported by index.js, and package.json declares "sideEffects": false-a
|
|
7
|
+
// bundler is then free to drop the registration, leaving gclassDev() to call
|
|
8
|
+
// GSDevTools.create() against an unregistered plugin. It is also unnecessary:
|
|
9
|
+
// gclassDev() is usable standalone (the docs site and dev-react-strict both
|
|
10
|
+
// call it without ever calling initAnimations()), so registration must happen
|
|
11
|
+
// at the point of use instead of at import time.
|
|
6
12
|
// localStorage key controlling whether the GSAP animation system is mounted.
|
|
7
13
|
const STORAGE_KEY = 'gclass-animations-enabled'
|
|
8
14
|
// localStorage key for a forced reduced-motion override (see
|
|
@@ -47,7 +53,7 @@ function readReducedOverride() {
|
|
|
47
53
|
// - Otherwise, if the user HAS an explicit stored choice, respect it
|
|
48
54
|
// (override wins), even under reduced motion.
|
|
49
55
|
// - Otherwise (no stored value) fall back to the default, which is ON unless
|
|
50
|
-
// reduced motion is detected
|
|
56
|
+
// reduced motion is detected-in which case animations are off.
|
|
51
57
|
function getEnabled() {
|
|
52
58
|
if (forcedReduced) return false
|
|
53
59
|
return stored === null ? !reduced : stored
|
|
@@ -119,7 +125,7 @@ let bootTimeout = null
|
|
|
119
125
|
let bootStyle = null
|
|
120
126
|
let hasBooted = false // true after first hard-load boot, skips boot on SPA path changes (remains false until first boot, resets on hard reload)
|
|
121
127
|
|
|
122
|
-
// Runtime config for gclassOpts
|
|
128
|
+
// Runtime config for gclassOpts-0 = defaults (no throttle, default GSAP ticker)
|
|
123
129
|
let currentThrottle = 0
|
|
124
130
|
let currentFps = 0
|
|
125
131
|
const configSubscribers = new Set()
|
|
@@ -145,7 +151,7 @@ function normalizeGclassArgs(throttlePerFrame, fps) {
|
|
|
145
151
|
|
|
146
152
|
/**
|
|
147
153
|
* Change GClass runtime options on the fly without reload.
|
|
148
|
-
* gclassOpts(throttlePerFrame, fps)
|
|
154
|
+
* gclassOpts(throttlePerFrame, fps)-both optional numbers.
|
|
149
155
|
* gclassOpts() or gclassOpts(undefined, undefined) resets to defaults (no throttle, default ticker).
|
|
150
156
|
* Also accepts gclassOpts({throttlePerFrame, fps}).
|
|
151
157
|
* Example low-end button: onClick={() => gclassOpts(1, 30)}
|
|
@@ -187,6 +193,8 @@ const readBootTime = (els, fallback) => {
|
|
|
187
193
|
* Accepts: gclassDev() | gclassDev("width:50%; bottom:30px") | gclassDev({width:"50%"}) | gclassDev({css:{}, minimal:true, animation:tl})
|
|
188
194
|
*/
|
|
189
195
|
export function gclassDev(cssOrOpts){
|
|
196
|
+
// Register at point of use-see the note at the top of this file.
|
|
197
|
+
gsap.registerPlugin(GSDevTools)
|
|
190
198
|
const docCss = {
|
|
191
199
|
backgroundColor: "rgba(15,23,42,0.96)", // slate-900 ~ doc bg-slate-950/900
|
|
192
200
|
border: "1px solid rgba(51,65,85,0.8)", // ring-slate-700 Header.jsx:8
|
|
@@ -223,12 +231,12 @@ export function gclassDev(cssOrOpts){
|
|
|
223
231
|
// or reduced-motion fallback with no explicit choice). Idempotent: calling it
|
|
224
232
|
// again tears down any previous run first.
|
|
225
233
|
// Now also handles boot screen: any HTML/JSX with `.boot-up` anywhere is treated as the boot overlay.
|
|
226
|
-
// No separate initBoot needed
|
|
234
|
+
// No separate initBoot needed-just call initAnimations().
|
|
227
235
|
// Boot stops all DOM rendering for defaults.bootTime (overwritten by boot-time-N class).
|
|
228
236
|
// throttlePerFrame / fps: forwarded to gclassOpts-equivalent runtime.
|
|
229
|
-
// initAnimations(throttlePerFrame, fps)
|
|
230
|
-
// initAnimations({throttlePerFrame, fps})
|
|
231
|
-
// initAnimations()
|
|
237
|
+
// initAnimations(throttlePerFrame, fps)-positional numbers, 0/undefined = defaults
|
|
238
|
+
// initAnimations({throttlePerFrame, fps})-object overload
|
|
239
|
+
// initAnimations()-uses last gclassOpts values (defaults on first call)
|
|
232
240
|
export function initAnimations(throttlePerFrame, fps) {
|
|
233
241
|
// gclassOpts-style normalization: (throttle, fps) positional or {throttlePerFrame, fps} object
|
|
234
242
|
// no args -> fallback to last gclassOpts values (defaults 0 = no throttle, default ticker)
|
|
@@ -248,9 +256,9 @@ export function initAnimations(throttlePerFrame, fps) {
|
|
|
248
256
|
else gsap.ticker.fps(0)
|
|
249
257
|
}
|
|
250
258
|
if (typeof window === 'undefined' || !getEnabled()) return
|
|
251
|
-
// boot already in progress (first mount in StrictMode)
|
|
259
|
+
// boot already in progress (first mount in StrictMode)-ignore second mount
|
|
252
260
|
if (bootTimeout) {
|
|
253
|
-
console.log(`[initAnimations] boot already in progress
|
|
261
|
+
console.log(`[initAnimations] boot already in progress-ignoring duplicate call`)
|
|
254
262
|
return
|
|
255
263
|
}
|
|
256
264
|
if (cleanup) { cleanup(); cleanup = null }
|
|
@@ -258,7 +266,7 @@ export function initAnimations(throttlePerFrame, fps) {
|
|
|
258
266
|
if (bootStyle) { bootStyle.remove(); bootStyle = null; document.documentElement.classList.remove('gclass-booting') }
|
|
259
267
|
|
|
260
268
|
const hideBootEls = (els) => {
|
|
261
|
-
// React-safe: don't el.remove()
|
|
269
|
+
// React-safe: don't el.remove()-React owns the nodes and will throw
|
|
262
270
|
// insertBefore/removeChild on next commit if we mutate outside React.
|
|
263
271
|
// Hiding keeps React's tree intact but visually removes boot screen.
|
|
264
272
|
els.forEach(el => {
|
|
@@ -272,12 +280,12 @@ export function initAnimations(throttlePerFrame, fps) {
|
|
|
272
280
|
if (!bootEls.length) {
|
|
273
281
|
// no .boot-up -> completely skip boot
|
|
274
282
|
} else if (bootEls.length > 1) {
|
|
275
|
-
console.error(`[initAnimations] Multiple .boot-up elements detected (${bootEls.length})
|
|
283
|
+
console.error(`[initAnimations] Multiple .boot-up elements detected (${bootEls.length})-skipping all boot animations`, bootEls)
|
|
276
284
|
hideBootEls(bootEls)
|
|
277
285
|
hasBooted = true
|
|
278
286
|
// fall through to normal initListeners without pausing DOM
|
|
279
287
|
} else if (hasBooted && !bootTimeout) {
|
|
280
|
-
// path change after already booted (SPA navigation)
|
|
288
|
+
// path change after already booted (SPA navigation)-skip boot, hard reload resets hasBooted
|
|
281
289
|
console.log(`[initAnimations] skipping boot on path change (already booted)`, bootEls)
|
|
282
290
|
hideBootEls(bootEls)
|
|
283
291
|
hasBooted = true
|
|
@@ -303,7 +311,7 @@ export function initAnimations(throttlePerFrame, fps) {
|
|
|
303
311
|
// ensure boot els are visible even if nested inside hidden ancestors
|
|
304
312
|
bootEls.forEach(el => { el.style.visibility = 'visible' })
|
|
305
313
|
|
|
306
|
-
// animations inside boot screen must play while rest of DOM is hidden
|
|
314
|
+
// animations inside boot screen must play while rest of DOM is hidden-init scoped to boot-up
|
|
307
315
|
bootCleanup = initListeners(bootEl, effThrottle)
|
|
308
316
|
|
|
309
317
|
bootTimeout = setTimeout(() => {
|
|
@@ -338,7 +346,7 @@ export function initAnimations(throttlePerFrame, fps) {
|
|
|
338
346
|
}
|
|
339
347
|
|
|
340
348
|
if (!cfg || !from) {
|
|
341
|
-
console.warn(`[initAnimations] boot-end-${name} has no from state
|
|
349
|
+
console.warn(`[initAnimations] boot-end-${name} has no from state-removing without animation`)
|
|
342
350
|
finish()
|
|
343
351
|
return
|
|
344
352
|
}
|
package/Animations.js
CHANGED
|
@@ -2,12 +2,32 @@ import { DrawSVGPlugin, Flip, MotionPathPlugin, ScrambleTextPlugin, SplitText, T
|
|
|
2
2
|
import { gsap } from "gsap";
|
|
3
3
|
import { defaults } from './Config.js'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
// Plugins are deliberately NOT registered here at module scope.
|
|
6
|
+
//
|
|
7
|
+
// package.json declares "sideEffects": false, which tells a consumer's
|
|
8
|
+
// bundler that importing this module has no observable side effects and that
|
|
9
|
+
// it may be dropped entirely when nothing is imported from it. Registering
|
|
10
|
+
// plugins on import contradicts that promise: a bundler that tree-shakes this
|
|
11
|
+
// module away silently un-registers SplitText / DrawSVG / ScrambleText and the
|
|
12
|
+
// corresponding classes then throw at runtime, with a stack trace that points
|
|
13
|
+
// nowhere useful.
|
|
14
|
+
//
|
|
15
|
+
// Registration is therefore deferred to registerPlugins() below, which
|
|
16
|
+
// initListeners() calls (Listeners.js). This module stays safe to import for
|
|
17
|
+
// side-effect-free helpers, and the whole set is registered exactly once.
|
|
18
|
+
let pluginsRegistered = false
|
|
19
|
+
export function registerPlugins() {
|
|
20
|
+
if (pluginsRegistered) return
|
|
21
|
+
pluginsRegistered = true
|
|
22
|
+
gsap.registerPlugin(
|
|
23
|
+
Flip,
|
|
24
|
+
SplitText,
|
|
25
|
+
TextPlugin,
|
|
26
|
+
DrawSVGPlugin,
|
|
27
|
+
MotionPathPlugin,
|
|
28
|
+
ScrambleTextPlugin,
|
|
29
|
+
)
|
|
30
|
+
}
|
|
11
31
|
|
|
12
32
|
// --- Breakpoint helpers for modifiers (xs/s/m/l/xl) -------------------------
|
|
13
33
|
// Lazy to avoid circular init (Config.js <-> Animations.js)
|
|
@@ -322,7 +342,14 @@ export function splitPaths (paths){
|
|
|
322
342
|
const path = toSplit[0]
|
|
323
343
|
if (!path) return newPaths
|
|
324
344
|
if (path._gcSplitPaths?.[0]?.isConnected) return path._gcSplitPaths
|
|
345
|
+
// Only SVG <path> elements can be split. A non-path target (or a detached
|
|
346
|
+
// node) makes MotionPathPlugin.getRawPath return undefined, and the
|
|
347
|
+
// .map() below then throws and takes the whole engine init down with it.
|
|
348
|
+
// Bail out quietly instead: draw-split is a decorative extra and a
|
|
349
|
+
// misapplied class must never be fatal.
|
|
350
|
+
if (path.nodeType !== 1 || path.tagName?.toLowerCase() !== "path" || !path.isConnected) return newPaths
|
|
325
351
|
const rawPath = MotionPathPlugin.getRawPath(path)
|
|
352
|
+
if (!rawPath || !Array.isArray(rawPath)) return newPaths
|
|
326
353
|
const parent = path.parentNode
|
|
327
354
|
const attributes = [...path.attributes]
|
|
328
355
|
newPaths = rawPath.map(segment => {
|
package/CHANGELOG.md
CHANGED
|
@@ -2,24 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `gclass-anims` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.0-beta.24] - 2026-10-05
|
|
6
|
+
### Added
|
|
7
|
+
- **`.gc-tween-[...]` escape hatch** - write GSAP vars inline when the menu has no class for it. `class="gc-tween-[y:40,opacity:0]"` plays **from** those values **to** the element's live resting state (read via `getComputedStyle`), so end values follow CSS / dark mode / breakpoints instead of being frozen into the class. Multiple `gc-tween-[...]` classes on one element **merge** (both properties end up on one tween). Modifiers work as usual: `.time-N`, `.ease-*`, `.order`, `.priority-N`, `.delay-N`, `.reduced`, `.preserve`, and `bp:` gating (`m:gc-tween-[...]`). Trigger prefixes mirror the `css-*` grammar: `hover-gc-tween-[...]`, `click-gc-tween-[...]`.
|
|
8
|
+
- **`.gc-tl` timeline host + `.gc-<n>-[...]` ordered steps** - `class="gc-tl gc-1-[y:40] gc-2-[opacity:1] gc-3-[scale:0.8]"` builds a `gsap.timeline()` with one tween per step, sorted ascending by the numeric prefix regardless of attribute order. Numbered steps imply a timeline, so `.gc-tl` is optional but expresses intent.
|
|
9
|
+
- **Per-step control keys inside the bracket** - `time:` / `dur:` overrides that step's duration (class-level `.time-N` still sets the default for steps that don't), `ease:` overrides the step's ease, and `at:` sets the GSAP **position** parameter (`at:0`, `at:">"`, `at:"+=0.2"`, `at:"<"`) for overlapping steps. These are consumed by the engine and never reach GSAP as properties.
|
|
10
|
+
- `.delay-N` is now a real modifier-a plain additive offset applied **after** the `.order` / `.priority-N` delay, so `order delay-2` shifts the stagger and `priority-3 delay-1` composes. `Config.js:23` previously promised `delay` support that no code implemented.
|
|
11
|
+
- `registerPlugins()` is exported, so a consumer can register the plugin set explicitly without booting the engine.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Consumer-package corruption via `sideEffects: false`.** All GSAP plugin registration moved out of module scope into `initListeners()` (`registerPlugins()` in `Animations.js`, plus the existing `TextPlugin`/`ScrollTrigger`/`SplitText` call). `package.json` declares `sideEffects: false`, which tells a consumer's bundler it may drop a module that only registers plugins on import-silently un-registering `SplitText` / `DrawSVG` / `ScrambleText` and making the matching classes throw at runtime inside someone else's app. Importing the package for helpers is now genuinely side-effect free. This also removes the duplicate `SplitText` / `TextPlugin` registration that existed at both module scope and init time.
|
|
15
|
+
- **`gclassDev()` no longer depends on import order.** `GSDevTools` registration moved from `AnimToggle.js` module scope into the body of `gclassDev()`, so it works whether or not `initAnimations()` has run. The docs site and `dev-react-strict` both call `gclassDev()` standalone and were relying on the module-scope registration.
|
|
16
|
+
- **Breakpoint tables are no longer frozen at import.** `Listeners.js` computed `bpNames` / `bpMap` / `bpPrefixRE` as module-scope `const`s, so assigning `defaults.breakpoints` after import was silently ignored. They are now derived lazily and memoised on the identity of the `defaults.breakpoints` object (port of the lazy `getBpDataMod()` approach `Animations.js` already used).
|
|
17
|
+
- **`css-<prop>-<from>-<to>` now merges instead of first-match-wins.** `parseCssAnim` returned on the first matching class, so an element could carry exactly one `css-*` animation and any further classes were ignored. All matching classes now merge into a single tween; a later class for the same property wins, and the first trigger prefix seen decides spawn/hover/click/loop for the whole element.
|
|
18
|
+
- **`.appear` on dynamically inserted `.gc` elements.** `setupGcAnims` is registered in the MutationObserver appear batch as well as the initial load pass, matching `setupCssAnims`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- `dist/` is now minified with source maps (`minify: true`, `sourcemap: true` in `vite.lib.config.js`). ESM 95.7 kB → 74.7 kB (gzip 19.6 kB), CJS 97.7 kB → 57.7 kB (gzip 17.5 kB). Source maps keep stack traces resolvable to the original `Listeners.js` / `Animations.js` lines. Note: `minify: 'esbuild'` fails on a clean install here because this repo has no direct `esbuild` dependency (Vite 8 delegates to rolldown)-`minify: true` is the portable form.
|
|
22
|
+
- **Removed `defaults.textStagger`.** Declared in `Config.js`, typed in `index.d.ts`, and documented on the defaults page, but read by nothing-stagger is derived arithmetically in `playText`. Deleted from all three rather than wired up, because making it the default would silently change the timing of every existing text animation.
|
|
23
|
+
- `index.d.ts` drift fixed: `initListeners` was declared as a **default** export while `index.js` re-exports it **named**, so `import initListeners from 'gclass-anims'` type-checked and then returned `undefined` at runtime; `Example` was typed but never exported (`index.js` omits it) and is now removed; `Defaults` now declares `breakpoints`, without which `defaults.breakpoints = {...}` was a type error and the whole `m:` system was unconfigurable in TypeScript; `finalOpacity`, `stashText`, `spawnClipReveal`, `curtainHorizontal`, `curtainVertical` and `scrambleSegments` now have declarations (all six ship in the bundle).
|
|
24
|
+
|
|
25
|
+
### Notes for consumers
|
|
26
|
+
- **One bracket group per `.gc` class.** Tailwind re-lexes bracket contents as standalone candidates, so a second bracket group leaks real CSS into your stylesheet: `gc-tween-[y:40]` emits nothing, but `gc-tween-[y:40]-[y:0]` makes Tailwind emit `.[y:0] { y: 0 }`. The parser only ever accepts one group, and `dev-react-strict/src/__tests__/gc-tween.test.jsx` asserts this against real Tailwind (with a control case proving the harness can detect a leak at all). For a two-value tween use two numbered steps, or the existing `css-<prop>-<from>-<to>`.
|
|
27
|
+
- `.randomize-*` does not reach `.gc` tweens-it is injected by monkey-patching `gsap.fromTo` inside `play()`-built tweens only.
|
|
28
|
+
- `demo/` is legacy: those static pages predate the docs site and are not wired into anything. Their `gclass-bundle.js` is a stale prebuilt bundle (dated 2026-08-27) and nothing in the repo regenerates it, so treat that directory as historical rather than a live example. `dist/` is the current build.
|
|
29
|
+
|
|
5
30
|
## [1.0.0-beta.23] - 2026-09-09
|
|
6
|
-
- Added `gclassDev()` helper
|
|
31
|
+
- Added `gclassDev()` helper-`AnimToggle.js:185` `gclassDev(cssOrOpts)` wraps `GSDevTools.create()` with doc-styled defaults (`slate-900` `rgba(15,23,42,0.96)`, `slate-700` border, `rounded-xl`, `backdrop-blur`). Accepts `gclassDev()` (defaults), `gclassDev("width:50%; bottom:30px")` (CSS string), `gclassDev({width:"50%"})` (style object shorthand), or `gclassDev({css, animation, minimal, ...})` (full `GSDevTools` opts). Registers `GSDevTools` via `gsap.registerPlugin(GSDevTools)` (`AnimToggle.js:4`), re-exported from `index.js:1` and typed in `index.d.ts:35`.
|
|
7
32
|
|
|
8
33
|
## [1.0.0-beta.22.2] - 2026-09-06
|
|
9
|
-
- Fixed `m:order` (and any `bp:order` / `bp:priority-*` / `bp:ease-*` / `bp:time-*`) disabling the entire `scroll` animation on smaller screens
|
|
34
|
+
- Fixed `m:order` (and any `bp:order` / `bp:priority-*` / `bp:ease-*` / `bp:time-*`) disabling the entire `scroll` animation on smaller screens-`Listeners.js:1200,1232,1262` previously wrapped `setupScroll` / `playText` scroll variants in generic `runWithBreakpoint(el, ...)` which gated on *any* `bp:*` class on the element (so `m:order` gated `scroll`). Now uses per-animation `qAllAllVariants` + `runWithBreakpointForSel` (`".scroll"`, `".scroll-progress"`, `tSel`) so only a true `m:scroll` / `m:spawn-*` gates its own animation; unrelated modifiers like `m:order` only affect `hasGClass("order")` / `readTiming` (stagger) and `spawn-*` + `scroll` still play on all sizes (without stagger on <m). Keeps live `gsap.matchMedia` handling for true breakpoint-gated scroll. Reverts `HowWorkSection.jsx` workaround from `m:order` back to plain `order` for the default staggered landing.
|
|
10
35
|
|
|
11
36
|
## [1.0.0-beta.22.1] - 2026-09-06
|
|
12
|
-
- Fixed `.order` stagger grouping bug
|
|
37
|
+
- Fixed `.order` stagger grouping bug-`Listeners.js:76` `wrapQAll` now preserves DOM order via `body *` filter + `elementMatchesSel` (was `Set([...spawn-up], [...spawn-down])` grouping by type, now top-to-bottom as `qAll` does). Fixes `doc` `spawn` and landing `order` appearing all over.
|
|
13
38
|
- No API change from `beta.22`.
|
|
14
39
|
|
|
15
40
|
## [1.0.0-beta.22] - 2026-09-06
|
|
16
|
-
- Added responsive breakpoints
|
|
17
|
-
- Added breakpoint-aware modifiers
|
|
18
|
-
- Fixed runtime `customAnims` re-normalization
|
|
19
|
-
- Added ESM + CJS dual build
|
|
20
|
-
- Fixed CJS `gsap` interop
|
|
21
|
-
- Added `dev-react-strict` test harness
|
|
22
|
-
- Documented breakpoints
|
|
41
|
+
- Added responsive breakpoints-`Config.js:75` `defaults.breakpoints {xs:475,s:640,m:768,l:1024,xl:1280}` (single-letter `s/m/l` avoids Tailwind `sm/md/lg` collision). Usage `m:spawn-up`, `l:float`, `xs:spawn-up`. Gating is live via `gsap.matchMedia` (`Listeners.js:26,202`).
|
|
42
|
+
- Added breakpoint-aware modifiers-`m:amount-20`, `m:time-2`, `m:ease-bounce`, `m:priority-3`, `m:chars-[...]`, `m:spawn-num-10` etc. Mobile-first largest active wins (`Listeners.js:237` `getActivePrefixedClass`, `Animations.js:13` lazy helpers). Covers `amount-`, `time-`, `priority-`, `edelay-`, `etime-`, `stagger-`, `fill-time-`, `reveal-delay-`, `spawn-num-`, `progress-start-`, etc.
|
|
43
|
+
- Fixed runtime `customAnims` re-normalization-`Listeners.js:190` now calls `normalize(customAnims)` inside `initListeners()` so `customAnims.push()` before next `init` is picked up.
|
|
44
|
+
- Added ESM + CJS dual build-`vite.lib.config.js` (Vite lib) builds `dist/gclass.esm.js` + `dist/gclass.cjs` (`gsap` external); `package.json:4` bumped to `beta.22`, `main/module` point to `dist/`, `exports: {import, require}`, `sideEffects:false`, `prepublishOnly: build`.
|
|
45
|
+
- Fixed CJS `gsap` interop-`Animations.js:2`/`Listeners.js:1`/`AnimToggle.js:3`/`CustomAnims.js:1` now `import {gsap} from 'gsap'` (named import) for correct `require('gsap').gsap` interop.
|
|
46
|
+
- Added `dev-react-strict` test harness-`vitest` + `jsdom` + `src/__tests__/breakpoints.test.jsx` (14 tests: gating, modifiers, Tailwind coexistence, StrictMode) + `BreakpointHarness.jsx` visual; `vite.config.js` test config.
|
|
47
|
+
- Documented breakpoints-`doc/src/app/documentation/responsive-design/page.js` (was duplicate `optimization`).
|
|
23
48
|
|
|
24
49
|
## [1.0.0-beta.21] - 2026-9-3
|
|
25
50
|
- Added a `gclassOpts()` function that controls the animation fps and observer throttling
|
|
@@ -51,22 +76,22 @@ All notable changes to `gclass-anims` will be documented in this file.
|
|
|
51
76
|
|
|
52
77
|
## [1.0.0-beta.12] - 2026-08-26
|
|
53
78
|
|
|
54
|
-
- Fixed `scramble` with `scroll-progress` throwing `can't convert undefined to object
|
|
79
|
+
- Fixed `scramble` with `scroll-progress` throwing `can't convert undefined to object`-`computeTo` (`Listeners.js:424`) and scrub `to` builder (`Listeners.js:867`) now guard `from` (`scramble` has no `from`).
|
|
55
80
|
|
|
56
81
|
## [1.0.0-beta.11] - 2026-08-26
|
|
57
82
|
|
|
58
|
-
- Fixed `.draw-split` infinite loop when paired with `.appear
|
|
83
|
+
- Fixed `.draw-split` infinite loop when paired with `.appear`-`splitPaths` (`Animations.js:244`) now strips `appear`/`scroll`/`scroll-progress`/`draw`/`draw-split`/`data-gsap-*` from cloned segments, marks children with `data-gsap-split` + `contain:paint`/`will-change:transform` isolation, and prevents `appearObserver` (`Listeners.js:1559`) re-triggering. Also isolated `draw-split` demos in docs.
|
|
59
84
|
|
|
60
85
|
## [1.0.0-beta.10] - 2026-08-26
|
|
61
86
|
|
|
62
|
-
- Added `.randomize-<prop>-[min]-[max]
|
|
63
|
-
- Added `.draw
|
|
64
|
-
- Added `.draw-split
|
|
65
|
-
- Added `.scramble
|
|
66
|
-
- Added `.scramble-all
|
|
67
|
-
- Added `.scroll-frame
|
|
68
|
-
- Fixed `spawn-text-*` (SplitText) not working correctly on flex containers
|
|
87
|
+
- Added `.randomize-<prop>-[min]-[max]`-randomize spawn start values per element (e.g. `randomize-rotation-[-90]-[90]`, `randomize-x-[-40]-[40]`). Re-rolls on every replay (`.scroll` re-enter, `.appear`).
|
|
88
|
+
- Added `.draw`-stroke-draw reveal for SVG paths using DrawSVGPlugin (`drawSVG: 0% → 100%`).
|
|
89
|
+
- Added `.draw-split`-draws multi-segment SVG paths sequentially at constant pen speed (splits paths with multiple `M` commands into individual strokes).
|
|
90
|
+
- Added `.scramble`-text resolves from empty through scrambled characters into real content (ScrambleTextPlugin). Supports `.reveal-delay-N`, `.chars-[...]`, `.amount-N`, `.scramble-rtl`.
|
|
91
|
+
- Added `.scramble-all`-variant of scramble with no empty start; the finished string flips to garbage as a whole then sweeps back.
|
|
92
|
+
- Added `.scroll-frame`-use a scrollable container as the ScrollTrigger scroller for nested `.scroll` / `.scroll-progress` elements (innermost `.scroll-frame` ancestor wins).
|
|
93
|
+
- Fixed `spawn-text-*` (SplitText) not working correctly on flex containers-text runs are now wrapped in block containers before splitting to preserve flex layout, spacing, and line grouping.
|
|
69
94
|
|
|
70
|
-
## [1.0.0-beta.9]
|
|
95
|
+
## [1.0.0-beta.9]-Previous release
|
|
71
96
|
|
|
72
97
|
- See git history for earlier changes.
|