@loword/loword-design-system 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/LDAccordion/AccordionBase.d.ts +41 -0
- package/dist/components/LDAccordion/AccordionBase.d.ts.map +1 -0
- package/dist/components/LDAccordion/AccordionBase.js +24 -0
- package/dist/components/LDAccordion/LDAccordion.d.ts +31 -0
- package/dist/components/LDAccordion/LDAccordion.d.ts.map +1 -0
- package/dist/components/LDAccordion/LDAccordion.js +21 -0
- package/dist/components/LDAvatar/LDAvatar.d.ts +1 -1
- package/dist/components/LDAvatar/LDAvatar.d.ts.map +1 -1
- package/dist/components/LDAvatar/LDAvatar.js +19 -10
- package/dist/components/LDCalendar/CalendarBase.d.ts +17 -0
- package/dist/components/LDCalendar/CalendarBase.d.ts.map +1 -0
- package/dist/components/LDCalendar/CalendarBase.js +49 -0
- package/dist/components/LDCalendar/LDCalendar.d.ts +4 -11
- package/dist/components/LDCalendar/LDCalendar.d.ts.map +1 -1
- package/dist/components/LDCalendar/LDCalendar.js +9 -40
- package/dist/components/LDCarousel/CarouselBase.d.ts +3 -3
- package/dist/components/LDCarousel/CarouselBase.d.ts.map +1 -1
- package/dist/components/LDCarousel/CarouselBase.js +9 -7
- package/dist/components/LDCarousel/LDCarousel.d.ts +7 -8
- package/dist/components/LDCarousel/LDCarousel.d.ts.map +1 -1
- package/dist/components/LDCarousel/LDCarousel.js +2 -2
- package/dist/components/LDCheckbox/CheckboxBase.js +1 -1
- package/dist/components/LDCheckbox/LDCheckbox.d.ts +2 -5
- package/dist/components/LDCheckbox/LDCheckbox.d.ts.map +1 -1
- package/dist/components/LDCheckbox/LDCheckbox.js +65 -7
- package/dist/components/LDCheckbox/LDCheckboxGroup.d.ts +3 -3
- package/dist/components/LDCheckbox/LDCheckboxGroup.d.ts.map +1 -1
- package/dist/components/LDCheckbox/LDCheckboxGroup.js +11 -2
- package/dist/components/LDCheckbox/LDFormCheckbox.d.ts +1 -3
- package/dist/components/LDCheckbox/LDFormCheckbox.d.ts.map +1 -1
- package/dist/components/LDCheckbox/LDFormCheckbox.js +3 -4
- package/dist/components/LDCheckbox/LDFormCheckboxGroup.d.ts +1 -3
- package/dist/components/LDCheckbox/LDFormCheckboxGroup.d.ts.map +1 -1
- package/dist/components/LDCheckbox/LDFormCheckboxGroup.js +3 -4
- package/dist/components/LDDataCalendar/DataCalendarBase.d.ts +17 -1
- package/dist/components/LDDataCalendar/DataCalendarBase.d.ts.map +1 -1
- package/dist/components/LDDataCalendar/DataCalendarBase.js +34 -4
- package/dist/components/LDDataCalendar/LDDataCalendar.d.ts +27 -10
- package/dist/components/LDDataCalendar/LDDataCalendar.d.ts.map +1 -1
- package/dist/components/LDDataCalendar/LDDataCalendar.js +8 -8
- package/dist/components/LDDatePicker/LDDatePicker.d.ts.map +1 -1
- package/dist/components/LDDatePicker/LDDatePicker.js +1 -1
- package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts.map +1 -1
- package/dist/components/LDDateRangePicker/LDDateRangePicker.js +1 -1
- package/dist/components/LDDrawer/LDDrawer.d.ts +2 -0
- package/dist/components/LDDrawer/LDDrawer.d.ts.map +1 -1
- package/dist/components/LDDrawer/LDDrawer.js +1 -1
- package/dist/components/LDEditor/LDEditor.d.ts.map +1 -1
- package/dist/components/LDEditor/LDEditor.js +94 -54
- package/dist/components/LDEmpty/EmptyBase.d.ts +19 -0
- package/dist/components/LDEmpty/EmptyBase.d.ts.map +1 -0
- package/dist/components/LDEmpty/EmptyBase.js +18 -0
- package/dist/components/LDEmpty/LDEmpty.d.ts +35 -0
- package/dist/components/LDEmpty/LDEmpty.d.ts.map +1 -0
- package/dist/components/LDEmpty/LDEmpty.js +30 -0
- package/dist/components/LDFileUpload/FileUploadBase.d.ts.map +1 -1
- package/dist/components/LDFileUpload/FileUploadBase.js +6 -6
- package/dist/components/LDFileUpload/LDFileUpload.d.ts +3 -0
- package/dist/components/LDFileUpload/LDFileUpload.d.ts.map +1 -1
- package/dist/components/LDFileUpload/LDFileUpload.js +2 -4
- package/dist/components/LDFileUpload/LDFileUploadList.d.ts +3 -0
- package/dist/components/LDFileUpload/LDFileUploadList.d.ts.map +1 -1
- package/dist/components/LDFileUpload/LDFileUploadList.js +1 -3
- package/dist/components/LDFileUpload/LDImageUpload.d.ts +3 -0
- package/dist/components/LDFileUpload/LDImageUpload.d.ts.map +1 -1
- package/dist/components/LDFileUpload/LDImageUpload.js +2 -4
- package/dist/components/LDFileUpload/LDImageUploadList.d.ts +3 -0
- package/dist/components/LDFileUpload/LDImageUploadList.d.ts.map +1 -1
- package/dist/components/LDFileUpload/LDImageUploadList.js +1 -3
- package/dist/components/LDInput/InputBase.d.ts +5 -3
- package/dist/components/LDInput/InputBase.d.ts.map +1 -1
- package/dist/components/LDInput/InputBase.js +4 -4
- package/dist/components/LDInput/LDFormInput.d.ts.map +1 -1
- package/dist/components/LDInput/LDFormInput.js +7 -27
- package/dist/components/LDInput/LDInput.d.ts +8 -2
- package/dist/components/LDInput/LDInput.d.ts.map +1 -1
- package/dist/components/LDInput/LDInput.js +91 -28
- package/dist/components/LDLNB/LDLNB.d.ts +42 -0
- package/dist/components/LDLNB/LDLNB.d.ts.map +1 -0
- package/dist/components/LDLNB/LDLNB.js +34 -0
- package/dist/components/LDLNB/LDLNBBase.d.ts +5 -13
- package/dist/components/LDLNB/LDLNBBase.d.ts.map +1 -1
- package/dist/components/LDLNB/LDLNBBase.js +52 -18
- package/dist/components/LDMenuBar/LDMenuBar.d.ts +33 -19
- package/dist/components/LDMenuBar/LDMenuBar.d.ts.map +1 -1
- package/dist/components/LDMenuBar/LDMenuBar.js +13 -27
- package/dist/components/LDMenuBar/MenuBarBase.d.ts +4 -5
- package/dist/components/LDMenuBar/MenuBarBase.d.ts.map +1 -1
- package/dist/components/LDMenuBar/MenuBarBase.js +12 -14
- package/dist/components/LDModal/LDModal.d.ts +2 -1
- package/dist/components/LDModal/LDModal.d.ts.map +1 -1
- package/dist/components/LDModal/LDModal.js +1 -1
- package/dist/components/LDModal/LDModalView.d.ts +11 -3
- package/dist/components/LDModal/LDModalView.d.ts.map +1 -1
- package/dist/components/LDModal/LDModalView.js +4 -4
- package/dist/components/LDNotification/LDNotification.d.ts +40 -0
- package/dist/components/LDNotification/LDNotification.d.ts.map +1 -0
- package/dist/components/LDNotification/LDNotification.js +76 -0
- package/dist/components/LDNotification/NotificationBase.d.ts +29 -0
- package/dist/components/LDNotification/NotificationBase.d.ts.map +1 -0
- package/dist/components/LDNotification/NotificationBase.js +27 -0
- package/dist/components/LDOTPInput/LDFormOTPInput.d.ts +15 -0
- package/dist/components/LDOTPInput/LDFormOTPInput.d.ts.map +1 -0
- package/dist/components/LDOTPInput/LDFormOTPInput.js +8 -0
- package/dist/components/LDOTPInput/LDOTPInput.d.ts +10 -22
- package/dist/components/LDOTPInput/LDOTPInput.d.ts.map +1 -1
- package/dist/components/LDOTPInput/LDOTPInput.js +44 -73
- package/dist/components/LDOTPInput/OTPInputBase.d.ts +46 -0
- package/dist/components/LDOTPInput/OTPInputBase.d.ts.map +1 -0
- package/dist/components/LDOTPInput/OTPInputBase.js +48 -0
- package/dist/components/LDPagination/LDPagination.d.ts +1 -1
- package/dist/components/LDPagination/LDPagination.d.ts.map +1 -1
- package/dist/components/LDPagination/LDPagination.js +1 -8
- package/dist/components/LDPopover/LDPopover.d.ts +1 -1
- package/dist/components/LDPopover/LDPopover.d.ts.map +1 -1
- package/dist/components/LDPopover/LDPopover.js +5 -4
- package/dist/components/LDProgressBar/LDProgressBar.d.ts +16 -0
- package/dist/components/LDProgressBar/LDProgressBar.d.ts.map +1 -0
- package/dist/components/LDProgressBar/LDProgressBar.js +9 -0
- package/dist/components/LDProgressBar/ProgressBarBase.d.ts +11 -0
- package/dist/components/LDProgressBar/ProgressBarBase.d.ts.map +1 -0
- package/dist/components/LDProgressBar/ProgressBarBase.js +10 -0
- package/dist/components/LDRadio/LDFormRadioGroup.d.ts +1 -3
- package/dist/components/LDRadio/LDFormRadioGroup.d.ts.map +1 -1
- package/dist/components/LDRadio/LDFormRadioGroup.js +3 -4
- package/dist/components/LDRadio/LDRadio.d.ts +1 -1
- package/dist/components/LDRadio/LDRadio.d.ts.map +1 -1
- package/dist/components/LDRadio/LDRadio.js +58 -12
- package/dist/components/LDRadio/LDRadioGroup.d.ts +5 -3
- package/dist/components/LDRadio/LDRadioGroup.d.ts.map +1 -1
- package/dist/components/LDRadio/LDRadioGroup.js +11 -2
- package/dist/components/LDSectionNav/LDSectionNav.d.ts +11 -0
- package/dist/components/LDSectionNav/LDSectionNav.d.ts.map +1 -0
- package/dist/components/LDSectionNav/LDSectionNav.js +11 -0
- package/dist/components/LDSectionNav/SectionNavBase.d.ts +20 -0
- package/dist/components/LDSectionNav/SectionNavBase.d.ts.map +1 -0
- package/dist/components/LDSectionNav/SectionNavBase.js +53 -0
- package/dist/components/LDSelect/LDMultiSelect.js +3 -3
- package/dist/components/LDSelect/LDSelect.d.ts.map +1 -1
- package/dist/components/LDSelect/LDSelect.js +2 -2
- package/dist/components/LDTable/LDCollapsibleTanstackTable.d.ts.map +1 -1
- package/dist/components/LDTable/LDCollapsibleTanstackTable.js +12 -9
- package/dist/components/LDTable/LDTable.d.ts.map +1 -1
- package/dist/components/LDTable/LDTable.js +1 -1
- package/dist/components/LDTable/LDTanstackTable.d.ts.map +1 -1
- package/dist/components/LDTable/LDTanstackTable.js +5 -6
- package/dist/components/LDTable/TableField.d.ts.map +1 -1
- package/dist/components/LDTextarea/LDTextarea.js +1 -1
- package/dist/components/LDTimePicker/LDTimePicker.js +1 -1
- package/dist/components/LDToast/LDToaster.d.ts +2 -1
- package/dist/components/LDToast/LDToaster.d.ts.map +1 -1
- package/dist/components/LDToast/LDToaster.js +2 -2
- package/dist/components/LDToggleButton/LDFormToggleButton.d.ts +1 -3
- package/dist/components/LDToggleButton/LDFormToggleButton.d.ts.map +1 -1
- package/dist/components/LDToggleButton/LDFormToggleButton.js +3 -4
- package/dist/components/LDTooltip/LDTooltip.js +1 -1
- package/dist/components/LDTooltip/TooltipBase.d.ts +6 -2
- package/dist/components/LDTooltip/TooltipBase.d.ts.map +1 -1
- package/dist/components/LDTooltip/TooltipBase.js +4 -4
- package/dist/index.css +633 -166
- package/dist/index.d.ts +21 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -13
- package/package.json +14 -2
- package/src/styles/carousel.css +15 -14
- package/src/styles/components/editor.css +6 -0
- package/src/styles/components/input.css +14 -0
- package/src/styles/components/shared.css +6 -6
- package/src/styles/motion.css +78 -0
|
@@ -1,33 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import cn from '../../utils/cn.js';
|
|
4
4
|
import MenuBarBase from './MenuBarBase.js';
|
|
5
|
-
|
|
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 }));
|
|
5
|
+
const TRIGGER_CLASS = 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');
|
|
12
6
|
// item 모드: 항목 바로 아래 작은 드롭다운
|
|
13
|
-
const
|
|
14
|
-
// mega 모드: 헤더 전체 폭
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Logo,
|
|
25
|
-
Nav,
|
|
26
|
-
Item,
|
|
27
|
-
Trigger,
|
|
28
|
-
Content,
|
|
29
|
-
MegaContent,
|
|
30
|
-
Actions,
|
|
31
|
-
Separator,
|
|
7
|
+
const DROPDOWN_CLASS = 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');
|
|
8
|
+
// mega 모드: fixed로 부모 li(relative)를 벗어나 헤더 전체 폭 차지. top-16 = 헤더 높이 64px.
|
|
9
|
+
const MEGA_CLASS = cn('fixed left-0 right-0 top-16 z-50', 'p-lg bg-white border-b border-mono100 shadow-lg');
|
|
10
|
+
const MEGA_BACKDROP_CLASS = 'fixed left-0 right-0 top-16 bottom-0 z-40 bg-black/40';
|
|
11
|
+
/**
|
|
12
|
+
* 가로 헤더형 메뉴바. items로 네비게이션을 구성하고 logo/actions 슬롯에 임의 콘텐츠를 주입한다.
|
|
13
|
+
* item.content가 있으면 드롭다운, 없으면 단순 링크. item.mega면 헤더 전체 폭 패널로 열린다.
|
|
14
|
+
*/
|
|
15
|
+
const LDMenuBar = ({ items, trigger = 'hover', logo, actions, className, }) => {
|
|
16
|
+
return (_jsxs(MenuBarBase.Root, { trigger: trigger, 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), children: [logo && (_jsx(MenuBarBase.Logo, { className: "flex items-center shrink-0", children: logo })), _jsx(MenuBarBase.Nav, { className: "flex flex-1 items-center justify-start gap-xs", children: items.map((item) => (_jsxs(MenuBarBase.Item, { value: item.value, hasDropdown: !!item.content, children: [_jsx(MenuBarBase.Trigger, { as: item.content ? undefined : item.as, href: item.content ? undefined : item.href, className: TRIGGER_CLASS, children: item.label }), item.content &&
|
|
17
|
+
(item.mega ? (_jsx(MenuBarBase.Content, { backdrop: true, backdropClassName: MEGA_BACKDROP_CLASS, className: MEGA_CLASS, children: item.content })) : (_jsx(MenuBarBase.Content, { className: DROPDOWN_CLASS, children: item.content })))] }, item.value))) }), actions && (_jsx(MenuBarBase.Actions, { className: "flex items-center gap-sm shrink-0", children: actions }))] }));
|
|
32
18
|
};
|
|
33
19
|
export default LDMenuBar;
|
|
@@ -10,6 +10,8 @@ interface SlotProps {
|
|
|
10
10
|
}
|
|
11
11
|
interface ItemProps {
|
|
12
12
|
value: string;
|
|
13
|
+
/** 드롭다운(Content/MegaContent)을 가진 항목이면 true. 지정 시 hover/click으로 열리고 Trigger가 토글로 동작한다. 없으면 단순 링크. */
|
|
14
|
+
hasDropdown?: boolean;
|
|
13
15
|
children: ReactNode;
|
|
14
16
|
className?: string;
|
|
15
17
|
}
|
|
@@ -28,12 +30,9 @@ declare const MenuBarBase: {
|
|
|
28
30
|
Root: ({ children, className, trigger }: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
29
31
|
Logo: ({ children, className }: SlotProps) => import("react/jsx-runtime").JSX.Element;
|
|
30
32
|
Nav: ({ children, className }: SlotProps) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
-
Item: ({ value, children, className }: ItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
Item: ({ value, hasDropdown, children, className, }: ItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
32
34
|
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
|
-
};
|
|
35
|
+
Content: ({ children, className, backdrop, backdropClassName, }: ContentProps) => import("react/jsx-runtime").JSX.Element;
|
|
37
36
|
Actions: ({ children, className }: SlotProps) => import("react/jsx-runtime").JSX.Element;
|
|
38
37
|
Separator: ({ className }: {
|
|
39
38
|
className?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MenuBarBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDMenuBar/MenuBarBase.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MenuBarBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDMenuBar/MenuBarBase.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAwCpD,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,oGAAoG;IACpG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyBD,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;AAmCD,QAAA,MAAM,WAAW;6CA3JyC,SAAS;oCAwB5B,SAAS;mCAIV,SAAS;yDA0B5C,SAAS;0DA8BT,YAAY;qEA2CZ,YAAY;uCA/F2B,SAAS;+BAIjB;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;CAgIvD,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { createContext, useContext, useState } from 'react';
|
|
4
4
|
import cn from '../../utils/cn.js';
|
|
5
|
-
const CONTENT_NAME = 'MenuBarContent';
|
|
6
5
|
const MenuBarContext = createContext(null);
|
|
7
6
|
const useMenuBarContext = () => {
|
|
8
7
|
const ctx = useContext(MenuBarContext);
|
|
@@ -26,21 +25,18 @@ const Logo = ({ children, className }) => (_jsx("div", { className: className, c
|
|
|
26
25
|
const Nav = ({ children, className }) => (_jsx("ul", { className: className, children: children }));
|
|
27
26
|
const Actions = ({ children, className }) => (_jsx("div", { className: className, children: children }));
|
|
28
27
|
const Separator = ({ className }) => (_jsx("span", { "aria-hidden": true, className: className }));
|
|
29
|
-
const Item = ({ value, children, className }) => {
|
|
28
|
+
const Item = ({ value, hasDropdown = false, children, className, }) => {
|
|
30
29
|
const { trigger, setOpenValue } = useMenuBarContext();
|
|
31
|
-
|
|
32
|
-
const hasContent = Children.toArray(children).some((c) => isValidElement(c) &&
|
|
33
|
-
c.type?.displayName === CONTENT_NAME);
|
|
34
|
-
const hoverProps = trigger === 'hover' && hasContent
|
|
30
|
+
const hoverProps = trigger === 'hover' && hasDropdown
|
|
35
31
|
? { onMouseEnter: () => setOpenValue(value) }
|
|
36
32
|
: {};
|
|
37
|
-
return (_jsx(ItemContext, { value: { value,
|
|
33
|
+
return (_jsx(ItemContext, { value: { value, hasDropdown }, children: _jsx("li", { className: cn('relative', className), ...hoverProps, children: children }) }));
|
|
38
34
|
};
|
|
39
35
|
const Trigger = ({ as: Comp = 'button', children, className, ...rest }) => {
|
|
40
36
|
const { trigger, setOpenValue, isOpen } = useMenuBarContext();
|
|
41
|
-
const { value,
|
|
37
|
+
const { value, hasDropdown } = useItemContext();
|
|
42
38
|
// 드롭다운 없는 항목 → 순수 링크/버튼 (토글 안 함)
|
|
43
|
-
if (!
|
|
39
|
+
if (!hasDropdown) {
|
|
44
40
|
return (_jsx(Comp, { className: className, ...rest, children: children }));
|
|
45
41
|
}
|
|
46
42
|
const handleClick = trigger === 'click'
|
|
@@ -51,11 +47,13 @@ const Trigger = ({ as: Comp = 'button', children, className, ...rest }) => {
|
|
|
51
47
|
const Content = ({ children, className, backdrop, backdropClassName, }) => {
|
|
52
48
|
const { isOpen, setOpenValue } = useMenuBarContext();
|
|
53
49
|
const { value } = useItemContext();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
const open = isOpen(value);
|
|
51
|
+
// 항상 마운트해두고 data-open으로 opacity를 300ms 전환(열림 fade-in / 닫힘 fade-out).
|
|
52
|
+
// 닫힘 상태에선 inert로 클릭·포커스·스크린리더에서 제외한다 — 안 그러면 opacity:0인
|
|
53
|
+
// mega 딤이 화면 전체 클릭을 가로챈다.
|
|
54
|
+
const fade = 'ld-transition data-[open=false]:opacity-0';
|
|
55
|
+
return (_jsxs(_Fragment, { children: [backdrop && (_jsx("div", { "aria-hidden": true, "data-open": open, inert: !open, onClick: () => setOpenValue(null), className: cn(fade, backdropClassName) })), _jsx("div", { "data-open": open, inert: !open, className: cn(fade, className), children: children })] }));
|
|
57
56
|
};
|
|
58
|
-
Content.displayName = CONTENT_NAME;
|
|
59
57
|
const MenuBarBase = {
|
|
60
58
|
Root,
|
|
61
59
|
Logo,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ModalSize } from './LDModalView.js';
|
|
1
|
+
import { TModalClassNames, type ModalSize } from './LDModalView.js';
|
|
2
2
|
export interface LDModalOptions<T = undefined> {
|
|
3
3
|
name?: string;
|
|
4
4
|
title?: string;
|
|
@@ -24,6 +24,7 @@ export interface LDModalOptions<T = undefined> {
|
|
|
24
24
|
/** 모달 패널 인라인 스타일 (자유 width/height 등) */
|
|
25
25
|
style?: React.CSSProperties;
|
|
26
26
|
onBeforeClose?: () => Promise<boolean> | boolean;
|
|
27
|
+
classNames?: TModalClassNames;
|
|
27
28
|
}
|
|
28
29
|
declare const LDModal: <T = undefined>(options: LDModalOptions<T>) => Promise<T | undefined>;
|
|
29
30
|
export default LDModal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDModal.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModal.tsx"],"names":[],"mappings":"AAIA,OAAoB,
|
|
1
|
+
{"version":3,"file":"LDModal.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModal.tsx"],"names":[],"mappings":"AAIA,OAAoB,EAClB,gBAAgB,EAEhB,KAAK,SAAS,EACf,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,SAAS;IAC3C,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,+BAA+B;IAC/B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjD,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,QAAA,MAAM,OAAO,GAAI,CAAC,GAAG,SAAS,EAC5B,SAAS,cAAc,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,CAAC,GAAG,SAAS,CA2EvB,CAAC;AAEF,eAAe,OAAO,CAAC"}
|
|
@@ -50,7 +50,7 @@ const LDModal = (options) => {
|
|
|
50
50
|
return (_jsx(LDModalView, { open: open, onOpenChange: (next) => {
|
|
51
51
|
if (!next)
|
|
52
52
|
close(undefined);
|
|
53
|
-
}, name: options.name, title: options.title, description: options.description, size: options.size, icon: options.icon, scrollBehavior: options.scrollBehavior,
|
|
53
|
+
}, name: options.name, title: options.title, description: options.description, size: options.size, icon: options.icon, scrollBehavior: options.scrollBehavior, style: options.style, buttons: list ? { direction: options.buttonsDirection, list } : undefined, classNames: options.classNames, children: content }));
|
|
54
54
|
};
|
|
55
55
|
root.render(_jsx(ModalHost, {}));
|
|
56
56
|
});
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
export type ModalSize = 'small' | 'medium' | 'large' | 'xlarge';
|
|
3
|
+
export type TModalClassNames = {
|
|
4
|
+
overlay?: string;
|
|
5
|
+
content?: string;
|
|
6
|
+
layout?: string;
|
|
7
|
+
panel?: string;
|
|
8
|
+
close?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
};
|
|
3
12
|
export interface ModalButtons {
|
|
4
13
|
direction?: 'row' | 'column';
|
|
5
14
|
list?: ModalButton[];
|
|
@@ -39,13 +48,12 @@ export interface LDModalViewProps {
|
|
|
39
48
|
buttons?: ModalButtons;
|
|
40
49
|
/** 스크롤 동작 */
|
|
41
50
|
scrollBehavior?: 'inside' | 'outside';
|
|
42
|
-
/** 추가 CSS 클래스 (모달 패널에 적용) */
|
|
43
|
-
className?: string;
|
|
44
51
|
/** 인라인 스타일 (모달 패널에 적용) */
|
|
45
52
|
style?: React.CSSProperties;
|
|
46
53
|
/** 버튼 클릭 시 해당 버튼의 value를 전달하는 콜백 */
|
|
47
54
|
onButtonClick?: (value: unknown) => void;
|
|
55
|
+
classNames?: TModalClassNames;
|
|
48
56
|
}
|
|
49
|
-
declare const LDModalView: ({ open, defaultOpen, onOpenChange, name, title, description, children, size, icon, buttons, scrollBehavior,
|
|
57
|
+
declare const LDModalView: ({ open, defaultOpen, onOpenChange, name, title, description, children, size, icon, buttons, scrollBehavior, classNames, style, onButtonClick, }: LDModalViewProps) => import("react/jsx-runtime").JSX.Element;
|
|
50
58
|
export default LDModalView;
|
|
51
59
|
//# sourceMappingURL=LDModalView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDModalView.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModalView.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,gBAAgB;IAC/B,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,
|
|
1
|
+
{"version":3,"file":"LDModalView.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModalView.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,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,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,gBAAgB;IAC/B,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,0BAA0B;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AA6CD,QAAA,MAAM,WAAW,GAAI,iJAelB,gBAAgB,4CAmLlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -41,7 +41,7 @@ const statusIconSizeClasses = {
|
|
|
41
41
|
large: 'size-12.5',
|
|
42
42
|
xlarge: 'size-12.5',
|
|
43
43
|
};
|
|
44
|
-
const LDModalView = ({ open, defaultOpen, onOpenChange, name, title, description, children, size = 'small', icon, buttons, scrollBehavior = 'inside',
|
|
44
|
+
const LDModalView = ({ open, defaultOpen, onOpenChange, name, title, description, children, size = 'small', icon, buttons, scrollBehavior = 'inside', classNames, style, onButtonClick, }) => {
|
|
45
45
|
const overlayRef = useRef(false);
|
|
46
46
|
const hasHeader = name || title || description || icon;
|
|
47
47
|
const handleClick = async (button) => {
|
|
@@ -53,17 +53,17 @@ const LDModalView = ({ open, defaultOpen, onOpenChange, name, title, description
|
|
|
53
53
|
onButtonClick?.(button.value);
|
|
54
54
|
onOpenChange?.(false);
|
|
55
55
|
};
|
|
56
|
-
return (_jsxs(ModalBase.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, children: [_jsx(ModalBase.Overlay, {}), _jsx(ModalBase.Content, { className: cn({
|
|
56
|
+
return (_jsxs(ModalBase.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, children: [_jsx(ModalBase.Overlay, { className: classNames?.overlay }), _jsx(ModalBase.Content, { className: cn({
|
|
57
57
|
['top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2']: scrollBehavior === 'inside',
|
|
58
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) => {
|
|
59
|
+
}, classNames?.content), onMouseDown: (e) => (overlayRef.current = e.target === e.currentTarget), onClick: (e) => {
|
|
60
60
|
if (scrollBehavior === 'outside' &&
|
|
61
61
|
e.target === e.currentTarget &&
|
|
62
62
|
overlayRef.current)
|
|
63
63
|
onOpenChange?.(false);
|
|
64
64
|
overlayRef.current = false;
|
|
65
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]',
|
|
66
|
+
'flex flex-col overflow-y-auto max-h-[90dvh]', classNames?.layout), style: style, onClick: (e) => e.stopPropagation(), children: [_jsx(ModalBase.Close, { asChild: true, className: cn('absolute top-4 right-5 text-neutral500 cursor-pointer outline-hidden', classNames?.close), children: _jsx(LDButton, { variant: "ghost", color: "neutral", leftIcon: _jsx(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], classNames?.panel), 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(Check, { className: "text-white" }) })), icon === 'fail' && (_jsx("div", { className: cn('flex items-center justify-center rounded-full bg-danger600', statusIconSizeClasses[size]), children: _jsx(CircleAlert, { className: "text-white" }) })), name && (_jsx("span", { className: "display16 bold text-neutral500 whitespace-pre-wrap", children: name })), title && (_jsx(ModalBase.Title, { className: cn('display28 bold whitespace-pre-wrap text-center', classNames?.title), children: title })), description && (_jsx(ModalBase.Description, { className: cn('display14 text-neutral500 whitespace-pre-wrap text-center', classNames?.description), children: description }))] })), children && (_jsx("div", { className: cn(scrollBehavior === 'inside' &&
|
|
67
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
68
|
const isFirst = index === 0;
|
|
69
69
|
return (_jsx("div", { className: "flex flex-1 w-full", children: _jsx(LDButton, { 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)));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from 'react';
|
|
2
|
+
import { type NotificationType } from './NotificationBase.js';
|
|
3
|
+
export type NotificationSize = 'small' | 'medium' | 'large';
|
|
4
|
+
export interface LDNotificationProps {
|
|
5
|
+
/** 트리거로 사용할 노드 — 벨 아이콘, 아바타 등 임의의 ReactNode */
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
/** 배지 표시 방식 — 'dot'이면 점만, 'count'면 숫자로 표시 (기본값 'count') */
|
|
8
|
+
type?: NotificationType;
|
|
9
|
+
/** type='dot'일 때 점을 보여줄지 여부 (기본값 false). type='count'일 땐 사용되지 않음 */
|
|
10
|
+
dot?: boolean;
|
|
11
|
+
/** type='count'일 때 표시할 알림 개수 (기본값 0) */
|
|
12
|
+
count?: number;
|
|
13
|
+
/** type='count'일 때, count가 이 값을 초과하면 `${overflowCount}+`로 표시 (기본값 99) */
|
|
14
|
+
overflowCount?: number;
|
|
15
|
+
/** type='count'일 때, count가 0이어도 배지를 표시할지 여부 (기본값 false) */
|
|
16
|
+
showZero?: boolean;
|
|
17
|
+
/** 기본 위치(우측 상단 모서리)에서 [x, y]만큼 px 이동. x는 오른쪽, y는 아래쪽이 + 방향 */
|
|
18
|
+
offset?: [number, number];
|
|
19
|
+
/** 배지 크기 — 'small' | 'medium' | 'large' (기본값 'medium') */
|
|
20
|
+
size?: NotificationSize;
|
|
21
|
+
/** 트리거와 배지를 함께 감싸는 Root wrapper에 적용할 className */
|
|
22
|
+
className?: string;
|
|
23
|
+
/** 배지(Indicator) 자체에 적용할 className — 색상 등 기본 스타일을 덮어쓸 때 사용 */
|
|
24
|
+
indicatorClassName?: string;
|
|
25
|
+
/**
|
|
26
|
+
* count가 증가하는 순간 트리거(children) wrapper에 잠깐 추가되는 className.
|
|
27
|
+
* 예: `"animate-bell"` — 새 알림이 왔을 때 트리거를 흔드는 등 강조 효과를 주고 싶을 때 사용
|
|
28
|
+
*/
|
|
29
|
+
triggerHighlightClassName?: string;
|
|
30
|
+
/**
|
|
31
|
+
* count가 증가하는 순간 배지(Indicator)에 추가되는 className.
|
|
32
|
+
* 예: `"animate-bounce"`
|
|
33
|
+
*/
|
|
34
|
+
indicatorHighlightClassName?: string;
|
|
35
|
+
/** Root wrapper에 적용할 인라인 스타일 */
|
|
36
|
+
style?: CSSProperties;
|
|
37
|
+
}
|
|
38
|
+
declare const LDNotification: ({ children, type, dot, count, overflowCount, showZero, offset, size, className, indicatorClassName, triggerHighlightClassName, indicatorHighlightClassName, style, }: LDNotificationProps) => import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export default LDNotification;
|
|
40
|
+
//# sourceMappingURL=LDNotification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDNotification.d.ts","sourceRoot":"","sources":["../../../src/components/LDNotification/LDNotification.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAyB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE7E,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,QAAQ,EAAE,SAAS,CAAC;IACpB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,oEAAoE;IACpE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,0DAA0D;IAC1D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC;;;OAGG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,gCAAgC;IAChC,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAiID,QAAA,MAAM,cAAc,GAAI,sKAcrB,mBAAmB,4CA4BrB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useLayoutEffect, useRef, useState, } from 'react';
|
|
4
|
+
import cn from '../../utils/cn.js';
|
|
5
|
+
import NotificationBase from './NotificationBase.js';
|
|
6
|
+
// dot 자체 지름(px) — count 박스와 무관한, 훨씬 작은 순수 점 표시용 크기
|
|
7
|
+
const DOT_SIZE_PX = {
|
|
8
|
+
small: 4,
|
|
9
|
+
medium: 6,
|
|
10
|
+
large: 8,
|
|
11
|
+
};
|
|
12
|
+
// count 박스 높이(px). Tailwind h-3.5/h-4/h-5과 동일한 값
|
|
13
|
+
const COUNT_HEIGHT_PX = {
|
|
14
|
+
small: 14,
|
|
15
|
+
medium: 16,
|
|
16
|
+
large: 20,
|
|
17
|
+
};
|
|
18
|
+
// 좌우 패딩(px, 한쪽 기준). Tailwind px-3xs/px-2xs와 동일한 값
|
|
19
|
+
const SIZE_PADDING_X_PX = {
|
|
20
|
+
small: 2,
|
|
21
|
+
medium: 4,
|
|
22
|
+
large: 4,
|
|
23
|
+
};
|
|
24
|
+
const SIZE_CLASSES = {
|
|
25
|
+
small: 'px-3xs display10 bold',
|
|
26
|
+
medium: 'px-2xs display10 bold',
|
|
27
|
+
large: 'px-2xs display12 bold',
|
|
28
|
+
};
|
|
29
|
+
// 표시값 얼리기·텍스트 폭 측정 state를 Indicator 전용으로 분리 — 이 값들이 바뀌어도
|
|
30
|
+
// 트리거 wrapper/Root는 리렌더되지 않고 이 컴포넌트만 리렌더된다.
|
|
31
|
+
const IndicatorContent = ({ type, dot, count, overflowCount, showZero, size, offset, isHighlight, indicatorClassName, indicatorHighlightClassName, }) => {
|
|
32
|
+
const isDot = type === 'dot';
|
|
33
|
+
const isShown = isDot ? dot : count > 0 || (count === 0 && showZero);
|
|
34
|
+
const isOverflow = !isDot && count > overflowCount;
|
|
35
|
+
const liveDisplay = isOverflow ? `${overflowCount}+` : count;
|
|
36
|
+
const [frozenDisplay, setFrozenDisplay] = useState(liveDisplay);
|
|
37
|
+
const textRef = useRef(null);
|
|
38
|
+
const [textWidth, setTextWidth] = useState(0);
|
|
39
|
+
// count가 실제로 보이는 중일 때만 표시값을 갱신하고, dot이거나 숨겨지는 중엔 마지막
|
|
40
|
+
// 표시값을 그대로 얼려둔다 — count→dot 전환 시 "99+"가 raw count로 풀리거나,
|
|
41
|
+
// showZero=false에서 count가 0으로 바뀌며 사라질 때 "0"으로 스냅되는 걸 막는다.
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!isDot && isShown) {
|
|
44
|
+
setFrozenDisplay(liveDisplay);
|
|
45
|
+
}
|
|
46
|
+
}, [isDot, isShown, liveDisplay]);
|
|
47
|
+
// count일 때 너비는 실제 텍스트 너비를 측정해 결정한다 — Tailwind 정적 클래스로는
|
|
48
|
+
// count의 실제 내용 너비만큼 부드럽게 트랜지션하기 어렵기 때문
|
|
49
|
+
useLayoutEffect(() => {
|
|
50
|
+
if (isDot)
|
|
51
|
+
return;
|
|
52
|
+
const el = textRef.current;
|
|
53
|
+
if (el)
|
|
54
|
+
setTextWidth(el.scrollWidth);
|
|
55
|
+
}, [frozenDisplay, isDot, size]);
|
|
56
|
+
const heightPx = isDot ? DOT_SIZE_PX[size] : COUNT_HEIGHT_PX[size];
|
|
57
|
+
const widthPx = isDot
|
|
58
|
+
? DOT_SIZE_PX[size]
|
|
59
|
+
: Math.max(COUNT_HEIGHT_PX[size], textWidth + SIZE_PADDING_X_PX[size] * 2);
|
|
60
|
+
const scale = isShown ? 1 : 0;
|
|
61
|
+
const indicatorTransform = [
|
|
62
|
+
offset && `translate(${offset[0]}px, ${offset[1]}px)`,
|
|
63
|
+
`scale(${scale})`,
|
|
64
|
+
]
|
|
65
|
+
.filter(Boolean)
|
|
66
|
+
.join(' ');
|
|
67
|
+
return (_jsx(NotificationBase.Indicator, { count: count, type: type, isShown: isShown, className: cn('absolute top-0 right-0 ld-transition rounded-full bg-danger600 text-white flex items-center justify-center leading-none', SIZE_CLASSES[size], isDot && 'px-0', isShown ? 'opacity-100' : 'opacity-0', indicatorClassName, isHighlight && indicatorHighlightClassName), style: {
|
|
68
|
+
transform: indicatorTransform,
|
|
69
|
+
width: widthPx,
|
|
70
|
+
height: heightPx,
|
|
71
|
+
}, children: _jsx("span", { ref: textRef, className: cn('ld-transition', isDot ? 'scale-0 opacity-0' : 'scale-100 opacity-100'), children: frozenDisplay }) }));
|
|
72
|
+
};
|
|
73
|
+
const LDNotification = ({ children, type = 'count', dot = false, count = 0, overflowCount = 99, showZero = false, offset, size = 'medium', className, indicatorClassName, triggerHighlightClassName, indicatorHighlightClassName, style, }) => {
|
|
74
|
+
return (_jsx(NotificationBase.Root, { className: cn('relative inline-block', className), style: style, count: count, children: (isHighlight) => (_jsxs(_Fragment, { children: [_jsx("div", { className: cn(isHighlight && triggerHighlightClassName), children: children }), _jsx(IndicatorContent, { type: type, dot: dot, count: count, overflowCount: overflowCount, showZero: showZero, size: size, offset: offset, isHighlight: isHighlight, indicatorClassName: indicatorClassName, indicatorHighlightClassName: indicatorHighlightClassName })] })) }));
|
|
75
|
+
};
|
|
76
|
+
export default LDNotification;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type CSSProperties, type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
interface RootProps {
|
|
3
|
+
/**
|
|
4
|
+
* count가 증가하는 순간 true가 되는 isHighlight 값을 받는 render-prop.
|
|
5
|
+
* 어디에(트리거·인디케이터) 어떤 className을 적용할지는 전부 Custom이 결정한다.
|
|
6
|
+
*/
|
|
7
|
+
children?: (isHighlight: boolean) => ReactNode;
|
|
8
|
+
/** 증가 감지 대상 알림 개수 (기본값 0). 이 값이 이전보다 커지면 isHighlight가 true가 된다 */
|
|
9
|
+
count?: number;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: CSSProperties;
|
|
12
|
+
}
|
|
13
|
+
export type NotificationType = 'dot' | 'count';
|
|
14
|
+
interface IndicatorProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
15
|
+
/** aria-label 문구에 쓰일 알림 개수 (기본값 0) */
|
|
16
|
+
count?: number;
|
|
17
|
+
/** 'dot'이면 aria-label을 "새 알림 있음"으로, 그 외엔 "알림 N개" 문구로 표시 */
|
|
18
|
+
type?: NotificationType;
|
|
19
|
+
/** 배지가 실제로 표시 중인지 여부 — false면 aria-hidden 처리(기본값 true) */
|
|
20
|
+
isShown?: boolean;
|
|
21
|
+
/** 렌더링할 내용(포맷된 count 등). 스타일은 Custom이 결정 */
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export declare const NotificationBase: {
|
|
25
|
+
Root: ({ children, count, className, style }: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
Indicator: ({ count, type, isShown, children, ...props }: IndicatorProps) => import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
};
|
|
28
|
+
export default NotificationBase;
|
|
29
|
+
//# sourceMappingURL=NotificationBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDNotification/NotificationBase.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,UAAU,SAAS;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,SAAS,CAAC;IAC/C,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AA+BD,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,OAAO,CAAC;AAE/C,UAAU,cAAe,SAAQ,IAAI,CACnC,cAAc,CAAC,cAAc,CAAC,EAC9B,UAAU,CACX;IACC,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAsBD,eAAO,MAAM,gBAAgB;kDAjE4B,SAAS;8DAmD/D,cAAc;CAiBhB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState, } from 'react';
|
|
4
|
+
const Root = ({ children, count = 0, className, style }) => {
|
|
5
|
+
const [isHighlight, setIsHighlight] = useState(false);
|
|
6
|
+
const prevCountRef = useRef(count);
|
|
7
|
+
const handleAnimationEnd = () => {
|
|
8
|
+
setIsHighlight(false);
|
|
9
|
+
};
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const prevCount = prevCountRef.current;
|
|
12
|
+
if (count > prevCount) {
|
|
13
|
+
setIsHighlight(true);
|
|
14
|
+
}
|
|
15
|
+
prevCountRef.current = count;
|
|
16
|
+
}, [count]);
|
|
17
|
+
return (_jsx("div", { className: className, style: style, onAnimationEnd: handleAnimationEnd, children: children?.(isHighlight) }));
|
|
18
|
+
};
|
|
19
|
+
const Indicator = ({ count = 0, type = 'count', isShown = true, children, ...props }) => {
|
|
20
|
+
const isDot = type === 'dot';
|
|
21
|
+
return (_jsx("div", { role: "status", "aria-label": isDot ? '새 알림 있음' : `알림 ${count}개`, "aria-hidden": !isShown, ...props, children: children }));
|
|
22
|
+
};
|
|
23
|
+
export const NotificationBase = {
|
|
24
|
+
Root,
|
|
25
|
+
Indicator,
|
|
26
|
+
};
|
|
27
|
+
export default NotificationBase;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import { type RegisterOptions } from 'react-hook-form';
|
|
3
|
+
import { type LDOTPInputProps } from './LDOTPInput.js';
|
|
4
|
+
interface LDFormOTPInputProps extends Omit<LDOTPInputProps, 'value' | 'onChange' | 'isInvalid'> {
|
|
5
|
+
/** react-hook-form 필드 이름 */
|
|
6
|
+
name: string;
|
|
7
|
+
/** react-hook-form 유효성 규칙 */
|
|
8
|
+
options?: RegisterOptions;
|
|
9
|
+
ref?: Ref<HTMLInputElement>;
|
|
10
|
+
/** 커스텀 에러 메시지 (지정 시 RHF 메시지 대신 사용) */
|
|
11
|
+
customErrorMessage?: string;
|
|
12
|
+
}
|
|
13
|
+
declare const LDFormOTPInput: ({ name, options, variant, size, disabled, ref, customErrorMessage, children, ...props }: LDFormOTPInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default LDFormOTPInput;
|
|
15
|
+
//# sourceMappingURL=LDFormOTPInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDFormOTPInput.d.ts","sourceRoot":"","sources":["../../../src/components/LDOTPInput/LDFormOTPInput.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAGhE,UAAU,mBAAoB,SAAQ,IAAI,CACxC,eAAe,EACf,OAAO,GAAG,UAAU,GAAG,WAAW,CACnC;IACC,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC5B,sCAAsC;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,QAAA,MAAM,cAAc,GAAI,yFAUrB,mBAAmB,4CAwBrB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import LDOTPInput from './LDOTPInput.js';
|
|
4
|
+
import LDFormField from '../LDForm/LDFormField.js';
|
|
5
|
+
const LDFormOTPInput = ({ name, options, variant = 'outline', size = 'medium', disabled = false, ref, customErrorMessage = '', children, ...props }) => {
|
|
6
|
+
return (_jsx(LDFormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, ref: ref, children: ({ field, fieldState }) => (_jsx(LDOTPInput, { ...props, value: field.value ?? '', onChange: field.onChange, isInvalid: fieldState.hasError, variant: variant, size: size, disabled: disabled, children: children })) }));
|
|
7
|
+
};
|
|
8
|
+
export default LDFormOTPInput;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
export type OTPInputSize = '
|
|
3
|
-
export type OTPInputVariant = 'filled' | 'outline'
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export type OTPInputSize = '2xsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
|
|
3
|
+
export type OTPInputVariant = 'filled' | 'outline';
|
|
4
4
|
export interface LDOTPInputProps {
|
|
5
5
|
maxLength: number;
|
|
6
6
|
value: string;
|
|
@@ -10,34 +10,22 @@ export interface LDOTPInputProps {
|
|
|
10
10
|
isInvalid?: boolean;
|
|
11
11
|
variant?: OTPInputVariant;
|
|
12
12
|
size?: OTPInputSize;
|
|
13
|
+
/** 그룹별 칸 수(예: [3, 3]). 지정 시 구분선으로 나눠 렌더한다. 합은 maxLength와 일치해야 함. */
|
|
14
|
+
groups?: number[];
|
|
13
15
|
className?: string;
|
|
14
|
-
|
|
16
|
+
/** 커스텀 레이아웃. 생략 시 groups/maxLength로 슬롯을 자동 생성한다. */
|
|
17
|
+
children?: ReactNode;
|
|
15
18
|
}
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
* 실제 입력을 처리하는 Hidden LDInput과 상태를 관리합니다.
|
|
19
|
-
*/
|
|
20
|
-
declare const LDOTPInput: ({ maxLength, value, onChange, onComplete, disabled, isInvalid, variant, size, className, children, }: LDOTPInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
-
/**
|
|
22
|
-
* OTPInputGroup
|
|
23
|
-
* 슬롯들을 묶어주는 컨테이너입니다.
|
|
24
|
-
*/
|
|
19
|
+
/** OTP 입력 루트 — Base.Root에 size/variant 스타일 컨텍스트를 덧씌운다. */
|
|
20
|
+
declare const LDOTPInput: ({ variant, size, maxLength, groups, children, ...rest }: LDOTPInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
25
21
|
declare const OTPInputGroup: ({ className, children, }: {
|
|
26
22
|
className?: string;
|
|
27
|
-
children:
|
|
23
|
+
children: ReactNode;
|
|
28
24
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
29
|
-
/**
|
|
30
|
-
* OTPInputSlot
|
|
31
|
-
* 개별 글자를 보여주는 칸입니다.
|
|
32
|
-
*/
|
|
33
25
|
declare const OTPInputSlot: ({ index, className, }: {
|
|
34
26
|
index: number;
|
|
35
27
|
className?: string;
|
|
36
28
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
37
|
-
/**
|
|
38
|
-
* OTPInputSeparator
|
|
39
|
-
* 그룹 사이의 구분선입니다.
|
|
40
|
-
*/
|
|
41
29
|
declare const OTPInputSeparator: ({ className }: {
|
|
42
30
|
className?: string;
|
|
43
31
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDOTPInput.d.ts","sourceRoot":"","sources":["../../../src/components/LDOTPInput/LDOTPInput.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"LDOTPInput.d.ts","sourceRoot":"","sources":["../../../src/components/LDOTPInput/LDOTPInput.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAuC,MAAM,OAAO,CAAC;AAK5E,MAAM,MAAM,YAAY,GACpB,SAAS,GACT,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,QAAQ,CAAC;AACb,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,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,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAwCD,0DAA0D;AAC1D,QAAA,MAAM,UAAU,GAAI,yDAOjB,eAAe,4CAqCjB,CAAC;AAEF,QAAA,MAAM,aAAa,GAAI,0BAGpB;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,4CAA8E,CAAC;AAEhF,QAAA,MAAM,YAAY,GAAI,uBAGnB;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,4CAuBA,CAAC;AAEF,QAAA,MAAM,iBAAiB,GAAI,eAAe;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,4CAI/D,CAAC;AAGF,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC;AACtE,eAAe,UAAU,CAAC"}
|