@pixerate/editor-react 0.82.0 → 0.83.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.
@@ -42,6 +42,7 @@ __export(vector_exports, {
42
42
  VectorGradientAnnotator: () => VectorGradientAnnotator,
43
43
  VectorGradientDefs: () => VectorGradientDefs,
44
44
  VectorGradientEditor: () => VectorGradientEditor,
45
+ VectorLensPanel: () => VectorLensPanel,
45
46
  VectorMaskPanel: () => VectorMaskPanel,
46
47
  VectorMaskedNodes: () => VectorMaskedNodes,
47
48
  VectorProviderEffectsPanel: () => VectorProviderEffectsPanel,
@@ -830,7 +831,7 @@ function VectorCanvas({
830
831
 
831
832
  // src/vector/VectorToolbar.tsx
832
833
  var import_react10 = __toESM(require("react"), 1);
833
- var import_vector16 = require("@pixerate/editor/vector");
834
+ var import_vector17 = require("@pixerate/editor/vector");
834
835
 
835
836
  // src/vector/VectorEffectsPanel.tsx
836
837
  var import_vector4 = require("@pixerate/editor/vector");
@@ -2081,16 +2082,69 @@ function VectorSymmetryPanel({ controller, className }) {
2081
2082
  ] });
2082
2083
  }
2083
2084
 
2084
- // src/vector/VectorGradientEditor.tsx
2085
+ // src/vector/VectorLensPanel.tsx
2085
2086
  var import_vector15 = require("@pixerate/editor/vector");
2086
2087
  var import_jsx_runtime15 = require("react/jsx-runtime");
2087
2088
  var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2088
- var numberClass9 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
2089
+ var numberClass9 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
2090
+ function VectorLensPanel({ controller, className }) {
2091
+ const state = useVectorEditorState(controller);
2092
+ const path = state.selection.map((id) => controller.getNode(id)).find((n) => n?.type === "path" && n.subpaths.some((sp) => sp.closed) && !n.connector);
2093
+ if (!path) return null;
2094
+ const lens = path.lens ?? null;
2095
+ const spec = lens ? import_vector15.VECTOR_LENS_SPECS[lens.type] : null;
2096
+ const ids = [path.id];
2097
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-lens-panel": "", "aria-label": "Lens", children: [
2098
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2099
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Lens" }),
2100
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2101
+ "select",
2102
+ {
2103
+ "aria-label": "Lens type",
2104
+ className: selectClass10,
2105
+ value: lens?.type ?? "",
2106
+ onChange: (e) => e.target.value ? controller.setLens({ type: e.target.value }, { ids }) : controller.setLens(null, { ids }),
2107
+ children: [
2108
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "", children: "None" }),
2109
+ import_vector15.VECTOR_LENS_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: t, children: import_vector15.VECTOR_LENS_LABELS[t] }, t))
2110
+ ]
2111
+ }
2112
+ )
2113
+ ] }),
2114
+ lens && spec && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2115
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16" }),
2116
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2117
+ "input",
2118
+ {
2119
+ type: "number",
2120
+ "aria-label": "Lens amount",
2121
+ title: `Amount: ${spec.unit} (${spec.min} to ${spec.max})`,
2122
+ className: numberClass9,
2123
+ min: spec.min,
2124
+ max: spec.max,
2125
+ step: lens.type === "magnify" ? 0.1 : 1,
2126
+ value: lens.amount,
2127
+ onChange: (e) => {
2128
+ const v = parseFloat(e.target.value);
2129
+ if (Number.isFinite(v)) controller.setLens({ amount: Math.min(spec.max, Math.max(spec.min, v)) }, { ids, merge: `lens-amount-${path.id}` });
2130
+ }
2131
+ }
2132
+ ),
2133
+ spec.color !== null && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "color", "aria-label": "Lens colour", title: "Lens colour", className: "h-7 w-9 rounded border border-border bg-background", value: lens.color ?? spec.color, onChange: (e) => controller.setLens({ color: e.target.value }, { ids, merge: `lens-color-${path.id}` }) })
2134
+ ] })
2135
+ ] });
2136
+ }
2137
+
2138
+ // src/vector/VectorGradientEditor.tsx
2139
+ var import_vector16 = require("@pixerate/editor/vector");
2140
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2141
+ var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2142
+ var numberClass10 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
2089
2143
  var buttonClass13 = "inline-flex h-7 min-w-7 items-center justify-center rounded border border-border bg-background px-1.5 text-xs text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2090
2144
  var percent = (v) => Math.round(v * 1e3) / 10;
2091
2145
  function VectorGradientEditor({ controller, className }) {
2092
2146
  const state = useVectorEditorState(controller);
2093
- const ed = (0, import_vector15.getVectorGradientEditor)(state);
2147
+ const ed = (0, import_vector16.getVectorGradientEditor)(state);
2094
2148
  if (!ed) return null;
2095
2149
  const g = ed.gradient;
2096
2150
  const sel = ed.selected;
@@ -2098,26 +2152,26 @@ function VectorGradientEditor({ controller, className }) {
2098
2152
  const setType = (value) => {
2099
2153
  if (value === "solid") {
2100
2154
  const first = ed.stops[0];
2101
- controller.setStyle({ [ed.target]: (0, import_vector15.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
2155
+ controller.setStyle({ [ed.target]: (0, import_vector16.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
2102
2156
  } else controller.setGradient({ type: value });
2103
2157
  };
2104
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
2105
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2106
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
2107
- ["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
2108
- ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2158
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
2159
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2160
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
2161
+ ["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass13, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
2162
+ ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2109
2163
  ] }),
2110
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2111
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
2112
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("select", { "aria-label": "Gradient type", className: selectClass10, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
2113
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "solid", children: "Solid" }),
2114
- import_vector15.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: t, children: import_vector15.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
2164
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2165
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
2166
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("select", { "aria-label": "Gradient type", className: selectClass11, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
2167
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "solid", children: "Solid" }),
2168
+ import_vector16.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: t, children: import_vector16.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
2115
2169
  ] }),
2116
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
2170
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass13, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
2117
2171
  ] }),
2118
- g && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2119
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
2120
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2172
+ g && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2173
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
2174
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2121
2175
  "div",
2122
2176
  {
2123
2177
  role: "button",
@@ -2131,7 +2185,7 @@ function VectorGradientEditor({ controller, className }) {
2131
2185
  }
2132
2186
  }
2133
2187
  ),
2134
- ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2188
+ ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2135
2189
  "button",
2136
2190
  {
2137
2191
  type: "button",
@@ -2145,21 +2199,21 @@ function VectorGradientEditor({ controller, className }) {
2145
2199
  s.index
2146
2200
  ))
2147
2201
  ] }),
2148
- sel && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
2149
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2202
+ sel && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
2203
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2150
2204
  "input",
2151
2205
  {
2152
2206
  type: "color",
2153
2207
  "aria-label": "Stop colour",
2154
2208
  className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
2155
- value: (0, import_vector15.vectorPaintToHex)(sel.color) ?? "#000000",
2209
+ value: (0, import_vector16.vectorPaintToHex)(sel.color) ?? "#000000",
2156
2210
  onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
2157
2211
  onBlur: end
2158
2212
  }
2159
2213
  ),
2160
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2214
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2161
2215
  "Opacity",
2162
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2216
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2163
2217
  "input",
