feat(joint-react): add useCollection / useSetCollection hooks#3309
Open
samuelgja wants to merge 7 commits into
Open
feat(joint-react): add useCollection / useSetCollection hooks#3309samuelgja wants to merge 7 commits into
samuelgja wants to merge 7 commits into
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tions - Implemented `useCollection` hook to subscribe to JointJS collection cells as `CellRecord` instances, supporting both direct and selector forms. - Created `useSetCollection` hook to replace contents of a JointJS collection with supplied records, supporting both direct and updater forms. - Introduced `createCollectionView` function to mirror a JointJS collection into a read-only records container, handling events like add, remove, change, and reset. - Added tests for collection view functionality, ensuring correct behavior on collection mutations and attribute changes. - Refactored data mapping utilities to support merging cell records and writing cells to containers, preserving reference identity where possible. - Updated GraphStore to manage collection views, ensuring proper cleanup and reference counting.
…hooks, remove collection view management
…ng JointJS collections - Implemented `useCellCollection` to subscribe to JointJS collections and return cell records or selected values based on a selector. - Introduced `useSetCellCollection` to replace contents of a JointJS collection with records or dia.Cell instances. - Enhanced cell input normalization with `normalizeCellInput` utility to handle both plain records and dia.Cell instances. - Updated related hooks and types to support new functionality, ensuring compatibility with existing code. - Added tests for `normalizeCellInput` to verify behavior with various input types.
kumilingus
reviewed
May 14, 2026
| * @param b - next result (expected to be a readonly array) | ||
| * @returns true when both arrays match by length and element identity | ||
| */ | ||
| function arrayResultEqual(a: unknown, b: unknown): boolean { |
Contributor
There was a problem hiding this comment.
is this wrapper necessary?
kumilingus
reviewed
May 14, 2026
| * @param graph - graph used for cell lookup and type-constructor resolution | ||
| * @returns the resolved `dia.Cell` (existing or freshly constructed) | ||
| */ | ||
| function resolveRecordToCell(record: AnyCellRecord, graph: dia.Graph): dia.Cell { |
Contributor
There was a problem hiding this comment.
I don't like this method.
- if it exists - it modifies it
- if it does not exist - it does not add it to graph
kumilingus
reviewed
May 14, 2026
| try { | ||
| expect(paper).toBeInstanceOf(dia.Paper); | ||
| expect(paper.el.classList.contains('jj-paper')).toBe(true); | ||
| expect(paper.el.classList.contains('joint-jj-paper')).toBe(true); |
Contributor
There was a problem hiding this comment.
this is wrong. revert it please. You need the latest joint-react
kumilingus
reviewed
May 14, 2026
| * @param minPathMargin - minimum path margin used by the underlying router. | ||
| */ | ||
| export function rightAngleRouter(margin: number, minPathMargin: number): routers.Router { | ||
| export function rightAngleRouter(margin: number = 0, minPathMargin: number = 0): routers.Router { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds two new React hooks to
@joint/react:useCollection(collection?, options?)/useCollection(collection?, selector, options?)— subscribe to anymvc.Collection<dia.Cell>(selection, clipboard, custom watchlists). Returns[cells, setCells](or[selected, setCells]). Options:onChange,isEqual. Built onuseSyncExternalStoreWithSelector.useSetCollection(collection?)— write-only sibling that returns the same setter without a subscription.The setter accepts full
CellRecordobjects (direct array or updater form). When a record'sidmatches an existing graph cell, attributes are merged into that cell inside agraph.startBatch/stopBatchwindow so changes flow through JointJS' normal change pipeline. Records for missing ids construct new cell instances via the graph'scellNamespace.Internals:
state/data-mapping/cell-record-merge.ts— extractedmergeCellRecord/toCellRecord/writeCellToContainer(shared bygraph-viewand the newcollection-view).store/collection-view.ts— mirrors anmvc.Collection<dia.Cell>into a records container using the samecreateContainer+mvc.Listenerpattern as the main graph view.GraphStoregainsacquireCollectionView/releaseCollectionView(refcount-cached, evicted on zero subscribers, torn down indestroy()).ArrayUpdate<T>type alias added next toUpdate<T>/AtomUpdate<T>instate-container.ts;useResetCellsrefactored to use it.areArraysShallowEqual,arrayAwareEqual) hoisted fromuse-cells.tstoutils/selector-utils.ts.Tests: 22 new tests covering reactivity on
data/attrs/size, selector form (records → ids), full-record setter under selector form, swap fromundefined→ defined collection, ref-counted view registry, batched cell-attribute setter.Storybook smoke: an interactive "Watchlist" demo (click to toggle membership, drag for live position updates, Shuffle / Resize / Clear via the setter, derived
Σ areavia selector).Motivation and Context
@joint/react-plusalready shipped an id-baseduseCollection. Bringing a records-based version into@joint/reactremoves the duplicated subscription plumbing across consumers (selection, clipboard, custom collections) and aligns the API withuseCellsso collection contents are first-class records rather than just ids — including reactive inner properties.