react-admin-crud-manager 1.1.2 → 1.2.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 (28) hide show
  1. package/README.md +1322 -207
  2. package/dist/index.cjs.js +20 -55
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.es.js +4092 -2529
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/types/components/Details/Details.d.ts +11 -0
  7. package/dist/types/components/Details/components/CardGroup.d.ts +9 -1
  8. package/dist/types/components/Details/components/DetailRow.d.ts +9 -1
  9. package/dist/types/components/Details/components/GroupRow.d.ts +9 -1
  10. package/dist/types/components/Filter/FilterDrawer.d.ts +2 -2
  11. package/dist/types/components/Form/components/AudioPicker.d.ts +2 -1
  12. package/dist/types/components/Form/components/Checkbox.d.ts +2 -1
  13. package/dist/types/components/Form/components/ImagePicker.d.ts +2 -1
  14. package/dist/types/components/Form/components/Input.d.ts +1 -0
  15. package/dist/types/components/Form/components/MultiImagePicker.d.ts +21 -0
  16. package/dist/types/components/Form/components/PhoneInput.d.ts +2 -1
  17. package/dist/types/components/Form/components/Radio.d.ts +2 -1
  18. package/dist/types/components/Form/components/RenderFields.d.ts +3 -2
  19. package/dist/types/components/Form/components/Select.d.ts +5 -2
  20. package/dist/types/components/Form/components/Switch.d.ts +1 -0
  21. package/dist/types/components/Form/components/TextArea.d.ts +2 -0
  22. package/dist/types/components/Form/components/TinyEditor.d.ts +3 -1
  23. package/dist/types/components/Form/components/VideoPicker.d.ts +2 -1
  24. package/dist/types/components/Modal/Modal.d.ts +10 -1
  25. package/dist/types/lib/crudClasses.d.ts +94 -0
  26. package/dist/types/types/crudtypes.d.ts +51 -0
  27. package/package.json +10 -8
  28. package/dist/tailwind.css +0 -2364
