@01.software/sdk 0.2.9-dev.260306.2ae88fe → 0.2.9-dev.260309.c56872d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/flow.cjs CHANGED
@@ -41,108 +41,366 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
41
41
  mod
42
42
  ));
43
43
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
44
+ var __async = (__this, __arguments, generator) => {
45
+ return new Promise((resolve, reject) => {
46
+ var fulfilled = (value) => {
47
+ try {
48
+ step(generator.next(value));
49
+ } catch (e) {
50
+ reject(e);
51
+ }
52
+ };
53
+ var rejected = (value) => {
54
+ try {
55
+ step(generator.throw(value));
56
+ } catch (e) {
57
+ reject(e);
58
+ }
59
+ };
60
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
61
+ step((generator = generator.apply(__this, __arguments)).next());
62
+ });
63
+ };
44
64
 
45
65
  // src/components/FlowRenderer/index.tsx
46
66
  var FlowRenderer_exports = {};
47
67
  __export(FlowRenderer_exports, {
48
- FLOW_NODE_TYPES: () => FLOW_NODE_TYPES,
49
- FlowRenderer: () => FlowRenderer
68
+ BUILT_IN_EDGE_TYPES: () => BUILT_IN_EDGE_TYPES,
69
+ BUILT_IN_NODE_TYPES: () => BUILT_IN_NODE_TYPES,
70
+ FlowRenderer: () => FlowRenderer,
71
+ isDynamicNode: () => isDynamicNode,
72
+ isFrameNode: () => isFrameNode,
73
+ useFlow: () => useFlow
50
74
  });
51
75
  module.exports = __toCommonJS(FlowRenderer_exports);
52
- var import_react = __toESM(require("react"), 1);
53
- var import_react2 = require("@xyflow/react");
76
+ var import_react2 = __toESM(require("react"), 1);
77
+ var import_react3 = require("@xyflow/react");
54
78
 
55
79
  // src/components/FlowRenderer/types.ts
56
- var FLOW_NODE_TYPES = ["text", "image", "iframe", "note"];
80
+ function isDynamicNode(node) {
81
+ return node.type === "dynamic";
82
+ }
83
+ function isFrameNode(node) {
84
+ return node.type === "frame";
85
+ }
86
+
87
+ // src/components/FlowRenderer/built-in-node-types.ts
88
+ var BUILT_IN_NODE_TYPES = [
89
+ {
90
+ slug: "text",
91
+ name: "Text",
92
+ color: "#e5e7eb",
93
+ defaultSize: { width: 200, height: 200 },
94
+ fields: [{ name: "body", label: "Body", fieldType: "textarea" }]
95
+ },
96
+ {
97
+ slug: "image",
98
+ name: "Image",
99
+ color: "#e5e7eb",
100
+ transparentBackground: true,
101
+ defaultSize: { width: 200, height: 200 },
102
+ fields: [
103
+ { name: "image", label: "Image", fieldType: "image" },
104
+ { name: "alt", label: "Alt Text", fieldType: "text" },
105
+ { name: "caption", label: "Caption", fieldType: "text" }
106
+ ]
107
+ }
108
+ ];
109
+
110
+ // src/components/FlowRenderer/built-in-edge-types.ts
111
+ var BUILT_IN_EDGE_TYPES = [
112
+ {
113
+ slug: "default",
114
+ name: "Default",
115
+ color: "",
116
+ strokeWidth: 2,
117
+ animated: true,
118
+ lineStyle: "default",
119
+ fields: []
120
+ }
121
+ ];
122
+
123
+ // src/components/FlowRenderer/useFlow.ts
124
+ var import_react_query = require("@tanstack/react-query");
125
+ var import_react = require("react");
126
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
127
+ function isId(value) {
128
+ return UUID_RE.test(value);
129
+ }
130
+ function apiNodeTypeToNodeTypeDef(doc) {
131
+ var _a, _b, _c, _d;
132
+ return {
133
+ slug: String((_a = doc.slug) != null ? _a : ""),
134
+ name: String((_b = doc.name) != null ? _b : ""),
135
+ color: String((_c = doc.color) != null ? _c : "#e5e7eb"),
136
+ defaultSize: (_d = doc.defaultSize) != null ? _d : { width: 200, height: 200 },
137
+ fields: Array.isArray(doc.fields) ? doc.fields : [],
138
+ transparentBackground: Boolean(doc.transparentBackground)
139
+ };
140
+ }
141
+ function apiEdgeTypeToEdgeTypeDef(doc) {
142
+ var _a, _b, _c, _d, _e, _f;
143
+ return {
144
+ slug: String((_a = doc.slug) != null ? _a : ""),
145
+ name: String((_b = doc.title) != null ? _b : ""),
146
+ color: String((_c = doc.color) != null ? _c : ""),
147
+ strokeWidth: (_d = doc.strokeWidth) != null ? _d : 2,
148
+ animated: (_e = doc.animated) != null ? _e : true,
149
+ lineStyle: String((_f = doc.lineStyle) != null ? _f : "default"),
150
+ fields: Array.isArray(doc.fields) ? doc.fields : []
151
+ };
152
+ }
153
+ function useFlow(slugOrId, options) {
154
+ var _a, _b;
155
+ const { client, enabled = true } = options;
156
+ const idDetected = isId(slugOrId);
157
+ const flowQuery = (0, import_react_query.useQuery)({
158
+ queryKey: ["flows", slugOrId],
159
+ queryFn: () => __async(null, null, function* () {
160
+ if (idDetected) {
161
+ return client.from("flows").findById(slugOrId);
162
+ }
163
+ const result = yield client.from("flows").find({
164
+ where: { slug: { equals: slugOrId } },
165
+ limit: 1
166
+ });
167
+ const doc = result.docs[0];
168
+ if (!doc) throw new Error(`Flow not found: ${slugOrId}`);
169
+ return doc;
170
+ }),
171
+ enabled
172
+ }, client.queryClient);
173
+ const nodeTypesQuery = (0, import_react_query.useQuery)({
174
+ queryKey: ["flow-node-types"],
175
+ queryFn: () => __async(null, null, function* () {
176
+ const result = yield client.from("flow-node-types").find({ limit: 100 });
177
+ return result.docs;
178
+ }),
179
+ enabled
180
+ }, client.queryClient);
181
+ const edgeTypesQuery = (0, import_react_query.useQuery)({
182
+ queryKey: ["flow-edge-types"],
183
+ queryFn: () => __async(null, null, function* () {
184
+ const result = yield client.from("flow-edge-types").find({ limit: 100 });
185
+ return result.docs;
186
+ }),
187
+ enabled
188
+ }, client.queryClient);
189
+ const nodeTypeDefs = (0, import_react.useMemo)(() => {
190
+ var _a2;
191
+ const apiDefs = ((_a2 = nodeTypesQuery.data) != null ? _a2 : []).map(apiNodeTypeToNodeTypeDef);
192
+ const builtInSlugs = new Set(BUILT_IN_NODE_TYPES.map((t) => t.slug));
193
+ const customDefs = apiDefs.filter((d) => !builtInSlugs.has(d.slug));
194
+ return [...BUILT_IN_NODE_TYPES, ...customDefs];
195
+ }, [nodeTypesQuery.data]);
196
+ const edgeTypeDefs = (0, import_react.useMemo)(() => {
197
+ var _a2;
198
+ const apiDefs = ((_a2 = edgeTypesQuery.data) != null ? _a2 : []).map(apiEdgeTypeToEdgeTypeDef);
199
+ const builtInSlugs = new Set(BUILT_IN_EDGE_TYPES.map((t) => t.slug));
200
+ const customDefs = apiDefs.filter((d) => !builtInSlugs.has(d.slug));
201
+ return [...BUILT_IN_EDGE_TYPES, ...customDefs];
202
+ }, [edgeTypesQuery.data]);
203
+ const flow = flowQuery.data;
204
+ const canvas = flow == null ? void 0 : flow.canvas;
205
+ return {
206
+ data: canvas,
207
+ nodeTypeDefs,
208
+ edgeTypeDefs,
209
+ flow,
210
+ isLoading: flowQuery.isLoading || nodeTypesQuery.isLoading || edgeTypesQuery.isLoading,
211
+ error: (_b = (_a = flowQuery.error) != null ? _a : nodeTypesQuery.error) != null ? _b : edgeTypesQuery.error
212
+ };
213
+ }
57
214
 
