made-refine 0.2.2 → 0.2.4

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.js CHANGED
@@ -79,13 +79,13 @@ __export(index_exports, {
79
79
  module.exports = __toCommonJS(index_exports);
80
80
 
81
81
  // src/provider.tsx
82
- var React7 = __toESM(require("react"));
82
+ var React8 = __toESM(require("react"));
83
83
 
84
84
  // src/portal-container.tsx
85
85
  var React = __toESM(require("react"));
86
86
 
87
87
  // dist/styles.css
88
- var styles_default = '/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */\n@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-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction: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-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@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-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--font-weight-thin:100;--font-weight-extralight:200;--font-weight-light:300;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--font-weight-black:900;--leading-relaxed:1.625;--radius-sm:calc(.5rem - 4px);--radius-md:calc(.5rem - 2px);--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--blur-xl:24px;--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);--color-border:#e6e6e6;--color-ring:#262626;--color-background:#fff;--color-foreground:#171717;--color-primary:#171717;--color-primary-foreground:#fafafa;--color-secondary-foreground:#171717;--color-destructive:#ef4444;--color-destructive-foreground:#fafafa;--color-muted:#f2f2f2;--color-muted-foreground:#737373;--color-popover-foreground:#171717}}@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;-webkit-text-decoration: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}:root,:host{color-scheme:light;color:var(--color-foreground)}@media (prefers-color-scheme:dark){:root,:host(:not([data-theme])),:host([data-theme=system]){color-scheme:dark;color:var(--color-foreground);--color-border:#2e2e2e;--color-input:#2e2e2e;--color-ring:#d4d4d4;--color-background:#121212;--color-foreground:#fafafa;--color-primary:#fafafa;--color-primary-foreground:#171717;--color-secondary:#262626;--color-secondary-foreground:#fafafa;--color-destructive:#7f1d1d;--color-destructive-foreground:#fafafa;--color-muted:#262626;--color-muted-foreground:#a3a3a3;--color-accent:#262626;--color-accent-foreground:#fafafa;--color-popover:#171717;--color-popover-foreground:#fafafa}}:host([data-theme=dark]){color-scheme:dark;color:var(--color-foreground);--color-border:#2e2e2e;--color-input:#2e2e2e;--color-ring:#d4d4d4;--color-background:#121212;--color-foreground:#fafafa;--color-primary:#fafafa;--color-primary-foreground:#171717;--color-secondary:#262626;--color-secondary-foreground:#fafafa;--color-destructive:#7f1d1d;--color-destructive-foreground:#fafafa;--color-muted:#262626;--color-muted-foreground:#a3a3a3;--color-accent:#262626;--color-accent-foreground:#fafafa;--color-popover:#171717;--color-popover-foreground:#fafafa}*,:before,:after{--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-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction: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:var(--color-background);--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;border-color:var(--color-border)}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.top-1\\/2{top:50%}.left-1\\.5{left:calc(var(--spacing)*1.5)}.left-1\\/2{left:50%}.left-2{left:calc(var(--spacing)*2)}.left-3{left:calc(var(--spacing)*3)}.z-\\[99990\\]{z-index:99990}.z-\\[99991\\]{z-index:99991}.z-\\[99998\\]{z-index:99998}.z-\\[99999\\]{z-index:99999}.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}}.m-4{margin:calc(var(--spacing)*4)}.mx-0\\.5{margin-inline:calc(var(--spacing)*.5)}.mx-2{margin-inline:calc(var(--spacing)*2)}.my-0\\.5{margin-block:calc(var(--spacing)*.5)}.my-1{margin-block:calc(var(--spacing)*1)}.mt-0{margin-top:calc(var(--spacing)*0)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2\\.5{margin-top:calc(var(--spacing)*2.5)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-1\\.5{margin-bottom:calc(var(--spacing)*1.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.ml-0{margin-left:calc(var(--spacing)*0)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-1\\.5{margin-left:calc(var(--spacing)*1.5)}.ml-2{margin-left:calc(var(--spacing)*2)}.block{display:block}.contents{display:contents}.flex{display:flex}.flow-root{display:flow-root}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.inline-grid{display:inline-grid}.list-item{display:list-item}.size-1{width:calc(var(--spacing)*1);height:calc(var(--spacing)*1)}.size-2\\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-3\\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-7{width:calc(var(--spacing)*7);height:calc(var(--spacing)*7)}.size-full{width:100%;height:100%}.h-0\\.5{height:calc(var(--spacing)*.5)}.h-2{height:calc(var(--spacing)*2)}.h-3\\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-11{height:calc(var(--spacing)*11)}.h-\\[150px\\]{height:150px}.h-auto{height:auto}.h-fit{height:fit-content}.h-full{height:100%}.max-h-0{max-height:calc(var(--spacing)*0)}.max-h-48{max-height:calc(var(--spacing)*48)}.max-h-\\[220px\\]{max-height:220px}.max-h-\\[240px\\]{max-height:240px}.min-h-\\[18px\\]{min-height:18px}.w-0\\.5{width:calc(var(--spacing)*.5)}.w-2{width:calc(var(--spacing)*2)}.w-3{width:calc(var(--spacing)*3)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-8{width:calc(var(--spacing)*8)}.w-9{width:calc(var(--spacing)*9)}.w-10{width:calc(var(--spacing)*10)}.w-11{width:calc(var(--spacing)*11)}.w-14{width:calc(var(--spacing)*14)}.w-\\[1\\.5px\\]{width:1.5px}.w-\\[60px\\]{width:60px}.w-\\[68px\\]{width:68px}.w-\\[200px\\]{width:200px}.w-\\[260px\\]{width:260px}.w-\\[280px\\]{width:280px}.w-\\[340px\\]{width:340px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.w-px{width:1px}.max-w-0{max-width:calc(var(--spacing)*0)}.max-w-\\[200px\\]{max-width:200px}.max-w-full{max-width:100%}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\\[20px\\]{min-width:20px}.min-w-\\[100px\\]{min-width:100px}.min-w-\\[120px\\]{min-width:120px}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.origin-\\(--transform-origin\\){transform-origin:var(--transform-origin)}.-translate-x-1\\/2{--tw-translate-x:calc(calc(1/2*100%)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1/2*100%)*-1);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,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-crosshair{cursor:crosshair}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-grabbing{cursor:grabbing}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.\\[appearance\\:textfield\\]{appearance:textfield}.appearance-none{appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-evenly{justify-content:space-evenly}.justify-start{justify-content:flex-start}.gap-0\\.5{gap:calc(var(--spacing)*.5)}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-\\[2px\\]{gap:2px}.gap-\\[4px\\]{gap:4px}:where(.space-y-1\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.rounded{border-radius:.25rem}.rounded-\\[8px\\]{border-radius:8px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-tl{border-top-left-radius:.25rem}.rounded-tr{border-top-right-radius:.25rem}.rounded-br{border-bottom-right-radius:.25rem}.rounded-bl{border-bottom-left-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-dotted{--tw-border-style:dotted;border-style:dotted}.border-double{--tw-border-style:double;border-style:double}.border-none{--tw-border-style:none;border-style:none}.border-solid{--tw-border-style:solid;border-style:solid}.\\[border-top-style\\:solid\\]{border-top-style:solid}.\\[border-right-style\\:dashed\\]{border-right-style:dashed}.\\[border-bottom-style\\:dashed\\]{border-bottom-style:dashed}.\\[border-bottom-style\\:dotted\\]{border-bottom-style:dotted}.\\[border-bottom-style\\:solid\\]{border-bottom-style:solid}.\\[border-left-style\\:double\\]{border-left-style:double}.\\[border-left-style\\:solid\\]{border-left-style:solid}.border-border{border-color:var(--color-border)}.border-border\\/30{border-color:#e6e6e64d}@supports (color:color-mix(in lab, red, red)){.border-border\\/30{border-color:color-mix(in oklab,var(--color-border)30%,transparent)}}.border-border\\/50{border-color:#e6e6e680}@supports (color:color-mix(in lab, red, red)){.border-border\\/50{border-color:color-mix(in oklab,var(--color-border)50%,transparent)}}.border-foreground\\/10{border-color:#1717171a}@supports (color:color-mix(in lab, red, red)){.border-foreground\\/10{border-color:color-mix(in oklab,var(--color-foreground)10%,transparent)}}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.bg-\\[canvas\\]{background-color:canvas}.bg-background{background-color:var(--color-background)}.bg-background\\/85{background-color:#ffffffd9}@supports (color:color-mix(in lab, red, red)){.bg-background\\/85{background-color:color-mix(in oklab,var(--color-background)85%,transparent)}}.bg-blue-500{background-color:var(--color-blue-500)}.bg-border{background-color:var(--color-border)}.bg-destructive{background-color:var(--color-destructive)}.bg-foreground{background-color:var(--color-foreground)}.bg-foreground\\/25{background-color:#17171740}@supports (color:color-mix(in lab, red, red)){.bg-foreground\\/25{background-color:color-mix(in oklab,var(--color-foreground)25%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-muted-foreground\\/30{background-color:#7373734d}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\\/30{background-color:color-mix(in oklab,var(--color-muted-foreground)30%,transparent)}}.bg-primary{background-color:var(--color-primary)}.bg-transparent{background-color:#0000}.fill-border{fill:var(--color-border)}.p-0{padding:calc(var(--spacing)*0)}.p-0\\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-1\\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-1\\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-3\\.5{padding-block:calc(var(--spacing)*3.5)}.pt-0{padding-top:calc(var(--spacing)*0)}.pt-1{padding-top:calc(var(--spacing)*1)}.pt-1\\.5{padding-top:calc(var(--spacing)*1.5)}.pt-2\\.5{padding-top:calc(var(--spacing)*2.5)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-6{padding-top:calc(var(--spacing)*6)}.pt-\\[13px\\]{padding-top:13px}.pr-1{padding-right:calc(var(--spacing)*1)}.pr-1\\.5{padding-right:calc(var(--spacing)*1.5)}.pr-2{padding-right:calc(var(--spacing)*2)}.pb-1{padding-bottom:calc(var(--spacing)*1)}.pb-1\\.5{padding-bottom:calc(var(--spacing)*1.5)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pl-0{padding-left:calc(var(--spacing)*0)}.pl-3{padding-left:calc(var(--spacing)*3)}.pl-6{padding-left:calc(var(--spacing)*6)}.pl-7{padding-left:calc(var(--spacing)*7)}.text-center{text-align:center}.text-justify{text-align:justify}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.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))}.text-\\[7px\\]{font-size:7px}.text-\\[10px\\]{font-size:10px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-black{--tw-font-weight:var(--font-weight-black);font-weight:var(--font-weight-black)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-extrabold{--tw-font-weight:var(--font-weight-extrabold);font-weight:var(--font-weight-extrabold)}.font-extralight{--tw-font-weight:var(--font-weight-extralight);font-weight:var(--font-weight-extralight)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.font-thin{--tw-font-weight:var(--font-weight-thin);font-weight:var(--font-weight-thin)}.whitespace-nowrap{white-space:nowrap}.text-background{color:var(--color-background)}.text-blue-500{color:var(--color-blue-500)}.text-destructive-foreground{color:var(--color-destructive-foreground)}.text-foreground{color:var(--color-foreground)}.text-green-400{color:var(--color-green-400)}.text-green-500{color:var(--color-green-500)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-popover-foreground{color:var(--color-popover-foreground)}.text-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-red-500{color:var(--color-red-500)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.text-white{color:var(--color-white)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,)var(--tw-slashed-zero,)var(--tw-numeric-figure,)var(--tw-numeric-spacing,)var(--tw-numeric-fraction,)}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px 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-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-2xs{--tw-shadow:0 1px 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)}.shadow-\\[0_0_0_1px_rgba\\(0\\,0\\,0\\,0\\.3\\)\\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\\[0_4px_6px_-1px_rgba\\(0\\,0\\,0\\,0\\.1\\)\\]{--tw-shadow:0 4px 6px -1px 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-\\[inset_0_0_0_1px_rgba\\(0\\,0\\,0\\,0\\.1\\)\\]{--tw-shadow:inset 0 0 0 1px 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-inner{--tw-shadow:inset 0 2px 4px 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)}.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-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px 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-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px 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-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px 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)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + 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)}.ring-white{--tw-ring-color:var(--color-white)}.outline,.outline-1{outline-style:var(--tw-outline-style);outline-width:1px}.outline-foreground\\/10{outline-color:#1717171a}@supports (color:color-mix(in lab, red, red)){.outline-foreground\\/10{outline-color:color-mix(in oklab,var(--color-foreground)10%,transparent)}}.outline-gray-200{outline-color:var(--color-gray-200)}.outline-red-500\\/70{outline-color:#fb2c36b3}@supports (color:color-mix(in lab, red, red)){.outline-red-500\\/70{outline-color:color-mix(in oklab,var(--color-red-500)70%,transparent)}}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[max-width\\,max-height\\,margin\\,opacity\\]{transition-property:max-width,max-height,margin,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[opacity\\,background-color\\,color\\]{transition-property:opacity,background-color,color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[transform\\,scale\\,opacity\\]{transition-property:transform,scale,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.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))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.animate-in{--tw-enter-opacity:initial;--tw-enter-scale:initial;--tw-enter-rotate:initial;--tw-enter-translate-x:initial;--tw-enter-translate-y:initial;animation-name:enter;animation-duration:.15s}.outline-dashed{--tw-outline-style:dashed;outline-style:dashed}.outline-dotted{--tw-outline-style:dotted;outline-style:dotted}.outline-double{--tw-outline-style:double;outline-style:double}.outline-none{--tw-outline-style:none;outline-style:none}.outline-solid{--tw-outline-style:solid;outline-style:solid}.select-none{-webkit-user-select:none;user-select:none}.\\[-ms-overflow-style\\:none\\]{-ms-overflow-style:none}.\\[scrollbar-width\\:none\\]{scrollbar-width:none}.duration-200{animation-duration:.2s}.duration-300{animation-duration:.3s}.ease-in-out{animation-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{animation-timing-function:cubic-bezier(0,0,.2,1)}.fade-in-0{--tw-enter-opacity:0}.running{animation-play-state:running}.zoom-in-95{--tw-enter-scale:.95}@media (hover:hover){.group-hover\\:opacity-100:is(:where(.group):hover *){opacity:1}.group-hover\\/pin\\:inline:is(:where(.group\\/pin):hover *){display:inline}}.file\\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\\:bg-transparent::file-selector-button{background-color:#0000}.file\\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\\:text-foreground::file-selector-button{color:var(--color-foreground)}.placeholder\\:text-muted-foreground::placeholder{color:var(--color-muted-foreground)}.placeholder\\:text-red-400::placeholder{color:var(--color-red-400)}.focus-within\\:ring-1:focus-within{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + 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-within\\:ring-ring:focus-within{--tw-ring-color:var(--color-ring)}.focus-within\\:outline-none:focus-within{--tw-outline-style:none;outline-style:none}.focus-within\\:ring-inset:focus-within{--tw-ring-inset:inset}@media (hover:hover){.hover\\:scale-\\[1\\.67\\]:hover{scale:1.67}.hover\\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\\:bg-destructive\\/90:hover{background-color:#ef4444e6}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-destructive\\/90:hover{background-color:color-mix(in oklab,var(--color-destructive)90%,transparent)}}.hover\\:bg-foreground\\/80:hover{background-color:#171717cc}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-foreground\\/80:hover{background-color:color-mix(in oklab,var(--color-foreground)80%,transparent)}}.hover\\:bg-muted:hover{background-color:var(--color-muted)}.hover\\:bg-muted-foreground\\/10:hover{background-color:#7373731a}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-muted-foreground\\/10:hover{background-color:color-mix(in oklab,var(--color-muted-foreground)10%,transparent)}}.hover\\:bg-muted\\/50:hover{background-color:#f2f2f280}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-muted\\/50:hover{background-color:color-mix(in oklab,var(--color-muted)50%,transparent)}}.hover\\:bg-primary\\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-primary\\/90:hover{background-color:color-mix(in oklab,var(--color-primary)90%,transparent)}}.hover\\:text-foreground:hover{color:var(--color-foreground)}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:shadow-lg:hover{--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)}}.focus\\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-1:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + 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-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.active\\:cursor-grabbing:active{cursor:grabbing}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}.disabled\\:opacity-60:disabled{opacity:.6}.data-ending-style\\:scale-90[data-ending-style]{--tw-scale-x:90%;--tw-scale-y:90%;--tw-scale-z:90%;scale:var(--tw-scale-x)var(--tw-scale-y)}.data-ending-style\\:opacity-0[data-ending-style]{opacity:0}.data-instant\\:transition-none[data-instant]{transition-property:none}.data-starting-style\\:scale-90[data-starting-style]{--tw-scale-x:90%;--tw-scale-y:90%;--tw-scale-z:90%;scale:var(--tw-scale-x)var(--tw-scale-y)}.data-starting-style\\:opacity-0[data-starting-style]{opacity:0}.data-\\[highlighted\\]\\:bg-muted[data-highlighted]{background-color:var(--color-muted)}.data-\\[highlighted\\]\\:text-foreground[data-highlighted]{color:var(--color-foreground)}@media (prefers-color-scheme:dark){.dark\\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark\\:-outline-offset-1{outline-offset:calc(1px*-1)}.dark\\:outline-gray-300{outline-color:var(--color-gray-300)}}.\\[\\&_svg\\]\\:pointer-events-none svg{pointer-events:none}.\\[\\&_svg\\]\\:size-4 svg{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\\[\\&_svg\\]\\:shrink-0 svg{flex-shrink:0}.\\[\\&\\:\\:-webkit-inner-spin-button\\]\\:appearance-none::-webkit-inner-spin-button{appearance:none}.\\[\\&\\:\\:-webkit-outer-spin-button\\]\\:appearance-none::-webkit-outer-spin-button{appearance:none}.\\[\\&\\:\\:-webkit-scrollbar\\]\\:hidden::-webkit-scrollbar{display:none}}.lucide{stroke-width:1px}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,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-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{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}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes pulse{50%{opacity:.5}}';
88
+ var styles_default = '/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */\n@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-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction: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-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@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-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--font-weight-thin:100;--font-weight-extralight:200;--font-weight-light:300;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--font-weight-black:900;--leading-relaxed:1.625;--radius-sm:calc(.5rem - 4px);--radius-md:calc(.5rem - 2px);--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--blur-xl:24px;--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);--color-border:#e6e6e6;--color-ring:#262626;--color-background:#fff;--color-foreground:#171717;--color-primary:#171717;--color-primary-foreground:#fafafa;--color-secondary-foreground:#171717;--color-destructive:#ef4444;--color-destructive-foreground:#fafafa;--color-muted:#f2f2f2;--color-muted-foreground:#737373;--color-popover-foreground:#171717}}@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;-webkit-text-decoration: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}:root,:host{color-scheme:light;color:var(--color-foreground)}@media (prefers-color-scheme:dark){:root,:host(:not([data-theme])),:host([data-theme=system]){color-scheme:dark;color:var(--color-foreground);--color-border:#2e2e2e;--color-input:#2e2e2e;--color-ring:#d4d4d4;--color-background:#121212;--color-foreground:#fafafa;--color-primary:#fafafa;--color-primary-foreground:#171717;--color-secondary:#262626;--color-secondary-foreground:#fafafa;--color-destructive:#7f1d1d;--color-destructive-foreground:#fafafa;--color-muted:#262626;--color-muted-foreground:#a3a3a3;--color-accent:#262626;--color-accent-foreground:#fafafa;--color-popover:#171717;--color-popover-foreground:#fafafa}}:host([data-theme=dark]){color-scheme:dark;color:var(--color-foreground);--color-border:#2e2e2e;--color-input:#2e2e2e;--color-ring:#d4d4d4;--color-background:#121212;--color-foreground:#fafafa;--color-primary:#fafafa;--color-primary-foreground:#171717;--color-secondary:#262626;--color-secondary-foreground:#fafafa;--color-destructive:#7f1d1d;--color-destructive-foreground:#fafafa;--color-muted:#262626;--color-muted-foreground:#a3a3a3;--color-accent:#262626;--color-accent-foreground:#fafafa;--color-popover:#171717;--color-popover-foreground:#fafafa}*,:before,:after{--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-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction: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:var(--color-background);--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;border-color:var(--color-border)}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.top-1\\/2{top:50%}.left-1\\.5{left:calc(var(--spacing)*1.5)}.left-1\\/2{left:50%}.left-2{left:calc(var(--spacing)*2)}.left-3{left:calc(var(--spacing)*3)}.z-\\[99990\\]{z-index:99990}.z-\\[99991\\]{z-index:99991}.z-\\[99998\\]{z-index:99998}.z-\\[99999\\]{z-index:99999}.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}}.m-4{margin:calc(var(--spacing)*4)}.mx-0\\.5{margin-inline:calc(var(--spacing)*.5)}.mx-2{margin-inline:calc(var(--spacing)*2)}.my-0\\.5{margin-block:calc(var(--spacing)*.5)}.my-1{margin-block:calc(var(--spacing)*1)}.mt-0{margin-top:calc(var(--spacing)*0)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2\\.5{margin-top:calc(var(--spacing)*2.5)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-1\\.5{margin-bottom:calc(var(--spacing)*1.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.ml-0{margin-left:calc(var(--spacing)*0)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-1\\.5{margin-left:calc(var(--spacing)*1.5)}.ml-2{margin-left:calc(var(--spacing)*2)}.block{display:block}.contents{display:contents}.flex{display:flex}.flow-root{display:flow-root}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.inline-grid{display:inline-grid}.list-item{display:list-item}.size-1{width:calc(var(--spacing)*1);height:calc(var(--spacing)*1)}.size-2\\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-3\\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-7{width:calc(var(--spacing)*7);height:calc(var(--spacing)*7)}.size-full{width:100%;height:100%}.h-0\\.5{height:calc(var(--spacing)*.5)}.h-2{height:calc(var(--spacing)*2)}.h-3\\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-11{height:calc(var(--spacing)*11)}.h-\\[150px\\]{height:150px}.h-auto{height:auto}.h-fit{height:fit-content}.h-full{height:100%}.max-h-48{max-height:calc(var(--spacing)*48)}.max-h-\\[240px\\]{max-height:240px}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-\\[18px\\]{min-height:18px}.w-0\\.5{width:calc(var(--spacing)*.5)}.w-2{width:calc(var(--spacing)*2)}.w-3{width:calc(var(--spacing)*3)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-8{width:calc(var(--spacing)*8)}.w-9{width:calc(var(--spacing)*9)}.w-10{width:calc(var(--spacing)*10)}.w-11{width:calc(var(--spacing)*11)}.w-14{width:calc(var(--spacing)*14)}.w-\\[1\\.5px\\]{width:1.5px}.w-\\[30px\\]{width:30px}.w-\\[60px\\]{width:60px}.w-\\[68px\\]{width:68px}.w-\\[180px\\]{width:180px}.w-\\[200px\\]{width:200px}.w-\\[260px\\]{width:260px}.w-\\[280px\\]{width:280px}.w-\\[300px\\]{width:300px}.w-\\[340px\\]{width:340px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.w-px{width:1px}.max-w-full{max-width:100%}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\\[18px\\]{min-width:18px}.min-w-\\[20px\\]{min-width:20px}.min-w-\\[100px\\]{min-width:100px}.min-w-\\[120px\\]{min-width:120px}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.origin-\\(--transform-origin\\){transform-origin:var(--transform-origin)}.-translate-x-1\\/2{--tw-translate-x:calc(calc(1/2*100%)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1/2*100%)*-1);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,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-crosshair{cursor:crosshair}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-grabbing{cursor:grabbing}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.\\[appearance\\:textfield\\]{appearance:textfield}.appearance-none{appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\\[0fr\\]{grid-template-columns:0fr}.grid-cols-\\[1fr\\]{grid-template-columns:1fr}.grid-rows-\\[0fr\\]{grid-template-rows:0fr}.grid-rows-\\[1fr\\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-evenly{justify-content:space-evenly}.justify-start{justify-content:flex-start}.gap-0\\.5{gap:calc(var(--spacing)*.5)}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-\\[2px\\]{gap:2px}.gap-\\[4px\\]{gap:4px}:where(.space-y-1\\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.rounded{border-radius:.25rem}.rounded-\\[6px\\]{border-radius:6px}.rounded-\\[8px\\]{border-radius:8px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-tl{border-top-left-radius:.25rem}.rounded-tr{border-top-right-radius:.25rem}.rounded-br{border-bottom-right-radius:.25rem}.rounded-bl{border-bottom-left-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-dotted{--tw-border-style:dotted;border-style:dotted}.border-double{--tw-border-style:double;border-style:double}.border-none{--tw-border-style:none;border-style:none}.border-solid{--tw-border-style:solid;border-style:solid}.\\[border-top-style\\:solid\\]{border-top-style:solid}.\\[border-right-style\\:dashed\\]{border-right-style:dashed}.\\[border-bottom-style\\:dashed\\]{border-bottom-style:dashed}.\\[border-bottom-style\\:dotted\\]{border-bottom-style:dotted}.\\[border-bottom-style\\:solid\\]{border-bottom-style:solid}.\\[border-left-style\\:double\\]{border-left-style:double}.\\[border-left-style\\:solid\\]{border-left-style:solid}.border-border{border-color:var(--color-border)}.border-border\\/30{border-color:#e6e6e64d}@supports (color:color-mix(in lab, red, red)){.border-border\\/30{border-color:color-mix(in oklab,var(--color-border)30%,transparent)}}.border-border\\/50{border-color:#e6e6e680}@supports (color:color-mix(in lab, red, red)){.border-border\\/50{border-color:color-mix(in oklab,var(--color-border)50%,transparent)}}.border-foreground\\/10{border-color:#1717171a}@supports (color:color-mix(in lab, red, red)){.border-foreground\\/10{border-color:color-mix(in oklab,var(--color-foreground)10%,transparent)}}.border-transparent{border-color:#0000}.border-white{border-color:var(--color-white)}.bg-\\[canvas\\]{background-color:canvas}.bg-background{background-color:var(--color-background)}.bg-background\\/85{background-color:#ffffffd9}@supports (color:color-mix(in lab, red, red)){.bg-background\\/85{background-color:color-mix(in oklab,var(--color-background)85%,transparent)}}.bg-blue-500{background-color:var(--color-blue-500)}.bg-border{background-color:var(--color-border)}.bg-destructive{background-color:var(--color-destructive)}.bg-foreground{background-color:var(--color-foreground)}.bg-foreground\\/25{background-color:#17171740}@supports (color:color-mix(in lab, red, red)){.bg-foreground\\/25{background-color:color-mix(in oklab,var(--color-foreground)25%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-muted-foreground\\/30{background-color:#7373734d}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\\/30{background-color:color-mix(in oklab,var(--color-muted-foreground)30%,transparent)}}.bg-primary{background-color:var(--color-primary)}.bg-transparent{background-color:#0000}.fill-border{fill:var(--color-border)}.p-0{padding:calc(var(--spacing)*0)}.p-0\\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-1\\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-1\\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-3\\.5{padding-block:calc(var(--spacing)*3.5)}.pt-0{padding-top:calc(var(--spacing)*0)}.pt-1{padding-top:calc(var(--spacing)*1)}.pt-2\\.5{padding-top:calc(var(--spacing)*2.5)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-6{padding-top:calc(var(--spacing)*6)}.pt-\\[13px\\]{padding-top:13px}.pr-1{padding-right:calc(var(--spacing)*1)}.pr-1\\.5{padding-right:calc(var(--spacing)*1.5)}.pr-2{padding-right:calc(var(--spacing)*2)}.pb-1{padding-bottom:calc(var(--spacing)*1)}.pb-1\\.5{padding-bottom:calc(var(--spacing)*1.5)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pl-0{padding-left:calc(var(--spacing)*0)}.pl-3{padding-left:calc(var(--spacing)*3)}.pl-6{padding-left:calc(var(--spacing)*6)}.pl-7{padding-left:calc(var(--spacing)*7)}.text-center{text-align:center}.text-justify{text-align:justify}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.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))}.text-\\[7px\\]{font-size:7px}.text-\\[9px\\]{font-size:9px}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-black{--tw-font-weight:var(--font-weight-black);font-weight:var(--font-weight-black)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-extrabold{--tw-font-weight:var(--font-weight-extrabold);font-weight:var(--font-weight-extrabold)}.font-extralight{--tw-font-weight:var(--font-weight-extralight);font-weight:var(--font-weight-extralight)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.font-thin{--tw-font-weight:var(--font-weight-thin);font-weight:var(--font-weight-thin)}.whitespace-nowrap{white-space:nowrap}.text-background{color:var(--color-background)}.text-blue-500{color:var(--color-blue-500)}.text-destructive-foreground{color:var(--color-destructive-foreground)}.text-foreground{color:var(--color-foreground)}.text-green-400{color:var(--color-green-400)}.text-green-500{color:var(--color-green-500)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-popover-foreground{color:var(--color-popover-foreground)}.text-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-red-500{color:var(--color-red-500)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.text-white{color:var(--color-white)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,)var(--tw-slashed-zero,)var(--tw-numeric-figure,)var(--tw-numeric-spacing,)var(--tw-numeric-fraction,)}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px 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-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-2xs{--tw-shadow:0 1px 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)}.shadow-\\[0_0_0_1px_rgba\\(0\\,0\\,0\\,0\\.3\\)\\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\\[0_4px_6px_-1px_rgba\\(0\\,0\\,0\\,0\\.1\\)\\]{--tw-shadow:0 4px 6px -1px 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-\\[inset_0_0_0_1px_rgba\\(0\\,0\\,0\\,0\\.1\\)\\]{--tw-shadow:inset 0 0 0 1px 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-inner{--tw-shadow:inset 0 2px 4px 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)}.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-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px 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-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px 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-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px 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)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + 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)}.ring-white{--tw-ring-color:var(--color-white)}.outline,.outline-1{outline-style:var(--tw-outline-style);outline-width:1px}.outline-border{outline-color:var(--color-border)}.outline-foreground\\/10{outline-color:#1717171a}@supports (color:color-mix(in lab, red, red)){.outline-foreground\\/10{outline-color:color-mix(in oklab,var(--color-foreground)10%,transparent)}}.outline-red-500\\/70{outline-color:#fb2c36b3}@supports (color:color-mix(in lab, red, red)){.outline-red-500\\/70{outline-color:color-mix(in oklab,var(--color-red-500)70%,transparent)}}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[color\\,background-color\\]{transition-property:color,background-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[opacity\\,background-color\\,color\\]{transition-property:opacity,background-color,color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[transform\\,scale\\,opacity\\]{transition-property:transform,scale,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.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))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.animate-in{--tw-enter-opacity:initial;--tw-enter-scale:initial;--tw-enter-rotate:initial;--tw-enter-translate-x:initial;--tw-enter-translate-y:initial;animation-name:enter;animation-duration:.15s}.outline-dashed{--tw-outline-style:dashed;outline-style:dashed}.outline-dotted{--tw-outline-style:dotted;outline-style:dotted}.outline-double{--tw-outline-style:double;outline-style:double}.outline-none{--tw-outline-style:none;outline-style:none}.outline-solid{--tw-outline-style:solid;outline-style:solid}.select-none{-webkit-user-select:none;user-select:none}.\\[-ms-overflow-style\\:none\\]{-ms-overflow-style:none}.\\[scrollbar-width\\:none\\]{scrollbar-width:none}.duration-150{animation-duration:.15s}.duration-200{animation-duration:.2s}.ease-in-out{animation-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{animation-timing-function:cubic-bezier(0,0,.2,1)}.fade-in-0{--tw-enter-opacity:0}.running{animation-play-state:running}.zoom-in-95{--tw-enter-scale:.95}@media (hover:hover){.group-hover\\:opacity-100:is(:where(.group):hover *){opacity:1}.group-hover\\/pin\\:inline:is(:where(.group\\/pin):hover *){display:inline}}.file\\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\\:bg-transparent::file-selector-button{background-color:#0000}.file\\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\\:text-foreground::file-selector-button{color:var(--color-foreground)}.placeholder\\:text-muted-foreground::placeholder{color:var(--color-muted-foreground)}.placeholder\\:text-red-400::placeholder{color:var(--color-red-400)}.focus-within\\:ring-1:focus-within{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + 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-within\\:ring-ring:focus-within{--tw-ring-color:var(--color-ring)}.focus-within\\:outline-none:focus-within{--tw-outline-style:none;outline-style:none}.focus-within\\:ring-inset:focus-within{--tw-ring-inset:inset}@media (hover:hover){.hover\\:scale-\\[1\\.67\\]:hover{scale:1.67}.hover\\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\\:bg-destructive\\/90:hover{background-color:#ef4444e6}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-destructive\\/90:hover{background-color:color-mix(in oklab,var(--color-destructive)90%,transparent)}}.hover\\:bg-foreground\\/80:hover{background-color:#171717cc}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-foreground\\/80:hover{background-color:color-mix(in oklab,var(--color-foreground)80%,transparent)}}.hover\\:bg-muted:hover{background-color:var(--color-muted)}.hover\\:bg-muted-foreground\\/10:hover{background-color:#7373731a}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-muted-foreground\\/10:hover{background-color:color-mix(in oklab,var(--color-muted-foreground)10%,transparent)}}.hover\\:bg-muted\\/50:hover{background-color:#f2f2f280}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-muted\\/50:hover{background-color:color-mix(in oklab,var(--color-muted)50%,transparent)}}.hover\\:bg-muted\\/80:hover{background-color:#f2f2f2cc}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-muted\\/80:hover{background-color:color-mix(in oklab,var(--color-muted)80%,transparent)}}.hover\\:bg-primary\\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-primary\\/90:hover{background-color:color-mix(in oklab,var(--color-primary)90%,transparent)}}.hover\\:text-foreground:hover{color:var(--color-foreground)}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:shadow-lg:hover{--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)}}.focus\\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\\:ring-1:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + 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-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.active\\:cursor-grabbing:active{cursor:grabbing}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}.disabled\\:opacity-60:disabled{opacity:.6}.data-ending-style\\:scale-90[data-ending-style]{--tw-scale-x:90%;--tw-scale-y:90%;--tw-scale-z:90%;scale:var(--tw-scale-x)var(--tw-scale-y)}.data-ending-style\\:opacity-0[data-ending-style]{opacity:0}.data-instant\\:transition-none[data-instant]{transition-property:none}.data-starting-style\\:scale-90[data-starting-style]{--tw-scale-x:90%;--tw-scale-y:90%;--tw-scale-z:90%;scale:var(--tw-scale-x)var(--tw-scale-y)}.data-starting-style\\:opacity-0[data-starting-style]{opacity:0}.data-\\[highlighted\\]\\:bg-muted[data-highlighted]{background-color:var(--color-muted)}.data-\\[highlighted\\]\\:bg-muted\\/50[data-highlighted]{background-color:#f2f2f280}@supports (color:color-mix(in lab, red, red)){.data-\\[highlighted\\]\\:bg-muted\\/50[data-highlighted]{background-color:color-mix(in oklab,var(--color-muted)50%,transparent)}}.data-\\[highlighted\\]\\:text-foreground[data-highlighted]{color:var(--color-foreground)}@media (prefers-color-scheme:dark){.dark\\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.dark\\:-outline-offset-1{outline-offset:calc(1px*-1)}}.\\[\\&_svg\\]\\:pointer-events-none svg{pointer-events:none}.\\[\\&_svg\\]\\:size-4 svg{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\\[\\&_svg\\]\\:shrink-0 svg{flex-shrink:0}.\\[\\&\\:\\:-webkit-inner-spin-button\\]\\:appearance-none::-webkit-inner-spin-button{appearance:none}.\\[\\&\\:\\:-webkit-outer-spin-button\\]\\:appearance-none::-webkit-outer-spin-button{appearance:none}.\\[\\&\\:\\:-webkit-scrollbar\\]\\:hidden::-webkit-scrollbar{display:none}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition:none;animation:none}}.lucide{stroke-width:1px}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,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-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{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}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes pulse{50%{opacity:.5}}';
89
89
 
90
90
  // src/portal-container.tsx
91
91
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -114,7 +114,7 @@ function PortalContainerProvider({ children }) {
114
114
  const root = document.createElement("div");
115
115
  root.setAttribute("data-direct-edit-root", "");
116
116
  shadow.appendChild(root);
117
- document.body.appendChild(host);
117
+ document.documentElement.appendChild(host);
118
118
  setContainer(root);
119
119
  return () => {
120
120
  host.remove();
@@ -156,6 +156,13 @@ function clamp(value, min, max) {
156
156
  if (max < min) return min;
157
157
  return Math.max(min, Math.min(max, value));
158
158
  }
159
+ function isInputFocused() {
160
+ let active = document.activeElement;
161
+ while (active?.shadowRoot?.activeElement) {
162
+ active = active.shadowRoot.activeElement;
163
+ }
164
+ return active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable;
165
+ }
159
166
  function getComputedStyles(element) {
160
167
  const computed = window.getComputedStyle(element);
161
168
  return {
@@ -2812,6 +2819,7 @@ function useSessionManager({
2812
2819
  borderStyleControlPreference: prev.borderStyleControlPreference,
2813
2820
  comments: prev.comments,
2814
2821
  activeCommentId: prev.activeCommentId,
2822
+ canvas: prev.canvas,
2815
2823
  textEditingElement: null
2816
2824
  }));
2817
2825
  }, [pushUndo, saveCurrentToSession]);
@@ -2946,6 +2954,7 @@ function useSessionManager({
2946
2954
  borderStyleControlPreference: prev.borderStyleControlPreference,
2947
2955
  comments: prev.comments,
2948
2956
  activeCommentId: prev.activeCommentId,
2957
+ canvas: prev.canvas,
2949
2958
  textEditingElement: null
2950
2959
  }));
2951
2960
  } else {
@@ -3144,6 +3153,7 @@ function useSessionManager({
3144
3153
  borderStyleControlPreference: prev.borderStyleControlPreference,
3145
3154
  comments: prev.comments,
3146
3155
  activeCommentId: prev.activeCommentId,
3156
+ canvas: prev.canvas,
3147
3157
  textEditingElement: null
3148
3158
  }));
3149
3159
  },
