diff --git a/CHANGELOG.md b/CHANGELOG.md index d8cab64..020301f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ - [View releases on NPM](https://www.npmjs.com/package/@hms-dbmi-bgm/react-workflow-viz?activeTab=versions) - [View releases on Unpkg](https://unpkg.com/browse/@hms-dbmi-bgm/react-workflow-viz/) +#### 2024-08-27 (v0.1.11) +- CSSTransition in Nodes and Edges was throwing the `findDOMNode is deprecated and will be removed in the next major release. Instead, add a ref directly to the element you want to reference.` during animations and transitions. Forwarding the referenced DOM element by nodeRef and ref props solved the issue. + #### 2023-05-17 (v0.1.9) - No changes except `package-lock.json` + `package.json` version (new NPM release) diff --git a/package-lock.json b/package-lock.json index 87eff8a..bd4c65f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hms-dbmi-bgm/react-workflow-viz", - "version": "0.1.10", + "version": "0.1.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@hms-dbmi-bgm/react-workflow-viz", - "version": "0.1.10", + "version": "0.1.11", "license": "MIT", "dependencies": { "memoize-one": "^5.1.1", @@ -21137,7 +21137,7 @@ "dev": true, "requires": { "atob": "^2.1.2", - "decode-uri-component": "^0.2.2", + "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", "urix": "^0.1.0" diff --git a/package.json b/package.json index a6f2e8b..fa6bb62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hms-dbmi-bgm/react-workflow-viz", - "version": "0.1.10", + "version": "0.1.11", "description": "React component for visualizing CWL-like workflows and provenance graphs.", "main": "./dist/react-workflow-viz.min.js", "unpkg": "./dist/react-workflow-viz.min.js", diff --git a/src/components/Edge.js b/src/components/Edge.js index e7e68b3..5639cd8 100644 --- a/src/components/Edge.js +++ b/src/components/Edge.js @@ -271,10 +271,6 @@ export default class Edge extends React.Component { this.state = { 'pathDimension' : this.generatePathDimension() }; - - // Alternative implementation of transition - - // adjust pathRef.current `d` attribute manually - this.pathRef = React.createRef(); } getComputedProperties(props = this.props){ @@ -390,7 +386,7 @@ export default class Edge extends React.Component { }); } - const pathElem = this.pathRef.current; // Necessary if using alternate transition approach(es). + const pathElem = this.props.forwardedRef.current; // Necessary if using alternate transition approach(es). const changeTween = () => (t) => { const nextCoords = [ @@ -463,7 +459,7 @@ export default class Edge extends React.Component { } render(){ - const { edge, pathArrows, style } = this.props; + const { edge, pathArrows, style, forwardedRef } = this.props; const { pathDimension } = this.state; const { disabled, selected, related, distantlySelected } = this.getComputedProperties(); let markerEnd; @@ -479,7 +475,7 @@ export default class Edge extends React.Component { } return ( - diff --git a/src/components/EdgesLayer.js b/src/components/EdgesLayer.js index b5b931f..8de8462 100644 --- a/src/components/EdgesLayer.js +++ b/src/components/EdgesLayer.js @@ -327,7 +327,9 @@ export function traceEdges( }; } - +const ForwardedEdge = React.forwardRef((props, ref) => { + return ; +}); export default class EdgesLayer extends React.PureComponent { @@ -363,37 +365,39 @@ export default class EdgesLayer extends React.PureComponent { constructor(props){ super(props); this.sortedEdges = this.sortedEdges.bind(this); - //this.getAllPathElements = this.getAllPathElements.bind(this); - //this.edgeRefs = []; + // Create refs for each node + this.nodeRefs = {}; + } + + static edgeOnEnter(nodeRef) { + if (nodeRef.current && nodeRef.current.style) { + nodeRef.current.style.opacity = 0; + } + } + + static edgeOnEntering(nodeRef) { + if (nodeRef.current && nodeRef.current.style) { + nodeRef.current.style.opacity = 0; + } } - static edgeOnEnter(elem) { elem.style.opacity = 0; } - static edgeOnEntering(elem) { elem.style.opacity = 0; } - static edgeOnEntered(elem) { elem.style.opacity = null; /** Allows CSS to override, e.g. .15 opacity for disabled edges */ } - static edgeOnExit(elem) { elem.style.opacity = 0; } + static edgeOnEntered(nodeRef) { + if (nodeRef.current && nodeRef.current.style) { + nodeRef.current.style.opacity = null; + } + } + + static edgeOnExit(nodeRef) { + if (nodeRef.current && nodeRef.current.style) { + nodeRef.current.style.opacity = 0; + } + } sortedEdges = memoize(function(edges, selectedNodes, isNodeDisabled){ - const nextEdges = EdgesLayer.sortedEdges(edges, selectedNodes, isNodeDisabled); - // Create new list of refs each time we're updated. - //this.edgeRefs = []; - //_.forEach(nextEdges, ()=>{ - // this.edgeRefs.push(React.createRef()); - //}); + const nextEdges = EdgesLayer.sortedEdges(edges, selectedNodes, isNodeDisabled);; return nextEdges; }); - // Experimentation with transitioning multiple edges at once within requestAnimationFrame. - // Need to rethink design of this, an array for this.edgeRefs won't work as we need to keep - // state.source.x, state.source.y cached in state and associated w/ each edge. - // Possibly can use object keyed by 'key' string (as determined in render method). - // Keeping for reference. - // - //getAllPathElements(){ - // return _.map(this.edgeRefs, function(ref){ - // return ref && ref.current && ref.current.pathRef && ref.current.pathRef.current; - // }); - //} - pathArrows(){ if (!this.props.pathArrows) return null; return Edge.pathArrowsMarkers(); @@ -425,13 +429,28 @@ export default class EdgesLayer extends React.PureComponent { { _.map(this.sortedEdges(edges, selectedNode, isNodeDisabled), (edge, index) => { const key = (edge.source.id || edge.source.name) + "----" + (edge.target.id || edge.target.name); + if (!this.nodeRefs[key]) { + this.nodeRefs[key] = React.createRef(); + } return ( - - + EdgesLayer.edgeOnEnter(this.nodeRefs[key])} + onEntering={() => EdgesLayer.edgeOnEntering(this.nodeRefs[key])} + onEntered={() => EdgesLayer.edgeOnEntered(this.nodeRefs[key])} + onExit={() => EdgesLayer.edgeOnExit(this.nodeRefs[key])} + nodeRef={this.nodeRefs[key]}> + ); }) diff --git a/src/components/Node.js b/src/components/Node.js index c1956bc..61ca5eb 100644 --- a/src/components/Node.js +++ b/src/components/Node.js @@ -96,21 +96,7 @@ export default class Node extends React.Component { static isSelected(currentNode, selectedNode){ if (!selectedNode) return false; if (selectedNode === currentNode) return true; - /* - // We shouldn't need the below and can just rely on a simple reference comparison - // Keeping around for now/reference. - if (typeof selectedNode.name === 'string' && typeof currentNode.name === 'string') { - if (selectedNode.name === currentNode.name){ - // Case: IO node (which would have add'l self-generated ID to ensure uniqueness) - if (typeof selectedNode.id === 'string'){ - if (selectedNode.id === currentNode.id) return true; - return false; - } - return true; - } - return false; - } - */ + return false; } @@ -230,7 +216,7 @@ export default class Node extends React.Component { } render(){ - var { node, isNodeDisabled, className, columnWidth, renderNodeElement, selectedNode } = this.props, + var { node, isNodeDisabled, className, columnWidth, renderNodeElement, selectedNode, forwardedRef } = this.props, disabled = typeof node.disabled !== 'undefined' ? node.disabled : this.isDisabled(node, isNodeDisabled), isCurrentContext = typeof node.isCurrentContext !== 'undefined' ? node.isCurrentContext : null, classNameList = ["node", "node-type-" + node.nodeType], @@ -258,7 +244,7 @@ export default class Node extends React.Component { 'left' : node.x, 'width' : columnWidth || 100, 'zIndex' : 2 + (node.indexInColumn || 0) - }}> + }} ref={forwardedRef}>
diff --git a/src/components/NodesLayer.js b/src/components/NodesLayer.js index 9909557..e8cae9d 100644 --- a/src/components/NodesLayer.js +++ b/src/components/NodesLayer.js @@ -36,6 +36,7 @@ export default class NodesLayer extends React.PureComponent { countInActiveContext: memoize(NodesLayer.countInActiveContext), lastActiveContextNode: memoize(NodesLayer.lastActiveContextNode) }; + this.nodeRefs = {}; } renderNodeElements(){ @@ -59,9 +60,12 @@ export default class NodesLayer extends React.PureComponent { 'className' : nodeClassName } ); + if (!this.nodeRefs[nodeProps.key]) { + this.nodeRefs[nodeProps.key] = React.createRef(); + } return ( - - + + ); }); @@ -83,3 +87,7 @@ export default class NodesLayer extends React.PureComponent { } } + +const ForwardedNode = React.forwardRef((props, ref) => { + return ; +});