import { Observable , Subject , asyncScheduler , combineLatestWith , distinctUntilChanged , filter , finalize , fromEvent , map , merge , observeOn , tap } from "rxjs" ; import { Keyboard } from "~/browser" ; import { SearchResult , SearchWorker , isSearchResultMessage } from "~/integrations" ; import { Component , getComponentElement } from "../../_" ; /**
 * Search suggestions
 */ export interface SearchSuggest { } /**
 * Mount options
 */ interface MountOptions { keyboard$ : Observable < Keyboard > ; } param el param worker param options returns export function mountSearchSuggest ( el , { rx$ } , { keyboard$ } ) { const push$ = new Subject < SearchResult > ( ) ; const query = getComponentElement ( "search-query" ) ; const query$ = merge ( fromEvent ( query , "keydown" ) , fromEvent ( query , "focus" ) ) . pipe ( observeOn ( asyncScheduler ) , map ( ( ) => query . value ) , distinctUntilChanged ( ) ) ; push$ . pipe ( combineLatestWith ( query$ ) , map ( ( [ { suggestions } , value ] ) => { const words = value . split ( /([\s-]+)/ ) ; if ( suggestions ?. length && words [ words . length - 1 ] ) { const last = suggestions [ suggestions . length - 1 ] ; if ( last . startsWith ( words [ words . length - 1 ] ) ) words [ words . length - 1 ] = last ; } else { words . length = 0 ; } return words ; } ) ) . subscribe ( words => el . innerHTML = words . join ( "" ) . replace ( /\s/g , "&nbsp;" ) ) ; keyboard$ . pipe ( filter ( ( { mode } ) => mode === "search" ) ) . subscribe ( key => { switch ( key . type ) { case "ArrowRight" : if ( el . innerText . length && query . selectionStart === query . value . length ) query . value = el . innerText ; break ; } } ) ; const result$ = rx$ . pipe ( filter ( isSearchResultMessage ) , map ( ( { data } ) => data ) ) ; return result$ . pipe ( tap ( state => push$ . next ( state ) ) , finalize ( ( ) => push$ . complete ( ) ) , map ( ( ) => ( { ref : el } ) ) ) ; }