@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.
@@ -1,3 +1,9 @@
1
+ import {
2
+ EffectParameters,
3
+ EffectsBrowser,
4
+ useEffectDescription,
5
+ useEffects
6
+ } from "./chunk-7RMNM3KC.js";
1
7
  import {
2
8
  PaintGradientEditorView
3
9
  } from "./chunk-MO354USR.js";
@@ -5,7 +11,8 @@ import {
5
11
  // src/image-editor/useImageEditor.ts
6
12
  import { useRef, useState, useEffect, useCallback, useMemo } from "react";
7
13
  import {
8
- ImageEditorController
14
+ ImageEditorController,
15
+ createImageEffectsToolProvider
9
16
  } from "@pixerate/editor/image-editor";
10
17
  function useImageEditor(options = {}) {
11
18
  const controllerRef = useRef(null);
@@ -161,9 +168,16 @@ function useImageEditor(options = {}) {
161
168
  [controller, state, historyTicks, histogram]
162
169
  );
163
170
  }
171
+ function useImageEffectsTools(registry, controller, options = {}) {
172
+ const { id, namespace, readOnly } = options;
173
+ useEffect(() => {
174
+ if (!registry) return;
175
+ return registry.register(createImageEffectsToolProvider(controller, { id, namespace, readOnly }));
176
+ }, [registry, controller, id, namespace, readOnly]);
177
+ }
164
178
 
165
179
  // src/image-editor/ImageEditor.tsx
166
- import React13, { useRef as useRef5, useEffect as useEffect11, useState as useState14, useCallback as useCallback2 } from "react";
180
+ import React14, { useRef as useRef5, useEffect as useEffect12, useState as useState15, useCallback as useCallback2 } from "react";
167
181
  import {
168
182
  canvasToImagePoint,
169
183
  hitTestCrop,
@@ -1268,8 +1282,139 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1268
1282
  ] });
1269
1283
  };
1270
1284
 
1285
+ // src/image-editor/ImageProviderEffectsPanel.tsx
1286
+ import React6, { useEffect as useEffect6, useState as useState7 } from "react";
1287
+ import { findLayer } from "@pixerate/editor/image-editor";
1288
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1289
+ var btn = "rounded border border-slate-700 px-1.5 py-0.5 text-[11px] text-slate-300 hover:text-white disabled:opacity-40";
1290
+ function Controls({
1291
+ provider,
1292
+ effect,
1293
+ name,
1294
+ values,
1295
+ onChange,
1296
+ onPreset
1297
+ }) {
1298
+ const { description, error } = useEffectDescription(provider, effect);
1299
+ if (!provider) return /* @__PURE__ */ jsxs7("p", { className: "text-[11px] text-slate-400", children: [
1300
+ 'No effects provider: "',
1301
+ name ?? effect,
1302
+ '" is kept but not drawn.'
1303
+ ] });
1304
+ if (error) return /* @__PURE__ */ jsx7("p", { className: "text-[11px] text-amber-400", children: error });
1305
+ if (!description) return /* @__PURE__ */ jsx7("p", { className: "text-[11px] text-slate-400", children: "Loading\u2026" });
1306
+ return /* @__PURE__ */ jsx7(EffectParameters, { description, values, onChange, onReset: (k) => onChange(k, description.defaults[k], null), onPreset });
1307
+ }
1308
+ function ImageProviderEffectsPanel({ controller, className = "" }) {
1309
+ const [, setTick] = useState7(0);
1310
+ useEffect6(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1311
+ const [browse, setBrowse] = useState7(null);
1312
+ const [message, setMessage] = useState7(null);
1313
+ const [open, setOpen] = useState7(null);
1314
+ const provider = controller.effectsProvider;
1315
+ const state = controller.getState();
1316
+ const layer = state.activeLayerId ? findLayer(state.layers, state.activeLayerId)?.layer ?? null : null;
1317
+ const run = (work) => {
1318
+ setMessage(null);
1319
+ Promise.resolve().then(work).catch((e) => setMessage(e instanceof Error ? e.message : String(e)));
1320
+ };
1321
+ const drags = React6.useRef(/* @__PURE__ */ new Set());
1322
+ const commit = (gesture) => {
1323
+ if (gesture) {
1324
+ if (!drags.current.has(gesture)) {
1325
+ drags.current.add(gesture);
1326
+ return true;
1327
+ }
1328
+ return false;
1329
+ }
1330
+ return true;
1331
+ };
1332
+ const filters = layer?.type === "smart" ? (layer.smartFilters?.filters ?? []).filter((f) => f.kind === "effect") : [];
1333
+ const generator = layer?.type === "pixel" ? layer.generator : void 0;
1334
+ const canFilter = !!layer && layer.type !== "adjustment" && layer.type !== "annotation";
1335
+ return /* @__PURE__ */ jsxs7("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Provider effects", "data-image-provider-effects": "", children: [
1336
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1", children: [
1337
+ /* @__PURE__ */ jsx7("span", { className: "flex-1 font-semibold uppercase tracking-wider text-[11px] text-slate-200", children: "Effects" }),
1338
+ /* @__PURE__ */ jsx7("button", { type: "button", className: btn, disabled: !provider || !canFilter, "aria-pressed": browse === "filter", onClick: () => setBrowse(browse === "filter" ? null : "filter"), children: "Apply effect\u2026" }),
1339
+ /* @__PURE__ */ jsx7("button", { type: "button", className: btn, disabled: !provider, "aria-pressed": browse === "layer", onClick: () => setBrowse(browse === "layer" ? null : "layer"), children: "Effect layer\u2026" })
1340
+ ] }),
1341
+ !provider && /* @__PURE__ */ jsx7("p", { className: "text-[11px] text-slate-400", children: "No effects provider is registered. Effects in the document are kept." }),
1342
+ browse === "filter" && layer && /* @__PURE__ */ jsx7(EffectsBrowser, { provider, uses: ["filter"], title: "Filters", onPick: (e) => (setBrowse(null), run(() => controller.applyEffectFilter(layer.id, e.id))) }),
1343
+ browse === "layer" && /* @__PURE__ */ jsx7(EffectsBrowser, { provider, uses: ["generator", "overlay", "title"], title: "Generators and overlays", onPick: (e) => (setBrowse(null), run(() => controller.addEffectLayer(e.id))) }),
1344
+ generator && layer && /* @__PURE__ */ jsxs7("div", { className: "space-y-1", "data-effect-part": "generator", children: [
1345
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1", children: [
1346
+ /* @__PURE__ */ jsx7("span", { className: "flex-1 font-medium text-slate-200", children: generator.name ?? generator.effect }),
1347
+ /* @__PURE__ */ jsx7("button", { type: "button", className: btn, title: "Keep the pixels as a plain layer", onClick: () => run(() => controller.rasterizeEffectLayer(layer.id)), children: "Rasterize" })
1348
+ ] }),
1349
+ /* @__PURE__ */ jsx7(
1350
+ Controls,
1351
+ {
1352
+ provider,
1353
+ effect: generator.effect,
1354
+ name: generator.name,
1355
+ values: generator.values,
1356
+ onChange: (k, v, gesture) => run(() => controller.updateEffectLayer(layer.id, { values: { [k]: v } }, commit(gesture))),
1357
+ onPreset: (values) => run(() => controller.updateEffectLayer(layer.id, { values }))
1358
+ }
1359
+ )
1360
+ ] }),
1361
+ filters.length > 0 && layer && /* @__PURE__ */ jsx7("ol", { className: "space-y-1", "data-effect-part": "filters", children: filters.map((f) => {
1362
+ const label = f.kind === "effect" ? f.name ?? f.effect : f.kind;
1363
+ const all = layer.smartFilters.filters;
1364
+ const index = all.indexOf(f);
1365
+ if (f.kind !== "effect") return null;
1366
+ return /* @__PURE__ */ jsxs7("li", { className: "rounded border border-slate-700 p-1", "data-smart-effect": f.id, children: [
1367
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1", children: [
1368
+ /* @__PURE__ */ jsx7("input", { type: "checkbox", checked: f.enabled, "aria-label": `${label} on`, onChange: (e) => {
1369
+ const enabled = e.currentTarget.checked;
1370
+ run(() => controller.updateEffectFilter(layer.id, f.id, { enabled }));
1371
+ } }),
1372
+ /* @__PURE__ */ jsx7("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 }),
1373
+ /* @__PURE__ */ jsx7("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" }),
1374
+ /* @__PURE__ */ jsx7("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" }),
1375
+ /* @__PURE__ */ jsx7("button", { type: "button", className: btn, "aria-label": `Remove ${label}`, onClick: () => run(() => controller.removeSmartFilter(layer.id, f.id)), children: "\u2715" })
1376
+ ] }),
1377
+ open === f.id && /* @__PURE__ */ jsxs7("div", { className: "mt-1 space-y-2", children: [
1378
+ /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1", children: [
1379
+ /* @__PURE__ */ jsx7("span", { className: "w-14 text-[11px] text-slate-300", children: "Opacity" }),
1380
+ /* @__PURE__ */ jsx7(
1381
+ "input",
1382
+ {
1383
+ type: "range",
1384
+ min: 0,
1385
+ max: 1,
1386
+ step: 0.01,
1387
+ className: "flex-1",
1388
+ value: f.opacity,
1389
+ "aria-label": `${label} opacity`,
1390
+ onChange: (e) => {
1391
+ const opacity = Number(e.currentTarget.value);
1392
+ run(() => controller.updateEffectFilter(layer.id, f.id, { opacity }));
1393
+ }
1394
+ }
1395
+ )
1396
+ ] }),
1397
+ /* @__PURE__ */ jsx7(
1398
+ Controls,
1399
+ {
1400
+ provider,
1401
+ effect: f.effect,
1402
+ name: f.name,
1403
+ values: f.values,
1404
+ onChange: (k, v, gesture) => run(() => controller.updateEffectFilter(layer.id, f.id, { values: { [k]: v } }, commit(gesture))),
1405
+ onPreset: (values) => run(() => controller.updateEffectFilter(layer.id, f.id, { values }))
1406
+ }
1407
+ )
1408
+ ] })
1409
+ ] }, f.id);
1410
+ }) }),
1411
+ !layer && /* @__PURE__ */ jsx7("p", { className: "text-[11px] text-slate-400", children: "Select a layer to apply effects to it." }),
1412
+ message && /* @__PURE__ */ jsx7("p", { role: "alert", className: "text-[11px] text-rose-400", children: message })
1413
+ ] });
1414
+ }
1415
+
1271
1416
  // src/image-editor/BrushOptionsBar.tsx
1272
- import { useEffect as useEffect6, useState as useState7 } from "react";
1417
+ import { useEffect as useEffect7, useState as useState8 } from "react";
1273
1418
  import {
1274
1419
  BRUSH_OPTION_CONTROLS,
1275
1420
  MIXER_MIXING_OPTIONS,
@@ -1287,16 +1432,16 @@ import { DEFAULT_PAINT_GRADIENT } from "@pixerate/editor/image-editor";
1287
1432
 
1288
1433
  // src/image-editor/PaintGradientEditor.tsx
1289
1434
  import { PAINT_GRADIENT_KIT } from "@pixerate/editor/image-editor";
1290
- import { jsx as jsx7 } from "react/jsx-runtime";
1291
- var PaintGradientEditor = (props) => /* @__PURE__ */ jsx7(PaintGradientEditorView, { ...props, kit: PAINT_GRADIENT_KIT });
1435
+ import { jsx as jsx8 } from "react/jsx-runtime";
1436
+ var PaintGradientEditor = (props) => /* @__PURE__ */ jsx8(PaintGradientEditorView, { ...props, kit: PAINT_GRADIENT_KIT });
1292
1437
 
1293
1438
  // src/image-editor/BrushOptionsBar.tsx
1294
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1439
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1295
1440
  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"}`;
1296
1441
  var BrushOptionsBar = ({ controller, className }) => {
1297
- const [, setTick] = useState7(0);
1298
- useEffect6(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1299
- const [error, setError] = useState7(null);
1442
+ const [, setTick] = useState8(0);
1443
+ useEffect7(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1444
+ const [error, setError] = useState8(null);
1300
1445
  const state = controller.getState();
1301
1446
  const { brush, foreground, background, mixer, mixerLoad, retouch, cloneSource, paint } = state.paint;
1302
1447
  const tool = state.activeTool;
@@ -1308,8 +1453,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1308
1453
  setError(err instanceof Error ? err.message : String(err));
1309
1454
  }
1310
1455
  };
1311
- return /* @__PURE__ */ jsxs7("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
1312
- /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Paint tools", children: PAINT_TOOLS.map((t) => /* @__PURE__ */ jsx8(
1456
+ return /* @__PURE__ */ jsxs8("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
1457
+ /* @__PURE__ */ jsx9("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Paint tools", children: PAINT_TOOLS.map((t) => /* @__PURE__ */ jsx9(
1313
1458
  "button",
1314
1459
  {
1315
1460
  type: "button",
@@ -1321,9 +1466,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1321
1466
  },
1322
1467
  t.id
1323
1468
  )) }),
1324
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
1325
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1", children: [
1326
- /* @__PURE__ */ jsx8(
1469
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
1470
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1", children: [
1471
+ /* @__PURE__ */ jsx9(
1327
1472
  "input",
1328
1473
  {
1329
1474
  type: "color",
@@ -1333,10 +1478,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1333
1478
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1334
1479
  }
1335
1480
  ),
1336
- /* @__PURE__ */ jsx8("span", { className: "text-slate-400", children: "FG" })
1481
+ /* @__PURE__ */ jsx9("span", { className: "text-slate-400", children: "FG" })
1337
1482
  ] }),
1338
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1", children: [
1339
- /* @__PURE__ */ jsx8(
1483
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1", children: [
1484
+ /* @__PURE__ */ jsx9(
1340
1485
  "input",
1341
1486
  {
1342
1487
  type: "color",
@@ -1346,11 +1491,11 @@ var BrushOptionsBar = ({ controller, className }) => {
1346
1491
  className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1347
1492
  }
1348
1493
  ),
1349
- /* @__PURE__ */ jsx8("span", { className: "text-slate-400", children: "BG" })
1494
+ /* @__PURE__ */ jsx9("span", { className: "text-slate-400", children: "BG" })
1350
1495
  ] }),
1351
- /* @__PURE__ */ jsx8("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
1352
- /* @__PURE__ */ jsx8("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" }),
1353
- state.activeTool === "brush" && /* @__PURE__ */ jsx8(
1496
+ /* @__PURE__ */ jsx9("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
1497
+ /* @__PURE__ */ jsx9("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" }),
1498
+ state.activeTool === "brush" && /* @__PURE__ */ jsx9(
1354
1499
  "button",
1355
1500
  {
1356
1501
  type: "button",
@@ -1362,8 +1507,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1362
1507
  }
1363
1508
  )
1364
1509
  ] }),
