import React from 'react' ; import classnames from 'classnames' ; import { MDCNotchedOutlineFoundation } from '@material/notched-outline/foundation' ; import { MDCNotchedOutlineAdapter } from '@material/notched-outline/adapter' ; import { MDCFloatingLabelFoundation } from '@material/floating-label/foundation' ; const { cssClasses } = MDCNotchedOutlineFoundation ; export interface NotchedOutlineProps extends React . HTMLProps < HTMLDivElement > { className ? : string ; notchWidth ? : number ; notch ? : boolean ; } interface NotchedOutlineState { classList : Set < string > ; foundationNotchWidth ? : number ; } export default class NotchedOutline extends React . Component < NotchedOutlineProps , NotchedOutlineState > { foundation ? : MDCNotchedOutlineFoundation ; notchedEl = React . createRef < HTMLDivElement > ( ) ; static defaultProps : Partial < NotchedOutlineProps > = { className : '' , notchWidth : 0 , notch : false , } ; state : NotchedOutlineState = { classList : new Set ( ) , foundationNotchWidth : undefined , } ; componentDidMount ( ) { this . foundation = new MDCNotchedOutlineFoundation ( this . adapter ) ; this . foundation . init ( ) ; this . notch ( ) ; if ( this . label ) { this . label . style . transitionDuration = '0s' ; this . addClass ( cssClasses . OUTLINE_UPGRADED ) ; requestAnimationFrame ( ( ) => { if ( this . label ) { this . label . style . transitionDuration = '' ; } } ) ; } } componentWillUnmount ( ) { if ( this . foundation ) { this . foundation . destroy ( ) ; } } componentDidUpdate ( prevProps ) { if ( this . props . notchWidth !== prevProps . notchWidth || this . props . notch !== prevProps . notch ) { this . notch ( ) ; } } get classes ( ) { const { classList } = this . state ; const { className } = this . props ; return classnames ( 'mdc-notched-outline' , Array . from ( classList ) , className , { [ cssClasses . NO_LABEL ] : ! this . label , } ) ; } get label ( ) { if ( ! this . notchedEl . current ) { return null ; } return this . notchedEl . current . querySelector < HTMLElement > ( `.${ MDCFloatingLabelFoundation . cssClasses . ROOT }` ) ; } get adapter ( ) : MDCNotchedOutlineAdapter { return { addClass : this . addClass , removeClass : ( className ) => { this . setState ( ( prevState ) => { const classList = new Set ( prevState . classList ) ; classList . delete ( className ) ; return { classList } ; } ) ; } , setNotchWidthProperty : ( foundationNotchWidth ) => this . setState ( { foundationNotchWidth } ) , removeNotchWidthProperty : ( ) => this . setState ( { foundationNotchWidth : undefined } ) , } ; } addClass = ( className ) => { this . setState ( ( prevState ) => { const classList = new Set ( prevState . classList ) ; classList . add ( className ) ; return { classList } ; } ) ; } ; notch = ( ) => { const { notchWidth , notch } = this . props ; if ( ! this . foundation ) return ; if ( notch ) { this . foundation . notch ( notchWidth ! ) ; } else { this . foundation . closeNotch ( ) ; } } ; render ( ) { const { children , className , notchWidth , notch , ... otherProps } = this . props ; const { foundationNotchWidth } = this . state ; const notchStyle = { width : foundationNotchWidth ? `${ foundationNotchWidth }px` : undefined , } ; return ( < div className = { this . classes } ref = { this . notchedEl } { ... otherProps } > < div className = 'mdc-notched-outline__leading' / > { children ? ( < div className = 'mdc-notched-outline__notch' style = { notchStyle } > { React . Children . only ( children ) } < /div>) : null} < div className = 'mdc-notched-outline__trailing' / > < /div>); } }