@@ -3357,8 +3367,8 @@ function useTextAndComments({
3357
3367
  const locator = getElementLocator(element);
3358
3368
  const rect = element.getBoundingClientRect();
3359
3369
  const relativePosition = {
3360
- x: clickPosition.x - rect.left,
3361
- y: clickPosition.y - rect.top
3370
+ x: rect.width > 0 ? (clickPosition.x - rect.left) / rect.width : 0,
3371
+ y: rect.height > 0 ? (clickPosition.y - rect.top) / rect.height : 0
3362
3372
  };
3363
3373
  const id = `comment-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
3364
3374
  const comment = {
@@ -3371,11 +3381,14 @@ function useTextAndComments({
3371
3381
  createdAt: Date.now(),
3372
3382
  replies: []
3373
3383
  };
3374
- setState((prev) => ({
3375
- ...prev,
3376
- comments: [...prev.comments, comment],
3377
- activeCommentId: id
3378
- }));
3384
+ setState((prev) => {
3385
+ const filtered = prev.activeCommentId ? prev.comments.filter((c) => c.id !== prev.activeCommentId || c.text.trim().length > 0) : prev.comments;
3386
+ return {
3387
+ ...prev,
3388
+ comments: [...filtered, comment],
3389
+ activeCommentId: id
3390
+ };
3391
+ });
3379
3392
  }, []);
3380
3393
  const updateCommentText = React4.useCallback((id, text) => {
3381
3394
  setState((prev) => ({
@@ -3798,11 +3811,11 @@ async function sendCommentToAgent(comment) {
3798
3811
 
3799
3812
  // src/use-agent-comms.ts
3800
3813
  function useAgentComms({ stateRef, sessionEditsRef, getSessionItems }) {
3801
- const canSendEditToAgent = React5.useCallback((snapshot) => {
3814
+ const canSendEditToAgent = React5.useCallback((snapshot2) => {
3802
3815
  const current = stateRef.current;
3803
- const selectedElement = snapshot?.selectedElement ?? current.selectedElement;
3804
- const elementInfo = snapshot?.elementInfo ?? current.elementInfo;
3805
- const pendingStyles = snapshot?.pendingStyles ?? current.pendingStyles;
3816
+ const selectedElement = snapshot2?.selectedElement ?? current.selectedElement;
3817
+ const elementInfo = snapshot2?.elementInfo ?? current.elementInfo;
3818
+ const pendingStyles = snapshot2?.pendingStyles ?? current.pendingStyles;
3806
3819
  if (!selectedElement || !elementInfo) return false;
3807
3820
  const sessionEdit = sessionEditsRef.current.get(selectedElement);
3808
3821
  const hasPendingStyles = Object.keys(pendingStyles).length > 0;
@@ -3925,7 +3938,11 @@ function useKeyboardShortcuts({
3925
3938
  commitTextEditing,
3926
3939
  startTextEditing,
3927
3940
  closePanel,
3928
- setState
3941
+ setState,
3942
+ toggleCanvas,
3943
+ setCanvasZoom,
3944
+ fitCanvasToViewport,
3945
+ zoomCanvasTo100
3929
3946
  }) {
3930
3947
  React6.useEffect(() => {
3931
3948
  function handleToggle(e) {
@@ -3947,15 +3964,13 @@ function useKeyboardShortcuts({
3947
3964
  return;
3948
3965
  }
3949
3966
  if (e.key === "C" && e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey && s.editModeActive) {
3950
- const active = document.activeElement;
3951
- const isInput = active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable;
3952
- if (!isInput) {
3967
+ if (!isInputFocused()) {
3953
3968
  e.preventDefault();
3954
3969
  setState((prev) => {
3955
3970
  let comments = prev.comments;
3956
3971
  if (prev.activeCommentId) {
3957
- const active2 = comments.find((c) => c.id === prev.activeCommentId);
3958
- if (active2 && active2.text === "") {
3972
+ const active = comments.find((c) => c.id === prev.activeCommentId);
3973
+ if (active && active.text === "") {
3959
3974
  comments = comments.filter((c) => c.id !== prev.activeCommentId);
3960
3975
  }
3961
3976
  }
@@ -3969,19 +3984,44 @@ function useKeyboardShortcuts({
3969
3984
  return;
3970
3985
  }
3971
3986
  }
3987
+ if (e.key === "Z" && e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey && s.editModeActive) {
3988
+ if (!isInputFocused()) {
3989
+ e.preventDefault();
3990
+ toggleCanvas();
3991
+ return;
3992
+ }
3993
+ }
3994
+ if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey && s.canvas?.active) {
3995
+ if (e.code === "Digit0" || e.key === "0") {
3996
+ e.preventDefault();
3997
+ fitCanvasToViewport();
3998
+ return;
3999
+ }
4000
+ if (e.code === "Digit1" || e.key === "1") {
4001
+ e.preventDefault();
4002
+ zoomCanvasTo100();
4003
+ return;
4004
+ }
4005
+ if (e.code === "Equal" || e.key === "=") {
4006
+ e.preventDefault();
4007
+ setCanvasZoom(Math.min(5, (s.canvas?.zoom ?? 1) * 1.1));
4008
+ return;
4009
+ }
4010
+ if (e.code === "Minus" || e.key === "-") {
4011
+ e.preventDefault();
4012
+ setCanvasZoom(Math.max(0.1, (s.canvas?.zoom ?? 1) / 1.1));
4013
+ return;
4014
+ }
4015
+ }
3972
4016
  if (e.key === "A" && e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey && s.editModeActive && s.selectedElement) {
3973
- const active = document.activeElement;
3974
- const isInput = active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable;
3975
- if (!isInput) {
4017
+ if (!isInputFocused()) {
3976
4018
  e.preventDefault();
3977
4019
  toggleFlexLayout();
3978
4020
  return;
3979
4021
  }
3980
4022
  }
3981
4023
  if (e.key === "Enter" && s.editModeActive && !s.textEditingElement && s.selectedElement) {
3982
- const active = document.activeElement;
3983
- const isInput = active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable;
3984
- if (!isInput && isTextElement(s.selectedElement)) {
4024
+ if (!isInputFocused() && isTextElement(s.selectedElement)) {
3985
4025
  e.preventDefault();
3986
4026
  startTextEditing(s.selectedElement);
3987
4027
  return;
@@ -4012,22 +4052,394 @@ function useKeyboardShortcuts({
4012
4052
  }
4013
4053
  window.addEventListener("keydown", handleKeyDown);
4014
4054
  return () => window.removeEventListener("keydown", handleKeyDown);
4015
- }, [closePanel, toggleEditMode, toggleFlexLayout, undo, commitTextEditing, startTextEditing]);
4055
+ }, [closePanel, toggleEditMode, toggleFlexLayout, undo, commitTextEditing, startTextEditing, toggleCanvas, setCanvasZoom, fitCanvasToViewport, zoomCanvasTo100]);
4056
+ }
4057
+
4058
+ // src/use-canvas.ts
4059
+ var React7 = __toESM(require("react"));
4060
+
4061
+ // src/canvas-store.ts
4062
+ var import_react = require("react");
4063
+ var DEFAULT = { active: false, zoom: 1, panX: 0, panY: 0 };
4064
+ var snapshot = DEFAULT;
4065
+ var listeners = /* @__PURE__ */ new Set();
4066
+ var ownerCount = 0;
4067
+ var bodyOffset = { x: 0, y: 0 };
4068
+ function getBodyOffset() {
4069
+ return bodyOffset;
4070
+ }
4071
+ function setBodyOffset(o) {
4072
+ bodyOffset = o;
4073
+ }
4074
+ function getCanvasSnapshot() {
4075
+ return snapshot;
4076
+ }
4077
+ function setCanvasSnapshot(next) {
4078
+ snapshot = next;
4079
+ listeners.forEach((cb) => cb());
4080
+ }
4081
+ function registerCanvasStoreOwner() {
4082
+ ownerCount += 1;
4083
+ if (ownerCount > 1 && (typeof process === "undefined" || process.env.NODE_ENV !== "test")) {
4084
+ console.warn("[made-refine] multiple DirectEditProvider instances share canvas-store globals");
4085
+ }
4086
+ return () => {
4087
+ ownerCount = Math.max(0, ownerCount - 1);
4088
+ };
4089
+ }
4090
+ function subscribe(cb) {
4091
+ listeners.add(cb);
4092
+ return () => {
4093
+ listeners.delete(cb);
4094
+ };
4095
+ }
4096
+ function useCanvasSnapshot() {
4097
+ return (0, import_react.useSyncExternalStore)(subscribe, getCanvasSnapshot, () => DEFAULT);
4098
+ }
4099
+
4100
+ // src/use-canvas.ts
4101
+ var MIN_ZOOM = 0.1;
4102
+ var MAX_ZOOM = 5;
4103
+ var ZOOM_SENSITIVITY = 0.0145;
4104
+ var LINE_HEIGHT_PX = 40;
4105
+ var PAGE_HEIGHT_PX = 800;
4106
+ function normalizeWheelDelta(e) {
4107
+ let { deltaX, deltaY } = e;
4108
+ if (e.deltaMode === 1) {
4109
+ deltaX *= LINE_HEIGHT_PX;
4110
+ deltaY *= LINE_HEIGHT_PX;
4111
+ } else if (e.deltaMode === 2) {
4112
+ deltaX *= PAGE_HEIGHT_PX;
4113
+ deltaY *= PAGE_HEIGHT_PX;
4114
+ }
4115
+ return { deltaX, deltaY };
4116
+ }
4117
+ var PAN_MARGIN = 0.1;
4118
+ function clampPan(zoom, panX, panY, bodyW, bodyH) {
4119
+ const vw = window.innerWidth;
4120
+ const vh = window.innerHeight;
4121
+ const minPanX = PAN_MARGIN * vw / zoom - bodyW;
4122
+ const maxPanX = (1 - PAN_MARGIN) * vw / zoom;
4123
+ const minPanY = PAN_MARGIN * vh / zoom - bodyH;
4124
+ const maxPanY = (1 - PAN_MARGIN) * vh / zoom;
4125
+ return {
4126
+ panX: Math.max(minPanX, Math.min(maxPanX, panX)),
4127
+ panY: Math.max(minPanY, Math.min(maxPanY, panY))
4128
+ };
4129
+ }
4130
+ function useCanvas({ stateRef, setState }) {
4131
+ React7.useEffect(() => registerCanvasStoreOwner(), []);
4132
+ const canvasRef = React7.useRef({ active: false, zoom: 1, panX: 0, panY: 0 });
4133
+ const savedScrollRef = React7.useRef({ x: 0, y: 0 });
4134
+ const savedBodyOverflowRef = React7.useRef("");
4135
+ const savedHtmlOverflowRef = React7.useRef("");
4136
+ const savedHtmlBgColorRef = React7.useRef("");
4137
+ const savedBodyDimensionsRef = React7.useRef({ width: 0, height: 0 });
4138
+ const savedScrollContainersRef = React7.useRef([]);
4139
+ const rafIdRef = React7.useRef(null);
4140
+ const rafPendingRef = React7.useRef(false);
4141
+ const spaceHeldRef = React7.useRef(false);
4142
+ const isDraggingRef = React7.useRef(false);
4143
+ const dragStartRef = React7.useRef({ x: 0, y: 0, panX: 0, panY: 0 });
4144
+ const applyTransform = React7.useCallback((zoom, panX, panY) => {
4145
+ document.body.style.transformOrigin = "0 0";
4146
+ document.body.style.transform = `scale(${zoom}) translate(${panX}px, ${panY}px)`;
4147
+ }, []);
4148
+ const dispatchCanvasChange = React7.useCallback(() => {
4149
+ window.dispatchEvent(new Event("direct-edit-canvas-change"));
4150
+ }, []);
4151
+ const readBodyOffset = React7.useCallback(() => {
4152
+ const bodyStyle = getComputedStyle(document.body);
4153
+ return {
4154
+ x: parseFloat(bodyStyle.marginLeft) || 0,
4155
+ y: parseFloat(bodyStyle.marginTop) || 0
4156
+ };
4157
+ }, []);
4158
+ const updateBodyOffset = React7.useCallback(() => {
4159
+ const next = readBodyOffset();
4160
+ const prev = getBodyOffset();
4161
+ if (prev.x === next.x && prev.y === next.y) return false;
4162
+ setBodyOffset(next);
4163
+ return true;
4164
+ }, [readBodyOffset]);
4165
+ const cancelPendingRaf = React7.useCallback(() => {
4166
+ if (rafIdRef.current !== null) {
4167
+ cancelAnimationFrame(rafIdRef.current);
4168
+ rafIdRef.current = null;
4169
+ rafPendingRef.current = false;
4170
+ }
4171
+ }, []);
4172
+ const updateCanvas = React7.useCallback((zoom, panX, panY) => {
4173
+ const dims = savedBodyDimensionsRef.current;
4174
+ const bodyW = dims.width || window.innerWidth;
4175
+ const bodyH = dims.height || window.innerHeight;
4176
+ const clamped = clampPan(zoom, panX, panY, bodyW, bodyH);
4177
+ canvasRef.current = { ...canvasRef.current, zoom, panX: clamped.panX, panY: clamped.panY };
4178
+ setCanvasSnapshot(canvasRef.current);
4179
+ applyTransform(zoom, clamped.panX, clamped.panY);
4180
+ dispatchCanvasChange();
4181
+ if (!rafPendingRef.current) {
4182
+ rafPendingRef.current = true;
4183
+ rafIdRef.current = requestAnimationFrame(() => {
4184
+ rafPendingRef.current = false;
4185
+ rafIdRef.current = null;
4186
+ const s = canvasRef.current;
4187
+ setState((prev) => ({
4188
+ ...prev,
4189
+ canvas: { active: s.active, zoom: s.zoom, panX: s.panX, panY: s.panY }
4190
+ }));
4191
+ });
4192
+ }
4193
+ }, [applyTransform, dispatchCanvasChange, setState]);
4194
+ function isScrollableContainer(el) {
4195
+ if (el.scrollHeight <= el.clientHeight + 1) return false;
4196
+ const style = getComputedStyle(el);
4197
+ const overflowY = style.overflowY || style.overflow;
4198
+ if (overflowY === "hidden" || overflowY === "clip") return false;
4199
+ return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
4200
+ }
4201
+ function expandScrollContainers() {
4202
+ const saved = [];
4203
+ const queue = Array.from(document.body.children).filter(
4204
+ (el) => el instanceof HTMLElement
4205
+ );
4206
+ let visited = 0;
4207
+ const maxNodes = 5e3;
4208
+ while (queue.length > 0 && visited < maxNodes) {
4209
+ const nextQueue = [];
4210
+ for (const el of queue) {
4211
+ if (visited >= maxNodes) break;
4212
+ visited++;
4213
+ if (isScrollableContainer(el)) {
4214
+ const style = el.style;
4215
+ saved.push({
4216
+ el,
4217
+ height: style.height,
4218
+ maxHeight: style.maxHeight,
4219
+ overflowX: style.overflowX,
4220
+ overflowY: style.overflowY
4221
+ });
4222
+ style.height = "auto";
4223
+ style.maxHeight = "none";
4224
+ style.overflowX = "visible";
4225
+ style.overflowY = "visible";
4226
+ }
4227
+ for (const child of el.children) {
4228
+ if (child instanceof HTMLElement) nextQueue.push(child);
4229
+ }
4230
+ }
4231
+ queue.length = 0;
4232
+ queue.push(...nextQueue);
4233
+ }
4234
+ savedScrollContainersRef.current = saved;
4235
+ }
4236
+ function restoreScrollContainers() {
4237
+ for (let i = savedScrollContainersRef.current.length - 1; i >= 0; i--) {
4238
+ const { el, height, maxHeight, overflowX, overflowY } = savedScrollContainersRef.current[i];
4239
+ el.style.height = height;
4240
+ el.style.maxHeight = maxHeight;
4241
+ el.style.overflowX = overflowX;
4242
+ el.style.overflowY = overflowY;
4243
+ }
4244
+ savedScrollContainersRef.current = [];
4245
+ }
4246
+ const enterCanvas = React7.useCallback(() => {
4247
+ const scrollX = window.scrollX;
4248
+ const scrollY = window.scrollY;
4249
+ savedScrollRef.current = { x: scrollX, y: scrollY };
4250
+ savedBodyOverflowRef.current = document.body.style.overflow;
4251
+ savedHtmlOverflowRef.current = document.documentElement.style.overflow;
4252
+ savedHtmlBgColorRef.current = document.documentElement.style.backgroundColor;
4253
+ const existingTransform = document.body.style.transform;
4254
+ if (existingTransform && existingTransform !== "none" && existingTransform !== "") {
4255
+ console.warn("[made-refine] canvas mode: overriding existing body transform:", existingTransform);
4256
+ }
4257
+ window.scrollTo(0, 0);
4258
+ expandScrollContainers();
4259
+ savedBodyDimensionsRef.current = {
4260
+ width: document.body.scrollWidth,
4261
+ height: document.body.scrollHeight
4262
+ };
4263
+ updateBodyOffset();
4264
+ document.body.style.overflow = "hidden";
4265
+ document.documentElement.style.overflow = "hidden";
4266
+ document.documentElement.style.backgroundColor = "#F5F5F5";
4267
+ const initialPanX = -scrollX;
4268
+ const initialPanY = -scrollY;
4269
+ applyTransform(1, initialPanX, initialPanY);
4270
+ canvasRef.current = { active: true, zoom: 1, panX: initialPanX, panY: initialPanY };
4271
+ setCanvasSnapshot(canvasRef.current);
4272
+ setState((prev) => ({
4273
+ ...prev,
4274
+ canvas: { active: true, zoom: 1, panX: initialPanX, panY: initialPanY }
4275
+ }));
4276
+ dispatchCanvasChange();
4277
+ }, [applyTransform, dispatchCanvasChange, setState, updateBodyOffset]);
4278
+ const exitCanvas = React7.useCallback(() => {
4279
+ cancelPendingRaf();
4280
+ document.body.style.transform = "";
4281
+ document.body.style.transformOrigin = "";
4282
+ restoreScrollContainers();
4283
+ document.body.style.overflow = savedBodyOverflowRef.current;
4284
+ document.documentElement.style.overflow = savedHtmlOverflowRef.current;
4285
+ document.documentElement.style.backgroundColor = savedHtmlBgColorRef.current;
4286
+ document.body.style.cursor = "";
4287
+ window.scrollTo(savedScrollRef.current.x, savedScrollRef.current.y);
4288
+ setBodyOffset({ x: 0, y: 0 });
4289
+ canvasRef.current = { active: false, zoom: 1, panX: 0, panY: 0 };
4290
+ setCanvasSnapshot(canvasRef.current);
4291
+ setState((prev) => ({
4292
+ ...prev,
4293
+ canvas: { active: false, zoom: 1, panX: 0, panY: 0 }
4294
+ }));
4295
+ dispatchCanvasChange();
4296
+ }, [cancelPendingRaf, dispatchCanvasChange, setState]);
4297
+ const toggleCanvas = React7.useCallback(() => {
4298
+ if (canvasRef.current.active) {
4299
+ exitCanvas();
4300
+ } else {
4301
+ enterCanvas();
4302
+ }
4303
+ }, [enterCanvas, exitCanvas]);
4304
+ const setCanvasZoom = React7.useCallback((zoom) => {
4305
+ const c = canvasRef.current;
4306
+ if (!c.active) return;
4307
+ const clampedZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom));
4308
+ updateCanvas(clampedZoom, c.panX, c.panY);
4309
+ }, [updateCanvas]);
4310
+ const fitCanvasToViewport = React7.useCallback(() => {
4311
+ const c = canvasRef.current;
4312
+ if (!c.active) return;
4313
+ const bodyWidth = savedBodyDimensionsRef.current.width || window.innerWidth;
4314
+ const bodyHeight = savedBodyDimensionsRef.current.height || window.innerHeight;
4315
+ const scaleX = window.innerWidth / bodyWidth;
4316
+ const scaleY = window.innerHeight / bodyHeight;
4317
+ const zoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, Math.min(scaleX, scaleY) * 0.9));
4318
+ const panX = (window.innerWidth / zoom - bodyWidth) / 2;
4319
+ const panY = (window.innerHeight / zoom - bodyHeight) / 2;
4320
+ updateCanvas(zoom, panX, panY);
4321
+ }, [updateCanvas]);
4322
+ const zoomCanvasTo100 = React7.useCallback(() => {
4323
+ const c = canvasRef.current;
4324
+ if (!c.active) return;
4325
+ updateCanvas(1, 0, 0);
4326
+ }, [updateCanvas]);
4327
+ React7.useEffect(() => {
4328
+ function handleWheel(e) {
4329
+ const c = canvasRef.current;
4330
+ if (!c.active) return;
4331
+ e.preventDefault();
4332
+ const { deltaX, deltaY } = normalizeWheelDelta(e);
4333
+ if (e.ctrlKey || e.metaKey) {
4334
+ const zoomFactor = Math.exp(-deltaY * ZOOM_SENSITIVITY);
4335
+ const oldZoom = c.zoom;
4336
+ const newZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, oldZoom * zoomFactor));
4337
+ const cx = e.clientX;
4338
+ const cy = e.clientY;
4339
+ const bo = getBodyOffset();
4340
+ const newPanX = c.panX + (cx - bo.x) * (1 / newZoom - 1 / oldZoom);
4341
+ const newPanY = c.panY + (cy - bo.y) * (1 / newZoom - 1 / oldZoom);
4342
+ updateCanvas(newZoom, newPanX, newPanY);
4343
+ } else {
4344
+ const newPanX = c.panX - deltaX / c.zoom;
4345
+ const newPanY = c.panY - deltaY / c.zoom;
4346
+ updateCanvas(c.zoom, newPanX, newPanY);
4347
+ }
4348
+ }
4349
+ window.addEventListener("wheel", handleWheel, { passive: false });
4350
+ return () => window.removeEventListener("wheel", handleWheel);
4351
+ }, [updateCanvas]);
4352
+ React7.useEffect(() => {
4353
+ function handleResize() {
4354
+ if (!canvasRef.current.active) return;
4355
+ if (updateBodyOffset()) {
4356
+ dispatchCanvasChange();
4357
+ }
4358
+ }
4359
+ window.addEventListener("resize", handleResize);
4360
+ return () => window.removeEventListener("resize", handleResize);
4361
+ }, [dispatchCanvasChange, updateBodyOffset]);
4362
+ React7.useEffect(() => {
4363
+ function handleKeyDown(e) {
4364
+ if (e.code !== "Space" || e.repeat) return;
4365
+ if (!canvasRef.current.active) return;
4366
+ if (isInputFocused()) return;
4367
+ spaceHeldRef.current = true;
4368
+ if (!isDraggingRef.current) {
4369
+ document.body.style.cursor = "grab";
4370
+ }
4371
+ e.preventDefault();
4372
+ }
4373
+ function handleKeyUp(e) {
4374
+ if (e.code !== "Space") return;
4375
+ if (!canvasRef.current.active) return;
4376
+ spaceHeldRef.current = false;
4377
+ if (!isDraggingRef.current) {
4378
+ document.body.style.cursor = "";
4379
+ }
4380
+ }
4381
+ window.addEventListener("keydown", handleKeyDown, true);
4382
+ window.addEventListener("keyup", handleKeyUp, true);
4383
+ return () => {
4384
+ window.removeEventListener("keydown", handleKeyDown, true);
4385
+ window.removeEventListener("keyup", handleKeyUp, true);
4386
+ };
4387
+ }, []);
4388
+ React7.useEffect(() => {
4389
+ function handlePointerDown(e) {
4390
+ const c = canvasRef.current;
4391
+ if (!c.active) return;
4392
+ const isMiddleMouse = e.button === 1;
4393
+ const isSpaceDrag = spaceHeldRef.current && e.button === 0;
4394
+ if (!isMiddleMouse && !isSpaceDrag) return;
4395
+ e.preventDefault();
4396
+ isDraggingRef.current = true;
4397
+ dragStartRef.current = { x: e.clientX, y: e.clientY, panX: c.panX, panY: c.panY };
4398
+ document.body.style.cursor = "grabbing";
4399
+ const dragAbort = new AbortController();
4400
+ const opts = { signal: dragAbort.signal };
4401
+ function endDrag() {
4402
+ isDraggingRef.current = false;
4403
+ document.body.style.cursor = spaceHeldRef.current ? "grab" : "";
4404
+ dragAbort.abort();
4405
+ }
4406
+ window.addEventListener("pointermove", (moveE) => {
4407
+ const current = canvasRef.current;
4408
+ const dx = (moveE.clientX - dragStartRef.current.x) / current.zoom;
4409
+ const dy = (moveE.clientY - dragStartRef.current.y) / current.zoom;
4410
+ updateCanvas(current.zoom, dragStartRef.current.panX + dx, dragStartRef.current.panY + dy);
4411
+ }, opts);
4412
+ window.addEventListener("pointerup", endDrag, opts);
4413
+ window.addEventListener("pointercancel", endDrag, opts);
4414
+ window.addEventListener("blur", endDrag, opts);
4415
+ }
4416
+ window.addEventListener("pointerdown", handlePointerDown, true);
4417
+ return () => window.removeEventListener("pointerdown", handlePointerDown, true);
4418
+ }, [updateCanvas]);
4419
+ React7.useEffect(() => {
4420
+ return () => {
4421
+ cancelPendingRaf();
4422
+ if (canvasRef.current.active) {
4423
+ exitCanvas();
4424
+ }
4425
+ };
4426
+ }, [cancelPendingRaf, exitCanvas]);
4427
+ return { toggleCanvas, enterCanvas, exitCanvas, setCanvasZoom, fitCanvasToViewport, zoomCanvasTo100 };
4016
4428
  }
4017
4429
 
4018
4430
  // src/provider.tsx
4019
4431
  var import_jsx_runtime2 = require("react/jsx-runtime");
4020
- var DirectEditStateContext = React7.createContext(null);
4021
- var DirectEditActionsContext = React7.createContext(null);
4432
+ var DirectEditStateContext = React8.createContext(null);
4433
+ var DirectEditActionsContext = React8.createContext(null);
4022
4434
  function useDirectEditState() {
4023
- const context = React7.useContext(DirectEditStateContext);
4435
+ const context = React8.useContext(DirectEditStateContext);
4024
4436
  if (!context) {
4025
4437
  throw new Error("useDirectEditState must be used within a DirectEditProvider");
4026
4438
  }
4027
4439
  return context;
4028
4440
  }
4029
4441
  function useDirectEditActions() {
4030
- const context = React7.useContext(DirectEditActionsContext);
4442
+ const context = React8.useContext(DirectEditActionsContext);
4031
4443
  if (!context) {
4032
4444
  throw new Error("useDirectEditActions must be used within a DirectEditProvider");
4033
4445
  }
@@ -4036,11 +4448,34 @@ function useDirectEditActions() {
4036
4448
  function useDirectEdit() {
4037
4449
  const state = useDirectEditState();
4038
4450
  const actions = useDirectEditActions();
4039
- return React7.useMemo(() => ({ ...state, ...actions }), [state, actions]);
4451
+ return React8.useMemo(() => ({ ...state, ...actions }), [state, actions]);
4040
4452
  }
4041
4453
  var BORDER_STYLE_CONTROL_PREFERENCE_KEY = "direct-edit-border-style-control";
4454
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? React8.useEffect : React8.useLayoutEffect;
4455
+ function getInitialTheme() {
4456
+ if (typeof window === "undefined") return "system";
4457
+ try {
4458
+ const theme = localStorage.getItem("direct-edit-theme");
4459
+ if (theme === "light" || theme === "dark" || theme === "system") {
4460
+ return theme;
4461
+ }
4462
+ } catch {
4463
+ }
4464
+ return "system";
4465
+ }
4466
+ function getInitialBorderStyleControlPreference() {
4467
+ if (typeof window === "undefined") return "icon";
4468
+ try {
4469
+ const borderPref = localStorage.getItem(BORDER_STYLE_CONTROL_PREFERENCE_KEY);
4470
+ if (borderPref === "label" || borderPref === "icon") {
4471
+ return borderPref;
4472
+ }
4473
+ } catch {
4474
+ }
4475
+ return "icon";
4476
+ }
4042
4477
  function DirectEditProvider({ children }) {
4043
- const [state, setState] = React7.useState({
4478
+ const [state, setState] = React8.useState(() => ({
4044
4479
  isOpen: false,
4045
4480
  selectedElement: null,
4046
4481
  elementInfo: null,
@@ -4056,38 +4491,22 @@ function DirectEditProvider({ children }) {
4056
4491
  pendingStyles: {},
4057
4492
  editModeActive: false,
4058
4493
  activeTool: "select",
4059
- theme: "system",
4060
- borderStyleControlPreference: "icon",
4494
+ theme: getInitialTheme(),
4495
+ borderStyleControlPreference: getInitialBorderStyleControlPreference(),
4061
4496
  comments: [],
4062
4497
  activeCommentId: null,
4063
- textEditingElement: null
4064
- });
4065
- React7.useEffect(() => {
4066
- try {
4067
- const updates = {};
4068
- const theme = localStorage.getItem("direct-edit-theme");
4069
- if (theme === "light" || theme === "dark" || theme === "system") {
4070
- updates.theme = theme;
4071
- }
4072
- const borderPref = localStorage.getItem(BORDER_STYLE_CONTROL_PREFERENCE_KEY);
4073
- if (borderPref === "label" || borderPref === "icon") {
4074
- updates.borderStyleControlPreference = borderPref;
4075
- }
4076
- if (Object.keys(updates).length > 0) {
4077
- setState((prev) => ({ ...prev, ...updates }));
4078
- }
4079
- } catch {
4080
- }
4081
- }, []);
4082
- const undoStackRef = React7.useRef([]);
4083
- const sessionEditsRef = React7.useRef(/* @__PURE__ */ new Map());
4084
- const removedSessionEditsRef = React7.useRef(/* @__PURE__ */ new WeakSet());
4085
- const [sessionEditCount, setSessionEditCount] = React7.useState(0);
4086
- const stateRef = React7.useRef(state);
4087
- React7.useEffect(() => {
4498
+ textEditingElement: null,
4499
+ canvas: { active: false, zoom: 1, panX: 0, panY: 0 }
4500
+ }));
4501
+ const undoStackRef = React8.useRef([]);
4502
+ const sessionEditsRef = React8.useRef(/* @__PURE__ */ new Map());
4503
+ const removedSessionEditsRef = React8.useRef(/* @__PURE__ */ new WeakSet());
4504
+ const [sessionEditCount, setSessionEditCount] = React8.useState(0);
4505
+ const stateRef = React8.useRef(state);
4506
+ React8.useEffect(() => {
4088
4507
  stateRef.current = state;
4089
4508
  });
4090
- const pushUndo = React7.useCallback((entry) => {
4509
+ const pushUndo = React8.useCallback((entry) => {
4091
4510
  undoStackRef.current.push(entry);
4092
4511
  if (undoStackRef.current.length > 500) {
4093
4512
  undoStackRef.current = undoStackRef.current.slice(-500);
@@ -4132,13 +4551,13 @@ function DirectEditProvider({ children }) {
4132
4551
  setState,
4133
4552
  setSessionEditCount
4134
4553
  });
4135
- React7.useEffect(() => {
4554
+ React8.useEffect(() => {
4136
4555
  if (!state.selectedElement) return;
4137
4556
  saveCurrentToSession();
4138
4557
  }, [state.selectedElement, state.pendingStyles, saveCurrentToSession]);
4139
4558
  const {
4140
4559
  finalizeTextEditing,
4141
- toggleEditMode,
4560
+ toggleEditMode: toggleEditModeBase,
4142
4561
  startTextEditing,
4143
4562
  commitTextEditing,
4144
4563
  addComment,
@@ -4155,10 +4574,32 @@ function DirectEditProvider({ children }) {
4155
4574
  syncSessionItemCount,
4156
4575
  setState
4157
4576
  });
4158
- React7.useEffect(() => {
4577
+ const { toggleCanvas, enterCanvas, exitCanvas, setCanvasZoom, fitCanvasToViewport, zoomCanvasTo100 } = useCanvas({
4578
+ stateRef,
4579
+ setState
4580
+ });
4581
+ const closePanel = React8.useCallback(() => {
4582
+ setState((prev) => ({
4583
+ ...prev,
4584
+ isOpen: false
4585
+ }));
4586
+ }, []);
4587
+ const toggleEditMode = React8.useCallback(() => {
4588
+ const wasActive = stateRef.current.editModeActive;
4589
+ toggleEditModeBase();
4590
+ if (wasActive && stateRef.current.canvas?.active) {
4591
+ exitCanvas();
4592
+ } else if (!wasActive) {
4593
+ enterCanvas();
4594
+ }
4595
+ if (wasActive) {
4596
+ closePanel();
4597
+ }
4598
+ }, [toggleEditModeBase, stateRef, exitCanvas, enterCanvas, closePanel]);
4599
+ React8.useEffect(() => {
4159
4600
  syncSessionItemCount(state.comments);
4160
4601
  }, [state.comments, syncSessionItemCount]);
4161
- React7.useEffect(() => {
4602
+ React8.useEffect(() => {
4162
4603
  const editingElement = state.textEditingElement;
4163
4604
  if (!editingElement) return;
4164
4605
  const activeEditingElement = editingElement;
@@ -4183,27 +4624,21 @@ function DirectEditProvider({ children }) {
4183
4624
  sendCommentToAgent: sendCommentToAgent2,
4184
4625
  sendAllSessionItemsToAgent
4185
4626
  } = useAgentComms({ stateRef, sessionEditsRef, getSessionItems });
4186
- const closePanel = React7.useCallback(() => {
4187
- setState((prev) => ({
4188
- ...prev,
4189
- isOpen: false
4190
- }));
4191
- }, []);
4192
- const setActiveTool = React7.useCallback((tool) => {
4627
+ const setActiveTool = React8.useCallback((tool) => {
4193
4628
  setState((prev) => ({
4194
4629
  ...prev,
4195
4630
  activeTool: tool,
4196
4631
  activeCommentId: null
4197
4632
  }));
4198
4633
  }, []);
4199
- const setTheme = React7.useCallback((theme) => {
4634
+ const setTheme = React8.useCallback((theme) => {
4200
4635
  setState((prev) => ({ ...prev, theme }));
4201
4636
  try {
4202
4637
  localStorage.setItem("direct-edit-theme", theme);
4203
4638
  } catch {
4204
4639
  }
4205
4640
  }, []);
4206
- const setBorderStyleControlPreference = React7.useCallback((preference) => {
4641
+ const setBorderStyleControlPreference = React8.useCallback((preference) => {
4207
4642
  setState((prev) => ({ ...prev, borderStyleControlPreference: preference }));
4208
4643
  try {
4209
4644
  localStorage.setItem(BORDER_STYLE_CONTROL_PREFERENCE_KEY, preference);
@@ -4218,13 +4653,17 @@ function DirectEditProvider({ children }) {
4218
4653
  commitTextEditing,
4219
4654
  startTextEditing,
4220
4655
  closePanel,
4221
- setState
4656
+ setState,
4657
+ toggleCanvas,
4658
+ setCanvasZoom,
4659
+ fitCanvasToViewport,
4660
+ zoomCanvasTo100
4222
4661
  });
4223
- const stateContextValue = React7.useMemo(() => ({
4662
+ const stateContextValue = React8.useMemo(() => ({
4224
4663
  ...state,
4225
4664
  sessionEditCount
4226
4665
  }), [state, sessionEditCount]);
4227
- const actionsContextValue = React7.useMemo(() => ({
4666
+ const actionsContextValue = React8.useMemo(() => ({
4228
4667
  selectElement,
4229
4668
  selectParent,
4230
4669
  selectChild,
@@ -4263,7 +4702,11 @@ function DirectEditProvider({ children }) {
4263
4702
  clearSessionEdits,
4264
4703
  removeSessionEdit,
4265
4704
  startTextEditing,
4266
- commitTextEditing
4705
+ commitTextEditing,
4706
+ toggleCanvas,
4707
+ setCanvasZoom,
4708
+ fitCanvasToViewport,
4709
+ zoomCanvasTo100
4267
4710
  }), [
4268
4711
  selectElement,
4269
4712
  selectParent,
@@ -4303,7 +4746,11 @@ function DirectEditProvider({ children }) {
4303
4746
  clearSessionEdits,
4304
4747
  removeSessionEdit,
4305
4748
  startTextEditing,
4306
- commitTextEditing
4749
+ commitTextEditing,
4750
+ toggleCanvas,
4751
+ setCanvasZoom,
4752
+ fitCanvasToViewport,
4753
+ zoomCanvasTo100
4307
4754
  ]);
4308
4755
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PortalContainerProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DirectEditStateContext.Provider, { value: stateContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(DirectEditActionsContext.Provider, { value: actionsContextValue, children: [
4309
4756
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThemeApplier, {}),
@@ -4313,7 +4760,7 @@ function DirectEditProvider({ children }) {
4313
4760
  function ThemeApplier() {
4314
4761
  const { theme } = useDirectEditState();
4315
4762
  const container = usePortalContainer();
4316
- React7.useEffect(() => {
4763
+ useIsomorphicLayoutEffect(() => {
4317
4764
  if (!container) return;
4318
4765
  const host = container.getRootNode().host;
4319
4766
  if (theme === "system") {
@@ -4326,11 +4773,11 @@ function ThemeApplier() {
4326
4773
  }
4327
4774
 
4328
4775
  // src/panel.tsx
4329
- var React28 = __toESM(require("react"));
4776
+ var React29 = __toESM(require("react"));
4330
4777
  var import_react_dom = require("react-dom");
4331
4778
 
4332
4779
  // src/ui/tooltip.tsx
4333
- var React8 = __toESM(require("react"));
4780
+ var React9 = __toESM(require("react"));
4334
4781
  var import_tooltip = require("@base-ui/react/tooltip");
4335
4782
 
4336
4783
  // src/cn.ts
@@ -4351,14 +4798,14 @@ var TooltipProvider = ({
4351
4798
  }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tooltip.Tooltip.Provider, { delay: delay ?? delayDuration, closeDelay, ...props, children });
4352
4799
  var Tooltip = import_tooltip.Tooltip.Root;
4353
4800
  var TooltipTrigger = import_tooltip.Tooltip.Trigger;
4354
- var TooltipContent = React8.forwardRef(({ className, side, align, sideOffset = 8, ...props }, ref) => {
4801
+ var TooltipContent = React9.forwardRef(({ className, side, align, sideOffset = 8, ...props }, ref) => {
4355
4802
  const container = usePortalContainer();
4356
4803
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tooltip.Tooltip.Portal, { container, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tooltip.Tooltip.Positioner, { side, align, sideOffset, className: "fixed z-[99999]", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4357
4804
  import_tooltip.Tooltip.Popup,
4358
4805
  {
4359
4806
  ref,
4360
4807
  className: cn(
4361
- "rounded-md bg-[canvas] px-2 py-1 text-xs origin-(--transform-origin) shadow-xs outline-1 outline-gray-200 transition-[transform,scale,opacity] data-starting-style:scale-90 data-starting-style:opacity-0 data-ending-style:scale-90 data-ending-style:opacity-0 data-instant:transition-none dark:shadow-none dark:outline-gray-300 dark:-outline-offset-1",
4808
+ "rounded-md bg-[canvas] px-2 py-1 text-xs origin-(--transform-origin) shadow-xs outline-1 outline-border transition-[transform,scale,opacity] data-starting-style:scale-90 data-starting-style:opacity-0 data-ending-style:scale-90 data-ending-style:opacity-0 data-instant:transition-none dark:shadow-none dark:-outline-offset-1",
4362
4809
  className
4363
4810
  ),
4364
4811
  ...props
@@ -4369,23 +4816,23 @@ TooltipContent.displayName = "TooltipContent";
4369
4816
  var createTooltipHandle = import_tooltip.Tooltip.createHandle;
4370
4817
 
4371
4818
  // src/use-measurement.ts
4372
- var React9 = __toESM(require("react"));
4819
+ var React10 = __toESM(require("react"));
4373
4820
  var INITIAL_STATE = {
4374
4821
  hoveredElement: null,
4375
4822
  measurements: []
4376
4823
  };
4377
4824
  function useMeasurement(selectedElement) {
4378
- const [altHeld, setAltHeld] = React9.useState(false);
4379
- const [state, setState] = React9.useState(INITIAL_STATE);
4380
- const [mousePosition, setMousePosition] = React9.useState(null);
4381
- const rafRef = React9.useRef(null);
4382
- const mousePositionRef = React9.useRef(null);
4383
- const getElementBelow = React9.useCallback((x, y) => {
4825
+ const [altHeld, setAltHeld] = React10.useState(false);
4826
+ const [state, setState] = React10.useState(INITIAL_STATE);
4827
+ const [mousePosition, setMousePosition] = React10.useState(null);
4828
+ const rafRef = React10.useRef(null);
4829
+ const mousePositionRef = React10.useRef(null);
4830
+ const getElementBelow = React10.useCallback((x, y) => {
4384
4831
  const element = elementFromPointWithoutOverlays(x, y);
4385
4832
  if (element?.closest("[data-direct-edit-host]")) return null;
4386
4833
  return element;
4387
4834
  }, []);
4388
- React9.useEffect(() => {
4835
+ React10.useEffect(() => {
4389
4836
  function handleKeyDown(e) {
4390
4837
  if (e.key === "Alt") {
4391
4838
  e.preventDefault();
@@ -4416,7 +4863,7 @@ function useMeasurement(selectedElement) {
4416
4863
  document.removeEventListener("visibilitychange", handleVisibilityChange);
4417
4864
  };
4418
4865
  }, []);
4419
- React9.useEffect(() => {
4866
+ React10.useEffect(() => {
4420
4867
  if (!altHeld || !selectedElement) {
4421
4868
  setState(INITIAL_STATE);
4422
4869
  return;
@@ -4475,7 +4922,7 @@ function useMeasurement(selectedElement) {
4475
4922
  }
4476
4923
 
4477
4924
  // src/measurement-overlay.tsx
4478
- var React10 = __toESM(require("react"));
4925
+ var React11 = __toESM(require("react"));
4479
4926
  var import_jsx_runtime4 = require("react/jsx-runtime");
4480
4927
  var TOMATO = "#E54D2E";
4481
4928
  var BLUE = "#0D99FF";
@@ -4552,16 +4999,18 @@ function MeasurementOverlay({
4552
4999
  hoveredElement,
4553
5000
  measurements
4554
5001
  }) {
4555
- const [, forceUpdate] = React10.useReducer((x) => x + 1, 0);
4556
- React10.useEffect(() => {
5002
+ const [, forceUpdate] = React11.useReducer((x) => x + 1, 0);
5003
+ React11.useEffect(() => {
4557
5004
  function handleUpdate() {
4558
5005
  requestAnimationFrame(forceUpdate);
4559
5006
  }
4560
5007
  window.addEventListener("scroll", handleUpdate, true);
4561
5008
  window.addEventListener("resize", handleUpdate);
5009
+ window.addEventListener("direct-edit-canvas-change", handleUpdate);
4562
5010
  return () => {
4563
5011
  window.removeEventListener("scroll", handleUpdate, true);
4564
5012
  window.removeEventListener("resize", handleUpdate);
5013
+ window.removeEventListener("direct-edit-canvas-change", handleUpdate);
4565
5014
  };
4566
5015
  }, [selectedElement]);
4567
5016
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -4586,7 +5035,7 @@ function MeasurementOverlay({
4586
5035
  }
4587
5036
 
4588
5037
  // src/use-move.ts
4589
- var React11 = __toESM(require("react"));
5038
+ var React12 = __toESM(require("react"));
4590
5039
  var INITIAL_DRAG_STATE = {
4591
5040
  isDragging: false,
4592
5041
  draggedElement: null,
@@ -4597,19 +5046,19 @@ var INITIAL_DRAG_STATE = {
4597
5046
  dragOffset: { x: 0, y: 0 }
4598
5047
  };
4599
5048
  function useMove({ onMoveComplete }) {
4600
- const [dragState, setDragState] = React11.useState(INITIAL_DRAG_STATE);
4601
- const [dropTarget, setDropTarget] = React11.useState(null);
4602
- const [dropIndicator, setDropIndicator] = React11.useState(null);
4603
- const dragStateRef = React11.useRef(dragState);
4604
- const dropTargetRef = React11.useRef(dropTarget);
4605
- const onMoveCompleteRef = React11.useRef(onMoveComplete);
4606
- const dragOptionsRef = React11.useRef({});
4607
- React11.useEffect(() => {
5049
+ const [dragState, setDragState] = React12.useState(INITIAL_DRAG_STATE);
5050
+ const [dropTarget, setDropTarget] = React12.useState(null);
5051
+ const [dropIndicator, setDropIndicator] = React12.useState(null);
5052
+ const dragStateRef = React12.useRef(dragState);
5053
+ const dropTargetRef = React12.useRef(dropTarget);
5054
+ const onMoveCompleteRef = React12.useRef(onMoveComplete);
5055
+ const dragOptionsRef = React12.useRef({});
5056
+ React12.useEffect(() => {
4608
5057
  dragStateRef.current = dragState;
4609
5058
  dropTargetRef.current = dropTarget;
4610
5059
  onMoveCompleteRef.current = onMoveComplete;
4611
5060
  });
4612
- const cancelDrag = React11.useCallback(() => {
5061
+ const cancelDrag = React12.useCallback(() => {
4613
5062
  const current = dragStateRef.current;
4614
5063
  if (current.draggedElement) {
4615
5064
  current.draggedElement.style.opacity = "";
@@ -4619,7 +5068,7 @@ function useMove({ onMoveComplete }) {
4619
5068
  setDropTarget(null);
4620
5069
  setDropIndicator(null);
4621
5070
  }, []);
4622
- const completeDrag = React11.useCallback(() => {
5071
+ const completeDrag = React12.useCallback(() => {
4623
5072
  const current = dragStateRef.current;
4624
5073
  const target = dropTargetRef.current;
4625
5074
  const { draggedElement, originalParent, originalPreviousSibling, originalNextSibling } = current;
@@ -4653,7 +5102,7 @@ function useMove({ onMoveComplete }) {
4653
5102
  onMoveCompleteRef.current(draggedElement, moveInfo);
4654
5103
  }
4655
5104
  }, [cancelDrag]);
4656
- const startDrag = React11.useCallback(
5105
+ const startDrag = React12.useCallback(
4657
5106
  (e, element, options) => {
4658
5107
  const rect = element.getBoundingClientRect();
4659
5108
  const parent = element.parentElement;
@@ -4673,7 +5122,7 @@ function useMove({ onMoveComplete }) {
4673
5122
  },
4674
5123
  []
4675
5124
  );
4676
- React11.useEffect(() => {
5125
+ React12.useEffect(() => {
4677
5126
  if (!dragState.isDragging) return;
4678
5127
  function handlePointerMove(e) {
4679
5128
  const current = dragStateRef.current;
@@ -4741,7 +5190,46 @@ function useMove({ onMoveComplete }) {
4741
5190
  }
4742
5191
 
4743
5192
  // src/use-guidelines.ts
4744
- var React12 = __toESM(require("react"));
5193
+ var React13 = __toESM(require("react"));
5194
+
5195
+ // src/utils/snap-targets.ts
5196
+ var SNAP_THRESHOLD_PX = 6;
5197
+ function collectSnapTargets(orientation) {
5198
+ const edges = [];
5199
+ const elements = document.body.querySelectorAll("*");
5200
+ const viewportW = window.innerWidth;
5201
+ const viewportH = window.innerHeight;
5202
+ for (let i = 0; i < elements.length; i++) {
5203
+ const el = elements[i];
5204
+ if (el === document.body || el === document.documentElement) continue;
5205
+ if (el.closest("[data-direct-edit]") || el.closest("[data-direct-edit-host]")) continue;
5206
+ if (el.offsetParent === null && el !== document.body) continue;
5207
+ const rect = el.getBoundingClientRect();
5208
+ if (rect.width < 4 || rect.height < 4) continue;
5209
+ if (rect.right < -200 || rect.bottom < -200 || rect.left > viewportW + 200 || rect.top > viewportH + 200) continue;
5210
+ if (orientation === "horizontal") {
5211
+ edges.push(rect.top, rect.bottom);
5212
+ } else {
5213
+ edges.push(rect.left, rect.right);
5214
+ }
5215
+ if (edges.length >= 2e3) break;
5216
+ }
5217
+ return edges;
5218
+ }
5219
+ function findSnap(viewportPos, snapEdges, threshold) {
5220
+ let best = null;
5221
+ let bestDist = threshold + 1;
5222
+ for (let i = 0; i < snapEdges.length; i++) {
5223
+ const dist = Math.abs(snapEdges[i] - viewportPos);
5224
+ if (dist < bestDist) {
5225
+ bestDist = dist;
5226
+ best = snapEdges[i];
5227
+ }
5228
+ }
5229
+ return bestDist <= threshold ? best : null;
5230
+ }
5231
+
5232
+ // src/use-guidelines.ts
4745
5233
  var STORAGE_KEY = "direct-edit-guidelines";
4746
5234
  function isGuidelineOrientation(value) {
4747
5235
  return value === "horizontal" || value === "vertical";
@@ -4778,6 +5266,7 @@ function generateId() {
4778
5266
  return `gl-${Date.now()}-${idCounter++}`;
4779
5267
  }
4780
5268
  var RULER_SIZE = 20;
5269
+ var SNAP_VELOCITY_THRESHOLD = 3;
4781
5270
  function viewportToCssCoord(hostElement, value, axis) {
4782
5271
  if (!hostElement) return value;
4783
5272
  const rect = hostElement.getBoundingClientRect();
@@ -4787,68 +5276,108 @@ function viewportToCssCoord(hostElement, value, axis) {
4787
5276
  if (size === 0) return value;
4788
5277
  return (value - origin) * (cssSize / size);
4789
5278
  }
4790
- function useGuidelines(enabled, hostElement) {
4791
- const [guidelines, setGuidelines] = React12.useState([]);
4792
- const [hydrated, setHydrated] = React12.useState(false);
4793
- const [activeGuidelineId, setActiveGuidelineId] = React12.useState(null);
4794
- const [dragPosition, setDragPosition] = React12.useState(null);
4795
- const [isCreating, setIsCreating] = React12.useState(false);
4796
- const [scrollOffset, setScrollOffset] = React12.useState({ x: 0, y: 0 });
4797
- const hostRef = React12.useRef(hostElement ?? null);
5279
+ function useGuidelines(enabled, hostElement, canvas) {
5280
+ const [guidelines, setGuidelines] = React13.useState([]);
5281
+ const [hydrated, setHydrated] = React13.useState(false);
5282
+ const [activeGuidelineId, setActiveGuidelineId] = React13.useState(null);
5283
+ const [dragPosition, setDragPosition] = React13.useState(null);
5284
+ const [isCreating, setIsCreating] = React13.useState(false);
5285
+ const [scrollOffset, setScrollOffset] = React13.useState({ x: 0, y: 0 });
5286
+ const hostRef = React13.useRef(hostElement ?? null);
4798
5287
  hostRef.current = hostElement ?? null;
4799
- const [dragging, setDragging] = React12.useState(false);
4800
- const guidelinesRef = React12.useRef(guidelines);
5288
+ const canvasRef = React13.useRef(canvas);
5289
+ canvasRef.current = canvas;
5290
+ const [dragging, setDragging] = React13.useState(false);
5291
+ const guidelinesRef = React13.useRef(guidelines);
4801
5292
  guidelinesRef.current = guidelines;
4802
- const dragInfoRef = React12.useRef(null);
4803
- React12.useEffect(() => {
5293
+ const dragInfoRef = React13.useRef(null);
5294
+ const snapTargetsRef = React13.useRef([]);
5295
+ const isSnappedRef = React13.useRef(false);
5296
+ const [isSnapped, setIsSnapped] = React13.useState(false);
5297
+ React13.useEffect(() => {
4804
5298
  setGuidelines(loadGuidelines());
4805
5299
  setHydrated(true);
4806
5300
  }, []);
4807
- React12.useEffect(() => {
5301
+ React13.useEffect(() => {
4808
5302
  if (!hydrated) return;
4809
5303
  saveGuidelines(guidelines);
4810
5304
  }, [guidelines, hydrated]);
4811
- React12.useEffect(() => {
5305
+ React13.useEffect(() => {
4812
5306
  if (!enabled) return;
4813
5307
  function update() {
4814
- setScrollOffset({ x: window.scrollX, y: window.scrollY });
5308
+ setScrollOffset((prev) => {
5309
+ const x = window.scrollX;
5310
+ const y = window.scrollY;
5311
+ return prev.x === x && prev.y === y ? prev : { x, y };
5312
+ });
4815
5313
  }
4816
5314
  update();
4817
5315
  window.addEventListener("scroll", update, true);
4818
5316
  window.addEventListener("resize", update);
5317
+ window.addEventListener("direct-edit-canvas-change", update);
4819
5318
  return () => {
4820
5319
  window.removeEventListener("scroll", update, true);
4821
5320
  window.removeEventListener("resize", update);
5321
+ window.removeEventListener("direct-edit-canvas-change", update);
4822
5322
  };
4823
5323
  }, [enabled]);
4824
- const endDrag = React12.useCallback(() => {
5324
+ const endDrag = React13.useCallback(() => {
4825
5325
  const wasCreating = dragInfoRef.current?.isCreating ?? false;
4826
5326
  dragInfoRef.current = null;
5327
+ snapTargetsRef.current = [];
5328
+ isSnappedRef.current = false;
5329
+ setIsSnapped(false);
4827
5330
  setDragging(false);
4828
5331
  setActiveGuidelineId(null);
4829
5332
  setDragPosition(null);
4830
5333
  if (wasCreating) setIsCreating(false);
4831
5334
  }, []);
4832
- React12.useEffect(() => {
5335
+ React13.useEffect(() => {
4833
5336
  if (!dragging) return;
4834
5337
  const info = dragInfoRef.current;
4835
5338
  if (!info) return;
4836
5339
  const { guidelineId, orientation } = info;
4837
5340
  const axis = orientation === "horizontal" ? "y" : "x";
4838
- function pointerToPos(e) {
4839
- const raw = orientation === "horizontal" ? e.clientY : e.clientX;
4840
- return viewportToCssCoord(hostRef.current, raw, axis);
4841
- }
5341
+ let lastPos = NaN;
5342
+ let lastTime = 0;
4842
5343
  function onPointerMove(e) {
4843
- const pos = pointerToPos(e);
5344
+ const rawViewportPos = orientation === "horizontal" ? e.clientY : e.clientX;
5345
+ const now = performance.now();
5346
+ const dt = now - lastTime;
5347
+ const velocity = dt > 0 && !Number.isNaN(lastPos) ? Math.abs(rawViewportPos - lastPos) / dt : 0;
5348
+ lastPos = rawViewportPos;
5349
+ lastTime = now;
5350
+ let effectiveViewportPos = rawViewportPos;
5351
+ let snapped = false;
5352
+ if (velocity < SNAP_VELOCITY_THRESHOLD) {
5353
+ const snapResult = findSnap(rawViewportPos, snapTargetsRef.current, SNAP_THRESHOLD_PX);
5354
+ if (snapResult !== null) {
5355
+ effectiveViewportPos = snapResult;
5356
+ snapped = true;
5357
+ }
5358
+ }
5359
+ isSnappedRef.current = snapped;
5360
+ setIsSnapped(snapped);
5361
+ const pos = viewportToCssCoord(hostRef.current, effectiveViewportPos, axis);
4844
5362
  setDragPosition(pos);
4845
- const currentScroll = orientation === "horizontal" ? window.scrollY : window.scrollX;
5363
+ const c = canvasRef.current;
5364
+ let storedPosition;
5365
+ if (c?.active) {
5366
+ const pan = orientation === "horizontal" ? c.panY || 0 : c.panX || 0;
5367
+ const bo = orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
5368
+ storedPosition = bo + (pos - bo) / (c.zoom || 1) - pan;
5369
+ } else {
5370
+ const currentScroll = orientation === "horizontal" ? window.scrollY : window.scrollX;
5371
+ storedPosition = pos + currentScroll;
5372
+ }
4846
5373
  setGuidelines(
4847
- (prev) => prev.map((g) => g.id === guidelineId ? { ...g, position: pos + currentScroll } : g)
5374
+ (prev) => prev.map((g) => g.id === guidelineId ? { ...g, position: storedPosition } : g)
4848
5375
  );
4849
5376
  }
4850
5377
  function onPointerUp(e) {
4851
- const pos = pointerToPos(e);
5378
+ const rawViewportPos = orientation === "horizontal" ? e.clientY : e.clientX;
5379
+ const snapResult = findSnap(rawViewportPos, snapTargetsRef.current, SNAP_THRESHOLD_PX);
5380
+ const pos = viewportToCssCoord(hostRef.current, snapResult ?? rawViewportPos, axis);
4852
5381
  if (pos <= RULER_SIZE) {
4853
5382
  setGuidelines((prev) => prev.filter((g) => g.id !== guidelineId));
4854
5383
  }
@@ -4861,22 +5390,32 @@ function useGuidelines(enabled, hostElement) {
4861
5390
  window.removeEventListener("pointerup", onPointerUp);
4862
5391
  };
4863
5392
  }, [dragging, endDrag]);
4864
- React12.useEffect(() => {
5393
+ React13.useEffect(() => {
4865
5394
  if (!enabled && dragging) {
4866
5395
  endDrag();
4867
5396
  }
4868
5397
  }, [enabled, dragging, endDrag]);
4869
- const activeGuideline = React12.useMemo(
5398
+ const activeGuideline = React13.useMemo(
4870
5399
  () => guidelines.find((g) => g.id === activeGuidelineId) ?? null,
4871
5400
  [guidelines, activeGuidelineId]
4872
5401
  );
4873
- const startCreate = React12.useCallback(
5402
+ const startCreate = React13.useCallback(
4874
5403
  (orientation, viewportPosition) => {
4875
5404
  const axis = orientation === "horizontal" ? "y" : "x";
4876
5405
  const pos = viewportToCssCoord(hostRef.current, viewportPosition, axis);
4877
- const scrollPos = orientation === "horizontal" ? window.scrollY : window.scrollX;
4878
5406
  const id = generateId();
4879
- const newGuideline = { id, orientation, position: pos + scrollPos };
5407
+ const c = canvasRef.current;
5408
+ let storedPosition;
5409
+ if (c?.active) {
5410
+ const pan = orientation === "horizontal" ? c.panY || 0 : c.panX || 0;
5411
+ const bo = orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
5412
+ storedPosition = bo + (pos - bo) / (c.zoom || 1) - pan;
5413
+ } else {
5414
+ const scrollPos = orientation === "horizontal" ? window.scrollY : window.scrollX;
5415
+ storedPosition = pos + scrollPos;
5416
+ }
5417
+ const newGuideline = { id, orientation, position: storedPosition };
5418
+ snapTargetsRef.current = collectSnapTargets(orientation);
4880
5419
  setGuidelines((prev) => [...prev, newGuideline]);
4881
5420
  setActiveGuidelineId(id);
4882
5421
  setDragPosition(pos);
@@ -4886,19 +5425,29 @@ function useGuidelines(enabled, hostElement) {
4886
5425
  },
4887
5426
  []
4888
5427
  );
4889
- const startDrag = React12.useCallback((guidelineId) => {
5428
+ const startDrag = React13.useCallback((guidelineId) => {
4890
5429
  const guideline = guidelinesRef.current.find((g) => g.id === guidelineId);
4891
5430
  if (!guideline) return;
4892
- const scrollPos = guideline.orientation === "horizontal" ? window.scrollY : window.scrollX;
5431
+ snapTargetsRef.current = collectSnapTargets(guideline.orientation);
5432
+ const c = canvasRef.current;
5433
+ let viewportPos;
5434
+ if (c?.active) {
5435
+ const pan = guideline.orientation === "horizontal" ? c.panY || 0 : c.panX || 0;
5436
+ const bo = guideline.orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
5437
+ viewportPos = bo + (guideline.position - bo + pan) * (c.zoom || 1);
5438
+ } else {
5439
+ const scrollPos = guideline.orientation === "horizontal" ? window.scrollY : window.scrollX;
5440
+ viewportPos = guideline.position - scrollPos;
5441
+ }
4893
5442
  setActiveGuidelineId(guidelineId);
4894
- setDragPosition(guideline.position - scrollPos);
5443
+ setDragPosition(viewportPos);
4895
5444
  dragInfoRef.current = { guidelineId, orientation: guideline.orientation, isCreating: false };
4896
5445
  setDragging(true);
4897
5446
  }, []);
4898
- const deleteGuideline = React12.useCallback((guidelineId) => {
5447
+ const deleteGuideline = React13.useCallback((guidelineId) => {
4899
5448
  setGuidelines((prev) => prev.filter((g) => g.id !== guidelineId));
4900
5449
  }, []);
4901
- const clearAll = React12.useCallback(() => {
5450
+ const clearAll = React13.useCallback(() => {
4902
5451
  setGuidelines([]);
4903
5452
  }, []);
4904
5453
  return {
@@ -4906,6 +5455,7 @@ function useGuidelines(enabled, hostElement) {
4906
5455
  activeGuideline,
4907
5456
  dragPosition,
4908
5457
  isCreating,
5458
+ isSnapped,
4909
5459
  scrollOffset,
4910
5460
  startCreate,
4911
5461
  startDrag,
@@ -4960,10 +5510,8 @@ function InteractionOverlay({
4960
5510
  if (activeTool === "comment") {
4961
5511
  if (hasPendingCommentDraft()) return;
4962
5512
  const elementUnder2 = elementFromPointWithoutOverlays(e.clientX, e.clientY);
4963
- if (elementUnder2 && elementUnder2 !== document.body && elementUnder2 !== document.documentElement) {
4964
- const resolved = resolveElementTarget(elementUnder2, selectedElement);
4965
- onAddComment(resolved, { x: e.clientX, y: e.clientY });
4966
- }
5513
+ const target = elementUnder2 && elementUnder2 !== document.body && elementUnder2 !== document.documentElement ? resolveElementTarget(elementUnder2, selectedElement) : document.body;
5514
+ onAddComment(target, { x: e.clientX, y: e.clientY });
4967
5515
  return;
4968
5516
  }
4969
5517
  if (activeCommentId) {
@@ -4981,39 +5529,41 @@ function InteractionOverlay({
4981
5529
  hoverHighlight && (() => {
4982
5530
  const cr = hoverHighlight.flexContainer.getBoundingClientRect();
4983
5531
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
4984
- "svg",
5532
+ "div",
4985
5533
  {
4986
5534
  "data-direct-edit": "hover-highlight",
4987
5535
  className: "pointer-events-none fixed inset-0 z-[99991]",
4988
- width: "100%",
4989
- height: "100%",
4990
- style: { width: "100vw", height: "100vh" },
4991
5536
  children: [
4992
5537
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4993
- "rect",
5538
+ "div",
4994
5539
  {
4995
- x: cr.left,
4996
- y: cr.top,
4997
- width: cr.width,
4998
- height: cr.height,
4999
- fill: "transparent",
5000
- stroke: "#3b82f6",
5001
- strokeWidth: 1
5540
+ style: {
5541
+ position: "absolute",
5542
+ left: cr.left,
5543
+ top: cr.top,
5544
+ width: cr.width,
5545
+ height: cr.height,
5546
+ border: "1px solid #3b82f6",
5547
+ borderRadius: "0px",
5548
+ boxSizing: "border-box"
5549
+ }
5002
5550
  }
5003
5551
  ),
5004
5552
  hoverHighlight.children.map((child) => {
5005
5553
  const r = child.getBoundingClientRect();
5006
5554
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5007
- "rect",
5555
+ "div",
5008
5556
  {
5009
- x: r.left,
5010
- y: r.top,
5011
- width: r.width,
5012
- height: r.height,
5013
- fill: "transparent",
5014
- stroke: "#3b82f6",
5015
- strokeWidth: 1,
5016
- strokeDasharray: "4 2"
5557
+ style: {
5558
+ position: "absolute",
5559
+ left: r.left,
5560
+ top: r.top,
5561
+ width: r.width,
5562
+ height: r.height,
5563
+ border: "1px dashed #3b82f6",
5564
+ borderRadius: "0px",
5565
+ boxSizing: "border-box"
5566
+ }
5017
5567
  },
5018
5568
  `${r.left}-${r.top}-${r.width}-${r.height}`
5019
5569
  );
@@ -5059,7 +5609,7 @@ function MoveOverlay({ dropIndicator }) {
5059
5609
  }
5060
5610
 
5061
5611
  // src/selection-overlay.tsx
5062
- var React13 = __toESM(require("react"));
5612
+ var React14 = __toESM(require("react"));
5063
5613
  var import_jsx_runtime7 = require("react/jsx-runtime");
5064
5614
  var BLUE3 = "#0D99FF";
5065
5615
  var MAGENTA = "#E11BB6";
@@ -5073,23 +5623,25 @@ function SelectionOverlay({
5073
5623
  ghostPosition,
5074
5624
  onMoveStart,
5075
5625
  showMoveHandle = false,
5626
+ activeTool = "select",
5076
5627
  isTextEditing,
5077
5628
  onDoubleClick,
5078
5629
  onHoverElement,
5079
5630
  onClickThrough
5080
5631
  }) {
5081
5632
  const rectElement = isDragging && draggedElement ? draggedElement : selectedElement;
5082
- const [rect, setRect] = React13.useState(() => rectElement.getBoundingClientRect());
5083
- const [moveHandleRects, setMoveHandleRects] = React13.useState([]);
5084
- const cleanupRef = React13.useRef(null);
5085
- const clickThroughTimerRef = React13.useRef(null);
5086
- React13.useEffect(() => {
5633
+ const [rect, setRect] = React14.useState(() => rectElement.getBoundingClientRect());
5634
+ const [moveHandleRects, setMoveHandleRects] = React14.useState([]);
5635
+ const cleanupRef = React14.useRef(null);
5636
+ const clickThroughTimerRef = React14.useRef(null);
5637
+ React14.useEffect(() => {
5087
5638
  function updateRect() {
5088
5639
  setRect(rectElement.getBoundingClientRect());
5089
5640
  }
5090
5641
  updateRect();
5091
5642
  window.addEventListener("scroll", updateRect, true);
5092
5643
  window.addEventListener("resize", updateRect);
5644
+ window.addEventListener("direct-edit-canvas-change", updateRect);
5093
5645
  const observer = new MutationObserver(updateRect);
5094
5646
  observer.observe(rectElement, {
5095
5647
  attributes: true,
@@ -5099,10 +5651,11 @@ function SelectionOverlay({
5099
5651
  return () => {
5100
5652
  window.removeEventListener("scroll", updateRect, true);
5101
5653
  window.removeEventListener("resize", updateRect);
5654
+ window.removeEventListener("direct-edit-canvas-change", updateRect);
5102
5655
  observer.disconnect();
5103
5656
  };
5104
5657
  }, [rectElement]);
5105
- React13.useEffect(() => {
5658
+ React14.useEffect(() => {
5106
5659
  return () => {
5107
5660
  cleanupRef.current?.();
5108
5661
  if (clickThroughTimerRef.current) clearTimeout(clickThroughTimerRef.current);
@@ -5163,7 +5716,7 @@ function SelectionOverlay({
5163
5716
  const handleMouseLeave = () => {
5164
5717
  onHoverElement?.(null);
5165
5718
  };
5166
- const getMoveHandleTargets = React13.useCallback(() => {
5719
+ const getMoveHandleTargets = React14.useCallback(() => {
5167
5720
  if (!showMoveHandle) return [];
5168
5721
  const selectedDisplay = window.getComputedStyle(selectedElement).display;
5169
5722
  const selectedIsFlexContainer = selectedDisplay === "flex" || selectedDisplay === "inline-flex";
@@ -5188,7 +5741,7 @@ function SelectionOverlay({
5188
5741
  }
5189
5742
  return [target];
5190
5743
  }, [selectedElement, showMoveHandle]);
5191
- React13.useEffect(() => {
5744
+ React14.useEffect(() => {
5192
5745
  if (!showMoveHandle || isDragging || isTextEditing) {
5193
5746
  setMoveHandleRects([]);
5194
5747
  return;
@@ -5228,30 +5781,22 @@ function SelectionOverlay({
5228
5781
  const displayX = isDragging && ghostPosition ? ghostPosition.x : rect.left;
5229
5782
  const displayY = isDragging && ghostPosition ? ghostPosition.y : rect.top;
5230
5783
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
5231
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5232
- "svg",
5784
+ !isTextEditing && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5785
+ "div",
5233
5786
  {
5234
5787
  "data-direct-edit": "selection-overlay",
5235
5788
  style: {
5236
5789
  position: "fixed",
5237
- inset: 0,
5238
- width: "100vw",
5239
- height: "100vh",
5790
+ left: displayX,
5791
+ top: displayY,
5792
+ width: rect.width,
5793
+ height: rect.height,
5240
5794
  pointerEvents: "none",
5241
- zIndex: 99996
5242
- },
5243
- children: !isTextEditing && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5244
- "rect",
5245
- {
5246
- x: displayX,
5247
- y: displayY,
5248
- width: rect.width,
5249
- height: rect.height,
5250
- fill: "transparent",
5251
- stroke: BLUE3,
5252
- strokeWidth: 1
5253
- }
5254
- )
5795
+ zIndex: 99996,
5796
+ border: `1px solid ${BLUE3}`,
5797
+ borderRadius: "0px",
5798
+ boxSizing: "border-box"
5799
+ }
5255
5800
  }
5256
5801
  ),
5257
5802
  !isDragging && !isTextEditing && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -5266,7 +5811,7 @@ function SelectionOverlay({
5266
5811
  height: rect.height,
5267
5812
  zIndex: 99996,
5268
5813
  cursor: "default",
5269
- pointerEvents: "auto"
5814
+ pointerEvents: activeTool === "comment" ? "none" : "auto"
5270
5815
  },
5271
5816
  onPointerDown: handlePointerDown,
5272
5817
  onDoubleClick: handleDoubleClick,
@@ -5308,7 +5853,7 @@ function SelectionOverlay({
5308
5853
  }
5309
5854
 
5310
5855
  // src/comment-overlay.tsx
5311
- var React14 = __toESM(require("react"));
5856
+ var React15 = __toESM(require("react"));
5312
5857
  var import_lucide_react = require("lucide-react");
5313
5858
  var import_jsx_runtime8 = require("react/jsx-runtime");
5314
5859
  function formatRelativeTime(timestamp) {
@@ -5348,7 +5893,8 @@ function CommentOverlay({
5348
5893
  onDelete,
5349
5894
  onExport,
5350
5895
  onSendToAgent,
5351
- attentionRequest = null
5896
+ attentionRequest = null,
5897
+ draftRef
5352
5898
  }) {
5353
5899
  if (comments.length === 0) return null;
5354
5900
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: comments.map((comment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
@@ -5364,7 +5910,8 @@ function CommentOverlay({
5364
5910
  onDelete: () => onDelete(comment.id),
5365
5911
  onExport: onExport ? () => onExport(comment.id) : void 0,
5366
5912
  onSendToAgent: () => onSendToAgent(comment.id),
5367
- attentionNonce: attentionRequest?.commentId === comment.id ? attentionRequest.nonce : 0
5913
+ attentionNonce: attentionRequest?.commentId === comment.id ? attentionRequest.nonce : 0,
5914
+ draftRef: activeCommentId === comment.id ? draftRef : void 0
5368
5915
  },
5369
5916
  comment.id
5370
5917
  )) });
@@ -5380,31 +5927,34 @@ function CommentPin({
5380
5927
  onDelete,
5381
5928
  onExport,
5382
5929
  onSendToAgent,
5383
- attentionNonce
5930
+ attentionNonce,
5931
+ draftRef
5384
5932
  }) {
5385
- const [position, setPosition] = React14.useState(comment.clickPosition);
5386
- const [elementRect, setElementRect] = React14.useState(null);
5387
- const [flipHorizontal, setFlipHorizontal] = React14.useState(false);
5388
- const [flipVertical, setFlipVertical] = React14.useState(false);
5389
- React14.useEffect(() => {
5933
+ const [position, setPosition] = React15.useState(comment.clickPosition);
5934
+ const [elementRect, setElementRect] = React15.useState(null);
5935
+ const [flipHorizontal, setFlipHorizontal] = React15.useState(false);
5936
+ const [flipVertical, setFlipVertical] = React15.useState(false);
5937
+ React15.useEffect(() => {
5390
5938
  function updatePosition() {
5391
5939
  if (!comment.element.isConnected) return;
5392
5940
  const rect = comment.element.getBoundingClientRect();
5393
5941
  setPosition({
5394
- x: rect.left + comment.relativePosition.x,
5395
- y: rect.top + comment.relativePosition.y
5942
+ x: rect.left + comment.relativePosition.x * rect.width,
5943
+ y: rect.top + comment.relativePosition.y * rect.height
5396
5944
  });
5397
5945
  setElementRect(rect);
5398
5946
  }
5399
5947
  updatePosition();
5400
5948
  window.addEventListener("scroll", updatePosition, true);
5401
5949
  window.addEventListener("resize", updatePosition);
5950
+ window.addEventListener("direct-edit-canvas-change", updatePosition);
5402
5951
  return () => {
5403
5952
  window.removeEventListener("scroll", updatePosition, true);
5404
5953
  window.removeEventListener("resize", updatePosition);
5954
+ window.removeEventListener("direct-edit-canvas-change", updatePosition);
5405
5955
  };
5406
5956
  }, [comment.element, comment.relativePosition]);
5407
- React14.useEffect(() => {
5957
+ React15.useEffect(() => {
5408
5958
  if (isActive) {
5409
5959
  const hasText = comment.text !== "";
5410
5960
  const cardWidth = hasText ? 280 : 220;
@@ -5470,7 +6020,8 @@ function CommentPin({
5470
6020
  onUpdateText(text);
5471
6021
  },
5472
6022
  onCancel: onClose,
5473
- attentionNonce
6023
+ attentionNonce,
6024
+ draftRef
5474
6025
  }
5475
6026
  ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5476
6027
  CommentThread,
@@ -5497,16 +6048,17 @@ function NewCommentInput({
5497
6048
  flipVertical,
5498
6049
  onSubmit,
5499
6050
  onCancel,
5500
- attentionNonce
6051
+ attentionNonce,
6052
+ draftRef
5501
6053
  }) {
5502
- const [text, setText] = React14.useState("");
5503
- const [showError, setShowError] = React14.useState(false);
5504
- const inputRef = React14.useRef(null);
5505
- const cardRef = React14.useRef(null);
5506
- React14.useEffect(() => {
6054
+ const [text, setText] = React15.useState("");
6055
+ const [showError, setShowError] = React15.useState(false);
6056
+ const inputRef = React15.useRef(null);
6057
+ const cardRef = React15.useRef(null);
6058
+ React15.useEffect(() => {
5507
6059
  inputRef.current?.focus();
5508
6060
  }, []);
5509
- React14.useEffect(() => {
6061
+ React15.useEffect(() => {
5510
6062
  if (attentionNonce <= 0) return;
5511
6063
  setShowError(true);
5512
6064
  cardRef.current?.animate?.(
@@ -5553,7 +6105,10 @@ function NewCommentInput({
5553
6105
  ),
5554
6106
  placeholder: "Add a comment...",
5555
6107
  value: text,
5556
- onChange: (e) => setText(e.target.value),
6108
+ onChange: (e) => {
6109
+ setText(e.target.value);
6110
+ if (draftRef) draftRef.current = e.target.value;
6111
+ },
5557
6112
  onKeyDown: (e) => {
5558
6113
  e.stopPropagation();
5559
6114
  if (e.key === "Enter" && text.trim()) {
@@ -5595,15 +6150,15 @@ function CommentThread({
5595
6150
  onExport,
5596
6151
  onSendToAgent
5597
6152
  }) {
5598
- const [replyText, setReplyText] = React14.useState("");
5599
- const [copied, setCopied] = React14.useState(false);
5600
- const [sendStatus, setSendStatus] = React14.useState("idle");
5601
- const inputRef = React14.useRef(null);
5602
- const copyTimerRef = React14.useRef(null);
5603
- React14.useEffect(() => {
6153
+ const [replyText, setReplyText] = React15.useState("");
6154
+ const [copied, setCopied] = React15.useState(false);
6155
+ const [sendStatus, setSendStatus] = React15.useState("idle");
6156
+ const inputRef = React15.useRef(null);
6157
+ const copyTimerRef = React15.useRef(null);
6158
+ React15.useEffect(() => {
5604
6159
  inputRef.current?.focus();
5605
6160
  }, []);
5606
- React14.useEffect(() => {
6161
+ React15.useEffect(() => {
5607
6162
  return () => {
5608
6163
  if (copyTimerRef.current) {
5609
6164
  window.clearTimeout(copyTimerRef.current);
@@ -5791,12 +6346,12 @@ function CommentThread({
5791
6346
  }
5792
6347
 
5793
6348
  // src/panel/shared.tsx
5794
- var React16 = __toESM(require("react"));
6349
+ var React17 = __toESM(require("react"));
5795
6350
 
5796
6351
  // src/ui/input.tsx
5797
- var React15 = __toESM(require("react"));
6352
+ var React16 = __toESM(require("react"));
5798
6353
  var import_jsx_runtime9 = require("react/jsx-runtime");
5799
- var Input = React15.forwardRef(
6354
+ var Input = React16.forwardRef(
5800
6355
  ({ className, type, ...props }, ref) => {
5801
6356
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
5802
6357
  "input",
@@ -5818,8 +6373,8 @@ Input.displayName = "Input";
5818
6373
  var import_jsx_runtime10 = require("react/jsx-runtime");
5819
6374
  var selectOnFocus = (e) => e.target.select();
5820
6375
  function NumberInput({ value: propValue, onValueChange, ...props }) {
5821
- const [localValue, setLocalValue] = React16.useState(propValue === null ? "" : String(propValue));
5822
- React16.useEffect(() => {
6376
+ const [localValue, setLocalValue] = React17.useState(propValue === null ? "" : String(propValue));
6377
+ React17.useEffect(() => {
5823
6378
  setLocalValue(propValue === null ? "" : String(propValue));
5824
6379
  }, [propValue]);
5825
6380
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -5866,9 +6421,9 @@ var SECTION_LABELS = {
5866
6421
  text: "Text"
5867
6422
  };
5868
6423
  function useSectionNav(sectionRefs) {
5869
- const scrollRef = React16.useRef(null);
5870
- const [activeSection, setActiveSection] = React16.useState("layout");
5871
- React16.useEffect(() => {
6424
+ const scrollRef = React17.useRef(null);
6425
+ const [activeSection, setActiveSection] = React17.useState("layout");
6426
+ React17.useEffect(() => {
5872
6427
  const scrollEl = scrollRef.current;
5873
6428
  if (!scrollEl) return;
5874
6429
  const handleScroll = () => {
@@ -5929,10 +6484,10 @@ function SectionNav({
5929
6484
  }
5930
6485
 
5931
6486
  // src/panel/border-radius-inputs.tsx
5932
- var React19 = __toESM(require("react"));
6487
+ var React20 = __toESM(require("react"));
5933
6488
 
5934
6489
  // src/ui/button.tsx
5935
- var React17 = __toESM(require("react"));
6490
+ var React18 = __toESM(require("react"));
5936
6491
  var import_jsx_runtime11 = require("react/jsx-runtime");
5937
6492
  var buttonVariants = {
5938
6493
  base: "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
@@ -5951,7 +6506,7 @@ var buttonVariants = {
5951
6506
  icon: "h-10 w-10"
5952
6507
  }
5953
6508
  };
5954
- var Button = React17.forwardRef(
6509
+ var Button = React18.forwardRef(
5955
6510
  ({ className, variant = "default", size = "default", ...props }, ref) => {
5956
6511
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5957
6512
  "button",
@@ -5971,10 +6526,10 @@ var Button = React17.forwardRef(
5971
6526
  Button.displayName = "Button";
5972
6527
 
5973
6528
  // src/ui/slider.tsx
5974
- var React18 = __toESM(require("react"));
6529
+ var React19 = __toESM(require("react"));
5975
6530
  var import_slider = require("@base-ui/react/slider");
5976
6531
  var import_jsx_runtime12 = require("react/jsx-runtime");
5977
- var Slider = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6532
+ var Slider = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5978
6533
  import_slider.Slider.Root,
5979
6534
  {
5980
6535
  ref,
@@ -6009,7 +6564,7 @@ function RadiusCornerIcon({ corner, className }) {
6009
6564
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className: cn("size-3", className), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: paths[corner] }) });
6010
6565
  }
6011
6566
  function BorderRadiusInputs({ values, onChange }) {
6012
- const [individual, setIndividual] = React19.useState(false);
6567
+ const [individual, setIndividual] = React20.useState(false);
6013
6568
  const handleChange = (corners, numericValue) => {
6014
6569
  const newValue = {
6015
6570
  numericValue,
@@ -6142,7 +6697,7 @@ function BorderRadiusInputs({ values, onChange }) {
6142
6697
  }
6143
6698
 
6144
6699
  // src/panel/border-section.tsx
6145
- var React22 = __toESM(require("react"));
6700
+ var React23 = __toESM(require("react"));
6146
6701
 
6147
6702
  // src/ui/select.tsx
6148
6703
  var import_select = require("@base-ui/react/select");
@@ -6207,21 +6762,21 @@ function SimpleSelect({
6207
6762
  }
6208
6763
 
6209
6764
  // src/ui/color-picker.tsx
6210
- var React20 = __toESM(require("react"));
6765
+ var React21 = __toESM(require("react"));
6211
6766
  var import_popover = require("@base-ui/react/popover");
6212
6767
  var import_jsx_runtime16 = require("react/jsx-runtime");
6213
6768
  function ColorPickerPortal(props) {
6214
6769
  const container = usePortalContainer();
6215
6770
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_popover.Popover.Portal, { container, ...props });
6216
6771
  }
6217
- var ColorPickerGroupContext = React20.createContext(null);
6772
+ var ColorPickerGroupContext = React21.createContext(null);
6218
6773
  function ColorPickerGroup({ children }) {
6219
- const [activePickerId, setActivePickerId] = React20.useState(null);
6774
+ const [activePickerId, setActivePickerId] = React21.useState(null);
6220
6775
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorPickerGroupContext.Provider, { value: { activePickerId, setActivePickerId }, children });
6221
6776
  }
6222
6777
  function useDrag(onMove) {
6223
- const ref = React20.useRef(null);
6224
- const handlePointerEvent = React20.useCallback(
6778
+ const ref = React21.useRef(null);
6779
+ const handlePointerEvent = React21.useCallback(
6225
6780
  (e) => {
6226
6781
  const el = ref.current;
6227
6782
  if (!el) return;
@@ -6232,7 +6787,7 @@ function useDrag(onMove) {
6232
6787
  },
6233
6788
  [onMove]
6234
6789
  );
6235
- const onPointerDown = React20.useCallback(
6790
+ const onPointerDown = React21.useCallback(
6236
6791
  (e) => {
6237
6792
  e.preventDefault();
6238
6793
  ref.current?.setPointerCapture(e.pointerId);
@@ -6240,7 +6795,7 @@ function useDrag(onMove) {
6240
6795
  },
6241
6796
  [handlePointerEvent]
6242
6797
  );
6243
- const onPointerMove = React20.useCallback(
6798
+ const onPointerMove = React21.useCallback(
6244
6799
  (e) => {
6245
6800
  if (e.buttons === 0) return;
6246
6801
  handlePointerEvent(e);
@@ -6310,8 +6865,8 @@ function NumericInput({
6310
6865
  max,
6311
6866
  onChange
6312
6867
  }) {
6313
- const [local, setLocal] = React20.useState(Math.round(value).toString());
6314
- React20.useEffect(() => {
6868
+ const [local, setLocal] = React21.useState(Math.round(value).toString());
6869
+ React21.useEffect(() => {
6315
6870
  setLocal(Math.round(value).toString());
6316
6871
  }, [value]);
6317
6872
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-1", children: [
@@ -6333,13 +6888,13 @@ function NumericInput({
6333
6888
  ] });
6334
6889
  }
6335
6890
  function ColorPickerPopover({ id, value, onChange, children }) {
6336
- const group = React20.useContext(ColorPickerGroupContext);
6891
+ const group = React21.useContext(ColorPickerGroupContext);
6337
6892
  const rgb = hexToRgb(value.hex);
6338
6893
  const initialHsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
6339
- const [hsv, setHsv] = React20.useState({ h: initialHsv.h, s: initialHsv.s, v: initialHsv.v });
6340
- const [alpha, setAlpha] = React20.useState(value.alpha);
6341
- const lastSyncedHex = React20.useRef(value.hex);
6342
- React20.useEffect(() => {
6894
+ const [hsv, setHsv] = React21.useState({ h: initialHsv.h, s: initialHsv.s, v: initialHsv.v });
6895
+ const [alpha, setAlpha] = React21.useState(value.alpha);
6896
+ const lastSyncedHex = React21.useRef(value.hex);
6897
+ React21.useEffect(() => {
6343
6898
  if (value.hex !== lastSyncedHex.current) {
6344
6899
  const newRgb = hexToRgb(value.hex);
6345
6900
  const newHsv = rgbToHsv(newRgb.r, newRgb.g, newRgb.b);
@@ -6352,7 +6907,7 @@ function ColorPickerPopover({ id, value, onChange, children }) {
6352
6907
  }
6353
6908
  setAlpha(value.alpha);
6354
6909
  }, [value.hex, value.alpha]);
6355
- const emitChange = React20.useCallback(
6910
+ const emitChange = React21.useCallback(
6356
6911
  (h, s, v, a) => {
6357
6912
  const newRgb = hsvToRgb(h, s, v);
6358
6913
  const hex = rgbToHex(newRgb.r, newRgb.g, newRgb.b);
@@ -6433,11 +6988,11 @@ function ColorPickerPopover({ id, value, onChange, children }) {
6433
6988
  const handleOpenChange = isControlled ? (open) => {
6434
6989
  group.setActivePickerId(open ? id : null);
6435
6990
  } : void 0;
6436
- const popupRef = React20.useRef(null);
6437
- const triggerRef = React20.useRef(null);
6438
- const onCloseRef = React20.useRef();
6991
+ const popupRef = React21.useRef(null);
6992
+ const triggerRef = React21.useRef(null);
6993
+ const onCloseRef = React21.useRef();
6439
6994
  onCloseRef.current = () => group?.setActivePickerId(null);
6440
- React20.useEffect(() => {
6995
+ React21.useEffect(() => {
6441
6996
  if (!isOpen) return;
6442
6997
  function handlePointerDown(e) {
6443
6998
  const path = e.composedPath();
@@ -6507,8 +7062,8 @@ function ColorPickerPopover({ id, value, onChange, children }) {
6507
7062
  ] });
6508
7063
  }
6509
7064
  function HexInput({ value, onChange }) {
6510
- const [local, setLocal] = React20.useState(value);
6511
- React20.useEffect(() => {
7065
+ const [local, setLocal] = React21.useState(value);
7066
+ React21.useEffect(() => {
6512
7067
  setLocal(value);
6513
7068
  }, [value]);
6514
7069
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -6527,8 +7082,8 @@ function HexInput({ value, onChange }) {
6527
7082
  );
6528
7083
  }
6529
7084
  function AlphaInput({ value, onChange }) {
6530
- const [local, setLocal] = React20.useState(value.toString());
6531
- React20.useEffect(() => {
7085
+ const [local, setLocal] = React21.useState(value.toString());
7086
+ React21.useEffect(() => {
6532
7087
  setLocal(value.toString());
6533
7088
  }, [value]);
6534
7089
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -6548,13 +7103,13 @@ function AlphaInput({ value, onChange }) {
6548
7103
  }
6549
7104
 
6550
7105
  // src/panel/fill-section.tsx
6551
- var React21 = __toESM(require("react"));
7106
+ var React22 = __toESM(require("react"));
6552
7107
  var import_lucide_react4 = require("lucide-react");
6553
7108
  var import_jsx_runtime17 = require("react/jsx-runtime");
6554
7109
  function ColorInput({ id, label, icon, value, onChange }) {
6555
- const [hexInput, setHexInput] = React21.useState(value.hex);
6556
- const [alphaInput, setAlphaInput] = React21.useState(value.alpha.toString());
6557
- React21.useEffect(() => {
7110
+ const [hexInput, setHexInput] = React22.useState(value.hex);
7111
+ const [alphaInput, setAlphaInput] = React22.useState(value.alpha.toString());
7112
+ React22.useEffect(() => {
6558
7113
  setHexInput(value.hex);
6559
7114
  setAlphaInput(value.alpha.toString());
6560
7115
  }, [value.hex, value.alpha]);
@@ -6745,7 +7300,7 @@ function BorderSideIcon({ side, className }) {
6745
7300
  ] });
6746
7301
  }
6747
7302
  function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChange, onBorderColorChange, onOutlineColorChange, onSetCSS, borderPosition, borderStyleControlPreference, onPositionChange, outlineStyle, outlineWidth }) {
6748
- const [selectedSide, setSelectedSide] = React22.useState("All");
7303
+ const [selectedSide, setSelectedSide] = React23.useState("All");
6749
7304
  const isOutline = borderPosition === "outline";
6750
7305
  const activeSides = selectedSide === "All" || selectedSide === "Custom" ? BORDER_SIDES : [selectedSide];
6751
7306
  const stylesMatch = activeSides.every(
@@ -6857,7 +7412,7 @@ function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChan
6857
7412
  onValueChange: (val) => handleStyleChange(val),
6858
7413
  options: BORDER_STYLE_OPTIONS,
6859
7414
  popupMinWidth: "120px",
6860
- children: borderStyleControlPreference === "icon" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Tip, { label: `Border style: ${currentStyleLabel}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SelectTrigger, { className: "flex h-7 w-auto shrink-0 items-center justify-center rounded-md border-0 bg-muted px-2 text-xs hover:bg-muted-foreground/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Settings2, { className: "size-3.5 text-muted-foreground" }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SelectTrigger, { className: "flex h-7 flex-1 items-center justify-between rounded-md border-0 bg-muted px-2 text-xs hover:bg-muted-foreground/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: [
7415
+ children: borderStyleControlPreference === "icon" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Tip, { label: `Border style: ${currentStyleLabel}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SelectTrigger, { className: "flex h-7 w-auto shrink-0 items-center justify-center rounded-md border-0 px-2 text-xs text-muted-foreground hover:bg-muted-foreground/10 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Settings2, { className: "size-3.5" }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SelectTrigger, { className: "flex h-7 flex-1 items-center justify-between rounded-md border-0 bg-muted px-2 text-xs hover:bg-muted-foreground/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: [
6861
7416
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "flex items-center gap-1.5", children: [
6862
7417
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Square, { className: "size-3.5 text-muted-foreground" }),
6863
7418
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: currentStyleLabel })
@@ -6873,7 +7428,7 @@ function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChan
6873
7428
  onValueChange: (val) => handleSideChange(val),
6874
7429
  options: BORDER_SIDE_OPTIONS.map((side) => ({ value: side, label: side })),
6875
7430
  popupMinWidth: "90px",
6876
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Tip, { label: `Sides: ${selectedSide}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SelectTrigger, { className: "flex h-7 w-auto shrink-0 items-center justify-center rounded-md border-0 bg-muted px-2 text-xs hover:bg-muted-foreground/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: selectedSide === "Custom" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Grid2x2, { className: "size-3.5 text-muted-foreground", strokeWidth: 1 }) : selectedSide === "All" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Square, { className: "size-3.5 text-muted-foreground" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(BorderSideIcon, { side: selectedSide, className: "text-muted-foreground" }) }) })
7431
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Tip, { label: `Sides: ${selectedSide}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SelectTrigger, { className: "flex h-7 w-auto shrink-0 items-center justify-center rounded-md border-0 px-2 text-xs text-muted-foreground hover:bg-muted-foreground/10 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: selectedSide === "Custom" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Grid2x2, { className: "size-3.5 text-muted-foreground", strokeWidth: 1 }) : selectedSide === "All" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Square, { className: "size-3.5 text-muted-foreground" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(BorderSideIcon, { side: selectedSide, className: "text-muted-foreground" }) }) })
6877
7432
  }
6878
7433
  )
6879
7434
  ] }),
@@ -6893,23 +7448,27 @@ function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChan
6893
7448
  )
6894
7449
  ] }) }, side);
6895
7450
  }) }),
6896
- activeColor && activeColorChange && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6897
- ColorInput,
6898
- {
6899
- id: isOutline ? "outline-color" : "border-color",
6900
- label: isOutline ? "Outline" : "Border",
6901
- icon: isOutline ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Focus, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Square, { className: "size-3.5" }),
6902
- value: activeColor,
6903
- onChange: activeColorChange
6904
- }
6905
- )
7451
+ activeColor && activeColorChange && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1.5", children: [
7452
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7453
+ ColorInput,
7454
+ {
7455
+ id: isOutline ? "outline-color" : "border-color",
7456
+ label: isOutline ? "Outline" : "Border",
7457
+ icon: isOutline ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Focus, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Square, { className: "size-3.5" }),
7458
+ value: activeColor,
7459
+ onChange: activeColorChange
7460
+ }
7461
+ ) }),
7462
+ borderStyleControlPreference === "icon" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "w-[30px] shrink-0" }),
7463
+ !isOutline && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "w-[30px] shrink-0" })
7464
+ ] })
6906
7465
  ] });
6907
7466
  }
6908
7467
  function BorderSection({ border, borderColor, outlineColor, borderStyleControlPreference, onChange, onBatchChange, onBorderColorChange, onOutlineColorChange, onSetCSS, pendingStyles }) {
6909
7468
  const hasOutlinePending = Boolean(
6910
7469
  pendingStyles?.["outline-style"] || pendingStyles?.["outline-width"]
6911
7470
  );
6912
- const [borderPosition, setBorderPosition] = React22.useState(
7471
+ const [borderPosition, setBorderPosition] = React23.useState(
6913
7472
  hasOutlinePending ? "outline" : "border"
6914
7473
  );
6915
7474
  const isOutline = borderPosition === "outline";
@@ -7015,7 +7574,7 @@ function BorderSection({ border, borderColor, outlineColor, borderStyleControlPr
7015
7574
  }
7016
7575
 
7017
7576
  // src/panel/shadow-section.tsx
7018
- var React23 = __toESM(require("react"));
7577
+ var React24 = __toESM(require("react"));
7019
7578
 
7020
7579
  // src/shadow-utils.ts
7021
7580
  var TAILWIND_SHADOW_PRESETS = [
@@ -7152,9 +7711,9 @@ function ShadowLayerEditor({
7152
7711
  onChange,
7153
7712
  onRemoveLayer
7154
7713
  }) {
7155
- const [hexInput, setHexInput] = React23.useState(layer.color.hex);
7156
- const [alphaInput, setAlphaInput] = React23.useState(String(layer.color.alpha));
7157
- React23.useEffect(() => {
7714
+ const [hexInput, setHexInput] = React24.useState(layer.color.hex);
7715
+ const [alphaInput, setAlphaInput] = React24.useState(String(layer.color.alpha));
7716
+ React24.useEffect(() => {
7158
7717
  setHexInput(layer.color.hex);
7159
7718
  setAlphaInput(String(layer.color.alpha));
7160
7719
  }, [layer.color.hex, layer.color.alpha]);
@@ -7245,10 +7804,10 @@ function ShadowLayerEditor({
7245
7804
  }
7246
7805
  function ShadowSection({ boxShadow, onSetCSS, pendingStyles }) {
7247
7806
  const effectiveShadow = (pendingStyles?.["box-shadow"] ?? boxShadow ?? "none").trim();
7248
- const parsedLayers = React23.useMemo(() => parseShadowLayers(effectiveShadow), [effectiveShadow]);
7249
- const [layers, setLayers] = React23.useState(parsedLayers);
7807
+ const parsedLayers = React24.useMemo(() => parseShadowLayers(effectiveShadow), [effectiveShadow]);
7808
+ const [layers, setLayers] = React24.useState(parsedLayers);
7250
7809
  const hasShadow = layers.length > 0;
7251
- React23.useEffect(() => {
7810
+ React24.useEffect(() => {
7252
7811
  setLayers(parsedLayers);
7253
7812
  }, [parsedLayers]);
7254
7813
  const commitLayers = (nextLayers) => {
@@ -7540,7 +8099,7 @@ function PanelHeader({
7540
8099
  }
7541
8100
 
7542
8101
  // src/panel/panel-footer.tsx
7543
- var React24 = __toESM(require("react"));
8102
+ var React25 = __toESM(require("react"));
7544
8103
  var import_lucide_react9 = require("lucide-react");
7545
8104
  var import_jsx_runtime22 = require("react/jsx-runtime");
7546
8105
  var panelBarBaseClass2 = "flex h-11 shrink-0 items-center border-border/50 bg-background pl-3 pr-2";
@@ -7554,9 +8113,9 @@ function PanelFooter({
7554
8113
  onPointerUp,
7555
8114
  onPointerCancel
7556
8115
  }) {
7557
- const [copied, setCopied] = React24.useState(false);
7558
- const [copyError, setCopyError] = React24.useState(false);
7559
- const [sendStatus, setSendStatus] = React24.useState("idle");
8116
+ const [copied, setCopied] = React25.useState(false);
8117
+ const [copyError, setCopyError] = React25.useState(false);
8118
+ const [sendStatus, setSendStatus] = React25.useState("idle");
7560
8119
  const handleCopy = async () => {
7561
8120
  const success = await onExportEdits();
7562
8121
  if (success) {
@@ -7624,11 +8183,11 @@ function PanelFooter({
7624
8183
  }
7625
8184
 
7626
8185
  // src/panel/spacing-inputs.tsx
7627
- var React25 = __toESM(require("react"));
8186
+ var React26 = __toESM(require("react"));
7628
8187
  var import_lucide_react10 = require("lucide-react");
7629
8188
  var import_jsx_runtime23 = require("react/jsx-runtime");
7630
8189
  function SpacingInputs({ prefix, values, onChange }) {
7631
- const [individual, setIndividual] = React25.useState(false);
8190
+ const [individual, setIndividual] = React26.useState(false);
7632
8191
  const allowNegative = prefix === "margin";
7633
8192
  const handleChange = (sides, numericValue) => {
7634
8193
  const clamped = allowNegative ? numericValue : Math.max(0, numericValue);
@@ -7746,7 +8305,7 @@ function SpacingInputs({ prefix, values, onChange }) {
7746
8305
  }
7747
8306
 
7748
8307
  // src/panel/sizing-inputs.tsx
7749
- var React26 = __toESM(require("react"));
8308
+ var React27 = __toESM(require("react"));
7750
8309
  var import_lucide_react11 = require("lucide-react");
7751
8310
  var import_jsx_runtime24 = require("react/jsx-runtime");
7752
8311
  var SIZING_OPTIONS = [
@@ -7762,8 +8321,8 @@ var DISTRIBUTE_LABELS = {
7762
8321
  "space-evenly": "Evenly"
7763
8322
  };
7764
8323
  function SizingFixedInput({ value, onValueChange }) {
7765
- const [localValue, setLocalValue] = React26.useState(String(value));
7766
- React26.useEffect(() => {
8324
+ const [localValue, setLocalValue] = React27.useState(String(value));
8325
+ React27.useEffect(() => {
7767
8326
  setLocalValue(String(value));
7768
8327
  }, [value]);
7769
8328
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
@@ -7824,9 +8383,9 @@ function SizingDropdown({ label, value, onChange }) {
7824
8383
  }
7825
8384
  function SizingInputs({ width, height, onWidthChange, onHeightChange }) {
7826
8385
  const { selectedElement } = useDirectEditState();
7827
- const [locked, setLocked] = React26.useState(false);
7828
- const ratioRef = React26.useRef(1);
7829
- React26.useEffect(() => {
8386
+ const [locked, setLocked] = React27.useState(false);
8387
+ const ratioRef = React27.useRef(1);
8388
+ React27.useEffect(() => {
7830
8389
  setLocked(false);
7831
8390
  }, [selectedElement]);
7832
8391
  const canLock = width.mode === "fixed" && height.mode === "fixed" && height.value.numericValue > 0 && width.value.numericValue > 0;
@@ -8082,7 +8641,7 @@ function LayoutSection({
8082
8641
  }
8083
8642
 
8084
8643
  // src/use-panel-position.ts
8085
- var React27 = __toESM(require("react"));
8644
+ var React28 = __toESM(require("react"));
8086
8645
  var PANEL_WIDTH = 300;
8087
8646
  var PANEL_HEIGHT = 420;
8088
8647
  var STORAGE_KEY2 = "direct-edit-panel-position";
@@ -8164,14 +8723,14 @@ function getInitialPosition() {
8164
8723
  });
8165
8724
  }
8166
8725
  function usePanelPosition() {
8167
- const [position, setPosition] = React27.useState(getInitialPosition);
8168
- const [isDragging, setIsDragging] = React27.useState(false);
8169
- const [isSnapping, setIsSnapping] = React27.useState(false);
8170
- const [dragOffset, setDragOffset] = React27.useState({ x: 0, y: 0 });
8171
- const snapTimerRef = React27.useRef(null);
8172
- const panelRef = React27.useRef(null);
8173
- const positionRef = React27.useRef(position);
8174
- React27.useEffect(() => {
8726
+ const [position, setPosition] = React28.useState(getInitialPosition);
8727
+ const [isDragging, setIsDragging] = React28.useState(false);
8728
+ const [isSnapping, setIsSnapping] = React28.useState(false);
8729
+ const [dragOffset, setDragOffset] = React28.useState({ x: 0, y: 0 });
8730
+ const snapTimerRef = React28.useRef(null);
8731
+ const panelRef = React28.useRef(null);
8732
+ const positionRef = React28.useRef(position);
8733
+ React28.useEffect(() => {
8175
8734
  positionRef.current = position;
8176
8735
  }, [position]);
8177
8736
  const handlePointerDown = (e) => {
@@ -8227,7 +8786,7 @@ function usePanelPosition() {
8227
8786
  } catch {
8228
8787
  }
8229
8788
  };
8230
- React27.useEffect(() => {
8789
+ React28.useEffect(() => {
8231
8790
  function handleResize() {
8232
8791
  setPosition((prev) => {
8233
8792
  const next = snapToEdge(prev);
@@ -8238,7 +8797,7 @@ function usePanelPosition() {
8238
8797
  window.addEventListener("resize", handleResize);
8239
8798
  return () => window.removeEventListener("resize", handleResize);
8240
8799
  }, []);
8241
- React27.useEffect(() => {
8800
+ React28.useEffect(() => {
8242
8801
  return () => {
8243
8802
  if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
8244
8803
  };
@@ -8299,12 +8858,12 @@ function DirectEditPanelInner({
8299
8858
  const canTriggerSend = canSendToAgent || hasPendingChanges;
8300
8859
  const isDraggable = onHeaderPointerDown !== void 0;
8301
8860
  const sectionRefs = {
8302
- layout: React28.useRef(null),
8303
- radius: React28.useRef(null),
8304
- border: React28.useRef(null),
8305
- shadow: React28.useRef(null),
8306
- colors: React28.useRef(null),
8307
- text: React28.useRef(null)
8861
+ layout: React29.useRef(null),
8862
+ radius: React29.useRef(null),
8863
+ border: React29.useRef(null),
8864
+ shadow: React29.useRef(null),
8865
+ colors: React29.useRef(null),
8866
+ text: React29.useRef(null)
8308
8867
  };
8309
8868
  const { scrollRef, activeSection } = useSectionNav(sectionRefs);
8310
8869
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
@@ -8347,7 +8906,7 @@ function DirectEditPanelInner({
8347
8906
  sectionRefs
8348
8907
  }
8349
8908
  ),
8350
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex-1 overflow-y-auto backdrop-blur-xl bg-background/85", ref: scrollRef, children: [
8909
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex-1 overflow-y-auto backdrop-blur-xl bg-background/85", ref: scrollRef, onWheelCapture: (e) => e.stopPropagation(), children: [
8351
8910
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8352
8911
  LayoutSection,
8353
8912
  {
@@ -8502,8 +9061,12 @@ function DirectEditPanelContent() {
8502
9061
  handlePointerUp,
8503
9062
  handlePointerCancel
8504
9063
  } = usePanelPosition();
8505
- const [hoverHighlight, setHoverHighlight] = React28.useState(null);
8506
- const [commentInputAttention, setCommentInputAttention] = React28.useState(null);
9064
+ const [hoverHighlight, setHoverHighlight] = React29.useState(null);
9065
+ const [commentInputAttention, setCommentInputAttention] = React29.useState(null);
9066
+ const commentDraftRef = React29.useRef("");
9067
+ React29.useEffect(() => {
9068
+ commentDraftRef.current = "";
9069
+ }, [activeCommentId]);
8507
9070
  const { isActive: measurementActive, hoveredElement, measurements, mousePosition } = useMeasurement(
8508
9071
  isOpen ? selectedElement : null
8509
9072
  );
@@ -8514,21 +9077,29 @@ function DirectEditPanelContent() {
8514
9077
  } = useMove({
8515
9078
  onMoveComplete: handleMoveComplete
8516
9079
  });
8517
- const triggerCommentInputAttention = React28.useCallback((commentId) => {
9080
+ const triggerCommentInputAttention = React29.useCallback((commentId) => {
8518
9081
  setCommentInputAttention((prev) => prev?.commentId === commentId ? { commentId, nonce: prev.nonce + 1 } : { commentId, nonce: 1 });
8519
9082
  }, []);
8520
- const hasPendingCommentDraft = React28.useCallback((nextCommentId = null) => {
9083
+ const hasPendingCommentDraft = React29.useCallback((nextCommentId = null) => {
8521
9084
  if (!activeCommentId) return false;
8522
9085
  if (nextCommentId && nextCommentId === activeCommentId) return false;
8523
9086
  const active = comments.find((comment) => comment.id === activeCommentId);
8524
- if (!active || active.text.trim().length > 0) return false;
9087
+ if (!active) return false;
9088
+ const hasUnsentDraft = active.text.trim().length === 0 && commentDraftRef.current.trim().length > 0;
9089
+ if (!hasUnsentDraft) return false;
8525
9090
  triggerCommentInputAttention(active.id);
8526
9091
  return true;
8527
9092
  }, [activeCommentId, comments, triggerCommentInputAttention]);
8528
- const handleSetActiveComment = React28.useCallback((id) => {
8529
- if (id && hasPendingCommentDraft(id)) return;
9093
+ const handleSetActiveComment = React29.useCallback((id) => {
9094
+ if (hasPendingCommentDraft(id)) return;
9095
+ if (activeCommentId && activeCommentId !== id) {
9096
+ const active = comments.find((comment) => comment.id === activeCommentId);
9097
+ if (active && active.text.trim().length === 0) {
9098
+ deleteComment(active.id);
9099
+ }
9100
+ }
8530
9101
  setActiveCommentId(id);
8531
- }, [hasPendingCommentDraft, setActiveCommentId]);
9102
+ }, [activeCommentId, comments, hasPendingCommentDraft, deleteComment, setActiveCommentId]);
8532
9103
  const overlay = editModeActive && container ? (0, import_react_dom.createPortal)(
8533
9104
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8534
9105
  InteractionOverlay,
@@ -8541,7 +9112,7 @@ function DirectEditPanelContent() {
8541
9112
  onSelectElement: selectElement,
8542
9113
  onStartTextEditing: startTextEditing,
8543
9114
  onAddComment: addComment,
8544
- onSetActiveCommentId: setActiveCommentId,
9115
+ onSetActiveCommentId: handleSetActiveComment,
8545
9116
  onSetHoverHighlight: setHoverHighlight,
8546
9117
  hasPendingCommentDraft
8547
9118
  }
@@ -8560,7 +9131,8 @@ function DirectEditPanelContent() {
8560
9131
  onDelete: deleteComment,
8561
9132
  onExport: exportComment,
8562
9133
  onSendToAgent: sendCommentToAgent2,
8563
- attentionRequest: commentInputAttention
9134
+ attentionRequest: commentInputAttention,
9135
+ draftRef: commentDraftRef
8564
9136
  }
8565
9137
  ),
8566
9138
  container
@@ -8602,6 +9174,7 @@ function DirectEditPanelContent() {
8602
9174
  ghostPosition: dragState.ghostPosition,
8603
9175
  onMoveStart: handleMoveStart,
8604
9176
  showMoveHandle,
9177
+ activeTool,
8605
9178
  isTextEditing: Boolean(textEditingElement),
8606
9179
  onDoubleClick: (clientX, clientY) => {
8607
9180
  if (!selectedElement) return;
@@ -8707,8 +9280,8 @@ function DirectEditPanelContent() {
8707
9280
  );
8708
9281
  }
8709
9282
  function DirectEditPanel() {
8710
- const [mounted, setMounted] = React28.useState(false);
8711
- React28.useEffect(() => {
9283
+ const [mounted, setMounted] = React29.useState(false);
9284
+ React29.useEffect(() => {
8712
9285
  setMounted(true);
8713
9286
  }, []);
8714
9287
  if (!mounted) {
@@ -8718,26 +9291,59 @@ function DirectEditPanel() {
8718
9291
  }
8719
9292
 
8720
9293
  // src/toolbar.tsx
8721
- var React34 = __toESM(require("react"));
9294
+ var React36 = __toESM(require("react"));
8722
9295
  var import_react_dom3 = require("react-dom");
8723
9296
 
8724
9297
  // src/rulers-overlay.tsx
8725
- var React29 = __toESM(require("react"));
9298
+ var React30 = __toESM(require("react"));
8726
9299
  var import_react_dom2 = require("react-dom");
8727
9300
  var import_jsx_runtime28 = require("react/jsx-runtime");
8728
9301
  var RULER_SIZE2 = 20;
8729
9302
  var GUIDELINE_COLOR = "#FF6B6B";
9303
+ var SNAPPED_COLOR = "#0D99FF";
8730
9304
  var HIT_ZONE = 9;
9305
+ function computeCanvasRulerScrollOffset(pan, zoom, bodyOffset2) {
9306
+ if (zoom === 0) return -pan;
9307
+ return bodyOffset2 * (1 - 1 / zoom) - pan;
9308
+ }
9309
+ function computeTickIntervals(zoom) {
9310
+ const MIN_LABEL_SPACING_PX = 80;
9311
+ const rawInterval = MIN_LABEL_SPACING_PX / zoom;
9312
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawInterval)));
9313
+ const residual = rawInterval / magnitude;
9314
+ let nice;
9315
+ if (residual <= 1) nice = 1;
9316
+ else if (residual <= 2) nice = 2;
9317
+ else if (residual <= 2.5) nice = 2.5;
9318
+ else if (residual <= 5) nice = 5;
9319
+ else nice = 10;
9320
+ const major = nice * magnitude;
9321
+ const stepsPerMajor = 10;
9322
+ const minor = major / stepsPerMajor;
9323
+ return { major, minor, stepsPerMajor };
9324
+ }
9325
+ function getColorSchemeQuery() {
9326
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
9327
+ return null;
9328
+ }
9329
+ return window.matchMedia("(prefers-color-scheme: dark)");
9330
+ }
8731
9331
  function subscribeColorScheme(cb) {
8732
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
8733
- mq.addEventListener("change", cb);
8734
- return () => mq.removeEventListener("change", cb);
9332
+ const mq = getColorSchemeQuery();
9333
+ if (!mq) return () => {
9334
+ };
9335
+ if (typeof mq.addEventListener === "function") {
9336
+ mq.addEventListener("change", cb);
9337
+ return () => mq.removeEventListener("change", cb);
9338
+ }
9339
+ mq.addListener(cb);
9340
+ return () => mq.removeListener(cb);
8735
9341
  }
8736
9342
  function getColorScheme() {
8737
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
9343
+ return getColorSchemeQuery()?.matches ?? false;
8738
9344
  }
8739
9345
  function useSystemDark() {
8740
- return React29.useSyncExternalStore(subscribeColorScheme, getColorScheme, () => false);
9346
+ return React30.useSyncExternalStore(subscribeColorScheme, getColorScheme, () => false);
8741
9347
  }
8742
9348
  var rulerFont = {
8743
9349
  fontFamily: "system-ui, -apple-system, sans-serif",
@@ -8746,13 +9352,14 @@ var rulerFont = {
8746
9352
  };
8747
9353
  function HorizontalRuler({
8748
9354
  scrollOffset,
9355
+ zoom = 1,
8749
9356
  onPointerDown
8750
9357
  }) {
8751
- const canvasRef = React29.useRef(null);
9358
+ const canvasRef = React30.useRef(null);
8752
9359
  const viewportWidth = useViewportWidth();
8753
9360
  const { theme } = useDirectEditState();
8754
9361
  const systemDark = useSystemDark();
8755
- React29.useEffect(() => {
9362
+ React30.useEffect(() => {
8756
9363
  const canvas = canvasRef.current;
8757
9364
  if (!canvas) return;
8758
9365
  const dpr = window.devicePixelRatio || 1;
@@ -8770,12 +9377,16 @@ function HorizontalRuler({
8770
9377
  const computed = getComputedStyle(canvas);
8771
9378
  const tick = computed.getPropertyValue("color");
8772
9379
  const label = tick;
8773
- const startPx = Math.floor(scrollOffset.x / 10) * 10;
8774
- const endPx = scrollOffset.x + width;
8775
- for (let px = startPx; px <= endPx; px += 10) {
8776
- const x = px - scrollOffset.x;
8777
- const isMajor = px % 100 === 0;
8778
- const isMid = px % 50 === 0;
9380
+ const { minor, stepsPerMajor } = computeTickIntervals(zoom);
9381
+ const midIdx = stepsPerMajor / 2;
9382
+ const visibleContentWidth = width / zoom;
9383
+ const startIdx = Math.floor(scrollOffset.x / minor);
9384
+ const endIdx = Math.ceil((scrollOffset.x + visibleContentWidth) / minor);
9385
+ for (let i = startIdx; i <= endIdx; i++) {
9386
+ const px = i * minor;
9387
+ const x = (px - scrollOffset.x) * zoom;
9388
+ const isMajor = i % stepsPerMajor === 0;
9389
+ const isMid = !isMajor && i % midIdx === 0;
8779
9390
  ctx.beginPath();
8780
9391
  ctx.moveTo(x, height);
8781
9392
  ctx.lineTo(x, height - (isMajor ? 10 : isMid ? 7 : 4));
@@ -8783,15 +9394,15 @@ function HorizontalRuler({
8783
9394
  ctx.globalAlpha = 0.6;
8784
9395
  ctx.lineWidth = 1;
8785
9396
  ctx.stroke();
8786
- if (isMajor && px !== 0) {
9397
+ if (isMajor) {
8787
9398
  ctx.globalAlpha = 1;
8788
9399
  ctx.fillStyle = label;
8789
9400
  ctx.font = "9px system-ui, -apple-system, sans-serif";
8790
9401
  ctx.textAlign = "center";
8791
- ctx.fillText(String(px), x, 9);
9402
+ ctx.fillText(String(Math.round(px)), x, 9);
8792
9403
  }
8793
9404
  }
8794
- }, [scrollOffset.x, viewportWidth, theme, systemDark]);
9405
+ }, [scrollOffset.x, viewportWidth, zoom, theme, systemDark]);
8795
9406
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
8796
9407
  "div",
8797
9408
  {
@@ -8817,13 +9428,14 @@ function HorizontalRuler({
8817
9428
  }
8818
9429
  function VerticalRuler({
8819
9430
  scrollOffset,
9431
+ zoom = 1,
8820
9432
  onPointerDown
8821
9433
  }) {
8822
- const canvasRef = React29.useRef(null);
9434
+ const canvasRef = React30.useRef(null);
8823
9435
  const viewportHeight = useViewportHeight();
8824
9436
  const { theme } = useDirectEditState();
8825
9437
  const systemDark = useSystemDark();
8826
- React29.useEffect(() => {
9438
+ React30.useEffect(() => {
8827
9439
  const canvas = canvasRef.current;
8828
9440
  if (!canvas) return;
8829
9441
  const dpr = window.devicePixelRatio || 1;
@@ -8841,12 +9453,16 @@ function VerticalRuler({
8841
9453
  const computed = getComputedStyle(canvas);
8842
9454
  const tick = computed.getPropertyValue("color");
8843
9455
  const label = tick;
8844
- const startPx = Math.floor(scrollOffset.y / 10) * 10;
8845
- const endPx = scrollOffset.y + height;
8846
- for (let px = startPx; px <= endPx; px += 10) {
8847
- const y = px - scrollOffset.y;
8848
- const isMajor = px % 100 === 0;
8849
- const isMid = px % 50 === 0;
9456
+ const { minor, stepsPerMajor } = computeTickIntervals(zoom);
9457
+ const midIdx = stepsPerMajor / 2;
9458
+ const visibleContentHeight = height / zoom;
9459
+ const startIdx = Math.floor(scrollOffset.y / minor);
9460
+ const endIdx = Math.ceil((scrollOffset.y + visibleContentHeight) / minor);
9461
+ for (let i = startIdx; i <= endIdx; i++) {
9462
+ const px = i * minor;
9463
+ const y = (px - scrollOffset.y) * zoom;
9464
+ const isMajor = i % stepsPerMajor === 0;
9465
+ const isMid = !isMajor && i % midIdx === 0;
8850
9466
  ctx.beginPath();
8851
9467
  ctx.moveTo(width, y);
8852
9468
  ctx.lineTo(width - (isMajor ? 10 : isMid ? 7 : 4), y);
@@ -8854,7 +9470,7 @@ function VerticalRuler({
8854
9470
  ctx.globalAlpha = 0.6;
8855
9471
  ctx.lineWidth = 1;
8856
9472
  ctx.stroke();
8857
- if (isMajor && px !== 0) {
9473
+ if (isMajor) {
8858
9474
  ctx.save();
8859
9475
  ctx.globalAlpha = 1;
8860
9476
  ctx.fillStyle = label;
@@ -8862,11 +9478,11 @@ function VerticalRuler({
8862
9478
  ctx.textAlign = "center";
8863
9479
  ctx.translate(9, y);
8864
9480
  ctx.rotate(-Math.PI / 2);
8865
- ctx.fillText(String(px), 0, 0);
9481
+ ctx.fillText(String(Math.round(px)), 0, 0);
8866
9482
  ctx.restore();
8867
9483
  }
8868
9484
  }
8869
- }, [scrollOffset.y, viewportHeight, theme, systemDark]);
9485
+ }, [scrollOffset.y, viewportHeight, zoom, theme, systemDark]);
8870
9486
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
8871
9487
  "div",
8872
9488
  {
@@ -8910,17 +9526,26 @@ function CornerSquare() {
8910
9526
  }
8911
9527
  );
8912
9528
  }
9529
+ function computeGuidelineViewportPos(position, orientation) {
9530
+ const snap = getCanvasSnapshot();
9531
+ const zoom = snap.active ? snap.zoom : 1;
9532
+ const pan = orientation === "horizontal" ? snap.active ? snap.panY : -window.scrollY : snap.active ? snap.panX : -window.scrollX;
9533
+ if (snap.active) {
9534
+ const bo = orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
9535
+ return bo + (position - bo + pan) * zoom;
9536
+ }
9537
+ return (position + pan) * zoom;
9538
+ }
8913
9539
  function GuidelineLine({
8914
9540
  guideline,
8915
- scrollOffset,
8916
9541
  isActive,
9542
+ isSnapped,
8917
9543
  dragPosition,
8918
9544
  onStartDrag,
8919
9545
  onDelete
8920
9546
  }) {
8921
9547
  const isHorizontal = guideline.orientation === "horizontal";
8922
- const scrollPos = isHorizontal ? scrollOffset.y : scrollOffset.x;
8923
- const viewportPos = guideline.position - scrollPos;
9548
+ const lineColor = isActive && isSnapped ? SNAPPED_COLOR : GUIDELINE_COLOR;
8924
9549
  const handlePointerDown = (e) => {
8925
9550
  e.preventDefault();
8926
9551
  e.stopPropagation();
@@ -8931,119 +9556,137 @@ function GuidelineLine({
8931
9556
  e.stopPropagation();
8932
9557
  onDelete(guideline.id);
8933
9558
  };
8934
- const displayPos = isActive && dragPosition !== null ? dragPosition : viewportPos;
9559
+ const isDragging = isActive && dragPosition !== null;
9560
+ const viewportPos = isDragging ? dragPosition : computeGuidelineViewportPos(guideline.position, guideline.orientation);
9561
+ const translate = isHorizontal ? `translateY(${viewportPos}px)` : `translateX(${viewportPos}px)`;
8935
9562
  if (isHorizontal) {
8936
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
8937
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
8938
- "div",
8939
- {
8940
- "data-direct-edit": "guideline",
8941
- style: {
8942
- position: "fixed",
8943
- top: displayPos,
8944
- left: 0,
8945
- right: 0,
8946
- height: 1,
8947
- background: GUIDELINE_COLOR,
8948
- zIndex: 99993,
8949
- pointerEvents: "none"
8950
- }
8951
- }
8952
- ),
8953
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
8954
- "div",
8955
- {
8956
- style: {
8957
- position: "fixed",
8958
- top: displayPos - Math.floor(HIT_ZONE / 2),
8959
- left: RULER_SIZE2,
8960
- right: 0,
8961
- height: HIT_ZONE,
8962
- zIndex: 99993,
8963
- cursor: "ns-resize",
8964
- pointerEvents: "auto"
8965
- },
8966
- onPointerDown: handlePointerDown,
8967
- onDoubleClick: handleDoubleClick
8968
- }
8969
- ),
8970
- isActive && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
8971
- "div",
8972
- {
8973
- style: {
8974
- position: "fixed",
8975
- top: displayPos + 4,
8976
- left: RULER_SIZE2 + 4,
8977
- background: GUIDELINE_COLOR,
8978
- color: "#fff",
8979
- padding: "1px 4px",
8980
- borderRadius: 2,
8981
- zIndex: 99995,
8982
- pointerEvents: "none",
8983
- ...rulerFont
8984
- },
8985
- children: Math.round(guideline.position)
8986
- }
8987
- )
8988
- ] });
8989
- }
8990
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
8991
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9563
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
8992
9564
  "div",
8993
9565
  {
8994
- "data-direct-edit": "guideline",
9566
+ "data-gl-pos": guideline.position,
9567
+ "data-gl-orient": "h",
9568
+ ...isDragging ? { "data-gl-dragging": "" } : {},
8995
9569
  style: {
8996
9570
  position: "fixed",
8997
- left: displayPos,
8998
9571
  top: 0,
8999
- bottom: 0,
9000
- width: 1,
9001
- background: GUIDELINE_COLOR,
9572
+ left: 0,
9573
+ right: 0,
9574
+ height: 0,
9575
+ transform: translate,
9002
9576
  zIndex: 99993,
9003
9577
  pointerEvents: "none"
9004
- }
9005
- }
9006
- ),
9007
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9008
- "div",
9009
- {
9010
- style: {
9011
- position: "fixed",
9012
- left: displayPos - Math.floor(HIT_ZONE / 2),
9013
- top: RULER_SIZE2,
9014
- bottom: 0,
9015
- width: HIT_ZONE,
9016
- zIndex: 99993,
9017
- cursor: "ew-resize",
9018
- pointerEvents: "auto"
9019
9578
  },
9020
- onPointerDown: handlePointerDown,
9021
- onDoubleClick: handleDoubleClick
9022
- }
9023
- ),
9024
- isActive && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9025
- "div",
9026
- {
9027
- style: {
9028
- position: "fixed",
9029
- left: displayPos + 4,
9030
- top: RULER_SIZE2 + 4,
9031
- background: GUIDELINE_COLOR,
9032
- color: "#fff",
9033
- padding: "1px 4px",
9034
- borderRadius: 2,
9035
- zIndex: 99995,
9036
- pointerEvents: "none",
9037
- ...rulerFont
9038
- },
9039
- children: Math.round(guideline.position)
9579
+ children: [
9580
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9581
+ "div",
9582
+ {
9583
+ "data-direct-edit": "guideline",
9584
+ style: { position: "absolute", top: 0, left: 0, right: 0, height: 1, background: lineColor }
9585
+ }
9586
+ ),
9587
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9588
+ "div",
9589
+ {
9590
+ style: {
9591
+ position: "absolute",
9592
+ top: -Math.floor(HIT_ZONE / 2),
9593
+ left: RULER_SIZE2,
9594
+ right: 0,
9595
+ height: HIT_ZONE,
9596
+ cursor: "ns-resize",
9597
+ pointerEvents: "auto"
9598
+ },
9599
+ onPointerDown: handlePointerDown,
9600
+ onDoubleClick: handleDoubleClick
9601
+ }
9602
+ ),
9603
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9604
+ "div",
9605
+ {
9606
+ style: {
9607
+ position: "absolute",
9608
+ top: 4,
9609
+ left: RULER_SIZE2 + 4,
9610
+ background: lineColor,
9611
+ color: "#fff",
9612
+ padding: "1px 4px",
9613
+ borderRadius: 2,
9614
+ zIndex: 99995,
9615
+ pointerEvents: "none",
9616
+ ...rulerFont
9617
+ },
9618
+ children: Math.round(guideline.position)
9619
+ }
9620
+ )
9621
+ ]
9040
9622
  }
9041
- )
9042
- ] });
9623
+ );
9624
+ }
9625
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
9626
+ "div",
9627
+ {
9628
+ "data-gl-pos": guideline.position,
9629
+ "data-gl-orient": "v",
9630
+ ...isDragging ? { "data-gl-dragging": "" } : {},
9631
+ style: {
9632
+ position: "fixed",
9633
+ top: 0,
9634
+ left: 0,
9635
+ bottom: 0,
9636
+ width: 0,
9637
+ transform: translate,
9638
+ zIndex: 99993,
9639
+ pointerEvents: "none"
9640
+ },
9641
+ children: [
9642
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9643
+ "div",
9644
+ {
9645
+ "data-direct-edit": "guideline",
9646
+ style: { position: "absolute", left: 0, top: 0, bottom: 0, width: 1, background: lineColor }
9647
+ }
9648
+ ),
9649
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9650
+ "div",
9651
+ {
9652
+ style: {
9653
+ position: "absolute",
9654
+ left: -Math.floor(HIT_ZONE / 2),
9655
+ top: RULER_SIZE2,
9656
+ bottom: 0,
9657
+ width: HIT_ZONE,
9658
+ cursor: "ew-resize",
9659
+ pointerEvents: "auto"
9660
+ },
9661
+ onPointerDown: handlePointerDown,
9662
+ onDoubleClick: handleDoubleClick
9663
+ }
9664
+ ),
9665
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9666
+ "div",
9667
+ {
9668
+ style: {
9669
+ position: "absolute",
9670
+ left: 4,
9671
+ top: RULER_SIZE2 + 4,
9672
+ background: lineColor,
9673
+ color: "#fff",
9674
+ padding: "1px 4px",
9675
+ borderRadius: 2,
9676
+ zIndex: 99995,
9677
+ pointerEvents: "none",
9678
+ ...rulerFont
9679
+ },
9680
+ children: Math.round(guideline.position)
9681
+ }
9682
+ )
9683
+ ]
9684
+ }
9685
+ );
9043
9686
  }
9044
9687
  function useViewportWidth() {
9045
- const [width, setWidth] = React29.useState(0);
9046
- React29.useEffect(() => {
9688
+ const [width, setWidth] = React30.useState(0);
9689
+ React30.useEffect(() => {
9047
9690
  setWidth(window.innerWidth);
9048
9691
  const onResize = () => setWidth(window.innerWidth);
9049
9692
  window.addEventListener("resize", onResize);
@@ -9052,8 +9695,8 @@ function useViewportWidth() {
9052
9695
  return width;
9053
9696
  }
9054
9697
  function useViewportHeight() {
9055
- const [height, setHeight] = React29.useState(0);
9056
- React29.useEffect(() => {
9698
+ const [height, setHeight] = React30.useState(0);
9699
+ React30.useEffect(() => {
9057
9700
  setHeight(window.innerHeight);
9058
9701
  const onResize = () => setHeight(window.innerHeight);
9059
9702
  window.addEventListener("resize", onResize);
@@ -9063,7 +9706,8 @@ function useViewportHeight() {
9063
9706
  }
9064
9707
  function RulersOverlay({ enabled }) {
9065
9708
  const container = usePortalContainer();
9066
- const hostElement = React29.useMemo(() => {
9709
+ const canvas = useCanvasSnapshot();
9710
+ const hostElement = React30.useMemo(() => {
9067
9711
  if (!container) return null;
9068
9712
  const root = container.getRootNode();
9069
9713
  if (root instanceof ShadowRoot) return root.host;
@@ -9073,12 +9717,51 @@ function RulersOverlay({ enabled }) {
9073
9717
  guidelines,
9074
9718
  activeGuideline,
9075
9719
  dragPosition,
9720
+ isSnapped,
9076
9721
  scrollOffset,
9077
9722
  startCreate,
9078
9723
  startDrag,
9079
9724
  deleteGuideline
9080
- } = useGuidelines(enabled, hostElement);
9725
+ } = useGuidelines(enabled, hostElement, canvas);
9726
+ React30.useLayoutEffect(() => {
9727
+ if (!container || !enabled) return;
9728
+ const el = container;
9729
+ function updateGuidelinePositions() {
9730
+ const snap = getCanvasSnapshot();
9731
+ const zoom2 = snap.active ? snap.zoom : 1;
9732
+ const panX = snap.active ? snap.panX : -window.scrollX;
9733
+ const panY = snap.active ? snap.panY : -window.scrollY;
9734
+ const bo = getBodyOffset();
9735
+ el.querySelectorAll("[data-gl-pos]").forEach((node) => {
9736
+ if (node.hasAttribute("data-gl-dragging")) return;
9737
+ const pos = Number(node.dataset.glPos);
9738
+ const orient = node.dataset.glOrient;
9739
+ let vp;
9740
+ if (snap.active) {
9741
+ vp = orient === "h" ? bo.y + (pos - bo.y + panY) * zoom2 : bo.x + (pos - bo.x + panX) * zoom2;
9742
+ } else {
9743
+ vp = orient === "h" ? (pos + panY) * zoom2 : (pos + panX) * zoom2;
9744
+ }
9745
+ node.style.transform = orient === "h" ? `translateY(${vp}px)` : `translateX(${vp}px)`;
9746
+ });
9747
+ }
9748
+ updateGuidelinePositions();
9749
+ window.addEventListener("direct-edit-canvas-change", updateGuidelinePositions);
9750
+ window.addEventListener("scroll", updateGuidelinePositions, true);
9751
+ return () => {
9752
+ window.removeEventListener("direct-edit-canvas-change", updateGuidelinePositions);
9753
+ window.removeEventListener("scroll", updateGuidelinePositions, true);
9754
+ };
9755
+ }, [container, enabled]);
9081
9756
  if (!enabled || !container) return null;
9757
+ const zoom = canvas?.active ? canvas.zoom || 1 : 1;
9758
+ const effectiveScrollOffset = canvas?.active ? (() => {
9759
+ const bo = getBodyOffset();
9760
+ return {
9761
+ x: computeCanvasRulerScrollOffset(canvas.panX || 0, zoom, bo.x),
9762
+ y: computeCanvasRulerScrollOffset(canvas.panY || 0, zoom, bo.y)
9763
+ };
9764
+ })() : scrollOffset;
9082
9765
  const handleHorizontalPointerDown = (e) => {
9083
9766
  e.preventDefault();
9084
9767
  startCreate("horizontal", e.clientY);
@@ -9090,14 +9773,14 @@ function RulersOverlay({ enabled }) {
9090
9773
  return (0, import_react_dom2.createPortal)(
9091
9774
  /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
9092
9775
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(CornerSquare, {}),
9093
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(HorizontalRuler, { scrollOffset, onPointerDown: handleHorizontalPointerDown }),
9094
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(VerticalRuler, { scrollOffset, onPointerDown: handleVerticalPointerDown }),
9776
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(HorizontalRuler, { scrollOffset: effectiveScrollOffset, zoom, onPointerDown: handleHorizontalPointerDown }),
9777
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(VerticalRuler, { scrollOffset: effectiveScrollOffset, zoom, onPointerDown: handleVerticalPointerDown }),
9095
9778
  guidelines.map((g) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9096
9779
  GuidelineLine,
9097
9780
  {
9098
9781
  guideline: g,
9099
- scrollOffset,
9100
9782
  isActive: activeGuideline?.id === g.id,
9783
+ isSnapped: activeGuideline?.id === g.id ? isSnapped : false,
9101
9784
  dragPosition: activeGuideline?.id === g.id ? dragPosition : null,
9102
9785
  onStartDrag: startDrag,
9103
9786
  onDelete: deleteGuideline
@@ -9145,12 +9828,12 @@ function subscribeRulersVisible(listener) {
9145
9828
  };
9146
9829
  }
9147
9830
  function useRulersVisible() {
9148
- const visible = React29.useSyncExternalStore(
9831
+ const visible = React30.useSyncExternalStore(
9149
9832
  subscribeRulersVisible,
9150
9833
  () => rulersVisibleSnapshot,
9151
9834
  () => true
9152
9835
  );
9153
- const toggle = React29.useCallback(() => {
9836
+ const toggle = React30.useCallback(() => {
9154
9837
  setRulersVisible(!rulersVisibleSnapshot);
9155
9838
  }, []);
9156
9839
  return [visible, toggle];
@@ -9158,7 +9841,7 @@ function useRulersVisible() {
9158
9841
  function Rulers() {
9159
9842
  const { editModeActive } = useDirectEditState();
9160
9843
  const [rulersVisible, toggleRulers] = useRulersVisible();
9161
- React29.useEffect(() => {
9844
+ React30.useEffect(() => {
9162
9845
  if (!editModeActive) return;
9163
9846
  function handleKeyDown(e) {
9164
9847
  if (e.shiftKey && e.key === "R" && !e.metaKey && !e.ctrlKey && !e.altKey) {
@@ -9176,7 +9859,7 @@ function Rulers() {
9176
9859
  }
9177
9860
 
9178
9861
  // src/use-toolbar-dock.ts
9179
- var React30 = __toESM(require("react"));
9862
+ var React31 = __toESM(require("react"));
9180
9863
  var STORAGE_KEY3 = "direct-edit-toolbar-dock";
9181
9864
  var EDGE_MARGIN = 8;
9182
9865
  var DRAG_THRESHOLD2 = 3;
@@ -9200,21 +9883,25 @@ function getToolbarBounds(width, height) {
9200
9883
  const maxY = availableY <= 0 ? 0 : Math.max(minY, availableY - EDGE_MARGIN);
9201
9884
  return { minX, maxX, minY, maxY };
9202
9885
  }
9203
- function getDockedPosition(edge, width, height, currentX, currentY) {
9886
+ function getDockedPosition(edge, width, height) {
9204
9887
  const { minX, maxX, minY, maxY } = getToolbarBounds(width, height);
9205
- const freeX = currentX !== void 0 ? clamp(currentX, minX, maxX) : clamp((window.innerWidth - width) / 2, minX, maxX);
9206
- const freeY = currentY !== void 0 ? clamp(currentY, minY, maxY) : clamp((window.innerHeight - height) / 2, minY, maxY);
9888
+ const centerX = clamp((window.innerWidth - width) / 2, minX, maxX);
9889
+ const centerY = clamp((window.innerHeight - height) / 2, minY, maxY);
9207
9890
  switch (edge) {
9208
9891
  case "bottom":
9209
- return { x: freeX, y: maxY };
9892
+ return { x: centerX, y: maxY };
9210
9893
  case "top":
9211
- return { x: freeX, y: minY };
9894
+ return { x: centerX, y: minY };
9212
9895
  case "left":
9213
- return { x: minX, y: freeY };
9896
+ return { x: minX, y: centerY };
9214
9897
  case "right":
9215
- return { x: maxX, y: freeY };
9898
+ return { x: maxX, y: centerY };
9216
9899
  }
9217
9900
  }
9901
+ function getInitialDockedPosition(edge) {
9902
+ if (typeof window === "undefined") return { x: 0, y: 0 };
9903
+ return getDockedPosition(edge, 0, 0);
9904
+ }
9218
9905
  function getNearestEdge(centerX, centerY) {
9219
9906
  const vw = window.innerWidth;
9220
9907
  const vh = window.innerHeight;
@@ -9235,53 +9922,65 @@ function getNearestEdge(centerX, centerY) {
9235
9922
  return nearest;
9236
9923
  }
9237
9924
  function useToolbarDock(toolbarRef) {
9238
- const [dockedEdge, setDockedEdge] = React30.useState(getInitialEdge);
9239
- const [phase, setPhase] = React30.useState("docked");
9240
- const [dragPosition, setDragPosition] = React30.useState(null);
9241
- const dragOffsetRef = React30.useRef({ x: 0, y: 0 });
9242
- const dockedPosRef = React30.useRef({ x: 0, y: 0 });
9243
- const pointerStartRef = React30.useRef({ x: 0, y: 0 });
9244
- const pendingDragRef = React30.useRef(false);
9245
- const capturedElementRef = React30.useRef(null);
9246
- const snapTimerRef = React30.useRef(null);
9247
- const getDockedPos = React30.useCallback(() => {
9925
+ const [dockedEdge, setDockedEdge] = React31.useState(getInitialEdge);
9926
+ const [phase, setPhase] = React31.useState("docked");
9927
+ const [dragPosition, setDragPosition] = React31.useState(null);
9928
+ const dragOffsetRef = React31.useRef({ x: 0, y: 0 });
9929
+ const pointerStartRef = React31.useRef({ x: 0, y: 0 });
9930
+ const pendingDragRef = React31.useRef(false);
9931
+ const capturedElementRef = React31.useRef(null);
9932
+ const snapTimerRef = React31.useRef(null);
9933
+ const transitionTimerRef = React31.useRef(null);
9934
+ const transitioningRef = React31.useRef(false);
9935
+ const recalcRef = React31.useRef(null);
9936
+ const getDockedPos = React31.useCallback(() => {
9248
9937
  const el = toolbarRef.current;
9249
9938
  if (!el) return { x: 0, y: 0 };
9250
9939
  const rect = el.getBoundingClientRect();
9251
9940
  return getDockedPosition(dockedEdge, rect.width, rect.height);
9252
9941
  }, [dockedEdge, toolbarRef]);
9253
- const [dockedPos, setDockedPos] = React30.useState({ x: 0, y: 0 });
9254
- const [ready, setReady] = React30.useState(false);
9255
- React30.useEffect(() => {
9942
+ const [dockedPos, setDockedPos] = React31.useState(() => getInitialDockedPosition(dockedEdge));
9943
+ const [dockedTransitionEnabled, setDockedTransitionEnabled] = React31.useState(false);
9944
+ React31.useLayoutEffect(() => {
9256
9945
  const el = toolbarRef.current;
9257
9946
  if (!el) return;
9947
+ setDockedPos(getDockedPos());
9948
+ }, [getDockedPos, toolbarRef]);
9949
+ React31.useEffect(() => {
9258
9950
  const raf = requestAnimationFrame(() => {
9259
- const pos = getDockedPos();
9260
- dockedPosRef.current = pos;
9261
- setDockedPos(pos);
9262
- setReady(true);
9951
+ setDockedTransitionEnabled(true);
9263
9952
  });
9264
9953
  return () => cancelAnimationFrame(raf);
9265
- }, [getDockedPos, toolbarRef]);
9266
- React30.useEffect(() => {
9954
+ }, []);
9955
+ const predictSize = React31.useCallback((width, height) => {
9956
+ transitioningRef.current = true;
9957
+ setDockedPos(getDockedPosition(dockedEdge, width, height));
9958
+ if (transitionTimerRef.current) clearTimeout(transitionTimerRef.current);
9959
+ transitionTimerRef.current = setTimeout(() => {
9960
+ transitioningRef.current = false;
9961
+ transitionTimerRef.current = null;
9962
+ recalcRef.current?.();
9963
+ }, 350);
9964
+ }, [dockedEdge]);
9965
+ React31.useEffect(() => {
9267
9966
  const el = toolbarRef.current;
9268
9967
  if (!el) return;
9269
9968
  function recalc() {
9270
- if (!el) return;
9969
+ if (!el || transitioningRef.current) return;
9271
9970
  const rect = el.getBoundingClientRect();
9272
- const pos = getDockedPosition(dockedEdge, rect.width, rect.height, dockedPosRef.current.x, dockedPosRef.current.y);
9273
- dockedPosRef.current = pos;
9274
- setDockedPos(pos);
9971
+ setDockedPos(getDockedPosition(dockedEdge, rect.width, rect.height));
9275
9972
  }
9973
+ recalcRef.current = recalc;
9276
9974
  const ro = new ResizeObserver(recalc);
9277
9975
  ro.observe(el);
9278
9976
  window.addEventListener("resize", recalc);
9279
9977
  return () => {
9978
+ recalcRef.current = null;
9280
9979
  ro.disconnect();
9281
9980
  window.removeEventListener("resize", recalc);
9282
9981
  };
9283
9982
  }, [dockedEdge, toolbarRef]);
9284
- const handlePointerDown = React30.useCallback((e) => {
9983
+ const handlePointerDown = React31.useCallback((e) => {
9285
9984
  const el = toolbarRef.current;
9286
9985
  if (!el) return;
9287
9986
  const rect = el.getBoundingClientRect();
@@ -9294,7 +9993,7 @@ function useToolbarDock(toolbarRef) {
9294
9993
  } catch {
9295
9994
  }
9296
9995
  }, [toolbarRef]);
9297
- const handlePointerMove = React30.useCallback((e) => {
9996
+ const handlePointerMove = React31.useCallback((e) => {
9298
9997
  if (!pendingDragRef.current && phase !== "dragging") return;
9299
9998
  const dx = e.clientX - pointerStartRef.current.x;
9300
9999
  const dy = e.clientY - pointerStartRef.current.y;
@@ -9311,7 +10010,7 @@ function useToolbarDock(toolbarRef) {
9311
10010
  const newY = Math.max(0, e.clientY - dragOffsetRef.current.y);
9312
10011
  setDragPosition({ x: newX, y: newY });
9313
10012
  }, [phase]);
9314
- const handlePointerUp = React30.useCallback((e) => {
10013
+ const handlePointerUp = React31.useCallback((e) => {
9315
10014
  if (capturedElementRef.current) {
9316
10015
  try {
9317
10016
  capturedElementRef.current.releasePointerCapture(e.pointerId);
@@ -9331,8 +10030,6 @@ function useToolbarDock(toolbarRef) {
9331
10030
  return;
9332
10031
  }
9333
10032
  const rect = el.getBoundingClientRect();
9334
- const width = el.offsetWidth;
9335
- const height = el.offsetHeight;
9336
10033
  const centerX = rect.left + rect.width / 2;
9337
10034
  const centerY = rect.top + rect.height / 2;
9338
10035
  const newEdge = getNearestEdge(centerX, centerY);
@@ -9341,9 +10038,7 @@ function useToolbarDock(toolbarRef) {
9341
10038
  localStorage.setItem(STORAGE_KEY3, newEdge);
9342
10039
  } catch {
9343
10040
  }
9344
- const newPos = getDockedPosition(newEdge, width, height, rect.left, rect.top);
9345
- dockedPosRef.current = newPos;
9346
- setDockedPos(newPos);
10041
+ setDockedPos(getDockedPosition(newEdge, el.offsetWidth, el.offsetHeight));
9347
10042
  setPhase("snapping");
9348
10043
  setDragPosition(null);
9349
10044
  if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
@@ -9352,7 +10047,7 @@ function useToolbarDock(toolbarRef) {
9352
10047
  setPhase("docked");
9353
10048
  }, 350);
9354
10049
  }, [phase, toolbarRef]);
9355
- const handlePointerCancel = React30.useCallback((e) => {
10050
+ const handlePointerCancel = React31.useCallback((e) => {
9356
10051
  if (capturedElementRef.current) {
9357
10052
  try {
9358
10053
  capturedElementRef.current.releasePointerCapture(e.pointerId);
@@ -9366,18 +10061,16 @@ function useToolbarDock(toolbarRef) {
9366
10061
  setDragPosition(null);
9367
10062
  }
9368
10063
  }, [phase]);
9369
- React30.useEffect(() => {
10064
+ React31.useEffect(() => {
9370
10065
  return () => {
9371
10066
  if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
10067
+ if (transitionTimerRef.current) clearTimeout(transitionTimerRef.current);
9372
10068
  };
9373
10069
  }, []);
9374
10070
  const isDragging = phase === "dragging";
9375
10071
  const isSnapping = phase === "snapping";
9376
- const style = React30.useMemo(() => {
9377
- const base = {
9378
- position: "fixed",
9379
- ...!ready && { visibility: "hidden" }
9380
- };
10072
+ const style = React31.useMemo(() => {
10073
+ const base = { position: "fixed" };
9381
10074
  if (phase === "dragging" && dragPosition) {
9382
10075
  return {
9383
10076
  ...base,
@@ -9400,14 +10093,18 @@ function useToolbarDock(toolbarRef) {
9400
10093
  return {
9401
10094
  ...base,
9402
10095
  left: dockedPos.x,
9403
- top: dockedPos.y
10096
+ top: dockedPos.y,
10097
+ ...dockedTransitionEnabled && {
10098
+ transition: "left 300ms cubic-bezier(0.25, 1, 0.5, 1), top 300ms cubic-bezier(0.25, 1, 0.5, 1), box-shadow 150ms ease-out"
10099
+ }
9404
10100
  };
9405
- }, [phase, dragPosition, dockedPos, ready]);
10101
+ }, [phase, dragPosition, dockedPos, dockedTransitionEnabled]);
9406
10102
  return {
9407
10103
  dockedEdge,
9408
10104
  isDragging,
9409
10105
  isSnapping,
9410
10106
  style,
10107
+ predictSize,
9411
10108
  handlePointerDown,
9412
10109
  handlePointerMove,
9413
10110
  handlePointerUp,
@@ -9416,16 +10113,16 @@ function useToolbarDock(toolbarRef) {
9416
10113
  }
9417
10114
 
9418
10115
  // src/toolbar.tsx
9419
- var import_lucide_react15 = require("lucide-react");
10116
+ var import_lucide_react16 = require("lucide-react");
9420
10117
 
9421
10118
  // src/toolbar/edits-popover.tsx
9422
- var React32 = __toESM(require("react"));
10119
+ var React33 = __toESM(require("react"));
9423
10120
  var import_button7 = require("@base-ui/react/button");
9424
10121
  var import_popover2 = require("@base-ui/react/popover");
9425
10122
  var import_lucide_react13 = require("lucide-react");
9426
10123
 
9427
10124
  // src/ui/badge.tsx
9428
- var React31 = __toESM(require("react"));
10125
+ var React32 = __toESM(require("react"));
9429
10126
  var import_jsx_runtime29 = require("react/jsx-runtime");
9430
10127
  var badgeVariants = {
9431
10128
  base: "inline-flex items-center rounded-md border px-2 py-0.5 text-[10px] font-medium whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
@@ -9435,7 +10132,7 @@ var badgeVariants = {
9435
10132
  outline: "border-border bg-transparent text-foreground"
9436
10133
  }
9437
10134
  };
9438
- var Badge = React31.forwardRef(
10135
+ var Badge = React32.forwardRef(
9439
10136
  ({ className, variant = "default", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
9440
10137
  "div",
9441
10138
  {
@@ -9461,14 +10158,11 @@ function truncateText(value, max = 64) {
9461
10158
  if (value.length <= max) return value;
9462
10159
  return `${value.slice(0, max)}...`;
9463
10160
  }
9464
- function isWithinFocusRegion(nextTarget, ...elements) {
9465
- if (!(nextTarget instanceof Node)) return false;
9466
- return elements.some((element) => Boolean(element?.contains(nextTarget)));
9467
- }
9468
10161
  function EditsPopover({
9469
10162
  tooltipSide,
9470
10163
  sessionEditCount,
9471
- isDragging,
10164
+ isOpen,
10165
+ onOpenChange,
9472
10166
  onGetSessionItems,
9473
10167
  onExportAllEdits,
9474
10168
  onSendAllToAgents,
@@ -9476,20 +10170,18 @@ function EditsPopover({
9476
10170
  onRemoveSessionEdit,
9477
10171
  onDeleteComment
9478
10172
  }) {
9479
- const [editsOpen, setEditsOpen] = React32.useState(false);
9480
- const [copied, setCopied] = React32.useState(false);
9481
- const [sendStatus, setSendStatus] = React32.useState("idle");
9482
- const editsPopupRef = React32.useRef(null);
9483
- const editsTriggerRef = React32.useRef(null);
9484
- const editsCloseTimerRef = React32.useRef(null);
9485
- const [editsSnapshot, setEditsSnapshot] = React32.useState([]);
9486
- React32.useEffect(() => {
9487
- if (!editsOpen) return;
10173
+ const [copied, setCopied] = React33.useState(false);
10174
+ const [sendStatus, setSendStatus] = React33.useState("idle");
10175
+ const editsPopupRef = React33.useRef(null);
10176
+ const editsTriggerRef = React33.useRef(null);
10177
+ const [editsSnapshot, setEditsSnapshot] = React33.useState([]);
10178
+ React33.useEffect(() => {
10179
+ if (!isOpen) return;
9488
10180
  function handlePointerDown(e) {
9489
10181
  const path = e.composedPath();
9490
10182
  if (editsPopupRef.current && path.includes(editsPopupRef.current)) return;
9491
10183
  if (editsTriggerRef.current && path.includes(editsTriggerRef.current)) return;
9492
- setEditsOpen(false);
10184
+ onOpenChange(false);
9493
10185
  }
9494
10186
  const raf = requestAnimationFrame(() => {
9495
10187
  document.addEventListener("pointerdown", handlePointerDown);
@@ -9498,42 +10190,19 @@ function EditsPopover({
9498
10190
  cancelAnimationFrame(raf);
9499
10191
  document.removeEventListener("pointerdown", handlePointerDown);
9500
10192
  };
9501
- }, [editsOpen]);
9502
- React32.useEffect(() => {
9503
- if (editsOpen && onGetSessionItems) {
10193
+ }, [isOpen, onOpenChange]);
10194
+ React33.useEffect(() => {
10195
+ if (isOpen && onGetSessionItems) {
9504
10196
  setEditsSnapshot(onGetSessionItems());
9505
10197
  }
9506
- }, [editsOpen, onGetSessionItems]);
9507
- React32.useEffect(() => {
9508
- return () => {
9509
- if (editsCloseTimerRef.current !== null) {
9510
- window.clearTimeout(editsCloseTimerRef.current);
9511
- }
9512
- };
9513
- }, []);
9514
- React32.useEffect(() => {
9515
- if (isDragging) setEditsOpen(false);
9516
- }, [isDragging]);
9517
- const clearEditsCloseTimer = React32.useCallback(() => {
9518
- if (editsCloseTimerRef.current !== null) {
9519
- window.clearTimeout(editsCloseTimerRef.current);
9520
- editsCloseTimerRef.current = null;
9521
- }
9522
- }, []);
9523
- const scheduleEditsClose = React32.useCallback(() => {
9524
- clearEditsCloseTimer();
9525
- editsCloseTimerRef.current = window.setTimeout(() => {
9526
- setEditsOpen(false);
9527
- editsCloseTimerRef.current = null;
9528
- }, 120);
9529
- }, [clearEditsCloseTimer]);
9530
- const handleCopyAll = React32.useCallback(async () => {
10198
+ }, [isOpen, onGetSessionItems]);
10199
+ const handleCopyAll = React33.useCallback(async () => {
9531
10200
  const success = await onExportAllEdits?.();
9532
10201
  if (!success) return;
9533
10202
  setCopied(true);
9534
10203
  window.setTimeout(() => setCopied(false), 2e3);
9535
10204
  }, [onExportAllEdits]);
9536
- const handleSendAll = React32.useCallback(async () => {
10205
+ const handleSendAll = React33.useCallback(async () => {
9537
10206
  if (!onSendAllToAgents || sendStatus === "sending") return;
9538
10207
  setSendStatus("sending");
9539
10208
  let success = false;
@@ -9550,7 +10219,7 @@ function EditsPopover({
9550
10219
  setSendStatus("offline");
9551
10220
  window.setTimeout(() => setSendStatus("idle"), 2e3);
9552
10221
  }, [onSendAllToAgents, sendStatus]);
9553
- const handleCopyItem = React32.useCallback(async (item) => {
10222
+ const handleCopyItem = React33.useCallback(async (item) => {
9554
10223
  const text = item.type === "edit" ? buildSessionExport([item.edit], []) : buildSessionExport([], [item.comment]);
9555
10224
  try {
9556
10225
  await navigator.clipboard.writeText(`implement the visual edits
@@ -9561,52 +10230,33 @@ ${text}`);
9561
10230
  } catch {
9562
10231
  }
9563
10232
  }, []);
9564
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_popover2.Popover.Root, { open: editsOpen, onOpenChange: setEditsOpen, children: [
9565
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_popover2.Popover.Trigger, { ref: editsTriggerRef, render: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
9566
- "button",
9567
- {
9568
- type: "button",
9569
- className: cn(
9570
- "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
9571
- sessionEditCount > 0 || editsOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
9572
- ),
9573
- onPointerDown: (e) => e.stopPropagation(),
9574
- onPointerEnter: () => {
9575
- clearEditsCloseTimer();
9576
- setEditsOpen(true);
9577
- },
9578
- onPointerLeave: scheduleEditsClose,
9579
- onFocus: (e) => {
9580
- clearEditsCloseTimer();
9581
- if (e.currentTarget.matches(":focus-visible")) {
9582
- setEditsOpen(true);
10233
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_popover2.Popover.Root, { open: isOpen, onOpenChange, children: [
10234
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(Tooltip, { disabled: isOpen, children: [
10235
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipTrigger, { render: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_popover2.Popover.Trigger, { render: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
10236
+ "button",
10237
+ {
10238
+ ref: editsTriggerRef,
10239
+ type: "button",
10240
+ className: cn(
10241
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10242
+ sessionEditCount > 0 || isOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10243
+ ),
10244
+ onPointerDown: (e) => e.stopPropagation(),
10245
+ onClick: (e) => {
10246
+ e.preventDefault();
10247
+ e.stopPropagation();
10248
+ onOpenChange(!isOpen);
9583
10249
  }
9584
- },
9585
- onBlur: (e) => {
9586
- if (isWithinFocusRegion(e.relatedTarget, editsTriggerRef.current, editsPopupRef.current)) return;
9587
- scheduleEditsClose();
9588
- },
9589
- onClick: (e) => {
9590
- e.preventDefault();
9591
- e.stopPropagation();
9592
- clearEditsCloseTimer();
9593
- setEditsOpen((prev) => !prev);
9594
10250
  }
9595
- }
9596
- ), children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react13.Copy, { className: "size-4" }) }),
10251
+ ) }), children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react13.Copy, { className: "size-4" }) }),
10252
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipContent, { side: tooltipSide, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { children: "Export edits" }) })
10253
+ ] }),
9597
10254
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EditsPopoverPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_popover2.Popover.Positioner, { side: tooltipSide, sideOffset: 12, className: "fixed z-[99999]", style: { pointerEvents: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
9598
10255
  import_popover2.Popover.Popup,
9599
10256
  {
9600
10257
  ref: editsPopupRef,
9601
10258
  className: "w-[340px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
9602
10259
  onPointerDown: (e) => e.stopPropagation(),
9603
- onPointerEnter: clearEditsCloseTimer,
9604
- onPointerLeave: scheduleEditsClose,
9605
- onFocus: clearEditsCloseTimer,
9606
- onBlur: (e) => {
9607
- if (isWithinFocusRegion(e.relatedTarget, editsTriggerRef.current, editsPopupRef.current)) return;
9608
- scheduleEditsClose();
9609
- },
9610
10260
  children: [
9611
10261
  /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center justify-between px-3 pb-1 pt-2.5", children: [
9612
10262
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs font-medium text-foreground", children: "Copy to AI agents" }),
@@ -9737,38 +10387,200 @@ ${text}`);
9737
10387
  }
9738
10388
 
9739
10389
  // src/toolbar/settings-popover.tsx
9740
- var React33 = __toESM(require("react"));
9741
- var import_button8 = require("@base-ui/react/button");
9742
- var import_popover3 = require("@base-ui/react/popover");
10390
+ var React34 = __toESM(require("react"));
10391
+ var import_menu = require("@base-ui/react/menu");
9743
10392
  var import_lucide_react14 = require("lucide-react");
9744
10393
  var import_jsx_runtime31 = require("react/jsx-runtime");
9745
- function ThemePopoverPortal(props) {
10394
+ function SettingsMenuPortal(props) {
9746
10395
  const container = usePortalContainer();
9747
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_popover3.Popover.Portal, { container, ...props });
9748
- }
9749
- function isWithinFocusRegion2(nextTarget, ...elements) {
9750
- if (!(nextTarget instanceof Node)) return false;
9751
- return elements.some((element) => Boolean(element?.contains(nextTarget)));
10396
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_menu.Menu.Portal, { container, ...props });
9752
10397
  }
9753
10398
  function SettingsPopover({
9754
10399
  tooltipSide,
9755
10400
  theme,
9756
10401
  isMac,
9757
- isDragging,
10402
+ isOpen,
10403
+ onOpenChange,
9758
10404
  onSetTheme
9759
10405
  }) {
9760
- const [settingsOpen, setSettingsOpen] = React33.useState(false);
9761
- const settingsPopupRef = React33.useRef(null);
9762
- const settingsTriggerRef = React33.useRef(null);
9763
- const settingsCloseTimerRef = React33.useRef(null);
9764
- const popupKbdClass = "inline-flex h-5 min-w-[20px] items-center justify-center rounded-md bg-muted px-1.5 font-mono text-[10px] text-muted-foreground";
9765
- React33.useEffect(() => {
9766
- if (!settingsOpen) return;
10406
+ const settingsTriggerRef = React34.useRef(null);
10407
+ const settingsPopupRef = React34.useRef(null);
10408
+ const popupKbdClass = "inline-flex h-4 min-w-[18px] items-center justify-center rounded-[6px] bg-muted px-1 text-[9px] font-mono text-muted-foreground";
10409
+ const popupTitleClass = "flex h-8 items-center px-3 text-xs font-medium text-foreground";
10410
+ const submenuSide = tooltipSide === "left" ? "left" : "right";
10411
+ const centeredSubmenuCollision = React34.useMemo(
10412
+ () => ({ side: "flip", align: "none", fallbackAxisSide: "none" }),
10413
+ []
10414
+ );
10415
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_menu.Menu.Root, { open: isOpen, onOpenChange, modal: false, children: [
10416
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(Tooltip, { disabled: isOpen, children: [
10417
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(TooltipTrigger, { render: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_menu.Menu.Trigger, { render: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
10418
+ "button",
10419
+ {
10420
+ ref: settingsTriggerRef,
10421
+ type: "button",
10422
+ className: cn(
10423
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10424
+ isOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10425
+ ),
10426
+ onPointerDown: (e) => e.stopPropagation()
10427
+ }
10428
+ ) }), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.EllipsisVertical, { className: "size-4" }) }),
10429
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(TooltipContent, { side: tooltipSide, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: "Preferences" }) })
10430
+ ] }),
10431
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SettingsMenuPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_menu.Menu.Positioner, { side: tooltipSide, sideOffset: 12, className: "fixed z-[99999]", style: { pointerEvents: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10432
+ import_menu.Menu.Popup,
10433
+ {
10434
+ ref: settingsPopupRef,
10435
+ className: "w-[200px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
10436
+ onPointerDown: (e) => e.stopPropagation(),
10437
+ children: [
10438
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: popupTitleClass, children: "Preferences" }),
10439
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "px-1 pb-1", children: [
10440
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_menu.Menu.SubmenuRoot, { children: [
10441
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10442
+ import_menu.Menu.SubmenuTrigger,
10443
+ {
10444
+ openOnHover: false,
10445
+ className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-muted-foreground transition-colors data-[highlighted]:bg-muted/50 data-[highlighted]:text-foreground",
10446
+ children: [
10447
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Monitor, { className: "size-3.5" }),
10448
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex-1", children: "Theme" }),
10449
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ChevronRight, { className: "size-3.5" })
10450
+ ]
10451
+ }
10452
+ ),
10453
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SettingsMenuPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
10454
+ import_menu.Menu.Positioner,
10455
+ {
10456
+ anchor: settingsPopupRef,
10457
+ side: submenuSide,
10458
+ align: "center",
10459
+ sideOffset: 6,
10460
+ collisionAvoidance: centeredSubmenuCollision,
10461
+ className: "fixed z-[99999]",
10462
+ style: { pointerEvents: "auto" },
10463
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10464
+ import_menu.Menu.Popup,
10465
+ {
10466
+ className: "w-[200px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
10467
+ onPointerDown: (e) => e.stopPropagation(),
10468
+ children: [
10469
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: popupTitleClass, children: "Theme" }),
10470
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-1 pb-1", children: [
10471
+ { value: "light", label: "Light", Icon: import_lucide_react14.Sun },
10472
+ { value: "dark", label: "Dark", Icon: import_lucide_react14.Moon },
10473
+ { value: "system", label: "System", Icon: import_lucide_react14.Monitor }
10474
+ ].map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10475
+ import_menu.Menu.Item,
10476
+ {
10477
+ className: cn(
10478
+ "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs transition-colors",
10479
+ theme === value ? "bg-muted text-foreground" : "text-muted-foreground data-[highlighted]:bg-muted/50 data-[highlighted]:text-foreground"
10480
+ ),
10481
+ onClick: () => {
10482
+ onSetTheme?.(value);
10483
+ onOpenChange(false);
10484
+ },
10485
+ children: [
10486
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { className: "size-3.5" }),
10487
+ label
10488
+ ]
10489
+ },
10490
+ value
10491
+ )) })
10492
+ ]
10493
+ }
10494
+ )
10495
+ }
10496
+ ) })
10497
+ ] }),
10498
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_menu.Menu.SubmenuRoot, { children: [
10499
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10500
+ import_menu.Menu.SubmenuTrigger,
10501
+ {
10502
+ openOnHover: false,
10503
+ className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-muted-foreground transition-colors data-[highlighted]:bg-muted/50 data-[highlighted]:text-foreground",
10504
+ children: [
10505
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Keyboard, { className: "size-3.5" }),
10506
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex-1", children: "Keyboard shortcuts" }),
10507
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ChevronRight, { className: "size-3.5" })
10508
+ ]
10509
+ }
10510
+ ),
10511
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SettingsMenuPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
10512
+ import_menu.Menu.Positioner,
10513
+ {
10514
+ anchor: settingsPopupRef,
10515
+ side: submenuSide,
10516
+ align: "center",
10517
+ sideOffset: 6,
10518
+ collisionAvoidance: centeredSubmenuCollision,
10519
+ className: "fixed z-[99999]",
10520
+ style: { pointerEvents: "auto" },
10521
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10522
+ import_menu.Menu.Popup,
10523
+ {
10524
+ className: "w-[300px] rounded-xl bg-background text-[11px] outline outline-1 outline-foreground/10 shadow-lg",
10525
+ onPointerDown: (e) => e.stopPropagation(),
10526
+ children: [
10527
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex h-7 items-center px-3 text-[11px] font-medium text-foreground", children: "Keyboard Shortcuts" }),
10528
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-1 pb-1", children: [
10529
+ { label: "Toggle design mode", keys: isMac ? [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Command, { className: "size-2.5" }, "cmd"), "."] : ["Ctrl", "."] },
10530
+ { label: "Undo", keys: isMac ? [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Command, { className: "size-2.5" }, "cmd"), "Z"] : ["Ctrl", "Z"] },
10531
+ { label: "Toggle comments", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "C"] },
10532
+ { label: "Toggle rulers", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "R"] },
10533
+ { label: "Toggle canvas mode", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "Z"] },
10534
+ { label: "Hover to measure", keys: isMac ? ["Hold", /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Option, { className: "size-2.5" }, "opt")] : ["Hold", "Alt"] },
10535
+ { label: "Back / Exit", keys: ["Esc"] }
10536
+ ].map(({ label, keys }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex h-7 w-full items-center justify-between rounded-md px-2 text-[11px] text-muted-foreground", children: [
10537
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: label }),
10538
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex items-center gap-1", children: keys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("kbd", { className: popupKbdClass, children: k }, typeof k === "string" ? k : i)) })
10539
+ ] }, label)) })
10540
+ ]
10541
+ }
10542
+ )
10543
+ }
10544
+ ) })
10545
+ ] })
10546
+ ] })
10547
+ ]
10548
+ }
10549
+ ) }) })
10550
+ ] });
10551
+ }
10552
+
10553
+ // src/toolbar/zoom-popover.tsx
10554
+ var React35 = __toESM(require("react"));
10555
+ var import_button8 = require("@base-ui/react/button");
10556
+ var import_popover3 = require("@base-ui/react/popover");
10557
+ var import_lucide_react15 = require("lucide-react");
10558
+ var import_jsx_runtime32 = require("react/jsx-runtime");
10559
+ function ZoomPopoverPortal(props) {
10560
+ const container = usePortalContainer();
10561
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_popover3.Popover.Portal, { container, ...props });
10562
+ }
10563
+ function ZoomPopover({
10564
+ tooltipSide,
10565
+ canvasActive,
10566
+ canvasZoom,
10567
+ isOpen,
10568
+ onOpenChange,
10569
+ onToggleCanvas,
10570
+ onSetCanvasZoom,
10571
+ onZoomTo100,
10572
+ onFitToViewport
10573
+ }) {
10574
+ const popupRef = React35.useRef(null);
10575
+ const triggerRef = React35.useRef(null);
10576
+ const kbdClass = "inline-flex items-center justify-center rounded bg-muted px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground min-w-[20px] min-h-[18px]";
10577
+ React35.useEffect(() => {
10578
+ if (!isOpen) return;
9767
10579
  function handlePointerDown(e) {
9768
10580
  const path = e.composedPath();
9769
- if (settingsPopupRef.current && path.includes(settingsPopupRef.current)) return;
9770
- if (settingsTriggerRef.current && path.includes(settingsTriggerRef.current)) return;
9771
- setSettingsOpen(false);
10581
+ if (popupRef.current && path.includes(popupRef.current)) return;
10582
+ if (triggerRef.current && path.includes(triggerRef.current)) return;
10583
+ onOpenChange(false);
9772
10584
  }
9773
10585
  const raf = requestAnimationFrame(() => {
9774
10586
  document.addEventListener("pointerdown", handlePointerDown);
@@ -9777,121 +10589,90 @@ function SettingsPopover({
9777
10589
  cancelAnimationFrame(raf);
9778
10590
  document.removeEventListener("pointerdown", handlePointerDown);
9779
10591
  };
9780
- }, [settingsOpen]);
9781
- React33.useEffect(() => {
9782
- return () => {
9783
- if (settingsCloseTimerRef.current !== null) {
9784
- window.clearTimeout(settingsCloseTimerRef.current);
9785
- }
9786
- };
9787
- }, []);
9788
- React33.useEffect(() => {
9789
- if (isDragging) setSettingsOpen(false);
9790
- }, [isDragging]);
9791
- const clearSettingsCloseTimer = React33.useCallback(() => {
9792
- if (settingsCloseTimerRef.current !== null) {
9793
- window.clearTimeout(settingsCloseTimerRef.current);
9794
- settingsCloseTimerRef.current = null;
9795
- }
9796
- }, []);
9797
- const scheduleSettingsClose = React33.useCallback(() => {
9798
- clearSettingsCloseTimer();
9799
- settingsCloseTimerRef.current = window.setTimeout(() => {
9800
- setSettingsOpen(false);
9801
- settingsCloseTimerRef.current = null;
9802
- }, 120);
9803
- }, [clearSettingsCloseTimer]);
9804
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_popover3.Popover.Root, { open: settingsOpen, onOpenChange: setSettingsOpen, children: [
9805
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_popover3.Popover.Trigger, { ref: settingsTriggerRef, render: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
9806
- "button",
9807
- {
9808
- type: "button",
9809
- className: cn(
9810
- "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
9811
- settingsOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
9812
- ),
9813
- onPointerDown: (e) => e.stopPropagation(),
9814
- onPointerEnter: () => {
9815
- clearSettingsCloseTimer();
9816
- setSettingsOpen(true);
9817
- },
9818
- onPointerLeave: scheduleSettingsClose,
9819
- onFocus: (e) => {
9820
- clearSettingsCloseTimer();
9821
- if (e.currentTarget.matches(":focus-visible")) {
9822
- setSettingsOpen(true);
10592
+ }, [isOpen, onOpenChange]);
10593
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_popover3.Popover.Root, { open: isOpen, onOpenChange, children: [
10594
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Tooltip, { disabled: isOpen, children: [
10595
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TooltipTrigger, { render: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_popover3.Popover.Trigger, { render: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10596
+ "button",
10597
+ {
10598
+ ref: triggerRef,
10599
+ type: "button",
10600
+ className: cn(
10601
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10602
+ isOpen ? "bg-muted text-foreground" : canvasActive ? "bg-muted text-foreground hover:bg-muted/80" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10603
+ ),
10604
+ onPointerDown: (e) => e.stopPropagation(),
10605
+ onClick: (e) => {
10606
+ e.preventDefault();
10607
+ e.stopPropagation();
10608
+ onOpenChange(!isOpen);
9823
10609
  }
9824
- },
9825
- onBlur: (e) => {
9826
- if (isWithinFocusRegion2(e.relatedTarget, settingsTriggerRef.current, settingsPopupRef.current)) return;
9827
- scheduleSettingsClose();
9828
- },
9829
- onClick: (e) => {
9830
- e.preventDefault();
9831
- e.stopPropagation();
9832
- clearSettingsCloseTimer();
9833
- setSettingsOpen((prev) => !prev);
9834
10610
  }
9835
- }
9836
- ), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.EllipsisVertical, { className: "size-4" }) }),
9837
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ThemePopoverPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_popover3.Popover.Positioner, { side: tooltipSide, sideOffset: 12, className: "fixed z-[99999]", style: { pointerEvents: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10611
+ ) }), children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Maximize2, { className: "size-4" }) }),
10612
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10613
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: "Canvas mode" }),
10614
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.ArrowBigUp, { className: "size-2.5" }) }),
10615
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: "Z" })
10616
+ ] })
10617
+ ] }),
10618
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ZoomPopoverPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_popover3.Popover.Positioner, { side: tooltipSide, sideOffset: 12, className: "fixed z-[99999]", style: { pointerEvents: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
9838
10619
  import_popover3.Popover.Popup,
9839
10620
  {
9840
- ref: settingsPopupRef,
9841
- className: "w-[340px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
10621
+ ref: popupRef,
10622
+ className: "w-[180px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
9842
10623
  onPointerDown: (e) => e.stopPropagation(),
9843
- onPointerEnter: clearSettingsCloseTimer,
9844
- onPointerLeave: scheduleSettingsClose,
9845
- onFocus: clearSettingsCloseTimer,
9846
- onBlur: (e) => {
9847
- if (isWithinFocusRegion2(e.relatedTarget, settingsTriggerRef.current, settingsPopupRef.current)) return;
9848
- scheduleSettingsClose();
9849
- },
9850
- children: [
9851
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-3 pb-1 pt-2.5 text-xs font-medium text-foreground", children: "Theme" }),
9852
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-1 pb-1", children: [
9853
- { value: "light", label: "Light", Icon: import_lucide_react14.Sun },
9854
- { value: "dark", label: "Dark", Icon: import_lucide_react14.Moon },
9855
- { value: "system", label: "System", Icon: import_lucide_react14.Monitor }
9856
- ].map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10624
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "px-1 py-1", children: [
10625
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
9857
10626
  import_button8.Button,
9858
10627
  {
9859
- className: cn(
9860
- "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs transition-colors",
9861
- theme === value ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
9862
- ),
10628
+ className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground",
9863
10629
  onClick: () => {
9864
- onSetTheme?.(value);
9865
- setSettingsOpen(false);
10630
+ onZoomTo100?.();
10631
+ onOpenChange(false);
9866
10632
  },
9867
10633
  children: [
9868
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { className: "size-3.5" }),
9869
- label
10634
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Scan, { className: "size-3.5" }),
10635
+ "Actual size (100%)"
9870
10636
  ]
9871
- },
9872
- value
9873
- )) }),
9874
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "mx-2 my-1 border-t border-foreground/10" }),
9875
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-3 pb-1 pt-1.5 text-xs font-medium text-foreground", children: "Keyboard Shortcuts" }),
9876
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-1 pb-1", children: [
9877
- { label: "Toggle design mode", keys: isMac ? [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Command, { className: "size-2.5" }, "cmd"), "."] : ["Ctrl", "."] },
9878
- { label: "Undo", keys: isMac ? [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Command, { className: "size-2.5" }, "cmd"), "Z"] : ["Ctrl", "Z"] },
9879
- { label: "Toggle comments", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "C"] },
9880
- { label: "Toggle rulers", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "R"] },
9881
- { label: "Hover to measure", keys: isMac ? ["Hold", /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Option, { className: "size-2.5" }, "opt")] : ["Hold", "Alt"] },
9882
- { label: "Back / Exit", keys: ["Esc"] }
9883
- ].map(({ label, keys }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex h-8 w-full items-center justify-between rounded-md px-2 text-xs text-muted-foreground", children: [
9884
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: label }),
9885
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex items-center gap-0.5", children: keys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("kbd", { className: popupKbdClass, children: k }, typeof k === "string" ? k : i)) })
9886
- ] }, label)) })
9887
- ]
10637
+ }
10638
+ ),
10639
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
10640
+ import_button8.Button,
10641
+ {
10642
+ className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground",
10643
+ onClick: () => {
10644
+ onFitToViewport?.();
10645
+ onOpenChange(false);
10646
+ },
10647
+ children: [
10648
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Minimize2, { className: "size-3.5" }),
10649
+ "Fit to viewport"
10650
+ ]
10651
+ }
10652
+ ),
10653
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "my-1 border-t border-foreground/10" }),
10654
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
10655
+ import_button8.Button,
10656
+ {
10657
+ className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground",
10658
+ onClick: () => {
10659
+ onToggleCanvas?.();
10660
+ onOpenChange(false);
10661
+ },
10662
+ children: [
10663
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Check, { className: cn("size-3.5", canvasActive ? "opacity-100" : "opacity-0") }),
10664
+ "Canvas mode"
10665
+ ]
10666
+ }
10667
+ )
10668
+ ] })
9888
10669
  }
