made-refine 0.2.1-beta.2 → 0.2.3

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,339 @@ 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 rafIdRef = React7.useRef(null);
4139
+ const rafPendingRef = React7.useRef(false);
4140
+ const spaceHeldRef = React7.useRef(false);
4141
+ const isDraggingRef = React7.useRef(false);
4142
+ const dragStartRef = React7.useRef({ x: 0, y: 0, panX: 0, panY: 0 });
4143
+ const applyTransform = React7.useCallback((zoom, panX, panY) => {
4144
+ document.body.style.transformOrigin = "0 0";
4145
+ document.body.style.transform = `scale(${zoom}) translate(${panX}px, ${panY}px)`;
4146
+ }, []);
4147
+ const dispatchCanvasChange = React7.useCallback(() => {
4148
+ window.dispatchEvent(new Event("direct-edit-canvas-change"));
4149
+ }, []);
4150
+ const readBodyOffset = React7.useCallback(() => {
4151
+ const bodyStyle = getComputedStyle(document.body);
4152
+ return {
4153
+ x: parseFloat(bodyStyle.marginLeft) || 0,
4154
+ y: parseFloat(bodyStyle.marginTop) || 0
4155
+ };
4156
+ }, []);
4157
+ const updateBodyOffset = React7.useCallback(() => {
4158
+ const next = readBodyOffset();
4159
+ const prev = getBodyOffset();
4160
+ if (prev.x === next.x && prev.y === next.y) return false;
4161
+ setBodyOffset(next);
4162
+ return true;
4163
+ }, [readBodyOffset]);
4164
+ const cancelPendingRaf = React7.useCallback(() => {
4165
+ if (rafIdRef.current !== null) {
4166
+ cancelAnimationFrame(rafIdRef.current);
4167
+ rafIdRef.current = null;
4168
+ rafPendingRef.current = false;
4169
+ }
4170
+ }, []);
4171
+ const updateCanvas = React7.useCallback((zoom, panX, panY) => {
4172
+ const dims = savedBodyDimensionsRef.current;
4173
+ const bodyW = dims.width || window.innerWidth;
4174
+ const bodyH = dims.height || window.innerHeight;
4175
+ const clamped = clampPan(zoom, panX, panY, bodyW, bodyH);
4176
+ canvasRef.current = { ...canvasRef.current, zoom, panX: clamped.panX, panY: clamped.panY };
4177
+ setCanvasSnapshot(canvasRef.current);
4178
+ applyTransform(zoom, clamped.panX, clamped.panY);
4179
+ dispatchCanvasChange();
4180
+ if (!rafPendingRef.current) {
4181
+ rafPendingRef.current = true;
4182
+ rafIdRef.current = requestAnimationFrame(() => {
4183
+ rafPendingRef.current = false;
4184
+ rafIdRef.current = null;
4185
+ const s = canvasRef.current;
4186
+ setState((prev) => ({
4187
+ ...prev,
4188
+ canvas: { active: s.active, zoom: s.zoom, panX: s.panX, panY: s.panY }
4189
+ }));
4190
+ });
4191
+ }
4192
+ }, [applyTransform, dispatchCanvasChange, setState]);
4193
+ const enterCanvas = React7.useCallback(() => {
4194
+ const scrollX = window.scrollX;
4195
+ const scrollY = window.scrollY;
4196
+ savedScrollRef.current = { x: scrollX, y: scrollY };
4197
+ savedBodyOverflowRef.current = document.body.style.overflow;
4198
+ savedHtmlOverflowRef.current = document.documentElement.style.overflow;
4199
+ savedHtmlBgColorRef.current = document.documentElement.style.backgroundColor;
4200
+ savedBodyDimensionsRef.current = {
4201
+ width: document.body.scrollWidth,
4202
+ height: document.body.scrollHeight
4203
+ };
4204
+ const existingTransform = document.body.style.transform;
4205
+ if (existingTransform && existingTransform !== "none" && existingTransform !== "") {
4206
+ console.warn("[made-refine] canvas mode: overriding existing body transform:", existingTransform);
4207
+ }
4208
+ window.scrollTo(0, 0);
4209
+ updateBodyOffset();
4210
+ document.body.style.overflow = "hidden";
4211
+ document.documentElement.style.overflow = "hidden";
4212
+ document.documentElement.style.backgroundColor = "#F5F5F5";
4213
+ const initialPanX = -scrollX;
4214
+ const initialPanY = -scrollY;
4215
+ applyTransform(1, initialPanX, initialPanY);
4216
+ canvasRef.current = { active: true, zoom: 1, panX: initialPanX, panY: initialPanY };
4217
+ setCanvasSnapshot(canvasRef.current);
4218
+ setState((prev) => ({
4219
+ ...prev,
4220
+ canvas: { active: true, zoom: 1, panX: initialPanX, panY: initialPanY }
4221
+ }));
4222
+ dispatchCanvasChange();
4223
+ }, [applyTransform, dispatchCanvasChange, setState, updateBodyOffset]);
4224
+ const exitCanvas = React7.useCallback(() => {
4225
+ cancelPendingRaf();
4226
+ document.body.style.transform = "";
4227
+ document.body.style.transformOrigin = "";
4228
+ document.body.style.overflow = savedBodyOverflowRef.current;
4229
+ document.documentElement.style.overflow = savedHtmlOverflowRef.current;
4230
+ document.documentElement.style.backgroundColor = savedHtmlBgColorRef.current;
4231
+ document.body.style.cursor = "";
4232
+ window.scrollTo(savedScrollRef.current.x, savedScrollRef.current.y);
4233
+ setBodyOffset({ x: 0, y: 0 });
4234
+ canvasRef.current = { active: false, zoom: 1, panX: 0, panY: 0 };
4235
+ setCanvasSnapshot(canvasRef.current);
4236
+ setState((prev) => ({
4237
+ ...prev,
4238
+ canvas: { active: false, zoom: 1, panX: 0, panY: 0 }
4239
+ }));
4240
+ dispatchCanvasChange();
4241
+ }, [cancelPendingRaf, dispatchCanvasChange, setState]);
4242
+ const toggleCanvas = React7.useCallback(() => {
4243
+ if (canvasRef.current.active) {
4244
+ exitCanvas();
4245
+ } else {
4246
+ enterCanvas();
4247
+ }
4248
+ }, [enterCanvas, exitCanvas]);
4249
+ const setCanvasZoom = React7.useCallback((zoom) => {
4250
+ const c = canvasRef.current;
4251
+ if (!c.active) return;
4252
+ const clampedZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom));
4253
+ updateCanvas(clampedZoom, c.panX, c.panY);
4254
+ }, [updateCanvas]);
4255
+ const fitCanvasToViewport = React7.useCallback(() => {
4256
+ const c = canvasRef.current;
4257
+ if (!c.active) return;
4258
+ const bodyWidth = savedBodyDimensionsRef.current.width || window.innerWidth;
4259
+ const bodyHeight = savedBodyDimensionsRef.current.height || window.innerHeight;
4260
+ const scaleX = window.innerWidth / bodyWidth;
4261
+ const scaleY = window.innerHeight / bodyHeight;
4262
+ const zoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, Math.min(scaleX, scaleY) * 0.9));
4263
+ const panX = (window.innerWidth / zoom - bodyWidth) / 2;
4264
+ const panY = (window.innerHeight / zoom - bodyHeight) / 2;
4265
+ updateCanvas(zoom, panX, panY);
4266
+ }, [updateCanvas]);
4267
+ const zoomCanvasTo100 = React7.useCallback(() => {
4268
+ const c = canvasRef.current;
4269
+ if (!c.active) return;
4270
+ updateCanvas(1, 0, 0);
4271
+ }, [updateCanvas]);
4272
+ React7.useEffect(() => {
4273
+ function handleWheel(e) {
4274
+ const c = canvasRef.current;
4275
+ if (!c.active) return;
4276
+ e.preventDefault();
4277
+ const { deltaX, deltaY } = normalizeWheelDelta(e);
4278
+ if (e.ctrlKey || e.metaKey) {
4279
+ const zoomFactor = Math.exp(-deltaY * ZOOM_SENSITIVITY);
4280
+ const oldZoom = c.zoom;
4281
+ const newZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, oldZoom * zoomFactor));
4282
+ const cx = e.clientX;
4283
+ const cy = e.clientY;
4284
+ const bo = getBodyOffset();
4285
+ const newPanX = c.panX + (cx - bo.x) * (1 / newZoom - 1 / oldZoom);
4286
+ const newPanY = c.panY + (cy - bo.y) * (1 / newZoom - 1 / oldZoom);
4287
+ updateCanvas(newZoom, newPanX, newPanY);
4288
+ } else {
4289
+ const newPanX = c.panX - deltaX / c.zoom;
4290
+ const newPanY = c.panY - deltaY / c.zoom;
4291
+ updateCanvas(c.zoom, newPanX, newPanY);
4292
+ }
4293
+ }
4294
+ window.addEventListener("wheel", handleWheel, { passive: false });
4295
+ return () => window.removeEventListener("wheel", handleWheel);
4296
+ }, [updateCanvas]);
4297
+ React7.useEffect(() => {
4298
+ function handleResize() {
4299
+ if (!canvasRef.current.active) return;
4300
+ if (updateBodyOffset()) {
4301
+ dispatchCanvasChange();
4302
+ }
4303
+ }
4304
+ window.addEventListener("resize", handleResize);
4305
+ return () => window.removeEventListener("resize", handleResize);
4306
+ }, [dispatchCanvasChange, updateBodyOffset]);
4307
+ React7.useEffect(() => {
4308
+ function handleKeyDown(e) {
4309
+ if (e.code !== "Space" || e.repeat) return;
4310
+ if (!canvasRef.current.active) return;
4311
+ if (isInputFocused()) return;
4312
+ spaceHeldRef.current = true;
4313
+ if (!isDraggingRef.current) {
4314
+ document.body.style.cursor = "grab";
4315
+ }
4316
+ e.preventDefault();
4317
+ }
4318
+ function handleKeyUp(e) {
4319
+ if (e.code !== "Space") return;
4320
+ if (!canvasRef.current.active) return;
4321
+ spaceHeldRef.current = false;
4322
+ if (!isDraggingRef.current) {
4323
+ document.body.style.cursor = "";
4324
+ }
4325
+ }
4326
+ window.addEventListener("keydown", handleKeyDown, true);
4327
+ window.addEventListener("keyup", handleKeyUp, true);
4328
+ return () => {
4329
+ window.removeEventListener("keydown", handleKeyDown, true);
4330
+ window.removeEventListener("keyup", handleKeyUp, true);
4331
+ };
4332
+ }, []);
4333
+ React7.useEffect(() => {
4334
+ function handlePointerDown(e) {
4335
+ const c = canvasRef.current;
4336
+ if (!c.active) return;
4337
+ const isMiddleMouse = e.button === 1;
4338
+ const isSpaceDrag = spaceHeldRef.current && e.button === 0;
4339
+ if (!isMiddleMouse && !isSpaceDrag) return;
4340
+ e.preventDefault();
4341
+ isDraggingRef.current = true;
4342
+ dragStartRef.current = { x: e.clientX, y: e.clientY, panX: c.panX, panY: c.panY };
4343
+ document.body.style.cursor = "grabbing";
4344
+ const dragAbort = new AbortController();
4345
+ const opts = { signal: dragAbort.signal };
4346
+ function endDrag() {
4347
+ isDraggingRef.current = false;
4348
+ document.body.style.cursor = spaceHeldRef.current ? "grab" : "";
4349
+ dragAbort.abort();
4350
+ }
4351
+ window.addEventListener("pointermove", (moveE) => {
4352
+ const current = canvasRef.current;
4353
+ const dx = (moveE.clientX - dragStartRef.current.x) / current.zoom;
4354
+ const dy = (moveE.clientY - dragStartRef.current.y) / current.zoom;
4355
+ updateCanvas(current.zoom, dragStartRef.current.panX + dx, dragStartRef.current.panY + dy);
4356
+ }, opts);
4357
+ window.addEventListener("pointerup", endDrag, opts);
4358
+ window.addEventListener("pointercancel", endDrag, opts);
4359
+ window.addEventListener("blur", endDrag, opts);
4360
+ }
4361
+ window.addEventListener("pointerdown", handlePointerDown, true);
4362
+ return () => window.removeEventListener("pointerdown", handlePointerDown, true);
4363
+ }, [updateCanvas]);
4364
+ React7.useEffect(() => {
4365
+ return () => {
4366
+ cancelPendingRaf();
4367
+ if (canvasRef.current.active) {
4368
+ exitCanvas();
4369
+ }
4370
+ };
4371
+ }, [cancelPendingRaf, exitCanvas]);
4372
+ return { toggleCanvas, enterCanvas, exitCanvas, setCanvasZoom, fitCanvasToViewport, zoomCanvasTo100 };
4016
4373
  }
4017
4374
 
4018
4375
  // src/provider.tsx
4019
4376
  var import_jsx_runtime2 = require("react/jsx-runtime");
4020
- var DirectEditStateContext = React7.createContext(null);
4021
- var DirectEditActionsContext = React7.createContext(null);
4377
+ var DirectEditStateContext = React8.createContext(null);
4378
+ var DirectEditActionsContext = React8.createContext(null);
4022
4379
  function useDirectEditState() {
4023
- const context = React7.useContext(DirectEditStateContext);
4380
+ const context = React8.useContext(DirectEditStateContext);
4024
4381
  if (!context) {
4025
4382
  throw new Error("useDirectEditState must be used within a DirectEditProvider");
4026
4383
  }
4027
4384
  return context;
4028
4385
  }
