import { Component , ElementRef , EventEmitter , HostBinding , HostListener , Inject , Input , Output , QueryList , ViewChild , ViewChildren , } from '@angular/core' ; import { shouldCall } from '@tinkoff/ng-event-plugins' ; @ Component ( { selector : 'custom-select' , templateUrl : './select.template.html' , styleUrls : [ './select.style.less' ] , } ) export class SelectComponent { @ ViewChild ( 'input' ) private readonly input ! : ElementRef ; @ ViewChildren ( 'option' ) private readonly options ! : QueryList < ElementRef > ; @ HostBinding ( 'class._open' ) open = false ; @ Input ( ) items : ReadonlyArray < string > = [ ] ; @ Input ( ) value = '' ; @ Output ( ) valueChange = new EventEmitter < string > ( ) ; constructor ( @ Inject ( ElementRef ) private readonly elementRef ) { } @ HostBinding ( 'class._focused' ) get focused ( ) : boolean { return this . elementRef . nativeElement . contains ( document . activeElement ) ; } @ shouldCall ( ( _ , open ) => open ) @ HostListener ( 'keydown.esc.init' , [ '$event' ] ) @ HostListener ( 'keydown.esc.silent' , [ '$event' , 'open' ] ) onEsc ( event ) { event . stopPropagation ( ) ; this . input . nativeElement . focus ( ) ; this . open = false ; } @ shouldCall ( ( relatedTarget , nativeElement ) => ! nativeElement . contains ( relatedTarget ) ) @ HostListener ( 'focusout.init' , [ '$event' ] ) @ HostListener ( 'focusout.silent' , [ '$event.relatedTarget' , 'elementRef.nativeElement' ] ) onBlur ( ) { this . open = false ; } @ shouldCall ( element => element !== document . activeElement ) @ HostListener ( 'mousemove.init' , [ '$event' ] ) onMouseMove ( element ) { element . focus ( ) ; } @ shouldCall ( ( currentIndex , length ) => currentIndex < length - 1 ) @ HostListener ( 'keydown.arrowDown.init' , [ '$event' ] ) onArrowDown ( currentIndex ) { this . options . find ( ( _item , index ) => index === currentIndex + 1 ) ! . nativeElement . focus ( ) ; } @ shouldCall ( currentIndex => ! ! currentIndex ) @ HostListener ( 'keydown.arrowUp.init' , [ '$event' ] ) onArrowUp ( currentIndex ) { this . options . find ( ( _item , index ) => index === currentIndex - 1 ) ! . nativeElement . focus ( ) ; } onClick ( ) { this . open = ! this . open ; } onSelect ( value ) { this . input . nativeElement . focus ( ) ; this . value = value ; this . valueChange . emit ( value ) ; this . open = false ; } onInputArrowDown ( ) { if ( ! this . options . first ) { this . open = true ; } else { this . options . first . nativeElement . focus ( ) ; } } }