import m from 'mithril' ; import classnames from 'classnames' ; import { Classes , safeCall } from '../../_shared' ; import { Popover , IPopoverAttrs } from '../popover' ; import { AbstractComponent } from '../abstract-component' ; import { Spinner } from '../spinner' ; import { QueryList , IQueryListAttrs } from '../query-list' ; export interface ISelectListAttrs < T > extends IQueryListAttrs < T > { default closeOnSelect ? : boolean ; default popoverAttrs ? : Partial < IPopoverAttrs > ; /** Trigger element */ trigger : m . Vnode < any , any > ; /** Header content */ header ? : m . Children ; /** Footer content */ footer ? : m . Children ; /** Toggles loading state of inner list */ loading ? : boolean ; } export class SelectList < T > extends AbstractComponent < ISelectListAttrs < T > > { public queryList = QueryList . ofType < T > ( ) ; private isOpen : boolean ; private activeIndex : number = 0 ; public static ofType < T > ( ) { return SelectList as new ( ) => SelectList < T > ; } public getDefaultAttrs ( ) { return { closeOnSelect : true , popoverAttrs : { } , inputAttrs : { } } as ISelectListAttrs < T > ; } public oninit ( vnode ) { super . oninit ( vnode ) ; const { isOpen , defaultIsOpen } = vnode . attrs . popoverAttrs ! ; this . isOpen = isOpen != null ? isOpen : defaultIsOpen != null ? defaultIsOpen : false ; } public onbeforeupdate ( vnode , old ) { super . onbeforeupdate ( vnode , old ) ; const isOpen = vnode . attrs . popoverAttrs ! . isOpen ; const wasOpen = old . attrs . popoverAttrs ! . isOpen ; if ( isOpen && ! wasOpen ) { this . isOpen = true ; } else if ( ! isOpen && wasOpen ) { this . isOpen = false ; } } public view ( ) { const { class : className , popoverAttrs , header , footer , trigger , closeOnSelect , loading , ... queryListAttrs } = this . attrs ; const queryList = m ( this . queryList , { activeIndex : this . activeIndex , onActiveItemChange : this . handleActiveItemChange , ... queryListAttrs , inputAttrs : { ... queryListAttrs . inputAttrs , autofocus : true } , onSelect : this . handleSelect } ) ; const content = [ header , m ( Spinner , { active : loading , background : true , fill : true } ) , queryList , footer ] ; return m ( Popover , { autofocus : true , position : 'bottom-start' , closeOnEscapeKey : false , ... popoverAttrs , class : classnames ( Classes . SELECT_LIST , className , popoverAttrs ! . class ) , isOpen : this . isOpen , content , onInteraction : this . handlePopoverInteraction , trigger } ) ; } private handleActiveItemChange = ( activeItem , index ) => { this . activeIndex = index ; safeCall ( this . attrs . onActiveItemChange , activeItem , index ) ; } ; private handleSelect = ( item , e , index ) => { const { onSelect , closeOnSelect } = this . attrs ; if ( closeOnSelect ) { this . isOpen = false ; } safeCall ( onSelect , item , e , index ) ; } ; private handlePopoverInteraction = ( nextOpenState , e ) => { const { isOpen , onInteraction } = this . attrs . popoverAttrs ! ; if ( isOpen != null ) { safeCall ( onInteraction , nextOpenState , e ) ; } else this . isOpen = nextOpenState ; } ; }