@pixerate/editor-react 0.85.0 → 0.87.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.
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  useImageEditor,
40
40
  useImageEffectsTools,
41
41
  useImageHistogram
42
- } from "./chunk-VKWTKESA.js";
42
+ } from "./chunk-4FQXRPBN.js";
43
43
  import "./chunk-MO354USR.js";
44
44
  import "./chunk-WOQ3H7KA.js";
45
45
  import "./chunk-ZQZAKUUM.js";
@@ -39,6 +39,7 @@ __export(vector_exports, {
39
39
  VectorEnvelopePanel: () => VectorEnvelopePanel,
40
40
  VectorFilterDefs: () => VectorFilterDefs,
41
41
  VectorFramePanel: () => VectorFramePanel,
42
+ VectorGeneratePanel: () => VectorGeneratePanel,
42
43
  VectorGradientAnnotator: () => VectorGradientAnnotator,
43
44
  VectorGradientDefs: () => VectorGradientDefs,
44
45
  VectorGradientEditor: () => VectorGradientEditor,
@@ -62,7 +63,8 @@ __export(vector_exports, {
62
63
  useVectorEditor: () => useVectorEditor,
63
64
  useVectorEditorController: () => useVectorEditorController,
64
65
  useVectorEditorState: () => useVectorEditorState,
65
- useVectorEffectsTools: () => useVectorEffectsTools
66
+ useVectorEffectsTools: () => useVectorEffectsTools,
67
+ useVectorGenerationTools: () => useVectorGenerationTools
66
68
  });
67
69
  module.exports = __toCommonJS(vector_exports);
68
70
 
@@ -114,6 +116,30 @@ function useVectorEffectsTools(registry, controller, options = {}) {
114
116
  return registry.register((0, import_vector.createVectorEffectsToolProvider)(controller, { id, namespace, readOnly }));
115
117
  }, [registry, controller, id, namespace, readOnly]);
116
118
  }
119
+ function useVectorGenerationTools(registry, controller, options) {
120
+ const latest = (0, import_react.useRef)(options);
121
+ latest.current = options;
122
+ const { id, namespace } = options;
123
+ (0, import_react.useEffect)(() => {
124
+ if (!registry) return;
125
+ const models = () => {
126
+ const m = latest.current.models;
127
+ return typeof m === "function" ? m() : m;
128
+ };
129
+ return registry.register(
130
+ (0, import_vector.createVectorGenerationToolProvider)(controller, {
131
+ id,
132
+ namespace,
133
+ models,
134
+ generate: (request, context) => latest.current.generate(request, context),
135
+ readOnly: () => {
136
+ const r = latest.current.readOnly;
137
+ return (typeof r === "function" ? r() : r) ?? false;
138
+ }
139
+ })
140
+ );
141
+ }, [registry, controller, id, namespace]);
142
+ }
117
143
 
118
144
  // src/vector/VectorCanvas.tsx
119
145
  var import_react3 = __toESM(require("react"), 1);
@@ -658,6 +684,7 @@ function VectorCanvas({
658
684
  overlay.builder.lines.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-builder-line": "", d, fill: "none", stroke: import_vector3.VECTOR_OVERLAY_THEME.builderErase, strokeWidth: 3, strokeLinecap: "round" }, `l${i}`)),
659
685
  overlay.builder.trail && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-builder-trail": "", d: overlay.builder.trail, fill: "none", stroke: overlay.builder.mode === "erase" ? import_vector3.VECTOR_OVERLAY_THEME.builderErase : accentColor, strokeWidth: 1 })
660
686
  ] }),
687
+ overlay.brush && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-brush": "", cx: overlay.brush.x, cy: overlay.brush.y, r: overlay.brush.r, fill: "none", stroke: accentColor, strokeWidth: 1, strokeDasharray: "4 3", pointerEvents: "none" }),
661
688
  overlay.toolStroke && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
662
689
  "path",
