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
"use client";
import type { ReactNode, Ref } from "react";
import { cx } from "../../utils";
export interface FoxSelectOptionItemProps {
/** 옵션 목록 안에서 유일해야 한다 — 목록을 여는 요소의 `aria-activedescendant`가 가리킨다. */
id?: string;
label: ReactNode;
/** 라벨 뒤에 놓인다(시안에 앞 슬롯이 없다). 색은 라벨을 따라간다. */
icon?: ReactNode;
/** 선택된 항목. `aria-selected`가 붙고 맨 앞에 체크 아이콘이 그려진다. */
selected?: boolean;
/**
* 키보드로 이동 중인 항목. 마우스 hover와 같은 모양이지만 `:hover`로는 표현할 수 없어
* 클래스로 둔다. 호출부가 소유한다 — 항목이 스스로 켜지지 않는다.
*/
active?: boolean;
/**
* 위험한 선택지(시안의 `state=danger`). 글자·아이콘이 danger 색으로 바뀌고, 선택된 뒤에도
* 그 색을 유지한다. 시안이 hover·pressed·selected와 한 `state`로 묶어 놨지만 나머지 셋은
* 브라우저가 스스로 아는 상태라, 밖에서 받아야 하는 건 이것뿐이다.
*/
danger?: boolean;
onSelect?: () => void;
/** 포인터가 올라왔을 때. 호출부가 활성 항목을 옮기는 데 쓴다. */
onHover?: () => void;
/** 배치 조정용. 모양이 달라야 하면 여기 말고 모디파이어를 추가한다. */
className?: string;
ref?: Ref<HTMLLIElement>;
}
/**
* @fox 옵션 목록(`FoxSelectOption`)의 항목 하나. 상태를 갖지 않는다.
*
* 목록을 여는 요소가 포커스를 계속 쥐고 있어야 하므로 이 항목은 포커스를 받지 않는다 —
* 활성 표시는 `aria-activedescendant`가, 클릭은 `onSelect`가 담당한다.
*
* ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
* (또는 개별 파티셜)로 한 번 불러와야 한다.
*/
export function FoxSelectOptionItem({
id,
label,
icon,
selected = false,
active = false,
danger = false,
onSelect,
onHover,
className,
ref,
}: FoxSelectOptionItemProps) {
return (
<li
ref={ref}
id={id}
role="option"
aria-selected={selected}
className={cx(
"fox-select-option-item",
active && "fox-select-option-item--active",
danger && "fox-select-option-item--danger",
className
)}
onMouseEnter={onHover}
onClick={onSelect}
>
{selected ? (
<span className="fox-select-option-item__check" aria-hidden="true">
<CheckIcon />
</span>
) : null}
<span className="fox-select-option-item__text">{label}</span>
{icon ? (
<span className="fox-select-option-item__icon" aria-hidden="true">
{icon}
</span>
) : null}
</li>
);
}
// 시안 아이콘. 호출부가 넘기는 콘텐츠가 아니라 디자인이 정한 표시라 컴포넌트가 소유한다.
// `fill`을 `currentColor`로 두면 선택된 항목의 글자색을 물려받는데, 그 값
// (`font-theme-secondary`)이 시안의 `#1C589C`와 같아 색 규칙을 따로 둘 필요가 없다.
function CheckIcon() {
return <i className="fox-ico fox-ico--bold fox-ico-Check" aria-hidden="true" />;
}