@pixerate/editor-react 0.76.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.
Files changed (49) hide show
  1. package/dist/PaintGradientEditorView-CCPCY5Ib.d.cts +14 -0
  2. package/dist/PaintGradientEditorView-CCPCY5Ib.d.ts +14 -0
  3. package/dist/canvas/index.cjs +662 -561
  4. package/dist/canvas/index.cjs.map +1 -1
  5. package/dist/canvas/index.d.cts +36 -5
  6. package/dist/canvas/index.d.ts +36 -5
  7. package/dist/canvas/index.js +232 -129
  8. package/dist/canvas/index.js.map +1 -1
  9. package/dist/{chunk-LWMUV5TC.js → chunk-2EW42UXC.js} +639 -461
  10. package/dist/chunk-2EW42UXC.js.map +1 -0
  11. package/dist/chunk-FX3EREF5.js +206 -0
  12. package/dist/chunk-FX3EREF5.js.map +1 -0
  13. package/dist/chunk-MO354USR.js +126 -0
  14. package/dist/chunk-MO354USR.js.map +1 -0
  15. package/dist/chunk-ZQZAKUUM.js +416 -0
  16. package/dist/chunk-ZQZAKUUM.js.map +1 -0
  17. package/dist/effects/index.cjs +606 -0
  18. package/dist/effects/index.cjs.map +1 -0
  19. package/dist/effects/index.d.cts +80 -0
  20. package/dist/effects/index.d.ts +80 -0
  21. package/dist/effects/index.js +16 -0
  22. package/dist/effects/index.js.map +1 -0
  23. package/dist/image-editor/index.cjs +1388 -534
  24. package/dist/image-editor/index.cjs.map +1 -1
  25. package/dist/image-editor/index.d.cts +36 -3
  26. package/dist/image-editor/index.d.ts +36 -3
  27. package/dist/image-editor/index.js +10 -1
  28. package/dist/index.cjs +1806 -952
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +4 -1
  31. package/dist/index.d.ts +4 -1
  32. package/dist/index.js +10 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/paint-editor/index.cjs +438 -289
  35. package/dist/paint-editor/index.cjs.map +1 -1
  36. package/dist/paint-editor/index.d.cts +8 -3
  37. package/dist/paint-editor/index.d.ts +8 -3
  38. package/dist/paint-editor/index.js +215 -187
  39. package/dist/paint-editor/index.js.map +1 -1
  40. package/dist/parameters/index.js +55 -439
  41. package/dist/parameters/index.js.map +1 -1
  42. package/dist/video-editor/index.cjs +732 -17
  43. package/dist/video-editor/index.cjs.map +1 -1
  44. package/dist/video-editor/index.d.cts +31 -3
  45. package/dist/video-editor/index.d.ts +31 -3
  46. package/dist/video-editor/index.js +184 -17
  47. package/dist/video-editor/index.js.map +1 -1
  48. package/package.json +8 -3
  49. package/dist/chunk-LWMUV5TC.js.map +0 -1
@@ -38,13 +38,16 @@ __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,
44
+ PaintGradientEditor: () => PaintGradientEditor,
43
45
  RefineEdgePanel: () => RefineEdgePanel,
44
46
  SelectionOptionsBar: () => SelectionOptionsBar,
45
47
  ShapeOptionsBar: () => ShapeOptionsBar,
46
48
  TypeOptionsBar: () => TypeOptionsBar,
47
49
  useImageEditor: () => useImageEditor,
50
+ useImageEffectsTools: () => useImageEffectsTools,
48
51
  useImageHistogram: () => useImageHistogram
49
52
  });
50
53
  module.exports = __toCommonJS(image_editor_exports);
@@ -206,10 +209,17 @@ function useImageEditor(options = {}) {
206
209
  [controller, state, historyTicks, histogram]
207
210
  );
208
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
+ }
209
219
 
210
220
  // src/image-editor/ImageEditor.tsx
211
- var import_react14 = __toESM(require("react"), 1);
212
- var import_image_editor15 = require("@pixerate/editor/image-editor");
221
+ var import_react21 = __toESM(require("react"), 1);
222
+ var import_image_editor18 = require("@pixerate/editor/image-editor");
213
223
 
214
224
  // src/image-editor/ControlSlider.tsx
215
225
  var import_image_editor2 = require("@pixerate/editor/image-editor");
@@ -1258,17 +1268,840 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1258
1268
  ] });
1259
1269
  };
1260
1270
 
1261
- // src/image-editor/BrushOptionsBar.tsx
1262
- var import_react7 = require("react");
1271
+ // src/image-editor/ImageProviderEffectsPanel.tsx
1272
+ var import_react12 = __toESM(require("react"), 1);
1263
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
1301
+ var import_react8 = require("react");
1302
+ var import_effects = require("@pixerate/editor/effects");
1264
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");
1964
+ var import_image_editor10 = require("@pixerate/editor/image-editor");
1965
+ var import_image_editor11 = require("@pixerate/editor/image-editor");
1966
+
1967
+ // src/image-editor/PaintGradientEditor.tsx
1968
+ var import_image_editor9 = require("@pixerate/editor/image-editor");
1969
+
1970
+ // src/paint-editor/PaintGradientEditorView.tsx
1971
+ var import_react13 = require("react");
1972
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1973
+ var button2 = "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40";
1974
+ var select = "rounded bg-slate-800 px-1 py-0.5 text-[11px]";
1975
+ var number = "w-16 rounded bg-slate-800 px-1 py-0.5 text-[11px]";
1976
+ var pct = (v) => Math.round(v * 1e3) / 10;
1977
+ var PaintGradientEditorView = ({ value, onChange, colors, className, kit }) => {
1978
+ const {
1979
+ PAINT_GRADIENT_MAPPINGS,
1980
+ PAINT_GRADIENT_MAPPING_LABELS,
1981
+ PAINT_GRADIENT_PRESETS,
1982
+ PAINT_GRADIENT_REPEATS,
1983
+ PAINT_GRADIENT_REPEAT_LABELS,
1984
+ PAINT_GRADIENT_SPACES,
1985
+ PAINT_GRADIENT_SPACE_LABELS,
1986
+ addPaintGradientStop,
1987
+ paintGradientMappingFor,
1988
+ paintSourceCss,
1989
+ removePaintGradientStop,
1990
+ reversePaintGradient,
1991
+ updatePaintGradientStop
1992
+ } = kit;
1993
+ const [selected, setSelected] = (0, import_react13.useState)(0);
1994
+ const sel = Math.min(selected, value.stops.length - 1);
1995
+ const stop = value.stops[sel];
1996
+ const map = value.map;
1997
+ const stopHex = (c) => c === "paint" ? colors.paint : c === "secondary" ? colors.secondary : c;
1998
+ const patchStop = (patch) => {
1999
+ const r = updatePaintGradientStop(value, sel, patch);
2000
+ setSelected(r.index);
2001
+ onChange(r.paint);
2002
+ };
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))
2008
+ ] }),
2009
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: button2, onClick: () => onChange(reversePaintGradient(value)), children: "Reverse" })
2010
+ ] }),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2012
+ "div",
2013
+ {
2014
+ role: "slider",
2015
+ tabIndex: 0,
2016
+ "aria-label": "Gradient ramp: click to add a stop",
2017
+ "aria-valuemin": 0,
2018
+ "aria-valuemax": 100,
2019
+ "aria-valuenow": pct(stop.offset),
2020
+ "data-testid": "paint-gradient-ramp",
2021
+ className: "relative h-6 cursor-copy rounded ring-1 ring-slate-700",
2022
+ style: { background: paintSourceCss(value, colors) },
2023
+ onClick: (e) => {
2024
+ const rect = e.currentTarget.getBoundingClientRect();
2025
+ const r = addPaintGradientStop(value, rect.width ? (e.clientX - rect.left) / rect.width : 0.5, colors);
2026
+ if (r.index >= 0) {
2027
+ setSelected(r.index);
2028
+ onChange(r.paint);
2029
+ }
2030
+ }
2031
+ }
2032
+ ),
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)(
2034
+ "button",
2035
+ {
2036
+ type: "button",
2037
+ "aria-label": `Stop ${i + 1} at ${pct(s.offset)}%`,
2038
+ "aria-pressed": i === sel,
2039
+ className: `absolute top-0 h-4 w-3 -translate-x-1/2 rounded-sm ring-1 ${i === sel ? "ring-white" : "ring-slate-600"}`,
2040
+ style: { left: `${s.offset * 100}%`, background: stopHex(s.color) },
2041
+ onClick: () => setSelected(i)
2042
+ },
2043
+ i
2044
+ )) }),
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" })
2050
+ ] }),
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: [
2053
+ "At",
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 }),
2055
+ "%"
2056
+ ] }),
2057
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
2058
+ "Opacity",
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 }),
2060
+ "%"
2061
+ ] }),
2062
+ sel < value.stops.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
2063
+ "Midpoint",
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 }),
2065
+ "%"
2066
+ ] }),
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" })
2068
+ ] }),
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" })
2076
+ ] })
2077
+ ] }),
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)) })
2081
+ ] }),
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: [
2085
+ "Softness",
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" })
2087
+ ] })
2088
+ ] })
2089
+ ] });
2090
+ };
2091
+
2092
+ // src/image-editor/PaintGradientEditor.tsx
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 });
2095
+
2096
+ // src/image-editor/BrushOptionsBar.tsx
2097
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1265
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"}`;
1266
2099
  var BrushOptionsBar = ({ controller, className }) => {
1267
- const [, setTick] = (0, import_react7.useState)(0);
1268
- (0, import_react7.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1269
- const [error, setError] = (0, import_react7.useState)(null);
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);
1270
2103
  const state = controller.getState();
1271
- const { brush, foreground, background, mixer, mixerLoad, retouch, cloneSource } = state.paint;
2104
+ const { brush, foreground, background, mixer, mixerLoad, retouch, cloneSource, paint } = state.paint;
1272
2105
  const tool = state.activeTool;
1273
2106
  const attempt = (fn) => {
1274
2107
  try {
@@ -1278,8 +2111,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1278
2111
  setError(err instanceof Error ? err.message : String(err));
1279
2112
  }
1280
2113
  };
1281
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
1282
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor8.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1283
2116
  "button",
1284
2117
  {
1285
2118
  type: "button",
@@ -1291,9 +2124,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1291
2124
  },
1292
2125
  t.id
1293
2126
  )) }),
1294
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
1295
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1", children: [
1296
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1297
2130
  "input",
