@pixerate/editor-react 0.77.0 → 0.78.1

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