@uniai-fe/uds-primitives 0.2.8 → 0.2.10
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/dist/styles.css +419 -0
- package/package.json +2 -1
- package/src/components/calendar/types/calendar.ts +5 -0
- package/src/components/dropdown/markup/Template.tsx +41 -17
- package/src/components/dropdown/markup/foundation/Container.tsx +14 -2
- package/src/components/dropdown/markup/foundation/MenuItem.tsx +20 -6
- package/src/components/dropdown/markup/foundation/Root.tsx +8 -1
- package/src/components/dropdown/markup/foundation/Trigger.tsx +7 -1
- package/src/components/dropdown/styles/dropdown.scss +4 -0
- package/src/components/dropdown/types/props.ts +5 -0
- package/src/components/input/markup/date/Template.tsx +36 -5
- package/src/components/input/markup/date/Trigger.tsx +22 -4
- package/src/components/input/markup/foundation/Input.tsx +19 -11
- package/src/components/input/markup/foundation/Utility.tsx +11 -7
- package/src/components/input/styles/date.scss +21 -0
- package/src/components/input/styles/foundation.scss +30 -0
- package/src/components/input/styles/variables.scss +11 -0
- package/src/components/input/types/date.ts +15 -0
- package/src/components/input/types/foundation.ts +18 -11
- package/src/components/input/utils/date.ts +15 -1
- package/src/components/select/hooks/index.ts +1 -45
- package/src/components/select/hooks/interaction.ts +62 -0
- package/src/components/select/markup/Default.tsx +59 -35
- package/src/components/select/markup/foundation/Base.tsx +12 -4
- package/src/components/select/markup/foundation/Container.tsx +37 -34
- package/src/components/select/markup/foundation/Icon.tsx +6 -1
- package/src/components/select/markup/multiple/Multiple.tsx +62 -35
- package/src/components/select/markup/multiple/SelectedChip.tsx +5 -2
- package/src/components/select/styles/select.scss +50 -0
- package/src/components/select/styles/variables.scss +26 -0
- package/src/components/select/types/base.ts +3 -2
- package/src/components/select/types/icon.ts +7 -6
- package/src/components/select/types/index.ts +1 -0
- package/src/components/select/types/interaction.ts +30 -0
- package/src/components/select/types/props.ts +8 -0
- package/src/components/select/types/trigger.ts +4 -0
- package/src/components/table/hooks/index.ts +0 -3
- package/src/components/table/index.tsx +5 -3
- package/src/components/table/markup/Container.tsx +126 -0
- package/src/components/table/markup/foundation/Body.tsx +24 -0
- package/src/components/table/markup/foundation/Cell.tsx +72 -0
- package/src/components/table/markup/foundation/Col.tsx +22 -0
- package/src/components/table/markup/foundation/Colgroup.tsx +29 -0
- package/src/components/table/markup/foundation/Foot.tsx +24 -0
- package/src/components/table/markup/foundation/Head.tsx +24 -0
- package/src/components/table/markup/foundation/Root.tsx +32 -0
- package/src/components/table/markup/foundation/Row.tsx +32 -0
- package/src/components/table/markup/foundation/Td.tsx +37 -0
- package/src/components/table/markup/foundation/Th.tsx +39 -0
- package/src/components/table/markup/foundation/index.tsx +30 -0
- package/src/components/table/markup/index.tsx +8 -2
- package/src/components/table/styles/foundation.scss +247 -0
- package/src/components/table/styles/index.scss +2 -0
- package/src/components/table/styles/variables.scss +29 -0
- package/src/components/table/types/foundation.ts +250 -0
- package/src/components/table/types/index.ts +1 -4
- package/src/components/tooltip/img/info.svg +5 -0
- package/src/components/tooltip/img/information.svg +9 -0
- package/src/components/tooltip/index.scss +1 -0
- package/src/components/tooltip/index.tsx +4 -0
- package/src/components/tooltip/markup/Message.tsx +70 -0
- package/src/components/tooltip/markup/Root.tsx +32 -0
- package/src/components/tooltip/markup/Template.tsx +46 -0
- package/src/components/tooltip/markup/Trigger.tsx +32 -0
- package/src/components/tooltip/markup/index.tsx +18 -0
- package/src/components/tooltip/styles/index.scss +2 -0
- package/src/components/tooltip/styles/tooltip.scss +47 -0
- package/src/components/tooltip/styles/variables.scss +14 -0
- package/src/components/tooltip/types/index.ts +1 -0
- package/src/components/tooltip/types/props.ts +118 -0
- package/src/index.scss +1 -0
- package/src/index.tsx +1 -0
|
@@ -6,13 +6,16 @@ import RemoveIcon from "../../img/remove.svg";
|
|
|
6
6
|
import type { SelectMultipleChipProps } from "../../types/multiple";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Select
|
|
9
|
+
* Select Markup; Multiple 선택값 Chip 렌더링 컴포넌트
|
|
10
10
|
* @component
|
|
11
11
|
* @param {SelectMultipleChipProps} props chip props
|
|
12
12
|
* @param {React.ReactNode} props.label chip 라벨
|
|
13
13
|
* @param {React.ReactNode} [props.suffix] 라벨 뒤에 붙는 서브 라벨
|
|
14
|
-
* @param {boolean} [props.removable] remove 버튼 노출 여부
|
|
14
|
+
* @param {boolean} [props.removable=true] remove 버튼 노출 여부
|
|
15
15
|
* @param {() => void} [props.onRemove] remove 클릭 핸들러
|
|
16
|
+
* @param {"value" | "summary"} [props.kind="value"] chip 용도 구분
|
|
17
|
+
* @example
|
|
18
|
+
* <SelectMultipleSelectedChip label="Apple" removable onRemove={() => {}} />
|
|
16
19
|
*/
|
|
17
20
|
export function SelectMultipleSelectedChip({
|
|
18
21
|
label,
|
|
@@ -109,6 +109,14 @@
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
&[data-priority="table"] {
|
|
113
|
+
// 변경: table priority는 input table과 동일하게 기본 border/background를 최소화한다.
|
|
114
|
+
border-radius: var(--select-table-radius);
|
|
115
|
+
border-color: var(--select-table-border-default-color);
|
|
116
|
+
background-color: var(--select-table-surface-color);
|
|
117
|
+
--select-icon-fill: var(--select-table-icon-color-default);
|
|
118
|
+
}
|
|
119
|
+
|
|
112
120
|
&:not([data-priority="secondary"])[data-state="focused"],
|
|
113
121
|
&:not([data-priority="secondary"])[data-open="true"],
|
|
114
122
|
&:not([data-priority="secondary"]):focus-visible {
|
|
@@ -117,6 +125,14 @@
|
|
|
117
125
|
--select-icon-fill: var(--select-icon-color-focused);
|
|
118
126
|
}
|
|
119
127
|
|
|
128
|
+
&[data-priority="table"][data-state="focused"],
|
|
129
|
+
&[data-priority="table"][data-open="true"],
|
|
130
|
+
&[data-priority="table"]:focus-visible {
|
|
131
|
+
border-color: var(--select-table-border-focus-color);
|
|
132
|
+
border-width: var(--select-primary-border-width-focus);
|
|
133
|
+
--select-icon-fill: var(--select-table-icon-color-focused);
|
|
134
|
+
}
|
|
135
|
+
|
|
120
136
|
// &:not([data-priority="secondary"]):hover:not(:disabled) {
|
|
121
137
|
// }
|
|
122
138
|
|
|
@@ -138,6 +154,14 @@
|
|
|
138
154
|
height: var(--select-secondary-underline-width-default);
|
|
139
155
|
}
|
|
140
156
|
}
|
|
157
|
+
|
|
158
|
+
&[data-priority="table"][data-state="disabled"],
|
|
159
|
+
&[data-priority="table"]:disabled {
|
|
160
|
+
border-color: var(--select-table-border-disabled-color);
|
|
161
|
+
background-color: var(--select-table-surface-disabled-color);
|
|
162
|
+
cursor: not-allowed;
|
|
163
|
+
--select-icon-fill: var(--select-table-icon-color-disabled);
|
|
164
|
+
}
|
|
141
165
|
}
|
|
142
166
|
|
|
143
167
|
.select-value {
|
|
@@ -165,6 +189,10 @@
|
|
|
165
189
|
color: var(--select-secondary-color-text);
|
|
166
190
|
}
|
|
167
191
|
|
|
192
|
+
.select-button[data-priority="table"] & {
|
|
193
|
+
color: var(--select-table-color-text);
|
|
194
|
+
}
|
|
195
|
+
|
|
168
196
|
.select-button[data-state="focused"] &,
|
|
169
197
|
.select-button[data-open="true"] & {
|
|
170
198
|
color: var(--select-primary-color-text-focused);
|
|
@@ -185,6 +213,10 @@
|
|
|
185
213
|
.select-button[data-priority="secondary"] & {
|
|
186
214
|
color: var(--select-secondary-color-placeholder);
|
|
187
215
|
}
|
|
216
|
+
|
|
217
|
+
.select-button[data-priority="table"] & {
|
|
218
|
+
color: var(--select-table-color-placeholder);
|
|
219
|
+
}
|
|
188
220
|
}
|
|
189
221
|
|
|
190
222
|
.select-button[data-size="small"] .select-label {
|
|
@@ -194,6 +226,12 @@
|
|
|
194
226
|
font-weight: var(--select-text-small-weight);
|
|
195
227
|
}
|
|
196
228
|
|
|
229
|
+
.select-button[data-priority="table"][data-size="small"] .select-label {
|
|
230
|
+
font-size: var(--select-table-text-small-size);
|
|
231
|
+
line-height: var(--select-table-text-small-line-height);
|
|
232
|
+
font-weight: var(--select-table-text-small-weight);
|
|
233
|
+
}
|
|
234
|
+
|
|
197
235
|
.select-button[data-size="large"] .select-label {
|
|
198
236
|
font-size: var(--select-text-large-size);
|
|
199
237
|
line-height: var(--select-text-large-line-height);
|
|
@@ -201,6 +239,18 @@
|
|
|
201
239
|
font-weight: var(--select-text-large-weight);
|
|
202
240
|
}
|
|
203
241
|
|
|
242
|
+
.select-button[data-priority="table"][data-size="medium"] .select-label {
|
|
243
|
+
font-size: var(--select-table-text-medium-size);
|
|
244
|
+
line-height: var(--select-table-text-medium-line-height);
|
|
245
|
+
font-weight: var(--select-table-text-medium-weight);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.select-button[data-priority="table"][data-size="large"] .select-label {
|
|
249
|
+
font-size: var(--select-table-text-large-size);
|
|
250
|
+
line-height: var(--select-table-text-large-line-height);
|
|
251
|
+
font-weight: var(--select-table-text-large-weight);
|
|
252
|
+
}
|
|
253
|
+
|
|
204
254
|
.select-button[data-priority="secondary"][data-size="large"] .select-label {
|
|
205
255
|
font-weight: 600;
|
|
206
256
|
}
|
|
@@ -24,6 +24,32 @@
|
|
|
24
24
|
--select-secondary-gap: var(--spacing-gap-2);
|
|
25
25
|
--select-secondary-underline-width-default: 1px;
|
|
26
26
|
--select-secondary-underline-width-focus: 1.4px;
|
|
27
|
+
--select-table-radius: var(--input-table-radius-base);
|
|
28
|
+
--select-table-border-default-color: var(--input-border-table-default-color);
|
|
29
|
+
--select-table-border-focus-color: var(--input-border-active-color);
|
|
30
|
+
--select-table-border-disabled-color: var(--input-border-disabled-color);
|
|
31
|
+
--select-table-surface-color: transparent;
|
|
32
|
+
--select-table-surface-disabled-color: var(--input-surface-disabled-color);
|
|
33
|
+
--select-table-color-text: var(--input-text-color);
|
|
34
|
+
--select-table-color-placeholder: var(--input-placeholder-color);
|
|
35
|
+
--select-table-icon-color-default: var(--select-icon-color-default);
|
|
36
|
+
--select-table-icon-color-focused: var(--select-icon-color-focused);
|
|
37
|
+
--select-table-icon-color-disabled: var(--select-icon-color-disabled);
|
|
38
|
+
--select-table-text-small-size: var(--input-table-text-small-size);
|
|
39
|
+
--select-table-text-small-line-height: var(
|
|
40
|
+
--input-table-text-small-line-height
|
|
41
|
+
);
|
|
42
|
+
--select-table-text-small-weight: var(--input-table-text-small-weight);
|
|
43
|
+
--select-table-text-medium-size: var(--input-table-text-medium-size);
|
|
44
|
+
--select-table-text-medium-line-height: var(
|
|
45
|
+
--input-table-text-medium-line-height
|
|
46
|
+
);
|
|
47
|
+
--select-table-text-medium-weight: var(--input-table-text-medium-weight);
|
|
48
|
+
--select-table-text-large-size: var(--input-table-text-large-size);
|
|
49
|
+
--select-table-text-large-line-height: var(
|
|
50
|
+
--input-table-text-large-line-height
|
|
51
|
+
);
|
|
52
|
+
--select-table-text-large-weight: var(--input-table-text-large-weight);
|
|
27
53
|
--select-text-small-size: 15px;
|
|
28
54
|
--select-text-small-line-height: 1.4;
|
|
29
55
|
--select-text-small-letter-spacing: 0.2px;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Select priority scale
|
|
3
|
-
* @typedef {"primary" | "secondary"} SelectPriority
|
|
3
|
+
* @typedef {"primary" | "secondary" | "table"} SelectPriority
|
|
4
4
|
* - primary: input primary 스타일과 동일한 기본 형태
|
|
5
5
|
* - secondary: borderless + underline 스타일
|
|
6
|
+
* - table: input table과 동일한 셀 임베드 스타일
|
|
6
7
|
*/
|
|
7
|
-
export type SelectPriority = "primary" | "secondary";
|
|
8
|
+
export type SelectPriority = "primary" | "secondary" | "table";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Select size scale
|
|
@@ -14,19 +14,20 @@ export type SelectIconSizeMap = Record<SelectSize, ElementType>;
|
|
|
14
14
|
* Select 아이콘 priority 맵
|
|
15
15
|
* @property {SelectIconSizeMap} primary primary priority용 아이콘 컬렉션
|
|
16
16
|
* @property {SelectIconSizeMap} secondary secondary priority용 아이콘 컬렉션
|
|
17
|
+
* @property {SelectIconSizeMap} table table priority용 아이콘 컬렉션
|
|
17
18
|
*/
|
|
18
19
|
export type SelectIconPriorityMap = Record<SelectPriority, SelectIconSizeMap>;
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Select multi remove priority 맵
|
|
22
23
|
* @property {SelectIconSizeMap} primary primary priority remove 아이콘
|
|
24
|
+
* @property {SelectIconSizeMap} secondary secondary priority remove 아이콘
|
|
25
|
+
* @property {SelectIconSizeMap} table table priority remove 아이콘
|
|
23
26
|
*/
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
primary: SelectIconSizeMap;
|
|
29
|
-
}
|
|
27
|
+
export type SelectIconRemovePriorityMap = Record<
|
|
28
|
+
SelectPriority,
|
|
29
|
+
SelectIconSizeMap
|
|
30
|
+
>;
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Select 아이콘 전체 컬렉션
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SelectDropdownBehaviorProps } from "./props";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Select Hook Types; Dropdown open state hook 입력 파라미터
|
|
5
|
+
* @property {boolean} [open] 외부 제어형 open 상태
|
|
6
|
+
* @property {boolean} [defaultOpen] 비제어형 초기 open 상태
|
|
7
|
+
* @property {(open: boolean) => void} [onOpenChange] open 상태 변경 콜백
|
|
8
|
+
*/
|
|
9
|
+
export interface UseSelectDropdownOpenStateParams extends SelectDropdownBehaviorProps {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Select Hook Types; Dropdown open state hook 반환값
|
|
13
|
+
* @property {boolean} open 최종 open 상태
|
|
14
|
+
* @property {(nextOpen: boolean) => void} setOpen open 상태 업데이트 함수
|
|
15
|
+
* @property {boolean} isControlled open prop 기반 제어형 여부
|
|
16
|
+
*/
|
|
17
|
+
export interface UseSelectDropdownOpenStateReturn {
|
|
18
|
+
/**
|
|
19
|
+
* 최종 open 상태
|
|
20
|
+
*/
|
|
21
|
+
open: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* open 상태 업데이트 함수
|
|
24
|
+
*/
|
|
25
|
+
setOpen: (nextOpen: boolean) => void;
|
|
26
|
+
/**
|
|
27
|
+
* open prop 기반 제어형 여부
|
|
28
|
+
*/
|
|
29
|
+
isControlled: boolean;
|
|
30
|
+
}
|
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
export interface SelectStyleOptions {
|
|
25
25
|
/**
|
|
26
26
|
* priority scale
|
|
27
|
+
* - table 우선순위는 width 미지정 시 기본 block(full)로 동작한다.
|
|
27
28
|
*/
|
|
28
29
|
priority?: SelectPriority;
|
|
29
30
|
/**
|
|
@@ -142,6 +143,7 @@ export type SelectProps = SelectStyleOptions &
|
|
|
142
143
|
* @property {DropdownMenuProps} [dropdownRootProps] Dropdown.Root 전달 props(제어 props 제외)
|
|
143
144
|
* @property {DropdownContainerProps} [dropdownContainerProps] Dropdown.Container 전달 props(children/size 제외)
|
|
144
145
|
* @property {DropdownMenuListProps} [dropdownMenuListProps] Dropdown.Menu.List 전달 props
|
|
146
|
+
* @property {ReactNode} [alt] option이 비어 있을 때 렌더링할 alternate 콘텐츠
|
|
145
147
|
*/
|
|
146
148
|
export interface SelectDropdownConfigProps {
|
|
147
149
|
/**
|
|
@@ -183,6 +185,10 @@ export interface SelectDropdownConfigProps {
|
|
|
183
185
|
* Dropdown.Menu.List 전달 props
|
|
184
186
|
*/
|
|
185
187
|
dropdownMenuListProps?: DropdownMenuListProps;
|
|
188
|
+
/**
|
|
189
|
+
* option이 비어 있을 때 렌더링할 alternate 콘텐츠
|
|
190
|
+
*/
|
|
191
|
+
alt?: ReactNode;
|
|
186
192
|
}
|
|
187
193
|
|
|
188
194
|
/**
|
|
@@ -227,6 +233,7 @@ export interface SelectDropdownBehaviorProps {
|
|
|
227
233
|
* @property {Omit<DropdownMenuProps, "open" | "defaultOpen" | "onOpenChange">} [dropdownRootProps] Dropdown.Root 전달 props
|
|
228
234
|
* @property {Omit<DropdownContainerProps, "children" | "size" | "width">} [dropdownContainerProps] Dropdown.Container 전달 props
|
|
229
235
|
* @property {DropdownMenuListProps} [dropdownMenuListProps] Dropdown.Menu.List 전달 props
|
|
236
|
+
* @property {ReactNode} [alt] option이 비어 있을 때 렌더링할 alternate 콘텐츠
|
|
230
237
|
* @property {boolean} [open] dropdown open 상태
|
|
231
238
|
* @property {boolean} [defaultOpen] uncontrolled 초기 open 상태
|
|
232
239
|
* @property {(open: boolean) => void} [onOpenChange] open state change 콜백
|
|
@@ -257,6 +264,7 @@ export type SelectDefaultComponentProps = SelectTriggerDefaultProps &
|
|
|
257
264
|
* @property {Omit<DropdownMenuProps, "open" | "defaultOpen" | "onOpenChange">} [dropdownRootProps] Dropdown.Root 전달 props
|
|
258
265
|
* @property {Omit<DropdownContainerProps, "children" | "size" | "width">} [dropdownContainerProps] Dropdown.Container 전달 props
|
|
259
266
|
* @property {DropdownMenuListProps} [dropdownMenuListProps] Dropdown.Menu.List 전달 props
|
|
267
|
+
* @property {ReactNode} [alt] option이 비어 있을 때 렌더링할 alternate 콘텐츠
|
|
260
268
|
* @property {boolean} [open] dropdown open 상태
|
|
261
269
|
* @property {boolean} [defaultOpen] uncontrolled 초기 open 상태
|
|
262
270
|
* @property {(open: boolean) => void} [onOpenChange] open state change 콜백
|
|
@@ -26,6 +26,7 @@ export interface SelectTriggerBaseProps extends HTMLAttributes<HTMLElement> {
|
|
|
26
26
|
* priority scale
|
|
27
27
|
* - primary
|
|
28
28
|
* - secondary
|
|
29
|
+
* - table
|
|
29
30
|
*/
|
|
30
31
|
priority?: SelectPriority;
|
|
31
32
|
/**
|
|
@@ -90,6 +91,7 @@ export interface SelectTriggerDefaultProps extends HTMLAttributes<HTMLElement> {
|
|
|
90
91
|
* priority scale
|
|
91
92
|
* - primary
|
|
92
93
|
* - secondary
|
|
94
|
+
* - table
|
|
93
95
|
*/
|
|
94
96
|
priority?: SelectPriority;
|
|
95
97
|
/**
|
|
@@ -144,6 +146,8 @@ export interface SelectTriggerMultipleProps extends HTMLAttributes<HTMLElement>
|
|
|
144
146
|
/**
|
|
145
147
|
* priority scale
|
|
146
148
|
* - primary
|
|
149
|
+
* - secondary
|
|
150
|
+
* - table
|
|
147
151
|
*/
|
|
148
152
|
priority?: SelectPriority;
|
|
149
153
|
/**
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import type { TableTemplateColumn, TableTemplateProps } from "../types";
|
|
3
|
+
import TableBody from "./foundation/Body";
|
|
4
|
+
import TableCell from "./foundation/Cell";
|
|
5
|
+
import TableHead from "./foundation/Head";
|
|
6
|
+
import TableTh from "./foundation/Th";
|
|
7
|
+
import TableRoot from "./foundation/Root";
|
|
8
|
+
import TableRow from "./foundation/Row";
|
|
9
|
+
|
|
10
|
+
const resolveHeadContent = (column: TableTemplateColumn): React.ReactNode => {
|
|
11
|
+
if (typeof column.cellContents !== "undefined") {
|
|
12
|
+
return column.cellContents;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof column.cellChildren !== "undefined") {
|
|
16
|
+
return column.cellChildren;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof column.headContent !== "undefined") {
|
|
20
|
+
return column.headContent;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof column.dataName !== "undefined") {
|
|
24
|
+
return column.dataName;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return column.dataKey;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Table Preset; 기본 Container 조합 컴포넌트
|
|
32
|
+
* @component
|
|
33
|
+
* @param {TableTemplateProps} props
|
|
34
|
+
* @param {TableTemplateColumn[]} [props.columns] colgroup/head 자동 렌더링 column 목록
|
|
35
|
+
* @param {boolean} [props.isCustomBody=false] true면 body wrapper 없이 children 직접 렌더링
|
|
36
|
+
* @param {"legacy-rem" | "raw"} [props.widthMode="legacy-rem"] number width 해석 방식
|
|
37
|
+
* @param {React.ReactNode} [props.footer] footer 노드. `<Table.Foot />`를 직접 전달하는 방식을 권장
|
|
38
|
+
* @param {React.ReactNode} [props.children] table body 콘텐츠
|
|
39
|
+
* @example
|
|
40
|
+
* <Table.Container
|
|
41
|
+
* columns={columns}
|
|
42
|
+
* footer={
|
|
43
|
+
* <Table.Foot>
|
|
44
|
+
* <Table.Row>
|
|
45
|
+
* <Table.Td colSpan={4}>
|
|
46
|
+
* <Table.Cell>합계</Table.Cell>
|
|
47
|
+
* </Table.Td>
|
|
48
|
+
* </Table.Row>
|
|
49
|
+
* </Table.Foot>
|
|
50
|
+
* }
|
|
51
|
+
* >
|
|
52
|
+
* {rows}
|
|
53
|
+
* </Table.Container>
|
|
54
|
+
*/
|
|
55
|
+
const TableContainer = forwardRef<HTMLTableElement, TableTemplateProps>(
|
|
56
|
+
(
|
|
57
|
+
{
|
|
58
|
+
columns,
|
|
59
|
+
isCustomBody = false,
|
|
60
|
+
widthMode = "legacy-rem",
|
|
61
|
+
footer,
|
|
62
|
+
children,
|
|
63
|
+
...tableProps
|
|
64
|
+
},
|
|
65
|
+
ref,
|
|
66
|
+
) => {
|
|
67
|
+
const hasColumns = Array.isArray(columns) && columns.length > 0;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<TableRoot {...tableProps} ref={ref}>
|
|
71
|
+
{hasColumns && (
|
|
72
|
+
<colgroup>
|
|
73
|
+
{columns.map(({ key, width, dataKey, className, span }) => {
|
|
74
|
+
const normalizedWidth =
|
|
75
|
+
typeof width === "number"
|
|
76
|
+
? widthMode === "legacy-rem"
|
|
77
|
+
? `${width / 10}rem`
|
|
78
|
+
: width
|
|
79
|
+
: width;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<col
|
|
83
|
+
key={`${key}/colgroup`}
|
|
84
|
+
className={className}
|
|
85
|
+
data-key={dataKey}
|
|
86
|
+
span={span}
|
|
87
|
+
style={
|
|
88
|
+
normalizedWidth
|
|
89
|
+
? {
|
|
90
|
+
width: normalizedWidth,
|
|
91
|
+
}
|
|
92
|
+
: undefined
|
|
93
|
+
}
|
|
94
|
+
width={typeof width === "number" ? width : undefined}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
})}
|
|
98
|
+
</colgroup>
|
|
99
|
+
)}
|
|
100
|
+
|
|
101
|
+
{hasColumns && (
|
|
102
|
+
<TableHead>
|
|
103
|
+
<TableRow>
|
|
104
|
+
{columns.map(column => (
|
|
105
|
+
<TableTh key={`${column.key}/head`} data-key={column.dataKey}>
|
|
106
|
+
{/* 변경: 헤더 셀 여백/정렬도 Cell 레이어에서 일관 제어한다. */}
|
|
107
|
+
<TableCell section="head" alignX={column.align}>
|
|
108
|
+
{resolveHeadContent(column)}
|
|
109
|
+
</TableCell>
|
|
110
|
+
</TableTh>
|
|
111
|
+
))}
|
|
112
|
+
</TableRow>
|
|
113
|
+
</TableHead>
|
|
114
|
+
)}
|
|
115
|
+
|
|
116
|
+
{isCustomBody ? children : <TableBody>{children}</TableBody>}
|
|
117
|
+
|
|
118
|
+
{footer}
|
|
119
|
+
</TableRoot>
|
|
120
|
+
);
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
TableContainer.displayName = "Table.Container";
|
|
125
|
+
|
|
126
|
+
export default TableContainer;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { TableBodyProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Table Foundation; Tbody 마크업 컴포넌트
|
|
7
|
+
* @component
|
|
8
|
+
* @param {TableBodyProps} props
|
|
9
|
+
* @param {string} [props.className] tbody className
|
|
10
|
+
* @param {React.ReactNode} [props.children] tbody 내부 콘텐츠
|
|
11
|
+
*/
|
|
12
|
+
const TableBody = forwardRef<HTMLTableSectionElement, TableBodyProps>(
|
|
13
|
+
({ className, children, ...bodyProps }, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<tbody {...bodyProps} ref={ref} className={clsx("table-body", className)}>
|
|
16
|
+
{children}
|
|
17
|
+
</tbody>
|
|
18
|
+
);
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
TableBody.displayName = "TableFoundation.Body";
|
|
23
|
+
|
|
24
|
+
export default TableBody;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { TableCellContentProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Table Foundation; Cell 콘텐츠 래퍼 컴포넌트
|
|
7
|
+
* @component
|
|
8
|
+
* @param {TableCellContentProps} props
|
|
9
|
+
* @param {"left" | "center" | "right"} [props.alignX] cell 콘텐츠 가로 정렬
|
|
10
|
+
* @param {"top" | "center" | "bottom"} [props.alignY] cell 콘텐츠 세로 정렬
|
|
11
|
+
* @param {boolean} [props.noPadding=false] true면 cell 내부 padding 제거
|
|
12
|
+
* @param {"default" | "none"} [props.padding="default"] cell 내부 padding 제어
|
|
13
|
+
* @param {"left" | "center" | "right"} [props.align] cell 콘텐츠 가로 정렬(호환 alias)
|
|
14
|
+
* @param {string} [props.className] cell content className
|
|
15
|
+
* @param {React.ReactNode} [props.children] 셀 내부 콘텐츠
|
|
16
|
+
*/
|
|
17
|
+
const TableCell = forwardRef<HTMLDivElement, TableCellContentProps>(
|
|
18
|
+
(
|
|
19
|
+
{
|
|
20
|
+
className,
|
|
21
|
+
children,
|
|
22
|
+
section,
|
|
23
|
+
alignX,
|
|
24
|
+
alignY,
|
|
25
|
+
noPadding = false,
|
|
26
|
+
padding = "default",
|
|
27
|
+
align,
|
|
28
|
+
...cellProps
|
|
29
|
+
},
|
|
30
|
+
ref,
|
|
31
|
+
) => {
|
|
32
|
+
const resolvedAlignX = alignX ?? align ?? "left";
|
|
33
|
+
const resolvedAlignY = alignY ?? "center";
|
|
34
|
+
// 변경: noPadding boolean이 주어지면 padding 옵션보다 우선해 none으로 고정한다.
|
|
35
|
+
const resolvedPadding = noPadding ? "none" : padding;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
{...cellProps}
|
|
40
|
+
ref={ref}
|
|
41
|
+
data-align-x={resolvedAlignX}
|
|
42
|
+
data-align-y={resolvedAlignY}
|
|
43
|
+
data-padding={resolvedPadding}
|
|
44
|
+
data-no-padding={noPadding ? "true" : undefined}
|
|
45
|
+
className={clsx(
|
|
46
|
+
"table-cell",
|
|
47
|
+
section && `table-${section}-cell`,
|
|
48
|
+
"table-cell-content",
|
|
49
|
+
className,
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
{/* 변경: 텍스트 콘텐츠는 slot 전용 className으로 감싸 스타일 적용 범위를 고정한다. */}
|
|
53
|
+
{typeof children === "string" || typeof children === "number" ? (
|
|
54
|
+
<span
|
|
55
|
+
className={clsx(
|
|
56
|
+
"table-cell-text",
|
|
57
|
+
section && `table-${section}-cell-text`,
|
|
58
|
+
)}
|
|
59
|
+
>
|
|
60
|
+
{children}
|
|
61
|
+
</span>
|
|
62
|
+
) : (
|
|
63
|
+
children
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
TableCell.displayName = "TableFoundation.Cell";
|
|
71
|
+
|
|
72
|
+
export default TableCell;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { TableColProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Table Foundation; Col 마크업 컴포넌트
|
|
7
|
+
* @component
|
|
8
|
+
* @param {TableColProps} props
|
|
9
|
+
* @param {string} [props.className] col className
|
|
10
|
+
* @deprecated `Table.Template` 또는 native `<col />` 사용을 권장한다.
|
|
11
|
+
*/
|
|
12
|
+
const TableCol = forwardRef<HTMLTableColElement, TableColProps>(
|
|
13
|
+
({ className, ...colProps }, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<col {...colProps} ref={ref} className={clsx("table-col", className)} />
|
|
16
|
+
);
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
TableCol.displayName = "TableFoundation.Col";
|
|
21
|
+
|
|
22
|
+
export default TableCol;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { TableColgroupProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Table Foundation; Colgroup 마크업 컴포넌트
|
|
7
|
+
* @component
|
|
8
|
+
* @param {TableColgroupProps} props
|
|
9
|
+
* @param {string} [props.className] colgroup className
|
|
10
|
+
* @param {React.ReactNode} [props.children] col 목록
|
|
11
|
+
* @deprecated `Table.Container` 또는 native `<colgroup />` 사용을 권장한다.
|
|
12
|
+
*/
|
|
13
|
+
const TableColgroup = forwardRef<HTMLTableColElement, TableColgroupProps>(
|
|
14
|
+
({ className, children, ...colgroupProps }, ref) => {
|
|
15
|
+
return (
|
|
16
|
+
<colgroup
|
|
17
|
+
{...colgroupProps}
|
|
18
|
+
ref={ref}
|
|
19
|
+
className={clsx("table-colgroup", className)}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</colgroup>
|
|
23
|
+
);
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
TableColgroup.displayName = "TableFoundation.Colgroup";
|
|
28
|
+
|
|
29
|
+
export default TableColgroup;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { TableFootProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Table Foundation; Tfoot 마크업 컴포넌트
|
|
7
|
+
* @component
|
|
8
|
+
* @param {TableFootProps} props
|
|
9
|
+
* @param {string} [props.className] tfoot className
|
|
10
|
+
* @param {React.ReactNode} [props.children] tfoot 내부 콘텐츠
|
|
11
|
+
*/
|
|
12
|
+
const TableFoot = forwardRef<HTMLTableSectionElement, TableFootProps>(
|
|
13
|
+
({ className, children, ...footProps }, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<tfoot {...footProps} ref={ref} className={clsx("table-foot", className)}>
|
|
16
|
+
{children}
|
|
17
|
+
</tfoot>
|
|
18
|
+
);
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
TableFoot.displayName = "TableFoundation.Foot";
|
|
23
|
+
|
|
24
|
+
export default TableFoot;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { TableHeadProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Table Foundation; Thead 마크업 컴포넌트
|
|
7
|
+
* @component
|
|
8
|
+
* @param {TableHeadProps} props
|
|
9
|
+
* @param {string} [props.className] thead className
|
|
10
|
+
* @param {React.ReactNode} [props.children] thead 내부 콘텐츠
|
|
11
|
+
*/
|
|
12
|
+
const TableHead = forwardRef<HTMLTableSectionElement, TableHeadProps>(
|
|
13
|
+
({ className, children, ...headProps }, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<thead {...headProps} ref={ref} className={clsx("table-head", className)}>
|
|
16
|
+
{children}
|
|
17
|
+
</thead>
|
|
18
|
+
);
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
TableHead.displayName = "TableFoundation.Head";
|
|
23
|
+
|
|
24
|
+
export default TableHead;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { TableRootProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Table Foundation; Table Root 마크업 컴포넌트
|
|
7
|
+
* @component
|
|
8
|
+
* @param {TableRootProps} props
|
|
9
|
+
* @param {string} [props.className] table 루트 className
|
|
10
|
+
* @param {React.ReactNode} [props.children] table 내부 콘텐츠
|
|
11
|
+
*/
|
|
12
|
+
const TableRoot = forwardRef<HTMLTableElement, TableRootProps>(
|
|
13
|
+
({ className, children, role, layout = "line", ...tableProps }, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<table
|
|
16
|
+
{...tableProps}
|
|
17
|
+
ref={ref}
|
|
18
|
+
className={clsx("table", "table-container", className)}
|
|
19
|
+
// 변경: line/grid 스타일 축을 data attribute로 명시해 foundation.scss에서 분기한다.
|
|
20
|
+
data-layout={layout}
|
|
21
|
+
// 기본 접근성 role은 table로 고정하고, 외부에서 전달한 role이 있으면 우선한다.
|
|
22
|
+
role={role ?? "table"}
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
</table>
|
|
26
|
+
);
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
TableRoot.displayName = "TableFoundation.Root";
|
|
31
|
+
|
|
32
|
+
export default TableRoot;
|