avoid-nodes-edge 0.1.2 → 0.1.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/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # avoid-nodes-edge
2
2
 
3
- **[Live Demo](https://avoid-nodes-pro-example.vercel.app)**
3
+ **[Live Demo](https://avoid-nodes-pro-example.vercel.app)** | **[How It Works](https://github.com/awaisshah228/react-flow-avoid-nodes-routing/blob/turbo-package/HOW_IT_WORKS.md)** | **[GitHub](https://github.com/awaisshah228/react-flow-avoid-nodes-routing/tree/turbo-package)**
4
+
5
+ [![npm](https://img.shields.io/npm/v/avoid-nodes-edge)](https://www.npmjs.com/package/avoid-nodes-edge) [![npm bundle size](https://img.shields.io/bundlephobia/minzip/avoid-nodes-edge)](https://bundlephobia.com/package/avoid-nodes-edge)
4
6
 
5
7
  Orthogonal edge routing for [React Flow](https://reactflow.dev/) — edges automatically route around nodes using [libavoid-js](https://github.com/nicknisi/libavoid-js) (WASM). All WASM and routing computation runs exclusively in a **Web Worker**, keeping the main thread free and your UI smooth.
6
8
 
@@ -0,0 +1 @@
1
+ var E=Object.defineProperty;var S=(o,t,e)=>t in o?E(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var O=(o,t,e)=>S(o,typeof t!="symbol"?t+"":t,e);import{create as b}from"zustand";var R=b(o=>({loaded:!1,routes:{},setLoaded:t=>o({loaded:t}),setRoutes:t=>o({routes:t})})),_=()=>{},h=o=>{},X=b(o=>({actions:{resetRouting:_,updateRoutesForNodeId:h},setActions:t=>o({actions:t})}));var L=!1,U=0,G=!0,m=0;import{useMemo as x}from"react";import{getStraightPath as D,getSmoothStepPath as F}from"@xyflow/react";var p={left:"left",right:"right",top:"top",bottom:"bottom"};function w(o){let{id:t,sourceX:e,sourceY:i,targetX:n,targetY:a,sourcePosition:d,targetPosition:u,offset:c}=o,l=R(r=>r.loaded),s=R(r=>r.routes[t]);return x(()=>{if(l&&s)return[s.path,s.labelX,s.labelY,!0];if(d&&u){let[f,g,v]=F({sourceX:e,sourceY:i,targetX:n,targetY:a,sourcePosition:p[d],targetPosition:p[u],borderRadius:o.borderRadius??0,offset:c??20});return[f,g,v,!1]}let[r,P,A]=D({sourceX:e,sourceY:i,targetX:n,targetY:a});return[r,P,A,!1]},[l,s,e,i,n,a,d,u,c,o.borderRadius])}export{O as a,R as b,X as c,L as d,U as e,G as f,m as g,w as h};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var E=Object.defineProperty;var S=(o,t,e)=>t in o?E(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var O=(o,t,e)=>S(o,typeof t!="symbol"?t+"":t,e);var _zustand = require('zustand');var R=_zustand.create.call(void 0, o=>({loaded:!1,routes:{},setLoaded:t=>o({loaded:t}),setRoutes:t=>o({routes:t})})),_=()=>{},h=o=>{},X= exports.c =_zustand.create.call(void 0, o=>({actions:{resetRouting:_,updateRoutesForNodeId:h},setActions:t=>o({actions:t})}));var L=!1,U= exports.e =0,G= exports.f =!0,m= exports.g =0;var _react = require('react');var _react3 = require('@xyflow/react');var p={left:"left",right:"right",top:"top",bottom:"bottom"};function w(o){let{id:t,sourceX:e,sourceY:i,targetX:n,targetY:a,sourcePosition:d,targetPosition:u,offset:c}=o,l=R(r=>r.loaded),s=R(r=>r.routes[t]);return _react.useMemo.call(void 0, ()=>{if(l&&s)return[s.path,s.labelX,s.labelY,!0];if(d&&u){let[f,g,v]=_react3.getSmoothStepPath.call(void 0, {sourceX:e,sourceY:i,targetX:n,targetY:a,sourcePosition:p[d],targetPosition:p[u],borderRadius:_nullishCoalesce(o.borderRadius, () => (0)),offset:_nullishCoalesce(c, () => (20))});return[f,g,v,!1]}let[r,P,A]=_react3.getStraightPath.call(void 0, {sourceX:e,sourceY:i,targetX:n,targetY:a});return[r,P,A,!1]},[l,s,e,i,n,a,d,u,c,o.borderRadius])}exports.a = O; exports.b = R; exports.c = X; exports.d = L; exports.e = U; exports.f = G; exports.g = m; exports.h = w;
package/dist/edge.cjs CHANGED
@@ -1,235 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
-
3
- var _chunkTO34Q3IDcjs = require('./chunk-TO34Q3ID.cjs');
4
-
5
- // src/AvoidNodesEdge.tsx
6
- var _react = require('react');
7
-
8
-
9
-
10
-
11
- var _react3 = require('@xyflow/react');
12
- var _jsxruntime = require('react/jsx-runtime');
13
- var PARALLEL_EDGE_GAP = 22;
14
- var EDGE_STROKE_WIDTH = 1.5;
15
- var MIN_EDGE_LENGTH_FOR_LABEL_PX = 72;
16
- var LABEL_WIDTH_APPROX_PX_PER_CHAR = 7;
17
- var LABEL_PADDING_PX = 32;
18
- var ER_RELATIONS = [
19
- { id: null, label: "None", sourceLabel: "", targetLabel: "" },
20
- { id: "one-to-one", label: "One to One", sourceLabel: "1", targetLabel: "1" },
21
- { id: "one-to-many", label: "One to Many", sourceLabel: "1", targetLabel: "*" },
22
- { id: "many-to-one", label: "Many to One", sourceLabel: "*", targetLabel: "1" },
23
- { id: "many-to-many", label: "Many to Many", sourceLabel: "*", targetLabel: "*" }
24
- ];
25
- function offsetPoint(fromX, fromY, toX, toY, gap) {
26
- const dx = toX - fromX;
27
- const dy = toY - fromY;
28
- const len = Math.sqrt(dx * dx + dy * dy);
29
- if (len === 0 || gap === 0) return { x: fromX, y: fromY };
30
- const ratio = gap / len;
31
- return { x: fromX + dx * ratio, y: fromY + dy * ratio };
32
- }
33
- function getStraightPathWithParallelOffset(sourceX, sourceY, targetX, targetY, offsetX, offsetY) {
34
- const s2 = sourceX + offsetX;
35
- const t2 = targetX + offsetX;
36
- const s3 = sourceY + offsetY;
37
- const t3 = targetY + offsetY;
38
- return `M ${sourceX} ${sourceY} L ${s2} ${s3} L ${t2} ${t3} L ${targetX} ${targetY}`;
39
- }
40
- function translatePath(pathStr, offsetX, offsetY) {
41
- return pathStr.replace(
42
- /([\d.-]+)\s+([\d.-]+)/g,
43
- (_, a, b) => `${Number(a) + offsetX} ${Number(b) + offsetY}`
44
- );
45
- }
46
- function applyAvoidPathParallelOffset(pathStr, sourceX, sourceY, targetX, targetY, offsetX, offsetY) {
47
- const translated = translatePath(pathStr, offsetX, offsetY);
48
- const rest = translated.replace(/^M\s*[\d.-]+\s+[\d.-]+/, "").trim();
49
- return "M " + sourceX + " " + sourceY + " L " + (sourceX + offsetX) + " " + (sourceY + offsetY) + " " + rest + " L " + targetX + " " + targetY;
50
- }
51
- function AvoidNodesEdgeComponent(props) {
52
- const {
53
- id,
54
- source,
55
- target,
56
- sourceX,
57
- sourceY,
58
- targetX,
59
- targetY,
60
- data,
61
- sourcePosition,
62
- targetPosition,
63
- markerEnd: markerEndProp,
64
- markerStart: markerStartProp
65
- } = props;
66
- const { getEdges } = _react3.useReactFlow.call(void 0, );
67
- const edgeData = data;
68
- const [basePath, labelX, labelY, isRouted] = _chunkTO34Q3IDcjs.useAvoidNodesPath.call(void 0, {
69
- id,
70
- sourceX,
71
- sourceY,
72
- targetX,
73
- targetY,
74
- sourcePosition,
75
- targetPosition,
76
- points: _optionalChain([edgeData, 'optionalAccess', _2 => _2.pathPoints])
77
- });
78
- const strokeColor = _nullishCoalesce(_optionalChain([edgeData, 'optionalAccess', _3 => _3.strokeColor]), () => ( "#94a3b8"));
79
- const strokeWidth = _nullishCoalesce(_optionalChain([edgeData, 'optionalAccess', _4 => _4.strokeWidth]), () => ( EDGE_STROKE_WIDTH));
80
- const strokeDasharray = _optionalChain([edgeData, 'optionalAccess', _5 => _5.strokeDasharray]);
81
- const flowDirection = _nullishCoalesce(_optionalChain([edgeData, 'optionalAccess', _6 => _6.flowDirection]), () => ( "mono"));
82
- const label = _nullishCoalesce(_optionalChain([edgeData, 'optionalAccess', _7 => _7.label]), () => ( ""));
83
- const erRelation = _nullishCoalesce(_optionalChain([edgeData, 'optionalAccess', _8 => _8.erRelation]), () => ( null));
84
- const connectorType = _nullishCoalesce(_optionalChain([edgeData, 'optionalAccess', _9 => _9.connectorType]), () => ( "default"));
85
- const dataMarkerEnd = _optionalChain([edgeData, 'optionalAccess', _10 => _10.markerEnd]);
86
- const dataMarkerStart = _optionalChain([edgeData, 'optionalAccess', _11 => _11.markerStart]);
87
- const flowDirectionMarkerEnd = flowDirection === "mono" || flowDirection === "bi" ? "url(#arrowClosed)" : void 0;
88
- const flowDirectionMarkerStart = flowDirection === "bi" ? "url(#arrowClosed)" : void 0;
89
- const effectiveMarkerEnd = _nullishCoalesce(_nullishCoalesce(dataMarkerEnd, () => ( markerEndProp)), () => ( flowDirectionMarkerEnd));
90
- const effectiveMarkerStart = _nullishCoalesce(_nullishCoalesce(dataMarkerStart, () => ( markerStartProp)), () => ( flowDirectionMarkerStart));
91
- const parallelEdgeOffset = _react.useMemo.call(void 0, () => {
92
- const edges = getEdges().filter(
93
- (e) => e.source === source && e.target === target && e.type === "avoidNodes"
94
- );
95
- if (edges.length <= 1) return { offsetX: 0, offsetY: 0 };
96
- const sorted = [...edges].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
97
- const index = sorted.findIndex((e) => e.id === id);
98
- if (index < 0) return { offsetX: 0, offsetY: 0 };
99
- const dx = targetX - sourceX;
100
- const dy = targetY - sourceY;
101
- const len = Math.hypot(dx, dy);
102
- if (len === 0) return { offsetX: 0, offsetY: 0 };
103
- const perpX = -dy / len;
104
- const perpY = dx / len;
105
- const amount = (index - (edges.length - 1) / 2) * PARALLEL_EDGE_GAP;
106
- return { offsetX: perpX * amount, offsetY: perpY * amount };
107
- }, [source, target, id, sourceX, sourceY, targetX, targetY, getEdges]);
108
- const hasParallelOffset = parallelEdgeOffset.offsetX !== 0 || parallelEdgeOffset.offsetY !== 0;
109
- const edgePath = hasParallelOffset ? connectorType === "straight" ? getStraightPathWithParallelOffset(
110
- sourceX,
111
- sourceY,
112
- targetX,
113
- targetY,
114
- parallelEdgeOffset.offsetX,
115
- parallelEdgeOffset.offsetY
116
- ) : applyAvoidPathParallelOffset(
117
- basePath,
118
- sourceX,
119
- sourceY,
120
- targetX,
121
- targetY,
122
- parallelEdgeOffset.offsetX,
123
- parallelEdgeOffset.offsetY
124
- ) : basePath;
125
- const effectiveStrokeDasharray = _nullishCoalesce(strokeDasharray, () => ( (!isRouted ? "12,4" : void 0)));
126
- const edgeLength = Math.hypot(targetX - sourceX, targetY - sourceY);
127
- const labelWidthApprox = (_nullishCoalesce(_optionalChain([label, 'optionalAccess', _12 => _12.length]), () => ( 0))) * LABEL_WIDTH_APPROX_PX_PER_CHAR;
128
- const minLengthToShowLabel = Math.max(
129
- MIN_EDGE_LENGTH_FOR_LABEL_PX,
130
- labelWidthApprox + LABEL_PADDING_PX
131
- );
132
- const showLabelByLength = !label || edgeLength >= minLengthToShowLabel;
133
- const style = _react.useMemo.call(void 0,
134
- () => ({
135
- strokeWidth,
136
- stroke: strokeColor,
137
- strokeDasharray: effectiveStrokeDasharray
138
- }),
139
- [strokeWidth, strokeColor, effectiveStrokeDasharray]
140
- );
141
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
142
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
143
- _react3.BaseEdge,
144
- {
145
- id,
146
- path: edgePath,
147
- markerEnd: effectiveMarkerEnd,
148
- markerStart: effectiveMarkerStart,
149
- style
150
- }
151
- ),
152
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _react3.EdgeLabelRenderer, { children: [
153
- erRelation && (() => {
154
- const relDef = ER_RELATIONS.find((r) => r.id === erRelation);
155
- if (!relDef) return null;
156
- const sOff = offsetPoint(sourceX, sourceY, targetX, targetY, 20);
157
- const tOff = offsetPoint(targetX, targetY, sourceX, sourceY, 20);
158
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
159
- relDef.sourceLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
160
- "div",
161
- {
162
- style: {
163
- position: "absolute",
164
- transform: `translate(-50%, -50%) translate(${sOff.x}px,${sOff.y}px)`,
165
- pointerEvents: "none",
166
- zIndex: 10
167
- },
168
- className: "nodrag nopan",
169
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: {
170
- padding: "2px 6px",
171
- fontSize: 10,
172
- fontWeight: "bold",
173
- fontFamily: "monospace",
174
- borderRadius: 4,
175
- background: "white",
176
- border: "1px solid #d1d5db",
177
- color: "#374151",
178
- boxShadow: "0 1px 2px rgba(0,0,0,0.05)"
179
- }, children: relDef.sourceLabel })
180
- }
181
- ),
182
- relDef.targetLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
183
- "div",
184
- {
185
- style: {
186
- position: "absolute",
187
- transform: `translate(-50%, -50%) translate(${tOff.x}px,${tOff.y}px)`,
188
- pointerEvents: "none",
189
- zIndex: 10
190
- },
191
- className: "nodrag nopan",
192
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: {
193
- padding: "2px 6px",
194
- fontSize: 10,
195
- fontWeight: "bold",
196
- fontFamily: "monospace",
197
- borderRadius: 4,
198
- background: "white",
199
- border: "1px solid #d1d5db",
200
- color: "#374151",
201
- boxShadow: "0 1px 2px rgba(0,0,0,0.05)"
202
- }, children: relDef.targetLabel })
203
- }
204
- )
205
- ] });
206
- })(),
207
- label && showLabelByLength && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
208
- "div",
209
- {
210
- style: {
211
- position: "absolute",
212
- transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
213
- pointerEvents: "all",
214
- zIndex: 10,
215
- background: "white",
216
- padding: "2px 10px",
217
- borderRadius: 6,
218
- fontSize: 12,
219
- fontWeight: 500,
220
- border: "1px solid #e2e8f0",
221
- color: "#475569",
222
- boxShadow: "0 1px 2px rgba(0,0,0,0.05)"
223
- },
224
- className: "nodrag nopan",
225
- children: label
226
- }
227
- )
228
- ] }, id)
229
- ] });
230
- }
231
- var AvoidNodesEdge = _react.memo.call(void 0, AvoidNodesEdgeComponent);
232
-
233
-
234
- exports.AvoidNodesEdge = AvoidNodesEdge;
235
- //# sourceMappingURL=edge.cjs.map
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunkHK5MLBM7cjs = require('./chunk-HK5MLBM7.cjs');var _react = require('react');var _react3 = require('@xyflow/react');var _jsxruntime = require('react/jsx-runtime');var ie=22,de=1.5,le=72,ce=7,be=32,fe=[{id:null,label:"None",sourceLabel:"",targetLabel:""},{id:"one-to-one",label:"One to One",sourceLabel:"1",targetLabel:"1"},{id:"one-to-many",label:"One to Many",sourceLabel:"1",targetLabel:"*"},{id:"many-to-one",label:"Many to One",sourceLabel:"*",targetLabel:"1"},{id:"many-to-many",label:"Many to Many",sourceLabel:"*",targetLabel:"*"}];function $(a,n,s,i,t){let e=s-a,o=i-n,r=Math.sqrt(e*e+o*o);if(r===0||t===0)return{x:a,y:n};let c=t/r;return{x:a+e*c,y:n+o*c}}function ue(a,n,s,i,t,e){let o=a+t,r=s+t,c=n+e,h=i+e;return`M ${a} ${n} L ${o} ${c} L ${r} ${h} L ${s} ${i}`}function pe(a,n,s){return a.replace(/([\d.-]+)\s+([\d.-]+)/g,(i,t,e)=>`${Number(t)+n} ${Number(e)+s}`)}function ge(a,n,s,i,t,e,o){let c=pe(a,e,o).replace(/^M\s*[\d.-]+\s+[\d.-]+/,"").trim();return"M "+n+" "+s+" L "+(n+e)+" "+(s+o)+" "+c+" L "+i+" "+t}function me(a){let{id:n,source:s,target:i,sourceX:t,sourceY:e,targetX:o,targetY:r,data:c,sourcePosition:h,targetPosition:T,markerEnd:C,markerStart:W}=a,{getEdges:k}=_react3.useReactFlow.call(void 0, ),d=c,[P,I,X,z]=_chunkHK5MLBM7cjs.h.call(void 0, {id:n,sourceX:t,sourceY:e,targetX:o,targetY:r,sourcePosition:h,targetPosition:T,points:_optionalChain([d, 'optionalAccess', _2 => _2.pathPoints])}),R=_nullishCoalesce(_optionalChain([d, 'optionalAccess', _3 => _3.strokeColor]), () => ("#94a3b8")),M=_nullishCoalesce(_optionalChain([d, 'optionalAccess', _4 => _4.strokeWidth]), () => (de)),B=_optionalChain([d, 'optionalAccess', _5 => _5.strokeDasharray]),y=_nullishCoalesce(_optionalChain([d, 'optionalAccess', _6 => _6.flowDirection]), () => ("mono")),g=_nullishCoalesce(_optionalChain([d, 'optionalAccess', _7 => _7.label]), () => ("")),D=_nullishCoalesce(_optionalChain([d, 'optionalAccess', _8 => _8.erRelation]), () => (null)),G=_nullishCoalesce(_optionalChain([d, 'optionalAccess', _9 => _9.connectorType]), () => ("default")),F=_optionalChain([d, 'optionalAccess', _10 => _10.markerEnd]),H=_optionalChain([d, 'optionalAccess', _11 => _11.markerStart]),Y=y==="mono"||y==="bi"?"url(#arrowClosed)":void 0,q=y==="bi"?"url(#arrowClosed)":void 0,K=_nullishCoalesce(_nullishCoalesce(F, () => (C)), () => (Y)),J=_nullishCoalesce(_nullishCoalesce(H, () => (W)), () => (q)),f=_react.useMemo.call(void 0, ()=>{let l=k().filter(b=>b.source===s&&b.target===i&&b.type==="avoidNodes");if(l.length<=1)return{offsetX:0,offsetY:0};let p=[...l].sort((b,A)=>b.id<A.id?-1:b.id>A.id?1:0).findIndex(b=>b.id===n);if(p<0)return{offsetX:0,offsetY:0};let m=o-t,v=r-e,x=Math.hypot(m,v);if(x===0)return{offsetX:0,offsetY:0};let te=-v/x,ne=m/x,_=(p-(l.length-1)/2)*ie;return{offsetX:te*_,offsetY:ne*_}},[s,i,n,t,e,o,r,k]),Q=f.offsetX!==0||f.offsetY!==0?G==="straight"?ue(t,e,o,r,f.offsetX,f.offsetY):ge(P,t,e,o,r,f.offsetX,f.offsetY):P,S=_nullishCoalesce(B, () => ((z?void 0:"12,4"))),U=Math.hypot(o-t,r-e),V=(_nullishCoalesce(_optionalChain([g, 'optionalAccess', _12 => _12.length]), () => (0)))*ce,Z=Math.max(le,V+be),j=!g||U>=Z,ee=_react.useMemo.call(void 0, ()=>({strokeWidth:M,stroke:R,strokeDasharray:S}),[M,R,S]);return _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment,{children:[_jsxruntime.jsx.call(void 0, _react3.BaseEdge,{id:n,path:Q,markerEnd:K,markerStart:J,style:ee}),_jsxruntime.jsxs.call(void 0, _react3.EdgeLabelRenderer,{children:[D&&(()=>{let l=fe.find(m=>m.id===D);if(!l)return null;let E=$(t,e,o,r,20),p=$(o,r,t,e,20);return _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment,{children:[l.sourceLabel&&_jsxruntime.jsx.call(void 0, "div",{style:{position:"absolute",transform:`translate(-50%, -50%) translate(${E.x}px,${E.y}px)`,pointerEvents:"none",zIndex:10},className:"nodrag nopan",children:_jsxruntime.jsx.call(void 0, "span",{style:{padding:"2px 6px",fontSize:10,fontWeight:"bold",fontFamily:"monospace",borderRadius:4,background:"white",border:"1px solid #d1d5db",color:"#374151",boxShadow:"0 1px 2px rgba(0,0,0,0.05)"},children:l.sourceLabel})}),l.targetLabel&&_jsxruntime.jsx.call(void 0, "div",{style:{position:"absolute",transform:`translate(-50%, -50%) translate(${p.x}px,${p.y}px)`,pointerEvents:"none",zIndex:10},className:"nodrag nopan",children:_jsxruntime.jsx.call(void 0, "span",{style:{padding:"2px 6px",fontSize:10,fontWeight:"bold",fontFamily:"monospace",borderRadius:4,background:"white",border:"1px solid #d1d5db",color:"#374151",boxShadow:"0 1px 2px rgba(0,0,0,0.05)"},children:l.targetLabel})})]})})(),g&&j&&_jsxruntime.jsx.call(void 0, "div",{style:{position:"absolute",transform:`translate(-50%, -50%) translate(${I}px,${X}px)`,pointerEvents:"all",zIndex:10,background:"white",padding:"2px 10px",borderRadius:6,fontSize:12,fontWeight:500,border:"1px solid #e2e8f0",color:"#475569",boxShadow:"0 1px 2px rgba(0,0,0,0.05)"},className:"nodrag nopan",children:g})]},n)]})}var Le=_react.memo.call(void 0, me);exports.AvoidNodesEdge = Le;
package/dist/edge.js CHANGED
@@ -1,235 +1 @@
1
- import {
2
- useAvoidNodesPath
3
- } from "./chunk-VPHZVUPR.js";
4
-
5
- // src/AvoidNodesEdge.tsx
6
- import { memo, useMemo } from "react";
7
- import {
8
- BaseEdge as RFBaseEdge,
9
- EdgeLabelRenderer,
10
- useReactFlow
11
- } from "@xyflow/react";
12
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
- var PARALLEL_EDGE_GAP = 22;
14
- var EDGE_STROKE_WIDTH = 1.5;
15
- var MIN_EDGE_LENGTH_FOR_LABEL_PX = 72;
16
- var LABEL_WIDTH_APPROX_PX_PER_CHAR = 7;
17
- var LABEL_PADDING_PX = 32;
18
- var ER_RELATIONS = [
19
- { id: null, label: "None", sourceLabel: "", targetLabel: "" },
20
- { id: "one-to-one", label: "One to One", sourceLabel: "1", targetLabel: "1" },
21
- { id: "one-to-many", label: "One to Many", sourceLabel: "1", targetLabel: "*" },
22
- { id: "many-to-one", label: "Many to One", sourceLabel: "*", targetLabel: "1" },
23
- { id: "many-to-many", label: "Many to Many", sourceLabel: "*", targetLabel: "*" }
24
- ];
25
- function offsetPoint(fromX, fromY, toX, toY, gap) {
26
- const dx = toX - fromX;
27
- const dy = toY - fromY;
28
- const len = Math.sqrt(dx * dx + dy * dy);
29
- if (len === 0 || gap === 0) return { x: fromX, y: fromY };
30
- const ratio = gap / len;
31
- return { x: fromX + dx * ratio, y: fromY + dy * ratio };
32
- }
33
- function getStraightPathWithParallelOffset(sourceX, sourceY, targetX, targetY, offsetX, offsetY) {
34
- const s2 = sourceX + offsetX;
35
- const t2 = targetX + offsetX;
36
- const s3 = sourceY + offsetY;
37
- const t3 = targetY + offsetY;
38
- return `M ${sourceX} ${sourceY} L ${s2} ${s3} L ${t2} ${t3} L ${targetX} ${targetY}`;
39
- }
40
- function translatePath(pathStr, offsetX, offsetY) {
41
- return pathStr.replace(
42
- /([\d.-]+)\s+([\d.-]+)/g,
43
- (_, a, b) => `${Number(a) + offsetX} ${Number(b) + offsetY}`
44
- );
45
- }
46
- function applyAvoidPathParallelOffset(pathStr, sourceX, sourceY, targetX, targetY, offsetX, offsetY) {
47
- const translated = translatePath(pathStr, offsetX, offsetY);
48
- const rest = translated.replace(/^M\s*[\d.-]+\s+[\d.-]+/, "").trim();
49
- return "M " + sourceX + " " + sourceY + " L " + (sourceX + offsetX) + " " + (sourceY + offsetY) + " " + rest + " L " + targetX + " " + targetY;
50
- }
51
- function AvoidNodesEdgeComponent(props) {
52
- const {
53
- id,
54
- source,
55
- target,
56
- sourceX,
57
- sourceY,
58
- targetX,
59
- targetY,
60
- data,
61
- sourcePosition,
62
- targetPosition,
63
- markerEnd: markerEndProp,
64
- markerStart: markerStartProp
65
- } = props;
66
- const { getEdges } = useReactFlow();
67
- const edgeData = data;
68
- const [basePath, labelX, labelY, isRouted] = useAvoidNodesPath({
69
- id,
70
- sourceX,
71
- sourceY,
72
- targetX,
73
- targetY,
74
- sourcePosition,
75
- targetPosition,
76
- points: edgeData?.pathPoints
77
- });
78
- const strokeColor = edgeData?.strokeColor ?? "#94a3b8";
79
- const strokeWidth = edgeData?.strokeWidth ?? EDGE_STROKE_WIDTH;
80
- const strokeDasharray = edgeData?.strokeDasharray;
81
- const flowDirection = edgeData?.flowDirection ?? "mono";
82
- const label = edgeData?.label ?? "";
83
- const erRelation = edgeData?.erRelation ?? null;
84
- const connectorType = edgeData?.connectorType ?? "default";
85
- const dataMarkerEnd = edgeData?.markerEnd;
86
- const dataMarkerStart = edgeData?.markerStart;
87
- const flowDirectionMarkerEnd = flowDirection === "mono" || flowDirection === "bi" ? "url(#arrowClosed)" : void 0;
88
- const flowDirectionMarkerStart = flowDirection === "bi" ? "url(#arrowClosed)" : void 0;
89
- const effectiveMarkerEnd = dataMarkerEnd ?? markerEndProp ?? flowDirectionMarkerEnd;
90
- const effectiveMarkerStart = dataMarkerStart ?? markerStartProp ?? flowDirectionMarkerStart;
91
- const parallelEdgeOffset = useMemo(() => {
92
- const edges = getEdges().filter(
93
- (e) => e.source === source && e.target === target && e.type === "avoidNodes"
94
- );
95
- if (edges.length <= 1) return { offsetX: 0, offsetY: 0 };
96
- const sorted = [...edges].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
97
- const index = sorted.findIndex((e) => e.id === id);
98
- if (index < 0) return { offsetX: 0, offsetY: 0 };
99
- const dx = targetX - sourceX;
100
- const dy = targetY - sourceY;
101
- const len = Math.hypot(dx, dy);
102
- if (len === 0) return { offsetX: 0, offsetY: 0 };
103
- const perpX = -dy / len;
104
- const perpY = dx / len;
105
- const amount = (index - (edges.length - 1) / 2) * PARALLEL_EDGE_GAP;
106
- return { offsetX: perpX * amount, offsetY: perpY * amount };
107
- }, [source, target, id, sourceX, sourceY, targetX, targetY, getEdges]);
108
- const hasParallelOffset = parallelEdgeOffset.offsetX !== 0 || parallelEdgeOffset.offsetY !== 0;
109
- const edgePath = hasParallelOffset ? connectorType === "straight" ? getStraightPathWithParallelOffset(
110
- sourceX,
111
- sourceY,
112
- targetX,
113
- targetY,
114
- parallelEdgeOffset.offsetX,
115
- parallelEdgeOffset.offsetY
116
- ) : applyAvoidPathParallelOffset(
117
- basePath,
118
- sourceX,
119
- sourceY,
120
- targetX,
121
- targetY,
122
- parallelEdgeOffset.offsetX,
123
- parallelEdgeOffset.offsetY
124
- ) : basePath;
125
- const effectiveStrokeDasharray = strokeDasharray ?? (!isRouted ? "12,4" : void 0);
126
- const edgeLength = Math.hypot(targetX - sourceX, targetY - sourceY);
127
- const labelWidthApprox = (label?.length ?? 0) * LABEL_WIDTH_APPROX_PX_PER_CHAR;
128
- const minLengthToShowLabel = Math.max(
129
- MIN_EDGE_LENGTH_FOR_LABEL_PX,
130
- labelWidthApprox + LABEL_PADDING_PX
131
- );
132
- const showLabelByLength = !label || edgeLength >= minLengthToShowLabel;
133
- const style = useMemo(
134
- () => ({
135
- strokeWidth,
136
- stroke: strokeColor,
137
- strokeDasharray: effectiveStrokeDasharray
138
- }),
139
- [strokeWidth, strokeColor, effectiveStrokeDasharray]
140
- );
141
- return /* @__PURE__ */ jsxs(Fragment, { children: [
142
- /* @__PURE__ */ jsx(
143
- RFBaseEdge,
144
- {
145
- id,
146
- path: edgePath,
147
- markerEnd: effectiveMarkerEnd,
148
- markerStart: effectiveMarkerStart,
149
- style
150
- }
151
- ),
152
- /* @__PURE__ */ jsxs(EdgeLabelRenderer, { children: [
153
- erRelation && (() => {
154
- const relDef = ER_RELATIONS.find((r) => r.id === erRelation);
155
- if (!relDef) return null;
156
- const sOff = offsetPoint(sourceX, sourceY, targetX, targetY, 20);
157
- const tOff = offsetPoint(targetX, targetY, sourceX, sourceY, 20);
158
- return /* @__PURE__ */ jsxs(Fragment, { children: [
159
- relDef.sourceLabel && /* @__PURE__ */ jsx(
160
- "div",
161
- {
162
- style: {
163
- position: "absolute",
164
- transform: `translate(-50%, -50%) translate(${sOff.x}px,${sOff.y}px)`,
165
- pointerEvents: "none",
166
- zIndex: 10
167
- },
168
- className: "nodrag nopan",
169
- children: /* @__PURE__ */ jsx("span", { style: {
170
- padding: "2px 6px",
171
- fontSize: 10,
172
- fontWeight: "bold",
173
- fontFamily: "monospace",
174
- borderRadius: 4,
175
- background: "white",
176
- border: "1px solid #d1d5db",
177
- color: "#374151",
178
- boxShadow: "0 1px 2px rgba(0,0,0,0.05)"
179
- }, children: relDef.sourceLabel })
180
- }
181
- ),
182
- relDef.targetLabel && /* @__PURE__ */ jsx(
183
- "div",
184
- {
185
- style: {
186
- position: "absolute",
187
- transform: `translate(-50%, -50%) translate(${tOff.x}px,${tOff.y}px)`,
188
- pointerEvents: "none",
189
- zIndex: 10
190
- },
191
- className: "nodrag nopan",
192
- children: /* @__PURE__ */ jsx("span", { style: {
193
- padding: "2px 6px",
194
- fontSize: 10,
195
- fontWeight: "bold",
196
- fontFamily: "monospace",
197
- borderRadius: 4,
198
- background: "white",
199
- border: "1px solid #d1d5db",
200
- color: "#374151",
201
- boxShadow: "0 1px 2px rgba(0,0,0,0.05)"
202
- }, children: relDef.targetLabel })
203
- }
204
- )
205
- ] });
206
- })(),
207
- label && showLabelByLength && /* @__PURE__ */ jsx(
208
- "div",
209
- {
210
- style: {
211
- position: "absolute",
212
- transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
213
- pointerEvents: "all",
214
- zIndex: 10,
215
- background: "white",
216
- padding: "2px 10px",
217
- borderRadius: 6,
218
- fontSize: 12,
219
- fontWeight: 500,
220
- border: "1px solid #e2e8f0",
221
- color: "#475569",
222
- boxShadow: "0 1px 2px rgba(0,0,0,0.05)"
223
- },
224
- className: "nodrag nopan",
225
- children: label
226
- }
227
- )
228
- ] }, id)
229
- ] });
230
- }
231
- var AvoidNodesEdge = memo(AvoidNodesEdgeComponent);
232
- export {
233
- AvoidNodesEdge
234
- };
235
- //# sourceMappingURL=edge.js.map
1
+ import{h as w}from"./chunk-2USZC2VI.js";import{memo as oe,useMemo as N}from"react";import{BaseEdge as re,EdgeLabelRenderer as ae,useReactFlow as se}from"@xyflow/react";import{Fragment as O,jsx as u,jsxs as L}from"react/jsx-runtime";var ie=22,de=1.5,le=72,ce=7,be=32,fe=[{id:null,label:"None",sourceLabel:"",targetLabel:""},{id:"one-to-one",label:"One to One",sourceLabel:"1",targetLabel:"1"},{id:"one-to-many",label:"One to Many",sourceLabel:"1",targetLabel:"*"},{id:"many-to-one",label:"Many to One",sourceLabel:"*",targetLabel:"1"},{id:"many-to-many",label:"Many to Many",sourceLabel:"*",targetLabel:"*"}];function $(a,n,s,i,t){let e=s-a,o=i-n,r=Math.sqrt(e*e+o*o);if(r===0||t===0)return{x:a,y:n};let c=t/r;return{x:a+e*c,y:n+o*c}}function ue(a,n,s,i,t,e){let o=a+t,r=s+t,c=n+e,h=i+e;return`M ${a} ${n} L ${o} ${c} L ${r} ${h} L ${s} ${i}`}function pe(a,n,s){return a.replace(/([\d.-]+)\s+([\d.-]+)/g,(i,t,e)=>`${Number(t)+n} ${Number(e)+s}`)}function ge(a,n,s,i,t,e,o){let c=pe(a,e,o).replace(/^M\s*[\d.-]+\s+[\d.-]+/,"").trim();return"M "+n+" "+s+" L "+(n+e)+" "+(s+o)+" "+c+" L "+i+" "+t}function me(a){let{id:n,source:s,target:i,sourceX:t,sourceY:e,targetX:o,targetY:r,data:c,sourcePosition:h,targetPosition:T,markerEnd:C,markerStart:W}=a,{getEdges:k}=se(),d=c,[P,I,X,z]=w({id:n,sourceX:t,sourceY:e,targetX:o,targetY:r,sourcePosition:h,targetPosition:T,points:d?.pathPoints}),R=d?.strokeColor??"#94a3b8",M=d?.strokeWidth??de,B=d?.strokeDasharray,y=d?.flowDirection??"mono",g=d?.label??"",D=d?.erRelation??null,G=d?.connectorType??"default",F=d?.markerEnd,H=d?.markerStart,Y=y==="mono"||y==="bi"?"url(#arrowClosed)":void 0,q=y==="bi"?"url(#arrowClosed)":void 0,K=F??C??Y,J=H??W??q,f=N(()=>{let l=k().filter(b=>b.source===s&&b.target===i&&b.type==="avoidNodes");if(l.length<=1)return{offsetX:0,offsetY:0};let p=[...l].sort((b,A)=>b.id<A.id?-1:b.id>A.id?1:0).findIndex(b=>b.id===n);if(p<0)return{offsetX:0,offsetY:0};let m=o-t,v=r-e,x=Math.hypot(m,v);if(x===0)return{offsetX:0,offsetY:0};let te=-v/x,ne=m/x,_=(p-(l.length-1)/2)*ie;return{offsetX:te*_,offsetY:ne*_}},[s,i,n,t,e,o,r,k]),Q=f.offsetX!==0||f.offsetY!==0?G==="straight"?ue(t,e,o,r,f.offsetX,f.offsetY):ge(P,t,e,o,r,f.offsetX,f.offsetY):P,S=B??(z?void 0:"12,4"),U=Math.hypot(o-t,r-e),V=(g?.length??0)*ce,Z=Math.max(le,V+be),j=!g||U>=Z,ee=N(()=>({strokeWidth:M,stroke:R,strokeDasharray:S}),[M,R,S]);return L(O,{children:[u(re,{id:n,path:Q,markerEnd:K,markerStart:J,style:ee}),L(ae,{children:[D&&(()=>{let l=fe.find(m=>m.id===D);if(!l)return null;let E=$(t,e,o,r,20),p=$(o,r,t,e,20);return L(O,{children:[l.sourceLabel&&u("div",{style:{position:"absolute",transform:`translate(-50%, -50%) translate(${E.x}px,${E.y}px)`,pointerEvents:"none",zIndex:10},className:"nodrag nopan",children:u("span",{style:{padding:"2px 6px",fontSize:10,fontWeight:"bold",fontFamily:"monospace",borderRadius:4,background:"white",border:"1px solid #d1d5db",color:"#374151",boxShadow:"0 1px 2px rgba(0,0,0,0.05)"},children:l.sourceLabel})}),l.targetLabel&&u("div",{style:{position:"absolute",transform:`translate(-50%, -50%) translate(${p.x}px,${p.y}px)`,pointerEvents:"none",zIndex:10},className:"nodrag nopan",children:u("span",{style:{padding:"2px 6px",fontSize:10,fontWeight:"bold",fontFamily:"monospace",borderRadius:4,background:"white",border:"1px solid #d1d5db",color:"#374151",boxShadow:"0 1px 2px rgba(0,0,0,0.05)"},children:l.targetLabel})})]})})(),g&&j&&u("div",{style:{position:"absolute",transform:`translate(-50%, -50%) translate(${I}px,${X}px)`,pointerEvents:"all",zIndex:10,background:"white",padding:"2px 10px",borderRadius:6,fontSize:12,fontWeight:500,border:"1px solid #e2e8f0",color:"#475569",boxShadow:"0 1px 2px rgba(0,0,0,0.05)"},className:"nodrag nopan",children:g})]},n)]})}var Le=oe(me);export{Le as AvoidNodesEdge};