1298
2131
  {
1299
2132
  type: "color",
@@ -1303,10 +2136,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1303
2136
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1304
2137
  }
1305
2138
  ),
1306
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", children: "FG" })
2139
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-400", children: "FG" })
1307
2140
  ] }),
1308
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1", children: [
1309
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2141
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1", children: [
2142
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1310
2143
  "input",
1311
2144
  {
1312
2145
  type: "color",
@@ -1316,12 +2149,24 @@ var BrushOptionsBar = ({ controller, className }) => {
1316
2149
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1317
2150
  }
1318
2151
  ),
1319
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", children: "BG" })
2152
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-400", children: "BG" })
1320
2153
  ] }),
1321
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
1322
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
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)(
2157
+ "button",
2158
+ {
2159
+ type: "button",
2160
+ "aria-pressed": paint.type === "gradient",
2161
+ title: "Gradient paint: the brush changes colour as the stroke goes",
2162
+ className: chip(paint.type === "gradient"),
2163
+ onClick: () => attempt(() => controller.setPaintOptions(paint.type === "gradient" ? { foreground } : { paint: import_image_editor11.DEFAULT_PAINT_GRADIENT })),
2164
+ children: "Gradient"
2165
+ }
2166
+ )
1323
2167
  ] }),
1324
- import_image_editor8.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1325
2170
  ControlSlider,
1326
2171
  {
1327
2172
  spec,
@@ -1330,21 +2175,21 @@ var BrushOptionsBar = ({ controller, className }) => {
1330
2175
  },
1331
2176
  spec.id
1332
2177
  )),
1333
- state.activeTool === "mixer" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2 border-t border-slate-800 pt-2", role: "group", "aria-label": "Mixer Brush", "data-testid": "mixer-options", children: [
1334
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [
1335
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1336
2181
  "span",
1337
2182
  {
1338
2183
  "aria-label": "Brush load",
1339
- title: mixerLoad.reservoir ? `Loaded ${(0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
2184
+ title: mixerLoad.reservoir ? `Loaded ${(0, import_image_editor10.rgbUnitToHex)(mixerLoad.reservoir)}, ${Math.round(mixerLoad.amount * 100)}% left` : "Unloaded",
1340
2185
  className: "h-6 w-6 rounded border border-slate-700",
1341
- style: { background: mixerLoad.reservoir ? (0, import_image_editor8.rgbUnitToHex)(mixerLoad.reservoir) : "transparent" }
2186
+ style: { background: mixerLoad.reservoir ? (0, import_image_editor10.rgbUnitToHex)(mixerLoad.reservoir) : "transparent" }
1342
2187
  }
1343
2188
  ),
1344
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
1345
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
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" })
1346
2191
  ] }),
1347
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: import_image_editor8.MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1348
2193
  "button",
1349
2194
  {
1350
2195
  type: "button",
@@ -1356,10 +2201,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1356
2201
  },
1357
2202
  m.id
1358
2203
  )) }),
1359
- import_image_editor8.MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
1360
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
1361
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1362
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1363
2208
  "input",
1364
2209
  {
1365
2210
  type: "checkbox",
@@ -1371,8 +2216,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1371
2216
  ),
1372
2217
  "Load each stroke"
1373
2218
  ] }),
1374
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1375
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2219
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1.5", children: [
2220
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1376
2221
  "input",
1377
2222
  {
1378
2223
  type: "checkbox",
@@ -1386,29 +2231,29 @@ var BrushOptionsBar = ({ controller, className }) => {
1386
2231
  ] })
1387
2232
  ] })
1388
2233
  ] }),
1389
- (0, import_image_editor8.isRetouchPaintTool)(tool) && /* @__PURE__ */ (0, import_jsx_runtime7.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: [
1390
- (tool === "clone" || tool === "heal") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [
1391
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", "data-testid": "clone-source", children: (0, import_image_editor8.cloneSourceLabel)(controller) }),
1392
- cloneSource && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", title: "Forget the source point", className: chip(false), onClick: () => controller.setCloneSource(null), children: "Clear source" })
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" })
1393
2238
  ] }),
1394
- import_image_editor8.RETOUCH_CHOICES.filter((c) => c.tools.includes(tool)).map((choice) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": choice.label, children: [
1395
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-slate-400", children: choice.label }),
1396
- choice.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1397
2242
  "button",
1398
2243
  {
1399
2244
  type: "button",
1400
2245
  "aria-pressed": retouch[choice.id] === o.id,
1401
2246
  title: o.title,
1402
2247
  className: chip(retouch[choice.id] === o.id),
1403
- onClick: () => (0, import_image_editor8.setRetouchChoice)(controller, choice.id, o.id),
2248
+ onClick: () => (0, import_image_editor10.setRetouchChoice)(controller, choice.id, o.id),
1404
2249
  children: o.label
1405
2250
  },
1406
2251
  o.id
1407
2252
  ))
1408
2253
  ] }, choice.id)),
1409
- import_image_editor8.RETOUCH_OPTION_CONTROLS.filter((c) => c.tools.includes(tool)).map((spec) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ControlSlider, { spec, value: retouch[spec.id], onChange: (v) => controller.setPaintOptions({ retouch: { [spec.id]: v } }) }, spec.id)),
1410
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: import_image_editor8.RETOUCH_TOGGLES.filter((t) => t.tools.includes(tool)).map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1411
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1412
2257
  "input",
1413
2258
  {
1414
2259
  type: "checkbox",
@@ -1421,9 +2266,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1421
2266
  t.label
1422
2267
  ] }, t.id)) })
1423
2268
  ] }),
1424
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1425
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1426
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1427
2272
  "input",
1428
2273
  {
1429
2274
  type: "checkbox",
@@ -1435,8 +2280,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1435
2280
  ),
1436
2281
  "Pressure size"
1437
2282
  ] }),
1438
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5", children: [
1439
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2283
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1.5", children: [
2284
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1440
2285
  "input",
1441
2286
  {
1442
2287
  type: "checkbox",
@@ -1449,28 +2294,28 @@ var BrushOptionsBar = ({ controller, className }) => {
1449
2294
  "Pressure opacity"
1450
2295
  ] })
1451
2296
  ] }),
1452
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-1", children: [
1453
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1454
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
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" })
1455
2300
  ] }),
1456
- error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
2301
+ error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
1457
2302
  ] });
1458
2303
  };
1459
2304
 
1460
2305
  // src/image-editor/ColorProfilePanel.tsx
1461
- var import_react8 = require("react");
1462
- var import_image_editor9 = require("@pixerate/editor/image-editor");
1463
- var import_jsx_runtime8 = require("react/jsx-runtime");
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");
1464
2309
  var chip2 = "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white";
1465
- var select = "rounded bg-slate-800 px-1 py-0.5 text-[11px] text-slate-200";
2310
+ var select2 = "rounded bg-slate-800 px-1 py-0.5 text-[11px] text-slate-200";
1466
2311
  var ColorProfilePanel = ({ controller, className }) => {
1467
- const [, setTick] = (0, import_react8.useState)(0);
1468
- (0, import_react8.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1469
- const [target, setTarget] = (0, import_react8.useState)("display-p3");
1470
- const [intent, setIntent] = (0, import_react8.useState)("relative");
1471
- const [bpc, setBpc] = (0, import_react8.useState)(true);
1472
- const [error, setError] = (0, import_react8.useState)(null);
1473
- const view = (0, import_image_editor9.colorPanelView)(controller);
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);
1474
2319
  const attempt = (fn) => {
1475
2320
  try {
1476
2321
  setError(null);
@@ -1491,61 +2336,61 @@ var ColorProfilePanel = ({ controller, className }) => {
1491
2336
  })
1492
2337
  );
1493
2338
  };
1494
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "color-profile-panel", children: [
1495
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", children: [
1496
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-slate-400", children: "Profile" }),
1497
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "data-testid": "color-profile-name", children: view.profileName })
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 })
1498
2343
  ] }),
1499
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Colour mode", children: [
1500
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-slate-400", children: "Mode" }),
1501
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("select", { "aria-label": "Colour mode", className: select, value: view.mode, onChange: (e) => attempt(() => controller.setColorMode(e.target.value)), children: import_image_editor9.COLOR_MODE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
1502
- view.cmykProfileName && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-slate-400", children: view.cmykProfileName })
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 })
1503
2348
  ] }),
1504
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Assign or convert", children: [
1505
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("select", { "aria-label": "Target profile", className: select, value: target, onChange: (e) => setTarget(e.target.value), children: import_image_editor9.WORKING_SPACE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.id, children: o.label }, o.id)) }),
1506
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("select", { "aria-label": "Rendering intent", className: select, value: intent, onChange: (e) => setIntent(e.target.value), children: import_image_editor9.INTENT_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
1507
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1", children: [
1508
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", "aria-label": "Black point compensation", checked: bpc, onChange: (e) => setBpc(e.target.checked), className: "accent-indigo-500" }),
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" }),
1509
2354
  "BPC"
1510
2355
  ] }),
1511
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: chip2, title: "Edit \u203A Assign Profile: keep the numbers", onClick: () => attempt(() => controller.assignProfile(target)), children: "Assign" }),
1512
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: chip2, title: "Edit \u203A Convert to Profile: keep the look", onClick: () => attempt(() => controller.convertToProfile(target, { intent, bpc })), children: "Convert" })
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" })
1513
2358
  ] }),
1514
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Proof setup", children: [
1515
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-slate-400", children: "Proof" }),
1516
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
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)(
1517
2362
  "select",
1518
2363
  {
1519
2364
  "aria-label": "Proof profile",
1520
- className: select,
2365
+ className: select2,
1521
2366
  value: view.proof?.id ?? "",
1522
2367
  onChange: (e) => e.target.value ? proofWith({ id: e.target.value }) : attempt(() => controller.setProofSetup(null)),
1523
2368
  children: [
1524
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "Off" }),
1525
- import_image_editor9.PROOF_PROFILE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.id, children: o.label }, o.id))
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))
1526
2371
  ]
1527
2372
  }
1528
2373
  ),
1529
- view.proof && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1530
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("select", { "aria-label": "Proof intent", className: select, value: view.proof.intent, onChange: (e) => proofWith({ intent: e.target.value }), children: import_image_editor9.INTENT_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.id, children: o.label }, o.id)) }),
1531
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1", children: [
1532
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", "aria-label": "Simulate paper colour", checked: view.proof.simulatePaper, onChange: (e) => proofWith({ simulatePaper: e.target.checked }), className: "accent-indigo-500" }),
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" }),
1533
2378
  "Paper"
1534
2379
  ] }),
1535
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1", children: [
1536
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", "aria-label": "Gamut warning", checked: view.proof.gamutWarning, onChange: (e) => proofWith({ gamutWarning: e.target.checked }), className: "accent-indigo-500" }),
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" }),
1537
2382
  "Gamut warning"
1538
2383
  ] })
1539
2384
  ] })
1540
2385
  ] }),
1541
- error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
2386
+ error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
1542
2387
  ] });
1543
2388
  };
1544
2389
 
1545
2390
  // src/image-editor/SelectionOptionsBar.tsx
1546
- var import_react9 = require("react");
1547
- var import_image_editor10 = require("@pixerate/editor/image-editor");
1548
- var import_jsx_runtime9 = require("react/jsx-runtime");
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");
1549
2394
  var MODIFY_OPS = [
1550
2395
  { op: "grow", label: "Grow" },
1551
2396
  { op: "shrink", label: "Shrink" },
@@ -1553,7 +2398,7 @@ var MODIFY_OPS = [
1553
2398
  { op: "border", label: "Border" },
1554
2399
  { op: "smooth", label: "Smooth" }
1555
2400
  ];
1556
- var btn = (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"}`;
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"}`;
1557
2402
  var SelectionOptionsBar = ({
1558
2403
  controller,
1559
2404
  options,
@@ -1562,20 +2407,20 @@ var SelectionOptionsBar = ({
1562
2407
  quickMask,
1563
2408
  className = ""
1564
2409
  }) => {
1565
- const [radius, setRadius] = (0, import_react9.useState)(2);
2410
+ const [radius, setRadius] = (0, import_react16.useState)(2);
1566
2411
  const set = (patch) => onOptionsChange({ ...options, ...patch });
1567
2412
  const sel = selection === void 0 ? controller.getSelection() : selection;
1568
2413
  const qm = quickMask ?? Boolean(controller.getState().quickMask);
1569
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1570
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor10.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
1571
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor10.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor10.SELECTION_MODE_LABELS[m] }, m)) }),
1572
- options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-2", children: [
1573
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex flex-col gap-1", children: [
1574
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1575
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Tolerance" }),
1576
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-mono", children: options.tolerance })
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 })
1577
2422
  ] }),
