gclass-anims 1.0.0-beta.14 → 1.0.0-beta.16
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 +99 -3
- package/Animations.js +24 -4
- package/Boot.js +12 -0
- package/CHANGELOG.md +5 -0
- package/Config.js +2 -1
- package/Listeners.js +35 -15
- package/index.d.ts +5 -1
- package/index.js +1 -0
- package/package.json +2 -1
package/AnimToggle.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import initListeners from './Listeners'
|
|
2
|
+
import { defaults, animations } from './Config.js'
|
|
3
|
+
import gsap from 'gsap'
|
|
2
4
|
|
|
3
5
|
// localStorage key controlling whether the GSAP animation system is mounted.
|
|
4
|
-
const STORAGE_KEY = '
|
|
6
|
+
const STORAGE_KEY = 'gclass-animations-enabled'
|
|
5
7
|
// localStorage key for a forced reduced-motion override (see
|
|
6
8
|
// enableReducedMotion / disableReducedMotion).
|
|
7
|
-
const REDUCED_KEY = '
|
|
9
|
+
const REDUCED_KEY = 'gclass-reduced-motion'
|
|
8
10
|
|
|
9
11
|
const reducedMotionQuery = typeof window !== 'undefined'
|
|
10
12
|
? window.matchMedia('(prefers-reduced-motion: reduce)')
|
|
@@ -111,12 +113,106 @@ export function disableReducedMotion() {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
let cleanup = null
|
|
116
|
+
let bootCleanup = null
|
|
117
|
+
let bootTimeout = null
|
|
118
|
+
let bootStyle = null
|
|
119
|
+
|
|
120
|
+
const readBootTime = (els, fallback) => {
|
|
121
|
+
let max = null
|
|
122
|
+
for (const el of els) {
|
|
123
|
+
const cls = [...el.classList].find(c => c.startsWith('boot-time-'))
|
|
124
|
+
if (cls) {
|
|
125
|
+
const n = Number(cls.slice('boot-time-'.length))
|
|
126
|
+
if (!Number.isNaN(n)) max = max === null ? n : Math.max(max, n)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return max ?? fallback
|
|
130
|
+
}
|
|
114
131
|
|
|
115
132
|
// Boots the GSAP animation system unless animations are disabled (stored "off"
|
|
116
133
|
// or reduced-motion fallback with no explicit choice). Idempotent: calling it
|
|
117
134
|
// again tears down any previous run first.
|
|
135
|
+
// Now also handles boot screen: any HTML/JSX with `.boot-up` anywhere is treated as the boot overlay.
|
|
136
|
+
// No separate initBoot needed - just call initAnimations().
|
|
137
|
+
// Boot stops all DOM rendering for defaults.bootTime (overwritten by boot-time-N class).
|
|
118
138
|
export function initAnimations() {
|
|
119
139
|
if (typeof window === 'undefined' || !getEnabled()) return
|
|
120
|
-
if (cleanup) cleanup()
|
|
140
|
+
if (cleanup) { cleanup(); cleanup = null }
|
|
141
|
+
if (bootCleanup) { bootCleanup(); bootCleanup = null }
|
|
142
|
+
if (bootTimeout) { clearTimeout(bootTimeout); bootTimeout = null }
|
|
143
|
+
if (bootStyle) { bootStyle.remove(); bootStyle = null; document.documentElement.classList.remove('gclass-booting') }
|
|
144
|
+
|
|
145
|
+
const bootEls = typeof document !== 'undefined' ? document.querySelectorAll(".boot-up") : []
|
|
146
|
+
if (!bootEls.length) {
|
|
147
|
+
// no .boot-up -> completely skip boot
|
|
148
|
+
} else if (bootEls.length > 1) {
|
|
149
|
+
console.error(`[initAnimations] Multiple .boot-up elements detected (${bootEls.length}) - skipping all boot animations`, bootEls)
|
|
150
|
+
bootEls.forEach(el => el.remove())
|
|
151
|
+
// fall through to normal initListeners without pausing DOM
|
|
152
|
+
} else {
|
|
153
|
+
const bootEl = bootEls[0]
|
|
154
|
+
const hasBootEnd = [...bootEl.classList].some(c => c.startsWith('boot-end-'))
|
|
155
|
+
if (!hasBootEnd) {
|
|
156
|
+
// no boot-end-* -> completely skip boot animation (still pause? spec says skip it)
|
|
157
|
+
// spec: skip boot-end animation if no class, but still do boot pause? user said "completely skip it if no .boot-end-<name> class is present"
|
|
158
|
+
// interpret as skip the exit animation only, still pause for bootTime
|
|
159
|
+
// To match "completely skip it" for boot-end, we just don't play exit tween
|
|
160
|
+
}
|
|
161
|
+
const bootTime = readBootTime(bootEls, defaults.bootTime ?? 2)
|
|
162
|
+
console.log(`[initAnimations] .boot-up found: ${bootEls.length} - pausing DOM for ${bootTime}s`, bootEls)
|
|
163
|
+
// stop all DOM rendering except .boot-up
|
|
164
|
+
bootStyle = document.createElement('style')
|
|
165
|
+
bootStyle.id = 'gclass-boot-style'
|
|
166
|
+
bootStyle.textContent = `html.gclass-booting{visibility:hidden} html.gclass-booting .boot-up,html.gclass-booting .boot-up *{visibility:visible} html.gclass-booting .boot-up{position:fixed;inset:0;z-index:9999;display:grid;place-items:center}`
|
|
167
|
+
document.head.appendChild(bootStyle)
|
|
168
|
+
document.documentElement.classList.add('gclass-booting')
|
|
169
|
+
// ensure boot els are visible even if nested inside hidden ancestors
|
|
170
|
+
bootEls.forEach(el => { el.style.visibility = 'visible' })
|
|
171
|
+
|
|
172
|
+
// animations inside boot screen must play while rest of DOM is hidden - init scoped to boot-up
|
|
173
|
+
bootCleanup = initListeners(bootEl)
|
|
174
|
+
|
|
175
|
+
bootTimeout = setTimeout(() => {
|
|
176
|
+
const bootEndCls = [...bootEl.classList].find(c => c.startsWith('boot-end-'))
|
|
177
|
+
if (!bootEndCls) {
|
|
178
|
+
// no boot-end -> skip exit animation, just remove
|
|
179
|
+
bootCleanup?.(); bootCleanup = null
|
|
180
|
+
document.documentElement.classList.remove('gclass-booting')
|
|
181
|
+
bootStyle?.remove(); bootStyle = null
|
|
182
|
+
bootEls.forEach(el => el.remove())
|
|
183
|
+
bootTimeout = null
|
|
184
|
+
cleanup = initListeners()
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
const name = bootEndCls.slice('boot-end-'.length) // e.g. spawn-blur
|
|
188
|
+
const cfg = animations.find(a => a.sel === '.' + name)
|
|
189
|
+
const from = cfg?.from
|
|
190
|
+
const easeCl = [...bootEl.classList].find(c => c.startsWith('ease-'))
|
|
191
|
+
const ease = easeCl ? easeCl.split('-')[1] : defaults.ease
|
|
192
|
+
const dur = readBootTime([bootEl], defaults.effectDuration ?? 1) // reuse boot-time- or fallback to effectDuration; if boot-time used for pause, reuse same value for exit unless overridden
|
|
193
|
+
// Actually use boot-end-time-N if present, else effectDuration
|
|
194
|
+
const endTimeCls = [...bootEl.classList].find(c => c.startsWith('boot-end-time-'))
|
|
195
|
+
const endDur = endTimeCls ? Number(endTimeCls.slice('boot-end-time-'.length)) : dur
|
|
196
|
+
|
|
197
|
+
const finish = () => {
|
|
198
|
+
bootCleanup?.(); bootCleanup = null
|
|
199
|
+
document.documentElement.classList.remove('gclass-booting')
|
|
200
|
+
bootStyle?.remove(); bootStyle = null
|
|
201
|
+
bootEls.forEach(el => el.remove())
|
|
202
|
+
bootTimeout = null
|
|
203
|
+
cleanup = initListeners()
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!cfg || !from) {
|
|
207
|
+
console.warn(`[initAnimations] boot-end-${name} has no from state - removing without animation`)
|
|
208
|
+
finish()
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
// play spawn in reverse (visible -> hidden) before removing
|
|
212
|
+
gsap.to(bootEl, { ...from, duration: endDur, ease, onComplete: finish })
|
|
213
|
+
}, bootTime * 1000)
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
121
217
|
cleanup = initListeners()
|
|
122
218
|
}
|
package/Animations.js
CHANGED
|
@@ -79,7 +79,11 @@ export function expandA (target , delay , dur , ease){
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function typewriter (target , text , dur , delay , ease){
|
|
82
|
-
|
|
82
|
+
// Any element using TextPlugin gets pre-wrap so "\n" from VSCode Enter or JS strings
|
|
83
|
+
// renders as a real line break and any innerHTML formatting is preserved.
|
|
84
|
+
gsap.utils.toArray(target).forEach(el => { if (el.style) el.style.whiteSpace = "pre-wrap" })
|
|
85
|
+
const value = String(text).replace(/\n/g, "<br>")
|
|
86
|
+
return gsap.fromTo(target , {text:""} , {ease:easeOf(ease) , duration:dur , delay:delay , text:{value}})
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
export function spawnSpinCCW (target , delay , dur , ease){
|
|
@@ -587,27 +591,43 @@ export function radiate (delay , target , amount , dur , ease , zIndex){
|
|
|
587
591
|
tick = true
|
|
588
592
|
requestAnimationFrame(() => { tick = false; applyRect() })
|
|
589
593
|
}
|
|
594
|
+
// Don't animate detached targets — return inert tween
|
|
595
|
+
if (!target.isConnected) {
|
|
596
|
+
return gsap.fromTo(clone, {}, { duration: 0 })
|
|
597
|
+
}
|
|
590
598
|
document.body.appendChild(clone)
|
|
591
599
|
applyRect()
|
|
592
600
|
window.addEventListener("scroll", schedule, { passive: true })
|
|
593
601
|
window.addEventListener("resize", schedule, { passive: true })
|
|
594
602
|
// Killing the tween (teardown, hover/click rebuilds) must clean up exactly
|
|
595
603
|
// like natural completion - otherwise clones + listeners leak.
|
|
604
|
+
let tween = null
|
|
596
605
|
const cleanup = () => {
|
|
597
606
|
clone.remove()
|
|
598
607
|
window.removeEventListener("scroll", schedule)
|
|
599
608
|
window.removeEventListener("resize", schedule)
|
|
609
|
+
if (observer) observer.disconnect()
|
|
600
610
|
}
|
|
611
|
+
// If target is removed from DOM (React unmount, .remove(), SPA navigation),
|
|
612
|
+
// kill the tween and remove the clone — mirrors React useEffect cleanup
|
|
613
|
+
const observer = new MutationObserver(() => {
|
|
614
|
+
if (!target.isConnected) {
|
|
615
|
+
if (tween) tween.kill()
|
|
616
|
+
cleanup()
|
|
617
|
+
}
|
|
618
|
+
})
|
|
619
|
+
observer.observe(document.body, { childList: true, subtree: true })
|
|
601
620
|
|
|
602
|
-
|
|
621
|
+
tween = gsap.fromTo(clone , {scale:1 , opacity:1} , {
|
|
603
622
|
scale:amount / 10 ,
|
|
604
623
|
opacity:0 ,
|
|
605
624
|
duration:dur ,
|
|
606
625
|
delay:delay ,
|
|
607
626
|
ease:easeOf(ease) ,
|
|
608
|
-
onComplete: cleanup ,
|
|
609
|
-
onInterrupt: cleanup ,
|
|
627
|
+
onComplete: () => { observer.disconnect(); cleanup(); },
|
|
628
|
+
onInterrupt: () => { observer.disconnect(); cleanup(); },
|
|
610
629
|
})
|
|
630
|
+
return tween
|
|
611
631
|
}
|
|
612
632
|
|
|
613
633
|
|
package/Boot.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { initAnimations } from './AnimToggle.js'
|
|
2
|
+
|
|
3
|
+
export function Boot(){
|
|
4
|
+
const els = document.querySelectorAll(".boot-up")
|
|
5
|
+
console.log(`[Boot -> initAnimations] .boot-up count: ${els.length}`, els)
|
|
6
|
+
// rewired: Boot now just delegates to initAnimations (single entry point)
|
|
7
|
+
return initAnimations()
|
|
8
|
+
}
|
|
9
|
+
// keep named exports wired so index.js / dev don't break during test
|
|
10
|
+
export const initBoot = Boot
|
|
11
|
+
export const createBootOverlay = Boot
|
|
12
|
+
export default Boot
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `gclass-anims` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.0-beta.16] - 2026-09-1
|
|
6
|
+
- Added a new `.boot-up` class for boot up animations
|
|
7
|
+
- Fixed text animations not taking formatting into account
|
|
8
|
+
|
|
9
|
+
|
|
5
10
|
## [1.0.0-beta.13] - 2026-08-27
|
|
6
11
|
- Added a new `.fill-svg` modifier for the `.draw` and `.draw-split` classes that fills the SVG after it has been drawn.
|
|
7
12
|
|
package/Config.js
CHANGED
|
@@ -70,7 +70,8 @@ export const defaults = {
|
|
|
70
70
|
typewriterSplitCharDuration: 0.05,
|
|
71
71
|
minTextPartDuration: 0.3,
|
|
72
72
|
revealDelay:0,
|
|
73
|
-
characterlist:"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
|
73
|
+
characterlist:"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz",
|
|
74
|
+
bootTime: 5,
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
export const animations = [
|
package/Listeners.js
CHANGED
|
@@ -93,9 +93,21 @@ const invokePlay = (config, el, delay, dur, ease) => {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
export default function initListeners() {
|
|
96
|
+
export default function initListeners(root = document) {
|
|
97
97
|
gsap.registerPlugin(TextPlugin, ScrollTrigger, SplitText)
|
|
98
98
|
|
|
99
|
+
// helper to scope queries to root (for boot screen: only boot-up subtree animates during boot)
|
|
100
|
+
const qAll = (sel) => {
|
|
101
|
+
if (root === document || root === document.documentElement || root === document.body) return gsap.utils.toArray(sel)
|
|
102
|
+
if (sel === "body *") return gsap.utils.toArray(root.querySelectorAll("*"))
|
|
103
|
+
try {
|
|
104
|
+
const els = [...(root.querySelectorAll ? root.querySelectorAll(sel) : [])]
|
|
105
|
+
if (root.matches?.(sel)) els.unshift(root)
|
|
106
|
+
// handle comma selectors where root itself may match one part
|
|
107
|
+
return els
|
|
108
|
+
} catch { return gsap.utils.toArray(sel) }
|
|
109
|
+
}
|
|
110
|
+
|
|
99
111
|
const registeredListeners = []
|
|
100
112
|
const onCompleteTweens = []
|
|
101
113
|
const addListener = (el, type, fn) => {
|
|
@@ -358,7 +370,7 @@ export default function initListeners() {
|
|
|
358
370
|
spawnConfigs.map(({ sel }) => "." + TEXT_PREFIX + sel.slice(1)).join(",")
|
|
359
371
|
|
|
360
372
|
const getOrderDelay = (el, priority) => {
|
|
361
|
-
const samepri =
|
|
373
|
+
const samepri = qAll(orderSelector())
|
|
362
374
|
.filter((e) => {
|
|
363
375
|
if (!e.classList.contains("order")) return false
|
|
364
376
|
const match = [...e.classList].find(p => p.startsWith("priority-"))
|
|
@@ -472,7 +484,10 @@ export default function initListeners() {
|
|
|
472
484
|
// would render it in its connecting form instead of its correct END form),
|
|
473
485
|
// but it should still be split into its own span so it animates too.
|
|
474
486
|
const RTL_LETTER = /[\u0621-\u064A\u066E-\u06D5\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/
|
|
475
|
-
const getRTLCharSplit = (el) =>
|
|
487
|
+
const getRTLCharSplit = (el) => {
|
|
488
|
+
// Any element using SplitText gets pre-wrap so "\n" and formatting is preserved
|
|
489
|
+
if (el.style) el.style.whiteSpace = "pre-wrap"
|
|
490
|
+
return new SplitText(el, {
|
|
476
491
|
type: "words",
|
|
477
492
|
linesClass: "gsap-line",
|
|
478
493
|
wordsClass: "gsap-word",
|
|
@@ -555,6 +570,7 @@ export default function initListeners() {
|
|
|
555
570
|
self.words.length = 0
|
|
556
571
|
},
|
|
557
572
|
})
|
|
573
|
+
}
|
|
558
574
|
|
|
559
575
|
// Flex targets can't be split directly: the split parts would become
|
|
560
576
|
// flex ITEMS, so justify-content/gap would apply per letter, whitespace-
|
|
@@ -595,6 +611,7 @@ export default function initListeners() {
|
|
|
595
611
|
}
|
|
596
612
|
|
|
597
613
|
const getSplit = (el, gran) => {
|
|
614
|
+
if (el.style) el.style.whiteSpace = "pre-wrap"
|
|
598
615
|
let s = splitCache.get(el)
|
|
599
616
|
const rtlChars = gran === "chars" && isRTLText(el)
|
|
600
617
|
const key = rtlChars ? "rtl-chars" : gran
|
|
@@ -604,6 +621,9 @@ export default function initListeners() {
|
|
|
604
621
|
? getRTLCharSplit(el)
|
|
605
622
|
: new SplitText(el, {
|
|
606
623
|
type: gran,
|
|
624
|
+
tag: "span",
|
|
625
|
+
reduceWhiteSpace: false,
|
|
626
|
+
|
|
607
627
|
linesClass: "gsap-line",
|
|
608
628
|
wordsClass: "gsap-word",
|
|
609
629
|
charsClass: "gsap-char",
|
|
@@ -739,7 +759,7 @@ export default function initListeners() {
|
|
|
739
759
|
// created before any scroll/scroll-progress trigger measures its position.
|
|
740
760
|
// Setting them up here (before the trigger pass below) keeps offsets correct
|
|
741
761
|
// and lets the single ScrollTrigger.refresh() at the end reconcile layout.
|
|
742
|
-
|
|
762
|
+
qAll(".pin").forEach(setupPin)
|
|
743
763
|
|
|
744
764
|
// Scroll-driven extras - class-driven ScrollTrigger behaviours that don't
|
|
745
765
|
// fit the spawn/loop machinery (no `play`/`build`), handled like `.pin`:
|
|
@@ -832,7 +852,7 @@ export default function initListeners() {
|
|
|
832
852
|
scrollTriggers.push(t.scrollTrigger)
|
|
833
853
|
}
|
|
834
854
|
}
|
|
835
|
-
|
|
855
|
+
qAll('[class^="parallax-"],[class*=" parallax-"], .progress-bar, .scroll-fill, .scroll-fade-bg, .scroll-horizontal').forEach(setupScrollDriven)
|
|
836
856
|
|
|
837
857
|
// Scroller resolution: a `.scroll`/`.scroll-progress` element inside a
|
|
838
858
|
// `.scroll-frame` container binds its trigger to THAT box instead of the
|
|
@@ -1001,7 +1021,7 @@ export default function initListeners() {
|
|
|
1001
1021
|
})
|
|
1002
1022
|
scrollTriggers.push(st)
|
|
1003
1023
|
}
|
|
1004
|
-
|
|
1024
|
+
qAll(".scroll, .scroll-progress").forEach(setupScroll)
|
|
1005
1025
|
|
|
1006
1026
|
// SplitText scroll variants: `.spawn-text-<spawn>.scroll` plays the per-part
|
|
1007
1027
|
// tween when the element enters the viewport and reverses on exit.
|
|
@@ -1009,7 +1029,7 @@ export default function initListeners() {
|
|
|
1009
1029
|
if (isTypewriter || text === false) return
|
|
1010
1030
|
const tSel = "." + TEXT_PREFIX + sel.slice(1)
|
|
1011
1031
|
|
|
1012
|
-
|
|
1032
|
+
qAll(tSel + ".scroll:not(.scroll-progress)").forEach((el) => {
|
|
1013
1033
|
if (isReduced(el)) return
|
|
1014
1034
|
const { delay, duration } = readTiming(el)
|
|
1015
1035
|
const ease = getEase(el)
|
|
@@ -1034,7 +1054,7 @@ export default function initListeners() {
|
|
|
1034
1054
|
}))
|
|
1035
1055
|
})
|
|
1036
1056
|
|
|
1037
|
-
|
|
1057
|
+
qAll(tSel + ".scroll-progress").forEach((el) => {
|
|
1038
1058
|
if (isReduced(el)) return
|
|
1039
1059
|
const ease = getEase(el)
|
|
1040
1060
|
const parts = getParts(el, getGranularity(el))
|
|
@@ -1087,7 +1107,7 @@ export default function initListeners() {
|
|
|
1087
1107
|
|
|
1088
1108
|
spawnConfigs.forEach((config) => {
|
|
1089
1109
|
const { sel, typewriter: isTypewriter, typewriterSplit } = config
|
|
1090
|
-
|
|
1110
|
+
qAll(sel).forEach((el) => {
|
|
1091
1111
|
if (el.classList.contains("scroll") || el.classList.contains("scroll-progress")) return
|
|
1092
1112
|
if (isPreserved(el)) return
|
|
1093
1113
|
if (isReduced(el)) return
|
|
@@ -1122,7 +1142,7 @@ export default function initListeners() {
|
|
|
1122
1142
|
spawnConfigs.forEach(({ sel, from, typewriter: isTypewriter, text }) => {
|
|
1123
1143
|
if (isTypewriter || text === false) return
|
|
1124
1144
|
const tSel = "." + TEXT_PREFIX + sel.slice(1)
|
|
1125
|
-
|
|
1145
|
+
qAll(tSel).forEach((el) => {
|
|
1126
1146
|
if (el.classList.contains("scroll") || el.classList.contains("scroll-progress")) return
|
|
1127
1147
|
if (isPreserved(el)) return
|
|
1128
1148
|
if (isReduced(el)) return
|
|
@@ -1487,7 +1507,7 @@ export default function initListeners() {
|
|
|
1487
1507
|
|
|
1488
1508
|
// Bind click + loop animations to every element present at load, tagging
|
|
1489
1509
|
// them so the MutationObserver below never double-binds a dynamic one.
|
|
1490
|
-
|
|
1510
|
+
qAll("body *").forEach((el) => {
|
|
1491
1511
|
if (el.dataset?.gsapSetup) return
|
|
1492
1512
|
el.dataset.gsapSetup = "1"
|
|
1493
1513
|
setupClicks(el)
|
|
@@ -1608,7 +1628,7 @@ export default function initListeners() {
|
|
|
1608
1628
|
appearObserver.observe(document.body, { childList: true, subtree: true })
|
|
1609
1629
|
|
|
1610
1630
|
// Capture any .leave elements already present so they can exit later
|
|
1611
|
-
|
|
1631
|
+
qAll(".leave").forEach(captureLeave)
|
|
1612
1632
|
|
|
1613
1633
|
const leaveObserver = new MutationObserver((mutations) => {
|
|
1614
1634
|
mutations.forEach((mutation) => {
|
|
@@ -1625,7 +1645,7 @@ export default function initListeners() {
|
|
|
1625
1645
|
if (positionTick) return
|
|
1626
1646
|
positionTick = true
|
|
1627
1647
|
requestAnimationFrame(() => {
|
|
1628
|
-
|
|
1648
|
+
qAll(".leave").forEach((el) => {
|
|
1629
1649
|
const s = leaveStates.get(el)
|
|
1630
1650
|
if (s) s.rect = el.getBoundingClientRect()
|
|
1631
1651
|
})
|
|
@@ -1666,7 +1686,7 @@ export default function initListeners() {
|
|
|
1666
1686
|
// so dynamically-added .appear elements can animate under the new
|
|
1667
1687
|
// engine run. data-gsap-preserved (cross-reset memory) and
|
|
1668
1688
|
// data-gsap-ghost (detached .leave clones) are intentionally KEPT.
|
|
1669
|
-
|
|
1689
|
+
qAll('[data-gsap-scroll],[data-gsap-setup],[data-gsap-pinned],[data-gsap-scroll-driven]').forEach((el) => {
|
|
1670
1690
|
delete el.dataset.gsapScroll
|
|
1671
1691
|
delete el.dataset.gsapSetup
|
|
1672
1692
|
delete el.dataset.gsapPinned
|
|
@@ -1681,7 +1701,7 @@ export default function initListeners() {
|
|
|
1681
1701
|
document.querySelectorAll('[data-gsap-radiate]').forEach((n) => n.remove())
|
|
1682
1702
|
cssTweens.forEach((t) => t?.kill())
|
|
1683
1703
|
cssTweens.length = 0
|
|
1684
|
-
|
|
1704
|
+
qAll(".typewriter, .scramble").forEach(el => {
|
|
1685
1705
|
// Preserved-region typewriters/scrambles stay as-is (already at
|
|
1686
1706
|
// their end state); finalize the rest so a mid-type/mid-scramble
|
|
1687
1707
|
// kill can't strand partial or garbled text where the next run's
|
package/index.d.ts
CHANGED
|
@@ -219,4 +219,8 @@ export function radiate(delay: number, target: TweenTarget, amount: number, dur:
|
|
|
219
219
|
export function hover(delay: number, target: TweenTarget, amount: number, dur: number, ease: string): any
|
|
220
220
|
export function marquee(target: TweenTarget, dir: string, duration: number, xOffset?: number, yOffset?: number, noRepeat?: boolean): any
|
|
221
221
|
export function flip(state: any, ease: string, dur: number): any
|
|
222
|
-
export function animatecss(target: TweenTarget, dur: number, delay: number, ease: string, propertyS: any, propertySValue: any, propertyE: any, propertyEValue: any): any
|
|
222
|
+
export function animatecss(target: TweenTarget, dur: number, delay: number, ease: string, propertyS: any, propertySValue: any, propertyE: any, propertyEValue: any): any
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
export default function Boot()
|
|
226
|
+
|
package/index.js
CHANGED
|
@@ -2,4 +2,5 @@ export { initAnimations, toggleAnimations, enableReducedMotion, disableReducedMo
|
|
|
2
2
|
export { default as initListeners, registerComplete } from './Listeners.js'
|
|
3
3
|
export { customAnims } from './CustomAnims.js'
|
|
4
4
|
export { defaults, animations, normalize } from './Config.js'
|
|
5
|
+
export { Boot } from './Boot.js'
|
|
5
6
|
export * from './Animations.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gclass-anims",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.16",
|
|
4
4
|
"description": "A Tailwind-style utility layer on top of GSAP. Framework-agnostic - works in vanilla JS, React, Vue, Svelte, or any bundler.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"Animations.js",
|
|
22
22
|
"Config.js",
|
|
23
23
|
"CustomAnims.js",
|
|
24
|
+
"Boot.js",
|
|
24
25
|
"README.md",
|
|
25
26
|
"LICENSE",
|
|
26
27
|
"CHANGELOG.md"
|