@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.
@@ -36,6 +36,7 @@ __export(image_editor_exports, {
36
36
  CurvesEditor: () => CurvesEditor,
37
37
  Histogram: () => Histogram,
38
38
  ImageEditor: () => ImageEditor,
39
+ LayerEffectsPanel: () => LayerEffectsPanel,
39
40
  LayersPanel: () => LayersPanel,
40
41
  RefineEdgePanel: () => RefineEdgePanel,
41
42
  SelectionOptionsBar: () => SelectionOptionsBar,
@@ -203,8 +204,8 @@ function useImageEditor(options = {}) {
203
204
  }
204
205
 
205
206
  // src/image-editor/ImageEditor.tsx
206
- var import_react9 = __toESM(require("react"), 1);
207
- var import_image_editor10 = require("@pixerate/editor/image-editor");
207
+ var import_react10 = __toESM(require("react"), 1);
208
+ var import_image_editor11 = require("@pixerate/editor/image-editor");
208
209
 
209
210
  // src/image-editor/ControlSlider.tsx
210
211
  var import_image_editor2 = require("@pixerate/editor/image-editor");
@@ -636,9 +637,198 @@ var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
636
637
  };
637
638
 
638
639
  // src/image-editor/LayersPanel.tsx
640
+ var import_react6 = require("react");
641
+
642
+ // src/image-editor/LayerEffectsPanel.tsx
639
643
  var import_react5 = require("react");
640
644
  var import_image_editor6 = require("@pixerate/editor/image-editor");
641
645
  var import_jsx_runtime5 = require("react/jsx-runtime");
646
+ var button = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
647
+ var LayerEffectsPanel = ({ controller, layerId, className }) => {
648
+ const [, setTick] = (0, import_react5.useState)(0);
649
+ (0, import_react5.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
650
+ const [open, setOpen] = (0, import_react5.useState)(null);
651
+ const [error, setError] = (0, import_react5.useState)(null);
652
+ const commitNext = (0, import_react5.useRef)(true);
653
+ const layer = layerId ? controller.getLayer(layerId) : controller.getActiveLayer();
654
+ const model = (0, import_image_editor6.layerEffectsPanel)(layer);
655
+ const id = layer?.id;
656
+ const attempt = (fn) => {
657
+ try {
658
+ setError(null);
659
+ fn();
660
+ } catch (err) {
661
+ setError(err instanceof Error ? err.message : String(err));
662
+ }
663
+ };
664
+ const sliderEvents = {
665
+ onPointerDown: () => commitNext.current = true,
666
+ onPointerUp: () => commitNext.current = true,
667
+ onKeyDown: () => commitNext.current = true
668
+ };
669
+ if (!model.available || !id) {
670
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: `text-xs text-slate-500 ${className ?? ""}`, "data-testid": "layer-effects", children: model.reason });
671
+ }
672
+ const effects = controller.getLayerEffects(id);
673
+ const patterns = controller.getDocumentPatterns();
674
+ const change = (effectId, control, value, drag = false) => attempt(() => {
675
+ const effect = controller.getLayerEffects(id).items.find((e) => e.id === effectId);
676
+ controller.updateLayerEffect(id, effectId, (0, import_image_editor6.effectControlChange)(effect, control.key, value, patterns), drag ? commitNext.current : true);
677
+ if (drag) commitNext.current = false;
678
+ });
679
+ const renderControl = (effectId, c) => {
680
+ const label = `${c.label}`;
681
+ switch (c.type) {
682
+ case "range": {
683
+ const k = c.percent ? 100 : 1;
684
+ const shown = Math.round(c.value * k * 100) / 100;
685
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
686
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
687
+ label,
688
+ " ",
689
+ shown,
690
+ c.unit
691
+ ] }),
692
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
693
+ "input",
694
+ {
695
+ type: "range",
696
+ "aria-label": label,
697
+ min: c.min * k,
698
+ max: c.max * k,
699
+ step: c.step * k,
700
+ value: shown,
701
+ disabled: model.readOnly,
702
+ ...sliderEvents,
703
+ onChange: (e) => change(effectId, c, Number(e.target.value) / k, true),
704
+ className: "accent-indigo-500"
705
+ }
706
+ )
707
+ ] }, c.key);
708
+ }
709
+ case "color":
710
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
711
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "color", "aria-label": label, value: c.value, disabled: model.readOnly, onChange: (e) => change(effectId, c, e.target.value) }),
712
+ label
713
+ ] }, c.key);
714
+ case "checkbox":
715
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
716
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", "aria-label": label, checked: c.value, disabled: model.readOnly, onChange: (e) => change(effectId, c, e.target.checked), className: "accent-indigo-500" }),
717
+ label
718
+ ] }, c.key);
719
+ case "select":
720
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
721
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-400", children: label }),
722
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
723
+ "select",
724
+ {
725
+ "aria-label": label,
726
+ value: c.value,
727
+ disabled: model.readOnly,
728
+ onChange: (e) => change(effectId, c, e.target.value),
729
+ className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
730
+ children: c.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: o.value, children: o.label }, o.value))
731
+ }
732
+ )
733
+ ] }, c.key);
734
+ }
735
+ };
736
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("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: [
737
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
738
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-300", children: "fx Effects" }),
739
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1 text-slate-300", children: [
740
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
741
+ "input",
742
+ {
743
+ type: "checkbox",
744
+ "aria-label": "Effects on",
745
+ checked: model.enabled,
746
+ disabled: model.readOnly,
747
+ onChange: (e) => attempt(() => controller.setLayerEffectsEnabled(id, e.target.checked)),
748
+ className: "accent-indigo-500"
749
+ }
750
+ ),
751
+ "On"
752
+ ] }),
753
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
754
+ "Scale",
755
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
756
+ "input",
757
+ {
758
+ type: "number",
759
+ "aria-label": "Scale effects",
760
+ min: 1,
761
+ max: 1e3,
762
+ step: 1,
763
+ value: Math.round(model.scale * 100),
764
+ disabled: model.readOnly,
765
+ onChange: (e) => {
766
+ const v = Number(e.target.value);
767
+ if (v >= 1 && v <= 1e3) attempt(() => controller.setLayerEffectsEnabled(id, model.enabled, v / 100));
768
+ },
769
+ className: "w-14 bg-slate-800 border border-slate-700 rounded px-1"
770
+ }
771
+ ),
772
+ "%"
773
+ ] }),
774
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
775
+ "select",
776
+ {
777
+ "aria-label": "Add effect",
778
+ value: "",
779
+ disabled: model.readOnly,
780
+ onChange: (e) => {
781
+ const kind = e.target.value;
782
+ if (!kind) return;
783
+ attempt(() => setOpen(controller.addLayerEffect(id, kind).effect.id));
784
+ },
785
+ className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
786
+ children: [
787
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", children: "Add effect\u2026" }),
788
+ import_image_editor6.LAYER_EFFECT_MENU.map((m) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: m.kind, children: m.label }, m.kind))
789
+ ]
790
+ }
791
+ )
792
+ ] }),
793
+ model.readOnly && model.reason && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-500", children: model.reason }),
794
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "flex flex-col gap-1", "aria-label": "Effects", children: model.rows.map((row) => {
795
+ const effect = effects.items.find((e) => e.id === row.id);
796
+ const expanded = open === row.id;
797
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { "data-effect-id": row.id, className: "rounded bg-slate-900/60 ring-1 ring-slate-800", children: [
798
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5 px-1.5 py-1", children: [
799
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
800
+ "input",
801
+ {
802
+ type: "checkbox",
803
+ "aria-label": `${row.label} on`,
804
+ checked: row.enabled,
805
+ disabled: model.readOnly,
806
+ onChange: (e) => attempt(() => controller.updateLayerEffect(id, row.id, { enabled: e.target.checked })),
807
+ className: "accent-indigo-500"
808
+ }
809
+ ),
810
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
811
+ "button",
812
+ {
813
+ type: "button",
814
+ "aria-expanded": expanded,
815
+ className: `flex-1 text-left ${row.enabled && model.enabled ? "" : "text-slate-500"}`,
816
+ onClick: () => setOpen(expanded ? null : row.id),
817
+ children: row.label
818
+ }
819
+ ),
820
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: button, "aria-label": `Remove ${row.label}`, disabled: model.readOnly, onClick: () => attempt(() => controller.removeLayerEffect(id, row.id)), children: "\u2715" })
821
+ ] }),
822
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 px-1.5 pb-1.5", "data-testid": "effect-settings", children: (0, import_image_editor6.layerEffectControls)(effect, patterns).map((c) => renderControl(row.id, c)) })
823
+ ] }, row.id);
824
+ }) }),
825
+ error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
826
+ ] });
827
+ };
828
+
829
+ // src/image-editor/LayersPanel.tsx
830
+ var import_image_editor7 = require("@pixerate/editor/image-editor");
831
+ var import_jsx_runtime6 = require("react/jsx-runtime");
642
832
  var iconButton = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
643
833
  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"}`;