58
215
  // src/components/FlowRenderer/index.tsx
59
- function DefaultTextNode({ data }) {
60
- const d = data;
61
- return /* @__PURE__ */ import_react.default.createElement("div", { style: { padding: 12 } }, /* @__PURE__ */ import_react.default.createElement("strong", null, d.label), d.body && /* @__PURE__ */ import_react.default.createElement("p", { style: { margin: "8px 0 0", whiteSpace: "pre-wrap" } }, d.body));
216
+ function sanitizeUrl(url) {
217
+ if (!url) return url;
218
+ try {
219
+ const parsed = new URL(url);
220
+ if (parsed.protocol === "http:" || parsed.protocol === "https:") return url;
221
+ return void 0;
222
+ } catch (e) {
223
+ return void 0;
224
+ }
62
225
  }
63
- function DefaultImageNode({ data }) {
64
- const d = data;
65
- return /* @__PURE__ */ import_react.default.createElement("div", { style: { padding: 12 } }, /* @__PURE__ */ import_react.default.createElement("strong", null, d.label), d.imageUrl && /* @__PURE__ */ import_react.default.createElement(
66
- "img",
67
- {
68
- src: d.imageUrl,
69
- alt: d.alt || d.label,
70
- style: { width: "100%", marginTop: 8, borderRadius: 4 }
71
- }
72
- ), d.caption && /* @__PURE__ */ import_react.default.createElement("p", { style: { margin: "4px 0 0", fontSize: "0.85em", opacity: 0.7 } }, d.caption));
226
+ function renderFieldValue(key, val, fieldDef) {
227
+ if (val == null || val === "") return null;
228
+ const fieldType = fieldDef == null ? void 0 : fieldDef.fieldType;
229
+ if (fieldType === "image" || typeof val === "object" && val !== null && "url" in val) {
230
+ const imgUrl = typeof val === "string" ? val : val == null ? void 0 : val.url;
231
+ const safeUrl = sanitizeUrl(imgUrl);
232
+ if (!safeUrl) return null;
233
+ return /* @__PURE__ */ import_react2.default.createElement(
234
+ "img",
235
+ {
236
+ key,
237
+ src: safeUrl,
238
+ alt: "",
239
+ style: { width: "100%", marginTop: 8, borderRadius: 4 }
240
+ }
241
+ );
242
+ }
243
+ if (fieldType === "url") {
244
+ const safeUrl = sanitizeUrl(String(val));
245
+ if (!safeUrl) return null;
246
+ return /* @__PURE__ */ import_react2.default.createElement(
247
+ "a",
248
+ {
249
+ key,
250
+ href: safeUrl,
251
+ target: "_blank",
252
+ rel: "noopener noreferrer",
253
+ style: { display: "block", marginTop: 4, fontSize: "0.85em", color: "#3b82f6", wordBreak: "break-all" }
254
+ },
255
+ String(val)
256
+ );
257
+ }
258
+ if (fieldType === "color") {
259
+ return /* @__PURE__ */ import_react2.default.createElement("div", { key, style: { display: "flex", alignItems: "center", gap: 6, marginTop: 4 } }, /* @__PURE__ */ import_react2.default.createElement(
260
+ "span",
261
+ {
262
+ style: {
263
+ display: "inline-block",
264
+ width: 14,
265
+ height: 14,
266
+ borderRadius: 3,
267
+ backgroundColor: String(val),
268
+ border: "1px solid rgba(0,0,0,0.1)",
269
+ flexShrink: 0
270
+ }
271
+ }
272
+ ), /* @__PURE__ */ import_react2.default.createElement("span", { style: { fontSize: "0.85em" } }, String(val)));
273
+ }
274
+ if (fieldType === "toggle") {
275
+ const isOn = val === true || val === "true";
276
+ return /* @__PURE__ */ import_react2.default.createElement("p", { key, style: { margin: "4px 0 0", fontSize: "0.85em" } }, isOn ? "On" : "Off");
277
+ }
278
+ return /* @__PURE__ */ import_react2.default.createElement("p", { key, style: { margin: "4px 0 0", fontSize: "0.85em", whiteSpace: "pre-wrap" } }, String(val));
73
279
  }
74
- function DefaultIframeNode({ data }) {
280
+ function DefaultDynamicNode({ data }) {
75
281
  const d = data;
76
- return /* @__PURE__ */ import_react.default.createElement("div", { style: { padding: 12 } }, /* @__PURE__ */ import_react.default.createElement("strong", null, d.label), d.url && /* @__PURE__ */ import_react.default.createElement(
77
- "iframe",
282
+ return /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: 12 } }, /* @__PURE__ */ import_react2.default.createElement("strong", null, d.label), d.fields && Object.entries(d.fields).map(([key, val]) => renderFieldValue(key, val)));
283
+ }
284
+ function EnhancedDynamicNode({ data, typeDef }) {
285
+ const fieldMap = new Map(typeDef.fields.map((f) => [f.name, f]));
286
+ const transparent = typeDef.transparentBackground;
287
+ return /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: transparent ? 0 : void 0 } }, !transparent && /* @__PURE__ */ import_react2.default.createElement(
288
+ "div",
78
289
  {
79
- src: d.url,
80
- title: d.label,
81
- style: { width: "100%", height: 150, border: "none", marginTop: 8, borderRadius: 4 }
82
- }
83
- ));
290
+ style: {
291
+ backgroundColor: typeDef.color,
292
+ padding: "4px 12px",
293
+ borderRadius: "6px 6px 0 0",
294
+ fontSize: "0.75em",
295
+ fontWeight: 600,
296
+ color: "rgba(0,0,0,0.6)"
297
+ }
298
+ },
299
+ typeDef.name
300
+ ), /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: transparent ? 0 : 12 } }, /* @__PURE__ */ import_react2.default.createElement("strong", { style: { display: "block", marginBottom: 4 } }, data.label), data.fields && Object.entries(data.fields).map(([key, val]) => {
301
+ const fieldDef = fieldMap.get(key);
302
+ return renderFieldValue(key, val, fieldDef);
303
+ })));
84
304
  }
