diff --git a/src/ExitSensor/__story__/StoryExitSensorExample.tsx b/src/ExitSensor/__story__/StoryExitSensorExample.tsx new file mode 100644 index 00000000..be767ec2 --- /dev/null +++ b/src/ExitSensor/__story__/StoryExitSensorExample.tsx @@ -0,0 +1,49 @@ +import {Component} from 'react'; +import {h} from '../../util'; +import {ExitSensor} from '..'; + +const Rectangle = ({exiting}: any) => { + return ( +
+ ); +}; + +const Circle = ({exiting}: any) => { + return ( +
+ ); +}; + +export class StoryExitSensorExample extends Component { + state = { + shape: 'rectangle' + }; + + render () { + const shape = this.state.shape === 'rectangle' ? + : ; + + return ( +
+ + {shape} + + + +
+ ); + } +} diff --git a/src/ExitSensor/__story__/story.tsx b/src/ExitSensor/__story__/story.tsx new file mode 100644 index 00000000..223a6f2e --- /dev/null +++ b/src/ExitSensor/__story__/story.tsx @@ -0,0 +1,10 @@ +import {Component, createElement as h} from 'react'; +import {storiesOf} from '@storybook/react'; +import {action} from '@storybook/addon-actions'; +import {linkTo} from '@storybook/addon-links'; +import {ExitSensor} from '..'; +import ShowDocs from '../../../.storybook/ShowDocs' +import {StoryExitSensorExample} from './StoryExitSensorExample'; + +storiesOf('Sensors/ExitSensor', module) + .add('Example', () => ); diff --git a/src/ExitSensor/index.ts b/src/ExitSensor/index.ts new file mode 100644 index 00000000..6d424545 --- /dev/null +++ b/src/ExitSensor/index.ts @@ -0,0 +1,78 @@ +import {Component, cloneElement} from 'react'; +import {h} from '../util'; +import renderProp from '../util/renderProp'; + +export interface IExitSensorProps { + children?: React.ReactElement; + time?: number; +} + +export interface IExitSensorState { + +} + +export class ExitSensor extends Component { + static defaultProps = { + time: 200 + }; + + element: React.ReactElement; + nextElement: React.ReactElement; + exitInFlight: boolean = false; + exitFinish: boolean = false; + timeout; + + state: IExitSensorState = { + + }; + + componentWillUnmount () { + clearTimeout(this.timeout); + } + + transition = () => { + this.exitFinish = true; + this.forceUpdate(); + }; + + render () { + if (this.exitFinish) { + this.exitFinish = false; + this.exitInFlight = false; + this.element = this.nextElement; + + return this.element; + } + + const element = this.props.children; + + if (this.exitInFlight) { + this.nextElement = element; + + return this.element; + } + + if (!this.element) { + this.element = element; + + return element; + } + + if (!element || (this.element.key !== element.key)) { + this.exitInFlight = true; + this.nextElement = element; + + this.timeout = setTimeout(this.transition, this.props.time); + + return cloneElement(this.element, { + exiting: true + }); + } + + if (this.exitInFlight) { + return this.element; + } + + return element; + } +}