@idbrnd/design-system 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +276 -0
- package/dist/components/Input/Input.d.ts +1 -1
- package/dist/components/Input/Input.types.d.ts +4 -3
- package/dist/components/Input/useInputState.d.ts +1 -3
- package/dist/components/SearchBar/SearchBar.d.ts +7 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +624 -573
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# @idbrnd/design-system
|
|
2
|
+
|
|
3
|
+
React 기반 IDB 디자인 시스템 컴포넌트 라이브러리입니다.
|
|
4
|
+
|
|
5
|
+
## 설치
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @idbrnd/design-system
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`peerDependencies`
|
|
12
|
+
- `react@^18.3.1`
|
|
13
|
+
- `react-dom@^18.3.1`
|
|
14
|
+
|
|
15
|
+
## 시작하기
|
|
16
|
+
|
|
17
|
+
엔트리 파일(예: `src/main.tsx`)에서 스타일을 먼저 로드한 뒤 컴포넌트를 사용합니다.
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import '@idbrnd/design-system/style.css';
|
|
21
|
+
import { FillButton } from '@idbrnd/design-system';
|
|
22
|
+
|
|
23
|
+
export default function App() {
|
|
24
|
+
return <FillButton>확인</FillButton>;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 제공 컴포넌트 / API
|
|
29
|
+
|
|
30
|
+
- 버튼
|
|
31
|
+
- `FillButton`
|
|
32
|
+
- `OutlineButton`
|
|
33
|
+
- `TextButton`
|
|
34
|
+
- `WeakButton`
|
|
35
|
+
- `BasicIconButton`
|
|
36
|
+
- `FillIconButton`
|
|
37
|
+
- `OutlineIconButton`
|
|
38
|
+
- 입력
|
|
39
|
+
- `Input`
|
|
40
|
+
- `SearchBar`
|
|
41
|
+
- 피드백
|
|
42
|
+
- `showToast`, `dismissToast`
|
|
43
|
+
- `showSnackbar`, `dismissSnackbar`
|
|
44
|
+
- `Spinner`, `CustomSpinner`, `Clip`, `FadeSpinner`
|
|
45
|
+
- 기타
|
|
46
|
+
- `PushBadge`
|
|
47
|
+
|
|
48
|
+
## 사용 예시
|
|
49
|
+
|
|
50
|
+
### 1. Fill / Outline / Text / Weak Button
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import {
|
|
54
|
+
FillButton,
|
|
55
|
+
OutlineButton,
|
|
56
|
+
TextButton,
|
|
57
|
+
WeakButton
|
|
58
|
+
} from '@idbrnd/design-system';
|
|
59
|
+
|
|
60
|
+
function ButtonExample() {
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<FillButton variant="primary">저장</FillButton>
|
|
64
|
+
<OutlineButton variant="secondary">취소</OutlineButton>
|
|
65
|
+
<TextButton size="small" variant="assistive">텍스트 버튼</TextButton>
|
|
66
|
+
<WeakButton size="xsmall" variant="error">삭제</WeakButton>
|
|
67
|
+
</>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Icon Button + PushBadge
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import {
|
|
76
|
+
BasicIconButton,
|
|
77
|
+
FillIconButton,
|
|
78
|
+
OutlineIconButton,
|
|
79
|
+
PushBadge
|
|
80
|
+
} from '@idbrnd/design-system';
|
|
81
|
+
|
|
82
|
+
function IconButtonExample() {
|
|
83
|
+
return (
|
|
84
|
+
<>
|
|
85
|
+
<div style={{ position: 'relative', width: 'fit-content' }}>
|
|
86
|
+
<BasicIconButton>+</BasicIconButton>
|
|
87
|
+
<PushBadge variant="dot" />
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<FillIconButton variant="primary" size="large">
|
|
91
|
+
+
|
|
92
|
+
</FillIconButton>
|
|
93
|
+
|
|
94
|
+
<OutlineIconButton size="medium">
|
|
95
|
+
+
|
|
96
|
+
</OutlineIconButton>
|
|
97
|
+
</>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`PushBadge` 단독 사용:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import { PushBadge } from '@idbrnd/design-system';
|
|
106
|
+
|
|
107
|
+
function PushBadgeExample() {
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
<PushBadge variant="number" count={32} />
|
|
111
|
+
<PushBadge variant="info" />
|
|
112
|
+
<PushBadge variant="dot" />
|
|
113
|
+
</>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. Input (Controlled)
|
|
119
|
+
|
|
120
|
+
`Input`은 `value` + `onChange`를 받는 controlled 컴포넌트입니다.
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { useState } from 'react';
|
|
124
|
+
import { Input } from '@idbrnd/design-system';
|
|
125
|
+
|
|
126
|
+
function InputExample() {
|
|
127
|
+
const [email, setEmail] = useState('');
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<Input
|
|
131
|
+
headingContent="이메일"
|
|
132
|
+
placeholder="이메일을 입력하세요"
|
|
133
|
+
value={email}
|
|
134
|
+
onChange={(event) => setEmail(event.target.value)}
|
|
135
|
+
description="가입 안내 메일을 받을 주소입니다."
|
|
136
|
+
/>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
유의사항:
|
|
142
|
+
|
|
143
|
+
- `heading={false}`이면 상단 라벨과 `required` 별표 표시는 렌더링되지 않습니다. 다만 실제 `<input>`의 `required` 속성은 그대로 적용됩니다.
|
|
144
|
+
- `description`은 문자열뿐 아니라 JSX도 받을 수 있습니다. `variant="error"`일 때는 `description` 대신 `errorMessage`가 우선 노출됩니다.
|
|
145
|
+
- `errorMessage`도 문자열뿐 아니라 JSX를 받을 수 있습니다.
|
|
146
|
+
- `leadingIcon`, `headingContent`, `trailingContent`는 모두 JSX를 넣을 수 있습니다. 특히 `trailingContent`에는 버튼, 텍스트, 아이콘 조합 등 원하는 형태의 trailing UI를 구성할 수 있습니다.
|
|
147
|
+
- `width`는 `number | string`을 지원하며, 지정하지 않으면 기본값은 `100%`입니다.
|
|
148
|
+
- `variant`를 지정하지 않으면 값 존재 여부에 따라 내부적으로 `basic` 또는 `typed` 상태가 자동 적용됩니다.
|
|
149
|
+
|
|
150
|
+
### 4. SearchBar
|
|
151
|
+
|
|
152
|
+
`SearchBar`는 `Enter` 입력 또는 우측 검색 버튼 클릭 시 `onSearch`를 호출합니다.
|
|
153
|
+
우측 삭제 버튼은 입력값이 있을 때만 표시되며, `onClear`를 전달하면 커스텀 삭제 동작을 사용할 수 있습니다.
|
|
154
|
+
`variant="default"`는 내부 `Input`의 `basic`에 매핑되며, `onTyping`/`typed`/`error`도 각각 대응됩니다.
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
import { useState } from 'react';
|
|
158
|
+
import { SearchBar } from '@idbrnd/design-system';
|
|
159
|
+
|
|
160
|
+
function SearchExample() {
|
|
161
|
+
const [keyword, setKeyword] = useState('');
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<SearchBar
|
|
165
|
+
value={keyword}
|
|
166
|
+
onChange={(event) => setKeyword(event.target.value)}
|
|
167
|
+
onSearch={(value) => {
|
|
168
|
+
console.log('search:', value);
|
|
169
|
+
}}
|
|
170
|
+
placeholder="검색어를 입력하세요"
|
|
171
|
+
/>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 5. Spinner
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import {
|
|
180
|
+
Spinner,
|
|
181
|
+
CustomSpinner,
|
|
182
|
+
Clip,
|
|
183
|
+
FadeSpinner
|
|
184
|
+
} from '@idbrnd/design-system';
|
|
185
|
+
|
|
186
|
+
function SpinnerExample() {
|
|
187
|
+
return (
|
|
188
|
+
<div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
|
|
189
|
+
<Spinner />
|
|
190
|
+
<CustomSpinner size={12} />
|
|
191
|
+
<Clip size={24} color="var(--semantic-primary-default)" />
|
|
192
|
+
<FadeSpinner width={4} height={12} />
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 6. Toast
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
import {
|
|
202
|
+
FillButton,
|
|
203
|
+
showToast,
|
|
204
|
+
dismissToast
|
|
205
|
+
} from '@idbrnd/design-system';
|
|
206
|
+
|
|
207
|
+
function ToastExample() {
|
|
208
|
+
return (
|
|
209
|
+
<>
|
|
210
|
+
<FillButton
|
|
211
|
+
onClick={() =>
|
|
212
|
+
showToast({
|
|
213
|
+
variant: 'positive',
|
|
214
|
+
message: '저장되었습니다.'
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
>
|
|
218
|
+
Toast 열기
|
|
219
|
+
</FillButton>
|
|
220
|
+
|
|
221
|
+
<FillButton variant="assistive" onClick={() => dismissToast()}>
|
|
222
|
+
Toast 닫기
|
|
223
|
+
</FillButton>
|
|
224
|
+
</>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### 7. Snackbar
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
import {
|
|
233
|
+
FillButton,
|
|
234
|
+
showSnackbar,
|
|
235
|
+
dismissSnackbar
|
|
236
|
+
} from '@idbrnd/design-system';
|
|
237
|
+
|
|
238
|
+
function SnackbarExample() {
|
|
239
|
+
return (
|
|
240
|
+
<>
|
|
241
|
+
<FillButton
|
|
242
|
+
onClick={() =>
|
|
243
|
+
showSnackbar({
|
|
244
|
+
variant: 'basic',
|
|
245
|
+
heading: 'Message deleted.',
|
|
246
|
+
description: 'You can undo this action.',
|
|
247
|
+
actionLabel: '실행 취소',
|
|
248
|
+
onActionClick: () => console.log('undo'),
|
|
249
|
+
closeButton: true
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
>
|
|
253
|
+
Snackbar 열기
|
|
254
|
+
</FillButton>
|
|
255
|
+
|
|
256
|
+
<FillButton variant="assistive" onClick={() => dismissSnackbar()}>
|
|
257
|
+
Snackbar 닫기
|
|
258
|
+
</FillButton>
|
|
259
|
+
</>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## TypeScript
|
|
265
|
+
|
|
266
|
+
모든 컴포넌트의 Props 타입을 패키지에서 직접 import 할 수 있습니다.
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
import type { FillButtonProps, InputProps, ToastShowOptions } from '@idbrnd/design-system';
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## 주의사항
|
|
273
|
+
|
|
274
|
+
- `Input`, `SearchBar`는 controlled 방식으로 사용해야 합니다.
|
|
275
|
+
- `showToast`, `showSnackbar`는 내부적으로 `document.body`에 포털을 생성하므로 브라우저 환경에서 호출해야 합니다.
|
|
276
|
+
- CSS 변수/타이포그래피를 포함한 스타일을 위해 `@idbrnd/design-system/style.css` import를 권장합니다.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { InputProps } from './Input.types';
|
|
2
|
-
export type { InputProps, InputSize, InputVariant,
|
|
2
|
+
export type { InputProps, InputSize, InputVariant, DesignType } from './Input.types';
|
|
3
3
|
declare function Input({ type, // input HTML 타입
|
|
4
4
|
designType, // 인풋 외형 타입
|
|
5
5
|
size, // 인풋 높이 크기
|
|
@@ -3,7 +3,7 @@ import type { CSSProperties, HTMLInputTypeAttribute, InputHTMLAttributes, ReactN
|
|
|
3
3
|
* Input 컨테이너의 시각 스타일 타입.
|
|
4
4
|
* @defaultValue `'outline'`
|
|
5
5
|
*/
|
|
6
|
-
export type
|
|
6
|
+
export type DesignType = 'outline' | 'fill';
|
|
7
7
|
/**
|
|
8
8
|
* Input 높이 타입.
|
|
9
9
|
* @defaultValue `'default'`
|
|
@@ -31,7 +31,7 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
|
|
|
31
31
|
* Input 컨테이너 외형 타입.
|
|
32
32
|
* @defaultValue `'outline'`
|
|
33
33
|
*/
|
|
34
|
-
designType?:
|
|
34
|
+
designType?: DesignType;
|
|
35
35
|
/**
|
|
36
36
|
* Input 높이.
|
|
37
37
|
* - `default`: 44px
|
|
@@ -41,7 +41,8 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
|
|
|
41
41
|
size?: InputSize;
|
|
42
42
|
/**
|
|
43
43
|
* Input 상태 variant.
|
|
44
|
-
* 미지정 시
|
|
44
|
+
* 미지정 시 값 존재 여부에 따라 `basic`/`typed`를 자동 계산한다.
|
|
45
|
+
* 포커스 시각 상태는 CSS interaction으로 처리한다.
|
|
45
46
|
*/
|
|
46
47
|
variant?: InputVariant;
|
|
47
48
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ChangeEvent, FocusEvent } from 'react';
|
|
2
2
|
import type { InputProps } from './Input.types';
|
|
3
3
|
interface UseInputStateParams {
|
|
4
4
|
value: InputProps['value'];
|
|
@@ -8,8 +8,6 @@ interface UseInputStateParams {
|
|
|
8
8
|
}
|
|
9
9
|
export interface UseInputStateResult {
|
|
10
10
|
currentValue: InputProps['value'];
|
|
11
|
-
isFocused: boolean;
|
|
12
|
-
isTyping: boolean;
|
|
13
11
|
handleFocus: (event: FocusEvent<HTMLInputElement>) => void;
|
|
14
12
|
handleBlur: (event: FocusEvent<HTMLInputElement>) => void;
|
|
15
13
|
handleChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import type { InputProps, InputSize } from '../Input/Input';
|
|
2
2
|
export type SearchBarSize = InputSize;
|
|
3
|
-
export
|
|
3
|
+
export type SearchBarVariant = 'default' | 'onTyping' | 'typed' | 'error';
|
|
4
|
+
export interface SearchBarProps extends Omit<InputProps, 'type' | 'value' | 'onChange' | 'variant'> {
|
|
4
5
|
value: string;
|
|
5
6
|
onChange: NonNullable<InputProps['onChange']>;
|
|
6
7
|
onSearch: (value: string) => void;
|
|
8
|
+
onClear?: () => void;
|
|
9
|
+
variant?: SearchBarVariant;
|
|
7
10
|
}
|
|
8
11
|
declare function SearchBar({ value, // 검색어 값
|
|
9
12
|
onChange, // 입력 변경 핸들러
|
|
10
13
|
onSearch, // 검색 실행 핸들러
|
|
14
|
+
onClear, // 입력내용 전체 삭제 핸들러(미전달 시 기본 삭제 동작)
|
|
11
15
|
size, // 인풋 크기
|
|
12
16
|
width, // 컴포넌트 너비
|
|
13
17
|
designType, // 인풋 외형 타입
|
|
14
18
|
heading, // 라벨 표시 여부
|
|
15
19
|
headingContent, // 라벨 내용
|
|
16
|
-
variant, //
|
|
20
|
+
variant, // SearchBar 상태 variant
|
|
17
21
|
description, // 하단 안내 문구
|
|
18
22
|
fixedDescriptionHeight, // 하단 문구 영역 높이 고정 여부
|
|
19
23
|
disabled, // 전체 비활성화 여부
|
|
@@ -22,6 +26,7 @@ id, // input id
|
|
|
22
26
|
name, // input name
|
|
23
27
|
placeholder, // placeholder 텍스트
|
|
24
28
|
leadingIcon, // 좌측 아이콘 슬롯
|
|
29
|
+
trailingContent, // 우측 trailing 콘텐츠(미지정 시 검색 버튼 사용)
|
|
25
30
|
maxLength, // 최대 입력 길이
|
|
26
31
|
required, // 필수 입력 여부
|
|
27
32
|
errorMessage, // 에러 상태 문구
|
package/dist/index.d.ts
CHANGED
|
@@ -16,9 +16,9 @@ export { default as WeakButton } from './components/Button/Weak/WeakButton';
|
|
|
16
16
|
export type { BasicIconButtonProps, BasicIconButtonSize } from './components/Button/BasicIcon/BasicIconButton';
|
|
17
17
|
export type { FillButtonProps, FillButtonSize, FillButtonVariant, FillButtonWidthType } from './components/Button/Fill/FillButton';
|
|
18
18
|
export type { FillIconButtonProps, FillIconButtonSize, FillIconButtonVariant } from './components/Button/FillIcon/FillIconButton';
|
|
19
|
-
export type { InputProps, InputSize,
|
|
19
|
+
export type { InputProps, InputSize, DesignType, InputVariant } from './components/Input/Input';
|
|
20
20
|
export type { PushBadgeProps, PushBadgeVariant } from './components/PushBadge/PushBadge';
|
|
21
|
-
export type { SearchBarProps, SearchBarSize } from './components/SearchBar/SearchBar';
|
|
21
|
+
export type { SearchBarProps, SearchBarSize, SearchBarVariant } from './components/SearchBar/SearchBar';
|
|
22
22
|
export type { SnackbarShowOptions, SnackbarVariant } from './components/Snackbar/Snackbar';
|
|
23
23
|
export type { ClipProps, CustomSpinnerProps, FadeSpinnerProps } from './components/Spinner/Spinner';
|
|
24
24
|
export type { ToastShowOptions, ToastVariant } from './components/Toast/Toast';
|