@coral-viz/viz 0.2.3

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.
Files changed (191) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +11 -0
  3. package/dist/compatibility/CompatibilityEdge.d.ts +106 -0
  4. package/dist/compatibility/CompatibilityEdge.d.ts.map +1 -0
  5. package/dist/compatibility/CompatibilityEdge.js +233 -0
  6. package/dist/compatibility/CompatibilityEdge.js.map +1 -0
  7. package/dist/compatibility/IncompatibilityTooltip.d.ts +44 -0
  8. package/dist/compatibility/IncompatibilityTooltip.d.ts.map +1 -0
  9. package/dist/compatibility/IncompatibilityTooltip.js +145 -0
  10. package/dist/compatibility/IncompatibilityTooltip.js.map +1 -0
  11. package/dist/compatibility/index.d.ts +10 -0
  12. package/dist/compatibility/index.d.ts.map +1 -0
  13. package/dist/compatibility/index.js +10 -0
  14. package/dist/compatibility/index.js.map +1 -0
  15. package/dist/compatibility/useEdgeCompatibility.d.ts +82 -0
  16. package/dist/compatibility/useEdgeCompatibility.d.ts.map +1 -0
  17. package/dist/compatibility/useEdgeCompatibility.js +170 -0
  18. package/dist/compatibility/useEdgeCompatibility.js.map +1 -0
  19. package/dist/compatibility/validateConnection.d.ts +56 -0
  20. package/dist/compatibility/validateConnection.d.ts.map +1 -0
  21. package/dist/compatibility/validateConnection.js +382 -0
  22. package/dist/compatibility/validateConnection.js.map +1 -0
  23. package/dist/components/EditContext.d.ts +45 -0
  24. package/dist/components/EditContext.d.ts.map +1 -0
  25. package/dist/components/EditContext.js +41 -0
  26. package/dist/components/EditContext.js.map +1 -0
  27. package/dist/components/ShapeRenderer.d.ts +35 -0
  28. package/dist/components/ShapeRenderer.d.ts.map +1 -0
  29. package/dist/components/ShapeRenderer.js +77 -0
  30. package/dist/components/ShapeRenderer.js.map +1 -0
  31. package/dist/components/SymbolNode.d.ts +53 -0
  32. package/dist/components/SymbolNode.d.ts.map +1 -0
  33. package/dist/components/SymbolNode.js +333 -0
  34. package/dist/components/SymbolNode.js.map +1 -0
  35. package/dist/components/index.d.ts +8 -0
  36. package/dist/components/index.d.ts.map +1 -0
  37. package/dist/components/index.js +10 -0
  38. package/dist/components/index.js.map +1 -0
  39. package/dist/components/nodes.d.ts +43 -0
  40. package/dist/components/nodes.d.ts.map +1 -0
  41. package/dist/components/nodes.js +111 -0
  42. package/dist/components/nodes.js.map +1 -0
  43. package/dist/editor/CoralEditor.d.ts +29 -0
  44. package/dist/editor/CoralEditor.d.ts.map +1 -0
  45. package/dist/editor/CoralEditor.js +112 -0
  46. package/dist/editor/CoralEditor.js.map +1 -0
  47. package/dist/editor/FileControls.d.ts +34 -0
  48. package/dist/editor/FileControls.d.ts.map +1 -0
  49. package/dist/editor/FileControls.js +139 -0
  50. package/dist/editor/FileControls.js.map +1 -0
  51. package/dist/editor/LayoutControls.d.ts +41 -0
  52. package/dist/editor/LayoutControls.d.ts.map +1 -0
  53. package/dist/editor/LayoutControls.js +124 -0
  54. package/dist/editor/LayoutControls.js.map +1 -0
  55. package/dist/editor/converter.d.ts +37 -0
  56. package/dist/editor/converter.d.ts.map +1 -0
  57. package/dist/editor/converter.js +256 -0
  58. package/dist/editor/converter.js.map +1 -0
  59. package/dist/editor/index.d.ts +8 -0
  60. package/dist/editor/index.d.ts.map +1 -0
  61. package/dist/editor/index.js +8 -0
  62. package/dist/editor/index.js.map +1 -0
  63. package/dist/file/deserialize.d.ts +15 -0
  64. package/dist/file/deserialize.d.ts.map +1 -0
  65. package/dist/file/deserialize.js +145 -0
  66. package/dist/file/deserialize.js.map +1 -0
  67. package/dist/file/index.d.ts +15 -0
  68. package/dist/file/index.d.ts.map +1 -0
  69. package/dist/file/index.js +20 -0
  70. package/dist/file/index.js.map +1 -0
  71. package/dist/file/migrate.d.ts +29 -0
  72. package/dist/file/migrate.d.ts.map +1 -0
  73. package/dist/file/migrate.js +103 -0
  74. package/dist/file/migrate.js.map +1 -0
  75. package/dist/file/schema.d.ts +385 -0
  76. package/dist/file/schema.d.ts.map +1 -0
  77. package/dist/file/schema.js +180 -0
  78. package/dist/file/schema.js.map +1 -0
  79. package/dist/file/serialize.d.ts +30 -0
  80. package/dist/file/serialize.d.ts.map +1 -0
  81. package/dist/file/serialize.js +218 -0
  82. package/dist/file/serialize.js.map +1 -0
  83. package/dist/file/validate.d.ts +21 -0
  84. package/dist/file/validate.d.ts.map +1 -0
  85. package/dist/file/validate.js +165 -0
  86. package/dist/file/validate.js.map +1 -0
  87. package/dist/index.d.ts +24 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +42 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/layout/elk.d.ts +77 -0
  92. package/dist/layout/elk.d.ts.map +1 -0
  93. package/dist/layout/elk.js +379 -0
  94. package/dist/layout/elk.js.map +1 -0
  95. package/dist/layout/index.d.ts +12 -0
  96. package/dist/layout/index.d.ts.map +1 -0
  97. package/dist/layout/index.js +12 -0
  98. package/dist/layout/index.js.map +1 -0
  99. package/dist/layout/nodeSizing.d.ts +65 -0
  100. package/dist/layout/nodeSizing.d.ts.map +1 -0
  101. package/dist/layout/nodeSizing.js +319 -0
  102. package/dist/layout/nodeSizing.js.map +1 -0
  103. package/dist/layout/positionStability.d.ts +73 -0
  104. package/dist/layout/positionStability.d.ts.map +1 -0
  105. package/dist/layout/positionStability.js +199 -0
  106. package/dist/layout/positionStability.js.map +1 -0
  107. package/dist/layout/useAxisConstrain.d.ts +20 -0
  108. package/dist/layout/useAxisConstrain.d.ts.map +1 -0
  109. package/dist/layout/useAxisConstrain.js +106 -0
  110. package/dist/layout/useAxisConstrain.js.map +1 -0
  111. package/dist/layout/useDiagramState.d.ts +92 -0
  112. package/dist/layout/useDiagramState.d.ts.map +1 -0
  113. package/dist/layout/useDiagramState.js +256 -0
  114. package/dist/layout/useDiagramState.js.map +1 -0
  115. package/dist/layout/useLayoutHistory.d.ts +53 -0
  116. package/dist/layout/useLayoutHistory.d.ts.map +1 -0
  117. package/dist/layout/useLayoutHistory.js +124 -0
  118. package/dist/layout/useLayoutHistory.js.map +1 -0
  119. package/dist/properties/NodePropertiesPanel.d.ts +47 -0
  120. package/dist/properties/NodePropertiesPanel.d.ts.map +1 -0
  121. package/dist/properties/NodePropertiesPanel.js +199 -0
  122. package/dist/properties/NodePropertiesPanel.js.map +1 -0
  123. package/dist/properties/index.d.ts +10 -0
  124. package/dist/properties/index.d.ts.map +1 -0
  125. package/dist/properties/index.js +10 -0
  126. package/dist/properties/index.js.map +1 -0
  127. package/dist/properties/propertyUtils.d.ts +60 -0
  128. package/dist/properties/propertyUtils.d.ts.map +1 -0
  129. package/dist/properties/propertyUtils.js +89 -0
  130. package/dist/properties/propertyUtils.js.map +1 -0
  131. package/dist/settings/FontSettingsForm.d.ts +28 -0
  132. package/dist/settings/FontSettingsForm.d.ts.map +1 -0
  133. package/dist/settings/FontSettingsForm.js +129 -0
  134. package/dist/settings/FontSettingsForm.js.map +1 -0
  135. package/dist/settings/LayoutSettingsForm.d.ts +37 -0
  136. package/dist/settings/LayoutSettingsForm.d.ts.map +1 -0
  137. package/dist/settings/LayoutSettingsForm.js +165 -0
  138. package/dist/settings/LayoutSettingsForm.js.map +1 -0
  139. package/dist/settings/SettingsPanel.d.ts +55 -0
  140. package/dist/settings/SettingsPanel.d.ts.map +1 -0
  141. package/dist/settings/SettingsPanel.js +84 -0
  142. package/dist/settings/SettingsPanel.js.map +1 -0
  143. package/dist/settings/index.d.ts +13 -0
  144. package/dist/settings/index.d.ts.map +1 -0
  145. package/dist/settings/index.js +13 -0
  146. package/dist/settings/index.js.map +1 -0
  147. package/dist/settings/useSettings.d.ts +51 -0
  148. package/dist/settings/useSettings.d.ts.map +1 -0
  149. package/dist/settings/useSettings.js +154 -0
  150. package/dist/settings/useSettings.js.map +1 -0
  151. package/dist/text-editor/SplitEditor.d.ts +72 -0
  152. package/dist/text-editor/SplitEditor.d.ts.map +1 -0
  153. package/dist/text-editor/SplitEditor.js +172 -0
  154. package/dist/text-editor/SplitEditor.js.map +1 -0
  155. package/dist/text-editor/TextEditor.d.ts +53 -0
  156. package/dist/text-editor/TextEditor.d.ts.map +1 -0
  157. package/dist/text-editor/TextEditor.js +181 -0
  158. package/dist/text-editor/TextEditor.js.map +1 -0
  159. package/dist/text-editor/hooks/useBidirectionalSync.d.ts +106 -0
  160. package/dist/text-editor/hooks/useBidirectionalSync.d.ts.map +1 -0
  161. package/dist/text-editor/hooks/useBidirectionalSync.js +151 -0
  162. package/dist/text-editor/hooks/useBidirectionalSync.js.map +1 -0
  163. package/dist/text-editor/index.d.ts +9 -0
  164. package/dist/text-editor/index.d.ts.map +1 -0
  165. package/dist/text-editor/index.js +11 -0
  166. package/dist/text-editor/index.js.map +1 -0
  167. package/dist/types.d.ts +242 -0
  168. package/dist/types.d.ts.map +1 -0
  169. package/dist/types.js +5 -0
  170. package/dist/types.js.map +1 -0
  171. package/dist/waypoints/index.d.ts +8 -0
  172. package/dist/waypoints/index.d.ts.map +1 -0
  173. package/dist/waypoints/index.js +7 -0
  174. package/dist/waypoints/index.js.map +1 -0
  175. package/dist/waypoints/operations.d.ts +29 -0
  176. package/dist/waypoints/operations.d.ts.map +1 -0
  177. package/dist/waypoints/operations.js +85 -0
  178. package/dist/waypoints/operations.js.map +1 -0
  179. package/dist/waypoints/router.d.ts +23 -0
  180. package/dist/waypoints/router.d.ts.map +1 -0
  181. package/dist/waypoints/router.js +109 -0
  182. package/dist/waypoints/router.js.map +1 -0
  183. package/dist/waypoints/types.d.ts +15 -0
  184. package/dist/waypoints/types.d.ts.map +1 -0
  185. package/dist/waypoints/types.js +5 -0
  186. package/dist/waypoints/types.js.map +1 -0
  187. package/dist/waypoints/useWaypointManager.d.ts +38 -0
  188. package/dist/waypoints/useWaypointManager.d.ts.map +1 -0
  189. package/dist/waypoints/useWaypointManager.js +106 -0
  190. package/dist/waypoints/useWaypointManager.js.map +1 -0
  191. package/package.json +76 -0
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Pure waypoint operations (CORAL-REQ-015)
3
+ *
4
+ * All functions are immutable — they return new arrays.
5
+ */
6
+ let counter = 0;
7
+ /** Create a new waypoint with a unique ID */
8
+ export function createWaypoint(x, y, type = 'corner') {
9
+ return { id: `wp-${Date.now()}-${++counter}`, x, y, type };
10
+ }
11
+ /** Add a waypoint to the end of an edge's waypoint list */
12
+ export function addWaypointToEdge(waypoints, waypoint) {
13
+ return [...waypoints, waypoint];
14
+ }
15
+ /** Remove a waypoint by ID */
16
+ export function removeWaypointFromEdge(waypoints, waypointId) {
17
+ return waypoints.filter((wp) => wp.id !== waypointId);
18
+ }
19
+ /** Move a waypoint to a new position */
20
+ export function moveWaypoint(waypoints, waypointId, x, y) {
21
+ return waypoints.map((wp) => wp.id === waypointId ? { ...wp, x, y } : wp);
22
+ }
23
+ /** Distance from a point to a line segment */
24
+ function pointToSegmentDistance(px, py, ax, ay, bx, by) {
25
+ const dx = bx - ax;
26
+ const dy = by - ay;
27
+ const lenSq = dx * dx + dy * dy;
28
+ if (lenSq === 0) {
29
+ return Math.hypot(px - ax, py - ay);
30
+ }
31
+ const t = Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / lenSq));
32
+ const projX = ax + t * dx;
33
+ const projY = ay + t * dy;
34
+ return Math.hypot(px - projX, py - projY);
35
+ }
36
+ /**
37
+ * Insert a waypoint at the closest segment of a polyline path.
38
+ *
39
+ * The path is an array of points representing the full edge path
40
+ * (startPoint + bendPoints + endPoint). The new waypoint is inserted
41
+ * at the position along the path where it is closest.
42
+ */
43
+ export function insertWaypointAtPosition(existing, path, position) {
44
+ if (path.length < 2) {
45
+ return addWaypointToEdge(existing, createWaypoint(position.x, position.y));
46
+ }
47
+ // Find the closest segment
48
+ let closestSegIdx = 0;
49
+ let closestDist = Infinity;
50
+ for (let i = 0; i < path.length - 1; i++) {
51
+ const d = pointToSegmentDistance(position.x, position.y, path[i].x, path[i].y, path[i + 1].x, path[i + 1].y);
52
+ if (d < closestDist) {
53
+ closestDist = d;
54
+ closestSegIdx = i;
55
+ }
56
+ }
57
+ const newWp = createWaypoint(position.x, position.y);
58
+ if (existing.length === 0) {
59
+ return [newWp];
60
+ }
61
+ // Find where each existing waypoint falls along the path to determine insertion index
62
+ const wpSegments = existing.map((wp) => {
63
+ let bestSeg = 0;
64
+ let bestDist = Infinity;
65
+ for (let i = 0; i < path.length - 1; i++) {
66
+ const d = pointToSegmentDistance(wp.x, wp.y, path[i].x, path[i].y, path[i + 1].x, path[i + 1].y);
67
+ if (d < bestDist) {
68
+ bestDist = d;
69
+ bestSeg = i;
70
+ }
71
+ }
72
+ return bestSeg;
73
+ });
74
+ // Find insertion index: insert after last waypoint whose segment is <= closestSegIdx
75
+ let insertIdx = 0;
76
+ for (let i = 0; i < wpSegments.length; i++) {
77
+ if (wpSegments[i] <= closestSegIdx) {
78
+ insertIdx = i + 1;
79
+ }
80
+ }
81
+ const result = [...existing];
82
+ result.splice(insertIdx, 0, newWp);
83
+ return result;
84
+ }
85
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/waypoints/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Edge routing adapter wrapping libavoided-js (CORAL-REQ-015)
3
+ *
4
+ * Converts CoralNodes/Edges + waypoints → libavoided-js input,
5
+ * routes, and converts output back to CoralEdgeData.routedPath format.
6
+ */
7
+ import type { CoralNode, CoralEdge, Position } from '../types.js';
8
+ import type { EdgeWaypoint } from './types.js';
9
+ export interface RoutedPath {
10
+ startPoint: Position;
11
+ endPoint: Position;
12
+ bendPoints: Position[];
13
+ }
14
+ /**
15
+ * Route edges through libavoided-js with optional pinned waypoints.
16
+ *
17
+ * @param nodes - React Flow nodes (positions + dimensions)
18
+ * @param edges - React Flow edges (source/target references)
19
+ * @param waypointMap - Optional map of edgeId → waypoints to pin
20
+ * @returns Map of edgeId → routed path (startPoint, endPoint, bendPoints)
21
+ */
22
+ export declare function routeWithWaypoints(nodes: CoralNode[], edges: CoralEdge[], waypointMap?: Map<string, EdgeWaypoint[]>): Map<string, RoutedPath>;
23
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/waypoints/router.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,QAAQ,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,QAAQ,EAAE,CAAC;CACxB;AA0DD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAAE,EAClB,KAAK,EAAE,SAAS,EAAE,EAClB,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,GACxC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAmDzB"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Edge routing adapter wrapping libavoided-js (CORAL-REQ-015)
3
+ *
4
+ * Converts CoralNodes/Edges + waypoints → libavoided-js input,
5
+ * routes, and converts output back to CoralEdgeData.routedPath format.
6
+ */
7
+ import { routeEdges } from 'libavoided-js';
8
+ /** Convert a CoralNode to a libavoided-js Obstacle */
9
+ function nodeToObstacle(node) {
10
+ return {
11
+ id: node.id,
12
+ x: node.position.x,
13
+ y: node.position.y,
14
+ width: node.width ?? node.measured?.width ?? 100,
15
+ height: node.height ?? node.measured?.height ?? 50,
16
+ };
17
+ }
18
+ /** Compute edge source/target attachment points (center of right/left sides) */
19
+ function getEdgeEndpoints(sourceNode, targetNode) {
20
+ const sw = sourceNode.width ?? sourceNode.measured?.width ?? 100;
21
+ const sh = sourceNode.height ?? sourceNode.measured?.height ?? 50;
22
+ const tw = targetNode.width ?? targetNode.measured?.width ?? 100;
23
+ const th = targetNode.height ?? targetNode.measured?.height ?? 50;
24
+ // Use center-to-center to determine which sides to connect
25
+ const sCenterX = sourceNode.position.x + sw / 2;
26
+ const sCenterY = sourceNode.position.y + sh / 2;
27
+ const tCenterX = targetNode.position.x + tw / 2;
28
+ const tCenterY = targetNode.position.y + th / 2;
29
+ const dx = tCenterX - sCenterX;
30
+ const dy = tCenterY - sCenterY;
31
+ let sourcePoint;
32
+ let targetPoint;
33
+ if (Math.abs(dx) > Math.abs(dy)) {
34
+ // Horizontal connection
35
+ if (dx > 0) {
36
+ sourcePoint = { x: sourceNode.position.x + sw, y: sCenterY };
37
+ targetPoint = { x: targetNode.position.x, y: tCenterY };
38
+ }
39
+ else {
40
+ sourcePoint = { x: sourceNode.position.x, y: sCenterY };
41
+ targetPoint = { x: targetNode.position.x + tw, y: tCenterY };
42
+ }
43
+ }
44
+ else {
45
+ // Vertical connection
46
+ if (dy > 0) {
47
+ sourcePoint = { x: sCenterX, y: sourceNode.position.y + sh };
48
+ targetPoint = { x: tCenterX, y: targetNode.position.y };
49
+ }
50
+ else {
51
+ sourcePoint = { x: sCenterX, y: sourceNode.position.y };
52
+ targetPoint = { x: tCenterX, y: targetNode.position.y + th };
53
+ }
54
+ }
55
+ return { sourcePoint, targetPoint };
56
+ }
57
+ /**
58
+ * Route edges through libavoided-js with optional pinned waypoints.
59
+ *
60
+ * @param nodes - React Flow nodes (positions + dimensions)
61
+ * @param edges - React Flow edges (source/target references)
62
+ * @param waypointMap - Optional map of edgeId → waypoints to pin
63
+ * @returns Map of edgeId → routed path (startPoint, endPoint, bendPoints)
64
+ */
65
+ export function routeWithWaypoints(nodes, edges, waypointMap) {
66
+ const nodeMap = new Map(nodes.map((n) => [n.id, n]));
67
+ const obstacles = nodes.map(nodeToObstacle);
68
+ const edgeRequests = [];
69
+ const validEdgeIds = new Set();
70
+ for (const edge of edges) {
71
+ const sourceNode = nodeMap.get(edge.source);
72
+ const targetNode = nodeMap.get(edge.target);
73
+ if (!sourceNode || !targetNode)
74
+ continue;
75
+ const { sourcePoint, targetPoint } = getEdgeEndpoints(sourceNode, targetNode);
76
+ const req = {
77
+ id: edge.id,
78
+ sourceId: edge.source,
79
+ targetId: edge.target,
80
+ sourcePoint,
81
+ targetPoint,
82
+ };
83
+ // Attach pinned waypoints
84
+ const waypoints = waypointMap?.get(edge.id);
85
+ if (waypoints && waypoints.length > 0) {
86
+ req.pinnedWaypoints = waypoints.map((wp) => ({ x: wp.x, y: wp.y }));
87
+ }
88
+ edgeRequests.push(req);
89
+ validEdgeIds.add(edge.id);
90
+ }
91
+ if (edgeRequests.length === 0) {
92
+ return new Map();
93
+ }
94
+ const input = { obstacles, edges: edgeRequests };
95
+ const output = routeEdges(input);
96
+ const result = new Map();
97
+ for (const routed of output.edges) {
98
+ if (routed.sections.length === 0)
99
+ continue;
100
+ const section = routed.sections[0];
101
+ result.set(routed.id, {
102
+ startPoint: { x: section.startPoint.x, y: section.startPoint.y },
103
+ endPoint: { x: section.endPoint.x, y: section.endPoint.y },
104
+ bendPoints: section.bendPoints.map((bp) => ({ x: bp.x, y: bp.y })),
105
+ });
106
+ }
107
+ return result;
108
+ }
109
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/waypoints/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Waypoint types for manual edge routing (CORAL-REQ-015)
3
+ */
4
+ /** A user-placed waypoint on an edge */
5
+ export interface EdgeWaypoint {
6
+ /** Unique identifier */
7
+ id: string;
8
+ /** X coordinate */
9
+ x: number;
10
+ /** Y coordinate */
11
+ y: number;
12
+ /** Waypoint type: corner (sharp bend) or smooth (curved) */
13
+ type: 'corner' | 'smooth';
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/waypoints/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,mBAAmB;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,4DAA4D;IAC5D,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC3B"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Waypoint types for manual edge routing (CORAL-REQ-015)
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/waypoints/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * useWaypointManager - Hook for managing edge waypoints (CORAL-REQ-015)
3
+ *
4
+ * Owns the Map<edgeId, EdgeWaypoint[]> state and exposes operations
5
+ * for adding, moving, removing, and clearing waypoints.
6
+ * Calls routeWithWaypoints internally to compute routed paths.
7
+ */
8
+ import type { CoralNode, CoralEdge, Position } from '../types.js';
9
+ import type { EdgeWaypoint } from './types.js';
10
+ import { type RoutedPath } from './router.js';
11
+ export interface UseWaypointManagerOptions {
12
+ nodes: CoralNode[];
13
+ edges: CoralEdge[];
14
+ initialWaypoints?: Map<string, EdgeWaypoint[]>;
15
+ onChange?: (waypointMap: Map<string, EdgeWaypoint[]>) => void;
16
+ }
17
+ export interface UseWaypointManagerResult {
18
+ /** Current waypoint map: edgeId → waypoints */
19
+ waypointMap: Map<string, EdgeWaypoint[]>;
20
+ /** Add a waypoint to an edge at a position */
21
+ addWaypoint: (edgeId: string, position: Position) => void;
22
+ /** Move an existing waypoint */
23
+ moveWaypoint: (edgeId: string, waypointId: string, position: Position) => void;
24
+ /** Remove a waypoint by ID */
25
+ removeWaypoint: (edgeId: string, waypointId: string) => void;
26
+ /** Clear all waypoints for a specific edge */
27
+ clearWaypoints: (edgeId: string) => void;
28
+ /** Clear all waypoints for all edges */
29
+ clearAllWaypoints: () => void;
30
+ /** Replace all waypoints, used when DSL, recovery, or a document is loaded. */
31
+ setWaypoints: (waypoints: Map<string, EdgeWaypoint[]>) => void;
32
+ /** Whether an edge has waypoints */
33
+ hasWaypoints: (edgeId: string) => boolean;
34
+ /** Get routed paths computed from current waypoints */
35
+ getRoutedPaths: () => Map<string, RoutedPath>;
36
+ }
37
+ export declare function useWaypointManager(options: UseWaypointManagerOptions): UseWaypointManagerResult;
38
+ //# sourceMappingURL=useWaypointManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWaypointManager.d.ts","sourceRoot":"","sources":["../../src/waypoints/useWaypointManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,KAAK,IAAI,CAAC;CAC/D;AAED,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACzC,8CAA8C;IAC9C,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IAC1D,gCAAgC;IAChC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IAC/E,8BAA8B;IAC9B,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,8CAA8C;IAC9C,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,+EAA+E;IAC/E,YAAY,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/D,oCAAoC;IACpC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,uDAAuD;IACvD,cAAc,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAC/C;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,CA0H1B"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * useWaypointManager - Hook for managing edge waypoints (CORAL-REQ-015)
3
+ *
4
+ * Owns the Map<edgeId, EdgeWaypoint[]> state and exposes operations
5
+ * for adding, moving, removing, and clearing waypoints.
6
+ * Calls routeWithWaypoints internally to compute routed paths.
7
+ */
8
+ import { useState, useCallback, useRef } from 'react';
9
+ import { createWaypoint } from './operations.js';
10
+ import { routeWithWaypoints } from './router.js';
11
+ export function useWaypointManager(options) {
12
+ const { nodes, edges, initialWaypoints, onChange } = options;
13
+ const [waypointMap, setWaypointMap] = useState(() => initialWaypoints ? new Map(initialWaypoints) : new Map());
14
+ // Keep refs for routing
15
+ const nodesRef = useRef(nodes);
16
+ const edgesRef = useRef(edges);
17
+ nodesRef.current = nodes;
18
+ edgesRef.current = edges;
19
+ // Cache routed paths
20
+ const routedPathsRef = useRef(new Map());
21
+ const addWaypoint = useCallback((edgeId, position) => {
22
+ setWaypointMap((prev) => {
23
+ const newMap = new Map(prev);
24
+ const existing = newMap.get(edgeId) || [];
25
+ const wp = createWaypoint(position.x, position.y);
26
+ newMap.set(edgeId, [...existing, wp]);
27
+ routedPathsRef.current = routeWithWaypoints(nodesRef.current, edgesRef.current, newMap);
28
+ onChange?.(newMap);
29
+ return newMap;
30
+ });
31
+ }, [onChange]);
32
+ const moveWaypointFn = useCallback((edgeId, waypointId, position) => {
33
+ setWaypointMap((prev) => {
34
+ const newMap = new Map(prev);
35
+ const wps = newMap.get(edgeId);
36
+ if (!wps)
37
+ return prev;
38
+ newMap.set(edgeId, wps.map((wp) => (wp.id === waypointId ? { ...wp, x: position.x, y: position.y } : wp)));
39
+ routedPathsRef.current = routeWithWaypoints(nodesRef.current, edgesRef.current, newMap);
40
+ onChange?.(newMap);
41
+ return newMap;
42
+ });
43
+ }, [onChange]);
44
+ const removeWaypoint = useCallback((edgeId, waypointId) => {
45
+ setWaypointMap((prev) => {
46
+ const newMap = new Map(prev);
47
+ const wps = newMap.get(edgeId);
48
+ if (!wps)
49
+ return prev;
50
+ const filtered = wps.filter((wp) => wp.id !== waypointId);
51
+ if (filtered.length === 0) {
52
+ newMap.delete(edgeId);
53
+ }
54
+ else {
55
+ newMap.set(edgeId, filtered);
56
+ }
57
+ routedPathsRef.current = routeWithWaypoints(nodesRef.current, edgesRef.current, newMap);
58
+ onChange?.(newMap);
59
+ return newMap;
60
+ });
61
+ }, [onChange]);
62
+ const clearWaypoints = useCallback((edgeId) => {
63
+ setWaypointMap((prev) => {
64
+ const newMap = new Map(prev);
65
+ newMap.delete(edgeId);
66
+ routedPathsRef.current = routeWithWaypoints(nodesRef.current, edgesRef.current, newMap);
67
+ onChange?.(newMap);
68
+ return newMap;
69
+ });
70
+ }, [onChange]);
71
+ const clearAllWaypoints = useCallback(() => {
72
+ const newMap = new Map();
73
+ setWaypointMap(newMap);
74
+ routedPathsRef.current = new Map();
75
+ onChange?.(newMap);
76
+ }, [onChange]);
77
+ const setWaypoints = useCallback((waypoints) => {
78
+ const newMap = new Map(waypoints);
79
+ setWaypointMap(newMap);
80
+ routedPathsRef.current = routeWithWaypoints(nodesRef.current, edgesRef.current, newMap);
81
+ onChange?.(newMap);
82
+ }, [onChange]);
83
+ const hasWaypoints = useCallback((edgeId) => {
84
+ const wps = waypointMap.get(edgeId);
85
+ return wps !== undefined && wps.length > 0;
86
+ }, [waypointMap]);
87
+ const getRoutedPaths = useCallback(() => {
88
+ // Recompute if cache is empty but waypoints exist
89
+ if (routedPathsRef.current.size === 0 && waypointMap.size > 0) {
90
+ routedPathsRef.current = routeWithWaypoints(nodesRef.current, edgesRef.current, waypointMap);
91
+ }
92
+ return routedPathsRef.current;
93
+ }, [waypointMap]);
94
+ return {
95
+ waypointMap,
96
+ addWaypoint,
97
+ moveWaypoint: moveWaypointFn,
98
+ removeWaypoint,
99
+ clearWaypoints,
100
+ clearAllWaypoints,
101
+ setWaypoints,
102
+ hasWaypoints,
103
+ getRoutedPaths,
104
+ };
105
+ }
106
+ //# sourceMappingURL=useWaypointManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWaypointManager.js","sourceRoot":"","sources":["../../src/waypoints/useWaypointManager.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@coral-viz/viz",
3
+ "version": "0.2.3",
4
+ "description": "Coral visual diagram editor using React Flow",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/coreyt/coral.git",
9
+ "directory": "packages/viz"
10
+ },
11
+ "type": "module",
12
+ "main": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./editor": {
20
+ "types": "./dist/editor/index.d.ts",
21
+ "import": "./dist/editor/index.js"
22
+ },
23
+ "./layout": {
24
+ "types": "./dist/layout/index.d.ts",
25
+ "import": "./dist/layout/index.js"
26
+ },
27
+ "./text-editor": {
28
+ "types": "./dist/text-editor/index.d.ts",
29
+ "import": "./dist/text-editor/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "scripts": {
38
+ "build": "node ../../scripts/clean.mjs dist && tsc",
39
+ "prepack": "npm run build",
40
+ "test": "vitest",
41
+ "test:run": "vitest run",
42
+ "test:coverage": "vitest run --coverage",
43
+ "lint": "eslint src test",
44
+ "typecheck": "tsc --noEmit"
45
+ },
46
+ "dependencies": {
47
+ "@graph-ir/core": "0.2.0",
48
+ "elkjs": "0.12.0",
49
+ "libavoided-js": "0.1.2",
50
+ "@coral-viz/render": "0.2.3"
51
+ },
52
+ "devDependencies": {
53
+ "@testing-library/react": "16.3.3",
54
+ "@types/node": "24.13.3",
55
+ "@types/react": "19.2.18",
56
+ "@types/react-dom": "19.2.7",
57
+ "@vitest/coverage-v8": "5.0.0",
58
+ "@xyflow/react": "12.11.6",
59
+ "jsdom": "30.0.1",
60
+ "react": "19.2.8",
61
+ "react-dom": "19.2.8",
62
+ "typescript": "6.0.3",
63
+ "vitest": "5.0.0"
64
+ },
65
+ "peerDependencies": {
66
+ "@xyflow/react": "^12.0.0",
67
+ "react": "^18.3.0 || ^19.0.0",
68
+ "react-dom": "^18.3.0 || ^19.0.0"
69
+ },
70
+ "engines": {
71
+ "node": ">=24.19.0"
72
+ },
73
+ "publishConfig": {
74
+ "access": "public"
75
+ }
76
+ }