@pixerate/editor-react 0.84.0 → 0.86.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.
@@ -45,6 +45,7 @@ __export(vector_exports, {
45
45
  VectorLensPanel: () => VectorLensPanel,
46
46
  VectorMaskPanel: () => VectorMaskPanel,
47
47
  VectorMaskedNodes: () => VectorMaskedNodes,
48
+ VectorPagesPanel: () => VectorPagesPanel,
48
49
  VectorPerspectivePanel: () => VectorPerspectivePanel,
49
50
  VectorProviderEffectsPanel: () => VectorProviderEffectsPanel,
50
51
  VectorSceneNodes: () => VectorSceneNodes,
@@ -837,7 +838,7 @@ function VectorCanvas({
837
838
 
838
839
  // src/vector/VectorToolbar.tsx
839
840
  var import_react11 = __toESM(require("react"), 1);
840
- var import_vector18 = require("@pixerate/editor/vector");
841
+ var import_vector19 = require("@pixerate/editor/vector");
841
842
 
842
843
  // src/vector/VectorEffectsPanel.tsx
843
844
  var import_vector4 = require("@pixerate/editor/vector");
@@ -1884,38 +1885,67 @@ function VectorFramePanel({ controller, className }) {
1884
1885
  ] });
1885
1886
  }
1886
1887
 
1887
- // src/vector/VectorConnectorPanel.tsx
1888
+ // src/vector/VectorPagesPanel.tsx
1888
1889
  var import_vector12 = require("@pixerate/editor/vector");
1889
1890
  var import_jsx_runtime11 = require("react/jsx-runtime");
1890
- var buttonClass9 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
1891
+ var buttonClass9 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-[current=true]:bg-primary aria-[current=true]:text-primary-foreground";
1891
1892
  var selectClass7 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
1893
+ function VectorPagesPanel({ controller, className }) {
1894
+ const state = useVectorEditorState(controller);
1895
+ const pages = (0, import_vector12.vectorPages)(state.document);
1896
+ const masters = (0, import_vector12.vectorMasterPages)(state.document);
1897
+ const selected = state.selection.map((id) => state.document.nodes.find((n) => n.id === id)).find((n) => (0, import_vector12.isVectorFrame)(n));
1898
+ const page = selected && !selected.frame.master ? selected : null;
1899
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-pages-panel": "", "aria-label": "Pages", children: [
1900
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1901
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Pages" }),
1902
+ pages.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass9, "aria-current": state.selection.includes(p.id), "data-vector-page": p.id, title: `Go to ${p.name ?? `page ${i + 1}`}`, onClick: () => controller.goToPage(p.id), children: i + 1 }, p.id)),
1903
+ masters.map((m) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass9, "aria-current": state.selection.includes(m.id), "data-vector-master-page": m.id, title: `Go to master page ${m.name ?? ""}`, onClick: () => controller.goToPage(m.id), children: m.name ?? "Master" }, m.id)),
1904
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass9, "data-vector-pages-action": "add", title: "Add a page after the last", onClick: () => controller.addPage(), children: "+ Page" }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass9, "data-vector-pages-action": "master", title: "Add a master page used by every page (headers, footers, {page} numbers)", onClick: () => controller.addMasterPage({ assignTo: "all" }), children: "+ Master" })
1906
+ ] }),
1907
+ page && masters.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1908
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-16" }),
1909
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("select", { "aria-label": "Master page", className: selectClass7, value: page.frame.masterId ?? "", onChange: (e) => controller.setPageMaster(e.target.value || null, { ids: [page.id] }), children: [
1910
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "", children: "No master" }),
1911
+ masters.map((m) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: m.id, children: m.name ?? "Master" }, m.id))
1912
+ ] })
1913
+ ] })
1914
+ ] });
1915
+ }
1916
+
1917
+ // src/vector/VectorConnectorPanel.tsx
1918
+ var import_vector13 = require("@pixerate/editor/vector");
1919
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1920
+ var buttonClass10 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
1921
+ var selectClass8 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
1892
1922
  var numberClass5 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
1893
1923
  function VectorConnectorPanel({ controller, className }) {
1894
1924
  const state = useVectorEditorState(controller);
1895
- const panel = (0, import_vector12.getVectorConnectorPanel)(state);
1925
+ const panel = (0, import_vector13.getVectorConnectorPanel)(state);
1896
1926
  if (!panel) return null;
1897
1927
  const ids = [panel.id];
1898
- const end = (key, label, e) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1", "data-vector-connector-end": key, children: [
1899
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
1900
- e ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1901
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1928
+ const end = (key, label, e) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1", "data-vector-connector-end": key, children: [
1929
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
1930
+ e ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1931
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1902
1932
  "select",
1903
1933
  {
1904
1934
  "aria-label": `${label} side`,
1905
- className: selectClass7,
1935
+ className: selectClass8,
1906
1936
  value: e.side ?? "auto",
1907
1937
  onChange: (ev) => controller.setConnector({ [key]: { nodeId: e.nodeId, side: ev.target.value } }, { ids }),
1908
- children: import_vector12.VECTOR_CONNECTOR_SIDES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: s, children: import_vector12.VECTOR_CONNECTOR_SIDE_LABELS[s] }, s))
1938
+ children: import_vector13.VECTOR_CONNECTOR_SIDES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: s, children: import_vector13.VECTOR_CONNECTOR_SIDE_LABELS[s] }, s))
1909
1939
  }
1910
1940
  ),
1911
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass9, title: "Unglue: the end stays where it is", "aria-label": `Unglue ${label.toLowerCase()}`, onClick: () => controller.setConnector({ [key]: null }, { ids }), children: "Unglue" })
1912
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Free" })
1941
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass10, title: "Unglue: the end stays where it is", "aria-label": `Unglue ${label.toLowerCase()}`, onClick: () => controller.setConnector({ [key]: null }, { ids }), children: "Unglue" })
1942
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Free" })
1913
1943
  ] });
1914
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-connector-panel": panel.id, "aria-label": "Connector", children: [
1915
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1", children: [
1916
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Connector" }),
1917
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("select", { "aria-label": "Connector route", className: selectClass7, value: panel.route, onChange: (e) => controller.setConnector({ route: e.target.value }, { ids }), children: import_vector12.VECTOR_CONNECTOR_ROUTES.map((r) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: r, children: import_vector12.VECTOR_CONNECTOR_ROUTE_LABELS[r] }, r)) }),
1918
- panel.route === "elbow" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1944
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-connector-panel": panel.id, "aria-label": "Connector", children: [
1945
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1", children: [
1946
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Connector" }),
1947
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("select", { "aria-label": "Connector route", className: selectClass8, value: panel.route, onChange: (e) => controller.setConnector({ route: e.target.value }, { ids }), children: import_vector13.VECTOR_CONNECTOR_ROUTES.map((r) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: r, children: import_vector13.VECTOR_CONNECTOR_ROUTE_LABELS[r] }, r)) }),
1948
+ panel.route === "elbow" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1919
1949
  "input",
1920
1950
  {
1921
1951
  type: "number",
@@ -1939,9 +1969,9 @@ function VectorConnectorPanel({ controller, className }) {
1939
1969
 
1940
1970
  // src/vector/VectorShadingPanel.tsx
1941
1971
  var import_react8 = require("react");
1942
- var import_vector13 = require("@pixerate/editor/vector");
1943
- var import_jsx_runtime12 = require("react/jsx-runtime");
1944
- var buttonClass10 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
1972
+ var import_vector14 = require("@pixerate/editor/vector");
1973
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1974
+ var buttonClass11 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
1945
1975
  var numberClass6 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
1946
1976
  function VectorShadingPanel({ controller, className }) {
1947
1977
  const state = useVectorEditorState(controller);
@@ -1951,8 +1981,8 @@ function VectorShadingPanel({ controller, className }) {
1951
1981
  if (!path) return null;
1952
1982
  const fill = path.fill;
1953
1983
  const sel = state.shadingPoint?.nodeId === path.id ? state.shadingPoint : null;
1954
- const mesh = (0, import_vector13.isVectorMeshGradient)(fill) ? fill : null;
1955
- const free = (0, import_vector13.isVectorFreeformGradient)(fill) ? fill : null;
1984
+ const mesh = (0, import_vector14.isVectorMeshGradient)(fill) ? fill : null;
1985
+ const free = (0, import_vector14.isVectorFreeformGradient)(fill) ? fill : null;
1956
1986
  const color = sel ? mesh ? mesh.colors[sel.index] : free?.points[sel.index]?.color : void 0;
1957
1987
  const opacity = sel ? mesh ? mesh.opacities?.[sel.index] ?? 1 : free?.points[sel.index]?.opacity ?? 1 : 1;
1958
1988
  const spread = sel && free ? free.points[sel.index]?.spread ?? 0 : 0;
@@ -1961,29 +1991,29 @@ function VectorShadingPanel({ controller, className }) {
1961
1991
  if (mesh) controller.setMeshPoint(path.id, sel.index, patch, merge ? { merge } : {});
1962
1992
  else controller.setFreeformPoint(path.id, sel.index, patch, merge ? { merge } : {});
1963
1993
  };
1964
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-shading-panel": path.id, "aria-label": "Mesh and freeform gradient", children: [
1965
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1966
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Shading" }),
1967
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", min: 1, max: 32, "aria-label": "Mesh rows", title: "Mesh rows", className: numberClass6, value: rows, onChange: (e) => setRows(Math.max(1, Math.min(32, parseInt(e.target.value, 10) || 1))) }),
1968
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-xs text-muted-foreground", children: "\xD7" }),
1969
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "number", min: 1, max: 32, "aria-label": "Mesh columns", title: "Mesh columns", className: numberClass6, value: columns, onChange: (e) => setColumns(Math.max(1, Math.min(32, parseInt(e.target.value, 10) || 1))) }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass10, "data-vector-shading-action": "mesh", title: "Create Gradient Mesh: smooth patches whose points blend colours (edit them with the Gradient tool)", onClick: () => controller.setMeshGradient({ rows, columns }, { ids: [path.id] }), children: "Mesh" }),
1971
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass10, "data-vector-shading-action": "freeform", title: "Freeform Gradient: colour points blended across the shape (click inside with the Gradient tool to add one)", onClick: () => controller.setFreeformGradient({}, { ids: [path.id] }), children: "Freeform" })
1994
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-shading-panel": path.id, "aria-label": "Mesh and freeform gradient", children: [
1995
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
1996
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Shading" }),
1997
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "number", min: 1, max: 32, "aria-label": "Mesh rows", title: "Mesh rows", className: numberClass6, value: rows, onChange: (e) => setRows(Math.max(1, Math.min(32, parseInt(e.target.value, 10) || 1))) }),
1998
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-xs text-muted-foreground", children: "\xD7" }),
1999
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "number", min: 1, max: 32, "aria-label": "Mesh columns", title: "Mesh columns", className: numberClass6, value: columns, onChange: (e) => setColumns(Math.max(1, Math.min(32, parseInt(e.target.value, 10) || 1))) }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: buttonClass11, "data-vector-shading-action": "mesh", title: "Create Gradient Mesh: smooth patches whose points blend colours (edit them with the Gradient tool)", onClick: () => controller.setMeshGradient({ rows, columns }, { ids: [path.id] }), children: "Mesh" }),
2001
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: buttonClass11, "data-vector-shading-action": "freeform", title: "Freeform Gradient: colour points blended across the shape (click inside with the Gradient tool to add one)", onClick: () => controller.setFreeformGradient({}, { ids: [path.id] }), children: "Freeform" })
1972
2002
  ] }),
