Compare commits
2 commits
b704a9c378
...
03579c9d11
| Author | SHA1 | Date | |
|---|---|---|---|
| 03579c9d11 | |||
| ee91d03514 |
3 changed files with 89 additions and 12 deletions
|
|
@ -5931,7 +5931,37 @@ Rettet til `grid grid-cols-3` (samme mønster som `NumberPicker` allerede
|
||||||
brukte). Alle FIRE andre `ChoiceRow`-bruk i filen (Kjønn,
|
brukte). Alle FIRE andre `ChoiceRow`-bruk i filen (Kjønn,
|
||||||
Statistikk-nivå × 2) har nøyaktig 3 valg fra før — visuelt uendret for
|
Statistikk-nivå × 2) har nøyaktig 3 valg fra før — visuelt uendret for
|
||||||
dem, kun 6-alternativs-tilfellet endrer seg. Browserverifisert lys+mørk.
|
dem, kun 6-alternativs-tilfellet endrer seg. Browserverifisert lys+mørk.
|
||||||
Committet (`17e4793`), IKKE deployet ennå i skrivende stund.
|
Committet (`17e4793`), deployet 2026-08-11 sammen med tagging-runden
|
||||||
|
(se ADR-063).
|
||||||
|
|
||||||
|
**Oppfølging 2026-08-11 — punkt 6 (ScrollFade) hadde TO reelle feil,
|
||||||
|
brukeren rapporterte via skjermbilde av Retning-steget:** "Den
|
||||||
|
sprettende ned-pilen fungerer ikke. Den ligger OPPÅ en annen nedpil."
|
||||||
|
|
||||||
|
1. `ResizeObserver` observerte scroll-BEHOLDEREN (`el`), ikke
|
||||||
|
innholdet. Beholderens boks-størrelse er fast (`flex-1`, bundet av
|
||||||
|
veiviserens layout) og endrer seg ALDRI når man bytter steg —
|
||||||
|
observeren fyrte derfor aldri når et steg med reelt overflow ble
|
||||||
|
vist, og `hasMore` ble stående på sin opprinnelige (ofte `false`)
|
||||||
|
verdi. Hintet virket rett og slett ikke der det trengtes, nøyaktig
|
||||||
|
det brukeren rapporterte. Rettet ved å observere en egen
|
||||||
|
`contentRef`-div rundt `children` i stedet for beholderen selv.
|
||||||
|
2. Fade-/piloverlayet er absolutt posisjonert over de siste 64px av
|
||||||
|
scroll-området uten noen garanti om at ekte innhold ikke havner
|
||||||
|
der. På Retning-steget (med fullt kølle-utvalg satt på testbrukeren
|
||||||
|
for å reprodusere brukerens eksakte rutenett) landet nettopp
|
||||||
|
"Kort"-knappens eget `ArrowDown`-ikon i den sonen — to piler oppå
|
||||||
|
hverandre, akkurat som beskrevet. Rettet med en usynlig 64px-buffer
|
||||||
|
(`SCROLL_FADE_HEIGHT_PX`) etter innholdet; `hasMore`-utregningen
|
||||||
|
trekker fra samme høyde så bufferen selv aldri gir et falskt
|
||||||
|
positivt hint på kort innhold.
|
||||||
|
|
||||||
|
Browserverifisert (samme reproduksjon: full kølle-liste for å tvinge
|
||||||
|
frem overflow): hintet vises korrekt (`opacity: 1`) når steget faktisk
|
||||||
|
overflower, forsvinner korrekt (`opacity: 0`) ved reell bunn, "Kort"
|
||||||
|
fullt synlig og klar av overlay-sonen ved skrolling, lys+mørk, ingen
|
||||||
|
konsollfeil. `tsc --noEmit` rent, 45/45 vitest grønt. Committet
|
||||||
|
(`ee91d03`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
28
CHANGELOG.md
28
CHANGELOG.md
|
|
@ -10505,3 +10505,31 @@ Neste steg:
|
||||||
tidligere upubliserte ChoiceRow-fiksen (`17e4793`). Ren omstart,
|
tidligere upubliserte ChoiceRow-fiksen (`17e4793`). Ren omstart,
|
||||||
ingen feil i containerloggene, ingen konsollfeil på
|
ingen feil i containerloggene, ingen konsollfeil på
|
||||||
`https://teecup.golf/logg-inn` etter omstart.
|
`https://teecup.golf/logg-inn` etter omstart.
|
||||||
|
|
||||||
|
73. **Fiks: ScrollFade-scrollhintet (fra ADR-062 punkt 6) hadde to
|
||||||
|
reelle feil — 2026-08-11, se oppfølgingsnotatet i ADR-062.**
|
||||||
|
Bruker sendte skjermbilde: "Den sprettende ned-pilen fungerer
|
||||||
|
ikke. Den ligger OPPÅ en annen nedpil."
|
||||||
|
|
||||||
|
To separate rotårsaker i samme `ScrollFade`-komponent
|
||||||
|
(`round-detail.tsx`): (1) `ResizeObserver` observerte scroll-
|
||||||
|
beholderen i stedet for innholdet — beholderens boksstørrelse er
|
||||||
|
fast, så observeren fyrte aldri ved stegbytte i veiviseren, og
|
||||||
|
hintet virket dermed rett og slett ikke på steg med reelt
|
||||||
|
overflow-innhold (som Retning-steget). Rettet ved å observere en
|
||||||
|
egen `contentRef`-div rundt innholdet i stedet for beholderen selv.
|
||||||
|
(2) Fade-/piloverlayet (absolutt posisjonert, siste 64px av
|
||||||
|
scroll-området) hadde ingen garanti mot å dekke ekte innhold —
|
||||||
|
på Retning-steget landet "Kort"-knappens eget `ArrowDown`-ikon i
|
||||||
|
akkurat den sonen, to piler oppå hverandre. Rettet med en usynlig
|
||||||
|
64px-buffer etter innholdet (`hasMore`-utregningen trekker fra
|
||||||
|
samme høyde for å unngå falske positiver på kort innhold).
|
||||||
|
|
||||||
|
**Verifisert:** Full scratch-stack, testbruker med fullt
|
||||||
|
kølle-utvalg for å reprodusere nøyaktig samme rutenett som i
|
||||||
|
brukerens skjermbilde. Bekreftet: hintet vises (`opacity: 1`) når
|
||||||
|
steget faktisk overflower, forsvinner (`opacity: 0`) ved reell
|
||||||
|
bunn, "Kort" fullt synlig og klar av overlay-sonen ved skrolling,
|
||||||
|
lys+mørk, ingen konsollfeil. `tsc --noEmit` rent, 45/45 vitest
|
||||||
|
grønt. `teecup_db` urørt (ren frontend-endring). Committet
|
||||||
|
(`ee91d03`), **ikke rullet ut ennå**.
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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
|
// har scrollet helt ned. Fanger både resize og innholdsendringer (ulikt
|
||||||
// stat_level/par gir ulik høyde) via en ResizeObserver på selve scrollboksen.
|
// 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 }) {
|
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)
|
const [hasMore, setHasMore] = useState(false)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = ref.current
|
const scrollEl = scrollRef.current
|
||||||
if (!el) return
|
const contentEl = contentRef.current
|
||||||
|
if (!scrollEl || !contentEl) return
|
||||||
const update = () => {
|
const update = () => {
|
||||||
// 4px slingring: unngår at en sub-piksel-rest holder hintet i live
|
// Trekker fra spacer-divens egen høyde (samme SCROLL_FADE_HEIGHT_PX)
|
||||||
// når man i praksis ER nederst.
|
// i tillegg til 4px slingring -- uten dette ville "hasMore" blitt
|
||||||
setHasMore(el.scrollTop + el.clientHeight < el.scrollHeight - 4)
|
// 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()
|
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)
|
const ro = new ResizeObserver(update)
|
||||||
ro.observe(el)
|
ro.observe(contentEl)
|
||||||
return () => {
|
return () => {
|
||||||
el.removeEventListener("scroll", update)
|
scrollEl.removeEventListener("scroll", update)
|
||||||
ro.disconnect()
|
ro.disconnect()
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<div className="relative flex min-h-0 flex-1 flex-col">
|
<div className="relative flex min-h-0 flex-1 flex-col">
|
||||||
<div ref={ref} className={className}>
|
<div ref={scrollRef} className={className}>
|
||||||
{children}
|
<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>
|
</div>
|
||||||
{/* Rent dekorativt -- selve scrollingen er fullt mulig uten dette. */}
|
{/* Rent dekorativt -- selve scrollingen er fullt mulig uten dette. */}
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue