@hitachivantara/uikit-react-lab
Version:
Contributed React components for the NEXT UI Kit.
205 lines (204 loc) • 6.64 kB
JavaScript
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const jsxRuntime = require("react/jsx-runtime");
const react = require("react");
const core = require("@dnd-kit/core");
const react$1 = require("@emotion/react");
const reactflow = require("reactflow");
const uid = require("uid");
const uikitReactCore = require("@hitachivantara/uikit-react-core");
const base = require("./base.cjs");
const Flow_styles = require("./Flow.styles.cjs");
const NodeMetaContext = require("./FlowContext/NodeMetaContext.cjs");
const useFlowInstance = require("./hooks/useFlowInstance.cjs");
const getNode = (nodes, nodeId) => {
return nodes.find((n) => n.id === nodeId);
};
const validateEdge = (nodes, edges, connection, nodeMetaRegistry) => {
const {
source: sourceId,
sourceHandle,
target: targetId,
targetHandle
} = connection;
if (!sourceHandle || !targetHandle || !sourceId || !targetId) return false;
const sourceNode = getNode(nodes, sourceId);
const targetNode = getNode(nodes, targetId);
if (!sourceNode || !targetNode) return false;
const sourceType = sourceNode.type;
const targetType = targetNode.type;
if (!sourceType || !targetType) return false;
const inputs = nodeMetaRegistry[targetId]?.inputs || [];
const outputs = nodeMetaRegistry[sourceId]?.outputs || [];
const source = outputs.flatMap((out) => out.outputs || out).find((out) => out.id === sourceHandle);
const target = inputs.flatMap((inp) => inp.inputs || inp).find((inp) => inp.id === targetHandle);
const sourceProvides = source?.provides || "";
const targetAccepts = target?.accepts || [];
const sourceMaxConnections = source?.maxConnections;
const targetMaxConnections = target?.maxConnections;
let isValid = targetAccepts.length === 0 || targetAccepts.includes(sourceProvides);
if (isValid && targetMaxConnections != null) {
const targetConnections = edges.filter(
(edg) => edg.target === targetId && edg.targetHandle === targetHandle
).length;
isValid = targetConnections < targetMaxConnections;
}
if (isValid && sourceMaxConnections != null) {
const sourceConnections = edges.filter(
(edg) => edg.source === sourceId && edg.sourceHandle === sourceHandle
).length;
isValid = sourceConnections < sourceMaxConnections;
}
return isValid;
};
const HvDroppableFlow = ({
id,
className,
children,
onFlowChange,
onDndDrop,
classes: classesProp,
nodes: initialNodes = [],
edges: initialEdges = [],
onConnect: onConnectProp,
onNodesChange: onNodesChangeProp,
onEdgesChange: onEdgesChangeProp,
defaultEdgeOptions: defaultEdgeOptionsProp,
nodeTypes,
...others
}) => {
const { classes, cx } = Flow_styles.useClasses(classesProp);
const elementId = uikitReactCore.useUniqueId(id);
const reactFlowInstance = useFlowInstance.useFlowInstance();
const [nodes, setNodes] = react.useState(initialNodes);
const [edges, setEdges] = react.useState(initialEdges);
const nodesRef = react.useRef(initialNodes);
const edgesRef = react.useRef(initialEdges);
const updateNodes = (nds) => {
setNodes(nds);
nodesRef.current = nds;
};
const updateEdges = (eds) => {
setEdges(eds);
edgesRef.current = eds;
};
const { setNodeRef } = core.useDroppable({
id: elementId
});
const handleDragEnd = react.useCallback(
(event) => {
if (event.over?.id !== elementId) return;
const hvFlow = event.active.data.current?.hvFlow;
const type = hvFlow?.type;
if (!type || !nodeTypes?.[type]) {
return;
}
const position = reactFlowInstance.screenToFlowPosition({
x: hvFlow?.x || 0,
y: hvFlow?.y || 0
});
const data = {
nodeLabel: hvFlow?.label,
...hvFlow?.data
};
const newNode = {
id: uid.uid(),
position,
data,
type
};
if (onDndDrop) {
onDndDrop(event, newNode);
return;
}
updateNodes(nodes.concat(newNode));
},
[elementId, nodeTypes, nodes, onDndDrop, reactFlowInstance]
);
core.useDndMonitor({
onDragEnd: handleDragEnd
});
const handleFlowChange = react.useCallback(
(nds, eds) => {
const isDragging = nds.find((node) => node.dragging);
if (!isDragging) {
onFlowChange?.(nds, eds);
}
},
[onFlowChange]
);
const handleConnect = react.useCallback(
(connection) => {
const eds = reactflow.addEdge(connection, edgesRef.current);
updateEdges(eds);
handleFlowChange(nodesRef.current, eds);
onConnectProp?.(connection);
},
[handleFlowChange, onConnectProp]
);
const handleNodesChange = react.useCallback(
(changes) => {
const nds = reactflow.applyNodeChanges(changes, nodesRef.current);
updateNodes(nds);
handleFlowChange(nds, edgesRef.current);
onNodesChangeProp?.(changes);
},
[handleFlowChange, onNodesChangeProp]
);
const handleEdgesChange = react.useCallback(
(changes) => {
const eds = reactflow.applyEdgeChanges(changes, edgesRef.current);
updateEdges(eds);
handleFlowChange(nodesRef.current, eds);
onEdgesChangeProp?.(changes);
},
[handleFlowChange, onEdgesChangeProp]
);
const { registry } = NodeMetaContext.useNodeMetaRegistry();
const isValidConnection = (connection) => validateEdge(nodes, edges, connection, registry);
const defaultEdgeOptions = {
markerEnd: {
type: reactflow.MarkerType.ArrowClosed,
height: 20,
width: 20
},
type: "smoothstep",
pathOptions: {
borderRadius: 40
},
...defaultEdgeOptionsProp
};
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(react$1.Global, { styles: base.flowStyles }),
/* @__PURE__ */ jsxRuntime.jsx(
"div",
{
id: elementId,
ref: setNodeRef,
className: cx(classes.root, className),
children: /* @__PURE__ */ jsxRuntime.jsx(
reactflow.ReactFlow,
{
nodes,
edges,
nodeTypes,
onNodesChange: handleNodesChange,
onEdgesChange: handleEdgesChange,
onConnect: handleConnect,
isValidConnection,
defaultEdgeOptions,
snapGrid: [1, 1],
snapToGrid: true,
onError: (code, message) => {
},
...others,
children
}
)
}
)
] });
};
exports.flowClasses = Flow_styles.staticClasses;
exports.HvDroppableFlow = HvDroppableFlow;
exports.getNode = getNode;