@pixerate/editor-react 0.70.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.
@@ -41,6 +41,8 @@ __export(image_editor_exports, {
41
41
  LayersPanel: () => LayersPanel,
42
42
  RefineEdgePanel: () => RefineEdgePanel,
43
43
  SelectionOptionsBar: () => SelectionOptionsBar,
44
+ ShapeOptionsBar: () => ShapeOptionsBar,
45
+ TypeOptionsBar: () => TypeOptionsBar,
44
46
  useImageEditor: () => useImageEditor,
45
47
  useImageHistogram: () => useImageHistogram
46
48
  });
@@ -205,8 +207,8 @@ function useImageEditor(options = {}) {
205
207
  }
206
208
 
207
209
  // src/image-editor/ImageEditor.tsx
208
- var import_react11 = __toESM(require("react"), 1);
209
- var import_image_editor12 = require("@pixerate/editor/image-editor");
210
+ var import_react13 = __toESM(require("react"), 1);
211
+ var import_image_editor14 = require("@pixerate/editor/image-editor");
210
212
 
211
213
  // src/image-editor/ControlSlider.tsx
212
214
  var import_image_editor2 = require("@pixerate/editor/image-editor");
@@ -916,7 +918,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
916
918
  const placement = (0, import_image_editor7.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor7.dropZone)(fraction, row.layer.type === "group"));
917
919
  if (placement) attempt(() => controller.moveLayer(id, placement));
918
920
  };
919
- const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
921
+ const thumb = (layer) => (0, import_image_editor7.layerHasThumbnail)(layer) ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
920
922
  const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
921
923
  const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
922
924
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
@@ -1109,15 +1111,25 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1109
1111
  }
1110
1112
  ),
1111
1113
  row.clipped && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
1112
- layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1113
- Thumbnail,
1114
- {
1115
- pixels: thumb(layer),
1116
- size: thumbnailSize,
1117
- label: `${row.label} pixels`,
1118
- selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
1119
- }
1120
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1114
+ (0, import_image_editor7.layerHasThumbnail)(layer) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "relative shrink-0", children: [
1115
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1116
+ Thumbnail,
1117
+ {
1118
+ pixels: thumb(layer),
1119
+ size: thumbnailSize,
1120
+ label: `${row.label} pixels`,
1121
+ selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
1122
+ }
1123
+ ),
1124
+ layer.type !== "pixel" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1125
+ "span",
1126
+ {
1127
+ "data-testid": "layer-kind-badge",
1128
+ 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",
1129
+ children: (0, import_image_editor7.layerBadge)(layer)
1130
+ }
1131
+ )
1132
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1121
1133
  "span",
1122
1134
  {
1123
1135
  className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
@@ -1184,6 +1196,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
1184
1196
  children: row.label
1185
1197
  }
1186
1198
  ),
1199
+ (0, import_image_editor7.layerWarning)(layer) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { role: "img", "data-testid": "layer-warning", "aria-label": (0, import_image_editor7.layerWarning)(layer), title: (0, import_image_editor7.layerWarning)(layer), className: "text-[10px] text-amber-400", children: "\u26A0" }),
1187
1200
  (0, import_image_editor7.layerEffectsBadge)(layer) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1188
1201
  "button",
1189
1202
  {
@@ -1791,8 +1804,215 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
1791
1804
  ] });
1792
1805
  };
1793
1806
 
1794
- // src/image-editor/ImageEditor.tsx
1807
+ // src/image-editor/ShapeOptionsBar.tsx
1808
+ var import_react11 = require("react");
1809
+ var import_image_editor12 = require("@pixerate/editor/image-editor");
1795
1810
  var import_jsx_runtime11 = require("react/jsx-runtime");
