@pixerate/editor-react 0.69.0 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -159,7 +159,7 @@ function useImageEditor(options = {}) {
159
159
  }
160
160
 
161
161
  // src/image-editor/ImageEditor.tsx
162
- import React10, { useRef as useRef5, useEffect as useEffect8, useState as useState11, useCallback as useCallback2 } from "react";
162
+ import React12, { useRef as useRef5, useEffect as useEffect10, useState as useState13, useCallback as useCallback2 } from "react";
163
163
  import {
164
164
  canvasToImagePoint,
165
165
  hitTestCrop,
@@ -176,7 +176,11 @@ import {
176
176
  handlePaintShortcut,
177
177
  pointerPressure,
178
178
  FreeTransformTool,
179
- getViewportProjection
179
+ getViewportProjection,
180
+ ShapeDrawGesture,
181
+ TypeToolGesture,
182
+ DEFAULT_SHAPE_TOOL_OPTIONS,
183
+ DEFAULT_TYPE_TOOL_OPTIONS
180
184
  } from "@pixerate/editor/image-editor";
181
185
 
182
186
  // src/image-editor/ControlSlider.tsx
@@ -826,6 +830,8 @@ import {
826
830
  dropZone,
827
831
  openPsdFile,
828
832
  layerBadge,
833
+ layerHasThumbnail,
834
+ layerWarning,
829
835
  layerEffectsBadge,
830
836
  layerMenu,
831
837
  layerPanelRows,
@@ -918,7 +924,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
918
924
  const placement = dropPlacement(state.layers, id, row.layer.id, dropZone(fraction, row.layer.type === "group"));
919
925
  if (placement) attempt(() => controller.moveLayer(id, placement));
920
926
  };
921
- const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
927
+ const thumb = (layer) => layerHasThumbnail(layer) ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
922
928
  const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
923
929
  const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
924
930
  return /* @__PURE__ */ jsxs6("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
@@ -1111,15 +1117,25 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1111
1117
  }
1112
1118
  ),
1113
1119
  row.clipped && /* @__PURE__ */ jsx6("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
1114
- layer.type === "pixel" ? /* @__PURE__ */ jsx6(
1115
- Thumbnail,
1116
- {
1117
- pixels: thumb(layer),
1118
- size: thumbnailSize,
1119
- label: `${row.label} pixels`,
1120
- selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
1121
- }
1122
- ) : /* @__PURE__ */ jsx6(
1120
+ layerHasThumbnail(layer) ? /* @__PURE__ */ jsxs6("span", { className: "relative shrink-0", children: [
1121
+ /* @__PURE__ */ jsx6(
1122
+ Thumbnail,
1123
+ {
1124
+ pixels: thumb(layer),
1125
+ size: thumbnailSize,
1126
+ label: `${row.label} pixels`,
1127
+ selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
1128
+ }
1129
+ ),
1130
+ layer.type !== "pixel" && /* @__PURE__ */ jsx6(
1131
+ "span",
1132
+ {
1133
+ "data-testid": "layer-kind-badge",
1134
+ className: "absolute -bottom-1 -right-1 rounded bg-slate-700 px-0.5 text-[8px] font-bold leading-tight text-slate-100 ring-1 ring-slate-900",
1135
+ children: layerBadge(layer)
1136
+ }
1137
+ )
1138
+ ] }) : /* @__PURE__ */ jsx6(
1123
1139
  "span",
1124
1140
  {
1125
1141
  className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
@@ -1186,6 +1202,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1186
1202
  children: row.label
1187
1203
  }
1188
1204
  ),
1205
+ layerWarning(layer) && /* @__PURE__ */ jsx6("span", { role: "img", "data-testid": "layer-warning", "aria-label": layerWarning(layer), title: layerWarning(layer), className: "text-[10px] text-amber-400", children: "\u26A0" }),
1189
1206
  layerEffectsBadge(layer) && /* @__PURE__ */ jsx6(
1190
1207
  "button",
1191
1208
  {
@@ -1803,8 +1820,215 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1803
1820
  ] });
1804
1821
  };
1805
1822
 
1806
- // src/image-editor/ImageEditor.tsx
1823
+ // src/image-editor/ShapeOptionsBar.tsx
1824
+ import { useEffect as useEffect8, useState as useState11 } from "react";
1825
+ import { LIVE_SHAPE_KINDS, SHAPE_KIND_LABELS, applyShapeOptions } from "@pixerate/editor/image-editor";
1807
1826
  import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1827