1578
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2423
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1579
2424
  "input",
1580
2425
  {
1581
2426
  type: "range",
@@ -1589,17 +2434,17 @@ var SelectionOptionsBar = ({
1589
2434
  }
1590
2435
  )
1591
2436
  ] }),
1592
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1593
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
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 }) }),
1594
2439
  "Contiguous"
1595
2440
  ] }),
1596
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1597
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
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 }) }),
1598
2443
  "Sample adjusted image"
1599
2444
  ] }),
1600
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
2445
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1601
2446
  "Sample",
1602
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2447
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1603
2448
  "select",
1604
2449
  {
1605
2450
  "aria-label": "Sample from",
@@ -1607,27 +2452,27 @@ var SelectionOptionsBar = ({
1607
2452
  onChange: (e) => set({ sample: e.target.value }),
1608
2453
  className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
1609
2454
  children: [
1610
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "composite", children: "All layers" }),
1611
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "active-layer", children: "Active layer" })
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" })
1612
2457
  ]
1613
2458
  }
1614
2459
  )
1615
2460
  ] })
1616
2461
  ] }),
1617
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1618
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
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 }) }),
1619
2464
  "Anti-alias"
1620
2465
  ] }),
1621
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1622
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
1623
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1624
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1625
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
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" })
1626
2471
  ] }),
1627
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1628
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
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: [
1629
2474
  "Radius",
1630
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2475
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1631
2476
  "input",
1632
2477
  {
1633
2478
  type: "number",
@@ -1641,24 +2486,24 @@ var SelectionOptionsBar = ({
1641
2486
  }
1642
2487
  )
1643
2488
  ] }),
1644
- MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
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))
1645
2490
  ] }),
1646
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor10.describeSelection)(sel) })
2491
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor13.describeSelection)(sel) })
1647
2492
  ] });
1648
2493
  };
1649
2494
 
1650
2495
  // src/image-editor/RefineEdgePanel.tsx
1651
- var import_react10 = require("react");
1652
- var import_image_editor11 = require("@pixerate/editor/image-editor");
1653
- var import_jsx_runtime10 = require("react/jsx-runtime");
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");
1654
2499
  var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
1655
- var button2 = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
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";
1656
2501
  var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1657
- const [params, setParams] = (0, import_react10.useState)(DEFAULT_PARAMS);
1658
- const [busy, setBusy] = (0, import_react10.useState)(false);
1659
- const [error, setError] = (0, import_react10.useState)(null);
1660
- const [layerId, setLayerId] = (0, import_react10.useState)("");
1661
- const [newKind, setNewKind] = (0, import_react10.useState)("hueSaturation");
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");
1662
2507
  const sel = selection === void 0 ? controller.getSelection() : selection;
1663
2508
  const list = layers ?? controller.getAdjustmentLayers();
1664
2509
  const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
@@ -1673,17 +2518,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1673
2518
  setBusy(false);
1674
2519
  }
1675
2520
  };
1676
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1677
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1678
- import_image_editor11.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex flex-col gap-1", children: [
1679
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1680
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: c.label }),
1681
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
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: [
1682
2527
  params[c.id],
1683
2528
  c.unit
1684
2529
  ] })
1685
2530
  ] }),
1686
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2531
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1687
2532
  "input",
1688
2533
  {
1689
2534
  type: "range",
@@ -1697,67 +2542,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1697
2542
  }
1698
2543
  )
1699
2544
  ] }, c.id)),
1700
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
1701
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
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 }) }),
1702
2547
  "Smart Radius"
1703
2548
  ] }),
1704
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-1", children: [
1705
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: button2, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1706
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: button2, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
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" })
1707
2552
  ] }),
1708
- error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
1709
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1710
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-1 items-center", children: [
1711
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
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)(
1712
2557
  "select",
1713
2558
  {
1714
2559
  "aria-label": "New masked layer kind",
1715
2560
  value: newKind,
1716
2561
  onChange: (e) => setNewKind(e.target.value),
1717
2562
  className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1718
- children: import_image_editor11.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: k.kind, children: k.label }, k.kind))
2563
+ children: import_image_editor14.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: k.kind, children: k.label }, k.kind))
1719
2564
  }
1720
2565
  ),
1721
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2566
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1722
2567
  "button",
1723
2568
  {
1724
2569
  type: "button",
1725
- className: button2,
2570
+ className: button3,
1726
2571
  disabled: !sel,
1727
- onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor11.layerMaskFromSelection)(sel) })),
2572
+ onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor14.layerMaskFromSelection)(sel) })),
1728
2573
  children: "New Masked Layer"
1729
2574
  }
1730
2575
  )
1731
2576
  ] }),
1732
- list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
1733
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
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)(
1734
2579
  "select",
1735
2580
  {
1736
2581
  "aria-label": "Mask layer",
1737
2582
  value: target.id,
1738
2583
  onChange: (e) => setLayerId(e.target.value),
1739
2584
  className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1740
- children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("option", { value: l.id, children: [
1741
- l.name || (0, import_image_editor11.adjustmentKindLabel)(l.kind),
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),
1742
2587
  l.mask ? " (masked)" : ""
1743
2588
  ] }, l.id))
1744
2589
  }
1745
2590
  ),
1746
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
1747
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: button2, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1748
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1749
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
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" })
1750
2595
  ] }),
1751
- target.mask && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1752
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex flex-col gap-1", children: [
1753
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1754
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Density" }),
1755
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
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: [
1756
2601
  Math.round((target.mask.density ?? 1) * 100),
1757
2602
  "%"
1758
2603
  ] })
1759
2604
  ] }),
1760
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2605
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1761
2606
  "input",
1762
2607
  {
1763
2608
  type: "range",
@@ -1771,15 +2616,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1771
2616
  }
1772
2617
  )
1773
2618
  ] }),
1774
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex flex-col gap-1", children: [
1775
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
1776
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Mask Feather" }),
1777
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
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: [
1778
2623
  target.mask.feather ?? 0,
1779
2624
  "px"
1780
2625
  ] })
1781
2626
  ] }),
1782
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2627
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1783
2628
  "input",
1784
2629
  {
1785
2630
  type: "range",
@@ -1799,14 +2644,14 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1799
2644
  };
1800
2645
 
1801
2646
  // src/image-editor/FreeTransformOptionsBar.tsx
1802
- var import_react11 = require("react");
1803
- var import_image_editor12 = require("@pixerate/editor/image-editor");
1804
- var import_jsx_runtime11 = require("react/jsx-runtime");
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");
1805
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"}`;
1806
2651
  var round = (v, unit) => unit === "px" ? Math.round(v * 10) / 10 : Math.round(v * 100) / 100;
1807
2652
  var FreeTransformOptionsBar = ({ tool, className }) => {
1808
- const [, setTick] = (0, import_react11.useState)(0);
1809
- (0, import_react11.useEffect)(() => tool.subscribe(() => setTick((n) => n + 1)), [tool]);
2653
+ const [, setTick] = (0, import_react18.useState)(0);
2654
+ (0, import_react18.useEffect)(() => tool.subscribe(() => setTick((n) => n + 1)), [tool]);
1810
2655
  const bar = tool.bar();
1811
2656
  if (!tool.active || !bar) return null;
1812
2657
  const warp = tool.warpBar();
@@ -1818,17 +2663,17 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1818
2663
  const v = Number(raw);
1819
2664
  if (raw.trim() !== "" && Number.isFinite(v) && Math.abs(v - bar[field]) > 1e-9) tool.setField(field, v);
1820
2665
  };
1821
- return /* @__PURE__ */ (0, import_jsx_runtime11.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: [
1822
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Transform mode", children: import_image_editor12.FREE_TRANSFORM_MODE_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime11.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)) }),
1823
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "grid grid-cols-3 gap-px", role: "group", "aria-label": "Reference point", children: import_image_editor12.TRANSFORM_ANCHORS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime11.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)) }),
1824
- tool.mode === "warp" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": "Warp options", children: [
1825
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1826
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-400", children: "Warp" }),
1827
- /* @__PURE__ */ (0, import_jsx_runtime11.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_editor12.WARP_STYLE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: o.id, children: o.label }, o.id)) })
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)) })
1828
2673
  ] }),