9889
10670
  ) }) })
9890
10671
  ] });
9891
10672
  }
9892
10673
 
9893
10674
  // src/toolbar.tsx
9894
- var import_jsx_runtime32 = require("react/jsx-runtime");
10675
+ var import_jsx_runtime33 = require("react/jsx-runtime");
9895
10676
  function DirectEditToolbarInner({
9896
10677
  editModeActive,
9897
10678
  onToggleEditMode,
@@ -9908,33 +10689,63 @@ function DirectEditToolbarInner({
9908
10689
  onClearSessionEdits,
9909
10690
  onRemoveSessionEdit,
9910
10691
  onDeleteComment,
9911
- className
10692
+ className,
10693
+ canvasActive = false,
10694
+ canvasZoom = 1,
10695
+ onToggleCanvas,
10696
+ onSetCanvasZoom,
10697
+ onZoomTo100,
10698
+ onFitToViewport
9912
10699
  }) {
9913
10700
  const container = usePortalContainer();
9914
- const toolbarRef = React34.useRef(null);
9915
- const { dockedEdge, isDragging, isSnapping, style: dockStyle, handlePointerDown, handlePointerMove, handlePointerUp, handlePointerCancel } = useToolbarDock(toolbarRef);
10701
+ const toolbarRef = React36.useRef(null);
10702
+ const { dockedEdge, isDragging, isSnapping, style: dockStyle, predictSize, handlePointerDown, handlePointerMove, handlePointerUp, handlePointerCancel } = useToolbarDock(toolbarRef);
9916
10703
  const isVertical = dockedEdge === "left" || dockedEdge === "right";
10704
+ const [activePopover, setActivePopover] = React36.useState(null);
10705
+ const sizeCacheRef = React36.useRef({});
10706
+ React36.useEffect(() => {
10707
+ const el = toolbarRef.current;
10708
+ if (!el) return;
10709
+ const key = `${dockedEdge}:${editModeActive ? "expanded" : "collapsed"}`;
10710
+ const timer = setTimeout(() => {
10711
+ const rect = el.getBoundingClientRect();
10712
+ sizeCacheRef.current[key] = { w: rect.width, h: rect.height };
10713
+ }, 350);
10714
+ return () => clearTimeout(timer);
10715
+ }, [editModeActive, dockedEdge]);
10716
+ const prevEditModeRef = React36.useRef(editModeActive);
10717
+ React36.useEffect(() => {
10718
+ if (prevEditModeRef.current === editModeActive) return;
10719
+ prevEditModeRef.current = editModeActive;
10720
+ const target = sizeCacheRef.current[`${dockedEdge}:${editModeActive ? "expanded" : "collapsed"}`];
10721
+ if (target) {
10722
+ predictSize(target.w, target.h);
10723
+ }
10724
+ }, [editModeActive, dockedEdge, predictSize]);
10725
+ React36.useEffect(() => {
10726
+ if (isDragging) setActivePopover(null);
10727
+ }, [isDragging]);
10728
+ React36.useEffect(() => {
10729
+ if (!editModeActive) setActivePopover(null);
10730
+ }, [editModeActive]);
9917
10731
  const tooltipSide = dockedEdge === "bottom" ? "top" : dockedEdge === "top" ? "bottom" : dockedEdge === "left" ? "right" : "left";
9918
- const [isMac, setIsMac] = React34.useState(false);
9919
- React34.useEffect(() => {
9920
- setIsMac(navigator.platform?.includes("Mac") ?? false);
9921
- }, []);
10732
+ const [isMac] = React36.useState(() => typeof navigator !== "undefined" ? navigator.platform?.includes("Mac") ?? false : false);
9922
10733
  const kbdClass = "inline-flex items-center justify-center rounded bg-muted px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground min-w-[20px] min-h-[18px]";
9923
- const shortcutContent = isMac ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
9924
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Command, { className: "size-2.5" }) }),
9925
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: "." })
9926
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
9927
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: "Ctrl" }),
9928
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: "." })
10734
+ const shortcutContent = isMac ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
10735
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.Command, { className: "size-2.5" }) }),
10736
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "." })
10737
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
10738
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "Ctrl" }),
10739
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "." })
9929
10740
  ] });
