Merge pull request #2469 from Alireza29675/feat/cancel-connection-example
feat(examples): example added for cancelConnection
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
"test-e2e": "start-server-and-test 'pnpm serve' http-get://localhost:3000 'pnpm test-e2e-cypress'"
|
"test-e2e": "start-server-and-test 'pnpm serve' http-get://localhost:3000 'pnpm test-e2e-cypress'"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"classcat": "^5.0.3",
|
||||||
"dagre": "^0.8.5",
|
"dagre": "^0.8.5",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import UseReactFlow from '../examples/UseReactFlow';
|
|||||||
import Validation from '../examples/Validation';
|
import Validation from '../examples/Validation';
|
||||||
import UseKeyPress from '../examples/UseKeyPress';
|
import UseKeyPress from '../examples/UseKeyPress';
|
||||||
import EdgeRouting from '../examples/EdgeRouting';
|
import EdgeRouting from '../examples/EdgeRouting';
|
||||||
|
import CancelConnection from '../examples/CancelConnection';
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@@ -173,6 +174,10 @@ const routes = [
|
|||||||
path: '/use-key-press',
|
path: '/use-key-press',
|
||||||
component: UseKeyPress,
|
component: UseKeyPress,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/cancel-connection',
|
||||||
|
component: CancelConnection
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
.Timer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 100%);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
z-index: 999;
|
||||||
|
background: linear-gradient(#fff, #fff, #f5f5f5);
|
||||||
|
padding: 0.8rem 1.5rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Timer.show {
|
||||||
|
transform: translate(-50%, 0%) translateY(-15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 5px;
|
||||||
|
background: linear-gradient(to right, #42df96, #16dfed);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Timer.show .progress {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import cc from 'classcat';
|
||||||
|
import styles from './Timer.module.css';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
duration: number;
|
||||||
|
remaining: number;
|
||||||
|
show: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Timer({
|
||||||
|
duration,
|
||||||
|
remaining,
|
||||||
|
show,
|
||||||
|
}: Props) {
|
||||||
|
const percentage = 100 - (remaining / duration) * 100;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cc({
|
||||||
|
[styles.Timer]: true,
|
||||||
|
[styles.show]: show,
|
||||||
|
})}>
|
||||||
|
<div className={styles.progress} style={{
|
||||||
|
width: `${percentage}%`,
|
||||||
|
}} />
|
||||||
|
Connection will be canceled in {remaining} seconds
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Edge, Node } from 'reactflow';
|
||||||
|
|
||||||
|
export const initialNodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const initialEdges: Edge[] = [
|
||||||
|
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||||
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
|
];
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
|
const useCountdown = (callback: () => void) => {
|
||||||
|
const interval = useRef<NodeJS.Timer>();
|
||||||
|
const [remaining, setRemaining] = useState(0);
|
||||||
|
|
||||||
|
const start = (duration: number) => {
|
||||||
|
setRemaining(duration);
|
||||||
|
|
||||||
|
interval.current = setInterval(() => {
|
||||||
|
setRemaining((prev) => {
|
||||||
|
if (prev === 1) {
|
||||||
|
clearInterval(interval.current);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return prev - 1;
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const stop = () => {
|
||||||
|
clearInterval(interval.current);
|
||||||
|
setRemaining(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
start,
|
||||||
|
remaining,
|
||||||
|
stop,
|
||||||
|
counting: remaining > 0,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useCountdown;
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import ReactFlow, {
|
||||||
|
Background,
|
||||||
|
MiniMap,
|
||||||
|
addEdge,
|
||||||
|
ReactFlowProvider,
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
useNodesState,
|
||||||
|
useEdgesState,
|
||||||
|
OnConnectStart,
|
||||||
|
OnConnectEnd,
|
||||||
|
useStore,
|
||||||
|
} from 'reactflow';
|
||||||
|
|
||||||
|
import useCountdown from './hooks/useCountdown';
|
||||||
|
import { initialEdges, initialNodes } from './data';
|
||||||
|
import Timer from './Timer';
|
||||||
|
|
||||||
|
const CANCEL_AFTER = 5; // seconds
|
||||||
|
|
||||||
|
const CancelConnection = () => {
|
||||||
|
const [nodes, _, onNodesChange] = useNodesState(initialNodes);
|
||||||
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
const cancelConnection = useStore(state => state.cancelConnection)
|
||||||
|
|
||||||
|
// Cancels connection after 5 seconds
|
||||||
|
const countdown = useCountdown(() => cancelConnection());
|
||||||
|
const onConnectStart: OnConnectStart = () => countdown.start(CANCEL_AFTER);
|
||||||
|
const onConnectEnd: OnConnectEnd = () => countdown.stop();
|
||||||
|
|
||||||
|
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Timer
|
||||||
|
duration={CANCEL_AFTER}
|
||||||
|
show={countdown.counting}
|
||||||
|
remaining={countdown.remaining}
|
||||||
|
/>
|
||||||
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
edges={edges}
|
||||||
|
onNodesChange={onNodesChange}
|
||||||
|
onEdgesChange={onEdgesChange}
|
||||||
|
onConnectStart={onConnectStart}
|
||||||
|
onConnectEnd={onConnectEnd}
|
||||||
|
onConnect={onConnect}
|
||||||
|
fitView
|
||||||
|
maxZoom={2}
|
||||||
|
>
|
||||||
|
<Background />
|
||||||
|
<MiniMap />
|
||||||
|
</ReactFlow>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<CancelConnection />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
);
|
||||||
@@ -224,6 +224,7 @@ export type ReactFlowActions = {
|
|||||||
setMaxZoom: (maxZoom: number) => void;
|
setMaxZoom: (maxZoom: number) => void;
|
||||||
setTranslateExtent: (translateExtent: CoordinateExtent) => void;
|
setTranslateExtent: (translateExtent: CoordinateExtent) => void;
|
||||||
setNodeExtent: (nodeExtent: CoordinateExtent) => void;
|
setNodeExtent: (nodeExtent: CoordinateExtent) => void;
|
||||||
|
cancelConnection: () => void;
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Generated
+2
@@ -60,6 +60,7 @@ importers:
|
|||||||
'@types/react': ^18.0.17
|
'@types/react': ^18.0.17
|
||||||
'@types/react-dom': ^18.0.6
|
'@types/react-dom': ^18.0.6
|
||||||
'@vitejs/plugin-react': ^2.1.0
|
'@vitejs/plugin-react': ^2.1.0
|
||||||
|
classcat: ^5.0.3
|
||||||
cypress: ^10.6.0
|
cypress: ^10.6.0
|
||||||
cypress-real-events: ^1.7.1
|
cypress-real-events: ^1.7.1
|
||||||
dagre: ^0.8.5
|
dagre: ^0.8.5
|
||||||
@@ -72,6 +73,7 @@ importers:
|
|||||||
typescript: ^4.8.3
|
typescript: ^4.8.3
|
||||||
vite: ^3.1.0
|
vite: ^3.1.0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
classcat: registry.npmjs.org/classcat/5.0.4
|
||||||
dagre: registry.npmjs.org/dagre/0.8.5
|
dagre: registry.npmjs.org/dagre/0.8.5
|
||||||
localforage: registry.npmjs.org/localforage/1.10.0
|
localforage: registry.npmjs.org/localforage/1.10.0
|
||||||
react: registry.npmjs.org/react/18.2.0
|
react: registry.npmjs.org/react/18.2.0
|
||||||
|
|||||||
Reference in New Issue
Block a user