663
690
  {
@@ -838,7 +865,7 @@ function VectorCanvas({
838
865
 
839
866
  // src/vector/VectorToolbar.tsx
840
867
  var import_react11 = __toESM(require("react"), 1);
841
- var import_vector19 = require("@pixerate/editor/vector");
868
+ var import_vector20 = require("@pixerate/editor/vector");
842
869
 
843
870
  // src/vector/VectorEffectsPanel.tsx
844
871
  var import_vector4 = require("@pixerate/editor/vector");
@@ -2021,6 +2048,7 @@ function VectorShadingPanel({ controller, className }) {
2021
2048
 
2022
2049
  // src/vector/VectorTracePanel.tsx
2023
2050
  var import_react9 = require("react");
2051
+ var import_vector15 = require("@pixerate/editor/vector");
2024
2052
  var import_jsx_runtime14 = require("react/jsx-runtime");
2025
2053
  var buttonClass12 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
2026
2054
  var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
@@ -2047,7 +2075,8 @@ function VectorTracePanel({ controller, className }) {
2047
2075
  const pixels = await filePixels(file);
2048
2076
  const doc = controller.getState().document;
2049
2077
  const width = Math.min(doc.width, pixels.width);
2050
- const r = controller.traceImage(pixels, { mode, colors, width, name: file.name.replace(/\.[^.]+$/, "") || "Image Trace" });
2078
+ const name = file.name.replace(/\.[^.]+$/, "") || void 0;
2079
+ const r = mode === "threshold" || mode === "color" ? controller.traceImage(pixels, { mode, colors, width, name: name ?? "Image Trace" }) : controller.stylizeImage(pixels, mode, { width, ...name ? { name } : {} });
2051
2080
  setMessage(r.ok ? null : r.message);
2052
2081
  } catch {
2053
2082
  setMessage("That file could not be read as an image.");
@@ -2058,7 +2087,8 @@ function VectorTracePanel({ controller, className }) {
2058
2087
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Trace" }),
2059
2088
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("select", { "aria-label": "Trace mode", className: selectClass9, value: mode, onChange: (e) => setMode(e.target.value), children: [
2060
2089
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "threshold", children: "Black & white" }),
2061
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "color", children: "Colours" })
2090
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "color", children: "Colours" }),
2091
+ import_vector15.VECTOR_STYLIZE_STYLES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: s, children: import_vector15.VECTOR_STYLIZE_LABELS[s] }, s))
2062
2092
  ] }),
2063
2093
  mode === "color" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "number", min: 2, max: 32, "aria-label": "Trace colours", title: "Colours", className: numberClass7, value: colors, onChange: (e) => setColors(Math.max(2, Math.min(32, parseInt(e.target.value, 10) || 2))) }),
2064
2094
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "data-vector-trace-action": "", title: "Image Trace: pick an image to turn into paths", onClick: () => input.current?.click(), children: "Image\u2026" }),
@@ -2082,14 +2112,14 @@ function VectorTracePanel({ controller, className }) {
2082
2112
  }
2083
2113
 
2084
2114
  // src/vector/VectorSymmetryPanel.tsx
2085
- var import_vector15 = require("@pixerate/editor/vector");
2115
+ var import_vector16 = require("@pixerate/editor/vector");
2086
2116
  var import_jsx_runtime15 = require("react/jsx-runtime");
2087
2117
  var buttonClass13 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2088
2118
  var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2089
2119
  var numberClass8 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
2090
2120
  function VectorSymmetryPanel({ controller, className }) {
2091
2121
  const state = useVectorEditorState(controller);
2092
- const group = state.selection.map((id) => controller.getNode(id)).find(import_vector15.isVectorSymmetryGroup) ?? null;
2122
+ const group = state.selection.map((id) => controller.getNode(id)).find(import_vector16.isVectorSymmetryGroup) ?? null;
2093
2123
  const s = group?.symmetry;
2094
2124
  const ids = group ? [group.id] : void 0;
2095
2125
  const drawing = !!group && state.symmetryTarget === group.id;
@@ -2099,7 +2129,7 @@ function VectorSymmetryPanel({ controller, className }) {
2099
2129
  !group && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "data-vector-symmetry-action": "make", title: "Make Symmetry: the selection (or nothing yet) mirrored live across a vertical axis", onClick: () => controller.makeSymmetry({ mode: "vertical" }), children: "Mirror" }),
