@olundot/ui · Indicators
Chip
선택 가능한 작은 라벨 — 필터, 카테고리, 제거 가능 태그 등 interactive 분류에 사용.
- 변형 (variant)
- filter (선택 토글) / choice (단일 선택) / status-filter (상태 tone) / removable (X 버튼)
- 톤 (tone)
- neutral / accent / success / warning / danger / muted — context별 시각 구분
- pressed 색감
- tone=accent pressed → 선택 시 wash 패턴 — light: deep olive 14% 배경 + olive 전경/보더, dark: lime 16% 배경 + lime 전경/보더. count slot은 별도로 --accent-solid + --accent-on-solid solid 유지.
- Tag와 차이
- Chip은 interactive (클릭/토글/제거 가능). Tag는 정적 라벨 (Badge variant=pill alias). interactivity 기준 분리
- 크기
- sm (26px) · md (30px, 기본) · lg (34px)
- count slot
- count prop으로 숫자 배지 추가 — 필터 결과 수 표시 등
필터 toolbar
라이브 (선택 토글 · tone=accent pressed solid fill)코드 보기tsx
import { useState } from "react";
import { Chip } from "@olundot/ui";
const SUBJECTS = ["전체", "내과", "외과", "소아과", "산부인과"];
// filter variant: 단일 선택 토글 그룹. pressed=true 시 accent solid fill.
// tone="accent" + pressed=true → --accent-solid 배경 + --accent-on-solid 텍스트.
export function ChipFilter() {
const [selected, setSelected] = useState<string>("전체");
return (
<div role="group" aria-label="과목 필터" style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
{SUBJECTS.map((subject) => (
<Chip
key={subject}
variant="filter"
tone="accent"
pressed={selected === subject}
onClick={() => setSelected(subject)}
aria-pressed={selected === subject}
>
{subject}
</Chip>
))}
</div>
);
}단일 선택
라이브 (choice variant · neutral tone)코드 보기tsx
import { useState } from "react";
import { Chip } from "@olundot/ui";
const TYPES = ["객관식", "단답형", "서술형", "OX"];
// choice variant: 라디오 버튼 대체 — 단일 선택.
// neutral tone: 기본 surface 배경 · pressed → action-selected.
export function ChipChoice() {
const [selected, setSelected] = useState<string>("객관식");
return (
<div role="group" aria-label="문항 유형 선택" style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
{TYPES.map((type) => (
<Chip
key={type}
variant="choice"
pressed={selected === type}
onClick={() => setSelected(type)}
aria-pressed={selected === type}
>
{type}
</Chip>
))}
</div>
);
}제거 가능
라이브 (variant=removable · X 버튼 제거)코드 보기tsx
import { useState } from "react";
import { Chip } from "@olundot/ui";
// removable variant: X 버튼 자동 추가. removeLabel로 스크린리더 이름 지정 필수.
// onClick 핸들러가 chip 전체(X 포함)의 클릭을 처리 → 목록에서 해당 항목 제거.
export function ChipRemovable() {
const initial = ["내과", "외과", "소아과"];
const [chips, setChips] = useState(initial);
return (
<div role="group" aria-label="선택된 필터" style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
{chips.map((chip) => (
<Chip
key={chip}
variant="removable"
removeLabel={`${chip} 제거`}
onClick={() => setChips(chips.filter((c) => c !== chip))}
>
{chip}
</Chip>
))}
</div>
);
}크기
정적 (sm · md · lg 3종 · 26/30/34px)코드 보기tsx
import { Chip } from "@olundot/ui";
// Chip size 3종 — compact 화면(sm=26px) · 기본(md=30px) · 여유 있는 toolbar(lg=34px).
export function ChipSizes() {
return (
<div style={{ display: "flex", gap: "12px", alignItems: "center", flexWrap: "wrap" }}>
<Chip size="sm">sm 26px</Chip>
<Chip size="md">md 30px (기본)</Chip>
<Chip size="lg">lg 34px</Chip>
</div>
);
}색조 비교
정적 (6 tone · status-filter variant)코드 보기tsx
import { Chip } from "@olundot/ui";
// status-filter variant + 6 tone: 상태 분류 chip — 색으로 context 구분.
// neutral / accent / success / warning / danger / muted 각각 semantic token 사용.
export function ChipTones() {
return (
<div style={{ display: "flex", gap: "8px", flexWrap: "wrap", alignItems: "center" }}>
<Chip tone="neutral" variant="status-filter">중립</Chip>
<Chip tone="accent" variant="status-filter">브랜드</Chip>
<Chip tone="success" variant="status-filter">성공</Chip>
<Chip tone="warning" variant="status-filter">경고</Chip>
<Chip tone="danger" variant="status-filter">위험</Chip>
<Chip tone="muted" variant="status-filter">음소거</Chip>
</div>
);
}