File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
"use client";
import type { ReactNode, Ref } from "react";
import { cx } from "../../utils";
export type FoxTextButtonType = "primary" | "secondary";
export type FoxTextButtonSize = "lg" | "md" | "sm" | "xsm";
export interface FoxTextButtonProps {
type?: FoxTextButtonType;
size: FoxTextButtonSize;
/** 네이티브 `type` — prop의 `type`이 시각 계열을 쓰므로 분리했다. */
htmlType?: "button" | "submit" | "reset";
/** 배치 조정용. 모양이 달라야 하면 여기 말고 `type`을 추가한다. */
className?: string;
/** `currentColor`로 그린 SVG여야 계열별 색이 적용된다. 크기는 슬롯이 정한다. */
leadingIcon?: ReactNode;
trailingIcon?: ReactNode;
label: string;
disabled?: boolean;
/** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
hidden?: boolean;
onAction?: () => void;
/** 포인터가 올라오면 `true`, 벗어나면 `false`. */
onHoverChange?: (hovered: boolean) => void;
ref?: Ref<HTMLButtonElement>;
}
const TYPE_CLASS: Record<FoxTextButtonType, string> = {
primary: "fox-text-button--primary",
secondary: "fox-text-button--secondary",
};
const SIZE_CLASS: Record<FoxTextButtonSize, string> = {
lg: "fox-text-button--lg",
md: "fox-text-button--md",
sm: "fox-text-button--sm",
xsm: "fox-text-button--xsm",
};
/**
* @fox 텍스트 버튼. 배경 없이 글자만으로 동작을 나타낸다. 상태를 갖지 않는다.
*
* ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
* (또는 개별 파티셜)로 한 번 불러와야 한다.
*/
export function FoxTextButton({
type = "primary",
size,
htmlType = "button",
className,
leadingIcon,
trailingIcon,
label,
disabled = false,
hidden = false,
onAction,
onHoverChange,
ref,
}: FoxTextButtonProps) {
if (hidden) {
return null;
}
return (
<button
ref={ref}
type={htmlType}
className={cx("fox-text-button", TYPE_CLASS[type], SIZE_CLASS[size], className)}
disabled={disabled}
onClick={disabled ? undefined : onAction}
onMouseEnter={onHoverChange ? () => onHoverChange(true) : undefined}
onMouseLeave={onHoverChange ? () => onHoverChange(false) : undefined}
>
{leadingIcon && (
<span className="fox-text-button__icon" aria-hidden="true">
{leadingIcon}
</span>
)}
<span className="fox-text-button__label">{label}</span>
{trailingIcon && (
<span className="fox-text-button__icon" aria-hidden="true">
{trailingIcon}
</span>
)}
</button>
);
}