2100
2130
  !group && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "data-vector-symmetry-action": "radial", title: "Make Symmetry: the selection repeated round its centre", onClick: () => controller.makeSymmetry({ mode: "radial", copies: 6 }), children: "Radial" }),
2101
2131
  group && s && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2102
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Symmetry mode", className: selectClass10, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: import_vector15.VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: m, children: import_vector15.VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
2132
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Symmetry mode", className: selectClass10, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: import_vector16.VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: m, children: import_vector16.VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
2103
2133
  s.mode === "radial" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2104
2134
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "number", min: 2, max: 64, "aria-label": "Symmetry copies", title: "Copies round the circle", className: numberClass8, value: s.copies ?? 6, onChange: (e) => controller.setSymmetry({ copies: Math.max(2, Math.min(64, parseInt(e.target.value, 10) || 2)) }, { ids }) }),
2105
2135
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Mirror each copy too (kaleidoscope)", children: [
@@ -2120,7 +2150,7 @@ function VectorSymmetryPanel({ controller, className }) {
2120
2150
 
2121
2151
  // src/vector/VectorPerspectivePanel.tsx
2122
2152
  var import_react10 = __toESM(require("react"), 1);
2123
- var import_vector16 = require("@pixerate/editor/vector");
2153
+ var import_vector17 = require("@pixerate/editor/vector");
2124
2154
  var import_jsx_runtime16 = require("react/jsx-runtime");
2125
2155
  var buttonClass14 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2126
2156
  var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
@@ -2128,10 +2158,10 @@ var PLANE_LABELS = { floor: "Floor", left: "Left wall", right: "Right wall", sid
2128
2158
  function VectorPerspectivePanel({ controller, className }) {
2129
2159
  const state = useVectorEditorState(controller);
2130
2160
  const grid = state.document.perspective ?? null;
2131
- const planes = grid ? (0, import_vector16.vectorPerspectivePlanes)(grid) : [];
2161
+ const planes = grid ? (0, import_vector17.vectorPerspectivePlanes)(grid) : [];
2132
2162
  const [attachTo, setAttachTo] = import_react10.default.useState("");
2133
2163
  const target = (state.perspectivePlane ?? attachTo) || planes[0];
2134
- const add = (n) => controller.setPerspective((0, import_vector16.vectorPerspectivePreset)(n, state.document.width, state.document.height));
2164
+ const add = (n) => controller.setPerspective((0, import_vector17.vectorPerspectivePreset)(n, state.document.width, state.document.height));
2135
2165
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-perspective-panel": "", "aria-label": "Perspective", children: [
2136
2166
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2137
2167
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Perspective" }),
@@ -2164,7 +2194,7 @@ function VectorPerspectivePanel({ controller, className }) {
2164
2194
  }
2165
2195
 
2166
2196
  // src/vector/VectorLensPanel.tsx
2167
- var import_vector17 = require("@pixerate/editor/vector");
2197
+ var import_vector18 = require("@pixerate/editor/vector");
2168
2198
  var import_jsx_runtime17 = require("react/jsx-runtime");
2169
2199
  var selectClass12 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2170
2200
  var numberClass9 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
@@ -2173,7 +2203,7 @@ function VectorLensPanel({ controller, className }) {
2173
2203
  const path = state.selection.map((id) => controller.getNode(id)).find((n) => n?.type === "path" && n.subpaths.some((sp) => sp.closed) && !n.connector);
2174
2204
  if (!path) return null;
2175
2205
  const lens = path.lens ?? null;
2176
- const spec = lens ? import_vector17.VECTOR_LENS_SPECS[lens.type] : null;
2206
+ const spec = lens ? import_vector18.VECTOR_LENS_SPECS[lens.type] : null;
2177
2207
  const ids = [path.id];
2178
2208
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-lens-panel": "", "aria-label": "Lens", children: [
2179
2209
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
@@ -2187,7 +2217,7 @@ function VectorLensPanel({ controller, className }) {
2187
2217
  onChange: (e) => e.target.value ? controller.setLens({ type: e.target.value }, { ids }) : controller.setLens(null, { ids }),
2188
2218
  children: [
2189
2219
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "", children: "None" }),
2190
- import_vector17.VECTOR_LENS_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: t, children: import_vector17.VECTOR_LENS_LABELS[t] }, t))
2220
+ import_vector18.VECTOR_LENS_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: t, children: import_vector18.VECTOR_LENS_LABELS[t] }, t))
2191
2221
  ]
