fix(stammbaum): SVG node font 14→16px and reliable keyboard focus ring

CSS box-shadow rings (focus-visible:ring-*) are invisible inside SVG.
Replace with a conditional <rect> drawn at -3px offset that renders in
all browsers. Name font-size bumped from 14 to 16px for the 60+
transcriber audience (WCAG readability, Leonie medium concerns).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-28 13:01:58 +02:00
committed by marcel
parent ea97bdd869
commit 93f4a00032

View File

@@ -286,6 +286,8 @@ function nodeCenter(id: string): { x: number; y: number } | null {
return { x: p.x + NODE_W / 2, y: p.y + NODE_H / 2 };
}
let focusedId = $state<string | null>(null);
function handleNodeKey(event: KeyboardEvent, id: string) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
@@ -479,6 +481,7 @@ const parentLinks = $derived.by<ParentLinks>(() => {
{@const pos = layout.positions.get(node.id)}
{#if pos}
{@const isSelected = selectedId === node.id}
{@const isFocused = focusedId === node.id}
<g
role="button"
tabindex="0"
@@ -489,8 +492,22 @@ const parentLinks = $derived.by<ParentLinks>(() => {
transform="translate({pos.x}, {pos.y})"
onclick={() => onSelect(node.id)}
onkeydown={(e) => handleNodeKey(e, node.id)}
class="cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
onfocus={() => (focusedId = node.id)}
onblur={() => (focusedId = null)}
class="cursor-pointer focus:outline-none"
>
{#if isFocused}
<rect
x="-3"
y="-3"
width={NODE_W + 6}
height={NODE_H + 6}
rx="6"
fill="none"
stroke="var(--c-focus-ring)"
stroke-width="2"
/>
{/if}
<rect
width={NODE_W}
height={NODE_H}
@@ -504,10 +521,10 @@ const parentLinks = $derived.by<ParentLinks>(() => {
{/if}
<text
x={NODE_W / 2}
y={NODE_H / 2 - 4}
y={NODE_H / 2 - 6}
text-anchor="middle"
font-family="serif"
font-size="14"
font-size="16"
fill={isSelected ? 'var(--c-primary-fg)' : 'var(--c-ink)'}
>
{node.displayName}