UNPKG

page-visualizer

Version:

TypeScript library for rendering and visualizing pages of digital books, comics, manga, or interactive content

3 lines (2 loc) 26 kB
import{z as t}from"zod";class e extends Error{constructor(t,e,r){super(t),this.code=e,this.details=r,this.name="PageVisualizerError"}}class r extends e{constructor(t,e){super(t,"VALIDATION_ERROR",e),this.name="ValidationError"}}class n extends e{constructor(t,e){super(t,"RENDERING_ERROR",e),this.name="RenderingError"}}var i=Object.freeze({__proto__:null,AssetLoadError:class extends e{constructor(t,e){super(t,"ASSET_LOAD_ERROR",e),this.name="AssetLoadError"}},PageVisualizerError:e,RenderingError:n,ValidationError:r});const o=t.union([t.number().positive(),t.string().regex(/^\d+(\.\d+)?(px|%|vw|vh|em|rem)$/)]),s=t.object({x:o,y:o,width:o,height:o,alignment:t.enum(["left","center","right","justify"]).optional()}),a=t.object({color:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/).optional(),image:t.string().url().optional(),gradient:t.string().optional()}),c=t.object({fontSize:t.union([t.number().positive(),t.string()]),fontFamily:t.string().min(1),fontStyle:t.enum(["normal","italic","oblique"]).optional(),fontWeight:t.union([t.number().min(100).max(900),t.enum(["normal","bold"])]).optional(),color:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/),lineHeight:t.number().positive().optional(),letterSpacing:t.number().optional(),textDecoration:t.enum(["none","underline","line-through"]).optional(),shadow:t.string().optional(),opacity:t.number().min(0).max(1).optional()}),l=t.object({width:t.number().nonnegative(),style:t.enum(["solid","dashed","dotted"]),color:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/),radius:t.number().nonnegative().optional()}),h=t.object({id:t.string().optional(),content:t.string(),position:s,formatting:c,zIndex:t.number().int().optional()}),d=t.object({id:t.string().optional(),src:t.string().url(),position:s,zIndex:t.number().int().optional(),altText:t.string().optional(),filters:t.array(t.string()).optional(),border:l.optional()}),g=t.object({type:t.enum(["absolute","grid","flex"]),columns:t.number().int().positive().optional(),rows:t.number().int().positive().optional(),direction:t.enum(["row","column"]).optional(),responsive:t.boolean().optional()}),u=t.object({target:t.string().min(1),type:t.enum(["fadeIn","slide","rotate"]),duration:t.number().positive(),delay:t.number().nonnegative().optional()}),m=t.object({id:t.string().min(1),type:t.enum(["button","link","input","custom"]),position:s,content:t.string().optional(),zIndex:t.number().int().optional(),onClick:t.function().optional(),onHover:t.function().optional(),onFocus:t.function().optional(),onBlur:t.function().optional()}),p=t.object({name:t.string().min(1),colors:t.object({primary:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/),secondary:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/),background:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/),text:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/),accent:t.string().regex(/^#[0-9A-Fa-f]{6}$|^rgb\(|^rgba\(|^hsl\(|^hsla\(/)}),fonts:t.object({primary:t.string().min(1),secondary:t.string().min(1),heading:t.string().min(1)}),spacing:t.object({small:t.number().positive(),medium:t.number().positive(),large:t.number().positive()})}),w=t.object({pageWidth:t.number().positive(),pageHeight:t.number().positive(),margin:t.object({top:t.number().nonnegative(),right:t.number().nonnegative(),bottom:t.number().nonnegative(),left:t.number().nonnegative()}),theme:t.union([t.enum(["light","dark"]),p])}),f=t.object({id:t.union([t.string(),t.number()]),background:a.optional(),textBlocks:t.array(h).optional(),images:t.array(d).optional(),layout:g.optional(),animations:t.array(u).optional(),interactiveElements:t.array(m).optional()}),b=t.object({container:t.instanceof(HTMLElement),mode:t.enum(["canvas","svg","dom"]).optional(),globalStyles:w.partial().optional(),onError:t.function().optional(),onLoad:t.function().optional(),onRender:t.function().optional()}),x=t.object({format:t.enum(["png","jpeg","pdf","svg"]),quality:t.number().min(0).max(1).optional(),filename:t.string().optional()}),y=e=>{try{return f.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid page data: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},v=e=>{try{return b.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid PageVisualizer options: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},S=e=>{try{return x.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid export options: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}};var A=Object.freeze({__proto__:null,animationSchema:u,backgroundSchema:a,customThemeSchema:p,exportOptionsSchema:x,globalStylesSchema:w,imageElementSchema:d,interactiveElementSchema:m,layoutOptionsSchema:g,pageSchema:f,pageVisualizerOptionsSchema:b,positionSchema:s,textBlockSchema:h,validateAnimation:e=>{try{return u.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid animation data: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validateBackground:e=>{try{return a.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid background data: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validateCustomTheme:e=>{try{return p.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid custom theme: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validateExportOptions:S,validateGlobalStyles:e=>{try{return w.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid global styles: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validateImageElement:e=>{try{return d.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid image element data: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validateInteractiveElement:e=>{try{return m.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid interactive element data: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validateLayoutOptions:e=>{try{return g.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid layout options: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validatePage:y,validatePageVisualizerOptions:v,validatePosition:e=>{try{return s.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid position data: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}},validateTextBlock:e=>{try{return h.parse(e)}catch(e){if(e instanceof t.ZodError)throw new r(`Invalid text block data: ${e.errors.map(t=>t.message).join(", ")}`,e.errors);throw e}}});const E=(t,e)=>{if("number"==typeof t)return t;const r=t.match(/^(\d+(?:\.\d+)?)(px|%|vw|vh|em|rem)$/);if(!r)throw new Error(`Invalid position value: ${t}`);const[,n,i]=r,o=parseFloat(n??"0");switch(i){case"px":default:return o;case"%":return o/100*e;case"vw":return o/100*window.innerWidth;case"vh":return o/100*window.innerHeight;case"em":case"rem":return 16*o}},I=t=>{const e=document.createElement("div");return e.textContent=t,e.innerHTML},R=t=>new Promise((e,r)=>{const n=new Image;n.crossOrigin="anonymous",n.onload=()=>e(n),n.onerror=()=>r(new Error(`Failed to load image: ${t}`)),n.src=t}),z=(t,e)=>{const r=document.createElement("canvas");return r.width=t,r.height=e,r.style.display="block",r},T=(t,e)=>{const r=document.createElementNS("http://www.w3.org/2000/svg","svg");return r.setAttribute("width",t.toString()),r.setAttribute("height",e.toString()),r.setAttribute("viewBox",`0 0 ${t} ${e}`),r},P=(t,e)=>{const r="number"==typeof e.fontSize?e.fontSize:E(e.fontSize,16);if(t.font=`${e.fontStyle||"normal"} ${e.fontWeight||"normal"} ${r}px ${e.fontFamily}`,t.fillStyle=e.color,t.globalAlpha=e.opacity??1,e.shadow){const r=e.shadow.split(" ");r.length>=3&&(t.shadowColor=r[2]??"transparent",t.shadowOffsetX=parseFloat(r[0]??"0")||0,t.shadowOffsetY=parseFloat(r[1]??"0")||0,t.shadowBlur=parseFloat(r[3]??"0")||0)}e.letterSpacing},C=(t,e,r,n,i,o="left")=>{if(t.textAlign=o,t.textBaseline="top","justify"===o){const o=e.split(" ");if(o.length>1){const s=t.measureText(" ").width,a=(i-t.measureText(e).width)/(o.length-1);let c=r;for(let e=0;e<o.length;e++){const r=o[e];r&&(t.fillText(r,c,n),c+=t.measureText(r).width+s+a)}}else t.fillText(e,r,n)}else t.fillText(e,r,n)},k=(t,e,r,n,i,o)=>{t.strokeStyle=o.color,t.lineWidth=o.width,t.setLineDash("dashed"===o.style?[5,5]:"dotted"===o.style?[2,2]:[]),o.radius?(t.beginPath(),t.roundRect(e,r,n,i,o.radius),t.stroke()):t.strokeRect(e,r,n,i)},$=(t,e)=>{if(0===e.length)return;const r=e.join(" ");t.filter=r},D=(t,e,r)=>{if(!r)return{width:t.measureText(e).width,height:parseFloat(t.font)||16,lines:[e]};const n=e.split(" "),i=[];let o="";for(const e of n){const n=o+(o?" ":"")+e;t.measureText(n).width>r&&o?(i.push(o),o=e):o=n}o&&i.push(o);const s=parseFloat(t.font)||16,a=i.length*s;return{width:Math.max(...i.map(e=>t.measureText(e).width)),height:a,lines:i}},j=(t,e)=>{let r;return(...n)=>{clearTimeout(r),r=setTimeout(()=>t(...n),e)}},F=t=>{if(null===t||"object"!=typeof t)return t;if(t instanceof Date)return new Date(t.getTime());if(t instanceof Array)return t.map(t=>F(t));if("object"==typeof t){const e={};for(const r in t)t.hasOwnProperty(r)&&(e[r]=F(t[r]));return e}return t};var O=Object.freeze({__proto__:null,applyImageFilters:$,applyTextFormatting:P,createCanvas:z,createSVG:T,debounce:j,deepClone:F,drawBorder:k,drawText:C,generateId:()=>Math.random().toString(36).substr(2,9),getTextMetrics:D,isInViewport:t=>{const e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&e.right<=(window.innerWidth||document.documentElement.clientWidth)},loadImage:R,parsePositionValue:E,positionToAbsolute:(t,e,r)=>({x:E(t.x,e),y:E(t.y,r),width:E(t.width,e),height:E(t.height,r)}),sanitizeHtml:I,throttle:(t,e)=>{let r;return(...n)=>{r||(t(...n),r=!0,setTimeout(()=>r=!1,e))}}});class M{constructor(t){this.loadedImages=new Map,this.context=t}async renderPage(t){if(!this.context.canvas||!this.context.ctx)throw new Error("Canvas context not available");const{ctx:e,width:r,height:n}=this.context;e.clearRect(0,0,r,n);try{if(t.background&&await this.renderBackground(t.background,r,n),t.images){const e=[...t.images].sort((t,e)=>(t.zIndex||0)-(e.zIndex||0));for(const t of e)await this.renderImage(t,r,n)}if(t.textBlocks){const e=[...t.textBlocks].sort((t,e)=>(t.zIndex||0)-(e.zIndex||0));for(const t of e)this.renderTextBlock(t,r,n)}t.animations&&this.applyAnimations(t.animations)}catch(t){throw console.error("Error rendering page:",t),t}}async renderBackground(t,e,r){if(!this.context.ctx)return;const{ctx:n}=this.context;if(t.color&&(n.fillStyle=t.color,n.fillRect(0,0,e,r)),t.gradient){const i=t.gradient.match(/linear-gradient\((\d+)deg,\s*([^,]+),\s*([^)]+)\)/);if(i){const[,t,o,s]=i,a=parseFloat(t??"0")*Math.PI/180,c=n.createLinearGradient(Math.cos(a)*e,Math.sin(a)*r,Math.cos(a+Math.PI)*e,Math.sin(a+Math.PI)*r);c.addColorStop(0,(o??"").trim()),c.addColorStop(1,(s??"").trim()),n.fillStyle=c,n.fillRect(0,0,e,r)}}if(t.image)try{const i=await this.loadImage(t.image);n.drawImage(i,0,0,e,r)}catch(t){console.warn("Failed to load background image:",t)}}renderTextBlock(t,e,r){if(!this.context.ctx)return;const{ctx:n}=this.context,{x:i,y:o,width:s,height:a}=this.parsePosition(t.position,e,r);P(n,t.formatting);const c=t.position.alignment||"left";let l=i;"center"===c?l=i+s/2:"right"===c&&(l=i+s);const h=D(n,t.content,s),d=E(t.formatting.lineHeight||t.formatting.fontSize,16);let g=o;for(const t of h.lines)C(n,t,l,g,s,c),g+=d;"underline"===t.formatting.textDecoration&&(n.beginPath(),n.moveTo(i,g-2),n.lineTo(i+s,g-2),n.stroke())}async renderImage(t,e,r){if(!this.context.ctx)return;const{ctx:n}=this.context,{x:i,y:o,width:s,height:a}=this.parsePosition(t.position,e,r);try{const e=await this.loadImage(t.src);t.filters&&t.filters.length>0&&$(n,t.filters),n.drawImage(e,i,o,s,a),t.border&&k(n,i,o,s,a,t.border)}catch(e){console.warn("Failed to load image:",t.src,e),n.fillStyle="#f0f0f0",n.fillRect(i,o,s,a),n.fillStyle="#666",n.font="14px Arial",n.textAlign="center",n.fillText("Image not found",i+s/2,o+a/2)}}applyAnimations(t){for(const e of t){const t=document.getElementById(e.target);t&&(t.style.transition=`all ${e.duration}ms ease`,t.style.opacity="0",setTimeout(()=>{t.style.opacity="1"},e.delay||0))}}async loadImage(t){if(this.loadedImages.has(t))return this.loadedImages.get(t);const e=await R(t);return this.loadedImages.set(t,e),e}parsePosition(t,e,r){return{x:E(t.x,e),y:E(t.y,r),width:E(t.width,e),height:E(t.height,r)}}resize(t,e){this.context.canvas&&(this.context.canvas.width=t,this.context.canvas.height=e,this.context.width=t,this.context.height=e)}clear(){if(!this.context.ctx)return;const{ctx:t,width:e,height:r}=this.context;t.clearRect(0,0,e,r)}getDataURL(t="image/png",e){if(!this.context.canvas)throw new Error("Canvas not available");return"image/jpeg"===t&&e?this.context.canvas.toDataURL(t,e):this.context.canvas.toDataURL(t)}destroy(){this.animationFrameId&&cancelAnimationFrame(this.animationFrameId),this.loadedImages.clear()}}class N{constructor(t){this.loadedImages=new Map,this.context=t}async renderPage(t){if(!this.context.svg)throw new Error("SVG context not available");const{svg:e,width:r,height:n}=this.context;e.innerHTML="";try{if(t.background&&await this.renderBackground(t.background,r,n),t.images){const e=[...t.images].sort((t,e)=>(t.zIndex||0)-(e.zIndex||0));for(const t of e)await this.renderImage(t,r,n)}if(t.textBlocks){const e=[...t.textBlocks].sort((t,e)=>(t.zIndex||0)-(e.zIndex||0));for(const t of e)this.renderTextBlock(t,r,n)}t.animations&&this.applyAnimations(t.animations)}catch(t){throw console.error("Error rendering page:",t),t}}async renderBackground(t,e,r){if(!this.context.svg)return;const{svg:n}=this.context;if(t.color){const i=document.createElementNS("http://www.w3.org/2000/svg","rect");i.setAttribute("x","0"),i.setAttribute("y","0"),i.setAttribute("width",e.toString()),i.setAttribute("height",r.toString()),i.setAttribute("fill",t.color),n.appendChild(i)}if(t.gradient){const i=`gradient-${Math.random().toString(36).substr(2,9)}`,o=t.gradient.match(/linear-gradient\((\d+)deg,\s*([^,]+),\s*([^)]+)\)/);if(o){const[,t,s,a]=o,c=document.createElementNS("http://www.w3.org/2000/svg","defs"),l=document.createElementNS("http://www.w3.org/2000/svg","linearGradient");l.setAttribute("id",i),l.setAttribute("x1","0%"),l.setAttribute("y1","0%"),l.setAttribute("x2","100%"),l.setAttribute("y2","100%"),l.setAttribute("gradientTransform",`rotate(${t})`);const h=document.createElementNS("http://www.w3.org/2000/svg","stop");h.setAttribute("offset","0%"),h.setAttribute("stop-color",(s??"").trim());const d=document.createElementNS("http://www.w3.org/2000/svg","stop");d.setAttribute("offset","100%"),d.setAttribute("stop-color",(a??"").trim()),l.appendChild(h),l.appendChild(d),c.appendChild(l),n.appendChild(c);const g=document.createElementNS("http://www.w3.org/2000/svg","rect");g.setAttribute("x","0"),g.setAttribute("y","0"),g.setAttribute("width",e.toString()),g.setAttribute("height",r.toString()),g.setAttribute("fill",`url(#${i})`),n.appendChild(g)}}if(t.image)try{const i=await this.loadImageAsDataURL(t.image),o=document.createElementNS("http://www.w3.org/2000/svg","image");o.setAttribute("x","0"),o.setAttribute("y","0"),o.setAttribute("width",e.toString()),o.setAttribute("height",r.toString()),o.setAttribute("href",i),o.setAttribute("preserveAspectRatio","xMidYMid slice"),n.appendChild(o)}catch(t){console.warn("Failed to load background image:",t)}}renderTextBlock(t,e,r){if(!this.context.svg)return;const{svg:n}=this.context,{x:i,y:o,width:s,height:a}=this.parsePosition(t.position,e,r),c=document.createElementNS("http://www.w3.org/2000/svg","text");c.setAttribute("x",i.toString()),c.setAttribute("y",(o+E(t.formatting.fontSize,16)).toString()),c.setAttribute("width",s.toString()),c.setAttribute("height",a.toString()),this.applyTextFormatting(c,t.formatting);const l=t.position.alignment||"left";"center"===l?(c.setAttribute("text-anchor","middle"),c.setAttribute("x",(i+s/2).toString())):"right"===l&&(c.setAttribute("text-anchor","end"),c.setAttribute("x",(i+s).toString()));const h=this.wrapText(t.content,t.formatting,s);if(1===h.length)c.textContent=I(h[0]??""),n.appendChild(c);else{const e=E(t.formatting.lineHeight||t.formatting.fontSize,16);for(let t=0;t<h.length;t++){const r=document.createElementNS("http://www.w3.org/2000/svg","tspan");r.setAttribute("x",c.getAttribute("x")||"0"),r.setAttribute("dy",0===t?"0":e.toString()),r.textContent=I(h[t]??""),c.appendChild(r)}n.appendChild(c)}if("underline"===t.formatting.textDecoration){const e=document.createElementNS("http://www.w3.org/2000/svg","line");e.setAttribute("x1",i.toString()),e.setAttribute("y1",(o+a-2).toString()),e.setAttribute("x2",(i+s).toString()),e.setAttribute("y2",(o+a-2).toString()),e.setAttribute("stroke",t.formatting.color),e.setAttribute("stroke-width","1"),n.appendChild(e)}}async renderImage(t,e,r){if(!this.context.svg)return;const{svg:n}=this.context,{x:i,y:o,width:s,height:a}=this.parsePosition(t.position,e,r);try{const e=await this.loadImageAsDataURL(t.src),r=document.createElementNS("http://www.w3.org/2000/svg","image");if(r.setAttribute("x",i.toString()),r.setAttribute("y",o.toString()),r.setAttribute("width",s.toString()),r.setAttribute("height",a.toString()),r.setAttribute("href",e),r.setAttribute("preserveAspectRatio","xMidYMid meet"),t.altText&&r.setAttribute("alt",t.altText),t.filters&&t.filters.length>0){const e=`filter-${Math.random().toString(36).substr(2,9)}`;this.createFilter(e,t.filters),r.setAttribute("filter",`url(#${e})`)}n.appendChild(r),t.border&&this.drawBorder(i,o,s,a,t.border)}catch(e){console.warn("Failed to load image:",t.src,e);const r=document.createElementNS("http://www.w3.org/2000/svg","rect");r.setAttribute("x",i.toString()),r.setAttribute("y",o.toString()),r.setAttribute("width",s.toString()),r.setAttribute("height",a.toString()),r.setAttribute("fill","#f0f0f0"),r.setAttribute("stroke","#ccc"),r.setAttribute("stroke-width","1"),n.appendChild(r);const c=document.createElementNS("http://www.w3.org/2000/svg","text");c.setAttribute("x",(i+s/2).toString()),c.setAttribute("y",(o+a/2).toString()),c.setAttribute("text-anchor","middle"),c.setAttribute("fill","#666"),c.setAttribute("font-family","Arial"),c.setAttribute("font-size","14"),c.textContent="Image not found",n.appendChild(c)}}applyAnimations(t){for(const e of t){const t=document.getElementById(e.target);t&&(t.style.transition=`all ${e.duration}ms ease`,t.style.opacity="0",setTimeout(()=>{t.style.opacity="1"},e.delay||0))}}async loadImageAsDataURL(t){if(this.loadedImages.has(t))return this.loadedImages.get(t);const e=await R(t),r=document.createElement("canvas"),n=r.getContext("2d");r.width=e.width,r.height=e.height,n.drawImage(e,0,0);const i=r.toDataURL("image/png");return this.loadedImages.set(t,i),i}parsePosition(t,e,r){return{x:E(t.x,e),y:E(t.y,r),width:E(t.width,e),height:E(t.height,r)}}applyTextFormatting(t,e){const r="number"==typeof e.fontSize?e.fontSize:E(e.fontSize,16);if(t.setAttribute("font-family",e.fontFamily),t.setAttribute("font-size",r.toString()),t.setAttribute("fill",e.color),e.fontStyle&&t.setAttribute("font-style",e.fontStyle),e.fontWeight&&t.setAttribute("font-weight",e.fontWeight.toString()),e.letterSpacing&&t.setAttribute("letter-spacing",e.letterSpacing.toString()),e.opacity&&t.setAttribute("opacity",e.opacity.toString()),e.shadow){const r=e.shadow.split(" ");if(r.length>=3){const e=`shadow-${Math.random().toString(36).substr(2,9)}`;this.createShadowFilter(e,r),t.setAttribute("filter",`url(#${e})`)}}}wrapText(t,e,r){const n=t.split(" "),i=[];let o="";for(const t of n){const n=o+(o?" ":"")+t,s="number"==typeof e.fontSize?e.fontSize:E(e.fontSize,16);n.length*s*.6>r&&o?(i.push(o),o=t):o=n}return o&&i.push(o),i}createFilter(t,e){if(!this.context.svg)return;let r=this.context.svg.querySelector("defs");r||(r=document.createElementNS("http://www.w3.org/2000/svg","defs"),this.context.svg.appendChild(r));const n=document.createElementNS("http://www.w3.org/2000/svg","filter");n.setAttribute("id",t);for(const t of e)if(t.includes("blur")){const e=t.match(/blur\((\d+)px\)/);if(e){const t=document.createElementNS("http://www.w3.org/2000/svg","feGaussianBlur");t.setAttribute("stdDeviation",e[1]??"0"),n.appendChild(t)}}r.appendChild(n)}createShadowFilter(t,e){if(!this.context.svg)return;let r=this.context.svg.querySelector("defs");r||(r=document.createElementNS("http://www.w3.org/2000/svg","defs"),this.context.svg.appendChild(r));const n=document.createElementNS("http://www.w3.org/2000/svg","filter");n.setAttribute("id",t);const i=document.createElementNS("http://www.w3.org/2000/svg","feDropShadow");i.setAttribute("dx",e[0]||"0"),i.setAttribute("dy",e[1]||"0"),i.setAttribute("stdDeviation",e[3]||"0"),i.setAttribute("flood-color",e[2]||"#000"),n.appendChild(i),r.appendChild(n)}drawBorder(t,e,r,n,i){if(!this.context.svg)return;const{svg:o}=this.context,s=document.createElementNS("http://www.w3.org/2000/svg","rect");s.setAttribute("x",t.toString()),s.setAttribute("y",e.toString()),s.setAttribute("width",r.toString()),s.setAttribute("height",n.toString()),s.setAttribute("fill","none"),s.setAttribute("stroke",i.color),s.setAttribute("stroke-width",i.width.toString()),"dashed"===i.style?s.setAttribute("stroke-dasharray","5,5"):"dotted"===i.style&&s.setAttribute("stroke-dasharray","2,2"),i.radius&&(s.setAttribute("rx",i.radius.toString()),s.setAttribute("ry",i.radius.toString())),o.appendChild(s)}resize(t,e){this.context.svg&&(this.context.svg.setAttribute("width",t.toString()),this.context.svg.setAttribute("height",e.toString()),this.context.svg.setAttribute("viewBox",`0 0 ${t} ${e}`),this.context.width=t,this.context.height=e)}getDataURL(){if(!this.context.svg)throw new Error("SVG not available");const t=(new XMLSerializer).serializeToString(this.context.svg);return`data:image/svg+xml,${encodeURIComponent(t)}`}clear(){this.context.svg&&(this.context.svg.innerHTML="")}destroy(){this.loadedImages.clear()}}var B={PageVisualizer:class{constructor(t){this.currentPage=null,this.isDestroyed=!1,this.options=v(t);const e={pageWidth:800,pageHeight:600,margin:{top:20,right:20,bottom:20,left:20},theme:"light",...this.options.globalStyles};this.context=this.createRenderingContext(e),this.renderer=this.createRenderer(),this.initializeContainer()}async renderPage(t){if(this.isDestroyed)throw new e("PageVisualizer has been destroyed","DESTROYED");try{const e=y(t);this.currentPage=e,this.updateContextForPage(e),await this.renderer.renderPage(e),this.options.onRender?.()}catch(t){const e=new n(`Failed to render page: ${t instanceof Error?t.message:"Unknown error"}`,t);throw this.options.onError?.(e),e}}async exportPage(t){if(this.isDestroyed)throw new e("PageVisualizer has been destroyed","DESTROYED");if(!this.currentPage)throw new e("No page to export","NO_PAGE");try{const r=S(t);if("canvas"===this.options.mode&&this.renderer instanceof M)return this.renderer.getDataURL(r.format,r.quality);if("svg"===this.options.mode&&this.renderer instanceof N)return this.renderer.getDataURL();throw new e("Export not supported for current rendering mode","UNSUPPORTED_EXPORT")}catch(t){const r=new e(`Failed to export page: ${t instanceof Error?t.message:"Unknown error"}`,"EXPORT_ERROR",t);throw this.options.onError?.(r),r}}resize(t,r){if(this.isDestroyed)throw new e("PageVisualizer has been destroyed","DESTROYED");this.context.width=t,this.context.height=r,this.context.scale=Math.min(t/(this.options.globalStyles?.pageWidth??800),r/(this.options.globalStyles?.pageHeight??600)),this.renderer.resize(t,r),this.currentPage&&this.renderPage(this.currentPage).catch(t=>{this.options.onError?.(t)})}clear(){this.isDestroyed||(this.renderer.clear(),this.currentPage=null)}getCurrentPage(){return this.currentPage}getContext(){return{...this.context}}updateGlobalStyles(t){this.isDestroyed||(this.options.globalStyles={...this.options.globalStyles,...t},this.context.width=this.options.globalStyles?.pageWidth??800,this.context.height=this.options.globalStyles?.pageHeight??600,this.currentPage&&this.renderPage(this.currentPage).catch(t=>{this.options.onError?.(t)}))}destroy(){this.isDestroyed||(this.isDestroyed=!0,this.renderer.destroy(),this.resizeObserver&&this.resizeObserver.disconnect(),this.options.container&&(this.options.container.innerHTML=""),this.currentPage=null,this.context=null,this.renderer=null)}createRenderingContext(t){const{pageWidth:r,pageHeight:n}=t,i={width:r,height:n,scale:1};switch(this.options.mode){case"canvas":const t=z(r,n),o=t.getContext("2d");if(!o)throw new e("Failed to get 2D context from canvas","CANVAS_ERROR");i.canvas=t,i.ctx=o;break;case"svg":const s=T(r,n);i.svg=s;break;case"dom":i.container=this.options.container;break;default:throw new e(`Unsupported rendering mode: ${this.options.mode}`,"UNSUPPORTED_MODE")}return i}createRenderer(){switch(this.options.mode){case"canvas":return new M(this.context);case"svg":return new N(this.context);case"dom":throw new e("DOM renderer not yet implemented","NOT_IMPLEMENTED");default:throw new e(`Unsupported rendering mode: ${this.options.mode}`,"UNSUPPORTED_MODE")}}initializeContainer(){const{container:t}=this.options;t.innerHTML="",this.context.canvas?t.appendChild(this.context.canvas):this.context.svg&&t.appendChild(this.context.svg),t.style.position="relative",t.style.overflow="hidden",this.options.onLoad?.()}updateContextForPage(t){}setupResizeHandling(){if("undefined"!=typeof ResizeObserver)this.resizeObserver=new ResizeObserver(j(t=>{for(const e of t){const{width:t,height:r}=e.contentRect;this.resize(t,r)}},100)),this.resizeObserver.observe(this.options.container);else{const t=j(()=>{const t=this.options.container.getBoundingClientRect();this.resize(t.width,t.height)},100);window.addEventListener("resize",t)}}},...i,...A,...O,CanvasRenderer:M,SVGRenderer:N};export{B as default}; //# sourceMappingURL=index.esm.js.map