2192
2222
  }
2193
2223
  )
@@ -2217,7 +2247,7 @@ function VectorLensPanel({ controller, className }) {
2217
2247
  }
2218
2248
 
2219
2249
  // src/vector/VectorGradientEditor.tsx
2220
- var import_vector18 = require("@pixerate/editor/vector");
2250
+ var import_vector19 = require("@pixerate/editor/vector");
2221
2251
  var import_jsx_runtime18 = require("react/jsx-runtime");
2222
2252
  var selectClass13 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2223
2253
  var numberClass10 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
@@ -2225,7 +2255,7 @@ var buttonClass15 = "inline-flex h-7 min-w-7 items-center justify-center rounded
2225
2255
  var percent = (v) => Math.round(v * 1e3) / 10;
2226
2256
  function VectorGradientEditor({ controller, className }) {
2227
2257
  const state = useVectorEditorState(controller);
2228
- const ed = (0, import_vector18.getVectorGradientEditor)(state);
2258
+ const ed = (0, import_vector19.getVectorGradientEditor)(state);
2229
2259
  if (!ed) return null;
2230
2260
  const g = ed.gradient;
2231
2261
  const sel = ed.selected;
@@ -2233,7 +2263,7 @@ function VectorGradientEditor({ controller, className }) {
2233
2263
  const setType = (value) => {
2234
2264
  if (value === "solid") {
2235
2265
  const first = ed.stops[0];
2236
- controller.setStyle({ [ed.target]: (0, import_vector18.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
2266
+ controller.setStyle({ [ed.target]: (0, import_vector19.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
2237
2267
  } else controller.setGradient({ type: value });
2238
2268
  };
2239
2269
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
@@ -2246,7 +2276,7 @@ function VectorGradientEditor({ controller, className }) {
2246
2276
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
2247
2277
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { "aria-label": "Gradient type", className: selectClass13, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
2248
2278
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "solid", children: "Solid" }),
2249
- import_vector18.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: t, children: import_vector18.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
2279
+ import_vector19.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: t, children: import_vector19.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
2250
2280
  ] }),
2251
2281
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: buttonClass15, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
2252
2282
  ] }),
@@ -2287,7 +2317,7 @@ function VectorGradientEditor({ controller, className }) {
2287
2317
  type: "color",
2288
2318
  "aria-label": "Stop colour",
2289
2319
  className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
2290
- value: (0, import_vector18.vectorPaintToHex)(sel.color) ?? "#000000",
2320
+ value: (0, import_vector19.vectorPaintToHex)(sel.color) ?? "#000000",
2291
2321
  onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
2292
2322
  onBlur: end
2293
2323
  }
@@ -2353,7 +2383,7 @@ function VectorGradientEditor({ controller, className }) {
2353
2383
  ] }),
2354
2384
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2355
2385
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Colours" }),
2356
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass13, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector18.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: i, children: import_vector18.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
2386
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass13, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector19.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: i, children: import_vector19.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
2357
2387
  ] }),
2358
2388
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2359
2389
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Smooth" }),
@@ -2375,11 +2405,11 @@ function VectorGradientEditor({ controller, className }) {
2375
2405
  ] }),
2376
2406
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2377
2407
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Spread" }),
2378
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient spread", className: selectClass13, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector18.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: sp, children: import_vector18.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
2408
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient spread", className: selectClass13, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector19.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: sp, children: import_vector19.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
2379
2409
  ] }),
2380
2410
  ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2381
2411
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "On stroke" }),
2382
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass13, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector18.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: m, children: import_vector18.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
2412
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass13, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector19.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: m, children: import_vector19.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
2383
2413
  ] })
