import React from 'react'; import type { TokenPath } from '../../../shared/types/tokenPath'; import { tokenPathPolyline } from '../../../shared/types/tokenPath'; import type { SceneNpcToken, SceneToken } from '../../../shared/types'; import { tokenPathKey, type TokenPathSessionState } from '../../../shared/types/tokenPathSession'; import styles from './TokenPathsOverlay.module.css'; type Viewport = { x: number; y: number; w: number; h: number }; type PathItem = { key: string; path: TokenPath; emphasized?: boolean; }; type Props = { tokens: readonly SceneToken[]; npcTokens?: readonly SceneNpcToken[]; viewport: Viewport | null; /** control/editor: always; presentation: only presentationVisible */ mode: 'always' | 'presentation'; pathSession?: TokenPathSessionState | null; /** Highlight path currently edited */ emphasizeKey?: string | null; }; function toSvgPoints(path: TokenPath, viewport: Viewport): string { const pts = tokenPathPolyline(path); return pts .map((p) => { const x = viewport.x + p.nx * viewport.w; const y = viewport.y + p.ny * viewport.h; return `${x},${y}`; }) .join(' '); } export function TokenPathsOverlay({ tokens, npcTokens = [], viewport, mode, pathSession = null, emphasizeKey = null, }: Props) { if (!viewport) return null; const items: PathItem[] = []; for (const t of tokens) { if (!t.path || t.path.points.length < 2) continue; const key = tokenPathKey('token', String(t.id)); if (mode === 'presentation' && !pathSession?.presentationVisible[key]) continue; items.push({ key, path: t.path, emphasized: emphasizeKey === key }); } for (const t of npcTokens) { if (!t.path || t.path.points.length < 2) continue; const key = tokenPathKey('npcToken', String(t.id)); if (mode === 'presentation' && !pathSession?.presentationVisible[key]) continue; items.push({ key, path: t.path, emphasized: emphasizeKey === key }); } if (items.length === 0) return null; return ( {items.map((item) => { const pts = toSvgPoints(item.path, viewport); if (!pts) return null; const first = item.path.points[0]!; const fx = viewport.x + first.nx * viewport.w; const fy = viewport.y + first.ny * viewport.h; return ( {item.path.closed ? ( ) : null} ); })} ); }