644
834
  var Thumbnail = ({
@@ -649,8 +839,8 @@ var Thumbnail = ({
649
839
  selected,
650
840
  testId
651
841
  }) => {
652
- const ref = (0, import_react5.useRef)(null);
653
- (0, import_react5.useEffect)(() => {
842
+ const ref = (0, import_react6.useRef)(null);
843
+ (0, import_react6.useEffect)(() => {
654
844
  const canvas = ref.current;
655
845
  const ctx = canvas?.getContext("2d");
656
846
  if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== "function") return;
@@ -660,7 +850,7 @@ var Thumbnail = ({
660
850
  img.data.set(pixels.data);
661
851
  ctx.putImageData(img, 0, 0);
662
852
  }, [pixels]);
663
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
853
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
664
854
  "canvas",
665
855
  {
666
856
  ref,
@@ -673,15 +863,15 @@ var Thumbnail = ({
673
863
  }
674
864
  );
675
865
  };
676
- var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "image", className }) => {
677
- const [, setTick] = (0, import_react5.useState)(0);
678
- (0, import_react5.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
679
- const [error, setError] = (0, import_react5.useState)(null);
680
- const [renaming, setRenaming] = (0, import_react5.useState)(null);
681
- const [menu, setMenu] = (0, import_react5.useState)(null);
682
- const [drag, setDrag] = (0, import_react5.useState)(null);
683
- const [psdNotes, setPsdNotes] = (0, import_react5.useState)([]);
684
- const fileInput = (0, import_react5.useRef)(null);
866
+ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "image", effects = true, className }) => {
867
+ const [, setTick] = (0, import_react6.useState)(0);
868
+ (0, import_react6.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
869
+ const [error, setError] = (0, import_react6.useState)(null);
870
+ const [renaming, setRenaming] = (0, import_react6.useState)(null);
871
+ const [menu, setMenu] = (0, import_react6.useState)(null);
872
+ const [drag, setDrag] = (0, import_react6.useState)(null);
873
+ const [psdNotes, setPsdNotes] = (0, import_react6.useState)([]);
874
+ const fileInput = (0, import_react6.useRef)(null);
685
875
  const psdTask = async (fn) => {
686
876
  try {
687
877
  setError(null);
@@ -690,9 +880,9 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
690
880
  setError(err instanceof Error ? err.message : String(err));
691
881
  }
692
882
  };
693
- const commitNext = (0, import_react5.useRef)(true);
883
+ const commitNext = (0, import_react6.useRef)(true);
694
884
  const state = controller.getState();
695
- const rows = (0, import_image_editor6.layerPanelRows)(state.layers, state.activeLayerId);
885
+ const rows = (0, import_image_editor7.layerPanelRows)(state.layers, state.activeLayerId);
696
886
  const active = controller.getActiveLayer();
697
887
  const attempt = (fn) => {
698
888
  try {
@@ -704,7 +894,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
704
894
  };
705
895
  const run = async (action) => {
706
896
  setMenu(null);
707
- setError(await (0, import_image_editor6.runLayerMenuAction)(controller, action));
897
+ setError(await (0, import_image_editor7.runLayerMenuAction)(controller, action));
708
898
  };
709
899
  const prop = (key, value) => attempt(() => {
710
900
  controller.setLayerProperties(active.id, { [key]: value }, commitNext.current);
@@ -722,20 +912,20 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
722
912
  if (!id) return;
723
913
  const rect = e.currentTarget.getBoundingClientRect();
724
914
  const fraction = rect.height ? (e.clientY - rect.top) / rect.height : 0.5;
725
- const placement = (0, import_image_editor6.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor6.dropZone)(fraction, row.layer.type === "group"));
915
+ const placement = (0, import_image_editor7.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor7.dropZone)(fraction, row.layer.type === "group"));
726
916
  if (placement) attempt(() => controller.moveLayer(id, placement));
727
917
  };
728
918
  const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
729
919
  const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
730
920
  const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
731
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
732
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
733
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
734
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
735
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
736
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
737
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
738
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
921
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
922
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
923
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
924
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
925
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
926
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
927
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
928
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
739
929
  "button",
740
930
  {
741
931
  type: "button",
@@ -750,39 +940,39 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
750
940
  children: "\u22EF"
751
941
  }
752
942
  ),
753
- psd && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
754
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, onClick: () => fileInput.current?.click(), children: "Open PSD\u2026" }),
755
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, onClick: () => psdTask(async () => (await (0, import_image_editor6.downloadPsd)(controller, psdFileName)).warnings), children: "Export PSD" }),
756
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
943
+ psd && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
944
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => fileInput.current?.click(), children: "Open PSD\u2026" }),
945
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => psdTask(async () => (await (0, import_image_editor7.downloadPsd)(controller, psdFileName)).warnings), children: "Export PSD" }),
946
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
757
947
  "input",
758
948
  {
759
949
  ref: fileInput,
760
950
  type: "file",
761
- accept: import_image_editor6.PSD_FILE_ACCEPT,
951
+ accept: import_image_editor7.PSD_FILE_ACCEPT,
762
952
  className: "hidden",
763
953
  "data-testid": "psd-file-input",
764
954
  "aria-label": "Open a PSD file",
765
955
  onChange: (e) => {
766
956
  const file = e.currentTarget.files?.[0];
767
957
  e.currentTarget.value = "";
768
- if (file) psdTask(() => (0, import_image_editor6.openPsdFile)(controller, file));
958
+ if (file) psdTask(() => (0, import_image_editor7.openPsdFile)(controller, file));
769
959
  }
770
960
  }
771
961
  )
772
962
  ] })
773
963
  ] }),
774
- psdNotes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("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: [
775
- psdNotes.map((n) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: n }, n)),
776
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "underline", onClick: () => setPsdNotes([]), children: "Dismiss" }) })
964
+ psdNotes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("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: [
965
+ psdNotes.map((n) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: n }, n)),
966
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "underline", onClick: () => setPsdNotes([]), children: "Dismiss" }) })
777
967
  ] }),
778
- active && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 items-center", "data-testid": "layer-properties", children: [
779
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
780
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
968
+ active && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 items-center", "data-testid": "layer-properties", children: [
969
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
970
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-slate-400", children: [
781
971
  "Opacity ",
782
972
  Math.round(active.opacity * 100),
783
973
  "%"
784
974
  ] }),
785
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
975
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
786
976
  "input",
787
977
  {
788
978
  type: "range",
@@ -796,13 +986,13 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
796
986
  }
797
987
  )
798
988
  ] }),
799
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
800
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
989
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
990
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-slate-400", children: [
801
991
  "Fill ",
802
992
  Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
803
993
  "%"
804
994
  ] }),
805
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
995
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
806
996
  "input",
807
997
  {
808
998
  type: "range",
@@ -817,7 +1007,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
817
1007
  }
818
1008
  )
819
1009
  ] }),
820
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1010
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
821
1011
  "select",
822
1012
  {
823
1013
  "aria-label": "Layer blend mode",
@@ -825,13 +1015,13 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
825
1015
  value: active.blend,
826
1016
  onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { blend: e.target.value })),
827
1017
  children: [
828
- active.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "pass-through", children: "Pass Through" }),
829
- import_image_editor6.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: m.id, children: m.label }, m.id))
1018
+ active.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "pass-through", children: "Pass Through" }),
1019
+ import_image_editor7.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: m.id, children: m.label }, m.id))
830
1020
  ]
831
1021
  }
832
1022
  ),
833
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
834
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1023
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
1024
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
835
1025
  "input",
836
1026
  {
837
1027
  type: "checkbox",
@@ -843,8 +1033,8 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
843
1033
  ),
844
1034
  "Clip to below"
845
1035
  ] }),
846
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1", children: [
847
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1036
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1", children: [
1037
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
848
1038
  "input",
849
1039
  {
850
1040
  type: "checkbox",
@@ -857,9 +1047,10 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
857
1047
  k
858
1048
  ] }, k)) })
859
1049
  ] }),
860
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
1050
+ effects && active && active.type !== "adjustment" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayerEffectsPanel, { controller, className: "border-t border-slate-800 pt-1.5" }),
1051
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
861
1052
  const { layer } = row;
862
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1053
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
863
1054
  "li",
864
1055
  {
865
1056
  role: "treeitem",
@@ -889,7 +1080,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
889
1080
  className: rowClass(row.active),
890
1081
  style: { paddingLeft: 6 + row.depth * 14 },
891
1082
  children: [
892
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1083
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
893
1084
  "button",
894
1085
  {
895
1086
  type: "button",
@@ -903,7 +1094,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
903
1094
  children: layer.visible ? "\u25CF" : "\u25CB"
904
1095
  }
905
1096
  ),
906
- layer.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1097
+ layer.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
907
1098
  "button",
908
1099
  {
909
1100
  type: "button",
@@ -916,8 +1107,8 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
916
1107
  children: layer.collapsed ? "\u25B8" : "\u25BE"
917
1108
  }
918
1109
  ),
