@pixerate/editor-react 0.62.0 → 0.64.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.
@@ -159,7 +159,7 @@ function useImageEditor(options = {}) {
159
159
  }
160
160
 
161
161
  // src/image-editor/ImageEditor.tsx
162
- import React8, { useRef as useRef4, useEffect as useEffect6, useState as useState9, useCallback as useCallback2 } from "react";
162
+ import React9, { useRef as useRef5, useEffect as useEffect7, useState as useState10, useCallback as useCallback2 } from "react";
163
163
  import {
164
164
  canvasToImagePoint,
165
165
  hitTestCrop,
@@ -626,7 +626,196 @@ var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
626
626
  };
627
627
 
628
628
  // src/image-editor/LayersPanel.tsx
629
+ import { useEffect as useEffect5, useRef as useRef4, useState as useState6 } from "react";
630
+
631
+ // src/image-editor/LayerEffectsPanel.tsx
629
632
  import { useEffect as useEffect4, useRef as useRef3, useState as useState5 } from "react";
633
+ import { LAYER_EFFECT_MENU, effectControlChange, layerEffectControls, layerEffectsPanel } from "@pixerate/editor/image-editor";
634
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
635
+ var button = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
636
+ var LayerEffectsPanel = ({ controller, layerId, className }) => {
637
+ const [, setTick] = useState5(0);
638
+ useEffect4(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
639
+ const [open, setOpen] = useState5(null);
640
+ const [error, setError] = useState5(null);
641
+ const commitNext = useRef3(true);
642
+ const layer = layerId ? controller.getLayer(layerId) : controller.getActiveLayer();
643
+ const model = layerEffectsPanel(layer);
644
+ const id = layer?.id;
645
+ const attempt = (fn) => {
646
+ try {
647
+ setError(null);
648
+ fn();
649
+ } catch (err) {
650
+ setError(err instanceof Error ? err.message : String(err));
651
+ }
652
+ };
653
+ const sliderEvents = {
654
+ onPointerDown: () => commitNext.current = true,
655
+ onPointerUp: () => commitNext.current = true,
656
+ onKeyDown: () => commitNext.current = true
657
+ };
658
+ if (!model.available || !id) {
659
+ return /* @__PURE__ */ jsx5("div", { className: `text-xs text-slate-500 ${className ?? ""}`, "data-testid": "layer-effects", children: model.reason });
660
+ }
661
+ const effects = controller.getLayerEffects(id);
662
+ const patterns = controller.getDocumentPatterns();
663
+ const change = (effectId, control, value, drag = false) => attempt(() => {
664
+ const effect = controller.getLayerEffects(id).items.find((e) => e.id === effectId);
665
+ controller.updateLayerEffect(id, effectId, effectControlChange(effect, control.key, value, patterns), drag ? commitNext.current : true);
666
+ if (drag) commitNext.current = false;
667
+ });
668
+ const renderControl = (effectId, c) => {
669
+ const label = `${c.label}`;
670
+ switch (c.type) {
671
+ case "range": {
672
+ const k = c.percent ? 100 : 1;
673
+ const shown = Math.round(c.value * k * 100) / 100;
674
+ return /* @__PURE__ */ jsxs5("label", { className: "flex flex-col gap-0.5", children: [
675
+ /* @__PURE__ */ jsxs5("span", { className: "text-slate-400", children: [
676
+ label,
677
+ " ",
678
+ shown,
679
+ c.unit
680
+ ] }),
681
+ /* @__PURE__ */ jsx5(
682
+ "input",
683
+ {
684
+ type: "range",
685
+ "aria-label": label,
686
+ min: c.min * k,
687
+ max: c.max * k,
688
+ step: c.step * k,
689
+ value: shown,
690
+ disabled: model.readOnly,
691
+ ...sliderEvents,
692
+ onChange: (e) => change(effectId, c, Number(e.target.value) / k, true),
693
+ className: "accent-indigo-500"
694
+ }
695
+ )
696
+ ] }, c.key);
697
+ }
698
+ case "color":
699
+ return /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
700
+ /* @__PURE__ */ jsx5("input", { type: "color", "aria-label": label, value: c.value, disabled: model.readOnly, onChange: (e) => change(effectId, c, e.target.value) }),
701
+ label
702
+ ] }, c.key);
703
+ case "checkbox":
704
+ return /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
705
+ /* @__PURE__ */ jsx5("input", { type: "checkbox", "aria-label": label, checked: c.value, disabled: model.readOnly, onChange: (e) => change(effectId, c, e.target.checked), className: "accent-indigo-500" }),
706
+ label
707
+ ] }, c.key);
708
+ case "select":
709
+ return /* @__PURE__ */ jsxs5("label", { className: "flex flex-col gap-0.5", children: [
710
+ /* @__PURE__ */ jsx5("span", { className: "text-slate-400", children: label }),
711
+ /* @__PURE__ */ jsx5(
712
+ "select",
713
+ {
714
+ "aria-label": label,
715
+ value: c.value,
716
+ disabled: model.readOnly,
717
+ onChange: (e) => change(effectId, c, e.target.value),
718
+ className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
719
+ children: c.options.map((o) => /* @__PURE__ */ jsx5("option", { value: o.value, children: o.label }, o.value))
720
+ }
721
+ )
722
+ ] }, c.key);
723
+ }
724
+ };
725
+ return /* @__PURE__ */ jsxs5("div", { className: `flex flex-col gap-1.5 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layer-effects", "aria-label": "Layer effects", role: "group", children: [
726
+ /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-2", children: [
727
+ /* @__PURE__ */ jsx5("span", { className: "font-semibold text-slate-300", children: "fx Effects" }),
728
+ /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1 text-slate-300", children: [
729
+ /* @__PURE__ */ jsx5(
730
+ "input",
731
+ {
732
+ type: "checkbox",
733
+ "aria-label": "Effects on",
734
+ checked: model.enabled,
735
+ disabled: model.readOnly,
736
+ onChange: (e) => attempt(() => controller.setLayerEffectsEnabled(id, e.target.checked)),
737
+ className: "accent-indigo-500"
738
+ }
739
+ ),
740
+ "On"
741
+ ] }),
742
+ /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1 text-slate-400", children: [
743
+ "Scale",
744
+ /* @__PURE__ */ jsx5(
745
+ "input",
746
+ {
747
+ type: "number",
748
+ "aria-label": "Scale effects",
749
+ min: 1,
750
+ max: 1e3,
751
+ step: 1,
752
+ value: Math.round(model.scale * 100),
753
+ disabled: model.readOnly,
754
+ onChange: (e) => {
755
+ const v = Number(e.target.value);
756
+ if (v >= 1 && v <= 1e3) attempt(() => controller.setLayerEffectsEnabled(id, model.enabled, v / 100));
757
+ },
758
+ className: "w-14 bg-slate-800 border border-slate-700 rounded px-1"
759
+ }
760
+ ),
761
+ "%"
762
+ ] }),
763
+ /* @__PURE__ */ jsxs5(
764
+ "select",
765
+ {
766
+ "aria-label": "Add effect",
767
+ value: "",
768
+ disabled: model.readOnly,
769
+ onChange: (e) => {
770
+ const kind = e.target.value;
771
+ if (!kind) return;
772
+ attempt(() => setOpen(controller.addLayerEffect(id, kind).effect.id));
773
+ },
774
+ className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
775
+ children: [
776
+ /* @__PURE__ */ jsx5("option", { value: "", children: "Add effect\u2026" }),
777
+ LAYER_EFFECT_MENU.map((m) => /* @__PURE__ */ jsx5("option", { value: m.kind, children: m.label }, m.kind))
778
+ ]
779
+ }
780
+ )
781
+ ] }),
782
+ model.readOnly && model.reason && /* @__PURE__ */ jsx5("p", { className: "text-slate-500", children: model.reason }),
783
+ /* @__PURE__ */ jsx5("ul", { className: "flex flex-col gap-1", "aria-label": "Effects", children: model.rows.map((row) => {
784
+ const effect = effects.items.find((e) => e.id === row.id);
785
+ const expanded = open === row.id;
786
+ return /* @__PURE__ */ jsxs5("li", { "data-effect-id": row.id, className: "rounded bg-slate-900/60 ring-1 ring-slate-800", children: [
787
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1.5 px-1.5 py-1", children: [
788
+ /* @__PURE__ */ jsx5(
789
+ "input",
790
+ {
791
+ type: "checkbox",
792
+ "aria-label": `${row.label} on`,
793
+ checked: row.enabled,
794
+ disabled: model.readOnly,
795
+ onChange: (e) => attempt(() => controller.updateLayerEffect(id, row.id, { enabled: e.target.checked })),
796
+ className: "accent-indigo-500"
797
+ }
798
+ ),
799
+ /* @__PURE__ */ jsx5(
800
+ "button",
801
+ {
802
+ type: "button",
803
+ "aria-expanded": expanded,
804
+ className: `flex-1 text-left ${row.enabled && model.enabled ? "" : "text-slate-500"}`,
805
+ onClick: () => setOpen(expanded ? null : row.id),
806
+ children: row.label
807
+ }
808
+ ),
809
+ /* @__PURE__ */ jsx5("button", { type: "button", className: button, "aria-label": `Remove ${row.label}`, disabled: model.readOnly, onClick: () => attempt(() => controller.removeLayerEffect(id, row.id)), children: "\u2715" })
810
+ ] }),
811
+ expanded && /* @__PURE__ */ jsx5("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 px-1.5 pb-1.5", "data-testid": "effect-settings", children: layerEffectControls(effect, patterns).map((c) => renderControl(row.id, c)) })
812
+ ] }, row.id);
813
+ }) }),
814
+ error && /* @__PURE__ */ jsx5("p", { role: "alert", className: "text-rose-400", children: error })
815
+ ] });
816
+ };
817
+
818
+ // src/image-editor/LayersPanel.tsx
630
819
  import {
631
820
  BLEND_MODES as BLEND_MODES2,
632
821
  PSD_FILE_ACCEPT,
@@ -635,11 +824,12 @@ import {
635
824
  dropZone,
636
825
  openPsdFile,
637
826
  layerBadge,
827
+ layerEffectsBadge,
638
828
  layerMenu,
639
829
  layerPanelRows,
640
830
  runLayerMenuAction
641
831
  } from "@pixerate/editor/image-editor";
642
- import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
832
+ import { Fragment, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
643
833
  var iconButton = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
644
834
  var rowClass = (active) => `flex items-center gap-1.5 px-1.5 py-1 rounded cursor-pointer select-none ${active ? "bg-indigo-600/30 ring-1 ring-indigo-500" : "hover:bg-slate-800"}`;
645
835
  var Thumbnail = ({
@@ -650,8 +840,8 @@ var Thumbnail = ({
650
840
  selected,
651
841
  testId
652
842
  }) => {
653
- const ref = useRef3(null);
654
- useEffect4(() => {
843
+ const ref = useRef4(null);
844
+ useEffect5(() => {
655
845
  const canvas = ref.current;
656
846
  const ctx = canvas?.getContext("2d");
657
847
  if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== "function") return;
@@ -661,7 +851,7 @@ var Thumbnail = ({
661
851
  img.data.set(pixels.data);
662
852
  ctx.putImageData(img, 0, 0);
663
853
  }, [pixels]);
664
- return /* @__PURE__ */ jsx5(
854
+ return /* @__PURE__ */ jsx6(
665
855
  "canvas",
666
856
  {
667
857
  ref,
@@ -674,15 +864,15 @@ var Thumbnail = ({
674
864
  }
675
865
  );
676
866
  };
677
- var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "image", className }) => {
678
- const [, setTick] = useState5(0);
679
- useEffect4(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
680
- const [error, setError] = useState5(null);
681
- const [renaming, setRenaming] = useState5(null);
682
- const [menu, setMenu] = useState5(null);
683
- const [drag, setDrag] = useState5(null);
684
- const [psdNotes, setPsdNotes] = useState5([]);
685
- const fileInput = useRef3(null);
867
+ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "image", effects = true, className }) => {
868
+ const [, setTick] = useState6(0);
869
+ useEffect5(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
870
+ const [error, setError] = useState6(null);
871
+ const [renaming, setRenaming] = useState6(null);
872
+ const [menu, setMenu] = useState6(null);
873
+ const [drag, setDrag] = useState6(null);
874
+ const [psdNotes, setPsdNotes] = useState6([]);
875
+ const fileInput = useRef4(null);
686
876
  const psdTask = async (fn) => {
687
877
  try {
688
878
  setError(null);
@@ -691,7 +881,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
691
881
  setError(err instanceof Error ? err.message : String(err));
692
882
  }
693
883
  };
694
- const commitNext = useRef3(true);
884
+ const commitNext = useRef4(true);
695
885
  const state = controller.getState();
696
886
  const rows = layerPanelRows(state.layers, state.activeLayerId);
697
887
  const active = controller.getActiveLayer();
@@ -729,14 +919,14 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
729
919
  const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
730
920
  const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
731
921
  const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
732
- return /* @__PURE__ */ jsxs5("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
733
- /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
734
- /* @__PURE__ */ jsx5("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
735
- /* @__PURE__ */ jsx5("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
736
- /* @__PURE__ */ jsx5("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
737
- /* @__PURE__ */ jsx5("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
738
- /* @__PURE__ */ jsx5("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
739
- /* @__PURE__ */ jsx5(
922
+ return /* @__PURE__ */ jsxs6("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
923
+ /* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
924
+ /* @__PURE__ */ jsx6("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
925
+ /* @__PURE__ */ jsx6("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
926
+ /* @__PURE__ */ jsx6("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
927
+ /* @__PURE__ */ jsx6("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
928
+ /* @__PURE__ */ jsx6("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
929
+ /* @__PURE__ */ jsx6(
740
930
  "button",
741
931
  {
742
932
  type: "button",
@@ -751,10 +941,10 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
751
941
  children: "\u22EF"
752
942
  }
753
943
  ),
754
- psd && /* @__PURE__ */ jsxs5(Fragment, { children: [
755
- /* @__PURE__ */ jsx5("button", { type: "button", className: iconButton, onClick: () => fileInput.current?.click(), children: "Open PSD\u2026" }),
756
- /* @__PURE__ */ jsx5("button", { type: "button", className: iconButton, onClick: () => psdTask(async () => (await downloadPsd(controller, psdFileName)).warnings), children: "Export PSD" }),
757
- /* @__PURE__ */ jsx5(
944
+ psd && /* @__PURE__ */ jsxs6(Fragment, { children: [
945
+ /* @__PURE__ */ jsx6("button", { type: "button", className: iconButton, onClick: () => fileInput.current?.click(), children: "Open PSD\u2026" }),
946
+ /* @__PURE__ */ jsx6("button", { type: "button", className: iconButton, onClick: () => psdTask(async () => (await downloadPsd(controller, psdFileName)).warnings), children: "Export PSD" }),
947
+ /* @__PURE__ */ jsx6(
758
948
  "input",
759
949
  {
760
950
  ref: fileInput,
@@ -772,18 +962,18 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
772
962
  )
773
963
  ] })
774
964
  ] }),
775
- psdNotes.length > 0 && /* @__PURE__ */ jsxs5("ul", { className: "rounded bg-amber-900/30 text-amber-200 px-2 py-1 space-y-0.5", "data-testid": "psd-warnings", "aria-label": "PSD warnings", children: [
776
- psdNotes.map((n) => /* @__PURE__ */ jsx5("li", { children: n }, n)),
777
- /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsx5("button", { type: "button", className: "underline", onClick: () => setPsdNotes([]), children: "Dismiss" }) })
965
+ psdNotes.length > 0 && /* @__PURE__ */ jsxs6("ul", { className: "rounded bg-amber-900/30 text-amber-200 px-2 py-1 space-y-0.5", "data-testid": "psd-warnings", "aria-label": "PSD warnings", children: [
966
+ psdNotes.map((n) => /* @__PURE__ */ jsx6("li", { children: n }, n)),
967
+ /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6("button", { type: "button", className: "underline", onClick: () => setPsdNotes([]), children: "Dismiss" }) })
778
968
  ] }),
779
- active && /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 items-center", "data-testid": "layer-properties", children: [
780
- /* @__PURE__ */ jsxs5("label", { className: "flex flex-col gap-0.5", children: [
781
- /* @__PURE__ */ jsxs5("span", { className: "text-slate-400", children: [
969
+ active && /* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 items-center", "data-testid": "layer-properties", children: [
970
+ /* @__PURE__ */ jsxs6("label", { className: "flex flex-col gap-0.5", children: [
971
+ /* @__PURE__ */ jsxs6("span", { className: "text-slate-400", children: [
782
972
  "Opacity ",
783
973
  Math.round(active.opacity * 100),
784
974
  "%"
785
975
  ] }),
786
- /* @__PURE__ */ jsx5(
976
+ /* @__PURE__ */ jsx6(
787
977
  "input",
788
978
  {
789
979
  type: "range",
@@ -797,13 +987,13 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
797
987
  }
798
988
  )
799
989
  ] }),
800
- /* @__PURE__ */ jsxs5("label", { className: "flex flex-col gap-0.5", children: [
801
- /* @__PURE__ */ jsxs5("span", { className: "text-slate-400", children: [
990
+ /* @__PURE__ */ jsxs6("label", { className: "flex flex-col gap-0.5", children: [
991
+ /* @__PURE__ */ jsxs6("span", { className: "text-slate-400", children: [
802
992
  "Fill ",
803
993
  Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
804
994
  "%"
805
995
  ] }),
806
- /* @__PURE__ */ jsx5(
996
+ /* @__PURE__ */ jsx6(
807
997
  "input",
808
998
  {
809
999
  type: "range",
@@ -818,7 +1008,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
818
1008
  }
819
1009
  )
820
1010
  ] }),
821
- /* @__PURE__ */ jsxs5(
1011
+ /* @__PURE__ */ jsxs6(
822
1012
  "select",
823
1013
  {
824
1014
  "aria-label": "Layer blend mode",
@@ -826,13 +1016,13 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
826
1016
  value: active.blend,
827
1017
  onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { blend: e.target.value })),
828
1018
  children: [
829
- active.type === "group" && /* @__PURE__ */ jsx5("option", { value: "pass-through", children: "Pass Through" }),
830
- BLEND_MODES2.map((m) => /* @__PURE__ */ jsx5("option", { value: m.id, children: m.label }, m.id))
1019
+ active.type === "group" && /* @__PURE__ */ jsx6("option", { value: "pass-through", children: "Pass Through" }),
1020
+ BLEND_MODES2.map((m) => /* @__PURE__ */ jsx6("option", { value: m.id, children: m.label }, m.id))
831
1021
  ]
832
1022
  }
833
1023
  ),
834
- /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
835
- /* @__PURE__ */ jsx5(
1024
+ /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
1025
+ /* @__PURE__ */ jsx6(
836
1026
  "input",
837
1027
  {
838
1028
  type: "checkbox",
@@ -844,8 +1034,8 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
844
1034
  ),
845
1035
  "Clip to below"
846
1036
  ] }),
847
- /* @__PURE__ */ jsx5("div", { className: "col-span-2 flex flex-wrap gap-2 text-slate-400", role: "group", "aria-label": "Layer locks", children: ["pixels", "transparency", "position", "all"].map((k) => /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1", children: [
848
- /* @__PURE__ */ jsx5(
1037
+ /* @__PURE__ */ jsx6("div", { className: "col-span-2 flex flex-wrap gap-2 text-slate-400", role: "group", "aria-label": "Layer locks", children: ["pixels", "transparency", "position", "all"].map((k) => /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1", children: [
1038
+ /* @__PURE__ */ jsx6(
849
1039
  "input",
850
1040
  {
851
1041
  type: "checkbox",
@@ -858,9 +1048,10 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
858
1048
  k
859
1049
  ] }, k)) })
860
1050
  ] }),
861
- /* @__PURE__ */ jsx5("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
1051
+ effects && active && active.type !== "adjustment" && /* @__PURE__ */ jsx6(LayerEffectsPanel, { controller, className: "border-t border-slate-800 pt-1.5" }),
1052
+ /* @__PURE__ */ jsx6("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
862
1053
  const { layer } = row;
863
- return /* @__PURE__ */ jsxs5(
1054
+ return /* @__PURE__ */ jsxs6(
864
1055
  "li",
865
1056
  {
866
1057
  role: "treeitem",
@@ -890,7 +1081,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
890
1081
  className: rowClass(row.active),
891
1082
  style: { paddingLeft: 6 + row.depth * 14 },
892
1083
  children: [
893
- /* @__PURE__ */ jsx5(
1084
+ /* @__PURE__ */ jsx6(
894
1085
  "button",
895
1086
  {
896
1087
  type: "button",
@@ -904,7 +1095,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
904
1095
  children: layer.visible ? "\u25CF" : "\u25CB"
905
1096
  }
906
1097
  ),
907
- layer.type === "group" && /* @__PURE__ */ jsx5(
1098
+ layer.type === "group" && /* @__PURE__ */ jsx6(
908
1099
  "button",
909
1100
  {
910
1101
  type: "button",
@@ -917,8 +1108,8 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
917
1108
  children: layer.collapsed ? "\u25B8" : "\u25BE"
918
1109
  }
919
1110
  ),
920
- row.clipped && /* @__PURE__ */ jsx5("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
921
- layer.type === "pixel" ? /* @__PURE__ */ jsx5(
1111
+ row.clipped && /* @__PURE__ */ jsx6("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
1112
+ layer.type === "pixel" ? /* @__PURE__ */ jsx6(
922
1113
  Thumbnail,
923
1114
  {
924
1115
  pixels: thumb(layer),
@@ -926,7 +1117,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
926
1117
  label: `${row.label} pixels`,
927
1118
  selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
928
1119
  }
929
- ) : /* @__PURE__ */ jsx5(
1120
+ ) : /* @__PURE__ */ jsx6(
930
1121
  "span",
931
1122
  {
932
1123
  className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
@@ -934,7 +1125,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
934
1125
  children: layerBadge(layer)
935
1126
  }
936
1127
  ),
937
- layer.mask && /* @__PURE__ */ jsx5(
1128
+ layer.mask && /* @__PURE__ */ jsx6(
938
1129
  Thumbnail,
939
1130
  {
940
1131
  pixels: maskThumb(layer),
@@ -949,7 +1140,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
949
1140
  }
950
1141
  }
951
1142
  ),
952
- renaming === layer.id ? /* @__PURE__ */ jsx5(
1143
+ renaming === layer.id ? /* @__PURE__ */ jsx6(
953
1144
  "input",
954
1145
  {
955
1146
  autoFocus: true,
@@ -966,7 +1157,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
966
1157
  if (e.key === "Escape") setRenaming(null);
967
1158
  }
968
1159
  }
969
- ) : /* @__PURE__ */ jsx5(
1160
+ ) : /* @__PURE__ */ jsx6(
970
1161
  "span",
971
1162
  {
972
1163
  className: `flex-1 min-w-0 truncate ${layer.visible ? "" : "text-slate-500"}`,
@@ -977,15 +1168,30 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
977
1168
  children: row.label
978
1169
  }
979
1170
  ),
980
- locked(layer) && /* @__PURE__ */ jsx5("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
981
- layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ jsx5("span", { className: "text-[9px] text-slate-500", children: layer.blend })
1171
+ layerEffectsBadge(layer) && /* @__PURE__ */ jsx6(
1172
+ "button",
1173
+ {
1174
+ type: "button",
1175
+ "data-testid": "layer-fx-badge",
1176
+ "aria-label": layerEffectsBadge(layer) === "on" ? `Turn effects off for ${row.label}` : `Turn effects on for ${row.label}`,
1177
+ "aria-pressed": layerEffectsBadge(layer) === "on",
1178
+ className: `text-[9px] italic font-semibold ${layerEffectsBadge(layer) === "on" ? "text-indigo-300" : "text-slate-600 line-through"}`,
1179
+ onClick: (e) => {
1180
+ e.stopPropagation();
1181
+ attempt(() => controller.setLayerEffectsEnabled(layer.id, layerEffectsBadge(layer) !== "on"));
1182
+ },
1183
+ children: "fx"
1184
+ }
1185
+ ),
1186
+ locked(layer) && /* @__PURE__ */ jsx6("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
1187
+ layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ jsx6("span", { className: "text-[9px] text-slate-500", children: layer.blend })
982
1188
  ]
983
1189
  },
984
1190
  layer.id
985
1191
  );
986
1192
  }) }),
987
- error && /* @__PURE__ */ jsx5("p", { role: "alert", className: "text-rose-400", children: error }),
988
- menu && /* @__PURE__ */ jsx5(
1193
+ error && /* @__PURE__ */ jsx6("p", { role: "alert", className: "text-rose-400", children: error }),
1194
+ menu && /* @__PURE__ */ jsx6(
989
1195
  "div",
990
1196
  {
991
1197
  role: "menu",
@@ -994,7 +1200,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
994
1200
  style: { left: menu.x, top: menu.y },
995
1201
  onClick: (e) => e.stopPropagation(),
996
1202
  onKeyDown: (e) => e.key === "Escape" && setMenu(null),
997
- children: layerMenu(controller).map((item) => /* @__PURE__ */ jsx5(
1203
+ children: layerMenu(controller).map((item) => /* @__PURE__ */ jsx6(
998
1204
  "button",
999
1205
  {
1000
1206
  type: "button",
@@ -1012,16 +1218,16 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1012
1218
  };
1013
1219
 
1014
1220
  // src/image-editor/BrushOptionsBar.tsx
1015
- import { useEffect as useEffect5, useState as useState6 } from "react";
1016
- import { BRUSH_OPTION_CONTROLS, PAINT_TOOLS } from "@pixerate/editor/image-editor";
1017
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1221
+ import { useEffect as useEffect6, useState as useState7 } from "react";
1222
+ import { BRUSH_OPTION_CONTROLS, MIXER_MIXING_OPTIONS, MIXER_OPTION_CONTROLS, PAINT_TOOLS, rgbUnitToHex } from "@pixerate/editor/image-editor";
1223
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1018
1224
  var chip = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
1019
1225
  var BrushOptionsBar = ({ controller, className }) => {
1020
- const [, setTick] = useState6(0);
1021
- useEffect5(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1022
- const [error, setError] = useState6(null);
1226
+ const [, setTick] = useState7(0);
1227
+ useEffect6(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1228
+ const [error, setError] = useState7(null);
1023
1229
  const state = controller.getState();
1024
- const { brush, foreground, background } = state.paint;
1230
+ const { brush, foreground, background, mixer, mixerLoad } = state.paint;
1025
1231
  const attempt = (fn) => {
1026
1232
  try {
1027
1233
  setError(null);
@@ -1030,8 +1236,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1030
1236
  setError(err instanceof Error ? err.message : String(err));
1031
1237
  }
1032
1238
  };
1033
- return /* @__PURE__ */ jsxs6("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
1034
- /* @__PURE__ */ jsx6("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: PAINT_TOOLS.map((t) => /* @__PURE__ */ jsx6(
1239
+ return /* @__PURE__ */ jsxs7("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
1240
+ /* @__PURE__ */ jsx7("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: PAINT_TOOLS.map((t) => /* @__PURE__ */ jsx7(
1035
1241
  "button",
1036
1242
  {
1037
1243
  type: "button",
@@ -1043,9 +1249,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1043
1249
  },
1044
1250
  t.id
1045
1251
  )) }),
1046
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
1047
- /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1", children: [
1048
- /* @__PURE__ */ jsx6(
1252
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
1253
+ /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1", children: [
1254
+ /* @__PURE__ */ jsx7(
1049
1255
  "input",
1050
1256
  {
1051
1257
  type: "color",
@@ -1055,10 +1261,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1055
1261
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1056
1262
  }
1057
1263
  ),
1058
- /* @__PURE__ */ jsx6("span", { className: "text-slate-400", children: "FG" })
1264
+ /* @__PURE__ */ jsx7("span", { className: "text-slate-400", children: "FG" })
1059
1265
  ] }),
1060
- /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1", children: [
1061
- /* @__PURE__ */ jsx6(
1266
+ /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1", children: [
1267
+ /* @__PURE__ */ jsx7(
1062
1268
  "input",
1063
1269
  {
1064
1270
  type: "color",
@@ -1068,12 +1274,12 @@ var BrushOptionsBar = ({ controller, className }) => {
1068
1274
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1069
1275
  }
1070
1276
  ),
1071
- /* @__PURE__ */ jsx6("span", { className: "text-slate-400", children: "BG" })
1277
+ /* @__PURE__ */ jsx7("span", { className: "text-slate-400", children: "BG" })
1072
1278
  ] }),
1073
- /* @__PURE__ */ jsx6("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
1074
- /* @__PURE__ */ jsx6("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
1279
+ /* @__PURE__ */ jsx7("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
1280
+ /* @__PURE__ */ jsx7("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
1075
1281
  ] }),
1076
- BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ jsx6(
1282
+ BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ jsx7(
1077
1283
  ControlSlider,
1078
1284
  {
1079
1285
  spec,
@@ -1082,9 +1288,65 @@ var BrushOptionsBar = ({ controller, className }) => {
1082
1288
  },
1083
1289
  spec.id
1084
1290
  )),
1085
- /* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1086
- /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1.5", children: [
1087
- /* @__PURE__ */ jsx6(
1291
+ state.activeTool === "mixer" && /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-2 border-t border-slate-800 pt-2", role: "group", "aria-label": "Mixer Brush", "data-testid": "mixer-options", children: [
1292
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
1293
+ /* @__PURE__ */ jsx7(
1294
+ "span",
1295
+ {
1296
+ "aria-label": "Brush load",
1297
+ title: mixerLoad.reservoir ? `Loaded ${rgbUnitToHex(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
1298
+ className: "h-6 w-6 rounded border border-slate-700",
1299
+ style: { background: mixerLoad.reservoir ? rgbUnitToHex(mixerLoad.reservoir) : "transparent" }
1300
+ }
1301
+ ),
1302
+ /* @__PURE__ */ jsx7("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
1303
+ /* @__PURE__ */ jsx7("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
1304
+ ] }),
1305
+ /* @__PURE__ */ jsx7("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ jsx7(
1306
+ "button",
1307
+ {
1308
+ type: "button",
1309
+ "aria-pressed": mixer.mixing === m.id,
1310
+ title: m.title,
1311
+ className: chip(mixer.mixing === m.id),
1312
+ onClick: () => controller.setPaintOptions({ mixer: { mixing: m.id } }),
1313
+ children: m.label
1314
+ },
1315
+ m.id
1316
+ )) }),
1317
+ MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ jsx7(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
1318
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
1319
+ /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1320
+ /* @__PURE__ */ jsx7(
1321
+ "input",
1322
+ {
1323
+ type: "checkbox",
1324
+ "aria-label": "Load the brush after each stroke",
1325
+ checked: mixer.loadEachStroke,
1326
+ onChange: (e) => controller.setPaintOptions({ mixer: { loadEachStroke: e.target.checked } }),
1327
+ className: "accent-indigo-500"
1328
+ }
1329
+ ),
1330
+ "Load each stroke"
1331
+ ] }),
1332
+ /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1333
+ /* @__PURE__ */ jsx7(
1334
+ "input",
1335
+ {
1336
+ type: "checkbox",
1337
+ "aria-label": "Clean the brush after each stroke",
1338
+ checked: mixer.cleanEachStroke,
1339
+ onChange: (e) => controller.setPaintOptions({ mixer: { cleanEachStroke: e.target.checked } }),
1340
+ className: "accent-indigo-500"
1341
+ }
1342
+ ),
1343
+ "Clean each stroke"
1344
+ ] })
1345
+ ] })
1346
+ ] }),
1347
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1348
+ /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1349
+ /* @__PURE__ */ jsx7(
1088
1350
  "input",
1089
1351
  {
1090
1352
  type: "checkbox",
@@ -1096,8 +1358,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1096
1358
  ),
1097
1359
  "Pressure size"
1098
1360
  ] }),
