added theme
This commit is contained in:
27
themes/onepirate/modules/form/FormButton.js
Normal file
27
themes/onepirate/modules/form/FormButton.js
Normal 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);
|
24
themes/onepirate/modules/form/FormButton.tsx
Normal file
24
themes/onepirate/modules/form/FormButton.tsx
Normal 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);
|
38
themes/onepirate/modules/form/FormFeedback.js
Normal file
38
themes/onepirate/modules/form/FormFeedback.js
Normal 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;
|
37
themes/onepirate/modules/form/FormFeedback.tsx
Normal file
37
themes/onepirate/modules/form/FormFeedback.tsx
Normal 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;
|
79
themes/onepirate/modules/form/RFTextField.js
Normal file
79
themes/onepirate/modules/form/RFTextField.js
Normal 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;
|
33
themes/onepirate/modules/form/RFTextField.tsx
Normal file
33
themes/onepirate/modules/form/RFTextField.tsx
Normal 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;
|
15
themes/onepirate/modules/form/defer.js
Normal file
15
themes/onepirate/modules/form/defer.js
Normal 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;
|
||||
}
|
15
themes/onepirate/modules/form/defer.tsx
Normal file
15
themes/onepirate/modules/form/defer.tsx
Normal 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;
|
||||
}
|
29
themes/onepirate/modules/form/validation.js
Normal file
29
themes/onepirate/modules/form/validation.js
Normal 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' }),
|
||||
}),
|
||||
{},
|
||||
);
|
||||
}
|
32
themes/onepirate/modules/form/validation.ts
Normal file
32
themes/onepirate/modules/form/validation.ts
Normal 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' }),
|
||||
}),
|
||||
{},
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user