diff --git a/src/NodeAnimator.js b/src/NodeAnimator.tsx similarity index 63% rename from src/NodeAnimator.js rename to src/NodeAnimator.tsx index 8456e6e9fd..b0d74ec00e 100644 --- a/src/NodeAnimator.js +++ b/src/NodeAnimator.tsx @@ -1,6 +1,21 @@ import React from "react"; import ReactDom from "react-dom"; -import PropTypes from 'prop-types'; + +interface IChildProps { + style: React.CSSProperties; + ref: (node: React.ReactInstance) => void; +} + +interface IProps { + // either a list of child nodes, or a single child. + children: React.ReactNode; + + // optional transition information for changing existing children + transition?: object; + + // a list of state objects to apply to each child node in turn + startStyles: React.CSSProperties[]; +} /** * The NodeAnimator contains components and animates transitions. @@ -9,55 +24,45 @@ import PropTypes from 'prop-types'; * from DOM order. This makes it a lot simpler and lighter: if you need fully * automatic positional animation, look at react-shuffle or similar libraries. */ -export default class NodeAnimator extends React.Component { - static propTypes = { - // either a list of child nodes, or a single child. - children: PropTypes.any, - - // optional transition information for changing existing children - transition: PropTypes.object, - - // a list of state objects to apply to each child node in turn - startStyles: PropTypes.array, - }; - - static defaultProps = { +export default class NodeAnimator extends React.Component { + private nodes = {}; + private children: { [key: string]: React.DetailedReactHTMLElement }; + static defaultProps: Partial = { startStyles: [], }; - constructor(props) { + constructor(props: IProps) { super(props); - this.nodes = {}; - this._updateChildren(this.props.children); + this.updateChildren(this.props.children); } - componentDidUpdate() { - this._updateChildren(this.props.children); + public componentDidUpdate(): void { + this.updateChildren(this.props.children); } /** * * @param {HTMLElement} node element to apply styles to - * @param {object} styles a key/value pair of CSS properties + * @param {React.CSSProperties} styles a key/value pair of CSS properties * @returns {void} */ - _applyStyles(node, styles) { + private applyStyles(node: HTMLElement, styles: React.CSSProperties): void { Object.entries(styles).forEach(([property, value]) => { node.style[property] = value; }); } - _updateChildren(newChildren) { + private updateChildren(newChildren: React.ReactNode): void { const oldChildren = this.children || {}; this.children = {}; - React.Children.toArray(newChildren).forEach((c) => { + React.Children.toArray(newChildren).forEach((c: any) => { if (oldChildren[c.key]) { const old = oldChildren[c.key]; const oldNode = ReactDom.findDOMNode(this.nodes[old.key]); - if (oldNode && oldNode.style.left !== c.props.style.left) { - this._applyStyles(oldNode, { left: c.props.style.left }); + if (oldNode && (oldNode as HTMLElement).style.left !== c.props.style.left) { + this.applyStyles(oldNode as HTMLElement, { left: c.props.style.left }); // console.log("translation: "+oldNode.style.left+" -> "+c.props.style.left); } // clone the old element with the props (and children) of the new element @@ -66,7 +71,7 @@ export default class NodeAnimator extends React.Component { } else { // new element. If we have a startStyle, use that as the style and go through // the enter animations - const newProps = {}; + const newProps: Partial = {}; const restingStyle = c.props.style; const startStyles = this.props.startStyles; @@ -76,7 +81,7 @@ export default class NodeAnimator extends React.Component { // console.log("mounted@startstyle0: "+JSON.stringify(startStyle)); } - newProps.ref = ((n) => this._collectNode( + newProps.ref = ((n) => this.collectNode( c.key, n, restingStyle, )); @@ -85,7 +90,7 @@ export default class NodeAnimator extends React.Component { }); } - _collectNode(k, node, restingStyle) { + private collectNode(k: string, node: React.ReactInstance, restingStyle: React.CSSProperties): void { if ( node && this.nodes[k] === undefined && @@ -96,7 +101,7 @@ export default class NodeAnimator extends React.Component { // start from startStyle 1: 0 is the one we gave it // to start with, so now we animate 1 etc. for (let i = 1; i < startStyles.length; ++i) { - this._applyStyles(domNode, startStyles[i]); + this.applyStyles(domNode as HTMLElement, startStyles[i]); // console.log("start:" // JSON.stringify(startStyles[i]), // ); @@ -104,7 +109,7 @@ export default class NodeAnimator extends React.Component { // and then we animate to the resting state setTimeout(() => { - this._applyStyles(domNode, restingStyle); + this.applyStyles(domNode as HTMLElement, restingStyle); }, 0); // console.log("enter:", @@ -113,7 +118,7 @@ export default class NodeAnimator extends React.Component { this.nodes[k] = node; } - render() { + public render(): JSX.Element { return ( <>{ Object.values(this.children) } );