919
- row.clipped && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
920
- layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1110
+ row.clipped && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
1111
+ layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
921
1112
  Thumbnail,
922
1113
  {
923
1114
  pixels: thumb(layer),
@@ -925,15 +1116,15 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
925
1116
  label: `${row.label} pixels`,
926
1117
  selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
927
1118
  }
928
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1119
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
929
1120
  "span",
930
1121
  {
931
1122
  className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
932
1123
  style: { width: thumbnailSize, height: thumbnailSize },
933
- children: (0, import_image_editor6.layerBadge)(layer)
1124
+ children: (0, import_image_editor7.layerBadge)(layer)
934
1125
  }
935
1126
  ),
936
- layer.mask && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1127
+ layer.mask && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
937
1128
  Thumbnail,
938
1129
  {
939
1130
  pixels: maskThumb(layer),
@@ -948,7 +1139,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
948
1139
  }
949
1140
  }
950
1141
  ),
951
- renaming === layer.id ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1142
+ renaming === layer.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
952
1143
  "input",
953
1144
  {
954
1145
  autoFocus: true,
@@ -965,7 +1156,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
965
1156
  if (e.key === "Escape") setRenaming(null);
966
1157
  }
967
1158
  }
968
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1159
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
969
1160
  "span",
970
1161
  {
971
1162
  className: `flex-1 min-w-0 truncate ${layer.visible ? "" : "text-slate-500"}`,
@@ -976,15 +1167,30 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
976
1167
  children: row.label
977
1168
  }
978
1169
  ),
979
- locked(layer) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
980
- layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-[9px] text-slate-500", children: layer.blend })
1170
+ (0, import_image_editor7.layerEffectsBadge)(layer) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1171
+ "button",
1172
+ {
1173
+ type: "button",
1174
+ "data-testid": "layer-fx-badge",
1175
+ "aria-label": (0, import_image_editor7.layerEffectsBadge)(layer) === "on" ? `Turn effects off for ${row.label}` : `Turn effects on for ${row.label}`,
1176
+ "aria-pressed": (0, import_image_editor7.layerEffectsBadge)(layer) === "on",
1177
+ className: `text-[9px] italic font-semibold ${(0, import_image_editor7.layerEffectsBadge)(layer) === "on" ? "text-indigo-300" : "text-slate-600 line-through"}`,
1178
+ onClick: (e) => {
1179
+ e.stopPropagation();
1180
+ attempt(() => controller.setLayerEffectsEnabled(layer.id, (0, import_image_editor7.layerEffectsBadge)(layer) !== "on"));
1181
+ },
1182
+ children: "fx"
1183
+ }
1184
+ ),
1185
+ locked(layer) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
1186
+ layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-[9px] text-slate-500", children: layer.blend })
981
1187
  ]
982
1188
  },
983
1189
  layer.id
984
1190
  );
985
1191
  }) }),
986
- error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
987
- menu && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1192
+ error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
1193
+ menu && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
988
1194
  "div",
989
1195
  {
990
1196
  role: "menu",
@@ -993,7 +1199,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
993
1199
  style: { left: menu.x, top: menu.y },
994
1200
  onClick: (e) => e.stopPropagation(),
995
1201
  onKeyDown: (e) => e.key === "Escape" && setMenu(null),
996
- children: (0, import_image_editor6.layerMenu)(controller).map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1202
+ children: (0, import_image_editor7.layerMenu)(controller).map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
997
1203
  "button",
998
1204
  {
999
1205
  type: "button",
@@ -1011,16 +1217,16 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1011
1217
  };
1012
1218
 
1013
1219
  // src/image-editor/BrushOptionsBar.tsx
1014
- var import_react6 = require("react");
1015
- var import_image_editor7 = require("@pixerate/editor/image-editor");
1016
- var import_jsx_runtime6 = require("react/jsx-runtime");
1220
+ var import_react7 = require("react");
1221
+ var import_image_editor8 = require("@pixerate/editor/image-editor");
1222
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1017
1223
  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"}`;
1018
1224
  var BrushOptionsBar = ({ controller, className }) => {
1019
- const [, setTick] = (0, import_react6.useState)(0);
1020
- (0, import_react6.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1021
- const [error, setError] = (0, import_react6.useState)(null);
1225
+ const [, setTick] = (0, import_react7.useState)(0);
1226
+ (0, import_react7.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1227
+ const [error, setError] = (0, import_react7.useState)(null);
1022
1228
  const state = controller.getState();
1023
- const { brush, foreground, background } = state.paint;
1229
+ const { brush, foreground, background, mixer, mixerLoad } = state.paint;
1024
1230
  const attempt = (fn) => {
1025
1231
  try {
1026
1232
  setError(null);
@@ -1029,8 +1235,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1029
1235
  setError(err instanceof Error ? err.message : String(err));
1030
1236
  }
1031
1237
  };
1032
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
1033
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor7.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1238
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
1239
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor8.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1034
1240
  "button",
1035
1241
  {
1036
1242
  type: "button",
@@ -1042,9 +1248,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1042
1248
  },
1043
1249
  t.id
1044
1250
  )) }),
1045
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
1046
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1", children: [
1047
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1251
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
1252
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1", children: [
1253
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1048
1254
  "input",
1049
1255
  {
1050
1256
  type: "color",
@@ -1054,10 +1260,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1054
1260
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1055
1261
  }
1056
1262
  ),
1057
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-400", children: "FG" })
1263
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", children: "FG" })
1058
1264
  ] }),
1059
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1", children: [
1060
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1265
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1", children: [
1266
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1061
1267
  "input",
1062
1268
  {
1063
1269
  type: "color",
@@ -1067,12 +1273,12 @@ var BrushOptionsBar = ({ controller, className }) => {
1067
1273
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1068
1274
  }
1069
1275
  ),
1070
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-400", children: "BG" })
1276
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", children: "BG" })
1071
1277
  ] }),
1072
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
1073
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
1278
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
1279
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
1074
1280
  ] }),
1075
- import_image_editor7.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1281
+ import_image_editor8.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1076
1282
  ControlSlider,
1077
1283
  {
1078
1284
  spec,
@@ -1081,9 +1287,65 @@ var BrushOptionsBar = ({ controller, className }) => {
1081
1287
  },
1082
1288
  spec.id
1083
1289
  )),
