@uniai-fe/uds-primitives 0.3.60 → 0.4.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.
Files changed (83) hide show
  1. package/README.md +209 -3
  2. package/dist/styles.css +20 -6
  3. package/package.json +7 -7
  4. package/src/components/alternate/index.tsx +7 -1
  5. package/src/components/alternate/markup/Label.tsx +10 -5
  6. package/src/components/alternate/markup/empty/Data.tsx +9 -6
  7. package/src/components/alternate/markup/index.tsx +8 -0
  8. package/src/components/alternate/markup/loading/Default.tsx +10 -6
  9. package/src/components/alternate/markup/loading/Icon.tsx +11 -4
  10. package/src/components/alternate/types/index.ts +75 -2
  11. package/src/components/badge/index.tsx +4 -1
  12. package/src/components/badge/markup/Badge.tsx +10 -8
  13. package/src/components/badge/types/index.ts +26 -2
  14. package/src/components/button/index.tsx +6 -1
  15. package/src/components/button/markup/Base.tsx +20 -18
  16. package/src/components/button/markup/Rounded.tsx +7 -4
  17. package/src/components/button/markup/Text.tsx +7 -4
  18. package/src/components/calendar/index.tsx +8 -0
  19. package/src/components/calendar/markup/index.tsx +7 -7
  20. package/src/components/carousel/index.tsx +8 -0
  21. package/src/components/carousel/markup/index.tsx +9 -0
  22. package/src/components/checkbox/index.tsx +7 -0
  23. package/src/components/chip/index.tsx +7 -1
  24. package/src/components/chip/markup/index.tsx +9 -0
  25. package/src/components/divider/index.tsx +4 -0
  26. package/src/components/divider/markup/Divider.tsx +11 -7
  27. package/src/components/divider/types/index.ts +1 -0
  28. package/src/components/divider/types/props.ts +27 -0
  29. package/src/components/drawer/index.tsx +7 -0
  30. package/src/components/drawer/markup/index.tsx +6 -0
  31. package/src/components/dropdown/index.tsx +7 -0
  32. package/src/components/dropdown/markup/Template.tsx +9 -2
  33. package/src/components/dropdown/markup/foundation/Container.tsx +30 -12
  34. package/src/components/dropdown/markup/index.tsx +9 -10
  35. package/src/components/dropdown/types/base.ts +13 -0
  36. package/src/components/dropdown/types/props.ts +19 -2
  37. package/src/components/form/index.tsx +7 -0
  38. package/src/components/form/markup/index.tsx +6 -2
  39. package/src/components/info-box/index.tsx +7 -0
  40. package/src/components/info-box/markup/InfoBox.tsx +1 -1
  41. package/src/components/info-box/markup/index.ts +6 -0
  42. package/src/components/info-box/types/props.ts +2 -2
  43. package/src/components/input/index.tsx +6 -1
  44. package/src/components/input/markup/foundation/Input.tsx +2 -2
  45. package/src/components/input/markup/foundation/Utility.tsx +1 -1
  46. package/src/components/input/types/foundation.ts +1 -1
  47. package/src/components/navigation/index.tsx +7 -0
  48. package/src/components/navigation/markup/index.tsx +6 -0
  49. package/src/components/pagination/index.tsx +6 -1
  50. package/src/components/pagination/markup/index.tsx +7 -0
  51. package/src/components/pop-over/index.tsx +7 -0
  52. package/src/components/pop-over/markup/index.tsx +5 -4
  53. package/src/components/radio/index.tsx +5 -1
  54. package/src/components/scrollbar/hooks/index.ts +1 -1
  55. package/src/components/scrollbar/index.tsx +1 -1
  56. package/src/components/scrollbar/markup/index.tsx +1 -1
  57. package/src/components/scrollbar/types/index.ts +1 -1
  58. package/src/components/scrollbar/utils/index.ts +1 -1
  59. package/src/components/segmented-control/index.tsx +5 -1
  60. package/src/components/segmented-control/markup/index.ts +6 -0
  61. package/src/components/select/index.tsx +6 -1
  62. package/src/components/select/markup/Default.tsx +10 -13
  63. package/src/components/select/markup/foundation/Selected.tsx +31 -26
  64. package/src/components/select/markup/index.tsx +1 -1
  65. package/src/components/select/markup/multiple/Multiple.tsx +32 -15
  66. package/src/components/select/styles/select.scss +15 -6
  67. package/src/components/select/styles/variables.scss +4 -0
  68. package/src/components/select/types/multiple.ts +19 -0
  69. package/src/components/select/types/props.ts +19 -6
  70. package/src/components/select/utils/display.tsx +41 -0
  71. package/src/components/select/utils/index.ts +1 -4
  72. package/src/components/slot/index.tsx +7 -0
  73. package/src/components/slot/markup/index.tsx +6 -0
  74. package/src/components/spinner/hooks/index.ts +1 -1
  75. package/src/components/spinner/index.tsx +1 -1
  76. package/src/components/spinner/markup/index.tsx +1 -1
  77. package/src/components/spinner/types/index.ts +1 -1
  78. package/src/components/spinner/utils/index.ts +1 -1
  79. package/src/components/tab/index.tsx +5 -1
  80. package/src/components/tab/markup/index.tsx +8 -0
  81. package/src/components/table/index.tsx +3 -0
  82. package/src/components/tooltip/index.tsx +7 -0
  83. package/src/components/tooltip/markup/index.tsx +7 -6
