@uniai-fe/uds-primitives 0.12.7 → 0.12.9
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 +15 -2
- package/package.json +4 -4
- package/src/components/alternate/layout/Layout.tsx +3 -0
- package/src/components/alternate/layout/Text.tsx +23 -0
- package/src/components/alternate/styles/layout.scss +11 -0
- package/src/components/alternate/styles/unit.scss +5 -0
- package/src/components/alternate/styles/variables.scss +1 -2
- package/src/components/alternate/types/layout.ts +16 -0
- package/src/components/input/markup/date/Template.tsx +83 -33
- package/src/components/input/markup/date/Trigger.tsx +28 -12
- package/src/components/input/markup/date/range/Template.tsx +94 -35
- package/src/components/input/markup/time/Template.tsx +118 -5
- package/src/components/input/markup/time/Trigger.tsx +35 -2
- package/src/components/input/types/date.ts +176 -33
- package/src/components/input/types/time.ts +10 -4
- package/src/components/time-picker/markup/Footer.tsx +5 -5
- package/src/components/time-picker/markup/HourSection.tsx +7 -7
- package/src/components/time-picker/markup/MinuteSection.tsx +5 -5
- package/src/components/time-picker/markup/Summary.tsx +2 -2
- package/src/components/time-picker/markup/Template.tsx +11 -11
- package/src/components/time-picker/types/time-picker.ts +6 -0
- package/src/components/time-picker/utils/time.ts +21 -9
package/dist/styles.css
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
--alternate-unit-text-color: var(--color-cool-gray-70);
|
|
4
4
|
--alternate-unit-text-font-size: 1.4rem;
|
|
5
5
|
--alternate-unit-text-line-height: 1.5;
|
|
6
|
-
--alternate-
|
|
6
|
+
--alternate-figure-text-gap-ratio: 0.344444;
|
|
7
7
|
--alternate-loading-icon-color: var(--color-primary-default);
|
|
8
8
|
--alternate-loading-icon-small-size: 2.4rem;
|
|
9
9
|
--alternate-loading-icon-medium-size: 3.6rem;
|
|
10
10
|
--alternate-loading-icon-large-size: 5.2rem;
|
|
11
11
|
--alternate-layout-min-block-size: 320px;
|
|
12
|
-
--alternate-layout-gap: var(--spacing-gap-7);
|
|
13
12
|
--alternate-layout-content-gap: var(--spacing-gap-4);
|
|
14
13
|
--alternate-layout-figure-size: 120px;
|
|
15
14
|
--alternate-layout-title-color: var(--color-label-strong);
|
|
@@ -1045,6 +1044,10 @@
|
|
|
1045
1044
|
}
|
|
1046
1045
|
|
|
1047
1046
|
.alternate {
|
|
1047
|
+
--alternate-unit-gap: calc(
|
|
1048
|
+
var(--alternate-loading-icon-small-size) *
|
|
1049
|
+
var(--alternate-figure-text-gap-ratio)
|
|
1050
|
+
);
|
|
1048
1051
|
width: 100%;
|
|
1049
1052
|
height: 100%;
|
|
1050
1053
|
display: flex;
|
|
@@ -1102,6 +1105,9 @@
|
|
|
1102
1105
|
}
|
|
1103
1106
|
|
|
1104
1107
|
.alternate-layout {
|
|
1108
|
+
--alternate-layout-gap: calc(
|
|
1109
|
+
var(--alternate-layout-figure-size) * var(--alternate-figure-text-gap-ratio)
|
|
1110
|
+
);
|
|
1105
1111
|
display: flex;
|
|
1106
1112
|
flex-direction: column;
|
|
1107
1113
|
align-items: center;
|
|
@@ -1122,6 +1128,13 @@
|
|
|
1122
1128
|
margin: 0;
|
|
1123
1129
|
}
|
|
1124
1130
|
|
|
1131
|
+
.alternate-layout-text {
|
|
1132
|
+
display: flex;
|
|
1133
|
+
flex-direction: column;
|
|
1134
|
+
align-items: center;
|
|
1135
|
+
gap: var(--alternate-layout-content-gap);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1125
1138
|
.alternate-layout-title {
|
|
1126
1139
|
margin: 0;
|
|
1127
1140
|
color: var(--alternate-layout-title-color);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniai-fe/uds-primitives",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.9",
|
|
4
4
|
"description": "UNIAI Design System; Primitives Components Package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -87,11 +87,11 @@
|
|
|
87
87
|
"react-hook-form": "^7.86.0",
|
|
88
88
|
"sass": "^1.102.0",
|
|
89
89
|
"typescript": "6.0.3",
|
|
90
|
-
"@uniai-fe/next-devkit": "0.4.1",
|
|
91
90
|
"@uniai-fe/eslint-config": "0.4.3",
|
|
92
|
-
"@uniai-fe/
|
|
91
|
+
"@uniai-fe/uds-foundation": "0.6.0",
|
|
93
92
|
"@uniai-fe/util-functions": "0.4.3",
|
|
94
|
-
"@uniai-fe/
|
|
93
|
+
"@uniai-fe/next-devkit": "0.4.1",
|
|
94
|
+
"@uniai-fe/tsconfig": "0.2.0"
|
|
95
95
|
},
|
|
96
96
|
"scripts": {
|
|
97
97
|
"check:pre-commit": "pnpm --dir ../../.. run check:pre-commit",
|
|
@@ -2,6 +2,7 @@ import AlternateLayoutButton from "./Button";
|
|
|
2
2
|
import AlternateLayoutContainer from "./Container";
|
|
3
3
|
import AlternateLayoutContents from "./Contents";
|
|
4
4
|
import AlternateLayoutFigure from "./Figure";
|
|
5
|
+
import AlternateLayoutText from "./Text";
|
|
5
6
|
import AlternateLayoutTextButton from "./TextButton";
|
|
6
7
|
import AlternateLayoutTitle from "./Title";
|
|
7
8
|
|
|
@@ -10,6 +11,7 @@ import AlternateLayoutTitle from "./Title";
|
|
|
10
11
|
* @desc
|
|
11
12
|
* - `Container`: 화면 상태 조합 루트다.
|
|
12
13
|
* - `Figure`: 도입 측이 제어하는 visual 영역이다.
|
|
14
|
+
* - `Text`: 제목과 본문을 묶는 텍스트 영역이다.
|
|
13
15
|
* - `Title`: 제목 텍스트 영역이다.
|
|
14
16
|
* - `Contents`: 본문 텍스트 영역이다.
|
|
15
17
|
* - `TextButton`: paragraph 내부 text action이다.
|
|
@@ -18,6 +20,7 @@ import AlternateLayoutTitle from "./Title";
|
|
|
18
20
|
const AlternateLayout = {
|
|
19
21
|
Container: AlternateLayoutContainer,
|
|
20
22
|
Figure: AlternateLayoutFigure,
|
|
23
|
+
Text: AlternateLayoutText,
|
|
21
24
|
Title: AlternateLayoutTitle,
|
|
22
25
|
Contents: AlternateLayoutContents,
|
|
23
26
|
TextButton: AlternateLayoutTextButton,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import type { AlternateLayoutTextProps } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Alternate Layout Text; 제목과 본문을 묶는 텍스트 영역
|
|
6
|
+
* @component
|
|
7
|
+
* @param {AlternateLayoutTextProps} props
|
|
8
|
+
* @param {string} [props.className] 텍스트 영역 className override다.
|
|
9
|
+
* @param {React.ReactNode} [props.children] 제목과 본문 콘텐츠다.
|
|
10
|
+
* @example
|
|
11
|
+
* <Alternate.Layout.Text>
|
|
12
|
+
* <Alternate.Layout.Title>데이터가 없습니다.</Alternate.Layout.Title>
|
|
13
|
+
* <Alternate.Layout.Contents>다른 조건으로 검색해 주세요.</Alternate.Layout.Contents>
|
|
14
|
+
* </Alternate.Layout.Text>
|
|
15
|
+
*/
|
|
16
|
+
export default function AlternateLayoutText({
|
|
17
|
+
className,
|
|
18
|
+
children,
|
|
19
|
+
}: AlternateLayoutTextProps) {
|
|
20
|
+
return (
|
|
21
|
+
<div className={clsx("alternate-layout-text", className)}>{children}</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
.alternate-layout {
|
|
2
|
+
--alternate-layout-gap: calc(
|
|
3
|
+
var(--alternate-layout-figure-size) * var(--alternate-figure-text-gap-ratio)
|
|
4
|
+
);
|
|
5
|
+
|
|
2
6
|
display: flex;
|
|
3
7
|
flex-direction: column;
|
|
4
8
|
align-items: center;
|
|
@@ -19,6 +23,13 @@
|
|
|
19
23
|
margin: 0;
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
.alternate-layout-text {
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: var(--alternate-layout-content-gap);
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
.alternate-layout-title {
|
|
23
34
|
margin: 0;
|
|
24
35
|
color: var(--alternate-layout-title-color);
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
--alternate-unit-text-color: var(--color-cool-gray-70);
|
|
3
3
|
--alternate-unit-text-font-size: 1.4rem;
|
|
4
4
|
--alternate-unit-text-line-height: 1.5;
|
|
5
|
-
--alternate-
|
|
5
|
+
--alternate-figure-text-gap-ratio: 0.344444;
|
|
6
6
|
--alternate-loading-icon-color: var(--color-primary-default);
|
|
7
7
|
--alternate-loading-icon-small-size: 2.4rem;
|
|
8
8
|
--alternate-loading-icon-medium-size: 3.6rem;
|
|
9
9
|
--alternate-loading-icon-large-size: 5.2rem;
|
|
10
10
|
|
|
11
11
|
--alternate-layout-min-block-size: 320px;
|
|
12
|
-
--alternate-layout-gap: var(--spacing-gap-7);
|
|
13
12
|
--alternate-layout-content-gap: var(--spacing-gap-4);
|
|
14
13
|
--alternate-layout-figure-size: 120px;
|
|
15
14
|
--alternate-layout-title-color: var(--color-label-strong);
|
|
@@ -38,6 +38,22 @@ export interface AlternateLayoutFigureProps {
|
|
|
38
38
|
children?: ReactNode;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Alternate Layout Text Props; 제목과 본문을 묶는 텍스트 영역 props
|
|
43
|
+
* @property {string} [className] 텍스트 영역 className override다.
|
|
44
|
+
* @property {ReactNode} [children] 제목과 본문 콘텐츠다.
|
|
45
|
+
*/
|
|
46
|
+
export interface AlternateLayoutTextProps {
|
|
47
|
+
/**
|
|
48
|
+
* 텍스트 영역 className override다.
|
|
49
|
+
*/
|
|
50
|
+
className?: string;
|
|
51
|
+
/**
|
|
52
|
+
* 제목과 본문 콘텐츠다.
|
|
53
|
+
*/
|
|
54
|
+
children?: ReactNode;
|
|
55
|
+
}
|
|
56
|
+
|
|
41
57
|
/**
|
|
42
58
|
* Alternate Layout Title Props; 제목 텍스트 props
|
|
43
59
|
* @property {ElementType} [as] 렌더링할 제목 요소다. 기본값은 strong이다.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
ChangeEvent,
|
|
5
|
+
FocusEvent as ReactFocusEvent,
|
|
6
|
+
MouseEvent as ReactMouseEvent,
|
|
7
|
+
} from "react";
|
|
4
8
|
import { forwardRef, useCallback, useMemo, useState } from "react";
|
|
5
9
|
import { useUncontrolled } from "@mantine/hooks";
|
|
6
10
|
import { Calendar } from "../../../calendar";
|
|
@@ -26,30 +30,39 @@ const INPUT_DATE_TABLE_FORMAT = "YY-MM-DD";
|
|
|
26
30
|
* placeholder는 format과 별도 props로 처리되며, format 변경으로 placeholder가 자동 치환되지는 않는다.
|
|
27
31
|
* @component
|
|
28
32
|
* @param {InputCalendarProps} props
|
|
29
|
-
* @
|
|
30
|
-
* @
|
|
31
|
-
* @
|
|
32
|
-
* @
|
|
33
|
-
* @
|
|
34
|
-
* @
|
|
35
|
-
* @
|
|
36
|
-
* @
|
|
37
|
-
* @
|
|
38
|
-
* @
|
|
39
|
-
* @
|
|
40
|
-
* @
|
|
41
|
-
* @
|
|
42
|
-
* @
|
|
43
|
-
* @
|
|
44
|
-
* @
|
|
45
|
-
* @
|
|
46
|
-
* @
|
|
47
|
-
* @
|
|
48
|
-
* @
|
|
49
|
-
* @
|
|
50
|
-
* @
|
|
51
|
-
* @
|
|
52
|
-
* @
|
|
33
|
+
* @property {"date" | "date-time" | "time"} [props.mode="date"] Calendar layout mode. 선택 body는 date로 유지된다.
|
|
34
|
+
* @property {1 | 2} [props.columns=1] 동시 노출 달력 수
|
|
35
|
+
* @property {string | null} [props.value] 제어형 날짜 값
|
|
36
|
+
* @property {string | null} [props.defaultValue] 비제어 초기 날짜 값
|
|
37
|
+
* @property {(value: string | null) => void} [props.onChange] 값 변경 이벤트
|
|
38
|
+
* @property {(value: string | null) => void} [props.onValueChange] onChange alias
|
|
39
|
+
* @property {boolean} [props.readOnly] 읽기 전용 여부
|
|
40
|
+
* @property {boolean} [props.disabled] 비활성화 여부
|
|
41
|
+
* @property {CalendarDatePickerProps} [props.datePickerProps] Mantine DatePicker 옵션
|
|
42
|
+
* @property {string} [props.name] hidden input form name
|
|
43
|
+
* @property {string} [props.form] hidden input form id
|
|
44
|
+
* @property {UseFormRegisterReturn} [props.register] hidden input RHF register
|
|
45
|
+
* @property {boolean} [props.required] hidden input required 여부
|
|
46
|
+
* @property {InputCalendarHiddenInputProps} [props.hiddenInputProps] Template 고정값을 제외한 hidden input native props
|
|
47
|
+
* @property {string} [props.placeholder="YYYY-MM-DD"] placeholder
|
|
48
|
+
* @property {"primary" | "secondary" | "tertiary" | "table"} [props.priority="primary"] trigger input priority
|
|
49
|
+
* @property {"small" | "medium" | "large"} [props.size="medium"] trigger input size
|
|
50
|
+
* @property {"default" | "active" | "focused" | "success" | "error" | "disabled" | "loading"} [props.state="default"] trigger input state
|
|
51
|
+
* @property {boolean} [props.block=false] trigger width 100% 여부
|
|
52
|
+
* @property {"full" | "fit" | "fill" | "auto" | number | string} [props.width] trigger width preset 또는 custom width
|
|
53
|
+
* @property {(event: FocusEvent<HTMLInputElement>) => void} [props.onFocus] trigger focus 핸들러
|
|
54
|
+
* @property {(event: FocusEvent<HTMLInputElement>) => void} [props.onBlur] trigger blur 핸들러
|
|
55
|
+
* @property {ReactNode} [props.header] 패널 header 콘텐츠
|
|
56
|
+
* @property {ReactNode} [props.footer] 패널 footer 콘텐츠
|
|
57
|
+
* @property {InputCalendarTexts} [props.texts] 기본 Date 문구
|
|
58
|
+
* @property {unknown} [props.timePicker] 미구현 compatibility prop
|
|
59
|
+
* @property {boolean} [props.calendarOpened] calendar 열림 제어 상태
|
|
60
|
+
* @property {(open: boolean) => void} [props.onCalendarOpen] calendar 열림 변경 이벤트
|
|
61
|
+
* @property {(event: MouseEvent<Element>) => void} [props.onClick] trigger 클릭 핸들러
|
|
62
|
+
* @property {string} [props.id] trigger id
|
|
63
|
+
* @property {ReactNode} [props.trigger] 커스텀 trigger 슬롯
|
|
64
|
+
* @property {(props: InputCalendarTriggerRenderProps) => ReactNode} [props.renderTrigger] 커스텀 trigger 렌더 함수
|
|
65
|
+
* @desc 날짜 표시 trigger, Calendar panel과 YYYY-MM-DD hidden form storage를 조합한다.
|
|
53
66
|
*/
|
|
54
67
|
const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
55
68
|
(
|
|
@@ -64,10 +77,18 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
64
77
|
disabled,
|
|
65
78
|
datePickerProps,
|
|
66
79
|
name,
|
|
80
|
+
form,
|
|
67
81
|
register,
|
|
82
|
+
required,
|
|
83
|
+
hiddenInputProps,
|
|
68
84
|
placeholder = "YYYY-MM-DD",
|
|
69
85
|
priority = "primary",
|
|
86
|
+
size = "medium",
|
|
70
87
|
state = "default",
|
|
88
|
+
block = false,
|
|
89
|
+
width,
|
|
90
|
+
onFocus,
|
|
91
|
+
onBlur,
|
|
71
92
|
header,
|
|
72
93
|
footer,
|
|
73
94
|
texts,
|
|
@@ -88,7 +109,7 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
88
109
|
* Input Date Template; Calendar open 상태 변경 전달 함수.
|
|
89
110
|
* 비제어 사용을 위해 내부 상태를 갱신하고, 제어형 사용을 위해 외부 owner에게 next open 값을 전달한다.
|
|
90
111
|
* @param {boolean} nextOpen 다음 calendar open 상태
|
|
91
|
-
* @
|
|
112
|
+
* @return {void}
|
|
92
113
|
*/
|
|
93
114
|
const handleCalendarOpenChange = useCallback(
|
|
94
115
|
(nextOpen: boolean) => {
|
|
@@ -113,7 +134,7 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
113
134
|
* Input Date Template; RHF hidden input 변경 이벤트 동기화 함수.
|
|
114
135
|
* trigger 표시값과 form 저장값을 분리하기 위해 CalendarValue를 직렬화한 synthetic change를 register에 전달한다.
|
|
115
136
|
* @param {CalendarValue} nextValue 다음 calendar 선택 값
|
|
116
|
-
* @
|
|
137
|
+
* @return {void}
|
|
117
138
|
*/
|
|
118
139
|
const emitRegisterChange = useCallback(
|
|
119
140
|
(nextValue: CalendarValue) => {
|
|
@@ -140,7 +161,7 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
140
161
|
* Input Date Template; calendar value 갱신 함수.
|
|
141
162
|
* 내부/제어형 value pipeline을 갱신한 뒤 RHF register 저장값을 같은 CalendarValue 기준으로 동기화한다.
|
|
142
163
|
* @param {CalendarValue} nextValue 다음 calendar 선택 값
|
|
143
|
-
* @
|
|
164
|
+
* @return {void}
|
|
144
165
|
*/
|
|
145
166
|
const updateValue = useCallback(
|
|
146
167
|
(nextValue: CalendarValue) => {
|
|
@@ -164,17 +185,33 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
164
185
|
* Input Date Template; trigger click 위임 함수.
|
|
165
186
|
* Calendar Root의 PopOver toggle은 asChild trigger props가 담당하고, 이 함수는 소비자가 넘긴 trigger onClick만 보존한다.
|
|
166
187
|
* @param {ReactMouseEvent<Element>} event trigger click event
|
|
167
|
-
* @
|
|
188
|
+
* @return {void}
|
|
168
189
|
*/
|
|
169
190
|
const handleTriggerClick = (event: ReactMouseEvent<Element>) => {
|
|
170
191
|
triggerOnClick?.(event);
|
|
171
192
|
};
|
|
172
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Input Date Template; trigger blur와 RHF touched 상태 동기화 함수.
|
|
196
|
+
* 표시 trigger는 form name을 소유하지 않으므로 직렬화된 hidden input 값을 synthetic blur event로 전달한다.
|
|
197
|
+
* @utility
|
|
198
|
+
* @param {ReactFocusEvent<HTMLInputElement>} event trigger blur event
|
|
199
|
+
* @desc 소비자 blur callback과 hidden input register blur를 같은 날짜 값으로 동기화한다.
|
|
200
|
+
* @return {void}
|
|
201
|
+
*/
|
|
202
|
+
const handleTriggerBlur = (event: ReactFocusEvent<HTMLInputElement>) => {
|
|
203
|
+
register?.onBlur({
|
|
204
|
+
target: { name: register.name, value: serializedCalendarValue },
|
|
205
|
+
type: "blur",
|
|
206
|
+
});
|
|
207
|
+
onBlur?.(event);
|
|
208
|
+
};
|
|
209
|
+
|
|
173
210
|
/**
|
|
174
211
|
* Input Date Template; Calendar Core change adapter 함수.
|
|
175
212
|
* Calendar.Root의 onChange 값을 Template value/RHF 동기화 pipeline으로 연결한다.
|
|
176
213
|
* @param {CalendarValue} nextValue 다음 calendar 선택 값
|
|
177
|
-
* @
|
|
214
|
+
* @return {void}
|
|
178
215
|
*/
|
|
179
216
|
const handleCalendarChange = (nextValue: CalendarValue) => {
|
|
180
217
|
updateValue(nextValue);
|
|
@@ -201,7 +238,12 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
201
238
|
readOnly,
|
|
202
239
|
onClick: handleTriggerClick,
|
|
203
240
|
priority,
|
|
241
|
+
size,
|
|
204
242
|
state,
|
|
243
|
+
block,
|
|
244
|
+
width,
|
|
245
|
+
onFocus,
|
|
246
|
+
onBlur: handleTriggerBlur,
|
|
205
247
|
};
|
|
206
248
|
|
|
207
249
|
const triggerNode = trigger ?? renderTrigger?.(triggerRenderProps) ?? (
|
|
@@ -214,6 +256,11 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
214
256
|
readOnly={readOnly}
|
|
215
257
|
onClick={handleTriggerClick}
|
|
216
258
|
priority={priority}
|
|
259
|
+
size={size}
|
|
260
|
+
block={block}
|
|
261
|
+
width={width}
|
|
262
|
+
onFocus={onFocus}
|
|
263
|
+
onBlur={handleTriggerBlur}
|
|
217
264
|
/>
|
|
218
265
|
);
|
|
219
266
|
|
|
@@ -228,7 +275,7 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
228
275
|
readOnly={readOnly}
|
|
229
276
|
value={calendarValue}
|
|
230
277
|
onChange={handleCalendarChange}
|
|
231
|
-
//
|
|
278
|
+
// Mantine DatePicker는 valueFormat prop을 지원하지 않으므로 옵션을 그대로 전달한다.
|
|
232
279
|
datePickerProps={datePickerProps}
|
|
233
280
|
header={header}
|
|
234
281
|
footer={footerContent}
|
|
@@ -239,11 +286,14 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
239
286
|
</Calendar.Root>
|
|
240
287
|
{(register?.name || name) && (
|
|
241
288
|
<input
|
|
242
|
-
//
|
|
289
|
+
// trigger 표시값과 form 저장값을 분리해 hidden input만 form에 참여한다.
|
|
290
|
+
{...hiddenInputProps}
|
|
291
|
+
{...register}
|
|
243
292
|
type="hidden"
|
|
244
293
|
value={serializedCalendarValue}
|
|
245
294
|
name={register?.name ?? name}
|
|
246
|
-
{
|
|
295
|
+
form={form ?? hiddenInputProps?.form}
|
|
296
|
+
required={required ?? hiddenInputProps?.required}
|
|
247
297
|
/>
|
|
248
298
|
)}
|
|
249
299
|
</>
|
|
@@ -19,17 +19,23 @@ import type { InputCalendarTriggerViewProps } from "../../types";
|
|
|
19
19
|
* 그 외 priority에서는 기존처럼 right 슬롯을 유지한다.
|
|
20
20
|
* @component
|
|
21
21
|
* @param {InputCalendarTriggerViewProps} props
|
|
22
|
-
* @
|
|
23
|
-
* @
|
|
24
|
-
* @
|
|
25
|
-
* @
|
|
26
|
-
* @
|
|
27
|
-
* @
|
|
28
|
-
* @
|
|
29
|
-
* @
|
|
30
|
-
* @
|
|
31
|
-
* @
|
|
32
|
-
* @
|
|
22
|
+
* @property {string} [props.className] trigger className
|
|
23
|
+
* @property {string} [props.placeholder] placeholder
|
|
24
|
+
* @property {string} [props.displayValue] 표시 문자열
|
|
25
|
+
* @property {(event: MouseEvent<Element>) => void} [props.onClick] 클릭 핸들러
|
|
26
|
+
* @property {boolean} [props.disabled] disabled 여부
|
|
27
|
+
* @property {boolean} [props.readOnly] readOnly 여부
|
|
28
|
+
* @property {"primary" | "secondary" | "tertiary" | "table"} [props.priority] trigger input priority
|
|
29
|
+
* @property {"small" | "medium" | "large"} [props.size] trigger input size
|
|
30
|
+
* @property {"default" | "active" | "focused" | "success" | "error" | "disabled" | "loading"} [props.state] trigger input state
|
|
31
|
+
* @property {boolean} [props.block] trigger width 100% 여부
|
|
32
|
+
* @property {"full" | "fit" | "fill" | "auto" | number | string} [props.width] trigger width preset 또는 custom width
|
|
33
|
+
* @property {(event: FocusEvent<HTMLInputElement>) => void} [props.onFocus] trigger focus 핸들러
|
|
34
|
+
* @property {(event: FocusEvent<HTMLInputElement>) => void} [props.onBlur] trigger blur 핸들러
|
|
35
|
+
* @property {string} [props.id] input id
|
|
36
|
+
* @property {string} [props.name] form name
|
|
37
|
+
* @property {UseFormRegisterReturn} [props.register] RHF register
|
|
38
|
+
* @desc Date 값을 직접 편집하지 않고 Calendar 선택값을 표시하는 기본 trigger다.
|
|
33
39
|
*/
|
|
34
40
|
const InputDateTrigger = forwardRef<
|
|
35
41
|
HTMLInputElement,
|
|
@@ -44,7 +50,12 @@ const InputDateTrigger = forwardRef<
|
|
|
44
50
|
disabled,
|
|
45
51
|
readOnly,
|
|
46
52
|
priority,
|
|
53
|
+
size,
|
|
47
54
|
state,
|
|
55
|
+
block,
|
|
56
|
+
width,
|
|
57
|
+
onFocus,
|
|
58
|
+
onBlur,
|
|
48
59
|
id,
|
|
49
60
|
name,
|
|
50
61
|
register,
|
|
@@ -90,7 +101,7 @@ const InputDateTrigger = forwardRef<
|
|
|
90
101
|
triggerInputRef.current?.click();
|
|
91
102
|
};
|
|
92
103
|
|
|
93
|
-
//
|
|
104
|
+
// Date trigger는 직접 타이핑을 막아 달력 선택을 단일 입력 경로로 유지한다.
|
|
94
105
|
const shouldBlockTyping = !disabled && !readOnly;
|
|
95
106
|
|
|
96
107
|
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
|
@@ -170,9 +181,14 @@ const InputDateTrigger = forwardRef<
|
|
|
170
181
|
name={name ?? register?.name}
|
|
171
182
|
register={register}
|
|
172
183
|
priority={priority}
|
|
184
|
+
size={size}
|
|
173
185
|
state={state}
|
|
186
|
+
block={block}
|
|
187
|
+
width={width}
|
|
174
188
|
placeholder={placeholder}
|
|
175
189
|
className={clsx("input-date-trigger-input", className)}
|
|
190
|
+
onFocus={onFocus}
|
|
191
|
+
onBlur={onBlur}
|
|
176
192
|
onClick={handleInputClick}
|
|
177
193
|
onKeyDown={handleKeyDown}
|
|
178
194
|
onBeforeInput={handleBeforeInput}
|