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,43 @@
1
+ import React from 'react';
2
+ import * as Dialog from '@radix-ui/react-dialog';
3
+ import { Scrollable } from './Scrollable';
4
+ import { cn } from '../libs';
5
+
6
+ /**
7
+ * @typedef {object} ComponentProps
8
+ * @property {boolean} isOpen
9
+ * @property {() => void} onClose
10
+ * @property {string} [className]
11
+ * @param {React.PropsWithChildren & ComponentProps} props
12
+ * @returns {JSX.Element}
13
+ */
14
+
15
+ const Component = ({ isOpen, onClose, className, children }) => {
16
+ const onOpenChange = React.useCallback(
17
+ (isOpen) => {
18
+ if (isOpen) return;
19
+ onClose();
20
+ },
21
+ [onClose]
22
+ );
23
+
24
+ return (
25
+ <Dialog.Root open={isOpen} onOpenChange={onOpenChange}>
26
+ <Dialog.Portal>
27
+ <Dialog.Overlay className="fixed inset-0 z-50 bg-black/20 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" />
28
+ <Dialog.Content
29
+ aria-describedby={undefined}
30
+ className={cn(
31
+ 'fixed left-[50%] top-[50%] z-50 p-5 grid translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-2xl bg-white font-inter overflow-hidden',
32
+ className
33
+ )}
34
+ >
35
+ <Dialog.Title className="sr-only"></Dialog.Title>
36
+ <Scrollable indicatorClassName="!w-1">{children}</Scrollable>
37
+ </Dialog.Content>
38
+ </Dialog.Portal>
39
+ </Dialog.Root>
40
+ );
41
+ };
42
+
43
+ export const Modal = memo(Component);
@@ -0,0 +1,47 @@
1
+ import * as ScrollArea from '@radix-ui/react-scroll-area';
2
+ import { memo } from 'react';
3
+ import { cn } from '../libs';
4
+
5
+ /**
6
+ * @typedef {object} ComponentProps
7
+ * @property {'horizontal' | 'vertical'} [orientation]
8
+ * @property {string} [className]
9
+ * @property {string} [indicatorClassName]
10
+ * @param {React.PropsWithChildren<ComponentProps>} props
11
+ * @returns {JSX.Element}
12
+ */
13
+
14
+ const Component = ({
15
+ orientation = 'vertical',
16
+ className,
17
+ children,
18
+ style,
19
+ onClick,
20
+ indicatorClassName,
21
+ viewPortClassName,
22
+ }) => {
23
+ return (
24
+ <ScrollArea.Root
25
+ className={cn('size-full overflow-hidden', className)}
26
+ style={style}
27
+ onClick={onClick}
28
+ >
29
+ <ScrollArea.Viewport className={cn('size-full overflow-hidden', viewPortClassName)}>
30
+ {children}
31
+ </ScrollArea.Viewport>
32
+
33
+ <ScrollArea.Scrollbar
34
+ orientation={orientation}
35
+ className={cn(
36
+ orientation === 'vertical' ? 'w-1 lg:w-1.5 2xl:w-2' : 'h-1 lg:h-1.5 flex flex-col',
37
+ indicatorClassName
38
+ )}
39
+ >
40
+ <ScrollArea.Thumb className="relative flex-1 rounded bg-gray-400/50 hover:bg-gray-800/50 transition-colors" />
41
+ </ScrollArea.Scrollbar>
42
+ <ScrollArea.Corner />
43
+ </ScrollArea.Root>
44
+ );
45
+ };
46
+
47
+ export const Scrollable = memo(Component);
@@ -0,0 +1,207 @@
1
+ import React from 'react';
2
+ import * as SelectPrimitive from '@radix-ui/react-select';
3
+ import { FaChevronDown, FaChevronUp, FaCheck } from 'react-icons/fa6';
4
+ import { memo } from '../utils';
5
+ import { cn } from '../libs';
6
+
7
+ const SelectRoot = SelectPrimitive.Root;
8
+
9
+ const SelectValue = SelectPrimitive.Value;
10
+
11
+ const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
12
+ <SelectPrimitive.Trigger
13
+ ref={ref}
14
+ className={cn(
15
+ 'flex w-full items-center justify-between whitespace-nowrap rounded-10rd border bg-transparent px-3 py-2.5 font-inter text-sm placeholder:!text-custom-grey-900 placeholder:!opacity-30 disabled:cursor-not-allowed disabled:bg-neutral-50 [&>span]:line-clamp-1',
16
+ className
17
+ )}
18
+ {...props}
19
+ >
20
+ {children}
21
+ <SelectPrimitive.Icon asChild>
22
+ <FaChevronDown size={12} className="text-neutral-300" />
23
+ </SelectPrimitive.Icon>
24
+ </SelectPrimitive.Trigger>
25
+ ));
26
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
27
+
28
+ const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => (
29
+ <SelectPrimitive.ScrollUpButton
30
+ ref={ref}
31
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
32
+ {...props}
33
+ >
34
+ <FaChevronUp className="h-4 w-4" />
35
+ </SelectPrimitive.ScrollUpButton>
36
+ ));
37
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
38
+
39
+ const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) => (
40
+ <SelectPrimitive.ScrollDownButton
41
+ ref={ref}
42
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
43
+ {...props}
44
+ >
45
+ <FaChevronDown className="h-4 w-4" />
46
+ </SelectPrimitive.ScrollDownButton>
47
+ ));
48
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
49
+
50
+ const SelectContent = React.forwardRef(
51
+ ({ className, children, position = 'popper', ...props }, ref) => (
52
+ <SelectPrimitive.Portal>
53
+ <SelectPrimitive.Content
54
+ ref={ref}
55
+ className={cn(
56
+ 'relative z-[100] max-h-80 min-w-[8rem] font-inter overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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 w-[var(--radix-select-trigger-width)]',
57
+ position === 'popper' &&
58
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
59
+ className
60
+ )}
61
+ position={position}
62
+ {...props}
63
+ >
64
+ <SelectScrollUpButton className="text-secondary" />
65
+ <SelectPrimitive.Viewport
66
+ className={cn(
67
+ 'p-1',
68
+ position === 'popper' &&
69
+ 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] font-inter'
70
+ )}
71
+ >
72
+ {children}
73
+ </SelectPrimitive.Viewport>
74
+ <SelectScrollDownButton className="text-secondary" />
75
+ </SelectPrimitive.Content>
76
+ </SelectPrimitive.Portal>
77
+ )
78
+ );
79
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
80
+
81
+ const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (
82
+ <SelectPrimitive.Label
83
+ ref={ref}
84
+ className={cn('px-2 py-1.5 text-13fs font-semibold font-inter', className)}
85
+ {...props}
86
+ />
87
+ ));
88
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
89
+
90
+ const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => (
91
+ <SelectPrimitive.Item
92
+ ref={ref}
93
+ className={cn(
94
+ 'relative flex w-full cursor-pointer select-none items-center hover:bg-neutral-100 rounded-sm py-1.5 pl-2 pr-8 text-sm focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 outline-none',
95
+ className
96
+ )}
97
+ {...props}
98
+ >
99
+ <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
100
+ <SelectPrimitive.ItemIndicator>
101
+ <FaCheck className="h-4 w-4 text-secondary" />
102
+ </SelectPrimitive.ItemIndicator>
103
+ </span>
104
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
105
+ </SelectPrimitive.Item>
106
+ ));
107
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
108
+
109
+ const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (
110
+ <SelectPrimitive.Separator
111
+ ref={ref}
112
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
113
+ {...props}
114
+ />
115
+ ));
116
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
117
+
118
+ /**
119
+ *
120
+ *
121
+ * @template T
122
+ * @typedef {object} ComponentProps
123
+ * @property {string} [placeholder]
124
+ * @property {T[]} values
125
+ * @property {T | undefined} value
126
+ * @property {(value: T) => string | number} getValueId
127
+ * @property {(value: T) => React.ReactNode} getValueLabel
128
+ * @property {(value: T) => void} onChange
129
+ * @property {boolean} [fullWidth]
130
+ * @property {'xxxs' | 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'} [size]
131
+ * @property {'sm' | 'rounded' | 'md' | 'lg' | 'xl' | 'full'} [radius]
132
+ * @property {boolean} [disabled]
133
+ * @property {string} [className]
134
+ */
135
+
136
+ /**
137
+ *
138
+ *
139
+ * @template T
140
+ * @param {ComponentProps<T>} props
141
+ * @returns {JSX.Element}
142
+ */
143
+
144
+ const Component = ({
145
+ placeholder = 'Seleccionar...',
146
+ value,
147
+ values,
148
+ getValueId = ({ id }) => id,
149
+ getValueLabel = ({ name }) => name,
150
+ onChange,
151
+ fullWidth,
152
+ customOption,
153
+ disabled,
154
+ contentClass,
155
+ }) => {
156
+ let id;
157
+ if (value) {
158
+ id = getValueId(value);
159
+ }
160
+
161
+ const valuesLookup = React.useMemo(
162
+ () =>
163
+ values.reduce((values, value) => {
164
+ const id = getValueId(value);
165
+ values[id] = value;
166
+ return values;
167
+ }, {}),
168
+ [getValueId, values]
169
+ );
170
+
171
+ const onValueChange = React.useCallback(
172
+ (id) => {
173
+ const value = valuesLookup[id];
174
+ onChange(value);
175
+ },
176
+ [onChange, valuesLookup]
177
+ );
178
+
179
+ return (
180
+ <SelectRoot value={id} onValueChange={onValueChange} disabled={disabled}>
181
+ <SelectTrigger
182
+ className={cn(
183
+ 'outline-none bg-white',
184
+ fullWidth ? 'w-full' : 'w-64',
185
+ 'data-placeholder:text-black/25'
186
+ )}
187
+ >
188
+ <SelectValue placeholder={placeholder} />
189
+ </SelectTrigger>
190
+ <SelectContent className={contentClass}>
191
+ {values.map((value, key) => {
192
+ const id = getValueId(value);
193
+ const label = getValueLabel(value);
194
+
195
+ return (
196
+ <SelectItem key={key} value={id}>
197
+ {label}
198
+ </SelectItem>
199
+ );
200
+ })}
201
+ {customOption}
202
+ </SelectContent>
203
+ </SelectRoot>
204
+ );
205
+ };
206
+
207
+ export const Select = memo(Component);
@@ -0,0 +1,112 @@
1
+ import * as SheetPrimitive from '@radix-ui/react-dialog';
2
+ import { cn } from '../libs';
3
+
4
+ function Sheet({ ...props }) {
5
+ return <SheetPrimitive.Root data-slot="sheet" {...props} />;
6
+ }
7
+
8
+ function SheetTrigger({ ...props }) {
9
+ return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
10
+ }
11
+
12
+ function SheetClose({ ...props }) {
13
+ return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
14
+ }
15
+
16
+ function SheetPortal({ ...props }) {
17
+ return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
18
+ }
19
+
20
+ function SheetOverlay({ className, ...props }) {
21
+ return (
22
+ <SheetPrimitive.Overlay
23
+ data-slot="sheet-overlay"
24
+ className={cn(
25
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-40 bg-black/50',
26
+ className
27
+ )}
28
+ {...props}
29
+ />
30
+ );
31
+ }
32
+
33
+ function SheetContent({ className, children, side = 'right', ...props }) {
34
+ return (
35
+ <SheetPortal>
36
+ <SheetOverlay />
37
+ <SheetPrimitive.Content
38
+ data-slot="sheet-content"
39
+ className={cn(
40
+ 'bg-bg data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
41
+ side === 'right' &&
42
+ 'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
43
+ side === 'left' &&
44
+ 'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
45
+ side === 'top' &&
46
+ 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
47
+ side === 'bottom' &&
48
+ 'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
49
+ className
50
+ )}
51
+ {...props}
52
+ >
53
+ {children}
54
+ <SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
55
+ <XIcon className="size-4" />
56
+ <span className="sr-only">Close</span>
57
+ </SheetPrimitive.Close>
58
+ </SheetPrimitive.Content>
59
+ </SheetPortal>
60
+ );
61
+ }
62
+
63
+ function SheetHeader({ className, ...props }) {
64
+ return (
65
+ <div
66
+ data-slot="sheet-header"
67
+ className={cn('flex flex-col gap-1.5 p-4', className)}
68
+ {...props}
69
+ />
70
+ );
71
+ }
72
+
73
+ function SheetFooter({ className, ...props }) {
74
+ return (
75
+ <div
76
+ data-slot="sheet-footer"
77
+ className={cn('mt-auto flex flex-col gap-2 p-4', className)}
78
+ {...props}
79
+ />
80
+ );
81
+ }
82
+
83
+ function SheetTitle({ className, ...props }) {
84
+ return (
85
+ <SheetPrimitive.Title
86
+ data-slot="sheet-title"
87
+ className={cn('text-foreground font-semibold', className)}
88
+ {...props}
89
+ />
90
+ );
91
+ }
92
+
93
+ function SheetDescription({ className, ...props }) {
94
+ return (
95
+ <SheetPrimitive.Description
96
+ data-slot="sheet-description"
97
+ className={cn('text-muted-foreground text-sm', className)}
98
+ {...props}
99
+ />
100
+ );
101
+ }
102
+
103
+ export {
104
+ Sheet,
105
+ SheetTrigger,
106
+ SheetClose,
107
+ SheetContent,
108
+ SheetHeader,
109
+ SheetFooter,
110
+ SheetTitle,
111
+ SheetDescription,
112
+ };
@@ -0,0 +1,122 @@
1
+ import React from 'react';
2
+ import {
3
+ fontSizeLookup,
4
+ fontSizeMdLookup,
5
+ fontSizeLgLookup,
6
+ fontWeightLookup,
7
+ fontWeightMdLookup,
8
+ fontWeightLgLookup,
9
+ textAlignLookup,
10
+ textAlignMdLookup,
11
+ textAlignLgLookup,
12
+ colorLookup,
13
+ fontFamilyLookup,
14
+ fontFamilyMdLookup,
15
+ fontFamilyLgLookup,
16
+ fontSizeXlLookup,
17
+ fontWeightXlLookup,
18
+ textAlignXlLookup,
19
+ fontFamilyXlLookup,
20
+ fontSize2xlLookup,
21
+ fontWeight2xlLookup,
22
+ colorMdLookup,
23
+ colorLgLookup,
24
+ colorXlLookup,
25
+ } from '../theme';
26
+ import { cn } from '../libs';
27
+ import { getClassName } from '../utils';
28
+
29
+ /**
30
+ * @typedef {'base' | 'md' | 'lg' | 'xl' | '2xl'} Breakpoint
31
+ *
32
+ * @typedef {'xs'
33
+ * | 'sm'
34
+ * | 'base'
35
+ * | 'lg'
36
+ * | 'xl'
37
+ * | '2xl'
38
+ * | '3xl'
39
+ * | '4xl'
40
+ * | '5xl'
41
+ * | '6xl'
42
+ * | '7xl'
43
+ * | '8xl'
44
+ * | '9xl'} Size
45
+ *
46
+ *
47
+ * @typedef {'left' | 'center' | 'right' | 'justify' | 'start' | 'end'} Align
48
+ *
49
+ * @typedef {'thin'
50
+ * | 'extralight'
51
+ * | 'light'
52
+ * | 'normal'
53
+ * | 'medium'
54
+ * | 'semibold'
55
+ * | 'bold'
56
+ * | 'extrabold'
57
+ * | 'black'} Weight
58
+ *
59
+ *
60
+ * @typedef {''} Font
61
+ *
62
+ * @typedef {'primary' | 'secondary' | 'success' | 'danger' | 'white' | 'black'} Color
63
+ *
64
+ * @typedef {object} ComponentProps
65
+ * @property {Size | Record<Breakpoint, Size>} [size]
66
+ * @property {Weight | Record<Breakpoint, Weight>} [weight]
67
+ * @property {Font | Record<Breakpoint, Font>} [font]
68
+ * @property {Align | Record<Breakpoint, Align>} [align]
69
+ * @property {boolean | Record<Breakpoint, boolean>} [truncate]
70
+ * @property {Color | Record<Breakpoint, Color>} [color]
71
+ * @param {React.ComponentProps<'p'> & ComponentProps} props
72
+ * @returns {JSX.Element}
73
+ */
74
+
75
+ const Component = (
76
+ { size, weight, align, truncate, color, font, animation, className, ...rest },
77
+ ref
78
+ ) => {
79
+ return (
80
+ <p
81
+ ref={ref}
82
+ className={cn(
83
+ typeof size !== 'object' && getClassName(size, fontSizeLookup),
84
+ getClassName(size?.base, fontSizeLookup),
85
+ getClassName(size?.md, fontSizeMdLookup),
86
+ getClassName(size?.lg, fontSizeLgLookup),
87
+ getClassName(size?.xl, fontSizeXlLookup),
88
+ getClassName(size?.['2xl'], fontSize2xlLookup),
89
+ typeof weight !== 'object' && getClassName(weight, fontWeightLookup),
90
+ getClassName(weight?.base, fontWeightLookup),
91
+ getClassName(weight?.md, fontWeightMdLookup),
92
+ getClassName(weight?.lg, fontWeightLgLookup),
93
+ getClassName(weight?.xl, fontWeightXlLookup),
94
+ getClassName(weight?.['2xl'], fontWeight2xlLookup),
95
+ typeof align !== 'object' && getClassName(align, textAlignLookup),
96
+ getClassName(align?.base, textAlignLookup),
97
+ getClassName(align?.md, textAlignMdLookup),
98
+ getClassName(align?.lg, textAlignLgLookup),
99
+ getClassName(align?.xl, textAlignXlLookup),
100
+ typeof font !== 'object' && getClassName(font, fontFamilyLookup),
101
+ getClassName(font?.base, fontFamilyLookup),
102
+ getClassName(font?.md, fontFamilyMdLookup),
103
+ getClassName(font?.lg, fontFamilyLgLookup),
104
+ getClassName(font?.xl, fontFamilyXlLookup),
105
+ typeof font !== 'object' && getClassName(color, colorLookup),
106
+ getClassName(color?.base, colorLookup),
107
+ getClassName(color?.md, colorMdLookup),
108
+ getClassName(color?.lg, colorLgLookup),
109
+ getClassName(color?.xl, colorXlLookup),
110
+ typeof truncate !== 'object' && truncate && 'truncate',
111
+ truncate?.base && 'truncate',
112
+ truncate?.md && 'md:truncate',
113
+ truncate?.lg && 'lg:truncate',
114
+ truncate?.xl && 'xl:truncate',
115
+ className
116
+ )}
117
+ {...rest}
118
+ />
119
+ );
120
+ };
121
+
122
+ export const Text = memo(React.forwardRef(Component));
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { Toaster as Toasts } from 'react-hot-toast';
3
+
4
+ export const Toaster = React.memo(() => {
5
+ return (
6
+ <Toasts
7
+ position="top-right"
8
+ toastOptions={{
9
+ style: {
10
+ borderRadius: '8px',
11
+ fontSize: '13px',
12
+ background: '#fff',
13
+ color: '#000',
14
+ },
15
+ error: {
16
+ style: {
17
+ background: '#fe8686',
18
+ color: '#fff',
19
+ backdropFilter: 'blur(20px)',
20
+ },
21
+ },
22
+ success: {
23
+ style: {
24
+ background: '#c2fcbf',
25
+ backdropFilter: 'blur(20px)',
26
+ },
27
+ },
28
+ }}
29
+ />
30
+ );
31
+ });
@@ -0,0 +1 @@
1
+ export { Toaster } from './Toaster';
@@ -0,0 +1,5 @@
1
+ export const getClassName = (prop, lookup) => {
2
+ const isNullish = prop === undefined || prop === null;
3
+ if (isNullish) return;
4
+ return lookup[prop];
5
+ };
@@ -0,0 +1,4 @@
1
+ export { parseArray, parseJSON, parseNumberForValidator, parseString } from './parser';
2
+ export { tryCatch } from './tryCatch';
3
+ export { getClassName } from './getClassName';
4
+ export { memo } from './memo';
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+
3
+ export const memo = (Component) => React.memo(Component);
@@ -0,0 +1,41 @@
1
+ export const parseString = (value) => {
2
+ const fallback = '';
3
+ if (!value) return fallback;
4
+ const isString = typeof value === 'string';
5
+ if (!isString) return fallback;
6
+ return value;
7
+ };
8
+
9
+ export const parseArray = (value) => {
10
+ const fallback = [];
11
+ if (!value) return fallback;
12
+ const isArray = Array.isArray(value);
13
+ if (!isArray) return value;
14
+ return value;
15
+ };
16
+
17
+ export const parseNumberForValidator = (value) => {
18
+ const fallback = '';
19
+ if (!value) return fallback;
20
+ const isNullish = value === undefined || value === null;
21
+ if (isNullish) return fallback;
22
+ const isValid = typeof value === 'number';
23
+ if (!isValid) return fallback;
24
+ return fallback;
25
+ };
26
+
27
+ export const parseJSON = (value) => {
28
+ const fallback = {};
29
+ if (!value) return fallback;
30
+ const isNotValid = typeof value === 'string';
31
+ if (isNotValid) return fallback;
32
+ const isValid = typeof value === 'object';
33
+ if (isValid) return value;
34
+
35
+ try {
36
+ const parsed = JSON.parse(value);
37
+ return parsed;
38
+ } catch {
39
+ return fallback;
40
+ }
41
+ };
@@ -0,0 +1,13 @@
1
+ export const tryCatch = (fn, ...args) => {
2
+ try {
3
+ const result = fn(...args);
4
+
5
+ if (result instanceof Promise) {
6
+ return result.then((result) => [null, result]).catch((error) => [error, null]);
7
+ }
8
+
9
+ return [null, result];
10
+ } catch (error) {
11
+ return [error, null];
12
+ }
13
+ };
@@ -0,0 +1,19 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import path from "path";
4
+
5
+ // https://vite.dev/config/
6
+ export default defineConfig({
7
+ plugins: [react()],
8
+ resolve: {
9
+ alias: {
10
+ "@": path.resolve(import.meta.dirname, "./src"),
11
+ },
12
+ },
13
+ preview: {
14
+ port: 3000,
15
+ },
16
+ server: {
17
+ port: 3000,
18
+ },
19
+ });