1829
- ["bend", "horizontal", "vertical"].map((k) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1830
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-400", children: k === "bend" ? "Bend" : k === "horizontal" ? "H" : "V" }),
1831
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
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)(
1832
2677
  "input",
1833
2678
  {
1834
2679
  type: "number",
@@ -1849,9 +2694,9 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1849
2694
  },
1850
2695
  `${k}:${warp[k]}`
1851
2696
  ),
1852
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-500", children: "%" })
2697
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-slate-500", children: "%" })
1853
2698
  ] }, k)),
1854
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2699
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1855
2700
  "button",
1856
2701
  {
1857
2702
  type: "button",
@@ -1863,26 +2708,26 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1863
2708
  children: "Vertical"
1864
2709
  }
1865
2710
  ),
1866
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1867
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-400", children: "Grid" }),
1868
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
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)(
1869
2714
  "select",
1870
2715
  {
1871
2716
  "aria-label": "Warp grid",
1872
- value: import_image_editor12.WARP_GRID_OPTIONS.find((g) => g.columns === warp.columns && g.rows === warp.rows)?.id ?? "1x1",
2717
+ value: import_image_editor15.WARP_GRID_OPTIONS.find((g) => g.columns === warp.columns && g.rows === warp.rows)?.id ?? "1x1",
1873
2718
  onChange: (e) => {
1874
- const g = import_image_editor12.WARP_GRID_OPTIONS.find((o) => o.id === e.target.value);
2719
+ const g = import_image_editor15.WARP_GRID_OPTIONS.find((o) => o.id === e.target.value);
1875
2720
  tool.setWarp({ columns: g.columns, rows: g.rows });
1876
2721
  },
1877
2722
  className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
1878
- children: import_image_editor12.WARP_GRID_OPTIONS.map((g) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: g.id, children: g.label }, g.id))
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))
1879
2724
  }
1880
2725
  )
1881
2726
  ] })
1882
2727
  ] }),
1883
- tool.mode !== "warp" && import_image_editor12.FREE_TRANSFORM_FIELDS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", title: f.title, children: [
1884
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-400", children: f.label }),
1885
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
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)(
1886
2731
  "input",
1887
2732
  {
1888
2733
  type: "number",
@@ -1902,8 +2747,8 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1902
2747
  },
1903
2748
  `${f.id}:${round(bar[f.id], f.unit)}`
1904
2749
  ),
1905
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-500", children: f.unit }),
1906
- f.id === "scaleX" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
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)(
1907
2752
  "button",
1908
2753
  {
1909
2754
  type: "button",
@@ -1918,34 +2763,34 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1918
2763
  }
1919
2764
  )
1920
2765
  ] }, f.id)),
1921
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1922
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-400", children: "Interpolation" }),
1923
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
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)(
1924
2769
  "select",
1925
2770
  {
1926
2771
  "aria-label": "Interpolation",
1927
2772
  value: tool.interpolation,
1928
2773
  onChange: (e) => tool.setInterpolation(e.target.value),
1929
2774
  className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
1930
- children: import_image_editor12.INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: i, children: i[0].toUpperCase() + i.slice(1) }, i))
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))
1931
2776
  }
1932
2777
  )
1933
2778
  ] }),
1934
- /* @__PURE__ */ (0, import_jsx_runtime11.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" }),
1935
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", title: "Cancel (Esc)", className: chip3(false), onClick: () => tool.cancel(), children: "Cancel" }),
1936
- tool.error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { role: "alert", className: "text-rose-400", children: tool.error })
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 })
1937
2782
  ] });
1938
2783
  };
1939
2784
 
1940
2785
  // src/image-editor/ShapeOptionsBar.tsx
1941
- var import_react12 = require("react");
1942
- var import_image_editor13 = require("@pixerate/editor/image-editor");
1943
- var import_jsx_runtime12 = require("react/jsx-runtime");
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");
1944
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"}`;
1945
2790
  var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
1946
- const [, setTick] = (0, import_react12.useState)(0);
1947
- (0, import_react12.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1948
- const [error, setError] = (0, import_react12.useState)(null);
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);
1949
2794
  const active = controller.getActiveLayer();
1950
2795
  const shapeId = active?.type === "shape" ? active.id : null;
1951
2796
  const set = (change) => {
@@ -1953,19 +2798,19 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
1953
2798
  if (!shapeId) return;
1954
2799
  try {
1955
2800
  setError(null);
1956
- (0, import_image_editor13.applyShapeOptions)(controller, shapeId, change);
2801
+ (0, import_image_editor16.applyShapeOptions)(controller, shapeId, change);
1957
2802
  } catch (e) {
1958
2803
  setError(e instanceof Error ? e.message : String(e));
1959
2804
  }
1960
2805
  };
1961
2806
  const num = (v, min, max) => Math.max(min, Math.min(max, Number(v) || min));
1962
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "shape-options", children: [
1963
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Shape kind", children: import_image_editor13.LIVE_SHAPE_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", "aria-pressed": options.kind === k, className: chip4(options.kind === k), onClick: () => onChange({ ...options, kind: k }), children: import_image_editor13.SHAPE_KIND_LABELS[k] }, k)) }),
1964
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
1965
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
1966
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "checkbox", "aria-label": "Fill", checked: options.fill !== null, onChange: (e) => set({ fill: e.target.checked ? "#4f46e5" : null }) }),
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 }) }),
1967
2812
  "Fill",
1968
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2813
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1969
2814
  "input",
1970
2815
  {
1971
2816
  type: "color",
@@ -1977,10 +2822,10 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
1977
2822
  }
1978
2823
  )
1979
2824
  ] }),
1980
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
1981
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "checkbox", "aria-label": "Stroke", checked: options.stroke !== null, onChange: (e) => set({ stroke: e.target.checked ? "#000000" : null }) }),
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 }) }),
1982
2827
  "Stroke",
1983
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2828
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1984
2829
  "input",
1985
2830
  {
1986
2831
  type: "color",
@@ -1992,9 +2837,9 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
1992
2837
  }
1993
2838
  )
1994
2839
  ] }),
1995
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
2840
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
1996
2841
  "Width",
1997
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2842
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1998
2843
  "input",
1999
2844
  {
2000
2845
  type: "number",
@@ -2008,23 +2853,23 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
2008
2853
  )
2009
2854
  ] })
2010
2855
  ] }),
2011
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
2012
- options.kind === "rect" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
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: [
2013
2858
  "Radius",
2014
- /* @__PURE__ */ (0, import_jsx_runtime12.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" })
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" })
2015
2860
  ] }),
2016
- options.kind === "polygon" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
2861
+ options.kind === "polygon" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
2017
2862
  "Sides",
2018
- /* @__PURE__ */ (0, import_jsx_runtime12.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" })
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" })
2019
2864
  ] }),
2020
- options.kind === "star" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2021
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
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: [
2022
2867
  "Points",
2023
- /* @__PURE__ */ (0, import_jsx_runtime12.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" })
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" })
2024
2869
  ] }),
2025
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
2870
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1", children: [
2026
2871
  "Inner",
2027
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2872
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2028
2873
  "input",
2029
2874
  {
2030
2875
  type: "range",
@@ -2039,33 +2884,33 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
2039
2884
  )
2040
2885
  ] })
2041
2886
  ] }),
2042
- options.kind === "line" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2043
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
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: [
2044
2889
  "Weight",
2045
- /* @__PURE__ */ (0, import_jsx_runtime12.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" })
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" })
2046
2891
  ] }),
2047
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
2048
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
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 }) }),
2049
2894
  "Arrowhead"
2050
2895
  ] })
2051
2896
  ] })
2052
2897
  ] }),
2053
- /* @__PURE__ */ (0, import_jsx_runtime12.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." }),
2054
- error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
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 })
2055
2900
  ] });
2056
2901
  };
2057
2902
 
2058
2903
  // src/image-editor/TypeOptionsBar.tsx
2059
- var import_react13 = require("react");
2060
- var import_image_editor14 = require("@pixerate/editor/image-editor");
2061
- var import_jsx_runtime13 = require("react/jsx-runtime");
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");
2062
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"}`;
2063
2908
  var ALIGN_LABELS = { left: "Left", center: "Centre", right: "Right", justify: "Justify" };
2064
2909
  var TypeOptionsBar = ({ controller, options, onChange, session, className }) => {
2065
- const [, setTick] = (0, import_react13.useState)(0);
2066
- (0, import_react13.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
2067
- (0, import_react13.useEffect)(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
2068
- const [error, setError] = (0, import_react13.useState)(null);
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);
2069
2914
  const active = controller.getActiveLayer();
2070
2915
  const typeId = !session && active?.type === "type" ? active.id : null;
2071
2916
  const here = session?.alive ? session.styleHere() : {};
@@ -2097,11 +2942,11 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
2097
2942
  setError(e instanceof Error ? e.message : String(e));
2098
2943
  }
2099
2944
  };
2100
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "type-options", children: [
2101
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
2102
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-1", children: [
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: [
2103
2948
  "Font",
2104
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2949
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2105
2950
  "input",
2106
2951
  {
2107
2952
  list: "pixerate-type-fonts",
@@ -2111,11 +2956,11 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
2111
2956
  className: "w-32 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
2112
2957
  }
2113
2958
  ),
2114
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("datalist", { id: "pixerate-type-fonts", children: fonts.map((f) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: f }, f)) })
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)) })
2115
2960
  ] }),
2116
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-1", children: [
2961
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "flex items-center gap-1", children: [
2117
2962
  "Size",
2118
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2963
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2119
2964
  "input",
2120
2965
  {
2121
2966
  type: "number",
@@ -2128,24 +2973,24 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
2128
2973
  }
2129
2974
  )
2130
2975
  ] }),
2131
- /* @__PURE__ */ (0, import_jsx_runtime13.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" }),
2132
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", "aria-pressed": shown.italic, className: `${chip5(shown.italic)} italic`, onClick: () => style({ italic: !shown.italic }), children: "I" }),
2133
- /* @__PURE__ */ (0, import_jsx_runtime13.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" })
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" })
2134
2979
  ] }),
2135
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Alignment", children: import_image_editor14.TEXT_ALIGNS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", "aria-pressed": options.align === a, className: chip5(options.align === a), onClick: () => style({ align: a }), children: ALIGN_LABELS[a] }, a)) }),
2136
- /* @__PURE__ */ (0, import_jsx_runtime13.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." }),
2137
- missing.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
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: [
2138
2983
  "Missing ",
2139
2984
  missing.length === 1 ? "font" : "fonts",
2140
2985
  ": ",
2141
2986
  missing.join(", ")
2142
2987
  ] }),
