@pixerate/editor-react 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +2 -2
  2. package/dist/canvas/index.cjs +406 -142
  3. package/dist/canvas/index.cjs.map +1 -1
  4. package/dist/canvas/index.d.cts +66 -3
  5. package/dist/canvas/index.d.ts +66 -3
  6. package/dist/canvas/index.js +277 -0
  7. package/dist/canvas/index.js.map +1 -1
  8. package/dist/chunk-I3E4KSA2.js +515 -0
  9. package/dist/chunk-I3E4KSA2.js.map +1 -0
  10. package/dist/chunk-JR5ZBDR7.js +2012 -0
  11. package/dist/chunk-JR5ZBDR7.js.map +1 -0
  12. package/dist/{chunk-XTFR3IMK.js → chunk-ZU54BMDC.js} +473 -160
  13. package/dist/chunk-ZU54BMDC.js.map +1 -0
  14. package/dist/generation/index.cjs +290 -0
  15. package/dist/generation/index.cjs.map +1 -1
  16. package/dist/generation/index.d.cts +66 -2
  17. package/dist/generation/index.d.ts +66 -2
  18. package/dist/generation/index.js +7 -1
  19. package/dist/image-editor/index.cjs +490 -187
  20. package/dist/image-editor/index.cjs.map +1 -1
  21. package/dist/image-editor/index.d.cts +34 -2
  22. package/dist/image-editor/index.d.ts +34 -2
  23. package/dist/image-editor/index.js +5 -1
  24. package/dist/index.cjs +2372 -731
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +88 -6
  27. package/dist/index.d.ts +88 -6
  28. package/dist/index.js +334 -96
  29. package/dist/index.js.map +1 -1
  30. package/dist/spreadsheet/index.cjs +943 -112
  31. package/dist/spreadsheet/index.cjs.map +1 -1
  32. package/dist/spreadsheet/index.d.cts +119 -7
  33. package/dist/spreadsheet/index.d.ts +119 -7
  34. package/dist/spreadsheet/index.js +11 -1
  35. package/dist/tokens/index.cjs +395 -0
  36. package/dist/tokens/index.cjs.map +1 -0
  37. package/dist/tokens/index.d.cts +54 -0
  38. package/dist/tokens/index.d.ts +54 -0
  39. package/dist/tokens/index.js +375 -0
  40. package/dist/tokens/index.js.map +1 -0
  41. package/package.json +10 -2
  42. package/dist/chunk-7SPRQZ6H.js +0 -216
  43. package/dist/chunk-7SPRQZ6H.js.map +0 -1
  44. package/dist/chunk-FYIPXHAE.js +0 -1169
  45. package/dist/chunk-FYIPXHAE.js.map +0 -1
  46. package/dist/chunk-XTFR3IMK.js.map +0 -1
@@ -35,6 +35,8 @@ __export(image_editor_exports, {
35
35
  CurvesEditor: () => CurvesEditor,
36
36
  Histogram: () => Histogram,
37
37
  ImageEditor: () => ImageEditor,
38
+ RefineEdgePanel: () => RefineEdgePanel,
39
+ SelectionOptionsBar: () => SelectionOptionsBar,
38
40
  useImageEditor: () => useImageEditor,
39
41
  useImageHistogram: () => useImageHistogram
40
42
  });
@@ -199,8 +201,8 @@ function useImageEditor(options = {}) {
199
201
  }
200
202
 
201
203
  // src/image-editor/ImageEditor.tsx
202
- var import_react5 = __toESM(require("react"), 1);
203
- var import_image_editor6 = require("@pixerate/editor/image-editor");
204
+ var import_react7 = __toESM(require("react"), 1);
205
+ var import_image_editor8 = require("@pixerate/editor/image-editor");
204
206
 
205
207
  // src/image-editor/ControlSlider.tsx
206
208
  var import_image_editor2 = require("@pixerate/editor/image-editor");
@@ -631,8 +633,248 @@ var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
631
633
  ] });
632
634
  };
633
635
 
634
- // src/image-editor/ImageEditor.tsx
636
+ // src/image-editor/SelectionOptionsBar.tsx
637
+ var import_react5 = require("react");
638
+ var import_image_editor6 = require("@pixerate/editor/image-editor");
635
639
  var import_jsx_runtime5 = require("react/jsx-runtime");