1973
- (mesh || free) && !sel && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
2003
+ (mesh || free) && !sel && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
1974
2004
  "Gradient tool (G): drag points; ",
1975
2005
  free ? "click inside to add one, Alt-click to remove." : "pick one to colour it."
1976
2006
  ] }),
1977
- sel && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-2", "data-vector-shading-point": sel.index, children: [
1978
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "w-16 text-xs text-foreground", children: [
2007
+ sel && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-wrap items-center gap-2", "data-vector-shading-point": sel.index, children: [
2008
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "w-16 text-xs text-foreground", children: [
1979
2009
  "Point ",
1980
2010
  sel.index
1981
2011
  ] }),
1982
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "color", "aria-label": "Point colour", className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value: (0, import_vector13.vectorPaintToHex)(color ?? "#000000") ?? "#000000", onChange: (e) => edit({ color: e.target.value }, "shading-color") }),
1983
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point opacity", title: "Opacity", className: "h-4 w-20 accent-primary", value: opacity, onChange: (e) => edit({ opacity: parseFloat(e.target.value) }, "shading-opacity") }),
1984
- free && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1985
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point spread", title: "Spread: pure colour round the point", className: "h-4 w-20 accent-primary", value: spread, onChange: (e) => edit({ spread: parseFloat(e.target.value) }, "shading-spread") }),
1986
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass10, "aria-label": "Remove point", onClick: () => controller.removeFreeformPoint(path.id, sel.index), children: "Remove" })
2012
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "color", "aria-label": "Point colour", className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value: (0, import_vector14.vectorPaintToHex)(color ?? "#000000") ?? "#000000", onChange: (e) => edit({ color: e.target.value }, "shading-color") }),
2013
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point opacity", title: "Opacity", className: "h-4 w-20 accent-primary", value: opacity, onChange: (e) => edit({ opacity: parseFloat(e.target.value) }, "shading-opacity") }),
2014
+ free && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2015
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point spread", title: "Spread: pure colour round the point", className: "h-4 w-20 accent-primary", value: spread, onChange: (e) => edit({ spread: parseFloat(e.target.value) }, "shading-spread") }),
2016
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: buttonClass11, "aria-label": "Remove point", onClick: () => controller.removeFreeformPoint(path.id, sel.index), children: "Remove" })
1987
2017
  ] })
1988
2018
  ] })
1989
2019
  ] });
@@ -1991,9 +2021,9 @@ function VectorShadingPanel({ controller, className }) {
1991
2021
 
1992
2022
  // src/vector/VectorTracePanel.tsx
1993
2023
  var import_react9 = require("react");
1994
- var import_jsx_runtime13 = require("react/jsx-runtime");
1995
- var buttonClass11 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
1996
- var selectClass8 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2024
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2025
+ var buttonClass12 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
2026
+ var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
1997
2027
  var numberClass7 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
1998
2028
  async function filePixels(file, max = 1e6) {
1999
2029
  const bitmap = await createImageBitmap(file);
@@ -2023,16 +2053,16 @@ function VectorTracePanel({ controller, className }) {
2023
2053
  setMessage("That file could not be read as an image.");
2024
2054
  }
2025
2055
  };
2026
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `space-y-1 ${className ?? ""}`, "data-vector-trace-panel": "", "aria-label": "Image trace", children: [
2027
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1", children: [
2028
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Trace" }),
2029
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("select", { "aria-label": "Trace mode", className: selectClass8, value: mode, onChange: (e) => setMode(e.target.value), children: [
2030
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "threshold", children: "Black & white" }),
2031
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "color", children: "Colours" })
2056
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `space-y-1 ${className ?? ""}`, "data-vector-trace-panel": "", "aria-label": "Image trace", children: [
2057
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-1", children: [
2058
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Trace" }),
2059
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("select", { "aria-label": "Trace mode", className: selectClass9, value: mode, onChange: (e) => setMode(e.target.value), children: [
2060
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "threshold", children: "Black & white" }),
2061
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "color", children: "Colours" })
2032
2062
  ] }),
2033
- mode === "color" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "number", min: 2, max: 32, "aria-label": "Trace colours", title: "Colours", className: numberClass7, value: colors, onChange: (e) => setColors(Math.max(2, Math.min(32, parseInt(e.target.value, 10) || 2))) }),
2034
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: buttonClass11, "data-vector-trace-action": "", title: "Image Trace: pick an image to turn into paths", onClick: () => input.current?.click(), children: "Image\u2026" }),
2035
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2063
+ mode === "color" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "number", min: 2, max: 32, "aria-label": "Trace colours", title: "Colours", className: numberClass7, value: colors, onChange: (e) => setColors(Math.max(2, Math.min(32, parseInt(e.target.value, 10) || 2))) }),
2064
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "data-vector-trace-action": "", title: "Image Trace: pick an image to turn into paths", onClick: () => input.current?.click(), children: "Image\u2026" }),
2065
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2036
2066
  "input",
2037
2067
  {
2038
2068
  ref: input,
@@ -2047,124 +2077,124 @@ function VectorTracePanel({ controller, className }) {
2047
2077
  }
2048
2078
  )
2049
2079
  ] }),
2050
- message && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-[11px] text-red-600", children: message })
2080
+ message && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-[11px] text-red-600", children: message })
2051
2081
  ] });
2052
2082
  }
2053
2083
 
2054
2084
  // src/vector/VectorSymmetryPanel.tsx
2055
- var import_vector14 = require("@pixerate/editor/vector");
2056
- var import_jsx_runtime14 = require("react/jsx-runtime");
2057
- var buttonClass12 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2058
- var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2085
+ var import_vector15 = require("@pixerate/editor/vector");
2086
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2087
+ var buttonClass13 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2088
+ var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2059
2089
  var numberClass8 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
2060
2090
  function VectorSymmetryPanel({ controller, className }) {
2061
2091
  const state = useVectorEditorState(controller);
2062
- const group = state.selection.map((id) => controller.getNode(id)).find(import_vector14.isVectorSymmetryGroup) ?? null;
2092
+ const group = state.selection.map((id) => controller.getNode(id)).find(import_vector15.isVectorSymmetryGroup) ?? null;
2063
2093
  const s = group?.symmetry;
2064
2094
  const ids = group ? [group.id] : void 0;
2065
2095
  const drawing = !!group && state.symmetryTarget === group.id;
2066
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symmetry-panel": "", "aria-label": "Symmetry", children: [
2067
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2068
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Symmetry" }),
2069
- !group && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "data-vector-symmetry-action": "make", title: "Make Symmetry: the selection (or nothing yet) mirrored live across a vertical axis", onClick: () => controller.makeSymmetry({ mode: "vertical" }), children: "Mirror" }),
2070
- !group && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "data-vector-symmetry-action": "radial", title: "Make Symmetry: the selection repeated round its centre", onClick: () => controller.makeSymmetry({ mode: "radial", copies: 6 }), children: "Radial" }),
2071
- group && s && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2072
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("select", { "aria-label": "Symmetry mode", className: selectClass9, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: import_vector14.VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: m, children: import_vector14.VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
2073
- s.mode === "radial" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2074
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "number", min: 2, max: 64, "aria-label": "Symmetry copies", title: "Copies round the circle", className: numberClass8, value: s.copies ?? 6, onChange: (e) => controller.setSymmetry({ copies: Math.max(2, Math.min(64, parseInt(e.target.value, 10) || 2)) }, { ids }) }),
2075
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Mirror each copy too (kaleidoscope)", children: [
2076
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "checkbox", "aria-label": "Mirror copies", checked: !!s.mirror, onChange: (e) => controller.setSymmetry({ mirror: e.target.checked }, { ids }) }),
2096
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symmetry-panel": "", "aria-label": "Symmetry", children: [
2097
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2098
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Symmetry" }),
2099
+ !group && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "data-vector-symmetry-action": "make", title: "Make Symmetry: the selection (or nothing yet) mirrored live across a vertical axis", onClick: () => controller.makeSymmetry({ mode: "vertical" }), children: "Mirror" }),
2100
+ !group && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "data-vector-symmetry-action": "radial", title: "Make Symmetry: the selection repeated round its centre", onClick: () => controller.makeSymmetry({ mode: "radial", copies: 6 }), children: "Radial" }),
2101
+ group && s && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2102
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Symmetry mode", className: selectClass10, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: import_vector15.VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: m, children: import_vector15.VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
2103
+ s.mode === "radial" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2104
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "number", min: 2, max: 64, "aria-label": "Symmetry copies", title: "Copies round the circle", className: numberClass8, value: s.copies ?? 6, onChange: (e) => controller.setSymmetry({ copies: Math.max(2, Math.min(64, parseInt(e.target.value, 10) || 2)) }, { ids }) }),
2105
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Mirror each copy too (kaleidoscope)", children: [
2106
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", "aria-label": "Mirror copies", checked: !!s.mirror, onChange: (e) => controller.setSymmetry({ mirror: e.target.checked }, { ids }) }),
2077
2107
  "Mirror"
2078
2108
  ] })
2079
2109
  ] })
2080
2110
  ] })
2081
2111
  ] }),