2143
- error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
2988
+ error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
2144
2989
  ] });
2145
2990
  };
2146
2991
 
2147
2992
  // src/image-editor/ImageEditor.tsx
2148
- var import_jsx_runtime14 = require("react/jsx-runtime");
2993
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2149
2994
  var ImageEditor = ({
2150
2995
  editor: externalEditor,
2151
2996
  src,
@@ -2155,70 +3000,75 @@ var ImageEditor = ({
2155
3000
  exportOptions,
2156
3001
  onInpaint,
2157
3002
  onRemoveBackground,
2158
- aiHooks
3003
+ aiHooks,
3004
+ effects
2159
3005
  }) => {
2160
3006
  const internalEditor = useImageEditor({ image: src });
2161
3007
  const editor = externalEditor || internalEditor;
2162
3008
  const { state, controller } = editor;
2163
- const legacyProcess = (0, import_image_editor15.normalizeProcessVersion)(state.adjustments.process) < import_image_editor15.LATEST_PROCESS_VERSION;
2164
- const canvasRef = (0, import_react14.useRef)(null);
2165
- const containerRef = (0, import_react14.useRef)(null);
2166
- const [activeTab, setActiveTab] = (0, import_react14.useState)("crop");
2167
- const [activeCropRatio, setActiveCropRatio] = (0, import_react14.useState)(null);
2168
- const [selectionOptions, setSelectionOptions] = (0, import_react14.useState)(import_image_editor15.DEFAULT_SELECTION_TOOL_OPTIONS);
2169
- const selectionOptionsRef = (0, import_react14.useRef)(selectionOptions);
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);
2170
3020
  selectionOptionsRef.current = selectionOptions;
2171
- const selectionGestureRef = (0, import_react14.useRef)(null);
3021
+ const selectionGestureRef = (0, import_react21.useRef)(null);
2172
3022
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
2173
- selectionGestureRef.current = new import_image_editor15.SelectionGesture(controller, () => selectionOptionsRef.current);
3023
+ selectionGestureRef.current = new import_image_editor18.SelectionGesture(controller, () => selectionOptionsRef.current);
2174
3024
  }
2175
- const selectionDraftRef = (0, import_react14.useRef)(null);
2176
- const [selectionError, setSelectionError] = (0, import_react14.useState)(null);
2177
- const paintGestureRef = (0, import_react14.useRef)(null);
2178
- const paintControllerRef = (0, import_react14.useRef)(controller);
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);
2179
3029
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
2180
- paintGestureRef.current = new import_image_editor15.PaintGesture(controller);
3030
+ paintGestureRef.current = new import_image_editor18.PaintGesture(controller);
2181
3031
  paintControllerRef.current = controller;
2182
3032
  }
2183
- const brushCursorRef = (0, import_react14.useRef)(null);
2184
- const [paintError, setPaintError] = (0, import_react14.useState)(null);
2185
- const transformToolRef = (0, import_react14.useRef)(null);
2186
- const transformControllerRef = (0, import_react14.useRef)(controller);
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);
2187
3037
  if (!transformToolRef.current || transformControllerRef.current !== controller) {
2188
3038
  transformToolRef.current?.cancel();
2189
- transformToolRef.current = new import_image_editor15.FreeTransformTool(controller, {
3039
+ transformToolRef.current = new import_image_editor18.FreeTransformTool(controller, {
2190
3040
  schedule: (run) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(run) : run()
2191
3041
  });
2192
3042
  transformControllerRef.current = controller;
2193
3043
  }
2194
3044
  const transformTool = transformToolRef.current;
2195
- const [, setTransformTick] = (0, import_react14.useState)(0);
2196
- const [transformCursor, setTransformCursor] = (0, import_react14.useState)("default");
2197
- const [shapeOptions, setShapeOptions] = (0, import_react14.useState)(import_image_editor15.DEFAULT_SHAPE_TOOL_OPTIONS);
2198
- const shapeOptionsRef = (0, import_react14.useRef)(shapeOptions);
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);
2199
3049
  shapeOptionsRef.current = shapeOptions;
2200
- const [typeOptions, setTypeOptions] = (0, import_react14.useState)(import_image_editor15.DEFAULT_TYPE_TOOL_OPTIONS);
2201
- const typeOptionsRef = (0, import_react14.useRef)(typeOptions);
3050
+ const [typeOptions, setTypeOptions] = (0, import_react21.useState)(import_image_editor18.DEFAULT_TYPE_TOOL_OPTIONS);
3051
+ const typeOptionsRef = (0, import_react21.useRef)(typeOptions);
2202
3052
  typeOptionsRef.current = typeOptions;
2203
- const shapeGestureRef = (0, import_react14.useRef)(null);
2204
- const typeToolRef = (0, import_react14.useRef)(null);
2205
- const shapeTypeControllerRef = (0, import_react14.useRef)(controller);
3053
+ const shapeGestureRef = (0, import_react21.useRef)(null);
3054
+ const typeToolRef = (0, import_react21.useRef)(null);
3055
+ const shapeTypeControllerRef = (0, import_react21.useRef)(controller);
2206
3056
  if (!shapeGestureRef.current || !typeToolRef.current || shapeTypeControllerRef.current !== controller) {
2207
3057
  typeToolRef.current?.finish();
2208
- shapeGestureRef.current = new import_image_editor15.ShapeDrawGesture(controller, () => shapeOptionsRef.current);
2209
- typeToolRef.current = new import_image_editor15.TypeToolGesture(controller, () => typeOptionsRef.current);
3058
+ shapeGestureRef.current = new import_image_editor18.ShapeDrawGesture(controller, () => shapeOptionsRef.current);
3059
+ typeToolRef.current = new import_image_editor18.TypeToolGesture(controller, () => typeOptionsRef.current);
2210
3060
  shapeTypeControllerRef.current = controller;
2211
3061
  }
2212
- const typeInputRef = (0, import_react14.useRef)(null);
2213
- const [typeSession, setTypeSession] = (0, import_react14.useState)(typeToolRef.current.session);
2214
- const [shapeTypeError, setShapeTypeError] = (0, import_react14.useState)(null);
2215
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react14.useState)("");
2216
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react14.useState)("annotations");
2217
- const [isRemovingBg, setIsRemovingBg] = (0, import_react14.useState)(false);
2218
- const [isInpainting, setIsInpainting] = (0, import_react14.useState)(false);
2219
- const [aiError, setAiError] = (0, import_react14.useState)(null);
2220
- const [aiSuccess, setAiSuccess] = (0, import_react14.useState)(null);
2221
- const [aiTarget, setAiTarget] = (0, import_react14.useState)("auto");
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");
2222
3072
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
2223
3073
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
2224
3074
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -2281,18 +3131,18 @@ var ImageEditor = ({
2281
3131
  setIsInpainting(false);
2282
3132
  }
2283
3133
  };
