@uniai-fe/uds-primitives 0.2.2 → 0.2.4

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 (61) hide show
  1. package/README.md +1 -1
  2. package/dist/styles.css +299 -81
  3. package/package.json +16 -9
  4. package/src/components/{input/img/calendar → calendar/img}/calendar.svg +5 -0
  5. package/src/components/calendar/index.tsx +5 -3
  6. package/src/components/calendar/markup/Core.tsx +67 -0
  7. package/src/components/calendar/markup/Icon.tsx +20 -0
  8. package/src/components/calendar/markup/Root.tsx +126 -0
  9. package/src/components/calendar/markup/index.tsx +24 -2
  10. package/src/components/calendar/markup/layout/Body.tsx +12 -0
  11. package/src/components/calendar/markup/layout/Container.tsx +43 -0
  12. package/src/components/calendar/markup/layout/Footer.tsx +12 -0
  13. package/src/components/calendar/markup/layout/Header.tsx +12 -0
  14. package/src/components/calendar/styles/index.scss +2 -0
  15. package/src/components/calendar/styles/layout.scss +21 -0
  16. package/src/components/calendar/styles/mantine-calendar.scss +240 -0
  17. package/src/components/calendar/types/calendar.ts +208 -0
  18. package/src/components/calendar/types/index.ts +1 -4
  19. package/src/components/calendar/utils/index.ts +1 -4
  20. package/src/components/calendar/utils/value-mapper.ts +24 -0
  21. package/src/components/input/index.scss +1 -1
  22. package/src/components/input/markup/date/Template.tsx +181 -0
  23. package/src/components/input/markup/date/Trigger.tsx +79 -0
  24. package/src/components/input/markup/date/button/ApplyButton.tsx +38 -0
  25. package/src/components/input/markup/date/button/ClearButton.tsx +36 -0
  26. package/src/components/input/markup/date/button/TodayButton.tsx +36 -0
  27. package/src/components/input/markup/date/footer/Container.tsx +24 -0
  28. package/src/components/input/markup/date/footer/Template.tsx +36 -0
  29. package/src/components/input/markup/date/footer/UtilContainer.tsx +23 -0
  30. package/src/components/input/markup/date/footer/index.ts +3 -0
  31. package/src/components/input/markup/date/index.tsx +27 -0
  32. package/src/components/input/markup/index.tsx +2 -4
  33. package/src/components/input/styles/date.scss +45 -0
  34. package/src/components/input/types/date.ts +286 -0
  35. package/src/components/input/types/index.ts +1 -1
  36. package/src/components/input/utils/address.ts +2 -2
  37. package/src/components/input/utils/date.ts +61 -0
  38. package/src/components/input/utils/index.tsx +1 -0
  39. package/src/components/pop-over/index.scss +1 -0
  40. package/src/components/pop-over/index.tsx +4 -0
  41. package/src/components/pop-over/markup/Content.tsx +77 -0
  42. package/src/components/pop-over/markup/Root.tsx +28 -0
  43. package/src/components/pop-over/markup/Trigger.tsx +26 -0
  44. package/src/components/pop-over/markup/index.tsx +17 -0
  45. package/src/components/pop-over/styles/base.scss +5 -0
  46. package/src/components/pop-over/styles/content.scss +24 -0
  47. package/src/components/pop-over/styles/index.scss +2 -0
  48. package/src/components/pop-over/types/index.ts +1 -0
  49. package/src/components/pop-over/types/pop-over.ts +86 -0
  50. package/src/index.scss +1 -0
  51. package/src/index.tsx +3 -1
  52. package/src/init/mantine.css +5 -0
  53. package/src/init/mantine.ts +2 -0
  54. package/src/components/input/markup/calendar/Base.tsx +0 -329
  55. package/src/components/input/markup/calendar/index.tsx +0 -8
  56. package/src/components/input/styles/calendar.scss +0 -110
  57. package/src/components/input/types/calendar.ts +0 -208
  58. /package/src/components/{input/img/calendar → calendar/img}/chevron-down.svg +0 -0
  59. /package/src/components/{input/img/calendar → calendar/img}/chevron-left.svg +0 -0
  60. /package/src/components/{input/img/calendar → calendar/img}/chevron-right.svg +0 -0
  61. /package/src/components/{input/img/calendar → calendar/img}/chevron-up.svg +0 -0
