@inseefr/lunatic 3.6.14 → 3.6.15-rc.1

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.
Files changed (60) hide show
  1. package/components/Roundabout/Roundabout.js +8 -3
  2. package/components/Roundabout/Roundabout.js.map +1 -1
  3. package/esm/components/Roundabout/Roundabout.js +8 -3
  4. package/esm/components/Roundabout/Roundabout.js.map +1 -1
  5. package/esm/hooks/useMultimode.d.ts +49 -0
  6. package/esm/hooks/useMultimode.js +83 -0
  7. package/esm/hooks/useMultimode.js.map +1 -0
  8. package/esm/index.d.ts +1 -0
  9. package/esm/index.js +1 -0
  10. package/esm/index.js.map +1 -1
  11. package/esm/type.source.d.ts +33 -1
  12. package/esm/type.source.js +0 -1
  13. package/esm/type.source.js.map +1 -1
  14. package/esm/use-lunatic/reducer/reduce-go-next-page.js +2 -1
  15. package/esm/use-lunatic/reducer/reduce-go-next-page.js.map +1 -1
  16. package/esm/use-lunatic/reducer/reducerInitializer.d.ts +2 -2
  17. package/esm/use-lunatic/reducer/reducerInitializer.js +31 -24
  18. package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  19. package/esm/use-lunatic/type.d.ts +2 -0
  20. package/esm/use-lunatic/use-lunatic.js +3 -0
  21. package/esm/use-lunatic/use-lunatic.js.map +1 -1
  22. package/esm/utils/getArticulationState.d.ts +64 -0
  23. package/esm/utils/getArticulationState.js +82 -0
  24. package/esm/utils/getArticulationState.js.map +1 -0
  25. package/hooks/useMultimode.d.ts +49 -0
  26. package/hooks/useMultimode.js +84 -0
  27. package/hooks/useMultimode.js.map +1 -0
  28. package/index.d.ts +1 -0
  29. package/index.js +3 -1
  30. package/index.js.map +1 -1
  31. package/package.json +18 -1
  32. package/src/components/Roundabout/Roundabout.tsx +8 -3
  33. package/src/hooks/useMultimode.ts +102 -0
  34. package/src/index.ts +1 -0
  35. package/src/stories/behaviour/articulation/articulation.stories.tsx +90 -0
  36. package/src/stories/behaviour/articulation/multimode.stories.tsx +19 -0
  37. package/src/stories/behaviour/articulation/roundabout.json +413 -0
  38. package/src/stories/utils/Orchestrator.tsx +3 -0
  39. package/src/stories/utils/OrchestratorSidebar.tsx +25 -1
  40. package/src/type.source.ts +33 -2
  41. package/src/use-lunatic/reducer/reduce-go-next-page.ts +2 -1
  42. package/src/use-lunatic/reducer/reducerInitializer.tsx +40 -29
  43. package/src/use-lunatic/type.ts +2 -0
  44. package/src/use-lunatic/use-lunatic.ts +4 -0
  45. package/src/utils/getArticulationState.ts +124 -0
  46. package/tsconfig.build.tsbuildinfo +1 -1
  47. package/type.source.d.ts +33 -1
  48. package/type.source.js +0 -1
  49. package/type.source.js.map +1 -1
  50. package/use-lunatic/reducer/reduce-go-next-page.js +2 -1
  51. package/use-lunatic/reducer/reduce-go-next-page.js.map +1 -1
  52. package/use-lunatic/reducer/reducerInitializer.d.ts +2 -2
  53. package/use-lunatic/reducer/reducerInitializer.js +31 -24
  54. package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  55. package/use-lunatic/type.d.ts +2 -0
  56. package/use-lunatic/use-lunatic.js +3 -0
  57. package/use-lunatic/use-lunatic.js.map +1 -1
  58. package/utils/getArticulationState.d.ts +64 -0
  59. package/utils/getArticulationState.js +84 -0
  60. package/utils/getArticulationState.js.map +1 -0