2284
- const [activeColor, setActiveColor] = (0, import_react14.useState)("#ef4444");
2285
- const [strokeWidth, setStrokeWidth] = (0, import_react14.useState)(3);
2286
- const [fontSize, setFontSize] = (0, import_react14.useState)(24);
2287
- const [textInput, setTextInput] = (0, import_react14.useState)("");
2288
- const draftAnnotationRef = (0, import_react14.useRef)(null);
2289
- const draftCropRef = (0, import_react14.useRef)(null);
2290
- const cropDragInfoRef = (0, import_react14.useRef)(null);
2291
- const annotationDragInfoRef = (0, import_react14.useRef)(null);
2292
- const isDrawingRef = (0, import_react14.useRef)(false);
2293
- const currentPathRef = (0, import_react14.useRef)([]);
2294
- const dragStartPointRef = (0, import_react14.useRef)(null);
2295
- const renderCanvas = (0, import_react14.useCallback)(
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)(
2296
3146
  async (draftAnnotation, draftCrop) => {
2297
3147
  const canvas = canvasRef.current;
2298
3148
  const container = containerRef.current;
@@ -2315,8 +3165,8 @@ var ImageEditor = ({
2315
3165
  },
2316
3166
  [controller, activeTab, transformTool]
2317
3167
  );
2318
- (0, import_react14.useEffect)(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
2319
- (0, import_react14.useEffect)(() => {
3168
+ (0, import_react21.useEffect)(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
3169
+ (0, import_react21.useEffect)(() => {
2320
3170
  if (activeTab === "annotate" && state.activeTool === "type") return;
2321
3171
  if (typeToolRef.current?.session) {
2322
3172
  typeToolRef.current.finish();
@@ -2351,7 +3201,7 @@ var ImageEditor = ({
2351
3201
  el.value = "";
2352
3202
  }
2353
3203
  };
2354
- (0, import_react14.useEffect)(() => transformTool.subscribe(() => {
3204
+ (0, import_react21.useEffect)(() => transformTool.subscribe(() => {
2355
3205
  setTransformTick((n) => n + 1);
2356
3206
  void renderCanvas();
2357
3207
  }), [transformTool, renderCanvas]);
@@ -2362,8 +3212,8 @@ var ImageEditor = ({
2362
3212
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
2363
3213
  const s = controller.getState();
2364
3214
  const cropping = activeTab === "crop";
2365
- const projection = (0, import_image_editor15.getViewportProjection)(s, canvas.width, canvas.height, cropping);
2366
- const pt = (0, import_image_editor15.canvasToImagePoint)({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvas.width, canvas.height, cropping);
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);
2367
3217
  transformTool.setView(projection.scale);
2368
3218
  return { pt, tolerance: 6 / (projection.scale || 1) };
2369
3219
  };
@@ -2394,7 +3244,7 @@ var ImageEditor = ({
2394
3244
  transformTool.up();
2395
3245
  return true;
2396
3246
  };
2397
- (0, import_react14.useEffect)(() => {
3247
+ (0, import_react21.useEffect)(() => {
2398
3248
  if (typeof window === "undefined") return;
2399
3249
  const onKey = (e) => {
2400
3250
  if (transformTool.key(e)) e.preventDefault();
@@ -2402,7 +3252,7 @@ var ImageEditor = ({
2402
3252
  window.addEventListener("keydown", onKey);
2403
3253
  return () => window.removeEventListener("keydown", onKey);
2404
3254
  }, [transformTool]);
2405
- (0, import_react14.useEffect)(() => {
3255
+ (0, import_react21.useEffect)(() => {
2406
3256
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
2407
3257
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
2408
3258
  const animId = raf(() => {
@@ -2410,12 +3260,12 @@ var ImageEditor = ({
2410
3260
  });
2411
3261
  return () => caf(animId);
2412
3262
  }, [renderCanvas, state]);
2413
- (0, import_react14.useEffect)(() => {
3263
+ (0, import_react21.useEffect)(() => {
2414
3264
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
2415
3265
  editor.setTool("crop");
2416
3266
  }
2417
3267
  }, [activeTab, editor]);
2418
- (0, import_react14.useEffect)(() => {
3268
+ (0, import_react21.useEffect)(() => {
2419
3269
  const container = containerRef.current;
2420
3270
  if (!container) return;
2421
3271
  if (typeof ResizeObserver !== "undefined") {
@@ -2451,8 +3301,8 @@ var ImageEditor = ({
2451
3301
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
2452
3302
  const s = controller.getState();
2453
3303
  return list.map((ev) => ({
2454
- ...(0, import_image_editor15.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
2455
- pressure: (0, import_image_editor15.pointerPressure)(ev)
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)
2456
3306
  }));
2457
3307
  };
2458
3308
  const handlePaintPointerDown = (e) => {
@@ -2483,10 +3333,10 @@ var ImageEditor = ({
2483
3333
  if (g.error) setPaintError(g.error);
2484
3334
  }
2485
3335
  };
2486
- (0, import_react14.useEffect)(() => {
3336
+ (0, import_react21.useEffect)(() => {
2487
3337
  if (activeTab !== "paint" || typeof window === "undefined") return;
2488
3338
  const onKey = (e) => {
2489
- if ((0, import_image_editor15.handlePaintShortcut)(controller, e)) e.preventDefault();
3339
+ if ((0, import_image_editor18.handlePaintShortcut)(controller, e)) e.preventDefault();
2490
3340
  };
2491
3341
  window.addEventListener("keydown", onKey);
2492
3342
  return () => window.removeEventListener("keydown", onKey);
@@ -2497,7 +3347,7 @@ var ImageEditor = ({
2497
3347
  const canvasPt = getCanvasEventPoint(e);
2498
3348
  if (activeTab === "select") {
2499
3349
  const gesture = selectionGestureRef.current;
2500
- const imgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
3350
+ const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2501
3351
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
2502
3352
  return;
2503
3353
  }
@@ -2508,8 +3358,8 @@ var ImageEditor = ({
2508
3358
  width: state.imageDimensions.width,
2509
3359
  height: state.imageDimensions.height
2510
3360
  };
2511
- const handle = (0, import_image_editor15.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
2512
- const startImgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
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);
2513
3363
  if (handle) {
2514
3364
  cropDragInfoRef.current = {
2515
3365
  handle,
@@ -2528,7 +3378,7 @@ var ImageEditor = ({
2528
3378
  return;
2529
3379
  }
2530
3380
  if (activeTab === "annotate" && (state.activeTool === "shape" || state.activeTool === "type")) {
2531
- const imgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
3381
+ const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2532
3382
  setShapeTypeError(null);
2533
3383
  if (state.activeTool === "shape") shapeGestureRef.current.down(imgPt);
2534
3384
  else {
@@ -2539,12 +3389,12 @@ var ImageEditor = ({
2539
3389
  return;
2540
3390
  }
2541
3391
  if (activeTab === "annotate") {
2542
- const imgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
3392
+ const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2543
3393
  dragStartPointRef.current = imgPt;
2544
3394
  if (state.activeTool === "select") {
2545
3395
  for (let i = state.annotations.length - 1; i >= 0; i--) {
2546
3396
  const ann = state.annotations[i];
2547
- if ((0, import_image_editor15.hitTestAnnotation)(imgPt, ann)) {
3397
+ if ((0, import_image_editor18.hitTestAnnotation)(imgPt, ann)) {
2548
3398
  editor.selectAnnotation(ann.id);
2549
3399
  annotationDragInfoRef.current = {
2550
3400
  annId: ann.id,
@@ -2580,7 +3430,7 @@ var ImageEditor = ({
2580
3430
  const canvasPt = getCanvasEventPoint(e);
2581
3431
  if (activeTab === "select") {
2582
3432
  const gesture = selectionGestureRef.current;
2583
- if (gesture.active && gesture.move((0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
3433
+ if (gesture.active && gesture.move((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
2584
3434
  selectionDraftRef.current = gesture.draftPath;
2585
3435
  renderCanvas();
2586
3436
  }
@@ -2589,7 +3439,7 @@ var ImageEditor = ({
2589
3439
  if (activeTab === "crop") {
2590
3440
  const drag = cropDragInfoRef.current;
2591
3441
  if (drag) {
2592
- const currentImgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
3442
+ const currentImgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
2593
3443
  let newCrop;
2594
3444
  if (drag.handle === "new") {
2595
3445
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -2603,7 +3453,7 @@ var ImageEditor = ({
2603
3453
  height: Math.round(Math.max(20, maxY - minY))
2604
3454
  };
2605
3455
  } else {
2606
- newCrop = (0, import_image_editor15.calculateCropDrag)(
3456
+ newCrop = (0, import_image_editor18.calculateCropDrag)(
2607
3457
  drag.startCrop,
2608
3458
  drag.handle,
2609
3459
  drag.startImgPt,
@@ -2623,15 +3473,15 @@ var ImageEditor = ({
2623
3473
  width: state.imageDimensions.width,
2624
3474
  height: state.imageDimensions.height
2625
3475
  };
2626
- const handle = (0, import_image_editor15.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
2627
- canvas.style.cursor = (0, import_image_editor15.getCropCursor)(handle, state.transform);
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);
2628
3478
  }
2629
3479
  return;
2630
3480
  }
2631
3481
  if (activeTab === "annotate" && state.activeTool === "shape") {
2632
3482
  const g = shapeGestureRef.current;
2633
3483
  if (g.active) {
2634
- g.move((0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), { shift: e.shiftKey, alt: e.altKey });
3484
+ g.move((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), { shift: e.shiftKey, alt: e.altKey });
2635
3485
  if (g.error) setShapeTypeError(g.error);
2636
3486
  }
2637
3487
  return;
@@ -2639,7 +3489,7 @@ var ImageEditor = ({
2639
3489
  if (activeTab === "annotate") {
2640
3490
  if (annotationDragInfoRef.current) {
2641
3491
  const drag = annotationDragInfoRef.current;
2642
- const currentImgPt2 = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
3492
+ const currentImgPt2 = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2643
3493
  const dx = currentImgPt2.x - drag.startImgPt.x;
2644
3494
  const dy = currentImgPt2.y - drag.startImgPt.y;
2645
3495
  editor.updateAnnotation(drag.annId, {
@@ -2651,10 +3501,10 @@ var ImageEditor = ({
2651
3501
  const startPt = dragStartPointRef.current;
2652
3502
  if (!startPt) {
2653
3503
  if (state.activeTool === "select") {
2654
- const imgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
3504
+ const imgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2655
3505
  let hovered = false;
2656
3506
  for (let i = state.annotations.length - 1; i >= 0; i--) {
2657
- if ((0, import_image_editor15.hitTestAnnotation)(imgPt, state.annotations[i])) {
3507
+ if ((0, import_image_editor18.hitTestAnnotation)(imgPt, state.annotations[i])) {
2658
3508
  hovered = true;
2659
3509
  break;
2660
3510
  }
@@ -2665,7 +3515,7 @@ var ImageEditor = ({
2665
3515
  }
2666
3516
  return;
2667
3517
  }
2668
- const currentImgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
3518
+ const currentImgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2669
3519
  if (state.activeTool === "pen" && isDrawingRef.current) {
2670
3520
  currentPathRef.current.push(currentImgPt);
2671
3521
  const draft = {
@@ -2745,7 +3595,7 @@ var ImageEditor = ({
2745
3595
  if (activeTab === "select") {
2746
3596
  const gesture = selectionGestureRef.current;
2747
3597
  if (gesture.active) {
2748
- gesture.end((0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
3598
+ gesture.end((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
2749
3599
  selectionDraftRef.current = null;
2750
3600
  renderCanvas();
2751
3601
  }
@@ -2768,7 +3618,7 @@ var ImageEditor = ({
2768
3618
  }
2769
3619
  if (activeTab === "annotate" && state.activeTool === "type") {
2770
3620
  const tool = typeToolRef.current;
2771
- tool.up((0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false));
3621
+ tool.up((0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false));
2772
3622
  setTypeSession(tool.session);
2773
3623
  if (tool.error) setShapeTypeError(tool.error);
2774
3624
  void renderCanvas();
@@ -2782,7 +3632,7 @@ var ImageEditor = ({
2782
3632
  }
2783
3633
  const startPt = dragStartPointRef.current;
2784
3634
  if (startPt) {
2785
- const currentImgPt = (0, import_image_editor15.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
3635
+ const currentImgPt = (0, import_image_editor18.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2786
3636
  if (state.activeTool === "pen" && isDrawingRef.current) {
2787
3637
  if (currentPathRef.current.length > 1) {
2788
3638
  editor.addAnnotation({
@@ -2878,15 +3728,15 @@ var ImageEditor = ({
2878
3728
  link.click();
2879
3729
  }
2880
3730
  };
2881
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3731
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2882
3732
  "div",
2883
3733
  {
2884
3734
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
2885
3735
  style,
2886
3736
  children: [
2887
- /* @__PURE__ */ (0, import_jsx_runtime14.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: [
2888
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2889
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
2890
3740
  "button",
2891
3741
  {
2892
3742
  type: "button",
@@ -2898,7 +3748,7 @@ var ImageEditor = ({
2898
3748
  children: "Transform & Crop"
2899
3749
  }
2900
3750
  ),
2901
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3751
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2902
3752
  "button",
2903
3753
  {
2904
3754
  type: "button",
@@ -2910,7 +3760,7 @@ var ImageEditor = ({
2910
3760
  children: "Adjustments"
2911
3761
  }
2912
3762
  ),
2913
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3763
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2914
3764
  "button",
2915
3765
  {
2916
3766
  type: "button",
@@ -2922,7 +3772,7 @@ var ImageEditor = ({
2922
3772
  children: "Layers"
2923
3773
  }
2924
3774
  ),
2925
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3775
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2926
3776
  "button",
2927
3777
  {
2928
3778
  type: "button",
@@ -2934,7 +3784,7 @@ var ImageEditor = ({
2934
3784
  children: "Paint"
2935
3785
  }
2936
3786
  ),
2937
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3787
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2938
3788
  "button",
2939
3789
  {
2940
3790
  type: "button",
@@ -2946,7 +3796,7 @@ var ImageEditor = ({
2946
3796
  children: "Select & Mask"
2947
3797
  }
2948
3798
  ),
2949
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3799
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2950
3800
  "button",
2951
3801
  {
2952
3802
  type: "button",
@@ -2958,7 +3808,7 @@ var ImageEditor = ({
2958
3808
  children: "Annotations"
2959
3809
  }
2960
3810
  ),
2961
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3811
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2962
3812
  "button",
2963
3813
  {
2964
3814
  type: "button",
@@ -2970,7 +3820,7 @@ var ImageEditor = ({
2970
3820
  children: "Depth Mask"
2971
3821
  }
2972
3822
  ),
2973
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3823
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2974
3824
  "button",
2975
3825
  {
2976
3826
  type: "button",
@@ -2980,14 +3830,14 @@ var ImageEditor = ({
2980
3830
  },
2981
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"}`,
2982
3832
  children: [
2983
- /* @__PURE__ */ (0, import_jsx_runtime14.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_runtime14.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" }) }),
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" }) }),
2984
3834
  "AI Tools"
2985
3835
  ]
2986
3836
  }
2987
3837
  )
2988
3838
  ] }),
2989
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
2990
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3839
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
3840
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2991
3841
  "button",
2992
3842
  {
2993
3843
  type: "button",
@@ -2998,7 +3848,7 @@ var ImageEditor = ({
2998
3848
  children: "\u21A9"
2999
3849
  }
3000
3850
  ),
3001
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3851
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3002
3852
  "button",
3003
3853
  {
3004
3854
  type: "button",
@@ -3009,7 +3859,7 @@ var ImageEditor = ({
3009
3859
  children: "\u21AA"
3010
3860
  }
3011
3861
  ),
3012
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3862
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3013
3863
  "button",
3014
3864
  {
3015
3865
  type: "button",
@@ -3018,8 +3868,8 @@ var ImageEditor = ({
3018
3868
  children: "Reset"
3019
3869
  }
3020
3870
  ),
3021
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
3022
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3023
3873
  "button",
3024
3874
  {
3025
3875
  type: "button",
@@ -3029,11 +3879,11 @@ var ImageEditor = ({
3029
3879
  children: "-"
3030
3880
  }
3031
3881
  ),
3032
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
3882
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
3033
3883
  Math.round(state.zoom * 100),
3034
3884
  "%"
3035
3885
  ] }),
3036
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3886
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3037
3887
  "button",
3038
3888
  {
3039
3889
  type: "button",
@@ -3043,8 +3893,8 @@ var ImageEditor = ({
3043
3893
  children: "+"
3044
3894
  }
3045
3895
  ),
3046
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
3047
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3048
3898
  "button",
3049
3899
  {
3050
3900
  type: "button",
@@ -3055,7 +3905,7 @@ var ImageEditor = ({
3055
3905
  children: "Hold Compare"
3056
3906
  }
3057
3907
  ),
3058
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3908
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3059
3909
  "button",
3060
3910
  {
3061
3911
  type: "button",
@@ -3066,16 +3916,16 @@ var ImageEditor = ({
3066
3916
  )
3067
3917
  ] })
3068
3918
  ] }),
3069
- transformTool.active && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
3070
- !transformTool.active && transformTool.error && /* @__PURE__ */ (0, import_jsx_runtime14.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 }),
3071
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
3072
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
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)(
3073
3923
  "div",
3074
3924
  {
3075
3925
  ref: containerRef,
3076
3926
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
3077
3927
  children: [
3078
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3928
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3079
3929
  "canvas",
3080
3930
  {
3081
3931
  ref: canvasRef,
@@ -3092,7 +3942,7 @@ var ImageEditor = ({
3092
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" : ""}`
3093
3943
  }
3094
3944
  ),
3095
- typeSession && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3945
+ typeSession && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3096
3946
  "textarea",
3097
3947
  {
3098
3948
  ref: typeInputRef,
@@ -3114,11 +3964,11 @@ var ImageEditor = ({
3114
3964
  ]
3115
3965
  }
3116
3966
  ),
3117
- /* @__PURE__ */ (0, import_jsx_runtime14.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: [
3118
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3119
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
3120
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
3121
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3122
3972
  "button",
3123
3973
  {
3124
3974
  type: "button",
@@ -3130,7 +3980,7 @@ var ImageEditor = ({
3130
3980
  children: "Freeform"
3131
3981
  }
3132
3982
  ),
3133
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3983
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3134
3984
  "button",
3135
3985
  {
3136
3986
  type: "button",
@@ -3142,7 +3992,7 @@ var ImageEditor = ({
3142
3992
  children: "1:1 Square"
3143
3993
  }
3144
3994
  ),
3145
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3995
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3146
3996
  "button",
3147
3997
  {
3148
3998
  type: "button",
@@ -3154,7 +4004,7 @@ var ImageEditor = ({
3154
4004
  children: "4:3 Standard"
3155
4005
  }
3156
4006
  ),
3157
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4007
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3158
4008
  "button",
3159
4009
  {
3160
4010
  type: "button",
@@ -3166,7 +4016,7 @@ var ImageEditor = ({
3166
4016
  children: "16:9 Wide"
3167
4017
  }
3168
4018
  ),
3169
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4019
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3170
4020
  "button",
3171
4021
  {
3172
4022
  type: "button",
@@ -3178,7 +4028,7 @@ var ImageEditor = ({
3178
4028
  children: "3:2 Photo"
3179
4029
  }
3180
4030
  ),
3181
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4031
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3182
4032
  "button",
3183
4033
  {
3184
4034
  type: "button",
@@ -3191,10 +4041,10 @@ var ImageEditor = ({
3191
4041
  }
3192
4042
  )
3193
4043
  ] }),
3194
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3195
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
3196
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
3197
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3198
4048
  "button",
3199
4049
  {
3200
4050
  type: "button",
@@ -3203,7 +4053,7 @@ var ImageEditor = ({
3203
4053
  children: "Rotate -90\xB0"
3204
4054
  }
3205
4055
  ),
3206
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4056
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3207
4057
  "button",
3208
4058
  {
3209
4059
  type: "button",
@@ -3212,7 +4062,7 @@ var ImageEditor = ({
3212
4062
  children: "Rotate +90\xB0"
3213
4063
  }
3214
4064
  ),
3215
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4065
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3216
4066
  "button",
3217
4067
  {
3218
4068
  type: "button",
@@ -3221,7 +4071,7 @@ var ImageEditor = ({
3221
4071
  children: "Flip Horizontal"
3222
4072
  }
3223
4073
  ),
3224
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4074
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3225
4075
  "button",
3226
4076
  {
3227
4077
  type: "button",
@@ -3232,10 +4082,10 @@ var ImageEditor = ({
3232
4082
  )
3233
4083
  ] })
3234
4084
  ] }),
3235
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3236
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between", children: [
3237
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
3238
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3239
4089
  "button",
3240
4090
  {
3241
4091
  type: "button",
@@ -3245,25 +4095,25 @@ var ImageEditor = ({
3245
4095
  }
3246
4096
  )
3247
4097
  ] }),
3248
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Histogram, { histogram: editor.histogram }),
3249
- import_image_editor15.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react14.default.Fragment, { children: [
3250
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3251
4101
  ControlSlider,
3252
4102
  {
3253
4103
  spec,
3254
- value: (0, import_image_editor15.readAdjustmentControls)(state.adjustments)[spec.id],
4104
+ value: (0, import_image_editor18.readAdjustmentControls)(state.adjustments)[spec.id],
3255
4105
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
3256
4106
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
3257
4107
  }
3258
4108
  ),
3259
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
4109
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3260
4110
  "div",
3261
4111
  {
3262
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",
3263
4113
  "data-testid": "image-editor-process-notice",
3264
4114
  children: [
3265
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
3266
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3267
4117
  "button",
3268
4118
  {
3269
4119
  type: "button",
@@ -3276,7 +4126,7 @@ var ImageEditor = ({
3276
4126
  }
3277
4127
  )
3278
4128
  ] }, spec.id)),
3279
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4129
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3280
4130
  AdjustmentLayersPanel,
3281
4131
  {
3282
4132
  controller,
@@ -3285,9 +4135,9 @@ var ImageEditor = ({
3285
4135
  }
3286
4136
  ) })
3287
4137
  ] }),
3288
- activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3289
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
3290
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3291
4141
  "button",
3292
4142
  {
3293
4143
  type: "button",
@@ -3298,14 +4148,15 @@ var ImageEditor = ({
3298
4148
  children: "Free Transform"
3299
4149
  }
3300
4150
  ),
3301
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LayersPanel, { controller }),
3302
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Colour" }),
3303
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ColorProfilePanel, { controller })
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 })
3304
4155
  ] }),
3305
- activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3306
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
3307
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(BrushOptionsBar, { controller }),
3308
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3309
4160
  "button",
3310
4161
  {
3311
4162
  type: "button",
@@ -3316,12 +4167,12 @@ var ImageEditor = ({
3316
4167
  children: "Free Transform"
3317
4168
  }
3318
4169
  ),
3319
- paintError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
3320
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LayersPanel, { controller }) })
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 }) })
3321
4172
  ] }),
3322
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3323
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
3324
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "grid grid-cols-2 gap-1.5", children: ["shape", "type"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3325
4176
  "button",
3326
4177
  {
3327
4178
  type: "button",
@@ -3332,13 +4183,13 @@ var ImageEditor = ({
3332
4183
  },
3333
4184
  t
3334
4185
  )) }),
3335
- state.activeTool === "shape" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
3336
- state.activeTool === "type" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
3337
- state.activeTool === "type" && typeSession && /* @__PURE__ */ (0, import_jsx_runtime14.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" }),
3338
- shapeTypeError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
3339
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3340
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
3341
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3342
4193
  "button",
3343
4194
  {
3344
4195
  type: "button",
@@ -3348,9 +4199,9 @@ var ImageEditor = ({
3348
4199
  },
3349
4200
  t
3350
4201
  )) }),
3351
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
3352
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { className: "text-slate-400", children: "Color:" }),
3353
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3354
4205
  "input",
3355
4206
  {
3356
4207
  type: "color",
@@ -3359,15 +4210,15 @@ var ImageEditor = ({
3359
4210
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
3360
4211
  }
3361
4212
  ),
3362
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex-1 ml-2", children: [
3363
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
3364
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Width:" }),
3365
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "font-mono", children: [
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: [
3366
4217
  strokeWidth,
3367
4218
  "px"
3368
4219
  ] })
3369
4220
  ] }),
3370
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4221
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3371
4222
  "input",
3372
4223
  {
3373
4224
  type: "range",
@@ -3380,10 +4231,10 @@ var ImageEditor = ({
3380
4231
  )
3381
4232
  ] })
3382
4233
  ] }),
3383
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3384
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
3385
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-2", children: [
3386
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3387
4238
  "input",
3388
4239
  {
3389
4240
  type: "text",
@@ -3394,7 +4245,7 @@ var ImageEditor = ({
3394
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"
3395
4246
  }
3396
4247
  ),
3397
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4248
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3398
4249
  "button",
3399
4250
  {
3400
4251
  type: "button",
@@ -3404,14 +4255,14 @@ var ImageEditor = ({
3404
4255
  }
3405
4256
  )
3406
4257
  ] }),
3407
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
3408
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Font Size:" }),
3409
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "font-mono", children: [
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: [
3410
4261
  fontSize,
3411
4262
  "px"
3412
4263
  ] })
3413
4264
  ] }),
3414
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4265
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3415
4266
  "input",
3416
4267
  {
3417
4268
  type: "range",
@@ -3422,14 +4273,14 @@ var ImageEditor = ({
3422
4273
  className: "w-full accent-indigo-500"
3423
4274
  }
3424
4275
  ),
3425
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3426
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between", children: [
3427
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "text-slate-400", children: [
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: [
3428
4279
  "Layers (",
3429
4280
  state.annotations.length,
3430
4281
  ")"
3431
4282
  ] }),
3432
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4283
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3433
4284
  "button",
3434
4285
  {
3435
4286
  type: "button",
@@ -3438,7 +4289,7 @@ var ImageEditor = ({
3438
4289
  children: "Delete Selected"
3439
4290
  }
3440
4291
  ),
3441
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4292
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3442
4293
  "button",
3443
4294
  {
3444
4295
  type: "button",
@@ -3449,10 +4300,10 @@ var ImageEditor = ({
3449
4300
  )
3450
4301
  ] })
3451
4302
  ] }),
3452
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3453
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between", children: [
3454
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
3455
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3456
4307
  "button",
3457
4308
  {
3458
4309
  type: "button",
@@ -3462,8 +4313,8 @@ var ImageEditor = ({
3462
4313
  }
3463
4314
  )
3464
4315
  ] }),
3465
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
3466
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3467
4318
  "input",
3468
4319
  {
3469
4320
  type: "checkbox",
@@ -3472,12 +4323,12 @@ var ImageEditor = ({
3472
4323
  className: "rounded accent-indigo-500"
3473
4324
  }
3474
4325
  ),
3475
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Enable Depth / Alpha Mask" })
4326
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Enable Depth / Alpha Mask" })
3476
4327
  ] }),
3477
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3478
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3479
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3480
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3481
4332
  "input",
3482
4333
  {
3483
4334
  type: "text",
@@ -3488,8 +4339,8 @@ var ImageEditor = ({
3488
4339
  }
3489
4340
  )
3490
4341
  ] }),
3491
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-2", children: [
3492
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4342
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex gap-2", children: [
4343
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3493
4344
  "button",
3494
4345
  {
3495
4346
  type: "button",
@@ -3498,7 +4349,7 @@ var ImageEditor = ({
3498
4349
  children: "Threshold Mode"
3499
4350
  }
3500
4351
  ),
3501
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4352
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3502
4353
  "button",
3503
4354
  {
3504
4355
  type: "button",
@@ -3508,12 +4359,12 @@ var ImageEditor = ({
3508
4359
  }
3509
4360
  )
3510
4361
  ] }),
3511
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3512
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3513
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Depth Start (Lower):" }),
3514
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[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] })
3515
4366
  ] }),
3516
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4367
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3517
4368
  "input",
3518
4369
  {
3519
4370
  type: "range",
@@ -3527,12 +4378,12 @@ var ImageEditor = ({
3527
4378
  }
3528
4379
  )
3529
4380
  ] }),
3530
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3531
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3532
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Depth Stop (Upper):" }),
3533
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
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] })
3534
4385
  ] }),
3535
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4386
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3536
4387
  "input",
3537
4388
  {
3538
4389
  type: "range",
@@ -3546,12 +4397,12 @@ var ImageEditor = ({
3546
4397
  }
3547
4398
  )
3548
4399
  ] }),
3549
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3550
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3551
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Softness:" }),
3552
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
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 })
3553
4404
  ] }),
3554
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4405
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3555
4406
  "input",
3556
4407
  {
3557
4408
  type: "range",
@@ -3563,8 +4414,8 @@ var ImageEditor = ({
3563
4414
  }
3564
4415
  )
3565
4416
  ] }),
3566
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3567
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3568
4419
  "input",
3569
4420
  {
3570
4421
  type: "checkbox",
@@ -3573,12 +4424,12 @@ var ImageEditor = ({
3573
4424
  className: "rounded accent-indigo-500"
3574
4425
  }
3575
4426
  ),
3576
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Invert Mask" })
4427
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Invert Mask" })
3577
4428
  ] })
3578
4429
  ] })
3579
4430
  ] }),
3580
- activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3581
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3582
4433
  SelectionOptionsBar,
3583
4434
  {
3584
4435
  controller,
@@ -3588,9 +4439,9 @@ var ImageEditor = ({
3588
4439
  quickMask: Boolean(state.quickMask)
3589
4440
  }
3590
4441
  ),
3591
- selectionError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
3592
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-1", children: [
3593
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3594
4445
  "button",
3595
4446
  {
3596
4447
  type: "button",
@@ -3601,7 +4452,7 @@ var ImageEditor = ({
3601
4452
  children: "Transform Selection"
3602
4453
  }
3603
4454
  ),
3604
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4455
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3605
4456
  "button",
3606
4457
  {
3607
4458
  type: "button",
@@ -3613,12 +4464,12 @@ var ImageEditor = ({
3613
4464
  }
3614
4465
  )
3615
4466
  ] }),
3616
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
4467
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
3617
4468
  ] }),
3618
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3619
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
3620
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Results go to" }),
3621
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
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)(
3622
4473
  "select",
3623
4474
  {
3624
4475
  "aria-label": "AI result target",
@@ -3626,54 +4477,54 @@ var ImageEditor = ({
3626
4477
  onChange: (e) => setAiTarget(e.target.value),
3627
4478
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
3628
4479
  children: [
3629
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
3630
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
3631
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "replace", children: "Replace image" })
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" })
3632
4483
  ]
3633
4484
  }
3634
4485
  )
3635
4486
  ] }),
3636
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3637
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between", children: [
3638
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3639
- /* @__PURE__ */ (0, import_jsx_runtime14.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_runtime14.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" }) }),
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" }) }),
3640
4491
  "Background Removal"
3641
4492
  ] }),
3642
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime14.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..." })
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..." })
3643
4494
  ] }),
3644
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3645
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3646
4497
  "button",
3647
4498
  {
3648
4499
  type: "button",
3649
4500
  onClick: handleRemoveBackground,
3650
4501
  disabled: isRemovingBg || isInpainting,
3651
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",
3652
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3653
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
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" }),
3654
4505
  "Removing Background..."
3655
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3656
- /* @__PURE__ */ (0, import_jsx_runtime14.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_runtime14.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" }) }),
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" }) }),
3657
4508
  "Remove Background"
3658
4509
  ] })
3659
4510
  }
3660
4511
  )
3661
4512
  ] }),
3662
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3663
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between", children: [
3664
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3665
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3666
- /* @__PURE__ */ (0, import_jsx_runtime14.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" }),
3667
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "m14 7 3 3" })
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" })
3668
4519
  ] }),
3669
4520
  "Generative Inpainting"
3670
4521
  ] }),
3671
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime14.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..." })
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..." })
3672
4523
  ] }),
3673
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3674
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1", children: [
3675
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3676
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
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)(
3677
4528
  "textarea",
3678
4529
  {
3679
4530
  id: "ai-inpaint-prompt-react",
@@ -3685,10 +4536,10 @@ var ImageEditor = ({
3685
4536
  }
3686
4537
  )
3687
4538
  ] }),
3688
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1", children: [
3689
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3690
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
3691
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
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)(
3692
4543
  "button",
3693
4544
  {
3694
4545
  type: "button",
@@ -3701,7 +4552,7 @@ var ImageEditor = ({
3701
4552
  ]
3702
4553
  }
3703
4554
  ),
3704
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
4555
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3705
4556
  "button",
3706
4557
  {
3707
4558
  type: "button",
@@ -3716,25 +4567,25 @@ var ImageEditor = ({
3716
4567
  )
3717
4568
  ] })
3718
4569
  ] }),
