autobrr/web/src/components/inputs/switch.tsx
2022-05-01 21:11:54 +02:00

126 lines
No EOL
4.3 KiB
TypeScript

import { Field } from "formik";
import type {
FieldInputProps,
FieldMetaProps,
FieldProps,
FormikProps,
FormikValues
} from "formik";
import { Switch as HeadlessSwitch } from "@headlessui/react";
import { classNames } from "../../utils";
type SwitchProps<V = any> = {
label: string
checked: boolean
disabled?: boolean
onChange: (value: boolean) => void
field?: FieldInputProps<V>
form?: FormikProps<FormikValues>
meta?: FieldMetaProps<V>
}
export const Switch = ({
label,
checked: $checked,
disabled = false,
onChange: $onChange,
field,
form,
}: SwitchProps) => {
const checked = field?.checked ?? $checked
return (
<HeadlessSwitch.Group as="div" className="flex items-center space-x-4">
<HeadlessSwitch.Label>{label}</HeadlessSwitch.Label>
<HeadlessSwitch
as="button"
name={field?.name}
disabled={disabled}
checked={checked}
onChange={value => {
form?.setFieldValue(field?.name ?? '', value)
$onChange && $onChange(value)
}}
className={classNames(
checked ? 'bg-teal-500 dark:bg-blue-500' : 'bg-gray-200 dark:bg-gray-600',
'ml-4 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500'
)}
>
{({ checked }) => (
<span
aria-hidden="true"
className={classNames(
checked ? 'translate-x-5' : 'translate-x-0',
'inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200'
)}
/>
)}
</HeadlessSwitch>
</HeadlessSwitch.Group>
)
}
export type SwitchFormikProps = SwitchProps & FieldProps & React.InputHTMLAttributes<HTMLInputElement>;
export const SwitchFormik = (props: SwitchProps) => <Switch {...props} />
interface SwitchGroupProps {
name: string;
label?: string;
description?: string;
className?: string;
}
const SwitchGroup = ({
name,
label,
description
}: SwitchGroupProps) => (
<HeadlessSwitch.Group as="ol" className="py-4 flex items-center justify-between">
{label && <div className="flex flex-col">
<HeadlessSwitch.Label as="p" className="text-sm font-medium text-gray-900 dark:text-gray-100"
passive>
{label}
</HeadlessSwitch.Label>
{description && (
<HeadlessSwitch.Description className="text-sm mt-1 text-gray-500 dark:text-gray-400">
{description}
</HeadlessSwitch.Description>
)}
</div>
}
<Field name={name} type="checkbox">
{({
field,
form: { setFieldValue },
}: any) => (
<Switch
{...field}
type="button"
value={field.value}
checked={field.checked}
onChange={value => {
setFieldValue(field?.name ?? '', value)
}}
className={classNames(
field.value ? 'bg-teal-500 dark:bg-blue-500' : 'bg-gray-200',
'ml-4 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500'
)}
>
<span
aria-hidden="true"
className={classNames(
field.value ? 'translate-x-5' : 'translate-x-0',
'inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200'
)}
/>
</Switch>
)}
</Field>
</HeadlessSwitch.Group>
);
export { SwitchGroup }