9930
- const toolbar = /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
10741
+ const toolbar = /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_jsx_runtime33.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
9931
10742
  "div",
9932
10743
  {
9933
10744
  ref: toolbarRef,
9934
10745
  "data-direct-edit": "toolbar",
9935
10746
  style: { pointerEvents: "auto", touchAction: "none", ...dockStyle },
9936
10747
  className: cn(
9937
- "group z-[99999] flex rounded-xl outline outline-1 outline-foreground/10 bg-background p-1.5 shadow-lg transition-shadow duration-200",
10748
+ "group z-[99999] flex rounded-xl outline outline-1 outline-foreground/10 bg-background p-1.5 shadow-lg",
9938
10749
  isVertical ? "flex-col items-center" : "flex-row items-center",
9939
10750
  isDragging && "cursor-grabbing select-none shadow-2xl",
9940
10751
  className
@@ -9945,21 +10756,21 @@ function DirectEditToolbarInner({
9945
10756
  onPointerCancel: handlePointerCancel,
9946
10757
  onLostPointerCapture: handlePointerCancel,
9947
10758
  children: [
9948
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn(
10759
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
9949
10760
  "flex shrink-0 cursor-grab items-center justify-center",
9950
10761
  isVertical ? "w-full pt-0 pb-1.5" : "h-full pl-0 pr-1.5"
9951
- ), children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn(
10762
+ ), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
9952
10763
  "shrink-0 rounded-full bg-foreground/25",
9953
10764
  isVertical ? "h-0.5 w-4" : "h-4 w-0.5"
9954
10765
  ) }) }),
