@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.
- package/LICENSE +4 -0
- package/README.md +11 -0
- package/dist/compatibility/CompatibilityEdge.d.ts +106 -0
- package/dist/compatibility/CompatibilityEdge.d.ts.map +1 -0
- package/dist/compatibility/CompatibilityEdge.js +233 -0
- package/dist/compatibility/CompatibilityEdge.js.map +1 -0
- package/dist/compatibility/IncompatibilityTooltip.d.ts +44 -0
- package/dist/compatibility/IncompatibilityTooltip.d.ts.map +1 -0
- package/dist/compatibility/IncompatibilityTooltip.js +145 -0
- package/dist/compatibility/IncompatibilityTooltip.js.map +1 -0
- package/dist/compatibility/index.d.ts +10 -0
- package/dist/compatibility/index.d.ts.map +1 -0
- package/dist/compatibility/index.js +10 -0
- package/dist/compatibility/index.js.map +1 -0
- package/dist/compatibility/useEdgeCompatibility.d.ts +82 -0
- package/dist/compatibility/useEdgeCompatibility.d.ts.map +1 -0
- package/dist/compatibility/useEdgeCompatibility.js +170 -0
- package/dist/compatibility/useEdgeCompatibility.js.map +1 -0
- package/dist/compatibility/validateConnection.d.ts +56 -0
- package/dist/compatibility/validateConnection.d.ts.map +1 -0
- package/dist/compatibility/validateConnection.js +382 -0
- package/dist/compatibility/validateConnection.js.map +1 -0
- package/dist/components/EditContext.d.ts +45 -0
- package/dist/components/EditContext.d.ts.map +1 -0
- package/dist/components/EditContext.js +41 -0
- package/dist/components/EditContext.js.map +1 -0
- package/dist/components/ShapeRenderer.d.ts +35 -0
- package/dist/components/ShapeRenderer.d.ts.map +1 -0
- package/dist/components/ShapeRenderer.js +77 -0
- package/dist/components/ShapeRenderer.js.map +1 -0
- package/dist/components/SymbolNode.d.ts +53 -0
- package/dist/components/SymbolNode.d.ts.map +1 -0
- package/dist/components/SymbolNode.js +333 -0
- package/dist/components/SymbolNode.js.map +1 -0
- package/dist/components/index.d.ts +8 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +10 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/nodes.d.ts +43 -0
- package/dist/components/nodes.d.ts.map +1 -0
- package/dist/components/nodes.js +111 -0
- package/dist/components/nodes.js.map +1 -0
- package/dist/editor/CoralEditor.d.ts +29 -0
- package/dist/editor/CoralEditor.d.ts.map +1 -0
- package/dist/editor/CoralEditor.js +112 -0
- package/dist/editor/CoralEditor.js.map +1 -0
- package/dist/editor/FileControls.d.ts +34 -0
- package/dist/editor/FileControls.d.ts.map +1 -0
- package/dist/editor/FileControls.js +139 -0
- package/dist/editor/FileControls.js.map +1 -0
- package/dist/editor/LayoutControls.d.ts +41 -0
- package/dist/editor/LayoutControls.d.ts.map +1 -0
- package/dist/editor/LayoutControls.js +124 -0
- package/dist/editor/LayoutControls.js.map +1 -0
- package/dist/editor/converter.d.ts +37 -0
- package/dist/editor/converter.d.ts.map +1 -0
- package/dist/editor/converter.js +256 -0
- package/dist/editor/converter.js.map +1 -0
- package/dist/editor/index.d.ts +8 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +8 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/file/deserialize.d.ts +15 -0
- package/dist/file/deserialize.d.ts.map +1 -0
- package/dist/file/deserialize.js +145 -0
- package/dist/file/deserialize.js.map +1 -0
- package/dist/file/index.d.ts +15 -0
- package/dist/file/index.d.ts.map +1 -0
- package/dist/file/index.js +20 -0
- package/dist/file/index.js.map +1 -0
- package/dist/file/migrate.d.ts +29 -0
- package/dist/file/migrate.d.ts.map +1 -0
- package/dist/file/migrate.js +103 -0
- package/dist/file/migrate.js.map +1 -0
- package/dist/file/schema.d.ts +385 -0
- package/dist/file/schema.d.ts.map +1 -0
- package/dist/file/schema.js +180 -0
- package/dist/file/schema.js.map +1 -0
- package/dist/file/serialize.d.ts +30 -0
- package/dist/file/serialize.d.ts.map +1 -0
- package/dist/file/serialize.js +218 -0
- package/dist/file/serialize.js.map +1 -0
- package/dist/file/validate.d.ts +21 -0
- package/dist/file/validate.d.ts.map +1 -0
- package/dist/file/validate.js +165 -0
- package/dist/file/validate.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/elk.d.ts +77 -0
- package/dist/layout/elk.d.ts.map +1 -0
- package/dist/layout/elk.js +379 -0
- package/dist/layout/elk.js.map +1 -0
- package/dist/layout/index.d.ts +12 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +12 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/layout/nodeSizing.d.ts +65 -0
- package/dist/layout/nodeSizing.d.ts.map +1 -0
- package/dist/layout/nodeSizing.js +319 -0
- package/dist/layout/nodeSizing.js.map +1 -0
- package/dist/layout/positionStability.d.ts +73 -0
- package/dist/layout/positionStability.d.ts.map +1 -0
- package/dist/layout/positionStability.js +199 -0
- package/dist/layout/positionStability.js.map +1 -0
- package/dist/layout/useAxisConstrain.d.ts +20 -0
- package/dist/layout/useAxisConstrain.d.ts.map +1 -0
- package/dist/layout/useAxisConstrain.js +106 -0
- package/dist/layout/useAxisConstrain.js.map +1 -0
- package/dist/layout/useDiagramState.d.ts +92 -0
- package/dist/layout/useDiagramState.d.ts.map +1 -0
- package/dist/layout/useDiagramState.js +256 -0
- package/dist/layout/useDiagramState.js.map +1 -0
- package/dist/layout/useLayoutHistory.d.ts +53 -0
- package/dist/layout/useLayoutHistory.d.ts.map +1 -0
- package/dist/layout/useLayoutHistory.js +124 -0
- package/dist/layout/useLayoutHistory.js.map +1 -0
- package/dist/properties/NodePropertiesPanel.d.ts +47 -0
- package/dist/properties/NodePropertiesPanel.d.ts.map +1 -0
- package/dist/properties/NodePropertiesPanel.js +199 -0
- package/dist/properties/NodePropertiesPanel.js.map +1 -0
- package/dist/properties/index.d.ts +10 -0
- package/dist/properties/index.d.ts.map +1 -0
- package/dist/properties/index.js +10 -0
- package/dist/properties/index.js.map +1 -0
- package/dist/properties/propertyUtils.d.ts +60 -0
- package/dist/properties/propertyUtils.d.ts.map +1 -0
- package/dist/properties/propertyUtils.js +89 -0
- package/dist/properties/propertyUtils.js.map +1 -0
- package/dist/settings/FontSettingsForm.d.ts +28 -0
- package/dist/settings/FontSettingsForm.d.ts.map +1 -0
- package/dist/settings/FontSettingsForm.js +129 -0
- package/dist/settings/FontSettingsForm.js.map +1 -0
- package/dist/settings/LayoutSettingsForm.d.ts +37 -0
- package/dist/settings/LayoutSettingsForm.d.ts.map +1 -0
- package/dist/settings/LayoutSettingsForm.js +165 -0
- package/dist/settings/LayoutSettingsForm.js.map +1 -0
- package/dist/settings/SettingsPanel.d.ts +55 -0
- package/dist/settings/SettingsPanel.d.ts.map +1 -0
- package/dist/settings/SettingsPanel.js +84 -0
- package/dist/settings/SettingsPanel.js.map +1 -0
- package/dist/settings/index.d.ts +13 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +13 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/settings/useSettings.d.ts +51 -0
- package/dist/settings/useSettings.d.ts.map +1 -0
- package/dist/settings/useSettings.js +154 -0
- package/dist/settings/useSettings.js.map +1 -0
- package/dist/text-editor/SplitEditor.d.ts +72 -0
- package/dist/text-editor/SplitEditor.d.ts.map +1 -0
- package/dist/text-editor/SplitEditor.js +172 -0
- package/dist/text-editor/SplitEditor.js.map +1 -0
- package/dist/text-editor/TextEditor.d.ts +53 -0
- package/dist/text-editor/TextEditor.d.ts.map +1 -0
- package/dist/text-editor/TextEditor.js +181 -0
- package/dist/text-editor/TextEditor.js.map +1 -0
- package/dist/text-editor/hooks/useBidirectionalSync.d.ts +106 -0
- package/dist/text-editor/hooks/useBidirectionalSync.d.ts.map +1 -0
- package/dist/text-editor/hooks/useBidirectionalSync.js +151 -0
- package/dist/text-editor/hooks/useBidirectionalSync.js.map +1 -0
- package/dist/text-editor/index.d.ts +9 -0
- package/dist/text-editor/index.d.ts.map +1 -0
- package/dist/text-editor/index.js +11 -0
- package/dist/text-editor/index.js.map +1 -0
- package/dist/types.d.ts +242 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/waypoints/index.d.ts +8 -0
- package/dist/waypoints/index.d.ts.map +1 -0
- package/dist/waypoints/index.js +7 -0
- package/dist/waypoints/index.js.map +1 -0
- package/dist/waypoints/operations.d.ts +29 -0
- package/dist/waypoints/operations.d.ts.map +1 -0
- package/dist/waypoints/operations.js +85 -0
- package/dist/waypoints/operations.js.map +1 -0
- package/dist/waypoints/router.d.ts +23 -0
- package/dist/waypoints/router.d.ts.map +1 -0
- package/dist/waypoints/router.js +109 -0
- package/dist/waypoints/router.js.map +1 -0
- package/dist/waypoints/types.d.ts +15 -0
- package/dist/waypoints/types.d.ts.map +1 -0
- package/dist/waypoints/types.js +5 -0
- package/dist/waypoints/types.js.map +1 -0
- package/dist/waypoints/useWaypointManager.d.ts +38 -0
- package/dist/waypoints/useWaypointManager.d.ts.map +1 -0
- package/dist/waypoints/useWaypointManager.js +106 -0
- package/dist/waypoints/useWaypointManager.js.map +1 -0
- 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 @@
|
|
|
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":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAmB,MAAM,aAAa,CAAC;AA8BlE,MAAM,UAAU,kBAAkB,CAChC,OAAkC;IAElC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAC5C,GAAG,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAC/D,CAAC;IAEF,wBAAwB;IACxB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;IACzB,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;IAEzB,qBAAqB;IACrB,MAAM,cAAc,GAAG,MAAM,CAA0B,IAAI,GAAG,EAAE,CAAC,CAAC;IAElE,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,MAAc,EAAE,QAAkB,EAAE,EAAE;QACrC,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC1C,MAAM,EAAE,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;YACtC,cAAc,CAAC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACxF,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,MAAc,EAAE,UAAkB,EAAE,QAAkB,EAAE,EAAE;QACzD,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YACtB,MAAM,CAAC,GAAG,CACR,MAAM,EACN,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CACvF,CAAC;YACF,cAAc,CAAC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACxF,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,MAAc,EAAE,UAAkB,EAAE,EAAE;QACrC,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YACtB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC;YAC1D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC/B,CAAC;YACD,cAAc,CAAC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACxF,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,MAAc,EAAE,EAAE;QACjB,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtB,cAAc,CAAC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACxF,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;QACzC,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;QACjD,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,cAAc,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QACnC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,SAAsC,EAAE,EAAE;QAC1E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAClC,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,cAAc,CAAC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxF,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,MAAc,EAAE,EAAE;QACjB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7C,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAAC,GAA4B,EAAE;QAC/D,kDAAkD;QAClD,IAAI,cAAc,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC9D,cAAc,CAAC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,cAAc,CAAC,OAAO,CAAC;IAChC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,OAAO;QACL,WAAW;QACX,WAAW;QACX,YAAY,EAAE,cAAc;QAC5B,cAAc;QACd,cAAc;QACd,iBAAiB;QACjB,YAAY;QACZ,YAAY;QACZ,cAAc;KACf,CAAC;AACJ,CAAC"}
|
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
|
+
}
|