4029
4386
  function useDirectEditActions() {
4030
- const context = React7.useContext(DirectEditActionsContext);
4387
+ const context = React8.useContext(DirectEditActionsContext);
4031
4388
  if (!context) {
4032
4389
  throw new Error("useDirectEditActions must be used within a DirectEditProvider");
4033
4390
  }
@@ -4036,11 +4393,34 @@ function useDirectEditActions() {
4036
4393
  function useDirectEdit() {
4037
4394
  const state = useDirectEditState();
4038
4395
  const actions = useDirectEditActions();
4039
- return React7.useMemo(() => ({ ...state, ...actions }), [state, actions]);
4396
+ return React8.useMemo(() => ({ ...state, ...actions }), [state, actions]);
4040
4397
  }
4041
4398
  var BORDER_STYLE_CONTROL_PREFERENCE_KEY = "direct-edit-border-style-control";
4399
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? React8.useEffect : React8.useLayoutEffect;
4400
+ function getInitialTheme() {
4401
+ if (typeof window === "undefined") return "system";
4402
+ try {
4403
+ const theme = localStorage.getItem("direct-edit-theme");
4404
+ if (theme === "light" || theme === "dark" || theme === "system") {
4405
+ return theme;
4406
+ }
4407
+ } catch {
4408
+ }
4409
+ return "system";
4410
+ }
4411
+ function getInitialBorderStyleControlPreference() {
4412
+ if (typeof window === "undefined") return "icon";
4413
+ try {
4414
+ const borderPref = localStorage.getItem(BORDER_STYLE_CONTROL_PREFERENCE_KEY);
4415
+ if (borderPref === "label" || borderPref === "icon") {
4416
+ return borderPref;
4417
+ }
4418
+ } catch {
4419
+ }
4420
+ return "icon";
4421
+ }
4042
4422
  function DirectEditProvider({ children }) {
4043
- const [state, setState] = React7.useState({
4423
+ const [state, setState] = React8.useState(() => ({
4044
4424
  isOpen: false,
4045
4425
  selectedElement: null,
4046
4426
  elementInfo: null,
@@ -4056,38 +4436,22 @@ function DirectEditProvider({ children }) {
4056
4436
  pendingStyles: {},
4057
4437
  editModeActive: false,
4058
4438
  activeTool: "select",
4059
- theme: "system",
4060
- borderStyleControlPreference: "icon",
4439
+ theme: getInitialTheme(),
4440
+ borderStyleControlPreference: getInitialBorderStyleControlPreference(),
4061
4441
  comments: [],
4062
4442
  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(() => {
4443
+ textEditingElement: null,
4444
+ canvas: { active: false, zoom: 1, panX: 0, panY: 0 }
4445
+ }));
4446
+ const undoStackRef = React8.useRef([]);
4447
+ const sessionEditsRef = React8.useRef(/* @__PURE__ */ new Map());
4448
+ const removedSessionEditsRef = React8.useRef(/* @__PURE__ */ new WeakSet());
4449
+ const [sessionEditCount, setSessionEditCount] = React8.useState(0);
4450
+ const stateRef = React8.useRef(state);
4451
+ React8.useEffect(() => {
4088
4452
  stateRef.current = state;
4089
4453
  });
4090
- const pushUndo = React7.useCallback((entry) => {
4454
+ const pushUndo = React8.useCallback((entry) => {
4091
4455
  undoStackRef.current.push(entry);
4092
4456
  if (undoStackRef.current.length > 500) {
4093
4457
  undoStackRef.current = undoStackRef.current.slice(-500);
@@ -4132,13 +4496,13 @@ function DirectEditProvider({ children }) {
4132
4496
  setState,
4133
4497
  setSessionEditCount
4134
4498
  });
4135
- React7.useEffect(() => {
4499
+ React8.useEffect(() => {
4136
4500
  if (!state.selectedElement) return;
4137
4501
  saveCurrentToSession();
4138
4502
  }, [state.selectedElement, state.pendingStyles, saveCurrentToSession]);
4139
4503
  const {
4140
4504
  finalizeTextEditing,
4141
- toggleEditMode,
4505
+ toggleEditMode: toggleEditModeBase,
4142
4506
  startTextEditing,
4143
4507
  commitTextEditing,
4144
4508
  addComment,
@@ -4155,10 +4519,32 @@ function DirectEditProvider({ children }) {
4155
4519
  syncSessionItemCount,
4156
4520
  setState
4157
4521
  });
4158
- React7.useEffect(() => {
4522
+ const { toggleCanvas, enterCanvas, exitCanvas, setCanvasZoom, fitCanvasToViewport, zoomCanvasTo100 } = useCanvas({
4523
+ stateRef,
4524
+ setState
4525
+ });
4526
+ const closePanel = React8.useCallback(() => {
4527
+ setState((prev) => ({
4528
+ ...prev,
4529
+ isOpen: false
4530
+ }));
4531
+ }, []);
4532
+ const toggleEditMode = React8.useCallback(() => {
4533
+ const wasActive = stateRef.current.editModeActive;
4534
+ toggleEditModeBase();
4535
+ if (wasActive && stateRef.current.canvas?.active) {
4536
+ exitCanvas();
4537
+ } else if (!wasActive) {
4538
+ enterCanvas();
4539
+ }
4540
+ if (wasActive) {
4541
+ closePanel();
4542
+ }
4543
+ }, [toggleEditModeBase, stateRef, exitCanvas, enterCanvas, closePanel]);
4544
+ React8.useEffect(() => {
4159
4545
  syncSessionItemCount(state.comments);
4160
4546
  }, [state.comments, syncSessionItemCount]);
4161
- React7.useEffect(() => {
4547
+ React8.useEffect(() => {
4162
4548
  const editingElement = state.textEditingElement;
4163
4549
  if (!editingElement) return;
4164
4550
  const activeEditingElement = editingElement;
@@ -4183,27 +4569,21 @@ function DirectEditProvider({ children }) {
4183
4569
  sendCommentToAgent: sendCommentToAgent2,
4184
4570
  sendAllSessionItemsToAgent
4185
4571
  } = 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) => {
4572
+ const setActiveTool = React8.useCallback((tool) => {
4193
4573
  setState((prev) => ({
4194
4574
  ...prev,
4195
4575
  activeTool: tool,
4196
4576
  activeCommentId: null
4197
4577
  }));
4198
4578
  }, []);
4199
- const setTheme = React7.useCallback((theme) => {
4579
+ const setTheme = React8.useCallback((theme) => {
4200
4580
  setState((prev) => ({ ...prev, theme }));
4201
4581
  try {
4202
4582
  localStorage.setItem("direct-edit-theme", theme);
4203
4583
  } catch {
4204
4584
  }
4205
4585
  }, []);
4206
- const setBorderStyleControlPreference = React7.useCallback((preference) => {
4586
+ const setBorderStyleControlPreference = React8.useCallback((preference) => {
4207
4587
  setState((prev) => ({ ...prev, borderStyleControlPreference: preference }));
4208
4588
  try {
4209
4589
  localStorage.setItem(BORDER_STYLE_CONTROL_PREFERENCE_KEY, preference);
@@ -4218,13 +4598,17 @@ function DirectEditProvider({ children }) {
4218
4598
  commitTextEditing,
4219
4599
  startTextEditing,
4220
4600
  closePanel,
4221
- setState
4601
+ setState,
4602
+ toggleCanvas,
4603
+ setCanvasZoom,
4604
+ fitCanvasToViewport,
4605
+ zoomCanvasTo100
4222
4606
  });
4223
- const stateContextValue = React7.useMemo(() => ({
4607
+ const stateContextValue = React8.useMemo(() => ({
4224
4608
  ...state,
4225
4609
  sessionEditCount
4226
4610
  }), [state, sessionEditCount]);
4227
- const actionsContextValue = React7.useMemo(() => ({
4611
+ const actionsContextValue = React8.useMemo(() => ({
4228
4612
  selectElement,
4229
4613
  selectParent,
4230
4614
  selectChild,
@@ -4263,7 +4647,11 @@ function DirectEditProvider({ children }) {
4263
4647
  clearSessionEdits,
4264
4648
  removeSessionEdit,
4265
4649
  startTextEditing,
4266
- commitTextEditing
4650
+ commitTextEditing,
4651
+ toggleCanvas,
4652
+ setCanvasZoom,
4653
+ fitCanvasToViewport,
4654
+ zoomCanvasTo100
4267
4655
  }), [
4268
4656
  selectElement,
4269
4657
  selectParent,
@@ -4303,7 +4691,11 @@ function DirectEditProvider({ children }) {
4303
4691
  clearSessionEdits,
4304
4692
  removeSessionEdit,
4305
4693
  startTextEditing,
4306
- commitTextEditing
4694
+ commitTextEditing,
4695
+ toggleCanvas,
4696
+ setCanvasZoom,
4697
+ fitCanvasToViewport,
4698
+ zoomCanvasTo100
4307
4699
  ]);
4308
4700
  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
4701
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThemeApplier, {}),
@@ -4313,7 +4705,7 @@ function DirectEditProvider({ children }) {
4313
4705
  function ThemeApplier() {
4314
4706
  const { theme } = useDirectEditState();
4315
4707
  const container = usePortalContainer();
4316
- React7.useEffect(() => {
4708
+ useIsomorphicLayoutEffect(() => {
4317
4709
  if (!container) return;
4318
4710
  const host = container.getRootNode().host;
4319
4711
  if (theme === "system") {
@@ -4326,11 +4718,11 @@ function ThemeApplier() {
4326
4718
  }
4327
4719
 
4328
4720
  // src/panel.tsx
4329
- var React28 = __toESM(require("react"));
4721
+ var React29 = __toESM(require("react"));
4330
4722
  var import_react_dom = require("react-dom");
4331
4723
 
4332
4724
  // src/ui/tooltip.tsx
4333
- var React8 = __toESM(require("react"));
4725
+ var React9 = __toESM(require("react"));
4334
4726
  var import_tooltip = require("@base-ui/react/tooltip");
4335
4727
 
4336
4728
  // src/cn.ts
@@ -4351,14 +4743,14 @@ var TooltipProvider = ({
4351
4743
  }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tooltip.Tooltip.Provider, { delay: delay ?? delayDuration, closeDelay, ...props, children });
4352
4744
  var Tooltip = import_tooltip.Tooltip.Root;
4353
4745
  var TooltipTrigger = import_tooltip.Tooltip.Trigger;
4354
- var TooltipContent = React8.forwardRef(({ className, side, align, sideOffset = 8, ...props }, ref) => {
4746
+ var TooltipContent = React9.forwardRef(({ className, side, align, sideOffset = 8, ...props }, ref) => {
4355
4747
  const container = usePortalContainer();
4356
4748
  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
4749
  import_tooltip.Tooltip.Popup,
4358
4750
  {
4359
4751
  ref,
4360
4752
  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",
4753
+ "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
4754
  className
4363
4755
  ),
4364
4756
  ...props
@@ -4369,23 +4761,23 @@ TooltipContent.displayName = "TooltipContent";
4369
4761
  var createTooltipHandle = import_tooltip.Tooltip.createHandle;
4370
4762
 
4371
4763
  // src/use-measurement.ts
4372
- var React9 = __toESM(require("react"));
4764
+ var React10 = __toESM(require("react"));
4373
4765
  var INITIAL_STATE = {
4374
4766
  hoveredElement: null,
4375
4767
  measurements: []
4376
4768
  };
4377
4769
  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) => {
4770
+ const [altHeld, setAltHeld] = React10.useState(false);
4771
+ const [state, setState] = React10.useState(INITIAL_STATE);
4772
+ const [mousePosition, setMousePosition] = React10.useState(null);
4773
+ const rafRef = React10.useRef(null);
4774
+ const mousePositionRef = React10.useRef(null);
4775
+ const getElementBelow = React10.useCallback((x, y) => {
4384
4776
  const element = elementFromPointWithoutOverlays(x, y);
4385
4777
  if (element?.closest("[data-direct-edit-host]")) return null;
4386
4778
  return element;
4387
4779
  }, []);
4388
- React9.useEffect(() => {
4780
+ React10.useEffect(() => {
4389
4781
  function handleKeyDown(e) {
4390
4782
  if (e.key === "Alt") {
4391
4783
  e.preventDefault();
@@ -4416,7 +4808,7 @@ function useMeasurement(selectedElement) {
4416
4808
  document.removeEventListener("visibilitychange", handleVisibilityChange);
4417
4809
  };
4418
4810
  }, []);
4419
- React9.useEffect(() => {
4811
+ React10.useEffect(() => {
4420
4812
  if (!altHeld || !selectedElement) {
4421
4813
  setState(INITIAL_STATE);
4422
4814
  return;
@@ -4475,7 +4867,7 @@ function useMeasurement(selectedElement) {
4475
4867
  }
4476
4868
 
4477
4869
  // src/measurement-overlay.tsx
4478
- var React10 = __toESM(require("react"));
4870
+ var React11 = __toESM(require("react"));
4479
4871
  var import_jsx_runtime4 = require("react/jsx-runtime");
4480
4872
  var TOMATO = "#E54D2E";
4481
4873
  var BLUE = "#0D99FF";
@@ -4552,16 +4944,18 @@ function MeasurementOverlay({
4552
4944
  hoveredElement,
4553
4945
  measurements
4554
4946
  }) {
4555
- const [, forceUpdate] = React10.useReducer((x) => x + 1, 0);
4556
- React10.useEffect(() => {
4947
+ const [, forceUpdate] = React11.useReducer((x) => x + 1, 0);
4948
+ React11.useEffect(() => {
4557
4949
  function handleUpdate() {
4558
4950
  requestAnimationFrame(forceUpdate);
4559
4951
  }
4560
4952
  window.addEventListener("scroll", handleUpdate, true);
4561
4953
  window.addEventListener("resize", handleUpdate);
4954
+ window.addEventListener("direct-edit-canvas-change", handleUpdate);
4562
4955
  return () => {
4563
4956
  window.removeEventListener("scroll", handleUpdate, true);
4564
4957
  window.removeEventListener("resize", handleUpdate);
4958
+ window.removeEventListener("direct-edit-canvas-change", handleUpdate);
4565
4959
  };
4566
4960
  }, [selectedElement]);
4567
4961
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -4586,7 +4980,7 @@ function MeasurementOverlay({
4586
4980
  }
4587
4981
 
4588
4982
  // src/use-move.ts
4589
- var React11 = __toESM(require("react"));
4983
+ var React12 = __toESM(require("react"));
4590
4984
  var INITIAL_DRAG_STATE = {
4591
4985
  isDragging: false,
4592
4986
  draggedElement: null,
@@ -4597,19 +4991,19 @@ var INITIAL_DRAG_STATE = {
4597
4991
  dragOffset: { x: 0, y: 0 }
4598
4992
  };
4599
4993
  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(() => {
4994
+ const [dragState, setDragState] = React12.useState(INITIAL_DRAG_STATE);
4995
+ const [dropTarget, setDropTarget] = React12.useState(null);
4996
+ const [dropIndicator, setDropIndicator] = React12.useState(null);
4997
+ const dragStateRef = React12.useRef(dragState);
4998
+ const dropTargetRef = React12.useRef(dropTarget);
4999
+ const onMoveCompleteRef = React12.useRef(onMoveComplete);
5000
+ const dragOptionsRef = React12.useRef({});
5001
+ React12.useEffect(() => {
4608
5002
  dragStateRef.current = dragState;
4609
5003
  dropTargetRef.current = dropTarget;
4610
5004
  onMoveCompleteRef.current = onMoveComplete;
4611
5005
  });
4612
- const cancelDrag = React11.useCallback(() => {
5006
+ const cancelDrag = React12.useCallback(() => {
4613
5007
  const current = dragStateRef.current;
4614
5008
  if (current.draggedElement) {
4615
5009
  current.draggedElement.style.opacity = "";
@@ -4619,7 +5013,7 @@ function useMove({ onMoveComplete }) {
4619
5013
  setDropTarget(null);
4620
5014
  setDropIndicator(null);
4621
5015
  }, []);
4622
- const completeDrag = React11.useCallback(() => {
5016
+ const completeDrag = React12.useCallback(() => {
4623
5017
  const current = dragStateRef.current;
4624
5018
  const target = dropTargetRef.current;
4625
5019
  const { draggedElement, originalParent, originalPreviousSibling, originalNextSibling } = current;
@@ -4653,7 +5047,7 @@ function useMove({ onMoveComplete }) {
4653
5047
  onMoveCompleteRef.current(draggedElement, moveInfo);
4654
5048
  }
4655
5049
  }, [cancelDrag]);
4656
- const startDrag = React11.useCallback(
5050
+ const startDrag = React12.useCallback(
4657
5051
  (e, element, options) => {
4658
5052
  const rect = element.getBoundingClientRect();
4659
5053
  const parent = element.parentElement;
@@ -4673,7 +5067,7 @@ function useMove({ onMoveComplete }) {
4673
5067
  },
4674
5068
  []
4675
5069
  );
4676
- React11.useEffect(() => {
5070
+ React12.useEffect(() => {
4677
5071
  if (!dragState.isDragging) return;
4678
5072
  function handlePointerMove(e) {
4679
5073
  const current = dragStateRef.current;
@@ -4741,7 +5135,46 @@ function useMove({ onMoveComplete }) {
4741
5135
  }
4742
5136
 
4743
5137
  // src/use-guidelines.ts
4744
- var React12 = __toESM(require("react"));
5138
+ var React13 = __toESM(require("react"));
5139
+
5140
+ // src/utils/snap-targets.ts
5141
+ var SNAP_THRESHOLD_PX = 6;
5142
+ function collectSnapTargets(orientation) {
5143
+ const edges = [];
5144
+ const elements = document.body.querySelectorAll("*");
5145
+ const viewportW = window.innerWidth;
5146
+ const viewportH = window.innerHeight;
5147
+ for (let i = 0; i < elements.length; i++) {
5148
+ const el = elements[i];
5149
+ if (el === document.body || el === document.documentElement) continue;
5150
+ if (el.closest("[data-direct-edit]") || el.closest("[data-direct-edit-host]")) continue;
5151
+ if (el.offsetParent === null && el !== document.body) continue;
5152
+ const rect = el.getBoundingClientRect();
5153
+ if (rect.width < 4 || rect.height < 4) continue;
5154
+ if (rect.right < -200 || rect.bottom < -200 || rect.left > viewportW + 200 || rect.top > viewportH + 200) continue;
5155
+ if (orientation === "horizontal") {
5156
+ edges.push(rect.top, rect.bottom);
5157
+ } else {
5158
+ edges.push(rect.left, rect.right);
5159
+ }
5160
+ if (edges.length >= 2e3) break;
5161
+ }
5162
+ return edges;
5163
+ }
5164
+ function findSnap(viewportPos, snapEdges, threshold) {
5165
+ let best = null;
5166
+ let bestDist = threshold + 1;
5167
+ for (let i = 0; i < snapEdges.length; i++) {
5168
+ const dist = Math.abs(snapEdges[i] - viewportPos);
5169
+ if (dist < bestDist) {
5170
+ bestDist = dist;
5171
+ best = snapEdges[i];
5172
+ }
5173
+ }
5174
+ return bestDist <= threshold ? best : null;
5175
+ }
5176
+
5177
+ // src/use-guidelines.ts
4745
5178
  var STORAGE_KEY = "direct-edit-guidelines";
4746
5179
  function isGuidelineOrientation(value) {
4747
5180
  return value === "horizontal" || value === "vertical";
@@ -4778,6 +5211,7 @@ function generateId() {
4778
5211
  return `gl-${Date.now()}-${idCounter++}`;
4779
5212
  }
4780
5213
  var RULER_SIZE = 20;
5214
+ var SNAP_VELOCITY_THRESHOLD = 3;
4781
5215
  function viewportToCssCoord(hostElement, value, axis) {
4782
5216
  if (!hostElement) return value;
4783
5217
  const rect = hostElement.getBoundingClientRect();
@@ -4787,68 +5221,108 @@ function viewportToCssCoord(hostElement, value, axis) {
4787
5221
  if (size === 0) return value;
4788
5222
  return (value - origin) * (cssSize / size);
4789
5223
  }
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);
5224
+ function useGuidelines(enabled, hostElement, canvas) {
5225
+ const [guidelines, setGuidelines] = React13.useState([]);
5226
+ const [hydrated, setHydrated] = React13.useState(false);
5227
+ const [activeGuidelineId, setActiveGuidelineId] = React13.useState(null);
5228
+ const [dragPosition, setDragPosition] = React13.useState(null);
5229
+ const [isCreating, setIsCreating] = React13.useState(false);
5230
+ const [scrollOffset, setScrollOffset] = React13.useState({ x: 0, y: 0 });
5231
+ const hostRef = React13.useRef(hostElement ?? null);
4798
5232
  hostRef.current = hostElement ?? null;
4799
- const [dragging, setDragging] = React12.useState(false);
4800
- const guidelinesRef = React12.useRef(guidelines);
5233
+ const canvasRef = React13.useRef(canvas);
5234
+ canvasRef.current = canvas;
5235
+ const [dragging, setDragging] = React13.useState(false);
5236
+ const guidelinesRef = React13.useRef(guidelines);
4801
5237
  guidelinesRef.current = guidelines;
4802
- const dragInfoRef = React12.useRef(null);
4803
- React12.useEffect(() => {
5238
+ const dragInfoRef = React13.useRef(null);
5239
+ const snapTargetsRef = React13.useRef([]);
5240
+ const isSnappedRef = React13.useRef(false);
5241
+ const [isSnapped, setIsSnapped] = React13.useState(false);
5242
+ React13.useEffect(() => {
4804
5243
  setGuidelines(loadGuidelines());
4805
5244
  setHydrated(true);
4806
5245
  }, []);
4807
- React12.useEffect(() => {
5246
+ React13.useEffect(() => {
4808
5247
  if (!hydrated) return;
4809
5248
  saveGuidelines(guidelines);
4810
5249
  }, [guidelines, hydrated]);
4811
- React12.useEffect(() => {
5250
+ React13.useEffect(() => {
4812
5251
  if (!enabled) return;
4813
5252
  function update() {
4814
- setScrollOffset({ x: window.scrollX, y: window.scrollY });
5253
+ setScrollOffset((prev) => {
5254
+ const x = window.scrollX;
5255
+ const y = window.scrollY;
5256
+ return prev.x === x && prev.y === y ? prev : { x, y };
5257
+ });
4815
5258
  }
4816
5259
  update();
4817
5260
  window.addEventListener("scroll", update, true);
4818
5261
  window.addEventListener("resize", update);
5262
+ window.addEventListener("direct-edit-canvas-change", update);
4819
5263
  return () => {
4820
5264
  window.removeEventListener("scroll", update, true);
4821
5265
  window.removeEventListener("resize", update);
5266
+ window.removeEventListener("direct-edit-canvas-change", update);
4822
5267
  };
4823
5268
  }, [enabled]);
4824
- const endDrag = React12.useCallback(() => {
5269
+ const endDrag = React13.useCallback(() => {
4825
5270
  const wasCreating = dragInfoRef.current?.isCreating ?? false;
4826
5271
  dragInfoRef.current = null;
5272
+ snapTargetsRef.current = [];
5273
+ isSnappedRef.current = false;
5274
+ setIsSnapped(false);
4827
5275
  setDragging(false);
4828
5276
  setActiveGuidelineId(null);
4829
5277
  setDragPosition(null);
4830
5278
  if (wasCreating) setIsCreating(false);
4831
5279
  }, []);
4832
- React12.useEffect(() => {
5280
+ React13.useEffect(() => {
4833
5281
  if (!dragging) return;
4834
5282
  const info = dragInfoRef.current;
4835
5283
  if (!info) return;
4836
5284
  const { guidelineId, orientation } = info;
4837
5285
  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
- }
5286
+ let lastPos = NaN;
5287
+ let lastTime = 0;
4842
5288
  function onPointerMove(e) {
4843
- const pos = pointerToPos(e);
5289
+ const rawViewportPos = orientation === "horizontal" ? e.clientY : e.clientX;
5290
+ const now = performance.now();
5291
+ const dt = now - lastTime;
5292
+ const velocity = dt > 0 && !Number.isNaN(lastPos) ? Math.abs(rawViewportPos - lastPos) / dt : 0;
5293
+ lastPos = rawViewportPos;
5294
+ lastTime = now;
5295
+ let effectiveViewportPos = rawViewportPos;
5296
+ let snapped = false;
5297
+ if (velocity < SNAP_VELOCITY_THRESHOLD) {
5298
+ const snapResult = findSnap(rawViewportPos, snapTargetsRef.current, SNAP_THRESHOLD_PX);
5299
+ if (snapResult !== null) {
5300
+ effectiveViewportPos = snapResult;
5301
+ snapped = true;
5302
+ }
5303
+ }
5304
+ isSnappedRef.current = snapped;
5305
+ setIsSnapped(snapped);
5306
+ const pos = viewportToCssCoord(hostRef.current, effectiveViewportPos, axis);
4844
5307
  setDragPosition(pos);
4845
- const currentScroll = orientation === "horizontal" ? window.scrollY : window.scrollX;
5308
+ const c = canvasRef.current;
5309
+ let storedPosition;
5310
+ if (c?.active) {
5311
+ const pan = orientation === "horizontal" ? c.panY || 0 : c.panX || 0;
5312
+ const bo = orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
5313
+ storedPosition = bo + (pos - bo) / (c.zoom || 1) - pan;
5314
+ } else {
5315
+ const currentScroll = orientation === "horizontal" ? window.scrollY : window.scrollX;
5316
+ storedPosition = pos + currentScroll;
5317
+ }
4846
5318
  setGuidelines(
4847
- (prev) => prev.map((g) => g.id === guidelineId ? { ...g, position: pos + currentScroll } : g)
5319
+ (prev) => prev.map((g) => g.id === guidelineId ? { ...g, position: storedPosition } : g)
4848
5320
  );
4849
5321
  }
4850
5322
  function onPointerUp(e) {
4851
- const pos = pointerToPos(e);
5323
+ const rawViewportPos = orientation === "horizontal" ? e.clientY : e.clientX;
5324
+ const snapResult = findSnap(rawViewportPos, snapTargetsRef.current, SNAP_THRESHOLD_PX);
5325
+ const pos = viewportToCssCoord(hostRef.current, snapResult ?? rawViewportPos, axis);
4852
5326
  if (pos <= RULER_SIZE) {
4853
5327
  setGuidelines((prev) => prev.filter((g) => g.id !== guidelineId));
4854
5328
  }
@@ -4861,22 +5335,32 @@ function useGuidelines(enabled, hostElement) {
4861
5335
  window.removeEventListener("pointerup", onPointerUp);
4862
5336
  };
4863
5337
  }, [dragging, endDrag]);
4864
- React12.useEffect(() => {
5338
+ React13.useEffect(() => {
4865
5339
  if (!enabled && dragging) {
4866
5340
  endDrag();
4867
5341
  }
4868
5342
  }, [enabled, dragging, endDrag]);
4869
- const activeGuideline = React12.useMemo(
5343
+ const activeGuideline = React13.useMemo(
4870
5344
  () => guidelines.find((g) => g.id === activeGuidelineId) ?? null,
4871
5345
  [guidelines, activeGuidelineId]
4872
5346
  );
4873
- const startCreate = React12.useCallback(
5347
+ const startCreate = React13.useCallback(
4874
5348
  (orientation, viewportPosition) => {
4875
5349
  const axis = orientation === "horizontal" ? "y" : "x";
4876
5350
  const pos = viewportToCssCoord(hostRef.current, viewportPosition, axis);
4877
- const scrollPos = orientation === "horizontal" ? window.scrollY : window.scrollX;
4878
5351
  const id = generateId();
4879
- const newGuideline = { id, orientation, position: pos + scrollPos };
5352
+ const c = canvasRef.current;
5353
+ let storedPosition;
5354
+ if (c?.active) {
5355
+ const pan = orientation === "horizontal" ? c.panY || 0 : c.panX || 0;
5356
+ const bo = orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
5357
+ storedPosition = bo + (pos - bo) / (c.zoom || 1) - pan;
5358
+ } else {
5359
+ const scrollPos = orientation === "horizontal" ? window.scrollY : window.scrollX;
5360
+ storedPosition = pos + scrollPos;
5361
+ }
5362
+ const newGuideline = { id, orientation, position: storedPosition };
5363
+ snapTargetsRef.current = collectSnapTargets(orientation);
4880
5364
  setGuidelines((prev) => [...prev, newGuideline]);
4881
5365
  setActiveGuidelineId(id);
4882
5366
  setDragPosition(pos);
@@ -4886,19 +5370,29 @@ function useGuidelines(enabled, hostElement) {
4886
5370
  },
4887
5371
  []
4888
5372
  );
4889
- const startDrag = React12.useCallback((guidelineId) => {
5373
+ const startDrag = React13.useCallback((guidelineId) => {
4890
5374
  const guideline = guidelinesRef.current.find((g) => g.id === guidelineId);
4891
5375
  if (!guideline) return;
4892
- const scrollPos = guideline.orientation === "horizontal" ? window.scrollY : window.scrollX;
5376
+ snapTargetsRef.current = collectSnapTargets(guideline.orientation);
5377
+ const c = canvasRef.current;
5378
+ let viewportPos;
5379
+ if (c?.active) {
5380
+ const pan = guideline.orientation === "horizontal" ? c.panY || 0 : c.panX || 0;
5381
+ const bo = guideline.orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
5382
+ viewportPos = bo + (guideline.position - bo + pan) * (c.zoom || 1);
5383
+ } else {
5384
+ const scrollPos = guideline.orientation === "horizontal" ? window.scrollY : window.scrollX;
5385
+ viewportPos = guideline.position - scrollPos;
5386
+ }
4893
5387
  setActiveGuidelineId(guidelineId);
4894
- setDragPosition(guideline.position - scrollPos);
5388
+ setDragPosition(viewportPos);
4895
5389
  dragInfoRef.current = { guidelineId, orientation: guideline.orientation, isCreating: false };
4896
5390
  setDragging(true);
4897
5391
  }, []);
4898
- const deleteGuideline = React12.useCallback((guidelineId) => {
5392
+ const deleteGuideline = React13.useCallback((guidelineId) => {
4899
5393
  setGuidelines((prev) => prev.filter((g) => g.id !== guidelineId));
4900
5394
  }, []);
4901
- const clearAll = React12.useCallback(() => {
5395
+ const clearAll = React13.useCallback(() => {
4902
5396
  setGuidelines([]);
4903
5397
  }, []);
4904
5398
  return {
@@ -4906,6 +5400,7 @@ function useGuidelines(enabled, hostElement) {
4906
5400
  activeGuideline,
4907
5401
  dragPosition,
4908
5402
  isCreating,
5403
+ isSnapped,
4909
5404
  scrollOffset,
4910
5405
  startCreate,
4911
5406
  startDrag,
@@ -4960,10 +5455,8 @@ function InteractionOverlay({
4960
5455
  if (activeTool === "comment") {
4961
5456
  if (hasPendingCommentDraft()) return;
4962
5457
  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
- }
5458
+ const target = elementUnder2 && elementUnder2 !== document.body && elementUnder2 !== document.documentElement ? resolveElementTarget(elementUnder2, selectedElement) : document.body;
5459
+ onAddComment(target, { x: e.clientX, y: e.clientY });
4967
5460
  return;
4968
5461
  }
4969
5462
  if (activeCommentId) {
@@ -4981,39 +5474,41 @@ function InteractionOverlay({
4981
5474
  hoverHighlight && (() => {
4982
5475
  const cr = hoverHighlight.flexContainer.getBoundingClientRect();
4983
5476
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
4984
- "svg",
5477
+ "div",
4985
5478
  {
4986
5479
  "data-direct-edit": "hover-highlight",
4987
5480
  className: "pointer-events-none fixed inset-0 z-[99991]",
4988
- width: "100%",
4989
- height: "100%",
4990
- style: { width: "100vw", height: "100vh" },
4991
5481
  children: [
4992
5482
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4993
- "rect",
5483
+ "div",
4994
5484
  {
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
5485
+ style: {
5486
+ position: "absolute",
5487
+ left: cr.left,
5488
+ top: cr.top,
5489
+ width: cr.width,
5490
+ height: cr.height,
5491
+ border: "1px solid #3b82f6",
5492
+ borderRadius: "0px",
5493
+ boxSizing: "border-box"
5494
+ }
5002
5495
  }
5003
5496
  ),
5004
5497
  hoverHighlight.children.map((child) => {
5005
5498
  const r = child.getBoundingClientRect();
5006
5499
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5007
- "rect",
5500
+ "div",
5008
5501
  {
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"
5502
+ style: {
5503
+ position: "absolute",
5504
+ left: r.left,
5505
+ top: r.top,
5506
+ width: r.width,
5507
+ height: r.height,
5508
+ border: "1px dashed #3b82f6",
5509
+ borderRadius: "0px",
5510
+ boxSizing: "border-box"
5511
+ }
5017
5512
  },
5018
5513
  `${r.left}-${r.top}-${r.width}-${r.height}`
5019
5514
  );
@@ -5059,7 +5554,7 @@ function MoveOverlay({ dropIndicator }) {
5059
5554
  }
5060
5555
 
5061
5556
  // src/selection-overlay.tsx
5062
- var React13 = __toESM(require("react"));
5557
+ var React14 = __toESM(require("react"));
5063
5558
  var import_jsx_runtime7 = require("react/jsx-runtime");
5064
5559
  var BLUE3 = "#0D99FF";
5065
5560
  var MAGENTA = "#E11BB6";
@@ -5073,23 +5568,25 @@ function SelectionOverlay({
5073
5568
  ghostPosition,
5074
5569
  onMoveStart,
5075
5570
  showMoveHandle = false,
5571
+ activeTool = "select",
5076
5572
  isTextEditing,
5077
5573
  onDoubleClick,
5078
5574
  onHoverElement,
5079
5575
  onClickThrough
5080
5576
  }) {
5081
5577
  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(() => {
5578
+ const [rect, setRect] = React14.useState(() => rectElement.getBoundingClientRect());
5579
+ const [moveHandleRects, setMoveHandleRects] = React14.useState([]);
5580
+ const cleanupRef = React14.useRef(null);
5581
+ const clickThroughTimerRef = React14.useRef(null);
5582
+ React14.useEffect(() => {
5087
5583
  function updateRect() {
5088
5584
  setRect(rectElement.getBoundingClientRect());
5089
5585
  }
5090
5586
  updateRect();
5091
5587
  window.addEventListener("scroll", updateRect, true);
5092
5588
  window.addEventListener("resize", updateRect);
5589
+ window.addEventListener("direct-edit-canvas-change", updateRect);
5093
5590
  const observer = new MutationObserver(updateRect);
5094
5591
  observer.observe(rectElement, {
5095
5592
  attributes: true,
@@ -5099,10 +5596,11 @@ function SelectionOverlay({
5099
5596
  return () => {
5100
5597
  window.removeEventListener("scroll", updateRect, true);
5101
5598
  window.removeEventListener("resize", updateRect);
5599
+ window.removeEventListener("direct-edit-canvas-change", updateRect);
5102
5600
  observer.disconnect();
5103
5601
  };
5104
5602
  }, [rectElement]);
5105
- React13.useEffect(() => {
5603
+ React14.useEffect(() => {
5106
5604
  return () => {
5107
5605
  cleanupRef.current?.();
5108
5606
  if (clickThroughTimerRef.current) clearTimeout(clickThroughTimerRef.current);
@@ -5163,7 +5661,7 @@ function SelectionOverlay({
5163
5661
  const handleMouseLeave = () => {
5164
5662
  onHoverElement?.(null);
5165
5663
  };
5166
- const getMoveHandleTargets = React13.useCallback(() => {
5664
+ const getMoveHandleTargets = React14.useCallback(() => {
5167
5665
  if (!showMoveHandle) return [];
5168
5666
  const selectedDisplay = window.getComputedStyle(selectedElement).display;
5169
5667
  const selectedIsFlexContainer = selectedDisplay === "flex" || selectedDisplay === "inline-flex";
@@ -5188,7 +5686,7 @@ function SelectionOverlay({
5188
5686
  }
5189
5687
  return [target];
5190
5688
  }, [selectedElement, showMoveHandle]);
5191
- React13.useEffect(() => {
5689
+ React14.useEffect(() => {
5192
5690
  if (!showMoveHandle || isDragging || isTextEditing) {
5193
5691
  setMoveHandleRects([]);
5194
5692
  return;
@@ -5228,30 +5726,22 @@ function SelectionOverlay({
5228
5726
  const displayX = isDragging && ghostPosition ? ghostPosition.x : rect.left;
5229
5727
  const displayY = isDragging && ghostPosition ? ghostPosition.y : rect.top;
5230
5728
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
5231
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5232
- "svg",
5729
+ !isTextEditing && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5730
+ "div",
5233
5731
  {
5234
5732
  "data-direct-edit": "selection-overlay",
5235
5733
  style: {
5236
5734
  position: "fixed",
5237
- inset: 0,
5238
- width: "100vw",
5239
- height: "100vh",
5735
+ left: displayX,
5736
+ top: displayY,
5737
+ width: rect.width,
5738
+ height: rect.height,
5240
5739
  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
- )
5740
+ zIndex: 99996,
5741
+ border: `1px solid ${BLUE3}`,
5742
+ borderRadius: "0px",
5743
+ boxSizing: "border-box"
5744
+ }
5255
5745
  }
5256
5746
  ),
5257
5747
  !isDragging && !isTextEditing && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -5266,7 +5756,7 @@ function SelectionOverlay({
5266
5756
  height: rect.height,
5267
5757
  zIndex: 99996,
5268
5758
  cursor: "default",
5269
- pointerEvents: "auto"
5759
+ pointerEvents: activeTool === "comment" ? "none" : "auto"
5270
5760
  },
5271
5761
  onPointerDown: handlePointerDown,
5272
5762
  onDoubleClick: handleDoubleClick,
@@ -5308,7 +5798,7 @@ function SelectionOverlay({
5308
5798
  }
5309
5799
 
5310
5800
  // src/comment-overlay.tsx
5311
- var React14 = __toESM(require("react"));
5801
+ var React15 = __toESM(require("react"));
5312
5802
  var import_lucide_react = require("lucide-react");
5313
5803
  var import_jsx_runtime8 = require("react/jsx-runtime");
5314
5804
  function formatRelativeTime(timestamp) {
@@ -5348,7 +5838,8 @@ function CommentOverlay({
5348
5838
  onDelete,
5349
5839
  onExport,
5350
5840
  onSendToAgent,
5351
- attentionRequest = null
5841
+ attentionRequest = null,
5842
+ draftRef
5352
5843
  }) {
5353
5844
  if (comments.length === 0) return null;
5354
5845
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: comments.map((comment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
@@ -5364,7 +5855,8 @@ function CommentOverlay({
5364
5855
  onDelete: () => onDelete(comment.id),
5365
5856
  onExport: onExport ? () => onExport(comment.id) : void 0,
5366
5857
  onSendToAgent: () => onSendToAgent(comment.id),
5367
- attentionNonce: attentionRequest?.commentId === comment.id ? attentionRequest.nonce : 0
5858
+ attentionNonce: attentionRequest?.commentId === comment.id ? attentionRequest.nonce : 0,
5859
+ draftRef: activeCommentId === comment.id ? draftRef : void 0
5368
5860
  },
5369
5861
  comment.id
5370
5862
  )) });
@@ -5380,31 +5872,34 @@ function CommentPin({
5380
5872
  onDelete,
5381
5873
  onExport,
5382
5874
  onSendToAgent,
5383
- attentionNonce
5875
+ attentionNonce,
5876
+ draftRef
5384
5877
  }) {
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(() => {
5878
+ const [position, setPosition] = React15.useState(comment.clickPosition);
5879
+ const [elementRect, setElementRect] = React15.useState(null);
5880
+ const [flipHorizontal, setFlipHorizontal] = React15.useState(false);
5881
+ const [flipVertical, setFlipVertical] = React15.useState(false);
5882
+ React15.useEffect(() => {
5390
5883
  function updatePosition() {
5391
5884
  if (!comment.element.isConnected) return;
5392
5885
  const rect = comment.element.getBoundingClientRect();
5393
5886
  setPosition({
5394
- x: rect.left + comment.relativePosition.x,
5395
- y: rect.top + comment.relativePosition.y
5887
+ x: rect.left + comment.relativePosition.x * rect.width,
5888
+ y: rect.top + comment.relativePosition.y * rect.height
5396
5889
  });
5397
5890
  setElementRect(rect);
5398
5891
  }
5399
5892
  updatePosition();
5400
5893
  window.addEventListener("scroll", updatePosition, true);
5401
5894
  window.addEventListener("resize", updatePosition);
5895
+ window.addEventListener("direct-edit-canvas-change", updatePosition);
5402
5896
  return () => {
5403
5897
  window.removeEventListener("scroll", updatePosition, true);
5404
5898
  window.removeEventListener("resize", updatePosition);
5899
+ window.removeEventListener("direct-edit-canvas-change", updatePosition);
5405
5900
  };
5406
5901
  }, [comment.element, comment.relativePosition]);
5407
- React14.useEffect(() => {
5902
+ React15.useEffect(() => {
5408
5903
  if (isActive) {
5409
5904
  const hasText = comment.text !== "";
5410
5905
  const cardWidth = hasText ? 280 : 220;
@@ -5470,7 +5965,8 @@ function CommentPin({
5470
5965
  onUpdateText(text);
5471
5966
  },
5472
5967
  onCancel: onClose,
5473
- attentionNonce
5968
+ attentionNonce,
5969
+ draftRef
5474
5970
  }
5475
5971
  ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5476
5972
  CommentThread,
@@ -5497,16 +5993,17 @@ function NewCommentInput({
5497
5993
  flipVertical,
5498
5994
  onSubmit,
5499
5995
  onCancel,
5500
- attentionNonce
5996
+ attentionNonce,
5997
+ draftRef
5501
5998
  }) {
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(() => {
5999
+ const [text, setText] = React15.useState("");
6000
+ const [showError, setShowError] = React15.useState(false);
6001
+ const inputRef = React15.useRef(null);
6002
+ const cardRef = React15.useRef(null);
6003
+ React15.useEffect(() => {
5507
6004
  inputRef.current?.focus();
5508
6005
  }, []);
5509
- React14.useEffect(() => {
6006
+ React15.useEffect(() => {
5510
6007
  if (attentionNonce <= 0) return;
5511
6008
  setShowError(true);
5512
6009
  cardRef.current?.animate?.(
@@ -5553,7 +6050,10 @@ function NewCommentInput({
5553
6050
  ),
5554
6051
  placeholder: "Add a comment...",
5555
6052
  value: text,
5556
- onChange: (e) => setText(e.target.value),
6053
+ onChange: (e) => {
6054
+ setText(e.target.value);
6055
+ if (draftRef) draftRef.current = e.target.value;
6056
+ },
5557
6057
  onKeyDown: (e) => {
5558
6058
  e.stopPropagation();
5559
6059
  if (e.key === "Enter" && text.trim()) {
@@ -5595,15 +6095,15 @@ function CommentThread({
5595
6095
  onExport,
5596
6096
  onSendToAgent
5597
6097
  }) {
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(() => {
6098
+ const [replyText, setReplyText] = React15.useState("");
6099
+ const [copied, setCopied] = React15.useState(false);
6100
+ const [sendStatus, setSendStatus] = React15.useState("idle");
6101
+ const inputRef = React15.useRef(null);
6102
+ const copyTimerRef = React15.useRef(null);
6103
+ React15.useEffect(() => {
5604
6104
  inputRef.current?.focus();
5605
6105
  }, []);
5606
- React14.useEffect(() => {
6106
+ React15.useEffect(() => {
5607
6107
  return () => {
5608
6108
  if (copyTimerRef.current) {
5609
6109
  window.clearTimeout(copyTimerRef.current);
@@ -5791,12 +6291,12 @@ function CommentThread({
5791
6291
  }
5792
6292
 
5793
6293
  // src/panel/shared.tsx
5794
- var React16 = __toESM(require("react"));
6294
+ var React17 = __toESM(require("react"));
5795
6295
 
5796
6296
  // src/ui/input.tsx
5797
- var React15 = __toESM(require("react"));
6297
+ var React16 = __toESM(require("react"));
5798
6298
  var import_jsx_runtime9 = require("react/jsx-runtime");
5799
- var Input = React15.forwardRef(
6299
+ var Input = React16.forwardRef(
5800
6300
  ({ className, type, ...props }, ref) => {
5801
6301
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
5802
6302
  "input",
@@ -5818,8 +6318,8 @@ Input.displayName = "Input";
5818
6318
  var import_jsx_runtime10 = require("react/jsx-runtime");
5819
6319
  var selectOnFocus = (e) => e.target.select();
5820
6320
  function NumberInput({ value: propValue, onValueChange, ...props }) {
5821
- const [localValue, setLocalValue] = React16.useState(propValue === null ? "" : String(propValue));
5822
- React16.useEffect(() => {
6321
+ const [localValue, setLocalValue] = React17.useState(propValue === null ? "" : String(propValue));
6322
+ React17.useEffect(() => {
5823
6323
  setLocalValue(propValue === null ? "" : String(propValue));
5824
6324
  }, [propValue]);
5825
6325
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -5866,9 +6366,9 @@ var SECTION_LABELS = {
5866
6366
  text: "Text"
5867
6367
  };
5868
6368
  function useSectionNav(sectionRefs) {
5869
- const scrollRef = React16.useRef(null);
5870
- const [activeSection, setActiveSection] = React16.useState("layout");
5871
- React16.useEffect(() => {
6369
+ const scrollRef = React17.useRef(null);
6370
+ const [activeSection, setActiveSection] = React17.useState("layout");
6371
+ React17.useEffect(() => {
5872
6372
  const scrollEl = scrollRef.current;
5873
6373
  if (!scrollEl) return;
5874
6374
  const handleScroll = () => {
@@ -5929,10 +6429,10 @@ function SectionNav({
5929
6429
  }
5930
6430
 
5931
6431
  // src/panel/border-radius-inputs.tsx
5932
- var React19 = __toESM(require("react"));
6432
+ var React20 = __toESM(require("react"));
5933
6433
 
5934
6434
  // src/ui/button.tsx
5935
- var React17 = __toESM(require("react"));
6435
+ var React18 = __toESM(require("react"));
5936
6436
  var import_jsx_runtime11 = require("react/jsx-runtime");
5937
6437
  var buttonVariants = {
5938
6438
  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 +6451,7 @@ var buttonVariants = {
5951
6451
  icon: "h-10 w-10"
5952
6452
  }
5953
6453
  };
5954
- var Button = React17.forwardRef(
6454
+ var Button = React18.forwardRef(
5955
6455
  ({ className, variant = "default", size = "default", ...props }, ref) => {
5956
6456
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5957
6457
  "button",
@@ -5971,10 +6471,10 @@ var Button = React17.forwardRef(
5971
6471
  Button.displayName = "Button";
5972
6472
 
5973
6473
  // src/ui/slider.tsx
5974
- var React18 = __toESM(require("react"));
6474
+ var React19 = __toESM(require("react"));
5975
6475
  var import_slider = require("@base-ui/react/slider");
5976
6476
  var import_jsx_runtime12 = require("react/jsx-runtime");
5977
- var Slider = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6477
+ var Slider = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5978
6478
  import_slider.Slider.Root,
5979
6479
  {
5980
6480
  ref,
@@ -6009,7 +6509,7 @@ function RadiusCornerIcon({ corner, className }) {
6009
6509
  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
6510
  }
6011
6511
  function BorderRadiusInputs({ values, onChange }) {
6012
- const [individual, setIndividual] = React19.useState(false);
6512
+ const [individual, setIndividual] = React20.useState(false);
6013
6513
  const handleChange = (corners, numericValue) => {
6014
6514
  const newValue = {
6015
6515
  numericValue,
@@ -6142,7 +6642,7 @@ function BorderRadiusInputs({ values, onChange }) {
6142
6642
  }
6143
6643
 
6144
6644
  // src/panel/border-section.tsx
6145
- var React22 = __toESM(require("react"));
6645
+ var React23 = __toESM(require("react"));
6146
6646
 
6147
6647
  // src/ui/select.tsx
6148
6648
  var import_select = require("@base-ui/react/select");
@@ -6207,21 +6707,21 @@ function SimpleSelect({
6207
6707
  }
6208
6708
 
6209
6709
  // src/ui/color-picker.tsx
6210
- var React20 = __toESM(require("react"));
6710
+ var React21 = __toESM(require("react"));
6211
6711
  var import_popover = require("@base-ui/react/popover");
6212
6712
  var import_jsx_runtime16 = require("react/jsx-runtime");
6213
6713
  function ColorPickerPortal(props) {
6214
6714
  const container = usePortalContainer();
6215
6715
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_popover.Popover.Portal, { container, ...props });
6216
6716
  }
6217
- var ColorPickerGroupContext = React20.createContext(null);
6717
+ var ColorPickerGroupContext = React21.createContext(null);
6218
6718
  function ColorPickerGroup({ children }) {
6219
- const [activePickerId, setActivePickerId] = React20.useState(null);
6719
+ const [activePickerId, setActivePickerId] = React21.useState(null);
6220
6720
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorPickerGroupContext.Provider, { value: { activePickerId, setActivePickerId }, children });
6221
6721
  }
6222
6722
  function useDrag(onMove) {
6223
- const ref = React20.useRef(null);
6224
- const handlePointerEvent = React20.useCallback(
6723
+ const ref = React21.useRef(null);
6724
+ const handlePointerEvent = React21.useCallback(
6225
6725
  (e) => {
6226
6726
  const el = ref.current;
6227
6727
  if (!el) return;
@@ -6232,7 +6732,7 @@ function useDrag(onMove) {
6232
6732
  },
6233
6733
  [onMove]
6234
6734
  );
6235
- const onPointerDown = React20.useCallback(
6735
+ const onPointerDown = React21.useCallback(
6236
6736
  (e) => {
6237
6737
  e.preventDefault();
6238
6738
  ref.current?.setPointerCapture(e.pointerId);
@@ -6240,7 +6740,7 @@ function useDrag(onMove) {
6240
6740
  },
6241
6741
  [handlePointerEvent]
6242
6742
  );
6243
- const onPointerMove = React20.useCallback(
6743
+ const onPointerMove = React21.useCallback(
6244
6744
  (e) => {
6245
6745
  if (e.buttons === 0) return;
6246
6746
  handlePointerEvent(e);
@@ -6310,8 +6810,8 @@ function NumericInput({
6310
6810
  max,
6311
6811
  onChange
6312
6812
  }) {
6313
- const [local, setLocal] = React20.useState(Math.round(value).toString());
6314
- React20.useEffect(() => {
6813
+ const [local, setLocal] = React21.useState(Math.round(value).toString());
6814
+ React21.useEffect(() => {
6315
6815
  setLocal(Math.round(value).toString());
6316
6816
  }, [value]);
6317
6817
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-1", children: [
@@ -6333,13 +6833,13 @@ function NumericInput({
6333
6833
  ] });
6334
6834
  }
6335
6835
  function ColorPickerPopover({ id, value, onChange, children }) {
6336
- const group = React20.useContext(ColorPickerGroupContext);
6836
+ const group = React21.useContext(ColorPickerGroupContext);
6337
6837
  const rgb = hexToRgb(value.hex);
6338
6838
  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(() => {
6839
+ const [hsv, setHsv] = React21.useState({ h: initialHsv.h, s: initialHsv.s, v: initialHsv.v });
6840
+ const [alpha, setAlpha] = React21.useState(value.alpha);
6841
+ const lastSyncedHex = React21.useRef(value.hex);
6842
+ React21.useEffect(() => {
6343
6843
  if (value.hex !== lastSyncedHex.current) {
6344
6844
  const newRgb = hexToRgb(value.hex);
6345
6845
  const newHsv = rgbToHsv(newRgb.r, newRgb.g, newRgb.b);
@@ -6352,7 +6852,7 @@ function ColorPickerPopover({ id, value, onChange, children }) {
6352
6852
  }
6353
6853
  setAlpha(value.alpha);
6354
6854
  }, [value.hex, value.alpha]);
6355
- const emitChange = React20.useCallback(
6855
+ const emitChange = React21.useCallback(
6356
6856
  (h, s, v, a) => {
6357
6857
  const newRgb = hsvToRgb(h, s, v);
6358
6858
  const hex = rgbToHex(newRgb.r, newRgb.g, newRgb.b);
@@ -6433,11 +6933,11 @@ function ColorPickerPopover({ id, value, onChange, children }) {
6433
6933
  const handleOpenChange = isControlled ? (open) => {
6434
6934
  group.setActivePickerId(open ? id : null);
6435
6935
  } : void 0;
6436
- const popupRef = React20.useRef(null);
6437
- const triggerRef = React20.useRef(null);
6438
- const onCloseRef = React20.useRef();
6936
+ const popupRef = React21.useRef(null);
6937
+ const triggerRef = React21.useRef(null);
6938
+ const onCloseRef = React21.useRef();
6439
6939
  onCloseRef.current = () => group?.setActivePickerId(null);
6440
- React20.useEffect(() => {
6940
+ React21.useEffect(() => {
6441
6941
  if (!isOpen) return;
6442
6942
  function handlePointerDown(e) {
6443
6943
  const path = e.composedPath();
@@ -6507,8 +7007,8 @@ function ColorPickerPopover({ id, value, onChange, children }) {
6507
7007
  ] });
6508
7008
  }
6509
7009
  function HexInput({ value, onChange }) {
6510
- const [local, setLocal] = React20.useState(value);
6511
- React20.useEffect(() => {
7010
+ const [local, setLocal] = React21.useState(value);
7011
+ React21.useEffect(() => {
6512
7012
  setLocal(value);
6513
7013
  }, [value]);
6514
7014
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -6527,8 +7027,8 @@ function HexInput({ value, onChange }) {
6527
7027
  );
6528
7028
  }
6529
7029
  function AlphaInput({ value, onChange }) {
6530
- const [local, setLocal] = React20.useState(value.toString());
6531
- React20.useEffect(() => {
7030
+ const [local, setLocal] = React21.useState(value.toString());
7031
+ React21.useEffect(() => {
6532
7032
  setLocal(value.toString());
6533
7033
  }, [value]);
6534
7034
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -6548,13 +7048,13 @@ function AlphaInput({ value, onChange }) {
6548
7048
  }
6549
7049
 
6550
7050
  // src/panel/fill-section.tsx
6551
- var React21 = __toESM(require("react"));
7051
+ var React22 = __toESM(require("react"));
6552
7052
  var import_lucide_react4 = require("lucide-react");
6553
7053
  var import_jsx_runtime17 = require("react/jsx-runtime");
6554
7054
  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(() => {
7055
+ const [hexInput, setHexInput] = React22.useState(value.hex);
7056
+ const [alphaInput, setAlphaInput] = React22.useState(value.alpha.toString());
7057
+ React22.useEffect(() => {
6558
7058
  setHexInput(value.hex);
6559
7059
  setAlphaInput(value.alpha.toString());
6560
7060
  }, [value.hex, value.alpha]);
@@ -6745,7 +7245,7 @@ function BorderSideIcon({ side, className }) {
6745
7245
  ] });
6746
7246
  }
6747
7247
  function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChange, onBorderColorChange, onOutlineColorChange, onSetCSS, borderPosition, borderStyleControlPreference, onPositionChange, outlineStyle, outlineWidth }) {
6748
- const [selectedSide, setSelectedSide] = React22.useState("All");
7248
+ const [selectedSide, setSelectedSide] = React23.useState("All");
6749
7249
  const isOutline = borderPosition === "outline";
6750
7250
  const activeSides = selectedSide === "All" || selectedSide === "Custom" ? BORDER_SIDES : [selectedSide];
6751
7251
  const stylesMatch = activeSides.every(
@@ -6857,7 +7357,7 @@ function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChan
6857
7357
  onValueChange: (val) => handleStyleChange(val),
6858
7358
  options: BORDER_STYLE_OPTIONS,
6859
7359
  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: [
7360
+ 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
7361
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "flex items-center gap-1.5", children: [
6862
7362
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react5.Square, { className: "size-3.5 text-muted-foreground" }),
6863
7363
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: currentStyleLabel })
@@ -6873,7 +7373,7 @@ function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChan
6873
7373
  onValueChange: (val) => handleSideChange(val),
6874
7374
  options: BORDER_SIDE_OPTIONS.map((side) => ({ value: side, label: side })),
6875
7375
  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" }) }) })
7376
+ 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
7377
  }
6878
7378
  )
6879
7379
  ] }),
@@ -6893,23 +7393,27 @@ function BorderInputs({ border, borderColor, outlineColor, onChange, onBatchChan
6893
7393
  )
6894
7394
  ] }) }, side);
6895
7395
  }) }),
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
- )
7396
+ activeColor && activeColorChange && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1.5", children: [
7397
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7398
+ ColorInput,
7399
+ {
7400
+ id: isOutline ? "outline-color" : "border-color",
7401
+ label: isOutline ? "Outline" : "Border",
7402
+ 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" }),
7403
+ value: activeColor,
7404
+ onChange: activeColorChange
7405
+ }
7406
+ ) }),
7407
+ borderStyleControlPreference === "icon" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "w-[30px] shrink-0" }),
7408
+ !isOutline && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "w-[30px] shrink-0" })
7409
+ ] })
6906
7410
  ] });
6907
7411
  }
6908
7412
  function BorderSection({ border, borderColor, outlineColor, borderStyleControlPreference, onChange, onBatchChange, onBorderColorChange, onOutlineColorChange, onSetCSS, pendingStyles }) {
6909
7413
  const hasOutlinePending = Boolean(
6910
7414
  pendingStyles?.["outline-style"] || pendingStyles?.["outline-width"]
6911
7415
  );
6912
- const [borderPosition, setBorderPosition] = React22.useState(
7416
+ const [borderPosition, setBorderPosition] = React23.useState(
6913
7417
  hasOutlinePending ? "outline" : "border"
6914
7418
  );
6915
7419
  const isOutline = borderPosition === "outline";
@@ -7015,7 +7519,7 @@ function BorderSection({ border, borderColor, outlineColor, borderStyleControlPr
7015
7519
  }
7016
7520
 
7017
7521
  // src/panel/shadow-section.tsx
7018
- var React23 = __toESM(require("react"));
7522
+ var React24 = __toESM(require("react"));
7019
7523
 
7020
7524
  // src/shadow-utils.ts
7021
7525
  var TAILWIND_SHADOW_PRESETS = [
@@ -7152,9 +7656,9 @@ function ShadowLayerEditor({
7152
7656
  onChange,
7153
7657
  onRemoveLayer
7154
7658
  }) {
7155
- const [hexInput, setHexInput] = React23.useState(layer.color.hex);
7156
- const [alphaInput, setAlphaInput] = React23.useState(String(layer.color.alpha));
7157
- React23.useEffect(() => {
7659
+ const [hexInput, setHexInput] = React24.useState(layer.color.hex);
7660
+ const [alphaInput, setAlphaInput] = React24.useState(String(layer.color.alpha));
7661
+ React24.useEffect(() => {
7158
7662
  setHexInput(layer.color.hex);
7159
7663
  setAlphaInput(String(layer.color.alpha));
7160
7664
  }, [layer.color.hex, layer.color.alpha]);
@@ -7245,10 +7749,10 @@ function ShadowLayerEditor({
7245
7749
  }
7246
7750
  function ShadowSection({ boxShadow, onSetCSS, pendingStyles }) {
7247
7751
  const effectiveShadow = (pendingStyles?.["box-shadow"] ?? boxShadow ?? "none").trim();
7248
- const parsedLayers = React23.useMemo(() => parseShadowLayers(effectiveShadow), [effectiveShadow]);
7249
- const [layers, setLayers] = React23.useState(parsedLayers);
7752
+ const parsedLayers = React24.useMemo(() => parseShadowLayers(effectiveShadow), [effectiveShadow]);
7753
+ const [layers, setLayers] = React24.useState(parsedLayers);
7250
7754
  const hasShadow = layers.length > 0;
7251
- React23.useEffect(() => {
7755
+ React24.useEffect(() => {
7252
7756
  setLayers(parsedLayers);
7253
7757
  }, [parsedLayers]);
7254
7758
  const commitLayers = (nextLayers) => {
@@ -7540,7 +8044,7 @@ function PanelHeader({
7540
8044
  }
7541
8045
 
7542
8046
  // src/panel/panel-footer.tsx
7543
- var React24 = __toESM(require("react"));
8047
+ var React25 = __toESM(require("react"));
7544
8048
  var import_lucide_react9 = require("lucide-react");
7545
8049
  var import_jsx_runtime22 = require("react/jsx-runtime");
7546
8050
  var panelBarBaseClass2 = "flex h-11 shrink-0 items-center border-border/50 bg-background pl-3 pr-2";
@@ -7554,9 +8058,9 @@ function PanelFooter({
7554
8058
  onPointerUp,
7555
8059
  onPointerCancel
7556
8060
  }) {
7557
- const [copied, setCopied] = React24.useState(false);
7558
- const [copyError, setCopyError] = React24.useState(false);
7559
- const [sendStatus, setSendStatus] = React24.useState("idle");
8061
+ const [copied, setCopied] = React25.useState(false);
8062
+ const [copyError, setCopyError] = React25.useState(false);
8063
+ const [sendStatus, setSendStatus] = React25.useState("idle");
7560
8064
  const handleCopy = async () => {
7561
8065
  const success = await onExportEdits();
7562
8066
  if (success) {
@@ -7624,11 +8128,11 @@ function PanelFooter({
7624
8128
  }
7625
8129
 
7626
8130
  // src/panel/spacing-inputs.tsx
7627
- var React25 = __toESM(require("react"));
8131
+ var React26 = __toESM(require("react"));
7628
8132
  var import_lucide_react10 = require("lucide-react");
7629
8133
  var import_jsx_runtime23 = require("react/jsx-runtime");
7630
8134
  function SpacingInputs({ prefix, values, onChange }) {
7631
- const [individual, setIndividual] = React25.useState(false);
8135
+ const [individual, setIndividual] = React26.useState(false);
7632
8136
  const allowNegative = prefix === "margin";
7633
8137
  const handleChange = (sides, numericValue) => {
7634
8138
  const clamped = allowNegative ? numericValue : Math.max(0, numericValue);
@@ -7746,7 +8250,7 @@ function SpacingInputs({ prefix, values, onChange }) {
7746
8250
  }
7747
8251
 
7748
8252
  // src/panel/sizing-inputs.tsx
7749
- var React26 = __toESM(require("react"));
8253
+ var React27 = __toESM(require("react"));
7750
8254
  var import_lucide_react11 = require("lucide-react");
7751
8255
  var import_jsx_runtime24 = require("react/jsx-runtime");
7752
8256
  var SIZING_OPTIONS = [
@@ -7762,8 +8266,8 @@ var DISTRIBUTE_LABELS = {
7762
8266
  "space-evenly": "Evenly"
7763
8267
  };
7764
8268
  function SizingFixedInput({ value, onValueChange }) {
7765
- const [localValue, setLocalValue] = React26.useState(String(value));
7766
- React26.useEffect(() => {
8269
+ const [localValue, setLocalValue] = React27.useState(String(value));
8270
+ React27.useEffect(() => {
7767
8271
  setLocalValue(String(value));
7768
8272
  }, [value]);
7769
8273
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
@@ -7824,9 +8328,9 @@ function SizingDropdown({ label, value, onChange }) {
7824
8328
  }
7825
8329
  function SizingInputs({ width, height, onWidthChange, onHeightChange }) {
7826
8330
  const { selectedElement } = useDirectEditState();
7827
- const [locked, setLocked] = React26.useState(false);
7828
- const ratioRef = React26.useRef(1);
7829
- React26.useEffect(() => {
8331
+ const [locked, setLocked] = React27.useState(false);
8332
+ const ratioRef = React27.useRef(1);
8333
+ React27.useEffect(() => {
7830
8334
  setLocked(false);
7831
8335
  }, [selectedElement]);
7832
8336
  const canLock = width.mode === "fixed" && height.mode === "fixed" && height.value.numericValue > 0 && width.value.numericValue > 0;
@@ -8082,7 +8586,7 @@ function LayoutSection({
8082
8586
  }
8083
8587
 
8084
8588
  // src/use-panel-position.ts
8085
- var React27 = __toESM(require("react"));
8589
+ var React28 = __toESM(require("react"));
8086
8590
  var PANEL_WIDTH = 300;
8087
8591
  var PANEL_HEIGHT = 420;
8088
8592
  var STORAGE_KEY2 = "direct-edit-panel-position";
@@ -8164,14 +8668,14 @@ function getInitialPosition() {
8164
8668
  });
8165
8669
  }
8166
8670
  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(() => {
8671
+ const [position, setPosition] = React28.useState(getInitialPosition);
8672
+ const [isDragging, setIsDragging] = React28.useState(false);
8673
+ const [isSnapping, setIsSnapping] = React28.useState(false);
8674
+ const [dragOffset, setDragOffset] = React28.useState({ x: 0, y: 0 });
8675
+ const snapTimerRef = React28.useRef(null);
8676
+ const panelRef = React28.useRef(null);
8677
+ const positionRef = React28.useRef(position);
8678
+ React28.useEffect(() => {
8175
8679
  positionRef.current = position;
8176
8680
  }, [position]);
8177
8681
  const handlePointerDown = (e) => {
@@ -8227,7 +8731,7 @@ function usePanelPosition() {
8227
8731
  } catch {
8228
8732
  }
8229
8733
  };
8230
- React27.useEffect(() => {
8734
+ React28.useEffect(() => {
8231
8735
  function handleResize() {
8232
8736
  setPosition((prev) => {
8233
8737
  const next = snapToEdge(prev);
@@ -8238,7 +8742,7 @@ function usePanelPosition() {
8238
8742
  window.addEventListener("resize", handleResize);
8239
8743
  return () => window.removeEventListener("resize", handleResize);
8240
8744
  }, []);
8241
- React27.useEffect(() => {
8745
+ React28.useEffect(() => {
8242
8746
  return () => {
8243
8747
  if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
8244
8748
  };
@@ -8299,12 +8803,12 @@ function DirectEditPanelInner({
8299
8803
  const canTriggerSend = canSendToAgent || hasPendingChanges;
8300
8804
  const isDraggable = onHeaderPointerDown !== void 0;
8301
8805
  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)
8806
+ layout: React29.useRef(null),
8807
+ radius: React29.useRef(null),
8808
+ border: React29.useRef(null),
8809
+ shadow: React29.useRef(null),
8810
+ colors: React29.useRef(null),
8811
+ text: React29.useRef(null)
8308
8812
  };
8309
8813
  const { scrollRef, activeSection } = useSectionNav(sectionRefs);
8310
8814
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
@@ -8347,7 +8851,7 @@ function DirectEditPanelInner({
8347
8851
  sectionRefs
8348
8852
  }
8349
8853
  ),
8350
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex-1 overflow-y-auto backdrop-blur-xl bg-background/85", ref: scrollRef, children: [
8854
+ /* @__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
8855
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8352
8856
  LayoutSection,
8353
8857
  {
@@ -8502,8 +9006,12 @@ function DirectEditPanelContent() {
8502
9006
  handlePointerUp,
8503
9007
  handlePointerCancel
8504
9008
  } = usePanelPosition();
8505
- const [hoverHighlight, setHoverHighlight] = React28.useState(null);
8506
- const [commentInputAttention, setCommentInputAttention] = React28.useState(null);
9009
+ const [hoverHighlight, setHoverHighlight] = React29.useState(null);
9010
+ const [commentInputAttention, setCommentInputAttention] = React29.useState(null);
9011
+ const commentDraftRef = React29.useRef("");
9012
+ React29.useEffect(() => {
9013
+ commentDraftRef.current = "";
9014
+ }, [activeCommentId]);
8507
9015
  const { isActive: measurementActive, hoveredElement, measurements, mousePosition } = useMeasurement(
8508
9016
  isOpen ? selectedElement : null
8509
9017
  );
@@ -8514,21 +9022,29 @@ function DirectEditPanelContent() {
8514
9022
  } = useMove({
8515
9023
  onMoveComplete: handleMoveComplete
8516
9024
  });
8517
- const triggerCommentInputAttention = React28.useCallback((commentId) => {
9025
+ const triggerCommentInputAttention = React29.useCallback((commentId) => {
8518
9026
  setCommentInputAttention((prev) => prev?.commentId === commentId ? { commentId, nonce: prev.nonce + 1 } : { commentId, nonce: 1 });
8519
9027
  }, []);
8520
- const hasPendingCommentDraft = React28.useCallback((nextCommentId = null) => {
9028
+ const hasPendingCommentDraft = React29.useCallback((nextCommentId = null) => {
8521
9029
  if (!activeCommentId) return false;
8522
9030
  if (nextCommentId && nextCommentId === activeCommentId) return false;
8523
9031
  const active = comments.find((comment) => comment.id === activeCommentId);
8524
- if (!active || active.text.trim().length > 0) return false;
9032
+ if (!active) return false;
9033
+ const hasUnsentDraft = active.text.trim().length === 0 && commentDraftRef.current.trim().length > 0;
9034
+ if (!hasUnsentDraft) return false;
8525
9035
  triggerCommentInputAttention(active.id);
8526
9036
  return true;
8527
9037
  }, [activeCommentId, comments, triggerCommentInputAttention]);
8528
- const handleSetActiveComment = React28.useCallback((id) => {
8529
- if (id && hasPendingCommentDraft(id)) return;
9038
+ const handleSetActiveComment = React29.useCallback((id) => {
9039
+ if (hasPendingCommentDraft(id)) return;
9040
+ if (activeCommentId && activeCommentId !== id) {
9041
+ const active = comments.find((comment) => comment.id === activeCommentId);
9042
+ if (active && active.text.trim().length === 0) {
9043
+ deleteComment(active.id);
9044
+ }
9045
+ }
8530
9046
  setActiveCommentId(id);
8531
- }, [hasPendingCommentDraft, setActiveCommentId]);
9047
+ }, [activeCommentId, comments, hasPendingCommentDraft, deleteComment, setActiveCommentId]);
8532
9048
  const overlay = editModeActive && container ? (0, import_react_dom.createPortal)(
8533
9049
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8534
9050
  InteractionOverlay,
@@ -8541,7 +9057,7 @@ function DirectEditPanelContent() {
8541
9057
  onSelectElement: selectElement,
8542
9058
  onStartTextEditing: startTextEditing,
8543
9059
  onAddComment: addComment,
8544
- onSetActiveCommentId: setActiveCommentId,
9060
+ onSetActiveCommentId: handleSetActiveComment,
8545
9061
  onSetHoverHighlight: setHoverHighlight,
8546
9062
  hasPendingCommentDraft
8547
9063
  }
@@ -8560,7 +9076,8 @@ function DirectEditPanelContent() {
8560
9076
  onDelete: deleteComment,
8561
9077
  onExport: exportComment,
8562
9078
  onSendToAgent: sendCommentToAgent2,
8563
- attentionRequest: commentInputAttention
9079
+ attentionRequest: commentInputAttention,
9080
+ draftRef: commentDraftRef
8564
9081
  }
8565
9082
  ),
8566
9083
  container
@@ -8602,6 +9119,7 @@ function DirectEditPanelContent() {
8602
9119
  ghostPosition: dragState.ghostPosition,
8603
9120
  onMoveStart: handleMoveStart,
8604
9121
  showMoveHandle,
9122
+ activeTool,
8605
9123
  isTextEditing: Boolean(textEditingElement),
8606
9124
  onDoubleClick: (clientX, clientY) => {
8607
9125
  if (!selectedElement) return;
@@ -8707,8 +9225,8 @@ function DirectEditPanelContent() {
8707
9225
  );
8708
9226
  }
8709
9227
  function DirectEditPanel() {
8710
- const [mounted, setMounted] = React28.useState(false);
8711
- React28.useEffect(() => {
9228
+ const [mounted, setMounted] = React29.useState(false);
9229
+ React29.useEffect(() => {
8712
9230
  setMounted(true);
8713
9231
  }, []);
8714
9232
  if (!mounted) {
@@ -8718,26 +9236,59 @@ function DirectEditPanel() {
8718
9236
  }
8719
9237
 
8720
9238
  // src/toolbar.tsx
8721
- var React34 = __toESM(require("react"));
9239
+ var React36 = __toESM(require("react"));
8722
9240
  var import_react_dom3 = require("react-dom");
8723
9241
 
8724
9242
  // src/rulers-overlay.tsx
8725
- var React29 = __toESM(require("react"));
9243
+ var React30 = __toESM(require("react"));
8726
9244
  var import_react_dom2 = require("react-dom");
8727
9245
  var import_jsx_runtime28 = require("react/jsx-runtime");
8728
9246
  var RULER_SIZE2 = 20;
8729
9247
  var GUIDELINE_COLOR = "#FF6B6B";
9248
+ var SNAPPED_COLOR = "#0D99FF";
8730
9249
  var HIT_ZONE = 9;
9250
+ function computeCanvasRulerScrollOffset(pan, zoom, bodyOffset2) {
9251
+ if (zoom === 0) return -pan;
9252
+ return bodyOffset2 * (1 - 1 / zoom) - pan;
9253
+ }
9254
+ function computeTickIntervals(zoom) {
9255
+ const MIN_LABEL_SPACING_PX = 80;
9256
+ const rawInterval = MIN_LABEL_SPACING_PX / zoom;
9257
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawInterval)));
9258
+ const residual = rawInterval / magnitude;
9259
+ let nice;
9260
+ if (residual <= 1) nice = 1;
9261
+ else if (residual <= 2) nice = 2;
9262
+ else if (residual <= 2.5) nice = 2.5;
9263
+ else if (residual <= 5) nice = 5;
9264
+ else nice = 10;
9265
+ const major = nice * magnitude;
9266
+ const stepsPerMajor = 10;
9267
+ const minor = major / stepsPerMajor;
9268
+ return { major, minor, stepsPerMajor };
9269
+ }
9270
+ function getColorSchemeQuery() {
9271
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
9272
+ return null;
9273
+ }
9274
+ return window.matchMedia("(prefers-color-scheme: dark)");
9275
+ }
8731
9276
  function subscribeColorScheme(cb) {
8732
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
8733
- mq.addEventListener("change", cb);
8734
- return () => mq.removeEventListener("change", cb);
9277
+ const mq = getColorSchemeQuery();
9278
+ if (!mq) return () => {
9279
+ };
9280
+ if (typeof mq.addEventListener === "function") {
9281
+ mq.addEventListener("change", cb);
9282
+ return () => mq.removeEventListener("change", cb);
9283
+ }
9284
+ mq.addListener(cb);
9285
+ return () => mq.removeListener(cb);
8735
9286
  }
8736
9287
  function getColorScheme() {
8737
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
9288
+ return getColorSchemeQuery()?.matches ?? false;
8738
9289
  }
8739
9290
  function useSystemDark() {
8740
- return React29.useSyncExternalStore(subscribeColorScheme, getColorScheme, () => false);
9291
+ return React30.useSyncExternalStore(subscribeColorScheme, getColorScheme, () => false);
8741
9292
  }
8742
9293
  var rulerFont = {
8743
9294
  fontFamily: "system-ui, -apple-system, sans-serif",
@@ -8746,13 +9297,14 @@ var rulerFont = {
8746
9297
  };
8747
9298
  function HorizontalRuler({
8748
9299
  scrollOffset,
9300
+ zoom = 1,
8749
9301
  onPointerDown
8750
9302
  }) {
8751
- const canvasRef = React29.useRef(null);
9303
+ const canvasRef = React30.useRef(null);
8752
9304
  const viewportWidth = useViewportWidth();
8753
9305
  const { theme } = useDirectEditState();
8754
9306
  const systemDark = useSystemDark();
8755
- React29.useEffect(() => {
9307
+ React30.useEffect(() => {
8756
9308
  const canvas = canvasRef.current;
8757
9309
  if (!canvas) return;
8758
9310
  const dpr = window.devicePixelRatio || 1;
@@ -8770,12 +9322,16 @@ function HorizontalRuler({
8770
9322
  const computed = getComputedStyle(canvas);
8771
9323
  const tick = computed.getPropertyValue("color");
8772
9324
  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;
9325
+ const { minor, stepsPerMajor } = computeTickIntervals(zoom);
9326
+ const midIdx = stepsPerMajor / 2;
9327
+ const visibleContentWidth = width / zoom;
9328
+ const startIdx = Math.floor(scrollOffset.x / minor);
9329
+ const endIdx = Math.ceil((scrollOffset.x + visibleContentWidth) / minor);
9330
+ for (let i = startIdx; i <= endIdx; i++) {
9331
+ const px = i * minor;
9332
+ const x = (px - scrollOffset.x) * zoom;
9333
+ const isMajor = i % stepsPerMajor === 0;
9334
+ const isMid = !isMajor && i % midIdx === 0;
8779
9335
  ctx.beginPath();
8780
9336
  ctx.moveTo(x, height);
8781
9337
  ctx.lineTo(x, height - (isMajor ? 10 : isMid ? 7 : 4));
@@ -8783,15 +9339,15 @@ function HorizontalRuler({
8783
9339
  ctx.globalAlpha = 0.6;
8784
9340
  ctx.lineWidth = 1;
8785
9341
  ctx.stroke();
8786
- if (isMajor && px !== 0) {
9342
+ if (isMajor) {
8787
9343
  ctx.globalAlpha = 1;
8788
9344
  ctx.fillStyle = label;
8789
9345
  ctx.font = "9px system-ui, -apple-system, sans-serif";
8790
9346
  ctx.textAlign = "center";
8791
- ctx.fillText(String(px), x, 9);
9347
+ ctx.fillText(String(Math.round(px)), x, 9);
8792
9348
  }
8793
9349
  }
8794
- }, [scrollOffset.x, viewportWidth, theme, systemDark]);
9350
+ }, [scrollOffset.x, viewportWidth, zoom, theme, systemDark]);
8795
9351
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
8796
9352
  "div",
8797
9353
  {
@@ -8817,13 +9373,14 @@ function HorizontalRuler({
8817
9373
  }
8818
9374
  function VerticalRuler({
8819
9375
  scrollOffset,
9376
+ zoom = 1,
8820
9377
  onPointerDown
8821
9378
  }) {
8822
- const canvasRef = React29.useRef(null);
9379
+ const canvasRef = React30.useRef(null);
8823
9380
  const viewportHeight = useViewportHeight();
8824
9381
  const { theme } = useDirectEditState();
8825
9382
  const systemDark = useSystemDark();
8826
- React29.useEffect(() => {
9383
+ React30.useEffect(() => {
8827
9384
  const canvas = canvasRef.current;
8828
9385
  if (!canvas) return;
8829
9386
  const dpr = window.devicePixelRatio || 1;
@@ -8841,12 +9398,16 @@ function VerticalRuler({
8841
9398
  const computed = getComputedStyle(canvas);
8842
9399
  const tick = computed.getPropertyValue("color");
8843
9400
  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;
9401
+ const { minor, stepsPerMajor } = computeTickIntervals(zoom);
9402
+ const midIdx = stepsPerMajor / 2;
9403
+ const visibleContentHeight = height / zoom;
9404
+ const startIdx = Math.floor(scrollOffset.y / minor);
9405
+ const endIdx = Math.ceil((scrollOffset.y + visibleContentHeight) / minor);
9406
+ for (let i = startIdx; i <= endIdx; i++) {
9407
+ const px = i * minor;
9408
+ const y = (px - scrollOffset.y) * zoom;
9409
+ const isMajor = i % stepsPerMajor === 0;
9410
+ const isMid = !isMajor && i % midIdx === 0;
8850
9411
  ctx.beginPath();
8851
9412
  ctx.moveTo(width, y);
8852
9413
  ctx.lineTo(width - (isMajor ? 10 : isMid ? 7 : 4), y);
@@ -8854,7 +9415,7 @@ function VerticalRuler({
8854
9415
  ctx.globalAlpha = 0.6;
8855
9416
  ctx.lineWidth = 1;
8856
9417
  ctx.stroke();
8857
- if (isMajor && px !== 0) {
9418
+ if (isMajor) {
8858
9419
  ctx.save();
8859
9420
  ctx.globalAlpha = 1;
8860
9421
  ctx.fillStyle = label;
@@ -8862,11 +9423,11 @@ function VerticalRuler({
8862
9423
  ctx.textAlign = "center";
8863
9424
  ctx.translate(9, y);
8864
9425
  ctx.rotate(-Math.PI / 2);
8865
- ctx.fillText(String(px), 0, 0);
9426
+ ctx.fillText(String(Math.round(px)), 0, 0);
8866
9427
  ctx.restore();
8867
9428
  }
8868
9429
  }
8869
- }, [scrollOffset.y, viewportHeight, theme, systemDark]);
9430
+ }, [scrollOffset.y, viewportHeight, zoom, theme, systemDark]);
8870
9431
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
8871
9432
  "div",
8872
9433
  {
@@ -8910,17 +9471,26 @@ function CornerSquare() {
8910
9471
  }
8911
9472
  );
8912
9473
  }
9474
+ function computeGuidelineViewportPos(position, orientation) {
9475
+ const snap = getCanvasSnapshot();
9476
+ const zoom = snap.active ? snap.zoom : 1;
9477
+ const pan = orientation === "horizontal" ? snap.active ? snap.panY : -window.scrollY : snap.active ? snap.panX : -window.scrollX;
9478
+ if (snap.active) {
9479
+ const bo = orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
9480
+ return bo + (position - bo + pan) * zoom;
9481
+ }
9482
+ return (position + pan) * zoom;
9483
+ }
8913
9484
  function GuidelineLine({
8914
9485
  guideline,
8915
- scrollOffset,
8916
9486
  isActive,
9487
+ isSnapped,
8917
9488
  dragPosition,
8918
9489
  onStartDrag,
8919
9490
  onDelete
8920
9491
  }) {
8921
9492
  const isHorizontal = guideline.orientation === "horizontal";
8922
- const scrollPos = isHorizontal ? scrollOffset.y : scrollOffset.x;
8923
- const viewportPos = guideline.position - scrollPos;
9493
+ const lineColor = isActive && isSnapped ? SNAPPED_COLOR : GUIDELINE_COLOR;
8924
9494
  const handlePointerDown = (e) => {
8925
9495
  e.preventDefault();
8926
9496
  e.stopPropagation();
@@ -8931,119 +9501,137 @@ function GuidelineLine({
8931
9501
  e.stopPropagation();
8932
9502
  onDelete(guideline.id);
8933
9503
  };
8934
- const displayPos = isActive && dragPosition !== null ? dragPosition : viewportPos;
9504
+ const isDragging = isActive && dragPosition !== null;
9505
+ const viewportPos = isDragging ? dragPosition : computeGuidelineViewportPos(guideline.position, guideline.orientation);
9506
+ const translate = isHorizontal ? `translateY(${viewportPos}px)` : `translateX(${viewportPos}px)`;
8935
9507
  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)(
9508
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
8992
9509
  "div",
8993
9510
  {
8994
- "data-direct-edit": "guideline",
9511
+ "data-gl-pos": guideline.position,
9512
+ "data-gl-orient": "h",
9513
+ ...isDragging ? { "data-gl-dragging": "" } : {},
8995
9514
  style: {
8996
9515
  position: "fixed",
8997
- left: displayPos,
8998
9516
  top: 0,
8999
- bottom: 0,
9000
- width: 1,
9001
- background: GUIDELINE_COLOR,
9517
+ left: 0,
9518
+ right: 0,
9519
+ height: 0,
9520
+ transform: translate,
9002
9521
  zIndex: 99993,
9003
9522
  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
9523
  },
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)
9524
+ children: [
9525
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9526
+ "div",
9527
+ {
9528
+ "data-direct-edit": "guideline",
9529
+ style: { position: "absolute", top: 0, left: 0, right: 0, height: 1, background: lineColor }
9530
+ }
9531
+ ),
9532
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9533
+ "div",
9534
+ {
9535
+ style: {
9536
+ position: "absolute",
9537
+ top: -Math.floor(HIT_ZONE / 2),
9538
+ left: RULER_SIZE2,
9539
+ right: 0,
9540
+ height: HIT_ZONE,
9541
+ cursor: "ns-resize",
9542
+ pointerEvents: "auto"
9543
+ },
9544
+ onPointerDown: handlePointerDown,
9545
+ onDoubleClick: handleDoubleClick
9546
+ }
9547
+ ),
9548
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9549
+ "div",
9550
+ {
9551
+ style: {
9552
+ position: "absolute",
9553
+ top: 4,
9554
+ left: RULER_SIZE2 + 4,
9555
+ background: lineColor,
9556
+ color: "#fff",
9557
+ padding: "1px 4px",
9558
+ borderRadius: 2,
9559
+ zIndex: 99995,
9560
+ pointerEvents: "none",
9561
+ ...rulerFont
9562
+ },
9563
+ children: Math.round(guideline.position)
9564
+ }
9565
+ )
9566
+ ]
9040
9567
  }
9041
- )
9042
- ] });
9568
+ );
9569
+ }
9570
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
9571
+ "div",
9572
+ {
9573
+ "data-gl-pos": guideline.position,
9574
+ "data-gl-orient": "v",
9575
+ ...isDragging ? { "data-gl-dragging": "" } : {},
9576
+ style: {
9577
+ position: "fixed",
9578
+ top: 0,
9579
+ left: 0,
9580
+ bottom: 0,
9581
+ width: 0,
9582
+ transform: translate,
9583
+ zIndex: 99993,
9584
+ pointerEvents: "none"
9585
+ },
9586
+ children: [
9587
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9588
+ "div",
9589
+ {
9590
+ "data-direct-edit": "guideline",
9591
+ style: { position: "absolute", left: 0, top: 0, bottom: 0, width: 1, background: lineColor }
9592
+ }
9593
+ ),
9594
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9595
+ "div",
9596
+ {
9597
+ style: {
9598
+ position: "absolute",
9599
+ left: -Math.floor(HIT_ZONE / 2),
9600
+ top: RULER_SIZE2,
9601
+ bottom: 0,
9602
+ width: HIT_ZONE,
9603
+ cursor: "ew-resize",
9604
+ pointerEvents: "auto"
9605
+ },
9606
+ onPointerDown: handlePointerDown,
9607
+ onDoubleClick: handleDoubleClick
9608
+ }
9609
+ ),
9610
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9611
+ "div",
9612
+ {
9613
+ style: {
9614
+ position: "absolute",
9615
+ left: 4,
9616
+ top: RULER_SIZE2 + 4,
9617
+ background: lineColor,
9618
+ color: "#fff",
9619
+ padding: "1px 4px",
9620
+ borderRadius: 2,
9621
+ zIndex: 99995,
9622
+ pointerEvents: "none",
9623
+ ...rulerFont
9624
+ },
9625
+ children: Math.round(guideline.position)
9626
+ }
9627
+ )
9628
+ ]
9629
+ }
9630
+ );
9043
9631
  }
9044
9632
  function useViewportWidth() {
9045
- const [width, setWidth] = React29.useState(0);
9046
- React29.useEffect(() => {
9633
+ const [width, setWidth] = React30.useState(0);
9634
+ React30.useEffect(() => {
9047
9635
  setWidth(window.innerWidth);
9048
9636
  const onResize = () => setWidth(window.innerWidth);
9049
9637
  window.addEventListener("resize", onResize);
@@ -9052,8 +9640,8 @@ function useViewportWidth() {
9052
9640
  return width;
9053
9641
  }
9054
9642
  function useViewportHeight() {
9055
- const [height, setHeight] = React29.useState(0);
9056
- React29.useEffect(() => {
9643
+ const [height, setHeight] = React30.useState(0);
9644
+ React30.useEffect(() => {
9057
9645
  setHeight(window.innerHeight);
9058
9646
  const onResize = () => setHeight(window.innerHeight);
9059
9647
  window.addEventListener("resize", onResize);
@@ -9063,7 +9651,8 @@ function useViewportHeight() {
9063
9651
  }
9064
9652
  function RulersOverlay({ enabled }) {
9065
9653
  const container = usePortalContainer();
9066
- const hostElement = React29.useMemo(() => {
9654
+ const canvas = useCanvasSnapshot();
9655
+ const hostElement = React30.useMemo(() => {
9067
9656
  if (!container) return null;
9068
9657
  const root = container.getRootNode();
9069
9658
  if (root instanceof ShadowRoot) return root.host;
@@ -9073,12 +9662,51 @@ function RulersOverlay({ enabled }) {
9073
9662
  guidelines,
9074
9663
  activeGuideline,
9075
9664
  dragPosition,
9665
+ isSnapped,
9076
9666
  scrollOffset,
9077
9667
  startCreate,
9078
9668
  startDrag,
9079
9669
  deleteGuideline
9080
- } = useGuidelines(enabled, hostElement);
9670
+ } = useGuidelines(enabled, hostElement, canvas);
9671
+ React30.useLayoutEffect(() => {
9672
+ if (!container || !enabled) return;
9673
+ const el = container;
9674
+ function updateGuidelinePositions() {
9675
+ const snap = getCanvasSnapshot();
9676
+ const zoom2 = snap.active ? snap.zoom : 1;
9677
+ const panX = snap.active ? snap.panX : -window.scrollX;
9678
+ const panY = snap.active ? snap.panY : -window.scrollY;
9679
+ const bo = getBodyOffset();
9680
+ el.querySelectorAll("[data-gl-pos]").forEach((node) => {
9681
+ if (node.hasAttribute("data-gl-dragging")) return;
9682
+ const pos = Number(node.dataset.glPos);
9683
+ const orient = node.dataset.glOrient;
9684
+ let vp;
9685
+ if (snap.active) {
9686
+ vp = orient === "h" ? bo.y + (pos - bo.y + panY) * zoom2 : bo.x + (pos - bo.x + panX) * zoom2;
9687
+ } else {
9688
+ vp = orient === "h" ? (pos + panY) * zoom2 : (pos + panX) * zoom2;
9689
+ }
9690
+ node.style.transform = orient === "h" ? `translateY(${vp}px)` : `translateX(${vp}px)`;
9691
+ });
9692
+ }
9693
+ updateGuidelinePositions();
9694
+ window.addEventListener("direct-edit-canvas-change", updateGuidelinePositions);
9695
+ window.addEventListener("scroll", updateGuidelinePositions, true);
9696
+ return () => {
9697
+ window.removeEventListener("direct-edit-canvas-change", updateGuidelinePositions);
9698
+ window.removeEventListener("scroll", updateGuidelinePositions, true);
9699
+ };
9700
+ }, [container, enabled]);
9081
9701
  if (!enabled || !container) return null;
9702
+ const zoom = canvas?.active ? canvas.zoom || 1 : 1;
9703
+ const effectiveScrollOffset = canvas?.active ? (() => {
9704
+ const bo = getBodyOffset();
9705
+ return {
9706
+ x: computeCanvasRulerScrollOffset(canvas.panX || 0, zoom, bo.x),
9707
+ y: computeCanvasRulerScrollOffset(canvas.panY || 0, zoom, bo.y)
9708
+ };
9709
+ })() : scrollOffset;
9082
9710
  const handleHorizontalPointerDown = (e) => {
9083
9711
  e.preventDefault();
9084
9712
  startCreate("horizontal", e.clientY);
@@ -9090,14 +9718,14 @@ function RulersOverlay({ enabled }) {
9090
9718
  return (0, import_react_dom2.createPortal)(
9091
9719
  /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
9092
9720
  /* @__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 }),
9721
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(HorizontalRuler, { scrollOffset: effectiveScrollOffset, zoom, onPointerDown: handleHorizontalPointerDown }),
9722
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(VerticalRuler, { scrollOffset: effectiveScrollOffset, zoom, onPointerDown: handleVerticalPointerDown }),
9095
9723
  guidelines.map((g) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
9096
9724
  GuidelineLine,
9097
9725
  {
9098
9726
  guideline: g,
9099
- scrollOffset,
9100
9727
  isActive: activeGuideline?.id === g.id,
9728
+ isSnapped: activeGuideline?.id === g.id ? isSnapped : false,
9101
9729
  dragPosition: activeGuideline?.id === g.id ? dragPosition : null,
9102
9730
  onStartDrag: startDrag,
9103
9731
  onDelete: deleteGuideline
@@ -9145,12 +9773,12 @@ function subscribeRulersVisible(listener) {
9145
9773
  };
9146
9774
  }
9147
9775
  function useRulersVisible() {
9148
- const visible = React29.useSyncExternalStore(
9776
+ const visible = React30.useSyncExternalStore(
9149
9777
  subscribeRulersVisible,
9150
9778
  () => rulersVisibleSnapshot,
9151
9779
  () => true
9152
9780
  );
9153
- const toggle = React29.useCallback(() => {
9781
+ const toggle = React30.useCallback(() => {
9154
9782
  setRulersVisible(!rulersVisibleSnapshot);
9155
9783
  }, []);
9156
9784
  return [visible, toggle];
@@ -9158,7 +9786,7 @@ function useRulersVisible() {
9158
9786
  function Rulers() {
9159
9787
  const { editModeActive } = useDirectEditState();
9160
9788
  const [rulersVisible, toggleRulers] = useRulersVisible();
9161
- React29.useEffect(() => {
9789
+ React30.useEffect(() => {
9162
9790
  if (!editModeActive) return;
9163
9791
  function handleKeyDown(e) {
9164
9792
  if (e.shiftKey && e.key === "R" && !e.metaKey && !e.ctrlKey && !e.altKey) {
@@ -9176,7 +9804,7 @@ function Rulers() {
9176
9804
  }
9177
9805
 
9178
9806
  // src/use-toolbar-dock.ts
9179
- var React30 = __toESM(require("react"));
9807
+ var React31 = __toESM(require("react"));
9180
9808
  var STORAGE_KEY3 = "direct-edit-toolbar-dock";
9181
9809
  var EDGE_MARGIN = 8;
9182
9810
  var DRAG_THRESHOLD2 = 3;
@@ -9200,21 +9828,25 @@ function getToolbarBounds(width, height) {
9200
9828
  const maxY = availableY <= 0 ? 0 : Math.max(minY, availableY - EDGE_MARGIN);
9201
9829
  return { minX, maxX, minY, maxY };
9202
9830
  }
9203
- function getDockedPosition(edge, width, height, currentX, currentY) {
9831
+ function getDockedPosition(edge, width, height) {
9204
9832
  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);
9833
+ const centerX = clamp((window.innerWidth - width) / 2, minX, maxX);
9834
+ const centerY = clamp((window.innerHeight - height) / 2, minY, maxY);
9207
9835
  switch (edge) {
9208
9836
  case "bottom":
9209
- return { x: freeX, y: maxY };
9837
+ return { x: centerX, y: maxY };
9210
9838
  case "top":
9211
- return { x: freeX, y: minY };
9839
+ return { x: centerX, y: minY };
9212
9840
  case "left":
9213
- return { x: minX, y: freeY };
9841
+ return { x: minX, y: centerY };
9214
9842
  case "right":
9215
- return { x: maxX, y: freeY };
9843
+ return { x: maxX, y: centerY };
9216
9844
  }
9217
9845
  }
9846
+ function getInitialDockedPosition(edge) {
9847
+ if (typeof window === "undefined") return { x: 0, y: 0 };
9848
+ return getDockedPosition(edge, 0, 0);
9849
+ }
9218
9850
  function getNearestEdge(centerX, centerY) {
9219
9851
  const vw = window.innerWidth;
9220
9852
  const vh = window.innerHeight;
@@ -9235,53 +9867,65 @@ function getNearestEdge(centerX, centerY) {
9235
9867
  return nearest;
9236
9868
  }
9237
9869
  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(() => {
9870
+ const [dockedEdge, setDockedEdge] = React31.useState(getInitialEdge);
9871
+ const [phase, setPhase] = React31.useState("docked");
9872
+ const [dragPosition, setDragPosition] = React31.useState(null);
9873
+ const dragOffsetRef = React31.useRef({ x: 0, y: 0 });
9874
+ const pointerStartRef = React31.useRef({ x: 0, y: 0 });
9875
+ const pendingDragRef = React31.useRef(false);
9876
+ const capturedElementRef = React31.useRef(null);
9877
+ const snapTimerRef = React31.useRef(null);
9878
+ const transitionTimerRef = React31.useRef(null);
9879
+ const transitioningRef = React31.useRef(false);
9880
+ const recalcRef = React31.useRef(null);
9881
+ const getDockedPos = React31.useCallback(() => {
9248
9882
  const el = toolbarRef.current;
9249
9883
  if (!el) return { x: 0, y: 0 };
9250
9884
  const rect = el.getBoundingClientRect();
9251
9885
  return getDockedPosition(dockedEdge, rect.width, rect.height);
9252
9886
  }, [dockedEdge, toolbarRef]);
9253
- const [dockedPos, setDockedPos] = React30.useState({ x: 0, y: 0 });
9254
- const [ready, setReady] = React30.useState(false);
9255
- React30.useEffect(() => {
9887
+ const [dockedPos, setDockedPos] = React31.useState(() => getInitialDockedPosition(dockedEdge));
9888
+ const [dockedTransitionEnabled, setDockedTransitionEnabled] = React31.useState(false);
9889
+ React31.useLayoutEffect(() => {
9256
9890
  const el = toolbarRef.current;
9257
9891
  if (!el) return;
9892
+ setDockedPos(getDockedPos());
9893
+ }, [getDockedPos, toolbarRef]);
9894
+ React31.useEffect(() => {
9258
9895
  const raf = requestAnimationFrame(() => {
9259
- const pos = getDockedPos();
9260
- dockedPosRef.current = pos;
9261
- setDockedPos(pos);
9262
- setReady(true);
9896
+ setDockedTransitionEnabled(true);
9263
9897
  });
9264
9898
  return () => cancelAnimationFrame(raf);
9265
- }, [getDockedPos, toolbarRef]);
9266
- React30.useEffect(() => {
9899
+ }, []);
9900
+ const predictSize = React31.useCallback((width, height) => {
9901
+ transitioningRef.current = true;
9902
+ setDockedPos(getDockedPosition(dockedEdge, width, height));
9903
+ if (transitionTimerRef.current) clearTimeout(transitionTimerRef.current);
9904
+ transitionTimerRef.current = setTimeout(() => {
9905
+ transitioningRef.current = false;
9906
+ transitionTimerRef.current = null;
9907
+ recalcRef.current?.();
9908
+ }, 350);
9909
+ }, [dockedEdge]);
9910
+ React31.useEffect(() => {
9267
9911
  const el = toolbarRef.current;
9268
9912
  if (!el) return;
9269
9913
  function recalc() {
9270
- if (!el) return;
9914
+ if (!el || transitioningRef.current) return;
9271
9915
  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);
9916
+ setDockedPos(getDockedPosition(dockedEdge, rect.width, rect.height));
9275
9917
  }
9918
+ recalcRef.current = recalc;
9276
9919
  const ro = new ResizeObserver(recalc);
9277
9920
  ro.observe(el);
9278
9921
  window.addEventListener("resize", recalc);
9279
9922
  return () => {
9923
+ recalcRef.current = null;
9280
9924
  ro.disconnect();
9281
9925
  window.removeEventListener("resize", recalc);
9282
9926
  };
9283
9927
  }, [dockedEdge, toolbarRef]);
9284
- const handlePointerDown = React30.useCallback((e) => {
9928
+ const handlePointerDown = React31.useCallback((e) => {
9285
9929
  const el = toolbarRef.current;
9286
9930
  if (!el) return;
9287
9931
  const rect = el.getBoundingClientRect();
@@ -9294,7 +9938,7 @@ function useToolbarDock(toolbarRef) {
9294
9938
  } catch {
9295
9939
  }
9296
9940
  }, [toolbarRef]);
9297
- const handlePointerMove = React30.useCallback((e) => {
9941
+ const handlePointerMove = React31.useCallback((e) => {
9298
9942
  if (!pendingDragRef.current && phase !== "dragging") return;
9299
9943
  const dx = e.clientX - pointerStartRef.current.x;
9300
9944
  const dy = e.clientY - pointerStartRef.current.y;
@@ -9311,7 +9955,7 @@ function useToolbarDock(toolbarRef) {
9311
9955
  const newY = Math.max(0, e.clientY - dragOffsetRef.current.y);
9312
9956
  setDragPosition({ x: newX, y: newY });
9313
9957
  }, [phase]);
9314
- const handlePointerUp = React30.useCallback((e) => {
9958
+ const handlePointerUp = React31.useCallback((e) => {
9315
9959
  if (capturedElementRef.current) {
9316
9960
  try {
9317
9961
  capturedElementRef.current.releasePointerCapture(e.pointerId);
@@ -9331,8 +9975,6 @@ function useToolbarDock(toolbarRef) {
9331
9975
  return;
9332
9976
  }
9333
9977
  const rect = el.getBoundingClientRect();
9334
- const width = el.offsetWidth;
9335
- const height = el.offsetHeight;
9336
9978
  const centerX = rect.left + rect.width / 2;
9337
9979
  const centerY = rect.top + rect.height / 2;
9338
9980
  const newEdge = getNearestEdge(centerX, centerY);
@@ -9341,9 +9983,7 @@ function useToolbarDock(toolbarRef) {
9341
9983
  localStorage.setItem(STORAGE_KEY3, newEdge);
9342
9984
  } catch {
9343
9985
  }
9344
- const newPos = getDockedPosition(newEdge, width, height, rect.left, rect.top);
9345
- dockedPosRef.current = newPos;
9346
- setDockedPos(newPos);
9986
+ setDockedPos(getDockedPosition(newEdge, el.offsetWidth, el.offsetHeight));
9347
9987
  setPhase("snapping");
9348
9988
  setDragPosition(null);
9349
9989
  if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
@@ -9352,7 +9992,7 @@ function useToolbarDock(toolbarRef) {
9352
9992
  setPhase("docked");
9353
9993
  }, 350);
9354
9994
  }, [phase, toolbarRef]);
9355
- const handlePointerCancel = React30.useCallback((e) => {
9995
+ const handlePointerCancel = React31.useCallback((e) => {
9356
9996
  if (capturedElementRef.current) {
9357
9997
  try {
9358
9998
  capturedElementRef.current.releasePointerCapture(e.pointerId);
@@ -9366,18 +10006,16 @@ function useToolbarDock(toolbarRef) {
9366
10006
  setDragPosition(null);
9367
10007
  }
9368
10008
  }, [phase]);
9369
- React30.useEffect(() => {
10009
+ React31.useEffect(() => {
9370
10010
  return () => {
9371
10011
  if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
10012
+ if (transitionTimerRef.current) clearTimeout(transitionTimerRef.current);
9372
10013
  };
9373
10014
  }, []);
9374
10015
  const isDragging = phase === "dragging";
9375
10016
  const isSnapping = phase === "snapping";
9376
- const style = React30.useMemo(() => {
9377
- const base = {
9378
- position: "fixed",
9379
- ...!ready && { visibility: "hidden" }
9380
- };
10017
+ const style = React31.useMemo(() => {
10018
+ const base = { position: "fixed" };
9381
10019
  if (phase === "dragging" && dragPosition) {
9382
10020
  return {
9383
10021
  ...base,
@@ -9400,14 +10038,18 @@ function useToolbarDock(toolbarRef) {
9400
10038
  return {
9401
10039
  ...base,
9402
10040
  left: dockedPos.x,
9403
- top: dockedPos.y
10041
+ top: dockedPos.y,
10042
+ ...dockedTransitionEnabled && {
10043
+ 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"
10044
+ }
9404
10045
  };
9405
- }, [phase, dragPosition, dockedPos, ready]);
10046
+ }, [phase, dragPosition, dockedPos, dockedTransitionEnabled]);
9406
10047
  return {
9407
10048
  dockedEdge,
9408
10049
  isDragging,
9409
10050
  isSnapping,
9410
10051
  style,
10052
+ predictSize,
9411
10053
  handlePointerDown,
9412
10054
  handlePointerMove,
9413
10055
  handlePointerUp,
@@ -9416,16 +10058,16 @@ function useToolbarDock(toolbarRef) {
9416
10058
  }
9417
10059
 
9418
10060
  // src/toolbar.tsx
9419
- var import_lucide_react15 = require("lucide-react");
10061
+ var import_lucide_react16 = require("lucide-react");
9420
10062
 
9421
10063
  // src/toolbar/edits-popover.tsx
9422
- var React32 = __toESM(require("react"));
10064
+ var React33 = __toESM(require("react"));
9423
10065
  var import_button7 = require("@base-ui/react/button");
9424
10066
  var import_popover2 = require("@base-ui/react/popover");
9425
10067
  var import_lucide_react13 = require("lucide-react");
9426
10068
 
9427
10069
  // src/ui/badge.tsx
9428
- var React31 = __toESM(require("react"));
10070
+ var React32 = __toESM(require("react"));
9429
10071
  var import_jsx_runtime29 = require("react/jsx-runtime");
9430
10072
  var badgeVariants = {
9431
10073
  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 +10077,7 @@ var badgeVariants = {
9435
10077
  outline: "border-border bg-transparent text-foreground"
9436
10078
  }
9437
10079
  };
9438
- var Badge = React31.forwardRef(
10080
+ var Badge = React32.forwardRef(
9439
10081
  ({ className, variant = "default", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
9440
10082
  "div",
9441
10083
  {
@@ -9461,14 +10103,11 @@ function truncateText(value, max = 64) {
9461
10103
  if (value.length <= max) return value;
9462
10104
  return `${value.slice(0, max)}...`;
9463
10105
  }
9464
- function isWithinFocusRegion(nextTarget, ...elements) {
9465
- if (!(nextTarget instanceof Node)) return false;
9466
- return elements.some((element) => Boolean(element?.contains(nextTarget)));
9467
- }
9468
10106
  function EditsPopover({
9469
10107
  tooltipSide,
9470
10108
  sessionEditCount,
9471
- isDragging,
10109
+ isOpen,
10110
+ onOpenChange,
9472
10111
  onGetSessionItems,
9473
10112
  onExportAllEdits,
9474
10113
  onSendAllToAgents,
@@ -9476,20 +10115,18 @@ function EditsPopover({
9476
10115
  onRemoveSessionEdit,
9477
10116
  onDeleteComment
9478
10117
  }) {
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;
10118
+ const [copied, setCopied] = React33.useState(false);
10119
+ const [sendStatus, setSendStatus] = React33.useState("idle");
10120
+ const editsPopupRef = React33.useRef(null);
10121
+ const editsTriggerRef = React33.useRef(null);
10122
+ const [editsSnapshot, setEditsSnapshot] = React33.useState([]);
10123
+ React33.useEffect(() => {
10124
+ if (!isOpen) return;
9488
10125
  function handlePointerDown(e) {
9489
10126
  const path = e.composedPath();
9490
10127
  if (editsPopupRef.current && path.includes(editsPopupRef.current)) return;
9491
10128
  if (editsTriggerRef.current && path.includes(editsTriggerRef.current)) return;
9492
- setEditsOpen(false);
10129
+ onOpenChange(false);
9493
10130
  }
9494
10131
  const raf = requestAnimationFrame(() => {
9495
10132
  document.addEventListener("pointerdown", handlePointerDown);
@@ -9498,42 +10135,19 @@ function EditsPopover({
9498
10135
  cancelAnimationFrame(raf);
9499
10136
  document.removeEventListener("pointerdown", handlePointerDown);
9500
10137
  };
9501
- }, [editsOpen]);
9502
- React32.useEffect(() => {
9503
- if (editsOpen && onGetSessionItems) {
10138
+ }, [isOpen, onOpenChange]);
10139
+ React33.useEffect(() => {
10140
+ if (isOpen && onGetSessionItems) {
9504
10141
  setEditsSnapshot(onGetSessionItems());
9505
10142
  }
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 () => {
10143
+ }, [isOpen, onGetSessionItems]);
10144
+ const handleCopyAll = React33.useCallback(async () => {
9531
10145
  const success = await onExportAllEdits?.();
9532
10146
  if (!success) return;
9533
10147
  setCopied(true);
9534
10148
  window.setTimeout(() => setCopied(false), 2e3);
9535
10149
  }, [onExportAllEdits]);
9536
- const handleSendAll = React32.useCallback(async () => {
10150
+ const handleSendAll = React33.useCallback(async () => {
9537
10151
  if (!onSendAllToAgents || sendStatus === "sending") return;
9538
10152
  setSendStatus("sending");
9539
10153
  let success = false;
@@ -9550,7 +10164,7 @@ function EditsPopover({
9550
10164
  setSendStatus("offline");
9551
10165
  window.setTimeout(() => setSendStatus("idle"), 2e3);
9552
10166
  }, [onSendAllToAgents, sendStatus]);
9553
- const handleCopyItem = React32.useCallback(async (item) => {
10167
+ const handleCopyItem = React33.useCallback(async (item) => {
9554
10168
  const text = item.type === "edit" ? buildSessionExport([item.edit], []) : buildSessionExport([], [item.comment]);
9555
10169
  try {
9556
10170
  await navigator.clipboard.writeText(`implement the visual edits
@@ -9561,52 +10175,33 @@ ${text}`);
9561
10175
  } catch {
9562
10176
  }
9563
10177
  }, []);
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);
10178
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_popover2.Popover.Root, { open: isOpen, onOpenChange, children: [
10179
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(Tooltip, { disabled: isOpen, children: [
10180
+ /* @__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)(
10181
+ "button",
10182
+ {
10183
+ ref: editsTriggerRef,
10184
+ type: "button",
10185
+ className: cn(
10186
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10187
+ sessionEditCount > 0 || isOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10188
+ ),
10189
+ onPointerDown: (e) => e.stopPropagation(),
10190
+ onClick: (e) => {
10191
+ e.preventDefault();
10192
+ e.stopPropagation();
10193
+ onOpenChange(!isOpen);
9583
10194
  }
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
10195
  }
9595
- }
9596
- ), children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react13.Copy, { className: "size-4" }) }),
10196
+ ) }), children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react13.Copy, { className: "size-4" }) }),
10197
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipContent, { side: tooltipSide, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { children: "Export edits" }) })
10198
+ ] }),
9597
10199
  /* @__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
10200
  import_popover2.Popover.Popup,
9599
10201
  {
9600
10202
  ref: editsPopupRef,
9601
10203
  className: "w-[340px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
9602
10204
  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
10205
  children: [
9611
10206
  /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center justify-between px-3 pb-1 pt-2.5", children: [
9612
10207
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs font-medium text-foreground", children: "Copy to AI agents" }),
@@ -9737,38 +10332,200 @@ ${text}`);
9737
10332
  }
9738
10333
 
9739
10334
  // 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");
10335
+ var React34 = __toESM(require("react"));
10336
+ var import_menu = require("@base-ui/react/menu");
9743
10337
  var import_lucide_react14 = require("lucide-react");
9744
10338
  var import_jsx_runtime31 = require("react/jsx-runtime");
9745
- function ThemePopoverPortal(props) {
10339
+ function SettingsMenuPortal(props) {
9746
10340
  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)));
10341
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_menu.Menu.Portal, { container, ...props });
9752
10342
  }
9753
10343
  function SettingsPopover({
9754
10344
  tooltipSide,
9755
10345
  theme,
9756
10346
  isMac,
9757
- isDragging,
10347
+ isOpen,
10348
+ onOpenChange,
9758
10349
  onSetTheme
9759
10350
  }) {
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;
10351
+ const settingsTriggerRef = React34.useRef(null);
10352
+ const settingsPopupRef = React34.useRef(null);
10353
+ 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";
10354
+ const popupTitleClass = "flex h-8 items-center px-3 text-xs font-medium text-foreground";
10355
+ const submenuSide = tooltipSide === "left" ? "left" : "right";
10356
+ const centeredSubmenuCollision = React34.useMemo(
10357
+ () => ({ side: "flip", align: "none", fallbackAxisSide: "none" }),
10358
+ []
10359
+ );
10360
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_menu.Menu.Root, { open: isOpen, onOpenChange, modal: false, children: [
10361
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(Tooltip, { disabled: isOpen, children: [
10362
+ /* @__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)(
10363
+ "button",
10364
+ {
10365
+ ref: settingsTriggerRef,
10366
+ type: "button",
10367
+ className: cn(
10368
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10369
+ isOpen ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10370
+ ),
10371
+ onPointerDown: (e) => e.stopPropagation()
10372
+ }
10373
+ ) }), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.EllipsisVertical, { className: "size-4" }) }),
10374
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(TooltipContent, { side: tooltipSide, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: "Preferences" }) })
10375
+ ] }),
10376
+ /* @__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)(
10377
+ import_menu.Menu.Popup,
10378
+ {
10379
+ ref: settingsPopupRef,
10380
+ className: "w-[200px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
10381
+ onPointerDown: (e) => e.stopPropagation(),
10382
+ children: [
10383
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: popupTitleClass, children: "Preferences" }),
10384
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "px-1 pb-1", children: [
10385
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_menu.Menu.SubmenuRoot, { children: [
10386
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10387
+ import_menu.Menu.SubmenuTrigger,
10388
+ {
10389
+ openOnHover: false,
10390
+ 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",
10391
+ children: [
10392
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Monitor, { className: "size-3.5" }),
10393
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex-1", children: "Theme" }),
10394
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ChevronRight, { className: "size-3.5" })
10395
+ ]
10396
+ }
10397
+ ),
10398
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SettingsMenuPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
10399
+ import_menu.Menu.Positioner,
10400
+ {
10401
+ anchor: settingsPopupRef,
10402
+ side: submenuSide,
10403
+ align: "center",
10404
+ sideOffset: 6,
10405
+ collisionAvoidance: centeredSubmenuCollision,
10406
+ className: "fixed z-[99999]",
10407
+ style: { pointerEvents: "auto" },
10408
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10409
+ import_menu.Menu.Popup,
10410
+ {
10411
+ className: "w-[200px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
10412
+ onPointerDown: (e) => e.stopPropagation(),
10413
+ children: [
10414
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: popupTitleClass, children: "Theme" }),
10415
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-1 pb-1", children: [
10416
+ { value: "light", label: "Light", Icon: import_lucide_react14.Sun },
10417
+ { value: "dark", label: "Dark", Icon: import_lucide_react14.Moon },
10418
+ { value: "system", label: "System", Icon: import_lucide_react14.Monitor }
10419
+ ].map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10420
+ import_menu.Menu.Item,
10421
+ {
10422
+ className: cn(
10423
+ "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs transition-colors",
10424
+ theme === value ? "bg-muted text-foreground" : "text-muted-foreground data-[highlighted]:bg-muted/50 data-[highlighted]:text-foreground"
10425
+ ),
10426
+ onClick: () => {
10427
+ onSetTheme?.(value);
10428
+ onOpenChange(false);
10429
+ },
10430
+ children: [
10431
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { className: "size-3.5" }),
10432
+ label
10433
+ ]
10434
+ },
10435
+ value
10436
+ )) })
10437
+ ]
10438
+ }
10439
+ )
10440
+ }
10441
+ ) })
10442
+ ] }),
10443
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_menu.Menu.SubmenuRoot, { children: [
10444
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10445
+ import_menu.Menu.SubmenuTrigger,
10446
+ {
10447
+ openOnHover: false,
10448
+ 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",
10449
+ children: [
10450
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Keyboard, { className: "size-3.5" }),
10451
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex-1", children: "Keyboard shortcuts" }),
10452
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ChevronRight, { className: "size-3.5" })
10453
+ ]
10454
+ }
10455
+ ),
10456
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SettingsMenuPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
10457
+ import_menu.Menu.Positioner,
10458
+ {
10459
+ anchor: settingsPopupRef,
10460
+ side: submenuSide,
10461
+ align: "center",
10462
+ sideOffset: 6,
10463
+ collisionAvoidance: centeredSubmenuCollision,
10464
+ className: "fixed z-[99999]",
10465
+ style: { pointerEvents: "auto" },
10466
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
10467
+ import_menu.Menu.Popup,
10468
+ {
10469
+ className: "w-[300px] rounded-xl bg-background text-[11px] outline outline-1 outline-foreground/10 shadow-lg",
10470
+ onPointerDown: (e) => e.stopPropagation(),
10471
+ children: [
10472
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex h-7 items-center px-3 text-[11px] font-medium text-foreground", children: "Keyboard Shortcuts" }),
10473
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-1 pb-1", children: [
10474
+ { label: "Toggle design mode", keys: isMac ? [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Command, { className: "size-2.5" }, "cmd"), "."] : ["Ctrl", "."] },
10475
+ { label: "Undo", keys: isMac ? [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Command, { className: "size-2.5" }, "cmd"), "Z"] : ["Ctrl", "Z"] },
10476
+ { label: "Toggle comments", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "C"] },
10477
+ { label: "Toggle rulers", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "R"] },
10478
+ { label: "Toggle canvas mode", keys: [/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.ArrowBigUp, { className: "size-3" }, "shift"), "Z"] },
10479
+ { label: "Hover to measure", keys: isMac ? ["Hold", /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react14.Option, { className: "size-2.5" }, "opt")] : ["Hold", "Alt"] },
10480
+ { label: "Back / Exit", keys: ["Esc"] }
10481
+ ].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: [
10482
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: label }),
10483
+ /* @__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)) })
10484
+ ] }, label)) })
10485
+ ]
10486
+ }
10487
+ )
10488
+ }
10489
+ ) })
10490
+ ] })
10491
+ ] })
10492
+ ]
10493
+ }
10494
+ ) }) })
10495
+ ] });
10496
+ }
10497
+
10498
+ // src/toolbar/zoom-popover.tsx
10499
+ var React35 = __toESM(require("react"));
10500
+ var import_button8 = require("@base-ui/react/button");
10501
+ var import_popover3 = require("@base-ui/react/popover");
10502
+ var import_lucide_react15 = require("lucide-react");
10503
+ var import_jsx_runtime32 = require("react/jsx-runtime");
10504
+ function ZoomPopoverPortal(props) {
10505
+ const container = usePortalContainer();
10506
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_popover3.Popover.Portal, { container, ...props });
10507
+ }
10508
+ function ZoomPopover({
10509
+ tooltipSide,
10510
+ canvasActive,
10511
+ canvasZoom,
10512
+ isOpen,
10513
+ onOpenChange,
10514
+ onToggleCanvas,
10515
+ onSetCanvasZoom,
10516
+ onZoomTo100,
10517
+ onFitToViewport
10518
+ }) {
10519
+ const popupRef = React35.useRef(null);
10520
+ const triggerRef = React35.useRef(null);
10521
+ 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]";
10522
+ React35.useEffect(() => {
10523
+ if (!isOpen) return;
9767
10524
  function handlePointerDown(e) {
9768
10525
  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);
10526
+ if (popupRef.current && path.includes(popupRef.current)) return;
10527
+ if (triggerRef.current && path.includes(triggerRef.current)) return;
10528
+ onOpenChange(false);
9772
10529
  }
9773
10530
  const raf = requestAnimationFrame(() => {
9774
10531
  document.addEventListener("pointerdown", handlePointerDown);
@@ -9777,121 +10534,90 @@ function SettingsPopover({
9777
10534
  cancelAnimationFrame(raf);
9778
10535
  document.removeEventListener("pointerdown", handlePointerDown);
9779
10536
  };
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);
10537
+ }, [isOpen, onOpenChange]);
10538
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_popover3.Popover.Root, { open: isOpen, onOpenChange, children: [
10539
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Tooltip, { disabled: isOpen, children: [
10540
+ /* @__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)(
10541
+ "button",
10542
+ {
10543
+ ref: triggerRef,
10544
+ type: "button",
10545
+ className: cn(
10546
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10547
+ isOpen ? "bg-muted text-foreground" : canvasActive ? "bg-muted text-foreground hover:bg-muted/80" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10548
+ ),
10549
+ onPointerDown: (e) => e.stopPropagation(),
10550
+ onClick: (e) => {
10551
+ e.preventDefault();
10552
+ e.stopPropagation();
10553
+ onOpenChange(!isOpen);
9823
10554
  }
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
10555
  }
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)(
10556
+ ) }), children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Maximize2, { className: "size-4" }) }),
10557
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10558
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: "Canvas mode" }),
10559
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.ArrowBigUp, { className: "size-2.5" }) }),
10560
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: kbdClass, children: "Z" })
10561
+ ] })
10562
+ ] }),
10563
+ /* @__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
10564
  import_popover3.Popover.Popup,
9839
10565
  {
9840
- ref: settingsPopupRef,
9841
- className: "w-[340px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
10566
+ ref: popupRef,
10567
+ className: "w-[180px] rounded-xl bg-background text-xs outline outline-1 outline-foreground/10 shadow-lg",
9842
10568
  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)(
10569
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "px-1 py-1", children: [
10570
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
9857
10571
  import_button8.Button,
9858
10572
  {
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
- ),
10573
+ 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
10574
  onClick: () => {
9864
- onSetTheme?.(value);
9865
- setSettingsOpen(false);
10575
+ onZoomTo100?.();
10576
+ onOpenChange(false);
9866
10577
  },
9867
10578
  children: [
9868
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { className: "size-3.5" }),
9869
- label
10579
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Scan, { className: "size-3.5" }),
10580
+ "Actual size (100%)"
9870
10581
  ]
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
- ]
10582
+ }
10583
+ ),
10584
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
10585
+ import_button8.Button,
10586
+ {
10587
+ 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",
10588
+ onClick: () => {
10589
+ onFitToViewport?.();
10590
+ onOpenChange(false);
10591
+ },
10592
+ children: [
10593
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Minimize2, { className: "size-3.5" }),
10594
+ "Fit to viewport"
10595
+ ]
10596
+ }
10597
+ ),
10598
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "my-1 border-t border-foreground/10" }),
10599
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
10600
+ import_button8.Button,
10601
+ {
10602
+ 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",
10603
+ onClick: () => {
10604
+ onToggleCanvas?.();
10605
+ onOpenChange(false);
10606
+ },
10607
+ children: [
10608
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.Check, { className: cn("size-3.5", canvasActive ? "opacity-100" : "opacity-0") }),
10609
+ "Canvas mode"
10610
+ ]
10611
+ }
10612
+ )
10613
+ ] })
9888
10614
  }
9889
10615
  ) }) })
9890
10616
  ] });
9891
10617
  }
9892
10618
 
9893
10619
  // src/toolbar.tsx
9894
- var import_jsx_runtime32 = require("react/jsx-runtime");
10620
+ var import_jsx_runtime33 = require("react/jsx-runtime");
9895
10621
  function DirectEditToolbarInner({
9896
10622
  editModeActive,
9897
10623
  onToggleEditMode,
@@ -9908,33 +10634,63 @@ function DirectEditToolbarInner({
9908
10634
  onClearSessionEdits,
9909
10635
  onRemoveSessionEdit,
9910
10636
  onDeleteComment,
9911
- className
10637
+ className,
10638
+ canvasActive = false,
10639
+ canvasZoom = 1,
10640
+ onToggleCanvas,
10641
+ onSetCanvasZoom,
10642
+ onZoomTo100,
10643
+ onFitToViewport
9912
10644
  }) {
9913
10645
  const container = usePortalContainer();
9914
- const toolbarRef = React34.useRef(null);
9915
- const { dockedEdge, isDragging, isSnapping, style: dockStyle, handlePointerDown, handlePointerMove, handlePointerUp, handlePointerCancel } = useToolbarDock(toolbarRef);
10646
+ const toolbarRef = React36.useRef(null);
10647
+ const { dockedEdge, isDragging, isSnapping, style: dockStyle, predictSize, handlePointerDown, handlePointerMove, handlePointerUp, handlePointerCancel } = useToolbarDock(toolbarRef);
9916
10648
  const isVertical = dockedEdge === "left" || dockedEdge === "right";
10649
+ const [activePopover, setActivePopover] = React36.useState(null);
10650
+ const sizeCacheRef = React36.useRef({});
10651
+ React36.useEffect(() => {
10652
+ const el = toolbarRef.current;
10653
+ if (!el) return;
10654
+ const key = `${dockedEdge}:${editModeActive ? "expanded" : "collapsed"}`;
10655
+ const timer = setTimeout(() => {
10656
+ const rect = el.getBoundingClientRect();
10657
+ sizeCacheRef.current[key] = { w: rect.width, h: rect.height };
10658
+ }, 350);
10659
+ return () => clearTimeout(timer);
10660
+ }, [editModeActive, dockedEdge]);
10661
+ const prevEditModeRef = React36.useRef(editModeActive);
10662
+ React36.useEffect(() => {
10663
+ if (prevEditModeRef.current === editModeActive) return;
10664
+ prevEditModeRef.current = editModeActive;
10665
+ const target = sizeCacheRef.current[`${dockedEdge}:${editModeActive ? "expanded" : "collapsed"}`];
10666
+ if (target) {
10667
+ predictSize(target.w, target.h);
10668
+ }
10669
+ }, [editModeActive, dockedEdge, predictSize]);
10670
+ React36.useEffect(() => {
10671
+ if (isDragging) setActivePopover(null);
10672
+ }, [isDragging]);
10673
+ React36.useEffect(() => {
10674
+ if (!editModeActive) setActivePopover(null);
10675
+ }, [editModeActive]);
9917
10676
  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
- }, []);
10677
+ const [isMac] = React36.useState(() => typeof navigator !== "undefined" ? navigator.platform?.includes("Mac") ?? false : false);
9922
10678
  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: "." })
10679
+ const shortcutContent = isMac ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
10680
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.Command, { className: "size-2.5" }) }),
10681
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "." })
10682
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
10683
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "Ctrl" }),
10684
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "." })
9929
10685
  ] });
9930
- const toolbar = /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
10686
+ const toolbar = /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_jsx_runtime33.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
9931
10687
  "div",
9932
10688
  {
9933
10689
  ref: toolbarRef,
9934
10690
  "data-direct-edit": "toolbar",
9935
10691
  style: { pointerEvents: "auto", touchAction: "none", ...dockStyle },
9936
10692
  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",
10693
+ "group z-[99999] flex rounded-xl outline outline-1 outline-foreground/10 bg-background p-1.5 shadow-lg",
9938
10694
  isVertical ? "flex-col items-center" : "flex-row items-center",
9939
10695
  isDragging && "cursor-grabbing select-none shadow-2xl",
9940
10696
  className
@@ -9945,21 +10701,21 @@ function DirectEditToolbarInner({
9945
10701
  onPointerCancel: handlePointerCancel,
9946
10702
  onLostPointerCapture: handlePointerCancel,
9947
10703
  children: [
9948
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn(
10704
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
9949
10705
  "flex shrink-0 cursor-grab items-center justify-center",
9950
10706
  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(
10707
+ ), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
9952
10708
  "shrink-0 rounded-full bg-foreground/25",
9953
10709
  isVertical ? "h-0.5 w-4" : "h-4 w-0.5"
9954
10710
  ) }) }),
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)(
10711
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipProvider, { delayDuration: 200, children: [
10712
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10713
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
9958
10714
  TooltipTrigger,
9959
10715
  {
9960
10716
  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"
10717
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-[color,background-color] duration-150 ease-out",
10718
+ editModeActive && activeTool !== "comment" ? "bg-foreground text-background hover:bg-foreground/80" : "text-muted-foreground hover:bg-muted hover:text-foreground"
9963
10719
  ),
9964
10720
  onPointerDown: (e) => e.stopPropagation(),
9965
10721
  onClick: () => {
@@ -9969,89 +10725,144 @@ function DirectEditToolbarInner({
9969
10725
  onToggleEditMode();
9970
10726
  }
9971
10727
  },
9972
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react15.MousePointer2, { className: "size-4" })
10728
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.MousePointer2, { className: "size-4" })
9973
10729
  }
9974
10730
  ),
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" }),
10731
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10732
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: editModeActive ? "Select" : "Activate design mode" }),
9977
10733
  shortcutContent
9978
10734
  ] })
9979
10735
  ] }),
9980
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10736
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
9981
10737
  "div",
9982
10738
  {
9983
10739
  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"
10740
+ "grid place-items-center overflow-hidden",
10741
+ isVertical ? editModeActive ? "mt-1 grid-rows-[1fr]" : "mt-0 grid-rows-[0fr]" : editModeActive ? "ml-1 grid-cols-[1fr]" : "ml-0 grid-cols-[0fr]"
9986
10742
  ),
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"
10743
+ style: {
10744
+ transitionProperty: "grid-template-columns, grid-template-rows, margin",
10745
+ transitionDuration: "200ms",
10746
+ transitionTimingFunction: "cubic-bezier(0.25, 1, 0.5, 1)",
10747
+ transitionDelay: editModeActive ? "0ms" : "80ms"
10748
+ },
10749
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
10750
+ "div",
10751
+ {
10752
+ className: cn("flex gap-1 overflow-hidden", isVertical ? "min-h-0 flex-col items-center" : "min-w-0 flex-row items-center"),
10753
+ style: {
10754
+ filter: editModeActive ? "blur(0px)" : "blur(5px)",
10755
+ opacity: editModeActive ? 1 : 0,
10756
+ transitionProperty: "filter, opacity",
10757
+ transitionDuration: "250ms, 100ms",
10758
+ transitionTimingFunction: "cubic-bezier(0.33, 1, 0.68, 1)",
10759
+ transitionDelay: editModeActive ? "80ms" : "0ms"
10760
+ },
10761
+ children: [
10762
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10763
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10764
+ TooltipTrigger,
10765
+ {
10766
+ className: cn(
10767
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10768
+ activeTool === "comment" ? "bg-foreground text-background hover:bg-foreground/80" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10769
+ ),
10770
+ onPointerDown: (e) => e.stopPropagation(),
10771
+ onClick: () => onSetActiveTool?.(activeTool === "comment" ? "select" : "comment"),
10772
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.MessageSquare, { className: "size-4" })
10773
+ }
9995
10774
  ),
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"
10775
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10776
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: activeTool === "comment" ? "Exit comment mode" : "Comment" }),
10777
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.ArrowBigUp, { className: "size-3" }) }),
10778
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "C" })
10779
+ ] })
10780
+ ] }),
10781
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10782
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10783
+ TooltipTrigger,
10784
+ {
10785
+ className: cn(
10786
+ "flex cursor-pointer items-center justify-center rounded-[8px] p-2 transition-colors",
10787
+ rulersVisible ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
10788
+ ),
10789
+ onPointerDown: (e) => e.stopPropagation(),
10790
+ onClick: onToggleRulers,
10791
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.Ruler, { className: "size-4" })
10792
+ }
10014
10793
  ),
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
- ] })
10794
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10795
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: rulersVisible ? "Hide rulers" : "Show rulers" }),
10796
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.ArrowBigUp, { className: "size-2.5" }) }),
10797
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "R" })
10798
+ ] })
10799
+ ] }),
10800
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10801
+ ZoomPopover,
10802
+ {
10803
+ tooltipSide,
10804
+ canvasActive,
10805
+ canvasZoom,
10806
+ isOpen: activePopover === "zoom",
10807
+ onOpenChange: (open) => setActivePopover(open ? "zoom" : null),
10808
+ onToggleCanvas,
10809
+ onSetCanvasZoom,
10810
+ onZoomTo100,
10811
+ onFitToViewport
10812
+ }
10813
+ ),
10814
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
10815
+ "border-foreground/10",
10816
+ isVertical ? "my-0.5 w-5 border-t" : "mx-0.5 h-5 border-l"
10817
+ ) }),
10818
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10819
+ EditsPopover,
10820
+ {
10821
+ tooltipSide,
10822
+ sessionEditCount,
10823
+ isOpen: activePopover === "edits",
10824
+ onOpenChange: (open) => setActivePopover(open ? "edits" : null),
10825
+ onGetSessionItems,
10826
+ onExportAllEdits,
10827
+ onSendAllToAgents,
10828
+ onClearSessionEdits,
10829
+ onRemoveSessionEdit,
10830
+ onDeleteComment
10831
+ }
10832
+ ),
10833
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10834
+ SettingsPopover,
10835
+ {
10836
+ tooltipSide,
10837
+ theme,
10838
+ isMac,
10839
+ isOpen: activePopover === "settings",
10840
+ onOpenChange: (open) => setActivePopover(open ? "settings" : null),
10841
+ onSetTheme
10842
+ }
10843
+ ),
10844
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(
10845
+ "border-foreground/10",
10846
+ isVertical ? "my-0.5 w-5 border-t" : "mx-0.5 h-5 border-l"
10847
+ ) }),
10848
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Tooltip, { children: [
10849
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10850
+ TooltipTrigger,
10851
+ {
10852
+ className: "flex cursor-pointer items-center justify-center rounded-[8px] p-2 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
10853
+ onPointerDown: (e) => e.stopPropagation(),
10854
+ onClick: onToggleEditMode,
10855
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react16.X, { className: "size-4" })
10856
+ }
10857
+ ),
10858
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(TooltipContent, { side: tooltipSide, className: "inline-flex items-center gap-1.5", children: [
10859
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: "Close" }),
10860
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: kbdClass, children: "Esc" })
10861
+ ] })
10862
+ ] })
10863
+ ]
10864
+ }
10865
+ )
10055
10866
  }
10056
10867
  )
10057
10868
  ] })
@@ -10064,7 +10875,7 @@ function DirectEditToolbarInner({
10064
10875
  return toolbar;
10065
10876
  }
10066
10877
  function DirectEditToolbarContent() {
10067
- const { editModeActive, activeTool, theme, sessionEditCount } = useDirectEditState();
10878
+ const { editModeActive, activeTool, theme, sessionEditCount, canvas } = useDirectEditState();
10068
10879
  const {
10069
10880
  toggleEditMode,
10070
10881
  setActiveTool,
@@ -10074,10 +10885,14 @@ function DirectEditToolbarContent() {
10074
10885
  sendAllSessionItemsToAgent,
10075
10886
  clearSessionEdits,
10076
10887
  removeSessionEdit,
10077
- deleteComment
10888
+ deleteComment,
10889
+ toggleCanvas,
10890
+ setCanvasZoom,
10891
+ zoomCanvasTo100,
10892
+ fitCanvasToViewport
10078
10893
  } = useDirectEditActions();
10079
10894
  const [rulersVisible, toggleRulers] = useRulersVisible();
10080
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
10895
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
10081
10896
  DirectEditToolbarInner,
10082
10897
  {
10083
10898
  editModeActive,
@@ -10094,34 +10909,40 @@ function DirectEditToolbarContent() {
10094
10909
  onSendAllToAgents: sendAllSessionItemsToAgent,
10095
10910
  onClearSessionEdits: clearSessionEdits,
10096
10911
  onRemoveSessionEdit: removeSessionEdit,
10097
- onDeleteComment: deleteComment
10912
+ onDeleteComment: deleteComment,
10913
+ canvasActive: canvas?.active ?? false,
10914
+ canvasZoom: canvas?.zoom ?? 1,
10915
+ onToggleCanvas: toggleCanvas,
10916
+ onSetCanvasZoom: setCanvasZoom,
10917
+ onZoomTo100: zoomCanvasTo100,
10918
+ onFitToViewport: fitCanvasToViewport
10098
10919
  }
10099
10920
  );
10100
10921
  }
10101
10922
  function DirectEditToolbar() {
10102
- const [mounted, setMounted] = React34.useState(false);
10103
- React34.useEffect(() => {
10923
+ const [mounted, setMounted] = React36.useState(false);
10924
+ React36.useEffect(() => {
10104
10925
  setMounted(true);
10105
10926
  }, []);
10106
10927
  if (!mounted) {
10107
10928
  return null;
10108
10929
  }
10109
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(DirectEditToolbarContent, {});
10930
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(DirectEditToolbarContent, {});
10110
10931
  }
10111
10932
 
10112
10933
  // src/direct-edit.tsx
10113
- var import_jsx_runtime33 = require("react/jsx-runtime");
10934
+ var import_jsx_runtime34 = require("react/jsx-runtime");
10114
10935
  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, {})
10936
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(DirectEditProvider, { children: [
10937
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DirectEditPanel, {}),
10938
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DirectEditToolbar, {}),
10939
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Rulers, {})
10119
10940
  ] });
10120
10941
  }
10121
10942
 
10122
10943
  // src/demo.tsx
10123
- var React35 = __toESM(require("react"));
10124
- var import_jsx_runtime34 = require("react/jsx-runtime");
10944
+ var React37 = __toESM(require("react"));
10945
+ var import_jsx_runtime35 = require("react/jsx-runtime");
10125
10946
  function createValue(num, unit = "px") {
10126
10947
  return { numericValue: num, unit, raw: `${num}${unit}` };
10127
10948
  }
@@ -10149,7 +10970,7 @@ var DEMO_LOCATOR = {
10149
10970
  classList: ELEMENT_INFO.classList
10150
10971
  };
10151
10972
  function DirectEditDemo() {
10152
- const [spacing, setSpacing] = React35.useState({
10973
+ const [spacing, setSpacing] = React37.useState({
10153
10974
  paddingTop: createValue(16),
10154
10975
  paddingRight: createValue(16),
10155
10976
  paddingBottom: createValue(16),
@@ -10160,13 +10981,13 @@ function DirectEditDemo() {
10160
10981
  marginLeft: createValue(0),
10161
10982
  gap: createValue(16)
10162
10983
  });
10163
- const [borderRadius, setBorderRadius] = React35.useState({
10984
+ const [borderRadius, setBorderRadius] = React37.useState({
10164
10985
  borderTopLeftRadius: createValue(8),
10165
10986
  borderTopRightRadius: createValue(8),
10166
10987
  borderBottomRightRadius: createValue(8),
10167
10988
  borderBottomLeftRadius: createValue(8)
10168
10989
  });
10169
- const [border, setBorder] = React35.useState({
10990
+ const [border, setBorder] = React37.useState({
10170
10991
  borderTopStyle: "solid",
10171
10992
  borderTopWidth: createValue(1),
10172
10993
  borderRightStyle: "solid",
@@ -10176,23 +10997,23 @@ function DirectEditDemo() {
10176
10997
  borderLeftStyle: "solid",
10177
10998
  borderLeftWidth: createValue(1)
10178
10999
  });
10179
- const [flex, setFlex] = React35.useState({
11000
+ const [flex, setFlex] = React37.useState({
10180
11001
  display: "flex",
10181
11002
  flexDirection: "row",
10182
11003
  justifyContent: "flex-start",
10183
11004
  alignItems: "center"
10184
11005
  });
10185
- const [sizing, setSizing] = React35.useState({
11006
+ const [sizing, setSizing] = React37.useState({
10186
11007
  width: { mode: "fit", value: createValue(300) },
10187
11008
  height: { mode: "fit", value: createValue(100) }
10188
11009
  });
10189
- const [color, setColor] = React35.useState({
11010
+ const [color, setColor] = React37.useState({
10190
11011
  backgroundColor: { hex: "FFFFFF", alpha: 100, raw: "rgb(255, 255, 255)" },
10191
11012
  color: { hex: "000000", alpha: 100, raw: "rgb(0, 0, 0)" },
10192
11013
  borderColor: { hex: "DDDDDD", alpha: 100, raw: "rgb(221, 221, 221)" },
10193
11014
  outlineColor: { hex: "000000", alpha: 0, raw: "transparent" }
10194
11015
  });
10195
- const [typography, setTypography] = React35.useState({
11016
+ const [typography, setTypography] = React37.useState({
10196
11017
  fontFamily: "system-ui, sans-serif",
10197
11018
  fontWeight: "400",
10198
11019
  fontSize: createValue(16),
@@ -10201,9 +11022,9 @@ function DirectEditDemo() {
10201
11022
  textAlign: "left",
10202
11023
  textVerticalAlign: "flex-start"
10203
11024
  });
10204
- const [boxShadow, setBoxShadow] = React35.useState("none");
10205
- const [pendingStyles, setPendingStyles] = React35.useState({});
10206
- const [editModeActive, setEditModeActive] = React35.useState(false);
11025
+ const [boxShadow, setBoxShadow] = React37.useState("none");
11026
+ const [pendingStyles, setPendingStyles] = React37.useState({});
11027
+ const [editModeActive, setEditModeActive] = React37.useState(false);
10207
11028
  const handleUpdateSpacing = (key, value) => {
10208
11029
  setSpacing((prev) => ({ ...prev, [key]: value }));
10209
11030
  setPendingStyles((prev) => ({ ...prev, [camelToKebab(key)]: value.raw }));
@@ -10314,10 +11135,10 @@ function DirectEditDemo() {
10314
11135
  return false;
10315
11136
  }
10316
11137
  };
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)(
11138
+ 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: [
11139
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { className: "mb-2 text-2xl font-bold", children: "Direct Edit Panel" }),
11140
+ /* @__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." }),
11141
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "mb-8 flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
10321
11142
  DirectEditToolbarInner,
10322
11143
  {
10323
11144
  editModeActive,
@@ -10327,8 +11148,8 @@ function DirectEditDemo() {
10327
11148
  }
10328
11149
  }
10329
11150
  ) }),
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)(
11151
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "grid gap-8 lg:grid-cols-[300px_1fr]", children: [
11152
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
10332
11153
  DirectEditPanelInner,
10333
11154
  {
10334
11155
  elementInfo: ELEMENT_INFO,
@@ -10360,10 +11181,10 @@ function DirectEditDemo() {
10360
11181
  onSendToAgent: async () => false
10361
11182
  }
10362
11183
  ),
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)(
11184
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "space-y-6", children: [
11185
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
11186
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Live Preview" }),
11187
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
10367
11188
  "div",
10368
11189
  {
10369
11190
  className: "bg-background border flex",
@@ -10386,20 +11207,20 @@ function DirectEditDemo() {
10386
11207
  alignItems: flex.alignItems
10387
11208
  },
10388
11209
  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" })
11210
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "size-12 rounded bg-blue-500/20 border border-blue-500/30" }),
11211
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "size-12 rounded bg-green-500/20 border border-green-500/30" }),
11212
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "size-12 rounded bg-purple-500/20 border border-purple-500/30" })
10392
11213
  ]
10393
11214
  }
10394
11215
  )
10395
11216
  ] }),
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" })
11217
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
11218
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Pending Styles" }),
11219
+ /* @__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
11220
  ] }),
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" })
11221
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
11222
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: "mb-3 text-sm font-medium", children: "Tailwind Classes" }),
11223
+ /* @__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
11224
  ] })
10404
11225
  ] })
10405
11226
  ] })