@pixerate/editor-react 0.57.0 → 0.59.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-ZU54BMDC.js → chunk-SYTV33TW.js} +810 -254
- package/dist/chunk-SYTV33TW.js.map +1 -0
- package/dist/image-editor/index.cjs +822 -275
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +26 -1
- package/dist/image-editor/index.d.ts +26 -1
- package/dist/image-editor/index.js +5 -1
- package/dist/index.cjs +1251 -704
- 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 +5 -1
- package/dist/index.js.map +1 -1
- package/dist/video-editor/index.cjs +71 -16
- package/dist/video-editor/index.cjs.map +1 -1
- package/dist/video-editor/index.js +70 -14
- package/dist/video-editor/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-ZU54BMDC.js.map +0 -1
|
@@ -31,10 +31,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var image_editor_exports = {};
|
|
32
32
|
__export(image_editor_exports, {
|
|
33
33
|
AdjustmentLayersPanel: () => AdjustmentLayersPanel,
|
|
34
|
+
BrushOptionsBar: () => BrushOptionsBar,
|
|
34
35
|
ControlSlider: () => ControlSlider,
|
|
35
36
|
CurvesEditor: () => CurvesEditor,
|
|
36
37
|
Histogram: () => Histogram,
|
|
37
38
|
ImageEditor: () => ImageEditor,
|
|
39
|
+
LayersPanel: () => LayersPanel,
|
|
38
40
|
RefineEdgePanel: () => RefineEdgePanel,
|
|
39
41
|
SelectionOptionsBar: () => SelectionOptionsBar,
|
|
40
42
|
useImageEditor: () => useImageEditor,
|
|
@@ -201,8 +203,8 @@ function useImageEditor(options = {}) {
|
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
// src/image-editor/ImageEditor.tsx
|
|
204
|
-
var
|
|
205
|
-
var
|
|
206
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
207
|
+
var import_image_editor10 = require("@pixerate/editor/image-editor");
|
|
206
208
|
|
|
207
209
|
// src/image-editor/ControlSlider.tsx
|
|
208
210
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
@@ -633,10 +635,458 @@ var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
|
|
|
633
635
|
] });
|
|
634
636
|
};
|
|
635
637
|
|
|
636
|
-
// src/image-editor/
|
|
638
|
+
// src/image-editor/LayersPanel.tsx
|
|
637
639
|
var import_react5 = require("react");
|
|
638
640
|
var import_image_editor6 = require("@pixerate/editor/image-editor");
|
|
639
641
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
642
|
+
var iconButton = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
|
|
643
|
+
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
|
+
var Thumbnail = ({
|
|
645
|
+
pixels,
|
|
646
|
+
size,
|
|
647
|
+
label,
|
|
648
|
+
onClick,
|
|
649
|
+
selected,
|
|
650
|
+
testId
|
|
651
|
+
}) => {
|
|
652
|
+
const ref = (0, import_react5.useRef)(null);
|
|
653
|
+
(0, import_react5.useEffect)(() => {
|
|
654
|
+
const canvas = ref.current;
|
|
655
|
+
const ctx = canvas?.getContext("2d");
|
|
656
|
+
if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== "function") return;
|
|
657
|
+
canvas.width = pixels.width;
|
|
658
|
+
canvas.height = pixels.height;
|
|
659
|
+
const img = ctx.createImageData(pixels.width, pixels.height);
|
|
660
|
+
img.data.set(pixels.data);
|
|
661
|
+
ctx.putImageData(img, 0, 0);
|
|
662
|
+
}, [pixels]);
|
|
663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
664
|
+
"canvas",
|
|
665
|
+
{
|
|
666
|
+
ref,
|
|
667
|
+
role: onClick ? "button" : "img",
|
|
668
|
+
"aria-label": label,
|
|
669
|
+
"data-testid": testId,
|
|
670
|
+
onClick,
|
|
671
|
+
style: { width: size, height: size },
|
|
672
|
+
className: `shrink-0 rounded bg-[repeating-conic-gradient(#334155_0%_25%,#1e293b_0%_50%)] [background-size:8px_8px] object-contain ${selected ? "ring-2 ring-white" : "ring-1 ring-slate-700"}`
|
|
673
|
+
}
|
|
674
|
+
);
|
|
675
|
+
};
|
|
676
|
+
var LayersPanel = ({ controller, thumbnailSize = 32, className }) => {
|
|
677
|
+
const [, setTick] = (0, import_react5.useState)(0);
|
|
678
|
+
(0, import_react5.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
679
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
680
|
+
const [renaming, setRenaming] = (0, import_react5.useState)(null);
|
|
681
|
+
const [menu, setMenu] = (0, import_react5.useState)(null);
|
|
682
|
+
const [drag, setDrag] = (0, import_react5.useState)(null);
|
|
683
|
+
const commitNext = (0, import_react5.useRef)(true);
|
|
684
|
+
const state = controller.getState();
|
|
685
|
+
const rows = (0, import_image_editor6.layerPanelRows)(state.layers, state.activeLayerId);
|
|
686
|
+
const active = controller.getActiveLayer();
|
|
687
|
+
const attempt = (fn) => {
|
|
688
|
+
try {
|
|
689
|
+
setError(null);
|
|
690
|
+
fn();
|
|
691
|
+
} catch (err) {
|
|
692
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
const run = async (action) => {
|
|
696
|
+
setMenu(null);
|
|
697
|
+
setError(await (0, import_image_editor6.runLayerMenuAction)(controller, action));
|
|
698
|
+
};
|
|
699
|
+
const prop = (key, value) => attempt(() => {
|
|
700
|
+
controller.setLayerProperties(active.id, { [key]: value }, commitNext.current);
|
|
701
|
+
commitNext.current = false;
|
|
702
|
+
});
|
|
703
|
+
const sliderEvents = {
|
|
704
|
+
onPointerDown: () => commitNext.current = true,
|
|
705
|
+
onPointerUp: () => commitNext.current = true,
|
|
706
|
+
onKeyDown: () => commitNext.current = true
|
|
707
|
+
};
|
|
708
|
+
const onDrop = (e, row) => {
|
|
709
|
+
e.preventDefault();
|
|
710
|
+
const id = e.dataTransfer.getData("text/x-pixerate-layer") || drag;
|
|
711
|
+
setDrag(null);
|
|
712
|
+
if (!id) return;
|
|
713
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
714
|
+
const fraction = rect.height ? (e.clientY - rect.top) / rect.height : 0.5;
|
|
715
|
+
const placement = (0, import_image_editor6.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor6.dropZone)(fraction, row.layer.type === "group"));
|
|
716
|
+
if (placement) attempt(() => controller.moveLayer(id, placement));
|
|
717
|
+
};
|
|
718
|
+
const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
|
|
719
|
+
const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
|
|
720
|
+
const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
|
|
721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
|
|
722
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
|
|
724
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
|
|
726
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
|
|
727
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
729
|
+
"button",
|
|
730
|
+
{
|
|
731
|
+
type: "button",
|
|
732
|
+
className: iconButton,
|
|
733
|
+
"aria-label": "Layer menu",
|
|
734
|
+
"aria-haspopup": "menu",
|
|
735
|
+
onClick: (e) => {
|
|
736
|
+
e.stopPropagation();
|
|
737
|
+
const r = e.currentTarget.getBoundingClientRect();
|
|
738
|
+
setMenu(menu ? null : { x: r.left, y: r.bottom });
|
|
739
|
+
},
|
|
740
|
+
children: "\u22EF"
|
|
741
|
+
}
|
|
742
|
+
)
|
|
743
|
+
] }),
|
|
744
|
+
active && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 items-center", "data-testid": "layer-properties", children: [
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
|
|
746
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
|
|
747
|
+
"Opacity ",
|
|
748
|
+
Math.round(active.opacity * 100),
|
|
749
|
+
"%"
|
|
750
|
+
] }),
|
|
751
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
752
|
+
"input",
|
|
753
|
+
{
|
|
754
|
+
type: "range",
|
|
755
|
+
min: 0,
|
|
756
|
+
max: 100,
|
|
757
|
+
"aria-label": "Layer opacity",
|
|
758
|
+
value: Math.round(active.opacity * 100),
|
|
759
|
+
...sliderEvents,
|
|
760
|
+
onChange: (e) => prop("opacity", Number(e.target.value) / 100),
|
|
761
|
+
className: "accent-indigo-500"
|
|
762
|
+
}
|
|
763
|
+
)
|
|
764
|
+
] }),
|
|
765
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
|
|
767
|
+
"Fill ",
|
|
768
|
+
Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
|
|
769
|
+
"%"
|
|
770
|
+
] }),
|
|
771
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
772
|
+
"input",
|
|
773
|
+
{
|
|
774
|
+
type: "range",
|
|
775
|
+
min: 0,
|
|
776
|
+
max: 100,
|
|
777
|
+
"aria-label": "Layer fill",
|
|
778
|
+
disabled: active.type !== "pixel",
|
|
779
|
+
value: Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
|
|
780
|
+
...sliderEvents,
|
|
781
|
+
onChange: (e) => prop("fillOpacity", Number(e.target.value) / 100),
|
|
782
|
+
className: "accent-indigo-500 disabled:opacity-40"
|
|
783
|
+
}
|
|
784
|
+
)
|
|
785
|
+
] }),
|
|
786
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
787
|
+
"select",
|
|
788
|
+
{
|
|
789
|
+
"aria-label": "Layer blend mode",
|
|
790
|
+
className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
|
|
791
|
+
value: active.blend,
|
|
792
|
+
onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { blend: e.target.value })),
|
|
793
|
+
children: [
|
|
794
|
+
active.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "pass-through", children: "Pass Through" }),
|
|
795
|
+
import_image_editor6.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: m.id, children: m.label }, m.id))
|
|
796
|
+
]
|
|
797
|
+
}
|
|
798
|
+
),
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
801
|
+
"input",
|
|
802
|
+
{
|
|
803
|
+
type: "checkbox",
|
|
804
|
+
"aria-label": "Clip to layer below",
|
|
805
|
+
checked: Boolean(active.clipped),
|
|
806
|
+
onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { clipped: e.target.checked })),
|
|
807
|
+
className: "accent-indigo-500"
|
|
808
|
+
}
|
|
809
|
+
),
|
|
810
|
+
"Clip to below"
|
|
811
|
+
] }),
|
|
812
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "col-span-2 flex flex-wrap gap-2 text-slate-400", role: "group", "aria-label": "Layer locks", children: ["pixels", "transparency", "position", "all"].map((k) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
813
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
814
|
+
"input",
|
|
815
|
+
{
|
|
816
|
+
type: "checkbox",
|
|
817
|
+
"aria-label": `Lock ${k}`,
|
|
818
|
+
checked: Boolean(active.locks?.[k]),
|
|
819
|
+
onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { locks: { ...active.locks, [k]: e.target.checked } })),
|
|
820
|
+
className: "accent-indigo-500"
|
|
821
|
+
}
|
|
822
|
+
),
|
|
823
|
+
k
|
|
824
|
+
] }, k)) })
|
|
825
|
+
] }),
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
|
|
827
|
+
const { layer } = row;
|
|
828
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
829
|
+
"li",
|
|
830
|
+
{
|
|
831
|
+
role: "treeitem",
|
|
832
|
+
"aria-selected": row.active,
|
|
833
|
+
"aria-level": row.depth + 1,
|
|
834
|
+
"data-layer-id": layer.id,
|
|
835
|
+
draggable: !layer.locks?.all,
|
|
836
|
+
onDragStart: (e) => {
|
|
837
|
+
e.dataTransfer.setData("text/x-pixerate-layer", layer.id);
|
|
838
|
+
setDrag(layer.id);
|
|
839
|
+
},
|
|
840
|
+
onDragOver: (e) => e.preventDefault(),
|
|
841
|
+
onDrop: (e) => onDrop(e, row),
|
|
842
|
+
tabIndex: 0,
|
|
843
|
+
onClick: () => attempt(() => controller.setActiveLayer(layer.id, "pixels")),
|
|
844
|
+
onKeyDown: (e) => {
|
|
845
|
+
if (e.target === e.currentTarget && (e.key === "Enter" || e.key === " ")) {
|
|
846
|
+
e.preventDefault();
|
|
847
|
+
attempt(() => controller.setActiveLayer(layer.id, "pixels"));
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
onContextMenu: (e) => {
|
|
851
|
+
e.preventDefault();
|
|
852
|
+
controller.setActiveLayer(layer.id, state.activeLayerId === layer.id ? state.activeTarget : "pixels");
|
|
853
|
+
setMenu({ x: e.clientX, y: e.clientY });
|
|
854
|
+
},
|
|
855
|
+
className: rowClass(row.active),
|
|
856
|
+
style: { paddingLeft: 6 + row.depth * 14 },
|
|
857
|
+
children: [
|
|
858
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
859
|
+
"button",
|
|
860
|
+
{
|
|
861
|
+
type: "button",
|
|
862
|
+
"aria-label": layer.visible ? `Hide ${row.label}` : `Show ${row.label}`,
|
|
863
|
+
"aria-pressed": layer.visible,
|
|
864
|
+
className: "w-4 text-center text-slate-300",
|
|
865
|
+
onClick: (e) => {
|
|
866
|
+
e.stopPropagation();
|
|
867
|
+
attempt(() => controller.setLayerProperties(layer.id, { visible: !layer.visible }));
|
|
868
|
+
},
|
|
869
|
+
children: layer.visible ? "\u25CF" : "\u25CB"
|
|
870
|
+
}
|
|
871
|
+
),
|
|
872
|
+
layer.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
873
|
+
"button",
|
|
874
|
+
{
|
|
875
|
+
type: "button",
|
|
876
|
+
"aria-label": layer.collapsed ? `Expand ${row.label}` : `Collapse ${row.label}`,
|
|
877
|
+
className: "w-3 text-slate-400",
|
|
878
|
+
onClick: (e) => {
|
|
879
|
+
e.stopPropagation();
|
|
880
|
+
attempt(() => controller.setLayerProperties(layer.id, { collapsed: !layer.collapsed }));
|
|
881
|
+
},
|
|
882
|
+
children: layer.collapsed ? "\u25B8" : "\u25BE"
|
|
883
|
+
}
|
|
884
|
+
),
|
|
885
|
+
row.clipped && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
|
|
886
|
+
layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
887
|
+
Thumbnail,
|
|
888
|
+
{
|
|
889
|
+
pixels: thumb(layer),
|
|
890
|
+
size: thumbnailSize,
|
|
891
|
+
label: `${row.label} pixels`,
|
|
892
|
+
selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
|
|
893
|
+
}
|
|
894
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
895
|
+
"span",
|
|
896
|
+
{
|
|
897
|
+
className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
|
|
898
|
+
style: { width: thumbnailSize, height: thumbnailSize },
|
|
899
|
+
children: (0, import_image_editor6.layerBadge)(layer)
|
|
900
|
+
}
|
|
901
|
+
),
|
|
902
|
+
layer.mask && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
903
|
+
Thumbnail,
|
|
904
|
+
{
|
|
905
|
+
pixels: maskThumb(layer),
|
|
906
|
+
size: thumbnailSize,
|
|
907
|
+
label: `${row.label} mask${layer.mask.enabled === false ? " (disabled)" : ""}`,
|
|
908
|
+
testId: "layer-mask-thumbnail",
|
|
909
|
+
selected: row.active && state.activeTarget === "mask",
|
|
910
|
+
onClick: (e) => {
|
|
911
|
+
e.stopPropagation();
|
|
912
|
+
if (e.shiftKey) attempt(() => controller.setLayerMaskProps(layer.id, { enabled: layer.mask.enabled === false }));
|
|
913
|
+
else attempt(() => controller.setActiveLayer(layer.id, "mask"));
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
),
|
|
917
|
+
renaming === layer.id ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
918
|
+
"input",
|
|
919
|
+
{
|
|
920
|
+
autoFocus: true,
|
|
921
|
+
"aria-label": "Layer name",
|
|
922
|
+
defaultValue: layer.name || row.label,
|
|
923
|
+
className: "flex-1 min-w-0 bg-slate-900 border border-slate-600 rounded px-1",
|
|
924
|
+
onClick: (e) => e.stopPropagation(),
|
|
925
|
+
onBlur: (e) => {
|
|
926
|
+
setRenaming(null);
|
|
927
|
+
if (e.target.value.trim() && e.target.value !== layer.name) attempt(() => controller.setLayerProperties(layer.id, { name: e.target.value }));
|
|
928
|
+
},
|
|
929
|
+
onKeyDown: (e) => {
|
|
930
|
+
if (e.key === "Enter") e.target.blur();
|
|
931
|
+
if (e.key === "Escape") setRenaming(null);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
935
|
+
"span",
|
|
936
|
+
{
|
|
937
|
+
className: `flex-1 min-w-0 truncate ${layer.visible ? "" : "text-slate-500"}`,
|
|
938
|
+
onDoubleClick: (e) => {
|
|
939
|
+
e.stopPropagation();
|
|
940
|
+
setRenaming(layer.id);
|
|
941
|
+
},
|
|
942
|
+
children: row.label
|
|
943
|
+
}
|
|
944
|
+
),
|
|
945
|
+
locked(layer) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
|
|
946
|
+
layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-[9px] text-slate-500", children: layer.blend })
|
|
947
|
+
]
|
|
948
|
+
},
|
|
949
|
+
layer.id
|
|
950
|
+
);
|
|
951
|
+
}) }),
|
|
952
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
|
|
953
|
+
menu && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
954
|
+
"div",
|
|
955
|
+
{
|
|
956
|
+
role: "menu",
|
|
957
|
+
"aria-label": "Layer menu",
|
|
958
|
+
className: "fixed z-50 min-w-44 rounded border border-slate-700 bg-slate-900 py-1 shadow-xl",
|
|
959
|
+
style: { left: menu.x, top: menu.y },
|
|
960
|
+
onClick: (e) => e.stopPropagation(),
|
|
961
|
+
onKeyDown: (e) => e.key === "Escape" && setMenu(null),
|
|
962
|
+
children: (0, import_image_editor6.layerMenu)(controller).map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
963
|
+
"button",
|
|
964
|
+
{
|
|
965
|
+
type: "button",
|
|
966
|
+
role: "menuitem",
|
|
967
|
+
disabled: !item.enabled,
|
|
968
|
+
className: "block w-full px-3 py-1 text-left hover:bg-slate-800 disabled:opacity-40",
|
|
969
|
+
onClick: () => run(item.action),
|
|
970
|
+
children: item.label
|
|
971
|
+
},
|
|
972
|
+
item.action
|
|
973
|
+
))
|
|
974
|
+
}
|
|
975
|
+
)
|
|
976
|
+
] });
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
// src/image-editor/BrushOptionsBar.tsx
|
|
980
|
+
var import_react6 = require("react");
|
|
981
|
+
var import_image_editor7 = require("@pixerate/editor/image-editor");
|
|
982
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
983
|
+
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"}`;
|
|
984
|
+
var BrushOptionsBar = ({ controller, className }) => {
|
|
985
|
+
const [, setTick] = (0, import_react6.useState)(0);
|
|
986
|
+
(0, import_react6.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
987
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
988
|
+
const state = controller.getState();
|
|
989
|
+
const { brush, foreground, background } = state.paint;
|
|
990
|
+
const attempt = (fn) => {
|
|
991
|
+
try {
|
|
992
|
+
setError(null);
|
|
993
|
+
fn();
|
|
994
|
+
} catch (err) {
|
|
995
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor7.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1000
|
+
"button",
|
|
1001
|
+
{
|
|
1002
|
+
type: "button",
|
|
1003
|
+
"aria-pressed": state.activeTool === t.id,
|
|
1004
|
+
title: `${t.label} (${t.shortcut})`,
|
|
1005
|
+
className: chip(state.activeTool === t.id),
|
|
1006
|
+
onClick: () => controller.setTool(t.id),
|
|
1007
|
+
children: t.label
|
|
1008
|
+
},
|
|
1009
|
+
t.id
|
|
1010
|
+
)) }),
|
|
1011
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
|
|
1012
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1013
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1014
|
+
"input",
|
|
1015
|
+
{
|
|
1016
|
+
type: "color",
|
|
1017
|
+
"aria-label": "Foreground colour",
|
|
1018
|
+
value: foreground,
|
|
1019
|
+
onChange: (e) => controller.setPaintOptions({ foreground: e.target.value }),
|
|
1020
|
+
className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
|
|
1021
|
+
}
|
|
1022
|
+
),
|
|
1023
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-400", children: "FG" })
|
|
1024
|
+
] }),
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1026
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1027
|
+
"input",
|
|
1028
|
+
{
|
|
1029
|
+
type: "color",
|
|
1030
|
+
"aria-label": "Background colour",
|
|
1031
|
+
value: background,
|
|
1032
|
+
onChange: (e) => controller.setPaintOptions({ background: e.target.value }),
|
|
1033
|
+
className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
|
|
1034
|
+
}
|
|
1035
|
+
),
|
|
1036
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-400", children: "BG" })
|
|
1037
|
+
] }),
|
|
1038
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
|
|
1039
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
|
|
1040
|
+
] }),
|
|
1041
|
+
import_image_editor7.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1042
|
+
ControlSlider,
|
|
1043
|
+
{
|
|
1044
|
+
spec,
|
|
1045
|
+
value: brush[spec.id],
|
|
1046
|
+
onChange: (v) => controller.setPaintOptions({ brush: { [spec.id]: v } })
|
|
1047
|
+
},
|
|
1048
|
+
spec.id
|
|
1049
|
+
)),
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
|
|
1051
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
1052
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1053
|
+
"input",
|
|
1054
|
+
{
|
|
1055
|
+
type: "checkbox",
|
|
1056
|
+
"aria-label": "Pressure controls size",
|
|
1057
|
+
checked: brush.pressureSize,
|
|
1058
|
+
onChange: (e) => controller.setPaintOptions({ brush: { pressureSize: e.target.checked } }),
|
|
1059
|
+
className: "accent-indigo-500"
|
|
1060
|
+
}
|
|
1061
|
+
),
|
|
1062
|
+
"Pressure size"
|
|
1063
|
+
] }),
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
1065
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1066
|
+
"input",
|
|
1067
|
+
{
|
|
1068
|
+
type: "checkbox",
|
|
1069
|
+
"aria-label": "Pressure controls opacity",
|
|
1070
|
+
checked: brush.pressureOpacity,
|
|
1071
|
+
onChange: (e) => controller.setPaintOptions({ brush: { pressureOpacity: e.target.checked } }),
|
|
1072
|
+
className: "accent-indigo-500"
|
|
1073
|
+
}
|
|
1074
|
+
),
|
|
1075
|
+
"Pressure opacity"
|
|
1076
|
+
] })
|
|
1077
|
+
] }),
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex gap-1", children: [
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
|
|
1080
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
|
|
1081
|
+
] }),
|
|
1082
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
|
|
1083
|
+
] });
|
|
1084
|
+
};
|
|
1085
|
+
|
|
1086
|
+
// src/image-editor/SelectionOptionsBar.tsx
|
|
1087
|
+
var import_react7 = require("react");
|
|
1088
|
+
var import_image_editor8 = require("@pixerate/editor/image-editor");
|
|
1089
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
640
1090
|
var MODIFY_OPS = [
|
|
641
1091
|
{ op: "grow", label: "Grow" },
|
|
642
1092
|
{ op: "shrink", label: "Shrink" },
|
|
@@ -653,20 +1103,20 @@ var SelectionOptionsBar = ({
|
|
|
653
1103
|
quickMask,
|
|
654
1104
|
className = ""
|
|
655
1105
|
}) => {
|
|
656
|
-
const [radius, setRadius] = (0,
|
|
1106
|
+
const [radius, setRadius] = (0, import_react7.useState)(2);
|
|
657
1107
|
const set = (patch) => onOptionsChange({ ...options, ...patch });
|
|
658
1108
|
const sel = selection === void 0 ? controller.getSelection() : selection;
|
|
659
1109
|
const qm = quickMask ?? Boolean(controller.getState().quickMask);
|
|
660
|
-
return /* @__PURE__ */ (0,
|
|
661
|
-
/* @__PURE__ */ (0,
|
|
662
|
-
/* @__PURE__ */ (0,
|
|
663
|
-
options.tool === "wand" && /* @__PURE__ */ (0,
|
|
664
|
-
/* @__PURE__ */ (0,
|
|
665
|
-
/* @__PURE__ */ (0,
|
|
666
|
-
/* @__PURE__ */ (0,
|
|
667
|
-
/* @__PURE__ */ (0,
|
|
1110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
|
|
1111
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor8.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
|
|
1112
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor8.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor8.SELECTION_MODE_LABELS[m] }, m)) }),
|
|
1113
|
+
options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1114
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1115
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1116
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Tolerance" }),
|
|
1117
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-mono", children: options.tolerance })
|
|
668
1118
|
] }),
|
|
669
|
-
/* @__PURE__ */ (0,
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
670
1120
|
"input",
|
|
671
1121
|
{
|
|
672
1122
|
type: "range",
|
|
@@ -680,29 +1130,29 @@ var SelectionOptionsBar = ({
|
|
|
680
1130
|
}
|
|
681
1131
|
)
|
|
682
1132
|
] }),
|
|
683
|
-
/* @__PURE__ */ (0,
|
|
684
|
-
/* @__PURE__ */ (0,
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1134
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
|
|
685
1135
|
"Contiguous"
|
|
686
1136
|
] }),
|
|
687
|
-
/* @__PURE__ */ (0,
|
|
688
|
-
/* @__PURE__ */ (0,
|
|
1137
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
|
|
689
1139
|
"Sample adjusted image"
|
|
690
1140
|
] })
|
|
691
1141
|
] }),
|
|
692
|
-
/* @__PURE__ */ (0,
|
|
693
|
-
/* @__PURE__ */ (0,
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
|
|
694
1144
|
"Anti-alias"
|
|
695
1145
|
] }),
|
|
696
|
-
/* @__PURE__ */ (0,
|
|
697
|
-
/* @__PURE__ */ (0,
|
|
698
|
-
/* @__PURE__ */ (0,
|
|
699
|
-
/* @__PURE__ */ (0,
|
|
700
|
-
/* @__PURE__ */ (0,
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
1147
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
|
|
1148
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
|
|
701
1151
|
] }),
|
|
702
|
-
/* @__PURE__ */ (0,
|
|
703
|
-
/* @__PURE__ */ (0,
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
|
|
704
1154
|
"Radius",
|
|
705
|
-
/* @__PURE__ */ (0,
|
|
1155
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
706
1156
|
"input",
|
|
707
1157
|
{
|
|
708
1158
|
type: "number",
|
|
@@ -716,24 +1166,24 @@ var SelectionOptionsBar = ({
|
|
|
716
1166
|
}
|
|
717
1167
|
)
|
|
718
1168
|
] }),
|
|
719
|
-
MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0,
|
|
1169
|
+
MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
|
|
720
1170
|
] }),
|
|
721
|
-
/* @__PURE__ */ (0,
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor8.describeSelection)(sel) })
|
|
722
1172
|
] });
|
|
723
1173
|
};
|
|
724
1174
|
|
|
725
1175
|
// src/image-editor/RefineEdgePanel.tsx
|
|
726
|
-
var
|
|
727
|
-
var
|
|
728
|
-
var
|
|
1176
|
+
var import_react8 = require("react");
|
|
1177
|
+
var import_image_editor9 = require("@pixerate/editor/image-editor");
|
|
1178
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
729
1179
|
var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
|
|
730
1180
|
var button = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
|
|
731
1181
|
var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
732
|
-
const [params, setParams] = (0,
|
|
733
|
-
const [busy, setBusy] = (0,
|
|
734
|
-
const [error, setError] = (0,
|
|
735
|
-
const [layerId, setLayerId] = (0,
|
|
736
|
-
const [newKind, setNewKind] = (0,
|
|
1182
|
+
const [params, setParams] = (0, import_react8.useState)(DEFAULT_PARAMS);
|
|
1183
|
+
const [busy, setBusy] = (0, import_react8.useState)(false);
|
|
1184
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1185
|
+
const [layerId, setLayerId] = (0, import_react8.useState)("");
|
|
1186
|
+
const [newKind, setNewKind] = (0, import_react8.useState)("hueSaturation");
|
|
737
1187
|
const sel = selection === void 0 ? controller.getSelection() : selection;
|
|
738
1188
|
const list = layers ?? controller.getAdjustmentLayers();
|
|
739
1189
|
const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
|
|
@@ -748,17 +1198,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
748
1198
|
setBusy(false);
|
|
749
1199
|
}
|
|
750
1200
|
};
|
|
751
|
-
return /* @__PURE__ */ (0,
|
|
752
|
-
/* @__PURE__ */ (0,
|
|
753
|
-
|
|
754
|
-
/* @__PURE__ */ (0,
|
|
755
|
-
/* @__PURE__ */ (0,
|
|
756
|
-
/* @__PURE__ */ (0,
|
|
1201
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
|
|
1202
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
|
|
1203
|
+
import_image_editor9.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1205
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: c.label }),
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "font-mono", children: [
|
|
757
1207
|
params[c.id],
|
|
758
1208
|
c.unit
|
|
759
1209
|
] })
|
|
760
1210
|
] }),
|
|
761
|
-
/* @__PURE__ */ (0,
|
|
1211
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
762
1212
|
"input",
|
|
763
1213
|
{
|
|
764
1214
|
type: "range",
|
|
@@ -772,67 +1222,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
772
1222
|
}
|
|
773
1223
|
)
|
|
774
1224
|
] }, c.id)),
|
|
775
|
-
/* @__PURE__ */ (0,
|
|
776
|
-
/* @__PURE__ */ (0,
|
|
1225
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1226
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
|
|
777
1227
|
"Smart Radius"
|
|
778
1228
|
] }),
|
|
779
|
-
/* @__PURE__ */ (0,
|
|
780
|
-
/* @__PURE__ */ (0,
|
|
781
|
-
/* @__PURE__ */ (0,
|
|
1229
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-1", children: [
|
|
1230
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
|
|
1231
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
|
|
782
1232
|
] }),
|
|
783
|
-
error && /* @__PURE__ */ (0,
|
|
784
|
-
/* @__PURE__ */ (0,
|
|
785
|
-
/* @__PURE__ */ (0,
|
|
786
|
-
/* @__PURE__ */ (0,
|
|
1233
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
|
|
1234
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
|
|
1235
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-1 items-center", children: [
|
|
1236
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
787
1237
|
"select",
|
|
788
1238
|
{
|
|
789
1239
|
"aria-label": "New masked layer kind",
|
|
790
1240
|
value: newKind,
|
|
791
1241
|
onChange: (e) => setNewKind(e.target.value),
|
|
792
1242
|
className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
|
|
793
|
-
children:
|
|
1243
|
+
children: import_image_editor9.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: k.kind, children: k.label }, k.kind))
|
|
794
1244
|
}
|
|
795
1245
|
),
|
|
796
|
-
/* @__PURE__ */ (0,
|
|
1246
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
797
1247
|
"button",
|
|
798
1248
|
{
|
|
799
1249
|
type: "button",
|
|
800
1250
|
className: button,
|
|
801
1251
|
disabled: !sel,
|
|
802
|
-
onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0,
|
|
1252
|
+
onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor9.layerMaskFromSelection)(sel) })),
|
|
803
1253
|
children: "New Masked Layer"
|
|
804
1254
|
}
|
|
805
1255
|
)
|
|
806
1256
|
] }),
|
|
807
|
-
list.length > 0 && target && /* @__PURE__ */ (0,
|
|
808
|
-
/* @__PURE__ */ (0,
|
|
1257
|
+
list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
809
1259
|
"select",
|
|
810
1260
|
{
|
|
811
1261
|
"aria-label": "Mask layer",
|
|
812
1262
|
value: target.id,
|
|
813
1263
|
onChange: (e) => setLayerId(e.target.value),
|
|
814
1264
|
className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
|
|
815
|
-
children: list.map((l) => /* @__PURE__ */ (0,
|
|
816
|
-
l.name || (0,
|
|
1265
|
+
children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("option", { value: l.id, children: [
|
|
1266
|
+
l.name || (0, import_image_editor9.adjustmentKindLabel)(l.kind),
|
|
817
1267
|
l.mask ? " (masked)" : ""
|
|
818
1268
|
] }, l.id))
|
|
819
1269
|
}
|
|
820
1270
|
),
|
|
821
|
-
/* @__PURE__ */ (0,
|
|
822
|
-
/* @__PURE__ */ (0,
|
|
823
|
-
/* @__PURE__ */ (0,
|
|
824
|
-
/* @__PURE__ */ (0,
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
|
|
1273
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
|
|
1274
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
|
|
825
1275
|
] }),
|
|
826
|
-
target.mask && /* @__PURE__ */ (0,
|
|
827
|
-
/* @__PURE__ */ (0,
|
|
828
|
-
/* @__PURE__ */ (0,
|
|
829
|
-
/* @__PURE__ */ (0,
|
|
830
|
-
/* @__PURE__ */ (0,
|
|
1276
|
+
target.mask && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1277
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Density" }),
|
|
1280
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "font-mono", children: [
|
|
831
1281
|
Math.round((target.mask.density ?? 1) * 100),
|
|
832
1282
|
"%"
|
|
833
1283
|
] })
|
|
834
1284
|
] }),
|
|
835
|
-
/* @__PURE__ */ (0,
|
|
1285
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
836
1286
|
"input",
|
|
837
1287
|
{
|
|
838
1288
|
type: "range",
|
|
@@ -846,15 +1296,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
846
1296
|
}
|
|
847
1297
|
)
|
|
848
1298
|
] }),
|
|
849
|
-
/* @__PURE__ */ (0,
|
|
850
|
-
/* @__PURE__ */ (0,
|
|
851
|
-
/* @__PURE__ */ (0,
|
|
852
|
-
/* @__PURE__ */ (0,
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1300
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1301
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Mask Feather" }),
|
|
1302
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "font-mono", children: [
|
|
853
1303
|
target.mask.feather ?? 0,
|
|
854
1304
|
"px"
|
|
855
1305
|
] })
|
|
856
1306
|
] }),
|
|
857
|
-
/* @__PURE__ */ (0,
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
858
1308
|
"input",
|
|
859
1309
|
{
|
|
860
1310
|
type: "range",
|
|
@@ -874,7 +1324,7 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
874
1324
|
};
|
|
875
1325
|
|
|
876
1326
|
// src/image-editor/ImageEditor.tsx
|
|
877
|
-
var
|
|
1327
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
878
1328
|
var ImageEditor = ({
|
|
879
1329
|
editor: externalEditor,
|
|
880
1330
|
src,
|
|
@@ -889,26 +1339,34 @@ var ImageEditor = ({
|
|
|
889
1339
|
const internalEditor = useImageEditor({ image: src });
|
|
890
1340
|
const editor = externalEditor || internalEditor;
|
|
891
1341
|
const { state, controller } = editor;
|
|
892
|
-
const legacyProcess = (0,
|
|
893
|
-
const canvasRef = (0,
|
|
894
|
-
const containerRef = (0,
|
|
895
|
-
const [activeTab, setActiveTab] = (0,
|
|
896
|
-
const [activeCropRatio, setActiveCropRatio] = (0,
|
|
897
|
-
const [selectionOptions, setSelectionOptions] = (0,
|
|
898
|
-
const selectionOptionsRef = (0,
|
|
1342
|
+
const legacyProcess = (0, import_image_editor10.normalizeProcessVersion)(state.adjustments.process) < import_image_editor10.LATEST_PROCESS_VERSION;
|
|
1343
|
+
const canvasRef = (0, import_react9.useRef)(null);
|
|
1344
|
+
const containerRef = (0, import_react9.useRef)(null);
|
|
1345
|
+
const [activeTab, setActiveTab] = (0, import_react9.useState)("crop");
|
|
1346
|
+
const [activeCropRatio, setActiveCropRatio] = (0, import_react9.useState)(null);
|
|
1347
|
+
const [selectionOptions, setSelectionOptions] = (0, import_react9.useState)(import_image_editor10.DEFAULT_SELECTION_TOOL_OPTIONS);
|
|
1348
|
+
const selectionOptionsRef = (0, import_react9.useRef)(selectionOptions);
|
|
899
1349
|
selectionOptionsRef.current = selectionOptions;
|
|
900
|
-
const selectionGestureRef = (0,
|
|
1350
|
+
const selectionGestureRef = (0, import_react9.useRef)(null);
|
|
901
1351
|
if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
|
|
902
|
-
selectionGestureRef.current = new
|
|
1352
|
+
selectionGestureRef.current = new import_image_editor10.SelectionGesture(controller, () => selectionOptionsRef.current);
|
|
1353
|
+
}
|
|
1354
|
+
const selectionDraftRef = (0, import_react9.useRef)(null);
|
|
1355
|
+
const [selectionError, setSelectionError] = (0, import_react9.useState)(null);
|
|
1356
|
+
const paintGestureRef = (0, import_react9.useRef)(null);
|
|
1357
|
+
const paintControllerRef = (0, import_react9.useRef)(controller);
|
|
1358
|
+
if (!paintGestureRef.current || paintControllerRef.current !== controller) {
|
|
1359
|
+
paintGestureRef.current = new import_image_editor10.PaintGesture(controller);
|
|
1360
|
+
paintControllerRef.current = controller;
|
|
903
1361
|
}
|
|
904
|
-
const
|
|
905
|
-
const [
|
|
906
|
-
const [inpaintPrompt, setInpaintPrompt] = (0,
|
|
907
|
-
const [inpaintMaskMode, setInpaintMaskMode] = (0,
|
|
908
|
-
const [isRemovingBg, setIsRemovingBg] = (0,
|
|
909
|
-
const [isInpainting, setIsInpainting] = (0,
|
|
910
|
-
const [aiError, setAiError] = (0,
|
|
911
|
-
const [aiSuccess, setAiSuccess] = (0,
|
|
1362
|
+
const brushCursorRef = (0, import_react9.useRef)(null);
|
|
1363
|
+
const [paintError, setPaintError] = (0, import_react9.useState)(null);
|
|
1364
|
+
const [inpaintPrompt, setInpaintPrompt] = (0, import_react9.useState)("");
|
|
1365
|
+
const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react9.useState)("annotations");
|
|
1366
|
+
const [isRemovingBg, setIsRemovingBg] = (0, import_react9.useState)(false);
|
|
1367
|
+
const [isInpainting, setIsInpainting] = (0, import_react9.useState)(false);
|
|
1368
|
+
const [aiError, setAiError] = (0, import_react9.useState)(null);
|
|
1369
|
+
const [aiSuccess, setAiSuccess] = (0, import_react9.useState)(null);
|
|
912
1370
|
const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
|
|
913
1371
|
const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
|
|
914
1372
|
const handleRemoveBackground = async () => {
|
|
@@ -970,18 +1428,18 @@ var ImageEditor = ({
|
|
|
970
1428
|
setIsInpainting(false);
|
|
971
1429
|
}
|
|
972
1430
|
};
|
|
973
|
-
const [activeColor, setActiveColor] = (0,
|
|
974
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
975
|
-
const [fontSize, setFontSize] = (0,
|
|
976
|
-
const [textInput, setTextInput] = (0,
|
|
977
|
-
const draftAnnotationRef = (0,
|
|
978
|
-
const draftCropRef = (0,
|
|
979
|
-
const cropDragInfoRef = (0,
|
|
980
|
-
const annotationDragInfoRef = (0,
|
|
981
|
-
const isDrawingRef = (0,
|
|
982
|
-
const currentPathRef = (0,
|
|
983
|
-
const dragStartPointRef = (0,
|
|
984
|
-
const renderCanvas = (0,
|
|
1431
|
+
const [activeColor, setActiveColor] = (0, import_react9.useState)("#ef4444");
|
|
1432
|
+
const [strokeWidth, setStrokeWidth] = (0, import_react9.useState)(3);
|
|
1433
|
+
const [fontSize, setFontSize] = (0, import_react9.useState)(24);
|
|
1434
|
+
const [textInput, setTextInput] = (0, import_react9.useState)("");
|
|
1435
|
+
const draftAnnotationRef = (0, import_react9.useRef)(null);
|
|
1436
|
+
const draftCropRef = (0, import_react9.useRef)(null);
|
|
1437
|
+
const cropDragInfoRef = (0, import_react9.useRef)(null);
|
|
1438
|
+
const annotationDragInfoRef = (0, import_react9.useRef)(null);
|
|
1439
|
+
const isDrawingRef = (0, import_react9.useRef)(false);
|
|
1440
|
+
const currentPathRef = (0, import_react9.useRef)([]);
|
|
1441
|
+
const dragStartPointRef = (0, import_react9.useRef)(null);
|
|
1442
|
+
const renderCanvas = (0, import_react9.useCallback)(
|
|
985
1443
|
async (draftAnnotation, draftCrop) => {
|
|
986
1444
|
const canvas = canvasRef.current;
|
|
987
1445
|
const container = containerRef.current;
|
|
@@ -996,12 +1454,13 @@ var ImageEditor = ({
|
|
|
996
1454
|
interactive: true,
|
|
997
1455
|
draftAnnotation: draftAnnotation !== void 0 ? draftAnnotation : draftAnnotationRef.current,
|
|
998
1456
|
draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
|
|
999
|
-
draftSelectionPath: selectionDraftRef.current
|
|
1457
|
+
draftSelectionPath: selectionDraftRef.current,
|
|
1458
|
+
brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null
|
|
1000
1459
|
});
|
|
1001
1460
|
},
|
|
1002
1461
|
[controller, activeTab]
|
|
1003
1462
|
);
|
|
1004
|
-
(0,
|
|
1463
|
+
(0, import_react9.useEffect)(() => {
|
|
1005
1464
|
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
1006
1465
|
const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
1007
1466
|
const animId = raf(() => {
|
|
@@ -1009,12 +1468,12 @@ var ImageEditor = ({
|
|
|
1009
1468
|
});
|
|
1010
1469
|
return () => caf(animId);
|
|
1011
1470
|
}, [renderCanvas, state]);
|
|
1012
|
-
(0,
|
|
1471
|
+
(0, import_react9.useEffect)(() => {
|
|
1013
1472
|
if (activeTab === "crop" && editor.state.activeTool !== "crop") {
|
|
1014
1473
|
editor.setTool("crop");
|
|
1015
1474
|
}
|
|
1016
1475
|
}, [activeTab, editor]);
|
|
1017
|
-
(0,
|
|
1476
|
+
(0, import_react9.useEffect)(() => {
|
|
1018
1477
|
const container = containerRef.current;
|
|
1019
1478
|
if (!container) return;
|
|
1020
1479
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -1040,13 +1499,60 @@ var ImageEditor = ({
|
|
|
1040
1499
|
y: (e.clientY - rect.top) * scaleY
|
|
1041
1500
|
};
|
|
1042
1501
|
};
|
|
1502
|
+
const paintSamples = (e) => {
|
|
1503
|
+
const canvas = canvasRef.current;
|
|
1504
|
+
const native = e.nativeEvent;
|
|
1505
|
+
const events = typeof native.getCoalescedEvents === "function" ? native.getCoalescedEvents() : [];
|
|
1506
|
+
const list = events.length ? events : [native];
|
|
1507
|
+
const rect = canvas.getBoundingClientRect();
|
|
1508
|
+
const sx = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
1509
|
+
const sy = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
1510
|
+
const s = controller.getState();
|
|
1511
|
+
return list.map((ev) => ({
|
|
1512
|
+
...(0, import_image_editor10.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
|
|
1513
|
+
pressure: (0, import_image_editor10.pointerPressure)(ev)
|
|
1514
|
+
}));
|
|
1515
|
+
};
|
|
1516
|
+
const handlePaintPointerDown = (e) => {
|
|
1517
|
+
if (activeTab !== "paint" || e.button !== 0) return;
|
|
1518
|
+
e.preventDefault();
|
|
1519
|
+
try {
|
|
1520
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
1521
|
+
} catch {
|
|
1522
|
+
}
|
|
1523
|
+
const [first] = paintSamples(e);
|
|
1524
|
+
setPaintError(paintGestureRef.current.down(first));
|
|
1525
|
+
};
|
|
1526
|
+
const handlePaintPointerMove = (e) => {
|
|
1527
|
+
if (activeTab !== "paint") return;
|
|
1528
|
+
const samples = paintSamples(e);
|
|
1529
|
+
brushCursorRef.current = samples[samples.length - 1] ?? null;
|
|
1530
|
+
if (paintGestureRef.current.active) paintGestureRef.current.moveTo(samples);
|
|
1531
|
+
else void renderCanvas();
|
|
1532
|
+
};
|
|
1533
|
+
const handlePaintPointerUp = () => {
|
|
1534
|
+
if (activeTab !== "paint") return;
|
|
1535
|
+
const g = paintGestureRef.current;
|
|
1536
|
+
if (g.active) {
|
|
1537
|
+
g.up();
|
|
1538
|
+
if (g.error) setPaintError(g.error);
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
(0, import_react9.useEffect)(() => {
|
|
1542
|
+
if (activeTab !== "paint" || typeof window === "undefined") return;
|
|
1543
|
+
const onKey = (e) => {
|
|
1544
|
+
if ((0, import_image_editor10.handlePaintShortcut)(controller, e)) e.preventDefault();
|
|
1545
|
+
};
|
|
1546
|
+
window.addEventListener("keydown", onKey);
|
|
1547
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
1548
|
+
}, [activeTab, controller]);
|
|
1043
1549
|
const handleMouseDown = (e) => {
|
|
1044
1550
|
const canvas = canvasRef.current;
|
|
1045
1551
|
if (!canvas) return;
|
|
1046
1552
|
const canvasPt = getCanvasEventPoint(e);
|
|
1047
1553
|
if (activeTab === "select") {
|
|
1048
1554
|
const gesture = selectionGestureRef.current;
|
|
1049
|
-
const imgPt = (0,
|
|
1555
|
+
const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1050
1556
|
void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
|
|
1051
1557
|
return;
|
|
1052
1558
|
}
|
|
@@ -1057,8 +1563,8 @@ var ImageEditor = ({
|
|
|
1057
1563
|
width: state.imageDimensions.width,
|
|
1058
1564
|
height: state.imageDimensions.height
|
|
1059
1565
|
};
|
|
1060
|
-
const handle = (0,
|
|
1061
|
-
const startImgPt = (0,
|
|
1566
|
+
const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
1567
|
+
const startImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
1062
1568
|
if (handle) {
|
|
1063
1569
|
cropDragInfoRef.current = {
|
|
1064
1570
|
handle,
|
|
@@ -1077,12 +1583,12 @@ var ImageEditor = ({
|
|
|
1077
1583
|
return;
|
|
1078
1584
|
}
|
|
1079
1585
|
if (activeTab === "annotate") {
|
|
1080
|
-
const imgPt = (0,
|
|
1586
|
+
const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1081
1587
|
dragStartPointRef.current = imgPt;
|
|
1082
1588
|
if (state.activeTool === "select") {
|
|
1083
1589
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
1084
1590
|
const ann = state.annotations[i];
|
|
1085
|
-
if ((0,
|
|
1591
|
+
if ((0, import_image_editor10.hitTestAnnotation)(imgPt, ann)) {
|
|
1086
1592
|
editor.selectAnnotation(ann.id);
|
|
1087
1593
|
annotationDragInfoRef.current = {
|
|
1088
1594
|
annId: ann.id,
|
|
@@ -1118,7 +1624,7 @@ var ImageEditor = ({
|
|
|
1118
1624
|
const canvasPt = getCanvasEventPoint(e);
|
|
1119
1625
|
if (activeTab === "select") {
|
|
1120
1626
|
const gesture = selectionGestureRef.current;
|
|
1121
|
-
if (gesture.active && gesture.move((0,
|
|
1627
|
+
if (gesture.active && gesture.move((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
|
|
1122
1628
|
selectionDraftRef.current = gesture.draftPath;
|
|
1123
1629
|
renderCanvas();
|
|
1124
1630
|
}
|
|
@@ -1127,7 +1633,7 @@ var ImageEditor = ({
|
|
|
1127
1633
|
if (activeTab === "crop") {
|
|
1128
1634
|
const drag = cropDragInfoRef.current;
|
|
1129
1635
|
if (drag) {
|
|
1130
|
-
const currentImgPt = (0,
|
|
1636
|
+
const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
1131
1637
|
let newCrop;
|
|
1132
1638
|
if (drag.handle === "new") {
|
|
1133
1639
|
const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
|
|
@@ -1141,7 +1647,7 @@ var ImageEditor = ({
|
|
|
1141
1647
|
height: Math.round(Math.max(20, maxY - minY))
|
|
1142
1648
|
};
|
|
1143
1649
|
} else {
|
|
1144
|
-
newCrop = (0,
|
|
1650
|
+
newCrop = (0, import_image_editor10.calculateCropDrag)(
|
|
1145
1651
|
drag.startCrop,
|
|
1146
1652
|
drag.handle,
|
|
1147
1653
|
drag.startImgPt,
|
|
@@ -1161,15 +1667,15 @@ var ImageEditor = ({
|
|
|
1161
1667
|
width: state.imageDimensions.width,
|
|
1162
1668
|
height: state.imageDimensions.height
|
|
1163
1669
|
};
|
|
1164
|
-
const handle = (0,
|
|
1165
|
-
canvas.style.cursor = (0,
|
|
1670
|
+
const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
1671
|
+
canvas.style.cursor = (0, import_image_editor10.getCropCursor)(handle, state.transform);
|
|
1166
1672
|
}
|
|
1167
1673
|
return;
|
|
1168
1674
|
}
|
|
1169
1675
|
if (activeTab === "annotate") {
|
|
1170
1676
|
if (annotationDragInfoRef.current) {
|
|
1171
1677
|
const drag = annotationDragInfoRef.current;
|
|
1172
|
-
const currentImgPt2 = (0,
|
|
1678
|
+
const currentImgPt2 = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1173
1679
|
const dx = currentImgPt2.x - drag.startImgPt.x;
|
|
1174
1680
|
const dy = currentImgPt2.y - drag.startImgPt.y;
|
|
1175
1681
|
editor.updateAnnotation(drag.annId, {
|
|
@@ -1181,10 +1687,10 @@ var ImageEditor = ({
|
|
|
1181
1687
|
const startPt = dragStartPointRef.current;
|
|
1182
1688
|
if (!startPt) {
|
|
1183
1689
|
if (state.activeTool === "select") {
|
|
1184
|
-
const imgPt = (0,
|
|
1690
|
+
const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1185
1691
|
let hovered = false;
|
|
1186
1692
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
1187
|
-
if ((0,
|
|
1693
|
+
if ((0, import_image_editor10.hitTestAnnotation)(imgPt, state.annotations[i])) {
|
|
1188
1694
|
hovered = true;
|
|
1189
1695
|
break;
|
|
1190
1696
|
}
|
|
@@ -1195,7 +1701,7 @@ var ImageEditor = ({
|
|
|
1195
1701
|
}
|
|
1196
1702
|
return;
|
|
1197
1703
|
}
|
|
1198
|
-
const currentImgPt = (0,
|
|
1704
|
+
const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1199
1705
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
1200
1706
|
currentPathRef.current.push(currentImgPt);
|
|
1201
1707
|
const draft = {
|
|
@@ -1275,7 +1781,7 @@ var ImageEditor = ({
|
|
|
1275
1781
|
if (activeTab === "select") {
|
|
1276
1782
|
const gesture = selectionGestureRef.current;
|
|
1277
1783
|
if (gesture.active) {
|
|
1278
|
-
gesture.end((0,
|
|
1784
|
+
gesture.end((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
|
|
1279
1785
|
selectionDraftRef.current = null;
|
|
1280
1786
|
renderCanvas();
|
|
1281
1787
|
}
|
|
@@ -1299,7 +1805,7 @@ var ImageEditor = ({
|
|
|
1299
1805
|
}
|
|
1300
1806
|
const startPt = dragStartPointRef.current;
|
|
1301
1807
|
if (startPt) {
|
|
1302
|
-
const currentImgPt = (0,
|
|
1808
|
+
const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1303
1809
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
1304
1810
|
if (currentPathRef.current.length > 1) {
|
|
1305
1811
|
editor.addAnnotation({
|
|
@@ -1395,15 +1901,15 @@ var ImageEditor = ({
|
|
|
1395
1901
|
link.click();
|
|
1396
1902
|
}
|
|
1397
1903
|
};
|
|
1398
|
-
return /* @__PURE__ */ (0,
|
|
1904
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1399
1905
|
"div",
|
|
1400
1906
|
{
|
|
1401
1907
|
className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
|
|
1402
1908
|
style,
|
|
1403
1909
|
children: [
|
|
1404
|
-
/* @__PURE__ */ (0,
|
|
1405
|
-
/* @__PURE__ */ (0,
|
|
1406
|
-
/* @__PURE__ */ (0,
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
|
|
1912
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1407
1913
|
"button",
|
|
1408
1914
|
{
|
|
1409
1915
|
type: "button",
|
|
@@ -1415,7 +1921,7 @@ var ImageEditor = ({
|
|
|
1415
1921
|
children: "Transform & Crop"
|
|
1416
1922
|
}
|
|
1417
1923
|
),
|
|
1418
|
-
/* @__PURE__ */ (0,
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1419
1925
|
"button",
|
|
1420
1926
|
{
|
|
1421
1927
|
type: "button",
|
|
@@ -1427,7 +1933,31 @@ var ImageEditor = ({
|
|
|
1427
1933
|
children: "Adjustments"
|
|
1428
1934
|
}
|
|
1429
1935
|
),
|
|
1430
|
-
/* @__PURE__ */ (0,
|
|
1936
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1937
|
+
"button",
|
|
1938
|
+
{
|
|
1939
|
+
type: "button",
|
|
1940
|
+
onClick: () => {
|
|
1941
|
+
setActiveTab("layers");
|
|
1942
|
+
editor.setTool("select");
|
|
1943
|
+
},
|
|
1944
|
+
className: `px-3 py-1.5 rounded-md font-medium transition-colors ${activeTab === "layers" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
|
|
1945
|
+
children: "Layers"
|
|
1946
|
+
}
|
|
1947
|
+
),
|
|
1948
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1949
|
+
"button",
|
|
1950
|
+
{
|
|
1951
|
+
type: "button",
|
|
1952
|
+
onClick: () => {
|
|
1953
|
+
setActiveTab("paint");
|
|
1954
|
+
editor.setTool("brush");
|
|
1955
|
+
},
|
|
1956
|
+
className: `px-3 py-1.5 rounded-md font-medium transition-colors ${activeTab === "paint" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
|
|
1957
|
+
children: "Paint"
|
|
1958
|
+
}
|
|
1959
|
+
),
|
|
1960
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1431
1961
|
"button",
|
|
1432
1962
|
{
|
|
1433
1963
|
type: "button",
|
|
@@ -1439,7 +1969,7 @@ var ImageEditor = ({
|
|
|
1439
1969
|
children: "Select & Mask"
|
|
1440
1970
|
}
|
|
1441
1971
|
),
|
|
1442
|
-
/* @__PURE__ */ (0,
|
|
1972
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1443
1973
|
"button",
|
|
1444
1974
|
{
|
|
1445
1975
|
type: "button",
|
|
@@ -1451,7 +1981,7 @@ var ImageEditor = ({
|
|
|
1451
1981
|
children: "Annotations"
|
|
1452
1982
|
}
|
|
1453
1983
|
),
|
|
1454
|
-
/* @__PURE__ */ (0,
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1455
1985
|
"button",
|
|
1456
1986
|
{
|
|
1457
1987
|
type: "button",
|
|
@@ -1463,7 +1993,7 @@ var ImageEditor = ({
|
|
|
1463
1993
|
children: "Depth Mask"
|
|
1464
1994
|
}
|
|
1465
1995
|
),
|
|
1466
|
-
/* @__PURE__ */ (0,
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1467
1997
|
"button",
|
|
1468
1998
|
{
|
|
1469
1999
|
type: "button",
|
|
@@ -1473,14 +2003,14 @@ var ImageEditor = ({
|
|
|
1473
2003
|
},
|
|
1474
2004
|
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"}`,
|
|
1475
2005
|
children: [
|
|
1476
|
-
/* @__PURE__ */ (0,
|
|
2006
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
1477
2007
|
"AI Tools"
|
|
1478
2008
|
]
|
|
1479
2009
|
}
|
|
1480
2010
|
)
|
|
1481
2011
|
] }),
|
|
1482
|
-
/* @__PURE__ */ (0,
|
|
1483
|
-
/* @__PURE__ */ (0,
|
|
2012
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
2013
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1484
2014
|
"button",
|
|
1485
2015
|
{
|
|
1486
2016
|
type: "button",
|
|
@@ -1491,7 +2021,7 @@ var ImageEditor = ({
|
|
|
1491
2021
|
children: "\u21A9"
|
|
1492
2022
|
}
|
|
1493
2023
|
),
|
|
1494
|
-
/* @__PURE__ */ (0,
|
|
2024
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1495
2025
|
"button",
|
|
1496
2026
|
{
|
|
1497
2027
|
type: "button",
|
|
@@ -1502,7 +2032,7 @@ var ImageEditor = ({
|
|
|
1502
2032
|
children: "\u21AA"
|
|
1503
2033
|
}
|
|
1504
2034
|
),
|
|
1505
|
-
/* @__PURE__ */ (0,
|
|
2035
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1506
2036
|
"button",
|
|
1507
2037
|
{
|
|
1508
2038
|
type: "button",
|
|
@@ -1511,8 +2041,8 @@ var ImageEditor = ({
|
|
|
1511
2041
|
children: "Reset"
|
|
1512
2042
|
}
|
|
1513
2043
|
),
|
|
1514
|
-
/* @__PURE__ */ (0,
|
|
1515
|
-
/* @__PURE__ */ (0,
|
|
2044
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
2045
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1516
2046
|
"button",
|
|
1517
2047
|
{
|
|
1518
2048
|
type: "button",
|
|
@@ -1522,11 +2052,11 @@ var ImageEditor = ({
|
|
|
1522
2052
|
children: "-"
|
|
1523
2053
|
}
|
|
1524
2054
|
),
|
|
1525
|
-
/* @__PURE__ */ (0,
|
|
2055
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
|
|
1526
2056
|
Math.round(state.zoom * 100),
|
|
1527
2057
|
"%"
|
|
1528
2058
|
] }),
|
|
1529
|
-
/* @__PURE__ */ (0,
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1530
2060
|
"button",
|
|
1531
2061
|
{
|
|
1532
2062
|
type: "button",
|
|
@@ -1536,8 +2066,8 @@ var ImageEditor = ({
|
|
|
1536
2066
|
children: "+"
|
|
1537
2067
|
}
|
|
1538
2068
|
),
|
|
1539
|
-
/* @__PURE__ */ (0,
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
2069
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
2070
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1541
2071
|
"button",
|
|
1542
2072
|
{
|
|
1543
2073
|
type: "button",
|
|
@@ -1548,7 +2078,7 @@ var ImageEditor = ({
|
|
|
1548
2078
|
children: "Hold Compare"
|
|
1549
2079
|
}
|
|
1550
2080
|
),
|
|
1551
|
-
/* @__PURE__ */ (0,
|
|
2081
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1552
2082
|
"button",
|
|
1553
2083
|
{
|
|
1554
2084
|
type: "button",
|
|
@@ -1559,13 +2089,13 @@ var ImageEditor = ({
|
|
|
1559
2089
|
)
|
|
1560
2090
|
] })
|
|
1561
2091
|
] }),
|
|
1562
|
-
/* @__PURE__ */ (0,
|
|
1563
|
-
/* @__PURE__ */ (0,
|
|
2092
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
|
|
2093
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1564
2094
|
"div",
|
|
1565
2095
|
{
|
|
1566
2096
|
ref: containerRef,
|
|
1567
2097
|
className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
|
|
1568
|
-
children: /* @__PURE__ */ (0,
|
|
2098
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1569
2099
|
"canvas",
|
|
1570
2100
|
{
|
|
1571
2101
|
ref: canvasRef,
|
|
@@ -1573,16 +2103,21 @@ var ImageEditor = ({
|
|
|
1573
2103
|
onMouseMove: handleMouseMove,
|
|
1574
2104
|
onMouseUp: handleMouseUp,
|
|
1575
2105
|
onMouseLeave: handleMouseUp,
|
|
1576
|
-
|
|
2106
|
+
onPointerDown: handlePaintPointerDown,
|
|
2107
|
+
onPointerMove: handlePaintPointerMove,
|
|
2108
|
+
onPointerUp: handlePaintPointerUp,
|
|
2109
|
+
onPointerCancel: () => paintGestureRef.current?.cancel(),
|
|
2110
|
+
"data-testid": "image-editor-canvas",
|
|
2111
|
+
className: `absolute inset-0 w-full h-full block ${activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
|
|
1577
2112
|
}
|
|
1578
2113
|
)
|
|
1579
2114
|
}
|
|
1580
2115
|
),
|
|
1581
|
-
/* @__PURE__ */ (0,
|
|
1582
|
-
activeTab === "crop" && /* @__PURE__ */ (0,
|
|
1583
|
-
/* @__PURE__ */ (0,
|
|
1584
|
-
/* @__PURE__ */ (0,
|
|
1585
|
-
/* @__PURE__ */ (0,
|
|
2116
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
|
|
2117
|
+
activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
|
|
2119
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
2120
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1586
2121
|
"button",
|
|
1587
2122
|
{
|
|
1588
2123
|
type: "button",
|
|
@@ -1594,7 +2129,7 @@ var ImageEditor = ({
|
|
|
1594
2129
|
children: "Freeform"
|
|
1595
2130
|
}
|
|
1596
2131
|
),
|
|
1597
|
-
/* @__PURE__ */ (0,
|
|
2132
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1598
2133
|
"button",
|
|
1599
2134
|
{
|
|
1600
2135
|
type: "button",
|
|
@@ -1606,7 +2141,7 @@ var ImageEditor = ({
|
|
|
1606
2141
|
children: "1:1 Square"
|
|
1607
2142
|
}
|
|
1608
2143
|
),
|
|
1609
|
-
/* @__PURE__ */ (0,
|
|
2144
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1610
2145
|
"button",
|
|
1611
2146
|
{
|
|
1612
2147
|
type: "button",
|
|
@@ -1618,7 +2153,7 @@ var ImageEditor = ({
|
|
|
1618
2153
|
children: "4:3 Standard"
|
|
1619
2154
|
}
|
|
1620
2155
|
),
|
|
1621
|
-
/* @__PURE__ */ (0,
|
|
2156
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1622
2157
|
"button",
|
|
1623
2158
|
{
|
|
1624
2159
|
type: "button",
|
|
@@ -1630,7 +2165,7 @@ var ImageEditor = ({
|
|
|
1630
2165
|
children: "16:9 Wide"
|
|
1631
2166
|
}
|
|
1632
2167
|
),
|
|
1633
|
-
/* @__PURE__ */ (0,
|
|
2168
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1634
2169
|
"button",
|
|
1635
2170
|
{
|
|
1636
2171
|
type: "button",
|
|
@@ -1642,7 +2177,7 @@ var ImageEditor = ({
|
|
|
1642
2177
|
children: "3:2 Photo"
|
|
1643
2178
|
}
|
|
1644
2179
|
),
|
|
1645
|
-
/* @__PURE__ */ (0,
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1646
2181
|
"button",
|
|
1647
2182
|
{
|
|
1648
2183
|
type: "button",
|
|
@@ -1655,10 +2190,10 @@ var ImageEditor = ({
|
|
|
1655
2190
|
}
|
|
1656
2191
|
)
|
|
1657
2192
|
] }),
|
|
1658
|
-
/* @__PURE__ */ (0,
|
|
1659
|
-
/* @__PURE__ */ (0,
|
|
1660
|
-
/* @__PURE__ */ (0,
|
|
1661
|
-
/* @__PURE__ */ (0,
|
|
2193
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
2194
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
|
|
2195
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
2196
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1662
2197
|
"button",
|
|
1663
2198
|
{
|
|
1664
2199
|
type: "button",
|
|
@@ -1667,7 +2202,7 @@ var ImageEditor = ({
|
|
|
1667
2202
|
children: "Rotate -90\xB0"
|
|
1668
2203
|
}
|
|
1669
2204
|
),
|
|
1670
|
-
/* @__PURE__ */ (0,
|
|
2205
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1671
2206
|
"button",
|
|
1672
2207
|
{
|
|
1673
2208
|
type: "button",
|
|
@@ -1676,7 +2211,7 @@ var ImageEditor = ({
|
|
|
1676
2211
|
children: "Rotate +90\xB0"
|
|
1677
2212
|
}
|
|
1678
2213
|
),
|
|
1679
|
-
/* @__PURE__ */ (0,
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1680
2215
|
"button",
|
|
1681
2216
|
{
|
|
1682
2217
|
type: "button",
|
|
@@ -1685,7 +2220,7 @@ var ImageEditor = ({
|
|
|
1685
2220
|
children: "Flip Horizontal"
|
|
1686
2221
|
}
|
|
1687
2222
|
),
|
|
1688
|
-
/* @__PURE__ */ (0,
|
|
2223
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1689
2224
|
"button",
|
|
1690
2225
|
{
|
|
1691
2226
|
type: "button",
|
|
@@ -1696,10 +2231,10 @@ var ImageEditor = ({
|
|
|
1696
2231
|
)
|
|
1697
2232
|
] })
|
|
1698
2233
|
] }),
|
|
1699
|
-
activeTab === "adjust" && /* @__PURE__ */ (0,
|
|
1700
|
-
/* @__PURE__ */ (0,
|
|
1701
|
-
/* @__PURE__ */ (0,
|
|
1702
|
-
/* @__PURE__ */ (0,
|
|
2234
|
+
activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
|
|
2237
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1703
2238
|
"button",
|
|
1704
2239
|
{
|
|
1705
2240
|
type: "button",
|
|
@@ -1709,25 +2244,25 @@ var ImageEditor = ({
|
|
|
1709
2244
|
}
|
|
1710
2245
|
)
|
|
1711
2246
|
] }),
|
|
1712
|
-
/* @__PURE__ */ (0,
|
|
1713
|
-
|
|
1714
|
-
/* @__PURE__ */ (0,
|
|
2247
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Histogram, { histogram: editor.histogram }),
|
|
2248
|
+
import_image_editor10.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react9.default.Fragment, { children: [
|
|
2249
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1715
2250
|
ControlSlider,
|
|
1716
2251
|
{
|
|
1717
2252
|
spec,
|
|
1718
|
-
value: (0,
|
|
2253
|
+
value: (0, import_image_editor10.readAdjustmentControls)(state.adjustments)[spec.id],
|
|
1719
2254
|
disabled: spec.requiresProcess !== void 0 && legacyProcess,
|
|
1720
2255
|
onChange: (v) => editor.setAdjustments({ [spec.id]: v })
|
|
1721
2256
|
}
|
|
1722
2257
|
),
|
|
1723
|
-
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0,
|
|
2258
|
+
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1724
2259
|
"div",
|
|
1725
2260
|
{
|
|
1726
2261
|
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",
|
|
1727
2262
|
"data-testid": "image-editor-process-notice",
|
|
1728
2263
|
children: [
|
|
1729
|
-
/* @__PURE__ */ (0,
|
|
1730
|
-
/* @__PURE__ */ (0,
|
|
2264
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
|
|
2265
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1731
2266
|
"button",
|
|
1732
2267
|
{
|
|
1733
2268
|
type: "button",
|
|
@@ -1740,7 +2275,7 @@ var ImageEditor = ({
|
|
|
1740
2275
|
}
|
|
1741
2276
|
)
|
|
1742
2277
|
] }, spec.id)),
|
|
1743
|
-
/* @__PURE__ */ (0,
|
|
2278
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1744
2279
|
AdjustmentLayersPanel,
|
|
1745
2280
|
{
|
|
1746
2281
|
controller,
|
|
@@ -1749,9 +2284,19 @@ var ImageEditor = ({
|
|
|
1749
2284
|
}
|
|
1750
2285
|
) })
|
|
1751
2286
|
] }),
|
|
1752
|
-
activeTab === "
|
|
1753
|
-
/* @__PURE__ */ (0,
|
|
1754
|
-
/* @__PURE__ */ (0,
|
|
2287
|
+
activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2288
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
|
|
2289
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LayersPanel, { controller })
|
|
2290
|
+
] }),
|
|
2291
|
+
activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2292
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
|
|
2293
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BrushOptionsBar, { controller }),
|
|
2294
|
+
paintError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
|
|
2295
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LayersPanel, { controller }) })
|
|
2296
|
+
] }),
|
|
2297
|
+
activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2298
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
|
|
2299
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1755
2300
|
"button",
|
|
1756
2301
|
{
|
|
1757
2302
|
type: "button",
|
|
@@ -1761,9 +2306,9 @@ var ImageEditor = ({
|
|
|
1761
2306
|
},
|
|
1762
2307
|
t
|
|
1763
2308
|
)) }),
|
|
1764
|
-
/* @__PURE__ */ (0,
|
|
1765
|
-
/* @__PURE__ */ (0,
|
|
1766
|
-
/* @__PURE__ */ (0,
|
|
2309
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
|
|
2310
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-slate-400", children: "Color:" }),
|
|
2311
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1767
2312
|
"input",
|
|
1768
2313
|
{
|
|
1769
2314
|
type: "color",
|
|
@@ -1772,15 +2317,15 @@ var ImageEditor = ({
|
|
|
1772
2317
|
className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
|
|
1773
2318
|
}
|
|
1774
2319
|
),
|
|
1775
|
-
/* @__PURE__ */ (0,
|
|
1776
|
-
/* @__PURE__ */ (0,
|
|
1777
|
-
/* @__PURE__ */ (0,
|
|
1778
|
-
/* @__PURE__ */ (0,
|
|
2320
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 ml-2", children: [
|
|
2321
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
|
|
2322
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Width:" }),
|
|
2323
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
|
|
1779
2324
|
strokeWidth,
|
|
1780
2325
|
"px"
|
|
1781
2326
|
] })
|
|
1782
2327
|
] }),
|
|
1783
|
-
/* @__PURE__ */ (0,
|
|
2328
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1784
2329
|
"input",
|
|
1785
2330
|
{
|
|
1786
2331
|
type: "range",
|
|
@@ -1793,10 +2338,10 @@ var ImageEditor = ({
|
|
|
1793
2338
|
)
|
|
1794
2339
|
] })
|
|
1795
2340
|
] }),
|
|
1796
|
-
/* @__PURE__ */ (0,
|
|
1797
|
-
/* @__PURE__ */ (0,
|
|
1798
|
-
/* @__PURE__ */ (0,
|
|
1799
|
-
/* @__PURE__ */ (0,
|
|
2341
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
2342
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
|
|
2343
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-2", children: [
|
|
2344
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1800
2345
|
"input",
|
|
1801
2346
|
{
|
|
1802
2347
|
type: "text",
|
|
@@ -1807,7 +2352,7 @@ var ImageEditor = ({
|
|
|
1807
2352
|
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"
|
|
1808
2353
|
}
|
|
1809
2354
|
),
|
|
1810
|
-
/* @__PURE__ */ (0,
|
|
2355
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1811
2356
|
"button",
|
|
1812
2357
|
{
|
|
1813
2358
|
type: "button",
|
|
@@ -1817,14 +2362,14 @@ var ImageEditor = ({
|
|
|
1817
2362
|
}
|
|
1818
2363
|
)
|
|
1819
2364
|
] }),
|
|
1820
|
-
/* @__PURE__ */ (0,
|
|
1821
|
-
/* @__PURE__ */ (0,
|
|
1822
|
-
/* @__PURE__ */ (0,
|
|
2365
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Font Size:" }),
|
|
2367
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
|
|
1823
2368
|
fontSize,
|
|
1824
2369
|
"px"
|
|
1825
2370
|
] })
|
|
1826
2371
|
] }),
|
|
1827
|
-
/* @__PURE__ */ (0,
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1828
2373
|
"input",
|
|
1829
2374
|
{
|
|
1830
2375
|
type: "range",
|
|
@@ -1835,14 +2380,14 @@ var ImageEditor = ({
|
|
|
1835
2380
|
className: "w-full accent-indigo-500"
|
|
1836
2381
|
}
|
|
1837
2382
|
),
|
|
1838
|
-
/* @__PURE__ */ (0,
|
|
1839
|
-
/* @__PURE__ */ (0,
|
|
1840
|
-
/* @__PURE__ */ (0,
|
|
2383
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
2384
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2385
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "text-slate-400", children: [
|
|
1841
2386
|
"Layers (",
|
|
1842
2387
|
state.annotations.length,
|
|
1843
2388
|
")"
|
|
1844
2389
|
] }),
|
|
1845
|
-
state.selectedAnnotationId && /* @__PURE__ */ (0,
|
|
2390
|
+
state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1846
2391
|
"button",
|
|
1847
2392
|
{
|
|
1848
2393
|
type: "button",
|
|
@@ -1851,7 +2396,7 @@ var ImageEditor = ({
|
|
|
1851
2396
|
children: "Delete Selected"
|
|
1852
2397
|
}
|
|
1853
2398
|
),
|
|
1854
|
-
state.annotations.length > 0 && /* @__PURE__ */ (0,
|
|
2399
|
+
state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1855
2400
|
"button",
|
|
1856
2401
|
{
|
|
1857
2402
|
type: "button",
|
|
@@ -1862,10 +2407,10 @@ var ImageEditor = ({
|
|
|
1862
2407
|
)
|
|
1863
2408
|
] })
|
|
1864
2409
|
] }),
|
|
1865
|
-
activeTab === "depth" && /* @__PURE__ */ (0,
|
|
1866
|
-
/* @__PURE__ */ (0,
|
|
1867
|
-
/* @__PURE__ */ (0,
|
|
1868
|
-
/* @__PURE__ */ (0,
|
|
2410
|
+
activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2411
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2412
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
|
|
2413
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1869
2414
|
"button",
|
|
1870
2415
|
{
|
|
1871
2416
|
type: "button",
|
|
@@ -1875,8 +2420,8 @@ var ImageEditor = ({
|
|
|
1875
2420
|
}
|
|
1876
2421
|
)
|
|
1877
2422
|
] }),
|
|
1878
|
-
/* @__PURE__ */ (0,
|
|
1879
|
-
/* @__PURE__ */ (0,
|
|
2423
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
|
|
2424
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1880
2425
|
"input",
|
|
1881
2426
|
{
|
|
1882
2427
|
type: "checkbox",
|
|
@@ -1885,12 +2430,12 @@ var ImageEditor = ({
|
|
|
1885
2430
|
className: "rounded accent-indigo-500"
|
|
1886
2431
|
}
|
|
1887
2432
|
),
|
|
1888
|
-
/* @__PURE__ */ (0,
|
|
2433
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Enable Depth / Alpha Mask" })
|
|
1889
2434
|
] }),
|
|
1890
|
-
state.depthMask.enabled && /* @__PURE__ */ (0,
|
|
1891
|
-
/* @__PURE__ */ (0,
|
|
1892
|
-
/* @__PURE__ */ (0,
|
|
1893
|
-
/* @__PURE__ */ (0,
|
|
2435
|
+
state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2436
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
|
|
2437
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
|
|
2438
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1894
2439
|
"input",
|
|
1895
2440
|
{
|
|
1896
2441
|
type: "text",
|
|
@@ -1901,8 +2446,8 @@ var ImageEditor = ({
|
|
|
1901
2446
|
}
|
|
1902
2447
|
)
|
|
1903
2448
|
] }),
|
|
1904
|
-
/* @__PURE__ */ (0,
|
|
1905
|
-
/* @__PURE__ */ (0,
|
|
2449
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-2", children: [
|
|
2450
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1906
2451
|
"button",
|
|
1907
2452
|
{
|
|
1908
2453
|
type: "button",
|
|
@@ -1911,7 +2456,7 @@ var ImageEditor = ({
|
|
|
1911
2456
|
children: "Threshold Mode"
|
|
1912
2457
|
}
|
|
1913
2458
|
),
|
|
1914
|
-
/* @__PURE__ */ (0,
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1915
2460
|
"button",
|
|
1916
2461
|
{
|
|
1917
2462
|
type: "button",
|
|
@@ -1921,12 +2466,12 @@ var ImageEditor = ({
|
|
|
1921
2466
|
}
|
|
1922
2467
|
)
|
|
1923
2468
|
] }),
|
|
1924
|
-
/* @__PURE__ */ (0,
|
|
1925
|
-
/* @__PURE__ */ (0,
|
|
1926
|
-
/* @__PURE__ */ (0,
|
|
1927
|
-
/* @__PURE__ */ (0,
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
2471
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Depth Start (Lower):" }),
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
|
|
1928
2473
|
] }),
|
|
1929
|
-
/* @__PURE__ */ (0,
|
|
2474
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1930
2475
|
"input",
|
|
1931
2476
|
{
|
|
1932
2477
|
type: "range",
|
|
@@ -1940,12 +2485,12 @@ var ImageEditor = ({
|
|
|
1940
2485
|
}
|
|
1941
2486
|
)
|
|
1942
2487
|
] }),
|
|
1943
|
-
/* @__PURE__ */ (0,
|
|
1944
|
-
/* @__PURE__ */ (0,
|
|
1945
|
-
/* @__PURE__ */ (0,
|
|
1946
|
-
/* @__PURE__ */ (0,
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
|
|
2489
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
2490
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Depth Stop (Upper):" }),
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
|
|
1947
2492
|
] }),
|
|
1948
|
-
/* @__PURE__ */ (0,
|
|
2493
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1949
2494
|
"input",
|
|
1950
2495
|
{
|
|
1951
2496
|
type: "range",
|
|
@@ -1959,12 +2504,12 @@ var ImageEditor = ({
|
|
|
1959
2504
|
}
|
|
1960
2505
|
)
|
|
1961
2506
|
] }),
|
|
1962
|
-
/* @__PURE__ */ (0,
|
|
1963
|
-
/* @__PURE__ */ (0,
|
|
1964
|
-
/* @__PURE__ */ (0,
|
|
1965
|
-
/* @__PURE__ */ (0,
|
|
2507
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
|
|
2508
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
2509
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Softness:" }),
|
|
2510
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
|
|
1966
2511
|
] }),
|
|
1967
|
-
/* @__PURE__ */ (0,
|
|
2512
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1968
2513
|
"input",
|
|
1969
2514
|
{
|
|
1970
2515
|
type: "range",
|
|
@@ -1976,8 +2521,8 @@ var ImageEditor = ({
|
|
|
1976
2521
|
}
|
|
1977
2522
|
)
|
|
1978
2523
|
] }),
|
|
1979
|
-
/* @__PURE__ */ (0,
|
|
1980
|
-
/* @__PURE__ */ (0,
|
|
2524
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1981
2526
|
"input",
|
|
1982
2527
|
{
|
|
1983
2528
|
type: "checkbox",
|
|
@@ -1986,12 +2531,12 @@ var ImageEditor = ({
|
|
|
1986
2531
|
className: "rounded accent-indigo-500"
|
|
1987
2532
|
}
|
|
1988
2533
|
),
|
|
1989
|
-
/* @__PURE__ */ (0,
|
|
2534
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Invert Mask" })
|
|
1990
2535
|
] })
|
|
1991
2536
|
] })
|
|
1992
2537
|
] }),
|
|
1993
|
-
activeTab === "select" && /* @__PURE__ */ (0,
|
|
1994
|
-
/* @__PURE__ */ (0,
|
|
2538
|
+
activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
2539
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1995
2540
|
SelectionOptionsBar,
|
|
1996
2541
|
{
|
|
1997
2542
|
controller,
|
|
@@ -2001,51 +2546,51 @@ var ImageEditor = ({
|
|
|
2001
2546
|
quickMask: Boolean(state.quickMask)
|
|
2002
2547
|
}
|
|
2003
2548
|
),
|
|
2004
|
-
selectionError && /* @__PURE__ */ (0,
|
|
2005
|
-
/* @__PURE__ */ (0,
|
|
2549
|
+
selectionError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
|
|
2006
2551
|
] }),
|
|
2007
|
-
activeTab === "ai" && /* @__PURE__ */ (0,
|
|
2008
|
-
/* @__PURE__ */ (0,
|
|
2009
|
-
/* @__PURE__ */ (0,
|
|
2010
|
-
/* @__PURE__ */ (0,
|
|
2011
|
-
/* @__PURE__ */ (0,
|
|
2552
|
+
activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
2553
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
2554
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2555
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
2556
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
|
|
2012
2557
|
"Background Removal"
|
|
2013
2558
|
] }),
|
|
2014
|
-
isRemovingBg && /* @__PURE__ */ (0,
|
|
2559
|
+
isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
|
|
2015
2560
|
] }),
|
|
2016
|
-
/* @__PURE__ */ (0,
|
|
2017
|
-
/* @__PURE__ */ (0,
|
|
2561
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
|
|
2562
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2018
2563
|
"button",
|
|
2019
2564
|
{
|
|
2020
2565
|
type: "button",
|
|
2021
2566
|
onClick: handleRemoveBackground,
|
|
2022
2567
|
disabled: isRemovingBg || isInpainting,
|
|
2023
2568
|
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",
|
|
2024
|
-
children: isRemovingBg ? /* @__PURE__ */ (0,
|
|
2025
|
-
/* @__PURE__ */ (0,
|
|
2569
|
+
children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2570
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
2026
2571
|
"Removing Background..."
|
|
2027
|
-
] }) : /* @__PURE__ */ (0,
|
|
2028
|
-
/* @__PURE__ */ (0,
|
|
2572
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2573
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
2029
2574
|
"Remove Background"
|
|
2030
2575
|
] })
|
|
2031
2576
|
}
|
|
2032
2577
|
)
|
|
2033
2578
|
] }),
|
|
2034
|
-
/* @__PURE__ */ (0,
|
|
2035
|
-
/* @__PURE__ */ (0,
|
|
2036
|
-
/* @__PURE__ */ (0,
|
|
2037
|
-
/* @__PURE__ */ (0,
|
|
2038
|
-
/* @__PURE__ */ (0,
|
|
2039
|
-
/* @__PURE__ */ (0,
|
|
2579
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
2580
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2581
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
2582
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
2583
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
|
|
2584
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "m14 7 3 3" })
|
|
2040
2585
|
] }),
|
|
2041
2586
|
"Generative Inpainting"
|
|
2042
2587
|
] }),
|
|
2043
|
-
isInpainting && /* @__PURE__ */ (0,
|
|
2588
|
+
isInpainting && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
|
|
2044
2589
|
] }),
|
|
2045
|
-
/* @__PURE__ */ (0,
|
|
2046
|
-
/* @__PURE__ */ (0,
|
|
2047
|
-
/* @__PURE__ */ (0,
|
|
2048
|
-
/* @__PURE__ */ (0,
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
|
|
2591
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
2592
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2049
2594
|
"textarea",
|
|
2050
2595
|
{
|
|
2051
2596
|
id: "ai-inpaint-prompt-react",
|
|
@@ -2057,10 +2602,10 @@ var ImageEditor = ({
|
|
|
2057
2602
|
}
|
|
2058
2603
|
)
|
|
2059
2604
|
] }),
|
|
2060
|
-
/* @__PURE__ */ (0,
|
|
2061
|
-
/* @__PURE__ */ (0,
|
|
2062
|
-
/* @__PURE__ */ (0,
|
|
2063
|
-
/* @__PURE__ */ (0,
|
|
2605
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
2606
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2064
2609
|
"button",
|
|
2065
2610
|
{
|
|
2066
2611
|
type: "button",
|
|
@@ -2073,7 +2618,7 @@ var ImageEditor = ({
|
|
|
2073
2618
|
]
|
|
2074
2619
|
}
|
|
2075
2620
|
),
|
|
2076
|
-
/* @__PURE__ */ (0,
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2077
2622
|
"button",
|
|
2078
2623
|
{
|
|
2079
2624
|
type: "button",
|
|
@@ -2088,25 +2633,25 @@ var ImageEditor = ({
|
|
|
2088
2633
|
)
|
|
2089
2634
|
] })
|
|
2090
2635
|
] }),
|
|
2091
|
-
/* @__PURE__ */ (0,
|
|
2636
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2092
2637
|
"button",
|
|
2093
2638
|
{
|
|
2094
2639
|
type: "button",
|
|
2095
2640
|
onClick: handleInpaint,
|
|
2096
2641
|
disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
|
|
2097
2642
|
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",
|
|
2098
|
-
children: isInpainting ? /* @__PURE__ */ (0,
|
|
2099
|
-
/* @__PURE__ */ (0,
|
|
2643
|
+
children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
2100
2645
|
"Generating Inpaint..."
|
|
2101
|
-
] }) : /* @__PURE__ */ (0,
|
|
2102
|
-
/* @__PURE__ */ (0,
|
|
2646
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2647
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
2103
2648
|
"Apply Inpainting"
|
|
2104
2649
|
] })
|
|
2105
2650
|
}
|
|
2106
2651
|
)
|
|
2107
2652
|
] }),
|
|
2108
|
-
aiError && /* @__PURE__ */ (0,
|
|
2109
|
-
aiSuccess && /* @__PURE__ */ (0,
|
|
2653
|
+
aiError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
|
|
2654
|
+
aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
|
|
2110
2655
|
] })
|
|
2111
2656
|
] })
|
|
2112
2657
|
] })
|
|
@@ -2117,10 +2662,12 @@ var ImageEditor = ({
|
|
|
2117
2662
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2118
2663
|
0 && (module.exports = {
|
|
2119
2664
|
AdjustmentLayersPanel,
|
|
2665
|
+
BrushOptionsBar,
|
|
2120
2666
|
ControlSlider,
|
|
2121
2667
|
CurvesEditor,
|
|
2122
2668
|
Histogram,
|
|
2123
2669
|
ImageEditor,
|
|
2670
|
+
LayersPanel,
|
|
2124
2671
|
RefineEdgePanel,
|
|
2125
2672
|
SelectionOptionsBar,
|
|
2126
2673
|
useImageEditor,
|