a tool for shared writing and social publishing
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};