CoastalCommitsPastes/client/app/components/input/index.tsx

72 lines
1.5 KiB
TypeScript
Raw Normal View History

2022-11-18 01:36:53 -05:00
import clsx from "clsx"
2022-04-09 20:48:19 -04:00
import React from "react"
import styles from "./input.module.css"
type Props = React.HTMLProps<HTMLInputElement> & {
2022-04-09 20:48:19 -04:00
label?: string
2022-11-16 03:49:12 -05:00
width?: number | string
height?: number | string
2022-11-18 01:36:53 -05:00
labelClassName?: string
}
// we have two special rules on top of the props:
// if onChange or value is passed, we require both
// if label is passed, we forbid aria-label and vice versa
type InputProps = Omit<Props, "onChange" | "value" | "label" | "aria-label"> &
(
| {
onChange: Props["onChange"]
value: Props["value"]
} // if onChange or value is passed, we require both
| {
onChange?: never
value?: never
}
) &
(
| {
label: Props["label"]
"aria-label"?: never
} // if label is passed, we forbid aria-label and vice versa
| {
label?: never
"aria-label": Props["aria-label"]
}
)
// eslint-disable-next-line react/display-name
const Input = React.forwardRef<HTMLInputElement, InputProps>(
2022-11-18 01:36:53 -05:00
({ label, className, width, height, labelClassName, ...props }, ref) => {
2022-04-09 20:48:19 -04:00
return (
2022-11-16 03:49:12 -05:00
<div
className={styles.wrapper}
style={{
width,
height
}}
>
2022-11-18 01:36:53 -05:00
{label && (
<label
aria-labelledby={label}
className={clsx(styles.label, labelClassName)}
>
{label}
</label>
)}
2022-04-09 20:48:19 -04:00
<input
ref={ref}
2022-11-18 01:36:53 -05:00
id={label}
className={clsx(styles.input, label && styles.withLabel, className)}
2022-04-09 20:48:19 -04:00
{...props}
2022-11-16 03:49:12 -05:00
style={{
width,
height,
...(props.style || {})
}}
2022-04-09 20:48:19 -04:00
/>
</div>
)
}
)
export default Input