2384
2414
  ] })
2385
2415
  ] });
@@ -2392,7 +2422,7 @@ var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.te
2392
2422
  var buttonClass16 = "inline-flex h-8 min-w-8 items-center justify-center rounded-md border border-border bg-background px-2 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2393
2423
  function VectorToolbar({
2394
2424
  controller,
2395
- tools = import_vector19.VECTOR_TOOLS,
2425
+ tools = import_vector20.VECTOR_TOOLS,
2396
2426
  showHistory = true,
2397
2427
  showArrange = true,
2398
2428
  showSnap = true,
@@ -2406,7 +2436,7 @@ function VectorToolbar({
2406
2436
  const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
2407
2437
  const editing = state.editing;
2408
2438
  const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
2409
- const maskSelected = state.selection.some((id) => (0, import_vector19.isVectorMaskGroup)(controller.getNode(id)));
2439
+ const maskSelected = state.selection.some((id) => (0, import_vector20.isVectorMaskGroup)(controller.getNode(id)));
2410
2440
  const [live, setLive] = import_react11.default.useState(false);
2411
2441
  const booleanDisabled = live ? count < 1 : count < 2;
2412
2442
  const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: buttonClass16, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
@@ -2418,10 +2448,10 @@ function VectorToolbar({
2418
2448
  "data-vector-tool": tool,
2419
2449
  className: buttonClass16,
2420
2450
  "aria-pressed": state.tool === tool,
2421
- title: `${(0, import_vector19.vectorToolLabel)(tool)} (${import_vector19.VECTOR_TOOL_SHORTCUTS[tool]})`,
2422
- "aria-label": (0, import_vector19.vectorToolLabel)(tool),
2451
+ title: `${(0, import_vector20.vectorToolLabel)(tool)} (${import_vector20.VECTOR_TOOL_SHORTCUTS[tool]})`,
2452
+ "aria-label": (0, import_vector20.vectorToolLabel)(tool),
2423
2453
  onClick: () => controller.setTool(tool),
2424
- children: import_vector19.VECTOR_TOOL_GLYPHS[tool]
2454
+ children: import_vector20.VECTOR_TOOL_GLYPHS[tool]
2425
2455
  },
2426
2456
  tool
2427
2457
  )) }),
@@ -2450,10 +2480,10 @@ function VectorToolbar({
2450
2480
  "aria-label": "Polar tracking increment",
2451
2481
  title: "Polar tracking: the angles drawn points snap to from where they leave",
2452
2482
  className: "h-8 rounded-md border border-border bg-background px-1 text-xs",
2453
- value: String((0, import_vector19.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
2454
- onChange: (e) => controller.setSnap({ angles: (0, import_vector19.vectorPolarAngles)(Number(e.target.value)) }),
2483
+ value: String((0, import_vector20.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
2484
+ onChange: (e) => controller.setSnap({ angles: (0, import_vector20.vectorPolarAngles)(Number(e.target.value)) }),
2455
2485
  children: [
2456
- (0, import_vector19.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "Custom" }),
2486
+ (0, import_vector20.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "Custom" }),
2457
2487
  [90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("option", { value: n, children: [
2458
2488
  n,
2459
2489
  "\xB0"
@@ -2463,7 +2493,7 @@ function VectorToolbar({
2463
2493
  )
2464
2494
  ] }),
2465
2495
  showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
2466
- import_vector19.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2496
+ import_vector20.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2467
2497
  "button",
2468
2498
  {
2469
2499
  type: "button",
@@ -2477,7 +2507,7 @@ function VectorToolbar({
2477
2507
  },
2478
2508
  a.id
2479
2509
  )),
2480
- import_vector19.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2510
+ import_vector20.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2481
2511
  "button",
2482
2512
  {
2483
2513
  type: "button",
@@ -2525,6 +2555,20 @@ function VectorToolbar({
2525
2555
  }
2526
2556
  )
2527
2557
  ] }),
2558
+ state.tool === "distort" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex flex-wrap items-center gap-1", "data-vector-distort-options": "", children: [
2559
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Distort brush", title: "What the brush does to the outlines it passes over", className: "h-7 rounded border border-border bg-background px-1 text-xs", value: editing.distortMode, onChange: (e) => controller.setEditing({ distortMode: e.target.value }), children: import_vector20.VECTOR_DISTORT_BRUSH_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: m, children: m[0].toUpperCase() + m.slice(1) }, m)) }),
2560
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2561
+ "Size",
2562
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "number", min: 1, step: 1, "aria-label": "Distort brush size", className: "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs", value: editing.distortSize, onChange: (e) => {
2563
+ const n = parseFloat(e.target.value);
2564
+ if (Number.isFinite(n) && n > 0) controller.setEditing({ distortSize: n });
2565
+ } })
2566
+ ] }),
2567
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2568
+ "Strength",
2569
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Distort brush strength", className: "h-4 w-20 accent-primary", value: editing.distortStrength, onChange: (e) => controller.setEditing({ distortStrength: parseFloat(e.target.value) }) })
2570
+ ] })
2571
+ ] }),
2528
2572
  state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2529
