dbml-erd-viewer 0.1.0 → 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.
- package/LICENSE +21 -21
- package/README.md +377 -329
- package/dist/dbml-erd-viewer.css +1 -1
- package/dist/dbml-erd-viewer.js +603 -378
- package/dist/dbml-erd-viewer.umd.cjs +1 -1
- package/dist/index.d.ts +84 -4
- package/package.json +1 -1
|
@@ -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=240,w=40,T=28;function E(e){return 40+Math.max(e.columns.length,1)*28}function D(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 O(e,t={}){let n=t.horizontalGap??120,r=t.verticalGap??40,i=D(e),a=new Map;for(let t of e.tables){let e=i.get(t.id)??0,n=a.get(e);n||(n=[],a.set(e,n)),n.push(t)}let o=new Map;return[...a.keys()].sort((e,t)=>e-t).forEach((e,t)=>{let i=a.get(e).sort((e,t)=>e.name.localeCompare(t.name)),s=t*(240+n),c=0;for(let e of i){let t=E(e);o.set(e.id,{x:s,y:c,width:240,height:t}),c+=t+r}}),o}async function k(e,t={}){let n=await import(`@dagrejs/dagre`),r=t.horizontalGap??120,i=t.verticalGap??40,a=t.direction===`TB`?`TB`:`LR`,o=new n.graphlib.Graph;o.setGraph({rankdir:a,ranksep:r,nodesep:i}),o.setDefaultEdgeLabel(()=>({}));for(let t of e.tables)o.setNode(t.id,{width:240,height:E(t)});for(let t of e.relations)o.hasNode(t.from.tableId)&&o.hasNode(t.to.tableId)&&o.setEdge(t.from.tableId,t.to.tableId);n.layout(o);let s=new Map;for(let e of o.nodes()){let t=o.node(e);t&&s.set(e,{x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height})}return s}async function A(e,t={}){let n=new(await(import(`elkjs/lib/elk.bundled.js`))).default,r=t.horizontalGap??120,i=t.verticalGap??40,a={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:240,height:E(e)})),edges:e.relations.map((e,t)=>({id:`e${t}`,sources:[e.from.tableId],targets:[e.to.tableId]}))},o=await n.layout(a),s=new Map;for(let e of o.children??[])s.set(e.id,{x:e.x??0,y:e.y??0,width:e.width??240,height:e.height??0});return s}var j=class extends Error{constructor(e,t){super(e,t),this.name=`LayoutError`}};async function M(e,t={}){let n=t.algorithm??`simple`;if(n===`simple`)return O(e,t);try{return n===`dagre`?await k(e,t):await A(e,t)}catch(e){throw new j(`"${n}" layout failed. Is the optional dependency "${n===`dagre`?`@dagrejs/dagre`:`elkjs`}" installed? (${e instanceof Error?e.message:String(e)})`,{cause:e})}}var N=[`--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`],P=class extends Error{constructor(e,t){super(e,t),this.name=`ExportError`}};function F(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 I(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 P(`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=L(e,t,i);try{return r===`svg`?await s.toSvg(e,d):await s.toPng(e,{...d,pixelRatio:o})}catch(e){throw new P(`Failed to render diagram image: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{f()}}function L(e,t,n){let r=[],i=e.closest(`.dv-viewer`);if(i){let t=getComputedStyle(i);for(let n of N){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 R(e,t){let n=document.createElement(`a`);n.href=e,n.download=t,n.click()}function z(e,t,n){return`${e}__${t}__${n}`}function B(e){return 40+e*28+28/2}function V({column:e,top:t}){let r={top:t,opacity:0};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.Handle,{id:z(e,`left`,`target`),type:`target`,position:n.Position.Left,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:z(e,`left`,`source`),type:`source`,position:n.Position.Left,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:z(e,`right`,`target`),type:`target`,position:n.Position.Right,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:z(e,`right`,`source`),type:`source`,position:n.Position.Right,style:r,isConnectable:!1})]})}function H({data:e}){let{table:t,highlightedColumns:n}=e;return(0,i.jsxs)(`div`,{className:`dv-table`,style:{width:240},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`,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`}),e.name]}),(0,i.jsxs)(`span`,{className:`dv-row__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)(V,{column:e.name,top:B(t)})]},e.name)})})]})}var U=(0,t.memo)(H),W=8,G=13,K=7,q=13,J=16;function Y(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-W,x2:e+c*n,y2:t+W,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*G;l.push((0,i.jsx)(`line`,{x1:n,y1:t,x2:e,y2:t-W,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+W,style:u},`cf3`)),a.optional===!0?f(17,`fr`):d(14,`fb`)}else d(K,`b1`),a.optional===!0?f(J,`r`):a.optional===!1&&d(q,`b2`);return(0,i.jsx)(`g`,{className:`dv-erd-marker`,children:l})}function X({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&&Y(e,t,o,d.sourceEnd,m,h),d&&Y(r,a,s,d.targetEnd,m,h)]})}var Z=(0,t.memo)(X);function ee(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 te={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`},ne={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`},re={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 Q(e){if(!e)return{};let t={};for(let n of Object.keys(e)){let r=e[n];r!=null&&(t[te[n]]=r)}return t}var ie=[],ae={table:U},oe={erd:Z};function se(){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 ce(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 le(e,t){if(e.length!==t.length)return!1;let n=new Set(e);return t.every(e=>n.has(e))}async function $(e,t,n){try{return await M(e,t)}catch(r){return n(r instanceof j?r:new j(String(r),{cause:r})),O(e,t)}}function ue(e,t){return e.tables.map(e=>({id:e.id,type:`table`,position:t.get(e.id)??{x:0,y:0},data:{table:e}}))}function de(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:z(s,a,`source`),targetHandle:z(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 fe=(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 P(`The diagram is not ready to export yet.`);let i=F((0,n.getNodesBounds)(t.getNodes()),r),a=e?.backgroundColor??(D.current?getComputedStyle(D.current).backgroundColor:void 0);return I(r,i,{...e,backgroundColor:a})};return{toDataUrl:e,download:async(t,n)=>{R(await e(n),t)}}},[]);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:L=`LR`,horizontalGap:z,verticalGap:B}=d??{},V=(0,t.useRef)(null),H=`${N}|${L}|${z}|${B}`,U=(0,t.useCallback)((e,t,n,r,i)=>{let a=ce(e,r,i.saved,i.prior);if(b(ue(e,a)),w(de(e,a)),V.current={ids:t,optionsKey:n},i.emit){let e={};a.forEach((t,n)=>{e[n]=t}),A.current?.(e)}i.fit&&requestAnimationFrame(()=>void E.current?.fitView())},[b,w]);(0,t.useEffect)(()=>{if(!v.ok){b([]),w([]),V.current=null;return}let e=v.schema,t={algorithm:N,direction:L,horizontalGap:z,verticalGap:B},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=V.current,a=n.every(e=>r.has(e));if(i&&i.optionsKey===H&&a&&le(i.ids,n)){U(e,n,H,new Map,{prior:r});return}let o=i&&i.optionsKey===H?r:void 0,c=!1;return $(e,t,e=>k.current?.(e)).then(t=>{c||U(e,n,H,t,{saved:j.current,prior:o,fit:s})}),()=>{c=!0}},[v,N,L,z,B,H,s,U,b,w]);let W=(0,t.useCallback)(()=>{if(!v.ok)return;let e=v.schema,t={algorithm:N,direction:L,horizontalGap:z,verticalGap:B},n=e.tables.map(e=>e.id);$(e,t,e=>k.current?.(e)).then(t=>{U(e,n,H,t,{emit:!0,fit:!0})})},[v,N,L,z,B,H,U]),G=(0,t.useCallback)(()=>{v.ok||f?.(v.error)},[v,f]);(0,t.useEffect)(G,[G]);let{displayNodes:K,displayEdges:q,onEdgeMouseEnter:J,onEdgeMouseLeave:Y}=ee(v.ok?v.schema.relations:ie,y,C),X={width:`100%`,height:`100%`,...Q(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:K,edges:q,nodeTypes:ae,edgeTypes:oe,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:W,title:`Auto layout`,"aria-label":`Auto layout`,children:(0,i.jsx)(se,{})})}),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=fe,e.ErdEdge=Z,e.ExportError=P,e.HEADER_HEIGHT=w,e.LayoutError=j,e.NODE_WIDTH=C,e.ROW_HEIGHT=T,e.TableNode=U,e.computeLayout=M,e.darkTheme=re,e.downloadDataUrl=R,e.layoutSchema=O,e.lightTheme=ne,e.parseDbml=S,e.renderDiagram=I,e.tableHeight=E,e.themeToCssVars=Q});
|
|
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
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { CSSProperties } from 'react';
|
|
2
2
|
import { EdgeProps } from '@xyflow/react';
|
|
3
|
+
import { FitViewOptions } from '@xyflow/react';
|
|
3
4
|
import { ForwardRefExoticComponent } from 'react';
|
|
4
5
|
import { JSX } from 'react';
|
|
5
6
|
import { MemoExoticComponent } from 'react';
|
|
6
7
|
import { Node as Node_2 } from '@xyflow/react';
|
|
7
8
|
import { NodeProps } from '@xyflow/react';
|
|
9
|
+
import { ReactNode } from 'react';
|
|
8
10
|
import { Rect } from '@xyflow/react';
|
|
9
11
|
import { RefAttributes } from 'react';
|
|
12
|
+
import { SetCenterOptions } from '@xyflow/react';
|
|
13
|
+
import { Viewport } from '@xyflow/react';
|
|
14
|
+
import { ViewportHelperFunctionOptions } from '@xyflow/react';
|
|
10
15
|
|
|
11
16
|
/** Cardinality of one side of a relation. `'1'` = one, `'*'` = many. */
|
|
12
17
|
export declare type Cardinality = '1' | '*';
|
|
@@ -86,6 +91,22 @@ export declare interface DbmlViewerHandle {
|
|
|
86
91
|
toDataUrl(options?: DiagramExportOptions): Promise<string>;
|
|
87
92
|
/** Render the diagram and trigger a browser download. */
|
|
88
93
|
download(filename: string, options?: DiagramExportOptions): Promise<void>;
|
|
94
|
+
/** Fit the whole diagram into the viewport. */
|
|
95
|
+
fitView(options?: FitViewOptions): void;
|
|
96
|
+
/** Zoom in by one step. */
|
|
97
|
+
zoomIn(options?: ViewportHelperFunctionOptions): void;
|
|
98
|
+
/** Zoom out by one step. */
|
|
99
|
+
zoomOut(options?: ViewportHelperFunctionOptions): void;
|
|
100
|
+
/** Zoom to a specific level (e.g. `1` = 100%). */
|
|
101
|
+
zoomTo(zoomLevel: number, options?: ViewportHelperFunctionOptions): void;
|
|
102
|
+
/** Center the viewport on a flow-coordinate point. */
|
|
103
|
+
setCenter(x: number, y: number, options?: SetCenterOptions): void;
|
|
104
|
+
/** Fit a specific flow-coordinate rectangle into the viewport. */
|
|
105
|
+
fitBounds(bounds: Rect, options?: ViewportHelperFunctionOptions): void;
|
|
106
|
+
/** Set the viewport position and zoom directly. */
|
|
107
|
+
setViewport(viewport: Viewport, options?: ViewportHelperFunctionOptions): void;
|
|
108
|
+
/** Read the current viewport (`{ x, y, zoom }`); returns `undefined` before the diagram mounts. */
|
|
109
|
+
getViewport(): Viewport | undefined;
|
|
89
110
|
}
|
|
90
111
|
|
|
91
112
|
export declare interface DbmlViewerProps {
|
|
@@ -107,6 +128,12 @@ export declare interface DbmlViewerProps {
|
|
|
107
128
|
showBackground?: boolean;
|
|
108
129
|
/** Layout tuning: algorithm (`'simple'` | `'dagre'` | `'elk'`), direction, gaps. */
|
|
109
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;
|
|
110
137
|
/** Called when the DBML fails to parse. */
|
|
111
138
|
onParseError?: (error: DbmlParseError) => void;
|
|
112
139
|
/** Called when a non-default layout fails (e.g. optional dependency missing). */
|
|
@@ -171,6 +198,9 @@ export declare interface DiagramExportOptions {
|
|
|
171
198
|
/** Trigger a browser download of a data URL. */
|
|
172
199
|
export declare function downloadDataUrl(dataUrl: string, filename: string): void;
|
|
173
200
|
|
|
201
|
+
/** How edges attach to tables. */
|
|
202
|
+
export declare type EdgeConnection = 'column' | 'floating';
|
|
203
|
+
|
|
174
204
|
/** Cardinality + optionality of one rendered edge end. */
|
|
175
205
|
export declare interface EdgeEndSpec {
|
|
176
206
|
cardinality: Cardinality;
|
|
@@ -180,7 +210,11 @@ export declare interface EdgeEndSpec {
|
|
|
180
210
|
|
|
181
211
|
export declare const ErdEdge: MemoExoticComponent<typeof ErdEdgeComponent>;
|
|
182
212
|
|
|
183
|
-
|
|
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;
|
|
184
218
|
|
|
185
219
|
export declare interface ErdEdgeData {
|
|
186
220
|
kind: RelationKind;
|
|
@@ -203,6 +237,8 @@ export declare class ExportError extends Error {
|
|
|
203
237
|
/** Image format for diagram export. */
|
|
204
238
|
export declare type ExportFormat = 'png' | 'svg';
|
|
205
239
|
|
|
240
|
+
export { FitViewOptions }
|
|
241
|
+
|
|
206
242
|
export declare const HEADER_HEIGHT = 40;
|
|
207
243
|
|
|
208
244
|
/** Layout algorithm to position the table nodes. */
|
|
@@ -231,13 +267,23 @@ export declare interface LayoutOptions {
|
|
|
231
267
|
horizontalGap?: number;
|
|
232
268
|
/** Vertical gap between stacked tables. */
|
|
233
269
|
verticalGap?: number;
|
|
270
|
+
/** Minimum table-node width in px. Default {@link MIN_NODE_WIDTH} (160). */
|
|
271
|
+
minNodeWidth?: number;
|
|
272
|
+
/**
|
|
273
|
+
* Maximum table-node width in px; content wider than this is truncated with an ellipsis.
|
|
274
|
+
* Default {@link MAX_NODE_WIDTH} (320). If set below `minNodeWidth`, the max wins.
|
|
275
|
+
*/
|
|
276
|
+
maxNodeWidth?: number;
|
|
234
277
|
}
|
|
235
278
|
|
|
236
279
|
/**
|
|
237
280
|
* Compute node positions for the parsed schema.
|
|
238
281
|
*
|
|
239
|
-
*
|
|
240
|
-
* vertically within each layer.
|
|
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}.
|
|
241
287
|
*/
|
|
242
288
|
export declare function layoutSchema(schema: ParsedSchema, options?: LayoutOptions): Map<string, NodeBox>;
|
|
243
289
|
|
|
@@ -247,8 +293,16 @@ export declare function layoutSchema(schema: ParsedSchema, options?: LayoutOptio
|
|
|
247
293
|
*/
|
|
248
294
|
export declare const lightTheme: DbmlViewerTheme;
|
|
249
295
|
|
|
296
|
+
export declare const MAX_NODE_WIDTH = 320;
|
|
297
|
+
|
|
250
298
|
/** Visual sizing used both for layout math and for the node component. */
|
|
251
|
-
export declare const
|
|
299
|
+
export declare const MIN_NODE_WIDTH = 160;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* @deprecated A node's width is now content-derived per table — use {@link tableWidth}.
|
|
303
|
+
* Kept as a stable reference (equal to {@link MAX_NODE_WIDTH}) for back-compat.
|
|
304
|
+
*/
|
|
305
|
+
export declare const NODE_WIDTH = 320;
|
|
252
306
|
|
|
253
307
|
/** Position and measured size of a laid-out table node. */
|
|
254
308
|
export declare interface NodeBox {
|
|
@@ -261,6 +315,12 @@ export declare interface NodeBox {
|
|
|
261
315
|
/** Map of table id → position, used to persist and restore where the user dragged tables. */
|
|
262
316
|
export declare type NodePositions = Record<string, XYPosition>;
|
|
263
317
|
|
|
318
|
+
/** Lower/upper bounds for {@link tableWidth}. Unset fields fall back to the module defaults. */
|
|
319
|
+
export declare interface NodeWidthBounds {
|
|
320
|
+
minWidth?: number;
|
|
321
|
+
maxWidth?: number;
|
|
322
|
+
}
|
|
323
|
+
|
|
264
324
|
/**
|
|
265
325
|
* Parse a DBML document into a normalized {@link ParsedSchema} of tables and relations.
|
|
266
326
|
*
|
|
@@ -275,6 +335,8 @@ export declare interface ParsedSchema {
|
|
|
275
335
|
relations: RelationInfo[];
|
|
276
336
|
}
|
|
277
337
|
|
|
338
|
+
export { Rect }
|
|
339
|
+
|
|
278
340
|
/** One end of a relation. */
|
|
279
341
|
export declare interface RelationEndpoint {
|
|
280
342
|
/** Id of the table this endpoint belongs to (matches {@link TableInfo.id}). */
|
|
@@ -321,6 +383,8 @@ export declare function renderDiagram(viewport: HTMLElement, bounds: Rect, optio
|
|
|
321
383
|
|
|
322
384
|
export declare const ROW_HEIGHT = 28;
|
|
323
385
|
|
|
386
|
+
export { SetCenterOptions }
|
|
387
|
+
|
|
324
388
|
/** Height of a table node given its column count. */
|
|
325
389
|
export declare function tableHeight(table: TableInfo): number;
|
|
326
390
|
|
|
@@ -348,16 +412,32 @@ export declare type TableNodeData = {
|
|
|
348
412
|
table: TableInfo;
|
|
349
413
|
/** Columns currently highlighted (e.g. endpoints of a hovered relation). */
|
|
350
414
|
highlightedColumns?: Set<string>;
|
|
415
|
+
/** Min/max width bounds; must match what layout used so render and layout agree. */
|
|
416
|
+
widthBounds?: NodeWidthBounds;
|
|
417
|
+
/** Columns that an edge attaches to; only these get connection handles. */
|
|
418
|
+
connectedColumns?: Set<string>;
|
|
351
419
|
};
|
|
352
420
|
|
|
353
421
|
export declare type TableNodeType = Node_2<TableNodeData, 'table'>;
|
|
354
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Estimate a table node's natural width from its content (the longest column row and the
|
|
425
|
+
* header), clamped to `[MIN_NODE_WIDTH, MAX_NODE_WIDTH]`. Used for both layout math and the
|
|
426
|
+
* rendered node, so they stay in sync. Text is measured by an average-character heuristic
|
|
427
|
+
* (no DOM); any underestimate is absorbed by the CSS ellipsis at the max width.
|
|
428
|
+
*/
|
|
429
|
+
export declare function tableWidth(table: TableInfo, bounds?: NodeWidthBounds): number;
|
|
430
|
+
|
|
355
431
|
/**
|
|
356
432
|
* Convert a {@link DbmlViewerTheme} into inline CSS custom properties. Only the keys
|
|
357
433
|
* present in `theme` are emitted, so unset tokens keep their stylesheet defaults.
|
|
358
434
|
*/
|
|
359
435
|
export declare function themeToCssVars(theme?: DbmlViewerTheme): CSSProperties;
|
|
360
436
|
|
|
437
|
+
export { Viewport }
|
|
438
|
+
|
|
439
|
+
export { ViewportHelperFunctionOptions }
|
|
440
|
+
|
|
361
441
|
/** A 2D position. */
|
|
362
442
|
export declare interface XYPosition {
|
|
363
443
|
x: number;
|