@loword/loword-design-system 0.0.1
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/README.md +20 -0
- package/dist/components/Avatar/Avatar.d.ts +11 -0
- package/dist/components/Avatar/Avatar.d.ts.map +1 -0
- package/dist/components/Avatar/Avatar.js +24 -0
- package/dist/components/Avatar/AvatarBase.d.ts +32 -0
- package/dist/components/Avatar/AvatarBase.d.ts.map +1 -0
- package/dist/components/Avatar/AvatarBase.js +49 -0
- package/dist/components/Badge/Badge.d.ts +25 -0
- package/dist/components/Badge/Badge.d.ts.map +1 -0
- package/dist/components/Badge/Badge.js +36 -0
- package/dist/components/Badge/BadgeBase.d.ts +10 -0
- package/dist/components/Badge/BadgeBase.d.ts.map +1 -0
- package/dist/components/Badge/BadgeBase.js +9 -0
- package/dist/components/Button/Button.d.ts +26 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/Button.js +102 -0
- package/dist/components/Button/ButtonBase.d.ts +5 -0
- package/dist/components/Button/ButtonBase.d.ts.map +1 -0
- package/dist/components/Button/ButtonBase.js +10 -0
- package/dist/components/Button/ButtonSpinner.d.ts +9 -0
- package/dist/components/Button/ButtonSpinner.d.ts.map +1 -0
- package/dist/components/Button/ButtonSpinner.js +14 -0
- package/dist/components/Calendar/Calendar.d.ts +16 -0
- package/dist/components/Calendar/Calendar.d.ts.map +1 -0
- package/dist/components/Calendar/Calendar.js +75 -0
- package/dist/components/Carousel/Carousel.d.ts +50 -0
- package/dist/components/Carousel/Carousel.d.ts.map +1 -0
- package/dist/components/Carousel/Carousel.js +22 -0
- package/dist/components/Carousel/CarouselBase.d.ts +98 -0
- package/dist/components/Carousel/CarouselBase.d.ts.map +1 -0
- package/dist/components/Carousel/CarouselBase.js +144 -0
- package/dist/components/Checkbox/Checkbox.d.ts +27 -0
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/Checkbox.js +30 -0
- package/dist/components/Checkbox/CheckboxBase.d.ts +40 -0
- package/dist/components/Checkbox/CheckboxBase.d.ts.map +1 -0
- package/dist/components/Checkbox/CheckboxBase.js +57 -0
- package/dist/components/Checkbox/CheckboxGroup.d.ts +22 -0
- package/dist/components/Checkbox/CheckboxGroup.d.ts.map +1 -0
- package/dist/components/Checkbox/CheckboxGroup.js +13 -0
- package/dist/components/Checkbox/FormCheckbox.d.ts +14 -0
- package/dist/components/Checkbox/FormCheckbox.d.ts.map +1 -0
- package/dist/components/Checkbox/FormCheckbox.js +9 -0
- package/dist/components/Checkbox/FormCheckboxGroup.d.ts +13 -0
- package/dist/components/Checkbox/FormCheckboxGroup.d.ts.map +1 -0
- package/dist/components/Checkbox/FormCheckboxGroup.js +9 -0
- package/dist/components/DataCalendar/DataCalendar.d.ts +12 -0
- package/dist/components/DataCalendar/DataCalendar.d.ts.map +1 -0
- package/dist/components/DataCalendar/DataCalendar.js +13 -0
- package/dist/components/DataCalendar/DataCalendarBase.d.ts +45 -0
- package/dist/components/DataCalendar/DataCalendarBase.d.ts.map +1 -0
- package/dist/components/DataCalendar/DataCalendarBase.js +57 -0
- package/dist/components/DatePicker/DatePicker.d.ts +34 -0
- package/dist/components/DatePicker/DatePicker.d.ts.map +1 -0
- package/dist/components/DatePicker/DatePicker.js +44 -0
- package/dist/components/DatePicker/FormDatePicker.d.ts +12 -0
- package/dist/components/DatePicker/FormDatePicker.d.ts.map +1 -0
- package/dist/components/DatePicker/FormDatePicker.js +12 -0
- package/dist/components/DateRangePicker/DateRangePicker.d.ts +49 -0
- package/dist/components/DateRangePicker/DateRangePicker.d.ts.map +1 -0
- package/dist/components/DateRangePicker/DateRangePicker.js +197 -0
- package/dist/components/DateRangePicker/FormDateRangePicker.d.ts +12 -0
- package/dist/components/DateRangePicker/FormDateRangePicker.d.ts.map +1 -0
- package/dist/components/DateRangePicker/FormDateRangePicker.js +10 -0
- package/dist/components/Drawer/Drawer.d.ts +51 -0
- package/dist/components/Drawer/Drawer.d.ts.map +1 -0
- package/dist/components/Drawer/Drawer.js +30 -0
- package/dist/components/Drawer/DrawerBase.d.ts +52 -0
- package/dist/components/Drawer/DrawerBase.d.ts.map +1 -0
- package/dist/components/Drawer/DrawerBase.js +38 -0
- package/dist/components/Editor/Editor.d.ts +12 -0
- package/dist/components/Editor/Editor.d.ts.map +1 -0
- package/dist/components/Editor/Editor.js +162 -0
- package/dist/components/Editor/EditorBase.d.ts +52 -0
- package/dist/components/Editor/EditorBase.d.ts.map +1 -0
- package/dist/components/Editor/EditorBase.js +89 -0
- package/dist/components/Editor/Viewer.d.ts +7 -0
- package/dist/components/Editor/Viewer.d.ts.map +1 -0
- package/dist/components/Editor/Viewer.js +9 -0
- package/dist/components/Editor/extensions.d.ts +6 -0
- package/dist/components/Editor/extensions.d.ts.map +1 -0
- package/dist/components/Editor/extensions.js +38 -0
- package/dist/components/FileUpload/FileUploadBase.d.ts +50 -0
- package/dist/components/FileUpload/FileUploadBase.d.ts.map +1 -0
- package/dist/components/FileUpload/FileUploadBase.js +102 -0
- package/dist/components/Form/Form.d.ts +21 -0
- package/dist/components/Form/Form.d.ts.map +1 -0
- package/dist/components/Form/Form.js +18 -0
- package/dist/components/Form/FormErrorMessage.d.ts +9 -0
- package/dist/components/Form/FormErrorMessage.d.ts.map +1 -0
- package/dist/components/Form/FormErrorMessage.js +6 -0
- package/dist/components/Form/FormField.d.ts +55 -0
- package/dist/components/Form/FormField.d.ts.map +1 -0
- package/dist/components/Form/FormField.js +43 -0
- package/dist/components/Icon/LucideIcon.d.ts +11 -0
- package/dist/components/Icon/LucideIcon.d.ts.map +1 -0
- package/dist/components/Icon/LucideIcon.js +41 -0
- package/dist/components/Input/FormInput.d.ts +15 -0
- package/dist/components/Input/FormInput.d.ts.map +1 -0
- package/dist/components/Input/FormInput.js +19 -0
- package/dist/components/Input/Input.d.ts +24 -0
- package/dist/components/Input/Input.d.ts.map +1 -0
- package/dist/components/Input/Input.js +71 -0
- package/dist/components/Input/InputBase.d.ts +22 -0
- package/dist/components/Input/InputBase.d.ts.map +1 -0
- package/dist/components/Input/InputBase.js +17 -0
- package/dist/components/LNB/LNBBase.d.ts +82 -0
- package/dist/components/LNB/LNBBase.d.ts.map +1 -0
- package/dist/components/LNB/LNBBase.js +108 -0
- package/dist/components/LoadingDots/LoadingDots.d.ts +8 -0
- package/dist/components/LoadingDots/LoadingDots.d.ts.map +1 -0
- package/dist/components/LoadingDots/LoadingDots.js +29 -0
- package/dist/components/MenuBar/MenuBar.d.ts +21 -0
- package/dist/components/MenuBar/MenuBar.d.ts.map +1 -0
- package/dist/components/MenuBar/MenuBar.js +33 -0
- package/dist/components/MenuBar/MenuBarBase.d.ts +43 -0
- package/dist/components/MenuBar/MenuBarBase.d.ts.map +1 -0
- package/dist/components/MenuBar/MenuBarBase.js +69 -0
- package/dist/components/Modal/Modal.d.ts +51 -0
- package/dist/components/Modal/Modal.d.ts.map +1 -0
- package/dist/components/Modal/Modal.js +72 -0
- package/dist/components/Modal/ModalBase.d.ts +42 -0
- package/dist/components/Modal/ModalBase.d.ts.map +1 -0
- package/dist/components/Modal/ModalBase.js +30 -0
- package/dist/components/Modal/openModal.d.ts +24 -0
- package/dist/components/Modal/openModal.d.ts.map +1 -0
- package/dist/components/Modal/openModal.js +52 -0
- package/dist/components/OTPInput/OTPInput.d.ts +46 -0
- package/dist/components/OTPInput/OTPInput.d.ts.map +1 -0
- package/dist/components/OTPInput/OTPInput.js +87 -0
- package/dist/components/Pagination/Pagination.d.ts +12 -0
- package/dist/components/Pagination/Pagination.d.ts.map +1 -0
- package/dist/components/Pagination/Pagination.js +5 -0
- package/dist/components/Pagination/PaginationBase.d.ts +36 -0
- package/dist/components/Pagination/PaginationBase.d.ts.map +1 -0
- package/dist/components/Pagination/PaginationBase.js +44 -0
- package/dist/components/Pagination/paginationUtils.d.ts +2 -0
- package/dist/components/Pagination/paginationUtils.d.ts.map +1 -0
- package/dist/components/Pagination/paginationUtils.js +18 -0
- package/dist/components/Popover/Popover.d.ts +42 -0
- package/dist/components/Popover/Popover.d.ts.map +1 -0
- package/dist/components/Popover/Popover.js +31 -0
- package/dist/components/Popover/PopoverBase.d.ts +31 -0
- package/dist/components/Popover/PopoverBase.d.ts.map +1 -0
- package/dist/components/Popover/PopoverBase.js +18 -0
- package/dist/components/Radio/FormRadioGroup.d.ts +13 -0
- package/dist/components/Radio/FormRadioGroup.d.ts.map +1 -0
- package/dist/components/Radio/FormRadioGroup.js +9 -0
- package/dist/components/Radio/Radio.d.ts +24 -0
- package/dist/components/Radio/Radio.d.ts.map +1 -0
- package/dist/components/Radio/Radio.js +39 -0
- package/dist/components/Radio/RadioBase.d.ts +38 -0
- package/dist/components/Radio/RadioBase.d.ts.map +1 -0
- package/dist/components/Radio/RadioBase.js +46 -0
- package/dist/components/Radio/RadioGroup.d.ts +22 -0
- package/dist/components/Radio/RadioGroup.d.ts.map +1 -0
- package/dist/components/Radio/RadioGroup.js +7 -0
- package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
- package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -0
- package/dist/components/ScrollArea/ScrollArea.js +10 -0
- package/dist/components/Select/FormMultiSelect.d.ts +13 -0
- package/dist/components/Select/FormMultiSelect.d.ts.map +1 -0
- package/dist/components/Select/FormMultiSelect.js +14 -0
- package/dist/components/Select/FormSelect.d.ts +13 -0
- package/dist/components/Select/FormSelect.d.ts.map +1 -0
- package/dist/components/Select/FormSelect.js +10 -0
- package/dist/components/Select/MultiSelect.d.ts +31 -0
- package/dist/components/Select/MultiSelect.d.ts.map +1 -0
- package/dist/components/Select/MultiSelect.js +59 -0
- package/dist/components/Select/Select.d.ts +41 -0
- package/dist/components/Select/Select.d.ts.map +1 -0
- package/dist/components/Select/Select.js +55 -0
- package/dist/components/Select/SelectBase.d.ts +59 -0
- package/dist/components/Select/SelectBase.d.ts.map +1 -0
- package/dist/components/Select/SelectBase.js +211 -0
- package/dist/components/Skeleton/Skeleton.d.ts +10 -0
- package/dist/components/Skeleton/Skeleton.d.ts.map +1 -0
- package/dist/components/Skeleton/Skeleton.js +8 -0
- package/dist/components/Slider/Slider.d.ts +23 -0
- package/dist/components/Slider/Slider.d.ts.map +1 -0
- package/dist/components/Slider/Slider.js +195 -0
- package/dist/components/Spinner/Spinner.d.ts +25 -0
- package/dist/components/Spinner/Spinner.d.ts.map +1 -0
- package/dist/components/Spinner/Spinner.js +20 -0
- package/dist/components/Table/Table.d.ts +34 -0
- package/dist/components/Table/Table.d.ts.map +1 -0
- package/dist/components/Table/Table.js +29 -0
- package/dist/components/Table/TableBase.d.ts +37 -0
- package/dist/components/Table/TableBase.d.ts.map +1 -0
- package/dist/components/Table/TableBase.js +39 -0
- package/dist/components/Table/TableField.d.ts +64 -0
- package/dist/components/Table/TableField.d.ts.map +1 -0
- package/dist/components/Table/TableField.js +87 -0
- package/dist/components/Table/TanstackTable.d.ts +23 -0
- package/dist/components/Table/TanstackTable.d.ts.map +1 -0
- package/dist/components/Table/TanstackTable.js +35 -0
- package/dist/components/TimePicker/FormTimePicker.d.ts +12 -0
- package/dist/components/TimePicker/FormTimePicker.d.ts.map +1 -0
- package/dist/components/TimePicker/FormTimePicker.js +12 -0
- package/dist/components/TimePicker/TimePicker.d.ts +27 -0
- package/dist/components/TimePicker/TimePicker.d.ts.map +1 -0
- package/dist/components/TimePicker/TimePicker.js +120 -0
- package/dist/components/Toast/Toast.d.ts +18 -0
- package/dist/components/Toast/Toast.d.ts.map +1 -0
- package/dist/components/Toast/Toast.js +42 -0
- package/dist/components/Toast/Toaster.d.ts +7 -0
- package/dist/components/Toast/Toaster.d.ts.map +1 -0
- package/dist/components/Toast/Toaster.js +7 -0
- package/dist/components/ToggleButton/FormToggleButton.d.ts +12 -0
- package/dist/components/ToggleButton/FormToggleButton.d.ts.map +1 -0
- package/dist/components/ToggleButton/FormToggleButton.js +9 -0
- package/dist/components/ToggleButton/ToggleButton.d.ts +31 -0
- package/dist/components/ToggleButton/ToggleButton.d.ts.map +1 -0
- package/dist/components/ToggleButton/ToggleButton.js +42 -0
- package/dist/components/ToggleButton/ToggleButtonBase.d.ts +41 -0
- package/dist/components/ToggleButton/ToggleButtonBase.d.ts.map +1 -0
- package/dist/components/ToggleButton/ToggleButtonBase.js +59 -0
- package/dist/components/Tooltip/Tooltip.d.ts +18 -0
- package/dist/components/Tooltip/Tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip/Tooltip.js +13 -0
- package/dist/components/Tooltip/TooltipBase.d.ts +39 -0
- package/dist/components/Tooltip/TooltipBase.d.ts.map +1 -0
- package/dist/components/Tooltip/TooltipBase.js +46 -0
- package/dist/constants/file.d.ts +42 -0
- package/dist/constants/file.d.ts.map +1 -0
- package/dist/constants/file.js +47 -0
- package/dist/index.css +4061 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/types/polymorphic.d.ts +19 -0
- package/dist/types/polymorphic.d.ts.map +1 -0
- package/dist/types/polymorphic.js +1 -0
- package/dist/utils/cn.d.ts +4 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/cn.js +6 -0
- package/dist/utils/file.d.ts +16 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +58 -0
- package/dist/utils/renderIcon.d.ts +4 -0
- package/dist/utils/renderIcon.d.ts.map +1 -0
- package/dist/utils/renderIcon.js +11 -0
- package/dist/utils/utils.d.ts +2 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +5 -0
- package/package.json +239 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import TimePicker from './TimePicker.js';
|
|
4
|
+
import FormField from '../Form/FormField.js';
|
|
5
|
+
import FormErrorMessage from '../Form/FormErrorMessage.js';
|
|
6
|
+
import cn from '../../utils/cn.js';
|
|
7
|
+
const FormTimePicker = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = false, errorClassName, disabled = false, block = false, ...props }) => {
|
|
8
|
+
return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, children: ({ field, fieldState }) => (_jsxs("div", { className: cn('relative border-2 border-transparent', block ? 'w-full' : 'w-auto'), children: [_jsx(TimePicker, { ...props, block: block, value: field.value ?? '', onChange: (time) => {
|
|
9
|
+
field.onChange(time);
|
|
10
|
+
}, disabled: disabled, color: fieldState.hasError ? 'danger' : 'neutral' }), !isHiddenErrorMessage && (_jsx(FormErrorMessage, { error: fieldState.error, disabled: disabled, className: errorClassName }))] })) }));
|
|
11
|
+
};
|
|
12
|
+
export default FormTimePicker;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface TimePickerProps {
|
|
2
|
+
/** 선택된 시간 (HH:MM 형식) */
|
|
3
|
+
value?: string;
|
|
4
|
+
/** 초기 선택 시간 (uncontrolled) */
|
|
5
|
+
defaultValue?: string;
|
|
6
|
+
/** 시간 변경 시 호출되는 콜백 */
|
|
7
|
+
onChange?: (value: string) => void;
|
|
8
|
+
/** 미선택 시 표시할 텍스트 */
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
/** 비활성화 여부 */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
/** true 시 너비 100% */
|
|
13
|
+
block?: boolean;
|
|
14
|
+
/** 색상 테마 (danger 시 에러 스타일) */
|
|
15
|
+
color?: 'neutral' | 'danger';
|
|
16
|
+
/** 최소 선택 가능 시간 (HH:MM 형식, 이전 시간 비활성화) */
|
|
17
|
+
minTime?: string;
|
|
18
|
+
/** 추가 CSS 클래스 */
|
|
19
|
+
className?: string;
|
|
20
|
+
/** 인라인 스타일 (트리거 버튼에 적용) */
|
|
21
|
+
style?: React.CSSProperties;
|
|
22
|
+
/** 트리거 버튼 className */
|
|
23
|
+
triggerClassName?: string;
|
|
24
|
+
}
|
|
25
|
+
declare const TimePicker: ({ value, defaultValue, onChange, placeholder, disabled, block, color, minTime, className, style, triggerClassName, }: TimePickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export default TimePicker;
|
|
27
|
+
//# sourceMappingURL=TimePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimePicker.d.ts","sourceRoot":"","sources":["../../../src/components/TimePicker/TimePicker.tsx"],"names":[],"mappings":"AAsCA,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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;AAED,QAAA,MAAM,UAAU,GAAI,sHAYjB,eAAe,4CA4KjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo, useState, useRef } from 'react';
|
|
4
|
+
import PopoverBase from '../Popover/PopoverBase.js';
|
|
5
|
+
import LucideIcon from '../Icon/LucideIcon.js';
|
|
6
|
+
import cn from '../../utils/cn.js';
|
|
7
|
+
/** 시간 입력 자동 포맷팅 (1212 -> 12:12) */
|
|
8
|
+
const formatTimeInput = (value) => {
|
|
9
|
+
const numbers = value.replace(/\D/g, '');
|
|
10
|
+
if (!numbers)
|
|
11
|
+
return '';
|
|
12
|
+
const limitedNumbers = numbers.slice(0, 4);
|
|
13
|
+
if (limitedNumbers.length <= 2)
|
|
14
|
+
return limitedNumbers;
|
|
15
|
+
const hours = limitedNumbers.slice(0, 2);
|
|
16
|
+
const minutes = limitedNumbers.slice(2);
|
|
17
|
+
const hoursNum = parseInt(hours, 10);
|
|
18
|
+
if (hoursNum > 23)
|
|
19
|
+
return hours.slice(0, 1);
|
|
20
|
+
if (minutes) {
|
|
21
|
+
const minutesNum = parseInt(minutes, 10);
|
|
22
|
+
if (minutesNum > 59)
|
|
23
|
+
return `${hours}:${minutes.slice(0, 1)}`;
|
|
24
|
+
}
|
|
25
|
+
return `${hours}:${minutes}`;
|
|
26
|
+
};
|
|
27
|
+
// ── 시간 옵션 생성 (00:00 ~ 23:30, 30분 간격) ──
|
|
28
|
+
const generateTimeOptions = (minTime) => {
|
|
29
|
+
const options = [];
|
|
30
|
+
for (let hour = 0; hour < 24; hour++) {
|
|
31
|
+
for (let minute = 0; minute < 60; minute += 30) {
|
|
32
|
+
const timeString = `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
|
|
33
|
+
if (minTime && timeString < minTime)
|
|
34
|
+
continue;
|
|
35
|
+
options.push(timeString);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return options;
|
|
39
|
+
};
|
|
40
|
+
const TimePicker = ({ value, defaultValue, onChange, placeholder = 'HH:MM', disabled = false, block = false, color = 'neutral', minTime, className, style, triggerClassName, }) => {
|
|
41
|
+
const [open, setOpen] = useState(false);
|
|
42
|
+
const [internal, setInternal] = useState(defaultValue);
|
|
43
|
+
const [isEditable, setIsEditable] = useState(false);
|
|
44
|
+
const inputRef = useRef(null);
|
|
45
|
+
const isControlled = value !== undefined;
|
|
46
|
+
const resolved = isControlled ? value : internal;
|
|
47
|
+
const timeOptions = useMemo(() => generateTimeOptions(minTime), [minTime]);
|
|
48
|
+
const handleTimeSelect = (time) => {
|
|
49
|
+
if (!isControlled)
|
|
50
|
+
setInternal(time);
|
|
51
|
+
onChange?.(time);
|
|
52
|
+
setOpen(false);
|
|
53
|
+
};
|
|
54
|
+
const handleInputChange = (e) => {
|
|
55
|
+
const formatted = formatTimeInput(e.target.value);
|
|
56
|
+
if (!isControlled)
|
|
57
|
+
setInternal(formatted);
|
|
58
|
+
onChange?.(formatted);
|
|
59
|
+
};
|
|
60
|
+
const handlePencilClick = (e) => {
|
|
61
|
+
e.stopPropagation();
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
if (isEditable) {
|
|
64
|
+
setIsEditable(false);
|
|
65
|
+
inputRef.current?.blur();
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
setIsEditable(true);
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
inputRef.current?.focus();
|
|
71
|
+
}, 0);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const handleInputBlur = (e) => {
|
|
75
|
+
const relatedTarget = e.relatedTarget;
|
|
76
|
+
if (relatedTarget?.closest('[data-pencil-button]'))
|
|
77
|
+
return;
|
|
78
|
+
setIsEditable(false);
|
|
79
|
+
};
|
|
80
|
+
return (_jsx("div", { className: cn(block ? 'w-full' : 'w-auto', className), children: _jsxs(PopoverBase.Root, { open: open, onOpenChange: setOpen, children: [_jsxs(PopoverBase.Trigger, { disabled: disabled, style: style, onClick: (e) => {
|
|
81
|
+
if (isEditable)
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
}, className: cn('border border-neutral10 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 && 'cursor-not-allowed opacity-50', color === 'danger'
|
|
84
|
+
? 'bg-tintRed outline-red500'
|
|
85
|
+
: 'focus:bg-tintBlue focus:outline-lb500', triggerClassName), children: [_jsx("input", { ref: inputRef, type: "text", value: resolved ?? '', onChange: handleInputChange, onBlur: handleInputBlur, onKeyDown: (e) => {
|
|
86
|
+
if (e.key === 'ArrowDown') {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
setOpen(true);
|
|
89
|
+
}
|
|
90
|
+
}, placeholder: placeholder, "aria-label": "\uC2DC\uAC04 \uC785\uB825", disabled: disabled, readOnly: !isEditable, className: cn('flex-1 bg-transparent outline-none min-w-0', !resolved && 'text-neutral40', !isEditable && 'cursor-pointer') }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsx("span", { "data-pencil-button": true, role: "button", tabIndex: 0, "aria-label": "\uC9C1\uC811 \uC785\uB825 \uBAA8\uB4DC \uC804\uD658", onClick: handlePencilClick, onKeyDown: (e) => {
|
|
91
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
handlePencilClick(e);
|
|
94
|
+
}
|
|
95
|
+
}, className: cn('p-0 transition-colors cursor-pointer', isEditable ? 'text-lb500' : 'text-neutral40'), children: _jsx(LucideIcon, { name: "pencil", size: 15 }) }), _jsx(LucideIcon, { name: "clock", size: 15, className: "text-neutral40" })] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white shadow-md p-0", style: { width: 'var(--radix-popover-trigger-width)' }, onOpenAutoFocus: (e) => {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
const targetTime = timeOptions.find((t) => t >= (resolved || '00:00')) ||
|
|
98
|
+
timeOptions[0];
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
const targetButton = document.querySelector(`[data-time-picker-list] button[data-time="${targetTime}"]`);
|
|
101
|
+
if (targetButton) {
|
|
102
|
+
targetButton.focus();
|
|
103
|
+
targetButton.scrollIntoView({ block: 'nearest' });
|
|
104
|
+
}
|
|
105
|
+
}, 0);
|
|
106
|
+
}, children: _jsx("div", { "data-time-picker-list": true, role: "listbox", "aria-label": "\uC2DC\uAC04 \uC120\uD0DD \uBAA9\uB85D", className: "max-h-[240px] overflow-y-auto scrollbar-hide p-2", children: timeOptions.map((time) => (_jsx("button", { "data-time": time, type: "button", role: "option", "aria-selected": resolved === time, "aria-label": `${time.split(':')[0]}시 ${time.split(':')[1]}분`, onClick: () => handleTimeSelect(time), onKeyDown: (e) => {
|
|
107
|
+
const target = e.currentTarget;
|
|
108
|
+
if (e.key === 'ArrowDown') {
|
|
109
|
+
e.preventDefault();
|
|
110
|
+
target.nextElementSibling?.focus();
|
|
111
|
+
}
|
|
112
|
+
else if (e.key === 'ArrowUp') {
|
|
113
|
+
e.preventDefault();
|
|
114
|
+
target.previousElementSibling?.focus();
|
|
115
|
+
}
|
|
116
|
+
}, className: cn('w-full text-left px-3 py-2 rounded-[5px] display14 transition-all cursor-pointer outline-none', 'hover:bg-lb50 hover:text-lb500', 'focus:bg-lb50 focus:text-lb500 focus:ring-1 focus:ring-inset focus:ring-lb500', resolved === time
|
|
117
|
+
? 'bg-neutral10 font-bold'
|
|
118
|
+
: 'text-neutral800'), children: time }, time))) }) })] }) }));
|
|
119
|
+
};
|
|
120
|
+
export default TimePicker;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const Toast: {
|
|
2
|
+
/** 성공 메시지를 표시합니다 */
|
|
3
|
+
success: (content: string) => string;
|
|
4
|
+
/** 에러 메시지를 표시합니다 */
|
|
5
|
+
error: (content: string) => string;
|
|
6
|
+
/** 일반 알림 메시지를 표시합니다 */
|
|
7
|
+
info: (content: string) => string;
|
|
8
|
+
/** 경고 메시지를 표시합니다 */
|
|
9
|
+
warning: (content: string) => string;
|
|
10
|
+
/** 로딩 상태 메시지를 표시합니다 */
|
|
11
|
+
loading: (content: string) => string;
|
|
12
|
+
/** 현재 표시 중인 토스트를 모두 닫습니다 */
|
|
13
|
+
dismiss: () => void;
|
|
14
|
+
/** 인사 메시지를 표시합니다 */
|
|
15
|
+
hello: (content: string) => string;
|
|
16
|
+
};
|
|
17
|
+
export default Toast;
|
|
18
|
+
//# sourceMappingURL=Toast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../src/components/Toast/Toast.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,KAAK;IAChB,oBAAoB;uBACD,MAAM;IAIzB,oBAAoB;qBACH,MAAM;IAIvB,uBAAuB;oBACP,MAAM;IAItB,oBAAoB;uBACD,MAAM;IAUzB,uBAAuB;uBACJ,MAAM;IAIzB,4BAA4B;;IAE5B,oBAAoB;qBACH,MAAM;CAMxB,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import toast from 'react-hot-toast';
|
|
4
|
+
export const Toast = {
|
|
5
|
+
/** 성공 메시지를 표시합니다 */
|
|
6
|
+
success: (content) => {
|
|
7
|
+
toast.dismiss();
|
|
8
|
+
return toast.success(content);
|
|
9
|
+
},
|
|
10
|
+
/** 에러 메시지를 표시합니다 */
|
|
11
|
+
error: (content) => {
|
|
12
|
+
toast.dismiss();
|
|
13
|
+
return toast.error(content);
|
|
14
|
+
},
|
|
15
|
+
/** 일반 알림 메시지를 표시합니다 */
|
|
16
|
+
info: (content) => {
|
|
17
|
+
toast.dismiss();
|
|
18
|
+
return toast(content);
|
|
19
|
+
},
|
|
20
|
+
/** 경고 메시지를 표시합니다 */
|
|
21
|
+
warning: (content) => {
|
|
22
|
+
toast.dismiss();
|
|
23
|
+
return toast(content, {
|
|
24
|
+
icon: (_jsx("div", { className: "flex justify-center items-center w-5 h-5 bg-yellow-400 rounded-full text-mono5", children: "!" })),
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
/** 로딩 상태 메시지를 표시합니다 */
|
|
28
|
+
loading: (content) => {
|
|
29
|
+
toast.dismiss();
|
|
30
|
+
return toast.loading(content);
|
|
31
|
+
},
|
|
32
|
+
/** 현재 표시 중인 토스트를 모두 닫습니다 */
|
|
33
|
+
dismiss: () => toast.dismiss(),
|
|
34
|
+
/** 인사 메시지를 표시합니다 */
|
|
35
|
+
hello: (content) => {
|
|
36
|
+
toast.dismiss();
|
|
37
|
+
return toast(content, {
|
|
38
|
+
icon: _jsx("div", { className: "flex justify-center items-center w-5 h-5", children: "\uD83D\uDC4B" }),
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
export default Toast;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface ToasterProps {
|
|
2
|
+
position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
3
|
+
duration?: number;
|
|
4
|
+
}
|
|
5
|
+
declare const Toaster: ({ position, duration, }: ToasterProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export default Toaster;
|
|
7
|
+
//# sourceMappingURL=Toaster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"AAIA,UAAU,YAAY;IACpB,QAAQ,CAAC,EACL,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,eAAe,GACf,cAAc,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,QAAA,MAAM,OAAO,GAAI,yBAGd,YAAY,4CAEd,CAAC;AAEF,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Toaster as HotToaster } from 'react-hot-toast';
|
|
4
|
+
const Toaster = ({ position = 'top-center', duration = 2500, }) => {
|
|
5
|
+
return _jsx(HotToaster, { position: position, toastOptions: { duration } });
|
|
6
|
+
};
|
|
7
|
+
export default Toaster;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RegisterOptions } from 'react-hook-form';
|
|
2
|
+
import { type ToggleButtonProps } from './ToggleButton.js';
|
|
3
|
+
interface FormToggleButtonProps extends Omit<ToggleButtonProps, 'checked' | 'name' | 'onCheckedChange'> {
|
|
4
|
+
name: string;
|
|
5
|
+
options?: RegisterOptions;
|
|
6
|
+
customErrorMessage?: string;
|
|
7
|
+
isHiddenErrorMessage?: boolean;
|
|
8
|
+
errorClassName?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const FormToggleButton: ({ name, options, customErrorMessage, isHiddenErrorMessage, errorClassName, disabled, ...props }: FormToggleButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default FormToggleButton;
|
|
12
|
+
//# sourceMappingURL=FormToggleButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormToggleButton.d.ts","sourceRoot":"","sources":["../../../src/components/ToggleButton/FormToggleButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAItE,UAAU,qBAAsB,SAAQ,IAAI,CAC1C,iBAAiB,EACjB,SAAS,GAAG,MAAM,GAAG,iBAAiB,CACvC;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,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,QAAA,MAAM,gBAAgB,GAAI,iGAQvB,qBAAqB,4CAgCvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import ToggleButton from './ToggleButton.js';
|
|
4
|
+
import FormField from '../Form/FormField.js';
|
|
5
|
+
import FormErrorMessage from '../Form/FormErrorMessage.js';
|
|
6
|
+
const FormToggleButton = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = false, errorClassName, disabled = false, ...props }) => {
|
|
7
|
+
return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, children: ({ field, fieldState }) => (_jsxs("div", { className: "relative", children: [_jsx(ToggleButton, { ...props, checked: !!field.value, onCheckedChange: field.onChange, onBlur: field.onBlur, disabled: disabled, ref: field.ref, "aria-invalid": field['aria-invalid'], "aria-describedby": field['aria-describedby'] }), !isHiddenErrorMessage && (_jsx(FormErrorMessage, { id: fieldState.errorId, error: fieldState.error, disabled: disabled, className: errorClassName }))] })) }));
|
|
8
|
+
};
|
|
9
|
+
export default FormToggleButton;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';
|
|
3
|
+
export interface ToggleButtonProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
4
|
+
/** controlled 체크 상태 */
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
/** 초기 체크 상태 (uncontrolled) */
|
|
7
|
+
defaultChecked?: boolean;
|
|
8
|
+
/** 체크 상태 변경 콜백 */
|
|
9
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
10
|
+
/** 비활성화 여부 */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
/** 크기 */
|
|
13
|
+
size?: ButtonSize;
|
|
14
|
+
/** input name */
|
|
15
|
+
name?: string;
|
|
16
|
+
/** input value */
|
|
17
|
+
value?: string;
|
|
18
|
+
/** input id */
|
|
19
|
+
id?: string;
|
|
20
|
+
/** 토글 옆에 표시할 라벨 텍스트 */
|
|
21
|
+
label?: string;
|
|
22
|
+
/** 추가 CSS 클래스 */
|
|
23
|
+
className?: string;
|
|
24
|
+
/** 인라인 스타일 */
|
|
25
|
+
style?: React.CSSProperties;
|
|
26
|
+
/** input 요소 ref */
|
|
27
|
+
ref?: Ref<HTMLInputElement>;
|
|
28
|
+
}
|
|
29
|
+
declare const ToggleButton: ({ checked, defaultChecked, onCheckedChange, disabled, size, label, className, style, ref, name, id, value, ...props }: ToggleButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export default ToggleButton;
|
|
31
|
+
//# sourceMappingURL=ToggleButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToggleButton.d.ts","sourceRoot":"","sources":["../../../src/components/ToggleButton/ToggleButton.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAKjC,KAAK,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAsC1D,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAC3C,MAAM,CACP;IACC,uBAAuB;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB;IAClB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS;IACT,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uBAAuB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc;IACd,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAmDD,QAAA,MAAM,YAAY,GAAI,uHAcnB,iBAAiB,4CAqBnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import ToggleButtonBase, { useToggleButtonContext } from './ToggleButtonBase.js';
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
const trackClass = {
|
|
5
|
+
small: 'toggle-track-sm',
|
|
6
|
+
medium: 'toggle-track-md',
|
|
7
|
+
large: 'toggle-track-lg',
|
|
8
|
+
xlarge: 'toggle-track-xl',
|
|
9
|
+
};
|
|
10
|
+
const thumbClass = {
|
|
11
|
+
small: 'toggle-thumb-sm',
|
|
12
|
+
medium: 'toggle-thumb-md',
|
|
13
|
+
large: 'toggle-thumb-lg',
|
|
14
|
+
xlarge: 'toggle-thumb-xl',
|
|
15
|
+
};
|
|
16
|
+
const thumbOffClass = {
|
|
17
|
+
small: 'toggle-thumb-off-sm',
|
|
18
|
+
medium: 'toggle-thumb-off-md',
|
|
19
|
+
large: 'toggle-thumb-off-lg',
|
|
20
|
+
xlarge: 'toggle-thumb-off-xl',
|
|
21
|
+
};
|
|
22
|
+
const thumbOnClass = {
|
|
23
|
+
small: 'toggle-thumb-on-sm',
|
|
24
|
+
medium: 'toggle-thumb-on-md',
|
|
25
|
+
large: 'toggle-thumb-on-lg',
|
|
26
|
+
xlarge: 'toggle-thumb-on-xl',
|
|
27
|
+
};
|
|
28
|
+
const rootClass = {
|
|
29
|
+
small: 'toggle-sm',
|
|
30
|
+
medium: 'toggle-md',
|
|
31
|
+
large: 'toggle-lg',
|
|
32
|
+
xlarge: 'toggle-xl',
|
|
33
|
+
};
|
|
34
|
+
// ── Inner: Context에서 checked/disabled 읽어 스타일 적용 ──
|
|
35
|
+
const ToggleInner = ({ label, ref, name, id, value, size, ...props }) => {
|
|
36
|
+
const { checked, disabled } = useToggleButtonContext();
|
|
37
|
+
return (_jsxs(_Fragment, { children: [_jsx(ToggleButtonBase.HiddenInput, { ref: ref, name: name, id: id, value: value, ...props }), _jsx(ToggleButtonBase.Track, { className: cn(trackClass[size], checked ? 'bg-lb500' : 'bg-mono300', disabled ? 'opacity-50' : 'cursor-pointer', 'peer-focus-visible:ring-2 peer-focus-visible:ring-lb500 peer-focus-visible:ring-offset-2'), children: _jsx(ToggleButtonBase.Thumb, { className: cn(thumbClass[size], 'bg-white ld-transition', checked ? thumbOnClass[size] : thumbOffClass[size]) }) }), label && (_jsx(ToggleButtonBase.Label, { className: "select-none", children: label }))] }));
|
|
38
|
+
};
|
|
39
|
+
const ToggleButton = ({ checked, defaultChecked, onCheckedChange, disabled = false, size = 'medium', label, className, style, ref, name, id, value, ...props }) => {
|
|
40
|
+
return (_jsx(ToggleButtonBase.Root, { checked: checked, defaultChecked: defaultChecked, onCheckedChange: onCheckedChange, disabled: disabled, style: style, className: cn(rootClass[size], className), children: _jsx(ToggleInner, { label: label, ref: ref, name: name, value: value, id: id, size: size, ...props }) }));
|
|
41
|
+
};
|
|
42
|
+
export default ToggleButton;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
|
+
interface ToggleButtonContextType {
|
|
3
|
+
checked: boolean;
|
|
4
|
+
onCheckedChange: (checked: boolean) => void;
|
|
5
|
+
disabled: boolean;
|
|
6
|
+
isFocused: boolean;
|
|
7
|
+
setIsFocused: (focused: boolean) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const useToggleButtonContext: () => ToggleButtonContextType;
|
|
10
|
+
interface RootProps {
|
|
11
|
+
checked?: boolean;
|
|
12
|
+
defaultChecked?: boolean;
|
|
13
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
className?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
interface HiddenInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
20
|
+
ref?: Ref<HTMLInputElement>;
|
|
21
|
+
}
|
|
22
|
+
interface TrackProps {
|
|
23
|
+
className?: string;
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
interface ThumbProps {
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
interface LabelProps {
|
|
30
|
+
className?: string;
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
export declare const ToggleButtonBase: {
|
|
34
|
+
Root: ({ checked, defaultChecked, onCheckedChange, disabled, className, style, children, }: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
HiddenInput: ({ ref, onFocus, onBlur, onChange, ...props }: HiddenInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
Track: ({ className, children }: TrackProps) => import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
Thumb: ({ className }: ThumbProps) => import("react/jsx-runtime").JSX.Element;
|
|
38
|
+
Label: ({ className, children }: LabelProps) => import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
};
|
|
40
|
+
export default ToggleButtonBase;
|
|
41
|
+
//# sourceMappingURL=ToggleButtonBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToggleButtonBase.d.ts","sourceRoot":"","sources":["../../../src/components/ToggleButton/ToggleButtonBase.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,GAAG,EAIT,MAAM,OAAO,CAAC;AAIf,UAAU,uBAAuB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAID,eAAO,MAAM,sBAAsB,+BAOlC,CAAC;AAGF,UAAU,SAAS;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA+CD,UAAU,gBAAiB,SAAQ,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC;IAC5E,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAuCD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAgBD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAcD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD,eAAO,MAAM,gBAAgB;gGA1H1B,SAAS;gEA+CT,gBAAgB;qCAoCqB,UAAU;2BAkBpB,UAAU;qCAiBA,UAAU;CAUjD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useState, } from 'react';
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
const ToggleButtonContext = createContext(null);
|
|
5
|
+
export const useToggleButtonContext = () => {
|
|
6
|
+
const ctx = useContext(ToggleButtonContext);
|
|
7
|
+
if (!ctx)
|
|
8
|
+
throw new Error('ToggleButtonBase 하위 컴포넌트는 Root 내부에서 사용해야 합니다.');
|
|
9
|
+
return ctx;
|
|
10
|
+
};
|
|
11
|
+
const Root = ({ checked, defaultChecked = false, onCheckedChange, disabled = false, className, style, children, }) => {
|
|
12
|
+
const [internal, setInternal] = useState(defaultChecked);
|
|
13
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
14
|
+
const isControlled = checked !== undefined;
|
|
15
|
+
const resolved = isControlled ? checked : internal;
|
|
16
|
+
const handleChange = (val) => {
|
|
17
|
+
if (!isControlled)
|
|
18
|
+
setInternal(val);
|
|
19
|
+
onCheckedChange?.(val);
|
|
20
|
+
};
|
|
21
|
+
return (_jsx(ToggleButtonContext, { value: {
|
|
22
|
+
checked: resolved,
|
|
23
|
+
onCheckedChange: handleChange,
|
|
24
|
+
disabled,
|
|
25
|
+
isFocused,
|
|
26
|
+
setIsFocused,
|
|
27
|
+
}, children: _jsx("label", { style: style, onClick: (e) => e.stopPropagation(), className: cn('flex items-center gap-sm', disabled ? 'cursor-not-allowed' : 'cursor-pointer', className), children: children }) }));
|
|
28
|
+
};
|
|
29
|
+
const HiddenInput = ({ ref, onFocus, onBlur, onChange, ...props }) => {
|
|
30
|
+
const { checked, onCheckedChange, disabled, setIsFocused } = useToggleButtonContext();
|
|
31
|
+
return (_jsx("input", { type: "checkbox", role: "switch", "aria-checked": checked, ref: ref, className: "sr-only peer", checked: checked, disabled: disabled, onChange: (e) => {
|
|
32
|
+
e.stopPropagation();
|
|
33
|
+
onCheckedChange(e.target.checked);
|
|
34
|
+
onChange?.(e);
|
|
35
|
+
}, onFocus: (e) => {
|
|
36
|
+
setIsFocused(true);
|
|
37
|
+
onFocus?.(e);
|
|
38
|
+
}, onBlur: (e) => {
|
|
39
|
+
setIsFocused(false);
|
|
40
|
+
onBlur?.(e);
|
|
41
|
+
}, ...props }));
|
|
42
|
+
};
|
|
43
|
+
const Track = ({ className, children }) => {
|
|
44
|
+
return (_jsx("span", { className: cn('relative flex items-center rounded-full shrink-0', className), children: children }));
|
|
45
|
+
};
|
|
46
|
+
const Thumb = ({ className }) => {
|
|
47
|
+
return (_jsx("span", { className: cn('absolute rounded-full top-1/2 -translate-y-1/2', className) }));
|
|
48
|
+
};
|
|
49
|
+
const Label = ({ className, children }) => {
|
|
50
|
+
return _jsx("span", { className: className, children: children });
|
|
51
|
+
};
|
|
52
|
+
export const ToggleButtonBase = {
|
|
53
|
+
Root,
|
|
54
|
+
HiddenInput,
|
|
55
|
+
Track,
|
|
56
|
+
Thumb,
|
|
57
|
+
Label,
|
|
58
|
+
};
|
|
59
|
+
export default ToggleButtonBase;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface TooltipProps {
|
|
3
|
+
/** 툴팁이 표시될 트리거 요소 */
|
|
4
|
+
children: React.ReactElement;
|
|
5
|
+
/** 툴팁 내용 (생략 시 children 텍스트가 잘릴 때만 자동 표시) */
|
|
6
|
+
content?: React.ReactNode;
|
|
7
|
+
/** 툴팁 표시 위치 */
|
|
8
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
9
|
+
/** 툴팁 정렬 */
|
|
10
|
+
align?: 'start' | 'center' | 'end';
|
|
11
|
+
/** 추가 CSS 클래스 */
|
|
12
|
+
className?: string;
|
|
13
|
+
/** 인라인 스타일 */
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
}
|
|
16
|
+
declare const Tooltip: ({ children, content, side, align, className, style, }: TooltipProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export default Tooltip;
|
|
18
|
+
//# sourceMappingURL=Tooltip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,YAAY;IAC3B,qBAAqB;IACrB,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC;IAC7B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,eAAe;IACf,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,YAAY;IACZ,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc;IACd,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,QAAA,MAAM,OAAO,GAAI,uDAOd,YAAY,4CA8Bd,CAAC;AAEF,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import TooltipBase from './TooltipBase.js';
|
|
4
|
+
import cn from '../../utils/cn.js';
|
|
5
|
+
const Tooltip = ({ children, content, side = 'top', align = 'center', className, style, }) => {
|
|
6
|
+
const { ref: textRef, isTruncated } = TooltipBase.useTruncation([children]);
|
|
7
|
+
const tooltipContent = content ?? textRef.current?.textContent ?? '';
|
|
8
|
+
const shouldShow = content ? true : isTruncated;
|
|
9
|
+
return (_jsx(TooltipBase.Provider, { children: _jsxs(TooltipBase.Root, { children: [_jsx(TooltipBase.Trigger, { asChild: true, children: _jsx("div", { className: cn('relative w-full', className), style: style, children: React.cloneElement(children, {
|
|
10
|
+
ref: textRef,
|
|
11
|
+
}) }) }), shouldShow && (_jsxs(TooltipBase.Content, { side: side, align: align, className: "px-2 py-1 text-xs text-white whitespace-nowrap bg-gray-900 rounded", children: [tooltipContent, _jsx(TooltipBase.Arrow, { className: "fill-gray-900" })] }))] }) }));
|
|
12
|
+
};
|
|
13
|
+
export default Tooltip;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
interface ProviderProps {
|
|
3
|
+
delayDuration?: number;
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
interface RootProps {
|
|
7
|
+
open?: boolean;
|
|
8
|
+
defaultOpen?: boolean;
|
|
9
|
+
onOpenChange?: (open: boolean) => void;
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
interface TriggerProps {
|
|
13
|
+
asChild?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
interface ContentProps {
|
|
18
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
19
|
+
sideOffset?: number;
|
|
20
|
+
align?: 'start' | 'center' | 'end';
|
|
21
|
+
className?: string;
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
interface ArrowProps {
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare const TooltipBase: {
|
|
28
|
+
Provider: ({ delayDuration, children }: ProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
Root: ({ open, defaultOpen, onOpenChange, children }: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
Trigger: ({ asChild, className, children }: TriggerProps) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
Content: ({ side, sideOffset, align, className, children, }: ContentProps) => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
Arrow: ({ className }: ArrowProps) => import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
useTruncation: (deps?: React.DependencyList) => {
|
|
34
|
+
ref: import("react").RefObject<HTMLElement | null>;
|
|
35
|
+
isTruncated: boolean;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export default TooltipBase;
|
|
39
|
+
//# sourceMappingURL=TooltipBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TooltipBase.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip/TooltipBase.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AA2BpE,UAAU,aAAa;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAeD,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA4BD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,eAAO,MAAM,WAAW;4CAtF6B,aAAa;0DAgBL,SAAS;gDAmBnB,YAAY;iEAuB5D,YAAY;2BAwBe,UAAU;2BA7GX,KAAK,CAAC,cAAc;;;;CAwHhD,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect, useState } from 'react';
|
|
3
|
+
import * as RadixTooltip from '@radix-ui/react-tooltip';
|
|
4
|
+
import cn from '../../utils/cn.js';
|
|
5
|
+
// ── 말줄임 감지 Hook ──
|
|
6
|
+
const useTruncation = (deps = []) => {
|
|
7
|
+
const ref = useRef(null);
|
|
8
|
+
const [isTruncated, setIsTruncated] = useState(false);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const element = ref.current;
|
|
11
|
+
if (!element)
|
|
12
|
+
return;
|
|
13
|
+
const checkTruncation = () => {
|
|
14
|
+
setIsTruncated(element.scrollWidth > element.clientWidth);
|
|
15
|
+
};
|
|
16
|
+
checkTruncation();
|
|
17
|
+
window.addEventListener('resize', checkTruncation);
|
|
18
|
+
return () => window.removeEventListener('resize', checkTruncation);
|
|
19
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
20
|
+
}, deps);
|
|
21
|
+
return { ref, isTruncated };
|
|
22
|
+
};
|
|
23
|
+
const Provider = ({ delayDuration = 200, children }) => {
|
|
24
|
+
return (_jsx(RadixTooltip.Provider, { delayDuration: delayDuration, children: children }));
|
|
25
|
+
};
|
|
26
|
+
const Root = ({ open, defaultOpen, onOpenChange, children }) => {
|
|
27
|
+
return (_jsx(RadixTooltip.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, children: children }));
|
|
28
|
+
};
|
|
29
|
+
const Trigger = ({ asChild, className, children }) => {
|
|
30
|
+
return (_jsx(RadixTooltip.Trigger, { asChild: asChild, className: className, children: children }));
|
|
31
|
+
};
|
|
32
|
+
const Content = ({ side = 'top', sideOffset = 8, align = 'center', className, children, }) => {
|
|
33
|
+
return (_jsx(RadixTooltip.Portal, { children: _jsx(RadixTooltip.Content, { side: side, sideOffset: sideOffset, align: align, className: cn('z-50 outline-hidden', 'animate-in fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0', className), children: children }) }));
|
|
34
|
+
};
|
|
35
|
+
const Arrow = ({ className }) => {
|
|
36
|
+
return _jsx(RadixTooltip.Arrow, { className: className });
|
|
37
|
+
};
|
|
38
|
+
export const TooltipBase = {
|
|
39
|
+
Provider,
|
|
40
|
+
Root,
|
|
41
|
+
Trigger,
|
|
42
|
+
Content,
|
|
43
|
+
Arrow,
|
|
44
|
+
useTruncation,
|
|
45
|
+
};
|
|
46
|
+
export default TooltipBase;
|