import { AfterViewInit , ChangeDetectionStrategy , ChangeDetectorRef , Component , Directive , ElementRef , EventEmitter , Inject , InjectionToken , Input , NgZone , OnDestroy , OnInit , Optional , Output , ViewChild , ViewEncapsulation } from '@angular/core' ; import { coerceBooleanProperty } from '@angular/cdk/coercion' ; import { fromEvent , Subject } from 'rxjs' ; import { takeUntil } from 'rxjs/operators' ; import { MDCComponent } from '@angular-mdc/web/base' ; import { MdcRipple , MDCRippleCapableSurface } from '@angular-mdc/web/ripple' ; import { MdcTabIndicator } from '@angular-mdc/web/tab-indicator' ; import { MDCTabFoundation , MDCTabAdapter } from '@material/tab' ; import { MDCRippleAdapter , MDCRippleFoundation } from '@material/ripple' ; /**
 * Describes a parent MdcTabBar component.
 * Contains properties that MdcTab can inherit.
 */ export interface MdcTabBarParentComponent { activateTab ( index ) : void ; getTabIndex ( tab ) : number ; } /**
 * Injection token used to provide the parent MdcTabBar component to MdcTab.
 */ export const MDC_TAB_BAR_PARENT_COMPONENT = new InjectionToken < MdcTabBarParentComponent > ( 'MDC_TAB_BAR_PARENT_COMPONENT' ) ; export interface MdcTabInteractedEvent { detail : { tabId : string ; tab : MdcTab ; } ; } let nextUniqueId = 0 ; @ Directive ( { selector : 'mdc-tab-label, [mdcTabLabel]' , host : { 'class' : 'mdc-tab__text-label' } } ) export class MdcTabLabel { constructor ( public elementRef ) { } } @ Directive ( { selector : 'mdc-tab-icon, [mdcTabIcon]' , host : { 'class' : 'mdc-tab__icon' } } ) export class MdcTabIcon { constructor ( public elementRef ) { } } @ Component ( { selector : '[mdcTab], mdc-tab' , exportAs : 'mdcTab' , host : { '[id]' : 'id' , 'role' : 'tab' , 'class' : 'mdc-tab' , '[class.mdc-tab--stacked]' : 'stacked' , '[class.mdc-tab--min-width]' : 'fixed' , '[class.ngx-mdc-tab--disabled]' : 'disabled' } , templateUrl : 'tab.html' , changeDetection : ChangeDetectionStrategy . OnPush , encapsulation : ViewEncapsulation . None , providers : [ MdcRipple ] } ) export class MdcTab extends MDCComponent < MDCTabFoundation > implements AfterViewInit , OnInit , OnDestroy , MDCRippleCapableSurface { /** Emits whenever the component is destroyed. */ private _destroy = new Subject < void > ( ) ; _root ! : Element ; private _uniqueId : string = `mdc-tab-${ ++ nextUniqueId }` ; @ Input ( ) id : string = this . _uniqueId ; @ Input ( ) label ? : string ; @ Input ( ) icon ? : string ; @ Input ( ) get stacked ( ) : boolean { return this . _stacked ; } set stacked ( value ) { const newValue = coerceBooleanProperty ( value ) ; if ( newValue !== this . _stacked ) { this . _stacked = newValue ; } } private _stacked : boolean = false ; @ Input ( ) get fixed ( ) : boolean { return this . _fixed ; } set fixed ( value ) { const newValue = coerceBooleanProperty ( value ) ; if ( newValue !== this . _fixed ) { this . _fixed = newValue ; this . _changeDetectorRef . detectChanges ( ) ; } } private _fixed : boolean = false ; @ Input ( ) get disabled ( ) : boolean { return this . _disabled ; } set disabled ( value ) { this . _disabled = coerceBooleanProperty ( value ) ; } private _disabled : boolean = false ; @ Input ( ) get focusOnActivate ( ) : boolean { return this . _focusOnActivate ; } set focusOnActivate ( value ) { const newValue = coerceBooleanProperty ( value ) ; if ( newValue !== this . _focusOnActivate ) { this . _focusOnActivate = newValue ; this . _foundation . setFocusOnActivate ( this . _focusOnActivate ) ; } } private _focusOnActivate : boolean = true ; @ Output ( ) readonly interacted : EventEmitter < MdcTabInteractedEvent > = new EventEmitter < MdcTabInteractedEvent > ( ) ; @ ViewChild ( 'content' , { static : false } ) content ! : ElementRef ; @ ViewChild ( 'ripplesurface' , { static : false } ) rippleSurface ! : ElementRef ; @ ViewChild ( MdcTabIndicator , { static : false } ) tabIndicator ! : MdcTabIndicator ; getDefaultFoundation ( ) { const adapter = { setAttr : ( attr , value ) => this . _getHostElement ( ) . setAttribute ( attr , value ) , addClass : ( className ) => this . _getHostElement ( ) . classList . add ( className ) , removeClass : ( className ) => this . _getHostElement ( ) . classList . remove ( className ) , hasClass : ( className ) => this . _getHostElement ( ) . classList . contains ( className ) , activateIndicator : ( previousIndicatorClientRect ) => this . tabIndicator . activate ( previousIndicatorClientRect ) , deactivateIndicator : ( ) => this . tabIndicator . deactivate ( ) , notifyInteracted : ( ) => this . interacted . emit ( { detail : { tabId : this . id , tab : this } } ) , getOffsetLeft : ( ) => this . _getHostElement ( ) . offsetLeft , getOffsetWidth : ( ) => this . _getHostElement ( ) . offsetWidth , getContentOffsetLeft : ( ) => this . content . nativeElement . offsetLeft , getContentOffsetWidth : ( ) => this . content . nativeElement . offsetWidth , focus : ( ) => this . _getHostElement ( ) . focus ( ) } ; return new MDCTabFoundation ( adapter ) ; } constructor ( private _ngZone , private _changeDetectorRef , private _ripple , public elementRef , @ Optional ( ) @ Inject ( MDC_TAB_BAR_PARENT_COMPONENT ) private _parent ) { super ( elementRef ) ; this . _root = this . elementRef . nativeElement ; } ngOnInit ( ) { this . _foundation . init ( ) ; this . _loadListeners ( ) ; } ngAfterViewInit ( ) { this . _ripple = this . _createRipple ( ) ; this . _ripple . init ( ) ; } ngOnDestroy ( ) { this . _destroy . next ( ) ; this . _destroy . complete ( ) ; this . _ripple . destroy ( ) ; } /** Getter for the active state of the tab */ get active ( ) : boolean { return this . _foundation . isActive ( ) ; } /** Activates the tab */ activate ( computeIndicatorClientRect ? ) { this . _foundation . activate ( computeIndicatorClientRect ) ; } /** Deactivates the tab */ deactivate ( ) { this . _foundation . deactivate ( ) ; } /** Returns the indicator's client rect */ computeIndicatorClientRect ( ) { return this . tabIndicator . computeContentClientRect ( ) ; } computeDimensions ( ) { return this . _foundation . computeDimensions ( ) ; } getTabBarParent ( ) { return this . _parent ; } focus ( ) { this . _getHostElement ( ) . focus ( ) ; } private _createRipple ( ) { const rippleSurface = this . rippleSurface . nativeElement as HTMLElement ; const adapter = { ... MdcRipple . createAdapter ( this ) , addClass : ( className ) => rippleSurface . classList . add ( className ) , removeClass : ( className ) => rippleSurface . classList . remove ( className ) , updateCssVariable : ( varName , value ) => rippleSurface . style . setProperty ( varName , value ) } ; return new MdcRipple ( this . elementRef , new MDCRippleFoundation ( adapter ) ) ; } private _loadListeners ( ) { this . _ngZone . runOutsideAngular ( ( ) => fromEvent < MouseEvent > ( this . _getHostElement ( ) , 'click' ) . pipe ( takeUntil ( this . _destroy ) ) . subscribe ( ( ) => this . _ngZone . run ( ( ) => { if ( ! this . active && ! this . _disabled ) { this . _foundation . handleClick ( ) ; } } ) ) ) ; } /** Retrieves the DOM element of the component host. */ private _getHostElement ( ) { return this . elementRef . nativeElement ; } }