@inseefr/lunatic 3.6.6 → 3.6.8-rc.0
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/README.md +25 -0
- package/components/Loop/Loop.d.ts +1 -1
- package/components/Loop/Loop.js +5 -27
- package/components/Loop/Loop.js.map +1 -1
- package/components/Loop/utils.d.ts +8 -0
- package/components/Loop/utils.js +66 -0
- package/components/Loop/utils.js.map +1 -0
- package/components/RosterForLoop/RosterForLoop.js +4 -27
- package/components/RosterForLoop/RosterForLoop.js.map +1 -1
- package/esm/components/Loop/Loop.d.ts +1 -1
- package/esm/components/Loop/Loop.js +5 -28
- package/esm/components/Loop/Loop.js.map +1 -1
- package/esm/components/Loop/utils.d.ts +8 -0
- package/esm/components/Loop/utils.js +63 -0
- package/esm/components/Loop/utils.js.map +1 -0
- package/esm/components/RosterForLoop/RosterForLoop.js +5 -29
- package/esm/components/RosterForLoop/RosterForLoop.js.map +1 -1
- package/esm/use-lunatic/commons/compile-controls.js +8 -0
- package/esm/use-lunatic/commons/compile-controls.js.map +1 -1
- package/esm/use-lunatic/props/propIterations.js +12 -1
- package/esm/use-lunatic/props/propIterations.js.map +1 -1
- package/esm/use-lunatic/reducer/controls/check-base-control.js.map +1 -1
- package/package.json +15 -3
- package/src/components/Loop/Loop.tsx +6 -35
- package/src/components/Loop/utils.test.ts +61 -0
- package/src/components/Loop/utils.ts +74 -0
- package/src/components/RosterForLoop/RosterForLoop.tsx +3 -33
- package/src/stories/behaviour/controls/controls.stories.tsx +12 -3
- package/src/stories/behaviour/controls/data-standalone-loop.json +17 -0
- package/src/stories/behaviour/controls/source-standalone-loop.json +5503 -0
- package/src/stories/loop/source-paginated.json +1 -1
- package/src/stories/roundabout/sourceWithControl.json +14 -0
- package/src/use-lunatic/commons/compile-controls.ts +13 -0
- package/src/use-lunatic/props/propIterations.ts +30 -15
- package/src/use-lunatic/reducer/controls/check-base-control.ts +0 -1
- package/src/use-lunatic/use-lunatic-bug.test.ts +42 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/use-lunatic/commons/compile-controls.js +7 -0
- package/use-lunatic/commons/compile-controls.js.map +1 -1
- package/use-lunatic/props/propIterations.js +12 -1
- package/use-lunatic/props/propIterations.js.map +1 -1
- package/use-lunatic/reducer/controls/check-base-control.js.map +1 -1
- /package/src/stories/behaviour/controls/{source-loop.json → source-roster-for-loop.json} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inseefr/lunatic",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.8-rc.0",
|
|
4
4
|
"description": "Library of questionnaire components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -70,6 +70,8 @@
|
|
|
70
70
|
"src/components/Loop/Loop.spec.tsx",
|
|
71
71
|
"src/components/Loop/Loop.tsx",
|
|
72
72
|
"src/components/Loop/constant.ts",
|
|
73
|
+
"src/components/Loop/utils.test.ts",
|
|
74
|
+
"src/components/Loop/utils.ts",
|
|
73
75
|
"src/components/LunaticComponents.tsx",
|
|
74
76
|
"src/components/PairwiseLinks/PairwiseLinks.tsx",
|
|
75
77
|
"src/components/Question/Question.tsx",
|
|
@@ -238,11 +240,13 @@
|
|
|
238
240
|
"src/stories/behaviour/cleaning/source-loop.json",
|
|
239
241
|
"src/stories/behaviour/cleaning/source.json",
|
|
240
242
|
"src/stories/behaviour/controls/controls.stories.tsx",
|
|
243
|
+
"src/stories/behaviour/controls/data-standalone-loop.json",
|
|
241
244
|
"src/stories/behaviour/controls/source-boucles-n.json",
|
|
242
|
-
"src/stories/behaviour/controls/source-loop.json",
|
|
245
|
+
"src/stories/behaviour/controls/source-roster-for-loop.json",
|
|
243
246
|
"src/stories/behaviour/controls/source-roundabout.json",
|
|
244
247
|
"src/stories/behaviour/controls/source-simple-numeric.json",
|
|
245
248
|
"src/stories/behaviour/controls/source-simple.json",
|
|
249
|
+
"src/stories/behaviour/controls/source-standalone-loop.json",
|
|
246
250
|
"src/stories/behaviour/disabled/disabled.stories.tsx",
|
|
247
251
|
"src/stories/behaviour/disabled/source.json",
|
|
248
252
|
"src/stories/behaviour/filter/filter.stories.tsx",
|
|
@@ -411,6 +415,7 @@
|
|
|
411
415
|
"src/use-lunatic/reducer/reducer.ts",
|
|
412
416
|
"src/use-lunatic/reducer/reducerInitializer.tsx",
|
|
413
417
|
"src/use-lunatic/type.ts",
|
|
418
|
+
"src/use-lunatic/use-lunatic-bug.test.ts",
|
|
414
419
|
"src/use-lunatic/use-lunatic.test.ts",
|
|
415
420
|
"src/use-lunatic/use-lunatic.ts",
|
|
416
421
|
"src/utils/array.spec.ts",
|
|
@@ -535,6 +540,9 @@
|
|
|
535
540
|
"components/Loop/constant.d.ts",
|
|
536
541
|
"components/Loop/constant.js",
|
|
537
542
|
"components/Loop/constant.js.map",
|
|
543
|
+
"components/Loop/utils.d.ts",
|
|
544
|
+
"components/Loop/utils.js",
|
|
545
|
+
"components/Loop/utils.js.map",
|
|
538
546
|
"components/LunaticComponents.d.ts",
|
|
539
547
|
"components/LunaticComponents.js",
|
|
540
548
|
"components/LunaticComponents.js.map",
|
|
@@ -958,6 +966,9 @@
|
|
|
958
966
|
"esm/components/Loop/constant.d.ts",
|
|
959
967
|
"esm/components/Loop/constant.js",
|
|
960
968
|
"esm/components/Loop/constant.js.map",
|
|
969
|
+
"esm/components/Loop/utils.d.ts",
|
|
970
|
+
"esm/components/Loop/utils.js",
|
|
971
|
+
"esm/components/Loop/utils.js.map",
|
|
961
972
|
"esm/components/LunaticComponents.d.ts",
|
|
962
973
|
"esm/components/LunaticComponents.js",
|
|
963
974
|
"esm/components/LunaticComponents.js.map",
|
|
@@ -1976,7 +1987,8 @@
|
|
|
1976
1987
|
},
|
|
1977
1988
|
"devDependencies": {
|
|
1978
1989
|
"@eslint/js": "^9.9.0",
|
|
1979
|
-
"@playwright/
|
|
1990
|
+
"@playwright/browser-chromium": "^1.51.1",
|
|
1991
|
+
"@playwright/test": "^1.52.0",
|
|
1980
1992
|
"@storybook/addon-a11y": "^8.2.9",
|
|
1981
1993
|
"@storybook/addon-essentials": "^8.2.9",
|
|
1982
1994
|
"@storybook/addon-interactions": "^8.2.9",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type PropsWithChildren
|
|
1
|
+
import { type PropsWithChildren } from 'react';
|
|
2
2
|
import D from '../../i18n';
|
|
3
3
|
import { times } from '../../utils/array';
|
|
4
4
|
import { LunaticComponents } from '../LunaticComponents';
|
|
@@ -13,45 +13,16 @@ import {
|
|
|
13
13
|
getComponentErrors,
|
|
14
14
|
} from '../shared/ComponentErrors/ComponentErrors';
|
|
15
15
|
import type { LunaticError } from '../../use-lunatic/type';
|
|
16
|
+
import { useLoopUtils } from './utils';
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Loop without specific markup (stack of subcomponents)
|
|
19
20
|
*/
|
|
20
|
-
export function Loop({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
value,
|
|
24
|
-
handleChanges,
|
|
25
|
-
getComponents,
|
|
26
|
-
errors,
|
|
27
|
-
...props
|
|
28
|
-
}: LunaticComponentProps<'Loop'>) {
|
|
29
|
-
const min = lines?.min ?? 0;
|
|
30
|
-
const max = lines?.max ?? Infinity;
|
|
31
|
-
const [nbRows, setNbRows] = useState(() => {
|
|
32
|
-
return Math.max(iterations, min);
|
|
33
|
-
});
|
|
34
|
-
const addRow = useCallback(() => {
|
|
35
|
-
if (nbRows < max) {
|
|
36
|
-
setNbRows(nbRows + 1);
|
|
37
|
-
}
|
|
38
|
-
}, [max, nbRows]);
|
|
39
|
-
const removeRow = useCallback(() => {
|
|
40
|
-
if (nbRows > 1) {
|
|
41
|
-
const newNbRows = nbRows - 1;
|
|
42
|
-
setNbRows(newNbRows);
|
|
43
|
-
// Downsize all variables by 1
|
|
44
|
-
const newResponses = Object.entries(value).map(([k, v]) => {
|
|
45
|
-
return {
|
|
46
|
-
name: k,
|
|
47
|
-
value: v?.filter((_, i) => i < newNbRows),
|
|
48
|
-
};
|
|
49
|
-
});
|
|
50
|
-
handleChanges(newResponses);
|
|
51
|
-
}
|
|
52
|
-
}, [nbRows, handleChanges, value]);
|
|
21
|
+
export function Loop(props: LunaticComponentProps<'Loop'>) {
|
|
22
|
+
const { min, max, nbRows, addRow, removeRow } = useLoopUtils(props);
|
|
23
|
+
const { getComponents, errors } = props;
|
|
53
24
|
|
|
54
|
-
if (nbRows
|
|
25
|
+
if (nbRows === 0) {
|
|
55
26
|
return null;
|
|
56
27
|
}
|
|
57
28
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { useLoopUtils } from './utils';
|
|
4
|
+
|
|
5
|
+
describe('useLoopUtils()', () => {
|
|
6
|
+
it('should handleChange where values have not the right size', () => {
|
|
7
|
+
const mockHandleChange = vi.fn();
|
|
8
|
+
|
|
9
|
+
renderHook(() =>
|
|
10
|
+
useLoopUtils({
|
|
11
|
+
handleChanges: mockHandleChange,
|
|
12
|
+
iterations: 5,
|
|
13
|
+
lines: { min: 2, max: 10 },
|
|
14
|
+
value: { NAME: ['John', 'Doe'], AGE: [10, 20] },
|
|
15
|
+
})
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
expect(mockHandleChange).toHaveBeenCalledOnce();
|
|
19
|
+
expect(mockHandleChange).toHaveBeenCalledWith([
|
|
20
|
+
{ name: 'NAME', value: ['John', 'Doe', null, null, null] },
|
|
21
|
+
{ name: 'AGE', value: [10, 20, null, null, null] },
|
|
22
|
+
]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should NOT handleChange where values have the right size', () => {
|
|
26
|
+
const mockHandleChange = vi.fn();
|
|
27
|
+
|
|
28
|
+
renderHook(() =>
|
|
29
|
+
useLoopUtils({
|
|
30
|
+
handleChanges: mockHandleChange,
|
|
31
|
+
iterations: 2,
|
|
32
|
+
lines: { min: 2, max: 10 },
|
|
33
|
+
value: { NAME: ['John', 'Doe'], AGE: [10, 20] },
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(mockHandleChange).toHaveBeenCalledTimes(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should handleChange with iteration when adding row', () => {
|
|
41
|
+
const mockHandleChange = vi.fn();
|
|
42
|
+
|
|
43
|
+
// Given
|
|
44
|
+
const { result } = renderHook(() =>
|
|
45
|
+
useLoopUtils({
|
|
46
|
+
handleChanges: mockHandleChange,
|
|
47
|
+
iterations: 2,
|
|
48
|
+
lines: { min: 2, max: 10 },
|
|
49
|
+
value: { NAME: ['John', 'Doe'], AGE: [10, 20] },
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
// When
|
|
53
|
+
result.current.addRow();
|
|
54
|
+
|
|
55
|
+
// Then
|
|
56
|
+
expect(mockHandleChange).toHaveBeenCalledWith([
|
|
57
|
+
{ name: 'NAME', value: null, iteration: [2] },
|
|
58
|
+
{ name: 'AGE', value: null, iteration: [2] },
|
|
59
|
+
]);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { LunaticComponentProps } from '../type';
|
|
3
|
+
import { resizeArrayVariable } from '../../use-lunatic/reducer/commons';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_MIN_ROWS = 1;
|
|
6
|
+
const DEFAULT_MAX_ROWS = 12;
|
|
7
|
+
|
|
8
|
+
export const useLoopUtils = (
|
|
9
|
+
props: Pick<
|
|
10
|
+
LunaticComponentProps<'RosterForLoop'> | LunaticComponentProps<'Loop'>,
|
|
11
|
+
'lines' | 'iterations' | 'value' | 'handleChanges'
|
|
12
|
+
>
|
|
13
|
+
) => {
|
|
14
|
+
const { lines, iterations, value: valueMap, handleChanges } = props;
|
|
15
|
+
const min = lines?.min ?? DEFAULT_MIN_ROWS;
|
|
16
|
+
const max = lines?.max ?? DEFAULT_MAX_ROWS;
|
|
17
|
+
const [nbRows, setNbRows] = useState(
|
|
18
|
+
Math.max(min, iterations ?? DEFAULT_MIN_ROWS)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* For Loop & rosterForLoop,
|
|
23
|
+
* Value can be inconsistent i.e the value has not the right size
|
|
24
|
+
* The function add null values to the end of value (array), only when component is mount
|
|
25
|
+
*
|
|
26
|
+
* This the case when size of value is defined by VTL (but the value is not triggered by change)
|
|
27
|
+
* - ex: external variable indicate the size of variable
|
|
28
|
+
* - ex: min != max
|
|
29
|
+
*
|
|
30
|
+
* Improvment: do some kind of dynamic resizing and remove this useEffect.
|
|
31
|
+
* Variables must be consistent in variable-store.
|
|
32
|
+
*/
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const initialResponses = Object.entries(valueMap)
|
|
35
|
+
.filter(([, v]) => (v?.length ?? 0) < nbRows)
|
|
36
|
+
.map(([k, v]) => ({
|
|
37
|
+
name: k,
|
|
38
|
+
value: resizeArrayVariable(v, nbRows, null),
|
|
39
|
+
}));
|
|
40
|
+
if (initialResponses.length > 0) handleChanges(initialResponses);
|
|
41
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
42
|
+
}, []);
|
|
43
|
+
|
|
44
|
+
const addRow = useCallback(() => {
|
|
45
|
+
if (nbRows < max) {
|
|
46
|
+
const newNbRows = nbRows + 1;
|
|
47
|
+
setNbRows(newNbRows);
|
|
48
|
+
const newResponses = Object.entries(valueMap).map(([k]) => ({
|
|
49
|
+
name: k,
|
|
50
|
+
value: null,
|
|
51
|
+
iteration: [nbRows],
|
|
52
|
+
}));
|
|
53
|
+
handleChanges(newResponses);
|
|
54
|
+
}
|
|
55
|
+
}, [max, nbRows, valueMap, handleChanges]);
|
|
56
|
+
|
|
57
|
+
const removeRow = useCallback(() => {
|
|
58
|
+
if (nbRows <= min) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const newNbRows = nbRows - 1;
|
|
62
|
+
setNbRows(newNbRows);
|
|
63
|
+
// Downsize all variables by 1
|
|
64
|
+
const newResponses = Object.entries(valueMap).map(([k, v]) => {
|
|
65
|
+
return {
|
|
66
|
+
name: k,
|
|
67
|
+
value: v?.filter((_, i) => i < newNbRows),
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
handleChanges(newResponses);
|
|
71
|
+
}, [nbRows, min, valueMap, handleChanges]);
|
|
72
|
+
|
|
73
|
+
return { min, max, nbRows, addRow, removeRow };
|
|
74
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fragment
|
|
1
|
+
import { Fragment } from 'react';
|
|
2
2
|
import type { LunaticComponentProps } from '../type';
|
|
3
3
|
import { Table, Tbody, Td, Tr, TableHeader } from '../shared/Table';
|
|
4
4
|
import { times } from '../../utils/array';
|
|
@@ -9,9 +9,7 @@ import {
|
|
|
9
9
|
getComponentErrors,
|
|
10
10
|
} from '../shared/ComponentErrors/ComponentErrors';
|
|
11
11
|
import { CustomLoop } from '../Loop/Loop';
|
|
12
|
-
|
|
13
|
-
const DEFAULT_MIN_ROWS = 1;
|
|
14
|
-
const DEFAULT_MAX_ROWS = 12;
|
|
12
|
+
import { useLoopUtils } from '../Loop/utils';
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
15
|
* Loop displayed as a table
|
|
@@ -19,46 +17,18 @@ const DEFAULT_MAX_ROWS = 12;
|
|
|
19
17
|
export const RosterForLoop = (
|
|
20
18
|
props: LunaticComponentProps<'RosterForLoop'>
|
|
21
19
|
) => {
|
|
20
|
+
const { min, max, nbRows, addRow, removeRow } = useLoopUtils(props);
|
|
22
21
|
const {
|
|
23
|
-
value: valueMap,
|
|
24
|
-
lines,
|
|
25
22
|
errors,
|
|
26
|
-
handleChanges,
|
|
27
23
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
24
|
declarations,
|
|
29
25
|
header,
|
|
30
|
-
iterations,
|
|
31
26
|
id,
|
|
32
27
|
getComponents,
|
|
33
28
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
34
29
|
label,
|
|
35
30
|
...otherProps // These props will be passed down to the child components
|
|
36
31
|
} = props;
|
|
37
|
-
const min = lines?.min ?? DEFAULT_MIN_ROWS;
|
|
38
|
-
const max = lines?.max ?? DEFAULT_MAX_ROWS;
|
|
39
|
-
const [nbRows, setNbRows] = useState(Math.max(min, iterations));
|
|
40
|
-
|
|
41
|
-
const addRow = useCallback(() => {
|
|
42
|
-
if (nbRows < max) {
|
|
43
|
-
setNbRows(nbRows + 1);
|
|
44
|
-
}
|
|
45
|
-
}, [max, nbRows]);
|
|
46
|
-
|
|
47
|
-
const removeRow = useCallback(() => {
|
|
48
|
-
if (nbRows <= min) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const newNbRows = nbRows - 1;
|
|
52
|
-
setNbRows(newNbRows);
|
|
53
|
-
// Downsize all variables by 1
|
|
54
|
-
const newResponses = Object.entries(valueMap).map(([k, v]) => {
|
|
55
|
-
return {
|
|
56
|
-
name: k,
|
|
57
|
-
value: v?.filter((_, i) => i < newNbRows),
|
|
58
|
-
};
|
|
59
|
-
});
|
|
60
|
-
handleChanges(newResponses);
|
|
61
|
-
}, [nbRows, min, valueMap, handleChanges]);
|
|
62
32
|
|
|
63
33
|
if (nbRows === 0) {
|
|
64
34
|
return null;
|
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
} from '../../utils/Orchestrator';
|
|
6
6
|
import simple from './source-simple.json';
|
|
7
7
|
import simpleNum from './source-simple-numeric.json';
|
|
8
|
-
import
|
|
8
|
+
import sourceRosterForLoop from './source-roster-for-loop.json';
|
|
9
|
+
import sourceStandaloneLoop from './source-standalone-loop.json';
|
|
10
|
+
import dataStandaloneLoop from './data-standalone-loop.json';
|
|
9
11
|
import sourceRoundabout from './source-roundabout.json';
|
|
10
12
|
import boucleNTabDynamique from './source-boucles-n.json';
|
|
11
13
|
|
|
@@ -38,9 +40,16 @@ export const SimpleNum: OrchestratorStory = {
|
|
|
38
40
|
|
|
39
41
|
export const LinkedLoop: OrchestratorStory = {};
|
|
40
42
|
|
|
41
|
-
export const
|
|
43
|
+
export const RosterForLoop: OrchestratorStory = {
|
|
42
44
|
args: {
|
|
43
|
-
source:
|
|
45
|
+
source: sourceRosterForLoop,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const StandaloneLoop: OrchestratorStory = {
|
|
50
|
+
args: {
|
|
51
|
+
source: sourceStandaloneLoop,
|
|
52
|
+
data: dataStandaloneLoop,
|
|
44
53
|
},
|
|
45
54
|
};
|
|
46
55
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"EXTERNAL": {
|
|
3
|
+
"NIR": ["23456", "23456", "23456", "23456", "23456", "12345"],
|
|
4
|
+
"CODE_CC": ["CODE", "CODE", "CODE", "CODE", "CODE", "CODE"],
|
|
5
|
+
"NBSAL_INT": "6",
|
|
6
|
+
"LIBELLE_CC": ["LIB CC", "LIB CC", "LIB CC", "LIB CC", "LIB CC", "LIB CC"],
|
|
7
|
+
"NUM_ORDRE_SALARIE": ["1", "2", "3", "4", "5", "6"],
|
|
8
|
+
"NOM_COMPLET_SALARIE": [
|
|
9
|
+
"THREEPWOOD GUYBRUSH",
|
|
10
|
+
"LINK",
|
|
11
|
+
"JANE DOE",
|
|
12
|
+
"JOHN DOE",
|
|
13
|
+
"IL FAIT CHAUD",
|
|
14
|
+
"POISSON STEVE"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|