2164
2218
  {
2165
2219
  type: "number",
@@ -2167,7 +2221,7 @@ function VectorGradientEditor({ controller, className }) {
2167
2221
  max: 100,
2168
2222
  step: 5,
2169
2223
  "aria-label": "Stop opacity",
2170
- className: numberClass9,
2224
+ className: numberClass10,
2171
2225
  value: percent(sel.opacity ?? 1),
2172
2226
  onChange: (e) => {
2173
2227
  const n = parseFloat(e.target.value);
@@ -2176,9 +2230,9 @@ function VectorGradientEditor({ controller, className }) {
2176
2230
  }
2177
2231
  )
2178
2232
  ] }),
2179
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2233
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2180
2234
  "At",
2181
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2235
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2182
2236
  "input",
2183
2237
  {
2184
2238
  type: "number",
@@ -2186,7 +2240,7 @@ function VectorGradientEditor({ controller, className }) {
2186
2240
  max: 100,
2187
2241
  step: 1,
2188
2242
  "aria-label": "Stop position",
2189
- className: numberClass9,
2243
+ className: numberClass10,
2190
2244
  value: percent(sel.offset),
2191
2245
  onChange: (e) => {
2192
2246
  const n = parseFloat(e.target.value);
@@ -2195,9 +2249,9 @@ function VectorGradientEditor({ controller, className }) {
2195
2249
  }
2196
2250
  )
2197
2251
  ] }),
2198
- !sel.last && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2252
+ !sel.last && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2199
2253
  "Midpoint",
2200
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2254
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2201
2255
  "input",
2202
2256
  {
2203
2257
  type: "number",
@@ -2205,7 +2259,7 @@ function VectorGradientEditor({ controller, className }) {
2205
2259
  max: 95,
2206
2260
  step: 1,
2207
2261
  "aria-label": "Stop midpoint",
2208
- className: numberClass9,
2262
+ className: numberClass10,
2209
2263
  value: percent(sel.midpoint ?? 0.5),
2210
2264
  onChange: (e) => {
2211
2265
  const n = parseFloat(e.target.value);
@@ -2214,15 +2268,15 @@ function VectorGradientEditor({ controller, className }) {
2214
2268
  }
2215
2269
  )
2216
2270
  ] }),
2217
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
2271
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass13, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
2218
2272
  ] }),
2219
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2220
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "Colours" }),
2221
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass10, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector15.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: i, children: import_vector15.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
2273
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2274
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Colours" }),
2275
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass11, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector16.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: i, children: import_vector16.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
2222
2276
  ] }),
2223
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2224
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "Smooth" }),
2225
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2277
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2278
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Smooth" }),
2279
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2226
2280
  "input",
2227
2281
  {
2228
2282
  type: "range",
@@ -2238,26 +2292,26 @@ function VectorGradientEditor({ controller, className }) {
2238
2292
  }
2239
2293
  )
2240
2294
  ] }),
2241
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2242
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "Spread" }),
2243
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Gradient spread", className: selectClass10, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector15.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: sp, children: import_vector15.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
2295
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2296
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Spread" }),
2297
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Gradient spread", className: selectClass11, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector16.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: sp, children: import_vector16.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
2244
2298
  ] }),
2245
- ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2246
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "On stroke" }),
2247
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass10, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector15.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: m, children: import_vector15.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
2299
+ ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2300
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "On stroke" }),
2301
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass11, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector16.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: m, children: import_vector16.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
2248
2302
  ] })
2249
2303
  ] })
2250
2304
  ] });
2251
2305
  }
2252
2306
 
2253
2307
  // src/vector/VectorToolbar.tsx
2254
- var import_jsx_runtime16 = require("react/jsx-runtime");
2308
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2255
2309
  var VECTOR_SNAP_TITLE = "Snap to objects";
2256
2310
  var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
2257
2311
  var buttonClass14 = "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";
2258
2312
  function VectorToolbar({
2259
2313
  controller,
2260
- tools = import_vector16.VECTOR_TOOLS,
2314
+ tools = import_vector17.VECTOR_TOOLS,
2261
2315
  showHistory = true,
2262
2316
  showArrange = true,
2263
2317
  showSnap = true,
@@ -2271,31 +2325,31 @@ function VectorToolbar({
2271
2325
  const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
2272
2326
  const editing = state.editing;
2273
2327
  const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
2274
- const maskSelected = state.selection.some((id) => (0, import_vector16.isVectorMaskGroup)(controller.getNode(id)));
2328
+ const maskSelected = state.selection.some((id) => (0, import_vector17.isVectorMaskGroup)(controller.getNode(id)));
2275
2329
  const [live, setLive] = import_react10.default.useState(false);
2276
2330
  const booleanDisabled = live ? count < 1 : count < 2;
2277
- const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass14, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
2278
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
2279
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2331
+ const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass14, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
2332
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
2333
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2280
2334
  "button",
2281
2335
  {
2282
2336
  type: "button",
2283
2337
  "data-vector-tool": tool,
2284
2338
  className: buttonClass14,
2285
2339
  "aria-pressed": state.tool === tool,
2286
- title: `${(0, import_vector16.vectorToolLabel)(tool)} (${import_vector16.VECTOR_TOOL_SHORTCUTS[tool]})`,
2287
- "aria-label": (0, import_vector16.vectorToolLabel)(tool),
2340
+ title: `${(0, import_vector17.vectorToolLabel)(tool)} (${import_vector17.VECTOR_TOOL_SHORTCUTS[tool]})`,
2341
+ "aria-label": (0, import_vector17.vectorToolLabel)(tool),
2288
2342
  onClick: () => controller.setTool(tool),
2289
- children: import_vector16.VECTOR_TOOL_GLYPHS[tool]
2343
+ children: import_vector17.VECTOR_TOOL_GLYPHS[tool]
2290
2344
  },
2291
2345
  tool
2292
2346
  )) }),
2293
- showHistory && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
2347
+ showHistory && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
2294
2348
  act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
2295
2349
  act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
2296
2350
  ] }),
2297
- showSnap && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
2298
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2351
+ showSnap && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
2352
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2299
2353
  "button",