2082
- group && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2083
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "w-16" }),
2084
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "aria-pressed": drawing, "data-vector-symmetry-action": "draw", title: "Draw inside: new pen, pencil, shape and text art goes into the group, mirrored as you draw (Escape stops)", onClick: () => drawing ? controller.exitSymmetry() : controller.enterSymmetry(group.id), children: "Draw inside" }),
2085
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, title: "Expand: keep the copies as real objects", onClick: () => controller.releaseSymmetry({ ids, expand: true }), children: "Expand" }),
2086
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, title: "Release: stop repeating (the copies go)", onClick: () => controller.releaseSymmetry({ ids }), children: "Release" })
2112
+ group && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2113
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16" }),
2114
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "aria-pressed": drawing, "data-vector-symmetry-action": "draw", title: "Draw inside: new pen, pencil, shape and text art goes into the group, mirrored as you draw (Escape stops)", onClick: () => drawing ? controller.exitSymmetry() : controller.enterSymmetry(group.id), children: "Draw inside" }),
2115
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, title: "Expand: keep the copies as real objects", onClick: () => controller.releaseSymmetry({ ids, expand: true }), children: "Expand" }),
2116
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, title: "Release: stop repeating (the copies go)", onClick: () => controller.releaseSymmetry({ ids }), children: "Release" })
2087
2117
  ] })
2088
2118
  ] });
2089
2119
  }
2090
2120
 
2091
2121
  // src/vector/VectorPerspectivePanel.tsx
2092
2122
  var import_react10 = __toESM(require("react"), 1);
2093
- var import_vector15 = require("@pixerate/editor/vector");
2094
- var import_jsx_runtime15 = require("react/jsx-runtime");
2095
- var buttonClass13 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2096
- var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2123
+ var import_vector16 = require("@pixerate/editor/vector");
2124
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2125
+ var buttonClass14 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2126
+ var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2097
2127
  var PLANE_LABELS = { floor: "Floor", left: "Left wall", right: "Right wall", side: "Side wall", front: "Front" };
2098
2128
  function VectorPerspectivePanel({ controller, className }) {
2099
2129
  const state = useVectorEditorState(controller);
2100
2130
  const grid = state.document.perspective ?? null;
2101
- const planes = grid ? (0, import_vector15.vectorPerspectivePlanes)(grid) : [];
2131
+ const planes = grid ? (0, import_vector16.vectorPerspectivePlanes)(grid) : [];
2102
2132
  const [attachTo, setAttachTo] = import_react10.default.useState("");
2103
2133
  const target = (state.perspectivePlane ?? attachTo) || planes[0];
2104
- const add = (n) => controller.setPerspective((0, import_vector15.vectorPerspectivePreset)(n, state.document.width, state.document.height));
2105
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-perspective-panel": "", "aria-label": "Perspective", children: [
2106
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2107
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Perspective" }),
2108
- [1, 2, 3].map((n) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { type: "button", className: buttonClass13, "aria-pressed": grid?.vanishingPoints.length === n, "data-vector-perspective-preset": n, title: `A ${n}-point perspective grid for the page`, onClick: () => add(n), children: [
2134
+ const add = (n) => controller.setPerspective((0, import_vector16.vectorPerspectivePreset)(n, state.document.width, state.document.height));
2135
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-perspective-panel": "", "aria-label": "Perspective", children: [
2136
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2137
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Perspective" }),
2138
+ [1, 2, 3].map((n) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", className: buttonClass14, "aria-pressed": grid?.vanishingPoints.length === n, "data-vector-perspective-preset": n, title: `A ${n}-point perspective grid for the page`, onClick: () => add(n), children: [
2109
2139
  n,
2110
2140
  "-pt"
2111
2141
  ] }, n))
2112
2142
  ] }),
2113
- grid && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2114
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16" }),
2115
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("select", { "aria-label": "Draw on plane", title: "New rectangles, ellipses, polygons and stars are drawn on this plane", className: selectClass10, value: state.perspectivePlane ?? "", onChange: (e) => controller.setPerspectivePlane(e.target.value || null), children: [
2116
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "", children: "Draw flat" }),
2117
- planes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("option", { value: p, children: [
2143
+ grid && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2144
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16" }),
2145
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("select", { "aria-label": "Draw on plane", title: "New rectangles, ellipses, polygons and stars are drawn on this plane", className: selectClass11, value: state.perspectivePlane ?? "", onChange: (e) => controller.setPerspectivePlane(e.target.value || null), children: [
2146
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "", children: "Draw flat" }),
2147
+ planes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("option", { value: p, children: [
2118
2148
  "Draw on ",
2119
2149
  PLANE_LABELS[p].toLowerCase()
2120
2150
  ] }, p))
2121
2151
  ] })
2122
2152
  ] }),
2123
- grid && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2124
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16" }),
2125
- !state.perspectivePlane && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Attach to plane", className: "h-7 w-24 rounded border border-border bg-background px-1 text-xs", value: attachTo || planes[0], onChange: (e) => setAttachTo(e.target.value), children: planes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: p, children: PLANE_LABELS[p] }, p)) }),
2126
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, disabled: !state.selection.length, title: "Lay the selection onto the plane (read flat from the grid's origin)", onClick: () => controller.attachToPerspective(target), children: "Attach" }),
2127
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Show the grid on the canvas", children: [
2128
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", "aria-label": "Show perspective grid", checked: grid.visible !== false, onChange: (e) => controller.setPerspective({ ...grid, visible: e.target.checked }) }),
2153
+ grid && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2154
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16" }),
2155
+ !state.perspectivePlane && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Attach to plane", className: "h-7 w-24 rounded border border-border bg-background px-1 text-xs", value: attachTo || planes[0], onChange: (e) => setAttachTo(e.target.value), children: planes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: p, children: PLANE_LABELS[p] }, p)) }),
2156
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass14, disabled: !state.selection.length, title: "Lay the selection onto the plane (read flat from the grid's origin)", onClick: () => controller.attachToPerspective(target), children: "Attach" }),
2157
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Show the grid on the canvas", children: [
2158
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "checkbox", "aria-label": "Show perspective grid", checked: grid.visible !== false, onChange: (e) => controller.setPerspective({ ...grid, visible: e.target.checked }) }),
2129
2159
  "Show"
2130
2160
  ] }),
2131
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, title: "Remove the grid (art on it stays)", onClick: () => controller.setPerspective(null), children: "Remove" })
2161
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass14, title: "Remove the grid (art on it stays)", onClick: () => controller.setPerspective(null), children: "Remove" })
2132
2162
  ] })
2133
2163
  ] });
2134
2164
  }
2135
2165
 
2136
2166
  // src/vector/VectorLensPanel.tsx
2137
- var import_vector16 = require("@pixerate/editor/vector");
2138
- var import_jsx_runtime16 = require("react/jsx-runtime");
2139
- var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2167
+ var import_vector17 = require("@pixerate/editor/vector");
2168
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2169
+ var selectClass12 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2140
2170
  var numberClass9 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
2141
2171
  function VectorLensPanel({ controller, className }) {
2142
2172
  const state = useVectorEditorState(controller);
2143
2173
  const path = state.selection.map((id) => controller.getNode(id)).find((n) => n?.type === "path" && n.subpaths.some((sp) => sp.closed) && !n.connector);
2144
2174
  if (!path) return null;
2145
2175
  const lens = path.lens ?? null;
2146
- const spec = lens ? import_vector16.VECTOR_LENS_SPECS[lens.type] : null;
2176
+ const spec = lens ? import_vector17.VECTOR_LENS_SPECS[lens.type] : null;
2147
2177
  const ids = [path.id];
2148
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-lens-panel": "", "aria-label": "Lens", children: [
2149
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2150
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Lens" }),
2151
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2178
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-lens-panel": "", "aria-label": "Lens", children: [
2179
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2180
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Lens" }),
2181
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2152
2182
  "select",
2153
2183
  {
2154
2184
  "aria-label": "Lens type",
2155
- className: selectClass11,
2185
+ className: selectClass12,
2156
2186
  value: lens?.type ?? "",
2157
2187
  onChange: (e) => e.target.value ? controller.setLens({ type: e.target.value }, { ids }) : controller.setLens(null, { ids }),
2158
2188
  children: [
2159
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "", children: "None" }),
2160
- import_vector16.VECTOR_LENS_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: t, children: import_vector16.VECTOR_LENS_LABELS[t] }, t))
2189
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "", children: "None" }),
2190
+ import_vector17.VECTOR_LENS_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: t, children: import_vector17.VECTOR_LENS_LABELS[t] }, t))
2161
2191
  ]
2162
2192
  }
2163
2193
  )
2164
2194
  ] }),
2165
- lens && spec && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2166
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16" }),
2167
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2195
+ lens && spec && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
2196
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16" }),
2197
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2168
2198
  "input",
2169
2199
  {
2170
2200
  type: "number",
@@ -2181,21 +2211,21 @@ function VectorLensPanel({ controller, className }) {
2181
2211
  }
2182
2212
  }
2183
2213
  ),
2184
- spec.color !== null && /* @__PURE__ */ (0, import_jsx_runtime16.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}` }) })
2214
+ spec.color !== null && /* @__PURE__ */ (0, import_jsx_runtime17.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}` }) })
2185
2215
  ] })
2186
2216
  ] });
2187
2217
  }
2188
2218
 
2189
2219
  // src/vector/VectorGradientEditor.tsx
2190
- var import_vector17 = require("@pixerate/editor/vector");
2191
- var import_jsx_runtime17 = require("react/jsx-runtime");
2192
- var selectClass12 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2220
+ var import_vector18 = require("@pixerate/editor/vector");
2221
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2222
+ var selectClass13 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2193
2223
  var numberClass10 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
2194
- var buttonClass14 = "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";
2224
+ var buttonClass15 = "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";
2195
2225
  var percent = (v) => Math.round(v * 1e3) / 10;