1811
+ 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"}`;
1812
+ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
1813
+ const [, setTick] = (0, import_react11.useState)(0);
1814
+ (0, import_react11.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1815
+ const [error, setError] = (0, import_react11.useState)(null);
1816
+ const active = controller.getActiveLayer();
1817
+ const shapeId = active?.type === "shape" ? active.id : null;
1818
+ const set = (change) => {
1819
+ onChange({ ...options, ...change });
1820
+ if (!shapeId) return;
1821
+ try {
1822
+ setError(null);
1823
+ (0, import_image_editor12.applyShapeOptions)(controller, shapeId, change);
1824
+ } catch (e) {
1825
+ setError(e instanceof Error ? e.message : String(e));
1826
+ }
1827
+ };
1828
+ const num = (v, min, max) => Math.max(min, Math.min(max, Number(v) || min));
1829
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "shape-options", children: [
1830
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Shape kind", children: import_image_editor12.LIVE_SHAPE_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": options.kind === k, className: chip3(options.kind === k), onClick: () => onChange({ ...options, kind: k }), children: import_image_editor12.SHAPE_KIND_LABELS[k] }, k)) }),
1831
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
1832
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1833
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "checkbox", "aria-label": "Fill", checked: options.fill !== null, onChange: (e) => set({ fill: e.target.checked ? "#4f46e5" : null }) }),
1834
+ "Fill",
1835
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1836
+ "input",
1837
+ {
1838
+ type: "color",
1839
+ "aria-label": "Fill colour",
1840
+ disabled: options.fill === null,
1841
+ value: options.fill ?? "#4f46e5",
1842
+ onChange: (e) => set({ fill: e.target.value }),
1843
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1844
+ }
1845
+ )
1846
+ ] }),
1847
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1848
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "checkbox", "aria-label": "Stroke", checked: options.stroke !== null, onChange: (e) => set({ stroke: e.target.checked ? "#000000" : null }) }),
1849
+ "Stroke",
1850
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1851
+ "input",
1852
+ {
1853
+ type: "color",
1854
+ "aria-label": "Stroke colour",
1855
+ disabled: options.stroke === null,
1856
+ value: options.stroke ?? "#000000",
1857
+ onChange: (e) => set({ stroke: e.target.value }),
1858
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
1859
+ }
1860
+ )
1861
+ ] }),
1862
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1863
+ "Width",
1864
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1865
+ "input",
1866
+ {
1867
+ type: "number",
1868
+ "aria-label": "Stroke width",
1869
+ min: 0,
1870
+ max: 200,
1871
+ value: options.strokeWidth,
1872
+ onChange: (e) => set({ strokeWidth: num(e.target.value, 0, 200) }),
1873
+ className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
1874
+ }
1875
+ )
1876
+ ] })
1877
+ ] }),
1878
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
1879
+ options.kind === "rect" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1880
+ "Radius",
1881
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "number", "aria-label": "Corner radius", min: 0, max: 1e3, value: options.radius, onChange: (e) => set({ radius: num(e.target.value, 0, 1e3) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
1882
+ ] }),
1883
+ options.kind === "polygon" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1884
+ "Sides",
1885
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "number", "aria-label": "Sides", min: 3, max: 100, value: options.sides, onChange: (e) => set({ sides: num(e.target.value, 3, 100) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
1886
+ ] }),
1887
+ options.kind === "star" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1888
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1889
+ "Points",
1890
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "number", "aria-label": "Points", min: 3, max: 100, value: options.points, onChange: (e) => set({ points: num(e.target.value, 3, 100) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
1891
+ ] }),
1892
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1893
+ "Inner",
1894
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1895
+ "input",
1896
+ {
1897
+ type: "range",
1898
+ "aria-label": "Inner radius",
1899
+ min: 0.05,
1900
+ max: 1,
1901
+ step: 0.05,
1902
+ value: options.innerRatio,
1903
+ onChange: (e) => set({ innerRatio: Number(e.target.value) }),
1904
+ className: "accent-indigo-500"
1905
+ }
1906
+ )
1907
+ ] })
1908
+ ] }),
1909
+ options.kind === "line" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1910
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1911
+ "Weight",
1912
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "number", "aria-label": "Line weight", min: 1, max: 200, value: options.weight, onChange: (e) => set({ weight: num(e.target.value, 1, 200) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
1913
+ ] }),
1914
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-1", children: [
1915
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
1916
+ "Arrowhead"
1917
+ ] })
1918
+ ] })
1919
+ ] }),
1920
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-[10px] text-slate-500", children: "Drag on the image to draw. Shift: square, circle or 45\xB0 line. Alt: from the centre." }),
1921
+ error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
1922
+ ] });
1923
+ };
1924
+
1925
+ // src/image-editor/TypeOptionsBar.tsx
1926
+ var import_react12 = require("react");
1927
+ var import_image_editor13 = require("@pixerate/editor/image-editor");
1928
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1929
+ 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"}`;
1930
+ var ALIGN_LABELS = { left: "Left", center: "Centre", right: "Right", justify: "Justify" };
1931
+ var TypeOptionsBar = ({ controller, options, onChange, session, className }) => {
1932
+ const [, setTick] = (0, import_react12.useState)(0);
1933
+ (0, import_react12.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
1934
+ (0, import_react12.useEffect)(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
1935
+ const [error, setError] = (0, import_react12.useState)(null);
1936
+ const active = controller.getActiveLayer();
1937
+ const typeId = !session && active?.type === "type" ? active.id : null;
1938
+ const here = session?.alive ? session.styleHere() : {};
1939
+ const shown = {
1940
+ ...options,
1941
+ ...here.fontFamily ? { fontFamily: here.fontFamily } : {},
1942
+ ...here.fontSize ? { fontSize: here.fontSize } : {},
1943
+ ...here.fontWeight ? { fontWeight: here.fontWeight } : {},
1944
+ ...session?.alive ? { italic: Boolean(here.italic), color: here.color ?? options.color } : {}
1945
+ };
1946
+ const fonts = controller.listFonts();
1947
+ const missing = active?.type === "type" ? active.missingFonts ?? [] : [];
1948
+ const style = (change) => {
1949
+ onChange({ ...options, ...change });
1950
+ const s = {};
1951
+ for (const k of ["fontFamily", "fontSize", "fontWeight", "italic", "color"]) if (k in change) s[k] = change[k];
1952
+ const p = change.align ? { align: change.align } : null;
1953
+ try {
1954
+ setError(null);
1955
+ if (session?.alive) {
1956
+ if (Object.keys(s).length) session.setStyle(s);
1957
+ if (p) session.setParagraph(p);
1958
+ if (session.error) setError(session.error);
1959
+ } else if (typeId) {
1960
+ if (Object.keys(s).length) controller.setTextStyle(typeId, s);
1961
+ if (p) controller.setParagraphStyle(typeId, p);
1962
+ }
1963
+ } catch (e) {
1964
+ setError(e instanceof Error ? e.message : String(e));
1965
+ }
1966
+ };
1967
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "type-options", children: [
1968
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
1969
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
1970
+ "Font",
1971
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1972
+ "input",
1973
+ {
1974
+ list: "pixerate-type-fonts",
1975
+ "aria-label": "Font family",
1976
+ value: shown.fontFamily,
1977
+ onChange: (e) => e.target.value.trim() && style({ fontFamily: e.target.value }),
1978
+ className: "w-32 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
1979
+ }
1980
+ ),
1981
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("datalist", { id: "pixerate-type-fonts", children: fonts.map((f) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: f }, f)) })
1982
+ ] }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1", children: [
1984
+ "Size",
1985
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1986
+ "input",
1987
+ {
1988
+ type: "number",
1989
+ "aria-label": "Font size",
1990
+ min: 1,
1991
+ max: 2e3,
1992
+ value: Math.round(shown.fontSize * 10) / 10,
1993
+ onChange: (e) => Number(e.target.value) > 0 && style({ fontSize: Number(e.target.value) }),
1994
+ className: "w-16 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
1995
+ }
1996
+ )
1997
+ ] }),
1998
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("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" }),
1999
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", "aria-pressed": shown.italic, className: `${chip4(shown.italic)} italic`, onClick: () => style({ italic: !shown.italic }), children: "I" }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "color", "aria-label": "Text colour", value: shown.color, onChange: (e) => style({ color: e.target.value }), className: "h-6 w-8 rounded border border-slate-700 bg-transparent" })
2001
+ ] }),
2002
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Alignment", children: import_image_editor13.TEXT_ALIGNS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", "aria-pressed": options.align === a, className: chip4(options.align === a), onClick: () => style({ align: a }), children: ALIGN_LABELS[a] }, a)) }),
2003
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-[10px] text-slate-500", children: "Click to type point text, drag for a paragraph box, click text to edit it. Esc finishes." }),
2004
+ missing.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
2005
+ "Missing ",
2006
+ missing.length === 1 ? "font" : "fonts",
2007
+ ": ",
2008
+ missing.join(", ")
2009
+ ] }),
2010
+ error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
2011
+ ] });
2012
+ };
2013
+
2014
+ // src/image-editor/ImageEditor.tsx
2015
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1796
2016
  var ImageEditor = ({
1797
2017
  editor: externalEditor,
1798
2018
  src,
@@ -1807,47 +2027,65 @@ var ImageEditor = ({
1807
2027
  const internalEditor = useImageEditor({ image: src });
1808
2028
  const editor = externalEditor || internalEditor;
1809
2029
  const { state, controller } = editor;
1810
- const legacyProcess = (0, import_image_editor12.normalizeProcessVersion)(state.adjustments.process) < import_image_editor12.LATEST_PROCESS_VERSION;
1811
- const canvasRef = (0, import_react11.useRef)(null);
1812
- const containerRef = (0, import_react11.useRef)(null);
1813
- const [activeTab, setActiveTab] = (0, import_react11.useState)("crop");
1814
- const [activeCropRatio, setActiveCropRatio] = (0, import_react11.useState)(null);
1815
- const [selectionOptions, setSelectionOptions] = (0, import_react11.useState)(import_image_editor12.DEFAULT_SELECTION_TOOL_OPTIONS);
1816
- const selectionOptionsRef = (0, import_react11.useRef)(selectionOptions);
2030
+ const legacyProcess = (0, import_image_editor14.normalizeProcessVersion)(state.adjustments.process) < import_image_editor14.LATEST_PROCESS_VERSION;
2031
+ const canvasRef = (0, import_react13.useRef)(null);
2032
+ const containerRef = (0, import_react13.useRef)(null);
2033
+ const [activeTab, setActiveTab] = (0, import_react13.useState)("crop");
2034
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react13.useState)(null);
2035
+ const [selectionOptions, setSelectionOptions] = (0, import_react13.useState)(import_image_editor14.DEFAULT_SELECTION_TOOL_OPTIONS);
2036
+ const selectionOptionsRef = (0, import_react13.useRef)(selectionOptions);
1817
2037
  selectionOptionsRef.current = selectionOptions;
1818
- const selectionGestureRef = (0, import_react11.useRef)(null);
2038
+ const selectionGestureRef = (0, import_react13.useRef)(null);
1819
2039
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
1820
- selectionGestureRef.current = new import_image_editor12.SelectionGesture(controller, () => selectionOptionsRef.current);
2040
+ selectionGestureRef.current = new import_image_editor14.SelectionGesture(controller, () => selectionOptionsRef.current);
1821
2041
  }
1822
- const selectionDraftRef = (0, import_react11.useRef)(null);
1823
- const [selectionError, setSelectionError] = (0, import_react11.useState)(null);
1824
- const paintGestureRef = (0, import_react11.useRef)(null);
1825
- const paintControllerRef = (0, import_react11.useRef)(controller);
2042
+ const selectionDraftRef = (0, import_react13.useRef)(null);
2043
+ const [selectionError, setSelectionError] = (0, import_react13.useState)(null);
2044
+ const paintGestureRef = (0, import_react13.useRef)(null);
2045
+ const paintControllerRef = (0, import_react13.useRef)(controller);
1826
2046
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
1827
- paintGestureRef.current = new import_image_editor12.PaintGesture(controller);
2047
+ paintGestureRef.current = new import_image_editor14.PaintGesture(controller);
1828
2048
  paintControllerRef.current = controller;
1829
2049
  }
1830
- const brushCursorRef = (0, import_react11.useRef)(null);
1831
- const [paintError, setPaintError] = (0, import_react11.useState)(null);
1832
- const transformToolRef = (0, import_react11.useRef)(null);
1833
- const transformControllerRef = (0, import_react11.useRef)(controller);
2050
+ const brushCursorRef = (0, import_react13.useRef)(null);
2051
+ const [paintError, setPaintError] = (0, import_react13.useState)(null);
2052
+ const transformToolRef = (0, import_react13.useRef)(null);
2053
+ const transformControllerRef = (0, import_react13.useRef)(controller);
1834
2054
  if (!transformToolRef.current || transformControllerRef.current !== controller) {
1835
2055
  transformToolRef.current?.cancel();
1836
- transformToolRef.current = new import_image_editor12.FreeTransformTool(controller, {
2056
+ transformToolRef.current = new import_image_editor14.FreeTransformTool(controller, {
1837
2057
  schedule: (run) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(run) : run()
1838
2058
  });
1839
2059
  transformControllerRef.current = controller;
1840
2060
  }
1841
2061
  const transformTool = transformToolRef.current;
1842
- const [, setTransformTick] = (0, import_react11.useState)(0);
1843
- const [transformCursor, setTransformCursor] = (0, import_react11.useState)("default");
1844
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react11.useState)("");
1845
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react11.useState)("annotations");
1846
- const [isRemovingBg, setIsRemovingBg] = (0, import_react11.useState)(false);
1847
- const [isInpainting, setIsInpainting] = (0, import_react11.useState)(false);
1848
- const [aiError, setAiError] = (0, import_react11.useState)(null);
1849
- const [aiSuccess, setAiSuccess] = (0, import_react11.useState)(null);
1850
- const [aiTarget, setAiTarget] = (0, import_react11.useState)("auto");
2062
+ const [, setTransformTick] = (0, import_react13.useState)(0);
2063
+ const [transformCursor, setTransformCursor] = (0, import_react13.useState)("default");
2064
+ const [shapeOptions, setShapeOptions] = (0, import_react13.useState)(import_image_editor14.DEFAULT_SHAPE_TOOL_OPTIONS);
2065
+ const shapeOptionsRef = (0, import_react13.useRef)(shapeOptions);
2066
+ shapeOptionsRef.current = shapeOptions;
2067
+ const [typeOptions, setTypeOptions] = (0, import_react13.useState)(import_image_editor14.DEFAULT_TYPE_TOOL_OPTIONS);
2068
+ const typeOptionsRef = (0, import_react13.useRef)(typeOptions);
2069
+ typeOptionsRef.current = typeOptions;
2070
+ const shapeGestureRef = (0, import_react13.useRef)(null);
2071
+ const typeToolRef = (0, import_react13.useRef)(null);
2072
+ const shapeTypeControllerRef = (0, import_react13.useRef)(controller);
2073
+ if (!shapeGestureRef.current || !typeToolRef.current || shapeTypeControllerRef.current !== controller) {
2074
+ typeToolRef.current?.finish();
2075
+ shapeGestureRef.current = new import_image_editor14.ShapeDrawGesture(controller, () => shapeOptionsRef.current);
2076
+ typeToolRef.current = new import_image_editor14.TypeToolGesture(controller, () => typeOptionsRef.current);
2077
+ shapeTypeControllerRef.current = controller;
2078
+ }
2079
+ const typeInputRef = (0, import_react13.useRef)(null);
2080
+ const [typeSession, setTypeSession] = (0, import_react13.useState)(typeToolRef.current.session);
2081
+ const [shapeTypeError, setShapeTypeError] = (0, import_react13.useState)(null);
2082
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react13.useState)("");
2083
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react13.useState)("annotations");
2084
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react13.useState)(false);
2085
+ const [isInpainting, setIsInpainting] = (0, import_react13.useState)(false);
2086
+ const [aiError, setAiError] = (0, import_react13.useState)(null);
2087
+ const [aiSuccess, setAiSuccess] = (0, import_react13.useState)(null);
2088
+ const [aiTarget, setAiTarget] = (0, import_react13.useState)("auto");
1851
2089
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
1852
2090
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
1853
2091
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -1910,18 +2148,18 @@ var ImageEditor = ({
1910
2148
  setIsInpainting(false);
1911
2149
  }
1912
2150
  };