package/README.md CHANGED
@@ -47,6 +47,212 @@ export default function Page() {
47
47
  }
48
48
  ```
49
49
 
50
+ ## 제공 도구 목록
51
+
52
+ - `Alternate.EmptyData`
53
+ - `Alternate.LoadingDefault`
54
+ - `Alternate.LoadingIcon`
55
+ - `Alternate.Text`
56
+ - `AlternateEmptyDataProps`
57
+ - `AlternateLoadingDefaultProps`
58
+ - `AlternateLoadingIconProps`
59
+ - `AlternateTextProps`
60
+ - `Badge`
61
+ - `BadgeProps`
62
+ - `Chip.Default`
63
+ - `Chip.ClickableStyle`
64
+ - `Chip.InputStyle`
65
+ - `Chip.Label`
66
+ - `Chip.List`
67
+ - `ChipProps`
68
+ - `ChipListRootProps`
69
+ - `ChipListItemData`
70
+ - `Calendar.Root`
71
+ - `Calendar.Container`
72
+ - `Calendar.Header`
73
+ - `Calendar.Body`
74
+ - `Calendar.Footer`
75
+ - `Calendar.Core`
76
+ - `Calendar.Icon`
77
+ - `CalendarValue`
78
+ - `CalendarRootProps`
79
+ - `CalendarContainerProps`
80
+ - `CalendarGridProps`
81
+ - `CalendarDatePickerProps`
82
+ - `Carousel.Provider`
83
+ - `Carousel.Container`
84
+ - `Carousel.Control`
85
+ - `Carousel.Track`
86
+ - `Carousel.Button.Base`
87
+ - `Carousel.Button.Prev`
88
+ - `Carousel.Button.Next`
89
+ - `useCarousel`
90
+ - `useCarouselProviderController`
91
+ - `CarouselProviderProps`
92
+ - `CarouselTrackProps`
93
+ - `CarouselContainerProps`
94
+ - `CarouselControlProps`
95
+ - `CarouselPrevButtonProps`
96
+ - `CarouselNextButtonProps`
97
+ - `DrawerRoot`
98
+ - `DrawerTrigger`
99
+ - `DrawerPortal`
100
+ - `DrawerOverlay`
101
+ - `DrawerContent`
102
+ - `DrawerHeader`
103
+ - `DrawerBody`
104
+ - `DrawerFooter`
105
+ - `DrawerTitle`
106
+ - `DrawerDescription`
107
+ - `DrawerClose`
108
+ - `DrawerRootProps`
109
+ - `DrawerTriggerProps`
110
+ - `DrawerContentProps`
111
+ - `useDrawerDrag`
112
+ - `Form.Provider`
113
+ - `Form.Field.Container`
114
+ - `Form.Field.Header`
115
+ - `Form.Field.Body`
116
+ - `Form.Field.Footer`
117
+ - `Form.Field.Template`
118
+ - `FormFieldTemplateProps`
119
+ - `FormFieldContainerProps`
120
+ - `FormFieldHeaderProps`
121
+ - `FormFieldFooterProps`
122
+ - `FormFieldWidth`
123
+ - `FormFieldState`
124
+ - `getFormFieldWidthAttr`
125
+ - `getFormFieldWidthValue`
126
+ - `InfoBox`
127
+ - `InfoBoxIcon`
128
+ - `InfoBoxProps`
129
+ - `InfoBoxState`
130
+ - `BottomNavigation`
131
+ - `BottomNavigationProps`
132
+ - `NavigationItem`
133
+ - `NavigationItemKey`
134
+ - `NavigationHrefItem`
135
+ - `NavigationActionItem`
136
+ - `NavigationSitemapNode`
137
+ - `NavigationSitemapCollection`
138
+ - `NavigationSitemapOptions`
139
+ - `composeNavigationClassName`
140
+ - `isHrefNavigationItem`
141
+ - `Pagination`
142
+ - `PaginationCarousel`
143
+ - `PaginationCount`
144
+ - `PaginationProps`
145
+ - `PaginationCarouselProps`
146
+ - `PaginationCountProps`
147
+ - `PaginationCountSize`
148
+ - `PaginationCarouselPriority`
149
+ - `normalizePaginationState`
150
+ - `createPaginationPages`
151
+ - `composePaginationClassName`
152
+ - `Slot.Base`
153
+ - `Slot.Text`
154
+ - `SlotComponentProps`
155
+ - `SlotTextProps`
156
+ - `TabRoot`
157
+ - `TabList`
158
+ - `TabTrigger`
159
+ - `TabContent`
160
+ - `TabRootProps`
161
+ - `TabListProps`
162
+ - `TabTriggerProps`
163
+ - `TabContentProps`
164
+ - `TabVariant`
165
+ - `TabScale`
166
+ - `TabContext`
167
+ - `useTabContext`
168
+ - `SegmentedControl`
169
+ - `SegmentedControlLabel`
170
+ - `SegmentedControlProps`
171
+ - `SegmentedControlOption`
172
+ - `SegmentedControlValue`
173
+ - `Divider`
174
+ - `DividerProps`
175
+ - `DividerDirection`
176
+ - `scrollbar` (현재 public export 없음)
177
+ - `spinner` (현재 public export 없음)
178
+ - `Table.Root`
179
+ - `Table.Head`
180
+ - `Table.Body`
181
+ - `Table.Foot`
182
+ - `Table.Row`
183
+ - `Table.Th`
184
+ - `Table.Td`
185
+ - `Table.Cell`
186
+ - `Table.Text`
187
+ - `Table.Container`
188
+ - `Table.Colgroup`
189
+ - `Table.Col`
190
+ - `TableColumnData`
191
+ - `TableRootProps`
192
+ - `TableContainerProps`
193
+ - `TableCellProps`
194
+ - `Button.Default`
195
+ - `Button.Text`
196
+ - `Button.Rounded`
197
+ - `Button.Label`
198
+ - `ButtonProps`
199
+ - `TextButtonProps`
200
+ - `RoundButtonProps`
201
+ - `Input.Base`
202
+ - `Input.TextArea`
203
+ - `Input.Text.Password`
204
+ - `Input.Text.Phone`
205
+ - `Input.Text.Email`
206
+ - `Input.Text.Search`
207
+ - `Input.Text.AuthCode`
208
+ - `Input.Date.Template`
209
+ - `Input.Address.Template`
210
+ - `Input.Address.Button`
211
+ - `Input.File.UploadButton`
212
+ - `Input.File.UploadedChip`
213
+ - `Input.File.List.*`
214
+ - `useInputFile`
215
+ - `useInputFileContext`
216
+ - `Select.Default`
217
+ - `Select.Multiple`
218
+ - `Select.Container`
219
+ - `Select.Trigger.Base`
220
+ - `Select.Selected.Base`
221
+ - `Select.Selected.Multiple`
222
+ - `SelectDropdownOption`
223
+ - `SelectMultipleTag`
224
+ - `Dropdown.Root`
225
+ - `Dropdown.Trigger`
226
+ - `Dropdown.Container`
227
+ - `Dropdown.Menu.Item`
228
+ - `Dropdown.Menu.List`
229
+ - `Dropdown.Template`
230
+ - `DropdownTemplateItem`
231
+ - `DropdownTemplateChangePayload`
232
+ - `Radio`
233
+ - `RadioField`
234
+ - `RadioCard`
235
+ - `RadioCardGroup`
236
+ - `RadioProps`
237
+ - `RadioFieldProps`
238
+ - `Checkbox`
239
+ - `CheckboxField`
240
+ - `CheckboxProps`
241
+ - `CheckboxFieldProps`
242
+ - `CheckboxSize`
243
+ - `Tooltip.Root`
244
+ - `Tooltip.Trigger`
245
+ - `Tooltip.Message`
246
+ - `Tooltip.Text`
247
+ - `Tooltip.Template`
248
+ - `TooltipMessageProps`
249
+ - `PopOver.Root`
250
+ - `PopOver.Trigger`
251
+ - `PopOver.Content`
252
+ - `PopOverRootProps`
253
+ - `PopOverTriggerProps`
254
+ - `PopOverContentProps`
255
+
50
256
  ### Link/Anchor로 사용하기
51
257
 
52
258
  ```tsx