640
+ var MODIFY_OPS = [
641
+ { op: "grow", label: "Grow" },
642
+ { op: "shrink", label: "Shrink" },
643
+ { op: "feather", label: "Feather" },
644
+ { op: "border", label: "Border" },
645
+ { op: "smooth", label: "Smooth" }
646
+ ];
647
+ var btn = (on) => `px-2 py-1 rounded-md border text-[11px] transition-colors ${on ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-950 border-slate-800 text-slate-300 hover:text-white"}`;
648
+ var SelectionOptionsBar = ({
649
+ controller,
650
+ options,
651
+ onOptionsChange,
652
+ selection,
653
+ quickMask,
654
+ className = ""
655
+ }) => {
656
+ const [radius, setRadius] = (0, import_react5.useState)(2);
657
+ const set = (patch) => onOptionsChange({ ...options, ...patch });
658
+ const sel = selection === void 0 ? controller.getSelection() : selection;
659
+ const qm = quickMask ?? Boolean(controller.getState().quickMask);
660
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
661
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor6.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
662
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor6.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor6.SELECTION_MODE_LABELS[m] }, m)) }),
663
+ options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-2", children: [
664
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-1", children: [
665
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
666
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Tolerance" }),
667
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: options.tolerance })
668
+ ] }),
669
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
670
+ "input",
671
+ {
672
+ type: "range",
673
+ min: 0,
674
+ max: 255,
675
+ step: 1,
676
+ "aria-label": "Tolerance",
677
+ value: options.tolerance,
678
+ onChange: (e) => set({ tolerance: Number(e.target.value) }),
679
+ className: "w-full accent-indigo-500"
680
+ }
681
+ )
682
+ ] }),
683
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
684
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
685
+ "Contiguous"
686
+ ] }),
687
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
688
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
689
+ "Sample adjusted image"
690
+ ] })
691
+ ] }),
692
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
693
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
694
+ "Anti-alias"
695
+ ] }),
696
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
697
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
698
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
699
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
700
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
701
+ ] }),
702
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
703
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
704
+ "Radius",
705
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
706
+ "input",
707
+ {
708
+ type: "number",
709
+ min: 0,
710
+ max: 500,
711
+ step: 1,
712
+ "aria-label": "Modify radius",
713
+ value: radius,
714
+ onChange: (e) => setRadius(Math.max(0, Number(e.target.value) || 0)),
715
+ className: "w-14 bg-slate-950 border border-slate-800 rounded px-1 py-0.5 text-slate-200"
716
+ }
717
+ )
718
+ ] }),
719
+ MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
720
+ ] }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor6.describeSelection)(sel) })
722
+ ] });
723
+ };
724
+
725
+ // src/image-editor/RefineEdgePanel.tsx
726
+ var import_react6 = require("react");
727
+ var import_image_editor7 = require("@pixerate/editor/image-editor");
728
+ var import_jsx_runtime6 = require("react/jsx-runtime");
729
+ var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
730
+ var button = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
731
+ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
732
+ const [params, setParams] = (0, import_react6.useState)(DEFAULT_PARAMS);
733
+ const [busy, setBusy] = (0, import_react6.useState)(false);
734
+ const [error, setError] = (0, import_react6.useState)(null);
735
+ const [layerId, setLayerId] = (0, import_react6.useState)("");
736
+ const [newKind, setNewKind] = (0, import_react6.useState)("hueSaturation");
737
+ const sel = selection === void 0 ? controller.getSelection() : selection;
738
+ const list = layers ?? controller.getAdjustmentLayers();
739
+ const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
740
+ const refine = async () => {
741
+ setBusy(true);
742
+ setError(null);
743
+ try {
744
+ await controller.refineSelection(params);
745
+ } catch (err) {
746
+ setError(err instanceof Error ? err.message : String(err));
747
+ } finally {
748
+ setBusy(false);
749
+ }
750
+ };
751
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
752
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
753
+ import_image_editor7.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex flex-col gap-1", children: [
754
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
755
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: c.label }),
756
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "font-mono", children: [
757
+ params[c.id],
758
+ c.unit
759
+ ] })
760
+ ] }),
761
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
762
+ "input",
763
+ {
764
+ type: "range",
765
+ min: c.min,
766
+ max: c.max,
767
+ step: c.step,
768
+ "aria-label": c.label,
769
+ value: params[c.id],
770
+ onChange: (e) => setParams({ ...params, [c.id]: Number(e.target.value) }),
771
+ className: "w-full accent-indigo-500"
772
+ }
773
+ )
774
+ ] }, c.id)),
775
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
776
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
777
+ "Smart Radius"
778
+ ] }),
779
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex gap-1", children: [
780
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
781
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: button, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
782
+ ] }),
783
+ error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
784
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
785
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex gap-1 items-center", children: [
786
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
787
+ "select",
788
+ {
789
+ "aria-label": "New masked layer kind",
790
+ value: newKind,
791
+ onChange: (e) => setNewKind(e.target.value),
792
+ className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
793
+ children: import_image_editor7.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: k.kind, children: k.label }, k.kind))
794
+ }
795
+ ),
796
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
797
+ "button",
798
+ {
799
+ type: "button",
800
+ className: button,
801
+ disabled: !sel,
802
+ onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor7.layerMaskFromSelection)(sel) })),
803
+ children: "New Masked Layer"
804
+ }
805
+ )
806
+ ] }),
807
+ list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col gap-2", children: [
808
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
809
+ "select",
810
+ {
811
+ "aria-label": "Mask layer",
812
+ value: target.id,
813
+ onChange: (e) => setLayerId(e.target.value),
814
+ className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
815
+ children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("option", { value: l.id, children: [
816
+ l.name || (0, import_image_editor7.adjustmentKindLabel)(l.kind),
817
+ l.mask ? " (masked)" : ""
818
+ ] }, l.id))
819
+ }
820
+ ),
821
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
822
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
823
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
824
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
825
+ ] }),
826
+ target.mask && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
827
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex flex-col gap-1", children: [
828
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
829
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Density" }),
830
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "font-mono", children: [
831
+ Math.round((target.mask.density ?? 1) * 100),
832
+ "%"
833
+ ] })
834
+ ] }),
835
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
836
+ "input",
837
+ {
838
+ type: "range",
839
+ min: 0,
840
+ max: 100,
841
+ step: 1,
842
+ "aria-label": "Mask density",
843
+ value: Math.round((target.mask.density ?? 1) * 100),
844
+ onChange: (e) => controller.setAdjustmentLayerMaskProps(target.id, { density: Number(e.target.value) / 100 }),
845
+ className: "w-full accent-indigo-500"
846
+ }
847
+ )
848
+ ] }),
849
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex flex-col gap-1", children: [
850
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
851
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Mask Feather" }),
852
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "font-mono", children: [
853
+ target.mask.feather ?? 0,
854
+ "px"
855
+ ] })
856
+ ] }),
857
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
858
+ "input",
859
+ {
860
+ type: "range",
861
+ min: 0,
862
+ max: 50,
863
+ step: 0.5,
864
+ "aria-label": "Mask feather",
865
+ value: target.mask.feather ?? 0,
866
+ onChange: (e) => controller.setAdjustmentLayerMaskProps(target.id, { feather: Number(e.target.value) }),
867
+ className: "w-full accent-indigo-500"
868
+ }
869
+ )
870
+ ] })
871
+ ] })
872
+ ] })
873
+ ] });
874
+ };
875
+
876
+ // src/image-editor/ImageEditor.tsx
877
+ var import_jsx_runtime7 = require("react/jsx-runtime");
636
878
  var ImageEditor = ({
637
879
  editor: externalEditor,
638
880
  src,
@@ -647,17 +889,26 @@ var ImageEditor = ({
647
889
  const internalEditor = useImageEditor({ image: src });
648
890
  const editor = externalEditor || internalEditor;
649
891
  const { state, controller } = editor;
650
- const legacyProcess = (0, import_image_editor6.normalizeProcessVersion)(state.adjustments.process) < import_image_editor6.LATEST_PROCESS_VERSION;
651
- const canvasRef = (0, import_react5.useRef)(null);
652
- const containerRef = (0, import_react5.useRef)(null);
653
- const [activeTab, setActiveTab] = (0, import_react5.useState)("crop");
654
- const [activeCropRatio, setActiveCropRatio] = (0, import_react5.useState)(null);
655
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react5.useState)("");
656
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react5.useState)("annotations");
657
- const [isRemovingBg, setIsRemovingBg] = (0, import_react5.useState)(false);
658
- const [isInpainting, setIsInpainting] = (0, import_react5.useState)(false);
659
- const [aiError, setAiError] = (0, import_react5.useState)(null);
660
- const [aiSuccess, setAiSuccess] = (0, import_react5.useState)(null);
892
+ const legacyProcess = (0, import_image_editor8.normalizeProcessVersion)(state.adjustments.process) < import_image_editor8.LATEST_PROCESS_VERSION;
893
+ const canvasRef = (0, import_react7.useRef)(null);
894
+ const containerRef = (0, import_react7.useRef)(null);
895
+ const [activeTab, setActiveTab] = (0, import_react7.useState)("crop");
896
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react7.useState)(null);
897
+ const [selectionOptions, setSelectionOptions] = (0, import_react7.useState)(import_image_editor8.DEFAULT_SELECTION_TOOL_OPTIONS);
898
+ const selectionOptionsRef = (0, import_react7.useRef)(selectionOptions);
899
+ selectionOptionsRef.current = selectionOptions;
900
+ const selectionGestureRef = (0, import_react7.useRef)(null);
901
+ if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
902
+ selectionGestureRef.current = new import_image_editor8.SelectionGesture(controller, () => selectionOptionsRef.current);
903
+ }
904
+ const selectionDraftRef = (0, import_react7.useRef)(null);
905
+ const [selectionError, setSelectionError] = (0, import_react7.useState)(null);
906
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react7.useState)("");
907
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react7.useState)("annotations");
908
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react7.useState)(false);
909
+ const [isInpainting, setIsInpainting] = (0, import_react7.useState)(false);
910
+ const [aiError, setAiError] = (0, import_react7.useState)(null);
911
+ const [aiSuccess, setAiSuccess] = (0, import_react7.useState)(null);
661
912
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
662
913
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
663
914
  const handleRemoveBackground = async () => {
@@ -719,18 +970,18 @@ var ImageEditor = ({
719
970
  setIsInpainting(false);
720
971
  }
721
972
  };
722
- const [activeColor, setActiveColor] = (0, import_react5.useState)("#ef4444");
723
- const [strokeWidth, setStrokeWidth] = (0, import_react5.useState)(3);
724
- const [fontSize, setFontSize] = (0, import_react5.useState)(24);
725
- const [textInput, setTextInput] = (0, import_react5.useState)("");
726
- const draftAnnotationRef = (0, import_react5.useRef)(null);
727
- const draftCropRef = (0, import_react5.useRef)(null);
728
- const cropDragInfoRef = (0, import_react5.useRef)(null);
729
- const annotationDragInfoRef = (0, import_react5.useRef)(null);
730
- const isDrawingRef = (0, import_react5.useRef)(false);
731
- const currentPathRef = (0, import_react5.useRef)([]);
732
- const dragStartPointRef = (0, import_react5.useRef)(null);
733
- const renderCanvas = (0, import_react5.useCallback)(
973
+ const [activeColor, setActiveColor] = (0, import_react7.useState)("#ef4444");
974
+ const [strokeWidth, setStrokeWidth] = (0, import_react7.useState)(3);
975
+ const [fontSize, setFontSize] = (0, import_react7.useState)(24);
976
+ const [textInput, setTextInput] = (0, import_react7.useState)("");
977
+ const draftAnnotationRef = (0, import_react7.useRef)(null);
978
+ const draftCropRef = (0, import_react7.useRef)(null);
979
+ const cropDragInfoRef = (0, import_react7.useRef)(null);
980
+ const annotationDragInfoRef = (0, import_react7.useRef)(null);
981
+ const isDrawingRef = (0, import_react7.useRef)(false);
982
+ const currentPathRef = (0, import_react7.useRef)([]);
983
+ const dragStartPointRef = (0, import_react7.useRef)(null);
984
+ const renderCanvas = (0, import_react7.useCallback)(
734
985
  async (draftAnnotation, draftCrop) => {
735
986
  const canvas = canvasRef.current;
736
987
  const container = containerRef.current;
@@ -744,12 +995,13 @@ var ImageEditor = ({
744
995
  showSelectionOverlay: true,
745
996
  interactive: true,
746
997
  draftAnnotation: draftAnnotation !== void 0 ? draftAnnotation : draftAnnotationRef.current,
747
- draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current
998
+ draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
999
+ draftSelectionPath: selectionDraftRef.current
748
1000
  });
749
1001
  },
750
1002
  [controller, activeTab]
751
1003
  );
752
- (0, import_react5.useEffect)(() => {
1004
+ (0, import_react7.useEffect)(() => {
753
1005
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
754
1006
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
755
1007
  const animId = raf(() => {
@@ -757,12 +1009,12 @@ var ImageEditor = ({
757
1009
  });
758
1010
  return () => caf(animId);
759
1011
  }, [renderCanvas, state]);
760
- (0, import_react5.useEffect)(() => {
1012
+ (0, import_react7.useEffect)(() => {
761
1013
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
762
1014
  editor.setTool("crop");
763
1015
  }
764
1016
  }, [activeTab, editor]);
765
- (0, import_react5.useEffect)(() => {
1017
+ (0, import_react7.useEffect)(() => {
766
1018
  const container = containerRef.current;
767
1019
  if (!container) return;
768
1020
  if (typeof ResizeObserver !== "undefined") {
@@ -792,6 +1044,12 @@ var ImageEditor = ({
792
1044
  const canvas = canvasRef.current;
793
1045
  if (!canvas) return;
794
1046
  const canvasPt = getCanvasEventPoint(e);
1047
+ if (activeTab === "select") {
1048
+ const gesture = selectionGestureRef.current;
1049
+ const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1050
+ void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
1051
+ return;
1052
+ }
795
1053
  if (activeTab === "crop") {
796
1054
  const activeCrop = draftCropRef.current || state.crop || {
797
1055
  x: 0,
@@ -799,8 +1057,8 @@ var ImageEditor = ({
799
1057
  width: state.imageDimensions.width,
800
1058
  height: state.imageDimensions.height
801
1059
  };
802
- const handle = (0, import_image_editor6.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
803
- const startImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
1060
+ const handle = (0, import_image_editor8.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1061
+ const startImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
804
1062
  if (handle) {
805
1063
  cropDragInfoRef.current = {
806
1064
  handle,
@@ -819,12 +1077,12 @@ var ImageEditor = ({
819
1077
  return;
820
1078
  }
821
1079
  if (activeTab === "annotate") {
822
- const imgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1080
+ const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
823
1081
  dragStartPointRef.current = imgPt;
824
1082
  if (state.activeTool === "select") {
825
1083
  for (let i = state.annotations.length - 1; i >= 0; i--) {
826
1084
  const ann = state.annotations[i];
827
- if ((0, import_image_editor6.hitTestAnnotation)(imgPt, ann)) {
1085
+ if ((0, import_image_editor8.hitTestAnnotation)(imgPt, ann)) {
828
1086
  editor.selectAnnotation(ann.id);
829
1087
  annotationDragInfoRef.current = {
830
1088
  annId: ann.id,
@@ -858,10 +1116,18 @@ var ImageEditor = ({
858
1116
  const canvas = canvasRef.current;
859
1117
  if (!canvas) return;
860
1118
  const canvasPt = getCanvasEventPoint(e);
1119
+ if (activeTab === "select") {
1120
+ const gesture = selectionGestureRef.current;
1121
+ if (gesture.active && gesture.move((0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
1122
+ selectionDraftRef.current = gesture.draftPath;
1123
+ renderCanvas();
1124
+ }
1125
+ return;
1126
+ }
861
1127
  if (activeTab === "crop") {
862
1128
  const drag = cropDragInfoRef.current;
863
1129
  if (drag) {
864
- const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
1130
+ const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
865
1131
  let newCrop;
866
1132
  if (drag.handle === "new") {
867
1133
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -875,7 +1141,7 @@ var ImageEditor = ({
875
1141
  height: Math.round(Math.max(20, maxY - minY))
876
1142
  };
877
1143
  } else {
878
- newCrop = (0, import_image_editor6.calculateCropDrag)(
1144
+ newCrop = (0, import_image_editor8.calculateCropDrag)(
879
1145
  drag.startCrop,
880
1146
  drag.handle,
881
1147
  drag.startImgPt,
@@ -895,15 +1161,15 @@ var ImageEditor = ({
895
1161
  width: state.imageDimensions.width,
896
1162
  height: state.imageDimensions.height
897
1163
  };
898
- const handle = (0, import_image_editor6.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
899
- canvas.style.cursor = (0, import_image_editor6.getCropCursor)(handle, state.transform);
1164
+ const handle = (0, import_image_editor8.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1165
+ canvas.style.cursor = (0, import_image_editor8.getCropCursor)(handle, state.transform);
900
1166
  }
901
1167
  return;
902
1168
  }
903
1169
  if (activeTab === "annotate") {
904
1170
  if (annotationDragInfoRef.current) {
905
1171
  const drag = annotationDragInfoRef.current;
906
- const currentImgPt2 = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1172
+ const currentImgPt2 = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
907
1173
  const dx = currentImgPt2.x - drag.startImgPt.x;
908
1174
  const dy = currentImgPt2.y - drag.startImgPt.y;
909
1175
  editor.updateAnnotation(drag.annId, {
@@ -915,10 +1181,10 @@ var ImageEditor = ({
915
1181
  const startPt = dragStartPointRef.current;
916
1182
  if (!startPt) {
917
1183
  if (state.activeTool === "select") {
918
- const imgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1184
+ const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
919
1185
  let hovered = false;
920
1186
  for (let i = state.annotations.length - 1; i >= 0; i--) {
921
- if ((0, import_image_editor6.hitTestAnnotation)(imgPt, state.annotations[i])) {
1187
+ if ((0, import_image_editor8.hitTestAnnotation)(imgPt, state.annotations[i])) {
922
1188
  hovered = true;
923
1189
  break;
924
1190
  }
@@ -929,7 +1195,7 @@ var ImageEditor = ({
929
1195
  }
930
1196
  return;
931
1197
  }
932
- const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1198
+ const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
933
1199
  if (state.activeTool === "pen" && isDrawingRef.current) {
934
1200
  currentPathRef.current.push(currentImgPt);
935
1201
  const draft = {
@@ -1006,6 +1272,15 @@ var ImageEditor = ({
1006
1272
  const canvas = canvasRef.current;
1007
1273
  if (!canvas) return;
1008
1274
  const canvasPt = getCanvasEventPoint(e);
1275
+ if (activeTab === "select") {
1276
+ const gesture = selectionGestureRef.current;
1277
+ if (gesture.active) {
1278
+ gesture.end((0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
1279
+ selectionDraftRef.current = null;
1280
+ renderCanvas();
1281
+ }
1282
+ return;
1283
+ }
1009
1284
  if (activeTab === "crop") {
1010
1285
  if (cropDragInfoRef.current) {
1011
1286
  if (draftCropRef.current && draftCropRef.current.width >= 20 && draftCropRef.current.height >= 20) {
@@ -1024,7 +1299,7 @@ var ImageEditor = ({
1024
1299
  }
1025
1300
  const startPt = dragStartPointRef.current;
1026
1301
  if (startPt) {
1027
- const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1302
+ const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1028
1303
  if (state.activeTool === "pen" && isDrawingRef.current) {
1029
1304
  if (currentPathRef.current.length > 1) {
1030
1305
  editor.addAnnotation({
@@ -1120,15 +1395,15 @@ var ImageEditor = ({
1120
1395
  link.click();
1121
1396
  }
1122
1397
  };
1123
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1398
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1124
1399
  "div",
1125
1400
  {
1126
1401
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
1127
1402
  style,
1128
1403
  children: [
1129
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
1130
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
1131
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1404
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
1405
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
1406
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1132
1407
  "button",
1133
1408
  {
1134
1409
  type: "button",
@@ -1140,7 +1415,7 @@ var ImageEditor = ({
1140
1415
  children: "Transform & Crop"
1141
1416
  }
1142
1417
  ),
1143
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1418
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1144
1419
  "button",
1145
1420
  {
1146
1421
  type: "button",
@@ -1152,7 +1427,19 @@ var ImageEditor = ({
1152
1427
  children: "Adjustments"
1153
1428
  }
1154
1429
  ),
1155
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1430
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1431
+ "button",
1432
+ {
1433
+ type: "button",
1434
+ onClick: () => {
1435
+ setActiveTab("select");
1436
+ editor.setTool("select");
1437
+ },
1438
+ className: `px-3 py-1.5 rounded-md font-medium transition-colors ${activeTab === "select" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
1439
+ children: "Select & Mask"
1440
+ }
1441
+ ),
1442
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1156
1443
  "button",
1157
1444
  {
1158
1445
  type: "button",
@@ -1164,7 +1451,7 @@ var ImageEditor = ({
1164
1451
  children: "Annotations"
1165
1452
  }
1166
1453
  ),
1167
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1454
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1168
1455
  "button",
1169
1456
  {
1170
1457
  type: "button",
@@ -1176,7 +1463,7 @@ var ImageEditor = ({
1176
1463
  children: "Depth Mask"
1177
1464
  }
1178
1465
  ),
1179
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1466
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1180
1467
  "button",
1181
1468
  {
1182
1469
  type: "button",
@@ -1186,14 +1473,14 @@ var ImageEditor = ({
1186
1473
  },
1187
1474
  className: `px-3 py-1.5 rounded-md font-medium transition-colors flex items-center gap-1.5 ${activeTab === "ai" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
1188
1475
  children: [
1189
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
1476
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
1190
1477
  "AI Tools"
1191
1478
  ]
1192
1479
  }
1193
1480
  )
1194
1481
  ] }),
1195
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
1196
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1482
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
1483
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1197
1484
  "button",
1198
1485
  {
1199
1486
  type: "button",
@@ -1204,7 +1491,7 @@ var ImageEditor = ({
1204
1491
  children: "\u21A9"
1205
1492
  }
1206
1493
  ),
1207
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1494
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1208
1495
  "button",
1209
1496
  {
1210
1497
  type: "button",
@@ -1215,7 +1502,7 @@ var ImageEditor = ({
1215
1502
  children: "\u21AA"
1216
1503
  }
1217
1504
  ),
1218
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1505
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1219
1506
  "button",
1220
1507
  {
1221
1508
  type: "button",
@@ -1224,8 +1511,8 @@ var ImageEditor = ({
1224
1511
  children: "Reset"
1225
1512
  }
1226
1513
  ),
1227
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
1228
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1514
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1229
1516
  "button",
1230
1517
  {
1231
1518
  type: "button",
@@ -1235,11 +1522,11 @@ var ImageEditor = ({
1235
1522
  children: "-"
1236
1523
  }
1237
1524
  ),
1238
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
1525
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
1239
1526
  Math.round(state.zoom * 100),
1240
1527
  "%"
1241
1528
  ] }),
1242
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1529
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1243
1530
  "button",
1244
1531
  {
1245
1532
  type: "button",
@@ -1249,8 +1536,8 @@ var ImageEditor = ({
1249
1536
  children: "+"
1250
1537
  }
1251
1538
  ),
1252
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
1253
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1539
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
1540
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1254
1541
  "button",
1255
1542
  {
1256
1543
  type: "button",
@@ -1261,7 +1548,7 @@ var ImageEditor = ({
1261
1548
  children: "Hold Compare"
1262
1549
  }
1263
1550
  ),
1264
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1551
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1265
1552
  "button",
1266
1553
  {
1267
1554
  type: "button",
@@ -1272,13 +1559,13 @@ var ImageEditor = ({
1272
1559
  )
1273
1560
  ] })
1274
1561
  ] }),
1275
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
1276
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1562
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
1563
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1277
1564
  "div",
1278
1565
  {
1279
1566
  ref: containerRef,
1280
1567
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
1281
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1568
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1282
1569
  "canvas",
1283
1570
  {
1284
1571
  ref: canvasRef,
@@ -1291,11 +1578,11 @@ var ImageEditor = ({
1291
1578
  )
1292
1579
  }
1293
1580
  ),
1294
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
1295
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
1296
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
1297
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
1298
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1581
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
1582
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
1583
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
1585
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1299
1586
  "button",
1300
1587
  {
1301
1588
  type: "button",
@@ -1307,7 +1594,7 @@ var ImageEditor = ({
1307
1594
  children: "Freeform"
1308
1595
  }
1309
1596
  ),
1310
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1597
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1311
1598
  "button",
1312
1599
  {
1313
1600
  type: "button",
@@ -1319,7 +1606,7 @@ var ImageEditor = ({
1319
1606
  children: "1:1 Square"
1320
1607
  }
1321
1608
  ),
1322
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1609
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1323
1610
  "button",
1324
1611
  {
1325
1612
  type: "button",
@@ -1331,7 +1618,7 @@ var ImageEditor = ({
1331
1618
  children: "4:3 Standard"
1332
1619
  }
1333
1620
  ),
1334
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1621
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1335
1622
  "button",
1336
1623
  {
1337
1624
  type: "button",
@@ -1343,7 +1630,7 @@ var ImageEditor = ({
1343
1630
  children: "16:9 Wide"
1344
1631
  }
1345
1632
  ),
1346
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1633
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1347
1634
  "button",
1348
1635
  {
1349
1636
  type: "button",
@@ -1355,7 +1642,7 @@ var ImageEditor = ({
1355
1642
  children: "3:2 Photo"
1356
1643
  }
1357
1644
  ),
1358
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1645
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1359
1646
  "button",
1360
1647
  {
1361
1648
  type: "button",
@@ -1368,10 +1655,10 @@ var ImageEditor = ({
1368
1655
  }
1369
1656
  )
1370
1657
  ] }),
1371
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
1372
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
1373
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
1374
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1658
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
1659
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
1660
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1375
1662
  "button",
1376
1663
  {
1377
1664
  type: "button",
@@ -1380,7 +1667,7 @@ var ImageEditor = ({
1380
1667
  children: "Rotate -90\xB0"
1381
1668
  }
1382
1669
  ),
1383
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1670
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1384
1671
  "button",
1385
1672
  {
1386
1673
  type: "button",
@@ -1389,7 +1676,7 @@ var ImageEditor = ({
1389
1676
  children: "Rotate +90\xB0"
1390
1677
  }
1391
1678
  ),
1392
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1679
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1393
1680
  "button",
1394
1681
  {
1395
1682
  type: "button",
@@ -1398,7 +1685,7 @@ var ImageEditor = ({
1398
1685
  children: "Flip Horizontal"
1399
1686
  }
1400
1687
  ),
1401
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1688
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1402
1689
  "button",
1403
1690
  {
1404
1691
  type: "button",
@@ -1409,10 +1696,10 @@ var ImageEditor = ({
1409
1696
  )
1410
1697
  ] })
1411
1698
  ] }),
1412
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
1413
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
1414
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
1415
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1699
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
1700
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between", children: [
1701
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
1702
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1416
1703
  "button",
1417
1704
  {
1418
1705
  type: "button",
@@ -1422,25 +1709,25 @@ var ImageEditor = ({
1422
1709
  }
1423
1710
  )
1424
1711
  ] }),
1425
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Histogram, { histogram: editor.histogram }),
1426
- import_image_editor6.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react5.default.Fragment, { children: [
1427
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1712
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Histogram, { histogram: editor.histogram }),
1713
+ import_image_editor8.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react7.default.Fragment, { children: [
1714
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1428
1715
  ControlSlider,
1429
1716
  {
1430
1717
  spec,
1431
- value: (0, import_image_editor6.readAdjustmentControls)(state.adjustments)[spec.id],
1718
+ value: (0, import_image_editor8.readAdjustmentControls)(state.adjustments)[spec.id],
1432
1719
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
1433
1720
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
1434
1721
  }
1435
1722
  ),
1436
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1723
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1437
1724
  "div",
1438
1725
  {
1439
1726
  className: "flex items-center justify-between gap-2 rounded border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-200",
1440
1727
  "data-testid": "image-editor-process-notice",
1441
1728
  children: [
1442
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
1443
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1729
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
1730
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1444
1731
  "button",
1445
1732
  {
1446
1733
  type: "button",
@@ -1453,7 +1740,7 @@ var ImageEditor = ({
1453
1740
  }
1454
1741
  )
1455
1742
  ] }, spec.id)),
1456
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1743
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1457
1744
  AdjustmentLayersPanel,
1458
1745
  {
1459
1746
  controller,
@@ -1462,9 +1749,9 @@ var ImageEditor = ({
1462
1749
  }
1463
1750
  ) })
1464
1751
  ] }),
1465
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
1466
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
1467
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1752
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
1753
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
1754
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1468
1755
  "button",
1469
1756
  {
1470
1757
  type: "button",
@@ -1474,9 +1761,9 @@ var ImageEditor = ({
1474
1761
  },
1475
1762
  t
1476
1763
  )) }),
1477
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
1478
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-slate-400", children: "Color:" }),
1479
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1764
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
1765
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "text-slate-400", children: "Color:" }),
1766
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1480
1767
  "input",
1481
1768
  {
1482
1769
  type: "color",
@@ -1485,15 +1772,15 @@ var ImageEditor = ({
1485
1772
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
1486
1773
  }
1487
1774
  ),
1488
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex-1 ml-2", children: [
1489
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
1490
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Width:" }),
1491
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
1775
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex-1 ml-2", children: [
1776
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
1777
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Width:" }),
1778
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "font-mono", children: [
1492
1779
  strokeWidth,
1493
1780
  "px"
1494
1781
  ] })
1495
1782
  ] }),
1496
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1783
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1497
1784
  "input",
1498
1785
  {
1499
1786
  type: "range",
@@ -1506,10 +1793,10 @@ var ImageEditor = ({
1506
1793
  )
1507
1794
  ] })
1508
1795
  ] }),
1509
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
1510
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
1511
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex gap-2", children: [
1512
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1796
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
1797
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
1798
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-2", children: [
1799
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1513
1800
  "input",
1514
1801
  {
1515
1802
  type: "text",
@@ -1520,7 +1807,7 @@ var ImageEditor = ({
1520
1807
  className: "flex-1 bg-slate-950 border border-slate-700 rounded-lg px-2.5 py-1.5 text-xs text-slate-100 placeholder-slate-500 focus:outline-none focus:border-indigo-500"
1521
1808
  }
1522
1809
  ),
1523
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1810
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1524
1811
  "button",
1525
1812
  {
1526
1813
  type: "button",
@@ -1530,14 +1817,14 @@ var ImageEditor = ({
1530
1817
  }
1531
1818
  )
1532
1819
  ] }),
1533
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
1534
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Font Size:" }),
1535
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
1820
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
1821
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Font Size:" }),
1822
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "font-mono", children: [
1536
1823
  fontSize,
1537
1824
  "px"
1538
1825
  ] })
1539
1826
  ] }),
1540
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1827
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1541
1828
  "input",
1542
1829
  {
1543
1830
  type: "range",
@@ -1548,14 +1835,14 @@ var ImageEditor = ({
1548
1835
  className: "w-full accent-indigo-500"
1549
1836
  }
1550
1837
  ),
1551
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
1552
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
1553
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
1838
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
1839
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between", children: [
1840
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "text-slate-400", children: [
1554
1841
  "Layers (",
1555
1842
  state.annotations.length,
1556
1843
  ")"
1557
1844
  ] }),
1558
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1845
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1559
1846
  "button",
1560
1847
  {
1561
1848
  type: "button",
@@ -1564,7 +1851,7 @@ var ImageEditor = ({
1564
1851
  children: "Delete Selected"
1565
1852
  }
1566
1853
  ),
1567
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1854
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1568
1855
  "button",
1569
1856
  {
1570
1857
  type: "button",
@@ -1575,10 +1862,10 @@ var ImageEditor = ({
1575
1862
  )
1576
1863
  ] })
1577
1864
  ] }),
1578
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
1579
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
1580
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
1581
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1865
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
1866
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between", children: [
1867
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
1868
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1582
1869
  "button",
1583
1870
  {
1584
1871
  type: "button",
@@ -1588,8 +1875,8 @@ var ImageEditor = ({
1588
1875
  }
1589
1876
  )
1590
1877
  ] }),
1591
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
1592
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1878
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
1879
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1593
1880
  "input",
1594
1881
  {
1595
1882
  type: "checkbox",
@@ -1598,12 +1885,12 @@ var ImageEditor = ({
1598
1885
  className: "rounded accent-indigo-500"
1599
1886
  }
1600
1887
  ),
1601
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Enable Depth / Alpha Mask" })
1888
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Enable Depth / Alpha Mask" })
1602
1889
  ] }),
1603
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1604
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1605
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
1606
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1890
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1891
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
1892
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
1893
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1607
1894
  "input",
1608
1895
  {
1609
1896
  type: "text",
@@ -1614,8 +1901,8 @@ var ImageEditor = ({
1614
1901
  }
1615
1902
  )
1616
1903
  ] }),
1617
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex gap-2", children: [
1618
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1904
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-2", children: [
1905
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1619
1906
  "button",
1620
1907
  {
1621
1908
  type: "button",
@@ -1624,7 +1911,7 @@ var ImageEditor = ({
1624
1911
  children: "Threshold Mode"
1625
1912
  }
1626
1913
  ),
1627
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1914
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1628
1915
  "button",
1629
1916
  {
1630
1917
  type: "button",
@@ -1634,12 +1921,12 @@ var ImageEditor = ({
1634
1921
  }
1635
1922
  )
1636
1923
  ] }),
1637
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1638
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
1639
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Depth Start (Lower):" }),
1640
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
1924
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
1925
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
1926
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Depth Start (Lower):" }),
1927
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
1641
1928
  ] }),
1642
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1929
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1643
1930
  "input",
1644
1931
  {
1645
1932
  type: "range",
@@ -1653,12 +1940,12 @@ var ImageEditor = ({
1653
1940
  }
1654
1941
  )
1655
1942
  ] }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1657
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
1658
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Depth Stop (Upper):" }),
1659
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
1943
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
1944
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
1945
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Depth Stop (Upper):" }),
1946
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
1660
1947
  ] }),
1661
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1948
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1662
1949
  "input",
1663
1950
  {
1664
1951
  type: "range",
@@ -1672,12 +1959,12 @@ var ImageEditor = ({
1672
1959
  }
1673
1960
  )
1674
1961
  ] }),
1675
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1676
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
1677
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Softness:" }),
1678
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
1962
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
1963
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
1964
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Softness:" }),
1965
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
1679
1966
  ] }),
1680
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1967
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1681
1968
  "input",
1682
1969
  {
1683
1970
  type: "range",
@@ -1689,8 +1976,8 @@ var ImageEditor = ({
1689
1976
  }
1690
1977
  )
1691
1978
  ] }),
1692
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
1693
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1979
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
1980
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1694
1981
  "input",
1695
1982
  {
1696
1983
  type: "checkbox",
@@ -1699,52 +1986,66 @@ var ImageEditor = ({
1699
1986
  className: "rounded accent-indigo-500"
1700
1987
  }
1701
1988
  ),
1702
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Invert Mask" })
1989
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Invert Mask" })
1703
1990
  ] })
1704
1991
  ] })
1705
1992
  ] }),
1706
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
1707
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
1708
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
1709
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
1710
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
1993
+ activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
1994
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1995
+ SelectionOptionsBar,
1996
+ {
1997
+ controller,
1998
+ options: selectionOptions,
1999
+ onOptionsChange: setSelectionOptions,
2000
+ selection: state.selection ?? null,
2001
+ quickMask: Boolean(state.quickMask)
2002
+ }
2003
+ ),
2004
+ selectionError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
2005
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
2006
+ ] }),
2007
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2008
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2009
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between", children: [
2010
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2011
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
1711
2012
  "Background Removal"
1712
2013
  ] }),
1713
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
2014
+ isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
1714
2015
  ] }),