1365
- state.activeTool === "brush" && paint.type === "gradient" && /* @__PURE__ */ jsx8(PaintGradientEditor, { value: paint, colors: { paint: foreground, secondary: background }, onChange: (g) => attempt(() => controller.setPaintOptions({ paint: g })) }),
1366
- BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ jsx8(
1510
+ state.activeTool === "brush" && paint.type === "gradient" && /* @__PURE__ */ jsx9(PaintGradientEditor, { value: paint, colors: { paint: foreground, secondary: background }, onChange: (g) => attempt(() => controller.setPaintOptions({ paint: g })) }),
1511
+ BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ jsx9(
1367
1512
  ControlSlider,
1368
1513
  {
1369
1514
  spec,
@@ -1372,9 +1517,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1372
1517
  },
1373
1518
  spec.id
1374
1519
  )),
1375
- state.activeTool === "mixer" && /* @__PURE__ */ jsxs7("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: [
1376
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
1377
- /* @__PURE__ */ jsx8(
1520
+ state.activeTool === "mixer" && /* @__PURE__ */ jsxs8("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: [
1521
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
1522
+ /* @__PURE__ */ jsx9(
1378
1523
  "span",
1379
1524
  {
1380
1525
  "aria-label": "Brush load",
@@ -1383,10 +1528,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1383
1528
  style: { background: mixerLoad.reservoir ? rgbUnitToHex(mixerLoad.reservoir) : "transparent" }
1384
1529
  }
1385
1530
  ),
1386
- /* @__PURE__ */ jsx8("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
1387
- /* @__PURE__ */ jsx8("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
1531
+ /* @__PURE__ */ jsx9("button", { type: "button", title: "Fill the reservoir with the foreground colour", className: chip(false), onClick: () => controller.loadMixerBrush(), children: "Load brush" }),
1532
+ /* @__PURE__ */ jsx9("button", { type: "button", title: "Empty the picked-up colour", className: chip(false), onClick: () => controller.cleanMixerBrush(), children: "Clean brush" })
1388
1533
  ] }),
1389
- /* @__PURE__ */ jsx8("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ jsx8(
1534
+ /* @__PURE__ */ jsx9("div", { className: "flex gap-1", role: "group", "aria-label": "Mixing", children: MIXER_MIXING_OPTIONS.map((m) => /* @__PURE__ */ jsx9(
1390
1535
  "button",
1391
1536
  {
1392
1537
  type: "button",
@@ -1398,10 +1543,10 @@ var BrushOptionsBar = ({ controller, className }) => {
1398
1543
  },
1399
1544
  m.id
1400
1545
  )) }),
1401
- MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ jsx8(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
1402
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
1403
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1404
- /* @__PURE__ */ jsx8(
1546
+ MIXER_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ jsx9(ControlSlider, { spec, value: mixer[spec.id], onChange: (v) => controller.setPaintOptions({ mixer: { [spec.id]: v } }) }, spec.id)),
1547
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap gap-3 text-slate-300", children: [
1548
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1.5", children: [
1549
+ /* @__PURE__ */ jsx9(
1405
1550
  "input",
1406
1551
  {
1407
1552
  type: "checkbox",
@@ -1413,8 +1558,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1413
1558
  ),
1414
1559
  "Load each stroke"
1415
1560
  ] }),
1416
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1417
- /* @__PURE__ */ jsx8(
1561
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1.5", children: [
1562
+ /* @__PURE__ */ jsx9(
1418
1563
  "input",
1419
1564
  {
1420
1565
  type: "checkbox",
@@ -1428,14 +1573,14 @@ var BrushOptionsBar = ({ controller, className }) => {
1428
1573
  ] })
1429
1574
  ] })
1430
1575
  ] }),
1431
- isRetouchPaintTool(tool) && /* @__PURE__ */ jsxs7("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: [
1432
- (tool === "clone" || tool === "heal") && /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
1433
- /* @__PURE__ */ jsx8("span", { className: "text-slate-400", "data-testid": "clone-source", children: cloneSourceLabel(controller) }),
1434
- cloneSource && /* @__PURE__ */ jsx8("button", { type: "button", title: "Forget the source point", className: chip(false), onClick: () => controller.setCloneSource(null), children: "Clear source" })
1576
+ isRetouchPaintTool(tool) && /* @__PURE__ */ jsxs8("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: [
1577
+ (tool === "clone" || tool === "heal") && /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
1578
+ /* @__PURE__ */ jsx9("span", { className: "text-slate-400", "data-testid": "clone-source", children: cloneSourceLabel(controller) }),
1579
+ cloneSource && /* @__PURE__ */ jsx9("button", { type: "button", title: "Forget the source point", className: chip(false), onClick: () => controller.setCloneSource(null), children: "Clear source" })
1435
1580
  ] }),
1436
- RETOUCH_CHOICES.filter((c) => c.tools.includes(tool)).map((choice) => /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": choice.label, children: [
1437
- /* @__PURE__ */ jsx8("span", { className: "text-slate-400", children: choice.label }),
1438
- choice.options.map((o) => /* @__PURE__ */ jsx8(
1581
+ RETOUCH_CHOICES.filter((c) => c.tools.includes(tool)).map((choice) => /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": choice.label, children: [
1582
+ /* @__PURE__ */ jsx9("span", { className: "text-slate-400", children: choice.label }),
1583
+ choice.options.map((o) => /* @__PURE__ */ jsx9(
1439
1584
  "button",
1440
1585
  {
1441
1586
  type: "button",
@@ -1448,9 +1593,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1448
1593
  o.id
1449
1594
  ))
1450
1595
  ] }, choice.id)),
1451
- RETOUCH_OPTION_CONTROLS.filter((c) => c.tools.includes(tool)).map((spec) => /* @__PURE__ */ jsx8(ControlSlider, { spec, value: retouch[spec.id], onChange: (v) => controller.setPaintOptions({ retouch: { [spec.id]: v } }) }, spec.id)),
1452
- /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-3 text-slate-300", children: RETOUCH_TOGGLES.filter((t) => t.tools.includes(tool)).map((t) => /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1453
- /* @__PURE__ */ jsx8(
1596
+ RETOUCH_OPTION_CONTROLS.filter((c) => c.tools.includes(tool)).map((spec) => /* @__PURE__ */ jsx9(ControlSlider, { spec, value: retouch[spec.id], onChange: (v) => controller.setPaintOptions({ retouch: { [spec.id]: v } }) }, spec.id)),
1597
+ /* @__PURE__ */ jsx9("div", { className: "flex flex-wrap gap-3 text-slate-300", children: RETOUCH_TOGGLES.filter((t) => t.tools.includes(tool)).map((t) => /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1.5", children: [
1598
+ /* @__PURE__ */ jsx9(
1454
1599
  "input",
1455
1600
  {
1456
1601
  type: "checkbox",
@@ -1463,9 +1608,9 @@ var BrushOptionsBar = ({ controller, className }) => {
1463
1608
  t.label
1464
1609
  ] }, t.id)) })
1465
1610
  ] }),
1466
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1467
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1468
- /* @__PURE__ */ jsx8(
1611
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
1612
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1.5", children: [
1613
+ /* @__PURE__ */ jsx9(
1469
1614
  "input",
1470
1615
  {
1471
1616
  type: "checkbox",
@@ -1477,8 +1622,8 @@ var BrushOptionsBar = ({ controller, className }) => {
1477
1622
  ),
1478
1623
  "Pressure size"
1479
1624
  ] }),
1480
- /* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-1.5", children: [
1481
- /* @__PURE__ */ jsx8(
1625
+ /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1.5", children: [
1626
+ /* @__PURE__ */ jsx9(
1482
1627
  "input",
1483
1628
  {
1484
1629
  type: "checkbox",
@@ -1491,27 +1636,27 @@ var BrushOptionsBar = ({ controller, className }) => {
1491
1636
  "Pressure opacity"
1492
1637
  ] })
1493
1638
  ] }),
1494
- /* @__PURE__ */ jsxs7("div", { className: "flex gap-1", children: [
1495
- /* @__PURE__ */ jsx8("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1496
- /* @__PURE__ */ jsx8("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
1639
+ /* @__PURE__ */ jsxs8("div", { className: "flex gap-1", children: [
1640
+ /* @__PURE__ */ jsx9("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
1641
+ /* @__PURE__ */ jsx9("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
1497
1642
  ] }),
1498
- error && /* @__PURE__ */ jsx8("p", { role: "alert", className: "text-rose-400", children: error })
1643
+ error && /* @__PURE__ */ jsx9("p", { role: "alert", className: "text-rose-400", children: error })
1499
1644
  ] });
1500
1645
  };
1501
1646
 
1502
1647
  // src/image-editor/ColorProfilePanel.tsx
1503
- import { useEffect as useEffect7, useState as useState8 } from "react";
1648
+ import { useEffect as useEffect8, useState as useState9 } from "react";
1504
1649
  import { COLOR_MODE_OPTIONS, INTENT_OPTIONS, PROOF_PROFILE_OPTIONS, WORKING_SPACE_OPTIONS, colorPanelView } from "@pixerate/editor/image-editor";
1505
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1650
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1506
1651
  var chip2 = "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white";
1507
1652
  var select = "rounded bg-slate-800 px-1 py-0.5 text-[11px] text-slate-200";
1508
1653
  var ColorProfilePanel = ({ controller, className }) => {
1509
- const [, setTick] = useState8(0);
1510
- useEffect7(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1511
- const [target, setTarget] = useState8("display-p3");
1512
- const [intent, setIntent] = useState8("relative");
1513
- const [bpc, setBpc] = useState8(true);
1514
- const [error, setError] = useState8(null);
1654
+ const [, setTick] = useState9(0);
1655
+ useEffect8(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1656
+ const [target, setTarget] = useState9("display-p3");
1657
+ const [intent, setIntent] = useState9("relative");
1658
+ const [bpc, setBpc] = useState9(true);
1659
+ const [error, setError] = useState9(null);
1515
1660
  const view = colorPanelView(controller);
1516
1661
  const attempt = (fn) => {
1517
1662
  try {
@@ -1533,29 +1678,29 @@ var ColorProfilePanel = ({ controller, className }) => {
1533
1678
  })
1534
1679
  );
1535
1680
  };
1536
- return /* @__PURE__ */ jsxs8("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "color-profile-panel", children: [
1537
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
1538
- /* @__PURE__ */ jsx9("span", { className: "text-slate-400", children: "Profile" }),
1539
- /* @__PURE__ */ jsx9("span", { "data-testid": "color-profile-name", children: view.profileName })
1681
+ return /* @__PURE__ */ jsxs9("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "color-profile-panel", children: [
1682
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
1683
+ /* @__PURE__ */ jsx10("span", { className: "text-slate-400", children: "Profile" }),
1684
+ /* @__PURE__ */ jsx10("span", { "data-testid": "color-profile-name", children: view.profileName })
1540
1685
  ] }),
1541
- /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Colour mode", children: [
1542
- /* @__PURE__ */ jsx9("span", { className: "text-slate-400", children: "Mode" }),
1543
- /* @__PURE__ */ jsx9("select", { "aria-label": "Colour mode", className: select, value: view.mode, onChange: (e) => attempt(() => controller.setColorMode(e.target.value)), children: COLOR_MODE_OPTIONS.map((o) => /* @__PURE__ */ jsx9("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
1544
- view.cmykProfileName && /* @__PURE__ */ jsx9("span", { className: "text-slate-400", children: view.cmykProfileName })
1686
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Colour mode", children: [
1687
+ /* @__PURE__ */ jsx10("span", { className: "text-slate-400", children: "Mode" }),
1688
+ /* @__PURE__ */ jsx10("select", { "aria-label": "Colour mode", className: select, value: view.mode, onChange: (e) => attempt(() => controller.setColorMode(e.target.value)), children: COLOR_MODE_OPTIONS.map((o) => /* @__PURE__ */ jsx10("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
1689
+ view.cmykProfileName && /* @__PURE__ */ jsx10("span", { className: "text-slate-400", children: view.cmykProfileName })
1545
1690
  ] }),
1546
- /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Assign or convert", children: [
1547
- /* @__PURE__ */ jsx9("select", { "aria-label": "Target profile", className: select, value: target, onChange: (e) => setTarget(e.target.value), children: WORKING_SPACE_OPTIONS.map((o) => /* @__PURE__ */ jsx9("option", { value: o.id, children: o.label }, o.id)) }),
1548
- /* @__PURE__ */ jsx9("select", { "aria-label": "Rendering intent", className: select, value: intent, onChange: (e) => setIntent(e.target.value), children: INTENT_OPTIONS.map((o) => /* @__PURE__ */ jsx9("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
1549
- /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1", children: [
1550
- /* @__PURE__ */ jsx9("input", { type: "checkbox", "aria-label": "Black point compensation", checked: bpc, onChange: (e) => setBpc(e.target.checked), className: "accent-indigo-500" }),
1691
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Assign or convert", children: [
1692
+ /* @__PURE__ */ jsx10("select", { "aria-label": "Target profile", className: select, value: target, onChange: (e) => setTarget(e.target.value), children: WORKING_SPACE_OPTIONS.map((o) => /* @__PURE__ */ jsx10("option", { value: o.id, children: o.label }, o.id)) }),
1693
+ /* @__PURE__ */ jsx10("select", { "aria-label": "Rendering intent", className: select, value: intent, onChange: (e) => setIntent(e.target.value), children: INTENT_OPTIONS.map((o) => /* @__PURE__ */ jsx10("option", { value: o.id, title: o.title, children: o.label }, o.id)) }),
1694
+ /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-1", children: [
1695
+ /* @__PURE__ */ jsx10("input", { type: "checkbox", "aria-label": "Black point compensation", checked: bpc, onChange: (e) => setBpc(e.target.checked), className: "accent-indigo-500" }),
1551
1696
  "BPC"
1552
1697
  ] }),
1553
- /* @__PURE__ */ jsx9("button", { type: "button", className: chip2, title: "Edit \u203A Assign Profile: keep the numbers", onClick: () => attempt(() => controller.assignProfile(target)), children: "Assign" }),
1554
- /* @__PURE__ */ jsx9("button", { type: "button", className: chip2, title: "Edit \u203A Convert to Profile: keep the look", onClick: () => attempt(() => controller.convertToProfile(target, { intent, bpc })), children: "Convert" })
1698
+ /* @__PURE__ */ jsx10("button", { type: "button", className: chip2, title: "Edit \u203A Assign Profile: keep the numbers", onClick: () => attempt(() => controller.assignProfile(target)), children: "Assign" }),
1699
+ /* @__PURE__ */ jsx10("button", { type: "button", className: chip2, title: "Edit \u203A Convert to Profile: keep the look", onClick: () => attempt(() => controller.convertToProfile(target, { intent, bpc })), children: "Convert" })
1555
1700
  ] }),
1556
- /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Proof setup", children: [
1557
- /* @__PURE__ */ jsx9("span", { className: "text-slate-400", children: "Proof" }),
1558
- /* @__PURE__ */ jsxs8(
1701
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Proof setup", children: [
1702
+ /* @__PURE__ */ jsx10("span", { className: "text-slate-400", children: "Proof" }),
1703
+ /* @__PURE__ */ jsxs9(
1559
1704
  "select",
1560
1705
  {
1561
1706
  "aria-label": "Proof profile",
@@ -1563,36 +1708,36 @@ var ColorProfilePanel = ({ controller, className }) => {
1563
1708
  value: view.proof?.id ?? "",
1564
1709
  onChange: (e) => e.target.value ? proofWith({ id: e.target.value }) : attempt(() => controller.setProofSetup(null)),
1565
1710
  children: [
1566
- /* @__PURE__ */ jsx9("option", { value: "", children: "Off" }),
1567
- PROOF_PROFILE_OPTIONS.map((o) => /* @__PURE__ */ jsx9("option", { value: o.id, children: o.label }, o.id))
1711
+ /* @__PURE__ */ jsx10("option", { value: "", children: "Off" }),
1712
+ PROOF_PROFILE_OPTIONS.map((o) => /* @__PURE__ */ jsx10("option", { value: o.id, children: o.label }, o.id))
1568
1713
  ]
1569
1714
  }
1570
1715
  ),
1571
- view.proof && /* @__PURE__ */ jsxs8(Fragment2, { children: [
1572
- /* @__PURE__ */ jsx9("select", { "aria-label": "Proof intent", className: select, value: view.proof.intent, onChange: (e) => proofWith({ intent: e.target.value }), children: INTENT_OPTIONS.map((o) => /* @__PURE__ */ jsx9("option", { value: o.id, children: o.label }, o.id)) }),
1573
- /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1", children: [
1574
- /* @__PURE__ */ jsx9("input", { type: "checkbox", "aria-label": "Simulate paper colour", checked: view.proof.simulatePaper, onChange: (e) => proofWith({ simulatePaper: e.target.checked }), className: "accent-indigo-500" }),
1716
+ view.proof && /* @__PURE__ */ jsxs9(Fragment2, { children: [
1717
+ /* @__PURE__ */ jsx10("select", { "aria-label": "Proof intent", className: select, value: view.proof.intent, onChange: (e) => proofWith({ intent: e.target.value }), children: INTENT_OPTIONS.map((o) => /* @__PURE__ */ jsx10("option", { value: o.id, children: o.label }, o.id)) }),
1718
+ /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-1", children: [
1719
+ /* @__PURE__ */ jsx10("input", { type: "checkbox", "aria-label": "Simulate paper colour", checked: view.proof.simulatePaper, onChange: (e) => proofWith({ simulatePaper: e.target.checked }), className: "accent-indigo-500" }),
1575
1720
  "Paper"
1576
1721
  ] }),
1577
- /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-1", children: [
1578
- /* @__PURE__ */ jsx9("input", { type: "checkbox", "aria-label": "Gamut warning", checked: view.proof.gamutWarning, onChange: (e) => proofWith({ gamutWarning: e.target.checked }), className: "accent-indigo-500" }),
1722
+ /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-1", children: [
1723
+ /* @__PURE__ */ jsx10("input", { type: "checkbox", "aria-label": "Gamut warning", checked: view.proof.gamutWarning, onChange: (e) => proofWith({ gamutWarning: e.target.checked }), className: "accent-indigo-500" }),
1579
1724
  "Gamut warning"
1580
1725
  ] })
1581
1726
  ] })
1582
1727
  ] }),
1583
- error && /* @__PURE__ */ jsx9("p", { role: "alert", className: "text-rose-400", children: error })
1728
+ error && /* @__PURE__ */ jsx10("p", { role: "alert", className: "text-rose-400", children: error })
1584
1729
  ] });
