added theme

This commit is contained in:
Arnaud Fauconnet
2022-10-28 11:41:58 +02:00
parent 99b63d95fd
commit 328a760eb8
67 changed files with 4358 additions and 6 deletions

View File

@ -0,0 +1,27 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import Button from '../components/Button';
import defer from './defer';
function FormButton(props) {
const { disabled, mounted, ...others } = props;
return (
<Button
disabled={!mounted || !!disabled}
type="submit"
variant="contained"
{...others}
/>
);
}
FormButton.propTypes = {
/**
* If `true`, the component is disabled.
*/
disabled: PropTypes.bool,
mounted: PropTypes.bool,
};
export default defer(FormButton);

View File

@ -0,0 +1,24 @@
import * as React from 'react';
import { ButtonProps } from '@mui/material';
import Button from '../components/Button';
import defer from './defer';
interface FormButtonProps {
disabled?: boolean;
mounted?: boolean;
}
function FormButton<C extends React.ElementType>(
props: FormButtonProps & ButtonProps<C, { component?: C }>,
) {
const { disabled, mounted, ...others } = props;
return (
<Button
disabled={!mounted || !!disabled}
type="submit"
variant="contained"
{...others}
/>
);
}
export default defer(FormButton);

View File

@ -0,0 +1,38 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { experimentalStyled as styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Typography from '../components/Typography';
const BoxStyled = styled(Box, {
shouldForwardProp: (prop) => prop !== 'error' && prop !== 'success',
})(({ theme, error, success }) => ({
padding: theme.spacing(2),
...(error && {
backgroundColor: theme.palette.error.light,
color: theme.palette.error.dark,
}),
...(success && {
backgroundColor: theme.palette.success.light,
color: theme.palette.success.dark,
}),
}));
function FormFeedback(props) {
const { className, children, error, success, ...others } = props;
return (
<BoxStyled error={error} success={success} className={className} {...others}>
<Typography color="inherit">{children}</Typography>
</BoxStyled>
);
}
FormFeedback.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
error: PropTypes.bool,
success: PropTypes.bool,
};
export default FormFeedback;

View File

@ -0,0 +1,37 @@
import * as React from 'react';
import { experimentalStyled as styled } from '@mui/material/styles';
import Box, { BoxProps as MuiBoxProps } from '@mui/material/Box';
import Typography from '../components/Typography';
interface FormFeedbackProps extends MuiBoxProps {
error?: boolean;
success?: boolean;
}
const BoxStyled = styled(Box, {
shouldForwardProp: (prop) => prop !== 'error' && prop !== 'success',
})<FormFeedbackProps>(({ theme, error, success }) => ({
padding: theme.spacing(2),
...(error && {
backgroundColor: theme.palette.error.light,
color: theme.palette.error.dark,
}),
...(success && {
backgroundColor: theme.palette.success.light,
color: theme.palette.success.dark,
}),
}));
function FormFeedback(
props: React.HTMLAttributes<HTMLDivElement> & FormFeedbackProps,
) {
const { className, children, error, success, ...others } = props;
return (
<BoxStyled error={error} success={success} className={className} {...others}>
<Typography color="inherit">{children}</Typography>
</BoxStyled>
);
}
export default FormFeedback;

View File

