import classNames from "classnames" ; import * as React from "react" ; import { polyfill } from "react-lifecycles-compat" ; import { CSSTransition , TransitionGroup } from "react-transition-group" ; import { AbstractPureComponent2 , Classes } from "../../common" ; import * as Errors from "../../common/errors" ; import { IProps } from "../../common/props" ; import { IPanel } from "./panelProps" ; import { PanelView } from "./panelView" ; export interface IPanelStackProps extends IProps { /**
     * The initial panel to show on mount. This panel cannot be removed from the
     * stack and will appear when the stack is empty.
     * This prop is only used in uncontrolled mode and is thus mutually
     * exclusive with the `stack` prop.
     */ initialPanel ? : IPanel < any > ; /**
     * Callback invoked when the user presses the back button or a panel invokes
     * the `closePanel()` injected prop method.
     */ onClose ? : ( removedPanel : IPanel ) => void ; /**
     * Callback invoked when a panel invokes the `openPanel(panel)` injected
     * prop method.
     */ onOpen ? : ( addedPanel : IPanel ) => void ; default renderActivePanelOnly ? : boolean ; default showPanelHeader ? : boolean ; /**
     * The full stack of panels in controlled mode. The last panel in the stack
     * will be displayed.
     */ stack ? : Array < IPanel < any > > ; } export interface IPanelStackState { /** Whether the stack is currently animating the push or pop of a panel. */ direction : "push" | "pop" ; /** The current stack of panels. The first panel in the stack will be displayed. */ stack : IPanel [ ] ; } deprecated @ polyfill export class PanelStack extends AbstractPureComponent2 < IPanelStackProps , IPanelStackState > { public state : IPanelStackState = { direction : "push" , stack : this . props . stack != null ? this . props . stack . slice ( ) . reverse ( ) : this . props . initialPanel !== undefined ? [ this . props . initialPanel ] : [ ] , } ; public componentDidUpdate ( prevProps , prevState ) { super . componentDidUpdate ( prevProps , prevState ) ; if ( this . props . stack !== prevProps . stack && prevProps . stack != null ) { this . setState ( { stack : this . props . stack ! . slice ( ) . reverse ( ) } ) ; } const stackLength = this . props . stack != null ? this . props . stack . length : 0 ; const prevStackLength = prevProps . stack != null ? prevProps . stack . length : 0 ; if ( stackLength !== prevStackLength && prevProps . stack != null ) { this . setState ( { direction : prevProps . stack . length - this . props . stack ! . length < 0 ? "push" : "pop" , } ) ; } } public render ( ) { const classes = classNames ( Classes . PANEL_STACK , `${ Classes . PANEL_STACK }-${ this . state . direction }` , this . props . className ) ; return ( < TransitionGroup className = { classes } component = "div" > { this . renderPanels ( ) } < /TransitionGroup>); } protected validateProps ( props ) { if ( ( props . initialPanel == null && props . stack == null ) || ( props . initialPanel != null && props . stack != null ) ) { console . error ( Errors . PANEL_STACK_INITIAL_PANEL_STACK_MUTEX ) ; } if ( props . stack != null && props . stack . length === 0 ) { console . error ( Errors . PANEL_STACK_REQUIRES_PANEL ) ; } } private renderPanels ( ) { const { renderActivePanelOnly = true } = this . props ; const { stack } = this . state ; if ( stack . length === 0 ) { return null ; } const panelsToRender = renderActivePanelOnly ? [ stack [ 0 ] ] : stack ; const panelViews = panelsToRender . map ( this . renderPanel ) . reverse ( ) ; return panelViews ; } private renderPanel = ( panel , index ) => { const { renderActivePanelOnly , showPanelHeader = true } = this . props ; const { stack } = this . state ; const layer = stack . length - index ; const key = renderActivePanelOnly ? stack . length : layer ; return ( < CSSTransition classNames = { Classes . PANEL_STACK } key = { key } timeout = { 400 } > < PanelView onClose = { this . handlePanelClose } onOpen = { this . handlePanelOpen } panel = { panel } previousPanel = { stack [ index + 1 ] } showHeader = { showPanelHeader } / > < /CSSTransition>); } ; private handlePanelClose = ( panel ) => { const { stack } = this . state ; if ( stack [ 0 ] !== panel || stack . length <= 1 ) { return ; } this . props . onClose ?. ( panel ) ; if ( this . props . stack == null ) { this . setState ( state => ( { direction : "pop" , stack : state . stack . slice ( 1 ) , } ) ) ; } } ; private handlePanelOpen = ( panel ) => { this . props . onOpen ?. ( panel ) ; if ( this . props . stack == null ) { this . setState ( state => ( { direction : "push" , stack : [ panel , ... state . stack ] , } ) ) ; } } ; }