@wishket/design-system 2.2.0 → 3.0.0

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.
Files changed (63) hide show
  1. package/README.md +58 -0
  2. package/dist/Components/Base/Layouts/Box/Box.d.ts +5 -5
  3. package/dist/Components/Base/Layouts/Box/Box.js +3 -2
  4. package/dist/Components/Base/Typography/Typography.d.ts +2 -1
  5. package/dist/Components/Base/Typography/Typography.js +1 -1
  6. package/dist/Components/Base/Typography/Typography.types.d.ts +4 -5
  7. package/dist/Components/Inputs/Calendar/Calendar.d.ts +2 -1
  8. package/dist/Components/Inputs/Calendar/Calendar.js +9 -8
  9. package/dist/Components/Inputs/Calendar/Calendar.parts.js +1 -1
  10. package/dist/Components/Inputs/Calendar/Calendar.types.d.ts +1 -0
  11. package/dist/Components/Navigations/GNBList/GNBList.d.ts +1 -1
  12. package/dist/Components/Navigations/GNBList/GNBList.parts.d.ts +3 -2
  13. package/dist/Components/Navigations/GNBList/GNBList.parts.js +10 -10
  14. package/dist/Components/Navigations/GNBList/GNBList.types.d.ts +8 -3
  15. package/dist/Components/Navigations/Menu/Menu.types.d.ts +53 -0
  16. package/dist/Components/Navigations/Menu/MenuBase.d.ts +21 -0
  17. package/dist/Components/Navigations/Menu/MenuBase.js +3 -0
  18. package/dist/Components/Navigations/Menu/MenuButton.d.ts +40 -0
  19. package/dist/Components/Navigations/Menu/MenuButton.js +39 -0
  20. package/dist/Components/Navigations/Menu/MenuLink.d.ts +43 -0
  21. package/dist/Components/Navigations/Menu/MenuLink.js +42 -0
  22. package/dist/Components/Navigations/Menu/index.d.ts +3 -1
  23. package/dist/Components/Navigations/TextLink/TextLink.d.ts +13 -35
  24. package/dist/Components/Navigations/TextLink/TextLink.js +11 -34
  25. package/dist/cjs/Components/Base/Layouts/Box/Box.js +3 -2
  26. package/dist/cjs/Components/Base/Typography/Typography.js +2 -2
  27. package/dist/cjs/Components/Inputs/Calendar/Calendar.js +7 -7
  28. package/dist/cjs/Components/Inputs/Calendar/Calendar.parts.js +6 -6
  29. package/dist/cjs/Components/Navigations/GNBList/GNBList.parts.js +11 -11
  30. package/dist/cjs/Components/Navigations/Menu/MenuBase.js +3 -0
  31. package/dist/cjs/Components/Navigations/Menu/MenuButton.js +39 -0
  32. package/dist/cjs/Components/Navigations/Menu/MenuLink.js +42 -0
  33. package/dist/cjs/Components/Navigations/TextLink/TextLink.js +11 -34
  34. package/dist/cjs/index.js +1 -1
  35. package/dist/index.js +1 -1
  36. package/package.json +7 -5
  37. package/scripts/codemods/README.md +178 -0
  38. package/scripts/codemods/__tests__/__fixtures__/add-as-link/already-has-as.input.tsx +6 -0
  39. package/scripts/codemods/__tests__/__fixtures__/add-as-link/already-has-as.output.tsx +6 -0
  40. package/scripts/codemods/__tests__/__fixtures__/add-as-link/basic.input.tsx +9 -0
  41. package/scripts/codemods/__tests__/__fixtures__/add-as-link/basic.output.tsx +10 -0
  42. package/scripts/codemods/__tests__/__fixtures__/add-as-link/existing-next-link-import.input.tsx +9 -0
  43. package/scripts/codemods/__tests__/__fixtures__/add-as-link/existing-next-link-import.output.tsx +9 -0
  44. package/scripts/codemods/__tests__/__fixtures__/add-as-link/menu-button-fallback.input.tsx +5 -0
  45. package/scripts/codemods/__tests__/__fixtures__/add-as-link/menu-button-fallback.output.tsx +5 -0
  46. package/scripts/codemods/__tests__/__fixtures__/add-as-link/unrelated-import.input.tsx +3 -0
  47. package/scripts/codemods/__tests__/__fixtures__/add-as-link/unrelated-import.output.tsx +3 -0
  48. package/scripts/codemods/__tests__/__fixtures__/menu-split/basic.input.tsx +8 -0
  49. package/scripts/codemods/__tests__/__fixtures__/menu-split/basic.output.tsx +8 -0
  50. package/scripts/codemods/__tests__/__fixtures__/menu-split/conflict.input.tsx +5 -0
  51. package/scripts/codemods/__tests__/__fixtures__/menu-split/conflict.output.tsx +6 -0
  52. package/scripts/codemods/__tests__/__fixtures__/menu-split/href-only.input.tsx +3 -0
  53. package/scripts/codemods/__tests__/__fixtures__/menu-split/href-only.output.tsx +3 -0
  54. package/scripts/codemods/__tests__/__fixtures__/menu-split/onclick-only.input.tsx +3 -0
  55. package/scripts/codemods/__tests__/__fixtures__/menu-split/onclick-only.output.tsx +3 -0
  56. package/scripts/codemods/__tests__/__fixtures__/menu-split/spread-props.input.tsx +3 -0
  57. package/scripts/codemods/__tests__/__fixtures__/menu-split/spread-props.output.tsx +4 -0
  58. package/scripts/codemods/__tests__/run-fixtures.cjs +100 -0
  59. package/scripts/codemods/add-as-link.ts +110 -0
  60. package/scripts/codemods/menu-split.ts +252 -0
  61. package/dist/Components/Navigations/Menu/Menu.d.ts +0 -81
  62. package/dist/Components/Navigations/Menu/Menu.js +0 -62
  63. package/dist/cjs/Components/Navigations/Menu/Menu.js +0 -2
