@kolosal-ai/rivet 0.1.1 → 0.2.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/README.md +4 -0
- package/dist/anchor/index.d.ts +2 -2
- package/dist/chunk-RG5ALD3X.js +306 -0
- package/dist/chunk-RG5ALD3X.js.map +1 -0
- package/dist/index.d.ts +481 -254
- package/dist/index.js +979 -410
- package/dist/index.js.map +1 -1
- package/dist/presence/index.d.ts +19 -0
- package/dist/presence/index.js +16 -0
- package/dist/presence/index.js.map +1 -0
- package/dist/{registry-Dkk4ZKt-.d.ts → registry-t5ldbviG.d.ts} +1 -1
- package/dist/svg/index.d.ts +2 -2
- package/dist/swimlane/index.d.ts +2 -2
- package/dist/{types-B8AAJ60T.d.ts → types-CQqnm4yW.d.ts} +55 -1
- package/dist/use-node-lock-Csg9pUeC.d.ts +323 -0
- package/package.json +5 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
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
|
|
2
|
-
export {
|
|
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 ChangeOrigin, h as EdgeId, i as HandleRecord, j as ChangeMeta, k as Viewport, l as NodeGestureEvent, m as NodeLockConflictEvent, n as RivetSelection, o as ReconnectDelegate, C as Connection, P as PendingConnection, p as EdgeTypes, D as DefaultEdgeOptions, q as EdgeRendererFactory, r as SwimlaneGroup, s as SwimlaneMargin, t as SwimlaneHeaderProps, u as SwimlaneLabelProps, v as SwimlaneSizeChange, L as LaneChange, w as RivetControls, x as RivetSnapshot, y as EdgeRenderer, z as EdgeRendererOptions, B as EdgeDrawExtras, F as EdgeEnd, G as EdgePathFn } from './types-CQqnm4yW.js';
|
|
2
|
+
export { I as CenterNodeOptions, J as EdgeMarker, K as EdgePath, M as EdgePathParams, O as EdgeStyle, Q as FitViewOptions, T as NodeComponent } from './types-CQqnm4yW.js';
|
|
3
3
|
import { ReactNode, CSSProperties, MouseEvent, RefObject } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { d as AnchorRecord, f as AnchorRegistrationOptions, b as AnchorOptions, R as ResolvedAnchorOptions, e as AnchorRegistration } from './registry-t5ldbviG.js';
|
|
5
|
+
import { h as PresenceRegistry, d as LockRegistry, f as Peer, a as LocalPresence, g as PresenceOptions, C as CanInteractWithLocked } from './use-node-lock-Csg9pUeC.js';
|
|
6
|
+
export { L as LOCK_DEFAULT_REFUSED, b as LockIntent, c as LockInteraction, N as NodeLock, u as useNodeLock, i as useNodeLockAllows } from './use-node-lock-Csg9pUeC.js';
|
|
5
7
|
import { ResolvedLane, ViewportElements, ResolvedSwimlaneGroup, ResolvedMargin } from './swimlane/index.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
@@ -153,7 +155,7 @@ type NodeResizerProps = {
|
|
|
153
155
|
* top/left handles) via {@link RivetStore.resizeNode} — so it works with
|
|
154
156
|
* controlled mode (emits dimension changes) and nested nodes alike.
|
|
155
157
|
*/
|
|
156
|
-
declare function NodeResizer({ minWidth, minHeight, maxWidth, maxHeight, keepAspectRatio, color, onResize, onResizeEnd, }: NodeResizerProps): React.ReactElement;
|
|
158
|
+
declare function NodeResizer({ minWidth, minHeight, maxWidth, maxHeight, keepAspectRatio, color, onResize, onResizeEnd, }: NodeResizerProps): React.ReactElement | null;
|
|
157
159
|
|
|
158
160
|
/**
|
|
159
161
|
* Edge alignment — the library-level policy for when an edge's endpoints
|
|
@@ -221,248 +223,6 @@ declare function resolveFacingSide(node: Rect, peer: Rect, previous?: HandlePosi
|
|
|
221
223
|
*/
|
|
222
224
|
declare function resolveFacingSideAmong(node: Rect, peer: Rect, allowed: readonly HandlePosition[], previous?: HandlePosition, hysteresis?: number): HandlePosition;
|
|
223
225
|
|
|
224
|
-
/** Resolved graph context for a pane right-click, passed to `onPaneContextMenu`. */
|
|
225
|
-
type PaneContextMenuContext = {
|
|
226
|
-
/** The click position in world coordinates (already unprojected). */
|
|
227
|
-
world: Vec2;
|
|
228
|
-
/** The swimlane lane whose body sits under the cursor, or `null`. */
|
|
229
|
-
lane: ResolvedLane | null;
|
|
230
|
-
};
|
|
231
|
-
type RivetProps = {
|
|
232
|
-
/**
|
|
233
|
-
* Nodes to seed the graph with (uncontrolled). Read once on mount to initialize
|
|
234
|
-
* the internal store — later changes to this array are ignored. Use {@link nodes}
|
|
235
|
-
* + {@link onNodesChange} for controlled mode instead. Defaults to `[]`.
|
|
236
|
-
*/
|
|
237
|
-
defaultNodes?: RivetNode[];
|
|
238
|
-
/**
|
|
239
|
-
* Edges to seed the graph with (uncontrolled). See {@link defaultNodes}. An edge
|
|
240
|
-
* whose `source` or `target` node is absent is skipped by the renderer. Defaults to `[]`.
|
|
241
|
-
*/
|
|
242
|
-
defaultEdges?: RivetEdge[];
|
|
243
|
-
/**
|
|
244
|
-
* Controlled nodes. When provided, the graph mirrors this array — hold the nodes
|
|
245
|
-
* in your own state and feed back the batches from {@link onNodesChange} (apply
|
|
246
|
-
* them with `applyNodeChanges`). Node drags are suppressed from reconciling
|
|
247
|
-
* mid-drag so the graph stays smooth. Takes precedence over {@link defaultNodes}.
|
|
248
|
-
*/
|
|
249
|
-
nodes?: RivetNode[];
|
|
250
|
-
/** Controlled edges. See {@link nodes}. Takes precedence over {@link defaultEdges}. */
|
|
251
|
-
edges?: RivetEdge[];
|
|
252
|
-
/** Change batches the graph wants applied to your nodes (controlled mode). */
|
|
253
|
-
onNodesChange?: (changes: NodeChange[]) => void;
|
|
254
|
-
/** Change batches the graph wants applied to your edges (controlled mode). */
|
|
255
|
-
onEdgesChange?: (changes: EdgeChange[]) => void;
|
|
256
|
-
/**
|
|
257
|
-
* Initial pan/zoom. `x`/`y` are the screen-space offset in pixels and `zoom`
|
|
258
|
-
* is the scale factor. Defaults to `{ x: 0, y: 0, zoom: 1 }` (origin, 1:1).
|
|
259
|
-
*/
|
|
260
|
-
defaultViewport?: Viewport;
|
|
261
|
-
/**
|
|
262
|
-
* Maps a node's `type` to the React component that renders it. A node whose
|
|
263
|
-
* `type` has no entry here (or no `type` at all) falls back to
|
|
264
|
-
* {@link DefaultNode}. Defaults to `{}`.
|
|
265
|
-
*/
|
|
266
|
-
nodeTypes?: NodeTypes;
|
|
267
|
-
/**
|
|
268
|
-
* Registry of custom edge shapes, keyed by `edge.type`. Each is a pure geometry
|
|
269
|
-
* function (see {@link EdgePathFn}) so edges stay canvas/GPU-renderable. Merged
|
|
270
|
-
* over the built-ins `bezier` (default), `smoothstep`, `step`, and `straight`.
|
|
271
|
-
*/
|
|
272
|
-
edgeTypes?: EdgeTypes;
|
|
273
|
-
/** Defaults merged into every edge that doesn't set the field (type, style, markers…). */
|
|
274
|
-
defaultEdgeOptions?: DefaultEdgeOptions;
|
|
275
|
-
/** Accessible name for the graph surface (`aria-label` on the pane). Defaults to "Node graph". */
|
|
276
|
-
ariaLabel?: string;
|
|
277
|
-
/**
|
|
278
|
-
* Backend factory for the edge layers — swap Canvas2D for another
|
|
279
|
-
* {@link EdgeRenderer}. Defaults to {@link canvas2DEdgeRenderer}. Pass a stable/memoized
|
|
280
|
-
* reference; a new identity re-creates the renderers.
|
|
281
|
-
*/
|
|
282
|
-
renderer?: EdgeRendererFactory;
|
|
283
|
-
/**
|
|
284
|
-
* Lower bound on `viewport.zoom`. All zooming (wheel, controls, `fitView`) is
|
|
285
|
-
* clamped to this. Defaults to `0.2` (zoomed out to 20%).
|
|
286
|
-
*/
|
|
287
|
-
minZoom?: number;
|
|
288
|
-
/**
|
|
289
|
-
* Upper bound on `viewport.zoom`. All zooming is clamped to this. Defaults to
|
|
290
|
-
* `2.5` (zoomed in to 250%).
|
|
291
|
-
*/
|
|
292
|
-
maxZoom?: number;
|
|
293
|
-
/**
|
|
294
|
-
* Spacing in world units between background grid dots. The grid scales with
|
|
295
|
-
* zoom, so this is measured at `zoom === 1`. Defaults to `24`.
|
|
296
|
-
*/
|
|
297
|
-
gridGap?: number;
|
|
298
|
-
/**
|
|
299
|
-
* Snap dragged nodes to a `[x, y]` world-unit grid. A `0` axis is left free.
|
|
300
|
-
* Omit (default) for free positioning. Independent of {@link gridGap} (the
|
|
301
|
-
* visual dot grid) — pass the same value to snap to the dots you see.
|
|
302
|
-
*/
|
|
303
|
-
snapGrid?: [number, number];
|
|
304
|
-
/**
|
|
305
|
-
* While dragging a single node, show alignment guides and snap its edges/center
|
|
306
|
-
* to nearby nodes' edges/centers. Defaults to `false`.
|
|
307
|
-
*/
|
|
308
|
-
alignmentGuides?: boolean;
|
|
309
|
-
/**
|
|
310
|
-
* Placement policy for anchor chrome — the grab dots and stray perimeter
|
|
311
|
-
* handles rivet renders for registered anchors (see {@link Anchor}). Omitted
|
|
312
|
-
* fields fall back to the defaults.
|
|
313
|
-
*/
|
|
314
|
-
anchorOptions?: AnchorOptions;
|
|
315
|
-
/**
|
|
316
|
-
* Which mouse buttons pan when dragging the pane: `true` = left only, `false` =
|
|
317
|
-
* none, or a list of `MouseEvent.button` codes (`0` left, `1` middle, `2` right).
|
|
318
|
-
* e.g. `[1, 2]` pans with middle/right and frees left for selection. Defaults to
|
|
319
|
-
* `true`. Pass a stable reference; a new array identity re-binds the listeners.
|
|
320
|
-
*/
|
|
321
|
-
panOnDrag?: boolean | number[];
|
|
322
|
-
/**
|
|
323
|
-
* Draw a selection marquee on a plain left-drag instead of panning. Pair with
|
|
324
|
-
* `panOnDrag={[1, 2]}` so left selects and middle/right pan. A marquee that
|
|
325
|
-
* ends over nodes leaves a persistent selection box around them — drag it to
|
|
326
|
-
* move the whole selection; a click elsewhere or Escape dismisses it.
|
|
327
|
-
* Defaults to `false`.
|
|
328
|
-
*/
|
|
329
|
-
selectionOnDrag?: boolean;
|
|
330
|
-
/**
|
|
331
|
-
* Key(s) that force a marquee on a left-drag when held (e.g. `"Shift"`, `"Meta"`,
|
|
332
|
-
* or `["Shift", "Meta"]`). `null` disables. Defaults to `"Shift"`.
|
|
333
|
-
*/
|
|
334
|
-
selectionKeyCode?: string | string[] | null;
|
|
335
|
-
/**
|
|
336
|
-
* Key(s) that make a click or marquee **add to** the selection instead of
|
|
337
|
-
* replacing it. Defaults to `["Meta", "Control", "Shift"]`. Use modifier keys
|
|
338
|
-
* (`Shift`/`Meta`/`Control`/`Alt`) — other keys only resolve during a pane drag.
|
|
339
|
-
*/
|
|
340
|
-
multiSelectionKeyCode?: string | string[];
|
|
341
|
-
/**
|
|
342
|
-
* Pan the viewport on wheel / two-finger trackpad scroll instead of zooming.
|
|
343
|
-
* A pinch gesture (reported by the browser as ctrl+wheel) still zooms. When
|
|
344
|
-
* `false` (default), scrolling zooms toward the cursor.
|
|
345
|
-
*/
|
|
346
|
-
scrollToPan?: boolean;
|
|
347
|
-
/**
|
|
348
|
-
* Wheel/pinch zoom sensitivity — larger zooms faster per scroll delta.
|
|
349
|
-
* Defaults to `0.0015`. Try `~0.003` for faster trackpad pinch zoom.
|
|
350
|
-
*/
|
|
351
|
-
zoomSpeed?: number;
|
|
352
|
-
/**
|
|
353
|
-
* Swimlanes drawn behind the graph — a decorative background of labeled lane
|
|
354
|
-
* groups (like planout's swimlanes). Not nodes or edges; just layout regions.
|
|
355
|
-
* Omit for no swimlanes.
|
|
356
|
-
*/
|
|
357
|
-
swimlane?: SwimlaneGroup[];
|
|
358
|
-
/**
|
|
359
|
-
* Bind node dragging to the swimlanes: on drop each node snaps fully inside
|
|
360
|
-
* one lane (honoring {@link swimlaneMargin}) and is reassigned to the lane it
|
|
361
|
-
* lands in via {@link RivetNode.laneId}. Defaults to `true` when
|
|
362
|
-
* {@link swimlane} is provided, `false` otherwise. Ignored with no swimlanes.
|
|
363
|
-
*/
|
|
364
|
-
clampToSwimlane?: boolean;
|
|
365
|
-
/**
|
|
366
|
-
* Inner clearance kept between a clamped node and its lane's edges. A number
|
|
367
|
-
* applies to all sides; per-side values override it. Defaults to `16`.
|
|
368
|
-
*/
|
|
369
|
-
swimlaneMargin?: number | SwimlaneMargin;
|
|
370
|
-
/** Screen height of the sticky group header band, in px. Defaults to `32`. */
|
|
371
|
-
swimlaneHeaderHeight?: number;
|
|
372
|
-
/**
|
|
373
|
-
* Show a resize handle on each lane's bottom edge to change its height.
|
|
374
|
-
* Defaults to `true` when {@link swimlane} is provided.
|
|
375
|
-
*/
|
|
376
|
-
swimlaneResizable?: boolean;
|
|
377
|
-
/**
|
|
378
|
-
* Fraction of the last lane's height that must stay visible when scrolled to
|
|
379
|
-
* the bottom — the down-scroll stop. `0.5` (default) keeps half of it in view.
|
|
380
|
-
* Only applies when {@link clampToSwimlane} is on.
|
|
381
|
-
*/
|
|
382
|
-
swimlaneBottomReveal?: number;
|
|
383
|
-
/** Render custom content for a group's sticky header (replaces the default). */
|
|
384
|
-
renderSwimlaneHeader?: (props: SwimlaneHeaderProps) => ReactNode;
|
|
385
|
-
/** Render custom content for a lane's sticky label (replaces the default). */
|
|
386
|
-
renderSwimlaneLabel?: (props: SwimlaneLabelProps) => ReactNode;
|
|
387
|
-
/**
|
|
388
|
-
* Called when a lane's height changes — from a resize drag or from auto-fit
|
|
389
|
-
* growing it to contain a node that grew. The graph owns lane heights, so this
|
|
390
|
-
* is a notification (persist it if you like), not a request to update state.
|
|
391
|
-
*/
|
|
392
|
-
onSwimlaneSizeChange?: (change: SwimlaneSizeChange) => void;
|
|
393
|
-
/**
|
|
394
|
-
* Right-click on empty canvas (not over a node or swimlane chrome). The second
|
|
395
|
-
* argument carries the resolved graph context — the world position and the lane
|
|
396
|
-
* under the cursor — so you don't have to re-derive them.
|
|
397
|
-
*/
|
|
398
|
-
onPaneContextMenu?: (event: MouseEvent, context: PaneContextMenuContext) => void;
|
|
399
|
-
/** Right-click on a lane's sticky label. */
|
|
400
|
-
onSwimlaneHeaderContextMenu?: (laneId: string, event: MouseEvent) => void;
|
|
401
|
-
/** Right-click on a group's sticky header. */
|
|
402
|
-
onSwimlaneGroupHeaderContextMenu?: (groupId: string, event: MouseEvent) => void;
|
|
403
|
-
/** Called when a dragged node is reassigned to a different lane. */
|
|
404
|
-
onLaneChange?: (change: LaneChange) => void;
|
|
405
|
-
/** Veto a proposed connection; return false to reject it. Applies to reconnection too. */
|
|
406
|
-
isValidConnection?: (connection: Connection) => boolean;
|
|
407
|
-
/**
|
|
408
|
-
* Rewrite a validated connection before it commits — normalize handle ids
|
|
409
|
-
* (e.g. redirect an in-content grab handle to its canonical perimeter
|
|
410
|
-
* handle), or force direction conventions. Returning `null` cancels the
|
|
411
|
-
* drop. Applies to new connections and reconnections; `isValidConnection`
|
|
412
|
-
* sees the raw connection, `onConnect`/`onReconnect` see the mapped one.
|
|
413
|
-
*/
|
|
414
|
-
mapConnection?: (connection: Connection) => Connection | null;
|
|
415
|
-
/** Called after a valid connection is made (the edge is already added). */
|
|
416
|
-
onConnect?: (connection: Connection) => void;
|
|
417
|
-
/**
|
|
418
|
-
* Allow reconnecting edges by dragging an endpoint onto a new handle. Per-edge
|
|
419
|
-
* `reconnectable` overrides this. Defaults to `false`.
|
|
420
|
-
*/
|
|
421
|
-
edgesReconnectable?: boolean;
|
|
422
|
-
/**
|
|
423
|
-
* When edge endpoints re-side to face the peer node. `"manual"` (default)
|
|
424
|
-
* never rewrites a chosen handle; `"on-move"` re-sides both ends of a moved
|
|
425
|
-
* node's edges when the move commits — in the same batch as the move, so one
|
|
426
|
-
* undo restores position and handles together. `"live"` additionally renders
|
|
427
|
-
* a dragging node's edges as if their ends were auto — re-siding per frame
|
|
428
|
-
* to face each other, with hysteresis so near-diagonal positions don't
|
|
429
|
-
* flicker — and commits the displayed sides on drop, inside the move's
|
|
430
|
-
* history step; nothing is persisted mid-gesture. Only committed position
|
|
431
|
-
* changes trigger a rewrite: data replaces and dimension changes never
|
|
432
|
-
* re-side, and a freshly created or reconnected edge keeps exactly the
|
|
433
|
-
* handles the user grabbed or dropped on. Anchor and bare-side ends rewrite
|
|
434
|
-
* their side directly; plain handles re-side to a registered handle of a
|
|
435
|
-
* compatible type on the facing side, or stay pinned when the node has none
|
|
436
|
-
* there. Independent of the policy, an end with *no* side — a missing
|
|
437
|
-
* handle, or an `anchorAutoHandleId` anchor end — always floats: the
|
|
438
|
-
* renderer resolves its facing side per frame and never writes it back.
|
|
439
|
-
*/
|
|
440
|
-
edgeAlignment?: EdgeAlignment;
|
|
441
|
-
/** Called when an endpoint drag re-points an edge (the edge is already updated). */
|
|
442
|
-
onReconnect?: (edge: RivetEdge, connection: Connection) => void;
|
|
443
|
-
/** Called when an endpoint reconnection drag starts. */
|
|
444
|
-
onReconnectStart?: (edge: RivetEdge) => void;
|
|
445
|
-
/** Called when an endpoint reconnection drag ends (committed or cancelled). */
|
|
446
|
-
onReconnectEnd?: (edge: RivetEdge) => void;
|
|
447
|
-
/** Called whenever the selected nodes and/or edges change. */
|
|
448
|
-
onSelectionChange?: (selection: RivetSelection) => void;
|
|
449
|
-
/**
|
|
450
|
-
* Called when keyboard focus moves to a node (or leaves the graph — `null`).
|
|
451
|
-
* The same state is available inside `<Rivet>` via {@link useRivetFocusedNode}.
|
|
452
|
-
* Rivet draws no focus ring; use this (or the wrapper's `:focus-visible`) to
|
|
453
|
-
* render your own indicator.
|
|
454
|
-
*/
|
|
455
|
-
onFocusChange?: (id: NodeId | null) => void;
|
|
456
|
-
className?: string;
|
|
457
|
-
style?: CSSProperties;
|
|
458
|
-
children?: ReactNode;
|
|
459
|
-
};
|
|
460
|
-
/**
|
|
461
|
-
* The graph surface. Stacks a background grid canvas, an edge canvas, and a DOM
|
|
462
|
-
* node layer — all driven by one shared viewport (see {@link useRivetRuntime}).
|
|
463
|
-
*/
|
|
464
|
-
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;
|
|
465
|
-
|
|
466
226
|
/** Composite key for the handle/anchor registries. */
|
|
467
227
|
declare function handleKey(nodeId: NodeId, handleId: string): string;
|
|
468
228
|
|
|
@@ -477,8 +237,22 @@ type ViewportClamp = {
|
|
|
477
237
|
maxY?: number;
|
|
478
238
|
};
|
|
479
239
|
type ChangeHandlers = {
|
|
480
|
-
nodes?: (changes: NodeChange[]) => void;
|
|
481
|
-
edges?: (changes: EdgeChange[]) => void;
|
|
240
|
+
nodes?: (changes: NodeChange[], meta: ChangeMeta) => void;
|
|
241
|
+
edges?: (changes: EdgeChange[], meta: ChangeMeta) => void;
|
|
242
|
+
};
|
|
243
|
+
/** Gesture lifecycle sinks — see {@link RivetStore.setGestureHandlers}. */
|
|
244
|
+
type GestureHandlers = {
|
|
245
|
+
start?: (event: NodeGestureEvent) => void;
|
|
246
|
+
end?: (event: NodeGestureEvent) => void;
|
|
247
|
+
/** A peer's lock landed on a node this client is already holding. */
|
|
248
|
+
conflict?: (event: NodeLockConflictEvent) => void;
|
|
249
|
+
};
|
|
250
|
+
/** Changes to hand to {@link RivetStore.applyRemote}. */
|
|
251
|
+
type RemoteChanges = {
|
|
252
|
+
nodes?: NodeChange[];
|
|
253
|
+
edges?: EdgeChange[];
|
|
254
|
+
/** Defaults to `"remote"`. Pass a peer or transaction id to route on it. */
|
|
255
|
+
origin?: ChangeOrigin;
|
|
482
256
|
};
|
|
483
257
|
/**
|
|
484
258
|
* The single source of truth for a graph instance — the public contract. It's an
|
|
@@ -516,6 +290,18 @@ type RivetStore = {
|
|
|
516
290
|
* nodes don't re-render.
|
|
517
291
|
*/
|
|
518
292
|
reconcile: (nodes: RivetNode[], edges: RivetEdge[]) => void;
|
|
293
|
+
/**
|
|
294
|
+
* Apply a change batch that happened somewhere else — a peer's edit arriving
|
|
295
|
+
* over your transport. The graph updates and repaints immediately, then the
|
|
296
|
+
* batch is re-emitted to the change handlers tagged `"remote"` so a controlled
|
|
297
|
+
* owner applies it through the same path as everything else.
|
|
298
|
+
*
|
|
299
|
+
* Remote batches never create an undo step: undoing a peer's edit isn't undo,
|
|
300
|
+
* and in a shared document it would silently revert work you don't own. The
|
|
301
|
+
* history baseline is refreshed instead, so your next local step still diffs
|
|
302
|
+
* against reality.
|
|
303
|
+
*/
|
|
304
|
+
applyRemote: (changes: RemoteChanges) => void;
|
|
519
305
|
/** Add a node (imperative CRUD). Ignored if the id already exists. */
|
|
520
306
|
addNode: (node: RivetNode) => void;
|
|
521
307
|
/** Replace a node wholesale by id (imperative CRUD). Ignored if absent. */
|
|
@@ -593,13 +379,54 @@ type RivetStore = {
|
|
|
593
379
|
/** True while a node drag is in progress (pauses swimlane auto-fit). */
|
|
594
380
|
isNodeDragging: () => boolean;
|
|
595
381
|
setNodeDragging: (dragging: boolean) => void;
|
|
382
|
+
/**
|
|
383
|
+
* Open a gesture on `ids` — a pointer drag, a resize, or a keyboard grab.
|
|
384
|
+
* While it's open those nodes are *held*: this client's geometry for them wins
|
|
385
|
+
* over anything arriving from elsewhere (see {@link isNodeHeld}), and
|
|
386
|
+
* {@link GestureHandlers.start} fires so a consumer can take a lock.
|
|
387
|
+
*
|
|
388
|
+
* `id` is the node the gesture began on; `ids` is everything moving with it
|
|
389
|
+
* (a group drag holds the whole selection). Re-opening an already-held node
|
|
390
|
+
* is a no-op, so a gesture may safely widen.
|
|
391
|
+
*/
|
|
392
|
+
beginNodeGesture: (id: NodeId, ids?: NodeId[]) => void;
|
|
393
|
+
/**
|
|
394
|
+
* Close a gesture opened by {@link beginNodeGesture}, releasing its nodes.
|
|
395
|
+
*
|
|
396
|
+
* Normally the gesture calls this itself on drop. Calling it from outside is
|
|
397
|
+
* how a consumer yields a contested node mid-drag: the running gesture sees
|
|
398
|
+
* that it no longer holds its nodes, stops writing to them, and tears itself
|
|
399
|
+
* down without committing.
|
|
400
|
+
*/
|
|
401
|
+
endNodeGesture: (id: NodeId, ids?: NodeId[]) => void;
|
|
402
|
+
/**
|
|
403
|
+
* Publish the lock table (the `lockedNodes` prop), and report any node it
|
|
404
|
+
* claims that a local gesture is already holding to
|
|
405
|
+
* {@link GestureHandlers.conflict}. The gesture itself is left running — see
|
|
406
|
+
* {@link NodeLockConflictEvent} for why rivet doesn't pick the loser.
|
|
407
|
+
*/
|
|
408
|
+
setLockedNodes: (locks: Record<NodeId, string> | undefined) => void;
|
|
409
|
+
/**
|
|
410
|
+
* True while a local gesture holds this node. Held geometry is exclusively
|
|
411
|
+
* this client's: {@link applyRemote} drops incoming `position`/`dimensions`
|
|
412
|
+
* for it, and {@link reconcile} keeps the live box rather than the prop's.
|
|
413
|
+
*/
|
|
414
|
+
isNodeHeld: (id: NodeId) => boolean;
|
|
415
|
+
/** Every node currently under a local gesture. */
|
|
416
|
+
getHeldNodeIds: () => ReadonlySet<NodeId>;
|
|
417
|
+
/**
|
|
418
|
+
* Subscribe to the held set opening or closing. Unlike
|
|
419
|
+
* {@link setGestureHandlers} — a single sink the `onNodeDragStart` /
|
|
420
|
+
* `onNodeDragEnd` props own — this is a broadcast channel, so presence can
|
|
421
|
+
* watch the same gesture the consumer's lock handler is acting on.
|
|
422
|
+
*/
|
|
423
|
+
subscribeHeldNodes: (listener: () => void) => () => void;
|
|
424
|
+
/** Register the gesture lifecycle handlers (the lock acquire/release signals). */
|
|
425
|
+
setGestureHandlers: (handlers: GestureHandlers) => void;
|
|
596
426
|
/**
|
|
597
427
|
* True while a resize gesture is in progress — set by {@link resizeNode}'s live
|
|
598
|
-
* frames and cleared by its commit.
|
|
599
|
-
*
|
|
600
|
-
* the store (live frames may be dropped, and measurement echoes carry `size`
|
|
601
|
-
* but not the explicit `width`/`height`), so reconciling them would stomp the
|
|
602
|
-
* live box back to its pre-gesture value every frame.
|
|
428
|
+
* frames and cleared by its commit. Stomp protection is per-node and lives in
|
|
429
|
+
* {@link isNodeHeld}; this stays a coarse "is a resize happening at all" flag.
|
|
603
430
|
*/
|
|
604
431
|
isNodeResizing: () => boolean;
|
|
605
432
|
/**
|
|
@@ -684,6 +511,20 @@ type RivetStore = {
|
|
|
684
511
|
setAlignmentGuides: (guides: AlignmentGuide[]) => void;
|
|
685
512
|
registerHandle: (record: HandleRecord) => void;
|
|
686
513
|
unregisterHandle: (nodeId: NodeId, handleId: string) => void;
|
|
514
|
+
/**
|
|
515
|
+
* Ephemeral peer presence — cursors, selections, and the boxes peers are
|
|
516
|
+
* dragging right now. Never part of the graph, the change stream, or
|
|
517
|
+
* history: presence describes people, not the document. Painted from the
|
|
518
|
+
* render loop; see `rivet/presence`.
|
|
519
|
+
*/
|
|
520
|
+
readonly presence: PresenceRegistry;
|
|
521
|
+
/**
|
|
522
|
+
* Nodes peers have claimed, and the policy for what this client may still do
|
|
523
|
+
* to them. Published whole by {@link setLockedNodes}; read by every input
|
|
524
|
+
* path before it acts, and by the render loop to outline the holder. Like
|
|
525
|
+
* presence, never part of the graph, the change stream, or history.
|
|
526
|
+
*/
|
|
527
|
+
readonly locks: LockRegistry;
|
|
687
528
|
readonly anchors: Map<string, AnchorRecord>;
|
|
688
529
|
/**
|
|
689
530
|
* Register (or re-bind) an anchor. Idempotent on the `(nodeId, anchorId)`
|
|
@@ -722,6 +563,339 @@ type RivetStore = {
|
|
|
722
563
|
/** Create a graph store. The public entry point; the class is an implementation detail. */
|
|
723
564
|
declare function createRivetStore(init: RivetStoreInit): RivetStore;
|
|
724
565
|
|
|
566
|
+
/** Resolved graph context for a pane right-click, passed to `onPaneContextMenu`. */
|
|
567
|
+
type PaneContextMenuContext = {
|
|
568
|
+
/** The click position in world coordinates (already unprojected). */
|
|
569
|
+
world: Vec2;
|
|
570
|
+
/** The swimlane lane whose body sits under the cursor, or `null`. */
|
|
571
|
+
lane: ResolvedLane | null;
|
|
572
|
+
};
|
|
573
|
+
type RivetProps = {
|
|
574
|
+
/**
|
|
575
|
+
* Nodes to seed the graph with (uncontrolled). Read once on mount to initialize
|
|
576
|
+
* the internal store — later changes to this array are ignored. Use {@link nodes}
|
|
577
|
+
* + {@link onNodesChange} for controlled mode instead. Defaults to `[]`.
|
|
578
|
+
*/
|
|
579
|
+
defaultNodes?: RivetNode[];
|
|
580
|
+
/**
|
|
581
|
+
* Edges to seed the graph with (uncontrolled). See {@link defaultNodes}. An edge
|
|
582
|
+
* whose `source` or `target` node is absent is skipped by the renderer. Defaults to `[]`.
|
|
583
|
+
*/
|
|
584
|
+
defaultEdges?: RivetEdge[];
|
|
585
|
+
/**
|
|
586
|
+
* Controlled nodes. When provided, the graph mirrors this array — hold the nodes
|
|
587
|
+
* in your own state and feed back the batches from {@link onNodesChange} (apply
|
|
588
|
+
* them with `applyNodeChanges`). A node under a live gesture keeps its own
|
|
589
|
+
* geometry rather than the array's, so a drag stays smooth while the props
|
|
590
|
+
* lag behind it. Takes precedence over {@link defaultNodes}.
|
|
591
|
+
*/
|
|
592
|
+
nodes?: RivetNode[];
|
|
593
|
+
/** Controlled edges. See {@link nodes}. Takes precedence over {@link defaultEdges}. */
|
|
594
|
+
edges?: RivetEdge[];
|
|
595
|
+
/**
|
|
596
|
+
* Change batches the graph wants applied to your nodes (controlled mode).
|
|
597
|
+
*
|
|
598
|
+
* `meta.origin` says where the batch came from: `"local"` for anything this
|
|
599
|
+
* client did, `"remote"` for a batch that arrived through
|
|
600
|
+
* {@link RivetInstance.applyRemote}. Multiplayer consumers apply both and send
|
|
601
|
+
* only the local ones onward — an untagged echo is indistinguishable from a
|
|
602
|
+
* peer's edit and loops straight back out.
|
|
603
|
+
*/
|
|
604
|
+
onNodesChange?: (changes: NodeChange[], meta: ChangeMeta) => void;
|
|
605
|
+
/** Change batches the graph wants applied to your edges (controlled mode). See {@link onNodesChange}. */
|
|
606
|
+
onEdgesChange?: (changes: EdgeChange[], meta: ChangeMeta) => void;
|
|
607
|
+
/**
|
|
608
|
+
* Initial pan/zoom. `x`/`y` are the screen-space offset in pixels and `zoom`
|
|
609
|
+
* is the scale factor. Defaults to `{ x: 0, y: 0, zoom: 1 }` (origin, 1:1).
|
|
610
|
+
*/
|
|
611
|
+
defaultViewport?: Viewport;
|
|
612
|
+
/**
|
|
613
|
+
* Maps a node's `type` to the React component that renders it. A node whose
|
|
614
|
+
* `type` has no entry here (or no `type` at all) falls back to
|
|
615
|
+
* {@link DefaultNode}. Defaults to `{}`.
|
|
616
|
+
*/
|
|
617
|
+
nodeTypes?: NodeTypes;
|
|
618
|
+
/**
|
|
619
|
+
* Registry of custom edge shapes, keyed by `edge.type`. Each is a pure geometry
|
|
620
|
+
* function (see {@link EdgePathFn}) so edges stay canvas/GPU-renderable. Merged
|
|
621
|
+
* over the built-ins `bezier` (default), `smoothstep`, `step`, and `straight`.
|
|
622
|
+
*/
|
|
623
|
+
edgeTypes?: EdgeTypes;
|
|
624
|
+
/** Defaults merged into every edge that doesn't set the field (type, style, markers…). */
|
|
625
|
+
defaultEdgeOptions?: DefaultEdgeOptions;
|
|
626
|
+
/** Accessible name for the graph surface (`aria-label` on the pane). Defaults to "Node graph". */
|
|
627
|
+
ariaLabel?: string;
|
|
628
|
+
/**
|
|
629
|
+
* Backend factory for the edge layers — swap Canvas2D for another
|
|
630
|
+
* {@link EdgeRenderer}. Defaults to {@link canvas2DEdgeRenderer}. Pass a stable/memoized
|
|
631
|
+
* reference; a new identity re-creates the renderers.
|
|
632
|
+
*/
|
|
633
|
+
renderer?: EdgeRendererFactory;
|
|
634
|
+
/**
|
|
635
|
+
* Lower bound on `viewport.zoom`. All zooming (wheel, controls, `fitView`) is
|
|
636
|
+
* clamped to this. Defaults to `0.2` (zoomed out to 20%).
|
|
637
|
+
*/
|
|
638
|
+
minZoom?: number;
|
|
639
|
+
/**
|
|
640
|
+
* Upper bound on `viewport.zoom`. All zooming is clamped to this. Defaults to
|
|
641
|
+
* `2.5` (zoomed in to 250%).
|
|
642
|
+
*/
|
|
643
|
+
maxZoom?: number;
|
|
644
|
+
/**
|
|
645
|
+
* Spacing in world units between background grid dots. The grid scales with
|
|
646
|
+
* zoom, so this is measured at `zoom === 1`. Defaults to `24`.
|
|
647
|
+
*/
|
|
648
|
+
gridGap?: number;
|
|
649
|
+
/**
|
|
650
|
+
* Snap dragged nodes to a `[x, y]` world-unit grid. A `0` axis is left free.
|
|
651
|
+
* Omit (default) for free positioning. Independent of {@link gridGap} (the
|
|
652
|
+
* visual dot grid) — pass the same value to snap to the dots you see.
|
|
653
|
+
*/
|
|
654
|
+
snapGrid?: [number, number];
|
|
655
|
+
/**
|
|
656
|
+
* While dragging a single node, show alignment guides and snap its edges/center
|
|
657
|
+
* to nearby nodes' edges/centers. Defaults to `false`.
|
|
658
|
+
*/
|
|
659
|
+
alignmentGuides?: boolean;
|
|
660
|
+
/**
|
|
661
|
+
* Placement policy for anchor chrome — the grab dots and stray perimeter
|
|
662
|
+
* handles rivet renders for registered anchors (see {@link Anchor}). Omitted
|
|
663
|
+
* fields fall back to the defaults.
|
|
664
|
+
*/
|
|
665
|
+
anchorOptions?: AnchorOptions;
|
|
666
|
+
/**
|
|
667
|
+
* The other people in this document — the presence roster. Identity (name,
|
|
668
|
+
* colour) plus the slow fields: what each peer has selected, and what they're
|
|
669
|
+
* holding under a gesture. Rivet paints them: a cursor per peer, an outline
|
|
670
|
+
* around what they've selected, and the nodes they're moving drawn where they
|
|
671
|
+
* currently have them.
|
|
672
|
+
*
|
|
673
|
+
* Peer cursors move far faster than React should re-render, so the roster
|
|
674
|
+
* carries only a seed for them — feed live cursors and drag boxes through
|
|
675
|
+
* {@link RivetInstance.setPeerCursor} / `setPeerNodeTransform` instead.
|
|
676
|
+
*
|
|
677
|
+
* Presence is ephemeral: none of it reaches the graph, the change stream, or
|
|
678
|
+
* history. Dropping a peer from the array is how they leave.
|
|
679
|
+
*/
|
|
680
|
+
peers?: Peer[];
|
|
681
|
+
/**
|
|
682
|
+
* Called with this client's presence — cursor (in world coordinates),
|
|
683
|
+
* selection, and held nodes — as a whole snapshot, ready to broadcast.
|
|
684
|
+
*
|
|
685
|
+
* Snapshots are idempotent, so a dropped or duplicated one costs nothing and
|
|
686
|
+
* a reconnecting peer is instantly correct. Cursor movement is coalesced to
|
|
687
|
+
* `presenceOptions.throttleMs`; selection and gesture changes are published
|
|
688
|
+
* immediately.
|
|
689
|
+
*/
|
|
690
|
+
onLocalPresence?: (presence: LocalPresence) => void;
|
|
691
|
+
/** Presence policy — outbound throttle, and whether rivet paints peer cursors. */
|
|
692
|
+
presenceOptions?: PresenceOptions;
|
|
693
|
+
/**
|
|
694
|
+
* Nodes a peer has claimed, as `nodeId -> peerId`. Locks are policy where
|
|
695
|
+
* {@link peers} is description: rivet paints a locked node in its holder's
|
|
696
|
+
* colour *and* refuses to act on it.
|
|
697
|
+
*
|
|
698
|
+
* By default it refuses selection, dragging, resizing and deletion, and
|
|
699
|
+
* allows connections — a lock claims the node, not the graph around it.
|
|
700
|
+
* {@link canInteractWithLocked} replaces that policy.
|
|
701
|
+
*
|
|
702
|
+
* Lifetime is yours: rivet never takes or releases a lock, it only reads the
|
|
703
|
+
* table. Take one in {@link onNodeDragStart} and drop it in
|
|
704
|
+
* {@link onNodeDragEnd} for drag-scoped locks, or hold through deselection
|
|
705
|
+
* for something stickier. Like presence, none of this reaches the graph, the
|
|
706
|
+
* change stream, or history.
|
|
707
|
+
*/
|
|
708
|
+
lockedNodes?: Record<NodeId, string>;
|
|
709
|
+
/**
|
|
710
|
+
* Decide what this client may do to a locked node, per attempt. Return `true`
|
|
711
|
+
* to allow the intent, `false` to refuse it.
|
|
712
|
+
*
|
|
713
|
+
* A handler owns the whole policy — rivet's defaults are replaced, not
|
|
714
|
+
* consulted — so answer every intent you care about:
|
|
715
|
+
*
|
|
716
|
+
* ```tsx
|
|
717
|
+
* // locked nodes stay inspectable, but nothing may change them
|
|
718
|
+
* canInteractWithLocked={({ intent }) => intent === "select" || intent === "connect"}
|
|
719
|
+
* ```
|
|
720
|
+
*
|
|
721
|
+
* Called on the input path (every marquee frame, every mover), so keep it
|
|
722
|
+
* cheap and free of side effects.
|
|
723
|
+
*/
|
|
724
|
+
canInteractWithLocked?: CanInteractWithLocked;
|
|
725
|
+
/**
|
|
726
|
+
* Called when a lock for a peer arrives on a node this client is already
|
|
727
|
+
* holding — two clients started before either lock reached the other.
|
|
728
|
+
*
|
|
729
|
+
* rivet reports it and keeps going: the running gesture stays authoritative
|
|
730
|
+
* over its geometry, because only your transport knows which client actually
|
|
731
|
+
* lost the race. To yield, call {@link RivetInstance.releaseNodeGesture} —
|
|
732
|
+
* the gesture stops writing and tears down without committing.
|
|
733
|
+
*/
|
|
734
|
+
onNodeLockConflict?: (event: NodeLockConflictEvent) => void;
|
|
735
|
+
/**
|
|
736
|
+
* Which mouse buttons pan when dragging the pane: `true` = left only, `false` =
|
|
737
|
+
* none, or a list of `MouseEvent.button` codes (`0` left, `1` middle, `2` right).
|
|
738
|
+
* e.g. `[1, 2]` pans with middle/right and frees left for selection. Defaults to
|
|
739
|
+
* `true`. Pass a stable reference; a new array identity re-binds the listeners.
|
|
740
|
+
*/
|
|
741
|
+
panOnDrag?: boolean | number[];
|
|
742
|
+
/**
|
|
743
|
+
* Draw a selection marquee on a plain left-drag instead of panning. Pair with
|
|
744
|
+
* `panOnDrag={[1, 2]}` so left selects and middle/right pan. A marquee that
|
|
745
|
+
* ends over nodes leaves a persistent selection box around them — drag it to
|
|
746
|
+
* move the whole selection; a click elsewhere or Escape dismisses it.
|
|
747
|
+
* Defaults to `false`.
|
|
748
|
+
*/
|
|
749
|
+
selectionOnDrag?: boolean;
|
|
750
|
+
/**
|
|
751
|
+
* Key(s) that force a marquee on a left-drag when held (e.g. `"Shift"`, `"Meta"`,
|
|
752
|
+
* or `["Shift", "Meta"]`). `null` disables. Defaults to `"Shift"`.
|
|
753
|
+
*/
|
|
754
|
+
selectionKeyCode?: string | string[] | null;
|
|
755
|
+
/**
|
|
756
|
+
* Key(s) that make a click or marquee **add to** the selection instead of
|
|
757
|
+
* replacing it. Defaults to `["Meta", "Control", "Shift"]`. Use modifier keys
|
|
758
|
+
* (`Shift`/`Meta`/`Control`/`Alt`) — other keys only resolve during a pane drag.
|
|
759
|
+
*/
|
|
760
|
+
multiSelectionKeyCode?: string | string[];
|
|
761
|
+
/**
|
|
762
|
+
* Pan the viewport on wheel / two-finger trackpad scroll instead of zooming.
|
|
763
|
+
* A pinch gesture (reported by the browser as ctrl+wheel) still zooms. When
|
|
764
|
+
* `false` (default), scrolling zooms toward the cursor.
|
|
765
|
+
*/
|
|
766
|
+
scrollToPan?: boolean;
|
|
767
|
+
/**
|
|
768
|
+
* Wheel/pinch zoom sensitivity — larger zooms faster per scroll delta.
|
|
769
|
+
* Defaults to `0.0015`. Try `~0.003` for faster trackpad pinch zoom.
|
|
770
|
+
*/
|
|
771
|
+
zoomSpeed?: number;
|
|
772
|
+
/**
|
|
773
|
+
* Swimlanes drawn behind the graph — a decorative background of labeled lane
|
|
774
|
+
* groups (like planout's swimlanes). Not nodes or edges; just layout regions.
|
|
775
|
+
* Omit for no swimlanes.
|
|
776
|
+
*/
|
|
777
|
+
swimlane?: SwimlaneGroup[];
|
|
778
|
+
/**
|
|
779
|
+
* Bind node dragging to the swimlanes: on drop each node snaps fully inside
|
|
780
|
+
* one lane (honoring {@link swimlaneMargin}) and is reassigned to the lane it
|
|
781
|
+
* lands in via {@link RivetNode.laneId}. Defaults to `true` when
|
|
782
|
+
* {@link swimlane} is provided, `false` otherwise. Ignored with no swimlanes.
|
|
783
|
+
*/
|
|
784
|
+
clampToSwimlane?: boolean;
|
|
785
|
+
/**
|
|
786
|
+
* Inner clearance kept between a clamped node and its lane's edges. A number
|
|
787
|
+
* applies to all sides; per-side values override it. Defaults to `16`.
|
|
788
|
+
*/
|
|
789
|
+
swimlaneMargin?: number | SwimlaneMargin;
|
|
790
|
+
/** Screen height of the sticky group header band, in px. Defaults to `32`. */
|
|
791
|
+
swimlaneHeaderHeight?: number;
|
|
792
|
+
/**
|
|
793
|
+
* Show a resize handle on each lane's bottom edge to change its height.
|
|
794
|
+
* Defaults to `true` when {@link swimlane} is provided.
|
|
795
|
+
*/
|
|
796
|
+
swimlaneResizable?: boolean;
|
|
797
|
+
/**
|
|
798
|
+
* Fraction of the last lane's height that must stay visible when scrolled to
|
|
799
|
+
* the bottom — the down-scroll stop. `0.5` (default) keeps half of it in view.
|
|
800
|
+
* Only applies when {@link clampToSwimlane} is on.
|
|
801
|
+
*/
|
|
802
|
+
swimlaneBottomReveal?: number;
|
|
803
|
+
/** Render custom content for a group's sticky header (replaces the default). */
|
|
804
|
+
renderSwimlaneHeader?: (props: SwimlaneHeaderProps) => ReactNode;
|
|
805
|
+
/** Render custom content for a lane's sticky label (replaces the default). */
|
|
806
|
+
renderSwimlaneLabel?: (props: SwimlaneLabelProps) => ReactNode;
|
|
807
|
+
/**
|
|
808
|
+
* Called when a lane's height changes — from a resize drag or from auto-fit
|
|
809
|
+
* growing it to contain a node that grew. The graph owns lane heights, so this
|
|
810
|
+
* is a notification (persist it if you like), not a request to update state.
|
|
811
|
+
*/
|
|
812
|
+
onSwimlaneSizeChange?: (change: SwimlaneSizeChange) => void;
|
|
813
|
+
/**
|
|
814
|
+
* Right-click on empty canvas (not over a node or swimlane chrome). The second
|
|
815
|
+
* argument carries the resolved graph context — the world position and the lane
|
|
816
|
+
* under the cursor — so you don't have to re-derive them.
|
|
817
|
+
*/
|
|
818
|
+
onPaneContextMenu?: (event: MouseEvent, context: PaneContextMenuContext) => void;
|
|
819
|
+
/** Right-click on a lane's sticky label. */
|
|
820
|
+
onSwimlaneHeaderContextMenu?: (laneId: string, event: MouseEvent) => void;
|
|
821
|
+
/** Right-click on a group's sticky header. */
|
|
822
|
+
onSwimlaneGroupHeaderContextMenu?: (groupId: string, event: MouseEvent) => void;
|
|
823
|
+
/** Called when a dragged node is reassigned to a different lane. */
|
|
824
|
+
onLaneChange?: (change: LaneChange) => void;
|
|
825
|
+
/** Veto a proposed connection; return false to reject it. Applies to reconnection too. */
|
|
826
|
+
isValidConnection?: (connection: Connection) => boolean;
|
|
827
|
+
/**
|
|
828
|
+
* Rewrite a validated connection before it commits — normalize handle ids
|
|
829
|
+
* (e.g. redirect an in-content grab handle to its canonical perimeter
|
|
830
|
+
* handle), or force direction conventions. Returning `null` cancels the
|
|
831
|
+
* drop. Applies to new connections and reconnections; `isValidConnection`
|
|
832
|
+
* sees the raw connection, `onConnect`/`onReconnect` see the mapped one.
|
|
833
|
+
*/
|
|
834
|
+
mapConnection?: (connection: Connection) => Connection | null;
|
|
835
|
+
/** Called after a valid connection is made (the edge is already added). */
|
|
836
|
+
onConnect?: (connection: Connection) => void;
|
|
837
|
+
/**
|
|
838
|
+
* Allow reconnecting edges by dragging an endpoint onto a new handle. Per-edge
|
|
839
|
+
* `reconnectable` overrides this. Defaults to `false`.
|
|
840
|
+
*/
|
|
841
|
+
edgesReconnectable?: boolean;
|
|
842
|
+
/**
|
|
843
|
+
* When edge endpoints re-side to face the peer node. `"manual"` (default)
|
|
844
|
+
* never rewrites a chosen handle; `"on-move"` re-sides both ends of a moved
|
|
845
|
+
* node's edges when the move commits — in the same batch as the move, so one
|
|
846
|
+
* undo restores position and handles together. `"live"` additionally renders
|
|
847
|
+
* a dragging node's edges as if their ends were auto — re-siding per frame
|
|
848
|
+
* to face each other, with hysteresis so near-diagonal positions don't
|
|
849
|
+
* flicker — and commits the displayed sides on drop, inside the move's
|
|
850
|
+
* history step; nothing is persisted mid-gesture. Only committed position
|
|
851
|
+
* changes trigger a rewrite: data replaces and dimension changes never
|
|
852
|
+
* re-side, and a freshly created or reconnected edge keeps exactly the
|
|
853
|
+
* handles the user grabbed or dropped on. Anchor and bare-side ends rewrite
|
|
854
|
+
* their side directly; plain handles re-side to a registered handle of a
|
|
855
|
+
* compatible type on the facing side, or stay pinned when the node has none
|
|
856
|
+
* there. Independent of the policy, an end with *no* side — a missing
|
|
857
|
+
* handle, or an `anchorAutoHandleId` anchor end — always floats: the
|
|
858
|
+
* renderer resolves its facing side per frame and never writes it back.
|
|
859
|
+
*/
|
|
860
|
+
edgeAlignment?: EdgeAlignment;
|
|
861
|
+
/** Called when an endpoint drag re-points an edge (the edge is already updated). */
|
|
862
|
+
onReconnect?: (edge: RivetEdge, connection: Connection) => void;
|
|
863
|
+
/** Called when an endpoint reconnection drag starts. */
|
|
864
|
+
onReconnectStart?: (edge: RivetEdge) => void;
|
|
865
|
+
/** Called when an endpoint reconnection drag ends (committed or cancelled). */
|
|
866
|
+
onReconnectEnd?: (edge: RivetEdge) => void;
|
|
867
|
+
/**
|
|
868
|
+
* Called when a local gesture takes hold of one or more nodes — a pointer
|
|
869
|
+
* drag, a resize, or a keyboard grab. While it's open, those nodes' geometry
|
|
870
|
+
* belongs to this client: remote `position`/`dimensions` writes for them are
|
|
871
|
+
* dropped, and controlled props can't stomp the live box.
|
|
872
|
+
*
|
|
873
|
+
* In a shared document this is where you acquire a lock. It's paired with
|
|
874
|
+
* {@link onNodeDragEnd} — every start gets exactly one end, including a
|
|
875
|
+
* cancelled keyboard grab.
|
|
876
|
+
*/
|
|
877
|
+
onNodeDragStart?: (event: NodeGestureEvent) => void;
|
|
878
|
+
/** Called when a gesture releases its nodes. See {@link onNodeDragStart}. */
|
|
879
|
+
onNodeDragEnd?: (event: NodeGestureEvent) => void;
|
|
880
|
+
/** Called whenever the selected nodes and/or edges change. */
|
|
881
|
+
onSelectionChange?: (selection: RivetSelection) => void;
|
|
882
|
+
/**
|
|
883
|
+
* Called when keyboard focus moves to a node (or leaves the graph — `null`).
|
|
884
|
+
* The same state is available inside `<Rivet>` via {@link useRivetFocusedNode}.
|
|
885
|
+
* Rivet draws no focus ring; use this (or the wrapper's `:focus-visible`) to
|
|
886
|
+
* render your own indicator.
|
|
887
|
+
*/
|
|
888
|
+
onFocusChange?: (id: NodeId | null) => void;
|
|
889
|
+
className?: string;
|
|
890
|
+
style?: CSSProperties;
|
|
891
|
+
children?: ReactNode;
|
|
892
|
+
};
|
|
893
|
+
/**
|
|
894
|
+
* The graph surface. Stacks a background grid canvas, an edge canvas, and a DOM
|
|
895
|
+
* node layer — all driven by one shared viewport (see {@link useRivetRuntime}).
|
|
896
|
+
*/
|
|
897
|
+
declare function Rivet({ defaultNodes, defaultEdges, nodes: controlledNodes, edges: controlledEdges, onNodesChange, onEdgesChange, defaultViewport, nodeTypes, edgeTypes, defaultEdgeOptions, ariaLabel, renderer, minZoom, maxZoom, gridGap, snapGrid, alignmentGuides, anchorOptions, peers, onLocalPresence, presenceOptions, lockedNodes, canInteractWithLocked, onNodeLockConflict, 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, onNodeDragStart, onNodeDragEnd, onSelectionChange, onFocusChange, className, style, children, }: RivetProps): React.ReactElement;
|
|
898
|
+
|
|
725
899
|
type RivetContextValue = {
|
|
726
900
|
store: RivetStore;
|
|
727
901
|
nodeTypes: NodeTypes;
|
|
@@ -905,6 +1079,25 @@ type RivetInstance<TNodeData = unknown, TEdgeData = unknown> = RivetControls & {
|
|
|
905
1079
|
nodes?: NodeId[];
|
|
906
1080
|
edges?: EdgeId[];
|
|
907
1081
|
}) => void;
|
|
1082
|
+
/**
|
|
1083
|
+
* Apply a change batch that already happened elsewhere — a peer's edit off
|
|
1084
|
+
* your transport. The graph updates and repaints, then re-emits the batch to
|
|
1085
|
+
* `onNodesChange`/`onEdgesChange` tagged `"remote"`, so a controlled owner
|
|
1086
|
+
* keeps its state in step through the one path it already has.
|
|
1087
|
+
*
|
|
1088
|
+
* Remote batches never create an undo step; in a shared document, undoing a
|
|
1089
|
+
* peer's edit would silently revert work you don't own.
|
|
1090
|
+
*
|
|
1091
|
+
* ```ts
|
|
1092
|
+
* connection.onNodeMoved((row) => {
|
|
1093
|
+
* if (row.caller === me) return // your own echo — already applied
|
|
1094
|
+
* rivet.applyRemote({
|
|
1095
|
+
* nodes: [{ type: "position", id: row.id, position: row.position }],
|
|
1096
|
+
* })
|
|
1097
|
+
* })
|
|
1098
|
+
* ```
|
|
1099
|
+
*/
|
|
1100
|
+
applyRemote: (changes: RemoteChanges) => void;
|
|
908
1101
|
/**
|
|
909
1102
|
* Bind an anchor — a connectable point — to a DOM element inside a node.
|
|
910
1103
|
* The imperative core behind `<Anchor>`, for consumers whose content DOM is
|
|
@@ -926,6 +1119,40 @@ type RivetInstance<TNodeData = unknown, TEdgeData = unknown> = RivetControls & {
|
|
|
926
1119
|
* load) — rivet can't observe those.
|
|
927
1120
|
*/
|
|
928
1121
|
remeasureAnchors: (nodeId: NodeId) => void;
|
|
1122
|
+
/**
|
|
1123
|
+
* Move a peer's cursor, in **world** coordinates (peers pan and zoom
|
|
1124
|
+
* independently, so a screen point means nothing to them). `null` parks it.
|
|
1125
|
+
*
|
|
1126
|
+
* The presence hot path: it paints on the next frame without going through
|
|
1127
|
+
* React, so call it as fast as your channel delivers. A peer the `peers`
|
|
1128
|
+
* roster hasn't mentioned yet still gets a cursor — a frame that beats the
|
|
1129
|
+
* join event shouldn't blink.
|
|
1130
|
+
*/
|
|
1131
|
+
setPeerCursor: (peerId: string, point: Vec2 | null) => void;
|
|
1132
|
+
/**
|
|
1133
|
+
* Show a node where a peer currently has it, in world space — their drag,
|
|
1134
|
+
* mid-flight. The node renders, hit-tests and wires at that box until their
|
|
1135
|
+
* change lands through {@link applyRemote}; the graph itself is untouched.
|
|
1136
|
+
* Pass `null` on their drop.
|
|
1137
|
+
*/
|
|
1138
|
+
setPeerNodeTransform: (peerId: string, nodeId: NodeId, rect: Rect | null) => void;
|
|
1139
|
+
/** Forget a peer entirely — cursor, held nodes and all. For a disconnect. */
|
|
1140
|
+
removePeer: (peerId: string) => void;
|
|
1141
|
+
/**
|
|
1142
|
+
* Give up a gesture's hold on its nodes without committing — the yield lever
|
|
1143
|
+
* for `onNodeLockConflict`, when your transport says this client lost the
|
|
1144
|
+
* race for a node it's already dragging.
|
|
1145
|
+
*
|
|
1146
|
+
* The running gesture notices on its next frame, stops writing, and tears
|
|
1147
|
+
* itself down; the nodes stay where they are and the holder's positions land
|
|
1148
|
+
* normally from then on. `onNodeDragEnd` fires as it would on a drop, so a
|
|
1149
|
+
* consumer's own lock release runs unchanged. Pass the conflict event's
|
|
1150
|
+
* `ids` to release a whole group.
|
|
1151
|
+
*
|
|
1152
|
+
* Doing nothing is also a valid answer: without this call the gesture keeps
|
|
1153
|
+
* its nodes until the pointer lifts.
|
|
1154
|
+
*/
|
|
1155
|
+
releaseNodeGesture: (id: NodeId, ids?: NodeId[]) => void;
|
|
929
1156
|
/** Copy nodes (default: the current selection) to the in-memory clipboard. */
|
|
930
1157
|
copy: (ids?: NodeId[]) => void;
|
|
931
1158
|
/** Copy then delete nodes (default: the current selection). */
|
|
@@ -1028,4 +1255,4 @@ declare function rectsIntersect(a: Rect, b: Rect): boolean;
|
|
|
1028
1255
|
|
|
1029
1256
|
declare const VERSION = "0.0.0";
|
|
1030
1257
|
|
|
1031
|
-
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, resolveFacingSideAmong, screenToWorld, serializeGraph, snapToGrid, useRivet, useRivetContext, useRivetControls, useRivetFocusedNode, useRivetHistory, useRivetViewport, viewportToCss, visibleWorldRect, worldToScreen, zoomAt };
|
|
1258
|
+
export { AlignmentGuide, BUILTIN_EDGE_TYPES, BUILTIN_NODE_TYPES, CanInteractWithLocked, Canvas2DEdgeRenderer, ChangeMeta, ChangeOrigin, 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, LockRegistry, MiniMap, type MiniMapProps, NodeChange, NodeGestureEvent, NodeId, NodeLockConflictEvent, NodeProps, NodeResizer, type NodeResizerProps, NodeTypes, type PaneContextMenuContext, PendingConnection, ReconnectDelegate, Rect, type RemoteChanges, 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, resolveFacingSideAmong, screenToWorld, serializeGraph, snapToGrid, useRivet, useRivetContext, useRivetControls, useRivetFocusedNode, useRivetHistory, useRivetViewport, viewportToCss, visibleWorldRect, worldToScreen, zoomAt };
|