1084
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1085
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1086
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1290
+ state.activeTool === "mixer" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("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: [
1291
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [
1292
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1293
+ "span",
1294
+ {
1295
+ "aria-label": "Brush load",
1296
+ title: mixerLoad.reservoir ? `Loaded ${(0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
1297
+ className: "h-6 w-6 rounded border border-slate-700",
1298
+ style: { background: mixerLoad.reservoir ? (0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir) : "transparent" }
1299
+ }
1300
+ ),
1301
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
1302
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
1303
+ ] }),
1304
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: import_image_editor8.MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1305
+ "button",
1306
+ {
1307
+ type: "button",
1308
+ "aria-pressed": mixer.mixing === m.id,
1309
+ title: m.title,
1310
+ className: chip(mixer.mixing === m.id),
1311
+ onClick: () => controller.setPaintOptions({ mixer: { mixing: m.id } }),
1312
+ children: m.label
1313
+ },
1314
+ m.id
1315
+ )) }),
1316
+ import_image_editor8.MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
1317
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
1318
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1319
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1320
+ "input",
1321
+ {
1322
+ type: "checkbox",
1323
+ "aria-label": "Load the brush after each stroke",
1324
+ checked: mixer.loadEachStroke,
1325
+ onChange: (e) => controller.setPaintOptions({ mixer: { loadEachStroke: e.target.checked } }),
1326
+ className: "accent-indigo-500"
1327
+ }
1328
+ ),
1329
+ "Load each stroke"
1330
+ ] }),
1331
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1332
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1333
+ "input",
1334
+ {
1335
+ type: "checkbox",
1336
+ "aria-label": "Clean the brush after each stroke",
1337
+ checked: mixer.cleanEachStroke,
1338
+ onChange: (e) => controller.setPaintOptions({ mixer: { cleanEachStroke: e.target.checked } }),
1339
+ className: "accent-indigo-500"
1340
+ }
1341
+ ),
1342
+ "Clean each stroke"
1343
+ ] })
1344
+ ] })
1345
+ ] }),
1346
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1347
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1348
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1087
1349
  "input",
1088
1350
  {
1089
1351
  type: "checkbox",
@@ -1095,8 +1357,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1095
1357
  ),
1096
1358
  "Pressure size"
1097
1359
  ] }),
1098
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1099
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1360
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1361
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1100
1362
  "input",
1101
1363
  {
1102
1364
  type: "checkbox",
@@ -1109,18 +1371,18 @@ var BrushOptionsBar = ({ controller, className }) => {
1109
1371
  "Pressure opacity"
1110
1372
  ] })
1111
1373
  ] }),
1112
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex gap-1", children: [
1113
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1114
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
1374
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-1", children: [
1375
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1376
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
1115
1377
  ] }),
1116
- error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
1378
+ error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
1117
1379
  ] });
1118
1380
  };
1119
1381
 
1120
1382
  // src/image-editor/SelectionOptionsBar.tsx
1121
- var import_react7 = require("react");
1122
- var import_image_editor8 = require("@pixerate/editor/image-editor");
1123
- var import_jsx_runtime7 = require("react/jsx-runtime");
1383
+ var import_react8 = require("react");
1384
+ var import_image_editor9 = require("@pixerate/editor/image-editor");
1385
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1124
1386
  var MODIFY_OPS = [
1125
1387
  { op: "grow", label: "Grow" },
1126
1388
  { op: "shrink", label: "Shrink" },
@@ -1137,20 +1399,20 @@ var SelectionOptionsBar = ({
1137
1399
  quickMask,
1138
1400
  className = ""
1139
1401
  }) => {
1140
- const [radius, setRadius] = (0, import_react7.useState)(2);
1402
+ const [radius, setRadius] = (0, import_react8.useState)(2);
1141
1403
  const set = (patch) => onOptionsChange({ ...options, ...patch });
1142
1404
  const sel = selection === void 0 ? controller.getSelection() : selection;
1143
1405
  const qm = quickMask ?? Boolean(controller.getState().quickMask);
1144
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1145
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor8.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
1146
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor8.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor8.SELECTION_MODE_LABELS[m] }, m)) }),
1147
- options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2", children: [
1148
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex flex-col gap-1", children: [
1149
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1150
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Tolerance" }),
1151
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-mono", children: options.tolerance })
1406
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1407
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor9.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
1408
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor9.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor9.SELECTION_MODE_LABELS[m] }, m)) }),
1409
+ options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-2", children: [
1410
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
1411
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1412
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Tolerance" }),
1413
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-mono", children: options.tolerance })
1152
1414
  ] }),
1153
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1415
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1154
1416
  "input",
1155
1417
  {
1156
1418
  type: "range",
@@ -1164,17 +1426,17 @@ var SelectionOptionsBar = ({
1164
1426
  }
1165
1427
  )
1166
1428
  ] }),
1167
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1168
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
1429
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1430
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
1169
1431
  "Contiguous"
1170
1432
  ] }),
1171
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1172
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
1433
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1434
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
1173
1435
  "Sample adjusted image"
1174
1436
  ] }),
1175
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1437
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1176
1438
  "Sample",
1177
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1439
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1178
1440
  "select",
1179
1441
  {
1180
1442
  "aria-label": "Sample from",
@@ -1182,27 +1444,27 @@ var SelectionOptionsBar = ({
1182
1444
  onChange: (e) => set({ sample: e.target.value }),
1183
1445
  className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
1184
1446
  children: [
1185
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "composite", children: "All layers" }),
1186
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "active-layer", children: "Active layer" })
1447
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "composite", children: "All layers" }),
1448
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "active-layer", children: "Active layer" })
1187
1449
  ]
1188
1450
  }
1189
1451
  )
1190
1452
  ] })
1191
1453
  ] }),
1192
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1193
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
1454
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1455
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
1194
1456
  "Anti-alias"
1195
1457
  ] }),
1196
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1197
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
1198
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1199
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1200
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
1458
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1459
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
1460
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1461
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1462
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
1201
1463
  ] }),
1202
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1203
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
1464
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1465
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
1204
1466
  "Radius",
1205
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1467
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1206
1468
  "input",
1207
1469
  {
1208
1470
  type: "number",
@@ -1216,24 +1478,24 @@ var SelectionOptionsBar = ({
1216
1478
  }
1217
1479
  )
1218
1480
  ] }),
1219
- MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
1481
+ MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
1220
1482
  ] }),
1221
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor8.describeSelection)(sel) })
1483
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor9.describeSelection)(sel) })
1222
1484
  ] });
1223
1485
  };
1224
1486
 
1225
1487
  // src/image-editor/RefineEdgePanel.tsx
1226
- var import_react8 = require("react");
1227
- var import_image_editor9 = require("@pixerate/editor/image-editor");
1228
- var import_jsx_runtime8 = require("react/jsx-runtime");
1488
+ var import_react9 = require("react");
1489
+ var import_image_editor10 = require("@pixerate/editor/image-editor");
1490
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1229
1491
  var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
1230
- 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";
1492
+ 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";
1231
1493
  var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1232
- const [params, setParams] = (0, import_react8.useState)(DEFAULT_PARAMS);
1233
- const [busy, setBusy] = (0, import_react8.useState)(false);
1234
- const [error, setError] = (0, import_react8.useState)(null);
1235
- const [layerId, setLayerId] = (0, import_react8.useState)("");
1236
- const [newKind, setNewKind] = (0, import_react8.useState)("hueSaturation");
1494
+ const [params, setParams] = (0, import_react9.useState)(DEFAULT_PARAMS);
1495
+ const [busy, setBusy] = (0, import_react9.useState)(false);
1496
+ const [error, setError] = (0, import_react9.useState)(null);
1497
+ const [layerId, setLayerId] = (0, import_react9.useState)("");
1498
+ const [newKind, setNewKind] = (0, import_react9.useState)("hueSaturation");
1237
1499
  const sel = selection === void 0 ? controller.getSelection() : selection;
1238
1500
  const list = layers ?? controller.getAdjustmentLayers();
1239
1501
  const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
@@ -1248,17 +1510,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1248
1510
  setBusy(false);
1249
1511
  }
1250
1512
  };
1251
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1252
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1253
- import_image_editor9.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
1254
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1255
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: c.label }),
1256
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "font-mono", children: [
1513
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1514
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1515
+ import_image_editor10.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1", children: [
1516
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1517
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: c.label }),
1518
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
1257
1519
  params[c.id],
1258
1520
  c.unit
1259
1521
  ] })
1260
1522
  ] }),
1261
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1523
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1262
1524
  "input",
1263
1525
  {
1264
1526
  type: "range",
@@ -1272,67 +1534,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1272
1534
  }
1273
1535
  )
1274
1536
  ] }, c.id)),
1275
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1276
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
1537
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1538
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
1277
1539
  "Smart Radius"
1278
1540
  ] }),
1279
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-1", children: [
1280
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1281
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
1541
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-1", children: [
1542
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1543
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
1282
1544
  ] }),
1283
- error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
1284
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1285
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-1 items-center", children: [
1286
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1545
+ error && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
1546
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1547
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-1 items-center", children: [
1548
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1287
1549
  "select",
1288
1550
  {
1289
1551
  "aria-label": "New masked layer kind",
1290
1552
  value: newKind,
1291
1553
  onChange: (e) => setNewKind(e.target.value),
1292
1554
  className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1293
- children: import_image_editor9.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: k.kind, children: k.label }, k.kind))
1555
+ children: import_image_editor10.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: k.kind, children: k.label }, k.kind))
1294
1556
  }
1295
1557
  ),
1296
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1558
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1297
1559
  "button",
1298
1560
  {
1299
1561
  type: "button",
1300
- className: button,
1562
+ className: button2,
1301
1563
  disabled: !sel,
1302
- onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor9.layerMaskFromSelection)(sel) })),
1564
+ onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor10.layerMaskFromSelection)(sel) })),
1303
1565
  children: "New Masked Layer"
1304
1566
  }
1305
1567
  )
1306
1568
  ] }),
1307
- list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-2", children: [
1308
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1569
+ list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-2", children: [
1570
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1309
1571
  "select",
1310
1572
  {
1311
1573
  "aria-label": "Mask layer",
1312
1574
  value: target.id,
1313
1575
  onChange: (e) => setLayerId(e.target.value),
1314
1576
  className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1315
- children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("option", { value: l.id, children: [
1316
- l.name || (0, import_image_editor9.adjustmentKindLabel)(l.kind),
1577
+ children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("option", { value: l.id, children: [
1578
+ l.name || (0, import_image_editor10.adjustmentKindLabel)(l.kind),
1317
1579
  l.mask ? " (masked)" : ""
1318
1580
  ] }, l.id))
1319
1581
  }
1320
1582
  ),
1321
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1322
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1323
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1324
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
1583
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1584
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1586
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
1325
1587
  ] }),
1326
- target.mask && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1327
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
1328
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1329
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Density" }),
1330
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "font-mono", children: [
1588
+ target.mask && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1589
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1", children: [
1590
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1591
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Density" }),
1592
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
1331
1593
  Math.round((target.mask.density ?? 1) * 100),
1332
1594
  "%"
1333
1595
  ] })
1334
1596
  ] }),
1335
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1597
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1336
1598
  "input",
1337
1599
  {
1338
1600
  type: "range",
@@ -1346,15 +1608,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1346
1608
  }
1347
1609
  )
1348
1610
  ] }),
1349
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
1350
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1351
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Mask Feather" }),
1352
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "font-mono", children: [
1611
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1", children: [
1612
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1613
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Mask Feather" }),
1614
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
1353
1615
  target.mask.feather ?? 0,
1354
1616
  "px"
1355
1617
  ] })
1356
1618
  ] }),
1357
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1619
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1358
1620
  "input",
1359
1621
  {
1360
1622
  type: "range",
@@ -1374,7 +1636,7 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1374
1636
  };
1375
1637
 
1376
1638
  // src/image-editor/ImageEditor.tsx
1377
- var import_jsx_runtime9 = require("react/jsx-runtime");
1639
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1378
1640
  var ImageEditor = ({
1379
1641
  editor: externalEditor,
1380
1642
  src,
@@ -1389,35 +1651,35 @@ var ImageEditor = ({
1389
1651
  const internalEditor = useImageEditor({ image: src });
1390
1652
  const editor = externalEditor || internalEditor;
1391
1653
  const { state, controller } = editor;
1392
- const legacyProcess = (0, import_image_editor10.normalizeProcessVersion)(state.adjustments.process) < import_image_editor10.LATEST_PROCESS_VERSION;
1393
- const canvasRef = (0, import_react9.useRef)(null);
1394
- const containerRef = (0, import_react9.useRef)(null);
1395
- const [activeTab, setActiveTab] = (0, import_react9.useState)("crop");
1396
- const [activeCropRatio, setActiveCropRatio] = (0, import_react9.useState)(null);
1397
- const [selectionOptions, setSelectionOptions] = (0, import_react9.useState)(import_image_editor10.DEFAULT_SELECTION_TOOL_OPTIONS);
1398
- const selectionOptionsRef = (0, import_react9.useRef)(selectionOptions);
1654
+ const legacyProcess = (0, import_image_editor11.normalizeProcessVersion)(state.adjustments.process) < import_image_editor11.LATEST_PROCESS_VERSION;
1655
+ const canvasRef = (0, import_react10.useRef)(null);
1656
+ const containerRef = (0, import_react10.useRef)(null);
1657
+ const [activeTab, setActiveTab] = (0, import_react10.useState)("crop");
1658
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react10.useState)(null);
1659
+ const [selectionOptions, setSelectionOptions] = (0, import_react10.useState)(import_image_editor11.DEFAULT_SELECTION_TOOL_OPTIONS);
1660
+ const selectionOptionsRef = (0, import_react10.useRef)(selectionOptions);
1399
1661
  selectionOptionsRef.current = selectionOptions;
1400
- const selectionGestureRef = (0, import_react9.useRef)(null);
1662
+ const selectionGestureRef = (0, import_react10.useRef)(null);
1401
1663
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
1402
- selectionGestureRef.current = new import_image_editor10.SelectionGesture(controller, () => selectionOptionsRef.current);
1664
+ selectionGestureRef.current = new import_image_editor11.SelectionGesture(controller, () => selectionOptionsRef.current);
1403
1665
  }
1404
- const selectionDraftRef = (0, import_react9.useRef)(null);
1405
- const [selectionError, setSelectionError] = (0, import_react9.useState)(null);
1406
- const paintGestureRef = (0, import_react9.useRef)(null);
1407
- const paintControllerRef = (0, import_react9.useRef)(controller);
1666
+ const selectionDraftRef = (0, import_react10.useRef)(null);
1667
+ const [selectionError, setSelectionError] = (0, import_react10.useState)(null);
1668
+ const paintGestureRef = (0, import_react10.useRef)(null);
1669
+ const paintControllerRef = (0, import_react10.useRef)(controller);
1408
1670
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
1409
- paintGestureRef.current = new import_image_editor10.PaintGesture(controller);
1671
+ paintGestureRef.current = new import_image_editor11.PaintGesture(controller);
1410
1672
  paintControllerRef.current = controller;
1411
1673
  }
1412
- const brushCursorRef = (0, import_react9.useRef)(null);
1413
- const [paintError, setPaintError] = (0, import_react9.useState)(null);
1414
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react9.useState)("");
1415
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react9.useState)("annotations");
1416
- const [isRemovingBg, setIsRemovingBg] = (0, import_react9.useState)(false);
1417
- const [isInpainting, setIsInpainting] = (0, import_react9.useState)(false);
1418
- const [aiError, setAiError] = (0, import_react9.useState)(null);
1419
- const [aiSuccess, setAiSuccess] = (0, import_react9.useState)(null);
1420
- const [aiTarget, setAiTarget] = (0, import_react9.useState)("auto");
1674
+ const brushCursorRef = (0, import_react10.useRef)(null);
1675
+ const [paintError, setPaintError] = (0, import_react10.useState)(null);
1676
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react10.useState)("");
1677
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react10.useState)("annotations");
1678
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react10.useState)(false);
1679
+ const [isInpainting, setIsInpainting] = (0, import_react10.useState)(false);
1680
+ const [aiError, setAiError] = (0, import_react10.useState)(null);
1681
+ const [aiSuccess, setAiSuccess] = (0, import_react10.useState)(null);
1682
+ const [aiTarget, setAiTarget] = (0, import_react10.useState)("auto");
1421
1683
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
1422
1684
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
1423
1685
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -1480,18 +1742,18 @@ var ImageEditor = ({
1480
1742
  setIsInpainting(false);
1481
1743
  }
1482
1744
  };
1483
- const [activeColor, setActiveColor] = (0, import_react9.useState)("#ef4444");
1484
- const [strokeWidth, setStrokeWidth] = (0, import_react9.useState)(3);
1485
- const [fontSize, setFontSize] = (0, import_react9.useState)(24);
1486
- const [textInput, setTextInput] = (0, import_react9.useState)("");
1487
- const draftAnnotationRef = (0, import_react9.useRef)(null);
1488
- const draftCropRef = (0, import_react9.useRef)(null);
1489
- const cropDragInfoRef = (0, import_react9.useRef)(null);
1490
- const annotationDragInfoRef = (0, import_react9.useRef)(null);
1491
- const isDrawingRef = (0, import_react9.useRef)(false);
1492
- const currentPathRef = (0, import_react9.useRef)([]);
1493
- const dragStartPointRef = (0, import_react9.useRef)(null);
1494
- const renderCanvas = (0, import_react9.useCallback)(
1745
+ const [activeColor, setActiveColor] = (0, import_react10.useState)("#ef4444");
1746
+ const [strokeWidth, setStrokeWidth] = (0, import_react10.useState)(3);
1747
+ const [fontSize, setFontSize] = (0, import_react10.useState)(24);
1748
+ const [textInput, setTextInput] = (0, import_react10.useState)("");
1749
+ const draftAnnotationRef = (0, import_react10.useRef)(null);
1750
+ const draftCropRef = (0, import_react10.useRef)(null);
1751
+ const cropDragInfoRef = (0, import_react10.useRef)(null);
1752
+ const annotationDragInfoRef = (0, import_react10.useRef)(null);
1753
+ const isDrawingRef = (0, import_react10.useRef)(false);
1754
+ const currentPathRef = (0, import_react10.useRef)([]);
1755
+ const dragStartPointRef = (0, import_react10.useRef)(null);
1756
+ const renderCanvas = (0, import_react10.useCallback)(
1495
1757
  async (draftAnnotation, draftCrop) => {
1496
1758
  const canvas = canvasRef.current;
1497
1759
  const container = containerRef.current;
@@ -1512,7 +1774,7 @@ var ImageEditor = ({
1512
1774
  },
1513
1775
  [controller, activeTab]
1514
1776
  );
1515
- (0, import_react9.useEffect)(() => {
1777
+ (0, import_react10.useEffect)(() => {
1516
1778
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
1517
1779
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
1518
1780
  const animId = raf(() => {
@@ -1520,12 +1782,12 @@ var ImageEditor = ({
1520
1782
  });
1521
1783
  return () => caf(animId);
1522
1784
  }, [renderCanvas, state]);
1523
- (0, import_react9.useEffect)(() => {
1785
+ (0, import_react10.useEffect)(() => {
1524
1786
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
1525
1787
  editor.setTool("crop");
1526
1788
  }
1527
1789
  }, [activeTab, editor]);
1528
- (0, import_react9.useEffect)(() => {
1790
+ (0, import_react10.useEffect)(() => {
1529
1791
  const container = containerRef.current;
1530
1792
  if (!container) return;
1531
1793
  if (typeof ResizeObserver !== "undefined") {
@@ -1561,8 +1823,8 @@ var ImageEditor = ({
1561
1823
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
1562
1824
  const s = controller.getState();
1563
1825
  return list.map((ev) => ({
1564
- ...(0, import_image_editor10.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
1565
- pressure: (0, import_image_editor10.pointerPressure)(ev)
1826
+ ...(0, import_image_editor11.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
1827
+ pressure: (0, import_image_editor11.pointerPressure)(ev)
1566
1828
  }));
1567
1829
  };
1568
1830
  const handlePaintPointerDown = (e) => {
@@ -1590,10 +1852,10 @@ var ImageEditor = ({
1590
1852
  if (g.error) setPaintError(g.error);
1591
1853
  }
1592
1854
  };
1593
- (0, import_react9.useEffect)(() => {
1855
+ (0, import_react10.useEffect)(() => {
1594
1856
  if (activeTab !== "paint" || typeof window === "undefined") return;
1595
1857
  const onKey = (e) => {
1596
- if ((0, import_image_editor10.handlePaintShortcut)(controller, e)) e.preventDefault();
1858
+ if ((0, import_image_editor11.handlePaintShortcut)(controller, e)) e.preventDefault();
1597
1859
  };
1598
1860
  window.addEventListener("keydown", onKey);
1599
1861
  return () => window.removeEventListener("keydown", onKey);
@@ -1604,7 +1866,7 @@ var ImageEditor = ({
1604
1866
  const canvasPt = getCanvasEventPoint(e);
1605
1867
  if (activeTab === "select") {
1606
1868
  const gesture = selectionGestureRef.current;
1607
- const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1869
+ const imgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1608
1870
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
1609
1871
  return;
1610
1872
  }
@@ -1615,8 +1877,8 @@ var ImageEditor = ({
1615
1877
  width: state.imageDimensions.width,
1616
1878
  height: state.imageDimensions.height
1617
1879
  };
1618
- const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1619
- const startImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
1880
+ const handle = (0, import_image_editor11.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1881
+ const startImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
1620
1882
  if (handle) {
1621
1883
  cropDragInfoRef.current = {
1622
1884
  handle,
@@ -1635,12 +1897,12 @@ var ImageEditor = ({
1635
1897
  return;
1636
1898
  }
1637
1899
  if (activeTab === "annotate") {
1638
- const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1900
+ const imgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1639
1901
  dragStartPointRef.current = imgPt;
1640
1902
  if (state.activeTool === "select") {
1641
1903
  for (let i = state.annotations.length - 1; i >= 0; i--) {
1642
1904
  const ann = state.annotations[i];
1643
- if ((0, import_image_editor10.hitTestAnnotation)(imgPt, ann)) {
1905
+ if ((0, import_image_editor11.hitTestAnnotation)(imgPt, ann)) {
1644
1906
  editor.selectAnnotation(ann.id);
1645
1907
  annotationDragInfoRef.current = {
1646
1908
  annId: ann.id,
@@ -1676,7 +1938,7 @@ var ImageEditor = ({
1676
1938
  const canvasPt = getCanvasEventPoint(e);
1677
1939
  if (activeTab === "select") {
1678
1940
  const gesture = selectionGestureRef.current;
1679
- if (gesture.active && gesture.move((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
1941
+ if (gesture.active && gesture.move((0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
1680
1942
  selectionDraftRef.current = gesture.draftPath;
1681
1943
  renderCanvas();
1682
1944
  }
@@ -1685,7 +1947,7 @@ var ImageEditor = ({
1685
1947
  if (activeTab === "crop") {
1686
1948
  const drag = cropDragInfoRef.current;
1687
1949
  if (drag) {
1688
- const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
1950
+ const currentImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
1689
1951
  let newCrop;
1690
1952
  if (drag.handle === "new") {
1691
1953
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -1699,7 +1961,7 @@ var ImageEditor = ({
1699
1961
  height: Math.round(Math.max(20, maxY - minY))
1700
1962
  };
1701
1963
  } else {
1702
- newCrop = (0, import_image_editor10.calculateCropDrag)(
1964
+ newCrop = (0, import_image_editor11.calculateCropDrag)(
1703
1965
  drag.startCrop,
1704
1966
  drag.handle,
1705
1967
  drag.startImgPt,
@@ -1719,15 +1981,15 @@ var ImageEditor = ({
1719
1981
  width: state.imageDimensions.width,
1720
1982
  height: state.imageDimensions.height
1721
1983
  };
1722
- const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1723
- canvas.style.cursor = (0, import_image_editor10.getCropCursor)(handle, state.transform);
1984
+ const handle = (0, import_image_editor11.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1985
+ canvas.style.cursor = (0, import_image_editor11.getCropCursor)(handle, state.transform);
1724
1986
  }
1725
1987
  return;
1726
1988
  }
1727
1989
  if (activeTab === "annotate") {
1728
1990
  if (annotationDragInfoRef.current) {
1729
1991
  const drag = annotationDragInfoRef.current;
1730
- const currentImgPt2 = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1992
+ const currentImgPt2 = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1731
1993
  const dx = currentImgPt2.x - drag.startImgPt.x;
1732
1994
  const dy = currentImgPt2.y - drag.startImgPt.y;
1733
1995
  editor.updateAnnotation(drag.annId, {
@@ -1739,10 +2001,10 @@ var ImageEditor = ({
1739
2001
  const startPt = dragStartPointRef.current;
1740
2002
  if (!startPt) {
1741
2003
  if (state.activeTool === "select") {
1742
- const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2004
+ const imgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1743
2005
  let hovered = false;
1744
2006
  for (let i = state.annotations.length - 1; i >= 0; i--) {
1745
- if ((0, import_image_editor10.hitTestAnnotation)(imgPt, state.annotations[i])) {
2007
+ if ((0, import_image_editor11.hitTestAnnotation)(imgPt, state.annotations[i])) {
1746
2008
  hovered = true;
1747
2009
  break;
1748
2010
  }
@@ -1753,7 +2015,7 @@ var ImageEditor = ({
1753
2015
  }
1754
2016
  return;
1755
2017
  }
1756
- const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2018
+ const currentImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1757
2019
  if (state.activeTool === "pen" && isDrawingRef.current) {
1758
2020
  currentPathRef.current.push(currentImgPt);
1759
2021
  const draft = {
@@ -1833,7 +2095,7 @@ var ImageEditor = ({
1833
2095
  if (activeTab === "select") {
1834
2096
  const gesture = selectionGestureRef.current;
1835
2097
  if (gesture.active) {
1836
- gesture.end((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
2098
+ gesture.end((0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
1837
2099
  selectionDraftRef.current = null;
1838
2100
  renderCanvas();
1839
2101
  }
@@ -1857,7 +2119,7 @@ var ImageEditor = ({
1857
2119
  }
1858
2120
  const startPt = dragStartPointRef.current;
1859
2121
  if (startPt) {
1860
- const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2122
+ const currentImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
1861
2123
  if (state.activeTool === "pen" && isDrawingRef.current) {
1862
2124
  if (currentPathRef.current.length > 1) {
1863
2125
  editor.addAnnotation({
@@ -1953,15 +2215,15 @@ var ImageEditor = ({
1953
2215
  link.click();
1954
2216
  }
1955
2217
  };
1956
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2218
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1957
2219
  "div",
1958
2220
  {
1959
2221
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
1960
2222
  style,
1961
2223
  children: [
1962
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
1963
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
1964
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2224
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
2225
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2226
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1965
2227
  "button",
1966
2228
  {
1967
2229
  type: "button",
@@ -1973,7 +2235,7 @@ var ImageEditor = ({
1973
2235
  children: "Transform & Crop"
1974
2236
  }
1975
2237
  ),
1976
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2238
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1977
2239
  "button",
1978
2240
  {
1979
2241
  type: "button",
@@ -1985,7 +2247,7 @@ var ImageEditor = ({
1985
2247
  children: "Adjustments"
1986
2248
  }
1987
2249
  ),
1988
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2250
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1989
2251
  "button",
1990
2252
  {
1991
2253
  type: "button",
@@ -1997,7 +2259,7 @@ var ImageEditor = ({
1997
2259
  children: "Layers"
1998
2260
  }
1999
2261
  ),
2000
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2262
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2001
2263
  "button",
2002
2264
  {
2003
2265
  type: "button",
@@ -2009,7 +2271,7 @@ var ImageEditor = ({
2009
2271
  children: "Paint"
2010
2272
  }
2011
2273
  ),
2012
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2274
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2013
2275
  "button",
2014
2276
  {
2015
2277
  type: "button",
@@ -2021,7 +2283,7 @@ var ImageEditor = ({
2021
2283
  children: "Select & Mask"
2022
2284
  }
2023
2285
  ),
2024
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2286
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2025
2287
  "button",
2026
2288
  {
2027
2289
  type: "button",
@@ -2033,7 +2295,7 @@ var ImageEditor = ({
2033
2295
  children: "Annotations"
2034
2296
  }
2035
2297
  ),
2036
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2298
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2037
2299
  "button",
2038
2300
  {
2039
2301
  type: "button",
@@ -2045,7 +2307,7 @@ var ImageEditor = ({
2045
2307
  children: "Depth Mask"
2046
2308
  }
2047
2309
  ),
2048
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2310
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2049
2311
  "button",
2050
2312
  {
2051
2313
  type: "button",
@@ -2055,14 +2317,14 @@ var ImageEditor = ({
2055
2317
  },
2056
2318
  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"}`,
2057
2319
  children: [
2058
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2320
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2059
2321
  "AI Tools"
2060
2322
  ]
2061
2323
  }
2062
2324
  )
2063
2325
  ] }),
