@loword/loword-design-system 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -3
- package/dist/components/BreadCrumb/BreadCrumb.d.ts +17 -0
- package/dist/components/BreadCrumb/BreadCrumb.d.ts.map +1 -0
- package/dist/components/BreadCrumb/BreadCrumb.js +37 -0
- package/dist/components/BreadCrumb/BreadCrumbBase.d.ts +9 -0
- package/dist/components/BreadCrumb/BreadCrumbBase.d.ts.map +1 -0
- package/dist/components/BreadCrumb/BreadCrumbBase.js +17 -0
- package/dist/components/Button/ButtonSpinner.d.ts +1 -2
- package/dist/components/Button/ButtonSpinner.d.ts.map +1 -1
- package/dist/components/Button/ButtonSpinner.js +3 -2
- package/dist/components/Callout/Callout.d.ts +10 -0
- package/dist/components/Callout/Callout.d.ts.map +1 -0
- package/dist/components/Callout/Callout.js +6 -0
- package/dist/components/Callout/CalloutBase.d.ts +18 -0
- package/dist/components/Callout/CalloutBase.d.ts.map +1 -0
- package/dist/components/Callout/CalloutBase.js +21 -0
- package/dist/components/Divider/Divider.d.ts +9 -0
- package/dist/components/Divider/Divider.d.ts.map +1 -0
- package/dist/components/Divider/Divider.js +11 -0
- package/dist/components/Divider/DividerBase.d.ts +9 -0
- package/dist/components/Divider/DividerBase.d.ts.map +1 -0
- package/dist/components/Divider/DividerBase.js +9 -0
- package/dist/components/FileUpload/FileUploadBase.d.ts +5 -5
- package/dist/components/FileUpload/FileUploadBase.d.ts.map +1 -1
- package/dist/components/FileUpload/FileUploadBase.js +4 -4
- package/dist/components/Form/FormField.d.ts +2 -2
- package/dist/components/LDAvatar/AvatarBase.d.ts +32 -0
- package/dist/components/LDAvatar/AvatarBase.d.ts.map +1 -0
- package/dist/components/LDAvatar/AvatarBase.js +49 -0
- package/dist/components/LDAvatar/LDAvatar.d.ts +11 -0
- package/dist/components/LDAvatar/LDAvatar.d.ts.map +1 -0
- package/dist/components/LDAvatar/LDAvatar.js +24 -0
- package/dist/components/LDBadge/BadgeBase.d.ts +10 -0
- package/dist/components/LDBadge/BadgeBase.d.ts.map +1 -0
- package/dist/components/LDBadge/BadgeBase.js +9 -0
- package/dist/components/LDBadge/LDBadge.d.ts +25 -0
- package/dist/components/LDBadge/LDBadge.d.ts.map +1 -0
- package/dist/components/LDBadge/LDBadge.js +36 -0
- package/dist/components/LDBreadCrumb/BreadCrumbBase.d.ts +9 -0
- package/dist/components/LDBreadCrumb/BreadCrumbBase.d.ts.map +1 -0
- package/dist/components/LDBreadCrumb/BreadCrumbBase.js +17 -0
- package/dist/components/LDBreadCrumb/LDBreadCrumb.d.ts +17 -0
- package/dist/components/LDBreadCrumb/LDBreadCrumb.d.ts.map +1 -0
- package/dist/components/LDBreadCrumb/LDBreadCrumb.js +37 -0
- package/dist/components/LDButton/ButtonBase.d.ts +5 -0
- package/dist/components/LDButton/ButtonBase.d.ts.map +1 -0
- package/dist/components/LDButton/ButtonBase.js +10 -0
- package/dist/components/LDButton/ButtonSpinner.d.ts +8 -0
- package/dist/components/LDButton/ButtonSpinner.d.ts.map +1 -0
- package/dist/components/LDButton/ButtonSpinner.js +15 -0
- package/dist/components/LDButton/LDButton.d.ts +26 -0
- package/dist/components/LDButton/LDButton.d.ts.map +1 -0
- package/dist/components/LDButton/LDButton.js +102 -0
- package/dist/components/LDCalendar/LDCalendar.d.ts +16 -0
- package/dist/components/LDCalendar/LDCalendar.d.ts.map +1 -0
- package/dist/components/LDCalendar/LDCalendar.js +75 -0
- package/dist/components/LDCallout/CalloutBase.d.ts +18 -0
- package/dist/components/LDCallout/CalloutBase.d.ts.map +1 -0
- package/dist/components/LDCallout/CalloutBase.js +21 -0
- package/dist/components/LDCallout/LDCallout.d.ts +10 -0
- package/dist/components/LDCallout/LDCallout.d.ts.map +1 -0
- package/dist/components/LDCallout/LDCallout.js +6 -0
- package/dist/components/LDCarousel/CarouselBase.d.ts +98 -0
- package/dist/components/LDCarousel/CarouselBase.d.ts.map +1 -0
- package/dist/components/LDCarousel/CarouselBase.js +144 -0
- package/dist/components/LDCarousel/LDCarousel.d.ts +50 -0
- package/dist/components/LDCarousel/LDCarousel.d.ts.map +1 -0
- package/dist/components/LDCarousel/LDCarousel.js +22 -0
- package/dist/components/LDCheckbox/CheckboxBase.d.ts +40 -0
- package/dist/components/LDCheckbox/CheckboxBase.d.ts.map +1 -0
- package/dist/components/LDCheckbox/CheckboxBase.js +57 -0
- package/dist/components/LDCheckbox/FormCheckbox.d.ts +14 -0
- package/dist/components/LDCheckbox/FormCheckbox.d.ts.map +1 -0
- package/dist/components/LDCheckbox/FormCheckbox.js +9 -0
- package/dist/components/LDCheckbox/FormCheckboxGroup.d.ts +13 -0
- package/dist/components/LDCheckbox/FormCheckboxGroup.d.ts.map +1 -0
- package/dist/components/LDCheckbox/FormCheckboxGroup.js +9 -0
- package/dist/components/LDCheckbox/LDCheckbox.d.ts +27 -0
- package/dist/components/LDCheckbox/LDCheckbox.d.ts.map +1 -0
- package/dist/components/LDCheckbox/LDCheckbox.js +30 -0
- package/dist/components/LDCheckbox/LDCheckboxGroup.d.ts +22 -0
- package/dist/components/LDCheckbox/LDCheckboxGroup.d.ts.map +1 -0
- package/dist/components/LDCheckbox/LDCheckboxGroup.js +13 -0
- package/dist/components/LDDataCalendar/DataCalendarBase.d.ts +45 -0
- package/dist/components/LDDataCalendar/DataCalendarBase.d.ts.map +1 -0
- package/dist/components/LDDataCalendar/DataCalendarBase.js +57 -0
- package/dist/components/LDDataCalendar/LDDataCalendar.d.ts +12 -0
- package/dist/components/LDDataCalendar/LDDataCalendar.d.ts.map +1 -0
- package/dist/components/LDDataCalendar/LDDataCalendar.js +13 -0
- package/dist/components/LDDatePicker/FormDatePicker.d.ts +12 -0
- package/dist/components/LDDatePicker/FormDatePicker.d.ts.map +1 -0
- package/dist/components/LDDatePicker/FormDatePicker.js +12 -0
- package/dist/components/LDDatePicker/LDDatePicker.d.ts +34 -0
- package/dist/components/LDDatePicker/LDDatePicker.d.ts.map +1 -0
- package/dist/components/LDDatePicker/LDDatePicker.js +44 -0
- package/dist/components/LDDateRangePicker/FormDateRangePicker.d.ts +12 -0
- package/dist/components/LDDateRangePicker/FormDateRangePicker.d.ts.map +1 -0
- package/dist/components/LDDateRangePicker/FormDateRangePicker.js +10 -0
- package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts +49 -0
- package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts.map +1 -0
- package/dist/components/LDDateRangePicker/LDDateRangePicker.js +197 -0
- package/dist/components/LDDivider/DividerBase.d.ts +9 -0
- package/dist/components/LDDivider/DividerBase.d.ts.map +1 -0
- package/dist/components/LDDivider/DividerBase.js +9 -0
- package/dist/components/LDDivider/LDDivider.d.ts +9 -0
- package/dist/components/LDDivider/LDDivider.d.ts.map +1 -0
- package/dist/components/LDDivider/LDDivider.js +11 -0
- package/dist/components/LDDrawer/DrawerBase.d.ts +52 -0
- package/dist/components/LDDrawer/DrawerBase.d.ts.map +1 -0
- package/dist/components/LDDrawer/DrawerBase.js +38 -0
- package/dist/components/LDDrawer/LDDrawer.d.ts +51 -0
- package/dist/components/LDDrawer/LDDrawer.d.ts.map +1 -0
- package/dist/components/LDDrawer/LDDrawer.js +30 -0
- package/dist/components/LDEditor/EditorBase.d.ts +52 -0
- package/dist/components/LDEditor/EditorBase.d.ts.map +1 -0
- package/dist/components/LDEditor/EditorBase.js +89 -0
- package/dist/components/LDEditor/LDEditor.d.ts +12 -0
- package/dist/components/LDEditor/LDEditor.d.ts.map +1 -0
- package/dist/components/LDEditor/LDEditor.js +162 -0
- package/dist/components/LDEditor/LDViewer.d.ts +7 -0
- package/dist/components/LDEditor/LDViewer.d.ts.map +1 -0
- package/dist/components/LDEditor/LDViewer.js +9 -0
- package/dist/components/LDEditor/extensions.d.ts +6 -0
- package/dist/components/LDEditor/extensions.d.ts.map +1 -0
- package/dist/components/LDEditor/extensions.js +38 -0
- package/dist/components/LDFileUpload/LDFileUploadBase.d.ts +50 -0
- package/dist/components/LDFileUpload/LDFileUploadBase.d.ts.map +1 -0
- package/dist/components/LDFileUpload/LDFileUploadBase.js +102 -0
- package/dist/components/LDInput/FormInput.d.ts +15 -0
- package/dist/components/LDInput/FormInput.d.ts.map +1 -0
- package/dist/components/LDInput/FormInput.js +19 -0
- package/dist/components/LDInput/InputBase.d.ts +22 -0
- package/dist/components/LDInput/InputBase.d.ts.map +1 -0
- package/dist/components/LDInput/InputBase.js +17 -0
- package/dist/components/LDInput/LDInput.d.ts +24 -0
- package/dist/components/LDInput/LDInput.d.ts.map +1 -0
- package/dist/components/LDInput/LDInput.js +71 -0
- package/dist/components/LDLNB/LDLNBBase.d.ts +82 -0
- package/dist/components/LDLNB/LDLNBBase.d.ts.map +1 -0
- package/dist/components/LDLNB/LDLNBBase.js +108 -0
- package/dist/components/LDLoadingDots/LDLoadingDots.d.ts +8 -0
- package/dist/components/LDLoadingDots/LDLoadingDots.d.ts.map +1 -0
- package/dist/components/LDLoadingDots/LDLoadingDots.js +29 -0
- package/dist/components/LDMenuBar/LDMenuBar.d.ts +21 -0
- package/dist/components/LDMenuBar/LDMenuBar.d.ts.map +1 -0
- package/dist/components/LDMenuBar/LDMenuBar.js +33 -0
- package/dist/components/LDMenuBar/MenuBarBase.d.ts +43 -0
- package/dist/components/LDMenuBar/MenuBarBase.d.ts.map +1 -0
- package/dist/components/LDMenuBar/MenuBarBase.js +69 -0
- package/dist/components/LDModal/LDModal.d.ts +51 -0
- package/dist/components/LDModal/LDModal.d.ts.map +1 -0
- package/dist/components/LDModal/LDModal.js +72 -0
- package/dist/components/LDModal/ModalBase.d.ts +42 -0
- package/dist/components/LDModal/ModalBase.d.ts.map +1 -0
- package/dist/components/LDModal/ModalBase.js +30 -0
- package/dist/components/LDModal/openModal.d.ts +24 -0
- package/dist/components/LDModal/openModal.d.ts.map +1 -0
- package/dist/components/LDModal/openModal.js +52 -0
- package/dist/components/LDOTPInput/LDOTPInput.d.ts +46 -0
- package/dist/components/LDOTPInput/LDOTPInput.d.ts.map +1 -0
- package/dist/components/LDOTPInput/LDOTPInput.js +87 -0
- package/dist/components/LDPagination/LDPagination.d.ts +12 -0
- package/dist/components/LDPagination/LDPagination.d.ts.map +1 -0
- package/dist/components/LDPagination/LDPagination.js +5 -0
- package/dist/components/LDPagination/PaginationBase.d.ts +36 -0
- package/dist/components/LDPagination/PaginationBase.d.ts.map +1 -0
- package/dist/components/LDPagination/PaginationBase.js +44 -0
- package/dist/components/LDPagination/paginationUtils.d.ts +2 -0
- package/dist/components/LDPagination/paginationUtils.d.ts.map +1 -0
- package/dist/components/LDPagination/paginationUtils.js +18 -0
- package/dist/components/LDPopover/LDPopover.d.ts +42 -0
- package/dist/components/LDPopover/LDPopover.d.ts.map +1 -0
- package/dist/components/LDPopover/LDPopover.js +31 -0
- package/dist/components/LDPopover/PopoverBase.d.ts +31 -0
- package/dist/components/LDPopover/PopoverBase.d.ts.map +1 -0
- package/dist/components/LDPopover/PopoverBase.js +18 -0
- package/dist/components/LDRadio/FormRadioGroup.d.ts +13 -0
- package/dist/components/LDRadio/FormRadioGroup.d.ts.map +1 -0
- package/dist/components/LDRadio/FormRadioGroup.js +9 -0
- package/dist/components/LDRadio/LDRadio.d.ts +24 -0
- package/dist/components/LDRadio/LDRadio.d.ts.map +1 -0
- package/dist/components/LDRadio/LDRadio.js +39 -0
- package/dist/components/LDRadio/LDRadioGroup.d.ts +22 -0
- package/dist/components/LDRadio/LDRadioGroup.d.ts.map +1 -0
- package/dist/components/LDRadio/LDRadioGroup.js +7 -0
- package/dist/components/LDRadio/RadioBase.d.ts +38 -0
- package/dist/components/LDRadio/RadioBase.d.ts.map +1 -0
- package/dist/components/LDRadio/RadioBase.js +46 -0
- package/dist/components/LDScrollArea/LDScrollArea.d.ts +15 -0
- package/dist/components/LDScrollArea/LDScrollArea.d.ts.map +1 -0
- package/dist/components/LDScrollArea/LDScrollArea.js +10 -0
- package/dist/components/LDSelect/FormMultiSelect.d.ts +13 -0
- package/dist/components/LDSelect/FormMultiSelect.d.ts.map +1 -0
- package/dist/components/LDSelect/FormMultiSelect.js +14 -0
- package/dist/components/LDSelect/FormSelect.d.ts +13 -0
- package/dist/components/LDSelect/FormSelect.d.ts.map +1 -0
- package/dist/components/LDSelect/FormSelect.js +10 -0
- package/dist/components/LDSelect/LDMultiSelect.d.ts +31 -0
- package/dist/components/LDSelect/LDMultiSelect.d.ts.map +1 -0
- package/dist/components/LDSelect/LDMultiSelect.js +59 -0
- package/dist/components/LDSelect/LDSelect.d.ts +41 -0
- package/dist/components/LDSelect/LDSelect.d.ts.map +1 -0
- package/dist/components/LDSelect/LDSelect.js +55 -0
- package/dist/components/LDSelect/SelectBase.d.ts +59 -0
- package/dist/components/LDSelect/SelectBase.d.ts.map +1 -0
- package/dist/components/LDSelect/SelectBase.js +211 -0
- package/dist/components/LDSkeleton/LDSkeleton.d.ts +10 -0
- package/dist/components/LDSkeleton/LDSkeleton.d.ts.map +1 -0
- package/dist/components/LDSkeleton/LDSkeleton.js +8 -0
- package/dist/components/LDSlider/LDSlider.d.ts +23 -0
- package/dist/components/LDSlider/LDSlider.d.ts.map +1 -0
- package/dist/components/LDSlider/LDSlider.js +195 -0
- package/dist/components/LDSpinner/LDSpinner.d.ts +25 -0
- package/dist/components/LDSpinner/LDSpinner.d.ts.map +1 -0
- package/dist/components/LDSpinner/LDSpinner.js +20 -0
- package/dist/components/LDTable/LDTable.d.ts +34 -0
- package/dist/components/LDTable/LDTable.d.ts.map +1 -0
- package/dist/components/LDTable/LDTable.js +29 -0
- package/dist/components/LDTable/LDTanstackTable.d.ts +23 -0
- package/dist/components/LDTable/LDTanstackTable.d.ts.map +1 -0
- package/dist/components/LDTable/LDTanstackTable.js +35 -0
- package/dist/components/LDTable/TableBase.d.ts +37 -0
- package/dist/components/LDTable/TableBase.d.ts.map +1 -0
- package/dist/components/LDTable/TableBase.js +39 -0
- package/dist/components/LDTable/TableField.d.ts +64 -0
- package/dist/components/LDTable/TableField.d.ts.map +1 -0
- package/dist/components/LDTable/TableField.js +87 -0
- package/dist/components/LDTimePicker/FormTimePicker.d.ts +12 -0
- package/dist/components/LDTimePicker/FormTimePicker.d.ts.map +1 -0
- package/dist/components/LDTimePicker/FormTimePicker.js +12 -0
- package/dist/components/LDTimePicker/LDTimePicker.d.ts +27 -0
- package/dist/components/LDTimePicker/LDTimePicker.d.ts.map +1 -0
- package/dist/components/LDTimePicker/LDTimePicker.js +120 -0
- package/dist/components/LDToast/LDToast.d.ts +18 -0
- package/dist/components/LDToast/LDToast.d.ts.map +1 -0
- package/dist/components/LDToast/LDToast.js +42 -0
- package/dist/components/LDToast/LDToaster.d.ts +7 -0
- package/dist/components/LDToast/LDToaster.d.ts.map +1 -0
- package/dist/components/LDToast/LDToaster.js +7 -0
- package/dist/components/LDToggleButton/FormToggleButton.d.ts +12 -0
- package/dist/components/LDToggleButton/FormToggleButton.d.ts.map +1 -0
- package/dist/components/LDToggleButton/FormToggleButton.js +9 -0
- package/dist/components/LDToggleButton/LDToggleButton.d.ts +31 -0
- package/dist/components/LDToggleButton/LDToggleButton.d.ts.map +1 -0
- package/dist/components/LDToggleButton/LDToggleButton.js +42 -0
- package/dist/components/LDToggleButton/ToggleButtonBase.d.ts +41 -0
- package/dist/components/LDToggleButton/ToggleButtonBase.d.ts.map +1 -0
- package/dist/components/LDToggleButton/ToggleButtonBase.js +59 -0
- package/dist/components/LDTooltip/LDTooltip.d.ts +18 -0
- package/dist/components/LDTooltip/LDTooltip.d.ts.map +1 -0
- package/dist/components/LDTooltip/LDTooltip.js +13 -0
- package/dist/components/LDTooltip/TooltipBase.d.ts +39 -0
- package/dist/components/LDTooltip/TooltipBase.d.ts.map +1 -0
- package/dist/components/LDTooltip/TooltipBase.js +46 -0
- package/dist/components/LNB/LNBBase.js +2 -2
- package/dist/components/Spinner/Spinner.d.ts +1 -1
- package/dist/components/Spinner/Spinner.d.ts.map +1 -1
- package/dist/components/Spinner/Spinner.js +1 -1
- package/dist/index.css +115 -13
- package/dist/index.d.ts +52 -49
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -82
- package/package.json +1 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useState, useEffect, useRef, useId, useCallback, } from 'react';
|
|
4
|
+
import cn from '../../utils/cn.js';
|
|
5
|
+
const SelectContext = createContext(null);
|
|
6
|
+
const useSelectContext = () => {
|
|
7
|
+
const ctx = useContext(SelectContext);
|
|
8
|
+
if (!ctx)
|
|
9
|
+
throw new Error('SelectBase 하위 컴포넌트는 Root 내부에서 사용해야 합니다.');
|
|
10
|
+
return ctx;
|
|
11
|
+
};
|
|
12
|
+
// ── Item Context (Item → ItemIndicator 간 value 공유) ──
|
|
13
|
+
const ItemContext = createContext(null);
|
|
14
|
+
const useItemContext = () => {
|
|
15
|
+
return useContext(ItemContext);
|
|
16
|
+
};
|
|
17
|
+
const Root = ({ multiple = false, value, defaultValue, values, defaultValues = [], onChange, onMultiChange, disabled = false, name, items, maxDisplay = 2, children, }) => {
|
|
18
|
+
const [open, setOpen] = useState(false);
|
|
19
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
20
|
+
const [internalValues, setInternalValues] = useState(defaultValues);
|
|
21
|
+
const rootRef = useRef(null);
|
|
22
|
+
const listboxId = useId();
|
|
23
|
+
const isControlled = value !== undefined;
|
|
24
|
+
const isMultiControlled = values !== undefined;
|
|
25
|
+
const resolvedValue = isControlled ? value : internalValue;
|
|
26
|
+
const resolvedValues = isMultiControlled ? values : internalValues;
|
|
27
|
+
const handleChange = useCallback((val) => {
|
|
28
|
+
if (!isControlled)
|
|
29
|
+
setInternalValue(val);
|
|
30
|
+
onChange?.(val);
|
|
31
|
+
}, [isControlled, onChange]);
|
|
32
|
+
const handleMultiChange = useCallback((vals) => {
|
|
33
|
+
if (!isMultiControlled)
|
|
34
|
+
setInternalValues(vals);
|
|
35
|
+
onMultiChange?.(vals);
|
|
36
|
+
}, [isMultiControlled, onMultiChange]);
|
|
37
|
+
const toggleValue = useCallback((val) => {
|
|
38
|
+
if (disabled)
|
|
39
|
+
return;
|
|
40
|
+
const newValues = resolvedValues.includes(val)
|
|
41
|
+
? resolvedValues.filter((v) => v !== val)
|
|
42
|
+
: [...resolvedValues, val];
|
|
43
|
+
handleMultiChange(newValues);
|
|
44
|
+
}, [disabled, resolvedValues, handleMultiChange]);
|
|
45
|
+
// click-outside (LDDropdown 방식: capture phase)
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const handler = (e) => {
|
|
48
|
+
if (!rootRef.current?.contains(e.target)) {
|
|
49
|
+
setOpen(false);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
document.addEventListener('mousedown', handler, { capture: true });
|
|
53
|
+
return () => document.removeEventListener('mousedown', handler, { capture: true });
|
|
54
|
+
}, []);
|
|
55
|
+
return (_jsx(SelectContext.Provider, { value: {
|
|
56
|
+
open,
|
|
57
|
+
setOpen,
|
|
58
|
+
multiple,
|
|
59
|
+
value: resolvedValue,
|
|
60
|
+
values: resolvedValues,
|
|
61
|
+
onChange: handleChange,
|
|
62
|
+
onMultiChange: handleMultiChange,
|
|
63
|
+
toggleValue,
|
|
64
|
+
disabled,
|
|
65
|
+
listboxId,
|
|
66
|
+
items,
|
|
67
|
+
maxDisplay,
|
|
68
|
+
}, children: _jsxs("div", { ref: rootRef, className: "relative w-full", children: [name && (_jsx("input", { type: "hidden", name: name, value: multiple ? JSON.stringify(resolvedValues) : (resolvedValue ?? '') })), children] }) }));
|
|
69
|
+
};
|
|
70
|
+
const Trigger = ({ className, style, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedby, }) => {
|
|
71
|
+
const { open, setOpen, disabled, listboxId } = useSelectContext();
|
|
72
|
+
return (_jsx("button", { type: "button", "aria-haspopup": "listbox", "aria-expanded": open, "aria-controls": listboxId, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, disabled: disabled, "data-state": open ? 'open' : 'closed', onClick: () => {
|
|
73
|
+
if (!disabled)
|
|
74
|
+
setOpen(!open);
|
|
75
|
+
}, onKeyDown: (e) => {
|
|
76
|
+
if (disabled)
|
|
77
|
+
return;
|
|
78
|
+
if (e.key === 'Enter' ||
|
|
79
|
+
e.key === ' ' ||
|
|
80
|
+
e.key === 'ArrowDown' ||
|
|
81
|
+
e.key === 'ArrowUp') {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
if (!open) {
|
|
84
|
+
setOpen(true);
|
|
85
|
+
}
|
|
86
|
+
else if (e.key === 'ArrowDown') {
|
|
87
|
+
const listbox = document.getElementById(listboxId);
|
|
88
|
+
const firstOption = listbox?.querySelector('[role="option"]');
|
|
89
|
+
firstOption?.focus();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (e.key === 'Escape') {
|
|
93
|
+
setOpen(false);
|
|
94
|
+
// 닫힐 때 트리거로 포커스 이동을 위해 버튼을 찾음
|
|
95
|
+
e.currentTarget.focus();
|
|
96
|
+
}
|
|
97
|
+
}, style: style, className: cn('w-full flex justify-center items-center', className), children: children }));
|
|
98
|
+
};
|
|
99
|
+
const Value = ({ placeholder, className, placeholderClassName, }) => {
|
|
100
|
+
const { multiple, value, values, items, maxDisplay } = useSelectContext();
|
|
101
|
+
// 단일 선택
|
|
102
|
+
if (!multiple) {
|
|
103
|
+
const selectedLabel = items?.find((item) => item.value === value)?.label;
|
|
104
|
+
return (_jsx("span", { className: cn(className, selectedLabel == null && placeholderClassName), children: selectedLabel ?? placeholder }));
|
|
105
|
+
}
|
|
106
|
+
// 다중 선택
|
|
107
|
+
if (values.length === 0) {
|
|
108
|
+
return (_jsx("span", { className: cn(className, placeholderClassName), children: placeholder }));
|
|
109
|
+
}
|
|
110
|
+
const selectedLabels = items
|
|
111
|
+
?.filter((item) => values.includes(item.value))
|
|
112
|
+
.map((item) => item.label) ?? [];
|
|
113
|
+
if (selectedLabels.length <= maxDisplay) {
|
|
114
|
+
return _jsx("span", { className: className, children: selectedLabels.join(', ') });
|
|
115
|
+
}
|
|
116
|
+
return (_jsxs("span", { className: className, children: [selectedLabels.slice(0, maxDisplay).join(', '), " \uC678", ' ', selectedLabels.length - maxDisplay, "\uAC1C"] }));
|
|
117
|
+
};
|
|
118
|
+
const Content = ({ className, openClassName, closedClassName, children, }) => {
|
|
119
|
+
const { open, multiple, listboxId } = useSelectContext();
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (open) {
|
|
122
|
+
const focusAndScroll = () => {
|
|
123
|
+
const listbox = document.getElementById(listboxId);
|
|
124
|
+
if (!listbox)
|
|
125
|
+
return;
|
|
126
|
+
let targetOption = listbox.querySelector('[role="option"][aria-selected="true"]');
|
|
127
|
+
if (!targetOption) {
|
|
128
|
+
targetOption = listbox.querySelector('[role="option"]');
|
|
129
|
+
}
|
|
130
|
+
if (targetOption) {
|
|
131
|
+
targetOption.focus();
|
|
132
|
+
targetOption.scrollIntoView({ block: 'nearest' });
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
// 즉시 포커스 (키보드 대응)
|
|
136
|
+
setTimeout(focusAndScroll, 0);
|
|
137
|
+
// 트랜지션(약 200ms) 후 스크롤 재조정 (max-height가 0일 때 scrollIntoView가 씹히는 문제 방지)
|
|
138
|
+
setTimeout(focusAndScroll, 200);
|
|
139
|
+
}
|
|
140
|
+
}, [open, listboxId]);
|
|
141
|
+
return (_jsx("ul", { id: listboxId, role: "listbox", tabIndex: -1, "aria-hidden": !open, "aria-multiselectable": multiple || undefined, "data-state": open ? 'open' : 'closed', className: cn('absolute z-50 w-full mt-1', className, open ? openClassName : closedClassName), children: children }));
|
|
142
|
+
};
|
|
143
|
+
const Item = ({ value: itemValue, className, children }) => {
|
|
144
|
+
const { multiple, value, values, onChange, toggleValue, setOpen, disabled, listboxId, } = useSelectContext();
|
|
145
|
+
const [highlighted, setHighlighted] = useState(false);
|
|
146
|
+
const isSelected = multiple
|
|
147
|
+
? values.includes(itemValue)
|
|
148
|
+
: value === itemValue;
|
|
149
|
+
const handleClick = useCallback(() => {
|
|
150
|
+
if (disabled)
|
|
151
|
+
return;
|
|
152
|
+
if (multiple) {
|
|
153
|
+
toggleValue(itemValue);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
onChange?.(itemValue);
|
|
157
|
+
setOpen(false);
|
|
158
|
+
}
|
|
159
|
+
}, [disabled, multiple, onChange, toggleValue, itemValue, setOpen]);
|
|
160
|
+
return (_jsx(ItemContext.Provider, { value: itemValue, children: _jsx("li", { role: "option", tabIndex: 0, "aria-selected": isSelected, "data-state": isSelected ? 'checked' : 'unchecked', "data-highlighted": highlighted || undefined, onMouseDown: (e) => e.preventDefault(), onClick: handleClick, onMouseEnter: () => setHighlighted(true), onMouseLeave: () => setHighlighted(false), onFocus: () => setHighlighted(true), onBlur: () => setHighlighted(false), onKeyDown: (e) => {
|
|
161
|
+
switch (e.key) {
|
|
162
|
+
case 'Enter':
|
|
163
|
+
case ' ':
|
|
164
|
+
e.preventDefault();
|
|
165
|
+
handleClick();
|
|
166
|
+
// 단일 선택 시 닫히고 트리거로 포커스 복귀
|
|
167
|
+
if (!multiple) {
|
|
168
|
+
const trigger = document.querySelector(`[aria-controls="${listboxId}"]`);
|
|
169
|
+
trigger?.focus();
|
|
170
|
+
}
|
|
171
|
+
break;
|
|
172
|
+
case 'Escape':
|
|
173
|
+
e.preventDefault();
|
|
174
|
+
setOpen(false);
|
|
175
|
+
document.querySelector(`[aria-controls="${listboxId}"]`)?.focus();
|
|
176
|
+
break;
|
|
177
|
+
case 'ArrowDown':
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
e.currentTarget.nextElementSibling?.focus();
|
|
180
|
+
break;
|
|
181
|
+
case 'ArrowUp':
|
|
182
|
+
e.preventDefault();
|
|
183
|
+
e.currentTarget.previousElementSibling?.focus();
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}, className: cn('relative flex items-center outline-none cursor-pointer', className), children: children }) }));
|
|
187
|
+
};
|
|
188
|
+
// ── ItemText ──
|
|
189
|
+
const ItemText = ({ children }) => {
|
|
190
|
+
return _jsx("span", { children: children });
|
|
191
|
+
};
|
|
192
|
+
const ItemIndicator = ({ className, children }) => {
|
|
193
|
+
const { multiple, value, values } = useSelectContext();
|
|
194
|
+
const itemValue = useItemContext();
|
|
195
|
+
const isSelected = multiple
|
|
196
|
+
? itemValue != null && values.includes(itemValue)
|
|
197
|
+
: value === itemValue;
|
|
198
|
+
if (!isSelected)
|
|
199
|
+
return null;
|
|
200
|
+
return _jsx("span", { className: cn('ml-auto', className), children: children });
|
|
201
|
+
};
|
|
202
|
+
export const SelectBase = {
|
|
203
|
+
Root,
|
|
204
|
+
Trigger,
|
|
205
|
+
Value,
|
|
206
|
+
Content,
|
|
207
|
+
Item,
|
|
208
|
+
ItemText,
|
|
209
|
+
ItemIndicator,
|
|
210
|
+
};
|
|
211
|
+
export default SelectBase;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface LDSkeletonProps {
|
|
3
|
+
/** false이면 children을 그대로 렌더링합니다 */
|
|
4
|
+
loading?: boolean;
|
|
5
|
+
className?: string;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
declare const LDSkeleton: ({ loading, className, children, }: LDSkeletonProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default LDSkeleton;
|
|
10
|
+
//# sourceMappingURL=LDSkeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDSkeleton.d.ts","sourceRoot":"","sources":["../../../src/components/LDSkeleton/LDSkeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,QAAA,MAAM,UAAU,GAAI,mCAIjB,eAAe,4CAgBjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import cn from '../../utils/cn.js';
|
|
3
|
+
const LDSkeleton = ({ loading = true, className, children, }) => {
|
|
4
|
+
if (!loading)
|
|
5
|
+
return _jsx(_Fragment, { children: children });
|
|
6
|
+
return (_jsxs("span", { "aria-busy": "true", "aria-label": "\uB85C\uB529 \uC911", className: cn('relative inline-block overflow-hidden rounded-md', className), children: [_jsx("span", { className: "invisible", children: children }), _jsx("span", { className: "absolute inset-0 rounded-[inherit] bg-mono200 animate-pulse" })] }));
|
|
7
|
+
};
|
|
8
|
+
export default LDSkeleton;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type SliderSingleProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
defaultValue?: number;
|
|
4
|
+
onChange?: (value: number) => void;
|
|
5
|
+
};
|
|
6
|
+
type SliderRangeProps = {
|
|
7
|
+
value?: [number, number];
|
|
8
|
+
defaultValue?: [number, number];
|
|
9
|
+
onChange?: (value: [number, number]) => void;
|
|
10
|
+
};
|
|
11
|
+
export type LDSliderProps = (SliderSingleProps | SliderRangeProps) & {
|
|
12
|
+
min?: number;
|
|
13
|
+
max?: number;
|
|
14
|
+
step?: number;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
orientation?: 'horizontal' | 'vertical';
|
|
17
|
+
showLabel?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
style?: React.CSSProperties;
|
|
20
|
+
};
|
|
21
|
+
declare const LDSlider: (props: LDSliderProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export default LDSlider;
|
|
23
|
+
//# sourceMappingURL=LDSlider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDSlider.d.ts","sourceRoot":"","sources":["../../../src/components/LDSlider/LDSlider.tsx"],"names":[],"mappings":"AAKA,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,iBAAiB,GAAG,gBAAgB,CAAC,GAAG;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAiCF,QAAA,MAAM,QAAQ,GAAI,OAAO,aAAa,4CAgUrC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useCallback, useMemo } from 'react';
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
// ── 헬퍼 함수 ────────────────────────────────────────────────────────────────
|
|
5
|
+
//퍼센테이지 계산
|
|
6
|
+
const toPercent = (value, min, max) => {
|
|
7
|
+
return ((value - min) / (max - min)) * 100;
|
|
8
|
+
};
|
|
9
|
+
//값 제한
|
|
10
|
+
const clamp = (value, min, max) => {
|
|
11
|
+
return Math.min(Math.max(value, min), max);
|
|
12
|
+
};
|
|
13
|
+
//값 범위
|
|
14
|
+
const getValueFromPointer = (clientPos, rect, isVertical, min, max, step) => {
|
|
15
|
+
const ratio = isVertical
|
|
16
|
+
? 1 - (clientPos - rect.top) / rect.height
|
|
17
|
+
: (clientPos - rect.left) / rect.width;
|
|
18
|
+
const raw = min + clamp(ratio, 0, 1) * (max - min);
|
|
19
|
+
const stepped = Math.round((raw - min) / step) * step + min;
|
|
20
|
+
return clamp(stepped, min, max);
|
|
21
|
+
};
|
|
22
|
+
// ── 컴포넌트 ──────────────────────────────────────────────────────────────
|
|
23
|
+
const LDSlider = (props) => {
|
|
24
|
+
const { min = 0, max = 100, step = 1, disabled = false, orientation = 'horizontal', showLabel = false, className, style, } = props;
|
|
25
|
+
const isVertical = orientation === 'vertical';
|
|
26
|
+
const isRange = Array.isArray(props.value ??
|
|
27
|
+
props.defaultValue);
|
|
28
|
+
// ── 단일 상태일 경우 제어, 비제어 상태 확인 ──
|
|
29
|
+
const singleControlled = !isRange && props.value !== undefined;
|
|
30
|
+
const [singleInternal, setSingleInternal] = useState(!isRange ? (props.defaultValue ?? min) : min);
|
|
31
|
+
const singleValue = singleControlled
|
|
32
|
+
? props.value
|
|
33
|
+
: singleInternal;
|
|
34
|
+
// ── 범위 상태일 경우 제어, 비제어 상태 확인 ──
|
|
35
|
+
const rangeControlled = isRange && props.value !== undefined;
|
|
36
|
+
const [rangeInternal, setRangeInternal] = useState(isRange
|
|
37
|
+
? (props.defaultValue ?? [min, max])
|
|
38
|
+
: [min, max]);
|
|
39
|
+
const rangeValue = rangeControlled
|
|
40
|
+
? props.value
|
|
41
|
+
: rangeInternal;
|
|
42
|
+
// stale closure 방지: 핸들러에서 항상 최신 rangeValue 참조
|
|
43
|
+
const rangeValueRef = useRef(rangeValue);
|
|
44
|
+
rangeValueRef.current = rangeValue;
|
|
45
|
+
// ── 범위 모드 시 활성화된 손잡이(Thumb) 관리 ──
|
|
46
|
+
const trackRef = useRef(null);
|
|
47
|
+
const activeThumbRef = useRef('a');
|
|
48
|
+
const resolveActiveThumb = useCallback((clientPos) => {
|
|
49
|
+
if (!trackRef.current)
|
|
50
|
+
return 'a';
|
|
51
|
+
const rect = trackRef.current.getBoundingClientRect();
|
|
52
|
+
const ratio = isVertical
|
|
53
|
+
? 1 - (clientPos - rect.top) / rect.height
|
|
54
|
+
: (clientPos - rect.left) / rect.width;
|
|
55
|
+
const pointValue = min + ratio * (max - min);
|
|
56
|
+
const current = rangeValueRef.current;
|
|
57
|
+
const distA = Math.abs(pointValue - current[0]);
|
|
58
|
+
const distB = Math.abs(pointValue - current[1]);
|
|
59
|
+
return distA <= distB ? 'a' : 'b';
|
|
60
|
+
}, [isVertical, min, max]);
|
|
61
|
+
// ── 변경 핸들러 ──
|
|
62
|
+
const handleSingleChange = useCallback((raw) => {
|
|
63
|
+
if (!singleControlled)
|
|
64
|
+
setSingleInternal(raw);
|
|
65
|
+
props.onChange?.(raw);
|
|
66
|
+
},
|
|
67
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
|
+
[singleControlled]);
|
|
69
|
+
const handleRangeChangeA = useCallback((raw) => {
|
|
70
|
+
const next = [
|
|
71
|
+
Math.min(raw, rangeValueRef.current[1]),
|
|
72
|
+
rangeValueRef.current[1],
|
|
73
|
+
];
|
|
74
|
+
if (!rangeControlled)
|
|
75
|
+
setRangeInternal(next);
|
|
76
|
+
props.onChange?.(next);
|
|
77
|
+
},
|
|
78
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
79
|
+
[rangeControlled]);
|
|
80
|
+
const handleRangeChangeB = useCallback((raw) => {
|
|
81
|
+
const next = [
|
|
82
|
+
rangeValueRef.current[0],
|
|
83
|
+
Math.max(raw, rangeValueRef.current[0]),
|
|
84
|
+
];
|
|
85
|
+
if (!rangeControlled)
|
|
86
|
+
setRangeInternal(next);
|
|
87
|
+
props.onChange?.(next);
|
|
88
|
+
},
|
|
89
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
+
[rangeControlled]);
|
|
91
|
+
// ── 트랙 포인터 핸들러 (클릭 이동 + 드래그) ──
|
|
92
|
+
const handleTrackPointerDown = useCallback((e) => {
|
|
93
|
+
if (disabled || !trackRef.current)
|
|
94
|
+
return;
|
|
95
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
96
|
+
const rect = trackRef.current.getBoundingClientRect();
|
|
97
|
+
const v = getValueFromPointer(isVertical ? e.clientY : e.clientX, rect, isVertical, min, max, step);
|
|
98
|
+
if (isRange) {
|
|
99
|
+
const which = resolveActiveThumb(isVertical ? e.clientY : e.clientX);
|
|
100
|
+
activeThumbRef.current = which;
|
|
101
|
+
if (which === 'a')
|
|
102
|
+
handleRangeChangeA(v);
|
|
103
|
+
else
|
|
104
|
+
handleRangeChangeB(v);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
handleSingleChange(v);
|
|
108
|
+
}
|
|
109
|
+
}, [
|
|
110
|
+
disabled,
|
|
111
|
+
isVertical,
|
|
112
|
+
min,
|
|
113
|
+
max,
|
|
114
|
+
step,
|
|
115
|
+
isRange,
|
|
116
|
+
resolveActiveThumb,
|
|
117
|
+
handleRangeChangeA,
|
|
118
|
+
handleRangeChangeB,
|
|
119
|
+
handleSingleChange,
|
|
120
|
+
]);
|
|
121
|
+
const handleTrackPointerMove = useCallback((e) => {
|
|
122
|
+
if (disabled ||
|
|
123
|
+
!e.currentTarget.hasPointerCapture(e.pointerId) ||
|
|
124
|
+
!trackRef.current)
|
|
125
|
+
return;
|
|
126
|
+
const rect = trackRef.current.getBoundingClientRect();
|
|
127
|
+
const v = getValueFromPointer(isVertical ? e.clientY : e.clientX, rect, isVertical, min, max, step);
|
|
128
|
+
if (isRange) {
|
|
129
|
+
if (activeThumbRef.current === 'a')
|
|
130
|
+
handleRangeChangeA(v);
|
|
131
|
+
else
|
|
132
|
+
handleRangeChangeB(v);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
handleSingleChange(v);
|
|
136
|
+
}
|
|
137
|
+
}, [
|
|
138
|
+
disabled,
|
|
139
|
+
isVertical,
|
|
140
|
+
min,
|
|
141
|
+
max,
|
|
142
|
+
step,
|
|
143
|
+
isRange,
|
|
144
|
+
handleRangeChangeA,
|
|
145
|
+
handleRangeChangeB,
|
|
146
|
+
handleSingleChange,
|
|
147
|
+
]);
|
|
148
|
+
// ── 채워지는 영역 퍼센트 계산 ──
|
|
149
|
+
const fillStyle = useMemo(() => {
|
|
150
|
+
if (isRange) {
|
|
151
|
+
const lo = toPercent(rangeValue[0], min, max);
|
|
152
|
+
const hi = toPercent(rangeValue[1], min, max);
|
|
153
|
+
return isVertical
|
|
154
|
+
? { bottom: `${lo}%`, height: `${hi - lo}%` }
|
|
155
|
+
: { left: `${lo}%`, width: `${hi - lo}%` };
|
|
156
|
+
}
|
|
157
|
+
const pct = toPercent(clamp(singleValue, min, max), min, max);
|
|
158
|
+
return isVertical
|
|
159
|
+
? { bottom: 0, height: `${pct}%` }
|
|
160
|
+
: { left: 0, width: `${pct}%` };
|
|
161
|
+
}, [isRange, isVertical, min, max, singleValue, rangeValue]);
|
|
162
|
+
// ── 라벨 위치 계산 ──
|
|
163
|
+
const labelAPercent = isRange
|
|
164
|
+
? toPercent(rangeValue[0], min, max)
|
|
165
|
+
: toPercent(clamp(singleValue, min, max), min, max);
|
|
166
|
+
const labelBPercent = isRange ? toPercent(rangeValue[1], min, max) : 0;
|
|
167
|
+
const shouldOffsetLabel = isRange && Math.abs(labelBPercent - labelAPercent) < 8;
|
|
168
|
+
const getLabelStyle = (percent, which) => {
|
|
169
|
+
const offset = shouldOffsetLabel ? (which === 'a' ? -16 : 16) : 0;
|
|
170
|
+
if (isVertical) {
|
|
171
|
+
return {
|
|
172
|
+
position: 'absolute',
|
|
173
|
+
left: 'calc(100% + 8px)',
|
|
174
|
+
bottom: `${percent}%`,
|
|
175
|
+
transform: `translateY(calc(50% + ${offset}px))`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
position: 'absolute',
|
|
180
|
+
bottom: 'calc(100% + 8px)',
|
|
181
|
+
left: `${percent}%`,
|
|
182
|
+
transform: `translateX(calc(-50% + ${offset}px))`,
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
// ── 수직 모드용 입력창 공통 스타일 ──
|
|
186
|
+
const inputStyle = isVertical
|
|
187
|
+
? { writingMode: 'vertical-lr', direction: 'rtl' }
|
|
188
|
+
: {};
|
|
189
|
+
// ── 렌더링 ──────────────────────────────────────────────────────────────
|
|
190
|
+
return (_jsxs("div", { className: cn('relative flex items-center', isVertical ? 'flex-col h-48 w-fit' : 'flex-row w-full', className), style: style, children: [_jsxs("div", { ref: trackRef, onPointerDown: handleTrackPointerDown, onPointerMove: handleTrackPointerMove, className: cn('relative rounded-full bg-mono200', isVertical ? 'w-1.5 h-full' : 'h-1.5 w-full', disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'), children: [_jsx("div", { className: "absolute rounded-full bg-lb500 pointer-events-none", style: {
|
|
191
|
+
...(isVertical ? { left: 0, right: 0 } : { top: 0, bottom: 0 }),
|
|
192
|
+
...fillStyle,
|
|
193
|
+
} }), !isRange && (_jsx("input", { type: "range", min: min, max: max, step: step, value: singleValue, disabled: disabled, onChange: (e) => handleSingleChange(e.target.valueAsNumber), className: "ld-slider-thumb absolute inset-0 w-full h-full", style: inputStyle })), isRange && (_jsxs(_Fragment, { children: [_jsx("input", { type: "range", min: min, max: max, step: step, value: rangeValue[0], disabled: disabled, onChange: (e) => handleRangeChangeA(e.target.valueAsNumber), className: "ld-slider-thumb absolute inset-0 w-full h-full z-0", style: inputStyle }), _jsx("input", { type: "range", min: min, max: max, step: step, value: rangeValue[1], disabled: disabled, onChange: (e) => handleRangeChangeB(e.target.valueAsNumber), className: "ld-slider-thumb absolute inset-0 w-full h-full z-0", style: inputStyle })] }))] }), showLabel && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-xs font-medium text-lb500 whitespace-nowrap pointer-events-none select-none", style: getLabelStyle(labelAPercent, 'a'), children: isRange ? rangeValue[0] : singleValue }), isRange && (_jsx("span", { className: "text-xs font-medium text-lb500 whitespace-nowrap pointer-events-none select-none", style: getLabelStyle(labelBPercent, 'b'), children: rangeValue[1] }))] }))] }));
|
|
194
|
+
};
|
|
195
|
+
export default LDSlider;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type SpinnerSize = 'xSmall' | 'small' | 'medium' | 'large' | 'big' | 'xLarge';
|
|
2
|
+
export interface LDSpinnerProps {
|
|
3
|
+
/**
|
|
4
|
+
* LDSpinner의 크기를 지정합니다. 프리셋 이름이나 숫자(px)를 사용할 수 있습니다. (기본값: 'large' / 24px)
|
|
5
|
+
*/
|
|
6
|
+
size?: SpinnerSize | number;
|
|
7
|
+
/**
|
|
8
|
+
* 추가적인 스타일 클래스를 지정합니다. (색상 등을 변경할 때 사용)
|
|
9
|
+
*/
|
|
10
|
+
className?: string;
|
|
11
|
+
/**
|
|
12
|
+
* 사용할 아이콘 타입을 지정합니다. (기본값: 'default')
|
|
13
|
+
*/
|
|
14
|
+
variant?: 'default' | 'split';
|
|
15
|
+
/**
|
|
16
|
+
* 접근성을 위한 라벨입니다. (기본값: 'loading')
|
|
17
|
+
*/
|
|
18
|
+
label?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 디자인 시스템 표준을 따르는 LDSpinner 컴포넌트입니다.
|
|
22
|
+
*/
|
|
23
|
+
declare const LDSpinner: ({ size, className, variant, label, }: LDSpinnerProps) => import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export default LDSpinner;
|
|
25
|
+
//# sourceMappingURL=LDSpinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDSpinner.d.ts","sourceRoot":"","sources":["../../../src/components/LDSpinner/LDSpinner.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,KAAK,GACL,QAAQ,CAAC;AAWb,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAC5B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,QAAA,MAAM,SAAS,GAAI,sCAKhB,cAAc,4CAYhB,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { LoaderIcon, LoaderCircleIcon } from 'lucide-react';
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
const sizeMap = {
|
|
5
|
+
xSmall: 12,
|
|
6
|
+
small: 16,
|
|
7
|
+
medium: 20,
|
|
8
|
+
large: 24,
|
|
9
|
+
big: 32,
|
|
10
|
+
xLarge: 48,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 디자인 시스템 표준을 따르는 LDSpinner 컴포넌트입니다.
|
|
14
|
+
*/
|
|
15
|
+
const LDSpinner = ({ size = 'large', className, variant = 'default', label = 'loading', }) => {
|
|
16
|
+
const Icon = variant === 'default' ? LoaderCircleIcon : LoaderIcon;
|
|
17
|
+
const pixelSize = typeof size === 'number' ? size : sizeMap[size];
|
|
18
|
+
return (_jsx(Icon, { size: pixelSize, className: cn('animate-spin text-muted-foreground', className), role: "status", "aria-label": label }));
|
|
19
|
+
};
|
|
20
|
+
export default LDSpinner;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ReactNode, type CSSProperties } from 'react';
|
|
2
|
+
export interface LDTableProps {
|
|
3
|
+
/** 테이블 콘텐츠 (LDTable.Header, LDTable.Body 등) */
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** 상단 타이틀 텍스트 */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** 전체 데이터 건수 (타이틀 옆에 표시) */
|
|
8
|
+
totalCount?: number;
|
|
9
|
+
/** 타이틀 우측에 배치할 요소 (버튼, 필터 등) */
|
|
10
|
+
/** 테이블 상단에 배치할 요소 */
|
|
11
|
+
/** 테이블 하단에 배치할 요소 (LDPagination 등) */
|
|
12
|
+
footer?: ReactNode;
|
|
13
|
+
/** 데이터 없음 상태 여부 */
|
|
14
|
+
isEmpty?: boolean;
|
|
15
|
+
/** 데이터 없을 때 표시할 메시지 */
|
|
16
|
+
emptyMessage?: string | ReactNode;
|
|
17
|
+
/** 빈 상태 행의 colSpan 값 */
|
|
18
|
+
columnCount?: number;
|
|
19
|
+
className?: string;
|
|
20
|
+
style?: CSSProperties;
|
|
21
|
+
}
|
|
22
|
+
declare const LDTable: {
|
|
23
|
+
({ children, title, totalCount, footer, isEmpty, emptyMessage, columnCount, className, style, }: LDTableProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
Header: ({ className, children, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) => import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
HeaderRow: ({ className, children, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
HeaderCell: ({ className, children, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>) => import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
Body: ({ className, children, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) => import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
Row: ({ className, children, ...props }: React.HTMLAttributes<HTMLTableRowElement> & {
|
|
29
|
+
selected?: boolean;
|
|
30
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
Cell: ({ className, children, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
};
|
|
33
|
+
export default LDTable;
|
|
34
|
+
//# sourceMappingURL=LDTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/LDTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAI3D,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,QAAQ,EAAE,SAAS,CAAC;IACpB,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,gCAAgC;IAGhC,qBAAqB;IAGrB,sCAAsC;IACtC,MAAM,CAAC,EAAE,SAAS,CAAC;IAQnB,mBAAmB;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,uBAAuB;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAElC,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CAOvB;AAED,QAAA,MAAM,OAAO;qGAgBV,YAAY;gDAmCZ,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC;mDAgB7C,KAAK,CAAC,cAAc,CAAC,mBAAmB,CAAC;oDAUzC,KAAK,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;8CAa5C,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC;6CAU7C,KAAK,CAAC,cAAc,CAAC,mBAAmB,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE;8CAgBlE,KAAK,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;CAxE9C,CAAC;AAqFF,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import TableBase from './TableBase.js';
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
const LDTable = ({ children, title, totalCount,
|
|
5
|
+
// rightSideContents,
|
|
6
|
+
// tableTop,
|
|
7
|
+
footer,
|
|
8
|
+
// scrollable = false,
|
|
9
|
+
// scrollMinWidth = '1440px',
|
|
10
|
+
isEmpty = false, emptyMessage = '조회하신 데이터가 없습니다.', columnCount, className, style,
|
|
11
|
+
// wrapperClassName,
|
|
12
|
+
// wrapperStyle,
|
|
13
|
+
}) => {
|
|
14
|
+
return (_jsxs("div", { className: cn('flex flex-col justify-between h-full gap-sm'), children: [title && (_jsxs("h3", { className: "whitespace-nowrap display16 bold", children: [title, totalCount !== undefined && ` (${totalCount.toLocaleString()})`] })), _jsxs(TableBase.Root, { className: cn('w-full', className), style: style, children: [children, isEmpty && columnCount && (_jsx(TableBase.Body, { children: _jsx(TableBase.Row, { children: _jsx(TableBase.Cell, { colSpan: columnCount, className: "text-center h-24 py-24", children: emptyMessage }) }) }))] }), footer] }));
|
|
15
|
+
};
|
|
16
|
+
// ── Styled Sub-components ──
|
|
17
|
+
const Header = ({ className, children, ...props }) => (_jsx(TableBase.Header, { className: cn('border-b border-neutral700 bg-mono100 hover:bg-mono200 ld-transition', className), ...props, children: children }));
|
|
18
|
+
const HeaderRow = ({ className, children, ...props }) => (_jsx(TableBase.HeaderRow, { className: cn('bg-neutral5', className), ...props, children: children }));
|
|
19
|
+
const HeaderCell = ({ className, children, ...props }) => (_jsx(TableBase.HeaderCell, { className: cn('px-4 py-3 text-left display12 regular', className), ...props, children: children }));
|
|
20
|
+
const Body = ({ className, children, ...props }) => (_jsx(TableBase.Body, { className: className, ...props, children: children }));
|
|
21
|
+
const Row = ({ className, children, ...props }) => (_jsx(TableBase.Row, { className: cn('border-b border-neutral100 hover:bg-black/3 ld-transition', className), ...props, children: children }));
|
|
22
|
+
const Cell = ({ className, children, ...props }) => (_jsx(TableBase.Cell, { className: cn('px-4 py-3 display14', className), ...props, children: children }));
|
|
23
|
+
LDTable.Header = Header;
|
|
24
|
+
LDTable.HeaderRow = HeaderRow;
|
|
25
|
+
LDTable.HeaderCell = HeaderCell;
|
|
26
|
+
LDTable.Body = Body;
|
|
27
|
+
LDTable.Row = Row;
|
|
28
|
+
LDTable.Cell = Cell;
|
|
29
|
+
export default LDTable;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode, type CSSProperties } from 'react';
|
|
2
|
+
import { type TableFieldProps, type Pageable } from './TableField.js';
|
|
3
|
+
export type { Pageable };
|
|
4
|
+
export interface LDTanstackTableProps<TData, TColumn> extends Omit<TableFieldProps<TData, TColumn>, 'children'> {
|
|
5
|
+
title?: string;
|
|
6
|
+
rightSideContents?: ReactNode;
|
|
7
|
+
tableTop?: ReactNode;
|
|
8
|
+
showPagination?: boolean;
|
|
9
|
+
emptyMessage?: string | ReactNode;
|
|
10
|
+
scrollable?: boolean;
|
|
11
|
+
stickyHeader?: boolean;
|
|
12
|
+
className?: string;
|
|
13
|
+
wrapperClassName?: string;
|
|
14
|
+
wrapperStyle?: CSSProperties;
|
|
15
|
+
headerClassName?: string;
|
|
16
|
+
theadClassName?: string;
|
|
17
|
+
rowClassName?: string;
|
|
18
|
+
cellClassName?: string;
|
|
19
|
+
paginationClassName?: string;
|
|
20
|
+
}
|
|
21
|
+
declare const LDTanstackTable: <TData, TColumn>({ columns, data, pageable, paginationState, onPageChange, sortingState, enableRowSelection, enableMultiRowSelection, rowSelectionState, enableToggleAllRowsSelection, getRowId, title, showPagination, emptyMessage, stickyHeader, className, headerClassName, theadClassName, rowClassName, cellClassName, paginationClassName, }: LDTanstackTableProps<TData, TColumn>) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export default LDTanstackTable;
|
|
23
|
+
//# sourceMappingURL=LDTanstackTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDTanstackTable.d.ts","sourceRoot":"","sources":["../../../src/components/LDTable/LDTanstackTable.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3D,OAAmB,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAM/E,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB,MAAM,WAAW,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAE,SAAQ,IAAI,CAChE,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,EAC/B,UAAU,CACX;IAEC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IAGrB,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,eAAe,GAAI,KAAK,EAAE,OAAO,EAAE,oUAwBtC,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,4CA+HtC,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ArrowUp, ArrowDown } from 'lucide-react';
|
|
4
|
+
import TableField from './TableField.js';
|
|
5
|
+
import LDTable from './LDTable.js';
|
|
6
|
+
import LDPagination from '../LDPagination/LDPagination.js';
|
|
7
|
+
import cn from '../../utils/cn.js';
|
|
8
|
+
const LDTanstackTable = ({
|
|
9
|
+
// TableField props
|
|
10
|
+
columns, data, pageable, paginationState, onPageChange, sortingState, enableRowSelection, enableMultiRowSelection, rowSelectionState, enableToggleAllRowsSelection, getRowId,
|
|
11
|
+
// 프레젠테이션 props
|
|
12
|
+
title, showPagination = true, emptyMessage, stickyHeader = false, className, headerClassName, theadClassName, rowClassName, cellClassName, paginationClassName, }) => {
|
|
13
|
+
return (_jsx(TableField, { columns: columns, data: data, pageable: pageable, paginationState: paginationState, onPageChange: onPageChange, sortingState: sortingState, enableRowSelection: enableRowSelection, enableMultiRowSelection: enableMultiRowSelection, rowSelectionState: rowSelectionState, enableToggleAllRowsSelection: enableToggleAllRowsSelection, getRowId: getRowId, children: ({ headerGroups, rows, isEmpty, currentPage, totalPages, toggleAllRowsSelected, onPageChange: handlePageChange, getHeader, getCell, }) => {
|
|
14
|
+
const paginationFooter = showPagination && !isEmpty && pageable && totalPages > 0 ? (_jsx(LDPagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: handlePageChange, className: paginationClassName })) : null;
|
|
15
|
+
return (_jsxs(LDTable, { title: title, totalCount: pageable?.totalCount,
|
|
16
|
+
// rightSideContents={rightSideContents}
|
|
17
|
+
// tableTop={tableTop}
|
|
18
|
+
// scrollable={scrollable}
|
|
19
|
+
isEmpty: isEmpty, emptyMessage: emptyMessage, columnCount: columns.length, footer: paginationFooter, className: className, children: [_jsx(LDTable.Header, { className: cn('hover:bg-mono11 ld-transition', theadClassName), children: headerGroups.map((hg) => (_jsx(LDTable.HeaderRow, { className: "w-full", onClick: toggleAllRowsSelected, children: hg.headers.map((header) => {
|
|
20
|
+
const h = getHeader(header);
|
|
21
|
+
return (_jsxs(LDTable.HeaderCell, { className: cn('relative h-9', headerClassName, stickyHeader &&
|
|
22
|
+
'sticky top-0 bg-mono10 z-10 border-b border-neutral10', h.canSort && 'cursor-pointer', h.meta
|
|
23
|
+
?.headerAlign === 'left'
|
|
24
|
+
? 'text-left'
|
|
25
|
+
: h.meta
|
|
26
|
+
?.headerAlign === 'right'
|
|
27
|
+
? 'text-right'
|
|
28
|
+
: 'text-center'), style: { width: h.size }, onClick: h.toggleSortingHandler, children: [h.renderHeader(), h.isSorted === 'asc' && (_jsx(ArrowUp, { className: "inline-block w-3 h-3 ml-1 align-middle" })), h.isSorted === 'desc' && (_jsx(ArrowDown, { className: "inline-block w-3 h-3 ml-1 align-middle" }))] }, h.id));
|
|
29
|
+
}) }, hg.id))) }), !isEmpty && (_jsx(LDTable.Body, { children: rows.map((row) => (_jsx(LDTable.Row, { selected: row.getIsSelected(), className: cn('hover:bg-black/3 ld-transition h-13', rowClassName), onClick: () => row.toggleSelected(), children: row.getVisibleCells().map((cell) => {
|
|
30
|
+
const c = getCell(cell);
|
|
31
|
+
return (_jsx(LDTable.Cell, { className: cellClassName, children: c.renderCell() }, c.id));
|
|
32
|
+
}) }, row.id))) }))] }));
|
|
33
|
+
} }));
|
|
34
|
+
};
|
|
35
|
+
export default LDTanstackTable;
|