@@ -0,0 +1,208 @@
1
+ import type {
2
+ DatePickerProps as MantineDatePickerProps,
3
+ DatePickerStylesNames,
4
+ } from "@mantine/dates";
5
+ import type { ReactNode } from "react";
6
+
7
+ /**
8
+ * Calendar 모드.
9
+ * @property {"date" | "date-time" | "time"} mode 날짜/시간 표시 모드
10
+ */
11
+ export type CalendarMode = "date" | "date-time" | "time";
12
+
13
+ /**
14
+ * Calendar 컬럼 수.
15
+ * @property {1 | 2} columns 단일/이중 컬럼 개수
16
+ */
17
+ export type CalendarColumns = 1 | 2;
18
+
19
+ /**
20
+ * Calendar value 직렬화 타입.
21
+ * @property {string | null} value YYYY-MM-DD 문자열 또는 null
22
+ */
23
+ export type CalendarValue = string | null;
24
+
25
+ /**
26
+ * Calendar 값 변경 핸들러.
27
+ * @param {CalendarValue} value 선택된 직렬화 값
28
+ * @example
29
+ * const onChange = (value: CalendarValue) => {
30
+ * console.log(value);
31
+ * };
32
+ */
33
+ export type CalendarOnChange = (value: CalendarValue) => void;
34
+
35
+ /**
36
+ * Mantine DatePicker 공개 옵션.
37
+ * @property {Partial<Record<DatePickerStylesNames, string>>} [classNames] Mantine 내부 스타일 클래스 매핑
38
+ */
39
+ export type CalendarDatePickerProps = Partial<
40
+ Omit<
41
+ MantineDatePickerProps<"default">,
42
+ | "value"
43
+ | "defaultValue"
44
+ | "onChange"
45
+ | "type"
46
+ | "numberOfColumns"
47
+ | "classNames"
48
+ | "styles"
49
+ >
50
+ > & {
51
+ /**
52
+ * Mantine 내부 스타일 classNames override.
53
+ */
54
+ classNames?: Partial<Record<DatePickerStylesNames, string>>;
55
+ };
56
+
57
+ /**
58
+ * Calendar Grid props.
59
+ * @property {CalendarValue} value 현재 선택 값
60
+ * @property {CalendarOnChange} onChange 값 변경 핸들러
61
+ * @property {CalendarDatePickerProps} [datePickerProps] Mantine DatePicker 옵션
62
+ */
63
+ export interface CalendarGridProps {
64
+ /**
65
+ * 현재 선택 값
66
+ */
67
+ value: CalendarValue;
68
+ /**
69
+ * 값 변경 핸들러
70
+ */
71
+ onChange: CalendarOnChange;
72
+ /**
73
+ * Mantine DatePicker 옵션
74
+ */
75
+ datePickerProps?: CalendarDatePickerProps;
76
+ }
77
+
78
+ /**
79
+ * Calendar Layout Container props.
80
+ * @property {ReactNode} [header] 상단 콘텐츠
81
+ * @property {ReactNode} body 본문(Calendar Grid) 콘텐츠
82
+ * @property {ReactNode} [footer] 하단 콘텐츠
83
+ * @property {CalendarMode} [mode="date"] calendar 모드
84
+ * @property {CalendarColumns} [columns=1] 동시 표시 컬럼 수
85
+ * @property {boolean} [disabled] 비활성화 상태
86
+ * @property {boolean} [readOnly] 읽기 전용 상태
87
+ */
88
+ export interface CalendarContainerProps {
89
+ /**
90
+ * 상단 콘텐츠
91
+ */
92
+ header?: ReactNode;
93
+ /**
94
+ * 본문(Calendar Grid) 콘텐츠
95
+ */
96
+ body: ReactNode;
97
+ /**
98
+ * 하단 콘텐츠
99
+ */
100
+ footer?: ReactNode;
101
+ /**
102
+ * calendar 모드
103
+ */
104
+ mode?: CalendarMode;
105
+ /**
106
+ * 동시 표시 컬럼 수
107
+ */
108
+ columns?: CalendarColumns;
109
+ /**
110
+ * 비활성화 상태
111
+ */
112
+ disabled?: boolean;
113
+ /**
114
+ * 읽기 전용 상태
115
+ */
116
+ readOnly?: boolean;
117
+ }
118
+
119
+ /**
120
+ * Calendar Root props.
121
+ * @extends CalendarContainerProps
122
+ * @property {string} [className] Trigger element className override
123
+ * @property {CalendarValue} value 현재 선택 값
124
+ * @property {CalendarOnChange} onChange 값 변경 핸들러
125
+ * @property {CalendarDatePickerProps} [datePickerProps] Mantine DatePicker 옵션
126
+ * @property {ReactNode} children Trigger 슬롯(children)
127
+ * @property {boolean} [open] 제어형 open 상태
128
+ * @property {boolean} [defaultOpen] 비제어 초기 open 상태
129
+ * @property {(open: boolean) => void} [onOpenChange] open 상태 변경 핸들러
130
+ * @property {"top" | "right" | "bottom" | "left"} [side="bottom"] content 배치 방향
131
+ * @property {"start" | "center" | "end"} [align="start"] content 정렬 기준
132
+ * @property {number} [sideOffset=4] trigger와 content 간격
133
+ * @property {number} [alignOffset] 정렬 보정값
134
+ * @property {boolean} [withPortal=true] Portal 사용 여부
135
+ * @property {HTMLElement | null} [portalContainer] Portal 컨테이너
136
+ */
137
+ export interface CalendarRootProps extends Omit<
138
+ CalendarContainerProps,
139
+ "body"
140
+ > {
141
+ /**
142
+ * Trigger element className override
143
+ */
144
+ className?: string;
145
+ /**
146
+ * 현재 선택 값
147
+ */
148
+ value: CalendarValue;
149
+ /**
150
+ * 값 변경 핸들러
151
+ */
152
+ onChange: CalendarOnChange;
153
+ /**
154
+ * Mantine DatePicker 옵션
155
+ */
156
+ datePickerProps?: CalendarDatePickerProps;
157
+ /**
158
+ * Trigger 슬롯(children)
159
+ */
160
+ children: ReactNode;
161
+ /**
162
+ * 제어형 open 상태
163
+ */
164
+ open?: boolean;
165
+ /**
166
+ * 비제어 초기 open 상태
167
+ */
168
+ defaultOpen?: boolean;
169
+ /**
170
+ * open 상태 변경 핸들러
171
+ */
172
+ onOpenChange?: (open: boolean) => void;
173
+ /**
174
+ * content 배치 방향
175
+ */
176
+ side?: "top" | "right" | "bottom" | "left";
177
+ /**
178
+ * content 정렬 기준
179
+ */
180
+ align?: "start" | "center" | "end";
181
+ /**
182
+ * trigger와 content 간격
183
+ */
184
+ sideOffset?: number;
185
+ /**
186
+ * 정렬 보정값
187
+ */
188
+ alignOffset?: number;
189
+ /**
190
+ * Portal 사용 여부
191
+ */
192
+ withPortal?: boolean;
193
+ /**
194
+ * Portal 컨테이너
195
+ */
196
+ portalContainer?: HTMLElement | null;
197
+ }
198
+
199
+ /**
200
+ * Calendar 섹션 공용 props.
201
+ * @property {ReactNode} [children] 섹션 내부 콘텐츠
202
+ */
203
+ export interface CalendarSectionProps {
204
+ /**
205
+ * 섹션 내부 콘텐츠
206
+ */
207
+ children?: ReactNode;
208
+ }
@@ -1,4 +1 @@
1
- /**
2
- * TODO(calendar): variant/slot 타입 정의를 작성한다.
3
- */
4
- export {};
1
+ export type * from "./calendar";
@@ -1,4 +1 @@
1
- /**
2
- * TODO(calendar): 토큰 매핑과 클래스명 유틸을 구현한다.
3
- */
4
- export {};
1
+ export * from "./value-mapper";
@@ -0,0 +1,24 @@
1
+ import { dayjs } from "../../../init/dayjs";
2
+ import type { CalendarValue } from "../types";
3
+
4
+ const DATE_FORMAT = "YYYY-MM-DD";
5
+
6
+ /**
7
+ * Calendar value를 DatePicker value로 변환한다.
8
+ * @param {CalendarValue} value YYYY-MM-DD 문자열 값
9
+ * @returns {Date | null} DatePicker value
10
+ * @example
11
+ * mapValueToPicker("2026-02-13");
12
+ */
13
+ export const mapValueToPicker = (value: CalendarValue) =>
14
+ value ? dayjs(value).toDate() : null;
15
+
16
+ /**
17
+ * DatePicker value를 Calendar 직렬화 값으로 변환한다.
18
+ * @param {Date | null} value DatePicker value
19
+ * @returns {CalendarValue} YYYY-MM-DD 직렬화 값
20
+ * @example
21
+ * parseValueFromPicker(new Date("2026-02-13"));
22
+ */
23
+ export const parseValueFromPicker = (value: Date | null): CalendarValue =>
24
+ value ? dayjs(value).format(DATE_FORMAT) : null;
@@ -1,5 +1,5 @@
1
1
  @use "./styles/variables.scss" as inputVariables;
