@digigov/form 2.0.0-d0adc9fb → 2.0.0-d4fe516b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Field/ErrorGroup/index.js +48 -0
- package/Field/ErrorGroup/package.json +6 -0
- package/Field/ErrorGroup.d.ts +15 -0
- package/Field/ErrorGroup.js.map +7 -0
- package/Field/FieldBase/index.js +30 -22
- package/Field/FieldBase.js.map +2 -2
- package/Field/FieldBaseContainer/index.js +3 -2
- package/Field/FieldBaseContainer.js.map +2 -2
- package/Field/types.d.ts +2 -0
- package/FieldArray/index.js +1 -0
- package/FieldArray/index.js.map +2 -2
- package/FormBuilder/FormBuilder.stories.d.ts +2 -0
- package/FormBuilder/__stories__/AutoErrorGrouping.d.ts +3 -0
- package/FormBuilder/__stories__/ErrorGrouping.d.ts +3 -0
- package/FormBuilder/index.js +79 -3
- package/FormBuilder/index.js.map +2 -2
- package/FormBuilder/interaction.test.d.ts +1 -0
- package/MultiplicityField/index.js +1 -0
- package/MultiplicityField/index.js.map +2 -2
- package/cjs/Field/ErrorGroup/index.js +82 -0
- package/cjs/Field/ErrorGroup.js.map +7 -0
- package/cjs/Field/FieldBase/index.js +29 -21
- package/cjs/Field/FieldBase.js.map +2 -2
- package/cjs/Field/FieldBaseContainer/index.js +3 -2
- package/cjs/Field/FieldBaseContainer.js.map +2 -2
- package/cjs/Field/types.js.map +1 -1
- package/cjs/FieldArray/index.js +1 -0
- package/cjs/FieldArray/index.js.map +2 -2
- package/cjs/FormBuilder/index.js +79 -3
- package/cjs/FormBuilder/index.js.map +2 -2
- package/cjs/MultiplicityField/index.js +1 -0
- package/cjs/MultiplicityField/index.js.map +2 -2
- package/cjs/inputs/Input/index.js +1 -0
- package/cjs/inputs/Input/index.js.map +2 -2
- package/cjs/lazy/index.js +3 -1
- package/cjs/lazy.js.map +2 -2
- package/cjs/registry/index.js +4 -2
- package/cjs/registry.js.map +2 -2
- package/cjs/validators/index.js +18 -12
- package/cjs/validators/index.js.map +2 -2
- package/cjs/validators/utils/int/index.js +1 -1
- package/cjs/validators/utils/int.js.map +2 -2
- package/cjs/validators/utils/number/index.js +1 -1
- package/cjs/validators/utils/number.js.map +2 -2
- package/index.js +1 -1
- package/inputs/Input/Input.stories.d.ts +1 -0
- package/inputs/Input/__stories__/StringWithTrimValidation.d.ts +3 -0
- package/inputs/Input/index.js +1 -0
- package/inputs/Input/index.js.map +2 -2
- package/lazy/index.js +3 -1
- package/package.json +4 -4
- package/registry/index.js +4 -2
- package/src/Field/ErrorGroup.tsx +84 -0
- package/src/Field/FieldBase.tsx +33 -22
- package/src/Field/FieldBaseContainer.tsx +3 -2
- package/src/Field/types.tsx +2 -0
- package/src/FieldArray/index.tsx +1 -0
- package/src/FormBuilder/FormBuilder.stories.js +2 -0
- package/src/FormBuilder/__stories__/AutoErrorGrouping.tsx +63 -0
- package/src/FormBuilder/__stories__/ErrorGrouping.tsx +43 -0
- package/src/FormBuilder/index.test.tsx +19 -10
- package/src/FormBuilder/index.tsx +88 -5
- package/src/FormBuilder/interaction.test.tsx +32 -0
- package/src/FormBuilder/scenarios.test.tsx +111 -4
- package/src/MultiplicityField/index.tsx +1 -0
- package/src/Questions/__snapshots__/index.spec.tsx.snap +2 -1
- package/src/Questions/index.spec.tsx +8 -0
- package/src/inputs/Input/Input.stories.js +1 -0
- package/src/inputs/Input/__stories__/StringWithTrimValidation.tsx +26 -0
- package/src/inputs/Input/__stories__/TextWithLimit.tsx +1 -0
- package/src/inputs/Input/index.test.tsx +4 -0
- package/src/inputs/Input/index.tsx +1 -0
- package/src/lazy.js +3 -1
- package/src/registry.js +4 -2
- package/src/validators/index.ts +38 -13
- package/src/validators/utils/int.ts +1 -1
- package/src/validators/utils/number.ts +1 -1
- package/validators/index.js +18 -12
- package/validators/index.js.map +2 -2
- package/validators/utils/int/index.js +1 -1
- package/validators/utils/int.js.map +2 -2
- package/validators/utils/number/index.js +1 -1
- package/validators/utils/number.js.map +2 -2
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, { createContext, useEffect, useState } from 'react';
|
|
2
|
+
import { ErrorOption } from 'react-hook-form';
|
|
3
|
+
import { FieldLabelProps } from '@digigov/form/Field/types';
|
|
4
|
+
import { List, ListItem } from '@digigov/ui/content/List';
|
|
5
|
+
import { ErrorSummary } from '@digigov/ui/feedback/ErrorSummary';
|
|
6
|
+
import { useTranslation } from '@digigov/ui/i18n';
|
|
7
|
+
import { Link } from '@digigov/ui/navigation/Link';
|
|
8
|
+
import { Heading } from '@digigov/ui/typography/Heading';
|
|
9
|
+
import { Base } from '@digigov/ui/utils/Base';
|
|
10
|
+
import { Breakpoints } from '@digigov/ui/utils/hooks/useScreen';
|
|
11
|
+
interface ErrorGroupContextType {
|
|
12
|
+
setError: (
|
|
13
|
+
name?: string,
|
|
14
|
+
label?: FieldLabelProps,
|
|
15
|
+
error?: ErrorOption
|
|
16
|
+
) => void;
|
|
17
|
+
}
|
|
18
|
+
export const ErrorGroupContext = createContext<ErrorGroupContextType | null>(
|
|
19
|
+
null
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export interface ErrorGroupProps {
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
screenSize?: Breakpoints | undefined;
|
|
25
|
+
fieldOrder?: any[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const ErrorGroup: React.FC<ErrorGroupProps> = ({
|
|
29
|
+
children,
|
|
30
|
+
screenSize,
|
|
31
|
+
fieldOrder,
|
|
32
|
+
}) => {
|
|
33
|
+
const [errors, setErrors] = useState<ErrorOption>({});
|
|
34
|
+
const { t } = useTranslation();
|
|
35
|
+
const setError = (name, label, error) => {
|
|
36
|
+
if (errors[name] !== error && errors[name]?.message !== error?.message) {
|
|
37
|
+
if (!error?.message) {
|
|
38
|
+
const updatedErrors = { ...errors };
|
|
39
|
+
delete updatedErrors[name];
|
|
40
|
+
setErrors(updatedErrors);
|
|
41
|
+
} else {
|
|
42
|
+
setErrors({
|
|
43
|
+
...errors,
|
|
44
|
+
[name]: {
|
|
45
|
+
...error,
|
|
46
|
+
label: label.primary,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setErrors({});
|
|
55
|
+
}, [screenSize]);
|
|
56
|
+
return (
|
|
57
|
+
<ErrorGroupContext.Provider value={{ setError }}>
|
|
58
|
+
{Object.keys(errors).length !== 0 && (
|
|
59
|
+
<ErrorSummary variant="error-group">
|
|
60
|
+
<Heading size="sm">
|
|
61
|
+
Τα παρακάτω πεδία της φόρμας ειναι λάθος.{' '}
|
|
62
|
+
</Heading>
|
|
63
|
+
<List listStyle="bullet">
|
|
64
|
+
{(fieldOrder || Object.keys(errors).reverse())
|
|
65
|
+
.filter((fieldName) => errors[fieldName])
|
|
66
|
+
.map((fieldName, index) => {
|
|
67
|
+
return (
|
|
68
|
+
<ListItem key={index} id={`${fieldName}-error`}>
|
|
69
|
+
<Base as="b">{t(errors[fieldName]?.label)}:</Base>{' '}
|
|
70
|
+
<Link href={`#${fieldName}`}>
|
|
71
|
+
{t(errors[fieldName]?.message)}
|
|
72
|
+
</Link>
|
|
73
|
+
</ListItem>
|
|
74
|
+
);
|
|
75
|
+
})}
|
|
76
|
+
</List>
|
|
77
|
+
</ErrorSummary>
|
|
78
|
+
)}
|
|
79
|
+
{children}
|
|
80
|
+
</ErrorGroupContext.Provider>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default ErrorGroup;
|
package/src/Field/FieldBase.tsx
CHANGED
|
@@ -1,36 +1,46 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useContext, useEffect } from 'react';
|
|
2
2
|
import { Controller } from 'react-hook-form';
|
|
3
|
+
import { ErrorGroupContext } from '@digigov/form/Field/ErrorGroup';
|
|
3
4
|
import FieldBaseContainer from '@digigov/form/Field/FieldBaseContainer';
|
|
4
5
|
import { FieldBaseProps } from '@digigov/form/Field/types';
|
|
5
6
|
|
|
6
|
-
export const FieldBase: React.FC<FieldBaseProps> = (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
export const FieldBase: React.FC<FieldBaseProps> = ({
|
|
8
|
+
required,
|
|
9
|
+
name,
|
|
10
|
+
component: Component,
|
|
11
|
+
wrapper,
|
|
12
|
+
control,
|
|
13
|
+
type,
|
|
14
|
+
controlled = false,
|
|
15
|
+
enabled = true,
|
|
16
|
+
editable,
|
|
17
|
+
defaultValue,
|
|
18
|
+
label,
|
|
19
|
+
extra = {},
|
|
20
|
+
layout,
|
|
21
|
+
error,
|
|
22
|
+
register,
|
|
23
|
+
...componentProps
|
|
24
|
+
}) => {
|
|
25
|
+
const errorGroupContext = useContext(ErrorGroupContext);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (errorGroupContext) {
|
|
29
|
+
errorGroupContext.setError(name, label, error);
|
|
30
|
+
}
|
|
31
|
+
}, [error, name, errorGroupContext?.setError]);
|
|
32
|
+
|
|
25
33
|
if (!enabled) {
|
|
26
34
|
return null;
|
|
27
35
|
}
|
|
36
|
+
|
|
28
37
|
if (controlled) {
|
|
29
38
|
return (
|
|
30
39
|
<FieldBaseContainer
|
|
31
40
|
label={label}
|
|
32
41
|
layout={layout}
|
|
33
|
-
error={error}
|
|
42
|
+
error={errorGroupContext ? undefined : error}
|
|
43
|
+
hasError={!!error}
|
|
34
44
|
wrapper={wrapper}
|
|
35
45
|
name={name}
|
|
36
46
|
>
|
|
@@ -64,7 +74,8 @@ export const FieldBase: React.FC<FieldBaseProps> = (props) => {
|
|
|
64
74
|
<FieldBaseContainer
|
|
65
75
|
label={label}
|
|
66
76
|
layout={layout}
|
|
67
|
-
error={error}
|
|
77
|
+
error={errorGroupContext ? undefined : error}
|
|
78
|
+
hasError={!!error}
|
|
68
79
|
wrapper={wrapper}
|
|
69
80
|
name={name}
|
|
70
81
|
>
|
|
@@ -15,6 +15,7 @@ export const FieldBaseContainer: React.FC<FieldContainerProps> = ({
|
|
|
15
15
|
label,
|
|
16
16
|
children,
|
|
17
17
|
error,
|
|
18
|
+
hasError,
|
|
18
19
|
layout,
|
|
19
20
|
}) => {
|
|
20
21
|
const { t } = useTranslation();
|
|
@@ -24,7 +25,7 @@ export const FieldBaseContainer: React.FC<FieldContainerProps> = ({
|
|
|
24
25
|
const errorContext = error?.message.context || {};
|
|
25
26
|
if (wrapper === 'fieldset') {
|
|
26
27
|
return (
|
|
27
|
-
<FieldContainer error={
|
|
28
|
+
<FieldContainer error={hasError} {...layout}>
|
|
28
29
|
<CoreFieldset>
|
|
29
30
|
<FieldsetLegend size="sm">{label && label.primary}</FieldsetLegend>
|
|
30
31
|
{label && label.secondary && <Hint>{t(label.secondary)}</Hint>}
|
|
@@ -40,7 +41,7 @@ export const FieldBaseContainer: React.FC<FieldContainerProps> = ({
|
|
|
40
41
|
);
|
|
41
42
|
} else {
|
|
42
43
|
return (
|
|
43
|
-
<FieldContainer error={
|
|
44
|
+
<FieldContainer error={hasError} {...layout}>
|
|
44
45
|
<LabelContainer>
|
|
45
46
|
{label && <Label label={label} />}
|
|
46
47
|
{error && (
|
package/src/Field/types.tsx
CHANGED
|
@@ -32,6 +32,7 @@ export interface FieldSpec {
|
|
|
32
32
|
| 'phone_number'
|
|
33
33
|
| 'array'
|
|
34
34
|
| 'object';
|
|
35
|
+
trim?: boolean;
|
|
35
36
|
component?: any;
|
|
36
37
|
autoComplete?: string;
|
|
37
38
|
maxLength?: number;
|
|
@@ -94,6 +95,7 @@ export interface FieldContainerProps {
|
|
|
94
95
|
layout?: FieldSpec['layout'];
|
|
95
96
|
label?: FieldSpec['label'];
|
|
96
97
|
error?: ErrorOption | Record<string, any>;
|
|
98
|
+
hasError?: boolean;
|
|
97
99
|
children?: React.ReactNode;
|
|
98
100
|
wrapper?: FieldSpec['wrapper'];
|
|
99
101
|
}
|
package/src/FieldArray/index.tsx
CHANGED
|
@@ -5,3 +5,5 @@ export default {
|
|
|
5
5
|
displayName: 'FormBuilder',
|
|
6
6
|
};
|
|
7
7
|
export { Default } from '@digigov/form/FormBuilder/__stories__/Default';
|
|
8
|
+
export { ErrorGrouping } from '@digigov/form/FormBuilder/__stories__/ErrorGrouping';
|
|
9
|
+
export { AutoErrorGrouping } from '@digigov/form/FormBuilder/__stories__/AutoErrorGrouping';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import FormBuilder, { FieldSpec } from '@digigov/form';
|
|
3
|
+
|
|
4
|
+
const FIELDS: FieldSpec[] = [
|
|
5
|
+
{
|
|
6
|
+
key: 'name',
|
|
7
|
+
type: 'string',
|
|
8
|
+
required: true,
|
|
9
|
+
layout: { xl: 4, lg: 4, md: 6, xs: 6 },
|
|
10
|
+
label: {
|
|
11
|
+
primary: 'Όνομα',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
key: 'surname',
|
|
16
|
+
type: 'string',
|
|
17
|
+
required: true,
|
|
18
|
+
layout: { xl: 4, lg: 4, md: 6, xs: 6 },
|
|
19
|
+
label: {
|
|
20
|
+
primary: 'Επίθετο',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
key: 'address',
|
|
25
|
+
type: 'string',
|
|
26
|
+
required: true,
|
|
27
|
+
layout: { xl: 4, lg: 2, md: 6, xs: 6 },
|
|
28
|
+
label: {
|
|
29
|
+
primary: 'Διεύθυνση',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: 'town',
|
|
34
|
+
type: 'string',
|
|
35
|
+
required: true,
|
|
36
|
+
layout: { xl: 4, lg: 4, md: 6, xs: 6 },
|
|
37
|
+
label: {
|
|
38
|
+
primary: 'Πόλη',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: 'country',
|
|
43
|
+
type: 'string',
|
|
44
|
+
required: true,
|
|
45
|
+
layout: { xs: 12 },
|
|
46
|
+
label: {
|
|
47
|
+
primary: 'Χώρα',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
export const AutoErrorGrouping = () => (
|
|
53
|
+
<FormBuilder
|
|
54
|
+
grid={true}
|
|
55
|
+
auto={true}
|
|
56
|
+
onSubmit={(data) => {
|
|
57
|
+
console.log(data);
|
|
58
|
+
}}
|
|
59
|
+
fields={FIELDS}
|
|
60
|
+
></FormBuilder>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export default AutoErrorGrouping;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import FormBuilder, { Field } from '@digigov/form';
|
|
3
|
+
import { ErrorGroup } from '@digigov/form/Field/ErrorGroup';
|
|
4
|
+
import { Button } from '@digigov/ui/form/Button';
|
|
5
|
+
|
|
6
|
+
export const ErrorGrouping = () => (
|
|
7
|
+
<FormBuilder
|
|
8
|
+
grid={true}
|
|
9
|
+
onSubmit={(data) => {
|
|
10
|
+
console.log(data);
|
|
11
|
+
}}
|
|
12
|
+
>
|
|
13
|
+
<ErrorGroup>
|
|
14
|
+
<Field
|
|
15
|
+
key="name"
|
|
16
|
+
name="name"
|
|
17
|
+
type="string"
|
|
18
|
+
label={{ primary: 'Όνομα' }}
|
|
19
|
+
layout={{ xs: 4 }}
|
|
20
|
+
required
|
|
21
|
+
/>
|
|
22
|
+
<Field
|
|
23
|
+
key="surname"
|
|
24
|
+
name="surname"
|
|
25
|
+
type="string"
|
|
26
|
+
label={{ primary: 'Επίθετο' }}
|
|
27
|
+
layout={{ xs: 4 }}
|
|
28
|
+
required
|
|
29
|
+
/>
|
|
30
|
+
<Field
|
|
31
|
+
key="address"
|
|
32
|
+
name="address"
|
|
33
|
+
type="string"
|
|
34
|
+
label={{ primary: 'Διεύθυνση' }}
|
|
35
|
+
layout={{ xs: 4 }}
|
|
36
|
+
required
|
|
37
|
+
/>
|
|
38
|
+
</ErrorGroup>
|
|
39
|
+
<Button type="submit">Συνέχεια</Button>
|
|
40
|
+
</FormBuilder>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export default ErrorGrouping;
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { test, expect } from '@playwright/experimental-ct-react';
|
|
3
|
-
import TestVariant from '@digigov/ui/utils/TestVariant'
|
|
3
|
+
import TestVariant from '@digigov/ui/utils/TestVariant';
|
|
4
|
+
import { AutoErrorGrouping } from '@digigov/form/FormBuilder/__stories__/AutoErrorGrouping';
|
|
4
5
|
import { Default } from '@digigov/form/FormBuilder/__stories__/Default';
|
|
6
|
+
import { ErrorGrouping } from '@digigov/form/FormBuilder/__stories__/ErrorGrouping';
|
|
5
7
|
|
|
6
8
|
test('renders the All FormBuilder variants', async ({ mount, page }) => {
|
|
7
9
|
await mount(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
<div>
|
|
11
|
+
<TestVariant title="AutoErrorGrouping">
|
|
12
|
+
<AutoErrorGrouping />
|
|
13
|
+
</TestVariant>
|
|
14
|
+
<TestVariant title="Default">
|
|
15
|
+
<Default />
|
|
16
|
+
</TestVariant>
|
|
17
|
+
<TestVariant title="ErrorGrouping">
|
|
18
|
+
<ErrorGrouping />
|
|
19
|
+
</TestVariant>
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
15
22
|
await page.evaluate(() => document.fonts.ready);
|
|
16
23
|
|
|
17
|
-
const screenshot = await page.screenshot({
|
|
24
|
+
const screenshot = await page.screenshot({
|
|
25
|
+
fullPage: true,
|
|
26
|
+
animations: 'disabled',
|
|
27
|
+
});
|
|
18
28
|
expect(screenshot).toMatchSnapshot();
|
|
19
29
|
});
|
|
20
|
-
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import React, { useCallback, useContext, useRef } from 'react';
|
|
2
2
|
import { useForm } from 'react-hook-form';
|
|
3
3
|
import { Field } from '@digigov/form/Field';
|
|
4
|
+
import { ErrorGroup } from '@digigov/form/Field/ErrorGroup';
|
|
4
5
|
import { CONTROLLED_FIELD_COMPONENTS } from '@digigov/form/Field/utils';
|
|
5
|
-
import {
|
|
6
|
+
import { FieldsetWithContext } from '@digigov/form/Fieldset/FieldsetWithContext';
|
|
6
7
|
import { FormContext } from '@digigov/form/FormContext';
|
|
7
8
|
import { FormBaseProps, FormData, FormBuilderProps } from '@digigov/form/types';
|
|
8
9
|
import { yupResolver } from '@digigov/form/utils';
|
|
9
10
|
import { useValidationSchema } from '@digigov/form/validators';
|
|
10
11
|
import { Button } from '@digigov/ui/form/Button';
|
|
11
12
|
import { Form } from '@digigov/ui/form/Form';
|
|
13
|
+
import { useScreenSize } from '@digigov/ui/utils/hooks/useScreen';
|
|
12
14
|
|
|
13
15
|
const FormBase = React.forwardRef(function FormBase(
|
|
14
16
|
{
|
|
@@ -79,6 +81,43 @@ const FormBase = React.forwardRef(function FormBase(
|
|
|
79
81
|
);
|
|
80
82
|
});
|
|
81
83
|
|
|
84
|
+
const DEFAULT_LAYOUT = {
|
|
85
|
+
xs: 12,
|
|
86
|
+
sm: 12,
|
|
87
|
+
md: 12,
|
|
88
|
+
lg: 12,
|
|
89
|
+
xl: 12,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const BREAKPOINTS = ['xs', 'sm', 'md', 'lg', 'xl'];
|
|
93
|
+
|
|
94
|
+
const groupFieldsByLayout = (fields) => {
|
|
95
|
+
return BREAKPOINTS.reduce((sizes, size) => {
|
|
96
|
+
sizes[size] = fields
|
|
97
|
+
.reduce((acc, item) => {
|
|
98
|
+
const layoutValue = item.layout?.[size] || 12;
|
|
99
|
+
if (layoutValue === 0) {
|
|
100
|
+
return [...acc, item];
|
|
101
|
+
}
|
|
102
|
+
const lastElement = acc[acc.length - 1];
|
|
103
|
+
const currentSum = Array.isArray(lastElement)
|
|
104
|
+
? lastElement.reduce((sum, i) => sum + (i.layout?.[size] || 0), 0)
|
|
105
|
+
: 0;
|
|
106
|
+
if (!Array.isArray(lastElement) || currentSum + layoutValue > 12) {
|
|
107
|
+
return layoutValue === 12 ? [...acc, item] : [...acc, [item]];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return [...acc.slice(0, -1), [...lastElement, item]];
|
|
111
|
+
}, [])
|
|
112
|
+
.map((item) => {
|
|
113
|
+
if (Array.isArray(item) && item.length === 1) {
|
|
114
|
+
return item[0];
|
|
115
|
+
}
|
|
116
|
+
return item;
|
|
117
|
+
});
|
|
118
|
+
return sizes;
|
|
119
|
+
}, {});
|
|
120
|
+
};
|
|
82
121
|
const useFormContext = () => {
|
|
83
122
|
return useContext(FormContext);
|
|
84
123
|
};
|
|
@@ -105,6 +144,34 @@ const FormBuilder = React.forwardRef(function FormBuilder(
|
|
|
105
144
|
}: FormBuilderProps,
|
|
106
145
|
ref: React.Ref<HTMLFormElement>
|
|
107
146
|
): React.ReactElement {
|
|
147
|
+
const { screenSize } = useScreenSize();
|
|
148
|
+
fields = fields.map((field) => {
|
|
149
|
+
const layout = field.layout;
|
|
150
|
+
if (!layout) {
|
|
151
|
+
return {
|
|
152
|
+
...field,
|
|
153
|
+
layout: DEFAULT_LAYOUT,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
...field,
|
|
158
|
+
layout: BREAKPOINTS.reduce(
|
|
159
|
+
(expandedLayout, breakpoint, breakpointIndex) => {
|
|
160
|
+
if (field?.layout?.[breakpoint]) {
|
|
161
|
+
expandedLayout[breakpoint] = field?.layout[breakpoint];
|
|
162
|
+
} else if (expandedLayout[BREAKPOINTS[breakpointIndex - 1]]) {
|
|
163
|
+
expandedLayout[breakpoint] =
|
|
164
|
+
expandedLayout[BREAKPOINTS[breakpointIndex - 1]];
|
|
165
|
+
} else {
|
|
166
|
+
expandedLayout[breakpoint] = 12;
|
|
167
|
+
}
|
|
168
|
+
return expandedLayout;
|
|
169
|
+
},
|
|
170
|
+
{}
|
|
171
|
+
),
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
|
|
108
175
|
const fieldsState = useRef(fields);
|
|
109
176
|
const setFieldsState = useCallback((newFields) => {
|
|
110
177
|
fieldsState.current = newFields;
|
|
@@ -140,12 +207,28 @@ const FormBuilder = React.forwardRef(function FormBuilder(
|
|
|
140
207
|
if (auto) {
|
|
141
208
|
if (fieldsets) {
|
|
142
209
|
fieldChildren = fieldsets.map((fieldset) => (
|
|
143
|
-
<
|
|
210
|
+
<FieldsetWithContext key={fieldset.key} name={fieldset.key} />
|
|
144
211
|
));
|
|
145
212
|
} else if (fields) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
213
|
+
const fieldsByLayouts = groupFieldsByLayout(fields);
|
|
214
|
+
const fieldsByLayoutSize = fieldsByLayouts[screenSize];
|
|
215
|
+
fieldChildren = fieldsByLayoutSize.map((item, index) => {
|
|
216
|
+
if (Array.isArray(item)) {
|
|
217
|
+
return (
|
|
218
|
+
<ErrorGroup
|
|
219
|
+
key={index}
|
|
220
|
+
screenSize={screenSize}
|
|
221
|
+
fieldOrder={item.map((field) => field.key)}
|
|
222
|
+
>
|
|
223
|
+
{item.map((f) => {
|
|
224
|
+
return <Field key={f.key} name={f.key} />;
|
|
225
|
+
})}
|
|
226
|
+
</ErrorGroup>
|
|
227
|
+
);
|
|
228
|
+
} else {
|
|
229
|
+
return <Field key={item.key} name={item.key} />;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
149
232
|
}
|
|
150
233
|
}
|
|
151
234
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { test, expect } from '@playwright/experimental-ct-react';
|
|
3
|
+
|
|
4
|
+
import { AutoErrorGrouping } from '@digigov/form/FormBuilder/__stories__/AutoErrorGrouping';
|
|
5
|
+
import { ErrorGrouping } from '@digigov/form/FormBuilder/__stories__/ErrorGrouping';
|
|
6
|
+
|
|
7
|
+
test('renders the ErrorGrouping and click submit', async ({ mount, page }) => {
|
|
8
|
+
await mount(<ErrorGrouping />);
|
|
9
|
+
await page.evaluate(() => document.fonts.ready);
|
|
10
|
+
await page.click('text="Συνέχεια"');
|
|
11
|
+
|
|
12
|
+
const screenshot = await page.screenshot({
|
|
13
|
+
fullPage: true,
|
|
14
|
+
animations: 'disabled',
|
|
15
|
+
});
|
|
16
|
+
expect(screenshot).toMatchSnapshot();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('renders the AutoErrorGrouping and click submit', async ({
|
|
20
|
+
mount,
|
|
21
|
+
page,
|
|
22
|
+
}) => {
|
|
23
|
+
await mount(<AutoErrorGrouping />);
|
|
24
|
+
await page.evaluate(() => document.fonts.ready);
|
|
25
|
+
await page.click('text="Συνέχεια"');
|
|
26
|
+
|
|
27
|
+
const screenshot = await page.screenshot({
|
|
28
|
+
fullPage: true,
|
|
29
|
+
animations: 'disabled',
|
|
30
|
+
});
|
|
31
|
+
expect(screenshot).toMatchSnapshot();
|
|
32
|
+
});
|