dbml-erd-viewer 0.1.1 → 0.1.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.
@@ -1,2 +1,2 @@
1
1
  (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@xyflow/react"),require("@dbml/core"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@xyflow/react`,`@dbml/core`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.DbmlErdViewer={},e.React,e.XYFlowReact,e.DbmlCore,e.jsxRuntime))})(this,function(e,t,n,r,i){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var a=Object.create,o=Object.defineProperty,s=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty,d=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=c(t),a=0,l=i.length,d;a<l;a++)d=i[a],!u.call(e,d)&&d!==n&&o(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=s(t,d))||r.enumerable});return e};r=((e,t,n)=>(n=e==null?{}:a(l(e)),d(t||!e||!e.__esModule?o(n,`default`,{value:e,enumerable:!0}):n,e)))(r,1);var f=r,p=f.Parser??f.default?.Parser;if(!p)throw Error("Could not resolve `Parser` export from @dbml/core.");var m=p,h=`public`,g=class extends Error{diagnostics;constructor(e,t){super(e,t),this.name=`DbmlParseError`,this.diagnostics=t?.diagnostics??[]}};function _(e){let t=e?.diags;return Array.isArray(t)?t.map(e=>({message:e.message??`Unknown error`,line:e.location?.start?.line,column:e.location?.start?.column,code:e.code})):[]}function v(e,t){if(e.length===0)return`Failed to parse DBML: ${t}`;let n=e.map(e=>` • ${e.line==null?``:`Line ${e.line}${e.column==null?``:`:${e.column}`} — `}${e.message}`);return`${e.length===1?`Failed to parse DBML:`:`Failed to parse DBML (${e.length} errors):`}\n${n.join(`
2
- `)}`}function y(e){if(e)return typeof e==`string`?e:e.value??void 0}function b(e,t){return e&&e!==h?`${e}.${t}`:t}function x(e){let t=new Set;for(let n of e.fields)n.pk&&t.add(n.name);for(let n of e.indexes??[])if(n.pk)for(let e of n.columns??[])e.type===`column`&&e.value&&t.add(e.value);return t}function S(e){let t;try{t=new m().parse(e,`dbmlv2`)}catch(e){let t=_(e);throw new g(v(t,e instanceof Error?e.message:String(e)),{cause:e,diagnostics:t})}let n=new Map;for(let e of t.schemas)for(let t of e.tables){let r=b(e.name,t.name),i=x(t),a=new Map;for(let e of t.fields){let t=i.has(e.name);a.set(e.name,{pk:t,notNull:t||!!e.not_null,note:y(e.note)})}n.set(r,a)}let r=e=>{let t=n.get(e.tableId);return!t||e.columns.length===0?!1:e.columns.every(e=>t.get(e)?.pk===!0)},i=e=>e.columns.some(t=>{let r=n.get(e.tableId)?.get(t);return r?!r.notNull&&!r.pk:!0}),a=e=>e.columns.some(t=>n.get(e.tableId)?.get(t)?.note?.toLowerCase().includes(`optional`)??!1),o=[],s=new Set;for(let e of t.schemas)for(let t of e.refs){if(t.endpoints.length!==2)continue;let[n,c]=t.endpoints.map(t=>({tableId:b(t.schemaName??e.name,t.tableName),columns:t.fieldNames,relation:t.relation})),l,u,d=n.relation===`*`;if(d!==(c.relation===`*`))l=d?n:c,u=d?c:n;else{let e=r(n),t=r(c);e&&!t?(l=c,u=n):(l=n,u=c)}let f=r(l),p=i(l);l.columns.forEach(e=>s.add(`${l.tableId}::${e}`)),o.push({id:`${l.tableId}.${l.columns.join(`-`)}__${u.tableId}.${u.columns.join(`-`)}`,kind:f?`identifying`:`non-identifying`,from:{...l,optional:a(l)?!0:void 0},to:{...u,optional:p}})}let c=[];for(let e of t.schemas){let t=e.name;for(let n of e.tables){let e=b(t,n.name),r=x(n),i=n.fields.map(t=>({name:t.name,type:t.type?.type_name??`unknown`,pk:r.has(t.name),notNull:r.has(t.name)||!!t.not_null,unique:!!t.unique,increment:!!t.increment,defaultValue:t.dbdefault?.value,note:y(t.note),isForeignKey:s.has(`${e}::${t.name}`)}));c.push({id:e,name:n.name,schema:t===h?void 0:t,note:y(n.note),headerColor:n.headerColor??void 0,columns:i})}}return{tables:c,relations:o}}var C=160,w=320,T=320,E=40,D=28;function O(e){return 40+Math.max(e.columns.length,1)*28}var k=24,A=8,j=24,M=12,N=24,P=6.8,F=7.4;function I(e,t={}){let n=t.minWidth??160,r=t.maxWidth??320,i=N+L(e)*F;for(let t of e.columns){let e=(t.pk||t.isForeignKey?j:0)+t.name.length*P,n=t.type.length*P+M;i=Math.max(i,k+e+A+n)}return Math.round(Math.min(r,Math.max(n,i)))}function L(e){return(e.schema?e.schema.length+1:0)+e.name.length}function R(e){let t=new Map;for(let n of e.tables)t.set(n.id,0);let n=e.relations.map(e=>[e.from.tableId,e.to.tableId]).filter(([e,n])=>e!==n&&t.has(e)&&t.has(n));for(let r=0;r<e.tables.length;r++){let e=!1;for(let[r,i]of n){let n=t.get(r)+1;t.get(i)<n&&(t.set(i,n),e=!0)}if(!e)break}return t}function z(e,t={}){let n=t.horizontalGap??120,r=t.verticalGap??40,i={minWidth:t.minNodeWidth,maxWidth:t.maxNodeWidth},a=R(e),o=new Map;for(let t of e.tables){let e=a.get(t.id)??0,n=o.get(e);n||(n=[],o.set(e,n)),n.push(t)}let s=new Map,c=[...o.keys()].sort((e,t)=>e-t),l=0;for(let e of c){let t=o.get(e).sort((e,t)=>e.name.localeCompare(t.name)),a=0,c=0;for(let e of t){let t=I(e,i),n=O(e);s.set(e.id,{x:l,y:c,width:t,height:n}),a=Math.max(a,t),c+=n+r}l+=a+n}return s}async function B(e,t={}){let n=await import(`@dagrejs/dagre`),r=t.horizontalGap??120,i=t.verticalGap??40,a={minWidth:t.minNodeWidth,maxWidth:t.maxNodeWidth},o=t.direction===`TB`?`TB`:`LR`,s=new n.graphlib.Graph;s.setGraph({rankdir:o,ranksep:r,nodesep:i}),s.setDefaultEdgeLabel(()=>({}));for(let t of e.tables)s.setNode(t.id,{width:I(t,a),height:O(t)});for(let t of e.relations)s.hasNode(t.from.tableId)&&s.hasNode(t.to.tableId)&&s.setEdge(t.from.tableId,t.to.tableId);n.layout(s);let c=new Map;for(let e of s.nodes()){let t=s.node(e);t&&c.set(e,{x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height})}return c}async function V(e,t={}){let n=new(await(import(`elkjs/lib/elk.bundled.js`))).default,r=t.horizontalGap??120,i=t.verticalGap??40,a={minWidth:t.minNodeWidth,maxWidth:t.maxNodeWidth},o={id:`root`,layoutOptions:{"elk.algorithm":`layered`,"elk.direction":t.direction===`TB`?`DOWN`:`RIGHT`,"elk.layered.spacing.nodeNodeBetweenLayers":String(r),"elk.spacing.nodeNode":String(i)},children:e.tables.map(e=>({id:e.id,width:I(e,a),height:O(e)})),edges:e.relations.map((e,t)=>({id:`e${t}`,sources:[e.from.tableId],targets:[e.to.tableId]}))},s=await n.layout(o),c=new Map;for(let e of s.children??[])c.set(e.id,{x:e.x??0,y:e.y??0,width:e.width??160,height:e.height??0});return c}var H=class extends Error{constructor(e,t){super(e,t),this.name=`LayoutError`}};async function U(e,t={}){let n=t.algorithm??`simple`;if(n===`simple`)return z(e,t);try{return n===`dagre`?await B(e,t):await V(e,t)}catch(e){throw new H(`"${n}" layout failed. Is the optional dependency "${n===`dagre`?`@dagrejs/dagre`:`elkjs`}" installed? (${e instanceof Error?e.message:String(e)})`,{cause:e})}}var ee=[`--dv-canvas`,`--dv-bg`,`--dv-border`,`--dv-header-bg`,`--dv-header-fg`,`--dv-row-fg`,`--dv-type-fg`,`--dv-row-hover`,`--dv-row-highlight`,`--dv-pk`,`--dv-fk`,`--dv-null`,`--dv-edge`,`--dv-edge-active`,`--dv-font`],W=class extends Error{constructor(e,t){super(e,t),this.name=`ExportError`}};function te(e,t){let n=e.x,r=e.y,i=e.x+e.width,a=e.y+e.height;for(let e of t.querySelectorAll(`.dv-erd-edge`)){let t;try{t=e.getBBox()}catch{continue}t.width===0&&t.height===0||(n=Math.min(n,t.x),r=Math.min(r,t.y),i=Math.max(i,t.x+t.width),a=Math.max(a,t.y+t.height))}return{x:n,y:r,width:i-n,height:a-r}}async function G(e,t,n={}){let{type:r=`png`,padding:i=24,backgroundColor:a,pixelRatio:o=2}=n,s;try{s=await import(`html-to-image`)}catch(e){throw new W(`Export requires the optional dependency "html-to-image". Install it to enable PNG/SVG export.`,{cause:e})}if(typeof document<`u`&&document.fonts?.ready)try{await document.fonts.ready}catch{}let c=Math.ceil(t.width+i*2),l=Math.ceil(t.height+i*2),u=`translate(${-t.x+i}px, ${-t.y+i}px) scale(1)`,d={width:c,height:l,backgroundColor:a,style:{width:`${c}px`,height:`${l}px`,transform:u}},f=K(e,t,i);try{return r===`svg`?await s.toSvg(e,d):await s.toPng(e,{...d,pixelRatio:o})}catch(e){throw new W(`Failed to render diagram image: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{f()}}function K(e,t,n){let r=[],i=e.closest(`.dv-viewer`);if(i){let t=getComputedStyle(i);for(let n of ee){let i=t.getPropertyValue(n);if(!i)continue;let a=e.style.getPropertyValue(n);e.style.setProperty(n,i),r.push(()=>{a?e.style.setProperty(n,a):e.style.removeProperty(n)})}}let a=`${Math.ceil(t.x+t.width+n)}px`,o=`${Math.ceil(t.y+t.height+n)}px`;for(let t of e.querySelectorAll(`.react-flow__edges svg`)){let{width:e,height:n}=t.style;t.style.width=a,t.style.height=o,r.push(()=>{t.style.width=e,t.style.height=n})}return()=>r.forEach(e=>e())}function q(e,t){let n=document.createElement(`a`);n.href=e,n.download=t,n.click()}function J(e,t,n){return`${e}__${t}__${n}`}function Y(e){return 40+e*28+28/2}function X({column:e,top:t}){let r={top:t,opacity:0};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.Handle,{id:J(e,`left`,`target`),type:`target`,position:n.Position.Left,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:J(e,`left`,`source`),type:`source`,position:n.Position.Left,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:J(e,`right`,`target`),type:`target`,position:n.Position.Right,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:J(e,`right`,`source`),type:`source`,position:n.Position.Right,style:r,isConnectable:!1})]})}function ne({data:e}){let{table:t,highlightedColumns:n,widthBounds:r}=e;return(0,i.jsxs)(`div`,{className:`dv-table`,style:{width:I(t,r)},children:[(0,i.jsxs)(`div`,{className:`dv-table__header`,style:t.headerColor?{background:t.headerColor,height:40}:{height:40},title:t.note,children:[t.schema&&(0,i.jsxs)(`span`,{className:`dv-table__schema`,children:[t.schema,`.`]}),(0,i.jsx)(`span`,{className:`dv-table__name`,title:t.name,children:t.name})]}),(0,i.jsx)(`div`,{className:`dv-table__body`,children:t.columns.map((e,t)=>{let r=n?.has(e.name);return(0,i.jsxs)(`div`,{className:`dv-row${r?` dv-row--highlighted`:``}`,style:{height:28},title:e.note,children:[(0,i.jsxs)(`span`,{className:`dv-row__name${e.pk?` dv-row__name--pk`:``}`,children:[e.pk&&(0,i.jsx)(`span`,{className:`dv-badge dv-badge--pk`,title:`Primary key`,children:`PK`}),e.isForeignKey&&!e.pk&&(0,i.jsx)(`span`,{className:`dv-badge dv-badge--fk`,title:`Foreign key`,children:`FK`}),(0,i.jsx)(`span`,{className:`dv-row__label`,title:e.name,children:e.name})]}),(0,i.jsxs)(`span`,{className:`dv-row__type`,children:[(0,i.jsx)(`span`,{className:`dv-row__typename`,title:e.type,children:e.type}),(0,i.jsx)(`span`,{className:`dv-row__null${e.notNull?` dv-row__null--notnull`:``}`,title:e.notNull?`Not null`:`Nullable`})]}),(0,i.jsx)(X,{column:e.name,top:Y(t)})]},e.name)})})]})}var Z=(0,t.memo)(ne),Q=8,re=13,ie=7,ae=13,oe=16;function $(e,t,r,a,o,s){let c=-(r===n.Position.Left?1:-1),l=[],u={stroke:o,strokeWidth:s},d=(n,r)=>l.push((0,i.jsx)(`line`,{x1:e+c*n,y1:t-Q,x2:e+c*n,y2:t+Q,style:u},r)),f=(n,r)=>l.push((0,i.jsx)(`circle`,{cx:e+c*n,cy:t,r:4,style:{stroke:o,strokeWidth:s,fill:`var(--dv-bg)`}},r));if(a.cardinality===`*`){let n=e+c*re;l.push((0,i.jsx)(`line`,{x1:n,y1:t,x2:e,y2:t-Q,style:u},`cf1`),(0,i.jsx)(`line`,{x1:n,y1:t,x2:e,y2:t,style:u},`cf2`),(0,i.jsx)(`line`,{x1:n,y1:t,x2:e,y2:t+Q,style:u},`cf3`)),a.optional===!0?f(17,`fr`):d(14,`fb`)}else d(ie,`b1`),a.optional===!0?f(oe,`r`):a.optional===!1&&d(ae,`b2`);return(0,i.jsx)(`g`,{className:`dv-erd-marker`,children:l})}function se({sourceX:e,sourceY:t,targetX:r,targetY:a,sourcePosition:o,targetPosition:s,data:c,selected:l}){let[u]=(0,n.getSmoothStepPath)({sourceX:e,sourceY:t,sourcePosition:o,targetX:r,targetY:a,targetPosition:s,borderRadius:8}),d=c,f=d?.kind===`non-identifying`,p=l||d?.hovered,m=p?`var(--dv-edge-active)`:`var(--dv-edge)`,h=p?2:1.5;return(0,i.jsxs)(`g`,{className:`dv-erd-edge${p?` dv-erd-edge--active`:``}`,children:[(0,i.jsx)(`path`,{className:`dv-erd-edge__interaction`,d:u,fill:`none`}),(0,i.jsx)(`path`,{className:`dv-erd-edge__path`,d:u,fill:`none`,style:{stroke:m,strokeWidth:h},strokeDasharray:f?`6 4`:void 0}),d&&$(e,t,o,d.sourceEnd,m,h),d&&$(r,a,s,d.targetEnd,m,h)]})}var ce=(0,t.memo)(se);function le(e,n,r){let[i,a]=(0,t.useState)(null),o=(0,t.useMemo)(()=>{let t=new Map;for(let n of e)t.set(n.id,n);return t},[e]),s=(0,t.useMemo)(()=>{let e=new Map,t=i?o.get(i):void 0;if(!t)return e;for(let n of[t.from,t.to]){let t=e.get(n.tableId)??new Set;n.columns.forEach(e=>t.add(e)),e.set(n.tableId,t)}return e},[i,o]);return{displayNodes:(0,t.useMemo)(()=>i?n.map(e=>{let t=s.get(e.id);return t?{...e,data:{...e.data,highlightedColumns:t}}:e}):n,[n,i,s]),displayEdges:(0,t.useMemo)(()=>i?r.map(e=>e.id===i?{...e,data:{...e.data,hovered:!0},zIndex:1}:e):r,[r,i]),onEdgeMouseEnter:(0,t.useCallback)((e,t)=>a(t.id),[]),onEdgeMouseLeave:(0,t.useCallback)(()=>a(null),[])}}var ue={canvas:`--dv-canvas`,background:`--dv-bg`,border:`--dv-border`,headerBackground:`--dv-header-bg`,headerForeground:`--dv-header-fg`,rowForeground:`--dv-row-fg`,typeForeground:`--dv-type-fg`,rowHover:`--dv-row-hover`,rowHighlight:`--dv-row-highlight`,primaryKey:`--dv-pk`,foreignKey:`--dv-fk`,edge:`--dv-edge`,edgeActive:`--dv-edge-active`,fontFamily:`--dv-font`},de={canvas:`#fafbfc`,background:`#ffffff`,border:`#d9dee5`,headerBackground:`#2d3748`,headerForeground:`#ffffff`,rowForeground:`#1a202c`,typeForeground:`#718096`,rowHover:`#f1f5f9`,rowHighlight:`#dbeafe`,primaryKey:`#b7791f`,foreignKey:`#2b6cb0`,edge:`#94a3b8`,edgeActive:`#2b6cb0`},fe={canvas:`#0f172a`,background:`#1e293b`,border:`#334155`,headerBackground:`#334155`,headerForeground:`#f1f5f9`,rowForeground:`#e2e8f0`,typeForeground:`#94a3b8`,rowHover:`#334155`,rowHighlight:`#1e3a5f`,primaryKey:`#d69e2e`,foreignKey:`#4299e1`,edge:`#64748b`,edgeActive:`#60a5fa`};function pe(e){if(!e)return{};let t={};for(let n of Object.keys(e)){let r=e[n];r!=null&&(t[ue[n]]=r)}return t}var me=[],he={table:Z},ge={erd:ce};function _e(){return(0,i.jsxs)(`svg`,{viewBox:`0 0 24 24`,width:`100%`,height:`100%`,fill:`currentColor`,"aria-hidden":`true`,children:[(0,i.jsx)(`rect`,{x:`3`,y:`3`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`13`,y:`3`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`3`,y:`13`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`13`,y:`13`,width:`8`,height:`8`,rx:`1.5`})]})}function ve(e,t,n,r){let i=new Map;for(let a of e.tables){let e=t.get(a.id);i.set(a.id,n?.[a.id]??r?.get(a.id)??{x:e?.x??0,y:e?.y??0})}return i}function ye(e,t){if(e.length!==t.length)return!1;let n=new Set(e);return t.every(e=>n.has(e))}function be(e,t,n){return e.x<t.x+t.w+n&&e.x+e.w+n>t.x&&e.y<t.y+t.h+n&&e.y+e.h+n>t.y}function xe(e,t,n,r,i){let a=(e,t)=>({x:t.x,y:t.y,w:I(e,i),h:O(e)}),o=[];for(let r of e.tables)n(r.id)&&o.push(a(r,t.get(r.id)));for(let i of e.tables){if(n(i.id))continue;let e=t.get(i.id),s=a(i,e),c=0;for(;c++<1e3;){let t=o.filter(e=>be(s,e,r));if(t.length===0)break;let n=Math.max(...t.map(e=>e.y+e.h));e={x:e.x,y:n+r},s=a(i,e)}t.set(i.id,e),o.push(s)}}async function Se(e,t,n){try{return await U(e,t)}catch(r){return n(r instanceof H?r:new H(String(r),{cause:r})),z(e,t)}}function Ce(e,t,n){return e.tables.map(e=>({id:e.id,type:`table`,position:t.get(e.id)??{x:0,y:0},data:{table:e,widthBounds:n}}))}function we(e,t){return e.relations.map(e=>{let n=t.get(e.from.tableId),r=t.get(e.to.tableId),i=(n?.x??0)>(r?.x??0),a=i?`left`:`right`,o=i?`right`:`left`,s=e.from.columns[0]??``,c=e.to.columns[0]??``;return{id:e.id,source:e.from.tableId,target:e.to.tableId,sourceHandle:J(s,a,`source`),targetHandle:J(c,o,`target`),type:`erd`,data:{kind:e.kind,sourceEnd:{cardinality:e.from.relation,optional:e.from.optional},targetEnd:{cardinality:e.to.relation,optional:e.to.optional}}}})}var Te=(0,t.forwardRef)(function({dbml:e,className:r,style:a,theme:o,fitView:s=!0,showControls:c=!0,showMiniMap:l=!1,showBackground:u=!0,layoutOptions:d,onParseError:f,onLayoutError:p,nodePositions:m,onNodePositionsChange:h},_){let v=(0,t.useMemo)(()=>{try{return{ok:!0,schema:S(e)}}catch(e){return{ok:!1,error:e instanceof g?e:new g(String(e),{cause:e})}}},[e]),[y,b,x]=(0,n.useNodesState)([]),[C,w,T]=(0,n.useEdgesState)([]),E=(0,t.useRef)(null),D=(0,t.useRef)(null),O=(0,t.useRef)(y);O.current=y,(0,t.useImperativeHandle)(_,()=>{let e=async e=>{let t=E.current,r=D.current?.querySelector(`.react-flow__viewport`);if(!t||!r)throw new W(`The diagram is not ready to export yet.`);let i=te((0,n.getNodesBounds)(t.getNodes()),r),a=e?.backgroundColor??(D.current?getComputedStyle(D.current).backgroundColor:void 0);return G(r,i,{...e,backgroundColor:a})};return{toDataUrl:e,download:async(t,n)=>{q(await e(n),t)},fitView:e=>E.current?.fitView(e),zoomIn:e=>E.current?.zoomIn(e),zoomOut:e=>E.current?.zoomOut(e),zoomTo:(e,t)=>E.current?.zoomTo(e,t),setCenter:(e,t,n)=>E.current?.setCenter(e,t,n),fitBounds:(e,t)=>E.current?.fitBounds(e,t),setViewport:(e,t)=>E.current?.setViewport(e,t),getViewport:()=>E.current?.getViewport()}},[]);let k=(0,t.useRef)(p);k.current=p;let A=(0,t.useRef)(h);A.current=h;let j=(0,t.useRef)(m);j.current=m;let M=(0,t.useCallback)(()=>{let e=A.current;if(!e)return;let t={};for(let e of O.current)t[e.id]={x:e.position.x,y:e.position.y};e(t)},[]),{algorithm:N=`simple`,direction:P=`LR`,horizontalGap:F,verticalGap:I,minNodeWidth:L,maxNodeWidth:R}=d??{},z=(0,t.useRef)(null),B=`${N}|${P}|${F}|${I}|${L}|${R}`,V=(0,t.useCallback)((e,t,n,r,i)=>{let a={minWidth:L,maxWidth:R},o=ve(e,r,i.saved,i.prior);if(i.prior){let t=i.prior,n=i.saved;xe(e,o,e=>t.has(e)||n?.[e]!==void 0,I??40,a)}if(b(Ce(e,o,a)),w(we(e,o)),z.current={ids:t,optionsKey:n},i.emit){let e={};o.forEach((t,n)=>{e[n]=t}),A.current?.(e)}i.fit&&requestAnimationFrame(()=>void E.current?.fitView())},[b,w,I,L,R]);(0,t.useEffect)(()=>{if(!v.ok){b([]),w([]),z.current=null;return}let e=v.schema,t={algorithm:N,direction:P,horizontalGap:F,verticalGap:I,minNodeWidth:L,maxNodeWidth:R},n=e.tables.map(e=>e.id),r=new Map(O.current.map(e=>[e.id,{x:e.position.x,y:e.position.y}])),i=z.current,a=n.every(e=>r.has(e));if(i&&i.optionsKey===B&&a&&ye(i.ids,n)){V(e,n,B,new Map,{prior:r});return}let o=i&&i.optionsKey===B?r:void 0,c=!1;return Se(e,t,e=>k.current?.(e)).then(t=>{c||V(e,n,B,t,{saved:j.current,prior:o,fit:s})}),()=>{c=!0}},[v,N,P,F,I,L,R,B,s,V,b,w]);let H=(0,t.useCallback)(()=>{if(!v.ok)return;let e=v.schema,t={algorithm:N,direction:P,horizontalGap:F,verticalGap:I,minNodeWidth:L,maxNodeWidth:R},n=e.tables.map(e=>e.id);Se(e,t,e=>k.current?.(e)).then(t=>{V(e,n,B,t,{emit:!0,fit:!0})})},[v,N,P,F,I,L,R,B,V]),U=(0,t.useCallback)(()=>{v.ok||f?.(v.error)},[v,f]);(0,t.useEffect)(U,[U]);let{displayNodes:ee,displayEdges:K,onEdgeMouseEnter:J,onEdgeMouseLeave:Y}=le(v.ok?v.schema.relations:me,y,C),X={width:`100%`,height:`100%`,...pe(o),...a};return v.ok?(0,i.jsx)(`div`,{ref:D,className:`dv-viewer${r?` ${r}`:``}`,style:X,children:(0,i.jsxs)(n.ReactFlow,{nodes:ee,edges:K,nodeTypes:he,edgeTypes:ge,onNodesChange:x,onEdgesChange:T,onEdgeMouseEnter:J,onEdgeMouseLeave:Y,onNodeDragStop:M,onInit:e=>{E.current=e},fitView:s,nodesConnectable:!1,elementsSelectable:!0,minZoom:.1,proOptions:{hideAttribution:!0},children:[u&&(0,i.jsx)(n.Background,{}),c&&(0,i.jsx)(n.Controls,{children:(0,i.jsx)(n.ControlButton,{onClick:H,title:`Auto layout`,"aria-label":`Auto layout`,children:(0,i.jsx)(_e,{})})}),l&&(0,i.jsx)(n.MiniMap,{pannable:!0,zoomable:!0})]})}):(0,i.jsx)(`div`,{className:`dv-error${r?` ${r}`:``}`,style:X,children:(0,i.jsx)(`pre`,{className:`dv-error__message`,children:v.error.message})})});e.DbmlParseError=g,e.DbmlViewer=Te,e.ErdEdge=ce,e.ExportError=W,e.HEADER_HEIGHT=E,e.LayoutError=H,e.MAX_NODE_WIDTH=w,e.MIN_NODE_WIDTH=C,e.NODE_WIDTH=T,e.ROW_HEIGHT=D,e.TableNode=Z,e.computeLayout=U,e.darkTheme=fe,e.downloadDataUrl=q,e.layoutSchema=z,e.lightTheme=de,e.parseDbml=S,e.renderDiagram=G,e.tableHeight=O,e.tableWidth=I,e.themeToCssVars=pe});
2
+ `)}`}function y(e){if(e)return typeof e==`string`?e:e.value??void 0}function b(e,t){return e&&e!==h?`${e}.${t}`:t}function x(e){let t=new Set;for(let n of e.fields)n.pk&&t.add(n.name);for(let n of e.indexes??[])if(n.pk)for(let e of n.columns??[])e.type===`column`&&e.value&&t.add(e.value);return t}function ee(e){let t;try{t=new m().parse(e,`dbmlv2`)}catch(e){let t=_(e);throw new g(v(t,e instanceof Error?e.message:String(e)),{cause:e,diagnostics:t})}let n=new Map;for(let e of t.schemas)for(let t of e.tables){let r=b(e.name,t.name),i=x(t),a=new Map;for(let e of t.fields){let t=i.has(e.name);a.set(e.name,{pk:t,notNull:t||!!e.not_null,note:y(e.note)})}n.set(r,a)}let r=e=>{let t=n.get(e.tableId);return!t||e.columns.length===0?!1:e.columns.every(e=>t.get(e)?.pk===!0)},i=e=>e.columns.some(t=>{let r=n.get(e.tableId)?.get(t);return r?!r.notNull&&!r.pk:!0}),a=e=>e.columns.some(t=>n.get(e.tableId)?.get(t)?.note?.toLowerCase().includes(`optional`)??!1),o=[],s=new Set;for(let e of t.schemas)for(let t of e.refs){if(t.endpoints.length!==2)continue;let[n,c]=t.endpoints.map(t=>({tableId:b(t.schemaName??e.name,t.tableName),columns:t.fieldNames,relation:t.relation})),l,u,d=n.relation===`*`;if(d!==(c.relation===`*`))l=d?n:c,u=d?c:n;else{let e=r(n),t=r(c);e&&!t?(l=c,u=n):(l=n,u=c)}let f=r(l),p=i(l);l.columns.forEach(e=>s.add(`${l.tableId}::${e}`)),o.push({id:`${l.tableId}.${l.columns.join(`-`)}__${u.tableId}.${u.columns.join(`-`)}`,kind:f?`identifying`:`non-identifying`,from:{...l,optional:a(l)?!0:void 0},to:{...u,optional:p}})}let c=[];for(let e of t.schemas){let t=e.name;for(let n of e.tables){let e=b(t,n.name),r=x(n),i=n.fields.map(t=>({name:t.name,type:t.type?.type_name??`unknown`,pk:r.has(t.name),notNull:r.has(t.name)||!!t.not_null,unique:!!t.unique,increment:!!t.increment,defaultValue:t.dbdefault?.value,note:y(t.note),isForeignKey:s.has(`${e}::${t.name}`)}));c.push({id:e,name:n.name,schema:t===h?void 0:t,note:y(n.note),headerColor:n.headerColor??void 0,columns:i})}}return{tables:c,relations:o}}var S=160,C=320,w=320,te=40,T=28;function E(e){return 40+Math.max(e.columns.length,1)*28}var D=24,O=8,k=24,A=12,ne=24,j=6.8,M=7.4;function N(e,t={}){let n=t.minWidth??160,r=t.maxWidth??320,i=ne+P(e)*M;for(let t of e.columns){let e=(t.pk||t.isForeignKey?k:0)+t.name.length*j,n=t.type.length*j+A;i=Math.max(i,D+e+O+n)}return Math.round(Math.min(r,Math.max(n,i)))}function P(e){return(e.schema?e.schema.length+1:0)+e.name.length}function F(e,t){let n=new Map;for(let t of e)n.set(t.id,0);let r=t.map(e=>[e.from.tableId,e.to.tableId]).filter(([e,t])=>e!==t&&n.has(e)&&n.has(t));for(let t=0;t<e.length;t++){let e=!1;for(let[t,i]of r){let r=n.get(t)+1;n.get(i)<r&&(n.set(i,r),e=!0)}if(!e)break}return n}function I(e,t={}){let n=t.horizontalGap??120,r=t.verticalGap??40,i={minWidth:t.minNodeWidth,maxWidth:t.maxNodeWidth},a=new Set;for(let t of e.relations)a.add(t.from.tableId),a.add(t.to.tableId);let o=e.tables.filter(e=>a.has(e.id)),s=e.tables.filter(e=>!a.has(e.id)),c=new Map,l=F(o,e.relations),u=new Map;for(let e of o){let t=l.get(e.id)??0,n=u.get(t);n||(n=[],u.set(t,n)),n.push(e)}let d=0,f=0,p=0;for(let e of[...u.keys()].sort((e,t)=>e-t)){let t=u.get(e).sort((e,t)=>e.name.localeCompare(t.name)),a=0,o=0;for(let e of t){let t=N(e,i),n=E(e);c.set(e.id,{x:p,y:o,width:t,height:n}),a=Math.max(a,t),o+=n+r}d=Math.max(d,p+a),f=Math.max(f,o-r),p+=a+n}if(s.length>0){let e=d>0?d:Math.ceil(Math.sqrt(s.length))*(320+n),t=0,a=f>0?f+r*2:0,o=0;for(let l of[...s].sort((e,t)=>e.name.localeCompare(t.name))){let s=N(l,i),u=E(l);t>0&&t+s>e&&(t=0,a+=o+r,o=0),c.set(l.id,{x:t,y:a,width:s,height:u}),t+=s+n,o=Math.max(o,u)}}return c}async function L(e,t={}){let n=await import(`@dagrejs/dagre`),r=t.horizontalGap??120,i=t.verticalGap??40,a={minWidth:t.minNodeWidth,maxWidth:t.maxNodeWidth},o=t.direction===`TB`?`TB`:`LR`,s=new n.graphlib.Graph;s.setGraph({rankdir:o,ranksep:r,nodesep:i}),s.setDefaultEdgeLabel(()=>({}));for(let t of e.tables)s.setNode(t.id,{width:N(t,a),height:E(t)});for(let t of e.relations)s.hasNode(t.from.tableId)&&s.hasNode(t.to.tableId)&&s.setEdge(t.from.tableId,t.to.tableId);n.layout(s);let c=new Map;for(let e of s.nodes()){let t=s.node(e);t&&c.set(e,{x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height})}return c}async function R(e,t={}){let n=new(await(import(`elkjs/lib/elk.bundled.js`))).default,r=t.horizontalGap??120,i=t.verticalGap??40,a={minWidth:t.minNodeWidth,maxWidth:t.maxNodeWidth},o={id:`root`,layoutOptions:{"elk.algorithm":`layered`,"elk.direction":t.direction===`TB`?`DOWN`:`RIGHT`,"elk.layered.spacing.nodeNodeBetweenLayers":String(r),"elk.spacing.nodeNode":String(i)},children:e.tables.map(e=>({id:e.id,width:N(e,a),height:E(e)})),edges:e.relations.map((e,t)=>({id:`e${t}`,sources:[e.from.tableId],targets:[e.to.tableId]}))},s=await n.layout(o),c=new Map;for(let e of s.children??[])c.set(e.id,{x:e.x??0,y:e.y??0,width:e.width??160,height:e.height??0});return c}var z=class extends Error{constructor(e,t){super(e,t),this.name=`LayoutError`}};async function B(e,t={}){let n=t.algorithm??`simple`;if(n===`simple`)return I(e,t);try{return n===`dagre`?await L(e,t):await R(e,t)}catch(e){throw new z(`"${n}" layout failed. Is the optional dependency "${n===`dagre`?`@dagrejs/dagre`:`elkjs`}" installed? (${e instanceof Error?e.message:String(e)})`,{cause:e})}}var V=[`--dv-canvas`,`--dv-bg`,`--dv-border`,`--dv-header-bg`,`--dv-header-fg`,`--dv-row-fg`,`--dv-type-fg`,`--dv-row-hover`,`--dv-row-highlight`,`--dv-pk`,`--dv-fk`,`--dv-null`,`--dv-edge`,`--dv-edge-active`,`--dv-font`],H=class extends Error{constructor(e,t){super(e,t),this.name=`ExportError`}};function re(e,t){let n=e.x,r=e.y,i=e.x+e.width,a=e.y+e.height;for(let e of t.querySelectorAll(`.dv-erd-edge`)){let t;try{t=e.getBBox()}catch{continue}t.width===0&&t.height===0||(n=Math.min(n,t.x),r=Math.min(r,t.y),i=Math.max(i,t.x+t.width),a=Math.max(a,t.y+t.height))}return{x:n,y:r,width:i-n,height:a-r}}async function U(e,t,n={}){let{type:r=`png`,padding:i=24,backgroundColor:a,pixelRatio:o=2}=n,s;try{s=await import(`html-to-image`)}catch(e){throw new H(`Export requires the optional dependency "html-to-image". Install it to enable PNG/SVG export.`,{cause:e})}if(typeof document<`u`&&document.fonts?.ready)try{await document.fonts.ready}catch{}let c=Math.ceil(t.width+i*2),l=Math.ceil(t.height+i*2),u=`translate(${-t.x+i}px, ${-t.y+i}px) scale(1)`,d={width:c,height:l,backgroundColor:a,style:{width:`${c}px`,height:`${l}px`,transform:u}},f=W(e,t,i);try{return r===`svg`?await s.toSvg(e,d):await s.toPng(e,{...d,pixelRatio:o})}catch(e){throw new H(`Failed to render diagram image: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{f()}}function W(e,t,n){let r=[],i=e.closest(`.dv-viewer`);if(i){let t=getComputedStyle(i);for(let n of V){let i=t.getPropertyValue(n);if(!i)continue;let a=e.style.getPropertyValue(n);e.style.setProperty(n,i),r.push(()=>{a?e.style.setProperty(n,a):e.style.removeProperty(n)})}}let a=`${Math.ceil(t.x+t.width+n)}px`,o=`${Math.ceil(t.y+t.height+n)}px`;for(let t of e.querySelectorAll(`.react-flow__edges svg`)){let{width:e,height:n}=t.style;t.style.width=a,t.style.height=o,r.push(()=>{t.style.width=e,t.style.height=n})}return()=>r.forEach(e=>e())}function G(e,t){let n=document.createElement(`a`);n.href=e,n.download=t,n.click()}function K(e,t,n){return`${e}__${t}__${n}`}var q=(0,t.createContext)(void 0),J=(0,t.createContext)(`column`);function Y(e){return 40+e*28+28/2}var X=4;function ie({column:e,top:t}){let r={top:t-X,opacity:0},a={top:t+X,opacity:0};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.Handle,{id:K(e,`left`,`target`),type:`target`,position:n.Position.Left,style:a,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:K(e,`left`,`source`),type:`source`,position:n.Position.Left,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:K(e,`right`,`target`),type:`target`,position:n.Position.Right,style:a,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:K(e,`right`,`source`),type:`source`,position:n.Position.Right,style:r,isConnectable:!1})]})}function Z({data:e}){let{table:r,highlightedColumns:a,widthBounds:o,connectedColumns:s}=e,c=(0,t.useContext)(q),l=(0,t.useContext)(J)===`floating`;return(0,i.jsxs)(`div`,{className:`dv-table`,style:{width:N(r,o)},children:[l&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.Handle,{type:`source`,position:n.Position.Right,style:{opacity:0},isConnectable:!1}),(0,i.jsx)(n.Handle,{type:`target`,position:n.Position.Left,style:{opacity:0},isConnectable:!1})]}),(0,i.jsxs)(`div`,{className:`dv-table__header`,style:r.headerColor?{background:r.headerColor,height:40}:{height:40},title:r.note,children:[r.schema&&(0,i.jsxs)(`span`,{className:`dv-table__schema`,children:[r.schema,`.`]}),(0,i.jsx)(`span`,{className:`dv-table__name`,title:r.name,children:r.name})]}),(0,i.jsx)(`div`,{className:`dv-table__body`,children:r.columns.map((e,t)=>{let n=a?.has(e.name);return(0,i.jsxs)(`div`,{className:`dv-row${n?` dv-row--highlighted`:``}`,style:{height:28},title:e.note,onMouseEnter:()=>c?.(r.id,e.name),onMouseLeave:()=>c?.(r.id,null),children:[(0,i.jsxs)(`span`,{className:`dv-row__name${e.pk?` dv-row__name--pk`:``}`,children:[e.pk&&(0,i.jsx)(`span`,{className:`dv-badge dv-badge--pk`,title:`Primary key`,children:`PK`}),e.isForeignKey&&!e.pk&&(0,i.jsx)(`span`,{className:`dv-badge dv-badge--fk`,title:`Foreign key`,children:`FK`}),(0,i.jsx)(`span`,{className:`dv-row__label`,title:e.name,children:e.name})]}),(0,i.jsxs)(`span`,{className:`dv-row__type`,children:[(0,i.jsx)(`span`,{className:`dv-row__typename`,title:e.type,children:e.type}),(0,i.jsx)(`span`,{className:`dv-row__null${e.notNull?` dv-row__null--notnull`:``}`,title:e.notNull?`Not null`:`Nullable`})]}),!l&&s?.has(e.name)&&(0,i.jsx)(ie,{column:e.name,top:Y(t)})]},e.name)})})]})}var ae=(0,t.memo)(Z),oe=8,Q=13,se=7,ce=13,le=16,ue={[n.Position.Right]:0,[n.Position.Left]:180,[n.Position.Top]:-90,[n.Position.Bottom]:90};function de(e,t,n,r,a,o){let s=[],c={stroke:a,strokeWidth:o},l=(e,t)=>s.push((0,i.jsx)(`line`,{x1:e,y1:-8,x2:e,y2:oe,style:c},t)),u=(e,t)=>s.push((0,i.jsx)(`circle`,{cx:e,cy:0,r:4,style:{stroke:a,strokeWidth:o,fill:`var(--dv-bg)`}},t));return r.cardinality===`*`?(s.push((0,i.jsx)(`line`,{x1:Q,y1:0,x2:0,y2:-8,style:c},`cf1`),(0,i.jsx)(`line`,{x1:Q,y1:0,x2:0,y2:0,style:c},`cf2`),(0,i.jsx)(`line`,{x1:Q,y1:0,x2:0,y2:oe,style:c},`cf3`)),r.optional===!0?u(17,`fr`):l(14,`fb`)):(l(se,`b1`),r.optional===!0?u(le,`r`):r.optional===!1&&l(ce,`b2`)),(0,i.jsx)(`g`,{className:`dv-erd-marker`,transform:`translate(${e}, ${t}) rotate(${ue[n]})`,children:s})}function fe(e,t,n,r,a,o,s,c,l){let u=t?.kind===`non-identifying`,d=n?`var(--dv-edge-active)`:`var(--dv-edge)`,f=n?2:1.5;return(0,i.jsxs)(`g`,{className:`dv-erd-edge${n?` dv-erd-edge--active`:``}`,children:[(0,i.jsx)(`path`,{className:`dv-erd-edge__interaction`,d:e,fill:`none`}),(0,i.jsx)(`path`,{className:`dv-erd-edge__path`,d:e,fill:`none`,style:{stroke:d,strokeWidth:f},strokeDasharray:u?`6 4`:void 0}),t&&de(r,a,o,t.sourceEnd,d,f),t&&de(s,c,l,t.targetEnd,d,f)]})}function pe({sourceX:e,sourceY:t,targetX:r,targetY:i,sourcePosition:a,targetPosition:o,data:s,selected:c}){let[l]=(0,n.getSmoothStepPath)({sourceX:e,sourceY:t,sourcePosition:a,targetX:r,targetY:i,targetPosition:o,borderRadius:8}),u=s;return fe(l,u,!!(c||u?.hovered),e,t,a,r,i,o)}var me=(0,t.memo)(pe);function $(e){let t=e.measured?.width??0,n=e.measured?.height??0,{x:r,y:i}=e.internals.positionAbsolute;return{x:r,y:i,w:t,h:n,cx:r+t/2,cy:i+n/2}}function he(e,t){let n=$(e),r=$(t),i=n.w/2,a=n.h/2,o=(r.cx-n.cx)/(2*i)-(r.cy-n.cy)/(2*a),s=(r.cx-n.cx)/(2*i)+(r.cy-n.cy)/(2*a),c=1/(Math.abs(o)+Math.abs(s)||1);return{x:i*c*(o+s)+n.cx,y:a*c*(-o+s)+n.cy}}function ge(e,t){let r=$(e),i=Math.round(t.x),a=Math.round(t.y);return i<=Math.round(r.x)+1?n.Position.Left:i>=Math.round(r.x+r.w)-1?n.Position.Right:a<=Math.round(r.y)+1?n.Position.Top:n.Position.Bottom}var _e=14;function ve({id:e,source:t,target:r,data:i,selected:a}){let o=(0,n.useInternalNode)(t),s=(0,n.useInternalNode)(r);if(!o||!s)return null;let c=i,l=!!(a||c?.hovered),u,d,f,p,m,h;if(t===r){let e=$(o);u=f=e.x+e.w,d=e.cy-_e,p=e.cy+_e,m=h=n.Position.Right}else{let e=he(o,s),t=he(s,o);u=e.x,d=e.y,f=t.x,p=t.y,m=ge(o,e),h=ge(s,t)}let[g]=(0,n.getBezierPath)({sourceX:u,sourceY:d,sourcePosition:m,targetX:f,targetY:p,targetPosition:h});return fe(g,c,l,u,d,m,f,p,h)}var ye=(0,t.memo)(ve);function be(e,n,r){let[i,a]=(0,t.useState)(null),[o,s]=(0,t.useState)(null),c=(0,t.useMemo)(()=>{let t=new Map;for(let n of e)t.set(n.id,n);return t},[e]),l=(0,t.useMemo)(()=>{let t=new Set;if(i&&t.add(i),o)for(let n of e){let e=e=>e.tableId===o.tableId&&e.columns.includes(o.column);(e(n.from)||e(n.to))&&t.add(n.id)}return t},[i,o,e]),u=(0,t.useMemo)(()=>{let e=new Map;for(let t of l){let n=c.get(t);if(n)for(let t of[n.from,n.to]){let n=e.get(t.tableId)??new Set;t.columns.forEach(e=>n.add(e)),e.set(t.tableId,n)}}return e},[l,c]),d=(0,t.useCallback)((e,t)=>{s(t?{tableId:e,column:t}:null)},[]);return{displayNodes:(0,t.useMemo)(()=>l.size===0?n:n.map(e=>{let t=u.get(e.id);return t?{...e,data:{...e.data,highlightedColumns:t}}:e}),[n,l,u]),displayEdges:(0,t.useMemo)(()=>l.size===0?r:r.map(e=>l.has(e.id)?{...e,data:{...e.data,hovered:!0},zIndex:1}:e),[r,l]),onEdgeMouseEnter:(0,t.useCallback)((e,t)=>a(t.id),[]),onEdgeMouseLeave:(0,t.useCallback)(()=>a(null),[]),onColumnHover:d}}var xe={canvas:`--dv-canvas`,background:`--dv-bg`,border:`--dv-border`,headerBackground:`--dv-header-bg`,headerForeground:`--dv-header-fg`,rowForeground:`--dv-row-fg`,typeForeground:`--dv-type-fg`,rowHover:`--dv-row-hover`,rowHighlight:`--dv-row-highlight`,primaryKey:`--dv-pk`,foreignKey:`--dv-fk`,edge:`--dv-edge`,edgeActive:`--dv-edge-active`,fontFamily:`--dv-font`},Se={canvas:`#fafbfc`,background:`#ffffff`,border:`#d9dee5`,headerBackground:`#2d3748`,headerForeground:`#ffffff`,rowForeground:`#1a202c`,typeForeground:`#718096`,rowHover:`#f1f5f9`,rowHighlight:`#dbeafe`,primaryKey:`#b7791f`,foreignKey:`#2b6cb0`,edge:`#94a3b8`,edgeActive:`#2b6cb0`},Ce={canvas:`#0f172a`,background:`#1e293b`,border:`#334155`,headerBackground:`#334155`,headerForeground:`#f1f5f9`,rowForeground:`#e2e8f0`,typeForeground:`#94a3b8`,rowHover:`#334155`,rowHighlight:`#1e3a5f`,primaryKey:`#d69e2e`,foreignKey:`#4299e1`,edge:`#64748b`,edgeActive:`#60a5fa`};function we(e){if(!e)return{};let t={};for(let n of Object.keys(e)){let r=e[n];r!=null&&(t[xe[n]]=r)}return t}var Te=[],Ee={table:ae},De={erd:me,"erd-floating":ye};function Oe(){return(0,i.jsxs)(`svg`,{viewBox:`0 0 24 24`,width:`100%`,height:`100%`,fill:`currentColor`,"aria-hidden":`true`,children:[(0,i.jsx)(`rect`,{x:`3`,y:`3`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`13`,y:`3`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`3`,y:`13`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`13`,y:`13`,width:`8`,height:`8`,rx:`1.5`})]})}function ke(e,t,n,r){let i=new Map;for(let a of e.tables){let e=t.get(a.id);i.set(a.id,n?.[a.id]??r?.get(a.id)??{x:e?.x??0,y:e?.y??0})}return i}function Ae(e,t){if(e.length!==t.length)return!1;let n=new Set(e);return t.every(e=>n.has(e))}function je(e,t,n){return e.x<t.x+t.w+n&&e.x+e.w+n>t.x&&e.y<t.y+t.h+n&&e.y+e.h+n>t.y}function Me(e,t,n,r,i){let a=(e,t)=>({x:t.x,y:t.y,w:N(e,i),h:E(e)}),o=[];for(let r of e.tables)n(r.id)&&o.push(a(r,t.get(r.id)));for(let i of e.tables){if(n(i.id))continue;let e=t.get(i.id),s=a(i,e),c=0;for(;c++<1e3;){let t=o.filter(e=>je(s,e,r));if(t.length===0)break;let n=Math.max(...t.map(e=>e.y+e.h));e={x:e.x,y:n+r},s=a(i,e)}t.set(i.id,e),o.push(s)}}async function Ne(e,t,n){try{return await B(e,t)}catch(r){return n(r instanceof z?r:new z(String(r),{cause:r})),I(e,t)}}function Pe(e){let t=new Map,n=(e,n)=>{if(!n)return;let r=t.get(e);r||(r=new Set,t.set(e,r)),r.add(n)};for(let t of e.relations)t.from.columns.forEach(e=>n(t.from.tableId,e)),t.to.columns.forEach(e=>n(t.to.tableId,e));return t}function Fe(e,t,n,r){return e.tables.map(e=>({id:e.id,type:`table`,position:t.get(e.id)??{x:0,y:0},data:{table:e,widthBounds:n,connectedColumns:r.get(e.id)}}))}function Ie(e,t){let n=e.from.tableId===e.to.tableId,r=n?!1:(t.get(e.from.tableId)?.x??0)>(t.get(e.to.tableId)?.x??0),i=r?`left`:`right`,a=n||r?`right`:`left`;return{sourceHandle:K(e.from.columns[0]??``,i,`source`),targetHandle:K(e.to.columns[0]??``,a,`target`)}}function Le(e,t,n){let r=n===`floating`;return e.relations.map(e=>{let n=r?{sourceHandle:void 0,targetHandle:void 0}:Ie(e,t);return{id:e.id,source:e.from.tableId,target:e.to.tableId,...n,type:r?`erd-floating`:`erd`,data:{kind:e.kind,sourceEnd:{cardinality:e.from.relation,optional:e.from.optional},targetEnd:{cardinality:e.to.relation,optional:e.to.optional}}}})}var Re=(0,t.forwardRef)(function({dbml:e,className:r,style:a,theme:o,fitView:s=!0,showControls:c=!0,showMiniMap:l=!1,showBackground:u=!0,layoutOptions:d,edgeConnection:f=`column`,onParseError:p,onLayoutError:m,nodePositions:h,onNodePositionsChange:_},v){let y=(0,t.useMemo)(()=>{try{return{ok:!0,schema:ee(e)}}catch(e){return{ok:!1,error:e instanceof g?e:new g(String(e),{cause:e})}}},[e]),[b,x,S]=(0,n.useNodesState)([]),[C,w,te]=(0,n.useEdgesState)([]),T=(0,t.useRef)(null),E=(0,t.useRef)(null),D=(0,t.useRef)(b);D.current=b,(0,t.useImperativeHandle)(v,()=>{let e=async e=>{let t=T.current,r=E.current?.querySelector(`.react-flow__viewport`);if(!t||!r)throw new H(`The diagram is not ready to export yet.`);let i=re((0,n.getNodesBounds)(t.getNodes()),r),a=e?.backgroundColor??(E.current?getComputedStyle(E.current).backgroundColor:void 0);return U(r,i,{...e,backgroundColor:a})};return{toDataUrl:e,download:async(t,n)=>{G(await e(n),t)},fitView:e=>T.current?.fitView(e),zoomIn:e=>T.current?.zoomIn(e),zoomOut:e=>T.current?.zoomOut(e),zoomTo:(e,t)=>T.current?.zoomTo(e,t),setCenter:(e,t,n)=>T.current?.setCenter(e,t,n),fitBounds:(e,t)=>T.current?.fitBounds(e,t),setViewport:(e,t)=>T.current?.setViewport(e,t),getViewport:()=>T.current?.getViewport()}},[]);let O=(0,t.useRef)(m);O.current=m;let k=(0,t.useRef)(_);k.current=_;let A=(0,t.useRef)(h);A.current=h;let ne=(0,t.useCallback)(()=>{let e=k.current;if(!e)return;let t={};for(let e of D.current)t[e.id]={x:e.position.x,y:e.position.y};e(t)},[]),{algorithm:j=`simple`,direction:M=`LR`,horizontalGap:N,verticalGap:P,minNodeWidth:F,maxNodeWidth:I}=d??{},L=(0,t.useRef)(null),R=`${j}|${M}|${N}|${P}|${F}|${I}`,z=(0,t.useCallback)((e,t,n,r,i)=>{let a={minWidth:F,maxWidth:I},o=ke(e,r,i.saved,i.prior);if(i.prior){let t=i.prior,n=i.saved;Me(e,o,e=>t.has(e)||n?.[e]!==void 0,P??40,a)}if(x(Fe(e,o,a,Pe(e))),w(Le(e,o,f)),L.current={ids:t,optionsKey:n},i.emit){let e={};o.forEach((t,n)=>{e[n]=t}),k.current?.(e)}i.fit&&requestAnimationFrame(()=>void T.current?.fitView())},[x,w,P,F,I,f]);(0,t.useEffect)(()=>{if(!y.ok){x([]),w([]),L.current=null;return}let e=y.schema,t={algorithm:j,direction:M,horizontalGap:N,verticalGap:P,minNodeWidth:F,maxNodeWidth:I},n=e.tables.map(e=>e.id),r=new Map(D.current.map(e=>[e.id,{x:e.position.x,y:e.position.y}])),i=L.current,a=n.every(e=>r.has(e));if(i&&i.optionsKey===R&&a&&Ae(i.ids,n)){z(e,n,R,new Map,{prior:r});return}let o=i&&i.optionsKey===R?r:void 0,c=!1;return Ne(e,t,e=>O.current?.(e)).then(t=>{c||z(e,n,R,t,{saved:A.current,prior:o,fit:s})}),()=>{c=!0}},[y,j,M,N,P,F,I,R,s,z,x,w]);let B=(0,t.useCallback)(()=>{if(!y.ok)return;let e=y.schema,t={algorithm:j,direction:M,horizontalGap:N,verticalGap:P,minNodeWidth:F,maxNodeWidth:I},n=e.tables.map(e=>e.id);Ne(e,t,e=>O.current?.(e)).then(t=>{z(e,n,R,t,{emit:!0,fit:!0})})},[y,j,M,N,P,F,I,R,z]),V=(0,t.useCallback)(()=>{y.ok||p?.(y.error)},[y,p]);(0,t.useEffect)(V,[V]);let{displayNodes:W,displayEdges:K,onEdgeMouseEnter:Y,onEdgeMouseLeave:X,onColumnHover:ie}=be(y.ok?y.schema.relations:Te,b,C),Z={width:`100%`,height:`100%`,...we(o),...a};return y.ok?(0,i.jsx)(`div`,{ref:E,className:`dv-viewer${r?` ${r}`:``}`,style:Z,children:(0,i.jsx)(J.Provider,{value:f,children:(0,i.jsx)(q.Provider,{value:ie,children:(0,i.jsxs)(n.ReactFlow,{nodes:W,edges:K,nodeTypes:Ee,edgeTypes:De,onNodesChange:S,onEdgesChange:te,onEdgeMouseEnter:Y,onEdgeMouseLeave:X,onNodeDragStop:ne,onInit:e=>{T.current=e},fitView:s,nodesConnectable:!1,elementsSelectable:!0,minZoom:.1,proOptions:{hideAttribution:!0},children:[u&&(0,i.jsx)(n.Background,{}),c&&(0,i.jsx)(n.Controls,{children:(0,i.jsx)(n.ControlButton,{onClick:B,title:`Auto layout`,"aria-label":`Auto layout`,children:(0,i.jsx)(Oe,{})})}),l&&(0,i.jsx)(n.MiniMap,{pannable:!0,zoomable:!0})]})})})}):(0,i.jsx)(`div`,{className:`dv-error${r?` ${r}`:``}`,style:Z,children:(0,i.jsx)(`pre`,{className:`dv-error__message`,children:y.error.message})})});e.DbmlParseError=g,e.DbmlViewer=Re,e.ErdEdge=me,e.ExportError=H,e.HEADER_HEIGHT=te,e.LayoutError=z,e.MAX_NODE_WIDTH=C,e.MIN_NODE_WIDTH=S,e.NODE_WIDTH=w,e.ROW_HEIGHT=T,e.TableNode=ae,e.computeLayout=B,e.darkTheme=Ce,e.downloadDataUrl=G,e.layoutSchema=I,e.lightTheme=Se,e.parseDbml=ee,e.renderDiagram=U,e.tableHeight=E,e.tableWidth=N,e.themeToCssVars=we});
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ import { JSX } from 'react';
6
6
  import { MemoExoticComponent } from 'react';
7
7
  import { Node as Node_2 } from '@xyflow/react';
8
8
  import { NodeProps } from '@xyflow/react';
9
+ import { ReactNode } from 'react';
9
10
  import { Rect } from '@xyflow/react';
10
11
  import { RefAttributes } from 'react';
11
12
  import { SetCenterOptions } from '@xyflow/react';
@@ -127,6 +128,12 @@ export declare interface DbmlViewerProps {
127
128
  showBackground?: boolean;
128
129
  /** Layout tuning: algorithm (`'simple'` | `'dagre'` | `'elk'`), direction, gaps. */
129
130
  layoutOptions?: LayoutOptions;
131
+ /**
132
+ * How edges attach to tables. `'column'` (default) anchors each edge to its specific
133
+ * FK/PK column rows. `'floating'` connects table-to-table, attaching wherever the two
134
+ * tables face each other and following them as they move.
135
+ */
136
+ edgeConnection?: EdgeConnection;
130
137
  /** Called when the DBML fails to parse. */
131
138
  onParseError?: (error: DbmlParseError) => void;
132
139
  /** Called when a non-default layout fails (e.g. optional dependency missing). */
@@ -191,6 +198,9 @@ export declare interface DiagramExportOptions {
191
198
  /** Trigger a browser download of a data URL. */
192
199
  export declare function downloadDataUrl(dataUrl: string, filename: string): void;
193
200
 
201
+ /** How edges attach to tables. */
202
+ export declare type EdgeConnection = 'column' | 'floating';
203
+
194
204
  /** Cardinality + optionality of one rendered edge end. */
195
205
  export declare interface EdgeEndSpec {
196
206
  cardinality: Cardinality;
@@ -200,7 +210,11 @@ export declare interface EdgeEndSpec {
200
210
 
201
211
  export declare const ErdEdge: MemoExoticComponent<typeof ErdEdgeComponent>;
202
212
 
203
- declare function ErdEdgeComponent({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, selected, }: EdgeProps): JSX.Element;
213
+ /**
214
+ * Column-anchored edge: endpoints are fixed to per-column handles on the left/right of each
215
+ * table (the default rendering). React Flow supplies the resolved handle coordinates.
216
+ */
217
+ declare function ErdEdgeComponent({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, selected, }: EdgeProps): ReactNode;
204
218
 
205
219
  export declare interface ErdEdgeData {
206
220
  kind: RelationKind;
@@ -265,8 +279,11 @@ export declare interface LayoutOptions {
265
279
  /**
266
280
  * Compute node positions for the parsed schema.
267
281
  *
268
- * Tables are arranged left-to-right by their layer in the FK graph and stacked
269
- * vertically within each layer. The result is keyed by {@link TableInfo.id}.
282
+ * FK-connected tables are arranged left-to-right by their layer in the FK graph and stacked
283
+ * vertically within each layer. Tables with no relations at all are packed into a grid below
284
+ * that layout — filled left-to-right then wrapped — spanning roughly its width, so a large
285
+ * number of unrelated tables no longer pile up in a single tall left-hand column. The result
286
+ * is keyed by {@link TableInfo.id}.
270
287
  */
271
288
  export declare function layoutSchema(schema: ParsedSchema, options?: LayoutOptions): Map<string, NodeBox>;
272
289
 
@@ -397,6 +414,8 @@ export declare type TableNodeData = {
397
414
  highlightedColumns?: Set<string>;
398
415
  /** Min/max width bounds; must match what layout used so render and layout agree. */
399
416
  widthBounds?: NodeWidthBounds;
417
+ /** Columns that an edge attaches to; only these get connection handles. */
418
+ connectedColumns?: Set<string>;
400
419
  };
401
420
 
402
421
  export declare type TableNodeType = Node_2<TableNodeData, 'table'>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbml-erd-viewer",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "React component library that renders DBML database schemas as an interactive diagram.",
5
5
  "keywords": [
6
6
  "database",