@01.software/sdk 0.4.3 → 0.5.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.
Files changed (40) hide show
  1. package/README.md +13 -13
  2. package/dist/auth.d.cts +1 -1
  3. package/dist/auth.d.ts +1 -1
  4. package/dist/{const-C3GC2SxR.d.cts → const-BO4SPN7f.d.ts} +2 -2
  5. package/dist/{const-ikSyKVND.d.ts → const-hqVXNZoy.d.cts} +2 -2
  6. package/dist/index.cjs +9 -7
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +27 -18
  9. package/dist/index.d.ts +27 -18
  10. package/dist/index.js +9 -7
  11. package/dist/index.js.map +1 -1
  12. package/dist/{payload-types-DPka7hJu.d.cts → payload-types-mZpmjJBz.d.cts} +102 -4
  13. package/dist/{payload-types-DPka7hJu.d.ts → payload-types-mZpmjJBz.d.ts} +102 -4
  14. package/dist/realtime.cjs.map +1 -1
  15. package/dist/realtime.d.cts +2 -2
  16. package/dist/realtime.d.ts +2 -2
  17. package/dist/realtime.js.map +1 -1
  18. package/dist/server-B80o7igg.d.cts +242 -0
  19. package/dist/server-B80o7igg.d.ts +242 -0
  20. package/dist/ui/flow/server.cjs +233 -0
  21. package/dist/ui/flow/server.cjs.map +1 -0
  22. package/dist/ui/flow/server.d.cts +3 -0
  23. package/dist/ui/flow/server.d.ts +3 -0
  24. package/dist/ui/flow/server.js +213 -0
  25. package/dist/ui/flow/server.js.map +1 -0
  26. package/dist/ui/flow.cjs +540 -127
  27. package/dist/ui/flow.cjs.map +1 -1
  28. package/dist/ui/flow.d.cts +39 -189
  29. package/dist/ui/flow.d.ts +39 -189
  30. package/dist/ui/flow.js +544 -135
  31. package/dist/ui/flow.js.map +1 -1
  32. package/dist/ui/form.d.cts +1 -1
  33. package/dist/ui/form.d.ts +1 -1
  34. package/dist/ui/video.d.cts +1 -1
  35. package/dist/ui/video.d.ts +1 -1
  36. package/dist/{webhook-CvNTdBWV.d.ts → webhook-CMi4JRCp.d.ts} +3 -3
  37. package/dist/{webhook-B8BfJ_Ka.d.cts → webhook-D65mzWt2.d.cts} +3 -3
  38. package/dist/webhook.d.cts +3 -3
  39. package/dist/webhook.d.ts +3 -3
  40. package/package.json +19 -14
package/dist/ui/flow.cjs CHANGED
@@ -71,16 +71,18 @@ __export(Flow_exports, {
71
71
  BUILT_IN_EDGE_TYPES: () => BUILT_IN_EDGE_TYPES,
72
72
  BUILT_IN_NODE_TYPES: () => BUILT_IN_NODE_TYPES,
73
73
  FlowRenderer: () => FlowRenderer,
74
+ clearTemplateCache: () => clearTemplateCache,
75
+ compileTemplate: () => compileTemplate,
76
+ getFrameData: () => getFrameData,
74
77
  getFrames: () => getFrames,
75
78
  getNodeBounds: () => getNodeBounds,
76
79
  isDynamicNode: () => isDynamicNode,
77
80
  isFrameNode: () => isFrameNode,
81
+ prefetchFlow: () => prefetchFlow,
78
82
  useFlow: () => useFlow,
79
83
  useFlowData: () => useFlowData
80
84
  });
81
85
  module.exports = __toCommonJS(Flow_exports);
82
- var import_react3 = __toESM(require("react"), 1);
83
- var import_react4 = require("@xyflow/react");
84
86
 
85
87
  // src/ui/Flow/types.ts
