/** * Select dropdown widget. */ import {dom, MaybeObsArray, Observable, subscribe} from '../../index'; export interface IOptionFull { value: T; label: string; disabled?: boolean; } // For string options, we can use a string for label and value, without wrapping into an object. export type IOption = (T & string) | IOptionFull; function unwrapMaybeObsArray(array: MaybeObsArray): T[] { return Array.isArray(array) ? array : array.get(); } function getOptionValue(option: IOption): T { return (typeof option === "string") ? option : (option as IOptionFull).value; } /** * Creates a select dropdown widget. The observable `obs` reflects the value of the selected * option, and `optionArray` is an array (regular or observable) of option values and labels. * These may be either strings, or `{label, value, disabled}` objects. * * The type of value may be any type at all; it is opaque to this widget. * * If obs is set to an invalid or disabled value, then defLabel option is used to determine the * label that the select box will show, blank by default. * * Usage: * ``` * const fruit = observable("apple"); * select(fruit, ["apple", "banana", "mango"]); * * const employee = observable(17); * const employees = obsArray>([ * {value: 12, label: "Bob", disabled: true}, * {value: 17, label: "Alice"}, * {value: 21, label: "Eve"}, * ]); * select(employee, employees, {defLabel: "Select employee:"}); * ``` */ export function select(obs: Observable, optionArray: MaybeObsArray>, options: {defLabel?: string} = {}) { const {defLabel = ""} = options; return dom('select', // Include a hidden option to represent a default value. This one gets shown when none of the // options are selected. This is more consistent when showing the first valid option. dom('option', dom.hide(true), defLabel), // Create all the option elements. dom.forEach(optionArray, (option) => { const obj: IOptionFull = (typeof option === "string") ? {value: option, label: option} : (option as IOptionFull); // Note we only set 'selected' when an