9955
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(TooltipProvider, { delayDuration: 200, children: [
9956
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Tooltip, { children: [
9957
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10766
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipProvider, { delayDuration: 200, children: [
10767
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10768
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
9958
10769
  TooltipTrigger,
9959
10770
  {
9960
10771
  className: cn(
9961
- "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
9962
- editModeActive && activeTool !== "comment" ? "bg-foreground text-background hover:bg-foreground/80" : editModeActive && activeTool === "comment" ? "text-muted-foreground hover:bg-muted hover:text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10772
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-[color,background-color] duration-150 ease-out",
10773
+ editModeActive && activeTool !== "comment" ? "bg-foreground text-background hover:bg-foreground/80" : "text-muted-foreground hover:bg-muted hover:text-foreground"
9963
10774
  ),
9964
10775
  onPointerDown: (e) => e.stopPropagation(),
9965
10776
  onClick: () => {
@@ -9969,89 +10780,144 @@ function DirectEditToolbarInner({
9969
10780
  onToggleEditMode();
9970
10781
  }
9971
10782
  },
9972
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.MousePointer2, { className: "size-4" })
10783
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.MousePointer2, { className: "size-4" })
9973
10784
  }
9974
10785
  ),
9975
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
9976
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: editModeActive ? "Select" : "Activate design mode" }),
10786
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10787
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: editModeActive ? "Select" : "Activate design mode" }),
9977
10788
  shortcutContent
9978
10789
  ] })