2300
2354
  {
2301
2355
  type: "button",
@@ -2308,18 +2362,18 @@ function VectorToolbar({
2308
2362
  children: "Snap"
2309
2363
  }
2310
2364
  ),
2311
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2365
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2312
2366
  "select",
2313
2367
  {
2314
2368
  "data-vector-polar": "",
2315
2369
  "aria-label": "Polar tracking increment",
2316
2370
  title: "Polar tracking: the angles drawn points snap to from where they leave",
2317
2371
  className: "h-8 rounded-md border border-border bg-background px-1 text-xs",
2318
- value: String((0, import_vector16.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
2319
- onChange: (e) => controller.setSnap({ angles: (0, import_vector16.vectorPolarAngles)(Number(e.target.value)) }),
2372
+ value: String((0, import_vector17.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
2373
+ onChange: (e) => controller.setSnap({ angles: (0, import_vector17.vectorPolarAngles)(Number(e.target.value)) }),
2320
2374
  children: [
2321
- (0, import_vector16.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "", children: "Custom" }),
2322
- [90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("option", { value: n, children: [
2375
+ (0, import_vector17.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "", children: "Custom" }),
2376
+ [90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("option", { value: n, children: [
2323
2377
  n,
2324
2378
  "\xB0"
2325
2379
  ] }, n))
@@ -2327,8 +2381,8 @@ function VectorToolbar({
2327
2381
  }
2328
2382
  )
2329
2383
  ] }),
2330
- showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
2331
- import_vector16.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2384
+ showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
2385
+ import_vector17.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2332
2386
  "button",
2333
2387
  {
2334
2388
  type: "button",
@@ -2342,7 +2396,7 @@ function VectorToolbar({
2342
2396
  },
2343
2397
  a.id
2344
2398
  )),
2345
- import_vector16.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2399
+ import_vector17.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2346
2400
  "button",
2347
2401
  {
2348
2402
  type: "button",
@@ -2356,9 +2410,9 @@ function VectorToolbar({
2356
2410
  },
2357
2411
  t.key
2358
2412
  )),
2359
- state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2413
+ state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2360
2414
  "Smoothing",
2361
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2415
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2362
2416
  "input",
2363
2417
  {
2364
2418
  type: "range",
@@ -2372,9 +2426,9 @@ function VectorToolbar({
2372
2426
  }
2373
2427
  )
2374
2428
  ] }),
2375
- state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2429
+ state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2376
2430
  "Size",
2377
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2431
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2378
2432
  "input",
2379
2433
  {
2380
2434
  type: "number",
@@ -2390,7 +2444,7 @@ function VectorToolbar({
2390
2444
  }
2391
2445
  )
2392
2446
  ] }),
2393
- state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2447
+ state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2394
2448
  "button",
2395
2449
  {
2396
2450
  type: "button",
@@ -2399,12 +2453,12 @@ function VectorToolbar({
2399
2453
  "aria-pressed": editing.fillGap > 0,
2400
2454
  title: "Close small gaps between path ends when filling",
2401
2455
  "aria-label": "Close gaps",
2402
- onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector16.VECTOR_FILL_GAP }),
2456
+ onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector17.VECTOR_FILL_GAP }),
2403
2457
  children: "Gaps"
2404
2458
  }
2405
2459
  )
2406
2460
  ] }),
2407
- showDistort && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2461
+ showDistort && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2408
2462
  "button",
2409
2463
  {
2410
2464
  type: "button",
@@ -2417,10 +2471,10 @@ function VectorToolbar({
2417
2471
  children: "Distort"
2418
2472
  }
2419
2473
  ) }),
2420
- showBlend && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorBlendControls, { controller }),
2421
- showArrange && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2422
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
2423
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2474
+ showBlend && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorBlendControls, { controller }),
2475
+ showArrange && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2476
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
2477
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2424
2478
  "button",
2425
2479
  {
2426
2480
  type: "button",
@@ -2442,7 +2496,7 @@ function VectorToolbar({
2442
2496
  act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
2443
2497
  act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
2444
2498
  ] }),
2445
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector16.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2499
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector17.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2446
2500
  "button",
2447
2501
  {
2448
2502
  type: "button",
@@ -2456,7 +2510,7 @@ function VectorToolbar({
2456
2510
  },
2457
2511
  a.id
2458
2512
  )) }),
2459
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
2513
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
2460
2514
  act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
2461
2515
  act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
2462
2516
  act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
@@ -2471,22 +2525,22 @@ function VectorToolbar({
2471
2525
  }
2472
2526
  function VectorBlendControls({ controller }) {
2473
2527
  const state = useVectorEditorState(controller);
2474
- const blend = (0, import_vector16.getVectorBlendControls)(state);
2528
+ const blend = (0, import_vector17.getVectorBlendControls)(state);
2475
2529
  const o = blend.options;
2476
2530
  const selected = blend.ids.length > 0;
2477
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
2478
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass14, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
2479
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2531
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
2532
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass14, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
2533
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2480
2534
  "select",
2481
2535
  {
2482
2536
  "aria-label": "Blend spacing",
2483
2537
  className: "h-7 rounded border border-border bg-background px-1 text-xs",
2484
2538
  value: o.spacing,
2485
- onChange: (e) => (0, import_vector16.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
2486
- children: import_vector16.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: sp, children: import_vector16.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
2539
+ onChange: (e) => (0, import_vector17.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
2540
+ children: import_vector17.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: sp, children: import_vector17.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
2487
2541
  }
2488
2542
  ),
2489
- o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2543
+ o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2490
2544
  "input",
2491
2545
  {
2492
2546
  type: "number",
@@ -2498,11 +2552,11 @@ function VectorBlendControls({ controller }) {
2498
2552
  onChange: (e) => {
2499
2553
  const n = parseFloat(e.target.value);
2500
2554
  if (!Number.isFinite(n) || n <= 0) return;
2501
- (0, import_vector16.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
2555
+ (0, import_vector17.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
2502
2556
  }
2503
2557
  }
2504
2558
  ),
2505
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2559
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2506
2560
  "button",
2507
2561
  {
2508
2562
  type: "button",
@@ -2511,11 +2565,11 @@ function VectorBlendControls({ controller }) {
2511
2565
  "aria-pressed": o.orientToSpine,
2512
2566
  title: "Orient steps to the spine",
2513
2567
  "aria-label": "Orient to spine",
2514
- onClick: () => (0, import_vector16.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
2568
+ onClick: () => (0, import_vector17.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
2515
2569
  children: "\u293F"
2516
2570
  }
2517
2571
  ),
2518
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2572
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2519
2573
  "button",
2520
2574
  {
2521
2575
  type: "button",
@@ -2528,15 +2582,15 @@ function VectorBlendControls({ controller }) {
2528
2582
  children: "\u2307"
2529
2583
  }
2530
2584
  ),
2531
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass14, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
2532
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass14, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
2585
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass14, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
2586
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass14, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
2533
2587
  ] });
2534
2588
  }
2535
- var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2536
- var numberClass10 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
2589
+ var selectClass12 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2590
+ var numberClass11 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
2537
2591
  function VectorStylePanel({ controller, className }) {
2538
2592
  const state = useVectorEditorState(controller);
2539
- const style = (0, import_vector16.getVectorSelectionStyle)(state);
2593
+ const style = (0, import_vector17.getVectorSelectionStyle)(state);
2540
2594
  const d = state.defaults;
2541
2595
  const source = style ?? {
2542
2596
  fill: d.fill ?? null,
@@ -2549,7 +2603,7 @@ function VectorStylePanel({ controller, className }) {
2549
2603
  arrowAlign: d.arrowAlign ?? "extend",
2550
2604
  startArrowScale: d.startArrowScale ?? 1,
2551
2605
  endArrowScale: d.endArrowScale ?? 1,
2552
- widthProfile: (0, import_vector16.widthProfilePresetId)(d.strokeWidthProfile),
2606
+ widthProfile: (0, import_vector17.widthProfilePresetId)(d.strokeWidthProfile),
2553
2607
  cornerRadius: d.cornerRadius,
2554
2608
  cornerKind: d.cornerKind ?? "round",
2555
2609
  cornerSmoothing: 0,
@@ -2563,19 +2617,19 @@ function VectorStylePanel({ controller, className }) {
2563
2617
  };
2564
2618
  const setProfile = (id) => {
2565
2619
  if (style) controller.setWidthProfile(id);
2566
- else controller.setDefaults({ strokeWidthProfile: (0, import_vector16.widthProfilePreset)(id)?.length ? (0, import_vector16.widthProfilePreset)(id) : null });
2620
+ else controller.setDefaults({ strokeWidthProfile: (0, import_vector17.widthProfilePreset)(id)?.length ? (0, import_vector17.widthProfilePreset)(id) : null });
2567
2621
  };
2568
- const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
2622
+ const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
2569
2623
  const arrowRow = (end, label) => {
2570
2624
  const key = end === "start" ? "startArrow" : "endArrow";
2571
2625
  const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
2572
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2573
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
2574
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass11, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
2575
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "", children: "None" }),
2576
- import_vector16.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: h, children: import_vector16.VECTOR_ARROWHEAD_LABELS[h] }, h))
2626
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2627
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
2628
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass12, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
2629
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "", children: "None" }),
2630
+ import_vector17.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: h, children: import_vector17.VECTOR_ARROWHEAD_LABELS[h] }, h))
2577
2631
  ] }),