1099
- /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1.5", children: [
1100
- /* @__PURE__ */ jsx6(
1361
+ /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1362
+ /* @__PURE__ */ jsx7(
1101
1363
  "input",
1102
1364
  {
1103
1365
  type: "checkbox",
@@ -1110,23 +1372,23 @@ var BrushOptionsBar = ({ controller, className }) => {
1110
1372
  "Pressure opacity"
1111
1373
  ] })
1112
1374
  ] }),
1113
- /* @__PURE__ */ jsxs6("div", { className: "flex gap-1", children: [
1114
- /* @__PURE__ */ jsx6("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1115
- /* @__PURE__ */ jsx6("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
1375
+ /* @__PURE__ */ jsxs7("div", { className: "flex gap-1", children: [
1376
+ /* @__PURE__ */ jsx7("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1377
+ /* @__PURE__ */ jsx7("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
1116
1378
  ] }),
1117
- error && /* @__PURE__ */ jsx6("p", { role: "alert", className: "text-rose-400", children: error })
1379
+ error && /* @__PURE__ */ jsx7("p", { role: "alert", className: "text-rose-400", children: error })
1118
1380
  ] });
1119
1381
  };
1120
1382
 
1121
1383
  // src/image-editor/SelectionOptionsBar.tsx
1122
- import { useState as useState7 } from "react";
1384
+ import { useState as useState8 } from "react";
1123
1385
  import {
1124
1386
  SELECTION_MODES,
1125
1387
  SELECTION_MODE_LABELS,
1126
1388
  SELECTION_TOOLS,
1127
1389
  describeSelection
1128
1390
  } from "@pixerate/editor/image-editor";
1129
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1391
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1130
1392
  var MODIFY_OPS = [
1131
1393
  { op: "grow", label: "Grow" },
1132
1394
  { op: "shrink", label: "Shrink" },
@@ -1143,20 +1405,20 @@ var SelectionOptionsBar = ({
1143
1405
  quickMask,
1144
1406
  className = ""
1145
1407
  }) => {
1146
- const [radius, setRadius] = useState7(2);
1408
+ const [radius, setRadius] = useState8(2);
1147
1409
  const set = (patch) => onOptionsChange({ ...options, ...patch });
1148
1410
  const sel = selection === void 0 ? controller.getSelection() : selection;
1149
1411
  const qm = quickMask ?? Boolean(controller.getState().quickMask);
1150
- return /* @__PURE__ */ jsxs7("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1151
- /* @__PURE__ */ jsx7("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: SELECTION_TOOLS.map((t) => /* @__PURE__ */ jsx7("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)) }),
1152
- /* @__PURE__ */ jsx7("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: SELECTION_MODES.map((m) => /* @__PURE__ */ jsx7("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: SELECTION_MODE_LABELS[m] }, m)) }),
1153
- options.tool === "wand" && /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-2", children: [
1154
- /* @__PURE__ */ jsxs7("label", { className: "flex flex-col gap-1", children: [
1155
- /* @__PURE__ */ jsxs7("span", { className: "flex justify-between text-slate-400", children: [
1156
- /* @__PURE__ */ jsx7("span", { children: "Tolerance" }),
1157
- /* @__PURE__ */ jsx7("span", { className: "font-mono", children: options.tolerance })
1412
+ return /* @__PURE__ */ jsxs8("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1413
+ /* @__PURE__ */ jsx8("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: SELECTION_TOOLS.map((t) => /* @__PURE__ */ jsx8("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)) }),
1414
+ /* @__PURE__ */ jsx8("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: SELECTION_MODES.map((m) => /* @__PURE__ */ jsx8("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: SELECTION_MODE_LABELS[m] }, m)) }),
1415
+ options.tool === "wand" && /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
1416
+ /* @__PURE__ */ jsxs8("label", { className: "flex flex-col gap-1", children: [
1417
+ /* @__PURE__ */ jsxs8("span", { className: "flex justify-between text-slate-400", children: [
1418
+ /* @__PURE__ */ jsx8("span", { children: "Tolerance" }),
1419
+ /* @__PURE__ */ jsx8("span", { className: "font-mono", children: options.tolerance })
1158
1420
  ] }),
1159
- /* @__PURE__ */ jsx7(
1421
+ /* @__PURE__ */ jsx8(
1160
1422
  "input",
1161
1423
  {
1162
1424
  type: "range",
@@ -1170,17 +1432,17 @@ var SelectionOptionsBar = ({
1170
1432
  }
1171
1433
  )
1172
1434
  ] }),
1173
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-2 text-slate-300", children: [
1174
- /* @__PURE__ */ jsx7("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
1435
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2 text-slate-300", children: [
1436
+ /* @__PURE__ */ jsx8("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
1175
1437
  "Contiguous"
1176
1438
  ] }),
1177
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-2 text-slate-300", children: [
1178
- /* @__PURE__ */ jsx7("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
1439
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2 text-slate-300", children: [
1440
+ /* @__PURE__ */ jsx8("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
1179
1441
  "Sample adjusted image"
1180
1442
  ] }),
1181
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-2 text-slate-300", children: [
1443
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2 text-slate-300", children: [
1182
1444
  "Sample",
1183
- /* @__PURE__ */ jsxs7(
1445
+ /* @__PURE__ */ jsxs8(
1184
1446
  "select",
1185
1447
  {
1186
1448
  "aria-label": "Sample from",
@@ -1188,27 +1450,27 @@ var SelectionOptionsBar = ({
1188
1450
  onChange: (e) => set({ sample: e.target.value }),
1189
1451
  className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
1190
1452
  children: [
1191
- /* @__PURE__ */ jsx7("option", { value: "composite", children: "All layers" }),
1192
- /* @__PURE__ */ jsx7("option", { value: "active-layer", children: "Active layer" })
1453
+ /* @__PURE__ */ jsx8("option", { value: "composite", children: "All layers" }),
1454
+ /* @__PURE__ */ jsx8("option", { value: "active-layer", children: "Active layer" })
1193
1455
  ]
1194
1456
  }
1195
1457
  )
1196
1458
  ] })
1197
1459
  ] }),
