create-react-scaffold-cli 0.1.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 (72) hide show
  1. package/bin/index.js +34 -0
  2. package/package.json +15 -0
  3. package/scripts/createProject.js +30 -0
  4. package/templates/base/.env +1 -0
  5. package/templates/base/.husky/pre-commit +1 -0
  6. package/templates/base/.husky/pre-push +0 -0
  7. package/templates/base/.prettierrc +8 -0
  8. package/templates/base/.vscode/extensions.json +8 -0
  9. package/templates/base/.vscode/settings.json +16 -0
  10. package/templates/base/eslint.config.js +48 -0
  11. package/templates/base/index.html +16 -0
  12. package/templates/base/jsconfig.json +7 -0
  13. package/templates/base/package.json +64 -0
  14. package/templates/base/postcss.config.mjs +7 -0
  15. package/templates/base/readme.md +97 -0
  16. package/templates/base/src/app/App.jsx +13 -0
  17. package/templates/base/src/app/Router.jsx +4 -0
  18. package/templates/base/src/app/app_readme.md +74 -0
  19. package/templates/base/src/app/index.css +1 -0
  20. package/templates/base/src/app/main.jsx +10 -0
  21. package/templates/base/src/app/middlewares/index.js +0 -0
  22. package/templates/base/src/app/providers/QueryProvider.jsx +75 -0
  23. package/templates/base/src/app/providers/index.js +1 -0
  24. package/templates/base/src/features/features_readme.md +102 -0
  25. package/templates/base/src/features/index.js +0 -0
  26. package/templates/base/src/features/sample/components/index.js +0 -0
  27. package/templates/base/src/features/sample/constants/index.js +0 -0
  28. package/templates/base/src/features/sample/constants/sample.constants.js +0 -0
  29. package/templates/base/src/features/sample/hooks/index.js +0 -0
  30. package/templates/base/src/features/sample/pages/index.js +0 -0
  31. package/templates/base/src/features/sample/sample.assets.js +0 -0
  32. package/templates/base/src/features/sample/sample.context.js +0 -0
  33. package/templates/base/src/features/sample/sample.navigations.js +0 -0
  34. package/templates/base/src/features/sample/sample.queryKeys.js +0 -0
  35. package/templates/base/src/features/sample/sample.routes.jsx +0 -0
  36. package/templates/base/src/shared/constants/app.constants.js +4 -0
  37. package/templates/base/src/shared/constants/assets.constants.js +0 -0
  38. package/templates/base/src/shared/constants/index.js +0 -0
  39. package/templates/base/src/shared/contexts/index.js +0 -0
  40. package/templates/base/src/shared/hooks/index.js +3 -0
  41. package/templates/base/src/shared/hooks/useBooleanState.js +19 -0
  42. package/templates/base/src/shared/hooks/useDebounce.js +17 -0
  43. package/templates/base/src/shared/hooks/useToggleState.js +11 -0
  44. package/templates/base/src/shared/layouts/index.js +0 -0
  45. package/templates/base/src/shared/libs/axios.js +6 -0
  46. package/templates/base/src/shared/libs/cn.js +7 -0
  47. package/templates/base/src/shared/libs/index.js +2 -0
  48. package/templates/base/src/shared/shared_readme.md +98 -0
  49. package/templates/base/src/shared/theme/index.js +1 -0
  50. package/templates/base/src/shared/theme/theme.js +2138 -0
  51. package/templates/base/src/shared/ui/Box.jsx +200 -0
  52. package/templates/base/src/shared/ui/Button.jsx +150 -0
  53. package/templates/base/src/shared/ui/Checkbox.jsx +112 -0
  54. package/templates/base/src/shared/ui/DropdownMenu.jsx +152 -0
  55. package/templates/base/src/shared/ui/Flex.jsx +151 -0
  56. package/templates/base/src/shared/ui/FlexItem.jsx +96 -0
  57. package/templates/base/src/shared/ui/FormField.jsx +184 -0
  58. package/templates/base/src/shared/ui/Grid.jsx +151 -0
  59. package/templates/base/src/shared/ui/GridItem.jsx +95 -0
  60. package/templates/base/src/shared/ui/Modal.jsx +43 -0
  61. package/templates/base/src/shared/ui/Scrollable.jsx +47 -0
  62. package/templates/base/src/shared/ui/Select.jsx +207 -0
  63. package/templates/base/src/shared/ui/Sheet.jsx +112 -0
  64. package/templates/base/src/shared/ui/Text.jsx +122 -0
  65. package/templates/base/src/shared/ui/Toaster.jsx +31 -0
  66. package/templates/base/src/shared/ui/index.js +1 -0
  67. package/templates/base/src/shared/utils/getClassName.js +5 -0
  68. package/templates/base/src/shared/utils/index.js +4 -0
  69. package/templates/base/src/shared/utils/memo.js +3 -0
  70. package/templates/base/src/shared/utils/parser.js +41 -0
  71. package/templates/base/src/shared/utils/tryCatch.js +13 -0
  72. package/templates/base/vite.config.js +19 -0
