license import { MDCFoundation } from '@material/base/foundation' ; import { MDCSnackbarAdapter } from './adapter' ; import { cssClasses , numbers , strings } from './constants' ; const { OPENING , OPEN , CLOSING } = cssClasses ; const { REASON_ACTION , REASON_DISMISS } = strings ; export class MDCSnackbarFoundation extends MDCFoundation < MDCSnackbarAdapter > { static override get cssClasses ( ) { return cssClasses ; } static override get strings ( ) { return strings ; } static override get numbers ( ) { return numbers ; } static override get defaultAdapter ( ) : MDCSnackbarAdapter { return { addClass : ( ) => undefined , announce : ( ) => undefined , notifyClosed : ( ) => undefined , notifyClosing : ( ) => undefined , notifyOpened : ( ) => undefined , notifyOpening : ( ) => undefined , removeClass : ( ) => undefined , } ; } private opened = false ; private animationFrame = 0 ; private animationTimer = 0 ; private autoDismissTimer = 0 ; private autoDismissTimeoutMs = numbers . DEFAULT_AUTO_DISMISS_TIMEOUT_MS ; private closeOnEscape = true ; constructor ( adapter ? ) { super ( { ... MDCSnackbarFoundation . defaultAdapter , ... adapter } ) ; } override destroy ( ) { this . clearAutoDismissTimer ( ) ; cancelAnimationFrame ( this . animationFrame ) ; this . animationFrame = 0 ; clearTimeout ( this . animationTimer ) ; this . animationTimer = 0 ; this . adapter . removeClass ( OPENING ) ; this . adapter . removeClass ( OPEN ) ; this . adapter . removeClass ( CLOSING ) ; } open ( ) { this . clearAutoDismissTimer ( ) ; this . opened = true ; this . adapter . notifyOpening ( ) ; this . adapter . removeClass ( CLOSING ) ; this . adapter . addClass ( OPENING ) ; this . adapter . announce ( ) ; this . runNextAnimationFrame ( ( ) => { this . adapter . addClass ( OPEN ) ; this . animationTimer = setTimeout ( ( ) => { const timeoutMs = this . getTimeoutMs ( ) ; this . handleAnimationTimerEnd ( ) ; this . adapter . notifyOpened ( ) ; if ( timeoutMs !== numbers . INDETERMINATE ) { this . autoDismissTimer = setTimeout ( ( ) => { this . close ( REASON_DISMISS ) ; } , timeoutMs ) ; } } , numbers . SNACKBAR_ANIMATION_OPEN_TIME_MS ) ; } ) ; } param reason close ( reason = '' ) { if ( ! this . opened ) { return ; } cancelAnimationFrame ( this . animationFrame ) ; this . animationFrame = 0 ; this . clearAutoDismissTimer ( ) ; this . opened = false ; this . adapter . notifyClosing ( reason ) ; this . adapter . addClass ( cssClasses . CLOSING ) ; this . adapter . removeClass ( cssClasses . OPEN ) ; this . adapter . removeClass ( cssClasses . OPENING ) ; clearTimeout ( this . animationTimer ) ; this . animationTimer = setTimeout ( ( ) => { this . handleAnimationTimerEnd ( ) ; this . adapter . notifyClosed ( reason ) ; } , numbers . SNACKBAR_ANIMATION_CLOSE_TIME_MS ) ; } isOpen ( ) { return this . opened ; } getTimeoutMs ( ) { return this . autoDismissTimeoutMs ; } setTimeoutMs ( timeoutMs ) { const minValue = numbers . MIN_AUTO_DISMISS_TIMEOUT_MS ; const maxValue = numbers . MAX_AUTO_DISMISS_TIMEOUT_MS ; const indeterminateValue = numbers . INDETERMINATE ; if ( timeoutMs === numbers . INDETERMINATE || ( timeoutMs <= maxValue && timeoutMs >= minValue ) ) { this . autoDismissTimeoutMs = timeoutMs ; } else { throw new Error ( `
        timeoutMs must be an integer in the range ${ minValue }–${ maxValue }
        (or ${ indeterminateValue } to disable), but got '${ timeoutMs }'` ) ; } } getCloseOnEscape ( ) { return this . closeOnEscape ; } setCloseOnEscape ( closeOnEscape ) { this . closeOnEscape = closeOnEscape ; } handleKeyDown ( evt ) { const isEscapeKey = evt . key === 'Escape' || evt . keyCode === 27 ; if ( isEscapeKey && this . getCloseOnEscape ( ) ) { this . close ( REASON_DISMISS ) ; } } handleActionButtonClick ( _evt ) { this . close ( REASON_ACTION ) ; } handleActionIconClick ( _evt ) { this . close ( REASON_DISMISS ) ; } private clearAutoDismissTimer ( ) { clearTimeout ( this . autoDismissTimer ) ; this . autoDismissTimer = 0 ; } private handleAnimationTimerEnd ( ) { this . animationTimer = 0 ; this . adapter . removeClass ( cssClasses . OPENING ) ; this . adapter . removeClass ( cssClasses . CLOSING ) ; } /**
     * Runs the given logic on the next animation frame, using setTimeout to factor in Firefox reflow behavior.
     */ private runNextAnimationFrame ( callback ) { cancelAnimationFrame ( this . animationFrame ) ; this . animationFrame = requestAnimationFrame ( ( ) => { this . animationFrame = 0 ; clearTimeout ( this . animationTimer ) ; this . animationTimer = setTimeout ( callback , 0 ) ; } ) ; } } export default MDCSnackbarFoundation ;