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.
- package/LICENSE +21 -21
- package/README.md +348 -329
- package/dist/dbml-erd-viewer.css +1 -1
- package/dist/dbml-erd-viewer.js +331 -241
- package/dist/dbml-erd-viewer.umd.cjs +1 -1
- package/dist/index.d.ts +62 -1
- 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 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
|
|
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;
|