@ -0,0 +1,79 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import TextField from '../components/TextField';
function RFTextField(props) {
const {
autoComplete,
input,
InputProps,
meta: { touched, error, submitError },
...other
} = props;
return (
<TextField
error={Boolean(!!touched && (error || submitError))}
{...input}
{...other}
InputProps={{
inputProps: {
autoComplete,
},
...InputProps,
}}
helperText={touched ? error || submitError : ''}
variant="standard"
/>
);
}
RFTextField.propTypes = {
/**
* This prop helps users to fill forms faster, especially on mobile devices.
* The name can be confusing, as it's more like an autofill.
* You can learn more about it [following the specification](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill).
*/
autoComplete: PropTypes.string,
input: PropTypes.shape({
checked: PropTypes.bool,
multiple: PropTypes.bool,
name: PropTypes.string.isRequired,
onBlur: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func.isRequired,
type: PropTypes.string,
value: PropTypes.string.isRequired,
}).isRequired,
/**
* Props applied to the Input element.
* It will be a [`FilledInput`](/material-ui/api/filled-input/),
* [`OutlinedInput`](/material-ui/api/outlined-input/) or [`Input`](/material-ui/api/input/)
* component depending on the `variant` prop value.
*/
InputProps: PropTypes.object,
meta: PropTypes.shape({
active: PropTypes.bool,
data: PropTypes.object,
dirty: PropTypes.bool,
dirtySinceLastSubmit: PropTypes.bool,
error: PropTypes.any,
initial: PropTypes.string,
invalid: PropTypes.bool,
length: PropTypes.number,
modified: PropTypes.bool,
modifiedSinceLastSubmit: PropTypes.bool,
pristine: PropTypes.bool,
submitError: PropTypes.any,
submitFailed: PropTypes.bool,
submitSucceeded: PropTypes.bool,
submitting: PropTypes.bool,
touched: PropTypes.bool,
valid: PropTypes.bool,
validating: PropTypes.bool,
visited: PropTypes.bool,
}).isRequired,
};
export default RFTextField;

View File

@ -0,0 +1,33 @@
import * as React from 'react';
import { FieldRenderProps } from 'react-final-form';
import TextField, { OnePirateTextFieldProps } from '../components/TextField';
function RFTextField(
props: OnePirateTextFieldProps & FieldRenderProps<string, HTMLElement>,
) {
const {
autoComplete,
input,
InputProps,
meta: { touched, error, submitError },
...other
} = props;
return (
<TextField
error={Boolean(!!touched && (error || submitError))}
{...input}
{...other}
InputProps={{
inputProps: {
autoComplete,
},
...InputProps,
}}
helperText={touched ? error || submitError : ''}
variant="standard"
/>
);
}
export default RFTextField;

View File

@ -0,0 +1,15 @@
import * as React from 'react';
export default function defer(Component) {
function Defer(props) {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
return <Component mounted={mounted} {...props} />;
}
return Defer;
}

View File

@ -0,0 +1,15 @@
import * as React from 'react';
export default function defer<P>(Component: React.ComponentType<P>) {
function Defer(props: P) {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
return <Component mounted={mounted} {...props} />;
}
return Defer;
}

View File

@ -0,0 +1,29 @@
/**
* This is a simplified logic.
* Consider using `import isEmail from 'validator/lib/isEmail'` from
* https://github.com/validatorjs/validator.js/blob/7376945b4ce028b65955ae57b8fccbbf3fe58467/src/lib/isEmail.js
* for a more robust version.
*/
function isEmail(string) {
const re =
/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
return re.test(string);
}
export function email(value) {
return value && !isEmail(value.trim()) ? 'Invalid email' : null;
}
function isDirty(value) {
return value || value === 0;
}
export function required(requiredFields, values) {
return requiredFields.reduce(
(fields, field) => ({
...fields,
...(isDirty(values[field]) ? undefined : { [field]: 'Required' }),
}),
{},
);
}

View File

@ -0,0 +1,32 @@
/**
* This is a simplified logic.
* Consider using `import isEmail from 'validator/lib/isEmail'` from
* https://github.com/validatorjs/validator.js/blob/7376945b4ce028b65955ae57b8fccbbf3fe58467/src/lib/isEmail.js
* for a more robust version.
*/
function isEmail(string: string) {
const re =
/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
return re.test(string);
}
export function email(value: string) {
return value && !isEmail(value.trim()) ? 'Invalid email' : null;
}
function isDirty(value: string | number) {
return value || value === 0;
}
export function required(
requiredFields: readonly string[],
values: Record<string, string>,
): Record<string, string> {
return requiredFields.reduce(
(fields, field) => ({
...fields,
...(isDirty(values[field]) ? undefined : { [field]: 'Required' }),
}),
{},
);
}