9979
10790
  ] }),
9980
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10791
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
9981
10792
  "div",
9982
10793
  {
9983
10794
  className: cn(
9984
- "overflow-hidden transition-[max-width,max-height,margin,opacity] duration-300 ease-out",
9985
- isVertical ? editModeActive ? "mt-1 max-h-[220px] opacity-100" : "mt-0 max-h-0 opacity-0" : editModeActive ? "ml-1 max-w-[200px] opacity-100" : "ml-0 max-w-0 opacity-0"
10795
+ "grid place-items-center overflow-hidden",
10796
+ isVertical ? editModeActive ? "mt-1 grid-rows-[1fr]" : "mt-0 grid-rows-[0fr]" : editModeActive ? "ml-1 grid-cols-[1fr]" : "ml-0 grid-cols-[0fr]"
9986
10797
  ),
9987
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cn("flex gap-1", isVertical ? "flex-col items-center" : "flex-row items-center"), children: [
9988
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Tooltip, { children: [
9989
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
9990
- TooltipTrigger,
9991
- {
9992
- className: cn(
9993
- "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
9994
- activeTool === "comment" ? "bg-foreground text-background hover:bg-foreground/80" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10798
+ style: {
10799
+ transitionProperty: "grid-template-columns, grid-template-rows, margin",
10800
+ transitionDuration: "200ms",
10801
+ transitionTimingFunction: "cubic-bezier(0.25, 1, 0.5, 1)",
10802
+ transitionDelay: editModeActive ? "0ms" : "80ms"
10803
+ },
10804
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
10805
+ "div",
10806
+ {
10807
+ className: cn("flex gap-1 overflow-hidden", isVertical ? "min-h-0 flex-col items-center" : "min-w-0 flex-row items-center"),
10808
+ style: {
10809
+ filter: editModeActive ? "blur(0px)" : "blur(5px)",
10810
+ opacity: editModeActive ? 1 : 0,
10811
+ transitionProperty: "filter, opacity",
10812
+ transitionDuration: "250ms, 100ms",
10813
+ transitionTimingFunction: "cubic-bezier(0.33, 1, 0.68, 1)",
10814
+ transitionDelay: editModeActive ? "80ms" : "0ms"
10815
+ },
10816
+ children: [
10817
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10818
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10819
+ TooltipTrigger,
10820
+ {
10821
+ className: cn(
10822
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10823
+ activeTool === "comment" ? "bg-foreground text-background hover:bg-foreground/80" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10824
+ ),
10825
+ onPointerDown: (e) => e.stopPropagation(),
10826
+ onClick: () => onSetActiveTool?.(activeTool === "comment" ? "select" : "comment"),
10827
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.MessageSquare, { className: "size-4" })
10828
+ }
9995
10829
  ),
9996
- onPointerDown: (e) => e.stopPropagation(),
9997
- onClick: () => onSetActiveTool?.(activeTool === "comment" ? "select" : "comment"),
9998
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.MessageSquare, { className: "size-4" })
9999
- }
10000
- ),
10001
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10002
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: activeTool === "comment" ? "Exit comment mode" : "Comment" }),
10003
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.ArrowBigUp, { className: "size-3" }) }),
10004
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: "C" })
10005
- ] })
10006
- ] }),
10007
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Tooltip, { children: [
10008
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10009
- TooltipTrigger,
10010
- {
10011
- className: cn(
10012
- "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10013
- rulersVisible ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10830
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10831
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: activeTool === "comment" ? "Exit comment mode" : "Comment" }),
10832
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.ArrowBigUp, { className: "size-3" }) }),
10833
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "C" })
10834
+ ] })
10835
+ ] }),
10836
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10837
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10838
+ TooltipTrigger,
10839
+ {
10840
+ className: cn(
10841
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10842
+ rulersVisible ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10843
+ ),
10844
+ onPointerDown: (e) => e.stopPropagation(),
10845
+ onClick: onToggleRulers,
10846
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.Ruler, { className: "size-4" })
10847
+ }
10014
10848
  ),
