import type { ReactNode, Ref } from "react"; import { cx } from "../../utils"; /** 시안의 state. 지난 단계 · 지금 단계 · 아직 오지 않은 단계다. */ export type FoxStepIndicatorItemState = "completion" | "ongoing" | "before"; export interface FoxStepIndicatorItemProps { state?: FoxStepIndicatorItemState; /** 단계 번호 줄(작고 흐린 글자). 넘기지 않으면 렌더링하지 않는다. */ step?: ReactNode; /** 단계 제목 줄. 넘기지 않으면 렌더링하지 않는다. */ title?: ReactNode; /** * 동그라미 오른쪽으로 뻗는 선. **마지막 단계에서는 꺼야 한다** — 켜 두면 선이 묶음 밖으로 * 삐져나간다. 선 색은 `state`가 정한다(지난 단계만 진하다). */ line?: boolean; /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */ hidden?: boolean; id?: string; /** 배치 조정용. 시안의 폭(80px)을 바꿔야 할 때도 여기로 준다. */ className?: string; ref?: Ref; } /** `Record`로 고정해 상태를 추가하면 항목 누락이 타입 에러가 되게 한다. */ const STATE_CLASS: Record = { completion: "fox-step-indicator-item--completion", ongoing: "fox-step-indicator-item--ongoing", before: "fox-step-indicator-item--before", }; /** * @fox 단계 하나. 위에 동그라미와 선, 아래에 단계 번호와 제목이 놓인다. * `FoxStepIndicator` 안에 여러 개를 늘어놓아 쓴다. * * 상태를 갖지 않는다 — 어디까지 왔는지는 호출부가 각 단계의 `state`로 정한다. * * **모바일에서는 글자가 사라지고 동그라미와 선만 남는다.** 그 판단은 CSS가 한다(화면 폭) — * 기기를 prop으로 받지 않는다. 조건부 렌더로 하면 창 폭이 바뀔 때마다 DOM이 들락거리고, * React를 쓰지 않는 소비자는 같은 결과를 얻지 못한다(`FoxChipSelectOption`의 확인 버튼과 * 같은 근거). * * ⚠️ 진행 상태를 소리로도 전해야 하면 감싼 쪽이 알린다 — 이 조각의 동그라미·선은 장식이라 * 보조기술에 아무것도 말하지 않고, 읽히는 것은 단계 번호와 제목뿐이다. 모바일에서는 그 * 글자마저 사라지므로, 그 화면에서 순서를 전해야 하면 호출부가 이름을 따로 준다. * * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"` * (또는 개별 파티셜)로 한 번 불러와야 한다. */ export function FoxStepIndicatorItem({ state = "before", step, title, line = true, hidden = false, id, className, ref, }: FoxStepIndicatorItemProps) { if (hidden) { return null; } return (
{step === undefined && title === undefined ? null : (
{step === undefined ? null : ( {step} )} {title === undefined ? null : ( {title} )}
)}
); } // 지난 단계의 체크 표시. `fox-ico`(Phosphor)를 쓰지 않는다 — 시안이 준 것은 선으로 // 그린 10×8 글리프이고, Phosphor의 Check는 면으로 채운 다른 그림이라 크기·굵기가 맞지 않는다. // `stroke`를 시안의 리터럴(흰색) 대신 `currentColor`로 두면 색을 상태 규칙이 정한다. function CheckMark() { return ( ); }