diff --git a/README.md b/README.md index bbb4e74f..3e39618e 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ Node example: `{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { - `data`: {} *(required if you are using a standard type, otherwise depends on your implementation)* - `type`: 'input' | 'output' | 'default' or a custom one you implemented - `style`: css properties +- `className`: additional class name - `targetPosition`: 'left' | 'right' | 'top' | 'bottom' handle position - default: 'top' - `sourcePosition`: 'left' | 'right' | 'top' | 'bottom' handle position - default: 'bottom' diff --git a/example/src/Horizontal/index.js b/example/src/Horizontal/index.js index 87cbf227..47684f5d 100644 --- a/example/src/Horizontal/index.js +++ b/example/src/Horizontal/index.js @@ -7,7 +7,7 @@ const onLoad = (graph) => { }; const initialElements = [ - { id: '1', sourcePosition: 'right', type: 'input', 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: '3', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Another node' }, position: { x: 250, y: 160 } }, { id: '4', sourcePosition: 'right', targetPosition: 'left', data: { label: 'Node 4' }, position: { x: 500, y: 80 } }, @@ -21,6 +21,15 @@ const HorizontalFlow = () => { const onElementsRemove = (elementsToRemove) => setElements(els => removeElements(elementsToRemove, els)); const onConnect = (params) => setElements(els => addEdge(params, els)); + const changeClassName = () => { + setElements(elms => elms.map(el => { + if (el.type === 'input') { + el.className = el.className ? '' : 'dark-node'; + } + + return {...el}; + })) + } return ( { onConnect={onConnect} onLoad={onLoad} selectNodesOnDrag={false} - /> + > + + ); } diff --git a/example/src/index.css b/example/src/index.css index 87da1ef6..cf5db29f 100644 --- a/example/src/index.css +++ b/example/src/index.css @@ -136,6 +136,11 @@ nav a.active:before { color: #111; } +.dark-node>div { + background: #333 !important; + color: #f8f8f8 !important; +} + @media screen and (min-width: 768px) { nav { position: relative; diff --git a/src/components/Nodes/wrapNode.tsx b/src/components/Nodes/wrapNode.tsx index bf938cf1..a1fb111a 100644 --- a/src/components/Nodes/wrapNode.tsx +++ b/src/components/Nodes/wrapNode.tsx @@ -142,6 +142,7 @@ export default (NodeComponent: ComponentType) => { onNodeDragStart, onNodeDragStop, style, + className, isInteractive, selectNodesOnDrag, sourcePosition, @@ -151,7 +152,8 @@ export default (NodeComponent: ComponentType) => { const [offset, setOffset] = useState({ x: 0, y: 0 }); const [isDragging, setDragging] = useState(false); const position = { x: xPos, y: yPos }; - const nodeClasses = cx('react-flow__node', { selected }); + const nodeClasses = cx('react-flow__node', `react-flow__node-${type}`, className, { selected }); + const nodeStyle: CSSProperties = { zIndex: selected ? 10 : 3, transform: `translate(${xPos}px,${yPos}px)`, diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx index e28c13ed..6c9d684b 100644 --- a/src/container/NodeRenderer/index.tsx +++ b/src/container/NodeRenderer/index.tsx @@ -42,6 +42,7 @@ function renderNode( transform={transform} selected={isSelected} style={node.style} + className={node.className} isInteractive={isInteractive} sourcePosition={node.sourcePosition} targetPosition={node.targetPosition} diff --git a/src/hooks/useElementUpdater.ts b/src/hooks/useElementUpdater.ts index 7eda42d4..c8c6936d 100644 --- a/src/hooks/useElementUpdater.ts +++ b/src/hooks/useElementUpdater.ts @@ -28,34 +28,33 @@ const useElementUpdater = (elements: Elements): void => { ? { ...existingNode.style, ...propNode.style } : existingNode.style; + const className = existingNode.className === propNode.className ? existingNode.className : propNode.className; + const positionChanged = existingNode.position.x !== propNode.position.x || existingNode.position.y !== propNode.position.y; - if (positionChanged) { - return { - ...existingNode, - __rg: { - ...existingNode.__rg, - position: propNode.position, - }, - position: propNode.position, - data, - style, - }; - } - - if (style) { - return { - ...existingNode, - data, - style, - }; - } - - return { + const nodeProps = { ...existingNode, data, }; + + if (positionChanged) { + nodeProps.__rg = { + ...existingNode.__rg, + position: propNode.position, + }; + nodeProps.position = propNode.position; + } + + if (typeof style !== 'undefined') { + nodeProps.style = style; + } + + if (typeof className !== 'undefined') { + nodeProps.className = className; + } + + return nodeProps; } return parseElement(propNode) as Node; diff --git a/src/types/index.ts b/src/types/index.ts index b3cb1584..34b84d42 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -37,6 +37,7 @@ export interface Node { __rg?: any; data?: any; style?: CSSProperties; + className?: string; targetPosition?: Position; sourcePosition?: Position; } @@ -128,6 +129,7 @@ export interface WrapNodeProps { onNodeDragStart?: (node: Node) => void; onNodeDragStop?: (node: Node) => void; style?: CSSProperties; + className?: string; sourcePosition?: Position; targetPosition?: Position; }