1715
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
1716
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2016
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1717
2018
  "button",
1718
2019
  {
1719
2020
  type: "button",
1720
2021
  onClick: handleRemoveBackground,
1721
2022
  disabled: isRemovingBg || isInpainting,
1722
2023
  className: "mt-1 px-3 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
1723
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1724
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2024
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2025
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
1725
2026
  "Removing Background..."
1726
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1727
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2027
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2028
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
1728
2029
  "Remove Background"
1729
2030
  ] })
1730
2031
  }
1731
2032
  )
1732
2033
  ] }),
1733
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
1734
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
1735
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
1736
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1737
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
1738
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m14 7 3 3" })
2034
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2035
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between", children: [
2036
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2037
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2038
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
2039
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m14 7 3 3" })
1739
2040
  ] }),
1740
2041
  "Generative Inpainting"
1741
2042
  ] }),
1742
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
2043
+ isInpainting && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
1743
2044
  ] }),
1744
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
1745
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-1", children: [
1746
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
1747
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2045
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
2046
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-1", children: [
2047
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
2048
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1748
2049
  "textarea",
1749
2050
  {
1750
2051
  id: "ai-inpaint-prompt-react",
@@ -1756,10 +2057,10 @@ var ImageEditor = ({
1756
2057
  }
1757
2058
  )
1758
2059
  ] }),
