@01.software/sdk 0.4.3-dev.260324.6dc30aa → 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.
package/dist/ui/flow.cjs CHANGED
@@ -78,12 +78,11 @@ __export(Flow_exports, {
78
78
  getNodeBounds: () => getNodeBounds,
79
79
  isDynamicNode: () => isDynamicNode,
80
80
  isFrameNode: () => isFrameNode,
81
+ prefetchFlow: () => prefetchFlow,
81
82
  useFlow: () => useFlow,
82
83
  useFlowData: () => useFlowData
83
84
  });
84
85
  module.exports = __toCommonJS(Flow_exports);
85
- var import_react4 = __toESM(require("react"), 1);
86
- var import_react5 = require("@xyflow/react");
87
86
 
88
87
  // src/ui/Flow/types.ts
89
88
  function isDynamicNode(node) {
@@ -251,6 +250,44 @@ function useFlow(options) {
251
250
  };
252
251
  }
253
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
+
254
291
  // src/ui/Flow/useFlowData.ts
255
292
  var import_react2 = require("react");
256
293
  function useFlowData(options) {
@@ -423,7 +460,7 @@ function validateTemplateCode(code) {
423
460
  return !BLOCKED_PATTERNS.some((pattern) => pattern.test(code));
424
461
  }
425
462
  function compileTemplate(code, slug) {
426
- const cacheKey = `${slug}:${code.length}:${hashCode(code)}:${code.slice(0, 64)}`;
463
+ const cacheKey = `${slug}:${hashCode(code)}`;
427
464
  if (componentCache.has(cacheKey)) {
428
465
  const cached = componentCache.get(cacheKey);
429
466
  componentCache.delete(cacheKey);
@@ -477,7 +514,15 @@ function clearTemplateCache() {
477
514
  componentCache.clear();
478
515
  }
479
516
 
480
- // src/ui/Flow/index.tsx
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);
481
526
  function sanitizeUrl(url) {
482
527
  if (!url) return url;
483
528
  try {
@@ -488,11 +533,6 @@ function sanitizeUrl(url) {
488
533
  return void 0;
489
534
  }
490
535
  }
491
- function toMarkerType(value) {
492
- if (value === "arrow") return import_react5.MarkerType.Arrow;
493
- if (value === "arrowclosed") return import_react5.MarkerType.ArrowClosed;
494
- return void 0;
495
- }
496
536
  function renderFieldValue(key, val, fieldDef) {
497
537
  if (val == null || val === "") return null;
498
538
  const fieldType = fieldDef == null ? void 0 : fieldDef.fieldType;
@@ -574,10 +614,7 @@ function EnhancedDynamicNode({
574
614
  "div",
575
615
  {
576
616
  className: `flow-node flow-node--${typeDef.slug}${typeDef.transparentBackground ? " flow-node--transparent-bg" : ""}`,
577
- style: {
578
- width: "100%",
579
- height: "100%"
580
- }
617
+ style: { width: "100%", height: "100%" }
581
618
  },
582
619
  /* @__PURE__ */ import_react4.default.createElement(TemplateErrorBoundary, { resetKey: typeDef.template }, /* @__PURE__ */ import_react4.default.createElement(
583
620
  Component,
@@ -586,8 +623,8 @@ function EnhancedDynamicNode({
586
623
  label: data.label,
587
624
  color: typeDef.color,
588
625
  nodeTypeSlug: typeDef.slug,
589
- width: width != null ? width : typeDef.defaultSize.width,
590
- height: height != null ? height : typeDef.defaultSize.height
626
+ width: width || typeDef.defaultSize.width,
627
+ height: height || typeDef.defaultSize.height
591
628
  }
592
629
  ))
593
630
  );
@@ -613,7 +650,7 @@ function EnhancedDynamicNode({
613
650
  function DefaultFrameNode({ data }) {
614
651
  var _a, _b, _c, _d;
615
652
  const d = data;
616
- 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)";
617
654
  const padding = (_b = d.padding) != null ? _b : 20;
618
655
  const borderStyle = (_c = d.borderStyle) != null ? _c : "dashed";
619
656
  const opacity = (_d = d.opacity) != null ? _d : 0.15;
@@ -647,43 +684,42 @@ function DefaultFrameNode({ data }) {
647
684
  )
648
685
  );
649
686
  }
687
+
688
+ // src/ui/Flow/node-types-factory.tsx
650
689
  function createNodeTypes(nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrapper, renderNode) {
651
690
  const types = {};
652
691
  types.dynamic = ((props) => {
653
692
  const d = props.data;
654
693
  const typeDef = nodeTypeDefsMap == null ? void 0 : nodeTypeDefsMap.get(d.nodeTypeSlug);
655
694
  const CustomRenderer = nodeRenderers == null ? void 0 : nodeRenderers[d.nodeTypeSlug];
656
- let content;
657
- if (CustomRenderer) {
658
- content = /* @__PURE__ */ import_react4.default.createElement(
659
- CustomRenderer,
660
- {
661
- id: props.id,
662
- nodeTypeSlug: d.nodeTypeSlug,
663
- label: d.label,
664
- fields: d.fields,
665
- nodeTypeDef: typeDef
666
- }
667
- );
668
- } else if (typeDef) {
669
- content = /* @__PURE__ */ import_react4.default.createElement(EnhancedDynamicNode, { data: d, typeDef, width: props.width, height: props.height });
670
- } else {
671
- content = /* @__PURE__ */ import_react4.default.createElement(DefaultDynamicNode, __spreadValues({}, props));
672
- }
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;
673
716
  if (renderNode) {
674
- const slotProps = {
675
- id: props.id,
676
- nodeTypeSlug: d.nodeTypeSlug,
677
- label: d.label,
678
- fields: d.fields,
679
- nodeTypeDef: typeDef
680
- };
681
717
  const result = renderNode(slotProps, content);
682
718
  if (result !== null) content = result;
683
719
  }
684
720
  if (nodeWrapper) {
685
721
  const Wrapper = nodeWrapper;
686
- content = /* @__PURE__ */ import_react4.default.createElement(
722
+ content = /* @__PURE__ */ import_react5.default.createElement(
687
723
  Wrapper,
688
724
  {
689
725
  id: props.id,
@@ -700,7 +736,7 @@ function createNodeTypes(nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrap
700
736
  types.frame = frameRenderer ? ((props) => {
701
737
  const d = props.data;
702
738
  const Renderer = frameRenderer;
703
- return /* @__PURE__ */ import_react4.default.createElement(
739
+ return /* @__PURE__ */ import_react5.default.createElement(
704
740
  Renderer,
705
741
  {
706
742
  id: props.id,
@@ -708,20 +744,23 @@ function createNodeTypes(nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrap
708
744
  color: d.color,
709
745
  padding: d.padding,
710
746
  borderStyle: d.borderStyle,
711
- opacity: d.opacity
747
+ opacity: d.opacity,
748
+ width: props.width,
749
+ height: props.height
712
750
  }
713
751
  );
714
752
  }) : DefaultFrameNode;
715
753
  return types;
716
754
  }
717
755
  function createEdgeTypes(edgeRenderers, edgeTypeDefsMap) {
718
- if (!edgeRenderers || Object.keys(edgeRenderers).length === 0) return void 0;
756
+ if (!edgeRenderers || Object.keys(edgeRenderers).length === 0)
757
+ return void 0;
719
758
  const types = {};
720
759
  for (const [slug, Renderer] of Object.entries(edgeRenderers)) {
721
760
  types[slug] = ((props) => {
722
761
  var _a;
723
762
  const def = edgeTypeDefsMap == null ? void 0 : edgeTypeDefsMap.get(slug);
724
- return /* @__PURE__ */ import_react4.default.createElement(
763
+ return /* @__PURE__ */ import_react5.default.createElement(
725
764
  Renderer,
726
765
  {
727
766
  id: props.id,
@@ -738,22 +777,92 @@ function createEdgeTypes(edgeRenderers, edgeTypeDefsMap) {
738
777
  }
739
778
  return types;
740
779
  }
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;
787
+ }
788
+ var EDGE_TYPE_MAP = {
789
+ step: "step",
790
+ smoothstep: "smoothstep",
791
+ bezier: "default",
792
+ default: "default"
793
+ };
794
+ function applyEdgeStyles(edges, edgeTypeDefsMap) {
795
+ if (!(edgeTypeDefsMap == null ? void 0 : edgeTypeDefsMap.size)) return edges;
796
+ return edges.map((edge) => {
797
+ var _a;
798
+ const slug = edge.edgeTypeSlug;
799
+ if (!slug) return edge;
800
+ const def = edgeTypeDefsMap.get(slug);
801
+ if (!def) return edge;
802
+ const styled = __spreadValues({}, edge);
803
+ if (!styled.type && def.lineStyle) {
804
+ styled.type = (_a = EDGE_TYPE_MAP[def.lineStyle]) != null ? _a : "default";
805
+ }
806
+ styled.style = __spreadValues(__spreadValues(__spreadValues({}, def.color ? { stroke: def.color } : void 0), def.strokeWidth ? { strokeWidth: def.strokeWidth } : void 0), edge.style);
807
+ if (styled.animated == null && def.animated) styled.animated = true;
808
+ if (!styled.markerStart) {
809
+ const startType = toMarkerType(def.markerStart);
810
+ if (startType) {
811
+ styled.markerStart = __spreadValues({
812
+ type: startType
813
+ }, def.color ? { color: def.color } : void 0);
814
+ }
815
+ }
816
+ if (!styled.markerEnd) {
817
+ const endType = toMarkerType(def.markerEnd);
818
+ if (endType) {
819
+ styled.markerEnd = __spreadValues({
820
+ type: endType
821
+ }, def.color ? { color: def.color } : void 0);
822
+ }
823
+ }
824
+ return styled;
825
+ });
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
+ }
741
845
  function FocusHandler({
742
846
  bounds,
743
847
  padding,
744
848
  animation,
745
849
  mode,
746
- responsive
850
+ responsive,
851
+ extent,
852
+ clampBounds,
853
+ minZoomProp,
854
+ onInitialFit
747
855
  }) {
748
- const { fitBounds, setViewport } = (0, import_react5.useReactFlow)();
749
- const containerRef = import_react4.default.useRef(null);
856
+ const { setViewport } = (0, import_react8.useReactFlow)();
857
+ const store = (0, import_react8.useStoreApi)();
858
+ const containerRef = import_react7.default.useRef(null);
750
859
  const boundsKey = `${bounds.x},${bounds.y},${bounds.width},${bounds.height}`;
751
- const boundsRef = import_react4.default.useRef(bounds);
860
+ const boundsRef = import_react7.default.useRef(bounds);
752
861
  boundsRef.current = bounds;
753
- const [containerSize, setContainerSize] = import_react4.default.useState({ w: 0, h: 0 });
754
- const prevBoundsKeyRef = import_react4.default.useRef(null);
755
- const prevSizeRef = import_react4.default.useRef({ w: 0, h: 0 });
756
- import_react4.default.useEffect(() => {
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(() => {
757
866
  const el = containerRef.current;
758
867
  if (!el) return;
759
868
  const observer = new ResizeObserver((entries) => {
@@ -765,7 +874,7 @@ function FocusHandler({
765
874
  observer.observe(el);
766
875
  return () => observer.disconnect();
767
876
  }, []);
768
- import_react4.default.useEffect(() => {
877
+ import_react7.default.useEffect(() => {
769
878
  if (containerSize.w === 0 || containerSize.h === 0) return;
770
879
  const prevKey = prevBoundsKeyRef.current;
771
880
  const prevSize = prevSizeRef.current;
@@ -775,70 +884,78 @@ function FocusHandler({
775
884
  const isResizeOnly = !isBoundsChange && (prevSize.w !== containerSize.w || prevSize.h !== containerSize.h);
776
885
  const isInitial = prevKey === null;
777
886
  if (isResizeOnly && !responsive) return;
778
- const duration = isInitial || isBoundsChange ? animation === true ? 300 : typeof animation === "number" ? animation : 0 : 0;
887
+ const duration = isInitial ? 0 : isBoundsChange ? animation === true ? 300 : typeof animation === "number" ? animation : 0 : 0;
779
888
  const b = boundsRef.current;
780
889
  const padX = padding * b.width;
781
890
  const padY = padding * b.height;
782
891
  const bw = b.width + padX * 2;
783
892
  const bh = b.height + padY * 2;
784
- if (mode === "cover") {
785
- const zoom = Math.max(containerSize.w / bw, containerSize.h / bh);
786
- const cx = b.x + b.width / 2;
787
- const cy = b.y + b.height / 2;
788
- const x = containerSize.w / 2 - cx * zoom;
789
- const y = containerSize.h / 2 - cy * zoom;
790
- setViewport({ x, y, zoom }, { duration });
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));
791
907
  } else {
792
- fitBounds(boundsRef.current, { padding, duration });
908
+ store.getState().setMinZoom(minZoomProp != null ? minZoomProp : 0.5);
793
909
  }
794
- }, [boundsKey, padding, animation, mode, responsive, containerSize.w, containerSize.h, fitBounds, setViewport]);
795
- return /* @__PURE__ */ import_react4.default.createElement(
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(
796
945
  "div",
797
946
  {
798
947
  ref: containerRef,
799
- style: { position: "absolute", inset: 0, pointerEvents: "none", visibility: "hidden" }
800
- }
801
- );
802
- }
803
- var EDGE_TYPE_MAP = {
804
- step: "step",
805
- smoothstep: "smoothstep",
806
- bezier: "default",
807
- default: "default"
808
- };
809
- function applyEdgeStyles(edges, edgeTypeDefsMap) {
810
- if (!(edgeTypeDefsMap == null ? void 0 : edgeTypeDefsMap.size)) return edges;
811
- return edges.map((edge) => {
812
- var _a;
813
- const slug = edge.edgeTypeSlug;
814
- if (!slug) return edge;
815
- const def = edgeTypeDefsMap.get(slug);
816
- if (!def) return edge;
817
- const styled = __spreadValues({}, edge);
818
- if (!styled.type && def.lineStyle) {
819
- styled.type = (_a = EDGE_TYPE_MAP[def.lineStyle]) != null ? _a : "default";
820
- }
821
- styled.style = __spreadValues(__spreadValues(__spreadValues({}, def.color ? { stroke: def.color } : void 0), def.strokeWidth ? { strokeWidth: def.strokeWidth } : void 0), edge.style);
822
- if (styled.animated == null && def.animated) styled.animated = true;
823
- if (!styled.markerStart) {
824
- const startType = toMarkerType(def.markerStart);
825
- if (startType) {
826
- styled.markerStart = __spreadValues({
827
- type: startType
828
- }, def.color ? { color: def.color } : void 0);
829
- }
830
- }
831
- if (!styled.markerEnd) {
832
- const endType = toMarkerType(def.markerEnd);
833
- if (endType) {
834
- styled.markerEnd = __spreadValues({
835
- type: endType
836
- }, def.color ? { color: def.color } : void 0);
948
+ style: {
949
+ position: "absolute",
950
+ inset: 0,
951
+ pointerEvents: "none",
952
+ visibility: "hidden"
837
953
  }
838
954
  }
839
- return styled;
840
- });
955
+ );
841
956
  }
957
+
958
+ // src/ui/Flow/FlowRenderer.tsx
842
959
  function FlowRenderer({
843
960
  data,
844
961
  className,
@@ -850,6 +967,10 @@ function FlowRenderer({
850
967
  interactive = false,
851
968
  fitView = true,
852
969
  onNodeClick,
970
+ onNodeDoubleClick,
971
+ onNodeContextMenu,
972
+ onNodeMouseEnter,
973
+ onNodeMouseLeave,
853
974
  onEdgeClick,
854
975
  frameRenderer,
855
976
  edgeRenderers,
@@ -867,30 +988,38 @@ function FlowRenderer({
867
988
  focusAnimation,
868
989
  focusMode = "contain",
869
990
  responsiveFit,
870
- translateExtent: translateExtentProp
991
+ translateExtent: translateExtentProp,
992
+ minZoom: minZoomProp,
993
+ maxZoom: maxZoomProp
871
994
  }) {
872
- var _a;
873
- const nodeTypeDefsMap = import_react4.default.useMemo(() => {
995
+ var _a, _b;
996
+ const nodeTypeDefsMap = import_react9.default.useMemo(() => {
874
997
  if (!(nodeTypeDefs == null ? void 0 : nodeTypeDefs.length)) return void 0;
875
998
  return new Map(nodeTypeDefs.map((d) => [d.slug, d]));
876
999
  }, [nodeTypeDefs]);
877
- const edgeTypeDefsMap = import_react4.default.useMemo(() => {
1000
+ const edgeTypeDefsMap = import_react9.default.useMemo(() => {
878
1001
  if (!(edgeTypeDefs == null ? void 0 : edgeTypeDefs.length)) return void 0;
879
1002
  return new Map(edgeTypeDefs.map((d) => [d.slug, d]));
880
1003
  }, [edgeTypeDefs]);
881
- const nodeTypes = import_react4.default.useMemo(
882
- () => 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
+ ),
883
1012
  [nodeRenderers, nodeTypeDefsMap, frameRenderer, nodeWrapper, renderNode]
884
1013
  );
885
- const customEdgeTypes = import_react4.default.useMemo(
1014
+ const customEdgeTypes = import_react9.default.useMemo(
886
1015
  () => createEdgeTypes(edgeRenderers, edgeTypeDefsMap),
887
1016
  [edgeRenderers, edgeTypeDefsMap]
888
1017
  );
889
- const mergedCSS = import_react4.default.useMemo(() => {
1018
+ const mergedCSS = import_react9.default.useMemo(() => {
890
1019
  if (!(nodeTypeDefs == null ? void 0 : nodeTypeDefs.length)) return "";
891
1020
  return nodeTypeDefs.filter((d) => d.customCSS).map((d) => d.customCSS).join("\n");
892
1021
  }, [nodeTypeDefs]);
893
- const styledEdges = import_react4.default.useMemo(() => {
1022
+ const styledEdges = import_react9.default.useMemo(() => {
894
1023
  var _a2;
895
1024
  let edges = applyEdgeStyles((_a2 = data == null ? void 0 : data.edges) != null ? _a2 : [], edgeTypeDefsMap);
896
1025
  if (edgeRenderers) {
@@ -904,64 +1033,98 @@ function FlowRenderer({
904
1033
  }
905
1034
  return edges;
906
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;
907
1065
  if (!data) return null;
908
1066
  const resolvedDefaultViewport = defaultViewportProp != null ? defaultViewportProp : !fitView && data.viewport ? data.viewport : void 0;
909
- const pad = focusPadding != null ? focusPadding : 0.1;
910
- const extentSource = clampBounds != null ? clampBounds : bounds;
911
- const extentPad = clampBounds ? 0 : pad;
912
- const translateExtent = translateExtentProp != null ? translateExtentProp : extentSource ? [
913
- [extentSource.x - extentPad * extentSource.width, extentSource.y - extentPad * extentSource.height],
914
- [
915
- extentSource.x + extentSource.width * (1 + extentPad),
916
- extentSource.y + extentSource.height * (1 + extentPad)
917
- ]
918
- ] : void 0;
919
- return /* @__PURE__ */ import_react4.default.createElement(import_react5.ReactFlowProvider, null, /* @__PURE__ */ import_react4.default.createElement(
1067
+ return /* @__PURE__ */ import_react9.default.createElement(import_react10.ReactFlowProvider, null, /* @__PURE__ */ import_react9.default.createElement(
920
1068
  "div",
921
1069
  {
922
1070
  className,
923
- style: __spreadValues({ width: "100%", height: "100%", background: "transparent" }, style)
1071
+ style: __spreadValues({
1072
+ width: "100%",
1073
+ height: "100%",
1074
+ background: "transparent"
1075
+ }, style)
924
1076
  },
925
- /* @__PURE__ */ import_react4.default.createElement(
926
- import_react5.ReactFlow,
1077
+ /* @__PURE__ */ import_react9.default.createElement(
1078
+ import_react10.ReactFlow,
927
1079
  {
928
- nodes: (_a = data.nodes) != null ? _a : [],
1080
+ nodes: (_b = data.nodes) != null ? _b : [],
929
1081
  edges: styledEdges,
930
1082
  nodeTypes,
931
1083
  edgeTypes: customEdgeTypes,
932
1084
  defaultViewport: resolvedDefaultViewport,
933
1085
  fitView: bounds ? false : fitView,
934
- translateExtent,
1086
+ translateExtent: activeExtent,
935
1087
  onNodeClick,
1088
+ onNodeDoubleClick,
1089
+ onNodeContextMenu,
1090
+ onNodeMouseEnter,
1091
+ onNodeMouseLeave,
936
1092
  onEdgeClick,
937
1093
  onMoveEnd: onViewportChange ? ((_, vp) => {
938
1094
  onViewportChange(vp);
939
1095
  }) : void 0,
940
1096
  nodesDraggable: interactive,
941
1097
  nodesConnectable: false,
942
- elementsSelectable: interactive || !!onNodeClick || !!onEdgeClick,
1098
+ elementsSelectable: interactive || !!onNodeClick || !!onNodeDoubleClick || !!onEdgeClick,
943
1099
  panOnDrag: interactive,
944
1100
  zoomOnScroll: interactive,
945
1101
  zoomOnPinch: interactive,
946
- zoomOnDoubleClick: false
1102
+ zoomOnDoubleClick: false,
1103
+ minZoom: minZoomProp,
1104
+ maxZoom: maxZoomProp,
1105
+ proOptions: { hideAttribution: true }
947
1106
  },
948
- mergedCSS && /* @__PURE__ */ import_react4.default.createElement("style", { dangerouslySetInnerHTML: { __html: mergedCSS } }),
949
- background && /* @__PURE__ */ import_react4.default.createElement(import_react5.Background, null),
950
- controls && /* @__PURE__ */ import_react4.default.createElement(import_react5.Controls, null),
951
- minimap && /* @__PURE__ */ import_react4.default.createElement(
952
- import_react5.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,
953
1112
  {
954
1113
  nodeColor: minimapNodeColor
955
1114
  }
956
1115
  ),
957
- bounds && /* @__PURE__ */ import_react4.default.createElement(
1116
+ bounds && /* @__PURE__ */ import_react9.default.createElement(
958
1117
  FocusHandler,
959
1118
  {
960
1119
  bounds,
961
1120
  padding: focusPadding != null ? focusPadding : 0.1,
962
1121
  animation: focusAnimation != null ? focusAnimation : true,
963
1122
  mode: focusMode,
964
- responsive: responsiveFit != null ? responsiveFit : true
1123
+ responsive: responsiveFit != null ? responsiveFit : true,
1124
+ extent: translateExtent,
1125
+ clampBounds,
1126
+ minZoomProp,
1127
+ onInitialFit: handleInitialFit
965
1128
  }
966
1129
  ),
967
1130
  children