Skip to content

Commit 79bb221

Browse files
committed
feat(forms): allow "required" prop to be a function
1 parent e66784d commit 79bb221

10 files changed

+53
-36
lines changed

demo/FormExamples.jsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export function FormExamples() {
147147
onSearch={console.log}
148148
placeholder="Type some letters"
149149
openOnFocus={true}
150-
required
150+
required={() => true}
151151
/>
152152
</div>
153153
<div className="col">
@@ -164,6 +164,7 @@ export function FormExamples() {
164164
<strong>{option}</strong> - {option}
165165
</>
166166
)}
167+
required={() => false}
167168
/>
168169
</div>
169170
</div>

src/forms/FormAutocomplete.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useState, useRef, useCallback, useEffect, useMemo } from 'react';
22
import PropTypes from 'prop-types';
3-
import { handleInputChange, normalizeOptions, normalizeDisabled } from './helpers/form-helpers';
3+
4+
import { handleInputChange, normalizeOptions, booleanOrFunction } from './helpers/form-helpers';
45
import { Dropdown } from '../mixed/Dropdown';
56
import { useOpenState } from '../utils/useOpenState';
67
import { formatClasses } from '../utils/attributes';
@@ -10,7 +11,7 @@ import { isEmpty } from '../utils/types';
1011
export function FormAutocomplete({
1112
onSearch,
1213
options,
13-
required,
14+
required: _required,
1415
id,
1516
placeholder,
1617
name,
@@ -33,7 +34,8 @@ export function FormAutocomplete({
3334
const searchInputRef = useRef(null);
3435

3536
const registerRef = useCallback(register, [register]);
36-
const disabled = normalizeDisabled(_disabled, getFormData());
37+
const disabled = booleanOrFunction(_disabled, getFormData());
38+
const required = booleanOrFunction(_required, getFormData());
3739

3840
const controlFeedback = getFormSubmitedAttempted() ? (isValid() ? 'is-valid' : 'is-invalid') : '';
3941

@@ -194,7 +196,7 @@ FormAutocomplete.propTypes = {
194196
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])),
195197
]),
196198
placeholder: PropTypes.string,
197-
required: PropTypes.bool,
199+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
198200
template: PropTypes.func,
199201
type: PropTypes.string,
200202
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

src/forms/FormCheckbox.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import React, { useCallback } from 'react';
22
import PropTypes from 'prop-types';
3+
34
import { useFormControl } from './helpers/useFormControl';
4-
import { normalizeDisabled } from './helpers/form-helpers';
5+
import { booleanOrFunction } from './helpers/form-helpers';
56

