@kolosal-ai/rivet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/anchor/index.d.ts +32 -0
- package/dist/anchor/index.js +21 -0
- package/dist/anchor/index.js.map +1 -0
- package/dist/chunk-6XRQSAQT.js +148 -0
- package/dist/chunk-6XRQSAQT.js.map +1 -0
- package/dist/chunk-AXT35ZJV.js +98 -0
- package/dist/chunk-AXT35ZJV.js.map +1 -0
- package/dist/chunk-VQYN27OK.js +36 -0
- package/dist/chunk-VQYN27OK.js.map +1 -0
- package/dist/index.d.ts +1012 -0
- package/dist/index.js +4849 -0
- package/dist/index.js.map +1 -0
- package/dist/registry-Dkk4ZKt-.d.ts +151 -0
- package/dist/svg/index.d.ts +127 -0
- package/dist/svg/index.js +126 -0
- package/dist/svg/index.js.map +1 -0
- package/dist/swimlane/index.d.ts +96 -0
- package/dist/swimlane/index.js +3 -0
- package/dist/swimlane/index.js.map +1 -0
- package/dist/types-B8AAJ60T.d.ts +515 -0
- package/package.json +70 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1012 @@
|
|
|
1
|
+
import { R as Rect, V as Vec2, A as AlignmentGuide, E as EdgeChange, a as RivetEdge, b as NodeChange, c as RivetNode, N as NodeId, d as NodeProps, e as NodeTypes, f as HandleType, H as HandlePosition, S as Size, g as Viewport, h as EdgeTypes, D as DefaultEdgeOptions, i as EdgeRendererFactory, j as SwimlaneGroup, k as SwimlaneMargin, l as SwimlaneHeaderProps, m as SwimlaneLabelProps, n as SwimlaneSizeChange, L as LaneChange, C as Connection, o as RivetSelection, p as EdgeId, q as HandleRecord, r as ReconnectDelegate, P as PendingConnection, s as RivetControls, t as RivetSnapshot, u as EdgeRenderer, v as EdgeRendererOptions, w as EdgeDrawExtras, x as EdgeEnd, y as EdgePathFn } from './types-B8AAJ60T.js';
|
|
2
|
+
export { z as CenterNodeOptions, B as EdgeMarker, F as EdgePath, G as EdgePathParams, I as EdgeStyle, J as FitViewOptions, K as NodeComponent } from './types-B8AAJ60T.js';
|
|
3
|
+
import { ReactNode, CSSProperties, MouseEvent, RefObject } from 'react';
|
|
4
|
+
import { b as AnchorOptions, d as AnchorRecord, f as AnchorRegistrationOptions, R as ResolvedAnchorOptions, e as AnchorRegistration } from './registry-Dkk4ZKt-.js';
|
|
5
|
+
import { ResolvedLane, ViewportElements, ResolvedSwimlaneGroup, ResolvedMargin } from './swimlane/index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Find the closest edge alignment between the moving rect and any static rect,
|
|
9
|
+
* within `threshold` (world units), independently per axis. Returns the offset
|
|
10
|
+
* to apply to `moving` so its aligned edge lands exactly on the neighbor's, plus
|
|
11
|
+
* the guide line(s) to draw. Pure — the drag loop supplies the rects.
|
|
12
|
+
*/
|
|
13
|
+
declare function alignRect(moving: Rect, statics: readonly Rect[], threshold: number): {
|
|
14
|
+
offset: Vec2;
|
|
15
|
+
guides: AlignmentGuide[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Apply a batch of {@link NodeChange}s to a nodes array, returning a new array
|
|
20
|
+
* (the input is not mutated). Order is preserved; added nodes are appended.
|
|
21
|
+
*
|
|
22
|
+
* Pair this with the graph's `onNodesChange` to run controlled mode:
|
|
23
|
+
* ```ts
|
|
24
|
+
* const [nodes, setNodes] = useState(initial)
|
|
25
|
+
* <Rivet nodes={nodes} onNodesChange={(c) => setNodes((ns) => applyNodeChanges(c, ns))} />
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
declare function applyNodeChanges<TData = unknown>(changes: NodeChange<TData>[], nodes: RivetNode<TData>[]): RivetNode<TData>[];
|
|
29
|
+
/**
|
|
30
|
+
* Apply a batch of {@link EdgeChange}s to an edges array, returning a new array.
|
|
31
|
+
* Order is preserved; added edges are appended. See {@link applyNodeChanges}.
|
|
32
|
+
*/
|
|
33
|
+
declare function applyEdgeChanges<TData = unknown>(changes: EdgeChange<TData>[], edges: RivetEdge<TData>[]): RivetEdge<TData>[];
|
|
34
|
+
|
|
35
|
+
/** Options for {@link cloneElements}. */
|
|
36
|
+
type CloneOptions = {
|
|
37
|
+
/**
|
|
38
|
+
* World-space offset applied to every top-level clone's position. Children of
|
|
39
|
+
* a copied parent keep their parent-relative position and ride along.
|
|
40
|
+
* Default `{0,0}`.
|
|
41
|
+
*/
|
|
42
|
+
offset?: Vec2;
|
|
43
|
+
/** Id generator for the clones. Default `crypto.randomUUID`. */
|
|
44
|
+
makeId?: () => NodeId;
|
|
45
|
+
};
|
|
46
|
+
/** The result of {@link cloneElements}: fresh nodes and their internal edges. */
|
|
47
|
+
type ClonedElements<TNodeData = unknown, TEdgeData = unknown> = {
|
|
48
|
+
nodes: RivetNode<TNodeData>[];
|
|
49
|
+
edges: RivetEdge<TEdgeData>[];
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Clone a set of nodes (and the edges wholly between them) with fresh ids —
|
|
53
|
+
* the core of copy/paste and duplicate. Edges are kept only when **both**
|
|
54
|
+
* endpoints are in the set (dangling connections to un-copied nodes are
|
|
55
|
+
* dropped). `parentId` is remapped when the parent is also copied, else cleared
|
|
56
|
+
* so the clone isn't orphaned to a missing parent. Transient flags are stripped;
|
|
57
|
+
* selecting the clones is the caller's job.
|
|
58
|
+
*/
|
|
59
|
+
declare function cloneElements<TNodeData = unknown, TEdgeData = unknown>(nodes: RivetNode<TNodeData>[], edges: RivetEdge<TEdgeData>[], options?: CloneOptions): ClonedElements<TNodeData, TEdgeData>;
|
|
60
|
+
|
|
61
|
+
type ControlsProps = {
|
|
62
|
+
/** Show the zoom-in / zoom-out buttons (default true). */
|
|
63
|
+
showZoom?: boolean;
|
|
64
|
+
/** Show the fit-view button (default true). */
|
|
65
|
+
showFitView?: boolean;
|
|
66
|
+
/** Extra buttons appended after the defaults. */
|
|
67
|
+
children?: ReactNode;
|
|
68
|
+
className?: string;
|
|
69
|
+
style?: CSSProperties;
|
|
70
|
+
};
|
|
71
|
+
/** A small zoom / fit-view button panel. Must be a child of `<Rivet>`. */
|
|
72
|
+
declare function Controls({ showZoom, showFitView, children, className, style, }: ControlsProps): React.ReactElement;
|
|
73
|
+
|
|
74
|
+
/** Fallback node used when a node's `type` has no entry in `nodeTypes`. */
|
|
75
|
+
declare function DefaultNode({ data, selected, hovered }: NodeProps): React.ReactElement;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Built-in container node (`type: "group"`) — the visual basis for sub-flows.
|
|
79
|
+
* A styled region with no content or handles of its own; children point at it
|
|
80
|
+
* via `parentId` (and `extent: "parent"` to stay confined). Give it explicit
|
|
81
|
+
* `width`/`height` — a group has no intrinsic content to measure. Children
|
|
82
|
+
* render above it automatically (z-index follows nesting depth).
|
|
83
|
+
*/
|
|
84
|
+
declare function GroupNode({ data, selected, hovered }: NodeProps): React.ReactElement;
|
|
85
|
+
/** The built-in node components, keyed by `type`. Consumer `nodeTypes` win. */
|
|
86
|
+
declare const BUILTIN_NODE_TYPES: NodeTypes;
|
|
87
|
+
|
|
88
|
+
type HandleProps = {
|
|
89
|
+
/**
|
|
90
|
+
* Whether this handle is a connection `source` or `target`. Optional — an
|
|
91
|
+
* untyped handle resolves to `"either"` and can start or receive a
|
|
92
|
+
* connection; a pair is valid when one end can source and the other can
|
|
93
|
+
* target. Set an explicit type to constrain direction.
|
|
94
|
+
*/
|
|
95
|
+
type?: HandleType;
|
|
96
|
+
/**
|
|
97
|
+
* Distinguishes multiple handles on a node. Defaults to the resolved
|
|
98
|
+
* `position`, since each side of a node is unique. Set an explicit `id` when a
|
|
99
|
+
* node has several handles sharing one side.
|
|
100
|
+
*/
|
|
101
|
+
id?: string;
|
|
102
|
+
position?: HandlePosition;
|
|
103
|
+
className?: string;
|
|
104
|
+
style?: CSSProperties;
|
|
105
|
+
/**
|
|
106
|
+
* Accessible name for the handle. Defaults to naming the handle and its node
|
|
107
|
+
* (e.g. `"right handle of node a"`) so a keyboard user tabbing across the
|
|
108
|
+
* graph can tell same-sided handles on different nodes apart.
|
|
109
|
+
*/
|
|
110
|
+
ariaLabel?: string;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* A connection point placed inside a node component. It measures its own
|
|
114
|
+
* position within the node (so edges anchor precisely) and starts a
|
|
115
|
+
* drag-to-connect gesture.
|
|
116
|
+
*/
|
|
117
|
+
declare function Handle({ type, id, position, className, style, ariaLabel, }: HandleProps): React.ReactElement;
|
|
118
|
+
|
|
119
|
+
type MiniMapProps = {
|
|
120
|
+
width?: number;
|
|
121
|
+
height?: number;
|
|
122
|
+
nodeColor?: string;
|
|
123
|
+
selectedColor?: string;
|
|
124
|
+
/** Fill for the area outside the current viewport. */
|
|
125
|
+
maskColor?: string;
|
|
126
|
+
className?: string;
|
|
127
|
+
style?: CSSProperties;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* An overview of the whole graph with a viewport indicator. Redraws on every
|
|
131
|
+
* canvas frame (via the store's frame channel) and recenters on click/drag.
|
|
132
|
+
* Must be a child of `<Rivet>`.
|
|
133
|
+
*/
|
|
134
|
+
declare function MiniMap({ width, height, nodeColor, selectedColor, maskColor, className, style, }: MiniMapProps): React.ReactElement;
|
|
135
|
+
|
|
136
|
+
type NodeResizerProps = {
|
|
137
|
+
minWidth?: number;
|
|
138
|
+
minHeight?: number;
|
|
139
|
+
maxWidth?: number;
|
|
140
|
+
maxHeight?: number;
|
|
141
|
+
/** Lock the width/height ratio while resizing from a corner. */
|
|
142
|
+
keepAspectRatio?: boolean;
|
|
143
|
+
/** Handle color. */
|
|
144
|
+
color?: string;
|
|
145
|
+
/** Called on every resize step (live). */
|
|
146
|
+
onResize?: (size: Size, position: Vec2) => void;
|
|
147
|
+
/** Called once when the resize gesture ends. */
|
|
148
|
+
onResizeEnd?: (size: Size, position: Vec2) => void;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Drop inside a node component to make it resizable. Renders eight drag handles
|
|
152
|
+
* that write the node's explicit `width`/`height` (and move its origin for
|
|
153
|
+
* top/left handles) via {@link RivetStore.resizeNode} — so it works with
|
|
154
|
+
* controlled mode (emits dimension changes) and nested nodes alike.
|
|
155
|
+
*/
|
|
156
|
+
declare function NodeResizer({ minWidth, minHeight, maxWidth, maxHeight, keepAspectRatio, color, onResize, onResizeEnd, }: NodeResizerProps): React.ReactElement;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Edge alignment — the library-level policy for when an edge's endpoints
|
|
160
|
+
* re-side to face the peer node.
|
|
161
|
+
*
|
|
162
|
+
* A handle chosen by the user (grabbed or dropped on) is *pinned*: rivet
|
|
163
|
+
* renders the edge exactly there. The alignment policy decides when geometry
|
|
164
|
+
* may override that pin. Under `"on-move"`, a committed position change of an
|
|
165
|
+
* endpoint node re-sides both ends of its edges toward each other — the user
|
|
166
|
+
* visibly changed the layout, so the pin yields. Nothing else triggers it:
|
|
167
|
+
* data replaces (description edits, history restores) and dimension echoes
|
|
168
|
+
* must never move an edge the user didn't touch or rewrite handles an undo
|
|
169
|
+
* just faithfully restored.
|
|
170
|
+
*
|
|
171
|
+
* The store performs the move and the re-side in one internal batch, so
|
|
172
|
+
* "move + realign = one undo step" holds by construction.
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* When pinned edge endpoints re-side to face the peer node.
|
|
177
|
+
*
|
|
178
|
+
* - `"manual"` — never; a chosen handle is kept until the user reconnects.
|
|
179
|
+
* - `"on-move"` — on a committed position change of an endpoint node.
|
|
180
|
+
* - `"live"` — as `"on-move"`, plus: while an endpoint node is dragging, the
|
|
181
|
+
* edge's pinned ends *render* as if auto — re-siding per frame to face each
|
|
182
|
+
* other, with hysteresis — and the displayed sides commit on drop, inside
|
|
183
|
+
* the move's history step. Nothing is persisted mid-gesture.
|
|
184
|
+
*/
|
|
185
|
+
type EdgeAlignment = "manual" | "on-move" | "live";
|
|
186
|
+
/** The side of `node` that faces `peer`, by dominant center-to-center axis. */
|
|
187
|
+
declare function facingSide(node: Rect, peer: Rect): HandlePosition;
|
|
188
|
+
/**
|
|
189
|
+
* How much the losing axis must dominate before a per-frame resolved side
|
|
190
|
+
* switches axes: with a current horizontal side, the edge flips to top/bottom
|
|
191
|
+
* only once `|dy| > |dx| * ratio` (and symmetrically). `1` disables the band.
|
|
192
|
+
*/
|
|
193
|
+
declare const DEFAULT_ALIGNMENT_HYSTERESIS = 1.2;
|
|
194
|
+
/**
|
|
195
|
+
* Per-frame side resolution with hysteresis. Without a `previous` side this is
|
|
196
|
+
* exactly {@link facingSide}; with one, the side keeps its current axis until
|
|
197
|
+
* the other axis dominates by `hysteresis`, so near-diagonal positions don't
|
|
198
|
+
* flicker between sides frame to frame. Within the kept axis the sign always
|
|
199
|
+
* tracks (a left↔right swap at a mostly-horizontal layout is a real crossing,
|
|
200
|
+
* not jitter — jitter near the diagonal is an axis change, which the band
|
|
201
|
+
* absorbs).
|
|
202
|
+
*/
|
|
203
|
+
declare function resolveFacingSide(node: Rect, peer: Rect, previous?: HandlePosition, hysteresis?: number): HandlePosition;
|
|
204
|
+
|
|
205
|
+
/** Resolved graph context for a pane right-click, passed to `onPaneContextMenu`. */
|
|
206
|
+
type PaneContextMenuContext = {
|
|
207
|
+
/** The click position in world coordinates (already unprojected). */
|
|
208
|
+
world: Vec2;
|
|
209
|
+
/** The swimlane lane whose body sits under the cursor, or `null`. */
|
|
210
|
+
lane: ResolvedLane | null;
|
|
211
|
+
};
|
|
212
|
+
type RivetProps = {
|
|
213
|
+
/**
|
|
214
|
+
* Nodes to seed the graph with (uncontrolled). Read once on mount to initialize
|
|
215
|
+
* the internal store — later changes to this array are ignored. Use {@link nodes}
|
|
216
|
+
* + {@link onNodesChange} for controlled mode instead. Defaults to `[]`.
|
|
217
|
+
*/
|
|
218
|
+
defaultNodes?: RivetNode[];
|
|
219
|
+
/**
|
|
220
|
+
* Edges to seed the graph with (uncontrolled). See {@link defaultNodes}. An edge
|
|
221
|
+
* whose `source` or `target` node is absent is skipped by the renderer. Defaults to `[]`.
|
|
222
|
+
*/
|
|
223
|
+
defaultEdges?: RivetEdge[];
|
|
224
|
+
/**
|
|
225
|
+
* Controlled nodes. When provided, the graph mirrors this array — hold the nodes
|
|
226
|
+
* in your own state and feed back the batches from {@link onNodesChange} (apply
|
|
227
|
+
* them with `applyNodeChanges`). Node drags are suppressed from reconciling
|
|
228
|
+
* mid-drag so the graph stays smooth. Takes precedence over {@link defaultNodes}.
|
|
229
|
+
*/
|
|
230
|
+
nodes?: RivetNode[];
|
|
231
|
+
/** Controlled edges. See {@link nodes}. Takes precedence over {@link defaultEdges}. */
|
|
232
|
+
edges?: RivetEdge[];
|
|
233
|
+
/** Change batches the graph wants applied to your nodes (controlled mode). */
|
|
234
|
+
onNodesChange?: (changes: NodeChange[]) => void;
|
|
235
|
+
/** Change batches the graph wants applied to your edges (controlled mode). */
|
|
236
|
+
onEdgesChange?: (changes: EdgeChange[]) => void;
|
|
237
|
+
/**
|
|
238
|
+
* Initial pan/zoom. `x`/`y` are the screen-space offset in pixels and `zoom`
|
|
239
|
+
* is the scale factor. Defaults to `{ x: 0, y: 0, zoom: 1 }` (origin, 1:1).
|
|
240
|
+
*/
|
|
241
|
+
defaultViewport?: Viewport;
|
|
242
|
+
/**
|
|
243
|
+
* Maps a node's `type` to the React component that renders it. A node whose
|
|
244
|
+
* `type` has no entry here (or no `type` at all) falls back to
|
|
245
|
+
* {@link DefaultNode}. Defaults to `{}`.
|
|
246
|
+
*/
|
|
247
|
+
nodeTypes?: NodeTypes;
|
|
248
|
+
/**
|
|
249
|
+
* Registry of custom edge shapes, keyed by `edge.type`. Each is a pure geometry
|
|
250
|
+
* function (see {@link EdgePathFn}) so edges stay canvas/GPU-renderable. Merged
|
|
251
|
+
* over the built-ins `bezier` (default), `smoothstep`, `step`, and `straight`.
|
|
252
|
+
*/
|
|
253
|
+
edgeTypes?: EdgeTypes;
|
|
254
|
+
/** Defaults merged into every edge that doesn't set the field (type, style, markers…). */
|
|
255
|
+
defaultEdgeOptions?: DefaultEdgeOptions;
|
|
256
|
+
/** Accessible name for the graph surface (`aria-label` on the pane). Defaults to "Node graph". */
|
|
257
|
+
ariaLabel?: string;
|
|
258
|
+
/**
|
|
259
|
+
* Backend factory for the edge layers — swap Canvas2D for another
|
|
260
|
+
* {@link EdgeRenderer}. Defaults to {@link canvas2DEdgeRenderer}. Pass a stable/memoized
|
|
261
|
+
* reference; a new identity re-creates the renderers.
|
|
262
|
+
*/
|
|
263
|
+
renderer?: EdgeRendererFactory;
|
|
264
|
+
/**
|
|
265
|
+
* Lower bound on `viewport.zoom`. All zooming (wheel, controls, `fitView`) is
|
|
266
|
+
* clamped to this. Defaults to `0.2` (zoomed out to 20%).
|
|
267
|
+
*/
|
|
268
|
+
minZoom?: number;
|
|
269
|
+
/**
|
|
270
|
+
* Upper bound on `viewport.zoom`. All zooming is clamped to this. Defaults to
|
|
271
|
+
* `2.5` (zoomed in to 250%).
|
|
272
|
+
*/
|
|
273
|
+
maxZoom?: number;
|
|
274
|
+
/**
|
|
275
|
+
* Spacing in world units between background grid dots. The grid scales with
|
|
276
|
+
* zoom, so this is measured at `zoom === 1`. Defaults to `24`.
|
|
277
|
+
*/
|
|
278
|
+
gridGap?: number;
|
|
279
|
+
/**
|
|
280
|
+
* Snap dragged nodes to a `[x, y]` world-unit grid. A `0` axis is left free.
|
|
281
|
+
* Omit (default) for free positioning. Independent of {@link gridGap} (the
|
|
282
|
+
* visual dot grid) — pass the same value to snap to the dots you see.
|
|
283
|
+
*/
|
|
284
|
+
snapGrid?: [number, number];
|
|
285
|
+
/**
|
|
286
|
+
* While dragging a single node, show alignment guides and snap its edges/center
|
|
287
|
+
* to nearby nodes' edges/centers. Defaults to `false`.
|
|
288
|
+
*/
|
|
289
|
+
alignmentGuides?: boolean;
|
|
290
|
+
/**
|
|
291
|
+
* Placement policy for anchor chrome — the grab dots and stray perimeter
|
|
292
|
+
* handles rivet renders for registered anchors (see {@link Anchor}). Omitted
|
|
293
|
+
* fields fall back to the defaults.
|
|
294
|
+
*/
|
|
295
|
+
anchorOptions?: AnchorOptions;
|
|
296
|
+
/**
|
|
297
|
+
* Which mouse buttons pan when dragging the pane: `true` = left only, `false` =
|
|
298
|
+
* none, or a list of `MouseEvent.button` codes (`0` left, `1` middle, `2` right).
|
|
299
|
+
* e.g. `[1, 2]` pans with middle/right and frees left for selection. Defaults to
|
|
300
|
+
* `true`. Pass a stable reference; a new array identity re-binds the listeners.
|
|
301
|
+
*/
|
|
302
|
+
panOnDrag?: boolean | number[];
|
|
303
|
+
/**
|
|
304
|
+
* Draw a selection marquee on a plain left-drag instead of panning. Pair with
|
|
305
|
+
* `panOnDrag={[1, 2]}` so left selects and middle/right pan. A marquee that
|
|
306
|
+
* ends over nodes leaves a persistent selection box around them — drag it to
|
|
307
|
+
* move the whole selection; a click elsewhere or Escape dismisses it.
|
|
308
|
+
* Defaults to `false`.
|
|
309
|
+
*/
|
|
310
|
+
selectionOnDrag?: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Key(s) that force a marquee on a left-drag when held (e.g. `"Shift"`, `"Meta"`,
|
|
313
|
+
* or `["Shift", "Meta"]`). `null` disables. Defaults to `"Shift"`.
|
|
314
|
+
*/
|
|
315
|
+
selectionKeyCode?: string | string[] | null;
|
|
316
|
+
/**
|
|
317
|
+
* Key(s) that make a click or marquee **add to** the selection instead of
|
|
318
|
+
* replacing it. Defaults to `["Meta", "Control", "Shift"]`. Use modifier keys
|
|
319
|
+
* (`Shift`/`Meta`/`Control`/`Alt`) — other keys only resolve during a pane drag.
|
|
320
|
+
*/
|
|
321
|
+
multiSelectionKeyCode?: string | string[];
|
|
322
|
+
/**
|
|
323
|
+
* Pan the viewport on wheel / two-finger trackpad scroll instead of zooming.
|
|
324
|
+
* A pinch gesture (reported by the browser as ctrl+wheel) still zooms. When
|
|
325
|
+
* `false` (default), scrolling zooms toward the cursor.
|
|
326
|
+
*/
|
|
327
|
+
scrollToPan?: boolean;
|
|
328
|
+
/**
|
|
329
|
+
* Wheel/pinch zoom sensitivity — larger zooms faster per scroll delta.
|
|
330
|
+
* Defaults to `0.0015`. Try `~0.003` for faster trackpad pinch zoom.
|
|
331
|
+
*/
|
|
332
|
+
zoomSpeed?: number;
|
|
333
|
+
/**
|
|
334
|
+
* Swimlanes drawn behind the graph — a decorative background of labeled lane
|
|
335
|
+
* groups (like planout's swimlanes). Not nodes or edges; just layout regions.
|
|
336
|
+
* Omit for no swimlanes.
|
|
337
|
+
*/
|
|
338
|
+
swimlane?: SwimlaneGroup[];
|
|
339
|
+
/**
|
|
340
|
+
* Bind node dragging to the swimlanes: on drop each node snaps fully inside
|
|
341
|
+
* one lane (honoring {@link swimlaneMargin}) and is reassigned to the lane it
|
|
342
|
+
* lands in via {@link RivetNode.laneId}. Defaults to `true` when
|
|
343
|
+
* {@link swimlane} is provided, `false` otherwise. Ignored with no swimlanes.
|
|
344
|
+
*/
|
|
345
|
+
clampToSwimlane?: boolean;
|
|
346
|
+
/**
|
|
347
|
+
* Inner clearance kept between a clamped node and its lane's edges. A number
|
|
348
|
+
* applies to all sides; per-side values override it. Defaults to `16`.
|
|
349
|
+
*/
|
|
350
|
+
swimlaneMargin?: number | SwimlaneMargin;
|
|
351
|
+
/** Screen height of the sticky group header band, in px. Defaults to `32`. */
|
|
352
|
+
swimlaneHeaderHeight?: number;
|
|
353
|
+
/**
|
|
354
|
+
* Show a resize handle on each lane's bottom edge to change its height.
|
|
355
|
+
* Defaults to `true` when {@link swimlane} is provided.
|
|
356
|
+
*/
|
|
357
|
+
swimlaneResizable?: boolean;
|
|
358
|
+
/**
|
|
359
|
+
* Fraction of the last lane's height that must stay visible when scrolled to
|
|
360
|
+
* the bottom — the down-scroll stop. `0.5` (default) keeps half of it in view.
|
|
361
|
+
* Only applies when {@link clampToSwimlane} is on.
|
|
362
|
+
*/
|
|
363
|
+
swimlaneBottomReveal?: number;
|
|
364
|
+
/** Render custom content for a group's sticky header (replaces the default). */
|
|
365
|
+
renderSwimlaneHeader?: (props: SwimlaneHeaderProps) => ReactNode;
|
|
366
|
+
/** Render custom content for a lane's sticky label (replaces the default). */
|
|
367
|
+
renderSwimlaneLabel?: (props: SwimlaneLabelProps) => ReactNode;
|
|
368
|
+
/**
|
|
369
|
+
* Called when a lane's height changes — from a resize drag or from auto-fit
|
|
370
|
+
* growing it to contain a node that grew. The graph owns lane heights, so this
|
|
371
|
+
* is a notification (persist it if you like), not a request to update state.
|
|
372
|
+
*/
|
|
373
|
+
onSwimlaneSizeChange?: (change: SwimlaneSizeChange) => void;
|
|
374
|
+
/**
|
|
375
|
+
* Right-click on empty canvas (not over a node or swimlane chrome). The second
|
|
376
|
+
* argument carries the resolved graph context — the world position and the lane
|
|
377
|
+
* under the cursor — so you don't have to re-derive them.
|
|
378
|
+
*/
|
|
379
|
+
onPaneContextMenu?: (event: MouseEvent, context: PaneContextMenuContext) => void;
|
|
380
|
+
/** Right-click on a lane's sticky label. */
|
|
381
|
+
onSwimlaneHeaderContextMenu?: (laneId: string, event: MouseEvent) => void;
|
|
382
|
+
/** Right-click on a group's sticky header. */
|
|
383
|
+
onSwimlaneGroupHeaderContextMenu?: (groupId: string, event: MouseEvent) => void;
|
|
384
|
+
/** Called when a dragged node is reassigned to a different lane. */
|
|
385
|
+
onLaneChange?: (change: LaneChange) => void;
|
|
386
|
+
/** Veto a proposed connection; return false to reject it. Applies to reconnection too. */
|
|
387
|
+
isValidConnection?: (connection: Connection) => boolean;
|
|
388
|
+
/**
|
|
389
|
+
* Rewrite a validated connection before it commits — normalize handle ids
|
|
390
|
+
* (e.g. redirect an in-content grab handle to its canonical perimeter
|
|
391
|
+
* handle), or force direction conventions. Returning `null` cancels the
|
|
392
|
+
* drop. Applies to new connections and reconnections; `isValidConnection`
|
|
393
|
+
* sees the raw connection, `onConnect`/`onReconnect` see the mapped one.
|
|
394
|
+
*/
|
|
395
|
+
mapConnection?: (connection: Connection) => Connection | null;
|
|
396
|
+
/** Called after a valid connection is made (the edge is already added). */
|
|
397
|
+
onConnect?: (connection: Connection) => void;
|
|
398
|
+
/**
|
|
399
|
+
* Allow reconnecting edges by dragging an endpoint onto a new handle. Per-edge
|
|
400
|
+
* `reconnectable` overrides this. Defaults to `false`.
|
|
401
|
+
*/
|
|
402
|
+
edgesReconnectable?: boolean;
|
|
403
|
+
/**
|
|
404
|
+
* When edge endpoints re-side to face the peer node. `"manual"` (default)
|
|
405
|
+
* never rewrites a chosen handle; `"on-move"` re-sides both ends of a moved
|
|
406
|
+
* node's edges when the move commits — in the same batch as the move, so one
|
|
407
|
+
* undo restores position and handles together. `"live"` additionally renders
|
|
408
|
+
* a dragging node's edges as if their ends were auto — re-siding per frame
|
|
409
|
+
* to face each other, with hysteresis so near-diagonal positions don't
|
|
410
|
+
* flicker — and commits the displayed sides on drop, inside the move's
|
|
411
|
+
* history step; nothing is persisted mid-gesture. Only committed position
|
|
412
|
+
* changes trigger a rewrite: data replaces and dimension changes never
|
|
413
|
+
* re-side, and a freshly created or reconnected edge keeps exactly the
|
|
414
|
+
* handles the user grabbed or dropped on. Anchor and bare-side ends rewrite
|
|
415
|
+
* their side directly; plain handles re-side to a registered handle of a
|
|
416
|
+
* compatible type on the facing side, or stay pinned when the node has none
|
|
417
|
+
* there. Independent of the policy, an end with *no* side — a missing
|
|
418
|
+
* handle, or an `anchorAutoHandleId` anchor end — always floats: the
|
|
419
|
+
* renderer resolves its facing side per frame and never writes it back.
|
|
420
|
+
*/
|
|
421
|
+
edgeAlignment?: EdgeAlignment;
|
|
422
|
+
/** Called when an endpoint drag re-points an edge (the edge is already updated). */
|
|
423
|
+
onReconnect?: (edge: RivetEdge, connection: Connection) => void;
|
|
424
|
+
/** Called when an endpoint reconnection drag starts. */
|
|
425
|
+
onReconnectStart?: (edge: RivetEdge) => void;
|
|
426
|
+
/** Called when an endpoint reconnection drag ends (committed or cancelled). */
|
|
427
|
+
onReconnectEnd?: (edge: RivetEdge) => void;
|
|
428
|
+
/** Called whenever the selected nodes and/or edges change. */
|
|
429
|
+
onSelectionChange?: (selection: RivetSelection) => void;
|
|
430
|
+
/**
|
|
431
|
+
* Called when keyboard focus moves to a node (or leaves the graph — `null`).
|
|
432
|
+
* The same state is available inside `<Rivet>` via {@link useRivetFocusedNode}.
|
|
433
|
+
* Rivet draws no focus ring; use this (or the wrapper's `:focus-visible`) to
|
|
434
|
+
* render your own indicator.
|
|
435
|
+
*/
|
|
436
|
+
onFocusChange?: (id: NodeId | null) => void;
|
|
437
|
+
className?: string;
|
|
438
|
+
style?: CSSProperties;
|
|
439
|
+
children?: ReactNode;
|
|
440
|
+
};
|
|
441
|
+
/**
|
|
442
|
+
* The graph surface. Stacks a background grid canvas, an edge canvas, and a DOM
|
|
443
|
+
* node layer — all driven by one shared viewport (see {@link useRivetRuntime}).
|
|
444
|
+
*/
|
|
445
|
+
declare function Rivet({ defaultNodes, defaultEdges, nodes: controlledNodes, edges: controlledEdges, onNodesChange, onEdgesChange, defaultViewport, nodeTypes, edgeTypes, defaultEdgeOptions, ariaLabel, renderer, minZoom, maxZoom, gridGap, snapGrid, alignmentGuides, anchorOptions, panOnDrag, selectionOnDrag, selectionKeyCode, multiSelectionKeyCode, scrollToPan, zoomSpeed, swimlane, clampToSwimlane, swimlaneMargin, swimlaneHeaderHeight, swimlaneResizable, swimlaneBottomReveal, renderSwimlaneHeader, renderSwimlaneLabel, onSwimlaneSizeChange, onPaneContextMenu, onSwimlaneHeaderContextMenu, onSwimlaneGroupHeaderContextMenu, onLaneChange, isValidConnection, mapConnection, onConnect, edgesReconnectable, edgeAlignment, onReconnect, onReconnectStart, onReconnectEnd, onSelectionChange, onFocusChange, className, style, children, }: RivetProps): React.ReactElement;
|
|
446
|
+
|
|
447
|
+
/** Composite key for the handle/anchor registries. */
|
|
448
|
+
declare function handleKey(nodeId: NodeId, handleId: string): string;
|
|
449
|
+
|
|
450
|
+
type RivetStoreInit = {
|
|
451
|
+
nodes: RivetNode[];
|
|
452
|
+
edges: RivetEdge[];
|
|
453
|
+
viewport: Viewport;
|
|
454
|
+
};
|
|
455
|
+
type ViewportClamp = {
|
|
456
|
+
minX: number;
|
|
457
|
+
minY: number;
|
|
458
|
+
maxY?: number;
|
|
459
|
+
};
|
|
460
|
+
type ChangeHandlers = {
|
|
461
|
+
nodes?: (changes: NodeChange[]) => void;
|
|
462
|
+
edges?: (changes: EdgeChange[]) => void;
|
|
463
|
+
};
|
|
464
|
+
/**
|
|
465
|
+
* The single source of truth for a graph instance — the public contract. It's an
|
|
466
|
+
* interface so consumers depend on the shape, not the implementation ({@link
|
|
467
|
+
* RivetGraphStore}); pure graph algorithms live in `graph.ts`.
|
|
468
|
+
*
|
|
469
|
+
* Subscriptions are deliberately granular so touching one node never re-renders
|
|
470
|
+
* the others:
|
|
471
|
+
* - **per-node** channel — a `NodeWrapper` subscribes to only its own node, so
|
|
472
|
+
* selecting/moving/measuring node A re-renders A alone.
|
|
473
|
+
* - the `NodeLayer`'s list is driven by the culled `visibleIds` prop, so it
|
|
474
|
+
* re-renders only when the visible set changes, never on node data.
|
|
475
|
+
* - **viewport** and **frame** channels drive the canvas (and the label
|
|
476
|
+
* layer's imperative positioning) without touching React at all.
|
|
477
|
+
*/
|
|
478
|
+
type RivetStore = {
|
|
479
|
+
readonly nodes: Map<NodeId, RivetNode>;
|
|
480
|
+
readonly edges: Map<EdgeId, RivetEdge>;
|
|
481
|
+
readonly handles: Map<string, HandleRecord>;
|
|
482
|
+
getNodeVersion: (id: NodeId) => number;
|
|
483
|
+
subscribeNode: (id: NodeId, listener: () => void) => () => void;
|
|
484
|
+
registerNodeElement: (id: NodeId, el: HTMLElement) => void;
|
|
485
|
+
unregisterNodeElement: (id: NodeId, el: HTMLElement) => void;
|
|
486
|
+
getNodeElement: (id: NodeId) => HTMLElement | undefined;
|
|
487
|
+
/**
|
|
488
|
+
* Register the controlled-mode change sinks. When set, node/edge mutations emit
|
|
489
|
+
* {@link NodeChange}/{@link EdgeChange} batches so a consumer can own the state.
|
|
490
|
+
* Emission is suppressed while {@link reconcile} is applying incoming props, so
|
|
491
|
+
* feeding changes back in never loops.
|
|
492
|
+
*/
|
|
493
|
+
setChangeHandlers: (handlers: ChangeHandlers) => void;
|
|
494
|
+
/**
|
|
495
|
+
* Sync the store to controlled `nodes`/`edges` props. Adds/removes/updates to
|
|
496
|
+
* match, without re-emitting changes. No-op writes are skipped so unrelated
|
|
497
|
+
* nodes don't re-render.
|
|
498
|
+
*/
|
|
499
|
+
reconcile: (nodes: RivetNode[], edges: RivetEdge[]) => void;
|
|
500
|
+
/** Add a node (imperative CRUD). Ignored if the id already exists. */
|
|
501
|
+
addNode: (node: RivetNode) => void;
|
|
502
|
+
/** Replace a node wholesale by id (imperative CRUD). Ignored if absent. */
|
|
503
|
+
replaceNode: (id: NodeId, node: RivetNode) => void;
|
|
504
|
+
getViewport: () => Viewport;
|
|
505
|
+
setViewport: (viewport: Viewport) => void;
|
|
506
|
+
subscribeViewport: (listener: (viewport: Viewport) => void) => () => void;
|
|
507
|
+
/**
|
|
508
|
+
* Bound panning against the swimlane area. `minX`/`minY` pin the top-left: you
|
|
509
|
+
* can't scroll left of `minX` or up above `minY`. `maxY` (optional) pins the
|
|
510
|
+
* bottom: you can't scroll down far enough to push the world-y `maxY` above the
|
|
511
|
+
* pane top. Pass `null` to remove the bound. Applied to every viewport change,
|
|
512
|
+
* including zoom and programmatic sets.
|
|
513
|
+
*/
|
|
514
|
+
setViewportClamp: (clamp: ViewportClamp | null) => void;
|
|
515
|
+
subscribeFrame: (listener: () => void) => () => void;
|
|
516
|
+
notifyFrame: () => void;
|
|
517
|
+
/** Move a node. `commit` re-renders just that node; skip it during drag. */
|
|
518
|
+
moveNode: (id: NodeId, position: Vec2, commit: boolean) => void;
|
|
519
|
+
setNodeSize: (id: NodeId, size: Size) => void;
|
|
520
|
+
/**
|
|
521
|
+
* Set a node's explicit `width`/`height` (from {@link NodeResizer}), optionally
|
|
522
|
+
* moving its origin (for top/left resize handles). Re-renders the node every
|
|
523
|
+
* frame so its box and geometry props update live; `commit` only marks the
|
|
524
|
+
* emitted change final (`resizing`/`dragging` false → recordable to history).
|
|
525
|
+
*/
|
|
526
|
+
resizeNode: (id: NodeId, size: Size, position?: Vec2, commit?: boolean) => void;
|
|
527
|
+
/** Absolute world position of a node, resolving its {@link RivetNode.parentId} chain. */
|
|
528
|
+
getNodeWorldPosition: (id: NodeId) => Vec2;
|
|
529
|
+
/**
|
|
530
|
+
* World positions for every node (parent chains applied), cached and rebuilt only
|
|
531
|
+
* when node geometry changes — so pan/zoom frames, where nothing moved, reuse it.
|
|
532
|
+
*/
|
|
533
|
+
getWorldPositions: () => ReadonlyMap<NodeId, Vec2>;
|
|
534
|
+
/** A node's world-space box (`getNodeWorldPosition` + measured/default size). */
|
|
535
|
+
getNodeRect: (id: NodeId) => Rect;
|
|
536
|
+
/** How many ancestors a node has (0 for a top-level node). Drives z-stacking. */
|
|
537
|
+
getNodeDepth: (id: NodeId) => number;
|
|
538
|
+
/** Ids of every descendant of a node (children, grandchildren, …). */
|
|
539
|
+
getDescendantIds: (id: NodeId) => NodeId[];
|
|
540
|
+
/**
|
|
541
|
+
* Of the given ids, the ones whose ancestor isn't also in the set — the nodes a
|
|
542
|
+
* group move should actually translate (a selected child of a selected parent
|
|
543
|
+
* rides along with the parent, so moving it too would double its travel).
|
|
544
|
+
*/
|
|
545
|
+
getMovers: (ids: NodeId[]) => NodeId[];
|
|
546
|
+
/**
|
|
547
|
+
* Reassign a node's swimlane. Returns the previous lane id if it changed (so
|
|
548
|
+
* the caller can fire a lane-change callback), or `false` when unchanged.
|
|
549
|
+
*/
|
|
550
|
+
setNodeLane: (id: NodeId, laneId: string | null) => string | null | false;
|
|
551
|
+
/**
|
|
552
|
+
* Set the edge-alignment policy (the `edgeAlignment` prop). Under
|
|
553
|
+
* `"on-move"`, a committed position change re-sides the moved node's edges
|
|
554
|
+
* to face their peers, inside the same emission batch as the move.
|
|
555
|
+
*/
|
|
556
|
+
setEdgeAlignment: (mode: EdgeAlignment) => void;
|
|
557
|
+
/** The current edge-alignment policy (the runtime reads it per frame). */
|
|
558
|
+
getEdgeAlignment: () => EdgeAlignment;
|
|
559
|
+
/**
|
|
560
|
+
* Hysteresis memory for per-frame side resolution, keyed by
|
|
561
|
+
* `displayedSideKey(edgeId, end)`. The render loop hands this map to the
|
|
562
|
+
* renderer, which reads each auto-resolved end's last displayed side and
|
|
563
|
+
* writes the new one back; a `"live"` alignment commit re-sides pinned ends
|
|
564
|
+
* to exactly what was displayed, then drops those entries. Never persisted.
|
|
565
|
+
*/
|
|
566
|
+
getDisplayedSides: () => Map<string, HandlePosition>;
|
|
567
|
+
/**
|
|
568
|
+
* Nodes currently mid-drag — populated by uncommitted {@link moveNode}
|
|
569
|
+
* frames, emptied on commit (and cleared as a backstop when
|
|
570
|
+
* {@link setNodeDragging} ends the gesture). Under `edgeAlignment: "live"`,
|
|
571
|
+
* edges touching these nodes render both ends as auto.
|
|
572
|
+
*/
|
|
573
|
+
getDraggingNodeIds: () => ReadonlySet<NodeId>;
|
|
574
|
+
/** True while a node drag is in progress (pauses swimlane auto-fit). */
|
|
575
|
+
isNodeDragging: () => boolean;
|
|
576
|
+
setNodeDragging: (dragging: boolean) => void;
|
|
577
|
+
/**
|
|
578
|
+
* True while a resize gesture is in progress — set by {@link resizeNode}'s live
|
|
579
|
+
* frames and cleared by its commit. Guards controlled-mode reconciliation the
|
|
580
|
+
* same way {@link isNodeDragging} does: mid-gesture the consumer's props lag
|
|
581
|
+
* the store (live frames may be dropped, and measurement echoes carry `size`
|
|
582
|
+
* but not the explicit `width`/`height`), so reconciling them would stomp the
|
|
583
|
+
* live box back to its pre-gesture value every frame.
|
|
584
|
+
*/
|
|
585
|
+
isNodeResizing: () => boolean;
|
|
586
|
+
/**
|
|
587
|
+
* Select node(s). `additive` toggles `id` in the current selection (Shift/Cmd
|
|
588
|
+
* click); otherwise the selection is replaced. Passing `null` clears it.
|
|
589
|
+
*/
|
|
590
|
+
selectNode: (id: NodeId | null, additive?: boolean) => void;
|
|
591
|
+
/** Replace (or, if `additive`, extend) the node selection with `ids`. */
|
|
592
|
+
selectNodes: (ids: NodeId[], additive?: boolean) => void;
|
|
593
|
+
/** The currently selected node ids. */
|
|
594
|
+
getSelectedNodes: () => NodeId[];
|
|
595
|
+
/** True if the node is part of the current selection. */
|
|
596
|
+
isNodeSelected: (id: NodeId) => boolean;
|
|
597
|
+
/** The current selection (nodes + edges) as full records. */
|
|
598
|
+
getSelection: () => RivetSelection;
|
|
599
|
+
/** Subscribe to selection changes (nodes and/or edges). */
|
|
600
|
+
subscribeSelection: (listener: (selection: RivetSelection) => void) => () => void;
|
|
601
|
+
/**
|
|
602
|
+
* The persistent selection box left behind by a marquee — a draggable rect
|
|
603
|
+
* over the selected nodes' bounding box. Activated by the marquee's end;
|
|
604
|
+
* deactivated by any other selection change (a node/edge/pane click, a
|
|
605
|
+
* programmatic select, Escape, or deleting the selection).
|
|
606
|
+
*/
|
|
607
|
+
setSelectionBoxActive: (active: boolean) => void;
|
|
608
|
+
isSelectionBoxActive: () => boolean;
|
|
609
|
+
/**
|
|
610
|
+
* Version channel for the selection box: bumped when the flag flips and, while
|
|
611
|
+
* active, when the boxed selection's membership or geometry changes — so the
|
|
612
|
+
* box component can re-render its bounding rect from a single subscription.
|
|
613
|
+
*/
|
|
614
|
+
getSelectionBoxVersion: () => number;
|
|
615
|
+
subscribeSelectionBox: (listener: () => void) => () => void;
|
|
616
|
+
/** Set (or clear, with `null`) the hovered node. */
|
|
617
|
+
hoverNode: (id: NodeId | null) => void;
|
|
618
|
+
/**
|
|
619
|
+
* The node that currently holds keyboard focus, or `null`. View state, like
|
|
620
|
+
* hover — never recorded to history, never emitted as a change, and stripped
|
|
621
|
+
* from snapshots. Tracked from the node elements' focus/blur by the node
|
|
622
|
+
* layer; set it programmatically to move real DOM focus to a node (the
|
|
623
|
+
* runtime follows this channel, centering the viewport first when the node
|
|
624
|
+
* is culled out of the DOM).
|
|
625
|
+
*/
|
|
626
|
+
getFocusedNode: () => NodeId | null;
|
|
627
|
+
/** Focus a node by id, or clear with `null`. Unknown ids are ignored. */
|
|
628
|
+
setFocusedNode: (id: NodeId | null) => void;
|
|
629
|
+
/** Subscribe to focused-node changes. */
|
|
630
|
+
subscribeFocus: (listener: (id: NodeId | null) => void) => () => void;
|
|
631
|
+
selectEdge: (id: EdgeId | null) => void;
|
|
632
|
+
/** The selected edge's id, or null. */
|
|
633
|
+
getSelectedEdge: () => EdgeId | null;
|
|
634
|
+
/**
|
|
635
|
+
* Runtime binding for the reconnect gateway. `<Handle>` consults it on
|
|
636
|
+
* pointer-down so a press that lands on a handle coinciding with a
|
|
637
|
+
* reconnectable edge's endpoint moves that edge instead of starting a new
|
|
638
|
+
* connection. Bound by the runtime (like {@link bindRenderRequester}).
|
|
639
|
+
*/
|
|
640
|
+
bindReconnectDelegate: (delegate: ReconnectDelegate | null) => void;
|
|
641
|
+
getReconnectDelegate: () => ReconnectDelegate | null;
|
|
642
|
+
addEdge: (edge: RivetEdge) => void;
|
|
643
|
+
/** Replace an edge wholesale by id (imperative CRUD). Ignored if absent. */
|
|
644
|
+
replaceEdge: (id: EdgeId, edge: RivetEdge) => void;
|
|
645
|
+
/** Re-point an edge's source/target (from an endpoint reconnection drag). */
|
|
646
|
+
reconnectEdge: (id: EdgeId, connection: Connection) => void;
|
|
647
|
+
removeEdge: (id: EdgeId) => void;
|
|
648
|
+
removeNode: (id: NodeId) => void;
|
|
649
|
+
/** Delete the selected node (and its edges) and/or edge. Returns true if any. */
|
|
650
|
+
deleteSelection: () => boolean;
|
|
651
|
+
/** Revert the last recordable change. Returns false when there's nothing to undo. */
|
|
652
|
+
undo: () => boolean;
|
|
653
|
+
/** Re-apply the last undone change. Returns false when there's nothing to redo. */
|
|
654
|
+
redo: () => boolean;
|
|
655
|
+
canUndo: () => boolean;
|
|
656
|
+
canRedo: () => boolean;
|
|
657
|
+
/** Drop all history and reset the baseline to the current graph. */
|
|
658
|
+
clearHistory: () => void;
|
|
659
|
+
/** Subscribe to history changes (drives `canUndo`/`canRedo` reactivity). */
|
|
660
|
+
subscribeHistory: (listener: () => void) => () => void;
|
|
661
|
+
getEdgeLabelAnchors: () => Map<EdgeId, Vec2>;
|
|
662
|
+
setEdgeLabelAnchors: (anchors: Map<EdgeId, Vec2>) => void;
|
|
663
|
+
/** Alignment/snap guides to draw for the current drag (world space). Empty when idle. */
|
|
664
|
+
getAlignmentGuides: () => AlignmentGuide[];
|
|
665
|
+
setAlignmentGuides: (guides: AlignmentGuide[]) => void;
|
|
666
|
+
registerHandle: (record: HandleRecord) => void;
|
|
667
|
+
unregisterHandle: (nodeId: NodeId, handleId: string) => void;
|
|
668
|
+
readonly anchors: Map<string, AnchorRecord>;
|
|
669
|
+
/**
|
|
670
|
+
* Register (or re-bind) an anchor. Idempotent on the `(nodeId, anchorId)`
|
|
671
|
+
* key: calling again with a new element re-attaches it, keeping any
|
|
672
|
+
* last-known geometry until the next successful measurement.
|
|
673
|
+
*/
|
|
674
|
+
registerAnchor: (nodeId: NodeId, anchorId: string, element: Element, options?: AnchorRegistrationOptions) => void;
|
|
675
|
+
/**
|
|
676
|
+
* Mark an anchor's element gone without removing the anchor — the stale
|
|
677
|
+
* retention signal. Geometry (and the stray handles rendered from it) is
|
|
678
|
+
* kept so edges stay put while the display is unmounted.
|
|
679
|
+
*/
|
|
680
|
+
detachAnchor: (nodeId: NodeId, anchorId: string) => void;
|
|
681
|
+
/** Explicitly remove an anchor and the chrome rendered for it. */
|
|
682
|
+
unregisterAnchor: (nodeId: NodeId, anchorId: string) => void;
|
|
683
|
+
/**
|
|
684
|
+
* Re-measure a node's anchors. Called automatically when the node's box
|
|
685
|
+
* resizes; call it directly after content reflows *without* a resize (an
|
|
686
|
+
* editor transaction, a font load) — rivet can't observe those.
|
|
687
|
+
*/
|
|
688
|
+
remeasureAnchors: (nodeId: NodeId) => void;
|
|
689
|
+
/** The node's anchors, in registration order. */
|
|
690
|
+
getNodeAnchors: (nodeId: NodeId) => AnchorRecord[];
|
|
691
|
+
getNodeAnchorsVersion: (nodeId: NodeId) => number;
|
|
692
|
+
subscribeNodeAnchors: (nodeId: NodeId, listener: () => void) => () => void;
|
|
693
|
+
getEdgesVersion: () => number;
|
|
694
|
+
subscribeEdges: (listener: () => void) => () => void;
|
|
695
|
+
getPending: () => PendingConnection | null;
|
|
696
|
+
beginConnection: (pending: PendingConnection) => void;
|
|
697
|
+
updateConnection: (to: Vec2, toPosition?: HandlePosition) => void;
|
|
698
|
+
endConnection: () => void;
|
|
699
|
+
/** Ask the runtime to schedule a canvas frame. */
|
|
700
|
+
requestRender: () => void;
|
|
701
|
+
bindRenderRequester: (fn: () => void) => void;
|
|
702
|
+
};
|
|
703
|
+
/** Create a graph store. The public entry point; the class is an implementation detail. */
|
|
704
|
+
declare function createRivetStore(init: RivetStoreInit): RivetStore;
|
|
705
|
+
|
|
706
|
+
type RivetContextValue = {
|
|
707
|
+
store: RivetStore;
|
|
708
|
+
nodeTypes: NodeTypes;
|
|
709
|
+
paneRef: RefObject<HTMLDivElement | null>;
|
|
710
|
+
/** Imperative viewport controls (zoom, fit-view). */
|
|
711
|
+
controls: RivetControls;
|
|
712
|
+
/** Keys that make a click add to (toggle in) the selection. */
|
|
713
|
+
multiSelectionKeys: string[];
|
|
714
|
+
/**
|
|
715
|
+
* Publish a message to the pane's visually-hidden live region, so screen
|
|
716
|
+
* readers narrate keyboard interactions (grab/move/drop, connect).
|
|
717
|
+
*/
|
|
718
|
+
announce: (message: string) => void;
|
|
719
|
+
/** Id of the pane's hidden keyboard-instructions element (`aria-describedby` target). */
|
|
720
|
+
nodeDescriptionId: string;
|
|
721
|
+
/** Defaults merged into every edge — the label layer reads `labelStyle`. */
|
|
722
|
+
defaultEdgeOptions?: DefaultEdgeOptions;
|
|
723
|
+
/** Grid to snap dragged nodes to (`[x, y]` world units), or null for free movement. */
|
|
724
|
+
snapGrid: [number, number] | null;
|
|
725
|
+
/** Whether a single-node drag shows alignment guides and snaps to neighbors. */
|
|
726
|
+
alignmentGuides: boolean;
|
|
727
|
+
/** Resolved placement policy for anchor chrome (dots + stray handles). */
|
|
728
|
+
anchorOptions: ResolvedAnchorOptions;
|
|
729
|
+
/** Snapshot the nodes and lanes currently on screen. Imperative — never subscribes. */
|
|
730
|
+
getViewportElements: () => ViewportElements;
|
|
731
|
+
/** Resolved swimlane groups (header + lanes, world space). Empty when unused. */
|
|
732
|
+
swimlaneGroups: ResolvedSwimlaneGroup[];
|
|
733
|
+
/** Every group's lanes, flattened — the clamp targets. */
|
|
734
|
+
swimlaneLanes: ResolvedLane[];
|
|
735
|
+
/** Whether node drags are bounded to a lane and reassign lane membership. */
|
|
736
|
+
clampToSwimlane: boolean;
|
|
737
|
+
/** Inner clearance kept between a clamped node and its lane edges. */
|
|
738
|
+
swimlaneMargin: ResolvedMargin;
|
|
739
|
+
/** Screen width of the sticky lane-label strip, in px. */
|
|
740
|
+
swimlaneLabelWidth: number;
|
|
741
|
+
/** Screen height of the sticky group header band, in px. */
|
|
742
|
+
swimlaneHeaderSize: number;
|
|
743
|
+
/** Whether lanes show a bottom resize handle. */
|
|
744
|
+
swimlaneResizable: boolean;
|
|
745
|
+
/**
|
|
746
|
+
* Resize a lane. `commit` fires the consumer's `onSwimlaneSizeChange` with the
|
|
747
|
+
* new height; `reason` tags it (`"resize"` for a drag, `"autofit"` for a
|
|
748
|
+
* fit-to-content snap). Defaults to `"resize"`.
|
|
749
|
+
*/
|
|
750
|
+
resizeSwimlane: (laneId: string, height: number, commit: boolean, reason?: SwimlaneSizeChange["reason"]) => void;
|
|
751
|
+
/** Consumer override for the sticky group header content. */
|
|
752
|
+
renderSwimlaneHeader?: (props: SwimlaneHeaderProps) => ReactNode;
|
|
753
|
+
/** Consumer override for the sticky lane label content. */
|
|
754
|
+
renderSwimlaneLabel?: (props: SwimlaneLabelProps) => ReactNode;
|
|
755
|
+
/** Called when a dragged node crosses into a different lane. */
|
|
756
|
+
onLaneChange?: (change: LaneChange) => void;
|
|
757
|
+
/** Veto a proposed connection; return false to reject. */
|
|
758
|
+
isValidConnection?: (connection: Connection) => boolean;
|
|
759
|
+
/** Rewrite a validated connection before commit; `null` cancels the drop. */
|
|
760
|
+
mapConnection?: (connection: Connection) => Connection | null;
|
|
761
|
+
/** Called after a valid connection is made. */
|
|
762
|
+
onConnect?: (connection: Connection) => void;
|
|
763
|
+
};
|
|
764
|
+
declare function useRivetContext(): RivetContextValue;
|
|
765
|
+
/** Access the imperative viewport controls from inside `<Rivet>`. */
|
|
766
|
+
declare function useRivetControls(): RivetControls;
|
|
767
|
+
/** Subscribe to the live viewport — re-renders on every pan/zoom. */
|
|
768
|
+
declare function useRivetViewport(): Viewport;
|
|
769
|
+
/** Reactive undo/redo state + actions — re-renders when `canUndo`/`canRedo` flip. */
|
|
770
|
+
declare function useRivetHistory(): {
|
|
771
|
+
canUndo: boolean;
|
|
772
|
+
canRedo: boolean;
|
|
773
|
+
undo: () => boolean;
|
|
774
|
+
redo: () => boolean;
|
|
775
|
+
clearHistory: () => void;
|
|
776
|
+
};
|
|
777
|
+
/**
|
|
778
|
+
* The node holding keyboard focus, or `null` — re-renders as focus roves.
|
|
779
|
+
* Rendering a focus indicator is the consumer's job (rivet is headless); this
|
|
780
|
+
* is the state to drive it from, along with the wrapper's native `:focus-visible`.
|
|
781
|
+
*/
|
|
782
|
+
declare function useRivetFocusedNode(): NodeId | null;
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Structured edge ends — the semantic model over the string handle ids that
|
|
786
|
+
* `RivetEdge.sourceHandle`/`targetHandle` persist.
|
|
787
|
+
*
|
|
788
|
+
* An end is `{ nodeId, anchorId?, side? }`:
|
|
789
|
+
* - `anchorId` present — the end binds to a registered {@link Anchor}.
|
|
790
|
+
* - `side` present — the end is *pinned*: the user chose it (grabbed a dot,
|
|
791
|
+
* dropped on a handle) and rivet renders it exactly there until the
|
|
792
|
+
* alignment policy says otherwise.
|
|
793
|
+
* - `side` absent — the end is *auto* (floating): the renderer resolves the
|
|
794
|
+
* facing side per frame from the two node boxes. Nothing is written while a
|
|
795
|
+
* node drags, so live re-anchoring is free and cannot touch history.
|
|
796
|
+
*
|
|
797
|
+
* Strings remain the wire format, so persisted graphs and external schemas
|
|
798
|
+
* keep working; this module is the codec between the two forms:
|
|
799
|
+
*
|
|
800
|
+
* | structured | handle string |
|
|
801
|
+
* |---------------------------------|----------------------|
|
|
802
|
+
* | `{ anchorId, side }` | `inode-<id>-<side>` |
|
|
803
|
+
* | `{ anchorId }` (auto) | `inode-<id>-auto` |
|
|
804
|
+
* | `{ side }` (plain, pinned) | `"<side>"` |
|
|
805
|
+
* | `{}` (plain, auto) | `undefined` |
|
|
806
|
+
*
|
|
807
|
+
* A custom handle id (anything else) stays a plain pinned end whose side lives
|
|
808
|
+
* in the handle registry; `parseEdgeEndpoint` reads it from there when given
|
|
809
|
+
* the registry, and otherwise leaves `side` unset.
|
|
810
|
+
*/
|
|
811
|
+
|
|
812
|
+
/** One end of an edge, structurally. See the module doc for the string mapping. */
|
|
813
|
+
type EdgeEndpoint = {
|
|
814
|
+
nodeId: NodeId;
|
|
815
|
+
/** Anchor this end binds to; absent for a plain node end. */
|
|
816
|
+
anchorId?: string;
|
|
817
|
+
/** Pinned side; absent = auto — the renderer resolves the facing side per frame. */
|
|
818
|
+
side?: HandlePosition;
|
|
819
|
+
};
|
|
820
|
+
/** Parse a bare-side handle id (`"left"`, `"top"`, …) — a side-pinned plain end. */
|
|
821
|
+
declare function parseSideHandleId(handleId: string | null | undefined): HandlePosition | null;
|
|
822
|
+
/**
|
|
823
|
+
* The handle string for a structured end — what `sourceHandle`/`targetHandle`
|
|
824
|
+
* stores. `undefined` (a plain auto end) means "no handle": the renderer
|
|
825
|
+
* resolves the side per frame. A plain pinned end that should attach to a
|
|
826
|
+
* specific registered handle keeps using that handle's own id directly; this
|
|
827
|
+
* codec covers the library-owned grammars.
|
|
828
|
+
*/
|
|
829
|
+
declare function edgeEndpointHandle(end: EdgeEndpoint): string | undefined;
|
|
830
|
+
/**
|
|
831
|
+
* Parse one end of an edge into the structured form. Library grammars (anchor
|
|
832
|
+
* stray/auto ids, bare sides, absent handles) round-trip exactly; a custom
|
|
833
|
+
* handle id resolves its side through `handles` when provided (the store's
|
|
834
|
+
* registry), and otherwise comes back with `side` unset — which callers must
|
|
835
|
+
* not read as auto without that context.
|
|
836
|
+
*/
|
|
837
|
+
declare function parseEdgeEndpoint(nodeId: NodeId, handleId: string | null | undefined, handles?: ReadonlyMap<string, HandleRecord>): EdgeEndpoint;
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Confine a child's parent-relative position so its box stays fully inside the
|
|
841
|
+
* parent (the `extent: "parent"` sub-flow constraint). Pure geometry — the
|
|
842
|
+
* caller supplies both measured sizes.
|
|
843
|
+
*/
|
|
844
|
+
declare function clampChildToParent(position: Vec2, childSize: Size, parentSize: Size): Vec2;
|
|
845
|
+
/** Snap a position to the nearest multiple of `[gx, gy]`. A `0` axis is left free. */
|
|
846
|
+
declare function snapToGrid(position: Vec2, grid: readonly [number, number]): Vec2;
|
|
847
|
+
/** The tight bounding rect over a set of rects, or `null` when empty. */
|
|
848
|
+
declare function boundingRect(rects: readonly Rect[]): Rect | null;
|
|
849
|
+
/**
|
|
850
|
+
* True when nothing the consumer controls has changed between two versions of a
|
|
851
|
+
* node — so reconcile can keep the existing one (preserving store-owned transient
|
|
852
|
+
* state like `hovered`). Compares only fields a controlled consumer owns.
|
|
853
|
+
*/
|
|
854
|
+
/**
|
|
855
|
+
* A serializable snapshot of the graph. Store-owned geometry (`position`, `size`)
|
|
856
|
+
* is cloned so mutating the snapshot can't reach back into the store, and purely
|
|
857
|
+
* transient node flags (`hovered`, `dragging`) are dropped — you never want to
|
|
858
|
+
* persist "was mid-drag". `data` is copied by reference, matching the
|
|
859
|
+
* controlled-mode contract (the consumer owns it).
|
|
860
|
+
*/
|
|
861
|
+
declare function serializeGraph<TNodeData = unknown, TEdgeData = unknown>(nodes: Iterable<RivetNode<TNodeData>>, edges: Iterable<RivetEdge<TEdgeData>>, viewport: Viewport): RivetSnapshot<TNodeData, TEdgeData>;
|
|
862
|
+
|
|
863
|
+
type Updater<T> = T | ((current: T) => T);
|
|
864
|
+
/**
|
|
865
|
+
* Imperative handle to the graph, returned by {@link useRivet}. Parameterize it
|
|
866
|
+
* with your node/edge `data` types — `useRivet<MyNodeData, MyEdgeData>()` — so
|
|
867
|
+
* `getNodes`, `toObject`, etc. hand those types back instead of `unknown`.
|
|
868
|
+
*/
|
|
869
|
+
type RivetInstance<TNodeData = unknown, TEdgeData = unknown> = RivetControls & {
|
|
870
|
+
/** Snapshot the nodes and lanes currently on screen. Reads the viewport once — never subscribes. */
|
|
871
|
+
getViewportElements: () => ViewportElements<TNodeData>;
|
|
872
|
+
/** Serializable snapshot of nodes, edges, and viewport. Safe to `JSON.stringify`. */
|
|
873
|
+
toObject: () => RivetSnapshot<TNodeData, TEdgeData>;
|
|
874
|
+
getNodes: () => RivetNode<TNodeData>[];
|
|
875
|
+
getNode: (id: NodeId) => RivetNode<TNodeData> | undefined;
|
|
876
|
+
setNodes: (nodes: Updater<RivetNode<TNodeData>[]>) => void;
|
|
877
|
+
addNodes: (nodes: RivetNode<TNodeData> | RivetNode<TNodeData>[]) => void;
|
|
878
|
+
updateNode: (id: NodeId, patch: Updater<RivetNode<TNodeData>>) => void;
|
|
879
|
+
getEdges: () => RivetEdge<TEdgeData>[];
|
|
880
|
+
getEdge: (id: EdgeId) => RivetEdge<TEdgeData> | undefined;
|
|
881
|
+
setEdges: (edges: Updater<RivetEdge<TEdgeData>[]>) => void;
|
|
882
|
+
addEdges: (edges: RivetEdge<TEdgeData> | RivetEdge<TEdgeData>[]) => void;
|
|
883
|
+
updateEdge: (id: EdgeId, patch: Updater<RivetEdge<TEdgeData>>) => void;
|
|
884
|
+
/** Delete nodes (and their edges) and/or edges by id. */
|
|
885
|
+
deleteElements: (elements: {
|
|
886
|
+
nodes?: NodeId[];
|
|
887
|
+
edges?: EdgeId[];
|
|
888
|
+
}) => void;
|
|
889
|
+
/**
|
|
890
|
+
* Bind an anchor — a connectable point — to a DOM element inside a node.
|
|
891
|
+
* The imperative core behind `<Anchor>`, for consumers whose content DOM is
|
|
892
|
+
* owned by another renderer (a rich-text editor's contentEditable, say).
|
|
893
|
+
* Idempotent on `(nodeId, anchorId)`; the returned registration re-binds a
|
|
894
|
+
* replaced element or unregisters explicitly.
|
|
895
|
+
*/
|
|
896
|
+
registerAnchor: (nodeId: NodeId, anchorId: string, element: Element, options?: AnchorRegistrationOptions) => AnchorRegistration;
|
|
897
|
+
/**
|
|
898
|
+
* Explicitly remove an anchor and its chrome. Unmounting `<Anchor>` (or
|
|
899
|
+
* rebinding `null`) only *detaches* — geometry and edges are retained — so
|
|
900
|
+
* call this when the anchored content is gone for good, alongside deleting
|
|
901
|
+
* its edges.
|
|
902
|
+
*/
|
|
903
|
+
unregisterAnchor: (nodeId: NodeId, anchorId: string) => void;
|
|
904
|
+
/**
|
|
905
|
+
* Re-measure a node's anchors. Automatic on node resize; needed after a
|
|
906
|
+
* content reflow that keeps the node box (an editor transaction, a font
|
|
907
|
+
* load) — rivet can't observe those.
|
|
908
|
+
*/
|
|
909
|
+
remeasureAnchors: (nodeId: NodeId) => void;
|
|
910
|
+
/** Copy nodes (default: the current selection) to the in-memory clipboard. */
|
|
911
|
+
copy: (ids?: NodeId[]) => void;
|
|
912
|
+
/** Copy then delete nodes (default: the current selection). */
|
|
913
|
+
cut: (ids?: NodeId[]) => void;
|
|
914
|
+
/** Paste the clipboard as fresh, selected nodes offset from the originals. No-op when empty. */
|
|
915
|
+
paste: (options?: {
|
|
916
|
+
offset?: Vec2;
|
|
917
|
+
}) => ClonedElements<TNodeData, TEdgeData> | undefined;
|
|
918
|
+
/** Clone nodes (default: the current selection) in place with fresh ids, and select them. */
|
|
919
|
+
duplicate: (ids?: NodeId[]) => ClonedElements<TNodeData, TEdgeData> | undefined;
|
|
920
|
+
/** Revert the last recordable change. Returns false when there's nothing to undo. */
|
|
921
|
+
undo: () => boolean;
|
|
922
|
+
/** Re-apply the last undone change. Returns false when there's nothing to redo. */
|
|
923
|
+
redo: () => boolean;
|
|
924
|
+
canUndo: () => boolean;
|
|
925
|
+
canRedo: () => boolean;
|
|
926
|
+
/** Drop all undo/redo history and reset the baseline to the current graph. */
|
|
927
|
+
clearHistory: () => void;
|
|
928
|
+
};
|
|
929
|
+
/**
|
|
930
|
+
* Imperative access to the graph from any component inside `<Rivet>` — CRUD on
|
|
931
|
+
* nodes/edges plus the viewport controls. Backed by the same store that drives
|
|
932
|
+
* rendering, so mutations are reflected immediately and (in controlled mode) emit
|
|
933
|
+
* changes to `onNodesChange`/`onEdgesChange`.
|
|
934
|
+
*
|
|
935
|
+
* Parameterize with your `data` types to keep them through the API:
|
|
936
|
+
* `const rivet = useRivet<MyNodeData, MyEdgeData>()`.
|
|
937
|
+
*/
|
|
938
|
+
declare function useRivet<TNodeData = unknown, TEdgeData = unknown>(): RivetInstance<TNodeData, TEdgeData>;
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* The default {@link EdgeRenderer}. Strokes each edge's sampled polyline (built by
|
|
942
|
+
* its {@link EdgePathFn}) on a 2D canvas, with per-edge style, arrowheads, and an
|
|
943
|
+
* animated dash. The geometry it draws comes from {@link buildEdges}, which is
|
|
944
|
+
* backend-neutral.
|
|
945
|
+
*/
|
|
946
|
+
declare class Canvas2DEdgeRenderer implements EdgeRenderer {
|
|
947
|
+
private readonly canvas;
|
|
948
|
+
private readonly ctx;
|
|
949
|
+
private dpr;
|
|
950
|
+
private width;
|
|
951
|
+
private height;
|
|
952
|
+
private readonly edgeTypes;
|
|
953
|
+
private readonly defaults;
|
|
954
|
+
/** Screen-space polylines from the last frame, keyed by edge id, for picking. */
|
|
955
|
+
private readonly geometry;
|
|
956
|
+
/** Screen-space endpoints per edge, for endpoint (reconnection) picking. */
|
|
957
|
+
private readonly endpoints;
|
|
958
|
+
/** Screen-space label anchor per edge that has a label. */
|
|
959
|
+
private readonly labels;
|
|
960
|
+
constructor(canvas: HTMLCanvasElement, options?: EdgeRendererOptions);
|
|
961
|
+
resize(width: number, height: number, dpr: number): void;
|
|
962
|
+
/** Screen-space label anchors for the edges drawn last frame. */
|
|
963
|
+
getLabels(): Map<EdgeId, Vec2>;
|
|
964
|
+
/** Screen-space endpoints per edge from the last frame (reconnect affordance). */
|
|
965
|
+
getEndpoints(): ReadonlyMap<EdgeId, {
|
|
966
|
+
source: Vec2;
|
|
967
|
+
target: Vec2;
|
|
968
|
+
}>;
|
|
969
|
+
draw(edges: RivetEdge[], nodes: Map<NodeId, RivetNode>, viewport: Viewport, extras?: EdgeDrawExtras): void;
|
|
970
|
+
pick(x: number, y: number, tolerance?: number): EdgeId | null;
|
|
971
|
+
pickEndpoint(x: number, y: number): {
|
|
972
|
+
edgeId: EdgeId;
|
|
973
|
+
end: EdgeEnd;
|
|
974
|
+
} | null;
|
|
975
|
+
dispose(): void;
|
|
976
|
+
}
|
|
977
|
+
/** The built-in {@link EdgeRendererFactory} — the default backend for `<Rivet>`. */
|
|
978
|
+
declare const canvas2DEdgeRenderer: EdgeRendererFactory;
|
|
979
|
+
|
|
980
|
+
/** A straight line between the two ends. */
|
|
981
|
+
declare const getStraightPath: EdgePathFn;
|
|
982
|
+
/**
|
|
983
|
+
* A cubic bezier that leaves each end perpendicular to its handle's side, so
|
|
984
|
+
* edges curve cleanly out of left/right/top/bottom handles. This is the default.
|
|
985
|
+
*/
|
|
986
|
+
declare const getBezierPath: EdgePathFn;
|
|
987
|
+
/** An axis-aligned step path with rounded corners. */
|
|
988
|
+
declare const getSmoothStepPath: EdgePathFn;
|
|
989
|
+
/** An axis-aligned step path with sharp corners. */
|
|
990
|
+
declare const getStepPath: EdgePathFn;
|
|
991
|
+
/** The built-in edge shapes, keyed by `type`. `bezier` is the default. */
|
|
992
|
+
declare const BUILTIN_EDGE_TYPES: Record<string, EdgePathFn>;
|
|
993
|
+
|
|
994
|
+
/** Convert a world-space point to screen-space pixels. */
|
|
995
|
+
declare function worldToScreen(point: Vec2, viewport: Viewport): Vec2;
|
|
996
|
+
/** Convert a screen-space point (e.g. a pointer event) to world space. */
|
|
997
|
+
declare function screenToWorld(point: Vec2, viewport: Viewport): Vec2;
|
|
998
|
+
/**
|
|
999
|
+
* Zoom toward an anchor point (usually the cursor) so the world point under the
|
|
1000
|
+
* anchor stays put. Returns a new viewport; the input is not mutated.
|
|
1001
|
+
*/
|
|
1002
|
+
declare function zoomAt(viewport: Viewport, anchor: Vec2, nextZoom: number, minZoom?: number, maxZoom?: number): Viewport;
|
|
1003
|
+
/** The CSS transform string applied to the DOM node layer. */
|
|
1004
|
+
declare function viewportToCss(viewport: Viewport): string;
|
|
1005
|
+
/** The visible world-space rectangle for a viewport of the given pixel size. */
|
|
1006
|
+
declare function visibleWorldRect(viewport: Viewport, width: number, height: number): Rect;
|
|
1007
|
+
/** True if two axis-aligned rectangles overlap (used for node culling). */
|
|
1008
|
+
declare function rectsIntersect(a: Rect, b: Rect): boolean;
|
|
1009
|
+
|
|
1010
|
+
declare const VERSION = "0.0.0";
|
|
1011
|
+
|
|
1012
|
+
export { AlignmentGuide, BUILTIN_EDGE_TYPES, BUILTIN_NODE_TYPES, Canvas2DEdgeRenderer, type CloneOptions, type ClonedElements, Connection, Controls, type ControlsProps, DEFAULT_ALIGNMENT_HYSTERESIS, DefaultEdgeOptions, DefaultNode, type EdgeAlignment, EdgeChange, EdgeDrawExtras, EdgeEnd, type EdgeEndpoint, EdgeId, EdgePathFn, EdgeRenderer, EdgeRendererFactory, EdgeRendererOptions, EdgeTypes, GroupNode, Handle, HandlePosition, type HandleProps, HandleRecord, HandleType, MiniMap, type MiniMapProps, NodeChange, NodeId, NodeProps, NodeResizer, type NodeResizerProps, NodeTypes, type PaneContextMenuContext, PendingConnection, ReconnectDelegate, Rect, Rivet, RivetControls, RivetEdge, type RivetInstance, RivetNode, type RivetProps, RivetSelection, RivetSnapshot, type RivetStore, Size, VERSION, Vec2, Viewport, alignRect, applyEdgeChanges, applyNodeChanges, boundingRect, canvas2DEdgeRenderer, clampChildToParent, cloneElements, createRivetStore, edgeEndpointHandle, facingSide, getBezierPath, getSmoothStepPath, getStepPath, getStraightPath, handleKey, parseEdgeEndpoint, parseSideHandleId, rectsIntersect, resolveFacingSide, screenToWorld, serializeGraph, snapToGrid, useRivet, useRivetContext, useRivetControls, useRivetFocusedNode, useRivetHistory, useRivetViewport, viewportToCss, visibleWorldRect, worldToScreen, zoomAt };
|