@msdshsk/react-er-canvas 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/MermaidER.d.ts +25 -1
- package/dist/components/MermaidER.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +161 -145
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CSSProperties } from 'react';
|
|
2
|
+
import { FitViewOptions, Rect, Viewport } from '@xyflow/react';
|
|
2
3
|
import { LayoutAlgorithm, LayoutDirection } from '../core/layout';
|
|
3
4
|
import { ColumnRef, ERModel, Join, PartialColumnRef } from '../core/model';
|
|
4
5
|
export interface NodePosition {
|
|
@@ -6,6 +7,29 @@ export interface NodePosition {
|
|
|
6
7
|
y: number;
|
|
7
8
|
}
|
|
8
9
|
export type NodePositions = Record<string, NodePosition>;
|
|
10
|
+
/**
|
|
11
|
+
* Imperative API exposed via `ref`. Designed to give consumers the primitives
|
|
12
|
+
* needed for image export (fit → snapshot → restore) without baking any
|
|
13
|
+
* specific export library into this package. Methods that change the viewport
|
|
14
|
+
* return Promise<boolean> matching React Flow's underlying API.
|
|
15
|
+
*/
|
|
16
|
+
export interface MermaidERHandle {
|
|
17
|
+
/** Fit all nodes into the visible viewport. */
|
|
18
|
+
fitView: (options?: FitViewOptions) => Promise<boolean>;
|
|
19
|
+
/** Read the current viewport (x, y, zoom) — capture before export to restore later. */
|
|
20
|
+
getViewport: () => Viewport;
|
|
21
|
+
/** Restore (or set) viewport. */
|
|
22
|
+
setViewport: (viewport: Viewport) => Promise<boolean>;
|
|
23
|
+
/** Bounding box of all current nodes. Useful for sizing offscreen canvases. */
|
|
24
|
+
getNodesBounds: () => Rect;
|
|
25
|
+
/** Outer wrapper element (the div that receives `className` / `style`). */
|
|
26
|
+
getWrapperElement: () => HTMLDivElement | null;
|
|
27
|
+
/**
|
|
28
|
+
* The internal `.react-flow__viewport` element. Typical snapshot target
|
|
29
|
+
* when you want to exclude `<Controls>` and `<MiniMap>` from the image.
|
|
30
|
+
*/
|
|
31
|
+
getViewportElement: () => HTMLElement | null;
|
|
32
|
+
}
|
|
9
33
|
export interface MermaidERProps {
|
|
10
34
|
/** Mermaid ER source. Mutually exclusive with `model`. */
|
|
11
35
|
source?: string;
|
|
@@ -42,5 +66,5 @@ export interface MermaidERProps {
|
|
|
42
66
|
className?: string;
|
|
43
67
|
style?: CSSProperties;
|
|
44
68
|
}
|
|
45
|
-
export declare
|
|
69
|
+
export declare const MermaidER: import('react').ForwardRefExoticComponent<MermaidERProps & import('react').RefAttributes<MermaidERHandle>>;
|
|
46
70
|
//# sourceMappingURL=MermaidER.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MermaidER.d.ts","sourceRoot":"","sources":["../../src/components/MermaidER.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"MermaidER.d.ts","sourceRoot":"","sources":["../../src/components/MermaidER.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,aAAa,EAEnB,MAAM,OAAO,CAAC;AACf,OAAO,EAUL,KAAK,cAAc,EAGnB,KAAK,IAAI,EACT,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AAMvB,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,eAAe,EAErB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EACP,IAAI,EACJ,gBAAgB,EAEjB,MAAM,eAAe,CAAC;AAqBvB,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,uFAAuF;IACvF,WAAW,EAAE,MAAM,QAAQ,CAAC;IAC5B,iCAAiC;IACjC,WAAW,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,+EAA+E;IAC/E,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,cAAc,GAAG,IAAI,CAAC;IAC/C;;;OAGG;IACH,kBAAkB,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,aAAa,KAAK,IAAI,CAAC;IACvD,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC;IAC9B,uBAAuB,CAAC,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;IACjE,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC7E,8EAA8E;IAC9E,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,0FAA0F;IAC1F,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6GAA6G;IAC7G,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAyED,eAAO,MAAM,SAAS,4GA0UpB,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./core-BtdV83x9.cjs`);let t=require(`react`),n=require(`@xyflow/react`),r=require(`react/jsx-runtime`);var i=(0,t.createContext)(new Map),a=(0,t.createContext)({enabled:!1,selected:new Set,onToggle:()=>void 0}),o=(0,t.createContext)(!1),s=(0,t.createContext)({}),c={pk:{label:`PK`,bg:`#f59e0b`},fk:{label:`FK`,bg:`#3b82f6`},uk:{label:`UK`,bg:`#10b981`}};function l({tableName:e,column:t,highlighted:n,onClick:i,selectionEnabled:a,selected:o,onSelectToggle:s}){let l=[];return t.keys.pk&&l.push(c.pk),t.keys.fk&&l.push(c.fk),t.keys.uk&&l.push(c.uk),(0,r.jsxs)(`div`,{title:t.comment,onClick:i?()=>i(e,t.name):void 0,style:{display:`flex`,alignItems:`center`,gap:6,padding:`0 10px`,fontSize:12,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,borderTop:`1px solid #eee`,height:22,boxSizing:`border-box`,cursor:i?`pointer`:`default`,background:n?`#fef3c7`:o?`#eff6ff`:`transparent`,transition:`background 0.15s`},children:[a&&(0,r.jsx)(`input`,{type:`checkbox`,checked:o,onChange:e=>s(e.target.checked),onClick:e=>e.stopPropagation(),style:{width:13,height:13,margin:0,flexShrink:0,cursor:`pointer`}}),(0,r.jsx)(`span`,{style:{display:`flex`,gap:2,flexShrink:0,minWidth:18},children:l.map(e=>(0,r.jsx)(`span`,{style:{display:`inline-block`,padding:`0 4px`,borderRadius:3,background:e.bg,color:`#fff`,fontSize:9,fontWeight:700,lineHeight:`14px`},children:e.label},e.label))}),(0,r.jsx)(`span`,{style:{flexShrink:0,fontWeight:t.keys.pk?600:400,color:`#1f2937`},children:t.name}),t.type&&(0,r.jsx)(`span`,{style:{flex:1,textAlign:`right`,color:`#9ca3af`,fontStyle:`italic`,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:t.type})]})}var u=(0,t.memo)(function({data:e}){let{table:c}=e,u=(0,t.useContext)(i),d=(0,t.useContext)(a),f=(0,t.useContext)(o),p=(0,t.useContext)(s),m=p.onColumnClick,h=u.get(c.name),g=c.group?`#1e40af`:`#374151`,_=e=>({...e,width:f?9:6,height:f?9:6,background:f?`#3b82f6`:`transparent`,border:f?`1.5px solid #fff`:`none`,boxShadow:f?`0 0 0 1px rgba(59,130,246,0.4)`:`none`,opacity:f?.85:0,pointerEvents:f?`auto`:`none`,cursor:f?`crosshair`:`default`});return(0,r.jsxs)(`div`,{style:{background:`#fff`,border:`1px solid #c4c4c4`,borderRadius:6,boxShadow:`0 2px 6px rgba(0,0,0,0.08)`,overflow:`visible`,width:`100%`,height:`100%`,display:`flex`,flexDirection:`column`,position:`relative`},children:[(0,r.jsx)(n.Handle,{id:`__default-target`,type:`target`,position:n.Position.Left,style:_({top:32/2})}),(0,r.jsx)(n.Handle,{id:`__default-source`,type:`source`,position:n.Position.Right,style:_({top:32/2})}),(0,r.jsxs)(`div`,{style:{padding:`6px 10px`,background:g,color:`#fff`,fontWeight:600,fontSize:13,height:32,boxSizing:`border-box`,display:`flex`,alignItems:`center`,justifyContent:`space-between`,gap:8,borderTopLeftRadius:6,borderTopRightRadius:6},children:[(0,r.jsx)(`span`,{style:{overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:c.name}),(0,r.jsxs)(`span`,{style:{display:`flex`,alignItems:`center`,gap:4,flexShrink:0},children:[c.group&&(0,r.jsx)(`span`,{style:{fontSize:10,opacity:.75,fontWeight:400,padding:`1px 5px`,border:`1px solid rgba(255,255,255,0.3)`,borderRadius:3},children:c.group}),p.onTableRemove&&(0,r.jsx)(`button`,{className:`nodrag`,onClick:e=>{e.stopPropagation(),p.onTableRemove?.(c.name)},onMouseDown:e=>e.stopPropagation(),title:`Remove this table`,style:{background:`rgba(255,255,255,0.18)`,border:`none`,color:`#fff`,width:18,height:18,borderRadius:3,cursor:`pointer`,fontSize:13,fontWeight:700,padding:0,lineHeight:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:`×`})]})]}),c.columns.map((e,i)=>{let a=32+i*22+22/2,o=h?.has(e.name)??!1,s=`${c.name}.${e.name}`,u=d.enabled&&d.selected.has(s);return(0,r.jsxs)(t.Fragment,{children:[(0,r.jsx)(n.Handle,{id:`${e.name}__target`,type:`target`,position:n.Position.Left,style:_({top:a})}),(0,r.jsx)(n.Handle,{id:`${e.name}__source`,type:`source`,position:n.Position.Right,style:_({top:a})}),(0,r.jsx)(l,{tableName:c.name,column:e,highlighted:o,onClick:m,selectionEnabled:d.enabled,selected:u,onSelectToggle:t=>d.onToggle(c.name,e.name,t)})]},`${e.name}-${i}`)})]})}),d=(0,t.memo)(function({id:e,sourceX:t,sourceY:i,targetX:a,targetY:o,sourcePosition:s,targetPosition:c,data:l,selected:u}){let[d,f,p]=(0,n.getSmoothStepPath)({sourceX:t,sourceY:i,sourcePosition:s,targetX:a,targetY:o,targetPosition:c}),m=l??{},h=!!u||!!m.hovered,g=m.color||`#3b82f6`;return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.BaseEdge,{id:e,path:d,style:{stroke:g,strokeWidth:h?2.5:2,strokeDasharray:`6 3`}}),(0,r.jsx)(n.EdgeLabelRenderer,{children:(0,r.jsxs)(`div`,{className:`nodrag nopan`,style:{position:`absolute`,transform:`translate(-50%, -50%) translate(${f}px, ${p}px)`,background:g,color:`#fff`,fontSize:10,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,fontWeight:700,borderRadius:3,padding:`2px 4px 2px 6px`,display:`flex`,alignItems:`center`,gap:4,pointerEvents:`all`,boxShadow:h?`0 0 0 2px rgba(0,0,0,0.4)`:`0 1px 2px rgba(0,0,0,0.15)`,userSelect:`none`},children:[(0,r.jsx)(`span`,{children:m.type}),m.onDelete&&(0,r.jsx)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),m.onDelete?.()},onMouseDown:e=>e.stopPropagation(),title:`Remove this JOIN`,style:{background:`rgba(255,255,255,0.25)`,border:`none`,color:`#fff`,width:14,height:14,borderRadius:2,cursor:`pointer`,fontSize:11,fontWeight:700,padding:0,lineHeight:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:`×`})]})})]})}),f={table:u},p={joinEdge:d};function m(t){try{return{model:e.c(t),error:null}}catch(t){if(t instanceof e.s)return{model:null,error:t};throw t}}function h(e,t){return t?`${t}__${e}`:`__default-${e}`}var g=`join:`;function _(e){if(!e||e.startsWith(`__default-`))return;let t=/^(.+)__(?:source|target)$/.exec(e);return t?t[1]:void 0}function ee(e){return`${e.table}.${e.column}`}var v={INNER:`#3b82f6`,LEFT:`#8b5cf6`,RIGHT:`#a855f7`,FULL:`#ec4899`,CROSS:`#6b7280`};function y(c){let{source:l,model:u,algorithm:d,direction:y,aspectRatio:b,positions:x,onPositionsChange:S,showColumnCheckboxes:C,selectedColumns:w,onColumnSelectionChange:T,enableManualJoins:E,joins:D,onJoinConnect:O,onJoinDelete:k,onTableRemove:A,onColumnClick:j,onTableClick:M,deleteKeyCode:N=`Delete`,className:P,style:F,highlightReferencesOnHover:I=!0}=c,{model:L,error:R}=(0,t.useMemo)(()=>u?{model:u,error:null}:l==null?{model:null,error:null}:m(l),[l,u]),[z,B]=(0,t.useState)(null),[V,H]=(0,t.useState)(null);(0,t.useEffect)(()=>{if(!L){B(null);return}let t=!1;return e.o(L,{algorithm:d,direction:y,aspectRatio:b}).then(e=>{t||B(e)}),()=>{t=!0}},[L,d,y,b]);let U=(0,t.useMemo)(()=>{if(!z||!L)return[];let e=new Map(L.tables.map(e=>[e.name,e])),t=[];for(let n of z.nodes){let r=e.get(n.id);if(!r)continue;let i=x?.[n.id],a={table:r};t.push({id:n.id,type:`table`,position:i??{x:n.x,y:n.y},data:a,width:n.width,height:n.height,draggable:!0,deletable:!1})}return t},[z,L,x]),[W,G,K]=(0,n.useNodesState)(U);(0,t.useEffect)(()=>{G(U)},[U,G]);let q=(0,t.useCallback)((e,t,n)=>{if(!S)return;let r={...x??{}};for(let e of n)r[e.id]={x:e.position.x,y:e.position.y};S(r)},[x,S]),J=(0,t.useMemo)(()=>{if(!(!V||!L))return L.relations.find(e=>e.id===V)},[V,L]),Y=(0,t.useMemo)(()=>{if(!V||!D||!V.startsWith(g))return;let e=V.slice(5);return D.find(t=>t.id===e)},[V,D]),X=(0,t.useMemo)(()=>{let e=new Map;if(!I)return e;let t=(t,n)=>{if(!n)return;let r=e.get(t)??new Set;r.add(n),e.set(t,r)};return J&&(t(J.from,J.fromColumn),t(J.to,J.toColumn)),Y&&(t(Y.source.table,Y.source.column),t(Y.target.table,Y.target.column)),e},[J,Y,I]),Z=(0,t.useMemo)(()=>new Set((w??[]).map(ee)),[w]),Q=(0,t.useCallback)((e,t,n)=>{if(!T)return;let r=w??[];if(n){if(r.some(n=>n.table===e&&n.column===t))return;T([...r,{table:e,column:t}])}else T(r.filter(n=>!(n.table===e&&n.column===t)))},[w,T]),te=(0,t.useMemo)(()=>({enabled:C??!1,selected:Z,onToggle:Q}),[C,Z,Q]),ne=(0,t.useMemo)(()=>{if(!z||!L)return[];let e=new Set(L.tables.map(e=>e.name)),t=new Map(L.relations.map(e=>[e.id,e])),n=[];for(let r of z.edges){if(!e.has(r.source)||!e.has(r.target))continue;let i=t.get(r.id),a=r.id===V;n.push({id:r.id,source:r.source,target:r.target,sourceHandle:h(`source`,i?.fromColumn),targetHandle:h(`target`,i?.toColumn),type:`smoothstep`,animated:a,deletable:!1,style:{stroke:a?`#f59e0b`:`#9ca3af`,strokeWidth:a?2:1.5},label:i?.label,labelStyle:{fontSize:10,fill:`#6b7280`},labelBgStyle:{fill:`#fff`,fillOpacity:.85},labelBgPadding:[4,2],labelBgBorderRadius:3})}let r=[];for(let t of D??[]){if(!e.has(t.source.table)||!e.has(t.target.table))continue;let n=`${g}${t.id}`,i=n===V,a=v[t.type]??`#3b82f6`,o={type:t.type,color:a,hovered:i,onDelete:k?()=>k(t.id):void 0};r.push({id:n,source:t.source.table,target:t.target.table,sourceHandle:h(`source`,t.source.column),targetHandle:h(`target`,t.target.column),type:`joinEdge`,deletable:!0,data:o})}return[...n,...r]},[z,L,D,V,k]),re=(0,t.useCallback)(e=>{O&&(!e.source||!e.target||O({table:e.source,column:_(e.sourceHandle)},{table:e.target,column:_(e.targetHandle)}))},[O]),ie=(0,t.useCallback)(e=>{if(k)for(let t of e)t.id.startsWith(g)&&k(t.id.slice(5))},[k]),$=!!E,ae=(0,t.useMemo)(()=>({onTableRemove:A,onColumnClick:j}),[A,j]);return(0,r.jsxs)(`div`,{className:P,style:{width:`100%`,height:`100%`,position:`relative`,...F},children:[R&&(0,r.jsx)(`div`,{style:{position:`absolute`,top:8,left:8,right:8,zIndex:10,padding:`8px 12px`,background:`#fef2f2`,border:`1px solid #fecaca`,borderRadius:6,color:`#991b1b`,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,fontSize:12,whiteSpace:`pre-wrap`},children:R.message}),!R&&!z&&(0,r.jsx)(`div`,{style:{position:`absolute`,inset:0,display:`flex`,alignItems:`center`,justifyContent:`center`,color:`#9ca3af`,fontSize:13},children:`Computing layout…`}),(0,r.jsx)(i.Provider,{value:X,children:(0,r.jsx)(a.Provider,{value:te,children:(0,r.jsx)(o.Provider,{value:$,children:(0,r.jsx)(s.Provider,{value:ae,children:(0,r.jsxs)(n.ReactFlow,{nodes:W,edges:ne,nodeTypes:f,edgeTypes:p,fitView:!0,onNodesChange:K,onNodeDragStop:q,onNodeClick:M?(e,t)=>M(t.id):void 0,onEdgeMouseEnter:(e,t)=>H(t.id),onEdgeMouseLeave:()=>H(null),onConnect:re,onEdgesDelete:ie,nodesDraggable:!0,nodesConnectable:$,elementsSelectable:!0,deleteKeyCode:N,minZoom:.1,maxZoom:4,children:[(0,r.jsx)(n.Background,{}),(0,r.jsx)(n.Controls,{}),(0,r.jsx)(n.MiniMap,{pannable:!0,zoomable:!0})]})})})})})]})}exports.HEADER_HEIGHT=e.t,exports.MermaidER=y,exports.MermaidERParseError=e.s,exports.NODE_WIDTH=e.n,exports.ROW_HEIGHT=e.r,exports.VERTICAL_PADDING=e.i,exports.estimateNodeHeight=e.a,exports.layoutER=e.o,exports.parseMermaidER=e.c;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./core-BtdV83x9.cjs`);let t=require(`react`),n=require(`@xyflow/react`),r=require(`react/jsx-runtime`);var i=(0,t.createContext)(new Map),a=(0,t.createContext)({enabled:!1,selected:new Set,onToggle:()=>void 0}),o=(0,t.createContext)(!1),s=(0,t.createContext)({}),c={pk:{label:`PK`,bg:`#f59e0b`},fk:{label:`FK`,bg:`#3b82f6`},uk:{label:`UK`,bg:`#10b981`}};function l({tableName:e,column:t,highlighted:n,onClick:i,selectionEnabled:a,selected:o,onSelectToggle:s}){let l=[];return t.keys.pk&&l.push(c.pk),t.keys.fk&&l.push(c.fk),t.keys.uk&&l.push(c.uk),(0,r.jsxs)(`div`,{title:t.comment,onClick:i?()=>i(e,t.name):void 0,style:{display:`flex`,alignItems:`center`,gap:6,padding:`0 10px`,fontSize:12,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,borderTop:`1px solid #eee`,height:22,boxSizing:`border-box`,cursor:i?`pointer`:`default`,background:n?`#fef3c7`:o?`#eff6ff`:`transparent`,transition:`background 0.15s`},children:[a&&(0,r.jsx)(`input`,{type:`checkbox`,checked:o,onChange:e=>s(e.target.checked),onClick:e=>e.stopPropagation(),style:{width:13,height:13,margin:0,flexShrink:0,cursor:`pointer`}}),(0,r.jsx)(`span`,{style:{display:`flex`,gap:2,flexShrink:0,minWidth:18},children:l.map(e=>(0,r.jsx)(`span`,{style:{display:`inline-block`,padding:`0 4px`,borderRadius:3,background:e.bg,color:`#fff`,fontSize:9,fontWeight:700,lineHeight:`14px`},children:e.label},e.label))}),(0,r.jsx)(`span`,{style:{flexShrink:0,fontWeight:t.keys.pk?600:400,color:`#1f2937`},children:t.name}),t.type&&(0,r.jsx)(`span`,{style:{flex:1,textAlign:`right`,color:`#9ca3af`,fontStyle:`italic`,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:t.type})]})}var u=(0,t.memo)(function({data:e}){let{table:c}=e,u=(0,t.useContext)(i),d=(0,t.useContext)(a),f=(0,t.useContext)(o),p=(0,t.useContext)(s),m=p.onColumnClick,h=u.get(c.name),g=c.group?`#1e40af`:`#374151`,_=e=>({...e,width:f?9:6,height:f?9:6,background:f?`#3b82f6`:`transparent`,border:f?`1.5px solid #fff`:`none`,boxShadow:f?`0 0 0 1px rgba(59,130,246,0.4)`:`none`,opacity:f?.85:0,pointerEvents:f?`auto`:`none`,cursor:f?`crosshair`:`default`});return(0,r.jsxs)(`div`,{style:{background:`#fff`,border:`1px solid #c4c4c4`,borderRadius:6,boxShadow:`0 2px 6px rgba(0,0,0,0.08)`,overflow:`visible`,width:`100%`,height:`100%`,display:`flex`,flexDirection:`column`,position:`relative`},children:[(0,r.jsx)(n.Handle,{id:`__default-target`,type:`target`,position:n.Position.Left,style:_({top:32/2})}),(0,r.jsx)(n.Handle,{id:`__default-source`,type:`source`,position:n.Position.Right,style:_({top:32/2})}),(0,r.jsxs)(`div`,{style:{padding:`6px 10px`,background:g,color:`#fff`,fontWeight:600,fontSize:13,height:32,boxSizing:`border-box`,display:`flex`,alignItems:`center`,justifyContent:`space-between`,gap:8,borderTopLeftRadius:6,borderTopRightRadius:6},children:[(0,r.jsx)(`span`,{style:{overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:c.name}),(0,r.jsxs)(`span`,{style:{display:`flex`,alignItems:`center`,gap:4,flexShrink:0},children:[c.group&&(0,r.jsx)(`span`,{style:{fontSize:10,opacity:.75,fontWeight:400,padding:`1px 5px`,border:`1px solid rgba(255,255,255,0.3)`,borderRadius:3},children:c.group}),p.onTableRemove&&(0,r.jsx)(`button`,{className:`nodrag`,onClick:e=>{e.stopPropagation(),p.onTableRemove?.(c.name)},onMouseDown:e=>e.stopPropagation(),title:`Remove this table`,style:{background:`rgba(255,255,255,0.18)`,border:`none`,color:`#fff`,width:18,height:18,borderRadius:3,cursor:`pointer`,fontSize:13,fontWeight:700,padding:0,lineHeight:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:`×`})]})]}),c.columns.map((e,i)=>{let a=32+i*22+22/2,o=h?.has(e.name)??!1,s=`${c.name}.${e.name}`,u=d.enabled&&d.selected.has(s);return(0,r.jsxs)(t.Fragment,{children:[(0,r.jsx)(n.Handle,{id:`${e.name}__target`,type:`target`,position:n.Position.Left,style:_({top:a})}),(0,r.jsx)(n.Handle,{id:`${e.name}__source`,type:`source`,position:n.Position.Right,style:_({top:a})}),(0,r.jsx)(l,{tableName:c.name,column:e,highlighted:o,onClick:m,selectionEnabled:d.enabled,selected:u,onSelectToggle:t=>d.onToggle(c.name,e.name,t)})]},`${e.name}-${i}`)})]})}),d=(0,t.memo)(function({id:e,sourceX:t,sourceY:i,targetX:a,targetY:o,sourcePosition:s,targetPosition:c,data:l,selected:u}){let[d,f,p]=(0,n.getSmoothStepPath)({sourceX:t,sourceY:i,sourcePosition:s,targetX:a,targetY:o,targetPosition:c}),m=l??{},h=!!u||!!m.hovered,g=m.color||`#3b82f6`;return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.BaseEdge,{id:e,path:d,style:{stroke:g,strokeWidth:h?2.5:2,strokeDasharray:`6 3`}}),(0,r.jsx)(n.EdgeLabelRenderer,{children:(0,r.jsxs)(`div`,{className:`nodrag nopan`,style:{position:`absolute`,transform:`translate(-50%, -50%) translate(${f}px, ${p}px)`,background:g,color:`#fff`,fontSize:10,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,fontWeight:700,borderRadius:3,padding:`2px 4px 2px 6px`,display:`flex`,alignItems:`center`,gap:4,pointerEvents:`all`,boxShadow:h?`0 0 0 2px rgba(0,0,0,0.4)`:`0 1px 2px rgba(0,0,0,0.15)`,userSelect:`none`},children:[(0,r.jsx)(`span`,{children:m.type}),m.onDelete&&(0,r.jsx)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),m.onDelete?.()},onMouseDown:e=>e.stopPropagation(),title:`Remove this JOIN`,style:{background:`rgba(255,255,255,0.25)`,border:`none`,color:`#fff`,width:14,height:14,borderRadius:2,cursor:`pointer`,fontSize:11,fontWeight:700,padding:0,lineHeight:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:`×`})]})})]})}),f={table:u},p={joinEdge:d};function m(t){try{return{model:e.c(t),error:null}}catch(t){if(t instanceof e.s)return{model:null,error:t};throw t}}function h(e,t){return t?`${t}__${e}`:`__default-${e}`}var g=`join:`;function _(e){if(!e||e.startsWith(`__default-`))return;let t=/^(.+)__(?:source|target)$/.exec(e);return t?t[1]:void 0}function v(e){return`${e.table}.${e.column}`}var y={INNER:`#3b82f6`,LEFT:`#8b5cf6`,RIGHT:`#a855f7`,FULL:`#ec4899`,CROSS:`#6b7280`};function ee({apiRef:e,wrapperRef:r}){let i=(0,n.useReactFlow)();return(0,t.useImperativeHandle)(e,()=>({fitView:e=>i.fitView(e),getViewport:()=>i.getViewport(),setViewport:e=>i.setViewport(e),getNodesBounds:()=>i.getNodesBounds(i.getNodes()),getWrapperElement:()=>r.current,getViewportElement:()=>r.current?.querySelector(`.react-flow__viewport`)??null}),[i,r]),null}var b=(0,t.forwardRef)(function(c,l){let{source:u,model:d,algorithm:b,direction:x,aspectRatio:S,positions:C,onPositionsChange:w,showColumnCheckboxes:T,selectedColumns:E,onColumnSelectionChange:D,enableManualJoins:O,joins:k,onJoinConnect:A,onJoinDelete:j,onTableRemove:M,onColumnClick:N,onTableClick:P,deleteKeyCode:F=`Delete`,className:I,style:L,highlightReferencesOnHover:R=!0}=c,{model:z,error:B}=(0,t.useMemo)(()=>d?{model:d,error:null}:u==null?{model:null,error:null}:m(u),[u,d]),[V,H]=(0,t.useState)(null),[U,W]=(0,t.useState)(null);(0,t.useEffect)(()=>{if(!z){H(null);return}let t=!1;return e.o(z,{algorithm:b,direction:x,aspectRatio:S}).then(e=>{t||H(e)}),()=>{t=!0}},[z,b,x,S]);let G=(0,t.useMemo)(()=>{if(!V||!z)return[];let e=new Map(z.tables.map(e=>[e.name,e])),t=[];for(let n of V.nodes){let r=e.get(n.id);if(!r)continue;let i=C?.[n.id],a={table:r};t.push({id:n.id,type:`table`,position:i??{x:n.x,y:n.y},data:a,width:n.width,height:n.height,draggable:!0,deletable:!1})}return t},[V,z,C]),[K,q,te]=(0,n.useNodesState)(G);(0,t.useEffect)(()=>{q(G)},[G,q]);let ne=(0,t.useCallback)((e,t,n)=>{if(!w)return;let r={...C??{}};for(let e of n)r[e.id]={x:e.position.x,y:e.position.y};w(r)},[C,w]),J=(0,t.useMemo)(()=>{if(!(!U||!z))return z.relations.find(e=>e.id===U)},[U,z]),Y=(0,t.useMemo)(()=>{if(!U||!k||!U.startsWith(g))return;let e=U.slice(5);return k.find(t=>t.id===e)},[U,k]),re=(0,t.useMemo)(()=>{let e=new Map;if(!R)return e;let t=(t,n)=>{if(!n)return;let r=e.get(t)??new Set;r.add(n),e.set(t,r)};return J&&(t(J.from,J.fromColumn),t(J.to,J.toColumn)),Y&&(t(Y.source.table,Y.source.column),t(Y.target.table,Y.target.column)),e},[J,Y,R]),X=(0,t.useMemo)(()=>new Set((E??[]).map(v)),[E]),Z=(0,t.useCallback)((e,t,n)=>{if(!D)return;let r=E??[];if(n){if(r.some(n=>n.table===e&&n.column===t))return;D([...r,{table:e,column:t}])}else D(r.filter(n=>!(n.table===e&&n.column===t)))},[E,D]),ie=(0,t.useMemo)(()=>({enabled:T??!1,selected:X,onToggle:Z}),[T,X,Z]),ae=(0,t.useMemo)(()=>{if(!V||!z)return[];let e=new Set(z.tables.map(e=>e.name)),t=new Map(z.relations.map(e=>[e.id,e])),n=[];for(let r of V.edges){if(!e.has(r.source)||!e.has(r.target))continue;let i=t.get(r.id),a=r.id===U;n.push({id:r.id,source:r.source,target:r.target,sourceHandle:h(`source`,i?.fromColumn),targetHandle:h(`target`,i?.toColumn),type:`smoothstep`,animated:a,deletable:!1,style:{stroke:a?`#f59e0b`:`#9ca3af`,strokeWidth:a?2:1.5},label:i?.label,labelStyle:{fontSize:10,fill:`#6b7280`},labelBgStyle:{fill:`#fff`,fillOpacity:.85},labelBgPadding:[4,2],labelBgBorderRadius:3})}let r=[];for(let t of k??[]){if(!e.has(t.source.table)||!e.has(t.target.table))continue;let n=`${g}${t.id}`,i=n===U,a=y[t.type]??`#3b82f6`,o={type:t.type,color:a,hovered:i,onDelete:j?()=>j(t.id):void 0};r.push({id:n,source:t.source.table,target:t.target.table,sourceHandle:h(`source`,t.source.column),targetHandle:h(`target`,t.target.column),type:`joinEdge`,deletable:!0,data:o})}return[...n,...r]},[V,z,k,U,j]),oe=(0,t.useCallback)(e=>{A&&(!e.source||!e.target||A({table:e.source,column:_(e.sourceHandle)},{table:e.target,column:_(e.targetHandle)}))},[A]),se=(0,t.useCallback)(e=>{if(j)for(let t of e)t.id.startsWith(g)&&j(t.id.slice(5))},[j]),Q=!!O,ce=(0,t.useMemo)(()=>({onTableRemove:M,onColumnClick:N}),[M,N]),$=(0,t.useRef)(null);return(0,r.jsxs)(`div`,{ref:$,className:I,style:{width:`100%`,height:`100%`,position:`relative`,...L},children:[B&&(0,r.jsx)(`div`,{style:{position:`absolute`,top:8,left:8,right:8,zIndex:10,padding:`8px 12px`,background:`#fef2f2`,border:`1px solid #fecaca`,borderRadius:6,color:`#991b1b`,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,fontSize:12,whiteSpace:`pre-wrap`},children:B.message}),!B&&!V&&(0,r.jsx)(`div`,{style:{position:`absolute`,inset:0,display:`flex`,alignItems:`center`,justifyContent:`center`,color:`#9ca3af`,fontSize:13},children:`Computing layout…`}),(0,r.jsx)(i.Provider,{value:re,children:(0,r.jsx)(a.Provider,{value:ie,children:(0,r.jsx)(o.Provider,{value:Q,children:(0,r.jsx)(s.Provider,{value:ce,children:(0,r.jsxs)(n.ReactFlow,{nodes:K,edges:ae,nodeTypes:f,edgeTypes:p,fitView:!0,onNodesChange:te,onNodeDragStop:ne,onNodeClick:P?(e,t)=>P(t.id):void 0,onEdgeMouseEnter:(e,t)=>W(t.id),onEdgeMouseLeave:()=>W(null),onConnect:oe,onEdgesDelete:se,nodesDraggable:!0,nodesConnectable:Q,elementsSelectable:!0,deleteKeyCode:F,minZoom:.1,maxZoom:4,children:[(0,r.jsx)(n.Background,{}),(0,r.jsx)(n.Controls,{}),(0,r.jsx)(n.MiniMap,{pannable:!0,zoomable:!0}),(0,r.jsx)(ee,{apiRef:l,wrapperRef:$})]})})})})})]})});exports.HEADER_HEIGHT=e.t,exports.MermaidER=b,exports.MermaidERParseError=e.s,exports.NODE_WIDTH=e.n,exports.ROW_HEIGHT=e.r,exports.VERTICAL_PADDING=e.i,exports.estimateNodeHeight=e.a,exports.layoutER=e.o,exports.parseMermaidER=e.c;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/components/TableNode.tsx","../src/components/JoinEdge.tsx","../src/components/MermaidER.tsx"],"sourcesContent":["import { Fragment, createContext, memo, useContext } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport type { NodeProps } from '@xyflow/react';\nimport type { Column, Table } from '../core/model';\nimport { HEADER_HEIGHT, ROW_HEIGHT } from '../core/layout';\n\nexport interface TableNodeData extends Record<string, unknown> {\n table: Table;\n}\n\n/**\n * Map from table name -> set of highlighted column names.\n * Provided by MermaidER, consumed by TableNode for hover-driven highlighting\n * without forcing the whole node array to recompute on every hover change.\n */\nexport const HighlightContext = createContext<ReadonlyMap<string, ReadonlySet<string>>>(new Map());\n\nexport interface ColumnSelectionContextValue {\n enabled: boolean;\n /** \"table.column\" keys for fast lookup. */\n selected: ReadonlySet<string>;\n onToggle: (table: string, column: string, checked: boolean) => void;\n}\n\nexport const ColumnSelectionContext = createContext<ColumnSelectionContextValue>({\n enabled: false,\n selected: new Set(),\n onToggle: () => undefined,\n});\n\n/** When true, column handles become visible/connectable for manual JOIN drawing. */\nexport const ConnectModeContext = createContext<boolean>(false);\n\nexport interface TableActionsContextValue {\n /** When provided, a delete affordance is shown on the table header. */\n onTableRemove?: (table: string) => void;\n /** Per-column click handler. Provided via context (not node data) so its\n * identity can change without invalidating the React Flow node array. */\n onColumnClick?: (table: string, column: string) => void;\n}\n\nexport const TableActionsContext = createContext<TableActionsContextValue>({});\n\nconst KEY_STYLES: Record<'pk' | 'fk' | 'uk', { label: string; bg: string }> = {\n pk: { label: 'PK', bg: '#f59e0b' },\n fk: { label: 'FK', bg: '#3b82f6' },\n uk: { label: 'UK', bg: '#10b981' },\n};\n\nfunction ColumnRow({\n tableName,\n column,\n highlighted,\n onClick,\n selectionEnabled,\n selected,\n onSelectToggle,\n}: {\n tableName: string;\n column: Column;\n highlighted: boolean;\n onClick?: (table: string, column: string) => void;\n selectionEnabled: boolean;\n selected: boolean;\n onSelectToggle: (checked: boolean) => void;\n}) {\n const badges: Array<{ label: string; bg: string }> = [];\n if (column.keys.pk) badges.push(KEY_STYLES.pk);\n if (column.keys.fk) badges.push(KEY_STYLES.fk);\n if (column.keys.uk) badges.push(KEY_STYLES.uk);\n\n return (\n <div\n title={column.comment}\n onClick={onClick ? () => onClick(tableName, column.name) : undefined}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '0 10px',\n fontSize: 12,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n borderTop: '1px solid #eee',\n height: ROW_HEIGHT,\n boxSizing: 'border-box',\n cursor: onClick ? 'pointer' : 'default',\n background: highlighted ? '#fef3c7' : selected ? '#eff6ff' : 'transparent',\n transition: 'background 0.15s',\n }}\n >\n {selectionEnabled && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(e) => onSelectToggle(e.target.checked)}\n onClick={(e) => e.stopPropagation()}\n style={{\n width: 13,\n height: 13,\n margin: 0,\n flexShrink: 0,\n cursor: 'pointer',\n }}\n />\n )}\n <span style={{ display: 'flex', gap: 2, flexShrink: 0, minWidth: 18 }}>\n {badges.map((b) => (\n <span\n key={b.label}\n style={{\n display: 'inline-block',\n padding: '0 4px',\n borderRadius: 3,\n background: b.bg,\n color: '#fff',\n fontSize: 9,\n fontWeight: 700,\n lineHeight: '14px',\n }}\n >\n {b.label}\n </span>\n ))}\n </span>\n <span\n style={{\n flexShrink: 0,\n fontWeight: column.keys.pk ? 600 : 400,\n color: '#1f2937',\n }}\n >\n {column.name}\n </span>\n {column.type && (\n <span\n style={{\n flex: 1,\n textAlign: 'right',\n color: '#9ca3af',\n fontStyle: 'italic',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {column.type}\n </span>\n )}\n </div>\n );\n}\n\nexport const TableNode = memo(function TableNode({ data }: NodeProps) {\n const { table } = data as TableNodeData;\n const highlightMap = useContext(HighlightContext);\n const selection = useContext(ColumnSelectionContext);\n const connectMode = useContext(ConnectModeContext);\n const tableActions = useContext(TableActionsContext);\n const onColumnClick = tableActions.onColumnClick;\n const highlightedCols = highlightMap.get(table.name);\n const headerBg = table.group ? '#1e40af' : '#374151';\n\n const handleStyle = (extra: { top?: number }): React.CSSProperties => ({\n ...extra,\n width: connectMode ? 9 : 6,\n height: connectMode ? 9 : 6,\n background: connectMode ? '#3b82f6' : 'transparent',\n border: connectMode ? '1.5px solid #fff' : 'none',\n boxShadow: connectMode ? '0 0 0 1px rgba(59,130,246,0.4)' : 'none',\n opacity: connectMode ? 0.85 : 0,\n pointerEvents: connectMode ? 'auto' : 'none',\n cursor: connectMode ? 'crosshair' : 'default',\n });\n\n return (\n <div\n style={{\n background: '#fff',\n border: '1px solid #c4c4c4',\n borderRadius: 6,\n boxShadow: '0 2px 6px rgba(0,0,0,0.08)',\n overflow: 'visible',\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n }}\n >\n <Handle\n id=\"__default-target\"\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n <Handle\n id=\"__default-source\"\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n\n <div\n style={{\n padding: '6px 10px',\n background: headerBg,\n color: '#fff',\n fontWeight: 600,\n fontSize: 13,\n height: HEADER_HEIGHT,\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n borderTopLeftRadius: 6,\n borderTopRightRadius: 6,\n }}\n >\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {table.name}\n </span>\n <span style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>\n {table.group && (\n <span\n style={{\n fontSize: 10,\n opacity: 0.75,\n fontWeight: 400,\n padding: '1px 5px',\n border: '1px solid rgba(255,255,255,0.3)',\n borderRadius: 3,\n }}\n >\n {table.group}\n </span>\n )}\n {tableActions.onTableRemove && (\n <button\n className=\"nodrag\"\n onClick={(e) => {\n e.stopPropagation();\n tableActions.onTableRemove?.(table.name);\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this table\"\n style={{\n background: 'rgba(255,255,255,0.18)',\n border: 'none',\n color: '#fff',\n width: 18,\n height: 18,\n borderRadius: 3,\n cursor: 'pointer',\n fontSize: 13,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </span>\n </div>\n\n {table.columns.map((col, i) => {\n const handleY = HEADER_HEIGHT + i * ROW_HEIGHT + ROW_HEIGHT / 2;\n const highlighted = highlightedCols?.has(col.name) ?? false;\n const selectionKey = `${table.name}.${col.name}`;\n const selected = selection.enabled && selection.selected.has(selectionKey);\n return (\n <Fragment key={`${col.name}-${i}`}>\n <Handle\n id={`${col.name}__target`}\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: handleY })}\n />\n <Handle\n id={`${col.name}__source`}\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: handleY })}\n />\n <ColumnRow\n tableName={table.name}\n column={col}\n highlighted={highlighted}\n onClick={onColumnClick}\n selectionEnabled={selection.enabled}\n selected={selected}\n onSelectToggle={(checked) =>\n selection.onToggle(table.name, col.name, checked)\n }\n />\n </Fragment>\n );\n })}\n </div>\n );\n});\n","import { memo } from 'react';\nimport {\n BaseEdge,\n EdgeLabelRenderer,\n getSmoothStepPath,\n type EdgeProps,\n} from '@xyflow/react';\nimport type { JoinType } from '../core/model';\n\nexport interface JoinEdgeData extends Record<string, unknown> {\n type: JoinType;\n color: string;\n hovered?: boolean;\n onDelete?: () => void;\n}\n\nexport const JoinEdge = memo(function JoinEdge({\n id,\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n data,\n selected,\n}: EdgeProps) {\n const [edgePath, labelX, labelY] = getSmoothStepPath({\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n });\n\n const d = (data ?? {}) as JoinEdgeData;\n const emphasized = !!selected || !!d.hovered;\n const color = d.color || '#3b82f6';\n\n return (\n <>\n <BaseEdge\n id={id}\n path={edgePath}\n style={{\n stroke: color,\n strokeWidth: emphasized ? 2.5 : 2,\n strokeDasharray: '6 3',\n }}\n />\n <EdgeLabelRenderer>\n <div\n className=\"nodrag nopan\"\n style={{\n position: 'absolute',\n transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,\n background: color,\n color: '#fff',\n fontSize: 10,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontWeight: 700,\n borderRadius: 3,\n padding: '2px 4px 2px 6px',\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n pointerEvents: 'all',\n boxShadow: emphasized\n ? '0 0 0 2px rgba(0,0,0,0.4)'\n : '0 1px 2px rgba(0,0,0,0.15)',\n userSelect: 'none',\n }}\n >\n <span>{d.type}</span>\n {d.onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n d.onDelete?.();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this JOIN\"\n style={{\n background: 'rgba(255,255,255,0.25)',\n border: 'none',\n color: '#fff',\n width: 14,\n height: 14,\n borderRadius: 2,\n cursor: 'pointer',\n fontSize: 11,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </div>\n </EdgeLabelRenderer>\n </>\n );\n});\n","import {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n} from 'react';\nimport {\n ReactFlow,\n Background,\n Controls,\n MiniMap,\n useNodesState,\n type Connection,\n type Edge,\n type EdgeTypes,\n type Node,\n type NodeTypes,\n} from '@xyflow/react';\n// React Flow's CSS is intentionally NOT imported here. Consumers must add it\n// once at their app entry point: `import '@xyflow/react/dist/style.css';`.\n// Importing it from this file would cause double-injection in apps that\n// already use React Flow, and inflate this library's bundled assets.\nimport { parseMermaidER, MermaidERParseError } from '../core/parser';\nimport {\n layoutER,\n type LayoutAlgorithm,\n type LayoutDirection,\n type LayoutResult,\n} from '../core/layout';\nimport type {\n ColumnRef,\n ERModel,\n Join,\n PartialColumnRef,\n Relation,\n} from '../core/model';\nimport {\n ColumnSelectionContext,\n ConnectModeContext,\n HighlightContext,\n TableActionsContext,\n TableNode,\n type ColumnSelectionContextValue,\n type TableActionsContextValue,\n type TableNodeData,\n} from './TableNode';\nimport { JoinEdge, type JoinEdgeData } from './JoinEdge';\n\nconst nodeTypes: NodeTypes = {\n table: TableNode,\n};\n\nconst edgeTypes: EdgeTypes = {\n joinEdge: JoinEdge,\n};\n\nexport interface NodePosition {\n x: number;\n y: number;\n}\n\nexport type NodePositions = Record<string, NodePosition>;\n\nexport interface MermaidERProps {\n /** Mermaid ER source. Mutually exclusive with `model`. */\n source?: string;\n /** Pre-built ER model. Takes precedence over `source`. */\n model?: ERModel;\n layout?: 'elk';\n algorithm?: LayoutAlgorithm;\n direction?: LayoutDirection;\n aspectRatio?: number;\n positions?: NodePositions;\n onPositionsChange?: (positions: NodePositions) => void;\n showColumnCheckboxes?: boolean;\n selectedColumns?: ColumnRef[];\n onColumnSelectionChange?: (selectedColumns: ColumnRef[]) => void;\n /** Enable column-to-column / card-to-card drag for manual JOINs. */\n enableManualJoins?: boolean;\n /** Existing manual joins to render alongside FK relations. */\n joins?: Join[];\n /**\n * Fired when the user finishes a connect drag. The consumer typically opens\n * a dialog to ask for join type, then appends a complete `Join` to its state.\n * `column` may be undefined when the drag landed on a default (table-center) handle.\n */\n onJoinConnect?: (source: PartialColumnRef, target: PartialColumnRef) => void;\n /** Fired when the user removes a manual join via Delete or the trash icon. */\n onJoinDelete?: (joinId: string) => void;\n /** When provided, a small × appears on each table header to remove it from the canvas. */\n onTableRemove?: (table: string) => void;\n highlightReferencesOnHover?: boolean;\n onColumnClick?: (table: string, column: string) => void;\n onTableClick?: (table: string) => void;\n /** Override the default delete-key code(s). Default is 'Delete' (Backspace ignored to prevent accidents). */\n deleteKeyCode?: string | string[] | null;\n className?: string;\n style?: CSSProperties;\n}\n\ninterface ParseState {\n model: ERModel | null;\n error: MermaidERParseError | null;\n}\n\nfunction safeParse(source: string): ParseState {\n try {\n return { model: parseMermaidER(source), error: null };\n } catch (e) {\n if (e instanceof MermaidERParseError) {\n return { model: null, error: e };\n }\n throw e;\n }\n}\n\nfunction handleIdFor(side: 'source' | 'target', column: string | undefined): string {\n return column ? `${column}__${side}` : `__default-${side}`;\n}\n\nconst JOIN_EDGE_PREFIX = 'join:';\n\nfunction parseHandleColumn(handleId: string | null | undefined): string | undefined {\n if (!handleId) return undefined;\n if (handleId.startsWith('__default-')) return undefined;\n const m = /^(.+)__(?:source|target)$/.exec(handleId);\n return m ? m[1] : undefined;\n}\n\nfunction refKey(ref: ColumnRef): string {\n return `${ref.table}.${ref.column}`;\n}\n\nconst JOIN_TYPE_COLOR: Record<Join['type'], string> = {\n INNER: '#3b82f6',\n LEFT: '#8b5cf6',\n RIGHT: '#a855f7',\n FULL: '#ec4899',\n CROSS: '#6b7280',\n};\n\nexport function MermaidER(props: MermaidERProps) {\n const {\n source,\n model: modelProp,\n algorithm,\n direction,\n aspectRatio,\n positions,\n onPositionsChange,\n showColumnCheckboxes,\n selectedColumns,\n onColumnSelectionChange,\n enableManualJoins,\n joins,\n onJoinConnect,\n onJoinDelete,\n onTableRemove,\n onColumnClick,\n onTableClick,\n deleteKeyCode = 'Delete',\n className,\n style,\n highlightReferencesOnHover = true,\n } = props;\n\n const { model, error } = useMemo<ParseState>(() => {\n if (modelProp) return { model: modelProp, error: null };\n if (source != null) return safeParse(source);\n return { model: null, error: null };\n }, [source, modelProp]);\n\n const [layout, setLayout] = useState<LayoutResult | null>(null);\n const [hoveredEdgeId, setHoveredEdgeId] = useState<string | null>(null);\n\n useEffect(() => {\n if (!model) {\n setLayout(null);\n return;\n }\n let cancelled = false;\n layoutER(model, { algorithm, direction, aspectRatio }).then((result) => {\n if (!cancelled) setLayout(result);\n });\n return () => {\n cancelled = true;\n };\n }, [model, algorithm, direction, aspectRatio]);\n\n const baseNodes = useMemo<Node[]>(() => {\n if (!layout || !model) return [];\n const tableMap = new Map(model.tables.map((t) => [t.name, t]));\n const result: Node[] = [];\n for (const n of layout.nodes) {\n const table = tableMap.get(n.id);\n // Skip stale nodes: a model update can arrive before the new layout\n // finishes; in that gap, layout may still reference a removed table.\n if (!table) continue;\n const override = positions?.[n.id];\n const data: TableNodeData = { table };\n result.push({\n id: n.id,\n type: 'table',\n position: override ?? { x: n.x, y: n.y },\n data,\n width: n.width,\n height: n.height,\n draggable: true,\n deletable: false,\n });\n }\n return result;\n // `onColumnClick` is intentionally NOT a dep — it flows via TableActionsContext\n // so a non-stable callback identity from the parent doesn't reset React Flow\n // node state (which would clobber an in-flight drag).\n }, [layout, model, positions]);\n\n const [nodes, setNodes, onNodesChange] = useNodesState<Node>(baseNodes);\n\n useEffect(() => {\n setNodes(baseNodes);\n }, [baseNodes, setNodes]);\n\n const handleNodeDragStop = useCallback(\n (_: unknown, _primary: Node, dragged: Node[]) => {\n if (!onPositionsChange) return;\n const next: NodePositions = { ...(positions ?? {}) };\n for (const n of dragged) {\n next[n.id] = { x: n.position.x, y: n.position.y };\n }\n onPositionsChange(next);\n },\n [positions, onPositionsChange],\n );\n\n const hoveredRelation = useMemo<Relation | undefined>(() => {\n if (!hoveredEdgeId || !model) return undefined;\n return model.relations.find((r) => r.id === hoveredEdgeId);\n }, [hoveredEdgeId, model]);\n\n const hoveredJoin = useMemo<Join | undefined>(() => {\n if (!hoveredEdgeId || !joins) return undefined;\n if (!hoveredEdgeId.startsWith(JOIN_EDGE_PREFIX)) return undefined;\n const id = hoveredEdgeId.slice(JOIN_EDGE_PREFIX.length);\n return joins.find((j) => j.id === id);\n }, [hoveredEdgeId, joins]);\n\n const highlightMap = useMemo<ReadonlyMap<string, ReadonlySet<string>>>(() => {\n const map = new Map<string, Set<string>>();\n if (!highlightReferencesOnHover) return map;\n\n const add = (table: string, column: string | undefined) => {\n if (!column) return;\n const set = map.get(table) ?? new Set();\n set.add(column);\n map.set(table, set);\n };\n\n if (hoveredRelation) {\n add(hoveredRelation.from, hoveredRelation.fromColumn);\n add(hoveredRelation.to, hoveredRelation.toColumn);\n }\n if (hoveredJoin) {\n add(hoveredJoin.source.table, hoveredJoin.source.column);\n add(hoveredJoin.target.table, hoveredJoin.target.column);\n }\n return map;\n }, [hoveredRelation, hoveredJoin, highlightReferencesOnHover]);\n\n const selectionSet = useMemo<ReadonlySet<string>>(() => {\n return new Set((selectedColumns ?? []).map(refKey));\n }, [selectedColumns]);\n\n const handleColumnSelectToggle = useCallback(\n (table: string, column: string, checked: boolean) => {\n if (!onColumnSelectionChange) return;\n const list = selectedColumns ?? [];\n if (checked) {\n if (list.some((r) => r.table === table && r.column === column)) return;\n onColumnSelectionChange([...list, { table, column }]);\n } else {\n onColumnSelectionChange(\n list.filter((r) => !(r.table === table && r.column === column)),\n );\n }\n },\n [selectedColumns, onColumnSelectionChange],\n );\n\n const selectionContext = useMemo<ColumnSelectionContextValue>(\n () => ({\n enabled: showColumnCheckboxes ?? false,\n selected: selectionSet,\n onToggle: handleColumnSelectToggle,\n }),\n [showColumnCheckboxes, selectionSet, handleColumnSelectToggle],\n );\n\n const edges = useMemo<Edge[]>(() => {\n if (!layout || !model) return [];\n const tableSet = new Set(model.tables.map((t) => t.name));\n const relMap = new Map(model.relations.map((r) => [r.id, r]));\n\n const fkEdges: Edge[] = [];\n for (const e of layout.edges) {\n // Skip stale edges referencing tables removed since the layout was computed.\n if (!tableSet.has(e.source) || !tableSet.has(e.target)) continue;\n const rel = relMap.get(e.id);\n const isHovered = e.id === hoveredEdgeId;\n fkEdges.push({\n id: e.id,\n source: e.source,\n target: e.target,\n sourceHandle: handleIdFor('source', rel?.fromColumn),\n targetHandle: handleIdFor('target', rel?.toColumn),\n type: 'smoothstep',\n animated: isHovered,\n deletable: false,\n style: {\n stroke: isHovered ? '#f59e0b' : '#9ca3af',\n strokeWidth: isHovered ? 2 : 1.5,\n },\n label: rel?.label,\n labelStyle: { fontSize: 10, fill: '#6b7280' },\n labelBgStyle: { fill: '#fff', fillOpacity: 0.85 },\n labelBgPadding: [4, 2] as [number, number],\n labelBgBorderRadius: 3,\n });\n }\n\n const joinEdges: Edge[] = [];\n for (const j of joins ?? []) {\n if (!tableSet.has(j.source.table) || !tableSet.has(j.target.table)) continue;\n const edgeId = `${JOIN_EDGE_PREFIX}${j.id}`;\n const isHovered = edgeId === hoveredEdgeId;\n const color = JOIN_TYPE_COLOR[j.type] ?? '#3b82f6';\n const data: JoinEdgeData = {\n type: j.type,\n color,\n hovered: isHovered,\n onDelete: onJoinDelete ? () => onJoinDelete(j.id) : undefined,\n };\n joinEdges.push({\n id: edgeId,\n source: j.source.table,\n target: j.target.table,\n sourceHandle: handleIdFor('source', j.source.column),\n targetHandle: handleIdFor('target', j.target.column),\n type: 'joinEdge',\n deletable: true,\n data: data as unknown as Record<string, unknown>,\n });\n }\n\n return [...fkEdges, ...joinEdges];\n }, [layout, model, joins, hoveredEdgeId, onJoinDelete]);\n\n const handleConnect = useCallback(\n (conn: Connection) => {\n if (!onJoinConnect) return;\n if (!conn.source || !conn.target) return;\n onJoinConnect(\n { table: conn.source, column: parseHandleColumn(conn.sourceHandle) },\n { table: conn.target, column: parseHandleColumn(conn.targetHandle) },\n );\n },\n [onJoinConnect],\n );\n\n const handleEdgesDelete = useCallback(\n (deleted: Edge[]) => {\n if (!onJoinDelete) return;\n for (const e of deleted) {\n if (e.id.startsWith(JOIN_EDGE_PREFIX)) {\n onJoinDelete(e.id.slice(JOIN_EDGE_PREFIX.length));\n }\n }\n },\n [onJoinDelete],\n );\n\n const connectModeOn = !!enableManualJoins;\n const tableActions = useMemo<TableActionsContextValue>(\n () => ({ onTableRemove, onColumnClick }),\n [onTableRemove, onColumnClick],\n );\n\n return (\n <div\n className={className}\n style={{ width: '100%', height: '100%', position: 'relative', ...style }}\n >\n {error && (\n <div\n style={{\n position: 'absolute',\n top: 8,\n left: 8,\n right: 8,\n zIndex: 10,\n padding: '8px 12px',\n background: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 6,\n color: '#991b1b',\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontSize: 12,\n whiteSpace: 'pre-wrap',\n }}\n >\n {error.message}\n </div>\n )}\n {!error && !layout && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#9ca3af',\n fontSize: 13,\n }}\n >\n Computing layout…\n </div>\n )}\n <HighlightContext.Provider value={highlightMap}>\n <ColumnSelectionContext.Provider value={selectionContext}>\n <ConnectModeContext.Provider value={connectModeOn}>\n <TableActionsContext.Provider value={tableActions}>\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n fitView\n onNodesChange={onNodesChange}\n onNodeDragStop={handleNodeDragStop}\n onNodeClick={\n onTableClick ? (_, node) => onTableClick(node.id) : undefined\n }\n onEdgeMouseEnter={(_, edge) => setHoveredEdgeId(edge.id)}\n onEdgeMouseLeave={() => setHoveredEdgeId(null)}\n onConnect={handleConnect}\n onEdgesDelete={handleEdgesDelete}\n nodesDraggable\n nodesConnectable={connectModeOn}\n elementsSelectable\n deleteKeyCode={deleteKeyCode}\n minZoom={0.1}\n maxZoom={4}\n >\n <Background />\n <Controls />\n <MiniMap pannable zoomable />\n </ReactFlow>\n </TableActionsContext.Provider>\n </ConnectModeContext.Provider>\n </ColumnSelectionContext.Provider>\n </HighlightContext.Provider>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/components/TableNode.tsx","../src/components/JoinEdge.tsx","../src/components/MermaidER.tsx"],"sourcesContent":["import { Fragment, createContext, memo, useContext } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport type { NodeProps } from '@xyflow/react';\nimport type { Column, Table } from '../core/model';\nimport { HEADER_HEIGHT, ROW_HEIGHT } from '../core/layout';\n\nexport interface TableNodeData extends Record<string, unknown> {\n table: Table;\n}\n\n/**\n * Map from table name -> set of highlighted column names.\n * Provided by MermaidER, consumed by TableNode for hover-driven highlighting\n * without forcing the whole node array to recompute on every hover change.\n */\nexport const HighlightContext = createContext<ReadonlyMap<string, ReadonlySet<string>>>(new Map());\n\nexport interface ColumnSelectionContextValue {\n enabled: boolean;\n /** \"table.column\" keys for fast lookup. */\n selected: ReadonlySet<string>;\n onToggle: (table: string, column: string, checked: boolean) => void;\n}\n\nexport const ColumnSelectionContext = createContext<ColumnSelectionContextValue>({\n enabled: false,\n selected: new Set(),\n onToggle: () => undefined,\n});\n\n/** When true, column handles become visible/connectable for manual JOIN drawing. */\nexport const ConnectModeContext = createContext<boolean>(false);\n\nexport interface TableActionsContextValue {\n /** When provided, a delete affordance is shown on the table header. */\n onTableRemove?: (table: string) => void;\n /** Per-column click handler. Provided via context (not node data) so its\n * identity can change without invalidating the React Flow node array. */\n onColumnClick?: (table: string, column: string) => void;\n}\n\nexport const TableActionsContext = createContext<TableActionsContextValue>({});\n\nconst KEY_STYLES: Record<'pk' | 'fk' | 'uk', { label: string; bg: string }> = {\n pk: { label: 'PK', bg: '#f59e0b' },\n fk: { label: 'FK', bg: '#3b82f6' },\n uk: { label: 'UK', bg: '#10b981' },\n};\n\nfunction ColumnRow({\n tableName,\n column,\n highlighted,\n onClick,\n selectionEnabled,\n selected,\n onSelectToggle,\n}: {\n tableName: string;\n column: Column;\n highlighted: boolean;\n onClick?: (table: string, column: string) => void;\n selectionEnabled: boolean;\n selected: boolean;\n onSelectToggle: (checked: boolean) => void;\n}) {\n const badges: Array<{ label: string; bg: string }> = [];\n if (column.keys.pk) badges.push(KEY_STYLES.pk);\n if (column.keys.fk) badges.push(KEY_STYLES.fk);\n if (column.keys.uk) badges.push(KEY_STYLES.uk);\n\n return (\n <div\n title={column.comment}\n onClick={onClick ? () => onClick(tableName, column.name) : undefined}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '0 10px',\n fontSize: 12,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n borderTop: '1px solid #eee',\n height: ROW_HEIGHT,\n boxSizing: 'border-box',\n cursor: onClick ? 'pointer' : 'default',\n background: highlighted ? '#fef3c7' : selected ? '#eff6ff' : 'transparent',\n transition: 'background 0.15s',\n }}\n >\n {selectionEnabled && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(e) => onSelectToggle(e.target.checked)}\n onClick={(e) => e.stopPropagation()}\n style={{\n width: 13,\n height: 13,\n margin: 0,\n flexShrink: 0,\n cursor: 'pointer',\n }}\n />\n )}\n <span style={{ display: 'flex', gap: 2, flexShrink: 0, minWidth: 18 }}>\n {badges.map((b) => (\n <span\n key={b.label}\n style={{\n display: 'inline-block',\n padding: '0 4px',\n borderRadius: 3,\n background: b.bg,\n color: '#fff',\n fontSize: 9,\n fontWeight: 700,\n lineHeight: '14px',\n }}\n >\n {b.label}\n </span>\n ))}\n </span>\n <span\n style={{\n flexShrink: 0,\n fontWeight: column.keys.pk ? 600 : 400,\n color: '#1f2937',\n }}\n >\n {column.name}\n </span>\n {column.type && (\n <span\n style={{\n flex: 1,\n textAlign: 'right',\n color: '#9ca3af',\n fontStyle: 'italic',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {column.type}\n </span>\n )}\n </div>\n );\n}\n\nexport const TableNode = memo(function TableNode({ data }: NodeProps) {\n const { table } = data as TableNodeData;\n const highlightMap = useContext(HighlightContext);\n const selection = useContext(ColumnSelectionContext);\n const connectMode = useContext(ConnectModeContext);\n const tableActions = useContext(TableActionsContext);\n const onColumnClick = tableActions.onColumnClick;\n const highlightedCols = highlightMap.get(table.name);\n const headerBg = table.group ? '#1e40af' : '#374151';\n\n const handleStyle = (extra: { top?: number }): React.CSSProperties => ({\n ...extra,\n width: connectMode ? 9 : 6,\n height: connectMode ? 9 : 6,\n background: connectMode ? '#3b82f6' : 'transparent',\n border: connectMode ? '1.5px solid #fff' : 'none',\n boxShadow: connectMode ? '0 0 0 1px rgba(59,130,246,0.4)' : 'none',\n opacity: connectMode ? 0.85 : 0,\n pointerEvents: connectMode ? 'auto' : 'none',\n cursor: connectMode ? 'crosshair' : 'default',\n });\n\n return (\n <div\n style={{\n background: '#fff',\n border: '1px solid #c4c4c4',\n borderRadius: 6,\n boxShadow: '0 2px 6px rgba(0,0,0,0.08)',\n overflow: 'visible',\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n }}\n >\n <Handle\n id=\"__default-target\"\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n <Handle\n id=\"__default-source\"\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n\n <div\n style={{\n padding: '6px 10px',\n background: headerBg,\n color: '#fff',\n fontWeight: 600,\n fontSize: 13,\n height: HEADER_HEIGHT,\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n borderTopLeftRadius: 6,\n borderTopRightRadius: 6,\n }}\n >\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {table.name}\n </span>\n <span style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>\n {table.group && (\n <span\n style={{\n fontSize: 10,\n opacity: 0.75,\n fontWeight: 400,\n padding: '1px 5px',\n border: '1px solid rgba(255,255,255,0.3)',\n borderRadius: 3,\n }}\n >\n {table.group}\n </span>\n )}\n {tableActions.onTableRemove && (\n <button\n className=\"nodrag\"\n onClick={(e) => {\n e.stopPropagation();\n tableActions.onTableRemove?.(table.name);\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this table\"\n style={{\n background: 'rgba(255,255,255,0.18)',\n border: 'none',\n color: '#fff',\n width: 18,\n height: 18,\n borderRadius: 3,\n cursor: 'pointer',\n fontSize: 13,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </span>\n </div>\n\n {table.columns.map((col, i) => {\n const handleY = HEADER_HEIGHT + i * ROW_HEIGHT + ROW_HEIGHT / 2;\n const highlighted = highlightedCols?.has(col.name) ?? false;\n const selectionKey = `${table.name}.${col.name}`;\n const selected = selection.enabled && selection.selected.has(selectionKey);\n return (\n <Fragment key={`${col.name}-${i}`}>\n <Handle\n id={`${col.name}__target`}\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: handleY })}\n />\n <Handle\n id={`${col.name}__source`}\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: handleY })}\n />\n <ColumnRow\n tableName={table.name}\n column={col}\n highlighted={highlighted}\n onClick={onColumnClick}\n selectionEnabled={selection.enabled}\n selected={selected}\n onSelectToggle={(checked) =>\n selection.onToggle(table.name, col.name, checked)\n }\n />\n </Fragment>\n );\n })}\n </div>\n );\n});\n","import { memo } from 'react';\nimport {\n BaseEdge,\n EdgeLabelRenderer,\n getSmoothStepPath,\n type EdgeProps,\n} from '@xyflow/react';\nimport type { JoinType } from '../core/model';\n\nexport interface JoinEdgeData extends Record<string, unknown> {\n type: JoinType;\n color: string;\n hovered?: boolean;\n onDelete?: () => void;\n}\n\nexport const JoinEdge = memo(function JoinEdge({\n id,\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n data,\n selected,\n}: EdgeProps) {\n const [edgePath, labelX, labelY] = getSmoothStepPath({\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n });\n\n const d = (data ?? {}) as JoinEdgeData;\n const emphasized = !!selected || !!d.hovered;\n const color = d.color || '#3b82f6';\n\n return (\n <>\n <BaseEdge\n id={id}\n path={edgePath}\n style={{\n stroke: color,\n strokeWidth: emphasized ? 2.5 : 2,\n strokeDasharray: '6 3',\n }}\n />\n <EdgeLabelRenderer>\n <div\n className=\"nodrag nopan\"\n style={{\n position: 'absolute',\n transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,\n background: color,\n color: '#fff',\n fontSize: 10,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontWeight: 700,\n borderRadius: 3,\n padding: '2px 4px 2px 6px',\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n pointerEvents: 'all',\n boxShadow: emphasized\n ? '0 0 0 2px rgba(0,0,0,0.4)'\n : '0 1px 2px rgba(0,0,0,0.15)',\n userSelect: 'none',\n }}\n >\n <span>{d.type}</span>\n {d.onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n d.onDelete?.();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this JOIN\"\n style={{\n background: 'rgba(255,255,255,0.25)',\n border: 'none',\n color: '#fff',\n width: 14,\n height: 14,\n borderRadius: 2,\n cursor: 'pointer',\n fontSize: 11,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </div>\n </EdgeLabelRenderer>\n </>\n );\n});\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type Ref,\n} from 'react';\nimport {\n ReactFlow,\n Background,\n Controls,\n MiniMap,\n useNodesState,\n useReactFlow,\n type Connection,\n type Edge,\n type EdgeTypes,\n type FitViewOptions,\n type Node,\n type NodeTypes,\n type Rect,\n type Viewport,\n} from '@xyflow/react';\n// React Flow's CSS is intentionally NOT imported here. Consumers must add it\n// once at their app entry point: `import '@xyflow/react/dist/style.css';`.\n// Importing it from this file would cause double-injection in apps that\n// already use React Flow, and inflate this library's bundled assets.\nimport { parseMermaidER, MermaidERParseError } from '../core/parser';\nimport {\n layoutER,\n type LayoutAlgorithm,\n type LayoutDirection,\n type LayoutResult,\n} from '../core/layout';\nimport type {\n ColumnRef,\n ERModel,\n Join,\n PartialColumnRef,\n Relation,\n} from '../core/model';\nimport {\n ColumnSelectionContext,\n ConnectModeContext,\n HighlightContext,\n TableActionsContext,\n TableNode,\n type ColumnSelectionContextValue,\n type TableActionsContextValue,\n type TableNodeData,\n} from './TableNode';\nimport { JoinEdge, type JoinEdgeData } from './JoinEdge';\n\nconst nodeTypes: NodeTypes = {\n table: TableNode,\n};\n\nconst edgeTypes: EdgeTypes = {\n joinEdge: JoinEdge,\n};\n\nexport interface NodePosition {\n x: number;\n y: number;\n}\n\nexport type NodePositions = Record<string, NodePosition>;\n\n/**\n * Imperative API exposed via `ref`. Designed to give consumers the primitives\n * needed for image export (fit → snapshot → restore) without baking any\n * specific export library into this package. Methods that change the viewport\n * return Promise<boolean> matching React Flow's underlying API.\n */\nexport interface MermaidERHandle {\n /** Fit all nodes into the visible viewport. */\n fitView: (options?: FitViewOptions) => Promise<boolean>;\n /** Read the current viewport (x, y, zoom) — capture before export to restore later. */\n getViewport: () => Viewport;\n /** Restore (or set) viewport. */\n setViewport: (viewport: Viewport) => Promise<boolean>;\n /** Bounding box of all current nodes. Useful for sizing offscreen canvases. */\n getNodesBounds: () => Rect;\n /** Outer wrapper element (the div that receives `className` / `style`). */\n getWrapperElement: () => HTMLDivElement | null;\n /**\n * The internal `.react-flow__viewport` element. Typical snapshot target\n * when you want to exclude `<Controls>` and `<MiniMap>` from the image.\n */\n getViewportElement: () => HTMLElement | null;\n}\n\nexport interface MermaidERProps {\n /** Mermaid ER source. Mutually exclusive with `model`. */\n source?: string;\n /** Pre-built ER model. Takes precedence over `source`. */\n model?: ERModel;\n layout?: 'elk';\n algorithm?: LayoutAlgorithm;\n direction?: LayoutDirection;\n aspectRatio?: number;\n positions?: NodePositions;\n onPositionsChange?: (positions: NodePositions) => void;\n showColumnCheckboxes?: boolean;\n selectedColumns?: ColumnRef[];\n onColumnSelectionChange?: (selectedColumns: ColumnRef[]) => void;\n /** Enable column-to-column / card-to-card drag for manual JOINs. */\n enableManualJoins?: boolean;\n /** Existing manual joins to render alongside FK relations. */\n joins?: Join[];\n /**\n * Fired when the user finishes a connect drag. The consumer typically opens\n * a dialog to ask for join type, then appends a complete `Join` to its state.\n * `column` may be undefined when the drag landed on a default (table-center) handle.\n */\n onJoinConnect?: (source: PartialColumnRef, target: PartialColumnRef) => void;\n /** Fired when the user removes a manual join via Delete or the trash icon. */\n onJoinDelete?: (joinId: string) => void;\n /** When provided, a small × appears on each table header to remove it from the canvas. */\n onTableRemove?: (table: string) => void;\n highlightReferencesOnHover?: boolean;\n onColumnClick?: (table: string, column: string) => void;\n onTableClick?: (table: string) => void;\n /** Override the default delete-key code(s). Default is 'Delete' (Backspace ignored to prevent accidents). */\n deleteKeyCode?: string | string[] | null;\n className?: string;\n style?: CSSProperties;\n}\n\ninterface ParseState {\n model: ERModel | null;\n error: MermaidERParseError | null;\n}\n\nfunction safeParse(source: string): ParseState {\n try {\n return { model: parseMermaidER(source), error: null };\n } catch (e) {\n if (e instanceof MermaidERParseError) {\n return { model: null, error: e };\n }\n throw e;\n }\n}\n\nfunction handleIdFor(side: 'source' | 'target', column: string | undefined): string {\n return column ? `${column}__${side}` : `__default-${side}`;\n}\n\nconst JOIN_EDGE_PREFIX = 'join:';\n\nfunction parseHandleColumn(handleId: string | null | undefined): string | undefined {\n if (!handleId) return undefined;\n if (handleId.startsWith('__default-')) return undefined;\n const m = /^(.+)__(?:source|target)$/.exec(handleId);\n return m ? m[1] : undefined;\n}\n\nfunction refKey(ref: ColumnRef): string {\n return `${ref.table}.${ref.column}`;\n}\n\nconst JOIN_TYPE_COLOR: Record<Join['type'], string> = {\n INNER: '#3b82f6',\n LEFT: '#8b5cf6',\n RIGHT: '#a855f7',\n FULL: '#ec4899',\n CROSS: '#6b7280',\n};\n\n/**\n * Bridge: `useReactFlow()` only works inside the <ReactFlow> provider, but the\n * imperative ref must be attached to MermaidER (which is the *parent* of\n * <ReactFlow>). This null-rendering child runs the hook in the right scope and\n * forwards the methods back out.\n */\nfunction HandleBridge({\n apiRef,\n wrapperRef,\n}: {\n apiRef: Ref<MermaidERHandle> | undefined;\n wrapperRef: React.RefObject<HTMLDivElement | null>;\n}) {\n const rf = useReactFlow();\n useImperativeHandle(\n apiRef,\n () => ({\n fitView: (options) => rf.fitView(options),\n getViewport: () => rf.getViewport(),\n setViewport: (viewport) => rf.setViewport(viewport),\n getNodesBounds: () => rf.getNodesBounds(rf.getNodes()),\n getWrapperElement: () => wrapperRef.current,\n getViewportElement: () =>\n wrapperRef.current?.querySelector<HTMLElement>('.react-flow__viewport') ?? null,\n }),\n [rf, wrapperRef],\n );\n return null;\n}\n\nexport const MermaidER = forwardRef<MermaidERHandle, MermaidERProps>(function MermaidER(\n props,\n ref,\n) {\n const {\n source,\n model: modelProp,\n algorithm,\n direction,\n aspectRatio,\n positions,\n onPositionsChange,\n showColumnCheckboxes,\n selectedColumns,\n onColumnSelectionChange,\n enableManualJoins,\n joins,\n onJoinConnect,\n onJoinDelete,\n onTableRemove,\n onColumnClick,\n onTableClick,\n deleteKeyCode = 'Delete',\n className,\n style,\n highlightReferencesOnHover = true,\n } = props;\n\n const { model, error } = useMemo<ParseState>(() => {\n if (modelProp) return { model: modelProp, error: null };\n if (source != null) return safeParse(source);\n return { model: null, error: null };\n }, [source, modelProp]);\n\n const [layout, setLayout] = useState<LayoutResult | null>(null);\n const [hoveredEdgeId, setHoveredEdgeId] = useState<string | null>(null);\n\n useEffect(() => {\n if (!model) {\n setLayout(null);\n return;\n }\n let cancelled = false;\n layoutER(model, { algorithm, direction, aspectRatio }).then((result) => {\n if (!cancelled) setLayout(result);\n });\n return () => {\n cancelled = true;\n };\n }, [model, algorithm, direction, aspectRatio]);\n\n const baseNodes = useMemo<Node[]>(() => {\n if (!layout || !model) return [];\n const tableMap = new Map(model.tables.map((t) => [t.name, t]));\n const result: Node[] = [];\n for (const n of layout.nodes) {\n const table = tableMap.get(n.id);\n // Skip stale nodes: a model update can arrive before the new layout\n // finishes; in that gap, layout may still reference a removed table.\n if (!table) continue;\n const override = positions?.[n.id];\n const data: TableNodeData = { table };\n result.push({\n id: n.id,\n type: 'table',\n position: override ?? { x: n.x, y: n.y },\n data,\n width: n.width,\n height: n.height,\n draggable: true,\n deletable: false,\n });\n }\n return result;\n // `onColumnClick` is intentionally NOT a dep — it flows via TableActionsContext\n // so a non-stable callback identity from the parent doesn't reset React Flow\n // node state (which would clobber an in-flight drag).\n }, [layout, model, positions]);\n\n const [nodes, setNodes, onNodesChange] = useNodesState<Node>(baseNodes);\n\n useEffect(() => {\n setNodes(baseNodes);\n }, [baseNodes, setNodes]);\n\n const handleNodeDragStop = useCallback(\n (_: unknown, _primary: Node, dragged: Node[]) => {\n if (!onPositionsChange) return;\n const next: NodePositions = { ...(positions ?? {}) };\n for (const n of dragged) {\n next[n.id] = { x: n.position.x, y: n.position.y };\n }\n onPositionsChange(next);\n },\n [positions, onPositionsChange],\n );\n\n const hoveredRelation = useMemo<Relation | undefined>(() => {\n if (!hoveredEdgeId || !model) return undefined;\n return model.relations.find((r) => r.id === hoveredEdgeId);\n }, [hoveredEdgeId, model]);\n\n const hoveredJoin = useMemo<Join | undefined>(() => {\n if (!hoveredEdgeId || !joins) return undefined;\n if (!hoveredEdgeId.startsWith(JOIN_EDGE_PREFIX)) return undefined;\n const id = hoveredEdgeId.slice(JOIN_EDGE_PREFIX.length);\n return joins.find((j) => j.id === id);\n }, [hoveredEdgeId, joins]);\n\n const highlightMap = useMemo<ReadonlyMap<string, ReadonlySet<string>>>(() => {\n const map = new Map<string, Set<string>>();\n if (!highlightReferencesOnHover) return map;\n\n const add = (table: string, column: string | undefined) => {\n if (!column) return;\n const set = map.get(table) ?? new Set();\n set.add(column);\n map.set(table, set);\n };\n\n if (hoveredRelation) {\n add(hoveredRelation.from, hoveredRelation.fromColumn);\n add(hoveredRelation.to, hoveredRelation.toColumn);\n }\n if (hoveredJoin) {\n add(hoveredJoin.source.table, hoveredJoin.source.column);\n add(hoveredJoin.target.table, hoveredJoin.target.column);\n }\n return map;\n }, [hoveredRelation, hoveredJoin, highlightReferencesOnHover]);\n\n const selectionSet = useMemo<ReadonlySet<string>>(() => {\n return new Set((selectedColumns ?? []).map(refKey));\n }, [selectedColumns]);\n\n const handleColumnSelectToggle = useCallback(\n (table: string, column: string, checked: boolean) => {\n if (!onColumnSelectionChange) return;\n const list = selectedColumns ?? [];\n if (checked) {\n if (list.some((r) => r.table === table && r.column === column)) return;\n onColumnSelectionChange([...list, { table, column }]);\n } else {\n onColumnSelectionChange(\n list.filter((r) => !(r.table === table && r.column === column)),\n );\n }\n },\n [selectedColumns, onColumnSelectionChange],\n );\n\n const selectionContext = useMemo<ColumnSelectionContextValue>(\n () => ({\n enabled: showColumnCheckboxes ?? false,\n selected: selectionSet,\n onToggle: handleColumnSelectToggle,\n }),\n [showColumnCheckboxes, selectionSet, handleColumnSelectToggle],\n );\n\n const edges = useMemo<Edge[]>(() => {\n if (!layout || !model) return [];\n const tableSet = new Set(model.tables.map((t) => t.name));\n const relMap = new Map(model.relations.map((r) => [r.id, r]));\n\n const fkEdges: Edge[] = [];\n for (const e of layout.edges) {\n // Skip stale edges referencing tables removed since the layout was computed.\n if (!tableSet.has(e.source) || !tableSet.has(e.target)) continue;\n const rel = relMap.get(e.id);\n const isHovered = e.id === hoveredEdgeId;\n fkEdges.push({\n id: e.id,\n source: e.source,\n target: e.target,\n sourceHandle: handleIdFor('source', rel?.fromColumn),\n targetHandle: handleIdFor('target', rel?.toColumn),\n type: 'smoothstep',\n animated: isHovered,\n deletable: false,\n style: {\n stroke: isHovered ? '#f59e0b' : '#9ca3af',\n strokeWidth: isHovered ? 2 : 1.5,\n },\n label: rel?.label,\n labelStyle: { fontSize: 10, fill: '#6b7280' },\n labelBgStyle: { fill: '#fff', fillOpacity: 0.85 },\n labelBgPadding: [4, 2] as [number, number],\n labelBgBorderRadius: 3,\n });\n }\n\n const joinEdges: Edge[] = [];\n for (const j of joins ?? []) {\n if (!tableSet.has(j.source.table) || !tableSet.has(j.target.table)) continue;\n const edgeId = `${JOIN_EDGE_PREFIX}${j.id}`;\n const isHovered = edgeId === hoveredEdgeId;\n const color = JOIN_TYPE_COLOR[j.type] ?? '#3b82f6';\n const data: JoinEdgeData = {\n type: j.type,\n color,\n hovered: isHovered,\n onDelete: onJoinDelete ? () => onJoinDelete(j.id) : undefined,\n };\n joinEdges.push({\n id: edgeId,\n source: j.source.table,\n target: j.target.table,\n sourceHandle: handleIdFor('source', j.source.column),\n targetHandle: handleIdFor('target', j.target.column),\n type: 'joinEdge',\n deletable: true,\n data: data as unknown as Record<string, unknown>,\n });\n }\n\n return [...fkEdges, ...joinEdges];\n }, [layout, model, joins, hoveredEdgeId, onJoinDelete]);\n\n const handleConnect = useCallback(\n (conn: Connection) => {\n if (!onJoinConnect) return;\n if (!conn.source || !conn.target) return;\n onJoinConnect(\n { table: conn.source, column: parseHandleColumn(conn.sourceHandle) },\n { table: conn.target, column: parseHandleColumn(conn.targetHandle) },\n );\n },\n [onJoinConnect],\n );\n\n const handleEdgesDelete = useCallback(\n (deleted: Edge[]) => {\n if (!onJoinDelete) return;\n for (const e of deleted) {\n if (e.id.startsWith(JOIN_EDGE_PREFIX)) {\n onJoinDelete(e.id.slice(JOIN_EDGE_PREFIX.length));\n }\n }\n },\n [onJoinDelete],\n );\n\n const connectModeOn = !!enableManualJoins;\n const tableActions = useMemo<TableActionsContextValue>(\n () => ({ onTableRemove, onColumnClick }),\n [onTableRemove, onColumnClick],\n );\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n return (\n <div\n ref={wrapperRef}\n className={className}\n style={{ width: '100%', height: '100%', position: 'relative', ...style }}\n >\n {error && (\n <div\n style={{\n position: 'absolute',\n top: 8,\n left: 8,\n right: 8,\n zIndex: 10,\n padding: '8px 12px',\n background: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 6,\n color: '#991b1b',\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontSize: 12,\n whiteSpace: 'pre-wrap',\n }}\n >\n {error.message}\n </div>\n )}\n {!error && !layout && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#9ca3af',\n fontSize: 13,\n }}\n >\n Computing layout…\n </div>\n )}\n <HighlightContext.Provider value={highlightMap}>\n <ColumnSelectionContext.Provider value={selectionContext}>\n <ConnectModeContext.Provider value={connectModeOn}>\n <TableActionsContext.Provider value={tableActions}>\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n fitView\n onNodesChange={onNodesChange}\n onNodeDragStop={handleNodeDragStop}\n onNodeClick={\n onTableClick ? (_, node) => onTableClick(node.id) : undefined\n }\n onEdgeMouseEnter={(_, edge) => setHoveredEdgeId(edge.id)}\n onEdgeMouseLeave={() => setHoveredEdgeId(null)}\n onConnect={handleConnect}\n onEdgesDelete={handleEdgesDelete}\n nodesDraggable\n nodesConnectable={connectModeOn}\n elementsSelectable\n deleteKeyCode={deleteKeyCode}\n minZoom={0.1}\n maxZoom={4}\n >\n <Background />\n <Controls />\n <MiniMap pannable zoomable />\n <HandleBridge apiRef={ref} wrapperRef={wrapperRef} />\n </ReactFlow>\n </TableActionsContext.Provider>\n </ConnectModeContext.Provider>\n </ColumnSelectionContext.Provider>\n </HighlightContext.Provider>\n </div>\n );\n});\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MermaidER } from './components/MermaidER';
|
|
2
|
-
export type { MermaidERProps, NodePosition, NodePositions, } from './components/MermaidER';
|
|
2
|
+
export type { MermaidERHandle, MermaidERProps, NodePosition, NodePositions, } from './components/MermaidER';
|
|
3
3
|
export type { TableNodeData } from './components/TableNode';
|
|
4
4
|
export type { JoinEdgeData } from './components/JoinEdge';
|
|
5
5
|
export * from './core';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,GACd,MAAM,wBAAwB,CAAC;AAKhC,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,cAAc,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,aAAa,GACd,MAAM,wBAAwB,CAAC;AAKhC,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,cAAc,QAAQ,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { a as e, c as t, i as n, n as r, o as i, r as a, s as o, t as s } from "./core-DZ30VgUT.js";
|
|
2
|
-
import { Fragment as c, createContext as l,
|
|
3
|
-
import { Background as
|
|
4
|
-
import { Fragment as
|
|
2
|
+
import { Fragment as c, createContext as l, forwardRef as u, memo as d, useCallback as f, useContext as p, useEffect as m, useImperativeHandle as h, useMemo as g, useRef as ee, useState as _ } from "react";
|
|
3
|
+
import { Background as v, BaseEdge as y, Controls as te, EdgeLabelRenderer as b, Handle as x, MiniMap as S, Position as C, ReactFlow as ne, getSmoothStepPath as w, useNodesState as re, useReactFlow as T } from "@xyflow/react";
|
|
4
|
+
import { Fragment as E, jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/TableNode.tsx
|
|
6
|
-
var
|
|
6
|
+
var k = l(/* @__PURE__ */ new Map()), A = l({
|
|
7
7
|
enabled: !1,
|
|
8
8
|
selected: /* @__PURE__ */ new Set(),
|
|
9
9
|
onToggle: () => void 0
|
|
10
|
-
}),
|
|
10
|
+
}), j = l(!1), M = l({}), N = {
|
|
11
11
|
pk: {
|
|
12
12
|
label: "PK",
|
|
13
13
|
bg: "#f59e0b"
|
|
@@ -21,9 +21,9 @@ var E = l(/* @__PURE__ */ new Map()), D = l({
|
|
|
21
21
|
bg: "#10b981"
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
|
-
function
|
|
24
|
+
function P({ tableName: e, column: t, highlighted: n, onClick: r, selectionEnabled: i, selected: a, onSelectToggle: o }) {
|
|
25
25
|
let s = [];
|
|
26
|
-
return t.keys.pk && s.push(
|
|
26
|
+
return t.keys.pk && s.push(N.pk), t.keys.fk && s.push(N.fk), t.keys.uk && s.push(N.uk), /* @__PURE__ */ O("div", {
|
|
27
27
|
title: t.comment,
|
|
28
28
|
onClick: r ? () => r(e, t.name) : void 0,
|
|
29
29
|
style: {
|
|
@@ -41,7 +41,7 @@ function j({ tableName: e, column: t, highlighted: n, onClick: r, selectionEnabl
|
|
|
41
41
|
transition: "background 0.15s"
|
|
42
42
|
},
|
|
43
43
|
children: [
|
|
44
|
-
i && /* @__PURE__ */
|
|
44
|
+
i && /* @__PURE__ */ D("input", {
|
|
45
45
|
type: "checkbox",
|
|
46
46
|
checked: a,
|
|
47
47
|
onChange: (e) => o(e.target.checked),
|
|
@@ -54,14 +54,14 @@ function j({ tableName: e, column: t, highlighted: n, onClick: r, selectionEnabl
|
|
|
54
54
|
cursor: "pointer"
|
|
55
55
|
}
|
|
56
56
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
57
|
+
/* @__PURE__ */ D("span", {
|
|
58
58
|
style: {
|
|
59
59
|
display: "flex",
|
|
60
60
|
gap: 2,
|
|
61
61
|
flexShrink: 0,
|
|
62
62
|
minWidth: 18
|
|
63
63
|
},
|
|
64
|
-
children: s.map((e) => /* @__PURE__ */
|
|
64
|
+
children: s.map((e) => /* @__PURE__ */ D("span", {
|
|
65
65
|
style: {
|
|
66
66
|
display: "inline-block",
|
|
67
67
|
padding: "0 4px",
|
|
@@ -75,7 +75,7 @@ function j({ tableName: e, column: t, highlighted: n, onClick: r, selectionEnabl
|
|
|
75
75
|
children: e.label
|
|
76
76
|
}, e.label))
|
|
77
77
|
}),
|
|
78
|
-
/* @__PURE__ */
|
|
78
|
+
/* @__PURE__ */ D("span", {
|
|
79
79
|
style: {
|
|
80
80
|
flexShrink: 0,
|
|
81
81
|
fontWeight: t.keys.pk ? 600 : 400,
|
|
@@ -83,7 +83,7 @@ function j({ tableName: e, column: t, highlighted: n, onClick: r, selectionEnabl
|
|
|
83
83
|
},
|
|
84
84
|
children: t.name
|
|
85
85
|
}),
|
|
86
|
-
t.type && /* @__PURE__ */
|
|
86
|
+
t.type && /* @__PURE__ */ D("span", {
|
|
87
87
|
style: {
|
|
88
88
|
flex: 1,
|
|
89
89
|
textAlign: "right",
|
|
@@ -98,8 +98,8 @@ function j({ tableName: e, column: t, highlighted: n, onClick: r, selectionEnabl
|
|
|
98
98
|
]
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
|
-
var
|
|
102
|
-
let { table: t } = e, n =
|
|
101
|
+
var F = d(function({ data: e }) {
|
|
102
|
+
let { table: t } = e, n = p(k), r = p(A), i = p(j), a = p(M), o = a.onColumnClick, s = n.get(t.name), l = t.group ? "#1e40af" : "#374151", u = (e) => ({
|
|
103
103
|
...e,
|
|
104
104
|
width: i ? 9 : 6,
|
|
105
105
|
height: i ? 9 : 6,
|
|
@@ -110,7 +110,7 @@ var M = u(function({ data: e }) {
|
|
|
110
110
|
pointerEvents: i ? "auto" : "none",
|
|
111
111
|
cursor: i ? "crosshair" : "default"
|
|
112
112
|
});
|
|
113
|
-
return /* @__PURE__ */
|
|
113
|
+
return /* @__PURE__ */ O("div", {
|
|
114
114
|
style: {
|
|
115
115
|
background: "#fff",
|
|
116
116
|
border: "1px solid #c4c4c4",
|
|
@@ -124,19 +124,19 @@ var M = u(function({ data: e }) {
|
|
|
124
124
|
position: "relative"
|
|
125
125
|
},
|
|
126
126
|
children: [
|
|
127
|
-
/* @__PURE__ */
|
|
127
|
+
/* @__PURE__ */ D(x, {
|
|
128
128
|
id: "__default-target",
|
|
129
129
|
type: "target",
|
|
130
|
-
position:
|
|
130
|
+
position: C.Left,
|
|
131
131
|
style: u({ top: 32 / 2 })
|
|
132
132
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ D(x, {
|
|
134
134
|
id: "__default-source",
|
|
135
135
|
type: "source",
|
|
136
|
-
position:
|
|
136
|
+
position: C.Right,
|
|
137
137
|
style: u({ top: 32 / 2 })
|
|
138
138
|
}),
|
|
139
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ O("div", {
|
|
140
140
|
style: {
|
|
141
141
|
padding: "6px 10px",
|
|
142
142
|
background: l,
|
|
@@ -152,21 +152,21 @@ var M = u(function({ data: e }) {
|
|
|
152
152
|
borderTopLeftRadius: 6,
|
|
153
153
|
borderTopRightRadius: 6
|
|
154
154
|
},
|
|
155
|
-
children: [/* @__PURE__ */
|
|
155
|
+
children: [/* @__PURE__ */ D("span", {
|
|
156
156
|
style: {
|
|
157
157
|
overflow: "hidden",
|
|
158
158
|
textOverflow: "ellipsis",
|
|
159
159
|
whiteSpace: "nowrap"
|
|
160
160
|
},
|
|
161
161
|
children: t.name
|
|
162
|
-
}), /* @__PURE__ */
|
|
162
|
+
}), /* @__PURE__ */ O("span", {
|
|
163
163
|
style: {
|
|
164
164
|
display: "flex",
|
|
165
165
|
alignItems: "center",
|
|
166
166
|
gap: 4,
|
|
167
167
|
flexShrink: 0
|
|
168
168
|
},
|
|
169
|
-
children: [t.group && /* @__PURE__ */
|
|
169
|
+
children: [t.group && /* @__PURE__ */ D("span", {
|
|
170
170
|
style: {
|
|
171
171
|
fontSize: 10,
|
|
172
172
|
opacity: .75,
|
|
@@ -176,7 +176,7 @@ var M = u(function({ data: e }) {
|
|
|
176
176
|
borderRadius: 3
|
|
177
177
|
},
|
|
178
178
|
children: t.group
|
|
179
|
-
}), a.onTableRemove && /* @__PURE__ */
|
|
179
|
+
}), a.onTableRemove && /* @__PURE__ */ D("button", {
|
|
180
180
|
className: "nodrag",
|
|
181
181
|
onClick: (e) => {
|
|
182
182
|
e.stopPropagation(), a.onTableRemove?.(t.name);
|
|
@@ -205,20 +205,20 @@ var M = u(function({ data: e }) {
|
|
|
205
205
|
}),
|
|
206
206
|
t.columns.map((e, n) => {
|
|
207
207
|
let i = 32 + n * 22 + 22 / 2, a = s?.has(e.name) ?? !1, l = `${t.name}.${e.name}`, d = r.enabled && r.selected.has(l);
|
|
208
|
-
return /* @__PURE__ */
|
|
209
|
-
/* @__PURE__ */
|
|
208
|
+
return /* @__PURE__ */ O(c, { children: [
|
|
209
|
+
/* @__PURE__ */ D(x, {
|
|
210
210
|
id: `${e.name}__target`,
|
|
211
211
|
type: "target",
|
|
212
|
-
position:
|
|
212
|
+
position: C.Left,
|
|
213
213
|
style: u({ top: i })
|
|
214
214
|
}),
|
|
215
|
-
/* @__PURE__ */
|
|
215
|
+
/* @__PURE__ */ D(x, {
|
|
216
216
|
id: `${e.name}__source`,
|
|
217
217
|
type: "source",
|
|
218
|
-
position:
|
|
218
|
+
position: C.Right,
|
|
219
219
|
style: u({ top: i })
|
|
220
220
|
}),
|
|
221
|
-
/* @__PURE__ */
|
|
221
|
+
/* @__PURE__ */ D(P, {
|
|
222
222
|
tableName: t.name,
|
|
223
223
|
column: e,
|
|
224
224
|
highlighted: a,
|
|
@@ -231,8 +231,8 @@ var M = u(function({ data: e }) {
|
|
|
231
231
|
})
|
|
232
232
|
]
|
|
233
233
|
});
|
|
234
|
-
}),
|
|
235
|
-
let [l, u, d] =
|
|
234
|
+
}), I = d(function({ id: e, sourceX: t, sourceY: n, targetX: r, targetY: i, sourcePosition: a, targetPosition: o, data: s, selected: c }) {
|
|
235
|
+
let [l, u, d] = w({
|
|
236
236
|
sourceX: t,
|
|
237
237
|
sourceY: n,
|
|
238
238
|
sourcePosition: a,
|
|
@@ -240,7 +240,7 @@ var M = u(function({ data: e }) {
|
|
|
240
240
|
targetY: i,
|
|
241
241
|
targetPosition: o
|
|
242
242
|
}), f = s ?? {}, p = !!c || !!f.hovered, m = f.color || "#3b82f6";
|
|
243
|
-
return /* @__PURE__ */
|
|
243
|
+
return /* @__PURE__ */ O(E, { children: [/* @__PURE__ */ D(y, {
|
|
244
244
|
id: e,
|
|
245
245
|
path: l,
|
|
246
246
|
style: {
|
|
@@ -248,7 +248,7 @@ var M = u(function({ data: e }) {
|
|
|
248
248
|
strokeWidth: p ? 2.5 : 2,
|
|
249
249
|
strokeDasharray: "6 3"
|
|
250
250
|
}
|
|
251
|
-
}), /* @__PURE__ */
|
|
251
|
+
}), /* @__PURE__ */ D(b, { children: /* @__PURE__ */ O("div", {
|
|
252
252
|
className: "nodrag nopan",
|
|
253
253
|
style: {
|
|
254
254
|
position: "absolute",
|
|
@@ -267,7 +267,7 @@ var M = u(function({ data: e }) {
|
|
|
267
267
|
boxShadow: p ? "0 0 0 2px rgba(0,0,0,0.4)" : "0 1px 2px rgba(0,0,0,0.15)",
|
|
268
268
|
userSelect: "none"
|
|
269
269
|
},
|
|
270
|
-
children: [/* @__PURE__ */
|
|
270
|
+
children: [/* @__PURE__ */ D("span", { children: f.type }), f.onDelete && /* @__PURE__ */ D("button", {
|
|
271
271
|
type: "button",
|
|
272
272
|
onClick: (e) => {
|
|
273
273
|
e.stopPropagation(), f.onDelete?.();
|
|
@@ -293,8 +293,8 @@ var M = u(function({ data: e }) {
|
|
|
293
293
|
children: "×"
|
|
294
294
|
})]
|
|
295
295
|
}) })] });
|
|
296
|
-
}),
|
|
297
|
-
function
|
|
296
|
+
}), ie = { table: F }, L = { joinEdge: I };
|
|
297
|
+
function ae(e) {
|
|
298
298
|
try {
|
|
299
299
|
return {
|
|
300
300
|
model: t(e),
|
|
@@ -308,61 +308,72 @@ function ie(e) {
|
|
|
308
308
|
throw e;
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
|
-
function
|
|
311
|
+
function R(e, t) {
|
|
312
312
|
return t ? `${t}__${e}` : `__default-${e}`;
|
|
313
313
|
}
|
|
314
|
-
var
|
|
315
|
-
function
|
|
314
|
+
var z = "join:";
|
|
315
|
+
function B(e) {
|
|
316
316
|
if (!e || e.startsWith("__default-")) return;
|
|
317
317
|
let t = /^(.+)__(?:source|target)$/.exec(e);
|
|
318
318
|
return t ? t[1] : void 0;
|
|
319
319
|
}
|
|
320
|
-
function
|
|
320
|
+
function oe(e) {
|
|
321
321
|
return `${e.table}.${e.column}`;
|
|
322
322
|
}
|
|
323
|
-
var
|
|
323
|
+
var se = {
|
|
324
324
|
INNER: "#3b82f6",
|
|
325
325
|
LEFT: "#8b5cf6",
|
|
326
326
|
RIGHT: "#a855f7",
|
|
327
327
|
FULL: "#ec4899",
|
|
328
328
|
CROSS: "#6b7280"
|
|
329
329
|
};
|
|
330
|
-
function
|
|
331
|
-
let
|
|
332
|
-
|
|
330
|
+
function ce({ apiRef: e, wrapperRef: t }) {
|
|
331
|
+
let n = T();
|
|
332
|
+
return h(e, () => ({
|
|
333
|
+
fitView: (e) => n.fitView(e),
|
|
334
|
+
getViewport: () => n.getViewport(),
|
|
335
|
+
setViewport: (e) => n.setViewport(e),
|
|
336
|
+
getNodesBounds: () => n.getNodesBounds(n.getNodes()),
|
|
337
|
+
getWrapperElement: () => t.current,
|
|
338
|
+
getViewportElement: () => t.current?.querySelector(".react-flow__viewport") ?? null
|
|
339
|
+
}), [n, t]), null;
|
|
340
|
+
}
|
|
341
|
+
var V = u(function(e, t) {
|
|
342
|
+
let { source: n, model: r, algorithm: a, direction: o, aspectRatio: s, positions: c, onPositionsChange: l, showColumnCheckboxes: u, selectedColumns: d, onColumnSelectionChange: p, enableManualJoins: h, joins: y, onJoinConnect: b, onJoinDelete: x, onTableRemove: C, onColumnClick: w, onTableClick: T, deleteKeyCode: E = "Delete", className: N, style: P, highlightReferencesOnHover: F = !0 } = e, { model: I, error: V } = g(() => r ? {
|
|
343
|
+
model: r,
|
|
333
344
|
error: null
|
|
334
|
-
} :
|
|
345
|
+
} : n == null ? {
|
|
335
346
|
model: null,
|
|
336
347
|
error: null
|
|
337
|
-
} :
|
|
338
|
-
|
|
339
|
-
if (!
|
|
348
|
+
} : ae(n), [n, r]), [H, U] = _(null), [W, G] = _(null);
|
|
349
|
+
m(() => {
|
|
350
|
+
if (!I) {
|
|
340
351
|
U(null);
|
|
341
352
|
return;
|
|
342
353
|
}
|
|
343
354
|
let e = !1;
|
|
344
|
-
return i(
|
|
345
|
-
algorithm:
|
|
346
|
-
direction:
|
|
347
|
-
aspectRatio:
|
|
355
|
+
return i(I, {
|
|
356
|
+
algorithm: a,
|
|
357
|
+
direction: o,
|
|
358
|
+
aspectRatio: s
|
|
348
359
|
}).then((t) => {
|
|
349
360
|
e || U(t);
|
|
350
361
|
}), () => {
|
|
351
362
|
e = !0;
|
|
352
363
|
};
|
|
353
364
|
}, [
|
|
354
|
-
|
|
355
|
-
r,
|
|
365
|
+
I,
|
|
356
366
|
a,
|
|
357
|
-
o
|
|
367
|
+
o,
|
|
368
|
+
s
|
|
358
369
|
]);
|
|
359
|
-
let K =
|
|
360
|
-
if (!H || !
|
|
361
|
-
let e = new Map(
|
|
370
|
+
let K = g(() => {
|
|
371
|
+
if (!H || !I) return [];
|
|
372
|
+
let e = new Map(I.tables.map((e) => [e.name, e])), t = [];
|
|
362
373
|
for (let n of H.nodes) {
|
|
363
374
|
let r = e.get(n.id);
|
|
364
375
|
if (!r) continue;
|
|
365
|
-
let i =
|
|
376
|
+
let i = c?.[n.id], a = { table: r };
|
|
366
377
|
t.push({
|
|
367
378
|
id: n.id,
|
|
368
379
|
type: "table",
|
|
@@ -380,60 +391,60 @@ function z(e) {
|
|
|
380
391
|
return t;
|
|
381
392
|
}, [
|
|
382
393
|
H,
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
]), [
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}, [K,
|
|
389
|
-
let
|
|
390
|
-
if (!
|
|
391
|
-
let r = { ...
|
|
394
|
+
I,
|
|
395
|
+
c
|
|
396
|
+
]), [le, q, ue] = re(K);
|
|
397
|
+
m(() => {
|
|
398
|
+
q(K);
|
|
399
|
+
}, [K, q]);
|
|
400
|
+
let de = f((e, t, n) => {
|
|
401
|
+
if (!l) return;
|
|
402
|
+
let r = { ...c ?? {} };
|
|
392
403
|
for (let e of n) r[e.id] = {
|
|
393
404
|
x: e.position.x,
|
|
394
405
|
y: e.position.y
|
|
395
406
|
};
|
|
396
|
-
|
|
397
|
-
}, [
|
|
398
|
-
if (!(!W || !
|
|
399
|
-
}, [W,
|
|
400
|
-
if (!W || !
|
|
407
|
+
l(r);
|
|
408
|
+
}, [c, l]), J = g(() => {
|
|
409
|
+
if (!(!W || !I)) return I.relations.find((e) => e.id === W);
|
|
410
|
+
}, [W, I]), Y = g(() => {
|
|
411
|
+
if (!W || !y || !W.startsWith(z)) return;
|
|
401
412
|
let e = W.slice(5);
|
|
402
|
-
return
|
|
403
|
-
}, [W,
|
|
413
|
+
return y.find((t) => t.id === e);
|
|
414
|
+
}, [W, y]), fe = g(() => {
|
|
404
415
|
let e = /* @__PURE__ */ new Map();
|
|
405
|
-
if (!
|
|
416
|
+
if (!F) return e;
|
|
406
417
|
let t = (t, n) => {
|
|
407
418
|
if (!n) return;
|
|
408
419
|
let r = e.get(t) ?? /* @__PURE__ */ new Set();
|
|
409
420
|
r.add(n), e.set(t, r);
|
|
410
421
|
};
|
|
411
|
-
return
|
|
422
|
+
return J && (t(J.from, J.fromColumn), t(J.to, J.toColumn)), Y && (t(Y.source.table, Y.source.column), t(Y.target.table, Y.target.column)), e;
|
|
412
423
|
}, [
|
|
424
|
+
J,
|
|
413
425
|
Y,
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
let r = u ?? [];
|
|
426
|
+
F
|
|
427
|
+
]), X = g(() => new Set((d ?? []).map(oe)), [d]), Z = f((e, t, n) => {
|
|
428
|
+
if (!p) return;
|
|
429
|
+
let r = d ?? [];
|
|
419
430
|
if (n) {
|
|
420
431
|
if (r.some((n) => n.table === e && n.column === t)) return;
|
|
421
|
-
|
|
432
|
+
p([...r, {
|
|
422
433
|
table: e,
|
|
423
434
|
column: t
|
|
424
435
|
}]);
|
|
425
|
-
} else
|
|
426
|
-
}, [
|
|
427
|
-
enabled:
|
|
428
|
-
selected:
|
|
429
|
-
onToggle:
|
|
436
|
+
} else p(r.filter((n) => !(n.table === e && n.column === t)));
|
|
437
|
+
}, [d, p]), pe = g(() => ({
|
|
438
|
+
enabled: u ?? !1,
|
|
439
|
+
selected: X,
|
|
440
|
+
onToggle: Z
|
|
430
441
|
}), [
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
]),
|
|
435
|
-
if (!H || !
|
|
436
|
-
let e = new Set(
|
|
442
|
+
u,
|
|
443
|
+
X,
|
|
444
|
+
Z
|
|
445
|
+
]), me = g(() => {
|
|
446
|
+
if (!H || !I) return [];
|
|
447
|
+
let e = new Set(I.tables.map((e) => e.name)), t = new Map(I.relations.map((e) => [e.id, e])), n = [];
|
|
437
448
|
for (let r of H.edges) {
|
|
438
449
|
if (!e.has(r.source) || !e.has(r.target)) continue;
|
|
439
450
|
let i = t.get(r.id), a = r.id === W;
|
|
@@ -441,8 +452,8 @@ function z(e) {
|
|
|
441
452
|
id: r.id,
|
|
442
453
|
source: r.source,
|
|
443
454
|
target: r.target,
|
|
444
|
-
sourceHandle:
|
|
445
|
-
targetHandle:
|
|
455
|
+
sourceHandle: R("source", i?.fromColumn),
|
|
456
|
+
targetHandle: R("target", i?.toColumn),
|
|
446
457
|
type: "smoothstep",
|
|
447
458
|
animated: a,
|
|
448
459
|
deletable: !1,
|
|
@@ -464,20 +475,20 @@ function z(e) {
|
|
|
464
475
|
});
|
|
465
476
|
}
|
|
466
477
|
let r = [];
|
|
467
|
-
for (let t of
|
|
478
|
+
for (let t of y ?? []) {
|
|
468
479
|
if (!e.has(t.source.table) || !e.has(t.target.table)) continue;
|
|
469
|
-
let n = `${
|
|
480
|
+
let n = `${z}${t.id}`, i = n === W, a = se[t.type] ?? "#3b82f6", o = {
|
|
470
481
|
type: t.type,
|
|
471
482
|
color: a,
|
|
472
483
|
hovered: i,
|
|
473
|
-
onDelete:
|
|
484
|
+
onDelete: x ? () => x(t.id) : void 0
|
|
474
485
|
};
|
|
475
486
|
r.push({
|
|
476
487
|
id: n,
|
|
477
488
|
source: t.source.table,
|
|
478
489
|
target: t.target.table,
|
|
479
|
-
sourceHandle:
|
|
480
|
-
targetHandle:
|
|
490
|
+
sourceHandle: R("source", t.source.column),
|
|
491
|
+
targetHandle: R("target", t.target.column),
|
|
481
492
|
type: "joinEdge",
|
|
482
493
|
deletable: !0,
|
|
483
494
|
data: o
|
|
@@ -486,34 +497,35 @@ function z(e) {
|
|
|
486
497
|
return [...n, ...r];
|
|
487
498
|
}, [
|
|
488
499
|
H,
|
|
489
|
-
|
|
490
|
-
|
|
500
|
+
I,
|
|
501
|
+
y,
|
|
491
502
|
W,
|
|
492
|
-
|
|
493
|
-
]),
|
|
494
|
-
|
|
503
|
+
x
|
|
504
|
+
]), he = f((e) => {
|
|
505
|
+
b && (!e.source || !e.target || b({
|
|
495
506
|
table: e.source,
|
|
496
|
-
column:
|
|
507
|
+
column: B(e.sourceHandle)
|
|
497
508
|
}, {
|
|
498
509
|
table: e.target,
|
|
499
|
-
column:
|
|
510
|
+
column: B(e.targetHandle)
|
|
500
511
|
}));
|
|
501
|
-
}, [
|
|
502
|
-
if (
|
|
503
|
-
}, [
|
|
504
|
-
onTableRemove:
|
|
505
|
-
onColumnClick:
|
|
506
|
-
}), [
|
|
507
|
-
return /* @__PURE__ */
|
|
508
|
-
|
|
512
|
+
}, [b]), ge = f((e) => {
|
|
513
|
+
if (x) for (let t of e) t.id.startsWith(z) && x(t.id.slice(5));
|
|
514
|
+
}, [x]), Q = !!h, _e = g(() => ({
|
|
515
|
+
onTableRemove: C,
|
|
516
|
+
onColumnClick: w
|
|
517
|
+
}), [C, w]), $ = ee(null);
|
|
518
|
+
return /* @__PURE__ */ O("div", {
|
|
519
|
+
ref: $,
|
|
520
|
+
className: N,
|
|
509
521
|
style: {
|
|
510
522
|
width: "100%",
|
|
511
523
|
height: "100%",
|
|
512
524
|
position: "relative",
|
|
513
|
-
...
|
|
525
|
+
...P
|
|
514
526
|
},
|
|
515
527
|
children: [
|
|
516
|
-
V && /* @__PURE__ */
|
|
528
|
+
V && /* @__PURE__ */ D("div", {
|
|
517
529
|
style: {
|
|
518
530
|
position: "absolute",
|
|
519
531
|
top: 8,
|
|
@@ -531,7 +543,7 @@ function z(e) {
|
|
|
531
543
|
},
|
|
532
544
|
children: V.message
|
|
533
545
|
}),
|
|
534
|
-
!V && !H && /* @__PURE__ */
|
|
546
|
+
!V && !H && /* @__PURE__ */ D("div", {
|
|
535
547
|
style: {
|
|
536
548
|
position: "absolute",
|
|
537
549
|
inset: 0,
|
|
@@ -543,39 +555,43 @@ function z(e) {
|
|
|
543
555
|
},
|
|
544
556
|
children: "Computing layout…"
|
|
545
557
|
}),
|
|
546
|
-
/* @__PURE__ */
|
|
547
|
-
value:
|
|
548
|
-
children: /* @__PURE__ */
|
|
549
|
-
value:
|
|
550
|
-
children: /* @__PURE__ */
|
|
551
|
-
value:
|
|
552
|
-
children: /* @__PURE__ */
|
|
553
|
-
value:
|
|
554
|
-
children: /* @__PURE__ */
|
|
555
|
-
nodes:
|
|
556
|
-
edges:
|
|
557
|
-
nodeTypes:
|
|
558
|
-
edgeTypes:
|
|
558
|
+
/* @__PURE__ */ D(k.Provider, {
|
|
559
|
+
value: fe,
|
|
560
|
+
children: /* @__PURE__ */ D(A.Provider, {
|
|
561
|
+
value: pe,
|
|
562
|
+
children: /* @__PURE__ */ D(j.Provider, {
|
|
563
|
+
value: Q,
|
|
564
|
+
children: /* @__PURE__ */ D(M.Provider, {
|
|
565
|
+
value: _e,
|
|
566
|
+
children: /* @__PURE__ */ O(ne, {
|
|
567
|
+
nodes: le,
|
|
568
|
+
edges: me,
|
|
569
|
+
nodeTypes: ie,
|
|
570
|
+
edgeTypes: L,
|
|
559
571
|
fitView: !0,
|
|
560
|
-
onNodesChange:
|
|
561
|
-
onNodeDragStop:
|
|
562
|
-
onNodeClick:
|
|
572
|
+
onNodesChange: ue,
|
|
573
|
+
onNodeDragStop: de,
|
|
574
|
+
onNodeClick: T ? (e, t) => T(t.id) : void 0,
|
|
563
575
|
onEdgeMouseEnter: (e, t) => G(t.id),
|
|
564
576
|
onEdgeMouseLeave: () => G(null),
|
|
565
|
-
onConnect:
|
|
566
|
-
onEdgesDelete:
|
|
577
|
+
onConnect: he,
|
|
578
|
+
onEdgesDelete: ge,
|
|
567
579
|
nodesDraggable: !0,
|
|
568
|
-
nodesConnectable:
|
|
580
|
+
nodesConnectable: Q,
|
|
569
581
|
elementsSelectable: !0,
|
|
570
|
-
deleteKeyCode:
|
|
582
|
+
deleteKeyCode: E,
|
|
571
583
|
minZoom: .1,
|
|
572
584
|
maxZoom: 4,
|
|
573
585
|
children: [
|
|
574
|
-
/* @__PURE__ */
|
|
575
|
-
/* @__PURE__ */
|
|
576
|
-
/* @__PURE__ */
|
|
586
|
+
/* @__PURE__ */ D(v, {}),
|
|
587
|
+
/* @__PURE__ */ D(te, {}),
|
|
588
|
+
/* @__PURE__ */ D(S, {
|
|
577
589
|
pannable: !0,
|
|
578
590
|
zoomable: !0
|
|
591
|
+
}),
|
|
592
|
+
/* @__PURE__ */ D(ce, {
|
|
593
|
+
apiRef: t,
|
|
594
|
+
wrapperRef: $
|
|
579
595
|
})
|
|
580
596
|
]
|
|
581
597
|
})
|
|
@@ -585,8 +601,8 @@ function z(e) {
|
|
|
585
601
|
})
|
|
586
602
|
]
|
|
587
603
|
});
|
|
588
|
-
}
|
|
604
|
+
});
|
|
589
605
|
//#endregion
|
|
590
|
-
export { s as HEADER_HEIGHT,
|
|
606
|
+
export { s as HEADER_HEIGHT, V as MermaidER, o as MermaidERParseError, r as NODE_WIDTH, a as ROW_HEIGHT, n as VERTICAL_PADDING, e as estimateNodeHeight, i as layoutER, t as parseMermaidER };
|
|
591
607
|
|
|
592
608
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/components/TableNode.tsx","../src/components/JoinEdge.tsx","../src/components/MermaidER.tsx"],"sourcesContent":["import { Fragment, createContext, memo, useContext } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport type { NodeProps } from '@xyflow/react';\nimport type { Column, Table } from '../core/model';\nimport { HEADER_HEIGHT, ROW_HEIGHT } from '../core/layout';\n\nexport interface TableNodeData extends Record<string, unknown> {\n table: Table;\n}\n\n/**\n * Map from table name -> set of highlighted column names.\n * Provided by MermaidER, consumed by TableNode for hover-driven highlighting\n * without forcing the whole node array to recompute on every hover change.\n */\nexport const HighlightContext = createContext<ReadonlyMap<string, ReadonlySet<string>>>(new Map());\n\nexport interface ColumnSelectionContextValue {\n enabled: boolean;\n /** \"table.column\" keys for fast lookup. */\n selected: ReadonlySet<string>;\n onToggle: (table: string, column: string, checked: boolean) => void;\n}\n\nexport const ColumnSelectionContext = createContext<ColumnSelectionContextValue>({\n enabled: false,\n selected: new Set(),\n onToggle: () => undefined,\n});\n\n/** When true, column handles become visible/connectable for manual JOIN drawing. */\nexport const ConnectModeContext = createContext<boolean>(false);\n\nexport interface TableActionsContextValue {\n /** When provided, a delete affordance is shown on the table header. */\n onTableRemove?: (table: string) => void;\n /** Per-column click handler. Provided via context (not node data) so its\n * identity can change without invalidating the React Flow node array. */\n onColumnClick?: (table: string, column: string) => void;\n}\n\nexport const TableActionsContext = createContext<TableActionsContextValue>({});\n\nconst KEY_STYLES: Record<'pk' | 'fk' | 'uk', { label: string; bg: string }> = {\n pk: { label: 'PK', bg: '#f59e0b' },\n fk: { label: 'FK', bg: '#3b82f6' },\n uk: { label: 'UK', bg: '#10b981' },\n};\n\nfunction ColumnRow({\n tableName,\n column,\n highlighted,\n onClick,\n selectionEnabled,\n selected,\n onSelectToggle,\n}: {\n tableName: string;\n column: Column;\n highlighted: boolean;\n onClick?: (table: string, column: string) => void;\n selectionEnabled: boolean;\n selected: boolean;\n onSelectToggle: (checked: boolean) => void;\n}) {\n const badges: Array<{ label: string; bg: string }> = [];\n if (column.keys.pk) badges.push(KEY_STYLES.pk);\n if (column.keys.fk) badges.push(KEY_STYLES.fk);\n if (column.keys.uk) badges.push(KEY_STYLES.uk);\n\n return (\n <div\n title={column.comment}\n onClick={onClick ? () => onClick(tableName, column.name) : undefined}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '0 10px',\n fontSize: 12,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n borderTop: '1px solid #eee',\n height: ROW_HEIGHT,\n boxSizing: 'border-box',\n cursor: onClick ? 'pointer' : 'default',\n background: highlighted ? '#fef3c7' : selected ? '#eff6ff' : 'transparent',\n transition: 'background 0.15s',\n }}\n >\n {selectionEnabled && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(e) => onSelectToggle(e.target.checked)}\n onClick={(e) => e.stopPropagation()}\n style={{\n width: 13,\n height: 13,\n margin: 0,\n flexShrink: 0,\n cursor: 'pointer',\n }}\n />\n )}\n <span style={{ display: 'flex', gap: 2, flexShrink: 0, minWidth: 18 }}>\n {badges.map((b) => (\n <span\n key={b.label}\n style={{\n display: 'inline-block',\n padding: '0 4px',\n borderRadius: 3,\n background: b.bg,\n color: '#fff',\n fontSize: 9,\n fontWeight: 700,\n lineHeight: '14px',\n }}\n >\n {b.label}\n </span>\n ))}\n </span>\n <span\n style={{\n flexShrink: 0,\n fontWeight: column.keys.pk ? 600 : 400,\n color: '#1f2937',\n }}\n >\n {column.name}\n </span>\n {column.type && (\n <span\n style={{\n flex: 1,\n textAlign: 'right',\n color: '#9ca3af',\n fontStyle: 'italic',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {column.type}\n </span>\n )}\n </div>\n );\n}\n\nexport const TableNode = memo(function TableNode({ data }: NodeProps) {\n const { table } = data as TableNodeData;\n const highlightMap = useContext(HighlightContext);\n const selection = useContext(ColumnSelectionContext);\n const connectMode = useContext(ConnectModeContext);\n const tableActions = useContext(TableActionsContext);\n const onColumnClick = tableActions.onColumnClick;\n const highlightedCols = highlightMap.get(table.name);\n const headerBg = table.group ? '#1e40af' : '#374151';\n\n const handleStyle = (extra: { top?: number }): React.CSSProperties => ({\n ...extra,\n width: connectMode ? 9 : 6,\n height: connectMode ? 9 : 6,\n background: connectMode ? '#3b82f6' : 'transparent',\n border: connectMode ? '1.5px solid #fff' : 'none',\n boxShadow: connectMode ? '0 0 0 1px rgba(59,130,246,0.4)' : 'none',\n opacity: connectMode ? 0.85 : 0,\n pointerEvents: connectMode ? 'auto' : 'none',\n cursor: connectMode ? 'crosshair' : 'default',\n });\n\n return (\n <div\n style={{\n background: '#fff',\n border: '1px solid #c4c4c4',\n borderRadius: 6,\n boxShadow: '0 2px 6px rgba(0,0,0,0.08)',\n overflow: 'visible',\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n }}\n >\n <Handle\n id=\"__default-target\"\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n <Handle\n id=\"__default-source\"\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n\n <div\n style={{\n padding: '6px 10px',\n background: headerBg,\n color: '#fff',\n fontWeight: 600,\n fontSize: 13,\n height: HEADER_HEIGHT,\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n borderTopLeftRadius: 6,\n borderTopRightRadius: 6,\n }}\n >\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {table.name}\n </span>\n <span style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>\n {table.group && (\n <span\n style={{\n fontSize: 10,\n opacity: 0.75,\n fontWeight: 400,\n padding: '1px 5px',\n border: '1px solid rgba(255,255,255,0.3)',\n borderRadius: 3,\n }}\n >\n {table.group}\n </span>\n )}\n {tableActions.onTableRemove && (\n <button\n className=\"nodrag\"\n onClick={(e) => {\n e.stopPropagation();\n tableActions.onTableRemove?.(table.name);\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this table\"\n style={{\n background: 'rgba(255,255,255,0.18)',\n border: 'none',\n color: '#fff',\n width: 18,\n height: 18,\n borderRadius: 3,\n cursor: 'pointer',\n fontSize: 13,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </span>\n </div>\n\n {table.columns.map((col, i) => {\n const handleY = HEADER_HEIGHT + i * ROW_HEIGHT + ROW_HEIGHT / 2;\n const highlighted = highlightedCols?.has(col.name) ?? false;\n const selectionKey = `${table.name}.${col.name}`;\n const selected = selection.enabled && selection.selected.has(selectionKey);\n return (\n <Fragment key={`${col.name}-${i}`}>\n <Handle\n id={`${col.name}__target`}\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: handleY })}\n />\n <Handle\n id={`${col.name}__source`}\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: handleY })}\n />\n <ColumnRow\n tableName={table.name}\n column={col}\n highlighted={highlighted}\n onClick={onColumnClick}\n selectionEnabled={selection.enabled}\n selected={selected}\n onSelectToggle={(checked) =>\n selection.onToggle(table.name, col.name, checked)\n }\n />\n </Fragment>\n );\n })}\n </div>\n );\n});\n","import { memo } from 'react';\nimport {\n BaseEdge,\n EdgeLabelRenderer,\n getSmoothStepPath,\n type EdgeProps,\n} from '@xyflow/react';\nimport type { JoinType } from '../core/model';\n\nexport interface JoinEdgeData extends Record<string, unknown> {\n type: JoinType;\n color: string;\n hovered?: boolean;\n onDelete?: () => void;\n}\n\nexport const JoinEdge = memo(function JoinEdge({\n id,\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n data,\n selected,\n}: EdgeProps) {\n const [edgePath, labelX, labelY] = getSmoothStepPath({\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n });\n\n const d = (data ?? {}) as JoinEdgeData;\n const emphasized = !!selected || !!d.hovered;\n const color = d.color || '#3b82f6';\n\n return (\n <>\n <BaseEdge\n id={id}\n path={edgePath}\n style={{\n stroke: color,\n strokeWidth: emphasized ? 2.5 : 2,\n strokeDasharray: '6 3',\n }}\n />\n <EdgeLabelRenderer>\n <div\n className=\"nodrag nopan\"\n style={{\n position: 'absolute',\n transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,\n background: color,\n color: '#fff',\n fontSize: 10,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontWeight: 700,\n borderRadius: 3,\n padding: '2px 4px 2px 6px',\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n pointerEvents: 'all',\n boxShadow: emphasized\n ? '0 0 0 2px rgba(0,0,0,0.4)'\n : '0 1px 2px rgba(0,0,0,0.15)',\n userSelect: 'none',\n }}\n >\n <span>{d.type}</span>\n {d.onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n d.onDelete?.();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this JOIN\"\n style={{\n background: 'rgba(255,255,255,0.25)',\n border: 'none',\n color: '#fff',\n width: 14,\n height: 14,\n borderRadius: 2,\n cursor: 'pointer',\n fontSize: 11,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </div>\n </EdgeLabelRenderer>\n </>\n );\n});\n","import {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n} from 'react';\nimport {\n ReactFlow,\n Background,\n Controls,\n MiniMap,\n useNodesState,\n type Connection,\n type Edge,\n type EdgeTypes,\n type Node,\n type NodeTypes,\n} from '@xyflow/react';\n// React Flow's CSS is intentionally NOT imported here. Consumers must add it\n// once at their app entry point: `import '@xyflow/react/dist/style.css';`.\n// Importing it from this file would cause double-injection in apps that\n// already use React Flow, and inflate this library's bundled assets.\nimport { parseMermaidER, MermaidERParseError } from '../core/parser';\nimport {\n layoutER,\n type LayoutAlgorithm,\n type LayoutDirection,\n type LayoutResult,\n} from '../core/layout';\nimport type {\n ColumnRef,\n ERModel,\n Join,\n PartialColumnRef,\n Relation,\n} from '../core/model';\nimport {\n ColumnSelectionContext,\n ConnectModeContext,\n HighlightContext,\n TableActionsContext,\n TableNode,\n type ColumnSelectionContextValue,\n type TableActionsContextValue,\n type TableNodeData,\n} from './TableNode';\nimport { JoinEdge, type JoinEdgeData } from './JoinEdge';\n\nconst nodeTypes: NodeTypes = {\n table: TableNode,\n};\n\nconst edgeTypes: EdgeTypes = {\n joinEdge: JoinEdge,\n};\n\nexport interface NodePosition {\n x: number;\n y: number;\n}\n\nexport type NodePositions = Record<string, NodePosition>;\n\nexport interface MermaidERProps {\n /** Mermaid ER source. Mutually exclusive with `model`. */\n source?: string;\n /** Pre-built ER model. Takes precedence over `source`. */\n model?: ERModel;\n layout?: 'elk';\n algorithm?: LayoutAlgorithm;\n direction?: LayoutDirection;\n aspectRatio?: number;\n positions?: NodePositions;\n onPositionsChange?: (positions: NodePositions) => void;\n showColumnCheckboxes?: boolean;\n selectedColumns?: ColumnRef[];\n onColumnSelectionChange?: (selectedColumns: ColumnRef[]) => void;\n /** Enable column-to-column / card-to-card drag for manual JOINs. */\n enableManualJoins?: boolean;\n /** Existing manual joins to render alongside FK relations. */\n joins?: Join[];\n /**\n * Fired when the user finishes a connect drag. The consumer typically opens\n * a dialog to ask for join type, then appends a complete `Join` to its state.\n * `column` may be undefined when the drag landed on a default (table-center) handle.\n */\n onJoinConnect?: (source: PartialColumnRef, target: PartialColumnRef) => void;\n /** Fired when the user removes a manual join via Delete or the trash icon. */\n onJoinDelete?: (joinId: string) => void;\n /** When provided, a small × appears on each table header to remove it from the canvas. */\n onTableRemove?: (table: string) => void;\n highlightReferencesOnHover?: boolean;\n onColumnClick?: (table: string, column: string) => void;\n onTableClick?: (table: string) => void;\n /** Override the default delete-key code(s). Default is 'Delete' (Backspace ignored to prevent accidents). */\n deleteKeyCode?: string | string[] | null;\n className?: string;\n style?: CSSProperties;\n}\n\ninterface ParseState {\n model: ERModel | null;\n error: MermaidERParseError | null;\n}\n\nfunction safeParse(source: string): ParseState {\n try {\n return { model: parseMermaidER(source), error: null };\n } catch (e) {\n if (e instanceof MermaidERParseError) {\n return { model: null, error: e };\n }\n throw e;\n }\n}\n\nfunction handleIdFor(side: 'source' | 'target', column: string | undefined): string {\n return column ? `${column}__${side}` : `__default-${side}`;\n}\n\nconst JOIN_EDGE_PREFIX = 'join:';\n\nfunction parseHandleColumn(handleId: string | null | undefined): string | undefined {\n if (!handleId) return undefined;\n if (handleId.startsWith('__default-')) return undefined;\n const m = /^(.+)__(?:source|target)$/.exec(handleId);\n return m ? m[1] : undefined;\n}\n\nfunction refKey(ref: ColumnRef): string {\n return `${ref.table}.${ref.column}`;\n}\n\nconst JOIN_TYPE_COLOR: Record<Join['type'], string> = {\n INNER: '#3b82f6',\n LEFT: '#8b5cf6',\n RIGHT: '#a855f7',\n FULL: '#ec4899',\n CROSS: '#6b7280',\n};\n\nexport function MermaidER(props: MermaidERProps) {\n const {\n source,\n model: modelProp,\n algorithm,\n direction,\n aspectRatio,\n positions,\n onPositionsChange,\n showColumnCheckboxes,\n selectedColumns,\n onColumnSelectionChange,\n enableManualJoins,\n joins,\n onJoinConnect,\n onJoinDelete,\n onTableRemove,\n onColumnClick,\n onTableClick,\n deleteKeyCode = 'Delete',\n className,\n style,\n highlightReferencesOnHover = true,\n } = props;\n\n const { model, error } = useMemo<ParseState>(() => {\n if (modelProp) return { model: modelProp, error: null };\n if (source != null) return safeParse(source);\n return { model: null, error: null };\n }, [source, modelProp]);\n\n const [layout, setLayout] = useState<LayoutResult | null>(null);\n const [hoveredEdgeId, setHoveredEdgeId] = useState<string | null>(null);\n\n useEffect(() => {\n if (!model) {\n setLayout(null);\n return;\n }\n let cancelled = false;\n layoutER(model, { algorithm, direction, aspectRatio }).then((result) => {\n if (!cancelled) setLayout(result);\n });\n return () => {\n cancelled = true;\n };\n }, [model, algorithm, direction, aspectRatio]);\n\n const baseNodes = useMemo<Node[]>(() => {\n if (!layout || !model) return [];\n const tableMap = new Map(model.tables.map((t) => [t.name, t]));\n const result: Node[] = [];\n for (const n of layout.nodes) {\n const table = tableMap.get(n.id);\n // Skip stale nodes: a model update can arrive before the new layout\n // finishes; in that gap, layout may still reference a removed table.\n if (!table) continue;\n const override = positions?.[n.id];\n const data: TableNodeData = { table };\n result.push({\n id: n.id,\n type: 'table',\n position: override ?? { x: n.x, y: n.y },\n data,\n width: n.width,\n height: n.height,\n draggable: true,\n deletable: false,\n });\n }\n return result;\n // `onColumnClick` is intentionally NOT a dep — it flows via TableActionsContext\n // so a non-stable callback identity from the parent doesn't reset React Flow\n // node state (which would clobber an in-flight drag).\n }, [layout, model, positions]);\n\n const [nodes, setNodes, onNodesChange] = useNodesState<Node>(baseNodes);\n\n useEffect(() => {\n setNodes(baseNodes);\n }, [baseNodes, setNodes]);\n\n const handleNodeDragStop = useCallback(\n (_: unknown, _primary: Node, dragged: Node[]) => {\n if (!onPositionsChange) return;\n const next: NodePositions = { ...(positions ?? {}) };\n for (const n of dragged) {\n next[n.id] = { x: n.position.x, y: n.position.y };\n }\n onPositionsChange(next);\n },\n [positions, onPositionsChange],\n );\n\n const hoveredRelation = useMemo<Relation | undefined>(() => {\n if (!hoveredEdgeId || !model) return undefined;\n return model.relations.find((r) => r.id === hoveredEdgeId);\n }, [hoveredEdgeId, model]);\n\n const hoveredJoin = useMemo<Join | undefined>(() => {\n if (!hoveredEdgeId || !joins) return undefined;\n if (!hoveredEdgeId.startsWith(JOIN_EDGE_PREFIX)) return undefined;\n const id = hoveredEdgeId.slice(JOIN_EDGE_PREFIX.length);\n return joins.find((j) => j.id === id);\n }, [hoveredEdgeId, joins]);\n\n const highlightMap = useMemo<ReadonlyMap<string, ReadonlySet<string>>>(() => {\n const map = new Map<string, Set<string>>();\n if (!highlightReferencesOnHover) return map;\n\n const add = (table: string, column: string | undefined) => {\n if (!column) return;\n const set = map.get(table) ?? new Set();\n set.add(column);\n map.set(table, set);\n };\n\n if (hoveredRelation) {\n add(hoveredRelation.from, hoveredRelation.fromColumn);\n add(hoveredRelation.to, hoveredRelation.toColumn);\n }\n if (hoveredJoin) {\n add(hoveredJoin.source.table, hoveredJoin.source.column);\n add(hoveredJoin.target.table, hoveredJoin.target.column);\n }\n return map;\n }, [hoveredRelation, hoveredJoin, highlightReferencesOnHover]);\n\n const selectionSet = useMemo<ReadonlySet<string>>(() => {\n return new Set((selectedColumns ?? []).map(refKey));\n }, [selectedColumns]);\n\n const handleColumnSelectToggle = useCallback(\n (table: string, column: string, checked: boolean) => {\n if (!onColumnSelectionChange) return;\n const list = selectedColumns ?? [];\n if (checked) {\n if (list.some((r) => r.table === table && r.column === column)) return;\n onColumnSelectionChange([...list, { table, column }]);\n } else {\n onColumnSelectionChange(\n list.filter((r) => !(r.table === table && r.column === column)),\n );\n }\n },\n [selectedColumns, onColumnSelectionChange],\n );\n\n const selectionContext = useMemo<ColumnSelectionContextValue>(\n () => ({\n enabled: showColumnCheckboxes ?? false,\n selected: selectionSet,\n onToggle: handleColumnSelectToggle,\n }),\n [showColumnCheckboxes, selectionSet, handleColumnSelectToggle],\n );\n\n const edges = useMemo<Edge[]>(() => {\n if (!layout || !model) return [];\n const tableSet = new Set(model.tables.map((t) => t.name));\n const relMap = new Map(model.relations.map((r) => [r.id, r]));\n\n const fkEdges: Edge[] = [];\n for (const e of layout.edges) {\n // Skip stale edges referencing tables removed since the layout was computed.\n if (!tableSet.has(e.source) || !tableSet.has(e.target)) continue;\n const rel = relMap.get(e.id);\n const isHovered = e.id === hoveredEdgeId;\n fkEdges.push({\n id: e.id,\n source: e.source,\n target: e.target,\n sourceHandle: handleIdFor('source', rel?.fromColumn),\n targetHandle: handleIdFor('target', rel?.toColumn),\n type: 'smoothstep',\n animated: isHovered,\n deletable: false,\n style: {\n stroke: isHovered ? '#f59e0b' : '#9ca3af',\n strokeWidth: isHovered ? 2 : 1.5,\n },\n label: rel?.label,\n labelStyle: { fontSize: 10, fill: '#6b7280' },\n labelBgStyle: { fill: '#fff', fillOpacity: 0.85 },\n labelBgPadding: [4, 2] as [number, number],\n labelBgBorderRadius: 3,\n });\n }\n\n const joinEdges: Edge[] = [];\n for (const j of joins ?? []) {\n if (!tableSet.has(j.source.table) || !tableSet.has(j.target.table)) continue;\n const edgeId = `${JOIN_EDGE_PREFIX}${j.id}`;\n const isHovered = edgeId === hoveredEdgeId;\n const color = JOIN_TYPE_COLOR[j.type] ?? '#3b82f6';\n const data: JoinEdgeData = {\n type: j.type,\n color,\n hovered: isHovered,\n onDelete: onJoinDelete ? () => onJoinDelete(j.id) : undefined,\n };\n joinEdges.push({\n id: edgeId,\n source: j.source.table,\n target: j.target.table,\n sourceHandle: handleIdFor('source', j.source.column),\n targetHandle: handleIdFor('target', j.target.column),\n type: 'joinEdge',\n deletable: true,\n data: data as unknown as Record<string, unknown>,\n });\n }\n\n return [...fkEdges, ...joinEdges];\n }, [layout, model, joins, hoveredEdgeId, onJoinDelete]);\n\n const handleConnect = useCallback(\n (conn: Connection) => {\n if (!onJoinConnect) return;\n if (!conn.source || !conn.target) return;\n onJoinConnect(\n { table: conn.source, column: parseHandleColumn(conn.sourceHandle) },\n { table: conn.target, column: parseHandleColumn(conn.targetHandle) },\n );\n },\n [onJoinConnect],\n );\n\n const handleEdgesDelete = useCallback(\n (deleted: Edge[]) => {\n if (!onJoinDelete) return;\n for (const e of deleted) {\n if (e.id.startsWith(JOIN_EDGE_PREFIX)) {\n onJoinDelete(e.id.slice(JOIN_EDGE_PREFIX.length));\n }\n }\n },\n [onJoinDelete],\n );\n\n const connectModeOn = !!enableManualJoins;\n const tableActions = useMemo<TableActionsContextValue>(\n () => ({ onTableRemove, onColumnClick }),\n [onTableRemove, onColumnClick],\n );\n\n return (\n <div\n className={className}\n style={{ width: '100%', height: '100%', position: 'relative', ...style }}\n >\n {error && (\n <div\n style={{\n position: 'absolute',\n top: 8,\n left: 8,\n right: 8,\n zIndex: 10,\n padding: '8px 12px',\n background: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 6,\n color: '#991b1b',\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontSize: 12,\n whiteSpace: 'pre-wrap',\n }}\n >\n {error.message}\n </div>\n )}\n {!error && !layout && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#9ca3af',\n fontSize: 13,\n }}\n >\n Computing layout…\n </div>\n )}\n <HighlightContext.Provider value={highlightMap}>\n <ColumnSelectionContext.Provider value={selectionContext}>\n <ConnectModeContext.Provider value={connectModeOn}>\n <TableActionsContext.Provider value={tableActions}>\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n fitView\n onNodesChange={onNodesChange}\n onNodeDragStop={handleNodeDragStop}\n onNodeClick={\n onTableClick ? (_, node) => onTableClick(node.id) : undefined\n }\n onEdgeMouseEnter={(_, edge) => setHoveredEdgeId(edge.id)}\n onEdgeMouseLeave={() => setHoveredEdgeId(null)}\n onConnect={handleConnect}\n onEdgesDelete={handleEdgesDelete}\n nodesDraggable\n nodesConnectable={connectModeOn}\n elementsSelectable\n deleteKeyCode={deleteKeyCode}\n minZoom={0.1}\n maxZoom={4}\n >\n <Background />\n <Controls />\n <MiniMap pannable zoomable />\n </ReactFlow>\n </TableActionsContext.Provider>\n </ConnectModeContext.Provider>\n </ColumnSelectionContext.Provider>\n </HighlightContext.Provider>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/components/TableNode.tsx","../src/components/JoinEdge.tsx","../src/components/MermaidER.tsx"],"sourcesContent":["import { Fragment, createContext, memo, useContext } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport type { NodeProps } from '@xyflow/react';\nimport type { Column, Table } from '../core/model';\nimport { HEADER_HEIGHT, ROW_HEIGHT } from '../core/layout';\n\nexport interface TableNodeData extends Record<string, unknown> {\n table: Table;\n}\n\n/**\n * Map from table name -> set of highlighted column names.\n * Provided by MermaidER, consumed by TableNode for hover-driven highlighting\n * without forcing the whole node array to recompute on every hover change.\n */\nexport const HighlightContext = createContext<ReadonlyMap<string, ReadonlySet<string>>>(new Map());\n\nexport interface ColumnSelectionContextValue {\n enabled: boolean;\n /** \"table.column\" keys for fast lookup. */\n selected: ReadonlySet<string>;\n onToggle: (table: string, column: string, checked: boolean) => void;\n}\n\nexport const ColumnSelectionContext = createContext<ColumnSelectionContextValue>({\n enabled: false,\n selected: new Set(),\n onToggle: () => undefined,\n});\n\n/** When true, column handles become visible/connectable for manual JOIN drawing. */\nexport const ConnectModeContext = createContext<boolean>(false);\n\nexport interface TableActionsContextValue {\n /** When provided, a delete affordance is shown on the table header. */\n onTableRemove?: (table: string) => void;\n /** Per-column click handler. Provided via context (not node data) so its\n * identity can change without invalidating the React Flow node array. */\n onColumnClick?: (table: string, column: string) => void;\n}\n\nexport const TableActionsContext = createContext<TableActionsContextValue>({});\n\nconst KEY_STYLES: Record<'pk' | 'fk' | 'uk', { label: string; bg: string }> = {\n pk: { label: 'PK', bg: '#f59e0b' },\n fk: { label: 'FK', bg: '#3b82f6' },\n uk: { label: 'UK', bg: '#10b981' },\n};\n\nfunction ColumnRow({\n tableName,\n column,\n highlighted,\n onClick,\n selectionEnabled,\n selected,\n onSelectToggle,\n}: {\n tableName: string;\n column: Column;\n highlighted: boolean;\n onClick?: (table: string, column: string) => void;\n selectionEnabled: boolean;\n selected: boolean;\n onSelectToggle: (checked: boolean) => void;\n}) {\n const badges: Array<{ label: string; bg: string }> = [];\n if (column.keys.pk) badges.push(KEY_STYLES.pk);\n if (column.keys.fk) badges.push(KEY_STYLES.fk);\n if (column.keys.uk) badges.push(KEY_STYLES.uk);\n\n return (\n <div\n title={column.comment}\n onClick={onClick ? () => onClick(tableName, column.name) : undefined}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '0 10px',\n fontSize: 12,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n borderTop: '1px solid #eee',\n height: ROW_HEIGHT,\n boxSizing: 'border-box',\n cursor: onClick ? 'pointer' : 'default',\n background: highlighted ? '#fef3c7' : selected ? '#eff6ff' : 'transparent',\n transition: 'background 0.15s',\n }}\n >\n {selectionEnabled && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(e) => onSelectToggle(e.target.checked)}\n onClick={(e) => e.stopPropagation()}\n style={{\n width: 13,\n height: 13,\n margin: 0,\n flexShrink: 0,\n cursor: 'pointer',\n }}\n />\n )}\n <span style={{ display: 'flex', gap: 2, flexShrink: 0, minWidth: 18 }}>\n {badges.map((b) => (\n <span\n key={b.label}\n style={{\n display: 'inline-block',\n padding: '0 4px',\n borderRadius: 3,\n background: b.bg,\n color: '#fff',\n fontSize: 9,\n fontWeight: 700,\n lineHeight: '14px',\n }}\n >\n {b.label}\n </span>\n ))}\n </span>\n <span\n style={{\n flexShrink: 0,\n fontWeight: column.keys.pk ? 600 : 400,\n color: '#1f2937',\n }}\n >\n {column.name}\n </span>\n {column.type && (\n <span\n style={{\n flex: 1,\n textAlign: 'right',\n color: '#9ca3af',\n fontStyle: 'italic',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {column.type}\n </span>\n )}\n </div>\n );\n}\n\nexport const TableNode = memo(function TableNode({ data }: NodeProps) {\n const { table } = data as TableNodeData;\n const highlightMap = useContext(HighlightContext);\n const selection = useContext(ColumnSelectionContext);\n const connectMode = useContext(ConnectModeContext);\n const tableActions = useContext(TableActionsContext);\n const onColumnClick = tableActions.onColumnClick;\n const highlightedCols = highlightMap.get(table.name);\n const headerBg = table.group ? '#1e40af' : '#374151';\n\n const handleStyle = (extra: { top?: number }): React.CSSProperties => ({\n ...extra,\n width: connectMode ? 9 : 6,\n height: connectMode ? 9 : 6,\n background: connectMode ? '#3b82f6' : 'transparent',\n border: connectMode ? '1.5px solid #fff' : 'none',\n boxShadow: connectMode ? '0 0 0 1px rgba(59,130,246,0.4)' : 'none',\n opacity: connectMode ? 0.85 : 0,\n pointerEvents: connectMode ? 'auto' : 'none',\n cursor: connectMode ? 'crosshair' : 'default',\n });\n\n return (\n <div\n style={{\n background: '#fff',\n border: '1px solid #c4c4c4',\n borderRadius: 6,\n boxShadow: '0 2px 6px rgba(0,0,0,0.08)',\n overflow: 'visible',\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n }}\n >\n <Handle\n id=\"__default-target\"\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n <Handle\n id=\"__default-source\"\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n\n <div\n style={{\n padding: '6px 10px',\n background: headerBg,\n color: '#fff',\n fontWeight: 600,\n fontSize: 13,\n height: HEADER_HEIGHT,\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n borderTopLeftRadius: 6,\n borderTopRightRadius: 6,\n }}\n >\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {table.name}\n </span>\n <span style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>\n {table.group && (\n <span\n style={{\n fontSize: 10,\n opacity: 0.75,\n fontWeight: 400,\n padding: '1px 5px',\n border: '1px solid rgba(255,255,255,0.3)',\n borderRadius: 3,\n }}\n >\n {table.group}\n </span>\n )}\n {tableActions.onTableRemove && (\n <button\n className=\"nodrag\"\n onClick={(e) => {\n e.stopPropagation();\n tableActions.onTableRemove?.(table.name);\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this table\"\n style={{\n background: 'rgba(255,255,255,0.18)',\n border: 'none',\n color: '#fff',\n width: 18,\n height: 18,\n borderRadius: 3,\n cursor: 'pointer',\n fontSize: 13,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </span>\n </div>\n\n {table.columns.map((col, i) => {\n const handleY = HEADER_HEIGHT + i * ROW_HEIGHT + ROW_HEIGHT / 2;\n const highlighted = highlightedCols?.has(col.name) ?? false;\n const selectionKey = `${table.name}.${col.name}`;\n const selected = selection.enabled && selection.selected.has(selectionKey);\n return (\n <Fragment key={`${col.name}-${i}`}>\n <Handle\n id={`${col.name}__target`}\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: handleY })}\n />\n <Handle\n id={`${col.name}__source`}\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: handleY })}\n />\n <ColumnRow\n tableName={table.name}\n column={col}\n highlighted={highlighted}\n onClick={onColumnClick}\n selectionEnabled={selection.enabled}\n selected={selected}\n onSelectToggle={(checked) =>\n selection.onToggle(table.name, col.name, checked)\n }\n />\n </Fragment>\n );\n })}\n </div>\n );\n});\n","import { memo } from 'react';\nimport {\n BaseEdge,\n EdgeLabelRenderer,\n getSmoothStepPath,\n type EdgeProps,\n} from '@xyflow/react';\nimport type { JoinType } from '../core/model';\n\nexport interface JoinEdgeData extends Record<string, unknown> {\n type: JoinType;\n color: string;\n hovered?: boolean;\n onDelete?: () => void;\n}\n\nexport const JoinEdge = memo(function JoinEdge({\n id,\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n data,\n selected,\n}: EdgeProps) {\n const [edgePath, labelX, labelY] = getSmoothStepPath({\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n });\n\n const d = (data ?? {}) as JoinEdgeData;\n const emphasized = !!selected || !!d.hovered;\n const color = d.color || '#3b82f6';\n\n return (\n <>\n <BaseEdge\n id={id}\n path={edgePath}\n style={{\n stroke: color,\n strokeWidth: emphasized ? 2.5 : 2,\n strokeDasharray: '6 3',\n }}\n />\n <EdgeLabelRenderer>\n <div\n className=\"nodrag nopan\"\n style={{\n position: 'absolute',\n transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,\n background: color,\n color: '#fff',\n fontSize: 10,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontWeight: 700,\n borderRadius: 3,\n padding: '2px 4px 2px 6px',\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n pointerEvents: 'all',\n boxShadow: emphasized\n ? '0 0 0 2px rgba(0,0,0,0.4)'\n : '0 1px 2px rgba(0,0,0,0.15)',\n userSelect: 'none',\n }}\n >\n <span>{d.type}</span>\n {d.onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n d.onDelete?.();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this JOIN\"\n style={{\n background: 'rgba(255,255,255,0.25)',\n border: 'none',\n color: '#fff',\n width: 14,\n height: 14,\n borderRadius: 2,\n cursor: 'pointer',\n fontSize: 11,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </div>\n </EdgeLabelRenderer>\n </>\n );\n});\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type Ref,\n} from 'react';\nimport {\n ReactFlow,\n Background,\n Controls,\n MiniMap,\n useNodesState,\n useReactFlow,\n type Connection,\n type Edge,\n type EdgeTypes,\n type FitViewOptions,\n type Node,\n type NodeTypes,\n type Rect,\n type Viewport,\n} from '@xyflow/react';\n// React Flow's CSS is intentionally NOT imported here. Consumers must add it\n// once at their app entry point: `import '@xyflow/react/dist/style.css';`.\n// Importing it from this file would cause double-injection in apps that\n// already use React Flow, and inflate this library's bundled assets.\nimport { parseMermaidER, MermaidERParseError } from '../core/parser';\nimport {\n layoutER,\n type LayoutAlgorithm,\n type LayoutDirection,\n type LayoutResult,\n} from '../core/layout';\nimport type {\n ColumnRef,\n ERModel,\n Join,\n PartialColumnRef,\n Relation,\n} from '../core/model';\nimport {\n ColumnSelectionContext,\n ConnectModeContext,\n HighlightContext,\n TableActionsContext,\n TableNode,\n type ColumnSelectionContextValue,\n type TableActionsContextValue,\n type TableNodeData,\n} from './TableNode';\nimport { JoinEdge, type JoinEdgeData } from './JoinEdge';\n\nconst nodeTypes: NodeTypes = {\n table: TableNode,\n};\n\nconst edgeTypes: EdgeTypes = {\n joinEdge: JoinEdge,\n};\n\nexport interface NodePosition {\n x: number;\n y: number;\n}\n\nexport type NodePositions = Record<string, NodePosition>;\n\n/**\n * Imperative API exposed via `ref`. Designed to give consumers the primitives\n * needed for image export (fit → snapshot → restore) without baking any\n * specific export library into this package. Methods that change the viewport\n * return Promise<boolean> matching React Flow's underlying API.\n */\nexport interface MermaidERHandle {\n /** Fit all nodes into the visible viewport. */\n fitView: (options?: FitViewOptions) => Promise<boolean>;\n /** Read the current viewport (x, y, zoom) — capture before export to restore later. */\n getViewport: () => Viewport;\n /** Restore (or set) viewport. */\n setViewport: (viewport: Viewport) => Promise<boolean>;\n /** Bounding box of all current nodes. Useful for sizing offscreen canvases. */\n getNodesBounds: () => Rect;\n /** Outer wrapper element (the div that receives `className` / `style`). */\n getWrapperElement: () => HTMLDivElement | null;\n /**\n * The internal `.react-flow__viewport` element. Typical snapshot target\n * when you want to exclude `<Controls>` and `<MiniMap>` from the image.\n */\n getViewportElement: () => HTMLElement | null;\n}\n\nexport interface MermaidERProps {\n /** Mermaid ER source. Mutually exclusive with `model`. */\n source?: string;\n /** Pre-built ER model. Takes precedence over `source`. */\n model?: ERModel;\n layout?: 'elk';\n algorithm?: LayoutAlgorithm;\n direction?: LayoutDirection;\n aspectRatio?: number;\n positions?: NodePositions;\n onPositionsChange?: (positions: NodePositions) => void;\n showColumnCheckboxes?: boolean;\n selectedColumns?: ColumnRef[];\n onColumnSelectionChange?: (selectedColumns: ColumnRef[]) => void;\n /** Enable column-to-column / card-to-card drag for manual JOINs. */\n enableManualJoins?: boolean;\n /** Existing manual joins to render alongside FK relations. */\n joins?: Join[];\n /**\n * Fired when the user finishes a connect drag. The consumer typically opens\n * a dialog to ask for join type, then appends a complete `Join` to its state.\n * `column` may be undefined when the drag landed on a default (table-center) handle.\n */\n onJoinConnect?: (source: PartialColumnRef, target: PartialColumnRef) => void;\n /** Fired when the user removes a manual join via Delete or the trash icon. */\n onJoinDelete?: (joinId: string) => void;\n /** When provided, a small × appears on each table header to remove it from the canvas. */\n onTableRemove?: (table: string) => void;\n highlightReferencesOnHover?: boolean;\n onColumnClick?: (table: string, column: string) => void;\n onTableClick?: (table: string) => void;\n /** Override the default delete-key code(s). Default is 'Delete' (Backspace ignored to prevent accidents). */\n deleteKeyCode?: string | string[] | null;\n className?: string;\n style?: CSSProperties;\n}\n\ninterface ParseState {\n model: ERModel | null;\n error: MermaidERParseError | null;\n}\n\nfunction safeParse(source: string): ParseState {\n try {\n return { model: parseMermaidER(source), error: null };\n } catch (e) {\n if (e instanceof MermaidERParseError) {\n return { model: null, error: e };\n }\n throw e;\n }\n}\n\nfunction handleIdFor(side: 'source' | 'target', column: string | undefined): string {\n return column ? `${column}__${side}` : `__default-${side}`;\n}\n\nconst JOIN_EDGE_PREFIX = 'join:';\n\nfunction parseHandleColumn(handleId: string | null | undefined): string | undefined {\n if (!handleId) return undefined;\n if (handleId.startsWith('__default-')) return undefined;\n const m = /^(.+)__(?:source|target)$/.exec(handleId);\n return m ? m[1] : undefined;\n}\n\nfunction refKey(ref: ColumnRef): string {\n return `${ref.table}.${ref.column}`;\n}\n\nconst JOIN_TYPE_COLOR: Record<Join['type'], string> = {\n INNER: '#3b82f6',\n LEFT: '#8b5cf6',\n RIGHT: '#a855f7',\n FULL: '#ec4899',\n CROSS: '#6b7280',\n};\n\n/**\n * Bridge: `useReactFlow()` only works inside the <ReactFlow> provider, but the\n * imperative ref must be attached to MermaidER (which is the *parent* of\n * <ReactFlow>). This null-rendering child runs the hook in the right scope and\n * forwards the methods back out.\n */\nfunction HandleBridge({\n apiRef,\n wrapperRef,\n}: {\n apiRef: Ref<MermaidERHandle> | undefined;\n wrapperRef: React.RefObject<HTMLDivElement | null>;\n}) {\n const rf = useReactFlow();\n useImperativeHandle(\n apiRef,\n () => ({\n fitView: (options) => rf.fitView(options),\n getViewport: () => rf.getViewport(),\n setViewport: (viewport) => rf.setViewport(viewport),\n getNodesBounds: () => rf.getNodesBounds(rf.getNodes()),\n getWrapperElement: () => wrapperRef.current,\n getViewportElement: () =>\n wrapperRef.current?.querySelector<HTMLElement>('.react-flow__viewport') ?? null,\n }),\n [rf, wrapperRef],\n );\n return null;\n}\n\nexport const MermaidER = forwardRef<MermaidERHandle, MermaidERProps>(function MermaidER(\n props,\n ref,\n) {\n const {\n source,\n model: modelProp,\n algorithm,\n direction,\n aspectRatio,\n positions,\n onPositionsChange,\n showColumnCheckboxes,\n selectedColumns,\n onColumnSelectionChange,\n enableManualJoins,\n joins,\n onJoinConnect,\n onJoinDelete,\n onTableRemove,\n onColumnClick,\n onTableClick,\n deleteKeyCode = 'Delete',\n className,\n style,\n highlightReferencesOnHover = true,\n } = props;\n\n const { model, error } = useMemo<ParseState>(() => {\n if (modelProp) return { model: modelProp, error: null };\n if (source != null) return safeParse(source);\n return { model: null, error: null };\n }, [source, modelProp]);\n\n const [layout, setLayout] = useState<LayoutResult | null>(null);\n const [hoveredEdgeId, setHoveredEdgeId] = useState<string | null>(null);\n\n useEffect(() => {\n if (!model) {\n setLayout(null);\n return;\n }\n let cancelled = false;\n layoutER(model, { algorithm, direction, aspectRatio }).then((result) => {\n if (!cancelled) setLayout(result);\n });\n return () => {\n cancelled = true;\n };\n }, [model, algorithm, direction, aspectRatio]);\n\n const baseNodes = useMemo<Node[]>(() => {\n if (!layout || !model) return [];\n const tableMap = new Map(model.tables.map((t) => [t.name, t]));\n const result: Node[] = [];\n for (const n of layout.nodes) {\n const table = tableMap.get(n.id);\n // Skip stale nodes: a model update can arrive before the new layout\n // finishes; in that gap, layout may still reference a removed table.\n if (!table) continue;\n const override = positions?.[n.id];\n const data: TableNodeData = { table };\n result.push({\n id: n.id,\n type: 'table',\n position: override ?? { x: n.x, y: n.y },\n data,\n width: n.width,\n height: n.height,\n draggable: true,\n deletable: false,\n });\n }\n return result;\n // `onColumnClick` is intentionally NOT a dep — it flows via TableActionsContext\n // so a non-stable callback identity from the parent doesn't reset React Flow\n // node state (which would clobber an in-flight drag).\n }, [layout, model, positions]);\n\n const [nodes, setNodes, onNodesChange] = useNodesState<Node>(baseNodes);\n\n useEffect(() => {\n setNodes(baseNodes);\n }, [baseNodes, setNodes]);\n\n const handleNodeDragStop = useCallback(\n (_: unknown, _primary: Node, dragged: Node[]) => {\n if (!onPositionsChange) return;\n const next: NodePositions = { ...(positions ?? {}) };\n for (const n of dragged) {\n next[n.id] = { x: n.position.x, y: n.position.y };\n }\n onPositionsChange(next);\n },\n [positions, onPositionsChange],\n );\n\n const hoveredRelation = useMemo<Relation | undefined>(() => {\n if (!hoveredEdgeId || !model) return undefined;\n return model.relations.find((r) => r.id === hoveredEdgeId);\n }, [hoveredEdgeId, model]);\n\n const hoveredJoin = useMemo<Join | undefined>(() => {\n if (!hoveredEdgeId || !joins) return undefined;\n if (!hoveredEdgeId.startsWith(JOIN_EDGE_PREFIX)) return undefined;\n const id = hoveredEdgeId.slice(JOIN_EDGE_PREFIX.length);\n return joins.find((j) => j.id === id);\n }, [hoveredEdgeId, joins]);\n\n const highlightMap = useMemo<ReadonlyMap<string, ReadonlySet<string>>>(() => {\n const map = new Map<string, Set<string>>();\n if (!highlightReferencesOnHover) return map;\n\n const add = (table: string, column: string | undefined) => {\n if (!column) return;\n const set = map.get(table) ?? new Set();\n set.add(column);\n map.set(table, set);\n };\n\n if (hoveredRelation) {\n add(hoveredRelation.from, hoveredRelation.fromColumn);\n add(hoveredRelation.to, hoveredRelation.toColumn);\n }\n if (hoveredJoin) {\n add(hoveredJoin.source.table, hoveredJoin.source.column);\n add(hoveredJoin.target.table, hoveredJoin.target.column);\n }\n return map;\n }, [hoveredRelation, hoveredJoin, highlightReferencesOnHover]);\n\n const selectionSet = useMemo<ReadonlySet<string>>(() => {\n return new Set((selectedColumns ?? []).map(refKey));\n }, [selectedColumns]);\n\n const handleColumnSelectToggle = useCallback(\n (table: string, column: string, checked: boolean) => {\n if (!onColumnSelectionChange) return;\n const list = selectedColumns ?? [];\n if (checked) {\n if (list.some((r) => r.table === table && r.column === column)) return;\n onColumnSelectionChange([...list, { table, column }]);\n } else {\n onColumnSelectionChange(\n list.filter((r) => !(r.table === table && r.column === column)),\n );\n }\n },\n [selectedColumns, onColumnSelectionChange],\n );\n\n const selectionContext = useMemo<ColumnSelectionContextValue>(\n () => ({\n enabled: showColumnCheckboxes ?? false,\n selected: selectionSet,\n onToggle: handleColumnSelectToggle,\n }),\n [showColumnCheckboxes, selectionSet, handleColumnSelectToggle],\n );\n\n const edges = useMemo<Edge[]>(() => {\n if (!layout || !model) return [];\n const tableSet = new Set(model.tables.map((t) => t.name));\n const relMap = new Map(model.relations.map((r) => [r.id, r]));\n\n const fkEdges: Edge[] = [];\n for (const e of layout.edges) {\n // Skip stale edges referencing tables removed since the layout was computed.\n if (!tableSet.has(e.source) || !tableSet.has(e.target)) continue;\n const rel = relMap.get(e.id);\n const isHovered = e.id === hoveredEdgeId;\n fkEdges.push({\n id: e.id,\n source: e.source,\n target: e.target,\n sourceHandle: handleIdFor('source', rel?.fromColumn),\n targetHandle: handleIdFor('target', rel?.toColumn),\n type: 'smoothstep',\n animated: isHovered,\n deletable: false,\n style: {\n stroke: isHovered ? '#f59e0b' : '#9ca3af',\n strokeWidth: isHovered ? 2 : 1.5,\n },\n label: rel?.label,\n labelStyle: { fontSize: 10, fill: '#6b7280' },\n labelBgStyle: { fill: '#fff', fillOpacity: 0.85 },\n labelBgPadding: [4, 2] as [number, number],\n labelBgBorderRadius: 3,\n });\n }\n\n const joinEdges: Edge[] = [];\n for (const j of joins ?? []) {\n if (!tableSet.has(j.source.table) || !tableSet.has(j.target.table)) continue;\n const edgeId = `${JOIN_EDGE_PREFIX}${j.id}`;\n const isHovered = edgeId === hoveredEdgeId;\n const color = JOIN_TYPE_COLOR[j.type] ?? '#3b82f6';\n const data: JoinEdgeData = {\n type: j.type,\n color,\n hovered: isHovered,\n onDelete: onJoinDelete ? () => onJoinDelete(j.id) : undefined,\n };\n joinEdges.push({\n id: edgeId,\n source: j.source.table,\n target: j.target.table,\n sourceHandle: handleIdFor('source', j.source.column),\n targetHandle: handleIdFor('target', j.target.column),\n type: 'joinEdge',\n deletable: true,\n data: data as unknown as Record<string, unknown>,\n });\n }\n\n return [...fkEdges, ...joinEdges];\n }, [layout, model, joins, hoveredEdgeId, onJoinDelete]);\n\n const handleConnect = useCallback(\n (conn: Connection) => {\n if (!onJoinConnect) return;\n if (!conn.source || !conn.target) return;\n onJoinConnect(\n { table: conn.source, column: parseHandleColumn(conn.sourceHandle) },\n { table: conn.target, column: parseHandleColumn(conn.targetHandle) },\n );\n },\n [onJoinConnect],\n );\n\n const handleEdgesDelete = useCallback(\n (deleted: Edge[]) => {\n if (!onJoinDelete) return;\n for (const e of deleted) {\n if (e.id.startsWith(JOIN_EDGE_PREFIX)) {\n onJoinDelete(e.id.slice(JOIN_EDGE_PREFIX.length));\n }\n }\n },\n [onJoinDelete],\n );\n\n const connectModeOn = !!enableManualJoins;\n const tableActions = useMemo<TableActionsContextValue>(\n () => ({ onTableRemove, onColumnClick }),\n [onTableRemove, onColumnClick],\n );\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n return (\n <div\n ref={wrapperRef}\n className={className}\n style={{ width: '100%', height: '100%', position: 'relative', ...style }}\n >\n {error && (\n <div\n style={{\n position: 'absolute',\n top: 8,\n left: 8,\n right: 8,\n zIndex: 10,\n padding: '8px 12px',\n background: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 6,\n color: '#991b1b',\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontSize: 12,\n whiteSpace: 'pre-wrap',\n }}\n >\n {error.message}\n </div>\n )}\n {!error && !layout && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#9ca3af',\n fontSize: 13,\n }}\n >\n Computing layout…\n </div>\n )}\n <HighlightContext.Provider value={highlightMap}>\n <ColumnSelectionContext.Provider value={selectionContext}>\n <ConnectModeContext.Provider value={connectModeOn}>\n <TableActionsContext.Provider value={tableActions}>\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n fitView\n onNodesChange={onNodesChange}\n onNodeDragStop={handleNodeDragStop}\n onNodeClick={\n onTableClick ? (_, node) => onTableClick(node.id) : undefined\n }\n onEdgeMouseEnter={(_, edge) => setHoveredEdgeId(edge.id)}\n onEdgeMouseLeave={() => setHoveredEdgeId(null)}\n onConnect={handleConnect}\n onEdgesDelete={handleEdgesDelete}\n nodesDraggable\n nodesConnectable={connectModeOn}\n elementsSelectable\n deleteKeyCode={deleteKeyCode}\n minZoom={0.1}\n maxZoom={4}\n >\n <Background />\n <Controls />\n <MiniMap pannable zoomable />\n <HandleBridge apiRef={ref} wrapperRef={wrapperRef} />\n </ReactFlow>\n </TableActionsContext.Provider>\n </ConnectModeContext.Provider>\n </ColumnSelectionContext.Provider>\n </HighlightContext.Provider>\n </div>\n );\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@msdshsk/react-er-canvas",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Render Mermaid-format ER diagrams in React/Electron with extended visual features (PK/FK icons, schema groups, FK reference highlighting, manual JOINs, drag-to-position).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|