@@ -3,6 +3,17 @@ interface DetailsProps {
3
3
  config: {
4
4
  fields?: Array<Record<string, any>>;
5
5
  containerClass?: string;
6
+ variant?: "default" | "card" | "split";
7
+ styles?: {
8
+ containerClass?: string;
9
+ rowClass?: string;
10
+ groupClass?: string;
11
+ cardGroupClass?: string;
12
+ labelClass?: string;
13
+ valueClass?: string;
14
+ iconClass?: string;
15
+ mediaGridClass?: string;
16
+ };
6
17
  };
7
18
  fetchRowDetails?: (payload: Record<string, any>) => Promise<{
8
19
  data: Record<string, any>;
@@ -1,6 +1,14 @@
1
1
  interface CardGroupProps {
2
2
  col: Record<string, any>;
3
3
  data: Record<string, any>;
4
+ uiVariant?: "default" | "card" | "split";
5
+ styleConfig?: {
6
+ rowClass?: string;
7
+ cardGroupClass?: string;
8
+ labelClass?: string;
9
+ valueClass?: string;
10
+ iconClass?: string;
11
+ };
4
12
  }
5
- declare const CardGroup: ({ col, data }: CardGroupProps) => import("react/jsx-runtime").JSX.Element;
13
+ declare const CardGroup: ({ col, data, uiVariant, styleConfig, }: CardGroupProps) => import("react/jsx-runtime").JSX.Element;
6
14
  export default CardGroup;
@@ -1,6 +1,14 @@
1
1
  interface DetailRowProps {
2
2
  col: Record<string, any>;
3
3
  data: Record<string, any>;
4
+ uiVariant?: "default" | "card" | "split";
5
+ styleConfig?: {
6
+ rowClass?: string;
7
+ labelClass?: string;
8
+ valueClass?: string;
9
+ iconClass?: string;
10
+ mediaGridClass?: string;
11
+ };
4
12
  }
5
- declare const DetailRow: ({ col, data }: DetailRowProps) => import("react/jsx-runtime").JSX.Element;
13
+ declare const DetailRow: ({ col, data, uiVariant, styleConfig, }: DetailRowProps) => import("react/jsx-runtime").JSX.Element;
6
14
  export default DetailRow;
@@ -1,6 +1,14 @@
1
1
  interface GroupRowProps {
2
2
  col: Record<string, any>;
3
3
  data: Record<string, any>;
4
+ uiVariant?: "default" | "card" | "split";
5
+ styleConfig?: {
6
+ rowClass?: string;
7
+ groupClass?: string;
8
+ labelClass?: string;
9
+ valueClass?: string;
10
+ iconClass?: string;
11
+ };
4
12
  }
5
- declare const GroupRow: ({ col, data }: GroupRowProps) => import("react/jsx-runtime").JSX.Element;
13
+ declare const GroupRow: ({ col, data, uiVariant, styleConfig, }: GroupRowProps) => import("react/jsx-runtime").JSX.Element;
6
14
  export default GroupRow;
@@ -1,11 +1,11 @@
1
1
  import React from "react";
2
- import { type FieldConfig } from "../Form/components/RenderFields";
2
+ import { FormField } from "../../types/crudtypes";
3
3
  interface FilterConfig {
4
4
  component: React.ComponentType<{
5
5
  filters: Record<string, any>;
6
6
  onFilterChange: (key: string, value: any) => void;
7
7
  }>;
8
- fields: FieldConfig[];
8
+ fields: Array<FormField>;
9
9
  }
10
10
  interface FilterDrawerProps {
11
11
  isOpen: boolean;
@@ -13,6 +13,7 @@ interface AudioPickerProps {
13
13
  name: string;
14
14
  parentClass?: string;
15
15
  maxSize?: number;
16
+ errorMessage?: string;
16
17
  }
17
- declare const AudioPicker: ({ label, value, onChange, required, accept, id, dragDrop, name, parentClass, maxSize, }: AudioPickerProps) => import("react/jsx-runtime").JSX.Element;
18
+ declare const AudioPicker: ({ label, value, onChange, required, accept, id, dragDrop, name, parentClass, errorMessage, maxSize, }: AudioPickerProps) => import("react/jsx-runtime").JSX.Element;
18
19
  export default AudioPicker;
@@ -14,6 +14,7 @@ interface CheckboxProps {
14
14
  parentClass?: string;
15
15
  className?: string;
16
16
  multiSelect?: boolean;
17
+ errorMessage?: string;
17
18
  }
18
- declare const Checkbox: ({ name, label, options, value, onChange, disabled, required, parentClass, className, multiSelect, }: CheckboxProps) => import("react/jsx-runtime").JSX.Element;
19
+ declare const Checkbox: ({ name, label, options, value, onChange, disabled, required, parentClass, className, errorMessage, multiSelect, }: CheckboxProps) => import("react/jsx-runtime").JSX.Element;
19
20
  export default Checkbox;
@@ -14,6 +14,7 @@ interface ImagePickerProps {
14
14
  cropImage?: boolean;
15
15
  name: string;
16
16
  parentClass?: string;
17
+ errorMessage?: string;
17
18
  }
18
- declare const ImagePicker: ({ label, value, onChange, required, accept, aspect, id, dragDrop, cropImage, name, parentClass, }: ImagePickerProps) => import("react/jsx-runtime").JSX.Element;
19
+ declare const ImagePicker: ({ label, value, onChange, required, accept, aspect, id, dragDrop, cropImage, name, parentClass, errorMessage, }: ImagePickerProps) => import("react/jsx-runtime").JSX.Element;
19
20
  export default ImagePicker;
@@ -13,6 +13,7 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
13
13
  onChange: (value: any) => void;
14
14
  mask?: string;
15
15
  maskApplyOnValue?: boolean;
16
+ errorMessage?: string;
16
17
  }
17
18
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
18
19
  export { Input };
@@ -0,0 +1,21 @@
1
+ type ImageValueItem = File | {
2
+ file?: File;
3
+ preview?: string;
4
+ } | string;
5
+ interface MultiImagePickerProps {
6
+ label?: string;
7
+ value: ImageValueItem[];
8
+ onChange: (files: ImageValueItem[]) => void;
9
+ required?: boolean;
10
+ accept?: string;
11
+ aspect?: number | string;
12
+ id: string;
13
+ dragDrop?: boolean;
14
+ cropImage?: boolean;
15
+ name: string;
16
+ parentClass?: string;
17
+ maxImages?: number;
18
+ errorMessage?: string;
19
+ }
20
+ declare const MultiImagePicker: ({ label, value, onChange, required, accept, aspect, id, dragDrop, cropImage, name, parentClass, maxImages, errorMessage, }: MultiImagePickerProps) => import("react/jsx-runtime").JSX.Element;
21
+ export default MultiImagePicker;
@@ -10,6 +10,7 @@ interface PhoneInputProps {
10
10
  search?: boolean;
11
11
  countriesList?: boolean;
12
12
  defaultCountry?: string;
13
+ errorMessage?: string;
13
14
  }
14
- export default function PhoneInput({ label, value, name, parentClass, onChange, disabled, required, placeholder, search, countriesList, defaultCountry, }: PhoneInputProps): import("react/jsx-runtime").JSX.Element;
15
+ export default function PhoneInput({ label, value, name, parentClass, onChange, disabled, required, placeholder, search, countriesList, defaultCountry, errorMessage, }: PhoneInputProps): import("react/jsx-runtime").JSX.Element;
15
16
  export {};
@@ -12,6 +12,7 @@ interface RadioProps {
12
12
  name: string;
13
13
  disabled?: boolean;
14
14
  parentClass?: string;
15
+ errorMessage?: string;
15
16
  }
16
- declare const Radio: ({ value, onChange, text, options, label, required, name, disabled, parentClass, }: RadioProps) => import("react/jsx-runtime").JSX.Element;
17
+ declare const Radio: ({ value, onChange, text, options, label, required, name, disabled, parentClass, errorMessage, }: RadioProps) => import("react/jsx-runtime").JSX.Element;
17
18
  export default Radio;
@@ -1,4 +1,4 @@
1
- export interface FieldConfig {
1
+ interface FieldConfig {
2
2
  key: string;
3
3
  label?: string;
4
4
  type?: string;
@@ -35,8 +35,9 @@ export interface FieldConfig {
35
35
  }
36
36
  interface RenderFieldsProps {
37
37
  field: FieldConfig;
38
+ errorMessage?: string;
38
39
  formData: Record<string, any>;
39
40
  handleChange: (key: string, value: any) => void;
40
41
  }
41
- declare const RenderFields: ({ field, formData, handleChange }: RenderFieldsProps) => import("react/jsx-runtime").JSX.Element | null;
42
+ declare const RenderFields: ({ field, formData, handleChange, errorMessage, }: RenderFieldsProps) => import("react/jsx-runtime").JSX.Element | null;
42
43
  export default RenderFields;
@@ -2,9 +2,10 @@ import React from "react";
2
2
  interface SelectOption {
3
3
  label: string;
4
4
  value: any;
5
+ code?: string;
5
6
  }
6
7
  interface SelectProps {
7
- options: SelectOption[] | ((formData: Record<string, any>) => Promise<SelectOption[]> | SelectOption[]);
8
+ options?: SelectOption[] | ((formData: Record<string, any>) => Promise<SelectOption[]> | SelectOption[]);
8
9
  value: any;
9
10
  defaultValue?: any;
10
11
  onChange: (value: any) => void;
@@ -20,6 +21,8 @@ interface SelectProps {
20
21
  dropdownMaxHeight?: string | number;
21
22
  formData: Record<string, any>;
22
23
  dependencyKey?: string;
24
+ countriesList?: boolean;
25
+ errorMessage?: string;
23
26
  }
24
- declare const Select: ({ options, value, defaultValue, onChange, placeholder, className, disabled, search, label, required, name, parentClass, multiple, dropdownMaxHeight, formData, dependencyKey, }: SelectProps) => import("react/jsx-runtime").JSX.Element;
27
+ declare const Select: ({ options, value, defaultValue, onChange, placeholder, className, disabled, search, label, required, name, parentClass, multiple, dropdownMaxHeight, formData, countriesList, dependencyKey, errorMessage, }: SelectProps) => import("react/jsx-runtime").JSX.Element;
25
28
  export default Select;
@@ -8,6 +8,7 @@ interface SwitchProps {
8
8
  onChange: (checked: boolean) => void;
9
9
  disabled?: boolean;
10
10
  name: string;
11
+ errorMessage?: string;
11
12
  }
12
13
  declare const Switch: React.ForwardRefExoticComponent<SwitchProps & React.RefAttributes<HTMLInputElement>>;
13
14
  export { Switch };
@@ -4,6 +4,8 @@ interface TextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement
4
4
  required?: boolean;
5
5
  parentClass?: string;
6
6
  className?: string;
7
+ errorMessage?: string;
8
+ name: string;
7
9
  }
8
10
  declare const TextArea: React.ForwardRefExoticComponent<TextAreaProps & React.RefAttributes<HTMLTextAreaElement>>;
9
11
  export { TextArea };
@@ -1,6 +1,7 @@
1
1
  interface TinyEditorProps {
2
2
  editorKey: string;
3
3
  value: string;
4
+ name: string;
4
5
  onChange: (content: string) => void;
5
6
  label?: string;
6
7
  required?: boolean;
@@ -14,7 +15,8 @@ interface TinyEditorProps {
14
15
  menubar?: boolean;
15
16
  fontFamily?: string;
16
17
  initConfig?: Record<string, any>;
18
+ errorMessage?: string;
17
19
  imageUploadHandler?: (blobInfo: any) => Promise<string>;
18
20
  }
19
- declare const TinyEditor: ({ editorKey, value, onChange, label, required, placeholder, parentClass, height, inline, disabled, plugins, toolbar, menubar, fontFamily, initConfig, imageUploadHandler, }: TinyEditorProps) => import("react/jsx-runtime").JSX.Element;
21
+ declare const TinyEditor: ({ editorKey, value, name, onChange, label, required, placeholder, parentClass, height, inline, disabled, plugins, toolbar, menubar, fontFamily, initConfig, imageUploadHandler, errorMessage, }: TinyEditorProps) => import("react/jsx-runtime").JSX.Element;
20
22
  export default TinyEditor;
@@ -13,6 +13,7 @@ interface VideoPickerProps {
13
13
  name: string;
14
14
  parentClass?: string;
15
15
  maxSize?: number;
16
+ errorMessage?: string;
16
17
  }
17
- declare const VideoPicker: ({ label, value, onChange, required, accept, id, dragDrop, name, parentClass, maxSize, }: VideoPickerProps) => import("react/jsx-runtime").JSX.Element;
18
+ declare const VideoPicker: ({ label, value, onChange, required, accept, id, dragDrop, name, parentClass, maxSize, errorMessage, }: VideoPickerProps) => import("react/jsx-runtime").JSX.Element;
18
19
  export default VideoPicker;
@@ -15,6 +15,15 @@ interface ModalProps {
15
15
  loading?: boolean;
16
16
  executeFunction?: (...args: any[]) => void;
17
17
  selectedItem?: any;
18
+ classNames?: {
19
+ overlay?: string;
20
+ container?: string;
21
+ header?: string;
22
+ title?: string;
23
+ body?: string;
24
+ footer?: string;
25
+ closeButton?: string;
26
+ };
18
27
  }
19
- declare const Modal: ({ isOpen, onClose, icon, title, children, size, actionButtons, onFormSubmit, loadingBtn, executeFunction, selectedItem, }: ModalProps) => import("react/jsx-runtime").JSX.Element | null;
28
+ declare const Modal: ({ isOpen, onClose, icon, title, children, size, actionButtons, onFormSubmit, loadingBtn, executeFunction, selectedItem, footerConfig, classNames, }: ModalProps) => import("react/jsx-runtime").JSX.Element | null;
20
29
  export default Modal;
@@ -0,0 +1,94 @@
1
+ type ClassValue = string | null | undefined | false;
2
+ export declare const joinClasses: (...classes: ClassValue[]) => string;
3
+ export declare const crudClasses: {
4
+ readonly crudPage: {
5
+ readonly root: "crud_page";
6
+ readonly deleteContent: "crud_page_delete_content";
7
+ };
8
+ readonly button: {
9
+ readonly root: "crud_button";
10
+ };
11
+ readonly chip: {
12
+ readonly root: "crud_chip";
13
+ };
14
+ readonly spinner: {
15
+ readonly root: "crud_spinner";
16
+ };
17
+ readonly modal: {
18
+ readonly root: "crud_modal";
19
+ readonly overlay: "crud_modal_overlay";
20
+ readonly container: "crud_modal_container";
21
+ readonly header: "crud_modal_header";
22
+ readonly title: "crud_modal_title";
23
+ readonly closeButton: "crud_modal_close_button";
24
+ readonly body: "crud_modal_body";
25
+ readonly footer: "crud_modal_footer";
26
+ readonly actionButton: "crud_modal_action_button";
27
+ readonly loadingIndicator: "crud_modal_loading_indicator";
28
+ };
29
+ readonly table: {
30
+ readonly root: "crud_table";
31
+ readonly toolbar: "crud_table_toolbar";
32
+ readonly searchField: "crud_table_search_field";
33
+ readonly searchInput: "crud_table_search_input";
34
+ readonly container: "crud_table_container";
35
+ readonly element: "crud_table_element";
36
+ readonly head: "crud_table_head";
37
+ readonly headRow: "crud_table_head_row";
38
+ readonly headCell: "crud_table_head_cell";
39
+ readonly body: "crud_table_body";
40
+ readonly row: "crud_table_row";
41
+ readonly cell: "crud_table_cell";
42
+ readonly noData: "crud_table_no_data";
43
+ readonly actionButton: "crud_table_action_button";
44
+ readonly menu: "crud_table_menu";
45
+ readonly menuItem: "crud_table_menu_item";
46
+ readonly pagination: "crud_table_pagination";
47
+ };
48
+ readonly tableSkeleton: {
49
+ readonly root: "crud_table_skeleton";
50
+ readonly table: "crud_table_skeleton_table";
51
+ };
52
+ readonly sortDropdown: {
53
+ readonly root: "crud_sort_dropdown";
54
+ readonly trigger: "crud_sort_dropdown_trigger";
55
+ readonly menu: "crud_sort_dropdown_menu";
56
+ readonly item: "crud_sort_dropdown_item";
57
+ };
58
+ readonly imagePreview: {
59
+ readonly root: "crud_image_preview";
60
+ readonly container: "crud_image_preview_container";
61
+ readonly image: "crud_image_preview_image";
62
+ };
63
+ readonly filterDrawer: {
64
+ readonly overlay: "crud_filter_overlay";
65
+ readonly panel: "crud_filter_panel";
66
+ readonly header: "crud_filter_header";
67
+ readonly body: "crud_filter_body";
68
+ readonly footer: "crud_filter_footer";
69
+ };
70
+ readonly form: {
71
+ readonly root: "crud_form";
72
+ readonly loading: "crud_form_loading";
73
+ };
74
+ readonly field: {
75
+ readonly wrapper: "crud_field_wrapper";
76
+ readonly label: "crud_field_label";
77
+ readonly input: "crud_field_input";
78
+ readonly error: "crud_field_error";
79
+ };
80
+ readonly mediaPicker: {
81
+ readonly image: "crud_media_image_picker";
82
+ readonly multiImage: "crud_media_multi_image_picker";
83
+ readonly audio: "crud_media_audio_picker";
84
+ readonly video: "crud_media_video_picker";
85
+ readonly dropzone: "crud_media_dropzone";
86
+ readonly cropModal: "crud_media_crop_modal";
87
+ };
88
+ readonly details: {
89
+ readonly root: "crud_details";
90
+ readonly container: "crud_details_container";
91
+ readonly row: "crud_details_row";
92
+ };
93
+ };
94
+ export {};
@@ -71,6 +71,7 @@ export interface FormField {
71
71
  maskApplyOnValue?: boolean;
72
72
  maxSize?: number;
73
73
  [key: string]: any;
74
+ customValidation?: (value: any) => boolean | string;
74
75
  }
75
76
  export interface ViewField {
76
77
  key?: string;
@@ -87,6 +88,25 @@ export interface ViewField {
87
88
  className?: string;
88
89
  format?: string;
89
90
  }
91
+ export interface ViewStyleConfig {
92
+ containerClass?: string;
93
+ rowClass?: string;
94
+ groupClass?: string;
95
+ cardGroupClass?: string;
96
+ labelClass?: string;
97
+ valueClass?: string;
98
+ iconClass?: string;
99
+ mediaGridClass?: string;
100
+ }
101
+ export interface ModalClassNames {
102
+ overlay?: string;
103
+ container?: string;
104
+ header?: string;
105
+ title?: string;
106
+ body?: string;
107
+ footer?: string;
108
+ closeButton?: string;
109
+ }
90
110
  export interface SearchConfig {
91
111
  enabled?: boolean;
92
112
  useServerSideSearch?: boolean;
@@ -129,12 +149,37 @@ export interface SortConfig {
129
149
  clearLabel?: string;
130
150
  onChange?: (payload: SortChangePayload) => void;
131
151
  }
152
+ export interface exportCSVConfig {
153
+ enabled?: boolean;
154
+ fileName?: string;
155
+ fields?: Array<{
156
+ label: string;
157
+ key: string;
158
+ }>;
159
+ }
160
+ export interface SortConfig {
161
+ enabled?: boolean;
162
+ useServerSideSorting?: boolean;
163
+ options?: Array<{
164
+ value: string;
165
+ label: string;
166
+ key: string;
167
+ order: string;
168
+ type?: string;
169
+ }>;
170
+ fields?: string[];
171
+ defaultValue?: string;
172
+ autoGenerate?: boolean;
173
+ clearLabel?: string;
174
+ onChange?: (payload: SortChangePayload) => void;
175
+ }
132
176
  export interface TableConfig {
133
177
  table_head: TableHead[];
134
178
  search?: SearchConfig;
135
179
  pagination?: PaginationConfig;
136
180
  filter?: FilterConfig;
137
181
  sort?: SortConfig;
182
+ exportCSV?: exportCSVConfig;
138
183
  }
139
184
  export interface ModalConfig {
140
185
  addModal?: {
@@ -168,6 +213,9 @@ export interface ModalConfig {
168
213
  confirmText?: string;
169
214
  referenceKey?: string;
170
215
  actionButtons?: ActionButton[];
216
+ action: (item: any) => Promise<{
217
+ targetObject: any;
218
+ } | null>;
171
219
  icon?: ReactNode;
172
220
  };
173
221
  viewModal?: {
@@ -177,6 +225,9 @@ export interface ModalConfig {
177
225
  data: any;
178
226
  }>;
179
227
  fields?: ViewField[];
228
+ variant?: "default" | "card" | "split";
229
+ styles?: ViewStyleConfig;
230
+ modalClassNames?: ModalClassNames;
180
231
  footer?: {
181
232
  cancelButton?: boolean;
182
233
  cancelText?: string;
package/package.json CHANGED
@@ -1,21 +1,22 @@
1
1
  {
2
2
  "name": "react-admin-crud-manager",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "A reusable React CRUD admin template with modular components.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
7
- "types": "dist/index.d.ts",
7
+ "types": "./dist/types/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
10
  "import": "./dist/index.es.js",
11
11
  "require": "./dist/index.cjs.js",
12
12
  "types": "./dist/types/index.d.ts"
13
- },
14
- "./dist/tailwind.css": "./dist/tailwind.css"
13
+ }
15
14
  },
16
15
  "files": [
17
- "dist",
18
- "dist/tailwind.css"
16
+ "dist"
17
+ ],
18
+ "sideEffects": [
19
+ "**/*.css"
19
20
  ],
20
21
  "keywords": [
21
22
  "react",
@@ -36,9 +37,9 @@
36
37
  },
37
38
  "scripts": {
38
39
  "dev": "vite",
39
- "build": "vite build && node build-css.js",
40
+ "build": "vite build && tsc --emitDeclarationOnly",
40
41
  "build:types": "tsc --emitDeclarationOnly",
41
- "build:all": "npm run build && npm run build:types",
42
+ "build:all": "npm run build",
42
43
  "preview": "vite preview"
43
44
  },
44
45
  "dependencies": {
@@ -59,6 +60,7 @@
59
60
  "@types/react-dom": "^19.2.3",
60
61
  "@vitejs/plugin-react": "^4.2.1",
61
62
  "autoprefixer": "10.4.15",
63
+ "postcss-cli": "^11.0.1",
62
64
  "tailwindcss": "3.3.3",
63
65
  "typescript": "^5.9.3",
64
66
  "vite": "^5.0.8"