2196
2226
  function VectorGradientEditor({ controller, className }) {
2197
2227
  const state = useVectorEditorState(controller);
2198
- const ed = (0, import_vector17.getVectorGradientEditor)(state);
2228
+ const ed = (0, import_vector18.getVectorGradientEditor)(state);
2199
2229
  if (!ed) return null;
2200
2230
  const g = ed.gradient;
2201
2231
  const sel = ed.selected;
@@ -2203,26 +2233,26 @@ function VectorGradientEditor({ controller, className }) {
2203
2233
  const setType = (value) => {
2204
2234
  if (value === "solid") {
2205
2235
  const first = ed.stops[0];
2206
- controller.setStyle({ [ed.target]: (0, import_vector17.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
2236
+ controller.setStyle({ [ed.target]: (0, import_vector18.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
2207
2237
  } else controller.setGradient({ type: value });
2208
2238
  };
2209
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
2210
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2211
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
2212
- ["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass14, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
2213
- ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2239
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
2240
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2241
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
2242
+ ["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: buttonClass15, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
2243
+ ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2214
2244
  ] }),
2215
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2216
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
2217
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("select", { "aria-label": "Gradient type", className: selectClass12, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
2218
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "solid", children: "Solid" }),
2219
- import_vector17.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: t, children: import_vector17.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
2245
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2246
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
2247
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { "aria-label": "Gradient type", className: selectClass13, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
2248
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "solid", children: "Solid" }),
2249
+ import_vector18.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: t, children: import_vector18.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
2220
2250
  ] }),
2221
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass14, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
2251
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: buttonClass15, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
2222
2252
  ] }),
2223
- g && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2224
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
2225
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2253
+ g && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2254
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
2255
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2226
2256
  "div",
2227
2257
  {
2228
2258
  role: "button",
@@ -2236,7 +2266,7 @@ function VectorGradientEditor({ controller, className }) {
2236
2266
  }
2237
2267
  }
2238
2268
  ),
2239
- ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2269
+ ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2240
2270
  "button",
2241
2271
  {
2242
2272
  type: "button",
@@ -2250,21 +2280,21 @@ function VectorGradientEditor({ controller, className }) {
2250
2280
  s.index
2251
2281
  ))
2252
2282
  ] }),
2253
- sel && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
2254
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2283
+ sel && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
2284
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2255
2285
  "input",
2256
2286
  {
2257
2287
  type: "color",
2258
2288
  "aria-label": "Stop colour",
2259
2289
  className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
2260
- value: (0, import_vector17.vectorPaintToHex)(sel.color) ?? "#000000",
2290
+ value: (0, import_vector18.vectorPaintToHex)(sel.color) ?? "#000000",
2261
2291
  onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
2262
2292
  onBlur: end
2263
2293
  }
2264
2294
  ),
2265
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2295
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2266
2296
  "Opacity",
2267
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2297
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2268
2298
  "input",
2269
2299
  {
2270
2300
  type: "number",
@@ -2281,9 +2311,9 @@ function VectorGradientEditor({ controller, className }) {
2281
2311
  }
2282
2312
  )
2283
2313
  ] }),
2284
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2314
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2285
2315
  "At",
2286
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2316
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2287
2317
  "input",
2288
2318
  {
2289
2319
  type: "number",
@@ -2300,9 +2330,9 @@ function VectorGradientEditor({ controller, className }) {
2300
2330
  }
2301
2331
  )
2302
2332
  ] }),
2303
- !sel.last && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2333
+ !sel.last && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
2304
2334
  "Midpoint",
2305
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2335
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2306
2336
  "input",
2307
2337
  {
2308
2338
  type: "number",
@@ -2319,15 +2349,15 @@ function VectorGradientEditor({ controller, className }) {
2319
2349
  }
2320
2350
  )
2321
2351
  ] }),
2322
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass14, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
2352
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: buttonClass15, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
2323
2353
  ] }),
2324
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2325
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Colours" }),
2326
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass12, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector17.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: i, children: import_vector17.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
2354
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2355
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Colours" }),
2356
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass13, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector18.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: i, children: import_vector18.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
2327
2357
  ] }),
2328
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2329
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Smooth" }),
2330
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2358
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2359
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Smooth" }),
2360
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2331
2361
  "input",
2332
2362
  {
2333
2363
  type: "range",
@@ -2343,26 +2373,26 @@ function VectorGradientEditor({ controller, className }) {
2343
2373
  }
2344
2374
  )
2345
2375
  ] }),
2346
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2347
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Spread" }),
2348
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Gradient spread", className: selectClass12, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector17.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: sp, children: import_vector17.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
2376
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2377
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Spread" }),
2378
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient spread", className: selectClass13, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector18.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: sp, children: import_vector18.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
2349
2379
  ] }),
2350
- ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2351
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "On stroke" }),
2352
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass12, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector17.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: m, children: import_vector17.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
2380
+ ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
2381
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "On stroke" }),
2382
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass13, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector18.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: m, children: import_vector18.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
2353
2383
  ] })
2354
2384
  ] })
2355
2385
  ] });
2356
2386
  }
2357
2387
 
2358
2388
  // src/vector/VectorToolbar.tsx
2359
- var import_jsx_runtime18 = require("react/jsx-runtime");
2389
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2360
2390
  var VECTOR_SNAP_TITLE = "Snap to objects";
2361
2391
  var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
2362
- var buttonClass15 = "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";
2392
+ var buttonClass16 = "inline-flex h-8 min-w-8 items-center justify-center rounded-md border border-border bg-background px-2 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
2363
2393
  function VectorToolbar({
2364
2394
  controller,
2365
- tools = import_vector18.VECTOR_TOOLS,
2395
+ tools = import_vector19.VECTOR_TOOLS,
2366
2396
  showHistory = true,
2367
2397
  showArrange = true,
2368
2398
  showSnap = true,
@@ -2376,36 +2406,36 @@ function VectorToolbar({
2376
2406
  const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
2377
2407
  const editing = state.editing;
2378
2408
  const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
2379
- const maskSelected = state.selection.some((id) => (0, import_vector18.isVectorMaskGroup)(controller.getNode(id)));
2409
+ const maskSelected = state.selection.some((id) => (0, import_vector19.isVectorMaskGroup)(controller.getNode(id)));
2380
2410
  const [live, setLive] = import_react11.default.useState(false);
2381
2411
  const booleanDisabled = live ? count < 1 : count < 2;
2382
- const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: buttonClass15, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
2383
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
2384
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2412
+ const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: buttonClass16, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
2413
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
2414
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2385
2415
  "button",
2386
2416
  {
2387
2417
  type: "button",
2388
2418
  "data-vector-tool": tool,
2389
- className: buttonClass15,
2419
+ className: buttonClass16,
2390
2420
  "aria-pressed": state.tool === tool,
2391
- title: `${(0, import_vector18.vectorToolLabel)(tool)} (${import_vector18.VECTOR_TOOL_SHORTCUTS[tool]})`,
2392
- "aria-label": (0, import_vector18.vectorToolLabel)(tool),
2421
+ title: `${(0, import_vector19.vectorToolLabel)(tool)} (${import_vector19.VECTOR_TOOL_SHORTCUTS[tool]})`,
2422
+ "aria-label": (0, import_vector19.vectorToolLabel)(tool),
2393
2423
  onClick: () => controller.setTool(tool),
2394
- children: import_vector18.VECTOR_TOOL_GLYPHS[tool]
2424
+ children: import_vector19.VECTOR_TOOL_GLYPHS[tool]
2395
2425
  },
2396
2426
  tool
2397
2427
  )) }),
2398
- showHistory && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
2428
+ showHistory && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
2399
2429
  act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
2400
2430
  act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
2401
2431
  ] }),
2402
- showSnap && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
2403
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2432
+ showSnap && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
2433
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2404
2434
  "button",
2405
2435
  {
2406
2436
  type: "button",
2407
2437
  "data-vector-snap": "",
2408
- className: buttonClass15,
2438
+ className: buttonClass16,
2409
2439
  "aria-pressed": state.snap.objects,
2410
2440
  title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
2411
2441
  "aria-label": VECTOR_SNAP_TITLE,
@@ -2413,18 +2443,18 @@ function VectorToolbar({
2413
2443
  children: "Snap"
2414
2444
  }
2415
2445
  ),
2416
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2446
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2417
2447
  "select",
2418
2448
  {
2419
2449
  "data-vector-polar": "",
2420
2450
  "aria-label": "Polar tracking increment",
2421
2451
  title: "Polar tracking: the angles drawn points snap to from where they leave",
2422
2452
  className: "h-8 rounded-md border border-border bg-background px-1 text-xs",
2423
- value: String((0, import_vector18.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
2424
- onChange: (e) => controller.setSnap({ angles: (0, import_vector18.vectorPolarAngles)(Number(e.target.value)) }),
2453
+ value: String((0, import_vector19.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
2454
+ onChange: (e) => controller.setSnap({ angles: (0, import_vector19.vectorPolarAngles)(Number(e.target.value)) }),
2425
2455
  children: [
2426
- (0, import_vector18.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "Custom" }),
2427
- [90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("option", { value: n, children: [
2456
+ (0, import_vector19.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "Custom" }),
2457
+ [90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("option", { value: n, children: [
2428
2458
  n,
2429
2459
  "\xB0"
2430
2460
  ] }, n))
@@ -2432,13 +2462,13 @@ function VectorToolbar({
2432
2462
  }
2433
2463
  )
2434
2464
  ] }),
2435
- showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
2436
- import_vector18.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2465
+ showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
2466
+ import_vector19.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2437
2467
  "button",
2438
2468
  {
2439
2469
  type: "button",
2440
2470
  "data-vector-path-action": a.id,
2441
- className: buttonClass15,
2471
+ className: buttonClass16,
2442
2472
  title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
2443
2473
  "aria-label": a.title,
2444
2474
  disabled: !a.enabled(count, points),
@@ -2447,12 +2477,12 @@ function VectorToolbar({
2447
2477
  },
2448
2478
  a.id
2449
2479
  )),
2450
- import_vector18.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2480
+ import_vector19.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2451
2481
  "button",
2452
2482
  {
2453
2483
  type: "button",
2454
2484
  "data-vector-edit": t.key,
2455
- className: buttonClass15,
2485
+ className: buttonClass16,
2456
2486
  "aria-pressed": editing[t.key],
2457
2487
  title: t.title,
2458
2488
  "aria-label": t.title,
@@ -2461,9 +2491,9 @@ function VectorToolbar({
2461
2491
  },
2462
2492
  t.key
2463
2493
  )),
2464
- state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2494
+ state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2465
2495
  "Smoothing",
2466
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2496
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2467
2497
  "input",
2468
2498
  {
2469
2499
  type: "range",
@@ -2477,9 +2507,9 @@ function VectorToolbar({
2477
2507
  }
2478
2508
  )
2479
2509
  ] }),
2480
- state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2510
+ state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
2481
2511
  "Size",
2482
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2512
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2483
2513
  "input",
2484
2514
  {
2485
2515
  type: "number",
@@ -2495,26 +2525,26 @@ function VectorToolbar({
2495
2525
  }
2496
2526
  )
2497
2527
  ] }),
2498
- state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2528
+ state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2499
2529
  "button",
2500
2530
  {
2501
2531
  type: "button",
2502
2532
  "data-vector-fill-gap": "",
2503
- className: buttonClass15,
2533
+ className: buttonClass16,
2504
2534
  "aria-pressed": editing.fillGap > 0,
2505
2535
  title: "Close small gaps between path ends when filling",
2506
2536
  "aria-label": "Close gaps",
2507
- onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector18.VECTOR_FILL_GAP }),
2537
+ onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector19.VECTOR_FILL_GAP }),
2508
2538
  children: "Gaps"