2064
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
2065
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2326
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
2327
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2066
2328
  "button",
2067
2329
  {
2068
2330
  type: "button",
@@ -2073,7 +2335,7 @@ var ImageEditor = ({
2073
2335
  children: "\u21A9"
2074
2336
  }
2075
2337
  ),
2076
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2338
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2077
2339
  "button",
2078
2340
  {
2079
2341
  type: "button",
@@ -2084,7 +2346,7 @@ var ImageEditor = ({
2084
2346
  children: "\u21AA"
2085
2347
  }
2086
2348
  ),
2087
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2349
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2088
2350
  "button",
2089
2351
  {
2090
2352
  type: "button",
@@ -2093,8 +2355,8 @@ var ImageEditor = ({
2093
2355
  children: "Reset"
2094
2356
  }
2095
2357
  ),
2096
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2097
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2358
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2359
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2098
2360
  "button",
2099
2361
  {
2100
2362
  type: "button",
@@ -2104,11 +2366,11 @@ var ImageEditor = ({
2104
2366
  children: "-"
2105
2367
  }
2106
2368
  ),
2107
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2369
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2108
2370
  Math.round(state.zoom * 100),
2109
2371
  "%"
2110
2372
  ] }),
2111
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2373
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2112
2374
  "button",
2113
2375
  {
2114
2376
  type: "button",
@@ -2118,8 +2380,8 @@ var ImageEditor = ({
2118
2380
  children: "+"
2119
2381
  }
2120
2382
  ),
2121
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2122
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2383
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2384
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2123
2385
  "button",
2124
2386
  {
2125
2387
  type: "button",
@@ -2130,7 +2392,7 @@ var ImageEditor = ({
2130
2392
  children: "Hold Compare"
2131
2393
  }
2132
2394
  ),
2133
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2395
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2134
2396
  "button",
2135
2397
  {
2136
2398
  type: "button",
@@ -2141,13 +2403,13 @@ var ImageEditor = ({
2141
2403
  )
2142
2404
  ] })
2143
2405
  ] }),
