gclass-anims 1.0.0-beta.17 → 1.0.0-beta.19

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 CHANGED
@@ -147,18 +147,29 @@ export function initAnimations() {
147
147
  if (bootCleanup) { bootCleanup(); bootCleanup = null }
148
148
  if (bootStyle) { bootStyle.remove(); bootStyle = null; document.documentElement.classList.remove('gclass-booting') }
149
149
 
150
- const bootEls = typeof document !== 'undefined' ? document.querySelectorAll(".boot-up") : []
150
+ const hideBootEls = (els) => {
151
+ // React-safe: don't el.remove() - React owns the nodes and will throw
152
+ // insertBefore/removeChild on next commit if we mutate outside React.
153
+ // Hiding keeps React's tree intact but visually removes boot screen.
154
+ els.forEach(el => {
155
+ el.style.display = 'none'
156
+ el.setAttribute('hidden', '')
157
+ el.setAttribute('data-gclass-boot-hidden', '1')
158
+ })
159
+ }
160
+
161
+ const bootEls = typeof document !== 'undefined' ? [...document.querySelectorAll(".boot-up")].filter(el => !el.hasAttribute('data-gclass-boot-hidden')) : []
151
162
  if (!bootEls.length) {
152
163
  // no .boot-up -> completely skip boot
153
164
  } else if (bootEls.length > 1) {
154
165
  console.error(`[initAnimations] Multiple .boot-up elements detected (${bootEls.length}) - skipping all boot animations`, bootEls)
155
- bootEls.forEach(el => el.remove())
166
+ hideBootEls(bootEls)
156
167
  hasBooted = true
157
168
  // fall through to normal initListeners without pausing DOM
158
169
  } else if (hasBooted && !bootTimeout) {
159
170
  // path change after already booted (SPA navigation) - skip boot, hard reload resets hasBooted
160
171
  console.log(`[initAnimations] skipping boot on path change (already booted)`, bootEls)
161
- bootEls.forEach(el => el.remove())
172
+ hideBootEls(bootEls)
162
173
  hasBooted = true
163
174
  // fall through
164
175
  } else {
@@ -188,11 +199,11 @@ export function initAnimations() {
188
199
  bootTimeout = setTimeout(() => {
189
200
  const bootEndCls = [...bootEl.classList].find(c => c.startsWith('boot-end-'))
190
201
  if (!bootEndCls) {
191
- // no boot-end -> skip exit animation, just remove
202
+ // no boot-end -> skip exit animation, just hide
192
203
  bootCleanup?.(); bootCleanup = null
193
204
  document.documentElement.classList.remove('gclass-booting')
194
205
  bootStyle?.remove(); bootStyle = null
195
- bootEls.forEach(el => el.remove())
206
+ hideBootEls(bootEls)
196
207
  bootTimeout = null
197
208
  cleanup = initListeners()
198
209
  return
@@ -211,7 +222,7 @@ export function initAnimations() {
211
222
  bootCleanup?.(); bootCleanup = null
212
223
  document.documentElement.classList.remove('gclass-booting')
213
224
  bootStyle?.remove(); bootStyle = null
214
- bootEls.forEach(el => el.remove())
225
+ hideBootEls(bootEls)
215
226
  bootTimeout = null
216
227
  cleanup = initListeners()
217
228
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to `gclass-anims` will be documented in this file.
4
4
 
5
+ ## [1.0.0-beta.19] - 2026-9-1
6
+ - Fixed the SplitText animations formatting and removed Boot.js
7
+
8
+ ## [1.0.0-beta.18] - 2026-9-1
9
+ - Hopefully finally fixed `.boot-up` properly skipping on path changes
10
+
5
11
  ## [1.0.0-beta.17] - 2026-9-1
6
12
  - Fixed the `.boot-up` class firing on every path change
7
13
 
package/Listeners.js CHANGED
@@ -484,10 +484,7 @@ export default function initListeners(root = document) {
484
484
  // would render it in its connecting form instead of its correct END form),
485
485
  // but it should still be split into its own span so it animates too.
486
486
  const RTL_LETTER = /[\u0621-\u064A\u066E-\u06D5\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/
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, {
487
+ const getRTLCharSplit = (el) => new SplitText(el, {
491
488
  type: "words",
492
489
  linesClass: "gsap-line",
493
490
  wordsClass: "gsap-word",
@@ -570,7 +567,6 @@ export default function initListeners(root = document) {
570
567
  self.words.length = 0
571
568
  },
572
569
  })
573
- }
574
570
 
575
571
  // Flex targets can't be split directly: the split parts would become
576
572
  // flex ITEMS, so justify-content/gap would apply per letter, whitespace-
@@ -611,22 +607,39 @@ export default function initListeners(root = document) {
611
607
  }
612
608
 
613
609
  const getSplit = (el, gran) => {
614
- if (el.style) el.style.whiteSpace = "pre-wrap"
615
610
  let s = splitCache.get(el)
616
611
  const rtlChars = gran === "chars" && isRTLText(el)
617
612
  const key = rtlChars ? "rtl-chars" : gran
618
613
  if (!s || s.granularity !== key) {
619
614
  if (s) revertSplitInstance(s)
615
+ const hasN = el.textContent.includes('\n')
616
+ // only set pre-wrap if element actually contains a newline, so \n renders without breaking other SplitText (flex/lines)
617
+ if (hasN && el.style) el.style.whiteSpace = 'pre-wrap'
620
618
  s = rtlChars
621
619
  ? getRTLCharSplit(el)
622
620
  : new SplitText(el, {
623
621
  type: gran,
624
- tag: "span",
625
- reduceWhiteSpace: false,
626
-
622
+ reduceWhiteSpace: hasN ? false : undefined,
627
623
  linesClass: "gsap-line",
628
624
  wordsClass: "gsap-word",
629
625
  charsClass: "gsap-char",
626
+ onSplit(self) {
627
+ // make \n actually break line DURING split (not just after revert)
628
+ for (const c of self.chars || []) {
629
+ if (c.textContent === '\n') {
630
+ c.textContent = ''
631
+ c.style.display = 'block'
632
+ c.style.width = '100%'
633
+ c.style.height = '0'
634
+ }
635
+ }
636
+ // also handle words split where \n is between words
637
+ for (const w of self.words || []) {
638
+ if (w.textContent.includes('\n')) {
639
+ w.style.whiteSpace = 'pre-wrap'
640
+ }
641
+ }
642
+ }
630
643
  })
631
644
  s._gcFlexUnwrap = wrapFlexTarget(el)
632
645
  s.granularity = key
@@ -642,8 +655,10 @@ export default function initListeners(root = document) {
642
655
  // does this automatically for animated elements; Firefox is
643
656
  // conservative and otherwise repaints these inline-block parts on the
644
657
  // main thread every frame, which is what makes split-text lag there.
658
+ // A: keep inline flow so <strong> etc stays inline during split
645
659
  for (let i = 0; i < parts.length; i++) {
646
660
  parts[i].style.willChange = "transform, opacity"
661
+ if (gran === "chars" || gran === "words") parts[i].style.display = "inline-block"
647
662
  }
648
663
  return parts
649
664
  }
package/index.d.ts CHANGED
@@ -27,8 +27,9 @@ export function registerComplete(name: string, fn: CompleteHandler): CompleteHan
27
27
  /**
28
28
  * Boot the engine directly, bypassing AnimToggle. Returns a teardown function
29
29
  * that removes all listeners/observers/tweens created by this run.
30
+ * Pass a root to scope to that subtree (used for .boot-up).
30
31
  */
31
- export default function initListeners(): () => void
32
+ export default function initListeners(root?: Document | HTMLElement): () => void
32
33
 
33
34
  // --- onComplete config -----------------------------------------------------
34
35
 
@@ -123,6 +124,7 @@ export interface Defaults {
123
124
  minTextPartDuration: number
124
125
  revealDelay: number
125
126
  characterlist: string
127
+ bootTime: number
126
128
  }
127
129
 
128
130
  /** Global timing / ease defaults (edit to tweak global behaviour). */
@@ -221,6 +223,3 @@ export function marquee(target: TweenTarget, dir: string, duration: number, xOff
221
223
  export function flip(state: any, ease: string, dur: number): any
222
224
  export function animatecss(target: TweenTarget, dur: number, delay: number, ease: string, propertyS: any, propertySValue: any, propertyE: any, propertyEValue: any): any
223
225
 
224
-
225
- export default function Boot()
226
-
package/index.js CHANGED
@@ -2,5 +2,4 @@ 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'
6
5
  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.17",
3
+ "version": "1.0.0-beta.19",
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,7 +21,6 @@
21
21
  "Animations.js",
22
22
  "Config.js",
23
23
  "CustomAnims.js",
24
- "Boot.js",
25
24
  "README.md",
26
25
  "LICENSE",
27
26
  "CHANGELOG.md"
package/Boot.js DELETED
@@ -1,12 +0,0 @@
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