@uniai-fe/uds-primitives 0.2.9 → 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 +415 -0
- package/package.json +2 -1
- package/src/components/calendar/types/calendar.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/markup/Default.tsx +6 -3
- package/src/components/select/markup/foundation/Base.tsx +1 -1
- package/src/components/select/markup/foundation/Icon.tsx +6 -1
- package/src/components/select/markup/multiple/Multiple.tsx +6 -3
- 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/props.ts +1 -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
|
@@ -9,6 +9,8 @@ import type { InputCalendarTriggerViewProps } from "../../types";
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Input Date trigger field.
|
|
12
|
+
* priority가 table인 경우 아이콘을 left 슬롯에 배치하고,
|
|
13
|
+
* 그 외 priority에서는 기존처럼 right 슬롯을 유지한다.
|
|
12
14
|
* @component
|
|
13
15
|
* @param {InputCalendarTriggerViewProps} props
|
|
14
16
|
* @param {string} [props.className] trigger className
|
|
@@ -16,6 +18,7 @@ import type { InputCalendarTriggerViewProps } from "../../types";
|
|
|
16
18
|
* @param {string} [props.displayValue] 표시 문자열
|
|
17
19
|
* @param {(event: MouseEvent<Element>) => void} [props.onClick] 클릭 핸들러
|
|
18
20
|
* @param {boolean} [props.disabled] disabled 여부
|
|
21
|
+
* @param {"primary" | "secondary" | "tertiary" | "table"} [props.priority] trigger input priority
|
|
19
22
|
* @param {string} [props.id] input id
|
|
20
23
|
* @param {string} [props.name] form name
|
|
21
24
|
* @param {UseFormRegisterReturn} [props.register] RHF register
|
|
@@ -31,6 +34,7 @@ const InputDateTrigger = forwardRef<
|
|
|
31
34
|
displayValue,
|
|
32
35
|
onClick,
|
|
33
36
|
disabled,
|
|
37
|
+
priority,
|
|
34
38
|
id,
|
|
35
39
|
name,
|
|
36
40
|
register,
|
|
@@ -55,19 +59,33 @@ const InputDateTrigger = forwardRef<
|
|
|
55
59
|
{...restProps}
|
|
56
60
|
ref={ref}
|
|
57
61
|
value={displayValue}
|
|
62
|
+
// PopOver.Trigger(asChild)가 주입한 `type="button"`으로 placeholder가 사라지는 문제를 막기 위해
|
|
63
|
+
// Date trigger는 항상 readOnly text input으로 고정한다.
|
|
64
|
+
type="text"
|
|
58
65
|
readOnly
|
|
59
66
|
disabled={disabled}
|
|
60
67
|
id={id}
|
|
61
68
|
name={name ?? register?.name}
|
|
62
69
|
register={register}
|
|
70
|
+
priority={priority}
|
|
63
71
|
placeholder={placeholder}
|
|
64
72
|
className={clsx("input-date-trigger-input", className)}
|
|
65
73
|
onClick={handleInputClick}
|
|
74
|
+
// table priority는 icon을 왼쪽 슬롯에 배치한다.
|
|
75
|
+
left={
|
|
76
|
+
priority === "table" ? (
|
|
77
|
+
<figure className="input-date-trigger-icon" aria-hidden="true">
|
|
78
|
+
<Calendar.Icon.Calendar />
|
|
79
|
+
</figure>
|
|
80
|
+
) : undefined
|
|
81
|
+
}
|
|
82
|
+
// 기본(priority != table)은 기존처럼 icon을 오른쪽 슬롯에 유지한다.
|
|
66
83
|
right={
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
84
|
+
priority === "table" ? undefined : (
|
|
85
|
+
<figure className="input-date-trigger-icon" aria-hidden="true">
|
|
86
|
+
<Calendar.Icon.Calendar />
|
|
87
|
+
</figure>
|
|
88
|
+
)
|
|
71
89
|
}
|
|
72
90
|
/>
|
|
73
91
|
);
|
|
@@ -29,15 +29,16 @@ import InputBaseUtil from "./Utility";
|
|
|
29
29
|
*
|
|
30
30
|
* @component
|
|
31
31
|
* @param {InputProps} props Input 컴포넌트 공통 props
|
|
32
|
-
* @param {"primary" | "secondary" | "tertiary"} [props.priority="primary"] 디자인 토큰 우선순위
|
|
32
|
+
* @param {"primary" | "secondary" | "tertiary" | "table"} [props.priority="primary"] 디자인 토큰 우선순위
|
|
33
33
|
* @param {"small" | "medium" | "large"} [props.size="medium"] 높이/타이포 세트
|
|
34
|
-
* @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.state="default"] 시각 상태
|
|
35
|
-
* @param {boolean} [props.block=false] true면 width 100%
|
|
34
|
+
* @param {"default" | "active" | "focused" | "success" | "error" | "disabled" | "loading"} [props.state="default"] 시각 상태
|
|
35
|
+
* @param {boolean} [props.block=false] true면 width 100% (`priority="table"`은 width 미지정 시 full 기본)
|
|
36
|
+
* @param {FormFieldWidth} [props.width] width preset
|
|
36
37
|
* @param {React.ReactNode} [props.left] 입력 왼쪽 슬롯(아이콘/텍스트)
|
|
37
38
|
* @param {React.ReactNode} [props.right] 입력 오른쪽 슬롯
|
|
38
|
-
* @param {React.ReactNode} [props.
|
|
39
|
-
* @param {React.ReactNode} [props.
|
|
40
|
-
* @param {React.ReactNode} [props.
|
|
39
|
+
* @param {React.ReactNode} [props.clear] 입력값 초기화 아이콘. 지정하지 않으면 기본 Reset 아이콘
|
|
40
|
+
* @param {React.ReactNode} [props.success] success 상태 아이콘 override
|
|
41
|
+
* @param {React.ReactNode} [props.error] error 상태 아이콘 override
|
|
41
42
|
* @param {string} [props.inputClassName] 실제 `<input>` 요소 className
|
|
42
43
|
* @param {string} [props.boxClassName] `.input-box` className
|
|
43
44
|
* @param {boolean} [props.disabled] native disabled
|
|
@@ -52,6 +53,7 @@ import InputBaseUtil from "./Utility";
|
|
|
52
53
|
* @param {string | number | readonly string[]} [props.value] 제어형 값
|
|
53
54
|
* @param {string | number | readonly string[]} [props.defaultValue] 비제어 초기값
|
|
54
55
|
* @param {string} [props.type="text"] native input type
|
|
56
|
+
* @param {boolean} [props.readOnly] native readOnly
|
|
55
57
|
*/
|
|
56
58
|
const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
57
59
|
(
|
|
@@ -84,6 +86,10 @@ const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
|
84
86
|
},
|
|
85
87
|
ref,
|
|
86
88
|
) => {
|
|
89
|
+
// table priority는 width 지정이 없으면 셀 가로폭을 기본으로 채운다.
|
|
90
|
+
const isTablePriority = priority === "table";
|
|
91
|
+
const resolvedBlock = block || (isTablePriority && width === undefined);
|
|
92
|
+
|
|
87
93
|
const generatedId = useId();
|
|
88
94
|
const registerRef = register?.ref;
|
|
89
95
|
const registerOnChange = register?.onChange;
|
|
@@ -174,7 +180,7 @@ const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
|
174
180
|
const widthAttr =
|
|
175
181
|
width !== undefined
|
|
176
182
|
? getFormFieldWidthAttr(width)
|
|
177
|
-
:
|
|
183
|
+
: resolvedBlock
|
|
178
184
|
? "full"
|
|
179
185
|
: undefined;
|
|
180
186
|
const widthValue =
|
|
@@ -191,13 +197,13 @@ const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
|
191
197
|
`input-priority-${priority}`,
|
|
192
198
|
`input-size-${size}`,
|
|
193
199
|
`input-state-${visualState}`,
|
|
194
|
-
|
|
200
|
+
resolvedBlock && "input-block",
|
|
195
201
|
className,
|
|
196
202
|
)}
|
|
197
203
|
data-priority={priority}
|
|
198
204
|
data-size={size}
|
|
199
205
|
data-state={visualState}
|
|
200
|
-
data-block={
|
|
206
|
+
data-block={resolvedBlock ? "true" : undefined}
|
|
201
207
|
{...(simulatedState ? { "data-simulated-state": simulatedState } : {})}
|
|
202
208
|
data-width={widthAttr}
|
|
203
209
|
style={containerStyle}
|
|
@@ -208,7 +214,7 @@ const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
|
208
214
|
`input-box-priority-${priority}`,
|
|
209
215
|
`input-box-size-${size}`,
|
|
210
216
|
`input-box-state-${visualState}`,
|
|
211
|
-
|
|
217
|
+
resolvedBlock && "input-box-block",
|
|
212
218
|
boxClassNameProp,
|
|
213
219
|
)}
|
|
214
220
|
data-slot="box"
|
|
@@ -218,7 +224,7 @@ const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
|
218
224
|
data-state={visualState}
|
|
219
225
|
data-priority={priority}
|
|
220
226
|
data-size={size}
|
|
221
|
-
data-block={
|
|
227
|
+
data-block={resolvedBlock ? "true" : undefined}
|
|
222
228
|
>
|
|
223
229
|
{/* 필드 컨트롤 wrapper; 슬롯과 input 정렬 */}
|
|
224
230
|
<div className="input-field-control">
|
|
@@ -242,6 +248,8 @@ const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
|
242
248
|
/>
|
|
243
249
|
</div>
|
|
244
250
|
<InputBaseUtil
|
|
251
|
+
// table priority는 success/error 상태 아이콘 대신 border만으로 상태를 표현한다.
|
|
252
|
+
priority={priority}
|
|
245
253
|
state={currentState}
|
|
246
254
|
isDisabled={isDisabled}
|
|
247
255
|
isFocused={isFocused}
|
|
@@ -9,23 +9,25 @@ import InputBaseSideSlot from "./SideSlot";
|
|
|
9
9
|
/**
|
|
10
10
|
* Input; 오른쪽 유틸리티 영역(wrapper)
|
|
11
11
|
* @component
|
|
12
|
-
* @param {
|
|
13
|
-
* @param {React.ReactNode} [props.
|
|
12
|
+
* @param {InputUtilityProps} props
|
|
13
|
+
* @param {React.ReactNode} [props.children] 오른쪽 슬롯 콘텐츠
|
|
14
14
|
* @param {React.ReactNode} [props.clear] clear 버튼 아이콘
|
|
15
15
|
* @param {React.ReactNode} [props.success] success 상태 아이콘 override
|
|
16
16
|
* @param {React.ReactNode} [props.error] error 상태 아이콘 override
|
|
17
|
-
* @param {
|
|
17
|
+
* @param {"primary" | "secondary" | "tertiary" | "table"} props.priority input priority
|
|
18
|
+
* @param {"default" | "active" | "focused" | "success" | "error" | "disabled" | "loading"} props.state 현재 input 상태
|
|
18
19
|
* @param {boolean} props.isDisabled disable 여부
|
|
19
20
|
* @param {boolean} props.isFocused focus 여부
|
|
20
21
|
* @param {boolean} props.hasValue 입력값 존재 여부
|
|
21
22
|
* @param {boolean} [props.readOnly] readOnly 여부
|
|
22
|
-
* @param {
|
|
23
|
+
* @param {(event: React.MouseEvent<HTMLButtonElement> | React.PointerEvent<HTMLButtonElement>) => void} [props.onClear] clear 버튼 클릭 핸들러
|
|
23
24
|
*/
|
|
24
25
|
export default function InputBaseUtil({
|
|
25
26
|
children: right,
|
|
26
27
|
clear,
|
|
27
28
|
success,
|
|
28
29
|
error,
|
|
30
|
+
priority,
|
|
29
31
|
state,
|
|
30
32
|
isDisabled,
|
|
31
33
|
isFocused,
|
|
@@ -42,6 +44,8 @@ export default function InputBaseUtil({
|
|
|
42
44
|
: state === "error"
|
|
43
45
|
? (error ?? baseStatusIcon)
|
|
44
46
|
: null;
|
|
47
|
+
// table priority는 상태를 border로만 표현하므로 status icon을 렌더하지 않는다.
|
|
48
|
+
const resolvedStatusIcon = priority === "table" ? null : statusIcon;
|
|
45
49
|
const clearIconNode = clear ?? InputStatusIcon.reset;
|
|
46
50
|
const showClearIcon = Boolean(
|
|
47
51
|
clearIconNode &&
|
|
@@ -50,7 +54,7 @@ export default function InputBaseUtil({
|
|
|
50
54
|
(isFocused || isClearInteracting),
|
|
51
55
|
);
|
|
52
56
|
|
|
53
|
-
if (!right && !showClearIcon && !
|
|
57
|
+
if (!right && !showClearIcon && !resolvedStatusIcon) {
|
|
54
58
|
return null;
|
|
55
59
|
}
|
|
56
60
|
|
|
@@ -91,13 +95,13 @@ export default function InputBaseUtil({
|
|
|
91
95
|
{clearIconNode}
|
|
92
96
|
</button>
|
|
93
97
|
) : null}
|
|
94
|
-
{
|
|
98
|
+
{resolvedStatusIcon ? (
|
|
95
99
|
<div
|
|
96
100
|
className="input-affix input-affix-status"
|
|
97
101
|
data-slot="status"
|
|
98
102
|
data-state={state}
|
|
99
103
|
>
|
|
100
|
-
{
|
|
104
|
+
{resolvedStatusIcon}
|
|
101
105
|
</div>
|
|
102
106
|
) : null}
|
|
103
107
|
</div>
|
|
@@ -21,6 +21,27 @@
|
|
|
21
21
|
pointer-events: none;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
.input-date-trigger-input.input-priority-table {
|
|
25
|
+
.input-field {
|
|
26
|
+
padding-inline: var(--spacing-padding-4);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.input-field-control {
|
|
30
|
+
gap: var(--spacing-gap-3);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.input-element {
|
|
34
|
+
font-size: var(--font-body-xsmall-size);
|
|
35
|
+
line-height: var(--font-body-xsmall-line-height);
|
|
36
|
+
font-weight: var(--font-body-xsmall-weight);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.input-date-trigger-icon {
|
|
40
|
+
// input date 아이콘 크기는 size/priority와 무관하게 공통 크기를 유지한다.
|
|
41
|
+
color: var(--color-label-alternative);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
24
45
|
.input-date-footer-template {
|
|
25
46
|
// footer 템플릿은 input 스킨에서만 관리한다.
|
|
26
47
|
display: grid;
|
|
@@ -154,6 +154,13 @@
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
&[data-priority="table"] {
|
|
158
|
+
// table priority는 default에서 border를 숨기고 상태(border-color)만 드러낸다.
|
|
159
|
+
border-radius: var(--input-table-radius-base);
|
|
160
|
+
border-color: var(--input-border-table-default-color);
|
|
161
|
+
background-color: transparent;
|
|
162
|
+
}
|
|
163
|
+
|
|
157
164
|
&:not([data-priority="secondary"]) {
|
|
158
165
|
&[data-state="active"],
|
|
159
166
|
&[data-state="focused"] {
|
|
@@ -252,6 +259,24 @@
|
|
|
252
259
|
min-height: var(--theme-size-medium-2);
|
|
253
260
|
}
|
|
254
261
|
|
|
262
|
+
.input-field[data-priority="table"][data-size="small"] .input-element {
|
|
263
|
+
font-size: var(--input-table-text-small-size);
|
|
264
|
+
line-height: var(--input-table-text-small-line-height);
|
|
265
|
+
font-weight: var(--input-table-text-small-weight);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.input-field[data-priority="table"][data-size="medium"] .input-element {
|
|
269
|
+
font-size: var(--input-table-text-medium-size);
|
|
270
|
+
line-height: var(--input-table-text-medium-line-height);
|
|
271
|
+
font-weight: var(--input-table-text-medium-weight);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.input-field[data-priority="table"][data-size="large"] .input-element {
|
|
275
|
+
font-size: var(--input-table-text-large-size);
|
|
276
|
+
line-height: var(--input-table-text-large-line-height);
|
|
277
|
+
font-weight: var(--input-table-text-large-weight);
|
|
278
|
+
}
|
|
279
|
+
|
|
255
280
|
.input-helper-text {
|
|
256
281
|
color: var(--input-helper-color);
|
|
257
282
|
font-size: var(--font-label-small-size);
|
|
@@ -362,6 +387,11 @@
|
|
|
362
387
|
&[data-priority="secondary"] {
|
|
363
388
|
background-color: transparent;
|
|
364
389
|
}
|
|
390
|
+
|
|
391
|
+
&[data-priority="table"] {
|
|
392
|
+
// table priority는 disabled 상태에서도 배경을 투명하게 유지한다.
|
|
393
|
+
background-color: transparent;
|
|
394
|
+
}
|
|
365
395
|
}
|
|
366
396
|
}
|
|
367
397
|
|
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
--input-default-gap: var(--spacing-gap-4);
|
|
14
14
|
--input-default-radius-base: var(--theme-radius-large-1);
|
|
15
15
|
--input-tertiary-radius-base: var(--theme-radius-large-2);
|
|
16
|
+
--input-table-radius-base: 0;
|
|
17
|
+
--input-table-text-small-size: var(--font-body-xxsmall-size);
|
|
18
|
+
--input-table-text-small-line-height: var(--font-body-xxsmall-line-height);
|
|
19
|
+
--input-table-text-small-weight: var(--font-body-xxsmall-weight);
|
|
20
|
+
--input-table-text-medium-size: var(--font-body-xsmall-size);
|
|
21
|
+
--input-table-text-medium-line-height: var(--font-body-xsmall-line-height);
|
|
22
|
+
--input-table-text-medium-weight: var(--font-body-xsmall-weight);
|
|
23
|
+
--input-table-text-large-size: var(--font-body-small-size);
|
|
24
|
+
--input-table-text-large-line-height: var(--font-body-small-line-height);
|
|
25
|
+
--input-table-text-large-weight: var(--font-body-small-weight);
|
|
16
26
|
|
|
17
27
|
/* Label/helper colors */
|
|
18
28
|
--input-label-color: var(--color-label-standard);
|
|
@@ -33,6 +43,7 @@
|
|
|
33
43
|
--input-border-width-emphasis: 1.4px;
|
|
34
44
|
--input-border-active-color: var(--color-blue-80);
|
|
35
45
|
--input-border-success-color: var(--color-blue-80);
|
|
46
|
+
--input-border-table-default-color: transparent;
|
|
36
47
|
/* error는 Figma 44% alpha */
|
|
37
48
|
--input-border-error-color: rgba(218, 29, 11, 0.44); // --color-feedback-error
|
|
38
49
|
--input-border-disabled-color: var(--color-border-standard-cool-gray);
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
CalendarOnChange,
|
|
8
8
|
CalendarValue,
|
|
9
9
|
} from "../../calendar";
|
|
10
|
+
import type { InputPriority } from "./foundation";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Calendar trigger(Input) 영역에서 필요한 속성 묶음.
|
|
@@ -17,6 +18,7 @@ import type {
|
|
|
17
18
|
* @property {(event: MouseEvent<Element>) => void} [onClick] trigger 클릭 핸들러
|
|
18
19
|
* @property {boolean} [disabled] disabled 여부
|
|
19
20
|
* @property {string} [placeholder] trigger 내부 placeholder
|
|
21
|
+
* @property {InputPriority} [priority] trigger input priority
|
|
20
22
|
*/
|
|
21
23
|
export interface InputCalendarTriggerProps {
|
|
22
24
|
/**
|
|
@@ -43,6 +45,11 @@ export interface InputCalendarTriggerProps {
|
|
|
43
45
|
* trigger 내부 placeholder
|
|
44
46
|
*/
|
|
45
47
|
placeholder?: string;
|
|
48
|
+
/**
|
|
49
|
+
* trigger input priority
|
|
50
|
+
* - table일 때 Trigger는 left icon 배치를 사용한다.
|
|
51
|
+
*/
|
|
52
|
+
priority?: InputPriority;
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
/**
|
|
@@ -69,6 +76,7 @@ export interface InputCalendarTriggerViewProps extends InputCalendarTriggerProps
|
|
|
69
76
|
* @property {string} [placeholder] 트리거 placeholder
|
|
70
77
|
* @property {boolean} [disabled] disabled 여부
|
|
71
78
|
* @property {(event: MouseEvent<Element>) => void} [onClick] 트리거 클릭 핸들러
|
|
79
|
+
* @property {InputPriority} [priority] trigger input priority
|
|
72
80
|
*/
|
|
73
81
|
export interface InputCalendarTriggerRenderProps {
|
|
74
82
|
/**
|
|
@@ -95,6 +103,11 @@ export interface InputCalendarTriggerRenderProps {
|
|
|
95
103
|
* 트리거 클릭 핸들러
|
|
96
104
|
*/
|
|
97
105
|
onClick?: (event: MouseEvent<Element>) => void;
|
|
106
|
+
/**
|
|
107
|
+
* trigger input priority
|
|
108
|
+
* - table일 때 Trigger는 left icon 배치를 사용한다.
|
|
109
|
+
*/
|
|
110
|
+
priority?: InputPriority;
|
|
98
111
|
}
|
|
99
112
|
|
|
100
113
|
/**
|
|
@@ -108,6 +121,7 @@ export interface InputCalendarTriggerRenderProps {
|
|
|
108
121
|
* @property {boolean} [readOnly] 읽기 전용 여부
|
|
109
122
|
* @property {boolean} [disabled] disabled 여부
|
|
110
123
|
* @property {CalendarDatePickerProps} [datePickerProps] Mantine DatePicker 직접 옵션
|
|
124
|
+
* @property {InputPriority} [priority] trigger input priority
|
|
111
125
|
* @property {ReactNode} [header] 커스텀 header 콘텐츠
|
|
112
126
|
* @property {ReactNode} [footer] 커스텀 footer 콘텐츠
|
|
113
127
|
* @property {unknown} [timePicker] TimePicker 확장용 예약 슬롯(현재 미구현)
|
|
@@ -168,6 +182,7 @@ export interface InputCalendarProps extends InputCalendarTriggerProps {
|
|
|
168
182
|
timePicker?: unknown;
|
|
169
183
|
/**
|
|
170
184
|
* calendar 열림 제어 여부
|
|
185
|
+
* - 지정되면 제어형(open state controlled)으로 동작한다.
|
|
171
186
|
*/
|
|
172
187
|
calendarOpened?: boolean;
|
|
173
188
|
/**
|
|
@@ -10,7 +10,7 @@ import type { FormFieldWidth } from "../../form/types/props";
|
|
|
10
10
|
/**
|
|
11
11
|
* input; priority option
|
|
12
12
|
*/
|
|
13
|
-
export type InputPriority = "primary" | "secondary" | "tertiary";
|
|
13
|
+
export type InputPriority = "primary" | "secondary" | "tertiary" | "table";
|
|
14
14
|
/**
|
|
15
15
|
* input; size option
|
|
16
16
|
*/
|
|
@@ -34,6 +34,7 @@ export const INPUT_PRIORITIES: InputPriority[] = [
|
|
|
34
34
|
"primary",
|
|
35
35
|
"secondary",
|
|
36
36
|
"tertiary",
|
|
37
|
+
"table",
|
|
37
38
|
];
|
|
38
39
|
/**
|
|
39
40
|
* size 축은 높이/타이포/spacing을 결정한다.
|
|
@@ -56,11 +57,11 @@ type NativeInputProps = ComponentPropsWithoutRef<"input">;
|
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* input; icon options
|
|
59
|
-
* @property {
|
|
60
|
-
* @property {
|
|
61
|
-
* @property {
|
|
62
|
-
* @property {
|
|
63
|
-
* @property {
|
|
60
|
+
* @property {ReactNode} [left] input 왼쪽 컨텐츠
|
|
61
|
+
* @property {ReactNode} [right] input 오른쪽 컨텐츠
|
|
62
|
+
* @property {ReactNode} [clear] input reset버튼 커스텀 컨텐츠
|
|
63
|
+
* @property {ReactNode} [success] input 입력상태 성공시 커스텀 컨텐츠
|
|
64
|
+
* @property {ReactNode} [error] input 입력상태 에러시 커스텀 컨텐츠
|
|
64
65
|
*/
|
|
65
66
|
export interface InputIcon {
|
|
66
67
|
/**
|
|
@@ -95,12 +96,13 @@ export interface InputIcon {
|
|
|
95
96
|
* @property {string} [inputClassName]
|
|
96
97
|
* @property {string} [boxClassName]
|
|
97
98
|
* @property {UseFormRegisterReturn} [register]
|
|
98
|
-
* @property {
|
|
99
|
-
* @property {
|
|
100
|
-
* @property {
|
|
101
|
-
* @property {
|
|
102
|
-
* @property {
|
|
99
|
+
* @property {ReactNode} [left] input 왼쪽 컨텐츠
|
|
100
|
+
* @property {ReactNode} [right] input 오른쪽 컨텐츠
|
|
101
|
+
* @property {ReactNode} [clear] input reset버튼 커스텀 컨텐츠
|
|
102
|
+
* @property {ReactNode} [success] input 입력상태 성공시 커스텀 컨텐츠
|
|
103
|
+
* @property {ReactNode} [error] input 입력상태 에러시 커스텀 컨텐츠
|
|
103
104
|
* @property {FormFieldWidth} [width] width preset 옵션
|
|
105
|
+
* @property {InputState} [data-simulated-state] Storybook 시각 상태 강제용
|
|
104
106
|
*/
|
|
105
107
|
export interface InputProps extends Omit<NativeInputProps, "size">, InputIcon {
|
|
106
108
|
/**
|
|
@@ -147,6 +149,7 @@ export interface InputProps extends Omit<NativeInputProps, "size">, InputIcon {
|
|
|
147
149
|
* @property {ReactNode} [clear] clear 버튼 아이콘
|
|
148
150
|
* @property {ReactNode} [success] success 상태 아이콘
|
|
149
151
|
* @property {ReactNode} [error] error 상태 아이콘
|
|
152
|
+
* @property {InputPriority} priority input priority
|
|
150
153
|
* @property {InputState} state 현재 상태
|
|
151
154
|
* @property {boolean} isDisabled disabled 여부
|
|
152
155
|
* @property {boolean} isFocused focus 여부
|
|
@@ -171,6 +174,10 @@ export interface InputUtilityProps {
|
|
|
171
174
|
* error 상태 아이콘
|
|
172
175
|
*/
|
|
173
176
|
error?: ReactNode;
|
|
177
|
+
/**
|
|
178
|
+
* priority 축
|
|
179
|
+
*/
|
|
180
|
+
priority: InputPriority;
|
|
174
181
|
/**
|
|
175
182
|
* 현재 input 상태
|
|
176
183
|
*/
|
|
@@ -51,7 +51,21 @@ export const serializeCalendarValue = (value: CalendarValue) => value ?? "";
|
|
|
51
51
|
* @param {CalendarValue} value 현재 값
|
|
52
52
|
* @returns {string} 표시 문자열
|
|
53
53
|
*/
|
|
54
|
-
export const formatTriggerValue = (
|
|
54
|
+
export const formatTriggerValue = (
|
|
55
|
+
value: CalendarValue,
|
|
56
|
+
format = DATE_FORMAT,
|
|
57
|
+
) => {
|
|
58
|
+
if (!value) {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const parsed = dayjs(value);
|
|
63
|
+
if (!parsed.isValid()) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return parsed.format(format);
|
|
68
|
+
};
|
|
55
69
|
|
|
56
70
|
/**
|
|
57
71
|
* columns 값을 Mantine numberOfColumns와 맞춘다.
|
|
@@ -18,7 +18,7 @@ import type { SelectDefaultComponentProps } from "../types/props";
|
|
|
18
18
|
* @param {SelectDropdownOption[]} [props.options] dropdown option 목록
|
|
19
19
|
* @param {string[]} [props.selectedOptionIds] 선택된 option id 리스트
|
|
20
20
|
* @param {(option: SelectDropdownOption) => void} [props.onOptionSelect] option 선택 콜백
|
|
21
|
-
* @param {"primary" | "secondary"} [props.priority="primary"] priority 스케일
|
|
21
|
+
* @param {"primary" | "secondary" | "table"} [props.priority="primary"] priority 스케일
|
|
22
22
|
* @param {"small" | "medium" | "large"} [props.size="medium"] size 스케일
|
|
23
23
|
* @param {"default" | "focused" | "disabled"} [props.state="default"] 시각 상태
|
|
24
24
|
* @param {boolean} [props.block] block 여부
|
|
@@ -65,6 +65,9 @@ const SelectDefault = forwardRef<HTMLElement, SelectDefaultComponentProps>(
|
|
|
65
65
|
},
|
|
66
66
|
ref,
|
|
67
67
|
) => {
|
|
68
|
+
// 변경: table priority는 width 미지정 시 기본 full width를 사용한다.
|
|
69
|
+
const resolvedBlock =
|
|
70
|
+
block || (priority === "table" && width === undefined);
|
|
68
71
|
const resolvedSelectedIds = selectedOptionIds ?? [];
|
|
69
72
|
|
|
70
73
|
const resolvedDisplayLabel =
|
|
@@ -96,7 +99,7 @@ const SelectDefault = forwardRef<HTMLElement, SelectDefaultComponentProps>(
|
|
|
96
99
|
return (
|
|
97
100
|
<Container
|
|
98
101
|
className={clsx("select-trigger-container", className)}
|
|
99
|
-
block={
|
|
102
|
+
block={resolvedBlock}
|
|
100
103
|
width={width}
|
|
101
104
|
>
|
|
102
105
|
<Dropdown.Root
|
|
@@ -112,7 +115,7 @@ const SelectDefault = forwardRef<HTMLElement, SelectDefaultComponentProps>(
|
|
|
112
115
|
priority={priority}
|
|
113
116
|
size={size}
|
|
114
117
|
state={disabled ? "disabled" : state}
|
|
115
|
-
block={
|
|
118
|
+
block={resolvedBlock}
|
|
116
119
|
open={dropdownOpen}
|
|
117
120
|
disabled={disabled}
|
|
118
121
|
buttonType={buttonType}
|
|
@@ -11,7 +11,7 @@ import type { SelectTriggerBaseProps } from "../../types/trigger";
|
|
|
11
11
|
* Select Foundation; Trigger Base 슬롯 렌더링 컴포넌트
|
|
12
12
|
* @component
|
|
13
13
|
* @param {SelectTriggerBaseProps} props trigger base props
|
|
14
|
-
* @param {"primary" | "secondary"} [props.priority="primary"] 스타일 우선순위
|
|
14
|
+
* @param {"primary" | "secondary" | "table"} [props.priority="primary"] 스타일 우선순위
|
|
15
15
|
* @param {"small" | "medium" | "large"} [props.size="medium"] 높이 스케일
|
|
16
16
|
* @param {"default" | "focused" | "disabled"} [props.state="default"] 시각 상태
|
|
17
17
|
* @param {boolean} [props.open=false] dropdown open 상태
|
|
@@ -41,10 +41,13 @@ const SelectChevronSecondaryIcon: SelectIconSizeMap = {
|
|
|
41
41
|
* Select; Chevron 아이콘 컬렉션
|
|
42
42
|
* - primary (small, medium, large)
|
|
43
43
|
* - secondary (small, medium, large)
|
|
44
|
+
* - table (small, medium, large)
|
|
44
45
|
*/
|
|
45
46
|
const SelectChevronIcon: SelectIconPriorityMap = {
|
|
46
47
|
primary: SelectChevronPrimaryIcon,
|
|
47
48
|
secondary: SelectChevronSecondaryIcon,
|
|
49
|
+
// 변경: table priority는 secondary chevron 자산을 재사용한다.
|
|
50
|
+
table: SelectChevronSecondaryIcon,
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
/**
|
|
@@ -61,10 +64,12 @@ const SelectMultipleRemoveIcon: SelectIconSizeMap = {
|
|
|
61
64
|
|
|
62
65
|
/**
|
|
63
66
|
* Select; Remove 아이콘 컬렉션
|
|
64
|
-
* - primary (small, medium, large)
|
|
67
|
+
* - primary/secondary/table (small, medium, large)
|
|
65
68
|
*/
|
|
66
69
|
const SelectRemoveIcon: SelectIconRemovePriorityMap = {
|
|
67
70
|
primary: SelectMultipleRemoveIcon,
|
|
71
|
+
secondary: SelectMultipleRemoveIcon,
|
|
72
|
+
table: SelectMultipleRemoveIcon,
|
|
68
73
|
};
|
|
69
74
|
|
|
70
75
|
/**
|
|
@@ -22,7 +22,7 @@ import { useSelectDropdownOpenState } from "../../hooks";
|
|
|
22
22
|
* @param {(option: SelectDropdownOption) => void} [props.onOptionSelect] option 선택 콜백
|
|
23
23
|
* @param {React.ReactNode} [props.displayLabel] fallback 라벨
|
|
24
24
|
* @param {React.ReactNode} [props.placeholder] placeholder 텍스트
|
|
25
|
-
* @param {"primary" | "secondary"} [props.priority="primary"] priority scale
|
|
25
|
+
* @param {"primary" | "secondary" | "table"} [props.priority="primary"] priority scale
|
|
26
26
|
* @param {"small" | "medium" | "large"} [props.size="medium"] size scale
|
|
27
27
|
* @param {"default" | "focused" | "disabled"} [props.state="default"] 시각 상태
|
|
28
28
|
* @param {boolean} [props.block] block 여부
|
|
@@ -72,6 +72,9 @@ const SelectMultipleTrigger = forwardRef<
|
|
|
72
72
|
},
|
|
73
73
|
ref,
|
|
74
74
|
) => {
|
|
75
|
+
// 변경: table priority는 width 미지정 시 기본 full width를 사용한다.
|
|
76
|
+
const resolvedBlock =
|
|
77
|
+
block || (priority === "table" && width === undefined);
|
|
75
78
|
// hook dependency 안정화를 위해 memoized selected id 배열을 유지한다.
|
|
76
79
|
const resolvedSelectedIds = useMemo(
|
|
77
80
|
() => selectedOptionIds ?? [],
|
|
@@ -128,7 +131,7 @@ const SelectMultipleTrigger = forwardRef<
|
|
|
128
131
|
return (
|
|
129
132
|
<Container
|
|
130
133
|
className={clsx("select-trigger-multiple", className)}
|
|
131
|
-
block={
|
|
134
|
+
block={resolvedBlock}
|
|
132
135
|
width={width}
|
|
133
136
|
>
|
|
134
137
|
<Dropdown.Root
|
|
@@ -144,7 +147,7 @@ const SelectMultipleTrigger = forwardRef<
|
|
|
144
147
|
priority={priority}
|
|
145
148
|
size={size}
|
|
146
149
|
state={disabled ? "disabled" : state}
|
|
147
|
-
block={
|
|
150
|
+
block={resolvedBlock}
|
|
148
151
|
open={dropdownOpen}
|
|
149
152
|
multiple
|
|
150
153
|
disabled={disabled}
|