-
-
Notifications
You must be signed in to change notification settings - Fork 344
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SignInPage] Allow slotProps to override all labels (#4418)
- Loading branch information
1 parent
1826da5
commit 3ecf527
Showing
7 changed files
with
159 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,6 @@ import Stack from '@mui/material/Stack'; | |
import Checkbox from '@mui/material/Checkbox'; | ||
import Container from '@mui/material/Container'; | ||
import Divider from '@mui/material/Divider'; | ||
import InputLabel from '@mui/material/InputLabel'; | ||
import FormControlLabel from '@mui/material/FormControlLabel'; | ||
import TextField, { TextFieldProps } from '@mui/material/TextField'; | ||
import Typography from '@mui/material/Typography'; | ||
|
@@ -17,7 +16,7 @@ import GitHubIcon from '@mui/icons-material/GitHub'; | |
import PasswordIcon from '@mui/icons-material/Password'; | ||
import FingerprintIcon from '@mui/icons-material/Fingerprint'; | ||
import AppleIcon from '@mui/icons-material/Apple'; | ||
import { alpha, useTheme, SxProps } from '@mui/material/styles'; | ||
import { alpha, useTheme, SxProps, type Theme } from '@mui/material/styles'; | ||
import { LinkProps } from '@mui/material/Link'; | ||
import GoogleIcon from './icons/Google'; | ||
import FacebookIcon from './icons/Facebook'; | ||
|
@@ -40,6 +39,49 @@ import FusionAuthIcon from './icons/FusionAuth'; | |
import { BrandingContext, RouterContext } from '../shared/context'; | ||
import { DocsContext } from '../internal/context'; | ||
|
||
const mergeSlotSx = (defaultSx: SxProps<Theme>, slotProps?: { sx?: SxProps<Theme> }) => { | ||
if (Array.isArray(slotProps?.sx)) { | ||
return [defaultSx, ...slotProps.sx]; | ||
} | ||
|
||
if (slotProps?.sx) { | ||
return [defaultSx, slotProps?.sx]; | ||
} | ||
|
||
return [defaultSx]; | ||
}; | ||
|
||
const getCommonTextFieldProps = (theme: Theme, baseProps: TextFieldProps = {}): TextFieldProps => ({ | ||
required: true, | ||
fullWidth: true, | ||
...baseProps, | ||
slotProps: { | ||
...baseProps.slotProps, | ||
htmlInput: { | ||
...baseProps.slotProps?.htmlInput, | ||
sx: mergeSlotSx( | ||
{ | ||
paddingTop: theme.spacing(1), | ||
paddingBottom: theme.spacing(1), | ||
}, | ||
typeof baseProps.slotProps?.htmlInput === 'function' ? {} : baseProps.slotProps?.htmlInput, | ||
), | ||
}, | ||
inputLabel: { | ||
...baseProps.slotProps?.inputLabel, | ||
sx: mergeSlotSx( | ||
{ | ||
lineHeight: theme.typography.pxToRem(12), | ||
fontSize: theme.typography.pxToRem(14), | ||
}, | ||
typeof baseProps.slotProps?.inputLabel === 'function' | ||
? {} | ||
: baseProps.slotProps?.inputLabel, | ||
), | ||
}, | ||
}, | ||
}); | ||
|
||
type SupportedOAuthProvider = | ||
| 'github' | ||
| 'google' | ||
|
@@ -380,37 +422,19 @@ function SignInPage(props: SignInPageProps) { | |
{slots?.emailField ? ( | ||
<slots.emailField {...slotProps?.emailField} /> | ||
) : ( | ||
<Box sx={{ marginBottom: theme.spacing(1) }}> | ||
<InputLabel shrink htmlFor="email-passkey" sx={{ marginBottom: 0 }}> | ||
</InputLabel> | ||
<TextField | ||
required | ||
slotProps={{ | ||
htmlInput: { | ||
sx: { | ||
paddingTop: theme.spacing(1), | ||
paddingBottom: theme.spacing(1), | ||
}, | ||
}, | ||
inputLabel: { | ||
sx: { | ||
lineHeight: theme.typography.pxToRem(12), | ||
}, | ||
}, | ||
}} | ||
fullWidth | ||
placeholder="[email protected]" | ||
id="email-passkey" | ||
name="email" | ||
type="email" | ||
autoComplete="email-webauthn" | ||
autoFocus={docs ? false : singleProvider} | ||
{...slotProps?.emailField} | ||
/> | ||
</Box> | ||
<TextField | ||
{...getCommonTextFieldProps(theme, { | ||
label: 'Email', | ||
placeholder: '[email protected]', | ||
id: 'email-passkey', | ||
name: 'email', | ||
type: 'email', | ||
autoComplete: 'email-webauthn', | ||
autoFocus: docs ? false : singleProvider, | ||
...slotProps?.emailField, | ||
})} | ||
/> | ||
)} | ||
|
||
{slots?.submitButton ? ( | ||
<slots.submitButton {...slotProps?.submitButton} /> | ||
) : ( | ||
|
@@ -469,36 +493,22 @@ function SignInPage(props: SignInPageProps) { | |
})); | ||
}} | ||
> | ||
<Box sx={{ marginBottom: theme.spacing(1) }}> | ||
<InputLabel shrink htmlFor="email-nodemailer" sx={{ marginBottom: 0 }}> | ||
</InputLabel> | ||
{slots?.emailField ? ( | ||
<slots.emailField {...slotProps?.emailField} /> | ||
) : ( | ||
<TextField | ||
required | ||
slotProps={{ | ||
htmlInput: { | ||
sx: { | ||
paddingTop: theme.spacing(1), | ||
paddingBottom: theme.spacing(1), | ||
}, | ||
}, | ||
inputLabel: { | ||
sx: { | ||
lineHeight: theme.typography.pxToRem(12), | ||
}, | ||
}, | ||
}} | ||
fullWidth | ||
placeholder="[email protected]" | ||
name="email" | ||
id="email-nodemailer" | ||
type="email" | ||
autoComplete="email-nodemailer" | ||
autoFocus={docs ? false : singleProvider} | ||
{...slotProps?.emailField} | ||
{...getCommonTextFieldProps(theme, { | ||
label: 'Email', | ||
placeholder: '[email protected]', | ||
name: 'email', | ||
id: 'email-nodemailer', | ||
type: 'email', | ||
autoComplete: 'email-nodemailer', | ||
autoFocus: docs ? false : singleProvider, | ||
...slotProps?.emailField, | ||
})} | ||
/> | ||
</Box> | ||
|
||
)} | ||
{slots?.submitButton ? ( | ||
<slots.submitButton {...slotProps?.submitButton} /> | ||
) : ( | ||
|
@@ -555,84 +565,64 @@ function SignInPage(props: SignInPageProps) { | |
})); | ||
}} | ||
> | ||
{slots?.emailField ? ( | ||
<slots.emailField {...slotProps?.emailField} /> | ||
) : ( | ||
<Box sx={{ marginBottom: theme.spacing(1) }}> | ||
<InputLabel shrink htmlFor="email" sx={{ marginBottom: 0 }}> | ||
</InputLabel> | ||
<Stack direction="column" spacing={2} sx={{ mb: 2 }}> | ||
{slots?.emailField ? ( | ||
<slots.emailField {...slotProps?.emailField} /> | ||
) : ( | ||
<TextField | ||
required | ||
slotProps={{ | ||
htmlInput: { | ||
sx: { | ||
paddingTop: theme.spacing(1), | ||
paddingBottom: theme.spacing(1), | ||
}, | ||
}, | ||
inputLabel: { | ||
sx: { | ||
lineHeight: theme.typography.pxToRem(12), | ||
}, | ||
}, | ||
}} | ||
placeholder="[email protected]" | ||
fullWidth | ||
id="email" | ||
name="email" | ||
type="email" | ||
autoComplete="email" | ||
autoFocus={docs ? false : singleProvider} | ||
{...slotProps?.emailField} | ||
{...getCommonTextFieldProps(theme, { | ||
label: 'Email', | ||
placeholder: '[email protected]', | ||
id: 'email', | ||
name: 'email', | ||
type: 'email', | ||
autoComplete: 'email', | ||
autoFocus: docs ? false : singleProvider, | ||
...slotProps?.emailField, | ||
})} | ||
/> | ||
</Box> | ||
)} | ||
|
||
{slots?.passwordField ? ( | ||
<slots.passwordField {...slotProps?.passwordField} /> | ||
) : ( | ||
<React.Fragment> | ||
<InputLabel shrink htmlFor="password" sx={{ marginBottom: 0 }}> | ||
Password | ||
</InputLabel> | ||
|
||
)} | ||
{slots?.passwordField ? ( | ||
<slots.passwordField {...slotProps?.passwordField} /> | ||
) : ( | ||
<TextField | ||
required | ||
fullWidth | ||
slotProps={{ | ||
htmlInput: { | ||
sx: { | ||
paddingTop: theme.spacing(1), | ||
paddingBottom: theme.spacing(1), | ||
}, | ||
}, | ||
inputLabel: { | ||
sx: { | ||
lineHeight: theme.typography.pxToRem(16), | ||
}, | ||
}, | ||
}} | ||
name="password" | ||
type="password" | ||
id="password" | ||
placeholder="******" | ||
autoComplete="current-password" | ||
{...slotProps?.passwordField} | ||
{...getCommonTextFieldProps(theme, { | ||
name: 'password', | ||
type: 'password', | ||
label: 'Password', | ||
id: 'password', | ||
placeholder: '*****', | ||
autoComplete: 'current-password', | ||
...slotProps?.passwordField, | ||
})} | ||
/> | ||
</React.Fragment> | ||
)} | ||
|
||
)} | ||
</Stack> | ||
<Stack | ||
direction="row" | ||
justifyContent="space-between" | ||
alignItems="center" | ||
spacing={1} | ||
sx={{ | ||
justifyContent: 'space-between', | ||
}} | ||
> | ||
<FormControlLabel | ||
control={<Checkbox name="remember" value="true" color="primary" />} | ||
control={ | ||
<Checkbox | ||
name="remember" | ||
value="true" | ||
color="primary" | ||
sx={{ padding: 0.5, '& .MuiSvgIcon-root': { fontSize: 20 } }} | ||
/> | ||
} | ||
label="Remember me" | ||
slotProps={{ typography: { color: 'textSecondary' } }} | ||
slotProps={{ | ||
typography: { | ||
color: 'textSecondary', | ||
fontSize: theme.typography.pxToRem(14), | ||
}, | ||
}} | ||
/> | ||
{slots?.forgotPasswordLink ? ( | ||
<slots.forgotPasswordLink {...slotProps?.forgotPasswordLink} /> | ||
|
Oops, something went wrong.