diff --git a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js index 801f21ff7af..536b3b76da4 100644 --- a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js +++ b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js @@ -35,7 +35,7 @@ export default function BrandingSignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx index 61fcf280ade..f3d758e7263 100644 --- a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx @@ -35,7 +35,7 @@ export default function BrandingSignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx.preview index 73da124c69b..3e0e5aa6efe 100644 --- a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx.preview +++ b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx.preview @@ -15,6 +15,6 @@ const BRANDING = { \ No newline at end of file diff --git a/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.js b/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.js index 379664289ff..01d5cfe3684 100644 --- a/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.js +++ b/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.js @@ -27,7 +27,7 @@ export default function CredentialsSignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx b/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx index 7ebe5d41a12..07e0fb1b9c4 100644 --- a/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx @@ -30,7 +30,7 @@ export default function CredentialsSignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx.preview index 636373e5404..16fd91f00e2 100644 --- a/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx.preview +++ b/docs/data/toolpad/core/components/sign-in-page/CredentialsSignInPage.tsx.preview @@ -6,6 +6,6 @@ const providers = [{ id: 'credentials', name: 'Email and Password' }]; \ No newline at end of file diff --git a/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.js b/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.js index f9c46a79762..73800c4d07b 100644 --- a/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.js +++ b/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.js @@ -27,7 +27,7 @@ export default function MagicLinkAlertSignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx b/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx index 1097b0bda9f..f7e674890a2 100644 --- a/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx @@ -36,7 +36,7 @@ export default function MagicLinkAlertSignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx.preview index 9de4b1c4e93..0c70a80c4b8 100644 --- a/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx.preview +++ b/docs/data/toolpad/core/components/sign-in-page/MagicLinkAlertSignInPage.tsx.preview @@ -8,6 +8,6 @@ resolve({ \ No newline at end of file diff --git a/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.js b/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.js index 326abcc3c64..575370713a5 100644 --- a/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.js +++ b/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.js @@ -32,7 +32,7 @@ export default function NotificationsSignInPageError() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx b/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx index 8035b294386..373d8f60c03 100644 --- a/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx @@ -39,7 +39,7 @@ export default function NotificationsSignInPageError() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx.preview index 30677d0d20c..e6e444e2beb 100644 --- a/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx.preview +++ b/docs/data/toolpad/core/components/sign-in-page/NotificationsSignInPageError.tsx.preview @@ -9,6 +9,6 @@ resolve({ \ No newline at end of file diff --git a/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.js b/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.js index f15f1cceded..ec39c35ddda 100644 --- a/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.js +++ b/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.js @@ -24,7 +24,7 @@ export default function PasskeySignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx b/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx index c69a3758ecf..352bdc93677 100644 --- a/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx @@ -24,7 +24,7 @@ export default function PasskeySignInPage() { // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx.preview index 5c2239d907e..6d8ac519206 100644 --- a/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx.preview +++ b/docs/data/toolpad/core/components/sign-in-page/PasskeySignInPage.tsx.preview @@ -6,6 +6,6 @@ const providers = [{ id: 'passkey', name: 'Passkey' }]; \ No newline at end of file diff --git a/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.js b/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.js index 4a4c1a833f9..ee0aacbd621 100644 --- a/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.js +++ b/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.js @@ -1,32 +1,47 @@ import * as React from 'react'; import Checkbox from '@mui/material/Checkbox'; import { AppProvider } from '@toolpad/core/AppProvider'; -import { SignInPage } from '@toolpad/core/SignInPage'; +import { SignInPage, RememberMeCheckbox } from '@toolpad/core/SignInPage'; import { useTheme } from '@mui/material/styles'; -const providers = [{ id: 'credentials', name: 'Email and Password' }]; +const providers = [ + { id: 'github', name: 'GitHub' }, + { id: 'credentials', name: 'Email and Password' }, +]; export default function SlotPropsSignIn() { const theme = useTheme(); return ( - alert( - `Signing in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')} and checkbox value: ${formData.get('tandc')}`, - ) - } + signIn={(provider, formData) => { + if (provider.id === 'credentials') { + alert( + `Signing in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')} and checkbox value: ${formData.get('tandc')}`, + ); + } else { + return new Promise((resolve) => { + setTimeout(() => { + resolve({ error: 'This is a fake error' }); + }, 1000); + }); + } + return undefined; + }} + slots={{ rememberMe: RememberMeCheckbox }} slotProps={{ + form: { noValidate: true }, emailField: { variant: 'standard', autoFocus: false }, passwordField: { variant: 'standard' }, submitButton: { variant: 'outlined' }, + oauthButton: { variant: 'contained' }, rememberMe: { control: ( ), color: 'textSecondary', diff --git a/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.tsx b/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.tsx index 4a4c1a833f9..ee0aacbd621 100644 --- a/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/SlotPropsSignIn.tsx @@ -1,32 +1,47 @@ import * as React from 'react'; import Checkbox from '@mui/material/Checkbox'; import { AppProvider } from '@toolpad/core/AppProvider'; -import { SignInPage } from '@toolpad/core/SignInPage'; +import { SignInPage, RememberMeCheckbox } from '@toolpad/core/SignInPage'; import { useTheme } from '@mui/material/styles'; -const providers = [{ id: 'credentials', name: 'Email and Password' }]; +const providers = [ + { id: 'github', name: 'GitHub' }, + { id: 'credentials', name: 'Email and Password' }, +]; export default function SlotPropsSignIn() { const theme = useTheme(); return ( - alert( - `Signing in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')} and checkbox value: ${formData.get('tandc')}`, - ) - } + signIn={(provider, formData) => { + if (provider.id === 'credentials') { + alert( + `Signing in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')} and checkbox value: ${formData.get('tandc')}`, + ); + } else { + return new Promise((resolve) => { + setTimeout(() => { + resolve({ error: 'This is a fake error' }); + }, 1000); + }); + } + return undefined; + }} + slots={{ rememberMe: RememberMeCheckbox }} slotProps={{ + form: { noValidate: true }, emailField: { variant: 'standard', autoFocus: false }, passwordField: { variant: 'standard' }, submitButton: { variant: 'outlined' }, + oauthButton: { variant: 'contained' }, rememberMe: { control: ( ), color: 'textSecondary', diff --git a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js index f67f1a9f1aa..54e6cab2e6e 100644 --- a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js +++ b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js @@ -2,8 +2,6 @@ import * as React from 'react'; import { Button, FormControl, - FormControlLabel, - Checkbox, InputLabel, OutlinedInput, TextField, @@ -16,7 +14,7 @@ import AccountCircle from '@mui/icons-material/AccountCircle'; import Visibility from '@mui/icons-material/Visibility'; import VisibilityOff from '@mui/icons-material/VisibilityOff'; import { AppProvider } from '@toolpad/core/AppProvider'; -import { SignInPage } from '@toolpad/core/SignInPage'; +import { SignInPage, RememberMeCheckbox } from '@toolpad/core/SignInPage'; import { useTheme } from '@mui/material/styles'; const providers = [{ id: 'credentials', name: 'Email and Password' }]; @@ -125,34 +123,12 @@ function Title() { function Subtitle() { return ( - + We are investigating an ongoing outage. ); } -function AgreeWithTerms() { - return ( - - } - slotProps={{ - typography: { - fontSize: 14, - }, - }} - color="textSecondary" - label="I agree with the T&C" - /> - ); -} - export default function SlotsSignIn() { const theme = useTheme(); return ( @@ -160,7 +136,7 @@ export default function SlotsSignIn() { alert( - `Logging in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}, and checkbox value: ${formData.get('tandc')}`, + `Logging in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}, and checkbox value: ${formData.get('remember')}`, ) } slots={{ @@ -170,9 +146,10 @@ export default function SlotsSignIn() { passwordField: CustomPasswordField, submitButton: CustomButton, signUpLink: SignUpLink, - rememberMe: AgreeWithTerms, + rememberMe: RememberMeCheckbox, forgotPasswordLink: ForgotPasswordLink, }} + slotProps={{ form: { noValidate: true } }} providers={providers} /> diff --git a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx index 7925f2c030b..8b083c36f0e 100644 --- a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx @@ -2,8 +2,6 @@ import * as React from 'react'; import { Button, FormControl, - FormControlLabel, - Checkbox, InputLabel, OutlinedInput, TextField, @@ -16,7 +14,7 @@ import AccountCircle from '@mui/icons-material/AccountCircle'; import Visibility from '@mui/icons-material/Visibility'; import VisibilityOff from '@mui/icons-material/VisibilityOff'; import { AppProvider } from '@toolpad/core/AppProvider'; -import { SignInPage } from '@toolpad/core/SignInPage'; +import { SignInPage, RememberMeCheckbox } from '@toolpad/core/SignInPage'; import { useTheme } from '@mui/material/styles'; const providers = [{ id: 'credentials', name: 'Email and Password' }]; @@ -125,34 +123,12 @@ function Title() { function Subtitle() { return ( - + We are investigating an ongoing outage. ); } -function AgreeWithTerms() { - return ( - - } - slotProps={{ - typography: { - fontSize: 14, - }, - }} - color="textSecondary" - label="I agree with the T&C" - /> - ); -} - export default function SlotsSignIn() { const theme = useTheme(); return ( @@ -160,7 +136,7 @@ export default function SlotsSignIn() { alert( - `Logging in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}, and checkbox value: ${formData.get('tandc')}`, + `Logging in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}, and checkbox value: ${formData.get('remember')}`, ) } slots={{ @@ -170,9 +146,10 @@ export default function SlotsSignIn() { passwordField: CustomPasswordField, submitButton: CustomButton, signUpLink: SignUpLink, - rememberMe: AgreeWithTerms, + rememberMe: RememberMeCheckbox, forgotPasswordLink: ForgotPasswordLink, }} + slotProps={{ form: { noValidate: true } }} providers={providers} /> diff --git a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js index 38d573b4453..14d3091fd3a 100644 --- a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js +++ b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js @@ -44,6 +44,7 @@ export default function ThemeSignInPage() { .MuiStack-root': { marginTop: '2rem', diff --git a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx index d9ce9dc1702..675906f8dae 100644 --- a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx @@ -50,6 +50,7 @@ export default function ThemeSignInPage() { .MuiStack-root': { marginTop: '2rem', diff --git a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview index 511c40e2811..493c55d7468 100644 --- a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview +++ b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview @@ -15,6 +15,7 @@ const THEME = createTheme({ .MuiStack-root': { marginTop: '2rem', diff --git a/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md b/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md index 9abf4d7bef6..69d9f437a42 100644 --- a/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md +++ b/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md @@ -1,7 +1,7 @@ --- productId: toolpad-core title: Sign-in Page -components: SignInPage, Account, NotificationsProvider +components: SignInPage, Account, RememberMeCheckbox, NotificationsProvider --- # Sign-in Page @@ -260,7 +260,7 @@ To enable deep customization beyond what is possible with custom props, the `Sig {{"demo": "SlotsSignIn.js", "iframe": true, "height": 540 }} -You can use the `slotProps` prop to pass props to the underlying components of each slot: +You can use the `slotProps` prop to pass props to the underlying components of each slot, and also to the `form` element: {{"demo": "SlotPropsSignIn.js", "iframe": true, "height": 600 }} diff --git a/docs/data/toolpad/core/pagesApi.js b/docs/data/toolpad/core/pagesApi.js index c36b8e189db..90e52eabf82 100644 --- a/docs/data/toolpad/core/pagesApi.js +++ b/docs/data/toolpad/core/pagesApi.js @@ -10,6 +10,7 @@ module.exports = [ { pathname: '/toolpad/core/api/page-container' }, { pathname: '/toolpad/core/api/page-header' }, { pathname: '/toolpad/core/api/page-header-toolbar' }, + { pathname: '/toolpad/core/api/remember-me-checkbox' }, { pathname: '/toolpad/core/api/sign-in-button' }, { pathname: '/toolpad/core/api/sign-in-page' }, { pathname: '/toolpad/core/api/sign-out-button' }, diff --git a/docs/pages/toolpad/core/api/remember-me-checkbox.js b/docs/pages/toolpad/core/api/remember-me-checkbox.js new file mode 100644 index 00000000000..cdb270120c4 --- /dev/null +++ b/docs/pages/toolpad/core/api/remember-me-checkbox.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './remember-me-checkbox.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docs-toolpad/translations/api-docs/remember-me-checkbox', + false, + /\.\/remember-me-checkbox.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/toolpad/core/api/remember-me-checkbox.json b/docs/pages/toolpad/core/api/remember-me-checkbox.json new file mode 100644 index 00000000000..04b78ce1ec7 --- /dev/null +++ b/docs/pages/toolpad/core/api/remember-me-checkbox.json @@ -0,0 +1,72 @@ +{ + "props": { + "control": { "type": { "name": "element" }, "required": true }, + "slotProps": { + "type": { "name": "shape", "description": "{ typography?: func
| object }" }, + "default": "{}" + } + }, + "name": "RememberMeCheckbox", + "imports": ["import { RememberMeCheckbox } from '@toolpad/core/SignInPage';"], + "classes": [ + { + "key": "asterisk", + "className": "", + "description": "Styles applied to the asterisk element.", + "isGlobal": false + }, + { + "key": "disabled", + "className": "", + "description": "State class applied to the root element if `disabled={true}`.", + "isGlobal": false + }, + { + "key": "error", + "className": "", + "description": "State class applied to the root element if `error={true}`.", + "isGlobal": false + }, + { + "key": "label", + "className": "", + "description": "Styles applied to the label's Typography component.", + "isGlobal": false + }, + { + "key": "labelPlacementBottom", + "className": "", + "description": "Styles applied to the root element if `labelPlacement=\"bottom\"`.", + "isGlobal": false + }, + { + "key": "labelPlacementStart", + "className": "", + "description": "Styles applied to the root element if `labelPlacement=\"start\"`.", + "isGlobal": false + }, + { + "key": "labelPlacementTop", + "className": "", + "description": "Styles applied to the root element if `labelPlacement=\"top\"`.", + "isGlobal": false + }, + { + "key": "required", + "className": "", + "description": "State class applied to the root element if `required={true}`.", + "isGlobal": false + }, + { + "key": "root", + "className": "", + "description": "Styles applied to the root element.", + "isGlobal": false + } + ], + "muiName": "RememberMeCheckbox", + "filename": "/packages/toolpad-core/src/SignInPage/RememberMeCheckbox.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/toolpad/core/api/sign-in-page.json b/docs/pages/toolpad/core/api/sign-in-page.json index 132fb1607bc..0a131fa2fcd 100644 --- a/docs/pages/toolpad/core/api/sign-in-page.json +++ b/docs/pages/toolpad/core/api/sign-in-page.json @@ -15,7 +15,7 @@ "slotProps": { "type": { "name": "shape", - "description": "{ emailField?: object, forgotPasswordLink?: object, passwordField?: object, rememberMe?: object, signUpLink?: object, submitButton?: object }" + "description": "{ emailField?: object, forgotPasswordLink?: object, form?: object, oauthButton?: object, passwordField?: object, rememberMe?: object, signUpLink?: object, submitButton?: object }" }, "default": "{}" }, @@ -85,7 +85,7 @@ }, { "name": "rememberMe", - "description": "A component to override the default \"Remember me\" checkbox in the Credentials form", + "description": "A custom checkbox placed in the credentials form", "default": "FormControlLabel", "class": null } diff --git a/docs/translations/api-docs/remember-me-checkbox/remember-me-checkbox.json b/docs/translations/api-docs/remember-me-checkbox/remember-me-checkbox.json new file mode 100644 index 00000000000..d789570c685 --- /dev/null +++ b/docs/translations/api-docs/remember-me-checkbox/remember-me-checkbox.json @@ -0,0 +1,50 @@ +{ + "componentDescription": "", + "propDescriptions": { + "control": { + "description": "A control element. For instance, it can be a Radio, a Switch or a Checkbox." + }, + "slotProps": { "description": "The props used for each slot inside." } + }, + "classDescriptions": { + "asterisk": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the asterisk element" + }, + "disabled": { + "description": "State class applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "disabled={true}" + }, + "error": { + "description": "State class applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "error={true}" + }, + "label": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the label's Typography component" + }, + "labelPlacementBottom": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "labelPlacement=\"bottom\"" + }, + "labelPlacementStart": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "labelPlacement=\"start\"" + }, + "labelPlacementTop": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "labelPlacement=\"top\"" + }, + "required": { + "description": "State class applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "required={true}" + }, + "root": { "description": "Styles applied to the root element." } + } +} diff --git a/docs/translations/api-docs/sign-in-page/sign-in-page.json b/docs/translations/api-docs/sign-in-page/sign-in-page.json index de36472fb55..31c9dbd4593 100644 --- a/docs/translations/api-docs/sign-in-page/sign-in-page.json +++ b/docs/translations/api-docs/sign-in-page/sign-in-page.json @@ -21,7 +21,7 @@ "emailField": "The custom email field component used in the credentials form.", "forgotPasswordLink": "The custom forgot password link component used in the credentials form.", "passwordField": "The custom password field component used in the credentials form.", - "rememberMe": "A component to override the default "Remember me" checkbox in the Credentials form", + "rememberMe": "A custom checkbox placed in the credentials form", "signUpLink": "The custom sign up link component used in the credentials form.", "submitButton": "The custom submit button component used in the credentials form.", "subtitle": "A component to override the default subtitle section", diff --git a/packages/toolpad-core/src/SignInPage/RememberMeCheckbox.tsx b/packages/toolpad-core/src/SignInPage/RememberMeCheckbox.tsx new file mode 100644 index 00000000000..bbbaf090644 --- /dev/null +++ b/packages/toolpad-core/src/SignInPage/RememberMeCheckbox.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { Checkbox, FormControlLabel, FormControlLabelProps } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; + +/** + * + * Demos: + * + * - [Sign-in Page](https://mui.com/toolpad/core/react-sign-in-page/) + * + * API: + * + * - [RememberMeCheckbox API](https://mui.com/toolpad/core/api/remember-me-checkbox) + */ +function RememberMeCheckbox(props: Partial) { + const theme = useTheme(); + return ( + + ) + } + slotProps={{ + ...props.slotProps, + typography: { + color: 'textSecondary', + fontSize: theme.typography.pxToRem(14), + ...props?.slotProps?.typography, + }, + }} + /> + ); +} + +RememberMeCheckbox.propTypes /* remove-proptypes */ = { + // ┌────────────────────────────── Warning ──────────────────────────────┐ + // │ These PropTypes are generated from the TypeScript type definitions. │ + // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │ + // └─────────────────────────────────────────────────────────────────────┘ + /** + * A control element. For instance, it can be a `Radio`, a `Switch` or a `Checkbox`. + */ + control: PropTypes.element.isRequired, + /** + * The props used for each slot inside. + * @default {} + */ + slotProps: PropTypes.shape({ + typography: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), +} as any; + +export { RememberMeCheckbox }; diff --git a/packages/toolpad-core/src/SignInPage/SignInPage.tsx b/packages/toolpad-core/src/SignInPage/SignInPage.tsx index 5a5c489d992..3170e1659ec 100644 --- a/packages/toolpad-core/src/SignInPage/SignInPage.tsx +++ b/packages/toolpad-core/src/SignInPage/SignInPage.tsx @@ -5,10 +5,9 @@ import PropTypes from 'prop-types'; import Alert from '@mui/material/Alert'; import Box from '@mui/material/Box'; 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 FormControlLabel, { FormControlLabelProps } from '@mui/material/FormControlLabel'; +import { FormControlLabelProps } from '@mui/material/FormControlLabel'; import TextField, { TextFieldProps } from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; import LoadingButton, { LoadingButtonProps } from '@mui/lab/LoadingButton'; @@ -209,7 +208,7 @@ export interface SignInPageSlots { */ subtitle?: React.ElementType; /** - * A component to override the default "Remember me" checkbox in the Credentials form + * A custom checkbox placed in the credentials form * @default FormControlLabel */ rememberMe?: React.ElementType; @@ -252,9 +251,11 @@ export interface SignInPageProps { emailField?: TextFieldProps; passwordField?: TextFieldProps; submitButton?: LoadingButtonProps; + oauthButton?: LoadingButtonProps; forgotPasswordLink?: LinkProps; signUpLink?: LinkProps; rememberMe?: Partial; + form?: Partial>; }; /** * The prop used to customize the styles on the `SignInPage` container @@ -312,7 +313,7 @@ function SignInPage(props: SignInPageProps) { }} > - )} - + {error && isOauthProvider(selectedProviderId) ? ( {error} @@ -374,6 +375,7 @@ function SignInPage(props: SignInPageProps) { error: oauthResponse?.error, })); }} + {...slotProps?.form} > Sign in with {provider.name} @@ -402,7 +405,7 @@ function SignInPage(props: SignInPageProps) { {singleProvider ? null : or} {error && selectedProviderId === 'passkey' ? ( - + {error} ) : null} @@ -423,6 +426,7 @@ function SignInPage(props: SignInPageProps) { error: passkeyResponse?.error, })); }} + {...slotProps?.form} > {slots?.emailField ? ( @@ -436,6 +440,7 @@ function SignInPage(props: SignInPageProps) { type: 'email', autoComplete: 'email-webauthn', autoFocus: singleProvider, + sx: { mt: 1 }, ...slotProps?.emailField, })} /> @@ -470,12 +475,12 @@ function SignInPage(props: SignInPageProps) { {singleProvider ? null : or} {error && selectedProviderId === 'nodemailer' ? ( - + {error} ) : null} {success && selectedProviderId === 'nodemailer' ? ( - + {success} ) : null} @@ -497,6 +502,7 @@ function SignInPage(props: SignInPageProps) { success: emailResponse?.success, })); }} + {...slotProps?.form} > {slots?.emailField ? ( @@ -508,6 +514,7 @@ function SignInPage(props: SignInPageProps) { name: 'email', id: 'email-nodemailer', type: 'email', + sx: { mt: 1 }, autoComplete: 'email-nodemailer', autoFocus: singleProvider, ...slotProps?.emailField, @@ -544,7 +551,7 @@ function SignInPage(props: SignInPageProps) { {singleProvider ? null : or} {error && selectedProviderId === 'credentials' ? ( - + {error} ) : null} @@ -569,8 +576,9 @@ function SignInPage(props: SignInPageProps) { error: credentialsResponse?.error, })); }} + {...slotProps?.form} > - + {slots?.emailField ? ( ) : ( @@ -603,42 +611,23 @@ function SignInPage(props: SignInPageProps) { /> )} - - {slots?.rememberMe ? ( - - ) : ( - - } - label="Remember me" - {...slotProps?.rememberMe} - slotProps={{ - typography: { - color: 'textSecondary', - fontSize: theme.typography.pxToRem(14), - }, - ...slotProps?.rememberMe?.slotProps, - }} - /> - )} - {slots?.forgotPasswordLink ? ( - - ) : null} - + {slots?.forgotPasswordLink || slots?.rememberMe ? ( + + {slots?.rememberMe ? : null} + {slots?.forgotPasswordLink ? ( + + ) : null} + + ) : null} {slots?.submitButton ? ( ) : ( @@ -670,7 +659,7 @@ function SignInPage(props: SignInPageProps) { ) : null} - + ); @@ -710,6 +699,8 @@ SignInPage.propTypes /* remove-proptypes */ = { slotProps: PropTypes.shape({ emailField: PropTypes.object, forgotPasswordLink: PropTypes.object, + form: PropTypes.object, + oauthButton: PropTypes.object, passwordField: PropTypes.object, rememberMe: PropTypes.object, signUpLink: PropTypes.object, diff --git a/packages/toolpad-core/src/SignInPage/index.ts b/packages/toolpad-core/src/SignInPage/index.ts index aa485859b44..c4976180061 100644 --- a/packages/toolpad-core/src/SignInPage/index.ts +++ b/packages/toolpad-core/src/SignInPage/index.ts @@ -1 +1,2 @@ export * from './SignInPage'; +export * from './RememberMeCheckbox'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8914f6a1033..ecd717ee3b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -201,7 +201,7 @@ importers: version: 7.37.3(eslint@8.57.1) eslint-plugin-react-compiler: specifier: latest - version: 19.0.0-beta-decd7b8-20250118(eslint@8.57.1) + version: 19.0.0-beta-27714ef-20250124(eslint@8.57.1) eslint-plugin-react-hooks: specifier: 5.1.0 version: 5.1.0(eslint@8.57.1) @@ -6090,8 +6090,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-react-compiler@19.0.0-beta-decd7b8-20250118: - resolution: {integrity: sha512-qfs+Xo+VcYPbbVLI2tCP+KBGwm0oksAhjFJO1GwOvP+4b18LLcPZu7xopRhUTOaNd+nn1vOp9EQLZC1wMNxSrQ==} + eslint-plugin-react-compiler@19.0.0-beta-27714ef-20250124: + resolution: {integrity: sha512-8/NaV8E+eQ+BiKGeWg5wIizuKwEXLo+n/lgiyTLmJnZj8eoFW3G7NGJf3Nke4ji3Rndy34LK5Qi5TF6BPiZlSQ==} engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0} peerDependencies: eslint: '>=7' @@ -7542,6 +7542,7 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. lodash.groupby@4.6.0: resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} @@ -7554,6 +7555,7 @@ packages: lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. lodash.isfunction@3.0.9: resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} @@ -7599,6 +7601,7 @@ packages: lodash.omit@4.5.0: resolution: {integrity: sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==} + deprecated: This package is deprecated. Use destructuring assignment syntax instead. lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} @@ -16276,7 +16279,7 @@ snapshots: globals: 13.24.0 rambda: 7.5.0 - eslint-plugin-react-compiler@19.0.0-beta-decd7b8-20250118(eslint@8.57.1): + eslint-plugin-react-compiler@19.0.0-beta-27714ef-20250124(eslint@8.57.1): dependencies: '@babel/core': 7.26.0 '@babel/parser': 7.26.2