import { Observable , Subject , bufferCount , filter , finalize , map , merge , of , skipUntil , switchMap , take , tap , withLatestFrom , zipWith } from "rxjs" ; import { translation } from "~/_" ; import { getElement , watchElementBoundary } from "~/browser" ; import { SearchResult , SearchWorker , isSearchReadyMessage , isSearchResultMessage } from "~/integrations" ; import { renderSearchResultItem } from "~/templates" ; import { round } from "~/utilities" ; import { Component } from "../../_" ; import { SearchQuery } from "../query" ; /**
 * Mount options
 */ interface MountOptions { query$ : Observable < SearchQuery > ; } param el param worker param options returns export function mountSearchResult ( el , { rx$ } , { query$ } ) { const push$ = new Subject < SearchResult > ( ) ; const boundary$ = watchElementBoundary ( el . parentElement ! ) . pipe ( filter ( Boolean ) ) ; const meta = getElement ( ":scope > :first-child" , el ) ; const list = getElement ( ":scope > :last-child" , el ) ; const ready$ = rx$ . pipe ( filter ( isSearchReadyMessage ) , take ( 1 ) ) ; push$ . pipe ( withLatestFrom ( query$ ) , skipUntil ( ready$ ) ) . subscribe ( ( [ { items } , { value } ] ) => { if ( value ) { switch ( items . length ) { case 0 : meta . textContent = translation ( "search.result.none" ) ; break ; case 1 : meta . textContent = translation ( "search.result.one" ) ; break ; default : meta . textContent = translation ( "search.result.other" , round ( items . length ) ) ; } } else { meta . textContent = translation ( "search.result.placeholder" ) ; } } ) ; push$ . pipe ( tap ( ( ) => list . innerHTML = "" ) , switchMap ( ( { items } ) => merge ( of ( ... items . slice ( 0 , 10 ) ) , of ( ... items . slice ( 10 ) ) . pipe ( bufferCount ( 4 ) , zipWith ( boundary$ ) , switchMap ( ( [ chunk ] ) => of ( ... chunk ) ) ) ) ) ) . subscribe ( result => list . appendChild ( renderSearchResultItem ( result ) ) ) ; const result$ = rx$ . pipe ( filter ( isSearchResultMessage ) , map ( ( { data } ) => data ) ) ; return result$ . pipe ( tap ( state => push$ . next ( state ) ) , finalize ( ( ) => push$ . complete ( ) ) , map ( state => ( { ref : el , ... state } ) ) ) ; }