{"version":3,"file":"use-cell.cjs","sources":["../../../src/hooks/use-cell.ts"],"sourcesContent":["import { useContext, useMemo, useRef } from 'react';\nimport { CellIdContext } from '../context';\nimport { useCells } from './use-cells';\nimport type { AnyCellRecord, CellId, CellRecord, Computed } from '../types/cell.types';\n\n/**\n * Read the current cell from the closest `CellIdContext`, the id is provided\n * by `<Paper />` around `renderElement` / `renderLink`. Use this inside a\n * render callback (or a component mounted from one) to access the full cell\n * record.\n *\n * Throws when used outside of a Paper render context, or when the id no longer\n * resolves to a cell in the store (e.g. deleted mid-render).\n * @title Read the current cell\n * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form\n * @returns the current resolved cell record\n * @group Hooks\n * @example\n * ```tsx\n * import { Paper, useCell } from '@joint/react';\n *\n * function NodeLabel() {\n *   // The id comes from the <Paper> render callback context.\n *   const cell = useCell();\n *   return <text>{String(cell.id)}</text>;\n * }\n *\n * <Paper renderElement={() => <NodeLabel />} />;\n * ```\n */\nexport function useCell<Cell extends AnyCellRecord = CellRecord>(): Computed<Cell>;\n/**\n * Read a selected slice from the current cell (context-scoped). Re-renders\n * only when `isEqual(prev, next)` returns false.\n *\n * Throws if no cell resolves, never returns `undefined`.\n * @title Select from the current cell\n * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form\n * @template Selected - selector return type (defaults to `Cell`)\n * @param selector - derive a value from the current resolved cell record\n * @param isEqual - equality test used to short-circuit re-renders (defaults to a shallow, array-aware comparison that falls back to Object.is for scalar results)\n * @returns selected value\n * @example\n * ```tsx\n * import { useCell, selectElementData } from '@joint/react';\n *\n * function NodeLabel() {\n *   type NodeData = { label: string };\n *   // Re-renders only when this element's data changes.\n *   const data = useCell(selectElementData<NodeData>);\n *   return <text>{data.label}</text>;\n * }\n * ```\n */\nexport function useCell<Cell extends AnyCellRecord = CellRecord, Selected = Computed<Cell>>(\n  selector: (cell: Computed<Cell>) => Selected,\n  isEqual?: (a: Selected, b: Selected) => boolean\n): Selected;\n/**\n * Subscribe to a specific cell by id. Works anywhere, does not require\n * `CellIdContext`. Throws when the id does not resolve to a cell.\n * @title Read a cell by id\n * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form\n * @param id - cell id to track\n * @returns the resolved cell record\n * @example\n * ```tsx\n * import { useCell } from '@joint/react';\n *\n * function CellTypeBadge({ id }: { id: string }) {\n *   // Works outside a render callback too — subscribes to this id anywhere.\n *   const cell = useCell(id);\n *   return <span>{cell.type}</span>;\n * }\n * ```\n */\nexport function useCell<Cell extends AnyCellRecord = CellRecord>(\n  // eslint-disable-next-line @typescript-eslint/unified-signatures\n  id: CellId\n): Computed<Cell>;\n/**\n * Subscribe to a specific cell by id and derive a value from it. Works\n * anywhere, does not require `CellIdContext`. Throws when the id does not\n * resolve to a cell.\n * @title Select from a cell by id\n * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form\n * @template Selected - selector return type (defaults to `Cell`)\n * @param id - cell id to track\n * @param selector - derive a value from the resolved cell record\n * @param isEqual - equality test used to short-circuit re-renders (defaults to a shallow, array-aware comparison that falls back to Object.is for scalar results)\n * @returns selected value\n */\nexport function useCell<Cell extends AnyCellRecord = CellRecord, Selected = Computed<Cell>>(\n  id: CellId,\n  selector: (cell: Computed<Cell>) => Selected,\n  isEqual?: (a: Selected, b: Selected) => boolean\n): Selected;\nexport function useCell<Cell extends AnyCellRecord = CellRecord, Selected = Computed<Cell>>(\n  argument1?: CellId | ((cell: Computed<Cell>) => Selected),\n  argument2?: ((cell: Computed<Cell>) => Selected) | ((a: Selected, b: Selected) => boolean),\n  argument3?: (a: Selected, b: Selected) => boolean\n): Computed<Cell> | Selected {\n  const contextId = useContext(CellIdContext);\n  const explicitId = typeof argument1 === 'function' ? undefined : argument1;\n  const id = explicitId ?? contextId;\n\n  let userSelector: ((cell: Computed<Cell>) => Selected) | undefined;\n  let isEqual: ((a: Selected, b: Selected) => boolean) | undefined;\n  if (typeof argument1 === 'function') {\n    userSelector = argument1;\n    if (typeof argument2 === 'function') {\n      isEqual = argument2 as (a: Selected, b: Selected) => boolean;\n    }\n  } else if (typeof argument2 === 'function') {\n    userSelector = argument2 as (cell: Computed<Cell>) => Selected;\n    if (typeof argument3 === 'function') {\n      isEqual = argument3;\n    }\n  }\n\n  if (id === undefined) {\n    throw new Error(\n      'useCell() must be called inside renderElement / renderLink, or with an explicit id argument'\n    );\n  }\n\n  // Remembers the last value this hook resolved and the id it belonged to, so the\n  // selector can tolerate the removed-mid-render window below. One ref mutated in\n  // place (never reassigned) — no per-render allocation on the hot path. Tagging\n  // by id means a changed id never returns a stale value from a different cell.\n  const lastResolvedRef = useRef<{\n    id: CellId | undefined;\n    value: Computed<Cell> | Selected | undefined;\n  }>({ id: undefined, value: undefined });\n\n  // Always run through the (id, selector, isEqual?) form so React only sees\n  // one stable hook call shape across all overloads. The identity case re-uses\n  // the cell record reference, so isEqual=Object.is bails out on data-only commits.\n  const selector = useMemo(() => {\n    return (cell: Computed<Cell> | undefined): Computed<Cell> | Selected => {\n      const lastResolved = lastResolvedRef.current;\n      if (cell === undefined) {\n        // The subscribed cell was removed while this subtree is still mounted: a\n        // controlled `cells` update fires the cell's per-id listener synchronously\n        // (inside GraphProvider's applyControlled commit) one step before <Paper>\n        // unmounts the portal, so the selector re-runs against a cell that is\n        // already gone. Return the last value resolved for THIS id — the doomed\n        // subtree renders once more with stale data (equal to the cached value, so\n        // it does not even re-render) and unmounts on the next commit, instead of\n        // throwing and taking the whole paper down. A cell that never resolved is\n        // genuine misuse (bad id / outside a render context) and still throws.\n        if (lastResolved.id === id) {\n          return lastResolved.value as Computed<Cell> | Selected;\n        }\n        throw new Error(`useCell(): no cell with id \"${String(id)}\"`);\n      }\n      const value = userSelector ? userSelector(cell) : cell;\n      lastResolved.id = id;\n      lastResolved.value = value;\n      return value;\n    };\n    // userSelector is captured by reference; React's referential equality on\n    // the closure is enough here because `useCells` keeps its own selectorRef.\n  }, [id, userSelector]);\n\n  return useCells<Cell, Computed<Cell> | Selected>(\n    id,\n    selector,\n    isEqual as ((a: Computed<Cell> | Selected, b: Computed<Cell> | Selected) => boolean) | undefined\n  );\n}\n"],"names":["useContext","CellIdContext","useRef","useMemo","useCells"],"mappings":"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"}