2509
2539
  }
2510
2540
  )
2511
2541
  ] }),
2512
- showDistort && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2542
+ showDistort && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2513
2543
  "button",
2514
2544
  {
2515
2545
  type: "button",
2516
2546
  "data-vector-free-distort": "",
2517
- className: buttonClass15,
2547
+ className: buttonClass16,
2518
2548
  "aria-pressed": state.freeDistort,
2519
2549
  title: `Free Distort: drag a corner of the selection box to distort in perspective (Shift+Alt+${modKeyLabel()}: symmetric perspective; ${modKeyLabel()}-drag a side to skew)`,
2520
2550
  "aria-label": "Free Distort",
@@ -2522,15 +2552,15 @@ function VectorToolbar({
2522
2552
  children: "Distort"
2523
2553
  }
2524
2554
  ) }),
2525
- showBlend && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorBlendControls, { controller }),
2526
- showArrange && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2527
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
2528
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2555
+ showBlend && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorBlendControls, { controller }),
2556
+ showArrange && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2557
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
2558
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2529
2559
  "button",
2530
2560
  {
2531
2561
  type: "button",
2532
2562
  "data-vector-live-boolean": "",
2533
- className: buttonClass15,
2563
+ className: buttonClass16,
2534
2564
  "aria-pressed": live,
2535
2565
  title: "Live booleans: keep the shapes editable",
2536
2566
  "aria-label": "Live booleans",
@@ -2547,12 +2577,12 @@ function VectorToolbar({
2547
2577
  act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
2548
2578
  act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
2549
2579
  ] }),
2550
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector18.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2580
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector19.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2551
2581
  "button",
2552
2582
  {
2553
2583
  type: "button",
2554
2584
  "data-vector-pathfinder": a.id,
2555
- className: buttonClass15,
2585
+ className: buttonClass16,
2556
2586
  title: a.title,
2557
2587
  "aria-label": a.title,
2558
2588
  disabled: count < a.min,
@@ -2561,7 +2591,7 @@ function VectorToolbar({
2561
2591
  },
2562
2592
  a.id
2563
2593
  )) }),
2564
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
2594
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
2565
2595
  act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
2566
2596
  act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
2567
2597
  act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
@@ -2576,22 +2606,22 @@ function VectorToolbar({
2576
2606
  }
2577
2607
  function VectorBlendControls({ controller }) {
2578
2608
  const state = useVectorEditorState(controller);
2579
- const blend = (0, import_vector18.getVectorBlendControls)(state);
2609
+ const blend = (0, import_vector19.getVectorBlendControls)(state);
2580
2610
  const o = blend.options;
2581
2611
  const selected = blend.ids.length > 0;
2582
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
2583
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass15, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
2584
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2612
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
2613
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass16, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
2614
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2585
2615
  "select",
2586
2616
  {
2587
2617
  "aria-label": "Blend spacing",
2588
2618
  className: "h-7 rounded border border-border bg-background px-1 text-xs",
2589
2619
  value: o.spacing,
2590
- onChange: (e) => (0, import_vector18.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
2591
- children: import_vector18.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: sp, children: import_vector18.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
2620
+ onChange: (e) => (0, import_vector19.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
2621
+ children: import_vector19.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: sp, children: import_vector19.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
2592
2622
  }
2593
2623
  ),
2594
- o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2624
+ o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2595
2625
  "input",
2596
2626
  {
2597
2627
  type: "number",
@@ -2603,29 +2633,29 @@ function VectorBlendControls({ controller }) {
2603
2633
  onChange: (e) => {
2604
2634
  const n = parseFloat(e.target.value);
2605
2635
  if (!Number.isFinite(n) || n <= 0) return;
2606
- (0, import_vector18.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
2636
+ (0, import_vector19.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
2607
2637
  }
2608
2638
  }
2609
2639
  ),
2610
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2640
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2611
2641
  "button",
2612
2642
  {
2613
2643
  type: "button",
2614
2644
  "data-vector-blend-action": "orient",
2615
- className: buttonClass15,
2645
+ className: buttonClass16,
2616
2646
  "aria-pressed": o.orientToSpine,
2617
2647
  title: "Orient steps to the spine",
2618
2648
  "aria-label": "Orient to spine",
2619
- onClick: () => (0, import_vector18.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
2649
+ onClick: () => (0, import_vector19.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
2620
2650
  children: "\u293F"
2621
2651
  }
2622
2652
  ),
2623
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2653
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2624
2654
  "button",
2625
2655
  {
2626
2656
  type: "button",
2627
2657
  "data-vector-blend-action": "spine",
2628
- className: buttonClass15,
2658
+ className: buttonClass16,
2629
2659
  title: "Replace Spine (select a blend and a path)",
2630
2660
  "aria-label": "Replace Spine",
2631
2661
  disabled: !blend.canReplaceSpine,
@@ -2633,15 +2663,15 @@ function VectorBlendControls({ controller }) {
2633
2663
  children: "\u2307"
2634
2664
  }
2635
2665
  ),
2636
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass15, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
2637
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass15, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
2666
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass16, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
2667
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass16, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
2638
2668
  ] });
2639
2669
  }
2640
- var selectClass13 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2670
+ var selectClass14 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
2641
2671
  var numberClass11 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
2642
2672
  function VectorStylePanel({ controller, className }) {
2643
2673
  const state = useVectorEditorState(controller);
2644
- const style = (0, import_vector18.getVectorSelectionStyle)(state);
2674
+ const style = (0, import_vector19.getVectorSelectionStyle)(state);
2645
2675
  const d = state.defaults;
2646
2676
  const source = style ?? {
2647
2677
  fill: d.fill ?? null,
@@ -2654,7 +2684,7 @@ function VectorStylePanel({ controller, className }) {
2654
2684
  arrowAlign: d.arrowAlign ?? "extend",
2655
2685
  startArrowScale: d.startArrowScale ?? 1,
2656
2686
  endArrowScale: d.endArrowScale ?? 1,
2657
- widthProfile: (0, import_vector18.widthProfilePresetId)(d.strokeWidthProfile),
2687
+ widthProfile: (0, import_vector19.widthProfilePresetId)(d.strokeWidthProfile),
2658
2688
  cornerRadius: d.cornerRadius,
2659
2689
  cornerKind: d.cornerKind ?? "round",
2660
2690
  cornerSmoothing: 0,
@@ -2668,19 +2698,19 @@ function VectorStylePanel({ controller, className }) {
2668
2698
  };
2669
2699
  const setProfile = (id) => {
2670
2700
  if (style) controller.setWidthProfile(id);
2671
- else controller.setDefaults({ strokeWidthProfile: (0, import_vector18.widthProfilePreset)(id)?.length ? (0, import_vector18.widthProfilePreset)(id) : null });
2701
+ else controller.setDefaults({ strokeWidthProfile: (0, import_vector19.widthProfilePreset)(id)?.length ? (0, import_vector19.widthProfilePreset)(id) : null });
2672
2702
  };
2673
- const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
2703
+ const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
2674
2704
  const arrowRow = (end, label) => {
2675
2705
  const key = end === "start" ? "startArrow" : "endArrow";
2676
2706
  const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
2677
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2678
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
2679
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass13, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
2680
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "None" }),
2681
- import_vector18.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: h, children: import_vector18.VECTOR_ARROWHEAD_LABELS[h] }, h))
2707
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2708
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
2709
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass14, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
2710
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "None" }),
2711
+ import_vector19.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: h, children: import_vector19.VECTOR_ARROWHEAD_LABELS[h] }, h))
2682
2712
  ] }),
2683
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2713
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2684
2714
  "input",
2685
2715
  {
2686
2716
  type: "number",
@@ -2704,14 +2734,14 @@ function VectorStylePanel({ controller, className }) {
2704
2734
  };
2705
2735
  const paintRow = (key, label) => {
2706
2736
  const paint = source[key];
2707
- const hex = (0, import_vector18.vectorPaintToHex)(paint);
2737
+ const hex = (0, import_vector19.vectorPaintToHex)(paint);
2708
2738
  const on = paint !== null && paint !== "none";
2709
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2710
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
2711
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
2739
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
2740
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
2741
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
2712
2742
  label
2713
2743
  ] }),
2714
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2744
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2715
2745
  "input",
2716
2746
  {
2717
2747
  type: "color",
@@ -2722,18 +2752,18 @@ function VectorStylePanel({ controller, className }) {
2722
2752
  onChange: (e) => apply({ [key]: e.target.value })
2723
2753
  }
2724
2754
  ),
2725
- on && !hex && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
2726
- style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2755
+ on && !hex && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
2756
+ style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
2727
2757
  ] });
2728
2758
  };
2729
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
2730
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
2759
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
2760
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
2731
2761
  paintRow("fill", "Fill"),
2732
2762
  paintRow("stroke", "Stroke"),
2733
- style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorGradientEditor, { controller }),
2734
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2735
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Width" }),
2736
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2763
+ style && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorGradientEditor, { controller }),
2764
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2765
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Width" }),
2766
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2737
2767
  "input",
2738
2768
  {
2739
2769
  type: "number",
@@ -2749,33 +2779,33 @@ function VectorStylePanel({ controller, className }) {
2749
2779
  }
2750
2780
  )
2751
2781
  ] }),
2752
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
2753
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Align" }),
2754
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass13, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector18.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: a, children: import_vector18.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
2782
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
2783
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Align" }),
2784
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass14, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector19.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: a, children: import_vector19.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
2755
2785
  mixed("strokeAlign")
2756
2786
  ] }),
2757
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
2758
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Profile" }),
2759
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2787
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
2788
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Profile" }),
2789
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2760
2790
  "select",
