{"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  personToCouple: PersonToCouple\n): Edge[] {\n  const edges: Edge[] = [];\n  const edgeSet = new Set<string>();\n  const processedCouples = new Set<string>();\n\n  // Process each couple to create edges to their parents\n  Object.values(personToCouple).forEach((coupleId) => {\n    if (processedCouples.has(coupleId)) return;\n    processedCouples.add(coupleId);\n\n    const coupleNode = nodes.find((node) => node.id === coupleId);\n    if (!coupleNode?.data.partner1 || !coupleNode?.data.partner2) return;\n\n    const { partner1, partner2 } = coupleNode.data;\n\n    // Create edge from dad handle to dad's parents\n    const dadEdge = createParentEdge(\n      coupleId,\n      partner1,\n      \"dad\",\n      personToCouple,\n      LAYOUT_CONFIG\n    );\n    if (dadEdge && !edgeSet.has(dadEdge.id)) {\n      edgeSet.add(dadEdge.id);\n      edges.push(dadEdge);\n    }\n\n    // Create edge from mom handle to mom's parents\n    const momEdge = createParentEdge(\n      coupleId,\n      partner2,\n      \"mom\",\n      personToCouple,\n      LAYOUT_CONFIG\n    );\n    if (momEdge && !edgeSet.has(momEdge.id)) {\n      edgeSet.add(momEdge.id);\n      edges.push(momEdge);\n    }\n  });\n\n  return edges;\n}\n\nfunction createParentEdge(\n  coupleId: string,\n  person: Person,\n  handleType: \"dad\" | \"mom\",\n  personToCouple: PersonToCouple,\n  layoutConfig: any\n): Edge | null {\n  if (!person.parentIds) return null;\n\n  const [parent1, parent2] = person.parentIds;\n  const targetCouple = parent1\n    ? personToCouple[parent1]\n    : parent2\n    ? personToCouple[parent2]\n    : undefined;\n\n  if (!targetCouple) return null;\n\n  return {\n    id: `${coupleId}-${handleType}-${targetCouple}`,\n    source: coupleId,\n    sourceHandle: handleType,\n    target: targetCouple,\n    type: \"step\",\n    style: layoutConfig.edgeStyle,\n  };\n}\n\nfunction buildExpandedGenerations(\n  people: PeopleIndex,\n  expandedId: string,\n  coupleToPartners: CoupleToPartners,\n  existingNodes: Node<NodeData>[],\n  flowKey: string,\n  layoutConfig: any,\n  onPersonClick?: (person: Person) => void,\n  formatPersonSubtitle?: (person: Person) => string\n) {\n  const nodes: Node<NodeData>[] = [];\n  const edges: Edge[] = [];\n  const personToCouple: PersonToCouple = {};\n  const coupleToPartners_new: CoupleToPartners = {};\n\n  const [selectedDad, selectedMom] = coupleToPartners[expandedId];\n\n  // Build generation 4 (parents of selected couple)\n  const generation4 = buildGenerationFromParents(\n    [selectedDad, selectedMom],\n    people\n  );\n  // Build generation 5 (grandparents of selected couple)\n  const generation5 = buildGenerationFromParents(generation4, people);\n\n  const expandedGenerations = [generation4, generation5];\n  const generation4CoupleIds: string[] = [];\n\n  // Get the anchor position for centering expanded generations\n  const selectedNode = existingNodes.find((node) => node.id === expandedId);\n  const anchorY = selectedNode\n    ? selectedNode.position.y + layoutConfig.nodeHeight / 2\n    : 0;\n\n  expandedGenerations.forEach((generation, index) => {\n    const generationIndex = 3 + index; // 3 for gen4, 4 for gen5\n    const coupleCount = Math.ceil(generation.length / 2);\n    const gap =\n      layoutConfig.verticalGaps[generationIndex] ?? layoutConfig.defaultGap;\n    const totalHeight =\n      coupleCount * layoutConfig.nodeHeight + (coupleCount - 1) * gap;\n    const startY = anchorY - totalHeight / 2;\n    const xPosition =\n      layoutConfig.xPositions[generationIndex] ??\n      layoutConfig.xPositions[layoutConfig.xPositions.length - 1];\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        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            onPersonClick,\n            formatPersonSubtitle,\n            coupleNodeWidth: layoutConfig.coupleNodeWidth,\n          },\n        });\n\n        personToCouple[partner1.id] = coupleId;\n        personToCouple[partner2.id] = coupleId;\n        coupleToPartners_new[coupleId] = [partner1, partner2];\n\n        if (index === 0) {\n          // Generation 4 - create arrow edge from selected couple\n          generation4CoupleIds.push(coupleId);\n          edges.push({\n            id: `t${flowKey}-${expandedId}-arrow-${coupleId}`,\n            source: expandedId,\n            sourceHandle: \"arrow\",\n            target: coupleId,\n            type: \"step\",\n            style: layoutConfig.edgeStyle,\n          });\n        }\n      } else {\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\n  // Create edges from generation 4 to generation 5\n  const generation4Edges = buildGeneration4ToGeneration5Edges(\n    generation4CoupleIds,\n    coupleToPartners_new,\n    personToCouple,\n    flowKey,\n    layoutConfig\n  );\n  edges.push(...generation4Edges);\n\n  return {\n    nodes,\n    edges,\n    mappings: { personToCouple, coupleToPartners: coupleToPartners_new },\n  };\n}\n\nfunction buildGenerationFromParents(\n  parents: Person[],\n  people: PeopleIndex\n): Person[] {\n  const result: Person[] = [];\n  parents.forEach((parent) => {\n    parent.parentIds?.forEach((parentId) => {\n      if (parentId) {\n        const person = people[parentId];\n        if (person) result.push(person);\n      }\n    });\n  });\n  return result;\n}\n\nfunction buildGeneration4ToGeneration5Edges(\n  generation4CoupleIds: string[],\n  coupleToPartners: CoupleToPartners,\n  personToCouple: PersonToCouple,\n  flowKey: string,\n  layoutConfig: any\n): Edge[] {\n  const edges: Edge[] = [];\n  const edgeSet = new Set<string>();\n\n  generation4CoupleIds.forEach((sourceId) => {\n    const [partner1, partner2] = coupleToPartners[sourceId];\n\n    [partner1, partner2].forEach((partner) => {\n      partner.parentIds?.forEach((parentId) => {\n        if (!parentId) return;\n\n        const targetCouple = personToCouple[parentId];\n        if (!targetCouple) return;\n\n        const handleType = partner === partner1 ? \"dad\" : \"mom\";\n        const edgeId = `t${flowKey}-${sourceId}-${handleType}-${targetCouple}`;\n\n        if (!edgeSet.has(edgeId)) {\n          edgeSet.add(edgeId);\n          edges.push({\n            id: edgeId,\n            source: sourceId,\n            sourceHandle: handleType,\n            target: targetCouple,\n            type: \"step\",\n            style: layoutConfig.edgeStyle,\n          });\n        }\n      });\n    });\n  });\n\n  return edges;\n}\n\nfunction filterEdgesByExpansionState(\n  edges: Edge[],\n  expandedId: string | undefined,\n  nodes: Node<NodeData>[]\n): Edge[] {\n  if (expandedId) {\n    // When expanded, show all edges\n    return edges;\n  }\n\n  // When collapsed, only show edges connecting base generations (0, 1, 2)\n  return edges.filter((edge) => {\n    if (edge.id.startsWith(\"t\")) return false;\n\n    const sourceNode = nodes.find((node) => node.id === edge.source);\n    const targetNode = nodes.find((node) => node.id === edge.target);\n\n    return (sourceNode?.data.gen ?? 0) <= 2 && (targetNode?.data.gen ?? 0) <= 2;\n  });\n}\n"]}