2573
  "button",
2530
2574
  {
@@ -2534,7 +2578,7 @@ function VectorToolbar({
2534
2578
  "aria-pressed": editing.fillGap > 0,
2535
2579
  title: "Close small gaps between path ends when filling",
2536
2580
  "aria-label": "Close gaps",
2537
- onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector19.VECTOR_FILL_GAP }),
2581
+ onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector20.VECTOR_FILL_GAP }),
2538
2582
  children: "Gaps"
2539
2583
  }
2540
2584
  )
@@ -2577,7 +2621,7 @@ function VectorToolbar({
2577
2621
  act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
2578
2622
  act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
2579
2623
  ] }),
2580
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector19.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2624
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector20.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2581
2625
  "button",
2582
2626
  {
2583
2627
  type: "button",
@@ -2606,7 +2650,7 @@ function VectorToolbar({
2606
2650
  }
2607
2651
  function VectorBlendControls({ controller }) {
2608
2652
  const state = useVectorEditorState(controller);
2609
- const blend = (0, import_vector19.getVectorBlendControls)(state);
2653
+ const blend = (0, import_vector20.getVectorBlendControls)(state);
2610
2654
  const o = blend.options;
2611
2655
  const selected = blend.ids.length > 0;
2612
2656
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
@@ -2617,8 +2661,8 @@ function VectorBlendControls({ controller }) {
2617
2661
  "aria-label": "Blend spacing",
2618
2662
  className: "h-7 rounded border border-border bg-background px-1 text-xs",
2619
2663
  value: o.spacing,
2620
- onChange: (e) => (0, import_vector19.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
2621
- children: import_vector19.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: sp, children: import_vector19.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
2664
+ onChange: (e) => (0, import_vector20.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
2665
+ children: import_vector20.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: sp, children: import_vector20.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
2622
2666
  }
2623
2667
  ),
2624
2668
  o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
@@ -2633,7 +2677,7 @@ function VectorBlendControls({ controller }) {
2633
2677
  onChange: (e) => {
2634
2678
  const n = parseFloat(e.target.value);
2635
2679
  if (!Number.isFinite(n) || n <= 0) return;
2636
- (0, import_vector19.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
2680
+ (0, import_vector20.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
2637
2681
  }
2638
2682
  }
2639
2683
  ),
@@ -2646,7 +2690,7 @@ function VectorBlendControls({ controller }) {
2646
2690
  "aria-pressed": o.orientToSpine,
2647
2691
  title: "Orient steps to the spine",
2648
2692
  "aria-label": "Orient to spine",
2649
- onClick: () => (0, import_vector19.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
2693
+ onClick: () => (0, import_vector20.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
2650
2694
  children: "\u293F"
2651
2695
  }
2652
2696
  ),
@@ -2671,7 +2715,7 @@ var selectClass14 = "h-7 min-w-0 flex-1 rounded border border-border bg-backgrou
2671
2715
  var numberClass11 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
2672
2716
  function VectorStylePanel({ controller, className }) {
2673
2717
  const state = useVectorEditorState(controller);
2674
- const style = (0, import_vector19.getVectorSelectionStyle)(state);
2718
+ const style = (0, import_vector20.getVectorSelectionStyle)(state);
2675
2719
  const d = state.defaults;
2676
2720
  const source = style ?? {
2677
2721
  fill: d.fill ?? null,
@@ -2684,7 +2728,7 @@ function VectorStylePanel({ controller, className }) {
2684
2728
  arrowAlign: d.arrowAlign ?? "extend",
2685
2729
  startArrowScale: d.startArrowScale ?? 1,
2686
2730
  endArrowScale: d.endArrowScale ?? 1,
2687
- widthProfile: (0, import_vector19.widthProfilePresetId)(d.strokeWidthProfile),
2731
+ widthProfile: (0, import_vector20.widthProfilePresetId)(d.strokeWidthProfile),
2688
2732
  cornerRadius: d.cornerRadius,
2689
2733
  cornerKind: d.cornerKind ?? "round",
2690
2734
  cornerSmoothing: 0,
@@ -2698,7 +2742,7 @@ function VectorStylePanel({ controller, className }) {
2698
2742
  };
2699
2743
  const setProfile = (id) => {
2700
2744
  if (style) controller.setWidthProfile(id);
2701
- else controller.setDefaults({ strokeWidthProfile: (0, import_vector19.widthProfilePreset)(id)?.length ? (0, import_vector19.widthProfilePreset)(id) : null });
2745
+ else controller.setDefaults({ strokeWidthProfile: (0, import_vector20.widthProfilePreset)(id)?.length ? (0, import_vector20.widthProfilePreset)(id) : null });
2702
2746
  };
2703
2747
  const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
2704
2748
  const arrowRow = (end, label) => {
@@ -2708,7 +2752,7 @@ function VectorStylePanel({ controller, className }) {
2708
2752
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
2709
2753
  /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass14, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
2710
2754
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "None" }),
2711
- import_vector19.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: h, children: import_vector19.VECTOR_ARROWHEAD_LABELS[h] }, h))
2755
+ import_vector20.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: h, children: import_vector20.VECTOR_ARROWHEAD_LABELS[h] }, h))
2712
2756
  ] }),
