diff options
Diffstat (limited to 'frontend/ts/src/lib/form.ts')
-rw-r--r-- | frontend/ts/src/lib/form.ts | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/frontend/ts/src/lib/form.ts b/frontend/ts/src/lib/form.ts new file mode 100644 index 0000000..a74ddca --- /dev/null +++ b/frontend/ts/src/lib/form.ts @@ -0,0 +1,175 @@ +import { h, Html, Rx, RxAble } from 'lib/rx' +import * as rx from 'lib/rx' +import * as L from 'lib/loadable' +import * as icons from 'lib/icons' + +interface InputParams { + label: string + type?: string + initValue?: string + select?: boolean + onUpdate: (value: string) => void + required?: boolean +} + +export function input({ label, type, initValue, select, onUpdate, required }: InputParams): Html { + return h('label', + { className: 'g-Label' }, + label, + h('input', + { + type: type ?? 'text', + className: 'g-Input', + onmount: (element: HTMLInputElement) => { + if (select) { + element.select() + } + }, + oninput: (event: Event) => { + let value = (event.target as HTMLInputElement).value + onUpdate(type == 'password' ? value : value.trim()) + }, + value: initValue, + required + } + ) + ) +} + +interface TextareaParams { + label: string + initValue?: string + select?: boolean + onUpdate: (value: string) => void + required?: boolean +} + +export function textarea({ label, initValue, select, onUpdate, required }: TextareaParams): Html { + return h('label', + { className: 'g-Label' }, + label, + h('textarea', + { + className: 'g-Textarea', + onmount: (element: HTMLInputElement) => { + if (select) { + element.select() + } + }, + oninput: (event: Event) => onUpdate((event.target as HTMLInputElement).value.trim()), + value: initValue, + required + } + ) + ) +} + +interface SelectParams { + label: string + initValue: string + values: { [key: string]: string } + onUpdate: (value: string) => void + required?: boolean +} + +export function select({ label, initValue, values, onUpdate, required }: SelectParams): Html { + let keys = Object.keys(values) + keys.sort((a, b) => values[a].localeCompare(values[b])) + + return h('label', + { className: 'g-Label' }, + label, + h('select', + { + className: 'g-Select', + onchange: (event: Event) => { + const element = event.target as HTMLSelectElement + onUpdate(element.value) + }, + required + }, + h('option', { label: ' ' }), + keys.map(key => + h('option', + { + value: key, + selected: initValue == key + }, + values[key] + ) + ) + ) + ) +} + +export function error(requestVar: Rx<L.Loadable<any>>): Html { + return requestVar.map(l => + L.isFailure(l) + ? h('div', { className: 'g-FormError' }, l.error) + : undefined + ) +} + +interface SubmitParams { + label: string + className?: string + disabled?: RxAble<boolean> + requestVar?: Rx<L.Loadable<any>> +} + +export function submit({ label, className, disabled, requestVar }: SubmitParams): Html { + const loadingClassname = requestVar + ? requestVar.map(l => L.isLoading(l) ? 'g-Button--Loading' : '') + : rx.pure('') + + return h('div', + { className: 'g-Form__SubmitParent' }, + h('input', { + type: 'submit', + className: loadingClassname.map(lc => `g-Button g-Button--Primary ${className ?? ''} ${lc}`), + value: label, + disabled + }), + loadingClassname.map(l => + l && h('div', + { className: 'g-Form__SubmitSpinner' }, + icons.spinner() + ) + ) + ) +} + +interface ButtonParams { + style?: string + label: string + className?: string + disabled?: RxAble<boolean> + requestVar?: Rx<L.Loadable<any>> + onClick: () => void, +} + +export function button({ style, label, className, disabled, requestVar, onClick }: ButtonParams): Html { + const loadingClassname = requestVar + ? requestVar.map(l => L.isLoading(l) ? 'g-Button--Loading' : '') + : rx.pure('') + + return h('div', + { className: 'g-Form__SubmitParent' }, + h('input', + { + type: 'button', + style, + className: loadingClassname.map(lc => `g-Button g-Button--Primary ${className ?? ''} ${lc}`), + disabled, + onclick: () => onClick(), + value: label + } + ), + loadingClassname.map(l => + l && h('div', + { className: 'g-Form__SubmitSpinner' }, + icons.spinner() + ) + ) + ) +} |