[!NOTE]
The goal of this project is to define a minimal basis for the various React components for JointJS. Please help us shape the package by reporting issues or proposing API changes.
[!IMPORTANT]
This is an early stage product. The package may contain bugs and security issues. The API is subject to change.
Installation
yarn install jointjs @joint/react
API
Components
\<Paper />
The main component that allows you to draw nodes and edges on the canvas. In JointJS terminology, you draw cells (elements and links) on paper. The component requires the <GraphProvider /> to be its ancestor.
Props
Property
Type
Description
options?
dia.Paper.Options
The options of the paper. It's async by default.
renderElement?
(dia.Element) => React.JSX.Element \| null
A callback to render React components inside the paper element views. The components are rendered using the React.createPortal().
onReady?
(dia.Paper) => void
A callback that is triggered after the paper is mounted and ready (cells may not be rendered).
A list of model attributes that, if changed, will cause the renderElement function to be triggered. The default is ["data"].
portal?
Element \| string \| (dia.ElementView) => string \| Element
An HTMLElement or SVGElement (or a string selector) that serves as portal for rendering element's content. By default, the portal is selector "portal".
Rendering React component inside an Element view
By default, the content of the element view is rendered using JointJS. However, the content (SVG or HTML) can also be rendered using React.
import { dia, shapes } from 'jointjs';
import { GraphProvider, Paper } from '@joint/react';
// Assumes that the `portal` node is a foreign object descendant.
const renderHTMLElement = (element) => {
const { label, value } = element.get('data');
return (
<div className="my-element">
<h3>{label}</h3>
<input
type='text'
value={value}
onChange={(e) => element.prop('data/value', e.target.value)}
/>
</div>
);
};
export default function Diagram() {
const graph = new dia.Graph({}, { cellNamespace: shapes });
const paperProps = { /* ... */ };
return (
<GraphProvider graph={graph}>
<Paper renderHTMLElement={renderHTMLElement} ...paperProps />
</GraphProvider>
)
}
Currently, the following drawbacks are known with this approach:
content rendered with React cannot be the source/target of any link (it's always a good idea to also render the SVG \ under the portal node).
<Paper /> currently replaces the default dia.Paper.prototype.options.elementView with a custom ElementView that triggers the portal:ready event ((elementView: dia.ElementView, portalEl: SVGElement | HTMLElement) => void) when the portal node is rendered (onRender() method). If you want to use custom views and you want to use renderElement with them, make sure you trigger the portal:ready event manually.
Paper provides context implicitly.
The <Paper /> context provides the paper context to its descendants implicitly. If you need to use the paper context outside of the <Paper />, use the <PaperProvider />.
<GraphProvider graph={graph}>
<Paper>
<MySelection/>{/* component is using JointJS `paper` */}
</Paper>
</GraphProvider>
\<PaperProvider />
The <PaperProvider /> component is a context provider that makes it possible to access the JointJS paper outside of the <Paper /> component. Unlike the GraphProvider, the PaperProvider is not mandatory.
import { GraphProvider, PaperProvider, Paper } from '@joint/react';
export default function Diagram() {
return (
<GraphProvider graph={graph}>
<PaperProvider>
<Paper/>
<MyZoomInButton/>
<MyZoomOutButton/>
</PaperProvider>
</GraphProvider>
)
}
\<GraphProvider />
The <GraphProvider /> component is a context provider that provides JointJS graph to <Paper /> components. You need use the <GraphProvider /> in order to render the <Paper /> component.
Here's an example of a GraphProvider providing a graph to two papers.
A graph instance to be provided to the descendants
Hooks
The package exposed several custom hooks.
usePaper
The usePaper is a hook that let you use the JointJS paper from your component.
import { usePaper } from '@joint/react';
export default function MyZoomInButton() {
const paper = usePaper();
const zoomIn = () => {
if (!paper) return;
const { sx, sy } = paper.scale();
paper.scale(sx * 2, sy * 2);
}
return <button onClick={zoomIn}>Zoom In</button>
}
useGraph
The useGraph is a hook that let you use the JointJS graph from your component.
import { useGraph } from '@joint/react';
export default function MyDeleteAllButton() {
const graph = useGraph();
const deleteAll = () => {
if (graph && confirm("Are you sure you want to delete all content?")) {
graph.clear();
}
}
return <button onClick={deleteAll}>Delete All</button>
}
What's next
The possible tasks ahead of us.
JointJS+
Define React Components for JointJS+.
// NOTE: This is fictional code
// It is just an example of possible API.
import { dia, mvc } from '@joint/core';
import { CommandManager } from '@joint/command-manager';
import { Paper } from '@joint/react';
import DiagramProvider from '@joint/diagram-provider';
import Toolbar from '@joint/toolbar-react';
import Stencil from '@joint/stencil-react';
import Scroller from '@joint/scroller-react';
import Inspector from '@joint/inspector-react';
import Selection from '@joint/selection-react';
import Snaplines from '@joint/snaplines-react';
import Grid from 'some-ui-lib';
export default function Diagram() {
const graph = new dia.Graph();
const cmd = new CommandManager({ graph });
const selection = new mvc.Collection();
return (
<DiagramProvider graph={graph} commandManager={cmd} selection={selection}/>
<Toolbar />
<Grid>
<Stencil />
<Scroller />
<Paper >
<Selection />
<Snaplines />
</Paper>
<Scroller>
<Navigator />
</Grid>
<Navigator />
<DiagramProvider />
)
}
Higher-level Components
Define user-friendly higher-level components.
// Paper, Scroller, Toolbar, CommandManager as a single component
<Diagram preset="kitchen-sink" width={400} height={400} fitView={true} virtualRendering={true}></Diagram>
Description
An early stage React package for working with JointJS.
Demo: https://codesandbox.io/s/jointjs-react-vldmzw?file=/src/App.js
This is a copy of https://github.com/clientIO/joint/pull/2391 recreated for
v4
.JointJS React
React core components for working with JointJS.
Installation
API
Components
\<Paper />
The main component that allows you to draw nodes and edges on the canvas. In JointJS terminology, you draw
cells
(elements
andlinks
) onpaper
. The component requires the<GraphProvider />
to be its ancestor.Props
dia.Paper.Options
paper
. It'sasync
by default.(dia.Element) => React.JSX.Element \| null
React.createPortal()
.(dia.Paper) => void
paper
is mounted and ready (cells may not be rendered).(dia.Paper, eventName, ...eventArgs) => void
string[]
renderElement
function to be triggered. The default is["data"]
.Element \| string \| (dia.ElementView) => string \| Element
portal
is selector"portal"
.Rendering React component inside an Element view
By default, the content of the element view is rendered using JointJS. However, the content (SVG or HTML) can also be rendered using React.
Currently, the following drawbacks are known with this approach:
portal
node).<Paper />
currently replaces the defaultdia.Paper.prototype.options.elementView
with a customElementView
that triggers theportal:ready
event ((elementView: dia.ElementView, portalEl: SVGElement | HTMLElement) => void
) when theportal
node is rendered (onRender()
method). If you want to use custom views and you want to userenderElement
with them, make sure you trigger theportal:ready
event manually.Paper provides context implicitly.
The
<Paper />
context provides thepaper
context to its descendants implicitly. If you need to use thepaper
context outside of the<Paper />
, use the<PaperProvider />
.\<PaperProvider />
The
<PaperProvider />
component is a context provider that makes it possible to access the JointJS paper outside of the<Paper />
component. Unlike theGraphProvider
, thePaperProvider
is not mandatory.\<GraphProvider />
The
<GraphProvider />
component is a context provider that provides JointJS graph to<Paper />
components. You need use the<GraphProvider />
in order to render the<Paper />
component.Here's an example of a
GraphProvider
providing agraph
to twopapers
.Props
dia.Graph
graph
instance to be provided to the descendantsHooks
The package exposed several custom hooks.
usePaper
The
usePaper
is a hook that let you use the JointJSpaper
from your component.useGraph
The
useGraph
is a hook that let you use the JointJSgraph
from your component.What's next
The possible tasks ahead of us.
JointJS+
Define React Components for JointJS+.
Higher-level Components
Define user-friendly higher-level components.