Skip to content

Commit

Permalink
Introduce PasswordInput
Browse files Browse the repository at this point in the history
  • Loading branch information
Kmaschta committed Dec 10, 2019
1 parent 07b5e4c commit 8d5ce2f
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 4 deletions.
26 changes: 26 additions & 0 deletions docs/Inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,32 @@ You can customize the `step` props (which defaults to "any"):

`<NumberInput>` also accepts the [common input props](./Inputs.md#common-input-props).

## `<PasswordInput>`

`<PasswordInput>` works like the [`<TextInput>`](#textinput) but overwrites its `type` prop to `password` or `text` in accordance with a visibility button, hidden by default.

```jsx
import { PasswordInput } from 'react-admin';
<PasswordInput source="password" />
```

![Password Input](./img/password-input.png)

It is possible to change the default behavior and display the value by default via the `initiallyVisible` prop:

```jsx
import { PasswordInput } from 'react-admin';
<PasswordInput source="password" initiallyVisible />
```

![Password Input (visible)](./img/password-input-visible.png)

**Tip**: It is possible to set the [`autocomplete` attribute](https://developer.mozilla.org/fr/docs/Web/HTML/Attributs/autocomplete) by injecting an input props:

```jsx
<PasswordInput source="password" inputProps={{ autocomplete: 'current-password' }} />
```

## `<RadioButtonGroupInput>`

If you want to let the user choose a value among a list of possible values that are always shown (instead of hiding them behind a dropdown list, as in [`<SelectInput>`](#selectinput)), `<RadioButtonGroupInput>` is the right component. Set the `choices` attribute to determine the options (with `id`, `name` tuples):
Expand Down
Binary file added docs/img/password-input-visible.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/password-input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions examples/demo/src/i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,24 @@ export default {
last_seen_gte: 'Visited Since',
name: 'Name',
total_spent: 'Total spent',
password: 'Password',
confirm_password: 'Confirm password',
},
fieldGroups: {
identity: 'Identity',
address: 'Address',
stats: 'Stats',
history: 'History',
password: 'Password',
change_password: 'Change Password',
},
page: {
delete: 'Delete Customer',
},
errors: {
password_mismatch:
'The password confirmation is not the same as the password.',
},
},
commands: {
name: 'Order |||| Orders',
Expand Down
8 changes: 8 additions & 0 deletions examples/demo/src/i18n/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,24 @@ export default {
name: 'Nom',
total_spent: 'Dépenses',
zipcode: 'Code postal',
password: 'Mot de passe',
confirm_password: 'Confirmez le mot de passe',
},
fieldGroups: {
identity: 'Identité',
address: 'Adresse',
stats: 'Statistiques',
history: 'Historique',
password: 'Mot de passe',
change_password: 'Changer le mot de passe',
},
page: {
delete: 'Supprimer le client',
},
errors: {
password_mismatch:
'La confirmation du mot de passe est différent du mot de passe.',
},
},
commands: {
name: 'Commande |||| Commandes',
Expand Down
29 changes: 28 additions & 1 deletion examples/demo/src/visitors/VisitorCreate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
SimpleForm,
TextInput,
useTranslate,
PasswordInput,
required,
} from 'react-admin';
import { Typography, Box } from '@material-ui/core';
Expand All @@ -23,15 +24,30 @@ export const styles = {
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
password: { display: 'inline-block' },
confirm_password: { display: 'inline-block', marginLeft: 32 },
};

const useStyles = makeStyles(styles);

export const validatePasswords = ({ password, confirm_password }) => {
const errors = {};

if (password && confirm_password && password !== confirm_password) {
errors.confirm_password = [
'resources.customers.errors.password_mismatch',
];
}

return errors;
};

const VisitorCreate = props => {
const classes = useStyles();

return (
<Create {...props}>
<SimpleForm>
<SimpleForm validate={validatePasswords}>
<SectionTitle label="resources.customers.fieldGroups.identity" />
<TextInput
autoFocus
Expand Down Expand Up @@ -63,6 +79,16 @@ const VisitorCreate = props => {
/>
<TextInput source="zipcode" formClassName={classes.zipcode} />
<TextInput source="city" formClassName={classes.city} />
<Separator />
<SectionTitle label="resources.customers.fieldGroups.password" />
<PasswordInput
source="password"
formClassName={classes.password}
/>
<PasswordInput
source="confirm_password"
formClassName={classes.confirm_password}
/>
</SimpleForm>
</Create>
);
Expand All @@ -72,6 +98,7 @@ const requiredValidate = [required()];

const SectionTitle = ({ label }) => {
const translate = useTranslate();

return (
<Typography variant="h6" gutterBottom>
{translate(label)}
Expand Down
34 changes: 34 additions & 0 deletions examples/demo/src/visitors/VisitorEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Edit,
NullableBooleanInput,
TextInput,
PasswordInput,
Toolbar,
useTranslate,
FormWithRedirect,
Expand All @@ -13,6 +14,7 @@ import { Box, Card, CardContent, Typography } from '@material-ui/core';
import Aside from './Aside';
import FullNameField from './FullNameField';
import SegmentsInput from './SegmentsInput';
import { validatePasswords } from './VisitorCreate';

const VisitorEdit = props => {
return (
Expand All @@ -32,9 +34,11 @@ const VisitorTitle = ({ record }) =>

const VisitorForm = props => {
const translate = useTranslate();

return (
<FormWithRedirect
{...props}
validate={validatePasswords}
render={formProps => (
<Card>
<form>
Expand Down Expand Up @@ -127,6 +131,36 @@ const VisitorForm = props => {
/>
</Box>
</Box>

<Box mt="1em" />

<Typography variant="h6" gutterBottom>
{translate(
'resources.customers.fieldGroups.change_password'
)}
</Typography>
<Box display={{ xs: 'block', sm: 'flex' }}>
<Box
flex={1}
mr={{ xs: 0, sm: '0.5em' }}
>
<PasswordInput
source="password"
resource="customers"
fullWidth
/>
</Box>
<Box
flex={1}
ml={{ xs: 0, sm: '0.5em' }}
>
<PasswordInput
source="confirm_password"
resource="customers"
fullWidth
/>
</Box>
</Box>
</Box>
<Box
flex={1}
Expand Down
4 changes: 4 additions & 0 deletions packages/ra-language-english/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ module.exports = {
single_missing:
'Associated reference no longer appears to be available.',
},
password: {
toggle_visible: 'Hide password',
toggle_hidden: 'Show password',
},
},
message: {
about: 'About',
Expand Down
4 changes: 4 additions & 0 deletions packages/ra-language-french/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ module.exports = {
single_missing:
'La référence associée ne semble plus disponible.',
},
password: {
toggle_visible: 'Cacher le mot de passe',
toggle_hidden: 'Montrer le mot de passe',
},
},
message: {
about: 'Au sujet de',
Expand Down
48 changes: 48 additions & 0 deletions packages/ra-ui-materialui/src/input/PasswordInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { FC, useState } from 'react';
import { useTranslate } from 'ra-core';
import { InputAdornment, IconButton } from '@material-ui/core';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';

import TextInput, { TextInputProps } from './TextInput';

export interface PasswordInputProps extends TextInputProps {
initiallyVisible?: boolean;
}

const PasswordInput: FC<PasswordInputProps> = ({
initiallyVisible = false,
...props
}) => {
const [visible, setVisible] = useState(initiallyVisible);
const translate = useTranslate();

const handleClick = () => {
setVisible(!visible);
};

return (
<TextInput
{...props}
type={visible ? 'text' : 'password'}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label={translate(
visible
? 'ra.input.password.toggle_visible'
: 'ra.input.password.toggle_hidden'
)}
onClick={handleClick}
>
{visible ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
),
}}
/>
);
};

export default PasswordInput;
7 changes: 4 additions & 3 deletions packages/ra-ui-materialui/src/input/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import ResettableTextField from './ResettableTextField';
import InputHelperText from './InputHelperText';
import sanitizeRestProps from './sanitizeRestProps';

export type TextInputProps = InputProps<TextFieldProps> &
Omit<TextFieldProps, 'label' | 'helperText'>;

/**
* An Input component for a string
*
Expand All @@ -21,9 +24,7 @@ import sanitizeRestProps from './sanitizeRestProps';
*
* The object passed as `options` props is passed to the <ResettableTextField> component
*/
export const TextInput: FunctionComponent<
InputProps<TextFieldProps> & Omit<TextFieldProps, 'label' | 'helperText'>
> = ({
export const TextInput: FunctionComponent<TextInputProps> = ({
label,
format,
helperText,
Expand Down
2 changes: 2 additions & 0 deletions packages/ra-ui-materialui/src/input/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import InputPropTypes from './InputPropTypes';
import Labeled from './Labeled';
import NullableBooleanInput from './NullableBooleanInput';
import NumberInput from './NumberInput';
import PasswordInput from './PasswordInput';
import RadioButtonGroupInput from './RadioButtonGroupInput';
import ReferenceArrayInput from './ReferenceArrayInput';
import ReferenceInput from './ReferenceInput';
Expand All @@ -36,6 +37,7 @@ export {
Labeled,
NullableBooleanInput,
NumberInput,
PasswordInput,
RadioButtonGroupInput,
ReferenceArrayInput,
ReferenceInput,
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4981,6 +4981,14 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"

data-generator-retail@^2.7.0:
version "2.9.5"
resolved "https://registry.yarnpkg.com/data-generator-retail/-/data-generator-retail-2.9.5.tgz#9a1a541f7bc19c00b633b0d17e6b39837e398976"
integrity sha512-scx3c91hhTMxFIvNgAO2Y2Xor4eIR8FfZ7LBCHVlsUt7DEIUvH6juHIVjT6ytzQjwBuR03UzEOlZpIMim1+KqQ==
dependencies:
date-fns "~1.29.0"
faker "^4.1.0"

data-urls@^1.0.0, data-urls@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe"
Expand Down

0 comments on commit 8d5ce2f

Please sign in to comment.