Gathering detailed insights and metrics for @chris-c-brine/form-dialog
Gathering detailed insights and metrics for @chris-c-brine/form-dialog
Gathering detailed insights and metrics for @chris-c-brine/form-dialog
Gathering detailed insights and metrics for @chris-c-brine/form-dialog
npm install @chris-c-brine/form-dialog
Typescript
Module System
Node Version
NPM Version
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
9
20
Easy Form Dialogs with a persistable state!
A React component library that seamlessly integrates Material UI dialogs with React Hook Form, providing persistable form state, context-aware components, and simplified dialog management.
1 npm install @chris-c-brine/form-dialog
This package has the following peer dependencies that need to be installed in your project:
1// LoginPage.tsx 2import { type FC } from "react"; 3import { Container, IconButton } from "@mui/material"; 4import { useDialog } from "@chris-c-brine/form-dialog"; 5import LoginForm from "./components/forms/LoginForm"; 6import { Lock as LockIcon } from "@mui/icons-material"; 7import { LoginDialog } from "./LoginDialog"; 8 9const LoginPage: FC = () => { 10 const { dialogProps, openDialog } = useDialog(); 11 12 return ( 13 <Container 14 component="main" 15 maxWidth={"xs"} 16 sx={{ 17 display: "flex", 18 alignItems: "center", 19 justifyContent: "center", 20 height: "85vh", 21 overflow: "hidden", 22 animation: "fadeIn 1s ease-in-out", 23 "@keyframes fadeIn": { 24 from: { opacity: 0 }, 25 to: { opacity: 1 }, 26 }, 27 }} 28 > 29 <LoginForm> 30 <IconButton color="primary" onClick={openDialog} sx={{ py: 1 }}> 31 <LockIcon sx={{ fontSize: 50 }} /> 32 </IconButton> 33 </LoginForm> 34 <LoginDialog dialogProps={dialogProps} /> 35 </Container> 36 ); 37}; 38 39export default LoginPage;
1// LoginPageConstants.ts 2import type { SubmitHandler } from "react-hook-form"; 3 4export const defaultLoginFormValues = { username: "", password: "" }; 5export type LoginFormValues = typeof defaultLoginFormValues;
1// LoginFormBase.tsx 2import { TextFieldElement, PasswordElement, type PasswordElementProps, useFormContext} from "react-hook-form-mui"; 3import { memo, useEffect } from "react"; 4import { useFormDialog } from "@chris-c-brine/form-dialog"; 5import { AutoGrid, type AutoGridProps } from "@chris-c-brine/autogrid"; 6 7/** 8 * Login Form 9 */ 10export type NameProp = { 11 name?: string; 12}; 13 14export type LoginFormProps = NameProp & Pick<AutoGridProps, "columnCount">; 15const LoginFormBase = memo(function ({ name, columnCount = 1 }: LoginFormProps) { 16 const { disabled } = useFormDialog(); 17 18 return ( 19 <AutoGrid 20 columnCount={columnCount} 21 columnSpacing={2} 22 rowSpacing={1} 23 components={[ 24 <UserName key={`${name}-username`} disabled={disabled} />, 25 <Password key={`${name}-password`} disabled={disabled} />, 26 ]} 27 /> 28 ); 29}); 30 31LoginFormBase.displayName = "LoginForm"; 32 33export default LoginFormBase; 34 35/** 36 * Inputs 37 */ 38const UserName = ({ disabled }: Pick<PasswordElementProps, "disabled">) => ( 39 <TextFieldElement 40 name="username" 41 label="Username" 42 required 43 autoFocus 44 autoComplete="off" 45 fullWidth 46 margin={"dense"} 47 size={"medium"} 48 disabled={disabled} 49 slotProps={{ 50 inputLabel: { shrink: true }, 51 }} 52 /> 53); 54UserName.displayName = "UserName"; 55 56const Password = ({ disabled }: Pick<PasswordElementProps, "disabled">) => { 57 const { setValue, getValues } = useFormContext(); 58 const password = getValues("password"); 59 60 useEffect(() => { 61 if (disabled && password !== "") { 62 setValue("disabledPassword", ""); 63 } 64 }, [disabled, setValue, password]); 65 66 return ( 67 <PasswordElement 68 name={"password"} 69 label={"Password"} 70 fullWidth 71 required 72 autoComplete="off" 73 size="medium" 74 margin={"dense"} 75 disabled={disabled} 76 slotProps={{ 77 inputLabel: { shrink: true }, 78 }} 79 {...(disabled && { renderIcon: () => <></> })} 80 /> 81 ); 82}; 83 84Password.displayName = "Password";
1// LoginForm.tsx 2import { Lock as LockIcon } from "@mui/icons-material"; 3import { Box, Typography, type TypographyProps } from "@mui/material"; 4import { merge } from "lodash"; 5import { FC, PropsWithChildren, useCallback, useMemo } from "react"; 6import { FormDialogActions, FormDialogProvider, PaperForm } from "@chris-c-brine/form-dialog"; 7import { SubmitHandler, useForm } from "react-hook-form-mui"; 8import { defaultLoginFormValues, LoginFormValues } from "./LoginPageConstants"; 9import LoginFormBase from "./LoginFormBase"; 10import { globalErrorAtom, useUser } from "@features"; 11import { useSetAtom } from "jotai/index"; 12import { Person as PersonIcon } from "@mui/icons-material"; 13 14const AltIcon = () => <LockIcon sx={{ mr: 1, fontSize: 20 }} />; 15 16export const LoginForm: FC<PropsWithChildren> = ({ children }) => { 17 18 return ( 19 <LoginPaperForm> 20 <Box px={2}> 21 {children} 22 <SecureLoginText /> 23 <LoginFormBase name="page-form" columnCount={1} /> 24 </Box> 25 <FormDialogActions 26 removeCancelButton={true} 27 gridProps={{ mt:3, mb:1,px:2 }} 28 submitProps={{ 29 altIcon: <AltIcon />, 30 children: "Log In", 31 maxAttempts: 5, 32 }} 33 /> 34 </LoginPaperForm> 35 ); 36}; 37 38const SecureLoginText: FC<TypographyProps> = (props) => { 39 const typographyProps = merge( 40 { 41 component: "h1", 42 variant: "h5", 43 sx: { marginBottom: "20px" }, 44 }, 45 props, 46 ); 47 return <Typography {...typographyProps}>Secure Login</Typography>; 48}; 49 50const LoginPaperForm: FC<PropsWithChildren> = ({ children }) => { 51 const formContext = useForm({defaultValues: defaultLoginFormValues}); 52 const { setUser } = useUser(); 53 const setError = useSetAtom(globalErrorAtom); 54 const reset = useMemo(() => formContext.reset, [formContext?.reset]); 55 56 const onSuccess: SubmitHandler<LoginFormValues> = useCallback( 57 (data, event) => { 58 event?.preventDefault(); // Stop default html form submit 59 event?.stopPropagation(); // STOP!!!!! 60 61 setUser({ name: data.username, isActive: true }); // Update User (and/or other business logic) 62 reset(); // reset form 63 setError({ // Signal Success! 64 message: <>Hello {data.username}!</>, 65 title: "Successful Login!", 66 severity: "success", 67 icon: <PersonIcon sx={{ fontSize: 35 }} />, 68 }); 69 }, [setUser, setError, reset]); 70 71 return ( 72 <FormDialogProvider> 73 <PaperForm 74 persistKey={'login-page-form'} 75 formProps={{ 76 formContext, 77 onSuccess, 78 onError: (errors, event) => { 79 event?.preventDefault(); 80 console.log(errors) 81 }, 82 }} 83 elevation={3} 84 sx={{ 85 padding: "20px", 86 marginTop: "50px", 87 textAlign: "center", 88 }} 89 > 90 {children} 91 </PaperForm> 92 </FormDialogProvider> 93 ); 94};
1// LoginDialog.tsx 2import { useDialog, FormDialog, FormDialogActions } from "@chris-c-brine/form-dialog"; 3import { memo, useCallback, useMemo } from "react"; 4import LoginFormBase from "./LoginFormBase"; 5import { defaultLoginFormValues, LoginFormValues } from "./LoginPageConstants"; 6import { SubmitHandler, useForm } from "react-hook-form-mui"; 7import { globalErrorAtom, useUser } from "@features"; 8import { useSetAtom } from "jotai/index"; 9import { Person as PersonIcon } from "@mui/icons-material"; 10 11const formKey = "dialog-login-form"; 12 13export type LoginDialogProps = { 14 dialogProps: ReturnType<typeof useDialog>["dialogProps"]; 15}; 16 17export const LoginDialog = memo(function ({ dialogProps }: LoginDialogProps) { 18 const setError = useSetAtom(globalErrorAtom); 19 const { setUser } = useUser(); 20 const formContext = useForm({ defaultValues: defaultLoginFormValues }); 21 22 const reset = useMemo(() => formContext.reset, [formContext?.reset]); 23 24 const onSuccess: SubmitHandler<LoginFormValues> = useCallback( 25 (data, event) => { 26 event?.preventDefault(); 27 event?.stopPropagation(); 28 29 console.log(event); 30 setUser({ name: data.username, isActive: true }); // Update User (and/or other business logic) 31 reset(); // reset form 32 setError({ 33 // Signal Success! 34 message: <>Hello {data.username}!</>, 35 title: "Successful Login!", 36 severity: "success", 37 icon: <PersonIcon sx={{ fontSize: 35 }} />, 38 }); 39 dialogProps?.onClose(); 40 }, 41 [setUser, setError, dialogProps, reset], 42 ); 43 44 return ( 45 <FormDialog 46 {...dialogProps} 47 persistKey={formKey} 48 formProps={{ onSuccess, formContext }} 49 title={"Basic Persist Form Dialog Test"} 50 titleProps={{ variant: "h5", textAlign: "center" }} 51 actions={<FormDialogActions resetProps={{ formKey }} submitProps={{ maxAttempts: 3 }} />} 52 > 53 <LoginFormBase columnCount={2} /> 54 </FormDialog> 55 ); 56}); 57 58LoginDialog.displayName = "LoginDialog"; 59
AAL © Christopher C. Brine
No vulnerabilities found.
No security vulnerabilities found.