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,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiRadioGroup, { RadioGroupProps as MuiRadioGroupProps } from '@mui/material/RadioGroup';
|
|
3
|
+
import MuiRadio from '@mui/material/Radio';
|
|
4
|
+
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
5
|
+
import FormControl from '@mui/material/FormControl';
|
|
6
|
+
import { styled } from '@mui/material/styles';
|
|
7
|
+
|
|
8
|
+
const StyledRadio = styled(MuiRadio)(({ theme }) => ({
|
|
9
|
+
color: theme.palette.text.secondary,
|
|
10
|
+
'&.Mui-checked': {
|
|
11
|
+
color: theme.palette.primary.main,
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
export type RadioGroupProps = MuiRadioGroupProps;
|
|
16
|
+
|
|
17
|
+
export function RadioGroup(props: RadioGroupProps) {
|
|
18
|
+
return <MuiRadioGroup {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const RadioGroupItem = StyledRadio;
|
|
22
|
+
|
|
23
|
+
export function RadioItem({ label, ...props }: { label?: React.ReactNode; value: string }) {
|
|
24
|
+
return <FormControlLabel control={<StyledRadio {...props} />} label={label} />;
|
|
25
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import { styled } from '@mui/material/styles';
|
|
4
|
+
|
|
5
|
+
const ScrollAreaRoot = styled(Box)({
|
|
6
|
+
overflow: 'auto',
|
|
7
|
+
position: 'relative',
|
|
8
|
+
'&::-webkit-scrollbar': {
|
|
9
|
+
width: 8,
|
|
10
|
+
height: 8,
|
|
11
|
+
},
|
|
12
|
+
'&::-webkit-scrollbar-track': {
|
|
13
|
+
backgroundColor: 'transparent',
|
|
14
|
+
},
|
|
15
|
+
'&::-webkit-scrollbar-thumb': {
|
|
16
|
+
backgroundColor: 'rgba(0,0,0,0.2)',
|
|
17
|
+
borderRadius: 4,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export type ScrollAreaProps = { children: React.ReactNode; className?: string };
|
|
22
|
+
|
|
23
|
+
export function ScrollArea({ children, ...props }: ScrollAreaProps) {
|
|
24
|
+
return <ScrollAreaRoot {...props}>{children}</ScrollAreaRoot>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const ScrollBar = Box;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiSelect, { SelectProps as MuiSelectProps } from '@mui/material/Select';
|
|
3
|
+
import MenuItem from '@mui/material/MenuItem';
|
|
4
|
+
import FormControl from '@mui/material/FormControl';
|
|
5
|
+
import InputLabel from '@mui/material/InputLabel';
|
|
6
|
+
import { styled } from '@mui/material/styles';
|
|
7
|
+
|
|
8
|
+
const StyledSelect = styled(MuiSelect)(({ theme }) => ({
|
|
9
|
+
borderRadius: theme.shape.borderRadius,
|
|
10
|
+
'& .MuiOutlinedInput-notchedOutline': {
|
|
11
|
+
borderRadius: theme.shape.borderRadius,
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
export type SelectProps = MuiSelectProps;
|
|
16
|
+
|
|
17
|
+
export function Select(props: SelectProps) {
|
|
18
|
+
return <StyledSelect {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const SelectItem = MenuItem;
|
|
22
|
+
export const SelectGroup = FormControl;
|
|
23
|
+
export const SelectLabel = InputLabel;
|
|
24
|
+
export const SelectValue = MuiSelect;
|
|
25
|
+
export const SelectTrigger = StyledSelect;
|
|
26
|
+
export const SelectContent = ({ children, ...props }: { children: React.ReactNode } & Record<string, any>) => <>{children}</>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import Divider from '@mui/material/Divider';
|
|
3
|
+
|
|
4
|
+
export type SeparatorProps = {
|
|
5
|
+
orientation?: 'horizontal' | 'vertical';
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function Separator({ orientation = 'horizontal', ...props }: SeparatorProps) {
|
|
10
|
+
return <Divider orientation={orientation === 'vertical' ? 'vertical' : 'horizontal'} {...props} />;
|
|
11
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiDrawer, { DrawerProps as MuiDrawerProps } from '@mui/material/Drawer';
|
|
3
|
+
import Box from '@mui/material/Box';
|
|
4
|
+
import IconButton from '@mui/material/IconButton';
|
|
5
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
6
|
+
import Typography from '@mui/material/Typography';
|
|
7
|
+
import { styled } from '@mui/material/styles';
|
|
8
|
+
|
|
9
|
+
const StyledSheet = styled(MuiDrawer)(({ theme }) => ({
|
|
10
|
+
'& .MuiDrawer-paper': {
|
|
11
|
+
borderRadius: 0,
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
export type SheetProps = MuiDrawerProps;
|
|
16
|
+
|
|
17
|
+
export function Sheet(props: SheetProps) {
|
|
18
|
+
return <StyledSheet {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const SheetTrigger = ({ children, onClick }: { children: React.ReactNode; onClick?: () => void }) => <>{children}</>;
|
|
22
|
+
export const SheetClose = CloseIcon;
|
|
23
|
+
export const SheetPortal = Box;
|
|
24
|
+
|
|
25
|
+
export function SheetContent({ children, onClose, title, ...props }: SheetProps & { title?: string }) {
|
|
26
|
+
return (
|
|
27
|
+
<StyledSheet {...props} onClose={onClose}>
|
|
28
|
+
<Box sx={{ p: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: 1, borderColor: 'divider' }}>
|
|
29
|
+
{title && <Typography variant="h6">{title}</Typography>}
|
|
30
|
+
{onClose && (
|
|
31
|
+
<IconButton onClick={() => onClose({}, 'escapeKeyDown')}>
|
|
32
|
+
<CloseIcon />
|
|
33
|
+
</IconButton>
|
|
34
|
+
)}
|
|
35
|
+
</Box>
|
|
36
|
+
<Box sx={{ p: 2 }}>{children}</Box>
|
|
37
|
+
</StyledSheet>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const SheetHeader = Box;
|
|
42
|
+
export const SheetFooter = Box;
|
|
43
|
+
export const SheetTitle = Typography;
|
|
44
|
+
export const SheetDescription = Typography;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiSwitch, { SwitchProps as MuiSwitchProps } from '@mui/material/Switch';
|
|
3
|
+
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
5
|
+
|
|
6
|
+
const StyledSwitch = styled(MuiSwitch)(({ theme }) => ({
|
|
7
|
+
'& .MuiSwitch-switchBase.Mui-checked': {
|
|
8
|
+
color: theme.palette.primary.main,
|
|
9
|
+
},
|
|
10
|
+
'& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': {
|
|
11
|
+
backgroundColor: theme.palette.primary.main,
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
export type SwitchProps = MuiSwitchProps;
|
|
16
|
+
|
|
17
|
+
export function Switch(props: SwitchProps) {
|
|
18
|
+
return <StyledSwitch {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function SwitchLabel({ label, ...props }: SwitchProps & { label?: React.ReactNode }) {
|
|
22
|
+
return <FormControlLabel control={<Switch {...props} />} label={label} />;
|
|
23
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiTable, { TableProps as MuiTableProps } from '@mui/material/Table';
|
|
3
|
+
import MuiTableBody from '@mui/material/TableBody';
|
|
4
|
+
import MuiTableCell from '@mui/material/TableCell';
|
|
5
|
+
import MuiTableContainer from '@mui/material/TableContainer';
|
|
6
|
+
import MuiTableHead from '@mui/material/TableHead';
|
|
7
|
+
import MuiTableRow from '@mui/material/TableRow';
|
|
8
|
+
import MuiTableFooter from '@mui/material/TableFooter';
|
|
9
|
+
import MuiTablePagination from '@mui/material/TablePagination';
|
|
10
|
+
import Paper from '@mui/material/Paper';
|
|
11
|
+
import { styled } from '@mui/material/styles';
|
|
12
|
+
|
|
13
|
+
const StyledTableContainer = styled(MuiTableContainer)(({ theme }) => ({
|
|
14
|
+
borderRadius: theme.shape.borderRadius,
|
|
15
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
export type TableProps = MuiTableProps;
|
|
19
|
+
|
|
20
|
+
export function Table({ children, ...props }: TableProps) {
|
|
21
|
+
return (
|
|
22
|
+
<StyledTableContainer component={Paper}>
|
|
23
|
+
<MuiTable {...props}>{children}</MuiTable>
|
|
24
|
+
</StyledTableContainer>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const TableHeader = MuiTableHead;
|
|
29
|
+
export const TableBody = MuiTableBody;
|
|
30
|
+
export const TableFooter = MuiTableFooter;
|
|
31
|
+
export const TableRow = MuiTableRow;
|
|
32
|
+
export const TableHead = MuiTableCell;
|
|
33
|
+
export const TableCell = MuiTableCell;
|
|
34
|
+
export const TableCaption = MuiTablePagination;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiTabs, { TabsProps as MuiTabsProps } from '@mui/material/Tabs';
|
|
3
|
+
import MuiTab, { TabProps as MuiTabProps } from '@mui/material/Tab';
|
|
4
|
+
import Box from '@mui/material/Box';
|
|
5
|
+
import { styled } from '@mui/material/styles';
|
|
6
|
+
|
|
7
|
+
const StyledTabs = styled(MuiTabs)(({ theme }) => ({
|
|
8
|
+
'& .MuiTabs-indicator': {
|
|
9
|
+
backgroundColor: theme.palette.primary.main,
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const StyledTab = styled(MuiTab)(({ theme }) => ({
|
|
14
|
+
textTransform: 'none',
|
|
15
|
+
fontWeight: 500,
|
|
16
|
+
borderRadius: theme.shape.borderRadius,
|
|
17
|
+
'&.Mui-selected': {
|
|
18
|
+
color: theme.palette.primary.main,
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
export type TabsProps = MuiTabsProps;
|
|
23
|
+
export type TabProps = MuiTabProps;
|
|
24
|
+
|
|
25
|
+
export function Tabs(props: TabsProps) {
|
|
26
|
+
return <StyledTabs {...props} />;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const TabsList = StyledTabs;
|
|
30
|
+
export const TabsTrigger = StyledTab;
|
|
31
|
+
|
|
32
|
+
export function TabsContent({ children, value, ...props }: { children: React.ReactNode; value: any } & Record<string, any>) {
|
|
33
|
+
return (
|
|
34
|
+
<Box role="tabpanel" {...props}>
|
|
35
|
+
{children}
|
|
36
|
+
</Box>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiTextField, { TextFieldProps as MuiTextFieldProps } from '@mui/material/TextField';
|
|
3
|
+
import { styled } from '@mui/material/styles';
|
|
4
|
+
|
|
5
|
+
const StyledTextarea = styled(MuiTextField)(({ theme }) => ({
|
|
6
|
+
'& .MuiOutlinedInput-root': {
|
|
7
|
+
borderRadius: theme.shape.borderRadius,
|
|
8
|
+
},
|
|
9
|
+
'& textarea': {
|
|
10
|
+
minHeight: 80,
|
|
11
|
+
},
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
export type TextareaProps = MuiTextFieldProps;
|
|
15
|
+
|
|
16
|
+
export function Textarea(props: TextareaProps) {
|
|
17
|
+
return <StyledTextarea variant="outlined" fullWidth multiline {...props} />;
|
|
18
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MuiTooltip, { TooltipProps as MuiTooltipProps } from '@mui/material/Tooltip';
|
|
3
|
+
import { styled } from '@mui/material/styles';
|
|
4
|
+
|
|
5
|
+
const StyledTooltip = styled(MuiTooltip)({
|
|
6
|
+
'& .MuiTooltip-tooltip': {
|
|
7
|
+
fontSize: '0.75rem',
|
|
8
|
+
padding: '6px 12px',
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type TooltipProps = MuiTooltipProps;
|
|
13
|
+
export type TooltipProviderProps = { children: React.ReactNode };
|
|
14
|
+
|
|
15
|
+
export function TooltipProvider({ children }: TooltipProviderProps) {
|
|
16
|
+
return <>{children}</>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function Tooltip(props: TooltipProps) {
|
|
20
|
+
return <StyledTooltip {...props} />;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const TooltipTrigger = ({ children, ...props }: { children: React.ReactElement } & Record<string, any>) => children;
|
|
24
|
+
export const TooltipContent = MuiTooltip;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { createTheme } from '@mui/material/styles';
|
|
3
|
+
|
|
4
|
+
export const theme = createTheme({
|
|
5
|
+
colorSchemes: {
|
|
6
|
+
light: {
|
|
7
|
+
palette: {
|
|
8
|
+
primary: { main: '#2563eb' },
|
|
9
|
+
secondary: { main: '#64748b' },
|
|
10
|
+
error: { main: '#dc2626' },
|
|
11
|
+
warning: { main: '#f59e0b' },
|
|
12
|
+
success: { main: '#16a34a' },
|
|
13
|
+
info: { main: '#0ea5e9' },
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
dark: {
|
|
17
|
+
palette: {
|
|
18
|
+
primary: { main: '#60a5fa' },
|
|
19
|
+
secondary: { main: '#94a3b8' },
|
|
20
|
+
error: { main: '#f87171' },
|
|
21
|
+
warning: { main: '#fbbf24' },
|
|
22
|
+
success: { main: '#4ade80' },
|
|
23
|
+
info: { main: '#38bdf8' },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
shape: { borderRadius: 8 },
|
|
28
|
+
typography: {
|
|
29
|
+
fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
|
|
30
|
+
},
|
|
31
|
+
components: {
|
|
32
|
+
MuiButton: {
|
|
33
|
+
styleOverrides: {
|
|
34
|
+
root: {
|
|
35
|
+
textTransform: 'none',
|
|
36
|
+
borderRadius: 8,
|
|
37
|
+
fontWeight: 500,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
MuiTextField: {
|
|
42
|
+
styleOverrides: {
|
|
43
|
+
root: {
|
|
44
|
+
'& .MuiOutlinedInput-root': {
|
|
45
|
+
borderRadius: 8,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
MuiCard: {
|
|
51
|
+
styleOverrides: {
|
|
52
|
+
root: {
|
|
53
|
+
borderRadius: 8,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
MuiDialog: {
|
|
58
|
+
styleOverrides: {
|
|
59
|
+
paper: {
|
|
60
|
+
borderRadius: 8,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
MuiChip: {
|
|
65
|
+
styleOverrides: {
|
|
66
|
+
root: {
|
|
67
|
+
fontWeight: 600,
|
|
68
|
+
fontSize: '0.75rem',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { ThemeProvider } from '@mui/material/styles';
|
|
3
|
+
import CssBaseline from '@mui/material/CssBaseline';
|
|
4
|
+
import { theme } from '@/lib/theme.util';
|
|
5
|
+
|
|
6
|
+
export function MuiProvider({ children }: { children: React.ReactNode }) {
|
|
7
|
+
return (
|
|
8
|
+
<ThemeProvider theme={theme}>
|
|
9
|
+
<CssBaseline />
|
|
10
|
+
{children}
|
|
11
|
+
</ThemeProvider>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Custom Component System — Usage Guide
|
|
2
|
+
|
|
3
|
+
This project includes a reusable, dynamic component system built on shadcn/ui + react-hook-form + zod. Every component follows a **dual-mode** pattern: works with or without react-hook-form.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. CustomField — Dynamic Form Fields
|
|
8
|
+
|
|
9
|
+
A compound object (`CustomField.*`) that registers all field types. Each field auto-wraps in shadcn `<FormField>` when given a `form` prop, or renders standalone with `value`/`setValue`.
|
|
10
|
+
|
|
11
|
+
### Available Fields
|
|
12
|
+
|
|
13
|
+
| Component | Usage |
|
|
14
|
+
|-----------|-------|
|
|
15
|
+
| `CustomField.Text` | Single-line text with optional left/right icons, array input |
|
|
16
|
+
| `CustomField.TextArea` | Multi-line text with configurable rows |
|
|
17
|
+
| `CustomField.Number` | Number input (integer/float) |
|
|
18
|
+
| `CustomField.StringNumber` | Numeric string (digits only, e.g. roll number, PIN) |
|
|
19
|
+
| `CustomField.Password` | Password with show/hide toggle |
|
|
20
|
+
| `CustomField.SingleSelectField` | Single-select dropdown (wraps shadcn Select) |
|
|
21
|
+
| `CustomField.SelectField` | Advanced select with search, single/multiple, images, flags |
|
|
22
|
+
| `CustomField.Switch` | Toggle switch with optional border/label/description |
|
|
23
|
+
| `CustomField.RadioField` | Radio group from options array |
|
|
24
|
+
| `CustomField.CheckField` | Multi-checkbox group from options array |
|
|
25
|
+
| `CustomField.MultiCheckField` | Alternative multi-checkbox (same as CheckField) |
|
|
26
|
+
| `CustomField.SingleCheckField` | Single checkbox with optional description |
|
|
27
|
+
| `CustomField.SearchField` | Search input with clear button |
|
|
28
|
+
| `CustomField.DatePickerField` | Native date picker input |
|
|
29
|
+
| `CustomField.PhoneNumber` | Telephone input (`type="tel"`) |
|
|
30
|
+
|
|
31
|
+
### Shared Props (all fields)
|
|
32
|
+
|
|
33
|
+
| Prop | Type | Default | Description |
|
|
34
|
+
|------|------|---------|-------------|
|
|
35
|
+
| `form` | `UseFormReturn` | — | react-hook-form instance (omit for standalone) |
|
|
36
|
+
| `name` | `string` | — | Field name in form schema |
|
|
37
|
+
| `labelName` | `string` | — | Visible label text |
|
|
38
|
+
| `required` | `boolean` | `false` | Shows red asterisk |
|
|
39
|
+
| `disabled` | `boolean` | `false` | Disables input |
|
|
40
|
+
| `viewOnly` | `boolean` | `false` | Renders plain text instead of input |
|
|
41
|
+
| `disableLabelFormatting` | `boolean` | `false` | Skip auto-formatting of label text |
|
|
42
|
+
| `customMessage` | `string\|ReactNode` | — | Custom message below field |
|
|
43
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
44
|
+
|
|
45
|
+
### With react-hook-form (controlled)
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { useForm } from 'react-hook-form';
|
|
49
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
50
|
+
import { z } from 'zod';
|
|
51
|
+
import { Form } from '@/components/ui/form.component';
|
|
52
|
+
import { CustomField } from '@/components/common/fields/cusInputField.component';
|
|
53
|
+
|
|
54
|
+
const schema = z.object({
|
|
55
|
+
name: z.string().min(1, 'Required'),
|
|
56
|
+
email: z.string().email('Invalid email'),
|
|
57
|
+
role: z.string().min(1),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export function UserForm() {
|
|
61
|
+
const form = useForm({ resolver: zodResolver(schema) });
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<Form {...form}>
|
|
65
|
+
<form onSubmit={form.handleSubmit(console.log)} className="space-y-4">
|
|
66
|
+
<CustomField.Text form={form} name="name" labelName="Full Name" required />
|
|
67
|
+
<CustomField.Text
|
|
68
|
+
form={form}
|
|
69
|
+
name="email"
|
|
70
|
+
labelName="Email"
|
|
71
|
+
placeholder="Enter email"
|
|
72
|
+
leftIcon={<MailIcon />}
|
|
73
|
+
/>
|
|
74
|
+
<CustomField.SingleSelectField
|
|
75
|
+
form={form}
|
|
76
|
+
name="role"
|
|
77
|
+
labelName="Role"
|
|
78
|
+
options={['admin', 'user', 'editor']}
|
|
79
|
+
/>
|
|
80
|
+
<Button type="submit">Submit</Button>
|
|
81
|
+
</form>
|
|
82
|
+
</Form>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Standalone (uncontrolled)
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
const [email, setEmail] = useState('');
|
|
91
|
+
|
|
92
|
+
<CustomField.Text
|
|
93
|
+
name="email"
|
|
94
|
+
labelName="Email"
|
|
95
|
+
value={email}
|
|
96
|
+
setValue={setEmail}
|
|
97
|
+
placeholder="Enter email"
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 2. DynamicTable — Config-Driven Table
|
|
104
|
+
|
|
105
|
+
Renders a table from a `columns` config array, with loading/empty states, optional checkboxes, and expandable rows.
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { DynamicTable } from '@/components/common/DynamicTable/dynamic-table.component';
|
|
109
|
+
|
|
110
|
+
const columns = [
|
|
111
|
+
{ key: 'name', header: 'Name' },
|
|
112
|
+
{ key: 'email', header: 'Email' },
|
|
113
|
+
{
|
|
114
|
+
key: 'status',
|
|
115
|
+
header: 'Status',
|
|
116
|
+
render: (row) => (
|
|
117
|
+
<Badge variant={row.active ? 'default' : 'secondary'}>
|
|
118
|
+
{row.active ? 'Active' : 'Inactive'}
|
|
119
|
+
</Badge>
|
|
120
|
+
),
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
key: 'actions',
|
|
124
|
+
header: '',
|
|
125
|
+
render: (row) => (
|
|
126
|
+
<ActionButton
|
|
127
|
+
variant="outline"
|
|
128
|
+
buttonContent="Edit"
|
|
129
|
+
handleOpen={() => handleEdit(row)}
|
|
130
|
+
/>
|
|
131
|
+
),
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
<DynamicTable
|
|
136
|
+
data={users}
|
|
137
|
+
isLoading={loading}
|
|
138
|
+
currentPage={page}
|
|
139
|
+
setCurrentPage={setPage}
|
|
140
|
+
config={{ columns, emptyMessage: 'No users found' }}
|
|
141
|
+
/>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### With checkbox selection
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
148
|
+
|
|
149
|
+
<DynamicTable
|
|
150
|
+
data={users}
|
|
151
|
+
isLoading={loading}
|
|
152
|
+
currentPage={page}
|
|
153
|
+
setCurrentPage={setPage}
|
|
154
|
+
config={{ columns }}
|
|
155
|
+
isCheckBox
|
|
156
|
+
selectedIds={selected}
|
|
157
|
+
setSelectedIds={setSelected}
|
|
158
|
+
/>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 3. DialogWrapper — Reusable Modal
|
|
164
|
+
|
|
165
|
+
A scrollable dialog with sticky header, optional close button, and optional footer.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { DialogWrapper } from '@/components/common/dialog/dialog-wrapper.component';
|
|
169
|
+
|
|
170
|
+
const [open, setOpen] = useState(false);
|
|
171
|
+
|
|
172
|
+
<DialogWrapper
|
|
173
|
+
open={open}
|
|
174
|
+
setOpen={setOpen}
|
|
175
|
+
title="Edit User"
|
|
176
|
+
description="Update user details"
|
|
177
|
+
triggerContent={<Button>Open Dialog</Button>}
|
|
178
|
+
footer={<Button type="submit">Save</Button>}
|
|
179
|
+
>
|
|
180
|
+
<Form {...form}>
|
|
181
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
182
|
+
<CustomField.Text form={form} name="name" labelName="Name" required />
|
|
183
|
+
</form>
|
|
184
|
+
</Form>
|
|
185
|
+
</DialogWrapper>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Controlled from parent
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
// Parent passes open/setOpen
|
|
192
|
+
<DialogWrapper open={modalOpen} setOpen={setModalOpen}>
|
|
193
|
+
<UserForm ... />
|
|
194
|
+
</DialogWrapper>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Without trigger content
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
// Dialog opened programmatically
|
|
201
|
+
const [open, setOpen] = useState(true); // starts open
|
|
202
|
+
|
|
203
|
+
<DialogWrapper open={open} setOpen={setOpen}>
|
|
204
|
+
<p>This dialog has no trigger button.</p>
|
|
205
|
+
</DialogWrapper>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 4. ActionButton — Extended Button
|
|
211
|
+
|
|
212
|
+
A button with variant, icon positions, loading spinner, and optional tooltip.
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
import { ActionButton } from '@/components/common/button/action-button.component';
|
|
216
|
+
|
|
217
|
+
// Simple
|
|
218
|
+
<ActionButton buttonContent="Save" handleOpen={handleSave} />
|
|
219
|
+
|
|
220
|
+
// With tooltip
|
|
221
|
+
<ActionButton
|
|
222
|
+
variant="outline"
|
|
223
|
+
icon={<EditIcon />}
|
|
224
|
+
buttonContent="Edit"
|
|
225
|
+
tooltipContent="Edit this item"
|
|
226
|
+
handleOpen={() => setEditOpen(true)}
|
|
227
|
+
/>
|
|
228
|
+
|
|
229
|
+
// Loading state
|
|
230
|
+
<ActionButton
|
|
231
|
+
buttonContent="Submit"
|
|
232
|
+
isPending={isSubmitting}
|
|
233
|
+
loadingContent="Saving..."
|
|
234
|
+
type="submit"
|
|
235
|
+
/>
|
|
236
|
+
|
|
237
|
+
// With left icon only
|
|
238
|
+
<ActionButton icon={<PlusIcon />} buttonContent="Add User" variant="default" />
|
|
239
|
+
|
|
240
|
+
// Destructive
|
|
241
|
+
<ActionButton buttonContent="Delete" variant="destructive" handleOpen={handleDelete} />
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 5. Pagination — Page Navigation
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
import { Pagination } from '@/components/common/pagination/pagination.component';
|
|
250
|
+
|
|
251
|
+
<Pagination
|
|
252
|
+
currentPage={page}
|
|
253
|
+
totalPages={totalPages}
|
|
254
|
+
setCurrentPage={setPage}
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 6. Form Pattern (recommended)
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { useForm } from 'react-hook-form';
|
|
264
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
265
|
+
import { z } from 'zod';
|
|
266
|
+
import { Form } from '@/components/ui/form';
|
|
267
|
+
import { Button } from '@/components/ui/button';
|
|
268
|
+
import { CustomField } from '@/components/common/fields/cusInputField';
|
|
269
|
+
|
|
270
|
+
// 1. Define schema
|
|
271
|
+
const formSchema = z.object({
|
|
272
|
+
title: z.string().min(1, 'Title is required'),
|
|
273
|
+
description: z.string().optional(),
|
|
274
|
+
category: z.string().min(1, 'Select a category'),
|
|
275
|
+
published: z.boolean().default(false),
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
type FormData = z.infer<typeof formSchema>;
|
|
279
|
+
|
|
280
|
+
// 2. Create form
|
|
281
|
+
const form = useForm<FormData>({
|
|
282
|
+
resolver: zodResolver(formSchema),
|
|
283
|
+
defaultValues: { title: '', published: false },
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// 3. Render
|
|
287
|
+
<Form {...form}>
|
|
288
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
|
289
|
+
<CustomField.Text form={form} name="title" labelName="Title" required />
|
|
290
|
+
<CustomField.TextArea form={form} name="description" labelName="Description" rows={5} />
|
|
291
|
+
<CustomField.SingleSelectField
|
|
292
|
+
form={form}
|
|
293
|
+
name="category"
|
|
294
|
+
labelName="Category"
|
|
295
|
+
options={['tech', 'design', 'business']}
|
|
296
|
+
/>
|
|
297
|
+
<CustomField.Switch
|
|
298
|
+
form={form}
|
|
299
|
+
name="published"
|
|
300
|
+
labelName="Publish"
|
|
301
|
+
description="Make this visible to everyone"
|
|
302
|
+
/>
|
|
303
|
+
<Button type="submit" disabled={isPending}>Save</Button>
|
|
304
|
+
</form>
|
|
305
|
+
</Form>
|
|
306
|
+
```
|