@idbrnd/design-system 3.1.0 → 3.3.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @idbrnd/design-system
2
2
 
3
- ![Version](https://img.shields.io/badge/version-3.1.0-4B5FE1?style=flat-square)
3
+ ![Version](https://img.shields.io/badge/version-3.3.0-4B5FE1?style=flat-square)
4
4
  ![React](https://img.shields.io/badge/React-18.3.1-61DAFB?style=flat-square&logo=react&logoColor=white)
5
5
  ![Vite](https://img.shields.io/badge/Vite-7.3.0-646CFF?style=flat-square&logo=vite&logoColor=white)
6
6
  ![TypeScript](https://img.shields.io/badge/TypeScript-5.9.3-3178C6?style=flat-square&logo=typescript&logoColor=white)
@@ -40,6 +40,7 @@ export default function App() {
40
40
  - [OutlineButton](#outlinebutton)
41
41
  - [TextButton](#textbutton)
42
42
  - [WeakButton](#weakbutton)
43
+ - [TertiaryButton](#tertiarybutton)
43
44
  - [아이콘 버튼](#아이콘-버튼)
44
45
  - [BasicIconButton](#basiciconbutton)
45
46
  - [FillIconButton](#filliconbutton)
@@ -47,6 +48,7 @@ export default function App() {
47
48
  - [입력](#입력)
48
49
  - [Input](#input)
49
50
  - [SearchBar](#searchbar)
51
+ - [Textarea](#textarea)
50
52
  - [컨트롤](#컨트롤)
51
53
  - [CheckBox](#checkbox)
52
54
  - [Radio](#radio)
@@ -55,6 +57,7 @@ export default function App() {
55
57
  - [Toast](#toast)
56
58
  - [Snackbar](#snackbar)
57
59
  - [PushBadge](#pushbadge)
60
+ - [EmptyState](#emptystate)
58
61
  - [Tooltip](#tooltip)
59
62
  - [Select](#select)
60
63
  - [Dropdown](#dropdown)
@@ -160,6 +163,35 @@ import { WeakButton } from "@idbrnd/design-system";
160
163
  | `keepFocusOnClick` | `boolean` | `false` | 클릭 후 포커스 유지 |
161
164
  | `customStyle` | `CSSProperties` | — | 추가 인라인 스타일 |
162
165
 
166
+ ### TertiaryButton
167
+
168
+ 아이콘 슬롯을 갖는 보조 버튼입니다. 다른 버튼과 달리 `widthType`이 없고, `leadingIcon` / `trailingIcon`으로 텍스트 앞뒤에 아이콘을 배치할 수 있습니다.
169
+
170
+ ```tsx
171
+ import { TertiaryButton } from "@idbrnd/design-system";
172
+ import { ChevronDownIcon, PlusIcon } from "@idbrnd/design-system";
173
+
174
+ <TertiaryButton variant="fill">확인</TertiaryButton>
175
+ <TertiaryButton variant="primary" leadingIcon={<PlusIcon size={16} />}>추가</TertiaryButton>
176
+ <TertiaryButton variant="gray" size="small" trailingIcon={<ChevronDownIcon size={16} />}>더보기</TertiaryButton>
177
+ ```
178
+
179
+ | Prop | 타입 | 기본값 | 설명 |
180
+ | ------------------ | ----------------------------------------------------- | ---------- | ------------------- |
181
+ | `variant` | `"fill"` \| `"tinted"` \| `"gray"` \| `"primary"` | `"fill"` | 색상 변형 |
182
+ | `size` | `"small"` \| `"medium"` \| `"large"` | `"medium"` | 크기 |
183
+ | `leadingIcon` | `ReactNode` | — | 텍스트 앞 아이콘 |
184
+ | `trailingIcon` | `ReactNode` | — | 텍스트 뒤 아이콘 |
185
+ | `loading` | `boolean` | `false` | 로딩 스피너 표시 |
186
+ | `disabled` | `boolean` | `false` | 비활성화 |
187
+ | `keepFocusOnClick` | `boolean` | `false` | 클릭 후 포커스 유지 |
188
+ | `customStyle` | `CSSProperties` | — | 추가 인라인 스타일 |
189
+
190
+ 유의사항:
191
+
192
+ - `loading` 중에는 아이콘과 children 대신 스피너만 표시되며 클릭이 동작하지 않습니다.
193
+ - 다른 버튼들과 달리 `widthType`이 없어 항상 콘텐츠 크기를 따릅니다.
194
+
163
195
  ---
164
196
 
165
197
  ## 아이콘 버튼
@@ -348,6 +380,82 @@ function SearchExample() {
348
380
  - `description`, `fixedDescriptionHeight` 등 나머지 보조 속성은 `Input`과 동일하게 사용할 수 있습니다.
349
381
  - helper 문구를 일부 케이스에서만 줄바꿈하고 싶다면 `errorMessage` 또는 `description`에 래퍼 노드를 넘겨 `maxWidth`나 `<br />`를 적용하면 됩니다.
350
382
 
383
+ ### Textarea
384
+
385
+ 두 줄 이상의 긴 텍스트를 입력받는 controlled 컴포넌트입니다. 한 줄 입력에는 [Input](#input)을 사용하세요.
386
+
387
+ 높이는 `size`와 `minRows`로 결정되며 내용이 길어져도 늘어나지 않습니다. 넘치는 내용은 입력 영역 내부에서 스크롤됩니다.
388
+
389
+ ```tsx
390
+ import { useState } from "react";
391
+ import { Textarea, TextButton, OutlineButton } from "@idbrnd/design-system";
392
+
393
+ function TextareaExample() {
394
+ const [content, setContent] = useState("");
395
+
396
+ return (
397
+ <Textarea
398
+ headingContent="문의 내용"
399
+ required
400
+ value={content}
401
+ onChange={(e) => setContent(e.target.value)}
402
+ description="접수 후 영업일 기준 2일 내에 답변드립니다."
403
+ bottom
404
+ leadingContent
405
+ maxLength={500}
406
+ trailingContent={
407
+ <>
408
+ <TextButton size="medium" variant="assistive">
409
+ 취소
410
+ </TextButton>
411
+ <OutlineButton size="xsmall" variant="secondary">
412
+ 등록
413
+ </OutlineButton>
414
+ </>
415
+ }
416
+ />
417
+ );
418
+ }
419
+ ```
420
+
421
+ | Prop | 타입 | 기본값 | 설명 |
422
+ | ----------------- | ------------------------------------------------------------------- | --------------------- | ---------------------------------------------------------------- |
423
+ | `designType` | `"outline"` \| `"fill"` | `"outline"` | 입력 영역 외형 |
424
+ | `size` | `"default"` \| `"large"` | `"default"` | 텍스트 크기와 컨테이너 높이 (108px / 112px) |
425
+ | `variant` | `"basic"` \| `"onFocus"` \| `"typed"` \| `"error"` \| `"success"` | 자동 계산 | 수동 상태 지정. `errorMessage`가 있으면 `error`가 우선 적용 |
426
+ | `minRows` | `number` | `2` | 노출할 줄 수 = 고정 높이. 넘치면 내부 스크롤 |
427
+ | `width` | `number \| string` | `"100%"` | 루트 너비 |
428
+ | `value` | `string` | — | **(필수)** 입력값 |
429
+ | `onChange` | `ChangeEventHandler<HTMLTextAreaElement>` | — | 값 변경 핸들러 |
430
+ | `heading` | `boolean` | `true` | 상단 라벨 표시 여부 |
431
+ | `headingContent` | `ReactNode` | `"Label"` | 상단 라벨 내용 |
432
+ | `required` | `boolean` | `false` | 필수 입력 표시 및 native `required` 속성 적용 |
433
+ | `description` | `ReactNode \| boolean` | `false` | 하단 안내 문구. `true`면 기본 안내 문구를 사용 |
434
+ | `errorMessage` | `ReactNode` | 기본 에러 문구 | 의미 있는 값이 전달되면 에러 상태가 자동 적용되고 해당 문구 표시 |
435
+ | `successMessage` | `ReactNode` | — | `variant="success"`일 때만 노출 |
436
+ | `bottom` | `boolean` | `false` | 입력 영역 내부 하단 영역(글자 수 · 보조 액션) 노출 여부 |
437
+ | `leadingContent` | `boolean` | `false` | 하단 좌측 글자 수 카운터 **상시** 노출 여부 |
438
+ | `maxLength` | `number` | `100` 또는 `1500` | 최대 입력 글자 수. 기본값은 `leadingContent`에 따라 달라짐 |
439
+ | `trailingContent` | `ReactNode` | — | 하단 우측 보조 액션. 전달한 노드를 그대로 렌더링 |
440
+ | `placeholder` | `string` | `"텍스트를 입력해 주세요."` | 플레이스홀더 |
441
+ | `readOnly` | `boolean` | `false` | 읽기 전용 |
442
+ | `disabled` | `boolean` | `false` | 비활성화 |
443
+ | `customStyle` | `CSSProperties` | `{}` | 루트 컨테이너에 적용할 추가 인라인 스타일 |
444
+
445
+ 유의사항:
446
+
447
+ - `defaultValue`는 지원하지 않습니다. 반드시 `value` + `onChange`로 제어해야 합니다.
448
+ - 컨테이너 높이는 `size`가 결정합니다(`default` 108px / `large` 112px). `trailingContent`나 카운터 유무로 높이가 달라지지 않습니다.
449
+ - 카운터와 보조 액션은 `bottom={true}`일 때만 노출됩니다. `bottom={false}`면 하단 영역 자체가 없습니다.
450
+ - **`leadingContent={false}`여도 한도까지 100자 이하로 남으면 카운터가 자동으로 나타납니다.** 곧 입력이 막힌다는 것을 사용자가 미리 알 수 있게 하기 위한 동작이며, 기본값 기준 1400자부터 `1400/1500`이 표시됩니다.
451
+ - `maxLength`를 지정하지 않으면 `leadingContent={true}`일 때 `100`, `false`일 때 `1500`이 적용됩니다. 즉 **입력 길이 제한은 항상 걸립니다.**
452
+ - `trailingContent`는 전달한 노드를 그대로 렌더링합니다. 버튼을 하나 넘기면 하나만, 둘 넘기면 둘 다 노출됩니다. 버튼이 두 개일 때는 위계가 높은 버튼을 우측에 둡니다.
453
+ - 하단 영역은 높이 32px을 차지합니다. 보조 액션 버튼은 이 높이에 맞춰 `TextButton size="medium"`, `OutlineButton size="xsmall"` 등을 사용하세요.
454
+ - `errorMessage`·`description`의 빈 문자열, 공백 문자열, 내용 없는 JSX 래퍼는 문구가 없는 것으로 처리합니다. 노출할 문구가 없으면 문구 영역 자체를 렌더링하지 않습니다.
455
+ - `variant="error"`면 적색 보더와 아이콘이, `variant="success"`면 녹색 체크 아이콘이 함께 표시됩니다.
456
+ - 사용자가 모서리를 드래그해 크기를 바꾸는 native resize는 비활성화되어 있습니다.
457
+ - `id`, `name`, `onFocus`, `onBlur`, `autoFocus` 등 대부분의 native `<textarea>` props도 함께 사용할 수 있습니다.
458
+
351
459
  ---
352
460
 
353
461
  ## 컨트롤
@@ -568,6 +676,64 @@ import { PushBadge } from "@idbrnd/design-system";
568
676
  | `maxCount` | `number` | `999` | `count`가 초과하면 `{maxCount}+`로 표시 |
569
677
  | `customStyle` | `CSSProperties` | — | 추가 인라인 스타일 |
570
678
 
679
+ ### EmptyState
680
+
681
+ 사용자가 특정 페이지에 처음 접속했을 때나 표시할 수 있는 데이터가 없을 때 노출하는 컴포넌트입니다.
682
+
683
+ ```tsx
684
+ import { EmptyState, FillButton } from "@idbrnd/design-system";
685
+ import { FolderIcon } from "@idbrnd/design-system";
686
+
687
+ <EmptyState
688
+ size="medium"
689
+ visualContent={<FolderIcon size={36} />}
690
+ headingContent="등록된 프로젝트가 없습니다."
691
+ descriptionContent={"첫 번째 프로젝트를 생성하고\n모니터링을 시작해 보세요."}
692
+ buttonContent={
693
+ <FillButton variant="primary" size="xsmall">
694
+ 프로젝트 생성
695
+ </FillButton>
696
+ }
697
+ />;
698
+ ```
699
+
700
+ **텍스트만 사용 (위젯·테이블 내부)**
701
+
702
+ ```tsx
703
+ <EmptyState
704
+ size="small"
705
+ headingContent="검색 결과가 없습니다."
706
+ descriptionContent="다른 키워드로 다시 검색해 보세요."
707
+ />
708
+ ```
709
+
710
+ | Prop | 타입 | 기본값 | 설명 |
711
+ | -------------------- | -------------------------------------- | --------- | --------------------------------------------------------------- |
712
+ | `size` | `"large"` \| `"medium"` \| `"small"` | `"small"` | 배치 구역의 크기·위계에 따른 사이즈 |
713
+ | `visualContent` | `ReactNode` | — | 상단 시각 요소. 일러스트·아이콘·이미지·임의 컴포넌트 모두 가능 |
714
+ | `headingContent` | `ReactNode` | — | 타이틀. 상황을 짧게 요약하며 단일 행 권장 |
715
+ | `descriptionContent` | `ReactNode` | — | 설명. 개행(`\n`)이 그대로 반영되며 줄 수 제한 없음 |
716
+ | `buttonContent` | `ReactNode` | — | CTA 버튼 슬롯 |
717
+ | `customStyle` | `CSSProperties` | — | 루트에 적용할 추가 인라인 스타일 |
718
+ | `className` | `string` | — | 루트에 추가할 클래스명 |
719
+
720
+ **size별 스펙**
721
+
722
+ | | `large` | `medium` | `small` |
723
+ | ---------------- | -------------------------------- | -------------------------------- | --------------------------------- |
724
+ | 시각 요소 슬롯 | 80×80 | 48×48 | 32×32 |
725
+ | 타이틀 | `--text-heading-2-semibold` | `--text-heading-2-semibold` | `--text-body-2-normal-semibold` |
726
+ | 설명 | `--text-body-1-reading-regular` | `--text-body-1-reading-regular` | `--text-label-2-reading-regular` |
727
+ | 권장 버튼 | `FillButton` `assistive`/`small` | `FillButton` `assistive`/`xsmall`| `FillButton` `assistive`/`xsmall` |
728
+
729
+ 유의사항:
730
+
731
+ - **네 슬롯 모두 넘긴 것만 렌더됩니다.** 넘기지 않으면 해당 영역과 인접 간격이 함께 사라지므로, 화면 상황에 맞게 가볍거나 묵직하게 조합할 수 있습니다.
732
+ - 루트는 부모를 채우고(`width`/`height: 100%`) 콘텐츠를 중앙 정렬합니다. 상하 여백은 80px입니다.
733
+ - 전체 화면 단위에는 `size="large"` 또는 `"medium"`에 시각 요소와 버튼을 함께 두어 액션을 유도하고, 카드·테이블 내부에는 `size="small"`로 컴팩트하게 노출하는 것을 권장합니다.
734
+ - 텍스트는 `[상황 설명 + 해결책 제안]` 구조로 작성합니다. 설명은 두 줄 이내를 권장하지만 강제되지는 않습니다.
735
+ - `visualContent`에 넣은 노드는 슬롯 크기에 맞춰 `max-width`/`max-height: 100%`가 적용됩니다.
736
+
571
737
  ### Tooltip
572
738
 
573
739
  트리거 엘리먼트에 마우스를 올리거나 클릭하면 말풍선 형태의 안내 텍스트를 표시하는 컴포넌트입니다. `trigger="always"`로 항상 표시되는 고정 안내 형태로도 사용할 수 있습니다.
@@ -1864,6 +2030,9 @@ import type {
1864
2030
  WeakButtonSize,
1865
2031
  WeakButtonVariant,
1866
2032
  WeakButtonWidthType,
2033
+ TertiaryButtonProps,
2034
+ TertiaryButtonSize,
2035
+ TertiaryButtonVariant,
1867
2036
 
1868
2037
  // IconButton
1869
2038
  BasicIconButtonProps,
@@ -1884,6 +2053,11 @@ import type {
1884
2053
  SearchBarSize,
1885
2054
  SearchBarVariant,
1886
2055
 
2056
+ // Textarea
2057
+ TextareaProps,
2058
+ TextareaSize,
2059
+ TextareaVariant,
2060
+
1887
2061
  // Control
1888
2062
  CheckBoxProps,
1889
2063
  CheckBoxVariant,
@@ -1903,6 +2077,8 @@ import type {
1903
2077
  SnackbarVariant,
1904
2078
  PushBadgeProps,
1905
2079
  PushBadgeVariant,
2080
+ EmptyStateProps,
2081
+ EmptyStateSize,
1906
2082
  ClipProps,
1907
2083
  CustomSpinnerProps,
1908
2084
  FadeSpinnerProps,
@@ -1938,6 +2114,17 @@ import type {
1938
2114
  DropdownType,
1939
2115
  DropdownAlign,
1940
2116
 
2117
+ // Chip
2118
+ ChipProps,
2119
+ ChipVariant,
2120
+ ChipSize,
2121
+ ChipGroupProps,
2122
+ ChipGroupType,
2123
+ ChipGroupSize,
2124
+ FilterChipProps,
2125
+ FilterBarProps,
2126
+ FilterBarSize,
2127
+
1941
2128
  // SegmentedControl
1942
2129
  SegmentedControlProps,
1943
2130
  SegmentedControlVariant,
@@ -0,0 +1,30 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ export type EmptyStateSize = 'large' | 'medium' | 'small';
3
+ export interface EmptyStateProps {
4
+ /** 배치 구역의 크기·위계에 따른 사이즈 */
5
+ size?: EmptyStateSize;
6
+ /**
7
+ * 상단 시각 요소 슬롯. 일러스트·아이콘·이미지·임의의 컴포넌트를 모두 받는다.
8
+ * 넘기지 않으면 영역 자체를 렌더하지 않는다.
9
+ */
10
+ visualContent?: ReactNode;
11
+ /**
12
+ * 타이틀. 상황을 짧게 요약하며 단일 행을 권장한다.
13
+ * 넘기지 않으면 영역 자체를 렌더하지 않는다.
14
+ */
15
+ headingContent?: ReactNode;
16
+ /**
17
+ * 설명. 개행(`\n`)이 그대로 반영되며, 줄 수는 제한하지 않는다 (가이드상 두 줄 권장).
18
+ * 넘기지 않으면 영역 자체를 렌더하지 않는다.
19
+ */
20
+ descriptionContent?: ReactNode;
21
+ /**
22
+ * CTA 버튼 슬롯. 소비처가 원하는 버튼 컴포넌트를 직접 넣는다.
23
+ * 넘기지 않으면 영역 자체를 렌더하지 않는다.
24
+ */
25
+ buttonContent?: ReactNode;
26
+ customStyle?: CSSProperties;
27
+ className?: string;
28
+ }
29
+ declare function EmptyState({ size, visualContent, headingContent, descriptionContent, buttonContent, customStyle, className }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
30
+ export default EmptyState;
@@ -0,0 +1,21 @@
1
+ import type { TextareaProps } from './Textarea.types';
2
+ export type { TextareaProps, TextareaSize, TextareaVariant, DesignType } from './Textarea.types';
3
+ declare function Textarea({ designType, // 입력 영역 외형 타입
4
+ size, // 텍스트 크기
5
+ variant, // 상태 variant
6
+ minRows, // 노출할 줄 수 (고정 높이)
7
+ width, // 루트 너비
8
+ value, // 현재 값
9
+ heading, // 라벨 표시 여부
10
+ headingContent, // 라벨 내용
11
+ required, // 라벨 우측 *
12
+ description, // 하단 안내 문구
13
+ errorMessage, // 에러 상태 문구
14
+ successMessage, // 성공 상태 문구
15
+ bottom, // 입력 영역 내부 하단 영역 표시 여부
16
+ leadingContent, // 하단 좌측 글자 수 카운터 표시 여부
17
+ maxLength, // 최대 입력 글자 수 (카운터 분모)
18
+ trailingContent, // 하단 우측 슬롯
19
+ customStyle, // 루트 커스텀 스타일
20
+ placeholder, disabled, readOnly, id, ...rest }: TextareaProps): import("react/jsx-runtime").JSX.Element;
21
+ export default Textarea;
@@ -0,0 +1,133 @@
1
+ import type { CSSProperties, ReactNode, TextareaHTMLAttributes } from 'react';
2
+ import type { DesignType } from '../Input/Input.types';
3
+ export type { DesignType };
4
+ /**
5
+ * Textarea 높이·텍스트 크기 타입.
6
+ * @defaultValue `'default'`
7
+ */
8
+ export type TextareaSize = 'default' | 'large';
9
+ /**
10
+ * Textarea 상태 variant 타입.
11
+ * - `basic`: 기본 상태
12
+ * - `onFocus`: 포커스 진입 상태(보더 강조)
13
+ * - `typed`: 값이 입력된 상태
14
+ * - `error`: 유효성 오류 상태
15
+ * - `success`: 유효성 통과 상태
16
+ */
17
+ export type TextareaVariant = 'basic' | 'onFocus' | 'typed' | 'error' | 'success';
18
+ /** `Textarea` 컴포넌트 public props. */
19
+ export interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'style' | 'className' | 'cols' | 'rows' | 'required' | 'defaultValue' | 'value'> {
20
+ /**
21
+ * 입력 영역 외형 타입.
22
+ * - `outline`: 테두리로 영역 구분
23
+ * - `fill`: 배경 채움 + 테두리로 영역 구분
24
+ * @defaultValue `'outline'`
25
+ */
26
+ designType?: DesignType;
27
+ /**
28
+ * 입력 영역 텍스트 크기.
29
+ * - `default`: 14px
30
+ * - `large`: 16px
31
+ * @defaultValue `'default'`
32
+ */
33
+ size?: TextareaSize;
34
+ /**
35
+ * 상태 variant.
36
+ * `errorMessage`가 있으면 `error`가 우선 적용된다.
37
+ * 미지정 시 값 존재 여부에 따라 `basic`/`typed`를 자동 계산한다.
38
+ * 실제 포커스 시각 상태는 CSS `:focus-within`으로 처리하므로,
39
+ * `onFocus`는 포커스 상태를 강제로 보여줘야 할 때만 사용한다.
40
+ */
41
+ variant?: TextareaVariant;
42
+ /**
43
+ * 입력 영역에 노출할 줄 수.
44
+ * 이 값이 곧 고정 높이가 되며, 내용이 넘치면 내부 스크롤로 처리한다.
45
+ * Text Field와 구분하기 위해 2줄 미만은 권장하지 않는다.
46
+ * @defaultValue `2`
47
+ */
48
+ minRows?: number;
49
+ /**
50
+ * 루트 너비.
51
+ * 미지정 시 `100%`가 적용된다.
52
+ */
53
+ width?: number | string;
54
+ /**
55
+ * Textarea 값.
56
+ * 이 컴포넌트는 controlled 방식만 지원하므로 필수로 전달해야 한다.
57
+ */
58
+ value: string;
59
+ /**
60
+ * 상단 heading(라벨) 표시 여부.
61
+ * @defaultValue `true`
62
+ */
63
+ heading?: boolean;
64
+ /**
65
+ * 상단 heading(라벨) 텍스트/노드.
66
+ * @defaultValue `'Label'`
67
+ */
68
+ headingContent?: ReactNode;
69
+ /**
70
+ * 필수 입력 여부.
71
+ * `true`면 textarea의 `required` 속성을 적용하고, heading 노출 시 `*`를 함께 표시한다.
72
+ * @defaultValue `false`
73
+ */
74
+ required?: boolean;
75
+ /**
76
+ * 하단 안내 문구
77
+ * - `false`: 안내 문구 없음
78
+ * - `true`: 기본 안내 문구 사용
79
+ * - `ReactNode`: 커스텀 안내 문구 사용
80
+ *
81
+ * 주의: `error`/`success` 상태에서는 `errorMessage`/`successMessage`가 우선 노출된다.
82
+ * 노출할 문구가 없으면 문구 영역(`<p>`) 자체를 렌더링하지 않는다.
83
+ * @defaultValue `false`
84
+ */
85
+ description?: ReactNode | boolean;
86
+ /**
87
+ * 에러 문구.
88
+ * 전달되면 `variant` 지정 여부와 관계없이 `error` 상태가 우선 적용된다.
89
+ * 빈 문자열, 공백 문자열, 내용 없는 JSX 래퍼는 에러 문구로 간주하지 않는다.
90
+ */
91
+ errorMessage?: ReactNode;
92
+ /**
93
+ * 성공 문구.
94
+ * `variant === 'success'`일 때만 노출되며, 상태를 바꾸지는 않는다.
95
+ * (성공 판정 시점은 소비처의 유효성 검사 결과에 맡긴다)
96
+ */
97
+ successMessage?: ReactNode;
98
+ /**
99
+ * 입력 영역 내부 하단 영역(글자 수 · 보조 액션) 노출 여부.
100
+ * @defaultValue `false`
101
+ */
102
+ bottom?: boolean;
103
+ /**
104
+ * 하단 영역 좌측 글자 수 카운터(`현재/최대`)를 **상시** 노출할지 여부.
105
+ * (피그마 `Leading Content`에 대응)
106
+ *
107
+ * `false`여도 한도까지 남은 글자 수가 100자 이하가 되면 카운터가 나타난다.
108
+ * 곧 입력이 막힌다는 것을 사용자가 미리 인지할 수 있게 하기 위함이다.
109
+ * (기본값 기준 1400자부터 `1400/1500`)
110
+ *
111
+ * 주의:
112
+ * - `bottom`이 `false`면 하단 영역 자체가 없으므로 표시되지 않는다.
113
+ * - 분모가 필요하므로 `maxLength`가 항상 적용된다. 즉 입력 길이 제한이 늘 걸린다.
114
+ * @defaultValue `false`
115
+ */
116
+ leadingContent?: boolean;
117
+ /**
118
+ * 최대 입력 글자 수. (textarea 네이티브 속성)
119
+ * 도달하면 추가 입력이 차단되고, 카운터가 노출될 때 분모로 표시된다.
120
+ *
121
+ * 미지정 시 기본값은 `leadingContent`에 따라 달라진다.
122
+ * - `true`: `100` (짧은 입력을 전제)
123
+ * - `false`: `1500` (긴 글 입력을 전제)
124
+ */
125
+ maxLength?: number;
126
+ /**
127
+ * 하단 영역 우측 콘텐츠(보조 액션 버튼 등).
128
+ * 버튼이 두 개일 경우 위계가 높은 버튼을 우측에 둔다.
129
+ */
130
+ trailingContent?: ReactNode;
131
+ /** 루트 컨테이너에 적용할 추가 style */
132
+ customStyle?: CSSProperties;
133
+ }
package/dist/index.d.ts CHANGED
@@ -20,16 +20,20 @@ export { default as Input } from "./components/Input/Input";
20
20
  export { default as SearchBar } from "./components/SearchBar/SearchBar";
21
21
  export type { InputProps, InputSize, DesignType, InputVariant, } from "./components/Input/Input";
22
22
  export type { SearchBarProps, SearchBarSize, SearchBarVariant, } from "./components/SearchBar/SearchBar";
23
+ export { default as Textarea } from "./components/Textarea/Textarea";
24
+ export type { TextareaProps, TextareaSize, TextareaVariant, } from "./components/Textarea/Textarea";
23
25
  export { default as CheckBox } from "./components/Control/CheckBox/CheckBox";
24
26
  export { default as Radio } from "./components/Control/Radio/Radio";
25
27
  export { default as ToggleSwitch } from "./components/Control/ToggleSwitch/ToggleSwitch";
26
28
  export type { CheckBoxProps, CheckBoxVariant, CheckBoxSize, CheckBoxDensity, } from "./components/Control/CheckBox/CheckBox";
27
29
  export type { RadioProps, RadioVariant, RadioSize, RadioDensity, } from "./components/Control/Radio/Radio";
28
30
  export type { ToggleSwitchProps, ToggleSwitchSize, } from "./components/Control/ToggleSwitch/ToggleSwitch";
31
+ export { default as EmptyState } from "./components/Feedback/EmptyState/EmptyState";
29
32
  export { default as PushBadge } from "./components/Feedback/PushBadge/PushBadge";
30
33
  export { dismissToast, showToast } from "./components/Feedback/Toast/Toast";
31
34
  export { dismissSnackbar, showSnackbar, } from "./components/Feedback/Snackbar/Snackbar";
32
35
  export { default as Spinner, Clip, CustomSpinner, FadeSpinner, } from "./components/Spinner/Spinner";
36
+ export type { EmptyStateProps, EmptyStateSize, } from "./components/Feedback/EmptyState/EmptyState";
33
37
  export type { PushBadgeProps, PushBadgeVariant, } from "./components/Feedback/PushBadge/PushBadge";
34
38
  export type { ToastShowOptions, ToastVariant, } from "./components/Feedback/Toast/Toast";
35
39
  export type { SnackbarShowOptions, SnackbarVariant, } from "./components/Feedback/Snackbar/Snackbar";