a tool for shared writing and social publishing
at main 2.4 kB view raw
1"use client"; 2import { useEffect, useRef, useState, type JSX } from "react"; 3import { onMouseDown } from "src/utils/iosInputMouseDown"; 4import { isIOS } from "src/utils/isDevice"; 5import { focusElement } from "src/utils/focusElement"; 6 7export const Input = ( 8 props: { 9 textarea?: boolean; 10 } & JSX.IntrinsicElements["input"] & 11 JSX.IntrinsicElements["textarea"], 12) => { 13 let { textarea, ...inputProps } = props; 14 let ref = useRef<HTMLInputElement>(null); 15 useEffect(() => { 16 if (!isIOS()) return; 17 if (props.autoFocus) { 18 focusElement(ref.current); 19 } 20 }, [props.autoFocus]); 21 22 if (textarea) return <textarea {...inputProps} />; 23 return ( 24 <input 25 {...inputProps} 26 autoFocus={isIOS() ? false : props.autoFocus} 27 ref={ref} 28 onMouseDown={onMouseDown} 29 /> 30 ); 31}; 32 33export const AsyncValueInput = ( 34 props: { 35 textarea?: boolean; 36 } & JSX.IntrinsicElements["input"] & 37 JSX.IntrinsicElements["textarea"], 38) => { 39 let [intermediateState, setIntermediateState] = useState( 40 props.value as string, 41 ); 42 43 useEffect(() => { 44 setIntermediateState(props.value as string); 45 }, [props.value]); 46 47 return ( 48 <Input 49 {...props} 50 value={intermediateState} 51 onChange={async (e) => { 52 if (!props.onChange) return; 53 setIntermediateState(e.currentTarget.value); 54 await Promise.all([ 55 props.onChange(e as React.ChangeEvent<HTMLInputElement>), 56 ]); 57 }} 58 /> 59 ); 60}; 61 62export const InputWithLabel = ( 63 props: { 64 label: string; 65 textarea?: boolean; 66 } & JSX.IntrinsicElements["input"] & 67 JSX.IntrinsicElements["textarea"], 68) => { 69 let { label, textarea, ...inputProps } = props; 70 let style = ` 71 appearance-none resize-none w-full 72 bg-transparent 73 outline-hidden focus:outline-0 74 font-normal not-italic text-base text-primary disabled:text-tertiary 75 disabled:cursor-not-allowed 76 ${props.className}`; 77 return ( 78 <label 79 className={`input-with-border flex flex-col gap-px text-sm text-tertiary font-bold italic leading-tight py-1! px-[6px]! ${props.disabled && "bg-border-light! cursor-not-allowed! hover:border-border!"}`} 80 > 81 {props.label} 82 {textarea ? ( 83 <textarea {...inputProps} className={style} /> 84 ) : ( 85 <Input {...inputProps} className={style} /> 86 )} 87 </label> 88 ); 89};