1198
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-2 text-slate-300", children: [
1199
- /* @__PURE__ */ jsx7("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
1460
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2 text-slate-300", children: [
1461
+ /* @__PURE__ */ jsx8("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
1200
1462
  "Anti-alias"
1201
1463
  ] }),
1202
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-1", children: [
1203
- /* @__PURE__ */ jsx7("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
1204
- /* @__PURE__ */ jsx7("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1205
- /* @__PURE__ */ jsx7("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1206
- /* @__PURE__ */ jsx7("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
1464
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap gap-1", children: [
1465
+ /* @__PURE__ */ jsx8("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
1466
+ /* @__PURE__ */ jsx8("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1467
+ /* @__PURE__ */ jsx8("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1468
+ /* @__PURE__ */ jsx8("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
1207
1469
  ] }),
1208
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-1", children: [
1209
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1 text-slate-400", children: [
1470
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-1", children: [
1471
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1 text-slate-400", children: [
1210
1472
  "Radius",
1211
- /* @__PURE__ */ jsx7(
1473
+ /* @__PURE__ */ jsx8(
1212
1474
  "input",
1213
1475
  {
1214
1476
  type: "number",
@@ -1222,29 +1484,29 @@ var SelectionOptionsBar = ({
1222
1484
  }
1223
1485
  )
1224
1486
  ] }),
1225
- MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ jsx7("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
1487
+ MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ jsx8("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
1226
1488
  ] }),
1227
- /* @__PURE__ */ jsx7("p", { "data-testid": "selection-status", className: "text-slate-400", children: describeSelection(sel) })
1489
+ /* @__PURE__ */ jsx8("p", { "data-testid": "selection-status", className: "text-slate-400", children: describeSelection(sel) })
1228
1490
  ] });
1229
1491
  };