@@ -0,0 +1,413 @@
1
+ {
2
+ "$schema": "../../../../lunatic-schema.json",
3
+ "maxPage": "4",
4
+ "articulation": {
5
+ "source": "roundabout",
6
+ "items": [
7
+ {
8
+ "label": "Prénom",
9
+ "value": "PRENOMS"
10
+ },
11
+ {
12
+ "label": "Sexe",
13
+ "value": "if SEXE = \"H\" then \"Homme\" else \"Femme\""
14
+ },
15
+ {
16
+ "label": "Age",
17
+ "value": "cast(AGE, string) || \" ans\""
18
+ }
19
+ ]
20
+ },
21
+ "multimode": {
22
+ "questionnaire": {
23
+ "rules": {
24
+ "IS_MOVED": {
25
+ "type": "VTL",
26
+ "value": "nvl(LIVE_HERE, false) = false"
27
+ }
28
+ }
29
+ },
30
+ "leaf": {
31
+ "source": "roundabout",
32
+ "rules": {
33
+ "IS_MOVED": {
34
+ "type": "VTL",
35
+ "value": "nvl(PRENOM_LIVE_HERE, false) = false"
36
+ }
37
+ }
38
+ }
39
+ },
40
+ "components": [
41
+ {
42
+ "id": "live",
43
+ "componentType": "CheckboxBoolean",
44
+ "mandatory": false,
45
+ "page": "1",
46
+ "label": {
47
+ "value": "Vous vivez encore dans ce logement ?",
48
+ "type": "TXT"
49
+ },
50
+ "conditionFilter": { "value": "true", "type": "VTL" },
51
+ "response": { "name": "LIVE_HERE" }
52
+ },
53
+ {
54
+ "id": "how",
55
+ "componentType": "InputNumber",
56
+ "mandatory": false,
57
+ "page": "2",
58
+ "min": 1,
59
+ "max": 10,
60
+ "decimals": 0,
61
+ "label": {
62
+ "value": "\"Combien de personnes vivent habituellement à votre adresse ?\"",
63
+ "type": "VTL|MD"
64
+ },
65
+ "conditionFilter": { "value": "true", "type": "VTL" },
66
+ "response": { "name": "NB_HAB" }
67
+ },
68
+ {
69
+ "id": "loop",
70
+ "componentType": "Loop",
71
+ "page": "3",
72
+ "depth": 1,
73
+ "paginatedLoop": false,
74
+ "conditionFilter": { "value": "true", "type": "VTL" },
75
+ "loopDependencies": ["NHAB"],
76
+ "lines": {
77
+ "min": { "value": "NB_HAB", "type": "VTL" },
78
+ "max": { "value": "NB_HAB", "type": "VTL" }
79
+ },
80
+ "components": [
81
+ {
82
+ "id": "prenom",
83
+ "componentType": "Input",
84
+ "mandatory": false,
85
+ "maxLength": 20,
86
+ "label": {
87
+ "value": "\"Prénom\"))",
88
+ "type": "VTL|MD"
89
+ },
90
+ "conditionFilter": {
91
+ "value": "true",
92
+ "type": "VTL"
93
+ },
94
+ "response": { "name": "PRENOMS" }
95
+ },
96
+ {
97
+ "id": "sexe",
98
+ "componentType": "CheckboxOne",
99
+ "mandatory": false,
100
+ "maxLength": 20,
101
+ "label": {
102
+ "value": "\"Sexe\"",
103
+ "type": "VTL|MD"
104
+ },
105
+ "conditionFilter": {
106
+ "value": "true",
107
+ "type": "VTL"
108
+ },
109
+ "options": [
110
+ {
111
+ "value": "H",
112
+ "label": { "value": "\"Homme\"", "type": "VTL|MD" }
113
+ },
114
+
115
+ {
116
+ "value": "F",
117
+ "label": { "value": "\"Femme\"", "type": "VTL|MD" }
118
+ }
119
+ ],
120
+ "response": { "name": "SEXE" }
121
+ },
122
+ {
123
+ "id": "age",
124
+ "componentType": "InputNumber",
125
+ "maxLength": 3,
126
+ "label": {
127
+ "value": "\"Age\"",
128
+ "type": "VTL|MD"
129
+ },
130
+ "conditionFilter": {
131
+ "value": "true",
132
+ "type": "VTL"
133
+ },
134
+ "response": { "name": "AGE" }
135
+ },
136
+ {
137
+ "id": "live",
138
+ "componentType": "CheckboxBoolean",
139
+ "mandatory": false,
140
+ "page": "1",
141
+ "label": {
142
+ "value": "Vous vivez encore dans ce logement ?",
143
+ "type": "TXT"
144
+ },
145
+ "conditionFilter": { "value": "true", "type": "VTL" },
146
+ "response": { "name": "PRENOM_LIVE_HERE" }
147
+ }
148
+ ]
149
+ },
150
+ {
151
+ "id": "roundabout",
152
+ "componentType": "Roundabout",
153
+ "page": "4",
154
+ "conditionFilter": { "value": "true", "type": "VTL" },
155
+ "iterations": { "value": "NB_HAB", "type": "VTL" },
156
+ "label": { "value": "\"Libellé du rondpoint\"", "type": "VTL" },
157
+ "locked": true,
158
+ "progressVariable": "PROGRESS",
159
+ "item": {
160
+ "label": {
161
+ "value": "\"Questions de \" || PRENOMS",
162
+ "type": "VTL"
163
+ },
164
+ "description": {
165
+ "value": "if AGE > 18 then \"Aller aux question destinées à \" || PRENOMS else PRENOMS || \" n'est pas majeur, il/elle n'a pas à répondre aux questions\"",
166
+ "type": "VTL"
167
+ },
168
+ "disabled": {
169
+ "value": "AGE < 18",
170
+ "type": "VTL"
171
+ }
172
+ },
173
+ "controls": [],
174
+ "components": [
175
+ {
176
+ "id": "radio",
177
+ "componentType": "Radio",
178
+ "mandatory": false,
179
+ "page": "4.1",
180
+ "label": {
181
+ "value": "\"Connaissez-vous le recensement de la population ?\"",
182
+ "type": "VTL|MD"
183
+ },
184
+
185
+ "conditionFilter": { "value": "true", "type": "VTL" },
186
+
187
+ "options": [
188
+ { "value": "1", "label": { "value": "\"oui\"", "type": "VTL|MD" } },
189
+
190
+ { "value": "2", "label": { "value": "\"non\"", "type": "VTL|MD" } }
191
+ ],
192
+ "response": { "name": "KNOWREC" }
193
+ },
194
+ {
195
+ "id": "jsygk7m7",
196
+ "componentType": "Subsequence",
197
+ "page": "4.2",
198
+ "label": {
199
+ "value": "\"Deuxième page de questions pour \"|| PRENOMS",
200
+ "type": "VTL|MD"
201
+ },
202
+ "conditionFilter": { "value": "true", "type": "VTL" }
203
+ },
204
+ {
205
+ "id": "sexe",
206
+ "componentType": "Radio",
207
+ "page": "4.2",
208
+ "label": {
209
+ "value": "\"Sexe\"",
210
+ "type": "VTL"
211
+ },
212
+ "conditionFilter": {
213
+ "value": "true",
214
+ "type": "VTL"
215
+ },
216
+ "options": [
217
+ {
218
+ "value": "1",
219
+ "label": { "value": "\"Homme\"", "type": "VTL|MD" }
220
+ },
221
+ {
222
+ "value": "2",
223
+ "label": { "value": "\"Femme\"", "type": "VTL|MD" }
224
+ }
225
+ ],
226
+ "response": { "name": "SEXE" }
227
+ },
228
+ {
229
+ "id": "jsygk7m7",
230
+ "componentType": "Subsequence",
231
+ "page": "4.3",
232
+ "label": {
233
+ "value": "\"Troisième page de questions \" || PRENOMS",
234
+ "type": "VTL|MD"
235
+ },
236
+ "conditionFilter": { "value": "true", "type": "VTL" }
237
+ },
238
+ {
239
+ "id": "kmno1n7m",
240
+ "componentType": "Input",
241
+ "maxLength": 30,
242
+ "page": "4.3",
243
+ "label": {
244
+ "value": "\"Dites quelque chose.\"))",
245
+ "type": "VTL|MD"
246
+ },
247
+ "conditionFilter": {
248
+ "value": "true",
249
+ "type": "VTL"
250
+ },
251
+ "response": { "name": "SOMETHING" }
252
+ }
253
+ ]
254
+ },
255
+ {
256
+ "id": "seq",
257
+ "componentType": "Sequence",
258
+ "label": {
259
+ "value": "\"Merci !\"",
260
+ "type": "VTL|MD"
261
+ },
262
+ "conditionFilter": { "value": "true", "type": "VTL" },
263
+ "page": "5"
264
+ }
265
+ ],
266
+ "variables": [
267
+ {
268
+ "variableType": "COLLECTED",
269
+ "name": "NB_HAB",
270
+ "values": {
271
+ "PREVIOUS": null,
272
+ "COLLECTED": 2,
273
+ "FORCED": null,
274
+ "EDITED": null,
275
+ "INPUTTED": null
276
+ }
277
+ },
278
+ {
279
+ "variableType": "COLLECTED",
280
+ "name": "LIVE_HERE",
281
+ "values": {
282
+ "PREVIOUS": null,
283
+ "COLLECTED": true,
284
+ "FORCED": null,
285
+ "EDITED": null,
286
+ "INPUTTED": null
287
+ }
288
+ },
289
+ {
290
+ "variableType": "COLLECTED",
291
+ "name": "PRENOM_LIVE_HERE",
292
+ "values": {
293
+ "PREVIOUS": null,
294
+ "COLLECTED": [true, true],
295
+ "FORCED": null,
296
+ "EDITED": null,
297
+ "INPUTTED": null
298
+ }
299
+ },
300
+ {
301
+ "variableType": "COLLECTED",
302
+ "name": "SOMETHING",
303
+ "values": {
304
+ "PREVIOUS": [],
305
+ "COLLECTED": [],
306
+ "FORCED": [],
307
+ "EDITED": [],
308
+ "INPUTTED": []
309
+ }
310
+ },
311
+ {
312
+ "variableType": "COLLECTED",
313
+ "name": "SEXE",
314
+ "values": {
315
+ "PREVIOUS": null,
316
+ "COLLECTED": ["H", "F"],
317
+ "FORCED": null,
318
+ "EDITED": null,
319
+ "INPUTTED": null
320
+ }
321
+ },
322
+ {
323
+ "variableType": "COLLECTED",
324
+ "name": "AGE",
325
+ "values": {
326
+ "PREVIOUS": null,
327
+ "COLLECTED": [24, 24],
328
+ "FORCED": null,
329
+ "EDITED": null,
330
+ "INPUTTED": null
331
+ }
332
+ },
333
+ {
334
+ "variableType": "COLLECTED",
335
+ "name": "SEXE",
336
+ "values": {
337
+ "PREVIOUS": [],
338
+ "COLLECTED": [],
339
+ "FORCED": [],
340
+ "EDITED": [],
341
+ "INPUTTED": []
342
+ }
343
+ },
344
+ {
345
+ "variableType": "COLLECTED",
346
+ "name": "PRENOMS",
347
+ "values": {
348
+ "PREVIOUS": null,
349
+ "COLLECTED": ["Fanny", "Ines"],
350
+ "FORCED": null,
351
+ "EDITED": null,
352
+ "INPUTTED": null
353
+ }
354
+ },
355
+ {
356
+ "variableType": "COLLECTED",
357
+ "name": "KNOWREC",
358
+ "values": {
359
+ "PREVIOUS": [],
360
+ "COLLECTED": [],
361
+ "FORCED": [],
362
+ "EDITED": [],
363
+ "INPUTTED": []
364
+ }
365
+ },
366
+ {
367
+ "variableType": "COLLECTED",
368
+ "name": "PROGRESS",
369
+ "values": {
370
+ "PREVIOUS": [],
371
+ "COLLECTED": [0, -1],
372
+ "FORCED": [],
373
+ "EDITED": [],
374
+ "INPUTTED": []
375
+ }
376
+ },
377
+ {
378
+ "variableType": "CALCULATED",
379
+ "name": "PRENOMREF",
380
+ "expression": { "value": "first_value(PRENOMS over())", "type": "VTL" },
381
+ "bindingDependencies": ["PRENOMS"],
382
+ "inFilter": "true"
383
+ },
384
+ {
385
+ "variableType": "CALCULATED",
386
+ "name": "COMPLETE",
387
+ "expression": {
388
+ "value": "not(isnull(KNOWREC)) and not(isnull(SEXE)) and not(isnull(SOMETHING))",
389
+ "type": "VTL"
390
+ },
391
+ "bindingDependencies": ["KNOWREC", "SEXE", "SOMETHING"],
392
+ "shapeFrom": "PRENOMS",
393
+ "inFilter": "true"
394
+ },
395
+ {
396
+ "variableType": "CALCULATED",
397
+ "name": "PARTIAL",
398
+ "expression": {
399
+ "value": "not(isnull(KNOWREC)) or not(isnull(SEXE)) or not(isnull(SOMETHING))",
400
+ "type": "VTL"
401
+ },
402
+ "bindingDependencies": ["KNOWREC", "SEXE", "SOMETHING"],
403
+ "shapeFrom": "PRENOMS",
404
+ "inFilter": "true"
405
+ }
406
+ ],
407
+ "resizing": {
408
+ "NB_HAB": {
409
+ "size": "NB_HAB",
410
+ "variables": ["PRENOMS", "AGE", "SEXE", "SOMETHING", "DATNAIS"]
411
+ }
412
+ }
413
+ }
@@ -55,6 +55,7 @@ type Props = {
55
55
  showOverview?: boolean;
56
56
  disabled?: boolean;
57
57
  extraTabs?: TabEntry[];
58
+ multiMode: boolean;
58
59
  };