2144
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2145
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2406
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2407
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2146
2408
  "div",
2147
2409
  {
2148
2410
  ref: containerRef,
2149
2411
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
2150
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2412
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2151
2413
  "canvas",
2152
2414
  {
2153
2415
  ref: canvasRef,
@@ -2165,11 +2427,11 @@ var ImageEditor = ({
2165
2427
  )
2166
2428
  }
2167
2429
  ),
2168
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
2169
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2170
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2171
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
2172
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2430
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
2431
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2432
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2433
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
2434
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2173
2435
  "button",
2174
2436
  {
2175
2437
  type: "button",
@@ -2181,7 +2443,7 @@ var ImageEditor = ({
2181
2443
  children: "Freeform"
2182
2444
  }
2183
2445
  ),
2184
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2446
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2185
2447
  "button",
2186
2448
  {
2187
2449
  type: "button",
@@ -2193,7 +2455,7 @@ var ImageEditor = ({
2193
2455
  children: "1:1 Square"
2194
2456
  }
2195
2457
  ),
2196
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2458
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2197
2459
  "button",
2198
2460
  {
2199
2461
  type: "button",
@@ -2205,7 +2467,7 @@ var ImageEditor = ({
2205
2467
  children: "4:3 Standard"
2206
2468
  }
2207
2469
  ),
2208
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2470
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2209
2471
  "button",
2210
2472
  {
2211
2473
  type: "button",
@@ -2217,7 +2479,7 @@ var ImageEditor = ({
2217
2479
  children: "16:9 Wide"
2218
2480
  }
2219
2481
  ),
2220
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2482
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2221
2483
  "button",
2222
2484
  {
2223
2485
  type: "button",
@@ -2229,7 +2491,7 @@ var ImageEditor = ({
2229
2491
  children: "3:2 Photo"
2230
2492
  }
2231
2493
  ),
2232
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2494
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2233
2495
  "button",
2234
2496
  {
2235
2497
  type: "button",
@@ -2242,10 +2504,10 @@ var ImageEditor = ({
2242
2504
  }
2243
2505
  )
2244
2506
  ] }),
2245
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2246
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2247
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
2248
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2507
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2508
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2509
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
2510
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2249
2511
  "button",
2250
2512
  {
2251
2513
  type: "button",
@@ -2254,7 +2516,7 @@ var ImageEditor = ({
2254
2516
  children: "Rotate -90\xB0"
2255
2517
  }
2256
2518
  ),
2257
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2519
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2258
2520
  "button",
2259
2521
  {
2260
2522
  type: "button",
@@ -2263,7 +2525,7 @@ var ImageEditor = ({
2263
2525
  children: "Rotate +90\xB0"
2264
2526
  }
2265
2527
  ),
2266
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2528
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2267
2529
  "button",
2268
2530
  {
2269
2531
  type: "button",
@@ -2272,7 +2534,7 @@ var ImageEditor = ({
2272
2534
  children: "Flip Horizontal"
2273
2535
  }
2274
2536
  ),
2275
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2537
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2276
2538
  "button",
2277
2539
  {
2278
2540
  type: "button",
@@ -2283,10 +2545,10 @@ var ImageEditor = ({
2283
2545
  )
2284
2546
  ] })
2285
2547
  ] }),
2286
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2287
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2288
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2289
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2548
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2549
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
2550
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2551
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2290
2552
  "button",
2291
2553
  {
2292
2554
  type: "button",
@@ -2296,25 +2558,25 @@ var ImageEditor = ({
2296
2558
  }
2297
2559
  )
2298
2560
  ] }),
2299
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Histogram, { histogram: editor.histogram }),
2300
- import_image_editor10.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react9.default.Fragment, { children: [
2301
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2561
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Histogram, { histogram: editor.histogram }),
2562
+ import_image_editor11.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react10.default.Fragment, { children: [
2563
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2302
2564
  ControlSlider,
2303
2565
  {
2304
2566
  spec,
2305
- value: (0, import_image_editor10.readAdjustmentControls)(state.adjustments)[spec.id],
2567
+ value: (0, import_image_editor11.readAdjustmentControls)(state.adjustments)[spec.id],
2306
2568
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
2307
2569
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
2308
2570
  }
2309
2571
  ),
2310
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2572
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2311
2573
  "div",
2312
2574
  {
2313
2575
  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",
2314
2576
  "data-testid": "image-editor-process-notice",
2315
2577
  children: [
2316
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
2317
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2578
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
2579
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2318
2580
  "button",
2319
2581
  {
2320
2582
  type: "button",
@@ -2327,7 +2589,7 @@ var ImageEditor = ({
2327
2589
  }
2328
2590
  )
2329
2591
  ] }, spec.id)),
2330
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2592
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2331
2593
  AdjustmentLayersPanel,
2332
2594
  {
2333
2595
  controller,
@@ -2336,19 +2598,19 @@ var ImageEditor = ({
2336
2598
  }
2337
2599
  ) })
