59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
import clsx, { type ClassValue } from "clsx";
|
|
import { useTranslation } from "react-i18next";
|
|
import ContentSurface from "@components/surface/ContentSurface";
|
|
import LightSurface from "@components/surface/LightSurface";
|
|
import { motion, type HTMLMotionProps } from "motion/react";
|
|
|
|
import classes from "./SwitchInput.module.css";
|
|
import tg from "@/tg";
|
|
import { useRef } from "react";
|
|
|
|
type Props = Omit<HTMLMotionProps<"div">, "className" | "onChange"> & {
|
|
value?: boolean | null;
|
|
onChange?: (value: boolean) => void;
|
|
className?: ClassValue;
|
|
};
|
|
|
|
export default function SwitchInput({ value, onChange, className, ...props }: Props) {
|
|
const { t } = useTranslation();
|
|
const selectedIndex = value != null ? (value ? 0 : 1) : 0;
|
|
const selectedIndexRef = useRef(selectedIndex);
|
|
|
|
return (
|
|
<ContentSurface
|
|
{...props}
|
|
className={clsx(classes.container, className)}
|
|
whileTap={{ scale: 1.1 }}
|
|
onClick={() => {
|
|
tg.hapticFeedback.click();
|
|
onChange?.(!value);
|
|
}}
|
|
>
|
|
<div className={classes.optionsContainer}>
|
|
<div className={classes.options}>
|
|
<motion.button
|
|
type="button"
|
|
className={clsx(classes.option, value === true && classes.selected)}
|
|
>
|
|
{t("common.on")}
|
|
</motion.button>
|
|
<motion.button
|
|
type="button"
|
|
className={clsx(classes.option, value === false && classes.selected)}
|
|
>
|
|
{t("common.off")}
|
|
</motion.button>
|
|
</div>
|
|
{selectedIndex >= 0 && (
|
|
<LightSurface
|
|
className={classes.thumb}
|
|
initial={{ left: `${selectedIndexRef.current * 50}%` }}
|
|
animate={{ left: `${selectedIndex * 50}%` }}
|
|
transition={{ type: "spring", stiffness: 500, damping: 35 }}
|
|
/>
|
|
)}
|
|
</div>
|
|
</ContentSurface>
|
|
);
|
|
}
|