1913
- const [activeColor, setActiveColor] = (0, import_react11.useState)("#ef4444");
1914
- const [strokeWidth, setStrokeWidth] = (0, import_react11.useState)(3);
1915
- const [fontSize, setFontSize] = (0, import_react11.useState)(24);
1916
- const [textInput, setTextInput] = (0, import_react11.useState)("");
1917
- const draftAnnotationRef = (0, import_react11.useRef)(null);
1918
- const draftCropRef = (0, import_react11.useRef)(null);
1919
- const cropDragInfoRef = (0, import_react11.useRef)(null);
1920
- const annotationDragInfoRef = (0, import_react11.useRef)(null);
1921
- const isDrawingRef = (0, import_react11.useRef)(false);
1922
- const currentPathRef = (0, import_react11.useRef)([]);
1923
- const dragStartPointRef = (0, import_react11.useRef)(null);
1924
- const renderCanvas = (0, import_react11.useCallback)(
2151
+ const [activeColor, setActiveColor] = (0, import_react13.useState)("#ef4444");
2152
+ const [strokeWidth, setStrokeWidth] = (0, import_react13.useState)(3);
2153
+ const [fontSize, setFontSize] = (0, import_react13.useState)(24);
2154
+ const [textInput, setTextInput] = (0, import_react13.useState)("");
2155
+ const draftAnnotationRef = (0, import_react13.useRef)(null);
2156
+ const draftCropRef = (0, import_react13.useRef)(null);
2157
+ const cropDragInfoRef = (0, import_react13.useRef)(null);
2158
+ const annotationDragInfoRef = (0, import_react13.useRef)(null);
2159
+ const isDrawingRef = (0, import_react13.useRef)(false);
2160
+ const currentPathRef = (0, import_react13.useRef)([]);
2161
+ const dragStartPointRef = (0, import_react13.useRef)(null);
2162
+ const renderCanvas = (0, import_react13.useCallback)(
1925
2163
  async (draftAnnotation, draftCrop) => {
1926
2164
  const canvas = canvasRef.current;
1927
2165
  const container = containerRef.current;
@@ -1938,12 +2176,49 @@ var ImageEditor = ({
1938
2176
  draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
1939
2177
  draftSelectionPath: selectionDraftRef.current,
1940
2178
  brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" && !transformTool.active ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null,
1941
- freeTransform: transformTool.overlay()
2179
+ freeTransform: transformTool.overlay(),
2180
+ textEdit: typeToolRef.current?.session?.alive ? typeToolRef.current.session.overlay() : null
1942
2181
  });
1943
2182
  },
1944
2183
  [controller, activeTab, transformTool]
1945
2184
  );
1946
- (0, import_react11.useEffect)(() => transformTool.subscribe(() => {
2185
+ (0, import_react13.useEffect)(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
2186
+ (0, import_react13.useEffect)(() => {
2187
+ if (activeTab === "annotate" && state.activeTool === "type") return;
2188
+ if (typeToolRef.current?.session) {
2189
+ typeToolRef.current.finish();
2190
+ setTypeSession(null);
2191
+ void renderCanvas();
2192
+ }
2193
+ }, [activeTab, state.activeTool, renderCanvas]);
2194
+ const finishTyping = () => {
2195
+ typeToolRef.current?.finish();
2196
+ setTypeSession(null);
2197
+ void renderCanvas();
2198
+ };
2199
+ const handleTypeKeyDown = (e) => {
2200
+ const session = typeToolRef.current?.session;
2201
+ if (!session || e.nativeEvent.isComposing) return;
2202
+ if (e.key === "Escape") {
2203
+ e.preventDefault();
2204
+ finishTyping();
2205
+ return;
2206
+ }
2207
+ if ((e.metaKey || e.ctrlKey) && ["z", "y", "c", "x", "v"].includes(e.key.toLowerCase())) return;
2208
+ if (session.handleKey(e)) {
2209
+ e.preventDefault();
2210
+ setShapeTypeError(session.error);
2211
+ }
2212
+ };
2213
+ const handleTypeInput = (e) => {
2214
+ const el = e.currentTarget;
2215
+ const session = typeToolRef.current?.session;
2216
+ if (session && el.value && !e.nativeEvent.isComposing) {
2217
+ session.insert(el.value);
2218
+ el.value = "";
2219
+ }
2220
+ };
2221
+ (0, import_react13.useEffect)(() => transformTool.subscribe(() => {
1947
2222
  setTransformTick((n) => n + 1);
1948
2223
  void renderCanvas();
1949
2224
  }), [transformTool, renderCanvas]);
@@ -1954,8 +2229,8 @@ var ImageEditor = ({
1954
2229
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
1955
2230
  const s = controller.getState();
1956
2231
  const cropping = activeTab === "crop";
1957
- const projection = (0, import_image_editor12.getViewportProjection)(s, canvas.width, canvas.height, cropping);
1958
- const pt = (0, import_image_editor12.canvasToImagePoint)({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvas.width, canvas.height, cropping);
2232
+ const projection = (0, import_image_editor14.getViewportProjection)(s, canvas.width, canvas.height, cropping);
2233
+ const pt = (0, import_image_editor14.canvasToImagePoint)({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvas.width, canvas.height, cropping);
1959
2234
  transformTool.setView(projection.scale);
1960
2235
  return { pt, tolerance: 6 / (projection.scale || 1) };
1961
2236
  };
@@ -1986,7 +2261,7 @@ var ImageEditor = ({
1986
2261
  transformTool.up();
1987
2262
  return true;
1988
2263
  };
1989
- (0, import_react11.useEffect)(() => {
2264
+ (0, import_react13.useEffect)(() => {
1990
2265
  if (typeof window === "undefined") return;
1991
2266
  const onKey = (e) => {
1992
2267
  if (transformTool.key(e)) e.preventDefault();
@@ -1994,7 +2269,7 @@ var ImageEditor = ({
1994
2269
  window.addEventListener("keydown", onKey);
1995
2270
  return () => window.removeEventListener("keydown", onKey);
1996
2271
  }, [transformTool]);
1997
- (0, import_react11.useEffect)(() => {
2272
+ (0, import_react13.useEffect)(() => {
1998
2273
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
1999
2274
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
2000
2275
  const animId = raf(() => {
@@ -2002,12 +2277,12 @@ var ImageEditor = ({
2002
2277
  });
2003
2278
  return () => caf(animId);
2004
2279
  }, [renderCanvas, state]);
2005
- (0, import_react11.useEffect)(() => {
2280
+ (0, import_react13.useEffect)(() => {
2006
2281
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
2007
2282
  editor.setTool("crop");
2008
2283
  }
2009
2284
  }, [activeTab, editor]);
2010
- (0, import_react11.useEffect)(() => {
2285
+ (0, import_react13.useEffect)(() => {
2011
2286
  const container = containerRef.current;
2012
2287
  if (!container) return;
2013
2288
  if (typeof ResizeObserver !== "undefined") {
@@ -2043,8 +2318,8 @@ var ImageEditor = ({
2043
2318
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
2044
2319
  const s = controller.getState();
2045
2320
  return list.map((ev) => ({
2046
- ...(0, import_image_editor12.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
2047
- pressure: (0, import_image_editor12.pointerPressure)(ev)
2321
+ ...(0, import_image_editor14.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
2322
+ pressure: (0, import_image_editor14.pointerPressure)(ev)
2048
2323
  }));
2049
2324
  };
2050
2325
  const handlePaintPointerDown = (e) => {
@@ -2075,10 +2350,10 @@ var ImageEditor = ({
2075
2350
  if (g.error) setPaintError(g.error);
2076
2351
  }
2077
2352
  };
2078
- (0, import_react11.useEffect)(() => {
2353
+ (0, import_react13.useEffect)(() => {
2079
2354
  if (activeTab !== "paint" || typeof window === "undefined") return;
2080
2355
  const onKey = (e) => {
2081
- if ((0, import_image_editor12.handlePaintShortcut)(controller, e)) e.preventDefault();
2356
+ if ((0, import_image_editor14.handlePaintShortcut)(controller, e)) e.preventDefault();
2082
2357
  };
2083
2358
  window.addEventListener("keydown", onKey);
2084
2359
  return () => window.removeEventListener("keydown", onKey);
@@ -2089,7 +2364,7 @@ var ImageEditor = ({
2089
2364
  const canvasPt = getCanvasEventPoint(e);
2090
2365
  if (activeTab === "select") {
2091
2366
  const gesture = selectionGestureRef.current;
2092
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2367
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2093
2368
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
2094
2369
  return;
2095
2370
  }
@@ -2100,8 +2375,8 @@ var ImageEditor = ({
2100
2375
  width: state.imageDimensions.width,
2101
2376
  height: state.imageDimensions.height
2102
2377
  };
2103
- const handle = (0, import_image_editor12.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
2104
- const startImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
2378
+ const handle = (0, import_image_editor14.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
2379
+ const startImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
2105
2380
  if (handle) {
2106
2381
  cropDragInfoRef.current = {
2107
2382
  handle,
@@ -2119,13 +2394,24 @@ var ImageEditor = ({
2119
2394
  }
2120
2395
  return;
2121
2396
  }
2397
+ if (activeTab === "annotate" && (state.activeTool === "shape" || state.activeTool === "type")) {
2398
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2399
+ setShapeTypeError(null);
2400
+ if (state.activeTool === "shape") shapeGestureRef.current.down(imgPt);
2401
+ else {
2402
+ typeToolRef.current.down(imgPt, { shift: e.shiftKey });
2403
+ setTypeSession(typeToolRef.current.session);
2404
+ void renderCanvas();
2405
+ }
2406
+ return;
2407
+ }
2122
2408
  if (activeTab === "annotate") {
2123
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2409
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2124
2410
  dragStartPointRef.current = imgPt;
2125
2411
  if (state.activeTool === "select") {
2126
2412
  for (let i = state.annotations.length - 1; i >= 0; i--) {
2127
2413
  const ann = state.annotations[i];
2128
- if ((0, import_image_editor12.hitTestAnnotation)(imgPt, ann)) {
2414
+ if ((0, import_image_editor14.hitTestAnnotation)(imgPt, ann)) {
2129
2415
  editor.selectAnnotation(ann.id);
2130
2416
  annotationDragInfoRef.current = {
2131
2417
  annId: ann.id,
@@ -2161,7 +2447,7 @@ var ImageEditor = ({
2161
2447
  const canvasPt = getCanvasEventPoint(e);
2162
2448
  if (activeTab === "select") {
2163
2449
  const gesture = selectionGestureRef.current;
2164
- if (gesture.active && gesture.move((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
2450
+ if (gesture.active && gesture.move((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
2165
2451
  selectionDraftRef.current = gesture.draftPath;
2166
2452
  renderCanvas();
2167
2453
  }
@@ -2170,7 +2456,7 @@ var ImageEditor = ({
2170
2456
  if (activeTab === "crop") {
2171
2457
  const drag = cropDragInfoRef.current;
2172
2458
  if (drag) {
2173
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
2459
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
2174
2460
  let newCrop;
2175
2461
  if (drag.handle === "new") {
2176
2462
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -2184,7 +2470,7 @@ var ImageEditor = ({
2184
2470
  height: Math.round(Math.max(20, maxY - minY))
2185
2471
  };
2186
2472
  } else {
2187
- newCrop = (0, import_image_editor12.calculateCropDrag)(
2473
+ newCrop = (0, import_image_editor14.calculateCropDrag)(
2188
2474
  drag.startCrop,
2189
2475
  drag.handle,
2190
2476
  drag.startImgPt,
@@ -2204,15 +2490,23 @@ var ImageEditor = ({
2204
2490
  width: state.imageDimensions.width,
2205
2491
  height: state.imageDimensions.height
2206
2492
  };
2207
- const handle = (0, import_image_editor12.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
2208
- canvas.style.cursor = (0, import_image_editor12.getCropCursor)(handle, state.transform);
2493
+ const handle = (0, import_image_editor14.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
2494
+ canvas.style.cursor = (0, import_image_editor14.getCropCursor)(handle, state.transform);
2495
+ }
2496
+ return;
2497
+ }
2498
+ if (activeTab === "annotate" && state.activeTool === "shape") {
2499
+ const g = shapeGestureRef.current;
2500
+ if (g.active) {
2501
+ g.move((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), { shift: e.shiftKey, alt: e.altKey });
2502
+ if (g.error) setShapeTypeError(g.error);
2209
2503
  }
2210
2504
  return;
2211
2505
  }
2212
2506
  if (activeTab === "annotate") {
2213
2507
  if (annotationDragInfoRef.current) {
2214
2508
  const drag = annotationDragInfoRef.current;
2215
- const currentImgPt2 = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2509
+ const currentImgPt2 = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2216
2510
  const dx = currentImgPt2.x - drag.startImgPt.x;
2217
2511
  const dy = currentImgPt2.y - drag.startImgPt.y;
2218
2512
  editor.updateAnnotation(drag.annId, {
@@ -2224,10 +2518,10 @@ var ImageEditor = ({
2224
2518
  const startPt = dragStartPointRef.current;
2225
2519
  if (!startPt) {
2226
2520
  if (state.activeTool === "select") {
2227
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2521
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2228
2522
  let hovered = false;
2229
2523
  for (let i = state.annotations.length - 1; i >= 0; i--) {
2230
- if ((0, import_image_editor12.hitTestAnnotation)(imgPt, state.annotations[i])) {
2524
+ if ((0, import_image_editor14.hitTestAnnotation)(imgPt, state.annotations[i])) {
2231
2525
  hovered = true;
2232
2526
  break;
2233
2527
  }
@@ -2238,7 +2532,7 @@ var ImageEditor = ({
2238
2532
  }
2239
2533
  return;
2240
2534
  }
2241
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2535
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2242
2536
  if (state.activeTool === "pen" && isDrawingRef.current) {
2243
2537
  currentPathRef.current.push(currentImgPt);
2244
2538
  const draft = {
@@ -2318,7 +2612,7 @@ var ImageEditor = ({
2318
2612
  if (activeTab === "select") {
2319
2613
  const gesture = selectionGestureRef.current;
2320
2614
  if (gesture.active) {
2321
- gesture.end((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
2615
+ gesture.end((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
2322
2616
  selectionDraftRef.current = null;
2323
2617
  renderCanvas();
2324
2618
  }
@@ -2335,6 +2629,19 @@ var ImageEditor = ({
2335
2629
  }
2336
2630
  return;
2337
2631
  }
2632
+ if (activeTab === "annotate" && state.activeTool === "shape") {
2633
+ shapeGestureRef.current.up();
2634
+ return;
2635
+ }
2636
+ if (activeTab === "annotate" && state.activeTool === "type") {
2637
+ const tool = typeToolRef.current;
2638
+ tool.up((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false));
2639
+ setTypeSession(tool.session);
2640
+ if (tool.error) setShapeTypeError(tool.error);
2641
+ void renderCanvas();
2642
+ if (tool.session) setTimeout(() => typeInputRef.current?.focus(), 0);
2643
+ return;
2644
+ }
2338
2645
  if (activeTab === "annotate") {
2339
2646
  if (annotationDragInfoRef.current) {
2340
2647
  annotationDragInfoRef.current = null;
@@ -2342,7 +2649,7 @@ var ImageEditor = ({
2342
2649
  }
2343
2650
  const startPt = dragStartPointRef.current;
2344
2651
  if (startPt) {
2345
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2652
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
2346
2653
  if (state.activeTool === "pen" && isDrawingRef.current) {
2347
2654
  if (currentPathRef.current.length > 1) {
2348
2655
  editor.addAnnotation({
@@ -2438,15 +2745,15 @@ var ImageEditor = ({
2438
2745
  link.click();
2439
2746
  }
2440
2747
  };
2441
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2748
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2442
2749
  "div",
2443
2750
  {
2444
2751
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
2445
2752
  style,
2446
2753
  children: [
2447
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
2448
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2449
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2754
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
2755
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2756
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2450
2757
  "button",
2451
2758
  {
2452
2759
  type: "button",
@@ -2458,7 +2765,7 @@ var ImageEditor = ({
2458
2765
  children: "Transform & Crop"
2459
2766
  }
2460
2767
  ),
2461
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2768
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2462
2769
  "button",
2463
2770
  {
2464
2771
  type: "button",
@@ -2470,7 +2777,7 @@ var ImageEditor = ({
2470
2777
  children: "Adjustments"
2471
2778
  }
2472
2779
  ),
2473
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2780
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2474
2781
  "button",
2475
2782
  {
2476
2783
  type: "button",
@@ -2482,7 +2789,7 @@ var ImageEditor = ({
2482
2789
  children: "Layers"
2483
2790
  }
2484
2791
  ),
2485
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2792
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2486
2793
  "button",
2487
2794
  {
2488
2795
  type: "button",
@@ -2494,7 +2801,7 @@ var ImageEditor = ({
2494
2801
  children: "Paint"
2495
2802
  }
2496
2803
  ),
2497
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2804
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2498
2805
  "button",
2499
2806
  {
2500
2807
  type: "button",
@@ -2506,7 +2813,7 @@ var ImageEditor = ({
2506
2813
  children: "Select & Mask"
2507
2814
  }
2508
2815
  ),
2509
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2816
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2510
2817
  "button",
2511
2818
  {
2512
2819
  type: "button",
@@ -2518,7 +2825,7 @@ var ImageEditor = ({
2518
2825
  children: "Annotations"
2519
2826
  }
2520
2827
  ),
2521
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2828
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2522
2829
  "button",
2523
2830
  {
2524
2831
  type: "button",
@@ -2530,7 +2837,7 @@ var ImageEditor = ({
2530
2837
  children: "Depth Mask"
2531
2838
  }
2532
2839
  ),
2533
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2840
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2534
2841
  "button",
2535
2842
  {
2536
2843
  type: "button",
@@ -2540,14 +2847,14 @@ var ImageEditor = ({
2540
2847
  },
2541
2848
  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"}`,
2542
2849
  children: [
2543
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2850
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2544
2851
  "AI Tools"
2545
2852
  ]
2546
2853
  }
2547
2854
  )
2548
2855
  ] }),
2549
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
2550
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2856
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
2857
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2551
2858
  "button",
2552
2859
  {
2553
2860
  type: "button",
@@ -2558,7 +2865,7 @@ var ImageEditor = ({
2558
2865
  children: "\u21A9"
2559
2866
  }
2560
2867
  ),
2561
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2868
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2562
2869
  "button",
2563
2870
  {
2564
2871
  type: "button",
@@ -2569,7 +2876,7 @@ var ImageEditor = ({
2569
2876
  children: "\u21AA"
2570
2877
  }
2571
2878
  ),
2572
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2879
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2573
2880
  "button",
2574
2881
  {
2575
2882
  type: "button",
@@ -2578,8 +2885,8 @@ var ImageEditor = ({
2578
2885
  children: "Reset"
2579
2886
  }
2580
2887
  ),
2581
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2582
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2888
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2889
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2583
2890
  "button",
2584
2891
  {
2585
2892
  type: "button",
@@ -2589,11 +2896,11 @@ var ImageEditor = ({
2589
2896
  children: "-"
2590
2897
  }
2591
2898
  ),
2592
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2899
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2593
2900
  Math.round(state.zoom * 100),
2594
2901
  "%"
2595
2902
  ] }),
2596
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2903
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2597
2904
  "button",
2598
2905
  {
2599
2906
  type: "button",
@@ -2603,8 +2910,8 @@ var ImageEditor = ({
2603
2910
  children: "+"
2604
2911
  }
2605
2912
  ),
2606
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2607
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2913
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2914
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2608
2915
  "button",
2609
2916
  {
2610
2917
  type: "button",
@@ -2615,7 +2922,7 @@ var ImageEditor = ({
2615
2922
  children: "Hold Compare"
2616
2923
  }
2617
2924
  ),
2618
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2925
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2619
2926
  "button",
2620
2927
  {
2621
2928
  type: "button",
@@ -2626,38 +2933,59 @@ var ImageEditor = ({
2626
2933
  )
2627
2934
  ] })
2628
2935
  ] }),
2629
- transformTool.active && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
2630
- !transformTool.active && transformTool.error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "alert", className: "border-b border-rose-900 bg-rose-950/80 px-4 py-1.5 text-xs text-rose-200", children: transformTool.error }),
2631
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2632
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2936
+ transformTool.active && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
2937
+ !transformTool.active && transformTool.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { role: "alert", className: "border-b border-rose-900 bg-rose-950/80 px-4 py-1.5 text-xs text-rose-200", children: transformTool.error }),
2938
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2939
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2633
2940
  "div",
2634
2941
  {
2635
2942
  ref: containerRef,
2636
2943
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
2637
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2638
- "canvas",
2639
- {
2640
- ref: canvasRef,
2641
- onMouseDown: handleMouseDown,
2642
- onMouseMove: handleMouseMove,
2643
- onMouseUp: handleMouseUp,
2644
- onMouseLeave: handleMouseUp,
2645
- onPointerDown: handlePaintPointerDown,
2646
- onPointerMove: handlePaintPointerMove,
2647
- onPointerUp: handlePaintPointerUp,
2648
- onPointerCancel: () => paintGestureRef.current?.cancel(),
2649
- "data-testid": "image-editor-canvas",
2650
- style: transformTool.active ? { cursor: transformCursor } : void 0,
2651
- className: `absolute inset-0 w-full h-full block ${transformTool.active ? "touch-none" : activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
2652
- }
2653
- )
2944
+ children: [
2945
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2946
+ "canvas",
2947
+ {
2948
+ ref: canvasRef,
2949
+ onMouseDown: handleMouseDown,
2950
+ onMouseMove: handleMouseMove,
2951
+ onMouseUp: handleMouseUp,
2952
+ onMouseLeave: handleMouseUp,
2953
+ onPointerDown: handlePaintPointerDown,
2954
+ onPointerMove: handlePaintPointerMove,
2955
+ onPointerUp: handlePaintPointerUp,
2956
+ onPointerCancel: () => paintGestureRef.current?.cancel(),
2957
+ "data-testid": "image-editor-canvas",
2958
+ style: transformTool.active ? { cursor: transformCursor } : void 0,
2959
+ 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" : ""}`
2960
+ }
2961
+ ),
2962
+ typeSession && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2963
+ "textarea",
2964
+ {
2965
+ ref: typeInputRef,
2966
+ "aria-label": "Edit text",
2967
+ "data-testid": "type-input",
2968
+ autoCapitalize: "off",
2969
+ autoCorrect: "off",
2970
+ spellCheck: false,
2971
+ onKeyDown: handleTypeKeyDown,
2972
+ onInput: handleTypeInput,
2973
+ onCompositionEnd: (e) => {
2974
+ const session = typeToolRef.current?.session;
2975
+ if (session && e.data) session.insert(e.data);
2976
+ e.currentTarget.value = "";
2977
+ },
2978
+ className: "absolute left-0 top-0 h-px w-px opacity-0"
2979
+ }
2980
+ )
2981
+ ]
2654
2982
  }
2655
2983
  ),
2656
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
2657
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2658
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2659
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
2660
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2984
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
2985
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2986
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2987
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
2988
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2661
2989
  "button",
2662
2990
  {
2663
2991
  type: "button",
@@ -2669,7 +2997,7 @@ var ImageEditor = ({
2669
2997
  children: "Freeform"
2670
2998
  }
2671
2999
  ),
2672
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3000
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2673
3001
  "button",
2674
3002
  {
2675
3003
  type: "button",
@@ -2681,7 +3009,7 @@ var ImageEditor = ({
2681
3009
  children: "1:1 Square"
2682
3010
  }
2683
3011
  ),
2684
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3012
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2685
3013
  "button",
2686
3014
  {
2687
3015
  type: "button",
@@ -2693,7 +3021,7 @@ var ImageEditor = ({
2693
3021
  children: "4:3 Standard"
2694
3022
  }
2695
3023
  ),
2696
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3024
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2697
3025
  "button",
2698
3026
  {
2699
3027
  type: "button",
@@ -2705,7 +3033,7 @@ var ImageEditor = ({
2705
3033
  children: "16:9 Wide"
2706
3034
  }
2707
3035
  ),
2708
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3036
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2709
3037
  "button",
2710
3038
  {
2711
3039
  type: "button",
@@ -2717,7 +3045,7 @@ var ImageEditor = ({
2717
3045
  children: "3:2 Photo"
2718
3046
  }
2719
3047
  ),
2720
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3048
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2721
3049
  "button",
2722
3050
  {
2723
3051
  type: "button",
@@ -2730,10 +3058,10 @@ var ImageEditor = ({
2730
3058
  }
2731
3059
  )
2732
3060
  ] }),
2733
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2734
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2735
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
2736
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3061
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3062
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
3063
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
3064
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2737
3065
  "button",
2738
3066
  {
2739
3067
  type: "button",
@@ -2742,7 +3070,7 @@ var ImageEditor = ({
2742
3070
  children: "Rotate -90\xB0"
2743
3071
  }
2744
3072
  ),
2745
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3073
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2746
3074
  "button",
2747
3075
  {
2748
3076
  type: "button",
@@ -2751,7 +3079,7 @@ var ImageEditor = ({
2751
3079
  children: "Rotate +90\xB0"
2752
3080
  }
2753
3081
  ),
2754
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3082
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2755
3083
  "button",
2756
3084
  {
2757
3085
  type: "button",
@@ -2760,7 +3088,7 @@ var ImageEditor = ({
2760
3088
  children: "Flip Horizontal"
2761
3089
  }
2762
3090
  ),
2763
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3091
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2764
3092
  "button",
2765
3093
  {
2766
3094
  type: "button",
@@ -2771,10 +3099,10 @@ var ImageEditor = ({
2771
3099
  )
2772
3100
  ] })
2773
3101
  ] }),
2774
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2775
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
2776
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2777
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3102
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3103
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
3104
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
3105
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2778
3106
  "button",
2779
3107
  {
2780
3108
  type: "button",
@@ -2784,25 +3112,25 @@ var ImageEditor = ({
2784
3112
  }
2785
3113
  )
2786
3114
  ] }),
2787
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Histogram, { histogram: editor.histogram }),
2788
- import_image_editor12.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react11.default.Fragment, { children: [
2789
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3115
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Histogram, { histogram: editor.histogram }),
3116
+ import_image_editor14.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react13.default.Fragment, { children: [
3117
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2790
3118
  ControlSlider,
2791
3119
  {
2792
3120
  spec,
2793
- value: (0, import_image_editor12.readAdjustmentControls)(state.adjustments)[spec.id],
3121
+ value: (0, import_image_editor14.readAdjustmentControls)(state.adjustments)[spec.id],
2794
3122
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
2795
3123
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
2796
3124
  }
2797
3125
  ),
2798
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3126
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2799
3127
  "div",
2800
3128
  {
2801
3129
  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",
2802
3130
  "data-testid": "image-editor-process-notice",
2803
3131
  children: [
2804
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
2805
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3132
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
3133
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2806
3134
  "button",
2807
3135
  {
2808
3136
  type: "button",
@@ -2815,7 +3143,7 @@ var ImageEditor = ({
2815
3143
  }
2816
3144
  )
2817
3145
  ] }, spec.id)),
2818
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3146
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2819
3147
  AdjustmentLayersPanel,
2820
3148
  {
2821
3149
  controller,
@@ -2824,9 +3152,9 @@ var ImageEditor = ({
2824
3152
  }
2825
3153
  ) })
2826
3154
  ] }),
2827
- activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2828
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
2829
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3155
+ activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3156
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
3157
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2830
3158
  "button",
2831
3159
  {
2832
3160
  type: "button",
@@ -2837,12 +3165,12 @@ var ImageEditor = ({
2837
3165
  children: "Free Transform"
2838
3166
  }
2839
3167
  ),
2840
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LayersPanel, { controller })
3168
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LayersPanel, { controller })
2841
3169
  ] }),
2842
- activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2843
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
2844
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(BrushOptionsBar, { controller }),
2845
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3170
+ activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3171
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
3172
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BrushOptionsBar, { controller }),
3173
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2846
3174
  "button",
2847
3175
  {
2848
3176
  type: "button",
@@ -2853,12 +3181,29 @@ var ImageEditor = ({
2853
3181
  children: "Free Transform"
2854
3182
  }
2855
3183
  ),
2856
- paintError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
2857
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LayersPanel, { controller }) })
3184
+ paintError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
3185
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LayersPanel, { controller }) })
2858
3186
  ] }),
2859
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2860
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2861
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3187
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3188
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
3189
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid grid-cols-2 gap-1.5", children: ["shape", "type"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3190
+ "button",
3191
+ {
3192
+ type: "button",
3193
+ "aria-pressed": state.activeTool === t,
3194
+ onClick: () => editor.setTool(t),
3195
+ 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"}`,
3196
+ children: t === "shape" ? "Shape" : "Type"
3197
+ },
3198
+ t
3199
+ )) }),
3200
+ state.activeTool === "shape" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
3201
+ state.activeTool === "type" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
3202
+ state.activeTool === "type" && typeSession && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: finishTyping, className: "self-start rounded bg-slate-800 px-2 py-1 text-[11px] text-slate-200 hover:bg-slate-700", children: "Done editing text" }),
3203
+ shapeTypeError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
3204
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3205
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
3206
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2862
3207
  "button",
2863
3208
  {
2864
3209
  type: "button",
@@ -2868,9 +3213,9 @@ var ImageEditor = ({
2868
3213
  },
2869
3214
  t
2870
3215
  )) }),
2871
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
2872
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { className: "text-slate-400", children: "Color:" }),
2873
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3216
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
3217
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { className: "text-slate-400", children: "Color:" }),
3218
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2874
3219
  "input",
2875
3220
  {
2876
3221
  type: "color",
@@ -2879,15 +3224,15 @@ var ImageEditor = ({
2879
3224
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
2880
3225
  }
2881
3226
  ),
2882
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 ml-2", children: [
2883
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2884
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Width:" }),
2885
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-mono", children: [
3227
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 ml-2", children: [
3228
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
3229
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Width:" }),
3230
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "font-mono", children: [
2886
3231
  strokeWidth,
2887
3232
  "px"
2888
3233
  ] })
2889
3234
  ] }),
2890
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3235
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2891
3236
  "input",
2892
3237
  {
2893
3238
  type: "range",
@@ -2900,10 +3245,10 @@ var ImageEditor = ({
2900
3245
  )
2901
3246
  ] })
2902
3247
  ] }),
2903
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2904
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2905
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex gap-2", children: [
2906
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3248
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3249
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
3250
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-2", children: [
3251
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2907
3252
  "input",
2908
3253
  {
2909
3254
  type: "text",
@@ -2914,7 +3259,7 @@ var ImageEditor = ({
2914
3259
  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"
2915
3260
  }
2916
3261
  ),
2917
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3262
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2918
3263
  "button",
2919
3264
  {
2920
3265
  type: "button",
@@ -2924,14 +3269,14 @@ var ImageEditor = ({
2924
3269
  }
2925
3270
  )
2926
3271
  ] }),
2927
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
2928
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Font Size:" }),
2929
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-mono", children: [
3272
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
3273
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Font Size:" }),
3274
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "font-mono", children: [
2930
3275
  fontSize,
2931
3276
  "px"
2932
3277
  ] })
2933
3278
  ] }),
2934
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3279
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2935
3280
  "input",
2936
3281
  {
2937
3282
  type: "range",
@@ -2942,14 +3287,14 @@ var ImageEditor = ({
2942
3287
  className: "w-full accent-indigo-500"
2943
3288
  }
2944
3289
  ),
2945
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2946
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
2947
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-slate-400", children: [
3290
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3291
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
3292
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-slate-400", children: [
2948
3293
  "Layers (",
2949
3294
  state.annotations.length,
2950
3295
  ")"
2951
3296
  ] }),
2952
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3297
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2953
3298
  "button",
2954
3299
  {
2955
3300
  type: "button",
@@ -2958,7 +3303,7 @@ var ImageEditor = ({
2958
3303
  children: "Delete Selected"
2959
3304
  }
2960
3305
  ),
2961
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3306
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2962
3307
  "button",
2963
3308
  {
2964
3309
  type: "button",
@@ -2969,10 +3314,10 @@ var ImageEditor = ({
2969
3314
  )
2970
3315
  ] })
2971
3316
  ] }),
2972
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2973
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
2974
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2975
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3317
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3318
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
3319
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
3320
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2976
3321
  "button",
2977
3322
  {
2978
3323
  type: "button",
@@ -2982,8 +3327,8 @@ var ImageEditor = ({
2982
3327
  }
2983
3328
  )
2984
3329
  ] }),
2985
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2986
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3330
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
3331
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2987
3332
  "input",
2988
3333
  {
2989
3334
  type: "checkbox",
@@ -2992,12 +3337,12 @@ var ImageEditor = ({
2992
3337
  className: "rounded accent-indigo-500"
2993
3338
  }
2994
3339
  ),
2995
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Enable Depth / Alpha Mask" })
3340
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Enable Depth / Alpha Mask" })
2996
3341
  ] }),
2997
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2998
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2999
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3000
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3342
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3343
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
3344
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3345
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3001
3346
  "input",
3002
3347
  {
3003
3348
  type: "text",
@@ -3008,8 +3353,8 @@ var ImageEditor = ({
3008
3353
  }
3009
3354
  )
3010
3355
  ] }),
3011
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex gap-2", children: [
3012
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3356
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-2", children: [
3357
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3013
3358
  "button",
3014
3359
  {
3015
3360
  type: "button",
@@ -3018,7 +3363,7 @@ var ImageEditor = ({
3018
3363
  children: "Threshold Mode"
3019
3364
  }
3020
3365
  ),
3021
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3366
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3022
3367
  "button",
3023
3368
  {
3024
3369
  type: "button",
@@ -3028,12 +3373,12 @@ var ImageEditor = ({
3028
3373
  }
3029
3374
  )
3030
3375
  ] }),
3031
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
3032
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3033
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Depth Start (Lower):" }),
3034
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
3376
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
3377
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3378
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Depth Start (Lower):" }),
3379
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
3035
3380
  ] }),
3036
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3381
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3037
3382
  "input",
3038
3383
  {
3039
3384
  type: "range",
@@ -3047,12 +3392,12 @@ var ImageEditor = ({
3047
3392
  }
3048
3393
  )
3049
3394
  ] }),
3050
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
3051
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3052
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Depth Stop (Upper):" }),
3053
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
3395
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
3396
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3397
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Depth Stop (Upper):" }),
3398
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
3054
3399
  ] }),
3055
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3400
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3056
3401
  "input",
3057
3402
  {
3058
3403
  type: "range",
@@ -3066,12 +3411,12 @@ var ImageEditor = ({
3066
3411
  }
3067
3412
  )
3068
3413
  ] }),
3069
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
3070
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3071
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Softness:" }),
3072
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
3414
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
3415
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3416
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Softness:" }),
3417
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
3073
3418
  ] }),
3074
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3419
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3075
3420
  "input",
3076
3421
  {
3077
3422
  type: "range",
@@ -3083,8 +3428,8 @@ var ImageEditor = ({
3083
3428
  }
3084
3429
  )
3085
3430
  ] }),
3086
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3087
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3431
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3432
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3088
3433
  "input",
3089
3434
  {
3090
3435
  type: "checkbox",
@@ -3093,12 +3438,12 @@ var ImageEditor = ({
3093
3438
  className: "rounded accent-indigo-500"
3094
3439
  }
3095
3440
  ),
3096
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Invert Mask" })
3441
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Invert Mask" })
3097
3442
  ] })
3098
3443
  ] })
3099
3444
  ] }),
3100
- activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3101
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3445
+ activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3446
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3102
3447
  SelectionOptionsBar,
3103
3448
  {
3104
3449
  controller,
@@ -3108,9 +3453,9 @@ var ImageEditor = ({
3108
3453
  quickMask: Boolean(state.quickMask)
3109
3454
  }
3110
3455
  ),
3111
- selectionError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
3112
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex gap-1", children: [
3113
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3456
+ selectionError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
3457
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-1", children: [
3458
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3114
3459
  "button",
3115
3460
  {
3116
3461
  type: "button",
@@ -3121,7 +3466,7 @@ var ImageEditor = ({
3121
3466
  children: "Transform Selection"
3122
3467
  }
3123
3468
  ),
3124
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3469
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3125
3470
  "button",
3126
3471
  {
3127
3472
  type: "button",
@@ -3133,12 +3478,12 @@ var ImageEditor = ({
3133
3478
  }
3134
3479
  )
3135
3480
  ] }),
3136
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
3481
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
3137
3482
  ] }),
3138
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3139
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
3140
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Results go to" }),
3141
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3483
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3484
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
3485
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Results go to" }),
3486
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3142
3487
  "select",
3143
3488
  {
3144
3489
  "aria-label": "AI result target",
@@ -3146,54 +3491,54 @@ var ImageEditor = ({
3146
3491
  onChange: (e) => setAiTarget(e.target.value),
3147
3492
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
3148
3493
  children: [
3149
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
3150
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
3151
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "replace", children: "Replace image" })
3494
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
3495
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
3496
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "replace", children: "Replace image" })
3152
3497
  ]
3153
3498
  }
3154
3499
  )
3155
3500
  ] }),
3156
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3157
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
3158
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3159
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
3501
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3502
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
3503
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3504
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
3160
3505
  "Background Removal"
3161
3506
  ] }),