2338
2600
  ] }),
2339
- activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2340
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
2341
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LayersPanel, { controller })
2601
+ activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2602
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
2603
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LayersPanel, { controller })
2342
2604
  ] }),
2343
- activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2344
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
2345
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BrushOptionsBar, { controller }),
2346
- paintError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
2347
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LayersPanel, { controller }) })
2605
+ activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2606
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
2607
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BrushOptionsBar, { controller }),
2608
+ paintError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
2609
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LayersPanel, { controller }) })
2348
2610
  ] }),
2349
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2350
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2351
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2611
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2612
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2613
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2352
2614
  "button",
2353
2615
  {
2354
2616
  type: "button",
@@ -2358,9 +2620,9 @@ var ImageEditor = ({
2358
2620
  },
2359
2621
  t
2360
2622
  )) }),
2361
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
2362
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-slate-400", children: "Color:" }),
2363
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2623
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
2624
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { className: "text-slate-400", children: "Color:" }),
2625
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2364
2626
  "input",
2365
2627
  {
2366
2628
  type: "color",
@@ -2369,15 +2631,15 @@ var ImageEditor = ({
2369
2631
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
2370
2632
  }
2371
2633
  ),
2372
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 ml-2", children: [
2373
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2374
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Width:" }),
2375
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
2634
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 ml-2", children: [
2635
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2636
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Width:" }),
2637
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
2376
2638
  strokeWidth,
2377
2639
  "px"
2378
2640
  ] })
2379
2641
  ] }),
2380
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2642
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2381
2643
  "input",
2382
2644
  {
2383
2645
  type: "range",
@@ -2390,10 +2652,10 @@ var ImageEditor = ({
2390
2652
  )
2391
2653
  ] })
2392
2654
  ] }),
2393
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2394
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2395
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-2", children: [
2396
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2655
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2656
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2657
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-2", children: [
2658
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2397
2659
  "input",
2398
2660
  {
2399
2661
  type: "text",
@@ -2404,7 +2666,7 @@ var ImageEditor = ({
2404
2666
  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"
2405
2667
  }
2406
2668
  ),
2407
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2669
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2408
2670
  "button",
2409
2671
  {
2410
2672
  type: "button",
@@ -2414,14 +2676,14 @@ var ImageEditor = ({
2414
2676
  }
2415
2677
  )
2416
2678
  ] }),
