mirror of
https://github.com/strapi/strapi.git
synced 2025-12-05 03:21:22 +00:00
chore: feedback fixes
This commit is contained in:
parent
3690ce3bc3
commit
402617b5f0
@ -23,7 +23,7 @@ import {
|
||||
const InputUID = ({
|
||||
attribute,
|
||||
contentTypeUID,
|
||||
fieldHint,
|
||||
hint,
|
||||
disabled,
|
||||
error,
|
||||
intlLabel,
|
||||
@ -226,7 +226,7 @@ const InputUID = ({
|
||||
</FieldActionWrapper>
|
||||
</EndActionWrapper>
|
||||
}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
name={name}
|
||||
@ -261,7 +261,7 @@ InputUID.propTypes = {
|
||||
values: PropTypes.object,
|
||||
}),
|
||||
required: PropTypes.bool,
|
||||
fieldHint: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
||||
hint: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
||||
};
|
||||
|
||||
InputUID.defaultProps = {
|
||||
@ -271,7 +271,7 @@ InputUID.defaultProps = {
|
||||
placeholder: undefined,
|
||||
value: '',
|
||||
required: false,
|
||||
fieldHint: '',
|
||||
hint: '',
|
||||
};
|
||||
|
||||
export default InputUID;
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
connect,
|
||||
generateOptions,
|
||||
getInputType,
|
||||
getMinMax,
|
||||
getStep,
|
||||
select,
|
||||
VALIDATIONS_TO_OMIT,
|
||||
@ -258,22 +259,7 @@ function Inputs({
|
||||
...customFieldInputs,
|
||||
};
|
||||
|
||||
const { minLength, maxLength, max, min } = fieldSchema;
|
||||
|
||||
let genericMinimum;
|
||||
let genericMaximum;
|
||||
|
||||
if (typeof min === 'number') {
|
||||
genericMinimum = min;
|
||||
} else if (typeof minLength === 'number') {
|
||||
genericMinimum = minLength;
|
||||
}
|
||||
|
||||
if (typeof max === 'number') {
|
||||
genericMaximum = max;
|
||||
} else if (typeof maxLength === 'number') {
|
||||
genericMaximum = maxLength;
|
||||
}
|
||||
const { inputMaximum, inputMinimum } = getMinMax(fieldSchema);
|
||||
|
||||
return (
|
||||
<GenericInput
|
||||
@ -283,8 +269,8 @@ function Inputs({
|
||||
// in case the default value of the boolean is null, attribute.default doesn't exist
|
||||
isNullable={inputType === 'bool' && [null, undefined].includes(fieldSchema.default)}
|
||||
description={description ? { id: description, defaultMessage: description } : null}
|
||||
minimum={genericMinimum}
|
||||
maximum={genericMaximum}
|
||||
minimum={inputMinimum}
|
||||
maximum={inputMaximum}
|
||||
disabled={shouldDisableField}
|
||||
error={error}
|
||||
labelAction={labelAction}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Get the minimum and maximum limits for an input
|
||||
* @param {Object} fieldSchema
|
||||
* @returns {Object}
|
||||
*/
|
||||
const getMinMax = (fieldSchema) => {
|
||||
const { minLength, maxLength, max, min } = fieldSchema;
|
||||
|
||||
let inputMinimum;
|
||||
let inputMaximum;
|
||||
|
||||
if (typeof min === 'number') {
|
||||
inputMinimum = min;
|
||||
} else if (typeof minLength === 'number') {
|
||||
inputMinimum = minLength;
|
||||
}
|
||||
|
||||
if (typeof max === 'number') {
|
||||
inputMaximum = max;
|
||||
} else if (typeof maxLength === 'number') {
|
||||
inputMaximum = maxLength;
|
||||
}
|
||||
|
||||
return { inputMaximum, inputMinimum };
|
||||
};
|
||||
|
||||
export default getMinMax;
|
||||
@ -3,4 +3,5 @@ export { default as generateOptions } from './generateOptions';
|
||||
export { default as getInputType } from './getInputType';
|
||||
export { default as getStep } from './getStep';
|
||||
export { default as select } from './select';
|
||||
export { default as getMinMax } from './getMinMax';
|
||||
export { default as VALIDATIONS_TO_OMIT } from './VALIDATIONS_TO_OMIT';
|
||||
|
||||
@ -28,6 +28,7 @@ import Eye from '@strapi/icons/Eye';
|
||||
|
||||
import NotSupported from './NotSupported';
|
||||
import useFieldHint from '../../hooks/useFieldHint';
|
||||
import { getFieldUnits } from './utils';
|
||||
|
||||
const GenericInput = ({
|
||||
autoComplete,
|
||||
@ -51,11 +52,11 @@ const GenericInput = ({
|
||||
...rest
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { fieldHint } = useFieldHint({
|
||||
isNumber: type === 'number',
|
||||
const { hint } = useFieldHint({
|
||||
description,
|
||||
minimum,
|
||||
maximum,
|
||||
units: getFieldUnits(type, minimum, maximum),
|
||||
});
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
@ -103,7 +104,7 @@ const GenericInput = ({
|
||||
<CustomInput
|
||||
{...rest}
|
||||
description={description}
|
||||
fieldHint={fieldHint}
|
||||
hint={hint}
|
||||
disabled={disabled}
|
||||
intlLabel={intlLabel}
|
||||
labelAction={labelAction}
|
||||
@ -154,7 +155,7 @@ const GenericInput = ({
|
||||
<ToggleInput
|
||||
checked={defaultValue === null ? null : defaultValue || false}
|
||||
disabled={disabled}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
label={label}
|
||||
error={errorMessage}
|
||||
labelAction={labelAction}
|
||||
@ -180,7 +181,7 @@ const GenericInput = ({
|
||||
<Checkbox
|
||||
disabled={disabled}
|
||||
error={errorMessage}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
id={name}
|
||||
name={name}
|
||||
onValueChange={(value) => {
|
||||
@ -202,7 +203,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={(date) => {
|
||||
const formattedDate = date.toISOString();
|
||||
@ -237,7 +238,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={(date) => {
|
||||
onChange({
|
||||
@ -260,7 +261,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onValueChange={(value) => onChange({ target: { name, value, type } })}
|
||||
placeholder={formattedPlaceholder}
|
||||
@ -279,7 +280,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
placeholder={formattedPlaceholder}
|
||||
@ -300,7 +301,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
placeholder={formattedPlaceholder}
|
||||
@ -342,7 +343,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
placeholder={formattedPlaceholder}
|
||||
@ -360,7 +361,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={(value) => onChange({ target: { name, value, type: 'select' } })}
|
||||
placeholder={formattedPlaceholder}
|
||||
@ -385,7 +386,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
required={required}
|
||||
@ -416,7 +417,7 @@ const GenericInput = ({
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
id={name}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
name={name}
|
||||
onChange={(time) => {
|
||||
onChange({ target: { name, value: `${time}`, type } });
|
||||
@ -437,7 +438,7 @@ const GenericInput = ({
|
||||
name={name}
|
||||
label={label}
|
||||
labelAction={labelAction}
|
||||
hint={fieldHint}
|
||||
hint={hint}
|
||||
error={errorMessage}
|
||||
required={required}
|
||||
/>
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @param {String} type
|
||||
* @param {Number} minimum
|
||||
* @param {Number} maximum
|
||||
* @returns
|
||||
*/
|
||||
const getFieldUnits = (type, minimum, maximum) => {
|
||||
if (type === 'number') {
|
||||
return '';
|
||||
}
|
||||
const plural = Math.max(minimum || 0, maximum || 0) > 1;
|
||||
|
||||
if (plural) {
|
||||
return 'characters';
|
||||
}
|
||||
|
||||
return 'character';
|
||||
};
|
||||
|
||||
export default getFieldUnits;
|
||||
@ -0,0 +1 @@
|
||||
export { default as getFieldUnits } from './fieldUnits';
|
||||
@ -7,12 +7,12 @@ import { useIntl } from 'react-intl';
|
||||
* @param {Object} description - the description of the field
|
||||
* @param {Number} minimum - the minimum length or value of the field
|
||||
* @param {Number} maximum - the maximum length or value of the field
|
||||
* @param {Boolean} isNumber - whether this is a number field
|
||||
* @param {String} units
|
||||
*/
|
||||
const useFieldHint = ({ description, minimum, maximum, isNumber = false }) => {
|
||||
const useFieldHint = ({ description, minimum, maximum, units }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const [fieldHint, setFieldHint] = useState([]);
|
||||
const [hint, setHint] = useState([]);
|
||||
|
||||
/**
|
||||
* @returns {String}
|
||||
@ -39,10 +39,10 @@ const useFieldHint = ({ description, minimum, maximum, isNumber = false }) => {
|
||||
|
||||
const minMaxDescription = [];
|
||||
|
||||
if (minIsNumber && minimum > 0) {
|
||||
if (minIsNumber) {
|
||||
minMaxDescription.push(`min. {minimum}`);
|
||||
}
|
||||
if (maxIsNumber && maximum > 0) {
|
||||
if (maxIsNumber) {
|
||||
minMaxDescription.push(`max. {maximum}`);
|
||||
}
|
||||
|
||||
@ -50,23 +50,19 @@ const useFieldHint = ({ description, minimum, maximum, isNumber = false }) => {
|
||||
|
||||
if (minMaxDescription.length === 0) {
|
||||
defaultMessage = '';
|
||||
} else if (isNumber) {
|
||||
defaultMessage = `${minMaxDescription.join(' / ')}{br}`;
|
||||
} else {
|
||||
defaultMessage = `${minMaxDescription.join(
|
||||
' / '
|
||||
)} {isPlural, select, true {characters} other {character}}{br}`;
|
||||
defaultMessage = `${minMaxDescription.join(' / ')} {units}{br}`;
|
||||
}
|
||||
|
||||
return formatMessage(
|
||||
{
|
||||
id: `content-manager.form.Input.minMaxDescription${isNumber ? '.number' : ''}`,
|
||||
id: `content-manager.form.Input.minMaxDescription`,
|
||||
defaultMessage,
|
||||
},
|
||||
{
|
||||
minimum,
|
||||
maximum,
|
||||
isPlural: Math.max(minimum || 0, maximum || 0) > 1,
|
||||
units,
|
||||
br: <br />,
|
||||
}
|
||||
);
|
||||
@ -77,16 +73,16 @@ const useFieldHint = ({ description, minimum, maximum, isNumber = false }) => {
|
||||
const minMaxHint = buildMinMaxHint();
|
||||
|
||||
if (description.length === 0 && minMaxHint.length === 0) {
|
||||
setFieldHint('');
|
||||
setHint('');
|
||||
|
||||
return;
|
||||
}
|
||||
setFieldHint([...minMaxHint, description]);
|
||||
setHint([...minMaxHint, description]);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isNumber, description, minimum, maximum]);
|
||||
}, [units, description, minimum, maximum]);
|
||||
|
||||
return { fieldHint };
|
||||
return { hint };
|
||||
};
|
||||
|
||||
export default useFieldHint;
|
||||
|
||||
@ -6,6 +6,7 @@ import useFieldHint from '../index';
|
||||
|
||||
const messages = { 'message.id': 'response' };
|
||||
const description = { id: 'message.id', defaultMessage: '' };
|
||||
const units = 'units';
|
||||
|
||||
// eslint-disable-next-line react/prop-types
|
||||
export const IntlWrapper = ({ children }) => (
|
||||
@ -23,72 +24,18 @@ function setup(args) {
|
||||
}
|
||||
|
||||
describe('useFieldHint', () => {
|
||||
describe('correctly generates the description', () => {
|
||||
test('correctly generates the description', async () => {
|
||||
const minimum = 1;
|
||||
const maximum = 5;
|
||||
|
||||
test('as a character limit', async () => {
|
||||
const { result } = await setup({
|
||||
description,
|
||||
minimum,
|
||||
maximum,
|
||||
});
|
||||
|
||||
expect(result.current.fieldHint).toContain('min. 1 / max. 5 characters');
|
||||
expect(result.current.fieldHint).toContain('response');
|
||||
});
|
||||
|
||||
test('as a number limit', async () => {
|
||||
const { result } = await setup({
|
||||
description,
|
||||
minimum,
|
||||
maximum,
|
||||
isNumber: true,
|
||||
});
|
||||
|
||||
expect(result.current.fieldHint).toContain(`min. ${minimum} / max. ${maximum}`);
|
||||
expect(result.current.fieldHint).toContain('response');
|
||||
});
|
||||
});
|
||||
|
||||
test('ignores 0 minimum values', async () => {
|
||||
const minimum = 0;
|
||||
const maximum = 2;
|
||||
const { result } = await setup({
|
||||
description,
|
||||
minimum,
|
||||
maximum,
|
||||
units,
|
||||
});
|
||||
|
||||
expect(result.current.fieldHint).toContain(`max. ${maximum} characters`);
|
||||
expect(result.current.fieldHint).toContain('response');
|
||||
});
|
||||
|
||||
describe('handles plurals correctly', () => {
|
||||
const minimum = undefined;
|
||||
const maximum = 1;
|
||||
test('maximum', async () => {
|
||||
const { result } = await setup({
|
||||
description,
|
||||
minimum,
|
||||
maximum,
|
||||
});
|
||||
|
||||
expect(result.current.fieldHint).toContain(`max. ${maximum} character`);
|
||||
expect(result.current.fieldHint).toContain('response');
|
||||
});
|
||||
|
||||
test('minimum', async () => {
|
||||
const minimum = 1;
|
||||
const maximum = undefined;
|
||||
const { result } = await setup({
|
||||
description,
|
||||
minimum,
|
||||
maximum,
|
||||
});
|
||||
|
||||
expect(result.current.fieldHint).toContain(`min. ${minimum} character`);
|
||||
expect(result.current.fieldHint).toContain('response');
|
||||
});
|
||||
expect(result.current.hint).toContain(`min. ${minimum} / max. ${maximum} ${units}`);
|
||||
expect(result.current.hint).toContain('response');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user