File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
08-14
08-14
08-14
08-14
File name
Commit message
Commit date
"use client";
import type { ComponentPropsWithRef } from "react";
import { cx } from "../../utils";
/**
* 필수·선택 표시. 둘은 배타적이라 boolean 두 개가 아니라 하나의 값으로 받는다 — 그래야
* "필수이면서 선택"이라는 있을 수 없는 조합이 타입에서 막힌다.
*/
export type FoxFormLabelRequirement = "required" | "optional";
/**
* 네이티브 `<label>`이 받는 것을 그대로 넘겨받는다 — htmlFor·id·title 등. 이름이 겹치는
* 것만 걷어내고 아래에서 다시 정의한다.
*/
type NativeLabelProps = Omit<ComponentPropsWithRef<"label">, "className" | "hidden">;
export interface FoxFormLabelProps extends NativeLabelProps {
requirement?: FoxFormLabelRequirement;
/** "(선택)" 대신 쓸 문구. */
optionalText?: string;
/** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
hidden?: boolean;
/** 배치 조정용. */
className?: string;
}
/**
* @fox 입력 칸 위에 붙는 라벨. 상태를 갖지 않는다.
*
* 필수는 글자 뒤에 `*`, 선택은 "(선택)"을 붙인다. `*`는 `aria-hidden`이라 스크린리더가 읽지
* 않는다 — 필수 여부는 입력 요소의 `required`가 알리는 것이고 별표는 그 눈에 보이는 짝이라,
* 둘 다 읽히면 같은 말이 두 번 나온다. 반대로 "(선택)"은 대신 알려 줄 속성이 없어 읽히게 둔다.
*
* ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
* (또는 개별 파티셜)로 한 번 불러와야 한다.
*/
export function FoxFormLabel({
requirement,
optionalText = "(선택)",
hidden = false,
className,
children,
...rest
}: FoxFormLabelProps) {
if (hidden) {
return null;
}
return (
<label {...rest} className={cx("fox-form-label", className)}>
{children}
{requirement === "required" ? (
<span className="fox-form-label__required" aria-hidden="true">
*
</span>
) : null}
{requirement === "optional" ? (
<span className="fox-form-label__optional">{optionalText}</span>
) : null}
</label>
);
}