"use client"; import type { ChangeEvent, ComponentPropsWithRef, ReactNode } from "react"; import { cx } from "../../utils"; export type FoxToggleSwitchSize = "lg" | "md"; /** * 네이티브 ``가 받는 것을 그대로 넘겨받는다 — name·value·checked· * defaultChecked·disabled·required·form 등. 의미가 겹치는 것만 걷어내고 아래에서 다시 정의한다. * `role`도 걷어낸다 — 스위치로 읽히는 것이 이 컴포넌트의 정체라 호출부가 바꿀 값이 아니다. */ type NativeCheckboxProps = Omit< ComponentPropsWithRef<"input">, "type" | "role" | "size" | "className" | "children" | "hidden" | "onChange" >; export interface FoxToggleSwitchProps extends NativeCheckboxProps { size?: FoxToggleSwitchSize; /** * 스위치 옆 글자. 넘기지 않으면 영역을 렌더링하지 않는다. * * ⚠️ 생략하면 스위치를 읽어 줄 이름이 없어진다 — 그때는 `aria-label`을 함께 넘긴다 * (네이티브 속성이라 그대로 전달된다). */ label?: ReactNode; /** * 켜지거나 꺼질 때 부른다. 켜짐 여부가 첫 인자다 — 네이티브 `onChange`를 `Omit`으로 * 걷어내고 그 자리를 대신한다(`FoxCheckbox`와 같은 방식). */ onChange?: (checked: boolean, event: ChangeEvent) => void; /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */ hidden?: boolean; /** 배치 조정용. */ className?: string; } const SIZE_CLASS: Record = { lg: "fox-toggle-switch--lg", md: "fox-toggle-switch--md", }; /** * @fox 토글 스위치. 켜짐 여부는 네이티브 ``가 소유한다. * * 체크박스와 마크업은 같지만 `role="switch"`를 얹어 "선택됨"이 아니라 "켜짐/꺼짐"으로 읽히게 * 한다. 폼에도 체크박스처럼 참여한다 — 켜져 있으면 `value`가 함께 전송된다. * * 루트가 `