2761
2791
  {
2762
2792
  "aria-label": "Width profile",
2763
- className: selectClass13,
2793
+ className: selectClass14,
2764
2794
  value: source.widthProfile,
2765
2795
  onChange: (e) => {
2766
2796
  if (e.target.value !== "custom") setProfile(e.target.value);
2767
2797
  },
2768
2798
  children: [
2769
- import_vector18.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: p.id, children: p.label }, p.id)),
2770
- source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
2799
+ import_vector19.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: p.id, children: p.label }, p.id)),
2800
+ source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
2771
2801
  ]
2772
2802
  }
2773
2803
  ),
2774
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2804
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2775
2805
  "button",
2776
2806
  {
2777
2807
  type: "button",
2778
- className: buttonClass15,
2808
+ className: buttonClass16,
2779
2809
  title: "Reset to uniform width",
2780
2810
  "aria-label": "Reset to uniform width",
2781
2811
  disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
@@ -2785,20 +2815,20 @@ function VectorStylePanel({ controller, className }) {
2785
2815
  ),
2786
2816
  mixed("widthProfile")
2787
2817
  ] }),
2788
- source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2818
+ source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2789
2819
  arrowRow("start", "Start"),
2790
2820
  arrowRow("end", "End"),
2791
- (source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
2792
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Heads" }),
2793
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass13, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
2794
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "extend", children: "Tip past end" }),
2795
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "tip", children: "Tip at end" })
2821
+ (source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
2822
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Heads" }),
2823
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass14, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
2824
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "extend", children: "Tip past end" }),
2825
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "tip", children: "Tip at end" })
2796
2826
  ] })
2797
2827
  ] })
2798
2828
  ] }),
2799
- source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
2800
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
2801
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2829
+ source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
2830
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2802
2832
  "input",
2803
2833
  {
2804
2834
  type: "number",
@@ -2813,12 +2843,12 @@ function VectorStylePanel({ controller, className }) {
2813
2843
  }
2814
2844
  }
2815
2845
  ),
2816
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Corner kind", className: selectClass13, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector18.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: k, children: import_vector18.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
2846
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Corner kind", className: selectClass14, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector19.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: k, children: import_vector19.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
2817
2847
  mixed("cornerRadius")
2818
2848
  ] }),
2819
- style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.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: [
2820
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Smoothing" }),
2821
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2849
+ style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "corner-smoothing", title: "Corner smoothing: squircle corners that ease into the curve (0.6 is iOS-like)", children: [
2850
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Smoothing" }),
2851
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2822
2852
  "input",
2823
2853
  {
2824
2854
  type: "range",
@@ -2833,9 +2863,9 @@ function VectorStylePanel({ controller, className }) {
2833
2863
  }
2834
2864
  )
2835
2865
  ] }),
2836
- style && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2837
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Opacity" }),
2838
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2866
+ style && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
2867
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Opacity" }),
2868
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2839
2869
  "input",
2840
2870
  {
2841
2871
  type: "range",
@@ -2849,20 +2879,21 @@ function VectorStylePanel({ controller, className }) {
2849
2879
  }
2850
2880
  )
2851
2881
  ] }),
2852
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorTextPanel, { controller }),
2853
- style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorAppearancePanel, { controller }),
2854
- style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorEffectsPanel, { controller }),
2855
- style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorEnvelopePanel, { controller }),
2856
- style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorMaskPanel, { controller }),
2857
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorFramePanel, { controller }),
2858
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorConnectorPanel, { controller }),
2859
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorShadingPanel, { controller }),
2860
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorSymmetryPanel, { controller }),
2861
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorPerspectivePanel, { controller }),
2862
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorLensPanel, { controller }),
2863
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorTracePanel, { controller }),
2864
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorConstraintsPanel, { controller }),
2865
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorSymbolsPanel, { controller })
2882
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorTextPanel, { controller }),
2883
+ style && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorAppearancePanel, { controller }),
2884
+ style && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorEffectsPanel, { controller }),
2885
+ style && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorEnvelopePanel, { controller }),
2886
+ style && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorMaskPanel, { controller }),
2887
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorFramePanel, { controller }),
2888
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorPagesPanel, { controller }),
2889
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorConnectorPanel, { controller }),
2890
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorShadingPanel, { controller }),
2891
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorSymmetryPanel, { controller }),
2892
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorPerspectivePanel, { controller }),
2893
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorLensPanel, { controller }),
2894
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorTracePanel, { controller }),
2895
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorConstraintsPanel, { controller }),
2896
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(VectorSymbolsPanel, { controller })
2866
2897
  ] });
2867
2898
  }
2868
2899
 
@@ -2894,7 +2925,7 @@ function useEffectDescription(provider, effect) {
2894
2925
  // src/effects/EffectThumbnail.tsx
2895
2926
  var import_react13 = require("react");
2896
2927
  var import_effects = require("@pixerate/editor/effects");
2897
- var import_jsx_runtime19 = require("react/jsx-runtime");
2928
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2898
2929
  function EffectThumbnail({ provider, effect, width = 96, height = 54, className = "" }) {
2899
2930
  const ref = (0, import_react13.useRef)(null);
2900
2931
  const [failed, setFailed] = (0, import_react13.useState)(effect.kind === "motion");
@@ -2913,13 +2944,13 @@ function EffectThumbnail({ provider, effect, width = 96, height = 54, className
2913
2944
  live = false;
2914
2945
  };
2915
2946
  }, [provider, effect, width, height]);
2916
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2947
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2917
2948
  "div",
2918
2949
  {
2919
2950
  className: `relative overflow-hidden rounded border border-border bg-[repeating-conic-gradient(#8884_0_25%,transparent_0_50%)] bg-[length:12px_12px] ${className}`,
2920
2951
  style: { aspectRatio: `${width} / ${height}` },
2921
2952
  "data-effect-thumbnail": effect.id,
2922
- children: failed ? /* @__PURE__ */ (0, import_jsx_runtime19.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_runtime19.jsx)("canvas", { ref, width, height, className: "h-full w-full", "aria-hidden": "true" })
2953
+ children: failed ? /* @__PURE__ */ (0, import_jsx_runtime20.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_runtime20.jsx)("canvas", { ref, width, height, className: "h-full w-full", "aria-hidden": "true" })
2923
2954
  }
2924
2955
  );
2925
2956
  }
@@ -2927,7 +2958,7 @@ function EffectThumbnail({ provider, effect, width = 96, height = 54, className
2927
2958
  // src/effects/EffectsBrowser.tsx
2928
2959
  var import_react14 = require("react");
2929
2960
  var import_effects2 = require("@pixerate/editor/effects");
2930
- var import_jsx_runtime20 = require("react/jsx-runtime");
2961
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2931
2962
  function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, title = "Effects", className = "" }) {
2932
2963
  const [all, setAll] = (0, import_react14.useState)([]);
2933
2964
  const [query, setQuery] = (0, import_react14.useState)("");
@@ -2958,11 +2989,11 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
2958
2989
  const categories = (0, import_react14.useMemo)(() => [...new Set(all.filter(allowed).map((e) => e.category))], [all, uses, kinds]);
2959
2990
  const shown = found.filter(allowed);
2960
2991
  if (!provider)
2961
- return /* @__PURE__ */ (0, import_jsx_runtime20.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." });
2962
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { className: `flex flex-col gap-2 ${className}`, "data-effects-browser": "", "aria-label": "Effects browser", children: [
2963
- title && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { className: "text-xs font-semibold", children: title }),
2964
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
2965
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2992
+ return /* @__PURE__ */ (0, import_jsx_runtime21.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." });
2993
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: `flex flex-col gap-2 ${className}`, "data-effects-browser": "", "aria-label": "Effects browser", children: [
2994
+ title && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { className: "text-xs font-semibold", children: title }),
2995
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
2996
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2966
2997
  "input",
2967
2998
  {
2968
2999
  type: "search",
@@ -2973,17 +3004,17 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
2973
3004
  onChange: (e) => setQuery(e.currentTarget.value)
2974
3005
  }
2975
3006
  ),
2976
- /* @__PURE__ */ (0, import_jsx_runtime20.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: [
2977
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "", children: "All categories" }),
2978
- categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: c, children: c }, c))
3007
+ /* @__PURE__ */ (0, import_jsx_runtime21.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: [
3008
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "", children: "All categories" }),
3009
+ categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: c, children: c }, c))
2979
3010
  ] }),
2980
- uses && uses.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime20.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: [
2981
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "", children: "Any use" }),
2982
- uses.map((u) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: u, children: import_effects2.EFFECT_USE_LABELS[u] }, u))
3011
+ uses && uses.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime21.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: [
3012
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "", children: "Any use" }),
3013
+ uses.map((u) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: u, children: import_effects2.EFFECT_USE_LABELS[u] }, u))
2983
3014
  ] })
2984
3015
  ] }),
