brf/client/shared/components/checkbox_factory.tsx

78 lines
1.8 KiB
TypeScript

import { h } from 'preact'
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
import cn from 'classnames'
/**
* @param {{
* base?: string
* touched?: string
* element?: string
* label?: string
* }} styles
* @returns {import('preact').FunctionComponent<{
* autoFocus?: boolean
* className?: string
* defaultChecked?: boolean
* disabled?: boolean
* name: string
* label?: string
* required?: boolean
* }>}
*/
export default function checkboxFactory(styles) {
const Checkbox = ({
autoFocus,
className,
defaultChecked,
disabled,
name,
label,
onChange,
required,
style = 'normal',
value = 'true',
}) => {
const [touched, setTouched] = useState(false)
const checkboxRef = useRef<HTMLInputElement>()
const onBlur = useCallback(() => setTouched(true), [])
useEffect(() => {
const form = checkboxRef.current.form
const resetTouched = setTouched.bind(null, false)
form.addEventListener('reset', resetTouched)
return () => form.removeEventListener('reset', resetTouched)
}, [])
useEffect(() => {
if (autoFocus) checkboxRef.current.focus()
}, [autoFocus])
return (
<label className={cn(styles.base, styles[style], touched && styles.touched, className)}>
<input
autoFocus={autoFocus}
className={styles.element}
defaultChecked={defaultChecked}
disabled={disabled}
name={name}
onBlur={onBlur}
onChange={onChange}
ref={checkboxRef}
required={required}
type='checkbox'
value={value}
/>
<i />
{label && <span className={styles.label}>{label}</span>}
</label>
)
}
return Checkbox
}