@pixerate/editor-react 0.14.0 → 0.16.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/README.md +6 -1
- package/dist/canvas/index.cjs +352 -118
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +112 -8
- package/dist/canvas/index.d.ts +112 -8
- package/dist/canvas/index.js +258 -19
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-4ZC2WCUO.js +196 -0
- package/dist/chunk-4ZC2WCUO.js.map +1 -0
- package/dist/chunk-7SPRQZ6H.js +216 -0
- package/dist/chunk-7SPRQZ6H.js.map +1 -0
- package/dist/{chunk-25S5EHH4.js → chunk-FYIPXHAE.js} +22 -13
- package/dist/chunk-FYIPXHAE.js.map +1 -0
- package/dist/{chunk-TL27COKM.js → chunk-XTFR3IMK.js} +683 -286
- package/dist/chunk-XTFR3IMK.js.map +1 -0
- package/dist/chunk-XWFU2CSG.js +167 -0
- package/dist/chunk-XWFU2CSG.js.map +1 -0
- package/dist/commands/index.cjs +232 -0
- package/dist/commands/index.cjs.map +1 -0
- package/dist/commands/index.d.cts +69 -0
- package/dist/commands/index.d.ts +69 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/generation/index.cjs +235 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +60 -0
- package/dist/generation/index.d.ts +60 -0
- package/dist/generation/index.js +13 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/image-editor/index.cjs +688 -299
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +65 -5
- package/dist/image-editor/index.d.ts +65 -5
- package/dist/image-editor/index.js +13 -3
- package/dist/index.cjs +2200 -683
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +201 -23
- package/dist/index.d.ts +201 -23
- package/dist/index.js +743 -129
- package/dist/index.js.map +1 -1
- package/dist/persistence/index.cjs +191 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +77 -0
- package/dist/persistence/index.d.ts +77 -0
- package/dist/persistence/index.js +9 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/spreadsheet/index.cjs +17 -10
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +9 -7
- package/dist/spreadsheet/index.d.ts +9 -7
- package/dist/spreadsheet/index.js +1 -1
- package/package.json +26 -2
- package/dist/chunk-25S5EHH4.js.map +0 -1
- package/dist/chunk-TL27COKM.js.map +0 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,13 +17,26 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/image-editor/index.ts
|
|
21
31
|
var image_editor_exports = {};
|
|
22
32
|
__export(image_editor_exports, {
|
|
33
|
+
AdjustmentLayersPanel: () => AdjustmentLayersPanel,
|
|
34
|
+
ControlSlider: () => ControlSlider,
|
|
35
|
+
CurvesEditor: () => CurvesEditor,
|
|
36
|
+
Histogram: () => Histogram,
|
|
23
37
|
ImageEditor: () => ImageEditor,
|
|
24
|
-
useImageEditor: () => useImageEditor
|
|
38
|
+
useImageEditor: () => useImageEditor,
|
|
39
|
+
useImageHistogram: () => useImageHistogram
|
|
25
40
|
});
|
|
26
41
|
module.exports = __toCommonJS(image_editor_exports);
|
|
27
42
|
|
|
@@ -36,6 +51,8 @@ function useImageEditor(options = {}) {
|
|
|
36
51
|
const controller = controllerRef.current;
|
|
37
52
|
const [state, setState] = (0, import_react.useState)(() => controller.getState());
|
|
38
53
|
const [historyTicks, setHistoryTicks] = (0, import_react.useState)(0);
|
|
54
|
+
const [histogram, setHistogram] = (0, import_react.useState)(() => controller.getHistogram());
|
|
55
|
+
(0, import_react.useEffect)(() => controller.subscribeHistogram(setHistogram), [controller]);
|
|
39
56
|
(0, import_react.useEffect)(() => {
|
|
40
57
|
const unsub = controller.subscribe((next) => {
|
|
41
58
|
setState(next);
|
|
@@ -67,6 +84,21 @@ function useImageEditor(options = {}) {
|
|
|
67
84
|
[controller]
|
|
68
85
|
);
|
|
69
86
|
const resetAdjustments = (0, import_react.useCallback)(() => controller.resetAdjustments(), [controller]);
|
|
87
|
+
const upgradeProcess = (0, import_react.useCallback)(() => controller.upgradeProcess(), [controller]);
|
|
88
|
+
const addAdjustmentLayer = (0, import_react.useCallback)(
|
|
89
|
+
(init, index) => controller.addAdjustmentLayer(init, index),
|
|
90
|
+
[controller]
|
|
91
|
+
);
|
|
92
|
+
const updateAdjustmentLayer = (0, import_react.useCallback)(
|
|
93
|
+
(id, update, commitToHistory = true) => controller.updateAdjustmentLayer(id, update, commitToHistory),
|
|
94
|
+
[controller]
|
|
95
|
+
);
|
|
96
|
+
const removeAdjustmentLayer = (0, import_react.useCallback)((id) => controller.removeAdjustmentLayer(id), [controller]);
|
|
97
|
+
const moveAdjustmentLayer = (0, import_react.useCallback)((id, to) => controller.moveAdjustmentLayer(id, to), [controller]);
|
|
98
|
+
const toggleAdjustmentLayer = (0, import_react.useCallback)(
|
|
99
|
+
(id, enabled) => controller.toggleAdjustmentLayer(id, enabled),
|
|
100
|
+
[controller]
|
|
101
|
+
);
|
|
70
102
|
const setDepthMask = (0, import_react.useCallback)((partial) => controller.setDepthMask(partial), [controller]);
|
|
71
103
|
const resetDepthMask = (0, import_react.useCallback)(() => controller.resetDepthMask(), [controller]);
|
|
72
104
|
const addAnnotation = (0, import_react.useCallback)((ann) => controller.addAnnotation(ann), [controller]);
|
|
@@ -127,6 +159,13 @@ function useImageEditor(options = {}) {
|
|
|
127
159
|
flipVertical,
|
|
128
160
|
setAdjustments,
|
|
129
161
|
resetAdjustments,
|
|
162
|
+
upgradeProcess,
|
|
163
|
+
addAdjustmentLayer,
|
|
164
|
+
updateAdjustmentLayer,
|
|
165
|
+
removeAdjustmentLayer,
|
|
166
|
+
moveAdjustmentLayer,
|
|
167
|
+
toggleAdjustmentLayer,
|
|
168
|
+
histogram,
|
|
130
169
|
setDepthMask,
|
|
131
170
|
resetDepthMask,
|
|
132
171
|
addAnnotation,
|
|
@@ -155,14 +194,445 @@ function useImageEditor(options = {}) {
|
|
|
155
194
|
applyBackgroundRemovedImage
|
|
156
195
|
}),
|
|
157
196
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
158
|
-
[controller, state, historyTicks]
|
|
197
|
+
[controller, state, historyTicks, histogram]
|
|
159
198
|
);
|
|
160
199
|
}
|
|
161
200
|
|
|
162
201
|
// src/image-editor/ImageEditor.tsx
|
|
163
|
-
var
|
|
202
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
203
|
+
var import_image_editor6 = require("@pixerate/editor/image-editor");
|
|
204
|
+
|
|
205
|
+
// src/image-editor/ControlSlider.tsx
|
|
164
206
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
165
207
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
208
|
+
var ControlSlider = ({ spec, value, onChange, disabled, label }) => {
|
|
209
|
+
const name = label ?? spec.label;
|
|
210
|
+
const track = (0, import_image_editor2.controlTrackBackground)(spec);
|
|
211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { "data-control-id": spec.id, children: [
|
|
212
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: name }),
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono", children: (0, import_image_editor2.formatControlValue)(spec, value) })
|
|
215
|
+
] }),
|
|
216
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
217
|
+
"input",
|
|
218
|
+
{
|
|
219
|
+
type: "range",
|
|
220
|
+
min: spec.min,
|
|
221
|
+
max: spec.max,
|
|
222
|
+
step: spec.step,
|
|
223
|
+
"aria-label": name,
|
|
224
|
+
disabled,
|
|
225
|
+
value,
|
|
226
|
+
onChange: (e) => onChange(Number(e.target.value)),
|
|
227
|
+
className: "w-full accent-indigo-500 disabled:opacity-40"
|
|
228
|
+
}
|
|
229
|
+
),
|
|
230
|
+
track && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-0.5 rounded-full opacity-70", style: { background: track } })
|
|
231
|
+
] });
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// src/image-editor/Histogram.tsx
|
|
235
|
+
var import_react2 = require("react");
|
|
236
|
+
var import_image_editor3 = require("@pixerate/editor/image-editor");
|
|
237
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
238
|
+
var FILL = {
|
|
239
|
+
luminance: "rgba(148, 163, 184, 0.45)",
|
|
240
|
+
red: "rgba(239, 68, 68, 0.45)",
|
|
241
|
+
green: "rgba(34, 197, 94, 0.45)",
|
|
242
|
+
blue: "rgba(59, 130, 246, 0.45)"
|
|
243
|
+
};
|
|
244
|
+
var W = 256;
|
|
245
|
+
var Histogram = ({ histogram, channel = "rgb", height = 64, className = "", style }) => {
|
|
246
|
+
const channels = channel === "rgb" ? ["luminance", "red", "green", "blue"] : [channel];
|
|
247
|
+
const paths = (0, import_react2.useMemo)(
|
|
248
|
+
() => histogram && histogram.samples > 0 ? channels.map((c) => ({ c, d: (0, import_image_editor3.histogramPath)(histogram, c, W, height) })) : [],
|
|
249
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
250
|
+
[histogram, channel, height]
|
|
251
|
+
);
|
|
252
|
+
const clipLow = histogram && histogram.samples ? Math.max(...histogram.shadows) / histogram.samples : 0;
|
|
253
|
+
const clipHigh = histogram && histogram.samples ? Math.max(...histogram.highlights) / histogram.samples : 0;
|
|
254
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
255
|
+
"svg",
|
|
256
|
+
{
|
|
257
|
+
viewBox: `0 0 ${W} ${height}`,
|
|
258
|
+
preserveAspectRatio: "none",
|
|
259
|
+
role: "img",
|
|
260
|
+
"aria-label": histogram ? `Histogram of ${histogram.samples} pixels` : "Histogram (no data)",
|
|
261
|
+
"data-testid": "image-editor-histogram",
|
|
262
|
+
className: `w-full rounded bg-slate-950/60 ${className}`,
|
|
263
|
+
style: { height, ...style },
|
|
264
|
+
children: [
|
|
265
|
+
paths.map(({ c, d }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d, fill: FILL[c], stroke: "none" }, c)),
|
|
266
|
+
clipLow > 5e-3 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: 0, y: 0, width: 3, height, fill: "#3b82f6", "data-testid": "histogram-clip-shadows" }),
|
|
267
|
+
clipHigh > 5e-3 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: W - 3, y: 0, width: 3, height, fill: "#ef4444", "data-testid": "histogram-clip-highlights" })
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
};
|
|
272
|
+
function useImageHistogram(controller) {
|
|
273
|
+
const [histogram, setHistogram] = (0, import_react2.useState)(() => controller.getHistogram());
|
|
274
|
+
(0, import_react2.useEffect)(() => controller.subscribeHistogram(setHistogram), [controller]);
|
|
275
|
+
return histogram;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/image-editor/AdjustmentLayersPanel.tsx
|
|
279
|
+
var import_react4 = require("react");
|
|
280
|
+
var import_image_editor5 = require("@pixerate/editor/image-editor");
|
|
281
|
+
|
|
282
|
+
// src/image-editor/CurvesEditor.tsx
|
|
283
|
+
var import_react3 = require("react");
|
|
284
|
+
var import_image_editor4 = require("@pixerate/editor/image-editor");
|
|
285
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
286
|
+
var BOX = 256;
|
|
287
|
+
var STROKE = { master: "#e2e8f0", red: "#ef4444", green: "#22c55e", blue: "#3b82f6" };
|
|
288
|
+
var CurvesEditor = ({ points, onChange, histogram, channel = "master", size = 200 }) => {
|
|
289
|
+
const svgRef = (0, import_react3.useRef)(null);
|
|
290
|
+
const [drag, setDrag] = (0, import_react3.useState)(null);
|
|
291
|
+
const toBox = (e) => {
|
|
292
|
+
const rect = svgRef.current?.getBoundingClientRect();
|
|
293
|
+
if (!rect || !rect.width || !rect.height) return { x: 0, y: 0 };
|
|
294
|
+
return { x: (e.clientX - rect.left) / rect.width * BOX, y: (e.clientY - rect.top) / rect.height * BOX };
|
|
295
|
+
};
|
|
296
|
+
const onPointerDown = (e) => {
|
|
297
|
+
const { x, y } = toBox(e);
|
|
298
|
+
let index = (0, import_image_editor4.hitTestCurvePoint)(points, x, y, BOX, BOX, 10);
|
|
299
|
+
if (index === -1) {
|
|
300
|
+
const inserted = (0, import_image_editor4.insertCurvePoint)(points, (0, import_image_editor4.boxToCurvePoint)(x, y, BOX, BOX));
|
|
301
|
+
onChange(inserted.points, true);
|
|
302
|
+
index = inserted.index;
|
|
303
|
+
} else {
|
|
304
|
+
onChange(points, true);
|
|
305
|
+
}
|
|
306
|
+
setDrag(index);
|
|
307
|
+
e.target.setPointerCapture?.(e.pointerId);
|
|
308
|
+
};
|
|
309
|
+
const onPointerMove = (e) => {
|
|
310
|
+
if (drag === null) return;
|
|
311
|
+
onChange((0, import_image_editor4.moveCurvePoint)(points, drag, (0, import_image_editor4.boxToCurvePoint)(toBox(e).x, toBox(e).y, BOX, BOX)), false);
|
|
312
|
+
};
|
|
313
|
+
const onDoubleClick = (e) => {
|
|
314
|
+
const { x, y } = toBox(e);
|
|
315
|
+
const index = (0, import_image_editor4.hitTestCurvePoint)(points, x, y, BOX, BOX, 10);
|
|
316
|
+
if (index !== -1 && points.length > 2) onChange((0, import_image_editor4.removeCurvePoint)(points, index), true);
|
|
317
|
+
};
|
|
318
|
+
const histChannel = channel === "master" ? "luminance" : channel;
|
|
319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
320
|
+
"svg",
|
|
321
|
+
{
|
|
322
|
+
ref: svgRef,
|
|
323
|
+
viewBox: `0 0 ${BOX} ${BOX}`,
|
|
324
|
+
width: size,
|
|
325
|
+
height: size,
|
|
326
|
+
role: "application",
|
|
327
|
+
"aria-label": `${channel} curve`,
|
|
328
|
+
"data-testid": "curves-editor",
|
|
329
|
+
className: "rounded bg-slate-950/70 touch-none select-none cursor-crosshair",
|
|
330
|
+
onPointerDown,
|
|
331
|
+
onPointerMove,
|
|
332
|
+
onPointerUp: () => setDrag(null),
|
|
333
|
+
onPointerCancel: () => setDrag(null),
|
|
334
|
+
onDoubleClick,
|
|
335
|
+
children: [
|
|
336
|
+
histogram && histogram.samples > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: (0, import_image_editor4.histogramPath)(histogram, histChannel, BOX, BOX), fill: "rgba(148, 163, 184, 0.25)" }),
|
|
337
|
+
[64, 128, 192].map((v) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("g", { stroke: "rgba(148, 163, 184, 0.2)", strokeWidth: 1, children: [
|
|
338
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: v, y1: 0, x2: v, y2: BOX }),
|
|
339
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: 0, y1: v, x2: BOX, y2: v })
|
|
340
|
+
] }, v)),
|
|
341
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: 0, y1: BOX, x2: BOX, y2: 0, stroke: "rgba(148, 163, 184, 0.35)", strokeDasharray: "4 4" }),
|
|
342
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: (0, import_image_editor4.curveSvgPath)(points, BOX, BOX), fill: "none", stroke: STROKE[channel], strokeWidth: 2 }),
|
|
343
|
+
points.map((p, i) => {
|
|
344
|
+
const b = (0, import_image_editor4.curvePointToBox)(p, BOX, BOX);
|
|
345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
346
|
+
"circle",
|
|
347
|
+
{
|
|
348
|
+
cx: b.x,
|
|
349
|
+
cy: b.y,
|
|
350
|
+
r: 5,
|
|
351
|
+
fill: drag === i ? STROKE[channel] : "#0f172a",
|
|
352
|
+
stroke: STROKE[channel],
|
|
353
|
+
strokeWidth: 2,
|
|
354
|
+
"aria-label": `Point ${p.input} to ${p.output}`
|
|
355
|
+
},
|
|
356
|
+
i
|
|
357
|
+
);
|
|
358
|
+
})
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
// src/image-editor/AdjustmentLayersPanel.tsx
|
|
365
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
366
|
+
var CHANNELS = [
|
|
367
|
+
{ id: "master", label: "RGB" },
|
|
368
|
+
{ id: "red", label: "Red" },
|
|
369
|
+
{ id: "green", label: "Green" },
|
|
370
|
+
{ id: "blue", label: "Blue" }
|
|
371
|
+
];
|
|
372
|
+
var TONES = [
|
|
373
|
+
{ id: "shadows", label: "Shadows" },
|
|
374
|
+
{ id: "midtones", label: "Midtones" },
|
|
375
|
+
{ id: "highlights", label: "Highlights" }
|
|
376
|
+
];
|
|
377
|
+
var selectClass = "bg-slate-800 border border-slate-700 rounded px-1.5 py-1 text-slate-200";
|
|
378
|
+
var chipClass = (on) => `px-2 py-0.5 rounded text-[10px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-400 hover:text-slate-200"}`;
|
|
379
|
+
var HueRangeStrip = ({ bounds }) => {
|
|
380
|
+
const pts = Array.from({ length: 73 }, (_, i) => `${i / 72 * 360},${20 - (0, import_image_editor5.hueRangeWeight)({ bounds }, i * 5) * 18}`).join(" ");
|
|
381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 360 20", preserveAspectRatio: "none", className: "w-full h-4 rounded", "data-testid": "hue-range-strip", children: [
|
|
382
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("linearGradient", { id: "pixerate-hue-strip", children: [0, 60, 120, 180, 240, 300, 360].map((h) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("stop", { offset: `${h / 360 * 100}%`, stopColor: `hsl(${h}, 90%, 50%)` }, h)) }) }),
|
|
383
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { width: 360, height: 20, fill: "url(#pixerate-hue-strip)", opacity: 0.6 }),
|
|
384
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: pts, fill: "none", stroke: "#fff", strokeWidth: 1.5 })
|
|
385
|
+
] });
|
|
386
|
+
};
|
|
387
|
+
var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
|
|
388
|
+
const follow = layersProp === void 0;
|
|
389
|
+
const [, setTick] = (0, import_react4.useState)(0);
|
|
390
|
+
(0, import_react4.useEffect)(() => follow ? controller.subscribe(() => setTick((n) => n + 1)) : void 0, [controller, follow]);
|
|
391
|
+
const layers = layersProp ?? controller.getAdjustmentLayers();
|
|
392
|
+
const [newKind, setNewKind] = (0, import_react4.useState)("curves");
|
|
393
|
+
const [selectedId, setSelectedId] = (0, import_react4.useState)(null);
|
|
394
|
+
const [channel, setChannel] = (0, import_react4.useState)("master");
|
|
395
|
+
const [range, setRange] = (0, import_react4.useState)(-1);
|
|
396
|
+
const [tone, setTone] = (0, import_react4.useState)("midtones");
|
|
397
|
+
const selected = layers.find((l) => l.id === selectedId) ?? null;
|
|
398
|
+
const topFirst = [...layers].reverse();
|
|
399
|
+
const setParam = (layer, path, value, commit = true) => controller.updateAdjustmentLayer(layer.id, { params: (0, import_image_editor5.setControlPath)(layer.params, path, value) }, commit);
|
|
400
|
+
const slider = (layer, spec, label) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
401
|
+
ControlSlider,
|
|
402
|
+
{
|
|
403
|
+
spec,
|
|
404
|
+
label,
|
|
405
|
+
value: Number((0, import_image_editor5.getControlPath)(layer.params, spec.id) ?? spec.default),
|
|
406
|
+
onChange: (v) => setParam(layer, spec.id, v)
|
|
407
|
+
},
|
|
408
|
+
spec.id
|
|
409
|
+
);
|
|
410
|
+
const controlsOf = (layer, filter = () => true) => import_image_editor5.ADJUSTMENT_LAYER_CONTROLS[layer.kind].filter(filter);
|
|
411
|
+
const checkbox = (layer, path, label) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
412
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
413
|
+
"input",
|
|
414
|
+
{
|
|
415
|
+
type: "checkbox",
|
|
416
|
+
checked: Boolean((0, import_image_editor5.getControlPath)(layer.params, path)),
|
|
417
|
+
onChange: (e) => setParam(layer, path, e.target.checked),
|
|
418
|
+
className: "accent-indigo-500"
|
|
419
|
+
}
|
|
420
|
+
),
|
|
421
|
+
label
|
|
422
|
+
] });
|
|
423
|
+
const editor = (layer) => {
|
|
424
|
+
switch (layer.kind) {
|
|
425
|
+
case "curves":
|
|
426
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
427
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Curve channel", children: CHANNELS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: chipClass(channel === c.id), onClick: () => setChannel(c.id), children: c.label }, c.id)) }),
|
|
428
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
429
|
+
CurvesEditor,
|
|
430
|
+
{
|
|
431
|
+
points: layer.params[channel],
|
|
432
|
+
channel,
|
|
433
|
+
histogram,
|
|
434
|
+
onChange: (points, commit) => setParam(layer, channel, points, commit)
|
|
435
|
+
}
|
|
436
|
+
)
|
|
437
|
+
] });
|
|
438
|
+
case "levels":
|
|
439
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
440
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Levels channel", children: CHANNELS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: chipClass(channel === c.id), onClick: () => setChannel(c.id), children: c.label }, c.id)) }),
|
|
441
|
+
controlsOf(layer, (s) => s.id.startsWith(`${channel}.`)).map((s) => slider(layer, s))
|
|
442
|
+
] });
|
|
443
|
+
case "hueSaturation":
|
|
444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap gap-1", role: "group", "aria-label": "Hue range", children: [
|
|
446
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: chipClass(range === -1), onClick: () => setRange(-1), children: "Master" }),
|
|
447
|
+
import_image_editor5.HUE_RANGE_LABELS.map((name, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: chipClass(range === i), onClick: () => setRange(i), disabled: layer.params.colorize, children: name }, name))
|
|
448
|
+
] }),
|
|
449
|
+
range >= 0 && !layer.params.colorize && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HueRangeStrip, { bounds: layer.params.ranges[range].bounds }),
|
|
450
|
+
controlsOf(layer, (s) => range === -1 || layer.params.colorize ? !s.id.startsWith("ranges.") : s.id.startsWith(`ranges.${range}.`)).map(
|
|
451
|
+
(s) => slider(layer, s)
|
|
452
|
+
),
|
|
453
|
+
range === -1 && checkbox(layer, "colorize", "Colorize")
|
|
454
|
+
] });
|
|
455
|
+
case "colorBalance":
|
|
456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
457
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Tone", children: TONES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: chipClass(tone === t.id), onClick: () => setTone(t.id), children: t.label }, t.id)) }),
|
|
458
|
+
controlsOf(layer, (s) => s.id.startsWith(`${tone}.`)).map((s) => slider(layer, s)),
|
|
459
|
+
checkbox(layer, "preserveLuminosity", "Preserve luminosity")
|
|
460
|
+
] });
|
|
461
|
+
case "blackWhite":
|
|
462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
463
|
+
controlsOf(layer).map((s) => slider(layer, s)),
|
|
464
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
465
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
466
|
+
"input",
|
|
467
|
+
{
|
|
468
|
+
type: "checkbox",
|
|
469
|
+
checked: layer.params.tint !== null,
|
|
470
|
+
onChange: (e) => setParam(layer, "tint", e.target.checked ? "#e1d3b3" : null),
|
|
471
|
+
className: "accent-indigo-500"
|
|
472
|
+
}
|
|
473
|
+
),
|
|
474
|
+
"Tint",
|
|
475
|
+
layer.params.tint && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
476
|
+
"input",
|
|
477
|
+
{
|
|
478
|
+
type: "color",
|
|
479
|
+
"aria-label": "Tint colour",
|
|
480
|
+
value: layer.params.tint,
|
|
481
|
+
onChange: (e) => setParam(layer, "tint", e.target.value),
|
|
482
|
+
className: "h-5 w-8 bg-transparent"
|
|
483
|
+
}
|
|
484
|
+
)
|
|
485
|
+
] })
|
|
486
|
+
] });
|
|
487
|
+
case "photoFilter":
|
|
488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
490
|
+
"Filter colour",
|
|
491
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
492
|
+
"input",
|
|
493
|
+
{
|
|
494
|
+
type: "color",
|
|
495
|
+
"aria-label": "Filter colour",
|
|
496
|
+
value: layer.params.color,
|
|
497
|
+
onChange: (e) => setParam(layer, "color", e.target.value),
|
|
498
|
+
className: "h-5 w-8 bg-transparent"
|
|
499
|
+
}
|
|
500
|
+
)
|
|
501
|
+
] }),
|
|
502
|
+
controlsOf(layer).map((s) => slider(layer, s)),
|
|
503
|
+
checkbox(layer, "preserveLuminosity", "Preserve luminosity")
|
|
504
|
+
] });
|
|
505
|
+
case "invert":
|
|
506
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-slate-500 text-[11px]", children: "Invert has no settings." });
|
|
507
|
+
default:
|
|
508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-col gap-2", children: controlsOf(layer).map((s) => slider(layer, s)) });
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2 text-xs", "data-testid": "adjustment-layers-panel", children: [
|
|
512
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Adjustment Layers" }) }),
|
|
513
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-1.5", children: [
|
|
514
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
515
|
+
"select",
|
|
516
|
+
{
|
|
517
|
+
"aria-label": "New adjustment layer kind",
|
|
518
|
+
className: `${selectClass} flex-1`,
|
|
519
|
+
value: newKind,
|
|
520
|
+
onChange: (e) => setNewKind(e.target.value),
|
|
521
|
+
children: import_image_editor5.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: k.kind, children: k.label }, k.kind))
|
|
522
|
+
}
|
|
523
|
+
),
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
525
|
+
"button",
|
|
526
|
+
{
|
|
527
|
+
type: "button",
|
|
528
|
+
className: "px-2 py-1 rounded bg-indigo-600 text-white hover:bg-indigo-500",
|
|
529
|
+
onClick: () => {
|
|
530
|
+
setSelectedId(controller.addAdjustmentLayer(newKind));
|
|
531
|
+
setChannel("master");
|
|
532
|
+
setRange(-1);
|
|
533
|
+
},
|
|
534
|
+
children: "Add Layer"
|
|
535
|
+
}
|
|
536
|
+
)
|
|
537
|
+
] }),
|
|
538
|
+
topFirst.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "flex flex-col gap-1", "aria-label": "Adjustment layers", children: topFirst.map((layer) => {
|
|
539
|
+
const index = layers.indexOf(layer);
|
|
540
|
+
const label = layer.name || (0, import_image_editor5.adjustmentKindLabel)(layer.kind);
|
|
541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
542
|
+
"li",
|
|
543
|
+
{
|
|
544
|
+
className: `flex items-center gap-1.5 rounded px-1.5 py-1 ${layer.id === selectedId ? "bg-indigo-600/20 ring-1 ring-indigo-500/50" : "bg-slate-800/60"}`,
|
|
545
|
+
children: [
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
547
|
+
"input",
|
|
548
|
+
{
|
|
549
|
+
type: "checkbox",
|
|
550
|
+
"aria-label": `Show ${label}`,
|
|
551
|
+
checked: layer.enabled,
|
|
552
|
+
onChange: () => controller.toggleAdjustmentLayer(layer.id),
|
|
553
|
+
className: "accent-indigo-500"
|
|
554
|
+
}
|
|
555
|
+
),
|
|
556
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
557
|
+
"button",
|
|
558
|
+
{
|
|
559
|
+
type: "button",
|
|
560
|
+
className: `flex-1 text-left truncate ${layer.enabled ? "text-slate-200" : "text-slate-500 line-through"}`,
|
|
561
|
+
onClick: () => setSelectedId(layer.id === selectedId ? null : layer.id),
|
|
562
|
+
"aria-pressed": layer.id === selectedId,
|
|
563
|
+
children: label
|
|
564
|
+
}
|
|
565
|
+
),
|
|
566
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
567
|
+
"button",
|
|
568
|
+
{
|
|
569
|
+
type: "button",
|
|
570
|
+
"aria-label": `Move ${label} up`,
|
|
571
|
+
disabled: index === layers.length - 1,
|
|
572
|
+
onClick: () => controller.moveAdjustmentLayer(layer.id, index + 1),
|
|
573
|
+
className: "px-1 text-slate-400 hover:text-slate-200 disabled:opacity-30",
|
|
574
|
+
children: "\u2191"
|
|
575
|
+
}
|
|
576
|
+
),
|
|
577
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
578
|
+
"button",
|
|
579
|
+
{
|
|
580
|
+
type: "button",
|
|
581
|
+
"aria-label": `Move ${label} down`,
|
|
582
|
+
disabled: index === 0,
|
|
583
|
+
onClick: () => controller.moveAdjustmentLayer(layer.id, index - 1),
|
|
584
|
+
className: "px-1 text-slate-400 hover:text-slate-200 disabled:opacity-30",
|
|
585
|
+
children: "\u2193"
|
|
586
|
+
}
|
|
587
|
+
),
|
|
588
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
589
|
+
"button",
|
|
590
|
+
{
|
|
591
|
+
type: "button",
|
|
592
|
+
"aria-label": `Remove ${label}`,
|
|
593
|
+
onClick: () => {
|
|
594
|
+
controller.removeAdjustmentLayer(layer.id);
|
|
595
|
+
if (selectedId === layer.id) setSelectedId(null);
|
|
596
|
+
},
|
|
597
|
+
className: "px-1 text-rose-400 hover:text-rose-300",
|
|
598
|
+
children: "\u2715"
|
|
599
|
+
}
|
|
600
|
+
)
|
|
601
|
+
]
|
|
602
|
+
},
|
|
603
|
+
layer.id
|
|
604
|
+
);
|
|
605
|
+
}) }),
|
|
606
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-2 rounded border border-slate-700/60 p-2", "data-testid": "adjustment-layer-editor", children: [
|
|
607
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
608
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Blend" }),
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
610
|
+
"select",
|
|
611
|
+
{
|
|
612
|
+
"aria-label": "Blend mode",
|
|
613
|
+
className: `${selectClass} flex-1`,
|
|
614
|
+
value: selected.blend,
|
|
615
|
+
onChange: (e) => controller.updateAdjustmentLayer(selected.id, { blend: e.target.value }),
|
|
616
|
+
children: import_image_editor5.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: m.id, children: m.label }, m.id))
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
] }),
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
621
|
+
ControlSlider,
|
|
622
|
+
{
|
|
623
|
+
spec: import_image_editor5.ADJUSTMENT_LAYER_OPACITY_CONTROL,
|
|
624
|
+
label: "Layer opacity",
|
|
625
|
+
value: selected.opacity,
|
|
626
|
+
onChange: (v) => controller.updateAdjustmentLayer(selected.id, { opacity: v })
|
|
627
|
+
}
|
|
628
|
+
),
|
|
629
|
+
editor(selected)
|
|
630
|
+
] })
|
|
631
|
+
] });
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
// src/image-editor/ImageEditor.tsx
|
|
635
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
166
636
|
var ImageEditor = ({
|
|
167
637
|
editor: externalEditor,
|
|
168
638
|
src,
|
|
@@ -177,16 +647,17 @@ var ImageEditor = ({
|
|
|
177
647
|
const internalEditor = useImageEditor({ image: src });
|
|
178
648
|
const editor = externalEditor || internalEditor;
|
|
179
649
|
const { state, controller } = editor;
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
const
|
|
183
|
-
const [
|
|
184
|
-
const [
|
|
185
|
-
const [
|
|
186
|
-
const [
|
|
187
|
-
const [
|
|
188
|
-
const [
|
|
189
|
-
const [
|
|
650
|
+
const legacyProcess = (0, import_image_editor6.normalizeProcessVersion)(state.adjustments.process) < import_image_editor6.LATEST_PROCESS_VERSION;
|
|
651
|
+
const canvasRef = (0, import_react5.useRef)(null);
|
|
652
|
+
const containerRef = (0, import_react5.useRef)(null);
|
|
653
|
+
const [activeTab, setActiveTab] = (0, import_react5.useState)("crop");
|
|
654
|
+
const [activeCropRatio, setActiveCropRatio] = (0, import_react5.useState)(null);
|
|
655
|
+
const [inpaintPrompt, setInpaintPrompt] = (0, import_react5.useState)("");
|
|
656
|
+
const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react5.useState)("annotations");
|
|
657
|
+
const [isRemovingBg, setIsRemovingBg] = (0, import_react5.useState)(false);
|
|
658
|
+
const [isInpainting, setIsInpainting] = (0, import_react5.useState)(false);
|
|
659
|
+
const [aiError, setAiError] = (0, import_react5.useState)(null);
|
|
660
|
+
const [aiSuccess, setAiSuccess] = (0, import_react5.useState)(null);
|
|
190
661
|
const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
|
|
191
662
|
const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
|
|
192
663
|
const handleRemoveBackground = async () => {
|
|
@@ -248,18 +719,18 @@ var ImageEditor = ({
|
|
|
248
719
|
setIsInpainting(false);
|
|
249
720
|
}
|
|
250
721
|
};
|
|
251
|
-
const [activeColor, setActiveColor] = (0,
|
|
252
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
253
|
-
const [fontSize, setFontSize] = (0,
|
|
254
|
-
const [textInput, setTextInput] = (0,
|
|
255
|
-
const draftAnnotationRef = (0,
|
|
256
|
-
const draftCropRef = (0,
|
|
257
|
-
const cropDragInfoRef = (0,
|
|
258
|
-
const annotationDragInfoRef = (0,
|
|
259
|
-
const isDrawingRef = (0,
|
|
260
|
-
const currentPathRef = (0,
|
|
261
|
-
const dragStartPointRef = (0,
|
|
262
|
-
const renderCanvas = (0,
|
|
722
|
+
const [activeColor, setActiveColor] = (0, import_react5.useState)("#ef4444");
|
|
723
|
+
const [strokeWidth, setStrokeWidth] = (0, import_react5.useState)(3);
|
|
724
|
+
const [fontSize, setFontSize] = (0, import_react5.useState)(24);
|
|
725
|
+
const [textInput, setTextInput] = (0, import_react5.useState)("");
|
|
726
|
+
const draftAnnotationRef = (0, import_react5.useRef)(null);
|
|
727
|
+
const draftCropRef = (0, import_react5.useRef)(null);
|
|
728
|
+
const cropDragInfoRef = (0, import_react5.useRef)(null);
|
|
729
|
+
const annotationDragInfoRef = (0, import_react5.useRef)(null);
|
|
730
|
+
const isDrawingRef = (0, import_react5.useRef)(false);
|
|
731
|
+
const currentPathRef = (0, import_react5.useRef)([]);
|
|
732
|
+
const dragStartPointRef = (0, import_react5.useRef)(null);
|
|
733
|
+
const renderCanvas = (0, import_react5.useCallback)(
|
|
263
734
|
async (draftAnnotation, draftCrop) => {
|
|
264
735
|
const canvas = canvasRef.current;
|
|
265
736
|
const container = containerRef.current;
|
|
@@ -278,7 +749,7 @@ var ImageEditor = ({
|
|
|
278
749
|
},
|
|
279
750
|
[controller, activeTab]
|
|
280
751
|
);
|
|
281
|
-
(0,
|
|
752
|
+
(0, import_react5.useEffect)(() => {
|
|
282
753
|
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
283
754
|
const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
284
755
|
const animId = raf(() => {
|
|
@@ -286,12 +757,12 @@ var ImageEditor = ({
|
|
|
286
757
|
});
|
|
287
758
|
return () => caf(animId);
|
|
288
759
|
}, [renderCanvas, state]);
|
|
289
|
-
(0,
|
|
760
|
+
(0, import_react5.useEffect)(() => {
|
|
290
761
|
if (activeTab === "crop" && editor.state.activeTool !== "crop") {
|
|
291
762
|
editor.setTool("crop");
|
|
292
763
|
}
|
|
293
764
|
}, [activeTab, editor]);
|
|
294
|
-
(0,
|
|
765
|
+
(0, import_react5.useEffect)(() => {
|
|
295
766
|
const container = containerRef.current;
|
|
296
767
|
if (!container) return;
|
|
297
768
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -328,8 +799,8 @@ var ImageEditor = ({
|
|
|
328
799
|
width: state.imageDimensions.width,
|
|
329
800
|
height: state.imageDimensions.height
|
|
330
801
|
};
|
|
331
|
-
const handle = (0,
|
|
332
|
-
const startImgPt = (0,
|
|
802
|
+
const handle = (0, import_image_editor6.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
803
|
+
const startImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
333
804
|
if (handle) {
|
|
334
805
|
cropDragInfoRef.current = {
|
|
335
806
|
handle,
|
|
@@ -348,12 +819,12 @@ var ImageEditor = ({
|
|
|
348
819
|
return;
|
|
349
820
|
}
|
|
350
821
|
if (activeTab === "annotate") {
|
|
351
|
-
const imgPt = (0,
|
|
822
|
+
const imgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
352
823
|
dragStartPointRef.current = imgPt;
|
|
353
824
|
if (state.activeTool === "select") {
|
|
354
825
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
355
826
|
const ann = state.annotations[i];
|
|
356
|
-
if ((0,
|
|
827
|
+
if ((0, import_image_editor6.hitTestAnnotation)(imgPt, ann)) {
|
|
357
828
|
editor.selectAnnotation(ann.id);
|
|
358
829
|
annotationDragInfoRef.current = {
|
|
359
830
|
annId: ann.id,
|
|
@@ -390,7 +861,7 @@ var ImageEditor = ({
|
|
|
390
861
|
if (activeTab === "crop") {
|
|
391
862
|
const drag = cropDragInfoRef.current;
|
|
392
863
|
if (drag) {
|
|
393
|
-
const currentImgPt = (0,
|
|
864
|
+
const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
394
865
|
let newCrop;
|
|
395
866
|
if (drag.handle === "new") {
|
|
396
867
|
const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
|
|
@@ -404,7 +875,7 @@ var ImageEditor = ({
|
|
|
404
875
|
height: Math.round(Math.max(20, maxY - minY))
|
|
405
876
|
};
|
|
406
877
|
} else {
|
|
407
|
-
newCrop = (0,
|
|
878
|
+
newCrop = (0, import_image_editor6.calculateCropDrag)(
|
|
408
879
|
drag.startCrop,
|
|
409
880
|
drag.handle,
|
|
410
881
|
drag.startImgPt,
|
|
@@ -424,15 +895,15 @@ var ImageEditor = ({
|
|
|
424
895
|
width: state.imageDimensions.width,
|
|
425
896
|
height: state.imageDimensions.height
|
|
426
897
|
};
|
|
427
|
-
const handle = (0,
|
|
428
|
-
canvas.style.cursor = (0,
|
|
898
|
+
const handle = (0, import_image_editor6.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
899
|
+
canvas.style.cursor = (0, import_image_editor6.getCropCursor)(handle, state.transform);
|
|
429
900
|
}
|
|
430
901
|
return;
|
|
431
902
|
}
|
|
432
903
|
if (activeTab === "annotate") {
|
|
433
904
|
if (annotationDragInfoRef.current) {
|
|
434
905
|
const drag = annotationDragInfoRef.current;
|
|
435
|
-
const currentImgPt2 = (0,
|
|
906
|
+
const currentImgPt2 = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
436
907
|
const dx = currentImgPt2.x - drag.startImgPt.x;
|
|
437
908
|
const dy = currentImgPt2.y - drag.startImgPt.y;
|
|
438
909
|
editor.updateAnnotation(drag.annId, {
|
|
@@ -444,10 +915,10 @@ var ImageEditor = ({
|
|
|
444
915
|
const startPt = dragStartPointRef.current;
|
|
445
916
|
if (!startPt) {
|
|
446
917
|
if (state.activeTool === "select") {
|
|
447
|
-
const imgPt = (0,
|
|
918
|
+
const imgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
448
919
|
let hovered = false;
|
|
449
920
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
450
|
-
if ((0,
|
|
921
|
+
if ((0, import_image_editor6.hitTestAnnotation)(imgPt, state.annotations[i])) {
|
|
451
922
|
hovered = true;
|
|
452
923
|
break;
|
|
453
924
|
}
|
|
@@ -458,7 +929,7 @@ var ImageEditor = ({
|
|
|
458
929
|
}
|
|
459
930
|
return;
|
|
460
931
|
}
|
|
461
|
-
const currentImgPt = (0,
|
|
932
|
+
const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
462
933
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
463
934
|
currentPathRef.current.push(currentImgPt);
|
|
464
935
|
const draft = {
|
|
@@ -553,7 +1024,7 @@ var ImageEditor = ({
|
|
|
553
1024
|
}
|
|
554
1025
|
const startPt = dragStartPointRef.current;
|
|
555
1026
|
if (startPt) {
|
|
556
|
-
const currentImgPt = (0,
|
|
1027
|
+
const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
557
1028
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
558
1029
|
if (currentPathRef.current.length > 1) {
|
|
559
1030
|
editor.addAnnotation({
|
|
@@ -649,15 +1120,15 @@ var ImageEditor = ({
|
|
|
649
1120
|
link.click();
|
|
650
1121
|
}
|
|
651
1122
|
};
|
|
652
|
-
return /* @__PURE__ */ (0,
|
|
1123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
653
1124
|
"div",
|
|
654
1125
|
{
|
|
655
1126
|
className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
|
|
656
1127
|
style,
|
|
657
1128
|
children: [
|
|
658
|
-
/* @__PURE__ */ (0,
|
|
659
|
-
/* @__PURE__ */ (0,
|
|
660
|
-
/* @__PURE__ */ (0,
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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: [
|
|
1130
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
|
|
1131
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
661
1132
|
"button",
|
|
662
1133
|
{
|
|
663
1134
|
type: "button",
|
|
@@ -669,7 +1140,7 @@ var ImageEditor = ({
|
|
|
669
1140
|
children: "Transform & Crop"
|
|
670
1141
|
}
|
|
671
1142
|
),
|
|
672
|
-
/* @__PURE__ */ (0,
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
673
1144
|
"button",
|
|
674
1145
|
{
|
|
675
1146
|
type: "button",
|
|
@@ -681,7 +1152,7 @@ var ImageEditor = ({
|
|
|
681
1152
|
children: "Adjustments"
|
|
682
1153
|
}
|
|
683
1154
|
),
|
|
684
|
-
/* @__PURE__ */ (0,
|
|
1155
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
685
1156
|
"button",
|
|
686
1157
|
{
|
|
687
1158
|
type: "button",
|
|
@@ -693,7 +1164,7 @@ var ImageEditor = ({
|
|
|
693
1164
|
children: "Annotations"
|
|
694
1165
|
}
|
|
695
1166
|
),
|
|
696
|
-
/* @__PURE__ */ (0,
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
697
1168
|
"button",
|
|
698
1169
|
{
|
|
699
1170
|
type: "button",
|
|
@@ -705,7 +1176,7 @@ var ImageEditor = ({
|
|
|
705
1176
|
children: "Depth Mask"
|
|
706
1177
|
}
|
|
707
1178
|
),
|
|
708
|
-
/* @__PURE__ */ (0,
|
|
1179
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
709
1180
|
"button",
|
|
710
1181
|
{
|
|
711
1182
|
type: "button",
|
|
@@ -715,14 +1186,14 @@ var ImageEditor = ({
|
|
|
715
1186
|
},
|
|
716
1187
|
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"}`,
|
|
717
1188
|
children: [
|
|
718
|
-
/* @__PURE__ */ (0,
|
|
1189
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) }),
|
|
719
1190
|
"AI Tools"
|
|
720
1191
|
]
|
|
721
1192
|
}
|
|
722
1193
|
)
|
|
723
1194
|
] }),
|
|
724
|
-
/* @__PURE__ */ (0,
|
|
725
|
-
/* @__PURE__ */ (0,
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
1196
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
726
1197
|
"button",
|
|
727
1198
|
{
|
|
728
1199
|
type: "button",
|
|
@@ -733,7 +1204,7 @@ var ImageEditor = ({
|
|
|
733
1204
|
children: "\u21A9"
|
|
734
1205
|
}
|
|
735
1206
|
),
|
|
736
|
-
/* @__PURE__ */ (0,
|
|
1207
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
737
1208
|
"button",
|
|
738
1209
|
{
|
|
739
1210
|
type: "button",
|
|
@@ -744,7 +1215,7 @@ var ImageEditor = ({
|
|
|
744
1215
|
children: "\u21AA"
|
|
745
1216
|
}
|
|
746
1217
|
),
|
|
747
|
-
/* @__PURE__ */ (0,
|
|
1218
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
748
1219
|
"button",
|
|
749
1220
|
{
|
|
750
1221
|
type: "button",
|
|
@@ -753,8 +1224,8 @@ var ImageEditor = ({
|
|
|
753
1224
|
children: "Reset"
|
|
754
1225
|
}
|
|
755
1226
|
),
|
|
756
|
-
/* @__PURE__ */ (0,
|
|
757
|
-
/* @__PURE__ */ (0,
|
|
1227
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
1228
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
758
1229
|
"button",
|
|
759
1230
|
{
|
|
760
1231
|
type: "button",
|
|
@@ -764,11 +1235,11 @@ var ImageEditor = ({
|
|
|
764
1235
|
children: "-"
|
|
765
1236
|
}
|
|
766
1237
|
),
|
|
767
|
-
/* @__PURE__ */ (0,
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
|
|
768
1239
|
Math.round(state.zoom * 100),
|
|
769
1240
|
"%"
|
|
770
1241
|
] }),
|
|
771
|
-
/* @__PURE__ */ (0,
|
|
1242
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
772
1243
|
"button",
|
|
773
1244
|
{
|
|
774
1245
|
type: "button",
|
|
@@ -778,8 +1249,8 @@ var ImageEditor = ({
|
|
|
778
1249
|
children: "+"
|
|
779
1250
|
}
|
|
780
1251
|
),
|
|
781
|
-
/* @__PURE__ */ (0,
|
|
782
|
-
/* @__PURE__ */ (0,
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
783
1254
|
"button",
|
|
784
1255
|
{
|
|
785
1256
|
type: "button",
|
|
@@ -790,7 +1261,7 @@ var ImageEditor = ({
|
|
|
790
1261
|
children: "Hold Compare"
|
|
791
1262
|
}
|
|
792
1263
|
),
|
|
793
|
-
/* @__PURE__ */ (0,
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
794
1265
|
"button",
|
|
795
1266
|
{
|
|
796
1267
|
type: "button",
|
|
@@ -801,13 +1272,13 @@ var ImageEditor = ({
|
|
|
801
1272
|
)
|
|
802
1273
|
] })
|
|
803
1274
|
] }),
|
|
804
|
-
/* @__PURE__ */ (0,
|
|
805
|
-
/* @__PURE__ */ (0,
|
|
1275
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
|
|
1276
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
806
1277
|
"div",
|
|
807
1278
|
{
|
|
808
1279
|
ref: containerRef,
|
|
809
1280
|
className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
|
|
810
|
-
children: /* @__PURE__ */ (0,
|
|
1281
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
811
1282
|
"canvas",
|
|
812
1283
|
{
|
|
813
1284
|
ref: canvasRef,
|
|
@@ -820,11 +1291,11 @@ var ImageEditor = ({
|
|
|
820
1291
|
)
|
|
821
1292
|
}
|
|
822
1293
|
),
|
|
823
|
-
/* @__PURE__ */ (0,
|
|
824
|
-
activeTab === "crop" && /* @__PURE__ */ (0,
|
|
825
|
-
/* @__PURE__ */ (0,
|
|
826
|
-
/* @__PURE__ */ (0,
|
|
827
|
-
/* @__PURE__ */ (0,
|
|
1294
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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: [
|
|
1295
|
+
activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
1296
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
1298
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
828
1299
|
"button",
|
|
829
1300
|
{
|
|
830
1301
|
type: "button",
|
|
@@ -836,7 +1307,7 @@ var ImageEditor = ({
|
|
|
836
1307
|
children: "Freeform"
|
|
837
1308
|
}
|
|
838
1309
|
),
|
|
839
|
-
/* @__PURE__ */ (0,
|
|
1310
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
840
1311
|
"button",
|
|
841
1312
|
{
|
|
842
1313
|
type: "button",
|
|
@@ -848,7 +1319,7 @@ var ImageEditor = ({
|
|
|
848
1319
|
children: "1:1 Square"
|
|
849
1320
|
}
|
|
850
1321
|
),
|
|
851
|
-
/* @__PURE__ */ (0,
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
852
1323
|
"button",
|
|
853
1324
|
{
|
|
854
1325
|
type: "button",
|
|
@@ -860,7 +1331,7 @@ var ImageEditor = ({
|
|
|
860
1331
|
children: "4:3 Standard"
|
|
861
1332
|
}
|
|
862
1333
|
),
|
|
863
|
-
/* @__PURE__ */ (0,
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
864
1335
|
"button",
|
|
865
1336
|
{
|
|
866
1337
|
type: "button",
|
|
@@ -872,7 +1343,7 @@ var ImageEditor = ({
|
|
|
872
1343
|
children: "16:9 Wide"
|
|
873
1344
|
}
|
|
874
1345
|
),
|
|
875
|
-
/* @__PURE__ */ (0,
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
876
1347
|
"button",
|
|
877
1348
|
{
|
|
878
1349
|
type: "button",
|
|
@@ -884,7 +1355,7 @@ var ImageEditor = ({
|
|
|
884
1355
|
children: "3:2 Photo"
|
|
885
1356
|
}
|
|
886
1357
|
),
|
|
887
|
-
/* @__PURE__ */ (0,
|
|
1358
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
888
1359
|
"button",
|
|
889
1360
|
{
|
|
890
1361
|
type: "button",
|
|
@@ -897,10 +1368,10 @@ var ImageEditor = ({
|
|
|
897
1368
|
}
|
|
898
1369
|
)
|
|
899
1370
|
] }),
|
|
900
|
-
/* @__PURE__ */ (0,
|
|
901
|
-
/* @__PURE__ */ (0,
|
|
902
|
-
/* @__PURE__ */ (0,
|
|
903
|
-
/* @__PURE__ */ (0,
|
|
1371
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
1372
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
|
|
1373
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
1374
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
904
1375
|
"button",
|
|
905
1376
|
{
|
|
906
1377
|
type: "button",
|
|
@@ -909,7 +1380,7 @@ var ImageEditor = ({
|
|
|
909
1380
|
children: "Rotate -90\xB0"
|
|
910
1381
|
}
|
|
911
1382
|
),
|
|
912
|
-
/* @__PURE__ */ (0,
|
|
1383
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
913
1384
|
"button",
|
|
914
1385
|
{
|
|
915
1386
|
type: "button",
|
|
@@ -918,7 +1389,7 @@ var ImageEditor = ({
|
|
|
918
1389
|
children: "Rotate +90\xB0"
|
|
919
1390
|
}
|
|
920
1391
|
),
|
|
921
|
-
/* @__PURE__ */ (0,
|
|
1392
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
922
1393
|
"button",
|
|
923
1394
|
{
|
|
924
1395
|
type: "button",
|
|
@@ -927,7 +1398,7 @@ var ImageEditor = ({
|
|
|
927
1398
|
children: "Flip Horizontal"
|
|
928
1399
|
}
|
|
929
1400
|
),
|
|
930
|
-
/* @__PURE__ */ (0,
|
|
1401
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
931
1402
|
"button",
|
|
932
1403
|
{
|
|
933
1404
|
type: "button",
|
|
@@ -938,10 +1409,10 @@ var ImageEditor = ({
|
|
|
938
1409
|
)
|
|
939
1410
|
] })
|
|
940
1411
|
] }),
|
|
941
|
-
activeTab === "adjust" && /* @__PURE__ */ (0,
|
|
942
|
-
/* @__PURE__ */ (0,
|
|
943
|
-
/* @__PURE__ */ (0,
|
|
944
|
-
/* @__PURE__ */ (0,
|
|
1412
|
+
activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
1413
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1414
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
945
1416
|
"button",
|
|
946
1417
|
{
|
|
947
1418
|
type: "button",
|
|
@@ -951,136 +1422,49 @@ var ImageEditor = ({
|
|
|
951
1422
|
}
|
|
952
1423
|
)
|
|
953
1424
|
] }),
|
|
954
|
-
/* @__PURE__ */ (0,
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
] }),
|
|
959
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
960
|
-
"input",
|
|
961
|
-
{
|
|
962
|
-
type: "range",
|
|
963
|
-
min: "-100",
|
|
964
|
-
max: "100",
|
|
965
|
-
value: state.adjustments.brightness,
|
|
966
|
-
onChange: (e) => editor.setAdjustments({ brightness: Number(e.target.value) }),
|
|
967
|
-
className: "w-full accent-indigo-500"
|
|
968
|
-
}
|
|
969
|
-
)
|
|
970
|
-
] }),
|
|
971
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
972
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
973
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Contrast" }),
|
|
974
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono", children: state.adjustments.contrast })
|
|
975
|
-
] }),
|
|
976
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
977
|
-
"input",
|
|
1425
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Histogram, { histogram: editor.histogram }),
|
|
1426
|
+
import_image_editor6.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react5.default.Fragment, { children: [
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1428
|
+
ControlSlider,
|
|
978
1429
|
{
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
onChange: (e) => editor.setAdjustments({ contrast: Number(e.target.value) }),
|
|
984
|
-
className: "w-full accent-indigo-500"
|
|
1430
|
+
spec,
|
|
1431
|
+
value: (0, import_image_editor6.readAdjustmentControls)(state.adjustments)[spec.id],
|
|
1432
|
+
disabled: spec.requiresProcess !== void 0 && legacyProcess,
|
|
1433
|
+
onChange: (v) => editor.setAdjustments({ [spec.id]: v })
|
|
985
1434
|
}
|
|
986
|
-
)
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
990
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Saturation" }),
|
|
991
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono", children: state.adjustments.saturation })
|
|
992
|
-
] }),
|
|
993
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
994
|
-
"input",
|
|
995
|
-
{
|
|
996
|
-
type: "range",
|
|
997
|
-
min: "-100",
|
|
998
|
-
max: "100",
|
|
999
|
-
value: state.adjustments.saturation,
|
|
1000
|
-
onChange: (e) => editor.setAdjustments({ saturation: Number(e.target.value) }),
|
|
1001
|
-
className: "w-full accent-indigo-500"
|
|
1002
|
-
}
|
|
1003
|
-
)
|
|
1004
|
-
] }),
|
|
1005
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1006
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
1007
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Exposure" }),
|
|
1008
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono", children: state.adjustments.exposure })
|
|
1009
|
-
] }),
|
|
1010
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1011
|
-
"input",
|
|
1012
|
-
{
|
|
1013
|
-
type: "range",
|
|
1014
|
-
min: "-100",
|
|
1015
|
-
max: "100",
|
|
1016
|
-
value: state.adjustments.exposure,
|
|
1017
|
-
onChange: (e) => editor.setAdjustments({ exposure: Number(e.target.value) }),
|
|
1018
|
-
className: "w-full accent-indigo-500"
|
|
1019
|
-
}
|
|
1020
|
-
)
|
|
1021
|
-
] }),
|
|
1022
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1023
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
1024
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Warmth / Temperature" }),
|
|
1025
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono", children: state.adjustments.temperature })
|
|
1026
|
-
] }),
|
|
1027
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1028
|
-
"input",
|
|
1029
|
-
{
|
|
1030
|
-
type: "range",
|
|
1031
|
-
min: "-100",
|
|
1032
|
-
max: "100",
|
|
1033
|
-
value: state.adjustments.temperature,
|
|
1034
|
-
onChange: (e) => editor.setAdjustments({ temperature: Number(e.target.value) }),
|
|
1035
|
-
className: "w-full accent-indigo-500"
|
|
1036
|
-
}
|
|
1037
|
-
)
|
|
1038
|
-
] }),
|
|
1039
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1040
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
1041
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Blur" }),
|
|
1042
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-mono", children: [
|
|
1043
|
-
state.adjustments.blur,
|
|
1044
|
-
"px"
|
|
1045
|
-
] })
|
|
1046
|
-
] }),
|
|
1047
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1048
|
-
"input",
|
|
1049
|
-
{
|
|
1050
|
-
type: "range",
|
|
1051
|
-
min: "0",
|
|
1052
|
-
max: "30",
|
|
1053
|
-
value: state.adjustments.blur,
|
|
1054
|
-
onChange: (e) => editor.setAdjustments({ blur: Number(e.target.value) }),
|
|
1055
|
-
className: "w-full accent-indigo-500"
|
|
1056
|
-
}
|
|
1057
|
-
)
|
|
1058
|
-
] }),
|
|
1059
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1060
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
1061
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Opacity" }),
|
|
1062
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-mono", children: [
|
|
1063
|
-
Math.round(state.adjustments.opacity * 100),
|
|
1064
|
-
"%"
|
|
1065
|
-
] })
|
|
1066
|
-
] }),
|
|
1067
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1068
|
-
"input",
|
|
1435
|
+
),
|
|
1436
|
+
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1437
|
+
"div",
|
|
1069
1438
|
{
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1439
|
+
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",
|
|
1440
|
+
"data-testid": "image-editor-process-notice",
|
|
1441
|
+
children: [
|
|
1442
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
|
|
1443
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1444
|
+
"button",
|
|
1445
|
+
{
|
|
1446
|
+
type: "button",
|
|
1447
|
+
onClick: () => editor.upgradeProcess(),
|
|
1448
|
+
className: "shrink-0 rounded bg-amber-500/20 px-2 py-0.5 hover:bg-amber-500/30",
|
|
1449
|
+
children: "Update"
|
|
1450
|
+
}
|
|
1451
|
+
)
|
|
1452
|
+
]
|
|
1077
1453
|
}
|
|
1078
1454
|
)
|
|
1079
|
-
] })
|
|
1455
|
+
] }, spec.id)),
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1457
|
+
AdjustmentLayersPanel,
|
|
1458
|
+
{
|
|
1459
|
+
controller,
|
|
1460
|
+
layers: state.adjustments.layers,
|
|
1461
|
+
histogram: editor.histogram
|
|
1462
|
+
}
|
|
1463
|
+
) })
|
|
1080
1464
|
] }),
|
|
1081
|
-
activeTab === "annotate" && /* @__PURE__ */ (0,
|
|
1082
|
-
/* @__PURE__ */ (0,
|
|
1083
|
-
/* @__PURE__ */ (0,
|
|
1465
|
+
activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
1466
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
|
|
1467
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1084
1468
|
"button",
|
|
1085
1469
|
{
|
|
1086
1470
|
type: "button",
|
|
@@ -1090,9 +1474,9 @@ var ImageEditor = ({
|
|
|
1090
1474
|
},
|
|
1091
1475
|
t
|
|
1092
1476
|
)) }),
|
|
1093
|
-
/* @__PURE__ */ (0,
|
|
1094
|
-
/* @__PURE__ */ (0,
|
|
1095
|
-
/* @__PURE__ */ (0,
|
|
1477
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-slate-400", children: "Color:" }),
|
|
1479
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1096
1480
|
"input",
|
|
1097
1481
|
{
|
|
1098
1482
|
type: "color",
|
|
@@ -1101,15 +1485,15 @@ var ImageEditor = ({
|
|
|
1101
1485
|
className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
|
|
1102
1486
|
}
|
|
1103
1487
|
),
|
|
1104
|
-
/* @__PURE__ */ (0,
|
|
1105
|
-
/* @__PURE__ */ (0,
|
|
1106
|
-
/* @__PURE__ */ (0,
|
|
1107
|
-
/* @__PURE__ */ (0,
|
|
1488
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex-1 ml-2", children: [
|
|
1489
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
|
|
1490
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Width:" }),
|
|
1491
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
|
|
1108
1492
|
strokeWidth,
|
|
1109
1493
|
"px"
|
|
1110
1494
|
] })
|
|
1111
1495
|
] }),
|
|
1112
|
-
/* @__PURE__ */ (0,
|
|
1496
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1113
1497
|
"input",
|
|
1114
1498
|
{
|
|
1115
1499
|
type: "range",
|
|
@@ -1122,10 +1506,10 @@ var ImageEditor = ({
|
|
|
1122
1506
|
)
|
|
1123
1507
|
] })
|
|
1124
1508
|
] }),
|
|
1125
|
-
/* @__PURE__ */ (0,
|
|
1126
|
-
/* @__PURE__ */ (0,
|
|
1127
|
-
/* @__PURE__ */ (0,
|
|
1128
|
-
/* @__PURE__ */ (0,
|
|
1509
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
1510
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
|
|
1511
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex gap-2", children: [
|
|
1512
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1129
1513
|
"input",
|
|
1130
1514
|
{
|
|
1131
1515
|
type: "text",
|
|
@@ -1136,7 +1520,7 @@ var ImageEditor = ({
|
|
|
1136
1520
|
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"
|
|
1137
1521
|
}
|
|
1138
1522
|
),
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
1523
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1140
1524
|
"button",
|
|
1141
1525
|
{
|
|
1142
1526
|
type: "button",
|
|
@@ -1146,14 +1530,14 @@ var ImageEditor = ({
|
|
|
1146
1530
|
}
|
|
1147
1531
|
)
|
|
1148
1532
|
] }),
|
|
1149
|
-
/* @__PURE__ */ (0,
|
|
1150
|
-
/* @__PURE__ */ (0,
|
|
1151
|
-
/* @__PURE__ */ (0,
|
|
1533
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Font Size:" }),
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
|
|
1152
1536
|
fontSize,
|
|
1153
1537
|
"px"
|
|
1154
1538
|
] })
|
|
1155
1539
|
] }),
|
|
1156
|
-
/* @__PURE__ */ (0,
|
|
1540
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1157
1541
|
"input",
|
|
1158
1542
|
{
|
|
1159
1543
|
type: "range",
|
|
@@ -1164,14 +1548,14 @@ var ImageEditor = ({
|
|
|
1164
1548
|
className: "w-full accent-indigo-500"
|
|
1165
1549
|
}
|
|
1166
1550
|
),
|
|
1167
|
-
/* @__PURE__ */ (0,
|
|
1168
|
-
/* @__PURE__ */ (0,
|
|
1169
|
-
/* @__PURE__ */ (0,
|
|
1551
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
1552
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1553
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
|
|
1170
1554
|
"Layers (",
|
|
1171
1555
|
state.annotations.length,
|
|
1172
1556
|
")"
|
|
1173
1557
|
] }),
|
|
1174
|
-
state.selectedAnnotationId && /* @__PURE__ */ (0,
|
|
1558
|
+
state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1175
1559
|
"button",
|
|
1176
1560
|
{
|
|
1177
1561
|
type: "button",
|
|
@@ -1180,7 +1564,7 @@ var ImageEditor = ({
|
|
|
1180
1564
|
children: "Delete Selected"
|
|
1181
1565
|
}
|
|
1182
1566
|
),
|
|
1183
|
-
state.annotations.length > 0 && /* @__PURE__ */ (0,
|
|
1567
|
+
state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1184
1568
|
"button",
|
|
1185
1569
|
{
|
|
1186
1570
|
type: "button",
|
|
@@ -1191,10 +1575,10 @@ var ImageEditor = ({
|
|
|
1191
1575
|
)
|
|
1192
1576
|
] })
|
|
1193
1577
|
] }),
|
|
1194
|
-
activeTab === "depth" && /* @__PURE__ */ (0,
|
|
1195
|
-
/* @__PURE__ */ (0,
|
|
1196
|
-
/* @__PURE__ */ (0,
|
|
1197
|
-
/* @__PURE__ */ (0,
|
|
1578
|
+
activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
1579
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1580
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
|
|
1581
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1198
1582
|
"button",
|
|
1199
1583
|
{
|
|
1200
1584
|
type: "button",
|
|
@@ -1204,8 +1588,8 @@ var ImageEditor = ({
|
|
|
1204
1588
|
}
|
|
1205
1589
|
)
|
|
1206
1590
|
] }),
|
|
1207
|
-
/* @__PURE__ */ (0,
|
|
1208
|
-
/* @__PURE__ */ (0,
|
|
1591
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1209
1593
|
"input",
|
|
1210
1594
|
{
|
|
1211
1595
|
type: "checkbox",
|
|
@@ -1214,12 +1598,12 @@ var ImageEditor = ({
|
|
|
1214
1598
|
className: "rounded accent-indigo-500"
|
|
1215
1599
|
}
|
|
1216
1600
|
),
|
|
1217
|
-
/* @__PURE__ */ (0,
|
|
1601
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Enable Depth / Alpha Mask" })
|
|
1218
1602
|
] }),
|
|
1219
|
-
state.depthMask.enabled && /* @__PURE__ */ (0,
|
|
1220
|
-
/* @__PURE__ */ (0,
|
|
1221
|
-
/* @__PURE__ */ (0,
|
|
1222
|
-
/* @__PURE__ */ (0,
|
|
1603
|
+
state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1604
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
1605
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
|
|
1606
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1223
1607
|
"input",
|
|
1224
1608
|
{
|
|
1225
1609
|
type: "text",
|
|
@@ -1230,8 +1614,8 @@ var ImageEditor = ({
|
|
|
1230
1614
|
}
|
|
1231
1615
|
)
|
|
1232
1616
|
] }),
|
|
1233
|
-
/* @__PURE__ */ (0,
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1617
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex gap-2", children: [
|
|
1618
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1235
1619
|
"button",
|
|
1236
1620
|
{
|
|
1237
1621
|
type: "button",
|
|
@@ -1240,7 +1624,7 @@ var ImageEditor = ({
|
|
|
1240
1624
|
children: "Threshold Mode"
|
|
1241
1625
|
}
|
|
1242
1626
|
),
|
|
1243
|
-
/* @__PURE__ */ (0,
|
|
1627
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1244
1628
|
"button",
|
|
1245
1629
|
{
|
|
1246
1630
|
type: "button",
|
|
@@ -1250,12 +1634,12 @@ var ImageEditor = ({
|
|
|
1250
1634
|
}
|
|
1251
1635
|
)
|
|
1252
1636
|
] }),
|
|
1253
|
-
/* @__PURE__ */ (0,
|
|
1254
|
-
/* @__PURE__ */ (0,
|
|
1255
|
-
/* @__PURE__ */ (0,
|
|
1256
|
-
/* @__PURE__ */ (0,
|
|
1637
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
1638
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
1639
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Depth Start (Lower):" }),
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
|
|
1257
1641
|
] }),
|
|
1258
|
-
/* @__PURE__ */ (0,
|
|
1642
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1259
1643
|
"input",
|
|
1260
1644
|
{
|
|
1261
1645
|
type: "range",
|
|
@@ -1269,12 +1653,12 @@ var ImageEditor = ({
|
|
|
1269
1653
|
}
|
|
1270
1654
|
)
|
|
1271
1655
|
] }),
|
|
1272
|
-
/* @__PURE__ */ (0,
|
|
1273
|
-
/* @__PURE__ */ (0,
|
|
1274
|
-
/* @__PURE__ */ (0,
|
|
1275
|
-
/* @__PURE__ */ (0,
|
|
1656
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
1658
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Depth Stop (Upper):" }),
|
|
1659
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
|
|
1276
1660
|
] }),
|
|
1277
|
-
/* @__PURE__ */ (0,
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1278
1662
|
"input",
|
|
1279
1663
|
{
|
|
1280
1664
|
type: "range",
|
|
@@ -1288,12 +1672,12 @@ var ImageEditor = ({
|
|
|
1288
1672
|
}
|
|
1289
1673
|
)
|
|
1290
1674
|
] }),
|
|
1291
|
-
/* @__PURE__ */ (0,
|
|
1292
|
-
/* @__PURE__ */ (0,
|
|
1293
|
-
/* @__PURE__ */ (0,
|
|
1294
|
-
/* @__PURE__ */ (0,
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
1676
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
1677
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Softness:" }),
|
|
1678
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
|
|
1295
1679
|
] }),
|
|
1296
|
-
/* @__PURE__ */ (0,
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1297
1681
|
"input",
|
|
1298
1682
|
{
|
|
1299
1683
|
type: "range",
|
|
@@ -1305,8 +1689,8 @@ var ImageEditor = ({
|
|
|
1305
1689
|
}
|
|
1306
1690
|
)
|
|
1307
1691
|
] }),
|
|
1308
|
-
/* @__PURE__ */ (0,
|
|
1309
|
-
/* @__PURE__ */ (0,
|
|
1692
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
|
|
1693
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1310
1694
|
"input",
|
|
1311
1695
|
{
|
|
1312
1696
|
type: "checkbox",
|
|
@@ -1315,52 +1699,52 @@ var ImageEditor = ({
|
|
|
1315
1699
|
className: "rounded accent-indigo-500"
|
|
1316
1700
|
}
|
|
1317
1701
|
),
|
|
1318
|
-
/* @__PURE__ */ (0,
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Invert Mask" })
|
|
1319
1703
|
] })
|
|
1320
1704
|
] })
|
|
1321
1705
|
] }),
|
|
1322
|
-
activeTab === "ai" && /* @__PURE__ */ (0,
|
|
1323
|
-
/* @__PURE__ */ (0,
|
|
1324
|
-
/* @__PURE__ */ (0,
|
|
1325
|
-
/* @__PURE__ */ (0,
|
|
1326
|
-
/* @__PURE__ */ (0,
|
|
1706
|
+
activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
1708
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1709
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) }),
|
|
1327
1711
|
"Background Removal"
|
|
1328
1712
|
] }),
|
|
1329
|
-
isRemovingBg && /* @__PURE__ */ (0,
|
|
1713
|
+
isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime5.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..." })
|
|
1330
1714
|
] }),
|
|
1331
|
-
/* @__PURE__ */ (0,
|
|
1332
|
-
/* @__PURE__ */ (0,
|
|
1715
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1333
1717
|
"button",
|
|
1334
1718
|
{
|
|
1335
1719
|
type: "button",
|
|
1336
1720
|
onClick: handleRemoveBackground,
|
|
1337
1721
|
disabled: isRemovingBg || isInpainting,
|
|
1338
1722
|
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",
|
|
1339
|
-
children: isRemovingBg ? /* @__PURE__ */ (0,
|
|
1340
|
-
/* @__PURE__ */ (0,
|
|
1723
|
+
children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
1341
1725
|
"Removing Background..."
|
|
1342
|
-
] }) : /* @__PURE__ */ (0,
|
|
1343
|
-
/* @__PURE__ */ (0,
|
|
1726
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1727
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) }),
|
|
1344
1728
|
"Remove Background"
|
|
1345
1729
|
] })
|
|
1346
1730
|
}
|
|
1347
1731
|
)
|
|
1348
1732
|
] }),
|
|
1349
|
-
/* @__PURE__ */ (0,
|
|
1350
|
-
/* @__PURE__ */ (0,
|
|
1351
|
-
/* @__PURE__ */ (0,
|
|
1352
|
-
/* @__PURE__ */ (0,
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
1354
|
-
/* @__PURE__ */ (0,
|
|
1733
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
1734
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1735
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1737
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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" }),
|
|
1738
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m14 7 3 3" })
|
|
1355
1739
|
] }),
|
|
1356
1740
|
"Generative Inpainting"
|
|
1357
1741
|
] }),
|
|
1358
|
-
isInpainting && /* @__PURE__ */ (0,
|
|
1742
|
+
isInpainting && /* @__PURE__ */ (0, import_jsx_runtime5.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..." })
|
|
1359
1743
|
] }),
|
|
1360
|
-
/* @__PURE__ */ (0,
|
|
1361
|
-
/* @__PURE__ */ (0,
|
|
1362
|
-
/* @__PURE__ */ (0,
|
|
1363
|
-
/* @__PURE__ */ (0,
|
|
1744
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
|
|
1745
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
1746
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
|
|
1747
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1364
1748
|
"textarea",
|
|
1365
1749
|
{
|
|
1366
1750
|
id: "ai-inpaint-prompt-react",
|
|
@@ -1372,10 +1756,10 @@ var ImageEditor = ({
|
|
|
1372
1756
|
}
|
|
1373
1757
|
)
|
|
1374
1758
|
] }),
|
|
1375
|
-
/* @__PURE__ */ (0,
|
|
1376
|
-
/* @__PURE__ */ (0,
|
|
1377
|
-
/* @__PURE__ */ (0,
|
|
1378
|
-
/* @__PURE__ */ (0,
|
|
1759
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1379
1763
|
"button",
|
|
1380
1764
|
{
|
|
1381
1765
|
type: "button",
|
|
@@ -1388,7 +1772,7 @@ var ImageEditor = ({
|
|
|
1388
1772
|
]
|
|
1389
1773
|
}
|
|
1390
1774
|
),
|
|
1391
|
-
/* @__PURE__ */ (0,
|
|
1775
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1392
1776
|
"button",
|
|
1393
1777
|
{
|
|
1394
1778
|
type: "button",
|
|
@@ -1403,25 +1787,25 @@ var ImageEditor = ({
|
|
|
1403
1787
|
)
|
|
1404
1788
|
] })
|
|
1405
1789
|
] }),
|
|
1406
|
-
/* @__PURE__ */ (0,
|
|
1790
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1407
1791
|
"button",
|
|
1408
1792
|
{
|
|
1409
1793
|
type: "button",
|
|
1410
1794
|
onClick: handleInpaint,
|
|
1411
1795
|
disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
|
|
1412
1796
|
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",
|
|
1413
|
-
children: isInpainting ? /* @__PURE__ */ (0,
|
|
1414
|
-
/* @__PURE__ */ (0,
|
|
1797
|
+
children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1798
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
1415
1799
|
"Generating Inpaint..."
|
|
1416
|
-
] }) : /* @__PURE__ */ (0,
|
|
1417
|
-
/* @__PURE__ */ (0,
|
|
1800
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) }),
|
|
1418
1802
|
"Apply Inpainting"
|
|
1419
1803
|
] })
|
|
1420
1804
|
}
|
|
1421
1805
|
)
|
|
1422
1806
|
] }),
|
|
1423
|
-
aiError && /* @__PURE__ */ (0,
|
|
1424
|
-
aiSuccess && /* @__PURE__ */ (0,
|
|
1807
|
+
aiError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
|
|
1808
|
+
aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
|
|
1425
1809
|
] })
|
|
1426
1810
|
] })
|
|
1427
1811
|
] })
|
|
@@ -1431,7 +1815,12 @@ var ImageEditor = ({
|
|
|
1431
1815
|
};
|
|
1432
1816
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1433
1817
|
0 && (module.exports = {
|
|
1818
|
+
AdjustmentLayersPanel,
|
|
1819
|
+
ControlSlider,
|
|
1820
|
+
CurvesEditor,
|
|
1821
|
+
Histogram,
|
|
1434
1822
|
ImageEditor,
|
|
1435
|
-
useImageEditor
|
|
1823
|
+
useImageEditor,
|
|
1824
|
+
useImageHistogram
|
|
1436
1825
|
});
|
|
1437
1826
|
//# sourceMappingURL=index.cjs.map
|