1585
1730
  };
1586
1731
 
1587
1732
  // src/image-editor/SelectionOptionsBar.tsx
1588
- import { useState as useState9 } from "react";
1733
+ import { useState as useState10 } from "react";
1589
1734
  import {
1590
1735
  SELECTION_MODES,
1591
1736
  SELECTION_MODE_LABELS,
1592
1737
  SELECTION_TOOLS,
1593
1738
  describeSelection
1594
1739
  } from "@pixerate/editor/image-editor";
1595
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1740
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1596
1741
  var MODIFY_OPS = [
1597
1742
  { op: "grow", label: "Grow" },
1598
1743
  { op: "shrink", label: "Shrink" },
@@ -1600,7 +1745,7 @@ var MODIFY_OPS = [
1600
1745
  { op: "border", label: "Border" },
1601
1746
  { op: "smooth", label: "Smooth" }
1602
1747
  ];
1603
- 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"}`;
1748
+ 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"}`;
1604
1749
  var SelectionOptionsBar = ({
1605
1750
  controller,
1606
1751
  options,
@@ -1609,20 +1754,20 @@ var SelectionOptionsBar = ({
1609
1754
  quickMask,
1610
1755
  className = ""
1611
1756
  }) => {
1612
- const [radius, setRadius] = useState9(2);
1757
+ const [radius, setRadius] = useState10(2);
1613
1758
  const set = (patch) => onOptionsChange({ ...options, ...patch });
1614
1759
  const sel = selection === void 0 ? controller.getSelection() : selection;
1615
1760
  const qm = quickMask ?? Boolean(controller.getState().quickMask);
1616
- return /* @__PURE__ */ jsxs9("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1617
- /* @__PURE__ */ jsx10("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: SELECTION_TOOLS.map((t) => /* @__PURE__ */ jsx10("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)) }),
1618
- /* @__PURE__ */ jsx10("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: SELECTION_MODES.map((m) => /* @__PURE__ */ jsx10("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: SELECTION_MODE_LABELS[m] }, m)) }),
1619
- options.tool === "wand" && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
1620
- /* @__PURE__ */ jsxs9("label", { className: "flex flex-col gap-1", children: [
1621
- /* @__PURE__ */ jsxs9("span", { className: "flex justify-between text-slate-400", children: [
1622
- /* @__PURE__ */ jsx10("span", { children: "Tolerance" }),
1623
- /* @__PURE__ */ jsx10("span", { className: "font-mono", children: options.tolerance })
1761
+ return /* @__PURE__ */ jsxs10("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1762
+ /* @__PURE__ */ jsx11("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: SELECTION_TOOLS.map((t) => /* @__PURE__ */ jsx11("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)) }),
1763
+ /* @__PURE__ */ jsx11("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: SELECTION_MODES.map((m) => /* @__PURE__ */ jsx11("button", { type: "button", "aria-pressed": options.mode === m, className: btn2(options.mode === m), onClick: () => set({ mode: m }), children: SELECTION_MODE_LABELS[m] }, m)) }),
1764
+ options.tool === "wand" && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
1765
+ /* @__PURE__ */ jsxs10("label", { className: "flex flex-col gap-1", children: [
1766
+ /* @__PURE__ */ jsxs10("span", { className: "flex justify-between text-slate-400", children: [
1767
+ /* @__PURE__ */ jsx11("span", { children: "Tolerance" }),
1768
+ /* @__PURE__ */ jsx11("span", { className: "font-mono", children: options.tolerance })
1624
1769
  ] }),
1625
- /* @__PURE__ */ jsx10(
1770
+ /* @__PURE__ */ jsx11(
1626
1771
  "input",
1627
1772
  {
1628
1773
  type: "range",
@@ -1636,17 +1781,17 @@ var SelectionOptionsBar = ({
1636
1781
  }
1637
1782
  )
1638
1783
  ] }),
1639
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-2 text-slate-300", children: [
1640
- /* @__PURE__ */ jsx10("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
1784
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 text-slate-300", children: [
1785
+ /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
1641
1786
  "Contiguous"
1642
1787
  ] }),
1643
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-2 text-slate-300", children: [
1644
- /* @__PURE__ */ jsx10("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
1788
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 text-slate-300", children: [
1789
+ /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
1645
1790
  "Sample adjusted image"
1646
1791
  ] }),
1647
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-2 text-slate-300", children: [
1792
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 text-slate-300", children: [
1648
1793
  "Sample",
1649
- /* @__PURE__ */ jsxs9(
1794
+ /* @__PURE__ */ jsxs10(
1650
1795
  "select",
1651
1796
  {
1652
1797
  "aria-label": "Sample from",
@@ -1654,27 +1799,27 @@ var SelectionOptionsBar = ({
1654
1799
  onChange: (e) => set({ sample: e.target.value }),
1655
1800
  className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
1656
1801
  children: [
1657
- /* @__PURE__ */ jsx10("option", { value: "composite", children: "All layers" }),
1658
- /* @__PURE__ */ jsx10("option", { value: "active-layer", children: "Active layer" })
1802
+ /* @__PURE__ */ jsx11("option", { value: "composite", children: "All layers" }),
1803
+ /* @__PURE__ */ jsx11("option", { value: "active-layer", children: "Active layer" })
1659
1804
  ]
1660
1805
  }
1661
1806
  )
1662
1807
  ] })
1663
1808
  ] }),
1664
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-2 text-slate-300", children: [
1665
- /* @__PURE__ */ jsx10("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
1809
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 text-slate-300", children: [
1810
+ /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
1666
1811
  "Anti-alias"
1667
1812
  ] }),
