Fiks ScrollFade: sprettende scroll-hint overlappet en ekte pil-knapp
Bruker (skjermbilde): "Den sprettende ned-pilen fungerer ikke. Den ligger OPPÅ en annen nedpil." -- gjelder Retning-steget (Utslag/ Innspill) i score-registreringen, hvor "Kort"-knappen har sitt eget ArrowDown-ikon. To reelle feil i ScrollFade (round-detail.tsx): 1. ResizeObserver observerte scroll-BEHOLDEREN, ikke innholdet. Beholderens boks-størrelse er fast (flex-1), så den endrer seg aldri når man bytter steg i veiviseren -- observeren fyrte derfor ALDRI når et steg med reelt overflow-innhold ble vist. Hintet dukket rett og slett ikke opp der det trengtes (f.eks. nettopp Retning-steget). Rettet ved å observere innholds-diven i stedet. 2. Fade-/pil-overlayet er absolutt posisjonert over de siste 64px av scroll-området, uten noen garanti om at ekte innhold ikke havner der. På Retning-steget landet "Kort"-knappens egen pil nøyaktig i den sonen -- to piler oppå hverandre. Rettet med en usynlig 64px-buffer etter innholdet (samme høyde som overlayet), slik at overlayet aldri kan dekke et ekte element. hasMore-utregningen trekker fra bufferhøyden så den ikke gir falske positiver på kort innhold som uansett får plass. Scratch-verifisert (egen DB/rolle/MinIO/API/frontend-container, ekte bruker med fullt kølle-utvalg for å reprodusere nøyaktig samme rutenett som i brukerens skjermbilde): hintet vises korrekt når Retning-steget faktisk overflower, forsvinner korrekt ved reell bunn, "Kort"-knappen fullt synlig og utenfor overlay-sonen ved skrolling, lys+mørk, ingen konsollfeil. tsc --noEmit rent, 45/45 vitest grønt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
b704a9c378
commit
ee91d03514
1 changed files with 30 additions and 11 deletions
|
|
@ -6577,30 +6577,49 @@ function WizardSection({ title, children }: { title: string; children: React.Rea
|
|||
// finnes mer innhold under fold-linjen -- og skjuler seg av seg selv idet man
|
||||
// har scrollet helt ned. Fanger både resize og innholdsendringer (ulikt
|
||||
// stat_level/par gir ulik høyde) via en ResizeObserver på selve scrollboksen.
|
||||
// Høyden (px) på fade-/piloverlayet under -- MÅ matche spacer-diven sin
|
||||
// h-16 og trekkes fra i hasMore-utregningen, se begrunnelse der.
|
||||
const SCROLL_FADE_HEIGHT_PX = 64
|
||||
|
||||
function ScrollFade({ children, className }: { children: React.ReactNode; className?: string }) {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
const [hasMore, setHasMore] = useState(false)
|
||||
useEffect(() => {
|
||||
const el = ref.current
|
||||
if (!el) return
|
||||
const scrollEl = scrollRef.current
|
||||
const contentEl = contentRef.current
|
||||
if (!scrollEl || !contentEl) return
|
||||
const update = () => {
|
||||
// 4px slingring: unngår at en sub-piksel-rest holder hintet i live
|
||||
// når man i praksis ER nederst.
|
||||
setHasMore(el.scrollTop + el.clientHeight < el.scrollHeight - 4)
|
||||
// Trekker fra spacer-divens egen høyde (samme SCROLL_FADE_HEIGHT_PX)
|
||||
// i tillegg til 4px slingring -- uten dette ville "hasMore" blitt
|
||||
// sant utelukkende fordi spaceren selv gjør scrollHeight større, selv
|
||||
// når ALT ekte innhold allerede er synlig (falskt positivt hint).
|
||||
setHasMore(scrollEl.scrollTop + scrollEl.clientHeight < scrollEl.scrollHeight - SCROLL_FADE_HEIGHT_PX - 4)
|
||||
}
|
||||
update()
|
||||
el.addEventListener("scroll", update, { passive: true })
|
||||
scrollEl.addEventListener("scroll", update, { passive: true })
|
||||
// Observerer INNHOLDS-diven, IKKE scroll-beholderen selv --
|
||||
// beholderens egen boks-størrelse er fast (flex-1, bundet av
|
||||
// veiviserens layout), den endrer seg ALDRI når man bytter steg. Uten
|
||||
// dette ble "hasMore" aldri regnet på nytt ved stegbytte -- den
|
||||
// sprettende pilen dukket rett og slett ikke opp på steg som faktisk
|
||||
// trengte scrolling (f.eks. "Retning"-steget med kølle-rutenett).
|
||||
const ro = new ResizeObserver(update)
|
||||
ro.observe(el)
|
||||
ro.observe(contentEl)
|
||||
return () => {
|
||||
el.removeEventListener("scroll", update)
|
||||
scrollEl.removeEventListener("scroll", update)
|
||||
ro.disconnect()
|
||||
}
|
||||
}, [])
|
||||
return (
|
||||
<div className="relative flex min-h-0 flex-1 flex-col">
|
||||
<div ref={ref} className={className}>
|
||||
{children}
|
||||
<div ref={scrollRef} className={className}>
|
||||
<div ref={contentRef}>{children}</div>
|
||||
{/* Usynlig buffer, SAMME høyde som fade-/piloverlayet -- garanterer at
|
||||
overlayet aldri dekker et ekte, interaktivt element (f.eks. en
|
||||
retningsknapp med sin egen pil-ikon nederst i steget). Uten denne
|
||||
kunne den sprettende pilen havne rett oppå en annen pil. */}
|
||||
<div aria-hidden="true" className="h-16 shrink-0" />
|
||||
</div>
|
||||
{/* Rent dekorativt -- selve scrollingen er fullt mulig uten dette. */}
|
||||
<div
|
||||
|
|
|
|||
Loading…
Reference in a new issue