@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 @@
|
|
|
1
|
+
{"version":3,"file":"MenuBar.d.ts","sourceRoot":"","sources":["../../../src/components/MenuBar/MenuBar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,WAAW,MAAM,eAAe,CAAC;AAkHxC,QAAA,MAAM,OAAO;oCA1GV,cAAc,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC;oCAcvC,cAAc,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC;mCAUvC,cAAc,CAAC,OAAO,WAAW,CAAC,GAAG,CAAC;oCAUtC,cAAc,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC;uCAOvC,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC;;kCAgB1C,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC;;;;kCAgB1C,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC;;;uCAoB1C,cAAc,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC;gCAS1C,cAAc,CAAC,OAAO,WAAW,CAAC,SAAS,CAAC;CAc9C,CAAC;AAEF,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
import MenuBarBase from './MenuBarBase.js';
|
|
5
|
+
// 스타일 래퍼: Base 골격에 디자인 토큰 클래스를 입혀 재노출.
|
|
6
|
+
// className을 주면 cn으로 머지되어 소비측 오버라이드 우선.
|
|
7
|
+
const Root = ({ className, ...props }) => (_jsx(MenuBarBase.Root, { className: cn('relative flex items-center justify-between w-full h-[64px] min-h-[64px]', 'px-md gap-10 bg-white border-b border-mono100 sticky top-0 z-50', className), ...props }));
|
|
8
|
+
const Logo = ({ className, ...props }) => (_jsx(MenuBarBase.Logo, { className: cn('flex items-center shrink-0', className), ...props }));
|
|
9
|
+
const Nav = ({ className, ...props }) => (_jsx(MenuBarBase.Nav, { className: cn('flex flex-1 items-center justify-start gap-xs', className), ...props }));
|
|
10
|
+
const Item = ({ className, ...props }) => (_jsx(MenuBarBase.Item, { className: className, ...props }));
|
|
11
|
+
const Trigger = ({ className, ...props }) => (_jsx(MenuBarBase.Trigger, { className: cn('flex items-center gap-xs px-sm py-xs rounded-[5px] cursor-pointer', 'display16 bold text-mono700 hover:bg-mono100 hover:text-mono900 ld-transition', 'aria-expanded:bg-tintBlue aria-expanded:text-blue400', className), ...props }));
|
|
12
|
+
// item 모드: 항목 바로 아래 작은 드롭다운
|
|
13
|
+
const Content = ({ className, ...props }) => (_jsx(MenuBarBase.Content, { className: cn('absolute top-full left-0 mt-xs min-w-[180px] z-50', 'flex flex-col gap-xs p-xs rounded-[8px] bg-white border border-mono100 shadow-lg', className), ...props }));
|
|
14
|
+
// mega 모드: 헤더 전체 폭 패널 + 뒤쪽 딤(클릭 시 닫기)
|
|
15
|
+
// fixed로 부모 li(relative)를 벗어나 뷰포트(=헤더) 전체 폭을 차지. top-16 = 헤더 높이 64px.
|
|
16
|
+
const MegaContent = ({ className, ...props }) => (_jsx(MenuBarBase.Content, { backdrop: true, backdropClassName: "fixed left-0 right-0 top-16 bottom-0 z-40 bg-black/40", className: cn('fixed left-0 right-0 top-16 z-50', 'p-lg bg-white border-b border-mono100 shadow-lg', className), ...props }));
|
|
17
|
+
// Item의 드롭다운 자동 판정이 래퍼를 통과하도록 Base와 동일한 displayName 부여
|
|
18
|
+
Content.displayName = MenuBarBase.Content.displayName;
|
|
19
|
+
MegaContent.displayName = MenuBarBase.Content.displayName;
|
|
20
|
+
const Actions = ({ className, ...props }) => (_jsx(MenuBarBase.Actions, { className: cn('flex items-center gap-sm shrink-0', className), ...props }));
|
|
21
|
+
const Separator = ({ className, }) => (_jsx(MenuBarBase.Separator, { className: cn('w-px h-5 bg-mono200', className) }));
|
|
22
|
+
const MenuBar = {
|
|
23
|
+
Root,
|
|
24
|
+
Logo,
|
|
25
|
+
Nav,
|
|
26
|
+
Item,
|
|
27
|
+
Trigger,
|
|
28
|
+
Content,
|
|
29
|
+
MegaContent,
|
|
30
|
+
Actions,
|
|
31
|
+
Separator,
|
|
32
|
+
};
|
|
33
|
+
export default MenuBar;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ElementType, ReactNode } from 'react';
|
|
2
|
+
interface RootProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
className?: string;
|
|
5
|
+
trigger?: 'hover' | 'click';
|
|
6
|
+
}
|
|
7
|
+
interface SlotProps {
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ItemProps {
|
|
12
|
+
value: string;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
interface TriggerProps {
|
|
17
|
+
as?: ElementType;
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface ContentProps extends SlotProps {
|
|
23
|
+
/** 뒤쪽 딤 + 클릭 시 닫기 */
|
|
24
|
+
backdrop?: boolean;
|
|
25
|
+
backdropClassName?: string;
|
|
26
|
+
}
|
|
27
|
+
declare const MenuBarBase: {
|
|
28
|
+
Root: ({ children, className, trigger }: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
Logo: ({ children, className }: SlotProps) => import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
Nav: ({ children, className }: SlotProps) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
Item: ({ value, children, className }: ItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
Trigger: ({ as: Comp, children, className, ...rest }: TriggerProps) => import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
Content: {
|
|
34
|
+
({ children, className, backdrop, backdropClassName, }: ContentProps): import("react/jsx-runtime").JSX.Element | null;
|
|
35
|
+
displayName: string;
|
|
36
|
+
};
|
|
37
|
+
Actions: ({ children, className }: SlotProps) => import("react/jsx-runtime").JSX.Element;
|
|
38
|
+
Separator: ({ className }: {
|
|
39
|
+
className?: string;
|
|
40
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
};
|
|
42
|
+
export default MenuBarBase;
|
|
43
|
+
//# sourceMappingURL=MenuBarBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MenuBarBase.d.ts","sourceRoot":"","sources":["../../../src/components/MenuBar/MenuBarBase.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AA0CpD,UAAU,SAAS;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC7B;AAqBD,UAAU,SAAS;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmBD,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0BD,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAuCD,UAAU,YAAa,SAAQ,SAAS;IACtC,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA0BD,QAAA,MAAM,WAAW;6CAjJyC,SAAS;oCAwB5B,SAAS;mCAIV,SAAS;2CAmBD,SAAS;0DAoCpD,YAAY;;gEA2CZ,YAAY;;;uCA9F2B,SAAS;+BAIjB;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;CAsHvD,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Children, createContext, isValidElement, useContext, useState, } from 'react';
|
|
4
|
+
import cn from '../../utils/cn.js';
|
|
5
|
+
const CONTENT_NAME = 'MenuBarContent';
|
|
6
|
+
const MenuBarContext = createContext(null);
|
|
7
|
+
const useMenuBarContext = () => {
|
|
8
|
+
const ctx = useContext(MenuBarContext);
|
|
9
|
+
if (!ctx)
|
|
10
|
+
throw new Error('MenuBarBase 서브컴포넌트는 MenuBarBase.Root 내부에서 사용해야 합니다.');
|
|
11
|
+
return ctx;
|
|
12
|
+
};
|
|
13
|
+
const ItemContext = createContext(null);
|
|
14
|
+
const useItemContext = () => {
|
|
15
|
+
const ctx = useContext(ItemContext);
|
|
16
|
+
if (!ctx)
|
|
17
|
+
throw new Error('MenuBarBase.Trigger / Content는 MenuBarBase.Item 내부에서 사용해야 합니다.');
|
|
18
|
+
return ctx;
|
|
19
|
+
};
|
|
20
|
+
const Root = ({ children, className, trigger = 'hover' }) => {
|
|
21
|
+
const [openValue, setOpenValue] = useState(null);
|
|
22
|
+
const isOpen = (v) => openValue === v;
|
|
23
|
+
return (_jsx(MenuBarContext, { value: { openValue, setOpenValue, isOpen, trigger }, children: _jsx("header", { className: className, onMouseLeave: trigger === 'hover' ? () => setOpenValue(null) : undefined, children: children }) }));
|
|
24
|
+
};
|
|
25
|
+
const Logo = ({ children, className }) => (_jsx("div", { className: className, children: children }));
|
|
26
|
+
const Nav = ({ children, className }) => (_jsx("ul", { className: className, children: children }));
|
|
27
|
+
const Actions = ({ children, className }) => (_jsx("div", { className: className, children: children }));
|
|
28
|
+
const Separator = ({ className }) => (_jsx("span", { "aria-hidden": true, className: className }));
|
|
29
|
+
const Item = ({ value, children, className }) => {
|
|
30
|
+
const { trigger, setOpenValue } = useMenuBarContext();
|
|
31
|
+
// Content 존재 여부로 드롭다운 항목인지 자동 판정 (스타일 래퍼도 같은 displayName을 가짐)
|
|
32
|
+
const hasContent = Children.toArray(children).some((c) => isValidElement(c) &&
|
|
33
|
+
c.type?.displayName === CONTENT_NAME);
|
|
34
|
+
const hoverProps = trigger === 'hover' && hasContent
|
|
35
|
+
? { onMouseEnter: () => setOpenValue(value) }
|
|
36
|
+
: {};
|
|
37
|
+
return (_jsx(ItemContext, { value: { value, hasContent }, children: _jsx("li", { className: cn('relative', className), ...hoverProps, children: children }) }));
|
|
38
|
+
};
|
|
39
|
+
const Trigger = ({ as: Comp = 'button', children, className, ...rest }) => {
|
|
40
|
+
const { trigger, setOpenValue, isOpen } = useMenuBarContext();
|
|
41
|
+
const { value, hasContent } = useItemContext();
|
|
42
|
+
// 드롭다운 없는 항목 → 순수 링크/버튼 (토글 안 함)
|
|
43
|
+
if (!hasContent) {
|
|
44
|
+
return (_jsx(Comp, { className: className, ...rest, children: children }));
|
|
45
|
+
}
|
|
46
|
+
const handleClick = trigger === 'click'
|
|
47
|
+
? () => setOpenValue(isOpen(value) ? null : value)
|
|
48
|
+
: undefined;
|
|
49
|
+
return (_jsx(Comp, { type: Comp === 'button' ? 'button' : undefined, "aria-expanded": isOpen(value), onClick: handleClick, className: className, ...rest, children: children }));
|
|
50
|
+
};
|
|
51
|
+
const Content = ({ children, className, backdrop, backdropClassName, }) => {
|
|
52
|
+
const { isOpen, setOpenValue } = useMenuBarContext();
|
|
53
|
+
const { value } = useItemContext();
|
|
54
|
+
if (!isOpen(value))
|
|
55
|
+
return null;
|
|
56
|
+
return (_jsxs(_Fragment, { children: [backdrop && (_jsx("div", { "aria-hidden": true, onClick: () => setOpenValue(null), className: backdropClassName })), _jsx("div", { className: className, children: children })] }));
|
|
57
|
+
};
|
|
58
|
+
Content.displayName = CONTENT_NAME;
|
|
59
|
+
const MenuBarBase = {
|
|
60
|
+
Root,
|
|
61
|
+
Logo,
|
|
62
|
+
Nav,
|
|
63
|
+
Item,
|
|
64
|
+
Trigger,
|
|
65
|
+
Content,
|
|
66
|
+
Actions,
|
|
67
|
+
Separator,
|
|
68
|
+
};
|
|
69
|
+
export default MenuBarBase;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export type ModalSize = 'small' | 'medium' | 'large' | 'xlarge';
|
|
3
|
+
export interface ModalButtons {
|
|
4
|
+
direction?: 'row' | 'column';
|
|
5
|
+
list?: ModalButton[];
|
|
6
|
+
}
|
|
7
|
+
export interface ModalButton<T = unknown> {
|
|
8
|
+
/** 버튼 텍스트 */
|
|
9
|
+
label: string;
|
|
10
|
+
/** 버튼 식별 값 (onButtonClick에 전달) */
|
|
11
|
+
value: T;
|
|
12
|
+
/** 버튼 스타일 유형 */
|
|
13
|
+
variant?: 'solid' | 'outline' | 'ghost';
|
|
14
|
+
/** 버튼 색상 테마 */
|
|
15
|
+
color?: 'neutral' | 'point' | 'danger';
|
|
16
|
+
/** 클릭 핸들러 (false 반환 시 모달 닫힘 방지) */
|
|
17
|
+
onClick?: () => void | boolean | Promise<void | boolean>;
|
|
18
|
+
}
|
|
19
|
+
export interface ModalProps {
|
|
20
|
+
/** 모달 열림 상태 (제어 컴포넌트) */
|
|
21
|
+
open?: boolean;
|
|
22
|
+
/** 초기 열림 상태 (비제어 컴포넌트) */
|
|
23
|
+
defaultOpen?: boolean;
|
|
24
|
+
/** 열림 상태 변경 시 호출되는 콜백 */
|
|
25
|
+
onOpenChange?: (open: boolean) => void;
|
|
26
|
+
/** 서브 타이틀 (title 위에 표시) */
|
|
27
|
+
name?: string;
|
|
28
|
+
/** 모달 제목 */
|
|
29
|
+
title?: string;
|
|
30
|
+
/** 모달 설명 텍스트 */
|
|
31
|
+
description?: string;
|
|
32
|
+
/** 본문 콘텐츠 */
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
/** 모달 너비 프리셋 */
|
|
35
|
+
size?: ModalSize;
|
|
36
|
+
/** 너비 직접 지정 (size보다 우선) */
|
|
37
|
+
icon?: 'success' | 'fail';
|
|
38
|
+
/** 하단 버튼 목록 */
|
|
39
|
+
buttons?: ModalButtons;
|
|
40
|
+
/** 스크롤 동작 */
|
|
41
|
+
scrollBehavior?: 'inside' | 'outside';
|
|
42
|
+
/** 추가 CSS 클래스 (모달 패널에 적용) */
|
|
43
|
+
className?: string;
|
|
44
|
+
/** 인라인 스타일 (모달 패널에 적용) */
|
|
45
|
+
style?: React.CSSProperties;
|
|
46
|
+
/** 버튼 클릭 시 해당 버튼의 value를 전달하는 콜백 */
|
|
47
|
+
onButtonClick?: (value: unknown) => void;
|
|
48
|
+
}
|
|
49
|
+
declare const Modal: ({ open, defaultOpen, onOpenChange, name, title, description, children, size, icon, buttons, scrollBehavior, className, style, onButtonClick, }: ModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
export default Modal;
|
|
51
|
+
//# sourceMappingURL=Modal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../src/components/Modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,OAAO,CAAC;AAO/C,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEhE,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,KAAK,EAAE,CAAC,CAAC;IACT,gBAAgB;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;IACxC,eAAe;IACf,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IACvC,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,UAAU;IACzB,yBAAyB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0BAA0B;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yBAAyB;IACzB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,gBAAgB;IAChB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,eAAe;IACf,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,aAAa;IACb,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AA6CD,QAAA,MAAM,KAAK,GAAI,gJAeZ,UAAU,4CA0JZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import ModalBase from './ModalBase.js';
|
|
4
|
+
import LucideIcon from '../Icon/LucideIcon.js';
|
|
5
|
+
import cn from '../../utils/cn.js';
|
|
6
|
+
import Button from '../Button/Button.js';
|
|
7
|
+
// ── 스타일 매핑 ──
|
|
8
|
+
const sizeClasses = {
|
|
9
|
+
small: 'modal-sm',
|
|
10
|
+
medium: 'modal-md',
|
|
11
|
+
large: 'modal-lg',
|
|
12
|
+
xlarge: 'modal-xl',
|
|
13
|
+
};
|
|
14
|
+
const buttonSizeClasses = {
|
|
15
|
+
small: 'medium',
|
|
16
|
+
medium: 'large',
|
|
17
|
+
large: 'large',
|
|
18
|
+
xlarge: 'large',
|
|
19
|
+
};
|
|
20
|
+
const buttonsGapSizeClasses = {
|
|
21
|
+
small: 'gap-xs',
|
|
22
|
+
medium: 'gap-sm',
|
|
23
|
+
large: 'gap-sm',
|
|
24
|
+
xlarge: 'gap-sm',
|
|
25
|
+
};
|
|
26
|
+
const layoutGapSizeClasses = {
|
|
27
|
+
small: 'gap-lg',
|
|
28
|
+
medium: 'gap-xl',
|
|
29
|
+
large: 'gap-xl',
|
|
30
|
+
xlarge: 'gap-xl',
|
|
31
|
+
};
|
|
32
|
+
const noHeaderPaddingTopSizeClasses = {
|
|
33
|
+
small: 'pt-lg',
|
|
34
|
+
medium: 'pt-xl',
|
|
35
|
+
large: 'pt-xl',
|
|
36
|
+
xlarge: 'pt-xl',
|
|
37
|
+
};
|
|
38
|
+
const statusIconSizeClasses = {
|
|
39
|
+
small: 'size-10',
|
|
40
|
+
medium: 'size-12.5',
|
|
41
|
+
large: 'size-12.5',
|
|
42
|
+
xlarge: 'size-12.5',
|
|
43
|
+
};
|
|
44
|
+
const Modal = ({ open, defaultOpen, onOpenChange, name, title, description, children, size = 'small', icon, buttons, scrollBehavior = 'inside', className, style, onButtonClick, }) => {
|
|
45
|
+
const overlayRef = useRef(false);
|
|
46
|
+
const hasHeader = name || title || description || icon;
|
|
47
|
+
const handleClick = async (button) => {
|
|
48
|
+
if (button.onClick) {
|
|
49
|
+
const res = await button.onClick();
|
|
50
|
+
if (res === false)
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
onButtonClick?.(button.value);
|
|
54
|
+
onOpenChange?.(false);
|
|
55
|
+
};
|
|
56
|
+
return (_jsxs(ModalBase.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, children: [_jsx(ModalBase.Overlay, {}), _jsx(ModalBase.Content, { className: cn({
|
|
57
|
+
['top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2']: scrollBehavior === 'inside',
|
|
58
|
+
['inset-0 overflow-y-auto flex justify-center items-start py-20']: scrollBehavior === 'outside',
|
|
59
|
+
}), onMouseDown: (e) => (overlayRef.current = e.target === e.currentTarget), onClick: (e) => {
|
|
60
|
+
if (scrollBehavior === 'outside' &&
|
|
61
|
+
e.target === e.currentTarget &&
|
|
62
|
+
overlayRef.current)
|
|
63
|
+
onOpenChange?.(false);
|
|
64
|
+
overlayRef.current = false;
|
|
65
|
+
}, children: _jsxs("div", { className: cn('relative bg-white rounded-2xl p-5', sizeClasses[size], 'mobile:max-w-[calc(100vw-40px)]', scrollBehavior === 'inside' &&
|
|
66
|
+
'flex flex-col overflow-y-auto max-h-[90dvh]', className), style: style, onClick: (e) => e.stopPropagation(), children: [_jsx(ModalBase.Close, { className: "absolute top-4 right-5 text-neutral500 cursor-pointer outline-hidden", children: _jsx(Button, { variant: "ghost", color: "neutral", leftIcon: "x", compact: true }) }), _jsxs("div", { className: cn('w-full flex flex-col shrink-0', scrollBehavior === 'inside' && 'flex-1 min-h-0', layoutGapSizeClasses[size], !hasHeader && noHeaderPaddingTopSizeClasses[size]), children: [hasHeader && (_jsxs("div", { className: "w-full flex gap-5 py-5 items-center flex-col text-center shrink-0", children: [icon === 'success' && (_jsx("div", { className: cn('flex items-center justify-center rounded-full bg-hyper-blue', statusIconSizeClasses[size]), children: _jsx(LucideIcon, { name: "check", className: "text-white" }) })), icon === 'fail' && (_jsx("div", { className: cn('flex items-center justify-center rounded-full bg-danger600', statusIconSizeClasses[size]), children: _jsx(LucideIcon, { name: "circleAlert", className: "text-white" }) })), name && (_jsx("span", { className: "display16 bold text-neutral500 whitespace-pre-wrap", children: name })), title && (_jsx(ModalBase.Title, { className: "display28 bold whitespace-pre-wrap text-center", children: title })), description && (_jsx(ModalBase.Description, { className: "display14 text-neutral500 whitespace-pre-wrap text-center", children: description }))] })), children && (_jsx("div", { className: cn(scrollBehavior === 'inside' &&
|
|
67
|
+
'flex-1 min-h-10 overflow-y-auto'), children: children })), buttons?.list && buttons?.list?.length > 0 && (_jsx("div", { className: cn('flex mobile:flex-1 mobile:flex-col mobile:items-center', buttons.direction === 'column' ? 'flex-col' : 'flex-row', buttonsGapSizeClasses[size]), children: buttons?.list?.map((button, index) => {
|
|
68
|
+
const isFirst = index === 0;
|
|
69
|
+
return (_jsx("div", { className: "flex flex-1 w-full", children: _jsx(Button, { type: "button", onClick: () => handleClick(button), variant: button.variant ?? (isFirst ? 'solid' : 'outline'), color: button.color ?? (isFirst ? 'point' : 'neutral'), size: buttonSizeClasses[size], block: true, children: button.label }) }, String(button.value)));
|
|
70
|
+
}) }))] })] }) })] }));
|
|
71
|
+
};
|
|
72
|
+
export default Modal;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
interface RootProps {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
defaultOpen?: boolean;
|
|
5
|
+
onOpenChange?: (open: boolean) => void;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
interface OverlayProps {
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ContentProps {
|
|
12
|
+
className?: string;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
onClick?: React.MouseEventHandler<HTMLElement>;
|
|
16
|
+
onMouseDown?: React.MouseEventHandler<HTMLElement>;
|
|
17
|
+
onPointerDownOutside?: (e: Event) => void;
|
|
18
|
+
onEscapeKeyDown?: (e: KeyboardEvent) => void;
|
|
19
|
+
}
|
|
20
|
+
interface CloseProps {
|
|
21
|
+
asChild?: boolean;
|
|
22
|
+
className?: string;
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
interface TitleProps {
|
|
26
|
+
className?: string;
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
interface DescriptionProps {
|
|
30
|
+
className?: string;
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
export declare const ModalBase: {
|
|
34
|
+
Root: ({ open, defaultOpen, onOpenChange, children }: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
Overlay: ({ className }: OverlayProps) => import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
Content: ({ className, children, style, onClick, onMouseDown, onPointerDownOutside, onEscapeKeyDown, }: ContentProps) => import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
Close: ({ asChild, className, children }: CloseProps) => import("react/jsx-runtime").JSX.Element;
|
|
38
|
+
Title: ({ className, children }: TitleProps) => import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
Description: ({ className, children }: DescriptionProps) => import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
};
|
|
41
|
+
export default ModalBase;
|
|
42
|
+
//# sourceMappingURL=ModalBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModalBase.d.ts","sourceRoot":"","sources":["../../../src/components/Modal/ModalBase.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,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,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiBD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACnD,oBAAoB,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAC1C,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;CAC9C;AAgCD,UAAU,UAAU;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAOD,UAAU,gBAAgB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAQD,eAAO,MAAM,SAAS;0DA5GuC,SAAS;6BAiBtC,YAAY;4GAiCzC,YAAY;8CA4BkC,UAAU;qCAcnB,UAAU;2CAUJ,gBAAgB;CAa7D,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as Dialog from '@radix-ui/react-dialog';
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
const Root = ({ open, defaultOpen, onOpenChange, children }) => {
|
|
5
|
+
return (_jsx(Dialog.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, children: children }));
|
|
6
|
+
};
|
|
7
|
+
const Overlay = ({ className }) => {
|
|
8
|
+
return (_jsx(Dialog.Portal, { children: _jsx(Dialog.Overlay, { className: cn('fixed inset-0 z-50 bg-black/30', 'data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out', className) }) }));
|
|
9
|
+
};
|
|
10
|
+
const Content = ({ className, children, style, onClick, onMouseDown, onPointerDownOutside, onEscapeKeyDown, }) => {
|
|
11
|
+
return (_jsx(Dialog.Portal, { children: _jsx(Dialog.Content, { className: cn('fixed z-50', 'data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out', className), style: style, onClick: onClick, onMouseDown: onMouseDown, onPointerDownOutside: onPointerDownOutside, onEscapeKeyDown: onEscapeKeyDown, children: children }) }));
|
|
12
|
+
};
|
|
13
|
+
const Close = ({ asChild, className, children }) => {
|
|
14
|
+
return (_jsx(Dialog.Close, { asChild: asChild, className: className, children: children }));
|
|
15
|
+
};
|
|
16
|
+
const Title = ({ className, children }) => {
|
|
17
|
+
return _jsx(Dialog.Title, { className: className, children: children });
|
|
18
|
+
};
|
|
19
|
+
const Description = ({ className, children }) => {
|
|
20
|
+
return (_jsx(Dialog.Description, { className: className, children: children }));
|
|
21
|
+
};
|
|
22
|
+
export const ModalBase = {
|
|
23
|
+
Root,
|
|
24
|
+
Overlay,
|
|
25
|
+
Content,
|
|
26
|
+
Close,
|
|
27
|
+
Title,
|
|
28
|
+
Description,
|
|
29
|
+
};
|
|
30
|
+
export default ModalBase;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ModalSize } from './Modal.js';
|
|
2
|
+
interface ModalOptions<T = undefined> {
|
|
3
|
+
name?: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
content?: React.ReactNode | ((args: {
|
|
7
|
+
onClose: (value?: T) => void;
|
|
8
|
+
}) => React.ReactNode);
|
|
9
|
+
buttons?: {
|
|
10
|
+
value: T;
|
|
11
|
+
label: string;
|
|
12
|
+
variant?: 'solid' | 'outline' | 'ghost';
|
|
13
|
+
color?: 'neutral' | 'point' | 'danger';
|
|
14
|
+
onClick?: () => void | boolean | Promise<void | boolean>;
|
|
15
|
+
}[];
|
|
16
|
+
/** 버튼 배치 방향 */
|
|
17
|
+
buttonsDirection?: 'row' | 'column';
|
|
18
|
+
size?: ModalSize;
|
|
19
|
+
icon?: 'success' | 'fail';
|
|
20
|
+
onBeforeClose?: () => Promise<boolean> | boolean;
|
|
21
|
+
}
|
|
22
|
+
declare const modal: <T = undefined>(options: ModalOptions<T>) => Promise<T | undefined>;
|
|
23
|
+
export default modal;
|
|
24
|
+
//# sourceMappingURL=openModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openModal.d.ts","sourceRoot":"","sources":["../../../src/components/Modal/openModal.tsx"],"names":[],"mappings":"AACA,OAAc,EAAoB,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAElE,UAAU,YAAY,CAAC,CAAC,GAAG,SAAS;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EACJ,KAAK,CAAC,SAAS,GACf,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAClE,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC;QACT,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;QACxC,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;QACvC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;KAC1D,EAAE,CAAC;IACJ,eAAe;IACf,gBAAgB,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAClD;AAED,QAAA,MAAM,KAAK,GAAI,CAAC,GAAG,SAAS,EAC1B,SAAS,YAAY,CAAC,CAAC,CAAC,KACvB,OAAO,CAAC,CAAC,GAAG,SAAS,CAgEvB,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import Modal from './Modal.js';
|
|
4
|
+
const modal = (options) => {
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
const container = document.createElement('div');
|
|
7
|
+
document.body.appendChild(container);
|
|
8
|
+
const root = createRoot(container);
|
|
9
|
+
const cleanup = () => {
|
|
10
|
+
root.unmount();
|
|
11
|
+
container.remove();
|
|
12
|
+
};
|
|
13
|
+
const handleClose = async (value) => {
|
|
14
|
+
try {
|
|
15
|
+
if (options.onBeforeClose) {
|
|
16
|
+
const canClose = await options.onBeforeClose();
|
|
17
|
+
if (!canClose)
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
console.error('onBeforeClose error:', e);
|
|
23
|
+
}
|
|
24
|
+
cleanup();
|
|
25
|
+
resolve(value);
|
|
26
|
+
};
|
|
27
|
+
const list = options.buttons?.map((btn) => ({
|
|
28
|
+
...btn,
|
|
29
|
+
value: btn.value,
|
|
30
|
+
onClick: async () => {
|
|
31
|
+
let shouldClose = true;
|
|
32
|
+
if (btn.onClick) {
|
|
33
|
+
const res = await btn.onClick();
|
|
34
|
+
if (res === false)
|
|
35
|
+
shouldClose = false;
|
|
36
|
+
}
|
|
37
|
+
if (shouldClose) {
|
|
38
|
+
handleClose(btn.value);
|
|
39
|
+
}
|
|
40
|
+
return false; // Modal 내부의 기본 닫기 동작 방지
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
43
|
+
const content = typeof options.content === 'function'
|
|
44
|
+
? options.content({ onClose: handleClose })
|
|
45
|
+
: options.content;
|
|
46
|
+
root.render(_jsx(Modal, { open: true, onOpenChange: (open) => {
|
|
47
|
+
if (!open)
|
|
48
|
+
handleClose(undefined);
|
|
49
|
+
}, name: options.name, title: options.title, description: options.description, size: options.size, icon: options.icon, buttons: list ? { direction: options.buttonsDirection, list } : undefined, children: content }));
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
export default modal;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type OTPInputSize = 'xSmall' | 'small' | 'medium' | 'large' | 'xLarge';
|
|
3
|
+
export type OTPInputVariant = 'filled' | 'outline' | 'ghost';
|
|
4
|
+
export interface OTPInputProps {
|
|
5
|
+
maxLength: number;
|
|
6
|
+
value: string;
|
|
7
|
+
onChange: (value: string) => void;
|
|
8
|
+
onComplete?: (value: string) => void;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
isInvalid?: boolean;
|
|
11
|
+
variant?: OTPInputVariant;
|
|
12
|
+
size?: OTPInputSize;
|
|
13
|
+
className?: string;
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* OTPInput (Root)
|
|
18
|
+
* 실제 입력을 처리하는 Hidden Input과 상태를 관리합니다.
|
|
19
|
+
*/
|
|
20
|
+
declare const OTPInput: ({ maxLength, value, onChange, onComplete, disabled, isInvalid, variant, size, className, children, }: OTPInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
/**
|
|
22
|
+
* OTPInputGroup
|
|
23
|
+
* 슬롯들을 묶어주는 컨테이너입니다.
|
|
24
|
+
*/
|
|
25
|
+
declare const OTPInputGroup: ({ className, children, }: {
|
|
26
|
+
className?: string;
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
/**
|
|
30
|
+
* OTPInputSlot
|
|
31
|
+
* 개별 글자를 보여주는 칸입니다.
|
|
32
|
+
*/
|
|
33
|
+
declare const OTPInputSlot: ({ index, className, }: {
|
|
34
|
+
index: number;
|
|
35
|
+
className?: string;
|
|
36
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
/**
|
|
38
|
+
* OTPInputSeparator
|
|
39
|
+
* 그룹 사이의 구분선입니다.
|
|
40
|
+
*/
|
|
41
|
+
declare const OTPInputSeparator: ({ className }: {
|
|
42
|
+
className?: string;
|
|
43
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export { OTPInput, OTPInputGroup, OTPInputSlot, OTPInputSeparator };
|
|
45
|
+
export default OTPInput;
|
|
46
|
+
//# sourceMappingURL=OTPInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OTPInput.d.ts","sourceRoot":"","sources":["../../../src/components/OTPInput/OTPInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAMN,MAAM,OAAO,CAAC;AA2Bf,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAC9E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAkBD;;;GAGG;AACH,QAAA,MAAM,QAAQ,GAAI,sGAWf,aAAa,4CA4Df,CAAC;AAEF;;;GAGG;AACH,QAAA,MAAM,aAAa,GAAI,0BAGpB;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,4CAIA,CAAC;AAEF;;;GAGG;AACH,QAAA,MAAM,YAAY,GAAI,uBAGnB;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,4CA0BA,CAAC;AAEF;;;GAGG;AACH,QAAA,MAAM,iBAAiB,GAAI,eAAe;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,4CAE/D,CAAC;AAGF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC;AACpE,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useState, useContext, createContext, useEffect, } from 'react';
|
|
4
|
+
import cn from '../../utils/cn.js';
|
|
5
|
+
const OTPInputContext = createContext(null);
|
|
6
|
+
function useOTPInputContext() {
|
|
7
|
+
const context = useContext(OTPInputContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error('OTPInput 하위 컴포넌트는 OTPInput 안에서 사용되어야 합니다.');
|
|
10
|
+
}
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
const sizeClasses = {
|
|
14
|
+
xSmall: 'w-[16px] h-[16px] display10',
|
|
15
|
+
small: 'w-[24px] h-[24px] display12',
|
|
16
|
+
medium: 'w-[32px] h-[32px] display14',
|
|
17
|
+
large: 'w-[40px] h-[40px] display16',
|
|
18
|
+
xLarge: 'w-[64px] h-[64px] display20',
|
|
19
|
+
};
|
|
20
|
+
const variantClasses = {
|
|
21
|
+
filled: 'bg-lb50 border-2 border-transparent text-lb900',
|
|
22
|
+
outline: 'bg-transparent border border-mono200',
|
|
23
|
+
ghost: 'bg-transparent border-b-2 border-mono200 rounded-none',
|
|
24
|
+
};
|
|
25
|
+
// ── Components ──
|
|
26
|
+
/**
|
|
27
|
+
* OTPInput (Root)
|
|
28
|
+
* 실제 입력을 처리하는 Hidden Input과 상태를 관리합니다.
|
|
29
|
+
*/
|
|
30
|
+
const OTPInput = ({ maxLength, value, onChange, onComplete, disabled = false, isInvalid = false, variant = 'outline', size = 'medium', className, children, }) => {
|
|
31
|
+
const inputRef = useRef(null);
|
|
32
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
33
|
+
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (isFocused) {
|
|
36
|
+
setFocusedIndex(value.length);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
setFocusedIndex(-1);
|
|
40
|
+
}
|
|
41
|
+
}, [value, isFocused]);
|
|
42
|
+
const handleInputChange = (e) => {
|
|
43
|
+
const newValue = e.target.value
|
|
44
|
+
.replace(/[^0-9a-zA-Z]/g, '')
|
|
45
|
+
.slice(0, maxLength);
|
|
46
|
+
onChange(newValue);
|
|
47
|
+
if (newValue.length === maxLength && onComplete) {
|
|
48
|
+
onComplete(newValue);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return (_jsx(OTPInputContext.Provider, { value: {
|
|
52
|
+
value,
|
|
53
|
+
maxLength,
|
|
54
|
+
focusedIndex,
|
|
55
|
+
isInvalid,
|
|
56
|
+
disabled,
|
|
57
|
+
size,
|
|
58
|
+
variant,
|
|
59
|
+
}, children: _jsxs("div", { className: cn('relative flex items-center gap-2 cursor-text select-none', disabled && 'opacity-50 cursor-not-allowed', className), onClick: () => !disabled && inputRef.current?.focus(), children: [_jsx("input", { ref: inputRef, type: "text", inputMode: "numeric", autoComplete: "one-time-code", value: value, onChange: handleInputChange, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), disabled: disabled, className: "absolute inset-0 opacity-0 cursor-default pointer-events-none" }), children] }) }));
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* OTPInputGroup
|
|
63
|
+
* 슬롯들을 묶어주는 컨테이너입니다.
|
|
64
|
+
*/
|
|
65
|
+
const OTPInputGroup = ({ className, children, }) => {
|
|
66
|
+
return (_jsx("div", { className: cn('flex items-center gap-2', className), children: children }));
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* OTPInputSlot
|
|
70
|
+
* 개별 글자를 보여주는 칸입니다.
|
|
71
|
+
*/
|
|
72
|
+
const OTPInputSlot = ({ index, className, }) => {
|
|
73
|
+
const { value, focusedIndex, isInvalid, variant, size, disabled } = useOTPInputContext();
|
|
74
|
+
const char = value[index];
|
|
75
|
+
const isActive = focusedIndex === index;
|
|
76
|
+
return (_jsxs("div", { className: cn('relative flex items-center justify-center font-bold transition-all rounded-[5px]', sizeClasses[size], variantClasses[variant], isActive && 'border-lb500 ring-2 ring-lb500/20', isActive && variant === 'filled' && 'bg-white', isActive && variant === 'ghost' && 'border-lb500', isInvalid && 'border-danger500 text-danger500 bg-tintRed', className), children: [char, isActive && !disabled && (_jsx("div", { className: "absolute inset-y-1/4 w-[2px] bg-lb500 animate-pulse" }))] }));
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* OTPInputSeparator
|
|
80
|
+
* 그룹 사이의 구분선입니다.
|
|
81
|
+
*/
|
|
82
|
+
const OTPInputSeparator = ({ className }) => {
|
|
83
|
+
return _jsx("div", { className: cn('w-2 h-[2px] bg-mono300 mx-1', className) });
|
|
84
|
+
};
|
|
85
|
+
// ── Export ──
|
|
86
|
+
export { OTPInput, OTPInputGroup, OTPInputSlot, OTPInputSeparator };
|
|
87
|
+
export default OTPInput;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
export interface PaginationProps {
|
|
3
|
+
currentPage: number;
|
|
4
|
+
totalPages: number;
|
|
5
|
+
onPageChange: (page: number) => void;
|
|
6
|
+
numbersToShow?: number;
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
}
|
|
10
|
+
declare const Pagination: ({ currentPage, totalPages, onPageChange, numbersToShow, className, style, }: PaginationProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default Pagination;
|
|
12
|
+
//# sourceMappingURL=Pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../../src/components/Pagination/Pagination.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,QAAA,MAAM,UAAU,GAAI,6EAOjB,eAAe,4CAYjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import PaginationBase from './PaginationBase.js';
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
const Pagination = ({ currentPage, totalPages, onPageChange, numbersToShow = 5, className, style, }) => (_jsx(PaginationBase.Provider, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange, children: _jsxs(PaginationBase.Root, { className: cn('py-5', className), style: style, children: [_jsx(PaginationBase.Prev, {}), _jsx(PaginationBase.List, { numbersToShow: numbersToShow }), _jsx(PaginationBase.Next, {})] }) }));
|
|
5
|
+
export default Pagination;
|