1759
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-1", children: [
1760
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
1761
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
1762
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2060
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-1", children: [
2061
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
2062
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
2063
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1763
2064
  "button",
1764
2065
  {
1765
2066
  type: "button",
@@ -1772,7 +2073,7 @@ var ImageEditor = ({
1772
2073
  ]
1773
2074
  }
1774
2075
  ),
1775
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2076
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1776
2077
  "button",
1777
2078
  {
1778
2079
  type: "button",
@@ -1787,25 +2088,25 @@ var ImageEditor = ({
1787
2088
  )
1788
2089
  ] })
1789
2090
  ] }),
1790
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2091
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1791
2092
  "button",
1792
2093
  {
1793
2094
  type: "button",
1794
2095
  onClick: handleInpaint,
1795
2096
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
1796
2097
  className: "mt-1 px-3 py-2 rounded-lg bg-purple-600 hover:bg-purple-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
1797
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1798
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2098
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2099
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
1799
2100
  "Generating Inpaint..."
1800
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1801
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2101
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2102
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
1802
2103
  "Apply Inpainting"
1803
2104
  ] })
1804
2105
  }
1805
2106
  )
1806
2107
  ] }),
1807
- aiError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
1808
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
2108
+ aiError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
2109
+ aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
1809
2110
  ] })
1810
2111
  ] })
1811
2112
  ] })
@@ -1820,6 +2121,8 @@ var ImageEditor = ({
1820
2121
  CurvesEditor,
1821
2122
  Histogram,
1822
2123
  ImageEditor,
2124
+ RefineEdgePanel,
2125
+ SelectionOptionsBar,
1823
2126
  useImageEditor,
1824
2127
  useImageHistogram
1825
2128
  });