@wishket/design-system 2.2.1 → 3.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 +58 -0
- package/dist/Components/Base/Layouts/Box/Box.d.ts +5 -5
- package/dist/Components/Base/Layouts/Box/Box.js +3 -2
- package/dist/Components/Base/Typography/Typography.d.ts +6 -1
- package/dist/Components/Base/Typography/Typography.js +4 -3
- package/dist/Components/Base/Typography/Typography.types.d.ts +4 -5
- package/dist/Components/DataDisplays/ImageLabel/ImageLabel.js +1 -1
- package/dist/Components/Feedbacks/Tooltip/Tooltip.js +3 -3
- package/dist/Components/Inputs/CheckboxCard/CheckboxCard.parts.js +1 -1
- package/dist/Components/Inputs/IconButtonDropdown/IconButtonDropdown.js +1 -1
- package/dist/Components/Inputs/RadioCard/RadioCard.parts.js +1 -1
- package/dist/Components/Inputs/TextFieldDropdown/TextFieldDropdown.js +2 -2
- package/dist/Components/Navigations/GNBList/GNBList.d.ts +1 -1
- package/dist/Components/Navigations/GNBList/GNBList.parts.d.ts +3 -2
- package/dist/Components/Navigations/GNBList/GNBList.parts.js +10 -10
- package/dist/Components/Navigations/GNBList/GNBList.types.d.ts +8 -3
- package/dist/Components/Navigations/Menu/Menu.types.d.ts +53 -0
- package/dist/Components/Navigations/Menu/MenuBase.d.ts +21 -0
- package/dist/Components/Navigations/Menu/MenuBase.js +3 -0
- package/dist/Components/Navigations/Menu/MenuButton.d.ts +40 -0
- package/dist/Components/Navigations/Menu/MenuButton.js +39 -0
- package/dist/Components/Navigations/Menu/MenuLink.d.ts +43 -0
- package/dist/Components/Navigations/Menu/MenuLink.js +42 -0
- package/dist/Components/Navigations/Menu/index.d.ts +3 -1
- package/dist/Components/Navigations/TextLink/TextLink.d.ts +13 -35
- package/dist/Components/Navigations/TextLink/TextLink.js +11 -34
- package/dist/Components/Utils/BackDrop/BackDrop.js +1 -1
- package/dist/Components/Utils/BottomModalContainer/BottomModalContainer.js +2 -2
- package/dist/Components/Utils/FullModalContainer/FullModalContainer.js +1 -1
- package/dist/Components/Utils/Modal/Modal.js +2 -2
- package/dist/Components/Utils/ModalContainer/ModalContainer.js +2 -2
- package/dist/Components/Wrappers/WithBadge/WithBadge.js +1 -1
- package/dist/Components/Wrappers/WithSnackBar/WithSnackBar.js +1 -1
- package/dist/cjs/Components/Base/Layouts/Box/Box.js +3 -2
- package/dist/cjs/Components/Base/Typography/Typography.js +4 -3
- package/dist/cjs/Components/DataDisplays/ImageLabel/ImageLabel.js +1 -1
- package/dist/cjs/Components/Feedbacks/Tooltip/Tooltip.js +3 -3
- package/dist/cjs/Components/Inputs/CheckboxCard/CheckboxCard.parts.js +1 -1
- package/dist/cjs/Components/Inputs/IconButtonDropdown/IconButtonDropdown.js +1 -1
- package/dist/cjs/Components/Inputs/RadioCard/RadioCard.parts.js +1 -1
- package/dist/cjs/Components/Inputs/TextFieldDropdown/TextFieldDropdown.js +2 -2
- package/dist/cjs/Components/Navigations/GNBList/GNBList.parts.js +11 -11
- package/dist/cjs/Components/Navigations/Menu/MenuBase.js +3 -0
- package/dist/cjs/Components/Navigations/Menu/MenuButton.js +39 -0
- package/dist/cjs/Components/Navigations/Menu/MenuLink.js +42 -0
- package/dist/cjs/Components/Navigations/TextLink/TextLink.js +11 -34
- package/dist/cjs/Components/Utils/BackDrop/BackDrop.js +1 -1
- package/dist/cjs/Components/Utils/BottomModalContainer/BottomModalContainer.js +3 -3
- package/dist/cjs/Components/Utils/FullModalContainer/FullModalContainer.js +1 -1
- package/dist/cjs/Components/Utils/Modal/Modal.js +2 -2
- package/dist/cjs/Components/Utils/ModalContainer/ModalContainer.js +2 -2
- package/dist/cjs/Components/Wrappers/WithBadge/WithBadge.js +1 -1
- package/dist/cjs/Components/Wrappers/WithSnackBar/WithSnackBar.js +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -5
- package/scripts/codemods/README.md +178 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/already-has-as.input.tsx +6 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/already-has-as.output.tsx +6 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/basic.input.tsx +9 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/basic.output.tsx +10 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/existing-next-link-import.input.tsx +9 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/existing-next-link-import.output.tsx +9 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/menu-button-fallback.input.tsx +5 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/menu-button-fallback.output.tsx +5 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/unrelated-import.input.tsx +3 -0
- package/scripts/codemods/__tests__/__fixtures__/add-as-link/unrelated-import.output.tsx +3 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/basic.input.tsx +8 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/basic.output.tsx +8 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/conflict.input.tsx +5 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/conflict.output.tsx +6 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/href-only.input.tsx +3 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/href-only.output.tsx +3 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/onclick-only.input.tsx +3 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/onclick-only.output.tsx +3 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/spread-props.input.tsx +3 -0
- package/scripts/codemods/__tests__/__fixtures__/menu-split/spread-props.output.tsx +4 -0
- package/scripts/codemods/__tests__/run-fixtures.cjs +100 -0
- package/scripts/codemods/add-as-link.ts +110 -0
- package/scripts/codemods/menu-split.ts +252 -0
- package/dist/Components/Navigations/Menu/Menu.d.ts +0 -81
- package/dist/Components/Navigations/Menu/Menu.js +0 -62
- package/dist/cjs/Components/Navigations/Menu/Menu.js +0 -2
package/README.md
CHANGED
|
@@ -82,6 +82,64 @@ export const Home = () => {
|
|
|
82
82
|
export default Home;
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
## Navigation 컴포넌트와 라우팅 라이브러리
|
|
86
|
+
|
|
87
|
+
`TextLink`, `Menu`, `GNBList.Item`은 기본적으로 `<a>` 태그로 렌더되며, `as` prop으로 라우팅 라이브러리의 Link를 주입할 수 있습니다.
|
|
88
|
+
|
|
89
|
+
### Next.js와 함께 사용
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import Link from 'next/link';
|
|
93
|
+
import { TextLink, Menu, GNBList } from '@wishket/design-system';
|
|
94
|
+
|
|
95
|
+
<TextLink as={Link} href="/about" text="About" />
|
|
96
|
+
<Menu as={Link} name="Settings" href="/settings" />
|
|
97
|
+
<GNBList.Item as={Link} href="/projects">프로젝트</GNBList.Item>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
매 호출마다 `as`를 적기 번거롭다면 컨슈머 앱에서 wrapper를 한 번만 정의해두는 패턴을 권장합니다.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
// app/components/AppTextLink.tsx
|
|
104
|
+
import { ComponentProps } from 'react';
|
|
105
|
+
import Link from 'next/link';
|
|
106
|
+
import { TextLink } from '@wishket/design-system';
|
|
107
|
+
|
|
108
|
+
export const AppTextLink = (props: ComponentProps<typeof TextLink>) => (
|
|
109
|
+
<TextLink as={Link} {...props} />
|
|
110
|
+
);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### react-router와 함께 사용
|
|
114
|
+
|
|
115
|
+
`react-router`의 `Link`는 `to` prop을 쓰므로 `href` → `to` 어댑터가 필요합니다.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import { Link as RouterLink } from 'react-router-dom';
|
|
119
|
+
|
|
120
|
+
const RouterLinkAdapter = ({
|
|
121
|
+
href,
|
|
122
|
+
...rest
|
|
123
|
+
}: { href: string } & React.ComponentProps<typeof RouterLink>) => (
|
|
124
|
+
<RouterLink to={href} {...rest} />
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
<TextLink as={RouterLinkAdapter} href="/about" text="About" />
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### v3 마이그레이션
|
|
131
|
+
|
|
132
|
+
v3.0부터 위 컴포넌트들이 더 이상 자동으로 `next/link`를 사용하지 않습니다. 컨슈머 앱에서 일괄 변환을 원한다면 패키지에 포함된 jscodeshift codemod를 사용하세요.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npx jscodeshift \
|
|
136
|
+
-t node_modules/@wishket/design-system/scripts/codemods/add-as-link.ts \
|
|
137
|
+
--extensions=tsx,ts --parser=tsx \
|
|
138
|
+
src/
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
자세한 내용은 [`scripts/codemods/README.md`](./scripts/codemods/README.md)를 참고하세요.
|
|
142
|
+
|
|
85
143
|
## Customize Theme in Config File
|
|
86
144
|
|
|
87
145
|
```typescript
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
as?:
|
|
4
|
-
}
|
|
1
|
+
import { ComponentPropsWithRef, ElementType, PropsWithChildren } from 'react';
|
|
2
|
+
export type BoxProps<T extends ElementType = 'div'> = {
|
|
3
|
+
as?: T;
|
|
4
|
+
} & PropsWithChildren<Omit<ComponentPropsWithRef<T>, 'as'>>;
|
|
5
5
|
/**
|
|
6
6
|
* @param {Object} props
|
|
7
7
|
* @param {ReactNode} props.children - 박스 내부에 렌더링할 컨텐츠
|
|
8
8
|
* @param {ElementType} [props.as='div'] - 렌더링할 HTML 요소
|
|
9
9
|
* @param {string} [props.className] - 추가적인 CSS 클래스
|
|
10
10
|
*/
|
|
11
|
-
declare const Box: import("react").ForwardRefExoticComponent<BoxProps & import("react").RefAttributes<
|
|
11
|
+
declare const Box: import("react").ForwardRefExoticComponent<Omit<BoxProps<ElementType>, "ref"> & import("react").RefAttributes<any>>;
|
|
12
12
|
export { Box };
|
|
@@ -4,5 +4,6 @@ import{jsx as e}from"react/jsx-runtime";import{twMerge as r}from"tailwind-merge"
|
|
|
4
4
|
* @param {ReactNode} props.children - 박스 내부에 렌더링할 컨텐츠
|
|
5
5
|
* @param {ElementType} [props.as='div'] - 렌더링할 HTML 요소
|
|
6
6
|
* @param {string} [props.className] - 추가적인 CSS 클래스
|
|
7
|
-
*/(e,r);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)t=c[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}const i=/*#__PURE__*/t(((t
|
|
8
|
-
|
|
7
|
+
*/(e,r);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)t=c[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}const i=/*#__PURE__*/t(((t,// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
+
i)=>{var{as:l,className:a,children:u}=t,b=c(t,["as","className","children"]);/*#__PURE__*/
|
|
9
|
+
return e(null!=l?l:"div",o(function(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{},o=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(t).filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})))),o.forEach((function(r){n(e,r,t[r])}))}return e}({ref:i,className:r("box-border",a)},b),{children:u}))}));i.displayName="Box";export{i as Box};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ElementType, ReactElement } from 'react';
|
|
1
2
|
import { TypographyProps } from './Typography.types';
|
|
3
|
+
type PolymorphicRef<T extends ElementType> = ComponentPropsWithRef<T>['ref'];
|
|
2
4
|
/**
|
|
3
5
|
* Typography
|
|
4
6
|
* @param {Object} props
|
|
@@ -6,6 +8,9 @@ import { TypographyProps } from './Typography.types';
|
|
|
6
8
|
* @param {string} props.variant - 텍스트 스타일 variant ('title48' | 'title32' | 'title24' | 'subTitle20' | 'subTitle18' | 'contents18' | 'contents16' | 'body16' | 'body14' | 'body13' | 'caption12' | 'caption11')
|
|
7
9
|
* @param {string} [props.className] - 추가적인 CSS 클래스
|
|
8
10
|
* @param {keyof JSX.IntrinsicElements} [props.as='span'] - 렌더링할 HTML 요소
|
|
11
|
+
* @param {Ref} [props.ref] - 렌더된 요소로 forward되는 ref. as에 따라 추론
|
|
9
12
|
*/
|
|
10
|
-
declare const Typography:
|
|
13
|
+
declare const Typography: <T extends ElementType = "span">(props: TypographyProps<T> & {
|
|
14
|
+
ref?: PolymorphicRef<T>;
|
|
15
|
+
}) => ReactElement | null;
|
|
11
16
|
export { Typography };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{jsx as t}from"react/jsx-runtime";import{twMerge as e}from"tailwind-merge";function
|
|
2
|
-
return t(
|
|
1
|
+
import{jsx as t}from"react/jsx-runtime";import{twMerge as e}from"tailwind-merge";import{forwardRef as n}from"react";function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function o(t,e){return e=null!=e?e:{},Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(e)):function(t){var e=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e.push.apply(e,n)}return e}(Object(e)).forEach((function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(e,n))})),t}function c(t,e){if(null==t)return{};var n,r,o=function(t,e){if(null==t)return{};var n,r,o={},c=Object.keys(t);for(r=0;r<c.length;r++)n=c[r],e.indexOf(n)>=0||(o[n]=t[n]);return o}(t,e);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(t);for(r=0;r<c.length;r++)n=c[r],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n])}return o}const a=[{name:"title48",class:"typo-title48"},{name:"title32",class:"typo-title32"},{name:"title28",class:"typo-title28"},{name:"title24",class:"typo-title24"},{name:"subTitle20",class:"typo-subTitle20"},{name:"subTitle18",class:"typo-subTitle18"},{name:"contents18",class:"typo-contents18"},{name:"contents16",class:"typo-contents16"},{name:"body16",class:"typo-body16"},{name:"body14",class:"typo-body14"},{name:"body13",class:"typo-body13"},{name:"caption12",class:"typo-caption12"},{name:"caption11",class:"typo-caption11"}],s=/*#__PURE__*/n(((n,s)=>{var l,{children:i,variant:p,className:y,as:b}=n,u=c(n,["children","variant","className","as"]);const m=null!=b?b:"span",f=(null===(l=a.find((t=>t.name===p)))||void 0===l?void 0:l.class)||"";/*#__PURE__*/
|
|
2
|
+
return t(m,o(function(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},o=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(n).filter((function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable})))),o.forEach((function(e){r(t,e,n[e])}))}return t}({ref:s,className:e("tracking-default",f,y)},u),{children:i}))}));
|
|
3
3
|
/**
|
|
4
4
|
* Typography
|
|
5
5
|
* @param {Object} props
|
|
@@ -7,4 +7,5 @@ return t(u,r(function(t){for(var e=1;e<arguments.length;e++){var r=null!=argumen
|
|
|
7
7
|
* @param {string} props.variant - 텍스트 스타일 variant ('title48' | 'title32' | 'title24' | 'subTitle20' | 'subTitle18' | 'contents18' | 'contents16' | 'body16' | 'body14' | 'body13' | 'caption12' | 'caption11')
|
|
8
8
|
* @param {string} [props.className] - 추가적인 CSS 클래스
|
|
9
9
|
* @param {keyof JSX.IntrinsicElements} [props.as='span'] - 렌더링할 HTML 요소
|
|
10
|
-
|
|
10
|
+
* @param {Ref} [props.ref] - 렌더된 요소로 forward되는 ref. as에 따라 추론
|
|
11
|
+
*/export{s as Typography};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ElementType, PropsWithChildren } from 'react';
|
|
1
|
+
import { ComponentPropsWithRef, ElementType, PropsWithChildren } from 'react';
|
|
2
2
|
export declare const typographyVariants: {
|
|
3
3
|
readonly title48: "title48";
|
|
4
4
|
readonly title32: "title32";
|
|
@@ -15,9 +15,8 @@ export declare const typographyVariants: {
|
|
|
15
15
|
readonly caption11: "caption11";
|
|
16
16
|
};
|
|
17
17
|
export type TypographyVariants = (typeof typographyVariants)[keyof typeof typographyVariants];
|
|
18
|
-
export
|
|
18
|
+
export type TypographyProps<T extends ElementType = 'span'> = PropsWithChildren<{
|
|
19
19
|
variant: TypographyVariants;
|
|
20
20
|
className?: string;
|
|
21
|
-
as?:
|
|
22
|
-
|
|
23
|
-
}
|
|
21
|
+
as?: T;
|
|
22
|
+
}> & Omit<ComponentPropsWithRef<T>, 'as' | 'children' | 'className'>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{jsx as r}from"react/jsx-runtime";import{twJoin as e}from"tailwind-merge";import{Box as t}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{NewCircle as s}from"./parts/NewCircle.js";import{New as a}from"./parts/New.js";import{Beta as i}from"./parts/Beta.js";import{Ai as o}from"./parts/Ai.js";
|
|
1
|
+
import{jsx as r}from"react/jsx-runtime";import{twJoin as e}from"tailwind-merge";import"react";import{Box as t}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{NewCircle as s}from"./parts/NewCircle.js";import{New as a}from"./parts/New.js";import{Beta as i}from"./parts/Beta.js";import{Ai as o}from"./parts/Ai.js";
|
|
2
2
|
/**
|
|
3
3
|
* 이미지에 오버레이되는 라벨을 표시하는 컴포넌트
|
|
4
4
|
* @param {('new_circle'|'new'|'beta'|'ai')} props.type - 표시할 라벨의 타입
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";import{jsx as i}from"react/jsx-runtime";import{twMerge as t}from"tailwind-merge";import{Box as e}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{PlainTooltip as o}from"./PlainTooltip/PlainTooltip.js";import{RichTooltip as l}from"./RichTooltip/RichTooltip.js";
|
|
1
|
+
"use client";import{jsx as i}from"react/jsx-runtime";import{twMerge as t}from"tailwind-merge";import"react";import{Box as e}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{PlainTooltip as o}from"./PlainTooltip/PlainTooltip.js";import{RichTooltip as l}from"./RichTooltip/RichTooltip.js";
|
|
2
2
|
/**
|
|
3
3
|
* 툴팁의 루트 컴포넌트입니다.
|
|
4
4
|
* CSS 기반 hover와 focus로 동작합니다.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* </Tooltip.Trigger>
|
|
14
14
|
* <Tooltip.Plain variant="up" text="간단한 툴팁" />
|
|
15
15
|
* </Tooltip>
|
|
16
|
-
*/const
|
|
16
|
+
*/const r=({children:o,className:l})=>/*#__PURE__*/i(e,{className:t("group relative inline-block h-fit w-fit",l),"data-testid":"design-system-tooltip",children:o});
|
|
17
17
|
/**
|
|
18
18
|
* 툴팁 트리거 컴포넌트입니다.
|
|
19
19
|
* 데스크톱에서는 CSS hover로, 모바일에서는 터치(focus)로 툴팁을 표시합니다.
|
|
@@ -22,4 +22,4 @@
|
|
|
22
22
|
* <Tooltip.Trigger>
|
|
23
23
|
* <SystemIcon name="medium_information" />
|
|
24
24
|
* </Tooltip.Trigger>
|
|
25
|
-
*/
|
|
25
|
+
*/r.Trigger=({children:t})=>/*#__PURE__*/i(e,{"data-testid":"design-system-tooltip--trigger",className:"h-fit w-fit focus:outline-hidden",tabIndex:0,children:t}),r.Plain=o,r.Rich=l;export{r as Tooltip};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{jsx as e}from"react/jsx-runtime";import{twMerge as r,twJoin as t}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import{Box as o}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";import{twMerge as r,twJoin as t}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import"react";import{Box as o}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import{ProductIcon as i}from"../../DataDisplays/ProductIcon/ProductIcon.js";import"../../DataDisplays/Accordion/Accordion.js";import{Checkbox as n}from"../Checkbox/Checkbox.js";function c(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function s(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{},o=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(t).filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})))),o.forEach((function(r){c(e,r,t[r])}))}return e}function a(e,r){return r=null!=r?r:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):function(e){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r.push.apply(r,t)}return r}(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})),e}function l(e,r){if(null==e)return{};var t,o,i=function(e,r){if(null==e)return{};var t,o,i={},n=Object.keys(e);for(o=0;o<n.length;o++)t=n[o],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o<n.length;o++)t=n[o],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}const p=t=>{var{children:o,isWide:i,checked:n,isError:c,disabled:p,className:d}=t,b=l(t,["children","isWide","checked","isError","disabled","className"]);/*#__PURE__*/
|
|
2
2
|
return e("div",a(s({className:r("relative flex h-auto cursor-pointer items-center gap-2 rounded-xl border",i?"min-h-[94px] w-[298px] flex-row gap-3 px-5 py-4":"min-h-fit w-[224px] flex-col justify-center px-4 pt-4 pb-6",!p&&!c&&"group-focus-within:border-primary-500",p?r("cursor-not-allowed",n&&!c?"border-primary-100":"border-w-gray-200"):c?"border-w-red-500":n?"border-primary-500":"border-w-gray-200 group-hover:border-primary",p?n&&!c?"bg-primary-10":"bg-w-gray-10":n?c?"bg-w-red-10":"bg-primary-10":"bg-w-white",d)},b),{children:o}))},d=({isWide:t,children:o})=>/*#__PURE__*/e("div",{className:r("flex h-auto w-full flex-col justify-between gap-0.5",t?"items-start":"items-center"),children:o}),b=i=>{var{isWide:c,className:a}=i,p=l(i,["isWide","className"]);const d=!c;/*#__PURE__*/
|
|
3
3
|
return e(o,{className:t(d&&"absolute top-[17px] left-[17px]"),children:/*#__PURE__*/e(n,s({className:r(d&&"group-hover:border-primary-500",a)},p))})},m=({iconName:t,disabled:o,checked:n,isError:c})=>{const s=c||!n;/*#__PURE__*/
|
|
4
4
|
return e("div",{className:r("flex size-[60px] shrink-0 items-center justify-center",o&&"opacity-30"),"data-testid":"design-system-checkboxCard--icon",children:/*#__PURE__*/e(i,{name:t,disabled:s})})};export{p as CheckboxCardContainer,m as CheckboxCardIcon,b as StyledCheckbox,d as TitleContainer};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";import{jsxs as t,jsx as e}from"react/jsx-runtime";import{twJoin as o}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import
|
|
1
|
+
"use client";import{jsxs as t,jsx as e}from"react/jsx-runtime";import{twJoin as o}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import"react";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{SystemIcon as s}from"../../DataDisplays/SystemIcon/SystemIcon.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import"../../DataDisplays/Accordion/Accordion.js";import{IconButton as i}from"../IconButton/IconButton.js";import{List as n}from"../List/List.js";import{useDropdown as a}from"../../../hooks/useDropdown.js";
|
|
2
2
|
/**
|
|
3
3
|
* 아이콘 버튼과 드롭다운 목록을 결합한 컴포넌트입니다.
|
|
4
4
|
* 버튼 클릭 시 드롭다운 목록이 표시되며, 키보드 탐색이 가능합니다.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{jsx as e}from"react/jsx-runtime";import{twMerge as r,twJoin as t}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";import{twMerge as r,twJoin as t}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import"react";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import{ProductIcon as o}from"../../DataDisplays/ProductIcon/ProductIcon.js";import"../../DataDisplays/Accordion/Accordion.js";import{Radio as i}from"../Radio/Radio.js";function n(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function s(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{},o=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(t).filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})))),o.forEach((function(r){n(e,r,t[r])}))}return e}function c(e,r){return r=null!=r?r:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):function(e){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r.push.apply(r,t)}return r}(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})),e}function a(e,r){if(null==e)return{};var t,o,i=function(e,r){if(null==e)return{};var t,o,i={},n=Object.keys(e);for(o=0;o<n.length;o++)t=n[o],r.indexOf(t)>=0||(i[t]=e[t]);return i}(e,r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o<n.length;o++)t=n[o],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}const l=t=>{var{children:o,isWide:i,checked:n,isError:l,disabled:d,className:p}=t,u=a(t,["children","isWide","checked","isError","disabled","className"]);/*#__PURE__*/
|
|
2
2
|
return e("div",c(s({className:r("relative flex h-auto cursor-pointer items-center gap-2 rounded-xl border",i?"min-h-[94px] w-[298px] flex-row gap-3 px-5 py-4":"min-h-fit w-[224px] flex-col justify-center px-4 py-6",!d&&!l&&"group-focus-within:border-primary-500",d&&n&&!l?"cursor-not-allowed border-primary-100":d?"cursor-not-allowed border-w-gray-200":l?"border-w-red-500":n?"border-primary-500":"border-w-gray-200 group-hover:border-primary",d?n&&!l?"bg-primary-10":"bg-w-gray-10":n?l?"bg-w-red-10":"bg-primary-10":"bg-w-white",p)},u),{children:o}))},d=({isWide:r,children:o})=>/*#__PURE__*/e("div",{className:t("flex h-auto w-full flex-col justify-between gap-0.5",r?"items-start":"items-center"),children:o}),p=t=>{var{isWide:o,disabled:n,isError:c,checked:l}=t,d=a(t,["isWide","disabled","isError","checked"]);const p=c&&l&&n;/*#__PURE__*/
|
|
3
3
|
return e(i,s({className:r(!o&&"absolute top-[17px] left-[17px]"),disabled:n||p,checked:!p&&l,isError:c},d))},u=({iconName:t,disabled:i,checked:n,isError:s})=>{const c=s||!n;/*#__PURE__*/
|
|
4
4
|
return e("div",{className:r("flex size-[60px] shrink-0 items-center justify-center",i&&"opacity-30"),"data-testid":"design-system-radioCard--icon",children:/*#__PURE__*/e(o,{name:t,disabled:c})})};export{l as RadioCardContainer,u as RadioCardIcon,p as StyledRadio,d as TitleContainer};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";import{jsxs as e,jsx as o}from"react/jsx-runtime";import"tailwind-merge";import{Box as
|
|
1
|
+
"use client";import{jsxs as e,jsx as o}from"react/jsx-runtime";import"tailwind-merge";import"react";import{Box as t}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{List as s}from"../List/List.js";import{SupportTextContainer as l}from"../SupportTextContainer/SupportTextContainer.js";import{useDropdown as i}from"../../../hooks/useDropdown.js";import{SelectBox as r}from"./TextFieldDropdown.parts.js";
|
|
2
2
|
/**
|
|
3
3
|
* 드롭다운 형태의 텍스트 필드 컴포넌트입니다.
|
|
4
4
|
*
|
|
@@ -32,4 +32,4 @@
|
|
|
32
32
|
* ```
|
|
33
33
|
*/const n=({selectedItem:n,items:a,onItemClick:d,placeholder:p,disabled:m,isError:c,errorMessage:u,supportMessage:x,className:f})=>{const{isListOpen:g,focusedIndex:I,ref:h,handleItemClick:k,toggleListOpen:v,handleKeyDown:w}=i({items:a,onItemClick:d,disabled:m}),y=!!x||!!u;/*#__PURE__*/
|
|
34
34
|
return e("div",{"data-testid":"design-system--textFieldDropdown",ref:h,className:"relative flex w-full flex-col gap-2 outline-hidden",onKeyDown:w,tabIndex:0,children:[
|
|
35
|
-
/*#__PURE__*/o(r,{placeholder:p,value:null==n?void 0:n.value,leadingIcon:null==n?void 0:n.leadingIcon,disabled:m,isListOpen:g,onClick:v,error:c,className:f}),y&&/*#__PURE__*/o(
|
|
35
|
+
/*#__PURE__*/o(r,{placeholder:p,value:null==n?void 0:n.value,leadingIcon:null==n?void 0:n.leadingIcon,disabled:m,isListOpen:g,onClick:v,error:c,className:f}),y&&/*#__PURE__*/o(l,{errorMessage:u,supportMessage:x}),g&&/*#__PURE__*/o(t,{className:"absolute top-[54px] z-40 w-full",children:/*#__PURE__*/o(s.Root,{children:a.map(((e,t)=>/*#__PURE__*/o(s.Item,{text:e.value,leadingIcon:e.leadingIcon,onClick:()=>k(e),selected:e.key===(null==n?void 0:n.key),isFocused:t===I},e.key)))})})]})};export{n as TextFieldDropdown};
|
|
@@ -51,6 +51,6 @@ declare const GNBList: {
|
|
|
51
51
|
UserInfo: ({ imgUrl, username, email, children, onClick, }: import("./GNBList.types").UserInfoProps) => import("react/jsx-runtime").JSX.Element;
|
|
52
52
|
List: ({ children }: import("react").PropsWithChildren) => import("react/jsx-runtime").JSX.Element;
|
|
53
53
|
SubList: ({ children }: import("react").PropsWithChildren) => import("react/jsx-runtime").JSX.Element;
|
|
54
|
-
Item: ({ hasNew, children, className, textClassName, href, ...rest }: import("./GNBList.types").GNBListItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
54
|
+
Item: ({ hasNew, children, className, textClassName, href, as: LinkComponent, ...rest }: import("./GNBList.types").GNBListItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
55
55
|
};
|
|
56
56
|
export { GNBList };
|
|
@@ -99,11 +99,12 @@ declare const SubList: ({ children }: PropsWithChildren) => import("react/jsx-ru
|
|
|
99
99
|
*
|
|
100
100
|
* @description
|
|
101
101
|
* 개별 메뉴 아이템을 렌더링합니다.
|
|
102
|
-
* - Next.js Link
|
|
102
|
+
* - 기본은 `<a>` 태그이며, `as` prop으로 Next.js Link 등 임의의 컴포넌트 주입 가능
|
|
103
103
|
* - 키보드 포커스 및 hover 스타일 지원
|
|
104
104
|
*
|
|
105
105
|
* @param {Object} props
|
|
106
106
|
* @param {string} props.href - 이동할 페이지 경로 (필수)
|
|
107
|
+
* @param {ElementType} [props.as='a'] - anchor로 렌더할 컴포넌트 (예: next/link)
|
|
107
108
|
* @param {ReactNode} props.children - 메뉴 텍스트
|
|
108
109
|
* @param {boolean} [props.hasNew=false] - New 뱃지 표시 여부
|
|
109
110
|
* @param {string} [props.className] - Link에 적용할 추가 CSS 클래스
|
|
@@ -131,5 +132,5 @@ declare const SubList: ({ children }: PropsWithChildren) => import("react/jsx-ru
|
|
|
131
132
|
* 특별 메뉴
|
|
132
133
|
* </Item>
|
|
133
134
|
*/
|
|
134
|
-
declare const Item: ({ hasNew, children, className, textClassName, href, ...rest }: GNBListItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
135
|
+
declare const Item: ({ hasNew, children, className, textClassName, href, as: LinkComponent, ...rest }: GNBListItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
135
136
|
export { Root, UserInfo, List, SubList, Item };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Children as a,Fragment as t}from"react";import{twMerge as l}from"tailwind-merge";import
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Children as a,Fragment as t}from"react";import{twMerge as l}from"tailwind-merge";import{Avatar as n}from"../../DataDisplays/Avatar/Avatar.js";import{Typography as o}from"../../Base/Typography/Typography.js";import{Box as s}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import{NewBadge as i}from"../../DataDisplays/NewBadge/NewBadge.js";import{Divider as c}from"../../DataDisplays/Divider/Divider.js";import"../../DataDisplays/Accordion/Accordion.js";function m(e,r,a){return r in e?Object.defineProperty(e,r,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[r]=a,e}function p(e){for(var r=1;r<arguments.length;r++){var a=null!=arguments[r]?arguments[r]:{},t=Object.keys(a);"function"==typeof Object.getOwnPropertySymbols&&(t=t.concat(Object.getOwnPropertySymbols(a).filter((function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable})))),t.forEach((function(r){m(e,r,a[r])}))}return e}function f(e,r){return r=null!=r?r:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):function(e){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);r.push.apply(r,a)}return r}(Object(r)).forEach((function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(r,a))})),e}function u(e,r){if(null==e)return{};var a,t,l=function(e,r){if(null==e)return{};var a,t,l={},n=Object.keys(e);for(t=0;t<n.length;t++)a=n[t],r.indexOf(a)>=0||(l[a]=e[a]);return l}
|
|
2
2
|
/**
|
|
3
3
|
* GNB 리스트의 루트 컴포넌트
|
|
4
4
|
*
|
|
@@ -31,16 +31,16 @@ import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Children as a,Fragment
|
|
|
31
31
|
* <Item href="/logout">로그아웃</Item>
|
|
32
32
|
* </SubList>
|
|
33
33
|
* </Root>
|
|
34
|
-
*/(e,r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(t=0;t<n.length;t++)a=n[t],r.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}const
|
|
35
|
-
/*#__PURE__*/e(
|
|
36
|
-
return e(s,{as:"nav","aria-label":"네비게이션 메뉴",className:l("absolute flex flex-col rounded-xl bg-w-white shadow-graymedium",n?"w-[280px] pb-3 pt-5":"h-auto w-[200px] overflow-hidden py-3",i),children:
|
|
34
|
+
*/(e,r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(t=0;t<n.length;t++)a=n[t],r.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}const y=({withUserInfo:n=!1,children:o,className:i})=>{const m=a.map(o,((a,l)=>0===l?a:/*#__PURE__*/r(t,{children:[
|
|
35
|
+
/*#__PURE__*/e(c,{className:"my-2"}),a]})));/*#__PURE__*/
|
|
36
|
+
return e(s,{as:"nav","aria-label":"네비게이션 메뉴",className:l("absolute flex flex-col rounded-xl bg-w-white shadow-graymedium",n?"w-[280px] pb-3 pt-5":"h-auto w-[200px] overflow-hidden py-3",i),children:m})},b=({imgUrl:a,username:t,email:l,children:i,onClick:c})=>/*#__PURE__*/r(s,{role:"region","aria-label":"사용자 정보",className:"flex w-full flex-col gap-4 px-6 pb-4",children:[
|
|
37
37
|
/*#__PURE__*/r(s,{className:"flex w-full items-center gap-4",children:[
|
|
38
|
-
/*#__PURE__*/e(
|
|
38
|
+
/*#__PURE__*/e(n,{size:"lg",isEditable:!0,imgUrl:a,onClick:c}),
|
|
39
39
|
/*#__PURE__*/r(s,{className:"flex w-full flex-col gap-0.5",children:[
|
|
40
|
-
/*#__PURE__*/e(
|
|
41
|
-
/*#__PURE__*/e(
|
|
42
|
-
return e(s,{as:"li",children:/*#__PURE__*/r(
|
|
43
|
-
/*#__PURE__*/e(
|
|
40
|
+
/*#__PURE__*/e(o,{variant:"body16",className:"text-w-gray-900 font-medium",children:t}),
|
|
41
|
+
/*#__PURE__*/e(o,{variant:"body14",className:"text-w-gray-600 line-clamp-2 break-all",children:l})]})]}),i&&/*#__PURE__*/e(s,{className:"flex w-full flex-col gap-2",children:i})]}),d=({children:r})=>/*#__PURE__*/e(s,{as:"ul","aria-label":"메인 메뉴",className:"text-w-gray-900 w-full",children:r}),h=({children:r})=>/*#__PURE__*/e(s,{as:"ul","aria-label":"서브 메뉴",className:"text-w-gray-600 w-full",children:r}),g=a=>{var{hasNew:t=!1,children:n,className:c,textClassName:m,href:y,as:b="a"}=a,d=u(a,["hasNew","children","className","textClassName","href","as"]);/*#__PURE__*/
|
|
42
|
+
return e(s,{as:"li",children:/*#__PURE__*/r(b,f(p({href:y,className:l("hover:bg-primary-10 flex w-full cursor-pointer gap-1 px-6 py-2",c)},d),{children:[
|
|
43
|
+
/*#__PURE__*/e(o,{variant:"body14",className:m,children:n}),t&&/*#__PURE__*/e(i,{className:"mt-1","aria-label":"새 소식"})]}))})};
|
|
44
44
|
/**
|
|
45
45
|
* 사용자 정보 컴포넌트
|
|
46
46
|
*
|
|
@@ -64,4 +64,4 @@ return e(s,{as:"li",children:/*#__PURE__*/r(n,u(f({href:b,className:l("hover:bg-
|
|
|
64
64
|
* <Button size="sm">프로필 수정</Button>
|
|
65
65
|
* <Button size="sm" variant="outlined">내 프로젝트</Button>
|
|
66
66
|
* </UserInfo>
|
|
67
|
-
*/export{
|
|
67
|
+
*/export{g as Item,d as List,y as Root,h as SubList,b as UserInfo};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ComponentPropsWithoutRef, PropsWithChildren } from 'react';
|
|
1
|
+
import { ComponentPropsWithoutRef, ElementType, PropsWithChildren } from 'react';
|
|
3
2
|
export interface GNBListRootProps extends PropsWithChildren {
|
|
4
3
|
withUserInfo?: boolean;
|
|
5
4
|
className?: string;
|
|
@@ -10,7 +9,13 @@ export interface UserInfoProps extends PropsWithChildren {
|
|
|
10
9
|
email?: string;
|
|
11
10
|
onClick?: () => void;
|
|
12
11
|
}
|
|
13
|
-
export interface GNBListItemProps extends ComponentPropsWithoutRef<
|
|
12
|
+
export interface GNBListItemProps extends Omit<ComponentPropsWithoutRef<'a'>, 'href'> {
|
|
13
|
+
href: string;
|
|
14
14
|
hasNew?: boolean;
|
|
15
15
|
textClassName?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Item에서 anchor로 렌더할 컴포넌트. 기본값은 일반 `<a>` 태그이며,
|
|
18
|
+
* Next.js의 Link 등을 주입할 수 있습니다.
|
|
19
|
+
*/
|
|
20
|
+
as?: ElementType;
|
|
16
21
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';
|
|
2
|
+
import { MediumSystemIconName, SmallSystemIconName } from '../../DataDisplays/SystemIcon';
|
|
3
|
+
import { IconButtonDropdownItem } from '../../Inputs';
|
|
4
|
+
/**
|
|
5
|
+
* `MenuLink`와 `MenuButton`이 공유하는 presentation props.
|
|
6
|
+
*
|
|
7
|
+
* - 시맨틱 분기(`href` vs `onClick`)는 각 컴포넌트의 별도 타입으로 표현되며,
|
|
8
|
+
* 이 타입에는 포함되지 않습니다.
|
|
9
|
+
*/
|
|
10
|
+
export interface MenuCommonProps {
|
|
11
|
+
type?: 'main' | 'sub';
|
|
12
|
+
variant?: 'white' | 'gray';
|
|
13
|
+
name: string;
|
|
14
|
+
badgeCount?: string;
|
|
15
|
+
isSelected?: boolean;
|
|
16
|
+
leadingIcon?: MediumSystemIconName;
|
|
17
|
+
iconButtonName?: SmallSystemIconName;
|
|
18
|
+
onOptionClick?: () => void;
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
items?: IconButtonDropdownItem[];
|
|
21
|
+
selectedItem?: IconButtonDropdownItem;
|
|
22
|
+
onItemClick?: (item: IconButtonDropdownItem) => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* `MenuLink`의 props.
|
|
26
|
+
*
|
|
27
|
+
* - `href`가 필수이며, 기본 anchor(`<a>`) 또는 `as`로 주입된 컴포넌트로 렌더링됩니다.
|
|
28
|
+
* - anchor 관련 native 속성(`target`, `rel`, `download` 등)을 그대로 받습니다.
|
|
29
|
+
*/
|
|
30
|
+
export type MenuLinkProps = MenuCommonProps & Omit<ComponentPropsWithoutRef<'a'>, 'href' | 'className' | 'children' | 'as'> & {
|
|
31
|
+
href: string;
|
|
32
|
+
/**
|
|
33
|
+
* anchor 자리에 렌더할 컴포넌트. 기본값은 일반 `<a>` 태그이며,
|
|
34
|
+
* Next.js의 Link 등을 주입할 수 있습니다.
|
|
35
|
+
*/
|
|
36
|
+
as?: ElementType;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* `MenuButton`의 props.
|
|
40
|
+
*
|
|
41
|
+
* - `onClick`이 필수이며, 항상 `<button>`으로 렌더링됩니다.
|
|
42
|
+
* - button 관련 native 속성(`disabled`, `type` 등)을 그대로 받습니다.
|
|
43
|
+
*/
|
|
44
|
+
export type MenuButtonProps = MenuCommonProps & Omit<ComponentPropsWithoutRef<'button'>, 'onClick' | 'className' | 'children' | 'type'> & {
|
|
45
|
+
onClick: () => void;
|
|
46
|
+
/**
|
|
47
|
+
* HTML `<button>`의 native `type` 속성. `MenuCommonProps.type`(`'main' | 'sub'`)과
|
|
48
|
+
* 이름이 충돌하므로 별도 prop으로 전달하려면 `htmlType`을 사용하세요.
|
|
49
|
+
*
|
|
50
|
+
* 디자인 시스템의 메뉴 타입(`'main' | 'sub'`)은 `MenuCommonProps`의 `type`을 그대로 사용합니다.
|
|
51
|
+
*/
|
|
52
|
+
htmlType?: 'button' | 'submit' | 'reset';
|
|
53
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ElementType, ReactNode } from 'react';
|
|
2
|
+
import { MenuCommonProps } from './Menu.types';
|
|
3
|
+
interface MenuBaseProps extends MenuCommonProps {
|
|
4
|
+
/**
|
|
5
|
+
* 자식 wrapper로 사용할 element 또는 컴포넌트.
|
|
6
|
+
* `MenuLink`에서는 `'a'` 또는 주입된 컴포넌트, `MenuButton`에서는 `'button'`이 들어옵니다.
|
|
7
|
+
*/
|
|
8
|
+
as: ElementType;
|
|
9
|
+
/**
|
|
10
|
+
* `as` 컴포넌트에 그대로 전달되는 native props (href, onClick, target 등).
|
|
11
|
+
*/
|
|
12
|
+
wrapperProps?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `MenuLink`와 `MenuButton`이 공유하는 내부 컴포넌트.
|
|
16
|
+
* presentation 로직(className 계산, leadingIcon, name, badge, trailing IconButton/Dropdown)을 담당합니다.
|
|
17
|
+
*
|
|
18
|
+
* 외부에 export 되지 않으며, `MenuLink` / `MenuButton`을 통해서만 사용됩니다.
|
|
19
|
+
*/
|
|
20
|
+
declare const MenuBase: ({ type, variant, name, isSelected, badgeCount, leadingIcon, iconButtonName, onOptionClick, items, selectedItem, onItemClick, as: Component, wrapperProps, }: MenuBaseProps) => ReactNode;
|
|
21
|
+
export { MenuBase };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{jsxs as t,jsx as e}from"react/jsx-runtime";import{twJoin as r,twMerge as o}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import{CountBadge as n}from"../../DataDisplays/CountBadge/CountBadge.js";import{Typography as s}from"../../Base/Typography/Typography.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"react";import{SystemIcon as i}from"../../DataDisplays/SystemIcon/SystemIcon.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import"../../DataDisplays/Accordion/Accordion.js";import"@wishket/yogokit";import"../../Inputs/AutoCompleteList/AutoCompleteList.parts.js";import"../../Inputs/Input/Input.js";import"../../Inputs/Input/PasswordInput.js";import"../../Inputs/Input/LabelInput.js";import"../../Inputs/Input/InputTypeSelector.js";import"../../Inputs/Button/Button.js";import"../../Inputs/Calendar/Calendar.utils.js";import"../../Inputs/Checkbox/Checkbox.js";import"../../Inputs/ChoiceChip/ChoiceChip.js";import{IconButton as p}from"../../Inputs/IconButton/IconButton.js";import"../../Inputs/Radio/Radio.js";import"../../Inputs/TextField/TextField.js";import"../../Inputs/CommentArea/CommentArea.js";import{IconButtonDropdown as a}from"../../Inputs/IconButtonDropdown/IconButtonDropdown.js";import"../../Inputs/FilterChip/FilterChip.js";function m(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function c(t,e){return e=null!=e?e:{},Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(e)):function(t){var e=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e.push.apply(e,r)}return e}(Object(e)).forEach((function(r){Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r))})),t}const u=(t,e,n)=>{const s="sub"===t?"pl-12":"",i={white:r("hover:bg-w-gray-50",n&&"bg-primary-10 text-primary hover:bg-primary-10"),gray:r("hover:bg-w-gray-100",n&&"bg-w-gray-100 hover:bg-w-gray-100")};return o("flex w-full cursor-pointer items-center gap-2 rounded-xl px-4 py-3 text-w-gray-900 text-left",s,i[e])},l=(t,e)=>"white"!==t?"white_gray":e?"primary":"gray",y=({type:o="main",variant:y="white",name:d,isSelected:g=!1,badgeCount:j,leadingIcon:I,iconButtonName:b,onOptionClick:f,items:h,selectedItem:w,onItemClick:O,as:C,wrapperProps:x})=>{const B=!!(b&&h&&O&&w),D=!!b&&!!f;/*#__PURE__*/
|
|
2
|
+
return t(C,c(function(t){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{},o=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(r).filter((function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable})))),o.forEach((function(e){m(t,e,r[e])}))}return t}({"data-testid":"design-system-menu",className:u(o,y,g)},x),{children:[I&&/*#__PURE__*/e(i,{testId:"design-system-menu-leading-icon",name:I,className:r("white"===y&&g&&"text-primary")}),
|
|
3
|
+
/*#__PURE__*/e(s,{"data-testid":"design-system-menu-name",variant:"body16",className:"w-full select-none",children:d}),j&&/*#__PURE__*/e(n,{variant:l(y,g),text:j,className:"relative",showZero:!0}),B&&/*#__PURE__*/e(a,{size:"sm",icon:b,items:h,selectedItem:w,onItemClick:O}),D&&/*#__PURE__*/e(p,{size:"sm",className:"shrink-0",onClick:t=>{t.stopPropagation(),f()},children:/*#__PURE__*/e(i,{name:b})})]}))};export{y as MenuBase};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { MenuButtonProps } from './Menu.types';
|
|
2
|
+
/**
|
|
3
|
+
* 네비게이션에서 사용되는 버튼형 메뉴 항목.
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* - 항상 `<button>`으로 렌더링됩니다.
|
|
7
|
+
* - `onClick`이 반드시 필요합니다. 페이지 이동을 위한 anchor가 필요한 경우 `MenuLink`를 사용하세요.
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} props
|
|
10
|
+
* @param {() => void} props.onClick - 메뉴 클릭 시 실행될 함수 (필수)
|
|
11
|
+
* @param {'main' | 'sub'} [props.type='main'] - 메뉴 타입 (HTML `<button>`의 native `type`과는 무관. native `type`을 지정하려면 `htmlType` prop 사용)
|
|
12
|
+
* @param {'button' | 'submit' | 'reset'} [props.htmlType] - `<button>`의 native `type` 속성
|
|
13
|
+
* @param {'white' | 'gray'} [props.variant='white'] - 메뉴 스타일 변형
|
|
14
|
+
* @param {string} props.name - 메뉴에 표시될 텍스트
|
|
15
|
+
* @param {string} [props.badgeCount] - 메뉴 항목에 표시될 뱃지 숫자
|
|
16
|
+
* @param {boolean} [props.isSelected=false] - 메뉴 선택 상태
|
|
17
|
+
* @param {SystemIconName} [props.leadingIcon] - 메뉴 앞쪽에 표시될 아이콘 (medium 사이즈)
|
|
18
|
+
* @param {SystemIconName} [props.iconButtonName] - IconButtonDropdown / IconButton 아이콘 (small 사이즈)
|
|
19
|
+
* @param {() => void} [props.onOptionClick] - 후행 아이콘 클릭 시 실행될 함수 (IconButton 옵션)
|
|
20
|
+
* @param {Item[]} [props.items] - IconButtonDropdown 사용 시 필요
|
|
21
|
+
* @param {Item} [props.selectedItem] - IconButtonDropdown 사용 시 필요
|
|
22
|
+
* @param {(item: Item) => void} [props.onItemClick] - IconButtonDropdown 사용 시 필요
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // 기본 사용
|
|
26
|
+
* <MenuButton name="설정" onClick={() => openModal()} />
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // IconButtonDropdown과 함께
|
|
30
|
+
* <MenuButton
|
|
31
|
+
* name="옵션"
|
|
32
|
+
* onClick={() => {}}
|
|
33
|
+
* iconButtonName="small_more_options"
|
|
34
|
+
* items={items}
|
|
35
|
+
* selectedItem={selectedItem}
|
|
36
|
+
* onItemClick={onItemClick}
|
|
37
|
+
* />
|
|
38
|
+
*/
|
|
39
|
+
declare const MenuButton: ({ type, variant, name, badgeCount, isSelected, leadingIcon, iconButtonName, onOptionClick, items, selectedItem, onItemClick, onClick, htmlType, children: _children, ...rest }: MenuButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
export { MenuButton };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";import{MenuBase as t}from"./MenuBase.js";function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{},o=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(r).filter((function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable})))),o.forEach((function(t){n(e,t,r[t])}))}return e}function o(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}
|
|
2
|
+
/**
|
|
3
|
+
* 네비게이션에서 사용되는 버튼형 메뉴 항목.
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* - 항상 `<button>`으로 렌더링됩니다.
|
|
7
|
+
* - `onClick`이 반드시 필요합니다. 페이지 이동을 위한 anchor가 필요한 경우 `MenuLink`를 사용하세요.
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} props
|
|
10
|
+
* @param {() => void} props.onClick - 메뉴 클릭 시 실행될 함수 (필수)
|
|
11
|
+
* @param {'main' | 'sub'} [props.type='main'] - 메뉴 타입 (HTML `<button>`의 native `type`과는 무관. native `type`을 지정하려면 `htmlType` prop 사용)
|
|
12
|
+
* @param {'button' | 'submit' | 'reset'} [props.htmlType] - `<button>`의 native `type` 속성
|
|
13
|
+
* @param {'white' | 'gray'} [props.variant='white'] - 메뉴 스타일 변형
|
|
14
|
+
* @param {string} props.name - 메뉴에 표시될 텍스트
|
|
15
|
+
* @param {string} [props.badgeCount] - 메뉴 항목에 표시될 뱃지 숫자
|
|
16
|
+
* @param {boolean} [props.isSelected=false] - 메뉴 선택 상태
|
|
17
|
+
* @param {SystemIconName} [props.leadingIcon] - 메뉴 앞쪽에 표시될 아이콘 (medium 사이즈)
|
|
18
|
+
* @param {SystemIconName} [props.iconButtonName] - IconButtonDropdown / IconButton 아이콘 (small 사이즈)
|
|
19
|
+
* @param {() => void} [props.onOptionClick] - 후행 아이콘 클릭 시 실행될 함수 (IconButton 옵션)
|
|
20
|
+
* @param {Item[]} [props.items] - IconButtonDropdown 사용 시 필요
|
|
21
|
+
* @param {Item} [props.selectedItem] - IconButtonDropdown 사용 시 필요
|
|
22
|
+
* @param {(item: Item) => void} [props.onItemClick] - IconButtonDropdown 사용 시 필요
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // 기본 사용
|
|
26
|
+
* <MenuButton name="설정" onClick={() => openModal()} />
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // IconButtonDropdown과 함께
|
|
30
|
+
* <MenuButton
|
|
31
|
+
* name="옵션"
|
|
32
|
+
* onClick={() => {}}
|
|
33
|
+
* iconButtonName="small_more_options"
|
|
34
|
+
* items={items}
|
|
35
|
+
* selectedItem={selectedItem}
|
|
36
|
+
* onItemClick={onItemClick}
|
|
37
|
+
* />
|
|
38
|
+
*/(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}const i=n=>{var{type:i,variant:c,name:l,badgeCount:a,isSelected:u,leadingIcon:m,iconButtonName:p,onOptionClick:s,items:b,selectedItem:f,onItemClick:y,onClick:O,htmlType:d,children:g}=n,C=o(n,["type","variant","name","badgeCount","isSelected","leadingIcon","iconButtonName","onOptionClick","items","selectedItem","onItemClick","onClick","htmlType","children"]);/*#__PURE__*/
|
|
39
|
+
return e(t,{type:i,variant:c,name:l,badgeCount:a,isSelected:u,leadingIcon:m,iconButtonName:p,onOptionClick:s,items:b,selectedItem:f,onItemClick:y,as:"button",wrapperProps:r({onClick:O,type:d},C)})};export{i as MenuButton};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { MenuLinkProps } from './Menu.types';
|
|
2
|
+
/**
|
|
3
|
+
* 네비게이션에서 사용되는 링크형 메뉴 항목.
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* - 기본은 `<a>` 태그이며, `as` prop으로 Next.js의 Link 등 임의의 컴포넌트를 주입할 수 있습니다.
|
|
7
|
+
* - `href`가 반드시 필요합니다. 클릭 핸들러만 필요한 경우 `MenuButton`을 사용하세요.
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} props
|
|
10
|
+
* @param {string} props.href - 메뉴 링크 주소 (필수)
|
|
11
|
+
* @param {ElementType} [props.as='a'] - anchor 자리에 렌더할 컴포넌트 (예: next/link)
|
|
12
|
+
* @param {'main' | 'sub'} [props.type='main'] - 메뉴 타입
|
|
13
|
+
* @param {'white' | 'gray'} [props.variant='white'] - 메뉴 스타일 변형
|
|
14
|
+
* @param {string} props.name - 메뉴에 표시될 텍스트
|
|
15
|
+
* @param {string} [props.badgeCount] - 메뉴 항목에 표시될 뱃지 숫자
|
|
16
|
+
* @param {boolean} [props.isSelected=false] - 메뉴 선택 상태
|
|
17
|
+
* @param {SystemIconName} [props.leadingIcon] - 메뉴 앞쪽에 표시될 아이콘 (medium 사이즈)
|
|
18
|
+
* @param {SystemIconName} [props.iconButtonName] - IconButtonDropdown / IconButton 아이콘 (small 사이즈)
|
|
19
|
+
* @param {() => void} [props.onOptionClick] - 후행 아이콘 클릭 시 실행될 함수 (IconButton 옵션)
|
|
20
|
+
* @param {Item[]} [props.items] - IconButtonDropdown 사용 시 필요
|
|
21
|
+
* @param {Item} [props.selectedItem] - IconButtonDropdown 사용 시 필요
|
|
22
|
+
* @param {(item: Item) => void} [props.onItemClick] - IconButtonDropdown 사용 시 필요
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // 기본 사용 (일반 <a>)
|
|
26
|
+
* <MenuLink href="/projects" name="프로젝트" />
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Next.js Link 주입
|
|
30
|
+
* import Link from 'next/link';
|
|
31
|
+
* <MenuLink as={Link} href="/projects" name="프로젝트" />
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // 외부 링크
|
|
35
|
+
* <MenuLink
|
|
36
|
+
* href="https://example.com"
|
|
37
|
+
* name="외부 사이트"
|
|
38
|
+
* target="_blank"
|
|
39
|
+
* rel="noopener noreferrer"
|
|
40
|
+
* />
|
|
41
|
+
*/
|
|
42
|
+
declare const MenuLink: ({ type, variant, name, badgeCount, isSelected, leadingIcon, iconButtonName, onOptionClick, items, selectedItem, onItemClick, href, as: LinkComponent, children: _children, ...rest }: MenuLinkProps) => import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
export { MenuLink };
|