59
60
 
60
61
  type TabEntry = { label: ReactNode; children: ReactNode };
@@ -97,6 +98,7 @@ function OrchestratorForStories(props: Readonly<Props>) {
97
98
  getData,
98
99
  Provider,
99
100
  hasPageResponse,
101
+ getMultimode,
100
102
  } = useLunatic(source, data, {
101
103
  initialPage,
102
104
  disableFilters,
@@ -247,6 +249,7 @@ function OrchestratorForStories(props: Readonly<Props>) {
247
249
  pageTag={pageTag}
248
250
  pager={pager}
249
251
  hasPageResponse={hasPageResponse()}
252
+ getMultimode={props.multiMode ? getMultimode : null}
250
253
  onLogData={() => console.log('Data', getData(true))}
251
254
  onLogComponents={() => console.log('Components', components)}
252
255
  >
@@ -1,6 +1,7 @@
1
1
  import type { useLunatic } from '../../use-lunatic/use-lunatic';
2
2
  import { objectKeys } from '../../utils/object';
3
- import type { PropsWithChildren } from 'react';
3
+ import { type PropsWithChildren, useState } from 'react';
4
+ import type { LunaticState } from '../../use-lunatic/type';
4
5
 
5
6
  type Props = PropsWithChildren<
6
7
  Pick<
@@ -16,6 +17,7 @@ type Props = PropsWithChildren<
16
17
  > & {
17
18
  hasPageResponse: unknown;
18
19
  onLogData: () => void;
20
+ getMultimode: LunaticState['getMultimode'] | null;
19
21
  onLogComponents: () => void;
20
22
  };
21
23
 
@@ -28,6 +30,7 @@ export function OrchestratorSidebar({
28
30
  pageTag,
29
31
  pager,
30
32
  children,
33
+ getMultimode,
31
34
  hasPageResponse,
32
35
  onLogData,
33
36
  onLogComponents,
@@ -113,7 +116,28 @@ export function OrchestratorSidebar({
113
116
  </li>
114
117
  </ul>
115
118
  </div>
119
+ {getMultimode && (
120
+ <div>
121
+ <MultiMode getMultimode={getMultimode} />
122
+ </div>
123
+ )}
116
124
  {children}
117
125
  </aside>
118
126
  );
119
127
  }
128
+
129
+ function MultiMode(props: Pick<LunaticState, 'getMultimode'>) {
130
+ const [state, setState] = useState<ReturnType<typeof props.getMultimode>>({});
131
+ const onClick = () => {
132
+ setState(props.getMultimode);
133
+ };
134
+ return (
135
+ <div className="space-y-2">
136
+ <h3 className="text-lg font-bold mb-2">Multimode</h3>
137
+ <pre>{JSON.stringify(state, null, 2)}</pre>
138
+ <button className="btn" onClick={onClick}>
139
+ Voir multimode
140
+ </button>
141
+ </div>
142
+ );
143
+ }
@@ -1,4 +1,3 @@
1
- /* eslint-disable */
2
1
  /**
3
2
  * This file was automatically generated by json-schema-to-typescript.
4
3
  * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
@@ -265,7 +264,7 @@ export type Variable =
265
264
  dimension?: number;
266
265
  };
267
266
  export type VariableValue = VariableScalarValue | unknown[];
268
- export type VariableScalarValue = string | number | null;
267
+ export type VariableScalarValue = string | number | null | boolean;
269
268
 
270
269
  /**
271
270
  * Representation of a Lunatic questionnaire.
@@ -329,6 +328,38 @@ export type LunaticSource = {
329
328
  };
330
329
  };
331
330
  maxPage?: string;
331
+ articulation?: {
332
+ /**
333
+ * id du composant roundabout
334
+ */
335
+ source: string;
336
+ /**
337
+ * Ligne du tableau d'articulation
338
+ */
339
+ items: {
340
+ /**
341
+ * Libellé du champs
342
+ */
343
+ label: string;
344
+ /**
345
+ * Expression VTL
346
+ */
347
+ value: string;
348
+ }[];
349
+ };
350
+ multimode?: {
351
+ questionnaire: {
352
+ rules: {
353
+ [k: string]: VTLExpression;
354
+ };
355
+ };
356
+ leaf: {
357
+ source: string;
358
+ rules: {
359
+ [k: string]: VTLExpression;
360
+ };
361
+ };
362
+ };
332
363
  };
333
364
  export type VTLExpression = {
334
365
  /**
@@ -5,6 +5,7 @@ import type { LunaticReducerState } from '../type';
5
5
  import { autoExploreLoop } from './commons/auto-explore-loop';
6
6
  import { reduceHandleChanges } from './reduce-handle-changes';
7
7
  import { ActionKind } from '../actions';
8
+ import { ArticulationState } from '../../utils/getArticulationState';
8
9
 
9
10
  export function reduceGoNextPage(
10
11
  state: LunaticReducerState
@@ -51,7 +52,7 @@ export function reduceGoNextPage(
51
52
  responses: [
52
53
  {
53
54
  name: firstComponent.progressVariable,
54
- value: 1,
55
+ value: ArticulationState.COMPLETED,
55
56
  iteration: [newState.previousPager.iteration],
56
57
  },
57
58
  ],
@@ -38,6 +38,8 @@ const baseState = {
38
38
  options: { disableFilters: false, disableFiltersDescription: true },
39
39
  } satisfies LunaticReducerState;
40
40
 
41
+ const onChange = { current: () => {} };
42
+
41
43
  export function reducerInitializer({
42
44
  source,
43
45
  data,
@@ -48,8 +50,8 @@ export function reducerInitializer({
48
50
  disableFilters = false,
49
51
  disableFiltersDescription = true,
50
52
  getReferentiel,
51
- onVariableChange,
52
- logger,
53
+ onVariableChange = onChange,
54
+ logger = console.error,
53
55
  }: {
54
56
  source: LunaticSource;
55
57
  data: LunaticData;
@@ -60,8 +62,8 @@ export function reducerInitializer({
60
62
  disableFilters?: LunaticOptions['disableFilters'];
61
63
  disableFiltersDescription?: LunaticOptions['disableFiltersDescription'];
62
64
  getReferentiel?: LunaticOptions['getReferentiel'];
63
- onVariableChange: RefObject<LunaticOptions['onVariableChange']>;
64
- logger: LunaticLogger;
65
+ onVariableChange?: RefObject<LunaticOptions['onVariableChange']>;
66
+ logger?: LunaticLogger;
65
67
  }): LunaticReducerState {
66
68
  const variables = LunaticVariablesStore.makeFromSource(
67
69
  source,
@@ -114,11 +116,13 @@ export function reducerInitializer({
114
116
  }
115
117
  return result as any;
116
118
  } catch (e) {
117
- // If there is an error interpreting a variable, return the raw expression
118
- logger({
119
- type: 'ERROR',
120
- error: e as Error,
121
- });
119
+ if (logger) {
120
+ // If there is an error interpreting a variable, return the raw expression
121
+ logger({
122
+ type: 'ERROR',
123
+ error: e as Error,
124
+ });
125
+ }
122
126
  return expressionString;
123
127
  }
124
128
  };
@@ -135,9 +139,9 @@ export function reducerInitializer({
135
139
  const pager = {
136
140
  page: initialPager?.page ?? 1,
137
141
  maxPage: source.maxPage ? parseInt(source.maxPage, 10) : 1,
138
- subPage: undefined,
142
+ subPage: initialPager?.subPage,
139
143
  nbSubPages: undefined,
140
- iteration: undefined,
144
+ iteration: initialPager?.iteration,
141
145
  nbIterations: undefined,
142
146
  lastReachedPage: lastReachedPage ?? initialPage,
143
147
  };
@@ -147,7 +151,7 @@ export function reducerInitializer({
147
151
  pager,
148
152
  previousPager: pager,
149
153
  pages,
150
- isInLoop: false,
154
+ isInLoop: pager.subPage !== undefined,
151
155
  updatedAt: Date.now(),
152
156
  overview: withOverview ? buildOverview(source) : [],
153
157
  updateBindings,
@@ -165,22 +169,29 @@ function fillPagerForLoop(state: LunaticReducerState): LunaticReducerState {
165
169
  return state;
166
170
  }
167
171
  const { isLoop, subPages, iterations, loopDependencies } = pages[pager.page];
168
- if (!isLoop) {
169
- return state;
172
+
173
+ if (
174
+ // For loop, jump at the first page
175
+ isLoop ||
176
+ // For roundabout, jump at the desired iteration / subpage (only if defined)
177
+ (pager?.iteration !== undefined && subPages)
178
+ ) {
179
+ return {
180
+ ...state,
181
+ isInLoop: true,
182
+ pager: {
183
+ ...pager,
184
+ subPage: pager?.subPage ?? 1,
185
+ nbSubPages: (subPages ?? []).length,
186
+ iteration: pager?.iteration ?? 0,
187
+ nbIterations: forceInt(
188
+ state.executeExpression(iterations, {
189
+ deps: loopDependencies,
190
+ })
191
+ ),
192
+ },
193
+ };
170
194
  }
171
- return {
172
- ...state,
173
- isInLoop: true,
174
- pager: {
175
- ...pager,
176
- subPage: pager?.subPage ?? 0,
177
- nbSubPages: (subPages ?? []).length,
178
- iteration: pager?.iteration ?? 0,
179
- nbIterations: forceInt(
180
- state.executeExpression(iterations, {
181
- deps: loopDependencies,
182
- })
183
- ),
184
- },
185
- };
195
+
196
+ return state;
186
197
  }
@@ -358,6 +358,8 @@ export type LunaticState = {
358
358
  * ])
359
359
  */
360
360
  handleChanges: LunaticChangesHandler;
361
+ /** Return the multimode state **/
362
+ getMultimode: () => Record<string, boolean>;
361
363
  };
362
364
 
363
365
  /** Function taking as arguments the various changes the user has made. */