import m from 'mithril' ; import classnames from 'classnames' ; import { Classes , IAttrs , safeCall , normalizeStyle } from '../../_shared' ; export interface IPortalAttrs extends IAttrs { /** Callback invoked when the component is mounted */ onContentMount ? : ( rootElement : HTMLElement ) => void ; /** Optional HTML element to mount to */ container ? : HTMLElement ; } export class Portal implements m . Component < IPortalAttrs > { private rootElement : HTMLElement ; private content : m . Component ; public oncreate ( { attrs , children } ) { const rootElement = document . createElement ( 'div' ) ; const container = attrs . container || document . body ; container . appendChild ( rootElement ) ; this . rootElement = rootElement ; this . setStyles ( attrs ) ; this . content = { view : ( ) => children } ; m . mount ( this . rootElement , this . content ) ; safeCall ( attrs . onContentMount , rootElement ) ; } public onupdate ( { attrs } ) { this . setStyles ( attrs ) ; } public onbeforeupdate ( { children } ) { if ( ! this . content ) return false ; this . content . view = ( ) => children ; } public onremove ( { attrs } ) { const container = attrs . container || document . body ; if ( container . contains ( this . rootElement ) ) { m . mount ( this . rootElement , null ) ; container . removeChild ( this . rootElement ) ; } } public view ( ) { return m . fragment ( { } , '' ) ; } private setStyles ( attrs ) { this . rootElement . className = classnames ( Classes . PORTAL , attrs . class ) ; this . rootElement . style . cssText = '' ; if ( attrs . style ) { Object . assign ( this . rootElement . style , normalizeStyle ( attrs . style ) ) ; } } }