- SilkBackground: beim Aufräumen nur Programm/Buffer löschen statt den WebGL-Kontext zu verwerfen. React Strict Mode mountet im Dev-Modus zweimal, der zweite Mount bekam sonst einen verlorenen Kontext und der Hintergrund blieb leer. Kontextverlust/-wiederherstellung wird jetzt behandelt. - useFitText: nur auf Breitenänderungen reagieren und die Anpassung in den nächsten Frame verschieben, damit keine "ResizeObserver loop"-Fehler entstehen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KBHsCnWNXAB2Le3gAEsivF
46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
import { useLayoutEffect, useRef } from 'react'
|
|
|
|
/**
|
|
* Skaliert die Schriftgröße eines einzeiligen Elements so, dass es genau die Breite
|
|
* seines Elternelements ausfüllt (randlose Wortmarke).
|
|
*/
|
|
export function useFitText<T extends HTMLElement>(max = 400) {
|
|
const ref = useRef<T>(null)
|
|
|
|
useLayoutEffect(() => {
|
|
const el = ref.current
|
|
const parent = el?.parentElement
|
|
if (!el || !parent) return
|
|
|
|
const fit = () => {
|
|
el.style.fontSize = '100px'
|
|
const natural = el.scrollWidth
|
|
const available = parent.clientWidth
|
|
if (!natural || !available) return
|
|
el.style.fontSize = `${Math.min(max, (100 * available) / natural) * 0.995}px`
|
|
}
|
|
|
|
fit()
|
|
document.fonts?.ready.then(fit)
|
|
|
|
let frame = 0
|
|
let lastWidth = parent.clientWidth
|
|
const ro = new ResizeObserver(() => {
|
|
// Höhenänderungen entstehen durch die Schriftgröße selbst — nur auf neue Breiten reagieren
|
|
const width = parent.clientWidth
|
|
if (width === lastWidth) return
|
|
lastWidth = width
|
|
// außerhalb der Observer-Runde anpassen, sonst meldet der Browser eine Resize-Schleife
|
|
cancelAnimationFrame(frame)
|
|
frame = requestAnimationFrame(fit)
|
|
})
|
|
ro.observe(parent)
|
|
return () => {
|
|
cancelAnimationFrame(frame)
|
|
ro.disconnect()
|
|
}
|
|
}, [max])
|
|
|
|
return ref
|
|
}
|