@kolosal-ai/rivet 0.3.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 +138 -24
- package/dist/index.js +543 -129
- package/dist/index.js.map +1 -1
- package/dist/presence/index.d.ts +69 -4
- package/dist/presence/index.js +1 -1
- package/dist/{registry-CCBgd7FN.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-C9Vn1rzy.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-A52HZWLH.js +0 -314
- package/dist/chunk-A52HZWLH.js.map +0 -1
- package/dist/chunk-AXT35ZJV.js.map +0 -1
- package/dist/use-node-lock-DH0dB1yA.d.ts +0 -327
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { parseAnchorHandleId, ANCHOR_SIDES, anchorDotHandleId, strayPlacementPct, anchorHandleId, anchorAutoHandleId, parseAnchorAutoHandleId, normalizeAnchorConnection, computeAnchorGeometry, anchorGeometryEqual, DEFAULT_ANCHOR_OPTIONS } from './chunk-
|
|
2
|
-
import { createPresenceRegistry, createLockRegistry, DEFAULT_PRESENCE_OPTIONS, peerColor } from './chunk-
|
|
3
|
-
export { LOCK_DEFAULT_REFUSED, useNodeLock, useNodeLockAllows } from './chunk-
|
|
1
|
+
import { findSelectableAnchor, parseAnchorHandleId, ANCHOR_SIDES, anchorDotHandleId, strayPlacementPct, anchorHandleId, anchorAutoHandleId, parseAnchorAutoHandleId, normalizeAnchorConnection, computeAnchorGeometry, anchorGeometryEqual, DEFAULT_ANCHOR_OPTIONS, anchorRect } from './chunk-W5HBJ4VF.js';
|
|
2
|
+
import { snapToGrid, boundingRect, clampChildToParent, anchorTargetKey, createPresenceRegistry, createLockRegistry, nodeControlledEqual, buildChildIndex, collectDescendants, worldPosition, nodeDepth, descendantIds, hasAncestorIn, edgeTargetKey, DEFAULT_PRESENCE_OPTIONS, collectPeerOutlines, peerOutlinesEqual, usePeerIdentities, serializeGraph, presenceTargetKey, peerColor, isNodeTarget, presenceTargetEdgeId } from './chunk-TT2N7KWU.js';
|
|
3
|
+
export { LOCK_DEFAULT_REFUSED, boundingRect, clampChildToParent, serializeGraph, snapToGrid, useNodeLock, useNodeLockAllows } from './chunk-TT2N7KWU.js';
|
|
4
4
|
import { useRivetContext, RivetNodeContext, useRivetNodeContext, useRivetControls, RivetContext, useRivetViewport } from './chunk-VQYN27OK.js';
|
|
5
5
|
export { useRivetContext, useRivetControls, useRivetFocusedNode, useRivetHistory, useRivetViewport } from './chunk-VQYN27OK.js';
|
|
6
6
|
import { clamp, clampNodeToLanes, swimlaneChromeAt, SWIMLANE_LABEL_WIDTH, resolveSwimlanes, flattenLanes, resolveMargin, requiredLaneHeight, withAlpha } from './chunk-6XRQSAQT.js';
|
|
@@ -282,6 +282,7 @@ var DEFAULT_NODE_SIZE = { width: 160, height: 44 };
|
|
|
282
282
|
function handleKey(nodeId, handleId) {
|
|
283
283
|
return `${nodeId} ${handleId}`;
|
|
284
284
|
}
|
|
285
|
+
var DRAG_THRESHOLD = 4;
|
|
285
286
|
var SELECTOR = {
|
|
286
287
|
node: "[data-rivet-node]",
|
|
287
288
|
handle: "[data-rivet-handle]",
|
|
@@ -387,111 +388,6 @@ function guardNodeChanges(changes, isHeld, getLocal) {
|
|
|
387
388
|
return guarded;
|
|
388
389
|
}
|
|
389
390
|
|
|
390
|
-
// src/graph.ts
|
|
391
|
-
function clampChildToParent(position, childSize, parentSize) {
|
|
392
|
-
const maxX = Math.max(0, parentSize.width - childSize.width);
|
|
393
|
-
const maxY = Math.max(0, parentSize.height - childSize.height);
|
|
394
|
-
return {
|
|
395
|
-
x: Math.min(maxX, Math.max(0, position.x)),
|
|
396
|
-
y: Math.min(maxY, Math.max(0, position.y))
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
function snapToGrid(position, grid) {
|
|
400
|
-
const [gx, gy] = grid;
|
|
401
|
-
return {
|
|
402
|
-
x: gx > 0 ? Math.round(position.x / gx) * gx : position.x,
|
|
403
|
-
y: gy > 0 ? Math.round(position.y / gy) * gy : position.y
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
function boundingRect(rects) {
|
|
407
|
-
if (rects.length === 0) return null;
|
|
408
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
409
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
410
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
411
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
412
|
-
for (const r of rects) {
|
|
413
|
-
minX = Math.min(minX, r.x);
|
|
414
|
-
minY = Math.min(minY, r.y);
|
|
415
|
-
maxX = Math.max(maxX, r.x + r.width);
|
|
416
|
-
maxY = Math.max(maxY, r.y + r.height);
|
|
417
|
-
}
|
|
418
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
419
|
-
}
|
|
420
|
-
var MAX_PARENT_DEPTH = 50;
|
|
421
|
-
function worldPosition(nodes, id, maxDepth = MAX_PARENT_DEPTH) {
|
|
422
|
-
const node = nodes.get(id);
|
|
423
|
-
if (!node) return { x: 0, y: 0 };
|
|
424
|
-
let x = node.position.x;
|
|
425
|
-
let y = node.position.y;
|
|
426
|
-
let parentId = node.parentId;
|
|
427
|
-
let guard = 0;
|
|
428
|
-
while (parentId && guard++ < maxDepth) {
|
|
429
|
-
const parent = nodes.get(parentId);
|
|
430
|
-
if (!parent) break;
|
|
431
|
-
x += parent.position.x;
|
|
432
|
-
y += parent.position.y;
|
|
433
|
-
parentId = parent.parentId;
|
|
434
|
-
}
|
|
435
|
-
return { x, y };
|
|
436
|
-
}
|
|
437
|
-
function nodeDepth(nodes, id, maxDepth = MAX_PARENT_DEPTH) {
|
|
438
|
-
let depth = 0;
|
|
439
|
-
let parentId = nodes.get(id)?.parentId;
|
|
440
|
-
while (parentId && depth < maxDepth) {
|
|
441
|
-
depth++;
|
|
442
|
-
parentId = nodes.get(parentId)?.parentId;
|
|
443
|
-
}
|
|
444
|
-
return depth;
|
|
445
|
-
}
|
|
446
|
-
function hasAncestorIn(nodes, id, set, maxDepth = MAX_PARENT_DEPTH) {
|
|
447
|
-
let parentId = nodes.get(id)?.parentId;
|
|
448
|
-
let guard = 0;
|
|
449
|
-
while (parentId && guard++ < maxDepth) {
|
|
450
|
-
if (set.has(parentId)) return true;
|
|
451
|
-
parentId = nodes.get(parentId)?.parentId;
|
|
452
|
-
}
|
|
453
|
-
return false;
|
|
454
|
-
}
|
|
455
|
-
function buildChildIndex(nodes) {
|
|
456
|
-
const childrenOf = /* @__PURE__ */ new Map();
|
|
457
|
-
for (const node of nodes.values()) {
|
|
458
|
-
if (!node.parentId) continue;
|
|
459
|
-
const list = childrenOf.get(node.parentId);
|
|
460
|
-
if (list) list.push(node.id);
|
|
461
|
-
else childrenOf.set(node.parentId, [node.id]);
|
|
462
|
-
}
|
|
463
|
-
return childrenOf;
|
|
464
|
-
}
|
|
465
|
-
function collectDescendants(id, childIndex, out) {
|
|
466
|
-
for (const child of childIndex.get(id) ?? []) {
|
|
467
|
-
out.push(child);
|
|
468
|
-
collectDescendants(child, childIndex, out);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
function descendantIds(nodes, id) {
|
|
472
|
-
const out = [];
|
|
473
|
-
collectDescendants(id, buildChildIndex(nodes), out);
|
|
474
|
-
return out;
|
|
475
|
-
}
|
|
476
|
-
function serializeGraph(nodes, edges, viewport) {
|
|
477
|
-
const cleanNodes = [];
|
|
478
|
-
for (const node of nodes) {
|
|
479
|
-
const copy = { ...node, position: { ...node.position } };
|
|
480
|
-
if (node.size) copy.size = { ...node.size };
|
|
481
|
-
copy.hovered = void 0;
|
|
482
|
-
copy.dragging = void 0;
|
|
483
|
-
cleanNodes.push(copy);
|
|
484
|
-
}
|
|
485
|
-
return {
|
|
486
|
-
nodes: cleanNodes,
|
|
487
|
-
edges: [...edges].map((edge) => ({ ...edge })),
|
|
488
|
-
viewport: { ...viewport }
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
function nodeControlledEqual(a, b) {
|
|
492
|
-
return a.position.x === b.position.x && a.position.y === b.position.y && Boolean(a.selected) === Boolean(b.selected) && a.data === b.data && a.type === b.type && a.laneId === b.laneId && a.ariaLabel === b.ariaLabel && a.parentId === b.parentId && a.extent === b.extent && a.width === b.width && a.height === b.height && Boolean(a.dragging) === Boolean(b.dragging) && a.size?.width === b.size?.width && a.size?.height === b.size?.height;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
391
|
// src/history.ts
|
|
496
392
|
function hasRecordableChange(changes) {
|
|
497
393
|
return changes.some((change) => {
|
|
@@ -997,6 +893,30 @@ function resolveEnd(edge, role, node, peer, frame) {
|
|
|
997
893
|
extras?.displayedSides?.set(key, side);
|
|
998
894
|
return endAt(side);
|
|
999
895
|
}
|
|
896
|
+
function polylineMidpoint(points) {
|
|
897
|
+
const first = points[0];
|
|
898
|
+
if (!first) return { x: 0, y: 0 };
|
|
899
|
+
let total = 0;
|
|
900
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
901
|
+
const a = points[i];
|
|
902
|
+
const b = points[i + 1];
|
|
903
|
+
if (a && b) total += Math.hypot(b.x - a.x, b.y - a.y);
|
|
904
|
+
}
|
|
905
|
+
let travelled = 0;
|
|
906
|
+
const half = total / 2;
|
|
907
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
908
|
+
const a = points[i];
|
|
909
|
+
const b = points[i + 1];
|
|
910
|
+
if (!a || !b) continue;
|
|
911
|
+
const length = Math.hypot(b.x - a.x, b.y - a.y);
|
|
912
|
+
if (travelled + length >= half) {
|
|
913
|
+
const t = length === 0 ? 0 : (half - travelled) / length;
|
|
914
|
+
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
915
|
+
}
|
|
916
|
+
travelled += length;
|
|
917
|
+
}
|
|
918
|
+
return points[points.length - 1] ?? first;
|
|
919
|
+
}
|
|
1000
920
|
function distanceToPolyline(point, points) {
|
|
1001
921
|
let best = Number.POSITIVE_INFINITY;
|
|
1002
922
|
for (let i = 0; i < points.length - 1; i++) {
|
|
@@ -1029,7 +949,10 @@ var RivetGraphStore = class {
|
|
|
1029
949
|
requestRender: () => this.requestRender(),
|
|
1030
950
|
requestCursorRender: () => this.requestCursorRender()
|
|
1031
951
|
});
|
|
1032
|
-
locks = createLockRegistry(
|
|
952
|
+
locks = createLockRegistry(
|
|
953
|
+
() => this.requestRender(),
|
|
954
|
+
(id) => this.nodes.get(id)?.parentId
|
|
955
|
+
);
|
|
1033
956
|
viewport;
|
|
1034
957
|
viewportClamp = null;
|
|
1035
958
|
pending = null;
|
|
@@ -1042,6 +965,8 @@ var RivetGraphStore = class {
|
|
|
1042
965
|
nodeElements = /* @__PURE__ */ new Map();
|
|
1043
966
|
viewportListeners = /* @__PURE__ */ new Set();
|
|
1044
967
|
frameListeners = /* @__PURE__ */ new Set();
|
|
968
|
+
cursorFrameListeners = /* @__PURE__ */ new Set();
|
|
969
|
+
connectionListeners = /* @__PURE__ */ new Set();
|
|
1045
970
|
selectionListeners = /* @__PURE__ */ new Set();
|
|
1046
971
|
selectedNodeIds = /* @__PURE__ */ new Set();
|
|
1047
972
|
selectionBoxActive = false;
|
|
@@ -1051,6 +976,11 @@ var RivetGraphStore = class {
|
|
|
1051
976
|
focusedNodeId = null;
|
|
1052
977
|
focusListeners = /* @__PURE__ */ new Set();
|
|
1053
978
|
selectedEdgeId = null;
|
|
979
|
+
/** Selected anchors, keyed like the registry so lookups are one hash. */
|
|
980
|
+
selectedAnchors = /* @__PURE__ */ new Map();
|
|
981
|
+
selectedAnchorSnapshot = [];
|
|
982
|
+
selectedAnchorsStale = false;
|
|
983
|
+
anchorSelectionListeners = /* @__PURE__ */ new Set();
|
|
1054
984
|
nodeDragging = false;
|
|
1055
985
|
nodeResizing = false;
|
|
1056
986
|
edgeAlignment = "manual";
|
|
@@ -1062,6 +992,8 @@ var RivetGraphStore = class {
|
|
|
1062
992
|
lockConflictHandler = null;
|
|
1063
993
|
displayedSides = /* @__PURE__ */ new Map();
|
|
1064
994
|
edgeLabelAnchors = /* @__PURE__ */ new Map();
|
|
995
|
+
/** Screen-space points on claimed edges, published only while DOM outlines are on. */
|
|
996
|
+
peerEdgeAnchors = /* @__PURE__ */ new Map();
|
|
1065
997
|
alignmentGuides = [];
|
|
1066
998
|
nodeChangeHandler = null;
|
|
1067
999
|
edgeChangeHandler = null;
|
|
@@ -1255,6 +1187,7 @@ var RivetGraphStore = class {
|
|
|
1255
1187
|
for (const key of this.anchors.keys()) {
|
|
1256
1188
|
if (key.startsWith(prefix)) this.anchors.delete(key);
|
|
1257
1189
|
}
|
|
1190
|
+
this.dropSelectedAnchors((ref) => ref.nodeId === id);
|
|
1258
1191
|
}
|
|
1259
1192
|
removeNodeInternal(id, removedEdges) {
|
|
1260
1193
|
if (!this.nodes.has(id)) return false;
|
|
@@ -1382,6 +1315,15 @@ var RivetGraphStore = class {
|
|
|
1382
1315
|
notifyFrame = () => {
|
|
1383
1316
|
for (const listener of this.frameListeners) listener();
|
|
1384
1317
|
};
|
|
1318
|
+
subscribeCursorFrame = (listener) => {
|
|
1319
|
+
this.cursorFrameListeners.add(listener);
|
|
1320
|
+
return () => {
|
|
1321
|
+
this.cursorFrameListeners.delete(listener);
|
|
1322
|
+
};
|
|
1323
|
+
};
|
|
1324
|
+
notifyCursorFrame = () => {
|
|
1325
|
+
for (const listener of this.cursorFrameListeners) listener();
|
|
1326
|
+
};
|
|
1385
1327
|
// --- node geometry -------------------------------------------------------
|
|
1386
1328
|
getWorldPositions = () => {
|
|
1387
1329
|
if (!this.worldCache) {
|
|
@@ -1633,8 +1575,10 @@ var RivetGraphStore = class {
|
|
|
1633
1575
|
const opened = this.locks.setLocks(locks);
|
|
1634
1576
|
if (opened.length === 0 || this.heldNodeIds.size === 0) return;
|
|
1635
1577
|
const held = [...this.heldNodeIds];
|
|
1636
|
-
|
|
1637
|
-
|
|
1578
|
+
const openedSet = new Set(opened);
|
|
1579
|
+
for (const nodeId of held) {
|
|
1580
|
+
const source = this.locks.getLockSource(nodeId);
|
|
1581
|
+
if (source === null || !openedSet.has(source)) continue;
|
|
1638
1582
|
const holderId = this.locks.getHolder(nodeId);
|
|
1639
1583
|
if (holderId) this.lockConflictHandler?.({ nodeId, holderId, ids: held });
|
|
1640
1584
|
}
|
|
@@ -1662,6 +1606,7 @@ var RivetGraphStore = class {
|
|
|
1662
1606
|
};
|
|
1663
1607
|
selectNode = (id, additive = false) => {
|
|
1664
1608
|
this.setSelectionBoxActive(false);
|
|
1609
|
+
this.dropSelectedAnchors(() => true);
|
|
1665
1610
|
if (id === null) {
|
|
1666
1611
|
this.applyNodeSelection(/* @__PURE__ */ new Set());
|
|
1667
1612
|
this.notifySelection();
|
|
@@ -1681,6 +1626,7 @@ var RivetGraphStore = class {
|
|
|
1681
1626
|
};
|
|
1682
1627
|
selectNodes = (ids, additive = false) => {
|
|
1683
1628
|
this.setSelectionBoxActive(false);
|
|
1629
|
+
this.dropSelectedAnchors(() => true);
|
|
1684
1630
|
const target = additive ? new Set(this.selectedNodeIds) : /* @__PURE__ */ new Set();
|
|
1685
1631
|
for (const id of ids) target.add(id);
|
|
1686
1632
|
this.applyNodeSelection(target);
|
|
@@ -1689,6 +1635,7 @@ var RivetGraphStore = class {
|
|
|
1689
1635
|
};
|
|
1690
1636
|
getSelectedNodes = () => [...this.selectedNodeIds];
|
|
1691
1637
|
isNodeSelected = (id) => this.selectedNodeIds.has(id);
|
|
1638
|
+
getSelectedEdgeId = () => this.selectedEdgeId;
|
|
1692
1639
|
getSelection = () => this.buildSelection();
|
|
1693
1640
|
subscribeSelection = (listener) => {
|
|
1694
1641
|
this.selectionListeners.add(listener);
|
|
@@ -1728,6 +1675,7 @@ var RivetGraphStore = class {
|
|
|
1728
1675
|
// --- edges ---------------------------------------------------------------
|
|
1729
1676
|
selectEdge = (id) => {
|
|
1730
1677
|
this.setSelectionBoxActive(false);
|
|
1678
|
+
this.dropSelectedAnchors(() => true);
|
|
1731
1679
|
this.setEdgeSelection(id);
|
|
1732
1680
|
this.applyNodeSelection(/* @__PURE__ */ new Set());
|
|
1733
1681
|
this.notifySelection();
|
|
@@ -1773,7 +1721,7 @@ var RivetGraphStore = class {
|
|
|
1773
1721
|
const removedNodes = [];
|
|
1774
1722
|
const removedEdges = [];
|
|
1775
1723
|
const selectedEdge = this.selectedEdgeId;
|
|
1776
|
-
if (selectedEdge && this.removeEdgeInternal(selectedEdge)) {
|
|
1724
|
+
if (selectedEdge && this.locks.allows(edgeTargetKey(selectedEdge), "delete") && this.removeEdgeInternal(selectedEdge)) {
|
|
1777
1725
|
removedEdges.push(selectedEdge);
|
|
1778
1726
|
}
|
|
1779
1727
|
if (this.selectedNodeIds.size > 0) {
|
|
@@ -1898,6 +1846,10 @@ var RivetGraphStore = class {
|
|
|
1898
1846
|
setEdgeLabelAnchors = (anchors) => {
|
|
1899
1847
|
this.edgeLabelAnchors = anchors;
|
|
1900
1848
|
};
|
|
1849
|
+
getPeerEdgeAnchors = () => this.peerEdgeAnchors;
|
|
1850
|
+
setPeerEdgeAnchors = (anchors) => {
|
|
1851
|
+
this.peerEdgeAnchors = anchors;
|
|
1852
|
+
};
|
|
1901
1853
|
getAlignmentGuides = () => this.alignmentGuides;
|
|
1902
1854
|
setAlignmentGuides = (guides) => {
|
|
1903
1855
|
this.alignmentGuides = guides;
|
|
@@ -1944,6 +1896,8 @@ var RivetGraphStore = class {
|
|
|
1944
1896
|
anchorId,
|
|
1945
1897
|
color: options?.color ?? prev?.color,
|
|
1946
1898
|
strays: options?.strays ?? prev?.strays,
|
|
1899
|
+
selectable: options?.selectable ?? prev?.selectable,
|
|
1900
|
+
data: options?.data ?? prev?.data,
|
|
1947
1901
|
element,
|
|
1948
1902
|
// Keep the last-known geometry until the next successful measurement, so
|
|
1949
1903
|
// a re-bind (display remount, editor DOM swap) never blanks the chrome.
|
|
@@ -1962,6 +1916,7 @@ var RivetGraphStore = class {
|
|
|
1962
1916
|
};
|
|
1963
1917
|
unregisterAnchor = (nodeId, anchorId) => {
|
|
1964
1918
|
if (!this.anchors.delete(handleKey(nodeId, anchorId))) return;
|
|
1919
|
+
this.dropSelectedAnchors((ref) => ref.nodeId === nodeId && ref.anchorId === anchorId);
|
|
1965
1920
|
this.bumpAnchors(nodeId);
|
|
1966
1921
|
this.requestRender();
|
|
1967
1922
|
};
|
|
@@ -1983,6 +1938,51 @@ var RivetGraphStore = class {
|
|
|
1983
1938
|
return records;
|
|
1984
1939
|
};
|
|
1985
1940
|
getNodeAnchorsVersion = (nodeId) => this.anchorVersions.get(nodeId) ?? 0;
|
|
1941
|
+
getSelectedAnchors = () => {
|
|
1942
|
+
if (this.selectedAnchorsStale) {
|
|
1943
|
+
this.selectedAnchorsStale = false;
|
|
1944
|
+
this.selectedAnchorSnapshot = [...this.selectedAnchors.values()];
|
|
1945
|
+
}
|
|
1946
|
+
return this.selectedAnchorSnapshot;
|
|
1947
|
+
};
|
|
1948
|
+
setSelectedAnchors = (refs) => {
|
|
1949
|
+
const next = /* @__PURE__ */ new Map();
|
|
1950
|
+
for (const ref of refs) next.set(handleKey(ref.nodeId, ref.anchorId), ref);
|
|
1951
|
+
if (next.size === this.selectedAnchors.size && [...next.keys()].every((key) => this.selectedAnchors.has(key))) {
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
const clearsGraph = next.size > 0 && (this.selectedNodeIds.size > 0 || this.selectedEdgeId !== null);
|
|
1955
|
+
this.selectedAnchors = /* @__PURE__ */ new Map();
|
|
1956
|
+
if (clearsGraph) {
|
|
1957
|
+
this.selectNode(null);
|
|
1958
|
+
this.selectEdge(null);
|
|
1959
|
+
}
|
|
1960
|
+
this.selectedAnchors = next;
|
|
1961
|
+
this.selectedAnchorsStale = true;
|
|
1962
|
+
for (const listener of this.anchorSelectionListeners) listener();
|
|
1963
|
+
this.requestRender();
|
|
1964
|
+
};
|
|
1965
|
+
isAnchorSelected = (nodeId, anchorId) => this.selectedAnchors.has(handleKey(nodeId, anchorId));
|
|
1966
|
+
subscribeAnchorSelection = (listener) => {
|
|
1967
|
+
this.anchorSelectionListeners.add(listener);
|
|
1968
|
+
return () => {
|
|
1969
|
+
this.anchorSelectionListeners.delete(listener);
|
|
1970
|
+
};
|
|
1971
|
+
};
|
|
1972
|
+
/** Drop every selected anchor the predicate claims. No-op when none match. */
|
|
1973
|
+
dropSelectedAnchors(matches) {
|
|
1974
|
+
if (this.selectedAnchors.size === 0) return;
|
|
1975
|
+
let changed = false;
|
|
1976
|
+
for (const [key, ref] of this.selectedAnchors) {
|
|
1977
|
+
if (!matches(ref)) continue;
|
|
1978
|
+
this.selectedAnchors.delete(key);
|
|
1979
|
+
changed = true;
|
|
1980
|
+
}
|
|
1981
|
+
if (!changed) return;
|
|
1982
|
+
this.selectedAnchorsStale = true;
|
|
1983
|
+
for (const listener of this.anchorSelectionListeners) listener();
|
|
1984
|
+
this.requestRender();
|
|
1985
|
+
}
|
|
1986
1986
|
subscribeNodeAnchors = (nodeId, listener) => {
|
|
1987
1987
|
let set = this.anchorListeners.get(nodeId);
|
|
1988
1988
|
if (!set) {
|
|
@@ -2007,17 +2007,29 @@ var RivetGraphStore = class {
|
|
|
2007
2007
|
beginConnection = (next) => {
|
|
2008
2008
|
this.pending = next;
|
|
2009
2009
|
this.requestRender();
|
|
2010
|
+
this.notifyConnection();
|
|
2010
2011
|
};
|
|
2011
2012
|
updateConnection = (to, toPosition) => {
|
|
2012
2013
|
if (!this.pending) return;
|
|
2013
2014
|
this.pending = { ...this.pending, to, toPosition };
|
|
2014
2015
|
this.requestRender();
|
|
2016
|
+
this.notifyConnection();
|
|
2015
2017
|
};
|
|
2016
2018
|
endConnection = () => {
|
|
2017
2019
|
if (!this.pending) return;
|
|
2018
2020
|
this.pending = null;
|
|
2019
2021
|
this.requestRender();
|
|
2022
|
+
this.notifyConnection();
|
|
2020
2023
|
};
|
|
2024
|
+
subscribeConnection = (listener) => {
|
|
2025
|
+
this.connectionListeners.add(listener);
|
|
2026
|
+
return () => {
|
|
2027
|
+
this.connectionListeners.delete(listener);
|
|
2028
|
+
};
|
|
2029
|
+
};
|
|
2030
|
+
notifyConnection() {
|
|
2031
|
+
for (const listener of this.connectionListeners) listener();
|
|
2032
|
+
}
|
|
2021
2033
|
// --- render loop hook ----------------------------------------------------
|
|
2022
2034
|
requestRender = () => {
|
|
2023
2035
|
this.renderRequester();
|
|
@@ -2696,7 +2708,12 @@ function NodeResizer({
|
|
|
2696
2708
|
|
|
2697
2709
|
// src/presence/local.ts
|
|
2698
2710
|
var sameIds = (a, b) => a.length === b.length && a.every((id, i) => id === b[i]);
|
|
2699
|
-
var
|
|
2711
|
+
var sameConnection = (a, b) => {
|
|
2712
|
+
if (a === b) return true;
|
|
2713
|
+
if (!a || !b) return false;
|
|
2714
|
+
return a.source === b.source && a.sourceHandle === b.sourceHandle && a.toPosition === b.toPosition && a.to.x === b.to.x && a.to.y === b.to.y;
|
|
2715
|
+
};
|
|
2716
|
+
var samePresence = (a, b) => a.cursor?.x === b.cursor?.x && a.cursor?.y === b.cursor?.y && sameIds(a.selection, b.selection) && sameIds(a.holding, b.holding) && sameConnection(a.pending, b.pending);
|
|
2700
2717
|
function trackLocalPresence({
|
|
2701
2718
|
store,
|
|
2702
2719
|
pane,
|
|
@@ -2708,6 +2725,21 @@ function trackLocalPresence({
|
|
|
2708
2725
|
let last = null;
|
|
2709
2726
|
let timer = null;
|
|
2710
2727
|
let lastEmit = Number.NEGATIVE_INFINITY;
|
|
2728
|
+
const selectionTargets = () => {
|
|
2729
|
+
const targets = store.getSelectedNodes();
|
|
2730
|
+
const edgeId = store.getSelectedEdgeId();
|
|
2731
|
+
if (edgeId) targets.push(presenceTargetKey({ kind: "edge", id: edgeId }));
|
|
2732
|
+
for (const ref of store.getSelectedAnchors()) {
|
|
2733
|
+
targets.push(presenceTargetKey({ kind: "anchor", ...ref }));
|
|
2734
|
+
}
|
|
2735
|
+
return targets;
|
|
2736
|
+
};
|
|
2737
|
+
const localConnection = () => {
|
|
2738
|
+
const pending = store.getPending();
|
|
2739
|
+
if (!pending) return null;
|
|
2740
|
+
const { source, sourceHandle, sourceType, from, to, toPosition } = pending;
|
|
2741
|
+
return toPosition === void 0 ? { source, sourceHandle, sourceType, from, to } : { source, sourceHandle, sourceType, from, to, toPosition };
|
|
2742
|
+
};
|
|
2711
2743
|
const publish = () => {
|
|
2712
2744
|
if (timer !== null) {
|
|
2713
2745
|
clearTimeout(timer);
|
|
@@ -2716,8 +2748,9 @@ function trackLocalPresence({
|
|
|
2716
2748
|
lastEmit = performance.now();
|
|
2717
2749
|
const next = {
|
|
2718
2750
|
cursor,
|
|
2719
|
-
selection:
|
|
2720
|
-
holding: [...store.getHeldNodeIds()]
|
|
2751
|
+
selection: selectionTargets(),
|
|
2752
|
+
holding: [...store.getHeldNodeIds()],
|
|
2753
|
+
pending: localConnection()
|
|
2721
2754
|
};
|
|
2722
2755
|
if (last && samePresence(last, next)) return;
|
|
2723
2756
|
last = next;
|
|
@@ -2759,7 +2792,18 @@ function trackLocalPresence({
|
|
|
2759
2792
|
schedule();
|
|
2760
2793
|
});
|
|
2761
2794
|
const unsubscribeSelection = store.subscribeSelection(() => publish());
|
|
2795
|
+
const unsubscribeAnchors = store.subscribeAnchorSelection(() => publish());
|
|
2762
2796
|
const unsubscribeHeld = store.subscribeHeldNodes(() => publish());
|
|
2797
|
+
let hadPending = store.getPending() !== null;
|
|
2798
|
+
const unsubscribeConnection = store.subscribeConnection(() => {
|
|
2799
|
+
const has = store.getPending() !== null;
|
|
2800
|
+
if (has === hadPending) {
|
|
2801
|
+
schedule();
|
|
2802
|
+
return;
|
|
2803
|
+
}
|
|
2804
|
+
hadPending = has;
|
|
2805
|
+
publish();
|
|
2806
|
+
});
|
|
2763
2807
|
pane.addEventListener("pointermove", onPointerMove);
|
|
2764
2808
|
pane.addEventListener("pointerleave", onPointerLeave);
|
|
2765
2809
|
return () => {
|
|
@@ -2768,7 +2812,9 @@ function trackLocalPresence({
|
|
|
2768
2812
|
pane.removeEventListener("pointerleave", onPointerLeave);
|
|
2769
2813
|
unsubscribeViewport();
|
|
2770
2814
|
unsubscribeSelection();
|
|
2815
|
+
unsubscribeAnchors();
|
|
2771
2816
|
unsubscribeHeld();
|
|
2817
|
+
unsubscribeConnection();
|
|
2772
2818
|
};
|
|
2773
2819
|
}
|
|
2774
2820
|
|
|
@@ -3170,6 +3216,9 @@ var LABEL_PADDING_X = 6;
|
|
|
3170
3216
|
var LABEL_HEIGHT = 17;
|
|
3171
3217
|
var LABEL_RADIUS = 4;
|
|
3172
3218
|
var CULL_MARGIN_PX = 64;
|
|
3219
|
+
var PENDING_DASH = [6, 4];
|
|
3220
|
+
var PENDING_LINE_WIDTH = 2;
|
|
3221
|
+
var PENDING_TIP_RADIUS = 3.5;
|
|
3173
3222
|
function traceRect(ctx, rect, radius) {
|
|
3174
3223
|
ctx.beginPath();
|
|
3175
3224
|
if (typeof ctx.roundRect === "function") {
|
|
@@ -3228,9 +3277,12 @@ function drawPeerOutlines(ctx, peers, { viewport, size, getNodeRect, locks }) {
|
|
|
3228
3277
|
ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);
|
|
3229
3278
|
const painted = /* @__PURE__ */ new Set();
|
|
3230
3279
|
for (const peer of peers) {
|
|
3231
|
-
const held = /* @__PURE__ */ new Set([
|
|
3280
|
+
const held = /* @__PURE__ */ new Set([
|
|
3281
|
+
...peer.holding.filter((key) => isNodeTarget(key)),
|
|
3282
|
+
...peer.transforms.keys()
|
|
3283
|
+
]);
|
|
3232
3284
|
for (const id of peer.selection) {
|
|
3233
|
-
if (held.has(id)) continue;
|
|
3285
|
+
if (!isNodeTarget(id) || held.has(id)) continue;
|
|
3234
3286
|
const rect = getNodeRect(id);
|
|
3235
3287
|
if (!rect) continue;
|
|
3236
3288
|
const screen = projectRect(rect, viewport);
|
|
@@ -3247,7 +3299,7 @@ function drawPeerOutlines(ctx, peers, { viewport, size, getNodeRect, locks }) {
|
|
|
3247
3299
|
if (locks.size > 0) {
|
|
3248
3300
|
const declared = new Map(peers.map((peer) => [peer.id, peer.color]));
|
|
3249
3301
|
for (const [id, holderId] of locks) {
|
|
3250
|
-
if (painted.has(id)) continue;
|
|
3302
|
+
if (!isNodeTarget(id) || painted.has(id)) continue;
|
|
3251
3303
|
const rect = getNodeRect(id);
|
|
3252
3304
|
if (!rect) continue;
|
|
3253
3305
|
const screen = projectRect(rect, viewport);
|
|
@@ -3257,6 +3309,69 @@ function drawPeerOutlines(ctx, peers, { viewport, size, getNodeRect, locks }) {
|
|
|
3257
3309
|
}
|
|
3258
3310
|
ctx.restore();
|
|
3259
3311
|
}
|
|
3312
|
+
function collectPeerEdges(peers, lockedEdges) {
|
|
3313
|
+
if (peers.length === 0 && lockedEdges.size === 0) return void 0;
|
|
3314
|
+
let claimed = null;
|
|
3315
|
+
const claim = (key, color, override) => {
|
|
3316
|
+
const edgeId = presenceTargetEdgeId(key);
|
|
3317
|
+
if (edgeId === null) return;
|
|
3318
|
+
claimed ??= /* @__PURE__ */ new Map();
|
|
3319
|
+
if (override || !claimed.has(edgeId)) claimed.set(edgeId, color);
|
|
3320
|
+
};
|
|
3321
|
+
for (const peer of peers) {
|
|
3322
|
+
for (const key of peer.selection) claim(key, peer.color, false);
|
|
3323
|
+
}
|
|
3324
|
+
for (const peer of peers) {
|
|
3325
|
+
for (const key of peer.holding) claim(key, peer.color, true);
|
|
3326
|
+
}
|
|
3327
|
+
if (lockedEdges.size > 0) {
|
|
3328
|
+
const declared = new Map(peers.map((peer) => [peer.id, peer.color]));
|
|
3329
|
+
for (const [edgeId, holderId] of lockedEdges) {
|
|
3330
|
+
claimed ??= /* @__PURE__ */ new Map();
|
|
3331
|
+
if (!claimed.has(edgeId)) {
|
|
3332
|
+
claimed.set(edgeId, declared.get(holderId) ?? peerColor(holderId));
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
return claimed ?? void 0;
|
|
3337
|
+
}
|
|
3338
|
+
function drawPeerPending(ctx, peers, { viewport, size, handles }) {
|
|
3339
|
+
let saved = false;
|
|
3340
|
+
for (const peer of peers) {
|
|
3341
|
+
if (!peer.pending) continue;
|
|
3342
|
+
const from = worldToScreen(peer.pending.from, viewport);
|
|
3343
|
+
const to = worldToScreen(peer.pending.to, viewport);
|
|
3344
|
+
const bounds = {
|
|
3345
|
+
x: Math.min(from.x, to.x),
|
|
3346
|
+
y: Math.min(from.y, to.y),
|
|
3347
|
+
width: Math.abs(to.x - from.x),
|
|
3348
|
+
height: Math.abs(to.y - from.y)
|
|
3349
|
+
};
|
|
3350
|
+
if (!onScreen(bounds, size)) continue;
|
|
3351
|
+
if (!saved) {
|
|
3352
|
+
saved = true;
|
|
3353
|
+
ctx.save();
|
|
3354
|
+
ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);
|
|
3355
|
+
ctx.lineWidth = PENDING_LINE_WIDTH;
|
|
3356
|
+
ctx.setLineDash(PENDING_DASH);
|
|
3357
|
+
}
|
|
3358
|
+
const points = buildPendingPath(peer.pending, handles, viewport);
|
|
3359
|
+
const [first, ...rest] = points;
|
|
3360
|
+
if (!first) continue;
|
|
3361
|
+
ctx.strokeStyle = peer.color;
|
|
3362
|
+
ctx.beginPath();
|
|
3363
|
+
ctx.moveTo(first.x, first.y);
|
|
3364
|
+
for (const point of rest) ctx.lineTo(point.x, point.y);
|
|
3365
|
+
ctx.stroke();
|
|
3366
|
+
ctx.setLineDash([]);
|
|
3367
|
+
ctx.fillStyle = peer.color;
|
|
3368
|
+
ctx.beginPath();
|
|
3369
|
+
ctx.arc(to.x, to.y, PENDING_TIP_RADIUS, 0, Math.PI * 2);
|
|
3370
|
+
ctx.fill();
|
|
3371
|
+
ctx.setLineDash(PENDING_DASH);
|
|
3372
|
+
}
|
|
3373
|
+
if (saved) ctx.restore();
|
|
3374
|
+
}
|
|
3260
3375
|
function drawPeerCursors(ctx, peers, { viewport, size }) {
|
|
3261
3376
|
ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);
|
|
3262
3377
|
ctx.clearRect(0, 0, size.width, size.height);
|
|
@@ -3327,6 +3442,7 @@ function drawAlignmentGuides(ctx, guides, viewport, size) {
|
|
|
3327
3442
|
}
|
|
3328
3443
|
var ENDPOINT_BUBBLE_RADIUS = 6;
|
|
3329
3444
|
var HOVER_KEEP_TOLERANCE = 16;
|
|
3445
|
+
var EMPTY_EDGE_ANCHORS = /* @__PURE__ */ new Map();
|
|
3330
3446
|
function drawEndpointBubbles(ctx, ends, size) {
|
|
3331
3447
|
ctx.save();
|
|
3332
3448
|
ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);
|
|
@@ -3351,6 +3467,8 @@ function useRivetRuntime(params) {
|
|
|
3351
3467
|
const [visibleIds, setVisibleIds] = useState([]);
|
|
3352
3468
|
const reconnectRef = useRef(params);
|
|
3353
3469
|
reconnectRef.current = params;
|
|
3470
|
+
const outlineModeRef = useRef(params.outlineMode);
|
|
3471
|
+
outlineModeRef.current = params.outlineMode;
|
|
3354
3472
|
const sizeRef = useRef({ width: 0, height: 0, dpr: 1 });
|
|
3355
3473
|
const visibleKeyRef = useRef("");
|
|
3356
3474
|
const swimlaneLanesRef = useRef(swimlaneLanes);
|
|
@@ -3457,6 +3575,7 @@ function useRivetRuntime(params) {
|
|
|
3457
3575
|
scrollToPan,
|
|
3458
3576
|
schedule: () => schedule()
|
|
3459
3577
|
});
|
|
3578
|
+
const canReconnect = (edgeId) => store.locks.size() === 0 || store.locks.allows(edgeTargetKey(edgeId), "reconnect");
|
|
3460
3579
|
const render = () => {
|
|
3461
3580
|
zoom.step();
|
|
3462
3581
|
stepPresence();
|
|
@@ -3471,6 +3590,8 @@ function useRivetRuntime(params) {
|
|
|
3471
3590
|
const edgeList = [...store.edges.values()];
|
|
3472
3591
|
const pending = store.getPending();
|
|
3473
3592
|
const liveAlignNodes = store.getEdgeAlignment() === "live" && store.isNodeDragging() ? store.getDraggingNodeIds() : void 0;
|
|
3593
|
+
const outlineMode = outlineModeRef.current;
|
|
3594
|
+
const peerEdges = outlineMode === "none" ? void 0 : collectPeerEdges(store.presence.getPeers(), store.locks.getLockedEdges());
|
|
3474
3595
|
edgeRenderer.draw(edgeList, store.nodes, viewport, {
|
|
3475
3596
|
handles: store.handles,
|
|
3476
3597
|
pending: null,
|
|
@@ -3479,24 +3600,35 @@ function useRivetRuntime(params) {
|
|
|
3479
3600
|
worldPositions,
|
|
3480
3601
|
displayedSides: store.getDisplayedSides(),
|
|
3481
3602
|
liveAlignNodes,
|
|
3482
|
-
anchorPlacement
|
|
3603
|
+
anchorPlacement,
|
|
3604
|
+
peerEdges
|
|
3483
3605
|
});
|
|
3484
3606
|
store.setEdgeLabelAnchors(edgeRenderer.getLabels());
|
|
3607
|
+
if (outlineMode === "dom") {
|
|
3608
|
+
store.setPeerEdgeAnchors(edgeRenderer.getPeerEdgeAnchors?.() ?? EMPTY_EDGE_ANCHORS);
|
|
3609
|
+
}
|
|
3485
3610
|
foregroundRenderer.draw([], store.nodes, viewport, {
|
|
3486
3611
|
handles: store.handles,
|
|
3487
3612
|
pending
|
|
3488
3613
|
});
|
|
3614
|
+
if (fgCtx && !store.presence.isEmpty()) {
|
|
3615
|
+
drawPeerPending(fgCtx, store.presence.getPeers(), {
|
|
3616
|
+
viewport,
|
|
3617
|
+
size,
|
|
3618
|
+
handles: store.handles
|
|
3619
|
+
});
|
|
3620
|
+
}
|
|
3489
3621
|
if (fgCtx) drawAlignmentGuides(fgCtx, store.getAlignmentGuides(), viewport, size);
|
|
3490
3622
|
if (fgCtx) {
|
|
3491
3623
|
const affordanceId = hoveredEdgeId ?? store.getSelectedEdge();
|
|
3492
3624
|
const edge = affordanceId ? store.edges.get(affordanceId) : void 0;
|
|
3493
3625
|
const reconnectable = edge ? edge.reconnectable ?? reconnectRef.current.edgesReconnectable : false;
|
|
3494
|
-
if (edge && reconnectable && edge.id !== pending?.reconnecting) {
|
|
3626
|
+
if (edge && reconnectable && edge.id !== pending?.reconnecting && canReconnect(edge.id)) {
|
|
3495
3627
|
const ends = edgeRenderer.getEndpoints?.().get(edge.id);
|
|
3496
3628
|
if (ends) drawEndpointBubbles(fgCtx, ends, size);
|
|
3497
3629
|
}
|
|
3498
3630
|
}
|
|
3499
|
-
if (fgCtx && (!store.presence.isEmpty() || store.locks.size() > 0)) {
|
|
3631
|
+
if (fgCtx && outlineMode === "canvas" && (!store.presence.isEmpty() || store.locks.size() > 0)) {
|
|
3500
3632
|
drawPeerOutlines(fgCtx, store.presence.getPeers(), {
|
|
3501
3633
|
viewport,
|
|
3502
3634
|
size,
|
|
@@ -3533,6 +3665,7 @@ function useRivetRuntime(params) {
|
|
|
3533
3665
|
setVisibleIds(ids);
|
|
3534
3666
|
}
|
|
3535
3667
|
store.notifyFrame();
|
|
3668
|
+
store.notifyCursorFrame();
|
|
3536
3669
|
};
|
|
3537
3670
|
const tick = () => {
|
|
3538
3671
|
frame = 0;
|
|
@@ -3546,6 +3679,7 @@ function useRivetRuntime(params) {
|
|
|
3546
3679
|
cursorsDirty = false;
|
|
3547
3680
|
stepPresence();
|
|
3548
3681
|
drawCursorLayer();
|
|
3682
|
+
store.notifyCursorFrame();
|
|
3549
3683
|
};
|
|
3550
3684
|
const schedule = () => {
|
|
3551
3685
|
dirty = true;
|
|
@@ -3594,6 +3728,7 @@ function useRivetRuntime(params) {
|
|
|
3594
3728
|
return { x, y: base.y + size2.height / 2 };
|
|
3595
3729
|
};
|
|
3596
3730
|
const beginReconnect = (edge, end) => {
|
|
3731
|
+
if (!canReconnect(edge.id)) return;
|
|
3597
3732
|
zoom.cancel();
|
|
3598
3733
|
const fixedIsSource = end === "target";
|
|
3599
3734
|
const fixedNodeId = fixedIsSource ? edge.source : edge.target;
|
|
@@ -3650,7 +3785,7 @@ function useRivetRuntime(params) {
|
|
|
3650
3785
|
if (hit.edgeId !== hoveredEdgeId && hit.edgeId !== store.getSelectedEdge()) return null;
|
|
3651
3786
|
const edge = store.edges.get(hit.edgeId);
|
|
3652
3787
|
const reconnectable = edge ? edge.reconnectable ?? reconnectRef.current.edgesReconnectable : false;
|
|
3653
|
-
return reconnectable ? hit : null;
|
|
3788
|
+
return reconnectable && canReconnect(hit.edgeId) ? hit : null;
|
|
3654
3789
|
},
|
|
3655
3790
|
begin: (edgeId, end) => {
|
|
3656
3791
|
const edge = store.edges.get(edgeId);
|
|
@@ -3689,7 +3824,7 @@ function useRivetRuntime(params) {
|
|
|
3689
3824
|
}
|
|
3690
3825
|
const hitEdge = edgeRenderer.pick(px, py);
|
|
3691
3826
|
if (hitEdge && store.edges.get(hitEdge)?.selectable !== false) {
|
|
3692
|
-
store.selectEdge(hitEdge);
|
|
3827
|
+
if (store.locks.allows(edgeTargetKey(hitEdge), "select")) store.selectEdge(hitEdge);
|
|
3693
3828
|
return;
|
|
3694
3829
|
}
|
|
3695
3830
|
store.selectNode(null);
|
|
@@ -4033,6 +4168,8 @@ var PICK_TOLERANCE = 6;
|
|
|
4033
4168
|
var ENDPOINT_RADIUS = 12;
|
|
4034
4169
|
var ARROW_SIZE = 9;
|
|
4035
4170
|
var DASH_SPEED = 40;
|
|
4171
|
+
var PEER_HALO_EXTRA = 6;
|
|
4172
|
+
var PEER_HALO_ALPHA = 0.45;
|
|
4036
4173
|
var Canvas2DEdgeRenderer = class {
|
|
4037
4174
|
constructor(canvas, options = {}) {
|
|
4038
4175
|
this.canvas = canvas;
|
|
@@ -4055,6 +4192,8 @@ var Canvas2DEdgeRenderer = class {
|
|
|
4055
4192
|
endpoints = /* @__PURE__ */ new Map();
|
|
4056
4193
|
/** Screen-space label anchor per edge that has a label. */
|
|
4057
4194
|
labels = /* @__PURE__ */ new Map();
|
|
4195
|
+
/** Screen-space midpoint per edge somebody has claimed, for DOM claim chrome. */
|
|
4196
|
+
peerAnchors = /* @__PURE__ */ new Map();
|
|
4058
4197
|
resize(width, height, dpr) {
|
|
4059
4198
|
this.width = width;
|
|
4060
4199
|
this.height = height;
|
|
@@ -4068,6 +4207,10 @@ var Canvas2DEdgeRenderer = class {
|
|
|
4068
4207
|
getLabels() {
|
|
4069
4208
|
return this.labels;
|
|
4070
4209
|
}
|
|
4210
|
+
/** Screen-space midpoints for the edges a peer had claimed last frame. */
|
|
4211
|
+
getPeerEdgeAnchors() {
|
|
4212
|
+
return this.peerAnchors;
|
|
4213
|
+
}
|
|
4071
4214
|
/** Screen-space endpoints per edge from the last frame (reconnect affordance). */
|
|
4072
4215
|
getEndpoints() {
|
|
4073
4216
|
return this.endpoints;
|
|
@@ -4082,11 +4225,23 @@ var Canvas2DEdgeRenderer = class {
|
|
|
4082
4225
|
this.geometry.clear();
|
|
4083
4226
|
this.endpoints.clear();
|
|
4084
4227
|
this.labels.clear();
|
|
4228
|
+
this.peerAnchors.clear();
|
|
4085
4229
|
const resolved = buildEdges(edges, nodes, viewport, this.edgeTypes, this.defaults, extras);
|
|
4230
|
+
const peerEdges = extras?.peerEdges;
|
|
4086
4231
|
for (const edge of resolved) {
|
|
4087
4232
|
this.geometry.set(edge.id, edge.points);
|
|
4088
4233
|
this.endpoints.set(edge.id, { source: edge.source, target: edge.target });
|
|
4089
4234
|
if (edge.label) this.labels.set(edge.id, edge.label);
|
|
4235
|
+
const peerColor2 = peerEdges?.get(edge.id);
|
|
4236
|
+
if (peerColor2) {
|
|
4237
|
+
this.peerAnchors.set(edge.id, polylineMidpoint(edge.points));
|
|
4238
|
+
ctx.strokeStyle = peerColor2;
|
|
4239
|
+
ctx.lineWidth = edge.width + PEER_HALO_EXTRA * 2;
|
|
4240
|
+
ctx.globalAlpha = PEER_HALO_ALPHA;
|
|
4241
|
+
ctx.setLineDash([]);
|
|
4242
|
+
ctx.lineDashOffset = 0;
|
|
4243
|
+
strokePolyline(ctx, edge.points);
|
|
4244
|
+
}
|
|
4090
4245
|
ctx.strokeStyle = edge.stroke;
|
|
4091
4246
|
ctx.lineWidth = edge.width;
|
|
4092
4247
|
ctx.globalAlpha = edge.opacity;
|
|
@@ -4147,6 +4302,7 @@ var Canvas2DEdgeRenderer = class {
|
|
|
4147
4302
|
this.geometry.clear();
|
|
4148
4303
|
this.endpoints.clear();
|
|
4149
4304
|
this.labels.clear();
|
|
4305
|
+
this.peerAnchors.clear();
|
|
4150
4306
|
}
|
|
4151
4307
|
};
|
|
4152
4308
|
var canvas2DEdgeRenderer = (canvas, options) => new Canvas2DEdgeRenderer(canvas, options);
|
|
@@ -4256,7 +4412,6 @@ function EdgeLabelLayer() {
|
|
|
4256
4412
|
}
|
|
4257
4413
|
|
|
4258
4414
|
// src/input/group-drag.ts
|
|
4259
|
-
var DRAG_THRESHOLD = 4;
|
|
4260
4415
|
var ALIGN_THRESHOLD = 6;
|
|
4261
4416
|
function startGroupDrag(params) {
|
|
4262
4417
|
const { store, el, snapGrid, alignmentGuides, onLaneChange, onFrame } = params;
|
|
@@ -4281,6 +4436,7 @@ function startGroupDrag(params) {
|
|
|
4281
4436
|
onFrame?.();
|
|
4282
4437
|
};
|
|
4283
4438
|
const beginDrag = () => {
|
|
4439
|
+
params.selectOnDrag?.();
|
|
4284
4440
|
const movers = store.getMovers(store.getSelectedNodes()).filter((moverId) => store.locks.allows(moverId, "drag"));
|
|
4285
4441
|
if (movers.length === 0) return false;
|
|
4286
4442
|
started = true;
|
|
@@ -4409,6 +4565,37 @@ function clampToParent(store, parentId, position, size) {
|
|
|
4409
4565
|
};
|
|
4410
4566
|
return clampChildToParent(position, size, parentSize);
|
|
4411
4567
|
}
|
|
4568
|
+
|
|
4569
|
+
// src/anchor/select-gesture.ts
|
|
4570
|
+
function attachAnchorSelection(store, record) {
|
|
4571
|
+
const element = record.element;
|
|
4572
|
+
if (!record.selectable || !(element instanceof HTMLElement || element instanceof SVGElement)) {
|
|
4573
|
+
return null;
|
|
4574
|
+
}
|
|
4575
|
+
const { nodeId, anchorId } = record;
|
|
4576
|
+
const previous = element.style.pointerEvents;
|
|
4577
|
+
element.style.pointerEvents = "auto";
|
|
4578
|
+
const onPointerDown = (event) => {
|
|
4579
|
+
if (!(event instanceof MouseEvent)) return;
|
|
4580
|
+
if (event.button !== 0) return;
|
|
4581
|
+
const originX = event.clientX;
|
|
4582
|
+
const originY = event.clientY;
|
|
4583
|
+
const onUp = (upEvent) => {
|
|
4584
|
+
window.removeEventListener("pointerup", onUp);
|
|
4585
|
+
if (!(upEvent instanceof MouseEvent)) return;
|
|
4586
|
+
const moved = Math.hypot(upEvent.clientX - originX, upEvent.clientY - originY);
|
|
4587
|
+
if (moved >= DRAG_THRESHOLD) return;
|
|
4588
|
+
if (!store.locks.allows(anchorTargetKey(nodeId, anchorId), "select")) return;
|
|
4589
|
+
store.setSelectedAnchors([{ nodeId, anchorId }]);
|
|
4590
|
+
};
|
|
4591
|
+
window.addEventListener("pointerup", onUp);
|
|
4592
|
+
};
|
|
4593
|
+
element.addEventListener("pointerdown", onPointerDown);
|
|
4594
|
+
return () => {
|
|
4595
|
+
element.removeEventListener("pointerdown", onPointerDown);
|
|
4596
|
+
element.style.pointerEvents = previous;
|
|
4597
|
+
};
|
|
4598
|
+
}
|
|
4412
4599
|
var DEFAULT_ANCHOR_COLOR = "#6366f1";
|
|
4413
4600
|
function NodeAnchors({ nodeId }) {
|
|
4414
4601
|
const { store, anchorOptions } = useRivetContext();
|
|
@@ -4417,8 +4604,27 @@ function NodeAnchors({ nodeId }) {
|
|
|
4417
4604
|
[store, nodeId]
|
|
4418
4605
|
);
|
|
4419
4606
|
const getAnchorsVersion = useCallback(() => store.getNodeAnchorsVersion(nodeId), [store, nodeId]);
|
|
4420
|
-
useSyncExternalStore(
|
|
4607
|
+
const anchorsVersion = useSyncExternalStore(
|
|
4608
|
+
subscribeAnchors,
|
|
4609
|
+
getAnchorsVersion,
|
|
4610
|
+
getAnchorsVersion
|
|
4611
|
+
);
|
|
4421
4612
|
useSyncExternalStore(store.subscribeEdges, store.getEdgesVersion, store.getEdgesVersion);
|
|
4613
|
+
useSyncExternalStore(
|
|
4614
|
+
store.subscribeAnchorSelection,
|
|
4615
|
+
store.getSelectedAnchors,
|
|
4616
|
+
store.getSelectedAnchors
|
|
4617
|
+
);
|
|
4618
|
+
useEffect(() => {
|
|
4619
|
+
const cleanups = [];
|
|
4620
|
+
for (const record of store.getNodeAnchors(nodeId)) {
|
|
4621
|
+
const cleanup = attachAnchorSelection(store, record);
|
|
4622
|
+
if (cleanup) cleanups.push(cleanup);
|
|
4623
|
+
}
|
|
4624
|
+
return () => {
|
|
4625
|
+
for (const cleanup of cleanups) cleanup();
|
|
4626
|
+
};
|
|
4627
|
+
}, [store, nodeId, anchorsVersion]);
|
|
4422
4628
|
const records = store.getNodeAnchors(nodeId);
|
|
4423
4629
|
if (records.length === 0) return null;
|
|
4424
4630
|
const dotsVisible = Boolean(store.nodes.get(nodeId)?.hovered);
|
|
@@ -4436,6 +4642,7 @@ function NodeAnchors({ nodeId }) {
|
|
|
4436
4642
|
}
|
|
4437
4643
|
}
|
|
4438
4644
|
return /* @__PURE__ */ jsx(Fragment, { children: records.map((record) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
4645
|
+
store.isAnchorSelected(nodeId, record.anchorId) && /* @__PURE__ */ jsx(AnchorSelectionOutline, { record }),
|
|
4439
4646
|
/* @__PURE__ */ jsx(AnchorDots, { record, options: anchorOptions, visible: dotsVisible }),
|
|
4440
4647
|
record.strays !== "none" && /* @__PURE__ */ jsx(
|
|
4441
4648
|
AnchorStrayHandles,
|
|
@@ -4447,6 +4654,31 @@ function NodeAnchors({ nodeId }) {
|
|
|
4447
4654
|
)
|
|
4448
4655
|
] }, record.anchorId)) });
|
|
4449
4656
|
}
|
|
4657
|
+
function AnchorSelectionOutline({ record }) {
|
|
4658
|
+
const geometry = record.geometry;
|
|
4659
|
+
if (!geometry) return null;
|
|
4660
|
+
const { dots } = geometry;
|
|
4661
|
+
const left = dots.left.xPct;
|
|
4662
|
+
const top = dots.top.yPct;
|
|
4663
|
+
return /* @__PURE__ */ jsx(
|
|
4664
|
+
"div",
|
|
4665
|
+
{
|
|
4666
|
+
"data-rivet-anchor-selected": record.anchorId,
|
|
4667
|
+
style: {
|
|
4668
|
+
position: "absolute",
|
|
4669
|
+
left: `${left}%`,
|
|
4670
|
+
top: `${top}%`,
|
|
4671
|
+
width: `${dots.right.xPct - left}%`,
|
|
4672
|
+
height: `${dots.bottom.yPct - top}%`,
|
|
4673
|
+
border: `1px solid ${record.color ?? DEFAULT_ANCHOR_COLOR}`,
|
|
4674
|
+
borderRadius: 2,
|
|
4675
|
+
// The box is a readout, never a target: presses belong to the element
|
|
4676
|
+
// underneath it, which is what put the selection here.
|
|
4677
|
+
pointerEvents: "none"
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
);
|
|
4681
|
+
}
|
|
4450
4682
|
function AnchorDots(props) {
|
|
4451
4683
|
const { record, options } = props;
|
|
4452
4684
|
if (!record.geometry || !record.element?.isConnected) return null;
|
|
@@ -4665,7 +4897,11 @@ var NodeWrapper = memo(function NodeWrapper2({ id }) {
|
|
|
4665
4897
|
if (!noSelect) store.selectNode(id, true);
|
|
4666
4898
|
return;
|
|
4667
4899
|
}
|
|
4668
|
-
|
|
4900
|
+
const onAnchor = target !== null && findSelectableAnchor(store.getNodeAnchors(id), target) !== null;
|
|
4901
|
+
const selectNode = () => {
|
|
4902
|
+
if (!noSelect && !store.isNodeSelected(id)) store.selectNode(id);
|
|
4903
|
+
};
|
|
4904
|
+
if (!onAnchor) selectNode();
|
|
4669
4905
|
if (noDrag) return;
|
|
4670
4906
|
startGroupDrag({
|
|
4671
4907
|
store,
|
|
@@ -4678,7 +4914,8 @@ var NodeWrapper = memo(function NodeWrapper2({ id }) {
|
|
|
4678
4914
|
clampToSwimlane,
|
|
4679
4915
|
swimlaneMargin,
|
|
4680
4916
|
swimlaneLabelWidth,
|
|
4681
|
-
onLaneChange
|
|
4917
|
+
onLaneChange,
|
|
4918
|
+
selectOnDrag: onAnchor ? selectNode : void 0
|
|
4682
4919
|
});
|
|
4683
4920
|
};
|
|
4684
4921
|
const node = store.nodes.get(id);
|
|
@@ -4835,6 +5072,176 @@ function NodeLayer({ containerRef, visibleIds }) {
|
|
|
4835
5072
|
/* @__PURE__ */ jsx(NodesSelection, {})
|
|
4836
5073
|
] });
|
|
4837
5074
|
}
|
|
5075
|
+
var overlayStyle2 = {
|
|
5076
|
+
position: "absolute",
|
|
5077
|
+
inset: 0,
|
|
5078
|
+
// Cursor chrome belongs to the canvas: clipped to the pane rather than
|
|
5079
|
+
// escaping into whatever app UI surrounds it.
|
|
5080
|
+
overflow: "hidden",
|
|
5081
|
+
pointerEvents: "none"
|
|
5082
|
+
};
|
|
5083
|
+
var cursorStyle = {
|
|
5084
|
+
position: "absolute",
|
|
5085
|
+
top: 0,
|
|
5086
|
+
left: 0,
|
|
5087
|
+
// The wrapper is a point, not a box: it sits at the pointer tip and whatever
|
|
5088
|
+
// the consumer renders lays itself out from there.
|
|
5089
|
+
width: 0,
|
|
5090
|
+
height: 0,
|
|
5091
|
+
pointerEvents: "none"
|
|
5092
|
+
};
|
|
5093
|
+
function PeerCursorLayer({
|
|
5094
|
+
component: Cursor
|
|
5095
|
+
}) {
|
|
5096
|
+
const { store, paneRef } = useRivetContext();
|
|
5097
|
+
const peers = usePeerIdentities();
|
|
5098
|
+
const refs = useRef(/* @__PURE__ */ new Map());
|
|
5099
|
+
const zoomRef = useRef(null);
|
|
5100
|
+
const zoomWritten = useRef(/* @__PURE__ */ new WeakSet());
|
|
5101
|
+
const position = useCallback(() => {
|
|
5102
|
+
const pane = paneRef.current;
|
|
5103
|
+
if (!pane) return;
|
|
5104
|
+
const viewport = store.getViewport();
|
|
5105
|
+
const zoomChanged = zoomRef.current !== viewport.zoom;
|
|
5106
|
+
zoomRef.current = viewport.zoom;
|
|
5107
|
+
const { width, height } = pane.getBoundingClientRect();
|
|
5108
|
+
const live = new Map(store.presence.getPeers().map((peer) => [peer.id, peer.cursor]));
|
|
5109
|
+
for (const [id, el] of refs.current) {
|
|
5110
|
+
if (!el) continue;
|
|
5111
|
+
const cursor = live.get(id);
|
|
5112
|
+
if (!cursor) {
|
|
5113
|
+
el.style.display = "none";
|
|
5114
|
+
continue;
|
|
5115
|
+
}
|
|
5116
|
+
el.style.display = "";
|
|
5117
|
+
const point = worldToScreen(cursor, viewport);
|
|
5118
|
+
const x = Math.min(Math.max(point.x, 0), width);
|
|
5119
|
+
const y = Math.min(Math.max(point.y, 0), height);
|
|
5120
|
+
const offscreen = x !== point.x || y !== point.y;
|
|
5121
|
+
el.style.transform = `translate(${x}px, ${y}px)`;
|
|
5122
|
+
el.style.visibility = offscreen ? "hidden" : "";
|
|
5123
|
+
if (offscreen) el.setAttribute("data-rivet-offscreen", "");
|
|
5124
|
+
else el.removeAttribute("data-rivet-offscreen");
|
|
5125
|
+
if (zoomChanged || !zoomWritten.current.has(el)) {
|
|
5126
|
+
el.style.setProperty("--rivet-zoom", String(viewport.zoom));
|
|
5127
|
+
zoomWritten.current.add(el);
|
|
5128
|
+
}
|
|
5129
|
+
}
|
|
5130
|
+
}, [store, paneRef]);
|
|
5131
|
+
useEffect(() => {
|
|
5132
|
+
return store.subscribeCursorFrame(position);
|
|
5133
|
+
}, [store, position]);
|
|
5134
|
+
useLayoutEffect(position);
|
|
5135
|
+
return /* @__PURE__ */ jsx("div", { style: overlayStyle2, children: peers.map((peer) => /* @__PURE__ */ jsx(
|
|
5136
|
+
"div",
|
|
5137
|
+
{
|
|
5138
|
+
ref: (el) => {
|
|
5139
|
+
if (el) refs.current.set(peer.id, el);
|
|
5140
|
+
else refs.current.delete(peer.id);
|
|
5141
|
+
},
|
|
5142
|
+
style: { ...cursorStyle, display: "none" },
|
|
5143
|
+
"data-rivet-peer-cursor": peer.id,
|
|
5144
|
+
children: /* @__PURE__ */ jsx(Cursor, { peer })
|
|
5145
|
+
},
|
|
5146
|
+
peer.id
|
|
5147
|
+
)) });
|
|
5148
|
+
}
|
|
5149
|
+
var overlayStyle3 = {
|
|
5150
|
+
position: "absolute",
|
|
5151
|
+
inset: 0,
|
|
5152
|
+
// Claim chrome belongs to the canvas, so a box that has been panned off the
|
|
5153
|
+
// pane is clipped rather than left hanging over the app around it.
|
|
5154
|
+
overflow: "hidden",
|
|
5155
|
+
pointerEvents: "none"
|
|
5156
|
+
};
|
|
5157
|
+
var wrapperStyle2 = {
|
|
5158
|
+
position: "absolute",
|
|
5159
|
+
top: 0,
|
|
5160
|
+
left: 0,
|
|
5161
|
+
pointerEvents: "none"
|
|
5162
|
+
};
|
|
5163
|
+
function projectRect2(rect, viewport) {
|
|
5164
|
+
const origin = worldToScreen({ x: rect.x, y: rect.y }, viewport);
|
|
5165
|
+
return {
|
|
5166
|
+
x: origin.x,
|
|
5167
|
+
y: origin.y,
|
|
5168
|
+
width: rect.width * viewport.zoom,
|
|
5169
|
+
height: rect.height * viewport.zoom
|
|
5170
|
+
};
|
|
5171
|
+
}
|
|
5172
|
+
function PeerOutlineLayer({
|
|
5173
|
+
component: Outline
|
|
5174
|
+
}) {
|
|
5175
|
+
const { store } = useRivetContext();
|
|
5176
|
+
const [entries, setEntries] = useState([]);
|
|
5177
|
+
const refs = useRef(/* @__PURE__ */ new Map());
|
|
5178
|
+
const zoomRef = useRef(null);
|
|
5179
|
+
const zoomWritten = useRef(/* @__PURE__ */ new WeakSet());
|
|
5180
|
+
const rectOf = useCallback(
|
|
5181
|
+
(target, viewport) => {
|
|
5182
|
+
if (target.kind === "edge") {
|
|
5183
|
+
const point = store.getPeerEdgeAnchors().get(target.id);
|
|
5184
|
+
return point ? { x: point.x, y: point.y, width: 0, height: 0 } : null;
|
|
5185
|
+
}
|
|
5186
|
+
const nodeId = target.kind === "node" ? target.id : target.nodeId;
|
|
5187
|
+
if (!store.nodes.has(nodeId)) return null;
|
|
5188
|
+
const node = store.getNodeRect(nodeId);
|
|
5189
|
+
if (target.kind === "node") return projectRect2(node, viewport);
|
|
5190
|
+
const record = store.anchors.get(handleKey(nodeId, target.anchorId));
|
|
5191
|
+
if (!record?.geometry) return null;
|
|
5192
|
+
return projectRect2(anchorRect(node, record.geometry), viewport);
|
|
5193
|
+
},
|
|
5194
|
+
[store]
|
|
5195
|
+
);
|
|
5196
|
+
const position = useCallback(() => {
|
|
5197
|
+
const viewport = store.getViewport();
|
|
5198
|
+
const zoomChanged = zoomRef.current !== viewport.zoom;
|
|
5199
|
+
zoomRef.current = viewport.zoom;
|
|
5200
|
+
for (const entry of entries) {
|
|
5201
|
+
const el = refs.current.get(entry.key);
|
|
5202
|
+
if (!el) continue;
|
|
5203
|
+
const rect = rectOf(entry.target, viewport);
|
|
5204
|
+
if (!rect) {
|
|
5205
|
+
el.style.display = "none";
|
|
5206
|
+
continue;
|
|
5207
|
+
}
|
|
5208
|
+
el.style.display = "";
|
|
5209
|
+
el.style.transform = `translate(${rect.x}px, ${rect.y}px)`;
|
|
5210
|
+
el.style.width = `${rect.width}px`;
|
|
5211
|
+
el.style.height = `${rect.height}px`;
|
|
5212
|
+
if (zoomChanged || !zoomWritten.current.has(el)) {
|
|
5213
|
+
el.style.setProperty("--rivet-zoom", String(viewport.zoom));
|
|
5214
|
+
zoomWritten.current.add(el);
|
|
5215
|
+
}
|
|
5216
|
+
}
|
|
5217
|
+
}, [store, entries, rectOf]);
|
|
5218
|
+
useEffect(() => {
|
|
5219
|
+
return store.subscribeFrame(() => {
|
|
5220
|
+
const next = collectPeerOutlines(
|
|
5221
|
+
store.presence.getPeers(),
|
|
5222
|
+
store.presence.getPeerIdentities(),
|
|
5223
|
+
store.locks.getLocks()
|
|
5224
|
+
);
|
|
5225
|
+
setEntries((prev) => peerOutlinesEqual(prev, next) ? prev : next);
|
|
5226
|
+
position();
|
|
5227
|
+
});
|
|
5228
|
+
}, [store, position]);
|
|
5229
|
+
useLayoutEffect(position);
|
|
5230
|
+
return /* @__PURE__ */ jsx("div", { style: overlayStyle3, children: entries.map((entry) => /* @__PURE__ */ jsx(
|
|
5231
|
+
"div",
|
|
5232
|
+
{
|
|
5233
|
+
ref: (el) => {
|
|
5234
|
+
if (el) refs.current.set(entry.key, el);
|
|
5235
|
+
else refs.current.delete(entry.key);
|
|
5236
|
+
},
|
|
5237
|
+
style: { ...wrapperStyle2, display: "none" },
|
|
5238
|
+
"data-rivet-peer-outline": entry.key,
|
|
5239
|
+
"data-rivet-outline-kind": entry.target.kind,
|
|
5240
|
+
children: /* @__PURE__ */ jsx(Outline, { target: entry.target, claims: entry.claims, lock: entry.lock })
|
|
5241
|
+
},
|
|
5242
|
+
entry.key
|
|
5243
|
+
)) });
|
|
5244
|
+
}
|
|
4838
5245
|
var containerStyle2 = {
|
|
4839
5246
|
position: "absolute",
|
|
4840
5247
|
inset: 0,
|
|
@@ -5282,6 +5689,7 @@ function Rivet({
|
|
|
5282
5689
|
store.setLockedNodes(lockedNodes);
|
|
5283
5690
|
}, [store, lockedNodes]);
|
|
5284
5691
|
useLocalPresence({ store, paneRef, onLocalPresence, throttleMs: cfg.presenceOptions.throttleMs });
|
|
5692
|
+
const outlineMode = !cfg.presenceOptions.renderOutlines ? "none" : cfg.presenceOptions.outlineComponent ? "dom" : "canvas";
|
|
5285
5693
|
const { visibleIds, controls, getViewportElements } = useRivetRuntime({
|
|
5286
5694
|
store,
|
|
5287
5695
|
paneRef,
|
|
@@ -5290,6 +5698,7 @@ function Rivet({
|
|
|
5290
5698
|
edgeCanvasRef,
|
|
5291
5699
|
foregroundCanvasRef,
|
|
5292
5700
|
cursorCanvasRef,
|
|
5701
|
+
outlineMode,
|
|
5293
5702
|
swimlaneLanes: swimlanes.lanes,
|
|
5294
5703
|
edgeTypes: cfg.edgeTypes,
|
|
5295
5704
|
defaultEdgeOptions: cfg.defaultEdgeOptions,
|
|
@@ -5382,7 +5791,8 @@ function Rivet({
|
|
|
5382
5791
|
/* @__PURE__ */ jsx("canvas", { ref: edgeCanvasRef, style: canvasStyle }),
|
|
5383
5792
|
/* @__PURE__ */ jsx(NodeLayer, { containerRef: nodeContainerRef, visibleIds }),
|
|
5384
5793
|
/* @__PURE__ */ jsx("canvas", { ref: foregroundCanvasRef, style: canvasStyle }),
|
|
5385
|
-
cfg.presenceOptions.
|
|
5794
|
+
outlineMode === "dom" && cfg.presenceOptions.outlineComponent && /* @__PURE__ */ jsx(PeerOutlineLayer, { component: cfg.presenceOptions.outlineComponent }),
|
|
5795
|
+
cfg.presenceOptions.renderCursors && (cfg.presenceOptions.cursorComponent ? /* @__PURE__ */ jsx(PeerCursorLayer, { component: cfg.presenceOptions.cursorComponent }) : /* @__PURE__ */ jsx("canvas", { ref: cursorCanvasRef, style: canvasStyle })),
|
|
5386
5796
|
/* @__PURE__ */ jsx(EdgeLabelLayer, {}),
|
|
5387
5797
|
/* @__PURE__ */ jsx(SwimlaneOverlay, {}),
|
|
5388
5798
|
children,
|
|
@@ -5480,8 +5890,12 @@ function buildInstance(store, controls, getViewportElements) {
|
|
|
5480
5890
|
},
|
|
5481
5891
|
unregisterAnchor: (nodeId, anchorId) => store.unregisterAnchor(nodeId, anchorId),
|
|
5482
5892
|
remeasureAnchors: (nodeId) => store.remeasureAnchors(nodeId),
|
|
5893
|
+
getAnchor: (nodeId, anchorId) => store.getNodeAnchors(nodeId).find((record) => record.anchorId === anchorId) ?? null,
|
|
5894
|
+
setSelectedAnchors: (refs) => store.setSelectedAnchors(refs),
|
|
5895
|
+
getSelectedAnchors: () => store.getSelectedAnchors(),
|
|
5483
5896
|
setPeerCursor: (peerId, point) => store.presence.setPeerCursor(peerId, point),
|
|
5484
5897
|
setPeerNodeTransform: (peerId, nodeId, rect) => store.presence.setPeerNodeTransform(peerId, nodeId, rect),
|
|
5898
|
+
setPeerConnection: (peerId, connection) => store.presence.setPeerConnection(peerId, connection),
|
|
5485
5899
|
removePeer: (peerId) => store.presence.removePeer(peerId),
|
|
5486
5900
|
releaseNodeGesture: (id, ids) => store.endNodeGesture(id, ids),
|
|
5487
5901
|
copy: (ids) => {
|
|
@@ -5523,6 +5937,6 @@ function useRivet() {
|
|
|
5523
5937
|
// src/index.ts
|
|
5524
5938
|
var VERSION = "0.0.0";
|
|
5525
5939
|
|
|
5526
|
-
export { BUILTIN_EDGE_TYPES, BUILTIN_NODE_TYPES, Canvas2DEdgeRenderer, Controls, DEFAULT_ALIGNMENT_HYSTERESIS, DefaultNode, GroupNode, Handle, MiniMap, NodeResizer, Rivet, VERSION, alignRect, applyEdgeChanges, applyNodeChanges,
|
|
5940
|
+
export { BUILTIN_EDGE_TYPES, BUILTIN_NODE_TYPES, Canvas2DEdgeRenderer, Controls, DEFAULT_ALIGNMENT_HYSTERESIS, DefaultNode, GroupNode, Handle, MiniMap, NodeResizer, Rivet, VERSION, alignRect, applyEdgeChanges, applyNodeChanges, canvas2DEdgeRenderer, cloneElements, createRivetStore, edgeEndpointHandle, facingSide, getBezierPath, getSmoothStepPath, getStepPath, getStraightPath, handleKey, parseEdgeEndpoint, parseSideHandleId, rectsIntersect, resolveFacingSide, resolveFacingSideAmong, screenToWorld, useRivet, viewportToCss, visibleWorldRect, worldToScreen, zoomAt };
|
|
5527
5941
|
//# sourceMappingURL=index.js.map
|
|
5528
5942
|
//# sourceMappingURL=index.js.map
|