2985
- error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: error }),
2986
- /* @__PURE__ */ (0, import_jsx_runtime20.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_runtime20.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3016
+ error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: error }),
3017
+ /* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2987
3018
  "button",
2988
3019
  {
2989
3020
  type: "button",
@@ -2992,13 +3023,13 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
2992
3023
  "data-effect-id": e.id,
2993
3024
  onClick: () => onPick(e),
2994
3025
  children: [
2995
- thumbnails && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EffectThumbnail, { provider, effect: e }),
2996
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-[11px] font-medium", children: e.name }),
2997
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-[10px] text-muted-foreground", children: e.uses.map((u) => import_effects2.EFFECT_USE_LABELS[u]).join(" \xB7 ") })
3026
+ thumbnails && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EffectThumbnail, { provider, effect: e }),
3027
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "truncate text-[11px] font-medium", children: e.name }),
3028
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "truncate text-[10px] text-muted-foreground", children: e.uses.map((u) => import_effects2.EFFECT_USE_LABELS[u]).join(" \xB7 ") })
2998
3029
  ]
2999
3030
  }
3000
3031
  ) }, e.id)) }),
3001
- !shown.length && !error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects match." })
3032
+ !shown.length && !error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects match." })
3002
3033
  ] });
3003
3034
  }
3004
3035
 
@@ -3010,7 +3041,7 @@ var import_parameters2 = require("@pixerate/editor/parameters");
3010
3041
  // src/parameters/fields.tsx
3011
3042
  var import_react15 = require("react");
3012
3043
  var import_parameters = require("@pixerate/editor/parameters");
3013
- var import_jsx_runtime21 = require("react/jsx-runtime");
3044
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3014
3045
  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";
3015
3046
  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";
3016
3047
  var rangeClass = "h-4 w-full min-w-0 flex-1 cursor-pointer accent-primary disabled:cursor-not-allowed disabled:opacity-50";
@@ -3034,7 +3065,7 @@ function ParameterCommitInput({ value, onCommit, multiline, className, onKeyDown
3034
3065
  onKeyDown: keyDown,
3035
3066
  ...rest
3036
3067
  };
3037
- return multiline ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { ...props, className: `${props.className} h-auto min-h-[3.5rem] py-1` }, value) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "text", ...props }, value);
3068
+ return multiline ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("textarea", { ...props, className: `${props.className} h-auto min-h-[3.5rem] py-1` }, value) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { type: "text", ...props }, value);
3038
3069
  }
3039
3070
  var plainNumber = (field, value) => (0, import_parameters.formatParameterNumber)({ ...field, unit: void 0 }, value);
3040
3071
  function ParameterNumberInput({
@@ -3045,8 +3076,8 @@ function ParameterNumberInput({
3045
3076
  id,
3046
3077
  "aria-label": ariaLabel
3047
3078
  }) {
3048
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
3049
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3079
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
3080
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3050
3081
  ParameterCommitInput,
3051
3082
  {
3052
3083
  id,
@@ -3068,7 +3099,7 @@ function ParameterNumberInput({
3068
3099
  }
3069
3100
  }
3070
3101
  ),
3071
- field.unit && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground", children: field.unit })
3102
+ field.unit && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground", children: field.unit })
3072
3103
  ] });
3073
3104
  }
3074
3105
  function ParameterSlider(props) {
@@ -3079,10 +3110,10 @@ function ParameterSlider(props) {
3079
3110
  dragging.current = false;
3080
3111
  onGestureEnd?.();
3081
3112
  };
3082
- if (!(0, import_parameters.isSliderField)(field)) return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterNumberInput, { ...props });
3113
+ if (!(0, import_parameters.isSliderField)(field)) return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterNumberInput, { ...props });
3083
3114
  const step = (0, import_parameters.parameterStep)(field);
3084
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
3085
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3115
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", children: [
3116
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3086
3117
  "input",
3087
3118
  {
3088
3119
  type: "range",
@@ -3105,11 +3136,11 @@ function ParameterSlider(props) {
3105
3136
  onChange: (e) => onChange((0, import_parameters.clampParameterNumber)(field, Number(e.target.value)))
3106
3137
  }
3107
3138
  ),
3108
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterNumberInput, { ...props, id: props.id, "aria-label": `${(0, import_parameters.parameterLabel)(field)} value` }) })
3139
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterNumberInput, { ...props, id: props.id, "aria-label": `${(0, import_parameters.parameterLabel)(field)} value` }) })
3109
3140
  ] });
3110
3141
  }
3111
3142
  function ParameterToggle({ field, value, onChange, disabled, id }) {
3112
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3143
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3113
3144
  "button",
3114
3145
  {
3115
3146
  type: "button",
@@ -3120,7 +3151,7 @@ function ParameterToggle({ field, value, onChange, disabled, id }) {
3120
3151
  disabled: disabled || field.readOnly,
3121
3152
  onClick: () => onChange(!value),
3122
3153
  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"}`,
3123
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3154
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3124
3155
  "span",
3125
3156
  {
3126
3157
  className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow transition-transform ${value ? "translate-x-4" : "translate-x-0.5"}`
@@ -3133,7 +3164,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
3133
3164
  const options = (0, import_parameters.getChoiceOptions)(field);
3134
3165
  const off = disabled || field.readOnly;
3135
3166
  if (field.control === "segmented") {
3136
- return /* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.jsx)(
3167
+ return /* @__PURE__ */ (0, import_jsx_runtime22.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_runtime22.jsx)(
3137
3168
  "button",
3138
3169
  {
3139
3170
  type: "button",
@@ -3149,7 +3180,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
3149
3180
  )) });
3150
3181
  }
3151
3182
  const index = options.findIndex((o) => o.value === value);
3152
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3183
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3153
3184
  "select",
3154
3185
  {
3155
3186
  id,
@@ -3161,7 +3192,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
3161
3192
  if (option) onChange(option.value);
3162
3193
  },
3163
3194
  className: parameterInputClass,
3164
- children: options.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: String(i), title: o.description, children: (0, import_parameters.choiceOptionLabel)(o) }, String(o.value)))
3195
+ children: options.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: String(i), title: o.description, children: (0, import_parameters.choiceOptionLabel)(o) }, String(o.value)))
3165
3196
  }
3166
3197
  );
3167
3198
  }
@@ -3182,11 +3213,11 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3182
3213
  picking.current = false;
3183
3214
  onGestureEnd?.();
3184
3215
  };
3185
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-1.5", children: [
3186
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
3187
- /* @__PURE__ */ (0, import_jsx_runtime21.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: [
3188
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "absolute inset-0", style: { background: alpha ? hex : rgb } }),
3189
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3216
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-1.5", children: [
3217
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", children: [
3218
+ /* @__PURE__ */ (0, import_jsx_runtime22.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: [
3219
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "absolute inset-0", style: { background: alpha ? hex : rgb } }),
3220
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3190
3221
  "input",
3191
3222
  {
3192
3223
  type: "color",
@@ -3202,7 +3233,7 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3202
3233
  }
3203
3234
  )
3204
3235
  ] }),
3205
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3236
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3206
3237
  ParameterCommitInput,
3207
3238
  {
3208
3239
  id,
@@ -3218,7 +3249,7 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3218
3249
  }
3219
3250
  )
3220
3251
  ] }),
3221
- alpha && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3252
+ alpha && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3222
3253
  "input",
3223
3254
  {
3224
3255
  type: "range",
@@ -3236,10 +3267,10 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3236
3267
  onChange: (e) => onChange(`${rgb}${Number(e.target.value).toString(16).padStart(2, "0")}`)
3237
3268
  }
3238
3269
  ),
3239
- field.swatches && field.swatches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex flex-wrap gap-1", children: field.swatches.map((s) => {
3270
+ field.swatches && field.swatches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-wrap gap-1", children: field.swatches.map((s) => {
3240
3271
  const swatch = (0, import_parameters.normalizeHexColor)(s, alpha);
3241
3272
  if (!swatch) return null;
3242
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3273
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3243
3274
  "button",
3244
3275
  {
3245
3276
  type: "button",
@@ -3258,11 +3289,11 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
3258
3289
  }
3259
3290
  function ParameterVector({ field, value, onChange, disabled, id }) {
3260
3291
  const size = (0, import_parameters.vectorSize)(field);
3261
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "grid gap-1.5", style: { gridTemplateColumns: `repeat(${size}, minmax(0, 1fr))` }, children: Array.from({ length: size }, (_, i) => {
3292
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "grid gap-1.5", style: { gridTemplateColumns: `repeat(${size}, minmax(0, 1fr))` }, children: Array.from({ length: size }, (_, i) => {
3262
3293
  const component = (0, import_parameters.vectorComponentField)(field, i);
3263
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex min-w-0 items-center gap-1", children: [
3264
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-3 shrink-0 text-[10px] uppercase text-muted-foreground", children: component.label }),
3265
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3294
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex min-w-0 items-center gap-1", children: [
3295
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-3 shrink-0 text-[10px] uppercase text-muted-foreground", children: component.label }),
3296
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3266
3297
  ParameterNumberInput,
3267
3298
  {
3268
3299
  field: component,
@@ -3279,11 +3310,11 @@ function ParameterVector({ field, value, onChange, disabled, id }) {
3279
3310
  function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3280
3311
  const off = disabled || field.readOnly;
3281
3312
  const name = (0, import_parameters.parameterLabel)(field);
3282
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-1.5", children: [
3283
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
3284
- /* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.jsx)("img", { src: value, alt: name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "None" }) }),
3285
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
3286
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3313
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-1.5", children: [
3314
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", children: [
3315
+ /* @__PURE__ */ (0, import_jsx_runtime22.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_runtime22.jsx)("img", { src: value, alt: name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "None" }) }),
3316
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
3317
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3287
3318
  ParameterCommitInput,
3288
3319
  {
3289
3320
  id,
@@ -3294,10 +3325,10 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3294
3325
  onCommit: (text) => onChange(text.trim())
3295
3326
  }
3296
3327
  ),
3297
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex gap-1", children: [
3298
- resolveFile && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: `${parameterButtonClass} cursor-pointer ${off ? "pointer-events-none opacity-50" : ""}`, children: [
3328
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex gap-1", children: [
3329
+ resolveFile && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: `${parameterButtonClass} cursor-pointer ${off ? "pointer-events-none opacity-50" : ""}`, children: [
3299
3330
  "Choose file\u2026",
3300
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3331
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3301
3332
  "input",
3302
3333
  {
3303
3334
  type: "file",
@@ -3313,11 +3344,11 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3313
3344
  }
3314
3345
  )
3315
3346
  ] }),
3316
- value && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: parameterButtonClass, disabled: off, onClick: () => onChange(""), "aria-label": `Clear ${name}`, children: "Clear" })
3347
+ value && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: parameterButtonClass, disabled: off, onClick: () => onChange(""), "aria-label": `Clear ${name}`, children: "Clear" })
3317
3348
  ] })
3318
3349
  ] })
3319
3350
  ] }),
3320
- field.options && field.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex flex-wrap gap-1", children: field.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3351
+ field.options && field.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-wrap gap-1", children: field.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3321
3352
  "button",
3322
3353
  {
3323
3354
  type: "button",
@@ -3327,14 +3358,14 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
3327
3358
  disabled: off,
3328
3359
  onClick: () => onChange(o.url),
3329
3360
  className: "h-9 w-12 overflow-hidden rounded border border-input aria-pressed:ring-2 aria-pressed:ring-primary",
3330
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("img", { src: o.url, alt: "", className: "h-full w-full object-cover" })
3361
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("img", { src: o.url, alt: "", className: "h-full w-full object-cover" })
3331
3362
  },
3332
3363
  o.url
3333
3364
  )) })
3334
3365
  ] });
3335
3366
  }
