@pixerate/editor-react 0.63.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,14 +1217,14 @@ 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
1229
  const { brush, foreground, background, mixer, mixerLoad } = state.paint;
1024
1230
  const attempt = (fn) => {
@@ -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,21 +1287,21 @@ var BrushOptionsBar = ({ controller, className }) => {
1081
1287
  },
1082
1288
  spec.id
1083
1289
  )),
1084
- state.activeTool === "mixer" && /* @__PURE__ */ (0, import_jsx_runtime6.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: [
1085
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", 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)(
1087
1293
  "span",
1088
1294
  {
1089
1295
  "aria-label": "Brush load",
1090
- title: mixerLoad.reservoir ? `Loaded ${(0, import_image_editor7.rgbUnitToHex)(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
1296
+ title: mixerLoad.reservoir ? `Loaded ${(0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
1091
1297
  className: "h-6 w-6 rounded border border-slate-700",
1092
- style: { background: mixerLoad.reservoir ? (0, import_image_editor7.rgbUnitToHex)(mixerLoad.reservoir) : "transparent" }
1298
+ style: { background: mixerLoad.reservoir ? (0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir) : "transparent" }
1093
1299
  }
1094
1300
  ),
1095
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
1096
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
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" })
1097
1303
  ] }),
1098
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: import_image_editor7.MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
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)(
1099
1305
  "button",
1100
1306
  {
1101
1307
  type: "button",
@@ -1107,10 +1313,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1107
1313
  },
1108
1314
  m.id
1109
1315
  )) }),
1110
- import_image_editor7.MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
1111
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
1112
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1113
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
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)(
1114
1320
  "input",
1115
1321
  {
1116
1322
  type: "checkbox",
@@ -1122,8 +1328,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1122
1328
  ),
1123
1329
  "Load each stroke"
1124
1330
  ] }),
1125
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1126
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1331
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1332
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1127
1333
  "input",
1128
1334
  {
1129
1335
  type: "checkbox",
@@ -1137,9 +1343,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1137
1343
  ] })
1138
1344
  ] })
1139
1345
  ] }),
1140
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1141
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1142
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
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)(
1143
1349
  "input",
1144
1350
  {
1145
1351
  type: "checkbox",
@@ -1151,8 +1357,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1151
1357
  ),
1152
1358
  "Pressure size"
1153
1359
  ] }),
