@kolosal-ai/rivet 0.2.0 → 0.4.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/dist/anchor/index.d.ts +31 -4
- package/dist/anchor/index.js +22 -6
- package/dist/anchor/index.js.map +1 -1
- package/dist/chunk-TT2N7KWU.js +676 -0
- package/dist/chunk-TT2N7KWU.js.map +1 -0
- package/dist/{chunk-AXT35ZJV.js → chunk-W5HBJ4VF.js} +25 -3
- package/dist/chunk-W5HBJ4VF.js.map +1 -0
- package/dist/index.d.ts +159 -24
- package/dist/index.js +644 -149
- package/dist/index.js.map +1 -1
- package/dist/presence/index.d.ts +158 -4
- package/dist/presence/index.js +24 -2
- package/dist/presence/index.js.map +1 -1
- package/dist/{registry-t5ldbviG.d.ts → registry-Z_oiPyjm.d.ts} +43 -2
- package/dist/svg/index.d.ts +18 -3
- package/dist/svg/index.js +5 -2
- package/dist/svg/index.js.map +1 -1
- package/dist/swimlane/index.d.ts +2 -2
- package/dist/{types-CQqnm4yW.d.ts → types-D3aldmsO.d.ts} +27 -1
- package/dist/use-node-lock-CbS59CRE.d.ts +716 -0
- package/package.json +1 -1
- package/dist/chunk-AXT35ZJV.js.map +0 -1
- package/dist/chunk-RG5ALD3X.js +0 -306
- package/dist/chunk-RG5ALD3X.js.map +0 -1
- package/dist/use-node-lock-Csg9pUeC.d.ts +0 -323
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { R as Rect, V as Vec2, A as AlignmentGuide,
|
|
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-
|
|
1
|
+
import { R as Rect, V as Vec2, A as AlignmentGuide, c as EdgeChange, d as RivetEdge, a as NodeChange, e as RivetNode, N as NodeId, f as NodeProps, g as NodeTypes, b as HandleType, H as HandlePosition, S as Size, h as ChangeOrigin, E 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-D3aldmsO.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-D3aldmsO.js';
|
|
3
3
|
import { ReactNode, CSSProperties, MouseEvent, RefObject } from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
export { L as LOCK_DEFAULT_REFUSED,
|
|
4
|
+
import { e as AnchorRecord, g as AnchorRegistrationOptions, A as AnchorRef, c as AnchorOptions, R as ResolvedAnchorOptions, f as AnchorRegistration } from './registry-Z_oiPyjm.js';
|
|
5
|
+
import { b as PresenceTargetKey, p as PresenceRegistry, h as LockRegistry, k as Peer, e as LocalPresence, o as PresenceOptions, C as CanInteractWithLocked, l as PeerConnection } from './use-node-lock-CbS59CRE.js';
|
|
6
|
+
export { L as LOCK_DEFAULT_REFUSED, f as LockIntent, g as LockInteraction, i as LockTarget, N as NodeLock, y as useNodeLock, z as useNodeLockAllows } from './use-node-lock-CbS59CRE.js';
|
|
7
7
|
import { ResolvedLane, ViewportElements, ResolvedSwimlaneGroup, ResolvedMargin } from './swimlane/index.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -319,6 +319,19 @@ type RivetStore = {
|
|
|
319
319
|
setViewportClamp: (clamp: ViewportClamp | null) => void;
|
|
320
320
|
subscribeFrame: (listener: () => void) => () => void;
|
|
321
321
|
notifyFrame: () => void;
|
|
322
|
+
/**
|
|
323
|
+
* Post-frame channel for peer cursors alone. Fires after every frame that
|
|
324
|
+
* repainted them — the cursor-only frames a pointer move schedules, *and*
|
|
325
|
+
* full frames, which own every layer.
|
|
326
|
+
*
|
|
327
|
+
* Its own channel because cursor frames are the ones that arrive at pointer
|
|
328
|
+
* rate for every peer: chrome that follows a cursor needs all of them, while
|
|
329
|
+
* everything else on {@link subscribeFrame} would be woken up for nothing.
|
|
330
|
+
* Read positions off `presence.getPeers()` — they're the interpolated ones,
|
|
331
|
+
* already stepped for this frame.
|
|
332
|
+
*/
|
|
333
|
+
subscribeCursorFrame: (listener: () => void) => () => void;
|
|
334
|
+
notifyCursorFrame: () => void;
|
|
322
335
|
/** Move a node. `commit` re-renders just that node; skip it during drag. */
|
|
323
336
|
moveNode: (id: NodeId, position: Vec2, commit: boolean) => void;
|
|
324
337
|
setNodeSize: (id: NodeId, size: Size) => void;
|
|
@@ -400,12 +413,17 @@ type RivetStore = {
|
|
|
400
413
|
*/
|
|
401
414
|
endNodeGesture: (id: NodeId, ids?: NodeId[]) => void;
|
|
402
415
|
/**
|
|
403
|
-
* Publish the lock table (the `lockedNodes` prop),
|
|
404
|
-
*
|
|
405
|
-
* {@link GestureHandlers.conflict}. The gesture
|
|
406
|
-
* {@link NodeLockConflictEvent} for why rivet
|
|
416
|
+
* Publish the lock table (the `lockedNodes` prop), keyed by
|
|
417
|
+
* {@link PresenceTargetKey}, and report any node it claims that a local
|
|
418
|
+
* gesture is already holding to {@link GestureHandlers.conflict}. The gesture
|
|
419
|
+
* itself is left running — see {@link NodeLockConflictEvent} for why rivet
|
|
420
|
+
* doesn't pick the loser.
|
|
421
|
+
*
|
|
422
|
+
* Only node gestures are scanned, because only nodes are held: an edge or an
|
|
423
|
+
* anchor has no gesture to conflict with, so a lock on either is simply in
|
|
424
|
+
* force from the moment it arrives.
|
|
407
425
|
*/
|
|
408
|
-
setLockedNodes: (locks: Record<
|
|
426
|
+
setLockedNodes: (locks: Record<PresenceTargetKey, string> | undefined) => void;
|
|
409
427
|
/**
|
|
410
428
|
* True while a local gesture holds this node. Held geometry is exclusively
|
|
411
429
|
* this client's: {@link applyRemote} drops incoming `position`/`dimensions`
|
|
@@ -440,6 +458,11 @@ type RivetStore = {
|
|
|
440
458
|
getSelectedNodes: () => NodeId[];
|
|
441
459
|
/** True if the node is part of the current selection. */
|
|
442
460
|
isNodeSelected: (id: NodeId) => boolean;
|
|
461
|
+
/**
|
|
462
|
+
* The selected edge, if any — edge selection is single. The id alone, for
|
|
463
|
+
* callers that would otherwise build {@link getSelection}'s records to read it.
|
|
464
|
+
*/
|
|
465
|
+
getSelectedEdgeId: () => EdgeId | null;
|
|
443
466
|
/** The current selection (nodes + edges) as full records. */
|
|
444
467
|
getSelection: () => RivetSelection;
|
|
445
468
|
/** Subscribe to selection changes (nodes and/or edges). */
|
|
@@ -506,6 +529,14 @@ type RivetStore = {
|
|
|
506
529
|
subscribeHistory: (listener: () => void) => () => void;
|
|
507
530
|
getEdgeLabelAnchors: () => Map<EdgeId, Vec2>;
|
|
508
531
|
setEdgeLabelAnchors: (anchors: Map<EdgeId, Vec2>) => void;
|
|
532
|
+
/**
|
|
533
|
+
* Screen-space anchor points for the edges peers have claimed, from the same
|
|
534
|
+
* renderer pass — a point on each drawn path, which is the one thing a DOM
|
|
535
|
+
* outline layer can't work out for itself. Empty unless something is claimed
|
|
536
|
+
* and DOM outline chrome is mounted.
|
|
537
|
+
*/
|
|
538
|
+
getPeerEdgeAnchors: () => ReadonlyMap<EdgeId, Vec2>;
|
|
539
|
+
setPeerEdgeAnchors: (anchors: ReadonlyMap<EdgeId, Vec2>) => void;
|
|
509
540
|
/** Alignment/snap guides to draw for the current drag (world space). Empty when idle. */
|
|
510
541
|
getAlignmentGuides: () => AlignmentGuide[];
|
|
511
542
|
setAlignmentGuides: (guides: AlignmentGuide[]) => void;
|
|
@@ -550,15 +581,40 @@ type RivetStore = {
|
|
|
550
581
|
getNodeAnchors: (nodeId: NodeId) => AnchorRecord[];
|
|
551
582
|
getNodeAnchorsVersion: (nodeId: NodeId) => number;
|
|
552
583
|
subscribeNodeAnchors: (nodeId: NodeId, listener: () => void) => () => void;
|
|
584
|
+
/** The selected anchors. A cached snapshot — identity changes with the data. */
|
|
585
|
+
getSelectedAnchors: () => readonly AnchorRef[];
|
|
586
|
+
/**
|
|
587
|
+
* Replace the anchor selection. Selecting any anchor clears the node and edge
|
|
588
|
+
* selection: one selection concept, so delete and the chrome never describe
|
|
589
|
+
* two claims at once.
|
|
590
|
+
*/
|
|
591
|
+
setSelectedAnchors: (refs: readonly AnchorRef[]) => void;
|
|
592
|
+
isAnchorSelected: (nodeId: NodeId, anchorId: string) => boolean;
|
|
593
|
+
subscribeAnchorSelection: (listener: () => void) => () => void;
|
|
553
594
|
getEdgesVersion: () => number;
|
|
554
595
|
subscribeEdges: (listener: () => void) => () => void;
|
|
555
596
|
getPending: () => PendingConnection | null;
|
|
556
597
|
beginConnection: (pending: PendingConnection) => void;
|
|
557
598
|
updateConnection: (to: Vec2, toPosition?: HandlePosition) => void;
|
|
558
599
|
endConnection: () => void;
|
|
600
|
+
/**
|
|
601
|
+
* The local pending connection changing — started, moved, dropped. Its own
|
|
602
|
+
* channel because presence has to publish it: the drag lives entirely in the
|
|
603
|
+
* canvas otherwise, and nothing else would tell an outbound tracker that a
|
|
604
|
+
* wire was let go of (a drop that moves the pointer no further would leave a
|
|
605
|
+
* peer's copy hanging there).
|
|
606
|
+
*/
|
|
607
|
+
subscribeConnection: (listener: () => void) => () => void;
|
|
559
608
|
/** Ask the runtime to schedule a canvas frame. */
|
|
560
609
|
requestRender: () => void;
|
|
561
610
|
bindRenderRequester: (fn: () => void) => void;
|
|
611
|
+
/**
|
|
612
|
+
* Ask the runtime to repaint the peer-cursor layer only — everything else on
|
|
613
|
+
* screen keeps last frame's pixels. Degrades to {@link requestRender} while
|
|
614
|
+
* no runtime has claimed the layer, so a caller never has to check.
|
|
615
|
+
*/
|
|
616
|
+
requestCursorRender: () => void;
|
|
617
|
+
bindCursorRenderRequester: (fn: (() => void) | null) => void;
|
|
562
618
|
};
|
|
563
619
|
/** Create a graph store. The public entry point; the class is an implementation detail. */
|
|
564
620
|
declare function createRivetStore(init: RivetStoreInit): RivetStore;
|
|
@@ -665,10 +721,14 @@ type RivetProps = {
|
|
|
665
721
|
anchorOptions?: AnchorOptions;
|
|
666
722
|
/**
|
|
667
723
|
* The other people in this document — the presence roster. Identity (name,
|
|
668
|
-
* colour) plus the slow fields: what each peer has selected, and what
|
|
669
|
-
* holding under a gesture. Rivet paints them: a cursor per peer, an
|
|
670
|
-
* around what they've selected, and the nodes they're moving drawn
|
|
671
|
-
* currently have them.
|
|
724
|
+
* colour, `data`) plus the slow fields: what each peer has selected, and what
|
|
725
|
+
* they're holding under a gesture. Rivet paints them: a cursor per peer, an
|
|
726
|
+
* outline around what they've selected, and the nodes they're moving drawn
|
|
727
|
+
* where they currently have them.
|
|
728
|
+
*
|
|
729
|
+
* Claims are node ids, or `PresenceTarget`s for an edge or an anchor. Only
|
|
730
|
+
* nodes are painted today — the rest travels and is readable through
|
|
731
|
+
* {@link usePeers}, which is what a consumer rendering its own chrome needs.
|
|
672
732
|
*
|
|
673
733
|
* Peer cursors move far faster than React should re-render, so the roster
|
|
674
734
|
* carries only a seed for them — feed live cursors and drag boxes through
|
|
@@ -688,16 +748,40 @@ type RivetProps = {
|
|
|
688
748
|
* immediately.
|
|
689
749
|
*/
|
|
690
750
|
onLocalPresence?: (presence: LocalPresence) => void;
|
|
691
|
-
/**
|
|
751
|
+
/**
|
|
752
|
+
* Presence policy — the outbound throttle, and how peer cursors are drawn:
|
|
753
|
+
* rivet's canvas arrow, your own component, or nothing.
|
|
754
|
+
*
|
|
755
|
+
* Compared shallowly, so `cursorComponent` must be a stable reference —
|
|
756
|
+
* declared outside the render or memoized. An inline component would be a new
|
|
757
|
+
* type on every render, and React remounts every cursor when the type changes.
|
|
758
|
+
*/
|
|
692
759
|
presenceOptions?: PresenceOptions;
|
|
693
760
|
/**
|
|
694
|
-
*
|
|
695
|
-
* {@link peers} is description: rivet paints a
|
|
696
|
-
* colour *and* refuses to act on it.
|
|
761
|
+
* What a peer has claimed, as `target -> peerId`. Locks are policy where
|
|
762
|
+
* {@link peers} is description: rivet paints a claimed element in its
|
|
763
|
+
* holder's colour *and* refuses to act on it.
|
|
697
764
|
*
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
765
|
+
* Keys are {@link PresenceTargetKey}s, and a bare node id is its own key — so
|
|
766
|
+
* `{ n1: "ada" }` means exactly what it always did, and edges and anchors
|
|
767
|
+
* join on the same table:
|
|
768
|
+
*
|
|
769
|
+
* ```tsx
|
|
770
|
+
* <Rivet
|
|
771
|
+
* lockedNodes={{
|
|
772
|
+
* n1: "ada", // a node, and everything inside it
|
|
773
|
+
* "edge:e7": "kai", // an edge — refuses reconnection
|
|
774
|
+
* "anchor:n2:door": "wren", // one anchor inside n2
|
|
775
|
+
* }}
|
|
776
|
+
* />
|
|
777
|
+
* ```
|
|
778
|
+
*
|
|
779
|
+
* By default it refuses selection, dragging, resizing, deletion and
|
|
780
|
+
* reconnection, and allows connections — a lock claims the element, not the
|
|
781
|
+
* graph around it. {@link canInteractWithLocked} replaces that policy.
|
|
782
|
+
*
|
|
783
|
+
* A node's lock reaches its contents and their anchors; an edge's reaches
|
|
784
|
+
* nothing, since an edge belongs to no container.
|
|
701
785
|
*
|
|
702
786
|
* Lifetime is yours: rivet never takes or releases a lock, it only reads the
|
|
703
787
|
* table. Take one in {@link onNodeDragStart} and drop it in
|
|
@@ -705,10 +789,10 @@ type RivetProps = {
|
|
|
705
789
|
* for something stickier. Like presence, none of this reaches the graph, the
|
|
706
790
|
* change stream, or history.
|
|
707
791
|
*/
|
|
708
|
-
lockedNodes?: Record<
|
|
792
|
+
lockedNodes?: Record<PresenceTargetKey, string>;
|
|
709
793
|
/**
|
|
710
|
-
* Decide what this client may do to a locked
|
|
711
|
-
* to allow the intent, `false` to refuse it.
|
|
794
|
+
* Decide what this client may do to a locked element, per attempt. Return
|
|
795
|
+
* `true` to allow the intent, `false` to refuse it.
|
|
712
796
|
*
|
|
713
797
|
* A handler owns the whole policy — rivet's defaults are replaced, not
|
|
714
798
|
* consulted — so answer every intent you care about:
|
|
@@ -718,6 +802,16 @@ type RivetProps = {
|
|
|
718
802
|
* canInteractWithLocked={({ intent }) => intent === "select" || intent === "connect"}
|
|
719
803
|
* ```
|
|
720
804
|
*
|
|
805
|
+
* `target` is what was touched and `lockedTarget` is what carries the lock —
|
|
806
|
+
* they differ when a lock is inherited, which is how a locked container can
|
|
807
|
+
* hold itself while leaving its contents free:
|
|
808
|
+
*
|
|
809
|
+
* ```tsx
|
|
810
|
+
* canInteractWithLocked={({ target, lockedTarget }) =>
|
|
811
|
+
* target.kind === "node" && lockedTarget.kind === "node" && target.id !== lockedTarget.id
|
|
812
|
+
* }
|
|
813
|
+
* ```
|
|
814
|
+
*
|
|
721
815
|
* Called on the input path (every marquee frame, every mover), so keep it
|
|
722
816
|
* cheap and free of side effects.
|
|
723
817
|
*/
|
|
@@ -1066,6 +1160,20 @@ type RivetInstance<TNodeData = unknown, TEdgeData = unknown> = RivetControls & {
|
|
|
1066
1160
|
toObject: () => RivetSnapshot<TNodeData, TEdgeData>;
|
|
1067
1161
|
getNodes: () => RivetNode<TNodeData>[];
|
|
1068
1162
|
getNode: (id: NodeId) => RivetNode<TNodeData> | undefined;
|
|
1163
|
+
/**
|
|
1164
|
+
* A node's box in **world** coordinates — its `parentId` chain resolved, and
|
|
1165
|
+
* its explicit or measured size applied. `null` for an id that isn't in the
|
|
1166
|
+
* graph.
|
|
1167
|
+
*
|
|
1168
|
+
* This is where the node currently *is on screen*, not what the document
|
|
1169
|
+
* says: a node a peer is dragging or resizing reports the box they last sent
|
|
1170
|
+
* (see {@link setPeerNodeTransform}), which is what anything painting over
|
|
1171
|
+
* the graph wants. Reach for {@link getNode} instead when you're computing a
|
|
1172
|
+
* mutation — that position is the one the document will agree with.
|
|
1173
|
+
*
|
|
1174
|
+
* Reads once; never subscribes. Call it inside your own frame loop.
|
|
1175
|
+
*/
|
|
1176
|
+
getNodeRect: (id: NodeId) => Rect | null;
|
|
1069
1177
|
setNodes: (nodes: Updater<RivetNode<TNodeData>[]>) => void;
|
|
1070
1178
|
addNodes: (nodes: RivetNode<TNodeData> | RivetNode<TNodeData>[]) => void;
|
|
1071
1179
|
updateNode: (id: NodeId, patch: Updater<RivetNode<TNodeData>>) => void;
|
|
@@ -1119,6 +1227,19 @@ type RivetInstance<TNodeData = unknown, TEdgeData = unknown> = RivetControls & {
|
|
|
1119
1227
|
* load) — rivet can't observe those.
|
|
1120
1228
|
*/
|
|
1121
1229
|
remeasureAnchors: (nodeId: NodeId) => void;
|
|
1230
|
+
/**
|
|
1231
|
+
* One anchor's record — geometry, colour, and whatever `data` was registered
|
|
1232
|
+
* with it — or `null` when the node has no such anchor.
|
|
1233
|
+
*/
|
|
1234
|
+
getAnchor: (nodeId: NodeId, anchorId: string) => AnchorRecord | null;
|
|
1235
|
+
/**
|
|
1236
|
+
* Replace the anchor selection. Selecting an anchor clears the node and edge
|
|
1237
|
+
* selection. View state: no change is emitted and nothing is recorded to
|
|
1238
|
+
* history, so this is safe to call from a render-driven effect.
|
|
1239
|
+
*/
|
|
1240
|
+
setSelectedAnchors: (refs: readonly AnchorRef[]) => void;
|
|
1241
|
+
/** The selected anchors. Reactive through `useSelectedAnchors()`. */
|
|
1242
|
+
getSelectedAnchors: () => readonly AnchorRef[];
|
|
1122
1243
|
/**
|
|
1123
1244
|
* Move a peer's cursor, in **world** coordinates (peers pan and zoom
|
|
1124
1245
|
* independently, so a screen point means nothing to them). `null` parks it.
|
|
@@ -1136,6 +1257,16 @@ type RivetInstance<TNodeData = unknown, TEdgeData = unknown> = RivetControls & {
|
|
|
1136
1257
|
* Pass `null` on their drop.
|
|
1137
1258
|
*/
|
|
1138
1259
|
setPeerNodeTransform: (peerId: string, nodeId: NodeId, rect: Rect | null) => void;
|
|
1260
|
+
/**
|
|
1261
|
+
* Draw the wire a peer is pulling out of a handle — their `LocalPresence.pending`,
|
|
1262
|
+
* fed straight back. Both ends are in **world** coordinates. Pass `null` when
|
|
1263
|
+
* they let go, which their next snapshot says either way.
|
|
1264
|
+
*
|
|
1265
|
+
* Painted on the foreground in their colour, with a dot on the loose end. It
|
|
1266
|
+
* changes nothing about the graph: a connection exists when their change
|
|
1267
|
+
* lands, not while they're dragging toward it.
|
|
1268
|
+
*/
|
|
1269
|
+
setPeerConnection: (peerId: string, connection: PeerConnection | null) => void;
|
|
1139
1270
|
/** Forget a peer entirely — cursor, held nodes and all. For a disconnect. */
|
|
1140
1271
|
removePeer: (peerId: string) => void;
|
|
1141
1272
|
/**
|
|
@@ -1203,10 +1334,14 @@ declare class Canvas2DEdgeRenderer implements EdgeRenderer {
|
|
|
1203
1334
|
private readonly endpoints;
|
|
1204
1335
|
/** Screen-space label anchor per edge that has a label. */
|
|
1205
1336
|
private readonly labels;
|
|
1337
|
+
/** Screen-space midpoint per edge somebody has claimed, for DOM claim chrome. */
|
|
1338
|
+
private readonly peerAnchors;
|
|
1206
1339
|
constructor(canvas: HTMLCanvasElement, options?: EdgeRendererOptions);
|
|
1207
1340
|
resize(width: number, height: number, dpr: number): void;
|
|
1208
1341
|
/** Screen-space label anchors for the edges drawn last frame. */
|
|
1209
1342
|
getLabels(): Map<EdgeId, Vec2>;
|
|
1343
|
+
/** Screen-space midpoints for the edges a peer had claimed last frame. */
|
|
1344
|
+
getPeerEdgeAnchors(): ReadonlyMap<EdgeId, Vec2>;
|
|
1210
1345
|
/** Screen-space endpoints per edge from the last frame (reconnect affordance). */
|
|
1211
1346
|
getEndpoints(): ReadonlyMap<EdgeId, {
|
|
1212
1347
|
source: Vec2;
|