2417
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
2418
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Font Size:" }),
2419
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
2679
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
2680
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Font Size:" }),
2681
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
2420
2682
  fontSize,
2421
2683
  "px"
2422
2684
  ] })
2423
2685
  ] }),
2424
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2686
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2425
2687
  "input",
2426
2688
  {
2427
2689
  type: "range",
@@ -2432,14 +2694,14 @@ var ImageEditor = ({
2432
2694
  className: "w-full accent-indigo-500"
2433
2695
  }
2434
2696
  ),
2435
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2436
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2437
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "text-slate-400", children: [
2697
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2698
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
2699
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-slate-400", children: [
2438
2700
  "Layers (",
2439
2701
  state.annotations.length,
2440
2702
  ")"
2441
2703
  ] }),
2442
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2704
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2443
2705
  "button",
2444
2706
  {
2445
2707
  type: "button",
@@ -2448,7 +2710,7 @@ var ImageEditor = ({
2448
2710
  children: "Delete Selected"
2449
2711
  }
2450
2712
  ),
2451
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2713
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2452
2714
  "button",
2453
2715
  {
2454
2716
  type: "button",
@@ -2459,10 +2721,10 @@ var ImageEditor = ({
2459
2721
  )
2460
2722
  ] })
2461
2723
  ] }),
2462
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2463
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2464
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2465
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2724
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2725
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
2726
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2727
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2466
2728
  "button",
2467
2729
  {
2468
2730
  type: "button",
@@ -2472,8 +2734,8 @@ var ImageEditor = ({
2472
2734
  }
2473
2735
  )
2474
2736
  ] }),
2475
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2476
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2737
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2738
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2477
2739
  "input",
2478
2740
  {
2479
2741
  type: "checkbox",
@@ -2482,12 +2744,12 @@ var ImageEditor = ({
2482
2744
  className: "rounded accent-indigo-500"
2483
2745
  }
2484
2746
  ),
2485
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Enable Depth / Alpha Mask" })
2747
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Enable Depth / Alpha Mask" })
2486
2748
  ] }),
2487
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2488
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2489
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
2490
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2749
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2750
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2751
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
2752
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2491
2753
  "input",
2492
2754
  {
2493
2755
  type: "text",
@@ -2498,8 +2760,8 @@ var ImageEditor = ({
2498
2760
  }
2499
2761
  )
2500
2762
  ] }),
2501
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-2", children: [
2502
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2763
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-2", children: [
2764
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2503
2765
  "button",
2504
2766
  {
2505
2767
  type: "button",
@@ -2508,7 +2770,7 @@ var ImageEditor = ({
2508
2770
  children: "Threshold Mode"
2509
2771
  }
2510
2772
  ),
2511
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2773
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2512
2774
  "button",
2513
2775
  {
2514
2776
  type: "button",
@@ -2518,12 +2780,12 @@ var ImageEditor = ({
2518
2780
  }
2519
2781
  )
2520
2782
  ] }),
2521
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2522
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2523
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Depth Start (Lower):" }),
2524
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
2783
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2784
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2785
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Depth Start (Lower):" }),
2786
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
2525
2787
  ] }),
2526
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2788
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2527
2789
  "input",
2528
2790
  {
2529
2791
  type: "range",
@@ -2537,12 +2799,12 @@ var ImageEditor = ({
2537
2799
  }
2538
2800
  )
2539
2801
  ] }),
2540
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2541
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2542
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Depth Stop (Upper):" }),
2543
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
2802
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2803
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2804
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Depth Stop (Upper):" }),
2805
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
2544
2806
  ] }),
2545
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2807
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2546
2808
  "input",
2547
2809
  {
2548
2810
  type: "range",
@@ -2556,12 +2818,12 @@ var ImageEditor = ({
2556
2818
  }
2557
2819
  )
2558
2820
  ] }),
2559
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2560
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2561
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Softness:" }),
2562
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
2821
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2822
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2823
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Softness:" }),
2824
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
2563
2825
  ] }),
2564
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2826
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2565
2827
  "input",
2566
2828
  {
2567
2829
  type: "range",
@@ -2573,8 +2835,8 @@ var ImageEditor = ({
2573
2835
  }
2574
2836
  )
2575
2837
  ] }),
2576
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
2577
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2838
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
2839
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2578
2840
  "input",
2579
2841
  {
2580
2842
  type: "checkbox",
@@ -2583,12 +2845,12 @@ var ImageEditor = ({
2583
2845
  className: "rounded accent-indigo-500"
2584
2846
  }
2585
2847
  ),
2586
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Invert Mask" })
2848
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Invert Mask" })
2587
2849
  ] })
2588
2850
  ] })
2589
2851
  ] }),
2590
- activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2591
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2852
+ activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2853
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2592
2854
  SelectionOptionsBar,
2593
2855
  {
2594
2856
  controller,
@@ -2598,13 +2860,13 @@ var ImageEditor = ({
2598
2860
  quickMask: Boolean(state.quickMask)
2599
2861
  }
2600
2862
  ),
2601
- selectionError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
2602
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
2863
+ selectionError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
2864
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
2603
2865
  ] }),
2604
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2605
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
2606
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Results go to" }),
2607
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2866
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2867
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
2868
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Results go to" }),
2869
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2608
2870
  "select",
2609
2871
  {
2610
2872
  "aria-label": "AI result target",
@@ -2612,54 +2874,54 @@ var ImageEditor = ({
2612
2874
  onChange: (e) => setAiTarget(e.target.value),
2613
2875
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
2614
2876
  children: [
2615
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
2616
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
2617
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "replace", children: "Replace image" })
2877
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
2878
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
2879
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "replace", children: "Replace image" })
2618
2880
  ]
2619
2881
  }
2620
2882
  )
2621
2883
  ] }),
2622
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2623
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2624
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2625
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
2884
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2885
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
2886
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2887
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
2626
2888
  "Background Removal"
2627
2889
  ] }),
2628
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
2890
+ isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
2629
2891
  ] }),
2630
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
2631
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2892
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
2893
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2632
2894
  "button",
2633
2895
  {
2634
2896
  type: "button",
2635
2897
  onClick: handleRemoveBackground,
2636
2898
  disabled: isRemovingBg || isInpainting,
2637
2899
  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",
2638
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2639
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2900
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2901
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2640
2902
  "Removing Background..."
2641
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2642
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2903
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2904
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2643
2905
  "Remove Background"
2644
2906
  ] })
2645
2907
  }
2646
2908
  )
2647
2909
  ] }),
2648
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2649
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2650
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2651
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2652
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
2653
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "m14 7 3 3" })
2910
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2911
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
2912
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2913
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2914
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
2915
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m14 7 3 3" })
2654
2916
  ] }),
2655
2917
  "Generative Inpainting"
2656
2918
  ] }),
2657
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
2919
+ isInpainting && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
2658
2920
  ] }),
2659
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
2660
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
2661
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
2662
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2921
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
2922
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-1", children: [
2923
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
2924
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2663
2925
  "textarea",
2664
2926
  {
2665
2927
  id: "ai-inpaint-prompt-react",
@@ -2671,10 +2933,10 @@ var ImageEditor = ({
2671
2933
  }
2672
2934
  )
2673
2935
  ] }),
2674
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
2675
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
2676
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
2677
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2936
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-1", children: [
2937
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
2938
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
2939
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2678
2940
  "button",
2679
2941
  {
2680
2942
  type: "button",
@@ -2687,7 +2949,7 @@ var ImageEditor = ({
2687
2949
  ]
2688
2950
  }
2689
2951
  ),
2690
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2952
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2691
2953
  "button",
2692
2954
  {
2693
2955
  type: "button",
@@ -2702,25 +2964,25 @@ var ImageEditor = ({
2702
2964
  )
2703
2965
  ] })
2704
2966
  ] }),
2705
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2967
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2706
2968
  "button",
2707
2969
  {
2708
2970
  type: "button",
2709
2971
  onClick: handleInpaint,
2710
2972
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
2711
2973
  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",
2712
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2713
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2974
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2975
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2714
2976
  "Generating Inpaint..."
2715
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2716
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2977
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2978
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2717
2979
  "Apply Inpainting"
2718
2980
  ] })
2719
2981
  }
2720
2982
  )
2721
2983
  ] }),
2722
- aiError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
2723
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
2984
+ aiError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
2985
+ aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
2724
2986
  ] })
2725
2987
  ] })
2726
2988
  ] })
@@ -2736,6 +2998,7 @@ var ImageEditor = ({
2736
2998
  CurvesEditor,
2737
2999
  Histogram,
2738
3000
  ImageEditor,
3001
+ LayerEffectsPanel,
2739
3002
  LayersPanel,
2740
3003
  RefineEdgePanel,
2741
3004
  SelectionOptionsBar,