UNPKG

rmwc

Version:

A thin React wrapper for Material Design (Web) Components

195 lines (174 loc) 5.01 kB
/** * Shows in browser notifications */ // @flow import type { SimpleTagPropsT } from '../Base'; import * as React from 'react'; import { MDCSnackbar } from '@material/snackbar/dist/mdc.snackbar'; import { getCorrectEventName } from '@material/animation/dist/mdc.animation'; import Button from '../Button'; import { simpleTag, syncFoundationProp, withFoundation, noop } from '../Base'; export type SnackbarPropsT = { /** Show the Snackbar. */ show?: boolean, /** A callback thats fired when the Snackbar shows. */ onShow?: () => mixed, /** A callback thats fired when the Snackbar hides. */ onHide?: () => mixed, /** A string or other renderable JSX to be used as the message body. */ message?: React.Node, /** Milliseconds to show the Snackbar for. */ timeout?: number, /** Callback that fires when action is pressed. The actionText property must be set to use this. */ actionHandler?: () => mixed, /** Label for the action button. */ actionText?: React.Node, /** Lets the Snackbar text overflow onto multiple lines. */ multiline?: boolean, /** Places the action underneath the message text. */ actionOnBottom?: boolean, /** Whether or not the Snackbar dismisses on the action press. */ dismissesOnAction?: boolean, /* Aligns the Snackbar to the start of the screen. */ alignStart?: boolean } & SimpleTagPropsT; export const SnackbarRoot = simpleTag({ displayName: 'SnackbarRoot', classNames: (props: SnackbarPropsT) => [ 'mdc-snackbar', { 'mdc-snackbar--align-start': props.alignStart } ], defaultProps: { alignStart: false, 'aria-live': 'assertive', 'aria-atomic': true, 'aria-hidden': true }, consumeProps: ['alignStart'] }); export const SnackbarText = simpleTag({ displayName: 'SnackbarText', classNames: 'mdc-snackbar__text' }); export const SnackbarActionWrapper = simpleTag({ displayName: 'SnackbarActionWrapper', classNames: 'mdc-snackbar__action-wrapper' }); export const SnackbarActionButton = simpleTag({ displayName: 'SnackbarActionButton', tag: Button, classNames: 'mdc-snackbar__action-button' }); /** * A Snackbar component for notifications. */ export class Snackbar extends withFoundation({ constructor: MDCSnackbar, adapter: { removeClass: function(className) { // only remove if we still have a reference to our root. this.root_ && this.root_.classList.remove(className); }, registerTransitionEndHandler: function(handler) { // only add if we still have a reference to our root. this.root_ && this.root_.addEventListener( getCorrectEventName(window, 'transitionend'), handler ); } } })<SnackbarPropsT> { static displayName = 'Snackbar'; static defaultProps = { show: false, onHide: noop, onShow: noop, message: undefined, timeout: undefined, actionHandler: undefined, actionText: undefined, multiline: false, actionOnBottom: false, dismissesOnAction: true }; isShowing_ = false; dismissesOnAction: boolean; show: Function; get isShowing() { return this.isShowing_; } set isShowing(isShowing: boolean) { this.isShowing_ = isShowing; } syncWithProps(nextProps: MDCSnackbar) { syncFoundationProp( nextProps.dismissesOnAction, this.dismissesOnAction, () => (this.dismissesOnAction = nextProps.dismissesOnAction) ); syncFoundationProp(nextProps.show, this.isShowing, () => { const { message, timeout, actionHandler, actionText, multiline, actionOnBottom } = nextProps; this.show({ message, timeout, actionHandler, actionText: actionText || ' ', multiline, actionOnBottom }); }); } render() { const { show, message, timeout, actionHandler, actionText, multiline, actionOnBottom, dismissesOnAction, onHide, onShow, children, ...rest } = this.props; const { root_ } = this.foundationRefs; const isJSX = typeof message === 'object'; const snackbarTextStyle: { display?: string } = {}; if (isJSX) { snackbarTextStyle.display = 'none'; } const snackbarActionWrapperStyle = !actionText ? { display: 'none' } : {}; /** * The double SnackbarText below is a hack to allow for rendering JSX * The real message gets rendered in the hidden container, and the second one is * ignored and shows th rendered content :) */ return ( <SnackbarRoot {...rest} elementRef={root_}> <SnackbarText style={snackbarTextStyle} /> {isJSX && <SnackbarText>{message}</SnackbarText>} <SnackbarActionWrapper style={snackbarActionWrapperStyle}> <SnackbarActionButton /> </SnackbarActionWrapper> {children} </SnackbarRoot> ); } } export default Snackbar;