ok-canvas-export 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,9 +1,224 @@
1
- export { useDiagramExport, } from './useDiagramExport';
2
- export { exportDiagram, } from './exportDiagram';
3
- export { calculateDimensions, calculateSvgDimensions, getSvgContentBounds, getScrollDimensions, } from './calculateDimensions';
4
- export { renderHighQuality, } from './renderHighQuality';
5
- export { serializeSvg, createSvgUrl, prepareSvgForExport, } from './utils/serializer';
6
- export { downloadBlob, generateFileName, canvasToBlob, } from './utils/download';
7
- export type { ExportOptions, ExportStatus, ExportContext, DiagramData, GetTableHeight, } from './types';
8
- export { useDiagramExport as default, } from './useDiagramExport';
9
- //# sourceMappingURL=index.d.ts.map
1
+ type ExportBackground = string;
2
+ interface ExportOptions {
3
+ format?: 'png' | 'svg';
4
+ /**
5
+ * Background color for the exported diagram.
6
+ *
7
+ * Supported examples:
8
+ *
9
+ * - 'white'
10
+ * - 'transparent'
11
+ * - '#C300FF'
12
+ * - '#ffffff'
13
+ * - 'rgb(195, 0, 255)'
14
+ * - 'rgba(195, 0, 255, 0.5)'
15
+ * - 'hsl(285, 100%, 50%)'
16
+ *
17
+ * Any valid CSS color supported by the browser can be used.
18
+ */
19
+ background?: ExportBackground;
20
+ /**
21
+ * Export scale.
22
+ *
23
+ * Example:
24
+ * scale: 2
25
+ */
26
+ scale?: number;
27
+ /**
28
+ * Additional space around the exported diagram.
29
+ */
30
+ margin?: number;
31
+ /**
32
+ * Custom output filename.
33
+ */
34
+ fileName?: string;
35
+ /**
36
+ * Export progress callback.
37
+ */
38
+ onProgress?: (status: ExportStatus) => void;
39
+ }
40
+ interface DiagramData {
41
+ tables: Array<{
42
+ id: string;
43
+ x: number;
44
+ y: number;
45
+ fields: any[];
46
+ }>;
47
+ relationships: any[];
48
+ }
49
+ type ExportStatus = {
50
+ type: 'preparing';
51
+ } | {
52
+ type: 'rendering';
53
+ } | {
54
+ type: 'serializing';
55
+ } | {
56
+ type: 'downloading';
57
+ } | {
58
+ type: 'complete';
59
+ } | {
60
+ type: 'error';
61
+ message: string;
62
+ };
63
+ interface GetTableHeight {
64
+ (fields: any[]): number;
65
+ }
66
+ interface ExportContext {
67
+ isExporting: boolean;
68
+ exportDiagram: (options?: ExportOptions) => Promise<void>;
69
+ }
70
+
71
+ interface UseDiagramExportParams {
72
+ svgRef: React.RefObject<SVGSVGElement>;
73
+ diagramData?: DiagramData | null;
74
+ getTableHeight?: GetTableHeight;
75
+ projectName?: string;
76
+ }
77
+ /**
78
+ * Hook that provides SVG diagram export functionality.
79
+ *
80
+ * The exporter automatically calculates the real SVG content bounds,
81
+ * so diagramData is optional for generic SVG usage.
82
+ */
83
+ declare const useDiagramExport: ({ svgRef, diagramData, getTableHeight, projectName, }: UseDiagramExportParams) => ExportContext & {
84
+ exportAllTables: boolean;
85
+ setExportAllTables: (value: boolean) => void;
86
+ };
87
+
88
+ interface ExportDiagramParams {
89
+ svgRef: React.RefObject<SVGSVGElement>;
90
+ diagramData?: DiagramData | null;
91
+ getTableHeight?: GetTableHeight;
92
+ projectName?: string;
93
+ setExportAllTables?: (value: boolean) => void;
94
+ showToast?: (message: string, type?: string) => void;
95
+ }
96
+ /**
97
+ * Exports the complete SVG diagram regardless of the
98
+ * visible viewport.
99
+ *
100
+ * The export process is:
101
+ *
102
+ * 1. Render all diagram content.
103
+ * 2. Calculate the real SVG content bounds.
104
+ * 3. Create an independent SVG clone.
105
+ * 4. Set a viewBox covering the complete content.
106
+ * 5. Apply the requested background.
107
+ * 6. Convert the SVG to PNG when requested.
108
+ *
109
+ * Background examples:
110
+ *
111
+ * - 'white'
112
+ * - 'transparent'
113
+ * - '#C300FF'
114
+ * - 'rgb(195, 0, 255)'
115
+ * - 'rgba(195, 0, 255, 0.5)'
116
+ */
117
+ declare const exportDiagram: (params: ExportDiagramParams, options?: ExportOptions) => Promise<void>;
118
+
119
+ interface Dimensions {
120
+ width: number;
121
+ height: number;
122
+ x: number;
123
+ y: number;
124
+ }
125
+ /**
126
+ * Calculates dimensions based on diagram data.
127
+ *
128
+ * This function is kept compatible with the original API and tests.
129
+ *
130
+ * It calculates the total diagram size from the table coordinates,
131
+ * assuming the table width is 280px plus the configured padding.
132
+ */
133
+ declare const calculateDimensions: (diagramData: DiagramData | undefined | null, getTableHeight: GetTableHeight, margin?: number) => Dimensions;
134
+ /**
135
+ * Calculates the visible bounds of an SVG's graphical content.
136
+ *
137
+ * This function is intended for generic SVG exports.
138
+ *
139
+ * It does NOT rely on:
140
+ *
141
+ * - width
142
+ * - height
143
+ * - viewport
144
+ * - scroll container
145
+ *
146
+ * Instead, it attempts to determine the real graphical bounds.
147
+ */
148
+ declare const getSvgContentBounds: (svg: SVGSVGElement) => Dimensions | null;
149
+ /**
150
+ * Calculates the dimensions that should be used for a real SVG export.
151
+ *
152
+ * The content bounds are preferred.
153
+ *
154
+ * The returned x/y values are important because the content does not
155
+ * necessarily start at 0,0.
156
+ */
157
+ declare const calculateSvgDimensions: (svg: SVGSVGElement, margin?: number) => Dimensions;
158
+ /**
159
+ * Calculates dimensions based on an SVG element and its scroll container.
160
+ *
161
+ * Kept for backwards compatibility.
162
+ */
163
+ declare const getScrollDimensions: (svg: SVGSVGElement) => Dimensions;
164
+
165
+ /**
166
+ * Renders an SVG image to a high-quality canvas.
167
+ *
168
+ * The background can be:
169
+ *
170
+ * - 'transparent'
171
+ * - any valid CSS color
172
+ *
173
+ * Examples:
174
+ *
175
+ * - '#C300FF'
176
+ * - '#ffffff'
177
+ * - 'rgb(195, 0, 255)'
178
+ * - 'rgba(195, 0, 255, 0.5)'
179
+ * - 'hsl(285, 100%, 50%)'
180
+ */
181
+ declare const renderHighQuality: (image: HTMLImageElement, width: number, height: number, scale?: number, background?: string) => Promise<HTMLCanvasElement>;
182
+
183
+ /**
184
+ * Downloads are handled elsewhere.
185
+ *
186
+ * This file contains SVG serialization and preparation utilities.
187
+ */
188
+ /**
189
+ * Serializes an SVG element to a string.
190
+ *
191
+ * CSS custom properties are resolved using the current document styles.
192
+ */
193
+ declare const serializeSvg: (svg: SVGSVGElement) => string;
194
+ /**
195
+ * Creates a Blob URL from SVG markup.
196
+ */
197
+ declare const createSvgUrl: (svgMarkup: string) => string;
198
+ /**
199
+ * Creates a clean SVG clone for export.
200
+ *
201
+ * The clone receives an explicit viewBox based on the REAL
202
+ * content bounds instead of assuming the content starts at 0,0.
203
+ *
204
+ * The background can be:
205
+ *
206
+ * - 'transparent'
207
+ * - any valid CSS color
208
+ */
209
+ declare const prepareSvgForExport: (sourceSvg: SVGSVGElement, width: number, height: number, background?: string, margin?: number, sourceX?: number, sourceY?: number) => SVGSVGElement;
210
+
211
+ /**
212
+ * Downloads a Blob as a file.
213
+ */
214
+ declare const downloadBlob: (blob: Blob, fileName: string) => void;
215
+ /**
216
+ * Generates a safe filename.
217
+ */
218
+ declare const generateFileName: (projectName: string | undefined, format: "png" | "svg") => string;
219
+ /**
220
+ * Converts a canvas to a PNG Blob.
221
+ */
222
+ declare const canvasToBlob: (canvas: HTMLCanvasElement) => Promise<Blob>;
223
+
224
+ export { type DiagramData, type ExportContext, type ExportOptions, type ExportStatus, type GetTableHeight, calculateDimensions, calculateSvgDimensions, canvasToBlob, createSvgUrl, useDiagramExport as default, downloadBlob, exportDiagram, generateFileName, getScrollDimensions, getSvgContentBounds, prepareSvgForExport, renderHighQuality, serializeSvg, useDiagramExport };
package/dist/index.js CHANGED
@@ -1,8 +1,2 @@
1
- export { useDiagramExport, } from './useDiagramExport';
2
- export { exportDiagram, } from './exportDiagram';
3
- export { calculateDimensions, calculateSvgDimensions, getSvgContentBounds, getScrollDimensions, } from './calculateDimensions';
4
- export { renderHighQuality, } from './renderHighQuality';
5
- export { serializeSvg, createSvgUrl, prepareSvgForExport, } from './utils/serializer';
6
- export { downloadBlob, generateFileName, canvasToBlob, } from './utils/download';
7
- export { useDiagramExport as default, } from './useDiagramExport';
1
+ import{useState as F,useCallback as z}from"react";var O=(r,o,t=100)=>{if(!r?.tables?.length)return{width:100+t*2,height:100+t*2,x:-t,y:-t};let e=Math.min(...r.tables.map(n=>n.x)),s=Math.min(...r.tables.map(n=>n.y)),a=Math.max(...r.tables.map(n=>n.x+280+40)),l=Math.max(...r.tables.map(n=>n.y+o(n.fields)+40));return{x:e-t,y:s-t,width:Math.max(100,a-e+t*2),height:Math.max(100,l-s+t*2)}},V=r=>{let o=Array.from(r.querySelectorAll("g, path, rect, circle, ellipse, line, polyline, polygon, text, use, image")),t=1/0,e=1/0,s=-1/0,a=-1/0,l=(n,m,i,c)=>{!Number.isFinite(n)||!Number.isFinite(m)||!Number.isFinite(i)||!Number.isFinite(c)||i<0||c<0||(t=Math.min(t,n),e=Math.min(e,m),s=Math.max(s,n+i),a=Math.max(a,m+c))};for(let n of o)if(!(n.matches('[data-export-bg="canvas"]')||n.closest('[data-export-bg="canvas"]')))try{let m=n.getBBox();l(m.x,m.y,m.width,m.height)}catch{}return!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(s)||!Number.isFinite(a)?null:{x:t,y:e,width:Math.max(1,s-t),height:Math.max(1,a-e)}},w=(r,o=100)=>{let t=V(r);if(t)return{x:t.x-o,y:t.y-o,width:t.width+o*2,height:t.height+o*2};let e=r.viewBox?.baseVal;if(e&&Number.isFinite(e.width)&&Number.isFinite(e.height)&&e.width>0&&e.height>0)return{x:e.x-o,y:e.y-o,width:e.width+o*2,height:e.height+o*2};let s=Number(r.getAttribute("width"))||r.clientWidth||1,a=Number(r.getAttribute("height"))||r.clientHeight||1;return{x:-o,y:-o,width:s+o*2,height:a+o*2}},k=r=>{let o=r.parentElement||r.closest(".overflow-auto")||r.closest(".overflow-scroll"),t=Number(r.getAttribute("width"))||r.clientWidth||1,e=Number(r.getAttribute("height"))||r.clientHeight||1;return o&&(t=Math.max(t,o.scrollWidth),e=Math.max(e,o.scrollHeight)),{x:0,y:0,width:t,height:e}};var S=async(r,o,t,e=2,s="transparent")=>{let l=Math.max(1,o),n=Math.max(1,t),m=Math.max(.1,e),i=Math.min(m,16384/Math.max(l,n,1)),c=document.createElement("canvas");c.width=Math.max(1,Math.floor(l*i)),c.height=Math.max(1,Math.floor(n*i));let p=c.getContext("2d",{alpha:!0});if(!p)throw new Error("Unable to create 2D canvas context");return p.imageSmoothingEnabled=!0,p.imageSmoothingQuality="high",s!=="transparent"?(p.fillStyle=s,p.fillRect(0,0,c.width,c.height)):p.clearRect(0,0,c.width,c.height),p.drawImage(r,0,0,l*i,n*i),c};var E=r=>{let o=new XMLSerializer,t=typeof document<"u"?getComputedStyle(document.documentElement):null,e=o.serializeToString(r);return t&&(e=e.replace(/var\(--([^)]+)\)/g,(s,a)=>t.getPropertyValue(`--${a}`)?.trim()||`var(--${a})`)),e.includes('xmlns="http://www.w3.org/2000/svg"')||(e=e.replace("<svg",'<svg xmlns="http://www.w3.org/2000/svg"')),e},v=r=>URL.createObjectURL(new Blob([r],{type:"image/svg+xml;charset=utf-8"})),D=(r,o,t,e="transparent",s=0,a=0,l=0)=>{let n=r.cloneNode(!0);if(n.querySelectorAll('[data-export-bg="canvas"]').forEach(i=>{i.remove()}),n.setAttribute("width",String(o)),n.setAttribute("height",String(t)),n.setAttribute("viewBox",`${a} ${l} ${o} ${t}`),n.setAttribute("preserveAspectRatio","xMinYMin meet"),e!=="transparent"){let i=document.createElementNS("http://www.w3.org/2000/svg","rect");i.setAttribute("x",String(a)),i.setAttribute("y",String(l)),i.setAttribute("width",String(o)),i.setAttribute("height",String(t)),i.setAttribute("fill",e),n.insertBefore(i,n.firstChild)}return n};var f=(r,o)=>{let t=URL.createObjectURL(r),e=document.createElement("a");e.href=t,e.download=o;try{document.body?.appendChild(e),e.click(),document.body?.removeChild(e)}catch{e.click()}setTimeout(()=>{URL.revokeObjectURL(t)},100)},d=(r,o)=>`${(r||"diagram").replace(/\s+/g,"_").toLowerCase().replace(/[^a-z0-9_-]/g,"")}.${o}`,A=r=>new Promise((o,t)=>{try{if(typeof r.toBlob!="function"){t(new Error("Canvas.toBlob is not supported"));return}r.toBlob(e=>{if(!e){t(new Error("Failed to create PNG blob"));return}o(e)},"image/png")}catch(e){t(e)}});var N=async(r,o={})=>{let{svgRef:t,diagramData:e,getTableHeight:s,projectName:a,setExportAllTables:l,showToast:n}=r,{format:m="png",background:i="white",scale:c=2,margin:p=100,fileName:G,onProgress:u}=o;if(!t.current){u?.({type:"error",message:"SVG reference not available"});return}let h=null;try{u?.({type:"preparing"}),n?.("Preparing export...","info"),l?.(!0),await new Promise(g=>{setTimeout(g,300)}),u?.({type:"rendering"});let x=t.current,C=w(x,p),{x:L,y:R,width:T,height:M}=C,P=D(x,T,M,i,p,L,R);u?.({type:"serializing"});let B=E(P);if(m==="svg"){let g=new Blob([B],{type:"image/svg+xml;charset=utf-8"}),y=G||d(a,"svg");f(g,y),u?.({type:"complete"}),n?.("Export completed successfully","success");return}let b=new Image;h=v(B),await new Promise((g,y)=>{b.onload=()=>{g()},b.onerror=()=>{y(new Error("Failed to load SVG image"))},b.src=h});let I=await S(b,T,M,c,i);u?.({type:"downloading"});let U=await A(I),_=G||d(a,"png");f(U,_),u?.({type:"complete"}),n?.("Export completed successfully","success")}catch(x){console.error("Export error:",x),u?.({type:"error",message:"Export failed"}),n?.("Failed to export file","error")}finally{l?.(!1),h&&URL.revokeObjectURL(h)}};var H=({svgRef:r,diagramData:o,getTableHeight:t,projectName:e})=>{let[s,a]=F(!1),[l,n]=F(!1),m=z(async(i={})=>{a(!0);try{await N({svgRef:r,diagramData:o,getTableHeight:t,projectName:e,setExportAllTables:n},i)}finally{a(!1),n(!1)}},[r,o,t,e]);return{isExporting:s,exportDiagram:m,exportAllTables:l,setExportAllTables:n}};export{O as calculateDimensions,w as calculateSvgDimensions,A as canvasToBlob,v as createSvgUrl,H as default,f as downloadBlob,N as exportDiagram,d as generateFileName,k as getScrollDimensions,V as getSvgContentBounds,D as prepareSvgForExport,S as renderHighQuality,E as serializeSvg,H as useDiagramExport};
8
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,GACb,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EACL,gBAAgB,IAAI,OAAO,GAC5B,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"sources":["../src/useDiagramExport.ts","../src/calculateDimensions.ts","../src/renderHighQuality.ts","../src/utils/serializer.ts","../src/utils/download.ts","../src/exportDiagram.ts"],"sourcesContent":["import {\n useState,\n useCallback,\n} from 'react';\n\nimport type {\n ExportOptions,\n ExportContext,\n DiagramData,\n GetTableHeight,\n} from './types';\n\nimport {\n exportDiagram,\n} from './exportDiagram';\n\nexport interface UseDiagramExportParams {\n svgRef:\n React.RefObject<SVGSVGElement>;\n\n diagramData?:\n | DiagramData\n | null;\n\n getTableHeight?:\n GetTableHeight;\n\n projectName?: string;\n}\n\n/**\n * Hook that provides SVG diagram export functionality.\n *\n * The exporter automatically calculates the real SVG content bounds,\n * so diagramData is optional for generic SVG usage.\n */\nexport const useDiagramExport = ({\n svgRef,\n diagramData,\n getTableHeight,\n projectName,\n}: UseDiagramExportParams):\n ExportContext & {\n exportAllTables: boolean;\n\n setExportAllTables: (\n value: boolean,\n ) => void;\n } => {\n const [\n isExporting,\n setIsExporting,\n ] = useState(false);\n\n const [\n exportAllTables,\n setExportAllTables,\n ] = useState(false);\n\n const handleExport =\n useCallback(\n async (\n options: ExportOptions = {},\n ) => {\n setIsExporting(\n true,\n );\n\n try {\n await exportDiagram(\n {\n svgRef,\n diagramData,\n getTableHeight,\n projectName,\n setExportAllTables,\n },\n options,\n );\n } finally {\n setIsExporting(\n false,\n );\n\n setExportAllTables(\n false,\n );\n }\n },\n [\n svgRef,\n diagramData,\n getTableHeight,\n projectName,\n ],\n );\n\n return {\n isExporting,\n\n exportDiagram:\n handleExport,\n\n exportAllTables,\n\n setExportAllTables,\n };\n};","import type {\n DiagramData,\n GetTableHeight,\n} from './types';\n\nconst TABLE_WIDTH = 280;\nconst TABLE_PADDING = 40;\n\nexport interface Dimensions {\n width: number;\n height: number;\n x: number;\n y: number;\n}\n\n/**\n * Calculates dimensions based on diagram data.\n *\n * This function is kept compatible with the original API and tests.\n *\n * It calculates the total diagram size from the table coordinates,\n * assuming the table width is 280px plus the configured padding.\n */\nexport const calculateDimensions = (\n diagramData:\n | DiagramData\n | undefined\n | null,\n getTableHeight:\n GetTableHeight,\n margin: number = 100,\n): Dimensions => {\n if (\n !diagramData?.tables?.length\n ) {\n return {\n width:\n 100 +\n margin * 2,\n\n height:\n 100 +\n margin * 2,\n\n x:\n -margin,\n\n y:\n -margin,\n };\n }\n\n const minX =\n Math.min(\n ...diagramData.tables.map(\n (table) =>\n table.x,\n ),\n );\n\n const minY =\n Math.min(\n ...diagramData.tables.map(\n (table) =>\n table.y,\n ),\n );\n\n const maxX =\n Math.max(\n ...diagramData.tables.map(\n (table) =>\n table.x +\n TABLE_WIDTH +\n TABLE_PADDING,\n ),\n );\n\n const maxY =\n Math.max(\n ...diagramData.tables.map(\n (table) =>\n table.y +\n getTableHeight(\n table.fields,\n ) +\n TABLE_PADDING,\n ),\n );\n\n return {\n x:\n minX -\n margin,\n\n y:\n minY -\n margin,\n\n width:\n Math.max(\n 100,\n maxX -\n minX +\n margin * 2,\n ),\n\n height:\n Math.max(\n 100,\n maxY -\n minY +\n margin * 2,\n ),\n };\n};\n\n/**\n * Calculates the visible bounds of an SVG's graphical content.\n *\n * This function is intended for generic SVG exports.\n *\n * It does NOT rely on:\n *\n * - width\n * - height\n * - viewport\n * - scroll container\n *\n * Instead, it attempts to determine the real graphical bounds.\n */\nexport const getSvgContentBounds = (\n svg: SVGSVGElement,\n): Dimensions | null => {\n const elements =\n Array.from(\n svg.querySelectorAll<SVGGraphicsElement>(\n 'g, path, rect, circle, ellipse, line, polyline, polygon, text, use, image',\n ),\n );\n\n let minX =\n Infinity;\n\n let minY =\n Infinity;\n\n let maxX =\n -Infinity;\n\n let maxY =\n -Infinity;\n\n const updateBounds =\n (\n x: number,\n y: number,\n width: number,\n height: number,\n ) => {\n if (\n !Number.isFinite(\n x,\n ) ||\n !Number.isFinite(\n y,\n ) ||\n !Number.isFinite(\n width,\n ) ||\n !Number.isFinite(\n height,\n )\n ) {\n return;\n }\n\n if (\n width < 0 ||\n height < 0\n ) {\n return;\n }\n\n minX =\n Math.min(\n minX,\n x,\n );\n\n minY =\n Math.min(\n minY,\n y,\n );\n\n maxX =\n Math.max(\n maxX,\n x + width,\n );\n\n maxY =\n Math.max(\n maxY,\n y + height,\n );\n };\n\n for (\n const element of elements\n ) {\n /*\n * Ignore the artificial canvas background.\n */\n if (\n element.matches(\n '[data-export-bg=\"canvas\"]',\n ) ||\n element.closest(\n '[data-export-bg=\"canvas\"]',\n )\n ) {\n continue;\n }\n\n try {\n const bbox =\n element.getBBox();\n\n updateBounds(\n bbox.x,\n bbox.y,\n bbox.width,\n bbox.height,\n );\n } catch {\n /*\n * getBBox() can fail in environments where\n * the SVG has not been rendered yet.\n */\n }\n }\n\n if (\n !Number.isFinite(\n minX,\n ) ||\n !Number.isFinite(\n minY,\n ) ||\n !Number.isFinite(\n maxX,\n ) ||\n !Number.isFinite(\n maxY,\n )\n ) {\n return null;\n }\n\n return {\n x:\n minX,\n\n y:\n minY,\n\n width:\n Math.max(\n 1,\n maxX - minX,\n ),\n\n height:\n Math.max(\n 1,\n maxY - minY,\n ),\n };\n};\n\n/**\n * Calculates the dimensions that should be used for a real SVG export.\n *\n * The content bounds are preferred.\n *\n * The returned x/y values are important because the content does not\n * necessarily start at 0,0.\n */\nexport const calculateSvgDimensions = (\n svg: SVGSVGElement,\n margin: number = 100,\n): Dimensions => {\n const bounds =\n getSvgContentBounds(\n svg,\n );\n\n if (bounds) {\n return {\n x:\n bounds.x -\n margin,\n\n y:\n bounds.y -\n margin,\n\n width:\n bounds.width +\n margin * 2,\n\n height:\n bounds.height +\n margin * 2,\n };\n }\n\n /*\n * Fallback to the SVG viewBox.\n */\n const viewBox =\n svg.viewBox?.baseVal;\n\n if (\n viewBox &&\n Number.isFinite(\n viewBox.width,\n ) &&\n Number.isFinite(\n viewBox.height,\n ) &&\n viewBox.width > 0 &&\n viewBox.height > 0\n ) {\n return {\n x:\n viewBox.x -\n margin,\n\n y:\n viewBox.y -\n margin,\n\n width:\n viewBox.width +\n margin * 2,\n\n height:\n viewBox.height +\n margin * 2,\n };\n }\n\n /*\n * Final fallback to width/height attributes.\n */\n const width =\n Number(\n svg.getAttribute(\n 'width',\n ),\n ) ||\n svg.clientWidth ||\n 1;\n\n const height =\n Number(\n svg.getAttribute(\n 'height',\n ),\n ) ||\n svg.clientHeight ||\n 1;\n\n return {\n x:\n -margin,\n\n y:\n -margin,\n\n width:\n width +\n margin * 2,\n\n height:\n height +\n margin * 2,\n };\n};\n\n/**\n * Calculates dimensions based on an SVG element and its scroll container.\n *\n * Kept for backwards compatibility.\n */\nexport const getScrollDimensions = (\n svg: SVGSVGElement,\n): Dimensions => {\n const scrollContainer =\n svg.parentElement ||\n svg.closest(\n '.overflow-auto',\n ) ||\n svg.closest(\n '.overflow-scroll',\n );\n\n let width =\n Number(\n svg.getAttribute(\n 'width',\n ),\n ) ||\n svg.clientWidth ||\n 1;\n\n let height =\n Number(\n svg.getAttribute(\n 'height',\n ),\n ) ||\n svg.clientHeight ||\n 1;\n\n if (\n scrollContainer\n ) {\n width =\n Math.max(\n width,\n scrollContainer.scrollWidth,\n );\n\n height =\n Math.max(\n height,\n scrollContainer.scrollHeight,\n );\n }\n\n return {\n x: 0,\n y: 0,\n width,\n height,\n };\n};","/**\n * Renders an SVG image to a high-quality canvas.\n *\n * The background can be:\n *\n * - 'transparent'\n * - any valid CSS color\n *\n * Examples:\n *\n * - '#C300FF'\n * - '#ffffff'\n * - 'rgb(195, 0, 255)'\n * - 'rgba(195, 0, 255, 0.5)'\n * - 'hsl(285, 100%, 50%)'\n */\nexport const renderHighQuality = async (\n image: HTMLImageElement,\n width: number,\n height: number,\n scale: number = 2,\n background: string = 'transparent',\n): Promise<HTMLCanvasElement> => {\n const MAX_CANVAS_SIZE = 16384;\n\n const safeWidth =\n Math.max(1, width);\n\n const safeHeight =\n Math.max(1, height);\n\n const safeScale =\n Math.max(0.1, scale);\n\n const effectiveScale = Math.min(\n safeScale,\n MAX_CANVAS_SIZE /\n Math.max(\n safeWidth,\n safeHeight,\n 1,\n ),\n );\n\n const canvas =\n document.createElement(\n 'canvas',\n );\n\n canvas.width = Math.max(\n 1,\n Math.floor(\n safeWidth *\n effectiveScale,\n ),\n );\n\n canvas.height = Math.max(\n 1,\n Math.floor(\n safeHeight *\n effectiveScale,\n ),\n );\n\n /*\n * Always keep alpha enabled.\n *\n * This is important because the user may provide:\n *\n * rgba(...)\n *\n * or transparent.\n */\n const context =\n canvas.getContext(\n '2d',\n {\n alpha: true,\n },\n );\n\n if (!context) {\n throw new Error(\n 'Unable to create 2D canvas context',\n );\n }\n\n context.imageSmoothingEnabled =\n true;\n\n context.imageSmoothingQuality =\n 'high';\n\n /*\n * Background handling.\n *\n * transparent:\n * Keep the canvas transparent.\n *\n * any other value:\n * Use it as a CSS color.\n */\n if (\n background !== 'transparent'\n ) {\n context.fillStyle =\n background;\n\n context.fillRect(\n 0,\n 0,\n canvas.width,\n canvas.height,\n );\n } else {\n context.clearRect(\n 0,\n 0,\n canvas.width,\n canvas.height,\n );\n }\n\n /*\n * The canvas already contains the\n * final scaled dimensions.\n */\n context.drawImage(\n image,\n 0,\n 0,\n safeWidth *\n effectiveScale,\n safeHeight *\n effectiveScale,\n );\n\n return canvas;\n};","/**\n * Downloads are handled elsewhere.\n *\n * This file contains SVG serialization and preparation utilities.\n */\n\n/**\n * Serializes an SVG element to a string.\n *\n * CSS custom properties are resolved using the current document styles.\n */\nexport const serializeSvg = (\n svg: SVGSVGElement,\n): string => {\n const serializer =\n new XMLSerializer();\n\n const styles =\n typeof document !== 'undefined'\n ? getComputedStyle(\n document.documentElement,\n )\n : null;\n\n let markup =\n serializer.serializeToString(\n svg,\n );\n\n if (styles) {\n markup = markup.replace(\n /var\\(--([^)]+)\\)/g,\n (\n _match,\n name: string,\n ) => {\n const value =\n styles\n .getPropertyValue(\n `--${name}`,\n )\n ?.trim();\n\n return value ||\n `var(--${name})`;\n },\n );\n }\n\n /*\n * Ensure SVG has the proper namespace.\n */\n if (\n !markup.includes(\n 'xmlns=\"http://www.w3.org/2000/svg\"',\n )\n ) {\n markup = markup.replace(\n '<svg',\n '<svg xmlns=\"http://www.w3.org/2000/svg\"',\n );\n }\n\n return markup;\n};\n\n/**\n * Creates a Blob URL from SVG markup.\n */\nexport const createSvgUrl = (\n svgMarkup: string,\n): string => {\n return URL.createObjectURL(\n new Blob(\n [svgMarkup],\n {\n type:\n 'image/svg+xml;charset=utf-8',\n },\n ),\n );\n};\n\n/**\n * Creates a clean SVG clone for export.\n *\n * The clone receives an explicit viewBox based on the REAL\n * content bounds instead of assuming the content starts at 0,0.\n *\n * The background can be:\n *\n * - 'transparent'\n * - any valid CSS color\n */\nexport const prepareSvgForExport = (\n sourceSvg: SVGSVGElement,\n width: number,\n height: number,\n background: string = 'transparent',\n margin: number = 0,\n sourceX: number = 0,\n sourceY: number = 0,\n): SVGSVGElement => {\n const clone =\n sourceSvg.cloneNode(\n true,\n ) as SVGSVGElement;\n\n /*\n * Remove elements explicitly marked as canvas backgrounds.\n *\n * These backgrounds are usually viewport-sized and would otherwise\n * make getBBox() consider the entire viewport instead of the\n * actual diagram.\n */\n const bgNodes =\n clone.querySelectorAll(\n '[data-export-bg=\"canvas\"]',\n );\n\n bgNodes.forEach(\n (node) => {\n node.remove();\n },\n );\n\n /*\n * The dimensions passed here already include the requested margin.\n */\n clone.setAttribute(\n 'width',\n String(width),\n );\n\n clone.setAttribute(\n 'height',\n String(height),\n );\n\n clone.setAttribute(\n 'viewBox',\n `${sourceX} ${sourceY} ${width} ${height}`,\n );\n\n /*\n * Prevent unexpected cropping or distortion.\n */\n clone.setAttribute(\n 'preserveAspectRatio',\n 'xMinYMin meet',\n );\n\n /*\n * Add an explicit background when requested.\n *\n * transparent:\n * No background is added.\n *\n * Any other CSS color:\n * The color is used as the SVG background.\n */\n if (\n background !== 'transparent'\n ) {\n const backgroundRect =\n document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'rect',\n );\n\n backgroundRect.setAttribute(\n 'x',\n String(sourceX),\n );\n\n backgroundRect.setAttribute(\n 'y',\n String(sourceY),\n );\n\n backgroundRect.setAttribute(\n 'width',\n String(width),\n );\n\n backgroundRect.setAttribute(\n 'height',\n String(height),\n );\n\n backgroundRect.setAttribute(\n 'fill',\n background,\n );\n\n /*\n * Keep the background behind the diagram.\n */\n clone.insertBefore(\n backgroundRect,\n clone.firstChild,\n );\n }\n\n /*\n * We intentionally do NOT manipulate arbitrary\n * transforms here.\n *\n * The viewBox handles positioning and margin.\n */\n return clone;\n};","/**\n * Downloads a Blob as a file.\n */\nexport const downloadBlob = (\n blob: Blob,\n fileName: string,\n): void => {\n const url =\n URL.createObjectURL(\n blob,\n );\n\n const link =\n document.createElement(\n 'a',\n );\n\n link.href = url;\n link.download = fileName;\n\n try {\n document.body?.appendChild(\n link,\n );\n\n link.click();\n\n document.body?.removeChild(\n link,\n );\n } catch {\n link.click();\n }\n\n /*\n * Give the browser a chance to start the download before\n * revoking the object URL.\n */\n setTimeout(() => {\n URL.revokeObjectURL(\n url,\n );\n }, 100);\n};\n\n/**\n * Generates a safe filename.\n */\nexport const generateFileName = (\n projectName:\n | string\n | undefined,\n format:\n | 'png'\n | 'svg',\n): string => {\n const safeName =\n (\n projectName ||\n 'diagram'\n )\n .replace(\n /\\s+/g,\n '_',\n )\n .toLowerCase()\n .replace(\n /[^a-z0-9_-]/g,\n '',\n );\n\n return `${safeName}.${format}`;\n};\n\n/**\n * Converts a canvas to a PNG Blob.\n */\nexport const canvasToBlob = (\n canvas: HTMLCanvasElement,\n): Promise<Blob> => {\n return new Promise(\n (\n resolve,\n reject,\n ) => {\n try {\n if (\n typeof canvas.toBlob !==\n 'function'\n ) {\n reject(\n new Error(\n 'Canvas.toBlob is not supported',\n ),\n );\n\n return;\n }\n\n canvas.toBlob(\n (\n blob,\n ) => {\n if (!blob) {\n reject(\n new Error(\n 'Failed to create PNG blob',\n ),\n );\n\n return;\n }\n\n resolve(blob);\n },\n 'image/png',\n );\n } catch (error) {\n reject(error);\n }\n },\n );\n};","import type {\n ExportOptions,\n DiagramData,\n GetTableHeight,\n} from './types';\n\nimport {\n calculateSvgDimensions,\n} from './calculateDimensions';\n\nimport {\n renderHighQuality,\n} from './renderHighQuality';\n\nimport {\n serializeSvg,\n createSvgUrl,\n prepareSvgForExport,\n} from './utils/serializer';\n\nimport {\n downloadBlob,\n generateFileName,\n canvasToBlob,\n} from './utils/download';\n\nexport interface ExportDiagramParams {\n svgRef: React.RefObject<SVGSVGElement>;\n\n diagramData?:\n | DiagramData\n | null;\n\n getTableHeight?:\n | GetTableHeight;\n\n projectName?: string;\n\n setExportAllTables?: (\n value: boolean,\n ) => void;\n\n showToast?: (\n message: string,\n type?: string,\n ) => void;\n}\n\n/**\n * Exports the complete SVG diagram regardless of the\n * visible viewport.\n *\n * The export process is:\n *\n * 1. Render all diagram content.\n * 2. Calculate the real SVG content bounds.\n * 3. Create an independent SVG clone.\n * 4. Set a viewBox covering the complete content.\n * 5. Apply the requested background.\n * 6. Convert the SVG to PNG when requested.\n *\n * Background examples:\n *\n * - 'white'\n * - 'transparent'\n * - '#C300FF'\n * - 'rgb(195, 0, 255)'\n * - 'rgba(195, 0, 255, 0.5)'\n */\nexport const exportDiagram = async (\n params: ExportDiagramParams,\n options: ExportOptions = {},\n): Promise<void> => {\n const {\n svgRef,\n diagramData,\n getTableHeight,\n projectName,\n setExportAllTables,\n showToast,\n } = params;\n\n const {\n format = 'png',\n background = 'white',\n scale = 2,\n margin = 100,\n fileName,\n onProgress,\n } = options;\n\n if (!svgRef.current) {\n onProgress?.({\n type: 'error',\n message:\n 'SVG reference not available',\n });\n\n return;\n }\n\n let objectUrl:\n string | null = null;\n\n try {\n onProgress?.({\n type: 'preparing',\n });\n\n showToast?.(\n 'Preparing export...',\n 'info',\n );\n\n /*\n * Tell the consuming application to render\n * all currently virtualized/cullable content.\n */\n setExportAllTables?.(\n true,\n );\n\n /*\n * Give React time to render the complete diagram.\n */\n await new Promise<void>(\n (resolve) => {\n setTimeout(\n resolve,\n 300,\n );\n },\n );\n\n onProgress?.({\n type: 'rendering',\n });\n\n const sourceSvg =\n svgRef.current;\n\n /*\n * Calculate the real SVG bounds.\n *\n * We intentionally do not use calculateDimensions()\n * because SVG content may extend beyond the viewport.\n */\n const dimensions =\n calculateSvgDimensions(\n sourceSvg,\n margin,\n );\n\n const {\n x,\n y,\n width,\n height,\n } = dimensions;\n\n /*\n * Prepare a completely independent SVG clone.\n *\n * The background is applied here for SVG exports\n * and is also preserved when converting to PNG.\n */\n const exportSvg =\n prepareSvgForExport(\n sourceSvg,\n width,\n height,\n background,\n margin,\n x,\n y,\n );\n\n onProgress?.({\n type: 'serializing',\n });\n\n /*\n * Serialize the prepared SVG.\n */\n const svgMarkup =\n serializeSvg(\n exportSvg,\n );\n\n /*\n * SVG export does not require canvas.\n */\n if (\n format === 'svg'\n ) {\n const blob =\n new Blob(\n [svgMarkup],\n {\n type:\n 'image/svg+xml;charset=utf-8',\n },\n );\n\n const finalFileName =\n fileName ||\n generateFileName(\n projectName,\n 'svg',\n );\n\n downloadBlob(\n blob,\n finalFileName,\n );\n\n onProgress?.({\n type: 'complete',\n });\n\n showToast?.(\n 'Export completed successfully',\n 'success',\n );\n\n return;\n }\n\n /*\n * Create an object URL for the SVG.\n */\n const image =\n new Image();\n\n objectUrl =\n createSvgUrl(\n svgMarkup,\n );\n\n await new Promise<void>(\n (\n resolve,\n reject,\n ) => {\n image.onload =\n () => {\n resolve();\n };\n\n image.onerror =\n () => {\n reject(\n new Error(\n 'Failed to load SVG image',\n ),\n );\n };\n\n image.src =\n objectUrl!;\n },\n );\n\n /*\n * Render the complete SVG into a high-quality canvas.\n *\n * The same background is passed to the canvas renderer,\n * allowing custom CSS colors for PNG exports.\n */\n const canvas =\n await renderHighQuality(\n image,\n width,\n height,\n scale,\n background,\n );\n\n onProgress?.({\n type: 'downloading',\n });\n\n /*\n * Convert the canvas to PNG.\n */\n const blob =\n await canvasToBlob(\n canvas,\n );\n\n const finalFileName =\n fileName ||\n generateFileName(\n projectName,\n 'png',\n );\n\n downloadBlob(\n blob,\n finalFileName,\n );\n\n onProgress?.({\n type: 'complete',\n });\n\n showToast?.(\n 'Export completed successfully',\n 'success',\n );\n } catch (error) {\n console.error(\n 'Export error:',\n error,\n );\n\n onProgress?.({\n type: 'error',\n message:\n 'Export failed',\n });\n\n showToast?.(\n 'Failed to export file',\n 'error',\n );\n } finally {\n /*\n * Always restore the normal rendering state.\n */\n setExportAllTables?.(\n false,\n );\n\n /*\n * Always release the object URL.\n */\n if (objectUrl) {\n URL.revokeObjectURL(\n objectUrl,\n );\n }\n }\n};"],"mappings":"AAAA,OACE,YAAAA,EACA,eAAAC,MACK,QCoBA,IAAMC,EAAsB,CACjCC,EAIAC,EAEAC,EAAiB,MACF,CACf,GACE,CAACF,GAAa,QAAQ,OAEtB,MAAO,CACL,MACE,IACAE,EAAS,EAEX,OACE,IACAA,EAAS,EAEX,EACE,CAACA,EAEH,EACE,CAACA,CACL,EAGF,IAAMC,EACJ,KAAK,IACH,GAAGH,EAAY,OAAO,IACnBI,GACCA,EAAM,CACV,CACF,EAEIC,EACJ,KAAK,IACH,GAAGL,EAAY,OAAO,IACnBI,GACCA,EAAM,CACV,CACF,EAEIE,EACJ,KAAK,IACH,GAAGN,EAAY,OAAO,IACnBI,GACCA,EAAM,EACN,IACA,EACJ,CACF,EAEIG,EACJ,KAAK,IACH,GAAGP,EAAY,OAAO,IACnBI,GACCA,EAAM,EACNH,EACEG,EAAM,MACR,EACA,EACJ,CACF,EAEF,MAAO,CACL,EACED,EACAD,EAEF,EACEG,EACAH,EAEF,MACE,KAAK,IACH,IACAI,EACEH,EACAD,EAAS,CACb,EAEF,OACE,KAAK,IACH,IACAK,EACEF,EACAH,EAAS,CACb,CACJ,CACF,EAgBaM,EACXC,GACsB,CACtB,IAAMC,EACJ,MAAM,KACJD,EAAI,iBACF,2EACF,CACF,EAEEN,EACF,IAEEE,EACF,IAEEC,EACF,KAEEC,EACF,KAEII,EACJ,CACEC,EACAC,EACAC,EACAC,IACG,CAED,CAAC,OAAO,SACNH,CACF,GACA,CAAC,OAAO,SACNC,CACF,GACA,CAAC,OAAO,SACNC,CACF,GACA,CAAC,OAAO,SACNC,CACF,GAMAD,EAAQ,GACRC,EAAS,IAKXZ,EACE,KAAK,IACHA,EACAS,CACF,EAEFP,EACE,KAAK,IACHA,EACAQ,CACF,EAEFP,EACE,KAAK,IACHA,EACAM,EAAIE,CACN,EAEFP,EACE,KAAK,IACHA,EACAM,EAAIE,CACN,EACJ,EAEF,QACQC,KAAWN,EAKjB,GACE,EAAAM,EAAQ,QACN,2BACF,GACAA,EAAQ,QACN,2BACF,GAKF,GAAI,CACF,IAAMC,EACJD,EAAQ,QAAQ,EAElBL,EACEM,EAAK,EACLA,EAAK,EACLA,EAAK,MACLA,EAAK,MACP,CACF,MAAQ,CAKR,CAGF,MACE,CAAC,OAAO,SACNd,CACF,GACA,CAAC,OAAO,SACNE,CACF,GACA,CAAC,OAAO,SACNC,CACF,GACA,CAAC,OAAO,SACNC,CACF,EAEO,KAGF,CACL,EACEJ,EAEF,EACEE,EAEF,MACE,KAAK,IACH,EACAC,EAAOH,CACT,EAEF,OACE,KAAK,IACH,EACAI,EAAOF,CACT,CACJ,CACF,EAUaa,EAAyB,CACpCT,EACAP,EAAiB,MACF,CACf,IAAMiB,EACJX,EACEC,CACF,EAEF,GAAIU,EACF,MAAO,CACL,EACEA,EAAO,EACPjB,EAEF,EACEiB,EAAO,EACPjB,EAEF,MACEiB,EAAO,MACPjB,EAAS,EAEX,OACEiB,EAAO,OACPjB,EAAS,CACb,EAMF,IAAMkB,EACJX,EAAI,SAAS,QAEf,GACEW,GACA,OAAO,SACLA,EAAQ,KACV,GACA,OAAO,SACLA,EAAQ,MACV,GACAA,EAAQ,MAAQ,GAChBA,EAAQ,OAAS,EAEjB,MAAO,CACL,EACEA,EAAQ,EACRlB,EAEF,EACEkB,EAAQ,EACRlB,EAEF,MACEkB,EAAQ,MACRlB,EAAS,EAEX,OACEkB,EAAQ,OACRlB,EAAS,CACb,EAMF,IAAMY,EACJ,OACEL,EAAI,aACF,OACF,CACF,GACAA,EAAI,aACJ,EAEIM,EACJ,OACEN,EAAI,aACF,QACF,CACF,GACAA,EAAI,cACJ,EAEF,MAAO,CACL,EACE,CAACP,EAEH,EACE,CAACA,EAEH,MACEY,EACAZ,EAAS,EAEX,OACEa,EACAb,EAAS,CACb,CACF,EAOamB,EACXZ,GACe,CACf,IAAMa,EACJb,EAAI,eACJA,EAAI,QACF,gBACF,GACAA,EAAI,QACF,kBACF,EAEEK,EACF,OACEL,EAAI,aACF,OACF,CACF,GACAA,EAAI,aACJ,EAEEM,EACF,OACEN,EAAI,aACF,QACF,CACF,GACAA,EAAI,cACJ,EAEF,OACEa,IAEAR,EACE,KAAK,IACHA,EACAQ,EAAgB,WAClB,EAEFP,EACE,KAAK,IACHA,EACAO,EAAgB,YAClB,GAGG,CACL,EAAG,EACH,EAAG,EACH,MAAAR,EACA,OAAAC,CACF,CACF,EClbO,IAAMQ,EAAoB,MAC/BC,EACAC,EACAC,EACAC,EAAgB,EAChBC,EAAqB,gBACU,CAG/B,IAAMC,EACJ,KAAK,IAAI,EAAGJ,CAAK,EAEbK,EACJ,KAAK,IAAI,EAAGJ,CAAM,EAEdK,EACJ,KAAK,IAAI,GAAKJ,CAAK,EAEfK,EAAiB,KAAK,IAC1BD,EACA,MACE,KAAK,IACHF,EACAC,EACA,CACF,CACJ,EAEMG,EACJ,SAAS,cACP,QACF,EAEFA,EAAO,MAAQ,KAAK,IAClB,EACA,KAAK,MACHJ,EACEG,CACJ,CACF,EAEAC,EAAO,OAAS,KAAK,IACnB,EACA,KAAK,MACHH,EACEE,CACJ,CACF,EAWA,IAAME,EACJD,EAAO,WACL,KACA,CACE,MAAO,EACT,CACF,EAEF,GAAI,CAACC,EACH,MAAM,IAAI,MACR,oCACF,EAGF,OAAAA,EAAQ,sBACN,GAEFA,EAAQ,sBACN,OAYAN,IAAe,eAEfM,EAAQ,UACNN,EAEFM,EAAQ,SACN,EACA,EACAD,EAAO,MACPA,EAAO,MACT,GAEAC,EAAQ,UACN,EACA,EACAD,EAAO,MACPA,EAAO,MACT,EAOFC,EAAQ,UACNV,EACA,EACA,EACAK,EACEG,EACFF,EACEE,CACJ,EAEOC,CACT,EChIO,IAAME,EACXC,GACW,CACX,IAAMC,EACJ,IAAI,cAEAC,EACJ,OAAO,SAAa,IAChB,iBACE,SAAS,eACX,EACA,KAEFC,EACFF,EAAW,kBACTD,CACF,EAEF,OAAIE,IACFC,EAASA,EAAO,QACd,oBACA,CACEC,EACAC,IAGEH,EACG,iBACC,KAAKG,CAAI,EACX,GACE,KAAK,GAGT,SAASA,CAAI,GAEnB,GAOCF,EAAO,SACN,oCACF,IAEAA,EAASA,EAAO,QACd,OACA,yCACF,GAGKA,CACT,EAKaG,EACXC,GAEO,IAAI,gBACT,IAAI,KACF,CAACA,CAAS,EACV,CACE,KACE,6BACJ,CACF,CACF,EAcWC,EAAsB,CACjCC,EACAC,EACAC,EACAC,EAAqB,cACrBC,EAAiB,EACjBC,EAAkB,EAClBC,EAAkB,IACA,CAClB,IAAMC,EACJP,EAAU,UACR,EACF,EAuDF,GA7CEO,EAAM,iBACJ,2BACF,EAEM,QACLC,GAAS,CACRA,EAAK,OAAO,CACd,CACF,EAKAD,EAAM,aACJ,QACA,OAAON,CAAK,CACd,EAEAM,EAAM,aACJ,SACA,OAAOL,CAAM,CACf,EAEAK,EAAM,aACJ,UACA,GAAGF,CAAO,IAAIC,CAAO,IAAIL,CAAK,IAAIC,CAAM,EAC1C,EAKAK,EAAM,aACJ,sBACA,eACF,EAYEJ,IAAe,cACf,CACA,IAAMM,EACJ,SAAS,gBACP,6BACA,MACF,EAEFA,EAAe,aACb,IACA,OAAOJ,CAAO,CAChB,EAEAI,EAAe,aACb,IACA,OAAOH,CAAO,CAChB,EAEAG,EAAe,aACb,QACA,OAAOR,CAAK,CACd,EAEAQ,EAAe,aACb,SACA,OAAOP,CAAM,CACf,EAEAO,EAAe,aACb,OACAN,CACF,EAKAI,EAAM,aACJE,EACAF,EAAM,UACR,CACF,CAQA,OAAOA,CACT,EChNO,IAAMG,EAAe,CAC1BC,EACAC,IACS,CACT,IAAMC,EACJ,IAAI,gBACFF,CACF,EAEIG,EACJ,SAAS,cACP,GACF,EAEFA,EAAK,KAAOD,EACZC,EAAK,SAAWF,EAEhB,GAAI,CACF,SAAS,MAAM,YACbE,CACF,EAEAA,EAAK,MAAM,EAEX,SAAS,MAAM,YACbA,CACF,CACF,MAAQ,CACNA,EAAK,MAAM,CACb,CAMA,WAAW,IAAM,CACf,IAAI,gBACFD,CACF,CACF,EAAG,GAAG,CACR,EAKaE,EAAmB,CAC9BC,EAGAC,IAmBO,IAbHD,GACA,WAEC,QACC,OACA,GACF,EACC,YAAY,EACZ,QACC,eACA,EACF,CAEc,IAAIC,CAAM,GAMjBC,EACXC,GAEO,IAAI,QACT,CACEC,EACAC,IACG,CACH,GAAI,CACF,GACE,OAAOF,EAAO,QACd,WACA,CACAE,EACE,IAAI,MACF,gCACF,CACF,EAEA,MACF,CAEAF,EAAO,OAEHR,GACG,CACH,GAAI,CAACA,EAAM,CACTU,EACE,IAAI,MACF,2BACF,CACF,EAEA,MACF,CAEAD,EAAQT,CAAI,CACd,EACA,WACF,CACF,OAASW,EAAO,CACdD,EAAOC,CAAK,CACd,CACF,CACF,ECpDK,IAAMC,EAAgB,MAC3BC,EACAC,EAAyB,CAAC,IACR,CAClB,GAAM,CACJ,OAAAC,EACA,YAAAC,EACA,eAAAC,EACA,YAAAC,EACA,mBAAAC,EACA,UAAAC,CACF,EAAIP,EAEE,CACJ,OAAAQ,EAAS,MACT,WAAAC,EAAa,QACb,MAAAC,EAAQ,EACR,OAAAC,EAAS,IACT,SAAAC,EACA,WAAAC,CACF,EAAIZ,EAEJ,GAAI,CAACC,EAAO,QAAS,CACnBW,IAAa,CACX,KAAM,QACN,QACE,6BACJ,CAAC,EAED,MACF,CAEA,IAAIC,EACc,KAElB,GAAI,CACFD,IAAa,CACX,KAAM,WACR,CAAC,EAEDN,IACE,sBACA,MACF,EAMAD,IACE,EACF,EAKA,MAAM,IAAI,QACPS,GAAY,CACX,WACEA,EACA,GACF,CACF,CACF,EAEAF,IAAa,CACX,KAAM,WACR,CAAC,EAED,IAAMG,EACJd,EAAO,QAQHe,EACJC,EACEF,EACAL,CACF,EAEI,CACJ,EAAAQ,EACA,EAAAC,EACA,MAAAC,EACA,OAAAC,CACF,EAAIL,EAQEM,EACJC,EACER,EACAK,EACAC,EACAb,EACAE,EACAQ,EACAC,CACF,EAEFP,IAAa,CACX,KAAM,aACR,CAAC,EAKD,IAAMY,EACJC,EACEH,CACF,EAKF,GACEf,IAAW,MACX,CACA,IAAMmB,EACJ,IAAI,KACF,CAACF,CAAS,EACV,CACE,KACE,6BACJ,CACF,EAEIG,EACJhB,GACAiB,EACExB,EACA,KACF,EAEFyB,EACEH,EACAC,CACF,EAEAf,IAAa,CACX,KAAM,UACR,CAAC,EAEDN,IACE,gCACA,SACF,EAEA,MACF,CAKA,IAAMwB,EACJ,IAAI,MAENjB,EACEkB,EACEP,CACF,EAEF,MAAM,IAAI,QACR,CACEV,EACAkB,IACG,CACHF,EAAM,OACJ,IAAM,CACJhB,EAAQ,CACV,EAEFgB,EAAM,QACJ,IAAM,CACJE,EACE,IAAI,MACF,0BACF,CACF,CACF,EAEFF,EAAM,IACJjB,CACJ,CACF,EAQA,IAAMoB,EACJ,MAAMC,EACJJ,EACAV,EACAC,EACAZ,EACAD,CACF,EAEFI,IAAa,CACX,KAAM,aACR,CAAC,EAKD,IAAMc,EACJ,MAAMS,EACJF,CACF,EAEIN,EACJhB,GACAiB,EACExB,EACA,KACF,EAEFyB,EACEH,EACAC,CACF,EAEAf,IAAa,CACX,KAAM,UACR,CAAC,EAEDN,IACE,gCACA,SACF,CACF,OAAS8B,EAAO,CACd,QAAQ,MACN,gBACAA,CACF,EAEAxB,IAAa,CACX,KAAM,QACN,QACE,eACJ,CAAC,EAEDN,IACE,wBACA,OACF,CACF,QAAE,CAIAD,IACE,EACF,EAKIQ,GACF,IAAI,gBACFA,CACF,CAEJ,CACF,ELnTO,IAAMwB,EAAmB,CAAC,CAC/B,OAAAC,EACA,YAAAC,EACA,eAAAC,EACA,YAAAC,CACF,IAOO,CACL,GAAM,CACJC,EACAC,CACF,EAAIC,EAAS,EAAK,EAEZ,CACJC,EACAC,CACF,EAAIF,EAAS,EAAK,EAEZG,EACJC,EACE,MACEC,EAAyB,CAAC,IACvB,CACHN,EACE,EACF,EAEA,GAAI,CACF,MAAMO,EACJ,CACE,OAAAZ,EACA,YAAAC,EACA,eAAAC,EACA,YAAAC,EACA,mBAAAK,CACF,EACAG,CACF,CACF,QAAE,CACAN,EACE,EACF,EAEAG,EACE,EACF,CACF,CACF,EACA,CACER,EACAC,EACAC,EACAC,CACF,CACF,EAEF,MAAO,CACL,YAAAC,EAEA,cACEK,EAEF,gBAAAF,EAEA,mBAAAC,CACF,CACF","names":["useState","useCallback","calculateDimensions","diagramData","getTableHeight","margin","minX","table","minY","maxX","maxY","getSvgContentBounds","svg","elements","updateBounds","x","y","width","height","element","bbox","calculateSvgDimensions","bounds","viewBox","getScrollDimensions","scrollContainer","renderHighQuality","image","width","height","scale","background","safeWidth","safeHeight","safeScale","effectiveScale","canvas","context","serializeSvg","svg","serializer","styles","markup","_match","name","createSvgUrl","svgMarkup","prepareSvgForExport","sourceSvg","width","height","background","margin","sourceX","sourceY","clone","node","backgroundRect","downloadBlob","blob","fileName","url","link","generateFileName","projectName","format","canvasToBlob","canvas","resolve","reject","error","exportDiagram","params","options","svgRef","diagramData","getTableHeight","projectName","setExportAllTables","showToast","format","background","scale","margin","fileName","onProgress","objectUrl","resolve","sourceSvg","dimensions","calculateSvgDimensions","x","y","width","height","exportSvg","prepareSvgForExport","svgMarkup","serializeSvg","blob","finalFileName","generateFileName","downloadBlob","image","createSvgUrl","reject","canvas","renderHighQuality","canvasToBlob","error","useDiagramExport","svgRef","diagramData","getTableHeight","projectName","isExporting","setIsExporting","useState","exportAllTables","setExportAllTables","handleExport","useCallback","options","exportDiagram"]}
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "ok-canvas-export",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "description": "Export complete SVG diagrams and canvases as high-quality images with full render pass to bypass viewport culling",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
7
8
  "types": "./dist/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
