@loword/loword-design-system 0.0.9 → 0.0.11
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/components/LDAutoComplete/AutoCompleteBase.js +6 -6
- package/dist/components/LDBadge/LDBadge.d.ts +5 -6
- package/dist/components/LDBadge/LDBadge.d.ts.map +1 -1
- package/dist/components/LDBadge/LDBadge.js +2 -2
- package/dist/components/LDBreadCrumb/LDBreadCrumb.d.ts +1 -2
- package/dist/components/LDBreadCrumb/LDBreadCrumb.d.ts.map +1 -1
- package/dist/components/LDButton/LDButton.d.ts +3 -3
- package/dist/components/LDButton/LDButton.d.ts.map +1 -1
- package/dist/components/LDButton/LDButton.js +5 -5
- package/dist/components/LDCalendar/LDCalendar.d.ts +7 -6
- package/dist/components/LDCalendar/LDCalendar.d.ts.map +1 -1
- package/dist/components/LDCalendar/LDCalendar.js +59 -16
- package/dist/components/LDCarousel/CarouselBase.d.ts.map +1 -1
- package/dist/components/LDCarousel/CarouselBase.js +8 -4
- package/dist/components/LDCheckbox/CheckboxBase.d.ts +1 -3
- package/dist/components/LDCheckbox/CheckboxBase.d.ts.map +1 -1
- package/dist/components/LDCheckbox/CheckboxBase.js +3 -3
- package/dist/components/LDCheckbox/LDCheckbox.d.ts.map +1 -1
- package/dist/components/LDCheckbox/LDCheckbox.js +4 -4
- package/dist/components/LDCheckbox/LDCheckboxGroup.js +1 -1
- package/dist/components/LDCheckbox/LDFormCheckbox.d.ts +14 -0
- package/dist/components/LDCheckbox/LDFormCheckbox.d.ts.map +1 -0
- package/dist/components/LDCheckbox/{FormCheckbox.js → LDFormCheckbox.js} +2 -2
- package/dist/components/LDCheckbox/LDFormCheckboxGroup.d.ts +13 -0
- package/dist/components/LDCheckbox/LDFormCheckboxGroup.d.ts.map +1 -0
- package/dist/components/LDCheckbox/{FormCheckboxGroup.js → LDFormCheckboxGroup.js} +2 -2
- package/dist/components/LDDatePicker/LDDatePicker.d.ts +10 -4
- package/dist/components/LDDatePicker/LDDatePicker.d.ts.map +1 -1
- package/dist/components/LDDatePicker/LDDatePicker.js +95 -25
- package/dist/components/LDDatePicker/LDFormDatePicker.d.ts +13 -0
- package/dist/components/LDDatePicker/LDFormDatePicker.d.ts.map +1 -0
- package/dist/components/LDDatePicker/LDFormDatePicker.js +15 -0
- package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts +13 -6
- package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts.map +1 -1
- package/dist/components/LDDateRangePicker/LDDateRangePicker.js +143 -93
- package/dist/components/LDDateRangePicker/LDFormDateRangePicker.d.ts +13 -0
- package/dist/components/LDDateRangePicker/LDFormDateRangePicker.d.ts.map +1 -0
- package/dist/components/LDDateRangePicker/LDFormDateRangePicker.js +20 -0
- package/dist/components/LDDrawer/LDDrawer.js +2 -2
- package/dist/components/LDFileUpload/FileUploadBase.d.ts +11 -3
- package/dist/components/LDFileUpload/FileUploadBase.d.ts.map +1 -1
- package/dist/components/LDFileUpload/FileUploadBase.js +17 -17
- package/dist/components/LDFileUpload/LDFileUpload.d.ts.map +1 -1
- package/dist/components/LDFileUpload/LDFileUpload.js +3 -1
- package/dist/components/LDFileUpload/LDFileUploadList.js +1 -1
- package/dist/components/LDFileUpload/LDImageUpload.d.ts +2 -0
- package/dist/components/LDFileUpload/LDImageUpload.d.ts.map +1 -1
- package/dist/components/LDFileUpload/LDImageUpload.js +5 -1
- package/dist/components/LDFileUpload/LDImageUploadList.js +1 -1
- package/dist/components/LDForm/LDFormErrorMessage.d.ts +3 -1
- package/dist/components/LDForm/LDFormErrorMessage.d.ts.map +1 -1
- package/dist/components/LDForm/LDFormErrorMessage.js +2 -2
- package/dist/components/LDInput/LDFormInput.d.ts +1 -1
- package/dist/components/LDInput/LDFormInput.d.ts.map +1 -1
- package/dist/components/LDInput/LDFormInput.js +37 -14
- package/dist/components/LDInput/LDInput.d.ts +4 -3
- package/dist/components/LDInput/LDInput.d.ts.map +1 -1
- package/dist/components/LDInput/LDInput.js +49 -48
- package/dist/components/LDModal/LDModal.d.ts +19 -40
- package/dist/components/LDModal/LDModal.d.ts.map +1 -1
- package/dist/components/LDModal/LDModal.js +56 -70
- package/dist/components/LDModal/LDModalView.d.ts +51 -0
- package/dist/components/LDModal/LDModalView.d.ts.map +1 -0
- package/dist/components/LDModal/LDModalView.js +72 -0
- package/dist/components/LDOTPInput/LDOTPInput.d.ts.map +1 -1
- package/dist/components/LDOTPInput/LDOTPInput.js +4 -3
- package/dist/components/LDPagination/LDPagination.d.ts +5 -1
- package/dist/components/LDPagination/LDPagination.d.ts.map +1 -1
- package/dist/components/LDPagination/LDPagination.js +10 -1
- package/dist/components/LDPagination/PaginationBase.d.ts +13 -4
- package/dist/components/LDPagination/PaginationBase.d.ts.map +1 -1
- package/dist/components/LDPagination/PaginationBase.js +8 -7
- package/dist/components/LDPopover/LDPopover.js +3 -3
- package/dist/components/LDRadio/LDFormRadioGroup.d.ts +13 -0
- package/dist/components/LDRadio/LDFormRadioGroup.d.ts.map +1 -0
- package/dist/components/LDRadio/{FormRadioGroup.js → LDFormRadioGroup.js} +2 -2
- package/dist/components/LDRadio/LDRadio.d.ts +1 -1
- package/dist/components/LDRadio/LDRadio.d.ts.map +1 -1
- package/dist/components/LDRadio/LDRadio.js +15 -6
- package/dist/components/LDRadio/LDRadioGroup.d.ts.map +1 -1
- package/dist/components/LDRadio/LDRadioGroup.js +1 -1
- package/dist/components/LDRadio/RadioBase.d.ts +2 -3
- package/dist/components/LDRadio/RadioBase.d.ts.map +1 -1
- package/dist/components/LDRadio/RadioBase.js +7 -4
- package/dist/components/LDSelect/LDFormMultiSelect.d.ts +13 -0
- package/dist/components/LDSelect/LDFormMultiSelect.d.ts.map +1 -0
- package/dist/components/LDSelect/{FormMultiSelect.js → LDFormMultiSelect.js} +2 -2
- package/dist/components/LDSelect/LDFormSelect.d.ts +13 -0
- package/dist/components/LDSelect/LDFormSelect.d.ts.map +1 -0
- package/dist/components/LDSelect/LDFormSelect.js +10 -0
- package/dist/components/LDSelect/LDMultiSelect.d.ts +6 -3
- package/dist/components/LDSelect/LDMultiSelect.d.ts.map +1 -1
- package/dist/components/LDSelect/LDMultiSelect.js +35 -31
- package/dist/components/LDSelect/LDSelect.d.ts +6 -3
- package/dist/components/LDSelect/LDSelect.d.ts.map +1 -1
- package/dist/components/LDSelect/LDSelect.js +37 -30
- package/dist/components/LDSelect/SelectBase.d.ts.map +1 -1
- package/dist/components/LDSelect/SelectBase.js +21 -7
- package/dist/components/LDSpinner/LDSpinner.d.ts +1 -1
- package/dist/components/LDSpinner/LDSpinner.d.ts.map +1 -1
- package/dist/components/LDSpinner/LDSpinner.js +6 -6
- package/dist/components/LDTable/LDTanstackTable.js +1 -1
- package/dist/components/LDTable/TableField.d.ts +1 -1
- package/dist/components/LDTable/TableField.d.ts.map +1 -1
- package/dist/components/LDTextarea/LDFormTextarea.d.ts +14 -0
- package/dist/components/LDTextarea/LDFormTextarea.d.ts.map +1 -0
- package/dist/components/LDTextarea/{FormTextarea.js → LDFormTextarea.js} +2 -2
- package/dist/components/LDTextarea/LDTextarea.d.ts +1 -1
- package/dist/components/LDTextarea/LDTextarea.d.ts.map +1 -1
- package/dist/components/LDTextarea/LDTextarea.js +30 -30
- package/dist/components/LDTimePicker/LDFormTimePicker.d.ts +12 -0
- package/dist/components/LDTimePicker/LDFormTimePicker.d.ts.map +1 -0
- package/dist/components/LDTimePicker/{FormTimePicker.js → LDFormTimePicker.js} +3 -3
- package/dist/components/LDTimePicker/LDTimePicker.js +2 -2
- package/dist/components/LDToast/LDToast.js +1 -1
- package/dist/components/LDToggleButton/LDFormToggleButton.d.ts +12 -0
- package/dist/components/LDToggleButton/LDFormToggleButton.d.ts.map +1 -0
- package/dist/components/LDToggleButton/{FormToggleButton.js → LDFormToggleButton.js} +2 -2
- package/dist/index.css +349 -207
- package/dist/index.d.ts +13 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -13
- package/dist/utils/cn.d.ts.map +1 -1
- package/dist/utils/cn.js +25 -1
- package/dist/utils/file.d.ts +2 -2
- package/dist/utils/file.d.ts.map +1 -1
- package/dist/utils/file.js +26 -23
- package/dist/utils/renderIcon.d.ts +1 -2
- package/dist/utils/renderIcon.d.ts.map +1 -1
- package/dist/utils/renderIcon.js +5 -4
- package/package.json +1 -1
- package/src/styles/components/button.css +2 -2
- package/src/styles/components/index.css +1 -0
- package/src/styles/components/input.css +2 -2
- package/src/styles/components/select.css +61 -0
- package/src/styles/motion.css +37 -0
- package/src/theme.css +3 -0
- package/dist/components/Icon/LucideIcon.d.ts +0 -12
- package/dist/components/Icon/LucideIcon.d.ts.map +0 -1
- package/dist/components/Icon/LucideIcon.js +0 -49
- package/dist/components/LDCheckbox/FormCheckbox.d.ts +0 -14
- package/dist/components/LDCheckbox/FormCheckbox.d.ts.map +0 -1
- package/dist/components/LDCheckbox/FormCheckboxGroup.d.ts +0 -13
- package/dist/components/LDCheckbox/FormCheckboxGroup.d.ts.map +0 -1
- package/dist/components/LDDatePicker/FormDatePicker.d.ts +0 -12
- package/dist/components/LDDatePicker/FormDatePicker.d.ts.map +0 -1
- package/dist/components/LDDatePicker/FormDatePicker.js +0 -12
- package/dist/components/LDDateRangePicker/FormDateRangePicker.d.ts +0 -12
- package/dist/components/LDDateRangePicker/FormDateRangePicker.d.ts.map +0 -1
- package/dist/components/LDDateRangePicker/FormDateRangePicker.js +0 -10
- package/dist/components/LDModal/openModal.d.ts +0 -24
- package/dist/components/LDModal/openModal.d.ts.map +0 -1
- package/dist/components/LDModal/openModal.js +0 -52
- package/dist/components/LDRadio/FormRadioGroup.d.ts +0 -13
- package/dist/components/LDRadio/FormRadioGroup.d.ts.map +0 -1
- package/dist/components/LDSelect/FormMultiSelect.d.ts +0 -13
- package/dist/components/LDSelect/FormMultiSelect.d.ts.map +0 -1
- package/dist/components/LDSelect/FormSelect.d.ts +0 -13
- package/dist/components/LDSelect/FormSelect.d.ts.map +0 -1
- package/dist/components/LDSelect/FormSelect.js +0 -10
- package/dist/components/LDTextarea/FormTextarea.d.ts +0 -14
- package/dist/components/LDTextarea/FormTextarea.d.ts.map +0 -1
- package/dist/components/LDTimePicker/FormTimePicker.d.ts +0 -12
- package/dist/components/LDTimePicker/FormTimePicker.d.ts.map +0 -1
- package/dist/components/LDToggleButton/FormToggleButton.d.ts +0 -12
- package/dist/components/LDToggleButton/FormToggleButton.d.ts.map +0 -1
|
@@ -1,42 +1,112 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState, } from 'react';
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
5
|
import { ko } from 'react-day-picker/locale';
|
|
6
6
|
import PopoverBase from '../LDPopover/PopoverBase.js';
|
|
7
|
-
import LDCalendar from '../LDCalendar/LDCalendar.js';
|
|
8
|
-
import LucideIcon from '../Icon/LucideIcon.js';
|
|
7
|
+
import LDCalendar, { TimePicker } from '../LDCalendar/LDCalendar.js';
|
|
9
8
|
import cn from '../../utils/cn.js';
|
|
10
|
-
|
|
9
|
+
import { Calendar, RotateCw } from 'lucide-react';
|
|
10
|
+
import LDButton from '../../components/LDButton/LDButton.js';
|
|
11
|
+
const timeFromDate = (selectedDate) => selectedDate ? dayjs(selectedDate).format('HH:mm:ss') : '00:00:00';
|
|
12
|
+
const combineDateTime = (date, time) => {
|
|
13
|
+
if (!date)
|
|
14
|
+
return undefined;
|
|
15
|
+
const [h = 0, m = 0, s = 0] = (time ?? '00:00:00').split(':').map(Number);
|
|
16
|
+
return dayjs(date).hour(h).minute(m).second(s).toDate();
|
|
17
|
+
};
|
|
18
|
+
// ── 스타일 매핑 ──
|
|
19
|
+
const variantColorClasses = {
|
|
20
|
+
filled: {
|
|
21
|
+
neutral: 'bg-neutral50 text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] focus:bg-tintBlue focus:outline-lb500',
|
|
22
|
+
point: 'bg-tintBlue text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] focus:outline-lb500',
|
|
23
|
+
danger: 'bg-tintRed text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] outline-danger600',
|
|
24
|
+
},
|
|
25
|
+
outline: {
|
|
26
|
+
neutral: 'bg-transparent text-neutral900 border-none outline-2 outline-neutral100 [outline-style:solid] [outline-offset:-2px] focus:outline-lb500',
|
|
27
|
+
point: 'bg-transparent text-neutral900 border-none outline-2 outline-lb500 [outline-style:solid] [outline-offset:-2px]',
|
|
28
|
+
danger: 'bg-transparent text-neutral900 border-none outline-2 outline-danger600 [outline-style:solid] [outline-offset:-2px]',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const LDDatePicker = ({ variant = 'filled', color = 'neutral', value, defaultValue, onChange, placeholder, dateFormat = 'YYYYMMDD', timeFormat = 'HH:MM:SS', disabled = false, block = false, isDisableAfterNow = false, minDate, trailingIcon = _jsx(Calendar, { size: 15, className: "text-mono400" }), showReset = true, isExistTime = true, className, style, triggerClassName, }) => {
|
|
11
32
|
const [open, setOpen] = useState(false);
|
|
12
|
-
const [
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
33
|
+
const [selectedDate, setSelectedDate] = useState(value);
|
|
34
|
+
const [selectedTime, setSelectedTime] = useState(timeFromDate(value));
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (open)
|
|
37
|
+
return;
|
|
38
|
+
setSelectedDate(value);
|
|
39
|
+
setSelectedTime(timeFromDate(value));
|
|
40
|
+
}, [open, value]);
|
|
41
|
+
const placeholderText = useMemo(() => {
|
|
42
|
+
if (placeholder)
|
|
43
|
+
return placeholder;
|
|
44
|
+
if (!isExistTime)
|
|
45
|
+
return dateFormat;
|
|
46
|
+
return `${dateFormat} ${timeFormat}`;
|
|
47
|
+
}, [placeholder, isExistTime, dateFormat, timeFormat]);
|
|
48
|
+
const reset = (d) => {
|
|
49
|
+
setSelectedDate(d);
|
|
50
|
+
setSelectedTime(timeFromDate(d));
|
|
20
51
|
};
|
|
21
52
|
const handleReset = (e) => {
|
|
22
53
|
e.stopPropagation();
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
54
|
+
reset(defaultValue);
|
|
55
|
+
if (!open)
|
|
56
|
+
onChange?.(defaultValue);
|
|
57
|
+
};
|
|
58
|
+
const handleConfirm = () => {
|
|
59
|
+
onChange?.(combineDateTime(selectedDate, selectedTime));
|
|
60
|
+
setOpen(false);
|
|
61
|
+
};
|
|
62
|
+
const handleCancel = () => {
|
|
63
|
+
reset(value);
|
|
64
|
+
setOpen(false);
|
|
65
|
+
};
|
|
66
|
+
const handleOpenChange = (next) => {
|
|
67
|
+
if (next) {
|
|
68
|
+
reset(value);
|
|
69
|
+
setOpen(true);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (selectedDate)
|
|
73
|
+
handleConfirm();
|
|
74
|
+
else
|
|
75
|
+
setOpen(false);
|
|
76
|
+
};
|
|
77
|
+
const handleSelect = useCallback((date) => {
|
|
78
|
+
setSelectedDate(date);
|
|
79
|
+
}, []);
|
|
80
|
+
const handleSelectedTime = (time) => {
|
|
81
|
+
setSelectedTime(time);
|
|
26
82
|
};
|
|
27
|
-
|
|
83
|
+
const isSameAsDefault = (combineDateTime(selectedDate, selectedTime)?.getTime() ?? null) ===
|
|
84
|
+
(defaultValue?.getTime() ?? null);
|
|
85
|
+
const showRotate = showReset && !isSameAsDefault;
|
|
86
|
+
const displayDate = open
|
|
87
|
+
? combineDateTime(selectedDate, selectedTime)
|
|
88
|
+
: value;
|
|
89
|
+
const isDateDisabled = useMemo(() => {
|
|
90
|
+
if (isDisableAfterNow)
|
|
91
|
+
return (date) => date > new Date();
|
|
92
|
+
if (minDate) {
|
|
93
|
+
return (date) => {
|
|
94
|
+
const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
95
|
+
const minDateOnly = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());
|
|
96
|
+
return dateOnly < minDateOnly;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}, [isDisableAfterNow, minDate]);
|
|
101
|
+
return (_jsx("div", { className: cn(block ? 'w-full' : 'w-auto', className), children: _jsxs(PopoverBase.Root, { open: open, onOpenChange: handleOpenChange, children: [_jsxs(PopoverBase.Trigger, { disabled: disabled, style: style, className: cn('border border-neutral100 h-[38px] w-full display14 px-4 rounded-[5px]', 'flex flex-row items-center justify-between gap-4', 'outline-2 outline-transparent ld-transition', disabled
|
|
102
|
+
? 'cursor-not-allowed opacity-50'
|
|
103
|
+
: variantColorClasses[variant][color], triggerClassName), children: [displayDate ? (_jsx("span", { children: !isExistTime
|
|
104
|
+
? `${dayjs(displayDate).format(dateFormat)}`
|
|
105
|
+
: `${dayjs(displayDate).format(`${dateFormat} ${timeFormat.replaceAll('M', 'm').replaceAll('S', 's')}`)}` })) : (_jsx("span", { className: "text-mono400", children: placeholderText })), _jsxs("div", { className: "flex items-center gap-xs", children: [_jsx("span", { role: "button", tabIndex: showRotate ? 0 : -1, "aria-hidden": !showRotate, className: cn('flex items-center text-mono400 cursor-pointer ld-transition', !showRotate ? 'opacity-0' : 'opacity-100'), onClick: handleReset, onKeyDown: (e) => {
|
|
28
106
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
29
107
|
e.preventDefault();
|
|
30
108
|
handleReset(e);
|
|
31
109
|
}
|
|
32
|
-
}, children: _jsx(
|
|
33
|
-
? (date) => date > new Date()
|
|
34
|
-
: minDate
|
|
35
|
-
? (date) => {
|
|
36
|
-
const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
37
|
-
const minDateOnly = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());
|
|
38
|
-
return dateOnly < minDateOnly;
|
|
39
|
-
}
|
|
40
|
-
: false }) })] }) }));
|
|
110
|
+
}, children: _jsx(RotateCw, { size: 15 }) }), trailingIcon] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white shadow-md p-0", children: _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex flex-row max-h-90", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "single", locale: ko, selected: selectedDate, onSelect: handleSelect, disabled: isDateDisabled }), isExistTime && (_jsx(TimePicker, { value: selectedTime, onChange: handleSelectedTime, className: "shrink-0" }))] }), _jsxs("div", { className: "flex items-center justify-end gap-sm py-xs px-sm border-t border-neutral100", children: [_jsx(LDButton, { variant: "outline", color: "neutral", onClick: handleCancel, children: "\uCDE8\uC18C" }), _jsx(LDButton, { onClick: handleConfirm, children: "\uD655\uC778" })] })] }) })] }) }));
|
|
41
111
|
};
|
|
42
112
|
export default LDDatePicker;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type RegisterOptions } from 'react-hook-form';
|
|
2
|
+
import { type LDDatePickerProps } from './LDDatePicker.js';
|
|
3
|
+
interface LDFormDatePickerProps extends Omit<LDDatePickerProps, 'value' | 'defaultValue' | 'onChange'> {
|
|
4
|
+
name: string;
|
|
5
|
+
options?: RegisterOptions;
|
|
6
|
+
customErrorMessage?: string;
|
|
7
|
+
isHiddenErrorMessage?: boolean;
|
|
8
|
+
isToastErrorMessage?: boolean;
|
|
9
|
+
errorClassName?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const LDFormDatePicker: ({ name, options, customErrorMessage, isHiddenErrorMessage, errorClassName, disabled, block, ...props }: LDFormDatePickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default LDFormDatePicker;
|
|
13
|
+
//# sourceMappingURL=LDFormDatePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDFormDatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/LDDatePicker/LDFormDatePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,iBAAiB,CAAC;AACvE,OAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAKtE,UAAU,qBAAsB,SAAQ,IAAI,CAC1C,iBAAiB,EACjB,OAAO,GAAG,cAAc,GAAG,UAAU,CACtC;IACC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,QAAA,MAAM,gBAAgB,GAAI,wGASvB,qBAAqB,4CAiCvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useFormContext } from 'react-hook-form';
|
|
4
|
+
import LDDatePicker from './LDDatePicker.js';
|
|
5
|
+
import FormField from '../LDForm/LDFormField.js';
|
|
6
|
+
import FormErrorMessage from '../LDForm/LDFormErrorMessage.js';
|
|
7
|
+
import cn from '../../utils/cn.js';
|
|
8
|
+
const LDFormDatePicker = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = true, errorClassName, disabled = false, block = false, ...props }) => {
|
|
9
|
+
const { formState } = useFormContext();
|
|
10
|
+
const defaultValue = formState.defaultValues?.[name];
|
|
11
|
+
return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, children: ({ field, fieldState }) => (_jsxs("div", { className: cn('relative', block ? 'w-full' : 'w-auto'), children: [_jsx(LDDatePicker, { ...props, block: block, value: field.value ?? undefined, defaultValue: defaultValue, onChange: (date) => {
|
|
12
|
+
field.onChange(date);
|
|
13
|
+
}, disabled: disabled, color: fieldState.hasError ? 'danger' : (props.color ?? 'neutral') }), _jsx(FormErrorMessage, { error: fieldState.error, disabled: disabled, className: cn(isHiddenErrorMessage && 'hidden', errorClassName) })] })) }));
|
|
14
|
+
};
|
|
15
|
+
export default LDFormDatePicker;
|
|
@@ -4,7 +4,10 @@ type DateRange = {
|
|
|
4
4
|
to?: Date;
|
|
5
5
|
};
|
|
6
6
|
type ViewMode = 'daily' | 'monthly' | 'yearly';
|
|
7
|
+
type DateRangePickerVariant = 'filled' | 'outline';
|
|
8
|
+
type DateRangePickerColor = 'neutral' | 'point' | 'danger';
|
|
7
9
|
export interface LDDateRangePickerProps {
|
|
10
|
+
variant?: DateRangePickerVariant;
|
|
8
11
|
/** 선택된 날짜 범위 ({ from, to? }) */
|
|
9
12
|
value?: DateRange;
|
|
10
13
|
/** 날짜 범위 변경 시 호출되는 콜백 */
|
|
@@ -14,19 +17,23 @@ export interface LDDateRangePickerProps {
|
|
|
14
17
|
/** true 시 너비 100% */
|
|
15
18
|
block?: boolean;
|
|
16
19
|
/** 색상 테마 (danger 시 에러 스타일) */
|
|
17
|
-
color?:
|
|
20
|
+
color?: DateRangePickerColor;
|
|
21
|
+
/** 미선택 시 표시할 텍스트 */
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
/** 날짜 표시 형식 */
|
|
24
|
+
dateFormat?: string;
|
|
25
|
+
/** 시간 표시 형식 */
|
|
26
|
+
timeFormat?: string;
|
|
18
27
|
/** 현재 시점 이후 날짜 선택 비활성화 */
|
|
19
28
|
isDisableAfterNow?: boolean;
|
|
20
29
|
/** 날짜 범위 완성 시 팝오버 자동 닫힘 */
|
|
21
30
|
isAutoClose?: boolean;
|
|
22
31
|
/** 선택 모드 (daily: 일별, monthly: 월별, yearly: 연별) */
|
|
23
32
|
viewMode?: ViewMode;
|
|
24
|
-
/** 초기 선택 날짜 범위 (uncontrolled) */
|
|
25
|
-
defaultValue?: DateRange;
|
|
26
33
|
/** 초기값 (리셋 시 이 값으로 복원) */
|
|
27
34
|
initialValue?: {
|
|
28
|
-
from: string;
|
|
29
|
-
to
|
|
35
|
+
from: string | Date;
|
|
36
|
+
to?: string | Date;
|
|
30
37
|
};
|
|
31
38
|
/** 트리거 우측 아이콘 */
|
|
32
39
|
trailingIcon?: ReactNode;
|
|
@@ -44,6 +51,6 @@ export interface LDDateRangePickerProps {
|
|
|
44
51
|
/** 트리거 버튼 className */
|
|
45
52
|
triggerClassName?: string;
|
|
46
53
|
}
|
|
47
|
-
declare const LDDateRangePicker: ({ value, onChange, disabled, block, color, isDisableAfterNow, isAutoClose, viewMode,
|
|
54
|
+
declare const LDDateRangePicker: ({ variant, value, onChange, disabled, block, color, placeholder, dateFormat, timeFormat, isDisableAfterNow, isAutoClose, viewMode, initialValue, trailingIcon, onRangeComplete, onResetComplete, className, style, triggerClassName, }: LDDateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
48
55
|
export default LDDateRangePicker;
|
|
49
56
|
//# sourceMappingURL=LDDateRangePicker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDDateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/LDDateRangePicker/LDDateRangePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"LDDateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/LDDateRangePicker/LDDateRangePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAWf,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAC3C,KAAK,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAC/C,KAAK,sBAAsB,GAAG,QAAQ,GAAG,SAAS,CAAC;AACnD,KAAK,oBAAoB,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAqB3D,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,gCAAgC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,0BAA0B;IAC1B,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC3D,iBAAiB;IACjB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,EAAE,EAAE,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5D,0BAA0B;IAC1B,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,uBAAuB;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAwBD,QAAA,MAAM,iBAAiB,GAAI,wOAoBxB,sBAAsB,4CAwSxB,CAAC;AA6LF,eAAe,iBAAiB,CAAC"}
|
|
@@ -1,121 +1,171 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
5
|
import { ko } from 'react-day-picker/locale';
|
|
6
6
|
import PopoverBase from '../LDPopover/PopoverBase.js';
|
|
7
|
-
import LDCalendar from '../LDCalendar/LDCalendar.js';
|
|
8
|
-
import
|
|
7
|
+
import LDCalendar, { TimePicker } from '../LDCalendar/LDCalendar.js';
|
|
8
|
+
import LDButton from '../LDButton/LDButton.js';
|
|
9
9
|
import cn from '../../utils/cn.js';
|
|
10
|
+
import { Calendar, ChevronLeft, ChevronRight, RotateCw } from 'lucide-react';
|
|
11
|
+
import LDDivider from '../../components/LDDivider/LDDivider.js';
|
|
10
12
|
const dateFormats = {
|
|
11
|
-
daily: '
|
|
12
|
-
monthly: '
|
|
13
|
+
daily: 'YYYYMMDD',
|
|
14
|
+
monthly: 'YYYYMM',
|
|
13
15
|
yearly: 'YYYY',
|
|
14
16
|
};
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const timeFromDate = (date) => date ? dayjs(date).format('HH:mm:ss') : '00:00:00';
|
|
18
|
+
const composeDateTime = (date, time) => {
|
|
19
|
+
const [h, m, s] = time.split(':').map(Number);
|
|
20
|
+
return dayjs(date)
|
|
21
|
+
.hour(h ?? 0)
|
|
22
|
+
.minute(m ?? 0)
|
|
23
|
+
.second(s ?? 0)
|
|
24
|
+
.toDate();
|
|
19
25
|
};
|
|
20
|
-
const
|
|
26
|
+
const variantColorClasses = {
|
|
27
|
+
filled: {
|
|
28
|
+
neutral: 'bg-neutral50 text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] focus:bg-tintBlue focus:outline-lb500',
|
|
29
|
+
point: 'bg-tintBlue text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] focus:outline-lb500',
|
|
30
|
+
danger: 'bg-tintRed text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] outline-danger600',
|
|
31
|
+
},
|
|
32
|
+
outline: {
|
|
33
|
+
neutral: 'bg-transparent text-neutral900 border-none outline-2 outline-neutral100 [outline-style:solid] [outline-offset:-2px] focus:outline-lb500',
|
|
34
|
+
point: 'bg-transparent text-neutral900 border-none outline-2 outline-lb500 [outline-style:solid] [outline-offset:-2px]',
|
|
35
|
+
danger: 'bg-transparent text-neutral900 border-none outline-2 outline-danger600 [outline-style:solid] [outline-offset:-2px]',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
const LDDateRangePicker = ({ variant = 'filled', value, onChange, disabled = false, block = false, color = 'neutral', placeholder, dateFormat, timeFormat = 'HH:MM:SS', isDisableAfterNow = false, isAutoClose = false, viewMode = 'daily', initialValue, trailingIcon = _jsx(Calendar, { size: 15, className: "text-mono400" }), onRangeComplete, onResetComplete, className, style, triggerClassName, }) => {
|
|
39
|
+
const fmt = dateFormat ?? dateFormats[viewMode];
|
|
40
|
+
const normalizedTimeFormat = timeFormat
|
|
41
|
+
.replaceAll('M', 'm')
|
|
42
|
+
.replaceAll('S', 's');
|
|
21
43
|
const [open, setOpen] = useState(false);
|
|
22
|
-
const [
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
44
|
+
const [leftMonth, setLeftMonth] = useState(new Date());
|
|
45
|
+
const [rightMonth, setRightMonth] = useState(dayjs().add(1, 'month').toDate());
|
|
46
|
+
const [selectedRange, setSelectedRange] = useState(value);
|
|
47
|
+
const [fromTime, setFromTime] = useState(timeFromDate(value?.from));
|
|
48
|
+
const [toTime, setToTime] = useState(timeFromDate(value?.to));
|
|
49
|
+
// 시간은 ref로도 들고 있어 select 핸들러가 시간 변경에도 참조 안정 유지(memo 스킵용)
|
|
50
|
+
const fromTimeRef = useRef(fromTime);
|
|
51
|
+
const toTimeRef = useRef(toTime);
|
|
52
|
+
fromTimeRef.current = fromTime;
|
|
53
|
+
toTimeRef.current = toTime;
|
|
54
|
+
// selectedRange(날짜)와 fromTime/toTime(시간)을 병합. 커밋·표시 시점에만 사용.
|
|
55
|
+
const composeRange = useCallback((r) => r?.from
|
|
56
|
+
? {
|
|
57
|
+
from: composeDateTime(r.from, fromTimeRef.current),
|
|
58
|
+
to: r.to ? composeDateTime(r.to, toTimeRef.current) : undefined,
|
|
59
|
+
}
|
|
60
|
+
: undefined, []);
|
|
61
|
+
const isDateDisabled = useMemo(() => (isDisableAfterNow ? (date) => date > new Date() : false), [isDisableAfterNow]);
|
|
62
|
+
const leftEndMonth = useMemo(() => dayjs(rightMonth).subtract(1, 'month').toDate(), [rightMonth]);
|
|
63
|
+
const rightStartMonth = useMemo(() => dayjs(leftMonth).add(1, 'month').toDate(), [leftMonth]);
|
|
64
|
+
const baseline = initialValue
|
|
65
|
+
? {
|
|
66
|
+
from: dayjs(initialValue.from).toDate(),
|
|
67
|
+
to: initialValue.to ? dayjs(initialValue.to).toDate() : undefined,
|
|
68
|
+
}
|
|
69
|
+
: undefined;
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (open)
|
|
72
|
+
return;
|
|
73
|
+
setSelectedRange(value);
|
|
74
|
+
setFromTime(timeFromDate(value?.from));
|
|
75
|
+
setToTime(timeFromDate(value?.to));
|
|
76
|
+
}, [open, value]);
|
|
77
|
+
const displayRange = open ? composeRange(selectedRange) : value;
|
|
78
|
+
const displayFmt = viewMode === 'daily' ? `${fmt} ${normalizedTimeFormat}` : fmt;
|
|
79
|
+
const placeholderFmt = viewMode === 'daily' ? `${fmt} ${timeFormat}` : fmt;
|
|
80
|
+
const placeholderText = placeholder ?? `${placeholderFmt} ~ ${placeholderFmt}`;
|
|
26
81
|
const renderDateRange = () => {
|
|
27
|
-
if (!
|
|
28
|
-
return _jsx("span", { className: "text-mono400", children:
|
|
82
|
+
if (!displayRange?.from) {
|
|
83
|
+
return _jsx("span", { className: "text-mono400", children: placeholderText });
|
|
29
84
|
}
|
|
30
|
-
if (!
|
|
31
|
-
return (_jsxs("span", { className: "text-mono400", children: [dayjs(
|
|
85
|
+
if (!displayRange.to) {
|
|
86
|
+
return (_jsxs("span", { className: "text-mono400", children: [dayjs(displayRange.from).format(displayFmt), " ~ ", placeholderFmt] }));
|
|
32
87
|
}
|
|
33
|
-
return (_jsxs(_Fragment, { children: [dayjs(
|
|
88
|
+
return (_jsxs(_Fragment, { children: [dayjs(displayRange.from).format(displayFmt), " ~", ' ', dayjs(displayRange.to).format(displayFmt)] }));
|
|
89
|
+
};
|
|
90
|
+
const reset = (r) => {
|
|
91
|
+
setFromTime(timeFromDate(r?.from));
|
|
92
|
+
setToTime(timeFromDate(r?.to));
|
|
34
93
|
};
|
|
94
|
+
// rotate: initialValue(baseline)로 복원. 기존 동작대로 즉시 커밋한다.
|
|
35
95
|
const handleReset = (e) => {
|
|
36
96
|
e.stopPropagation();
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
to: dayjs(initialValue.to).toDate(),
|
|
41
|
-
}
|
|
42
|
-
: undefined;
|
|
43
|
-
if (!isControlled)
|
|
44
|
-
setInternal(resetValue);
|
|
45
|
-
onChange?.(resetValue);
|
|
97
|
+
setSelectedRange(baseline);
|
|
98
|
+
reset(baseline);
|
|
99
|
+
onChange?.(baseline);
|
|
46
100
|
onResetComplete?.();
|
|
47
101
|
};
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
102
|
+
const formatRangeDate = (date) => date ? dayjs(date).format(fmt) : '';
|
|
103
|
+
const isResetAvailable = baseline?.from
|
|
104
|
+
? formatRangeDate(selectedRange?.from) !== formatRangeDate(baseline.from) ||
|
|
105
|
+
formatRangeDate(selectedRange?.to) !== formatRangeDate(baseline.to) ||
|
|
106
|
+
// daily 모드는 시간 차이도 리셋 대상
|
|
107
|
+
(viewMode === 'daily' &&
|
|
108
|
+
(fromTime !== timeFromDate(baseline.from) ||
|
|
109
|
+
toTime !== timeFromDate(baseline.to)))
|
|
110
|
+
: !!selectedRange?.from;
|
|
111
|
+
const handleConfirm = () => {
|
|
112
|
+
onChange?.(composeRange(selectedRange));
|
|
113
|
+
setOpen(false);
|
|
114
|
+
};
|
|
115
|
+
const handleCancel = () => {
|
|
116
|
+
setSelectedRange(value);
|
|
117
|
+
reset(value);
|
|
118
|
+
setOpen(false);
|
|
119
|
+
};
|
|
120
|
+
const handleOpenChange = (next) => {
|
|
121
|
+
if (next) {
|
|
122
|
+
setSelectedRange(value); // 열 때 현재 값으로 편집 시작
|
|
123
|
+
reset(value);
|
|
124
|
+
setOpen(true);
|
|
54
125
|
return;
|
|
55
|
-
if (!isControlled)
|
|
56
|
-
setInternal(range);
|
|
57
|
-
onChange?.(range);
|
|
58
|
-
if (range.from && range.to) {
|
|
59
|
-
onRangeComplete?.(range);
|
|
60
|
-
if (isAutoClose)
|
|
61
|
-
setOpen(false);
|
|
62
126
|
}
|
|
127
|
+
// overlay·ESC: 선택이 있으면 커밋, 없으면 그냥 닫기
|
|
128
|
+
if (selectedRange?.from)
|
|
129
|
+
handleConfirm();
|
|
130
|
+
else
|
|
131
|
+
setOpen(false);
|
|
63
132
|
};
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (current?.from && !current?.to && selected?.from && selected?.to) {
|
|
70
|
-
handleRangeSelect(selected);
|
|
133
|
+
// 시간만 갱신 (selectedRange는 안 건드림 → 캘린더 selected 불변 → 애니메이션 재실행 X)
|
|
134
|
+
const handleFromTime = (time) => setFromTime(time);
|
|
135
|
+
const handleToTime = (time) => setToTime(time);
|
|
136
|
+
const handleRangeSelect = useCallback((range) => {
|
|
137
|
+
if (!range)
|
|
71
138
|
return;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
setInternal({ from: selected.from, to: undefined });
|
|
80
|
-
onChange?.({ from: selected.from, to: undefined });
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (selected?.from && selected?.to) {
|
|
84
|
-
const clickedDate = selected.from.getTime() !== current.from.getTime() &&
|
|
85
|
-
selected.from.getTime() !== current.to.getTime()
|
|
86
|
-
? selected.from
|
|
87
|
-
: selected.to.getTime() !== current.from.getTime() &&
|
|
88
|
-
selected.to.getTime() !== current.to.getTime()
|
|
89
|
-
? selected.to
|
|
90
|
-
: selected.from;
|
|
91
|
-
if (!isControlled)
|
|
92
|
-
setInternal({ from: clickedDate, to: undefined });
|
|
93
|
-
onChange?.({ from: clickedDate, to: undefined });
|
|
94
|
-
return;
|
|
139
|
+
setSelectedRange(range);
|
|
140
|
+
if (range.from && range.to) {
|
|
141
|
+
const composed = composeRange(range);
|
|
142
|
+
onRangeComplete?.(composed);
|
|
143
|
+
if (isAutoClose) {
|
|
144
|
+
onChange?.(composed);
|
|
145
|
+
setOpen(false);
|
|
95
146
|
}
|
|
96
147
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
else {
|
|
106
|
-
if (!isControlled)
|
|
107
|
-
setInternal(selected);
|
|
108
|
-
onChange?.(selected);
|
|
148
|
+
}, [composeRange, isAutoClose, onChange, onRangeComplete]);
|
|
149
|
+
const handleDailySelect = useCallback((selected, clickedDate) => {
|
|
150
|
+
if (selectedRange?.from &&
|
|
151
|
+
!selectedRange.to &&
|
|
152
|
+
selected?.from &&
|
|
153
|
+
selected?.to) {
|
|
154
|
+
handleRangeSelect({ from: selected.from, to: selected.to });
|
|
155
|
+
return;
|
|
109
156
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
157
|
+
setSelectedRange({ from: clickedDate, to: undefined });
|
|
158
|
+
}, [selectedRange, handleRangeSelect]);
|
|
159
|
+
return (_jsx("div", { className: cn(block ? 'w-full' : 'w-auto', className), children: _jsxs(PopoverBase.Root, { open: open, onOpenChange: handleOpenChange, children: [_jsxs(PopoverBase.Trigger, { disabled: disabled, style: style, className: cn('border border-neutral100 h-[38px] w-full display14 px-4 rounded-[5px]', 'flex flex-row items-center justify-between gap-4', 'whitespace-nowrap outline-2 outline-transparent ld-transition', disabled
|
|
160
|
+
? 'cursor-not-allowed opacity-50'
|
|
161
|
+
: variantColorClasses[variant][color], triggerClassName), children: [renderDateRange(), _jsxs("div", { className: "shrink-0 flex items-center gap-xs", children: [_jsx("span", { role: "button", tabIndex: 0, className: cn('inline-flex items-center text-mono400 cursor-pointer transition-opacity duration-300', isResetAvailable
|
|
162
|
+
? 'opacity-100'
|
|
163
|
+
: 'opacity-0 pointer-events-none'), onClick: handleReset, onKeyDown: (e) => {
|
|
114
164
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
115
165
|
e.preventDefault();
|
|
116
166
|
handleReset(e);
|
|
117
167
|
}
|
|
118
|
-
}, children: _jsx(
|
|
168
|
+
}, children: _jsx(RotateCw, { size: 15 }) }), trailingIcon] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white shadow-md p-0", children: _jsxs("div", { className: "flex flex-col", children: [viewMode === 'daily' && (_jsxs("div", { className: "flex flex-row mobile:flex-col", children: [_jsxs("div", { className: "flex flex-row max-h-90", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: leftMonth, onMonthChange: setLeftMonth, endMonth: leftEndMonth, disabled: isDateDisabled }), _jsx(TimePicker, { value: fromTime, onChange: handleFromTime, className: "shrink-0" })] }), _jsx(LDDivider, { orientation: "vertical", className: "h-auto self-stretch inline-block mobile:hidden" }), _jsx(LDDivider, { orientation: "horizontal", className: "w-auto self-stretch hidden mobile:inline-block" }), _jsxs("div", { className: "flex flex-row max-h-90", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: rightMonth, onMonthChange: setRightMonth, startMonth: rightStartMonth, disabled: isDateDisabled }), _jsx(TimePicker, { value: toTime, onChange: handleToTime, className: "shrink-0" })] })] })), viewMode === 'monthly' && (_jsx(MonthRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), viewMode === 'yearly' && (_jsx(YearRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), _jsxs("div", { className: "flex items-center justify-end gap-sm py-xs px-sm border-t border-neutral100", children: [_jsx(LDButton, { variant: "outline", color: "neutral", onClick: handleCancel, children: "\uCDE8\uC18C" }), _jsx(LDButton, { onClick: handleConfirm, children: "\uD655\uC778" })] })] }) })] }) }));
|
|
119
169
|
};
|
|
120
170
|
// ── MonthRangePicker ──
|
|
121
171
|
const MonthRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
|
|
@@ -151,8 +201,8 @@ const MonthRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
|
|
|
151
201
|
return false;
|
|
152
202
|
return new Date(currentYear, month, 1) > dayjs(now).endOf('month').toDate();
|
|
153
203
|
};
|
|
154
|
-
return (_jsxs("div", { className: "p-3 w-[280px]", children: [_jsxs("div", { className: "flex items-center justify-between mb-4 px-2", children: [_jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer", onClick: () => setCurrentYear((prev) => prev - 1), children: _jsx(
|
|
155
|
-
? 'bg-
|
|
204
|
+
return (_jsxs("div", { className: "p-3 w-[280px]", children: [_jsxs("div", { className: "flex items-center justify-between mb-4 px-2", children: [_jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer", onClick: () => setCurrentYear((prev) => prev - 1), children: _jsx(ChevronLeft, { size: 16 }) }), _jsxs("span", { className: "display14 bold", children: [currentYear, "\uB144"] }), _jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed", onClick: () => setCurrentYear((prev) => prev + 1), disabled: isDisableAfterNow && currentYear >= now.getFullYear(), children: _jsx(ChevronRight, { size: 16 }) })] }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: Array.from({ length: 12 }, (_, m) => (_jsxs("button", { type: "button", onClick: () => handleMonthClick(m), disabled: isDisabled(m), className: cn('h-10 rounded-md display12 ld-transition cursor-pointer', isSelected(m)
|
|
205
|
+
? 'bg-tintBlue text-lb500 bold'
|
|
156
206
|
: 'hover:bg-neutral100 text-mono500', isDisabled(m) && 'opacity-30 cursor-not-allowed'), children: [m + 1, "\uC6D4"] }, m))) })] }));
|
|
157
207
|
};
|
|
158
208
|
// ── YearRangePicker ──
|
|
@@ -189,9 +239,9 @@ const YearRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
|
|
|
189
239
|
return false;
|
|
190
240
|
return year > now.getFullYear();
|
|
191
241
|
};
|
|
192
|
-
return (_jsxs("div", { className: "p-3 w-[280px]", children: [_jsxs("div", { className: "flex items-center justify-between mb-4 px-2", children: [_jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer", onClick: () => setStartYearPage((prev) => prev - 12), children: _jsx(
|
|
193
|
-
(years[years.length - 1] ?? 0) >= now.getFullYear(), children: _jsx(
|
|
194
|
-
? 'bg-
|
|
242
|
+
return (_jsxs("div", { className: "p-3 w-[280px]", children: [_jsxs("div", { className: "flex items-center justify-between mb-4 px-2", children: [_jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer", onClick: () => setStartYearPage((prev) => prev - 12), children: _jsx(ChevronLeft, { size: 16 }) }), _jsxs("span", { className: "display14 bold", children: [years[0], " - ", years[years.length - 1]] }), _jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed", onClick: () => setStartYearPage((prev) => prev + 12), disabled: isDisableAfterNow &&
|
|
243
|
+
(years[years.length - 1] ?? 0) >= now.getFullYear(), children: _jsx(ChevronRight, { size: 16 }) })] }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: years.map((y) => (_jsxs("button", { type: "button", onClick: () => handleYearClick(y), disabled: isDisabled(y), className: cn('h-10 rounded-md display12 ld-transition cursor-pointer', isSelected(y)
|
|
244
|
+
? 'bg-tintBlue text-lb500 bold'
|
|
195
245
|
: 'hover:bg-neutral100 text-mono500', isDisabled(y) && 'opacity-30 cursor-not-allowed'), children: [y, "\uB144"] }, y))) })] }));
|
|
196
246
|
};
|
|
197
247
|
export default LDDateRangePicker;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type RegisterOptions } from 'react-hook-form';
|
|
2
|
+
import { type LDDateRangePickerProps } from './LDDateRangePicker.js';
|
|
3
|
+
interface LDFormDateRangePickerProps extends Omit<LDDateRangePickerProps, 'value' | 'onChange'> {
|
|
4
|
+
name: string;
|
|
5
|
+
options?: RegisterOptions;
|
|
6
|
+
customErrorMessage?: string;
|
|
7
|
+
isHiddenErrorMessage?: boolean;
|
|
8
|
+
isToastErrorMessage?: boolean;
|
|
9
|
+
errorClassName?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const LDFormDateRangePicker: ({ name, options, customErrorMessage, isHiddenErrorMessage, errorClassName, disabled, block, ...props }: LDFormDateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default LDFormDateRangePicker;
|
|
13
|
+
//# sourceMappingURL=LDFormDateRangePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDFormDateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/LDDateRangePicker/LDFormDateRangePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,iBAAiB,CAAC;AACvE,OAA0B,EACxB,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAC;AAK7B,UAAU,0BAA2B,SAAQ,IAAI,CAC/C,sBAAsB,EACtB,OAAO,GAAG,UAAU,CACrB;IACC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,QAAA,MAAM,qBAAqB,GAAI,wGAS5B,0BAA0B,4CAyC5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useFormContext } from 'react-hook-form';
|
|
4
|
+
import LDDateRangePicker from './LDDateRangePicker.js';
|
|
5
|
+
import FormField from '../LDForm/LDFormField.js';
|
|
6
|
+
import FormErrorMessage from '../LDForm/LDFormErrorMessage.js';
|
|
7
|
+
import cn from '../../utils/cn.js';
|
|
8
|
+
const LDFormDateRangePicker = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = true, errorClassName, disabled = false, block = false, ...props }) => {
|
|
9
|
+
const { formState } = useFormContext();
|
|
10
|
+
const defaultValue = formState.defaultValues?.[name];
|
|
11
|
+
const initialValue = props.initialValue ??
|
|
12
|
+
(defaultValue?.from
|
|
13
|
+
? {
|
|
14
|
+
from: defaultValue.from,
|
|
15
|
+
to: defaultValue.to,
|
|
16
|
+
}
|
|
17
|
+
: undefined);
|
|
18
|
+
return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, children: ({ field, fieldState }) => (_jsxs("div", { className: cn('relative', block ? 'w-full' : 'w-auto'), children: [_jsx(LDDateRangePicker, { ...props, block: block, value: field.value ?? undefined, initialValue: initialValue, onChange: field.onChange, disabled: disabled, color: fieldState.hasError ? 'danger' : (props.color ?? 'neutral') }), _jsx(FormErrorMessage, { error: fieldState.error, disabled: disabled, className: cn(isHiddenErrorMessage && 'hidden', errorClassName) })] })) }));
|
|
19
|
+
};
|
|
20
|
+
export default LDFormDateRangePicker;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import DrawerBase from './DrawerBase.js';
|
|
3
|
-
import LucideIcon from '../Icon/LucideIcon.js';
|
|
4
3
|
import LDButton from '../LDButton/LDButton.js';
|
|
5
4
|
import cn from '../../utils/cn.js';
|
|
5
|
+
import { X } from 'lucide-react';
|
|
6
6
|
// ── 방향별 스타일 매핑 ──
|
|
7
7
|
const directionClasses = {
|
|
8
8
|
bottom: 'bottom-0 left-0 right-0 rounded-t-2xl max-h-[95dvh] flex flex-col',
|
|
@@ -25,6 +25,6 @@ const LDDrawer = ({ open, defaultOpen, onOpenChange, direction = 'bottom', snapP
|
|
|
25
25
|
onOpenChange?.(false);
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
-
return (_jsxs(DrawerBase.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, direction: direction, snapPoints: snapPoints, activeSnapPoint: activeSnapPoint, setActiveSnapPoint: setActiveSnapPoint, children: [trigger && _jsx(DrawerBase.Trigger, { asChild: true, children: trigger }), _jsx(DrawerBase.Overlay, {}), _jsxs(DrawerBase.Content, { className: cn('bg-white', directionClasses[direction], className), style: style, children: [shouldShowHandle && _jsx(DrawerBase.Handle, {}), _jsxs("div", { className: "relative flex flex-col flex-1 overflow-hidden p-5 gap-6", children: [_jsx(DrawerBase.Close, { asChild: true, children: _jsx("button", { className: "absolute top-4 right-5 text-neutral500 cursor-pointer outline-hidden", children: _jsx(
|
|
28
|
+
return (_jsxs(DrawerBase.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, direction: direction, snapPoints: snapPoints, activeSnapPoint: activeSnapPoint, setActiveSnapPoint: setActiveSnapPoint, children: [trigger && _jsx(DrawerBase.Trigger, { asChild: true, children: trigger }), _jsx(DrawerBase.Overlay, {}), _jsxs(DrawerBase.Content, { className: cn('bg-white', directionClasses[direction], className), style: style, children: [shouldShowHandle && _jsx(DrawerBase.Handle, {}), _jsxs("div", { className: "relative flex flex-col flex-1 overflow-hidden p-5 gap-6", children: [_jsx(DrawerBase.Close, { asChild: true, children: _jsx("button", { className: "absolute top-4 right-5 text-neutral500 cursor-pointer outline-hidden", children: _jsx(X, { size: 16 }) }) }), (title || description) && (_jsxs("div", { className: "flex flex-col gap-2 pt-2", children: [title && (_jsx(DrawerBase.Title, { className: "display20 bold", children: title })), description && (_jsx(DrawerBase.Description, { className: "display14 text-neutral500", children: description }))] })), children && _jsx("div", { className: "flex-1 overflow-auto", children: children }), buttons && buttons.length > 0 && (_jsx("div", { className: "flex gap-2", children: buttons.map((button, index) => (_jsx(LDButton, { block: true, variant: button.variant, color: button.color, onClick: () => handleButtonClick(button), children: button.label }, index))) }))] })] })] }));
|
|
29
29
|
};
|
|
30
30
|
export default LDDrawer;
|