import React from 'react' ; import classnames from 'classnames' ; import TopAppBarFixedAdjust , { TopAppbarFixedAdjustProps } from './FixedAdjust' ; import TopAppBarSection from './Section' ; import TopAppBarRow from './Row' ; import TopAppBarTitle from './Title' ; import TopAppBarIcon from './Icon' ; import { cssClasses } from './constants' ; import { MDCFixedTopAppBarFoundation } from '@material/top-app-bar/fixed/foundation' ; import { MDCTopAppBarAdapter } from '@material/top-app-bar/adapter' ; import { MDCTopAppBarFoundation } from '@material/top-app-bar/standard/foundation' ; import { MDCShortTopAppBarFoundation } from '@material/top-app-bar/short/foundation' ; import { SpecificEventListener } from '@material/base/types' ; export type MDCTopAppBarFoundationTypes = MDCFixedTopAppBarFoundation | MDCTopAppBarFoundation | MDCShortTopAppBarFoundation ; export interface TopAppBarProps < T > extends React . HTMLProps < T > { className ? : string ; dense ? : boolean ; fixed ? : boolean ; prominent ? : boolean ; short ? : boolean ; shortCollapsed ? : boolean ; style ? : React . CSSProperties ; scrollTarget ? : React . RefObject < HTMLElement > ; tag ? : string ; onNavIconClicked ? : ( ) => void ; } interface TopAppBarState { classList : Set < string > ; style : React . CSSProperties ; scrollTarget ? : React . RefObject < HTMLElement > ; } export type VariantType = 'dense' | 'fixed' | 'prominent' | 'short' | 'shortCollapsed' ; class TopAppBar < T extends HTMLElement = HTMLHeadingElement > extends React . Component < TopAppBarProps < T > , TopAppBarState > { topAppBarElement : React . RefObject < HTMLElement > = React . createRef ( ) ; foundation ! : MDCTopAppBarFoundationTypes ; state : TopAppBarState = { classList : new Set ( ) , style : { } , } ; static defaultProps : Partial < TopAppBarProps < HTMLHeadingElement > > = { className : '' , dense : false , fixed : false , prominent : false , short : false , shortCollapsed : false , style : { } , tag : 'header' , } ; get classes ( ) { const { classList } = this . state ; const { className , dense , fixed , prominent , short , shortCollapsed , } = this . props ; return classnames ( cssClasses . BASE , Array . from ( classList ) , className , { [ cssClasses . FIXED ] : fixed , [ cssClasses . SHORT ] : shortCollapsed || short , [ cssClasses . SHORT_COLLAPSED ] : shortCollapsed , [ cssClasses . PROMINENT ] : prominent , [ cssClasses . DENSE ] : dense , } ) ; } componentDidMount ( ) { this . initializeFoundation ( ) ; if ( this . props . scrollTarget ) { this . setState ( { scrollTarget : this . props . scrollTarget } ) ; } } componentWillUnmount ( ) { this . foundation . destroy ( ) ; } componentDidUpdate ( prevProps , prevState ) { const foundationChanged = [ 'short' , 'shortCollapsed' , 'fixed' ] . some ( ( variant ) => this . props [ variant as VariantType ] !== prevProps [ variant as VariantType ] ) ; if ( foundationChanged ) { this . setState ( { classList : new Set < string > ( ) } , this . initializeFoundation ) ; } if ( prevProps . scrollTarget !== this . props . scrollTarget ) { this . foundation . destroyScrollHandler ( ) ; this . setState ( { scrollTarget : this . props . scrollTarget } ) ; } if ( prevState . scrollTarget !== this . state . scrollTarget ) { this . foundation . initScrollHandler ( ) ; } } private initializeFoundation = ( ) => { const { short , shortCollapsed , fixed } = this . props ; if ( this . foundation ) { this . foundation . destroy ( ) ; } if ( short || shortCollapsed ) { this . foundation = new MDCShortTopAppBarFoundation ( this . adapter ) ; } else if ( fixed ) { this . foundation = new MDCFixedTopAppBarFoundation ( this . adapter ) ; } else { this . foundation = new MDCTopAppBarFoundation ( this . adapter ) ; } this . foundation . init ( ) ; } ; getMergedStyles = ( ) => { const { style } = this . state ; return Object . assign ( { } , style , this . props . style ) ; } ; get adapter ( ) : MDCTopAppBarAdapter { return { addClass : ( className ) => this . setState ( { classList : this . state . classList . add ( className ) } ) , removeClass : ( className ) => { const { classList } = this . state ; classList . delete ( className ) ; this . setState ( { classList } ) ; } , hasClass : ( className ) => this . classes . split ( ' ' ) . includes ( className ) , setStyle : ( varName , value ) => { const updatedStyle = Object . assign ( { } , this . state . style ) as React . CSSProperties ; updatedStyle [ varName ] = value ; this . setState ( { style : updatedStyle } ) ; } , getTopAppBarHeight : ( ) => { if ( this . topAppBarElement && this . topAppBarElement . current ) { return this . topAppBarElement . current . clientHeight ; } return 0 ; } , registerScrollHandler : ( handler ) => { if ( this . state . scrollTarget && this . state . scrollTarget . current ) { this . state . scrollTarget . current . addEventListener ( 'scroll' , handler ) ; } else { window . addEventListener ( 'scroll' , handler ) ; } } , deregisterScrollHandler : ( handler ) => { if ( this . state . scrollTarget && this . state . scrollTarget . current ) { this . state . scrollTarget . current . removeEventListener ( 'scroll' , handler ) ; } else { window . removeEventListener ( 'scroll' , handler ) ; } } , getViewportScrollY : ( ) => { return this . state . scrollTarget && this . state . scrollTarget . current ? this . state . scrollTarget . current . scrollTop : window . pageYOffset ; } , getTotalActionItems : ( ) => { if ( this . topAppBarElement && this . topAppBarElement . current ) { const actionItems = this . topAppBarElement . current . querySelectorAll ( `.${ cssClasses . ACTION_ITEM }` ) ; return actionItems . length ; } return 0 ; } , registerResizeHandler : ( handler ) => { window . addEventListener ( 'resize' , handler ) ; } , deregisterResizeHandler : ( handler ) => { window . removeEventListener ( 'resize' , handler ) ; } , registerNavigationIconInteractionHandler : ( ) => null , deregisterNavigationIconInteractionHandler : ( ) => null , notifyNavigationIconClicked : ( ) => { if ( this . props . onNavIconClicked ) { this . props . onNavIconClicked ( ) ; } } , } ; } render ( ) { const { children , className , dense , fixed , short , shortCollapsed , prominent , scrollTarget , tag : Tag , ... otherProps } = this . props ; return ( < Tag { ... otherProps } className = { this . classes } style = { this . getMergedStyles ( ) } ref = { this . topAppBarElement } > { children } < /Tag>); } } export default TopAppBar ; export { TopAppBarFixedAdjust , TopAppbarFixedAdjustProps , TopAppBarIcon , TopAppBarRow , TopAppBarSection , TopAppBarTitle , } ;