react-admin-crud-manager 1.2.10 → 1.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@ A reusable React CRUD admin template with modular components for rapid admin das
10
10
  - Tailwind CSS for styling
11
11
  - Server-side and client-side data handling
12
12
  - Sorting, filtering, searching, and pagination support
13
- - Rich form fields including text, select, image upload, rich text editor, and more
13
+ - Rich form fields including text, select, image upload, file upload, rich text editor, and more
14
14
 
15
15
  ## Installation
16
16
 
@@ -22,13 +22,15 @@ npm install react-admin-crud-manager
22
22
 
23
23
  ### 1. Use the component
24
24
 
25
- ```
26
- import Crud from 'react-admin-crud-manager';
25
+ ```js
26
+ import Crud from "react-admin-crud-manager";
27
27
 
28
28
  function App() {
29
29
  const config = {
30
- title: 'Users',
31
- fetchData: async () => { /* fetch logic */ },
30
+ title: "Users",
31
+ fetchData: async () => {
32
+ /* fetch logic */
33
+ },
32
34
  // ...other config options
33
35
  };
34
36
  return <Crud config={config} />;
@@ -81,26 +83,26 @@ Below is a complete reference of the public props accepted by this package (type
81
83
  | `exportCSV` | object | Export data as CSV | `{ enabled: true, fileName: "users.csv", fields: [{ label: "Name", key: "name" }, ...] }` |
82
84
  | `rowClick` | function or boolean | Callback on table row click | `(row: object, rowIndex: number) => void` or `true` (setting true will open details) |
83
85
 
84
- <br>
86
+ `customButtons` can also be passed in `tableConfig` to render extra header toolbar buttons with custom click handlers. See [Custom Toolbar Buttons (Header)](#12-custom-toolbar-buttons-header).
85
87
 
86
88
  #### Table Column Object (`table_head[]`)
87
89
 
88
- | Key | Type | Description | Accepted Values / Example |
89
- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
90
- | `key` | string | Property name in row objects | `"id"`, `"name"`, `"email"` (must exist in data objects) |
91
- | `title` | string | Column header text | `"User ID"`, `"Full Name"`, `"Email Address"` |
92
- | `type` | string | Column renderer type | `"plain"` (default), `"index"` (row number), `"group"` (avatar+text), `"chip"` (badge), `"date"`, `"avatar"`, `"menu_actions"` |
93
- | `imageKey` | string | Image property for avatar/group types | `"profileImage"`, `"avatarUrl"` (path to image in data object) |
94
- | `titleKey` | string | Title property for group/avatar types | `"name"`, `"fullName"` (property key in data object) |
95
- | `subtitleKey` | string | Subtitle property for group/avatar types | `"email"`, `"department"` (property key in data object) |
96
- | `onClickDetails` | boolean | Clicking cell opens view details modal | `true`, `false` (default: `false`) |
97
- | `variant` | string | Chip styling variant | `"contained"`, `"outline"`, `"soft"` (used with `type: "chip"`) |
98
- | `chipOptions` | array | Map values to chip labels and colors; array of `{ value: string\|number\|boolean, label: string, color?: string }` | `[{ value: "active", label: "Active", color: "green" }, { value: "inactive", label: "Inactive", color: "red" }]` |
99
- | `defaultColor` | string | Default color for chips (if no match in chipOptions) | `"green"`, `"red"`, `"blue"`, `"yellow"`, `"purple"`, `"gray"`, etc. |
100
- | `className` | string | Custom CSS class for cell content | Tailwind classes: `"font-bold text-sm text-gray-600"` |
101
- | `format` | string | Date format pattern | `"DD MMM YYYY"`, `"YYYY-MM-DD"`, `"DD/MM/YYYY HH:mm"` (uses date-fns patterns) |
102
- | `menuList` | array | Action menu items; array of `{ title: string, type: string, variant?: string, icon?: ReactNode }` | `[{ title: "Edit", type: "edit", icon: <EditIcon /> }, { title: "Delete", type: "delete", icon: <TrashIcon /> }]` |
103
- | `render` | function | Custom cell renderer (overrides built-in logic) | `(row: object, rowIndex: number) => ReactNode`; e.g., `(row) => <span>{row.name.toUpperCase()}</span>` |
90
+ | Key | Type | Description | Accepted Values / Example |
91
+ | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
92
+ | `key` | string | Property name in row objects | `"id"`, `"name"`, `"email"` (must exist in data objects) |
93
+ | `title` | string | Column header text | `"User ID"`, `"Full Name"`, `"Email Address"` |
94
+ | `type` | string | Column renderer type | `"plain"` (default), `"index"` (row number), `"group"` (avatar+text), `"chip"` (badge), `"date"`, `"avatar"`, `"menu_actions"` |
95
+ | `imageKey` | string | Image property for avatar/group types | `"profileImage"`, `"avatarUrl"` (path to image in data object) |
96
+ | `titleKey` | string | Title property for group/avatar types | `"name"`, `"fullName"` (property key in data object) |
97
+ | `subtitleKey` | string | Subtitle property for group/avatar types | `"email"`, `"department"` (property key in data object) |
98
+ | `onClickDetails` | boolean | Clicking cell opens view details modal | `true`, `false` (default: `false`) |
99
+ | `variant` | string | Chip styling variant | `"contained"`, `"outline"`, `"soft"` (used with `type: "chip"`) |
100
+ | `chipOptions` | array | Map values to chip labels and colors; array of `{ value: string\|number\|boolean, label: string, color?: string }` | `[{ value: "active", label: "Active", color: "green" }, { value: "inactive", label: "Inactive", color: "red" }]` |
101
+ | `defaultColor` | string | Default color for chips (if no match in chipOptions) | `"green"`, `"red"`, `"blue"`, `"yellow"`, `"purple"`, `"gray"`, etc. |
102
+ | `className` | string | Custom CSS class for cell content | Tailwind classes: `"font-bold text-sm text-gray-600"` |
103
+ | `format` | string | Date format pattern | `"DD MMM YYYY"`, `"YYYY-MM-DD"`, `"DD/MM/YYYY HH:mm"` (uses date-fns patterns) |
104
+ | `menuList` | array | Action menu items; array of `{ title: string, type: string, variant?: string, icon?: ReactNode, onClick?: Function }` | `[{ title: "Edit", type: "edit", icon: <EditIcon /> }, { title: "Open", type: "custom", onClick: (event, row) => setShowModal(true) }]` |
105
+ | `render` | function | Custom cell renderer (overrides built-in logic) | `(row: object, rowIndex: number) => ReactNode`; e.g., `(row) => <span>{row.name.toUpperCase()}</span>` |
104
106
 
105
107
  ---
106
108
 
@@ -168,19 +170,19 @@ Used by `modalConfig.*.formFields`, `filterConfig.fields`, and `viewModal.fields
168
170
 
169
171
  #### Common Field Properties (All Types)
170
172
 
171
- | Key | Type | Required | Description | Accepted Values / Example |
172
- | ------------------ | -------- | -------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
173
- | `key` | string | Yes | Property name/identifier for form data | `"username"`, `"email"`, `"birth_date"` |
174
- | `label` | string | No | Human-readable label for the field | `"User Name"`, `"Email Address"`, `"Date of Birth"` |
175
- | `type` | string | Yes | Field type determining the input/renderer | `"text"`, `"number"`, `"email"`, `"password"`, `"select"`, `"checkbox"`, `"radio"`, `"switch"`, `"phone"`, `"textarea"`, `"image"`, `"video"`, `"audio"`, `"tinyEditor"`, `"group"` |
176
- | `required` | boolean | No | Field must have a value for form submission | `true`, `false` (default: `false`) |
177
- | `minLength` | number | No | Minimum character length (for text fields) | `5`, `10`, `50` |
178
- | `placeholder` | string | No | Placeholder text shown in empty field | `"Enter your name"`, `"user@example.com"` |
179
- | `disabled` | boolean | No | Field is disabled and read-only | `true`, `false` (default: `false`) |
180
- | `parentClass` | string | No | Custom CSS classes for field wrapper (grid) | Tailwind classes: `"col-span-6"`, `"col-span-12"` |
181
- | `renderCondition` | function | No | Show field based on form data | `(formData: Record<string, any>) => boolean`; e.g., `(data) => data.userType === 'admin'` |
182
- | `customValidation` | function | No | Custom validation logic | `(value: any) => boolean \| string`; return `false` for invalid, error message string, or `true` for valid |
183
- | `className` | string | No | Custom CSS class for input element | Tailwind classes: `"bg-gray-100 rounded-lg"` |
173
+ | Key | Type | Required | Description | Accepted Values / Example |
174
+ | ------------------ | -------- | -------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
175
+ | `key` | string | Yes | Property name/identifier for form data | `"username"`, `"email"`, `"birth_date"` |
176
+ | `label` | string | No | Human-readable label for the field | `"User Name"`, `"Email Address"`, `"Date of Birth"` |
177
+ | `type` | string | Yes | Field type determining the input/renderer | `"text"`, `"number"`, `"email"`, `"password"`, `"select"`, `"checkbox"`, `"radio"`, `"switch"`, `"phone"`, `"textarea"`, `"image"`, `"video"`, `"audio"`, `"file"`, `"tinyEditor"`, `"group"` |
178
+ | `required` | boolean | No | Field must have a value for form submission | `true`, `false` (default: `false`) |
179
+ | `minLength` | number | No | Minimum character length (for text fields) | `5`, `10`, `50` |
180
+ | `placeholder` | string | No | Placeholder text shown in empty field | `"Enter your name"`, `"user@example.com"` |
181
+ | `disabled` | boolean | No | Field is disabled and read-only | `true`, `false` (default: `false`) |
182
+ | `parentClass` | string | No | Custom CSS classes for field wrapper (grid) | Tailwind classes: `"col-span-6"`, `"col-span-12"` |
183
+ | `renderCondition` | function | No | Show field based on form data | `(formData: Record<string, any>) => boolean`; e.g., `(data) => data.userType === 'admin'` |
184
+ | `customValidation` | function | No | Custom validation logic | `(value: any) => boolean \| string`; return `false` for invalid, error message string, or `true` for valid |
185
+ | `className` | string | No | Custom CSS class for input element | Tailwind classes: `"bg-gray-100 rounded-lg"` |
184
186
 
185
187
  #### Type-Specific Properties
186
188
 
@@ -261,7 +263,7 @@ Used by `modalConfig.*.formFields`, `filterConfig.fields`, and `viewModal.fields
261
263
  | ---------- | ------- | --------------------------- | ----------------------------------------------- |
262
264
  | `accept` | string | MIME type filter | `"video/*"` (default), `"video/mp4,video/webm"` |
263
265
  | `dragDrop` | boolean | Enable drag-and-drop upload | `true`, `false` (default: `false`) |
264
- | `maxSize` | number | Maximum file size in bytes | `5242880` (5MB), `10485760` (10MB) |
266
+ | `maxSize` | number | Maximum file size in MB | `5`, `10`, `25` |
265
267
 
266
268
  ##### `"audio"` Field
267
269
 
@@ -269,7 +271,45 @@ Used by `modalConfig.*.formFields`, `filterConfig.fields`, and `viewModal.fields
269
271
  | ---------- | ------- | --------------------------- | ----------------------------------------------- |
270
272
  | `accept` | string | MIME type filter | `"audio/*"` (default), `"audio/mpeg,audio/wav"` |
271
273
  | `dragDrop` | boolean | Enable drag-and-drop upload | `true`, `false` (default: `false`) |
272
- | `maxSize` | number | Maximum file size in bytes | `5242880` (5MB), `10485760` (10MB) |
274
+ | `maxSize` | number | Maximum file size in MB | `5`, `10`, `25` |
275
+
276
+ ##### `"file"` Field
277
+
278
+ Upload any file type in add/edit forms, with client-side type restriction and file icon preview.
279
+
280
+ | Property | Type | Description | Accepted Values / Example |
281
+ | ---------- | ------- | ------------------------------------------------ | ------------------------------------------------------------------------ |
282
+ | `accept` | string | Allowed file types (same as native input accept) | `"*/*"` (default), `".pdf,.doc,.docx"`, `"application/pdf"`, `"image/*"` |
283
+ | `dragDrop` | boolean | Enable drag-and-drop upload | `true`, `false` (default: `false`) |
284
+ | `maxSize` | number | Maximum file size in MB | `5`, `10`, `25` |
285
+
286
+ Behavior:
287
+
288
+ - Validates selected/dropped file using `accept`
289
+ - Shows file icon automatically based on extension (pdf/doc/xls/ppt/zip/txt/json, etc.)
290
+ - Shows selected file name and allows replacing/removing the file
291
+
292
+ Example:
293
+
294
+ ```js
295
+ const formFields = [
296
+ {
297
+ key: "attachment",
298
+ label: "Attachment",
299
+ type: "file",
300
+ accept: ".pdf,.doc,.docx",
301
+ maxSize: 10, // MB
302
+ dragDrop: true,
303
+ required: true,
304
+ },
305
+ {
306
+ key: "contractFile",
307
+ label: "Contract",
308
+ type: "file",
309
+ accept: "application/pdf",
310
+ },
311
+ ];
312
+ ```
273
313
 
274
314
  ##### `"tinyEditor"` Field
275
315
 
@@ -714,13 +754,91 @@ const config = {
714
754
  };
715
755
  ```
716
756
 
757
+ ### 12. Custom Toolbar Buttons (Header)
758
+
759
+ Add custom buttons in the table header area (same area as Add / Search / Filter / Sort / Export), with your own click handlers.
760
+
761
+ ```js
762
+ import { Upload, RefreshCw } from "lucide-react";
763
+
764
+ const config = {
765
+ tableConfig: {
766
+ table_head: [...],
767
+ search: { enabled: true },
768
+ filter: { enabled: true },
769
+ sort: { enabled: true },
770
+ customButtons: [
771
+ {
772
+ key: "import",
773
+ label: "Import",
774
+ icon: <Upload className="w-4 h-4" />,
775
+ color: "primary",
776
+ variant: "contained",
777
+ onClick: (event, ctx) => {
778
+ // ctx has: data, filteredData, sortedData, paginatedData,
779
+ // searchTerm, appliedFilters, currentPage, pageSize, totalRecords
780
+ console.log("Import clicked", ctx.totalRecords);
781
+ },
782
+ },
783
+ {
784
+ key: "refresh",
785
+ label: "Refresh",
786
+ icon: <RefreshCw className="w-4 h-4" />,
787
+ variant: "outlined",
788
+ onClick: async () => {
789
+ // your custom logic
790
+ },
791
+ },
792
+ ],
793
+ customMenuItems: [
794
+ {
795
+ key: "bulk-actions",
796
+ label: "Bulk Action",
797
+ onClick: (event, ctx) => {
798
+ console.log("bulk action", ctx.filteredData.length);
799
+ },
800
+ },
801
+ {
802
+ key: "archive-all",
803
+ label: "Archive Filtered",
804
+ onClick: async (event, ctx) => {
805
+ // run async logic using current filtered records
806
+ },
807
+ },
808
+ ],
809
+ },
810
+ };
811
+ ```
812
+
813
+ Supported button properties:
814
+
815
+ - `key` (optional): unique key
816
+ - `label` (required): button text
817
+ - `icon` (optional): React node shown before label
818
+ - `variant` (optional): `contained`, `outlined`, `text`
819
+ - `color` (optional): `primary`, `success`, `error`, `default`
820
+ - `className` (optional): custom Tailwind/class string
821
+ - `disabled` (optional): disable button
822
+ - `show` (optional): set `false` to hide a button
823
+ - `onClick` (optional): `(event, context) => void | Promise<void>`
824
+
825
+ `customMenuItems` opens in a 3-dot menu button in the same header toolbar. Supported fields:
826
+
827
+ - `key` (optional): unique key
828
+ - `label` (required): menu item text
829
+ - `icon` (optional): React node before label
830
+ - `className` (optional): custom class string
831
+ - `disabled` (optional): disable item
832
+ - `show` (optional): set `false` to hide item
833
+ - `onClick` (optional): `(event, context) => void | Promise<void>`
834
+
717
835
  ### Primary Color Customization
718
836
 
719
837
  You can override the default primary color used across the UI by defining CSS variables in your global `:root`.
720
838
 
721
839
  Simply add the following variables to your main CSS file (e.g., `root.css`, `global.css`):
722
840
 
723
- ````css
841
+ ```css
724
842
  :root {
725
843
  --primary-50: #eff6ff;
726
844
  --primary-100: #dbeafe;
@@ -733,7 +851,8 @@ Simply add the following variables to your main CSS file (e.g., `root.css`, `glo
733
851
  --primary-800: #1e40af;
734
852
  --primary-900: #1e3a8a;
735
853
  }
736
- ````
854
+ ```
855
+
737
856
  ### CSS Class Customization
738
857
 
739
858
  The following table lists all available CSS classes that can be overridden to customize the UI.
@@ -880,7 +999,7 @@ function App() {
880
999
  }
881
1000
 
882
1001
  export default App;
883
- ````
1002
+ ```
884
1003
 
885
1004
  #### Example 2: Server-Side CRUD with Advanced Features
886
1005