@pixerate/editor-react 0.63.0 → 0.65.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-QJSMW4CM.js → chunk-OSBDCFF4.js} +799 -382
- package/dist/chunk-OSBDCFF4.js.map +1 -0
- package/dist/image-editor/index.cjs +833 -417
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +31 -3
- package/dist/image-editor/index.d.ts +31 -3
- package/dist/image-editor/index.js +5 -1
- package/dist/index.cjs +1267 -851
- 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/package.json +3 -3
- package/dist/chunk-QJSMW4CM.js.map +0 -1
|
@@ -34,8 +34,10 @@ __export(image_editor_exports, {
|
|
|
34
34
|
BrushOptionsBar: () => BrushOptionsBar,
|
|
35
35
|
ControlSlider: () => ControlSlider,
|
|
36
36
|
CurvesEditor: () => CurvesEditor,
|
|
37
|
+
FreeTransformOptionsBar: () => FreeTransformOptionsBar,
|
|
37
38
|
Histogram: () => Histogram,
|
|
38
39
|
ImageEditor: () => ImageEditor,
|
|
40
|
+
LayerEffectsPanel: () => LayerEffectsPanel,
|
|
39
41
|
LayersPanel: () => LayersPanel,
|
|
40
42
|
RefineEdgePanel: () => RefineEdgePanel,
|
|
41
43
|
SelectionOptionsBar: () => SelectionOptionsBar,
|
|
@@ -203,8 +205,8 @@ function useImageEditor(options = {}) {
|
|
|
203
205
|
}
|
|
204
206
|
|
|
205
207
|
// src/image-editor/ImageEditor.tsx
|
|
206
|
-
var
|
|
207
|
-
var
|
|
208
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
209
|
+
var import_image_editor12 = require("@pixerate/editor/image-editor");
|
|
208
210
|
|
|
209
211
|
// src/image-editor/ControlSlider.tsx
|
|
210
212
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
@@ -636,9 +638,198 @@ var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
|
|
|
636
638
|
};
|
|
637
639
|
|
|
638
640
|
// src/image-editor/LayersPanel.tsx
|
|
641
|
+
var import_react6 = require("react");
|
|
642
|
+
|
|
643
|
+
// src/image-editor/LayerEffectsPanel.tsx
|
|
639
644
|
var import_react5 = require("react");
|
|
640
645
|
var import_image_editor6 = require("@pixerate/editor/image-editor");
|
|
641
646
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
647
|
+
var button = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
|
|
648
|
+
var LayerEffectsPanel = ({ controller, layerId, className }) => {
|
|
649
|
+
const [, setTick] = (0, import_react5.useState)(0);
|
|
650
|
+
(0, import_react5.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
651
|
+
const [open, setOpen] = (0, import_react5.useState)(null);
|
|
652
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
653
|
+
const commitNext = (0, import_react5.useRef)(true);
|
|
654
|
+
const layer = layerId ? controller.getLayer(layerId) : controller.getActiveLayer();
|
|
655
|
+
const model = (0, import_image_editor6.layerEffectsPanel)(layer);
|
|
656
|
+
const id = layer?.id;
|
|
657
|
+
const attempt = (fn) => {
|
|
658
|
+
try {
|
|
659
|
+
setError(null);
|
|
660
|
+
fn();
|
|
661
|
+
} catch (err) {
|
|
662
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
const sliderEvents = {
|
|
666
|
+
onPointerDown: () => commitNext.current = true,
|
|
667
|
+
onPointerUp: () => commitNext.current = true,
|
|
668
|
+
onKeyDown: () => commitNext.current = true
|
|
669
|
+
};
|
|
670
|
+
if (!model.available || !id) {
|
|
671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: `text-xs text-slate-500 ${className ?? ""}`, "data-testid": "layer-effects", children: model.reason });
|
|
672
|
+
}
|
|
673
|
+
const effects = controller.getLayerEffects(id);
|
|
674
|
+
const patterns = controller.getDocumentPatterns();
|
|
675
|
+
const change = (effectId, control, value, drag = false) => attempt(() => {
|
|
676
|
+
const effect = controller.getLayerEffects(id).items.find((e) => e.id === effectId);
|
|
677
|
+
controller.updateLayerEffect(id, effectId, (0, import_image_editor6.effectControlChange)(effect, control.key, value, patterns), drag ? commitNext.current : true);
|
|
678
|
+
if (drag) commitNext.current = false;
|
|
679
|
+
});
|
|
680
|
+
const renderControl = (effectId, c) => {
|
|
681
|
+
const label = `${c.label}`;
|
|
682
|
+
switch (c.type) {
|
|
683
|
+
case "range": {
|
|
684
|
+
const k = c.percent ? 100 : 1;
|
|
685
|
+
const shown = Math.round(c.value * k * 100) / 100;
|
|
686
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
|
|
687
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
|
|
688
|
+
label,
|
|
689
|
+
" ",
|
|
690
|
+
shown,
|
|
691
|
+
c.unit
|
|
692
|
+
] }),
|
|
693
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
694
|
+
"input",
|
|
695
|
+
{
|
|
696
|
+
type: "range",
|
|
697
|
+
"aria-label": label,
|
|
698
|
+
min: c.min * k,
|
|
699
|
+
max: c.max * k,
|
|
700
|
+
step: c.step * k,
|
|
701
|
+
value: shown,
|
|
702
|
+
disabled: model.readOnly,
|
|
703
|
+
...sliderEvents,
|
|
704
|
+
onChange: (e) => change(effectId, c, Number(e.target.value) / k, true),
|
|
705
|
+
className: "accent-indigo-500"
|
|
706
|
+
}
|
|
707
|
+
)
|
|
708
|
+
] }, c.key);
|
|
709
|
+
}
|
|
710
|
+
case "color":
|
|
711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
|
|
712
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "color", "aria-label": label, value: c.value, disabled: model.readOnly, onChange: (e) => change(effectId, c, e.target.value) }),
|
|
713
|
+
label
|
|
714
|
+
] }, c.key);
|
|
715
|
+
case "checkbox":
|
|
716
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
|
|
717
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", "aria-label": label, checked: c.value, disabled: model.readOnly, onChange: (e) => change(effectId, c, e.target.checked), className: "accent-indigo-500" }),
|
|
718
|
+
label
|
|
719
|
+
] }, c.key);
|
|
720
|
+
case "select":
|
|
721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
|
|
722
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-400", children: label }),
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
724
|
+
"select",
|
|
725
|
+
{
|
|
726
|
+
"aria-label": label,
|
|
727
|
+
value: c.value,
|
|
728
|
+
disabled: model.readOnly,
|
|
729
|
+
onChange: (e) => change(effectId, c, e.target.value),
|
|
730
|
+
className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
|
|
731
|
+
children: c.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: o.value, children: o.label }, o.value))
|
|
732
|
+
}
|
|
733
|
+
)
|
|
734
|
+
] }, c.key);
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `flex flex-col gap-1.5 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layer-effects", "aria-label": "Layer effects", role: "group", children: [
|
|
738
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
739
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-300", children: "fx Effects" }),
|
|
740
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1 text-slate-300", children: [
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
742
|
+
"input",
|
|
743
|
+
{
|
|
744
|
+
type: "checkbox",
|
|
745
|
+
"aria-label": "Effects on",
|
|
746
|
+
checked: model.enabled,
|
|
747
|
+
disabled: model.readOnly,
|
|
748
|
+
onChange: (e) => attempt(() => controller.setLayerEffectsEnabled(id, e.target.checked)),
|
|
749
|
+
className: "accent-indigo-500"
|
|
750
|
+
}
|
|
751
|
+
),
|
|
752
|
+
"On"
|
|
753
|
+
] }),
|
|
754
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
|
|
755
|
+
"Scale",
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
757
|
+
"input",
|
|
758
|
+
{
|
|
759
|
+
type: "number",
|
|
760
|
+
"aria-label": "Scale effects",
|
|
761
|
+
min: 1,
|
|
762
|
+
max: 1e3,
|
|
763
|
+
step: 1,
|
|
764
|
+
value: Math.round(model.scale * 100),
|
|
765
|
+
disabled: model.readOnly,
|
|
766
|
+
onChange: (e) => {
|
|
767
|
+
const v = Number(e.target.value);
|
|
768
|
+
if (v >= 1 && v <= 1e3) attempt(() => controller.setLayerEffectsEnabled(id, model.enabled, v / 100));
|
|
769
|
+
},
|
|
770
|
+
className: "w-14 bg-slate-800 border border-slate-700 rounded px-1"
|
|
771
|
+
}
|
|
772
|
+
),
|
|
773
|
+
"%"
|
|
774
|
+
] }),
|
|
775
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
776
|
+
"select",
|
|
777
|
+
{
|
|
778
|
+
"aria-label": "Add effect",
|
|
779
|
+
value: "",
|
|
780
|
+
disabled: model.readOnly,
|
|
781
|
+
onChange: (e) => {
|
|
782
|
+
const kind = e.target.value;
|
|
783
|
+
if (!kind) return;
|
|
784
|
+
attempt(() => setOpen(controller.addLayerEffect(id, kind).effect.id));
|
|
785
|
+
},
|
|
786
|
+
className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
|
|
787
|
+
children: [
|
|
788
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", children: "Add effect\u2026" }),
|
|
789
|
+
import_image_editor6.LAYER_EFFECT_MENU.map((m) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: m.kind, children: m.label }, m.kind))
|
|
790
|
+
]
|
|
791
|
+
}
|
|
792
|
+
)
|
|
793
|
+
] }),
|
|
794
|
+
model.readOnly && model.reason && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-500", children: model.reason }),
|
|
795
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "flex flex-col gap-1", "aria-label": "Effects", children: model.rows.map((row) => {
|
|
796
|
+
const effect = effects.items.find((e) => e.id === row.id);
|
|
797
|
+
const expanded = open === row.id;
|
|
798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { "data-effect-id": row.id, className: "rounded bg-slate-900/60 ring-1 ring-slate-800", children: [
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5 px-1.5 py-1", children: [
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
801
|
+
"input",
|
|
802
|
+
{
|
|
803
|
+
type: "checkbox",
|
|
804
|
+
"aria-label": `${row.label} on`,
|
|
805
|
+
checked: row.enabled,
|
|
806
|
+
disabled: model.readOnly,
|
|
807
|
+
onChange: (e) => attempt(() => controller.updateLayerEffect(id, row.id, { enabled: e.target.checked })),
|
|
808
|
+
className: "accent-indigo-500"
|
|
809
|
+
}
|
|
810
|
+
),
|
|
811
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
812
|
+
"button",
|
|
813
|
+
{
|
|
814
|
+
type: "button",
|
|
815
|
+
"aria-expanded": expanded,
|
|
816
|
+
className: `flex-1 text-left ${row.enabled && model.enabled ? "" : "text-slate-500"}`,
|
|
817
|
+
onClick: () => setOpen(expanded ? null : row.id),
|
|
818
|
+
children: row.label
|
|
819
|
+
}
|
|
820
|
+
),
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: button, "aria-label": `Remove ${row.label}`, disabled: model.readOnly, onClick: () => attempt(() => controller.removeLayerEffect(id, row.id)), children: "\u2715" })
|
|
822
|
+
] }),
|
|
823
|
+
expanded && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 px-1.5 pb-1.5", "data-testid": "effect-settings", children: (0, import_image_editor6.layerEffectControls)(effect, patterns).map((c) => renderControl(row.id, c)) })
|
|
824
|
+
] }, row.id);
|
|
825
|
+
}) }),
|
|
826
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
|
|
827
|
+
] });
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
// src/image-editor/LayersPanel.tsx
|
|
831
|
+
var import_image_editor7 = require("@pixerate/editor/image-editor");
|
|
832
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
642
833
|
var iconButton = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
|
|
643
834
|
var rowClass = (active) => `flex items-center gap-1.5 px-1.5 py-1 rounded cursor-pointer select-none ${active ? "bg-indigo-600/30 ring-1 ring-indigo-500" : "hover:bg-slate-800"}`;
|
|
644
835
|
var Thumbnail = ({
|
|
@@ -649,8 +840,8 @@ var Thumbnail = ({
|
|
|
649
840
|
selected,
|
|
650
841
|
testId
|
|
651
842
|
}) => {
|
|
652
|
-
const ref = (0,
|
|
653
|
-
(0,
|
|
843
|
+
const ref = (0, import_react6.useRef)(null);
|
|
844
|
+
(0, import_react6.useEffect)(() => {
|
|
654
845
|
const canvas = ref.current;
|
|
655
846
|
const ctx = canvas?.getContext("2d");
|
|
656
847
|
if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== "function") return;
|
|
@@ -660,7 +851,7 @@ var Thumbnail = ({
|
|
|
660
851
|
img.data.set(pixels.data);
|
|
661
852
|
ctx.putImageData(img, 0, 0);
|
|
662
853
|
}, [pixels]);
|
|
663
|
-
return /* @__PURE__ */ (0,
|
|
854
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
664
855
|
"canvas",
|
|
665
856
|
{
|
|
666
857
|
ref,
|
|
@@ -673,15 +864,15 @@ var Thumbnail = ({
|
|
|
673
864
|
}
|
|
674
865
|
);
|
|
675
866
|
};
|
|
676
|
-
var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "image", className }) => {
|
|
677
|
-
const [, setTick] = (0,
|
|
678
|
-
(0,
|
|
679
|
-
const [error, setError] = (0,
|
|
680
|
-
const [renaming, setRenaming] = (0,
|
|
681
|
-
const [menu, setMenu] = (0,
|
|
682
|
-
const [drag, setDrag] = (0,
|
|
683
|
-
const [psdNotes, setPsdNotes] = (0,
|
|
684
|
-
const fileInput = (0,
|
|
867
|
+
var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "image", effects = true, className }) => {
|
|
868
|
+
const [, setTick] = (0, import_react6.useState)(0);
|
|
869
|
+
(0, import_react6.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
870
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
871
|
+
const [renaming, setRenaming] = (0, import_react6.useState)(null);
|
|
872
|
+
const [menu, setMenu] = (0, import_react6.useState)(null);
|
|
873
|
+
const [drag, setDrag] = (0, import_react6.useState)(null);
|
|
874
|
+
const [psdNotes, setPsdNotes] = (0, import_react6.useState)([]);
|
|
875
|
+
const fileInput = (0, import_react6.useRef)(null);
|
|
685
876
|
const psdTask = async (fn) => {
|
|
686
877
|
try {
|
|
687
878
|
setError(null);
|
|
@@ -690,9 +881,9 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
690
881
|
setError(err instanceof Error ? err.message : String(err));
|
|
691
882
|
}
|
|
692
883
|
};
|
|
693
|
-
const commitNext = (0,
|
|
884
|
+
const commitNext = (0, import_react6.useRef)(true);
|
|
694
885
|
const state = controller.getState();
|
|
695
|
-
const rows = (0,
|
|
886
|
+
const rows = (0, import_image_editor7.layerPanelRows)(state.layers, state.activeLayerId);
|
|
696
887
|
const active = controller.getActiveLayer();
|
|
697
888
|
const attempt = (fn) => {
|
|
698
889
|
try {
|
|
@@ -704,7 +895,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
704
895
|
};
|
|
705
896
|
const run = async (action) => {
|
|
706
897
|
setMenu(null);
|
|
707
|
-
setError(await (0,
|
|
898
|
+
setError(await (0, import_image_editor7.runLayerMenuAction)(controller, action));
|
|
708
899
|
};
|
|
709
900
|
const prop = (key, value) => attempt(() => {
|
|
710
901
|
controller.setLayerProperties(active.id, { [key]: value }, commitNext.current);
|
|
@@ -722,20 +913,20 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
722
913
|
if (!id) return;
|
|
723
914
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
724
915
|
const fraction = rect.height ? (e.clientY - rect.top) / rect.height : 0.5;
|
|
725
|
-
const placement = (0,
|
|
916
|
+
const placement = (0, import_image_editor7.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor7.dropZone)(fraction, row.layer.type === "group"));
|
|
726
917
|
if (placement) attempt(() => controller.moveLayer(id, placement));
|
|
727
918
|
};
|
|
728
919
|
const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
|
|
729
920
|
const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
|
|
730
921
|
const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
|
|
731
|
-
return /* @__PURE__ */ (0,
|
|
732
|
-
/* @__PURE__ */ (0,
|
|
733
|
-
/* @__PURE__ */ (0,
|
|
734
|
-
/* @__PURE__ */ (0,
|
|
735
|
-
/* @__PURE__ */ (0,
|
|
736
|
-
/* @__PURE__ */ (0,
|
|
737
|
-
/* @__PURE__ */ (0,
|
|
738
|
-
/* @__PURE__ */ (0,
|
|
922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
|
|
928
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
|
|
929
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
739
930
|
"button",
|
|
740
931
|
{
|
|
741
932
|
type: "button",
|
|
@@ -750,39 +941,39 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
750
941
|
children: "\u22EF"
|
|
751
942
|
}
|
|
752
943
|
),
|
|
753
|
-
psd && /* @__PURE__ */ (0,
|
|
754
|
-
/* @__PURE__ */ (0,
|
|
755
|
-
/* @__PURE__ */ (0,
|
|
756
|
-
/* @__PURE__ */ (0,
|
|
944
|
+
psd && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
945
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => fileInput.current?.click(), children: "Open PSD\u2026" }),
|
|
946
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: iconButton, onClick: () => psdTask(async () => (await (0, import_image_editor7.downloadPsd)(controller, psdFileName)).warnings), children: "Export PSD" }),
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
757
948
|
"input",
|
|
758
949
|
{
|
|
759
950
|
ref: fileInput,
|
|
760
951
|
type: "file",
|
|
761
|
-
accept:
|
|
952
|
+
accept: import_image_editor7.PSD_FILE_ACCEPT,
|
|
762
953
|
className: "hidden",
|
|
763
954
|
"data-testid": "psd-file-input",
|
|
764
955
|
"aria-label": "Open a PSD file",
|
|
765
956
|
onChange: (e) => {
|
|
766
957
|
const file = e.currentTarget.files?.[0];
|
|
767
958
|
e.currentTarget.value = "";
|
|
768
|
-
if (file) psdTask(() => (0,
|
|
959
|
+
if (file) psdTask(() => (0, import_image_editor7.openPsdFile)(controller, file));
|
|
769
960
|
}
|
|
770
961
|
}
|
|
771
962
|
)
|
|
772
963
|
] })
|
|
773
964
|
] }),
|
|
774
|
-
psdNotes.length > 0 && /* @__PURE__ */ (0,
|
|
775
|
-
psdNotes.map((n) => /* @__PURE__ */ (0,
|
|
776
|
-
/* @__PURE__ */ (0,
|
|
965
|
+
psdNotes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("ul", { className: "rounded bg-amber-900/30 text-amber-200 px-2 py-1 space-y-0.5", "data-testid": "psd-warnings", "aria-label": "PSD warnings", children: [
|
|
966
|
+
psdNotes.map((n) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: n }, n)),
|
|
967
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "underline", onClick: () => setPsdNotes([]), children: "Dismiss" }) })
|
|
777
968
|
] }),
|
|
778
|
-
active && /* @__PURE__ */ (0,
|
|
779
|
-
/* @__PURE__ */ (0,
|
|
780
|
-
/* @__PURE__ */ (0,
|
|
969
|
+
active && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 items-center", "data-testid": "layer-properties", children: [
|
|
970
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
|
|
971
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-slate-400", children: [
|
|
781
972
|
"Opacity ",
|
|
782
973
|
Math.round(active.opacity * 100),
|
|
783
974
|
"%"
|
|
784
975
|
] }),
|
|
785
|
-
/* @__PURE__ */ (0,
|
|
976
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
786
977
|
"input",
|
|
787
978
|
{
|
|
788
979
|
type: "range",
|
|
@@ -796,13 +987,13 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
796
987
|
}
|
|
797
988
|
)
|
|
798
989
|
] }),
|
|
799
|
-
/* @__PURE__ */ (0,
|
|
800
|
-
/* @__PURE__ */ (0,
|
|
990
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
|
|
991
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-slate-400", children: [
|
|
801
992
|
"Fill ",
|
|
802
993
|
Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
|
|
803
994
|
"%"
|
|
804
995
|
] }),
|
|
805
|
-
/* @__PURE__ */ (0,
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
806
997
|
"input",
|
|
807
998
|
{
|
|
808
999
|
type: "range",
|
|
@@ -817,7 +1008,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
817
1008
|
}
|
|
818
1009
|
)
|
|
819
1010
|
] }),
|
|
820
|
-
/* @__PURE__ */ (0,
|
|
1011
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
821
1012
|
"select",
|
|
822
1013
|
{
|
|
823
1014
|
"aria-label": "Layer blend mode",
|
|
@@ -825,13 +1016,13 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
825
1016
|
value: active.blend,
|
|
826
1017
|
onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { blend: e.target.value })),
|
|
827
1018
|
children: [
|
|
828
|
-
active.type === "group" && /* @__PURE__ */ (0,
|
|
829
|
-
|
|
1019
|
+
active.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "pass-through", children: "Pass Through" }),
|
|
1020
|
+
import_image_editor7.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: m.id, children: m.label }, m.id))
|
|
830
1021
|
]
|
|
831
1022
|
}
|
|
832
1023
|
),
|
|
833
|
-
/* @__PURE__ */ (0,
|
|
834
|
-
/* @__PURE__ */ (0,
|
|
1024
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
835
1026
|
"input",
|
|
836
1027
|
{
|
|
837
1028
|
type: "checkbox",
|
|
@@ -843,8 +1034,8 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
843
1034
|
),
|
|
844
1035
|
"Clip to below"
|
|
845
1036
|
] }),
|
|
846
|
-
/* @__PURE__ */ (0,
|
|
847
|
-
/* @__PURE__ */ (0,
|
|
1037
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "col-span-2 flex flex-wrap gap-2 text-slate-400", role: "group", "aria-label": "Layer locks", children: ["pixels", "transparency", "position", "all"].map((k) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1038
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
848
1039
|
"input",
|
|
849
1040
|
{
|
|
850
1041
|
type: "checkbox",
|
|
@@ -857,9 +1048,10 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
857
1048
|
k
|
|
858
1049
|
] }, k)) })
|
|
859
1050
|
] }),
|
|
860
|
-
/* @__PURE__ */ (0,
|
|
1051
|
+
effects && active && active.type !== "adjustment" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayerEffectsPanel, { controller, className: "border-t border-slate-800 pt-1.5" }),
|
|
1052
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
|
|
861
1053
|
const { layer } = row;
|
|
862
|
-
return /* @__PURE__ */ (0,
|
|
1054
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
863
1055
|
"li",
|
|
864
1056
|
{
|
|
865
1057
|
role: "treeitem",
|
|
@@ -889,7 +1081,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
889
1081
|
className: rowClass(row.active),
|
|
890
1082
|
style: { paddingLeft: 6 + row.depth * 14 },
|
|
891
1083
|
children: [
|
|
892
|
-
/* @__PURE__ */ (0,
|
|
1084
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
893
1085
|
"button",
|
|
894
1086
|
{
|
|
895
1087
|
type: "button",
|
|
@@ -903,7 +1095,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
903
1095
|
children: layer.visible ? "\u25CF" : "\u25CB"
|
|
904
1096
|
}
|
|
905
1097
|
),
|
|
906
|
-
layer.type === "group" && /* @__PURE__ */ (0,
|
|
1098
|
+
layer.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
907
1099
|
"button",
|
|
908
1100
|
{
|
|
909
1101
|
type: "button",
|
|
@@ -916,8 +1108,8 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
916
1108
|
children: layer.collapsed ? "\u25B8" : "\u25BE"
|
|
917
1109
|
}
|
|
918
1110
|
),
|
|
919
|
-
row.clipped && /* @__PURE__ */ (0,
|
|
920
|
-
layer.type === "pixel" ? /* @__PURE__ */ (0,
|
|
1111
|
+
row.clipped && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
|
|
1112
|
+
layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
921
1113
|
Thumbnail,
|
|
922
1114
|
{
|
|
923
1115
|
pixels: thumb(layer),
|
|
@@ -925,15 +1117,31 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
925
1117
|
label: `${row.label} pixels`,
|
|
926
1118
|
selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
|
|
927
1119
|
}
|
|
928
|
-
) : /* @__PURE__ */ (0,
|
|
1120
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
929
1121
|
"span",
|
|
930
1122
|
{
|
|
931
1123
|
className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
|
|
932
1124
|
style: { width: thumbnailSize, height: thumbnailSize },
|
|
933
|
-
children: (0,
|
|
1125
|
+
children: (0, import_image_editor7.layerBadge)(layer)
|
|
934
1126
|
}
|
|
935
1127
|
),
|
|
936
|
-
layer.mask && /* @__PURE__ */ (0,
|
|
1128
|
+
layer.mask && !layer.mask.source && layer.type === "pixel" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1129
|
+
"button",
|
|
1130
|
+
{
|
|
1131
|
+
type: "button",
|
|
1132
|
+
"aria-label": `${layer.mask.linked === false ? "Link" : "Unlink"} ${row.label} mask`,
|
|
1133
|
+
"aria-pressed": layer.mask.linked !== false,
|
|
1134
|
+
title: layer.mask.linked === false ? "Mask unlinked: it stays put when the layer moves or transforms. Click to link." : "Mask linked: it moves with the layer. Click to unlink.",
|
|
1135
|
+
"data-testid": "layer-mask-link",
|
|
1136
|
+
className: `shrink-0 text-[10px] leading-none ${layer.mask.linked === false ? "text-slate-600" : "text-slate-300"}`,
|
|
1137
|
+
onClick: (e) => {
|
|
1138
|
+
e.stopPropagation();
|
|
1139
|
+
attempt(() => controller.setLayerMaskProps(layer.id, { linked: layer.mask.linked === false }));
|
|
1140
|
+
},
|
|
1141
|
+
children: layer.mask.linked === false ? "\u26D3\uFE0E\u0338" : "\u26D3\uFE0E"
|
|
1142
|
+
}
|
|
1143
|
+
),
|
|
1144
|
+
layer.mask && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
937
1145
|
Thumbnail,
|
|
938
1146
|
{
|
|
939
1147
|
pixels: maskThumb(layer),
|
|
@@ -948,7 +1156,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
948
1156
|
}
|
|
949
1157
|
}
|
|
950
1158
|
),
|
|
951
|
-
renaming === layer.id ? /* @__PURE__ */ (0,
|
|
1159
|
+
renaming === layer.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
952
1160
|
"input",
|
|
953
1161
|
{
|
|
954
1162
|
autoFocus: true,
|
|
@@ -965,7 +1173,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
965
1173
|
if (e.key === "Escape") setRenaming(null);
|
|
966
1174
|
}
|
|
967
1175
|
}
|
|
968
|
-
) : /* @__PURE__ */ (0,
|
|
1176
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
969
1177
|
"span",
|
|
970
1178
|
{
|
|
971
1179
|
className: `flex-1 min-w-0 truncate ${layer.visible ? "" : "text-slate-500"}`,
|
|
@@ -976,15 +1184,30 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
976
1184
|
children: row.label
|
|
977
1185
|
}
|
|
978
1186
|
),
|
|
979
|
-
|
|
980
|
-
|
|
1187
|
+
(0, import_image_editor7.layerEffectsBadge)(layer) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1188
|
+
"button",
|
|
1189
|
+
{
|
|
1190
|
+
type: "button",
|
|
1191
|
+
"data-testid": "layer-fx-badge",
|
|
1192
|
+
"aria-label": (0, import_image_editor7.layerEffectsBadge)(layer) === "on" ? `Turn effects off for ${row.label}` : `Turn effects on for ${row.label}`,
|
|
1193
|
+
"aria-pressed": (0, import_image_editor7.layerEffectsBadge)(layer) === "on",
|
|
1194
|
+
className: `text-[9px] italic font-semibold ${(0, import_image_editor7.layerEffectsBadge)(layer) === "on" ? "text-indigo-300" : "text-slate-600 line-through"}`,
|
|
1195
|
+
onClick: (e) => {
|
|
1196
|
+
e.stopPropagation();
|
|
1197
|
+
attempt(() => controller.setLayerEffectsEnabled(layer.id, (0, import_image_editor7.layerEffectsBadge)(layer) !== "on"));
|
|
1198
|
+
},
|
|
1199
|
+
children: "fx"
|
|
1200
|
+
}
|
|
1201
|
+
),
|
|
1202
|
+
locked(layer) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
|
|
1203
|
+
layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-[9px] text-slate-500", children: layer.blend })
|
|
981
1204
|
]
|
|
982
1205
|
},
|
|
983
1206
|
layer.id
|
|
984
1207
|
);
|
|
985
1208
|
}) }),
|
|
986
|
-
error && /* @__PURE__ */ (0,
|
|
987
|
-
menu && /* @__PURE__ */ (0,
|
|
1209
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
|
|
1210
|
+
menu && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
988
1211
|
"div",
|
|
989
1212
|
{
|
|
990
1213
|
role: "menu",
|
|
@@ -993,7 +1216,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
993
1216
|
style: { left: menu.x, top: menu.y },
|
|
994
1217
|
onClick: (e) => e.stopPropagation(),
|
|
995
1218
|
onKeyDown: (e) => e.key === "Escape" && setMenu(null),
|
|
996
|
-
children: (0,
|
|
1219
|
+
children: (0, import_image_editor7.layerMenu)(controller).map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
997
1220
|
"button",
|
|
998
1221
|
{
|
|
999
1222
|
type: "button",
|
|
@@ -1011,14 +1234,14 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
1011
1234
|
};
|
|
1012
1235
|
|
|
1013
1236
|
// src/image-editor/BrushOptionsBar.tsx
|
|
1014
|
-
var
|
|
1015
|
-
var
|
|
1016
|
-
var
|
|
1237
|
+
var import_react7 = require("react");
|
|
1238
|
+
var import_image_editor8 = require("@pixerate/editor/image-editor");
|
|
1239
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1017
1240
|
var chip = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
|
|
1018
1241
|
var BrushOptionsBar = ({ controller, className }) => {
|
|
1019
|
-
const [, setTick] = (0,
|
|
1020
|
-
(0,
|
|
1021
|
-
const [error, setError] = (0,
|
|
1242
|
+
const [, setTick] = (0, import_react7.useState)(0);
|
|
1243
|
+
(0, import_react7.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
1244
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
1022
1245
|
const state = controller.getState();
|
|
1023
1246
|
const { brush, foreground, background, mixer, mixerLoad } = state.paint;
|
|
1024
1247
|
const attempt = (fn) => {
|
|
@@ -1029,8 +1252,8 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1029
1252
|
setError(err instanceof Error ? err.message : String(err));
|
|
1030
1253
|
}
|
|
1031
1254
|
};
|
|
1032
|
-
return /* @__PURE__ */ (0,
|
|
1033
|
-
/* @__PURE__ */ (0,
|
|
1255
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor8.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1034
1257
|
"button",
|
|
1035
1258
|
{
|
|
1036
1259
|
type: "button",
|
|
@@ -1042,9 +1265,9 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1042
1265
|
},
|
|
1043
1266
|
t.id
|
|
1044
1267
|
)) }),
|
|
1045
|
-
/* @__PURE__ */ (0,
|
|
1046
|
-
/* @__PURE__ */ (0,
|
|
1047
|
-
/* @__PURE__ */ (0,
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1048
1271
|
"input",
|
|
1049
1272
|
{
|
|
1050
1273
|
type: "color",
|
|
@@ -1054,10 +1277,10 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1054
1277
|
className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
|
|
1055
1278
|
}
|
|
1056
1279
|
),
|
|
1057
|
-
/* @__PURE__ */ (0,
|
|
1280
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", children: "FG" })
|
|
1058
1281
|
] }),
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1282
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1283
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1061
1284
|
"input",
|
|
1062
1285
|
{
|
|
1063
1286
|
type: "color",
|
|
@@ -1067,12 +1290,12 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1067
1290
|
className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
|
|
1068
1291
|
}
|
|
1069
1292
|
),
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1293
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", children: "BG" })
|
|
1071
1294
|
] }),
|
|
1072
|
-
/* @__PURE__ */ (0,
|
|
1073
|
-
/* @__PURE__ */ (0,
|
|
1295
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
|
|
1296
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
|
|
1074
1297
|
] }),
|
|
1075
|
-
|
|
1298
|
+
import_image_editor8.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1076
1299
|
ControlSlider,
|
|
1077
1300
|
{
|
|
1078
1301
|
spec,
|
|
@@ -1081,21 +1304,21 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1081
1304
|
},
|
|
1082
1305
|
spec.id
|
|
1083
1306
|
)),
|
|
1084
|
-
state.activeTool === "mixer" && /* @__PURE__ */ (0,
|
|
1085
|
-
/* @__PURE__ */ (0,
|
|
1086
|
-
/* @__PURE__ */ (0,
|
|
1307
|
+
state.activeTool === "mixer" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2 border-t border-slate-800 pt-2", role: "group", "aria-label": "Mixer Brush", "data-testid": "mixer-options", children: [
|
|
1308
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1309
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1087
1310
|
"span",
|
|
1088
1311
|
{
|
|
1089
1312
|
"aria-label": "Brush load",
|
|
1090
|
-
title: mixerLoad.reservoir ? `Loaded ${(0,
|
|
1313
|
+
title: mixerLoad.reservoir ? `Loaded ${(0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
|
|
1091
1314
|
className: "h-6 w-6 rounded border border-slate-700",
|
|
1092
|
-
style: { background: mixerLoad.reservoir ? (0,
|
|
1315
|
+
style: { background: mixerLoad.reservoir ? (0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir) : "transparent" }
|
|
1093
1316
|
}
|
|
1094
1317
|
),
|
|
1095
|
-
/* @__PURE__ */ (0,
|
|
1096
|
-
/* @__PURE__ */ (0,
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
|
|
1097
1320
|
] }),
|
|
1098
|
-
/* @__PURE__ */ (0,
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: import_image_editor8.MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1099
1322
|
"button",
|
|
1100
1323
|
{
|
|
1101
1324
|
type: "button",
|
|
@@ -1107,10 +1330,10 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1107
1330
|
},
|
|
1108
1331
|
m.id
|
|
1109
1332
|
)) }),
|
|
1110
|
-
|
|
1111
|
-
/* @__PURE__ */ (0,
|
|
1112
|
-
/* @__PURE__ */ (0,
|
|
1113
|
-
/* @__PURE__ */ (0,
|
|
1333
|
+
import_image_editor8.MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
|
|
1335
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
1336
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1114
1337
|
"input",
|
|
1115
1338
|
{
|
|
1116
1339
|
type: "checkbox",
|
|
@@ -1122,8 +1345,8 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1122
1345
|
),
|
|
1123
1346
|
"Load each stroke"
|
|
1124
1347
|
] }),
|
|
1125
|
-
/* @__PURE__ */ (0,
|
|
1126
|
-
/* @__PURE__ */ (0,
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
1349
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1127
1350
|
"input",
|
|
1128
1351
|
{
|
|
1129
1352
|
type: "checkbox",
|
|
@@ -1137,9 +1360,9 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1137
1360
|
] })
|
|
1138
1361
|
] })
|
|
1139
1362
|
] }),
|
|
1140
|
-
/* @__PURE__ */ (0,
|
|
1141
|
-
/* @__PURE__ */ (0,
|
|
1142
|
-
/* @__PURE__ */ (0,
|
|
1363
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
|
|
1364
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
1365
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1143
1366
|
"input",
|
|
1144
1367
|
{
|
|
1145
1368
|
type: "checkbox",
|
|
@@ -1151,8 +1374,8 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1151
1374
|
),
|
|
1152
1375
|
"Pressure size"
|
|
1153
1376
|
] }),
|
|
1154
|
-
/* @__PURE__ */ (0,
|
|
1155
|
-
/* @__PURE__ */ (0,
|
|
1377
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1156
1379
|
"input",
|
|
1157
1380
|
{
|
|
1158
1381
|
type: "checkbox",
|
|
@@ -1165,18 +1388,18 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1165
1388
|
"Pressure opacity"
|
|
1166
1389
|
] })
|
|
1167
1390
|
] }),
|
|
1168
|
-
/* @__PURE__ */ (0,
|
|
1169
|
-
/* @__PURE__ */ (0,
|
|
1170
|
-
/* @__PURE__ */ (0,
|
|
1391
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-1", children: [
|
|
1392
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
|
|
1171
1394
|
] }),
|
|
1172
|
-
error && /* @__PURE__ */ (0,
|
|
1395
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
|
|
1173
1396
|
] });
|
|
1174
1397
|
};
|
|
1175
1398
|
|
|
1176
1399
|
// src/image-editor/SelectionOptionsBar.tsx
|
|
1177
|
-
var
|
|
1178
|
-
var
|
|
1179
|
-
var
|
|
1400
|
+
var import_react8 = require("react");
|
|
1401
|
+
var import_image_editor9 = require("@pixerate/editor/image-editor");
|
|
1402
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1180
1403
|
var MODIFY_OPS = [
|
|
1181
1404
|
{ op: "grow", label: "Grow" },
|
|
1182
1405
|
{ op: "shrink", label: "Shrink" },
|
|
@@ -1193,20 +1416,20 @@ var SelectionOptionsBar = ({
|
|
|
1193
1416
|
quickMask,
|
|
1194
1417
|
className = ""
|
|
1195
1418
|
}) => {
|
|
1196
|
-
const [radius, setRadius] = (0,
|
|
1419
|
+
const [radius, setRadius] = (0, import_react8.useState)(2);
|
|
1197
1420
|
const set = (patch) => onOptionsChange({ ...options, ...patch });
|
|
1198
1421
|
const sel = selection === void 0 ? controller.getSelection() : selection;
|
|
1199
1422
|
const qm = quickMask ?? Boolean(controller.getState().quickMask);
|
|
1200
|
-
return /* @__PURE__ */ (0,
|
|
1201
|
-
/* @__PURE__ */ (0,
|
|
1202
|
-
/* @__PURE__ */ (0,
|
|
1203
|
-
options.tool === "wand" && /* @__PURE__ */ (0,
|
|
1204
|
-
/* @__PURE__ */ (0,
|
|
1205
|
-
/* @__PURE__ */ (0,
|
|
1206
|
-
/* @__PURE__ */ (0,
|
|
1207
|
-
/* @__PURE__ */ (0,
|
|
1423
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
|
|
1424
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor9.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
|
|
1425
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor9.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor9.SELECTION_MODE_LABELS[m] }, m)) }),
|
|
1426
|
+
options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Tolerance" }),
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-mono", children: options.tolerance })
|
|
1208
1431
|
] }),
|
|
1209
|
-
/* @__PURE__ */ (0,
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1210
1433
|
"input",
|
|
1211
1434
|
{
|
|
1212
1435
|
type: "range",
|
|
@@ -1220,17 +1443,17 @@ var SelectionOptionsBar = ({
|
|
|
1220
1443
|
}
|
|
1221
1444
|
)
|
|
1222
1445
|
] }),
|
|
1223
|
-
/* @__PURE__ */ (0,
|
|
1224
|
-
/* @__PURE__ */ (0,
|
|
1446
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1447
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
|
|
1225
1448
|
"Contiguous"
|
|
1226
1449
|
] }),
|
|
1227
|
-
/* @__PURE__ */ (0,
|
|
1228
|
-
/* @__PURE__ */ (0,
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1451
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
|
|
1229
1452
|
"Sample adjusted image"
|
|
1230
1453
|
] }),
|
|
1231
|
-
/* @__PURE__ */ (0,
|
|
1454
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1232
1455
|
"Sample",
|
|
1233
|
-
/* @__PURE__ */ (0,
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1234
1457
|
"select",
|
|
1235
1458
|
{
|
|
1236
1459
|
"aria-label": "Sample from",
|
|
@@ -1238,27 +1461,27 @@ var SelectionOptionsBar = ({
|
|
|
1238
1461
|
onChange: (e) => set({ sample: e.target.value }),
|
|
1239
1462
|
className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
|
|
1240
1463
|
children: [
|
|
1241
|
-
/* @__PURE__ */ (0,
|
|
1242
|
-
/* @__PURE__ */ (0,
|
|
1464
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "composite", children: "All layers" }),
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "active-layer", children: "Active layer" })
|
|
1243
1466
|
]
|
|
1244
1467
|
}
|
|
1245
1468
|
)
|
|
1246
1469
|
] })
|
|
1247
1470
|
] }),
|
|
1248
|
-
/* @__PURE__ */ (0,
|
|
1249
|
-
/* @__PURE__ */ (0,
|
|
1471
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1472
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
|
|
1250
1473
|
"Anti-alias"
|
|
1251
1474
|
] }),
|
|
1252
|
-
/* @__PURE__ */ (0,
|
|
1253
|
-
/* @__PURE__ */ (0,
|
|
1254
|
-
/* @__PURE__ */ (0,
|
|
1255
|
-
/* @__PURE__ */ (0,
|
|
1256
|
-
/* @__PURE__ */ (0,
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
1476
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
|
|
1477
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
|
|
1479
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
|
|
1257
1480
|
] }),
|
|
1258
|
-
/* @__PURE__ */ (0,
|
|
1259
|
-
/* @__PURE__ */ (0,
|
|
1481
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
|
|
1260
1483
|
"Radius",
|
|
1261
|
-
/* @__PURE__ */ (0,
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1262
1485
|
"input",
|
|
1263
1486
|
{
|
|
1264
1487
|
type: "number",
|
|
@@ -1272,24 +1495,24 @@ var SelectionOptionsBar = ({
|
|
|
1272
1495
|
}
|
|
1273
1496
|
)
|
|
1274
1497
|
] }),
|
|
1275
|
-
MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0,
|
|
1498
|
+
MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
|
|
1276
1499
|
] }),
|
|
1277
|
-
/* @__PURE__ */ (0,
|
|
1500
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor9.describeSelection)(sel) })
|
|
1278
1501
|
] });
|
|
1279
1502
|
};
|
|
1280
1503
|
|
|
1281
1504
|
// src/image-editor/RefineEdgePanel.tsx
|
|
1282
|
-
var
|
|
1283
|
-
var
|
|
1284
|
-
var
|
|
1505
|
+
var import_react9 = require("react");
|
|
1506
|
+
var import_image_editor10 = require("@pixerate/editor/image-editor");
|
|
1507
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1285
1508
|
var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
|
|
1286
|
-
var
|
|
1509
|
+
var button2 = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
|
|
1287
1510
|
var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
1288
|
-
const [params, setParams] = (0,
|
|
1289
|
-
const [busy, setBusy] = (0,
|
|
1290
|
-
const [error, setError] = (0,
|
|
1291
|
-
const [layerId, setLayerId] = (0,
|
|
1292
|
-
const [newKind, setNewKind] = (0,
|
|
1511
|
+
const [params, setParams] = (0, import_react9.useState)(DEFAULT_PARAMS);
|
|
1512
|
+
const [busy, setBusy] = (0, import_react9.useState)(false);
|
|
1513
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
1514
|
+
const [layerId, setLayerId] = (0, import_react9.useState)("");
|
|
1515
|
+
const [newKind, setNewKind] = (0, import_react9.useState)("hueSaturation");
|
|
1293
1516
|
const sel = selection === void 0 ? controller.getSelection() : selection;
|
|
1294
1517
|
const list = layers ?? controller.getAdjustmentLayers();
|
|
1295
1518
|
const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
|
|
@@ -1304,17 +1527,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1304
1527
|
setBusy(false);
|
|
1305
1528
|
}
|
|
1306
1529
|
};
|
|
1307
|
-
return /* @__PURE__ */ (0,
|
|
1308
|
-
/* @__PURE__ */ (0,
|
|
1309
|
-
|
|
1310
|
-
/* @__PURE__ */ (0,
|
|
1311
|
-
/* @__PURE__ */ (0,
|
|
1312
|
-
/* @__PURE__ */ (0,
|
|
1530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
|
|
1531
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
|
|
1532
|
+
import_image_editor10.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1533
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: c.label }),
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
|
|
1313
1536
|
params[c.id],
|
|
1314
1537
|
c.unit
|
|
1315
1538
|
] })
|
|
1316
1539
|
] }),
|
|
1317
|
-
/* @__PURE__ */ (0,
|
|
1540
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1318
1541
|
"input",
|
|
1319
1542
|
{
|
|
1320
1543
|
type: "range",
|
|
@@ -1328,67 +1551,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1328
1551
|
}
|
|
1329
1552
|
)
|
|
1330
1553
|
] }, c.id)),
|
|
1331
|
-
/* @__PURE__ */ (0,
|
|
1332
|
-
/* @__PURE__ */ (0,
|
|
1554
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1555
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
|
|
1333
1556
|
"Smart Radius"
|
|
1334
1557
|
] }),
|
|
1335
|
-
/* @__PURE__ */ (0,
|
|
1336
|
-
/* @__PURE__ */ (0,
|
|
1337
|
-
/* @__PURE__ */ (0,
|
|
1558
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-1", children: [
|
|
1559
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
|
|
1560
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
|
|
1338
1561
|
] }),
|
|
1339
|
-
error && /* @__PURE__ */ (0,
|
|
1340
|
-
/* @__PURE__ */ (0,
|
|
1341
|
-
/* @__PURE__ */ (0,
|
|
1342
|
-
/* @__PURE__ */ (0,
|
|
1562
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
|
|
1563
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
|
|
1564
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-1 items-center", children: [
|
|
1565
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1343
1566
|
"select",
|
|
1344
1567
|
{
|
|
1345
1568
|
"aria-label": "New masked layer kind",
|
|
1346
1569
|
value: newKind,
|
|
1347
1570
|
onChange: (e) => setNewKind(e.target.value),
|
|
1348
1571
|
className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
|
|
1349
|
-
children:
|
|
1572
|
+
children: import_image_editor10.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: k.kind, children: k.label }, k.kind))
|
|
1350
1573
|
}
|
|
1351
1574
|
),
|
|
1352
|
-
/* @__PURE__ */ (0,
|
|
1575
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1353
1576
|
"button",
|
|
1354
1577
|
{
|
|
1355
1578
|
type: "button",
|
|
1356
|
-
className:
|
|
1579
|
+
className: button2,
|
|
1357
1580
|
disabled: !sel,
|
|
1358
|
-
onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0,
|
|
1581
|
+
onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor10.layerMaskFromSelection)(sel) })),
|
|
1359
1582
|
children: "New Masked Layer"
|
|
1360
1583
|
}
|
|
1361
1584
|
)
|
|
1362
1585
|
] }),
|
|
1363
|
-
list.length > 0 && target && /* @__PURE__ */ (0,
|
|
1364
|
-
/* @__PURE__ */ (0,
|
|
1586
|
+
list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1587
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1365
1588
|
"select",
|
|
1366
1589
|
{
|
|
1367
1590
|
"aria-label": "Mask layer",
|
|
1368
1591
|
value: target.id,
|
|
1369
1592
|
onChange: (e) => setLayerId(e.target.value),
|
|
1370
1593
|
className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
|
|
1371
|
-
children: list.map((l) => /* @__PURE__ */ (0,
|
|
1372
|
-
l.name || (0,
|
|
1594
|
+
children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("option", { value: l.id, children: [
|
|
1595
|
+
l.name || (0, import_image_editor10.adjustmentKindLabel)(l.kind),
|
|
1373
1596
|
l.mask ? " (masked)" : ""
|
|
1374
1597
|
] }, l.id))
|
|
1375
1598
|
}
|
|
1376
1599
|
),
|
|
1377
|
-
/* @__PURE__ */ (0,
|
|
1378
|
-
/* @__PURE__ */ (0,
|
|
1379
|
-
/* @__PURE__ */ (0,
|
|
1380
|
-
/* @__PURE__ */ (0,
|
|
1600
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
1601
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
|
|
1602
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
|
|
1603
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
|
|
1381
1604
|
] }),
|
|
1382
|
-
target.mask && /* @__PURE__ */ (0,
|
|
1383
|
-
/* @__PURE__ */ (0,
|
|
1384
|
-
/* @__PURE__ */ (0,
|
|
1385
|
-
/* @__PURE__ */ (0,
|
|
1386
|
-
/* @__PURE__ */ (0,
|
|
1605
|
+
target.mask && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
1606
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1607
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1608
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Density" }),
|
|
1609
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
|
|
1387
1610
|
Math.round((target.mask.density ?? 1) * 100),
|
|
1388
1611
|
"%"
|
|
1389
1612
|
] })
|
|
1390
1613
|
] }),
|
|
1391
|
-
/* @__PURE__ */ (0,
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1392
1615
|
"input",
|
|
1393
1616
|
{
|
|
1394
1617
|
type: "range",
|
|
@@ -1402,15 +1625,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1402
1625
|
}
|
|
1403
1626
|
)
|
|
1404
1627
|
] }),
|
|
1405
|
-
/* @__PURE__ */ (0,
|
|
1406
|
-
/* @__PURE__ */ (0,
|
|
1407
|
-
/* @__PURE__ */ (0,
|
|
1408
|
-
/* @__PURE__ */ (0,
|
|
1628
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Mask Feather" }),
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "font-mono", children: [
|
|
1409
1632
|
target.mask.feather ?? 0,
|
|
1410
1633
|
"px"
|
|
1411
1634
|
] })
|
|
1412
1635
|
] }),
|
|
1413
|
-
/* @__PURE__ */ (0,
|
|
1636
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1414
1637
|
"input",
|
|
1415
1638
|
{
|
|
1416
1639
|
type: "range",
|
|
@@ -1429,8 +1652,83 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1429
1652
|
] });
|
|
1430
1653
|
};
|
|
1431
1654
|
|
|
1655
|
+
// src/image-editor/FreeTransformOptionsBar.tsx
|
|
1656
|
+
var import_react10 = require("react");
|
|
1657
|
+
var import_image_editor11 = require("@pixerate/editor/image-editor");
|
|
1658
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1659
|
+
var chip2 = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
|
|
1660
|
+
var round = (v, unit) => unit === "px" ? Math.round(v * 10) / 10 : Math.round(v * 100) / 100;
|
|
1661
|
+
var FreeTransformOptionsBar = ({ tool, className }) => {
|
|
1662
|
+
const [, setTick] = (0, import_react10.useState)(0);
|
|
1663
|
+
(0, import_react10.useEffect)(() => tool.subscribe(() => setTick((n) => n + 1)), [tool]);
|
|
1664
|
+
const bar = tool.bar();
|
|
1665
|
+
if (!tool.active || !bar) return null;
|
|
1666
|
+
const apply = (field, raw) => {
|
|
1667
|
+
const v = Number(raw);
|
|
1668
|
+
if (raw.trim() !== "" && Number.isFinite(v) && Math.abs(v - bar[field]) > 1e-9) tool.setField(field, v);
|
|
1669
|
+
};
|
|
1670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `flex flex-wrap items-center gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "free-transform-options", role: "toolbar", "aria-label": "Free Transform options", children: [
|
|
1671
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Transform mode", children: import_image_editor11.FREE_TRANSFORM_MODE_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", title: m.title, "aria-pressed": tool.mode === m.id, className: chip2(tool.mode === m.id), onClick: () => tool.setMode(m.id), children: m.label }, m.id)) }),
|
|
1672
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "grid grid-cols-3 gap-px", role: "group", "aria-label": "Reference point", children: import_image_editor11.TRANSFORM_ANCHORS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-label": `Reference point ${a}`, title: `Reference point: ${a}`, className: "h-2.5 w-2.5 rounded-sm bg-slate-700 hover:bg-indigo-500", onClick: () => tool.setReference(a) }, a)) }),
|
|
1673
|
+
import_image_editor11.FREE_TRANSFORM_FIELDS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-1", title: f.title, children: [
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-slate-400", children: f.label }),
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1676
|
+
"input",
|
|
1677
|
+
{
|
|
1678
|
+
type: "number",
|
|
1679
|
+
"aria-label": f.title,
|
|
1680
|
+
defaultValue: round(bar[f.id], f.unit),
|
|
1681
|
+
disabled: !bar.affine,
|
|
1682
|
+
step: f.unit === "px" ? 1 : 0.1,
|
|
1683
|
+
className: "w-16 rounded border border-slate-700 bg-slate-900 px-1 py-0.5 text-right disabled:opacity-40",
|
|
1684
|
+
onBlur: (e) => apply(f.id, e.currentTarget.value),
|
|
1685
|
+
onKeyDown: (e) => {
|
|
1686
|
+
if (e.key === "Enter") {
|
|
1687
|
+
e.preventDefault();
|
|
1688
|
+
e.stopPropagation();
|
|
1689
|
+
apply(f.id, e.currentTarget.value);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
},
|
|
1693
|
+
`${f.id}:${round(bar[f.id], f.unit)}`
|
|
1694
|
+
),
|
|
1695
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-slate-500", children: f.unit }),
|
|
1696
|
+
f.id === "scaleX" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1697
|
+
"button",
|
|
1698
|
+
{
|
|
1699
|
+
type: "button",
|
|
1700
|
+
"aria-label": "Keep width and height proportional",
|
|
1701
|
+
"aria-pressed": tool.proportional,
|
|
1702
|
+
className: chip2(tool.proportional),
|
|
1703
|
+
onClick: () => {
|
|
1704
|
+
tool.proportional = !tool.proportional;
|
|
1705
|
+
setTick((n) => n + 1);
|
|
1706
|
+
},
|
|
1707
|
+
children: "\u26D3\uFE0E"
|
|
1708
|
+
}
|
|
1709
|
+
)
|
|
1710
|
+
] }, f.id)),
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-slate-400", children: "Interpolation" }),
|
|
1713
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1714
|
+
"select",
|
|
1715
|
+
{
|
|
1716
|
+
"aria-label": "Interpolation",
|
|
1717
|
+
value: tool.interpolation,
|
|
1718
|
+
onChange: (e) => tool.setInterpolation(e.target.value),
|
|
1719
|
+
className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
|
|
1720
|
+
children: import_image_editor11.INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: i, children: i[0].toUpperCase() + i.slice(1) }, i))
|
|
1721
|
+
}
|
|
1722
|
+
)
|
|
1723
|
+
] }),
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", title: "Commit (Enter)", className: "px-2 py-1 rounded bg-emerald-600 text-white hover:bg-emerald-500", onClick: () => tool.commit(), children: "Commit" }),
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", title: "Cancel (Esc)", className: chip2(false), onClick: () => tool.cancel(), children: "Cancel" }),
|
|
1726
|
+
tool.error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { role: "alert", className: "text-rose-400", children: tool.error })
|
|
1727
|
+
] });
|
|
1728
|
+
};
|
|
1729
|
+
|
|
1432
1730
|
// src/image-editor/ImageEditor.tsx
|
|
1433
|
-
var
|
|
1731
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1434
1732
|
var ImageEditor = ({
|
|
1435
1733
|
editor: externalEditor,
|
|
1436
1734
|
src,
|
|
@@ -1445,35 +1743,47 @@ var ImageEditor = ({
|
|
|
1445
1743
|
const internalEditor = useImageEditor({ image: src });
|
|
1446
1744
|
const editor = externalEditor || internalEditor;
|
|
1447
1745
|
const { state, controller } = editor;
|
|
1448
|
-
const legacyProcess = (0,
|
|
1449
|
-
const canvasRef = (0,
|
|
1450
|
-
const containerRef = (0,
|
|
1451
|
-
const [activeTab, setActiveTab] = (0,
|
|
1452
|
-
const [activeCropRatio, setActiveCropRatio] = (0,
|
|
1453
|
-
const [selectionOptions, setSelectionOptions] = (0,
|
|
1454
|
-
const selectionOptionsRef = (0,
|
|
1746
|
+
const legacyProcess = (0, import_image_editor12.normalizeProcessVersion)(state.adjustments.process) < import_image_editor12.LATEST_PROCESS_VERSION;
|
|
1747
|
+
const canvasRef = (0, import_react11.useRef)(null);
|
|
1748
|
+
const containerRef = (0, import_react11.useRef)(null);
|
|
1749
|
+
const [activeTab, setActiveTab] = (0, import_react11.useState)("crop");
|
|
1750
|
+
const [activeCropRatio, setActiveCropRatio] = (0, import_react11.useState)(null);
|
|
1751
|
+
const [selectionOptions, setSelectionOptions] = (0, import_react11.useState)(import_image_editor12.DEFAULT_SELECTION_TOOL_OPTIONS);
|
|
1752
|
+
const selectionOptionsRef = (0, import_react11.useRef)(selectionOptions);
|
|
1455
1753
|
selectionOptionsRef.current = selectionOptions;
|
|
1456
|
-
const selectionGestureRef = (0,
|
|
1754
|
+
const selectionGestureRef = (0, import_react11.useRef)(null);
|
|
1457
1755
|
if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
|
|
1458
|
-
selectionGestureRef.current = new
|
|
1756
|
+
selectionGestureRef.current = new import_image_editor12.SelectionGesture(controller, () => selectionOptionsRef.current);
|
|
1459
1757
|
}
|
|
1460
|
-
const selectionDraftRef = (0,
|
|
1461
|
-
const [selectionError, setSelectionError] = (0,
|
|
1462
|
-
const paintGestureRef = (0,
|
|
1463
|
-
const paintControllerRef = (0,
|
|
1758
|
+
const selectionDraftRef = (0, import_react11.useRef)(null);
|
|
1759
|
+
const [selectionError, setSelectionError] = (0, import_react11.useState)(null);
|
|
1760
|
+
const paintGestureRef = (0, import_react11.useRef)(null);
|
|
1761
|
+
const paintControllerRef = (0, import_react11.useRef)(controller);
|
|
1464
1762
|
if (!paintGestureRef.current || paintControllerRef.current !== controller) {
|
|
1465
|
-
paintGestureRef.current = new
|
|
1763
|
+
paintGestureRef.current = new import_image_editor12.PaintGesture(controller);
|
|
1466
1764
|
paintControllerRef.current = controller;
|
|
1467
1765
|
}
|
|
1468
|
-
const brushCursorRef = (0,
|
|
1469
|
-
const [paintError, setPaintError] = (0,
|
|
1470
|
-
const
|
|
1471
|
-
const
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1766
|
+
const brushCursorRef = (0, import_react11.useRef)(null);
|
|
1767
|
+
const [paintError, setPaintError] = (0, import_react11.useState)(null);
|
|
1768
|
+
const transformToolRef = (0, import_react11.useRef)(null);
|
|
1769
|
+
const transformControllerRef = (0, import_react11.useRef)(controller);
|
|
1770
|
+
if (!transformToolRef.current || transformControllerRef.current !== controller) {
|
|
1771
|
+
transformToolRef.current?.cancel();
|
|
1772
|
+
transformToolRef.current = new import_image_editor12.FreeTransformTool(controller, {
|
|
1773
|
+
schedule: (run) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(run) : run()
|
|
1774
|
+
});
|
|
1775
|
+
transformControllerRef.current = controller;
|
|
1776
|
+
}
|
|
1777
|
+
const transformTool = transformToolRef.current;
|
|
1778
|
+
const [, setTransformTick] = (0, import_react11.useState)(0);
|
|
1779
|
+
const [transformCursor, setTransformCursor] = (0, import_react11.useState)("default");
|
|
1780
|
+
const [inpaintPrompt, setInpaintPrompt] = (0, import_react11.useState)("");
|
|
1781
|
+
const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react11.useState)("annotations");
|
|
1782
|
+
const [isRemovingBg, setIsRemovingBg] = (0, import_react11.useState)(false);
|
|
1783
|
+
const [isInpainting, setIsInpainting] = (0, import_react11.useState)(false);
|
|
1784
|
+
const [aiError, setAiError] = (0, import_react11.useState)(null);
|
|
1785
|
+
const [aiSuccess, setAiSuccess] = (0, import_react11.useState)(null);
|
|
1786
|
+
const [aiTarget, setAiTarget] = (0, import_react11.useState)("auto");
|
|
1477
1787
|
const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
|
|
1478
1788
|
const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
|
|
1479
1789
|
const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
|
|
@@ -1536,18 +1846,18 @@ var ImageEditor = ({
|
|
|
1536
1846
|
setIsInpainting(false);
|
|
1537
1847
|
}
|
|
1538
1848
|
};
|
|
1539
|
-
const [activeColor, setActiveColor] = (0,
|
|
1540
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
1541
|
-
const [fontSize, setFontSize] = (0,
|
|
1542
|
-
const [textInput, setTextInput] = (0,
|
|
1543
|
-
const draftAnnotationRef = (0,
|
|
1544
|
-
const draftCropRef = (0,
|
|
1545
|
-
const cropDragInfoRef = (0,
|
|
1546
|
-
const annotationDragInfoRef = (0,
|
|
1547
|
-
const isDrawingRef = (0,
|
|
1548
|
-
const currentPathRef = (0,
|
|
1549
|
-
const dragStartPointRef = (0,
|
|
1550
|
-
const renderCanvas = (0,
|
|
1849
|
+
const [activeColor, setActiveColor] = (0, import_react11.useState)("#ef4444");
|
|
1850
|
+
const [strokeWidth, setStrokeWidth] = (0, import_react11.useState)(3);
|
|
1851
|
+
const [fontSize, setFontSize] = (0, import_react11.useState)(24);
|
|
1852
|
+
const [textInput, setTextInput] = (0, import_react11.useState)("");
|
|
1853
|
+
const draftAnnotationRef = (0, import_react11.useRef)(null);
|
|
1854
|
+
const draftCropRef = (0, import_react11.useRef)(null);
|
|
1855
|
+
const cropDragInfoRef = (0, import_react11.useRef)(null);
|
|
1856
|
+
const annotationDragInfoRef = (0, import_react11.useRef)(null);
|
|
1857
|
+
const isDrawingRef = (0, import_react11.useRef)(false);
|
|
1858
|
+
const currentPathRef = (0, import_react11.useRef)([]);
|
|
1859
|
+
const dragStartPointRef = (0, import_react11.useRef)(null);
|
|
1860
|
+
const renderCanvas = (0, import_react11.useCallback)(
|
|
1551
1861
|
async (draftAnnotation, draftCrop) => {
|
|
1552
1862
|
const canvas = canvasRef.current;
|
|
1553
1863
|
const container = containerRef.current;
|
|
@@ -1563,12 +1873,64 @@ var ImageEditor = ({
|
|
|
1563
1873
|
draftAnnotation: draftAnnotation !== void 0 ? draftAnnotation : draftAnnotationRef.current,
|
|
1564
1874
|
draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
|
|
1565
1875
|
draftSelectionPath: selectionDraftRef.current,
|
|
1566
|
-
brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null
|
|
1876
|
+
brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" && !transformTool.active ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null,
|
|
1877
|
+
freeTransform: transformTool.overlay()
|
|
1567
1878
|
});
|
|
1568
1879
|
},
|
|
1569
|
-
[controller, activeTab]
|
|
1880
|
+
[controller, activeTab, transformTool]
|
|
1570
1881
|
);
|
|
1571
|
-
(0,
|
|
1882
|
+
(0, import_react11.useEffect)(() => transformTool.subscribe(() => {
|
|
1883
|
+
setTransformTick((n) => n + 1);
|
|
1884
|
+
void renderCanvas();
|
|
1885
|
+
}), [transformTool, renderCanvas]);
|
|
1886
|
+
const transformPoint = (e) => {
|
|
1887
|
+
const canvas = canvasRef.current;
|
|
1888
|
+
const rect = canvas.getBoundingClientRect();
|
|
1889
|
+
const sx = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
1890
|
+
const sy = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
1891
|
+
const s = controller.getState();
|
|
1892
|
+
const cropping = activeTab === "crop";
|
|
1893
|
+
const projection = (0, import_image_editor12.getViewportProjection)(s, canvas.width, canvas.height, cropping);
|
|
1894
|
+
const pt = (0, import_image_editor12.canvasToImagePoint)({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvas.width, canvas.height, cropping);
|
|
1895
|
+
transformTool.setView(projection.scale);
|
|
1896
|
+
return { pt, tolerance: 6 / (projection.scale || 1) };
|
|
1897
|
+
};
|
|
1898
|
+
const handleTransformPointerDown = (e) => {
|
|
1899
|
+
if (!transformTool.active) return false;
|
|
1900
|
+
if (e.button !== 0) return true;
|
|
1901
|
+
e.preventDefault();
|
|
1902
|
+
try {
|
|
1903
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
1904
|
+
} catch {
|
|
1905
|
+
}
|
|
1906
|
+
const { pt, tolerance } = transformPoint(e);
|
|
1907
|
+
transformTool.down(pt, tolerance);
|
|
1908
|
+
return true;
|
|
1909
|
+
};
|
|
1910
|
+
const handleTransformPointerMove = (e) => {
|
|
1911
|
+
if (!transformTool.active) return false;
|
|
1912
|
+
const { pt, tolerance } = transformPoint(e);
|
|
1913
|
+
if (e.buttons & 1) transformTool.move(pt, e);
|
|
1914
|
+
else {
|
|
1915
|
+
const over = transformTool.hit(pt, tolerance);
|
|
1916
|
+
setTransformCursor(transformTool.cursor(over));
|
|
1917
|
+
}
|
|
1918
|
+
return true;
|
|
1919
|
+
};
|
|
1920
|
+
const handleTransformPointerUp = () => {
|
|
1921
|
+
if (!transformTool.active) return false;
|
|
1922
|
+
transformTool.up();
|
|
1923
|
+
return true;
|
|
1924
|
+
};
|
|
1925
|
+
(0, import_react11.useEffect)(() => {
|
|
1926
|
+
if (typeof window === "undefined") return;
|
|
1927
|
+
const onKey = (e) => {
|
|
1928
|
+
if (transformTool.key(e)) e.preventDefault();
|
|
1929
|
+
};
|
|
1930
|
+
window.addEventListener("keydown", onKey);
|
|
1931
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
1932
|
+
}, [transformTool]);
|
|
1933
|
+
(0, import_react11.useEffect)(() => {
|
|
1572
1934
|
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
1573
1935
|
const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
1574
1936
|
const animId = raf(() => {
|
|
@@ -1576,12 +1938,12 @@ var ImageEditor = ({
|
|
|
1576
1938
|
});
|
|
1577
1939
|
return () => caf(animId);
|
|
1578
1940
|
}, [renderCanvas, state]);
|
|
1579
|
-
(0,
|
|
1941
|
+
(0, import_react11.useEffect)(() => {
|
|
1580
1942
|
if (activeTab === "crop" && editor.state.activeTool !== "crop") {
|
|
1581
1943
|
editor.setTool("crop");
|
|
1582
1944
|
}
|
|
1583
1945
|
}, [activeTab, editor]);
|
|
1584
|
-
(0,
|
|
1946
|
+
(0, import_react11.useEffect)(() => {
|
|
1585
1947
|
const container = containerRef.current;
|
|
1586
1948
|
if (!container) return;
|
|
1587
1949
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -1617,11 +1979,12 @@ var ImageEditor = ({
|
|
|
1617
1979
|
const sy = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
1618
1980
|
const s = controller.getState();
|
|
1619
1981
|
return list.map((ev) => ({
|
|
1620
|
-
...(0,
|
|
1621
|
-
pressure: (0,
|
|
1982
|
+
...(0, import_image_editor12.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
|
|
1983
|
+
pressure: (0, import_image_editor12.pointerPressure)(ev)
|
|
1622
1984
|
}));
|
|
1623
1985
|
};
|
|
1624
1986
|
const handlePaintPointerDown = (e) => {
|
|
1987
|
+
if (handleTransformPointerDown(e)) return;
|
|
1625
1988
|
if (activeTab !== "paint" || e.button !== 0) return;
|
|
1626
1989
|
e.preventDefault();
|
|
1627
1990
|
try {
|
|
@@ -1632,6 +1995,7 @@ var ImageEditor = ({
|
|
|
1632
1995
|
setPaintError(paintGestureRef.current.down(first));
|
|
1633
1996
|
};
|
|
1634
1997
|
const handlePaintPointerMove = (e) => {
|
|
1998
|
+
if (handleTransformPointerMove(e)) return;
|
|
1635
1999
|
if (activeTab !== "paint") return;
|
|
1636
2000
|
const samples = paintSamples(e);
|
|
1637
2001
|
brushCursorRef.current = samples[samples.length - 1] ?? null;
|
|
@@ -1639,6 +2003,7 @@ var ImageEditor = ({
|
|
|
1639
2003
|
else void renderCanvas();
|
|
1640
2004
|
};
|
|
1641
2005
|
const handlePaintPointerUp = () => {
|
|
2006
|
+
if (handleTransformPointerUp()) return;
|
|
1642
2007
|
if (activeTab !== "paint") return;
|
|
1643
2008
|
const g = paintGestureRef.current;
|
|
1644
2009
|
if (g.active) {
|
|
@@ -1646,21 +2011,21 @@ var ImageEditor = ({
|
|
|
1646
2011
|
if (g.error) setPaintError(g.error);
|
|
1647
2012
|
}
|
|
1648
2013
|
};
|
|
1649
|
-
(0,
|
|
2014
|
+
(0, import_react11.useEffect)(() => {
|
|
1650
2015
|
if (activeTab !== "paint" || typeof window === "undefined") return;
|
|
1651
2016
|
const onKey = (e) => {
|
|
1652
|
-
if ((0,
|
|
2017
|
+
if ((0, import_image_editor12.handlePaintShortcut)(controller, e)) e.preventDefault();
|
|
1653
2018
|
};
|
|
1654
2019
|
window.addEventListener("keydown", onKey);
|
|
1655
2020
|
return () => window.removeEventListener("keydown", onKey);
|
|
1656
2021
|
}, [activeTab, controller]);
|
|
1657
2022
|
const handleMouseDown = (e) => {
|
|
1658
2023
|
const canvas = canvasRef.current;
|
|
1659
|
-
if (!canvas) return;
|
|
2024
|
+
if (!canvas || transformTool.active) return;
|
|
1660
2025
|
const canvasPt = getCanvasEventPoint(e);
|
|
1661
2026
|
if (activeTab === "select") {
|
|
1662
2027
|
const gesture = selectionGestureRef.current;
|
|
1663
|
-
const imgPt = (0,
|
|
2028
|
+
const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1664
2029
|
void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
|
|
1665
2030
|
return;
|
|
1666
2031
|
}
|
|
@@ -1671,8 +2036,8 @@ var ImageEditor = ({
|
|
|
1671
2036
|
width: state.imageDimensions.width,
|
|
1672
2037
|
height: state.imageDimensions.height
|
|
1673
2038
|
};
|
|
1674
|
-
const handle = (0,
|
|
1675
|
-
const startImgPt = (0,
|
|
2039
|
+
const handle = (0, import_image_editor12.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
2040
|
+
const startImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
1676
2041
|
if (handle) {
|
|
1677
2042
|
cropDragInfoRef.current = {
|
|
1678
2043
|
handle,
|
|
@@ -1691,12 +2056,12 @@ var ImageEditor = ({
|
|
|
1691
2056
|
return;
|
|
1692
2057
|
}
|
|
1693
2058
|
if (activeTab === "annotate") {
|
|
1694
|
-
const imgPt = (0,
|
|
2059
|
+
const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1695
2060
|
dragStartPointRef.current = imgPt;
|
|
1696
2061
|
if (state.activeTool === "select") {
|
|
1697
2062
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
1698
2063
|
const ann = state.annotations[i];
|
|
1699
|
-
if ((0,
|
|
2064
|
+
if ((0, import_image_editor12.hitTestAnnotation)(imgPt, ann)) {
|
|
1700
2065
|
editor.selectAnnotation(ann.id);
|
|
1701
2066
|
annotationDragInfoRef.current = {
|
|
1702
2067
|
annId: ann.id,
|
|
@@ -1728,11 +2093,11 @@ var ImageEditor = ({
|
|
|
1728
2093
|
};
|
|
1729
2094
|
const handleMouseMove = (e) => {
|
|
1730
2095
|
const canvas = canvasRef.current;
|
|
1731
|
-
if (!canvas) return;
|
|
2096
|
+
if (!canvas || transformTool.active) return;
|
|
1732
2097
|
const canvasPt = getCanvasEventPoint(e);
|
|
1733
2098
|
if (activeTab === "select") {
|
|
1734
2099
|
const gesture = selectionGestureRef.current;
|
|
1735
|
-
if (gesture.active && gesture.move((0,
|
|
2100
|
+
if (gesture.active && gesture.move((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
|
|
1736
2101
|
selectionDraftRef.current = gesture.draftPath;
|
|
1737
2102
|
renderCanvas();
|
|
1738
2103
|
}
|
|
@@ -1741,7 +2106,7 @@ var ImageEditor = ({
|
|
|
1741
2106
|
if (activeTab === "crop") {
|
|
1742
2107
|
const drag = cropDragInfoRef.current;
|
|
1743
2108
|
if (drag) {
|
|
1744
|
-
const currentImgPt = (0,
|
|
2109
|
+
const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
1745
2110
|
let newCrop;
|
|
1746
2111
|
if (drag.handle === "new") {
|
|
1747
2112
|
const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
|
|
@@ -1755,7 +2120,7 @@ var ImageEditor = ({
|
|
|
1755
2120
|
height: Math.round(Math.max(20, maxY - minY))
|
|
1756
2121
|
};
|
|
1757
2122
|
} else {
|
|
1758
|
-
newCrop = (0,
|
|
2123
|
+
newCrop = (0, import_image_editor12.calculateCropDrag)(
|
|
1759
2124
|
drag.startCrop,
|
|
1760
2125
|
drag.handle,
|
|
1761
2126
|
drag.startImgPt,
|
|
@@ -1775,15 +2140,15 @@ var ImageEditor = ({
|
|
|
1775
2140
|
width: state.imageDimensions.width,
|
|
1776
2141
|
height: state.imageDimensions.height
|
|
1777
2142
|
};
|
|
1778
|
-
const handle = (0,
|
|
1779
|
-
canvas.style.cursor = (0,
|
|
2143
|
+
const handle = (0, import_image_editor12.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
2144
|
+
canvas.style.cursor = (0, import_image_editor12.getCropCursor)(handle, state.transform);
|
|
1780
2145
|
}
|
|
1781
2146
|
return;
|
|
1782
2147
|
}
|
|
1783
2148
|
if (activeTab === "annotate") {
|
|
1784
2149
|
if (annotationDragInfoRef.current) {
|
|
1785
2150
|
const drag = annotationDragInfoRef.current;
|
|
1786
|
-
const currentImgPt2 = (0,
|
|
2151
|
+
const currentImgPt2 = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1787
2152
|
const dx = currentImgPt2.x - drag.startImgPt.x;
|
|
1788
2153
|
const dy = currentImgPt2.y - drag.startImgPt.y;
|
|
1789
2154
|
editor.updateAnnotation(drag.annId, {
|
|
@@ -1795,10 +2160,10 @@ var ImageEditor = ({
|
|
|
1795
2160
|
const startPt = dragStartPointRef.current;
|
|
1796
2161
|
if (!startPt) {
|
|
1797
2162
|
if (state.activeTool === "select") {
|
|
1798
|
-
const imgPt = (0,
|
|
2163
|
+
const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1799
2164
|
let hovered = false;
|
|
1800
2165
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
1801
|
-
if ((0,
|
|
2166
|
+
if ((0, import_image_editor12.hitTestAnnotation)(imgPt, state.annotations[i])) {
|
|
1802
2167
|
hovered = true;
|
|
1803
2168
|
break;
|
|
1804
2169
|
}
|
|
@@ -1809,7 +2174,7 @@ var ImageEditor = ({
|
|
|
1809
2174
|
}
|
|
1810
2175
|
return;
|
|
1811
2176
|
}
|
|
1812
|
-
const currentImgPt = (0,
|
|
2177
|
+
const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1813
2178
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
1814
2179
|
currentPathRef.current.push(currentImgPt);
|
|
1815
2180
|
const draft = {
|
|
@@ -1884,12 +2249,12 @@ var ImageEditor = ({
|
|
|
1884
2249
|
};
|
|
1885
2250
|
const handleMouseUp = (e) => {
|
|
1886
2251
|
const canvas = canvasRef.current;
|
|
1887
|
-
if (!canvas) return;
|
|
2252
|
+
if (!canvas || transformTool.active) return;
|
|
1888
2253
|
const canvasPt = getCanvasEventPoint(e);
|
|
1889
2254
|
if (activeTab === "select") {
|
|
1890
2255
|
const gesture = selectionGestureRef.current;
|
|
1891
2256
|
if (gesture.active) {
|
|
1892
|
-
gesture.end((0,
|
|
2257
|
+
gesture.end((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
|
|
1893
2258
|
selectionDraftRef.current = null;
|
|
1894
2259
|
renderCanvas();
|
|
1895
2260
|
}
|
|
@@ -1913,7 +2278,7 @@ var ImageEditor = ({
|
|
|
1913
2278
|
}
|
|
1914
2279
|
const startPt = dragStartPointRef.current;
|
|
1915
2280
|
if (startPt) {
|
|
1916
|
-
const currentImgPt = (0,
|
|
2281
|
+
const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
1917
2282
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
1918
2283
|
if (currentPathRef.current.length > 1) {
|
|
1919
2284
|
editor.addAnnotation({
|
|
@@ -2009,15 +2374,15 @@ var ImageEditor = ({
|
|
|
2009
2374
|
link.click();
|
|
2010
2375
|
}
|
|
2011
2376
|
};
|
|
2012
|
-
return /* @__PURE__ */ (0,
|
|
2377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2013
2378
|
"div",
|
|
2014
2379
|
{
|
|
2015
2380
|
className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
|
|
2016
2381
|
style,
|
|
2017
2382
|
children: [
|
|
2018
|
-
/* @__PURE__ */ (0,
|
|
2019
|
-
/* @__PURE__ */ (0,
|
|
2020
|
-
/* @__PURE__ */ (0,
|
|
2383
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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: [
|
|
2384
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
|
|
2385
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2021
2386
|
"button",
|
|
2022
2387
|
{
|
|
2023
2388
|
type: "button",
|
|
@@ -2029,7 +2394,7 @@ var ImageEditor = ({
|
|
|
2029
2394
|
children: "Transform & Crop"
|
|
2030
2395
|
}
|
|
2031
2396
|
),
|
|
2032
|
-
/* @__PURE__ */ (0,
|
|
2397
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2033
2398
|
"button",
|
|
2034
2399
|
{
|
|
2035
2400
|
type: "button",
|
|
@@ -2041,7 +2406,7 @@ var ImageEditor = ({
|
|
|
2041
2406
|
children: "Adjustments"
|
|
2042
2407
|
}
|
|
2043
2408
|
),
|
|
2044
|
-
/* @__PURE__ */ (0,
|
|
2409
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2045
2410
|
"button",
|
|
2046
2411
|
{
|
|
2047
2412
|
type: "button",
|
|
@@ -2053,7 +2418,7 @@ var ImageEditor = ({
|
|
|
2053
2418
|
children: "Layers"
|
|
2054
2419
|
}
|
|
2055
2420
|
),
|
|
2056
|
-
/* @__PURE__ */ (0,
|
|
2421
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2057
2422
|
"button",
|
|
2058
2423
|
{
|
|
2059
2424
|
type: "button",
|
|
@@ -2065,7 +2430,7 @@ var ImageEditor = ({
|
|
|
2065
2430
|
children: "Paint"
|
|
2066
2431
|
}
|
|
2067
2432
|
),
|
|
2068
|
-
/* @__PURE__ */ (0,
|
|
2433
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2069
2434
|
"button",
|
|
2070
2435
|
{
|
|
2071
2436
|
type: "button",
|
|
@@ -2077,7 +2442,7 @@ var ImageEditor = ({
|
|
|
2077
2442
|
children: "Select & Mask"
|
|
2078
2443
|
}
|
|
2079
2444
|
),
|
|
2080
|
-
/* @__PURE__ */ (0,
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2081
2446
|
"button",
|
|
2082
2447
|
{
|
|
2083
2448
|
type: "button",
|
|
@@ -2089,7 +2454,7 @@ var ImageEditor = ({
|
|
|
2089
2454
|
children: "Annotations"
|
|
2090
2455
|
}
|
|
2091
2456
|
),
|
|
2092
|
-
/* @__PURE__ */ (0,
|
|
2457
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2093
2458
|
"button",
|
|
2094
2459
|
{
|
|
2095
2460
|
type: "button",
|
|
@@ -2101,7 +2466,7 @@ var ImageEditor = ({
|
|
|
2101
2466
|
children: "Depth Mask"
|
|
2102
2467
|
}
|
|
2103
2468
|
),
|
|
2104
|
-
/* @__PURE__ */ (0,
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2105
2470
|
"button",
|
|
2106
2471
|
{
|
|
2107
2472
|
type: "button",
|
|
@@ -2111,14 +2476,14 @@ var ImageEditor = ({
|
|
|
2111
2476
|
},
|
|
2112
2477
|
className: `px-3 py-1.5 rounded-md font-medium transition-colors flex items-center gap-1.5 ${activeTab === "ai" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
|
|
2113
2478
|
children: [
|
|
2114
|
-
/* @__PURE__ */ (0,
|
|
2479
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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_runtime11.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
2115
2480
|
"AI Tools"
|
|
2116
2481
|
]
|
|
2117
2482
|
}
|
|
2118
2483
|
)
|
|
2119
2484
|
] }),
|
|
2120
|
-
/* @__PURE__ */ (0,
|
|
2121
|
-
/* @__PURE__ */ (0,
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2122
2487
|
"button",
|
|
2123
2488
|
{
|
|
2124
2489
|
type: "button",
|
|
@@ -2129,7 +2494,7 @@ var ImageEditor = ({
|
|
|
2129
2494
|
children: "\u21A9"
|
|
2130
2495
|
}
|
|
2131
2496
|
),
|
|
2132
|
-
/* @__PURE__ */ (0,
|
|
2497
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2133
2498
|
"button",
|
|
2134
2499
|
{
|
|
2135
2500
|
type: "button",
|
|
@@ -2140,7 +2505,7 @@ var ImageEditor = ({
|
|
|
2140
2505
|
children: "\u21AA"
|
|
2141
2506
|
}
|
|
2142
2507
|
),
|
|
2143
|
-
/* @__PURE__ */ (0,
|
|
2508
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2144
2509
|
"button",
|
|
2145
2510
|
{
|
|
2146
2511
|
type: "button",
|
|
@@ -2149,8 +2514,8 @@ var ImageEditor = ({
|
|
|
2149
2514
|
children: "Reset"
|
|
2150
2515
|
}
|
|
2151
2516
|
),
|
|
2152
|
-
/* @__PURE__ */ (0,
|
|
2153
|
-
/* @__PURE__ */ (0,
|
|
2517
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
2518
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2154
2519
|
"button",
|
|
2155
2520
|
{
|
|
2156
2521
|
type: "button",
|
|
@@ -2160,11 +2525,11 @@ var ImageEditor = ({
|
|
|
2160
2525
|
children: "-"
|
|
2161
2526
|
}
|
|
2162
2527
|
),
|
|
2163
|
-
/* @__PURE__ */ (0,
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
|
|
2164
2529
|
Math.round(state.zoom * 100),
|
|
2165
2530
|
"%"
|
|
2166
2531
|
] }),
|
|
2167
|
-
/* @__PURE__ */ (0,
|
|
2532
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2168
2533
|
"button",
|
|
2169
2534
|
{
|
|
2170
2535
|
type: "button",
|
|
@@ -2174,8 +2539,8 @@ var ImageEditor = ({
|
|
|
2174
2539
|
children: "+"
|
|
2175
2540
|
}
|
|
2176
2541
|
),
|
|
2177
|
-
/* @__PURE__ */ (0,
|
|
2178
|
-
/* @__PURE__ */ (0,
|
|
2542
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
2543
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2179
2544
|
"button",
|
|
2180
2545
|
{
|
|
2181
2546
|
type: "button",
|
|
@@ -2186,7 +2551,7 @@ var ImageEditor = ({
|
|
|
2186
2551
|
children: "Hold Compare"
|
|
2187
2552
|
}
|
|
2188
2553
|
),
|
|
2189
|
-
/* @__PURE__ */ (0,
|
|
2554
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2190
2555
|
"button",
|
|
2191
2556
|
{
|
|
2192
2557
|
type: "button",
|
|
@@ -2197,13 +2562,15 @@ var ImageEditor = ({
|
|
|
2197
2562
|
)
|
|
2198
2563
|
] })
|
|
2199
2564
|
] }),
|
|
2200
|
-
/* @__PURE__ */ (0,
|
|
2201
|
-
|
|
2565
|
+
transformTool.active && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
|
|
2566
|
+
!transformTool.active && transformTool.error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "alert", className: "border-b border-rose-900 bg-rose-950/80 px-4 py-1.5 text-xs text-rose-200", children: transformTool.error }),
|
|
2567
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2202
2569
|
"div",
|
|
2203
2570
|
{
|
|
2204
2571
|
ref: containerRef,
|
|
2205
2572
|
className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
|
|
2206
|
-
children: /* @__PURE__ */ (0,
|
|
2573
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2207
2574
|
"canvas",
|
|
2208
2575
|
{
|
|
2209
2576
|
ref: canvasRef,
|
|
@@ -2216,16 +2583,17 @@ var ImageEditor = ({
|
|
|
2216
2583
|
onPointerUp: handlePaintPointerUp,
|
|
2217
2584
|
onPointerCancel: () => paintGestureRef.current?.cancel(),
|
|
2218
2585
|
"data-testid": "image-editor-canvas",
|
|
2219
|
-
|
|
2586
|
+
style: transformTool.active ? { cursor: transformCursor } : void 0,
|
|
2587
|
+
className: `absolute inset-0 w-full h-full block ${transformTool.active ? "touch-none" : activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
|
|
2220
2588
|
}
|
|
2221
2589
|
)
|
|
2222
2590
|
}
|
|
2223
2591
|
),
|
|
2224
|
-
/* @__PURE__ */ (0,
|
|
2225
|
-
activeTab === "crop" && /* @__PURE__ */ (0,
|
|
2226
|
-
/* @__PURE__ */ (0,
|
|
2227
|
-
/* @__PURE__ */ (0,
|
|
2228
|
-
/* @__PURE__ */ (0,
|
|
2592
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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: [
|
|
2593
|
+
activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
|
|
2595
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
2596
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2229
2597
|
"button",
|
|
2230
2598
|
{
|
|
2231
2599
|
type: "button",
|
|
@@ -2237,7 +2605,7 @@ var ImageEditor = ({
|
|
|
2237
2605
|
children: "Freeform"
|
|
2238
2606
|
}
|
|
2239
2607
|
),
|
|
2240
|
-
/* @__PURE__ */ (0,
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2241
2609
|
"button",
|
|
2242
2610
|
{
|
|
2243
2611
|
type: "button",
|
|
@@ -2249,7 +2617,7 @@ var ImageEditor = ({
|
|
|
2249
2617
|
children: "1:1 Square"
|
|
2250
2618
|
}
|
|
2251
2619
|
),
|
|
2252
|
-
/* @__PURE__ */ (0,
|
|
2620
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2253
2621
|
"button",
|
|
2254
2622
|
{
|
|
2255
2623
|
type: "button",
|
|
@@ -2261,7 +2629,7 @@ var ImageEditor = ({
|
|
|
2261
2629
|
children: "4:3 Standard"
|
|
2262
2630
|
}
|
|
2263
2631
|
),
|
|
2264
|
-
/* @__PURE__ */ (0,
|
|
2632
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2265
2633
|
"button",
|
|
2266
2634
|
{
|
|
2267
2635
|
type: "button",
|
|
@@ -2273,7 +2641,7 @@ var ImageEditor = ({
|
|
|
2273
2641
|
children: "16:9 Wide"
|
|
2274
2642
|
}
|
|
2275
2643
|
),
|
|
2276
|
-
/* @__PURE__ */ (0,
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2277
2645
|
"button",
|
|
2278
2646
|
{
|
|
2279
2647
|
type: "button",
|
|
@@ -2285,7 +2653,7 @@ var ImageEditor = ({
|
|
|
2285
2653
|
children: "3:2 Photo"
|
|
2286
2654
|
}
|
|
2287
2655
|
),
|
|
2288
|
-
/* @__PURE__ */ (0,
|
|
2656
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2289
2657
|
"button",
|
|
2290
2658
|
{
|
|
2291
2659
|
type: "button",
|
|
@@ -2298,10 +2666,10 @@ var ImageEditor = ({
|
|
|
2298
2666
|
}
|
|
2299
2667
|
)
|
|
2300
2668
|
] }),
|
|
2301
|
-
/* @__PURE__ */ (0,
|
|
2302
|
-
/* @__PURE__ */ (0,
|
|
2303
|
-
/* @__PURE__ */ (0,
|
|
2304
|
-
/* @__PURE__ */ (0,
|
|
2669
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
2670
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2305
2673
|
"button",
|
|
2306
2674
|
{
|
|
2307
2675
|
type: "button",
|
|
@@ -2310,7 +2678,7 @@ var ImageEditor = ({
|
|
|
2310
2678
|
children: "Rotate -90\xB0"
|
|
2311
2679
|
}
|
|
2312
2680
|
),
|
|
2313
|
-
/* @__PURE__ */ (0,
|
|
2681
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2314
2682
|
"button",
|
|
2315
2683
|
{
|
|
2316
2684
|
type: "button",
|
|
@@ -2319,7 +2687,7 @@ var ImageEditor = ({
|
|
|
2319
2687
|
children: "Rotate +90\xB0"
|
|
2320
2688
|
}
|
|
2321
2689
|
),
|
|
2322
|
-
/* @__PURE__ */ (0,
|
|
2690
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2323
2691
|
"button",
|
|
2324
2692
|
{
|
|
2325
2693
|
type: "button",
|
|
@@ -2328,7 +2696,7 @@ var ImageEditor = ({
|
|
|
2328
2696
|
children: "Flip Horizontal"
|
|
2329
2697
|
}
|
|
2330
2698
|
),
|
|
2331
|
-
/* @__PURE__ */ (0,
|
|
2699
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2332
2700
|
"button",
|
|
2333
2701
|
{
|
|
2334
2702
|
type: "button",
|
|
@@ -2339,10 +2707,10 @@ var ImageEditor = ({
|
|
|
2339
2707
|
)
|
|
2340
2708
|
] })
|
|
2341
2709
|
] }),
|
|
2342
|
-
activeTab === "adjust" && /* @__PURE__ */ (0,
|
|
2343
|
-
/* @__PURE__ */ (0,
|
|
2344
|
-
/* @__PURE__ */ (0,
|
|
2345
|
-
/* @__PURE__ */ (0,
|
|
2710
|
+
activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2711
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2712
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
|
|
2713
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2346
2714
|
"button",
|
|
2347
2715
|
{
|
|
2348
2716
|
type: "button",
|
|
@@ -2352,25 +2720,25 @@ var ImageEditor = ({
|
|
|
2352
2720
|
}
|
|
2353
2721
|
)
|
|
2354
2722
|
] }),
|
|
2355
|
-
/* @__PURE__ */ (0,
|
|
2356
|
-
|
|
2357
|
-
/* @__PURE__ */ (0,
|
|
2723
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Histogram, { histogram: editor.histogram }),
|
|
2724
|
+
import_image_editor12.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react11.default.Fragment, { children: [
|
|
2725
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2358
2726
|
ControlSlider,
|
|
2359
2727
|
{
|
|
2360
2728
|
spec,
|
|
2361
|
-
value: (0,
|
|
2729
|
+
value: (0, import_image_editor12.readAdjustmentControls)(state.adjustments)[spec.id],
|
|
2362
2730
|
disabled: spec.requiresProcess !== void 0 && legacyProcess,
|
|
2363
2731
|
onChange: (v) => editor.setAdjustments({ [spec.id]: v })
|
|
2364
2732
|
}
|
|
2365
2733
|
),
|
|
2366
|
-
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0,
|
|
2734
|
+
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2367
2735
|
"div",
|
|
2368
2736
|
{
|
|
2369
2737
|
className: "flex items-center justify-between gap-2 rounded border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-200",
|
|
2370
2738
|
"data-testid": "image-editor-process-notice",
|
|
2371
2739
|
children: [
|
|
2372
|
-
/* @__PURE__ */ (0,
|
|
2373
|
-
/* @__PURE__ */ (0,
|
|
2740
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2374
2742
|
"button",
|
|
2375
2743
|
{
|
|
2376
2744
|
type: "button",
|
|
@@ -2383,7 +2751,7 @@ var ImageEditor = ({
|
|
|
2383
2751
|
}
|
|
2384
2752
|
)
|
|
2385
2753
|
] }, spec.id)),
|
|
2386
|
-
/* @__PURE__ */ (0,
|
|
2754
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2387
2755
|
AdjustmentLayersPanel,
|
|
2388
2756
|
{
|
|
2389
2757
|
controller,
|
|
@@ -2392,19 +2760,41 @@ var ImageEditor = ({
|
|
|
2392
2760
|
}
|
|
2393
2761
|
) })
|
|
2394
2762
|
] }),
|
|
2395
|
-
activeTab === "layers" && /* @__PURE__ */ (0,
|
|
2396
|
-
/* @__PURE__ */ (0,
|
|
2397
|
-
/* @__PURE__ */ (0,
|
|
2763
|
+
activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2764
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
|
|
2765
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2766
|
+
"button",
|
|
2767
|
+
{
|
|
2768
|
+
type: "button",
|
|
2769
|
+
title: "Edit \u203A Free Transform (Ctrl/Cmd+T): the selected pixels, or the whole active layer",
|
|
2770
|
+
className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40",
|
|
2771
|
+
disabled: transformTool.active,
|
|
2772
|
+
onClick: () => transformTool.begin(),
|
|
2773
|
+
children: "Free Transform"
|
|
2774
|
+
}
|
|
2775
|
+
),
|
|
2776
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LayersPanel, { controller })
|
|
2398
2777
|
] }),
|
|
2399
|
-
activeTab === "paint" && /* @__PURE__ */ (0,
|
|
2400
|
-
/* @__PURE__ */ (0,
|
|
2401
|
-
/* @__PURE__ */ (0,
|
|
2402
|
-
|
|
2403
|
-
|
|
2778
|
+
activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2779
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
|
|
2780
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(BrushOptionsBar, { controller }),
|
|
2781
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2782
|
+
"button",
|
|
2783
|
+
{
|
|
2784
|
+
type: "button",
|
|
2785
|
+
title: "Edit \u203A Free Transform (Ctrl/Cmd+T): the selected pixels, or the whole active layer",
|
|
2786
|
+
className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start",
|
|
2787
|
+
disabled: transformTool.active,
|
|
2788
|
+
onClick: () => transformTool.begin(),
|
|
2789
|
+
children: "Free Transform"
|
|
2790
|
+
}
|
|
2791
|
+
),
|
|
2792
|
+
paintError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
|
|
2793
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LayersPanel, { controller }) })
|
|
2404
2794
|
] }),
|
|
2405
|
-
activeTab === "annotate" && /* @__PURE__ */ (0,
|
|
2406
|
-
/* @__PURE__ */ (0,
|
|
2407
|
-
/* @__PURE__ */ (0,
|
|
2795
|
+
activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2796
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
|
|
2797
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2408
2798
|
"button",
|
|
2409
2799
|
{
|
|
2410
2800
|
type: "button",
|
|
@@ -2414,9 +2804,9 @@ var ImageEditor = ({
|
|
|
2414
2804
|
},
|
|
2415
2805
|
t
|
|
2416
2806
|
)) }),
|
|
2417
|
-
/* @__PURE__ */ (0,
|
|
2418
|
-
/* @__PURE__ */ (0,
|
|
2419
|
-
/* @__PURE__ */ (0,
|
|
2807
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
|
|
2808
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { className: "text-slate-400", children: "Color:" }),
|
|
2809
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2420
2810
|
"input",
|
|
2421
2811
|
{
|
|
2422
2812
|
type: "color",
|
|
@@ -2425,15 +2815,15 @@ var ImageEditor = ({
|
|
|
2425
2815
|
className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
|
|
2426
2816
|
}
|
|
2427
2817
|
),
|
|
2428
|
-
/* @__PURE__ */ (0,
|
|
2429
|
-
/* @__PURE__ */ (0,
|
|
2430
|
-
/* @__PURE__ */ (0,
|
|
2431
|
-
/* @__PURE__ */ (0,
|
|
2818
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 ml-2", children: [
|
|
2819
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
|
|
2820
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Width:" }),
|
|
2821
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-mono", children: [
|
|
2432
2822
|
strokeWidth,
|
|
2433
2823
|
"px"
|
|
2434
2824
|
] })
|
|
2435
2825
|
] }),
|
|
2436
|
-
/* @__PURE__ */ (0,
|
|
2826
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2437
2827
|
"input",
|
|
2438
2828
|
{
|
|
2439
2829
|
type: "range",
|
|
@@ -2446,10 +2836,10 @@ var ImageEditor = ({
|
|
|
2446
2836
|
)
|
|
2447
2837
|
] })
|
|
2448
2838
|
] }),
|
|
2449
|
-
/* @__PURE__ */ (0,
|
|
2450
|
-
/* @__PURE__ */ (0,
|
|
2451
|
-
/* @__PURE__ */ (0,
|
|
2452
|
-
/* @__PURE__ */ (0,
|
|
2839
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
2840
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
|
|
2841
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex gap-2", children: [
|
|
2842
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2453
2843
|
"input",
|
|
2454
2844
|
{
|
|
2455
2845
|
type: "text",
|
|
@@ -2460,7 +2850,7 @@ var ImageEditor = ({
|
|
|
2460
2850
|
className: "flex-1 bg-slate-950 border border-slate-700 rounded-lg px-2.5 py-1.5 text-xs text-slate-100 placeholder-slate-500 focus:outline-none focus:border-indigo-500"
|
|
2461
2851
|
}
|
|
2462
2852
|
),
|
|
2463
|
-
/* @__PURE__ */ (0,
|
|
2853
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2464
2854
|
"button",
|
|
2465
2855
|
{
|
|
2466
2856
|
type: "button",
|
|
@@ -2470,14 +2860,14 @@ var ImageEditor = ({
|
|
|
2470
2860
|
}
|
|
2471
2861
|
)
|
|
2472
2862
|
] }),
|
|
2473
|
-
/* @__PURE__ */ (0,
|
|
2474
|
-
/* @__PURE__ */ (0,
|
|
2475
|
-
/* @__PURE__ */ (0,
|
|
2863
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
|
|
2864
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Font Size:" }),
|
|
2865
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-mono", children: [
|
|
2476
2866
|
fontSize,
|
|
2477
2867
|
"px"
|
|
2478
2868
|
] })
|
|
2479
2869
|
] }),
|
|
2480
|
-
/* @__PURE__ */ (0,
|
|
2870
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2481
2871
|
"input",
|
|
2482
2872
|
{
|
|
2483
2873
|
type: "range",
|
|
@@ -2488,14 +2878,14 @@ var ImageEditor = ({
|
|
|
2488
2878
|
className: "w-full accent-indigo-500"
|
|
2489
2879
|
}
|
|
2490
2880
|
),
|
|
2491
|
-
/* @__PURE__ */ (0,
|
|
2492
|
-
/* @__PURE__ */ (0,
|
|
2493
|
-
/* @__PURE__ */ (0,
|
|
2881
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
2882
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2883
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-slate-400", children: [
|
|
2494
2884
|
"Layers (",
|
|
2495
2885
|
state.annotations.length,
|
|
2496
2886
|
")"
|
|
2497
2887
|
] }),
|
|
2498
|
-
state.selectedAnnotationId && /* @__PURE__ */ (0,
|
|
2888
|
+
state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2499
2889
|
"button",
|
|
2500
2890
|
{
|
|
2501
2891
|
type: "button",
|
|
@@ -2504,7 +2894,7 @@ var ImageEditor = ({
|
|
|
2504
2894
|
children: "Delete Selected"
|
|
2505
2895
|
}
|
|
2506
2896
|
),
|
|
2507
|
-
state.annotations.length > 0 && /* @__PURE__ */ (0,
|
|
2897
|
+
state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2508
2898
|
"button",
|
|
2509
2899
|
{
|
|
2510
2900
|
type: "button",
|
|
@@ -2515,10 +2905,10 @@ var ImageEditor = ({
|
|
|
2515
2905
|
)
|
|
2516
2906
|
] })
|
|
2517
2907
|
] }),
|
|
2518
|
-
activeTab === "depth" && /* @__PURE__ */ (0,
|
|
2519
|
-
/* @__PURE__ */ (0,
|
|
2520
|
-
/* @__PURE__ */ (0,
|
|
2521
|
-
/* @__PURE__ */ (0,
|
|
2908
|
+
activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
2909
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2910
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
|
|
2911
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2522
2912
|
"button",
|
|
2523
2913
|
{
|
|
2524
2914
|
type: "button",
|
|
@@ -2528,8 +2918,8 @@ var ImageEditor = ({
|
|
|
2528
2918
|
}
|
|
2529
2919
|
)
|
|
2530
2920
|
] }),
|
|
2531
|
-
/* @__PURE__ */ (0,
|
|
2532
|
-
/* @__PURE__ */ (0,
|
|
2921
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
|
|
2922
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2533
2923
|
"input",
|
|
2534
2924
|
{
|
|
2535
2925
|
type: "checkbox",
|
|
@@ -2538,12 +2928,12 @@ var ImageEditor = ({
|
|
|
2538
2928
|
className: "rounded accent-indigo-500"
|
|
2539
2929
|
}
|
|
2540
2930
|
),
|
|
2541
|
-
/* @__PURE__ */ (0,
|
|
2931
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Enable Depth / Alpha Mask" })
|
|
2542
2932
|
] }),
|
|
2543
|
-
state.depthMask.enabled && /* @__PURE__ */ (0,
|
|
2544
|
-
/* @__PURE__ */ (0,
|
|
2545
|
-
/* @__PURE__ */ (0,
|
|
2546
|
-
/* @__PURE__ */ (0,
|
|
2933
|
+
state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2934
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
|
|
2935
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
|
|
2936
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2547
2937
|
"input",
|
|
2548
2938
|
{
|
|
2549
2939
|
type: "text",
|
|
@@ -2554,8 +2944,8 @@ var ImageEditor = ({
|
|
|
2554
2944
|
}
|
|
2555
2945
|
)
|
|
2556
2946
|
] }),
|
|
2557
|
-
/* @__PURE__ */ (0,
|
|
2558
|
-
/* @__PURE__ */ (0,
|
|
2947
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex gap-2", children: [
|
|
2948
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2559
2949
|
"button",
|
|
2560
2950
|
{
|
|
2561
2951
|
type: "button",
|
|
@@ -2564,7 +2954,7 @@ var ImageEditor = ({
|
|
|
2564
2954
|
children: "Threshold Mode"
|
|
2565
2955
|
}
|
|
2566
2956
|
),
|
|
2567
|
-
/* @__PURE__ */ (0,
|
|
2957
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2568
2958
|
"button",
|
|
2569
2959
|
{
|
|
2570
2960
|
type: "button",
|
|
@@ -2574,12 +2964,12 @@ var ImageEditor = ({
|
|
|
2574
2964
|
}
|
|
2575
2965
|
)
|
|
2576
2966
|
] }),
|
|
2577
|
-
/* @__PURE__ */ (0,
|
|
2578
|
-
/* @__PURE__ */ (0,
|
|
2579
|
-
/* @__PURE__ */ (0,
|
|
2580
|
-
/* @__PURE__ */ (0,
|
|
2967
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
|
|
2968
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
2969
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Depth Start (Lower):" }),
|
|
2970
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
|
|
2581
2971
|
] }),
|
|
2582
|
-
/* @__PURE__ */ (0,
|
|
2972
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2583
2973
|
"input",
|
|
2584
2974
|
{
|
|
2585
2975
|
type: "range",
|
|
@@ -2593,12 +2983,12 @@ var ImageEditor = ({
|
|
|
2593
2983
|
}
|
|
2594
2984
|
)
|
|
2595
2985
|
] }),
|
|
2596
|
-
/* @__PURE__ */ (0,
|
|
2597
|
-
/* @__PURE__ */ (0,
|
|
2598
|
-
/* @__PURE__ */ (0,
|
|
2599
|
-
/* @__PURE__ */ (0,
|
|
2986
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
|
|
2987
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
2988
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Depth Stop (Upper):" }),
|
|
2989
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
|
|
2600
2990
|
] }),
|
|
2601
|
-
/* @__PURE__ */ (0,
|
|
2991
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2602
2992
|
"input",
|
|
2603
2993
|
{
|
|
2604
2994
|
type: "range",
|
|
@@ -2612,12 +3002,12 @@ var ImageEditor = ({
|
|
|
2612
3002
|
}
|
|
2613
3003
|
)
|
|
2614
3004
|
] }),
|
|
2615
|
-
/* @__PURE__ */ (0,
|
|
2616
|
-
/* @__PURE__ */ (0,
|
|
2617
|
-
/* @__PURE__ */ (0,
|
|
2618
|
-
/* @__PURE__ */ (0,
|
|
3005
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
|
|
3006
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3007
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Softness:" }),
|
|
3008
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
|
|
2619
3009
|
] }),
|
|
2620
|
-
/* @__PURE__ */ (0,
|
|
3010
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2621
3011
|
"input",
|
|
2622
3012
|
{
|
|
2623
3013
|
type: "range",
|
|
@@ -2629,8 +3019,8 @@ var ImageEditor = ({
|
|
|
2629
3019
|
}
|
|
2630
3020
|
)
|
|
2631
3021
|
] }),
|
|
2632
|
-
/* @__PURE__ */ (0,
|
|
2633
|
-
/* @__PURE__ */ (0,
|
|
3022
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
|
|
3023
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2634
3024
|
"input",
|
|
2635
3025
|
{
|
|
2636
3026
|
type: "checkbox",
|
|
@@ -2639,12 +3029,12 @@ var ImageEditor = ({
|
|
|
2639
3029
|
className: "rounded accent-indigo-500"
|
|
2640
3030
|
}
|
|
2641
3031
|
),
|
|
2642
|
-
/* @__PURE__ */ (0,
|
|
3032
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Invert Mask" })
|
|
2643
3033
|
] })
|
|
2644
3034
|
] })
|
|
2645
3035
|
] }),
|
|
2646
|
-
activeTab === "select" && /* @__PURE__ */ (0,
|
|
2647
|
-
/* @__PURE__ */ (0,
|
|
3036
|
+
activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
3037
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2648
3038
|
SelectionOptionsBar,
|
|
2649
3039
|
{
|
|
2650
3040
|
controller,
|
|
@@ -2654,13 +3044,37 @@ var ImageEditor = ({
|
|
|
2654
3044
|
quickMask: Boolean(state.quickMask)
|
|
2655
3045
|
}
|
|
2656
3046
|
),
|
|
2657
|
-
selectionError && /* @__PURE__ */ (0,
|
|
2658
|
-
/* @__PURE__ */ (0,
|
|
3047
|
+
selectionError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
|
|
3048
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex gap-1", children: [
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3050
|
+
"button",
|
|
3051
|
+
{
|
|
3052
|
+
type: "button",
|
|
3053
|
+
title: "Select \u203A Transform Selection: the outline only",
|
|
3054
|
+
className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40",
|
|
3055
|
+
disabled: transformTool.active,
|
|
3056
|
+
onClick: () => transformTool.begin({ content: "selection-outline" }),
|
|
3057
|
+
children: "Transform Selection"
|
|
3058
|
+
}
|
|
3059
|
+
),
|
|
3060
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3061
|
+
"button",
|
|
3062
|
+
{
|
|
3063
|
+
type: "button",
|
|
3064
|
+
title: "Edit \u203A Free Transform: the selected pixels of the active layer",
|
|
3065
|
+
className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40",
|
|
3066
|
+
disabled: transformTool.active,
|
|
3067
|
+
onClick: () => transformTool.begin({ content: "selection" }),
|
|
3068
|
+
children: "Free Transform Pixels"
|
|
3069
|
+
}
|
|
3070
|
+
)
|
|
3071
|
+
] }),
|
|
3072
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
|
|
2659
3073
|
] }),
|
|
2660
|
-
activeTab === "ai" && /* @__PURE__ */ (0,
|
|
2661
|
-
/* @__PURE__ */ (0,
|
|
2662
|
-
/* @__PURE__ */ (0,
|
|
2663
|
-
/* @__PURE__ */ (0,
|
|
3074
|
+
activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
3075
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
|
|
3076
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Results go to" }),
|
|
3077
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2664
3078
|
"select",
|
|
2665
3079
|
{
|
|
2666
3080
|
"aria-label": "AI result target",
|
|
@@ -2668,54 +3082,54 @@ var ImageEditor = ({
|
|
|
2668
3082
|
onChange: (e) => setAiTarget(e.target.value),
|
|
2669
3083
|
className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
|
|
2670
3084
|
children: [
|
|
2671
|
-
/* @__PURE__ */ (0,
|
|
2672
|
-
/* @__PURE__ */ (0,
|
|
2673
|
-
/* @__PURE__ */ (0,
|
|
3085
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
|
|
3086
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
|
|
3087
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "replace", children: "Replace image" })
|
|
2674
3088
|
]
|
|
2675
3089
|
}
|
|
2676
3090
|
)
|
|
2677
3091
|
] }),
|
|
2678
|
-
/* @__PURE__ */ (0,
|
|
2679
|
-
/* @__PURE__ */ (0,
|
|
2680
|
-
/* @__PURE__ */ (0,
|
|
2681
|
-
/* @__PURE__ */ (0,
|
|
3092
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
3093
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
3094
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
3095
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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_runtime11.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
|
|
2682
3096
|
"Background Removal"
|
|
2683
3097
|
] }),
|
|
2684
|
-
isRemovingBg && /* @__PURE__ */ (0,
|
|
3098
|
+
isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
|
|
2685
3099
|
] }),
|
|
2686
|
-
/* @__PURE__ */ (0,
|
|
2687
|
-
/* @__PURE__ */ (0,
|
|
3100
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
|
|
3101
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2688
3102
|
"button",
|
|
2689
3103
|
{
|
|
2690
3104
|
type: "button",
|
|
2691
3105
|
onClick: handleRemoveBackground,
|
|
2692
3106
|
disabled: isRemovingBg || isInpainting,
|
|
2693
3107
|
className: "mt-1 px-3 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
|
|
2694
|
-
children: isRemovingBg ? /* @__PURE__ */ (0,
|
|
2695
|
-
/* @__PURE__ */ (0,
|
|
3108
|
+
children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3109
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
2696
3110
|
"Removing Background..."
|
|
2697
|
-
] }) : /* @__PURE__ */ (0,
|
|
2698
|
-
/* @__PURE__ */ (0,
|
|
3111
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3112
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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_runtime11.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
2699
3113
|
"Remove Background"
|
|
2700
3114
|
] })
|
|
2701
3115
|
}
|
|
2702
3116
|
)
|
|
2703
3117
|
] }),
|
|
2704
|
-
/* @__PURE__ */ (0,
|
|
2705
|
-
/* @__PURE__ */ (0,
|
|
2706
|
-
/* @__PURE__ */ (0,
|
|
2707
|
-
/* @__PURE__ */ (0,
|
|
2708
|
-
/* @__PURE__ */ (0,
|
|
2709
|
-
/* @__PURE__ */ (0,
|
|
3118
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
3119
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
3120
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
3121
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
3122
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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" }),
|
|
3123
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m14 7 3 3" })
|
|
2710
3124
|
] }),
|
|
2711
3125
|
"Generative Inpainting"
|
|
2712
3126
|
] }),
|
|
2713
|
-
isInpainting && /* @__PURE__ */ (0,
|
|
3127
|
+
isInpainting && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
|
|
2714
3128
|
] }),
|
|
2715
|
-
/* @__PURE__ */ (0,
|
|
2716
|
-
/* @__PURE__ */ (0,
|
|
2717
|
-
/* @__PURE__ */ (0,
|
|
2718
|
-
/* @__PURE__ */ (0,
|
|
3129
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
|
|
3130
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
3131
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
|
|
3132
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2719
3133
|
"textarea",
|
|
2720
3134
|
{
|
|
2721
3135
|
id: "ai-inpaint-prompt-react",
|
|
@@ -2727,10 +3141,10 @@ var ImageEditor = ({
|
|
|
2727
3141
|
}
|
|
2728
3142
|
)
|
|
2729
3143
|
] }),
|
|
2730
|
-
/* @__PURE__ */ (0,
|
|
2731
|
-
/* @__PURE__ */ (0,
|
|
2732
|
-
/* @__PURE__ */ (0,
|
|
2733
|
-
/* @__PURE__ */ (0,
|
|
3144
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
3145
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
|
|
3146
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
|
|
3147
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2734
3148
|
"button",
|
|
2735
3149
|
{
|
|
2736
3150
|
type: "button",
|
|
@@ -2743,7 +3157,7 @@ var ImageEditor = ({
|
|
|
2743
3157
|
]
|
|
2744
3158
|
}
|
|
2745
3159
|
),
|
|
2746
|
-
/* @__PURE__ */ (0,
|
|
3160
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2747
3161
|
"button",
|
|
2748
3162
|
{
|
|
2749
3163
|
type: "button",
|
|
@@ -2758,25 +3172,25 @@ var ImageEditor = ({
|
|
|
2758
3172
|
)
|
|
2759
3173
|
] })
|
|
2760
3174
|
] }),
|
|
2761
|
-
/* @__PURE__ */ (0,
|
|
3175
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2762
3176
|
"button",
|
|
2763
3177
|
{
|
|
2764
3178
|
type: "button",
|
|
2765
3179
|
onClick: handleInpaint,
|
|
2766
3180
|
disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
|
|
2767
3181
|
className: "mt-1 px-3 py-2 rounded-lg bg-purple-600 hover:bg-purple-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
|
|
2768
|
-
children: isInpainting ? /* @__PURE__ */ (0,
|
|
2769
|
-
/* @__PURE__ */ (0,
|
|
3182
|
+
children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3183
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
2770
3184
|
"Generating Inpaint..."
|
|
2771
|
-
] }) : /* @__PURE__ */ (0,
|
|
2772
|
-
/* @__PURE__ */ (0,
|
|
3185
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3186
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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_runtime11.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
2773
3187
|
"Apply Inpainting"
|
|
2774
3188
|
] })
|
|
2775
3189
|
}
|
|
2776
3190
|
)
|
|
2777
3191
|
] }),
|
|
2778
|
-
aiError && /* @__PURE__ */ (0,
|
|
2779
|
-
aiSuccess && /* @__PURE__ */ (0,
|
|
3192
|
+
aiError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
|
|
3193
|
+
aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
|
|
2780
3194
|
] })
|
|
2781
3195
|
] })
|
|
2782
3196
|
] })
|
|
@@ -2790,8 +3204,10 @@ var ImageEditor = ({
|
|
|
2790
3204
|
BrushOptionsBar,
|
|
2791
3205
|
ControlSlider,
|
|
2792
3206
|
CurvesEditor,
|
|
3207
|
+
FreeTransformOptionsBar,
|
|
2793
3208
|
Histogram,
|
|
2794
3209
|
ImageEditor,
|
|
3210
|
+
LayerEffectsPanel,
|
|
2795
3211
|
LayersPanel,
|
|
2796
3212
|
RefineEdgePanel,
|
|
2797
3213
|
SelectionOptionsBar,
|