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