@rxflow/base
Version:
BaseFlow - 核心 Flow 组件库
253 lines (250 loc) • 14.6 kB
JavaScript
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
/**
* @author: yanxianliang
* @date: 2025-07-27 16:33
* @modified:2025/7/27 16:33 by yanxianliang
* @desc: Flow
*
* Copyright (c) 2025 by yanxianliang, All Rights Reserved.
*/
import '@xyflow/react/dist/style.css';
import { Legend } from "./components";
import { MarkerDefinitions } from "./components";
import { useForceUpdate } from "./hooks";
import { useGetState } from "./hooks";
import { useNodeTypes } from "./hooks";
import { useTheme } from "./hooks";
import { useThemeVars } from "./hooks";
import { Background, BackgroundVariant, MiniMap, ReactFlow, SelectionMode, useReactFlow, useStoreApi } from "@xyflow/react";
import { useMemoizedFn } from "ahooks";
import { omit } from "lodash";
import React, { useEffect, useMemo, useRef, useState } from "react";
import Controls from "./components/Controls";
import { DebugInfo } from "./components/DebugInfo";
import { ManhattanEdge } from "./edges/manhattan";
import { useGetEdgesChangeHandlers } from "./hooks/edges/useGetEdgesChangeHandlers";
import { useSetNodeDragging } from "./hooks/node/useSetNodeDragging";
import { useForceUpdateTimes } from "./hooks/render/useForceUpdateTimes";
import { useListenRender } from "./hooks/useListenRender";
import { Scrollbar } from "./plugins/scrollbar";
import { hasDimensionsChange } from "./utils/hasDimensionsChange";
import "./index.less";
import { baseLayout } from "./utils/layouts/base";
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
var proOptions = {
hideAttribution: true
}; // 默认隐藏水印
export function Flow(props) {
var width = props.width,
height = props.height,
_props$showControls = props.showControls,
showControls = _props$showControls === void 0 ? true : _props$showControls,
_props$controlsPositi = props.controlsPosition,
controlsPosition = _props$controlsPositi === void 0 ? 'top-right' : _props$controlsPositi,
controlsOrientation = props.controlsOrientation,
showMiniMap = props.showMiniMap,
showLegend = props.showLegend,
_props$background = props.background,
background = _props$background === void 0 ? '#F2F7FAFF' : _props$background,
showFullscreen = props.showFullscreen,
showForceLayout = props.showForceLayout,
showInteractive = props.showInteractive,
showFitView = props.showFitView,
showZoom = props.showZoom,
_props$onlyRenderVisi = props.onlyRenderVisibleElements,
onlyRenderVisibleElements = _props$onlyRenderVisi === void 0 ? true : _props$onlyRenderVisi,
_rootStyle = props.rootStyle,
fitViewOptions = props.fitViewOptions,
nodes = props.nodes,
edges = props.edges,
_props$layout = props.layout,
layout = _props$layout === void 0 ? baseLayout : _props$layout,
_props$autoCenter = props.autoCenter,
autoCenter = _props$autoCenter === void 0 ? false : _props$autoCenter,
_props$omitProps = props.omitProps,
omitProps = _props$omitProps === void 0 ? [] : _props$omitProps,
_props$forceLayout = props.forceLayout,
forceLayout = _props$forceLayout === void 0 ? !!props.layout : _props$forceLayout,
getMiniMapNodeColor = props.getMiniMapNodeColor,
markers = props.markers,
plugins = props.plugins,
readOnly = props.readOnly,
onZoomOut = props.onZoomOut,
onZoomIn = props.onZoomIn,
onFitView = props.onFitView,
onInteractiveChange = props.onInteractiveChange,
customControls = props.customControls,
_nodeTypes = props.nodeTypes,
onEdgesChange = props.onEdgesChange,
children = props.children,
forceFitView = props.forceFitView;
useListenRender(); // 性能监听 hook
var _useState = useState(!!(showMiniMap && !showControls)),
_useState2 = _slicedToArray(_useState, 2),
minimapVisible = _useState2[0],
setMinimapVisible = _useState2[1]; // 不显示控制器是默认按照字段控制 miniMap显示状态
var storeApi = useStoreApi();
var containerRef = useRef(null);
var theme = useTheme();
var themeVars = useThemeVars();
var nodeTypes = useNodeTypes(_nodeTypes); // 获取注册的节点类型
var forceUpdateTimes = useForceUpdateTimes();
var triggerLayout = useForceUpdate();
var setNodeDragging = useSetNodeDragging();
var instance = useReactFlow();
var getState = useGetState();
var rootStyle = useMemo(function () {
return _objectSpread(_objectSpread({
width: typeof width === 'number' ? "".concat(width, "px") : width,
height: typeof height === 'number' ? "".concat(height, "px") : height
}, _rootStyle), themeVars);
}, [width, height, _rootStyle, themeVars]);
var _useMemo = useMemo(function () {
var store = storeApi.getState();
return layout({
nodeTypes: nodeTypes,
originNodes: nodes || [],
originEdges: edges || [],
theme: theme,
onlyRenderVisibleElements: onlyRenderVisibleElements,
// 不支持修改该参数
store: store,
state: getState(),
flowProps: props
});
}, [nodes, edges, forceUpdateTimes]),
_nodes = _useMemo.nodes,
_edges = _useMemo.edges;
var flowProps = useMemo(function () {
var options = _objectSpread(_objectSpread({
selectNodesOnDrag: false,
preventScrolling: true,
panOnScroll: false,
zoomOnScroll: true,
nodesDraggable: false,
proOptions: proOptions,
fitViewOptions: _objectSpread({
nodes: _nodes !== null && _nodes !== void 0 && _nodes.length && autoCenter ? [_nodes[0]] : undefined
}, props.fitViewOptions),
fitView: true,
onlyRenderVisibleElements: onlyRenderVisibleElements
}, omit(props, ['flowInstanceRef', 'width', 'height', 'nodes', 'edges', 'fitViewOptions', 'theme', 'background', 'nodeTypes', 'showControls', 'showMiniMap', 'autoCenter', 'rootStyle', 'layout', 'onNodesChange', 'omitProps', 'forceLayout', 'controlsPosition', 'getMiniMapNodeColor', 'markers', 'onBeforeLayout', 'onLayout', 'onAfterLayout', 'plugins', 'readOnly', 'showFitView', 'showFullscreen', 'showInteractive', 'showZoom', 'showForceLayout', 'onInteractiveChange', 'onZoomOut', 'onZoomIn', 'onFitView', 'customControls', 'controlsOrientation'].concat(_toConsumableArray(omitProps)))), {}, {
edgeTypes: _objectSpread({
manhattan: ManhattanEdge
}, props.edgeTypes || {})
});
if (plugins !== null && plugins !== void 0 && plugins.scroller) {
var _options$panOnDrag, _options$selectionOnD, _options$selectionMod;
// 只读模式也需要
options.zoomOnScroll = false;
options.panOnScroll = true;
options.panOnDrag = (_options$panOnDrag = options.panOnDrag) !== null && _options$panOnDrag !== void 0 ? _options$panOnDrag : [1, 2];
options.selectionOnDrag = (_options$selectionOnD = options.selectionOnDrag) !== null && _options$selectionOnD !== void 0 ? _options$selectionOnD : true;
options.selectionMode = (_options$selectionMod = options.selectionMode) !== null && _options$selectionMod !== void 0 ? _options$selectionMod : SelectionMode.Partial;
}
if (readOnly) {
options.nodesDraggable = false;
options.nodesConnectable = false;
options.elementsSelectable = false;
}
return options;
}, [props, _nodes, readOnly, onlyRenderVisibleElements]);
var onNodesChange = useMemoizedFn(function (changes) {
var _props$onNodesChange;
if (forceLayout && hasDimensionsChange(changes)) {
// 强制布局
triggerLayout();
}
(_props$onNodesChange = props.onNodesChange) === null || _props$onNodesChange === void 0 || _props$onNodesChange.call(props, changes);
});
var onNodeDragStart = useMemoizedFn(function (event, node, nodes) {
var _flowProps$onNodeDrag;
setNodeDragging(true);
(_flowProps$onNodeDrag = flowProps.onNodeDragStart) === null || _flowProps$onNodeDrag === void 0 || _flowProps$onNodeDrag.call(flowProps, event, node, nodes);
});
var onNodeDragStop = useMemoizedFn(function (event, node, nodes) {
var _flowProps$onNodeDrag2;
setNodeDragging(false);
(_flowProps$onNodeDrag2 = flowProps.onNodeDragStop) === null || _flowProps$onNodeDrag2 === void 0 || _flowProps$onNodeDrag2.call(flowProps, event, node, nodes);
});
var getEdgesChangeHandlers = useGetEdgesChangeHandlers();
var _onEdgesChange = useMemoizedFn(function (changes) {
var _getEdgesChangeHandle;
onEdgesChange === null || onEdgesChange === void 0 || onEdgesChange(changes);
// 触发注册事件
(_getEdgesChangeHandle = getEdgesChangeHandlers()) === null || _getEdgesChangeHandle === void 0 || _getEdgesChangeHandle.forEach(function (onEdgesChange) {
onEdgesChange === null || onEdgesChange === void 0 || onEdgesChange(changes);
});
});
useEffect(function () {
if (forceFitView) {
instance.fitView(fitViewOptions);
}
}, [nodes]);
return /*#__PURE__*/_jsxs("div", {
ref: containerRef,
style: rootStyle,
children: [/*#__PURE__*/_jsx(DebugInfo, {
debug: props.debug
}), markers ? /*#__PURE__*/_jsx(MarkerDefinitions, {
marks: markers
}) : null, /*#__PURE__*/_jsxs(ReactFlow, _objectSpread(_objectSpread({
nodeTypes: nodeTypes
}, flowProps), {}, {
nodes: _nodes,
edges: _edges,
onNodesChange: onNodesChange,
onNodeDragStart: onNodeDragStart,
onNodeDragStop: onNodeDragStop,
onEdgesChange: _onEdgesChange,
children: [plugins !== null && plugins !== void 0 && plugins.scroller ? /*#__PURE__*/_jsx(Scrollbar, _objectSpread(_objectSpread({}, plugins.scroller), {}, {
width: width,
height: height
})) : null, /*#__PURE__*/_jsx(Background, {
bgColor: background,
className: 'rxflow-bg-hide-pattern',
variant: BackgroundVariant.Lines
}), minimapVisible && /*#__PURE__*/_jsx(MiniMap, {
zoomable: true,
pannable: true,
nodeColor: getMiniMapNodeColor
}), showControls && /*#__PURE__*/_jsx(Controls, {
showFullscreen: showFullscreen,
containerRef: containerRef,
fitViewOptions: fitViewOptions,
position: controlsPosition,
showInteractive: showInteractive,
showMiniMap: showMiniMap,
showFitView: showFitView,
showZoom: showZoom,
setMinimapVisible: setMinimapVisible,
minimapVisible: minimapVisible,
showForceLayout: showForceLayout,
onFitView: onFitView,
onZoomOut: onZoomOut,
onZoomIn: onZoomIn,
onInteractiveChange: onInteractiveChange,
children: customControls,
orientation: controlsOrientation
}), showLegend && /*#__PURE__*/_jsx(Legend, {
showLegend: showLegend
}), children]
}))]
});
}