@8btc/whiteboard 0.0.5 → 0.0.7

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.umd.js CHANGED
@@ -1,3 +1,3479 @@
1
- (function(d,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react"),require("konva"),require("mitt"),require("uuid"),require("@radix-ui/react-slot"),require("class-variance-authority"),require("clsx"),require("tailwind-merge"),require("lucide-react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","konva","mitt","uuid","@radix-ui/react-slot","class-variance-authority","clsx","tailwind-merge","lucide-react"],c):(d=typeof globalThis<"u"?globalThis:d||self,c(d.konvaWhiteboard={},d.jsxRuntime,d.React,d.Konva,d.mitt,d.uuid,d.ReactSlot,d.ClassVarianceAuthority,d.clsx,d.tailwindMerge,d.LucideReact))})(this,(function(d,c,m,I,jt,K,Ft,qt,Wt,$t,tt){"use strict";var Se=Object.defineProperty;var Rt=d=>{throw TypeError(d)};var Ne=(d,c,m)=>c in d?Se(d,c,{enumerable:!0,configurable:!0,writable:!0,value:m}):d[c]=m;var V=(d,c,m)=>Ne(d,typeof c!="symbol"?c+"":c,m),bt=(d,c,m)=>c.has(d)||Rt("Cannot "+m);var a=(d,c,m)=>(bt(d,c,"read from private field"),m?m.call(d):c.get(d)),p=(d,c,m)=>c.has(d)?Rt("Cannot add the same private member more than once"):c instanceof WeakSet?c.add(d):c.set(d,m),S=(d,c,m,I)=>(bt(d,c,"write to private field"),I?I.call(d,m):c.set(d,m),m),M=(d,c,m)=>(bt(d,c,"access private method"),m);var w,g,Y,et,rt,it,ot,at,st,nt,lt,Ut,G,x,ct,ht,dt,gt,pt,ut,mt,Vt,_,Z,kt,St,Lt,z,Nt,Ot,Mt,_t,L,P,B,J,ft,Ht,b,A,R,k;var Et=document.createElement("style");Et.textContent=`@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-cyan-500:oklch(71.5% .143 215.221);--color-cyan-600:oklch(60.9% .126 221.723);--color-cyan-700:oklch(52% .105 223.128);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-purple-500:oklch(62.7% .265 303.9);--color-purple-600:oklch(55.8% .288 302.321);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--font-weight-medium:500;--font-weight-bold:700;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){*{outline-color:color-mix(in oklab,var(--ring)50%,transparent)}}body{background-color:var(--background);color:var(--foreground)}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.static{position:static}.top-0{top:calc(var(--spacing)*0)}.top-4{top:calc(var(--spacing)*4)}.right-4{right:calc(var(--spacing)*4)}.bottom-4{bottom:calc(var(--spacing)*4)}.left-0{left:calc(var(--spacing)*0)}.left-4{left:calc(var(--spacing)*4)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-10{width:calc(var(--spacing)*10);height:calc(var(--spacing)*10)}.size-full{width:100%;height:100%}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-\\[500px\\]{height:500px}.h-full{height:100%}.max-h-40{max-height:calc(var(--spacing)*40)}.w-\\[700px\\]{width:700px}.w-full{width:100%}.max-w-xs{max-width:var(--container-xs)}.min-w-16{min-width:calc(var(--spacing)*16)}.shrink-0{flex-shrink:0}.-translate-x-1\\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.touch-none{touch-action:none}.resize{resize:both}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1\\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.overflow-auto{overflow:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.bg-background{background-color:var(--background)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-cyan-500{background-color:var(--color-cyan-500)}.bg-cyan-600{background-color:var(--color-cyan-600)}.bg-destructive{background-color:var(--destructive)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-green-500{background-color:var(--color-green-500)}.bg-indigo-500{background-color:var(--color-indigo-500)}.bg-primary{background-color:var(--primary)}.bg-purple-500{background-color:var(--color-purple-500)}.bg-red-500{background-color:var(--color-red-500)}.bg-secondary{background-color:var(--secondary)}.bg-white{background-color:var(--color-white)}.p-2{padding:calc(var(--spacing)*2)}.p-4{padding:calc(var(--spacing)*4)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-2{padding-block:calc(var(--spacing)*2)}.pt-4{padding-top:calc(var(--spacing)*4)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-gray-400{color:var(--color-gray-400)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-white{color:var(--color-white)}.underline-offset-4{text-underline-offset:4px}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}@media(hover:hover){.hover\\:bg-accent:hover{background-color:var(--accent)}.hover\\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\\:bg-cyan-600:hover{background-color:var(--color-cyan-600)}.hover\\:bg-cyan-700:hover{background-color:var(--color-cyan-700)}.hover\\:bg-destructive\\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.hover\\:bg-destructive\\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}.hover\\:bg-gray-200:hover{background-color:var(--color-gray-200)}.hover\\:bg-green-600:hover{background-color:var(--color-green-600)}.hover\\:bg-indigo-600:hover{background-color:var(--color-indigo-600)}.hover\\:bg-primary\\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){.hover\\:bg-primary\\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}.hover\\:bg-purple-600:hover{background-color:var(--color-purple-600)}.hover\\:bg-red-600:hover{background-color:var(--color-red-600)}.hover\\:bg-secondary\\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\\:bg-secondary\\/80:hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.hover\\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\\:underline:hover{text-decoration-line:underline}}.focus-visible\\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\\:ring-\\[3px\\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\\:ring-destructive\\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.focus-visible\\:ring-destructive\\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.focus-visible\\:ring-ring\\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){.focus-visible\\:ring-ring\\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--ring)50%,transparent)}}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}.has-\\[\\>svg\\]\\:px-2\\.5:has(>svg){padding-inline:calc(var(--spacing)*2.5)}.has-\\[\\>svg\\]\\:px-3:has(>svg){padding-inline:calc(var(--spacing)*3)}.has-\\[\\>svg\\]\\:px-4:has(>svg){padding-inline:calc(var(--spacing)*4)}.aria-invalid\\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\\:ring-destructive\\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.aria-invalid\\:ring-destructive\\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.dark\\:border-input:is(.dark *){border-color:var(--input)}.dark\\:bg-destructive\\/60:is(.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\\:bg-destructive\\/60:is(.dark *){background-color:color-mix(in oklab,var(--destructive)60%,transparent)}}.dark\\:bg-input\\/30:is(.dark *){background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\\:bg-input\\/30:is(.dark *){background-color:color-mix(in oklab,var(--input)30%,transparent)}}@media(hover:hover){.dark\\:hover\\:bg-accent\\/50:is(.dark *):hover{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.dark\\:hover\\:bg-accent\\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--accent)50%,transparent)}}.dark\\:hover\\:bg-input\\/50:is(.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\\:hover\\:bg-input\\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}}.dark\\:focus-visible\\:ring-destructive\\/40:is(.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\\:focus-visible\\:ring-destructive\\/40:is(.dark *):focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\\:aria-invalid\\:ring-destructive\\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\\:aria-invalid\\:ring-destructive\\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.\\[\\&_svg\\]\\:pointer-events-none svg{pointer-events:none}.\\[\\&_svg\\]\\:shrink-0 svg{flex-shrink:0}.\\[\\&_svg\\:not\\(\\[class\\*\\=\\'size-\\'\\]\\)\\]\\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}:root{--radius:.625rem;--background:oklch(100% 0 0);--foreground:oklch(14.5% 0 0);--card:oklch(100% 0 0);--card-foreground:oklch(14.5% 0 0);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.5% 0 0);--primary:oklch(20.5% 0 0);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(97% 0 0);--secondary-foreground:oklch(20.5% 0 0);--muted:oklch(97% 0 0);--muted-foreground:oklch(55.6% 0 0);--accent:oklch(97% 0 0);--accent-foreground:oklch(20.5% 0 0);--destructive:oklch(57.7% .245 27.325);--border:oklch(92.2% 0 0);--input:oklch(92.2% 0 0);--ring:oklch(70.8% 0 0);--chart-1:oklch(64.6% .222 41.116);--chart-2:oklch(60% .118 184.704);--chart-3:oklch(39.8% .07 227.392);--chart-4:oklch(82.8% .189 84.429);--chart-5:oklch(76.9% .188 70.08);--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.5% 0 0);--sidebar-primary:oklch(20.5% 0 0);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(97% 0 0);--sidebar-accent-foreground:oklch(20.5% 0 0);--sidebar-border:oklch(92.2% 0 0);--sidebar-ring:oklch(70.8% 0 0)}.dark{--background:oklch(14.5% 0 0);--foreground:oklch(98.5% 0 0);--card:oklch(20.5% 0 0);--card-foreground:oklch(98.5% 0 0);--popover:oklch(20.5% 0 0);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(92.2% 0 0);--primary-foreground:oklch(20.5% 0 0);--secondary:oklch(26.9% 0 0);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(26.9% 0 0);--muted-foreground:oklch(70.8% 0 0);--accent:oklch(26.9% 0 0);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.6% 0 0);--chart-1:oklch(48.8% .243 264.376);--chart-2:oklch(69.6% .17 162.48);--chart-3:oklch(76.9% .188 70.08);--chart-4:oklch(62.7% .265 303.9);--chart-5:oklch(64.5% .246 16.439);--sidebar:oklch(20.5% 0 0);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(48.8% .243 264.376);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(26.9% 0 0);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.6% 0 0)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}
2
- /*$vite$:1*/`,document.head.appendChild(Et);class Gt{constructor(r,t){p(this,lt);p(this,w);p(this,g);p(this,Y,{x:0,y:0,scale:1});p(this,et,r=>{r.evt.preventDefault();const e=a(this,g).getPointerPosition();if(e)if(r.evt.ctrlKey){const i=a(this,Y).scale,o={x:(e.x-a(this,Y).x)/i,y:(e.y-a(this,Y).y)/i},s=1.01,l=r.evt.deltaY>0?-1:1,h=Math.min(Math.abs(r.evt.deltaY),10);let u=i;for(let y=0;y<h;y++)u=l>0?u*s:u/s;const f=Math.max(.1,Math.min(5,u)),N={x:e.x-o.x*f,y:e.y-o.y*f};a(this,w).updateViewport({x:N.x,y:N.y,scale:f})}else{const i=r.evt.shiftKey?r.evt.deltaY:r.evt.deltaX,o=r.evt.shiftKey?0:r.evt.deltaY;a(this,w).updateViewport({x:a(this,Y).x-i,y:a(this,Y).y-o})}});p(this,rt,r=>{const t=a(this,w).getState().toolType;if(r.evt.button!==0||t==="hand")return;const e=r.target===a(this,g),i=a(this,g).getRelativePointerPosition();if(t==="select"&&!e){const o=r.target.id();o&&a(this,w).selectNode(o,r.evt.shiftKey);return}if(t==="rectangle"&&i&&a(this,w).createDraftNode(t,i),t==="image-marker"&&i){const o=a(this,w).findImageAtPosition(i);if(console.log(o,"imageShape"),o){const s=o.width(),l=o.height();if(s&&l){const h={x:o.x(),y:o.y(),width:s,height:l};a(this,w).createDraftNode(t,i,{parent:o.id(),bounds:h,startPosition:i})}}}a(this,w).selectNode()});p(this,it,()=>{const r=a(this,w).getState().toolType;if(r==="hand")return;const t=a(this,g).getRelativePointerPosition();(r==="rectangle"||r==="image-marker")&&t&&a(this,w).updateDraftNode(t)});p(this,ot,()=>{const r=a(this,w).getState().toolType;r!=="hand"&&(r==="rectangle"||r==="image-marker")&&a(this,w).finalizeDraftNode()});p(this,at,r=>{if(r.target!==a(this,g))return;const t=a(this,w).getState().toolType;t==="hand"?this.setCursor("grabbing"):t==="select"&&this.setCursor("all-scroll")});p(this,st,r=>{r.target===a(this,g)&&a(this,w).updateViewport({x:a(this,g).x(),y:a(this,g).y()})});p(this,nt,r=>{r.target===a(this,g)&&(a(this,w).updateViewport({x:a(this,g).x(),y:a(this,g).y()}),this.resetCursor())});S(this,w,r),S(this,g,new I.Stage({container:t.container,width:t.width,height:t.height,x:0,y:0,scaleX:1,scaleY:1,draggable:t.draggable??!1,className:t.className})),M(this,lt,Ut).call(this)}getStage(){return a(this,g)}getViewport(){return{...a(this,Y)}}setViewport(r){const t={...a(this,Y),...r};S(this,Y,t),r.x!==void 0&&a(this,g).x(r.x),r.y!==void 0&&a(this,g).y(r.y),r.scale!==void 0&&(a(this,g).scaleX(r.scale),a(this,g).scaleY(r.scale)),r.width!==void 0&&a(this,g).width(r.width),r.height!==void 0&&a(this,g).height(r.height)}setDraggable(r){a(this,g).draggable(r)}setCursor(r){const t=a(this,g).container();t.style.cursor=r}resetCursor(){const r=a(this,g).container();if(a(this,w).getState().toolType==="hand"){r.style.cursor="grab";return}r.style.cursor="default"}destroy(){a(this,g).destroy()}}w=new WeakMap,g=new WeakMap,Y=new WeakMap,et=new WeakMap,rt=new WeakMap,it=new WeakMap,ot=new WeakMap,at=new WeakMap,st=new WeakMap,nt=new WeakMap,lt=new WeakSet,Ut=function(){a(this,g).on("wheel",a(this,et)),a(this,g).on("pointerdown",a(this,rt)),a(this,g).on("pointermove",a(this,it)),a(this,g).on("pointerup",a(this,ot)),a(this,g).on("dragstart",a(this,at)),a(this,g).on("dragmove",a(this,st)),a(this,g).on("dragend",a(this,nt))};class Bt{constructor(r,t){p(this,mt);p(this,G);p(this,x);p(this,ct,()=>{this.emitPositionChange()});p(this,ht,()=>{console.log("transforming..."),this.emitPositionChange()});p(this,dt,()=>{this.emitPositionChange()});p(this,gt,()=>{this.emitPositionChange()});p(this,pt,()=>{this.emitPositionChange()});p(this,ut,()=>{this.emitPositionChange()});S(this,G,r),S(this,x,new I.Transformer({rotateEnabled:t?.rotateEnabled??!0,ignoreStroke:t?.ignoreStroke??!0,anchorSize:t?.anchorSize??8,borderDash:t?.borderDash??[4,4],anchorCornerRadius:t?.anchorCornerRadius??4,padding:t?.padding??6})),M(this,mt,Vt).call(this)}getTransformer(){return a(this,x)}getPosition(){if(a(this,x).nodes().length===0)return null;const t=a(this,x).getClientRect();return{x:t.x,y:t.y,width:t.width,height:t.height,rotation:a(this,x).rotation()}}setNodes(r){if(r.length===0){this.clearNodes();return}a(this,x).nodes(r),a(this,x).moveToTop(),this.emitPositionChange()}getNodes(){return a(this,x).nodes()}clearNodes(){a(this,x).nodes([]),a(this,x).moveToBottom(),this.emitPositionChange()}emitPositionChange(){const r=this.getPosition();a(this,G).emitEvent("transformer:positionChange",r)}destroy(){a(this,x).destroy()}}G=new WeakMap,x=new WeakMap,ct=new WeakMap,ht=new WeakMap,dt=new WeakMap,gt=new WeakMap,pt=new WeakMap,ut=new WeakMap,mt=new WeakSet,Vt=function(){a(this,x).on("transformstart",a(this,ct)),a(this,x).on("transform",a(this,ht)),a(this,x).on("transformend",a(this,dt)),a(this,x).on("dragstart",a(this,gt)),a(this,x).on("dragmove",a(this,pt)),a(this,x).on("dragend",a(this,ut))};class Jt{constructor(r){V(this,"_past",[]);V(this,"_present");V(this,"_future",[]);V(this,"_emitter");this._present=r,this._emitter=jt()}getState(){return{...this._present}}getHistory(){return{past:[...this._past],present:{...this._present},future:[...this._future]}}canUndo(){return this._past.length>0}canRedo(){return this._future.length>0}on(r,t){this._emitter.on(r,t)}off(r,t){this._emitter.off(r,t)}emit(r,t){this._emitter.emit(r,t)}undo(){if(this._past.length===0)return;const r=this._past[this._past.length-1],t=this._past.slice(0,this._past.length-1);this._past=t,this._future=[this._present,...this._future],this._present=r,this._syncState(r),this._emitter.emit("state:undo",r),this._emitter.emit("state:change",r)}redo(){if(this._future.length===0)return;const r=this._future[0],t=this._future.slice(1);this._past=[...this._past,this._present],this._future=t,this._present=r,this._syncState(r),this._emitter.emit("state:redo",r),this._emitter.emit("state:change",r)}resetHistory(){this._past=[],this._future=[],this._emitter.emit("state:reset",this._present),this._emitter.emit("state:change",this._present)}_updateState(r,t=!0){const e={...this._present,...r};t&&(this._past=[...this._past,this._present],this._future=[]),this._present=e,this._emitter.emit("state:change",e)}_syncState(r){}_dispose(){this._emitter.all.clear()}}const W="shapeNameForSelect",v={CORNER_RADIUS:6,MIN_SIZE:10},q={MIN_SIZE:10},It={MIN_SIZE:10};function Qt(n,r,t){return 2*(r+n-t*(4-Math.PI))}function Kt(n,r,t){let e=1,i=0,o=0;switch(t){case"dashed":i=Math.min(r*2,n/4);break;case"dotted":e=8,i=r/e;break;default:return[]}let s=Math.floor(n/i/(2*e));return s=Math.max(s,3),i=n/s/(2*e),o=(n-s*i)/s,[i,o]}function te(n){switch(n){case"small":return 2;case"medium":return 3;case"large":return 5;case"extra-large":return 8;default:return 3}}function ee(n){return Array.isArray(n)&&n.length>1?n[0]+n[1]:0}function Ct(n){return{width:Math.max(It.MIN_SIZE,n.width()*n.scaleX()),height:Math.max(It.MIN_SIZE,n.height()*n.scaleY())}}class vt{constructor(r,t){V(this,"core");V(this,"node");V(this,"element");V(this,"toolTypeChangeHandler");this.core=r,this.node=t,this.element=this.createElement(),this.toolTypeChangeHandler=e=>{const i=e==="select";this.element.listening(i)},this.toolTypeChangeHandler(this.core.getToolType()),this.core.on("toolType:change",this.toolTypeChangeHandler)}getElement(){return this.element}getNode(){return this.node}destroy(){this.core.off("toolType:change",this.toolTypeChangeHandler),this.element.destroy()}}function re(n,r){if(!r||r===0)return null;const t=new I.Animation(e=>{if(!e)return;const i=-e.time/10%r;n.dashOffset(i)},n.getLayer());return{start:()=>t.start(),stop:()=>t.stop(),isRunning:()=>t.isRunning()}}class ie extends vt{constructor(t,e){super(t,e);p(this,Z);p(this,_,null);e.style.animated&&M(this,Z,kt).call(this),M(this,Z,Lt).call(this,this.getElement())}createElement(){const t=Math.max(this.node.props.width??v.MIN_SIZE,v.MIN_SIZE),e=Math.max(this.node.props.height??v.MIN_SIZE,v.MIN_SIZE),i={id:this.node.id,...this.node.props,...this.node.style,width:t,height:e,cornerRadius:v.CORNER_RADIUS,name:W,draggable:!0,stroke:"black",strokeWidth:2},o=new I.Rect(i);return o.setAttrs({width:t,height:e}),o}getElement(){return this.element}updateNode(t){this.node={...this.node,...t,props:{...this.node.props,...t.props},style:{...this.node.style,...t.style}};const e=this.getElement();e.x(this.node.props.x),e.y(this.node.props.y);const i=Math.max(this.node.props.width??v.MIN_SIZE,v.MIN_SIZE),o=Math.max(this.node.props.height??v.MIN_SIZE,v.MIN_SIZE);e.width(i),e.height(o),this.node.style.animated&&!a(this,_)?M(this,Z,kt).call(this):!this.node.style.animated&&a(this,_)&&M(this,Z,St).call(this)}destroy(){M(this,Z,St).call(this),super.destroy()}}_=new WeakMap,Z=new WeakSet,kt=function(){const t=this.getElement(),e=t.dash();if(!e||e.length===0)return;const i=ee(e);S(this,_,re(t,i)),a(this,_)&&a(this,_).start()},St=function(){a(this,_)&&(a(this,_).stop(),S(this,_,null))},Lt=function(t=void 0){const e=t??this.getElement();e.on("transformstart",()=>{this.node.style.animated&&a(this,_)&&a(this,_).stop()}),e.on("transform",i=>{const o=i.target,{width:s,height:l}=Ct(o),h=Qt(s,l,v.CORNER_RADIUS),u=Kt(h,te(this.node.style.size),this.node.style.line);o.scale({x:1,y:1}),o.width(s),o.height(l),o.dash(u.map(f=>f*this.core.getStageScale()))}),e.on("transformend",i=>{const o=i.target,{width:s,height:l}=Ct(o),h={...this.node.props,x:o.x(),y:o.y(),width:s,height:l,rotation:o.rotation()};this.node.props=h,this.core._syncNodeFromElement(this.node.id,{props:h}),this.node.style.animated&&a(this,_)?.isRunning()===!1&&a(this,_).start()}),e.on("dragend",i=>{const o=i.target,s={...this.node.props,x:o.x(),y:o.y()};this.node.props=s,this.core._syncNodeFromElement(this.node.id,{props:s})})};class oe extends vt{constructor(t,e){super(t,e);p(this,z);M(this,z,Nt).call(this),M(this,z,Ot).call(this,this.getElement())}createElement(){const t=document.createElement("canvas");return t.width=1,t.height=1,new I.Image({id:this.node.id,x:this.node.props.x,y:this.node.props.y,name:W,draggable:!0,image:t})}getElement(){return this.element}updateNode(t){this.node={...this.node,...t,props:{...this.node.props,...t.props},style:{...this.node.style,...t.style},meta:{...this.node.meta,...t.meta}};const e=this.getElement();if(e.x(this.node.props.x),e.y(this.node.props.y),this.node.props.width&&this.node.props.height){const i=Math.max(this.node.props.width,q.MIN_SIZE),o=Math.max(this.node.props.height,q.MIN_SIZE);e.width(i),e.height(o)}this.node.props.rotation!==void 0&&e.rotation(this.node.props.rotation),t.meta?.imageUrl&&t.meta.imageUrl!==this.node.meta.imageUrl&&M(this,z,Nt).call(this)}destroy(){super.destroy()}}z=new WeakSet,Nt=function(){const t=this.node.meta.imageUrl;if(!t){console.warn("Image URL is missing");return}const e=new window.Image;e.crossOrigin="anonymous",e.src=t,e.onload=()=>{this.getElement().image(e);const i=this.node.props.width??e.width,o=this.node.props.height??e.height;this.getElement().width(Math.max(i,q.MIN_SIZE)),this.getElement().height(Math.max(o,q.MIN_SIZE))},e.onerror=()=>{console.error("Failed to load image:",t)}},Ot=function(t){t.on("transform",e=>{const i=e.target,o=Math.max(q.MIN_SIZE,i.width()*i.scaleX()),s=Math.max(q.MIN_SIZE,i.height()*i.scaleY());i.scale({x:1,y:1}),i.width(o),i.height(s),M(this,z,Mt).call(this)}),t.on("transformend",e=>{const i=e.target,o={...this.node.props,x:i.x(),y:i.y(),width:i.width(),height:i.height(),rotation:i.rotation()};this.node.props=o,this.core._syncNodeFromElement(this.node.id,{props:o}),M(this,z,_t).call(this)}),t.on("dragmove",()=>{M(this,z,Mt).call(this)}),t.on("dragend",e=>{const i=e.target,o={...this.node.props,x:i.x(),y:i.y()};this.node.props=o,this.core._syncNodeFromElement(this.node.id,{props:o}),M(this,z,_t).call(this)})},Mt=function(){const t=this.getElement(),e=t.getLayer();if(!e)return;const i=t.x(),o=t.y(),s=t.width(),l=t.height(),h=e.find(f=>f.hasName(this.node.id)),u=this.core.getState().nodes||[];h.forEach(f=>{const N=u.find(y=>y.id===f.id());if(N?.type==="image-marker"&&N.meta.relativePosition){const{start:y,end:C}=N.meta.relativePosition,E=i+y.percentX/100*s,T=o+y.percentY/100*l,U=i+C.percentX/100*s,X=o+C.percentY/100*l,wt=Math.min(E,U),j=Math.min(T,X),O=Math.abs(U-E),Q=Math.abs(X-T);f.position({x:wt,y:j}),f.setAttrs({width:O,height:Q}),f.getChildren().forEach(D=>{D.getClassName()==="Rect"?D.setAttrs({width:O,height:Q}):D.getClassName()==="Group"&&D.setAttrs({x:O,y:Q})})}})},_t=function(){const e=this.getElement().getLayer();if(!e)return;e.find(o=>o.hasName(this.node.id)).forEach(o=>{this.core._syncNodeFromElement(o.id(),{props:{x:o.x(),y:o.y(),width:o.width(),height:o.height()}})})};class ae extends vt{constructor(t,e){super(t,e);p(this,ft);p(this,L);p(this,P);p(this,B);p(this,J);const i=this.getElement();S(this,L,i.findOne(".rect")),S(this,P,i.findOne(".marker-group")),S(this,B,a(this,P).findOne("Circle")),S(this,J,a(this,P).findOne("Text")),M(this,ft,Ht).call(this)}createElement(){const t=Math.max(this.node.props.width??v.MIN_SIZE,v.MIN_SIZE),e=Math.max(this.node.props.height??v.MIN_SIZE,v.MIN_SIZE),i=new I.Group({id:this.node.id,name:`static ${this.node.meta.parent}`,x:this.node.props.x,y:this.node.props.y,width:t,height:e}),o=new I.Rect({name:"rect",x:0,y:0,width:t,height:e,stroke:this.node.style.color,strokeWidth:2,dash:[5,5],fill:"transparent",cornerRadius:v.CORNER_RADIUS}),s=new I.Group({name:"marker-group",x:t,y:e}),h=16/this.core.getStageScale(),u=new I.Circle({radius:h,fill:"red",stroke:"black",strokeWidth:2}),f=new I.Text({x:-h,y:-h,width:h*2,height:h*2,text:String(this.node.meta.markerNumber||""),align:"center",verticalAlign:"middle",fontSize:16,fill:"white"});return s.add(u),s.add(f),i.add(o),i.add(s),i}getElement(){return this.element}updateNode(t){this.node={...this.node,...t,props:{...this.node.props,...t.props},style:{...this.node.style,...t.style},meta:{...this.node.meta,...t.meta}};const e=this.getElement();e.x(this.node.props.x),e.y(this.node.props.y);const i=Math.max(this.node.props.width??v.MIN_SIZE,v.MIN_SIZE),o=Math.max(this.node.props.height??v.MIN_SIZE,v.MIN_SIZE);e.width(i),e.height(o),a(this,L).width(i),a(this,L).height(o),a(this,P).x(i),a(this,P).y(o),t.style?.color&&a(this,L).stroke(t.style.color),t.meta?.markerNumber!==void 0&&a(this,J).text(String(t.meta.markerNumber))}destroy(){super.destroy()}setFocusState(t){const e=t?3:2,i=t?1.2:1;a(this,L).strokeWidth(e),a(this,B).strokeWidth(e),a(this,P).scaleX(i),a(this,P).scaleY(i)}}L=new WeakMap,P=new WeakMap,B=new WeakMap,J=new WeakMap,ft=new WeakSet,Ht=function(){a(this,P).on("pointerover",()=>{this.setFocusState(!0),this.core.setCursor("pointer")}),a(this,P).on("pointerout",()=>{const e=(this.core.getState().selectedNodeIds||[]).includes(this.node.id);this.setFocusState(e),this.core.resetCursor()}),a(this,P).on("pointerdown",()=>{this.core.selectNode(this.node.id)})};function Tt(n,r,t){switch(r){case"rectangle":return new ie(n,t);case"image":return new oe(n,t);case"image-marker":return new ae(n,t);default:return null}}const se=(n,r,t,e)=>{const i={type:n,id:K.v4(),text:null,style:{opacity:1,line:"solid",color:"black",size:"medium",animated:!1},props:{x:r.x,y:r.y,rotation:0,visible:!0},meta:e??{}};return n==="image-marker"?{...i,style:{...i.style,color:"#ff0000",line:"dashed"}}:i};function ne(n,r,t){let e=r;n.type==="image-marker"&&t&&(e={x:Math.max(t.x,Math.min(t.x+t.width,r.x)),y:Math.max(t.y,Math.min(t.y+t.height,r.y))});const[i,o]=le({x:n.props.x,y:n.props.y},e);return n.type==="rectangle"||n.type==="image-marker"?{...n,props:{...n.props,x:i.x,y:i.y,width:Math.max(o.x-i.x,v.MIN_SIZE),height:Math.max(o.y-i.y,v.MIN_SIZE)}}:n}function le(n,r){let t=n.x,e=n.y,i=r.x,o=r.y,s;return t>i&&(s=Math.abs(t-i),t=i,i=t+s),e>o&&(s=Math.abs(e-o),e=o,o=e+s),[{x:t,y:e},{x:i,y:o}]}class ce extends Jt{constructor(t){super({viewport:{x:0,y:0,width:t.clientWidth,height:t.clientHeight,scale:1},toolType:"select",nodes:[]});p(this,b);p(this,A);p(this,R);p(this,k,null);S(this,b,new Gt(this,{container:t,width:t.clientWidth,height:t.clientHeight,draggable:!1,className:"touch-none"})),S(this,A,new I.Layer),S(this,R,new Bt(this)),a(this,b).getStage().add(a(this,A)),a(this,A).add(a(this,R).getTransformer()),this.updateViewport(this.getState().viewport,!1)}getCanvasStage(){return a(this,b)}getCanvasTransformer(){return a(this,R)}emitEvent(t,e){this.emit(t,e)}getStage(){return a(this,b).getStage()}getContainer(){return a(this,b).getStage().container()}getMainLayer(){return a(this,A)}getToolType(){return this.getState().toolType}setToolType(t){this.selectNode(),this._updateState({toolType:t},!1),this.emit("toolType:change",t),t==="hand"?(a(this,b).setDraggable(!0),a(this,b).setCursor("grab")):(a(this,b).setDraggable(!1),a(this,b).resetCursor())}setDraggable(t){a(this,b).setDraggable(t)}setCursor(t){a(this,b).setCursor(t)}resetCursor(){a(this,b).resetCursor()}getStageScale(){return a(this,b).getStage().scaleX()}updateViewport(t,e=!1){a(this,b).setViewport(t);const i={...this.getState().viewport,...t};this._updateState({viewport:i},e),this.emit("viewport:change",i),a(this,R).emitPositionChange()}createNodes(t){t.map(o=>Tt(this,o.type,o)).filter(o=>o!==null).forEach(o=>{a(this,A).add(o.getElement())});const i=[...this.getState().nodes||[],...t];this._updateState({nodes:i},!0)}createImageMarkerNode(t,e,i,o){const s=this.getState().nodes||[];let l=0;s.forEach(X=>{X.type==="image-marker"&&X.meta.parent===t&&typeof X.meta.markerNumber=="number"&&(l=Math.max(l,X.meta.markerNumber))});const h=(e.x-o.x)/o.width*100,u=(e.y-o.y)/o.height*100,f=(i.x-o.x)/o.width*100,N=(i.y-o.y)/o.height*100,y=Math.min(e.x,i.x),C=Math.min(e.y,i.y),E=Math.abs(i.x-e.x),T=Math.abs(i.y-e.y),U={id:K.v4(),type:"image-marker",props:{x:y,y:C,width:E,height:T,rotation:0,visible:!0},style:{color:"#ff0000",line:"dashed",size:"medium",opacity:1},meta:{parent:t,markerNumber:l+1,relativePosition:{start:{percentX:Math.max(0,Math.min(100,h)),percentY:Math.max(0,Math.min(100,u))},end:{percentX:Math.max(0,Math.min(100,f)),percentY:Math.max(0,Math.min(100,N))}}}};this.createNodes([U])}findImageAtPosition(t){const e=a(this,b).getStage(),i=e.find(s=>s.getClassName()==="Image"),o=i.map(s=>s.listening());i.forEach(s=>s.listening(!0));try{const l=e.getAllIntersections(t).filter(h=>h.getClassName()==="Image");return l.length===0?null:l[l.length-1]}finally{i.forEach((s,l)=>{s.listening(o[l])})}}createDraftNode(t,e,i){a(this,k)&&a(this,k).destroy();const o=se(t,e,void 0,i);S(this,k,Tt(this,t,o)),console.log(a(this,k)),a(this,k)&&a(this,A).add(a(this,k).getElement())}updateDraftNode(t,e){if(!a(this,k))return;const i=a(this,k).getNode(),o=ne(i,t,e);a(this,k).updateNode(o)}finalizeDraftNode(){if(!a(this,k))return;const t=K.v4(),e=a(this,k).getNode();if(e.type==="image-marker"&&e.meta.parent){const o=e.meta.bounds,s=e.meta.startPosition,l={x:e.props.x+(e.props.width||0),y:e.props.y+(e.props.height||0)},h=this.getState().nodes||[];let u=0;h.forEach(T=>{T.type==="image-marker"&&T.meta.parent===e.meta.parent&&typeof T.meta.markerNumber=="number"&&(u=Math.max(u,T.meta.markerNumber))});const f=(s.x-o.x)/o.width*100,N=(s.y-o.y)/o.height*100,y=(l.x-o.x)/o.width*100,C=(l.y-o.y)/o.height*100,E={...e,props:{...e.props},style:{...e.style},meta:{parent:e.meta.parent,markerNumber:u+1,relativePosition:{start:{percentX:Math.max(0,Math.min(100,f)),percentY:Math.max(0,Math.min(100,N))},end:{percentX:Math.max(0,Math.min(100,y)),percentY:Math.max(0,Math.min(100,C))}}},id:t,type:"image-marker"};this.createNodes([E]),a(this,k).destroy(),S(this,k,null),this.setToolType("select");return}const i={...e,props:{...e.props},style:{...e.style},meta:{...e.meta},id:t};this.createNodes([i]),a(this,k).destroy(),S(this,k,null),this.setToolType("select")}selectNode(t,e=!1){const i=this.getState().selectedNodeIds??[];if(i.length===0&&!t)return;if(!t){a(this,R).clearNodes(),this._updateState({selectedNodeIds:[]},!1);return}let o=[];e?o=i.length?[...i,t]:[t]:o=[t];const s=this.getStage().find(`.${W}`).filter(l=>{const h=l.id();return o.includes(h)});a(this,R).setNodes(s),this._updateState({selectedNodeIds:o},!1)}dispose(){this.getCanvasTransformer().destroy(),this.getMainLayer().destroy(),this.getCanvasStage().destroy(),this._dispose()}_syncNodeFromElement(t,e){const i=this.getState().nodes||[],o=i.findIndex(h=>h.id===t);if(o===-1)return;const s={...i[o],...e,props:{...i[o].props,...e.props},style:{...i[o].style,...e.style},meta:{...i[o].meta,...e.meta}},l=[...i];l[o]=s,this._updateState({nodes:l},!0)}_syncState(t){a(this,b).setViewport({x:t.viewport.x,y:t.viewport.y,scale:t.viewport.scale,width:t.viewport.width,height:t.viewport.height})}}b=new WeakMap,A=new WeakMap,R=new WeakMap,k=new WeakMap;class zt extends ce{getAvailableTools(){return["select","hand","rectangle","image-marker"]}setToolType(r){super.setToolType(r)}createNodes(r){super.createNodes(r)}updateViewport(r,t=!1){super.updateViewport(r,t)}createImageNode(r,t){const e=t??{x:100,y:100},i={id:K.v4(),type:"image",props:{x:e.x,y:e.y,width:void 0,height:void 0,rotation:0,visible:!0},style:{color:"#000000",line:"solid",size:"medium",opacity:1},meta:{imageUrl:r}};this.createNodes([i])}exportAsImage(r){const t=this.getStage(),e=this.getCanvasTransformer().getTransformer(),i=e.visible();e.visible(!1);try{return t.toDataURL({pixelRatio:r?.pixelRatio??2,mimeType:r?.mimeType??"image/png",quality:r?.quality??1})}finally{e.visible(i)}}exportSelectionAsImage(r){const t=this.getCanvasTransformer().getPosition();if(!t)return console.warn("No selection to export"),null;const e=this.getStage(),i=r?.padding??0,o=this.getCanvasTransformer().getTransformer(),s=o.visible();o.visible(!1);try{return e.toDataURL({x:t.x-i,y:t.y-i,width:t.width+i*2,height:t.height+i*2,pixelRatio:r?.pixelRatio??1,mimeType:r?.mimeType??"image/png",quality:r?.quality??1})}finally{o.visible(s)}}deleteSelectedNodes(){const r=this.getState().selectedNodeIds||[];r.length!==0&&this.deleteNodes(r)}deleteNodes(r){if(r.length===0)return;const t=this.getState().nodes||[],e=new Set(r);r.forEach(o=>{t.find(l=>l.id===o)?.type==="image"&&t.forEach(l=>{l.type==="image-marker"&&l.meta.parent===o&&e.add(l.id)})}),e.forEach(o=>{const s=this.getStage().findOne(`#${o}`);s&&s.destroy()});const i=t.filter(o=>!e.has(o.id));this.getCanvasTransformer().clearNodes(),this._updateState({nodes:i,selectedNodeIds:[]},!0)}scrollToContent(r){if((this.getState().nodes||[]).length===0)return;const e=r?.padding??50,i=r?.scale===!0,o=r?.nodeIds;let s=1/0,l=1/0,h=-1/0,u=-1/0;const f=this.getMainLayer(),N=this.getState().selectedNodeIds||[],y=o&&o.length>0,C=!y&&N.length>0,E=y?o:C?N:null;if(f.children.forEach(D=>{if(D.visible()&&D.getClassName()!=="Transformer"&&D.hasName(W)){if(E){const H=D.id();if(!E.includes(H))return}const F=D.getAttrs(),Yt=F.x||0,Xt=F.y||0,ye=F.width||0,ve=F.height||0;if(F.rotation||0){const H=D.getClientRect({skipTransform:!1}),xt=this.getStage(),yt=xt.scaleX(),Zt=xt.x(),At=xt.y(),we=(H.x-Zt)/yt,xe=(H.y-At)/yt,be=(H.x+H.width-Zt)/yt,ke=(H.y+H.height-At)/yt;s=Math.min(s,we),l=Math.min(l,xe),h=Math.max(h,be),u=Math.max(u,ke)}else s=Math.min(s,Yt),l=Math.min(l,Xt),h=Math.max(h,Yt+ye),u=Math.max(u,Xt+ve)}}),s===1/0||l===1/0)return;const T=h-s,U=u-l,X=s+T/2,wt=l+U/2,j=this.getState().viewport;let O=j.scale;if(i){const D=(j.width-e*2)/T,F=(j.height-e*2)/U;O=Math.min(D,F,1)}const Q=j.width/2-X*O,Dt=j.height/2-wt*O;this.updateViewport({x:Q,y:Dt,scale:O},!0)}}function he(n,r,t,e=!1){const[i,o]=r,[s,l]=t,h=s+(n-i)/(o-i)*(l-s);return e?s<l?Math.max(Math.min(h,l),s):Math.max(Math.min(h,s),l):h}const Pt=[{min:-1,mid:.15,step:64},{min:.05,mid:.375,step:16},{min:.15,mid:1,step:4},{min:.7,mid:2.5,step:1}];function de({viewportX:n,viewportY:r,scale:t,size:e=20,showGrid:i=!0}){const o=n/t,s=r/t,l=t;return i?c.jsxs("svg",{className:"canvas-grid w-full h-full absolute top-0 left-0",version:"1.1",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[c.jsx("defs",{children:Pt.map(({min:h,mid:u,step:f},N)=>{const y=f*e*l,C=.5+o*l,E=.5+s*l,T=C>0?C%y:y+C%y,U=E>0?E%y:y+E%y,X=l<u?he(l,[h,u],[0,1]):1;return c.jsx("pattern",{id:`grid_${f}`,width:y,height:y,patternUnits:"userSpaceOnUse",children:c.jsx("circle",{className:"tl-grid-dot",cx:T,cy:U,r:1,opacity:X})},N)})}),Pt.map(({step:h},u)=>c.jsx("rect",{width:"100%",height:"100%",fill:`url(#grid_${h})`},u))]}):null}function ge(...n){return $t.twMerge(Wt.clsx(n))}const pe=qt.cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90",destructive:"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2 has-[>svg]:px-3",sm:"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",lg:"h-10 rounded-md px-6 has-[>svg]:px-4",icon:"size-9","icon-sm":"size-8","icon-lg":"size-10"}},defaultVariants:{variant:"default",size:"default"}});function $({className:n,variant:r="default",size:t="default",asChild:e=!1,...i}){const o=e?Ft.Slot:"button";return c.jsx(o,{"data-slot":"button","data-variant":r,"data-size":t,className:ge(pe({variant:r,size:t,className:n})),...i})}function ue({api:n}){const[r,t]=m.useState(n.getState().viewport);m.useEffect(()=>{n.on("viewport:change",h=>{t(h)})},[t,n]);const e=h=>{const u=r.width/2,f=r.height/2,N=(u-r.x)/r.scale,y=(f-r.y)/r.scale,C=u-N*h,E=f-y*h;n.updateViewport({x:C,y:E,scale:h})},i=()=>{const h=Math.min(r.scale*1.2,5);e(h)},o=()=>{const h=Math.max(r.scale/1.2,.1);e(h)},s=()=>{e(1)},l=Math.round(r.scale*100);return c.jsxs("div",{className:"zoom-panel flex items-center gap-2",children:[c.jsx($,{size:"sm",variant:"secondary",onClick:o,title:"缩小",children:c.jsx(tt.Minus,{})}),c.jsxs($,{size:"sm",variant:"secondary",onClick:s,title:`${l}%`,className:"min-w-16",children:[l,"%"]}),c.jsx($,{size:"sm",variant:"secondary",onClick:i,title:"放大",children:c.jsx(tt.Plus,{})})]})}function me({api:n}){const[r,t]=m.useState(n.canUndo()),[e,i]=m.useState(n.canRedo());return m.useEffect(()=>{const o=()=>{t(n.canUndo()),i(n.canRedo())};return n.on("state:change",o),()=>{n.off("state:change",o)}},[n]),c.jsxs("div",{className:"history-panel flex items-center gap-2",children:[c.jsx($,{size:"sm",variant:"secondary",disabled:!r,onClick:()=>n.undo(),title:"撤销",children:c.jsx(tt.Undo2,{})}),c.jsx($,{size:"sm",variant:"secondary",disabled:!e,onClick:()=>n.redo(),title:"重做",children:c.jsx(tt.Redo2,{})})]})}function fe({setApi:n}){const r=m.useRef(null),[t,e]=m.useState(null),[i,o]=m.useState({x:0,y:0,scale:1});return m.useEffect(()=>{if(!r.current)return;const s=new zt(r.current);return e(s),n?.(s),s.on("viewport:change",l=>{o(l)}),s.on("transformer:positionChange",l=>{console.log("Transformer position changed:",l)}),()=>{s.dispose()}},[n]),c.jsxs("div",{className:"pure-canvas relative size-full",children:[c.jsx(de,{viewportX:i.x,viewportY:i.y,scale:i.scale}),c.jsx("div",{ref:r,className:"size-full"}),t&&c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"history-panel-wrapper absolute bottom-4 left-4 z-10",children:c.jsx(me,{api:t})}),c.jsx("div",{className:"zoom-panel-wrapper absolute bottom-4 right-4 z-10",children:c.jsx(ue,{api:t})})]})]})}d.CanvasApi=zt,d.NODE_NAME_FOR_SELECT=W,d.PureCanvas=fe,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
3
- //# sourceMappingURL=index.umd.js.map
1
+ (function(global, factory) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react/jsx-runtime"), require("react"), require("konva"), require("mitt"), require("uuid"), require("@radix-ui/react-slot"), require("class-variance-authority"), require("clsx"), require("tailwind-merge"), require("lucide-react")) : typeof define === "function" && define.amd ? define(["exports", "react/jsx-runtime", "react", "konva", "mitt", "uuid", "@radix-ui/react-slot", "class-variance-authority", "clsx", "tailwind-merge", "lucide-react"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.konvaWhiteboard = {}, global.jsxRuntime, global.React, global.Konva, global.mitt, global.uuid, global.ReactSlot, global.ClassVarianceAuthority, global.clsx, global.tailwindMerge, global.LucideReact));
3
+ })(this, (function(exports2, jsxRuntime, react, Konva, mitt, uuid, reactSlot, classVarianceAuthority, clsx, tailwindMerge, lucideReact) {
4
+ "use strict";var __defProp = Object.defineProperty;
5
+ var __typeError = (msg) => {
6
+ throw TypeError(msg);
7
+ };
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
10
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
11
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
12
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
13
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
14
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
15
+
16
+ var _core, _stage, _viewport, _handleWheel, _handlePointerDown, _handlePointerMove, _handlePointerUp, _handleDragStart, _handleDragMove, _handleDragEnd, _CanvasStage_instances, setupEventListeners_fn, _core2, _transformer, _handleTransformStart, _handleTransform, _handleTransformEnd, _handleDragStart2, _handleDragMove2, _handleDragEnd2, _CanvasTransformer_instances, setupEventListeners_fn2, _animation, _RectNode_instances, initAnimation_fn, destroyAnimation_fn, setupEventHandlers_fn, _ImageNode_instances, loadImage_fn, setupEventHandlers_fn2, syncImageMarkers_fn, syncImageMarkersToState_fn, _rect, _markerGroup, _circle, _text, _ImageMarkerNode_instances, setupEventHandlers_fn3, _canvasStage, _mainLayer, _canvasTransformer, _draftNode;
17
+ var __vite_style__ = document.createElement("style");
18
+ __vite_style__.textContent = `/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
19
+ @layer properties {
20
+ @supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {
21
+ *, :before, :after, ::backdrop {
22
+ --tw-translate-x: 0;
23
+ --tw-translate-y: 0;
24
+ --tw-translate-z: 0;
25
+ --tw-rotate-x: initial;
26
+ --tw-rotate-y: initial;
27
+ --tw-rotate-z: initial;
28
+ --tw-skew-x: initial;
29
+ --tw-skew-y: initial;
30
+ --tw-border-style: solid;
31
+ --tw-font-weight: initial;
32
+ --tw-shadow: 0 0 #0000;
33
+ --tw-shadow-color: initial;
34
+ --tw-shadow-alpha: 100%;
35
+ --tw-inset-shadow: 0 0 #0000;
36
+ --tw-inset-shadow-color: initial;
37
+ --tw-inset-shadow-alpha: 100%;
38
+ --tw-ring-color: initial;
39
+ --tw-ring-shadow: 0 0 #0000;
40
+ --tw-inset-ring-color: initial;
41
+ --tw-inset-ring-shadow: 0 0 #0000;
42
+ --tw-ring-inset: initial;
43
+ --tw-ring-offset-width: 0px;
44
+ --tw-ring-offset-color: #fff;
45
+ --tw-ring-offset-shadow: 0 0 #0000;
46
+ --tw-outline-style: solid;
47
+ --tw-animation-delay: 0s;
48
+ --tw-animation-direction: normal;
49
+ --tw-animation-duration: initial;
50
+ --tw-animation-fill-mode: none;
51
+ --tw-animation-iteration-count: 1;
52
+ --tw-enter-blur: 0;
53
+ --tw-enter-opacity: 1;
54
+ --tw-enter-rotate: 0;
55
+ --tw-enter-scale: 1;
56
+ --tw-enter-translate-x: 0;
57
+ --tw-enter-translate-y: 0;
58
+ --tw-exit-blur: 0;
59
+ --tw-exit-opacity: 1;
60
+ --tw-exit-rotate: 0;
61
+ --tw-exit-scale: 1;
62
+ --tw-exit-translate-x: 0;
63
+ --tw-exit-translate-y: 0;
64
+ }
65
+ }
66
+ }
67
+
68
+ @layer theme {
69
+ :root, :host {
70
+ --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
71
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
72
+ --color-red-500: oklch(63.7% .237 25.331);
73
+ --color-red-600: oklch(57.7% .245 27.325);
74
+ --color-green-500: oklch(72.3% .219 149.579);
75
+ --color-green-600: oklch(62.7% .194 149.214);
76
+ --color-cyan-500: oklch(71.5% .143 215.221);
77
+ --color-cyan-600: oklch(60.9% .126 221.723);
78
+ --color-cyan-700: oklch(52% .105 223.128);
79
+ --color-blue-500: oklch(62.3% .214 259.815);
80
+ --color-blue-600: oklch(54.6% .245 262.881);
81
+ --color-indigo-500: oklch(58.5% .233 277.117);
82
+ --color-indigo-600: oklch(51.1% .262 276.966);
83
+ --color-purple-500: oklch(62.7% .265 303.9);
84
+ --color-purple-600: oklch(55.8% .288 302.321);
85
+ --color-gray-50: oklch(98.5% .002 247.839);
86
+ --color-gray-100: oklch(96.7% .003 264.542);
87
+ --color-gray-200: oklch(92.8% .006 264.531);
88
+ --color-gray-400: oklch(70.7% .022 261.325);
89
+ --color-gray-600: oklch(44.6% .03 256.802);
90
+ --color-gray-700: oklch(37.3% .034 259.733);
91
+ --color-gray-800: oklch(27.8% .033 256.848);
92
+ --color-white: #fff;
93
+ --spacing: .25rem;
94
+ --container-xs: 20rem;
95
+ --text-xs: .75rem;
96
+ --text-xs--line-height: calc(1 / .75);
97
+ --text-sm: .875rem;
98
+ --text-sm--line-height: calc(1.25 / .875);
99
+ --font-weight-medium: 500;
100
+ --font-weight-bold: 700;
101
+ --default-transition-duration: .15s;
102
+ --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
103
+ --default-font-family: var(--font-sans);
104
+ --default-mono-font-family: var(--font-mono);
105
+ }
106
+ }
107
+
108
+ @layer base {
109
+ *, :after, :before, ::backdrop {
110
+ box-sizing: border-box;
111
+ border: 0 solid;
112
+ margin: 0;
113
+ padding: 0;
114
+ }
115
+
116
+ ::file-selector-button {
117
+ box-sizing: border-box;
118
+ border: 0 solid;
119
+ margin: 0;
120
+ padding: 0;
121
+ }
122
+
123
+ html, :host {
124
+ -webkit-text-size-adjust: 100%;
125
+ tab-size: 4;
126
+ line-height: 1.5;
127
+ font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
128
+ font-feature-settings: var(--default-font-feature-settings, normal);
129
+ font-variation-settings: var(--default-font-variation-settings, normal);
130
+ -webkit-tap-highlight-color: transparent;
131
+ }
132
+
133
+ hr {
134
+ height: 0;
135
+ color: inherit;
136
+ border-top-width: 1px;
137
+ }
138
+
139
+ abbr:where([title]) {
140
+ -webkit-text-decoration: underline dotted;
141
+ text-decoration: underline dotted;
142
+ }
143
+
144
+ h1, h2, h3, h4, h5, h6 {
145
+ font-size: inherit;
146
+ font-weight: inherit;
147
+ }
148
+
149
+ a {
150
+ color: inherit;
151
+ -webkit-text-decoration: inherit;
152
+ -webkit-text-decoration: inherit;
153
+ -webkit-text-decoration: inherit;
154
+ text-decoration: inherit;
155
+ }
156
+
157
+ b, strong {
158
+ font-weight: bolder;
159
+ }
160
+
161
+ code, kbd, samp, pre {
162
+ font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
163
+ font-feature-settings: var(--default-mono-font-feature-settings, normal);
164
+ font-variation-settings: var(--default-mono-font-variation-settings, normal);
165
+ font-size: 1em;
166
+ }
167
+
168
+ small {
169
+ font-size: 80%;
170
+ }
171
+
172
+ sub, sup {
173
+ vertical-align: baseline;
174
+ font-size: 75%;
175
+ line-height: 0;
176
+ position: relative;
177
+ }
178
+
179
+ sub {
180
+ bottom: -.25em;
181
+ }
182
+
183
+ sup {
184
+ top: -.5em;
185
+ }
186
+
187
+ table {
188
+ text-indent: 0;
189
+ border-color: inherit;
190
+ border-collapse: collapse;
191
+ }
192
+
193
+ :-moz-focusring {
194
+ outline: auto;
195
+ }
196
+
197
+ progress {
198
+ vertical-align: baseline;
199
+ }
200
+
201
+ summary {
202
+ display: list-item;
203
+ }
204
+
205
+ ol, ul, menu {
206
+ list-style: none;
207
+ }
208
+
209
+ img, svg, video, canvas, audio, iframe, embed, object {
210
+ vertical-align: middle;
211
+ display: block;
212
+ }
213
+
214
+ img, video {
215
+ max-width: 100%;
216
+ height: auto;
217
+ }
218
+
219
+ button, input, select, optgroup, textarea {
220
+ font: inherit;
221
+ font-feature-settings: inherit;
222
+ font-variation-settings: inherit;
223
+ letter-spacing: inherit;
224
+ color: inherit;
225
+ opacity: 1;
226
+ background-color: #0000;
227
+ border-radius: 0;
228
+ }
229
+
230
+ ::file-selector-button {
231
+ font: inherit;
232
+ font-feature-settings: inherit;
233
+ font-variation-settings: inherit;
234
+ letter-spacing: inherit;
235
+ color: inherit;
236
+ opacity: 1;
237
+ background-color: #0000;
238
+ border-radius: 0;
239
+ }
240
+
241
+ :where(select:is([multiple], [size])) optgroup {
242
+ font-weight: bolder;
243
+ }
244
+
245
+ :where(select:is([multiple], [size])) optgroup option {
246
+ padding-inline-start: 20px;
247
+ }
248
+
249
+ ::file-selector-button {
250
+ margin-inline-end: 4px;
251
+ }
252
+
253
+ ::placeholder {
254
+ opacity: 1;
255
+ }
256
+
257
+ @supports (not ((-webkit-appearance: -apple-pay-button))) or (contain-intrinsic-size: 1px) {
258
+ ::placeholder {
259
+ color: currentColor;
260
+ }
261
+
262
+ @supports (color: color-mix(in lab, red, red)) {
263
+ ::placeholder {
264
+ color: color-mix(in oklab, currentcolor 50%, transparent);
265
+ }
266
+ }
267
+ }
268
+
269
+ textarea {
270
+ resize: vertical;
271
+ }
272
+
273
+ ::-webkit-search-decoration {
274
+ -webkit-appearance: none;
275
+ }
276
+
277
+ ::-webkit-date-and-time-value {
278
+ min-height: 1lh;
279
+ text-align: inherit;
280
+ }
281
+
282
+ ::-webkit-datetime-edit {
283
+ display: inline-flex;
284
+ }
285
+
286
+ ::-webkit-datetime-edit-fields-wrapper {
287
+ padding: 0;
288
+ }
289
+
290
+ ::-webkit-datetime-edit {
291
+ padding-block: 0;
292
+ }
293
+
294
+ ::-webkit-datetime-edit-year-field {
295
+ padding-block: 0;
296
+ }
297
+
298
+ ::-webkit-datetime-edit-month-field {
299
+ padding-block: 0;
300
+ }
301
+
302
+ ::-webkit-datetime-edit-day-field {
303
+ padding-block: 0;
304
+ }
305
+
306
+ ::-webkit-datetime-edit-hour-field {
307
+ padding-block: 0;
308
+ }
309
+
310
+ ::-webkit-datetime-edit-minute-field {
311
+ padding-block: 0;
312
+ }
313
+
314
+ ::-webkit-datetime-edit-second-field {
315
+ padding-block: 0;
316
+ }
317
+
318
+ ::-webkit-datetime-edit-millisecond-field {
319
+ padding-block: 0;
320
+ }
321
+
322
+ ::-webkit-datetime-edit-meridiem-field {
323
+ padding-block: 0;
324
+ }
325
+
326
+ ::-webkit-calendar-picker-indicator {
327
+ line-height: 1;
328
+ }
329
+
330
+ :-moz-ui-invalid {
331
+ box-shadow: none;
332
+ }
333
+
334
+ button, input:where([type="button"], [type="reset"], [type="submit"]) {
335
+ appearance: button;
336
+ }
337
+
338
+ ::file-selector-button {
339
+ appearance: button;
340
+ }
341
+
342
+ ::-webkit-inner-spin-button {
343
+ height: auto;
344
+ }
345
+
346
+ ::-webkit-outer-spin-button {
347
+ height: auto;
348
+ }
349
+
350
+ [hidden]:where(:not([hidden="until-found"])) {
351
+ display: none !important;
352
+ }
353
+
354
+ * {
355
+ border-color: var(--border);
356
+ outline-color: var(--ring);
357
+ }
358
+
359
+ @supports (color: color-mix(in lab, red, red)) {
360
+ * {
361
+ outline-color: color-mix(in oklab, var(--ring) 50%, transparent);
362
+ }
363
+ }
364
+
365
+ body {
366
+ background-color: var(--background);
367
+ color: var(--foreground);
368
+ }
369
+ }
370
+
371
+ @layer components;
372
+
373
+ @layer utilities {
374
+ .pointer-events-auto {
375
+ pointer-events: auto;
376
+ }
377
+
378
+ .pointer-events-none {
379
+ pointer-events: none;
380
+ }
381
+
382
+ .visible {
383
+ visibility: visible;
384
+ }
385
+
386
+ .absolute {
387
+ position: absolute;
388
+ }
389
+
390
+ .relative {
391
+ position: relative;
392
+ }
393
+
394
+ .static {
395
+ position: static;
396
+ }
397
+
398
+ .top-0 {
399
+ top: calc(var(--spacing) * 0);
400
+ }
401
+
402
+ .top-4 {
403
+ top: calc(var(--spacing) * 4);
404
+ }
405
+
406
+ .right-4 {
407
+ right: calc(var(--spacing) * 4);
408
+ }
409
+
410
+ .bottom-4 {
411
+ bottom: calc(var(--spacing) * 4);
412
+ }
413
+
414
+ .left-0 {
415
+ left: calc(var(--spacing) * 0);
416
+ }
417
+
418
+ .left-4 {
419
+ left: calc(var(--spacing) * 4);
420
+ }
421
+
422
+ .z-10 {
423
+ z-index: 10;
424
+ }
425
+
426
+ .z-20 {
427
+ z-index: 20;
428
+ }
429
+
430
+ .z-50 {
431
+ z-index: 50;
432
+ }
433
+
434
+ .container {
435
+ width: 100%;
436
+ }
437
+
438
+ @media (min-width: 40rem) {
439
+ .container {
440
+ max-width: 40rem;
441
+ }
442
+ }
443
+
444
+ @media (min-width: 48rem) {
445
+ .container {
446
+ max-width: 48rem;
447
+ }
448
+ }
449
+
450
+ @media (min-width: 64rem) {
451
+ .container {
452
+ max-width: 64rem;
453
+ }
454
+ }
455
+
456
+ @media (min-width: 80rem) {
457
+ .container {
458
+ max-width: 80rem;
459
+ }
460
+ }
461
+
462
+ @media (min-width: 96rem) {
463
+ .container {
464
+ max-width: 96rem;
465
+ }
466
+ }
467
+
468
+ .mt-2 {
469
+ margin-top: calc(var(--spacing) * 2);
470
+ }
471
+
472
+ .mt-4 {
473
+ margin-top: calc(var(--spacing) * 4);
474
+ }
475
+
476
+ .mb-2 {
477
+ margin-bottom: calc(var(--spacing) * 2);
478
+ }
479
+
480
+ .mb-3 {
481
+ margin-bottom: calc(var(--spacing) * 3);
482
+ }
483
+
484
+ .mb-4 {
485
+ margin-bottom: calc(var(--spacing) * 4);
486
+ }
487
+
488
+ .mb-6 {
489
+ margin-bottom: calc(var(--spacing) * 6);
490
+ }
491
+
492
+ .flex {
493
+ display: flex;
494
+ }
495
+
496
+ .grid {
497
+ display: grid;
498
+ }
499
+
500
+ .inline-flex {
501
+ display: inline-flex;
502
+ }
503
+
504
+ .size-8 {
505
+ width: calc(var(--spacing) * 8);
506
+ height: calc(var(--spacing) * 8);
507
+ }
508
+
509
+ .size-9 {
510
+ width: calc(var(--spacing) * 9);
511
+ height: calc(var(--spacing) * 9);
512
+ }
513
+
514
+ .size-10 {
515
+ width: calc(var(--spacing) * 10);
516
+ height: calc(var(--spacing) * 10);
517
+ }
518
+
519
+ .size-full {
520
+ width: 100%;
521
+ height: 100%;
522
+ }
523
+
524
+ .h-8 {
525
+ height: calc(var(--spacing) * 8);
526
+ }
527
+
528
+ .h-9 {
529
+ height: calc(var(--spacing) * 9);
530
+ }
531
+
532
+ .h-10 {
533
+ height: calc(var(--spacing) * 10);
534
+ }
535
+
536
+ .h-\\[500px\\] {
537
+ height: 500px;
538
+ }
539
+
540
+ .h-full {
541
+ height: 100%;
542
+ }
543
+
544
+ .max-h-40 {
545
+ max-height: calc(var(--spacing) * 40);
546
+ }
547
+
548
+ .w-\\[700px\\] {
549
+ width: 700px;
550
+ }
551
+
552
+ .w-full {
553
+ width: 100%;
554
+ }
555
+
556
+ .max-w-xs {
557
+ max-width: var(--container-xs);
558
+ }
559
+
560
+ .min-w-16 {
561
+ min-width: calc(var(--spacing) * 16);
562
+ }
563
+
564
+ .shrink-0 {
565
+ flex-shrink: 0;
566
+ }
567
+
568
+ .-translate-x-1\\/2 {
569
+ --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
570
+ translate: var(--tw-translate-x) var(--tw-translate-y);
571
+ }
572
+
573
+ .transform {
574
+ transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
575
+ }
576
+
577
+ .touch-none {
578
+ touch-action: none;
579
+ }
580
+
581
+ .resize {
582
+ resize: both;
583
+ }
584
+
585
+ .grid-cols-2 {
586
+ grid-template-columns: repeat(2, minmax(0, 1fr));
587
+ }
588
+
589
+ .flex-col {
590
+ flex-direction: column;
591
+ }
592
+
593
+ .items-center {
594
+ align-items: center;
595
+ }
596
+
597
+ .justify-center {
598
+ justify-content: center;
599
+ }
600
+
601
+ .gap-1\\.5 {
602
+ gap: calc(var(--spacing) * 1.5);
603
+ }
604
+
605
+ .gap-2 {
606
+ gap: calc(var(--spacing) * 2);
607
+ }
608
+
609
+ .overflow-auto {
610
+ overflow: auto;
611
+ }
612
+
613
+ .rounded {
614
+ border-radius: .25rem;
615
+ }
616
+
617
+ .rounded-lg {
618
+ border-radius: var(--radius);
619
+ }
620
+
621
+ .rounded-md {
622
+ border-radius: calc(var(--radius) - 2px);
623
+ }
624
+
625
+ .border {
626
+ border-style: var(--tw-border-style);
627
+ border-width: 1px;
628
+ }
629
+
630
+ .border-t {
631
+ border-top-style: var(--tw-border-style);
632
+ border-top-width: 1px;
633
+ }
634
+
635
+ .bg-background {
636
+ background-color: var(--background);
637
+ }
638
+
639
+ .bg-blue-500 {
640
+ background-color: var(--color-blue-500);
641
+ }
642
+
643
+ .bg-cyan-500 {
644
+ background-color: var(--color-cyan-500);
645
+ }
646
+
647
+ .bg-cyan-600 {
648
+ background-color: var(--color-cyan-600);
649
+ }
650
+
651
+ .bg-destructive {
652
+ background-color: var(--destructive);
653
+ }
654
+
655
+ .bg-gray-50 {
656
+ background-color: var(--color-gray-50);
657
+ }
658
+
659
+ .bg-gray-100 {
660
+ background-color: var(--color-gray-100);
661
+ }
662
+
663
+ .bg-green-500 {
664
+ background-color: var(--color-green-500);
665
+ }
666
+
667
+ .bg-indigo-500 {
668
+ background-color: var(--color-indigo-500);
669
+ }
670
+
671
+ .bg-primary {
672
+ background-color: var(--primary);
673
+ }
674
+
675
+ .bg-purple-500 {
676
+ background-color: var(--color-purple-500);
677
+ }
678
+
679
+ .bg-red-500 {
680
+ background-color: var(--color-red-500);
681
+ }
682
+
683
+ .bg-secondary {
684
+ background-color: var(--secondary);
685
+ }
686
+
687
+ .bg-white {
688
+ background-color: var(--color-white);
689
+ }
690
+
691
+ .p-2 {
692
+ padding: calc(var(--spacing) * 2);
693
+ }
694
+
695
+ .p-4 {
696
+ padding: calc(var(--spacing) * 4);
697
+ }
698
+
699
+ .px-3 {
700
+ padding-inline: calc(var(--spacing) * 3);
701
+ }
702
+
703
+ .px-4 {
704
+ padding-inline: calc(var(--spacing) * 4);
705
+ }
706
+
707
+ .px-6 {
708
+ padding-inline: calc(var(--spacing) * 6);
709
+ }
710
+
711
+ .py-2 {
712
+ padding-block: calc(var(--spacing) * 2);
713
+ }
714
+
715
+ .pt-4 {
716
+ padding-top: calc(var(--spacing) * 4);
717
+ }
718
+
719
+ .text-sm {
720
+ font-size: var(--text-sm);
721
+ line-height: var(--tw-leading, var(--text-sm--line-height));
722
+ }
723
+
724
+ .text-xs {
725
+ font-size: var(--text-xs);
726
+ line-height: var(--tw-leading, var(--text-xs--line-height));
727
+ }
728
+
729
+ .font-bold {
730
+ --tw-font-weight: var(--font-weight-bold);
731
+ font-weight: var(--font-weight-bold);
732
+ }
733
+
734
+ .font-medium {
735
+ --tw-font-weight: var(--font-weight-medium);
736
+ font-weight: var(--font-weight-medium);
737
+ }
738
+
739
+ .whitespace-nowrap {
740
+ white-space: nowrap;
741
+ }
742
+
743
+ .whitespace-pre-wrap {
744
+ white-space: pre-wrap;
745
+ }
746
+
747
+ .text-gray-400 {
748
+ color: var(--color-gray-400);
749
+ }
750
+
751
+ .text-gray-600 {
752
+ color: var(--color-gray-600);
753
+ }
754
+
755
+ .text-gray-700 {
756
+ color: var(--color-gray-700);
757
+ }
758
+
759
+ .text-gray-800 {
760
+ color: var(--color-gray-800);
761
+ }
762
+
763
+ .text-primary {
764
+ color: var(--primary);
765
+ }
766
+
767
+ .text-primary-foreground {
768
+ color: var(--primary-foreground);
769
+ }
770
+
771
+ .text-secondary-foreground {
772
+ color: var(--secondary-foreground);
773
+ }
774
+
775
+ .text-white {
776
+ color: var(--color-white);
777
+ }
778
+
779
+ .underline-offset-4 {
780
+ text-underline-offset: 4px;
781
+ }
782
+
783
+ .shadow-lg {
784
+ --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, #0000001a), 0 4px 6px -4px var(--tw-shadow-color, #0000001a);
785
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
786
+ }
787
+
788
+ .shadow-xs {
789
+ --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, #0000000d);
790
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
791
+ }
792
+
793
+ .outline {
794
+ outline-style: var(--tw-outline-style);
795
+ outline-width: 1px;
796
+ }
797
+
798
+ .transition-all {
799
+ transition-property: all;
800
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
801
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
802
+ }
803
+
804
+ .outline-none {
805
+ --tw-outline-style: none;
806
+ outline-style: none;
807
+ }
808
+
809
+ @media (hover: hover) {
810
+ .hover\\:bg-accent:hover {
811
+ background-color: var(--accent);
812
+ }
813
+
814
+ .hover\\:bg-blue-600:hover {
815
+ background-color: var(--color-blue-600);
816
+ }
817
+
818
+ .hover\\:bg-cyan-600:hover {
819
+ background-color: var(--color-cyan-600);
820
+ }
821
+
822
+ .hover\\:bg-cyan-700:hover {
823
+ background-color: var(--color-cyan-700);
824
+ }
825
+
826
+ .hover\\:bg-destructive\\/90:hover {
827
+ background-color: var(--destructive);
828
+ }
829
+
830
+ @supports (color: color-mix(in lab, red, red)) {
831
+ .hover\\:bg-destructive\\/90:hover {
832
+ background-color: color-mix(in oklab, var(--destructive) 90%, transparent);
833
+ }
834
+ }
835
+
836
+ .hover\\:bg-gray-200:hover {
837
+ background-color: var(--color-gray-200);
838
+ }
839
+
840
+ .hover\\:bg-green-600:hover {
841
+ background-color: var(--color-green-600);
842
+ }
843
+
844
+ .hover\\:bg-indigo-600:hover {
845
+ background-color: var(--color-indigo-600);
846
+ }
847
+
848
+ .hover\\:bg-primary\\/90:hover {
849
+ background-color: var(--primary);
850
+ }
851
+
852
+ @supports (color: color-mix(in lab, red, red)) {
853
+ .hover\\:bg-primary\\/90:hover {
854
+ background-color: color-mix(in oklab, var(--primary) 90%, transparent);
855
+ }
856
+ }
857
+
858
+ .hover\\:bg-purple-600:hover {
859
+ background-color: var(--color-purple-600);
860
+ }
861
+
862
+ .hover\\:bg-red-600:hover {
863
+ background-color: var(--color-red-600);
864
+ }
865
+
866
+ .hover\\:bg-secondary\\/80:hover {
867
+ background-color: var(--secondary);
868
+ }
869
+
870
+ @supports (color: color-mix(in lab, red, red)) {
871
+ .hover\\:bg-secondary\\/80:hover {
872
+ background-color: color-mix(in oklab, var(--secondary) 80%, transparent);
873
+ }
874
+ }
875
+
876
+ .hover\\:text-accent-foreground:hover {
877
+ color: var(--accent-foreground);
878
+ }
879
+
880
+ .hover\\:underline:hover {
881
+ text-decoration-line: underline;
882
+ }
883
+ }
884
+
885
+ .focus-visible\\:border-ring:focus-visible {
886
+ border-color: var(--ring);
887
+ }
888
+
889
+ .focus-visible\\:ring-\\[3px\\]:focus-visible {
890
+ --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
891
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
892
+ }
893
+
894
+ .focus-visible\\:ring-destructive\\/20:focus-visible {
895
+ --tw-ring-color: var(--destructive);
896
+ }
897
+
898
+ @supports (color: color-mix(in lab, red, red)) {
899
+ .focus-visible\\:ring-destructive\\/20:focus-visible {
900
+ --tw-ring-color: color-mix(in oklab, var(--destructive) 20%, transparent);
901
+ }
902
+ }
903
+
904
+ .focus-visible\\:ring-ring\\/50:focus-visible {
905
+ --tw-ring-color: var(--ring);
906
+ }
907
+
908
+ @supports (color: color-mix(in lab, red, red)) {
909
+ .focus-visible\\:ring-ring\\/50:focus-visible {
910
+ --tw-ring-color: color-mix(in oklab, var(--ring) 50%, transparent);
911
+ }
912
+ }
913
+
914
+ .disabled\\:pointer-events-none:disabled {
915
+ pointer-events: none;
916
+ }
917
+
918
+ .disabled\\:cursor-not-allowed:disabled {
919
+ cursor: not-allowed;
920
+ }
921
+
922
+ .disabled\\:opacity-50:disabled {
923
+ opacity: .5;
924
+ }
925
+
926
+ .has-\\[\\>svg\\]\\:px-2\\.5:has( > svg) {
927
+ padding-inline: calc(var(--spacing) * 2.5);
928
+ }
929
+
930
+ .has-\\[\\>svg\\]\\:px-3:has( > svg) {
931
+ padding-inline: calc(var(--spacing) * 3);
932
+ }
933
+
934
+ .has-\\[\\>svg\\]\\:px-4:has( > svg) {
935
+ padding-inline: calc(var(--spacing) * 4);
936
+ }
937
+
938
+ .aria-invalid\\:border-destructive[aria-invalid="true"] {
939
+ border-color: var(--destructive);
940
+ }
941
+
942
+ .aria-invalid\\:ring-destructive\\/20[aria-invalid="true"] {
943
+ --tw-ring-color: var(--destructive);
944
+ }
945
+
946
+ @supports (color: color-mix(in lab, red, red)) {
947
+ .aria-invalid\\:ring-destructive\\/20[aria-invalid="true"] {
948
+ --tw-ring-color: color-mix(in oklab, var(--destructive) 20%, transparent);
949
+ }
950
+ }
951
+
952
+ .dark\\:border-input:is(.dark *) {
953
+ border-color: var(--input);
954
+ }
955
+
956
+ .dark\\:bg-destructive\\/60:is(.dark *) {
957
+ background-color: var(--destructive);
958
+ }
959
+
960
+ @supports (color: color-mix(in lab, red, red)) {
961
+ .dark\\:bg-destructive\\/60:is(.dark *) {
962
+ background-color: color-mix(in oklab, var(--destructive) 60%, transparent);
963
+ }
964
+ }
965
+
966
+ .dark\\:bg-input\\/30:is(.dark *) {
967
+ background-color: var(--input);
968
+ }
969
+
970
+ @supports (color: color-mix(in lab, red, red)) {
971
+ .dark\\:bg-input\\/30:is(.dark *) {
972
+ background-color: color-mix(in oklab, var(--input) 30%, transparent);
973
+ }
974
+ }
975
+
976
+ @media (hover: hover) {
977
+ .dark\\:hover\\:bg-accent\\/50:is(.dark *):hover {
978
+ background-color: var(--accent);
979
+ }
980
+
981
+ @supports (color: color-mix(in lab, red, red)) {
982
+ .dark\\:hover\\:bg-accent\\/50:is(.dark *):hover {
983
+ background-color: color-mix(in oklab, var(--accent) 50%, transparent);
984
+ }
985
+ }
986
+
987
+ .dark\\:hover\\:bg-input\\/50:is(.dark *):hover {
988
+ background-color: var(--input);
989
+ }
990
+
991
+ @supports (color: color-mix(in lab, red, red)) {
992
+ .dark\\:hover\\:bg-input\\/50:is(.dark *):hover {
993
+ background-color: color-mix(in oklab, var(--input) 50%, transparent);
994
+ }
995
+ }
996
+ }
997
+
998
+ .dark\\:focus-visible\\:ring-destructive\\/40:is(.dark *):focus-visible {
999
+ --tw-ring-color: var(--destructive);
1000
+ }
1001
+
1002
+ @supports (color: color-mix(in lab, red, red)) {
1003
+ .dark\\:focus-visible\\:ring-destructive\\/40:is(.dark *):focus-visible {
1004
+ --tw-ring-color: color-mix(in oklab, var(--destructive) 40%, transparent);
1005
+ }
1006
+ }
1007
+
1008
+ .dark\\:aria-invalid\\:ring-destructive\\/40:is(.dark *)[aria-invalid="true"] {
1009
+ --tw-ring-color: var(--destructive);
1010
+ }
1011
+
1012
+ @supports (color: color-mix(in lab, red, red)) {
1013
+ .dark\\:aria-invalid\\:ring-destructive\\/40:is(.dark *)[aria-invalid="true"] {
1014
+ --tw-ring-color: color-mix(in oklab, var(--destructive) 40%, transparent);
1015
+ }
1016
+ }
1017
+
1018
+ .\\[\\&_svg\\]\\:pointer-events-none svg {
1019
+ pointer-events: none;
1020
+ }
1021
+
1022
+ .\\[\\&_svg\\]\\:shrink-0 svg {
1023
+ flex-shrink: 0;
1024
+ }
1025
+
1026
+ .\\[\\&_svg\\:not\\(\\[class\\*\\=\\'size-\\'\\]\\)\\]\\:size-4 svg:not([class*="size-"]) {
1027
+ width: calc(var(--spacing) * 4);
1028
+ height: calc(var(--spacing) * 4);
1029
+ }
1030
+ }
1031
+
1032
+ @property --tw-animation-delay {
1033
+ syntax: "*";
1034
+ inherits: false;
1035
+ initial-value: 0s;
1036
+ }
1037
+
1038
+ @property --tw-animation-direction {
1039
+ syntax: "*";
1040
+ inherits: false;
1041
+ initial-value: normal;
1042
+ }
1043
+
1044
+ @property --tw-animation-duration {
1045
+ syntax: "*";
1046
+ inherits: false
1047
+ }
1048
+
1049
+ @property --tw-animation-fill-mode {
1050
+ syntax: "*";
1051
+ inherits: false;
1052
+ initial-value: none;
1053
+ }
1054
+
1055
+ @property --tw-animation-iteration-count {
1056
+ syntax: "*";
1057
+ inherits: false;
1058
+ initial-value: 1;
1059
+ }
1060
+
1061
+ @property --tw-enter-blur {
1062
+ syntax: "*";
1063
+ inherits: false;
1064
+ initial-value: 0;
1065
+ }
1066
+
1067
+ @property --tw-enter-opacity {
1068
+ syntax: "*";
1069
+ inherits: false;
1070
+ initial-value: 1;
1071
+ }
1072
+
1073
+ @property --tw-enter-rotate {
1074
+ syntax: "*";
1075
+ inherits: false;
1076
+ initial-value: 0;
1077
+ }
1078
+
1079
+ @property --tw-enter-scale {
1080
+ syntax: "*";
1081
+ inherits: false;
1082
+ initial-value: 1;
1083
+ }
1084
+
1085
+ @property --tw-enter-translate-x {
1086
+ syntax: "*";
1087
+ inherits: false;
1088
+ initial-value: 0;
1089
+ }
1090
+
1091
+ @property --tw-enter-translate-y {
1092
+ syntax: "*";
1093
+ inherits: false;
1094
+ initial-value: 0;
1095
+ }
1096
+
1097
+ @property --tw-exit-blur {
1098
+ syntax: "*";
1099
+ inherits: false;
1100
+ initial-value: 0;
1101
+ }
1102
+
1103
+ @property --tw-exit-opacity {
1104
+ syntax: "*";
1105
+ inherits: false;
1106
+ initial-value: 1;
1107
+ }
1108
+
1109
+ @property --tw-exit-rotate {
1110
+ syntax: "*";
1111
+ inherits: false;
1112
+ initial-value: 0;
1113
+ }
1114
+
1115
+ @property --tw-exit-scale {
1116
+ syntax: "*";
1117
+ inherits: false;
1118
+ initial-value: 1;
1119
+ }
1120
+
1121
+ @property --tw-exit-translate-x {
1122
+ syntax: "*";
1123
+ inherits: false;
1124
+ initial-value: 0;
1125
+ }
1126
+
1127
+ @property --tw-exit-translate-y {
1128
+ syntax: "*";
1129
+ inherits: false;
1130
+ initial-value: 0;
1131
+ }
1132
+
1133
+ :root {
1134
+ --radius: .625rem;
1135
+ --background: oklch(100% 0 0);
1136
+ --foreground: oklch(14.5% 0 0);
1137
+ --card: oklch(100% 0 0);
1138
+ --card-foreground: oklch(14.5% 0 0);
1139
+ --popover: oklch(100% 0 0);
1140
+ --popover-foreground: oklch(14.5% 0 0);
1141
+ --primary: oklch(20.5% 0 0);
1142
+ --primary-foreground: oklch(98.5% 0 0);
1143
+ --secondary: oklch(97% 0 0);
1144
+ --secondary-foreground: oklch(20.5% 0 0);
1145
+ --muted: oklch(97% 0 0);
1146
+ --muted-foreground: oklch(55.6% 0 0);
1147
+ --accent: oklch(97% 0 0);
1148
+ --accent-foreground: oklch(20.5% 0 0);
1149
+ --destructive: oklch(57.7% .245 27.325);
1150
+ --border: oklch(92.2% 0 0);
1151
+ --input: oklch(92.2% 0 0);
1152
+ --ring: oklch(70.8% 0 0);
1153
+ --chart-1: oklch(64.6% .222 41.116);
1154
+ --chart-2: oklch(60% .118 184.704);
1155
+ --chart-3: oklch(39.8% .07 227.392);
1156
+ --chart-4: oklch(82.8% .189 84.429);
1157
+ --chart-5: oklch(76.9% .188 70.08);
1158
+ --sidebar: oklch(98.5% 0 0);
1159
+ --sidebar-foreground: oklch(14.5% 0 0);
1160
+ --sidebar-primary: oklch(20.5% 0 0);
1161
+ --sidebar-primary-foreground: oklch(98.5% 0 0);
1162
+ --sidebar-accent: oklch(97% 0 0);
1163
+ --sidebar-accent-foreground: oklch(20.5% 0 0);
1164
+ --sidebar-border: oklch(92.2% 0 0);
1165
+ --sidebar-ring: oklch(70.8% 0 0);
1166
+ }
1167
+
1168
+ .dark {
1169
+ --background: oklch(14.5% 0 0);
1170
+ --foreground: oklch(98.5% 0 0);
1171
+ --card: oklch(20.5% 0 0);
1172
+ --card-foreground: oklch(98.5% 0 0);
1173
+ --popover: oklch(20.5% 0 0);
1174
+ --popover-foreground: oklch(98.5% 0 0);
1175
+ --primary: oklch(92.2% 0 0);
1176
+ --primary-foreground: oklch(20.5% 0 0);
1177
+ --secondary: oklch(26.9% 0 0);
1178
+ --secondary-foreground: oklch(98.5% 0 0);
1179
+ --muted: oklch(26.9% 0 0);
1180
+ --muted-foreground: oklch(70.8% 0 0);
1181
+ --accent: oklch(26.9% 0 0);
1182
+ --accent-foreground: oklch(98.5% 0 0);
1183
+ --destructive: oklch(70.4% .191 22.216);
1184
+ --border: oklch(100% 0 0 / .1);
1185
+ --input: oklch(100% 0 0 / .15);
1186
+ --ring: oklch(55.6% 0 0);
1187
+ --chart-1: oklch(48.8% .243 264.376);
1188
+ --chart-2: oklch(69.6% .17 162.48);
1189
+ --chart-3: oklch(76.9% .188 70.08);
1190
+ --chart-4: oklch(62.7% .265 303.9);
1191
+ --chart-5: oklch(64.5% .246 16.439);
1192
+ --sidebar: oklch(20.5% 0 0);
1193
+ --sidebar-foreground: oklch(98.5% 0 0);
1194
+ --sidebar-primary: oklch(48.8% .243 264.376);
1195
+ --sidebar-primary-foreground: oklch(98.5% 0 0);
1196
+ --sidebar-accent: oklch(26.9% 0 0);
1197
+ --sidebar-accent-foreground: oklch(98.5% 0 0);
1198
+ --sidebar-border: oklch(100% 0 0 / .1);
1199
+ --sidebar-ring: oklch(55.6% 0 0);
1200
+ }
1201
+
1202
+ @property --tw-translate-x {
1203
+ syntax: "*";
1204
+ inherits: false;
1205
+ initial-value: 0;
1206
+ }
1207
+
1208
+ @property --tw-translate-y {
1209
+ syntax: "*";
1210
+ inherits: false;
1211
+ initial-value: 0;
1212
+ }
1213
+
1214
+ @property --tw-translate-z {
1215
+ syntax: "*";
1216
+ inherits: false;
1217
+ initial-value: 0;
1218
+ }
1219
+
1220
+ @property --tw-rotate-x {
1221
+ syntax: "*";
1222
+ inherits: false
1223
+ }
1224
+
1225
+ @property --tw-rotate-y {
1226
+ syntax: "*";
1227
+ inherits: false
1228
+ }
1229
+
1230
+ @property --tw-rotate-z {
1231
+ syntax: "*";
1232
+ inherits: false
1233
+ }
1234
+
1235
+ @property --tw-skew-x {
1236
+ syntax: "*";
1237
+ inherits: false
1238
+ }
1239
+
1240
+ @property --tw-skew-y {
1241
+ syntax: "*";
1242
+ inherits: false
1243
+ }
1244
+
1245
+ @property --tw-border-style {
1246
+ syntax: "*";
1247
+ inherits: false;
1248
+ initial-value: solid;
1249
+ }
1250
+
1251
+ @property --tw-font-weight {
1252
+ syntax: "*";
1253
+ inherits: false
1254
+ }
1255
+
1256
+ @property --tw-shadow {
1257
+ syntax: "*";
1258
+ inherits: false;
1259
+ initial-value: 0 0 #0000;
1260
+ }
1261
+
1262
+ @property --tw-shadow-color {
1263
+ syntax: "*";
1264
+ inherits: false
1265
+ }
1266
+
1267
+ @property --tw-shadow-alpha {
1268
+ syntax: "<percentage>";
1269
+ inherits: false;
1270
+ initial-value: 100%;
1271
+ }
1272
+
1273
+ @property --tw-inset-shadow {
1274
+ syntax: "*";
1275
+ inherits: false;
1276
+ initial-value: 0 0 #0000;
1277
+ }
1278
+
1279
+ @property --tw-inset-shadow-color {
1280
+ syntax: "*";
1281
+ inherits: false
1282
+ }
1283
+
1284
+ @property --tw-inset-shadow-alpha {
1285
+ syntax: "<percentage>";
1286
+ inherits: false;
1287
+ initial-value: 100%;
1288
+ }
1289
+
1290
+ @property --tw-ring-color {
1291
+ syntax: "*";
1292
+ inherits: false
1293
+ }
1294
+
1295
+ @property --tw-ring-shadow {
1296
+ syntax: "*";
1297
+ inherits: false;
1298
+ initial-value: 0 0 #0000;
1299
+ }
1300
+
1301
+ @property --tw-inset-ring-color {
1302
+ syntax: "*";
1303
+ inherits: false
1304
+ }
1305
+
1306
+ @property --tw-inset-ring-shadow {
1307
+ syntax: "*";
1308
+ inherits: false;
1309
+ initial-value: 0 0 #0000;
1310
+ }
1311
+
1312
+ @property --tw-ring-inset {
1313
+ syntax: "*";
1314
+ inherits: false
1315
+ }
1316
+
1317
+ @property --tw-ring-offset-width {
1318
+ syntax: "<length>";
1319
+ inherits: false;
1320
+ initial-value: 0;
1321
+ }
1322
+
1323
+ @property --tw-ring-offset-color {
1324
+ syntax: "*";
1325
+ inherits: false;
1326
+ initial-value: #fff;
1327
+ }
1328
+
1329
+ @property --tw-ring-offset-shadow {
1330
+ syntax: "*";
1331
+ inherits: false;
1332
+ initial-value: 0 0 #0000;
1333
+ }
1334
+
1335
+ @property --tw-outline-style {
1336
+ syntax: "*";
1337
+ inherits: false;
1338
+ initial-value: solid;
1339
+ }
1340
+ /*$vite$:1*/`;
1341
+ document.head.appendChild(__vite_style__);
1342
+ class CanvasStage {
1343
+ constructor(core, config) {
1344
+ __privateAdd(this, _CanvasStage_instances);
1345
+ __privateAdd(this, _core);
1346
+ __privateAdd(this, _stage);
1347
+ __privateAdd(this, _viewport, { x: 0, y: 0, scale: 1 });
1348
+ /**
1349
+ * 处理滚轮缩放和平移
1350
+ */
1351
+ __privateAdd(this, _handleWheel, (e) => {
1352
+ e.evt.preventDefault();
1353
+ const stage = __privateGet(this, _stage);
1354
+ const pointer = stage.getPointerPosition();
1355
+ if (!pointer) return;
1356
+ if (e.evt.ctrlKey) {
1357
+ const oldScale = __privateGet(this, _viewport).scale;
1358
+ const mousePointTo = {
1359
+ x: (pointer.x - __privateGet(this, _viewport).x) / oldScale,
1360
+ y: (pointer.y - __privateGet(this, _viewport).y) / oldScale
1361
+ };
1362
+ const scaleBy = 1.01;
1363
+ const direction = e.evt.deltaY > 0 ? -1 : 1;
1364
+ const steps = Math.min(Math.abs(e.evt.deltaY), 10);
1365
+ let newScale = oldScale;
1366
+ for (let i = 0; i < steps; i++) {
1367
+ newScale = direction > 0 ? newScale * scaleBy : newScale / scaleBy;
1368
+ }
1369
+ const scale = Math.max(0.1, Math.min(5, newScale));
1370
+ const newPos = {
1371
+ x: pointer.x - mousePointTo.x * scale,
1372
+ y: pointer.y - mousePointTo.y * scale
1373
+ };
1374
+ __privateGet(this, _core).updateViewport({ x: newPos.x, y: newPos.y, scale });
1375
+ } else {
1376
+ const deltaX = e.evt.shiftKey ? e.evt.deltaY : e.evt.deltaX;
1377
+ const deltaY = e.evt.shiftKey ? 0 : e.evt.deltaY;
1378
+ __privateGet(this, _core).updateViewport({
1379
+ x: __privateGet(this, _viewport).x - deltaX,
1380
+ y: __privateGet(this, _viewport).y - deltaY
1381
+ });
1382
+ }
1383
+ });
1384
+ __privateAdd(this, _handlePointerDown, (event) => {
1385
+ const toolType = __privateGet(this, _core).getState().toolType;
1386
+ if (event.evt.button !== 0 || toolType === "hand") {
1387
+ return;
1388
+ }
1389
+ const clickedOnEmpty = event.target === __privateGet(this, _stage);
1390
+ const pointerPos = __privateGet(this, _stage).getRelativePointerPosition();
1391
+ if (toolType === "select" && !clickedOnEmpty) {
1392
+ const nodeId = event.target.id();
1393
+ if (nodeId) {
1394
+ __privateGet(this, _core).selectNode(nodeId, event.evt.shiftKey);
1395
+ }
1396
+ return;
1397
+ }
1398
+ if (toolType === "rectangle" && pointerPos) {
1399
+ __privateGet(this, _core).createDraftNode(toolType, pointerPos);
1400
+ }
1401
+ if (toolType === "image-marker" && pointerPos) {
1402
+ const imageShape = __privateGet(this, _core).findImageAtPosition(pointerPos);
1403
+ if (imageShape) {
1404
+ const width = imageShape.width();
1405
+ const height = imageShape.height();
1406
+ if (width && height) {
1407
+ const imageBounds = {
1408
+ x: imageShape.x(),
1409
+ y: imageShape.y(),
1410
+ width,
1411
+ height
1412
+ };
1413
+ __privateGet(this, _core).createDraftNode(toolType, pointerPos, {
1414
+ parent: imageShape.id(),
1415
+ bounds: imageBounds,
1416
+ startPosition: pointerPos
1417
+ });
1418
+ }
1419
+ }
1420
+ }
1421
+ __privateGet(this, _core).selectNode();
1422
+ });
1423
+ __privateAdd(this, _handlePointerMove, () => {
1424
+ const toolType = __privateGet(this, _core).getState().toolType;
1425
+ if (toolType === "hand") {
1426
+ return;
1427
+ }
1428
+ const pointerPos = __privateGet(this, _stage).getRelativePointerPosition();
1429
+ if ((toolType === "rectangle" || toolType === "image-marker") && pointerPos) {
1430
+ __privateGet(this, _core).updateDraftNode(pointerPos);
1431
+ }
1432
+ });
1433
+ __privateAdd(this, _handlePointerUp, () => {
1434
+ const toolType = __privateGet(this, _core).getState().toolType;
1435
+ if (toolType === "hand") {
1436
+ return;
1437
+ }
1438
+ if (toolType === "rectangle" || toolType === "image-marker") {
1439
+ __privateGet(this, _core).finalizeDraftNode();
1440
+ }
1441
+ });
1442
+ __privateAdd(this, _handleDragStart, (event) => {
1443
+ if (event.target !== __privateGet(this, _stage)) {
1444
+ return;
1445
+ }
1446
+ const toolType = __privateGet(this, _core).getState().toolType;
1447
+ if (toolType === "hand") {
1448
+ this.setCursor("grabbing");
1449
+ } else if (toolType === "select") {
1450
+ this.setCursor("all-scroll");
1451
+ }
1452
+ });
1453
+ __privateAdd(this, _handleDragMove, (event) => {
1454
+ if (event.target !== __privateGet(this, _stage)) {
1455
+ return;
1456
+ }
1457
+ __privateGet(this, _core).updateViewport({
1458
+ x: __privateGet(this, _stage).x(),
1459
+ y: __privateGet(this, _stage).y()
1460
+ });
1461
+ });
1462
+ __privateAdd(this, _handleDragEnd, (event) => {
1463
+ if (event.target !== __privateGet(this, _stage)) {
1464
+ return;
1465
+ }
1466
+ __privateGet(this, _core).updateViewport({
1467
+ x: __privateGet(this, _stage).x(),
1468
+ y: __privateGet(this, _stage).y()
1469
+ });
1470
+ this.resetCursor();
1471
+ });
1472
+ __privateSet(this, _core, core);
1473
+ __privateSet(this, _stage, new Konva.Stage({
1474
+ container: config.container,
1475
+ width: config.width,
1476
+ height: config.height,
1477
+ x: 0,
1478
+ y: 0,
1479
+ scaleX: 1,
1480
+ scaleY: 1,
1481
+ draggable: config.draggable ?? false,
1482
+ className: config.className
1483
+ }));
1484
+ __privateMethod(this, _CanvasStage_instances, setupEventListeners_fn).call(this);
1485
+ }
1486
+ /**
1487
+ * 获取原生 Konva.Stage 实例
1488
+ */
1489
+ getStage() {
1490
+ return __privateGet(this, _stage);
1491
+ }
1492
+ /**
1493
+ * 获取当前视口状态
1494
+ */
1495
+ getViewport() {
1496
+ return { ...__privateGet(this, _viewport) };
1497
+ }
1498
+ /**
1499
+ * 设置视口(包括位置、缩放和尺寸)
1500
+ */
1501
+ setViewport(viewport) {
1502
+ const newViewport = { ...__privateGet(this, _viewport), ...viewport };
1503
+ __privateSet(this, _viewport, newViewport);
1504
+ if (viewport.x !== void 0) {
1505
+ __privateGet(this, _stage).x(viewport.x);
1506
+ }
1507
+ if (viewport.y !== void 0) {
1508
+ __privateGet(this, _stage).y(viewport.y);
1509
+ }
1510
+ if (viewport.scale !== void 0) {
1511
+ __privateGet(this, _stage).scaleX(viewport.scale);
1512
+ __privateGet(this, _stage).scaleY(viewport.scale);
1513
+ }
1514
+ if (viewport.width !== void 0) {
1515
+ __privateGet(this, _stage).width(viewport.width);
1516
+ }
1517
+ if (viewport.height !== void 0) {
1518
+ __privateGet(this, _stage).height(viewport.height);
1519
+ }
1520
+ }
1521
+ /**
1522
+ * 设置是否可拖拽
1523
+ */
1524
+ setDraggable(draggable) {
1525
+ __privateGet(this, _stage).draggable(draggable);
1526
+ }
1527
+ /**
1528
+ * 设置光标样式
1529
+ */
1530
+ setCursor(cursor) {
1531
+ const container = __privateGet(this, _stage).container();
1532
+ container.style.cursor = cursor;
1533
+ }
1534
+ /**
1535
+ * 重置光标样式
1536
+ */
1537
+ resetCursor() {
1538
+ const container = __privateGet(this, _stage).container();
1539
+ const toolType = __privateGet(this, _core).getState().toolType;
1540
+ if (toolType === "hand") {
1541
+ container.style.cursor = "grab";
1542
+ return;
1543
+ }
1544
+ container.style.cursor = "default";
1545
+ }
1546
+ /**
1547
+ * 销毁 Stage
1548
+ */
1549
+ destroy() {
1550
+ __privateGet(this, _stage).destroy();
1551
+ }
1552
+ }
1553
+ _core = new WeakMap();
1554
+ _stage = new WeakMap();
1555
+ _viewport = new WeakMap();
1556
+ _handleWheel = new WeakMap();
1557
+ _handlePointerDown = new WeakMap();
1558
+ _handlePointerMove = new WeakMap();
1559
+ _handlePointerUp = new WeakMap();
1560
+ _handleDragStart = new WeakMap();
1561
+ _handleDragMove = new WeakMap();
1562
+ _handleDragEnd = new WeakMap();
1563
+ _CanvasStage_instances = new WeakSet();
1564
+ /**
1565
+ * 设置事件监听器
1566
+ */
1567
+ setupEventListeners_fn = function() {
1568
+ __privateGet(this, _stage).on("wheel", __privateGet(this, _handleWheel));
1569
+ __privateGet(this, _stage).on("pointerdown", __privateGet(this, _handlePointerDown));
1570
+ __privateGet(this, _stage).on("pointermove", __privateGet(this, _handlePointerMove));
1571
+ __privateGet(this, _stage).on("pointerup", __privateGet(this, _handlePointerUp));
1572
+ __privateGet(this, _stage).on("dragstart", __privateGet(this, _handleDragStart));
1573
+ __privateGet(this, _stage).on("dragmove", __privateGet(this, _handleDragMove));
1574
+ __privateGet(this, _stage).on("dragend", __privateGet(this, _handleDragEnd));
1575
+ };
1576
+ class CanvasTransformer {
1577
+ constructor(core, config) {
1578
+ __privateAdd(this, _CanvasTransformer_instances);
1579
+ __privateAdd(this, _core2);
1580
+ __privateAdd(this, _transformer);
1581
+ /**
1582
+ * 处理 transformstart 事件
1583
+ */
1584
+ __privateAdd(this, _handleTransformStart, () => {
1585
+ this.emitPositionChange();
1586
+ });
1587
+ /**
1588
+ * 处理 transform 事件
1589
+ */
1590
+ __privateAdd(this, _handleTransform, () => {
1591
+ console.log("transforming...");
1592
+ this.emitPositionChange();
1593
+ });
1594
+ /**
1595
+ * 处理 transformend 事件
1596
+ */
1597
+ __privateAdd(this, _handleTransformEnd, () => {
1598
+ this.emitPositionChange();
1599
+ });
1600
+ /**
1601
+ * 处理 dragstart 事件
1602
+ */
1603
+ __privateAdd(this, _handleDragStart2, () => {
1604
+ this.emitPositionChange();
1605
+ });
1606
+ /**
1607
+ * 处理 dragmove 事件
1608
+ */
1609
+ __privateAdd(this, _handleDragMove2, () => {
1610
+ this.emitPositionChange();
1611
+ });
1612
+ /**
1613
+ * 处理 dragend 事件
1614
+ */
1615
+ __privateAdd(this, _handleDragEnd2, () => {
1616
+ this.emitPositionChange();
1617
+ });
1618
+ __privateSet(this, _core2, core);
1619
+ __privateSet(this, _transformer, new Konva.Transformer({
1620
+ rotateEnabled: config?.rotateEnabled ?? true,
1621
+ ignoreStroke: config?.ignoreStroke ?? true,
1622
+ anchorSize: config?.anchorSize ?? 8,
1623
+ borderDash: config?.borderDash ?? [4, 4],
1624
+ anchorCornerRadius: config?.anchorCornerRadius ?? 4,
1625
+ padding: config?.padding ?? 6
1626
+ }));
1627
+ __privateMethod(this, _CanvasTransformer_instances, setupEventListeners_fn2).call(this);
1628
+ }
1629
+ /**
1630
+ * 获取原生 Konva.Transformer 实例
1631
+ */
1632
+ getTransformer() {
1633
+ return __privateGet(this, _transformer);
1634
+ }
1635
+ /**
1636
+ * 获取 Transformer 的位置信息
1637
+ */
1638
+ getPosition() {
1639
+ const nodes = __privateGet(this, _transformer).nodes();
1640
+ if (nodes.length === 0) {
1641
+ return null;
1642
+ }
1643
+ const box = __privateGet(this, _transformer).getClientRect();
1644
+ return {
1645
+ x: box.x,
1646
+ y: box.y,
1647
+ width: box.width,
1648
+ height: box.height,
1649
+ rotation: __privateGet(this, _transformer).rotation()
1650
+ };
1651
+ }
1652
+ /**
1653
+ * 设置要变换的节点
1654
+ */
1655
+ setNodes(nodes) {
1656
+ if (nodes.length === 0) {
1657
+ this.clearNodes();
1658
+ return;
1659
+ }
1660
+ __privateGet(this, _transformer).nodes(nodes);
1661
+ __privateGet(this, _transformer).moveToTop();
1662
+ this.emitPositionChange();
1663
+ }
1664
+ /**
1665
+ * 获取当前变换的节点
1666
+ */
1667
+ getNodes() {
1668
+ return __privateGet(this, _transformer).nodes();
1669
+ }
1670
+ /**
1671
+ * 清除所有节点
1672
+ */
1673
+ clearNodes() {
1674
+ __privateGet(this, _transformer).nodes([]);
1675
+ __privateGet(this, _transformer).moveToBottom();
1676
+ this.emitPositionChange();
1677
+ }
1678
+ /**
1679
+ * emit Transformer 位置
1680
+ */
1681
+ emitPositionChange() {
1682
+ const position = this.getPosition();
1683
+ __privateGet(this, _core2).emitEvent("transformer:positionChange", position);
1684
+ }
1685
+ /**
1686
+ * 销毁 Transformer
1687
+ */
1688
+ destroy() {
1689
+ __privateGet(this, _transformer).destroy();
1690
+ }
1691
+ }
1692
+ _core2 = new WeakMap();
1693
+ _transformer = new WeakMap();
1694
+ _handleTransformStart = new WeakMap();
1695
+ _handleTransform = new WeakMap();
1696
+ _handleTransformEnd = new WeakMap();
1697
+ _handleDragStart2 = new WeakMap();
1698
+ _handleDragMove2 = new WeakMap();
1699
+ _handleDragEnd2 = new WeakMap();
1700
+ _CanvasTransformer_instances = new WeakSet();
1701
+ /**
1702
+ * 设置事件监听器
1703
+ */
1704
+ setupEventListeners_fn2 = function() {
1705
+ __privateGet(this, _transformer).on("transformstart", __privateGet(this, _handleTransformStart));
1706
+ __privateGet(this, _transformer).on("transform", __privateGet(this, _handleTransform));
1707
+ __privateGet(this, _transformer).on("transformend", __privateGet(this, _handleTransformEnd));
1708
+ __privateGet(this, _transformer).on("dragstart", __privateGet(this, _handleDragStart2));
1709
+ __privateGet(this, _transformer).on("dragmove", __privateGet(this, _handleDragMove2));
1710
+ __privateGet(this, _transformer).on("dragend", __privateGet(this, _handleDragEnd2));
1711
+ };
1712
+ class CanvasState {
1713
+ constructor(initialState) {
1714
+ __publicField(this, "_past", []);
1715
+ __publicField(this, "_present");
1716
+ __publicField(this, "_future", []);
1717
+ __publicField(this, "_emitter");
1718
+ this._present = initialState;
1719
+ this._emitter = mitt();
1720
+ }
1721
+ /**
1722
+ * 获取当前状态
1723
+ */
1724
+ getState() {
1725
+ return { ...this._present };
1726
+ }
1727
+ /**
1728
+ * 获取完整历史状态
1729
+ */
1730
+ getHistory() {
1731
+ return {
1732
+ past: [...this._past],
1733
+ present: { ...this._present },
1734
+ future: [...this._future]
1735
+ };
1736
+ }
1737
+ /**
1738
+ * 是否可以撤销
1739
+ */
1740
+ canUndo() {
1741
+ return this._past.length > 0;
1742
+ }
1743
+ /**
1744
+ * 是否可以重做
1745
+ */
1746
+ canRedo() {
1747
+ return this._future.length > 0;
1748
+ }
1749
+ /**
1750
+ * 订阅状态事件
1751
+ */
1752
+ on(event, handler) {
1753
+ this._emitter.on(event, handler);
1754
+ }
1755
+ /**
1756
+ * 取消订阅状态事件
1757
+ */
1758
+ off(event, handler) {
1759
+ this._emitter.off(event, handler);
1760
+ }
1761
+ /**
1762
+ * 发送事件
1763
+ */
1764
+ emit(event, data) {
1765
+ this._emitter.emit(event, data);
1766
+ }
1767
+ /**
1768
+ * 撤销操作
1769
+ */
1770
+ undo() {
1771
+ if (this._past.length === 0) return;
1772
+ const previous = this._past[this._past.length - 1];
1773
+ const newPast = this._past.slice(0, this._past.length - 1);
1774
+ this._past = newPast;
1775
+ this._future = [this._present, ...this._future];
1776
+ this._present = previous;
1777
+ this._syncState(previous);
1778
+ this._emitter.emit("state:undo", previous);
1779
+ this._emitter.emit("state:change", previous);
1780
+ }
1781
+ /**
1782
+ * 重做操作
1783
+ */
1784
+ redo() {
1785
+ if (this._future.length === 0) return;
1786
+ const next = this._future[0];
1787
+ const newFuture = this._future.slice(1);
1788
+ this._past = [...this._past, this._present];
1789
+ this._future = newFuture;
1790
+ this._present = next;
1791
+ this._syncState(next);
1792
+ this._emitter.emit("state:redo", next);
1793
+ this._emitter.emit("state:change", next);
1794
+ }
1795
+ /**
1796
+ * 重置历史记录
1797
+ */
1798
+ resetHistory() {
1799
+ this._past = [];
1800
+ this._future = [];
1801
+ this._emitter.emit("state:reset", this._present);
1802
+ this._emitter.emit("state:change", this._present);
1803
+ }
1804
+ /**
1805
+ * 更新状态
1806
+ * @param partial - 部分状态更新
1807
+ * @param addToHistory - 是否添加到历史记录
1808
+ */
1809
+ _updateState(partial, addToHistory = true) {
1810
+ const newState = { ...this._present, ...partial };
1811
+ if (addToHistory) {
1812
+ this._past = [...this._past, this._present];
1813
+ this._future = [];
1814
+ }
1815
+ this._present = newState;
1816
+ this._emitter.emit("state:change", newState);
1817
+ }
1818
+ /**
1819
+ * 同步状态到外部系统(由子类实现)
1820
+ * @param _state - 要同步的状态
1821
+ */
1822
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1823
+ _syncState(_state) {
1824
+ }
1825
+ /**
1826
+ * 清理资源
1827
+ */
1828
+ _dispose() {
1829
+ this._emitter.all.clear();
1830
+ }
1831
+ }
1832
+ const NODE_NAME_FOR_SELECT = "shapeNameForSelect";
1833
+ const RECT$1 = {
1834
+ CORNER_RADIUS: 6,
1835
+ MIN_SIZE: 10
1836
+ };
1837
+ const IMAGE = {
1838
+ MIN_SIZE: 10
1839
+ };
1840
+ const RECT = {
1841
+ MIN_SIZE: 10
1842
+ };
1843
+ function calculatePerimeter(width, height, cornerRadius) {
1844
+ return 2 * (height + width - cornerRadius * (4 - Math.PI));
1845
+ }
1846
+ function getDashValue(shapeLength, strokeWidth, lineStyle) {
1847
+ let ratio = 1;
1848
+ let dashLength = 0;
1849
+ let dashGap = 0;
1850
+ switch (lineStyle) {
1851
+ case "dashed":
1852
+ dashLength = Math.min(strokeWidth * 2, shapeLength / 4);
1853
+ break;
1854
+ case "dotted":
1855
+ ratio = 8;
1856
+ dashLength = strokeWidth / ratio;
1857
+ break;
1858
+ default:
1859
+ return [];
1860
+ }
1861
+ let dashCount = Math.floor(shapeLength / dashLength / (2 * ratio));
1862
+ dashCount = Math.max(dashCount, 3);
1863
+ dashLength = shapeLength / dashCount / (2 * ratio);
1864
+ dashGap = (shapeLength - dashCount * dashLength) / dashCount;
1865
+ return [dashLength, dashGap];
1866
+ }
1867
+ function getSizeValue(key) {
1868
+ switch (key) {
1869
+ case "small":
1870
+ return 2;
1871
+ case "medium":
1872
+ return 3;
1873
+ case "large":
1874
+ return 5;
1875
+ case "extra-large":
1876
+ return 8;
1877
+ default:
1878
+ return 3;
1879
+ }
1880
+ }
1881
+ function getTotalDashLength(dash) {
1882
+ return Array.isArray(dash) && dash.length > 1 ? dash[0] + dash[1] : 0;
1883
+ }
1884
+ function getRectSize(rect) {
1885
+ return {
1886
+ width: Math.max(RECT.MIN_SIZE, rect.width() * rect.scaleX()),
1887
+ height: Math.max(RECT.MIN_SIZE, rect.height() * rect.scaleY())
1888
+ };
1889
+ }
1890
+ class BaseCanvasNode {
1891
+ constructor(core, node) {
1892
+ __publicField(this, "core");
1893
+ __publicField(this, "node");
1894
+ __publicField(this, "element");
1895
+ __publicField(this, "toolTypeChangeHandler");
1896
+ this.core = core;
1897
+ this.node = node;
1898
+ this.element = this.createElement();
1899
+ this.toolTypeChangeHandler = (toolType) => {
1900
+ const isSelect = toolType === "select";
1901
+ this.element.listening(isSelect);
1902
+ };
1903
+ this.toolTypeChangeHandler(this.core.getToolType());
1904
+ this.core.on("toolType:change", this.toolTypeChangeHandler);
1905
+ }
1906
+ /**
1907
+ * 获取 Konva 元素
1908
+ */
1909
+ getElement() {
1910
+ return this.element;
1911
+ }
1912
+ /**
1913
+ * 获取节点数据
1914
+ */
1915
+ getNode() {
1916
+ return this.node;
1917
+ }
1918
+ /**
1919
+ * 销毁节点
1920
+ */
1921
+ destroy() {
1922
+ this.core.off("toolType:change", this.toolTypeChangeHandler);
1923
+ this.element.destroy();
1924
+ }
1925
+ }
1926
+ function createRectAnimation(rect, totalDashLength) {
1927
+ if (!totalDashLength || totalDashLength === 0) {
1928
+ return null;
1929
+ }
1930
+ const anim = new Konva.Animation((frame) => {
1931
+ if (!frame) return;
1932
+ const dashOffset = -frame.time / 10 % totalDashLength;
1933
+ rect.dashOffset(dashOffset);
1934
+ }, rect.getLayer());
1935
+ return {
1936
+ start: () => anim.start(),
1937
+ stop: () => anim.stop(),
1938
+ isRunning: () => anim.isRunning()
1939
+ };
1940
+ }
1941
+ class RectNode extends BaseCanvasNode {
1942
+ constructor(core, node) {
1943
+ super(core, node);
1944
+ __privateAdd(this, _RectNode_instances);
1945
+ __privateAdd(this, _animation, null);
1946
+ if (node.style.animated) {
1947
+ __privateMethod(this, _RectNode_instances, initAnimation_fn).call(this);
1948
+ }
1949
+ __privateMethod(this, _RectNode_instances, setupEventHandlers_fn).call(this, this.getElement());
1950
+ }
1951
+ createElement() {
1952
+ const width = Math.max(
1953
+ this.node.props.width ?? RECT$1.MIN_SIZE,
1954
+ RECT$1.MIN_SIZE
1955
+ );
1956
+ const height = Math.max(
1957
+ this.node.props.height ?? RECT$1.MIN_SIZE,
1958
+ RECT$1.MIN_SIZE
1959
+ );
1960
+ const config = {
1961
+ id: this.node.id,
1962
+ ...this.node.props,
1963
+ ...this.node.style,
1964
+ width,
1965
+ height,
1966
+ cornerRadius: RECT$1.CORNER_RADIUS,
1967
+ name: NODE_NAME_FOR_SELECT,
1968
+ draggable: true,
1969
+ stroke: "black",
1970
+ strokeWidth: 2
1971
+ };
1972
+ const rect = new Konva.Rect(config);
1973
+ rect.setAttrs({
1974
+ width,
1975
+ height
1976
+ });
1977
+ return rect;
1978
+ }
1979
+ /**
1980
+ * 获取 Konva.Rect 实例
1981
+ */
1982
+ getElement() {
1983
+ return this.element;
1984
+ }
1985
+ /**
1986
+ * 更新节点数据
1987
+ */
1988
+ updateNode(node) {
1989
+ this.node = {
1990
+ ...this.node,
1991
+ ...node,
1992
+ props: {
1993
+ ...this.node.props,
1994
+ ...node.props
1995
+ },
1996
+ style: {
1997
+ ...this.node.style,
1998
+ ...node.style
1999
+ }
2000
+ };
2001
+ const rect = this.getElement();
2002
+ rect.x(this.node.props.x);
2003
+ rect.y(this.node.props.y);
2004
+ const width = Math.max(
2005
+ this.node.props.width ?? RECT$1.MIN_SIZE,
2006
+ RECT$1.MIN_SIZE
2007
+ );
2008
+ const height = Math.max(
2009
+ this.node.props.height ?? RECT$1.MIN_SIZE,
2010
+ RECT$1.MIN_SIZE
2011
+ );
2012
+ rect.width(width);
2013
+ rect.height(height);
2014
+ if (this.node.style.animated && !__privateGet(this, _animation)) {
2015
+ __privateMethod(this, _RectNode_instances, initAnimation_fn).call(this);
2016
+ } else if (!this.node.style.animated && __privateGet(this, _animation)) {
2017
+ __privateMethod(this, _RectNode_instances, destroyAnimation_fn).call(this);
2018
+ }
2019
+ }
2020
+ /**
2021
+ * 销毁
2022
+ */
2023
+ destroy() {
2024
+ __privateMethod(this, _RectNode_instances, destroyAnimation_fn).call(this);
2025
+ super.destroy();
2026
+ }
2027
+ }
2028
+ _animation = new WeakMap();
2029
+ _RectNode_instances = new WeakSet();
2030
+ /**
2031
+ * 初始化动画
2032
+ */
2033
+ initAnimation_fn = function() {
2034
+ const rect = this.getElement();
2035
+ const dash = rect.dash();
2036
+ if (!dash || dash.length === 0) return;
2037
+ const totalDashLength = getTotalDashLength(dash);
2038
+ __privateSet(this, _animation, createRectAnimation(rect, totalDashLength));
2039
+ if (__privateGet(this, _animation)) {
2040
+ __privateGet(this, _animation).start();
2041
+ }
2042
+ };
2043
+ /**
2044
+ * 销毁动画
2045
+ */
2046
+ destroyAnimation_fn = function() {
2047
+ if (__privateGet(this, _animation)) {
2048
+ __privateGet(this, _animation).stop();
2049
+ __privateSet(this, _animation, null);
2050
+ }
2051
+ };
2052
+ /**
2053
+ * 设置事件处理器
2054
+ */
2055
+ setupEventHandlers_fn = function(rect = void 0) {
2056
+ const element = rect ?? this.getElement();
2057
+ element.on("transformstart", () => {
2058
+ if (this.node.style.animated && __privateGet(this, _animation)) {
2059
+ __privateGet(this, _animation).stop();
2060
+ }
2061
+ });
2062
+ element.on("transform", (event) => {
2063
+ const rect2 = event.target;
2064
+ const { width, height } = getRectSize(rect2);
2065
+ const totalLength = calculatePerimeter(width, height, RECT$1.CORNER_RADIUS);
2066
+ const dash = getDashValue(
2067
+ totalLength,
2068
+ getSizeValue(this.node.style.size),
2069
+ this.node.style.line
2070
+ );
2071
+ rect2.scale({ x: 1, y: 1 });
2072
+ rect2.width(width);
2073
+ rect2.height(height);
2074
+ rect2.dash(dash.map((d) => d * this.core.getStageScale()));
2075
+ });
2076
+ element.on("transformend", (event) => {
2077
+ const rect2 = event.target;
2078
+ const { width, height } = getRectSize(rect2);
2079
+ const newProps = {
2080
+ ...this.node.props,
2081
+ x: rect2.x(),
2082
+ y: rect2.y(),
2083
+ width,
2084
+ height,
2085
+ rotation: rect2.rotation()
2086
+ };
2087
+ this.node.props = newProps;
2088
+ this.core._syncNodeFromElement(this.node.id, {
2089
+ props: newProps
2090
+ });
2091
+ if (this.node.style.animated && __privateGet(this, _animation)?.isRunning() === false) {
2092
+ __privateGet(this, _animation).start();
2093
+ }
2094
+ });
2095
+ element.on("dragend", (event) => {
2096
+ const rect2 = event.target;
2097
+ const newProps = {
2098
+ ...this.node.props,
2099
+ x: rect2.x(),
2100
+ y: rect2.y()
2101
+ };
2102
+ this.node.props = newProps;
2103
+ this.core._syncNodeFromElement(this.node.id, {
2104
+ props: newProps
2105
+ });
2106
+ });
2107
+ };
2108
+ class ImageNode extends BaseCanvasNode {
2109
+ constructor(core, node) {
2110
+ super(core, node);
2111
+ __privateAdd(this, _ImageNode_instances);
2112
+ __privateMethod(this, _ImageNode_instances, loadImage_fn).call(this);
2113
+ __privateMethod(this, _ImageNode_instances, setupEventHandlers_fn2).call(this, this.getElement());
2114
+ }
2115
+ createElement() {
2116
+ const placeholder = document.createElement("canvas");
2117
+ placeholder.width = 1;
2118
+ placeholder.height = 1;
2119
+ const img = new Konva.Image({
2120
+ id: this.node.id,
2121
+ x: this.node.props.x,
2122
+ y: this.node.props.y,
2123
+ name: NODE_NAME_FOR_SELECT,
2124
+ draggable: true,
2125
+ image: placeholder
2126
+ });
2127
+ return img;
2128
+ }
2129
+ /**
2130
+ * 获取 Konva.Image 实例
2131
+ */
2132
+ getElement() {
2133
+ return this.element;
2134
+ }
2135
+ /**
2136
+ * 更新节点数据
2137
+ */
2138
+ updateNode(node) {
2139
+ this.node = {
2140
+ ...this.node,
2141
+ ...node,
2142
+ props: {
2143
+ ...this.node.props,
2144
+ ...node.props
2145
+ },
2146
+ style: {
2147
+ ...this.node.style,
2148
+ ...node.style
2149
+ },
2150
+ meta: {
2151
+ ...this.node.meta,
2152
+ ...node.meta
2153
+ }
2154
+ };
2155
+ const img = this.getElement();
2156
+ img.x(this.node.props.x);
2157
+ img.y(this.node.props.y);
2158
+ if (this.node.props.width && this.node.props.height) {
2159
+ const width = Math.max(this.node.props.width, IMAGE.MIN_SIZE);
2160
+ const height = Math.max(this.node.props.height, IMAGE.MIN_SIZE);
2161
+ img.width(width);
2162
+ img.height(height);
2163
+ }
2164
+ if (this.node.props.rotation !== void 0) {
2165
+ img.rotation(this.node.props.rotation);
2166
+ }
2167
+ if (node.meta?.imageUrl && node.meta.imageUrl !== this.node.meta.imageUrl) {
2168
+ __privateMethod(this, _ImageNode_instances, loadImage_fn).call(this);
2169
+ }
2170
+ }
2171
+ /**
2172
+ * 销毁
2173
+ */
2174
+ destroy() {
2175
+ super.destroy();
2176
+ }
2177
+ }
2178
+ _ImageNode_instances = new WeakSet();
2179
+ /**
2180
+ * 加载图片
2181
+ */
2182
+ loadImage_fn = function() {
2183
+ const imageUrl = this.node.meta.imageUrl;
2184
+ if (!imageUrl) {
2185
+ console.warn("Image URL is missing");
2186
+ return;
2187
+ }
2188
+ const img = new window.Image();
2189
+ img.crossOrigin = "anonymous";
2190
+ img.src = imageUrl;
2191
+ img.onload = () => {
2192
+ this.getElement().image(img);
2193
+ const width = this.node.props.width ?? img.width;
2194
+ const height = this.node.props.height ?? img.height;
2195
+ this.getElement().width(Math.max(width, IMAGE.MIN_SIZE));
2196
+ this.getElement().height(Math.max(height, IMAGE.MIN_SIZE));
2197
+ };
2198
+ img.onerror = () => {
2199
+ console.error("Failed to load image:", imageUrl);
2200
+ };
2201
+ };
2202
+ /**
2203
+ * 设置事件处理器
2204
+ */
2205
+ setupEventHandlers_fn2 = function(img) {
2206
+ img.on("transform", (event) => {
2207
+ const img2 = event.target;
2208
+ const width = Math.max(IMAGE.MIN_SIZE, img2.width() * img2.scaleX());
2209
+ const height = Math.max(IMAGE.MIN_SIZE, img2.height() * img2.scaleY());
2210
+ img2.scale({ x: 1, y: 1 });
2211
+ img2.width(width);
2212
+ img2.height(height);
2213
+ __privateMethod(this, _ImageNode_instances, syncImageMarkers_fn).call(this);
2214
+ });
2215
+ img.on("transformend", (event) => {
2216
+ const img2 = event.target;
2217
+ const newProps = {
2218
+ ...this.node.props,
2219
+ x: img2.x(),
2220
+ y: img2.y(),
2221
+ width: img2.width(),
2222
+ height: img2.height(),
2223
+ rotation: img2.rotation()
2224
+ };
2225
+ this.node.props = newProps;
2226
+ this.core._syncNodeFromElement(this.node.id, {
2227
+ props: newProps
2228
+ });
2229
+ __privateMethod(this, _ImageNode_instances, syncImageMarkersToState_fn).call(this);
2230
+ });
2231
+ img.on("dragmove", () => {
2232
+ __privateMethod(this, _ImageNode_instances, syncImageMarkers_fn).call(this);
2233
+ });
2234
+ img.on("dragend", (event) => {
2235
+ const img2 = event.target;
2236
+ const newProps = {
2237
+ ...this.node.props,
2238
+ x: img2.x(),
2239
+ y: img2.y()
2240
+ };
2241
+ this.node.props = newProps;
2242
+ this.core._syncNodeFromElement(this.node.id, {
2243
+ props: newProps
2244
+ });
2245
+ __privateMethod(this, _ImageNode_instances, syncImageMarkersToState_fn).call(this);
2246
+ });
2247
+ };
2248
+ /**
2249
+ * 同步 image-marker 节点的位置(实时更新 Konva 元素)
2250
+ */
2251
+ syncImageMarkers_fn = function() {
2252
+ const img = this.getElement();
2253
+ const layer = img.getLayer();
2254
+ if (!layer) return;
2255
+ const imgX = img.x();
2256
+ const imgY = img.y();
2257
+ const imgWidth = img.width();
2258
+ const imgHeight = img.height();
2259
+ const imageMarkerElements = layer.find(
2260
+ (node) => node.hasName(this.node.id)
2261
+ );
2262
+ const nodes = this.core.getState().nodes || [];
2263
+ imageMarkerElements.forEach((nodeElement) => {
2264
+ const nodeData = nodes.find((n) => n.id === nodeElement.id());
2265
+ if (nodeData?.type === "image-marker" && nodeData.meta.relativePosition) {
2266
+ const { start, end } = nodeData.meta.relativePosition;
2267
+ const startX = imgX + start.percentX / 100 * imgWidth;
2268
+ const startY = imgY + start.percentY / 100 * imgHeight;
2269
+ const endX = imgX + end.percentX / 100 * imgWidth;
2270
+ const endY = imgY + end.percentY / 100 * imgHeight;
2271
+ const newX = Math.min(startX, endX);
2272
+ const newY = Math.min(startY, endY);
2273
+ const newWidth = Math.abs(endX - startX);
2274
+ const newHeight = Math.abs(endY - startY);
2275
+ nodeElement.position({ x: newX, y: newY });
2276
+ nodeElement.setAttrs({ width: newWidth, height: newHeight });
2277
+ const children = nodeElement.getChildren();
2278
+ children.forEach((child) => {
2279
+ if (child.getClassName() === "Rect") {
2280
+ child.setAttrs({ width: newWidth, height: newHeight });
2281
+ } else if (child.getClassName() === "Group") {
2282
+ child.setAttrs({ x: newWidth, y: newHeight });
2283
+ }
2284
+ });
2285
+ }
2286
+ });
2287
+ };
2288
+ /**
2289
+ * 同步 image-marker 节点到状态
2290
+ */
2291
+ syncImageMarkersToState_fn = function() {
2292
+ const img = this.getElement();
2293
+ const layer = img.getLayer();
2294
+ if (!layer) return;
2295
+ const imageMarkerElements = layer.find(
2296
+ (node) => node.hasName(this.node.id)
2297
+ );
2298
+ imageMarkerElements.forEach((nodeElement) => {
2299
+ this.core._syncNodeFromElement(nodeElement.id(), {
2300
+ props: {
2301
+ x: nodeElement.x(),
2302
+ y: nodeElement.y(),
2303
+ width: nodeElement.width(),
2304
+ height: nodeElement.height()
2305
+ }
2306
+ });
2307
+ });
2308
+ };
2309
+ class ImageMarkerNode extends BaseCanvasNode {
2310
+ constructor(core, node) {
2311
+ super(core, node);
2312
+ __privateAdd(this, _ImageMarkerNode_instances);
2313
+ __privateAdd(this, _rect);
2314
+ __privateAdd(this, _markerGroup);
2315
+ __privateAdd(this, _circle);
2316
+ __privateAdd(this, _text);
2317
+ const group = this.getElement();
2318
+ __privateSet(this, _rect, group.findOne(".rect"));
2319
+ __privateSet(this, _markerGroup, group.findOne(".marker-group"));
2320
+ __privateSet(this, _circle, __privateGet(this, _markerGroup).findOne("Circle"));
2321
+ __privateSet(this, _text, __privateGet(this, _markerGroup).findOne("Text"));
2322
+ __privateMethod(this, _ImageMarkerNode_instances, setupEventHandlers_fn3).call(this);
2323
+ }
2324
+ createElement() {
2325
+ const width = Math.max(
2326
+ this.node.props.width ?? RECT$1.MIN_SIZE,
2327
+ RECT$1.MIN_SIZE
2328
+ );
2329
+ const height = Math.max(
2330
+ this.node.props.height ?? RECT$1.MIN_SIZE,
2331
+ RECT$1.MIN_SIZE
2332
+ );
2333
+ const group = new Konva.Group({
2334
+ id: this.node.id,
2335
+ name: `static ${this.node.meta.parent}`,
2336
+ x: this.node.props.x,
2337
+ y: this.node.props.y,
2338
+ width,
2339
+ height
2340
+ });
2341
+ const rect = new Konva.Rect({
2342
+ name: "rect",
2343
+ x: 0,
2344
+ y: 0,
2345
+ width,
2346
+ height,
2347
+ stroke: this.node.style.color,
2348
+ strokeWidth: 2,
2349
+ dash: [5, 5],
2350
+ fill: "transparent",
2351
+ cornerRadius: RECT$1.CORNER_RADIUS
2352
+ });
2353
+ const markerGroup = new Konva.Group({
2354
+ name: "marker-group",
2355
+ x: width,
2356
+ y: height
2357
+ });
2358
+ const stageScale = this.core.getStageScale();
2359
+ const radius = 16 / stageScale;
2360
+ const circle = new Konva.Circle({
2361
+ radius,
2362
+ fill: "red",
2363
+ stroke: "black",
2364
+ strokeWidth: 2
2365
+ });
2366
+ const text = new Konva.Text({
2367
+ x: -radius,
2368
+ y: -radius,
2369
+ width: radius * 2,
2370
+ height: radius * 2,
2371
+ text: String(this.node.meta.markerNumber || ""),
2372
+ align: "center",
2373
+ verticalAlign: "middle",
2374
+ fontSize: 16,
2375
+ fill: "white"
2376
+ });
2377
+ markerGroup.add(circle);
2378
+ markerGroup.add(text);
2379
+ group.add(rect);
2380
+ group.add(markerGroup);
2381
+ return group;
2382
+ }
2383
+ /**
2384
+ * 获取 Konva.Group 实例
2385
+ */
2386
+ getElement() {
2387
+ return this.element;
2388
+ }
2389
+ /**
2390
+ * 更新节点数据
2391
+ */
2392
+ updateNode(node) {
2393
+ this.node = {
2394
+ ...this.node,
2395
+ ...node,
2396
+ props: {
2397
+ ...this.node.props,
2398
+ ...node.props
2399
+ },
2400
+ style: {
2401
+ ...this.node.style,
2402
+ ...node.style
2403
+ },
2404
+ meta: {
2405
+ ...this.node.meta,
2406
+ ...node.meta
2407
+ }
2408
+ };
2409
+ const group = this.getElement();
2410
+ group.x(this.node.props.x);
2411
+ group.y(this.node.props.y);
2412
+ const width = Math.max(
2413
+ this.node.props.width ?? RECT$1.MIN_SIZE,
2414
+ RECT$1.MIN_SIZE
2415
+ );
2416
+ const height = Math.max(
2417
+ this.node.props.height ?? RECT$1.MIN_SIZE,
2418
+ RECT$1.MIN_SIZE
2419
+ );
2420
+ group.width(width);
2421
+ group.height(height);
2422
+ __privateGet(this, _rect).width(width);
2423
+ __privateGet(this, _rect).height(height);
2424
+ __privateGet(this, _markerGroup).x(width);
2425
+ __privateGet(this, _markerGroup).y(height);
2426
+ if (node.style?.color) {
2427
+ __privateGet(this, _rect).stroke(node.style.color);
2428
+ }
2429
+ if (node.meta?.markerNumber !== void 0) {
2430
+ __privateGet(this, _text).text(String(node.meta.markerNumber));
2431
+ }
2432
+ }
2433
+ /**
2434
+ * 销毁
2435
+ */
2436
+ destroy() {
2437
+ super.destroy();
2438
+ }
2439
+ /**
2440
+ * 更新焦点状态(hover 或 selected)
2441
+ */
2442
+ setFocusState(isFocus) {
2443
+ const strokeWidth = isFocus ? 3 : 2;
2444
+ const scale = isFocus ? 1.2 : 1;
2445
+ __privateGet(this, _rect).strokeWidth(strokeWidth);
2446
+ __privateGet(this, _circle).strokeWidth(strokeWidth);
2447
+ __privateGet(this, _markerGroup).scaleX(scale);
2448
+ __privateGet(this, _markerGroup).scaleY(scale);
2449
+ }
2450
+ }
2451
+ _rect = new WeakMap();
2452
+ _markerGroup = new WeakMap();
2453
+ _circle = new WeakMap();
2454
+ _text = new WeakMap();
2455
+ _ImageMarkerNode_instances = new WeakSet();
2456
+ /**
2457
+ * 设置事件处理器
2458
+ */
2459
+ setupEventHandlers_fn3 = function() {
2460
+ __privateGet(this, _markerGroup).on("pointerover", () => {
2461
+ this.setFocusState(true);
2462
+ this.core.setCursor("pointer");
2463
+ });
2464
+ __privateGet(this, _markerGroup).on("pointerout", () => {
2465
+ const selectedIds = this.core.getState().selectedNodeIds || [];
2466
+ const isSelected = selectedIds.includes(this.node.id);
2467
+ this.setFocusState(isSelected);
2468
+ this.core.resetCursor();
2469
+ });
2470
+ __privateGet(this, _markerGroup).on("pointerdown", () => {
2471
+ this.core.selectNode(this.node.id);
2472
+ });
2473
+ };
2474
+ function createCanvasNodeByType(core, type, config) {
2475
+ switch (type) {
2476
+ case "rectangle":
2477
+ return new RectNode(core, config);
2478
+ case "image":
2479
+ return new ImageNode(core, config);
2480
+ case "image-marker":
2481
+ return new ImageMarkerNode(core, config);
2482
+ default:
2483
+ return null;
2484
+ }
2485
+ }
2486
+ const createNodeByType = (type, position, style, meta) => {
2487
+ const baseNode = {
2488
+ type,
2489
+ id: uuid.v4(),
2490
+ text: null,
2491
+ style: {
2492
+ opacity: 1,
2493
+ line: "solid",
2494
+ color: "black",
2495
+ size: "medium",
2496
+ animated: false
2497
+ },
2498
+ props: {
2499
+ x: position.x,
2500
+ y: position.y,
2501
+ rotation: 0,
2502
+ visible: true
2503
+ },
2504
+ meta: meta ?? {}
2505
+ };
2506
+ if (type === "image-marker") {
2507
+ return {
2508
+ ...baseNode,
2509
+ style: {
2510
+ ...baseNode.style,
2511
+ color: "#ff0000",
2512
+ line: "dashed"
2513
+ }
2514
+ };
2515
+ }
2516
+ return baseNode;
2517
+ };
2518
+ function updateNodeByType(node, position, bounds) {
2519
+ let finalPosition = position;
2520
+ if (node.type === "image-marker" && bounds) {
2521
+ finalPosition = {
2522
+ x: Math.max(bounds.x, Math.min(bounds.x + bounds.width, position.x)),
2523
+ y: Math.max(bounds.y, Math.min(bounds.y + bounds.height, position.y))
2524
+ };
2525
+ }
2526
+ const [p1, p2] = normalizePoints(
2527
+ { x: node.props.x, y: node.props.y },
2528
+ finalPosition
2529
+ );
2530
+ if (node.type === "rectangle" || node.type === "image-marker") {
2531
+ return {
2532
+ ...node,
2533
+ props: {
2534
+ ...node.props,
2535
+ x: p1.x,
2536
+ y: p1.y,
2537
+ width: Math.max(p2.x - p1.x, RECT$1.MIN_SIZE),
2538
+ height: Math.max(p2.y - p1.y, RECT$1.MIN_SIZE)
2539
+ }
2540
+ };
2541
+ }
2542
+ return node;
2543
+ }
2544
+ function normalizePoints(p1, p2) {
2545
+ let p1x = p1.x, p1y = p1.y, p2x = p2.x, p2y = p2.y, d;
2546
+ if (p1x > p2x) {
2547
+ d = Math.abs(p1x - p2x);
2548
+ p1x = p2x;
2549
+ p2x = p1x + d;
2550
+ }
2551
+ if (p1y > p2y) {
2552
+ d = Math.abs(p1y - p2y);
2553
+ p1y = p2y;
2554
+ p2y = p1y + d;
2555
+ }
2556
+ return [
2557
+ { x: p1x, y: p1y },
2558
+ { x: p2x, y: p2y }
2559
+ ];
2560
+ }
2561
+ class CanvasCore extends CanvasState {
2562
+ constructor(el) {
2563
+ super({
2564
+ viewport: {
2565
+ x: 0,
2566
+ y: 0,
2567
+ width: el.clientWidth,
2568
+ height: el.clientHeight,
2569
+ scale: 1
2570
+ },
2571
+ toolType: "select",
2572
+ nodes: []
2573
+ });
2574
+ __privateAdd(this, _canvasStage);
2575
+ __privateAdd(this, _mainLayer);
2576
+ __privateAdd(this, _canvasTransformer);
2577
+ __privateAdd(this, _draftNode, null);
2578
+ __privateSet(this, _canvasStage, new CanvasStage(this, {
2579
+ container: el,
2580
+ width: el.clientWidth,
2581
+ height: el.clientHeight,
2582
+ draggable: false,
2583
+ className: "touch-none"
2584
+ }));
2585
+ __privateSet(this, _mainLayer, new Konva.Layer());
2586
+ __privateSet(this, _canvasTransformer, new CanvasTransformer(this));
2587
+ __privateGet(this, _canvasStage).getStage().add(__privateGet(this, _mainLayer));
2588
+ __privateGet(this, _mainLayer).add(__privateGet(this, _canvasTransformer).getTransformer());
2589
+ this.updateViewport(this.getState().viewport, false);
2590
+ }
2591
+ /**
2592
+ * 获取 CanvasStage 实例
2593
+ */
2594
+ getCanvasStage() {
2595
+ return __privateGet(this, _canvasStage);
2596
+ }
2597
+ /**
2598
+ * 获取 CanvasTransformer 实例
2599
+ */
2600
+ getCanvasTransformer() {
2601
+ return __privateGet(this, _canvasTransformer);
2602
+ }
2603
+ /**
2604
+ * 发射事件(供内部类使用)
2605
+ */
2606
+ emitEvent(event, data) {
2607
+ this.emit(event, data);
2608
+ }
2609
+ /**
2610
+ * 获取 Konva.Stage 实例
2611
+ */
2612
+ getStage() {
2613
+ return __privateGet(this, _canvasStage).getStage();
2614
+ }
2615
+ /**
2616
+ * 获取 Stage 容器元素
2617
+ */
2618
+ getContainer() {
2619
+ return __privateGet(this, _canvasStage).getStage().container();
2620
+ }
2621
+ /**
2622
+ * 获取主图层
2623
+ */
2624
+ getMainLayer() {
2625
+ return __privateGet(this, _mainLayer);
2626
+ }
2627
+ /**
2628
+ * 获取当前工具类型
2629
+ */
2630
+ getToolType() {
2631
+ return this.getState().toolType;
2632
+ }
2633
+ /**
2634
+ * 设置当前工具类型(内部使用)
2635
+ */
2636
+ setToolType(type) {
2637
+ this.selectNode();
2638
+ this._updateState(
2639
+ {
2640
+ toolType: type
2641
+ },
2642
+ false
2643
+ );
2644
+ this.emit("toolType:change", type);
2645
+ if (type === "hand") {
2646
+ __privateGet(this, _canvasStage).setDraggable(true);
2647
+ __privateGet(this, _canvasStage).setCursor("grab");
2648
+ } else {
2649
+ __privateGet(this, _canvasStage).setDraggable(false);
2650
+ __privateGet(this, _canvasStage).resetCursor();
2651
+ }
2652
+ }
2653
+ /**
2654
+ * 设置是否可拖拽(内部使用)
2655
+ */
2656
+ setDraggable(draggable) {
2657
+ __privateGet(this, _canvasStage).setDraggable(draggable);
2658
+ }
2659
+ /**
2660
+ * 设置光标
2661
+ * @internal 仅供内部使用
2662
+ */
2663
+ setCursor(cursor) {
2664
+ __privateGet(this, _canvasStage).setCursor(cursor);
2665
+ }
2666
+ /**
2667
+ * 重置光标
2668
+ * @internal 仅供内部使用
2669
+ */
2670
+ resetCursor() {
2671
+ __privateGet(this, _canvasStage).resetCursor();
2672
+ }
2673
+ /**
2674
+ * 获取当前 Stage 缩放比例
2675
+ */
2676
+ getStageScale() {
2677
+ return __privateGet(this, _canvasStage).getStage().scaleX();
2678
+ }
2679
+ /**
2680
+ * 更新视口位置
2681
+ * @internal 仅供内部使用,外部请使用 CanvasApi
2682
+ */
2683
+ updateViewport(viewport, addToHistory = false) {
2684
+ __privateGet(this, _canvasStage).setViewport(viewport);
2685
+ const newViewport = {
2686
+ ...this.getState().viewport,
2687
+ ...viewport
2688
+ };
2689
+ this._updateState(
2690
+ {
2691
+ viewport: newViewport
2692
+ },
2693
+ addToHistory
2694
+ );
2695
+ this.emit("viewport:change", newViewport);
2696
+ __privateGet(this, _canvasTransformer).emitPositionChange();
2697
+ }
2698
+ createNodes(nodes) {
2699
+ const canvasNodes = nodes.map((node) => createCanvasNodeByType(this, node.type, node)).filter((node) => node !== null);
2700
+ canvasNodes.forEach((node) => {
2701
+ __privateGet(this, _mainLayer).add(node.getElement());
2702
+ });
2703
+ const newNodes = [...this.getState().nodes || [], ...nodes];
2704
+ this._updateState(
2705
+ {
2706
+ nodes: newNodes
2707
+ },
2708
+ true
2709
+ );
2710
+ }
2711
+ /**
2712
+ * 创建图片标注节点(内部使用)
2713
+ */
2714
+ createImageMarkerNode(parentImageId, startPosition, endPosition, imageBounds) {
2715
+ const nodes = this.getState().nodes || [];
2716
+ let maxMarkerNumber = 0;
2717
+ nodes.forEach((node) => {
2718
+ if (node.type === "image-marker" && node.meta.parent === parentImageId && typeof node.meta.markerNumber === "number") {
2719
+ maxMarkerNumber = Math.max(maxMarkerNumber, node.meta.markerNumber);
2720
+ }
2721
+ });
2722
+ const startPercentX = (startPosition.x - imageBounds.x) / imageBounds.width * 100;
2723
+ const startPercentY = (startPosition.y - imageBounds.y) / imageBounds.height * 100;
2724
+ const endPercentX = (endPosition.x - imageBounds.x) / imageBounds.width * 100;
2725
+ const endPercentY = (endPosition.y - imageBounds.y) / imageBounds.height * 100;
2726
+ const x = Math.min(startPosition.x, endPosition.x);
2727
+ const y = Math.min(startPosition.y, endPosition.y);
2728
+ const width = Math.abs(endPosition.x - startPosition.x);
2729
+ const height = Math.abs(endPosition.y - startPosition.y);
2730
+ const markerNode = {
2731
+ id: uuid.v4(),
2732
+ type: "image-marker",
2733
+ props: {
2734
+ x,
2735
+ y,
2736
+ width,
2737
+ height,
2738
+ rotation: 0,
2739
+ visible: true
2740
+ },
2741
+ style: {
2742
+ color: "#ff0000",
2743
+ line: "dashed",
2744
+ size: "medium",
2745
+ opacity: 1
2746
+ },
2747
+ meta: {
2748
+ parent: parentImageId,
2749
+ markerNumber: maxMarkerNumber + 1,
2750
+ relativePosition: {
2751
+ start: {
2752
+ percentX: Math.max(0, Math.min(100, startPercentX)),
2753
+ percentY: Math.max(0, Math.min(100, startPercentY))
2754
+ },
2755
+ end: {
2756
+ percentX: Math.max(0, Math.min(100, endPercentX)),
2757
+ percentY: Math.max(0, Math.min(100, endPercentY))
2758
+ }
2759
+ }
2760
+ }
2761
+ };
2762
+ this.createNodes([markerNode]);
2763
+ }
2764
+ /**
2765
+ * 在指定位置查找图片节点
2766
+ * @internal 仅供内部使用
2767
+ */
2768
+ findImageAtPosition(position) {
2769
+ const layer = __privateGet(this, _mainLayer).getLayer();
2770
+ const imageShapes = layer.find(
2771
+ (node) => node.getClassName() === "Image"
2772
+ );
2773
+ const originalListeningStates = imageShapes.map(
2774
+ (shape) => shape.listening()
2775
+ );
2776
+ imageShapes.forEach((shape) => shape.listening(true));
2777
+ layer.draw();
2778
+ try {
2779
+ const shape = layer.getIntersection(position);
2780
+ if (shape?.getClassName() === "Image") {
2781
+ return shape;
2782
+ }
2783
+ return null;
2784
+ } finally {
2785
+ imageShapes.forEach((shape, index) => {
2786
+ shape.listening(originalListeningStates[index]);
2787
+ });
2788
+ }
2789
+ }
2790
+ /**
2791
+ * @internal 仅供内部使用
2792
+ */
2793
+ createDraftNode(type, position, meta) {
2794
+ if (__privateGet(this, _draftNode)) {
2795
+ __privateGet(this, _draftNode).destroy();
2796
+ }
2797
+ const node = createNodeByType(type, position, void 0, meta);
2798
+ __privateSet(this, _draftNode, createCanvasNodeByType(this, type, node));
2799
+ console.log(__privateGet(this, _draftNode));
2800
+ if (!__privateGet(this, _draftNode)) return;
2801
+ __privateGet(this, _mainLayer).add(__privateGet(this, _draftNode).getElement());
2802
+ }
2803
+ /**
2804
+ * @internal 仅供内部使用
2805
+ */
2806
+ updateDraftNode(position, bounds) {
2807
+ if (!__privateGet(this, _draftNode)) return;
2808
+ const node = __privateGet(this, _draftNode).getNode();
2809
+ const updatedNode = updateNodeByType(node, position, bounds);
2810
+ __privateGet(this, _draftNode).updateNode(updatedNode);
2811
+ }
2812
+ /**
2813
+ * @internal 仅供内部使用
2814
+ */
2815
+ finalizeDraftNode() {
2816
+ if (!__privateGet(this, _draftNode)) return;
2817
+ const id = uuid.v4();
2818
+ const draftNode = __privateGet(this, _draftNode).getNode();
2819
+ if (draftNode.type === "image-marker" && draftNode.meta.parent) {
2820
+ const bounds = draftNode.meta.bounds;
2821
+ const startPosition = draftNode.meta.startPosition;
2822
+ const endPosition = {
2823
+ x: draftNode.props.x + (draftNode.props.width || 0),
2824
+ y: draftNode.props.y + (draftNode.props.height || 0)
2825
+ };
2826
+ const nodes = this.getState().nodes || [];
2827
+ let maxMarkerNumber = 0;
2828
+ nodes.forEach((node3) => {
2829
+ if (node3.type === "image-marker" && node3.meta.parent === draftNode.meta.parent && typeof node3.meta.markerNumber === "number") {
2830
+ maxMarkerNumber = Math.max(maxMarkerNumber, node3.meta.markerNumber);
2831
+ }
2832
+ });
2833
+ const startPercentX = (startPosition.x - bounds.x) / bounds.width * 100;
2834
+ const startPercentY = (startPosition.y - bounds.y) / bounds.height * 100;
2835
+ const endPercentX = (endPosition.x - bounds.x) / bounds.width * 100;
2836
+ const endPercentY = (endPosition.y - bounds.y) / bounds.height * 100;
2837
+ const node2 = {
2838
+ ...draftNode,
2839
+ props: {
2840
+ ...draftNode.props
2841
+ },
2842
+ style: {
2843
+ ...draftNode.style
2844
+ },
2845
+ meta: {
2846
+ parent: draftNode.meta.parent,
2847
+ markerNumber: maxMarkerNumber + 1,
2848
+ relativePosition: {
2849
+ start: {
2850
+ percentX: Math.max(0, Math.min(100, startPercentX)),
2851
+ percentY: Math.max(0, Math.min(100, startPercentY))
2852
+ },
2853
+ end: {
2854
+ percentX: Math.max(0, Math.min(100, endPercentX)),
2855
+ percentY: Math.max(0, Math.min(100, endPercentY))
2856
+ }
2857
+ }
2858
+ },
2859
+ id,
2860
+ type: "image-marker"
2861
+ };
2862
+ this.createNodes([node2]);
2863
+ __privateGet(this, _draftNode).destroy();
2864
+ __privateSet(this, _draftNode, null);
2865
+ this.setToolType("select");
2866
+ return;
2867
+ }
2868
+ const node = {
2869
+ ...draftNode,
2870
+ props: {
2871
+ ...draftNode.props
2872
+ },
2873
+ style: {
2874
+ ...draftNode.style
2875
+ },
2876
+ meta: {
2877
+ ...draftNode.meta
2878
+ },
2879
+ id
2880
+ };
2881
+ this.createNodes([node]);
2882
+ __privateGet(this, _draftNode).destroy();
2883
+ __privateSet(this, _draftNode, null);
2884
+ this.setToolType("select");
2885
+ }
2886
+ /**
2887
+ * 选择节点
2888
+ * @internal 仅供内部使用,外部请使用 CanvasApi
2889
+ */
2890
+ selectNode(nodeId, multiSelect = false) {
2891
+ const curSelectedNodeIds = this.getState().selectedNodeIds ?? [];
2892
+ if (curSelectedNodeIds.length === 0 && !nodeId) {
2893
+ return;
2894
+ }
2895
+ if (!nodeId) {
2896
+ __privateGet(this, _canvasTransformer).clearNodes();
2897
+ this._updateState(
2898
+ {
2899
+ selectedNodeIds: []
2900
+ },
2901
+ false
2902
+ );
2903
+ return;
2904
+ }
2905
+ let selectedNodeIds = [];
2906
+ if (multiSelect) {
2907
+ selectedNodeIds = curSelectedNodeIds.length ? [...curSelectedNodeIds, nodeId] : [nodeId];
2908
+ } else {
2909
+ selectedNodeIds = [nodeId];
2910
+ }
2911
+ const nodes = this.getStage().find(`.${NODE_NAME_FOR_SELECT}`).filter((node) => {
2912
+ const id = node.id();
2913
+ return selectedNodeIds.includes(id);
2914
+ });
2915
+ __privateGet(this, _canvasTransformer).setNodes(nodes);
2916
+ this._updateState(
2917
+ {
2918
+ selectedNodeIds
2919
+ },
2920
+ false
2921
+ );
2922
+ }
2923
+ /**
2924
+ * 销毁 canvas
2925
+ */
2926
+ dispose() {
2927
+ this.getCanvasTransformer().destroy();
2928
+ this.getMainLayer().destroy();
2929
+ this.getCanvasStage().destroy();
2930
+ this._dispose();
2931
+ }
2932
+ /**
2933
+ * 从元素同步节点数据(供节点类内部使用)
2934
+ */
2935
+ _syncNodeFromElement(nodeId, updates) {
2936
+ const nodes = this.getState().nodes || [];
2937
+ const nodeIndex = nodes.findIndex((n) => n.id === nodeId);
2938
+ if (nodeIndex === -1) return;
2939
+ const updatedNode = {
2940
+ ...nodes[nodeIndex],
2941
+ ...updates,
2942
+ props: {
2943
+ ...nodes[nodeIndex].props,
2944
+ ...updates.props
2945
+ },
2946
+ style: {
2947
+ ...nodes[nodeIndex].style,
2948
+ ...updates.style
2949
+ },
2950
+ meta: {
2951
+ ...nodes[nodeIndex].meta,
2952
+ ...updates.meta
2953
+ }
2954
+ };
2955
+ const newNodes = [...nodes];
2956
+ newNodes[nodeIndex] = updatedNode;
2957
+ this._updateState(
2958
+ {
2959
+ nodes: newNodes
2960
+ },
2961
+ true
2962
+ );
2963
+ }
2964
+ /**
2965
+ * 实现父类的状态同步方法
2966
+ * 当 undo/redo 时被调用
2967
+ */
2968
+ _syncState(state) {
2969
+ __privateGet(this, _canvasStage).setViewport({
2970
+ x: state.viewport.x,
2971
+ y: state.viewport.y,
2972
+ scale: state.viewport.scale,
2973
+ width: state.viewport.width,
2974
+ height: state.viewport.height
2975
+ });
2976
+ }
2977
+ }
2978
+ _canvasStage = new WeakMap();
2979
+ _mainLayer = new WeakMap();
2980
+ _canvasTransformer = new WeakMap();
2981
+ _draftNode = new WeakMap();
2982
+ class CanvasApi extends CanvasCore {
2983
+ /**
2984
+ * 获取所有可用的工具类型
2985
+ */
2986
+ getAvailableTools() {
2987
+ return ["select", "hand", "rectangle", "image-marker"];
2988
+ }
2989
+ /**
2990
+ * 设置当前工具类型
2991
+ */
2992
+ setToolType(type) {
2993
+ super.setToolType(type);
2994
+ }
2995
+ /**
2996
+ * 手动创建多个节点
2997
+ * 如果你不知道自己在干什么,请使用更高层的封装方法,如 createImageNode
2998
+ */
2999
+ createNodes(nodes) {
3000
+ super.createNodes(nodes);
3001
+ }
3002
+ /**
3003
+ * 更新视口位置
3004
+ */
3005
+ updateViewport(viewport, addToHistory = false) {
3006
+ super.updateViewport(viewport, addToHistory);
3007
+ }
3008
+ /**
3009
+ * 创建图片节点
3010
+ */
3011
+ createImageNode(imageUrl, position) {
3012
+ const pos = position ?? { x: 100, y: 100 };
3013
+ const imageNode = {
3014
+ id: uuid.v4(),
3015
+ type: "image",
3016
+ props: {
3017
+ x: pos.x,
3018
+ y: pos.y,
3019
+ width: void 0,
3020
+ height: void 0,
3021
+ rotation: 0,
3022
+ visible: true
3023
+ },
3024
+ style: {
3025
+ color: "#000000",
3026
+ line: "solid",
3027
+ size: "medium",
3028
+ opacity: 1
3029
+ },
3030
+ meta: {
3031
+ imageUrl
3032
+ }
3033
+ };
3034
+ this.createNodes([imageNode]);
3035
+ }
3036
+ /**
3037
+ * 导出全部图形为图片
3038
+ * @param options - 导出配置
3039
+ * @returns DataURL 格式的图片数据
3040
+ */
3041
+ exportAsImage(options) {
3042
+ const stage = this.getStage();
3043
+ const transformer = this.getCanvasTransformer().getTransformer();
3044
+ const transformerVisible = transformer.visible();
3045
+ transformer.visible(false);
3046
+ try {
3047
+ return stage.toDataURL({
3048
+ pixelRatio: options?.pixelRatio ?? 2,
3049
+ mimeType: options?.mimeType ?? "image/png",
3050
+ quality: options?.quality ?? 1
3051
+ });
3052
+ } finally {
3053
+ transformer.visible(transformerVisible);
3054
+ }
3055
+ }
3056
+ /**
3057
+ * 导出当前选区为图片
3058
+ * @param options - 导出配置
3059
+ * @returns DataURL 格式的图片数据,如果没有选区则返回 null
3060
+ */
3061
+ exportSelectionAsImage(options) {
3062
+ const position = this.getCanvasTransformer().getPosition();
3063
+ if (!position) {
3064
+ console.warn("No selection to export");
3065
+ return null;
3066
+ }
3067
+ const stage = this.getStage();
3068
+ const padding = options?.padding ?? 0;
3069
+ const transformer = this.getCanvasTransformer().getTransformer();
3070
+ const transformerVisible = transformer.visible();
3071
+ transformer.visible(false);
3072
+ try {
3073
+ return stage.toDataURL({
3074
+ x: position.x - padding,
3075
+ y: position.y - padding,
3076
+ width: position.width + padding * 2,
3077
+ height: position.height + padding * 2,
3078
+ pixelRatio: options?.pixelRatio ?? 1,
3079
+ mimeType: options?.mimeType ?? "image/png",
3080
+ quality: options?.quality ?? 1
3081
+ });
3082
+ } finally {
3083
+ transformer.visible(transformerVisible);
3084
+ }
3085
+ }
3086
+ /**
3087
+ * 删除当前选中的节点
3088
+ * 如果删除的是 image 节点,会同步删除所有关联的 image-marker
3089
+ */
3090
+ deleteSelectedNodes() {
3091
+ const selectedNodeIds = this.getState().selectedNodeIds || [];
3092
+ if (selectedNodeIds.length === 0) return;
3093
+ this.deleteNodes(selectedNodeIds);
3094
+ }
3095
+ /**
3096
+ * 删除指定的节点
3097
+ * 如果删除的是 image 节点,会同步删除所有关联的 image-marker
3098
+ * @param nodeIds - 要删除的节点 ID 数组
3099
+ */
3100
+ deleteNodes(nodeIds) {
3101
+ if (nodeIds.length === 0) return;
3102
+ const nodes = this.getState().nodes || [];
3103
+ const idsToDelete = new Set(nodeIds);
3104
+ nodeIds.forEach((id) => {
3105
+ const node = nodes.find((n) => n.id === id);
3106
+ if (node?.type === "image") {
3107
+ nodes.forEach((n) => {
3108
+ if (n.type === "image-marker" && n.meta.parent === id) {
3109
+ idsToDelete.add(n.id);
3110
+ }
3111
+ });
3112
+ }
3113
+ });
3114
+ idsToDelete.forEach((id) => {
3115
+ const shape = this.getStage().findOne(`#${id}`);
3116
+ if (shape) {
3117
+ shape.destroy();
3118
+ }
3119
+ });
3120
+ const newNodes = nodes.filter((n) => !idsToDelete.has(n.id));
3121
+ this.getCanvasTransformer().clearNodes();
3122
+ this._updateState(
3123
+ {
3124
+ nodes: newNodes,
3125
+ selectedNodeIds: []
3126
+ },
3127
+ true
3128
+ );
3129
+ }
3130
+ /**
3131
+ * 滚动到内容区域
3132
+ * - 如果提供了 nodeIds,将指定的节点居中显示
3133
+ * - 如果没有提供 nodeIds 但有选中的节点,将选中节点居中显示
3134
+ * - 如果没有选中节点,将所有内容居中显示
3135
+ * @param options - 配置选项
3136
+ * @param options.padding - 内容周围的留白,默认 50px
3137
+ * @param options.scale - 是否自动调整缩放以适应内容,默认 false
3138
+ * @param options.nodeIds - 要滚动到的节点 ID 数组
3139
+ */
3140
+ scrollToContent(options) {
3141
+ const nodes = this.getState().nodes || [];
3142
+ if (nodes.length === 0) return;
3143
+ const padding = options?.padding ?? 50;
3144
+ const shouldScale = options?.scale === true;
3145
+ const targetNodeIds = options?.nodeIds;
3146
+ let minX = Infinity;
3147
+ let minY = Infinity;
3148
+ let maxX = -Infinity;
3149
+ let maxY = -Infinity;
3150
+ const mainLayer = this.getMainLayer();
3151
+ const selectedNodeIds = this.getState().selectedNodeIds || [];
3152
+ const hasTargetIds = targetNodeIds && targetNodeIds.length > 0;
3153
+ const hasSelection = !hasTargetIds && selectedNodeIds.length > 0;
3154
+ const idsToShow = hasTargetIds ? targetNodeIds : hasSelection ? selectedNodeIds : null;
3155
+ mainLayer.children.forEach((child) => {
3156
+ if (child.visible() && child.getClassName() !== "Transformer" && child.hasName(NODE_NAME_FOR_SELECT)) {
3157
+ if (idsToShow) {
3158
+ const id = child.id();
3159
+ if (!idsToShow.includes(id)) return;
3160
+ }
3161
+ const attrs = child.getAttrs();
3162
+ const x2 = attrs.x || 0;
3163
+ const y2 = attrs.y || 0;
3164
+ const width = attrs.width || 0;
3165
+ const height = attrs.height || 0;
3166
+ const rotation = attrs.rotation || 0;
3167
+ if (rotation) {
3168
+ const box = child.getClientRect({ skipTransform: false });
3169
+ const stage = this.getStage();
3170
+ const currentScale = stage.scaleX();
3171
+ const currentX = stage.x();
3172
+ const currentY = stage.y();
3173
+ const worldMinX = (box.x - currentX) / currentScale;
3174
+ const worldMinY = (box.y - currentY) / currentScale;
3175
+ const worldMaxX = (box.x + box.width - currentX) / currentScale;
3176
+ const worldMaxY = (box.y + box.height - currentY) / currentScale;
3177
+ minX = Math.min(minX, worldMinX);
3178
+ minY = Math.min(minY, worldMinY);
3179
+ maxX = Math.max(maxX, worldMaxX);
3180
+ maxY = Math.max(maxY, worldMaxY);
3181
+ } else {
3182
+ minX = Math.min(minX, x2);
3183
+ minY = Math.min(minY, y2);
3184
+ maxX = Math.max(maxX, x2 + width);
3185
+ maxY = Math.max(maxY, y2 + height);
3186
+ }
3187
+ }
3188
+ });
3189
+ if (minX === Infinity || minY === Infinity) return;
3190
+ const contentWidth = maxX - minX;
3191
+ const contentHeight = maxY - minY;
3192
+ const contentCenterX = minX + contentWidth / 2;
3193
+ const contentCenterY = minY + contentHeight / 2;
3194
+ const viewport = this.getState().viewport;
3195
+ let newScale = viewport.scale;
3196
+ if (shouldScale) {
3197
+ const scaleX = (viewport.width - padding * 2) / contentWidth;
3198
+ const scaleY = (viewport.height - padding * 2) / contentHeight;
3199
+ newScale = Math.min(scaleX, scaleY, 1);
3200
+ }
3201
+ const x = viewport.width / 2 - contentCenterX * newScale;
3202
+ const y = viewport.height / 2 - contentCenterY * newScale;
3203
+ this.updateViewport({ x, y, scale: newScale }, true);
3204
+ }
3205
+ }
3206
+ function modulate(value, rangeA, rangeB, clamp = false) {
3207
+ const [fromLow, fromHigh] = rangeA;
3208
+ const [v0, v1] = rangeB;
3209
+ const result = v0 + (value - fromLow) / (fromHigh - fromLow) * (v1 - v0);
3210
+ return clamp ? v0 < v1 ? Math.max(Math.min(result, v1), v0) : Math.max(Math.min(result, v0), v1) : result;
3211
+ }
3212
+ const gridSteps = [
3213
+ {
3214
+ min: -1,
3215
+ mid: 0.15,
3216
+ step: 64
3217
+ },
3218
+ {
3219
+ min: 0.05,
3220
+ mid: 0.375,
3221
+ step: 16
3222
+ },
3223
+ {
3224
+ min: 0.15,
3225
+ mid: 1,
3226
+ step: 4
3227
+ },
3228
+ {
3229
+ min: 0.7,
3230
+ mid: 2.5,
3231
+ step: 1
3232
+ }
3233
+ ];
3234
+ function GridBackground({
3235
+ viewportX,
3236
+ viewportY,
3237
+ scale,
3238
+ size = 20,
3239
+ showGrid = true
3240
+ }) {
3241
+ const x = viewportX / scale;
3242
+ const y = viewportY / scale;
3243
+ const z = scale;
3244
+ if (!showGrid) {
3245
+ return null;
3246
+ }
3247
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3248
+ "svg",
3249
+ {
3250
+ className: "canvas-grid w-full h-full absolute top-0 left-0",
3251
+ version: "1.1",
3252
+ xmlns: "http://www.w3.org/2000/svg",
3253
+ "aria-hidden": "true",
3254
+ children: [
3255
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: gridSteps.map(({ min, mid, step }, i) => {
3256
+ const s = step * size * z;
3257
+ const xo = 0.5 + x * z;
3258
+ const yo = 0.5 + y * z;
3259
+ const gxo = xo > 0 ? xo % s : s + xo % s;
3260
+ const gyo = yo > 0 ? yo % s : s + yo % s;
3261
+ const opacity = z < mid ? modulate(z, [min, mid], [0, 1]) : 1;
3262
+ return /* @__PURE__ */ jsxRuntime.jsx(
3263
+ "pattern",
3264
+ {
3265
+ id: `grid_${step}`,
3266
+ width: s,
3267
+ height: s,
3268
+ patternUnits: "userSpaceOnUse",
3269
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3270
+ "circle",
3271
+ {
3272
+ className: "tl-grid-dot",
3273
+ cx: gxo,
3274
+ cy: gyo,
3275
+ r: 1,
3276
+ opacity
3277
+ }
3278
+ )
3279
+ },
3280
+ i
3281
+ );
3282
+ }) }),
3283
+ gridSteps.map(({ step }, i) => /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "100%", height: "100%", fill: `url(#grid_${step})` }, i))
3284
+ ]
3285
+ }
3286
+ );
3287
+ }
3288
+ function cn(...inputs) {
3289
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
3290
+ }
3291
+ const buttonVariants = classVarianceAuthority.cva(
3292
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
3293
+ {
3294
+ variants: {
3295
+ variant: {
3296
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
3297
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
3298
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
3299
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
3300
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
3301
+ link: "text-primary underline-offset-4 hover:underline"
3302
+ },
3303
+ size: {
3304
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
3305
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
3306
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
3307
+ icon: "size-9",
3308
+ "icon-sm": "size-8",
3309
+ "icon-lg": "size-10"
3310
+ }
3311
+ },
3312
+ defaultVariants: {
3313
+ variant: "default",
3314
+ size: "default"
3315
+ }
3316
+ }
3317
+ );
3318
+ function Button({
3319
+ className,
3320
+ variant = "default",
3321
+ size = "default",
3322
+ asChild = false,
3323
+ ...props
3324
+ }) {
3325
+ const Comp = asChild ? reactSlot.Slot : "button";
3326
+ return /* @__PURE__ */ jsxRuntime.jsx(
3327
+ Comp,
3328
+ {
3329
+ "data-slot": "button",
3330
+ "data-variant": variant,
3331
+ "data-size": size,
3332
+ className: cn(buttonVariants({ variant, size, className })),
3333
+ ...props
3334
+ }
3335
+ );
3336
+ }
3337
+ function ZoomPanel({ api }) {
3338
+ const [viewport, setViewport] = react.useState(api.getState().viewport);
3339
+ react.useEffect(() => {
3340
+ api.on("viewport:change", (newViewport) => {
3341
+ setViewport(newViewport);
3342
+ });
3343
+ }, [setViewport, api]);
3344
+ const updateScale = (scale) => {
3345
+ const halfWidth = viewport.width / 2;
3346
+ const halfHeight = viewport.height / 2;
3347
+ const worldCenterX = (halfWidth - viewport.x) / viewport.scale;
3348
+ const worldCenterY = (halfHeight - viewport.y) / viewport.scale;
3349
+ const x = halfWidth - worldCenterX * scale;
3350
+ const y = halfHeight - worldCenterY * scale;
3351
+ api.updateViewport({ x, y, scale });
3352
+ };
3353
+ const handleZoomIn = () => {
3354
+ const scale = Math.min(viewport.scale * 1.2, 5);
3355
+ updateScale(scale);
3356
+ };
3357
+ const handleZoomOut = () => {
3358
+ const scale = Math.max(viewport.scale / 1.2, 0.1);
3359
+ updateScale(scale);
3360
+ };
3361
+ const handleReset = () => {
3362
+ updateScale(1);
3363
+ };
3364
+ const percent = Math.round(viewport.scale * 100);
3365
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "zoom-panel flex items-center gap-2", children: [
3366
+ /* @__PURE__ */ jsxRuntime.jsx(
3367
+ Button,
3368
+ {
3369
+ size: "sm",
3370
+ variant: "secondary",
3371
+ onClick: handleZoomOut,
3372
+ title: "缩小",
3373
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, {})
3374
+ }
3375
+ ),
3376
+ /* @__PURE__ */ jsxRuntime.jsxs(
3377
+ Button,
3378
+ {
3379
+ size: "sm",
3380
+ variant: "secondary",
3381
+ onClick: handleReset,
3382
+ title: `${percent}%`,
3383
+ className: "min-w-16",
3384
+ children: [
3385
+ percent,
3386
+ "%"
3387
+ ]
3388
+ }
3389
+ ),
3390
+ /* @__PURE__ */ jsxRuntime.jsx(
3391
+ Button,
3392
+ {
3393
+ size: "sm",
3394
+ variant: "secondary",
3395
+ onClick: handleZoomIn,
3396
+ title: "放大",
3397
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {})
3398
+ }
3399
+ )
3400
+ ] });
3401
+ }
3402
+ function HistoryPanel({ api }) {
3403
+ const [canUndo, setCanUndo] = react.useState(api.canUndo());
3404
+ const [canRedo, setCanRedo] = react.useState(api.canRedo());
3405
+ react.useEffect(() => {
3406
+ const handleStateChange = () => {
3407
+ setCanUndo(api.canUndo());
3408
+ setCanRedo(api.canRedo());
3409
+ };
3410
+ api.on("state:change", handleStateChange);
3411
+ return () => {
3412
+ api.off("state:change", handleStateChange);
3413
+ };
3414
+ }, [api]);
3415
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "history-panel flex items-center gap-2", children: [
3416
+ /* @__PURE__ */ jsxRuntime.jsx(
3417
+ Button,
3418
+ {
3419
+ size: "sm",
3420
+ variant: "secondary",
3421
+ disabled: !canUndo,
3422
+ onClick: () => api.undo(),
3423
+ title: "撤销",
3424
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo2, {})
3425
+ }
3426
+ ),
3427
+ /* @__PURE__ */ jsxRuntime.jsx(
3428
+ Button,
3429
+ {
3430
+ size: "sm",
3431
+ variant: "secondary",
3432
+ disabled: !canRedo,
3433
+ onClick: () => api.redo(),
3434
+ title: "重做",
3435
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Redo2, {})
3436
+ }
3437
+ )
3438
+ ] });
3439
+ }
3440
+ function PureCanvas({ setApi }) {
3441
+ const containerRef = react.useRef(null);
3442
+ const [_api, _setApi] = react.useState(null);
3443
+ const [viewport, setViewport] = react.useState({ x: 0, y: 0, scale: 1 });
3444
+ react.useEffect(() => {
3445
+ if (!containerRef.current) return;
3446
+ const core = new CanvasApi(containerRef.current);
3447
+ _setApi(core);
3448
+ setApi?.(core);
3449
+ core.on("viewport:change", (newViewport) => {
3450
+ setViewport(newViewport);
3451
+ });
3452
+ core.on("transformer:positionChange", (position) => {
3453
+ console.log("Transformer position changed:", position);
3454
+ });
3455
+ return () => {
3456
+ core.dispose();
3457
+ };
3458
+ }, [setApi]);
3459
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pure-canvas relative size-full", children: [
3460
+ /* @__PURE__ */ jsxRuntime.jsx(
3461
+ GridBackground,
3462
+ {
3463
+ viewportX: viewport.x,
3464
+ viewportY: viewport.y,
3465
+ scale: viewport.scale
3466
+ }
3467
+ ),
3468
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "size-full" }),
3469
+ _api && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3470
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "history-panel-wrapper absolute bottom-4 left-4 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(HistoryPanel, { api: _api }) }),
3471
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "zoom-panel-wrapper absolute bottom-4 right-4 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(ZoomPanel, { api: _api }) })
3472
+ ] })
3473
+ ] });
3474
+ }
3475
+ exports2.CanvasApi = CanvasApi;
3476
+ exports2.NODE_NAME_FOR_SELECT = NODE_NAME_FOR_SELECT;
3477
+ exports2.PureCanvas = PureCanvas;
3478
+ Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
3479
+ }));