1668
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap gap-1", children: [
1669
- /* @__PURE__ */ jsx10("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
1670
- /* @__PURE__ */ jsx10("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1671
- /* @__PURE__ */ jsx10("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1672
- /* @__PURE__ */ jsx10("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
1813
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-1", children: [
1814
+ /* @__PURE__ */ jsx11("button", { type: "button", className: btn2(false), onClick: () => controller.selectAll(), children: "Select All" }),
1815
+ /* @__PURE__ */ jsx11("button", { type: "button", className: btn2(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
1816
+ /* @__PURE__ */ jsx11("button", { type: "button", className: btn2(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
1817
+ /* @__PURE__ */ jsx11("button", { type: "button", "aria-pressed": qm, className: btn2(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
1673
1818
  ] }),
1674
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-1", children: [
1675
- /* @__PURE__ */ jsxs9("label", { className: "flex items-center gap-1 text-slate-400", children: [
1819
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-1", children: [
1820
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-1 text-slate-400", children: [
1676
1821
  "Radius",
1677
- /* @__PURE__ */ jsx10(
1822
+ /* @__PURE__ */ jsx11(
1678
1823
  "input",
1679
1824
  {
1680
1825
  type: "number",
@@ -1688,29 +1833,29 @@ var SelectionOptionsBar = ({
1688
1833
  }
1689
1834
  )
1690
1835
  ] }),
1691
- MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ jsx10("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
1836
+ MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ jsx11("button", { type: "button", className: btn2(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
1692
1837
  ] }),
1693
- /* @__PURE__ */ jsx10("p", { "data-testid": "selection-status", className: "text-slate-400", children: describeSelection(sel) })
1838
+ /* @__PURE__ */ jsx11("p", { "data-testid": "selection-status", className: "text-slate-400", children: describeSelection(sel) })
1694
1839
  ] });
1695
1840
  };
1696
1841
 
1697
1842
  // src/image-editor/RefineEdgePanel.tsx
1698
- import { useState as useState10 } from "react";
1843
+ import { useState as useState11 } from "react";
1699
1844
  import {
1700
1845
  ADJUSTMENT_KINDS as ADJUSTMENT_KINDS2,
1701
1846
  REFINE_EDGE_CONTROLS,
1702
1847
  adjustmentKindLabel as adjustmentKindLabel2,
1703
1848
  layerMaskFromSelection
1704
1849
  } from "@pixerate/editor/image-editor";
1705
- import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1850
+ import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1706
1851
  var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
1707
1852
  var button2 = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
1708
1853
  var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1709
- const [params, setParams] = useState10(DEFAULT_PARAMS);
1710
- const [busy, setBusy] = useState10(false);
1711
- const [error, setError] = useState10(null);
1712
- const [layerId, setLayerId] = useState10("");
1713
- const [newKind, setNewKind] = useState10("hueSaturation");
1854
+ const [params, setParams] = useState11(DEFAULT_PARAMS);
1855
+ const [busy, setBusy] = useState11(false);
1856
+ const [error, setError] = useState11(null);
1857
+ const [layerId, setLayerId] = useState11("");
1858
+ const [newKind, setNewKind] = useState11("hueSaturation");
1714
1859
  const sel = selection === void 0 ? controller.getSelection() : selection;
1715
1860
  const list = layers ?? controller.getAdjustmentLayers();
1716
1861
  const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
@@ -1725,17 +1870,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1725
1870
  setBusy(false);
1726
1871
  }
1727
1872
  };
1728
- return /* @__PURE__ */ jsxs10("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1729
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1730
- REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ jsxs10("label", { className: "flex flex-col gap-1", children: [
1731
- /* @__PURE__ */ jsxs10("span", { className: "flex justify-between text-slate-400", children: [
1732
- /* @__PURE__ */ jsx11("span", { children: c.label }),
1733
- /* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
1873
+ return /* @__PURE__ */ jsxs11("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
1874
+ /* @__PURE__ */ jsx12("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
1875
+ REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ jsxs11("label", { className: "flex flex-col gap-1", children: [
1876
+ /* @__PURE__ */ jsxs11("span", { className: "flex justify-between text-slate-400", children: [
1877
+ /* @__PURE__ */ jsx12("span", { children: c.label }),
1878
+ /* @__PURE__ */ jsxs11("span", { className: "font-mono", children: [
1734
1879
  params[c.id],
1735
1880
  c.unit
1736
1881
  ] })
1737
1882
  ] }),
1738
- /* @__PURE__ */ jsx11(
1883
+ /* @__PURE__ */ jsx12(
1739
1884
  "input",
1740
1885
  {
1741
1886
  type: "range",
@@ -1749,28 +1894,28 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1749
1894
  }
1750
1895
  )
1751
1896
  ] }, c.id)),
1752
- /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 text-slate-300", children: [
1753
- /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
1897
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-2 text-slate-300", children: [
1898
+ /* @__PURE__ */ jsx12("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
1754
1899
  "Smart Radius"
1755
1900
  ] }),
1756
- /* @__PURE__ */ jsxs10("div", { className: "flex gap-1", children: [
1757
- /* @__PURE__ */ jsx11("button", { type: "button", className: button2, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1758
- /* @__PURE__ */ jsx11("button", { type: "button", className: button2, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
1901
+ /* @__PURE__ */ jsxs11("div", { className: "flex gap-1", children: [
1902
+ /* @__PURE__ */ jsx12("button", { type: "button", className: button2, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
1903
+ /* @__PURE__ */ jsx12("button", { type: "button", className: button2, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
1759
1904
  ] }),
1760
- error && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-rose-400", children: error }),
1761
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1762
- /* @__PURE__ */ jsxs10("div", { className: "flex gap-1 items-center", children: [
1763
- /* @__PURE__ */ jsx11(
1905
+ error && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-rose-400", children: error }),
1906
+ /* @__PURE__ */ jsx12("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
1907
+ /* @__PURE__ */ jsxs11("div", { className: "flex gap-1 items-center", children: [
1908
+ /* @__PURE__ */ jsx12(
1764
1909
  "select",
1765
1910
  {
1766
1911
  "aria-label": "New masked layer kind",
1767
1912
  value: newKind,
1768
1913
  onChange: (e) => setNewKind(e.target.value),
1769
1914
  className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1770
- children: ADJUSTMENT_KINDS2.map((k) => /* @__PURE__ */ jsx11("option", { value: k.kind, children: k.label }, k.kind))
1915
+ children: ADJUSTMENT_KINDS2.map((k) => /* @__PURE__ */ jsx12("option", { value: k.kind, children: k.label }, k.kind))
1771
1916
  }
1772
1917
  ),
1773
- /* @__PURE__ */ jsx11(
1918
+ /* @__PURE__ */ jsx12(
1774
1919
  "button",
1775
1920
  {
1776
1921
  type: "button",
@@ -1781,35 +1926,35 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1781
1926
  }
1782
1927
  )
1783
1928
  ] }),
1784
- list.length > 0 && target && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
1785
- /* @__PURE__ */ jsx11(
1929
+ list.length > 0 && target && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-2", children: [
1930
+ /* @__PURE__ */ jsx12(
1786
1931
  "select",
1787
1932
  {
1788
1933
  "aria-label": "Mask layer",
1789
1934
  value: target.id,
1790
1935
  onChange: (e) => setLayerId(e.target.value),
1791
1936
  className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
1792
- children: list.map((l) => /* @__PURE__ */ jsxs10("option", { value: l.id, children: [
1937
+ children: list.map((l) => /* @__PURE__ */ jsxs11("option", { value: l.id, children: [
1793
1938
  l.name || adjustmentKindLabel2(l.kind),
1794
1939
  l.mask ? " (masked)" : ""
1795
1940
  ] }, l.id))
1796
1941
  }
1797
1942
  ),
1798
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-1", children: [
1799
- /* @__PURE__ */ jsx11("button", { type: "button", className: button2, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1800
- /* @__PURE__ */ jsx11("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1801
- /* @__PURE__ */ jsx11("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
1943
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap gap-1", children: [
1944
+ /* @__PURE__ */ jsx12("button", { type: "button", className: button2, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
1945
+ /* @__PURE__ */ jsx12("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
1946
+ /* @__PURE__ */ jsx12("button", { type: "button", className: button2, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
1802
1947
  ] }),
1803
- target.mask && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1804
- /* @__PURE__ */ jsxs10("label", { className: "flex flex-col gap-1", children: [
1805
- /* @__PURE__ */ jsxs10("span", { className: "flex justify-between text-slate-400", children: [
1806
- /* @__PURE__ */ jsx11("span", { children: "Density" }),
1807
- /* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
1948
+ target.mask && /* @__PURE__ */ jsxs11(Fragment3, { children: [
1949
+ /* @__PURE__ */ jsxs11("label", { className: "flex flex-col gap-1", children: [
1950
+ /* @__PURE__ */ jsxs11("span", { className: "flex justify-between text-slate-400", children: [
1951
+ /* @__PURE__ */ jsx12("span", { children: "Density" }),
1952
+ /* @__PURE__ */ jsxs11("span", { className: "font-mono", children: [
1808
1953
  Math.round((target.mask.density ?? 1) * 100),
1809
1954
  "%"
1810
1955
  ] })
1811
1956
  ] }),
1812
- /* @__PURE__ */ jsx11(
1957
+ /* @__PURE__ */ jsx12(
1813
1958
  "input",
1814
1959
  {
1815
1960
  type: "range",
@@ -1823,15 +1968,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1823
1968
  }
1824
1969
  )
1825
1970
  ] }),
1826
- /* @__PURE__ */ jsxs10("label", { className: "flex flex-col gap-1", children: [
1827
- /* @__PURE__ */ jsxs10("span", { className: "flex justify-between text-slate-400", children: [
1828
- /* @__PURE__ */ jsx11("span", { children: "Mask Feather" }),
1829
- /* @__PURE__ */ jsxs10("span", { className: "font-mono", children: [
1971
+ /* @__PURE__ */ jsxs11("label", { className: "flex flex-col gap-1", children: [
1972
+ /* @__PURE__ */ jsxs11("span", { className: "flex justify-between text-slate-400", children: [
1973
+ /* @__PURE__ */ jsx12("span", { children: "Mask Feather" }),
1974
+ /* @__PURE__ */ jsxs11("span", { className: "font-mono", children: [
1830
1975
  target.mask.feather ?? 0,
1831
1976
  "px"
1832
1977
  ] })
1833
1978
  ] }),
1834
- /* @__PURE__ */ jsx11(
1979
+ /* @__PURE__ */ jsx12(
1835
1980
  "input",
1836
1981
  {
1837
1982
  type: "range",
@@ -1851,14 +1996,14 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
1851
1996
  };
1852
1997
 
1853
1998
  // src/image-editor/FreeTransformOptionsBar.tsx
1854
- import { useEffect as useEffect8, useState as useState11 } from "react";
1999
+ import { useEffect as useEffect9, useState as useState12 } from "react";
1855
2000
  import { FREE_TRANSFORM_FIELDS, FREE_TRANSFORM_MODE_OPTIONS, INTERPOLATIONS, TRANSFORM_ANCHORS, WARP_GRID_OPTIONS, WARP_STYLE_OPTIONS } from "@pixerate/editor/image-editor";
1856
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2001
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1857
2002
  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"}`;
1858
2003
  var round = (v, unit) => unit === "px" ? Math.round(v * 10) / 10 : Math.round(v * 100) / 100;
1859
2004
  var FreeTransformOptionsBar = ({ tool, className }) => {
1860
- const [, setTick] = useState11(0);
1861
- useEffect8(() => tool.subscribe(() => setTick((n) => n + 1)), [tool]);
2005
+ const [, setTick] = useState12(0);
2006
+ useEffect9(() => tool.subscribe(() => setTick((n) => n + 1)), [tool]);
1862
2007
  const bar = tool.bar();
1863
2008
  if (!tool.active || !bar) return null;
1864
2009
  const warp = tool.warpBar();
@@ -1870,17 +2015,17 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1870
2015
  const v = Number(raw);
1871
2016
  if (raw.trim() !== "" && Number.isFinite(v) && Math.abs(v - bar[field]) > 1e-9) tool.setField(field, v);
1872
2017
  };
1873
- return /* @__PURE__ */ jsxs11("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: [
1874
- /* @__PURE__ */ jsx12("div", { className: "flex gap-1", role: "group", "aria-label": "Transform mode", children: FREE_TRANSFORM_MODE_OPTIONS.map((m) => /* @__PURE__ */ jsx12("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)) }),
1875
- /* @__PURE__ */ jsx12("div", { className: "grid grid-cols-3 gap-px", role: "group", "aria-label": "Reference point", children: TRANSFORM_ANCHORS.map((a) => /* @__PURE__ */ jsx12("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)) }),
1876
- tool.mode === "warp" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": "Warp options", children: [
1877
- /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1878
- /* @__PURE__ */ jsx12("span", { className: "text-slate-400", children: "Warp" }),
1879
- /* @__PURE__ */ jsx12("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: WARP_STYLE_OPTIONS.map((o) => /* @__PURE__ */ jsx12("option", { value: o.id, children: o.label }, o.id)) })
2018
+ return /* @__PURE__ */ jsxs12("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: [
2019
+ /* @__PURE__ */ jsx13("div", { className: "flex gap-1", role: "group", "aria-label": "Transform mode", children: FREE_TRANSFORM_MODE_OPTIONS.map((m) => /* @__PURE__ */ jsx13("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)) }),
2020
+ /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-px", role: "group", "aria-label": "Reference point", children: TRANSFORM_ANCHORS.map((a) => /* @__PURE__ */ jsx13("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)) }),
2021
+ tool.mode === "warp" && /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": "Warp options", children: [
2022
+ /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2023
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-400", children: "Warp" }),
2024
+ /* @__PURE__ */ jsx13("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: WARP_STYLE_OPTIONS.map((o) => /* @__PURE__ */ jsx13("option", { value: o.id, children: o.label }, o.id)) })
1880
2025
  ] }),
1881
- ["bend", "horizontal", "vertical"].map((k) => /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1882
- /* @__PURE__ */ jsx12("span", { className: "text-slate-400", children: k === "bend" ? "Bend" : k === "horizontal" ? "H" : "V" }),
1883
- /* @__PURE__ */ jsx12(
2026
+ ["bend", "horizontal", "vertical"].map((k) => /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2027
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-400", children: k === "bend" ? "Bend" : k === "horizontal" ? "H" : "V" }),
2028
+ /* @__PURE__ */ jsx13(
1884
2029
  "input",
1885
2030
  {
1886
2031
  type: "number",
@@ -1901,9 +2046,9 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1901
2046
  },
1902
2047
  `${k}:${warp[k]}`
1903
2048
  ),
1904
- /* @__PURE__ */ jsx12("span", { className: "text-slate-500", children: "%" })
2049
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-500", children: "%" })
1905
2050
  ] }, k)),
1906
- /* @__PURE__ */ jsx12(
2051
+ /* @__PURE__ */ jsx13(
1907
2052
  "button",
1908
2053
  {
1909
2054
  type: "button",
@@ -1915,9 +2060,9 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1915
2060
  children: "Vertical"
1916
2061
  }
1917
2062
  ),
1918
- /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1919
- /* @__PURE__ */ jsx12("span", { className: "text-slate-400", children: "Grid" }),
1920
- /* @__PURE__ */ jsx12(
2063
+ /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2064
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-400", children: "Grid" }),
2065
+ /* @__PURE__ */ jsx13(
1921
2066
  "select",
1922
2067
  {
1923
2068
  "aria-label": "Warp grid",
@@ -1927,14 +2072,14 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1927
2072
  tool.setWarp({ columns: g.columns, rows: g.rows });
1928
2073
  },
1929
2074
  className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
1930
- children: WARP_GRID_OPTIONS.map((g) => /* @__PURE__ */ jsx12("option", { value: g.id, children: g.label }, g.id))
2075
+ children: WARP_GRID_OPTIONS.map((g) => /* @__PURE__ */ jsx13("option", { value: g.id, children: g.label }, g.id))
1931
2076
  }
1932
2077
  )
1933
2078
  ] })
1934
2079
  ] }),
1935
- tool.mode !== "warp" && FREE_TRANSFORM_FIELDS.map((f) => /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", title: f.title, children: [
1936
- /* @__PURE__ */ jsx12("span", { className: "text-slate-400", children: f.label }),
1937
- /* @__PURE__ */ jsx12(
2080
+ tool.mode !== "warp" && FREE_TRANSFORM_FIELDS.map((f) => /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", title: f.title, children: [
2081
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-400", children: f.label }),
2082
+ /* @__PURE__ */ jsx13(
1938
2083
  "input",
1939
2084
  {
1940
2085
  type: "number",
@@ -1954,8 +2099,8 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1954
2099
  },
1955
2100
  `${f.id}:${round(bar[f.id], f.unit)}`
1956
2101
  ),
1957
- /* @__PURE__ */ jsx12("span", { className: "text-slate-500", children: f.unit }),
1958
- f.id === "scaleX" && /* @__PURE__ */ jsx12(
2102
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-500", children: f.unit }),
2103
+ f.id === "scaleX" && /* @__PURE__ */ jsx13(
1959
2104
  "button",
1960
2105
  {
1961
2106
  type: "button",
@@ -1970,34 +2115,34 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1970
2115
  }
1971
2116
  )
1972
2117
  ] }, f.id)),
1973
- /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1974
- /* @__PURE__ */ jsx12("span", { className: "text-slate-400", children: "Interpolation" }),
1975
- /* @__PURE__ */ jsx12(
2118
+ /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2119
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-400", children: "Interpolation" }),
2120
+ /* @__PURE__ */ jsx13(
1976
2121
  "select",
1977
2122
  {
1978
2123
  "aria-label": "Interpolation",
1979
2124
  value: tool.interpolation,
1980
2125
  onChange: (e) => tool.setInterpolation(e.target.value),
1981
2126
  className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
1982
- children: INTERPOLATIONS.map((i) => /* @__PURE__ */ jsx12("option", { value: i, children: i[0].toUpperCase() + i.slice(1) }, i))
2127
+ children: INTERPOLATIONS.map((i) => /* @__PURE__ */ jsx13("option", { value: i, children: i[0].toUpperCase() + i.slice(1) }, i))
1983
2128
  }
1984
2129
  )
1985
2130
  ] }),
1986
- /* @__PURE__ */ jsx12("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" }),
1987
- /* @__PURE__ */ jsx12("button", { type: "button", title: "Cancel (Esc)", className: chip3(false), onClick: () => tool.cancel(), children: "Cancel" }),
1988
- tool.error && /* @__PURE__ */ jsx12("span", { role: "alert", className: "text-rose-400", children: tool.error })
2131
+ /* @__PURE__ */ jsx13("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" }),
2132
+ /* @__PURE__ */ jsx13("button", { type: "button", title: "Cancel (Esc)", className: chip3(false), onClick: () => tool.cancel(), children: "Cancel" }),
2133
+ tool.error && /* @__PURE__ */ jsx13("span", { role: "alert", className: "text-rose-400", children: tool.error })
1989
2134
  ] });
1990
2135
  };
1991
2136
 
1992
2137
  // src/image-editor/ShapeOptionsBar.tsx
1993
- import { useEffect as useEffect9, useState as useState12 } from "react";
2138
+ import { useEffect as useEffect10, useState as useState13 } from "react";
1994
2139
  import { LIVE_SHAPE_KINDS, SHAPE_KIND_LABELS, applyShapeOptions } from "@pixerate/editor/image-editor";
1995
- import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
2140
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1996
2141
  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"}`;
1997
2142
  var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
1998
- const [, setTick] = useState12(0);
1999
- useEffect9(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
2000
- const [error, setError] = useState12(null);
2143
+ const [, setTick] = useState13(0);
2144
+ useEffect10(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
2145
+ const [error, setError] = useState13(null);
2001
2146
  const active = controller.getActiveLayer();
2002
2147
  const shapeId = active?.type === "shape" ? active.id : null;
2003
2148
  const set = (change) => {
@@ -2011,13 +2156,13 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
2011
2156
  }
2012
2157
  };
2013
2158
  const num = (v, min, max) => Math.max(min, Math.min(max, Number(v) || min));
2014
- return /* @__PURE__ */ jsxs12("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "shape-options", children: [
2015
- /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Shape kind", children: LIVE_SHAPE_KINDS.map((k) => /* @__PURE__ */ jsx13("button", { type: "button", "aria-pressed": options.kind === k, className: chip4(options.kind === k), onClick: () => onChange({ ...options, kind: k }), children: SHAPE_KIND_LABELS[k] }, k)) }),
2016
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-3", children: [
2017
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2018
- /* @__PURE__ */ jsx13("input", { type: "checkbox", "aria-label": "Fill", checked: options.fill !== null, onChange: (e) => set({ fill: e.target.checked ? "#4f46e5" : null }) }),
2159
+ return /* @__PURE__ */ jsxs13("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "shape-options", children: [
2160
+ /* @__PURE__ */ jsx14("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Shape kind", children: LIVE_SHAPE_KINDS.map((k) => /* @__PURE__ */ jsx14("button", { type: "button", "aria-pressed": options.kind === k, className: chip4(options.kind === k), onClick: () => onChange({ ...options, kind: k }), children: SHAPE_KIND_LABELS[k] }, k)) }),
2161
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-3", children: [
2162
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2163
+ /* @__PURE__ */ jsx14("input", { type: "checkbox", "aria-label": "Fill", checked: options.fill !== null, onChange: (e) => set({ fill: e.target.checked ? "#4f46e5" : null }) }),
2019
2164
  "Fill",
2020
- /* @__PURE__ */ jsx13(
2165
+ /* @__PURE__ */ jsx14(
2021
2166
  "input",
2022
2167
  {
2023
2168
  type: "color",
@@ -2029,10 +2174,10 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
2029
2174
  }
2030
2175
  )
2031
2176
  ] }),
2032
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2033
- /* @__PURE__ */ jsx13("input", { type: "checkbox", "aria-label": "Stroke", checked: options.stroke !== null, onChange: (e) => set({ stroke: e.target.checked ? "#000000" : null }) }),
2177
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2178
+ /* @__PURE__ */ jsx14("input", { type: "checkbox", "aria-label": "Stroke", checked: options.stroke !== null, onChange: (e) => set({ stroke: e.target.checked ? "#000000" : null }) }),
2034
2179
  "Stroke",
2035
- /* @__PURE__ */ jsx13(
2180
+ /* @__PURE__ */ jsx14(
2036
2181
  "input",
2037
2182
  {
2038
2183
  type: "color",
@@ -2044,9 +2189,9 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
2044
2189
  }
2045
2190
  )
2046
2191
  ] }),
2047
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2192
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2048
2193
  "Width",
2049
- /* @__PURE__ */ jsx13(
2194
+ /* @__PURE__ */ jsx14(
2050
2195
  "input",
2051
2196
  {
2052
2197
  type: "number",
@@ -2060,23 +2205,23 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
2060
2205
  )
2061
2206
  ] })
2062
2207
  ] }),
2063
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-3", children: [
2064
- options.kind === "rect" && /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2208
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-3", children: [
2209
+ options.kind === "rect" && /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2065
2210
  "Radius",
2066
- /* @__PURE__ */ jsx13("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" })
2211
+ /* @__PURE__ */ jsx14("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" })
2067
2212
  ] }),
2068
- options.kind === "polygon" && /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2213
+ options.kind === "polygon" && /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2069
2214
  "Sides",
2070
- /* @__PURE__ */ jsx13("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" })
2215
+ /* @__PURE__ */ jsx14("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" })
2071
2216
  ] }),
2072
- options.kind === "star" && /* @__PURE__ */ jsxs12(Fragment4, { children: [
2073
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2217
+ options.kind === "star" && /* @__PURE__ */ jsxs13(Fragment4, { children: [
2218
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2074
2219
  "Points",
2075
- /* @__PURE__ */ jsx13("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" })
2220
+ /* @__PURE__ */ jsx14("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" })
2076
2221
  ] }),
2077
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2222
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2078
2223
  "Inner",
2079
- /* @__PURE__ */ jsx13(
2224
+ /* @__PURE__ */ jsx14(
2080
2225
  "input",
2081
2226
  {
2082
2227
  type: "range",
@@ -2091,33 +2236,33 @@ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
2091
2236
  )
2092
2237
  ] })
2093
2238
  ] }),
2094
- options.kind === "line" && /* @__PURE__ */ jsxs12(Fragment4, { children: [
2095
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2239
+ options.kind === "line" && /* @__PURE__ */ jsxs13(Fragment4, { children: [
2240
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2096
2241
  "Weight",
2097
- /* @__PURE__ */ jsx13("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" })
2242
+ /* @__PURE__ */ jsx14("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" })
2098
2243
  ] }),
2099
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2100
- /* @__PURE__ */ jsx13("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
2244
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2245
+ /* @__PURE__ */ jsx14("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
2101
2246
  "Arrowhead"
2102
2247
  ] })
2103
2248
  ] })
2104
2249
  ] }),
2105
- /* @__PURE__ */ jsx13("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." }),
2106
- error && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-rose-400", children: error })
2250
+ /* @__PURE__ */ jsx14("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." }),
2251
+ error && /* @__PURE__ */ jsx14("p", { role: "alert", className: "text-rose-400", children: error })
2107
2252
  ] });
2108
2253
  };
2109
2254
 
2110
2255
  // src/image-editor/TypeOptionsBar.tsx
2111
- import { useEffect as useEffect10, useState as useState13 } from "react";
2256
+ import { useEffect as useEffect11, useState as useState14 } from "react";
2112
2257
  import { TEXT_ALIGNS } from "@pixerate/editor/image-editor";
2113
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
2258
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2114
2259
  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"}`;
2115
2260
  var ALIGN_LABELS = { left: "Left", center: "Centre", right: "Right", justify: "Justify" };
2116
2261
  var TypeOptionsBar = ({ controller, options, onChange, session, className }) => {
2117
- const [, setTick] = useState13(0);
2118
- useEffect10(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
2119
- useEffect10(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
2120
- const [error, setError] = useState13(null);
2262
+ const [, setTick] = useState14(0);
2263
+ useEffect11(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
2264
+ useEffect11(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
2265
+ const [error, setError] = useState14(null);
2121
2266
  const active = controller.getActiveLayer();
2122
2267
  const typeId = !session && active?.type === "type" ? active.id : null;
2123
2268
  const here = session?.alive ? session.styleHere() : {};
@@ -2149,11 +2294,11 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
2149
2294
  setError(e instanceof Error ? e.message : String(e));
2150
2295
  }
2151
2296
  };
2152
- return /* @__PURE__ */ jsxs13("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "type-options", children: [
2153
- /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-2", children: [
2154
- /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2297
+ return /* @__PURE__ */ jsxs14("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "type-options", children: [
2298
+ /* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-2", children: [
2299
+ /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1", children: [
2155
2300
  "Font",
2156
- /* @__PURE__ */ jsx14(
2301
+ /* @__PURE__ */ jsx15(
2157
2302
  "input",
2158
2303
  {
2159
2304
  list: "pixerate-type-fonts",
@@ -2163,11 +2308,11 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
2163
2308
  className: "w-32 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
2164
2309
  }
2165
2310
  ),
2166
- /* @__PURE__ */ jsx14("datalist", { id: "pixerate-type-fonts", children: fonts.map((f) => /* @__PURE__ */ jsx14("option", { value: f }, f)) })
2311
+ /* @__PURE__ */ jsx15("datalist", { id: "pixerate-type-fonts", children: fonts.map((f) => /* @__PURE__ */ jsx15("option", { value: f }, f)) })
2167
2312
  ] }),
2168
- /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1", children: [
2313
+ /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1", children: [
2169
2314
  "Size",
2170
- /* @__PURE__ */ jsx14(
2315
+ /* @__PURE__ */ jsx15(
2171
2316
  "input",
2172
2317
  {
2173
2318
  type: "number",
@@ -2180,24 +2325,24 @@ var TypeOptionsBar = ({ controller, options, onChange, session, className }) =>
2180
2325
  }
2181
2326
  )
2182
2327
  ] }),
2183
- /* @__PURE__ */ jsx14("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" }),
2184
- /* @__PURE__ */ jsx14("button", { type: "button", "aria-pressed": shown.italic, className: `${chip5(shown.italic)} italic`, onClick: () => style({ italic: !shown.italic }), children: "I" }),
2185
- /* @__PURE__ */ jsx14("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" })
2328
+ /* @__PURE__ */ jsx15("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" }),
2329
+ /* @__PURE__ */ jsx15("button", { type: "button", "aria-pressed": shown.italic, className: `${chip5(shown.italic)} italic`, onClick: () => style({ italic: !shown.italic }), children: "I" }),
2330
+ /* @__PURE__ */ jsx15("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" })
2186
2331
  ] }),
2187
- /* @__PURE__ */ jsx14("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Alignment", children: TEXT_ALIGNS.map((a) => /* @__PURE__ */ jsx14("button", { type: "button", "aria-pressed": options.align === a, className: chip5(options.align === a), onClick: () => style({ align: a }), children: ALIGN_LABELS[a] }, a)) }),
2188
- /* @__PURE__ */ jsx14("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." }),
2189
- missing.length > 0 && /* @__PURE__ */ jsxs13("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
2332
+ /* @__PURE__ */ jsx15("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Alignment", children: TEXT_ALIGNS.map((a) => /* @__PURE__ */ jsx15("button", { type: "button", "aria-pressed": options.align === a, className: chip5(options.align === a), onClick: () => style({ align: a }), children: ALIGN_LABELS[a] }, a)) }),
2333
+ /* @__PURE__ */ jsx15("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." }),
2334
+ missing.length > 0 && /* @__PURE__ */ jsxs14("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
2190
2335
  "Missing ",
2191
2336
  missing.length === 1 ? "font" : "fonts",
2192
2337
  ": ",
2193
2338
  missing.join(", ")
2194
2339
  ] }),
2195
- error && /* @__PURE__ */ jsx14("p", { role: "alert", className: "text-rose-400", children: error })
2340
+ error && /* @__PURE__ */ jsx15("p", { role: "alert", className: "text-rose-400", children: error })
2196
2341
  ] });
2197
2342
  };
2198
2343
 
2199
2344
  // src/image-editor/ImageEditor.tsx
2200
- import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2345
+ import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
2201
2346
  var ImageEditor = ({
2202
2347
  editor: externalEditor,
2203
2348
  src,
@@ -2207,17 +2352,22 @@ var ImageEditor = ({
2207
2352
  exportOptions,
2208
2353
  onInpaint,
2209
2354
  onRemoveBackground,
2210
- aiHooks
2355
+ aiHooks,
2356
+ effects
2211
2357
  }) => {
2212
2358
  const internalEditor = useImageEditor({ image: src });
2213
2359
  const editor = externalEditor || internalEditor;
2214
2360
  const { state, controller } = editor;
2361
+ useEffects(controller, effects);
2362
+ const effectsShown = !!controller.effectsProvider || state.layers.some(function has(l) {
2363
+ return l.type === "pixel" && !!l.generator || l.type === "smart" && !!l.smartFilters?.filters.some((f) => f.kind === "effect") || l.type === "group" && l.children.some(has);
2364
+ });
2215
2365
  const legacyProcess = normalizeProcessVersion(state.adjustments.process) < LATEST_PROCESS_VERSION;
2216
2366
  const canvasRef = useRef5(null);
2217
2367
  const containerRef = useRef5(null);
2218
- const [activeTab, setActiveTab] = useState14("crop");
2219
- const [activeCropRatio, setActiveCropRatio] = useState14(null);
2220
- const [selectionOptions, setSelectionOptions] = useState14(DEFAULT_SELECTION_TOOL_OPTIONS);
2368
+ const [activeTab, setActiveTab] = useState15("crop");
2369
+ const [activeCropRatio, setActiveCropRatio] = useState15(null);
2370
+ const [selectionOptions, setSelectionOptions] = useState15(DEFAULT_SELECTION_TOOL_OPTIONS);
2221
2371
  const selectionOptionsRef = useRef5(selectionOptions);
2222
2372
  selectionOptionsRef.current = selectionOptions;
2223
2373
  const selectionGestureRef = useRef5(null);
@@ -2225,7 +2375,7 @@ var ImageEditor = ({
2225
2375
  selectionGestureRef.current = new SelectionGesture(controller, () => selectionOptionsRef.current);
2226
2376
  }
2227
2377
  const selectionDraftRef = useRef5(null);
2228
- const [selectionError, setSelectionError] = useState14(null);
2378
+ const [selectionError, setSelectionError] = useState15(null);
2229
2379
  const paintGestureRef = useRef5(null);
2230
2380
  const paintControllerRef = useRef5(controller);
2231
2381
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
@@ -2233,7 +2383,7 @@ var ImageEditor = ({
2233
2383
  paintControllerRef.current = controller;
2234
2384
  }
2235
2385
  const brushCursorRef = useRef5(null);
2236
- const [paintError, setPaintError] = useState14(null);
2386
+ const [paintError, setPaintError] = useState15(null);
2237
2387
  const transformToolRef = useRef5(null);
2238
2388
  const transformControllerRef = useRef5(controller);
2239
2389
  if (!transformToolRef.current || transformControllerRef.current !== controller) {
@@ -2244,12 +2394,12 @@ var ImageEditor = ({
2244
2394
  transformControllerRef.current = controller;
2245
2395
  }
2246
2396
  const transformTool = transformToolRef.current;
2247
- const [, setTransformTick] = useState14(0);
2248
- const [transformCursor, setTransformCursor] = useState14("default");
2249
- const [shapeOptions, setShapeOptions] = useState14(DEFAULT_SHAPE_TOOL_OPTIONS);
2397
+ const [, setTransformTick] = useState15(0);
2398
+ const [transformCursor, setTransformCursor] = useState15("default");
2399
+ const [shapeOptions, setShapeOptions] = useState15(DEFAULT_SHAPE_TOOL_OPTIONS);
2250
2400
  const shapeOptionsRef = useRef5(shapeOptions);
2251
2401
  shapeOptionsRef.current = shapeOptions;
2252
- const [typeOptions, setTypeOptions] = useState14(DEFAULT_TYPE_TOOL_OPTIONS);
2402
+ const [typeOptions, setTypeOptions] = useState15(DEFAULT_TYPE_TOOL_OPTIONS);
2253
2403
  const typeOptionsRef = useRef5(typeOptions);
2254
2404
  typeOptionsRef.current = typeOptions;
2255
2405
  const shapeGestureRef = useRef5(null);
@@ -2262,15 +2412,15 @@ var ImageEditor = ({
2262
2412
  shapeTypeControllerRef.current = controller;
2263
2413
  }
2264
2414
  const typeInputRef = useRef5(null);
2265
- const [typeSession, setTypeSession] = useState14(typeToolRef.current.session);
2266
- const [shapeTypeError, setShapeTypeError] = useState14(null);
2267
- const [inpaintPrompt, setInpaintPrompt] = useState14("");
2268
- const [inpaintMaskMode, setInpaintMaskMode] = useState14("annotations");
2269
- const [isRemovingBg, setIsRemovingBg] = useState14(false);
2270
- const [isInpainting, setIsInpainting] = useState14(false);
2271
- const [aiError, setAiError] = useState14(null);
2272
- const [aiSuccess, setAiSuccess] = useState14(null);
2273
- const [aiTarget, setAiTarget] = useState14("auto");
2415
+ const [typeSession, setTypeSession] = useState15(typeToolRef.current.session);
2416
+ const [shapeTypeError, setShapeTypeError] = useState15(null);
2417
+ const [inpaintPrompt, setInpaintPrompt] = useState15("");
2418
+ const [inpaintMaskMode, setInpaintMaskMode] = useState15("annotations");
2419
+ const [isRemovingBg, setIsRemovingBg] = useState15(false);
2420
+ const [isInpainting, setIsInpainting] = useState15(false);
2421
+ const [aiError, setAiError] = useState15(null);
2422
+ const [aiSuccess, setAiSuccess] = useState15(null);
2423
+ const [aiTarget, setAiTarget] = useState15("auto");
2274
2424
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
2275
2425
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
2276
2426
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -2333,10 +2483,10 @@ var ImageEditor = ({
2333
2483
  setIsInpainting(false);
2334
2484
  }
2335
2485
  };
2336
- const [activeColor, setActiveColor] = useState14("#ef4444");
2337
- const [strokeWidth, setStrokeWidth] = useState14(3);
2338
- const [fontSize, setFontSize] = useState14(24);
2339
- const [textInput, setTextInput] = useState14("");
2486
+ const [activeColor, setActiveColor] = useState15("#ef4444");
2487
+ const [strokeWidth, setStrokeWidth] = useState15(3);
2488
+ const [fontSize, setFontSize] = useState15(24);
2489
+ const [textInput, setTextInput] = useState15("");
2340
2490
  const draftAnnotationRef = useRef5(null);
2341
2491
  const draftCropRef = useRef5(null);
2342
2492
  const cropDragInfoRef = useRef5(null);
@@ -2367,8 +2517,8 @@ var ImageEditor = ({
2367
2517
  },
2368
2518
  [controller, activeTab, transformTool]
2369
2519
  );
2370
- useEffect11(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
2371
- useEffect11(() => {
2520
+ useEffect12(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
2521
+ useEffect12(() => {
2372
2522
  if (activeTab === "annotate" && state.activeTool === "type") return;
2373
2523
  if (typeToolRef.current?.session) {
2374
2524
  typeToolRef.current.finish();
@@ -2403,7 +2553,7 @@ var ImageEditor = ({
2403
2553
  el.value = "";
2404
2554
  }
2405
2555
  };
2406
- useEffect11(() => transformTool.subscribe(() => {
2556
+ useEffect12(() => transformTool.subscribe(() => {
2407
2557
  setTransformTick((n) => n + 1);
2408
2558
  void renderCanvas();
2409
2559
  }), [transformTool, renderCanvas]);
@@ -2446,7 +2596,7 @@ var ImageEditor = ({
2446
2596
  transformTool.up();
2447
2597
  return true;
2448
2598
  };
2449
- useEffect11(() => {
2599
+ useEffect12(() => {
2450
2600
  if (typeof window === "undefined") return;
2451
2601
  const onKey = (e) => {
2452
2602
  if (transformTool.key(e)) e.preventDefault();
@@ -2454,7 +2604,7 @@ var ImageEditor = ({
2454
2604
  window.addEventListener("keydown", onKey);
2455
2605
  return () => window.removeEventListener("keydown", onKey);
2456
2606
  }, [transformTool]);
2457
- useEffect11(() => {
2607
+ useEffect12(() => {
2458
2608
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
2459
2609
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
2460
2610
  const animId = raf(() => {
@@ -2462,12 +2612,12 @@ var ImageEditor = ({
2462
2612
  });
2463
2613
  return () => caf(animId);
2464
2614
  }, [renderCanvas, state]);
2465
- useEffect11(() => {
2615
+ useEffect12(() => {
2466
2616
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
2467
2617
  editor.setTool("crop");
2468
2618
  }
2469
2619
  }, [activeTab, editor]);
2470
- useEffect11(() => {
2620
+ useEffect12(() => {
2471
2621
  const container = containerRef.current;
2472
2622
  if (!container) return;
2473
2623
  if (typeof ResizeObserver !== "undefined") {
@@ -2535,7 +2685,7 @@ var ImageEditor = ({
2535
2685
  if (g.error) setPaintError(g.error);
2536
2686
  }
2537
2687
  };
2538
- useEffect11(() => {
2688
+ useEffect12(() => {
2539
2689
  if (activeTab !== "paint" || typeof window === "undefined") return;
2540
2690
  const onKey = (e) => {
2541
2691
  if (handlePaintShortcut(controller, e)) e.preventDefault();
@@ -2930,15 +3080,15 @@ var ImageEditor = ({
2930
3080
  link.click();
2931
3081
  }
2932
3082
  };
2933
- return /* @__PURE__ */ jsxs14(
3083
+ return /* @__PURE__ */ jsxs15(
2934
3084
  "div",
2935
3085
  {
2936
3086
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
2937
3087
  style,
2938
3088
  children: [
2939
- /* @__PURE__ */ jsxs14("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: [
2940
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2941
- /* @__PURE__ */ jsx15(
3089
+ /* @__PURE__ */ jsxs15("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: [
3090
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
3091
+ /* @__PURE__ */ jsx16(
2942
3092
  "button",
2943
3093
  {
2944
3094
  type: "button",
@@ -2950,7 +3100,7 @@ var ImageEditor = ({
2950
3100
  children: "Transform & Crop"
2951
3101
  }
2952
3102
  ),
2953
- /* @__PURE__ */ jsx15(
3103
+ /* @__PURE__ */ jsx16(
2954
3104
  "button",
2955
3105
  {
2956
3106
  type: "button",
@@ -2962,7 +3112,7 @@ var ImageEditor = ({
2962
3112
  children: "Adjustments"
2963
3113
  }
2964
3114
  ),
2965
- /* @__PURE__ */ jsx15(
3115
+ /* @__PURE__ */ jsx16(
2966
3116
  "button",
2967
3117
  {
2968
3118
  type: "button",
@@ -2974,7 +3124,7 @@ var ImageEditor = ({
2974
3124
  children: "Layers"
2975
3125
  }
2976
3126
  ),
2977
- /* @__PURE__ */ jsx15(
3127
+ /* @__PURE__ */ jsx16(
2978
3128
  "button",
2979
3129
  {
2980
3130
  type: "button",
@@ -2986,7 +3136,7 @@ var ImageEditor = ({
2986
3136
  children: "Paint"
2987
3137
  }
2988
3138
  ),
2989
- /* @__PURE__ */ jsx15(
3139
+ /* @__PURE__ */ jsx16(
2990
3140
  "button",
2991
3141
  {
2992
3142
  type: "button",
@@ -2998,7 +3148,7 @@ var ImageEditor = ({
2998
3148
  children: "Select & Mask"
2999
3149
  }
3000
3150
  ),
3001
- /* @__PURE__ */ jsx15(
3151
+ /* @__PURE__ */ jsx16(
3002
3152
  "button",
3003
3153
  {
3004
3154
  type: "button",
@@ -3010,7 +3160,7 @@ var ImageEditor = ({
3010
3160
  children: "Annotations"
3011
3161
  }
3012
3162
  ),
3013
- /* @__PURE__ */ jsx15(
3163
+ /* @__PURE__ */ jsx16(
3014
3164
  "button",
3015
3165
  {
3016
3166
  type: "button",
@@ -3022,7 +3172,7 @@ var ImageEditor = ({
3022
3172
  children: "Depth Mask"
3023
3173
  }
3024
3174
  ),
3025
- /* @__PURE__ */ jsxs14(
3175
+ /* @__PURE__ */ jsxs15(
3026
3176
  "button",
3027
3177
  {
3028
3178
  type: "button",
@@ -3032,14 +3182,14 @@ var ImageEditor = ({
3032
3182
  },
3033
3183
  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"}`,
3034
3184
  children: [
3035
- /* @__PURE__ */ jsx15("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx15("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" }) }),
3185
+ /* @__PURE__ */ jsx16("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx16("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" }) }),
3036
3186
  "AI Tools"
3037
3187
  ]
3038
3188
  }
3039
3189
  )
3040
3190
  ] }),
3041
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 text-xs", children: [
3042
- /* @__PURE__ */ jsx15(
3191
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 text-xs", children: [
3192
+ /* @__PURE__ */ jsx16(
3043
3193
  "button",
3044
3194
  {
3045
3195
  type: "button",
@@ -3050,7 +3200,7 @@ var ImageEditor = ({
3050
3200
  children: "\u21A9"
3051
3201
  }
3052
3202
  ),
3053
- /* @__PURE__ */ jsx15(
3203
+ /* @__PURE__ */ jsx16(
3054
3204
  "button",
3055
3205
  {
3056
3206
  type: "button",
@@ -3061,7 +3211,7 @@ var ImageEditor = ({
3061
3211
  children: "\u21AA"
3062
3212
  }
3063
3213
  ),
3064
- /* @__PURE__ */ jsx15(
3214
+ /* @__PURE__ */ jsx16(
3065
3215
  "button",
3066
3216
  {
3067
3217
  type: "button",
@@ -3070,8 +3220,8 @@ var ImageEditor = ({
3070
3220
  children: "Reset"
3071
3221
  }
3072
3222
  ),
3073
- /* @__PURE__ */ jsx15("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
3074
- /* @__PURE__ */ jsx15(
3223
+ /* @__PURE__ */ jsx16("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
3224
+ /* @__PURE__ */ jsx16(
3075
3225
  "button",
3076
3226
  {
3077
3227
  type: "button",
@@ -3081,11 +3231,11 @@ var ImageEditor = ({
3081
3231
  children: "-"
3082
3232
  }
3083
3233
  ),
3084
- /* @__PURE__ */ jsxs14("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
3234
+ /* @__PURE__ */ jsxs15("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
3085
3235
  Math.round(state.zoom * 100),
3086
3236
  "%"
3087
3237
  ] }),
3088
- /* @__PURE__ */ jsx15(
3238
+ /* @__PURE__ */ jsx16(
3089
3239
  "button",
3090
3240
  {
3091
3241
  type: "button",
@@ -3095,8 +3245,8 @@ var ImageEditor = ({
3095
3245
  children: "+"
3096
3246
  }
3097
3247
  ),
3098
- /* @__PURE__ */ jsx15("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
3099
- /* @__PURE__ */ jsx15(
3248
+ /* @__PURE__ */ jsx16("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
3249
+ /* @__PURE__ */ jsx16(
3100
3250
  "button",
3101
3251
  {
3102
3252
  type: "button",
@@ -3107,7 +3257,7 @@ var ImageEditor = ({
3107
3257
  children: "Hold Compare"
3108
3258
  }
3109
3259
  ),
3110
- /* @__PURE__ */ jsx15(
3260
+ /* @__PURE__ */ jsx16(
3111
3261
  "button",
3112
3262
  {
3113
3263
  type: "button",
@@ -3118,16 +3268,16 @@ var ImageEditor = ({
3118
3268
  )
3119
3269
  ] })
3120
3270
  ] }),
3121
- transformTool.active && /* @__PURE__ */ jsx15(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
3122
- !transformTool.active && transformTool.error && /* @__PURE__ */ jsx15("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 }),
3123
- /* @__PURE__ */ jsxs14("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
3124
- /* @__PURE__ */ jsxs14(
3271
+ transformTool.active && /* @__PURE__ */ jsx16(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
3272
+ !transformTool.active && transformTool.error && /* @__PURE__ */ jsx16("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 }),
3273
+ /* @__PURE__ */ jsxs15("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
3274
+ /* @__PURE__ */ jsxs15(
3125
3275
  "div",
3126
3276
  {
3127
3277
  ref: containerRef,
3128
3278
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
3129
3279
  children: [
3130
- /* @__PURE__ */ jsx15(
3280
+ /* @__PURE__ */ jsx16(
3131
3281
  "canvas",
3132
3282
  {
3133
3283
  ref: canvasRef,
@@ -3144,7 +3294,7 @@ var ImageEditor = ({
3144
3294
  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" : ""}`
3145
3295
  }
3146
3296
  ),
3147
- typeSession && /* @__PURE__ */ jsx15(
3297
+ typeSession && /* @__PURE__ */ jsx16(
3148
3298
  "textarea",
3149
3299
  {
3150
3300
  ref: typeInputRef,
@@ -3166,11 +3316,11 @@ var ImageEditor = ({
3166
3316
  ]
3167
3317
  }
3168
3318
  ),
3169
- /* @__PURE__ */ jsxs14("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: [
3170
- activeTab === "crop" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-4 text-xs", children: [
3171
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
3172
- /* @__PURE__ */ jsxs14("div", { className: "grid grid-cols-3 gap-2", children: [
3173
- /* @__PURE__ */ jsx15(
3319
+ /* @__PURE__ */ jsxs15("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: [
3320
+ activeTab === "crop" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-4 text-xs", children: [
3321
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
3322
+ /* @__PURE__ */ jsxs15("div", { className: "grid grid-cols-3 gap-2", children: [
3323
+ /* @__PURE__ */ jsx16(
3174
3324
  "button",
3175
3325
  {
3176
3326
  type: "button",
@@ -3182,7 +3332,7 @@ var ImageEditor = ({
3182
3332
  children: "Freeform"
3183
3333
  }
3184
3334
  ),
3185
- /* @__PURE__ */ jsx15(
3335
+ /* @__PURE__ */ jsx16(
3186
3336
  "button",
3187
3337
  {
3188
3338
  type: "button",
@@ -3194,7 +3344,7 @@ var ImageEditor = ({
3194
3344
  children: "1:1 Square"
3195
3345
  }
3196
3346
  ),
3197
- /* @__PURE__ */ jsx15(
3347
+ /* @__PURE__ */ jsx16(
3198
3348
  "button",
3199
3349
  {
3200
3350
  type: "button",
@@ -3206,7 +3356,7 @@ var ImageEditor = ({
3206
3356
  children: "4:3 Standard"
3207
3357
  }
3208
3358
  ),
3209
- /* @__PURE__ */ jsx15(
3359
+ /* @__PURE__ */ jsx16(
3210
3360
  "button",
3211
3361
  {
3212
3362
  type: "button",
@@ -3218,7 +3368,7 @@ var ImageEditor = ({
3218
3368
  children: "16:9 Wide"
3219
3369
  }
3220
3370
  ),
3221
- /* @__PURE__ */ jsx15(
3371
+ /* @__PURE__ */ jsx16(
3222
3372
  "button",
3223
3373
  {
3224
3374
  type: "button",
@@ -3230,7 +3380,7 @@ var ImageEditor = ({
3230
3380
  children: "3:2 Photo"
3231
3381
  }
3232
3382
  ),
3233
- /* @__PURE__ */ jsx15(
3383
+ /* @__PURE__ */ jsx16(
3234
3384
  "button",
3235
3385
  {
3236
3386
  type: "button",
@@ -3243,10 +3393,10 @@ var ImageEditor = ({
3243
3393
  }
3244
3394
  )
3245
3395
  ] }),
3246
- /* @__PURE__ */ jsx15("div", { className: "h-px bg-slate-800 my-1" }),
3247
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
3248
- /* @__PURE__ */ jsxs14("div", { className: "grid grid-cols-2 gap-2", children: [
3249
- /* @__PURE__ */ jsx15(
3396
+ /* @__PURE__ */ jsx16("div", { className: "h-px bg-slate-800 my-1" }),
3397
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
3398
+ /* @__PURE__ */ jsxs15("div", { className: "grid grid-cols-2 gap-2", children: [
3399
+ /* @__PURE__ */ jsx16(
3250
3400
  "button",
3251
3401
  {
3252
3402
  type: "button",
@@ -3255,7 +3405,7 @@ var ImageEditor = ({
3255
3405
  children: "Rotate -90\xB0"
3256
3406
  }
3257
3407
  ),
3258
- /* @__PURE__ */ jsx15(
3408
+ /* @__PURE__ */ jsx16(
3259
3409
  "button",
3260
3410
  {
3261
3411
  type: "button",
@@ -3264,7 +3414,7 @@ var ImageEditor = ({
3264
3414
  children: "Rotate +90\xB0"
3265
3415
  }
3266
3416
  ),
3267
- /* @__PURE__ */ jsx15(
3417
+ /* @__PURE__ */ jsx16(
3268
3418
  "button",
3269
3419
  {
3270
3420
  type: "button",
@@ -3273,7 +3423,7 @@ var ImageEditor = ({
3273
3423
  children: "Flip Horizontal"
3274
3424
  }
3275
3425
  ),
3276
- /* @__PURE__ */ jsx15(
3426
+ /* @__PURE__ */ jsx16(
3277
3427
  "button",
3278
3428
  {
3279
3429
  type: "button",
@@ -3284,10 +3434,10 @@ var ImageEditor = ({
3284
3434
  )
3285
3435
  ] })
3286
3436
  ] }),
3287
- activeTab === "adjust" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3 text-xs", children: [
3288
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between", children: [
3289
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
3290
- /* @__PURE__ */ jsx15(
3437
+ activeTab === "adjust" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 text-xs", children: [
3438
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between", children: [
3439
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
3440
+ /* @__PURE__ */ jsx16(
3291
3441
  "button",
3292
3442
  {
3293
3443
  type: "button",
@@ -3297,9 +3447,9 @@ var ImageEditor = ({
3297
3447
  }
3298
3448
  )
3299
3449
  ] }),
3300
- /* @__PURE__ */ jsx15(Histogram, { histogram: editor.histogram }),
3301
- IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ jsxs14(React13.Fragment, { children: [
3302
- /* @__PURE__ */ jsx15(
3450
+ /* @__PURE__ */ jsx16(Histogram, { histogram: editor.histogram }),
3451
+ IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ jsxs15(React14.Fragment, { children: [
3452
+ /* @__PURE__ */ jsx16(
3303
3453
  ControlSlider,
3304
3454
  {
3305
3455
  spec,
@@ -3308,14 +3458,14 @@ var ImageEditor = ({
3308
3458
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
3309
3459
  }
3310
3460
  ),
3311
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ jsxs14(
3461
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ jsxs15(
3312
3462
  "div",
3313
3463
  {
3314
3464
  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",
3315
3465
  "data-testid": "image-editor-process-notice",
3316
3466
  children: [
3317
- /* @__PURE__ */ jsx15("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
3318
- /* @__PURE__ */ jsx15(
3467
+ /* @__PURE__ */ jsx16("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
3468
+ /* @__PURE__ */ jsx16(
3319
3469
  "button",
3320
3470
  {
3321
3471
  type: "button",
@@ -3328,7 +3478,7 @@ var ImageEditor = ({
3328
3478
  }
3329
3479
  )
3330
3480
  ] }, spec.id)),
3331
- /* @__PURE__ */ jsx15("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx15(
3481
+ /* @__PURE__ */ jsx16("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx16(
3332
3482
  AdjustmentLayersPanel,
3333
3483
  {
3334
3484
  controller,
@@ -3337,9 +3487,9 @@ var ImageEditor = ({
3337
3487
  }
3338
3488
  ) })
3339
3489
  ] }),
3340
- activeTab === "layers" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3 text-xs", children: [
3341
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
3342
- /* @__PURE__ */ jsx15(
3490
+ activeTab === "layers" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 text-xs", children: [
3491
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
3492
+ /* @__PURE__ */ jsx16(
3343
3493
  "button",
3344
3494
  {
3345
3495
  type: "button",
@@ -3350,14 +3500,15 @@ var ImageEditor = ({
3350
3500
  children: "Free Transform"
3351
3501
  }
3352
3502
  ),
3353
- /* @__PURE__ */ jsx15(LayersPanel, { controller }),
3354
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Colour" }),
3355
- /* @__PURE__ */ jsx15(ColorProfilePanel, { controller })
3503
+ /* @__PURE__ */ jsx16(LayersPanel, { controller }),
3504
+ effectsShown && /* @__PURE__ */ jsx16(ImageProviderEffectsPanel, { controller, className: "border-t border-slate-700/60 pt-3" }),
3505
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Colour" }),
3506
+ /* @__PURE__ */ jsx16(ColorProfilePanel, { controller })
3356
3507
  ] }),
3357
- activeTab === "paint" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3 text-xs", children: [
3358
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
3359
- /* @__PURE__ */ jsx15(BrushOptionsBar, { controller }),
3360
- /* @__PURE__ */ jsx15(
3508
+ activeTab === "paint" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 text-xs", children: [
3509
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
3510
+ /* @__PURE__ */ jsx16(BrushOptionsBar, { controller }),
3511
+ /* @__PURE__ */ jsx16(
3361
3512
  "button",
3362
3513
  {
3363
3514
  type: "button",
@@ -3368,12 +3519,12 @@ var ImageEditor = ({
3368
3519
  children: "Free Transform"
3369
3520
  }
3370
3521
  ),
3371
- paintError && /* @__PURE__ */ jsx15("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
3372
- /* @__PURE__ */ jsx15("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx15(LayersPanel, { controller }) })
3522
+ paintError && /* @__PURE__ */ jsx16("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
3523
+ /* @__PURE__ */ jsx16("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx16(LayersPanel, { controller }) })
3373
3524
  ] }),
3374
- activeTab === "annotate" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3 text-xs", children: [
3375
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
3376
- /* @__PURE__ */ jsx15("div", { className: "grid grid-cols-2 gap-1.5", children: ["shape", "type"].map((t) => /* @__PURE__ */ jsx15(
3525
+ activeTab === "annotate" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 text-xs", children: [
3526
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
3527
+ /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-2 gap-1.5", children: ["shape", "type"].map((t) => /* @__PURE__ */ jsx16(
3377
3528
  "button",
3378
3529
  {
3379
3530
  type: "button",
@@ -3384,13 +3535,13 @@ var ImageEditor = ({
3384
3535
  },
3385
3536
  t
3386
3537
  )) }),
3387
- state.activeTool === "shape" && /* @__PURE__ */ jsx15(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
3388
- state.activeTool === "type" && /* @__PURE__ */ jsx15(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
3389
- state.activeTool === "type" && typeSession && /* @__PURE__ */ jsx15("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" }),
3390
- shapeTypeError && /* @__PURE__ */ jsx15("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
3391
- /* @__PURE__ */ jsx15("div", { className: "h-px bg-slate-800 my-1" }),
3392
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
3393
- /* @__PURE__ */ jsx15("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ jsx15(
3538
+ state.activeTool === "shape" && /* @__PURE__ */ jsx16(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
3539
+ state.activeTool === "type" && /* @__PURE__ */ jsx16(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
3540
+ state.activeTool === "type" && typeSession && /* @__PURE__ */ jsx16("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" }),
3541
+ shapeTypeError && /* @__PURE__ */ jsx16("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
3542
+ /* @__PURE__ */ jsx16("div", { className: "h-px bg-slate-800 my-1" }),
3543
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
3544
+ /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ jsx16(
3394
3545
  "button",
3395
3546
  {
3396
3547
  type: "button",
@@ -3400,9 +3551,9 @@ var ImageEditor = ({
3400
3551
  },
3401
3552
  t
3402
3553
  )) }),
3403
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 mt-2", children: [
3404
- /* @__PURE__ */ jsx15("label", { className: "text-slate-400", children: "Color:" }),
3405
- /* @__PURE__ */ jsx15(
3554
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 mt-2", children: [
3555
+ /* @__PURE__ */ jsx16("label", { className: "text-slate-400", children: "Color:" }),
3556
+ /* @__PURE__ */ jsx16(
3406
3557
  "input",
3407
3558
  {
3408
3559
  type: "color",
@@ -3411,15 +3562,15 @@ var ImageEditor = ({
3411
3562
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
3412
3563
  }
3413
3564
  ),
3414
- /* @__PURE__ */ jsxs14("div", { className: "flex-1 ml-2", children: [
3415
- /* @__PURE__ */ jsxs14("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
3416
- /* @__PURE__ */ jsx15("span", { children: "Width:" }),
3417
- /* @__PURE__ */ jsxs14("span", { className: "font-mono", children: [
3565
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1 ml-2", children: [
3566
+ /* @__PURE__ */ jsxs15("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
3567
+ /* @__PURE__ */ jsx16("span", { children: "Width:" }),
3568
+ /* @__PURE__ */ jsxs15("span", { className: "font-mono", children: [
3418
3569
  strokeWidth,
3419
3570
  "px"
3420
3571
  ] })
3421
3572
  ] }),
3422
- /* @__PURE__ */ jsx15(
3573
+ /* @__PURE__ */ jsx16(
3423
3574
  "input",
3424
3575
  {
3425
3576
  type: "range",
@@ -3432,10 +3583,10 @@ var ImageEditor = ({
3432
3583
  )
3433
3584
  ] })
3434
3585
  ] }),
3435
- /* @__PURE__ */ jsx15("div", { className: "h-px bg-slate-800 my-1" }),
3436
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
3437
- /* @__PURE__ */ jsxs14("div", { className: "flex gap-2", children: [
3438
- /* @__PURE__ */ jsx15(
3586
+ /* @__PURE__ */ jsx16("div", { className: "h-px bg-slate-800 my-1" }),
3587
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
3588
+ /* @__PURE__ */ jsxs15("div", { className: "flex gap-2", children: [
3589
+ /* @__PURE__ */ jsx16(
3439
3590
  "input",
3440
3591
  {
3441
3592
  type: "text",
@@ -3446,7 +3597,7 @@ var ImageEditor = ({
3446
3597
  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"
3447
3598
  }
3448
3599
  ),
3449
- /* @__PURE__ */ jsx15(
3600
+ /* @__PURE__ */ jsx16(
3450
3601
  "button",
3451
3602
  {
3452
3603
  type: "button",
@@ -3456,14 +3607,14 @@ var ImageEditor = ({
3456
3607
  }
3457
3608
  )
3458
3609
  ] }),
3459
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between text-slate-400", children: [
3460
- /* @__PURE__ */ jsx15("span", { children: "Font Size:" }),
3461
- /* @__PURE__ */ jsxs14("span", { className: "font-mono", children: [
3610
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between text-slate-400", children: [
3611
+ /* @__PURE__ */ jsx16("span", { children: "Font Size:" }),
3612
+ /* @__PURE__ */ jsxs15("span", { className: "font-mono", children: [
3462
3613
  fontSize,
3463
3614
  "px"
3464
3615
  ] })
3465
3616
  ] }),
3466
- /* @__PURE__ */ jsx15(
3617
+ /* @__PURE__ */ jsx16(
3467
3618
  "input",
3468
3619
  {
3469
3620
  type: "range",
@@ -3474,14 +3625,14 @@ var ImageEditor = ({
3474
3625
  className: "w-full accent-indigo-500"
3475
3626
  }
3476
3627
  ),
3477
- /* @__PURE__ */ jsx15("div", { className: "h-px bg-slate-800 my-1" }),
3478
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between", children: [
3479
- /* @__PURE__ */ jsxs14("span", { className: "text-slate-400", children: [
3628
+ /* @__PURE__ */ jsx16("div", { className: "h-px bg-slate-800 my-1" }),
3629
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between", children: [
3630
+ /* @__PURE__ */ jsxs15("span", { className: "text-slate-400", children: [
3480
3631
  "Layers (",
3481
3632
  state.annotations.length,
3482
3633
  ")"
3483
3634
  ] }),
3484
- state.selectedAnnotationId && /* @__PURE__ */ jsx15(
3635
+ state.selectedAnnotationId && /* @__PURE__ */ jsx16(
3485
3636
  "button",
3486
3637
  {
3487
3638
  type: "button",
@@ -3490,7 +3641,7 @@ var ImageEditor = ({
3490
3641
  children: "Delete Selected"
3491
3642
  }
3492
3643
  ),
3493
- state.annotations.length > 0 && /* @__PURE__ */ jsx15(
3644
+ state.annotations.length > 0 && /* @__PURE__ */ jsx16(
3494
3645
  "button",
3495
3646
  {
3496
3647
  type: "button",
@@ -3501,10 +3652,10 @@ var ImageEditor = ({
3501
3652
  )
3502
3653
  ] })
3503
3654
  ] }),
3504
- activeTab === "depth" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3 text-xs", children: [
3505
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between", children: [
3506
- /* @__PURE__ */ jsx15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
3507
- /* @__PURE__ */ jsx15(
3655
+ activeTab === "depth" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 text-xs", children: [
3656
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between", children: [
3657
+ /* @__PURE__ */ jsx16("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
3658
+ /* @__PURE__ */ jsx16(
3508
3659
  "button",
3509
3660
  {
3510
3661
  type: "button",
@@ -3514,8 +3665,8 @@ var ImageEditor = ({
3514
3665
  }
3515
3666
  )
3516
3667
  ] }),
3517
- /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
3518
- /* @__PURE__ */ jsx15(
3668
+ /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
3669
+ /* @__PURE__ */ jsx16(
3519
3670
  "input",
3520
3671
  {
3521
3672
  type: "checkbox",
@@ -3524,12 +3675,12 @@ var ImageEditor = ({
3524
3675
  className: "rounded accent-indigo-500"
3525
3676
  }
3526
3677
  ),
3527
- /* @__PURE__ */ jsx15("span", { children: "Enable Depth / Alpha Mask" })
3678
+ /* @__PURE__ */ jsx16("span", { children: "Enable Depth / Alpha Mask" })
3528
3679
  ] }),
3529
- state.depthMask.enabled && /* @__PURE__ */ jsxs14(Fragment5, { children: [
3530
- /* @__PURE__ */ jsxs14("div", { children: [
3531
- /* @__PURE__ */ jsx15("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3532
- /* @__PURE__ */ jsx15(
3680
+ state.depthMask.enabled && /* @__PURE__ */ jsxs15(Fragment5, { children: [
3681
+ /* @__PURE__ */ jsxs15("div", { children: [
3682
+ /* @__PURE__ */ jsx16("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3683
+ /* @__PURE__ */ jsx16(
3533
3684
  "input",
3534
3685
  {
3535
3686
  type: "text",
@@ -3540,8 +3691,8 @@ var ImageEditor = ({
3540
3691
  }
3541
3692
  )
3542
3693
  ] }),
3543
- /* @__PURE__ */ jsxs14("div", { className: "flex gap-2", children: [
3544
- /* @__PURE__ */ jsx15(
3694
+ /* @__PURE__ */ jsxs15("div", { className: "flex gap-2", children: [
3695
+ /* @__PURE__ */ jsx16(
3545
3696
  "button",
3546
3697
  {
3547
3698
  type: "button",
@@ -3550,7 +3701,7 @@ var ImageEditor = ({
3550
3701
  children: "Threshold Mode"
3551
3702
  }
3552
3703
  ),
3553
- /* @__PURE__ */ jsx15(
3704
+ /* @__PURE__ */ jsx16(
3554
3705
  "button",
3555
3706
  {
3556
3707
  type: "button",
@@ -3560,12 +3711,12 @@ var ImageEditor = ({
3560
3711
  }
3561
3712
  )
3562
3713
  ] }),
3563
- /* @__PURE__ */ jsxs14("div", { children: [
3564
- /* @__PURE__ */ jsxs14("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3565
- /* @__PURE__ */ jsx15("span", { children: "Depth Start (Lower):" }),
3566
- /* @__PURE__ */ jsx15("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
3714
+ /* @__PURE__ */ jsxs15("div", { children: [
3715
+ /* @__PURE__ */ jsxs15("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3716
+ /* @__PURE__ */ jsx16("span", { children: "Depth Start (Lower):" }),
3717
+ /* @__PURE__ */ jsx16("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
3567
3718
  ] }),
3568
- /* @__PURE__ */ jsx15(
3719
+ /* @__PURE__ */ jsx16(
3569
3720
  "input",
3570
3721
  {
3571
3722
  type: "range",
@@ -3579,12 +3730,12 @@ var ImageEditor = ({
3579
3730
  }
3580
3731
  )
3581
3732
  ] }),
3582
- /* @__PURE__ */ jsxs14("div", { children: [
3583
- /* @__PURE__ */ jsxs14("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3584
- /* @__PURE__ */ jsx15("span", { children: "Depth Stop (Upper):" }),
3585
- /* @__PURE__ */ jsx15("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
3733
+ /* @__PURE__ */ jsxs15("div", { children: [
3734
+ /* @__PURE__ */ jsxs15("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3735
+ /* @__PURE__ */ jsx16("span", { children: "Depth Stop (Upper):" }),
3736
+ /* @__PURE__ */ jsx16("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
3586
3737
  ] }),
3587
- /* @__PURE__ */ jsx15(
3738
+ /* @__PURE__ */ jsx16(
3588
3739
  "input",
3589
3740
  {
3590
3741
  type: "range",
@@ -3598,12 +3749,12 @@ var ImageEditor = ({
3598
3749
  }
3599
3750
  )
3600
3751
  ] }),
3601
- /* @__PURE__ */ jsxs14("div", { children: [
3602
- /* @__PURE__ */ jsxs14("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3603
- /* @__PURE__ */ jsx15("span", { children: "Softness:" }),
3604
- /* @__PURE__ */ jsx15("span", { className: "font-mono", children: state.depthMask.softness })
3752
+ /* @__PURE__ */ jsxs15("div", { children: [
3753
+ /* @__PURE__ */ jsxs15("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3754
+ /* @__PURE__ */ jsx16("span", { children: "Softness:" }),
3755
+ /* @__PURE__ */ jsx16("span", { className: "font-mono", children: state.depthMask.softness })
3605
3756
  ] }),
3606
- /* @__PURE__ */ jsx15(
3757
+ /* @__PURE__ */ jsx16(
3607
3758
  "input",
3608
3759
  {
3609
3760
  type: "range",
@@ -3615,8 +3766,8 @@ var ImageEditor = ({
3615
3766
  }
3616
3767
  )
3617
3768
  ] }),
3618
- /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3619
- /* @__PURE__ */ jsx15(
3769
+ /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3770
+ /* @__PURE__ */ jsx16(
3620
3771
  "input",
3621
3772
  {
3622
3773
  type: "checkbox",
@@ -3625,12 +3776,12 @@ var ImageEditor = ({
3625
3776
  className: "rounded accent-indigo-500"
3626
3777
  }
3627
3778
  ),
3628
- /* @__PURE__ */ jsx15("span", { children: "Invert Mask" })
3779
+ /* @__PURE__ */ jsx16("span", { children: "Invert Mask" })
3629
3780
  ] })
3630
3781
  ] })
3631
3782
  ] }),
3632
- activeTab === "select" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-4 text-xs", children: [
3633
- /* @__PURE__ */ jsx15(
3783
+ activeTab === "select" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-4 text-xs", children: [
3784
+ /* @__PURE__ */ jsx16(
3634
3785
  SelectionOptionsBar,
3635
3786
  {
3636
3787
  controller,
@@ -3640,9 +3791,9 @@ var ImageEditor = ({
3640
3791
  quickMask: Boolean(state.quickMask)
3641
3792
  }
3642
3793
  ),
3643
- selectionError && /* @__PURE__ */ jsx15("p", { role: "alert", className: "text-rose-400", children: selectionError }),
3644
- /* @__PURE__ */ jsxs14("div", { className: "flex gap-1", children: [
3645
- /* @__PURE__ */ jsx15(
3794
+ selectionError && /* @__PURE__ */ jsx16("p", { role: "alert", className: "text-rose-400", children: selectionError }),
3795
+ /* @__PURE__ */ jsxs15("div", { className: "flex gap-1", children: [
3796
+ /* @__PURE__ */ jsx16(
3646
3797
  "button",
3647
3798
  {
3648
3799
  type: "button",
@@ -3653,7 +3804,7 @@ var ImageEditor = ({
3653
3804
  children: "Transform Selection"
3654
3805
  }
3655
3806
  ),
3656
- /* @__PURE__ */ jsx15(
3807
+ /* @__PURE__ */ jsx16(
3657
3808
  "button",
3658
3809
  {
3659
3810
  type: "button",
@@ -3665,12 +3816,12 @@ var ImageEditor = ({
3665
3816
  }
3666
3817
  )
3667
3818
  ] }),
3668
- /* @__PURE__ */ jsx15(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
3819
+ /* @__PURE__ */ jsx16(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
3669
3820
  ] }),
3670
- activeTab === "ai" && /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-4 text-xs", children: [
3671
- /* @__PURE__ */ jsxs14("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
3672
- /* @__PURE__ */ jsx15("span", { children: "Results go to" }),
3673
- /* @__PURE__ */ jsxs14(
3821
+ activeTab === "ai" && /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-4 text-xs", children: [
3822
+ /* @__PURE__ */ jsxs15("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
3823
+ /* @__PURE__ */ jsx16("span", { children: "Results go to" }),
3824
+ /* @__PURE__ */ jsxs15(
3674
3825
  "select",
3675
3826
  {
3676
3827
  "aria-label": "AI result target",
@@ -3678,54 +3829,54 @@ var ImageEditor = ({
3678
3829
  onChange: (e) => setAiTarget(e.target.value),
3679
3830
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
3680
3831
  children: [
3681
- /* @__PURE__ */ jsx15("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
3682
- /* @__PURE__ */ jsx15("option", { value: "new-layer", children: "New layer / mask" }),
3683
- /* @__PURE__ */ jsx15("option", { value: "replace", children: "Replace image" })
3832
+ /* @__PURE__ */ jsx16("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
3833
+ /* @__PURE__ */ jsx16("option", { value: "new-layer", children: "New layer / mask" }),
3834
+ /* @__PURE__ */ jsx16("option", { value: "replace", children: "Replace image" })
3684
3835
  ]
3685
3836
  }
3686
3837
  )
3687
3838
  ] }),
3688
- /* @__PURE__ */ jsxs14("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3689
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between", children: [
3690
- /* @__PURE__ */ jsxs14("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3691
- /* @__PURE__ */ jsx15("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx15("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" }) }),
3839
+ /* @__PURE__ */ jsxs15("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3840
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between", children: [
3841
+ /* @__PURE__ */ jsxs15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3842
+ /* @__PURE__ */ jsx16("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx16("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" }) }),
3692
3843
  "Background Removal"
3693
3844
  ] }),
3694
- isRemovingBg && /* @__PURE__ */ jsx15("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..." })
3845
+ isRemovingBg && /* @__PURE__ */ jsx16("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..." })
3695
3846
  ] }),
3696
- /* @__PURE__ */ jsx15("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3697
- /* @__PURE__ */ jsx15(
3847
+ /* @__PURE__ */ jsx16("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3848
+ /* @__PURE__ */ jsx16(
3698
3849
  "button",
3699
3850
  {
3700
3851
  type: "button",
3701
3852
  onClick: handleRemoveBackground,
3702
3853
  disabled: isRemovingBg || isInpainting,
3703
3854
  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",
3704
- children: isRemovingBg ? /* @__PURE__ */ jsxs14(Fragment5, { children: [
3705
- /* @__PURE__ */ jsx15("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3855
+ children: isRemovingBg ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
3856
+ /* @__PURE__ */ jsx16("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3706
3857
  "Removing Background..."
3707
- ] }) : /* @__PURE__ */ jsxs14(Fragment5, { children: [
3708
- /* @__PURE__ */ jsx15("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx15("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" }) }),
3858
+ ] }) : /* @__PURE__ */ jsxs15(Fragment5, { children: [
3859
+ /* @__PURE__ */ jsx16("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx16("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" }) }),
3709
3860
  "Remove Background"
3710
3861
  ] })
3711
3862
  }
3712
3863
  )
3713
3864
  ] }),
3714
- /* @__PURE__ */ jsxs14("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3715
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between", children: [
3716
- /* @__PURE__ */ jsxs14("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3717
- /* @__PURE__ */ jsxs14("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3718
- /* @__PURE__ */ jsx15("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" }),
3719
- /* @__PURE__ */ jsx15("path", { d: "m14 7 3 3" })
3865
+ /* @__PURE__ */ jsxs15("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3866
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between", children: [
3867
+ /* @__PURE__ */ jsxs15("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3868
+ /* @__PURE__ */ jsxs15("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3869
+ /* @__PURE__ */ jsx16("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" }),
3870
+ /* @__PURE__ */ jsx16("path", { d: "m14 7 3 3" })
3720
3871
  ] }),
3721
3872
  "Generative Inpainting"
3722
3873
  ] }),
3723
- isInpainting && /* @__PURE__ */ jsx15("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..." })
3874
+ isInpainting && /* @__PURE__ */ jsx16("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..." })
3724
3875
  ] }),
3725
- /* @__PURE__ */ jsx15("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3726
- /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1", children: [
3727
- /* @__PURE__ */ jsx15("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3728
- /* @__PURE__ */ jsx15(
3876
+ /* @__PURE__ */ jsx16("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3877
+ /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-1", children: [
3878
+ /* @__PURE__ */ jsx16("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3879
+ /* @__PURE__ */ jsx16(
3729
3880
  "textarea",
3730
3881
  {
3731
3882
  id: "ai-inpaint-prompt-react",
@@ -3737,10 +3888,10 @@ var ImageEditor = ({
3737
3888
  }
3738
3889
  )
3739
3890
  ] }),
3740
- /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1", children: [
3741
- /* @__PURE__ */ jsx15("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3742
- /* @__PURE__ */ jsxs14("div", { className: "grid grid-cols-2 gap-1.5", children: [
3743
- /* @__PURE__ */ jsxs14(
3891
+ /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-1", children: [
3892
+ /* @__PURE__ */ jsx16("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3893
+ /* @__PURE__ */ jsxs15("div", { className: "grid grid-cols-2 gap-1.5", children: [
3894
+ /* @__PURE__ */ jsxs15(
3744
3895
  "button",
3745
3896
  {
3746
3897
  type: "button",
@@ -3753,7 +3904,7 @@ var ImageEditor = ({
3753
3904
  ]
3754
3905
  }
3755
3906
  ),
3756
- /* @__PURE__ */ jsxs14(
3907
+ /* @__PURE__ */ jsxs15(
3757
3908
  "button",
3758
3909
  {
3759
3910
  type: "button",
@@ -3768,25 +3919,25 @@ var ImageEditor = ({
3768
3919
  )
3769
3920
  ] })
3770
3921
  ] }),
3771
- /* @__PURE__ */ jsx15(
3922
+ /* @__PURE__ */ jsx16(
3772
3923
  "button",
3773
3924
  {
3774
3925
  type: "button",
3775
3926
  onClick: handleInpaint,
3776
3927
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
3777
3928
  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",
3778
- children: isInpainting ? /* @__PURE__ */ jsxs14(Fragment5, { children: [
3779
- /* @__PURE__ */ jsx15("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3929
+ children: isInpainting ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
3930
+ /* @__PURE__ */ jsx16("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3780
3931
  "Generating Inpaint..."
3781
- ] }) : /* @__PURE__ */ jsxs14(Fragment5, { children: [
3782
- /* @__PURE__ */ jsx15("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx15("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" }) }),
3932
+ ] }) : /* @__PURE__ */ jsxs15(Fragment5, { children: [
3933
+ /* @__PURE__ */ jsx16("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx16("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" }) }),
3783
3934
  "Apply Inpainting"
3784
3935
  ] })
3785
3936
  }
3786
3937
  )
3787
3938
  ] }),
3788
- aiError && /* @__PURE__ */ jsx15("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3789
- aiSuccess && /* @__PURE__ */ jsx15("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
3939
+ aiError && /* @__PURE__ */ jsx16("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3940
+ aiSuccess && /* @__PURE__ */ jsx16("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
3790
3941
  ] })
3791
3942
  ] })
3792
3943
  ] })
@@ -3797,6 +3948,7 @@ var ImageEditor = ({
3797
3948
 
3798
3949
  export {
3799
3950
  useImageEditor,
3951
+ useImageEffectsTools,
3800
3952
  ControlSlider,
3801
3953
  Histogram,
3802
3954
  useImageHistogram,
@@ -3804,6 +3956,7 @@ export {
3804
3956
  AdjustmentLayersPanel,
3805
3957
  LayerEffectsPanel,
3806
3958
  LayersPanel,
3959
+ ImageProviderEffectsPanel,
3807
3960
  PaintGradientEditor,
3808
3961
  BrushOptionsBar,
3809
3962
  ColorProfilePanel,
@@ -3814,4 +3967,4 @@ export {
3814
3967
  TypeOptionsBar,
3815
3968
  ImageEditor
3816
3969
  };
3817
- //# sourceMappingURL=chunk-QARGR5E5.js.map
3970
+ //# sourceMappingURL=chunk-S5SSL3ZO.js.map