nexstruct 1.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.
- package/AGENTS.md +122 -0
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/package.json +99 -0
- package/scaffold/generator.js +409 -0
- package/scaffold/index.js +20 -0
- package/scaffold/prompts.js +108 -0
- package/templates/api/axios/src/api/axios/client.api.ts +30 -0
- package/templates/api/axios/src/api/axios/users.api.ts +15 -0
- package/templates/api/fetch/src/api/fetch/client.api.ts +68 -0
- package/templates/api/fetch/src/api/fetch/users.api.ts +15 -0
- package/templates/api/trpc/src/api/trpc/client.api.ts +4 -0
- package/templates/api/trpc/src/api/trpc/router.api.ts +15 -0
- package/templates/api/trpc/src/api/trpc/server.client.api.ts +4 -0
- package/templates/api/trpc/src/providers/trpc.provider.tsx +24 -0
- package/templates/auth/clerk/src/auth/clerk/auth.service.ts +4 -0
- package/templates/auth/clerk/src/hooks/use-auth.hook.ts +13 -0
- package/templates/auth/clerk/src/middleware.ts +7 -0
- package/templates/auth/clerk/src/providers/auth.provider.tsx +6 -0
- package/templates/auth/next-auth/src/app/api/auth/[...nextauth]/route.ts +5 -0
- package/templates/auth/next-auth/src/auth/next-auth/auth.service.ts +45 -0
- package/templates/auth/next-auth/src/hooks/use-session.hook.ts +13 -0
- package/templates/auth/next-auth/src/providers/session.provider.tsx +6 -0
- package/templates/forms/formik/src/components/forms/login-form.component.tsx +30 -0
- package/templates/forms/formik/src/forms/formik/hooks/use-form-config.hook.ts +7 -0
- package/templates/forms/formik/src/forms/formik/schemas/example.schema.ts +8 -0
- package/templates/forms/react-hook-form/src/components/forms/login-form.component.tsx +27 -0
- package/templates/forms/react-hook-form/src/forms/react-hook-form/hooks/use-form.hook.ts +13 -0
- package/templates/forms/react-hook-form/src/forms/react-hook-form/schemas/example.schema.ts +15 -0
- package/templates/nextjs-base/next.config.ts +5 -0
- package/templates/nextjs-base/postcss.config.mjs +9 -0
- package/templates/nextjs-base/src/app/_components/navbar.tsx +88 -0
- package/templates/nextjs-base/src/app/_components/sidebar.tsx +223 -0
- package/templates/nextjs-base/src/app/error.tsx +39 -0
- package/templates/nextjs-base/src/app/globals.css +71 -0
- package/templates/nextjs-base/src/app/layout.tsx +21 -0
- package/templates/nextjs-base/src/app/loading.tsx +13 -0
- package/templates/nextjs-base/src/app/not-found.tsx +22 -0
- package/templates/nextjs-base/src/app/page.tsx +10 -0
- package/templates/nextjs-base/tailwind.config.ts +69 -0
- package/templates/shared/src/components/common/theme-toggle.component.tsx +31 -0
- package/templates/shared/src/components/common/toast/custom-message.component.tsx +18 -0
- package/templates/shared/src/components/common/toast/index.ts +8 -0
- package/templates/shared/src/components/common/toast/toast-message.component.tsx +112 -0
- package/templates/shared/src/hooks/use-debounce.hook.ts +12 -0
- package/templates/shared/src/hooks/use-fetch.hook.ts +42 -0
- package/templates/shared/src/hooks/use-intersection-observer.hook.ts +39 -0
- package/templates/shared/src/hooks/use-local-storage.hook.ts +30 -0
- package/templates/shared/src/hooks/use-media-query.hook.ts +26 -0
- package/templates/shared/src/hooks/use-toggle.hook.ts +12 -0
- package/templates/shared/src/lib/utils.util.ts +361 -0
- package/templates/shared/src/providers/theme.provider.tsx +17 -0
- package/templates/shared/src/providers/toast.provider.tsx +32 -0
- package/templates/shared/src/types/common.type.ts +34 -0
- package/templates/state/context/src/store/context/auth.context.tsx +47 -0
- package/templates/state/context/src/store/context/counter.context.tsx +41 -0
- package/templates/state/context/src/store/context/index.ts +2 -0
- package/templates/state/redux/src/providers/redux.provider.tsx +7 -0
- package/templates/state/redux/src/store/redux/hooks.store.ts +5 -0
- package/templates/state/redux/src/store/redux/index.ts +4 -0
- package/templates/state/redux/src/store/redux/slices/api.slice.ts +8 -0
- package/templates/state/redux/src/store/redux/slices/counter.slice.ts +24 -0
- package/templates/state/redux/src/store/redux/store.store.ts +13 -0
- package/templates/state/zustand/src/store/zustand/counter.store.ts +15 -0
- package/templates/state/zustand/src/store/zustand/index.ts +2 -0
- package/templates/state/zustand/src/store/zustand/user.store.ts +32 -0
- package/templates/ui/antd/COMPONENT_GUIDE.md +326 -0
- package/templates/ui/antd/src/app/examples/dialog/page.tsx +205 -0
- package/templates/ui/antd/src/app/examples/form/page.tsx +160 -0
- package/templates/ui/antd/src/app/examples/layout.tsx +125 -0
- package/templates/ui/antd/src/app/examples/page.tsx +64 -0
- package/templates/ui/antd/src/app/examples/table/page.tsx +118 -0
- package/templates/ui/antd/src/app/page.tsx +283 -0
- package/templates/ui/antd/src/components/common/DynamicTable/dynamic-table.component.tsx +79 -0
- package/templates/ui/antd/src/components/common/button/action-button.component.tsx +63 -0
- package/templates/ui/antd/src/components/common/dialog/dialog-wrapper.component.tsx +63 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/check-field.component.tsx +55 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/date-picker-field.component.tsx +80 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/limit-field.component.tsx +26 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/multi-check-field.component.tsx +56 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/number-field.component.tsx +100 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/otp-field.component.tsx +63 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/password-field.component.tsx +106 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/phone-number-field.component.tsx +78 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/radio-field.component.tsx +55 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/range-date-picker.component.tsx +66 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/search-field.component.tsx +24 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/select-field.component.tsx +82 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/single-check-field.component.tsx +50 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/single-select-field.component.tsx +86 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/string-number-field.component.tsx +80 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/switch-field.component.tsx +62 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/text-area-field.component.tsx +85 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/text-field.component.tsx +88 -0
- package/templates/ui/antd/src/components/common/fields/assets/interface/input-props.type.ts +233 -0
- package/templates/ui/antd/src/components/common/fields/cusInputField.component.tsx +40 -0
- package/templates/ui/antd/src/components/common/pagination/pagination.component.tsx +27 -0
- package/templates/ui/antd/src/components/ui/avatar.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/badge.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/button.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/card.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/checkbox.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/dialog.component.tsx +9 -0
- package/templates/ui/antd/src/components/ui/dropdown-menu.component.tsx +10 -0
- package/templates/ui/antd/src/components/ui/form.component.tsx +12 -0
- package/templates/ui/antd/src/components/ui/input.component.tsx +13 -0
- package/templates/ui/antd/src/components/ui/label.component.tsx +18 -0
- package/templates/ui/antd/src/components/ui/popover.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/progress.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/radio-group.component.tsx +10 -0
- package/templates/ui/antd/src/components/ui/scroll-area.component.tsx +25 -0
- package/templates/ui/antd/src/components/ui/select.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/separator.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/sheet.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/switch.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/table.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/tabs.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/textarea.component.tsx +9 -0
- package/templates/ui/antd/src/components/ui/tooltip.component.tsx +8 -0
- package/templates/ui/antd/src/lib/theme.util.ts +40 -0
- package/templates/ui/antd/src/providers/antd.provider.tsx +13 -0
- package/templates/ui/mui/src/app/examples/layout.tsx +113 -0
- package/templates/ui/mui/src/app/examples/page.tsx +716 -0
- package/templates/ui/mui/src/app/page.tsx +298 -0
- package/templates/ui/mui/src/components/common/DynamicTable/dynamic-table.component.tsx +131 -0
- package/templates/ui/mui/src/components/common/button/action-button.component.tsx +57 -0
- package/templates/ui/mui/src/components/common/dialog/dialog-wrapper.component.tsx +55 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/check-field.component.tsx +51 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/date-picker-field.component.tsx +50 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/multi-check-field.component.tsx +14 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/number-field.component.tsx +59 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/password-field.component.tsx +87 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/phone-number-field.component.tsx +48 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/radio-field.component.tsx +37 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/search-field.component.tsx +41 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/select-field.component.tsx +77 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/single-check-field.component.tsx +39 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/single-select-field.component.tsx +56 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/string-number-field.component.tsx +52 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/switch-field.component.tsx +35 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/text-area-field.component.tsx +46 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/text-field.component.tsx +51 -0
- package/templates/ui/mui/src/components/common/fields/assets/interface/input-props.type.ts +193 -0
- package/templates/ui/mui/src/components/common/fields/cusInputField.component.tsx +34 -0
- package/templates/ui/mui/src/components/common/pagination/pagination.component.tsx +59 -0
- package/templates/ui/mui/src/components/ui/avatar.component.tsx +19 -0
- package/templates/ui/mui/src/components/ui/badge.component.tsx +18 -0
- package/templates/ui/mui/src/components/ui/button.component.tsx +22 -0
- package/templates/ui/mui/src/components/ui/card.component.tsx +39 -0
- package/templates/ui/mui/src/components/ui/checkbox.component.tsx +21 -0
- package/templates/ui/mui/src/components/ui/dialog.component.tsx +38 -0
- package/templates/ui/mui/src/components/ui/dropdown-menu.component.tsx +43 -0
- package/templates/ui/mui/src/components/ui/form.component.tsx +98 -0
- package/templates/ui/mui/src/components/ui/input.component.tsx +15 -0
- package/templates/ui/mui/src/components/ui/label.component.tsx +15 -0
- package/templates/ui/mui/src/components/ui/popover.component.tsx +20 -0
- package/templates/ui/mui/src/components/ui/progress.component.tsx +19 -0
- package/templates/ui/mui/src/components/ui/radio-group.component.tsx +25 -0
- package/templates/ui/mui/src/components/ui/scroll-area.component.tsx +27 -0
- package/templates/ui/mui/src/components/ui/select.component.tsx +26 -0
- package/templates/ui/mui/src/components/ui/separator.component.tsx +11 -0
- package/templates/ui/mui/src/components/ui/sheet.component.tsx +44 -0
- package/templates/ui/mui/src/components/ui/switch.component.tsx +23 -0
- package/templates/ui/mui/src/components/ui/table.component.tsx +34 -0
- package/templates/ui/mui/src/components/ui/tabs.component.tsx +38 -0
- package/templates/ui/mui/src/components/ui/textarea.component.tsx +18 -0
- package/templates/ui/mui/src/components/ui/tooltip.component.tsx +24 -0
- package/templates/ui/mui/src/lib/theme.util.ts +73 -0
- package/templates/ui/mui/src/providers/mui.provider.tsx +13 -0
- package/templates/ui/shadcn/COMPONENT_GUIDE.md +306 -0
- package/templates/ui/shadcn/src/app/examples/dialog/page.tsx +122 -0
- package/templates/ui/shadcn/src/app/examples/form/page.tsx +107 -0
- package/templates/ui/shadcn/src/app/examples/layout.tsx +24 -0
- package/templates/ui/shadcn/src/app/examples/page.tsx +30 -0
- package/templates/ui/shadcn/src/app/examples/table/page.tsx +77 -0
- package/templates/ui/shadcn/src/app/page.tsx +20 -0
- package/templates/ui/shadcn/src/components/common/DynamicTable/dynamic-table.component.tsx +136 -0
- package/templates/ui/shadcn/src/components/common/button/action-button.component.tsx +68 -0
- package/templates/ui/shadcn/src/components/common/dialog/dialog-wrapper.component.tsx +58 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/check-field.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/date-picker-field.component.tsx +62 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/dynamic-file-upload-field.component.tsx +152 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/limit-field.component.tsx +73 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/multi-check-field.component.tsx +46 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/number-field.component.tsx +124 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/otp-field.component.tsx +61 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/password-field.component.tsx +110 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/phone-number-field.component.tsx +90 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/radio-field.component.tsx +41 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/range-date-picker.component.tsx +71 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/rich-text-editor.component.tsx +91 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/search-field.component.tsx +34 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/select-field.component.tsx +231 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/single-check-field.component.tsx +42 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/single-select-field.component.tsx +82 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/string-number-field.component.tsx +68 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/switch-field.component.tsx +61 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/text-area-field.component.tsx +62 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/text-area-with-file.component.tsx +142 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/text-field.component.tsx +80 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/tiny-editor.component.tsx +51 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/upload-profile-picture.component.tsx +103 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/upload-video-file.component.tsx +86 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/interface/input-props.type.ts +198 -0
- package/templates/ui/shadcn/src/components/common/fields/cusInputField.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/common/pagination/pagination.component.tsx +68 -0
- package/templates/ui/shadcn/src/components/ui/avatar.component.tsx +37 -0
- package/templates/ui/shadcn/src/components/ui/badge.component.tsx +28 -0
- package/templates/ui/shadcn/src/components/ui/button.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/ui/card.component.tsx +46 -0
- package/templates/ui/shadcn/src/components/ui/checkbox.component.tsx +25 -0
- package/templates/ui/shadcn/src/components/ui/dialog.component.tsx +98 -0
- package/templates/ui/shadcn/src/components/ui/dropdown-menu.component.tsx +163 -0
- package/templates/ui/shadcn/src/components/ui/form.component.tsx +110 -0
- package/templates/ui/shadcn/src/components/ui/input-otp.component.tsx +64 -0
- package/templates/ui/shadcn/src/components/ui/input.component.tsx +23 -0
- package/templates/ui/shadcn/src/components/ui/label.component.tsx +23 -0
- package/templates/ui/shadcn/src/components/ui/popover.component.tsx +27 -0
- package/templates/ui/shadcn/src/components/ui/progress.component.tsx +22 -0
- package/templates/ui/shadcn/src/components/ui/radio-group.component.tsx +33 -0
- package/templates/ui/shadcn/src/components/ui/scroll-area.component.tsx +37 -0
- package/templates/ui/shadcn/src/components/ui/select.component.tsx +139 -0
- package/templates/ui/shadcn/src/components/ui/separator.component.tsx +23 -0
- package/templates/ui/shadcn/src/components/ui/sheet.component.tsx +89 -0
- package/templates/ui/shadcn/src/components/ui/switch.component.tsx +26 -0
- package/templates/ui/shadcn/src/components/ui/table.component.tsx +71 -0
- package/templates/ui/shadcn/src/components/ui/tabs.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/ui/textarea.component.tsx +20 -0
- package/templates/ui/shadcn/src/components/ui/tooltip.component.tsx +25 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# Ant Design Component System
|
|
2
|
+
|
|
3
|
+
This template includes a comprehensive reusable component system built on **Ant Design 5**.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/components/
|
|
9
|
+
├── common/
|
|
10
|
+
│ ├── button/
|
|
11
|
+
│ │ └── action-button.component.tsx # Button + Tooltip + Loading
|
|
12
|
+
│ ├── dialog/
|
|
13
|
+
│ │ └── dialog-wrapper.component.tsx # Scrollable modal wrapper
|
|
14
|
+
│ ├── DynamicTable/
|
|
15
|
+
│ │ └── dynamic-table.component.tsx # Config-driven table
|
|
16
|
+
│ ├── fields/
|
|
17
|
+
│ │ ├── assets/
|
|
18
|
+
│ │ │ ├── components/ # Individual field components
|
|
19
|
+
│ │ │ └── interface/
|
|
20
|
+
│ │ │ └── input-props.type.ts # Shared type definitions
|
|
21
|
+
│ │ └── cusInputField.component.tsx # CustomField barrel export
|
|
22
|
+
│ └── pagination/
|
|
23
|
+
│ └── pagination.component.tsx # Page navigation
|
|
24
|
+
└── ui/ # Base primitives (22 components)
|
|
25
|
+
├── avatar.component.tsx
|
|
26
|
+
├── badge.component.tsx
|
|
27
|
+
├── button.component.tsx
|
|
28
|
+
├── card.component.tsx
|
|
29
|
+
├── checkbox.component.tsx
|
|
30
|
+
├── dialog.component.tsx # Ant Design Modal wrapper
|
|
31
|
+
├── dropdown-menu.component.tsx # Ant Design Dropdown wrapper
|
|
32
|
+
├── form.component.tsx # Ant Design Form + Form.Item
|
|
33
|
+
├── input.component.tsx # Input + TextArea + OTP + Password + Search
|
|
34
|
+
├── label.component.tsx
|
|
35
|
+
├── popover.component.tsx
|
|
36
|
+
├── progress.component.tsx
|
|
37
|
+
├── radio-group.component.tsx
|
|
38
|
+
├── scroll-area.component.tsx
|
|
39
|
+
├── select.component.tsx
|
|
40
|
+
├── separator.component.tsx # Ant Design Divider wrapper
|
|
41
|
+
├── sheet.component.tsx # Ant Design Drawer wrapper
|
|
42
|
+
├── switch.component.tsx
|
|
43
|
+
├── table.component.tsx
|
|
44
|
+
├── tabs.component.tsx
|
|
45
|
+
├── textarea.component.tsx
|
|
46
|
+
└── tooltip.component.tsx
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## CustomField System
|
|
52
|
+
|
|
53
|
+
The `CustomField` compound object provides 17 field types. Every field supports **dual-mode**:
|
|
54
|
+
|
|
55
|
+
- **With `form` prop**: Integrates with `react-hook-form` via `<Controller>` for validation/errors.
|
|
56
|
+
- **Without `form` prop**: Renders standalone using `value`/`setValue` props.
|
|
57
|
+
|
|
58
|
+
### Import
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { CustomField } from '@/components/common/fields/cusInputField.component';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Available Fields
|
|
65
|
+
|
|
66
|
+
| Field | Component | Description |
|
|
67
|
+
|-------|-----------|-------------|
|
|
68
|
+
| Text | `CustomField.Text` | Single-line text input |
|
|
69
|
+
| TextArea | `CustomField.TextArea` | Multi-line text area with optional `maxLength`/`showCount` |
|
|
70
|
+
| Number | `CustomField.Number` | Numeric input with `numberType` (`float`/`integer`), `min`, `max`, `step` |
|
|
71
|
+
| StringNumber | `CustomField.StringNumber` | Text input that only allows digits and decimals |
|
|
72
|
+
| Password | `CustomField.Password` | Password input with show/hide toggle; `mode="validate"` adds confirm field |
|
|
73
|
+
| SingleSelectField | `CustomField.SingleSelectField` | Dropdown select from string array |
|
|
74
|
+
| SelectField | `CustomField.SelectField` | Advanced select with `single`/`multiple`, search, images, flags |
|
|
75
|
+
| SwitchField | `CustomField.SwitchField` | Toggle switch with optional description and border |
|
|
76
|
+
| RadioField | `CustomField.RadioField` | Radio button group |
|
|
77
|
+
| CheckField | `CustomField.CheckField` | Checkbox group |
|
|
78
|
+
| MultiCheckField | `CustomField.MultiCheckField` | Multi-select checkbox group (alias for CheckField) |
|
|
79
|
+
| SingleCheckField | `CustomField.SingleCheckField` | Single checkbox with label |
|
|
80
|
+
| SearchField | `CustomField.SearchField` | Search input with clear and enter-button |
|
|
81
|
+
| DatePickerField | `CustomField.DatePickerField` | Date picker with `picker` prop (`date`, `week`, `month`, `quarter`, `year`) |
|
|
82
|
+
| RangeDatePicker | `CustomField.RangeDatePicker` | Date range picker |
|
|
83
|
+
| PhoneNumber | `CustomField.PhoneNumber` | Phone number text input (type="tel") |
|
|
84
|
+
| OTP | `CustomField.OTP` | OTP input with configurable `length` |
|
|
85
|
+
| LimitField | `CustomField.LimitField` | Per-page limit selector for pagination |
|
|
86
|
+
|
|
87
|
+
### Dual-mode Example
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
// With react-hook-form (recommended)
|
|
91
|
+
<CustomField.Text
|
|
92
|
+
form={form}
|
|
93
|
+
name="fullName"
|
|
94
|
+
labelName="Full Name"
|
|
95
|
+
placeholder="Enter your name"
|
|
96
|
+
required
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
// Standalone (without form)
|
|
100
|
+
<CustomField.Text
|
|
101
|
+
labelName="Full Name"
|
|
102
|
+
value={name}
|
|
103
|
+
setValue={setName}
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Common Components
|
|
110
|
+
|
|
111
|
+
### ActionButton
|
|
112
|
+
|
|
113
|
+
A button component with icon positions, loading spinner, and optional Ant Design Tooltip.
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import { ActionButton } from '@/components/common/button/action-button.component';
|
|
117
|
+
|
|
118
|
+
// Basic
|
|
119
|
+
<ActionButton buttonContent="Save" variant="primary" />
|
|
120
|
+
|
|
121
|
+
// With loading state
|
|
122
|
+
<ActionButton buttonContent="Saving..." isPending variant="primary" />
|
|
123
|
+
|
|
124
|
+
// With icons
|
|
125
|
+
<ActionButton
|
|
126
|
+
buttonContent="Add User"
|
|
127
|
+
icon={<PlusOutlined />}
|
|
128
|
+
lastIcon={<ArrowRightOutlined />}
|
|
129
|
+
variant="primary"
|
|
130
|
+
/>
|
|
131
|
+
|
|
132
|
+
// With tooltip
|
|
133
|
+
<ActionButton
|
|
134
|
+
buttonContent="Delete"
|
|
135
|
+
variant="primary"
|
|
136
|
+
danger
|
|
137
|
+
tooltipContent="Permanently delete this item"
|
|
138
|
+
side="top"
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
// Submit button
|
|
142
|
+
<ActionButton htmlType="submit" buttonContent="Submit" variant="primary" />
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Props:**
|
|
146
|
+
|
|
147
|
+
| Prop | Type | Default | Description |
|
|
148
|
+
|------|------|---------|-------------|
|
|
149
|
+
| `variant` | `'primary' \| 'dashed' \| 'link' \| 'text' \| 'default'` | `'primary'` | Button variant |
|
|
150
|
+
| `btnSize` | `'small' \| 'middle' \| 'large'` | `'middle'` | Button size |
|
|
151
|
+
| `danger` | `boolean` | `false` | Danger styling |
|
|
152
|
+
| `isPending` | `boolean` | `false` | Show loading spinner |
|
|
153
|
+
| `icon` | `ReactNode` | - | Icon before content |
|
|
154
|
+
| `lastIcon` | `ReactNode` | - | Icon after content |
|
|
155
|
+
| `tooltipContent` | `string` | - | Tooltip text (wraps in Tooltip) |
|
|
156
|
+
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | Tooltip placement |
|
|
157
|
+
| `htmlType` | `'submit' \| 'button' \| 'reset'` | `'button'` | HTML button type |
|
|
158
|
+
| `handleOpen` | `function` | - | Click handler |
|
|
159
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
160
|
+
| `ghost` | `boolean` | - | Ghost mode |
|
|
161
|
+
| `block` | `boolean` | - | Full-width block |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### DialogWrapper
|
|
166
|
+
|
|
167
|
+
A scrollable modal with sticky header, close button, optional trigger content, and footer slot.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { DialogWrapper } from '@/components/common/dialog/dialog-wrapper.component';
|
|
171
|
+
|
|
172
|
+
const [open, setOpen] = useState(false);
|
|
173
|
+
|
|
174
|
+
<DialogWrapper
|
|
175
|
+
open={open}
|
|
176
|
+
setOpen={setOpen}
|
|
177
|
+
title="Dialog Title"
|
|
178
|
+
description="Optional description"
|
|
179
|
+
footer={
|
|
180
|
+
<Space>
|
|
181
|
+
<ActionButton variant="default" buttonContent="Cancel" handleOpen={() => setOpen(false)} />
|
|
182
|
+
<ActionButton variant="primary" buttonContent="Confirm" />
|
|
183
|
+
</Space>
|
|
184
|
+
}
|
|
185
|
+
>
|
|
186
|
+
<p>Your content here — scrollable if long.</p>
|
|
187
|
+
</DialogWrapper>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Props:**
|
|
191
|
+
|
|
192
|
+
| Prop | Type | Default | Description |
|
|
193
|
+
|------|------|---------|-------------|
|
|
194
|
+
| `open` | `boolean` | required | Visibility state |
|
|
195
|
+
| `setOpen` | `function` | required | State setter |
|
|
196
|
+
| `triggerContent` | `ReactNode` | - | Optional trigger element |
|
|
197
|
+
| `title` | `ReactNode` | - | Modal title |
|
|
198
|
+
| `description` | `string` | - | Subtitle text |
|
|
199
|
+
| `children` | `ReactNode` | required | Modal body content |
|
|
200
|
+
| `closer` | `boolean` | `true` | Show close button |
|
|
201
|
+
| `footer` | `ReactNode` | - | Footer content |
|
|
202
|
+
| `width` | `number \| string` | `520` | Modal width |
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### DynamicTable
|
|
207
|
+
|
|
208
|
+
A config-driven table built on Ant Design Table.
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
import { DynamicTable, type TableColumn } from '@/components/common/DynamicTable/dynamic-table.component';
|
|
212
|
+
|
|
213
|
+
const columns: TableColumn[] = [
|
|
214
|
+
{ key: 'name', header: 'Name' },
|
|
215
|
+
{ key: 'email', header: 'Email' },
|
|
216
|
+
{ key: 'role', header: 'Role', render: (item) => <Tag>{item.role}</Tag> },
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
<DynamicTable
|
|
220
|
+
data={data}
|
|
221
|
+
isLoading={isLoading}
|
|
222
|
+
config={{ columns, emptyMessage: 'No users found' }}
|
|
223
|
+
isCheckBox
|
|
224
|
+
selectedIds={selectedIds}
|
|
225
|
+
setSelectedIds={setSelectedIds}
|
|
226
|
+
rowKey="id"
|
|
227
|
+
/>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Props:**
|
|
231
|
+
|
|
232
|
+
| Prop | Type | Default | Description |
|
|
233
|
+
|------|------|---------|-------------|
|
|
234
|
+
| `data` | `any[]` | required | Table data |
|
|
235
|
+
| `isLoading` | `boolean` | required | Loading state |
|
|
236
|
+
| `config` | `TableConfig` | required | Column definitions |
|
|
237
|
+
| `isCheckBox` | `boolean` | `false` | Enable row checkbox selection |
|
|
238
|
+
| `selectedIds` | `string[]` | `[]` | Controlled selected row IDs |
|
|
239
|
+
| `setSelectedIds` | `function` | noop | Selected IDs setter |
|
|
240
|
+
| `setSelectObject` | `function` | noop | Full selected row objects setter |
|
|
241
|
+
| `rowKey` | `string` | `'id'` | Unique ID field name |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### Pagination
|
|
246
|
+
|
|
247
|
+
Page navigation using Ant Design Pagination.
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
import { Pagination } from '@/components/common/pagination/pagination.component';
|
|
251
|
+
|
|
252
|
+
<Pagination
|
|
253
|
+
currentPage={currentPage}
|
|
254
|
+
totalPages={totalPages}
|
|
255
|
+
setCurrentPage={setCurrentPage}
|
|
256
|
+
total={totalItems}
|
|
257
|
+
/>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Props:**
|
|
261
|
+
|
|
262
|
+
| Prop | Type | Default | Description |
|
|
263
|
+
|------|------|---------|-------------|
|
|
264
|
+
| `currentPage` | `number` | required | Current active page |
|
|
265
|
+
| `totalPages` | `number` | required | Total number of pages |
|
|
266
|
+
| `setCurrentPage` | `function` | required | Page setter |
|
|
267
|
+
| `total` | `number` | - | Total items (for display) |
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## UI Primitives
|
|
272
|
+
|
|
273
|
+
Each primitive in `src/components/ui/` is a thin re-export of an Ant Design component with consistent naming.
|
|
274
|
+
Import directly from their respective files:
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { Button } from '@/components/ui/button.component';
|
|
278
|
+
import { Card } from '@/components/ui/card.component';
|
|
279
|
+
import { Tabs } from '@/components/ui/tabs.component';
|
|
280
|
+
import { Table } from '@/components/ui/table.component';
|
|
281
|
+
// etc.
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Full List
|
|
285
|
+
|
|
286
|
+
| Component | Ant Design Equivalent | File |
|
|
287
|
+
|-----------|----------------------|------|
|
|
288
|
+
| `Avatar` | `Avatar` | `avatar.component.tsx` |
|
|
289
|
+
| `Badge` | `Badge` | `badge.component.tsx` |
|
|
290
|
+
| `Button` | `Button` | `button.component.tsx` |
|
|
291
|
+
| `Card` | `Card` | `card.component.tsx` |
|
|
292
|
+
| `Checkbox` | `Checkbox` | `checkbox.component.tsx` |
|
|
293
|
+
| `Dialog` | `Modal` | `dialog.component.tsx` |
|
|
294
|
+
| `DropdownMenu` | `Dropdown` | `dropdown-menu.component.tsx` |
|
|
295
|
+
| `Form`, `FormItem` | `Form`, `Form.Item` | `form.component.tsx` |
|
|
296
|
+
| `Input` | `Input` | `input.component.tsx` |
|
|
297
|
+
| `Label` | `Typography.Text` | `label.component.tsx` |
|
|
298
|
+
| `Popover` | `Popover` | `popover.component.tsx` |
|
|
299
|
+
| `Progress` | `Progress` | `progress.component.tsx` |
|
|
300
|
+
| `RadioGroup` | `Radio.Group` | `radio-group.component.tsx` |
|
|
301
|
+
| `ScrollArea` | Custom scrollable div | `scroll-area.component.tsx` |
|
|
302
|
+
| `Select` | `Select` | `select.component.tsx` |
|
|
303
|
+
| `Separator` | `Divider` | `separator.component.tsx` |
|
|
304
|
+
| `Sheet` | `Drawer` | `sheet.component.tsx` |
|
|
305
|
+
| `Switch` | `Switch` | `switch.component.tsx` |
|
|
306
|
+
| `Table` | `Table` | `table.component.tsx` |
|
|
307
|
+
| `Tabs` | `Tabs` | `tabs.component.tsx` |
|
|
308
|
+
| `Textarea` | `Input.TextArea` | `textarea.component.tsx` |
|
|
309
|
+
| `Tooltip` | `Tooltip` | `tooltip.component.tsx` |
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Theme
|
|
314
|
+
|
|
315
|
+
The Ant Design theme is configured in `src/lib/theme.util.ts` using the `ThemeConfig` API.
|
|
316
|
+
The `AntdProvider` in `src/providers/antd.provider.tsx` wraps the app with `<ConfigProvider>`.
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
// Customize in src/lib/theme.util.ts
|
|
320
|
+
export const themeConfig: ThemeConfig = {
|
|
321
|
+
token: {
|
|
322
|
+
colorPrimary: '#1677ff',
|
|
323
|
+
borderRadius: 6,
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
```
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Typography, Space, Tag, Card, Row, Col, Divider, theme } from 'antd';
|
|
5
|
+
import {
|
|
6
|
+
EditOutlined, DeleteOutlined, PlusOutlined,
|
|
7
|
+
InfoCircleOutlined, CheckCircleOutlined, WarningOutlined,
|
|
8
|
+
} from '@ant-design/icons';
|
|
9
|
+
import { DialogWrapper } from '@/components/common/dialog/dialog-wrapper.component';
|
|
10
|
+
import { ActionButton } from '@/components/common/button/action-button.component';
|
|
11
|
+
import { Pagination } from '@/components/common/pagination/pagination.component';
|
|
12
|
+
|
|
13
|
+
const { Title, Text, Paragraph } = Typography;
|
|
14
|
+
|
|
15
|
+
const sampleItems = Array.from({ length: 25 }, (_, i) => ({
|
|
16
|
+
id: i + 1,
|
|
17
|
+
title: `Item ${i + 1}`,
|
|
18
|
+
status: ['Active', 'Pending', 'Archived'][i % 3],
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
export default function DialogExamplePage() {
|
|
22
|
+
const { token } = theme.useToken();
|
|
23
|
+
const [basicOpen, setBasicOpen] = useState(false);
|
|
24
|
+
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
25
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
26
|
+
const perPage = 5;
|
|
27
|
+
const totalPages = Math.ceil(sampleItems.length / perPage);
|
|
28
|
+
const paginatedItems = sampleItems.slice((currentPage - 1) * perPage, currentPage * perPage);
|
|
29
|
+
|
|
30
|
+
const getStatusColor = (status: string) => {
|
|
31
|
+
switch (status) {
|
|
32
|
+
case 'Active': return 'green';
|
|
33
|
+
case 'Pending': return 'orange';
|
|
34
|
+
case 'Archived': return 'default';
|
|
35
|
+
default: return 'default';
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div style={{ maxWidth: 960, margin: '0 auto', padding: 32 }}>
|
|
41
|
+
<div style={{ marginBottom: 24 }}>
|
|
42
|
+
<Title level={2} style={{ fontWeight: 800, margin: 0 }}>Dialog, ActionButton & Pagination Demo</Title>
|
|
43
|
+
<Text type="secondary" style={{ fontSize: 15, display: 'block', marginTop: 4 }}>
|
|
44
|
+
Reusable DialogWrapper with sticky header, ActionButton variants with tooltips, and pagination.
|
|
45
|
+
</Text>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{/* ActionButton Variants */}
|
|
49
|
+
<Card title="ActionButton Variants" style={{ borderRadius: 12, marginBottom: 24 }} variant="outlined">
|
|
50
|
+
<Space wrap size="middle">
|
|
51
|
+
<ActionButton
|
|
52
|
+
variant="primary"
|
|
53
|
+
icon={<InfoCircleOutlined />}
|
|
54
|
+
buttonContent="Info"
|
|
55
|
+
tooltipContent="Default primary variant"
|
|
56
|
+
/>
|
|
57
|
+
<ActionButton
|
|
58
|
+
variant="primary"
|
|
59
|
+
danger
|
|
60
|
+
icon={<DeleteOutlined />}
|
|
61
|
+
buttonContent="Delete"
|
|
62
|
+
tooltipContent="Danger variant"
|
|
63
|
+
/>
|
|
64
|
+
<ActionButton
|
|
65
|
+
variant="default"
|
|
66
|
+
icon={<EditOutlined />}
|
|
67
|
+
buttonContent="Edit"
|
|
68
|
+
tooltipContent="Default variant"
|
|
69
|
+
/>
|
|
70
|
+
<ActionButton
|
|
71
|
+
variant="dashed"
|
|
72
|
+
icon={<PlusOutlined />}
|
|
73
|
+
buttonContent="Add"
|
|
74
|
+
tooltipContent="Dashed variant"
|
|
75
|
+
/>
|
|
76
|
+
<ActionButton
|
|
77
|
+
variant="text"
|
|
78
|
+
icon={<WarningOutlined />}
|
|
79
|
+
buttonContent="Warn"
|
|
80
|
+
tooltipContent="Text variant"
|
|
81
|
+
/>
|
|
82
|
+
<ActionButton
|
|
83
|
+
variant="link"
|
|
84
|
+
icon={<CheckCircleOutlined />}
|
|
85
|
+
buttonContent="Confirm"
|
|
86
|
+
tooltipContent="Link variant"
|
|
87
|
+
/>
|
|
88
|
+
</Space>
|
|
89
|
+
</Card>
|
|
90
|
+
|
|
91
|
+
{/* Loading State */}
|
|
92
|
+
<Card title="ActionButton States" style={{ borderRadius: 12, marginBottom: 24 }} variant="outlined">
|
|
93
|
+
<Space wrap size="middle">
|
|
94
|
+
<ActionButton
|
|
95
|
+
buttonContent="Save Changes"
|
|
96
|
+
isPending
|
|
97
|
+
variant="primary"
|
|
98
|
+
/>
|
|
99
|
+
<ActionButton
|
|
100
|
+
buttonContent="Disabled"
|
|
101
|
+
disabled
|
|
102
|
+
variant="default"
|
|
103
|
+
/>
|
|
104
|
+
<ActionButton
|
|
105
|
+
buttonContent="With Icon"
|
|
106
|
+
icon={<PlusOutlined />}
|
|
107
|
+
variant="primary"
|
|
108
|
+
/>
|
|
109
|
+
<ActionButton
|
|
110
|
+
buttonContent="Icon After"
|
|
111
|
+
lastIcon={<EditOutlined />}
|
|
112
|
+
variant="default"
|
|
113
|
+
/>
|
|
114
|
+
</Space>
|
|
115
|
+
</Card>
|
|
116
|
+
|
|
117
|
+
{/* Dialogs */}
|
|
118
|
+
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
|
|
119
|
+
<Col xs={24} md={12}>
|
|
120
|
+
<Card title="Basic Dialog" style={{ borderRadius: 12 }} variant="outlined">
|
|
121
|
+
<ActionButton
|
|
122
|
+
buttonContent="Open Dialog"
|
|
123
|
+
variant="primary"
|
|
124
|
+
handleOpen={() => setBasicOpen(true)}
|
|
125
|
+
/>
|
|
126
|
+
</Card>
|
|
127
|
+
</Col>
|
|
128
|
+
<Col xs={24} md={12}>
|
|
129
|
+
<Card title="Confirmation Dialog" style={{ borderRadius: 12 }} variant="outlined">
|
|
130
|
+
<ActionButton
|
|
131
|
+
buttonContent="Confirm Action"
|
|
132
|
+
variant="default"
|
|
133
|
+
danger
|
|
134
|
+
icon={<DeleteOutlined />}
|
|
135
|
+
handleOpen={() => setConfirmOpen(true)}
|
|
136
|
+
/>
|
|
137
|
+
</Card>
|
|
138
|
+
</Col>
|
|
139
|
+
</Row>
|
|
140
|
+
|
|
141
|
+
<DialogWrapper
|
|
142
|
+
open={basicOpen}
|
|
143
|
+
setOpen={setBasicOpen}
|
|
144
|
+
title="Basic Dialog"
|
|
145
|
+
description="This is a reusable dialog wrapper with a sticky header and close button."
|
|
146
|
+
footer={
|
|
147
|
+
<Space>
|
|
148
|
+
<ActionButton variant="default" buttonContent="Cancel" handleOpen={() => setBasicOpen(false)} />
|
|
149
|
+
<ActionButton variant="primary" buttonContent="Confirm" handleOpen={() => { alert('Confirmed!'); setBasicOpen(false); }} />
|
|
150
|
+
</Space>
|
|
151
|
+
}
|
|
152
|
+
>
|
|
153
|
+
<Paragraph>
|
|
154
|
+
This dialog content area is scrollable. The header and footer remain sticky.
|
|
155
|
+
The close button in the top-right corner dismisses the dialog.
|
|
156
|
+
</Paragraph>
|
|
157
|
+
<Paragraph>
|
|
158
|
+
DialogWrapper uses Ant Design Modal under the hood with a polished scrollable body,
|
|
159
|
+
sticky header with title and description, and an optional footer slot.
|
|
160
|
+
</Paragraph>
|
|
161
|
+
</DialogWrapper>
|
|
162
|
+
|
|
163
|
+
<DialogWrapper
|
|
164
|
+
open={confirmOpen}
|
|
165
|
+
setOpen={setConfirmOpen}
|
|
166
|
+
title="Confirm Delete"
|
|
167
|
+
description="Are you sure you want to delete this item? This action cannot be undone."
|
|
168
|
+
footer={
|
|
169
|
+
<Space>
|
|
170
|
+
<ActionButton variant="default" buttonContent="Cancel" handleOpen={() => setConfirmOpen(false)} />
|
|
171
|
+
<ActionButton variant="primary" danger buttonContent="Delete" handleOpen={() => { alert('Deleted!'); setConfirmOpen(false); }} />
|
|
172
|
+
</Space>
|
|
173
|
+
}
|
|
174
|
+
>
|
|
175
|
+
<Paragraph>
|
|
176
|
+
<WarningOutlined style={{ color: token.colorWarning, marginRight: 8 }} />
|
|
177
|
+
This action is irreversible. All associated data will be permanently removed.
|
|
178
|
+
</Paragraph>
|
|
179
|
+
</DialogWrapper>
|
|
180
|
+
|
|
181
|
+
{/* Pagination */}
|
|
182
|
+
<Card title="Pagination" style={{ borderRadius: 12 }} variant="outlined">
|
|
183
|
+
<div style={{ marginBottom: 16 }}>
|
|
184
|
+
{paginatedItems.map((item) => (
|
|
185
|
+
<div key={item.id} style={{
|
|
186
|
+
display: 'flex', justifyContent: 'space-between',
|
|
187
|
+
alignItems: 'center', padding: '8px 12px',
|
|
188
|
+
borderBottom: `1px solid ${token.colorBorderSecondary}`,
|
|
189
|
+
}}>
|
|
190
|
+
<Text>{item.title}</Text>
|
|
191
|
+
<Tag color={getStatusColor(item.status)} style={{ borderRadius: 6 }}>
|
|
192
|
+
{item.status}
|
|
193
|
+
</Tag>
|
|
194
|
+
</div>
|
|
195
|
+
))}
|
|
196
|
+
</div>
|
|
197
|
+
<Pagination
|
|
198
|
+
currentPage={currentPage}
|
|
199
|
+
totalPages={totalPages}
|
|
200
|
+
setCurrentPage={setCurrentPage}
|
|
201
|
+
/>
|
|
202
|
+
</Card>
|
|
203
|
+
</div>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useForm } from 'react-hook-form';
|
|
4
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { Typography, Divider, Row, Col, Card, Space, theme } from 'antd';
|
|
7
|
+
import { CustomField } from '@/components/common/fields/cusInputField.component';
|
|
8
|
+
import { ActionButton } from '@/components/common/button/action-button.component';
|
|
9
|
+
|
|
10
|
+
const { Title, Text } = Typography;
|
|
11
|
+
|
|
12
|
+
const formSchema = z.object({
|
|
13
|
+
fullName: z.string().min(2, 'Name must be at least 2 characters'),
|
|
14
|
+
bio: z.string().optional(),
|
|
15
|
+
age: z.coerce.number().min(1, 'Required').max(150),
|
|
16
|
+
phone: z.string().optional(),
|
|
17
|
+
password: z.string().min(6, 'Min 6 characters'),
|
|
18
|
+
role: z.string().min(1, 'Select a role'),
|
|
19
|
+
notify: z.boolean().optional(),
|
|
20
|
+
acceptTerms: z.boolean().refine((v) => v === true, 'You must accept'),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
type FormValues = z.infer<typeof formSchema>;
|
|
24
|
+
|
|
25
|
+
export default function FormExamplePage() {
|
|
26
|
+
const { token } = theme.useToken();
|
|
27
|
+
const form = useForm<FormValues>({
|
|
28
|
+
resolver: zodResolver(formSchema),
|
|
29
|
+
defaultValues: {
|
|
30
|
+
fullName: '', bio: '', age: undefined, phone: '',
|
|
31
|
+
password: '', role: '', notify: false, acceptTerms: false,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const onSubmit = (data: FormValues) => alert(JSON.stringify(data, null, 2));
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div style={{ maxWidth: 900, margin: '0 auto', padding: 32 }}>
|
|
39
|
+
<div style={{ marginBottom: 24 }}>
|
|
40
|
+
<Title level={2} style={{ fontWeight: 800, margin: 0 }}>CustomField Form Demo</Title>
|
|
41
|
+
<Text type="secondary" style={{ fontSize: 15, display: 'block', marginTop: 4 }}>
|
|
42
|
+
All field types with react-hook-form + Zod validation.
|
|
43
|
+
</Text>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<Card style={{ borderRadius: 12 }} variant="outlined">
|
|
47
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
48
|
+
<Row gutter={[24, 0]}>
|
|
49
|
+
<Col xs={24} md={12}>
|
|
50
|
+
<CustomField.Text
|
|
51
|
+
form={form}
|
|
52
|
+
name="fullName"
|
|
53
|
+
labelName="Full Name"
|
|
54
|
+
placeholder="Enter your name"
|
|
55
|
+
required
|
|
56
|
+
/>
|
|
57
|
+
</Col>
|
|
58
|
+
<Col xs={24} md={12}>
|
|
59
|
+
<CustomField.Number
|
|
60
|
+
form={form}
|
|
61
|
+
name="age"
|
|
62
|
+
labelName="Age"
|
|
63
|
+
numberType="integer"
|
|
64
|
+
placeholder="Enter age"
|
|
65
|
+
required
|
|
66
|
+
/>
|
|
67
|
+
</Col>
|
|
68
|
+
<Col xs={24}>
|
|
69
|
+
<CustomField.TextArea
|
|
70
|
+
form={form}
|
|
71
|
+
name="bio"
|
|
72
|
+
labelName="Biography"
|
|
73
|
+
placeholder="Tell us about yourself"
|
|
74
|
+
rows={3}
|
|
75
|
+
/>
|
|
76
|
+
</Col>
|
|
77
|
+
<Col xs={24} md={12}>
|
|
78
|
+
<CustomField.PhoneNumber
|
|
79
|
+
form={form}
|
|
80
|
+
name="phone"
|
|
81
|
+
labelName="Phone Number"
|
|
82
|
+
placeholder="+1 (555) 123-4567"
|
|
83
|
+
/>
|
|
84
|
+
</Col>
|
|
85
|
+
<Col xs={24} md={12}>
|
|
86
|
+
<CustomField.Password
|
|
87
|
+
form={form}
|
|
88
|
+
name="password"
|
|
89
|
+
labelName="Password"
|
|
90
|
+
placeholder="Min 6 characters"
|
|
91
|
+
required
|
|
92
|
+
/>
|
|
93
|
+
</Col>
|
|
94
|
+
<Col xs={24} md={12}>
|
|
95
|
+
<CustomField.SelectField
|
|
96
|
+
form={form}
|
|
97
|
+
name="role"
|
|
98
|
+
labelName="Role"
|
|
99
|
+
placeholder="Select role"
|
|
100
|
+
required
|
|
101
|
+
options={[
|
|
102
|
+
{ value: 'admin', label: 'Admin' },
|
|
103
|
+
{ value: 'editor', label: 'Editor' },
|
|
104
|
+
{ value: 'viewer', label: 'Viewer' },
|
|
105
|
+
]}
|
|
106
|
+
/>
|
|
107
|
+
</Col>
|
|
108
|
+
<Col xs={24} md={12}>
|
|
109
|
+
<CustomField.SingleSelectField
|
|
110
|
+
form={form}
|
|
111
|
+
name="department"
|
|
112
|
+
labelName="Department"
|
|
113
|
+
placeholder="Select department"
|
|
114
|
+
options={['Engineering', 'Design', 'Marketing', 'Sales']}
|
|
115
|
+
/>
|
|
116
|
+
</Col>
|
|
117
|
+
</Row>
|
|
118
|
+
|
|
119
|
+
<Divider />
|
|
120
|
+
|
|
121
|
+
<Row gutter={[24, 0]}>
|
|
122
|
+
<Col xs={24} md={12}>
|
|
123
|
+
<CustomField.SwitchField
|
|
124
|
+
form={form}
|
|
125
|
+
name="notify"
|
|
126
|
+
labelName="Enable Notifications"
|
|
127
|
+
description="Receive email updates about your account"
|
|
128
|
+
border
|
|
129
|
+
/>
|
|
130
|
+
</Col>
|
|
131
|
+
<Col xs={24} md={12}>
|
|
132
|
+
<CustomField.SingleCheckField
|
|
133
|
+
form={form}
|
|
134
|
+
name="acceptTerms"
|
|
135
|
+
labelName="I accept the terms and conditions"
|
|
136
|
+
required
|
|
137
|
+
/>
|
|
138
|
+
</Col>
|
|
139
|
+
</Row>
|
|
140
|
+
|
|
141
|
+
<Divider />
|
|
142
|
+
|
|
143
|
+
<Space>
|
|
144
|
+
<ActionButton
|
|
145
|
+
htmlType="submit"
|
|
146
|
+
buttonContent="Submit"
|
|
147
|
+
variant="primary"
|
|
148
|
+
isPending={form.formState.isSubmitting}
|
|
149
|
+
/>
|
|
150
|
+
<ActionButton
|
|
151
|
+
buttonContent="Reset"
|
|
152
|
+
variant="default"
|
|
153
|
+
handleOpen={() => form.reset()}
|
|
154
|
+
/>
|
|
155
|
+
</Space>
|
|
156
|
+
</form>
|
|
157
|
+
</Card>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|