2578
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2632
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2579
2633
  "input",
2580
2634
  {
2581
2635
  type: "number",
@@ -2583,7 +2637,7 @@ function VectorStylePanel({ controller, className }) {
2583
2637
  step: 0.25,
2584
2638
  "aria-label": `${label} arrowhead scale`,
2585
2639
  title: "Scale (\xD7 stroke width)",
2586
- className: numberClass10,
2640
+ className: numberClass11,
2587
2641
  value: source[scaleKey],
2588
2642
  onChange: (e) => {
2589
2643
  const n = parseFloat(e.target.value);
@@ -2599,14 +2653,14 @@ function VectorStylePanel({ controller, className }) {
2599
2653
  };
2600
2654
  const paintRow = (key, label) => {
2601
2655
  const paint = source[key];
2602
- const hex = (0, import_vector16.vectorPaintToHex)(paint);
2656
+ const hex = (0, import_vector17.vectorPaintToHex)(paint);
2603
2657
  const on = paint !== null && paint !== "none";
2604
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2605
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
2606
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
2658
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2659
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
2660
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
2607
2661
  label
2608
2662
  ] }),
2609
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2663
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2610
2664
  "input",
2611
2665
  {
2612
2666
  type: "color",
@@ -2617,18 +2671,18 @@ function VectorStylePanel({ controller, className }) {
2617
2671
  onChange: (e) => apply({ [key]: e.target.value })
2618
2672
  }
2619
2673
  ),
2620
- on && !hex && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
2621
- style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2674
+ on && !hex && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
2675
+ style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2622
2676
  ] });
2623
2677
  };
2624
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
2625
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
2678
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
2679
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
2626
2680
  paintRow("fill", "Fill"),
2627
2681
  paintRow("stroke", "Stroke"),
2628
- style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorGradientEditor, { controller }),
2629
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2630
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Width" }),
2631
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2682
+ style && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorGradientEditor, { controller }),
2683
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2684
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Width" }),
2685
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2632
2686
  "input",
2633
2687
  {
2634
2688
  type: "number",
@@ -2644,29 +2698,29 @@ function VectorStylePanel({ controller, className }) {
2644
2698
  }
2645
2699
  )
2646
2700
  ] }),
2647
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
2648
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Align" }),
2649
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass11, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector16.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: a, children: import_vector16.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
2701
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
2702
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Align" }),
2703
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass12, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector17.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: a, children: import_vector17.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
2650
2704
  mixed("strokeAlign")
2651
2705
  ] }),
2652
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
2653
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Profile" }),
2654
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2706
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
2707
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Profile" }),
2708
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2655
2709
  "select",
2656
2710
  {
2657
2711
  "aria-label": "Width profile",
2658
- className: selectClass11,
2712
+ className: selectClass12,
2659
2713
  value: source.widthProfile,
2660
2714
  onChange: (e) => {
2661
2715
  if (e.target.value !== "custom") setProfile(e.target.value);
2662
2716
  },
2663
2717
  children: [
2664
- import_vector16.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: p.id, children: p.label }, p.id)),
2665
- source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
2718
+ import_vector17.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: p.id, children: p.label }, p.id)),
2719
+ source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
2666
2720
  ]
2667
2721
  }
2668
2722
  ),
2669
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2723
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2670
2724
  "button",
2671
2725
  {
2672
2726
  type: "button",
@@ -2680,27 +2734,27 @@ function VectorStylePanel({ controller, className }) {
2680
2734
  ),
2681
2735
  mixed("widthProfile")
2682
2736
  ] }),
2683
- source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2737
+ source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2684
2738
  arrowRow("start", "Start"),
2685
2739
  arrowRow("end", "End"),
2686
- (source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
2687
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Heads" }),
2688
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass11, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
2689
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "extend", children: "Tip past end" }),
2690
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "tip", children: "Tip at end" })
2740
+ (source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
2741
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Heads" }),
2742
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass12, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
2743
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "extend", children: "Tip past end" }),
2744
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "tip", children: "Tip at end" })
2691
2745
  ] })
2692
2746
  ] })
2693
2747
  ] }),
2694
- source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
2695
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
2696
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2748
+ source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
2749
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
2750
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2697
2751
  "input",
2698
2752
  {
2699
2753
  type: "number",
2700
2754
  min: 0,
2701
2755
  step: 1,
2702
2756
  "aria-label": "Corner radius",
2703
- className: numberClass10,
2757
+ className: numberClass11,
2704
2758
  value: Math.round(source.cornerRadius * 100) / 100,
2705
2759
  onChange: (e) => {
2706
2760
  const n = parseFloat(e.target.value);
@@ -2708,12 +2762,12 @@ function VectorStylePanel({ controller, className }) {
2708
2762
  }
2709
2763
  }
2710
2764
  ),
2711
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Corner kind", className: selectClass11, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector16.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: k, children: import_vector16.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
2765
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Corner kind", className: selectClass12, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector17.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: k, children: import_vector17.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
2712
2766
  mixed("cornerRadius")
2713
2767
  ] }),
2714
- style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.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: [
2715
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Smoothing" }),
2716
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2768
+ style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.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: [
2769
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Smoothing" }),
2770
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2717
2771
  "input",
2718
2772
  {
2719
2773
  type: "range",
@@ -2728,9 +2782,9 @@ function VectorStylePanel({ controller, className }) {
2728
2782
  }
2729
2783
  )
2730
2784
  ] }),
2731
- style && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2732
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Opacity" }),
2733
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2785
+ style && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2786
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Opacity" }),
2787
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2734
2788
  "input",
2735
2789
  {
2736
2790
  type: "range",
@@ -2744,18 +2798,19 @@ function VectorStylePanel({ controller, className }) {
2744
2798
  }
2745
2799
  )
2746
2800
  ] }),
