handy online tools for AT Protocol boat.kelinci.net
atproto bluesky atcute typescript solidjs
at trunk 60 lines 1.6 kB view raw
1import { createEffect, type JSX } from 'solid-js'; 2 3import { createId } from '~/lib/hooks/id'; 4 5import type { BoundInputEvent } from './_types'; 6 7interface SelectInputProps<T extends string> { 8 label: JSX.Element; 9 blurb?: string; 10 name?: string; 11 required?: boolean; 12 value?: T; 13 autofocus?: boolean; 14 options: { value: NoInfer<T>; label: string; disabled?: boolean }[]; 15 onChange?: (next: NoInfer<T>, event: BoundInputEvent<HTMLSelectElement>) => void; 16} 17 18const SelectInput = <T extends string>(props: SelectInputProps<T>) => { 19 const fieldId = createId(); 20 21 const onChange = props.onChange; 22 23 return ( 24 <div class="flex flex-col gap-2"> 25 <label for={fieldId} class="font-semibold text-gray-600"> 26 {props.label} 27 </label> 28 29 <select 30 ref={(node) => { 31 if ('autofocus' in props) { 32 createEffect(() => { 33 if (props.autofocus) { 34 node.focus(); 35 } 36 }); 37 } 38 }} 39 id={fieldId} 40 name={props.name} 41 required={props.required} 42 value={props.value ?? ''} 43 class="rounded border border-gray-400 py-2 pl-3 pr-8 text-sm focus:border-purple-800 focus:ring-1 focus:ring-purple-800 focus:ring-offset-0" 44 onInput={(event) => onChange?.(event.target.value as T, event)} 45 > 46 {props.options.map((props) => { 47 return ( 48 <option value={/* @once */ props.value} disabled={props.disabled}> 49 {props.label} 50 </option> 51 ); 52 })} 53 </select> 54 55 <p class="text-pretty text-[0.8125rem] leading-5 text-gray-500 empty:hidden">{props.blurb}</p> 56 </div> 57 ); 58}; 59 60export default SelectInput;