@pixerate/editor-react 0.18.1 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,7 +51,9 @@ export function Document() {
51
51
  const editor = useEditor({ content: "<p>Hello</p>", richTextOptions: { markdown: true } });
52
52
  return (
53
53
  <>
54
- <BubbleMenu editor={editor}>{/* your formatting buttons */}</BubbleMenu>
54
+ <BubbleMenu editor={editor}>
55
+ <button onClick={() => editor?.chain().focus().toggleBold().run()}>Bold</button>
56
+ </BubbleMenu>
55
57
  <EditorContent editor={editor} />
56
58
  </>
57
59
  );
@@ -100,6 +102,8 @@ useAgentToolProvider(registry, provider);
100
102
  | `@pixerate/editor-react/generation` | `GenerationSettings` (controls generated from a model's capabilities, reference slots by role, plan adjustments), `useGenerationPlan`, `JobProgress`, `useJobProgress` over `@pixerate/editor/generation` (also re-exported from the root entry) |
101
103
  | `@pixerate/editor-react/canvas` | `useCanvasGraph`, `useCanvasLayout`, `useCanvasClipboard`, `useCanvasDocking`, `useCanvasShortcuts`, `useCanvasExplosion`, `useStreamingCanvas`, `AgentPresenceLayer`, plus the pure layout helpers from `@pixerate/editor/canvas` |
102
104
 
105
+ Spreadsheet persistence: `useSpreadsheetEditor` exposes `document` (and passes it to `onDocumentChange`) with the defined names its formulas use in `document.names`, so saving that document and passing it back as `document` restores workbook, sheet-scoped and LAMBDA names. For several sheets, save `controller.getWorkbook()` instead.
106
+
103
107
  ## Styling (Tailwind CSS required)
104
108
 
105
109
  The components are styled with [Tailwind CSS](https://tailwindcss.com) utility classes and ship no stylesheet of their own. To style them:
@@ -53,6 +53,7 @@ __export(canvas_exports, {
53
53
  TOKEN_MODES_DATA_KEY: () => import_canvas23.TOKEN_MODES_DATA_KEY,
54
54
  TokenBindingPicker: () => TokenBindingPicker,
55
55
  TokenModeSwitcher: () => TokenModeSwitcher,
56
+ addCanvasVariant: () => import_canvas25.addCanvasVariant,
56
57
  addKeyframesAtTime: () => import_canvas24.addKeyframesAtTime,
57
58
  alignNodes: () => import_canvas18.alignNodes,
58
59
  animateNode: () => import_canvas24.animateNode,
@@ -158,6 +159,7 @@ __export(canvas_exports, {
158
159
  getLayoutParent: () => import_canvas22.getLayoutParent,
159
160
  getLayoutSizing: () => import_canvas22.getLayoutSizing,
160
161
  getLayoutedNodes: () => import_canvas21.getLayoutedNodes,
162
+ getNextVariantValues: () => import_canvas25.getNextVariantValues,
161
163
  getNodeAnimation: () => import_canvas24.getNodeAnimation,
162
164
  getNodeOverrides: () => import_canvas25.getNodeOverrides,
163
165
  getNodeRect: () => import_canvas18.getNodeRect,
@@ -256,7 +258,10 @@ __export(canvas_exports, {
256
258
  recordAnimationChanges: () => import_canvas24.recordAnimationChanges,
257
259
  relayoutUpdates: () => import_canvas22.relayoutUpdates,
258
260
  remapPastedNodes: () => import_canvas21.remapPastedNodes,
261
+ removeCanvasVariant: () => import_canvas25.removeCanvasVariant,
259
262
  removeTrack: () => import_canvas24.removeTrack,
263
+ renameCanvasVariantProperty: () => import_canvas25.renameCanvasVariantProperty,
264
+ renameCanvasVariantValue: () => import_canvas25.renameCanvasVariantValue,
260
265
  reorderNodes: () => import_canvas18.reorderNodes,
261
266
  repositionNodesTo: () => import_canvas21.repositionNodesTo,
262
267
  resetCanvasInstanceOverrides: () => import_canvas25.resetCanvasInstanceOverrides,
@@ -275,6 +280,7 @@ __export(canvas_exports, {
275
280
  setCanvasComponentProperty: () => import_canvas25.setCanvasComponentProperty,
276
281
  setCanvasInstanceProperties: () => import_canvas25.setCanvasInstanceProperties,
277
282
  setCanvasTokenMode: () => import_canvas23.setCanvasTokenMode,
283
+ setCanvasVariantProperties: () => import_canvas25.setCanvasVariantProperties,
278
284
  setKeyframe: () => import_canvas24.setKeyframe,
279
285
  setKeyframeEasing: () => import_canvas24.setKeyframeEasing,
280
286
  setMotionPath: () => import_canvas24.setMotionPath,
@@ -1909,28 +1915,64 @@ function useCanvasComponents(options) {
1909
1915
  var import_react16 = require("react");
1910
1916
  var import_canvas16 = require("@pixerate/editor/canvas");
1911
1917
  var import_jsx_runtime6 = require("react/jsx-runtime");
1918
+ function InlineField({ value, label, onCommit }) {
1919
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1920
+ "input",
1921
+ {
1922
+ type: "text",
1923
+ "aria-label": label,
1924
+ defaultValue: value,
1925
+ className: "min-w-0 flex-1 rounded border border-border bg-background px-1 py-0.5 text-xs",
1926
+ onBlur: (e) => {
1927
+ const next = e.currentTarget.value.trim();
1928
+ if (next && next !== value) onCommit(next);
1929
+ else e.currentTarget.value = value;
1930
+ },
1931
+ onKeyDown: (e) => {
1932
+ if (e.key === "Enter") e.currentTarget.blur();
1933
+ if (e.key === "Escape") {
1934
+ e.currentTarget.value = value;
1935
+ e.currentTarget.blur();
1936
+ }
1937
+ }
1938
+ },
1939
+ value
1940
+ );
1941
+ }
1912
1942
  function CanvasComponentsPanel({
1913
1943
  nodes,
1914
1944
  onInsert,
1945
+ components,
1946
+ onError,
1915
1947
  search = true,
1916
1948
  className = ""
1917
1949
  }) {
1918
1950
  const [query, setQuery] = (0, import_react16.useState)("");
1919
- const { components, sets } = (0, import_canvas16.listCanvasComponents)(nodes);
1951
+ const [propsOpen, setPropsOpen] = (0, import_react16.useState)(null);
1952
+ const [menuFor, setMenuFor] = (0, import_react16.useState)(null);
1953
+ const [editing, setEditing] = (0, import_react16.useState)(null);
1954
+ const { components: all, sets } = (0, import_canvas16.listCanvasComponents)(nodes);
1920
1955
  const q = query.trim().toLowerCase();
1921
1956
  const match = (name) => !q || name.toLowerCase().includes(q);
1922
- const lone = components.filter((c) => !c.setId && match(c.name));
1957
+ const lone = all.filter((c) => !c.setId && match(c.name));
1923
1958
  const shownSets = sets.filter((s) => match(s.name) || s.variants.some((v) => match(v.name)));
1924
- const item = (id, name, count, extra = {}) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1959
+ const report = (result) => {
1960
+ if (result && !result.ok && result.reason) onError?.(result.reason);
1961
+ return !!result?.ok;
1962
+ };
1963
+ const small = "shrink-0 rounded px-1 text-[10px] text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40";
1964
+ const menuItem = "rounded px-2 py-0.5 text-left hover:bg-muted disabled:opacity-40";
1965
+ const item = (id, name, count, extra = {}, onContextMenu) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1925
1966
  "button",
1926
1967
  {
1927
1968
  type: "button",
1928
1969
  draggable: true,
1929
1970
  "data-component-id": id,
1930
1971
  ...extra,
1931
- className: "flex w-full items-center justify-between gap-2 rounded px-2 py-1 text-left text-xs hover:bg-muted",
1972
+ className: "flex w-full min-w-0 items-center justify-between gap-2 rounded px-2 py-1 text-left text-xs hover:bg-muted",
1932
1973
  title: `Insert an instance of ${name}`,
1933
1974
  onClick: () => onInsert(id),
1975
+ onContextMenu,
1934
1976
  onDragStart: (e) => {
1935
1977
  e.dataTransfer.setData(import_canvas16.CANVAS_COMPONENT_DRAG_TYPE, id);
1936
1978
  e.dataTransfer.setData("text/plain", name);
@@ -1958,11 +2000,165 @@ function CanvasComponentsPanel({
1958
2000
  }
1959
2001
  ) : null,
1960
2002
  shownSets.map((set) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-component-set": set.id, className: "flex flex-col", children: [
1961
- item(set.id, set.name, set.variants.reduce((sum, v) => sum + v.instanceCount, 0), { "data-kind": "set" }),
1962
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ml-3 flex flex-col border-l border-border pl-1", children: set.variants.map((v) => item(v.id, v.name, v.instanceCount, { "data-kind": "variant" })) })
2003
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1", children: [
2004
+ item(set.id, set.name, set.variants.reduce((sum, v) => sum + v.instanceCount, 0), { "data-kind": "set" }),
2005
+ components ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2006
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2007
+ "button",
2008
+ {
2009
+ type: "button",
2010
+ className: small,
2011
+ "data-action": "add-variant",
2012
+ "aria-label": `Add a variant to ${set.name}`,
2013
+ title: "Add a variant (duplicates the default variant)",
2014
+ onClick: () => report(components.addVariant(set.id)),
2015
+ children: "+\xA0Variant"
2016
+ }
2017
+ ),
2018
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2019
+ "button",
2020
+ {
2021
+ type: "button",
2022
+ className: small,
2023
+ "data-action": "variant-properties",
2024
+ "aria-expanded": propsOpen === set.id,
2025
+ "aria-label": `Edit the variant properties of ${set.name}`,
2026
+ title: "Rename variant properties and values",
2027
+ onClick: () => setPropsOpen(propsOpen === set.id ? null : set.id),
2028
+ children: "\u2699"
2029
+ }
2030
+ )
2031
+ ] }) : null
2032
+ ] }),
2033
+ components && propsOpen === set.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-variant-properties": set.id, className: "ml-3 flex flex-col gap-1 border-l border-border py-1 pl-2", children: set.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-variant-option": option.name, className: "flex flex-col gap-0.5", children: [
2034
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2035
+ InlineField,
2036
+ {
2037
+ value: option.name,
2038
+ label: `Rename property ${option.name}`,
2039
+ onCommit: (next) => report(components.renameVariantProperty(option.name, next, set.id))
2040
+ }
2041
+ ),
2042
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ml-2 flex flex-wrap gap-1", children: option.values.map((value) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2043
+ InlineField,
2044
+ {
2045
+ value,
2046
+ label: `Rename ${option.name} value ${value}`,
2047
+ onCommit: (next) => report(components.renameVariantValue(option.name, value, next, set.id))
2048
+ },
2049
+ value
2050
+ )) })
2051
+ ] }, option.name)) }) : null,
2052
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ml-3 flex flex-col border-l border-border pl-1", children: set.variants.map((v) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-variant-row": v.id, className: "flex flex-col", children: [
2053
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1", children: [
2054
+ item(
2055
+ v.id,
2056
+ v.name,
2057
+ v.instanceCount,
2058
+ { "data-kind": "variant" },
2059
+ components ? (e) => {
2060
+ e.preventDefault();
2061
+ setMenuFor(v.id);
2062
+ } : void 0
2063
+ ),
2064
+ components ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2065
+ "button",
2066
+ {
2067
+ type: "button",
2068
+ className: small,
2069
+ "data-action": "variant-menu",
2070
+ "aria-haspopup": "menu",
2071
+ "aria-expanded": menuFor === v.id,
2072
+ "aria-label": `Variant actions for ${v.name}`,
2073
+ onClick: () => setMenuFor(menuFor === v.id ? null : v.id),
2074
+ children: "\u22EF"
2075
+ }
2076
+ ) : null
2077
+ ] }),
2078
+ components && menuFor === v.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "menu", "data-variant-menu": v.id, className: "ml-2 flex flex-col rounded border border-border bg-background p-1 shadow", children: [
2079
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2080
+ "button",
2081
+ {
2082
+ type: "button",
2083
+ role: "menuitem",
2084
+ className: menuItem,
2085
+ "data-action": "edit-variant",
2086
+ onClick: () => {
2087
+ setEditing(v.id);
2088
+ setMenuFor(null);
2089
+ },
2090
+ children: "Edit values\u2026"
2091
+ }
2092
+ ),
2093
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2094
+ "button",
2095
+ {
2096
+ type: "button",
2097
+ role: "menuitem",
2098
+ className: menuItem,
2099
+ "data-action": "duplicate-variant",
2100
+ onClick: () => {
2101
+ setMenuFor(null);
2102
+ report(components.addVariant(set.id, { from: v.id }));
2103
+ },
2104
+ children: "Duplicate"
2105
+ }
2106
+ ),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2108
+ "button",
2109
+ {
2110
+ type: "button",
2111
+ role: "menuitem",
2112
+ className: menuItem,
2113
+ "data-action": "remove-variant",
2114
+ disabled: set.variants.length < 2,
2115
+ title: set.variants.length < 2 ? "A component set needs at least one variant." : "Its instances switch to the closest variant",
2116
+ onClick: () => {
2117
+ setMenuFor(null);
2118
+ report(components.removeVariant(v.id));
2119
+ },
2120
+ children: "Remove variant"
2121
+ }
2122
+ )
2123
+ ] }) : null,
2124
+ components && editing === v.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2125
+ "form",
2126
+ {
2127
+ "data-variant-editor": v.id,
2128
+ className: "ml-2 flex flex-col gap-1 py-1",
2129
+ onSubmit: (e) => {
2130
+ e.preventDefault();
2131
+ const values = {};
2132
+ for (const input of e.currentTarget.querySelectorAll("input[data-variant-value]")) {
2133
+ values[input.dataset.variantValue] = input.value;
2134
+ }
2135
+ if (report(components.setVariantProperties(values, v.id))) setEditing(null);
2136
+ },
2137
+ children: [
2138
+ set.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-2", children: [
2139
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w-16 shrink-0 truncate text-muted-foreground", children: option.name }),
2140
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2141
+ "input",
2142
+ {
2143
+ type: "text",
2144
+ "data-variant-value": option.name,
2145
+ "aria-label": `${option.name} value`,
2146
+ defaultValue: v.variant?.[option.name] ?? "",
2147
+ className: "min-w-0 flex-1 rounded border border-border bg-background px-1 py-0.5 text-xs"
2148
+ }
2149
+ )
2150
+ ] }, option.name)),
2151
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex gap-1", children: [
2152
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "submit", className: "rounded border border-border px-2 py-0.5 hover:bg-muted", "data-action": "save-variant", children: "Save" }),
2153
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "rounded px-2 py-0.5 hover:bg-muted", "data-action": "cancel-variant", onClick: () => setEditing(null), children: "Cancel" })
2154
+ ] })
2155
+ ]
2156
+ }
2157
+ ) : null
2158
+ ] }, v.id)) })
1963
2159
  ] }, set.id)),