3336
3367
  function ParameterText({ field, value, onChange, disabled, id }) {
3337
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3368
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3338
3369
  ParameterCommitInput,
3339
3370
  {
3340
3371
  id,
@@ -3353,31 +3384,31 @@ function ParameterFieldControl({ field, value, onChange, resolveFile, ...rest })
3353
3384
  switch (field.type) {
3354
3385
  case "number":
3355
3386
  case "int":
3356
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterSlider, { field, value, onChange: set, ...rest });
3387
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterSlider, { field, value, onChange: set, ...rest });
3357
3388
  case "boolean":
3358
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterToggle, { field, value, onChange: set, ...rest });
3389
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterToggle, { field, value, onChange: set, ...rest });
3359
3390
  case "choice":
3360
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterSelect, { field, value, onChange: set, ...rest });
3391
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterSelect, { field, value, onChange: set, ...rest });
3361
3392
  case "color":
3362
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterColor, { field, value, onChange: set, ...rest });
3393
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterColor, { field, value, onChange: set, ...rest });
3363
3394
  case "vector":
3364
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterVector, { field, value, onChange: set, ...rest });
3395
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterVector, { field, value, onChange: set, ...rest });
3365
3396
  case "image":
3366
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterImage, { field, value, onChange: set, resolveFile, ...rest });
3397
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterImage, { field, value, onChange: set, resolveFile, ...rest });
3367
3398
  case "text":
3368
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterText, { field, value, onChange: set, ...rest });
3399
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ParameterText, { field, value, onChange: set, ...rest });
3369
3400
  }
3370
3401
  }
3371
3402
 
3372
3403
  // src/effects/EffectParameters.tsx
3373
- var import_jsx_runtime22 = require("react/jsx-runtime");
3404
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3374
3405
  function EffectParameters({ description, values, onChange, onReset, keyframed, onPreset, disabled = false, className = "" }) {
3375
3406
  const fields = (0, import_react16.useMemo)(() => (0, import_effects3.effectParameterFields)(description), [description]);
3376
3407
  const idBase = (0, import_react16.useId)();
3377
3408
  const gesture = import_react16.default.useRef(null);
3378
3409
  const count = import_react16.default.useRef(0);
3379
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `space-y-2 ${className}`, "data-effect-parameters": description.id, children: [
3380
- onPreset && description.presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
3410
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `space-y-2 ${className}`, "data-effect-parameters": description.id, children: [
3411
+ onPreset && description.presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3381
3412
  "select",
3382
3413
  {
3383
3414
  className: "w-full rounded border border-border bg-transparent px-1 py-0.5 text-xs",
@@ -3389,8 +3420,8 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
3389
3420
  if (preset) onPreset({ ...description.defaults, ...preset.values });
3390
3421
  },
3391
3422
  children: [
3392
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "", children: "Presets\u2026" }),
3393
- description.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: p.name, children: p.name }, p.name))
3423
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "", children: "Presets\u2026" }),
3424
+ description.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: p.name, children: p.name }, p.name))
3394
3425
  ]
3395
3426
  }
3396
3427
  ),
@@ -3400,13 +3431,13 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
3400
3431
  const keyed = keyframed?.has(field.id) ?? false;
3401
3432
  const value = (0, import_effects3.effectFieldValue)(field, values[field.id]);
3402
3433
  const changed = !keyed && !(0, import_parameters2.parameterValuesEqual)(value, field.default);
3403
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-1", "data-effect-control": field.id, children: [
3404
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3405
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { htmlFor: inputId, className: "min-w-0 flex-1 truncate text-xs font-medium", title: field.description, children: label }),
3406
- keyed && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "keyframed" }),
3407
- onReset && changed && !disabled && /* @__PURE__ */ (0, import_jsx_runtime22.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" })
3434
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-1", "data-effect-control": field.id, children: [
3435
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3436
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { htmlFor: inputId, className: "min-w-0 flex-1 truncate text-xs font-medium", title: field.description, children: label }),
3437
+ keyed && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "keyframed" }),
3438
+ onReset && changed && !disabled && /* @__PURE__ */ (0, import_jsx_runtime23.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" })
3408
3439
  ] }),
3409
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3440
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3410
3441
  ParameterFieldControl,
3411
3442
  {
3412
3443
  field,
@@ -3420,13 +3451,13 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
3420
3451
  )
3421
3452
  ] }, field.id);
3422
3453
  }),
3423
- !fields.length && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No controls." })
3454
+ !fields.length && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No controls." })
3424
3455
  ] });
3425
3456
  }
3426
3457
 
3427
3458
  // src/vector/VectorProviderEffectsPanel.tsx
3428
3459
  var import_react17 = require("react");
3429
- var import_jsx_runtime23 = require("react/jsx-runtime");
3460
+ var import_jsx_runtime24 = require("react/jsx-runtime");
3430
3461
  var btn = "rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40";
3431
3462
  function Controls({ controller, group }) {
3432
3463
  const provider = controller.effectsProvider;
@@ -3434,11 +3465,11 @@ function Controls({ controller, group }) {
3434
3465
  const { description, error } = useEffectDescription(provider, tag.effect);
3435
3466
  const [message, setMessage] = (0, import_react17.useState)(null);
3436
3467
  const run = (work) => void work.then(() => setMessage(null), (e) => setMessage(e instanceof Error ? e.message : String(e)));
3437
- if (!provider) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider: the shapes are kept as they are." });
3438
- if (error) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-amber-500", children: error });
3439
- if (!description) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Loading\u2026" });
3440
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
3441
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3468
+ if (!provider) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider: the shapes are kept as they are." });
3469
+ if (error) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-[11px] text-amber-500", children: error });
3470
+ if (!description) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Loading\u2026" });
3471
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
3472
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3442
3473
  EffectParameters,
3443
3474
  {
3444
3475
  description,
@@ -3448,7 +3479,7 @@ function Controls({ controller, group }) {
3448
3479
  onPreset: (v) => run(controller.updateVectorEffect(group.id, v))
3449
3480
  }
3450
3481
  ),
3451
- message && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3482
+ message && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3452
3483
  ] });
3453
3484
  }
3454
3485
  function VectorProviderEffectsPanel({ controller, className = "" }) {
@@ -3467,41 +3498,41 @@ function VectorProviderEffectsPanel({ controller, className = "" }) {
3467
3498
  setMessage(null);
3468
3499
  Promise.resolve().then(work).catch((e) => setMessage(e instanceof Error ? e.message : String(e)));
3469
3500
  };
3470
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Vector effects", "data-vector-provider-effects": "", children: [
3471
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1", children: [
3472
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "flex-1 font-semibold", children: "Effects" }),
3473
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn, disabled: !provider, "aria-pressed": browse, onClick: () => setBrowse(!browse), children: "Add effect\u2026" })
3501
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Vector effects", "data-vector-provider-effects": "", children: [
3502
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-1", children: [
3503
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "flex-1 font-semibold", children: "Effects" }),
3504
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: btn, disabled: !provider, "aria-pressed": browse, onClick: () => setBrowse(!browse), children: "Add effect\u2026" })
3474
3505
  ] }),
3475
- !provider && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider is registered. Effect groups are kept as shapes." }),
3476
- browse && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EffectsBrowser, { provider, kinds: ["vector"], title: "Vector effects", onPick: (e) => (setBrowse(false), run(() => controller.addVectorEffect(e.id))) }),
3477
- selected.map((g) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-1 rounded border border-border p-1", "data-vector-effect-group": g.id, children: [
3478
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1", children: [
3479
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: g.providerEffect.name ?? g.providerEffect.effect }),
3480
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn, title: "Keep the shapes as a plain group", onClick: () => run(() => controller.detachVectorEffect(g.id)), children: "Detach" })
3506
+ !provider && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider is registered. Effect groups are kept as shapes." }),
3507
+ browse && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(EffectsBrowser, { provider, kinds: ["vector"], title: "Vector effects", onPick: (e) => (setBrowse(false), run(() => controller.addVectorEffect(e.id))) }),
3508
+ selected.map((g) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "space-y-1 rounded border border-border p-1", "data-vector-effect-group": g.id, children: [
3509
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-1", children: [
3510
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: g.providerEffect.name ?? g.providerEffect.effect }),
3511
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: btn, title: "Keep the shapes as a plain group", onClick: () => run(() => controller.detachVectorEffect(g.id)), children: "Detach" })
3481
3512
  ] }),
3482
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Controls, { controller, group: g })
3513
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Controls, { controller, group: g })
3483
3514
  ] }, g.id)),
3484
- groups.length > 0 && !selected.length && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
3515
+ groups.length > 0 && !selected.length && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
3485
3516
  "Select an effect group (",
3486
3517
  groups.length,
3487
3518
  " in the drawing) to change it."
3488
3519
  ] }),
3489
- message && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3520
+ message && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
3490
3521
  ] });
3491
3522
  }
3492
3523
 
3493
3524
  // src/vector/VectorEditor.tsx
3494
- var import_jsx_runtime24 = require("react/jsx-runtime");
3525
+ var import_jsx_runtime25 = require("react/jsx-runtime");
3495
3526
  function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, effects, className }) {
3496
3527
  useEffects(controller, effects);
3497
3528
  const effectsShown = !!effects || controller.vectorEffectGroups().length > 0;
3498
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
3499
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(VectorToolbar, { controller, tools }),
3500
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
3501
- /* @__PURE__ */ (0, import_jsx_runtime24.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_runtime24.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
3502
- showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex w-full shrink-0 flex-col gap-2 md:w-56", children: [
3503
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(VectorStylePanel, { controller, className: "rounded-md border border-border p-3" }),
3504
- effectsShown && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(VectorProviderEffectsPanel, { controller, className: "rounded-md border border-border p-3" })
3529
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
3530
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VectorToolbar, { controller, tools }),
3531
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
3532
+ /* @__PURE__ */ (0, import_jsx_runtime25.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_runtime25.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
3533
+ showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex w-full shrink-0 flex-col gap-2 md:w-56", children: [
3534
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VectorStylePanel, { controller, className: "rounded-md border border-border p-3" }),
3535
+ effectsShown && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VectorProviderEffectsPanel, { controller, className: "rounded-md border border-border p-3" })
3505
3536
  ] })
3506
3537
  ] })
3507
3538
  ] });
@@ -3523,6 +3554,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
3523
3554
  VectorLensPanel,
3524
3555
  VectorMaskPanel,
3525
3556
  VectorMaskedNodes,
3557
+ VectorPagesPanel,
3526
3558
  VectorPerspectivePanel,
3527
3559
  VectorProviderEffectsPanel,
3528
3560
  VectorSceneNodes,