fix(stammbaum): seed gutter media-query state synchronously (#689)
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m32s
CI / OCR Service Tests (pull_request) Successful in 23s
CI / Backend Unit Tests (pull_request) Successful in 3m39s
CI / fail2ban Regex (pull_request) Failing after 45s
CI / Semgrep Security Scan (pull_request) Successful in 24s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m4s
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m32s
CI / OCR Service Tests (pull_request) Successful in 23s
CI / Backend Unit Tests (pull_request) Successful in 3m39s
CI / fail2ban Regex (pull_request) Failing after 45s
CI / Semgrep Security Scan (pull_request) Successful in 24s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m4s
CI flagged two browser tests:
- "renders a G{n} label per occupied generation row …"
- "wraps the visible G3 text inside an aria-labelled group …"
Both queried g[role="text"] and got an empty array. Root cause:
isMdOrUp was initialised to false and only flipped to true inside a
$effect — but $effect runs after the first render, so the test's
post-render DOM scan saw the pre-effect (gutter-absent) state.
Seed the rune synchronously from window.matchMedia(...).matches when
window is available; SSR still picks the false branch and hydrates
without a layout flash. The effect now only attaches the change
listener for subsequent resizes.
Refs #689
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -30,11 +30,17 @@ const layout = $derived.by<Layout>(() => buildLayout(nodes, edges));
|
|||||||
// too costly on a 320 px screen).
|
// too costly on a 320 px screen).
|
||||||
const GUTTER_WIDTH_DESKTOP = 100;
|
const GUTTER_WIDTH_DESKTOP = 100;
|
||||||
const GUTTER_MEDIA_QUERY = '(min-width: 768px)';
|
const GUTTER_MEDIA_QUERY = '(min-width: 768px)';
|
||||||
let isMdOrUp = $state(false);
|
// Seed synchronously so the first paint already has the right gutter state —
|
||||||
|
// otherwise the test (and a brief flash on real CSR mount) would see the
|
||||||
|
// pre-effect false. SSR has no window; the gutter stays hidden until hydrate.
|
||||||
|
let isMdOrUp = $state(
|
||||||
|
typeof window !== 'undefined' && typeof window.matchMedia === 'function'
|
||||||
|
? window.matchMedia(GUTTER_MEDIA_QUERY).matches
|
||||||
|
: false
|
||||||
|
);
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
|
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
|
||||||
const mq = window.matchMedia(GUTTER_MEDIA_QUERY);
|
const mq = window.matchMedia(GUTTER_MEDIA_QUERY);
|
||||||
isMdOrUp = mq.matches;
|
|
||||||
const handler = (e: MediaQueryListEvent) => (isMdOrUp = e.matches);
|
const handler = (e: MediaQueryListEvent) => (isMdOrUp = e.matches);
|
||||||
mq.addEventListener('change', handler);
|
mq.addEventListener('change', handler);
|
||||||
return () => mq.removeEventListener('change', handler);
|
return () => mq.removeEventListener('change', handler);
|
||||||
|
|||||||
Reference in New Issue
Block a user