import React from 'react' ; import classnames from 'classnames' ; import { MDCSnackbarFoundation } from '@material/snackbar/foundation' ; import { MDCSnackbarAdapter } from '@material/snackbar/adapter' ; export interface Props { message : string ; className ? : string ; timeoutMs ? : number ; closeOnEscape ? : boolean ; actionText ? : string ; leading ? : boolean ; stacked ? : boolean ; open ? : boolean ; reason ? : string ; onOpening ? : ( ) => void ; onOpen ? : ( ) => void ; onClosing ? : ( reason : string ) => void ; onClose ? : ( reason : string ) => void ; onAnnounce ? : ( ) => void ; } type State = { classes : Set < string > ; } ; export class Snackbar extends React . Component < Props , State > { foundation : MDCSnackbarFoundation ; static defaultProps : Partial < Props > = { open : true , stacked : false , leading : false , } ; constructor ( props ) { super ( props ) ; const { timeoutMs , closeOnEscape , leading , stacked } = this . props ; const classes = new Set < string > ( ) ; if ( leading ) { classes . add ( 'mdc-snackbar--leading' ) ; } if ( stacked ) { classes . add ( 'mdc-snackbar--stacked' ) ; } this . state = { classes , } ; this . foundation = new MDCSnackbarFoundation ( this . adapter ) ; if ( timeoutMs ) { this . foundation . setTimeoutMs ( timeoutMs ) ; } if ( closeOnEscape ) { this . foundation . setCloseOnEscape ( closeOnEscape ) ; } } get adapter ( ) : MDCSnackbarAdapter { return { addClass : ( className ) => { const { classes } = this . state ; classes . add ( className ) ; this . setState ( { classes , } ) ; } , removeClass : ( className ) => { const { classes } = this . state ; classes . delete ( className ) ; this . setState ( { classes , } ) ; } , announce : ( ) => { this . props . onAnnounce && this . props . onAnnounce ( ) ; } , notifyOpening : ( ) => { const { onOpening } = this . props ; if ( onOpening ) { onOpening ( ) ; } } , notifyOpened : ( ) => { const { onOpen } = this . props ; if ( onOpen ) { onOpen ( ) ; } } , notifyClosing : ( reason ) => { const { onClosing } = this . props ; if ( onClosing ) { onClosing ( reason ) ; } } , notifyClosed : ( reason ) => { const { onClose } = this . props ; if ( onClose ) { onClose ( reason ) ; } } , } ; } close ( action ) { this . foundation . close ( action ) ; } getTimeoutMs ( ) { return this . foundation . getTimeoutMs ( ) ; } getCloseOnEscape ( ) { return this . foundation . getCloseOnEscape ( ) ; } isOpen ( ) { return this . foundation . isOpen ( ) ; } handleKeyDown = ( e ) => { this . foundation . handleKeyDown ( e . nativeEvent ) ; } ; handleActionClick = ( e ) => { this . foundation . handleActionButtonClick ( e . nativeEvent ) ; } ; componentDidMount ( ) { this . foundation . init ( ) ; if ( this . props . open ) { this . foundation . open ( ) ; } } componentDidUpdate ( prevProps ) { const { open , reason } = this . props ; if ( prevProps . open !== open ) { if ( open ) { this . foundation . open ( ) ; } else { this . foundation . close ( reason ? reason : '' ) ; } } } componentWillUnmount ( ) { this . foundation . destroy ( ) ; } get classes ( ) { return classnames ( this . props . className , 'mdc-snackbar' , ... Array . from ( this . state . classes ) ) ; } render ( ) { return ( < div className = { this . classes } onKeyDown = { this . handleKeyDown } > < div className = 'mdc-snackbar__surface' > < div className = 'mdc-snackbar__label' role = 'status' aria - live = 'polite' > { this . props . message } < /div> { this . props . actionText ? ( < div className = 'mdc-snackbar__actions' > < button type = 'button' onClick = { this . handleActionClick } className = 'mdc-button mdc-snackbar__action' > { this . props . actionText } < /button> < /div>) : null} < /div> < /div>); } }