6-
export function FormCheckbox({ id, name, required, valueLabel, disabled: _disabled }) {
7+
export function FormCheckbox({ id, name, required: _required, valueLabel, disabled: _disabled }) {
78
const { getValue, handleOnChange, register, getFormData } = useFormControl(name, 'boolean');
89
const registerRef = useCallback(register, [register]);
9-
const disabled = normalizeDisabled(_disabled, getFormData());
10+
const disabled = booleanOrFunction(_disabled, getFormData());
11+
const required = booleanOrFunction(_required, getFormData());
1012

1113
return (
1214
<div className="custom-control custom-checkbox">
@@ -29,6 +31,6 @@ FormCheckbox.propTypes = {
2931
id: PropTypes.string.isRequired,
3032
name: PropTypes.string.isRequired,
3133
valueLabel: PropTypes.string,
32-
required: PropTypes.bool,
34+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3335
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3436
};

src/forms/FormInput.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React, { useCallback } from 'react';
22
import PropTypes from 'prop-types';
3+
34
import { useFormControl } from './helpers/useFormControl';
4-
import { normalizeDisabled } from './helpers/form-helpers';
5+
import { booleanOrFunction } from './helpers/form-helpers';
56

67
export function FormInput({
78
id,
89
type,
910
name,
1011
placeholder,
11-
required,
12+
required: _required,
1213
minLength,
1314
maxLength,
1415
min,
@@ -19,7 +20,8 @@ export function FormInput({
1920
}) {
2021
const { getValue, handleOnChange, register, getFormData } = useFormControl(name, type);
2122
const registerRef = useCallback(register, [register]);
22-
const disabled = normalizeDisabled(_disabled, getFormData());
23+
const disabled = booleanOrFunction(_disabled, getFormData());
24+
const required = booleanOrFunction(_required, getFormData());
2325

2426
const attrs = { required, name, id, placeholder, type, minLength, maxLength, min, max, pattern, step, disabled };
2527

@@ -45,7 +47,7 @@ FormInput.propTypes = {
4547
name: PropTypes.string.isRequired,
4648
pattern: PropTypes.string,
4749
placeholder: PropTypes.string,
48-
required: PropTypes.bool,
50+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
4951
step: PropTypes.string,
5052
type: PropTypes.string,
5153
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

src/forms/FormLabel.jsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33

4-
export function FormLabel({ id, label, required }) {
4+
export function FormLabel({ id, label, required: _required }) {
5+
const required = typeof _required === 'boolean';
6+
57
return (
68
<label htmlFor={id}>
79
{label}
@@ -14,5 +16,5 @@ export function FormLabel({ id, label, required }) {
1416
FormLabel.propTypes = {
1517
id: PropTypes.string,
1618
label: PropTypes.string,
17-
required: PropTypes.bool,
19+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
1820
};

src/forms/FormRadio.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import React, { useCallback } from 'react';
22
import PropTypes from 'prop-types';
3+
34
import { useFormControl } from './helpers/useFormControl';
4-
import { normalizeDisabled } from './helpers/form-helpers';
5+
import { booleanOrFunction } from './helpers/form-helpers';
56

6-
export function FormRadio({ id, name, required, checkedValue, valueLabel, inline, disabled: _disabled }) {
7+
export function FormRadio({ id, name, required: _required, checkedValue, valueLabel, inline, disabled: _disabled }) {
78
const { getValue, handleOnChange, register, getFormData } = useFormControl(name, 'boolean');
89
const registerRef = useCallback(register, [register]);
910
const value = getValue();
10-
const disabled = normalizeDisabled(_disabled, getFormData());
11+
const disabled = booleanOrFunction(_disabled, getFormData());
12+
const required = booleanOrFunction(_required, getFormData());
1113

1214
return (
1315
<div className={`custom-control custom-radio ${inline ? 'custom-control-inline' : ''}`}>
@@ -36,7 +38,7 @@ FormRadio.propTypes = {
3638
id: PropTypes.string.isRequired,
3739
inline: PropTypes.bool,
3840
name: PropTypes.string.isRequired,
39-
required: PropTypes.bool,
41+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
4042
valueLabel: PropTypes.string,
4143
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
4244
};

src/forms/FormSelect.jsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import React, { useCallback } from 'react';
22
import PropTypes from 'prop-types';
3-
import { normalizeOptions, normalizeDisabled } from './helpers/form-helpers';
4-
import { useFormControl } from './helpers/useFormControl';
3+
54
import { getValueByPath } from '../utils/getters-setters';
5+
import { normalizeOptions, booleanOrFunction } from './helpers/form-helpers';
6+
import { useFormControl } from './helpers/useFormControl';
67

7-
export function FormSelect({ id, name, options, required, placeholder, trackBy, disabled: _disabled }) {
8+
export function FormSelect({ id, name, options, required: _required, placeholder, trackBy, disabled: _disabled }) {
89
const { getFormData, getValue, handleOnChange, register } = useFormControl(name);
910
const registerRef = useCallback(register, [register]);
1011
const value = getValue();
1112
const normalizedOptions = normalizeOptions(options, getFormData());
12-
const disabled = normalizeDisabled(_disabled, getFormData());
13+
const disabled = booleanOrFunction(_disabled, getFormData());
14+
const required = booleanOrFunction(_required, getFormData());
1315

1416
return (
1517
<select
@@ -34,7 +36,7 @@ FormSelect.propTypes = {
3436
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])),
3537
]),
3638
placeholder: PropTypes.string,
37-
required: PropTypes.bool,
39+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3840
trackBy: PropTypes.string,
3941
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
4042
};

src/forms/FormSwitch.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import React, { useCallback } from 'react';
22
import PropTypes from 'prop-types';
3+
34
import { useFormControl } from './helpers/useFormControl';
4-
import { normalizeDisabled } from './helpers/form-helpers';
5+
import { booleanOrFunction } from './helpers/form-helpers';
56

6-
export function FormSwitch({ id, name, required, trueLabel, falseLabel, disabled: _disabled }) {
7+
export function FormSwitch({ id, name, required: _required, trueLabel, falseLabel, disabled: _disabled }) {
78
const { getValue, handleOnChange, register, getFormData } = useFormControl(name, 'boolean');
89
const registerRef = useCallback(register, [register]);
910
const value = getValue();
10-
const disabled = normalizeDisabled(_disabled, getFormData());
11+
const disabled = booleanOrFunction(_disabled, getFormData());
12+
const required = booleanOrFunction(_required, getFormData());
1113

1214
return (
1315
<div className="custom-control custom-switch">
@@ -30,7 +32,7 @@ FormSwitch.propTypes = {
3032
falseLabel: PropTypes.string,
3133
id: PropTypes.string.isRequired,
3234
name: PropTypes.string.isRequired,
33-
required: PropTypes.bool,
35+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3436
trueLabel: PropTypes.string,
3537
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3638
};

src/forms/FormTextarea.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import React, { useCallback } from 'react';
22
import PropTypes from 'prop-types';
3+
34
import { useFormControl } from './helpers/useFormControl';
4-
import { normalizeDisabled } from './helpers/form-helpers';
5+
import { booleanOrFunction } from './helpers/form-helpers';
56

6-
export function FormTextarea({ id, name, required, placeholder, rows, disabled: _disabled }) {
7+
export function FormTextarea({ id, name, required: _required, placeholder, rows, disabled: _disabled }) {
78
const { getValue, handleOnChange, register, getFormData } = useFormControl(name);
89
const registerRef = useCallback(register, [register]);
9-
const disabled = normalizeDisabled(_disabled, getFormData());
10+
const disabled = booleanOrFunction(_disabled, getFormData());
11+
const required = booleanOrFunction(_required, getFormData());
1012

1113
return (
1214
<textarea
@@ -27,7 +29,7 @@ FormTextarea.propTypes = {
2729
id: PropTypes.string,
2830
name: PropTypes.string.isRequired,
2931
placeholder: PropTypes.string,
30-
required: PropTypes.bool,
32+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3133
rows: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
3234
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3335
};

src/forms/helpers/form-helpers.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ export function normalizeOptions(options, formData, extraData) {
5656
});
5757
}
5858

59-
export function normalizeDisabled(disabled, formData) {
60-
if (!isFunction(disabled)) {
61-
return disabled;
59+
export function booleanOrFunction(property, formData) {
60+
if (!isFunction(property)) {
61+
return property;
6262
}
6363

64-
return disabled(formData);
64+
return property(formData);
6565
}

0 commit comments

Comments
 (0)