mdc-react
Version:
Material Components for the web implemented in React
133 lines (117 loc) • 3.95 kB
JSX
import { forwardRef, useRef, useCallback, useImperativeHandle } from 'react';
import { CSSTransition } from 'react-transition-group';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Clone } from '../component';
import Icon from '../icon';
import { numbers, cssClasses } from './constants';
const Banner = forwardRef(({
text,
icon,
graphic = icon,
action,
primaryAction = action,
secondaryAction,
open = false,
centered = false,
fixed = false,
mobileStacked = false,
element = 'div',
component: Element = element,
className,
children = text,
...props
}, ref) => {
const rootRef = useRef();
const contentRef = useRef();
useImperativeHandle(ref, () => rootRef.current);
const handleEntering = useCallback((node, isAppearing) => {
if (!isAppearing) {
node.style.height = `${contentRef.current.offsetHeight}px`;
}
}, []);
const handleExiting = useCallback(node => {
node.style.height = '0px';
}, []);
const classNames = classnames(cssClasses.ROOT, {
[cssClasses.FIXED]: fixed,
[cssClasses.CENTERED]: centered,
[cssClasses.MOBILE_STACKED]: mobileStacked
}, className);
const content = (
<div ref={contentRef} className={cssClasses.CONTENT} role="status">
<div className={cssClasses.GRAPHIC_TEXT_WRAPPER}>
{graphic &&
<div className={cssClasses.GRAPHIC}>
<Clone
component={graphic}
fallback={Icon}
className={cssClasses.ICON}
/>
</div>
}
<Clone
component={children}
fallback="div"
className={cssClasses.TEXT}
/>
</div>
{primaryAction &&
<div className={cssClasses.ACTIONS}>
{secondaryAction &&
<Clone
component={secondaryAction}
className={cssClasses.SECONDARY_ACTION}
/>
}
<Clone
component={primaryAction}
className={cssClasses.PRIMARY_ACTION}
/>
</div>
}
</div>
);
return (
<CSSTransition
in={open}
appear={open}
timeout={{
appear: 0,
enter: numbers.BANNER_ANIMATION_OPEN_TIME_MS,
exit: numbers.BANNER_ANIMATION_CLOSE_TIME_MS
}}
classNames={{
appear: cssClasses.APPEARING,
appearDone: cssClasses.APPEARED,
enter: cssClasses.OPENING,
enterActive: cssClasses.OPEN,
enterDone: cssClasses.OPEN,
exit: cssClasses.CLOSING
}}
mountOnEnter
unmountOnExit
onEntering={handleEntering}
onExiting={handleExiting}
>
<Element ref={rootRef} className={classNames} role="banner" {...props}>
{content}
</Element>
</CSSTransition>
);
});
Banner.displayName = 'MDCBanner';
Banner.propTypes = {
text: PropTypes.node.isRequired,
icon: PropTypes.node,
graphic: PropTypes.element,
action: PropTypes.element,
primaryAction: PropTypes.element,
secondaryAction: PropTypes.element,
open: PropTypes.bool,
appear: PropTypes.bool,
fixed: PropTypes.bool,
centered: PropTypes.bool,
mobileStacked: PropTypes.bool
};
export default Banner;