@pixerate/editor-react 0.77.0 → 0.78.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-QARGR5E5.js → chunk-2EW42UXC.js} +617 -464
- package/dist/chunk-2EW42UXC.js.map +1 -0
- package/dist/chunk-FX3EREF5.js +206 -0
- package/dist/chunk-FX3EREF5.js.map +1 -0
- package/dist/chunk-ZQZAKUUM.js +416 -0
- package/dist/chunk-ZQZAKUUM.js.map +1 -0
- package/dist/effects/index.cjs +606 -0
- package/dist/effects/index.cjs.map +1 -0
- package/dist/effects/index.d.cts +80 -0
- package/dist/effects/index.d.ts +80 -0
- package/dist/effects/index.js +16 -0
- package/dist/effects/index.js.map +1 -0
- package/dist/image-editor/index.cjs +1282 -574
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +29 -2
- package/dist/image-editor/index.d.ts +29 -2
- package/dist/image-editor/index.js +7 -1
- package/dist/index.cjs +1695 -987
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/parameters/index.js +55 -439
- package/dist/parameters/index.js.map +1 -1
- package/dist/video-editor/index.cjs +732 -17
- package/dist/video-editor/index.cjs.map +1 -1
- package/dist/video-editor/index.d.cts +31 -3
- package/dist/video-editor/index.d.ts +31 -3
- package/dist/video-editor/index.js +184 -17
- package/dist/video-editor/index.js.map +1 -1
- package/package.json +8 -3
- package/dist/chunk-QARGR5E5.js.map +0 -1
|
@@ -38,6 +38,7 @@ __export(image_editor_exports, {
|
|
|
38
38
|
FreeTransformOptionsBar: () => FreeTransformOptionsBar,
|
|
39
39
|
Histogram: () => Histogram,
|
|
40
40
|
ImageEditor: () => ImageEditor,
|
|
41
|
+
ImageProviderEffectsPanel: () => ImageProviderEffectsPanel,
|
|
41
42
|
LayerEffectsPanel: () => LayerEffectsPanel,
|
|
42
43
|
LayersPanel: () => LayersPanel,
|
|
43
44
|
PaintGradientEditor: () => PaintGradientEditor,
|
|
@@ -46,6 +47,7 @@ __export(image_editor_exports, {
|
|
|
46
47
|
ShapeOptionsBar: () => ShapeOptionsBar,
|
|
47
48
|
TypeOptionsBar: () => TypeOptionsBar,
|
|
48
49
|
useImageEditor: () => useImageEditor,
|
|
50
|
+
useImageEffectsTools: () => useImageEffectsTools,
|
|
49
51
|
useImageHistogram: () => useImageHistogram
|
|
50
52
|
});
|
|
51
53
|
module.exports = __toCommonJS(image_editor_exports);
|
|
@@ -207,10 +209,17 @@ function useImageEditor(options = {}) {
|
|
|
207
209
|
[controller, state, historyTicks, histogram]
|
|
208
210
|
);
|
|
209
211
|
}
|
|
212
|
+
function useImageEffectsTools(registry, controller, options = {}) {
|
|
213
|
+
const { id, namespace, readOnly } = options;
|
|
214
|
+
(0, import_react.useEffect)(() => {
|
|
215
|
+
if (!registry) return;
|
|
216
|
+
return registry.register((0, import_image_editor.createImageEffectsToolProvider)(controller, { id, namespace, readOnly }));
|
|
217
|
+
}, [registry, controller, id, namespace, readOnly]);
|
|
218
|
+
}
|
|
210
219
|
|
|
211
220
|
// src/image-editor/ImageEditor.tsx
|
|
212
|
-
var
|
|
213
|
-
var
|
|
221
|
+
var import_react21 = __toESM(require("react"), 1);
|
|
222
|
+
var import_image_editor18 = require("@pixerate/editor/image-editor");
|
|
214
223
|
|
|
215
224
|
// src/image-editor/ControlSlider.tsx
|
|
216
225
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
@@ -1259,17 +1268,708 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
|
|
|
1259
1268
|
] });
|
|
1260
1269
|
};
|
|
1261
1270
|
|
|
1262
|
-
// src/image-editor/
|
|
1271
|
+
// src/image-editor/ImageProviderEffectsPanel.tsx
|
|
1272
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
1273
|
+
var import_image_editor8 = require("@pixerate/editor/image-editor");
|
|
1274
|
+
|
|
1275
|
+
// src/effects/useEffects.ts
|
|
1276
|
+
var import_react7 = require("react");
|
|
1277
|
+
function useEffects(host, provider) {
|
|
1278
|
+
(0, import_react7.useEffect)(() => {
|
|
1279
|
+
if (!host || !provider) return;
|
|
1280
|
+
return host.useEffects(provider);
|
|
1281
|
+
}, [host, provider]);
|
|
1282
|
+
}
|
|
1283
|
+
function useEffectDescription(provider, effect) {
|
|
1284
|
+
const [state, setState] = (0, import_react7.useState)({ key: "", description: null, error: null });
|
|
1285
|
+
const key = provider && effect ? `${provider.id}:${effect}` : "";
|
|
1286
|
+
(0, import_react7.useEffect)(() => {
|
|
1287
|
+
if (!provider || !effect) return;
|
|
1288
|
+
let live = true;
|
|
1289
|
+
Promise.resolve().then(() => provider.describe(effect)).then(
|
|
1290
|
+
(description) => live && setState({ key, description, error: null }),
|
|
1291
|
+
(e) => live && setState({ key, description: null, error: e instanceof Error ? e.message : String(e) })
|
|
1292
|
+
);
|
|
1293
|
+
return () => {
|
|
1294
|
+
live = false;
|
|
1295
|
+
};
|
|
1296
|
+
}, [provider, effect, key]);
|
|
1297
|
+
return state.key === key ? { description: state.description, error: state.error } : { description: null, error: null };
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// src/effects/EffectThumbnail.tsx
|
|
1263
1301
|
var import_react8 = require("react");
|
|
1264
|
-
var
|
|
1302
|
+
var import_effects = require("@pixerate/editor/effects");
|
|
1303
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1304
|
+
function EffectThumbnail({ provider, effect, width = 96, height = 54, className = "" }) {
|
|
1305
|
+
const ref = (0, import_react8.useRef)(null);
|
|
1306
|
+
const [failed, setFailed] = (0, import_react8.useState)(effect.kind === "motion");
|
|
1307
|
+
(0, import_react8.useEffect)(() => {
|
|
1308
|
+
if (effect.kind === "motion") return;
|
|
1309
|
+
let live = true;
|
|
1310
|
+
(0, import_effects.renderEffectThumbnail)(provider, effect, { width, height }).then(
|
|
1311
|
+
(pixels) => {
|
|
1312
|
+
const ctx = live ? ref.current?.getContext("2d") : null;
|
|
1313
|
+
if (!ctx || typeof ImageData === "undefined") return;
|
|
1314
|
+
ctx.putImageData(new ImageData(new Uint8ClampedArray(pixels.data), pixels.width, pixels.height), 0, 0);
|
|
1315
|
+
},
|
|
1316
|
+
() => live && setFailed(true)
|
|
1317
|
+
);
|
|
1318
|
+
return () => {
|
|
1319
|
+
live = false;
|
|
1320
|
+
};
|
|
1321
|
+
}, [provider, effect, width, height]);
|
|
1322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1323
|
+
"div",
|
|
1324
|
+
{
|
|
1325
|
+
className: `relative overflow-hidden rounded border border-border bg-[repeating-conic-gradient(#8884_0_25%,transparent_0_50%)] bg-[length:12px_12px] ${className}`,
|
|
1326
|
+
style: { aspectRatio: `${width} / ${height}` },
|
|
1327
|
+
"data-effect-thumbnail": effect.id,
|
|
1328
|
+
children: failed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] text-muted-foreground", children: effect.kind === "motion" ? "Motion" : "No preview" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("canvas", { ref, width, height, className: "h-full w-full", "aria-hidden": "true" })
|
|
1329
|
+
}
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// src/effects/EffectsBrowser.tsx
|
|
1334
|
+
var import_react9 = require("react");
|
|
1335
|
+
var import_effects2 = require("@pixerate/editor/effects");
|
|
1336
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1337
|
+
function EffectsBrowser({ provider, uses, onPick, thumbnails = true, title = "Effects", className = "" }) {
|
|
1338
|
+
const [all, setAll] = (0, import_react9.useState)([]);
|
|
1339
|
+
const [query, setQuery] = (0, import_react9.useState)("");
|
|
1340
|
+
const [category, setCategory] = (0, import_react9.useState)("");
|
|
1341
|
+
const [use, setUse] = (0, import_react9.useState)("");
|
|
1342
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
1343
|
+
(0, import_react9.useEffect)(() => {
|
|
1344
|
+
if (!provider) return setAll([]);
|
|
1345
|
+
let live = true;
|
|
1346
|
+
Promise.resolve().then(() => provider.list()).then(
|
|
1347
|
+
(list) => live && (setAll(list), setError(null)),
|
|
1348
|
+
(e) => live && setError(e instanceof Error ? e.message : String(e))
|
|
1349
|
+
);
|
|
1350
|
+
return () => {
|
|
1351
|
+
live = false;
|
|
1352
|
+
};
|
|
1353
|
+
}, [provider]);
|
|
1354
|
+
const [found, setFound] = (0, import_react9.useState)([]);
|
|
1355
|
+
(0, import_react9.useEffect)(() => {
|
|
1356
|
+
if (!provider) return setFound([]);
|
|
1357
|
+
let live = true;
|
|
1358
|
+
Promise.resolve().then(() => provider.search(query, { ...category ? { category } : {}, ...use ? { use } : {} })).then((list) => live && setFound(list), () => live && setFound([]));
|
|
1359
|
+
return () => {
|
|
1360
|
+
live = false;
|
|
1361
|
+
};
|
|
1362
|
+
}, [provider, query, category, use]);
|
|
1363
|
+
const allowed = (e) => (uses ? e.kind !== "motion" || uses.includes("motion") : e.kind !== "motion") && (!uses || e.uses.some((u) => uses.includes(u)));
|
|
1364
|
+
const categories = (0, import_react9.useMemo)(() => [...new Set(all.filter(allowed).map((e) => e.category))], [all, uses]);
|
|
1365
|
+
const shown = found.filter(allowed);
|
|
1366
|
+
if (!provider)
|
|
1367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `rounded-md border border-dashed border-border p-3 text-xs text-muted-foreground ${className}`, "data-effects-browser": "", "data-effects-unavailable": "", children: "No effects provider is registered, so effects cannot be added. Effects already in the document are kept." });
|
|
1368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: `flex flex-col gap-2 ${className}`, "data-effects-browser": "", "aria-label": "Effects browser", children: [
|
|
1369
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: "text-xs font-semibold", children: title }),
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
1371
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1372
|
+
"input",
|
|
1373
|
+
{
|
|
1374
|
+
type: "search",
|
|
1375
|
+
className: "min-w-0 flex-1 rounded border border-border bg-transparent px-1.5 py-0.5 text-xs",
|
|
1376
|
+
placeholder: "Search effects",
|
|
1377
|
+
"aria-label": "Search effects",
|
|
1378
|
+
value: query,
|
|
1379
|
+
onChange: (e) => setQuery(e.currentTarget.value)
|
|
1380
|
+
}
|
|
1381
|
+
),
|
|
1382
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Category", value: category, onChange: (e) => setCategory(e.currentTarget.value), children: [
|
|
1383
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "All categories" }),
|
|
1384
|
+
categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: c, children: c }, c))
|
|
1385
|
+
] }),
|
|
1386
|
+
uses && uses.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Use", value: use, onChange: (e) => setUse(e.currentTarget.value), children: [
|
|
1387
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "Any use" }),
|
|
1388
|
+
uses.map((u) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: u, children: import_effects2.EFFECT_USE_LABELS[u] }, u))
|
|
1389
|
+
] })
|
|
1390
|
+
] }),
|
|
1391
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: error }),
|
|
1392
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "grid grid-cols-[repeat(auto-fill,minmax(6.5rem,1fr))] gap-1.5", role: "list", children: shown.map((e) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1393
|
+
"button",
|
|
1394
|
+
{
|
|
1395
|
+
type: "button",
|
|
1396
|
+
className: "flex w-full flex-col gap-1 rounded border border-transparent p-1 text-left hover:border-border focus-visible:border-border",
|
|
1397
|
+
title: e.description ?? e.name,
|
|
1398
|
+
"data-effect-id": e.id,
|
|
1399
|
+
onClick: () => onPick(e),
|
|
1400
|
+
children: [
|
|
1401
|
+
thumbnails && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EffectThumbnail, { provider, effect: e }),
|
|
1402
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate text-[11px] font-medium", children: e.name }),
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate text-[10px] text-muted-foreground", children: e.uses.map((u) => import_effects2.EFFECT_USE_LABELS[u]).join(" \xB7 ") })
|
|
1404
|
+
]
|
|
1405
|
+
}
|
|
1406
|
+
) }, e.id)) }),
|
|
1407
|
+
!shown.length && !error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects match." })
|
|
1408
|
+
] });
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
// src/effects/EffectParameters.tsx
|
|
1412
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
1413
|
+
var import_effects3 = require("@pixerate/editor/effects");
|
|
1414
|
+
var import_parameters2 = require("@pixerate/editor/parameters");
|
|
1415
|
+
|
|
1416
|
+
// src/parameters/fields.tsx
|
|
1417
|
+
var import_react10 = require("react");
|
|
1418
|
+
var import_parameters = require("@pixerate/editor/parameters");
|
|
1419
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1420
|
+
var parameterInputClass = "h-7 w-full min-w-0 rounded-md border border-input bg-background px-2 text-xs text-foreground tabular-nums focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50";
|
|
1421
|
+
var parameterButtonClass = "inline-flex h-7 items-center justify-center gap-1 rounded-md border border-input bg-background px-2 text-xs text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50";
|
|
1422
|
+
var rangeClass = "h-4 w-full min-w-0 flex-1 cursor-pointer accent-primary disabled:cursor-not-allowed disabled:opacity-50";
|
|
1423
|
+
function ParameterCommitInput({ value, onCommit, multiline, className, onKeyDown, ...rest }) {
|
|
1424
|
+
const commit = (el) => {
|
|
1425
|
+
if (el.value !== value) onCommit(el.value, el);
|
|
1426
|
+
};
|
|
1427
|
+
const keyDown = (e) => {
|
|
1428
|
+
onKeyDown?.(e);
|
|
1429
|
+
if (e.defaultPrevented) return;
|
|
1430
|
+
if (e.key === "Enter" && (!multiline || e.metaKey || e.ctrlKey)) {
|
|
1431
|
+
e.preventDefault();
|
|
1432
|
+
commit(e.currentTarget);
|
|
1433
|
+
}
|
|
1434
|
+
if (e.key === "Escape") e.currentTarget.value = value;
|
|
1435
|
+
};
|
|
1436
|
+
const props = {
|
|
1437
|
+
defaultValue: value,
|
|
1438
|
+
className: className ?? parameterInputClass,
|
|
1439
|
+
onBlur: (e) => commit(e.currentTarget),
|
|
1440
|
+
onKeyDown: keyDown,
|
|
1441
|
+
...rest
|
|
1442
|
+
};
|
|
1443
|
+
return multiline ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("textarea", { ...props, className: `${props.className} h-auto min-h-[3.5rem] py-1` }, value) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "text", ...props }, value);
|
|
1444
|
+
}
|
|
1445
|
+
var plainNumber = (field, value) => (0, import_parameters.formatParameterNumber)({ ...field, unit: void 0 }, value);
|
|
1446
|
+
function ParameterNumberInput({
|
|
1447
|
+
field,
|
|
1448
|
+
value,
|
|
1449
|
+
onChange,
|
|
1450
|
+
disabled,
|
|
1451
|
+
id,
|
|
1452
|
+
"aria-label": ariaLabel
|
|
1453
|
+
}) {
|
|
1454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1456
|
+
ParameterCommitInput,
|
|
1457
|
+
{
|
|
1458
|
+
id,
|
|
1459
|
+
inputMode: "decimal",
|
|
1460
|
+
"aria-label": ariaLabel ?? (0, import_parameters.parameterLabel)(field),
|
|
1461
|
+
value: plainNumber(field, value),
|
|
1462
|
+
disabled: disabled || field.readOnly,
|
|
1463
|
+
className: `${parameterInputClass} ${field.unit ? "pr-6" : ""}`,
|
|
1464
|
+
onCommit: (text, input) => {
|
|
1465
|
+
const n = (0, import_parameters.parseParameterNumberInput)(field, text);
|
|
1466
|
+
if (n === null || n === value) input.value = plainNumber(field, value);
|
|
1467
|
+
else onChange(n);
|
|
1468
|
+
},
|
|
1469
|
+
onKeyDown: (e) => {
|
|
1470
|
+
if (e.key !== "ArrowUp" && e.key !== "ArrowDown") return;
|
|
1471
|
+
e.preventDefault();
|
|
1472
|
+
const step = (0, import_parameters.parameterStep)(field) * (e.shiftKey ? 10 : 1);
|
|
1473
|
+
onChange((0, import_parameters.clampParameterNumber)(field, value + (e.key === "ArrowUp" ? step : -step)));
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
),
|
|
1477
|
+
field.unit && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground", children: field.unit })
|
|
1478
|
+
] });
|
|
1479
|
+
}
|
|
1480
|
+
function ParameterSlider(props) {
|
|
1481
|
+
const { field, value, onChange, onGestureStart, onGestureEnd, disabled } = props;
|
|
1482
|
+
const dragging = (0, import_react10.useRef)(false);
|
|
1483
|
+
const end = () => {
|
|
1484
|
+
if (!dragging.current) return;
|
|
1485
|
+
dragging.current = false;
|
|
1486
|
+
onGestureEnd?.();
|
|
1487
|
+
};
|
|
1488
|
+
if (!(0, import_parameters.isSliderField)(field)) return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterNumberInput, { ...props });
|
|
1489
|
+
const step = (0, import_parameters.parameterStep)(field);
|
|
1490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1491
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1492
|
+
"input",
|
|
1493
|
+
{
|
|
1494
|
+
type: "range",
|
|
1495
|
+
"aria-label": (0, import_parameters.parameterLabel)(field),
|
|
1496
|
+
"aria-valuetext": (0, import_parameters.formatParameterNumber)(field, value),
|
|
1497
|
+
min: field.min,
|
|
1498
|
+
max: field.max,
|
|
1499
|
+
step,
|
|
1500
|
+
value,
|
|
1501
|
+
disabled: disabled || field.readOnly,
|
|
1502
|
+
className: rangeClass,
|
|
1503
|
+
onPointerDown: () => {
|
|
1504
|
+
if (dragging.current) return;
|
|
1505
|
+
dragging.current = true;
|
|
1506
|
+
onGestureStart?.();
|
|
1507
|
+
},
|
|
1508
|
+
onPointerUp: end,
|
|
1509
|
+
onPointerCancel: end,
|
|
1510
|
+
onBlur: end,
|
|
1511
|
+
onChange: (e) => onChange((0, import_parameters.clampParameterNumber)(field, Number(e.target.value)))
|
|
1512
|
+
}
|
|
1513
|
+
),
|
|
1514
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterNumberInput, { ...props, id: props.id, "aria-label": `${(0, import_parameters.parameterLabel)(field)} value` }) })
|
|
1515
|
+
] });
|
|
1516
|
+
}
|
|
1517
|
+
function ParameterToggle({ field, value, onChange, disabled, id }) {
|
|
1518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1519
|
+
"button",
|
|
1520
|
+
{
|
|
1521
|
+
type: "button",
|
|
1522
|
+
role: "switch",
|
|
1523
|
+
id,
|
|
1524
|
+
"aria-checked": value,
|
|
1525
|
+
"aria-label": (0, import_parameters.parameterLabel)(field),
|
|
1526
|
+
disabled: disabled || field.readOnly,
|
|
1527
|
+
onClick: () => onChange(!value),
|
|
1528
|
+
className: `relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:opacity-50 ${value ? "bg-primary" : "bg-muted"}`,
|
|
1529
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1530
|
+
"span",
|
|
1531
|
+
{
|
|
1532
|
+
className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow transition-transform ${value ? "translate-x-4" : "translate-x-0.5"}`
|
|
1533
|
+
}
|
|
1534
|
+
)
|
|
1535
|
+
}
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
function ParameterSelect({ field, value, onChange, disabled, id }) {
|
|
1539
|
+
const options = (0, import_parameters.getChoiceOptions)(field);
|
|
1540
|
+
const off = disabled || field.readOnly;
|
|
1541
|
+
if (field.control === "segmented") {
|
|
1542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { role: "radiogroup", "aria-label": (0, import_parameters.parameterLabel)(field), className: "inline-flex flex-wrap rounded-md border border-input bg-muted p-0.5", children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1543
|
+
"button",
|
|
1544
|
+
{
|
|
1545
|
+
type: "button",
|
|
1546
|
+
role: "radio",
|
|
1547
|
+
"aria-checked": o.value === value,
|
|
1548
|
+
title: o.description,
|
|
1549
|
+
disabled: off,
|
|
1550
|
+
onClick: () => onChange(o.value),
|
|
1551
|
+
className: `rounded px-2 py-0.5 text-xs disabled:opacity-50 ${o.value === value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
1552
|
+
children: (0, import_parameters.choiceOptionLabel)(o)
|
|
1553
|
+
},
|
|
1554
|
+
String(o.value)
|
|
1555
|
+
)) });
|
|
1556
|
+
}
|
|
1557
|
+
const index = options.findIndex((o) => o.value === value);
|
|
1558
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1559
|
+
"select",
|
|
1560
|
+
{
|
|
1561
|
+
id,
|
|
1562
|
+
"aria-label": (0, import_parameters.parameterLabel)(field),
|
|
1563
|
+
value: String(index),
|
|
1564
|
+
disabled: off,
|
|
1565
|
+
onChange: (e) => {
|
|
1566
|
+
const option = options[Number(e.target.value)];
|
|
1567
|
+
if (option) onChange(option.value);
|
|
1568
|
+
},
|
|
1569
|
+
className: parameterInputClass,
|
|
1570
|
+
children: options.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: String(i), title: o.description, children: (0, import_parameters.choiceOptionLabel)(o) }, String(o.value)))
|
|
1571
|
+
}
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd, disabled, id }) {
|
|
1575
|
+
const picking = (0, import_react10.useRef)(false);
|
|
1576
|
+
const alpha = !!field.alpha;
|
|
1577
|
+
const hex = (0, import_parameters.normalizeHexColor)(value, true) ?? "#000000ff";
|
|
1578
|
+
const rgb = hex.slice(0, 7);
|
|
1579
|
+
const a = hex.slice(7);
|
|
1580
|
+
const off = disabled || field.readOnly;
|
|
1581
|
+
const start = () => {
|
|
1582
|
+
if (picking.current) return;
|
|
1583
|
+
picking.current = true;
|
|
1584
|
+
onGestureStart?.();
|
|
1585
|
+
};
|
|
1586
|
+
const end = () => {
|
|
1587
|
+
if (!picking.current) return;
|
|
1588
|
+
picking.current = false;
|
|
1589
|
+
onGestureEnd?.();
|
|
1590
|
+
};
|
|
1591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-1.5", children: [
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "relative h-7 w-9 shrink-0 overflow-hidden rounded-md border border-input bg-[repeating-conic-gradient(#d4d4d8_0_25%,#fff_0_50%)] bg-[length:8px_8px]", children: [
|
|
1594
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "absolute inset-0", style: { background: alpha ? hex : rgb } }),
|
|
1595
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1596
|
+
"input",
|
|
1597
|
+
{
|
|
1598
|
+
type: "color",
|
|
1599
|
+
"aria-label": (0, import_parameters.parameterLabel)(field),
|
|
1600
|
+
value: rgb,
|
|
1601
|
+
disabled: off,
|
|
1602
|
+
className: "absolute inset-0 h-full w-full cursor-pointer opacity-0 disabled:cursor-not-allowed",
|
|
1603
|
+
onChange: (e) => {
|
|
1604
|
+
start();
|
|
1605
|
+
onChange(alpha ? `${e.target.value}${a}` : e.target.value);
|
|
1606
|
+
},
|
|
1607
|
+
onBlur: end
|
|
1608
|
+
}
|
|
1609
|
+
)
|
|
1610
|
+
] }),
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1612
|
+
ParameterCommitInput,
|
|
1613
|
+
{
|
|
1614
|
+
id,
|
|
1615
|
+
"aria-label": `${(0, import_parameters.parameterLabel)(field)} hex`,
|
|
1616
|
+
value: alpha ? hex : rgb,
|
|
1617
|
+
disabled: off,
|
|
1618
|
+
spellCheck: false,
|
|
1619
|
+
className: `${parameterInputClass} font-mono`,
|
|
1620
|
+
onCommit: (text) => {
|
|
1621
|
+
const next = (0, import_parameters.normalizeHexColor)(text, alpha);
|
|
1622
|
+
if (next) onChange(next);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
)
|
|
1626
|
+
] }),
|
|
1627
|
+
alpha && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1628
|
+
"input",
|
|
1629
|
+
{
|
|
1630
|
+
type: "range",
|
|
1631
|
+
"aria-label": `${(0, import_parameters.parameterLabel)(field)} opacity`,
|
|
1632
|
+
min: 0,
|
|
1633
|
+
max: 255,
|
|
1634
|
+
step: 1,
|
|
1635
|
+
value: parseInt(a, 16),
|
|
1636
|
+
disabled: off,
|
|
1637
|
+
className: rangeClass,
|
|
1638
|
+
onPointerDown: start,
|
|
1639
|
+
onPointerUp: end,
|
|
1640
|
+
onPointerCancel: end,
|
|
1641
|
+
onBlur: end,
|
|
1642
|
+
onChange: (e) => onChange(`${rgb}${Number(e.target.value).toString(16).padStart(2, "0")}`)
|
|
1643
|
+
}
|
|
1644
|
+
),
|
|
1645
|
+
field.swatches && field.swatches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex flex-wrap gap-1", children: field.swatches.map((s) => {
|
|
1646
|
+
const swatch = (0, import_parameters.normalizeHexColor)(s, alpha);
|
|
1647
|
+
if (!swatch) return null;
|
|
1648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1649
|
+
"button",
|
|
1650
|
+
{
|
|
1651
|
+
type: "button",
|
|
1652
|
+
title: swatch,
|
|
1653
|
+
"aria-label": `${(0, import_parameters.parameterLabel)(field)} ${swatch}`,
|
|
1654
|
+
"aria-pressed": swatch === (alpha ? hex : rgb),
|
|
1655
|
+
disabled: off,
|
|
1656
|
+
onClick: () => onChange(swatch),
|
|
1657
|
+
className: "h-5 w-5 rounded border border-input aria-pressed:ring-1 aria-pressed:ring-primary",
|
|
1658
|
+
style: { background: swatch }
|
|
1659
|
+
},
|
|
1660
|
+
s
|
|
1661
|
+
);
|
|
1662
|
+
}) })
|
|
1663
|
+
] });
|
|
1664
|
+
}
|
|
1665
|
+
function ParameterVector({ field, value, onChange, disabled, id }) {
|
|
1666
|
+
const size = (0, import_parameters.vectorSize)(field);
|
|
1667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "grid gap-1.5", style: { gridTemplateColumns: `repeat(${size}, minmax(0, 1fr))` }, children: Array.from({ length: size }, (_, i) => {
|
|
1668
|
+
const component = (0, import_parameters.vectorComponentField)(field, i);
|
|
1669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex min-w-0 items-center gap-1", children: [
|
|
1670
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "w-3 shrink-0 text-[10px] uppercase text-muted-foreground", children: component.label }),
|
|
1671
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1672
|
+
ParameterNumberInput,
|
|
1673
|
+
{
|
|
1674
|
+
field: component,
|
|
1675
|
+
value: value[i] ?? 0,
|
|
1676
|
+
id: i === 0 ? id : void 0,
|
|
1677
|
+
"aria-label": `${(0, import_parameters.parameterLabel)(field)} ${component.label}`,
|
|
1678
|
+
disabled: disabled || field.readOnly,
|
|
1679
|
+
onChange: (n) => onChange(Array.from({ length: size }, (_2, j) => j === i ? n : value[j] ?? 0))
|
|
1680
|
+
}
|
|
1681
|
+
)
|
|
1682
|
+
] }, i);
|
|
1683
|
+
}) });
|
|
1684
|
+
}
|
|
1685
|
+
function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
|
|
1686
|
+
const off = disabled || field.readOnly;
|
|
1687
|
+
const name = (0, import_parameters.parameterLabel)(field);
|
|
1688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-1.5", children: [
|
|
1689
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1690
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex h-12 w-16 shrink-0 items-center justify-center overflow-hidden rounded-md border border-input bg-muted", children: value ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: value, alt: name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "None" }) }),
|
|
1691
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
1692
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1693
|
+
ParameterCommitInput,
|
|
1694
|
+
{
|
|
1695
|
+
id,
|
|
1696
|
+
"aria-label": `${name} URL`,
|
|
1697
|
+
placeholder: "Image URL",
|
|
1698
|
+
value: value.startsWith("data:") ? "" : value,
|
|
1699
|
+
disabled: off,
|
|
1700
|
+
onCommit: (text) => onChange(text.trim())
|
|
1701
|
+
}
|
|
1702
|
+
),
|
|
1703
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-1", children: [
|
|
1704
|
+
resolveFile && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: `${parameterButtonClass} cursor-pointer ${off ? "pointer-events-none opacity-50" : ""}`, children: [
|
|
1705
|
+
"Choose file\u2026",
|
|
1706
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1707
|
+
"input",
|
|
1708
|
+
{
|
|
1709
|
+
type: "file",
|
|
1710
|
+
className: "sr-only",
|
|
1711
|
+
accept: field.accept ?? "image/*",
|
|
1712
|
+
disabled: off,
|
|
1713
|
+
"aria-label": `${name} file`,
|
|
1714
|
+
onChange: async (e) => {
|
|
1715
|
+
const file = e.target.files?.[0];
|
|
1716
|
+
e.target.value = "";
|
|
1717
|
+
if (file) onChange(await resolveFile(file));
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
)
|
|
1721
|
+
] }),
|
|
1722
|
+
value && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: parameterButtonClass, disabled: off, onClick: () => onChange(""), "aria-label": `Clear ${name}`, children: "Clear" })
|
|
1723
|
+
] })
|
|
1724
|
+
] })
|
|
1725
|
+
] }),
|
|
1726
|
+
field.options && field.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex flex-wrap gap-1", children: field.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1727
|
+
"button",
|
|
1728
|
+
{
|
|
1729
|
+
type: "button",
|
|
1730
|
+
title: o.label ?? o.url,
|
|
1731
|
+
"aria-label": o.label ?? o.url,
|
|
1732
|
+
"aria-pressed": o.url === value,
|
|
1733
|
+
disabled: off,
|
|
1734
|
+
onClick: () => onChange(o.url),
|
|
1735
|
+
className: "h-9 w-12 overflow-hidden rounded border border-input aria-pressed:ring-2 aria-pressed:ring-primary",
|
|
1736
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: o.url, alt: "", className: "h-full w-full object-cover" })
|
|
1737
|
+
},
|
|
1738
|
+
o.url
|
|
1739
|
+
)) })
|
|
1740
|
+
] });
|
|
1741
|
+
}
|
|
1742
|
+
function ParameterText({ field, value, onChange, disabled, id }) {
|
|
1743
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1744
|
+
ParameterCommitInput,
|
|
1745
|
+
{
|
|
1746
|
+
id,
|
|
1747
|
+
"aria-label": (0, import_parameters.parameterLabel)(field),
|
|
1748
|
+
multiline: field.multiline,
|
|
1749
|
+
placeholder: field.placeholder,
|
|
1750
|
+
maxLength: field.maxLength,
|
|
1751
|
+
value,
|
|
1752
|
+
disabled: disabled || field.readOnly,
|
|
1753
|
+
onCommit: onChange
|
|
1754
|
+
}
|
|
1755
|
+
);
|
|
1756
|
+
}
|
|
1757
|
+
function ParameterFieldControl({ field, value, onChange, resolveFile, ...rest }) {
|
|
1758
|
+
const set = onChange;
|
|
1759
|
+
switch (field.type) {
|
|
1760
|
+
case "number":
|
|
1761
|
+
case "int":
|
|
1762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterSlider, { field, value, onChange: set, ...rest });
|
|
1763
|
+
case "boolean":
|
|
1764
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterToggle, { field, value, onChange: set, ...rest });
|
|
1765
|
+
case "choice":
|
|
1766
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterSelect, { field, value, onChange: set, ...rest });
|
|
1767
|
+
case "color":
|
|
1768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterColor, { field, value, onChange: set, ...rest });
|
|
1769
|
+
case "vector":
|
|
1770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterVector, { field, value, onChange: set, ...rest });
|
|
1771
|
+
case "image":
|
|
1772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterImage, { field, value, onChange: set, resolveFile, ...rest });
|
|
1773
|
+
case "text":
|
|
1774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ParameterText, { field, value, onChange: set, ...rest });
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// src/effects/EffectParameters.tsx
|
|
1779
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1780
|
+
function EffectParameters({ description, values, onChange, onReset, keyframed, onPreset, disabled = false, className = "" }) {
|
|
1781
|
+
const fields = (0, import_react11.useMemo)(() => (0, import_effects3.effectParameterFields)(description), [description]);
|
|
1782
|
+
const idBase = (0, import_react11.useId)();
|
|
1783
|
+
const gesture = import_react11.default.useRef(null);
|
|
1784
|
+
const count = import_react11.default.useRef(0);
|
|
1785
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `space-y-2 ${className}`, "data-effect-parameters": description.id, children: [
|
|
1786
|
+
onPreset && description.presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1787
|
+
"select",
|
|
1788
|
+
{
|
|
1789
|
+
className: "w-full rounded border border-border bg-transparent px-1 py-0.5 text-xs",
|
|
1790
|
+
"aria-label": `${description.name} presets`,
|
|
1791
|
+
value: "",
|
|
1792
|
+
disabled,
|
|
1793
|
+
onChange: (e) => {
|
|
1794
|
+
const preset = description.presets.find((p) => p.name === e.currentTarget.value);
|
|
1795
|
+
if (preset) onPreset({ ...description.defaults, ...preset.values });
|
|
1796
|
+
},
|
|
1797
|
+
children: [
|
|
1798
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "Presets\u2026" }),
|
|
1799
|
+
description.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: p.name, children: p.name }, p.name))
|
|
1800
|
+
]
|
|
1801
|
+
}
|
|
1802
|
+
),
|
|
1803
|
+
fields.map((field) => {
|
|
1804
|
+
const label = (0, import_parameters2.parameterLabel)(field);
|
|
1805
|
+
const inputId = `${idBase}-${field.id}`;
|
|
1806
|
+
const keyed = keyframed?.has(field.id) ?? false;
|
|
1807
|
+
const value = (0, import_effects3.effectFieldValue)(field, values[field.id]);
|
|
1808
|
+
const changed = !keyed && !(0, import_parameters2.parameterValuesEqual)(value, field.default);
|
|
1809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-1", "data-effect-control": field.id, children: [
|
|
1810
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1811
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { htmlFor: inputId, className: "min-w-0 flex-1 truncate text-xs font-medium", title: field.description, children: label }),
|
|
1812
|
+
keyed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "keyframed" }),
|
|
1813
|
+
onReset && changed && !disabled && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rounded px-1 text-[11px] text-muted-foreground hover:text-foreground", "aria-label": `Reset ${label}`, onClick: () => onReset(field.id), children: "\u21BA" })
|
|
1814
|
+
] }),
|
|
1815
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1816
|
+
ParameterFieldControl,
|
|
1817
|
+
{
|
|
1818
|
+
field,
|
|
1819
|
+
value,
|
|
1820
|
+
id: inputId,
|
|
1821
|
+
disabled: disabled || keyed,
|
|
1822
|
+
onChange: (v) => onChange(field.id, v, gesture.current),
|
|
1823
|
+
onGestureStart: () => gesture.current = `${idBase}:${field.id}:${++count.current}`,
|
|
1824
|
+
onGestureEnd: () => gesture.current = null
|
|
1825
|
+
}
|
|
1826
|
+
)
|
|
1827
|
+
] }, field.id);
|
|
1828
|
+
}),
|
|
1829
|
+
!fields.length && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No controls." })
|
|
1830
|
+
] });
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
// src/image-editor/ImageProviderEffectsPanel.tsx
|
|
1834
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1835
|
+
var btn = "rounded border border-slate-700 px-1.5 py-0.5 text-[11px] text-slate-300 hover:text-white disabled:opacity-40";
|
|
1836
|
+
function Controls({
|
|
1837
|
+
provider,
|
|
1838
|
+
effect,
|
|
1839
|
+
name,
|
|
1840
|
+
values,
|
|
1841
|
+
onChange,
|
|
1842
|
+
onPreset
|
|
1843
|
+
}) {
|
|
1844
|
+
const { description, error } = useEffectDescription(provider, effect);
|
|
1845
|
+
if (!provider) return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { className: "text-[11px] text-slate-400", children: [
|
|
1846
|
+
'No effects provider: "',
|
|
1847
|
+
name ?? effect,
|
|
1848
|
+
'" is kept but not drawn.'
|
|
1849
|
+
] });
|
|
1850
|
+
if (error) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-[11px] text-amber-400", children: error });
|
|
1851
|
+
if (!description) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-[11px] text-slate-400", children: "Loading\u2026" });
|
|
1852
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(EffectParameters, { description, values, onChange, onReset: (k) => onChange(k, description.defaults[k], null), onPreset });
|
|
1853
|
+
}
|
|
1854
|
+
function ImageProviderEffectsPanel({ controller, className = "" }) {
|
|
1855
|
+
const [, setTick] = (0, import_react12.useState)(0);
|
|
1856
|
+
(0, import_react12.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
1857
|
+
const [browse, setBrowse] = (0, import_react12.useState)(null);
|
|
1858
|
+
const [message, setMessage] = (0, import_react12.useState)(null);
|
|
1859
|
+
const [open, setOpen] = (0, import_react12.useState)(null);
|
|
1860
|
+
const provider = controller.effectsProvider;
|
|
1861
|
+
const state = controller.getState();
|
|
1862
|
+
const layer = state.activeLayerId ? (0, import_image_editor8.findLayer)(state.layers, state.activeLayerId)?.layer ?? null : null;
|
|
1863
|
+
const run = (work) => {
|
|
1864
|
+
setMessage(null);
|
|
1865
|
+
Promise.resolve().then(work).catch((e) => setMessage(e instanceof Error ? e.message : String(e)));
|
|
1866
|
+
};
|
|
1867
|
+
const drags = import_react12.default.useRef(/* @__PURE__ */ new Set());
|
|
1868
|
+
const commit = (gesture) => {
|
|
1869
|
+
if (gesture) {
|
|
1870
|
+
if (!drags.current.has(gesture)) {
|
|
1871
|
+
drags.current.add(gesture);
|
|
1872
|
+
return true;
|
|
1873
|
+
}
|
|
1874
|
+
return false;
|
|
1875
|
+
}
|
|
1876
|
+
return true;
|
|
1877
|
+
};
|
|
1878
|
+
const filters = layer?.type === "smart" ? (layer.smartFilters?.filters ?? []).filter((f) => f.kind === "effect") : [];
|
|
1879
|
+
const generator = layer?.type === "pixel" ? layer.generator : void 0;
|
|
1880
|
+
const canFilter = !!layer && layer.type !== "adjustment" && layer.type !== "annotation";
|
|
1881
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Provider effects", "data-image-provider-effects": "", children: [
|
|
1882
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "flex-1 font-semibold uppercase tracking-wider text-[11px] text-slate-200", children: "Effects" }),
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: btn, disabled: !provider || !canFilter, "aria-pressed": browse === "filter", onClick: () => setBrowse(browse === "filter" ? null : "filter"), children: "Apply effect\u2026" }),
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: btn, disabled: !provider, "aria-pressed": browse === "layer", onClick: () => setBrowse(browse === "layer" ? null : "layer"), children: "Effect layer\u2026" })
|
|
1886
|
+
] }),
|
|
1887
|
+
!provider && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-[11px] text-slate-400", children: "No effects provider is registered. Effects in the document are kept." }),
|
|
1888
|
+
browse === "filter" && layer && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(EffectsBrowser, { provider, uses: ["filter"], title: "Filters", onPick: (e) => (setBrowse(null), run(() => controller.applyEffectFilter(layer.id, e.id))) }),
|
|
1889
|
+
browse === "layer" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(EffectsBrowser, { provider, uses: ["generator", "overlay", "title"], title: "Generators and overlays", onPick: (e) => (setBrowse(null), run(() => controller.addEffectLayer(e.id))) }),
|
|
1890
|
+
generator && layer && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "space-y-1", "data-effect-part": "generator", children: [
|
|
1891
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1892
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "flex-1 font-medium text-slate-200", children: generator.name ?? generator.effect }),
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: btn, title: "Keep the pixels as a plain layer", onClick: () => run(() => controller.rasterizeEffectLayer(layer.id)), children: "Rasterize" })
|
|
1894
|
+
] }),
|
|
1895
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1896
|
+
Controls,
|
|
1897
|
+
{
|
|
1898
|
+
provider,
|
|
1899
|
+
effect: generator.effect,
|
|
1900
|
+
name: generator.name,
|
|
1901
|
+
values: generator.values,
|
|
1902
|
+
onChange: (k, v, gesture) => run(() => controller.updateEffectLayer(layer.id, { values: { [k]: v } }, commit(gesture))),
|
|
1903
|
+
onPreset: (values) => run(() => controller.updateEffectLayer(layer.id, { values }))
|
|
1904
|
+
}
|
|
1905
|
+
)
|
|
1906
|
+
] }),
|
|
1907
|
+
filters.length > 0 && layer && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ol", { className: "space-y-1", "data-effect-part": "filters", children: filters.map((f) => {
|
|
1908
|
+
const label = f.kind === "effect" ? f.name ?? f.effect : f.kind;
|
|
1909
|
+
const all = layer.smartFilters.filters;
|
|
1910
|
+
const index = all.indexOf(f);
|
|
1911
|
+
if (f.kind !== "effect") return null;
|
|
1912
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("li", { className: "rounded border border-slate-700 p-1", "data-smart-effect": f.id, children: [
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1914
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "checkbox", checked: f.enabled, "aria-label": `${label} on`, onChange: (e) => {
|
|
1915
|
+
const enabled = e.currentTarget.checked;
|
|
1916
|
+
run(() => controller.updateEffectFilter(layer.id, f.id, { enabled }));
|
|
1917
|
+
} }),
|
|
1918
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "min-w-0 flex-1 truncate text-left text-slate-200", "aria-expanded": open === f.id, onClick: () => setOpen(open === f.id ? null : f.id), children: label }),
|
|
1919
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: btn, disabled: index === all.length - 1, "aria-label": "Move up", onClick: () => run(() => controller.updateEffectFilter(layer.id, f.id, { index: index + 1 })), children: "\u2191" }),
|
|
1920
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: btn, disabled: index === 0, "aria-label": "Move down", onClick: () => run(() => controller.updateEffectFilter(layer.id, f.id, { index: index - 1 })), children: "\u2193" }),
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: btn, "aria-label": `Remove ${label}`, onClick: () => run(() => controller.removeSmartFilter(layer.id, f.id)), children: "\u2715" })
|
|
1922
|
+
] }),
|
|
1923
|
+
open === f.id && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mt-1 space-y-2", children: [
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1925
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-14 text-[11px] text-slate-300", children: "Opacity" }),
|
|
1926
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1927
|
+
"input",
|
|
1928
|
+
{
|
|
1929
|
+
type: "range",
|
|
1930
|
+
min: 0,
|
|
1931
|
+
max: 1,
|
|
1932
|
+
step: 0.01,
|
|
1933
|
+
className: "flex-1",
|
|
1934
|
+
value: f.opacity,
|
|
1935
|
+
"aria-label": `${label} opacity`,
|
|
1936
|
+
onChange: (e) => {
|
|
1937
|
+
const opacity = Number(e.currentTarget.value);
|
|
1938
|
+
run(() => controller.updateEffectFilter(layer.id, f.id, { opacity }));
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
)
|
|
1942
|
+
] }),
|
|
1943
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1944
|
+
Controls,
|
|
1945
|
+
{
|
|
1946
|
+
provider,
|
|
1947
|
+
effect: f.effect,
|
|
1948
|
+
name: f.name,
|
|
1949
|
+
values: f.values,
|
|
1950
|
+
onChange: (k, v, gesture) => run(() => controller.updateEffectFilter(layer.id, f.id, { values: { [k]: v } }, commit(gesture))),
|
|
1951
|
+
onPreset: (values) => run(() => controller.updateEffectFilter(layer.id, f.id, { values }))
|
|
1952
|
+
}
|
|
1953
|
+
)
|
|
1954
|
+
] })
|
|
1955
|
+
] }, f.id);
|
|
1956
|
+
}) }),
|
|
1957
|
+
!layer && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-[11px] text-slate-400", children: "Select a layer to apply effects to it." }),
|
|
1958
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { role: "alert", className: "text-[11px] text-rose-400", children: message })
|
|
1959
|
+
] });
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/image-editor/BrushOptionsBar.tsx
|
|
1963
|
+
var import_react14 = require("react");
|
|
1265
1964
|
var import_image_editor10 = require("@pixerate/editor/image-editor");
|
|
1965
|
+
var import_image_editor11 = require("@pixerate/editor/image-editor");
|
|
1266
1966
|
|
|
1267
1967
|
// src/image-editor/PaintGradientEditor.tsx
|
|
1268
|
-
var
|
|
1968
|
+
var import_image_editor9 = require("@pixerate/editor/image-editor");
|
|
1269
1969
|
|
|
1270
1970
|
// src/paint-editor/PaintGradientEditorView.tsx
|
|
1271
|
-
var
|
|
1272
|
-
var
|
|
1971
|
+
var import_react13 = require("react");
|
|
1972
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1273
1973
|
var button2 = "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40";
|
|
1274
1974
|
var select = "rounded bg-slate-800 px-1 py-0.5 text-[11px]";
|
|
1275
1975
|
var number = "w-16 rounded bg-slate-800 px-1 py-0.5 text-[11px]";
|
|
@@ -1290,7 +1990,7 @@ var PaintGradientEditorView = ({ value, onChange, colors, className, kit }) => {
|
|
|
1290
1990
|
reversePaintGradient,
|
|
1291
1991
|
updatePaintGradientStop
|
|
1292
1992
|
} = kit;
|
|
1293
|
-
const [selected, setSelected] = (0,
|
|
1993
|
+
const [selected, setSelected] = (0, import_react13.useState)(0);
|
|
1294
1994
|
const sel = Math.min(selected, value.stops.length - 1);
|
|
1295
1995
|
const stop = value.stops[sel];
|
|
1296
1996
|
const map = value.map;
|
|
@@ -1300,15 +2000,15 @@ var PaintGradientEditorView = ({ value, onChange, colors, className, kit }) => {
|
|
|
1300
2000
|
setSelected(r.index);
|
|
1301
2001
|
onChange(r.paint);
|
|
1302
2002
|
};
|
|
1303
|
-
return /* @__PURE__ */ (0,
|
|
1304
|
-
/* @__PURE__ */ (0,
|
|
1305
|
-
/* @__PURE__ */ (0,
|
|
1306
|
-
/* @__PURE__ */ (0,
|
|
1307
|
-
PAINT_GRADIENT_PRESETS.map((p, i) => /* @__PURE__ */ (0,
|
|
2003
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex flex-col gap-1.5 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "paint-gradient-editor", "aria-label": "Gradient paint", children: [
|
|
2004
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("select", { "aria-label": "Gradient preset", className: select, value: "", onChange: (e) => e.target.value && (setSelected(0), onChange(PAINT_GRADIENT_PRESETS[Number(e.target.value)].paint)), children: [
|
|
2006
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "", children: "Presets\u2026" }),
|
|
2007
|
+
PAINT_GRADIENT_PRESETS.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: i, children: p.name }, p.name))
|
|
1308
2008
|
] }),
|
|
1309
|
-
/* @__PURE__ */ (0,
|
|
2009
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: button2, onClick: () => onChange(reversePaintGradient(value)), children: "Reverse" })
|
|
1310
2010
|
] }),
|
|
1311
|
-
/* @__PURE__ */ (0,
|
|
2011
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1312
2012
|
"div",
|
|
1313
2013
|
{
|
|
1314
2014
|
role: "slider",
|
|
@@ -1330,7 +2030,7 @@ var PaintGradientEditorView = ({ value, onChange, colors, className, kit }) => {
|
|
|
1330
2030
|
}
|
|
1331
2031
|
}
|
|
1332
2032
|
),
|
|
1333
|
-
/* @__PURE__ */ (0,
|
|
2033
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative h-4", "aria-label": "Stops", children: value.stops.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1334
2034
|
"button",
|
|
1335
2035
|
{
|
|
1336
2036
|
type: "button",
|
|
@@ -1342,64 +2042,64 @@ var PaintGradientEditorView = ({ value, onChange, colors, className, kit }) => {
|
|
|
1342
2042
|
},
|
|
1343
2043
|
i
|
|
1344
2044
|
)) }),
|
|
1345
|
-
/* @__PURE__ */ (0,
|
|
1346
|
-
/* @__PURE__ */ (0,
|
|
1347
|
-
/* @__PURE__ */ (0,
|
|
1348
|
-
/* @__PURE__ */ (0,
|
|
1349
|
-
/* @__PURE__ */ (0,
|
|
2045
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-1", "data-testid": "paint-gradient-stop", children: [
|
|
2046
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("select", { "aria-label": "Stop colour source", className: select, value: stop.color === "paint" || stop.color === "secondary" ? stop.color : "color", onChange: (e) => patchStop({ color: e.target.value === "color" ? stopHex(stop.color) : e.target.value }), children: [
|
|
2047
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "color", children: "Colour" }),
|
|
2048
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "paint", children: "Paint colour" }),
|
|
2049
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "secondary", children: "Second colour" })
|
|
1350
2050
|
] }),
|
|
1351
|
-
stop.color !== "paint" && stop.color !== "secondary" && /* @__PURE__ */ (0,
|
|
1352
|
-
/* @__PURE__ */ (0,
|
|
2051
|
+
stop.color !== "paint" && stop.color !== "secondary" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "color", "aria-label": "Stop colour", value: stop.color, onChange: (e) => patchStop({ color: e.target.value }), className: "h-6 w-8 rounded bg-transparent" }),
|
|
2052
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1353
2053
|
"At",
|
|
1354
|
-
/* @__PURE__ */ (0,
|
|
2054
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", "aria-label": "Stop position", min: 0, max: 100, step: 1, value: pct(stop.offset), onChange: (e) => patchStop({ offset: Number(e.target.value) / 100 }), className: number }),
|
|
1355
2055
|
"%"
|
|
1356
2056
|
] }),
|
|
1357
|
-
/* @__PURE__ */ (0,
|
|
2057
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1358
2058
|
"Opacity",
|
|
1359
|
-
/* @__PURE__ */ (0,
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", "aria-label": "Stop opacity", min: 0, max: 100, step: 5, value: pct(stop.opacity ?? 1), onChange: (e) => patchStop({ opacity: Number(e.target.value) / 100 }), className: number }),
|
|
1360
2060
|
"%"
|
|
1361
2061
|
] }),
|
|
1362
|
-
sel < value.stops.length - 1 && /* @__PURE__ */ (0,
|
|
2062
|
+
sel < value.stops.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
1363
2063
|
"Midpoint",
|
|
1364
|
-
/* @__PURE__ */ (0,
|
|
2064
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", "aria-label": "Stop midpoint", min: 5, max: 95, step: 1, value: pct(stop.midpoint ?? 0.5), onChange: (e) => patchStop({ midpoint: Number(e.target.value) / 100 }), className: number }),
|
|
1365
2065
|
"%"
|
|
1366
2066
|
] }),
|
|
1367
|
-
/* @__PURE__ */ (0,
|
|
2067
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: button2, disabled: value.stops.length <= 2, onClick: () => (setSelected(Math.max(0, sel - 1)), onChange(removePaintGradientStop(value, sel))), children: "Remove stop" })
|
|
1368
2068
|
] }),
|
|
1369
|
-
/* @__PURE__ */ (0,
|
|
1370
|
-
/* @__PURE__ */ (0,
|
|
1371
|
-
map.by === "distance" && /* @__PURE__ */ (0,
|
|
1372
|
-
/* @__PURE__ */ (0,
|
|
1373
|
-
/* @__PURE__ */ (0,
|
|
1374
|
-
/* @__PURE__ */ (0,
|
|
1375
|
-
/* @__PURE__ */ (0,
|
|
2069
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-1", "data-testid": "paint-gradient-mapping", children: [
|
|
2070
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("select", { "aria-label": "Gradient follows", className: select, value: map.by, onChange: (e) => onChange({ ...value, map: paintGradientMappingFor(e.target.value, map) }), children: PAINT_GRADIENT_MAPPINGS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: m, children: PAINT_GRADIENT_MAPPING_LABELS[m] }, m)) }),
|
|
2071
|
+
map.by === "distance" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2072
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", "aria-label": "Gradient length", min: 1, max: 1e5, value: map.length, onChange: (e) => onChange({ ...value, map: { ...map, length: Math.max(1, Number(e.target.value) || 1) } }), className: number }),
|
|
2073
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("select", { "aria-label": "Gradient length unit", className: select, value: map.unit ?? "px", onChange: (e) => onChange({ ...value, map: { ...map, unit: e.target.value } }), children: [
|
|
2074
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "px", children: "px" }),
|
|
2075
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "dabs", children: "dabs" })
|
|
1376
2076
|
] })
|
|
1377
2077
|
] }),
|
|
1378
|
-
map.by === "time" && /* @__PURE__ */ (0,
|
|
1379
|
-
map.by === "random" && /* @__PURE__ */ (0,
|
|
1380
|
-
(map.by === "distance" || map.by === "time") && /* @__PURE__ */ (0,
|
|
2078
|
+
map.by === "time" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", "aria-label": "Gradient duration", min: 1, max: 6e5, value: map.duration, onChange: (e) => onChange({ ...value, map: { ...map, duration: Math.max(1, Number(e.target.value) || 1) } }), className: number }),
|
|
2079
|
+
map.by === "random" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", "aria-label": "Dabs per pick", min: 1, max: 500, value: map.every ?? 1, onChange: (e) => onChange({ ...value, map: { ...map, every: Math.max(1, Math.round(Number(e.target.value) || 1)) } }), className: number }),
|
|
2080
|
+
(map.by === "distance" || map.by === "time") && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("select", { "aria-label": "Gradient repeat", className: select, value: map.repeat ?? "clamp", onChange: (e) => onChange({ ...value, map: { ...map, repeat: e.target.value } }), children: PAINT_GRADIENT_REPEATS.map((r) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: r, children: PAINT_GRADIENT_REPEAT_LABELS[r] }, r)) })
|
|
1381
2081
|
] }),
|
|
1382
|
-
/* @__PURE__ */ (0,
|
|
1383
|
-
/* @__PURE__ */ (0,
|
|
1384
|
-
/* @__PURE__ */ (0,
|
|
2082
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
2083
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("select", { "aria-label": "Gradient mixing", className: select, value: value.space, onChange: (e) => onChange({ ...value, space: e.target.value }), children: PAINT_GRADIENT_SPACES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: s, children: PAINT_GRADIENT_SPACE_LABELS[s] }, s)) }),
|
|
2084
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex flex-1 items-center gap-1", children: [
|
|
1385
2085
|
"Softness",
|
|
1386
|
-
/* @__PURE__ */ (0,
|
|
2086
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "range", "aria-label": "Gradient softness", min: 0, max: 1, step: 0.05, value: value.softness ?? 1, onChange: (e) => onChange({ ...value, softness: Number(e.target.value) }), className: "flex-1 accent-indigo-500" })
|
|
1387
2087
|
] })
|
|
1388
2088
|
] })
|
|
1389
2089
|
] });
|
|
1390
2090
|
};
|
|
1391
2091
|
|
|
1392
2092
|
// src/image-editor/PaintGradientEditor.tsx
|
|
1393
|
-
var
|
|
1394
|
-
var PaintGradientEditor = (props) => /* @__PURE__ */ (0,
|
|
2093
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2094
|
+
var PaintGradientEditor = (props) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PaintGradientEditorView, { ...props, kit: import_image_editor9.PAINT_GRADIENT_KIT });
|
|
1395
2095
|
|
|
1396
2096
|
// src/image-editor/BrushOptionsBar.tsx
|
|
1397
|
-
var
|
|
2097
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1398
2098
|
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"}`;
|
|
1399
2099
|
var BrushOptionsBar = ({ controller, className }) => {
|
|
1400
|
-
const [, setTick] = (0,
|
|
1401
|
-
(0,
|
|
1402
|
-
const [error, setError] = (0,
|
|
2100
|
+
const [, setTick] = (0, import_react14.useState)(0);
|
|
2101
|
+
(0, import_react14.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
2102
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1403
2103
|
const state = controller.getState();
|
|
1404
2104
|
const { brush, foreground, background, mixer, mixerLoad, retouch, cloneSource, paint } = state.paint;
|
|
1405
2105
|
const tool = state.activeTool;
|
|
@@ -1411,8 +2111,8 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1411
2111
|
setError(err instanceof Error ? err.message : String(err));
|
|
1412
2112
|
}
|
|
1413
2113
|
};
|
|
1414
|
-
return /* @__PURE__ */ (0,
|
|
1415
|
-
/* @__PURE__ */ (0,
|
|
2114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
|
|
2115
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor10.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1416
2116
|
"button",
|
|
1417
2117
|
{
|
|
1418
2118
|
type: "button",
|
|
@@ -1424,9 +2124,9 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1424
2124
|
},
|
|
1425
2125
|
t.id
|
|
1426
2126
|
)) }),
|
|
1427
|
-
/* @__PURE__ */ (0,
|
|
1428
|
-
/* @__PURE__ */ (0,
|
|
1429
|
-
/* @__PURE__ */ (0,
|
|
2127
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
|
|
2128
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2129
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1430
2130
|
"input",
|
|
1431
2131
|
{
|
|
1432
2132
|
type: "color",
|
|
@@ -1436,10 +2136,10 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1436
2136
|
className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
|
|
1437
2137
|
}
|
|
1438
2138
|
),
|
|
1439
|
-
/* @__PURE__ */ (0,
|
|
2139
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-400", children: "FG" })
|
|
1440
2140
|
] }),
|
|
1441
|
-
/* @__PURE__ */ (0,
|
|
1442
|
-
/* @__PURE__ */ (0,
|
|
2141
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2142
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1443
2143
|
"input",
|
|
1444
2144
|
{
|
|
1445
2145
|
type: "color",
|
|
@@ -1449,24 +2149,24 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1449
2149
|
className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
|
|
1450
2150
|
}
|
|
1451
2151
|
),
|
|
1452
|
-
/* @__PURE__ */ (0,
|
|
2152
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-400", children: "BG" })
|
|
1453
2153
|
] }),
|
|
1454
|
-
/* @__PURE__ */ (0,
|
|
1455
|
-
/* @__PURE__ */ (0,
|
|
1456
|
-
state.activeTool === "brush" && /* @__PURE__ */ (0,
|
|
2154
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
|
|
2155
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" }),
|
|
2156
|
+
state.activeTool === "brush" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1457
2157
|
"button",
|
|
1458
2158
|
{
|
|
1459
2159
|
type: "button",
|
|
1460
2160
|
"aria-pressed": paint.type === "gradient",
|
|
1461
2161
|
title: "Gradient paint: the brush changes colour as the stroke goes",
|
|
1462
2162
|
className: chip(paint.type === "gradient"),
|
|
1463
|
-
onClick: () => attempt(() => controller.setPaintOptions(paint.type === "gradient" ? { foreground } : { paint:
|
|
2163
|
+
onClick: () => attempt(() => controller.setPaintOptions(paint.type === "gradient" ? { foreground } : { paint: import_image_editor11.DEFAULT_PAINT_GRADIENT })),
|
|
1464
2164
|
children: "Gradient"
|
|
1465
2165
|
}
|
|
1466
2166
|
)
|
|
1467
2167
|
] }),
|
|
1468
|
-
state.activeTool === "brush" && paint.type === "gradient" && /* @__PURE__ */ (0,
|
|
1469
|
-
|
|
2168
|
+
state.activeTool === "brush" && paint.type === "gradient" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PaintGradientEditor, { value: paint, colors: { paint: foreground, secondary: background }, onChange: (g) => attempt(() => controller.setPaintOptions({ paint: g })) }),
|
|
2169
|
+
import_image_editor10.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1470
2170
|
ControlSlider,
|
|
1471
2171
|
{
|
|
1472
2172
|
spec,
|
|
@@ -1475,21 +2175,21 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1475
2175
|
},
|
|
1476
2176
|
spec.id
|
|
1477
2177
|
)),
|
|
1478
|
-
state.activeTool === "mixer" && /* @__PURE__ */ (0,
|
|
1479
|
-
/* @__PURE__ */ (0,
|
|
1480
|
-
/* @__PURE__ */ (0,
|
|
2178
|
+
state.activeTool === "mixer" && /* @__PURE__ */ (0, import_jsx_runtime14.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: [
|
|
2179
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1481
2181
|
"span",
|
|
1482
2182
|
{
|
|
1483
2183
|
"aria-label": "Brush load",
|
|
1484
|
-
title: mixerLoad.reservoir ? `Loaded ${(0,
|
|
2184
|
+
title: mixerLoad.reservoir ? `Loaded ${(0, import_image_editor10.rgbUnitToHex)(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
|
|
1485
2185
|
className: "h-6 w-6 rounded border border-slate-700",
|
|
1486
|
-
style: { background: mixerLoad.reservoir ? (0,
|
|
2186
|
+
style: { background: mixerLoad.reservoir ? (0, import_image_editor10.rgbUnitToHex)(mixerLoad.reservoir) : "transparent" }
|
|
1487
2187
|
}
|
|
1488
2188
|
),
|
|
1489
|
-
/* @__PURE__ */ (0,
|
|
1490
|
-
/* @__PURE__ */ (0,
|
|
2189
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
|
|
2190
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
|
|
1491
2191
|
] }),
|
|
1492
|
-
/* @__PURE__ */ (0,
|
|
2192
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: import_image_editor10.MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1493
2193
|
"button",
|
|
1494
2194
|
{
|
|
1495
2195
|
type: "button",
|
|
@@ -1501,10 +2201,10 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1501
2201
|
},
|
|
1502
2202
|
m.id
|
|
1503
2203
|
)) }),
|
|
1504
|
-
|
|
1505
|
-
/* @__PURE__ */ (0,
|
|
1506
|
-
/* @__PURE__ */ (0,
|
|
1507
|
-
/* @__PURE__ */ (0,
|
|
2204
|
+
import_image_editor10.MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
|
|
2205
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
|
|
2206
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
2207
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1508
2208
|
"input",
|
|
1509
2209
|
{
|
|
1510
2210
|
type: "checkbox",
|
|
@@ -1516,8 +2216,8 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1516
2216
|
),
|
|
1517
2217
|
"Load each stroke"
|
|
1518
2218
|
] }),
|
|
1519
|
-
/* @__PURE__ */ (0,
|
|
1520
|
-
/* @__PURE__ */ (0,
|
|
2219
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
2220
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1521
2221
|
"input",
|
|
1522
2222
|
{
|
|
1523
2223
|
type: "checkbox",
|
|
@@ -1531,29 +2231,29 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1531
2231
|
] })
|
|
1532
2232
|
] })
|
|
1533
2233
|
] }),
|
|
1534
|
-
(0,
|
|
1535
|
-
(tool === "clone" || tool === "heal") && /* @__PURE__ */ (0,
|
|
1536
|
-
/* @__PURE__ */ (0,
|
|
1537
|
-
cloneSource && /* @__PURE__ */ (0,
|
|
2234
|
+
(0, import_image_editor10.isRetouchPaintTool)(tool) && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2 border-t border-slate-800 pt-2", role: "group", "aria-label": "Retouch options", "data-testid": "retouch-options", children: [
|
|
2235
|
+
(tool === "clone" || tool === "heal") && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-400", "data-testid": "clone-source", children: (0, import_image_editor10.cloneSourceLabel)(controller) }),
|
|
2237
|
+
cloneSource && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", title: "Forget the source point", className: chip(false), onClick: () => controller.setCloneSource(null), children: "Clear source" })
|
|
1538
2238
|
] }),
|
|
1539
|
-
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
1541
|
-
choice.options.map((o) => /* @__PURE__ */ (0,
|
|
2239
|
+
import_image_editor10.RETOUCH_CHOICES.filter((c) => c.tools.includes(tool)).map((choice) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": choice.label, children: [
|
|
2240
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-400", children: choice.label }),
|
|
2241
|
+
choice.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1542
2242
|
"button",
|
|
1543
2243
|
{
|
|
1544
2244
|
type: "button",
|
|
1545
2245
|
"aria-pressed": retouch[choice.id] === o.id,
|
|
1546
2246
|
title: o.title,
|
|
1547
2247
|
className: chip(retouch[choice.id] === o.id),
|
|
1548
|
-
onClick: () => (0,
|
|
2248
|
+
onClick: () => (0, import_image_editor10.setRetouchChoice)(controller, choice.id, o.id),
|
|
1549
2249
|
children: o.label
|
|
1550
2250
|
},
|
|
1551
2251
|
o.id
|
|
1552
2252
|
))
|
|
1553
2253
|
] }, choice.id)),
|
|
1554
|
-
|
|
1555
|
-
/* @__PURE__ */ (0,
|
|
1556
|
-
/* @__PURE__ */ (0,
|
|
2254
|
+
import_image_editor10.RETOUCH_OPTION_CONTROLS.filter((c) => c.tools.includes(tool)).map((spec) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ControlSlider, { spec, value: retouch[spec.id], onChange: (v) => controller.setPaintOptions({ retouch: { [spec.id]: v } }) }, spec.id)),
|
|
2255
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: import_image_editor10.RETOUCH_TOGGLES.filter((t) => t.tools.includes(tool)).map((t) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
2256
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1557
2257
|
"input",
|
|
1558
2258
|
{
|
|
1559
2259
|
type: "checkbox",
|
|
@@ -1566,9 +2266,9 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1566
2266
|
t.label
|
|
1567
2267
|
] }, t.id)) })
|
|
1568
2268
|
] }),
|
|
1569
|
-
/* @__PURE__ */ (0,
|
|
1570
|
-
/* @__PURE__ */ (0,
|
|
1571
|
-
/* @__PURE__ */ (0,
|
|
2269
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
|
|
2270
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
2271
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1572
2272
|
"input",
|
|
1573
2273
|
{
|
|
1574
2274
|
type: "checkbox",
|
|
@@ -1580,8 +2280,8 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1580
2280
|
),
|
|
1581
2281
|
"Pressure size"
|
|
1582
2282
|
] }),
|
|
1583
|
-
/* @__PURE__ */ (0,
|
|
1584
|
-
/* @__PURE__ */ (0,
|
|
2283
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1.5", children: [
|
|
2284
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1585
2285
|
"input",
|
|
1586
2286
|
{
|
|
1587
2287
|
type: "checkbox",
|
|
@@ -1594,28 +2294,28 @@ var BrushOptionsBar = ({ controller, className }) => {
|
|
|
1594
2294
|
"Pressure opacity"
|
|
1595
2295
|
] })
|
|
1596
2296
|
] }),
|
|
1597
|
-
/* @__PURE__ */ (0,
|
|
1598
|
-
/* @__PURE__ */ (0,
|
|
1599
|
-
/* @__PURE__ */ (0,
|
|
2297
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-1", children: [
|
|
2298
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
|
|
2299
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
|
|
1600
2300
|
] }),
|
|
1601
|
-
error && /* @__PURE__ */ (0,
|
|
2301
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
|
|
1602
2302
|
] });
|
|
1603
2303
|
};
|
|
1604
2304
|
|
|
1605
2305
|
// src/image-editor/ColorProfilePanel.tsx
|
|
1606
|
-
var
|
|
1607
|
-
var
|
|
1608
|
-
var
|
|
2306
|
+
var import_react15 = require("react");
|
|
2307
|
+
var import_image_editor12 = require("@pixerate/editor/image-editor");
|
|
2308
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1609
2309
|
var chip2 = "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white";
|
|
1610
2310
|
var select2 = "rounded bg-slate-800 px-1 py-0.5 text-[11px] text-slate-200";
|
|
1611
2311
|
var ColorProfilePanel = ({ controller, className }) => {
|
|
1612
|
-
const [, setTick] = (0,
|
|
1613
|
-
(0,
|
|
1614
|
-
const [target, setTarget] = (0,
|
|
1615
|
-
const [intent, setIntent] = (0,
|
|
1616
|
-
const [bpc, setBpc] = (0,
|
|
1617
|
-
const [error, setError] = (0,
|
|
1618
|
-
const view = (0,
|
|
2312
|
+
const [, setTick] = (0, import_react15.useState)(0);
|
|
2313
|
+
(0, import_react15.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
2314
|
+
const [target, setTarget] = (0, import_react15.useState)("display-p3");
|
|
2315
|
+
const [intent, setIntent] = (0, import_react15.useState)("relative");
|
|
2316
|
+
const [bpc, setBpc] = (0, import_react15.useState)(true);
|
|
2317
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
2318
|
+
const view = (0, import_image_editor12.colorPanelView)(controller);
|
|
1619
2319
|
const attempt = (fn) => {
|
|
1620
2320
|
try {
|
|
1621
2321
|
setError(null);
|
|
@@ -1636,29 +2336,29 @@ var ColorProfilePanel = ({ controller, className }) => {
|
|
|
1636
2336
|
})
|
|
1637
2337
|
);
|
|
1638
2338
|
};
|
|
1639
|
-
return /* @__PURE__ */ (0,
|
|
1640
|
-
/* @__PURE__ */ (0,
|
|
1641
|
-
/* @__PURE__ */ (0,
|
|
1642
|
-
/* @__PURE__ */ (0,
|
|
2339
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "color-profile-panel", children: [
|
|
2340
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2341
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-slate-400", children: "Profile" }),
|
|
2342
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "data-testid": "color-profile-name", children: view.profileName })
|
|
1643
2343
|
] }),
|
|
1644
|
-
/* @__PURE__ */ (0,
|
|
1645
|
-
/* @__PURE__ */ (0,
|
|
1646
|
-
/* @__PURE__ */ (0,
|
|
1647
|
-
view.cmykProfileName && /* @__PURE__ */ (0,
|
|
2344
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Colour mode", children: [
|
|
2345
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-slate-400", children: "Mode" }),
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Colour mode", className: select2, value: view.mode, onChange: (e) => attempt(() => controller.setColorMode(e.target.value)), children: import_image_editor12.COLOR_MODE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
|
|
2347
|
+
view.cmykProfileName && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-slate-400", children: view.cmykProfileName })
|
|
1648
2348
|
] }),
|
|
1649
|
-
/* @__PURE__ */ (0,
|
|
1650
|
-
/* @__PURE__ */ (0,
|
|
1651
|
-
/* @__PURE__ */ (0,
|
|
1652
|
-
/* @__PURE__ */ (0,
|
|
1653
|
-
/* @__PURE__ */ (0,
|
|
2349
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Assign or convert", children: [
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Target profile", className: select2, value: target, onChange: (e) => setTarget(e.target.value), children: import_image_editor12.WORKING_SPACE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: o.id, children: o.label }, o.id)) }),
|
|
2351
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Rendering intent", className: select2, value: intent, onChange: (e) => setIntent(e.target.value), children: import_image_editor12.INTENT_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
|
|
2352
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2353
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", "aria-label": "Black point compensation", checked: bpc, onChange: (e) => setBpc(e.target.checked), className: "accent-indigo-500" }),
|
|
1654
2354
|
"BPC"
|
|
1655
2355
|
] }),
|
|
1656
|
-
/* @__PURE__ */ (0,
|
|
1657
|
-
/* @__PURE__ */ (0,
|
|
2356
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: chip2, title: "Edit \u203A Assign Profile: keep the numbers", onClick: () => attempt(() => controller.assignProfile(target)), children: "Assign" }),
|
|
2357
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: chip2, title: "Edit \u203A Convert to Profile: keep the look", onClick: () => attempt(() => controller.convertToProfile(target, { intent, bpc })), children: "Convert" })
|
|
1658
2358
|
] }),
|
|
1659
|
-
/* @__PURE__ */ (0,
|
|
1660
|
-
/* @__PURE__ */ (0,
|
|
1661
|
-
/* @__PURE__ */ (0,
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Proof setup", children: [
|
|
2360
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-slate-400", children: "Proof" }),
|
|
2361
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1662
2362
|
"select",
|
|
1663
2363
|
{
|
|
1664
2364
|
"aria-label": "Proof profile",
|
|
@@ -1666,31 +2366,31 @@ var ColorProfilePanel = ({ controller, className }) => {
|
|
|
1666
2366
|
value: view.proof?.id ?? "",
|
|
1667
2367
|
onChange: (e) => e.target.value ? proofWith({ id: e.target.value }) : attempt(() => controller.setProofSetup(null)),
|
|
1668
2368
|
children: [
|
|
1669
|
-
/* @__PURE__ */ (0,
|
|
1670
|
-
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "", children: "Off" }),
|
|
2370
|
+
import_image_editor12.PROOF_PROFILE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: o.id, children: o.label }, o.id))
|
|
1671
2371
|
]
|
|
1672
2372
|
}
|
|
1673
2373
|
),
|
|
1674
|
-
view.proof && /* @__PURE__ */ (0,
|
|
1675
|
-
/* @__PURE__ */ (0,
|
|
1676
|
-
/* @__PURE__ */ (0,
|
|
1677
|
-
/* @__PURE__ */ (0,
|
|
2374
|
+
view.proof && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
2375
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Proof intent", className: select2, value: view.proof.intent, onChange: (e) => proofWith({ intent: e.target.value }), children: import_image_editor12.INTENT_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: o.id, children: o.label }, o.id)) }),
|
|
2376
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2377
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", "aria-label": "Simulate paper colour", checked: view.proof.simulatePaper, onChange: (e) => proofWith({ simulatePaper: e.target.checked }), className: "accent-indigo-500" }),
|
|
1678
2378
|
"Paper"
|
|
1679
2379
|
] }),
|
|
1680
|
-
/* @__PURE__ */ (0,
|
|
1681
|
-
/* @__PURE__ */ (0,
|
|
2380
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2381
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", "aria-label": "Gamut warning", checked: view.proof.gamutWarning, onChange: (e) => proofWith({ gamutWarning: e.target.checked }), className: "accent-indigo-500" }),
|
|
1682
2382
|
"Gamut warning"
|
|
1683
2383
|
] })
|
|
1684
2384
|
] })
|
|
1685
2385
|
] }),
|
|
1686
|
-
error && /* @__PURE__ */ (0,
|
|
2386
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
|
|
1687
2387
|
] });
|
|
1688
2388
|
};
|
|
1689
2389
|
|
|
1690
2390
|
// src/image-editor/SelectionOptionsBar.tsx
|
|
1691
|
-
var
|
|
1692
|
-
var
|
|
1693
|
-
var
|
|
2391
|
+
var import_react16 = require("react");
|
|
2392
|
+
var import_image_editor13 = require("@pixerate/editor/image-editor");
|
|
2393
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1694
2394
|
var MODIFY_OPS = [
|
|
1695
2395
|
{ op: "grow", label: "Grow" },
|
|
1696
2396
|
{ op: "shrink", label: "Shrink" },
|
|
@@ -1698,7 +2398,7 @@ var MODIFY_OPS = [
|
|
|
1698
2398
|
{ op: "border", label: "Border" },
|
|
1699
2399
|
{ op: "smooth", label: "Smooth" }
|
|
1700
2400
|
];
|
|
1701
|
-
var
|
|
2401
|
+
var btn2 = (on) => `px-2 py-1 rounded-md border text-[11px] transition-colors ${on ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-950 border-slate-800 text-slate-300 hover:text-white"}`;
|
|
1702
2402
|
var SelectionOptionsBar = ({
|
|
1703
2403
|
controller,
|
|
1704
2404
|
options,
|
|
@@ -1707,20 +2407,20 @@ var SelectionOptionsBar = ({
|
|
|
1707
2407
|
quickMask,
|
|
1708
2408
|
className = ""
|
|
1709
2409
|
}) => {
|
|
1710
|
-
const [radius, setRadius] = (0,
|
|
2410
|
+
const [radius, setRadius] = (0, import_react16.useState)(2);
|
|
1711
2411
|
const set = (patch) => onOptionsChange({ ...options, ...patch });
|
|
1712
2412
|
const sel = selection === void 0 ? controller.getSelection() : selection;
|
|
1713
2413
|
const qm = quickMask ?? Boolean(controller.getState().quickMask);
|
|
1714
|
-
return /* @__PURE__ */ (0,
|
|
1715
|
-
/* @__PURE__ */ (0,
|
|
1716
|
-
/* @__PURE__ */ (0,
|
|
1717
|
-
options.tool === "wand" && /* @__PURE__ */ (0,
|
|
1718
|
-
/* @__PURE__ */ (0,
|
|
1719
|
-
/* @__PURE__ */ (0,
|
|
1720
|
-
/* @__PURE__ */ (0,
|
|
1721
|
-
/* @__PURE__ */ (0,
|
|
2414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
|
|
2415
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor13.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn2(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
|
|
2416
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor13.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn2(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor13.SELECTION_MODE_LABELS[m] }, m)) }),
|
|
2417
|
+
options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2418
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
2419
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
2420
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: "Tolerance" }),
|
|
2421
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-mono", children: options.tolerance })
|
|
1722
2422
|
] }),
|
|
1723
|
-
/* @__PURE__ */ (0,
|
|
2423
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1724
2424
|
"input",
|
|
1725
2425
|
{
|
|
1726
2426
|
type: "range",
|
|
@@ -1734,17 +2434,17 @@ var SelectionOptionsBar = ({
|
|
|
1734
2434
|
}
|
|
1735
2435
|
)
|
|
1736
2436
|
] }),
|
|
1737
|
-
/* @__PURE__ */ (0,
|
|
1738
|
-
/* @__PURE__ */ (0,
|
|
2437
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
2438
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
|
|
1739
2439
|
"Contiguous"
|
|
1740
2440
|
] }),
|
|
1741
|
-
/* @__PURE__ */ (0,
|
|
1742
|
-
/* @__PURE__ */ (0,
|
|
2441
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
2442
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
|
|
1743
2443
|
"Sample adjusted image"
|
|
1744
2444
|
] }),
|
|
1745
|
-
/* @__PURE__ */ (0,
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
1746
2446
|
"Sample",
|
|
1747
|
-
/* @__PURE__ */ (0,
|
|
2447
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1748
2448
|
"select",
|
|
1749
2449
|
{
|
|
1750
2450
|
"aria-label": "Sample from",
|
|
@@ -1752,27 +2452,27 @@ var SelectionOptionsBar = ({
|
|
|
1752
2452
|
onChange: (e) => set({ sample: e.target.value }),
|
|
1753
2453
|
className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
|
|
1754
2454
|
children: [
|
|
1755
|
-
/* @__PURE__ */ (0,
|
|
1756
|
-
/* @__PURE__ */ (0,
|
|
2455
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "composite", children: "All layers" }),
|
|
2456
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "active-layer", children: "Active layer" })
|
|
1757
2457
|
]
|
|
1758
2458
|
}
|
|
1759
2459
|
)
|
|
1760
2460
|
] })
|
|
1761
2461
|
] }),
|
|
1762
|
-
/* @__PURE__ */ (0,
|
|
1763
|
-
/* @__PURE__ */ (0,
|
|
2462
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
2463
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
|
|
1764
2464
|
"Anti-alias"
|
|
1765
2465
|
] }),
|
|
1766
|
-
/* @__PURE__ */ (0,
|
|
1767
|
-
/* @__PURE__ */ (0,
|
|
1768
|
-
/* @__PURE__ */ (0,
|
|
1769
|
-
/* @__PURE__ */ (0,
|
|
1770
|
-
/* @__PURE__ */ (0,
|
|
2466
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
2467
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: btn2(false), onClick: () => controller.selectAll(), children: "Select All" }),
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: btn2(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: btn2(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "aria-pressed": qm, className: btn2(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
|
|
1771
2471
|
] }),
|
|
1772
|
-
/* @__PURE__ */ (0,
|
|
1773
|
-
/* @__PURE__ */ (0,
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2473
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
|
|
1774
2474
|
"Radius",
|
|
1775
|
-
/* @__PURE__ */ (0,
|
|
2475
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1776
2476
|
"input",
|
|
1777
2477
|
{
|
|
1778
2478
|
type: "number",
|
|
@@ -1786,24 +2486,24 @@ var SelectionOptionsBar = ({
|
|
|
1786
2486
|
}
|
|
1787
2487
|
)
|
|
1788
2488
|
] }),
|
|
1789
|
-
MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0,
|
|
2489
|
+
MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: btn2(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
|
|
1790
2490
|
] }),
|
|
1791
|
-
/* @__PURE__ */ (0,
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor13.describeSelection)(sel) })
|
|
1792
2492
|
] });
|
|
1793
2493
|
};
|
|
1794
2494
|
|
|
1795
2495
|
// src/image-editor/RefineEdgePanel.tsx
|
|
1796
|
-
var
|
|
1797
|
-
var
|
|
1798
|
-
var
|
|
2496
|
+
var import_react17 = require("react");
|
|
2497
|
+
var import_image_editor14 = require("@pixerate/editor/image-editor");
|
|
2498
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1799
2499
|
var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
|
|
1800
2500
|
var button3 = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
|
|
1801
2501
|
var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
1802
|
-
const [params, setParams] = (0,
|
|
1803
|
-
const [busy, setBusy] = (0,
|
|
1804
|
-
const [error, setError] = (0,
|
|
1805
|
-
const [layerId, setLayerId] = (0,
|
|
1806
|
-
const [newKind, setNewKind] = (0,
|
|
2502
|
+
const [params, setParams] = (0, import_react17.useState)(DEFAULT_PARAMS);
|
|
2503
|
+
const [busy, setBusy] = (0, import_react17.useState)(false);
|
|
2504
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
2505
|
+
const [layerId, setLayerId] = (0, import_react17.useState)("");
|
|
2506
|
+
const [newKind, setNewKind] = (0, import_react17.useState)("hueSaturation");
|
|
1807
2507
|
const sel = selection === void 0 ? controller.getSelection() : selection;
|
|
1808
2508
|
const list = layers ?? controller.getAdjustmentLayers();
|
|
1809
2509
|
const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
|
|
@@ -1818,17 +2518,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1818
2518
|
setBusy(false);
|
|
1819
2519
|
}
|
|
1820
2520
|
};
|
|
1821
|
-
return /* @__PURE__ */ (0,
|
|
1822
|
-
/* @__PURE__ */ (0,
|
|
1823
|
-
|
|
1824
|
-
/* @__PURE__ */ (0,
|
|
1825
|
-
/* @__PURE__ */ (0,
|
|
1826
|
-
/* @__PURE__ */ (0,
|
|
2521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
|
|
2523
|
+
import_image_editor14.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
2524
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: c.label }),
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "font-mono", children: [
|
|
1827
2527
|
params[c.id],
|
|
1828
2528
|
c.unit
|
|
1829
2529
|
] })
|
|
1830
2530
|
] }),
|
|
1831
|
-
/* @__PURE__ */ (0,
|
|
2531
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1832
2532
|
"input",
|
|
1833
2533
|
{
|
|
1834
2534
|
type: "range",
|
|
@@ -1842,67 +2542,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1842
2542
|
}
|
|
1843
2543
|
)
|
|
1844
2544
|
] }, c.id)),
|
|
1845
|
-
/* @__PURE__ */ (0,
|
|
1846
|
-
/* @__PURE__ */ (0,
|
|
2545
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
2546
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
|
|
1847
2547
|
"Smart Radius"
|
|
1848
2548
|
] }),
|
|
1849
|
-
/* @__PURE__ */ (0,
|
|
1850
|
-
/* @__PURE__ */ (0,
|
|
1851
|
-
/* @__PURE__ */ (0,
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-1", children: [
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: button3, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
|
|
2551
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: button3, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
|
|
1852
2552
|
] }),
|
|
1853
|
-
error && /* @__PURE__ */ (0,
|
|
1854
|
-
/* @__PURE__ */ (0,
|
|
1855
|
-
/* @__PURE__ */ (0,
|
|
1856
|
-
/* @__PURE__ */ (0,
|
|
2553
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
|
|
2554
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
|
|
2555
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-1 items-center", children: [
|
|
2556
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1857
2557
|
"select",
|
|
1858
2558
|
{
|
|
1859
2559
|
"aria-label": "New masked layer kind",
|
|
1860
2560
|
value: newKind,
|
|
1861
2561
|
onChange: (e) => setNewKind(e.target.value),
|
|
1862
2562
|
className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
|
|
1863
|
-
children:
|
|
2563
|
+
children: import_image_editor14.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: k.kind, children: k.label }, k.kind))
|
|
1864
2564
|
}
|
|
1865
2565
|
),
|
|
1866
|
-
/* @__PURE__ */ (0,
|
|
2566
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1867
2567
|
"button",
|
|
1868
2568
|
{
|
|
1869
2569
|
type: "button",
|
|
1870
2570
|
className: button3,
|
|
1871
2571
|
disabled: !sel,
|
|
1872
|
-
onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0,
|
|
2572
|
+
onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor14.layerMaskFromSelection)(sel) })),
|
|
1873
2573
|
children: "New Masked Layer"
|
|
1874
2574
|
}
|
|
1875
2575
|
)
|
|
1876
2576
|
] }),
|
|
1877
|
-
list.length > 0 && target && /* @__PURE__ */ (0,
|
|
1878
|
-
/* @__PURE__ */ (0,
|
|
2577
|
+
list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2578
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1879
2579
|
"select",
|
|
1880
2580
|
{
|
|
1881
2581
|
"aria-label": "Mask layer",
|
|
1882
2582
|
value: target.id,
|
|
1883
2583
|
onChange: (e) => setLayerId(e.target.value),
|
|
1884
2584
|
className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
|
|
1885
|
-
children: list.map((l) => /* @__PURE__ */ (0,
|
|
1886
|
-
l.name || (0,
|
|
2585
|
+
children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("option", { value: l.id, children: [
|
|
2586
|
+
l.name || (0, import_image_editor14.adjustmentKindLabel)(l.kind),
|
|
1887
2587
|
l.mask ? " (masked)" : ""
|
|
1888
2588
|
] }, l.id))
|
|
1889
2589
|
}
|
|
1890
2590
|
),
|
|
1891
|
-
/* @__PURE__ */ (0,
|
|
1892
|
-
/* @__PURE__ */ (0,
|
|
1893
|
-
/* @__PURE__ */ (0,
|
|
1894
|
-
/* @__PURE__ */ (0,
|
|
2591
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
2592
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: button3, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: button3, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: button3, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
|
|
1895
2595
|
] }),
|
|
1896
|
-
target.mask && /* @__PURE__ */ (0,
|
|
1897
|
-
/* @__PURE__ */ (0,
|
|
1898
|
-
/* @__PURE__ */ (0,
|
|
1899
|
-
/* @__PURE__ */ (0,
|
|
1900
|
-
/* @__PURE__ */ (0,
|
|
2596
|
+
target.mask && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
2597
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
2598
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
2599
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: "Density" }),
|
|
2600
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "font-mono", children: [
|
|
1901
2601
|
Math.round((target.mask.density ?? 1) * 100),
|
|
1902
2602
|
"%"
|
|
1903
2603
|
] })
|
|
1904
2604
|
] }),
|
|
1905
|
-
/* @__PURE__ */ (0,
|
|
2605
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1906
2606
|
"input",
|
|
1907
2607
|
{
|
|
1908
2608
|
type: "range",
|
|
@@ -1916,15 +2616,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1916
2616
|
}
|
|
1917
2617
|
)
|
|
1918
2618
|
] }),
|
|
1919
|
-
/* @__PURE__ */ (0,
|
|
1920
|
-
/* @__PURE__ */ (0,
|
|
1921
|
-
/* @__PURE__ */ (0,
|
|
1922
|
-
/* @__PURE__ */ (0,
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
2620
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: "Mask Feather" }),
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "font-mono", children: [
|
|
1923
2623
|
target.mask.feather ?? 0,
|
|
1924
2624
|
"px"
|
|
1925
2625
|
] })
|
|
1926
2626
|
] }),
|
|
1927
|
-
/* @__PURE__ */ (0,
|
|
2627
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1928
2628
|
"input",
|
|
1929
2629
|
{
|
|
1930
2630
|
type: "range",
|
|
@@ -1944,14 +2644,14 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
|
|
|
1944
2644
|
};
|
|
1945
2645
|
|
|
1946
2646
|
// src/image-editor/FreeTransformOptionsBar.tsx
|
|
1947
|
-
var
|
|
1948
|
-
var
|
|
1949
|
-
var
|
|
2647
|
+
var import_react18 = require("react");
|
|
2648
|
+
var import_image_editor15 = require("@pixerate/editor/image-editor");
|
|
2649
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1950
2650
|
var chip3 = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
|
|
1951
2651
|
var round = (v, unit) => unit === "px" ? Math.round(v * 10) / 10 : Math.round(v * 100) / 100;
|
|
1952
2652
|
var FreeTransformOptionsBar = ({ tool, className }) => {
|
|
1953
|
-
const [, setTick] = (0,
|
|
1954
|
-
(0,
|
|
2653
|
+
const [, setTick] = (0, import_react18.useState)(0);
|
|
2654
|
+
(0, import_react18.useEffect)(() => tool.subscribe(() => setTick((n) => n + 1)), [tool]);
|
|
1955
2655
|
const bar = tool.bar();
|
|
1956
2656
|
if (!tool.active || !bar) return null;
|
|
1957
2657
|
const warp = tool.warpBar();
|
|
@@ -1963,17 +2663,17 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
|
|
|
1963
2663
|
const v = Number(raw);
|
|
1964
2664
|
if (raw.trim() !== "" && Number.isFinite(v) && Math.abs(v - bar[field]) > 1e-9) tool.setField(field, v);
|
|
1965
2665
|
};
|
|
1966
|
-
return /* @__PURE__ */ (0,
|
|
1967
|
-
/* @__PURE__ */ (0,
|
|
1968
|
-
/* @__PURE__ */ (0,
|
|
1969
|
-
tool.mode === "warp" && /* @__PURE__ */ (0,
|
|
1970
|
-
/* @__PURE__ */ (0,
|
|
1971
|
-
/* @__PURE__ */ (0,
|
|
1972
|
-
/* @__PURE__ */ (0,
|
|
2666
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.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: [
|
|
2667
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Transform mode", children: import_image_editor15.FREE_TRANSFORM_MODE_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", title: m.title, "aria-pressed": tool.mode === m.id, className: chip3(tool.mode === m.id), onClick: () => tool.setMode(m.id), children: m.label }, m.id)) }),
|
|
2668
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "grid grid-cols-3 gap-px", role: "group", "aria-label": "Reference point", children: import_image_editor15.TRANSFORM_ANCHORS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime18.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)) }),
|
|
2669
|
+
tool.mode === "warp" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": "Warp options", children: [
|
|
2670
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-400", children: "Warp" }),
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Warp style", value: warp.style, onChange: (e) => tool.setWarp({ style: e.target.value }), className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5", children: import_image_editor15.WARP_STYLE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: o.id, children: o.label }, o.id)) })
|
|
1973
2673
|
] }),
|
|
1974
|
-
["bend", "horizontal", "vertical"].map((k) => /* @__PURE__ */ (0,
|
|
1975
|
-
/* @__PURE__ */ (0,
|
|
1976
|
-
/* @__PURE__ */ (0,
|
|
2674
|
+
["bend", "horizontal", "vertical"].map((k) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2675
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-400", children: k === "bend" ? "Bend" : k === "horizontal" ? "H" : "V" }),
|
|
2676
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1977
2677
|
"input",
|
|
1978
2678
|
{
|
|
1979
2679
|
type: "number",
|
|
@@ -1994,9 +2694,9 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
|
|
|
1994
2694
|
},
|
|
1995
2695
|
`${k}:${warp[k]}`
|
|
1996
2696
|
),
|
|
1997
|
-
/* @__PURE__ */ (0,
|
|
2697
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-500", children: "%" })
|
|
1998
2698
|
] }, k)),
|
|
1999
|
-
/* @__PURE__ */ (0,
|
|
2699
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2000
2700
|
"button",
|
|
2001
2701
|
{
|
|
2002
2702
|
type: "button",
|
|
@@ -2008,26 +2708,26 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
|
|
|
2008
2708
|
children: "Vertical"
|
|
2009
2709
|
}
|
|
2010
2710
|
),
|
|
2011
|
-
/* @__PURE__ */ (0,
|
|
2012
|
-
/* @__PURE__ */ (0,
|
|
2013
|
-
/* @__PURE__ */ (0,
|
|
2711
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2712
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-400", children: "Grid" }),
|
|
2713
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2014
2714
|
"select",
|
|
2015
2715
|
{
|
|
2016
2716
|
"aria-label": "Warp grid",
|
|
2017
|
-
value:
|
|
2717
|
+
value: import_image_editor15.WARP_GRID_OPTIONS.find((g) => g.columns === warp.columns && g.rows === warp.rows)?.id ?? "1x1",
|
|
2018
2718
|
onChange: (e) => {
|
|
2019
|
-
const g =
|
|
2719
|
+
const g = import_image_editor15.WARP_GRID_OPTIONS.find((o) => o.id === e.target.value);
|
|
2020
2720
|
tool.setWarp({ columns: g.columns, rows: g.rows });
|
|
2021
2721
|
},
|
|
2022
2722
|
className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
|
|
2023
|
-
children:
|
|
2723
|
+
children: import_image_editor15.WARP_GRID_OPTIONS.map((g) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: g.id, children: g.label }, g.id))
|
|
2024
2724
|
}
|
|
2025
2725
|
)
|
|
2026
2726
|
] })
|
|
2027
2727
|
] }),
|
|
2028
|
-
tool.mode !== "warp" &&
|
|
2029
|
-
/* @__PURE__ */ (0,
|
|
2030
|
-
/* @__PURE__ */ (0,
|
|
2728
|
+
tool.mode !== "warp" && import_image_editor15.FREE_TRANSFORM_FIELDS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1", title: f.title, children: [
|
|
2729
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-400", children: f.label }),
|
|
2730
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2031
2731
|
"input",
|
|
2032
2732
|
{
|
|
2033
2733
|
type: "number",
|
|
@@ -2047,8 +2747,8 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
|
|
|
2047
2747
|
},
|
|
2048
2748
|
`${f.id}:${round(bar[f.id], f.unit)}`
|
|
2049
2749
|
),
|
|
2050
|
-
/* @__PURE__ */ (0,
|
|
2051
|
-
f.id === "scaleX" && /* @__PURE__ */ (0,
|
|
2750
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-500", children: f.unit }),
|
|
2751
|
+
f.id === "scaleX" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2052
2752
|
"button",
|
|
2053
2753
|
{
|
|
2054
2754
|
type: "button",
|
|
@@ -2063,34 +2763,34 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
|
|
|
2063
2763
|
}
|
|
2064
2764
|
)
|
|
2065
2765
|
] }, f.id)),
|
|
2066
|
-
/* @__PURE__ */ (0,
|
|
2067
|
-
/* @__PURE__ */ (0,
|
|
2068
|
-
/* @__PURE__ */ (0,
|
|
2766
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2767
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-400", children: "Interpolation" }),
|
|
2768
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2069
2769
|
"select",
|
|
2070
2770
|
{
|
|
2071
2771
|
"aria-label": "Interpolation",
|
|
2072
2772
|
value: tool.interpolation,
|
|
2073
2773
|
onChange: (e) => tool.setInterpolation(e.target.value),
|
|
2074
2774
|
className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
|
|
2075
|
-
children:
|
|
2775
|
+
children: import_image_editor15.INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: i, children: i[0].toUpperCase() + i.slice(1) }, i))
|
|
2076
2776
|
}
|
|
2077
2777
|
)
|
|
2078
2778
|
] }),
|
|
2079
|
-
/* @__PURE__ */ (0,
|
|
2080
|
-
/* @__PURE__ */ (0,
|
|
2081
|
-
tool.error && /* @__PURE__ */ (0,
|
|
2779
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.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" }),
|
|
2780
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", title: "Cancel (Esc)", className: chip3(false), onClick: () => tool.cancel(), children: "Cancel" }),
|
|
2781
|
+
tool.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { role: "alert", className: "text-rose-400", children: tool.error })
|
|
2082
2782
|
] });
|
|
2083
2783
|
};
|
|
2084
2784
|
|
|
2085
2785
|
// src/image-editor/ShapeOptionsBar.tsx
|
|
2086
|
-
var
|
|
2087
|
-
var
|
|
2088
|
-
var
|
|
2786
|
+
var import_react19 = require("react");
|
|
2787
|
+
var import_image_editor16 = require("@pixerate/editor/image-editor");
|
|
2788
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2089
2789
|
var chip4 = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
|
|
2090
2790
|
var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
|
|
2091
|
-
const [, setTick] = (0,
|
|
2092
|
-
(0,
|
|
2093
|
-
const [error, setError] = (0,
|
|
2791
|
+
const [, setTick] = (0, import_react19.useState)(0);
|
|
2792
|
+
(0, import_react19.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
2793
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
2094
2794
|
const active = controller.getActiveLayer();
|
|
2095
2795
|
const shapeId = active?.type === "shape" ? active.id : null;
|
|
2096
2796
|
const set = (change) => {
|
|
@@ -2098,19 +2798,19 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
|
|
|
2098
2798
|
if (!shapeId) return;
|
|
2099
2799
|
try {
|
|
2100
2800
|
setError(null);
|
|
2101
|
-
(0,
|
|
2801
|
+
(0, import_image_editor16.applyShapeOptions)(controller, shapeId, change);
|
|
2102
2802
|
} catch (e) {
|
|
2103
2803
|
setError(e instanceof Error ? e.message : String(e));
|
|
2104
2804
|
}
|
|
2105
2805
|
};
|
|
2106
2806
|
const num = (v, min, max) => Math.max(min, Math.min(max, Number(v) || min));
|
|
2107
|
-
return /* @__PURE__ */ (0,
|
|
2108
|
-
/* @__PURE__ */ (0,
|
|
2109
|
-
/* @__PURE__ */ (0,
|
|
2110
|
-
/* @__PURE__ */ (0,
|
|
2111
|
-
/* @__PURE__ */ (0,
|
|
2807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "shape-options", children: [
|
|
2808
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Shape kind", children: import_image_editor16.LIVE_SHAPE_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", "aria-pressed": options.kind === k, className: chip4(options.kind === k), onClick: () => onChange({ ...options, kind: k }), children: import_image_editor16.SHAPE_KIND_LABELS[k] }, k)) }),
|
|
2809
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
2810
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2811
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "checkbox", "aria-label": "Fill", checked: options.fill !== null, onChange: (e) => set({ fill: e.target.checked ? "#4f46e5" : null }) }),
|
|
2112
2812
|
"Fill",
|
|
2113
|
-
/* @__PURE__ */ (0,
|
|
2813
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2114
2814
|
"input",
|
|
2115
2815
|
{
|
|
2116
2816
|
type: "color",
|
|
@@ -2122,10 +2822,10 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
|
|
|
2122
2822
|
}
|
|
2123
2823
|
)
|
|
2124
2824
|
] }),
|
|
2125
|
-
/* @__PURE__ */ (0,
|
|
2126
|
-
/* @__PURE__ */ (0,
|
|
2825
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2826
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "checkbox", "aria-label": "Stroke", checked: options.stroke !== null, onChange: (e) => set({ stroke: e.target.checked ? "#000000" : null }) }),
|
|
2127
2827
|
"Stroke",
|
|
2128
|
-
/* @__PURE__ */ (0,
|
|
2828
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2129
2829
|
"input",
|
|
2130
2830
|
{
|
|
2131
2831
|
type: "color",
|
|
@@ -2137,9 +2837,9 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
|
|
|
2137
2837
|
}
|
|
2138
2838
|
)
|
|
2139
2839
|
] }),
|
|
2140
|
-
/* @__PURE__ */ (0,
|
|
2840
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2141
2841
|
"Width",
|
|
2142
|
-
/* @__PURE__ */ (0,
|
|
2842
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2143
2843
|
"input",
|
|
2144
2844
|
{
|
|
2145
2845
|
type: "number",
|
|
@@ -2153,23 +2853,23 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
|
|
|
2153
2853
|
)
|
|
2154
2854
|
] })
|
|
2155
2855
|
] }),
|
|
2156
|
-
/* @__PURE__ */ (0,
|
|
2157
|
-
options.kind === "rect" && /* @__PURE__ */ (0,
|
|
2856
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
2857
|
+
options.kind === "rect" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2158
2858
|
"Radius",
|
|
2159
|
-
/* @__PURE__ */ (0,
|
|
2859
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "number", "aria-label": "Corner radius", min: 0, max: 1e3, value: options.radius, onChange: (e) => set({ radius: num(e.target.value, 0, 1e3) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
|
|
2160
2860
|
] }),
|
|
2161
|
-
options.kind === "polygon" && /* @__PURE__ */ (0,
|
|
2861
|
+
options.kind === "polygon" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2162
2862
|
"Sides",
|
|
2163
|
-
/* @__PURE__ */ (0,
|
|
2863
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "number", "aria-label": "Sides", min: 3, max: 100, value: options.sides, onChange: (e) => set({ sides: num(e.target.value, 3, 100) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
|
|
2164
2864
|
] }),
|
|
2165
|
-
options.kind === "star" && /* @__PURE__ */ (0,
|
|
2166
|
-
/* @__PURE__ */ (0,
|
|
2865
|
+
options.kind === "star" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
2866
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2167
2867
|
"Points",
|
|
2168
|
-
/* @__PURE__ */ (0,
|
|
2868
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "number", "aria-label": "Points", min: 3, max: 100, value: options.points, onChange: (e) => set({ points: num(e.target.value, 3, 100) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
|
|
2169
2869
|
] }),
|
|
2170
|
-
/* @__PURE__ */ (0,
|
|
2870
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2171
2871
|
"Inner",
|
|
2172
|
-
/* @__PURE__ */ (0,
|
|
2872
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2173
2873
|
"input",
|
|
2174
2874
|
{
|
|
2175
2875
|
type: "range",
|
|
@@ -2184,33 +2884,33 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
|
|
|
2184
2884
|
)
|
|
2185
2885
|
] })
|
|
2186
2886
|
] }),
|
|
2187
|
-
options.kind === "line" && /* @__PURE__ */ (0,
|
|
2188
|
-
/* @__PURE__ */ (0,
|
|
2887
|
+
options.kind === "line" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
2888
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2189
2889
|
"Weight",
|
|
2190
|
-
/* @__PURE__ */ (0,
|
|
2890
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "number", "aria-label": "Line weight", min: 1, max: 200, value: options.weight, onChange: (e) => set({ weight: num(e.target.value, 1, 200) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
|
|
2191
2891
|
] }),
|
|
2192
|
-
/* @__PURE__ */ (0,
|
|
2193
|
-
/* @__PURE__ */ (0,
|
|
2892
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2893
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
|
|
2194
2894
|
"Arrowhead"
|
|
2195
2895
|
] })
|
|
2196
2896
|
] })
|
|
2197
2897
|
] }),
|
|
2198
|
-
/* @__PURE__ */ (0,
|
|
2199
|
-
error && /* @__PURE__ */ (0,
|
|
2898
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-[10px] text-slate-500", children: "Drag on the image to draw. Shift: square, circle or 45\xB0 line. Alt: from the centre." }),
|
|
2899
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
|
|
2200
2900
|
] });
|
|
2201
2901
|
};
|
|
2202
2902
|
|
|
2203
2903
|
// src/image-editor/TypeOptionsBar.tsx
|
|
2204
|
-
var
|
|
2205
|
-
var
|
|
2206
|
-
var
|
|
2904
|
+
var import_react20 = require("react");
|
|
2905
|
+
var import_image_editor17 = require("@pixerate/editor/image-editor");
|
|
2906
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2207
2907
|
var chip5 = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
|
|
2208
2908
|
var ALIGN_LABELS = { left: "Left", center: "Centre", right: "Right", justify: "Justify" };
|
|
2209
2909
|
var TypeOptionsBar = ({ controller, options, onChange, session, className }) => {
|
|
2210
|
-
const [, setTick] = (0,
|
|
2211
|
-
(0,
|
|
2212
|
-
(0,
|
|
2213
|
-
const [error, setError] = (0,
|
|
2910
|
+
const [, setTick] = (0, import_react20.useState)(0);
|
|
2911
|
+
(0, import_react20.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
2912
|
+
(0, import_react20.useEffect)(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
|
|
2913
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
2214
2914
|
const active = controller.getActiveLayer();
|
|
2215
2915
|
const typeId = !session && active?.type === "type" ? active.id : null;
|
|
2216
2916
|
const here = session?.alive ? session.styleHere() : {};
|
|
@@ -2242,11 +2942,11 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
|
|
|
2242
2942
|
setError(e instanceof Error ? e.message : String(e));
|
|
2243
2943
|
}
|
|
2244
2944
|
};
|
|
2245
|
-
return /* @__PURE__ */ (0,
|
|
2246
|
-
/* @__PURE__ */ (0,
|
|
2247
|
-
/* @__PURE__ */ (0,
|
|
2945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "type-options", children: [
|
|
2946
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2947
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2248
2948
|
"Font",
|
|
2249
|
-
/* @__PURE__ */ (0,
|
|
2949
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2250
2950
|
"input",
|
|
2251
2951
|
{
|
|
2252
2952
|
list: "pixerate-type-fonts",
|
|
@@ -2256,11 +2956,11 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
|
|
|
2256
2956
|
className: "w-32 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
|
|
2257
2957
|
}
|
|
2258
2958
|
),
|
|
2259
|
-
/* @__PURE__ */ (0,
|
|
2959
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("datalist", { id: "pixerate-type-fonts", children: fonts.map((f) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: f }, f)) })
|
|
2260
2960
|
] }),
|
|
2261
|
-
/* @__PURE__ */ (0,
|
|
2961
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
2262
2962
|
"Size",
|
|
2263
|
-
/* @__PURE__ */ (0,
|
|
2963
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2264
2964
|
"input",
|
|
2265
2965
|
{
|
|
2266
2966
|
type: "number",
|
|
@@ -2273,24 +2973,24 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
|
|
|
2273
2973
|
}
|
|
2274
2974
|
)
|
|
2275
2975
|
] }),
|
|
2276
|
-
/* @__PURE__ */ (0,
|
|
2277
|
-
/* @__PURE__ */ (0,
|
|
2278
|
-
/* @__PURE__ */ (0,
|
|
2976
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", "aria-pressed": shown.fontWeight >= 600, className: `${chip5(shown.fontWeight >= 600)} font-bold`, onClick: () => style({ fontWeight: shown.fontWeight >= 600 ? 400 : 700 }), children: "B" }),
|
|
2977
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", "aria-pressed": shown.italic, className: `${chip5(shown.italic)} italic`, onClick: () => style({ italic: !shown.italic }), children: "I" }),
|
|
2978
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { type: "color", "aria-label": "Text colour", value: shown.color, onChange: (e) => style({ color: e.target.value }), className: "h-6 w-8 rounded border border-slate-700 bg-transparent" })
|
|
2279
2979
|
] }),
|
|
2280
|
-
/* @__PURE__ */ (0,
|
|
2281
|
-
/* @__PURE__ */ (0,
|
|
2282
|
-
missing.length > 0 && /* @__PURE__ */ (0,
|
|
2980
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Alignment", children: import_image_editor17.TEXT_ALIGNS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", "aria-pressed": options.align === a, className: chip5(options.align === a), onClick: () => style({ align: a }), children: ALIGN_LABELS[a] }, a)) }),
|
|
2981
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-[10px] text-slate-500", children: "Click to type point text, drag for a paragraph box, click text to edit it. Esc finishes." }),
|
|
2982
|
+
missing.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
|
|
2283
2983
|
"Missing ",
|
|
2284
2984
|
missing.length === 1 ? "font" : "fonts",
|
|
2285
2985
|
": ",
|
|
2286
2986
|
missing.join(", ")
|
|
2287
2987
|
] }),
|
|
2288
|
-
error && /* @__PURE__ */ (0,
|
|
2988
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
|
|
2289
2989
|
] });
|
|
2290
2990
|
};
|
|
2291
2991
|
|
|
2292
2992
|
// src/image-editor/ImageEditor.tsx
|
|
2293
|
-
var
|
|
2993
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2294
2994
|
var ImageEditor = ({
|
|
2295
2995
|
editor: externalEditor,
|
|
2296
2996
|
src,
|
|
@@ -2300,70 +3000,75 @@ var ImageEditor = ({
|
|
|
2300
3000
|
exportOptions,
|
|
2301
3001
|
onInpaint,
|
|
2302
3002
|
onRemoveBackground,
|
|
2303
|
-
aiHooks
|
|
3003
|
+
aiHooks,
|
|
3004
|
+
effects
|
|
2304
3005
|
}) => {
|
|
2305
3006
|
const internalEditor = useImageEditor({ image: src });
|
|
2306
3007
|
const editor = externalEditor || internalEditor;
|
|
2307
3008
|
const { state, controller } = editor;
|
|
2308
|
-
|
|
2309
|
-
const
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
const
|
|
2313
|
-
const
|
|
2314
|
-
const
|
|
3009
|
+
useEffects(controller, effects);
|
|
3010
|
+
const effectsShown = !!controller.effectsProvider || state.layers.some(function has(l) {
|
|
3011
|
+
return l.type === "pixel" && !!l.generator || l.type === "smart" && !!l.smartFilters?.filters.some((f) => f.kind === "effect") || l.type === "group" && l.children.some(has);
|
|
3012
|
+
});
|
|
3013
|
+
const legacyProcess = (0, import_image_editor18.normalizeProcessVersion)(state.adjustments.process) < import_image_editor18.LATEST_PROCESS_VERSION;
|
|
3014
|
+
const canvasRef = (0, import_react21.useRef)(null);
|
|
3015
|
+
const containerRef = (0, import_react21.useRef)(null);
|
|
3016
|
+
const [activeTab, setActiveTab] = (0, import_react21.useState)("crop");
|
|
3017
|
+
const [activeCropRatio, setActiveCropRatio] = (0, import_react21.useState)(null);
|
|
3018
|
+
const [selectionOptions, setSelectionOptions] = (0, import_react21.useState)(import_image_editor18.DEFAULT_SELECTION_TOOL_OPTIONS);
|
|
3019
|
+
const selectionOptionsRef = (0, import_react21.useRef)(selectionOptions);
|
|
2315
3020
|
selectionOptionsRef.current = selectionOptions;
|
|
2316
|
-
const selectionGestureRef = (0,
|
|
3021
|
+
const selectionGestureRef = (0, import_react21.useRef)(null);
|
|
2317
3022
|
if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
|
|
2318
|
-
selectionGestureRef.current = new
|
|
3023
|
+
selectionGestureRef.current = new import_image_editor18.SelectionGesture(controller, () => selectionOptionsRef.current);
|
|
2319
3024
|
}
|
|
2320
|
-
const selectionDraftRef = (0,
|
|
2321
|
-
const [selectionError, setSelectionError] = (0,
|
|
2322
|
-
const paintGestureRef = (0,
|
|
2323
|
-
const paintControllerRef = (0,
|
|
3025
|
+
const selectionDraftRef = (0, import_react21.useRef)(null);
|
|
3026
|
+
const [selectionError, setSelectionError] = (0, import_react21.useState)(null);
|
|
3027
|
+
const paintGestureRef = (0, import_react21.useRef)(null);
|
|
3028
|
+
const paintControllerRef = (0, import_react21.useRef)(controller);
|
|
2324
3029
|
if (!paintGestureRef.current || paintControllerRef.current !== controller) {
|
|
2325
|
-
paintGestureRef.current = new
|
|
3030
|
+
paintGestureRef.current = new import_image_editor18.PaintGesture(controller);
|
|
2326
3031
|
paintControllerRef.current = controller;
|
|
2327
3032
|
}
|
|
2328
|
-
const brushCursorRef = (0,
|
|
2329
|
-
const [paintError, setPaintError] = (0,
|
|
2330
|
-
const transformToolRef = (0,
|
|
2331
|
-
const transformControllerRef = (0,
|
|
3033
|
+
const brushCursorRef = (0, import_react21.useRef)(null);
|
|
3034
|
+
const [paintError, setPaintError] = (0, import_react21.useState)(null);
|
|
3035
|
+
const transformToolRef = (0, import_react21.useRef)(null);
|
|
3036
|
+
const transformControllerRef = (0, import_react21.useRef)(controller);
|
|
2332
3037
|
if (!transformToolRef.current || transformControllerRef.current !== controller) {
|
|
2333
3038
|
transformToolRef.current?.cancel();
|
|
2334
|
-
transformToolRef.current = new
|
|
3039
|
+
transformToolRef.current = new import_image_editor18.FreeTransformTool(controller, {
|
|
2335
3040
|
schedule: (run) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(run) : run()
|
|
2336
3041
|
});
|
|
2337
3042
|
transformControllerRef.current = controller;
|
|
2338
3043
|
}
|
|
2339
3044
|
const transformTool = transformToolRef.current;
|
|
2340
|
-
const [, setTransformTick] = (0,
|
|
2341
|
-
const [transformCursor, setTransformCursor] = (0,
|
|
2342
|
-
const [shapeOptions, setShapeOptions] = (0,
|
|
2343
|
-
const shapeOptionsRef = (0,
|
|
3045
|
+
const [, setTransformTick] = (0, import_react21.useState)(0);
|
|
3046
|
+
const [transformCursor, setTransformCursor] = (0, import_react21.useState)("default");
|
|
3047
|
+
const [shapeOptions, setShapeOptions] = (0, import_react21.useState)(import_image_editor18.DEFAULT_SHAPE_TOOL_OPTIONS);
|
|
3048
|
+
const shapeOptionsRef = (0, import_react21.useRef)(shapeOptions);
|
|
2344
3049
|
shapeOptionsRef.current = shapeOptions;
|
|
2345
|
-
const [typeOptions, setTypeOptions] = (0,
|
|
2346
|
-
const typeOptionsRef = (0,
|
|
3050
|
+
const [typeOptions, setTypeOptions] = (0, import_react21.useState)(import_image_editor18.DEFAULT_TYPE_TOOL_OPTIONS);
|
|
3051
|
+
const typeOptionsRef = (0, import_react21.useRef)(typeOptions);
|
|
2347
3052
|
typeOptionsRef.current = typeOptions;
|
|
2348
|
-
const shapeGestureRef = (0,
|
|
2349
|
-
const typeToolRef = (0,
|
|
2350
|
-
const shapeTypeControllerRef = (0,
|
|
3053
|
+
const shapeGestureRef = (0, import_react21.useRef)(null);
|
|
3054
|
+
const typeToolRef = (0, import_react21.useRef)(null);
|
|
3055
|
+
const shapeTypeControllerRef = (0, import_react21.useRef)(controller);
|
|
2351
3056
|
if (!shapeGestureRef.current || !typeToolRef.current || shapeTypeControllerRef.current !== controller) {
|
|
2352
3057
|
typeToolRef.current?.finish();
|
|
2353
|
-
shapeGestureRef.current = new
|
|
2354
|
-
typeToolRef.current = new
|
|
3058
|
+
shapeGestureRef.current = new import_image_editor18.ShapeDrawGesture(controller, () => shapeOptionsRef.current);
|
|
3059
|
+
typeToolRef.current = new import_image_editor18.TypeToolGesture(controller, () => typeOptionsRef.current);
|
|
2355
3060
|
shapeTypeControllerRef.current = controller;
|
|
2356
3061
|
}
|
|
2357
|
-
const typeInputRef = (0,
|
|
2358
|
-
const [typeSession, setTypeSession] = (0,
|
|
2359
|
-
const [shapeTypeError, setShapeTypeError] = (0,
|
|
2360
|
-
const [inpaintPrompt, setInpaintPrompt] = (0,
|
|
2361
|
-
const [inpaintMaskMode, setInpaintMaskMode] = (0,
|
|
2362
|
-
const [isRemovingBg, setIsRemovingBg] = (0,
|
|
2363
|
-
const [isInpainting, setIsInpainting] = (0,
|
|
2364
|
-
const [aiError, setAiError] = (0,
|
|
2365
|
-
const [aiSuccess, setAiSuccess] = (0,
|
|
2366
|
-
const [aiTarget, setAiTarget] = (0,
|
|
3062
|
+
const typeInputRef = (0, import_react21.useRef)(null);
|
|
3063
|
+
const [typeSession, setTypeSession] = (0, import_react21.useState)(typeToolRef.current.session);
|
|
3064
|
+
const [shapeTypeError, setShapeTypeError] = (0, import_react21.useState)(null);
|
|
3065
|
+
const [inpaintPrompt, setInpaintPrompt] = (0, import_react21.useState)("");
|
|
3066
|
+
const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react21.useState)("annotations");
|
|
3067
|
+
const [isRemovingBg, setIsRemovingBg] = (0, import_react21.useState)(false);
|
|
3068
|
+
const [isInpainting, setIsInpainting] = (0, import_react21.useState)(false);
|
|
3069
|
+
const [aiError, setAiError] = (0, import_react21.useState)(null);
|
|
3070
|
+
const [aiSuccess, setAiSuccess] = (0, import_react21.useState)(null);
|
|
3071
|
+
const [aiTarget, setAiTarget] = (0, import_react21.useState)("auto");
|
|
2367
3072
|
const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
|
|
2368
3073
|
const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
|
|
2369
3074
|
const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
|
|
@@ -2426,18 +3131,18 @@ var ImageEditor = ({
|
|
|
2426
3131
|
setIsInpainting(false);
|
|
2427
3132
|
}
|
|
2428
3133
|
};
|
|
2429
|
-
const [activeColor, setActiveColor] = (0,
|
|
2430
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
2431
|
-
const [fontSize, setFontSize] = (0,
|
|
2432
|
-
const [textInput, setTextInput] = (0,
|
|
2433
|
-
const draftAnnotationRef = (0,
|
|
2434
|
-
const draftCropRef = (0,
|
|
2435
|
-
const cropDragInfoRef = (0,
|
|
2436
|
-
const annotationDragInfoRef = (0,
|
|
2437
|
-
const isDrawingRef = (0,
|
|
2438
|
-
const currentPathRef = (0,
|
|
2439
|
-
const dragStartPointRef = (0,
|
|
2440
|
-
const renderCanvas = (0,
|
|
3134
|
+
const [activeColor, setActiveColor] = (0, import_react21.useState)("#ef4444");
|
|
3135
|
+
const [strokeWidth, setStrokeWidth] = (0, import_react21.useState)(3);
|
|
3136
|
+
const [fontSize, setFontSize] = (0, import_react21.useState)(24);
|
|
3137
|
+
const [textInput, setTextInput] = (0, import_react21.useState)("");
|
|
3138
|
+
const draftAnnotationRef = (0, import_react21.useRef)(null);
|
|
3139
|
+
const draftCropRef = (0, import_react21.useRef)(null);
|
|
3140
|
+
const cropDragInfoRef = (0, import_react21.useRef)(null);
|
|
3141
|
+
const annotationDragInfoRef = (0, import_react21.useRef)(null);
|
|
3142
|
+
const isDrawingRef = (0, import_react21.useRef)(false);
|
|
3143
|
+
const currentPathRef = (0, import_react21.useRef)([]);
|
|
3144
|
+
const dragStartPointRef = (0, import_react21.useRef)(null);
|
|
3145
|
+
const renderCanvas = (0, import_react21.useCallback)(
|
|
2441
3146
|
async (draftAnnotation, draftCrop) => {
|
|
2442
3147
|
const canvas = canvasRef.current;
|
|
2443
3148
|
const container = containerRef.current;
|
|
@@ -2460,8 +3165,8 @@ var ImageEditor = ({
|
|
|
2460
3165
|
},
|
|
2461
3166
|
[controller, activeTab, transformTool]
|
|
2462
3167
|
);
|
|
2463
|
-
(0,
|
|
2464
|
-
(0,
|
|
3168
|
+
(0, import_react21.useEffect)(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
|
|
3169
|
+
(0, import_react21.useEffect)(() => {
|
|
2465
3170
|
if (activeTab === "annotate" && state.activeTool === "type") return;
|
|
2466
3171
|
if (typeToolRef.current?.session) {
|
|
2467
3172
|
typeToolRef.current.finish();
|
|
@@ -2496,7 +3201,7 @@ var ImageEditor = ({
|
|
|
2496
3201
|
el.value = "";
|
|
2497
3202
|
}
|
|
2498
3203
|
};
|
|
2499
|
-
(0,
|
|
3204
|
+
(0, import_react21.useEffect)(() => transformTool.subscribe(() => {
|
|
2500
3205
|
setTransformTick((n) => n + 1);
|
|
2501
3206
|
void renderCanvas();
|
|
2502
3207
|
}), [transformTool, renderCanvas]);
|
|
@@ -2507,8 +3212,8 @@ var ImageEditor = ({
|
|
|
2507
3212
|
const sy = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
2508
3213
|
const s = controller.getState();
|
|
2509
3214
|
const cropping = activeTab === "crop";
|
|
2510
|
-
const projection = (0,
|
|
2511
|
-
const pt = (0,
|
|
3215
|
+
const projection = (0, import_image_editor18.getViewportProjection)(s, canvas.width, canvas.height, cropping);
|
|
3216
|
+
const pt = (0, import_image_editor18.canvasToImagePoint)({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvas.width, canvas.height, cropping);
|
|
2512
3217
|
transformTool.setView(projection.scale);
|
|
2513
3218
|
return { pt, tolerance: 6 / (projection.scale || 1) };
|
|
2514
3219
|
};
|
|
@@ -2539,7 +3244,7 @@ var ImageEditor = ({
|
|
|
2539
3244
|
transformTool.up();
|
|
2540
3245
|
return true;
|
|
2541
3246
|
};
|
|
2542
|
-
(0,
|
|
3247
|
+
(0, import_react21.useEffect)(() => {
|
|
2543
3248
|
if (typeof window === "undefined") return;
|
|
2544
3249
|
const onKey = (e) => {
|
|
2545
3250
|
if (transformTool.key(e)) e.preventDefault();
|
|
@@ -2547,7 +3252,7 @@ var ImageEditor = ({
|
|
|
2547
3252
|
window.addEventListener("keydown", onKey);
|
|
2548
3253
|
return () => window.removeEventListener("keydown", onKey);
|
|
2549
3254
|
}, [transformTool]);
|
|
2550
|
-
(0,
|
|
3255
|
+
(0, import_react21.useEffect)(() => {
|
|
2551
3256
|
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
2552
3257
|
const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
2553
3258
|
const animId = raf(() => {
|
|
@@ -2555,12 +3260,12 @@ var ImageEditor = ({
|
|
|
2555
3260
|
});
|
|
2556
3261
|
return () => caf(animId);
|
|
2557
3262
|
}, [renderCanvas, state]);
|
|
2558
|
-
(0,
|
|
3263
|
+
(0, import_react21.useEffect)(() => {
|
|
2559
3264
|
if (activeTab === "crop" && editor.state.activeTool !== "crop") {
|
|
2560
3265
|
editor.setTool("crop");
|
|
2561
3266
|
}
|
|
2562
3267
|
}, [activeTab, editor]);
|
|
2563
|
-
(0,
|
|
3268
|
+
(0, import_react21.useEffect)(() => {
|
|
2564
3269
|
const container = containerRef.current;
|
|
2565
3270
|
if (!container) return;
|
|
2566
3271
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -2596,8 +3301,8 @@ var ImageEditor = ({
|
|
|
2596
3301
|
const sy = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
2597
3302
|
const s = controller.getState();
|
|
2598
3303
|
return list.map((ev) => ({
|
|
2599
|
-
...(0,
|
|
2600
|
-
pressure: (0,
|
|
3304
|
+
...(0, import_image_editor18.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
|
|
3305
|
+
pressure: (0, import_image_editor18.pointerPressure)(ev)
|
|
2601
3306
|
}));
|
|
2602
3307
|
};
|
|
2603
3308
|
const handlePaintPointerDown = (e) => {
|
|
@@ -2628,10 +3333,10 @@ var ImageEditor = ({
|
|
|
2628
3333
|
if (g.error) setPaintError(g.error);
|
|
2629
3334
|
}
|
|
2630
3335
|
};
|
|
2631
|
-
(0,
|
|
3336
|
+
(0, import_react21.useEffect)(() => {
|
|
2632
3337
|
if (activeTab !== "paint" || typeof window === "undefined") return;
|
|
2633
3338
|
const onKey = (e) => {
|
|
2634
|
-
if ((0,
|
|
3339
|
+
if ((0, import_image_editor18.handlePaintShortcut)(controller, e)) e.preventDefault();
|
|
2635
3340
|
};
|
|
2636
3341
|
window.addEventListener("keydown", onKey);
|
|
2637
3342
|
return () => window.removeEventListener("keydown", onKey);
|
|
@@ -2642,7 +3347,7 @@ var ImageEditor = ({
|
|
|
2642
3347
|
const canvasPt = getCanvasEventPoint(e);
|
|
2643
3348
|
if (activeTab === "select") {
|
|
2644
3349
|
const gesture = selectionGestureRef.current;
|
|
2645
|
-
const imgPt = (0,
|
|
3350
|
+
const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2646
3351
|
void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
|
|
2647
3352
|
return;
|
|
2648
3353
|
}
|
|
@@ -2653,8 +3358,8 @@ var ImageEditor = ({
|
|
|
2653
3358
|
width: state.imageDimensions.width,
|
|
2654
3359
|
height: state.imageDimensions.height
|
|
2655
3360
|
};
|
|
2656
|
-
const handle = (0,
|
|
2657
|
-
const startImgPt = (0,
|
|
3361
|
+
const handle = (0, import_image_editor18.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
3362
|
+
const startImgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
2658
3363
|
if (handle) {
|
|
2659
3364
|
cropDragInfoRef.current = {
|
|
2660
3365
|
handle,
|
|
@@ -2673,7 +3378,7 @@ var ImageEditor = ({
|
|
|
2673
3378
|
return;
|
|
2674
3379
|
}
|
|
2675
3380
|
if (activeTab === "annotate" && (state.activeTool === "shape" || state.activeTool === "type")) {
|
|
2676
|
-
const imgPt = (0,
|
|
3381
|
+
const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2677
3382
|
setShapeTypeError(null);
|
|
2678
3383
|
if (state.activeTool === "shape") shapeGestureRef.current.down(imgPt);
|
|
2679
3384
|
else {
|
|
@@ -2684,12 +3389,12 @@ var ImageEditor = ({
|
|
|
2684
3389
|
return;
|
|
2685
3390
|
}
|
|
2686
3391
|
if (activeTab === "annotate") {
|
|
2687
|
-
const imgPt = (0,
|
|
3392
|
+
const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2688
3393
|
dragStartPointRef.current = imgPt;
|
|
2689
3394
|
if (state.activeTool === "select") {
|
|
2690
3395
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
2691
3396
|
const ann = state.annotations[i];
|
|
2692
|
-
if ((0,
|
|
3397
|
+
if ((0, import_image_editor18.hitTestAnnotation)(imgPt, ann)) {
|
|
2693
3398
|
editor.selectAnnotation(ann.id);
|
|
2694
3399
|
annotationDragInfoRef.current = {
|
|
2695
3400
|
annId: ann.id,
|
|
@@ -2725,7 +3430,7 @@ var ImageEditor = ({
|
|
|
2725
3430
|
const canvasPt = getCanvasEventPoint(e);
|
|
2726
3431
|
if (activeTab === "select") {
|
|
2727
3432
|
const gesture = selectionGestureRef.current;
|
|
2728
|
-
if (gesture.active && gesture.move((0,
|
|
3433
|
+
if (gesture.active && gesture.move((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
|
|
2729
3434
|
selectionDraftRef.current = gesture.draftPath;
|
|
2730
3435
|
renderCanvas();
|
|
2731
3436
|
}
|
|
@@ -2734,7 +3439,7 @@ var ImageEditor = ({
|
|
|
2734
3439
|
if (activeTab === "crop") {
|
|
2735
3440
|
const drag = cropDragInfoRef.current;
|
|
2736
3441
|
if (drag) {
|
|
2737
|
-
const currentImgPt = (0,
|
|
3442
|
+
const currentImgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
2738
3443
|
let newCrop;
|
|
2739
3444
|
if (drag.handle === "new") {
|
|
2740
3445
|
const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
|
|
@@ -2748,7 +3453,7 @@ var ImageEditor = ({
|
|
|
2748
3453
|
height: Math.round(Math.max(20, maxY - minY))
|
|
2749
3454
|
};
|
|
2750
3455
|
} else {
|
|
2751
|
-
newCrop = (0,
|
|
3456
|
+
newCrop = (0, import_image_editor18.calculateCropDrag)(
|
|
2752
3457
|
drag.startCrop,
|
|
2753
3458
|
drag.handle,
|
|
2754
3459
|
drag.startImgPt,
|
|
@@ -2768,15 +3473,15 @@ var ImageEditor = ({
|
|
|
2768
3473
|
width: state.imageDimensions.width,
|
|
2769
3474
|
height: state.imageDimensions.height
|
|
2770
3475
|
};
|
|
2771
|
-
const handle = (0,
|
|
2772
|
-
canvas.style.cursor = (0,
|
|
3476
|
+
const handle = (0, import_image_editor18.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
3477
|
+
canvas.style.cursor = (0, import_image_editor18.getCropCursor)(handle, state.transform);
|
|
2773
3478
|
}
|
|
2774
3479
|
return;
|
|
2775
3480
|
}
|
|
2776
3481
|
if (activeTab === "annotate" && state.activeTool === "shape") {
|
|
2777
3482
|
const g = shapeGestureRef.current;
|
|
2778
3483
|
if (g.active) {
|
|
2779
|
-
g.move((0,
|
|
3484
|
+
g.move((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), { shift: e.shiftKey, alt: e.altKey });
|
|
2780
3485
|
if (g.error) setShapeTypeError(g.error);
|
|
2781
3486
|
}
|
|
2782
3487
|
return;
|
|
@@ -2784,7 +3489,7 @@ var ImageEditor = ({
|
|
|
2784
3489
|
if (activeTab === "annotate") {
|
|
2785
3490
|
if (annotationDragInfoRef.current) {
|
|
2786
3491
|
const drag = annotationDragInfoRef.current;
|
|
2787
|
-
const currentImgPt2 = (0,
|
|
3492
|
+
const currentImgPt2 = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2788
3493
|
const dx = currentImgPt2.x - drag.startImgPt.x;
|
|
2789
3494
|
const dy = currentImgPt2.y - drag.startImgPt.y;
|
|
2790
3495
|
editor.updateAnnotation(drag.annId, {
|
|
@@ -2796,10 +3501,10 @@ var ImageEditor = ({
|
|
|
2796
3501
|
const startPt = dragStartPointRef.current;
|
|
2797
3502
|
if (!startPt) {
|
|
2798
3503
|
if (state.activeTool === "select") {
|
|
2799
|
-
const imgPt = (0,
|
|
3504
|
+
const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2800
3505
|
let hovered = false;
|
|
2801
3506
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
2802
|
-
if ((0,
|
|
3507
|
+
if ((0, import_image_editor18.hitTestAnnotation)(imgPt, state.annotations[i])) {
|
|
2803
3508
|
hovered = true;
|
|
2804
3509
|
break;
|
|
2805
3510
|
}
|
|
@@ -2810,7 +3515,7 @@ var ImageEditor = ({
|
|
|
2810
3515
|
}
|
|
2811
3516
|
return;
|
|
2812
3517
|
}
|
|
2813
|
-
const currentImgPt = (0,
|
|
3518
|
+
const currentImgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2814
3519
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
2815
3520
|
currentPathRef.current.push(currentImgPt);
|
|
2816
3521
|
const draft = {
|
|
@@ -2890,7 +3595,7 @@ var ImageEditor = ({
|
|
|
2890
3595
|
if (activeTab === "select") {
|
|
2891
3596
|
const gesture = selectionGestureRef.current;
|
|
2892
3597
|
if (gesture.active) {
|
|
2893
|
-
gesture.end((0,
|
|
3598
|
+
gesture.end((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
|
|
2894
3599
|
selectionDraftRef.current = null;
|
|
2895
3600
|
renderCanvas();
|
|
2896
3601
|
}
|
|
@@ -2913,7 +3618,7 @@ var ImageEditor = ({
|
|
|
2913
3618
|
}
|
|
2914
3619
|
if (activeTab === "annotate" && state.activeTool === "type") {
|
|
2915
3620
|
const tool = typeToolRef.current;
|
|
2916
|
-
tool.up((0,
|
|
3621
|
+
tool.up((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false));
|
|
2917
3622
|
setTypeSession(tool.session);
|
|
2918
3623
|
if (tool.error) setShapeTypeError(tool.error);
|
|
2919
3624
|
void renderCanvas();
|
|
@@ -2927,7 +3632,7 @@ var ImageEditor = ({
|
|
|
2927
3632
|
}
|
|
2928
3633
|
const startPt = dragStartPointRef.current;
|
|
2929
3634
|
if (startPt) {
|
|
2930
|
-
const currentImgPt = (0,
|
|
3635
|
+
const currentImgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2931
3636
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
2932
3637
|
if (currentPathRef.current.length > 1) {
|
|
2933
3638
|
editor.addAnnotation({
|
|
@@ -3023,15 +3728,15 @@ var ImageEditor = ({
|
|
|
3023
3728
|
link.click();
|
|
3024
3729
|
}
|
|
3025
3730
|
};
|
|
3026
|
-
return /* @__PURE__ */ (0,
|
|
3731
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3027
3732
|
"div",
|
|
3028
3733
|
{
|
|
3029
3734
|
className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
|
|
3030
3735
|
style,
|
|
3031
3736
|
children: [
|
|
3032
|
-
/* @__PURE__ */ (0,
|
|
3033
|
-
/* @__PURE__ */ (0,
|
|
3034
|
-
/* @__PURE__ */ (0,
|
|
3737
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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: [
|
|
3738
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
|
|
3739
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3035
3740
|
"button",
|
|
3036
3741
|
{
|
|
3037
3742
|
type: "button",
|
|
@@ -3043,7 +3748,7 @@ var ImageEditor = ({
|
|
|
3043
3748
|
children: "Transform & Crop"
|
|
3044
3749
|
}
|
|
3045
3750
|
),
|
|
3046
|
-
/* @__PURE__ */ (0,
|
|
3751
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3047
3752
|
"button",
|
|
3048
3753
|
{
|
|
3049
3754
|
type: "button",
|
|
@@ -3055,7 +3760,7 @@ var ImageEditor = ({
|
|
|
3055
3760
|
children: "Adjustments"
|
|
3056
3761
|
}
|
|
3057
3762
|
),
|
|
3058
|
-
/* @__PURE__ */ (0,
|
|
3763
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3059
3764
|
"button",
|
|
3060
3765
|
{
|
|
3061
3766
|
type: "button",
|
|
@@ -3067,7 +3772,7 @@ var ImageEditor = ({
|
|
|
3067
3772
|
children: "Layers"
|
|
3068
3773
|
}
|
|
3069
3774
|
),
|
|
3070
|
-
/* @__PURE__ */ (0,
|
|
3775
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3071
3776
|
"button",
|
|
3072
3777
|
{
|
|
3073
3778
|
type: "button",
|
|
@@ -3079,7 +3784,7 @@ var ImageEditor = ({
|
|
|
3079
3784
|
children: "Paint"
|
|
3080
3785
|
}
|
|
3081
3786
|
),
|
|
3082
|
-
/* @__PURE__ */ (0,
|
|
3787
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3083
3788
|
"button",
|
|
3084
3789
|
{
|
|
3085
3790
|
type: "button",
|
|
@@ -3091,7 +3796,7 @@ var ImageEditor = ({
|
|
|
3091
3796
|
children: "Select & Mask"
|
|
3092
3797
|
}
|
|
3093
3798
|
),
|
|
3094
|
-
/* @__PURE__ */ (0,
|
|
3799
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3095
3800
|
"button",
|
|
3096
3801
|
{
|
|
3097
3802
|
type: "button",
|
|
@@ -3103,7 +3808,7 @@ var ImageEditor = ({
|
|
|
3103
3808
|
children: "Annotations"
|
|
3104
3809
|
}
|
|
3105
3810
|
),
|
|
3106
|
-
/* @__PURE__ */ (0,
|
|
3811
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3107
3812
|
"button",
|
|
3108
3813
|
{
|
|
3109
3814
|
type: "button",
|
|
@@ -3115,7 +3820,7 @@ var ImageEditor = ({
|
|
|
3115
3820
|
children: "Depth Mask"
|
|
3116
3821
|
}
|
|
3117
3822
|
),
|
|
3118
|
-
/* @__PURE__ */ (0,
|
|
3823
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3119
3824
|
"button",
|
|
3120
3825
|
{
|
|
3121
3826
|
type: "button",
|
|
@@ -3125,14 +3830,14 @@ var ImageEditor = ({
|
|
|
3125
3830
|
},
|
|
3126
3831
|
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"}`,
|
|
3127
3832
|
children: [
|
|
3128
|
-
/* @__PURE__ */ (0,
|
|
3833
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.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" }) }),
|
|
3129
3834
|
"AI Tools"
|
|
3130
3835
|
]
|
|
3131
3836
|
}
|
|
3132
3837
|
)
|
|
3133
3838
|
] }),
|
|
3134
|
-
/* @__PURE__ */ (0,
|
|
3135
|
-
/* @__PURE__ */ (0,
|
|
3839
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
3840
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3136
3841
|
"button",
|
|
3137
3842
|
{
|
|
3138
3843
|
type: "button",
|
|
@@ -3143,7 +3848,7 @@ var ImageEditor = ({
|
|
|
3143
3848
|
children: "\u21A9"
|
|
3144
3849
|
}
|
|
3145
3850
|
),
|
|
3146
|
-
/* @__PURE__ */ (0,
|
|
3851
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3147
3852
|
"button",
|
|
3148
3853
|
{
|
|
3149
3854
|
type: "button",
|
|
@@ -3154,7 +3859,7 @@ var ImageEditor = ({
|
|
|
3154
3859
|
children: "\u21AA"
|
|
3155
3860
|
}
|
|
3156
3861
|
),
|
|
3157
|
-
/* @__PURE__ */ (0,
|
|
3862
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3158
3863
|
"button",
|
|
3159
3864
|
{
|
|
3160
3865
|
type: "button",
|
|
@@ -3163,8 +3868,8 @@ var ImageEditor = ({
|
|
|
3163
3868
|
children: "Reset"
|
|
3164
3869
|
}
|
|
3165
3870
|
),
|
|
3166
|
-
/* @__PURE__ */ (0,
|
|
3167
|
-
/* @__PURE__ */ (0,
|
|
3871
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
3872
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3168
3873
|
"button",
|
|
3169
3874
|
{
|
|
3170
3875
|
type: "button",
|
|
@@ -3174,11 +3879,11 @@ var ImageEditor = ({
|
|
|
3174
3879
|
children: "-"
|
|
3175
3880
|
}
|
|
3176
3881
|
),
|
|
3177
|
-
/* @__PURE__ */ (0,
|
|
3882
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
|
|
3178
3883
|
Math.round(state.zoom * 100),
|
|
3179
3884
|
"%"
|
|
3180
3885
|
] }),
|
|
3181
|
-
/* @__PURE__ */ (0,
|
|
3886
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3182
3887
|
"button",
|
|
3183
3888
|
{
|
|
3184
3889
|
type: "button",
|
|
@@ -3188,8 +3893,8 @@ var ImageEditor = ({
|
|
|
3188
3893
|
children: "+"
|
|
3189
3894
|
}
|
|
3190
3895
|
),
|
|
3191
|
-
/* @__PURE__ */ (0,
|
|
3192
|
-
/* @__PURE__ */ (0,
|
|
3896
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
3897
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3193
3898
|
"button",
|
|
3194
3899
|
{
|
|
3195
3900
|
type: "button",
|
|
@@ -3200,7 +3905,7 @@ var ImageEditor = ({
|
|
|
3200
3905
|
children: "Hold Compare"
|
|
3201
3906
|
}
|
|
3202
3907
|
),
|
|
3203
|
-
/* @__PURE__ */ (0,
|
|
3908
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3204
3909
|
"button",
|
|
3205
3910
|
{
|
|
3206
3911
|
type: "button",
|
|
@@ -3211,16 +3916,16 @@ var ImageEditor = ({
|
|
|
3211
3916
|
)
|
|
3212
3917
|
] })
|
|
3213
3918
|
] }),
|
|
3214
|
-
transformTool.active && /* @__PURE__ */ (0,
|
|
3215
|
-
!transformTool.active && transformTool.error && /* @__PURE__ */ (0,
|
|
3216
|
-
/* @__PURE__ */ (0,
|
|
3217
|
-
/* @__PURE__ */ (0,
|
|
3919
|
+
transformTool.active && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
|
|
3920
|
+
!transformTool.active && transformTool.error && /* @__PURE__ */ (0, import_jsx_runtime21.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 }),
|
|
3921
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
|
|
3922
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3218
3923
|
"div",
|
|
3219
3924
|
{
|
|
3220
3925
|
ref: containerRef,
|
|
3221
3926
|
className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
|
|
3222
3927
|
children: [
|
|
3223
|
-
/* @__PURE__ */ (0,
|
|
3928
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3224
3929
|
"canvas",
|
|
3225
3930
|
{
|
|
3226
3931
|
ref: canvasRef,
|
|
@@ -3237,7 +3942,7 @@ var ImageEditor = ({
|
|
|
3237
3942
|
className: `absolute inset-0 w-full h-full block ${transformTool.active ? "touch-none" : activeTab === "paint" ? "touch-none cursor-crosshair" : activeTab === "annotate" && state.activeTool === "type" ? "cursor-text" : activeTab === "annotate" && state.activeTool === "shape" ? "cursor-crosshair" : ""}`
|
|
3238
3943
|
}
|
|
3239
3944
|
),
|
|
3240
|
-
typeSession && /* @__PURE__ */ (0,
|
|
3945
|
+
typeSession && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3241
3946
|
"textarea",
|
|
3242
3947
|
{
|
|
3243
3948
|
ref: typeInputRef,
|
|
@@ -3259,11 +3964,11 @@ var ImageEditor = ({
|
|
|
3259
3964
|
]
|
|
3260
3965
|
}
|
|
3261
3966
|
),
|
|
3262
|
-
/* @__PURE__ */ (0,
|
|
3263
|
-
activeTab === "crop" && /* @__PURE__ */ (0,
|
|
3264
|
-
/* @__PURE__ */ (0,
|
|
3265
|
-
/* @__PURE__ */ (0,
|
|
3266
|
-
/* @__PURE__ */ (0,
|
|
3967
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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: [
|
|
3968
|
+
activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
3969
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
|
|
3970
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
3971
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3267
3972
|
"button",
|
|
3268
3973
|
{
|
|
3269
3974
|
type: "button",
|
|
@@ -3275,7 +3980,7 @@ var ImageEditor = ({
|
|
|
3275
3980
|
children: "Freeform"
|
|
3276
3981
|
}
|
|
3277
3982
|
),
|
|
3278
|
-
/* @__PURE__ */ (0,
|
|
3983
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3279
3984
|
"button",
|
|
3280
3985
|
{
|
|
3281
3986
|
type: "button",
|
|
@@ -3287,7 +3992,7 @@ var ImageEditor = ({
|
|
|
3287
3992
|
children: "1:1 Square"
|
|
3288
3993
|
}
|
|
3289
3994
|
),
|
|
3290
|
-
/* @__PURE__ */ (0,
|
|
3995
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3291
3996
|
"button",
|
|
3292
3997
|
{
|
|
3293
3998
|
type: "button",
|
|
@@ -3299,7 +4004,7 @@ var ImageEditor = ({
|
|
|
3299
4004
|
children: "4:3 Standard"
|
|
3300
4005
|
}
|
|
3301
4006
|
),
|
|
3302
|
-
/* @__PURE__ */ (0,
|
|
4007
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3303
4008
|
"button",
|
|
3304
4009
|
{
|
|
3305
4010
|
type: "button",
|
|
@@ -3311,7 +4016,7 @@ var ImageEditor = ({
|
|
|
3311
4016
|
children: "16:9 Wide"
|
|
3312
4017
|
}
|
|
3313
4018
|
),
|
|
3314
|
-
/* @__PURE__ */ (0,
|
|
4019
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3315
4020
|
"button",
|
|
3316
4021
|
{
|
|
3317
4022
|
type: "button",
|
|
@@ -3323,7 +4028,7 @@ var ImageEditor = ({
|
|
|
3323
4028
|
children: "3:2 Photo"
|
|
3324
4029
|
}
|
|
3325
4030
|
),
|
|
3326
|
-
/* @__PURE__ */ (0,
|
|
4031
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3327
4032
|
"button",
|
|
3328
4033
|
{
|
|
3329
4034
|
type: "button",
|
|
@@ -3336,10 +4041,10 @@ var ImageEditor = ({
|
|
|
3336
4041
|
}
|
|
3337
4042
|
)
|
|
3338
4043
|
] }),
|
|
3339
|
-
/* @__PURE__ */ (0,
|
|
3340
|
-
/* @__PURE__ */ (0,
|
|
3341
|
-
/* @__PURE__ */ (0,
|
|
3342
|
-
/* @__PURE__ */ (0,
|
|
4044
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
4045
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
|
|
4046
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
4047
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3343
4048
|
"button",
|
|
3344
4049
|
{
|
|
3345
4050
|
type: "button",
|
|
@@ -3348,7 +4053,7 @@ var ImageEditor = ({
|
|
|
3348
4053
|
children: "Rotate -90\xB0"
|
|
3349
4054
|
}
|
|
3350
4055
|
),
|
|
3351
|
-
/* @__PURE__ */ (0,
|
|
4056
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3352
4057
|
"button",
|
|
3353
4058
|
{
|
|
3354
4059
|
type: "button",
|
|
@@ -3357,7 +4062,7 @@ var ImageEditor = ({
|
|
|
3357
4062
|
children: "Rotate +90\xB0"
|
|
3358
4063
|
}
|
|
3359
4064
|
),
|
|
3360
|
-
/* @__PURE__ */ (0,
|
|
4065
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3361
4066
|
"button",
|
|
3362
4067
|
{
|
|
3363
4068
|
type: "button",
|
|
@@ -3366,7 +4071,7 @@ var ImageEditor = ({
|
|
|
3366
4071
|
children: "Flip Horizontal"
|
|
3367
4072
|
}
|
|
3368
4073
|
),
|
|
3369
|
-
/* @__PURE__ */ (0,
|
|
4074
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3370
4075
|
"button",
|
|
3371
4076
|
{
|
|
3372
4077
|
type: "button",
|
|
@@ -3377,10 +4082,10 @@ var ImageEditor = ({
|
|
|
3377
4082
|
)
|
|
3378
4083
|
] })
|
|
3379
4084
|
] }),
|
|
3380
|
-
activeTab === "adjust" && /* @__PURE__ */ (0,
|
|
3381
|
-
/* @__PURE__ */ (0,
|
|
3382
|
-
/* @__PURE__ */ (0,
|
|
3383
|
-
/* @__PURE__ */ (0,
|
|
4085
|
+
activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
4086
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
4087
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
|
|
4088
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3384
4089
|
"button",
|
|
3385
4090
|
{
|
|
3386
4091
|
type: "button",
|
|
@@ -3390,25 +4095,25 @@ var ImageEditor = ({
|
|
|
3390
4095
|
}
|
|
3391
4096
|
)
|
|
3392
4097
|
] }),
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3394
|
-
|
|
3395
|
-
/* @__PURE__ */ (0,
|
|
4098
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Histogram, { histogram: editor.histogram }),
|
|
4099
|
+
import_image_editor18.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react21.default.Fragment, { children: [
|
|
4100
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3396
4101
|
ControlSlider,
|
|
3397
4102
|
{
|
|
3398
4103
|
spec,
|
|
3399
|
-
value: (0,
|
|
4104
|
+
value: (0, import_image_editor18.readAdjustmentControls)(state.adjustments)[spec.id],
|
|
3400
4105
|
disabled: spec.requiresProcess !== void 0 && legacyProcess,
|
|
3401
4106
|
onChange: (v) => editor.setAdjustments({ [spec.id]: v })
|
|
3402
4107
|
}
|
|
3403
4108
|
),
|
|
3404
|
-
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0,
|
|
4109
|
+
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3405
4110
|
"div",
|
|
3406
4111
|
{
|
|
3407
4112
|
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",
|
|
3408
4113
|
"data-testid": "image-editor-process-notice",
|
|
3409
4114
|
children: [
|
|
3410
|
-
/* @__PURE__ */ (0,
|
|
3411
|
-
/* @__PURE__ */ (0,
|
|
4115
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
|
|
4116
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3412
4117
|
"button",
|
|
3413
4118
|
{
|
|
3414
4119
|
type: "button",
|
|
@@ -3421,7 +4126,7 @@ var ImageEditor = ({
|
|
|
3421
4126
|
}
|
|
3422
4127
|
)
|
|
3423
4128
|
] }, spec.id)),
|
|
3424
|
-
/* @__PURE__ */ (0,
|
|
4129
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3425
4130
|
AdjustmentLayersPanel,
|
|
3426
4131
|
{
|
|
3427
4132
|
controller,
|
|
@@ -3430,9 +4135,9 @@ var ImageEditor = ({
|
|
|
3430
4135
|
}
|
|
3431
4136
|
) })
|
|
3432
4137
|
] }),
|
|
3433
|
-
activeTab === "layers" && /* @__PURE__ */ (0,
|
|
3434
|
-
/* @__PURE__ */ (0,
|
|
3435
|
-
/* @__PURE__ */ (0,
|
|
4138
|
+
activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
4139
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
|
|
4140
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3436
4141
|
"button",
|
|
3437
4142
|
{
|
|
3438
4143
|
type: "button",
|
|
@@ -3443,14 +4148,15 @@ var ImageEditor = ({
|
|
|
3443
4148
|
children: "Free Transform"
|
|
3444
4149
|
}
|
|
3445
4150
|
),
|
|
3446
|
-
/* @__PURE__ */ (0,
|
|
3447
|
-
/* @__PURE__ */ (0,
|
|
3448
|
-
/* @__PURE__ */ (0,
|
|
4151
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LayersPanel, { controller }),
|
|
4152
|
+
effectsShown && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ImageProviderEffectsPanel, { controller, className: "border-t border-slate-700/60 pt-3" }),
|
|
4153
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Colour" }),
|
|
4154
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ColorProfilePanel, { controller })
|
|
3449
4155
|
] }),
|
|
3450
|
-
activeTab === "paint" && /* @__PURE__ */ (0,
|
|
3451
|
-
/* @__PURE__ */ (0,
|
|
3452
|
-
/* @__PURE__ */ (0,
|
|
3453
|
-
/* @__PURE__ */ (0,
|
|
4156
|
+
activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
4157
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
|
|
4158
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(BrushOptionsBar, { controller }),
|
|
4159
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3454
4160
|
"button",
|
|
3455
4161
|
{
|
|
3456
4162
|
type: "button",
|
|
@@ -3461,12 +4167,12 @@ var ImageEditor = ({
|
|
|
3461
4167
|
children: "Free Transform"
|
|
3462
4168
|
}
|
|
3463
4169
|
),
|
|
3464
|
-
paintError && /* @__PURE__ */ (0,
|
|
3465
|
-
/* @__PURE__ */ (0,
|
|
4170
|
+
paintError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
|
|
4171
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LayersPanel, { controller }) })
|
|
3466
4172
|
] }),
|
|
3467
|
-
activeTab === "annotate" && /* @__PURE__ */ (0,
|
|
3468
|
-
/* @__PURE__ */ (0,
|
|
3469
|
-
/* @__PURE__ */ (0,
|
|
4173
|
+
activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
4174
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
|
|
4175
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "grid grid-cols-2 gap-1.5", children: ["shape", "type"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3470
4176
|
"button",
|
|
3471
4177
|
{
|
|
3472
4178
|
type: "button",
|
|
@@ -3477,13 +4183,13 @@ var ImageEditor = ({
|
|
|
3477
4183
|
},
|
|
3478
4184
|
t
|
|
3479
4185
|
)) }),
|
|
3480
|
-
state.activeTool === "shape" && /* @__PURE__ */ (0,
|
|
3481
|
-
state.activeTool === "type" && /* @__PURE__ */ (0,
|
|
3482
|
-
state.activeTool === "type" && typeSession && /* @__PURE__ */ (0,
|
|
3483
|
-
shapeTypeError && /* @__PURE__ */ (0,
|
|
3484
|
-
/* @__PURE__ */ (0,
|
|
3485
|
-
/* @__PURE__ */ (0,
|
|
3486
|
-
/* @__PURE__ */ (0,
|
|
4186
|
+
state.activeTool === "shape" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
|
|
4187
|
+
state.activeTool === "type" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
|
|
4188
|
+
state.activeTool === "type" && typeSession && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: finishTyping, className: "self-start rounded bg-slate-800 px-2 py-1 text-[11px] text-slate-200 hover:bg-slate-700", children: "Done editing text" }),
|
|
4189
|
+
shapeTypeError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
|
|
4190
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
4191
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
|
|
4192
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3487
4193
|
"button",
|
|
3488
4194
|
{
|
|
3489
4195
|
type: "button",
|
|
@@ -3493,9 +4199,9 @@ var ImageEditor = ({
|
|
|
3493
4199
|
},
|
|
3494
4200
|
t
|
|
3495
4201
|
)) }),
|
|
3496
|
-
/* @__PURE__ */ (0,
|
|
3497
|
-
/* @__PURE__ */ (0,
|
|
3498
|
-
/* @__PURE__ */ (0,
|
|
4202
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
|
|
4203
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { className: "text-slate-400", children: "Color:" }),
|
|
4204
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3499
4205
|
"input",
|
|
3500
4206
|
{
|
|
3501
4207
|
type: "color",
|
|
@@ -3504,15 +4210,15 @@ var ImageEditor = ({
|
|
|
3504
4210
|
className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
|
|
3505
4211
|
}
|
|
3506
4212
|
),
|
|
3507
|
-
/* @__PURE__ */ (0,
|
|
3508
|
-
/* @__PURE__ */ (0,
|
|
3509
|
-
/* @__PURE__ */ (0,
|
|
3510
|
-
/* @__PURE__ */ (0,
|
|
4213
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex-1 ml-2", children: [
|
|
4214
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
|
|
4215
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Width:" }),
|
|
4216
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "font-mono", children: [
|
|
3511
4217
|
strokeWidth,
|
|
3512
4218
|
"px"
|
|
3513
4219
|
] })
|
|
3514
4220
|
] }),
|
|
3515
|
-
/* @__PURE__ */ (0,
|
|
4221
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3516
4222
|
"input",
|
|
3517
4223
|
{
|
|
3518
4224
|
type: "range",
|
|
@@ -3525,10 +4231,10 @@ var ImageEditor = ({
|
|
|
3525
4231
|
)
|
|
3526
4232
|
] })
|
|
3527
4233
|
] }),
|
|
3528
|
-
/* @__PURE__ */ (0,
|
|
3529
|
-
/* @__PURE__ */ (0,
|
|
3530
|
-
/* @__PURE__ */ (0,
|
|
3531
|
-
/* @__PURE__ */ (0,
|
|
4234
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
4235
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
|
|
4236
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex gap-2", children: [
|
|
4237
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3532
4238
|
"input",
|
|
3533
4239
|
{
|
|
3534
4240
|
type: "text",
|
|
@@ -3539,7 +4245,7 @@ var ImageEditor = ({
|
|
|
3539
4245
|
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"
|
|
3540
4246
|
}
|
|
3541
4247
|
),
|
|
3542
|
-
/* @__PURE__ */ (0,
|
|
4248
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3543
4249
|
"button",
|
|
3544
4250
|
{
|
|
3545
4251
|
type: "button",
|
|
@@ -3549,14 +4255,14 @@ var ImageEditor = ({
|
|
|
3549
4255
|
}
|
|
3550
4256
|
)
|
|
3551
4257
|
] }),
|
|
3552
|
-
/* @__PURE__ */ (0,
|
|
3553
|
-
/* @__PURE__ */ (0,
|
|
3554
|
-
/* @__PURE__ */ (0,
|
|
4258
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
|
|
4259
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Font Size:" }),
|
|
4260
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "font-mono", children: [
|
|
3555
4261
|
fontSize,
|
|
3556
4262
|
"px"
|
|
3557
4263
|
] })
|
|
3558
4264
|
] }),
|
|
3559
|
-
/* @__PURE__ */ (0,
|
|
4265
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3560
4266
|
"input",
|
|
3561
4267
|
{
|
|
3562
4268
|
type: "range",
|
|
@@ -3567,14 +4273,14 @@ var ImageEditor = ({
|
|
|
3567
4273
|
className: "w-full accent-indigo-500"
|
|
3568
4274
|
}
|
|
3569
4275
|
),
|
|
3570
|
-
/* @__PURE__ */ (0,
|
|
3571
|
-
/* @__PURE__ */ (0,
|
|
3572
|
-
/* @__PURE__ */ (0,
|
|
4276
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
4277
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
4278
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-slate-400", children: [
|
|
3573
4279
|
"Layers (",
|
|
3574
4280
|
state.annotations.length,
|
|
3575
4281
|
")"
|
|
3576
4282
|
] }),
|
|
3577
|
-
state.selectedAnnotationId && /* @__PURE__ */ (0,
|
|
4283
|
+
state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3578
4284
|
"button",
|
|
3579
4285
|
{
|
|
3580
4286
|
type: "button",
|
|
@@ -3583,7 +4289,7 @@ var ImageEditor = ({
|
|
|
3583
4289
|
children: "Delete Selected"
|
|
3584
4290
|
}
|
|
3585
4291
|
),
|
|
3586
|
-
state.annotations.length > 0 && /* @__PURE__ */ (0,
|
|
4292
|
+
state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3587
4293
|
"button",
|
|
3588
4294
|
{
|
|
3589
4295
|
type: "button",
|
|
@@ -3594,10 +4300,10 @@ var ImageEditor = ({
|
|
|
3594
4300
|
)
|
|
3595
4301
|
] })
|
|
3596
4302
|
] }),
|
|
3597
|
-
activeTab === "depth" && /* @__PURE__ */ (0,
|
|
3598
|
-
/* @__PURE__ */ (0,
|
|
3599
|
-
/* @__PURE__ */ (0,
|
|
3600
|
-
/* @__PURE__ */ (0,
|
|
4303
|
+
activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
4304
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
4305
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
|
|
4306
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3601
4307
|
"button",
|
|
3602
4308
|
{
|
|
3603
4309
|
type: "button",
|
|
@@ -3607,8 +4313,8 @@ var ImageEditor = ({
|
|
|
3607
4313
|
}
|
|
3608
4314
|
)
|
|
3609
4315
|
] }),
|
|
3610
|
-
/* @__PURE__ */ (0,
|
|
3611
|
-
/* @__PURE__ */ (0,
|
|
4316
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
|
|
4317
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3612
4318
|
"input",
|
|
3613
4319
|
{
|
|
3614
4320
|
type: "checkbox",
|
|
@@ -3617,12 +4323,12 @@ var ImageEditor = ({
|
|
|
3617
4323
|
className: "rounded accent-indigo-500"
|
|
3618
4324
|
}
|
|
3619
4325
|
),
|
|
3620
|
-
/* @__PURE__ */ (0,
|
|
4326
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Enable Depth / Alpha Mask" })
|
|
3621
4327
|
] }),
|
|
3622
|
-
state.depthMask.enabled && /* @__PURE__ */ (0,
|
|
3623
|
-
/* @__PURE__ */ (0,
|
|
3624
|
-
/* @__PURE__ */ (0,
|
|
3625
|
-
/* @__PURE__ */ (0,
|
|
4328
|
+
state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
4329
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
|
|
4330
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
|
|
4331
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3626
4332
|
"input",
|
|
3627
4333
|
{
|
|
3628
4334
|
type: "text",
|
|
@@ -3633,8 +4339,8 @@ var ImageEditor = ({
|
|
|
3633
4339
|
}
|
|
3634
4340
|
)
|
|
3635
4341
|
] }),
|
|
3636
|
-
/* @__PURE__ */ (0,
|
|
3637
|
-
/* @__PURE__ */ (0,
|
|
4342
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex gap-2", children: [
|
|
4343
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3638
4344
|
"button",
|
|
3639
4345
|
{
|
|
3640
4346
|
type: "button",
|
|
@@ -3643,7 +4349,7 @@ var ImageEditor = ({
|
|
|
3643
4349
|
children: "Threshold Mode"
|
|
3644
4350
|
}
|
|
3645
4351
|
),
|
|
3646
|
-
/* @__PURE__ */ (0,
|
|
4352
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3647
4353
|
"button",
|
|
3648
4354
|
{
|
|
3649
4355
|
type: "button",
|
|
@@ -3653,12 +4359,12 @@ var ImageEditor = ({
|
|
|
3653
4359
|
}
|
|
3654
4360
|
)
|
|
3655
4361
|
] }),
|
|
3656
|
-
/* @__PURE__ */ (0,
|
|
3657
|
-
/* @__PURE__ */ (0,
|
|
3658
|
-
/* @__PURE__ */ (0,
|
|
3659
|
-
/* @__PURE__ */ (0,
|
|
4362
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
|
|
4363
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
4364
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Depth Start (Lower):" }),
|
|
4365
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
|
|
3660
4366
|
] }),
|
|
3661
|
-
/* @__PURE__ */ (0,
|
|
4367
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3662
4368
|
"input",
|
|
3663
4369
|
{
|
|
3664
4370
|
type: "range",
|
|
@@ -3672,12 +4378,12 @@ var ImageEditor = ({
|
|
|
3672
4378
|
}
|
|
3673
4379
|
)
|
|
3674
4380
|
] }),
|
|
3675
|
-
/* @__PURE__ */ (0,
|
|
3676
|
-
/* @__PURE__ */ (0,
|
|
3677
|
-
/* @__PURE__ */ (0,
|
|
3678
|
-
/* @__PURE__ */ (0,
|
|
4381
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
|
|
4382
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
4383
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Depth Stop (Upper):" }),
|
|
4384
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
|
|
3679
4385
|
] }),
|
|
3680
|
-
/* @__PURE__ */ (0,
|
|
4386
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3681
4387
|
"input",
|
|
3682
4388
|
{
|
|
3683
4389
|
type: "range",
|
|
@@ -3691,12 +4397,12 @@ var ImageEditor = ({
|
|
|
3691
4397
|
}
|
|
3692
4398
|
)
|
|
3693
4399
|
] }),
|
|
3694
|
-
/* @__PURE__ */ (0,
|
|
3695
|
-
/* @__PURE__ */ (0,
|
|
3696
|
-
/* @__PURE__ */ (0,
|
|
3697
|
-
/* @__PURE__ */ (0,
|
|
4400
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
|
|
4401
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
4402
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Softness:" }),
|
|
4403
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
|
|
3698
4404
|
] }),
|
|
3699
|
-
/* @__PURE__ */ (0,
|
|
4405
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3700
4406
|
"input",
|
|
3701
4407
|
{
|
|
3702
4408
|
type: "range",
|
|
@@ -3708,8 +4414,8 @@ var ImageEditor = ({
|
|
|
3708
4414
|
}
|
|
3709
4415
|
)
|
|
3710
4416
|
] }),
|
|
3711
|
-
/* @__PURE__ */ (0,
|
|
3712
|
-
/* @__PURE__ */ (0,
|
|
4417
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
|
|
4418
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3713
4419
|
"input",
|
|
3714
4420
|
{
|
|
3715
4421
|
type: "checkbox",
|
|
@@ -3718,12 +4424,12 @@ var ImageEditor = ({
|
|
|
3718
4424
|
className: "rounded accent-indigo-500"
|
|
3719
4425
|
}
|
|
3720
4426
|
),
|
|
3721
|
-
/* @__PURE__ */ (0,
|
|
4427
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Invert Mask" })
|
|
3722
4428
|
] })
|
|
3723
4429
|
] })
|
|
3724
4430
|
] }),
|
|
3725
|
-
activeTab === "select" && /* @__PURE__ */ (0,
|
|
3726
|
-
/* @__PURE__ */ (0,
|
|
4431
|
+
activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
4432
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3727
4433
|
SelectionOptionsBar,
|
|
3728
4434
|
{
|
|
3729
4435
|
controller,
|
|
@@ -3733,9 +4439,9 @@ var ImageEditor = ({
|
|
|
3733
4439
|
quickMask: Boolean(state.quickMask)
|
|
3734
4440
|
}
|
|
3735
4441
|
),
|
|
3736
|
-
selectionError && /* @__PURE__ */ (0,
|
|
3737
|
-
/* @__PURE__ */ (0,
|
|
3738
|
-
/* @__PURE__ */ (0,
|
|
4442
|
+
selectionError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
|
|
4443
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex gap-1", children: [
|
|
4444
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3739
4445
|
"button",
|
|
3740
4446
|
{
|
|
3741
4447
|
type: "button",
|
|
@@ -3746,7 +4452,7 @@ var ImageEditor = ({
|
|
|
3746
4452
|
children: "Transform Selection"
|
|
3747
4453
|
}
|
|
3748
4454
|
),
|
|
3749
|
-
/* @__PURE__ */ (0,
|
|
4455
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3750
4456
|
"button",
|
|
3751
4457
|
{
|
|
3752
4458
|
type: "button",
|
|
@@ -3758,12 +4464,12 @@ var ImageEditor = ({
|
|
|
3758
4464
|
}
|
|
3759
4465
|
)
|
|
3760
4466
|
] }),
|
|
3761
|
-
/* @__PURE__ */ (0,
|
|
4467
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
|
|
3762
4468
|
] }),
|
|
3763
|
-
activeTab === "ai" && /* @__PURE__ */ (0,
|
|
3764
|
-
/* @__PURE__ */ (0,
|
|
3765
|
-
/* @__PURE__ */ (0,
|
|
3766
|
-
/* @__PURE__ */ (0,
|
|
4469
|
+
activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
4470
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
|
|
4471
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Results go to" }),
|
|
4472
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3767
4473
|
"select",
|
|
3768
4474
|
{
|
|
3769
4475
|
"aria-label": "AI result target",
|
|
@@ -3771,54 +4477,54 @@ var ImageEditor = ({
|
|
|
3771
4477
|
onChange: (e) => setAiTarget(e.target.value),
|
|
3772
4478
|
className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
|
|
3773
4479
|
children: [
|
|
3774
|
-
/* @__PURE__ */ (0,
|
|
3775
|
-
/* @__PURE__ */ (0,
|
|
3776
|
-
/* @__PURE__ */ (0,
|
|
4480
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
|
|
4481
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
|
|
4482
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "replace", children: "Replace image" })
|
|
3777
4483
|
]
|
|
3778
4484
|
}
|
|
3779
4485
|
)
|
|
3780
4486
|
] }),
|
|
3781
|
-
/* @__PURE__ */ (0,
|
|
3782
|
-
/* @__PURE__ */ (0,
|
|
3783
|
-
/* @__PURE__ */ (0,
|
|
3784
|
-
/* @__PURE__ */ (0,
|
|
4487
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
4488
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
4489
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
4490
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.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" }) }),
|
|
3785
4491
|
"Background Removal"
|
|
3786
4492
|
] }),
|
|
3787
|
-
isRemovingBg && /* @__PURE__ */ (0,
|
|
4493
|
+
isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime21.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..." })
|
|
3788
4494
|
] }),
|
|
3789
|
-
/* @__PURE__ */ (0,
|
|
3790
|
-
/* @__PURE__ */ (0,
|
|
4495
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
|
|
4496
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3791
4497
|
"button",
|
|
3792
4498
|
{
|
|
3793
4499
|
type: "button",
|
|
3794
4500
|
onClick: handleRemoveBackground,
|
|
3795
4501
|
disabled: isRemovingBg || isInpainting,
|
|
3796
4502
|
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",
|
|
3797
|
-
children: isRemovingBg ? /* @__PURE__ */ (0,
|
|
3798
|
-
/* @__PURE__ */ (0,
|
|
4503
|
+
children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
4504
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
3799
4505
|
"Removing Background..."
|
|
3800
|
-
] }) : /* @__PURE__ */ (0,
|
|
3801
|
-
/* @__PURE__ */ (0,
|
|
4506
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
4507
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.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" }) }),
|
|
3802
4508
|
"Remove Background"
|
|
3803
4509
|
] })
|
|
3804
4510
|
}
|
|
3805
4511
|
)
|
|
3806
4512
|
] }),
|
|
3807
|
-
/* @__PURE__ */ (0,
|
|
3808
|
-
/* @__PURE__ */ (0,
|
|
3809
|
-
/* @__PURE__ */ (0,
|
|
3810
|
-
/* @__PURE__ */ (0,
|
|
3811
|
-
/* @__PURE__ */ (0,
|
|
3812
|
-
/* @__PURE__ */ (0,
|
|
4513
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
4514
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
4515
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
4516
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
4517
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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" }),
|
|
4518
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "m14 7 3 3" })
|
|
3813
4519
|
] }),
|
|
3814
4520
|
"Generative Inpainting"
|
|
3815
4521
|
] }),
|
|
3816
|
-
isInpainting && /* @__PURE__ */ (0,
|
|
4522
|
+
isInpainting && /* @__PURE__ */ (0, import_jsx_runtime21.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..." })
|
|
3817
4523
|
] }),
|
|
3818
|
-
/* @__PURE__ */ (0,
|
|
3819
|
-
/* @__PURE__ */ (0,
|
|
3820
|
-
/* @__PURE__ */ (0,
|
|
3821
|
-
/* @__PURE__ */ (0,
|
|
4524
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
|
|
4525
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
4526
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
|
|
4527
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3822
4528
|
"textarea",
|
|
3823
4529
|
{
|
|
3824
4530
|
id: "ai-inpaint-prompt-react",
|
|
@@ -3830,10 +4536,10 @@ var ImageEditor = ({
|
|
|
3830
4536
|
}
|
|
3831
4537
|
)
|
|
3832
4538
|
] }),
|
|
3833
|
-
/* @__PURE__ */ (0,
|
|
3834
|
-
/* @__PURE__ */ (0,
|
|
3835
|
-
/* @__PURE__ */ (0,
|
|
3836
|
-
/* @__PURE__ */ (0,
|
|
4539
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
4540
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
|
|
4541
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
|
|
4542
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3837
4543
|
"button",
|
|
3838
4544
|
{
|
|
3839
4545
|
type: "button",
|
|
@@ -3846,7 +4552,7 @@ var ImageEditor = ({
|
|
|
3846
4552
|
]
|
|
3847
4553
|
}
|
|
3848
4554
|
),
|
|
3849
|
-
/* @__PURE__ */ (0,
|
|
4555
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3850
4556
|
"button",
|
|
3851
4557
|
{
|
|
3852
4558
|
type: "button",
|
|
@@ -3861,25 +4567,25 @@ var ImageEditor = ({
|
|
|
3861
4567
|
)
|
|
3862
4568
|
] })
|
|
3863
4569
|
] }),
|
|
3864
|
-
/* @__PURE__ */ (0,
|
|
4570
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3865
4571
|
"button",
|
|
3866
4572
|
{
|
|
3867
4573
|
type: "button",
|
|
3868
4574
|
onClick: handleInpaint,
|
|
3869
4575
|
disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
|
|
3870
4576
|
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",
|
|
3871
|
-
children: isInpainting ? /* @__PURE__ */ (0,
|
|
3872
|
-
/* @__PURE__ */ (0,
|
|
4577
|
+
children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
4578
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
3873
4579
|
"Generating Inpaint..."
|
|
3874
|
-
] }) : /* @__PURE__ */ (0,
|
|
3875
|
-
/* @__PURE__ */ (0,
|
|
4580
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
4581
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.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" }) }),
|
|
3876
4582
|
"Apply Inpainting"
|
|
3877
4583
|
] })
|
|
3878
4584
|
}
|
|
3879
4585
|
)
|
|
3880
4586
|
] }),
|
|
3881
|
-
aiError && /* @__PURE__ */ (0,
|
|
3882
|
-
aiSuccess && /* @__PURE__ */ (0,
|
|
4587
|
+
aiError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
|
|
4588
|
+
aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
|
|
3883
4589
|
] })
|
|
3884
4590
|
] })
|
|
3885
4591
|
] })
|
|
@@ -3897,6 +4603,7 @@ var ImageEditor = ({
|
|
|
3897
4603
|
FreeTransformOptionsBar,
|
|
3898
4604
|
Histogram,
|
|
3899
4605
|
ImageEditor,
|
|
4606
|
+
ImageProviderEffectsPanel,
|
|
3900
4607
|
LayerEffectsPanel,
|
|
3901
4608
|
LayersPanel,
|
|
3902
4609
|
PaintGradientEditor,
|
|
@@ -3905,6 +4612,7 @@ var ImageEditor = ({
|
|
|
3905
4612
|
ShapeOptionsBar,
|
|
3906
4613
|
TypeOptionsBar,
|
|
3907
4614
|
useImageEditor,
|
|
4615
|
+
useImageEffectsTools,
|
|
3908
4616
|
useImageHistogram
|
|
3909
4617
|
});
|
|
3910
4618
|
//# sourceMappingURL=index.cjs.map
|