10015
- onPointerDown: (e) => e.stopPropagation(),
10016
- onClick: onToggleRulers,
10017
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Ruler, { className: "size-4" })
10018
- }
10019
- ),
10020
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10021
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: rulersVisible ? "Hide rulers" : "Show rulers" }),
10022
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.ArrowBigUp, { className: "size-2.5" }) }),
10023
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: "R" })
10024
- ] })
10025
- ] }),
10026
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn(
10027
- "border-foreground/10",
10028
- isVertical ? "my-0.5 w-5 border-t" : "mx-0.5 h-5 border-l"
10029
- ) }),
10030
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10031
- EditsPopover,
10032
- {
10033
- tooltipSide,
10034
- sessionEditCount,
10035
- isDragging,
10036
- onGetSessionItems,
10037
- onExportAllEdits,
10038
- onSendAllToAgents,
10039
- onClearSessionEdits,
10040
- onRemoveSessionEdit,
10041
- onDeleteComment
10042
- }
10043
- ),
10044
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10045
- SettingsPopover,
10046
- {
10047
- tooltipSide,
10048
- theme,
10049
- isMac,
10050
- isDragging,
10051
- onSetTheme
10052
- }
10053
- )
10054
- ] })
10849
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10850
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: rulersVisible ? "Hide rulers" : "Show rulers" }),
10851
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.ArrowBigUp, { className: "size-2.5" }) }),
10852
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "R" })
10853
+ ] })
10854
+ ] }),
10855
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10856
+ ZoomPopover,
10857
+ {
10858
+ tooltipSide,
10859
+ canvasActive,
10860
+ canvasZoom,
10861
+ isOpen: activePopover === "zoom",
10862
+ onOpenChange: (open) => setActivePopover(open ? "zoom" : null),
10863
+ onToggleCanvas,
10864
+ onSetCanvasZoom,
10865
+ onZoomTo100,
10866
+ onFitToViewport
10867
+ }
10868
+ ),
10869
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
10870
+ "border-foreground/10",
10871
+ isVertical ? "my-0.5 w-5 border-t" : "mx-0.5 h-5 border-l"
10872
+ ) }),
10873
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10874
+ EditsPopover,
10875
+ {
10876
+ tooltipSide,
10877
+ sessionEditCount,
10878
+ isOpen: activePopover === "edits",
10879
+ onOpenChange: (open) => setActivePopover(open ? "edits" : null),
10880
+ onGetSessionItems,
10881
+ onExportAllEdits,
10882
+ onSendAllToAgents,
10883
+ onClearSessionEdits,
10884
+ onRemoveSessionEdit,
10885
+ onDeleteComment
10886
+ }
10887
+ ),
10888
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10889
+ SettingsPopover,
10890
+ {
10891
+ tooltipSide,
10892
+ theme,
10893
+ isMac,
10894
+ isOpen: activePopover === "settings",
10895
+ onOpenChange: (open) => setActivePopover(open ? "settings" : null),
10896
+ onSetTheme
10897
+ }
10898
+ ),
10899
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
10900
+ "border-foreground/10",
10901
+ isVertical ? "my-0.5 w-5 border-t" : "mx-0.5 h-5 border-l"
10902
+ ) }),
10903
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10904
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10905
+ TooltipTrigger,
10906
+ {
10907
+ className: "flex cursor-pointer items-center justify-center rounded-[8px] p-2 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
10908
+ onPointerDown: (e) => e.stopPropagation(),
10909
+ onClick: onToggleEditMode,
10910
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.X, { className: "size-4" })
10911
+ }
10912
+ ),
10913
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10914
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: "Close" }),
10915
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "Esc" })
10916
+ ] })
10917
+ ] })
10918
+ ]
10919
+ }
10920
+ )
10055
10921
  }
