/*! JointJS React v4.3.6 (2026-09-04) - React bindings and hooks for JointJS to build interactive diagrams and graphs. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { dia, Vectorizer, util, mvc } from '@joint/core'; import * as react from 'react'; import react__default, { SVGTextElementAttributes, HTMLAttributes, ReactNode, JSX } from 'react'; import { P as PaperProps, E as ElementJSONInit, L as LinkJSONInit, A as AutoSizeOrigin, G as GraphStore, C as CellInput, O as OnIncrementalCellsChange, a as CellId, b as CellRef, c as ArrayUpdate, d as AnyCellRecord, e as CellRecord, f as Computed, g as PaperTarget, h as ElementRecord, i as ELEMENT_MODEL_TYPE, j as LINK_MODEL_TYPE, k as LinkLayout } from './use-cell-drag-shT4kvtb.js'; export { l as CanConnectOptions, m as CellDragState, n as CellInteractivity, o as CellInteractivityParams, p as CellVisibility, q as CellVisibilityParams, r as ConnectionEnd, s as ConnectionStrategy, t as ConnectionStrategyOptions, u as ConnectionStrategyParams, v as ConnectionStrategyPin, D as DEFAULT_PAPER_ID, w as DefaultLink, x as DefaultLinkParams, y as ElementModel, z as ElementPort, B as ElementPortShape, F as ElementPosition, H as ElementSize, I as IncrementalCellsChange, J as LinkLabel, K as LinkMarker, M as LinkMarkerName, N as LinkMarkerOptions, Q as LinkMarkerRecord, R as LinkMode, S as LinkModel, T as LinkRecord, U as LinkRoutingOrthogonalOptions, V as LinkRoutingSmoothOptions, W as LinkRoutingStraightOptions, X as LinkStyle, Y as MeasureElementOptions, Z as PaperApi, _ as PaperEventHandler, $ as PaperEventMap, a0 as PaperOptions, a1 as PaperTransform, a2 as PortalHostCell, a3 as PortalSelector, a4 as PortalSelectorParams, a5 as RenderElement, a6 as RenderLink, a7 as TransformElementLayout, a8 as TransformElementLayoutParams, a9 as ValidateConnection, aa as ValidateConnectionParams, ab as ValidateEmbedding, ac as ValidateEmbeddingParams, ad as ValidateUnembedding, ae as ValidateUnembeddingParams, af as elementAttributes, ag as elementPort, ah as elementPorts, ai as linkAttributes, aj as linkLabel, ak as linkLabels, al as linkMarkerArrow, am as linkMarkerArrowDouble, an as linkMarkerArrowOpen, ao as linkMarkerArrowQuill, ap as linkMarkerArrowSunken, aq as linkMarkerCircle, ar as linkMarkerCross, as as linkMarkerDiamond, at as linkMarkerFork, au as linkMarkerForkClose, av as linkMarkerLine, aw as linkMarkerMany, ax as linkMarkerManyOptional, ay as linkMarkerOne, az as linkMarkerOneOptional, aA as linkMarkerOneOrMany, aB as linkRoutingOrthogonal, aC as linkRoutingSmooth, aD as linkRoutingStraight, aE as linkStyle, aF as linkStyleLine, aG as linkStyleWrapper, aH as resolveLinkMarker, aI as useCellDrag, aJ as useMeasureElement, aK as useOnPaperEvents, aL as usePaper } from './use-cell-drag-shT4kvtb.js'; import * as _joint_core_types_dia_d_ts from '@joint/core/types/dia.d.ts'; import * as _joint_core_types_geometry_d_ts from '@joint/core/types/geometry.d.ts'; import '@joint/core/types/dia'; import '@joint/core/types/internal'; /** * The interactive diagram canvas. * * Renders the graph's elements and links, hosts user interactions * (selection, drag, link creation, zoom/pan), and lets you customize each * cell with your own React components. Mount inside a `` and * size it with CSS. The canvas fills its parent. * @example * ```tsx * import { GraphProvider, Paper, HTMLBox, type CellRecord } from '@joint/react'; * * interface NodeData { * label: string; * } * * const initialCells: ReadonlyArray> = [ * { id: '1', type: 'element', position: { x: 40, y: 40 }, data: { label: 'Hello' } }, * { id: '2', type: 'element', position: { x: 280, y: 180 }, data: { label: 'World' } }, * { id: 'edge', type: 'link', source: { id: '1' }, target: { id: '2' } }, * ]; * * function Diagram() { * return ( * * {data.label}} * /> * * ); * } * ``` * @see {@link PaperProps} for the full prop surface. * @group Components */ declare const Paper: (props: PaperProps & { ref?: react__default.Ref; }) => react__default.ReactNode; /** * Props for {@link SVGText}: native SVG `` attributes plus the JointJS * Vectorizer text options (end-of-line marker, vertical anchor, line height, * text-on-path, annotations) and opt-in word wrapping. * @expand * @group Types */ interface SVGTextProps extends SVGTextElementAttributes, Vectorizer.TextOptions { /** * Wrapping width in pixels for the `textWrap` pass. Falls back to the graph * element's current width when omitted. */ readonly width?: number; /** * Maximum height in pixels for the `textWrap` pass; lines that overflow it * are dropped. */ readonly height?: number; /** * Wrap the text to the available `width` using the JointJS `util.breakText` * algorithm. Pass `true` for the defaults, or an options object to fine-tune * wrapping (ellipsis, max line count, hyphenation, …). * @default false */ readonly textWrap?: boolean | util.BreakTextOptions; } /** * Renders an SVG `` element with JointJS-quality text layout: word * wrapping, custom line breaks, vertical alignment, line height, text-on-path, * and rich annotations. Use it inside `` to label or * caption an element; its children must be a single string. * * The text is laid out with the JointJS Vectorizer (`V(...).text()`), and * `textWrap` runs `util.breakText` so long strings wrap to the element's width. * See {@link SVGTextProps} for every supported option. * @group Components * @example Basic label * ```tsx * import { Paper, SVGText } from '@joint/react'; * * // Label each element with a static caption. * Hello World} /> * ``` * @example Wrap text to a fixed width * ```tsx * import { Paper, SVGText } from '@joint/react'; * * // Wrap a long caption to the element's current width. * ( * * This is a long text that will wrap to multiple lines * * )} * /> * ``` * @example Vertical anchor, line height, and line breaks * ```tsx * import { Paper, SVGText } from '@joint/react'; * * // A real "\n" in the string is what splits the content into two lines, so * // pass it through an expression container (not raw JSX text, where "\n" * // stays literal). textVerticalAnchor centers the block and lineHeight sets * // the spacing between the lines. * ( * * {'Line 1\nLine 2'} * * )} * /> * ``` */ declare const SVGText: (props: SVGTextProps & { ref?: react__default.Ref; }) => react__default.ReactNode; /** Cells array accepted by GraphProvider. */ type ProviderCells = ReadonlyArray; /** * Props for {@link GraphProvider} — pick the graph source (existing * instance, initial cells, or a controlled cells array) and subscribe to changes. * @template Element - Shape of the element cells stored in the graph. * @template Link - Shape of the link cells stored in the graph. * @expand * @group Types */ interface GraphProviderProps { /** * Pre-existing JointJS graph instance to use. If omitted, GraphProvider * creates a fresh `new dia.Graph(...)`. * @see [`dia.Graph`](https://docs.jointjs.com/api/dia/Graph) */ readonly graph?: dia.Graph; /** React children rendered inside the provider, typically a ``. */ readonly children?: react__default.ReactNode; /** * Cell namespace passed to `new dia.Graph`. Your entries are merged on top of * the built-ins, so JointJS shapes and the `@joint/react` {@link ElementModel} * / {@link LinkModel} stay available even when you register custom shapes. * @default JointJS `shapes` plus the `@joint/react` cell models */ readonly cellNamespace?: unknown; /** * Base model class used for every cell the graph constructs from JSON. Maps to * the (deprecated) `cellModel` option of `dia.Graph`; prefer `cellNamespace`, * which registers shapes by `type` and supports per-type model classes. * @see [`dia.Graph`](https://docs.jointjs.com/api/dia/Graph) */ readonly cellModel?: typeof dia.Cell; /** * Reference point that stays fixed when an auto-sized element's measured * size changes (via {@link useMeasureElement}). Mirrors CSS `transform-origin` semantics. * - `'top-left'` (default): element grows right/down. * - `'center'`: element grows symmetrically, its geometric center stays put. * * Only affects measurement-driven writes. Manual `cell.resize()`, interactive * resize tools, and direct `cell.set('size', ...)` calls are unaffected. * @default 'top-left' */ readonly autoSizeOrigin?: AutoSizeOrigin; /** * Pre-built `GraphStore` instance. When provided, GraphProvider does not own its lifecycle. * @hidden */ readonly store?: GraphStore; /** * Cells used to seed the graph once, at mount, for uncontrolled mode. Later * changes to this array are not applied. Ignored when `cells` is provided. * @see {@link CellInput} */ readonly initialCells?: ReadonlyArray>; /** * Controlled cells array. Whenever this array changes, the graph is re-synced * to match it (and `initialCells` is ignored); passing the same reference on a * re-render does not re-sync. Pair it with `onCellsChange` to mirror user edits * back into your own state. */ readonly cells?: ProviderCells; /** * Fires after each graph change with the full, updated cells array. Use it to * keep external React state in sync with the graph; it is notification only * and does not itself write anything back into the graph. */ readonly onCellsChange?: (newCells: ProviderCells) => void; /** * Fires after each commit with the granular `added` / `changed` / `removed` * delta, so you can apply just the change to an external store (Redux, Zustand, * etc.). Works in both controlled and uncontrolled mode. * @see {@link IncrementalCellsChange} */ readonly onIncrementalCellsChange?: OnIncrementalCellsChange; } /** * Provider props normalised to the unparameterised base shape. * * Internally GraphProvider stores the `GraphStore` with default generics * (`ElementAttributes` / `LinkAttributes`). Each `useGraphStore()` call * re-binds the generics on read, the runtime instance is the same. */ type GraphProviderBaseInternalProps = GraphProviderProps; /** * Internal base component for GraphProvider. * * Operates exclusively on the base record shape so the runtime instance can * flow into the unparameterised `GraphStoreContext` without a variance cast. * The exported {@link GraphProvider} re-types this base to the caller's `` parameters. * @param props - GraphProvider props. * @returns The rendered graph context provider or null while loading. */ declare function GraphBase(props: Readonly): react__default.ReactNode; /** * Creates (or adopts) a JointJS graph and shares it with every `` and * graph hook rendered inside it. Mount it near the root of your diagram: hooks * like {@link useGraph}, {@link useCells}, and {@link useCell} read the graph * from its context and throw when used outside a provider. * * It works in three modes, depending on which props you pass: pass * `initialCells` to let JointJS own the graph after mount (uncontrolled), pass * `cells` + `onCellsChange` to drive the graph from React state (controlled), or * pass `onIncrementalCellsChange` to forward deltas to an external store. * @example Uncontrolled — seed once, JointJS owns the graph * ```tsx * import { GraphProvider, Paper } from '@joint/react'; * * // `renderElement` receives the element's `data` slice only — not its * // geometry. Read position/size with the context hooks (e.g. useCell) when * // you need them. * * } /> * * ``` * @example Controlled — React state owns the cells * ```tsx * import { useState } from 'react'; * import { GraphProvider, Paper, type CellRecord } from '@joint/react'; * * const [cells, setCells] = useState([]); * * * * ``` * @example Incremental — forward deltas to an external store * ```tsx * import { GraphProvider, Paper } from '@joint/react'; * * { * // forward the { added, changed, removed } delta to your external store * store.apply(delta); * }} * > * * * ``` * @see {@link GraphProviderProps} for the full list of props. * @group Components */ declare const GraphProvider: (props: GraphProviderProps) => ReturnType; /** * Props accepted by {@link HTMLHost}. Inherits all standard `
` attributes. * @expand * @group Types */ interface HTMLHostProps extends HTMLAttributes { /** * Skip measuring the rendered content and size the host from the graph * element's stored geometry instead. Cheaper, but the element no longer * auto-resizes when the React subtree changes. * @default false */ readonly useModelGeometry?: boolean; } /** * Renders a graph element as an unstyled HTML node you fully control. Reach for * this inside `` when you want plain DOM (a `
`, * inputs, your own components) instead of SVG shapes, with no default theme. * * All props are spread onto the inner `
` (`children`, `style`, * `className`, event handlers, `data-*`, etc.), and a forwarded `ref` lands on * that same inner `
` — so a parent can focus or measure the host directly. * By default the host measures its content via {@link useMeasureElement} and * syncs that size back to the graph element; set `useModelGeometry` to skip * measurement and size the host from the element's model geometry instead. * * Applies no default styling. For a ready-themed box driven by `--jj-box-*` CSS * variables, use {@link HTMLBox} instead. * @example * ```tsx * import { Paper, HTMLHost } from '@joint/react'; * * // Render each element as your own HTML node and style it via CSS. * ( * {label} * )} /> * ``` * @group Components */ declare const HTMLHost: react.ForwardRefExoticComponent & react.RefAttributes>; /** * Props for {@link HTMLBox}. Same shape as {@link HTMLHostProps}: `className` is * merged with the `jj-box` class and `style` is layered on top of the default * box styling before reaching the underlying {@link HTMLHost}; the rest pass * through unchanged. * @expand * @group Types */ interface HTMLBoxProps extends HTMLHostProps { } /** * Renders a graph element as a pre-styled HTML box. Reach for this inside * `` when you want elements that already look good * without writing any CSS. * * Wraps {@link HTMLHost} and adds the `jj-box` class, which themes the box * through `--jj-box-*` CSS variables (background, border, radius, padding, * font). Like {@link HTMLHost}, it measures its content and syncs the size back * to the element by default; set `useModelGeometry` to size it from the model * instead. All props reach the underlying {@link HTMLHost}; `className` is merged * with the `jj-box` class and `style` is layered on top of the default box * styling, while the rest pass through unchanged. Use {@link HTMLHost} directly * when you want a blank host with no default styling. * @example * ```tsx * import { Paper, HTMLBox } from '@joint/react'; * * // Each element renders as a ready-styled box showing its label. * {label}} /> * ``` * @group Components */ declare function HTMLBox(props?: Readonly): ReactNode; /** * Options for a {@link Transaction}. * @group Types */ interface TransactionOptions { /** * Restore the graph to its pre-transaction state when the callback throws or * its promise rejects. Disabled by default; pass `true` to roll back on error * (otherwise partial edits are kept). The error is always re-thrown. * * Comes with an up-front overhead: enabling it snapshots the full cells * array at transaction start (an `O(n)` shallow copy over every cell in the * graph), even when the callback succeeds and no rollback is needed. Leave * off for large graphs where the callback is trusted not to throw. */ readonly rollbackOnError?: boolean; /** * Defer paint on every paper bound to the graph for the duration, so all views * repaint once when the transaction closes instead of on every edit. Disabled * by default; pass `true` to coalesce the repaint (hides intermediate frames). */ readonly deferPaint?: boolean; /** * Name of the JointJS batch used to group the edits — drives undo grouping and * identifies the batch on `batch:start` / `batch:stop`. Defaults to `'transaction'`. */ readonly name?: string; } /** * Runs a callback as one atomic transaction: every graph edit inside it * collapses into a single undo entry and a single React update (async edits * split across `await`s coalesce too). * * Pass `rollbackOnError: true` to restore the graph to its pre-transaction * state when the callback throws or rejects (the error is always re-thrown), and * `deferPaint: true` to defer paint on every bound paper so views repaint once, * on close. The callback may be sync or `async`; an async callback is awaited * before the transaction closes and the call returns the pending promise. * @group Types */ type Transaction = (callback: () => TResult, options?: TransactionOptions) => TResult; /** * Updater function form for {@link SetCell}. Receives the current cell record * (read from the cells container) and returns the next record. Invoked * exactly once with the real previous value. * @template Element - element record shape * @template Link - link record shape * @group Types */ type SetCellUpdater = (previous: Element | Link) => Element | Link; /** * Function exposed by {@link GraphApi}.setCell. Three forms: * - `setCell(record)`, direct form. `record.id` names the target. Cell * exists: attributes merge over it. Cell missing: cell is added. * - `setCell(diaCell)`, dia.Cell form. The cell is converted to a record * and handled like the direct form. * - `setCell(id, updater)`, updater form. The updater is called once with the * real previous record. A nullish `id`, or an `id` with no matching cell, * warns in dev and no-ops, pass the direct form to add a new cell. * @template Element - element record shape * @template Link - link record shape * @group Types */ interface SetCell { (record: CellInput, metadata?: Record): void; (id: CellId | null | undefined, updater: SetCellUpdater, metadata?: Record): void; } /** * Updater form for `SetCellData`. Receives the cell's current `data` and * returns the next `data`. The return value replaces `data` wholesale, perform * a partial update by merging inside the updater * (`(prev) => ({ ...prev, ...patch })`). * @template Data - cell data shape * @group Types */ type SetCellDataUpdater = (previousData: Data) => Data; /** * Function exposed by {@link GraphApi}.setCellData. Two forms, both keyed by * cell id: * - `setCellData(id, data)`, replaces the cell's `data` with `data`. * - `setCellData(id, (prev) => next)`, updater form; `prev` is the current * `data`, the return value replaces it. * * A nullish `id`, or an `id` with no matching cell, warns in dev and no-ops. * updating data implies the cell is already on the graph (use `setCell` to add * a new one). * @template Data - cell data shape (defaults to an open `Record`) * @group Types */ interface SetCellData> { (id: CellId | null | undefined, updater: SetCellDataUpdater, metadata?: Record): void; (id: CellId | null | undefined, data: Data, metadata?: Record): void; } /** * The shape of the graph's JSON export, as produced by `graph.toJSON()`. * @group Types */ type GraphJSON = dia.Graph.JSON; /** Drops an untyped (`unknown`) `data` side so it doesn't collapse a union. */ type TypedData = unknown extends Data ? never : Data; /** * `data` type for the GraphApi's `setCellData`, derived from {@link useGraph}'s * `Element` / `Link` generics by reusing each record's `['data']`: * - both sides untyped → open `Record` (keeps the no-generic * {@link useGraph}() spreadable) * - one side typed → that side's data * - both sides typed → their union (narrow inside the updater) * * A cell id is opaque at the type level, so this cannot narrow element-vs-link * per call, it exposes the data shapes {@link useGraph} was told about. */ type HandleCellData = [ TypedData | TypedData ] extends [never] ? Record : TypedData | TypedData; /** * Imperative API returned by {@link useGraph}. * @template Element - element record shape (e.g. `ElementRecord` for * write input, `Computed>` for reads) * @template Link - link record shape (e.g. `LinkRecord` / * `Computed>`) * @expand * @group Types */ interface GraphApi { /** The JointJS graph instance. */ readonly graph: dia.Graph; /** * Add or update a cell. Two forms: * - `setCell(record)`, `record.id` names the target. Existing cell: * attributes merge over it. Missing cell: the cell is added. * - `setCell(id, (prev) => next)`, updater form. The updater is invoked * once with the real previous record. A nullish `id`, or an `id` with no * matching cell, warns in dev and no-ops (use the direct form to add). */ readonly setCell: SetCell; /** * Set a single cell's `data` field. Two forms, both keyed by cell id: * - `setCellData(id, data)`, replaces the cell's `data` with `data`. * - `setCellData(id, (prev) => next)`, updater form; `prev` is the current * `data`, the return value replaces it (merge inside the updater for a * partial update). A nullish `id`, or an `id` with no matching cell, warns * in dev and no-ops. * * The `data` type is derived from the `useGraph` generics: * typed records flow through, otherwise it falls back to * `Record`. A cell id can't be narrowed to element-vs-link * at the type level, so when both are typed the updater sees their union. * Narrow inside it, or fix the `data` shape via `useGraph>()`. */ readonly setCellData: SetCellData>; /** * Remove a cell by id or dia.Cell reference. A nullish reference warns in dev * and no-ops; a reference that resolves to no cell is a silent no-op. The * optional `metadata` is forwarded as the `graph.removeCells` event opt. */ readonly removeCell: (cellRef?: CellRef | null, metadata?: Record) => void; /** * Remove multiple cells by id or dia.Cell reference. A nullish array warns in * dev and no-ops; references that resolve to no cell are silently skipped. The * optional `metadata` is forwarded as the `graph.removeCells` event opt. */ readonly removeCells: (cellRefs?: readonly CellRef[] | null, metadata?: Record) => void; /** * Atomically replace the cell set. Accepts dia.Cell instances alongside * records. The optional `metadata` is forwarded as the `graph.resetCells` opt. */ readonly resetCells: (input: ArrayUpdate>, metadata?: Record) => void; /** * Apply an updater to the current cells array. Updater may return dia.Cell * instances. The optional `metadata` is forwarded as the sync event opt. */ readonly updateCells: (updater: (previous: ReadonlyArray) => ReadonlyArray>, metadata?: Record) => void; /** * Predicate / type guard: true when the input resolves to an element cell. * Consults the graph's type registry so any `dia.Element` subclass (including * custom shapes) is recognised, not just the default {@link ElementModel}. */ readonly isElement: (input: Element | Link) => input is Element; /** * Predicate / type guard: true when the input resolves to a link cell. * Consults the graph's type registry so any `dia.Link` subclass (including * custom shapes) is recognised, not just the default {@link LinkModel}. */ readonly isLink: (input: Element | Link) => input is Link; /** * Serialize the graph to a plain JSON object. * * By default the output is **minimal**: attributes that match each cell's * `defaults` are dropped and empty `{}` placeholders are pruned everywhere * except inside `attrs` at the third nesting level (e.g. * `attrs.text.textWrap: {}` is a meaningful reset marker in JointJS shapes * and must survive). Pass `{ includeDefaults: true }` to keep every * attribute on every cell, no pruning is applied in that mode. */ readonly exportToJSON: (options?: ExportToJSONOptions) => GraphJSON; /** * Replace the graph contents from a previously exported JSON object * (e.g. produced by `exportToJSON`). Triggers JointJS's `reset` event so * all React subscriptions resync automatically. */ readonly importFromJSON: (json: GraphJSON) => void; /** * Run a callback as one atomic transaction: every edit inside collapses into * a single undo entry and (for sync callbacks) a single re-render. Pass * `{ rollbackOnError: true }` to restore the graph on error (off by default — * partial edits stay; enabling it snapshots the full cells array up-front, * so leave off for large graphs when the callback is trusted). See * {@link Transaction}. */ readonly transaction: Transaction; } /** * Options for {@link GraphApi}'s `exportToJSON`. * @expand * @group Types */ interface ExportToJSONOptions { /** * When `true`, every attribute is kept (defaults included) and no * empty-attribute pruning is applied. The default minimal output strips * attributes that match each cell's `defaults` and prunes empty `{}` * (except inside `attrs` at depth 3, e.g. `attrs.text.textWrap: {}`, which * JointJS treats as a meaningful reset marker). * @default false */ readonly includeDefaults?: boolean; } /** * Access the graph together with its imperative cell-mutation API for adding, * updating, removing, and serializing cells. Call this inside a * {@link GraphProvider}. * @template Element - element record shape (use `ElementRecord` for input, * `Computed>` for read shapes) * @template Link - link record shape (use `LinkRecord` / * `Computed>`) * @returns The {@link GraphApi}: the `dia.Graph` instance plus `setCell`, * `setCellData`, `removeCell`, `resetCells`, `exportToJSON`, and the * other cell actions. * @group Hooks * @example * ```tsx * import { GraphProvider, Paper, useGraph } from '@joint/react'; * * function Toolbar() { * const { setCell, exportToJSON } = useGraph(); * return ( * * ); * } * * function App() { * return ( * * * * * ); * } * ``` */ declare function useGraph(): GraphApi; /** * Subscribe to a collection's cells. Tracks collection membership * (`add`/`remove`/`reset`) and reads cell records from the GraphProvider's * container. Cells not in the graph (e.g. `ui.Clipboard` clones) fall back to * the collection's own `dia.Cell` instances, converted to records on demand. * @title Subscribe to a collection * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @param collection - JointJS collection whose member IDs drive the subscription * @returns readonly resolved cells array filtered by collection membership * @group Hooks */ declare function useCells(collection: mvc.Collection): ReadonlyArray>; /** * Subscribe to a collection's cells with a selector. * @title Select from a collection * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @template Selected - selector return type * @param collection - JointJS collection whose member IDs drive the subscription * @param selector - derive a value from the picked resolved cells array * @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) * @returns selected value */ declare function useCells>>(collection: mvc.Collection, selector: (cells: ReadonlyArray>) => Selected, isEqual?: (a: Selected, b: Selected) => boolean): Selected; /** * Subscribe to the full cells array. * * Returned array reference is stable across data-only mutations (the internal * container mutates items in-place). Size changes produce a new snapshot token. * @title Subscribe to all cells * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @returns readonly resolved cells array * @example * ```tsx * import { useCells } from '@joint/react'; * * function CellCount() { * const cells = useCells(); * return {cells.length} cells; * } * ``` */ declare function useCells(): ReadonlyArray>; /** * Subscribe to a single cell by id. * @title Subscribe to a cell by id * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @param id - cell id to track * @returns current resolved cell, or undefined when missing */ declare function useCells(id: CellId): Computed | undefined; /** * Subscribe to a single cell by id and derive a value from it. Subscribes * only to that id so unrelated mutations don't trigger re-renders. A nullish * `id` resolves to no cell, so the selector runs against `undefined`, handy * for optional selection state (`useCells(selectedId, ...)`) with no `?? ''`. * @title Select from a cell by id * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @template Selected - selector return type (defaults to `Cell | undefined`) * @param id - cell id to track (nullish → selector receives `undefined`) * @param selector - derive a value from the cell (or `undefined` when missing) * @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) * @returns selected value */ declare function useCells | undefined>(id: CellId | null | undefined, selector: (cell: Computed | undefined) => Selected, isEqual?: (a: Selected, b: Selected) => boolean): Selected; /** * Subscribe to a specific set of cells by id. Subscribes only to those ids * (not the full container) so unrelated mutations don't trigger re-renders. * Returns the picked cells in the order they appear in `ids`; missing ids * are skipped. The array reference is stable when no picked cell changed. * @title Subscribe to specific cells * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @param ids - cell ids to track * @returns array of resolved cells (only those that exist; missing ids are skipped) */ declare function useCells(ids: readonly CellId[]): ReadonlyArray>; /** * Subscribe to a specific set of cells by id and derive a value from them. * Subscribes only to those ids; the selector receives the picked cells array. * @title Select from specific cells * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @template Selected - selector return type (defaults to `readonly Cell[]`) * @param ids - cell ids to track * @param selector - derive a value from the picked resolved cells array * @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) * @returns selected value */ declare function useCells>>(ids: readonly CellId[], selector: (cells: ReadonlyArray>) => Selected, isEqual?: (a: Selected, b: Selected) => boolean): Selected; /** * Subscribe via a selector. Runs on every commit; return equal values to skip re-render. * @title Subscribe via a selector * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @template Selected - selector return type (defaults to `readonly Cell[]`) * @param selector - derive a value from the resolved cells array * @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) * @returns selected value * @example * ```tsx * import { useCells } from '@joint/react'; * * function ElementCount() { * // Counts cells whose type is the default 'element' and re-renders only when * // that count changes; shape-typed elements (e.g. 'standard.Rectangle') are * // not included. * const count = useCells((cells) => cells.filter((cell) => cell.type === 'element').length); * return {count} elements; * } * ``` */ declare function useCells>>(selector: (cells: ReadonlyArray>) => Selected, isEqual?: (a: Selected, b: Selected) => boolean): Selected; /** * Read the current cell from the closest `CellIdContext`, the id is provided * by `` around `renderElement` / `renderLink`. Use this inside a * render callback (or a component mounted from one) to access the full cell * record. * * Throws when used outside of a Paper render context, or when the id no longer * resolves to a cell in the store (e.g. deleted mid-render). * @title Read the current cell * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @returns the current resolved cell record * @group Hooks * @example * ```tsx * import { Paper, useCell } from '@joint/react'; * * function NodeLabel() { * // The id comes from the render callback context. * const cell = useCell(); * return {String(cell.id)}; * } * * } />; * ``` */ declare function useCell(): Computed; /** * Read a selected slice from the current cell (context-scoped). Re-renders * only when `isEqual(prev, next)` returns false. * * Throws if no cell resolves, never returns `undefined`. * @title Select from the current cell * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @template Selected - selector return type (defaults to `Cell`) * @param selector - derive a value from the current resolved cell record * @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) * @returns selected value * @example * ```tsx * import { useCell, selectElementData } from '@joint/react'; * * function NodeLabel() { * type NodeData = { label: string }; * // Re-renders only when this element's data changes. * const data = useCell(selectElementData); * return {data.label}; * } * ``` */ declare function useCell>(selector: (cell: Computed) => Selected, isEqual?: (a: Selected, b: Selected) => boolean): Selected; /** * Subscribe to a specific cell by id. Works anywhere, does not require * `CellIdContext`. Throws when the id does not resolve to a cell. * @title Read a cell by id * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @param id - cell id to track * @returns the resolved cell record * @example * ```tsx * import { useCell } from '@joint/react'; * * function CellTypeBadge({ id }: { id: string }) { * // Works outside a render callback too — subscribes to this id anywhere. * const cell = useCell(id); * return {cell.type}; * } * ``` */ declare function useCell(id: CellId): Computed; /** * Subscribe to a specific cell by id and derive a value from it. Works * anywhere, does not require `CellIdContext`. Throws when the id does not * resolve to a cell. * @title Select from a cell by id * @template Cell - input cell record shape (defaults to CellRecord); reads resolve to its Computed form * @template Selected - selector return type (defaults to `Cell`) * @param id - cell id to track * @param selector - derive a value from the resolved cell record * @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) * @returns selected value */ declare function useCell>(id: CellId, selector: (cell: Computed) => Selected, isEqual?: (a: Selected, b: Selected) => boolean): Selected; /** * Read the current cell id from the nearest `CellIdContext`. Populated by * `` around every `renderElement` / `renderLink` invocation. * * Use this inside a render callback (or any component mounted from one) when * you only need the id, it's cheaper than {@link useCell}() since * it never subscribes to store updates. Throws when used outside a Paper * render context. * @returns the current cell id * @group Hooks * @example * ```tsx * import { useCellId } from '@joint/react'; * * function MyElement() { * const id = useCellId(); * return {id}; * } * ``` */ declare function useCellId(): CellId; /** * Payload passed to the {@link useOnElementsMeasured} callback after a * measurement pass. * @group Types * @expand */ interface ElementsMeasuredParams { /** True on the first measurement pass (at least one element has been sized). */ readonly isInitial: boolean; /** The paper this hook is bound to (the surrounding `` context, or the paper passed via `paperTarget`). */ readonly paper: dia.Paper; /** The graph model associated with the paper. */ readonly graph: dia.Graph; } /** * Callback invoked by {@link useOnElementsMeasured} after each measurement pass; * receives the {@link ElementsMeasuredParams} payload. * @group Types */ type OnElementsMeasured = (params: ElementsMeasuredParams) => void; /** * Calls a callback when element sizes are measured or re-measured. * * Fires on the first measurement pass (at least one element has been sized) * and again whenever an element is resized. * * The callback receives {@link ElementsMeasuredParams}; check `isInitial` to * distinguish the first measurement from later ones. * @title On the current paper * @param callback - Called each time element sizes are measured. * @group Hooks * @example * ```tsx * import { useOnElementsMeasured } from '@joint/react'; * * // Mount inside a : fit the surrounding paper once everything is sized. * function FitOnMeasure() { * useOnElementsMeasured(({ paper, isInitial }) => { * if (isInitial) { * paper.transformToFitContent({ padding: 20 }); * } * }); * return null; * } * ``` */ declare function useOnElementsMeasured(callback: OnElementsMeasured): void; /** * Calls a callback when element sizes are measured, targeting a specific paper * instead of the surrounding context. Useful when several papers share one graph. * @title On a specific paper * @param paperTarget - Which paper to watch: a registered paper id, a * `dia.Paper` instance, or a React ref to one. * @param callback - Called each time element sizes are measured. * @group Hooks * @example * ```tsx * import { useOnElementsMeasured } from '@joint/react'; * import { useRef } from 'react'; * import type { dia } from '@joint/core'; * * function FitSpecificPaper() { * const paperRef = useRef(null); * useOnElementsMeasured(paperRef, ({ paper }) => { * paper.transformToFitContent({ padding: 20 }); * }); * return null; * } * ``` */ declare function useOnElementsMeasured(paperTarget: PaperTarget, callback: OnElementsMeasured): void; /** * Maps JointJS graph event names to their handler callbacks, the shape * {@link useOnGraphEvents} accepts. Every entry is optional, list only the * events you want to react to. Keys and handler arguments mirror * [`dia.Graph` events](https://docs.jointjs.com/api/dia/Graph#events) one to one * (`'add'`, `'remove'`, `'change:position'`, …). * @group Types */ type GraphEventMap = Partial; /** * Subscribes to graph events by their native JointJS names, so you can react to * cells being added, removed, moved, or otherwise changed without wiring up * listeners by hand. This form reads the graph from the surrounding * `` and throws when used outside one. * * Handlers are **always-latest**: the subscription is established once and each * event reads the current handler, so inline maps and closures need no * `useCallback`. Re-subscription happens only when the graph or the set of event * names changes. * * See {@link GraphEventMap} for the available event names and their arguments. * @title On the current graph * @param handlers - Map of JointJS graph event names to callbacks. * @group Hooks * @example * ```tsx * import { GraphProvider, useOnGraphEvents } from '@joint/react'; * * function CellLogger() { * useOnGraphEvents({ * add: (cell) => console.log('added', cell.id), * remove: (cell) => console.log('removed', cell.id), * 'change:position': (cell) => console.log('moved', cell.id), * }); * return null; * } * * // Mount inside a so the hook can find the graph. * * * * ``` */ declare function useOnGraphEvents(handlers: GraphEventMap): void; /** * Subscribes to graph events on a graph instance you pass in explicitly. Reach * for this when you hold a `dia.Graph` outside of any `` (e.g. a * graph you created yourself). Same always-latest handler semantics as the * context form. * @title On a specific graph * @param graph - The graph instance to listen on. * @param handlers - Map of JointJS graph event names to callbacks. * @group Hooks * @example * ```tsx * import { dia } from '@joint/core'; * import { useOnGraphEvents } from '@joint/react'; * * function useGraphLogger(graph: dia.Graph) { * useOnGraphEvents(graph, { * add: (cell) => console.log('added', cell.id), * }); * } * ``` */ declare function useOnGraphEvents(graph: dia.Graph, handlers: GraphEventMap): void; /** * Options for {@link MarkupApi}'s `magnetRef`. * @expand * @group Types */ interface MagnetRefOptions { /** * When `true`, the magnet is passive: a valid connection target but not a * source. When `false`, it is active and links can also start from it. * @default false */ readonly passive?: boolean; } /** * Markup utilities returned by {@link useMarkup}. * @expand * @group Types */ interface MarkupApi { /** * Returns a React ref callback that registers the node under the given selector * name so links and tools can target it by name. * @param selector - Unique selector name within the element (e.g. `'body'`, `'item-0'`). * @throws If `selector` is one of the reserved names (`__portal__`, `root`, `portRoot`). */ readonly selectorRef: (selector: string) => (node: Element | null) => void; /** * Returns a React ref callback that registers the node under the given selector name * AND marks it as a JointJS magnet, a valid endpoint for link connections. * @param selector - Unique selector name within the element (e.g. `'port-in'`, `'row-0'`). * @param options - Magnet behavior options. * @throws If `selector` is one of the reserved names (`__portal__`, `root`, `portRoot`). */ readonly magnetRef: (selector: string, options?: MagnetRefOptions) => (node: Element | null) => void; } /** * Register SVG sub-elements as JointJS selectors (and optionally magnets) on * the current element view, so links and tools can target named parts of a * React-rendered element. Must be used inside `renderElement`. * @group Hooks * @returns The {@link MarkupApi}: a `selectorRef` factory that tags an SVG node * under a named selector so links and tools can target it, and a `magnetRef` * factory that does the same and also marks the node as a connectable magnet. * @example * ```tsx * import { useMarkup } from '@joint/react'; * * function MyComponent({ labels }: { labels: string[] }) { * const { selectorRef, magnetRef } = useMarkup(); * return ( * // Tag the group as the 'body' selector so tools can target it. * * {labels.map((label, index) => ( * // Each row is a magnet, so links can connect to it. * * {label} * * ))} * * ); * } * ``` */ declare function useMarkup(): MarkupApi; /** * Ready-made selectors to pass into {@link useCell} / {@link useCells}. * * Each one picks a single field off the resolved cell record so a component * re-renders only when that field changes, not on every unrelated cell update. * Reach for them when you want to subscribe to just the position, size, data, * or another slice of a cell. */ /** * Selects an element's top-left position `{ x, y }`. A subscribed component * re-renders only when the element moves. * @group Selectors * @param element - the resolved element record * @example * ```tsx * import { useCell, selectElementPosition } from '@joint/react'; * * const { x, y } = useCell(elementId, selectElementPosition); * ``` */ declare function selectElementPosition(element: Computed): _joint_core_types_geometry_d_ts.PlainPoint; /** * Selects an element's bounding-box size `{ width, height }`. A subscribed * component re-renders only when the element is resized. * @group Selectors * @param element - the resolved element record * @example * ```tsx * import { useCell, selectElementSize } from '@joint/react'; * * const { width, height } = useCell(elementId, selectElementSize); * ``` */ declare function selectElementSize(element: Computed): _joint_core_types_dia_d_ts.Size; /** * Selects an element's rotation in degrees, falling back to `0` when the * element has no explicit angle. * @group Selectors * @param element - the resolved element record * @example * ```tsx * import { useCell, selectElementAngle } from '@joint/react'; * * const angle = useCell(elementId, selectElementAngle); * ``` */ declare function selectElementAngle(element: Computed): number; /** * Selects an element's custom `data` payload, typed as `ElementData`. Supply * the type when you call it (`selectElementData`) and TypeScript * carries `NodeData` through to the value {@link useCell} returns. * @group Selectors * @template ElementData - shape of the custom `data` payload carried on the element * @param element - the resolved element record * @example * ```tsx * import { useCell, selectElementData } from '@joint/react'; * * type NodeData = { label: string }; * const data = useCell(elementId, selectElementData); * ``` */ declare function selectElementData(element: Computed>): ElementData; /** * Selects a cell's id. Prefer {@link useCellId} when the id is all you need — * it skips the selector machinery. * @group Selectors * @param cell - the resolved cell record * @example * ```tsx * import { useCell, selectCellId } from '@joint/react'; * * const id = useCell(cellId, selectCellId); * ``` */ declare const selectCellId: (cell: Computed) => string | number; /** * Selects a cell's `type` discriminator — `'element'` for React elements or * `'link'` for React links. Handy for branching on the kind of cell. * @group Selectors * @param cell - the resolved cell record * @example * ```tsx * import { useCell, selectCellType } from '@joint/react'; * * const type = useCell(cellId, selectCellType); * ``` */ declare const selectCellType: (cell: Computed) => "link" | "element"; /** * Selects the id of the cell this one is embedded in, or `null` for a * top-level cell. Works for elements and links alike, since any cell can be * embedded. * @group Selectors * @param cell - the resolved cell record * @example * ```tsx * import { useCell, selectCellParent } from '@joint/react'; * * const parentId = useCell(cellId, selectCellParent); * ``` */ declare const selectCellParent: (cell: Computed) => CellId | null; /** * Selects the name of the paper layer the cell renders into, or `null` when it * sits on the paper's default layer. * @group Selectors * @param cell - the resolved cell record * @example * ```tsx * import { useCell, selectCellLayer } from '@joint/react'; * * const layer = useCell(cellId, selectCellLayer); * ``` */ declare const selectCellLayer: (cell: Computed) => string | null; /** * Selects a cell's z-index — its paint order within a layer, where higher * values draw on top. Falls back to `0` when the cell has no explicit z-index. * @group Selectors * @param cell - the resolved cell record * @example * ```tsx * import { useCell, selectCellZIndex } from '@joint/react'; * * const z = useCell(cellId, selectCellZIndex); * ``` */ declare const selectCellZIndex: (cell: Computed) => number; /** The member type of a cells array; passes a non-array `Cells` through. */ type CellArrayMember = Cells extends ReadonlyArray ? Member : Cells; /** * Infer the element record type from a cells collection, typically * `typeof cells`. Selects the member whose `type` is `'element'`, so a mixed * array narrows to its element variant with the inferred `data` shape. * Compose with {@link Computed} for reading hooks, or index `['data']` for the * render-data type. * * Custom shapes (a `type` other than `'element'`) are excluded, type the * record union manually for those, as documented on {@link CellRecord}. * @template Cells - the cells collection to infer from, usually `typeof cells` * @group Types * @example * ```ts * import type { InferElement } from '@joint/react'; * * const cells = [ * { id: 'a', type: 'element', data: { label: 'A' } }, * { id: 'e', type: 'link', source: { id: 'a' }, target: { id: 'b' }, data: { weight: 2 } }, * ] as const; * * type Node = InferElement; // element variant of the union * type NodeData = InferElement['data']; // { label: 'A' } * ``` */ type InferElement = Extract, { readonly type: typeof ELEMENT_MODEL_TYPE; }>; /** * Infer the link record type from a cells collection, the link counterpart of * {@link InferElement}. Selects the member whose `type` is `'link'`. * @template Cells - the cells collection to infer from, usually `typeof cells` * @group Types * @example * ```ts * import type { InferLink } from '@joint/react'; * * const cells = [ * { id: 'a', type: 'element', data: { label: 'A' } }, * { id: 'e', type: 'link', source: { id: 'a' }, target: { id: 'b' }, data: { weight: 2 } }, * ] as const; * * type Edge = InferLink; // link variant of the union * type EdgeData = InferLink['data']; // { weight: 2 } * ``` */ type InferLink = Extract, { readonly type: typeof LINK_MODEL_TYPE; }>; /** * Converts a JSX tree into static JointJS markup (`dia.MarkupJSON`), ready to * assign as a cell's `markup`. Intrinsic SVG/HTML tags become markup nodes; * function components are rendered once and their output is converted; fragments * (and any non-string element type) are unwrapped so their children flow through * without a wrapper node. * * Text, number, boolean, and `null` children become text content; any other * child type throws. This is a one-time, static conversion with no hooks, no * state, and no React lifecycle, so author plain markup here rather than * interactive components. * @param element - The JSX tree to convert, typically authored inline as ``. * @returns The equivalent JointJS markup array. * @remarks * Two prop conventions are translated for you: * - `className` is emitted as the SVG `class` attribute. * - Any `joint-*` prop is lifted onto the markup node itself, e.g. * `joint-selector="body"` sets the node's `selector` (the same selector names * that {@link useMarkup} registers at runtime). * @example * ```tsx * import { jsx } from '@joint/react'; * * const markup = jsx( * * * Hello * * ); * ``` * @group Utils */ declare function jsx(element: JSX.Element): dia.MarkupJSON; /** * Returns the current link's rendered geometry, its source and target endpoint * coordinates plus the SVG path string (`{ sourceX, sourceY, targetX, targetY, * d }`, where `d` is the path computed by JointJS). Use it to draw custom link * decorations, labels, or overlays that need to follow the link's actual route. * * Geometry is per-paper: the same link can render with different routing on * different papers (e.g. the main canvas and a minimap), so the hook reports the * geometry on the paper it is mounted under. The value stays in sync, it * re-reads after every render pass, covering drags, programmatic position * changes, source/target reconnections, and resizes. * * Call it inside `renderLink` (or a component mounted from one) so the target * link id resolves from context. Returns `undefined` only until the link view * exists — no paper has mounted yet, or the view is still being created. Once the * view appears the value is always defined; it may briefly report zeroed * coordinates and an empty path string until JointJS computes the first route. * @returns The current link's layout, or `undefined` while no link view exists yet. * @experimental Depends on `renderLink`, which is itself experimental. * @group Hooks * @example * ```tsx * import { GraphProvider, Paper, useLinkLayout } from '@joint/react'; * * // A badge that tracks the midpoint of the link as it is routed. * function LinkMidpointBadge() { * const layout = useLinkLayout(); * if (!layout) return null; * const midX = (layout.sourceX + layout.targetX) / 2; * const midY = (layout.sourceY + layout.targetY) / 2; * return ; * } * * * } /> * * ``` */ declare function useLinkLayout(): LinkLayout | undefined; export { AnyCellRecord, AutoSizeOrigin, CellId, CellInput, CellRecord, CellRef, Computed, ELEMENT_MODEL_TYPE, ElementRecord, GraphProvider, HTMLBox, HTMLHost, LINK_MODEL_TYPE, LinkLayout, Paper, PaperProps, PaperTarget, SVGText, jsx, selectCellId, selectCellLayer, selectCellParent, selectCellType, selectCellZIndex, selectElementAngle, selectElementData, selectElementPosition, selectElementSize, useCell, useCellId, useCells, useGraph, useLinkLayout, useMarkup, useOnElementsMeasured, useOnGraphEvents }; export type { ElementsMeasuredParams, ExportToJSONOptions, GraphApi, GraphEventMap, GraphJSON, GraphProviderProps, HTMLBoxProps, HTMLHostProps, InferElement, InferLink, MagnetRefOptions, MarkupApi, OnElementsMeasured, SVGTextProps, Transaction, TransactionOptions };