2713
2757
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2714
2758
  "input",
@@ -2734,7 +2778,7 @@ function VectorStylePanel({ controller, className }) {
2734
2778
  };
2735
2779
  const paintRow = (key, label) => {
2736
2780
  const paint = source[key];
2737
- const hex = (0, import_vector19.vectorPaintToHex)(paint);
2781
+ const hex = (0, import_vector20.vectorPaintToHex)(paint);
2738
2782
  const on = paint !== null && paint !== "none";
2739
2783
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2740
2784
  /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
@@ -2781,7 +2825,7 @@ function VectorStylePanel({ controller, className }) {
2781
2825
  ] }),
2782
2826
  /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
2783
2827
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Align" }),
2784
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass14, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector19.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: a, children: import_vector19.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
2828
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass14, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector20.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: a, children: import_vector20.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
2785
2829
  mixed("strokeAlign")
2786
2830
  ] }),
2787
2831
  /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
@@ -2796,7 +2840,7 @@ function VectorStylePanel({ controller, className }) {
2796
2840
  if (e.target.value !== "custom") setProfile(e.target.value);
2797
2841
  },
2798
2842
  children: [
2799
- import_vector19.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: p.id, children: p.label }, p.id)),
2843
+ import_vector20.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: p.id, children: p.label }, p.id)),
2800
2844
  source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
2801
2845
  ]
2802
2846
  }
@@ -2843,7 +2887,7 @@ function VectorStylePanel({ controller, className }) {
2843
2887
  }
2844
2888
  }
2845
2889
  ),
2846
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Corner kind", className: selectClass14, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector19.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: k, children: import_vector19.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
2890
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Corner kind", className: selectClass14, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector20.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: k, children: import_vector20.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
2847
2891
  mixed("cornerRadius")
2848
2892
  ] }),
2849
2893
  style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "corner-smoothing", title: "Corner smoothing: squircle corners that ease into the curve (0.6 is iOS-like)", children: [
@@ -3537,6 +3581,44 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
3537
3581
  ] })
