react-select
Version:
A Select control built with and for ReactJS
117 lines (102 loc) • 2.91 kB
JavaScript
// @flow
import React, { Component, type ComponentType, type ElementRef } from 'react';
import { Transition } from 'react-transition-group';
export type fn = () => void;
export type BaseTransition = {
/** Whether we are in a transition. */
in: boolean,
/** Function to be called once transition finishes. */
onExited: fn
};
// ==============================
// Fade Transition
// ==============================
type FadeProps = BaseTransition & {
component: ComponentType<any>,
duration: number,
};
export const Fade = ({
component: Tag,
duration = 1,
in: inProp,
onExited, // eslint-disable-line no-unused-vars
...props
}: FadeProps) => {
const transition = {
entering: { opacity: 0 },
entered: { opacity: 1, transition: `opacity ${duration}ms` },
exiting: { opacity: 0 },
exited: { opacity: 0 },
};
return (
<Transition mountOnEnter unmountOnExit in={inProp} timeout={duration}>
{state => {
const innerProps = {
style: {
...transition[state],
}
};
return <Tag innerProps={innerProps} {...props} />;
}}
</Transition>
);
};
// ==============================
// Collapse Transition
// ==============================
export const collapseDuration = 260;
type TransitionState = 'exiting' | 'exited';
type Width = number | 'auto';
type CollapseProps = { children: any, in: boolean };
type CollapseState = { width: Width };
// wrap each MultiValue with a collapse transition; decreases width until
// finally removing from DOM
export class Collapse extends Component<CollapseProps, CollapseState> {
duration = collapseDuration;
state = { width: 'auto' };
transition = {
exiting: { width: 0, transition: `width ${this.duration}ms ease-out` },
exited: { width: 0 },
};
// width must be calculated; cannot transition from `undefined` to `number`
getWidth = (ref: ElementRef<*>) => {
if (ref && isNaN(this.state.width)) {
// cannot use `offsetWidth` because it is rounded
const { width } = ref.getBoundingClientRect();
this.setState({ width });
}
};
// get base styles
getStyle = (width: Width) => ({
overflow: 'hidden',
whiteSpace: 'nowrap',
width,
});
// get transition styles
getTransition = (state: TransitionState) => this.transition[state];
render() {
const { children, in: inProp } = this.props;
const { width } = this.state;
return (
<Transition
enter={false}
mountOnEnter
unmountOnExit
in={inProp}
timeout={this.duration}
>
{state => {
const style = {
...this.getStyle(width),
...this.getTransition(state),
};
return (
<div ref={this.getWidth} style={style}>
{children}
</div>
);
}}
</Transition>
);
}
}