@@ -0,0 +1,252 @@
1
+ import type {
2
+ API,
3
+ ASTPath,
4
+ Collection,
5
+ FileInfo,
6
+ ImportDeclaration,
7
+ ImportSpecifier,
8
+ JSCodeshift,
9
+ JSXAttribute,
10
+ JSXIdentifier,
11
+ JSXOpeningElement,
12
+ } from 'jscodeshift';
13
+
14
+ const DESIGN_SYSTEM_PACKAGE = '@wishket/design-system';
15
+ const SOURCE_NAME = 'Menu';
16
+ const LINK_NAME = 'MenuLink';
17
+ const BUTTON_NAME = 'MenuButton';
18
+
19
+ /**
20
+ * v3 — `Menu` 컴포넌트를 `MenuLink` / `MenuButton`으로 분리하는 codemod.
21
+ *
22
+ * 변환 규칙:
23
+ *
24
+ * 1. `@wishket/design-system`에서 import된 `Menu`만 처리 (alias 미지원).
25
+ * 2. JSX 호출 분석:
26
+ * - `href` prop 있음 → `<MenuLink ...>`로 rename + import 정리
27
+ * - `href` 없고 `onClick` 있음 → `<MenuButton ...>`로 rename + import 정리
28
+ * - 둘 다 있음 (모순) → 변환 안 함 + TODO 코멘트
29
+ * - 둘 다 없음 → 변환 안 함 + TODO 코멘트
30
+ * - spread props (`<Menu {...props} />`) → 변환 안 함 + TODO 코멘트
31
+ * 3. import 정리:
32
+ * - `Menu`를 사용된 변형(`MenuLink` / `MenuButton` / 둘 다)으로 교체
33
+ * - 모든 호출을 변환하지 못해 `Menu`가 여전히 필요한 경우 `Menu`도 유지
34
+ */
35
+ export default function transformer(file: FileInfo, api: API): string {
36
+ const j: JSCodeshift = api.jscodeshift;
37
+ const root = j(file.source);
38
+
39
+ const dsImports: Collection<ImportDeclaration> = root.find(
40
+ j.ImportDeclaration,
41
+ {
42
+ source: { value: DESIGN_SYSTEM_PACKAGE },
43
+ },
44
+ );
45
+ if (dsImports.size() === 0) return file.source;
46
+
47
+ // `Menu`가 alias 없이 default-named로 import 되었는지 확인.
48
+ let hasMenuImport = false;
49
+ let hasAliasedMenuImport = false;
50
+
51
+ dsImports.forEach(path => {
52
+ const specifiers = path.node.specifiers ?? [];
53
+ specifiers.forEach(spec => {
54
+ if (spec.type !== 'ImportSpecifier') return;
55
+ const importedName = spec.imported.name;
56
+ if (importedName !== SOURCE_NAME) return;
57
+ const localName = spec.local?.name ?? importedName;
58
+ if (localName !== SOURCE_NAME) {
59
+ hasAliasedMenuImport = true;
60
+ } else {
61
+ hasMenuImport = true;
62
+ }
63
+ });
64
+ });
65
+
66
+ if (!hasMenuImport && !hasAliasedMenuImport) {
67
+ return file.source;
68
+ }
69
+
70
+ let didChange = false;
71
+ let usedMenuLink = false;
72
+ let usedMenuButton = false;
73
+ let hasUnconvertedMenu = false;
74
+
75
+ if (hasAliasedMenuImport) {
76
+ // alias가 있는 경우 안전하게 변환하기 어려움 — 파일 상단에 안내 코멘트 추가.
77
+ addLeadingComment(
78
+ j,
79
+ root,
80
+ ` TODO: codemod could not safely resolve aliased Menu import — manually split into MenuLink / MenuButton.`,
81
+ );
82
+ return root.toSource({ quote: 'single' });
83
+ }
84
+
85
+ root
86
+ .find(j.JSXOpeningElement)
87
+ .forEach((path: ASTPath<JSXOpeningElement>) => {
88
+ const name = getJSXName(path.node);
89
+ if (name !== SOURCE_NAME) return;
90
+
91
+ const attrs = path.node.attributes ?? [];
92
+
93
+ const hasSpread = attrs.some(attr => attr.type === 'JSXSpreadAttribute');
94
+ if (hasSpread) {
95
+ addCommentBefore(
96
+ j,
97
+ path,
98
+ ` TODO: codemod could not safely resolve spread props — manually choose MenuLink or MenuButton.`,
99
+ );
100
+ hasUnconvertedMenu = true;
101
+ return;
102
+ }
103
+
104
+ const hasHref = attrs.some(
105
+ (attr): attr is JSXAttribute =>
106
+ attr.type === 'JSXAttribute' &&
107
+ attr.name.type === 'JSXIdentifier' &&
108
+ attr.name.name === 'href',
109
+ );
110
+ const hasOnClick = attrs.some(
111
+ (attr): attr is JSXAttribute =>
112
+ attr.type === 'JSXAttribute' &&
113
+ attr.name.type === 'JSXIdentifier' &&
114
+ attr.name.name === 'onClick',
115
+ );
116
+
117
+ if (hasHref && hasOnClick) {
118
+ addCommentBefore(
119
+ j,
120
+ path,
121
+ ` TODO: codemod could not safely resolve — manually choose MenuLink or MenuButton.`,
122
+ );
123
+ hasUnconvertedMenu = true;
124
+ return;
125
+ }
126
+
127
+ if (!hasHref && !hasOnClick) {
128
+ addCommentBefore(
129
+ j,
130
+ path,
131
+ ` TODO: codemod could not safely resolve — Menu without href or onClick. Choose MenuLink (add href) or MenuButton (add onClick).`,
132
+ );
133
+ hasUnconvertedMenu = true;
134
+ return;
135
+ }
136
+
137
+ const target = hasHref ? LINK_NAME : BUTTON_NAME;
138
+ renameJSXElement(j, path, target);
139
+
140
+ if (target === LINK_NAME) usedMenuLink = true;
141
+ else usedMenuButton = true;
142
+
143
+ didChange = true;
144
+ });
145
+
146
+ // Import 정리.
147
+ dsImports.forEach(path => {
148
+ const specifiers = path.node.specifiers ?? [];
149
+ const next: ImportSpecifier[] = [];
150
+ let touched = false;
151
+
152
+ specifiers.forEach(spec => {
153
+ if (spec.type !== 'ImportSpecifier') {
154
+ next.push(spec as ImportSpecifier);
155
+ return;
156
+ }
157
+ if (spec.imported.name !== SOURCE_NAME) {
158
+ next.push(spec);
159
+ return;
160
+ }
161
+ // `Menu`를 제거하고 사용된 변형으로 교체.
162
+ touched = true;
163
+ if (hasUnconvertedMenu) {
164
+ // 일부 변환 못한 호출이 남아있어 Menu도 유지가 필요할 수 있음.
165
+ next.push(spec);
166
+ }
167
+ if (usedMenuLink) {
168
+ next.push(
169
+ j.importSpecifier(j.identifier(LINK_NAME)) as ImportSpecifier,
170
+ );
171
+ }
172
+ if (usedMenuButton) {
173
+ next.push(
174
+ j.importSpecifier(j.identifier(BUTTON_NAME)) as ImportSpecifier,
175
+ );
176
+ }
177
+ });
178
+
179
+ if (touched) {
180
+ // 중복 제거 (같은 이름이 이미 import된 경우 대비).
181
+ const seen = new Set<string>();
182
+ path.node.specifiers = next.filter(spec => {
183
+ if (spec.type !== 'ImportSpecifier') return true;
184
+ const importedName = spec.imported.name;
185
+ const localName = spec.local?.name ?? importedName;
186
+ const key = `${importedName}::${localName}`;
187
+ if (seen.has(key)) return false;
188
+ seen.add(key);
189
+ return true;
190
+ });
191
+ didChange = true;
192
+ }
193
+ });
194
+
195
+ if (!didChange) return file.source;
196
+
197
+ return root.toSource({ quote: 'single' });
198
+ }
199
+
200
+ function getJSXName(node: JSXOpeningElement): string | null {
201
+ const { name } = node;
202
+ if (name.type === 'JSXIdentifier') return name.name;
203
+ return null;
204
+ }
205
+
206
+ function renameJSXElement(
207
+ j: JSCodeshift,
208
+ path: ASTPath<JSXOpeningElement>,
209
+ newName: string,
210
+ ) {
211
+ const opening = path.node;
212
+ (opening.name as JSXIdentifier).name = newName;
213
+
214
+ // self-closing이 아니면 닫는 태그도 함께 갱신.
215
+ const parent = path.parent.node;
216
+ if (parent && parent.type === 'JSXElement' && parent.closingElement) {
217
+ const closingName = parent.closingElement.name;
218
+ if (closingName.type === 'JSXIdentifier') {
219
+ (closingName as JSXIdentifier).name = newName;
220
+ }
221
+ }
222
+ }
223
+
224
+ function addCommentBefore(
225
+ j: JSCodeshift,
226
+ path: ASTPath<JSXOpeningElement>,
227
+ message: string,
228
+ ) {
229
+ // JSX element 자체의 부모(보통 JSXElement)를 찾아 그 앞에 코멘트를 삽입.
230
+ let current: ASTPath | null = path;
231
+ while (current && current.node && current.node.type !== 'JSXElement') {
232
+ current = current.parent;
233
+ }
234
+ if (!current) return;
235
+
236
+ const node = current.node;
237
+ node.comments = node.comments ?? [];
238
+ node.comments.push(j.commentLine(message, true, false));
239
+ }
240
+
241
+ function addLeadingComment(
242
+ j: JSCodeshift,
243
+ root: Collection,
244
+ message: string,
245
+ ) {
246
+ const program = root.get().node.program;
247
+ const body = program.body;
248
+ if (!body || body.length === 0) return;
249
+ const first = body[0];
250
+ first.comments = first.comments ?? [];
251
+ first.comments.push(j.commentLine(message, true, false));
252
+ }
@@ -1,81 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { MediumSystemIconName, SmallSystemIconName } from '../../DataDisplays/SystemIcon';
3
- import { IconButtonDropdownItem } from '../../Inputs';
4
- export interface MenuProps {
5
- type?: 'main' | 'sub';
6
- variant?: 'white' | 'gray';
7
- name: string;
8
- badgeCount?: string;
9
- isSelected?: boolean;
10
- leadingIcon?: MediumSystemIconName;
11
- iconButtonName?: SmallSystemIconName;
12
- onClick?: () => void;
13
- onOptionClick?: () => void;
14
- href?: string;
15
- children?: ReactNode;
16
- items?: IconButtonDropdownItem[];
17
- selectedItem?: IconButtonDropdownItem;
18
- onItemClick?: (item: IconButtonDropdownItem) => void;
19
- }
20
- /**
21
- * 메뉴 컴포넌트는 네비게이션에서 사용되는 클릭 가능한 항목을 표시합니다.
22
- *
23
- * @param {Object} props
24
- * @param {'main' | 'sub'} [props.type='main'] - 메뉴 타입 ('main', 'sub')
25
- * @param {'white' | 'gray'} [props.variant='white'] - 메뉴 스타일 변형 ('white', 'gray')
26
- * @param {string} props.name - 메뉴에 표시될 텍스트
27
- * @param {string} [props.badgeCount] - 메뉴 항목에 표시될 뱃지 숫자
28
- * @param {boolean} [props.isSelected=false] - 메뉴 선택 상태
29
- * @param {SystemIconName} [props.leadingIcon] - 메뉴 앞쪽에 표시될 아이콘(medium 사이즈)
30
- * @param {SystemIconName} [props.iconButtonName] - IconButtonDropdown 아이콘(small 사이즈)
31
- * @param {() => void} props.onClick - 메뉴 클릭 시 실행될 함수
32
- * @param {() => void} [props.onOptionClick] - 후행 아이콘 클릭 시 실행될 함수 (IconButtonDropdown이 아닌 IconButton으로만 사용 시 필요)
33
- * @param {string} [props.href] - 메뉴 링크 주소
34
- * @param {ReactNode} [props.children] - 메뉴 내부에 표시될 자식 요소 (IconButtonDropdown 컴포넌트 사용 시 필요, trailingIcon과 함께 사용하지 않도록 주의 필요)
35
- * @param {Item[]} [props.items] - IconButtonDropdown 컴포넌트 사용 시 필요 {key: number, value: string}[]
36
- * @param {Item} [props.selectedItem] - IconButtonDropdown 컴포넌트 사용 시 필요 {key: number, value: string}
37
- * @param {(item: Item) => void} [props.onItemClick] - IconButtonDropdown 컴포넌트 사용 시 필요 (item: Item) => {}
38
- *
39
- * @example
40
- * // 기본 메뉴
41
- * <Menu
42
- * name="메뉴 항목"
43
- * onClick={() => console.log('메뉴 클릭')}
44
- * />
45
- *
46
- * // 아이콘과 뱃지가 있는 서브 메뉴
47
- * <Menu
48
- * type="sub"
49
- * name="서브 메뉴"
50
- * leadingIcon="home"
51
- * badgeCount="5"
52
- * onClick={() => console.log('서브 메뉴 클릭')}
53
- * />
54
- *
55
- * // IconButtonDropdown과 함께 사용시
56
- * <Menu
57
- * name="메뉴"
58
- * onClick={() => console.log('메뉴 클릭')}
59
- * iconButtonName="small_more_options"
60
- * items={items}
61
- * selectedItem={selectedItem}
62
- * onItemClick={onItemClick}
63
- * />
64
- *
65
- * // 드롭다운이 필요하지 않은 옵션 메뉴(ex. 버튼 클릭 시 모달 오픈))
66
- * <Menu
67
- * variant="gray"
68
- * name="옵션 메뉴"
69
- * isSelected={true}
70
- * iconButtonName="small_more_options"
71
- * onClick={() => console.log('메뉴 클릭')}
72
- * onOptionClick={() => console.log('옵션 클릭', '모달 오픈')}
73
- * />
74
- * // 링크로 사용해야하는 메뉴
75
- * <Menu
76
- * href="/test"
77
- * name="테스트 메뉴"
78
- * />
79
- */
80
- declare const Menu: ({ type, variant, name, isSelected, badgeCount, leadingIcon, iconButtonName, onClick, onOptionClick, href, items, selectedItem, onItemClick, }: MenuProps) => import("react/jsx-runtime").JSX.Element;
81
- export { Menu };
@@ -1,62 +0,0 @@
1
- import{jsxs as t,Fragment as e,jsx as o}from"react/jsx-runtime";import{twJoin as s,twMerge as i}from"tailwind-merge";import r from"next/link";import"../../DataDisplays/Avatar/Avatar.js";import{CountBadge as n}from"../../DataDisplays/CountBadge/CountBadge.js";import{Typography as a}from"../../Base/Typography/Typography.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"react";import{SystemIcon as p}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 m}from"../../Inputs/IconButton/IconButton.js";import"../../Inputs/Radio/Radio.js";import"../../Inputs/TextField/TextField.js";import"../../Inputs/CommentArea/CommentArea.js";import{IconButtonDropdown as l}from"../../Inputs/IconButtonDropdown/IconButtonDropdown.js";import"../../Inputs/FilterChip/FilterChip.js";
2
- /**
3
- * 메뉴 컴포넌트는 네비게이션에서 사용되는 클릭 가능한 항목을 표시합니다.
4
- *
5
- * @param {Object} props
6
- * @param {'main' | 'sub'} [props.type='main'] - 메뉴 타입 ('main', 'sub')
7
- * @param {'white' | 'gray'} [props.variant='white'] - 메뉴 스타일 변형 ('white', 'gray')
8
- * @param {string} props.name - 메뉴에 표시될 텍스트
9
- * @param {string} [props.badgeCount] - 메뉴 항목에 표시될 뱃지 숫자
10
- * @param {boolean} [props.isSelected=false] - 메뉴 선택 상태
11
- * @param {SystemIconName} [props.leadingIcon] - 메뉴 앞쪽에 표시될 아이콘(medium 사이즈)
12
- * @param {SystemIconName} [props.iconButtonName] - IconButtonDropdown 아이콘(small 사이즈)
13
- * @param {() => void} props.onClick - 메뉴 클릭 시 실행될 함수
14
- * @param {() => void} [props.onOptionClick] - 후행 아이콘 클릭 시 실행될 함수 (IconButtonDropdown이 아닌 IconButton으로만 사용 시 필요)
15
- * @param {string} [props.href] - 메뉴 링크 주소
16
- * @param {ReactNode} [props.children] - 메뉴 내부에 표시될 자식 요소 (IconButtonDropdown 컴포넌트 사용 시 필요, trailingIcon과 함께 사용하지 않도록 주의 필요)
17
- * @param {Item[]} [props.items] - IconButtonDropdown 컴포넌트 사용 시 필요 {key: number, value: string}[]
18
- * @param {Item} [props.selectedItem] - IconButtonDropdown 컴포넌트 사용 시 필요 {key: number, value: string}
19
- * @param {(item: Item) => void} [props.onItemClick] - IconButtonDropdown 컴포넌트 사용 시 필요 (item: Item) => {}
20
- *
21
- * @example
22
- * // 기본 메뉴
23
- * <Menu
24
- * name="메뉴 항목"
25
- * onClick={() => console.log('메뉴 클릭')}
26
- * />
27
- *
28
- * // 아이콘과 뱃지가 있는 서브 메뉴
29
- * <Menu
30
- * type="sub"
31
- * name="서브 메뉴"
32
- * leadingIcon="home"
33
- * badgeCount="5"
34
- * onClick={() => console.log('서브 메뉴 클릭')}
35
- * />
36
- *
37
- * // IconButtonDropdown과 함께 사용시
38
- * <Menu
39
- * name="메뉴"
40
- * onClick={() => console.log('메뉴 클릭')}
41
- * iconButtonName="small_more_options"
42
- * items={items}
43
- * selectedItem={selectedItem}
44
- * onItemClick={onItemClick}
45
- * />
46
- *
47
- * // 드롭다운이 필요하지 않은 옵션 메뉴(ex. 버튼 클릭 시 모달 오픈))
48
- * <Menu
49
- * variant="gray"
50
- * name="옵션 메뉴"
51
- * isSelected={true}
52
- * iconButtonName="small_more_options"
53
- * onClick={() => console.log('메뉴 클릭')}
54
- * onOptionClick={() => console.log('옵션 클릭', '모달 오픈')}
55
- * />
56
- * // 링크로 사용해야하는 메뉴
57
- * <Menu
58
- * href="/test"
59
- * name="테스트 메뉴"
60
- * />
61
- */const u=({type:u="main",variant:c="white",name:d,isSelected:y=!1,badgeCount:I,leadingIcon:g,iconButtonName:h,onClick:j,onOptionClick:C,href:w,items:x,selectedItem:B,onItemClick:f})=>{const b=!!(h&&x&&f&&B),k=!!h&&!!C,D=(t,e,o)=>{const r="sub"===t?"pl-12":"",n={white:s("hover:bg-w-gray-50",o&&"bg-primary-10 text-primary hover:bg-primary-10"),gray:s("hover:bg-w-gray-100",o&&"bg-w-gray-100 hover:bg-w-gray-100")};return i("flex w-full cursor-pointer items-center gap-2 rounded-xl px-4 py-3 text-w-gray-900 text-left",r,n[e])},v=/*#__PURE__*/t(e,{children:[g&&/*#__PURE__*/o(p,{testId:"design-system-menu-leading-icon",name:g,className:s("white"===c&&y&&"text-primary")}),
62
- /*#__PURE__*/o(a,{"data-testid":"design-system-menu-name",variant:"body16",className:"w-full select-none",children:d}),I&&/*#__PURE__*/o(n,{variant:((t,e)=>"white"!==t?"white_gray":e?"primary":"gray")(c,y),text:I,className:"relative",showZero:!0}),b&&/*#__PURE__*/o(l,{size:"sm",icon:h,items:x,selectedItem:B,onItemClick:f}),k&&/*#__PURE__*/o(m,{size:"sm",className:"shrink-0",onClick:t=>{t.stopPropagation(),C()},children:/*#__PURE__*/o(p,{name:h})})]});return w?/*#__PURE__*/o(r,{href:w,"data-testid":"design-system-menu",className:D(u,c,y),children:v}):/*#__PURE__*/o("button",{"data-testid":"design-system-menu",className:D(u,c,y),onClick:j,children:v})};export{u as Menu};
@@ -1,2 +0,0 @@
1
- "use strict";var e=require("react/jsx-runtime"),t=require("tailwind-merge"),r=require("next/link");require("../../DataDisplays/Avatar/Avatar.js");var s=require("../../DataDisplays/CountBadge/CountBadge.js"),n=require("../../Base/Typography/Typography.js");require("../../Base/Layouts/Box/Box.js"),require("../../Base/Layouts/FullBleed/FullBleed.js"),require("react");var i=require("../../DataDisplays/SystemIcon/SystemIcon.js");require("../../DataDisplays/SystemIcon/SystemIcon.constants.js"),require("../../DataDisplays/Accordion/Accordion.js"),require("@wishket/yogokit"),require("../../Inputs/AutoCompleteList/AutoCompleteList.parts.js"),require("../../Inputs/Input/Input.js"),require("../../Inputs/Input/PasswordInput.js"),require("../../Inputs/Input/LabelInput.js"),require("../../Inputs/Input/InputTypeSelector.js"),require("../../Inputs/Button/Button.js"),require("../../Inputs/Calendar/Calendar.utils.js"),require("../../Inputs/Checkbox/Checkbox.js"),require("../../Inputs/ChoiceChip/ChoiceChip.js");var a=require("../../Inputs/IconButton/IconButton.js");require("../../Inputs/Radio/Radio.js"),require("../../Inputs/TextField/TextField.js"),require("../../Inputs/CommentArea/CommentArea.js");var o=require("../../Inputs/IconButtonDropdown/IconButtonDropdown.js");require("../../Inputs/FilterChip/FilterChip.js");exports.Menu=({type:u="main",variant:p="white",name:l,isSelected:c=!1,badgeCount:m,leadingIcon:d,iconButtonName:y,onClick:I,onOptionClick:g,href:j,items:h,selectedItem:q,onItemClick:x})=>{const C=!!(y&&h&&x&&q),w=!!y&&!!g,B=(e,r,s)=>{const n="sub"===e?"pl-12":"",i={white:t.twJoin("hover:bg-w-gray-50",s&&"bg-primary-10 text-primary hover:bg-primary-10"),gray:t.twJoin("hover:bg-w-gray-100",s&&"bg-w-gray-100 hover:bg-w-gray-100")};return t.twMerge("flex w-full cursor-pointer items-center gap-2 rounded-xl px-4 py-3 text-w-gray-900 text-left",n,i[r])},v=/*#__PURE__*/e.jsxs(e.Fragment,{children:[d&&/*#__PURE__*/e.jsx(i.SystemIcon,{testId:"design-system-menu-leading-icon",name:d,className:t.twJoin("white"===p&&c&&"text-primary")}),
2
- /*#__PURE__*/e.jsx(n.Typography,{"data-testid":"design-system-menu-name",variant:"body16",className:"w-full select-none",children:l}),m&&/*#__PURE__*/e.jsx(s.CountBadge,{variant:((e,t)=>"white"!==e?"white_gray":t?"primary":"gray")(p,c),text:m,className:"relative",showZero:!0}),C&&/*#__PURE__*/e.jsx(o.IconButtonDropdown,{size:"sm",icon:y,items:h,selectedItem:q,onItemClick:x}),w&&/*#__PURE__*/e.jsx(a.IconButton,{size:"sm",className:"shrink-0",onClick:e=>{e.stopPropagation(),g()},children:/*#__PURE__*/e.jsx(i.SystemIcon,{name:y})})]});return j?/*#__PURE__*/e.jsx(r,{href:j,"data-testid":"design-system-menu",className:B(u,p,c),children:v}):/*#__PURE__*/e.jsx("button",{"data-testid":"design-system-menu",className:B(u,p,c),onClick:I,children:v})};