Skip to content

Commit e15dbf8

Browse files
authored
feat(meta): add option to display mandatory field hint (#98)
1 parent e8ac803 commit e15dbf8

21 files changed

+135
-9
lines changed

apps/demo/src/app/examples/with-material-ui/dictionary/checkBox.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const Checkbox = ({
1616
onChange,
1717
propRef,
1818
value,
19+
shouldDisplayRequiredHint,
1920
}: {
2021
'data-testid': string;
2122
errorMessage: string;
@@ -29,9 +30,14 @@ export const Checkbox = ({
2930
propRef: Ref<any>;
3031
type?: string;
3132
value?: boolean;
33+
shouldDisplayRequiredHint?: boolean;
3234
}) => {
3335
const inputProps = useMemo(() => ({ ref: propRef, 'aria-label': 'controlled' }), [propRef]);
3436

37+
if (shouldDisplayRequiredHint) {
38+
label += ' *';
39+
}
40+
3541
return (
3642
<Box sx={{ m: 2 }}>
3743
<FormGroup>

apps/demo/src/app/examples/with-material-ui/dictionary/date.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const DateInput = ({
2727
onChange,
2828
onBlur,
2929
propRef,
30+
shouldDisplayRequiredHint,
3031
}: {
3132
'data-testid': string;
3233
errors: FieldErrors;
@@ -41,6 +42,7 @@ export const DateInput = ({
4142
value?: string | number;
4243
validation: Validations;
4344
setFieldValue: (id: Path<FieldValues>, value: any) => void;
45+
shouldDisplayRequiredHint?: boolean;
4446
}) => {
4547
const inputProps = useMemo(() => ({ ref: propRef }), [propRef]);
4648
const rules = getValidationRulesHints({
@@ -50,6 +52,10 @@ export const DateInput = ({
5052

5153
const hasError = !!checkRules(value, rules).length;
5254

55+
if (shouldDisplayRequiredHint) {
56+
label += ' *';
57+
}
58+
5359
return (
5460
<div>
5561
<BirthdateInput

apps/demo/src/app/examples/with-material-ui/dictionary/password.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const Password = ({
2525
propRef,
2626
value,
2727
validation,
28+
shouldDisplayRequiredHint,
2829
}: {
2930
'data-testid': string;
3031
errors: FieldErrors;
@@ -38,6 +39,7 @@ export const Password = ({
3839
type?: string;
3940
value?: string | number;
4041
validation: Validations;
42+
shouldDisplayRequiredHint?: boolean;
4143
}) => {
4244
const inputProps = useMemo(() => ({ ref: propRef }), [propRef]);
4345

@@ -48,6 +50,10 @@ export const Password = ({
4850

4951
const hasError = !!checkRules(value, rules).length;
5052

53+
if (shouldDisplayRequiredHint) {
54+
label += ' *';
55+
}
56+
5157
return (
5258
<ValidatedTextField
5359
type="password"

apps/demo/src/app/examples/with-material-ui/dictionary/select.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const Select = ({
1313
value,
1414
choices,
1515
multiple,
16+
shouldDisplayRequiredHint,
1617
}: {
1718
'data-testid': string;
1819
errorMessage: string;
@@ -28,9 +29,14 @@ export const Select = ({
2829
value?: string | number;
2930
choices: string[] | number[];
3031
multiple?: boolean;
32+
shouldDisplayRequiredHint?: boolean;
3133
}) => {
3234
const inputProps = useMemo(() => ({ ref: propRef }), [propRef]);
3335

36+
if (shouldDisplayRequiredHint) {
37+
label += ' *';
38+
}
39+
3440
return (
3541
<Box sx={{ m: 2 }}>
3642
<InputLabel id="label-id">{label}</InputLabel>

apps/demo/src/app/examples/with-material-ui/dictionary/text.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const Text = ({
1717
type,
1818
value,
1919
multiline,
20+
shouldDisplayRequiredHint,
2021
}: {
2122
'data-testid': string;
2223
errorMessage: string;
@@ -31,10 +32,15 @@ export const Text = ({
3132
type?: string;
3233
value?: string | number;
3334
multiline?: boolean;
35+
shouldDisplayRequiredHint?: boolean;
3436
}) => {
3537
const inputProps = useMemo(() => ({ ref: propRef }), [propRef]);
3638
const error = errors && errors.type && errorMessage;
3739

40+
if (shouldDisplayRequiredHint) {
41+
label += ' *';
42+
}
43+
3844
return (
3945
<Box sx={{ m: 2 }}>
4046
<TextField

apps/demo/src/app/examples/with-styled-components/dictionary/checkBox.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ export const Checkbox = ({
22
onChange,
33
value,
44
label,
5+
shouldDisplayRequiredHint,
56
}: {
67
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
78
value: boolean;
89
label: string;
10+
shouldDisplayRequiredHint?: boolean;
911
}) => {
12+
if (shouldDisplayRequiredHint) {
13+
label += ' *';
14+
}
15+
1016
return (
1117
<div>
1218
<label>{label}</label>

apps/demo/src/app/examples/with-styled-components/dictionary/date.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { RuleList } from '../atoms/rule-list.component';
1212
export const DateInput = ({
1313
errors,
1414
validation,
15+
shouldDisplayRequiredHint,
1516
label,
1617
...props
1718
}: {
@@ -23,6 +24,7 @@ export const DateInput = ({
2324
id: string;
2425
setFieldValue: (id: Path<FieldValues>, value: any) => void;
2526
onChange: (event: any) => void;
27+
shouldDisplayRequiredHint?: boolean;
2628
}) => {
2729
const rules = getValidationRulesHints({
2830
errors,
@@ -32,6 +34,10 @@ export const DateInput = ({
3234
const fieldError = errors && errors.type;
3335
const isValid = !!(props.value && !hasError && !fieldError);
3436

37+
if (shouldDisplayRequiredHint) {
38+
label += ' *';
39+
}
40+
3541
return (
3642
<TextFieldMarginWrapper>
3743
<BirthdateInput

apps/demo/src/app/examples/with-styled-components/dictionary/password.component.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ import { RuleList } from '../atoms/rule-list.component';
1111
export const Password = ({
1212
errors,
1313
validation,
14+
shouldDisplayRequiredHint,
15+
label,
1416
...props
1517
}: {
1618
errors: FieldErrors;
1719
errorMessage: string;
1820
label: string;
1921
value?: string | number;
2022
validation: Validations;
23+
shouldDisplayRequiredHint?: boolean;
2124
}) => {
2225
const rules = getValidationRulesHints({
2326
errors,
@@ -27,11 +30,16 @@ export const Password = ({
2730
const fieldError = errors && errors.type;
2831
const isValid = !!(props.value && !hasError && !fieldError);
2932

33+
if (shouldDisplayRequiredHint) {
34+
label += ' *';
35+
}
36+
3037
return (
3138
<TextFieldTopMarginWrapper>
3239
<ValidatedPasswordTextField
3340
hasError={hasError}
3441
valid={isValid}
42+
label={label}
3543
{...props}
3644
rules={rules}
3745
ruleComponent={RuleList}

apps/demo/src/app/examples/with-styled-components/dictionary/select.component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ export const Select = ({
44
label,
55
choices,
66
multiple,
7+
shouldDisplayRequiredHint,
78
}: {
89
onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
910
value: string | number;
1011
label: string;
1112
choices: string[] | number[];
1213
multiple?: boolean;
14+
shouldDisplayRequiredHint?: boolean;
1315
}) => {
16+
if (shouldDisplayRequiredHint) {
17+
label += ' *';
18+
}
19+
1420
return (
1521
<div style={{ margin: '24px' }}>
1622
<label>

apps/demo/src/app/examples/with-styled-components/dictionary/submit.component.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,16 @@ const PreviousButton = styled.button`
2020
border: 1px solid rgba(150, 100, 255);
2121
`;
2222

23-
export const Submit = ({ label, formId, ...props }: { label: string; formId: string }) => {
23+
export const Submit = ({
24+
label,
25+
formId,
26+
shouldDisplayRequiredHint,
27+
...props
28+
}: {
29+
label: string;
30+
formId: string;
31+
shouldDisplayRequiredHint?: boolean;
32+
}) => {
2433
const dispatch = useDispatch();
2534

2635
const shouldDisplayPrevious = useSelector(getCurrentStepIndex(formId)) !== 0;
@@ -29,6 +38,10 @@ export const Submit = ({ label, formId, ...props }: { label: string; formId: str
2938
dispatch(setPreviousStep(formId));
3039
};
3140

41+
if (shouldDisplayRequiredHint) {
42+
label += ' *';
43+
}
44+
3245
return (
3346
<ActionsWrapper>
3447
{shouldDisplayPrevious && (

apps/demo/src/app/examples/with-styled-components/dictionary/text.component.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,33 @@ export const Text = ({
99
errors,
1010
errorMessage,
1111
validation,
12+
shouldDisplayRequiredHint,
13+
label,
1214
...props
1315
}: {
1416
errors: FieldErrors;
1517
errorMessage: string;
1618
label: string;
1719
value?: string | number;
1820
validation: Validations;
21+
shouldDisplayRequiredHint?: boolean;
1922
}) => {
2023
const error = errors && errors.type && errorMessage;
2124

25+
if (shouldDisplayRequiredHint) {
26+
label += ' *';
27+
}
28+
2229
return (
2330
<TextFieldMarginWrapper>
24-
<ValidatedTextField type="text" hasError={!!error} errorText={error} valid={!!props.value && !error} {...props} />
31+
<ValidatedTextField
32+
type="text"
33+
hasError={!!error}
34+
errorText={error}
35+
valid={!!props.value && !error}
36+
label={label}
37+
{...props}
38+
/>
2539
</TextFieldMarginWrapper>
2640
);
2741
};

apps/demo/src/app/login.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ export const config = {
6161
},
6262
},
6363
},
64+
formMeta: {
65+
shouldDisplayRequiredHint: false,
66+
},
6467
steps: {
6568
'login-step-0': {
6669
fieldsById: ['email'],

apps/demo/src/app/register.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ export const config: Config = {
170170
},
171171
},
172172
},
173+
formMeta: {
174+
shouldDisplayRequiredHint: true,
175+
},
173176
steps: {
174177
'register-step-0': {
175178
fieldsById: ['email', 'discloseGender', 'gender', 'firstName', 'lastName'],

apps/docsite/docs/form-builder.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ export interface FormSchema {
6666
| Path<string>;
6767
};
6868
};
69+
formMeta?: {
70+
shouldDisplayRequiredHint?: boolean;
71+
};
6972
steps: {
7073
[key: string]: {
7174
id: string;

libs/form-builder/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export interface FormSchema {
6363
| Path<string>;
6464
};
6565
};
66+
formMeta?: {
67+
shouldDisplayRequiredHint?: boolean;
68+
};
6669
steps: {
6770
[key: string]: {
6871
id: string;

libs/form-builder/src/lib/__tests__/fixtures.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const CORRECT_SCHEMA: FormSchema = {
5454
type: 'text',
5555
},
5656
},
57+
formMeta: {},
5758
steps: { ...stepOne, ...stepTwo },
5859
stepsById: [stepOneId, stepTwoId],
5960
};

libs/form-builder/src/lib/components/formField.component.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,32 @@ export interface FormFieldProps {
1616
onClick?: (event: any) => void;
1717
isValidating?: boolean;
1818
formId?: string;
19+
shouldDisplayRequiredHint?: boolean;
1920
}
2021

21-
export function FormField({ id, fieldType, dictionary, ...props }: FormFieldProps) {
22+
export function FormField({
23+
id,
24+
fieldType,
25+
dictionary,
26+
shouldDisplayRequiredHint,
27+
validation,
28+
...props
29+
}: FormFieldProps) {
2230
const Field = dictionary[fieldType];
2331

2432
if (!Field) return null;
2533

26-
return <Field data-testid={id} id={id} {...props} />;
34+
if (!validation?.required?.value) {
35+
shouldDisplayRequiredHint = false;
36+
}
37+
38+
return (
39+
<Field
40+
data-testid={id}
41+
id={id}
42+
shouldDisplayRequiredHint={shouldDisplayRequiredHint}
43+
validation={validation}
44+
{...props}
45+
/>
46+
);
2747
}

libs/form-builder/src/lib/formBuilder.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function FormBuilder({
7777

7878
const typesAllowed = React.useMemo(() => Object.keys(dictionary || EMPTY_OBJECT), [dictionary]);
7979

80-
const { fields, fieldsById, stepsById, submitLabel } = React.useMemo(
80+
const { fields, fieldsById, stepsById, submitLabel, formMeta } = React.useMemo(
8181
() => getSchemaInfo(schema, typesAllowed, currentStepIndex),
8282
[currentStepIndex, schema, typesAllowed],
8383
);
@@ -161,6 +161,7 @@ export function FormBuilder({
161161
triggerValidationField={triggerValidationField}
162162
propRef={ref}
163163
isValidating={isValidating}
164+
{...formMeta}
164165
{...meta}
165166
{...fieldRest}
166167
/>

0 commit comments

Comments
 (0)