@@ -0,0 +1,200 @@
1
+ import React from 'react';
2
+ import {
3
+ marginLookup,
4
+ marginMdLookup,
5
+ marginLgLookup,
6
+ marginXLookup,
7
+ marginXMdLookup,
8
+ marginYLookup,
9
+ marginYMdLookup,
10
+ marginYLgLookup,
11
+ paddingLgLookup,
12
+ paddingLookup,
13
+ paddingMdLookup,
14
+ paddingXLgLookup,
15
+ paddingXLookup,
16
+ paddingXMdLookup,
17
+ paddingYLgLookup,
18
+ paddingYLookup,
19
+ paddingYMdLookup,
20
+ widthLookup,
21
+ widthMdLookup,
22
+ widthLgLookup,
23
+ marginXlLookup,
24
+ marginXXlLookup,
25
+ marginYXlLookup,
26
+ paddingXlLookup,
27
+ paddingXXlLookup,
28
+ paddingYXlLookup,
29
+ marginXlgLookup,
30
+ AnimationLookup,
31
+ AnimationMdLookup,
32
+ AnimationLgLookup,
33
+ AnimationXlLookup,
34
+ radiusLookup,
35
+ radiusMdLookup,
36
+ radiusLgLookup,
37
+ radiusXlLookup,
38
+ paddingY2XlLookup,
39
+ paddingX2XlLookup,
40
+ } from '../theme';
41
+ import { getClassName, memo } from '../utils';
42
+ import { cn } from '../libs';
43
+
44
+ /**
45
+ * @typedef {'base' | 'md' | 'lg' | 'xl' | '2xl'} Breakpoint
46
+ *
47
+ * @typedef {0
48
+ * | 0.5
49
+ * | 1
50
+ * | 1.5
51
+ * | 2
52
+ * | 2.5
53
+ * | 3
54
+ * | 3.5
55
+ * | 4
56
+ * | 5
57
+ * | 6
58
+ * | 7
59
+ * | 8
60
+ * | 9
61
+ * | 10
62
+ * | 11
63
+ * | 12
64
+ * | 14
65
+ * | 16
66
+ * | 20
67
+ * | 24
68
+ * | 28
69
+ * | 32
70
+ * | 36
71
+ * | 40} Size
72
+ *
73
+ *
74
+ * @typedef {0
75
+ * | 0.5
76
+ * | 1
77
+ * | 1.5
78
+ * | 2
79
+ * | 2.5
80
+ * | 3
81
+ * | 3.5
82
+ * | 4
83
+ * | 5
84
+ * | 6
85
+ * | 7
86
+ * | 8
87
+ * | 9
88
+ * | 10
89
+ * | 11
90
+ * | 12
91
+ * | 14
92
+ * | 16
93
+ * | 20
94
+ * | 24
95
+ * | 28
96
+ * | 32
97
+ * | 36
98
+ * | 40
99
+ * | fit
100
+ * | full
101
+ * | auto} Width
102
+ *
103
+ *
104
+ * @typedef {'sm' | 'rounded' | 'md' | 'lg' | 'xl' | 'full'} Radius
105
+ *
106
+ * @typedef {Size} Margin
107
+ *
108
+ * @typedef {Size} Padding
109
+ *
110
+ * @typedef {'x' | 'y'} Axis
111
+ *
112
+ * @typedef {object} ComponentProps
113
+ * @property {boolean | Record<Breakpoint, boolean>} [hide]
114
+ * @property {boolean | Record<Breakpoint, boolean>} [grow]
115
+ * @property {Margin
116
+ * | Record<Breakpoint, Margin>
117
+ * | Record<Axis, Margin>
118
+ * | Record<Axis, Record<Breakpoint, Margin>>} [margin]
119
+ * @property {Padding
120
+ * | Record<Breakpoint, Padding>
121
+ * | Record<Axis, Padding>
122
+ * | Record<Axis, Record<Breakpoint, Padding>>} [padding]
123
+ * @property {Width | Record<Breakpoint, Width>} [width]
124
+ * @property {Radius} [radius]
125
+ * @property {Animation} [animation]
126
+ * @param {React.ComponentProps<'div'> & ComponentProps} props
127
+ * @returns {JSX.Element}
128
+ */
129
+
130
+ const Component = (
131
+ { hide, grow, margin, radius, padding, width, animation, className, ...rest },
132
+ ref
133
+ ) => {
134
+ return (
135
+ <div
136
+ ref={ref}
137
+ className={cn(
138
+ typeof hide !== 'object' && hide === true ? 'hidden' : hide === false && 'block',
139
+ hide?.base === true ? 'hidden' : hide?.base === false && 'block',
140
+ hide?.md === true ? 'md:hidden' : hide?.md === false && 'md:block',
141
+ hide?.lg === true ? 'lg:hidden' : hide?.lg === false && 'lg:block',
142
+ typeof grow !== 'object' && grow === true ? 'h-full' : grow === false && 'h-auto',
143
+ grow?.base === true ? 'h-full' : grow?.base === false && 'h-auto',
144
+ grow?.md === true ? 'md:h-full' : grow?.md === false && 'md:h-auto',
145
+ grow?.lg === true ? 'lg:h-full' : grow?.lg === false && 'lg:h-auto',
146
+ typeof margin !== 'object' && getClassName(margin, marginLookup),
147
+ getClassName(margin?.base, marginLookup),
148
+ getClassName(margin?.md, marginMdLookup),
149
+ getClassName(margin?.lg, marginLgLookup),
150
+ getClassName(margin?.xl, marginXlLookup),
151
+ typeof margin?.x !== 'object' && getClassName(margin?.x, marginXLookup),
152
+ getClassName(margin?.x?.base, marginXLookup),
153
+ getClassName(margin?.x?.md, marginXMdLookup),
154
+ getClassName(margin?.x?.lg, marginXlgLookup),
155
+ getClassName(margin?.x?.xl, marginXXlLookup),
156
+ typeof margin?.y !== 'object' && getClassName(margin?.y, marginYLookup),
157
+ getClassName(margin?.y?.base, marginYLookup),
158
+ getClassName(margin?.y?.md, marginYMdLookup),
159
+ getClassName(margin?.y?.lg, marginYLgLookup),
160
+ getClassName(margin?.y?.xl, marginYXlLookup),
161
+ typeof padding !== 'object' && getClassName(padding, paddingLookup),
162
+ getClassName(padding?.base, paddingLookup),
163
+ getClassName(padding?.md, paddingMdLookup),
164
+ getClassName(padding?.lg, paddingLgLookup),
165
+ getClassName(padding?.xl, paddingXlLookup),
166
+ getClassName(padding?.['2xl'], paddingXlLookup),
167
+ typeof padding?.x !== 'object' && getClassName(padding?.x, paddingXLookup),
168
+ getClassName(padding?.x?.base, paddingXLookup),
169
+ getClassName(padding?.x?.md, paddingXMdLookup),
170
+ getClassName(padding?.x?.lg, paddingXLgLookup),
171
+ getClassName(padding?.x?.xl, paddingXXlLookup),
172
+ getClassName(padding?.x?.['2xl'], paddingX2XlLookup),
173
+ typeof padding?.y !== 'object' && getClassName(padding?.y, paddingYLookup),
174
+ getClassName(padding?.y?.base, paddingYLookup),
175
+ getClassName(padding?.y?.md, paddingYMdLookup),
176
+ getClassName(padding?.y?.lg, paddingYLgLookup),
177
+ getClassName(padding?.y?.xl, paddingYXlLookup),
178
+ getClassName(padding?.y?.['2xl'], paddingY2XlLookup),
179
+ typeof width !== 'object' && getClassName(width, widthLookup),
180
+ getClassName(width?.base, widthLookup),
181
+ getClassName(width?.md, widthMdLookup),
182
+ getClassName(width?.lg, widthLgLookup),
183
+ typeof font !== 'object' && getClassName(animation, AnimationLookup),
184
+ getClassName(animation?.base, AnimationLookup),
185
+ getClassName(animation?.md, AnimationMdLookup),
186
+ getClassName(animation?.lg, AnimationLgLookup),
187
+ getClassName(animation?.xl, AnimationXlLookup),
188
+ typeof radius !== 'object' && getClassName(radius, radiusLookup),
189
+ getClassName(radius?.base, radiusLookup),
190
+ getClassName(radius?.md, radiusMdLookup),
191
+ getClassName(radius?.lg, radiusLgLookup),
192
+ getClassName(radius?.xl, radiusXlLookup),
193
+ className
194
+ )}
195
+ {...rest}
196
+ />
197
+ );
198
+ };
199
+
200
+ export const Box = memo(React.forwardRef(Component));
@@ -0,0 +1,150 @@
1
+ import React from 'react';
2
+ import { PiSpinnerBold } from 'react-icons/pi';
3
+ import {
4
+ AnimationLookup,
5
+ colorLookup,
6
+ fieldSize2XlLookup,
7
+ fieldSizeLgLookup,
8
+ fieldSizeLookup,
9
+ fieldSizeMdLookup,
10
+ fieldSizeXlLookup,
11
+ fontFamilyLookup,
12
+ fontSize2xlLookup,
13
+ fontSizeLgLookup,
14
+ fontSizeLookup,
15
+ fontSizeMdLookup,
16
+ fontSizeXlLookup,
17
+ fontWeight2xlLookup,
18
+ fontWeightLgLookup,
19
+ fontWeightLookup,
20
+ fontWeightMdLookup,
21
+ fontWeightXlLookup,
22
+ radiusLgLookup,
23
+ radiusLookup,
24
+ radiusMdLookup,
25
+ radiusXlLookup,
26
+ } from '../theme';
27
+ import { getClassName, memo } from '../utils';
28
+
29
+ const variantLookup = {
30
+ primary:
31
+ 'text-primary-foreground bg-primary hover:bg-primary/90 disabled:text-primary-foreground/70 disabled:bg-primary/50',
32
+ outline:
33
+ 'border text-primary bg-primary-foreground hover:bg-neutral-50 disabled:text-primary/70 disabled:bg-neutral-50/50',
34
+ pill: 'text-primary-foreground bg-primary hover:bg-primary/90 disabled:text-primary-foreground/70 disabled:bg-primary/50 rounded-lg',
35
+ };
36
+
37
+ /**
38
+ * @typedef {'base' | 'md' | 'lg' | 'xl' | '2xl'} Breakpoint
39
+ *
40
+ * @typedef {'primary' | 'outline' | 'pill'} Variant
41
+ *
42
+ * @typedef {'xxxs' | 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'} Size
43
+ *
44
+ * @typedef {''} Font
45
+ *
46
+ * @typedef {'primary' | 'secondary' | 'success' | 'danger' | 'white' | 'black'} Color
47
+ *
48
+ * @typedef {'sm' | 'rounded' | 'md' | 'lg' | 'xl' | 'full'} Radius
49
+ *
50
+ * @typedef {'thin'
51
+ * | 'extralight'
52
+ * | 'light'
53
+ * | 'normal'
54
+ * | 'medium'
55
+ * | 'semibold'
56
+ * | 'bold'
57
+ * | 'extrabold'
58
+ * | 'black'} Weight
59
+ *
60
+ *
61
+ * @typedef {'xs'
62
+ * | 'sm'
63
+ * | 'base'
64
+ * | 'lg'
65
+ * | 'xl'
66
+ * | '2xl'
67
+ * | '3xl'
68
+ * | '4xl'
69
+ * | '5xl'
70
+ * | '6xl'
71
+ * | '7xl'
72
+ * | '8xl'
73
+ * | '9xl'} fontSize
74
+ *
75
+ *
76
+ * @typedef {object} ComponentProps
77
+ * @property {Variant} [variant]
78
+ * @property {Radius} [radius]
79
+ * @property {Size} [size]
80
+ * @property {Font} [font]
81
+ * @property {fontSize} [fontSize]
82
+ * @property {Weight} [weight]
83
+ * @property {boolean} [isLoading]
84
+ * @property {Color} [color]
85
+ * @param {React.ComponentProps<'button'> & ComponentProps} props
86
+ * @returns {JSX.Element}
87
+ */
88
+
89
+ const Component = (
90
+ {
91
+ variant = 'primary',
92
+ radius = 'lg',
93
+ size = 'lg',
94
+ font = 'inter',
95
+ fontSize = 'base',
96
+ weight = 'semibold',
97
+ color,
98
+ isLoading,
99
+ className,
100
+ animation,
101
+ type = 'button',
102
+ children,
103
+ ...rest
104
+ },
105
+ ref
106
+ ) => {
107
+ return (
108
+ <button
109
+ ref={ref}
110
+ className={cn(
111
+ 'h-12 px-4 w-full rounded-lg text-base font-inter font-semibold disabled:cursor-not-allowed transition-colors flex justify-center items-center',
112
+ typeof fontSize !== 'object' && getClassName(fontSize, fontSizeLookup),
113
+ getClassName(fontSize?.base, fontSizeLookup),
114
+ getClassName(fontSize?.md, fontSizeMdLookup),
115
+ getClassName(fontSize?.lg, fontSizeLgLookup),
116
+ getClassName(fontSize?.xl, fontSizeXlLookup),
117
+ getClassName(fontSize?.['2xl'], fontSize2xlLookup),
118
+ typeof weight !== 'object' && getClassName(weight, fontWeightLookup),
119
+ getClassName(weight?.base, fontWeightLookup),
120
+ getClassName(weight?.md, fontWeightMdLookup),
121
+ getClassName(weight?.lg, fontWeightLgLookup),
122
+ getClassName(weight?.xl, fontWeightXlLookup),
123
+ getClassName(weight?.['2xl'], fontWeight2xlLookup),
124
+ typeof size !== 'object' && getClassName(size, fieldSizeLookup),
125
+ getClassName(size?.base, fieldSizeLookup),
126
+ getClassName(size?.md, fieldSizeMdLookup),
127
+ getClassName(size?.lg, fieldSizeLgLookup),
128
+ getClassName(size?.xl, fieldSizeXlLookup),
129
+ getClassName(size?.['2xl'], fieldSize2XlLookup),
130
+ typeof radius !== 'object' && getClassName(radius, radiusLookup),
131
+ getClassName(radius?.base, radiusLookup),
132
+ getClassName(radius?.md, radiusMdLookup),
133
+ getClassName(radius?.lg, radiusLgLookup),
134
+ getClassName(radius?.xl, radiusXlLookup),
135
+ variantLookup[variant],
136
+ fontFamilyLookup[font],
137
+ colorLookup[color],
138
+ AnimationLookup[animation],
139
+ className
140
+ )}
141
+ type={type}
142
+ {...(isLoading && { disabled: true })}
143
+ {...rest}
144
+ >
145
+ {isLoading ? <PiSpinnerBold className="animate-spin size-5 m-auto" /> : children}
146
+ </button>
147
+ );
148
+ };
149
+
150
+ export const Button = memo(React.forwardRef(Component));
@@ -0,0 +1,112 @@
1
+ import React from 'react';
2
+ import {
3
+ sizeLookup,
4
+ sizeMdLookup,
5
+ sizeLgLookup,
6
+ fontSizeLookup,
7
+ fontSizeMdLookup,
8
+ fontSizeLgLookup,
9
+ fontWeightLookup,
10
+ fontWeightMdLookup,
11
+ fontWeightLgLookup,
12
+ } from '../theme';
13
+ import { getClassName, memo } from '../utils';
14
+
15
+ /**
16
+ *
17
+ *
18
+ * @typedef {'base' | 'md' | 'lg'} Breakpoint
19
+ *
20
+ * @typedef {0 | 0.5 | 1 | 1.5 | 2 | 2.5 | 3 | 3.5 | 4 | 5 | 6 | 7 | 8} Size
21
+ *
22
+ * @typedef {'xs'
23
+ * | 'sm'
24
+ * | 'base'
25
+ * | 'lg'
26
+ * | 'xl'
27
+ * | '2xl'
28
+ * | '3xl'
29
+ * | '4xl'
30
+ * | '5xl'
31
+ * | '6xl'
32
+ * | '7xl'
33
+ * | '8xl'
34
+ * | '9xl'} LabelFontSize
35
+ *
36
+ *
37
+ * @typedef {'thin'
38
+ * | 'extralight'
39
+ * | 'light'
40
+ * | 'normal'
41
+ * | 'medium'
42
+ * | 'semibold'
43
+ * | 'bold'
44
+ * | 'extrabold'
45
+ * | 'black'} LabelFontWeight
46
+ *
47
+ *
48
+ * @typedef {object} ComponentProps
49
+ * @property {Size | Record<Breakpoint, Size>} [size]
50
+ *
51
+ * - @property {LabelFontSize | Record<Breakpoint, LabelFontSize>} [labelFontSize]
52
+ *
53
+ * @property {LabelFontWeight | Record<Breakpoint, LabelFontWeight>} [labelFontWeight]
54
+ * @param {React.ComponentProps<'input'> & ComponentProps} props
55
+ * @returns {JSX.Element}
56
+ */
57
+
58
+ const Component = ({
59
+ label,
60
+ disabled = false,
61
+ className = '',
62
+ labelClass,
63
+ checkClass,
64
+ onChange,
65
+ size = { base: 4, md: 5 },
66
+ labelFontSize = { base: 'xs', md: 'sm', lg: 'base' },
67
+ labelFontWeight,
68
+ ...rest
69
+ }) => {
70
+ const id = React.useId();
71
+
72
+ return (
73
+ <div className={cn('flex items-center gap-2', className)}>
74
+ <input
75
+ type="checkbox"
76
+ disabled={disabled}
77
+ onChange={onChange}
78
+ className={cn(
79
+ ' border border-tertiary checked:bg-primary accent-primary transition-colors duration-200',
80
+ typeof size !== 'object' && getClassName(size, sizeLookup),
81
+ disabled && 'cursor-not-allowed bg-opacity-60',
82
+ getClassName(size?.base, sizeLookup),
83
+ getClassName(size?.md, sizeMdLookup),
84
+ getClassName(size?.lg, sizeLgLookup),
85
+ checkClass
86
+ )}
87
+ id={id}
88
+ {...rest}
89
+ />
90
+ <label
91
+ htmlFor={id}
92
+ className={cn(
93
+ 'text-secondary font-inter',
94
+ disabled && 'opacity-50 cursor-not-allowed',
95
+ typeof labelFontSize !== 'object' && getClassName(labelFontSize, fontSizeLookup),
96
+ getClassName(labelFontSize?.base, fontSizeLookup),
97
+ getClassName(labelFontSize?.md, fontSizeMdLookup),
98
+ getClassName(labelFontSize?.lg, fontSizeLgLookup),
99
+ typeof labelFontWeight !== 'object' && getClassName(labelFontWeight, fontWeightLookup),
100
+ getClassName(labelFontWeight?.base, fontWeightLookup),
101
+ getClassName(labelFontWeight?.md, fontWeightMdLookup),
102
+ getClassName(labelFontWeight?.lg, fontWeightLgLookup),
103
+ labelClass
104
+ )}
105
+ >
106
+ {label}
107
+ </label>
108
+ </div>
109
+ );
110
+ };
111
+
112
+ export const Checkbox = memo(Component);
@@ -0,0 +1,152 @@
1
+ import React from 'react';
2
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3
+ import { FaChevronRight } from 'react-icons/fa';
4
+ import { memo } from '@/utils';
5
+ import { cn } from '@/libs';
6
+
7
+ const DropdownMenuRoot = DropdownMenuPrimitive.Root;
8
+
9
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
10
+
11
+ const DropdownMenuSubTrigger = React.forwardRef(
12
+ ({ className, inset, children, ...props }, ref) => (
13
+ <DropdownMenuPrimitive.SubTrigger
14
+ ref={ref}
15
+ className={cn(
16
+ 'flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
17
+ inset && 'pl-8',
18
+ className
19
+ )}
20
+ {...props}
21
+ >
22
+ {children}
23
+ <FaChevronRight className="ml-auto" />
24
+ </DropdownMenuPrimitive.SubTrigger>
25
+ )
26
+ );
27
+ DropdownMenuSubTrigger.displayName =
28
+ DropdownMenuPrimitive.SubTrigger.displayName;
29
+
30
+ const DropdownMenuSubContent = React.forwardRef(
31
+ ({ className, ...props }, ref) => (
32
+ <DropdownMenuPrimitive.SubContent
33
+ ref={ref}
34
+ className={cn(
35
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
36
+ className
37
+ )}
38
+ {...props}
39
+ />
40
+ )
41
+ );
42
+ DropdownMenuSubContent.displayName =
43
+ DropdownMenuPrimitive.SubContent.displayName;
44
+
45
+ const DropdownMenuContent = React.forwardRef(
46
+ ({ className, sideOffset = 4, contentClassName, ...props }, ref) => (
47
+ <DropdownMenuPrimitive.Portal>
48
+ <DropdownMenuPrimitive.Content
49
+ ref={ref}
50
+ sideOffset={sideOffset}
51
+ className={cn(
52
+ 'z-50 min-w-[8rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow',
53
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
54
+ className,
55
+ contentClassName
56
+ )}
57
+ {...props}
58
+ />
59
+ </DropdownMenuPrimitive.Portal>
60
+ )
61
+ );
62
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
63
+
64
+ const DropdownMenuItem = React.forwardRef(
65
+ ({ className, inset, ...props }, ref) => (
66
+ <DropdownMenuPrimitive.Item
67
+ ref={ref}
68
+ className={cn(
69
+ 'relative flex select-none items-center gap-2 font-inter cursor-pointer rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
70
+ inset && 'pl-8',
71
+ className
72
+ )}
73
+ {...props}
74
+ />
75
+ )
76
+ );
77
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
78
+
79
+ const DropdownMenuLabel = React.forwardRef(
80
+ ({ className, inset, ...props }, ref) => (
81
+ <DropdownMenuPrimitive.Label
82
+ ref={ref}
83
+ className={cn(
84
+ 'px-2 py-1.5 text-sm font-semibold font-inter',
85
+ inset && 'pl-8',
86
+ className
87
+ )}
88
+ {...props}
89
+ />
90
+ )
91
+ );
92
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
93
+
94
+ const DropdownMenuSeparator = React.forwardRef(
95
+ ({ className, ...props }, ref) => (
96
+ <DropdownMenuPrimitive.Separator
97
+ ref={ref}
98
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
99
+ {...props}
100
+ />
101
+ )
102
+ );
103
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
104
+
105
+ const DropdownMenuShortcut = ({ className, ...props }) => {
106
+ return (
107
+ <span
108
+ className={cn('ml-auto text-xs tracking-widest opacity-60', className)}
109
+ {...props}
110
+ />
111
+ );
112
+ };
113
+ DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
114
+
115
+ /**
116
+ * @typedef {object} ComponentProps
117
+ * @property {boolean} [open]
118
+ * @property {(open: boolean) => void} [onOpenChange]
119
+ * @property {React.ReactNode} content
120
+ * @param {React.PropsWithChildren<ComponentProps>} props
121
+ * @returns {JSX.Element}
122
+ */
123
+
124
+ const Component = ({
125
+ open,
126
+ onOpenChange,
127
+ content,
128
+ children,
129
+ contentClassName,
130
+ }) => {
131
+ return (
132
+ <DropdownMenuRoot
133
+ className="border w-full "
134
+ open={open}
135
+ onOpenChange={onOpenChange}
136
+ >
137
+ <DropdownMenuTrigger className="w-full">{children}</DropdownMenuTrigger>
138
+ <DropdownMenuContent align="end" contentClassName={contentClassName}>
139
+ {content}
140
+ </DropdownMenuContent>
141
+ </DropdownMenuRoot>
142
+ );
143
+ };
144
+
145
+ const DropdownMenu = memo(Component);
146
+
147
+ export {
148
+ DropdownMenu,
149
+ DropdownMenuLabel,
150
+ DropdownMenuSeparator,
151
+ DropdownMenuItem,
152
+ };