3162
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
3507
+ isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
3163
3508
  ] }),
3164
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3165
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3509
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3510
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3166
3511
  "button",
3167
3512
  {
3168
3513
  type: "button",
3169
3514
  onClick: handleRemoveBackground,
3170
3515
  disabled: isRemovingBg || isInpainting,
3171
3516
  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",
3172
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3173
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3517
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3518
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3174
3519
  "Removing Background..."
3175
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3176
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
3520
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3521
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
3177
3522
  "Remove Background"
3178
3523
  ] })
3179
3524
  }
3180
3525
  )
3181
3526
  ] }),
3182
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3183
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between", children: [
3184
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3185
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3186
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
3187
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m14 7 3 3" })
3527
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3528
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
3529
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3530
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3531
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
3532
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "m14 7 3 3" })
3188
3533
  ] }),
3189
3534
  "Generative Inpainting"
3190
3535
  ] }),
3191
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
3536
+ isInpainting && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
3192
3537
  ] }),
3193
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3194
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-1", children: [
3195
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3196
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3538
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3539
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-1", children: [
3540
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3541
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3197
3542
  "textarea",
3198
3543
  {
3199
3544
  id: "ai-inpaint-prompt-react",
@@ -3205,10 +3550,10 @@ var ImageEditor = ({
3205
3550
  }
3206
3551
  )
3207
3552
  ] }),
