dbml-erd-viewer 0.1.0 → 0.1.1

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=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 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});
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
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';
@@ -7,6 +8,9 @@ import { Node as Node_2 } from '@xyflow/react';
7
8
  import { NodeProps } from '@xyflow/react';
8
9
  import { Rect } from '@xyflow/react';
9
10
  import { RefAttributes } from 'react';
11
+ import { SetCenterOptions } from '@xyflow/react';
12
+ import { Viewport } from '@xyflow/react';
13
+ import { ViewportHelperFunctionOptions } from '@xyflow/react';
10
14
 
11
15
  /** Cardinality of one side of a relation. `'1'` = one, `'*'` = many. */
12
16
  export declare type Cardinality = '1' | '*';
@@ -86,6 +90,22 @@ export declare interface DbmlViewerHandle {
86
90
  toDataUrl(options?: DiagramExportOptions): Promise<string>;
87
91
  /** Render the diagram and trigger a browser download. */
88
92
  download(filename: string, options?: DiagramExportOptions): Promise<void>;
93
+ /** Fit the whole diagram into the viewport. */
94
+ fitView(options?: FitViewOptions): void;
95
+ /** Zoom in by one step. */
96
+ zoomIn(options?: ViewportHelperFunctionOptions): void;
97
+ /** Zoom out by one step. */
98
+ zoomOut(options?: ViewportHelperFunctionOptions): void;
99
+ /** Zoom to a specific level (e.g. `1` = 100%). */
100
+ zoomTo(zoomLevel: number, options?: ViewportHelperFunctionOptions): void;
101
+ /** Center the viewport on a flow-coordinate point. */
102
+ setCenter(x: number, y: number, options?: SetCenterOptions): void;
103
+ /** Fit a specific flow-coordinate rectangle into the viewport. */
104
+ fitBounds(bounds: Rect, options?: ViewportHelperFunctionOptions): void;
105
+ /** Set the viewport position and zoom directly. */
106
+ setViewport(viewport: Viewport, options?: ViewportHelperFunctionOptions): void;
107
+ /** Read the current viewport (`{ x, y, zoom }`); returns `undefined` before the diagram mounts. */
108
+ getViewport(): Viewport | undefined;
89
109
  }
90
110
 
91
111
  export declare interface DbmlViewerProps {
@@ -203,6 +223,8 @@ export declare class ExportError extends Error {
203
223
  /** Image format for diagram export. */
204
224
  export declare type ExportFormat = 'png' | 'svg';
205
225
 
226
+ export { FitViewOptions }
227
+
206
228
  export declare const HEADER_HEIGHT = 40;
207
229
 
208
230
  /** Layout algorithm to position the table nodes. */
@@ -231,6 +253,13 @@ export declare interface LayoutOptions {
231
253
  horizontalGap?: number;
232
254
  /** Vertical gap between stacked tables. */
233
255
  verticalGap?: number;
256
+ /** Minimum table-node width in px. Default {@link MIN_NODE_WIDTH} (160). */
257
+ minNodeWidth?: number;
258
+ /**
259
+ * Maximum table-node width in px; content wider than this is truncated with an ellipsis.
260
+ * Default {@link MAX_NODE_WIDTH} (320). If set below `minNodeWidth`, the max wins.
261
+ */
262
+ maxNodeWidth?: number;
234
263
  }
235
264
 
236
265
  /**
@@ -247,8 +276,16 @@ export declare function layoutSchema(schema: ParsedSchema, options?: LayoutOptio
247
276
  */
248
277
  export declare const lightTheme: DbmlViewerTheme;
249
278
 
279
+ export declare const MAX_NODE_WIDTH = 320;
280
+
250
281
  /** Visual sizing used both for layout math and for the node component. */
251
- export declare const NODE_WIDTH = 240;
282
+ export declare const MIN_NODE_WIDTH = 160;
283
+
284
+ /**
285
+ * @deprecated A node's width is now content-derived per table — use {@link tableWidth}.
286
+ * Kept as a stable reference (equal to {@link MAX_NODE_WIDTH}) for back-compat.
287
+ */
288
+ export declare const NODE_WIDTH = 320;
252
289
 
253
290
  /** Position and measured size of a laid-out table node. */
254
291
  export declare interface NodeBox {
@@ -261,6 +298,12 @@ export declare interface NodeBox {
261
298
  /** Map of table id → position, used to persist and restore where the user dragged tables. */
262
299
  export declare type NodePositions = Record<string, XYPosition>;
263
300
 
301
+ /** Lower/upper bounds for {@link tableWidth}. Unset fields fall back to the module defaults. */
302
+ export declare interface NodeWidthBounds {
303
+ minWidth?: number;
304
+ maxWidth?: number;
305
+ }
306
+
264
307
  /**
265
308
  * Parse a DBML document into a normalized {@link ParsedSchema} of tables and relations.
266
309
  *
@@ -275,6 +318,8 @@ export declare interface ParsedSchema {
275
318
  relations: RelationInfo[];
276
319
  }
277
320
 
321
+ export { Rect }
322
+
278
323
  /** One end of a relation. */
279
324
  export declare interface RelationEndpoint {
280
325
  /** Id of the table this endpoint belongs to (matches {@link TableInfo.id}). */
@@ -321,6 +366,8 @@ export declare function renderDiagram(viewport: HTMLElement, bounds: Rect, optio
321
366
 
322
367
  export declare const ROW_HEIGHT = 28;
323
368
 
369
+ export { SetCenterOptions }
370
+
324
371
  /** Height of a table node given its column count. */
325
372
  export declare function tableHeight(table: TableInfo): number;
326
373
 
@@ -348,16 +395,30 @@ export declare type TableNodeData = {
348
395
  table: TableInfo;
349
396
  /** Columns currently highlighted (e.g. endpoints of a hovered relation). */
350
397
  highlightedColumns?: Set<string>;
398
+ /** Min/max width bounds; must match what layout used so render and layout agree. */
399
+ widthBounds?: NodeWidthBounds;
351
400
  };
352
401
 
353
402
  export declare type TableNodeType = Node_2<TableNodeData, 'table'>;
354
403
 
404
+ /**
405
+ * Estimate a table node's natural width from its content (the longest column row and the
406
+ * header), clamped to `[MIN_NODE_WIDTH, MAX_NODE_WIDTH]`. Used for both layout math and the
407
+ * rendered node, so they stay in sync. Text is measured by an average-character heuristic
408
+ * (no DOM); any underestimate is absorbed by the CSS ellipsis at the max width.
409
+ */
410
+ export declare function tableWidth(table: TableInfo, bounds?: NodeWidthBounds): number;
411
+
355
412
  /**
356
413
  * Convert a {@link DbmlViewerTheme} into inline CSS custom properties. Only the keys
357
414
  * present in `theme` are emitted, so unset tokens keep their stylesheet defaults.
358
415
  */
359
416
  export declare function themeToCssVars(theme?: DbmlViewerTheme): CSSProperties;
360
417
 
418
+ export { Viewport }
419
+
420
+ export { ViewportHelperFunctionOptions }
421
+
361
422
  /** A 2D position. */
362
423
  export declare interface XYPosition {
363
424
  x: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbml-erd-viewer",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "React component library that renders DBML database schemas as an interactive diagram.",
5
5
  "keywords": [
6
6
  "database",