2747
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorTextPanel, { controller }),
2748
- style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorAppearancePanel, { controller }),
2749
- style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorEffectsPanel, { controller }),
2750
- style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorEnvelopePanel, { controller }),
2751
- style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorMaskPanel, { controller }),
2752
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorFramePanel, { controller }),
2753
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorConnectorPanel, { controller }),
2754
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorShadingPanel, { controller }),
2755
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorSymmetryPanel, { controller }),
2756
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorTracePanel, { controller }),
2757
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorConstraintsPanel, { controller }),
2758
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorSymbolsPanel, { controller })
2801
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorTextPanel, { controller }),
2802
+ style && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorAppearancePanel, { controller }),
2803
+ style && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorEffectsPanel, { controller }),
2804
+ style && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorEnvelopePanel, { controller }),
2805
+ style && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorMaskPanel, { controller }),
2806
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorFramePanel, { controller }),
2807
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorConnectorPanel, { controller }),
2808
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorShadingPanel, { controller }),
2809
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorSymmetryPanel, { controller }),
2810
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorLensPanel, { controller }),
2811
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorTracePanel, { controller }),
2812
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorConstraintsPanel, { controller }),
2813
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorSymbolsPanel, { controller })
2759
2814
  ] });
2760
2815
  }
2761
2816
 
@@ -2787,7 +2842,7 @@ function useEffectDescription(provider, effect) {
2787
2842
  // src/effects/EffectThumbnail.tsx
2788
2843
  var import_react12 = require("react");
2789
2844
  var import_effects = require("@pixerate/editor/effects");
2790
- var import_jsx_runtime17 = require("react/jsx-runtime");
2845
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2791
2846
  function EffectThumbnail({ provider, effect, width = 96, height = 54, className = "" }) {
2792
2847
  const ref = (0, import_react12.useRef)(null);
2793
2848
  const [failed, setFailed] = (0, import_react12.useState)(effect.kind === "motion");
@@ -2806,13 +2861,13 @@ function EffectThumbnail({ provider, effect, width = 96, height = 54, className
2806
2861
  live = false;
2807
2862
  };
2808
2863
  }, [provider, effect, width, height]);
2809
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2864
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2810
2865
  "div",
2811
2866
  {
2812
2867
  className: `relative overflow-hidden rounded border border-border bg-[repeating-conic-gradient(#8884_0_25%,transparent_0_50%)] bg-[length:12px_12px] ${className}`,
2813
2868
  style: { aspectRatio: `${width} / ${height}` },
2814
2869
  "data-effect-thumbnail": effect.id,
2815
- children: failed ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] text-muted-foreground", children: effect.kind === "motion" ? "Motion" : "No preview" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("canvas", { ref, width, height, className: "h-full w-full", "aria-hidden": "true" })
2870
+ children: failed ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] text-muted-foreground", children: effect.kind === "motion" ? "Motion" : "No preview" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("canvas", { ref, width, height, className: "h-full w-full", "aria-hidden": "true" })
2816
2871
  }
2817
2872
  );
2818
2873
  }
@@ -2820,7 +2875,7 @@ function EffectThumbnail({ provider, effect, width = 96, height = 54, className
2820
2875
  // src/effects/EffectsBrowser.tsx
2821
2876
  var import_react13 = require("react");
2822
2877
  var import_effects2 = require("@pixerate/editor/effects");
2823
- var import_jsx_runtime18 = require("react/jsx-runtime");
2878
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2824
2879
  function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, title = "Effects", className = "" }) {
2825
2880
  const [all, setAll] = (0, import_react13.useState)([]);
2826
2881
  const [query, setQuery] = (0, import_react13.useState)("");
@@ -2851,11 +2906,11 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
2851
2906
  const categories = (0, import_react13.useMemo)(() => [...new Set(all.filter(allowed).map((e) => e.category))], [all, uses, kinds]);
2852
2907
  const shown = found.filter(allowed);
2853
2908
  if (!provider)
2854
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `rounded-md border border-dashed border-border p-3 text-xs text-muted-foreground ${className}`, "data-effects-browser": "", "data-effects-unavailable": "", children: "No effects provider is registered, so effects cannot be added. Effects already in the document are kept." });
2855
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: `flex flex-col gap-2 ${className}`, "data-effects-browser": "", "aria-label": "Effects browser", children: [
2856
- title && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: "text-xs font-semibold", children: title }),
2857
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
2858
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2909
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `rounded-md border border-dashed border-border p-3 text-xs text-muted-foreground ${className}`, "data-effects-browser": "", "data-effects-unavailable": "", children: "No effects provider is registered, so effects cannot be added. Effects already in the document are kept." });
2910
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: `flex flex-col gap-2 ${className}`, "data-effects-browser": "", "aria-label": "Effects browser", children: [
2911
+ title && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "text-xs font-semibold", children: title }),
2912
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
2913
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2859
2914
  "input",
2860
2915
  {
2861
2916
  type: "search",
@@ -2866,17 +2921,17 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
2866
2921
  onChange: (e) => setQuery(e.currentTarget.value)
2867
2922
  }
2868
2923
  ),
2869
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Category", value: category, onChange: (e) => setCategory(e.currentTarget.value), children: [
2870
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "All categories" }),
2871
- categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: c, children: c }, c))
2924
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Category", value: category, onChange: (e) => setCategory(e.currentTarget.value), children: [
2925
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "All categories" }),
2926
+ categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: c, children: c }, c))
2872
2927
  ] }),
2873
- uses && uses.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Use", value: use, onChange: (e) => setUse(e.currentTarget.value), children: [
2874
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "Any use" }),
2875
- uses.map((u) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: u, children: import_effects2.EFFECT_USE_LABELS[u] }, u))
2928
+ uses && uses.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Use", value: use, onChange: (e) => setUse(e.currentTarget.value), children: [
2929
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "Any use" }),
2930
+ uses.map((u) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: u, children: import_effects2.EFFECT_USE_LABELS[u] }, u))
2876
2931
  ] })
2877
2932
  ] }),
2878
- error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: error }),
2879
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ul", { className: "grid max-h-96 grid-cols-[repeat(auto-fill,minmax(6.5rem,1fr))] gap-1.5 overflow-y-auto", role: "list", children: shown.map((e) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2933
+ error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: error }),
2934
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "grid max-h-96 grid-cols-[repeat(auto-fill,minmax(6.5rem,1fr))] gap-1.5 overflow-y-auto", role: "list", children: shown.map((e) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2880
2935
  "button",
2881
2936
  {
2882
2937
  type: "button",
@@ -2885,13 +2940,13 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
2885
2940
  "data-effect-id": e.id,
2886
2941
  onClick: () => onPick(e),
2887
2942
  children: [
2888
- thumbnails && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EffectThumbnail, { provider, effect: e }),
2889
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-[11px] font-medium", children: e.name }),
2890
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-[10px] text-muted-foreground", children: e.uses.map((u) => import_effects2.EFFECT_USE_LABELS[u]).join(" \xB7 ") })
2943
+ thumbnails && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EffectThumbnail, { provider, effect: e }),
2944
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate text-[11px] font-medium", children: e.name }),
2945
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate text-[10px] text-muted-foreground", children: e.uses.map((u) => import_effects2.EFFECT_USE_LABELS[u]).join(" \xB7 ") })
2891
2946
  ]
2892
2947
  }
2893
2948
  ) }, e.id)) }),
2894
- !shown.length && !error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects match." })
2949
+ !shown.length && !error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects match." })
2895
2950
  ] });
2896
2951
  }
2897
2952
 
@@ -2903,7 +2958,7 @@ var import_parameters2 = require("@pixerate/editor/parameters");
2903
2958
  // src/parameters/fields.tsx
2904
2959
  var import_react14 = require("react");
2905
2960
  var import_parameters = require("@pixerate/editor/parameters");