1154
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1155
- /* @__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)(
1156
1362
  "input",
1157
1363
  {
1158
1364
  type: "checkbox",
@@ -1165,18 +1371,18 @@ var BrushOptionsBar = ({ controller, className }) => {
1165
1371
  "Pressure opacity"
1166
1372
  ] })
1167
1373
  ] }),
1168
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex gap-1", children: [
1169
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1170
- /* @__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" })
1171
1377
  ] }),
1172
- 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 })
1173
1379
  ] });
1174
1380
  };
1175
1381
 
1176
1382
  // src/image-editor/SelectionOptionsBar.tsx
1177
- var import_react7 = require("react");
1178
- var import_image_editor8 = require("@pixerate/editor/image-editor");
1179
- 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");
1180
1386
  var MODIFY_OPS = [
1181
1387
  { op: "grow", label: "Grow" },
1182
1388
  { op: "shrink", label: "Shrink" },
@@ -1193,20 +1399,20 @@ var SelectionOptionsBar = ({
1193
1399
  quickMask,
1194
1400
  className = ""
1195
1401
  }) => {
1196
- const [radius, setRadius] = (0, import_react7.useState)(2);
1402
+ const [radius, setRadius] = (0, import_react8.useState)(2);
1197
1403
  const set = (patch) => onOptionsChange({ ...options, ...patch });
1198
1404
  const sel = selection === void 0 ? controller.getSelection() : selection;
1199
1405
  const qm = quickMask ?? Boolean(controller.getState().quickMask);
1200
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1201
- /* @__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)) }),
1202
- /* @__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)) }),
1203
- options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2", children: [
1204
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex flex-col gap-1", children: [
1205
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1206
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Tolerance" }),
1207
- /* @__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 })
1208
1414
  ] }),
1209
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1415
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1210
1416
  "input",
1211
1417
  {
1212
1418
  type: "range",
@@ -1220,17 +1426,17 @@ var SelectionOptionsBar = ({
1220
1426
  }
1221
1427
  )
1222
1428
  ] }),
1223
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1224
- /* @__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 }) }),
1225
1431
  "Contiguous"
1226
1432
  ] }),
1227
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1228
- /* @__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 }) }),
1229
1435
  "Sample adjusted image"
1230
1436
  ] }),
1231
- /* @__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: [
1232
1438
  "Sample",
1233
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1439
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1234
1440
  "select",
1235
1441
  {
1236
1442
  "aria-label": "Sample from",
@@ -1238,27 +1444,27 @@ var SelectionOptionsBar = ({
1238
1444
  onChange: (e) => set({ sample: e.target.value }),
1239
1445
  className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
1240
1446
  children: [
1241
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "composite", children: "All layers" }),
1242
- /* @__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" })
1243
1449
  ]
1244
1450
  }
1245
1451
  )
1246
1452
  ] })
1247
1453
  ] }),
1248
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1249
- /* @__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 }) }),
1250
1456
  "Anti-alias"
1251
1457
  ] }),
1252
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1253
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
1254
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1255
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1256
- /* @__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" })
1257
1463
  ] }),
1258
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1259
- /* @__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: [
1260
1466
  "Radius",
1261
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1467
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1262
1468
  "input",
1263
1469
  {
1264
1470
  type: "number",
@@ -1272,24 +1478,24 @@ var SelectionOptionsBar = ({
1272
1478
  }
1273
1479
  )
1274
1480
  ] }),
1275
- 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))
1276
1482
  ] }),
1277
- /* @__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) })
1278
1484
  ] });
1279
1485
  };
1280
1486
 
1281
1487
  // src/image-editor/RefineEdgePanel.tsx
1282
- var import_react8 = require("react");
1283
- var import_image_editor9 = require("@pixerate/editor/image-editor");
1284
- 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");
1285
1491
  var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
1286
- 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";
1287
1493
  var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1288
- const [params, setParams] = (0, import_react8.useState)(DEFAULT_PARAMS);
1289
- const [busy, setBusy] = (0, import_react8.useState)(false);
1290
- const [error, setError] = (0, import_react8.useState)(null);
1291
- const [layerId, setLayerId] = (0, import_react8.useState)("");
1292
- 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");
1293
1499
  const sel = selection === void 0 ? controller.getSelection() : selection;
1294
1500
  const list = layers ?? controller.getAdjustmentLayers();
1295
1501
  const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
@@ -1304,17 +1510,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1304
1510
  setBusy(false);
1305
1511
  }
1306
1512
  };
1307
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1308
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1309
- import_image_editor9.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
1310
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1311
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: c.label }),
1312
- /* @__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: [
1313
1519
  params[c.id],
1314
1520
  c.unit
1315
1521
  ] })
1316
1522
  ] }),
1317
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1523
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1318
1524
  "input",
1319
1525
  {
1320
1526
  type: "range",
@@ -1328,67 +1534,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1328
1534
  }
1329
1535
  )
1330
1536
  ] }, c.id)),
1331
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1332
- /* @__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 }) }),
1333
1539
  "Smart Radius"
1334
1540
  ] }),
1335
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-1", children: [
1336
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1337
- /* @__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" })
1338
1544
  ] }),
1339
- error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
1340
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1341
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-1 items-center", children: [
1342
- /* @__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)(
1343
1549
  "select",
1344
1550
  {
1345
1551
  "aria-label": "New masked layer kind",
1346
1552
  value: newKind,
1347
1553
  onChange: (e) => setNewKind(e.target.value),
1348
1554
  className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1349
- 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))
1350
1556
  }
1351
1557
  ),
1352
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1558
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1353
1559
  "button",
1354
1560
  {
1355
1561
  type: "button",
1356
- className: button,
1562
+ className: button2,
1357
1563
  disabled: !sel,
1358
- 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) })),
1359
1565
  children: "New Masked Layer"
1360
1566
  }
1361
1567
  )
1362
1568
  ] }),
1363
- list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-2", children: [
1364
- /* @__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)(
1365
1571
  "select",
1366
1572
  {
1367
1573
  "aria-label": "Mask layer",
1368
1574
  value: target.id,
1369
1575
  onChange: (e) => setLayerId(e.target.value),
1370
1576
  className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1371
- children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("option", { value: l.id, children: [
1372
- 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),
1373
1579
  l.mask ? " (masked)" : ""
1374
1580
  ] }, l.id))
1375
1581
  }
1376
1582
  ),
1377
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1378
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1379
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1380
- /* @__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" })
1381
1587
  ] }),
1382
- target.mask && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1383
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
1384
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1385
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Density" }),
1386
- /* @__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: [
1387
1593
  Math.round((target.mask.density ?? 1) * 100),
1388
1594
  "%"
1389
1595
  ] })
1390
1596
  ] }),
1391
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1597
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1392
1598
  "input",
1393
1599
  {
1394
1600
  type: "range",
@@ -1402,15 +1608,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1402
1608
  }
1403
1609
  )
1404
1610
  ] }),
1405
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
1406
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1407
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Mask Feather" }),
1408
- /* @__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: [
1409
1615
  target.mask.feather ?? 0,
1410
1616
  "px"
1411
1617
  ] })
1412
1618
  ] }),
1413
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1619
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1414
1620
  "input",
1415
1621
  {
1416
1622
  type: "range",
@@ -1430,7 +1636,7 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1430
1636
  };
1431
1637
 
1432
1638
  // src/image-editor/ImageEditor.tsx
1433
- var import_jsx_runtime9 = require("react/jsx-runtime");
1639
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1434
1640
  var ImageEditor = ({
1435
1641
  editor: externalEditor,
1436
1642
  src,
@@ -1445,35 +1651,35 @@ var ImageEditor = ({
1445
1651
  const internalEditor = useImageEditor({ image: src });
1446
1652
  const editor = externalEditor || internalEditor;
1447
1653
  const { state, controller } = editor;
1448
- const legacyProcess = (0, import_image_editor10.normalizeProcessVersion)(state.adjustments.process) < import_image_editor10.LATEST_PROCESS_VERSION;
1449
- const canvasRef = (0, import_react9.useRef)(null);
1450
- const containerRef = (0, import_react9.useRef)(null);
1451
- const [activeTab, setActiveTab] = (0, import_react9.useState)("crop");
1452
- const [activeCropRatio, setActiveCropRatio] = (0, import_react9.useState)(null);
1453
- const [selectionOptions, setSelectionOptions] = (0, import_react9.useState)(import_image_editor10.DEFAULT_SELECTION_TOOL_OPTIONS);
1454
- 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);
1455
1661
  selectionOptionsRef.current = selectionOptions;
1456
- const selectionGestureRef = (0, import_react9.useRef)(null);
1662
+ const selectionGestureRef = (0, import_react10.useRef)(null);
1457
1663
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
1458
- selectionGestureRef.current = new import_image_editor10.SelectionGesture(controller, () => selectionOptionsRef.current);
1664
+ selectionGestureRef.current = new import_image_editor11.SelectionGesture(controller, () => selectionOptionsRef.current);
1459
1665
  }
1460
- const selectionDraftRef = (0, import_react9.useRef)(null);
1461
- const [selectionError, setSelectionError] = (0, import_react9.useState)(null);
1462
- const paintGestureRef = (0, import_react9.useRef)(null);
1463
- 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);
1464
1670
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
1465
- paintGestureRef.current = new import_image_editor10.PaintGesture(controller);
1671
+ paintGestureRef.current = new import_image_editor11.PaintGesture(controller);
1466
1672
  paintControllerRef.current = controller;
1467
1673
  }
1468
- const brushCursorRef = (0, import_react9.useRef)(null);
1469
- const [paintError, setPaintError] = (0, import_react9.useState)(null);
1470
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react9.useState)("");
1471
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react9.useState)("annotations");
1472
- const [isRemovingBg, setIsRemovingBg] = (0, import_react9.useState)(false);
1473
- const [isInpainting, setIsInpainting] = (0, import_react9.useState)(false);
1474
- const [aiError, setAiError] = (0, import_react9.useState)(null);
1475
- const [aiSuccess, setAiSuccess] = (0, import_react9.useState)(null);
1476
- 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");
1477
1683
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
1478
1684
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
1479
1685
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -1536,18 +1742,18 @@ var ImageEditor = ({
1536
1742
  setIsInpainting(false);
1537
1743
  }
1538
1744
  };
1539
- const [activeColor, setActiveColor] = (0, import_react9.useState)("#ef4444");
1540
- const [strokeWidth, setStrokeWidth] = (0, import_react9.useState)(3);
1541
- const [fontSize, setFontSize] = (0, import_react9.useState)(24);
1542
- const [textInput, setTextInput] = (0, import_react9.useState)("");
1543
- const draftAnnotationRef = (0, import_react9.useRef)(null);
1544
- const draftCropRef = (0, import_react9.useRef)(null);
1545
- const cropDragInfoRef = (0, import_react9.useRef)(null);
1546
- const annotationDragInfoRef = (0, import_react9.useRef)(null);
1547
- const isDrawingRef = (0, import_react9.useRef)(false);
1548
- const currentPathRef = (0, import_react9.useRef)([]);
1549
- const dragStartPointRef = (0, import_react9.useRef)(null);
1550
- 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)(
1551
1757
  async (draftAnnotation, draftCrop) => {
1552
1758
  const canvas = canvasRef.current;
1553
1759
  const container = containerRef.current;
@@ -1568,7 +1774,7 @@ var ImageEditor = ({
1568
1774
  },
1569
1775
  [controller, activeTab]
1570
1776
  );
1571
- (0, import_react9.useEffect)(() => {
1777
+ (0, import_react10.useEffect)(() => {
1572
1778
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
1573
1779
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
1574
1780
  const animId = raf(() => {
@@ -1576,12 +1782,12 @@ var ImageEditor = ({
1576
1782
  });
1577
1783
  return () => caf(animId);
1578
1784
  }, [renderCanvas, state]);
1579
- (0, import_react9.useEffect)(() => {
1785
+ (0, import_react10.useEffect)(() => {
1580
1786
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
1581
1787
  editor.setTool("crop");
1582
1788
  }
1583
1789
  }, [activeTab, editor]);
1584
- (0, import_react9.useEffect)(() => {
1790
+ (0, import_react10.useEffect)(() => {
1585
1791
  const container = containerRef.current;
1586
1792
  if (!container) return;
1587
1793
  if (typeof ResizeObserver !== "undefined") {
@@ -1617,8 +1823,8 @@ var ImageEditor = ({
1617
1823
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
1618
1824
  const s = controller.getState();
1619
1825
  return list.map((ev) => ({
1620
- ...(0, import_image_editor10.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
1621
- 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)
1622
1828
  }));
1623
1829
  };
1624
1830
  const handlePaintPointerDown = (e) => {
@@ -1646,10 +1852,10 @@ var ImageEditor = ({
1646
1852
  if (g.error) setPaintError(g.error);
1647
1853
  }
1648
1854
  };
1649
- (0, import_react9.useEffect)(() => {
1855
+ (0, import_react10.useEffect)(() => {
1650
1856
  if (activeTab !== "paint" || typeof window === "undefined") return;
1651
1857
  const onKey = (e) => {
1652
- if ((0, import_image_editor10.handlePaintShortcut)(controller, e)) e.preventDefault();
1858
+ if ((0, import_image_editor11.handlePaintShortcut)(controller, e)) e.preventDefault();
1653
1859
  };
1654
1860
  window.addEventListener("keydown", onKey);
1655
1861
  return () => window.removeEventListener("keydown", onKey);
@@ -1660,7 +1866,7 @@ var ImageEditor = ({
1660
1866
  const canvasPt = getCanvasEventPoint(e);
1661
1867
  if (activeTab === "select") {
1662
1868
  const gesture = selectionGestureRef.current;
1663
- 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);
1664
1870
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
1665
1871
  return;
1666
1872
  }
@@ -1671,8 +1877,8 @@ var ImageEditor = ({
1671
1877
  width: state.imageDimensions.width,
1672
1878
  height: state.imageDimensions.height
1673
1879
  };
1674
- const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1675
- 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);
1676
1882
  if (handle) {
1677
1883
  cropDragInfoRef.current = {
1678
1884
  handle,
@@ -1691,12 +1897,12 @@ var ImageEditor = ({
1691
1897
  return;
1692
1898
  }
1693
1899
  if (activeTab === "annotate") {
1694
- 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);
1695
1901
  dragStartPointRef.current = imgPt;
1696
1902
  if (state.activeTool === "select") {
1697
1903
  for (let i = state.annotations.length - 1; i >= 0; i--) {
1698
1904
  const ann = state.annotations[i];
1699
- if ((0, import_image_editor10.hitTestAnnotation)(imgPt, ann)) {
1905
+ if ((0, import_image_editor11.hitTestAnnotation)(imgPt, ann)) {
1700
1906
  editor.selectAnnotation(ann.id);
1701
1907
  annotationDragInfoRef.current = {
1702
1908
  annId: ann.id,
@@ -1732,7 +1938,7 @@ var ImageEditor = ({
1732
1938
  const canvasPt = getCanvasEventPoint(e);
1733
1939
  if (activeTab === "select") {
1734
1940
  const gesture = selectionGestureRef.current;
1735
- 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))) {
1736
1942
  selectionDraftRef.current = gesture.draftPath;
1737
1943
  renderCanvas();
1738
1944
  }
@@ -1741,7 +1947,7 @@ var ImageEditor = ({
1741
1947
  if (activeTab === "crop") {
1742
1948
  const drag = cropDragInfoRef.current;
1743
1949
  if (drag) {
1744
- 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);
1745
1951
  let newCrop;
1746
1952
  if (drag.handle === "new") {
1747
1953
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -1755,7 +1961,7 @@ var ImageEditor = ({
1755
1961
  height: Math.round(Math.max(20, maxY - minY))
1756
1962
  };
1757
1963
  } else {
1758
- newCrop = (0, import_image_editor10.calculateCropDrag)(
1964
+ newCrop = (0, import_image_editor11.calculateCropDrag)(
1759
1965
  drag.startCrop,
1760
1966
  drag.handle,
1761
1967
  drag.startImgPt,
@@ -1775,15 +1981,15 @@ var ImageEditor = ({
1775
1981
  width: state.imageDimensions.width,
1776
1982
  height: state.imageDimensions.height
1777
1983
  };
1778
- const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
1779
- 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);
1780
1986
  }
1781
1987
  return;
1782
1988
  }
1783
1989
  if (activeTab === "annotate") {
1784
1990
  if (annotationDragInfoRef.current) {
1785
1991
  const drag = annotationDragInfoRef.current;
1786
- 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);
1787
1993
  const dx = currentImgPt2.x - drag.startImgPt.x;
1788
1994
  const dy = currentImgPt2.y - drag.startImgPt.y;
1789
1995
  editor.updateAnnotation(drag.annId, {
@@ -1795,10 +2001,10 @@ var ImageEditor = ({
1795
2001
  const startPt = dragStartPointRef.current;
1796
2002
  if (!startPt) {
1797
2003
  if (state.activeTool === "select") {
1798
- 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);
1799
2005
  let hovered = false;
1800
2006
  for (let i = state.annotations.length - 1; i >= 0; i--) {
1801
- if ((0, import_image_editor10.hitTestAnnotation)(imgPt, state.annotations[i])) {
2007
+ if ((0, import_image_editor11.hitTestAnnotation)(imgPt, state.annotations[i])) {
1802
2008
  hovered = true;
1803
2009
  break;
1804
2010
  }
@@ -1809,7 +2015,7 @@ var ImageEditor = ({
1809
2015
  }
1810
2016
  return;
1811
2017
  }
1812
- 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);
1813
2019
  if (state.activeTool === "pen" && isDrawingRef.current) {
1814
2020
  currentPathRef.current.push(currentImgPt);
1815
2021
  const draft = {
@@ -1889,7 +2095,7 @@ var ImageEditor = ({
1889
2095
  if (activeTab === "select") {
1890
2096
  const gesture = selectionGestureRef.current;
1891
2097
  if (gesture.active) {
1892
- 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);
1893
2099
  selectionDraftRef.current = null;
1894
2100
  renderCanvas();
1895
2101
  }
@@ -1913,7 +2119,7 @@ var ImageEditor = ({
1913
2119
  }
1914
2120
  const startPt = dragStartPointRef.current;
1915
2121
  if (startPt) {
1916
- 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);
1917
2123
  if (state.activeTool === "pen" && isDrawingRef.current) {
1918
2124
  if (currentPathRef.current.length > 1) {
1919
2125
  editor.addAnnotation({
@@ -2009,15 +2215,15 @@ var ImageEditor = ({
2009
2215
  link.click();
2010
2216
  }
2011
2217
  };
2012
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2218
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2013
2219
  "div",
2014
2220
  {
2015
2221
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
2016
2222
  style,
2017
2223
  children: [
2018
- /* @__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: [
2019
- /* @__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: [
2020
- /* @__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)(
2021
2227
  "button",
2022
2228
  {
2023
2229
  type: "button",
@@ -2029,7 +2235,7 @@ var ImageEditor = ({
2029
2235
  children: "Transform & Crop"
2030
2236
  }
2031
2237
  ),
2032
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2238
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2033
2239
  "button",
2034
2240
  {
2035
2241
  type: "button",
@@ -2041,7 +2247,7 @@ var ImageEditor = ({
2041
2247
  children: "Adjustments"
2042
2248
  }
2043
2249
  ),
2044
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2250
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2045
2251
  "button",
2046
2252
  {
2047
2253
  type: "button",
@@ -2053,7 +2259,7 @@ var ImageEditor = ({
2053
2259
  children: "Layers"
2054
2260
  }
2055
2261
  ),
2056
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2262
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2057
2263
  "button",
2058
2264
  {
2059
2265
  type: "button",
@@ -2065,7 +2271,7 @@ var ImageEditor = ({
2065
2271
  children: "Paint"
2066
2272
  }
2067
2273
  ),
2068
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2274
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2069
2275
  "button",
2070
2276
  {
2071
2277
  type: "button",
@@ -2077,7 +2283,7 @@ var ImageEditor = ({
2077
2283
  children: "Select & Mask"
2078
2284
  }
2079
2285
  ),
2080
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2286
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2081
2287
  "button",
2082
2288
  {
2083
2289
  type: "button",
@@ -2089,7 +2295,7 @@ var ImageEditor = ({
2089
2295
  children: "Annotations"
2090
2296
  }
2091
2297
  ),
2092
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2298
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2093
2299
  "button",
2094
2300
  {
2095
2301
  type: "button",
@@ -2101,7 +2307,7 @@ var ImageEditor = ({
2101
2307
  children: "Depth Mask"
2102
2308
  }
2103
2309
  ),
2104
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2310
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2105
2311
  "button",
2106
2312
  {
2107
2313
  type: "button",
@@ -2111,14 +2317,14 @@ var ImageEditor = ({
2111
2317
  },
2112
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"}`,
2113
2319
  children: [
2114
- /* @__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" }) }),
2115
2321
  "AI Tools"
2116
2322
  ]
2117
2323
  }
2118
2324
  )
2119
2325
  ] }),
2120
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
2121
- /* @__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)(
2122
2328
  "button",
2123
2329
  {
2124
2330
  type: "button",
@@ -2129,7 +2335,7 @@ var ImageEditor = ({
2129
2335
  children: "\u21A9"
2130
2336
  }
2131
2337
  ),
2132
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2338
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2133
2339
  "button",
2134
2340
  {
2135
2341
  type: "button",
@@ -2140,7 +2346,7 @@ var ImageEditor = ({
2140
2346
  children: "\u21AA"
2141
2347
  }
2142
2348
  ),
2143
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2349
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2144
2350
  "button",
2145
2351
  {
2146
2352
  type: "button",
@@ -2149,8 +2355,8 @@ var ImageEditor = ({
2149
2355
  children: "Reset"
2150
2356
  }
2151
2357
  ),
2152
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2153
- /* @__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)(
2154
2360
  "button",
2155
2361
  {
2156
2362
  type: "button",
@@ -2160,11 +2366,11 @@ var ImageEditor = ({
2160
2366
  children: "-"
2161
2367
  }
2162
2368
  ),
2163
- /* @__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: [
2164
2370
  Math.round(state.zoom * 100),
2165
2371
  "%"
2166
2372
  ] }),
2167
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2373
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2168
2374
  "button",
2169
2375
  {
2170
2376
  type: "button",
@@ -2174,8 +2380,8 @@ var ImageEditor = ({
2174
2380
  children: "+"
2175
2381
  }
2176
2382
  ),
2177
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2178
- /* @__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)(
2179
2385
  "button",
2180
2386
  {
2181
2387
  type: "button",
@@ -2186,7 +2392,7 @@ var ImageEditor = ({
2186
2392
  children: "Hold Compare"
2187
2393
  }
2188
2394
  ),
2189
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2395
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2190
2396
  "button",
2191
2397
  {
2192
2398
  type: "button",
@@ -2197,13 +2403,13 @@ var ImageEditor = ({
2197
2403
  )
2198
2404
  ] })
2199
2405
  ] }),
2200
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2201
- /* @__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)(
2202
2408
  "div",
2203
2409
  {
2204
2410
  ref: containerRef,
2205
2411
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
2206
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2412
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2207
2413
  "canvas",
2208
2414
  {
2209
2415
  ref: canvasRef,
@@ -2221,11 +2427,11 @@ var ImageEditor = ({
2221
2427
  )
2222
2428
  }
2223
2429
  ),
2224
- /* @__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: [
2225
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2226
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2227
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
2228
- /* @__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)(
2229
2435
  "button",
2230
2436
  {
2231
2437
  type: "button",
@@ -2237,7 +2443,7 @@ var ImageEditor = ({
2237
2443
  children: "Freeform"
2238
2444
  }
2239
2445
  ),
2240
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2446
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2241
2447
  "button",
2242
2448
  {
2243
2449
  type: "button",
@@ -2249,7 +2455,7 @@ var ImageEditor = ({
2249
2455
  children: "1:1 Square"
2250
2456
  }
2251
2457
  ),
2252
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2458
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2253
2459
  "button",
2254
2460
  {
2255
2461
  type: "button",
@@ -2261,7 +2467,7 @@ var ImageEditor = ({
2261
2467
  children: "4:3 Standard"
2262
2468
  }
2263
2469
  ),
2264
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2470
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2265
2471
  "button",
2266
2472
  {
2267
2473
  type: "button",
@@ -2273,7 +2479,7 @@ var ImageEditor = ({
2273
2479
  children: "16:9 Wide"
2274
2480
  }
2275
2481
  ),
2276
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2482
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2277
2483
  "button",
2278
2484
  {
2279
2485
  type: "button",
@@ -2285,7 +2491,7 @@ var ImageEditor = ({
2285
2491
  children: "3:2 Photo"
2286
2492
  }
2287
2493
  ),
2288
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2494
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2289
2495
  "button",
2290
2496
  {
2291
2497
  type: "button",
@@ -2298,10 +2504,10 @@ var ImageEditor = ({
2298
2504
  }
2299
2505
  )
2300
2506
  ] }),
2301
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2302
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2303
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
2304
- /* @__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)(
2305
2511
  "button",
2306
2512
  {
2307
2513
  type: "button",
@@ -2310,7 +2516,7 @@ var ImageEditor = ({
2310
2516
  children: "Rotate -90\xB0"
2311
2517
  }
2312
2518
  ),
2313
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2519
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2314
2520
  "button",
2315
2521
  {
2316
2522
  type: "button",
@@ -2319,7 +2525,7 @@ var ImageEditor = ({
2319
2525
  children: "Rotate +90\xB0"
2320
2526
  }
2321
2527
  ),
2322
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2528
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2323
2529
  "button",
2324
2530
  {
2325
2531
  type: "button",
@@ -2328,7 +2534,7 @@ var ImageEditor = ({
2328
2534
  children: "Flip Horizontal"
2329
2535
  }
2330
2536
  ),
2331
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2537
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2332
2538
  "button",
2333
2539
  {
2334
2540
  type: "button",
@@ -2339,10 +2545,10 @@ var ImageEditor = ({
2339
2545
  )
2340
2546
  ] })
2341
2547
  ] }),
2342
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2343
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2344
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2345
- /* @__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)(
2346
2552
  "button",
2347
2553
  {
2348
2554
  type: "button",
@@ -2352,25 +2558,25 @@ var ImageEditor = ({
2352
2558
  }
2353
2559
  )
2354
2560
  ] }),
2355
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Histogram, { histogram: editor.histogram }),
2356
- import_image_editor10.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react9.default.Fragment, { children: [
2357
- /* @__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)(
2358
2564
  ControlSlider,
2359
2565
  {
2360
2566
  spec,
2361
- value: (0, import_image_editor10.readAdjustmentControls)(state.adjustments)[spec.id],
2567
+ value: (0, import_image_editor11.readAdjustmentControls)(state.adjustments)[spec.id],
2362
2568
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
2363
2569
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
2364
2570
  }
2365
2571
  ),
2366
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2572
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2367
2573
  "div",
2368
2574
  {
2369
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",
2370
2576
  "data-testid": "image-editor-process-notice",
2371
2577
  children: [
2372
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
2373
- /* @__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)(
2374
2580
  "button",
2375
2581
  {
2376
2582
  type: "button",
@@ -2383,7 +2589,7 @@ var ImageEditor = ({
2383
2589
  }
2384
2590
  )
2385
2591
  ] }, spec.id)),
2386
- /* @__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)(
2387
2593
  AdjustmentLayersPanel,
2388
2594
  {
2389
2595
  controller,
@@ -2392,19 +2598,19 @@ var ImageEditor = ({
2392
2598
  }
2393
2599
  ) })
2394
2600
  ] }),
2395
- activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2396
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
2397
- /* @__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 })
2398
2604
  ] }),
2399
- activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2400
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
2401
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BrushOptionsBar, { controller }),
2402
- paintError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
2403
- /* @__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 }) })
2404
2610
  ] }),
2405
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2406
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2407
- /* @__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)(
2408
2614
  "button",
2409
2615
  {
2410
2616
  type: "button",
@@ -2414,9 +2620,9 @@ var ImageEditor = ({
2414
2620
  },
2415
2621
  t
2416
2622
  )) }),
2417
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
2418
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-slate-400", children: "Color:" }),
2419
- /* @__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)(
2420
2626
  "input",
2421
2627
  {
2422
2628
  type: "color",
@@ -2425,15 +2631,15 @@ var ImageEditor = ({
2425
2631
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
2426
2632
  }
2427
2633
  ),
2428
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 ml-2", children: [
2429
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2430
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Width:" }),
2431
- /* @__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: [
2432
2638
  strokeWidth,
2433
2639
  "px"
2434
2640
  ] })
2435
2641
  ] }),
2436
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2642
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2437
2643
  "input",
2438
2644
  {
2439
2645
  type: "range",
@@ -2446,10 +2652,10 @@ var ImageEditor = ({
2446
2652
  )
2447
2653
  ] })
2448
2654
  ] }),
2449
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2450
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2451
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-2", children: [
2452
- /* @__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)(
2453
2659
  "input",
2454
2660
  {
2455
2661
  type: "text",
@@ -2460,7 +2666,7 @@ var ImageEditor = ({
2460
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"
2461
2667
  }
2462
2668
  ),
2463
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2669
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2464
2670
  "button",
2465
2671
  {
2466
2672
  type: "button",
@@ -2470,14 +2676,14 @@ var ImageEditor = ({
2470
2676
  }
2471
2677
  )
2472
2678
  ] }),
2473
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
2474
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Font Size:" }),
2475
- /* @__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: [
2476
2682
  fontSize,
2477
2683
  "px"
2478
2684
  ] })
2479
2685
  ] }),
2480
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2686
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2481
2687
  "input",
2482
2688
  {
2483
2689
  type: "range",
@@ -2488,14 +2694,14 @@ var ImageEditor = ({
2488
2694
  className: "w-full accent-indigo-500"
2489
2695
  }
2490
2696
  ),
2491
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2492
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2493
- /* @__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: [
2494
2700
  "Layers (",
2495
2701
  state.annotations.length,
2496
2702
  ")"
2497
2703
  ] }),
2498
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2704
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2499
2705
  "button",
2500
2706
  {
2501
2707
  type: "button",
@@ -2504,7 +2710,7 @@ var ImageEditor = ({
2504
2710
  children: "Delete Selected"
2505
2711
  }
2506
2712
  ),
2507
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2713
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2508
2714
  "button",
2509
2715
  {
2510
2716
  type: "button",
@@ -2515,10 +2721,10 @@ var ImageEditor = ({
2515
2721
  )
2516
2722
  ] })
2517
2723
  ] }),
2518
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2519
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2520
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2521
- /* @__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)(
2522
2728
  "button",
2523
2729
  {
2524
2730
  type: "button",
@@ -2528,8 +2734,8 @@ var ImageEditor = ({
2528
2734
  }
2529
2735
  )
2530
2736
  ] }),
2531
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2532
- /* @__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)(
2533
2739
  "input",
2534
2740
  {
2535
2741
  type: "checkbox",
@@ -2538,12 +2744,12 @@ var ImageEditor = ({
2538
2744
  className: "rounded accent-indigo-500"
2539
2745
  }
2540
2746
  ),
2541
- /* @__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" })
2542
2748
  ] }),
2543
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2544
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2545
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
2546
- /* @__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)(
2547
2753
  "input",
2548
2754
  {
2549
2755
  type: "text",
@@ -2554,8 +2760,8 @@ var ImageEditor = ({
2554
2760
  }
2555
2761
  )
2556
2762
  ] }),
2557
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-2", children: [
2558
- /* @__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)(
2559
2765
  "button",
2560
2766
  {
2561
2767
  type: "button",
@@ -2564,7 +2770,7 @@ var ImageEditor = ({
2564
2770
  children: "Threshold Mode"
2565
2771
  }
2566
2772
  ),
2567
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2773
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2568
2774
  "button",
2569
2775
  {
2570
2776
  type: "button",
@@ -2574,12 +2780,12 @@ var ImageEditor = ({
2574
2780
  }
2575
2781
  )
2576
2782
  ] }),
2577
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2578
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2579
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Depth Start (Lower):" }),
2580
- /* @__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] })
2581
2787
  ] }),
2582
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2788
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2583
2789
  "input",
2584
2790
  {
2585
2791
  type: "range",
@@ -2593,12 +2799,12 @@ var ImageEditor = ({
2593
2799
  }
2594
2800
  )
2595
2801
  ] }),
2596
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2597
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2598
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Depth Stop (Upper):" }),
2599
- /* @__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] })
2600
2806
  ] }),
2601
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2807
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2602
2808
  "input",
2603
2809
  {
2604
2810
  type: "range",
@@ -2612,12 +2818,12 @@ var ImageEditor = ({
2612
2818
  }
2613
2819
  )
2614
2820
  ] }),
2615
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2616
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2617
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Softness:" }),
2618
- /* @__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 })
2619
2825
  ] }),
2620
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2826
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2621
2827
  "input",
2622
2828
  {
2623
2829
  type: "range",
@@ -2629,8 +2835,8 @@ var ImageEditor = ({
2629
2835
  }
2630
2836
  )
2631
2837
  ] }),
2632
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
2633
- /* @__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)(
2634
2840
  "input",
2635
2841
  {
2636
2842
  type: "checkbox",
@@ -2639,12 +2845,12 @@ var ImageEditor = ({
2639
2845
  className: "rounded accent-indigo-500"
2640
2846
  }
2641
2847
  ),
2642
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Invert Mask" })
2848
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Invert Mask" })
2643
2849
  ] })
2644
2850
  ] })
2645
2851
  ] }),
2646
- activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2647
- /* @__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)(
2648
2854
  SelectionOptionsBar,
2649
2855
  {
2650
2856
  controller,
@@ -2654,13 +2860,13 @@ var ImageEditor = ({
2654
2860
  quickMask: Boolean(state.quickMask)
2655
2861
  }
2656
2862
  ),
2657
- selectionError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
2658
- /* @__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 })
2659
2865
  ] }),
2660
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2661
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
2662
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Results go to" }),
2663
- /* @__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)(
2664
2870
  "select",
2665
2871
  {
2666
2872
  "aria-label": "AI result target",
@@ -2668,54 +2874,54 @@ var ImageEditor = ({
2668
2874
  onChange: (e) => setAiTarget(e.target.value),
2669
2875
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
2670
2876
  children: [
2671
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
2672
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
2673
- /* @__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" })
2674
2880
  ]
2675
2881
  }
2676
2882
  )
2677
2883
  ] }),
2678
- /* @__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: [
2679
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2680
- /* @__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: [
2681
- /* @__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" }) }),
2682
2888
  "Background Removal"
2683
2889
  ] }),
2684
- 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..." })
2685
2891
  ] }),
2686
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
2687
- /* @__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)(
2688
2894
  "button",
2689
2895
  {
2690
2896
  type: "button",
2691
2897
  onClick: handleRemoveBackground,
2692
2898
  disabled: isRemovingBg || isInpainting,
2693
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",
2694
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2695
- /* @__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" }),
2696
2902
  "Removing Background..."
2697
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2698
- /* @__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" }) }),
2699
2905
  "Remove Background"
2700
2906
  ] })
2701
2907
  }
2702
2908
  )
2703
2909
  ] }),
2704
- /* @__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: [
2705
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
2706
- /* @__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: [
2707
- /* @__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: [
2708
- /* @__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" }),
2709
- /* @__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" })
2710
2916
  ] }),
2711
2917
  "Generative Inpainting"
2712
2918
  ] }),
2713
- 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..." })
2714
2920
  ] }),
2715
- /* @__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." }),
2716
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
2717
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
2718
- /* @__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)(
2719
2925
  "textarea",
2720
2926
  {
2721
2927
  id: "ai-inpaint-prompt-react",
@@ -2727,10 +2933,10 @@ var ImageEditor = ({
2727
2933
  }
2728
2934
  )
2729
2935
  ] }),
2730
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
2731
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
2732
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
2733
- /* @__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)(
2734
2940
  "button",
2735
2941
  {
2736
2942
  type: "button",
@@ -2743,7 +2949,7 @@ var ImageEditor = ({
2743
2949
  ]
2744
2950
  }
2745
2951
  ),
2746
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2952
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2747
2953
  "button",
2748
2954
  {
2749
2955
  type: "button",
@@ -2758,25 +2964,25 @@ var ImageEditor = ({
2758
2964
  )
2759
2965
  ] })
2760
2966
  ] }),
2761
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2967
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2762
2968
  "button",
2763
2969
  {
2764
2970
  type: "button",
2765
2971
  onClick: handleInpaint,
2766
2972
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
2767
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",
2768
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2769
- /* @__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" }),
2770
2976
  "Generating Inpaint..."
2771
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2772
- /* @__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" }) }),
2773
2979
  "Apply Inpainting"
2774
2980
  ] })
2775
2981
  }
2776
2982
  )
2777
2983
  ] }),
2778
- 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 }),
2779
- 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 })
2780
2986
  ] })
2781
2987
  ] })
2782
2988
  ] })
@@ -2792,6 +2998,7 @@ var ImageEditor = ({
2792
2998
  CurvesEditor,
2793
2999
  Histogram,
2794
3000
  ImageEditor,
3001
+ LayerEffectsPanel,
2795
3002
  LayersPanel,
2796
3003
  RefineEdgePanel,
2797
3004
  SelectionOptionsBar,