1230
1492
 
1231
1493
  // src/image-editor/RefineEdgePanel.tsx
1232
- import { useState as useState8 } from "react";
1494
+ import { useState as useState9 } from "react";
1233
1495
  import {
1234
1496
  ADJUSTMENT_KINDS as ADJUSTMENT_KINDS2,
1235
1497
  REFINE_EDGE_CONTROLS,
1236
1498
  adjustmentKindLabel as adjustmentKindLabel2,
1237
1499
  layerMaskFromSelection
1238
1500
  } from "@pixerate/editor/image-editor";
1239
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1501
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1240
1502
  var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
1241
- 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";
1503
+ var button2 = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
1242
1504
  var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1243
- const [params, setParams] = useState8(DEFAULT_PARAMS);
1244
- const [busy, setBusy] = useState8(false);
1245
- const [error, setError] = useState8(null);
1246
- const [layerId, setLayerId] = useState8("");
1247
- const [newKind, setNewKind] = useState8("hueSaturation");
1505
+ const [params, setParams] = useState9(DEFAULT_PARAMS);
1506
+ const [busy, setBusy] = useState9(false);
1507
+ const [error, setError] = useState9(null);
1508
+ const [layerId, setLayerId] = useState9("");
1509
+ const [newKind, setNewKind] = useState9("hueSaturation");
1248
1510
  const sel = selection === void 0 ? controller.getSelection() : selection;
1249
1511
  const list = layers ?? controller.getAdjustmentLayers();
1250
1512
  const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
@@ -1259,17 +1521,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1259
1521
  setBusy(false);
1260
1522
  }
1261
1523
  };
