Skip to content

Commit

Permalink
feat: Chip 컴포넌트 구현 (#137)
Browse files Browse the repository at this point in the history
* .

* .

* refactor: chip group의 gap을 token으로 수정

* feat: Chip, ChipGroup 컴포넌트 구현 완료

* feat: Chip 문서에서 ChipGroup 링크 생성

* package: framer-motion 멸종

* fix: mdx와 stories 컴포넌트 내용 불일치 수정

* fix: ChipGroup 자식 Gap을 10px로 고정

* refactor: style prop이 2개 이상인 컴포넌트들에 대해 interface로 추출
  • Loading branch information
fecapark authored Aug 10, 2024
1 parent c9ef5e5 commit 8da0d09
Show file tree
Hide file tree
Showing 18 changed files with 3,285 additions and 4,997 deletions.
6,716 changes: 1,719 additions & 4,997 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

256 changes: 256 additions & 0 deletions src/components/Chip/Chip.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
import { Canvas, Meta, Controls } from '@storybook/blocks';
import * as ChipStories from './Chip.stories';

<Meta of={ChipStories} />

# Chip

Chip은 항목을 설명하는 키워드를 사용하여 항목에 레이블을 지정하거나 분류하거나 구성합니다.
사용자는 칩을 통해 정보를 입력하거나 선택하여 콘텐츠를 필터링하거나 행동을 유발할 수 있습니다.

<Canvas of={ChipStories.Control} />
<Controls />

<br />
<br />

## ChipGroup

둘 이상의 Chip들을 조작하는 UI를 구성하고 싶다면, <code><a style={{ textDecoration: "underline" }} href="/?path=/docs/components-chipgroup--docs#chipgroup" alt="ChipGroup">ChipGroup</a></code>을 사용하세요.

<br />
<br />

## 사용법

Chip은 필수 프로퍼티로 `size``role` 을 받습니다.

- `size`: 칩의 크기를 결정합니다. 값은 `small`, `medium`, `large` 중 하나입니다.
- `role`: 칩의 용법을 결정합니다. 값은 `input`, `filter`, `suggestion` 중 하나입니다.

```tsx
import { Chip } from '@yourssu/design-system-react';
```

```tsx
<Chip size="medium" role="suggestion">
</Chip>
```

<Canvas of={ChipStories.DefaultUsage} withSource="none" />

### role

Chip 컴포넌트는 `role` 프로퍼티를 통해 칩의 용법을 결정합니다.

- `input`: 사용자가 입력한 개별적인 정보를 나타내기 위해 사용합니다.
- `filter`: 콘텐츠를 필터링할 때 사용합니다. `ChipGroup` 과 함께 사용했을 때 다중선택이 가능합니다.
- `suggestion`: 사용자가 선택할 수 있는 옵션을 제공할 때 사용합니다. `ChipGroup` 과 함께 사용했을 때 다중선택이 불가능합니다.

또한, `filter``suggestion` 의 경우 기본적으로 사용자 인터랙션에 따른 스타일이 적용됩니다.

```tsx
<Chip size="medium" role="input">input</Chip>

<Chip size="medium" role="filter">filter</Chip>

<Chip size="medium" role="suggestion">suggestion</Chip>
```

<Canvas of={ChipStories.Role} withSource="none" />

<br />
<br />

### role : input

role:input 으로 설정된 Chip 컴포넌트에서
사용자에게 인터랙션이 존재한다고 알려주어야 한다면, `onClick` 프로퍼티를 사용하세요.

```tsx
<Chip size="medium" role="input">No Interaction</Chip>

<Chip size="medium" role="input" onClick={() => {}}>Can Interaction</Chip>

<Chip size="medium" role="input" onClick={() => alert('클릭했습니다')}>Alert</Chip>
```

<Canvas of={ChipStories.RoleInput} withSource="none" />

<br />
<br />

### role : group

단일 Chip 컴포넌트에 부여할 수 없습니다.

단, `ChipGroup` 컴포넌트와 함께 사용할 때 반드시 부여해야합니다.

`ChipGroup` 내부의 Chip 컴포넌트는 마운트시 `ChipGroup` 컴포넌트의 `role` 프로퍼티를 상속받습니다.

```tsx
<Chip size="medium" role="group">
</Chip>


<ChipGroup role="suggestion">
<Chip size="medium" role="group">
</Chip>
</ChipGroup>
```

<br />
<br />

### 삭제 아이콘

`Chip.Remove` 컴포넌트를 선언하여
Chip 컴포넌트에 삭제 아이콘을 추가할 수 있습니다.

삭제 아이콘의 위치는 JSX 상의 선언 위치에 관계없이 항상 Chip 컴포넌트의 마지막에 위치합니다.
이를 보장하기 위해 칩의 콘텐츠 선언은 `Chip.Content` 컴포넌트로 감싸주는 것을 권장합니다.

```tsx
<Chip size="medium" role="group">
<Chip.Content>삭제 가능한 칩1</Chip.Content>
<Chip.Remove />
</Chip>
```

```tsx
// ✅ Chip.Remove의 선언 위치에 상관없이 삭제 아이콘은 항상 마지막에 위치하게 됩니다.
<Chip size="medium" role="group">
<Chip.Remove />
<Chip.Content>삭제 가능한 칩2</Chip.Content>
</Chip>

// ❌ 추천하지 않음
<Chip size="medium" role="group">
<Chip.Remove />
삭제 가능한 칩3
</Chip>
```

<Canvas of={ChipStories.RemovableChip} withSource="none" />

<br />
<br />

### 삭제 아이콘 : onClick

삭제 아이콘에 클릭 이벤트를 부여하고 싶다면, `Chip.Remove` 컴포넌트에 `onClick` 프로퍼티를 사용하세요.

```tsx
const Component = () => {
const onRemoveClick = (e: React.MouseEvent<HTMLDivElement>) => {
const target = e.currentTarget as HTMLDivElement;
const chip = target.closest('.chip') as HTMLDivElement;
alert(`삭제되었습니다: ${chip?.dataset.chip}`);
};

return (
<Chip size="medium" role="suggestion" data-chip="2024">
이벤트가 달린 삭제 가능한 칩
<Chip.Remove onClick={onRemoveClick} />
</Chip>
);
};
```

<Canvas of={ChipStories.EventRemovableChip} withSource="none" />

<br />
<br />

### 아이콘 추가

삭제 아이콘 외에도, Chip 컴포넌트에 원하는 아이콘을 추가할 수 있습니다.

`Chip.Icon` 컴포넌트를 사용해주세요.

```tsx
<Chip size="medium" role="suggestion">
<Chip.Icon>
<IcInfoCircleLine />
</Chip.Icon>
<Chip.Content>아이콘 추가</Chip.Content>
</Chip>
```

<Canvas of={ChipStories.IconChip} withSource="none" />

<br />
<br />

### 아이콘 추가 : position

`Chip.Icon` 컴포넌트는 `position` 프로퍼티를 통해 아이콘의 위치를 결정할 수 있습니다.

- `left`: 아이콘을 왼쪽에 배치합니다.
- `right`: 아이콘을 오른쪽에 배치합니다.

만약 `position` 프로퍼티를 선언하지 않는다면, 선언된 순서에 따라 아이콘의 위치가 결정됩니다.

이 순서를 보장하기 위해 칩의 콘텐츠 선언은 `Chip.Content` 컴포넌트로 감싸주는 것을 권장합니다.

```tsx
<Chip size="medium" role="suggestion">
<Chip.Icon position="left">
<IcInfoCircleLine />
</Chip.Icon>
<Chip.Icon position="right">
<IcArrowDownLine />
</Chip.Icon>
<Chip.Icon position="right">
<IcArrowDownLine />
</Chip.Icon>
<Chip.Content>아이콘 순서 변경</Chip.Content>
</Chip>
```

<Canvas of={ChipStories.IconOrderChip} withSource="none" />

<br />
<br />

## 예시

### disabled

인터랙션에 의한 Chip의 상태를 변경할 수 없도록 막습니다.

```tsx
<Chip size="medium" role="suggestion" disabled>
변경 불가
</Chip>
```

<Canvas of={ChipStories.ChipDisabled} withSource="none" />

<br />
<br />

### 상태 전달

체크박스의 선택 여부를 외부에서 상태로 관리할 수 있게 합니다.

```tsx
const Component = () => {
const [selected, setSelected] = useState(false);

const onClick = () => {
setSelected((prev) => !prev);
};

return (
<Chip size="medium" role="suggestion" selected={selected} onClick={onClick}>
상태 관리 칩
</Chip>
);
};
```

<Canvas of={ChipStories.StateManagement} withSource="none" />
Loading

0 comments on commit 8da0d09

Please sign in to comment.