2
2
  @use "./styles/foundation.scss" as inputFoundation;
3
3
  @use "./styles/text.scss" as inputText;
4
- @use "./styles/calendar.scss" as inputCalendar;
4
+ @use "./styles/date.scss" as inputDate;
5
5
  @use "./styles/address.scss" as inputAddress;
@@ -0,0 +1,181 @@
1
+ "use client";
2
+
3
+ import type { ChangeEvent, MouseEvent as ReactMouseEvent } from "react";
4
+ import { forwardRef, useCallback, useMemo } from "react";
5
+ import { useUncontrolled } from "@mantine/hooks";
6
+ import clsx from "clsx";
7
+ import { Calendar } from "../../../calendar";
8
+ import type {
9
+ InputCalendarProps,
10
+ InputCalendarTriggerRenderProps,
11
+ } from "../../types";
12
+ import type { CalendarValue } from "../../../calendar";
13
+ import {
14
+ createEmptyValue,
15
+ formatTriggerValue,
16
+ getTodayValue,
17
+ serializeCalendarValue,
18
+ } from "../../utils/date";
19
+ import InputDateFooterTemplate from "./footer/Template";
20
+ import InputDateTrigger from "./Trigger";
21
+
22
+ /**
23
+ * Input Date Template; trigger + calendar 조합.
24
+ * @component
25
+ * @param {InputCalendarProps} props
26
+ * @param {CalendarMode} [props.mode="date"] 날짜/시간 모드
27
+ * @param {CalendarColumns} [props.columns=1] 동시 노출 달력 수
28
+ * @param {CalendarValue} [props.value] 제어형 값
29
+ * @param {CalendarValue} [props.defaultValue] 비제어 초기값
30
+ * @param {CalendarOnChange} [props.onChange] 값 변경 이벤트
31
+ * @param {CalendarOnChange} [props.onValueChange] onChange alias
32
+ * @param {boolean} [props.readOnly] 읽기 전용 여부
33
+ * @param {boolean} [props.disabled] 비활성화 여부
34
+ * @param {CalendarDatePickerProps} [props.datePickerProps] Mantine DatePicker 옵션
35
+ * @param {string} [props.name] form name/RHF name
36
+ * @param {UseFormRegisterReturn} [props.register] RHF register
37
+ * @param {string} [props.placeholder="YYYY-MM-DD"] placeholder
38
+ * @param {ReactNode} [props.header] 패널 header 콘텐츠
39
+ * @param {ReactNode} [props.footer] 패널 footer 콘텐츠
40
+ * @param {unknown} [props.timePicker] TimePicker 확장용 예약 슬롯(현재 미구현)
41
+ * @param {boolean} [props.calendarOpened] calendar 열림 제어 상태
42
+ * @param {(event: MouseEvent<Element>) => void} [props.onClick] trigger 클릭 핸들러
43
+ * @param {string} [props.className] root className
44
+ * @param {string} [props.id] trigger id
45
+ * @param {ReactNode} [props.trigger] 커스텀 trigger 슬롯
46
+ * @param {(props: InputCalendarTriggerRenderProps) => ReactNode} [props.renderTrigger] 커스텀 trigger 렌더 함수
47
+ */
48
+ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
49
+ (
50
+ {
51
+ mode = "date",
52
+ columns = 1,
53
+ value,
54
+ defaultValue,
55
+ onChange,
56
+ onValueChange,
57
+ readOnly,
58
+ disabled,
59
+ datePickerProps,
60
+ name,
61
+ register,
62
+ placeholder = "YYYY-MM-DD",
63
+ className,
64
+ header,
65
+ footer,
66
+ calendarOpened,
67
+ onClick: triggerOnClick,
68
+ id,
69
+ trigger,
70
+ renderTrigger,
71
+ },
72
+ ref,
73
+ ) => {
74
+ // useUncontrolled로 제어형/비제어 값을 모두 허용한다.
75
+ const [calendarValue, setCalendarValue] = useUncontrolled<CalendarValue>({
76
+ value,
77
+ defaultValue,
78
+ finalValue: createEmptyValue(),
79
+ onChange: next => {
80
+ onChange?.(next as CalendarValue);
81
+ onValueChange?.(next as CalendarValue);
82
+ },
83
+ });
84
+
85
+ // react-hook-form register onChange를 수동 호출해 값 직렬화를 맞춘다.
86
+ const emitRegisterChange = useCallback(
87
+ (nextValue: CalendarValue) => {
88
+ if (!register?.onChange) {
89
+ return;
90
+ }
91
+ const serialized = serializeCalendarValue(nextValue);
92
+ const syntheticEvent = {
93
+ target: {
94
+ name: register.name,
95
+ value: serialized,
96
+ },
97
+ currentTarget: {
98
+ name: register.name,
99
+ value: serialized,
100
+ },
101
+ } as unknown as ChangeEvent<HTMLInputElement>;
102
+ register.onChange(syntheticEvent);
103
+ },
104
+ [register],
105
+ );
106
+
107
+ const updateValue = useCallback(
108
+ (nextValue: CalendarValue) => {
109
+ setCalendarValue(nextValue);
110
+ emitRegisterChange(nextValue);
111
+ },
112
+ [emitRegisterChange, setCalendarValue],
113
+ );
114
+
115
+ const triggerValue = useMemo(
116
+ () => formatTriggerValue(calendarValue) ?? "",
117
+ [calendarValue],
118
+ );
119
+
120
+ const handleTriggerClick = (event: ReactMouseEvent<Element>) => {
121
+ triggerOnClick?.(event);
122
+ };
123
+
124
+ const handleCalendarChange = (nextValue: CalendarValue) => {
125
+ updateValue(nextValue);
126
+ };
127
+
128
+ // footer 미지정 시 기본 FooterTemplate을 연결한다.
129
+ const footerContent = footer ?? (
130
+ <InputDateFooterTemplate
131
+ disabled={disabled}
132
+ onClear={() => updateValue(createEmptyValue())}
133
+ onToday={() => updateValue(getTodayValue())}
134
+ />
135
+ );
136
+
137
+ const triggerRenderProps: InputCalendarTriggerRenderProps = {
138
+ id,
139
+ name: name ?? register?.name,
140
+ placeholder,
141
+ displayValue: triggerValue,
142
+ disabled,
143
+ onClick: handleTriggerClick,
144
+ };
145
+
146
+ const triggerNode = trigger ?? renderTrigger?.(triggerRenderProps) ?? (
147
+ <InputDateTrigger
148
+ id={id}
149
+ name={name ?? register?.name}
150
+ register={register}
151
+ placeholder={placeholder}
152
+ displayValue={triggerValue}
153
+ disabled={disabled}
154
+ onClick={handleTriggerClick}
155
+ />
156
+ );
157
+
158
+ return (
159
+ <Calendar.Root
160
+ ref={ref}
161
+ className={clsx("input-date-field", className)}
162
+ mode={mode}
163
+ columns={columns}
164
+ disabled={disabled}
165
+ readOnly={readOnly}
166
+ value={calendarValue}
167
+ onChange={handleCalendarChange}
168
+ datePickerProps={datePickerProps}
169
+ header={header}
170
+ footer={footerContent}
171
+ open={calendarOpened}
172
+ >
173
+ {triggerNode}
174
+ </Calendar.Root>
175
+ );
176
+ },
177
+ );
178
+
179
+ InputDateTemplate.displayName = "InputDateTemplate";
180
+
181
+ export default InputDateTemplate;
@@ -0,0 +1,79 @@
1
+ "use client";
2
+
3
+ import clsx from "clsx";
4
+ import type { MouseEvent } from "react";
5
+ import { forwardRef } from "react";
6
+ import { Calendar } from "../../../calendar";
7
+ import { InputFoundation } from "../foundation";
8
+ import type { InputCalendarTriggerViewProps } from "../../types";
9
+
10
+ /**
11
+ * Input Date trigger field.
12
+ * @component
13
+ * @param {InputCalendarTriggerViewProps} props
14
+ * @param {string} [props.className] trigger className
15
+ * @param {string} [props.placeholder] placeholder
16
+ * @param {string} [props.displayValue] 표시 문자열
17
+ * @param {(event: MouseEvent<Element>) => void} [props.onClick] 클릭 핸들러
18
+ * @param {boolean} [props.disabled] disabled 여부
19
+ * @param {string} [props.id] input id
20
+ * @param {string} [props.name] form name
21
+ * @param {UseFormRegisterReturn} [props.register] RHF register
22
+ */
23
+ const InputDateTrigger = forwardRef<
24
+ HTMLInputElement,
25
+ InputCalendarTriggerViewProps
26
+ >(
27
+ (
28
+ {
29
+ className,
30
+ placeholder,
31
+ displayValue,
32
+ onClick,
33
+ disabled,
34
+ id,
35
+ name,
36
+ register,
37
+ ...restProps
38
+ },
39
+ ref,
40
+ ) => {
41
+ /**
42
+ * Radix `asChild`가 주입한 onClick을 보존하기 위해 restProps.onClick을 병합한다.
43
+ * (Input Date 자체 onClick 계약도 함께 실행)
44
+ */
45
+ const handleInputClick = (event: MouseEvent<HTMLInputElement>) => {
46
+ const rawOnClick = (restProps as Record<string, unknown>).onClick;
47
+ if (typeof rawOnClick === "function") {
48
+ (rawOnClick as (event: MouseEvent<HTMLInputElement>) => void)(event);
49
+ }
50
+ onClick?.(event as never);
51
+ };
52
+
53
+ return (
54
+ <InputFoundation.Base
55
+ {...restProps}
56
+ ref={ref}
57
+ value={displayValue}
58
+ readOnly
59
+ disabled={disabled}
60
+ id={id}
61
+ name={name ?? register?.name}
62
+ register={register}
63
+ placeholder={placeholder}
64
+ className={clsx("input-date-trigger-input", className)}
65
+ onClick={handleInputClick}
66
+ right={
67
+ // 토글 인터랙션은 input 단일 경로로 유지하고, 오른쪽 아이콘은 장식 요소로만 둔다.
68
+ <figure className="input-date-trigger-icon" aria-hidden="true">
69
+ <Calendar.Icon.Calendar />
70
+ </figure>
71
+ }
72
+ />
73
+ );
74
+ },
75
+ );
76
+
77
+ InputDateTrigger.displayName = "InputDateTrigger";
78
+
79
+ export default InputDateTrigger;
@@ -0,0 +1,38 @@
1
+ import clsx from "clsx";
2
+ import { Button } from "../../../../button";
3
+ import type { InputCalendarApplyButtonProps } from "../../../types";
4
+
5
+ /**
6
+ * Calendar footer apply 버튼.
7
+ * @component
8
+ * @param {InputCalendarApplyButtonProps} props
9
+ * @param {string} [props.className] 추가 className
10
+ * @param {React.ReactNode} [props.children] override 라벨
11
+ * @param {React.ReactNode} [props.label] fallback 라벨
12
+ * @param {boolean} [props.disabled] disabled 여부
13
+ * @param {() => void} [props.onClick] 클릭 핸들러
14
+ */
15
+ export default function InputDateApplyButton({
16
+ className,
17
+ label,
18
+ disabled,
19
+ onClick,
20
+ children,
21
+ }: InputCalendarApplyButtonProps) {
22
+ return (
23
+ <Button.Default
24
+ className={clsx("input-date-apply-button", className)}
25
+ priority="primary"
26
+ fill="solid"
27
+ size="large"
28
+ disabled={disabled}
29
+ onClick={onClick}
30
+ >
31
+ {
32
+ children ??
33
+ label ??
34
+ "적용하기" /* children 우선, 없으면 label/기본 라벨 */
35
+ }
36
+ </Button.Default>
37
+ );
38
+ }
@@ -0,0 +1,36 @@
1
+ import clsx from "clsx";
2
+ import { Button } from "../../../../button";
3
+ import type { InputCalendarInlineButtonProps } from "../../../types";
4
+
5
+ /**
6
+ * Calendar footer clear 버튼.
7
+ * @component
8
+ * @param {InputCalendarInlineButtonProps} props
9
+ * @param {React.ReactNode} [props.children] 라벨
10
+ * @param {() => void} [props.onClick] 클릭 핸들러
11
+ * @param {boolean} [props.disabled] disabled 여부
12
+ * @param {string} [props.className] 확장 className
13
+ */
14
+ export default function InputDateClearButton({
15
+ children,
16
+ onClick,
17
+ disabled,
18
+ className,
19
+ }: InputCalendarInlineButtonProps) {
20
+ return (
21
+ <Button.Default
22
+ className={clsx(
23
+ "input-date-action-button input-date-action-clear",
24
+ className,
25
+ )}
26
+ priority="tertiary"
27
+ fill="outlined"
28
+ size="small"
29
+ onClick={onClick}
30
+ disabled={disabled}
31
+ type="button"
32
+ >
33
+ {children ?? "삭제" /* 텍스트 미지정 시 기본 라벨 */}
34
+ </Button.Default>
35
+ );
36
+ }
@@ -0,0 +1,36 @@
1
+ import clsx from "clsx";
2
+ import { Button } from "../../../../button";
3
+ import type { InputCalendarInlineButtonProps } from "../../../types";
4
+
5
+ /**
6
+ * Calendar footer today 버튼.
7
+ * @component
8
+ * @param {InputCalendarInlineButtonProps} props
9
+ * @param {React.ReactNode} [props.children] 라벨
10
+ * @param {() => void} [props.onClick] 클릭 핸들러
11
+ * @param {boolean} [props.disabled] disabled 여부
12
+ * @param {string} [props.className] className 확장
13
+ */
14
+ export default function InputDateTodayButton({
15
+ children,
16
+ onClick,
17
+ disabled,
18
+ className,
19
+ }: InputCalendarInlineButtonProps) {
20
+ return (
21
+ <Button.Default
22
+ className={clsx(
23
+ "input-date-action-button input-date-action-today",
24
+ className,
25
+ )}
26
+ priority="secondary"
27
+ fill="solid"
28
+ size="small"
29
+ onClick={onClick}
30
+ disabled={disabled}
31
+ type="button"
32
+ >
33
+ {children ?? "오늘" /* default 라벨 */}
34
+ </Button.Default>
35
+ );
36
+ }
@@ -0,0 +1,24 @@
1
+ import clsx from "clsx";
2
+ import type { InputCalendarFooterTemplateContainerProps } from "../../../types";
3
+
4
+ /**
5
+ * FooterTemplate root container.
6
+ * @component
7
+ * @param {InputCalendarFooterTemplateContainerProps} props
8
+ * @param {React.ReactNode} [props.children] footer 내부 children
9
+ * @param {string} [props.className] container className
10
+ * @example
11
+ * <InputDateFooterTemplateContainer>
12
+ * <div>...</div>
13
+ * </InputDateFooterTemplateContainer>
14
+ */
15
+ export default function InputDateFooterTemplateContainer({
16
+ children,
17
+ className,
18
+ }: InputCalendarFooterTemplateContainerProps) {
19
+ return (
20
+ <div className={clsx("input-date-footer-template", className)}>
21
+ {children}
22
+ </div>
23
+ );
24
+ }
@@ -0,0 +1,36 @@
1
+ import type { InputCalendarFooterTemplateProps } from "../../../types";
2
+ import InputDateApplyButton from "../button/ApplyButton";
3
+ import InputDateClearButton from "../button/ClearButton";
4
+ import InputDateTodayButton from "../button/TodayButton";
5
+ import InputDateFooterTemplateContainer from "./Container";
6
+ import InputDateFooterUtilContainer from "./UtilContainer";
7
+
8
+ /**
9
+ * Calendar footer 기본 템플릿.
10
+ * @component
11
+ * @param {InputCalendarFooterTemplateProps} props
12
+ * @param {string} [props.className] root className
13
+ * @param {() => void} [props.onClear] clear 버튼 클릭 핸들러
14
+ * @param {() => void} [props.onToday] today 버튼 클릭 핸들러
15
+ * @param {() => void} [props.onApply] apply 버튼 클릭 핸들러
16
+ * @param {boolean} [props.disabled] 전체 버튼 disabled 여부
17
+ * @example
18
+ * <InputDateFooterTemplate onClear={onClear} onToday={onToday} onApply={onApply} />
19
+ */
20
+ export default function InputDateFooterTemplate({
21
+ className,
22
+ onClear,
23
+ onToday,
24
+ onApply,
25
+ disabled,
26
+ }: InputCalendarFooterTemplateProps) {
27
+ return (
28
+ <InputDateFooterTemplateContainer className={className}>
29
+ <InputDateFooterUtilContainer>
30
+ <InputDateClearButton disabled={disabled} onClick={onClear} />
31
+ <InputDateTodayButton disabled={disabled} onClick={onToday} />
32
+ </InputDateFooterUtilContainer>
33
+ <InputDateApplyButton disabled={disabled} onClick={onApply} />
34
+ </InputDateFooterTemplateContainer>
35
+ );
36
+ }