11
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
12
14
  }
13
15
  },
14
16
  "files": [
@@ -17,8 +19,8 @@
17
19
  "LICENSE"
18
20
  ],
19
21
  "scripts": {
20
- "build": "tsc --outDir dist",
21
- "build:types": "tsc --emitDeclarationOnly --outDir dist",
22
+ "build": "tsup",
23
+ "build:types": "tsup --dts",
22
24
  "prepublishOnly": "bun test && bun run build",
23
25
  "test": "bun test",
24
26
  "test:watch": "bun test --watch",
@@ -48,6 +50,7 @@
48
50
  "@types/react": "^19.2.18",
49
51
  "@types/react-dom": "^19.2.5",
50
52
  "happy-dom": "^20.11.6",
53
+ "tsup": "^8.0.0",
51
54
  "typescript": "^5.7.0"
52
55
  },
53
56
  "repository": {
@@ -1,47 +0,0 @@
1
- import type { DiagramData, GetTableHeight } from './types';
2
- export interface Dimensions {
3
- width: number;
4
- height: number;
5
- x: number;
6
- y: number;
7
- }
8
- /**
9
- * Calculates dimensions based on diagram data.
10
- *
11
- * This function is kept compatible with the original API and tests.
12
- *
13
- * It calculates the total diagram size from the table coordinates,
14
- * assuming the table width is 280px plus the configured padding.
15
- */
16
- export declare const calculateDimensions: (diagramData: DiagramData | undefined | null, getTableHeight: GetTableHeight, margin?: number) => Dimensions;
17
- /**
18
- * Calculates the visible bounds of an SVG's graphical content.
19
- *
20
- * This function is intended for generic SVG exports.
21
- *
22
- * It does NOT rely on:
23
- *
24
- * - width
25
- * - height
26
- * - viewport
27
- * - scroll container
28
- *
29
- * Instead, it attempts to determine the real graphical bounds.
30
- */
31
- export declare const getSvgContentBounds: (svg: SVGSVGElement) => Dimensions | null;
32
- /**
33
- * Calculates the dimensions that should be used for a real SVG export.
34
- *
35
- * The content bounds are preferred.
36
- *
37
- * The returned x/y values are important because the content does not
38
- * necessarily start at 0,0.
39
- */
40
- export declare const calculateSvgDimensions: (svg: SVGSVGElement, margin?: number) => Dimensions;
41
- /**
42
- * Calculates dimensions based on an SVG element and its scroll container.
43
- *
44
- * Kept for backwards compatibility.
45
- */
46
- export declare const getScrollDimensions: (svg: SVGSVGElement) => Dimensions;
47
- //# sourceMappingURL=calculateDimensions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculateDimensions.d.ts","sourceRoot":"","sources":["../src/calculateDimensions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK3D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,aAAa,WAAW,GAAG,SAAS,GAAG,IAAI,EAC3C,gBAAgB,cAAc,EAC9B,SAAQ,MAAY,KACnB,UAqDF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,GAC9B,KAAK,aAAa,KACjB,UAAU,GAAG,IAgFf,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GACjC,KAAK,aAAa,EAClB,SAAQ,MAAY,KACnB,UAmDF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,KAAK,aAAa,KACjB,UAkCF,CAAC"}
@@ -1,184 +0,0 @@
1
- const TABLE_WIDTH = 280;
2
- const TABLE_PADDING = 40;
3
- /**
4
- * Calculates dimensions based on diagram data.
5
- *
6
- * This function is kept compatible with the original API and tests.
7
- *
8
- * It calculates the total diagram size from the table coordinates,
9
- * assuming the table width is 280px plus the configured padding.
10
- */
11
- export const calculateDimensions = (diagramData, getTableHeight, margin = 100) => {
12
- if (!diagramData?.tables?.length) {
13
- return {
14
- width: 100 + margin * 2,
15
- height: 100 + margin * 2,
16
- x: -margin,
17
- y: -margin,
18
- };
19
- }
20
- const minX = Math.min(...diagramData.tables.map((table) => table.x));
21
- const minY = Math.min(...diagramData.tables.map((table) => table.y));
22
- const maxX = Math.max(...diagramData.tables.map((table) => table.x + TABLE_WIDTH + TABLE_PADDING));
23
- const maxY = Math.max(...diagramData.tables.map((table) => table.y +
24
- getTableHeight(table.fields) +
25
- TABLE_PADDING));
26
- /*
27
- * Keep the original expected behavior:
28
- *
29
- * width = maxX - minX
30
- * height = maxY - minY
31
- *
32
- * with margin added on both sides.
33
- */
34
- return {
35
- x: minX - margin,
36
- y: minY - margin,
37
- width: Math.max(100, maxX - minX + margin * 2),
38
- height: Math.max(100, maxY - minY + margin * 2),
39
- };
40
- };
41
- /**
42
- * Calculates the visible bounds of an SVG's graphical content.
43
- *
44
- * This function is intended for generic SVG exports.
45
- *
46
- * It does NOT rely on:
47
- *
48
- * - width
49
- * - height
50
- * - viewport
51
- * - scroll container
52
- *
53
- * Instead, it attempts to determine the real graphical bounds.
54
- */
55
- export const getSvgContentBounds = (svg) => {
56
- const elements = Array.from(svg.querySelectorAll('g, path, rect, circle, ellipse, line, polyline, polygon, text, use, image'));
57
- let minX = Infinity;
58
- let minY = Infinity;
59
- let maxX = -Infinity;
60
- let maxY = -Infinity;
61
- const updateBounds = (x, y, width, height) => {
62
- if (!Number.isFinite(x) ||
63
- !Number.isFinite(y) ||
64
- !Number.isFinite(width) ||
65
- !Number.isFinite(height)) {
66
- return;
67
- }
68
- if (width < 0 || height < 0) {
69
- return;
70
- }
71
- minX = Math.min(minX, x);
72
- minY = Math.min(minY, y);
73
- maxX = Math.max(maxX, x + width);
74
- maxY = Math.max(maxY, y + height);
75
- };
76
- for (const element of elements) {
77
- /*
78
- * Ignore the artificial canvas background.
79
- */
80
- if (element.matches('[data-export-bg="canvas"]') ||
81
- element.closest('[data-export-bg="canvas"]')) {
82
- continue;
83
- }
84
- try {
85
- const bbox = element.getBBox();
86
- updateBounds(bbox.x, bbox.y, bbox.width, bbox.height);
87
- }
88
- catch {
89
- /*
90
- * getBBox() can fail in environments where the SVG
91
- * has not been rendered yet.
92
- */
93
- }
94
- }
95
- if (!Number.isFinite(minX) ||
96
- !Number.isFinite(minY) ||
97
- !Number.isFinite(maxX) ||
98
- !Number.isFinite(maxY)) {
99
- return null;
100
- }
101
- return {
102
- x: minX,
103
- y: minY,
104
- width: Math.max(1, maxX - minX),
105
- height: Math.max(1, maxY - minY),
106
- };
107
- };
108
- /**
109
- * Calculates the dimensions that should be used for a real SVG export.
110
- *
111
- * The content bounds are preferred.
112
- *
113
- * The returned x/y values are important because the content does not
114
- * necessarily start at 0,0.
115
- */
116
- export const calculateSvgDimensions = (svg, margin = 100) => {
117
- const bounds = getSvgContentBounds(svg);
118
- if (bounds) {
119
- return {
120
- x: bounds.x - margin,
121
- y: bounds.y - margin,
122
- width: bounds.width + margin * 2,
123
- height: bounds.height + margin * 2,
124
- };
125
- }
126
- /*
127
- * Fallback to the SVG viewBox.
128
- */
129
- const viewBox = svg.viewBox?.baseVal;
130
- if (viewBox &&
131
- Number.isFinite(viewBox.width) &&
132
- Number.isFinite(viewBox.height) &&
133
- viewBox.width > 0 &&
134
- viewBox.height > 0) {
135
- return {
136
- x: viewBox.x - margin,
137
- y: viewBox.y - margin,
138
- width: viewBox.width + margin * 2,
139
- height: viewBox.height + margin * 2,
140
- };
141
- }
142
- /*
143
- * Final fallback to width/height attributes.
144
- */
145
- const width = Number(svg.getAttribute('width')) ||
146
- svg.clientWidth ||
147
- 1;
148
- const height = Number(svg.getAttribute('height')) ||
149
- svg.clientHeight ||
150
- 1;
151
- return {
152
- x: -margin,
153
- y: -margin,
154
- width: width + margin * 2,
155
- height: height + margin * 2,
156
- };
157
- };
158
- /**
159
- * Calculates dimensions based on an SVG element and its scroll container.
160
- *
161
- * Kept for backwards compatibility.
162
- */
163
- export const getScrollDimensions = (svg) => {
164
- const scrollContainer = svg.parentElement ||
165
- svg.closest('.overflow-auto') ||
166
- svg.closest('.overflow-scroll');
167
- let width = Number(svg.getAttribute('width')) ||
168
- svg.clientWidth ||
169
- 1;
170
- let height = Number(svg.getAttribute('height')) ||
171
- svg.clientHeight ||
172
- 1;
173
- if (scrollContainer) {
174
- width = Math.max(width, scrollContainer.scrollWidth);
175
- height = Math.max(height, scrollContainer.scrollHeight);
176
- }
177
- return {
178
- x: 0,
179
- y: 0,
180
- width,
181
- height,
182
- };
183
- };
184
- //# sourceMappingURL=calculateDimensions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculateDimensions.js","sourceRoot":"","sources":["../src/calculateDimensions.ts"],"names":[],"mappings":"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"}
@@ -1,23 +0,0 @@
1
- import type { ExportOptions, DiagramData, GetTableHeight } from './types';
2
- export interface ExportDiagramParams {
3
- svgRef: React.RefObject<SVGSVGElement>;
4
- diagramData: DiagramData;
5
- getTableHeight: GetTableHeight;
6
- projectName?: string;
7
- setExportAllTables?: (value: boolean) => void;
8
- showToast?: (message: string, type?: string) => void;
9
- }
10
- /**
11
- * Exports the complete SVG diagram regardless of the
12
- * visible viewport.
13
- *
14
- * The export process is:
15
- *
16
- * 1. Render all diagram content.
17
- * 2. Calculate the real SVG content bounds.
18
- * 3. Create an independent SVG clone.
19
- * 4. Set a viewBox covering the complete content.
20
- * 5. Convert the SVG to PNG when requested.
21
- */
22
- export declare const exportDiagram: (params: ExportDiagramParams, options?: ExportOptions) => Promise<void>;
23
- //# sourceMappingURL=exportDiagram.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"exportDiagram.d.ts","sourceRoot":"","sources":["../src/exportDiagram.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,cAAc,EACf,MAAM,SAAS,CAAC;AAsBjB,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,CACV,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,KACV,IAAI,CAAC;CACX;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,mBAAmB,EAC3B,UAAS,aAAkB,KAC1B,OAAO,CAAC,IAAI,CAoPd,CAAC"}