@ryandymock/ancestor-tree
Version:
Interactive ancestor tree React component built with ReactFlow, featuring expandable generations and customizable UI controls
1 lines • 57.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/hooks/useAncestorTree.ts","../src/components/PersonCard.tsx","../src/components/PersonNode.tsx","../src/components/CoupleNode.tsx","../src/components/CoupleCard.tsx","../src/hooks/useCoupleExpansion.ts","../src/components/AncestorTree.tsx"],"names":["useAncestorTree","people","rootId","defaultDepth","expansionPath","setExpansionPath","useState","generations","useMemo","cols","root","spouse","parentIds","pid","grandparents","p","id","parents","gparents","par","handleSelect","useCallback","gen","expIndex","prev","handleExpand","personId","newPath","PersonCard","person","isEdge","onClick","registerPosition","formatPersonSubtitle","personNodeWidth","ref","React","jsx","Card","CardActionArea","jsxs","CardContent","Avatar","Typography","IconButton","ArrowForwardIosIcon","PersonNode","data","onPersonClick","handleClick","Handle","Position","PersonNode_default","memo","CoupleCard","partner1","partner2","coupleNodeWidth","renderPersonRow","subtitle","lifeText","Box","CoupleNode","onExpand","CoupleNode_default","useCoupleExpansion","expandedId","setExpandedId","token","setToken","t","LAYOUT_CONFIG","AncestorTree","callbacks","uiControls","expand","showControls","showMiniMap","showBackground","enablePan","enableZoom","enableFitView","backgroundColor","nodeHeight","verticalGaps","defaultVerticalGap","layoutConfig","baseXPositions","widthDiff","adjustedXPositions","x","index","flowKey","coupleToPartnersRef","useRef","handleCoupleExpansion","coupleId","wasExpanded","couple","ViewportChangeHandler","useOnViewportChange","y","zoom","nodes","edges","personToCouple","coupleToPartners","generation","generationIndex","generationNodes","mappings","buildGenerationNodes","baseEdges","buildBaseGenerationEdges","expandedResult","buildExpandedGenerations","validNodeIds","node","validEdges","edge","finalEdges","filterEdgesByExpansionState","ReactFlowProvider","ReactFlow","ConnectionMode","Background","Controls","MiniMap","getGenerationLayout","coupleCount","xPosition","gap","startY","i","coupleIndex","yPosition","edgeSet","processedCouples","coupleNode","dadEdge","createParentEdge","momEdge","handleType","parent1","parent2","targetCouple","existingNodes","coupleToPartners_new","selectedDad","selectedMom","generation4","buildGenerationFromParents","generation5","expandedGenerations","generation4CoupleIds","selectedNode","anchorY","totalHeight","generation4Edges","buildGeneration4ToGeneration5Edges","result","parent","parentId","sourceId","partner","edgeId","sourceNode","targetNode"],"mappings":"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","file":"index.mjs","sourcesContent":["import { useState, useMemo, useCallback } from \"react\";\nimport { PeopleIndex, Person } from \"../types/person\";\n\nexport function useAncestorTree(\n people: PeopleIndex,\n rootId: string,\n defaultDepth = 2\n) {\n const [expansionPath, setExpansionPath] = useState<string[]>([]);\n\n const generations: Person[][] = useMemo(() => {\n const cols: Person[][] = [];\n\n // Guard against invalid rootId\n const root = people[rootId];\n if (!root) {\n // If the root person cannot be found, return an empty generation list\n // so the calling component can decide how to handle the missing data.\n return cols;\n }\n\n const spouse = root.spouseId ? people[root.spouseId] : undefined;\n\n // 0: root + spouse\n cols.push(spouse ? [root, spouse] : [root]);\n\n // 1: parents (root & spouse)\n const parentIds = [\n ...(root.parentIds ?? []),\n ...(spouse?.parentIds ?? []),\n ].filter((pid): pid is string => pid !== undefined);\n cols.push(parentIds.map((pid) => people[pid]).filter(Boolean));\n\n // 2: grandparents\n const grandparents = cols[1]\n .flatMap((p) => p.parentIds ?? [])\n .filter((pid): pid is string => pid !== undefined)\n .map((pid) => people[pid])\n .filter(Boolean);\n cols.push(grandparents);\n\n // additional drilled generations\n expansionPath.forEach((id) => {\n const p = people[id];\n if (!p?.parentIds) return;\n const parents = p.parentIds\n .filter((pid): pid is string => pid !== undefined)\n .map((pid) => people[pid])\n .filter(Boolean);\n cols.push(parents);\n const gparents = parents\n .flatMap((par) => par.parentIds ?? [])\n .filter((pid): pid is string => pid !== undefined)\n .map((pid) => people[pid])\n .filter(Boolean);\n cols.push(gparents);\n });\n\n return cols;\n }, [people, rootId, expansionPath, defaultDepth]);\n\n const handleSelect = useCallback(\n (gen: number) => {\n if (gen <= defaultDepth) {\n setExpansionPath([]);\n } else {\n const expIndex = Math.floor((gen - (defaultDepth + 1)) / 2);\n setExpansionPath((prev) => prev.slice(0, expIndex + 1));\n }\n },\n [defaultDepth]\n );\n\n const handleExpand = useCallback(\n (personId: string, gen: number) => {\n const person = people[personId];\n if (!person?.parentIds?.length) return;\n let newPath: string[];\n if (gen === defaultDepth) {\n newPath = [personId];\n } else {\n const expIndex = Math.floor((gen - (defaultDepth + 1)) / 2);\n newPath = [...expansionPath.slice(0, expIndex), personId];\n }\n setExpansionPath(newPath);\n },\n [people, expansionPath, defaultDepth]\n );\n\n return { generations, handleSelect, handleExpand };\n}\n","import {\n Card,\n CardActionArea,\n CardContent,\n Avatar,\n Typography,\n IconButton,\n} from \"@mui/material\";\nimport ArrowForwardIosIcon from \"@mui/icons-material/ArrowForwardIos\";\nimport React from \"react\";\n\nimport { Person } from \"../types/person\";\n\ninterface Props {\n person: Person;\n isEdge: boolean;\n onClick: () => void;\n registerPosition?: (id: string, rect: DOMRect) => void;\n formatPersonSubtitle?: (person: Person) => string;\n personNodeWidth?: number;\n}\n\nexport default function PersonCard({\n person,\n isEdge,\n onClick,\n registerPosition,\n formatPersonSubtitle,\n personNodeWidth = 160,\n}: Props) {\n const ref = React.useRef<HTMLDivElement>(null);\n\n React.useLayoutEffect(() => {\n if (ref.current && registerPosition) {\n registerPosition(person.id, ref.current.getBoundingClientRect());\n }\n });\n\n return (\n <Card variant=\"outlined\" sx={{ my: 1, width: personNodeWidth }} ref={ref}>\n <CardActionArea onClick={onClick}>\n <CardContent\n sx={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n position: \"relative\",\n }}\n >\n <Avatar\n src={person.imageUrl}\n alt={person.name}\n sx={{ width: 56, height: 56, mb: 1 }}\n />\n <Typography\n variant=\"subtitle2\"\n align=\"center\"\n sx={{\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n width: \"100%\",\n px: 1, // Add horizontal padding to prevent text from touching edges\n }}\n >\n {person.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {formatPersonSubtitle\n ? formatPersonSubtitle(person)\n : person.birth || person.death\n ? `${person.birth ?? \"–\"} – ${person.death ?? \"\"}`\n : \"\"}\n </Typography>\n\n {isEdge && (\n <IconButton\n size=\"small\"\n sx={{ position: \"absolute\", right: 4, top: 4 }}\n aria-label=\"expand ancestors\"\n >\n <ArrowForwardIosIcon fontSize=\"inherit\" />\n </IconButton>\n )}\n </CardContent>\n </CardActionArea>\n </Card>\n );\n}\n","import { memo } from \"react\";\nimport { Handle, Position } from \"reactflow\";\nimport PersonCard from \"./PersonCard\";\nimport { Person } from \"../types/person\";\n\ninterface Props {\n data: {\n person: Person;\n isEdge: boolean;\n onPersonClick?: (person: Person) => void;\n registerPosition?: (id: string, rect: DOMRect) => void;\n formatPersonSubtitle?: (person: Person) => string;\n personNodeWidth?: number;\n };\n}\n\nfunction PersonNode({ data }: Props) {\n const {\n person,\n isEdge,\n onPersonClick,\n registerPosition,\n formatPersonSubtitle,\n personNodeWidth,\n } = data;\n\n const handleClick = () => {\n onPersonClick?.(person);\n };\n\n return (\n <div style={{ position: \"relative\" }}>\n <Handle type=\"target\" position={Position.Left} />\n <PersonCard\n person={person}\n isEdge={isEdge}\n onClick={handleClick}\n registerPosition={registerPosition}\n formatPersonSubtitle={formatPersonSubtitle}\n personNodeWidth={personNodeWidth}\n />\n <Handle type=\"source\" position={Position.Top} />\n </div>\n );\n}\n\nexport default memo(PersonNode);\n","import { memo } from \"react\";\nimport { Handle, Position } from \"reactflow\";\nimport CoupleCard from \"./CoupleCard\";\nimport { Person } from \"../types/person\";\nimport ArrowForwardIosIcon from \"@mui/icons-material/ArrowForwardIos\";\nimport { IconButton } from \"@mui/material\";\n\ninterface Props {\n data: {\n partner1: Person;\n partner2?: Person;\n onPersonClick?: (person: Person) => void;\n onExpand?: () => void;\n gen: number; // generation index (0=root)\n formatPersonSubtitle?: (person: Person) => string;\n coupleNodeWidth?: number;\n };\n}\n\nfunction CoupleNode({ data }: Props) {\n const {\n partner1,\n partner2,\n onPersonClick,\n onExpand,\n gen,\n formatPersonSubtitle,\n coupleNodeWidth,\n } = data;\n\n return (\n <div style={{ position: \"relative\" }}>\n <Handle type=\"target\" position={Position.Left} />\n <CoupleCard\n partner1={partner1}\n partner2={partner2}\n onPersonClick={onPersonClick}\n formatPersonSubtitle={formatPersonSubtitle}\n coupleNodeWidth={coupleNodeWidth}\n />\n {/* Dad handle - positioned at top third of card for partner1 */}\n <Handle id=\"dad\" type=\"source\" position={Position.Top} />\n {/* Mom handle - positioned at bottom third of card for partner2 */}\n {partner2 && <Handle id=\"mom\" type=\"source\" position={Position.Bottom} />}\n {/* Expansion arrow appears on odd-numbered edge generations: gen 2,4,6... */}\n {onExpand && gen >= 2 && gen % 2 === 0 && (\n <IconButton\n size=\"small\"\n onClick={onExpand}\n sx={{\n position: \"absolute\",\n right: -32,\n top: \"50%\",\n transform: \"translateY(-50%)\",\n backgroundColor: \"#fff\",\n boxShadow: 3,\n \"&:hover\": { backgroundColor: \"#f5f5f5\" },\n }}\n >\n <ArrowForwardIosIcon fontSize=\"inherit\" />\n </IconButton>\n )}\n {/* source handle aligned with arrow centre */}\n {onExpand && gen >= 2 && gen % 2 === 0 && (\n <Handle\n id=\"arrow\"\n type=\"source\"\n position={Position.Right}\n style={{ top: \"50%\" }}\n />\n )}\n </div>\n );\n}\n\nexport default memo(CoupleNode);\n","import { Card, Avatar, Typography, Box } from \"@mui/material\";\nimport ArrowForwardIosIcon from \"@mui/icons-material/ArrowForwardIos\";\nimport { Person } from \"../types/person\";\nimport React from \"react\";\n\ninterface Props {\n partner1: Person;\n partner2?: Person;\n isEdge?: boolean;\n onPersonClick?: (person: Person) => void;\n registerPosition?: (id: string, rect: DOMRect) => void;\n formatPersonSubtitle?: (person: Person) => string;\n coupleNodeWidth?: number;\n}\n\nexport default function CoupleCard({\n partner1,\n partner2,\n isEdge,\n onPersonClick,\n registerPosition,\n formatPersonSubtitle,\n coupleNodeWidth = 320,\n}: Props) {\n const ref = React.useRef<HTMLDivElement>(null);\n\n React.useLayoutEffect(() => {\n if (ref.current && registerPosition) {\n // register using first partner id\n registerPosition(partner1.id, ref.current.getBoundingClientRect());\n if (partner2)\n registerPosition(partner2.id, ref.current.getBoundingClientRect());\n }\n });\n\n const renderPersonRow = (person: Person) => {\n let subtitle = \"\";\n if (formatPersonSubtitle) {\n subtitle = formatPersonSubtitle(person);\n } else {\n // Default format: dates + ID\n let lifeText = \"\";\n if (person.birth && person.death) {\n lifeText = `${person.birth} – ${person.death}`;\n } else if (person.birth) {\n lifeText = `${person.birth}`;\n } else if (person.death) {\n lifeText = `– ${person.death}`;\n }\n subtitle = lifeText ? `${lifeText} • ${person.id}` : person.id;\n }\n return (\n <Box\n sx={{\n display: \"flex\",\n alignItems: \"center\",\n py: 1,\n cursor: \"pointer\",\n \"&:hover\": {\n backgroundColor: \"rgba(0, 0, 0, 0.04)\",\n },\n }}\n onClick={() => onPersonClick?.(person)}\n >\n <Avatar\n src={person.imageUrl}\n alt={person.name}\n sx={{ width: 56, height: 56, mr: 2 }}\n />\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Typography\n variant=\"h6\"\n sx={{\n lineHeight: 1,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {person.name}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {subtitle}\n </Typography>\n </Box>\n </Box>\n );\n };\n\n return (\n <Card\n sx={{\n my: 1,\n width: coupleNodeWidth,\n borderRadius: 2,\n boxShadow: 3,\n position: \"relative\",\n }}\n ref={ref}\n >\n <Box sx={{ px: 2, py: 1 }}>\n {renderPersonRow(partner1)}\n {partner2 && renderPersonRow(partner2)}\n {isEdge && (\n <ArrowForwardIosIcon\n sx={{ position: \"absolute\", right: 8, top: 8, fontSize: 18 }}\n />\n )}\n </Box>\n </Card>\n );\n}\n","import { useState } from \"react\";\n\n/**\n * Simple hook to remember which couple (by node id) is currently expanded.\n * If `expandedId` is undefined the tree shows only the default three generations.\n */\nexport default function useCoupleExpansion() {\n const [expandedId, setExpandedId] = useState<string | undefined>(undefined);\n const [token, setToken] = useState(0);\n\n const expand = (id: string) => {\n setExpandedId((prev) => {\n if (prev === id) {\n // collapse\n return undefined;\n }\n // expand new\n return id;\n });\n setToken((t) => t + 1);\n };\n const reset = () => setExpandedId(undefined);\n\n return { expandedId, token, expand, reset };\n}\n","import { Box } from \"@mui/material\";\nimport { useMemo, useRef } from \"react\";\nimport ReactFlow, {\n Background,\n ReactFlowProvider,\n Node,\n Edge,\n Controls,\n MiniMap,\n ConnectionMode,\n Viewport,\n useOnViewportChange,\n} from \"reactflow\";\nimport \"reactflow/dist/style.css\";\n\nimport { PeopleIndex, Person } from \"../types/person\";\nimport { useAncestorTree } from \"../hooks/useAncestorTree\";\nimport PersonNode from \"./PersonNode\";\nimport CoupleNode from \"./CoupleNode\";\nimport useCoupleExpansion from \"../hooks/useCoupleExpansion\";\n\n// Callback function types for library consumers\nexport interface AncestorTreeCallbacks {\n /** Called when a person node is clicked */\n onPersonClick?: (person: Person) => void;\n /** Called when a couple node is clicked */\n onCoupleClick?: (partner1: Person, partner2: Person) => void;\n /** Called when the tree is panned */\n onTreePan?: (x: number, y: number) => void;\n /** Called when the tree is zoomed */\n onTreeZoom?: (zoom: number) => void;\n /** Called when the tree viewport changes (pan or zoom) */\n onViewportChange?: (x: number, y: number, zoom: number) => void;\n /** Called when a couple is expanded/collapsed */\n onCoupleExpansion?: (\n partner1: Person | undefined,\n partner2: Person | undefined,\n isExpanded: boolean\n ) => void;\n}\n\n// UI control props for showing/hiding features\nexport interface AncestorTreeUIControls {\n /** Show/hide the zoom and fit controls */\n showControls?: boolean;\n /** Show/hide the mini map */\n showMiniMap?: boolean;\n /** Show/hide the background grid */\n showBackground?: boolean;\n /** Enable/disable panning */\n enablePan?: boolean;\n /** Enable/disable zooming */\n enableZoom?: boolean;\n /** Enable/disable fit view on mount */\n enableFitView?: boolean;\n /** Custom background color */\n backgroundColor?: string;\n /** Node height (affects vertical spacing calculation) */\n nodeHeight?: number;\n /** Vertical gaps between nodes for each generation [gen0, gen1, gen2, gen3, gen4...] */\n verticalGaps?: number[];\n /** Default vertical gap when generation not specified in verticalGaps */\n defaultVerticalGap?: number;\n /** Custom formatter for person subtitle text */\n formatPersonSubtitle?: (person: Person) => string;\n /** Width of couple nodes */\n coupleNodeWidth?: number;\n /** Width of person nodes */\n personNodeWidth?: number;\n}\n\ninterface Props {\n people: PeopleIndex;\n rootId: string;\n /** Callback functions for various tree interactions */\n callbacks?: AncestorTreeCallbacks;\n /** UI control options */\n uiControls?: AncestorTreeUIControls;\n}\n\n// Layout configuration\nconst LAYOUT_CONFIG = {\n nodeHeight: 120,\n // X positions for each generation\n xPositions: [0, 225, 600, 1000, 1400],\n defaultXStep: 200,\n // Vertical gaps between nodes in each generation\n verticalGaps: [0, 325, 100, 325, 100],\n defaultGap: 50,\n // Edge styling\n edgeStyle: { stroke: \"#999\", strokeWidth: 3 },\n} as const;\n\ntype PersonToCouple = Record<string, string>;\ntype CoupleToPartners = Record<string, [Person, Person]>;\n\ninterface NodeData {\n partner1?: Person;\n partner2?: Person;\n person?: Person;\n gen: number;\n isEdge?: boolean;\n onExpand?: () => void;\n onPersonClick?: (person: Person) => void;\n onCoupleClick?: (partner1: Person, partner2: Person) => void;\n formatPersonSubtitle?: (person: Person) => string;\n coupleNodeWidth?: number;\n personNodeWidth?: number;\n}\n\nexport default function AncestorTree({\n people,\n rootId,\n callbacks = {},\n uiControls = {},\n}: Props) {\n const { generations } = useAncestorTree(people, rootId);\n const { expandedId, token, expand } = useCoupleExpansion();\n\n // Default UI control values\n const {\n showControls = true,\n showMiniMap = false,\n showBackground = true,\n enablePan = true,\n enableZoom = true,\n enableFitView = true,\n backgroundColor = \"#fafafa\",\n nodeHeight = 120,\n verticalGaps = [0, 325, 100, 325, 100],\n defaultVerticalGap = 50,\n formatPersonSubtitle,\n coupleNodeWidth = 320,\n personNodeWidth = 160,\n } = uiControls;\n\n // Create layout config from props\n const layoutConfig = useMemo(() => {\n // Base configuration\n const baseXPositions = [0, 225, 600, 1000, 1400];\n const baseCoupleWidth = 320;\n\n // Calculate width difference from baseline\n const widthDiff = coupleNodeWidth - baseCoupleWidth;\n\n // Apply cumulative adjustment to X-positions\n const adjustedXPositions = baseXPositions.map(\n (x, index) => x + index * widthDiff\n );\n\n return {\n nodeHeight,\n // Dynamically calculated X positions\n xPositions: adjustedXPositions,\n defaultXStep: 200 + widthDiff,\n // Vertical gaps between nodes in each generation\n verticalGaps,\n defaultGap: defaultVerticalGap,\n // Node widths\n coupleNodeWidth,\n personNodeWidth,\n // Edge styling\n edgeStyle: { stroke: \"#999\", strokeWidth: 3 },\n };\n }, [\n nodeHeight,\n coupleNodeWidth,\n personNodeWidth,\n verticalGaps,\n defaultVerticalGap,\n ]);\n\n const flowKey = `${token}-${\n expandedId ?? \"root\"\n }-${showBackground}-${showControls}-${showMiniMap}`;\n\n // Store couple mappings for callback access\n const coupleToPartnersRef = useRef<CoupleToPartners>({});\n\n // Handle couple expansion with callback\n const handleCoupleExpansion = (coupleId: string) => {\n const wasExpanded = expandedId === coupleId;\n expand(coupleId);\n\n // Get the couple's Person objects for the callback\n const couple = coupleToPartnersRef.current[coupleId];\n const [partner1, partner2] = couple || [undefined, undefined];\n\n callbacks.onCoupleExpansion?.(\n wasExpanded ? undefined : partner1,\n wasExpanded ? undefined : partner2,\n !wasExpanded\n );\n };\n\n // Viewport change handler component - must be inside ReactFlow\n const ViewportChangeHandler = () => {\n useOnViewportChange({\n onChange: ({ x, y, zoom }: Viewport) => {\n callbacks.onViewportChange?.(x, y, zoom);\n callbacks.onTreePan?.(x, y);\n callbacks.onTreeZoom?.(zoom);\n },\n });\n return null;\n };\n\n const { nodes, edges } = useMemo(() => {\n const nodes: Node<NodeData>[] = [];\n const edges: Edge[] = [];\n const personToCouple: PersonToCouple = {};\n const coupleToPartners: CoupleToPartners = {};\n\n // Build base generations (0-2)\n generations.forEach((generation, generationIndex) => {\n const { nodes: generationNodes, mappings } = buildGenerationNodes(\n generation,\n generationIndex,\n handleCoupleExpansion,\n layoutConfig,\n callbacks.onPersonClick,\n formatPersonSubtitle\n );\n\n nodes.push(...generationNodes);\n Object.assign(personToCouple, mappings.personToCouple);\n Object.assign(coupleToPartners, mappings.coupleToPartners);\n });\n\n // Update the ref with the couple mappings for callback access\n coupleToPartnersRef.current = { ...coupleToPartners };\n\n // Build edges between base generations\n const baseEdges = buildBaseGenerationEdges(nodes, personToCouple);\n edges.push(...baseEdges);\n\n // Build expanded generations if needed\n if (expandedId && coupleToPartners[expandedId]) {\n const expandedResult = buildExpandedGenerations(\n people,\n expandedId,\n coupleToPartners,\n nodes,\n flowKey,\n layoutConfig,\n callbacks.onPersonClick,\n formatPersonSubtitle\n );\n\n nodes.push(...expandedResult.nodes);\n edges.push(...expandedResult.edges);\n Object.assign(personToCouple, expandedResult.mappings.personToCouple);\n Object.assign(coupleToPartners, expandedResult.mappings.coupleToPartners);\n\n // Update the ref with expanded mappings too\n coupleToPartnersRef.current = { ...coupleToPartners };\n }\n\n // Filter edges to only include those with valid source/target nodes\n const validNodeIds = new Set(nodes.map((node) => node.id));\n const validEdges = edges.filter(\n (edge) => validNodeIds.has(edge.source) && validNodeIds.has(edge.target)\n );\n\n // Filter edges based on expansion state\n const finalEdges = filterEdgesByExpansionState(\n validEdges,\n expandedId,\n nodes\n );\n\n return { nodes, edges: finalEdges };\n }, [\n generations,\n expandedId,\n token,\n people,\n callbacks.onPersonClick,\n flowKey,\n uiControls.formatPersonSubtitle,\n layoutConfig,\n ]);\n\n return (\n <ReactFlowProvider>\n <Box\n sx={{\n width: \"100%\",\n height: \"100%\",\n backgroundColor: showBackground ? \"transparent\" : backgroundColor,\n }}\n >\n <ReactFlow\n key={flowKey}\n nodes={nodes}\n edges={edges}\n nodeTypes={{\n person: PersonNode,\n couple: CoupleNode,\n }}\n panOnScroll={enablePan}\n zoomOnScroll={enableZoom}\n fitView={enableFitView}\n zoomOnDoubleClick={false}\n connectionMode={ConnectionMode.Loose}\n defaultEdgeOptions={{\n type: \"step\",\n animated: false,\n style: { strokeWidth: 3 },\n }}\n >\n <ViewportChangeHandler />\n {showBackground && <Background gap={16} color=\"#eee\" />}\n {showControls && <Controls />}\n {showMiniMap && (\n <MiniMap\n nodeColor={(node) => {\n switch (node.type) {\n case \"person\":\n return \"#4fc3f7\";\n case \"couple\":\n return \"#81c784\";\n default:\n return \"#eee\";\n }\n }}\n nodeStrokeWidth={3}\n zoomable\n pannable\n />\n )}\n </ReactFlow>\n </Box>\n </ReactFlowProvider>\n );\n}\n\n// Helper functions\n\nfunction getGenerationLayout(\n generationIndex: number,\n coupleCount: number,\n layoutConfig: typeof LAYOUT_CONFIG\n) {\n const xPosition =\n layoutConfig.xPositions[generationIndex] ??\n layoutConfig.xPositions[layoutConfig.xPositions.length - 1] +\n (generationIndex - layoutConfig.xPositions.length + 1) *\n layoutConfig.defaultXStep;\n\n const gap =\n layoutConfig.verticalGaps[generationIndex] ?? layoutConfig.defaultGap;\n const totalHeight =\n coupleCount * layoutConfig.nodeHeight + (coupleCount - 1) * gap;\n const startY = -totalHeight / 2;\n\n return { xPosition, gap, startY };\n}\n\nfunction buildGenerationNodes(\n generation: Person[],\n generationIndex: number,\n expand: (id: string) => void,\n layoutConfig: any,\n onPersonClick?: (person: Person) => void,\n formatPersonSubtitle?: (person: Person) => string\n) {\n const nodes: Node<NodeData>[] = [];\n const personToCouple: PersonToCouple = {};\n const coupleToPartners: CoupleToPartners = {};\n\n const coupleCount = Math.ceil(generation.length / 2);\n const { xPosition, gap, startY } = getGenerationLayout(\n generationIndex,\n coupleCount,\n layoutConfig\n );\n\n for (let i = 0; i < generation.length; i += 2) {\n const partner1 = generation[i];\n const partner2 = generation[i + 1];\n const coupleIndex = i / 2;\n const yPosition = startY + coupleIndex * (layoutConfig.nodeHeight + gap);\n\n if (partner2) {\n // Couple node\n const coupleId = `c-${partner1.id}-${partner2.id}`;\n nodes.push({\n id: coupleId,\n position: { x: xPosition, y: yPosition },\n type: \"couple\",\n data: {\n partner1,\n partner2,\n gen: generationIndex,\n onExpand: generationIndex === 2 ? () => expand(coupleId) : undefined,\n onPersonClick,\n formatPersonSubtitle,\n coupleNodeWidth: layoutConfig.coupleNodeWidth,\n },\n });\n\n personToCouple[partner1.id] = coupleId;\n personToCouple[partner2.id] = coupleId;\n coupleToPartners[coupleId] = [partner1, partner2];\n } else {\n // Single person node\n nodes.push({\n id: partner1.id,\n position: { x: xPosition, y: yPosition },\n type: \"person\",\n data: {\n person: partner1,\n gen: generationIndex,\n isEdge: !!partner1.parentIds?.length,\n onPersonClick,\n formatPersonSubtitle,\n personNodeWidth: layoutConfig.personNodeWidth,\n },\n });\n }\n }\n\n return {\n nodes,\n mappings: { personToCouple, coupleToPartners },\n };\n}\n\nfunction buildBaseGenerationEdges(\n nodes: Node<NodeData>[],\n personTo