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