86
88
  function isDynamicNode(node) {
@@ -147,7 +149,7 @@ function collectionKeys(collection) {
147
149
 
148
150
  // src/ui/Flow/useFlow.ts
149
151
  function toNodeTypeDef(doc) {
150
- var _a, _b, _c, _d;
152
+ var _a, _b, _c, _d, _e, _f;
151
153
  return {
152
154
  slug: String((_a = doc.slug) != null ? _a : ""),
153
155
  name: String((_b = doc.title) != null ? _b : ""),
@@ -157,7 +159,9 @@ function toNodeTypeDef(doc) {
157
159
  height: 200
158
160
  },
159
161
  fields: Array.isArray(doc.fields) ? doc.fields : [],
160
- transparentBackground: Boolean(doc.transparentBackground)
162
+ transparentBackground: Boolean(doc.transparentBackground),
163
+ template: (_e = doc.template) != null ? _e : null,
164
+ customCSS: (_f = doc.customCSS) != null ? _f : null
161
165
  };
162
166
  }
163
167
  function toEdgeTypeDef(doc) {
@@ -246,6 +250,44 @@ function useFlow(options) {
246
250
  };
247
251
  }
248
252
 
253
+ // src/ui/Flow/prefetchFlow.ts
254
+ function prefetchFlow(options) {
255
+ return __async(this, null, function* () {
256
+ var _a;
257
+ const { client, slug, id } = options;
258
+ const identifier = (_a = id != null ? id : slug) != null ? _a : "";
259
+ yield Promise.all([
260
+ client.queryClient.prefetchQuery({
261
+ queryKey: collectionKeys("flows").detail(identifier),
262
+ queryFn: () => __async(null, null, function* () {
263
+ if (id) return client.from("flows").findById(id);
264
+ const result = yield client.from("flows").find({
265
+ where: { slug: { equals: slug } },
266
+ limit: 1
267
+ });
268
+ const doc = result.docs[0];
269
+ if (!doc) throw new Error(`Flow not found: ${slug}`);
270
+ return doc;
271
+ })
272
+ }),
273
+ client.queryClient.prefetchQuery({
274
+ queryKey: collectionKeys("flow-node-types").lists(),
275
+ queryFn: () => __async(null, null, function* () {
276
+ const result = yield client.from("flow-node-types").find({ limit: 100 });
277
+ return result.docs;
278
+ })
279
+ }),
280
+ client.queryClient.prefetchQuery({
281
+ queryKey: collectionKeys("flow-edge-types").lists(),
282
+ queryFn: () => __async(null, null, function* () {
283
+ const result = yield client.from("flow-edge-types").find({ limit: 100 });
284
+ return result.docs;
285
+ })
286
+ })
287
+ ]);
288
+ });
289
+ }
290
+
249
291
  // src/ui/Flow/useFlowData.ts
250
292
  var import_react2 = require("react");
251
293
  function useFlowData(options) {
@@ -275,37 +317,57 @@ function useFlowData(options) {
275
317
  }
276
318
 
277
319
  // src/ui/Flow/utils.ts
278
- function getNodeBounds(nodes, nodeIds) {
320
+ function getNodeSize(node) {
279
321
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
322
+ return {
323
+ width: (_e = (_d = (_c = (_a = node.style) == null ? void 0 : _a.width) != null ? _c : (_b = node.measured) == null ? void 0 : _b.width) != null ? _d : node.width) != null ? _e : 200,
324
+ height: (_j = (_i = (_h = (_f = node.style) == null ? void 0 : _f.height) != null ? _h : (_g = node.measured) == null ? void 0 : _g.height) != null ? _i : node.height) != null ? _j : 200
325
+ };
326
+ }
327
+ function getAbsolutePosition(node, nodeMap) {
328
+ let x = node.position.x;
329
+ let y = node.position.y;
330
+ let current = node;
331
+ const visited = /* @__PURE__ */ new Set([node.id]);
332
+ while (current.parentId) {
333
+ const parentId = current.parentId;
334
+ if (visited.has(parentId)) break;
335
+ const parent = nodeMap.get(parentId);
336
+ if (!parent) break;
337
+ visited.add(parent.id);
338
+ x += parent.position.x;
339
+ y += parent.position.y;
340
+ current = parent;
341
+ }
342
+ return { x, y };
343
+ }
344
+ function collectDescendants(nodes, rootId) {
345
+ const result = /* @__PURE__ */ new Set([rootId]);
346
+ const queue = [rootId];
347
+ let i = 0;
348
+ while (i < queue.length) {
349
+ const current = queue[i++];
350
+ for (const n of nodes) {
351
+ if (n.parentId === current && !result.has(n.id)) {
352
+ result.add(n.id);
353
+ queue.push(n.id);
354
+ }
355
+ }
356
+ }
357
+ return result;
358
+ }
359
+ function getNodeBounds(nodes, nodeIds) {
280
360
  const idSet = new Set(nodeIds);
281
361
  const targetNodes = nodes.filter((n) => idSet.has(n.id));
282
362
  if (targetNodes.length === 0) return void 0;
283
363
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
284
- function getAbsolutePosition(node) {
285
- let x = node.position.x;
286
- let y = node.position.y;
287
- let current = node;
288
- const visited = /* @__PURE__ */ new Set([node.id]);
289
- while (current.parentId) {
290
- const parentId = current.parentId;
291
- if (visited.has(parentId)) break;
292
- const parent = nodeMap.get(parentId);
293
- if (!parent) break;
294
- visited.add(parent.id);
295
- x += parent.position.x;
296
- y += parent.position.y;
297
- current = parent;
298
- }
299
- return { x, y };
300
- }
301
364
  let minX = Infinity;
302
365
  let minY = Infinity;
303
366
  let maxX = -Infinity;
304
367
  let maxY = -Infinity;
305
368
  for (const node of targetNodes) {
306
- const abs = getAbsolutePosition(node);
307
- const w = (_e = (_d = (_c = (_a = node.style) == null ? void 0 : _a.width) != null ? _c : (_b = node.measured) == null ? void 0 : _b.width) != null ? _d : node.width) != null ? _e : 200;
308
- const h = (_j = (_i = (_h = (_f = node.style) == null ? void 0 : _f.height) != null ? _h : (_g = node.measured) == null ? void 0 : _g.height) != null ? _i : node.height) != null ? _j : 200;
369
+ const abs = getAbsolutePosition(node, nodeMap);
370
+ const { width: w, height: h } = getNodeSize(node);
309
371
  minX = Math.min(minX, abs.x);
310
372
  minY = Math.min(minY, abs.y);
311
373
  maxX = Math.max(maxX, abs.x + w);
@@ -317,34 +379,150 @@ function getFrames(nodes) {
317
379
  const frames = nodes.filter((n) => n.type === "frame");
318
380
  if (frames.length === 0) return [];
319
381
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
320
- function getAbsolutePosition(node) {
321
- let x = node.position.x;
322
- let y = node.position.y;
323
- let current = node;
324
- const visited = /* @__PURE__ */ new Set([node.id]);
325
- while (current.parentId) {
326
- const parentId = current.parentId;
327
- if (visited.has(parentId)) break;
328
- const parent = nodeMap.get(parentId);
329
- if (!parent) break;
330
- visited.add(parent.id);
331
- x += parent.position.x;
332
- y += parent.position.y;
333
- current = parent;
334
- }
335
- return { x, y };
336
- }
337
382
  return frames.map((f) => {
338
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
383
+ var _a;
339
384
  const data = f.data;
340
- const abs = getAbsolutePosition(f);
341
- const w = (_e = (_d = (_c = (_a = f.style) == null ? void 0 : _a.width) != null ? _c : (_b = f.measured) == null ? void 0 : _b.width) != null ? _d : f.width) != null ? _e : 200;
342
- const h = (_j = (_i = (_h = (_f = f.style) == null ? void 0 : _f.height) != null ? _h : (_g = f.measured) == null ? void 0 : _g.height) != null ? _i : f.height) != null ? _j : 200;
343
- return { id: f.id, label: (_k = data.label) != null ? _k : "", bounds: { x: abs.x, y: abs.y, width: w, height: h } };
385
+ const abs = getAbsolutePosition(f, nodeMap);
386
+ const { width: w, height: h } = getNodeSize(f);
387
+ return {
388
+ id: f.id,
389
+ label: (_a = data.label) != null ? _a : "",
390
+ bounds: { x: abs.x, y: abs.y, width: w, height: h }
391
+ };
344
392
  }).sort((a, b) => a.bounds.y - b.bounds.y || a.bounds.x - b.bounds.x);
345
393
  }
394
+ function getFrameData(data, frameId) {
395
+ const frame = data.nodes.find((n) => n.id === frameId);
396
+ if (!frame || frame.type !== "frame") return void 0;
397
+ const descendantIds = collectDescendants(data.nodes, frameId);
398
+ const childNodes = data.nodes.filter((n) => descendantIds.has(n.id)).map((n) => __spreadProps(__spreadValues({}, n), { draggable: false }));
399
+ const childEdges = data.edges.filter(
400
+ (e) => descendantIds.has(e.source) && descendantIds.has(e.target)
401
+ );
402
+ const frameBounds = getNodeBounds(data.nodes, [frameId]);
403
+ const { width: w, height: h } = getNodeSize(frame);
404
+ const clampBounds = frameBounds != null ? frameBounds : {
405
+ x: frame.position.x,
406
+ y: frame.position.y,
407
+ width: w,
408
+ height: h
409
+ };
410
+ const contentNodeIds = childNodes.filter((n) => n.id !== frameId).map((n) => n.id);
411
+ const contentBounds = contentNodeIds.length > 0 ? getNodeBounds(data.nodes, contentNodeIds) : void 0;
412
+ const fitBounds = contentBounds != null ? contentBounds : clampBounds;
413
+ return {
414
+ data: {
415
+ nodes: childNodes,
416
+ edges: childEdges,
417
+ viewport: data.viewport
418
+ },
419
+ fitBounds,
420
+ clampBounds,
421
+ bounds: clampBounds
422
+ };
423
+ }
346
424
 
347
- // src/ui/Flow/index.tsx
425
+ // src/ui/Flow/template-compiler.ts
426
+ var import_react3 = __toESM(require("react"), 1);
427
+ var import_sucrase = require("sucrase");
428
+ var MAX_CACHE_SIZE = 100;
429
+ var componentCache = /* @__PURE__ */ new Map();
430
+ function hashCode(str) {
431
+ let hash = 0;
432
+ for (let i = 0; i < str.length; i++) {
433
+ const char = str.charCodeAt(i);
434
+ hash = (hash << 5) - hash + char | 0;
435
+ }
436
+ return hash.toString(36);
437
+ }
438
+ var BLOCKED_PATTERNS = [
439
+ /\bdocument\s*\./,
440
+ /\bwindow\s*\./,
441
+ /\bwindow\s*\[/,
442
+ /\bglobalThis\s*\./,
443
+ /\bfetch\s*\(/,
444
+ /\bXMLHttpRequest/,
445
+ /\beval\s*\(/,
446
+ /\bFunction\s*\(/,
447
+ /\bimport\s*\(/,
448
+ /\blocalStorage/,
449
+ /\bsessionStorage/,
450
+ /\bcookie/,
451
+ /\bpostMessage\s*\(/,
452
+ /\blocation\s*[.=]/,
453
+ /\bnavigator\s*\./,
454
+ /\bsetTimeout\s*\(/,
455
+ /\bsetInterval\s*\(/,
456
+ /\bsetImmediate\s*\(/,
457
+ /\brequire\s*\(/
458
+ ];
459
+ function validateTemplateCode(code) {
460
+ return !BLOCKED_PATTERNS.some((pattern) => pattern.test(code));
461
+ }
462
+ function compileTemplate(code, slug) {
463
+ const cacheKey = `${slug}:${hashCode(code)}`;
464
+ if (componentCache.has(cacheKey)) {
465
+ const cached = componentCache.get(cacheKey);
466
+ componentCache.delete(cacheKey);
467
+ componentCache.set(cacheKey, cached);
468
+ return cached;
469
+ }
470
+ if (!validateTemplateCode(code)) {
471
+ console.warn(`[flow] Template "${slug}" contains blocked patterns`);
472
+ return null;
473
+ }
474
+ try {
475
+ const { code: jsCode } = (0, import_sucrase.transform)(code, {
476
+ transforms: ["typescript", "jsx", "imports"],
477
+ jsxRuntime: "classic",
478
+ jsxPragma: "React.createElement",
479
+ jsxFragmentPragma: "React.Fragment"
480
+ });
481
+ const factory = new Function(
482
+ "React",
483
+ `
484
+ var window = undefined;
485
+ var document = undefined;
486
+ var globalThis = undefined;
487
+ var setTimeout = undefined;
488
+ var setInterval = undefined;
489
+ var setImmediate = undefined;
490
+ var fetch = undefined;
491
+ var XMLHttpRequest = undefined;
492
+ var navigator = undefined;
493
+ var location = undefined;
494
+ var exports = {};
495
+ var module = { exports: exports };
496
+ ${jsCode}
497
+ return module.exports.default || module.exports;
498
+ `
499
+ );
500
+ const Component = factory(import_react3.default);
501
+ if (typeof Component !== "function") return null;
502
+ if (componentCache.size >= MAX_CACHE_SIZE) {
503
+ const oldestKey = componentCache.keys().next().value;
504
+ if (oldestKey) componentCache.delete(oldestKey);
505
+ }
506
+ componentCache.set(cacheKey, Component);
507
+ return Component;
508
+ } catch (e) {
509
+ console.warn(`[flow] Failed to compile template for "${slug}":`, e);
510
+ return null;
511
+ }
512
+ }
513
+ function clearTemplateCache() {
514
+ componentCache.clear();
515
+ }
516
+
517
+ // src/ui/Flow/FlowRenderer.tsx
518
+ var import_react9 = __toESM(require("react"), 1);
519
+ var import_react10 = require("@xyflow/react");
520
+
521
+ // src/ui/Flow/node-types-factory.tsx
522
+ var import_react5 = __toESM(require("react"), 1);
523
+
524
+ // src/ui/Flow/node-renderers.tsx
525
+ var import_react4 = __toESM(require("react"), 1);
348
526
  function sanitizeUrl(url) {
349
527
  if (!url) return url;
350
528
  try {
@@ -355,11 +533,6 @@ function sanitizeUrl(url) {
355
533
  return void 0;
356
534
  }
357
535
  }
358
- function toMarkerType(value) {
359
- if (value === "arrow") return import_react4.MarkerType.Arrow;
360
- if (value === "arrowclosed") return import_react4.MarkerType.ArrowClosed;
361
- return void 0;
362
- }
363
536
  function renderFieldValue(key, val, fieldDef) {
364
537
  if (val == null || val === "") return null;
365
538
  const fieldType = fieldDef == null ? void 0 : fieldDef.fieldType;
@@ -367,7 +540,7 @@ function renderFieldValue(key, val, fieldDef) {
367
540
  const imgUrl = typeof val === "string" ? val : val == null ? void 0 : val.url;
368
541
  const safeUrl = sanitizeUrl(imgUrl);
369
542
  if (!safeUrl) return null;
370
- return /* @__PURE__ */ import_react3.default.createElement(
543
+ return /* @__PURE__ */ import_react4.default.createElement(
371
544
  "img",
372
545
  {
373
546
  key,
@@ -378,7 +551,7 @@ function renderFieldValue(key, val, fieldDef) {
378
551
  }
379
552
  );
380
553
  }
381
- return /* @__PURE__ */ import_react3.default.createElement(
554
+ return /* @__PURE__ */ import_react4.default.createElement(
382
555
  "div",
383
556
  {
384
557
  key,
@@ -395,7 +568,7 @@ function renderFieldValue(key, val, fieldDef) {
395
568
  }
396
569
  function DefaultDynamicNode({ data }) {
397
570
  const d = data;
398
- return /* @__PURE__ */ import_react3.default.createElement(
571
+ return /* @__PURE__ */ import_react4.default.createElement(
399
572
  "div",
400
573
  {
401
574
  style: {
@@ -408,11 +581,56 @@ function DefaultDynamicNode({ data }) {
408
581
  d.fields && Object.entries(d.fields).filter(([, v]) => v != null && v !== "").map(([key, val]) => renderFieldValue(key, val))
409
582
  );
410
583
  }
584
+ var TemplateErrorBoundary = class extends import_react4.default.Component {
585
+ constructor() {
586
+ super(...arguments);
587
+ this.state = { error: null };
588
+ }
589
+ static getDerivedStateFromError(error) {
590
+ return { error };
591
+ }
592
+ componentDidUpdate(prevProps) {
593
+ if (prevProps.resetKey !== this.props.resetKey && this.state.error) {
594
+ this.setState({ error: null });
595
+ }
596
+ }
597
+ render() {
598
+ if (this.state.error) {
599
+ return /* @__PURE__ */ import_react4.default.createElement("div", { style: { padding: 8, fontSize: 11, color: "#ef4444" } }, /* @__PURE__ */ import_react4.default.createElement("strong", null, "Render error"), /* @__PURE__ */ import_react4.default.createElement("pre", { style: { fontSize: 10, whiteSpace: "pre-wrap" } }, this.state.error.message));
600
+ }
601
+ return this.props.children;
602
+ }
603
+ };
411
604
  function EnhancedDynamicNode({
412
605
  data,
413
- typeDef
606
+ typeDef,
607
+ width,
608
+ height
414
609
  }) {
415
- return /* @__PURE__ */ import_react3.default.createElement(
610
+ if (typeDef.template) {
611
+ const Component = compileTemplate(typeDef.template, typeDef.slug);
612
+ if (Component) {
613
+ return /* @__PURE__ */ import_react4.default.createElement(
614
+ "div",
615
+ {
616
+ className: `flow-node flow-node--${typeDef.slug}${typeDef.transparentBackground ? " flow-node--transparent-bg" : ""}`,
617
+ style: { width: "100%", height: "100%" }
618
+ },
619
+ /* @__PURE__ */ import_react4.default.createElement(TemplateErrorBoundary, { resetKey: typeDef.template }, /* @__PURE__ */ import_react4.default.createElement(
620
+ Component,
621
+ {
622
+ fields: data.fields,
623
+ label: data.label,
624
+ color: typeDef.color,
625
+ nodeTypeSlug: typeDef.slug,
626
+ width: width || typeDef.defaultSize.width,
627
+ height: height || typeDef.defaultSize.height
628
+ }
629
+ ))
630
+ );
631
+ }
632
+ }
633
+ return /* @__PURE__ */ import_react4.default.createElement(
416
634
  "div",
417
635
  {
418
636
  style: {
@@ -432,7 +650,7 @@ function EnhancedDynamicNode({
432
650
  function DefaultFrameNode({ data }) {
433
651
  var _a, _b, _c, _d;
434
652
  const d = data;
435
- const baseColor = (_a = d.color) != null ? _a : "rgba(128,128,128,0.15)";
653
+ const baseColor = (_a = d.color) != null ? _a : "rgb(128,128,128)";
436
654
  const padding = (_b = d.padding) != null ? _b : 20;
437
655
  const borderStyle = (_c = d.borderStyle) != null ? _c : "dashed";
438
656
  const opacity = (_d = d.opacity) != null ? _d : 0.15;
@@ -441,7 +659,7 @@ function DefaultFrameNode({ data }) {
441
659
  if (m) return `rgba(${m[1]},${m[2]},${m[3]},${opacity})`;
442
660
  return baseColor;
443
661
  })();
444
- return /* @__PURE__ */ import_react3.default.createElement(
662
+ return /* @__PURE__ */ import_react4.default.createElement(
445
663
  "div",
446
664
  {
447
665
  style: {
@@ -452,7 +670,7 @@ function DefaultFrameNode({ data }) {
452
670
  border: borderStyle === "none" ? "none" : `2px ${borderStyle} rgba(128,128,128,0.3)`
453
671
  }
454
672
  },
455
- /* @__PURE__ */ import_react3.default.createElement(
673
+ /* @__PURE__ */ import_react4.default.createElement(
456
674
  "div",
457
675
  {
458
676
  style: {
@@ -466,43 +684,42 @@ function DefaultFrameNode({ data }) {
466
684
  )
467
685
  );
468
686
  }
687
+
688
+ // src/ui/Flow/node-types-factory.tsx
469
689
  function createNodeTypes(nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrapper, renderNode) {
470
690
  const types = {};
471
691
  types.dynamic = ((props) => {
472
692
  const d = props.data;
473
693
  const typeDef = nodeTypeDefsMap == null ? void 0 : nodeTypeDefsMap.get(d.nodeTypeSlug);
474
694
  const CustomRenderer = nodeRenderers == null ? void 0 : nodeRenderers[d.nodeTypeSlug];
475
- let content;
476
- if (CustomRenderer) {
477
- content = /* @__PURE__ */ import_react3.default.createElement(
478
- CustomRenderer,
479
- {
480
- id: props.id,
481
- nodeTypeSlug: d.nodeTypeSlug,
482
- label: d.label,
483
- fields: d.fields,
484
- nodeTypeDef: typeDef
485
- }
486
- );
487
- } else if (typeDef) {
488
- content = /* @__PURE__ */ import_react3.default.createElement(EnhancedDynamicNode, { data: d, typeDef });
489
- } else {
490
- content = /* @__PURE__ */ import_react3.default.createElement(DefaultDynamicNode, __spreadValues({}, props));
491
- }
695
+ const defaultRender = typeDef ? /* @__PURE__ */ import_react5.default.createElement(
696
+ EnhancedDynamicNode,
697
+ {
698
+ data: d,
699
+ typeDef,
700
+ width: props.width,
701
+ height: props.height
702
+ }
703
+ ) : /* @__PURE__ */ import_react5.default.createElement(DefaultDynamicNode, __spreadValues({}, props));
704
+ const slotProps = {
705
+ id: props.id,
706
+ nodeTypeSlug: d.nodeTypeSlug,
707
+ label: d.label,
708
+ fields: d.fields,
709
+ nodeTypeDef: typeDef,
710
+ selected: props.selected,
711
+ width: props.width,
712
+ height: props.height,
713
+ defaultRender
714
+ };
715
+ let content = CustomRenderer ? /* @__PURE__ */ import_react5.default.createElement(CustomRenderer, __spreadValues({}, slotProps)) : defaultRender;
492
716
  if (renderNode) {
493
- const slotProps = {
494
- id: props.id,
495
- nodeTypeSlug: d.nodeTypeSlug,
496
- label: d.label,
497
- fields: d.fields,
498
- nodeTypeDef: typeDef
499
- };
500
717
  const result = renderNode(slotProps, content);
501
718
  if (result !== null) content = result;
502
719
  }
503
720
  if (nodeWrapper) {
504
721
  const Wrapper = nodeWrapper;
505
- content = /* @__PURE__ */ import_react3.default.createElement(
722
+ content = /* @__PURE__ */ import_react5.default.createElement(
506
723
  Wrapper,
507
724
  {
508
725
  id: props.id,
@@ -519,7 +736,7 @@ function createNodeTypes(nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrap
519
736
  types.frame = frameRenderer ? ((props) => {
520
737
  const d = props.data;
521
738
  const Renderer = frameRenderer;
522
- return /* @__PURE__ */ import_react3.default.createElement(
739
+ return /* @__PURE__ */ import_react5.default.createElement(
523
740
  Renderer,
524
741
  {
525
742
  id: props.id,
@@ -527,20 +744,23 @@ function createNodeTypes(nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrap
527
744
  color: d.color,
528
745
  padding: d.padding,
529
746
  borderStyle: d.borderStyle,
530
- opacity: d.opacity
747
+ opacity: d.opacity,
748
+ width: props.width,
749
+ height: props.height
531
750
  }
532
751
  );
533
752
  }) : DefaultFrameNode;
534
753
  return types;
535
754
  }
536
755
  function createEdgeTypes(edgeRenderers, edgeTypeDefsMap) {
537
- if (!edgeRenderers || Object.keys(edgeRenderers).length === 0) return void 0;
756
+ if (!edgeRenderers || Object.keys(edgeRenderers).length === 0)
757
+ return void 0;
538
758
  const types = {};
539
759
  for (const [slug, Renderer] of Object.entries(edgeRenderers)) {
540
760
  types[slug] = ((props) => {
541
761
  var _a;
542
762
  const def = edgeTypeDefsMap == null ? void 0 : edgeTypeDefsMap.get(slug);
543
- return /* @__PURE__ */ import_react3.default.createElement(
763
+ return /* @__PURE__ */ import_react5.default.createElement(
544
764
  Renderer,
545
765
  {
546
766
  id: props.id,
@@ -557,20 +777,13 @@ function createEdgeTypes(edgeRenderers, edgeTypeDefsMap) {
557
777
  }
558
778
  return types;
559
779
  }
560
- function FocusHandler({
561
- bounds,
562
- padding,
563
- animation
564
- }) {
565
- const { fitBounds } = (0, import_react4.useReactFlow)();
566
- const boundsKey = `${bounds.x},${bounds.y},${bounds.width},${bounds.height}`;
567
- const boundsRef = import_react3.default.useRef(bounds);
568
- boundsRef.current = bounds;
569
- import_react3.default.useEffect(() => {
570
- const duration = animation === true ? 300 : typeof animation === "number" ? animation : 0;
571
- fitBounds(boundsRef.current, { padding, duration });
572
- }, [boundsKey, padding, animation, fitBounds]);
573
- return null;
780
+
781
+ // src/ui/Flow/edge-styles.ts
782
+ var import_react6 = require("@xyflow/react");
783
+ function toMarkerType(value) {
784
+ if (value === "arrow") return import_react6.MarkerType.Arrow;
785
+ if (value === "arrowclosed") return import_react6.MarkerType.ArrowClosed;
786
+ return void 0;
574
787
  }
575
788
  var EDGE_TYPE_MAP = {
576
789
  step: "step",
@@ -611,6 +824,138 @@ function applyEdgeStyles(edges, edgeTypeDefsMap) {
611
824
  return styled;
612
825
  });
613
826
  }
827
+
828
+ // src/ui/Flow/focus-handler.tsx
829
+ var import_react7 = __toESM(require("react"), 1);
830
+ var import_react8 = require("@xyflow/react");
831
+ function clampViewport(vp, cw, ch, extent) {
832
+ const left = -vp.x / vp.zoom;
833
+ const right = (cw - vp.x) / vp.zoom;
834
+ const top = -vp.y / vp.zoom;
835
+ const bottom = (ch - vp.y) / vp.zoom;
836
+ const dx0 = left - extent[0][0];
837
+ const dx1 = right - extent[1][0];
838
+ const dy0 = top - extent[0][1];
839
+ const dy1 = bottom - extent[1][1];
840
+ const cx = dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1);
841
+ const cy = dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1);
842
+ if (cx === 0 && cy === 0) return vp;
843
+ return { x: vp.x + cx * vp.zoom, y: vp.y + cy * vp.zoom, zoom: vp.zoom };
844
+ }
845
+ function FocusHandler({
846
+ bounds,
847
+ padding,
848
+ animation,
849
+ mode,
850
+ responsive,
851
+ extent,
852
+ clampBounds,
853
+ minZoomProp,
854
+ onInitialFit
855
+ }) {
856
+ const { setViewport } = (0, import_react8.useReactFlow)();
857
+ const store = (0, import_react8.useStoreApi)();
858
+ const containerRef = import_react7.default.useRef(null);
859
+ const boundsKey = `${bounds.x},${bounds.y},${bounds.width},${bounds.height}`;
860
+ const boundsRef = import_react7.default.useRef(bounds);
861
+ boundsRef.current = bounds;
862
+ const [containerSize, setContainerSize] = import_react7.default.useState({ w: 0, h: 0 });
863
+ const prevBoundsKeyRef = import_react7.default.useRef(null);
864
+ const prevSizeRef = import_react7.default.useRef({ w: 0, h: 0 });
865
+ import_react7.default.useEffect(() => {
866
+ const el = containerRef.current;
867
+ if (!el) return;
868
+ const observer = new ResizeObserver((entries) => {
869
+ const entry = entries[0];
870
+ if (!entry) return;
871
+ const { width, height } = entry.contentRect;
872
+ setContainerSize({ w: width, h: height });
873
+ });
874
+ observer.observe(el);
875
+ return () => observer.disconnect();
876
+ }, []);
877
+ import_react7.default.useEffect(() => {
878
+ if (containerSize.w === 0 || containerSize.h === 0) return;
879
+ const prevKey = prevBoundsKeyRef.current;
880
+ const prevSize = prevSizeRef.current;
881
+ prevBoundsKeyRef.current = boundsKey;
882
+ prevSizeRef.current = { w: containerSize.w, h: containerSize.h };
883
+ const isBoundsChange = prevKey !== boundsKey;
884
+ const isResizeOnly = !isBoundsChange && (prevSize.w !== containerSize.w || prevSize.h !== containerSize.h);
885
+ const isInitial = prevKey === null;
886
+ if (isResizeOnly && !responsive) return;
887
+ const duration = isInitial ? 0 : isBoundsChange ? animation === true ? 300 : typeof animation === "number" ? animation : 0 : 0;
888
+ const b = boundsRef.current;
889
+ const padX = padding * b.width;
890
+ const padY = padding * b.height;
891
+ const bw = b.width + padX * 2;
892
+ const bh = b.height + padY * 2;
893
+ if (bw === 0 || bh === 0) return;
894
+ const zoomFn = mode === "cover" ? Math.max : Math.min;
895
+ const zoom = zoomFn(containerSize.w / bw, containerSize.h / bh);
896
+ const centerTarget = clampBounds != null ? clampBounds : b;
897
+ const cx = centerTarget.x + centerTarget.width / 2;
898
+ const cy = centerTarget.y + centerTarget.height / 2;
899
+ const x = containerSize.w / 2 - cx * zoom;
900
+ const y = containerSize.h / 2 - cy * zoom;
901
+ if (clampBounds) {
902
+ const coverZoom = Math.max(
903
+ containerSize.w / clampBounds.width,
904
+ containerSize.h / clampBounds.height
905
+ );
906
+ store.getState().setMinZoom(Math.max(Math.min(coverZoom, zoom), minZoomProp != null ? minZoomProp : 0));
907
+ } else {
908
+ store.getState().setMinZoom(minZoomProp != null ? minZoomProp : 0.5);
909
+ }
910
+ let vp = { x, y, zoom };
911
+ if (isInitial || isBoundsChange) {
912
+ setViewport(vp, { duration: isInitial ? 0 : duration });
913
+ if (extent) {
914
+ const visW = containerSize.w / zoom;
915
+ const visH = containerSize.h / zoom;
916
+ onInitialFit == null ? void 0 : onInitialFit([
917
+ [Math.min(extent[0][0], cx - visW / 2), Math.min(extent[0][1], cy - visH / 2)],
918
+ [Math.max(extent[1][0], cx + visW / 2), Math.max(extent[1][1], cy + visH / 2)]
919
+ ]);
920
+ } else {
921
+ onInitialFit == null ? void 0 : onInitialFit();
922
+ }
923
+ } else {
924
+ if (extent) {
925
+ vp = clampViewport(vp, containerSize.w, containerSize.h, extent);
926
+ }
927
+ setViewport(vp, { duration });
928
+ }
929
+ }, [
930
+ boundsKey,
931
+ padding,
932
+ animation,
933
+ mode,
934
+ responsive,
935
+ containerSize.w,
936
+ containerSize.h,
937
+ extent,
938
+ setViewport,
939
+ clampBounds,
940
+ minZoomProp,
941
+ store,
942
+ onInitialFit
943
+ ]);
944
+ return /* @__PURE__ */ import_react7.default.createElement(
945
+ "div",
946
+ {
947
+ ref: containerRef,
948
+ style: {
949
+ position: "absolute",
950
+ inset: 0,
951
+ pointerEvents: "none",
952
+ visibility: "hidden"
953
+ }
954
+ }
955
+ );
956
+ }
957
+
958
+ // src/ui/Flow/FlowRenderer.tsx
614
959
  function FlowRenderer({
615
960
  data,
616
961
  className,
@@ -622,6 +967,10 @@ function FlowRenderer({
622
967
  interactive = false,
623
968
  fitView = true,
624
969
  onNodeClick,
970
+ onNodeDoubleClick,
971
+ onNodeContextMenu,
972
+ onNodeMouseEnter,
973
+ onNodeMouseLeave,
625
974
  onEdgeClick,
626
975
  frameRenderer,
627
976
  edgeRenderers,
@@ -634,27 +983,43 @@ function FlowRenderer({
634
983
  onViewportChange,
635
984
  defaultViewport: defaultViewportProp,
636
985
  bounds,
986
+ clampBounds,
637
987
  focusPadding,
638
- focusAnimation
988
+ focusAnimation,
989
+ focusMode = "contain",
990
+ responsiveFit,
991
+ translateExtent: translateExtentProp,
992
+ minZoom: minZoomProp,
993
+ maxZoom: maxZoomProp
639
994
  }) {
640
- var _a;
641
- const nodeTypeDefsMap = import_react3.default.useMemo(() => {
995
+ var _a, _b;
996
+ const nodeTypeDefsMap = import_react9.default.useMemo(() => {
642
997
  if (!(nodeTypeDefs == null ? void 0 : nodeTypeDefs.length)) return void 0;
643
998
  return new Map(nodeTypeDefs.map((d) => [d.slug, d]));
644
999
  }, [nodeTypeDefs]);
645
- const edgeTypeDefsMap = import_react3.default.useMemo(() => {
1000
+ const edgeTypeDefsMap = import_react9.default.useMemo(() => {
646
1001
  if (!(edgeTypeDefs == null ? void 0 : edgeTypeDefs.length)) return void 0;
647
1002
  return new Map(edgeTypeDefs.map((d) => [d.slug, d]));
648
1003
  }, [edgeTypeDefs]);
649
- const nodeTypes = import_react3.default.useMemo(
650
- () => createNodeTypes(nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrapper, renderNode),
1004
+ const nodeTypes = import_react9.default.useMemo(
1005
+ () => createNodeTypes(
1006
+ nodeRenderers,
1007
+ nodeTypeDefsMap,
1008
+ frameRenderer,
1009
+ nodeWrapper,
1010
+ renderNode
1011
+ ),
651
1012
  [nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrapper, renderNode]
652
1013
  );
653
- const customEdgeTypes = import_react3.default.useMemo(
1014
+ const customEdgeTypes = import_react9.default.useMemo(
654
1015
  () => createEdgeTypes(edgeRenderers, edgeTypeDefsMap),
655
1016
  [edgeRenderers, edgeTypeDefsMap]
656
1017
  );
657
- const styledEdges = import_react3.default.useMemo(() => {
1018
+ const mergedCSS = import_react9.default.useMemo(() => {
1019
+ if (!(nodeTypeDefs == null ? void 0 : nodeTypeDefs.length)) return "";
1020
+ return nodeTypeDefs.filter((d) => d.customCSS).map((d) => d.customCSS).join("\n");
1021
+ }, [nodeTypeDefs]);
1022
+ const styledEdges = import_react9.default.useMemo(() => {
658
1023
  var _a2;
659
1024
  let edges = applyEdgeStyles((_a2 = data == null ? void 0 : data.edges) != null ? _a2 : [], edgeTypeDefsMap);
660
1025
  if (edgeRenderers) {
@@ -668,50 +1033,98 @@ function FlowRenderer({
668
1033
  }
669
1034
  return edges;
670
1035
  }, [data == null ? void 0 : data.edges, edgeTypeDefsMap, edgeRenderers]);
1036
+ const translateExtent = import_react9.default.useMemo(() => {
1037
+ if (translateExtentProp) return translateExtentProp;
1038
+ const es = clampBounds != null ? clampBounds : bounds;
1039
+ if (!es) return void 0;
1040
+ const ep = clampBounds ? 0 : focusPadding != null ? focusPadding : 0.1;
1041
+ return [
1042
+ [es.x - ep * es.width, es.y - ep * es.height],
1043
+ [es.x + es.width * (1 + ep), es.y + es.height * (1 + ep)]
1044
+ ];
1045
+ }, [translateExtentProp, clampBounds, bounds, focusPadding]);
1046
+ const boundsKey = bounds ? `${bounds.x},${bounds.y},${bounds.width},${bounds.height}` : "";
1047
+ const extentReadyRef = import_react9.default.useRef(false);
1048
+ const expandedExtentRef = import_react9.default.useRef(void 0);
1049
+ const prevBoundsKeyRef = import_react9.default.useRef(boundsKey);
1050
+ if (prevBoundsKeyRef.current !== boundsKey) {
1051
+ prevBoundsKeyRef.current = boundsKey;
1052
+ extentReadyRef.current = false;
1053
+ expandedExtentRef.current = void 0;
1054
+ }
1055
+ const [, rerender] = import_react9.default.useReducer((x) => x + 1, 0);
1056
+ const handleInitialFit = import_react9.default.useCallback(
1057
+ (expandedExtent) => {
1058
+ extentReadyRef.current = true;
1059
+ expandedExtentRef.current = expandedExtent;
1060
+ rerender();
1061
+ },
1062
+ []
1063
+ );
1064
+ const activeExtent = !bounds || extentReadyRef.current ? (_a = expandedExtentRef.current) != null ? _a : translateExtent : void 0;
671
1065
  if (!data) return null;
672
1066
  const resolvedDefaultViewport = defaultViewportProp != null ? defaultViewportProp : !fitView && data.viewport ? data.viewport : void 0;
673
- return /* @__PURE__ */ import_react3.default.createElement(import_react4.ReactFlowProvider, null, /* @__PURE__ */ import_react3.default.createElement(
1067
+ return /* @__PURE__ */ import_react9.default.createElement(import_react10.ReactFlowProvider, null, /* @__PURE__ */ import_react9.default.createElement(
674
1068
  "div",
675
1069
  {
676
1070
  className,
677
- style: __spreadValues({ width: "100%", height: "100%" }, style)
1071
+ style: __spreadValues({
1072
+ width: "100%",
1073
+ height: "100%",
1074
+ background: "transparent"
1075
+ }, style)
678
1076
  },
679
- /* @__PURE__ */ import_react3.default.createElement(
680
- import_react4.ReactFlow,
1077
+ /* @__PURE__ */ import_react9.default.createElement(
1078
+ import_react10.ReactFlow,
681
1079
  {
682
- nodes: (_a = data.nodes) != null ? _a : [],
1080
+ nodes: (_b = data.nodes) != null ? _b : [],
683
1081
  edges: styledEdges,
684
1082
  nodeTypes,
685
1083
  edgeTypes: customEdgeTypes,
686
1084
  defaultViewport: resolvedDefaultViewport,
687
- fitView,
1085
+ fitView: bounds ? false : fitView,
1086
+ translateExtent: activeExtent,
688
1087
  onNodeClick,
1088
+ onNodeDoubleClick,
1089
+ onNodeContextMenu,
1090
+ onNodeMouseEnter,
1091
+ onNodeMouseLeave,
689
1092
  onEdgeClick,
690
1093
  onMoveEnd: onViewportChange ? ((_, vp) => {
691
1094
  onViewportChange(vp);
692
1095
  }) : void 0,
693
- nodesDraggable: interactive ? void 0 : false,
1096
+ nodesDraggable: interactive,
694
1097
  nodesConnectable: false,
695
- elementsSelectable: interactive || !!onNodeClick || !!onEdgeClick,
1098
+ elementsSelectable: interactive || !!onNodeClick || !!onNodeDoubleClick || !!onEdgeClick,
696
1099
  panOnDrag: interactive,
697
1100
  zoomOnScroll: interactive,
698
1101
  zoomOnPinch: interactive,
699
- zoomOnDoubleClick: false
1102
+ zoomOnDoubleClick: false,
1103
+ minZoom: minZoomProp,
1104
+ maxZoom: maxZoomProp,
1105
+ proOptions: { hideAttribution: true }
700
1106
  },
701
- background && /* @__PURE__ */ import_react3.default.createElement(import_react4.Background, null),
702
- controls && /* @__PURE__ */ import_react3.default.createElement(import_react4.Controls, null),
703
- minimap && /* @__PURE__ */ import_react3.default.createElement(
704
- import_react4.MiniMap,
1107
+ mergedCSS && /* @__PURE__ */ import_react9.default.createElement("style", { dangerouslySetInnerHTML: { __html: mergedCSS } }),
1108
+ background && /* @__PURE__ */ import_react9.default.createElement(import_react10.Background, null),
1109
+ controls && /* @__PURE__ */ import_react9.default.createElement(import_react10.Controls, null),
1110
+ minimap && /* @__PURE__ */ import_react9.default.createElement(
1111
+ import_react10.MiniMap,
705
1112
  {
706
1113
  nodeColor: minimapNodeColor
707
1114
  }
708
1115
  ),
709
- bounds && /* @__PURE__ */ import_react3.default.createElement(
1116
+ bounds && /* @__PURE__ */ import_react9.default.createElement(
710
1117
  FocusHandler,
711
1118
  {
712
1119
  bounds,
713
1120
  padding: focusPadding != null ? focusPadding : 0.1,
714
- animation: focusAnimation != null ? focusAnimation : true
1121
+ animation: focusAnimation != null ? focusAnimation : true,
1122
+ mode: focusMode,
1123
+ responsive: responsiveFit != null ? responsiveFit : true,
1124
+ extent: translateExtent,
1125
+ clampBounds,
1126
+ minZoomProp,
1127
+ onInitialFit: handleInitialFit
715
1128
  }
716
1129
  ),
717
1130
  children