+ 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"}`;
1828
+ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
1829
+ const [, setTick] = useState11(0);
1830
+ useEffect8(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1831
+ const [error, setError] = useState11(null);
1832
+ const active = controller.getActiveLayer();
1833
+ const shapeId = active?.type === "shape" ? active.id : null;
1834
+ const set = (change) => {
1835
+ onChange({ ...options, ...change });
1836
+ if (!shapeId) return;
1837
+ try {
1838
+ setError(null);
1839
+ applyShapeOptions(controller, shapeId, change);
1840
+ } catch (e) {
1841
+ setError(e instanceof Error ? e.message : String(e));
1842
+ }
1843
+ };
1844
+ const num = (v, min, max) => Math.max(min, Math.min(max, Number(v) || min));
1845
+ return /* @__PURE__ */ jsxs11("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "shape-options", children: [
1846
+ /* @__PURE__ */ jsx11("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Shape kind", children: LIVE_SHAPE_KINDS.map((k) => /* @__PURE__ */ jsx11("button", { type: "button", "aria-pressed": options.kind === k, className: chip3(options.kind === k), onClick: () => onChange({ ...options, kind: k }), children: SHAPE_KIND_LABELS[k] }, k)) }),
1847
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-3", children: [
1848
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1849
+ /* @__PURE__ */ jsx11("input", { type: "checkbox", "aria-label": "Fill", checked: options.fill !== null, onChange: (e) => set({ fill: e.target.checked ? "#4f46e5" : null }) }),
1850
+ "Fill",
1851
+ /* @__PURE__ */ jsx11(
1852
+ "input",
1853
+ {
1854
+ type: "color",
1855
+ "aria-label": "Fill colour",
1856
+ disabled: options.fill === null,
1857
+ value: options.fill ?? "#4f46e5",
1858
+ onChange: (e) => set({ fill: e.target.value }),
1859
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1860
+ }
1861
+ )
1862
+ ] }),
1863
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1864
+ /* @__PURE__ */ jsx11("input", { type: "checkbox", "aria-label": "Stroke", checked: options.stroke !== null, onChange: (e) => set({ stroke: e.target.checked ? "#000000" : null }) }),
1865
+ "Stroke",
1866
+ /* @__PURE__ */ jsx11(
1867
+ "input",
1868
+ {
1869
+ type: "color",
1870
+ "aria-label": "Stroke colour",
1871
+ disabled: options.stroke === null,
1872
+ value: options.stroke ?? "#000000",
1873
+ onChange: (e) => set({ stroke: e.target.value }),
1874
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1875
+ }
1876
+ )
1877
+ ] }),
1878
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1879
+ "Width",
1880
+ /* @__PURE__ */ jsx11(
1881
+ "input",
1882
+ {
1883
+ type: "number",
1884
+ "aria-label": "Stroke width",
1885
+ min: 0,
1886
+ max: 200,
1887
+ value: options.strokeWidth,
1888
+ onChange: (e) => set({ strokeWidth: num(e.target.value, 0, 200) }),
1889
+ className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
1890
+ }
1891
+ )
1892
+ ] })
1893
+ ] }),
1894
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-3", children: [
1895
+ options.kind === "rect" && /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1896
+ "Radius",
1897
+ /* @__PURE__ */ jsx11("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" })
1898
+ ] }),
1899
+ options.kind === "polygon" && /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1900
+ "Sides",
1901
+ /* @__PURE__ */ jsx11("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" })
1902
+ ] }),
1903
+ options.kind === "star" && /* @__PURE__ */ jsxs11(Fragment3, { children: [
1904
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1905
+ "Points",
1906
+ /* @__PURE__ */ jsx11("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" })
1907
+ ] }),
1908
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1909
+ "Inner",
1910
+ /* @__PURE__ */ jsx11(
1911
+ "input",
1912
+ {
1913
+ type: "range",
1914
+ "aria-label": "Inner radius",
1915
+ min: 0.05,
1916
+ max: 1,
1917
+ step: 0.05,
1918
+ value: options.innerRatio,
1919
+ onChange: (e) => set({ innerRatio: Number(e.target.value) }),
1920
+ className: "accent-indigo-500"
1921
+ }
1922
+ )
1923
+ ] })
1924
+ ] }),
1925
+ options.kind === "line" && /* @__PURE__ */ jsxs11(Fragment3, { children: [
1926
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1927
+ "Weight",
1928
+ /* @__PURE__ */ jsx11("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" })
1929
+ ] }),
1930
+ /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-1", children: [
1931
+ /* @__PURE__ */ jsx11("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
1932
+ "Arrowhead"
1933
+ ] })
1934
+ ] })
1935
+ ] }),
1936
+ /* @__PURE__ */ jsx11("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." }),
1937
+ error && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-rose-400", children: error })
1938
+ ] });
1939
+ };
1940
+
1941
+ // src/image-editor/TypeOptionsBar.tsx
1942
+ import { useEffect as useEffect9, useState as useState12 } from "react";
1943
+ import { TEXT_ALIGNS } from "@pixerate/editor/image-editor";
1944
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1945
+ 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"}`;
1946
+ var ALIGN_LABELS = { left: "Left", center: "Centre", right: "Right", justify: "Justify" };
1947
+ var TypeOptionsBar = ({ controller, options, onChange, session, className }) => {
1948
+ const [, setTick] = useState12(0);
1949
+ useEffect9(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1950
+ useEffect9(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
1951
+ const [error, setError] = useState12(null);
1952
+ const active = controller.getActiveLayer();
1953
+ const typeId = !session && active?.type === "type" ? active.id : null;
1954
+ const here = session?.alive ? session.styleHere() : {};
1955
+ const shown = {
1956
+ ...options,
1957
+ ...here.fontFamily ? { fontFamily: here.fontFamily } : {},
1958
+ ...here.fontSize ? { fontSize: here.fontSize } : {},
1959
+ ...here.fontWeight ? { fontWeight: here.fontWeight } : {},
1960
+ ...session?.alive ? { italic: Boolean(here.italic), color: here.color ?? options.color } : {}
1961
+ };
1962
+ const fonts = controller.listFonts();
1963
+ const missing = active?.type === "type" ? active.missingFonts ?? [] : [];
1964
+ const style = (change) => {
1965
+ onChange({ ...options, ...change });
1966
+ const s = {};
1967
+ for (const k of ["fontFamily", "fontSize", "fontWeight", "italic", "color"]) if (k in change) s[k] = change[k];
1968
+ const p = change.align ? { align: change.align } : null;
1969
+ try {
1970
+ setError(null);
1971
+ if (session?.alive) {
1972
+ if (Object.keys(s).length) session.setStyle(s);
1973
+ if (p) session.setParagraph(p);
1974
+ if (session.error) setError(session.error);
1975
+ } else if (typeId) {
1976
+ if (Object.keys(s).length) controller.setTextStyle(typeId, s);
1977
+ if (p) controller.setParagraphStyle(typeId, p);
1978
+ }
1979
+ } catch (e) {
1980
+ setError(e instanceof Error ? e.message : String(e));
1981
+ }
1982
+ };
1983
+ return /* @__PURE__ */ jsxs12("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "type-options", children: [
1984
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", children: [
1985
+ /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
1986
+ "Font",
1987
+ /* @__PURE__ */ jsx12(
1988
+ "input",
1989
+ {
1990
+ list: "pixerate-type-fonts",
1991
+ "aria-label": "Font family",
1992
+ value: shown.fontFamily,
1993
+ onChange: (e) => e.target.value.trim() && style({ fontFamily: e.target.value }),
1994
+ className: "w-32 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
1995
+ }
1996
+ ),
1997
+ /* @__PURE__ */ jsx12("datalist", { id: "pixerate-type-fonts", children: fonts.map((f) => /* @__PURE__ */ jsx12("option", { value: f }, f)) })
1998
+ ] }),
1999
+ /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-1", children: [
2000
+ "Size",
2001
+ /* @__PURE__ */ jsx12(
2002
+ "input",
2003
+ {
2004
+ type: "number",
2005
+ "aria-label": "Font size",
2006
+ min: 1,
2007
+ max: 2e3,
2008
+ value: Math.round(shown.fontSize * 10) / 10,
2009
+ onChange: (e) => Number(e.target.value) > 0 && style({ fontSize: Number(e.target.value) }),
2010
+ className: "w-16 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
2011
+ }
2012
+ )
2013
+ ] }),
2014
+ /* @__PURE__ */ jsx12("button", { type: "button", "aria-pressed": shown.fontWeight >= 600, className: `${chip4(shown.fontWeight >= 600)} font-bold`, onClick: () => style({ fontWeight: shown.fontWeight >= 600 ? 400 : 700 }), children: "B" }),
2015
+ /* @__PURE__ */ jsx12("button", { type: "button", "aria-pressed": shown.italic, className: `${chip4(shown.italic)} italic`, onClick: () => style({ italic: !shown.italic }), children: "I" }),
2016
+ /* @__PURE__ */ jsx12("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" })
2017
+ ] }),
2018
+ /* @__PURE__ */ jsx12("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Alignment", children: TEXT_ALIGNS.map((a) => /* @__PURE__ */ jsx12("button", { type: "button", "aria-pressed": options.align === a, className: chip4(options.align === a), onClick: () => style({ align: a }), children: ALIGN_LABELS[a] }, a)) }),
2019
+ /* @__PURE__ */ jsx12("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." }),
2020
+ missing.length > 0 && /* @__PURE__ */ jsxs12("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
2021
+ "Missing ",
2022
+ missing.length === 1 ? "font" : "fonts",
2023
+ ": ",
2024
+ missing.join(", ")
2025
+ ] }),
2026
+ error && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-rose-400", children: error })
2027
+ ] });
2028
+ };
2029
+
2030
+ // src/image-editor/ImageEditor.tsx
2031
+ import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1808
2032
  var ImageEditor = ({
1809
2033
  editor: externalEditor,
1810
2034
  src,
@@ -1822,9 +2046,9 @@ var ImageEditor = ({
1822
2046
  const legacyProcess = normalizeProcessVersion(state.adjustments.process) < LATEST_PROCESS_VERSION;
1823
2047
  const canvasRef = useRef5(null);
1824
2048
  const containerRef = useRef5(null);
1825
- const [activeTab, setActiveTab] = useState11("crop");
1826
- const [activeCropRatio, setActiveCropRatio] = useState11(null);
1827
- const [selectionOptions, setSelectionOptions] = useState11(DEFAULT_SELECTION_TOOL_OPTIONS);
2049
+ const [activeTab, setActiveTab] = useState13("crop");
2050
+ const [activeCropRatio, setActiveCropRatio] = useState13(null);
2051
+ const [selectionOptions, setSelectionOptions] = useState13(DEFAULT_SELECTION_TOOL_OPTIONS);
1828
2052
  const selectionOptionsRef = useRef5(selectionOptions);
1829
2053
  selectionOptionsRef.current = selectionOptions;
1830
2054
  const selectionGestureRef = useRef5(null);
@@ -1832,7 +2056,7 @@ var ImageEditor = ({
1832
2056
  selectionGestureRef.current = new SelectionGesture(controller, () => selectionOptionsRef.current);
1833
2057
  }
1834
2058
  const selectionDraftRef = useRef5(null);
1835
- const [selectionError, setSelectionError] = useState11(null);
2059
+ const [selectionError, setSelectionError] = useState13(null);
1836
2060
  const paintGestureRef = useRef5(null);
1837
2061
  const paintControllerRef = useRef5(controller);
1838
2062
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
@@ -1840,7 +2064,7 @@ var ImageEditor = ({
1840
2064
  paintControllerRef.current = controller;
1841
2065
  }
1842
2066
  const brushCursorRef = useRef5(null);
1843
- const [paintError, setPaintError] = useState11(null);
2067
+ const [paintError, setPaintError] = useState13(null);
1844
2068
  const transformToolRef = useRef5(null);
1845
2069
  const transformControllerRef = useRef5(controller);
1846
2070
  if (!transformToolRef.current || transformControllerRef.current !== controller) {
@@ -1851,15 +2075,33 @@ var ImageEditor = ({
1851
2075
  transformControllerRef.current = controller;
1852
2076
  }
1853
2077
  const transformTool = transformToolRef.current;
1854
- const [, setTransformTick] = useState11(0);
1855
- const [transformCursor, setTransformCursor] = useState11("default");
1856
- const [inpaintPrompt, setInpaintPrompt] = useState11("");
1857
- const [inpaintMaskMode, setInpaintMaskMode] = useState11("annotations");
1858
- const [isRemovingBg, setIsRemovingBg] = useState11(false);
1859
- const [isInpainting, setIsInpainting] = useState11(false);
1860
- const [aiError, setAiError] = useState11(null);
1861
- const [aiSuccess, setAiSuccess] = useState11(null);
1862
- const [aiTarget, setAiTarget] = useState11("auto");
2078
+ const [, setTransformTick] = useState13(0);
2079
+ const [transformCursor, setTransformCursor] = useState13("default");
2080
+ const [shapeOptions, setShapeOptions] = useState13(DEFAULT_SHAPE_TOOL_OPTIONS);
2081
+ const shapeOptionsRef = useRef5(shapeOptions);
2082
+ shapeOptionsRef.current = shapeOptions;
2083
+ const [typeOptions, setTypeOptions] = useState13(DEFAULT_TYPE_TOOL_OPTIONS);
2084
+ const typeOptionsRef = useRef5(typeOptions);
2085
+ typeOptionsRef.current = typeOptions;
2086
+ const shapeGestureRef = useRef5(null);
2087
+ const typeToolRef = useRef5(null);
2088
+ const shapeTypeControllerRef = useRef5(controller);
2089
+ if (!shapeGestureRef.current || !typeToolRef.current || shapeTypeControllerRef.current !== controller) {
2090
+ typeToolRef.current?.finish();
2091
+ shapeGestureRef.current = new ShapeDrawGesture(controller, () => shapeOptionsRef.current);
2092
+ typeToolRef.current = new TypeToolGesture(controller, () => typeOptionsRef.current);
2093
+ shapeTypeControllerRef.current = controller;
2094
+ }
2095
+ const typeInputRef = useRef5(null);
2096
+ const [typeSession, setTypeSession] = useState13(typeToolRef.current.session);
2097
+ const [shapeTypeError, setShapeTypeError] = useState13(null);
2098
+ const [inpaintPrompt, setInpaintPrompt] = useState13("");
2099
+ const [inpaintMaskMode, setInpaintMaskMode] = useState13("annotations");
2100
+ const [isRemovingBg, setIsRemovingBg] = useState13(false);
2101
+ const [isInpainting, setIsInpainting] = useState13(false);
2102
+ const [aiError, setAiError] = useState13(null);
2103
+ const [aiSuccess, setAiSuccess] = useState13(null);
2104
+ const [aiTarget, setAiTarget] = useState13("auto");
1863
2105
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
1864
2106
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
1865
2107
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -1922,10 +2164,10 @@ var ImageEditor = ({
1922
2164
  setIsInpainting(false);
1923
2165
  }
1924
2166
  };
1925
- const [activeColor, setActiveColor] = useState11("#ef4444");
1926
- const [strokeWidth, setStrokeWidth] = useState11(3);
1927
- const [fontSize, setFontSize] = useState11(24);
1928
- const [textInput, setTextInput] = useState11("");
2167
+ const [activeColor, setActiveColor] = useState13("#ef4444");
2168
+ const [strokeWidth, setStrokeWidth] = useState13(3);
2169
+ const [fontSize, setFontSize] = useState13(24);
2170
+ const [textInput, setTextInput] = useState13("");
1929
2171
  const draftAnnotationRef = useRef5(null);
1930
2172
  const draftCropRef = useRef5(null);
1931
2173
  const cropDragInfoRef = useRef5(null);
@@ -1950,12 +2192,49 @@ var ImageEditor = ({
1950
2192
  draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
1951
2193
  draftSelectionPath: selectionDraftRef.current,
1952
2194
  brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" && !transformTool.active ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null,
1953
- freeTransform: transformTool.overlay()
2195
+ freeTransform: transformTool.overlay(),
2196
+ textEdit: typeToolRef.current?.session?.alive ? typeToolRef.current.session.overlay() : null
1954
2197
  });
1955
2198
  },
1956
2199
  [controller, activeTab, transformTool]
1957
2200
  );
1958
- useEffect8(() => transformTool.subscribe(() => {
2201
+ useEffect10(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
2202
+ useEffect10(() => {
2203
+ if (activeTab === "annotate" && state.activeTool === "type") return;
2204
+ if (typeToolRef.current?.session) {
2205
+ typeToolRef.current.finish();
2206
+ setTypeSession(null);
2207
+ void renderCanvas();
2208
+ }
2209
+ }, [activeTab, state.activeTool, renderCanvas]);
2210
+ const finishTyping = () => {
2211
+ typeToolRef.current?.finish();
2212
+ setTypeSession(null);
2213
+ void renderCanvas();
2214
+ };
2215
+ const handleTypeKeyDown = (e) => {
2216
+ const session = typeToolRef.current?.session;
2217
+ if (!session || e.nativeEvent.isComposing) return;
2218
+ if (e.key === "Escape") {
2219
+ e.preventDefault();
2220
+ finishTyping();
2221
+ return;
2222
+ }
2223
+ if ((e.metaKey || e.ctrlKey) && ["z", "y", "c", "x", "v"].includes(e.key.toLowerCase())) return;
2224
+ if (session.handleKey(e)) {
2225
+ e.preventDefault();
2226
+ setShapeTypeError(session.error);
2227
+ }
2228
+ };
2229
+ const handleTypeInput = (e) => {
2230
+ const el = e.currentTarget;
2231
+ const session = typeToolRef.current?.session;
2232
+ if (session && el.value && !e.nativeEvent.isComposing) {
2233
+ session.insert(el.value);
2234
+ el.value = "";
2235
+ }
2236
+ };
2237
+ useEffect10(() => transformTool.subscribe(() => {
1959
2238
  setTransformTick((n) => n + 1);
1960
2239
  void renderCanvas();
1961
2240
  }), [transformTool, renderCanvas]);
@@ -1998,7 +2277,7 @@ var ImageEditor = ({
1998
2277
  transformTool.up();
1999
2278
  return true;
2000
2279
  };
2001
- useEffect8(() => {
2280
+ useEffect10(() => {
2002
2281
  if (typeof window === "undefined") return;
2003
2282
  const onKey = (e) => {
2004
2283
  if (transformTool.key(e)) e.preventDefault();
@@ -2006,7 +2285,7 @@ var ImageEditor = ({
2006
2285
  window.addEventListener("keydown", onKey);
2007
2286
  return () => window.removeEventListener("keydown", onKey);
2008
2287
  }, [transformTool]);
2009
- useEffect8(() => {
2288
+ useEffect10(() => {
2010
2289
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
2011
2290
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
2012
2291
  const animId = raf(() => {
@@ -2014,12 +2293,12 @@ var ImageEditor = ({
2014
2293
  });
2015
2294
  return () => caf(animId);
2016
2295
  }, [renderCanvas, state]);
2017
- useEffect8(() => {
2296
+ useEffect10(() => {
2018
2297
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
2019
2298
  editor.setTool("crop");
2020
2299
  }
2021
2300
  }, [activeTab, editor]);
2022
- useEffect8(() => {
2301
+ useEffect10(() => {
2023
2302
  const container = containerRef.current;
2024
2303
  if (!container) return;
2025
2304
  if (typeof ResizeObserver !== "undefined") {
@@ -2087,7 +2366,7 @@ var ImageEditor = ({
2087
2366
  if (g.error) setPaintError(g.error);
2088
2367
  }
2089
2368
  };
2090
- useEffect8(() => {
2369
+ useEffect10(() => {
2091
2370
  if (activeTab !== "paint" || typeof window === "undefined") return;
2092
2371
  const onKey = (e) => {
2093
2372
  if (handlePaintShortcut(controller, e)) e.preventDefault();
@@ -2131,6 +2410,17 @@ var ImageEditor = ({
2131
2410
  }
2132
2411
  return;
2133
2412
  }
2413
+ if (activeTab === "annotate" && (state.activeTool === "shape" || state.activeTool === "type")) {
2414
+ const imgPt = canvasToImagePoint(canvasPt, state, canvas.width, canvas.height, false);
2415
+ setShapeTypeError(null);
2416
+ if (state.activeTool === "shape") shapeGestureRef.current.down(imgPt);
2417
+ else {
2418
+ typeToolRef.current.down(imgPt, { shift: e.shiftKey });
2419
+ setTypeSession(typeToolRef.current.session);
2420
+ void renderCanvas();
2421
+ }
2422
+ return;
2423
+ }
2134
2424
  if (activeTab === "annotate") {
2135
2425
  const imgPt = canvasToImagePoint(canvasPt, state, canvas.width, canvas.height, false);
2136
2426
  dragStartPointRef.current = imgPt;
@@ -2221,6 +2511,14 @@ var ImageEditor = ({
2221
2511
  }
2222
2512
  return;
2223
2513
  }
2514
+ if (activeTab === "annotate" && state.activeTool === "shape") {
2515
+ const g = shapeGestureRef.current;
2516
+ if (g.active) {
2517
+ g.move(canvasToImagePoint(canvasPt, state, canvas.width, canvas.height, false), { shift: e.shiftKey, alt: e.altKey });
2518
+ if (g.error) setShapeTypeError(g.error);
2519
+ }
2520
+ return;
2521
+ }
2224
2522
  if (activeTab === "annotate") {
2225
2523
  if (annotationDragInfoRef.current) {
2226
2524
  const drag = annotationDragInfoRef.current;
@@ -2347,6 +2645,19 @@ var ImageEditor = ({
2347
2645
  }
2348
2646
  return;
2349
2647
  }
2648
+ if (activeTab === "annotate" && state.activeTool === "shape") {
2649
+ shapeGestureRef.current.up();
2650
+ return;
2651
+ }
2652
+ if (activeTab === "annotate" && state.activeTool === "type") {
2653
+ const tool = typeToolRef.current;
2654
+ tool.up(canvasToImagePoint(canvasPt, state, canvas.width, canvas.height, false));
2655
+ setTypeSession(tool.session);
2656
+ if (tool.error) setShapeTypeError(tool.error);
2657
+ void renderCanvas();
2658
+ if (tool.session) setTimeout(() => typeInputRef.current?.focus(), 0);
2659
+ return;
2660
+ }
2350
2661
  if (activeTab === "annotate") {
2351
2662
  if (annotationDragInfoRef.current) {
2352
2663
  annotationDragInfoRef.current = null;
@@ -2450,15 +2761,15 @@ var ImageEditor = ({
2450
2761
  link.click();
2451
2762
  }
2452
2763
  };
2453
- return /* @__PURE__ */ jsxs11(
2764
+ return /* @__PURE__ */ jsxs13(
2454
2765
  "div",
2455
2766
  {
2456
2767
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
2457
2768
  style,
2458
2769
  children: [
2459
- /* @__PURE__ */ jsxs11("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: [
2460
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2461
- /* @__PURE__ */ jsx11(
2770
+ /* @__PURE__ */ jsxs13("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: [
2771
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2772
+ /* @__PURE__ */ jsx13(
2462
2773
  "button",
2463
2774
  {
2464
2775
  type: "button",
@@ -2470,7 +2781,7 @@ var ImageEditor = ({
2470
2781
  children: "Transform & Crop"
2471
2782
  }
2472
2783
  ),
2473
- /* @__PURE__ */ jsx11(
2784
+ /* @__PURE__ */ jsx13(
2474
2785
  "button",
2475
2786
  {
2476
2787
  type: "button",
@@ -2482,7 +2793,7 @@ var ImageEditor = ({
2482
2793
  children: "Adjustments"
2483
2794
  }
2484
2795
  ),
2485
- /* @__PURE__ */ jsx11(
2796
+ /* @__PURE__ */ jsx13(
2486
2797
  "button",
2487
2798
  {
2488
2799
  type: "button",
@@ -2494,7 +2805,7 @@ var ImageEditor = ({
2494
2805
  children: "Layers"
2495
2806
  }
2496
2807
  ),
2497
- /* @__PURE__ */ jsx11(
2808
+ /* @__PURE__ */ jsx13(
2498
2809
  "button",
2499
2810
  {
2500
2811
  type: "button",
@@ -2506,7 +2817,7 @@ var ImageEditor = ({
2506
2817
  children: "Paint"
2507
2818
  }
2508
2819
  ),
2509
- /* @__PURE__ */ jsx11(
2820
+ /* @__PURE__ */ jsx13(
2510
2821
  "button",
2511
2822
  {
2512
2823
  type: "button",
@@ -2518,7 +2829,7 @@ var ImageEditor = ({
2518
2829
  children: "Select & Mask"
2519
2830
  }
2520
2831
  ),
2521
- /* @__PURE__ */ jsx11(
2832
+ /* @__PURE__ */ jsx13(
2522
2833
  "button",
2523
2834
  {
2524
2835
  type: "button",
@@ -2530,7 +2841,7 @@ var ImageEditor = ({
2530
2841
  children: "Annotations"
2531
2842
  }
2532
2843
  ),
2533
- /* @__PURE__ */ jsx11(
2844
+ /* @__PURE__ */ jsx13(
2534
2845
  "button",
2535
2846
  {
2536
2847
  type: "button",
@@ -2542,7 +2853,7 @@ var ImageEditor = ({
2542
2853
  children: "Depth Mask"
2543
2854
  }
2544
2855
  ),
2545
- /* @__PURE__ */ jsxs11(
2856
+ /* @__PURE__ */ jsxs13(
2546
2857
  "button",
2547
2858
  {
2548
2859
  type: "button",
@@ -2552,14 +2863,14 @@ var ImageEditor = ({
2552
2863
  },
2553
2864
  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"}`,
2554
2865
  children: [
2555
- /* @__PURE__ */ jsx11("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx11("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" }) }),
2866
+ /* @__PURE__ */ jsx13("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx13("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" }) }),
2556
2867
  "AI Tools"
2557
2868
  ]
2558
2869
  }
2559
2870
  )
2560
2871
  ] }),
2561
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 text-xs", children: [
2562
- /* @__PURE__ */ jsx11(
2872
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 text-xs", children: [
2873
+ /* @__PURE__ */ jsx13(
2563
2874
  "button",
2564
2875
  {
2565
2876
  type: "button",
@@ -2570,7 +2881,7 @@ var ImageEditor = ({
2570
2881
  children: "\u21A9"
2571
2882
  }
2572
2883
  ),
2573
- /* @__PURE__ */ jsx11(
2884
+ /* @__PURE__ */ jsx13(
2574
2885
  "button",
2575
2886
  {
2576
2887
  type: "button",
@@ -2581,7 +2892,7 @@ var ImageEditor = ({
2581
2892
  children: "\u21AA"
2582
2893
  }
2583
2894
  ),
2584
- /* @__PURE__ */ jsx11(
2895
+ /* @__PURE__ */ jsx13(
2585
2896
  "button",
2586
2897
  {
2587
2898
  type: "button",
@@ -2590,8 +2901,8 @@ var ImageEditor = ({
2590
2901
  children: "Reset"
2591
2902
  }
2592
2903
  ),
2593
- /* @__PURE__ */ jsx11("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2594
- /* @__PURE__ */ jsx11(
2904
+ /* @__PURE__ */ jsx13("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2905
+ /* @__PURE__ */ jsx13(
2595
2906
  "button",
2596
2907
  {
2597
2908
  type: "button",
@@ -2601,11 +2912,11 @@ var ImageEditor = ({
2601
2912
  children: "-"
2602
2913
  }
2603
2914
  ),
2604
- /* @__PURE__ */ jsxs11("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2915
+ /* @__PURE__ */ jsxs13("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2605
2916
  Math.round(state.zoom * 100),
2606
2917
  "%"
2607
2918
  ] }),
2608
- /* @__PURE__ */ jsx11(
2919
+ /* @__PURE__ */ jsx13(
2609
2920
  "button",
2610
2921
  {
2611
2922
  type: "button",
@@ -2615,8 +2926,8 @@ var ImageEditor = ({
2615
2926
  children: "+"
2616
2927
  }
2617
2928
  ),
2618
- /* @__PURE__ */ jsx11("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2619
- /* @__PURE__ */ jsx11(
2929
+ /* @__PURE__ */ jsx13("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2930
+ /* @__PURE__ */ jsx13(
2620
2931
  "button",
2621
2932
  {
2622
2933
  type: "button",
@@ -2627,7 +2938,7 @@ var ImageEditor = ({
2627
2938
  children: "Hold Compare"
2628
2939
  }
2629
2940
  ),
2630
- /* @__PURE__ */ jsx11(
2941
+ /* @__PURE__ */ jsx13(
2631
2942
  "button",
2632
2943
  {
2633
2944
  type: "button",
@@ -2638,38 +2949,59 @@ var ImageEditor = ({
2638
2949
  )
2639
2950
  ] })
2640
2951
  ] }),
2641
- transformTool.active && /* @__PURE__ */ jsx11(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
2642
- !transformTool.active && transformTool.error && /* @__PURE__ */ jsx11("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 }),
2643
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2644
- /* @__PURE__ */ jsx11(
2952
+ transformTool.active && /* @__PURE__ */ jsx13(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
2953
+ !transformTool.active && transformTool.error && /* @__PURE__ */ jsx13("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 }),
2954
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2955
+ /* @__PURE__ */ jsxs13(
2645
2956
  "div",
2646
2957
  {
2647
2958
  ref: containerRef,
2648
2959
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
2649
- children: /* @__PURE__ */ jsx11(
2650
- "canvas",
2651
- {
2652
- ref: canvasRef,
2653
- onMouseDown: handleMouseDown,
2654
- onMouseMove: handleMouseMove,
2655
- onMouseUp: handleMouseUp,
2656
- onMouseLeave: handleMouseUp,
2657
- onPointerDown: handlePaintPointerDown,
2658
- onPointerMove: handlePaintPointerMove,
2659
- onPointerUp: handlePaintPointerUp,
2660
- onPointerCancel: () => paintGestureRef.current?.cancel(),
2661
- "data-testid": "image-editor-canvas",
2662
- style: transformTool.active ? { cursor: transformCursor } : void 0,
2663
- className: `absolute inset-0 w-full h-full block ${transformTool.active ? "touch-none" : activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
2664
- }
2665
- )
2960
+ children: [
2961
+ /* @__PURE__ */ jsx13(
2962
+ "canvas",
2963
+ {
2964
+ ref: canvasRef,
2965
+ onMouseDown: handleMouseDown,
2966
+ onMouseMove: handleMouseMove,
2967
+ onMouseUp: handleMouseUp,
2968
+ onMouseLeave: handleMouseUp,
2969
+ onPointerDown: handlePaintPointerDown,
2970
+ onPointerMove: handlePaintPointerMove,
2971
+ onPointerUp: handlePaintPointerUp,
2972
+ onPointerCancel: () => paintGestureRef.current?.cancel(),
2973
+ "data-testid": "image-editor-canvas",
2974
+ style: transformTool.active ? { cursor: transformCursor } : void 0,
2975
+ 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" : ""}`
2976
+ }
2977
+ ),
2978
+ typeSession && /* @__PURE__ */ jsx13(
2979
+ "textarea",
2980
+ {
2981
+ ref: typeInputRef,
2982
+ "aria-label": "Edit text",
2983
+ "data-testid": "type-input",
2984
+ autoCapitalize: "off",
2985
+ autoCorrect: "off",
2986
+ spellCheck: false,
2987
+ onKeyDown: handleTypeKeyDown,
2988
+ onInput: handleTypeInput,
2989
+ onCompositionEnd: (e) => {
2990
+ const session = typeToolRef.current?.session;
2991
+ if (session && e.data) session.insert(e.data);
2992
+ e.currentTarget.value = "";
2993
+ },
2994
+ className: "absolute left-0 top-0 h-px w-px opacity-0"
2995
+ }
2996
+ )
2997
+ ]
2666
2998
  }
2667
2999
  ),
2668
- /* @__PURE__ */ jsxs11("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: [
2669
- activeTab === "crop" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-4 text-xs", children: [
2670
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2671
- /* @__PURE__ */ jsxs11("div", { className: "grid grid-cols-3 gap-2", children: [
2672
- /* @__PURE__ */ jsx11(
3000
+ /* @__PURE__ */ jsxs13("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: [
3001
+ activeTab === "crop" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-4 text-xs", children: [
3002
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
3003
+ /* @__PURE__ */ jsxs13("div", { className: "grid grid-cols-3 gap-2", children: [
3004
+ /* @__PURE__ */ jsx13(
2673
3005
  "button",
2674
3006
  {
2675
3007
  type: "button",
@@ -2681,7 +3013,7 @@ var ImageEditor = ({
2681
3013
  children: "Freeform"
2682
3014
  }
2683
3015
  ),
2684
- /* @__PURE__ */ jsx11(
3016
+ /* @__PURE__ */ jsx13(
2685
3017
  "button",
2686
3018
  {
2687
3019
  type: "button",
@@ -2693,7 +3025,7 @@ var ImageEditor = ({
2693
3025
  children: "1:1 Square"
2694
3026
  }
2695
3027
  ),
2696
- /* @__PURE__ */ jsx11(
3028
+ /* @__PURE__ */ jsx13(
2697
3029
  "button",
2698
3030
  {
2699
3031
  type: "button",
@@ -2705,7 +3037,7 @@ var ImageEditor = ({
2705
3037
  children: "4:3 Standard"
2706
3038
  }
2707
3039
  ),
2708
- /* @__PURE__ */ jsx11(
3040
+ /* @__PURE__ */ jsx13(
2709
3041
  "button",
2710
3042
  {
2711
3043
  type: "button",
@@ -2717,7 +3049,7 @@ var ImageEditor = ({
2717
3049
  children: "16:9 Wide"
2718
3050
  }
2719
3051
  ),
2720
- /* @__PURE__ */ jsx11(
3052
+ /* @__PURE__ */ jsx13(
2721
3053
  "button",
2722
3054
  {
2723
3055
  type: "button",
@@ -2729,7 +3061,7 @@ var ImageEditor = ({
2729
3061
  children: "3:2 Photo"
2730
3062
  }
2731
3063
  ),
2732
- /* @__PURE__ */ jsx11(
3064
+ /* @__PURE__ */ jsx13(
2733
3065
  "button",
2734
3066
  {
2735
3067
  type: "button",
@@ -2742,10 +3074,10 @@ var ImageEditor = ({
2742
3074
  }
2743
3075
  )
2744
3076
  ] }),
2745
- /* @__PURE__ */ jsx11("div", { className: "h-px bg-slate-800 my-1" }),
2746
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2747
- /* @__PURE__ */ jsxs11("div", { className: "grid grid-cols-2 gap-2", children: [
2748
- /* @__PURE__ */ jsx11(
3077
+ /* @__PURE__ */ jsx13("div", { className: "h-px bg-slate-800 my-1" }),
3078
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
3079
+ /* @__PURE__ */ jsxs13("div", { className: "grid grid-cols-2 gap-2", children: [
3080
+ /* @__PURE__ */ jsx13(
2749
3081
  "button",
2750
3082
  {
2751
3083
  type: "button",
@@ -2754,7 +3086,7 @@ var ImageEditor = ({
2754
3086
  children: "Rotate -90\xB0"
2755
3087
  }
2756
3088
  ),
2757
- /* @__PURE__ */ jsx11(
3089
+ /* @__PURE__ */ jsx13(
2758
3090
  "button",
2759
3091
  {
2760
3092
  type: "button",
@@ -2763,7 +3095,7 @@ var ImageEditor = ({
2763
3095
  children: "Rotate +90\xB0"
2764
3096
  }
2765
3097
  ),
2766
- /* @__PURE__ */ jsx11(
3098
+ /* @__PURE__ */ jsx13(
2767
3099
  "button",
2768
3100
  {
2769
3101
  type: "button",
@@ -2772,7 +3104,7 @@ var ImageEditor = ({
2772
3104
  children: "Flip Horizontal"
2773
3105
  }
2774
3106
  ),
2775
- /* @__PURE__ */ jsx11(
3107
+ /* @__PURE__ */ jsx13(
2776
3108
  "button",
2777
3109
  {
2778
3110
  type: "button",
@@ -2783,10 +3115,10 @@ var ImageEditor = ({
2783
3115
  )
2784
3116
  ] })
2785
3117
  ] }),
2786
- activeTab === "adjust" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3 text-xs", children: [
2787
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
2788
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2789
- /* @__PURE__ */ jsx11(
3118
+ activeTab === "adjust" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3 text-xs", children: [
3119
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
3120
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
3121
+ /* @__PURE__ */ jsx13(
2790
3122
  "button",
2791
3123
  {
2792
3124
  type: "button",
@@ -2796,9 +3128,9 @@ var ImageEditor = ({
2796
3128
  }
2797
3129
  )
2798
3130
  ] }),
2799
- /* @__PURE__ */ jsx11(Histogram, { histogram: editor.histogram }),
2800
- IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ jsxs11(React10.Fragment, { children: [
2801
- /* @__PURE__ */ jsx11(
3131
+ /* @__PURE__ */ jsx13(Histogram, { histogram: editor.histogram }),
3132
+ IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ jsxs13(React12.Fragment, { children: [
3133
+ /* @__PURE__ */ jsx13(
2802
3134
  ControlSlider,
2803
3135
  {
2804
3136
  spec,
@@ -2807,14 +3139,14 @@ var ImageEditor = ({
2807
3139
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
2808
3140
  }
2809
3141
  ),
2810
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ jsxs11(
3142
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ jsxs13(
2811
3143
  "div",
2812
3144
  {
2813
3145
  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",
2814
3146
  "data-testid": "image-editor-process-notice",
2815
3147
  children: [
2816
- /* @__PURE__ */ jsx11("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
2817
- /* @__PURE__ */ jsx11(
3148
+ /* @__PURE__ */ jsx13("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
3149
+ /* @__PURE__ */ jsx13(
2818
3150
  "button",
2819
3151
  {
2820
3152
  type: "button",
@@ -2827,7 +3159,7 @@ var ImageEditor = ({
2827
3159
  }
2828
3160
  )
2829
3161
  ] }, spec.id)),
2830
- /* @__PURE__ */ jsx11("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx11(
3162
+ /* @__PURE__ */ jsx13("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx13(
2831
3163
  AdjustmentLayersPanel,
2832
3164
  {
2833
3165
  controller,
@@ -2836,9 +3168,9 @@ var ImageEditor = ({
2836
3168
  }
2837
3169
  ) })
2838
3170
  ] }),
2839
- activeTab === "layers" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3 text-xs", children: [
2840
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
2841
- /* @__PURE__ */ jsx11(
3171
+ activeTab === "layers" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3 text-xs", children: [
3172
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
3173
+ /* @__PURE__ */ jsx13(
2842
3174
  "button",
2843
3175
  {
2844
3176
  type: "button",
@@ -2849,12 +3181,12 @@ var ImageEditor = ({
2849
3181
  children: "Free Transform"
2850
3182
  }
2851
3183
  ),
2852
- /* @__PURE__ */ jsx11(LayersPanel, { controller })
3184
+ /* @__PURE__ */ jsx13(LayersPanel, { controller })
2853
3185
  ] }),
2854
- activeTab === "paint" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3 text-xs", children: [
2855
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
2856
- /* @__PURE__ */ jsx11(BrushOptionsBar, { controller }),
2857
- /* @__PURE__ */ jsx11(
3186
+ activeTab === "paint" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3 text-xs", children: [
3187
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
3188
+ /* @__PURE__ */ jsx13(BrushOptionsBar, { controller }),
3189
+ /* @__PURE__ */ jsx13(
2858
3190
  "button",
2859
3191
  {
2860
3192
  type: "button",
@@ -2865,12 +3197,29 @@ var ImageEditor = ({
2865
3197
  children: "Free Transform"
2866
3198
  }
2867
3199
  ),
2868
- paintError && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
2869
- /* @__PURE__ */ jsx11("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx11(LayersPanel, { controller }) })
3200
+ paintError && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
3201
+ /* @__PURE__ */ jsx13("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ jsx13(LayersPanel, { controller }) })
2870
3202
  ] }),
2871
- activeTab === "annotate" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3 text-xs", children: [
2872
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2873
- /* @__PURE__ */ jsx11("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ jsx11(
3203
+ activeTab === "annotate" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3 text-xs", children: [
3204
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
3205
+ /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-2 gap-1.5", children: ["shape", "type"].map((t) => /* @__PURE__ */ jsx13(
3206
+ "button",
3207
+ {
3208
+ type: "button",
3209
+ "aria-pressed": state.activeTool === t,
3210
+ onClick: () => editor.setTool(t),
3211
+ className: `py-1.5 px-2 rounded-lg font-medium border transition-colors ${state.activeTool === t ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-800 border-slate-700 text-slate-300 hover:bg-slate-700"}`,
3212
+ children: t === "shape" ? "Shape" : "Type"
3213
+ },
3214
+ t
3215
+ )) }),
3216
+ state.activeTool === "shape" && /* @__PURE__ */ jsx13(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
3217
+ state.activeTool === "type" && /* @__PURE__ */ jsx13(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
3218
+ state.activeTool === "type" && typeSession && /* @__PURE__ */ jsx13("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" }),
3219
+ shapeTypeError && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
3220
+ /* @__PURE__ */ jsx13("div", { className: "h-px bg-slate-800 my-1" }),
3221
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
3222
+ /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ jsx13(
2874
3223
  "button",
2875
3224
  {
2876
3225
  type: "button",
@@ -2880,9 +3229,9 @@ var ImageEditor = ({
2880
3229
  },
2881
3230
  t
2882
3231
  )) }),
2883
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 mt-2", children: [
2884
- /* @__PURE__ */ jsx11("label", { className: "text-slate-400", children: "Color:" }),
2885
- /* @__PURE__ */ jsx11(
3232
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 mt-2", children: [
3233
+ /* @__PURE__ */ jsx13("label", { className: "text-slate-400", children: "Color:" }),
3234
+ /* @__PURE__ */ jsx13(
2886
3235
  "input",
2887
3236
  {
2888
3237
  type: "color",
@@ -2891,15 +3240,15 @@ var ImageEditor = ({
2891
3240
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
2892
3241
  }
2893
3242
  ),
2894
- /* @__PURE__ */ jsxs11("div", { className: "flex-1 ml-2", children: [
2895
- /* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2896
- /* @__PURE__ */ jsx11("span", { children: "Width:" }),
2897
- /* @__PURE__ */ jsxs11("span", { className: "font-mono", children: [
3243
+ /* @__PURE__ */ jsxs13("div", { className: "flex-1 ml-2", children: [
3244
+ /* @__PURE__ */ jsxs13("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
3245
+ /* @__PURE__ */ jsx13("span", { children: "Width:" }),
3246
+ /* @__PURE__ */ jsxs13("span", { className: "font-mono", children: [
2898
3247
  strokeWidth,
2899
3248
  "px"
2900
3249
  ] })
2901
3250
  ] }),
2902
- /* @__PURE__ */ jsx11(
3251
+ /* @__PURE__ */ jsx13(
2903
3252
  "input",
2904
3253
  {
2905
3254
  type: "range",
@@ -2912,10 +3261,10 @@ var ImageEditor = ({
2912
3261
  )
2913
3262
  ] })
2914
3263
  ] }),
2915
- /* @__PURE__ */ jsx11("div", { className: "h-px bg-slate-800 my-1" }),
2916
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2917
- /* @__PURE__ */ jsxs11("div", { className: "flex gap-2", children: [
2918
- /* @__PURE__ */ jsx11(
3264
+ /* @__PURE__ */ jsx13("div", { className: "h-px bg-slate-800 my-1" }),
3265
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
3266
+ /* @__PURE__ */ jsxs13("div", { className: "flex gap-2", children: [
3267
+ /* @__PURE__ */ jsx13(
2919
3268
  "input",
2920
3269
  {
2921
3270
  type: "text",
@@ -2926,7 +3275,7 @@ var ImageEditor = ({
2926
3275
  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"
2927
3276
  }
2928
3277
  ),
2929
- /* @__PURE__ */ jsx11(
3278
+ /* @__PURE__ */ jsx13(
2930
3279
  "button",
2931
3280
  {
2932
3281
  type: "button",
@@ -2936,14 +3285,14 @@ var ImageEditor = ({
2936
3285
  }
2937
3286
  )
2938
3287
  ] }),
2939
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between text-slate-400", children: [
2940
- /* @__PURE__ */ jsx11("span", { children: "Font Size:" }),
2941
- /* @__PURE__ */ jsxs11("span", { className: "font-mono", children: [
3288
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between text-slate-400", children: [
3289
+ /* @__PURE__ */ jsx13("span", { children: "Font Size:" }),
3290
+ /* @__PURE__ */ jsxs13("span", { className: "font-mono", children: [
2942
3291
  fontSize,
2943
3292
  "px"
2944
3293
  ] })
2945
3294
  ] }),
2946
- /* @__PURE__ */ jsx11(
3295
+ /* @__PURE__ */ jsx13(
2947
3296
  "input",
2948
3297
  {
2949
3298
  type: "range",
@@ -2954,14 +3303,14 @@ var ImageEditor = ({
2954
3303
  className: "w-full accent-indigo-500"
2955
3304
  }
2956
3305
  ),
2957
- /* @__PURE__ */ jsx11("div", { className: "h-px bg-slate-800 my-1" }),
2958
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
2959
- /* @__PURE__ */ jsxs11("span", { className: "text-slate-400", children: [
3306
+ /* @__PURE__ */ jsx13("div", { className: "h-px bg-slate-800 my-1" }),
3307
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
3308
+ /* @__PURE__ */ jsxs13("span", { className: "text-slate-400", children: [
2960
3309
  "Layers (",
2961
3310
  state.annotations.length,
2962
3311
  ")"
2963
3312
  ] }),
2964
- state.selectedAnnotationId && /* @__PURE__ */ jsx11(
3313
+ state.selectedAnnotationId && /* @__PURE__ */ jsx13(
2965
3314
  "button",
2966
3315
  {
2967
3316
  type: "button",
@@ -2970,7 +3319,7 @@ var ImageEditor = ({
2970
3319
  children: "Delete Selected"
2971
3320
  }
2972
3321
  ),
2973
- state.annotations.length > 0 && /* @__PURE__ */ jsx11(
3322
+ state.annotations.length > 0 && /* @__PURE__ */ jsx13(
2974
3323
  "button",
2975
3324
  {
2976
3325
  type: "button",
@@ -2981,10 +3330,10 @@ var ImageEditor = ({
2981
3330
  )
2982
3331
  ] })
2983
3332
  ] }),
2984
- activeTab === "depth" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3 text-xs", children: [
2985
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
2986
- /* @__PURE__ */ jsx11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2987
- /* @__PURE__ */ jsx11(
3333
+ activeTab === "depth" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3 text-xs", children: [
3334
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
3335
+ /* @__PURE__ */ jsx13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
3336
+ /* @__PURE__ */ jsx13(
2988
3337
  "button",
2989
3338
  {
2990
3339
  type: "button",
@@ -2994,8 +3343,8 @@ var ImageEditor = ({
2994
3343
  }
2995
3344
  )
2996
3345
  ] }),
2997
- /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2998
- /* @__PURE__ */ jsx11(
3346
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
3347
+ /* @__PURE__ */ jsx13(
2999
3348
  "input",
3000
3349
  {
3001
3350
  type: "checkbox",
@@ -3004,12 +3353,12 @@ var ImageEditor = ({
3004
3353
  className: "rounded accent-indigo-500"
3005
3354
  }
3006
3355
  ),
3007
- /* @__PURE__ */ jsx11("span", { children: "Enable Depth / Alpha Mask" })
3356
+ /* @__PURE__ */ jsx13("span", { children: "Enable Depth / Alpha Mask" })
3008
3357
  ] }),
3009
- state.depthMask.enabled && /* @__PURE__ */ jsxs11(Fragment3, { children: [
3010
- /* @__PURE__ */ jsxs11("div", { children: [
3011
- /* @__PURE__ */ jsx11("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3012
- /* @__PURE__ */ jsx11(
3358
+ state.depthMask.enabled && /* @__PURE__ */ jsxs13(Fragment4, { children: [
3359
+ /* @__PURE__ */ jsxs13("div", { children: [
3360
+ /* @__PURE__ */ jsx13("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3361
+ /* @__PURE__ */ jsx13(
3013
3362
  "input",
3014
3363
  {
3015
3364
  type: "text",
@@ -3020,8 +3369,8 @@ var ImageEditor = ({
3020
3369
  }
3021
3370
  )
3022
3371
  ] }),
3023
- /* @__PURE__ */ jsxs11("div", { className: "flex gap-2", children: [
3024
- /* @__PURE__ */ jsx11(
3372
+ /* @__PURE__ */ jsxs13("div", { className: "flex gap-2", children: [
3373
+ /* @__PURE__ */ jsx13(
3025
3374
  "button",
3026
3375
  {
3027
3376
  type: "button",
@@ -3030,7 +3379,7 @@ var ImageEditor = ({
3030
3379
  children: "Threshold Mode"
3031
3380
  }
3032
3381
  ),
3033
- /* @__PURE__ */ jsx11(
3382
+ /* @__PURE__ */ jsx13(
3034
3383
  "button",
3035
3384
  {
3036
3385
  type: "button",
@@ -3040,12 +3389,12 @@ var ImageEditor = ({
3040
3389
  }
3041
3390
  )
3042
3391
  ] }),
3043
- /* @__PURE__ */ jsxs11("div", { children: [
3044
- /* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3045
- /* @__PURE__ */ jsx11("span", { children: "Depth Start (Lower):" }),
3046
- /* @__PURE__ */ jsx11("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
3392
+ /* @__PURE__ */ jsxs13("div", { children: [
3393
+ /* @__PURE__ */ jsxs13("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3394
+ /* @__PURE__ */ jsx13("span", { children: "Depth Start (Lower):" }),
3395
+ /* @__PURE__ */ jsx13("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
3047
3396
  ] }),
3048
- /* @__PURE__ */ jsx11(
3397
+ /* @__PURE__ */ jsx13(
3049
3398
  "input",
3050
3399
  {
3051
3400
  type: "range",
@@ -3059,12 +3408,12 @@ var ImageEditor = ({
3059
3408
  }
3060
3409
  )
3061
3410
  ] }),
3062
- /* @__PURE__ */ jsxs11("div", { children: [
3063
- /* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3064
- /* @__PURE__ */ jsx11("span", { children: "Depth Stop (Upper):" }),
3065
- /* @__PURE__ */ jsx11("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
3411
+ /* @__PURE__ */ jsxs13("div", { children: [
3412
+ /* @__PURE__ */ jsxs13("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3413
+ /* @__PURE__ */ jsx13("span", { children: "Depth Stop (Upper):" }),
3414
+ /* @__PURE__ */ jsx13("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
3066
3415
  ] }),
3067
- /* @__PURE__ */ jsx11(
3416
+ /* @__PURE__ */ jsx13(
3068
3417
  "input",
3069
3418
  {
3070
3419
  type: "range",
@@ -3078,12 +3427,12 @@ var ImageEditor = ({
3078
3427
  }
3079
3428
  )
3080
3429
  ] }),
3081
- /* @__PURE__ */ jsxs11("div", { children: [
3082
- /* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3083
- /* @__PURE__ */ jsx11("span", { children: "Softness:" }),
3084
- /* @__PURE__ */ jsx11("span", { className: "font-mono", children: state.depthMask.softness })
3430
+ /* @__PURE__ */ jsxs13("div", { children: [
3431
+ /* @__PURE__ */ jsxs13("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3432
+ /* @__PURE__ */ jsx13("span", { children: "Softness:" }),
3433
+ /* @__PURE__ */ jsx13("span", { className: "font-mono", children: state.depthMask.softness })
3085
3434
  ] }),
3086
- /* @__PURE__ */ jsx11(
3435
+ /* @__PURE__ */ jsx13(
3087
3436
  "input",
3088
3437
  {
3089
3438
  type: "range",
@@ -3095,8 +3444,8 @@ var ImageEditor = ({
3095
3444
  }
3096
3445
  )
3097
3446
  ] }),
3098
- /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3099
- /* @__PURE__ */ jsx11(
3447
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3448
+ /* @__PURE__ */ jsx13(
3100
3449
  "input",
3101
3450
  {
3102
3451
  type: "checkbox",
@@ -3105,12 +3454,12 @@ var ImageEditor = ({
3105
3454
  className: "rounded accent-indigo-500"
3106
3455
  }
3107
3456
  ),
3108
- /* @__PURE__ */ jsx11("span", { children: "Invert Mask" })
3457
+ /* @__PURE__ */ jsx13("span", { children: "Invert Mask" })
3109
3458
  ] })
3110
3459
  ] })
3111
3460
  ] }),
3112
- activeTab === "select" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-4 text-xs", children: [
3113
- /* @__PURE__ */ jsx11(
3461
+ activeTab === "select" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-4 text-xs", children: [
3462
+ /* @__PURE__ */ jsx13(
3114
3463
  SelectionOptionsBar,
3115
3464
  {
3116
3465
  controller,
@@ -3120,9 +3469,9 @@ var ImageEditor = ({
3120
3469
  quickMask: Boolean(state.quickMask)
3121
3470
  }
3122
3471
  ),
3123
- selectionError && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-rose-400", children: selectionError }),
3124
- /* @__PURE__ */ jsxs11("div", { className: "flex gap-1", children: [
3125
- /* @__PURE__ */ jsx11(
3472
+ selectionError && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-rose-400", children: selectionError }),
3473
+ /* @__PURE__ */ jsxs13("div", { className: "flex gap-1", children: [
3474
+ /* @__PURE__ */ jsx13(
3126
3475
  "button",
3127
3476
  {
3128
3477
  type: "button",
@@ -3133,7 +3482,7 @@ var ImageEditor = ({
3133
3482
  children: "Transform Selection"
3134
3483
  }
3135
3484
  ),
3136
- /* @__PURE__ */ jsx11(
3485
+ /* @__PURE__ */ jsx13(
3137
3486
  "button",
3138
3487
  {
3139
3488
  type: "button",
@@ -3145,12 +3494,12 @@ var ImageEditor = ({
3145
3494
  }
3146
3495
  )
3147
3496
  ] }),
3148
- /* @__PURE__ */ jsx11(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
3497
+ /* @__PURE__ */ jsx13(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
3149
3498
  ] }),
3150
- activeTab === "ai" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-4 text-xs", children: [
3151
- /* @__PURE__ */ jsxs11("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
3152
- /* @__PURE__ */ jsx11("span", { children: "Results go to" }),
3153
- /* @__PURE__ */ jsxs11(
3499
+ activeTab === "ai" && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-4 text-xs", children: [
3500
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
3501
+ /* @__PURE__ */ jsx13("span", { children: "Results go to" }),
3502
+ /* @__PURE__ */ jsxs13(
3154
3503
  "select",
3155
3504
  {
3156
3505
  "aria-label": "AI result target",
@@ -3158,54 +3507,54 @@ var ImageEditor = ({
3158
3507
  onChange: (e) => setAiTarget(e.target.value),
3159
3508
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
3160
3509
  children: [
3161
- /* @__PURE__ */ jsx11("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
3162
- /* @__PURE__ */ jsx11("option", { value: "new-layer", children: "New layer / mask" }),
3163
- /* @__PURE__ */ jsx11("option", { value: "replace", children: "Replace image" })
3510
+ /* @__PURE__ */ jsx13("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
3511
+ /* @__PURE__ */ jsx13("option", { value: "new-layer", children: "New layer / mask" }),
3512
+ /* @__PURE__ */ jsx13("option", { value: "replace", children: "Replace image" })
3164
3513
  ]
3165
3514
  }
3166
3515
  )
3167
3516
  ] }),
3168
- /* @__PURE__ */ jsxs11("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3169
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
3170
- /* @__PURE__ */ jsxs11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3171
- /* @__PURE__ */ jsx11("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx11("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" }) }),
3517
+ /* @__PURE__ */ jsxs13("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3518
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
3519
+ /* @__PURE__ */ jsxs13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3520
+ /* @__PURE__ */ jsx13("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx13("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" }) }),
3172
3521
  "Background Removal"
3173
3522
  ] }),
3174
- isRemovingBg && /* @__PURE__ */ jsx11("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..." })
3523
+ isRemovingBg && /* @__PURE__ */ jsx13("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..." })
3175
3524
  ] }),
3176
- /* @__PURE__ */ jsx11("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3177
- /* @__PURE__ */ jsx11(
3525
+ /* @__PURE__ */ jsx13("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3526
+ /* @__PURE__ */ jsx13(
3178
3527
  "button",
3179
3528
  {
3180
3529
  type: "button",
3181
3530
  onClick: handleRemoveBackground,
3182
3531
  disabled: isRemovingBg || isInpainting,
3183
3532
  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",
3184
- children: isRemovingBg ? /* @__PURE__ */ jsxs11(Fragment3, { children: [
3185
- /* @__PURE__ */ jsx11("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3533
+ children: isRemovingBg ? /* @__PURE__ */ jsxs13(Fragment4, { children: [
3534
+ /* @__PURE__ */ jsx13("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3186
3535
  "Removing Background..."
3187
- ] }) : /* @__PURE__ */ jsxs11(Fragment3, { children: [
3188
- /* @__PURE__ */ jsx11("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx11("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" }) }),
3536
+ ] }) : /* @__PURE__ */ jsxs13(Fragment4, { children: [
3537
+ /* @__PURE__ */ jsx13("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx13("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" }) }),
3189
3538
  "Remove Background"
3190
3539
  ] })
3191
3540
  }
3192
3541
  )
3193
3542
  ] }),
3194
- /* @__PURE__ */ jsxs11("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3195
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
3196
- /* @__PURE__ */ jsxs11("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3197
- /* @__PURE__ */ jsxs11("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3198
- /* @__PURE__ */ jsx11("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" }),
3199
- /* @__PURE__ */ jsx11("path", { d: "m14 7 3 3" })
3543
+ /* @__PURE__ */ jsxs13("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3544
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
3545
+ /* @__PURE__ */ jsxs13("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3546
+ /* @__PURE__ */ jsxs13("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3547
+ /* @__PURE__ */ jsx13("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" }),
3548
+ /* @__PURE__ */ jsx13("path", { d: "m14 7 3 3" })
3200
3549
  ] }),
3201
3550
  "Generative Inpainting"
3202
3551
  ] }),
3203
- isInpainting && /* @__PURE__ */ jsx11("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..." })
3552
+ isInpainting && /* @__PURE__ */ jsx13("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..." })
3204
3553
  ] }),
3205
- /* @__PURE__ */ jsx11("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3206
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-1", children: [
3207
- /* @__PURE__ */ jsx11("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3208
- /* @__PURE__ */ jsx11(
3554
+ /* @__PURE__ */ jsx13("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3555
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1", children: [
3556
+ /* @__PURE__ */ jsx13("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3557
+ /* @__PURE__ */ jsx13(
3209
3558
  "textarea",
3210
3559
  {
3211
3560
  id: "ai-inpaint-prompt-react",
@@ -3217,10 +3566,10 @@ var ImageEditor = ({
3217
3566
  }
3218
3567
  )
3219
3568
  ] }),
3220
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-1", children: [
3221
- /* @__PURE__ */ jsx11("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3222
- /* @__PURE__ */ jsxs11("div", { className: "grid grid-cols-2 gap-1.5", children: [
3223
- /* @__PURE__ */ jsxs11(
3569
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1", children: [
3570
+ /* @__PURE__ */ jsx13("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3571
+ /* @__PURE__ */ jsxs13("div", { className: "grid grid-cols-2 gap-1.5", children: [
3572
+ /* @__PURE__ */ jsxs13(
3224
3573
  "button",
3225
3574
  {
3226
3575
  type: "button",
@@ -3233,7 +3582,7 @@ var ImageEditor = ({
3233
3582
  ]
3234
3583
  }
3235
3584
  ),
3236
- /* @__PURE__ */ jsxs11(
3585
+ /* @__PURE__ */ jsxs13(
3237
3586
  "button",
3238
3587
  {
3239
3588
  type: "button",
@@ -3248,25 +3597,25 @@ var ImageEditor = ({
3248
3597
  )
3249
3598
  ] })
3250
3599
  ] }),
3251
- /* @__PURE__ */ jsx11(
3600
+ /* @__PURE__ */ jsx13(
3252
3601
  "button",
3253
3602
  {
3254
3603
  type: "button",
3255
3604
  onClick: handleInpaint,
3256
3605
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
3257
3606
  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",
3258
- children: isInpainting ? /* @__PURE__ */ jsxs11(Fragment3, { children: [
3259
- /* @__PURE__ */ jsx11("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3607
+ children: isInpainting ? /* @__PURE__ */ jsxs13(Fragment4, { children: [
3608
+ /* @__PURE__ */ jsx13("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3260
3609
  "Generating Inpaint..."
3261
- ] }) : /* @__PURE__ */ jsxs11(Fragment3, { children: [
3262
- /* @__PURE__ */ jsx11("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx11("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" }) }),
3610
+ ] }) : /* @__PURE__ */ jsxs13(Fragment4, { children: [
3611
+ /* @__PURE__ */ jsx13("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx13("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" }) }),
3263
3612
  "Apply Inpainting"
3264
3613
  ] })
3265
3614
  }
3266
3615
  )
3267
3616
  ] }),
3268
- aiError && /* @__PURE__ */ jsx11("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3269
- aiSuccess && /* @__PURE__ */ jsx11("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
3617
+ aiError && /* @__PURE__ */ jsx13("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3618
+ aiSuccess && /* @__PURE__ */ jsx13("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
3270
3619
  ] })
3271
3620
  ] })
3272
3621
  ] })
@@ -3288,6 +3637,8 @@ export {
3288
3637
  SelectionOptionsBar,
3289
3638
  RefineEdgePanel,
3290
3639
  FreeTransformOptionsBar,
3640
+ ShapeOptionsBar,
3641
+ TypeOptionsBar,
3291
3642
  ImageEditor
3292
3643
  };
3293
- //# sourceMappingURL=chunk-LCTQWNTL.js.map
3644
+ //# sourceMappingURL=chunk-63FQB5BT.js.map