1964
2160
  lone.map((c) => item(c.id, c.name, c.instanceCount, { "data-kind": "component" })),
1965
- components.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-muted-foreground", children: "No components yet. Select a frame and choose Create Component." }) : null
2161
+ all.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-muted-foreground", children: "No components yet. Select a frame and choose Create Component." }) : null
1966
2162
  ] });
1967
2163
  }
1968
2164
  function CanvasInstanceInspector({
@@ -2117,6 +2313,7 @@ var import_canvas25 = require("@pixerate/editor/canvas");
2117
2313
  TOKEN_MODES_DATA_KEY,
2118
2314
  TokenBindingPicker,
2119
2315
  TokenModeSwitcher,
2316
+ addCanvasVariant,
2120
2317
  addKeyframesAtTime,
2121
2318
  alignNodes,
2122
2319
  animateNode,
@@ -2222,6 +2419,7 @@ var import_canvas25 = require("@pixerate/editor/canvas");
2222
2419
  getLayoutParent,
2223
2420
  getLayoutSizing,
2224
2421
  getLayoutedNodes,
2422
+ getNextVariantValues,
2225
2423
  getNodeAnimation,
2226
2424
  getNodeOverrides,
2227
2425
  getNodeRect,
@@ -2320,7 +2518,10 @@ var import_canvas25 = require("@pixerate/editor/canvas");
2320
2518
  recordAnimationChanges,
2321
2519
  relayoutUpdates,
2322
2520
  remapPastedNodes,
2521
+ removeCanvasVariant,
2323
2522
  removeTrack,
2523
+ renameCanvasVariantProperty,
2524
+ renameCanvasVariantValue,
2324
2525
  reorderNodes,
2325
2526
  repositionNodesTo,
2326
2527
  resetCanvasInstanceOverrides,
@@ -2339,6 +2540,7 @@ var import_canvas25 = require("@pixerate/editor/canvas");
2339
2540
  setCanvasComponentProperty,
2340
2541
  setCanvasInstanceProperties,
2341
2542
  setCanvasTokenMode,
2543
+ setCanvasVariantProperties,
2342
2544
  setKeyframe,
2343
2545
  setKeyframeEasing,
2344
2546
  setMotionPath,