2906
- var import_jsx_runtime19 = require("react/jsx-runtime");
2961
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2907
2962
  var parameterInputClass = "h-7 w-full min-w-0 rounded-md border border-input bg-background px-2 text-xs text-foreground tabular-nums focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50";
2908
2963
  var parameterButtonClass = "inline-flex h-7 items-center justify-center gap-1 rounded-md border border-input bg-background px-2 text-xs text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50";
2909
2964
  var rangeClass = "h-4 w-full min-w-0 flex-1 cursor-pointer accent-primary disabled:cursor-not-allowed disabled:opacity-50";
@@ -2927,7 +2982,7 @@ function ParameterCommitInput({ value, onCommit, multiline, className, onKeyDown
2927
2982
  onKeyDown: keyDown,
2928
2983
  ...rest
2929
2984
  };
2930
- return multiline ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("textarea", { ...props, className: `${props.className} h-auto min-h-[3.5rem] py-1` }, value) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "text", ...props }, value);
2985
+ return multiline ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("textarea", { ...props, className: `${props.className} h-auto min-h-[3.5rem] py-1` }, value) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { type: "text", ...props }, value);
2931
2986
  }
2932
2987
  var plainNumber = (field, value) => (0, import_parameters.formatParameterNumber)({ ...field, unit: void 0 }, value);
2933
2988
  function ParameterNumberInput({
@@ -2938,8 +2993,8 @@ function ParameterNumberInput({
2938
2993
  id,
2939
2994
  "aria-label": ariaLabel
2940
2995
  }) {
2941
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
2942
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2996
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
2997
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2943
2998
  ParameterCommitInput,
2944
2999
  {
2945
3000
  id,
@@ -2961,7 +3016,7 @@ function ParameterNumberInput({
2961
3016
  }
2962
3017
  }
2963
3018
  ),
2964
- field.unit && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground", children: field.unit })
3019
+ field.unit && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground", children: field.unit })
2965
3020
  ] });
2966
3021
  }
2967
3022
  function ParameterSlider(props) {
@@ -2972,10 +3027,10 @@ function ParameterSlider(props) {
2972
3027
  dragging.current = false;
2973
3028
  onGestureEnd?.();
2974
3029
  };
2975
- if (!(0, import_parameters.isSliderField)(field)) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterNumberInput, { ...props });
3030
+ if (!(0, import_parameters.isSliderField)(field)) return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterNumberInput, { ...props });
2976
3031
  const step = (0, import_parameters.parameterStep)(field);
2977
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
2978
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3032
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2", children: [
3033
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2979
3034
  "input",
2980
3035
  {
2981
3036
  type: "range",
@@ -2998,11 +3053,11 @@ function ParameterSlider(props) {
2998
3053
  onChange: (e) => onChange((0, import_parameters.clampParameterNumber)(field, Number(e.target.value)))
2999
3054
  }
3000
3055
  ),
3001
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterNumberInput, { ...props, id: props.id, "aria-label": `${(0, import_parameters.parameterLabel)(field)} value` }) })
3056
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterNumberInput, { ...props, id: props.id, "aria-label": `${(0, import_parameters.parameterLabel)(field)} value` }) })
3002
3057
  ] });
3003
3058
  }
