handy online tools for AT Protocol boat.kelinci.net
atproto bluesky atcute typescript solidjs
at trunk 73 lines 1.8 kB view raw
1import { createEffect, type JSX } from 'solid-js'; 2 3import { createId } from '~/lib/hooks/id'; 4 5import type { BoundInputEvent } from './_types'; 6 7export interface TextInputProps { 8 label: JSX.Element; 9 blurb?: JSX.Element; 10 monospace?: boolean; 11 type?: 'text' | 'password' | 'url' | 'email'; 12 name?: string; 13 required?: boolean; 14 disabled?: boolean; 15 autocomplete?: 'off' | 'on' | 'one-time-code' | 'username'; 16 autocorrect?: 'off' | 'on'; 17 pattern?: string; 18 placeholder?: string; 19 value?: string; 20 autofocus?: boolean; 21 onChange?: (next: string, event: BoundInputEvent<HTMLInputElement>) => void; 22} 23 24const textInputStyles = ({ monospace = false }: TextInputProps) => { 25 let cn = `rounded border border-gray-400 px-3 py-2 text-sm placeholder:text-gray-400 focus:border-purple-800 focus:ring-1 focus:ring-purple-800 focus:ring-offset-0`; 26 27 if (monospace) { 28 cn += ` font-mono tracking-wide`; 29 } 30 31 return cn; 32}; 33 34const TextInput = (props: TextInputProps) => { 35 const fieldId = createId(); 36 37 const onChange = props.onChange; 38 39 return ( 40 <div class="flex flex-col gap-2"> 41 <label for={fieldId} class="font-semibold text-gray-600"> 42 {props.label} 43 </label> 44 45 <input 46 ref={(node) => { 47 if ('autofocus' in props) { 48 createEffect(() => { 49 if (props.autofocus) { 50 node.focus(); 51 } 52 }); 53 } 54 }} 55 type={props.type ?? 'text'} 56 id={fieldId} 57 name={props.name} 58 required={props.required} 59 disabled={props.disabled} 60 autocomplete={props.autocomplete} 61 pattern={props.pattern} 62 placeholder={props.placeholder} 63 value={props.value ?? ''} 64 class={textInputStyles(props)} 65 onInput={(event) => onChange?.(event.target.value, event)} 66 /> 67 68 <p class="text-pretty text-[0.8125rem] leading-5 text-gray-500 empty:hidden">{props.blurb}</p> 69 </div> 70 ); 71}; 72 73export default TextInput;