1262
- return /* @__PURE__ */ jsxs8("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1263
- /* @__PURE__ */ jsx8("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1264
- REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ jsxs8("label", { className: "flex flex-col gap-1", children: [
1265
- /* @__PURE__ */ jsxs8("span", { className: "flex justify-between text-slate-400", children: [
1266
- /* @__PURE__ */ jsx8("span", { children: c.label }),
1267
- /* @__PURE__ */ jsxs8("span", { className: "font-mono", children: [
1524
+ return /* @__PURE__ */ jsxs9("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1525
+ /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1526
+ REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ jsxs9("label", { className: "flex flex-col gap-1", children: [
1527
+ /* @__PURE__ */ jsxs9("span", { className: "flex justify-between text-slate-400", children: [
1528
+ /* @__PURE__ */ jsx9("span", { children: c.label }),
1529
+ /* @__PURE__ */ jsxs9("span", { className: "font-mono", children: [
1268
1530
  params[c.id],
1269
1531
  c.unit
1270
1532
  ] })
1271
1533
  ] }),
1272
- /* @__PURE__ */ jsx8(
1534
+ /* @__PURE__ */ jsx9(
1273
1535
  "input",
1274
1536
  {
1275
1537
  type: "range",
@@ -1283,67 +1545,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1283
1545
  }
1284
1546
  )
1285
1547
  ] }, c.id)),
1286
- /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2 text-slate-300", children: [
1287
- /* @__PURE__ */ jsx8("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
1548
+ /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-2 text-slate-300", children: [
1549
+ /* @__PURE__ */ jsx9("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
1288
1550
  "Smart Radius"
1289
1551
  ] }),
1290
- /* @__PURE__ */ jsxs8("div", { className: "flex gap-1", children: [
1291
- /* @__PURE__ */ jsx8("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1292
- /* @__PURE__ */ jsx8("button", { type: "button", className: button, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
1552
+ /* @__PURE__ */ jsxs9("div", { className: "flex gap-1", children: [
1553
+ /* @__PURE__ */ jsx9("button", { type: "button", className: button2, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1554
+ /* @__PURE__ */ jsx9("button", { type: "button", className: button2, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
1293
1555
  ] }),
1294
- error && /* @__PURE__ */ jsx8("p", { role: "alert", className: "text-rose-400", children: error }),
1295
- /* @__PURE__ */ jsx8("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1296
- /* @__PURE__ */ jsxs8("div", { className: "flex gap-1 items-center", children: [
1297
- /* @__PURE__ */ jsx8(
1556
+ error && /* @__PURE__ */ jsx9("p", { role: "alert", className: "text-rose-400", children: error }),
1557
+ /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1558
+ /* @__PURE__ */ jsxs9("div", { className: "flex gap-1 items-center", children: [
1559
+ /* @__PURE__ */ jsx9(
1298
1560
  "select",
1299
1561
  {
1300
1562
  "aria-label": "New masked layer kind",
1301
1563
  value: newKind,
1302
1564
  onChange: (e) => setNewKind(e.target.value),
1303
1565
  className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1304
- children: ADJUSTMENT_KINDS2.map((k) => /* @__PURE__ */ jsx8("option", { value: k.kind, children: k.label }, k.kind))
1566
+ children: ADJUSTMENT_KINDS2.map((k) => /* @__PURE__ */ jsx9("option", { value: k.kind, children: k.label }, k.kind))
1305
1567
  }
1306
1568
  ),
1307
- /* @__PURE__ */ jsx8(
1569
+ /* @__PURE__ */ jsx9(
1308
1570
  "button",
1309
1571
  {
1310
1572
  type: "button",
1311
- className: button,
1573
+ className: button2,
1312
1574
  disabled: !sel,
1313
1575
  onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: layerMaskFromSelection(sel) })),
1314
1576
  children: "New Masked Layer"
1315
1577
  }
1316
1578
  )
1317
1579
  ] }),
1318
- list.length > 0 && target && /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
1319
- /* @__PURE__ */ jsx8(
1580
+ list.length > 0 && target && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
1581
+ /* @__PURE__ */ jsx9(
1320
1582
  "select",
1321
1583
  {
1322
1584
  "aria-label": "Mask layer",
1323
1585
  value: target.id,
1324
1586
  onChange: (e) => setLayerId(e.target.value),
1325
1587
  className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1326
- children: list.map((l) => /* @__PURE__ */ jsxs8("option", { value: l.id, children: [
1588
+ children: list.map((l) => /* @__PURE__ */ jsxs9("option", { value: l.id, children: [
1327
1589
  l.name || adjustmentKindLabel2(l.kind),
1328
1590
  l.mask ? " (masked)" : ""
1329
1591
  ] }, l.id))
1330
1592
  }
1331
1593
  ),
1332
- /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap gap-1", children: [
1333
- /* @__PURE__ */ jsx8("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1334
- /* @__PURE__ */ jsx8("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1335
- /* @__PURE__ */ jsx8("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
1594
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap gap-1", children: [
1595
+ /* @__PURE__ */ jsx9("button", { type: "button", className: button2, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1596
+ /* @__PURE__ */ jsx9("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1597
+ /* @__PURE__ */ jsx9("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
1336
1598
  ] }),
1337
- target.mask && /* @__PURE__ */ jsxs8(Fragment2, { children: [
1338
- /* @__PURE__ */ jsxs8("label", { className: "flex flex-col gap-1", children: [
1339
- /* @__PURE__ */ jsxs8("span", { className: "flex justify-between text-slate-400", children: [
1340
- /* @__PURE__ */ jsx8("span", { children: "Density" }),
1341
- /* @__PURE__ */ jsxs8("span", { className: "font-mono", children: [
1599
+ target.mask && /* @__PURE__ */ jsxs9(Fragment2, { children: [
1600
+ /* @__PURE__ */ jsxs9("label", { className: "flex flex-col gap-1", children: [
1601
+ /* @__PURE__ */ jsxs9("span", { className: "flex justify-between text-slate-400", children: [
1602
+ /* @__PURE__ */ jsx9("span", { children: "Density" }),
1603
+ /* @__PURE__ */ jsxs9("span", { className: "font-mono", children: [
1342
1604
  Math.round((target.mask.density ?? 1) * 100),
1343
1605
  "%"
1344
1606
  ] })
1345
1607
  ] }),
1346
- /* @__PURE__ */ jsx8(
1608
+ /* @__PURE__ */ jsx9(
1347
1609
  "input",
1348
1610
  {
1349
1611
  type: "range",
@@ -1357,15 +1619,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1357
1619
  }
1358
1620
  )
1359
1621
  ] }),
1360
- /* @__PURE__ */ jsxs8("label", { className: "flex flex-col gap-1", children: [
1361
- /* @__PURE__ */ jsxs8("span", { className: "flex justify-between text-slate-400", children: [
1362
- /* @__PURE__ */ jsx8("span", { children: "Mask Feather" }),
1363
- /* @__PURE__ */ jsxs8("span", { className: "font-mono", children: [
1622
+ /* @__PURE__ */ jsxs9("label", { className: "flex flex-col gap-1", children: [
1623
+ /* @__PURE__ */ jsxs9("span", { className: "flex justify-between text-slate-400", children: [
1624
+ /* @__PURE__ */ jsx9("span", { children: "Mask Feather" }),
1625
+ /* @__PURE__ */ jsxs9("span", { className: "font-mono", children: [
1364
1626
  target.mask.feather ?? 0,
1365
1627
  "px"
1366
1628
  ] })
1367
1629
  ] }),
1368
- /* @__PURE__ */ jsx8(
1630
+ /* @__PURE__ */ jsx9(
1369
1631
  "input",
1370
1632
  {
1371
1633
  type: "range",
@@ -1385,7 +1647,7 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1385
1647
  };
1386
1648
 
1387
1649
  // src/image-editor/ImageEditor.tsx
1388
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1650
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1389
1651
  var ImageEditor = ({
1390
1652
  editor: externalEditor,
1391
1653
  src,
@@ -1401,34 +1663,34 @@ var ImageEditor = ({
1401
1663
  const editor = externalEditor || internalEditor;
1402
1664
  const { state, controller } = editor;
1403
1665
  const legacyProcess = normalizeProcessVersion(state.adjustments.process) < LATEST_PROCESS_VERSION;
1404
- const canvasRef = useRef4(null);
1405
- const containerRef = useRef4(null);
1406
- const [activeTab, setActiveTab] = useState9("crop");
1407
- const [activeCropRatio, setActiveCropRatio] = useState9(null);
1408
- const [selectionOptions, setSelectionOptions] = useState9(DEFAULT_SELECTION_TOOL_OPTIONS);
1409
- const selectionOptionsRef = useRef4(selectionOptions);
1666
+ const canvasRef = useRef5(null);
1667
+ const containerRef = useRef5(null);
1668
+ const [activeTab, setActiveTab] = useState10("crop");
1669
+ const [activeCropRatio, setActiveCropRatio] = useState10(null);
1670
+ const [selectionOptions, setSelectionOptions] = useState10(DEFAULT_SELECTION_TOOL_OPTIONS);
1671
+ const selectionOptionsRef = useRef5(selectionOptions);
1410
1672
  selectionOptionsRef.current = selectionOptions;
1411
- const selectionGestureRef = useRef4(null);
1673
+ const selectionGestureRef = useRef5(null);
1412
1674
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
1413
1675
  selectionGestureRef.current = new SelectionGesture(controller, () => selectionOptionsRef.current);
1414
1676
  }
1415
- const selectionDraftRef = useRef4(null);
1416
- const [selectionError, setSelectionError] = useState9(null);
1417
- const paintGestureRef = useRef4(null);
1418
- const paintControllerRef = useRef4(controller);
1677
+ const selectionDraftRef = useRef5(null);
1678
+ const [selectionError, setSelectionError] = useState10(null);
1679
+ const paintGestureRef = useRef5(null);
1680
+ const paintControllerRef = useRef5(controller);
1419
1681
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
1420
1682
  paintGestureRef.current = new PaintGesture(controller);
1421
1683
  paintControllerRef.current = controller;
1422
1684
  }
1423
- const brushCursorRef = useRef4(null);
1424
- const [paintError, setPaintError] = useState9(null);
1425
- const [inpaintPrompt, setInpaintPrompt] = useState9("");
1426
- const [inpaintMaskMode, setInpaintMaskMode] = useState9("annotations");
1427
- const [isRemovingBg, setIsRemovingBg] = useState9(false);
1428
- const [isInpainting, setIsInpainting] = useState9(false);
1429
- const [aiError, setAiError] = useState9(null);
1430
- const [aiSuccess, setAiSuccess] = useState9(null);
1431
- const [aiTarget, setAiTarget] = useState9("auto");
1685
+ const brushCursorRef = useRef5(null);
1686
+ const [paintError, setPaintError] = useState10(null);
1687
+ const [inpaintPrompt, setInpaintPrompt] = useState10("");
1688
+ const [inpaintMaskMode, setInpaintMaskMode] = useState10("annotations");
1689
+ const [isRemovingBg, setIsRemovingBg] = useState10(false);
1690
+ const [isInpainting, setIsInpainting] = useState10(false);
1691
+ const [aiError, setAiError] = useState10(null);
1692
+ const [aiSuccess, setAiSuccess] = useState10(null);
1693
+ const [aiTarget, setAiTarget] = useState10("auto");
1432
1694
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
1433
1695
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
1434
1696
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -1491,17 +1753,17 @@ var ImageEditor = ({
1491
1753
  setIsInpainting(false);
1492
1754
  }
1493
1755
  };
1494
- const [activeColor, setActiveColor] = useState9("#ef4444");
1495
- const [strokeWidth, setStrokeWidth] = useState9(3);
1496
- const [fontSize, setFontSize] = useState9(24);
1497
- const [textInput, setTextInput] = useState9("");
1498
- const draftAnnotationRef = useRef4(null);
1499
- const draftCropRef = useRef4(null);
1500
- const cropDragInfoRef = useRef4(null);
1501
- const annotationDragInfoRef = useRef4(null);
1502
- const isDrawingRef = useRef4(false);
1503
- const currentPathRef = useRef4([]);
1504
- const dragStartPointRef = useRef4(null);
1756
+ const [activeColor, setActiveColor] = useState10("#ef4444");
1757
+ const [strokeWidth, setStrokeWidth] = useState10(3);
1758
+ const [fontSize, setFontSize] = useState10(24);
1759
+ const [textInput, setTextInput] = useState10("");
1760
+ const draftAnnotationRef = useRef5(null);
1761
+ const draftCropRef = useRef5(null);
1762
+ const cropDragInfoRef = useRef5(null);
1763
+ const annotationDragInfoRef = useRef5(null);
1764
+ const isDrawingRef = useRef5(false);
1765
+ const currentPathRef = useRef5([]);
1766
+ const dragStartPointRef = useRef5(null);
1505
1767
  const renderCanvas = useCallback2(
1506
1768
  async (draftAnnotation, draftCrop) => {
1507
1769
  const canvas = canvasRef.current;
@@ -1523,7 +1785,7 @@ var ImageEditor = ({
1523
1785
  },
1524
1786
  [controller, activeTab]
1525
1787
  );
1526
- useEffect6(() => {
1788
+ useEffect7(() => {
1527
1789
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
1528
1790
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
1529
1791
  const animId = raf(() => {
@@ -1531,12 +1793,12 @@ var ImageEditor = ({
1531
1793
  });
1532
1794
  return () => caf(animId);
1533
1795
  }, [renderCanvas, state]);
1534
- useEffect6(() => {
1796
+ useEffect7(() => {
1535
1797
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
1536
1798
  editor.setTool("crop");
1537
1799
  }
1538
1800
  }, [activeTab, editor]);
1539
- useEffect6(() => {
1801
+ useEffect7(() => {
1540
1802
  const container = containerRef.current;
1541
1803
  if (!container) return;
1542
1804
  if (typeof ResizeObserver !== "undefined") {
@@ -1601,7 +1863,7 @@ var ImageEditor = ({
1601
1863
  if (g.error) setPaintError(g.error);
1602
1864
  }
1603
1865
  };
1604
- useEffect6(() => {
1866
+ useEffect7(() => {
1605
1867
  if (activeTab !== "paint" || typeof window === "undefined") return;
1606
1868
  const onKey = (e) => {
1607
1869
  if (handlePaintShortcut(controller, e)) e.preventDefault();
@@ -1964,15 +2226,15 @@ var ImageEditor = ({
1964
2226
  link.click();
1965
2227
  }
1966
2228
  };
1967
- return /* @__PURE__ */ jsxs9(
2229
+ return /* @__PURE__ */ jsxs10(
1968
2230
  "div",
1969
2231
  {
1970
2232
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
1971
2233
  style,
1972
2234
  children: [
1973
- /* @__PURE__ */ jsxs9("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: [
1974
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
1975
- /* @__PURE__ */ jsx9(
2235
+ /* @__PURE__ */ jsxs10("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: [
2236
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2237
+ /* @__PURE__ */ jsx10(
1976
2238
  "button",
1977
2239
  {
1978
2240
  type: "button",
@@ -1984,7 +2246,7 @@ var ImageEditor = ({
1984
2246
  children: "Transform & Crop"
1985
2247
  }
1986
2248
  ),
1987
- /* @__PURE__ */ jsx9(
2249
+ /* @__PURE__ */ jsx10(
1988
2250
  "button",
1989
2251
  {
1990
2252
  type: "button",
@@ -1996,7 +2258,7 @@ var ImageEditor = ({
1996
2258
  children: "Adjustments"
1997
2259
  }
1998
2260
  ),
1999
- /* @__PURE__ */ jsx9(
2261
+ /* @__PURE__ */ jsx10(
2000
2262
  "button",
2001
2263
  {
2002
2264
  type: "button",
@@ -2008,7 +2270,7 @@ var ImageEditor = ({
2008
2270
  children: "Layers"
2009
2271
  }
2010
2272
  ),
2011
- /* @__PURE__ */ jsx9(
2273
+ /* @__PURE__ */ jsx10(
2012
2274
  "button",
2013
2275
  {
2014
2276
  type: "button",
@@ -2020,7 +2282,7 @@ var ImageEditor = ({
2020
2282
  children: "Paint"
2021
2283
  }
2022
2284
  ),
2023
- /* @__PURE__ */ jsx9(
2285
+ /* @__PURE__ */ jsx10(
2024
2286
  "button",
2025
2287
  {
2026
2288
  type: "button",
@@ -2032,7 +2294,7 @@ var ImageEditor = ({
2032
2294
  children: "Select & Mask"
2033
2295
  }
2034
2296
  ),
2035
- /* @__PURE__ */ jsx9(
2297
+ /* @__PURE__ */ jsx10(
2036
2298
  "button",
2037
2299
  {
2038
2300
  type: "button",
@@ -2044,7 +2306,7 @@ var ImageEditor = ({
2044
2306
  children: "Annotations"
2045
2307
  }
2046
2308
  ),
2047
- /* @__PURE__ */ jsx9(
2309
+ /* @__PURE__ */ jsx10(
2048
2310
  "button",
2049
2311
  {
2050
2312
  type: "button",
@@ -2056,7 +2318,7 @@ var ImageEditor = ({
2056
2318
  children: "Depth Mask"
2057
2319
  }
2058
2320
  ),
2059
- /* @__PURE__ */ jsxs9(
2321
+ /* @__PURE__ */ jsxs10(
2060
2322
  "button",
2061
2323
  {
2062
2324
  type: "button",
@@ -2066,14 +2328,14 @@ var ImageEditor = ({
2066
2328
  },
2067
2329
  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"}`,
2068
2330
  children: [
2069
- /* @__PURE__ */ jsx9("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx9("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" }) }),
2331
+ /* @__PURE__ */ jsx10("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx10("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" }) }),
2070
2332
  "AI Tools"
2071
2333
  ]
2072
2334
  }
2073
2335
  )
2074
2336
  ] }),
2075
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 text-xs", children: [
2076
- /* @__PURE__ */ jsx9(
2337
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 text-xs", children: [
2338
+ /* @__PURE__ */ jsx10(
2077
2339
  "button",
2078
2340
  {
2079
2341
  type: "button",
@@ -2084,7 +2346,7 @@ var ImageEditor = ({
2084
2346
  children: "\u21A9"
2085
2347
  }
2086
2348
  ),
2087
- /* @__PURE__ */ jsx9(
2349
+ /* @__PURE__ */ jsx10(
2088
2350
  "button",
2089
2351
  {
2090
2352
  type: "button",
@@ -2095,7 +2357,7 @@ var ImageEditor = ({
2095
2357
  children: "\u21AA"
2096
2358
  }
2097
2359
  ),
2098
- /* @__PURE__ */ jsx9(
2360
+ /* @__PURE__ */ jsx10(
2099
2361
  "button",
2100
2362
  {
2101
2363
  type: "button",
@@ -2104,8 +2366,8 @@ var ImageEditor = ({
2104
2366
  children: "Reset"
2105
2367
  }
2106
2368
  ),
2107
- /* @__PURE__ */ jsx9("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2108
- /* @__PURE__ */ jsx9(
2369
+ /* @__PURE__ */ jsx10("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2370
+ /* @__PURE__ */ jsx10(
2109
2371
  "button",
2110
2372
  {
2111
2373
  type: "button",
@@ -2115,11 +2377,11 @@ var ImageEditor = ({
2115
2377
  children: "-"
2116
2378
  }
2117
2379
  ),
2118
- /* @__PURE__ */ jsxs9("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2380
+ /* @__PURE__ */ jsxs10("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2119
2381
  Math.round(state.zoom * 100),
2120
2382
  "%"
2121
2383
  ] }),
2122
- /* @__PURE__ */ jsx9(
2384
+ /* @__PURE__ */ jsx10(
2123
2385
  "button",
2124
2386
  {
2125
2387
  type: "button",
@@ -2129,8 +2391,8 @@ var ImageEditor = ({
2129
2391
  children: "+"
2130
2392
  }
2131
2393
  ),
2132
- /* @__PURE__ */ jsx9("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2133
- /* @__PURE__ */ jsx9(
2394
+ /* @__PURE__ */ jsx10("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2395
+ /* @__PURE__ */ jsx10(
2134
2396
  "button",
2135
2397
  {
2136
2398
  type: "button",
@@ -2141,7 +2403,7 @@ var ImageEditor = ({
2141
2403
  children: "Hold Compare"
2142
2404
  }
2143
2405
  ),
2144
- /* @__PURE__ */ jsx9(
2406
+ /* @__PURE__ */ jsx10(
2145
2407
  "button",
2146
2408
  {
2147
2409
  type: "button",
@@ -2152,13 +2414,13 @@ var ImageEditor = ({
2152
2414
  )
2153
2415
  ] })
2154
2416
  ] }),
2155
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2156
- /* @__PURE__ */ jsx9(
2417
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2418
+ /* @__PURE__ */ jsx10(
2157
2419
  "div",
2158
2420
  {
2159
2421
  ref: containerRef,
2160
2422
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
2161
- children: /* @__PURE__ */ jsx9(
2423
+ children: /* @__PURE__ */ jsx10(
2162
2424
  "canvas",
2163
2425
  {
2164
2426
  ref: canvasRef,
@@ -2176,11 +2438,11 @@ var ImageEditor = ({
2176
2438
  )
2177
2439
  }
2178
2440
  ),
2179
- /* @__PURE__ */ jsxs9("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: [
2180
- activeTab === "crop" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-4 text-xs", children: [
2181
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2182
- /* @__PURE__ */ jsxs9("div", { className: "grid grid-cols-3 gap-2", children: [
2183
- /* @__PURE__ */ jsx9(
2441
+ /* @__PURE__ */ jsxs10("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: [
2442
+ activeTab === "crop" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-4 text-xs", children: [
2443
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2444
+ /* @__PURE__ */ jsxs10("div", { className: "grid grid-cols-3 gap-2", children: [
2445
+ /* @__PURE__ */ jsx10(
2184
2446
  "button",
2185
2447
  {
2186
2448
  type: "button",
@@ -2192,7 +2454,7 @@ var ImageEditor = ({
2192
2454
  children: "Freeform"
2193
2455
  }
2194
2456
  ),
2195
- /* @__PURE__ */ jsx9(
2457
+ /* @__PURE__ */ jsx10(
2196
2458
  "button",
2197
2459
  {
2198
2460
  type: "button",
@@ -2204,7 +2466,7 @@ var ImageEditor = ({
2204
2466
  children: "1:1 Square"
2205
2467
  }
2206
2468
  ),
2207
- /* @__PURE__ */ jsx9(
2469
+ /* @__PURE__ */ jsx10(
2208
2470
  "button",
2209
2471
  {
2210
2472
  type: "button",
@@ -2216,7 +2478,7 @@ var ImageEditor = ({
2216
2478
  children: "4:3 Standard"
2217
2479
  }
2218
2480
  ),
2219
- /* @__PURE__ */ jsx9(
2481
+ /* @__PURE__ */ jsx10(
2220
2482
  "button",
2221
2483
  {
2222
2484
  type: "button",
@@ -2228,7 +2490,7 @@ var ImageEditor = ({
2228
2490
  children: "16:9 Wide"
2229
2491
  }
2230
2492
  ),
2231
- /* @__PURE__ */ jsx9(
2493
+ /* @__PURE__ */ jsx10(
2232
2494
  "button",
2233
2495
  {
2234
2496
  type: "button",
@@ -2240,7 +2502,7 @@ var ImageEditor = ({
2240
2502
  children: "3:2 Photo"
2241
2503
  }
2242
2504
  ),
2243
- /* @__PURE__ */ jsx9(
2505
+ /* @__PURE__ */ jsx10(
2244
2506
  "button",
2245
2507
  {
2246
2508
  type: "button",
@@ -2253,10 +2515,10 @@ var ImageEditor = ({
2253
2515
  }
2254
2516
  )
2255
2517
  ] }),
2256
- /* @__PURE__ */ jsx9("div", { className: "h-px bg-slate-800 my-1" }),
2257
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2258
- /* @__PURE__ */ jsxs9("div", { className: "grid grid-cols-2 gap-2", children: [
2259
- /* @__PURE__ */ jsx9(
2518
+ /* @__PURE__ */ jsx10("div", { className: "h-px bg-slate-800 my-1" }),
2519
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2520
+ /* @__PURE__ */ jsxs10("div", { className: "grid grid-cols-2 gap-2", children: [
2521
+ /* @__PURE__ */ jsx10(
2260
2522
  "button",
2261
2523
  {
2262
2524
  type: "button",
@@ -2265,7 +2527,7 @@ var ImageEditor = ({
2265
2527
  children: "Rotate -90\xB0"
2266
2528
  }
2267
2529
  ),
2268
- /* @__PURE__ */ jsx9(
2530
+ /* @__PURE__ */ jsx10(
2269
2531
  "button",
2270
2532
  {
2271
2533
  type: "button",
@@ -2274,7 +2536,7 @@ var ImageEditor = ({
2274
2536
  children: "Rotate +90\xB0"
2275
2537
  }
2276
2538
  ),
2277
- /* @__PURE__ */ jsx9(
2539
+ /* @__PURE__ */ jsx10(
2278
2540
  "button",
2279
2541
  {
2280
2542
  type: "button",
@@ -2283,7 +2545,7 @@ var ImageEditor = ({
2283
2545
  children: "Flip Horizontal"
2284
2546
  }
2285
2547
  ),
2286
- /* @__PURE__ */ jsx9(
2548
+ /* @__PURE__ */ jsx10(
2287
2549
  "button",
2288
2550
  {
2289
2551
  type: "button",
@@ -2294,10 +2556,10 @@ var ImageEditor = ({
2294
2556
  )
2295
2557
  ] })
2296
2558
  ] }),
2297
- activeTab === "adjust" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-3 text-xs", children: [
2298
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
2299
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2300
- /* @__PURE__ */ jsx9(
2559
+ activeTab === "adjust" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3 text-xs", children: [
2560
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
2561
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2562
+ /* @__PURE__ */ jsx10(
2301
2563
  "button",
2302
2564
  {
2303
2565
  type: "button",
@@ -2307,9 +2569,9 @@ var ImageEditor = ({
2307
2569
  }
2308
2570
  )
2309
2571
  ] }),
2310
- /* @__PURE__ */ jsx9(Histogram, { histogram: editor.histogram }),
2311
- IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ jsxs9(React8.Fragment, { children: [
2312
- /* @__PURE__ */ jsx9(
2572
+ /* @__PURE__ */ jsx10(Histogram, { histogram: editor.histogram }),
2573
+ IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ jsxs10(React9.Fragment, { children: [
2574
+ /* @__PURE__ */ jsx10(
2313
2575
  ControlSlider,
2314
2576
  {
2315
2577
  spec,
@@ -2318,14 +2580,14 @@ var ImageEditor = ({
2318
2580
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
2319
2581
  }
2320
2582
  ),
2321
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ jsxs9(
2583
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ jsxs10(
2322
2584
  "div",
2323
2585
  {
2324
2586
  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",
2325
2587
  "data-testid": "image-editor-process-notice",
2326
2588
  children: [
2327
- /* @__PURE__ */ jsx9("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
2328
- /* @__PURE__ */ jsx9(
2589
+ /* @__PURE__ */ jsx10("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
2590
+ /* @__PURE__ */ jsx10(
2329
2591
  "button",
2330
2592
  {
2331
2593
  type: "button",
@@ -2338,7 +2600,7 @@ var ImageEditor = ({
2338
2600
  }
2339
2601
  )
2340
2602
  ] }, spec.id)),
2341
- /* @__PURE__ */ jsx9("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx9(
2603
+ /* @__PURE__ */ jsx10("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx10(
2342
2604
  AdjustmentLayersPanel,
2343
2605
  {
2344
2606
  controller,
@@ -2347,19 +2609,19 @@ var ImageEditor = ({
2347
2609
  }
2348
2610
  ) })
2349
2611
  ] }),
2350
- activeTab === "layers" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-3 text-xs", children: [
2351
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
2352
- /* @__PURE__ */ jsx9(LayersPanel, { controller })
2612
+ activeTab === "layers" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3 text-xs", children: [
2613
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
2614
+ /* @__PURE__ */ jsx10(LayersPanel, { controller })
2353
2615
  ] }),
2354
- activeTab === "paint" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-3 text-xs", children: [
2355
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
2356
- /* @__PURE__ */ jsx9(BrushOptionsBar, { controller }),
2357
- paintError && /* @__PURE__ */ jsx9("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
2358
- /* @__PURE__ */ jsx9("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx9(LayersPanel, { controller }) })
2616
+ activeTab === "paint" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3 text-xs", children: [
2617
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
2618
+ /* @__PURE__ */ jsx10(BrushOptionsBar, { controller }),
2619
+ paintError && /* @__PURE__ */ jsx10("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
2620
+ /* @__PURE__ */ jsx10("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx10(LayersPanel, { controller }) })
2359
2621
  ] }),
2360
- activeTab === "annotate" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-3 text-xs", children: [
2361
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2362
- /* @__PURE__ */ jsx9("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ jsx9(
2622
+ activeTab === "annotate" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3 text-xs", children: [
2623
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2624
+ /* @__PURE__ */ jsx10("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ jsx10(
2363
2625
  "button",
2364
2626
  {
2365
2627
  type: "button",
@@ -2369,9 +2631,9 @@ var ImageEditor = ({
2369
2631
  },
2370
2632
  t
2371
2633
  )) }),
2372
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 mt-2", children: [
2373
- /* @__PURE__ */ jsx9("label", { className: "text-slate-400", children: "Color:" }),
2374
- /* @__PURE__ */ jsx9(
2634
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 mt-2", children: [
2635
+ /* @__PURE__ */ jsx10("label", { className: "text-slate-400", children: "Color:" }),
2636
+ /* @__PURE__ */ jsx10(
2375
2637
  "input",
2376
2638
  {
2377
2639
  type: "color",
@@ -2380,15 +2642,15 @@ var ImageEditor = ({
2380
2642
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
2381
2643
  }
2382
2644
  ),
2383
- /* @__PURE__ */ jsxs9("div", { className: "flex-1 ml-2", children: [
2384
- /* @__PURE__ */ jsxs9("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2385
- /* @__PURE__ */ jsx9("span", { children: "Width:" }),
2386
- /* @__PURE__ */ jsxs9("span", { className: "font-mono", children: [
2645
+ /* @__PURE__ */ jsxs10("div", { className: "flex-1 ml-2", children: [
2646
+ /* @__PURE__ */ jsxs10("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2647
+ /* @__PURE__ */ jsx10("span", { children: "Width:" }),
2648
+ /* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
2387
2649
  strokeWidth,
2388
2650
  "px"
2389
2651
  ] })
2390
2652
  ] }),
2391
- /* @__PURE__ */ jsx9(
2653
+ /* @__PURE__ */ jsx10(
2392
2654
  "input",
2393
2655
  {
2394
2656
  type: "range",
@@ -2401,10 +2663,10 @@ var ImageEditor = ({
2401
2663
  )
2402
2664
  ] })
2403
2665
  ] }),
2404
- /* @__PURE__ */ jsx9("div", { className: "h-px bg-slate-800 my-1" }),
2405
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2406
- /* @__PURE__ */ jsxs9("div", { className: "flex gap-2", children: [
2407
- /* @__PURE__ */ jsx9(
2666
+ /* @__PURE__ */ jsx10("div", { className: "h-px bg-slate-800 my-1" }),
2667
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2668
+ /* @__PURE__ */ jsxs10("div", { className: "flex gap-2", children: [
2669
+ /* @__PURE__ */ jsx10(
2408
2670
  "input",
2409
2671
  {
2410
2672
  type: "text",
@@ -2415,7 +2677,7 @@ var ImageEditor = ({
2415
2677
  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"
2416
2678
  }
2417
2679
  ),
2418
- /* @__PURE__ */ jsx9(
2680
+ /* @__PURE__ */ jsx10(
2419
2681
  "button",
2420
2682
  {
2421
2683
  type: "button",
@@ -2425,14 +2687,14 @@ var ImageEditor = ({
2425
2687
  }
2426
2688
  )
2427
2689
  ] }),
2428
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between text-slate-400", children: [
2429
- /* @__PURE__ */ jsx9("span", { children: "Font Size:" }),
2430
- /* @__PURE__ */ jsxs9("span", { className: "font-mono", children: [
2690
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between text-slate-400", children: [
2691
+ /* @__PURE__ */ jsx10("span", { children: "Font Size:" }),
2692
+ /* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
2431
2693
  fontSize,
2432
2694
  "px"
2433
2695
  ] })
2434
2696
  ] }),
2435
- /* @__PURE__ */ jsx9(
2697
+ /* @__PURE__ */ jsx10(
2436
2698
  "input",
2437
2699
  {
2438
2700
  type: "range",
@@ -2443,14 +2705,14 @@ var ImageEditor = ({
2443
2705
  className: "w-full accent-indigo-500"
2444
2706
  }
2445
2707
  ),
2446
- /* @__PURE__ */ jsx9("div", { className: "h-px bg-slate-800 my-1" }),
2447
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
2448
- /* @__PURE__ */ jsxs9("span", { className: "text-slate-400", children: [
2708
+ /* @__PURE__ */ jsx10("div", { className: "h-px bg-slate-800 my-1" }),
2709
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
2710
+ /* @__PURE__ */ jsxs10("span", { className: "text-slate-400", children: [
2449
2711
  "Layers (",
2450
2712
  state.annotations.length,
2451
2713
  ")"
2452
2714
  ] }),
2453
- state.selectedAnnotationId && /* @__PURE__ */ jsx9(
2715
+ state.selectedAnnotationId && /* @__PURE__ */ jsx10(
2454
2716
  "button",
2455
2717
  {
2456
2718
  type: "button",
@@ -2459,7 +2721,7 @@ var ImageEditor = ({
2459
2721
  children: "Delete Selected"
2460
2722
  }
2461
2723
  ),
2462
- state.annotations.length > 0 && /* @__PURE__ */ jsx9(
2724
+ state.annotations.length > 0 && /* @__PURE__ */ jsx10(
2463
2725
  "button",
2464
2726
  {
2465
2727
  type: "button",
@@ -2470,10 +2732,10 @@ var ImageEditor = ({
2470
2732
  )
2471
2733
  ] })
2472
2734
  ] }),
2473
- activeTab === "depth" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-3 text-xs", children: [
2474
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
2475
- /* @__PURE__ */ jsx9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2476
- /* @__PURE__ */ jsx9(
2735
+ activeTab === "depth" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3 text-xs", children: [
2736
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
2737
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2738
+ /* @__PURE__ */ jsx10(
2477
2739
  "button",
2478
2740
  {
2479
2741
  type: "button",
@@ -2483,8 +2745,8 @@ var ImageEditor = ({
2483
2745
  }
2484
2746
  )
2485
2747
  ] }),
2486
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2487
- /* @__PURE__ */ jsx9(
2748
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2749
+ /* @__PURE__ */ jsx10(
2488
2750
  "input",
2489
2751
  {
2490
2752
  type: "checkbox",
@@ -2493,12 +2755,12 @@ var ImageEditor = ({
2493
2755
  className: "rounded accent-indigo-500"
2494
2756
  }
2495
2757
  ),
2496
- /* @__PURE__ */ jsx9("span", { children: "Enable Depth / Alpha Mask" })
2758
+ /* @__PURE__ */ jsx10("span", { children: "Enable Depth / Alpha Mask" })
2497
2759
  ] }),
2498
- state.depthMask.enabled && /* @__PURE__ */ jsxs9(Fragment3, { children: [
2499
- /* @__PURE__ */ jsxs9("div", { children: [
2500
- /* @__PURE__ */ jsx9("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
2501
- /* @__PURE__ */ jsx9(
2760
+ state.depthMask.enabled && /* @__PURE__ */ jsxs10(Fragment3, { children: [
2761
+ /* @__PURE__ */ jsxs10("div", { children: [
2762
+ /* @__PURE__ */ jsx10("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
2763
+ /* @__PURE__ */ jsx10(
2502
2764
  "input",
2503
2765
  {
2504
2766
  type: "text",
@@ -2509,8 +2771,8 @@ var ImageEditor = ({
2509
2771
  }
2510
2772
  )
2511
2773
  ] }),
2512
- /* @__PURE__ */ jsxs9("div", { className: "flex gap-2", children: [
2513
- /* @__PURE__ */ jsx9(
2774
+ /* @__PURE__ */ jsxs10("div", { className: "flex gap-2", children: [
2775
+ /* @__PURE__ */ jsx10(
2514
2776
  "button",
2515
2777
  {
2516
2778
  type: "button",
@@ -2519,7 +2781,7 @@ var ImageEditor = ({
2519
2781
  children: "Threshold Mode"
2520
2782
  }
2521
2783
  ),
2522
- /* @__PURE__ */ jsx9(
2784
+ /* @__PURE__ */ jsx10(
2523
2785
  "button",
2524
2786
  {
2525
2787
  type: "button",
@@ -2529,12 +2791,12 @@ var ImageEditor = ({
2529
2791
  }
2530
2792
  )
2531
2793
  ] }),
2532
- /* @__PURE__ */ jsxs9("div", { children: [
2533
- /* @__PURE__ */ jsxs9("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2534
- /* @__PURE__ */ jsx9("span", { children: "Depth Start (Lower):" }),
2535
- /* @__PURE__ */ jsx9("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
2794
+ /* @__PURE__ */ jsxs10("div", { children: [
2795
+ /* @__PURE__ */ jsxs10("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2796
+ /* @__PURE__ */ jsx10("span", { children: "Depth Start (Lower):" }),
2797
+ /* @__PURE__ */ jsx10("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
2536
2798
  ] }),
2537
- /* @__PURE__ */ jsx9(
2799
+ /* @__PURE__ */ jsx10(
2538
2800
  "input",
2539
2801
  {
2540
2802
  type: "range",
@@ -2548,12 +2810,12 @@ var ImageEditor = ({
2548
2810
  }
2549
2811
  )
2550
2812
  ] }),
2551
- /* @__PURE__ */ jsxs9("div", { children: [
2552
- /* @__PURE__ */ jsxs9("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2553
- /* @__PURE__ */ jsx9("span", { children: "Depth Stop (Upper):" }),
2554
- /* @__PURE__ */ jsx9("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
2813
+ /* @__PURE__ */ jsxs10("div", { children: [
2814
+ /* @__PURE__ */ jsxs10("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2815
+ /* @__PURE__ */ jsx10("span", { children: "Depth Stop (Upper):" }),
2816
+ /* @__PURE__ */ jsx10("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
2555
2817
  ] }),
2556
- /* @__PURE__ */ jsx9(
2818
+ /* @__PURE__ */ jsx10(
2557
2819
  "input",
2558
2820
  {
2559
2821
  type: "range",
@@ -2567,12 +2829,12 @@ var ImageEditor = ({
2567
2829
  }
2568
2830
  )
2569
2831
  ] }),
2570
- /* @__PURE__ */ jsxs9("div", { children: [
2571
- /* @__PURE__ */ jsxs9("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2572
- /* @__PURE__ */ jsx9("span", { children: "Softness:" }),
2573
- /* @__PURE__ */ jsx9("span", { className: "font-mono", children: state.depthMask.softness })
2832
+ /* @__PURE__ */ jsxs10("div", { children: [
2833
+ /* @__PURE__ */ jsxs10("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2834
+ /* @__PURE__ */ jsx10("span", { children: "Softness:" }),
2835
+ /* @__PURE__ */ jsx10("span", { className: "font-mono", children: state.depthMask.softness })
2574
2836
  ] }),
2575
- /* @__PURE__ */ jsx9(
2837
+ /* @__PURE__ */ jsx10(
2576
2838
  "input",
2577
2839
  {
2578
2840
  type: "range",
@@ -2584,8 +2846,8 @@ var ImageEditor = ({
2584
2846
  }
2585
2847
  )
2586
2848
  ] }),
2587
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
2588
- /* @__PURE__ */ jsx9(
2849
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
2850
+ /* @__PURE__ */ jsx10(
2589
2851
  "input",
2590
2852
  {
2591
2853
  type: "checkbox",
@@ -2594,12 +2856,12 @@ var ImageEditor = ({
2594
2856
  className: "rounded accent-indigo-500"
2595
2857
  }
2596
2858
  ),
2597
- /* @__PURE__ */ jsx9("span", { children: "Invert Mask" })
2859
+ /* @__PURE__ */ jsx10("span", { children: "Invert Mask" })
2598
2860
  ] })
2599
2861
  ] })
2600
2862
  ] }),
2601
- activeTab === "select" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-4 text-xs", children: [
2602
- /* @__PURE__ */ jsx9(
2863
+ activeTab === "select" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-4 text-xs", children: [
2864
+ /* @__PURE__ */ jsx10(
2603
2865
  SelectionOptionsBar,
2604
2866
  {
2605
2867
  controller,
@@ -2609,13 +2871,13 @@ var ImageEditor = ({
2609
2871
  quickMask: Boolean(state.quickMask)
2610
2872
  }
2611
2873
  ),
2612
- selectionError && /* @__PURE__ */ jsx9("p", { role: "alert", className: "text-rose-400", children: selectionError }),
2613
- /* @__PURE__ */ jsx9(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
2874
+ selectionError && /* @__PURE__ */ jsx10("p", { role: "alert", className: "text-rose-400", children: selectionError }),
2875
+ /* @__PURE__ */ jsx10(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
2614
2876
  ] }),
2615
- activeTab === "ai" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-4 text-xs", children: [
2616
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
2617
- /* @__PURE__ */ jsx9("span", { children: "Results go to" }),
2618
- /* @__PURE__ */ jsxs9(
2877
+ activeTab === "ai" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-4 text-xs", children: [
2878
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
2879
+ /* @__PURE__ */ jsx10("span", { children: "Results go to" }),
2880
+ /* @__PURE__ */ jsxs10(
2619
2881
  "select",
2620
2882
  {
2621
2883
  "aria-label": "AI result target",
@@ -2623,54 +2885,54 @@ var ImageEditor = ({
2623
2885
  onChange: (e) => setAiTarget(e.target.value),
2624
2886
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
2625
2887
  children: [
2626
- /* @__PURE__ */ jsx9("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
2627
- /* @__PURE__ */ jsx9("option", { value: "new-layer", children: "New layer / mask" }),
2628
- /* @__PURE__ */ jsx9("option", { value: "replace", children: "Replace image" })
2888
+ /* @__PURE__ */ jsx10("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
2889
+ /* @__PURE__ */ jsx10("option", { value: "new-layer", children: "New layer / mask" }),
2890
+ /* @__PURE__ */ jsx10("option", { value: "replace", children: "Replace image" })
2629
2891
  ]
2630
2892
  }
2631
2893
  )
2632
2894
  ] }),
2633
- /* @__PURE__ */ jsxs9("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2634
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
2635
- /* @__PURE__ */ jsxs9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2636
- /* @__PURE__ */ jsx9("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx9("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" }) }),
2895
+ /* @__PURE__ */ jsxs10("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2896
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
2897
+ /* @__PURE__ */ jsxs10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2898
+ /* @__PURE__ */ jsx10("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx10("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" }) }),
2637
2899
  "Background Removal"
2638
2900
  ] }),
2639
- isRemovingBg && /* @__PURE__ */ jsx9("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..." })
2901
+ isRemovingBg && /* @__PURE__ */ jsx10("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..." })
2640
2902
  ] }),
2641
- /* @__PURE__ */ jsx9("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
2642
- /* @__PURE__ */ jsx9(
2903
+ /* @__PURE__ */ jsx10("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
2904
+ /* @__PURE__ */ jsx10(
2643
2905
  "button",
2644
2906
  {
2645
2907
  type: "button",
2646
2908
  onClick: handleRemoveBackground,
2647
2909
  disabled: isRemovingBg || isInpainting,
2648
2910
  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",
2649
- children: isRemovingBg ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
2650
- /* @__PURE__ */ jsx9("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2911
+ children: isRemovingBg ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
2912
+ /* @__PURE__ */ jsx10("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2651
2913
  "Removing Background..."
2652
- ] }) : /* @__PURE__ */ jsxs9(Fragment3, { children: [
2653
- /* @__PURE__ */ jsx9("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx9("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" }) }),
2914
+ ] }) : /* @__PURE__ */ jsxs10(Fragment3, { children: [
2915
+ /* @__PURE__ */ jsx10("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx10("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" }) }),
2654
2916
  "Remove Background"
2655
2917
  ] })
2656
2918
  }
2657
2919
  )
2658
2920
  ] }),
2659
- /* @__PURE__ */ jsxs9("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2660
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
2661
- /* @__PURE__ */ jsxs9("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2662
- /* @__PURE__ */ jsxs9("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2663
- /* @__PURE__ */ jsx9("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" }),
2664
- /* @__PURE__ */ jsx9("path", { d: "m14 7 3 3" })
2921
+ /* @__PURE__ */ jsxs10("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2922
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
2923
+ /* @__PURE__ */ jsxs10("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2924
+ /* @__PURE__ */ jsxs10("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2925
+ /* @__PURE__ */ jsx10("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" }),
2926
+ /* @__PURE__ */ jsx10("path", { d: "m14 7 3 3" })
2665
2927
  ] }),
2666
2928
  "Generative Inpainting"
2667
2929
  ] }),
2668
- isInpainting && /* @__PURE__ */ jsx9("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..." })
2930
+ isInpainting && /* @__PURE__ */ jsx10("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..." })
2669
2931
  ] }),
2670
- /* @__PURE__ */ jsx9("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
2671
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1", children: [
2672
- /* @__PURE__ */ jsx9("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
2673
- /* @__PURE__ */ jsx9(
2932
+ /* @__PURE__ */ jsx10("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
2933
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-1", children: [
2934
+ /* @__PURE__ */ jsx10("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
2935
+ /* @__PURE__ */ jsx10(
2674
2936
  "textarea",
2675
2937
  {
2676
2938
  id: "ai-inpaint-prompt-react",
@@ -2682,10 +2944,10 @@ var ImageEditor = ({
2682
2944
  }
2683
2945
  )
2684
2946
  ] }),
2685
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1", children: [
2686
- /* @__PURE__ */ jsx9("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
2687
- /* @__PURE__ */ jsxs9("div", { className: "grid grid-cols-2 gap-1.5", children: [
2688
- /* @__PURE__ */ jsxs9(
2947
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-1", children: [
2948
+ /* @__PURE__ */ jsx10("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
2949
+ /* @__PURE__ */ jsxs10("div", { className: "grid grid-cols-2 gap-1.5", children: [
2950
+ /* @__PURE__ */ jsxs10(
2689
2951
  "button",
2690
2952
  {
2691
2953
  type: "button",
@@ -2698,7 +2960,7 @@ var ImageEditor = ({
2698
2960
  ]
2699
2961
  }
2700
2962
  ),
2701
- /* @__PURE__ */ jsxs9(
2963
+ /* @__PURE__ */ jsxs10(
2702
2964
  "button",
2703
2965
  {
2704
2966
  type: "button",
@@ -2713,25 +2975,25 @@ var ImageEditor = ({
2713
2975
  )
2714
2976
  ] })
2715
2977
  ] }),
2716
- /* @__PURE__ */ jsx9(
2978
+ /* @__PURE__ */ jsx10(
2717
2979
  "button",
2718
2980
  {
2719
2981
  type: "button",
2720
2982
  onClick: handleInpaint,
2721
2983
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
2722
2984
  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",
2723
- children: isInpainting ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
2724
- /* @__PURE__ */ jsx9("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2985
+ children: isInpainting ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
2986
+ /* @__PURE__ */ jsx10("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2725
2987
  "Generating Inpaint..."
2726
- ] }) : /* @__PURE__ */ jsxs9(Fragment3, { children: [
2727
- /* @__PURE__ */ jsx9("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx9("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" }) }),
2988
+ ] }) : /* @__PURE__ */ jsxs10(Fragment3, { children: [
2989
+ /* @__PURE__ */ jsx10("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx10("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" }) }),
2728
2990
  "Apply Inpainting"
2729
2991
  ] })
2730
2992
  }
2731
2993
  )
2732
2994
  ] }),
2733
- aiError && /* @__PURE__ */ jsx9("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
2734
- aiSuccess && /* @__PURE__ */ jsx9("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
2995
+ aiError && /* @__PURE__ */ jsx10("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
2996
+ aiSuccess && /* @__PURE__ */ jsx10("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
2735
2997
  ] })
2736
2998
  ] })
2737
2999
  ] })
@@ -2747,10 +3009,11 @@ export {
2747
3009
  useImageHistogram,
2748
3010
  CurvesEditor,
2749
3011
  AdjustmentLayersPanel,
3012
+ LayerEffectsPanel,
2750
3013
  LayersPanel,
2751
3014
  BrushOptionsBar,
2752
3015
  SelectionOptionsBar,
2753
3016
  RefineEdgePanel,
2754
3017
  ImageEditor
2755
3018
  };
2756
- //# sourceMappingURL=chunk-OSOGA2OJ.js.map
3019
+ //# sourceMappingURL=chunk-M4WLX3IR.js.map