3538
3582
  ] });
3539
3583
  }
3584
+
3585
+ // src/vector/VectorGeneratePanel.tsx
3586
+ var import_react18 = require("react");
3587
+ var import_vector21 = require("@pixerate/editor/vector");
3588
+ var import_jsx_runtime26 = require("react/jsx-runtime");
3589
+ var buttonClass17 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
3590
+ var selectClass15 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
3591
+ var AS_LABELS = { color: "Traced in colour", threshold: "Traced in one colour", mosaic: "Mosaic", halftone: "Halftone", lowPoly: "Low poly", hatch: "Engraving" };
3592
+ function VectorGeneratePanel({ controller, models, generate, className }) {
3593
+ const usable = (0, import_vector21.vectorArtModels)(models);
3594
+ const [prompt, setPrompt] = (0, import_react18.useState)("");
3595
+ const [model, setModel] = (0, import_react18.useState)("");
3596
+ const [as, setAs] = (0, import_react18.useState)("color");
3597
+ const [busy, setBusy] = (0, import_react18.useState)(false);
3598
+ const [message, setMessage] = (0, import_react18.useState)(null);
3599
+ const chosen = usable.find((m) => m.id === model) ?? usable[0];
3600
+ if (!usable.length) return null;
3601
+ const run = async () => {
3602
+ setBusy(true);
3603
+ setMessage(null);
3604
+ const r = await (0, import_vector21.generateVectorArt)(controller, { prompt, model: chosen.id, as, idempotencyKey: `${Date.now()}-${Math.random().toString(36).slice(2)}` }, { models, generate });
3605
+ setBusy(false);
3606
+ setMessage(r.ok ? null : r.message ?? "Generation failed.");
3607
+ };
3608
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: `space-y-1 ${className ?? ""}`, "data-vector-generate-panel": "", "aria-label": "Generate", children: [
3609
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-1", children: [
3610
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Generate" }),
3611
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("select", { "aria-label": "Generation model", className: selectClass15, value: chosen.id, onChange: (e) => setModel(e.target.value), children: usable.map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: m.id, children: m.name ?? m.id }, m.id)) }),
3612
+ chosen.media === "image" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("select", { "aria-label": "Image to vectors", className: selectClass15, value: as, onChange: (e) => setAs(e.target.value), children: import_vector21.VECTOR_GENERATED_IMAGE_AS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: a, children: AS_LABELS[a] }, a)) })
3613
+ ] }),
3614
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-1", children: [
3615
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "w-16" }),
3616
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("input", { type: "text", "aria-label": "Prompt", placeholder: "Describe the art\u2026", className: "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1.5 text-xs", value: prompt, onChange: (e) => setPrompt(e.target.value), onKeyDown: (e) => e.key === "Enter" && prompt.trim() && !busy && void run() }),
3617
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: buttonClass17, "data-vector-generate-action": "", disabled: !prompt.trim() || busy, onClick: () => void run(), children: busy ? "Generating\u2026" : "Generate" })
3618
+ ] }),
3619
+ message && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-[11px] text-red-600", children: message })
3620
+ ] });
3621
+ }
3540
3622
  // Annotate the CommonJS export names for ESM import in node:
3541
3623
  0 && (module.exports = {
3542
3624
  VectorAppearancePanel,
@@ -3548,6 +3630,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
3548
3630
  VectorEnvelopePanel,
3549
3631
  VectorFilterDefs,
3550
3632
  VectorFramePanel,
3633
+ VectorGeneratePanel,
3551
3634
  VectorGradientAnnotator,
3552
3635
  VectorGradientDefs,
3553
3636
  VectorGradientEditor,
@@ -3571,6 +3654,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
3571
3654
  useVectorEditor,
3572
3655
  useVectorEditorController,
3573
3656
  useVectorEditorState,
3574
- useVectorEffectsTools
3657
+ useVectorEffectsTools,
3658
+ useVectorGenerationTools
3575
3659
  });
3576
3660
  //# sourceMappingURL=index.cjs.map