3719
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4570
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3720
4571
  "button",
3721
4572
  {
3722
4573
  type: "button",
3723
4574
  onClick: handleInpaint,
3724
4575
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
3725
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",
3726
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3727
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
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" }),
3728
4579
  "Generating Inpaint..."
3729
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3730
- /* @__PURE__ */ (0, import_jsx_runtime14.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_runtime14.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" }) }),
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" }) }),
3731
4582
  "Apply Inpainting"
3732
4583
  ] })
3733
4584
  }
3734
4585
  )
3735
4586
  ] }),
3736
- aiError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3737
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
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 })
3738
4589
  ] })
3739
4590
  ] })
3740
4591
  ] })
@@ -3752,13 +4603,16 @@ var ImageEditor = ({
3752
4603
  FreeTransformOptionsBar,
3753
4604
  Histogram,
3754
4605
  ImageEditor,
4606
+ ImageProviderEffectsPanel,
3755
4607
  LayerEffectsPanel,
3756
4608
  LayersPanel,
4609
+ PaintGradientEditor,
3757
4610
  RefineEdgePanel,
3758
4611
  SelectionOptionsBar,
3759
4612
  ShapeOptionsBar,
3760
4613
  TypeOptionsBar,
3761
4614
  useImageEditor,
4615
+ useImageEffectsTools,
3762
4616
  useImageHistogram
3763
4617
  });
3764
4618
  //# sourceMappingURL=index.cjs.map