@@ -188,6 +188,7 @@ const targetHandleWithValidation = (
|
|||||||
- `onConnect`: function that gets triggered on connect
|
- `onConnect`: function that gets triggered on connect
|
||||||
- `isValidConnection`: function receives a connection `{ target: 'some-id', source: 'another-id' }` as param, returns a boolean - true by default
|
- `isValidConnection`: function receives a connection `{ target: 'some-id', source: 'another-id' }` as param, returns a boolean - true by default
|
||||||
- `style`: css properties
|
- `style`: css properties
|
||||||
|
- `className`: additional class name
|
||||||
|
|
||||||
#### Multiple Handles
|
#### Multiple Handles
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="m376,187l-20,0l0,-40c0,-55 -45,-100 -100,-100c-54.002,23.996 -17.999,27.998 4,31.998c21.999,4 58.002,33.998 58.002,68.002l-0.002,0l0,40l-182,0c-22.002,0 -40,17.998 -40,40l0,200c0,22.002 17.998,40 40,40l240,0c22.002,0 40,-17.998 40,-40l0,-200c0,-22.002 -17.998,-40 -40,-40zm-120,182c-22.002,0 -40,-17.998 -40,-40s17.998,-40 40,-40s40,17.998 40,40s-17.998,40 -40,40z"/></svg>
|
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m376 187h-20v-40c0-55-45-100-100-100-54.002 23.996-17.999 27.998 4 31.998s58.002 33.998 58.002 68.002h-.002v40h-182c-22.002 0-40 17.998-40 40v200c0 22.002 17.998 40 40 40h240c22.002 0 40-17.998 40-40v-200c0-22.002-17.998-40-40-40zm-120 182c-22.002 0-40-17.998-40-40s17.998-40 40-40 40 17.998 40 40-17.998 40-40 40z"/></svg>
|
||||||
|
Before Width: | Height: | Size: 445 B After Width: | Height: | Size: 394 B |
@@ -6,7 +6,7 @@ describe('Basic Graph Rendering', () => {
|
|||||||
cy.get('.react-flow-basic-example'); // check if className prop works
|
cy.get('.react-flow-basic-example'); // check if className prop works
|
||||||
cy.get('.react-flow__node').should('have.length', 4);
|
cy.get('.react-flow__node').should('have.length', 4);
|
||||||
cy.get('.react-flow__edge').should('have.length', 2);
|
cy.get('.react-flow__edge').should('have.length', 2);
|
||||||
cy.get('.react-flow__node').children('div').children('.react-flow__handle');
|
cy.get('.react-flow__node').children('.react-flow__handle');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a grid', () => {
|
it('renders a grid', () => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ describe('Inactive Graph Rendering', () => {
|
|||||||
cy.get('.react-flow__renderer');
|
cy.get('.react-flow__renderer');
|
||||||
cy.get('.react-flow__node').should('have.length', 4);
|
cy.get('.react-flow__node').should('have.length', 4);
|
||||||
cy.get('.react-flow__edge').should('have.length', 2);
|
cy.get('.react-flow__edge').should('have.length', 2);
|
||||||
cy.get('.react-flow__node').children('div').children('.react-flow__handle');
|
cy.get('.react-flow__node').children('.react-flow__handle');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tries to select a node by click', () => {
|
it('tries to select a node by click', () => {
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ import React from 'react';
|
|||||||
|
|
||||||
import { Handle } from 'react-flow-renderer';
|
import { Handle } from 'react-flow-renderer';
|
||||||
|
|
||||||
export default ({ data, styles }) => {
|
export default ({ data }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
style={{ background: '#eee', border: '1px solid #ddd', padding: 10, borderRadius: 5, ...styles }}
|
|
||||||
>
|
|
||||||
<Handle
|
<Handle
|
||||||
type="target"
|
type="target"
|
||||||
position="left"
|
position="left"
|
||||||
@@ -27,6 +25,6 @@ export default ({ data, styles }) => {
|
|||||||
id="b"
|
id="b"
|
||||||
style={{ bottom: 10, top: 'auto', background: '#fff' }}
|
style={{ bottom: 10, top: 'auto', background: '#fff' }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const CustomNodeFlow = () => {
|
|||||||
|
|
||||||
setElements([
|
setElements([
|
||||||
{ id: '1', type: 'input', data: { label: 'An input node' }, position: { x: 0, y: 50 }, sourcePosition: 'right' },
|
{ id: '1', type: 'input', data: { label: 'An input node' }, position: { x: 0, y: 50 }, sourcePosition: 'right' },
|
||||||
{ id: '2', type: 'selectorNode', data: { onChange: onChange, color: initBgColor }, position: { x: 250, y: 50 } },
|
{ id: '2', type: 'selectorNode', data: { onChange: onChange, color: initBgColor }, style: { border: '1px solid #777' }, position: { x: 250, y: 50 } },
|
||||||
{ id: '3', type: 'output', data: { label: 'Output A' }, position: { x: 550, y: 25 }, targetPosition: 'left' },
|
{ id: '3', type: 'output', data: { label: 'Output A' }, position: { x: 550, y: 25 }, targetPosition: 'left' },
|
||||||
{ id: '4', type: 'output', data: { label: 'Output B' }, position: { x: 550, y: 100 }, targetPosition: 'left' },
|
{ id: '4', type: 'output', data: { label: 'Output B' }, position: { x: 550, y: 100 }, targetPosition: 'left' },
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,20 @@ const onLoad = (graph) => {
|
|||||||
const initialElements = [
|
const initialElements = [
|
||||||
{ id: '1', sourcePosition: 'right', type: 'input', className: 'dark-node', data: { label: 'Input' }, position: { x: 0, y: 80 } },
|
{ id: '1', sourcePosition: 'right', type: 'input', className: 'dark-node', data: { label: 'Input' }, position: { x: 0, y: 80 } },
|
||||||
{ id: '2', sourcePosition: 'right', targetPosition: 'left', data: { label: 'A Node' }, position: { x: 250, y: 0 } },
|
{ id: '2', sourcePosition: 'right', targetPosition: 'left', data: { label: 'A Node' }, position: { x: 250, y: 0 } },
|
||||||
{ id: '3', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Another node' }, position: { x: 250, y: 160 } },
|
{ id: '3', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Node 3' }, position: { x: 250, y: 160 } },
|
||||||
{ id: '4', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Node 4' }, position: { x: 500, y: 80 } },
|
{ id: '4', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Node 4' }, position: { x: 500, y: 0 } },
|
||||||
|
{ id: '5', sourcePosition: 'top', targetPosition: 'bottom', data: { label: 'Node 5' }, position: { x: 500, y: 100 } },
|
||||||
|
{ id: '6', sourcePosition: 'bottom', targetPosition: 'top', data: { label: 'Node 6' }, position: { x: 500, y: 230 } },
|
||||||
|
{ id: '7', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Node 7' }, position: { x: 750, y: 50 } },
|
||||||
|
{ id: '8', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Node 8' }, position: { x: 750, y: 300 } },
|
||||||
|
|
||||||
{ id: 'e1-2', source: '1', target: '2', animated: true, },
|
{ id: 'e1-2', source: '1', target: '2', animated: true, },
|
||||||
{ id: 'e1-3', source: '1', target: '3', animated: true, },
|
{ id: 'e1-3', source: '1', target: '3', animated: true, },
|
||||||
{ id: 'e1-4', source: '2', target: '4', label: 'edge label' }
|
{ id: 'e1-4', source: '2', target: '4', label: 'edge label' },
|
||||||
|
{ id: 'e3-5', source: '3', target: '5', animated: true },
|
||||||
|
{ id: 'e3-6', source: '3', target: '6', animated: true },
|
||||||
|
{ id: 'e5-7', source: '5', target: '7', animated: true },
|
||||||
|
{ id: 'e6-8', source: '6', target: '8', animated: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
const HorizontalFlow = () => {
|
const HorizontalFlow = () => {
|
||||||
|
|||||||
@@ -136,9 +136,9 @@ nav a.active:before {
|
|||||||
color: #111;
|
color: #111;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark-node>div {
|
.dark-node {
|
||||||
background: #333 !important;
|
background: #333;
|
||||||
color: #f8f8f8 !important;
|
color: #f8f8f8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
|
|||||||
+3
-1
@@ -37,7 +37,9 @@ export default [
|
|||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
bundleSize(),
|
bundleSize(),
|
||||||
postcss(),
|
postcss({
|
||||||
|
minimize: isProd,
|
||||||
|
}),
|
||||||
babel({
|
babel({
|
||||||
exclude: 'node_modules/**',
|
exclude: 'node_modules/**',
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import React, { memo, HTMLAttributes, CSSProperties } from 'react';
|
import React, { memo, HTMLAttributes } from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import { useStoreState } from '../../store/hooks';
|
import { useStoreState } from '../../store/hooks';
|
||||||
import { BackgroundVariant } from '../../types';
|
import { BackgroundVariant } from '../../types';
|
||||||
import { createGridLinesPath, createGridDotsPath } from './utils';
|
import { createGridLinesPath, createGridDotsPath } from './utils';
|
||||||
|
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
interface BackgroundProps extends HTMLAttributes<SVGElement> {
|
interface BackgroundProps extends HTMLAttributes<SVGElement> {
|
||||||
variant?: BackgroundVariant;
|
variant?: BackgroundVariant;
|
||||||
gap?: number;
|
gap?: number;
|
||||||
@@ -12,19 +14,13 @@ interface BackgroundProps extends HTMLAttributes<SVGElement> {
|
|||||||
size?: number;
|
size?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseStyles: CSSProperties = {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultColors = {
|
const defaultColors = {
|
||||||
[BackgroundVariant.Dots]: '#999',
|
[BackgroundVariant.Dots]: '#999',
|
||||||
[BackgroundVariant.Lines]: '#eee',
|
[BackgroundVariant.Lines]: '#eee',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Background = memo(
|
const Background = memo(
|
||||||
({ variant = BackgroundVariant.Dots, gap = 24, size = 0.5, color, style = {}, className = '' }: BackgroundProps) => {
|
({ variant = BackgroundVariant.Dots, gap = 24, size = 0.5, color, style, className }: BackgroundProps) => {
|
||||||
const width = useStoreState((s) => s.width);
|
const width = useStoreState((s) => s.width);
|
||||||
const height = useStoreState((s) => s.height);
|
const height = useStoreState((s) => s.height);
|
||||||
const [x, y, scale] = useStoreState((s) => s.transform);
|
const [x, y, scale] = useStoreState((s) => s.transform);
|
||||||
@@ -42,7 +38,7 @@ const Background = memo(
|
|||||||
const stroke = isLines ? bgColor : 'none';
|
const stroke = isLines ? bgColor : 'none';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg width={width} height={height} style={{ ...baseStyles, ...style }} className={bgClasses}>
|
<svg width={width} height={height} style={style} className={bgClasses}>
|
||||||
<path fill={fill} stroke={stroke} strokeWidth={size} d={path} />
|
<path fill={fill} stroke={stroke} strokeWidth={size} d={path} />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.react-flow__background {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { CSSProperties } from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
||||||
@@ -10,12 +10,7 @@ import FitviewIcon from '../../../assets/icons/fitview.svg';
|
|||||||
import LockIcon from '../../../assets/icons/lock.svg';
|
import LockIcon from '../../../assets/icons/lock.svg';
|
||||||
import UnlockIcon from '../../../assets/icons/unlock.svg';
|
import UnlockIcon from '../../../assets/icons/unlock.svg';
|
||||||
|
|
||||||
const baseStyle: CSSProperties = {
|
import './style.css';
|
||||||
position: 'absolute',
|
|
||||||
zIndex: 5,
|
|
||||||
bottom: 10,
|
|
||||||
left: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
showZoom?: boolean;
|
showZoom?: boolean;
|
||||||
@@ -26,16 +21,10 @@ interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
|||||||
const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
||||||
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
||||||
const isInteractive = useStoreState((s) => s.isInteractive);
|
const isInteractive = useStoreState((s) => s.isInteractive);
|
||||||
const mapClasses: string = classnames('react-flow__controls', className);
|
const mapClasses = classnames('react-flow__controls', className);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={mapClasses} style={style}>
|
||||||
className={mapClasses}
|
|
||||||
style={{
|
|
||||||
...baseStyle,
|
|
||||||
...style,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{showZoom && (
|
{showZoom && (
|
||||||
<>
|
<>
|
||||||
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={zoomIn}>
|
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={zoomIn}>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
.react-flow__controls {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 5;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 10px;
|
||||||
|
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
&-button {
|
||||||
|
background: #fefefe;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f4f4f4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ const MiniMapNode = ({ node, color, borderRadius }: MiniMapNodeProps) => {
|
|||||||
} = node.__rg;
|
} = node.__rg;
|
||||||
const { background, backgroundColor } = node.style || {};
|
const { background, backgroundColor } = node.style || {};
|
||||||
const fill = (background || backgroundColor || color) as string;
|
const fill = (background || backgroundColor || color) as string;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<rect
|
<rect
|
||||||
className="react-flow__minimap-node"
|
className="react-flow__minimap-node"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { CSSProperties } from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import { useStoreState } from '../../store/hooks';
|
import { useStoreState } from '../../store/hooks';
|
||||||
@@ -6,6 +6,8 @@ import { getRectOfNodes, getBoundsofRects } from '../../utils/graph';
|
|||||||
import { Node, Rect } from '../../types';
|
import { Node, Rect } from '../../types';
|
||||||
import MiniMapNode from './MiniMapNode';
|
import MiniMapNode from './MiniMapNode';
|
||||||
|
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
type StringFunc = (node: Node) => string;
|
type StringFunc = (node: Node) => string;
|
||||||
|
|
||||||
interface MiniMapProps extends React.HTMLAttributes<SVGSVGElement> {
|
interface MiniMapProps extends React.HTMLAttributes<SVGSVGElement> {
|
||||||
@@ -14,14 +16,8 @@ interface MiniMapProps extends React.HTMLAttributes<SVGSVGElement> {
|
|||||||
maskColor?: string;
|
maskColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseStyle: CSSProperties = {
|
const defaultWidth = 200;
|
||||||
position: 'absolute',
|
const defaultHeight = 150;
|
||||||
zIndex: 5,
|
|
||||||
bottom: 10,
|
|
||||||
right: 10,
|
|
||||||
width: 200,
|
|
||||||
height: 150,
|
|
||||||
};
|
|
||||||
|
|
||||||
const MiniMap = ({
|
const MiniMap = ({
|
||||||
style = { backgroundColor: '#f8f8f8' },
|
style = { backgroundColor: '#f8f8f8' },
|
||||||
@@ -36,11 +32,10 @@ const MiniMap = ({
|
|||||||
const nodes = useStoreState((s) => s.nodes);
|
const nodes = useStoreState((s) => s.nodes);
|
||||||
|
|
||||||
const mapClasses = classnames('react-flow__minimap', className);
|
const mapClasses = classnames('react-flow__minimap', className);
|
||||||
const elementWidth = (style.width || baseStyle.width)! as number;
|
const elementWidth = (style.width || defaultWidth)! as number;
|
||||||
const elementHeight = (style.height || baseStyle.height)! as number;
|
const elementHeight = (style.height || defaultHeight)! as number;
|
||||||
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
||||||
const hasNodes = nodes && nodes.length;
|
const hasNodes = nodes && nodes.length;
|
||||||
|
|
||||||
const bb = getRectOfNodes(nodes);
|
const bb = getRectOfNodes(nodes);
|
||||||
const viewBB: Rect = {
|
const viewBB: Rect = {
|
||||||
x: -tX / tScale,
|
x: -tX / tScale,
|
||||||
@@ -48,17 +43,13 @@ const MiniMap = ({
|
|||||||
width: containerWidth / tScale,
|
width: containerWidth / tScale,
|
||||||
height: containerHeight / tScale,
|
height: containerHeight / tScale,
|
||||||
};
|
};
|
||||||
|
|
||||||
const boundingRect = hasNodes ? getBoundsofRects(bb, viewBB) : viewBB;
|
const boundingRect = hasNodes ? getBoundsofRects(bb, viewBB) : viewBB;
|
||||||
|
|
||||||
const scaledWidth = boundingRect.width / elementWidth;
|
const scaledWidth = boundingRect.width / elementWidth;
|
||||||
const scaledHeight = boundingRect.height / elementHeight;
|
const scaledHeight = boundingRect.height / elementHeight;
|
||||||
const viewScale = Math.max(scaledWidth, scaledHeight);
|
const viewScale = Math.max(scaledWidth, scaledHeight);
|
||||||
const viewWidth = viewScale * elementWidth;
|
const viewWidth = viewScale * elementWidth;
|
||||||
const viewHeight = viewScale * elementHeight;
|
const viewHeight = viewScale * elementHeight;
|
||||||
|
|
||||||
const offset = 5 * viewScale;
|
const offset = 5 * viewScale;
|
||||||
|
|
||||||
const x = boundingRect.x - (viewWidth - boundingRect.width) / 2 - offset;
|
const x = boundingRect.x - (viewWidth - boundingRect.width) / 2 - offset;
|
||||||
const y = boundingRect.y - (viewHeight - boundingRect.height) / 2 - offset;
|
const y = boundingRect.y - (viewHeight - boundingRect.height) / 2 - offset;
|
||||||
const width = viewWidth + offset * 2;
|
const width = viewWidth + offset * 2;
|
||||||
@@ -69,10 +60,7 @@ const MiniMap = ({
|
|||||||
width={elementWidth}
|
width={elementWidth}
|
||||||
height={elementHeight}
|
height={elementHeight}
|
||||||
viewBox={`${x} ${y} ${width} ${height}`}
|
viewBox={`${x} ${y} ${width} ${height}`}
|
||||||
style={{
|
style={style}
|
||||||
...baseStyle,
|
|
||||||
...style,
|
|
||||||
}}
|
|
||||||
className={mapClasses}
|
className={mapClasses}
|
||||||
>
|
>
|
||||||
{nodes.map((node) => (
|
{nodes.map((node) => (
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.react-flow__minimap {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 5;
|
||||||
|
bottom: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import React, { useEffect, useState, CSSProperties } from 'react';
|
import React, { useEffect, useState, CSSProperties } from 'react';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
|
|
||||||
import { ElementId, Node, Transform, HandleElement, Position } from '../../types';
|
import { ElementId, Node, Transform, HandleElement, Position, ConnectionLineType } from '../../types';
|
||||||
|
|
||||||
interface ConnectionLineProps {
|
interface ConnectionLineProps {
|
||||||
connectionSourceId: ElementId;
|
connectionSourceId: ElementId;
|
||||||
connectionPositionX: number;
|
connectionPositionX: number;
|
||||||
connectionPositionY: number;
|
connectionPositionY: number;
|
||||||
connectionLineType?: string | null;
|
connectionLineType: ConnectionLineType;
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
transform: Transform;
|
transform: Transform;
|
||||||
isInteractive: boolean;
|
isInteractive: boolean;
|
||||||
@@ -17,10 +17,10 @@ interface ConnectionLineProps {
|
|||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
connectionSourceId,
|
connectionSourceId,
|
||||||
connectionLineStyle = {},
|
connectionLineStyle,
|
||||||
connectionPositionX,
|
connectionPositionX,
|
||||||
connectionPositionY,
|
connectionPositionY,
|
||||||
connectionLineType,
|
connectionLineType = ConnectionLineType.Bezier,
|
||||||
nodes = [],
|
nodes = [],
|
||||||
className,
|
className,
|
||||||
transform,
|
transform,
|
||||||
@@ -60,7 +60,7 @@ export default ({
|
|||||||
|
|
||||||
let dAttr: string = '';
|
let dAttr: string = '';
|
||||||
|
|
||||||
if (connectionLineType === 'bezier') {
|
if (connectionLineType === ConnectionLineType.Bezier) {
|
||||||
if (sourceHandle?.position === Position.Left || sourceHandle?.position === Position.Right) {
|
if (sourceHandle?.position === Position.Left || sourceHandle?.position === Position.Right) {
|
||||||
const xOffset = Math.abs(targetX - sourceX) / 2;
|
const xOffset = Math.abs(targetX - sourceX) / 2;
|
||||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default memo(
|
|||||||
labelStyle,
|
labelStyle,
|
||||||
labelShowBg,
|
labelShowBg,
|
||||||
labelBgStyle,
|
labelBgStyle,
|
||||||
style = {},
|
style,
|
||||||
}: EdgeBezierProps) => {
|
}: EdgeBezierProps) => {
|
||||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||||
@@ -26,10 +26,13 @@ export default memo(
|
|||||||
let dAttr = `M${sourceX},${sourceY} C${sourceX},${centerY} ${targetX},${centerY} ${targetX},${targetY}`;
|
let dAttr = `M${sourceX},${sourceY} C${sourceX},${centerY} ${targetX},${centerY} ${targetX},${targetY}`;
|
||||||
|
|
||||||
const leftAndRight = [Position.Left, Position.Right];
|
const leftAndRight = [Position.Left, Position.Right];
|
||||||
|
|
||||||
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||||
dAttr = `M${sourceX},${sourceY} C${centerX},${sourceY} ${centerX},${targetY} ${targetX},${targetY}`;
|
dAttr = `M${sourceX},${sourceY} C${centerX},${sourceY} ${centerX},${targetY} ${targetX},${targetY}`;
|
||||||
} else if (leftAndRight.includes(sourcePosition) || leftAndRight.includes(targetPosition)) {
|
} else if (leftAndRight.includes(targetPosition)) {
|
||||||
dAttr = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
|
dAttr = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
|
||||||
|
} else if (leftAndRight.includes(sourcePosition)) {
|
||||||
|
dAttr = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = label ? (
|
const text = label ? (
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import EdgeText from './EdgeText';
|
|||||||
import { EdgeProps } from '../../types';
|
import { EdgeProps } from '../../types';
|
||||||
|
|
||||||
export default memo(
|
export default memo(
|
||||||
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style = {} }: EdgeProps) => {
|
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: EdgeProps) => {
|
||||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import EdgeText from './EdgeText';
|
|||||||
import { EdgeProps } from '../../types';
|
import { EdgeProps } from '../../types';
|
||||||
|
|
||||||
export default memo(
|
export default memo(
|
||||||
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style = {} }: EdgeProps) => {
|
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: EdgeProps) => {
|
||||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ interface EdgeWrapperProps {
|
|||||||
labelStyle?: CSSProperties;
|
labelStyle?: CSSProperties;
|
||||||
labelShowBg?: boolean;
|
labelShowBg?: boolean;
|
||||||
labelBgStyle: CSSProperties;
|
labelBgStyle: CSSProperties;
|
||||||
|
className?: string;
|
||||||
onClick?: (edge: Edge) => void;
|
onClick?: (edge: Edge) => void;
|
||||||
animated: boolean;
|
animated?: boolean;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
isInteractive: boolean;
|
isInteractive: boolean;
|
||||||
}
|
}
|
||||||
@@ -34,9 +35,10 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
|||||||
labelStyle,
|
labelStyle,
|
||||||
labelShowBg,
|
labelShowBg,
|
||||||
labelBgStyle,
|
labelBgStyle,
|
||||||
|
className,
|
||||||
...rest
|
...rest
|
||||||
}: EdgeWrapperProps) => {
|
}: EdgeWrapperProps) => {
|
||||||
const edgeClasses = cx('react-flow__edge', { selected, animated });
|
const edgeClasses = cx('react-flow__edge', `react-flow__edge-${type}`, className, { selected, animated });
|
||||||
const edgeGroupStyle: CSSProperties = {
|
const edgeGroupStyle: CSSProperties = {
|
||||||
pointerEvents: isInteractive ? 'all' : 'none',
|
pointerEvents: isInteractive ? 'all' : 'none',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ const Handle = memo(
|
|||||||
position = Position.Top,
|
position = Position.Top,
|
||||||
onConnect = () => {},
|
onConnect = () => {},
|
||||||
isValidConnection = () => true,
|
isValidConnection = () => true,
|
||||||
...rest
|
style,
|
||||||
|
className,
|
||||||
|
id,
|
||||||
}: HandleProps) => {
|
}: HandleProps) => {
|
||||||
const nodeId = useContext(NodeIdContext) as ElementId;
|
const nodeId = useContext(NodeIdContext) as ElementId;
|
||||||
const setPosition = useStoreActions((a) => a.setConnectionPosition);
|
const setPosition = useStoreActions((a) => a.setConnectionPosition);
|
||||||
@@ -32,7 +34,9 @@ const Handle = memo(
|
|||||||
type={type}
|
type={type}
|
||||||
position={position}
|
position={position}
|
||||||
isValidConnection={isValidConnection}
|
isValidConnection={isValidConnection}
|
||||||
{...rest}
|
style={style}
|
||||||
|
className={className}
|
||||||
|
id={id}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
import React, { CSSProperties } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Handle from '../../components/Handle';
|
import Handle from '../../components/Handle';
|
||||||
import { NodeProps, Position } from '../../types';
|
import { NodeProps, Position } from '../../types';
|
||||||
|
|
||||||
const nodeStyles: CSSProperties = {
|
const DefaultNode = ({ data, targetPosition = Position.Top, sourcePosition = Position.Bottom }: NodeProps) => (
|
||||||
background: '#ff6060',
|
<>
|
||||||
padding: 10,
|
|
||||||
borderRadius: 5,
|
|
||||||
width: 150,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ({ data, targetPosition = Position.Top, sourcePosition = Position.Bottom, style }: NodeProps) => (
|
|
||||||
<div style={{ ...nodeStyles, ...style }}>
|
|
||||||
<Handle type="target" position={targetPosition} />
|
<Handle type="target" position={targetPosition} />
|
||||||
{data.label}
|
{data.label}
|
||||||
<Handle type="source" position={sourcePosition} />
|
<Handle type="source" position={sourcePosition} />
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DefaultNode.displayName = 'DefaultNode';
|
||||||
|
|
||||||
|
export default DefaultNode;
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import React, { CSSProperties } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Handle from '../../components/Handle';
|
import Handle from '../../components/Handle';
|
||||||
import { NodeProps, Position } from '../../types';
|
import { NodeProps, Position } from '../../types';
|
||||||
|
|
||||||
const nodeStyles: CSSProperties = {
|
const InputNode = ({ data, sourcePosition = Position.Bottom }: NodeProps) => (
|
||||||
background: '#9999ff',
|
<>
|
||||||
padding: 10,
|
|
||||||
borderRadius: 5,
|
|
||||||
width: 150,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ({ data, style, sourcePosition = Position.Bottom }: NodeProps) => (
|
|
||||||
<div style={{ ...nodeStyles, ...style }}>
|
|
||||||
{data.label}
|
{data.label}
|
||||||
<Handle type="source" position={sourcePosition} />
|
<Handle type="source" position={sourcePosition} />
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
InputNode.displayName = 'InputNode';
|
||||||
|
|
||||||
|
export default InputNode;
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import React, { CSSProperties } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Handle from '../../components/Handle';
|
import Handle from '../../components/Handle';
|
||||||
import { NodeProps, Position } from '../../types';
|
import { NodeProps, Position } from '../../types';
|
||||||
|
|
||||||
const nodeStyles: CSSProperties = {
|
const OutputNode = ({ data, targetPosition = Position.Top }: NodeProps) => (
|
||||||
background: '#55dd99',
|
<>
|
||||||
padding: 10,
|
|
||||||
borderRadius: 5,
|
|
||||||
width: 150,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ({ data, style, targetPosition = Position.Top }: NodeProps) => (
|
|
||||||
<div style={{ ...nodeStyles, ...style }}>
|
|
||||||
<Handle type="target" position={targetPosition} />
|
<Handle type="target" position={targetPosition} />
|
||||||
{data.label}
|
{data.label}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
OutputNode.displayName = 'OutputNode';
|
||||||
|
|
||||||
|
export default OutputNode;
|
||||||
|
|||||||
@@ -158,23 +158,16 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
zIndex: selected ? 10 : 3,
|
zIndex: selected ? 10 : 3,
|
||||||
transform: `translate(${xPos}px,${yPos}px)`,
|
transform: `translate(${xPos}px,${yPos}px)`,
|
||||||
pointerEvents: isInteractive ? 'all' : 'none',
|
pointerEvents: isInteractive ? 'all' : 'none',
|
||||||
};
|
...style,
|
||||||
|
|
||||||
const updateNode = (): void => {
|
|
||||||
if (!nodeElement.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
store.dispatch.updateNodeDimensions({ id, nodeElement: nodeElement.current });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (nodeElement.current) {
|
if (nodeElement.current) {
|
||||||
updateNode();
|
store.dispatch.updateNodeDimensions({ id, nodeElement: nodeElement.current });
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver((entries) => {
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
for (let _ of entries) {
|
for (let _ of entries) {
|
||||||
updateNode();
|
store.dispatch.updateNodeDimensions({ id, nodeElement: nodeElement.current! });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -188,7 +181,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}, []);
|
}, [id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DraggableCore
|
<DraggableCore
|
||||||
@@ -219,7 +212,6 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
id={id}
|
id={id}
|
||||||
data={data}
|
data={data}
|
||||||
type={type}
|
type={type}
|
||||||
style={style}
|
|
||||||
selected={selected}
|
selected={selected}
|
||||||
sourcePosition={sourcePosition}
|
sourcePosition={sourcePosition}
|
||||||
targetPosition={targetPosition}
|
targetPosition={targetPosition}
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ import React, { memo, CSSProperties } from 'react';
|
|||||||
import { useStoreState } from '../../store/hooks';
|
import { useStoreState } from '../../store/hooks';
|
||||||
import ConnectionLine from '../../components/ConnectionLine/index';
|
import ConnectionLine from '../../components/ConnectionLine/index';
|
||||||
import { isEdge } from '../../utils/graph';
|
import { isEdge } from '../../utils/graph';
|
||||||
import { XYPosition, Position, Edge, Node, ElementId, HandleElement, Elements } from '../../types';
|
import { XYPosition, Position, Edge, Node, ElementId, HandleElement, Elements, ConnectionLineType } from '../../types';
|
||||||
|
|
||||||
interface EdgeRendererProps {
|
interface EdgeRendererProps {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
edgeTypes: any;
|
edgeTypes: any;
|
||||||
|
connectionLineType: ConnectionLineType;
|
||||||
connectionLineStyle?: CSSProperties;
|
connectionLineStyle?: CSSProperties;
|
||||||
connectionLineType?: string;
|
|
||||||
onElementClick?: (element: Node | Edge) => void;
|
onElementClick?: (element: Node | Edge) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,16 @@ import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
|||||||
import useElementUpdater from '../../hooks/useElementUpdater';
|
import useElementUpdater from '../../hooks/useElementUpdater';
|
||||||
import { getDimensions } from '../../utils';
|
import { getDimensions } from '../../utils';
|
||||||
import { fitView, zoomIn, zoomOut, project } from '../../utils/graph';
|
import { fitView, zoomIn, zoomOut, project } from '../../utils/graph';
|
||||||
import { Elements, NodeTypesType, EdgeTypesType, OnLoadFunc, Node, Edge, Connection } from '../../types';
|
import {
|
||||||
|
Elements,
|
||||||
|
NodeTypesType,
|
||||||
|
EdgeTypesType,
|
||||||
|
OnLoadFunc,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
Connection,
|
||||||
|
ConnectionLineType,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
export interface GraphViewProps {
|
export interface GraphViewProps {
|
||||||
elements: Elements;
|
elements: Elements;
|
||||||
@@ -26,8 +35,8 @@ export interface GraphViewProps {
|
|||||||
selectionKeyCode: number;
|
selectionKeyCode: number;
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
edgeTypes: EdgeTypesType;
|
edgeTypes: EdgeTypesType;
|
||||||
connectionLineType: string;
|
connectionLineType: ConnectionLineType;
|
||||||
connectionLineStyle: CSSProperties;
|
connectionLineStyle?: CSSProperties;
|
||||||
deleteKeyCode: number;
|
deleteKeyCode: number;
|
||||||
snapToGrid: boolean;
|
snapToGrid: boolean;
|
||||||
snapGrid: [number, number];
|
snapGrid: [number, number];
|
||||||
|
|||||||
@@ -20,7 +20,16 @@ import StraightEdge from '../../components/Edges/StraightEdge';
|
|||||||
import StepEdge from '../../components/Edges/StepEdge';
|
import StepEdge from '../../components/Edges/StepEdge';
|
||||||
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import { Elements, NodeTypesType, EdgeTypesType, OnLoadFunc, Node, Edge, Connection } from '../../types';
|
import {
|
||||||
|
Elements,
|
||||||
|
NodeTypesType,
|
||||||
|
EdgeTypesType,
|
||||||
|
OnLoadFunc,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
Connection,
|
||||||
|
ConnectionLineType,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
import '../../style.css';
|
import '../../style.css';
|
||||||
|
|
||||||
@@ -36,8 +45,8 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
|||||||
onSelectionChange?: (elements: Elements | null) => void;
|
onSelectionChange?: (elements: Elements | null) => void;
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
edgeTypes: EdgeTypesType;
|
edgeTypes: EdgeTypesType;
|
||||||
connectionLineType: string;
|
connectionLineType: ConnectionLineType;
|
||||||
connectionLineStyle: CSSProperties;
|
connectionLineStyle?: CSSProperties;
|
||||||
deleteKeyCode: number;
|
deleteKeyCode: number;
|
||||||
selectionKeyCode: number;
|
selectionKeyCode: number;
|
||||||
snapToGrid: boolean;
|
snapToGrid: boolean;
|
||||||
@@ -119,8 +128,7 @@ ReactFlow.defaultProps = {
|
|||||||
straight: StraightEdge,
|
straight: StraightEdge,
|
||||||
step: StepEdge,
|
step: StepEdge,
|
||||||
},
|
},
|
||||||
connectionLineType: 'bezier',
|
connectionLineType: ConnectionLineType.Bezier,
|
||||||
connectionLineStyle: {},
|
|
||||||
deleteKeyCode: 8,
|
deleteKeyCode: 8,
|
||||||
selectionKeyCode: 16,
|
selectionKeyCode: 16,
|
||||||
snapToGrid: false,
|
snapToGrid: false,
|
||||||
|
|||||||
+25
-34
@@ -60,6 +60,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes dashdraw {
|
||||||
|
from {
|
||||||
|
stroke-dashoffset: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.react-flow__connection {
|
.react-flow__connection {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -85,12 +91,6 @@
|
|||||||
fill: white;
|
fill: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes dashdraw {
|
|
||||||
from {
|
|
||||||
stroke-dashoffset: 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__nodes {
|
.react-flow__nodes {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -110,13 +110,17 @@
|
|||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 150px;
|
||||||
|
background: #eee;
|
||||||
|
|
||||||
&.selected > *,
|
&.selected,
|
||||||
&.selected:hover > * {
|
&.selected:hover {
|
||||||
box-shadow: 0 0 0 2px #555;
|
box-shadow: 0 0 0 2px #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover > * {
|
&:hover {
|
||||||
box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +129,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-flow__node-default {
|
||||||
|
background: #ff6060;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-flow__node-input {
|
||||||
|
background: #9999ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-flow__node-output {
|
||||||
|
background: #55dd99;
|
||||||
|
}
|
||||||
|
|
||||||
.react-flow__handle {
|
.react-flow__handle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
@@ -174,28 +190,3 @@
|
|||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__controls {
|
|
||||||
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
|
||||||
|
|
||||||
&-button {
|
|
||||||
background: #fefefe;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
padding: 5px;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: #f4f4f4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+6
-1
@@ -96,7 +96,6 @@ export interface NodeProps {
|
|||||||
selected: boolean;
|
selected: boolean;
|
||||||
targetPosition?: Position;
|
targetPosition?: Position;
|
||||||
sourcePosition?: Position;
|
sourcePosition?: Position;
|
||||||
style?: CSSProperties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeComponentProps {
|
export interface NodeComponentProps {
|
||||||
@@ -154,6 +153,11 @@ export interface Connection {
|
|||||||
target: ElementId | null;
|
target: ElementId | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ConnectionLineType {
|
||||||
|
Bezier = 'bezier',
|
||||||
|
Straight = 'straight',
|
||||||
|
}
|
||||||
|
|
||||||
export type OnConnectFunc = (connection: Connection) => void;
|
export type OnConnectFunc = (connection: Connection) => void;
|
||||||
|
|
||||||
export interface HandleElement extends XYPosition, Dimensions {
|
export interface HandleElement extends XYPosition, Dimensions {
|
||||||
@@ -168,6 +172,7 @@ export interface HandleProps {
|
|||||||
isValidConnection?: (connection: Connection) => boolean;
|
isValidConnection?: (connection: Connection) => boolean;
|
||||||
id?: string;
|
id?: string;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EdgeCompProps {
|
export interface EdgeCompProps {
|
||||||
|
|||||||
Reference in New Issue
Block a user