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; } /** * @fox 토스트. 어두운 판 위에 한 줄짜리 알림을 얹는다. 크기 수식어가 없다 — 시안에 하나뿐이다. * * **상태를 갖지 않는다.** 언제 뜨고 언제 사라질지, 화면 어디에 놓일지는 전부 호출부가 정한다 * (사용자 결정) — 이 조각은 조건부로 렌더하고 `className`으로 자리를 잡아 주면 된다. 타이머와 * 위치를 안에 두면 SCSS만 쓰는 소비자가 그 절반을 못 쓰고, 뒤이어 만들 스낵바와 규칙이 갈린다. * * 상호작용이 없어 `"use client"`가 아니다 — 서버 컴포넌트로 렌더된다. * * ⚠️ 보조기술은 **이미 화면에 있던 live region의 내용이 바뀔 때** 읽는다. 이 요소를 통째로 새로 * 붙이면 브라우저·리더 조합에 따라 읽히지 않을 수 있다. 확실히 읽혀야 하는 자리라면 호출부가 * 빈 `
`를 미리 두고 그 안에서 토스트를 갈아 끼운다. * * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"` * (또는 개별 파티셜)로 한 번 불러와야 한다. */ export function FoxToast({ message, urgent = false, hidden = false, id, className, ref, }: FoxToastProps) { if (hidden) { return null; } return (
{message}
); }