3208
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-1", children: [
3209
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3210
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
3211
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3553
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-1", children: [
3554
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3555
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
3556
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3212
3557
  "button",
3213
3558
  {
3214
3559
  type: "button",
@@ -3221,7 +3566,7 @@ var ImageEditor = ({
3221
3566
  ]
3222
3567
  }
3223
3568
  ),
3224
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3569
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3225
3570
  "button",
3226
3571
  {
3227
3572
  type: "button",
@@ -3236,25 +3581,25 @@ var ImageEditor = ({
3236
3581
  )
3237
3582
  ] })
3238
3583
  ] }),
3239
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3584
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3240
3585
  "button",
3241
3586
  {
3242
3587
  type: "button",
3243
3588
  onClick: handleInpaint,
3244
3589
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
3245
3590
  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",
3246
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3247
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3591
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3592
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3248
3593
  "Generating Inpaint..."
3249
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3250
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
3594
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3595
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
3251
3596
  "Apply Inpainting"
3252
3597
  ] })
3253
3598
  }
3254
3599
  )
3255
3600
  ] }),
3256
- aiError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3257
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
3601
+ aiError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3602
+ aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
3258
3603
  ] })
3259
3604
  ] })
3260
3605
  ] })
@@ -3275,6 +3620,8 @@ var ImageEditor = ({
3275
3620
  LayersPanel,
3276
3621
  RefineEdgePanel,
3277
3622
  SelectionOptionsBar,
3623
+ ShapeOptionsBar,
3624
+ TypeOptionsBar,
3278
3625
  useImageEditor,
3279
3626
  useImageHistogram
3280
3627
  });