85
- function DefaultNoteNode({ data }) {
305
+ function DefaultFrameNode({ data }) {
306
+ var _a, _b;
86
307
  const d = data;
87
- return /* @__PURE__ */ import_react.default.createElement("div", { style: { padding: 12, backgroundColor: d.color || "#fef3c7", borderRadius: 4 } }, /* @__PURE__ */ import_react.default.createElement("strong", null, d.label), d.body && /* @__PURE__ */ import_react.default.createElement("p", { style: { margin: "8px 0 0", whiteSpace: "pre-wrap" } }, d.body));
308
+ const color = (_a = d.color) != null ? _a : "rgba(128,128,128,0.06)";
309
+ const padding = (_b = d.padding) != null ? _b : 20;
310
+ return /* @__PURE__ */ import_react2.default.createElement(
311
+ "div",
312
+ {
313
+ style: {
314
+ backgroundColor: color,
315
+ padding,
316
+ width: "100%",
317
+ height: "100%",
318
+ borderRadius: 8,
319
+ border: "2px dashed rgba(128,128,128,0.3)"
320
+ }
321
+ },
322
+ /* @__PURE__ */ import_react2.default.createElement(
323
+ "div",
324
+ {
325
+ style: {
326
+ fontSize: 11,
327
+ fontWeight: 600,
328
+ color: "rgba(128,128,128,0.6)",
329
+ userSelect: "none"
330
+ }
331
+ },
332
+ d.label
333
+ )
334
+ );
88
335
  }
89
- function createNodeTypes(components) {
336
+ function createNodeTypes(nodeRenderers, nodeTypeDefsMap) {
90
337
  const types = {};
91
- if (components == null ? void 0 : components.Text) {
92
- const Text = components.Text;
93
- types.text = (({ id, data }) => /* @__PURE__ */ import_react.default.createElement(Text, { id, data }));
94
- } else {
95
- types.text = DefaultTextNode;
96
- }
97
- if (components == null ? void 0 : components.Image) {
98
- const Image = components.Image;
99
- types.image = (({ id, data }) => /* @__PURE__ */ import_react.default.createElement(Image, { id, data }));
100
- } else {
101
- types.image = DefaultImageNode;
102
- }
103
- if (components == null ? void 0 : components.Iframe) {
104
- const Iframe = components.Iframe;
105
- types.iframe = (({ id, data }) => /* @__PURE__ */ import_react.default.createElement(Iframe, { id, data }));
106
- } else {
107
- types.iframe = DefaultIframeNode;
108
- }
109
- if (components == null ? void 0 : components.Note) {
110
- const Note = components.Note;
111
- types.note = (({ id, data }) => /* @__PURE__ */ import_react.default.createElement(Note, { id, data }));
112
- } else {
113
- types.note = DefaultNoteNode;
114
- }
338
+ types.dynamic = ((props) => {
339
+ const d = props.data;
340
+ const typeDef = nodeTypeDefsMap == null ? void 0 : nodeTypeDefsMap.get(d.nodeTypeSlug);
341
+ const CustomRenderer = nodeRenderers == null ? void 0 : nodeRenderers[d.nodeTypeSlug];
342
+ if (CustomRenderer) {
343
+ return /* @__PURE__ */ import_react2.default.createElement(
344
+ CustomRenderer,
345
+ {
346
+ id: props.id,
347
+ nodeTypeSlug: d.nodeTypeSlug,
348
+ label: d.label,
349
+ fields: d.fields,
350
+ nodeTypeDef: typeDef
351
+ }
352
+ );
353
+ }
354
+ if (typeDef) {
355
+ return /* @__PURE__ */ import_react2.default.createElement(EnhancedDynamicNode, { data: d, typeDef });
356
+ }
357
+ return /* @__PURE__ */ import_react2.default.createElement(DefaultDynamicNode, __spreadValues({}, props));
358
+ });
359
+ types.frame = DefaultFrameNode;
115
360
  return types;
116
361
  }
117
362
  function FlowRenderer({
118
363
  data,
119
364
  className,
120
365
  style,
121
- nodeComponents,
366
+ nodeRenderers,
367
+ nodeTypeDefs,
122
368
  background = true,
123
369
  interactive = false,
124
- fitView = true
370
+ fitView = true,
371
+ onNodeClick,
372
+ onEdgeClick
125
373
  }) {
126
374
  var _a, _b;
127
- const nodeTypes = import_react.default.useMemo(() => createNodeTypes(nodeComponents), [nodeComponents]);
375
+ const nodeTypeDefsMap = import_react2.default.useMemo(() => {
376
+ if (!(nodeTypeDefs == null ? void 0 : nodeTypeDefs.length)) return void 0;
377
+ return new Map(nodeTypeDefs.map((d) => [d.slug, d]));
378
+ }, [nodeTypeDefs]);
379
+ const nodeTypes = import_react2.default.useMemo(
380
+ () => createNodeTypes(nodeRenderers, nodeTypeDefsMap),
381
+ [nodeRenderers, nodeTypeDefsMap]
382
+ );
383
+ if (!data) return null;
128
384
  const defaultViewport = !fitView && data.viewport ? data.viewport : void 0;
129
- return /* @__PURE__ */ import_react.default.createElement("div", { className, style: __spreadValues({ width: "100%", height: "100%" }, style) }, /* @__PURE__ */ import_react.default.createElement(
130
- import_react2.ReactFlow,
385
+ return /* @__PURE__ */ import_react2.default.createElement(import_react3.ReactFlowProvider, null, /* @__PURE__ */ import_react2.default.createElement("div", { className, style: __spreadValues({ width: "100%", height: "100%" }, style) }, /* @__PURE__ */ import_react2.default.createElement(
386
+ import_react3.ReactFlow,
131
387
  {
132
388
  nodes: (_a = data.nodes) != null ? _a : [],
133
389
  edges: (_b = data.edges) != null ? _b : [],
134
390
  nodeTypes,
135
391
  defaultViewport,
136
392
  fitView,
393
+ onNodeClick,
394
+ onEdgeClick,
137
395
  nodesDraggable: interactive,
138
396
  nodesConnectable: false,
139
- elementsSelectable: interactive,
397
+ elementsSelectable: interactive || !!onNodeClick || !!onEdgeClick,
140
398
  panOnDrag: interactive,
141
399
  zoomOnScroll: interactive,
142
400
  zoomOnPinch: interactive,
143
401
  zoomOnDoubleClick: false
144
402
  },
145
- background && /* @__PURE__ */ import_react.default.createElement(import_react2.Background, null)
146
- ));
403
+ background && /* @__PURE__ */ import_react2.default.createElement(import_react3.Background, null)
404
+ )));
147
405
  }
148
406
  //# sourceMappingURL=flow.cjs.map
package/dist/flow.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/FlowRenderer/index.tsx","../src/components/FlowRenderer/types.ts"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport {\n ReactFlow,\n Background,\n type NodeTypes,\n type NodeProps,\n} from '@xyflow/react'\nimport type {\n CanvasData,\n FlowNodeComponents,\n TextNodeData,\n ImageNodeData,\n IframeNodeData,\n NoteNodeData,\n} from './types'\n\nexport { FLOW_NODE_TYPES } from './types'\nexport type { CanvasData, FlowNodeComponents } from './types'\nexport type {\n FlowNodeType,\n FlowNode,\n FlowEdge,\n FlowViewport,\n FlowNodeData,\n TextNodeData,\n ImageNodeData,\n IframeNodeData,\n NoteNodeData,\n TextNodeSlotProps,\n ImageNodeSlotProps,\n IframeNodeSlotProps,\n NoteNodeSlotProps,\n FlowNodePosition,\n} from './types'\n\n// ── Default node renderers ──\n\nfunction DefaultTextNode({ data }: NodeProps) {\n const d = data as unknown as TextNodeData\n return (\n <div style={{ padding: 12 }}>\n <strong>{d.label}</strong>\n {d.body && <p style={{ margin: '8px 0 0', whiteSpace: 'pre-wrap' }}>{d.body}</p>}\n </div>\n )\n}\n\nfunction DefaultImageNode({ data }: NodeProps) {\n const d = data as unknown as ImageNodeData\n return (\n <div style={{ padding: 12 }}>\n <strong>{d.label}</strong>\n {d.imageUrl && (\n <img\n src={d.imageUrl}\n alt={d.alt || d.label}\n style={{ width: '100%', marginTop: 8, borderRadius: 4 }}\n />\n )}\n {d.caption && (\n <p style={{ margin: '4px 0 0', fontSize: '0.85em', opacity: 0.7 }}>{d.caption}</p>\n )}\n </div>\n )\n}\n\nfunction DefaultIframeNode({ data }: NodeProps) {\n const d = data as unknown as IframeNodeData\n return (\n <div style={{ padding: 12 }}>\n <strong>{d.label}</strong>\n {d.url && (\n <iframe\n src={d.url}\n title={d.label}\n style={{ width: '100%', height: 150, border: 'none', marginTop: 8, borderRadius: 4 }}\n />\n )}\n </div>\n )\n}\n\nfunction DefaultNoteNode({ data }: NodeProps) {\n const d = data as unknown as NoteNodeData\n return (\n <div style={{ padding: 12, backgroundColor: d.color || '#fef3c7', borderRadius: 4 }}>\n <strong>{d.label}</strong>\n {d.body && <p style={{ margin: '8px 0 0', whiteSpace: 'pre-wrap' }}>{d.body}</p>}\n </div>\n )\n}\n\nfunction createNodeTypes(components?: FlowNodeComponents): NodeTypes {\n const types: NodeTypes = {} as NodeTypes\n\n if (components?.Text) {\n const Text = components.Text\n types.text = (({ id, data }: NodeProps) => (\n <Text id={id} data={data as unknown as TextNodeData} />\n )) as NodeTypes[string]\n } else {\n types.text = DefaultTextNode as NodeTypes[string]\n }\n\n if (components?.Image) {\n const Image = components.Image\n types.image = (({ id, data }: NodeProps) => (\n <Image id={id} data={data as unknown as ImageNodeData} />\n )) as NodeTypes[string]\n } else {\n types.image = DefaultImageNode as NodeTypes[string]\n }\n\n if (components?.Iframe) {\n const Iframe = components.Iframe\n types.iframe = (({ id, data }: NodeProps) => (\n <Iframe id={id} data={data as unknown as IframeNodeData} />\n )) as NodeTypes[string]\n } else {\n types.iframe = DefaultIframeNode as NodeTypes[string]\n }\n\n if (components?.Note) {\n const Note = components.Note\n types.note = (({ id, data }: NodeProps) => (\n <Note id={id} data={data as unknown as NoteNodeData} />\n )) as NodeTypes[string]\n } else {\n types.note = DefaultNoteNode as NodeTypes[string]\n }\n\n return types\n}\n\n// ── FlowRenderer ──\n\n/**\n * Renders a Flow canvas in read-only mode.\n *\n * Requires `@xyflow/react` peer dependency and its CSS:\n * ```ts\n * import '@xyflow/react/dist/style.css'\n * ```\n */\nexport interface FlowRendererProps {\n /** Canvas data from Flow document's `canvas` field */\n data: CanvasData\n /** Container className */\n className?: string\n /** Container style */\n style?: React.CSSProperties\n /** Custom node type components (memoize or define outside component to avoid re-renders) */\n nodeComponents?: FlowNodeComponents\n /** Show background pattern (default: true) */\n background?: boolean\n /** Allow user interaction - pan, zoom (default: false for read-only display) */\n interactive?: boolean\n /** Fit view on mount (default: true) */\n fitView?: boolean\n}\n\nexport function FlowRenderer({\n data,\n className,\n style,\n nodeComponents,\n background = true,\n interactive = false,\n fitView = true,\n}: FlowRendererProps) {\n const nodeTypes = React.useMemo(() => createNodeTypes(nodeComponents), [nodeComponents])\n\n const defaultViewport = !fitView && data.viewport ? data.viewport : undefined\n\n return (\n <div className={className} style={{ width: '100%', height: '100%', ...style }}>\n <ReactFlow\n nodes={(data.nodes ?? []) as unknown as Parameters<typeof ReactFlow>[0]['nodes']}\n edges={(data.edges ?? []) as unknown as Parameters<typeof ReactFlow>[0]['edges']}\n nodeTypes={nodeTypes}\n defaultViewport={defaultViewport}\n fitView={fitView}\n nodesDraggable={interactive}\n nodesConnectable={false}\n elementsSelectable={interactive}\n panOnDrag={interactive}\n zoomOnScroll={interactive}\n zoomOnPinch={interactive}\n zoomOnDoubleClick={false}\n >\n {background && <Background />}\n </ReactFlow>\n </div>\n )\n}\n","import type React from 'react'\n\n// ── Node type constants ──\n\nexport const FLOW_NODE_TYPES = ['text', 'image', 'iframe', 'note'] as const\n\nexport type FlowNodeType = (typeof FLOW_NODE_TYPES)[number]\n\n// ── Per-type data ──\n\ninterface BaseNodeData {\n label: string\n}\n\nexport interface TextNodeData extends BaseNodeData {\n nodeType: 'text'\n body?: string\n}\n\nexport interface ImageNodeData extends BaseNodeData {\n nodeType: 'image'\n imageId?: string\n imageUrl?: string\n alt?: string\n caption?: string\n}\n\nexport interface IframeNodeData extends BaseNodeData {\n nodeType: 'iframe'\n url?: string\n}\n\nexport interface NoteNodeData extends BaseNodeData {\n nodeType: 'note'\n body?: string\n color?: string\n}\n\nexport type FlowNodeData = (TextNodeData | ImageNodeData | IframeNodeData | NoteNodeData) &\n Record<string, unknown>\n\n// ── Canvas types (mirrors @xyflow/react but standalone) ──\n\nexport interface FlowNodePosition {\n x: number\n y: number\n}\n\nexport interface FlowNode {\n id: string\n type?: string\n position: FlowNodePosition\n data: FlowNodeData\n style?: React.CSSProperties\n width?: number\n height?: number\n measured?: { width?: number; height?: number }\n [key: string]: unknown\n}\n\nexport interface FlowEdge {\n id: string\n source: string\n target: string\n sourceHandle?: string | null\n targetHandle?: string | null\n type?: string\n style?: React.CSSProperties\n [key: string]: unknown\n}\n\nexport interface FlowViewport {\n x: number\n y: number\n zoom: number\n}\n\nexport interface CanvasData {\n nodes: FlowNode[]\n edges: FlowEdge[]\n viewport: FlowViewport\n}\n\n// ── Component slot props ──\n\nexport interface TextNodeSlotProps {\n id: string\n data: TextNodeData\n}\n\nexport interface ImageNodeSlotProps {\n id: string\n data: ImageNodeData\n}\n\nexport interface IframeNodeSlotProps {\n id: string\n data: IframeNodeData\n}\n\nexport interface NoteNodeSlotProps {\n id: string\n data: NoteNodeData\n}\n\nexport interface FlowNodeComponents {\n Text?: React.ComponentType<TextNodeSlotProps>\n Image?: React.ComponentType<ImageNodeSlotProps>\n Iframe?: React.ComponentType<IframeNodeSlotProps>\n Note?: React.ComponentType<NoteNodeSlotProps>\n}\n"],"mappings":"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","names":["import_react","React"]}
1
+ {"version":3,"sources":["../src/components/FlowRenderer/index.tsx","../src/components/FlowRenderer/types.ts","../src/components/FlowRenderer/built-in-node-types.ts","../src/components/FlowRenderer/built-in-edge-types.ts","../src/components/FlowRenderer/useFlow.ts"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport {\n ReactFlow,\n ReactFlowProvider,\n Background,\n type NodeTypes,\n type NodeProps,\n} from '@xyflow/react'\nimport type {\n CanvasData,\n DynamicNodeData,\n DynamicNodeSlotProps,\n FlowEdge,\n FlowNode,\n FrameNodeData,\n NodeTypeDef,\n NodeTypeFieldDef,\n} from './types'\n\nexport type {\n CanvasData,\n DynamicNodeSlotProps,\n FlowNode,\n FlowEdge,\n FlowViewport,\n FlowNodePosition,\n FlowNodeData,\n DynamicNodeData,\n FrameNodeData,\n NodeTypeDef,\n NodeTypeFieldDef,\n EdgeTypeDef,\n} from './types'\nexport { isDynamicNode, isFrameNode } from './types'\nexport { BUILT_IN_NODE_TYPES } from './built-in-node-types'\nexport { BUILT_IN_EDGE_TYPES } from './built-in-edge-types'\nexport { useFlow } from './useFlow'\nexport type { UseFlowOptions, UseFlowResult } from './useFlow'\n\n// ── Helpers ──\n\nfunction sanitizeUrl(url: string | undefined): string | undefined {\n if (!url) return url\n try {\n const parsed = new URL(url)\n if (parsed.protocol === 'http:' || parsed.protocol === 'https:') return url\n return undefined\n } catch {\n return undefined\n }\n}\n\n// ── Field renderer (type-aware) ──\n\nfunction renderFieldValue(\n key: string,\n val: unknown,\n fieldDef?: NodeTypeFieldDef,\n): React.ReactNode {\n if (val == null || val === '') return null\n\n const fieldType = fieldDef?.fieldType\n\n // Image field\n if (fieldType === 'image' || (typeof val === 'object' && val !== null && 'url' in val)) {\n const imgUrl = typeof val === 'string' ? val : (val as { url?: string })?.url\n const safeUrl = sanitizeUrl(imgUrl)\n if (!safeUrl) return null\n return (\n <img\n key={key}\n src={safeUrl}\n alt=\"\"\n style={{ width: '100%', marginTop: 8, borderRadius: 4 }}\n />\n )\n }\n\n // URL field\n if (fieldType === 'url') {\n const safeUrl = sanitizeUrl(String(val))\n if (!safeUrl) return null\n return (\n <a\n key={key}\n href={safeUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{ display: 'block', marginTop: 4, fontSize: '0.85em', color: '#3b82f6', wordBreak: 'break-all' }}\n >\n {String(val)}\n </a>\n )\n }\n\n // Color field\n if (fieldType === 'color') {\n return (\n <div key={key} style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 4 }}>\n <span\n style={{\n display: 'inline-block',\n width: 14,\n height: 14,\n borderRadius: 3,\n backgroundColor: String(val),\n border: '1px solid rgba(0,0,0,0.1)',\n flexShrink: 0,\n }}\n />\n <span style={{ fontSize: '0.85em' }}>{String(val)}</span>\n </div>\n )\n }\n\n // Toggle field\n if (fieldType === 'toggle') {\n const isOn = val === true || val === 'true'\n return (\n <p key={key} style={{ margin: '4px 0 0', fontSize: '0.85em' }}>\n {isOn ? 'On' : 'Off'}\n </p>\n )\n }\n\n // Text / textarea / number / select / fallback\n return (\n <p key={key} style={{ margin: '4px 0 0', fontSize: '0.85em', whiteSpace: 'pre-wrap' }}>\n {String(val)}\n </p>\n )\n}\n\n// ── Default dynamic node renderer ──\n\nfunction DefaultDynamicNode({ data }: NodeProps) {\n const d = data as unknown as DynamicNodeData\n return (\n <div style={{ padding: 12 }}>\n <strong>{d.label}</strong>\n {d.fields &&\n Object.entries(d.fields).map(([key, val]) => renderFieldValue(key, val))}\n </div>\n )\n}\n\n// ── Enhanced dynamic node renderer (with NodeTypeDef) ──\n\nfunction EnhancedDynamicNode({ data, typeDef }: { data: DynamicNodeData; typeDef: NodeTypeDef }) {\n const fieldMap = new Map(typeDef.fields.map((f) => [f.name, f]))\n const transparent = typeDef.transparentBackground\n\n return (\n <div style={{ padding: transparent ? 0 : undefined }}>\n {/* Color badge header (shows type name) */}\n {!transparent && (\n <div\n style={{\n backgroundColor: typeDef.color,\n padding: '4px 12px',\n borderRadius: '6px 6px 0 0',\n fontSize: '0.75em',\n fontWeight: 600,\n color: 'rgba(0,0,0,0.6)',\n }}\n >\n {typeDef.name}\n </div>\n )}\n <div style={{ padding: transparent ? 0 : 12 }}>\n <strong style={{ display: 'block', marginBottom: 4 }}>{data.label}</strong>\n {data.fields &&\n Object.entries(data.fields).map(([key, val]) => {\n const fieldDef = fieldMap.get(key)\n return renderFieldValue(key, val, fieldDef)\n })}\n </div>\n </div>\n )\n}\n\n// ── Default frame node renderer (#15) ──\n\nfunction DefaultFrameNode({ data }: NodeProps) {\n const d = data as unknown as FrameNodeData\n const color = d.color ?? 'rgba(128,128,128,0.06)'\n const padding = d.padding ?? 20\n return (\n <div\n style={{\n backgroundColor: color,\n padding,\n width: '100%',\n height: '100%',\n borderRadius: 8,\n border: '2px dashed rgba(128,128,128,0.3)',\n }}\n >\n <div\n style={{\n fontSize: 11,\n fontWeight: 600,\n color: 'rgba(128,128,128,0.6)',\n userSelect: 'none',\n }}\n >\n {d.label}\n </div>\n </div>\n )\n}\n\n// ── Node types builder ──\n\nfunction createNodeTypes(\n nodeRenderers?: Record<string, React.ComponentType<DynamicNodeSlotProps>>,\n nodeTypeDefsMap?: Map<string, NodeTypeDef>,\n): NodeTypes {\n const types: NodeTypes = {} as NodeTypes\n\n // Dynamic node type\n types.dynamic = ((props: NodeProps) => {\n const d = props.data as unknown as DynamicNodeData\n const typeDef = nodeTypeDefsMap?.get(d.nodeTypeSlug)\n const CustomRenderer = nodeRenderers?.[d.nodeTypeSlug]\n if (CustomRenderer) {\n return (\n <CustomRenderer\n id={props.id}\n nodeTypeSlug={d.nodeTypeSlug}\n label={d.label}\n fields={d.fields}\n nodeTypeDef={typeDef}\n />\n )\n }\n // Use enhanced renderer when type def is available\n if (typeDef) {\n return <EnhancedDynamicNode data={d} typeDef={typeDef} />\n }\n return <DefaultDynamicNode {...props} />\n }) as NodeTypes[string]\n\n // Frame node type\n types.frame = DefaultFrameNode as NodeTypes[string]\n\n return types\n}\n\n// ── FlowRenderer ──\n\n/**\n * Renders a Flow canvas in read-only mode.\n *\n * Requires `@xyflow/react` peer dependency and its CSS:\n * ```ts\n * import '@xyflow/react/dist/style.css'\n * ```\n */\nexport interface FlowRendererProps {\n /** Canvas data from Flow document's `canvas` field */\n data: CanvasData\n /** Container className */\n className?: string\n /** Container style */\n style?: React.CSSProperties\n /** Custom renderers by node type slug (e.g., `{ 'product-card': MyProductCard }`) */\n nodeRenderers?: Record<string, React.ComponentType<DynamicNodeSlotProps>>\n /** Node type definitions for enhanced rendering (color badges, field-type-aware display) */\n nodeTypeDefs?: NodeTypeDef[]\n /** Show background pattern (default: true) */\n background?: boolean\n /** Allow user interaction - pan, zoom (default: false for read-only display) */\n interactive?: boolean\n /** Fit view on mount (default: true) */\n fitView?: boolean\n /** Called when a node is clicked */\n onNodeClick?: (event: React.MouseEvent, node: FlowNode) => void\n /** Called when an edge is clicked */\n onEdgeClick?: (event: React.MouseEvent, edge: FlowEdge) => void\n}\n\nexport function FlowRenderer({\n data,\n className,\n style,\n nodeRenderers,\n nodeTypeDefs,\n background = true,\n interactive = false,\n fitView = true,\n onNodeClick,\n onEdgeClick,\n}: FlowRendererProps) {\n const nodeTypeDefsMap = React.useMemo(() => {\n if (!nodeTypeDefs?.length) return undefined\n return new Map(nodeTypeDefs.map((d) => [d.slug, d]))\n }, [nodeTypeDefs])\n\n const nodeTypes = React.useMemo(\n () => createNodeTypes(nodeRenderers, nodeTypeDefsMap),\n [nodeRenderers, nodeTypeDefsMap],\n )\n\n // Guard: null/undefined data (#8)\n if (!data) return null\n\n const defaultViewport = !fitView && data.viewport ? data.viewport : undefined\n\n return (\n <ReactFlowProvider>\n <div className={className} style={{ width: '100%', height: '100%', ...style }}>\n <ReactFlow\n nodes={(data.nodes ?? []) as unknown as Parameters<typeof ReactFlow>[0]['nodes']}\n edges={(data.edges ?? []) as unknown as Parameters<typeof ReactFlow>[0]['edges']}\n nodeTypes={nodeTypes}\n defaultViewport={defaultViewport}\n fitView={fitView}\n onNodeClick={onNodeClick as Parameters<typeof ReactFlow>[0]['onNodeClick']}\n onEdgeClick={onEdgeClick as Parameters<typeof ReactFlow>[0]['onEdgeClick']}\n nodesDraggable={interactive}\n nodesConnectable={false}\n elementsSelectable={interactive || !!onNodeClick || !!onEdgeClick}\n panOnDrag={interactive}\n zoomOnScroll={interactive}\n zoomOnPinch={interactive}\n zoomOnDoubleClick={false}\n >\n {background && <Background />}\n </ReactFlow>\n </div>\n </ReactFlowProvider>\n )\n}\n","import type React from 'react'\n\n// ── Dynamic node data ──\n\nexport interface DynamicNodeData {\n nodeTypeSlug: string\n label: string\n fields: Record<string, unknown>\n}\n\nexport type FlowNodeData = DynamicNodeData & Record<string, unknown>\n\n// ── Canvas types (mirrors @xyflow/react but standalone) ──\n\nexport interface FlowNodePosition {\n x: number\n y: number\n}\n\nexport interface FlowNode {\n id: string\n type?: string\n position: FlowNodePosition\n data: FlowNodeData\n style?: React.CSSProperties\n width?: number\n height?: number\n measured?: { width?: number; height?: number }\n draggable?: boolean\n [key: string]: unknown\n}\n\nexport interface FlowEdge {\n id: string\n source: string\n target: string\n sourceHandle?: string | null\n targetHandle?: string | null\n type?: string\n style?: React.CSSProperties\n edgeTypeSlug?: string\n fields?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface FlowViewport {\n x: number\n y: number\n zoom: number\n}\n\nexport interface CanvasData {\n nodes: FlowNode[]\n edges: FlowEdge[]\n viewport: FlowViewport\n}\n\n// ── Node type definitions (mirrors console's NodeTypeDef) ──\n\nexport interface NodeTypeFieldDef {\n name: string\n label: string\n fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'select' | 'toggle'\n options?: { label: string; value: string }[]\n defaultValue?: string\n required?: boolean\n}\n\nexport interface NodeTypeDef {\n slug: string\n name: string\n color: string\n defaultSize: { width: number; height: number }\n fields: NodeTypeFieldDef[]\n transparentBackground?: boolean\n}\n\n// ── Edge type definitions (mirrors console's EdgeTypeDef) ──\n\nexport interface EdgeTypeDef {\n slug: string\n name: string\n color: string\n strokeWidth: number\n animated: boolean\n lineStyle: string\n fields: NodeTypeFieldDef[]\n}\n\n// ── Type guards ──\n\nexport function isDynamicNode(node: FlowNode): node is FlowNode & { data: DynamicNodeData } {\n return node.type === 'dynamic'\n}\n\nexport function isFrameNode(node: FlowNode): node is FlowNode & { data: FrameNodeData } {\n return node.type === 'frame'\n}\n\n// ── Component slot props ──\n\nexport interface DynamicNodeSlotProps {\n id: string\n nodeTypeSlug: string\n label: string\n fields: Record<string, unknown>\n nodeTypeDef?: NodeTypeDef\n}\n\n// ── Frame node data ──\n\nexport interface FrameNodeData {\n label: string\n color?: string\n padding?: number\n}\n","import type { NodeTypeDef } from './types'\n\nexport const BUILT_IN_NODE_TYPES: NodeTypeDef[] = [\n {\n slug: 'text',\n name: 'Text',\n color: '#e5e7eb',\n defaultSize: { width: 200, height: 200 },\n fields: [{ name: 'body', label: 'Body', fieldType: 'textarea' }],\n },\n {\n slug: 'image',\n name: 'Image',\n color: '#e5e7eb',\n transparentBackground: true,\n defaultSize: { width: 200, height: 200 },\n fields: [\n { name: 'image', label: 'Image', fieldType: 'image' },\n { name: 'alt', label: 'Alt Text', fieldType: 'text' },\n { name: 'caption', label: 'Caption', fieldType: 'text' },\n ],\n },\n]\n","import type { EdgeTypeDef } from './types'\n\nexport const BUILT_IN_EDGE_TYPES: EdgeTypeDef[] = [\n {\n slug: 'default',\n name: 'Default',\n color: '',\n strokeWidth: 2,\n animated: true,\n lineStyle: 'default',\n fields: [],\n },\n]\n","'use client'\n\nimport { useQuery, type QueryClient } from '@tanstack/react-query'\nimport { useMemo } from 'react'\nimport type { CanvasData, NodeTypeDef, EdgeTypeDef } from './types'\nimport { BUILT_IN_NODE_TYPES } from './built-in-node-types'\nimport { BUILT_IN_EDGE_TYPES } from './built-in-edge-types'\n\n// ── Client interface (matches SDK's client shape) ──\n\ninterface FlowClient {\n from(collection: string): {\n find(options?: Record<string, unknown>): Promise<{ docs: Record<string, unknown>[] }>\n findById(id: string, options?: Record<string, unknown>): Promise<Record<string, unknown>>\n }\n queryClient: QueryClient\n}\n\n// ── Options & Result ──\n\nexport interface UseFlowOptions {\n client: FlowClient\n enabled?: boolean\n}\n\nexport interface UseFlowResult {\n data: CanvasData | undefined\n nodeTypeDefs: NodeTypeDef[]\n edgeTypeDefs: EdgeTypeDef[]\n flow: Record<string, unknown> | undefined\n isLoading: boolean\n error: Error | null\n}\n\n// ── Helpers ──\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nfunction isId(value: string): boolean {\n return UUID_RE.test(value)\n}\n\nfunction apiNodeTypeToNodeTypeDef(doc: Record<string, unknown>): NodeTypeDef {\n return {\n slug: String(doc.slug ?? ''),\n name: String(doc.name ?? ''),\n color: String(doc.color ?? '#e5e7eb'),\n defaultSize: (doc.defaultSize as NodeTypeDef['defaultSize']) ?? { width: 200, height: 200 },\n fields: Array.isArray(doc.fields)\n ? (doc.fields as NodeTypeDef['fields'])\n : [],\n transparentBackground: Boolean(doc.transparentBackground),\n }\n}\n\nfunction apiEdgeTypeToEdgeTypeDef(doc: Record<string, unknown>): EdgeTypeDef {\n return {\n slug: String(doc.slug ?? ''),\n name: String(doc.title ?? ''),\n color: String(doc.color ?? ''),\n strokeWidth: (doc.strokeWidth as number) ?? 2,\n animated: (doc.animated as boolean) ?? true,\n lineStyle: String(doc.lineStyle ?? 'default'),\n fields: Array.isArray(doc.fields)\n ? (doc.fields as EdgeTypeDef['fields'])\n : [],\n }\n}\n\n// ── Hook ──\n\nexport function useFlow(slugOrId: string, options: UseFlowOptions): UseFlowResult {\n const { client, enabled = true } = options\n const idDetected = isId(slugOrId)\n\n // Fetch flow document\n const flowQuery = useQuery<Record<string, unknown>>({\n queryKey: ['flows', slugOrId],\n queryFn: async () => {\n if (idDetected) {\n return client.from('flows').findById(slugOrId)\n }\n const result = await client.from('flows').find({\n where: { slug: { equals: slugOrId } },\n limit: 1,\n })\n const doc = result.docs[0]\n if (!doc) throw new Error(`Flow not found: ${slugOrId}`)\n return doc\n },\n enabled,\n }, client.queryClient)\n\n // Fetch tenant's custom node types\n const nodeTypesQuery = useQuery<Record<string, unknown>[]>({\n queryKey: ['flow-node-types'],\n queryFn: async () => {\n const result = await client.from('flow-node-types').find({ limit: 100 })\n return result.docs\n },\n enabled,\n }, client.queryClient)\n\n // Fetch tenant's custom edge types\n const edgeTypesQuery = useQuery<Record<string, unknown>[]>({\n queryKey: ['flow-edge-types'],\n queryFn: async () => {\n const result = await client.from('flow-edge-types').find({ limit: 100 })\n return result.docs\n },\n enabled,\n }, client.queryClient)\n\n // Merge built-in + API node types\n const nodeTypeDefs = useMemo<NodeTypeDef[]>(() => {\n const apiDefs = (nodeTypesQuery.data ?? []).map(apiNodeTypeToNodeTypeDef)\n const builtInSlugs = new Set(BUILT_IN_NODE_TYPES.map((t) => t.slug))\n // Built-in slugs are reserved — exclude API types with same slug\n const customDefs = apiDefs.filter((d) => !builtInSlugs.has(d.slug))\n return [...BUILT_IN_NODE_TYPES, ...customDefs]\n }, [nodeTypesQuery.data])\n\n // Merge built-in + API edge types\n const edgeTypeDefs = useMemo<EdgeTypeDef[]>(() => {\n const apiDefs = (edgeTypesQuery.data ?? []).map(apiEdgeTypeToEdgeTypeDef)\n const builtInSlugs = new Set(BUILT_IN_EDGE_TYPES.map((t) => t.slug))\n const customDefs = apiDefs.filter((d) => !builtInSlugs.has(d.slug))\n return [...BUILT_IN_EDGE_TYPES, ...customDefs]\n }, [edgeTypesQuery.data])\n\n const flow = flowQuery.data\n const canvas = flow?.canvas as CanvasData | undefined\n\n return {\n data: canvas,\n nodeTypeDefs,\n edgeTypeDefs,\n flow,\n isLoading: flowQuery.isLoading || nodeTypesQuery.isLoading || edgeTypesQuery.isLoading,\n error: (flowQuery.error as Error | null) ?? (nodeTypesQuery.error as Error | null) ?? (edgeTypesQuery.error as Error | null),\n }\n}\n"],"mappings":"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","names":["import_react","_a","React"]}