10056
10922
  )
10057
10923
  ] })
@@ -10064,7 +10930,7 @@ function DirectEditToolbarInner({
10064
10930
  return toolbar;
10065
10931
  }
10066
10932
  function DirectEditToolbarContent() {
10067
- const { editModeActive, activeTool, theme, sessionEditCount } = useDirectEditState();
10933
+ const { editModeActive, activeTool, theme, sessionEditCount, canvas } = useDirectEditState();
10068
10934
  const {
10069
10935
  toggleEditMode,
10070
10936
  setActiveTool,
@@ -10074,10 +10940,14 @@ function DirectEditToolbarContent() {
10074
10940
  sendAllSessionItemsToAgent,
10075
10941
  clearSessionEdits,
10076
10942
  removeSessionEdit,
10077
- deleteComment
10943
+ deleteComment,
10944
+ toggleCanvas,
10945
+ setCanvasZoom,
10946
+ zoomCanvasTo100,
10947
+ fitCanvasToViewport
10078
10948
  } = useDirectEditActions();
10079
10949
  const [rulersVisible, toggleRulers] = useRulersVisible();
10080
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10950
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10081
10951
  DirectEditToolbarInner,
10082
10952
  {
10083
10953
  editModeActive,
@@ -10094,34 +10964,40 @@ function DirectEditToolbarContent() {
10094
10964
  onSendAllToAgents: sendAllSessionItemsToAgent,
10095
10965
  onClearSessionEdits: clearSessionEdits,
10096
10966
  onRemoveSessionEdit: removeSessionEdit,
10097
- onDeleteComment: deleteComment
10967
+ onDeleteComment: deleteComment,
10968
+ canvasActive: canvas?.active ?? false,
10969
+ canvasZoom: canvas?.zoom ?? 1,
10970
+ onToggleCanvas: toggleCanvas,
10971
+ onSetCanvasZoom: setCanvasZoom,
10972
+ onZoomTo100: zoomCanvasTo100,
10973
+ onFitToViewport: fitCanvasToViewport
10098
10974
  }
10099
10975
  );
10100
10976
  }
10101
10977
  function DirectEditToolbar() {
10102
- const [mounted, setMounted] = React34.useState(false);
10103
- React34.useEffect(() => {
10978
+ const [mounted, setMounted] = React36.useState(false);
10979
+ React36.useEffect(() => {
10104
10980
  setMounted(true);
10105
10981
  }, []);
10106
10982
  if (!mounted) {
10107
10983
  return null;
10108
10984
  }
10109
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(DirectEditToolbarContent, {});
10985
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(DirectEditToolbarContent, {});
10110
10986
  }
10111
10987
 
10112
10988
  // src/direct-edit.tsx
10113
- var import_jsx_runtime33 = require("react/jsx-runtime");
10989
+ var import_jsx_runtime34 = require("react/jsx-runtime");
10114
10990
  function DirectEdit() {
10115
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(DirectEditProvider, { children: [
10116
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(DirectEditPanel, {}),
10117
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(DirectEditToolbar, {}),
10118
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Rulers, {})
10991
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(DirectEditProvider, { children: [
10992
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DirectEditPanel, {}),
10993
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DirectEditToolbar, {}),
10994
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Rulers, {})
10119
10995
  ] });
10120
10996
  }
10121
10997
 
10122
10998
  // src/demo.tsx
10123
- var React35 = __toESM(require("react"));
10124
- var import_jsx_runtime34 = require("react/jsx-runtime");
10999
+ var React37 = __toESM(require("react"));
11000
+ var import_jsx_runtime35 = require("react/jsx-runtime");
10125
11001
  function createValue(num, unit = "px") {
10126
11002
  return { numericValue: num, unit, raw: `${num}${unit}` };
10127
11003
  }
@@ -10149,7 +11025,7 @@ var DEMO_LOCATOR = {
10149
11025
  classList: ELEMENT_INFO.classList
10150
11026
  };
10151
11027
  function DirectEditDemo() {
10152
- const [spacing, setSpacing] = React35.useState({
11028
+ const [spacing, setSpacing] = React37.useState({
10153
11029
  paddingTop: createValue(16),
10154
11030
  paddingRight: createValue(16),
10155
11031
  paddingBottom: createValue(16),
@@ -10160,13 +11036,13 @@ function DirectEditDemo() {
10160
11036
  marginLeft: createValue(0),
10161
11037
  gap: createValue(16)
10162
11038
  });
10163
- const [borderRadius, setBorderRadius] = React35.useState({
11039
+ const [borderRadius, setBorderRadius] = React37.useState({
10164
11040
  borderTopLeftRadius: createValue(8),
10165
11041
  borderTopRightRadius: createValue(8),
10166
11042
  borderBottomRightRadius: createValue(8),
10167
11043
  borderBottomLeftRadius: createValue(8)
10168
11044
  });
10169
- const [border, setBorder] = React35.useState({
11045
+ const [border, setBorder] = React37.useState({
10170
11046
  borderTopStyle: "solid",
10171
11047
  borderTopWidth: createValue(1),
10172
11048
  borderRightStyle: "solid",
@@ -10176,23 +11052,23 @@ function DirectEditDemo() {
10176
11052
  borderLeftStyle: "solid",
10177
11053
  borderLeftWidth: createValue(1)
10178
11054
  });
10179
- const [flex, setFlex] = React35.useState({
11055
+ const [flex, setFlex] = React37.useState({
10180
11056
  display: "flex",
10181
11057
  flexDirection: "row",
10182
11058
  justifyContent: "flex-start",
10183
11059
  alignItems: "center"
10184
11060
  });
10185
- const [sizing, setSizing] = React35.useState({
11061
+ const [sizing, setSizing] = React37.useState({
10186
11062
  width: { mode: "fit", value: createValue(300) },
10187
11063
  height: { mode: "fit", value: createValue(100) }
10188
11064
  });
10189
- const [color, setColor] = React35.useState({
11065
+ const [color, setColor] = React37.useState({
10190
11066
  backgroundColor: { hex: "FFFFFF", alpha: 100, raw: "rgb(255, 255, 255)" },
10191
11067
  color: { hex: "000000", alpha: 100, raw: "rgb(0, 0, 0)" },
10192
11068
  borderColor: { hex: "DDDDDD", alpha: 100, raw: "rgb(221, 221, 221)" },
10193
11069
  outlineColor: { hex: "000000", alpha: 0, raw: "transparent" }
10194
11070
  });
10195
- const [typography, setTypography] = React35.useState({
11071
+ const [typography, setTypography] = React37.useState({
10196
11072
  fontFamily: "system-ui, sans-serif",
10197
11073
  fontWeight: "400",
10198
11074
  fontSize: createValue(16),
@@ -10201,9 +11077,9 @@ function DirectEditDemo() {
10201
11077
  textAlign: "left",
10202
11078
  textVerticalAlign: "flex-start"
10203
11079
  });
10204
- const [boxShadow, setBoxShadow] = React35.useState("none");
10205
- const [pendingStyles, setPendingStyles] = React35.useState({});
10206
- const [editModeActive, setEditModeActive] = React35.useState(false);
11080
+ const [boxShadow, setBoxShadow] = React37.useState("none");
11081
+ const [pendingStyles, setPendingStyles] = React37.useState({});
11082
+ const [editModeActive, setEditModeActive] = React37.useState(false);
10207
11083
  const handleUpdateSpacing = (key, value) => {
10208
11084
  setSpacing((prev) => ({ ...prev, [key]: value }));
10209
11085
  setPendingStyles((prev) => ({ ...prev, [camelToKebab(key)]: value.raw }));
@@ -10314,10 +11190,10 @@ function DirectEditDemo() {
10314
11190
  return false;
10315
11191
  }
10316
11192
  };
10317
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "min-h-screen p-8", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "mx-auto max-w-4xl", children: [
10318
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { className: "mb-2 text-2xl font-bold", children: "Direct Edit Panel" }),
10319
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "mb-8 text-muted-foreground", children: "Interactive showcase of the visual editing panel UI with mock data." }),
10320
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mb-8 flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
11193
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "min-h-screen p-8", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mx-auto max-w-4xl", children: [
11194
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { className: "mb-2 text-2xl font-bold", children: "Direct Edit Panel" }),
11195
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mb-8 text-muted-foreground", children: "Interactive showcase of the visual editing panel UI with mock data." }),
11196
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "mb-8 flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
10321
11197
  DirectEditToolbarInner,
10322
11198
  {
10323
11199
  editModeActive,
@@ -10327,8 +11203,8 @@ function DirectEditDemo() {
10327
11203
  }
10328
11204
  }
10329
11205
  ) }),
10330
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "grid gap-8 lg:grid-cols-[300px_1fr]", children: [
10331
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
11206
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "grid gap-8 lg:grid-cols-[300px_1fr]", children: [
11207
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
10332
11208
  DirectEditPanelInner,
10333
11209
  {
10334
11210
  elementInfo: ELEMENT_INFO,
@@ -10360,10 +11236,10 @@ function DirectEditDemo() {
10360
11236
  onSendToAgent: async () => false
10361
11237
  }
10362
11238
  ),
10363
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "space-y-6", children: [
10364
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { children: [
10365
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Live Preview" }),
10366
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
11239
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "space-y-6", children: [
11240
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
11241
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Live Preview" }),
11242
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
10367
11243
  "div",
10368
11244
  {
10369
11245
  className: "bg-background border flex",
@@ -10386,20 +11262,20 @@ function DirectEditDemo() {
10386
11262
  alignItems: flex.alignItems
10387
11263
  },
10388
11264
  children: [
10389
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "size-12 rounded bg-blue-500/20 border border-blue-500/30" }),
10390
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "size-12 rounded bg-green-500/20 border border-green-500/30" }),
10391
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "size-12 rounded bg-purple-500/20 border border-purple-500/30" })
11265
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "size-12 rounded bg-blue-500/20 border border-blue-500/30" }),
11266
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "size-12 rounded bg-green-500/20 border border-green-500/30" }),
11267
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "size-12 rounded bg-purple-500/20 border border-purple-500/30" })
10392
11268
  ]
10393
11269
  }
10394
11270
  )
10395
11271
  ] }),
10396
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { children: [
10397
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Pending Styles" }),
10398
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { className: "rounded-lg border bg-background p-4 text-xs min-h-[60px]", children: Object.keys(pendingStyles).length > 0 ? JSON.stringify(pendingStyles, null, 2) : "// Make changes to see pending styles" })
11272
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
11273
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Pending Styles" }),
11274
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("pre", { className: "rounded-lg border bg-background p-4 text-xs min-h-[60px]", children: Object.keys(pendingStyles).length > 0 ? JSON.stringify(pendingStyles, null, 2) : "// Make changes to see pending styles" })
10399
11275
  ] }),
10400
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { children: [
10401
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Tailwind Classes" }),
10402
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("code", { className: "block rounded-lg border bg-background p-4 text-xs min-h-[40px]", children: Object.keys(pendingStyles).length > 0 ? stylesToTailwind(pendingStyles) : "// Tailwind classes will appear here" })
11276
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
11277
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Tailwind Classes" }),
11278
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { className: "block rounded-lg border bg-background p-4 text-xs min-h-[40px]", children: Object.keys(pendingStyles).length > 0 ? stylesToTailwind(pendingStyles) : "// Tailwind classes will appear here" })
10403
11279
  ] })
10404
11280
  ] })
10405
11281
  ] })