@@ -103,11 +309,11 @@ function Templates() {
103
309
  - 템플릿별 클래스를 추가로 노출한다: `.button-template-text`, `.button-template-text-size-*`, `.button-template-round`, `.button-template-round-size-*`.
104
310
  - 스토리북 `primitives/Button` Story에서 solid/outlined/텍스트/라운드 4가지 카테고리를 한 번에 확인할 수 있다.
105
311
 
106
- ### SlotComponent (폴리모픽 as 래퍼)
312
+ ### Slot (폴리모픽 as 래퍼)
107
313
 
108
- - `Button.Default`는 `SlotComponent`를 통해 `as` prop으로 전달된 요소(예: `Link`, `a`, `button`)에 공통 속성/`ref`를 안전하게 전달한다.
314
+ - `Button.Default`는 `Slot.Base`를 통해 `as` prop으로 전달된 요소(예: `Link`, `a`, `button`)에 공통 속성/`ref`를 안전하게 전달한다.
109
315
  - `SlotComponentProps<C>`는 React가 허용하는 모든 native props + `data-*` 속성을 그대로 포함하고, `as/children/className`만 재정의한다.
110
- - 필요 시 `import { SlotComponent } from "@uniai-fe/uds-primitives";`로 직접 사용해 카드/배너 등의 래퍼를 구현할 수 있다.
316
+ - 필요 시 `import { Slot } from "@uniai-fe/uds-primitives";` 후 `Slot.Base`, `Slot.Text`를 직접 사용해 카드/배너 래퍼나 텍스트 슬롯을 구현할 수 있다.
111
317
  - 자세한 도입 배경과 API는 `docs/CONTEXT-SLOT.md`에서 확인할 수 있다.
112
318
 
113
319
  ### 최근 업데이트
package/dist/styles.css CHANGED
@@ -614,6 +614,8 @@
614
614
  --select-secondary-color-text-readonly: var(
615
615
  --select-primary-color-text-readonly
616
616
  );
617
+ --select-secondary-color-border-disabled: var(--color-label-disabled);
618
+ --select-secondary-color-border-readonly: transparent;
617
619
  --select-secondary-color-placeholder: var(--color-label-alternative);
618
620
  --select-secondary-color-placeholder-disabled: var(--color-label-disabled);
619
621
  --select-secondary-color-placeholder-readonly: var(
@@ -623,9 +625,11 @@
623
625
  --select-color-surface-secondary-hover: var(--color-surface-static-cool-gray);
624
626
  --select-color-surface-secondary-active: var(--color-surface-standard);
625
627
  --select-color-surface-secondary-disabled: var(--color-surface-neutral);
628
+ --select-color-surface-secondary-readonly: transparent;
626
629
  --select-icon-color-default: var(--color-cool-gray-75);
627
630
  --select-icon-color-focused: var(--color-cool-gray-20);
628
631
  --select-icon-color-disabled: var(--color-cool-gray-85);
632
+ --select-icon-color-readonly: transparent;
629
633
  /* Multi select chip */
630
634
  --select-multiple-chip-gap: var(--spacing-gap-2);
631
635
  --select-multiple-tag-label-gap: var(--spacing-gap-1);
@@ -3872,7 +3876,11 @@ figure.chip {
3872
3876
  --select-flex: 1 1 0%;
3873
3877
  }
3874
3878
 
3875
- .select[data-width=full],
3879
+ .select:where([data-width=full]) {
3880
+ --select-width: 100%;
3881
+ --select-flex: 0 0 100%;
3882
+ }
3883
+
3876
3884
  .select-block {
3877
3885
  --select-width: 100%;
3878
3886
  --select-flex: 0 0 100%;
@@ -3983,12 +3991,13 @@ figure.chip {
3983
3991
  border-color: var(--select-primary-color-border-disabled);
3984
3992
  background-color: var(--select-primary-color-surface-disabled);
3985
3993
  cursor: default;
3986
- --select-icon-fill: var(--select-icon-color-disabled);
3994
+ --select-icon-fill: var(--select-icon-color-readonly);
3987
3995
  }
3988
3996
  .select-button:where([data-priority=secondary]):where([data-readonly=true]) {
3989
- border-color: transparent;
3990
- background-color: var(--select-color-surface-secondary-disabled);
3997
+ border-color: var(--select-secondary-color-border-readonly);
3998
+ background-color: var(--select-color-surface-secondary-readonly);
3991
3999
  cursor: default;
4000
+ --select-icon-fill: var(--select-icon-color-readonly);
3992
4001
  }
3993
4002
  .select-button:where([data-priority=secondary]):where([data-readonly=true])::after {
3994
4003
  background-color: var(--select-color-border-secondary-disabled);
@@ -3998,7 +4007,7 @@ figure.chip {
3998
4007
  border-color: var(--select-table-border-readonly-color);
3999
4008
  background-color: var(--select-table-surface-readonly-color);
4000
4009
  cursor: not-allowed;
4001
- --select-icon-fill: var(--select-table-icon-color-disabled);
4010
+ --select-icon-fill: var(--select-table-icon-color-readonly);
4002
4011
  }
4003
4012
  .select-button:where(:not([data-priority=secondary])):where([data-state=disabled]), .select-button:where(:not([data-priority=secondary])):disabled {
4004
4013
  border-color: var(--select-primary-color-border-disabled);
@@ -4007,7 +4016,7 @@ figure.chip {
4007
4016
  --select-icon-fill: var(--select-icon-color-disabled);
4008
4017
  }
4009
4018
  .select-button:where([data-priority=secondary]):where([data-state=disabled]), .select-button:where([data-priority=secondary]):disabled {
4010
- border-color: transparent;
4019
+ border-color: var(--select-secondary-color-border-disabled);
4011
4020
  background-color: var(--select-color-surface-secondary-disabled);
4012
4021
  }
4013
4022
  .select-button:where([data-priority=secondary]):where([data-state=disabled])::after, .select-button:where([data-priority=secondary]):disabled::after {
@@ -4074,6 +4083,11 @@ figure.chip {
4074
4083
  color: var(--select-secondary-color-text-readonly);
4075
4084
  }
4076
4085
 
4086
+ .select-input-label-readonly {
4087
+ width: auto;
4088
+ max-width: 100%;
4089
+ }
4090
+
4077
4091
  .select-button:where(:not([data-state=disabled])) .select-value[data-has-value=true] .select-input-label {
4078
4092
  color: var(--select-color-text-value);
4079
4093
  caret-color: var(--select-color-text-value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniai-fe/uds-primitives",
3
- "version": "0.3.60",
3
+ "version": "0.4.1",
4
4
  "description": "UNIAI Design System; Primitives Components Package",
5
5
  "type": "module",
6
6
  "private": false,
@@ -15,7 +15,7 @@
15
15
  "publishConfig": {
16
16
  "access": "public"
17
17
  },
18
- "packageManager": "pnpm@10.32.0",
18
+ "packageManager": "pnpm@10.32.1",
19
19
  "engines": {
20
20
  "node": ">=24",
21
21
  "pnpm": ">=10"
@@ -85,13 +85,13 @@
85
85
  "@radix-ui/react-tooltip": "^1.2.8",
86
86
  "@radix-ui/react-visually-hidden": "^1.2.4",
87
87
  "clsx": "^2.1.1",
88
- "dayjs": "^1.11.19",
88
+ "dayjs": "^1.11.20",
89
89
  "react-daum-postcode": "^4.0.0"
90
90
  },
91
91
  "devDependencies": {
92
- "@mantine/core": "^8.3.16",
93
- "@mantine/dates": "^8.3.16",
94
- "@mantine/hooks": "^8.3.16",
92
+ "@mantine/core": "^8.3.18",
93
+ "@mantine/dates": "^8.3.18",
94
+ "@mantine/hooks": "^8.3.18",
95
95
  "@svgr/webpack": "^8.1.0",
96
96
  "@types/node": "^24.10.2",
97
97
  "@types/react": "^19.2.14",
@@ -104,7 +104,7 @@
104
104
  "eslint": "^9.39.2",
105
105
  "prettier": "^3.8.1",
106
106
  "react-hook-form": "^7.71.2",
107
- "sass": "^1.97.3",
107
+ "sass": "^1.98.0",
108
108
  "typescript": "~5.9.3"
109
109
  }
110
110
  }
@@ -1,4 +1,10 @@
1
1
  /**
2
- * alternate 카테고리 배럴 placeholder: 실제 구현은 markup/ 하위에 추가한다.
2
+ * Alternate; empty/loading fallback 유닛 카테고리 배럴
3
+ * @desc
4
+ * - `Alternate.EmptyData`: 빈 데이터 안내 레이아웃이다.
5
+ * - `Alternate.LoadingDefault`: 로딩 아이콘과 안내 문구를 함께 렌더링한다.
6
+ * - `Alternate.LoadingIcon`: 단독 스피너 아이콘이다.
7
+ * - `Alternate.Text`: fallback 문구 스타일 슬롯이다.
3
8
  */
4
9
  export { default as Alternate } from "./markup";
10
+ export type * from "./types";
@@ -1,9 +1,14 @@
1
1
  import { Slot } from "../../slot";
2
+ import type { AlternateTextProps } from "../types";
2
3
 
3
- export default function AlternateText({
4
- children,
5
- }: {
6
- children: React.ReactNode;
7
- }) {
4
+ /**
5
+ * Alternate Text; fallback 문구 슬롯
6
+ * @component
7
+ * @param {AlternateTextProps} props
8
+ * @param {React.ReactNode} props.children 렌더링할 문구 콘텐츠다.
9
+ * @example
10
+ * <Alternate.Text>데이터가 없습니다.</Alternate.Text>
11
+ */
12
+ export default function AlternateText({ children }: AlternateTextProps) {
8
13
  return <Slot.Text className="alternate-text">{children}</Slot.Text>;
9
14
  }
@@ -2,20 +2,23 @@
2
2
 
3
3
  import { clsx } from "clsx";
4
4
  import AlternateText from "../Label";
5
+ import type { AlternateEmptyDataProps } from "../../types";
5
6
 
6
7
  /**
7
- * 차트; 데이터 없는 경우 대체 컴포넌트
8
+ * Alternate EmptyData; 데이터 안내 레이아웃
8
9
  * @component
10
+ * @param {AlternateEmptyDataProps} props
11
+ * @param {string} [props.className] 루트 className override다.
12
+ * @param {"vertical" | "horizontal"} [props.direction="vertical"] 아이콘/문구 배치 방향이다.
13
+ * @param {React.ReactNode} [props.children] 안내 문구 콘텐츠다. 비어 있으면 기본 문구를 사용한다.
14
+ * @example
15
+ * <Alternate.EmptyData direction="horizontal">데이터가 없습니다.</Alternate.EmptyData>
9
16
  */
10
17
  export default function AlternateEmptyData({
11
18
  className,
12
19
  direction = "vertical",
13
20
  children: text,
14
- }: Partial<{
15
- className: string;
16
- direction: "vertical" | "horizontal";
17
- children: React.ReactNode;
18
- }>) {
21
+ }: AlternateEmptyDataProps) {
19
22
  const directionClass =
20
23
  direction === "horizontal" ? "is-horizontal" : "is-vertical";
21
24
 
@@ -3,6 +3,14 @@ import AlternateText from "./Label";
3
3
  import AlternateLoadingDefault from "./loading/Default";
4
4
  import AlternateLoadingIcon from "./loading/Icon";
5
5
 
6
+ /**
7
+ * Alternate; empty/loading fallback namespace
8
+ * @desc
9
+ * - `Alternate.EmptyData`: 빈 데이터 안내 레이아웃이다.
10
+ * - `Alternate.LoadingDefault`: 로딩 안내 레이아웃이다.
11
+ * - `Alternate.LoadingIcon`: 단독 스피너 아이콘이다.
12
+ * - `Alternate.Text`: 안내 문구 슬롯이다.
13
+ */
6
14
  const Alternate = {
7
15
  EmptyData: AlternateEmptyData,
8
16
  LoadingDefault: AlternateLoadingDefault,
@@ -3,25 +3,29 @@
3
3
  import { clsx } from "clsx";
4
4
  import AlternateLoadingIcon from "./Icon";
5
5
  import AlternateText from "../Label";
6
+ import type { AlternateLoadingDefaultProps } from "../../types";
6
7
 
7
8
  /**
8
- * 데이터 로딩중 컴포넌트
9
+ * Alternate LoadingDefault; 로딩 안내 레이아웃
9
10
  * @component
11
+ * @param {AlternateLoadingDefaultProps} props
12
+ * @param {"vertical" | "horizontal"} [props.direction="vertical"] 아이콘/문구 배치 방향이다.
13
+ * @param {React.ReactNode} [props.children] 안내 문구 콘텐츠다. 비어 있으면 기본 문구를 사용한다.
14
+ * @example
15
+ * <Alternate.LoadingDefault>데이터를 불러오는 중입니다.</Alternate.LoadingDefault>
10
16
  */
11
17
  export default function AlternateLoadingDefault({
12
18
  direction = "vertical",
13
19
  children: text,
14
- }: Partial<{
15
- direction: "vertical" | "horizontal";
16
- children: React.ReactNode;
17
- }>) {
20
+ }: AlternateLoadingDefaultProps) {
18
21
  const directionClass =
19
22
  direction === "horizontal" ? "is-horizontal" : "is-vertical";
20
23
 
21
24
  return (
22
25
  <div className={clsx("alternate loading", directionClass)}>
23
26
  <AlternateLoadingIcon direction={direction} />
24
- {["string", "undefined"].includes(typeof text) ? (
27
+ {/* string/number만 Slot.Text로 감싸고, 외 ReactNode는 그대로 렌더링한다. */}
28
+ {["string", "number", "undefined"].includes(typeof text) ? (
25
29
  <AlternateText>{text || "데이터를 불러오는 중입니다."}</AlternateText>
26
30
  ) : (
27
31
  text
@@ -4,14 +4,21 @@ import { clsx } from "clsx";
4
4
  import SpinnerSmallIcon from "../../img/spinner-small-24x24.svg";
5
5
  import SpinnerMediumIcon from "../../img/spinner-medium-36x36.svg";
6
6
  import SpinnerLargeIcon from "../../img/spinner-large-52x52.svg";
7
+ import type { AlternateLoadingIconProps } from "../../types";
7
8
 
9
+ /**
10
+ * Alternate LoadingIcon; 단독 스피너 아이콘
11
+ * @component
12
+ * @param {AlternateLoadingIconProps} props
13
+ * @param {"small" | "medium" | "large"} [props.size="small"] 로딩 아이콘 스케일이다.
14
+ * @param {"vertical" | "horizontal"} [props.direction] 부모 레이아웃 방향 클래스 동기화용 값이다.
15
+ * @example
16
+ * <Alternate.LoadingIcon size="medium" />
17
+ */
8
18
  export default function AlternateLoadingIcon({
9
19
  size = "small",
10
20
  direction,
11
- }: {
12
- size?: "small" | "medium" | "large";
13
- direction?: "vertical" | "horizontal";
14
- }) {
21
+ }: AlternateLoadingIconProps) {
15
22
  const directionClass =
16
23
  direction === "horizontal" ? "is-horizontal" : "is-vertical";
17
24
  const sizeClass = size ? `is-${size}` : undefined;
@@ -1,4 +1,77 @@
1
+ import type { ReactNode } from "react";
2
+
1
3
  /**
2
- * TODO(alternate): variant/slot 타입 정의를 작성한다.
4
+ * Alternate Direction; fallback 레이아웃 방향 축
5
+ * @typedef {"vertical" | "horizontal"} AlternateDirection
3
6
  */
4
- export {};
7
+ export type AlternateDirection = "vertical" | "horizontal";
8
+
9
+ /**
10
+ * Alternate Loading Icon Size; 로딩 아이콘 스케일 축
11
+ * @typedef {"small" | "medium" | "large"} AlternateLoadingIconSize
12
+ */
13
+ export type AlternateLoadingIconSize = "small" | "medium" | "large";
14
+
15
+ /**
16
+ * Alternate Text Props; fallback 문구 슬롯 props
17
+ * @property {ReactNode} children 렌더링할 문구 콘텐츠다.
18
+ */
19
+ export interface AlternateTextProps {
20
+ /**
21
+ * 렌더링할 문구 콘텐츠다.
22
+ */
23
+ children: ReactNode;
24
+ }
25
+
26
+ /**
27
+ * Alternate Empty Data Props; 빈 데이터 안내 레이아웃 props
28
+ * @property {string} [className] 루트 className override다.
29
+ * @property {"vertical" | "horizontal"} [direction] 아이콘/문구 배치 방향이다.
30
+ * @property {ReactNode} [children] 안내 문구 콘텐츠다.
31
+ */
32
+ export interface AlternateEmptyDataProps {
33
+ /**
34
+ * 루트 className override다.
35
+ */
36
+ className?: string;
37
+ /**
38
+ * 아이콘/문구 배치 방향이다.
39
+ */
40
+ direction?: AlternateDirection;
41
+ /**
42
+ * 안내 문구 콘텐츠다.
43
+ */
44
+ children?: ReactNode;
45
+ }
46
+
47
+ /**
48
+ * Alternate Loading Default Props; 로딩 안내 레이아웃 props
49
+ * @property {"vertical" | "horizontal"} [direction] 아이콘/문구 배치 방향이다.
50
+ * @property {ReactNode} [children] 안내 문구 콘텐츠다.
51
+ */
52
+ export interface AlternateLoadingDefaultProps {
53
+ /**
54
+ * 아이콘/문구 배치 방향이다.
55
+ */
56
+ direction?: AlternateDirection;
57
+ /**
58
+ * 안내 문구 콘텐츠다.
59
+ */
60
+ children?: ReactNode;
61
+ }
62
+
63
+ /**
64
+ * Alternate Loading Icon Props; 단독 스피너 아이콘 props
65
+ * @property {"small" | "medium" | "large"} [size] 로딩 아이콘 스케일이다.
66
+ * @property {"vertical" | "horizontal"} [direction] 부모 레이아웃 방향 클래스 동기화용 값이다.
67
+ */
68
+ export interface AlternateLoadingIconProps {
69
+ /**
70
+ * 로딩 아이콘 스케일이다.
71
+ */
72
+ size?: AlternateLoadingIconSize;
73
+ /**
74
+ * 부모 레이아웃 방향 클래스 동기화용 값이다.
75
+ */
76
+ direction?: AlternateDirection;
77
+ }
@@ -1,5 +1,8 @@
1
1
  /**
2
- * badge 카테고리 배럴 placeholder: 실제 구현은 markup/ 하위에 추가한다.
2
+ * Badge; status/info label 렌더링 카테고리 배럴
3
+ * @desc
4
+ * - `Badge`: size/style/intent/tone 축을 렌더링하는 단일 leaf 컴포넌트다.
5
+ * - `BadgeProps`: badge public props 계약이다.
3
6
  */
4
7
  import "./index.scss";
5
8
 
@@ -4,17 +4,19 @@ import { composeBadgeClassName } from "../utils";
4
4
  import { Slot } from "../../slot";
5
5
 
6
6
  /**
7
- * Badge 컴포넌트; size/style/intent 축을 data attribute로 노출한다.
7
+ * Badge; status/info label 렌더링 leaf 컴포넌트
8
8
  * @component
9
9
  * @param {BadgeProps} props
10
- * @param {"xsmall" | "small"} [props.size="xsmall"] 토큰 size.
11
- * @param {"fill" | "outlined" | "dot"} [props.style="fill"] 시각 스타일.
10
+ * @param {"xsmall" | "small"} [props.size="xsmall"] 토큰 size 축이다.
11
+ * @param {"fill" | "outlined" | "dot"} [props.style="fill"] 시각 스타일 축이다.
12
12
  * @param {"primary" | "secondary" | "tertiary" | "gray" | "green" | "yellow" | "orange" | "red"} [props.intent="primary"]
13
- * fill/outlined 스타일에서 사용되는 intent.
14
- * @param {"primary" | "feedback"} [props.tone="primary"] dot 스타일에 사용되는 tone.
15
- * @param {React.ReactNode} [props.children] 라벨 텍스트. dot 스타일에서 생략하면 점만 렌더.
16
- * @param {string} [props.className] figure className.
17
- * @param {React.CSSProperties} [props.inlineStyle] figure inline style.
13
+ * fill/outlined 스타일에서 사용되는 intent 축이다.
14
+ * @param {"primary" | "feedback"} [props.tone="primary"] dot 스타일 전용 tone 축이다.
15
+ * @param {React.ReactNode} [props.children] 라벨 텍스트다. dot 스타일에서 생략하면 점만 렌더링한다.
16
+ * @param {string} [props.className] figure root className override다.
17
+ * @param {React.CSSProperties} [props.inlineStyle] figure root inline style이다.
18
+ * @example
19
+ * <Badge style="fill" intent="primary">승인됨</Badge>
18
20
  */
19
21
  const Badge = forwardRef<HTMLElementTagNameMap["figure"], BadgeProps>(
20
22
  (
@@ -1,4 +1,4 @@
1
- import type { ComponentPropsWithoutRef, ReactNode } from "react";
1
+ import type { CSSProperties, ComponentPropsWithoutRef, ReactNode } from "react";
2
2
 
3
3
  export const BADGE_SIZES = ["xsmall", "small"] as const;
4
4
  export const BADGE_STYLES = ["fill", "outlined", "dot"] as const;
@@ -21,6 +21,15 @@ export type BadgeTone = (typeof BADGE_TONES)[number];
21
21
 
22
22
  type NativeFigureProps = Omit<ComponentPropsWithoutRef<"figure">, "style">;
23
23
 
24
+ /**
25
+ * Badge Props; status/info label badge public props
26
+ * @property {ReactNode} [children] 표시할 라벨이다. 생략하면 dot만 렌더링한다.
27
+ * @property {"xsmall" | "small"} [size] Figma size 축이다.
28
+ * @property {"fill" | "outlined" | "dot"} [style] badge 시각 스타일 축이다.
29
+ * @property {"primary" | "secondary" | "tertiary" | "gray" | "green" | "yellow" | "orange" | "red"} [intent] fill/outlined 변형의 색상 의도다.
30
+ * @property {"primary" | "feedback"} [tone] dot 변형 전용 tone 축이다.
31
+ * @property {CSSProperties} [inlineStyle] 원본 figure 요소에 적용할 inline style이다.
32
+ */
24
33
  export interface BadgeProps extends Omit<NativeFigureProps, "children"> {
25
34
  /**
26
35
  * 표시할 라벨. 생략하면 dot 스타일만 렌더링된다.
@@ -45,11 +54,26 @@ export interface BadgeProps extends Omit<NativeFigureProps, "children"> {
45
54
  /**
46
55
  * 원본 figure 요소에 적용할 인라인 스타일.
47
56
  */
48
- inlineStyle?: ComponentPropsWithoutRef<"figure">["style"];
57
+ inlineStyle?: CSSProperties;
49
58
  }
50
59
 
60
+ /**
61
+ * Badge ClassName Options; badge root className 조합 입력값
62
+ * @property {"xsmall" | "small"} size badge size 축이다.
63
+ * @property {"fill" | "outlined" | "dot"} style badge style 축이다.
64
+ * @property {string} [className] 외부 className override다.
65
+ */
51
66
  export interface BadgeClassNameOptions {
67
+ /**
68
+ * badge size 축이다.
69
+ */
52
70
  size: BadgeSize;
71
+ /**
72
+ * badge style 축이다.
73
+ */
53
74
  style: BadgeStyle;
75
+ /**
76
+ * 외부 className override다.
77
+ */
54
78
  className?: string;
55
79
  }
@@ -1,5 +1,10 @@
1
1
  /**
2
- * button 카테고리 배럴 placeholder: 실제 구현은 markup/ 하위에 추가한다.
2
+ * Button; namespace 배럴 export
3
+ * @desc
4
+ * - `Button.Default`: fill/priority/size 축 기반 기본 버튼
5
+ * - `Button.Text`: text action 템플릿
6
+ * - `Button.Rounded`: round icon action 템플릿
7
+ * - `Button.Label`: button-label className 고정 래퍼
3
8
  */
4
9
  import "./index.scss";
5
10