3004
3059
  function ParameterToggle({ field, value, onChange, disabled, id }) {
3005
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3060
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3006
3061
  "button",
3007
3062
  {
3008
3063
  type: "button",
@@ -3013,7 +3068,7 @@ function ParameterToggle({ field, value, onChange, disabled, id }) {
3013
3068
  disabled: disabled || field.readOnly,
3014
3069
  onClick: () => onChange(!value),
3015
3070
  className: `relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:opacity-50 ${value ? "bg-primary" : "bg-muted"}`,
3016
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3071
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3017
3072
  "span",
3018
3073
  {
3019
3074
  className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow transition-transform ${value ? "translate-x-4" : "translate-x-0.5"}`
@@ -3026,7 +3081,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
3026
3081
  const options = (0, import_parameters.getChoiceOptions)(field);
3027
3082
  const off = disabled || field.readOnly;
3028
3083
  if (field.control === "segmented") {
3029
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "radiogroup", "aria-label": (0, import_parameters.parameterLabel)(field), className: "inline-flex flex-wrap rounded-md border border-input bg-muted p-0.5", children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3084
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "radiogroup", "aria-label": (0, import_parameters.parameterLabel)(field), className: "inline-flex flex-wrap rounded-md border border-input bg-muted p-0.5", children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3030
3085
  "button",
3031
3086
  {
3032
3087
  type: "button",
@@ -3042,7 +3097,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
3042
3097
  )) });
3043
3098
  }
3044
3099
  const index = options.findIndex((o) => o.value === value);
3045
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3100
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3046
3101
  "select",
3047
3102
  {
3048
3103
  id,
@@ -3054,7 +3109,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
3054
3109
  if (option) onChange(option.value);
3055
3110
  },
3056
3111
  className: parameterInputClass,
3057
- children: options.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: String(i), title: o.description, children: (0, import_parameters.choiceOptionLabel)(o) }, String(o.value)))
3112
+ children: options.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: String(i), title: o.description, children: (0, import_parameters.choiceOptionLabel)(o) }, String(o.value)))
3058
3113
  }
3059
3114
  );
3060
3115
  }
@@ -3075,11 +3130,11 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3075
3130
  picking.current = false;
3076
3131
  onGestureEnd?.();
3077
3132
  };
3078
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-1.5", children: [
3079
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
3080
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "relative h-7 w-9 shrink-0 overflow-hidden rounded-md border border-input bg-[repeating-conic-gradient(#d4d4d8_0_25%,#fff_0_50%)] bg-[length:8px_8px]", children: [
3081
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "absolute inset-0", style: { background: alpha ? hex : rgb } }),
3082
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3133
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1.5", children: [
3134
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2", children: [
3135
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "relative h-7 w-9 shrink-0 overflow-hidden rounded-md border border-input bg-[repeating-conic-gradient(#d4d4d8_0_25%,#fff_0_50%)] bg-[length:8px_8px]", children: [
3136
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "absolute inset-0", style: { background: alpha ? hex : rgb } }),
3137
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3083
3138
  "input",
3084
3139
  {
3085
3140
  type: "color",
@@ -3095,7 +3150,7 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3095
3150
  }
3096
3151
  )
3097
3152
  ] }),
3098
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3153
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3099
3154
  ParameterCommitInput,
3100
3155
  {
3101
3156
  id,
@@ -3111,7 +3166,7 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3111
3166
  }
3112
3167
  )
3113
3168
  ] }),
3114
- alpha && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3169
+ alpha && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3115
3170
  "input",
3116
3171
  {
3117
3172
  type: "range",
@@ -3129,10 +3184,10 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3129
3184
  onChange: (e) => onChange(`${rgb}${Number(e.target.value).toString(16).padStart(2, "0")}`)
3130
3185
  }
3131
3186
  ),
3132
- field.swatches && field.swatches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex flex-wrap gap-1", children: field.swatches.map((s) => {
3187
+ field.swatches && field.swatches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-wrap gap-1", children: field.swatches.map((s) => {
3133
3188
  const swatch = (0, import_parameters.normalizeHexColor)(s, alpha);
3134
3189
  if (!swatch) return null;
3135
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3190
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3136
3191
  "button",
3137
3192
  {
3138
3193
  type: "button",
@@ -3151,11 +3206,11 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3151
3206
  }
3152
3207
  function ParameterVector({ field, value, onChange, disabled, id }) {
3153
3208
  const size = (0, import_parameters.vectorSize)(field);
3154
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "grid gap-1.5", style: { gridTemplateColumns: `repeat(${size}, minmax(0, 1fr))` }, children: Array.from({ length: size }, (_, i) => {
3209
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "grid gap-1.5", style: { gridTemplateColumns: `repeat(${size}, minmax(0, 1fr))` }, children: Array.from({ length: size }, (_, i) => {
3155
3210
  const component = (0, import_parameters.vectorComponentField)(field, i);
3156
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex min-w-0 items-center gap-1", children: [
3157
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-3 shrink-0 text-[10px] uppercase text-muted-foreground", children: component.label }),
3158
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3211
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "flex min-w-0 items-center gap-1", children: [
3212
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "w-3 shrink-0 text-[10px] uppercase text-muted-foreground", children: component.label }),
3213
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3159
3214
  ParameterNumberInput,
3160
3215
  {
3161
3216
  field: component,
@@ -3172,11 +3227,11 @@ function ParameterVector({ field, value, onChange, disabled, id }) {
3172
3227
  function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3173
3228
  const off = disabled || field.readOnly;
3174
3229
  const name = (0, import_parameters.parameterLabel)(field);
3175
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-1.5", children: [
3176
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
3177
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex h-12 w-16 shrink-0 items-center justify-center overflow-hidden rounded-md border border-input bg-muted", children: value ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("img", { src: value, alt: name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "None" }) }),
3178
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
3179
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3230
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1.5", children: [
3231
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2", children: [
3232
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex h-12 w-16 shrink-0 items-center justify-center overflow-hidden rounded-md border border-input bg-muted", children: value ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: value, alt: name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "None" }) }),
3233
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
3234
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3180
3235
  ParameterCommitInput,
3181
3236
  {
3182
3237
  id,
@@ -3187,10 +3242,10 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3187
3242
  onCommit: (text) => onChange(text.trim())
3188
3243
  }
3189
3244
  ),
3190
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex gap-1", children: [
3191
- resolveFile && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: `${parameterButtonClass} cursor-pointer ${off ? "pointer-events-none opacity-50" : ""}`, children: [
3245
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex gap-1", children: [
3246
+ resolveFile && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: `${parameterButtonClass} cursor-pointer ${off ? "pointer-events-none opacity-50" : ""}`, children: [
3192
3247
  "Choose file\u2026",
3193
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3248
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3194
3249
  "input",
3195
3250
  {
3196
3251
  type: "file",
@@ -3206,11 +3261,11 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3206
3261
  }
3207
3262
  )
3208
3263
  ] }),
3209
- value && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: parameterButtonClass, disabled: off, onClick: () => onChange(""), "aria-label": `Clear ${name}`, children: "Clear" })
3264
+ value && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: parameterButtonClass, disabled: off, onClick: () => onChange(""), "aria-label": `Clear ${name}`, children: "Clear" })
3210
3265
  ] })
3211
3266
  ] })
3212
3267
  ] }),
3213
- field.options && field.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex flex-wrap gap-1", children: field.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3268
+ field.options && field.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-wrap gap-1", children: field.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3214
3269
  "button",
3215
3270
  {
3216
3271
  type: "button",
@@ -3220,14 +3275,14 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3220
3275
  disabled: off,
3221
3276
  onClick: () => onChange(o.url),
3222
3277
  className: "h-9 w-12 overflow-hidden rounded border border-input aria-pressed:ring-2 aria-pressed:ring-primary",
3223
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("img", { src: o.url, alt: "", className: "h-full w-full object-cover" })
3278
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: o.url, alt: "", className: "h-full w-full object-cover" })
3224
3279
  },
3225
3280
  o.url
3226
3281
  )) })
3227
3282
  ] });
3228
3283
  }
3229
3284
  function ParameterText({ field, value, onChange, disabled, id }) {
3230
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3285
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3231
3286
  ParameterCommitInput,
3232
3287
  {
3233
3288
  id,
@@ -3246,31 +3301,31 @@ function ParameterFieldControl({ field, value, onChange, resolveFile, ...rest })
3246
3301
  switch (field.type) {
3247
3302
  case "number":
3248
3303
  case "int":
3249
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterSlider, { field, value, onChange: set, ...rest });
3304
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterSlider, { field, value, onChange: set, ...rest });
3250
3305
  case "boolean":
3251
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterToggle, { field, value, onChange: set, ...rest });
3306
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterToggle, { field, value, onChange: set, ...rest });
3252
3307
  case "choice":
3253
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterSelect, { field, value, onChange: set, ...rest });
3308
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterSelect, { field, value, onChange: set, ...rest });
3254
3309
  case "color":
3255
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterColor, { field, value, onChange: set, ...rest });
3310
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterColor, { field, value, onChange: set, ...rest });
3256
3311
  case "vector":
3257
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterVector, { field, value, onChange: set, ...rest });
3312
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterVector, { field, value, onChange: set, ...rest });
3258
3313
  case "image":
3259
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterImage, { field, value, onChange: set, resolveFile, ...rest });
3314
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterImage, { field, value, onChange: set, resolveFile, ...rest });
3260
3315
  case "text":
3261
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ParameterText, { field, value, onChange: set, ...rest });
3316
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ParameterText, { field, value, onChange: set, ...rest });
3262
3317
  }
3263
3318
  }
3264
3319
 
3265
3320
  // src/effects/EffectParameters.tsx
3266
- var import_jsx_runtime20 = require("react/jsx-runtime");
3321
+ var import_jsx_runtime21 = require("react/jsx-runtime");
3267
3322
  function EffectParameters({ description, values, onChange, onReset, keyframed, onPreset, disabled = false, className = "" }) {
3268
3323
  const fields = (0, import_react15.useMemo)(() => (0, import_effects3.effectParameterFields)(description), [description]);
3269
3324
  const idBase = (0, import_react15.useId)();
3270
3325
  const gesture = import_react15.default.useRef(null);
3271
3326
  const count = import_react15.default.useRef(0);
3272
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: `space-y-2 ${className}`, "data-effect-parameters": description.id, children: [
3273
- onPreset && description.presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3327
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: `space-y-2 ${className}`, "data-effect-parameters": description.id, children: [
3328
+ onPreset && description.presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3274
3329
  "select",
3275
3330
  {
3276
3331
  className: "w-full rounded border border-border bg-transparent px-1 py-0.5 text-xs",
@@ -3282,8 +3337,8 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
3282
3337
  if (preset) onPreset({ ...description.defaults, ...preset.values });
3283
3338
  },
3284
3339
  children: [
3285
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "", children: "Presets\u2026" }),
3286
- description.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: p.name, children: p.name }, p.name))
3340
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "", children: "Presets\u2026" }),
3341
+ description.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: p.name, children: p.name }, p.name))
3287
3342
  ]
3288
3343
  }
3289
3344
  ),
@@ -3293,13 +3348,13 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
3293
3348
  const keyed = keyframed?.has(field.id) ?? false;
3294
3349
  const value = (0, import_effects3.effectFieldValue)(field, values[field.id]);
3295
3350
  const changed = !keyed && !(0, import_parameters2.parameterValuesEqual)(value, field.default);
3296
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", "data-effect-control": field.id, children: [
3297
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3298
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: inputId, className: "min-w-0 flex-1 truncate text-xs font-medium", title: field.description, children: label }),
3299
- keyed && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "keyframed" }),
3300
- onReset && changed && !disabled && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "rounded px-1 text-[11px] text-muted-foreground hover:text-foreground", "aria-label": `Reset ${label}`, onClick: () => onReset(field.id), children: "\u21BA" })
3351
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-1", "data-effect-control": field.id, children: [
3352
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3353
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: inputId, className: "min-w-0 flex-1 truncate text-xs font-medium", title: field.description, children: label }),
3354
+ keyed && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "keyframed" }),
3355
+ onReset && changed && !disabled && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: "rounded px-1 text-[11px] text-muted-foreground hover:text-foreground", "aria-label": `Reset ${label}`, onClick: () => onReset(field.id), children: "\u21BA" })
3301
3356
  ] }),
3302
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3357
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3303
3358
  ParameterFieldControl,
3304
3359
  {
3305
3360
  field,
@@ -3313,13 +3368,13 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
3313
3368
  )
3314
3369
  ] }, field.id);
3315
3370
  }),
3316
- !fields.length && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No controls." })
3371
+ !fields.length && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No controls." })
3317
3372
  ] });
3318
3373
  }
3319
3374
 
3320
3375
  // src/vector/VectorProviderEffectsPanel.tsx
3321
3376
  var import_react16 = require("react");
3322
- var import_jsx_runtime21 = require("react/jsx-runtime");
3377
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3323
3378
  var btn = "rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40";
3324
3379
  function Controls({ controller, group }) {
3325
3380
  const provider = controller.effectsProvider;
@@ -3327,11 +3382,11 @@ function Controls({ controller, group }) {
3327
3382
  const { description, error } = useEffectDescription(provider, tag.effect);
3328
3383
  const [message, setMessage] = (0, import_react16.useState)(null);
3329
3384
  const run = (work) => void work.then(() => setMessage(null), (e) => setMessage(e instanceof Error ? e.message : String(e)));
3330
- if (!provider) return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider: the shapes are kept as they are." });
3331
- if (error) return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-[11px] text-amber-500", children: error });
3332
- if (!description) return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Loading\u2026" });
3333
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
3334
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3385
+ if (!provider) return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider: the shapes are kept as they are." });
3386
+ if (error) return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[11px] text-amber-500", children: error });
3387
+ if (!description) return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Loading\u2026" });
3388
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3389
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3335
3390
  EffectParameters,
3336
3391
  {
3337
3392
  description,
@@ -3341,7 +3396,7 @@ function Controls({ controller, group }) {
3341
3396
  onPreset: (v) => run(controller.updateVectorEffect(group.id, v))
3342
3397
  }
3343
3398
  ),
3344
- message && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3399
+ message && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3345
3400
  ] });
3346
3401
  }
3347
3402
  function VectorProviderEffectsPanel({ controller, className = "" }) {
@@ -3360,41 +3415,41 @@ function VectorProviderEffectsPanel({ controller, className = "" }) {
3360
3415
  setMessage(null);
3361
3416
  Promise.resolve().then(work).catch((e) => setMessage(e instanceof Error ? e.message : String(e)));
3362
3417
  };
3363
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Vector effects", "data-vector-provider-effects": "", children: [
3364
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1", children: [
3365
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 font-semibold", children: "Effects" }),
3366
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: btn, disabled: !provider, "aria-pressed": browse, onClick: () => setBrowse(!browse), children: "Add effect\u2026" })
3418
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Vector effects", "data-vector-provider-effects": "", children: [
3419
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1", children: [
3420
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "flex-1 font-semibold", children: "Effects" }),
3421
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: btn, disabled: !provider, "aria-pressed": browse, onClick: () => setBrowse(!browse), children: "Add effect\u2026" })
3367
3422
  ] }),
3368
- !provider && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider is registered. Effect groups are kept as shapes." }),
3369
- browse && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EffectsBrowser, { provider, kinds: ["vector"], title: "Vector effects", onPick: (e) => (setBrowse(false), run(() => controller.addVectorEffect(e.id))) }),
3370
- selected.map((g) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-1 rounded border border-border p-1", "data-vector-effect-group": g.id, children: [
3371
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1", children: [
3372
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: g.providerEffect.name ?? g.providerEffect.effect }),
3373
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: btn, title: "Keep the shapes as a plain group", onClick: () => run(() => controller.detachVectorEffect(g.id)), children: "Detach" })
3423
+ !provider && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider is registered. Effect groups are kept as shapes." }),
3424
+ browse && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EffectsBrowser, { provider, kinds: ["vector"], title: "Vector effects", onPick: (e) => (setBrowse(false), run(() => controller.addVectorEffect(e.id))) }),
3425
+ selected.map((g) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-1 rounded border border-border p-1", "data-vector-effect-group": g.id, children: [
3426
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1", children: [
3427
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: g.providerEffect.name ?? g.providerEffect.effect }),
3428
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: btn, title: "Keep the shapes as a plain group", onClick: () => run(() => controller.detachVectorEffect(g.id)), children: "Detach" })
3374
3429
  ] }),
3375
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Controls, { controller, group: g })
3430
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Controls, { controller, group: g })
3376
3431
  ] }, g.id)),
3377
- groups.length > 0 && !selected.length && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
3432
+ groups.length > 0 && !selected.length && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
3378
3433
  "Select an effect group (",
3379
3434
  groups.length,
3380
3435
  " in the drawing) to change it."
3381
3436
  ] }),
3382
- message && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3437
+ message && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3383
3438
  ] });
3384
3439
  }
3385
3440
 
3386
3441
  // src/vector/VectorEditor.tsx
3387
- var import_jsx_runtime22 = require("react/jsx-runtime");
3442
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3388
3443
  function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, effects, className }) {
3389
3444
  useEffects(controller, effects);
3390
3445
  const effectsShown = !!effects || controller.vectorEffectGroups().length > 0;
3391
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
3392
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VectorToolbar, { controller, tools }),
3393
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
3394
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
3395
- showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex w-full shrink-0 flex-col gap-2 md:w-56", children: [
3396
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VectorStylePanel, { controller, className: "rounded-md border border-border p-3" }),
3397
- effectsShown && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VectorProviderEffectsPanel, { controller, className: "rounded-md border border-border p-3" })
3446
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
3447
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VectorToolbar, { controller, tools }),
3448
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
3449
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
3450
+ showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full shrink-0 flex-col gap-2 md:w-56", children: [
3451
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VectorStylePanel, { controller, className: "rounded-md border border-border p-3" }),
3452
+ effectsShown && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VectorProviderEffectsPanel, { controller, className: "rounded-md border border-border p-3" })
3398
3453
  ] })
3399
3454
  ] })
3400
3455
  ] });
@@ -3413,6 +3468,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
3413
3468
  VectorGradientAnnotator,
3414
3469
  VectorGradientDefs,
3415
3470
  VectorGradientEditor,
3471
+ VectorLensPanel,
3416
3472
  VectorMaskPanel,
3417
3473
  VectorMaskedNodes,
3418
3474
  VectorProviderEffectsPanel,