import { VirtualDOM, AnyVirtualDOM, RxChildren } from '@youwol/rx-vdom' import { BehaviorSubject, from } from 'rxjs' import { install } from '@youwol/webpm-client' /** * Represents a drop-down view. * * * let dropdown = new Views.DropDown({ * items: {foo:42, bar:84}, * selected: 'foo', * displayedNames: { 'foo': 'Foo', 'bar': 'Bar'} * }) * display(dropdown) * display(dropdown.value$) * * */ export class DropDown implements VirtualDOM<'div'> { public readonly tag = 'div' /** * Classes associated to the view. */ public readonly class = 'mknb-DropDown dropdown' public readonly children: RxChildren<'replace'> /** * Observable on the current value. */ public readonly value$: BehaviorSubject /** * Observable on the current item's ID. */ public readonly itemId$: BehaviorSubject /** * Default value. */ public readonly value: unknown /** * Style attributes. */ public readonly style = { fontSize: 'small', } /** * * @param params * @param params.items Dictionary itemId -> values. * @param params.selected Initial item ID selected. * @param params.displayedNames Dictionary itemId -> displayed names. */ constructor(params: { items: { [k: string]: unknown } selected: string displayedNames?: { [k: string]: unknown } }) { Object.assign(this, params) this.value$ = new BehaviorSubject(params.items[params.selected]) this.itemId$ = new BehaviorSubject(params.selected) const displayedNames = params.displayedNames || Object.keys(params.items).reduce( (acc, e) => ({ ...acc, [e]: e }), {}, ) this.children = { policy: 'replace', source$: from(install({ esm: ['bootstrap#^5.3.0'] })), vdomMap: (_): AnyVirtualDOM[] => { return [ { tag: 'button', type: 'button', class: 'btn btn-sm dropdown-toggle btn-secondary', innerText: { source$: this.itemId$, vdomMap: (id: string) => displayedNames[id], }, customAttributes: { dataBsToggle: 'dropdown', ariaExpanded: 'true', }, }, { tag: 'ul', class: 'dropdown-menu', children: Object.entries(params.items).map( ([key, val]) => { return { tag: 'li', children: [ { tag: 'button', class: 'dropdown-item', innerText: key, onclick: () => { this.value$.next(val) this.itemId$.next(key) }, }, ], } }, ), }, ] }, } } }