Skip to content

fix(joint-react): useCells falls back to collection for non-graph cells#3349

Merged
kumilingus merged 1 commit into
clientIO:devfrom
kumilingus:fix/joint-react-use-cells-non-graph-collection
Jun 8, 2026
Merged

fix(joint-react): useCells falls back to collection for non-graph cells#3349
kumilingus merged 1 commit into
clientIO:devfrom
kumilingus:fix/joint-react-use-cells-non-graph-collection

Conversation

@kumilingus

Copy link
Copy Markdown
Contributor

Summary

useCells(collection, …) previously resolved every member id through the GraphProvider's cell container. Cells living outside the graph (e.g. ui.Clipboard clones, freshly constructed dia.Cell instances) were silently skipped, so a selector like (cells) => cells.length === 0 always returned true regardless of how many cells the collection actually held.

Resolve cells from the collection itself when the graph container lacks them. The raw dia.Cell is converted on the fly via the existing toCellRecord mapper. A per-hook WeakMap<dia.Cell, AnyCellRecord> keeps the converted records reference-stable across renders so the outer shallow-equality short-circuit can still fire.

Per-cell change events are not subscribed for the fallback path — the only caller today (clipboard membership) needs add/remove/reset reactivity, which the collection-level subscription already covers. Adding per-cell listening is straightforward later if a use case appears.

Changes

  • packages/joint-react/src/hooks/use-cells.ts — new resolveCell helper, pickCells / computeNext thread collection + WeakMap cache through; collection overload JSDoc updated.
  • packages/joint-react/src/hooks/__tests__/use-cells.test.tsx — 3 new tests covering non-graph cells (records returned, length-selector reactive, ref stable across renders).

Test plan

  • yarn jest --testPathPatterns=\"use-cells\" — 60 tests pass (incl. 3 new)
  • Full yarn jest in @joint/react — clean
  • yarn typecheck in @joint/react-plus (downstream consumer of new behavior)

🤖 Generated with Claude Code

`useCells(collection, …)` previously resolved every member id through the
GraphProvider's cell container. Cells living outside the graph (e.g.
`ui.Clipboard` clones, freshly constructed `dia.Cell` instances) were silently
skipped, so a selector like `(cells) => cells.length === 0` always returned
`true` regardless of how many cells the collection actually held.

Resolve cells from the collection itself when the graph container lacks them.
The raw `dia.Cell` is converted on the fly via the existing `toCellRecord`
mapper, and a per-hook `WeakMap<dia.Cell, AnyCellRecord>` keeps the converted
records reference-stable across renders so the outer shallow-equality
short-circuit can still fire.

Per-cell `change` events are not subscribed for the fallback path — the only
caller today (clipboard membership) needs add/remove/reset reactivity, and the
collection-level subscription already covers that. Adding per-cell listening
is straightforward later if a use case appears.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kumilingus kumilingus requested a review from samuelgja June 6, 2026 16:43
@kumilingus kumilingus merged commit cb4425e into clientIO:dev Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants