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-18
08-14
08-18
08-18
File name
Commit message
Commit date
import type { ReactNode, Ref } from "react";
import { cx } from "../../utils";
export interface FoxToastProps {
/**
* 알림 문구.
*
* 이름이 `label`이 아니다 — 다른 컴포넌트의 `label`은 컨트롤에 붙는 이름이지만, 이쪽은
* 조각 안에 담기는 **내용**이라 성격이 다르다.
*/
message: ReactNode;
/**
* 보조기술이 읽는 방식을 정한다.
*
* - `false`(기본): `role="status"` — 하던 말을 끊지 않고 차례가 오면 읽는다. 저장 완료처럼
* 놓쳐도 되는 알림.
* - `true`: `role="alert"` — 읽던 것을 끊고 바로 읽는다. 지금 손을 멈춰야 하는 알림에만
* 쓴다. 남발하면 화면 낭독이 계속 끊긴다.
*/
urgent?: boolean;
/** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
hidden?: boolean;
id?: string;
/** 배치 조정용. 띄우는 위치(fixed·bottom 등)를 여기로 준다. */
className?: string;
ref?: Ref<HTMLDivElement>;
}
/**
* @fox 토스트. 어두운 판 위에 한 줄짜리 알림을 얹는다. 크기 수식어가 없다 — 시안에 하나뿐이다.
*
* **상태를 갖지 않는다.** 언제 뜨고 언제 사라질지, 화면 어디에 놓일지는 전부 호출부가 정한다
* (사용자 결정) — 이 조각은 조건부로 렌더하고 `className`으로 자리를 잡아 주면 된다. 타이머와
* 위치를 안에 두면 SCSS만 쓰는 소비자가 그 절반을 못 쓰고, 뒤이어 만들 스낵바와 규칙이 갈린다.
*
* 상호작용이 없어 `"use client"`가 아니다 — 서버 컴포넌트로 렌더된다.
*
* ⚠️ 보조기술은 **이미 화면에 있던 live region의 내용이 바뀔 때** 읽는다. 이 요소를 통째로 새로
* 붙이면 브라우저·리더 조합에 따라 읽히지 않을 수 있다. 확실히 읽혀야 하는 자리라면 호출부가
* 빈 `<div role="status">`를 미리 두고 그 안에서 토스트를 갈아 끼운다.
*
* ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
* (또는 개별 파티셜)로 한 번 불러와야 한다.
*/
export function FoxToast({
message,
urgent = false,
hidden = false,
id,
className,
ref,
}: FoxToastProps) {
if (hidden) {
return null;
}
return (
<div
ref={ref}
id={id}
role={urgent ? "alert" : "status"}
className={cx("fox-toast", className)}
>
{message}
</div>
);
}