@inseefr/lunatic 3.4.10 → 3.5.0-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.
Files changed (27) hide show
  1. package/esm/hooks/useArticulation.d.ts +58 -0
  2. package/esm/hooks/useArticulation.js +81 -0
  3. package/esm/hooks/useArticulation.js.map +1 -0
  4. package/esm/use-lunatic/commons/variables/lunatic-variables-store.js +1 -1
  5. package/esm/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
  6. package/esm/use-lunatic/reducer/reducerInitializer.d.ts +2 -2
  7. package/esm/use-lunatic/reducer/reducerInitializer.js +31 -24
  8. package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  9. package/hooks/useArticulation.d.ts +58 -0
  10. package/hooks/useArticulation.js +81 -0
  11. package/hooks/useArticulation.js.map +1 -0
  12. package/package.json +13 -4
  13. package/src/hooks/useArticulation.ts +124 -0
  14. package/src/stories/behaviour/articulation/articulation.stories.tsx +105 -0
  15. package/src/stories/behaviour/articulation/roundabout.json +348 -0
  16. package/src/stories/behaviour/performance/performance.stories.jsx +1 -1
  17. package/src/stories/utils/{SchemaValidator.jsx → SchemaValidator.tsx} +1 -1
  18. package/src/stories/utils/{orchestrator.jsx → orchestrator.tsx} +13 -9
  19. package/src/stories/utils/{overview.jsx → overview.tsx} +2 -0
  20. package/src/use-lunatic/commons/variables/lunatic-variables-store.ts +1 -1
  21. package/src/use-lunatic/reducer/reducerInitializer.tsx +40 -29
  22. package/tsconfig.build.tsbuildinfo +1 -1
  23. package/use-lunatic/commons/variables/lunatic-variables-store.js +1 -1
  24. package/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
  25. package/use-lunatic/reducer/reducerInitializer.d.ts +2 -2
  26. package/use-lunatic/reducer/reducerInitializer.js +31 -24
  27. package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
@@ -0,0 +1,124 @@
1
+ import type {
2
+ ComponentDefinition,
3
+ ComponentRoundaboutDefinition,
4
+ LunaticSource,
5
+ } from '../type.source';
6
+ import type { LunaticData } from '../use-lunatic/type';
7
+ import { reducerInitializer } from '../use-lunatic/reducer/reducerInitializer';
8
+ import { type ReactNode, useMemo } from 'react';
9
+ import { times } from '../utils/array';
10
+ import { forceInt } from '../utils/number';
11
+
12
+ type ArticulationItem = {
13
+ label: string;
14
+ value: string;
15
+ };
16
+
17
+ type Articulation = {
18
+ source: string;
19
+ items: ArticulationItem[];
20
+ };
21
+
22
+ type Item = {
23
+ cells: {
24
+ label: string;
25
+ value: ReactNode;
26
+ page?: string;
27
+ }[];
28
+ progress: number; // -1: not completed, 0: started, 1: finished
29
+ };
30
+
31
+ /**
32
+ * Hook to get articulation state
33
+ *
34
+ * ## Why this hook
35
+ *
36
+ * The goal of this hook is to provide insights about a roundabout using extra information inserted in the JSON source
37
+ * provided to Lunatic.
38
+ *
39
+ * For instance
40
+ *
41
+ * ```
42
+ * "articulation": {
43
+ * "source": "roundabout",
44
+ * "items": [
45
+ * {
46
+ * "label": "Prénom",
47
+ * "value": "PRENOMS"
48
+ * },
49
+ * {
50
+ * "label": "Sexe",
51
+ * "value": "if SEXE = \"H\" then \"Homme\" else \"Femme\""
52
+ * },
53
+ * {
54
+ * "label": "Age",
55
+ * "value": "cast(AGE, string) || \" ans\""
56
+ * }
57
+ * ]
58
+ * },
59
+ * ```
60
+ *
61
+ * - source is the ID of the roundabout component
62
+ * - items define the field to extract from the roundabout data
63
+ */
64
+ export function useArticulation(
65
+ source: LunaticSource & { articulation: Articulation },
66
+ data: LunaticData
67
+ ): { items: Item[] } {
68
+ const roundabout = useMemo(
69
+ () => findComponentById(source.components, source.articulation.source),
70
+ [source]
71
+ );
72
+ const { variables } = useMemo(
73
+ () => reducerInitializer({ source, data }),
74
+ [source, data]
75
+ );
76
+
77
+ const iterations = useMemo(
78
+ () => forceInt(variables.run(roundabout?.iterations.value ?? '0')),
79
+ // eslint-disable-next-line react-hooks/exhaustive-deps
80
+ [source, data]
81
+ );
82
+
83
+ const rows = useMemo(() => {
84
+ return times(iterations, (k) =>
85
+ source.articulation.items.map((item) => ({
86
+ label: item.label,
87
+ value: variables.run(item.value, { iteration: [k] }) as ReactNode,
88
+ }))
89
+ );
90
+ // eslint-disable-next-line react-hooks/exhaustive-deps
91
+ }, [source, data, iterations, roundabout?.progressVariable]);
92
+
93
+ if (!roundabout) {
94
+ return {
95
+ items: [],
96
+ };
97
+ }
98
+
99
+ return {
100
+ items: rows.map((row, k) => ({
101
+ cells: row,
102
+ progress: forceInt(variables.get(roundabout.progressVariable, [k]) ?? -1),
103
+ page: roundabout.page ? `${roundabout.page}.1#${k + 1}` : '1',
104
+ })),
105
+ };
106
+ }
107
+
108
+ function findComponentById(
109
+ components: ComponentDefinition[],
110
+ id: string
111
+ ): (ComponentRoundaboutDefinition & { page?: string }) | null {
112
+ for (const c of components) {
113
+ if ('id' in c && c.id === id && c.componentType === 'Roundabout') {
114
+ return c;
115
+ }
116
+ if ('components' in c) {
117
+ const child = findComponentById(c.components, id);
118
+ if (child) {
119
+ return child;
120
+ }
121
+ }
122
+ }
123
+ return null;
124
+ }
@@ -0,0 +1,105 @@
1
+ import Orchestrator from '../../utils/orchestrator';
2
+ import source from './roundabout.json';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { useState } from 'react';
5
+ import { useArticulation } from '../../../hooks/useArticulation';
6
+
7
+ type Source = Parameters<typeof useArticulation>[0];
8
+ type Data = Parameters<typeof useArticulation>[1];
9
+
10
+ type Props = {
11
+ source: Source;
12
+ data: Data;
13
+ };
14
+
15
+ function StoryComponent({ source, data }: Props) {
16
+ const [page, setPage] = useState(null as null | string);
17
+ const gotoNav = () => setPage(null);
18
+ const { items } = useArticulation(source, data);
19
+
20
+ if (page) {
21
+ return (
22
+ <div>
23
+ {page}
24
+ <button onClick={gotoNav}>&lt; Revenir à l'articulation</button>
25
+ {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
26
+ {/*/ @ts-ignore */}
27
+ <Orchestrator source={source} data={data} initialPage={page} />
28
+ </div>
29
+ );
30
+ }
31
+
32
+ const progressLabel = (n: number) => {
33
+ if (n === -1) {
34
+ return 'Commencer';
35
+ }
36
+ if (n === 0) {
37
+ return 'Continuer';
38
+ }
39
+ return 'Complété';
40
+ };
41
+
42
+ return (
43
+ <div>
44
+ <h2>Articulation</h2>
45
+ <table style={{ borderCollapse: 'collapse' }}>
46
+ <thead>
47
+ <tr>
48
+ {items[0].cells.map((cell, k) => (
49
+ <th
50
+ style={{ border: 'solid 1px #00000024', padding: '.5rem 1rem' }}
51
+ key={k}
52
+ >
53
+ {cell.label}
54
+ </th>
55
+ ))}
56
+ <th>Actions</th>
57
+ </tr>
58
+ </thead>
59
+ <tbody>
60
+ {items.map((item, k) => (
61
+ <tr key={k}>
62
+ {item.cells.map((cell, kk) => (
63
+ <td
64
+ key={kk}
65
+ style={{
66
+ border: 'solid 1px #00000024',
67
+ padding: '.5rem 1rem',
68
+ }}
69
+ >
70
+ {cell.value}
71
+ </td>
72
+ ))}
73
+ <td
74
+ style={{
75
+ border: 'solid 1px #00000024',
76
+ padding: '.5rem 1rem',
77
+ }}
78
+ >
79
+ <button onClick={() => console.log('ToDo')}>
80
+ {progressLabel(item.progress)}
81
+ </button>
82
+ </td>
83
+ </tr>
84
+ ))}
85
+ </tbody>
86
+ </table>
87
+ </div>
88
+ );
89
+ }
90
+
91
+ const meta: Meta<typeof StoryComponent> = {
92
+ title: 'Behaviour/Articulation',
93
+ component: StoryComponent,
94
+ };
95
+
96
+ export default meta;
97
+
98
+ type Story = StoryObj<typeof StoryComponent>;
99
+
100
+ export const Basic: Story = {
101
+ args: {
102
+ source: source as Source,
103
+ data: {},
104
+ },
105
+ };
@@ -0,0 +1,348 @@
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
+ "components": [
22
+ {
23
+ "id": "how",
24
+ "componentType": "InputNumber",
25
+ "mandatory": false,
26
+ "page": "1",
27
+ "min": 1,
28
+ "max": 10,
29
+ "decimals": 0,
30
+ "label": {
31
+ "value": "\"Combien de personnes vivent habituellement à votre adresse ?\"",
32
+ "type": "VTL|MD"
33
+ },
34
+ "conditionFilter": { "value": "true", "type": "VTL" },
35
+ "response": { "name": "NB_HAB" }
36
+ },
37
+ {
38
+ "id": "loop",
39
+ "componentType": "Loop",
40
+ "page": "2",
41
+ "depth": 1,
42
+ "paginatedLoop": false,
43
+ "conditionFilter": { "value": "true", "type": "VTL" },
44
+ "loopDependencies": ["NHAB"],
45
+ "lines": {
46
+ "min": { "value": "NB_HAB", "type": "VTL" },
47
+ "max": { "value": "NB_HAB", "type": "VTL" }
48
+ },
49
+ "components": [
50
+ {
51
+ "id": "prenom",
52
+ "componentType": "Input",
53
+ "mandatory": false,
54
+ "maxLength": 20,
55
+ "label": {
56
+ "value": "\"Prénom\"))",
57
+ "type": "VTL|MD"
58
+ },
59
+ "conditionFilter": {
60
+ "value": "true",
61
+ "type": "VTL"
62
+ },
63
+ "response": { "name": "PRENOMS" }
64
+ },
65
+ {
66
+ "id": "sexe",
67
+ "componentType": "CheckboxOne",
68
+ "mandatory": false,
69
+ "maxLength": 20,
70
+ "label": {
71
+ "value": "\"Sexe\"",
72
+ "type": "VTL|MD"
73
+ },
74
+ "conditionFilter": {
75
+ "value": "true",
76
+ "type": "VTL"
77
+ },
78
+ "options": [
79
+ {
80
+ "value": "H",
81
+ "label": { "value": "\"Homme\"", "type": "VTL|MD" }
82
+ },
83
+
84
+ {
85
+ "value": "F",
86
+ "label": { "value": "\"Femme\"", "type": "VTL|MD" }
87
+ }
88
+ ],
89
+ "response": { "name": "SEXE" }
90
+ },
91
+ {
92
+ "id": "age",
93
+ "componentType": "InputNumber",
94
+ "maxLength": 3,
95
+ "label": {
96
+ "value": "\"Age\"",
97
+ "type": "VTL|MD"
98
+ },
99
+ "conditionFilter": {
100
+ "value": "true",
101
+ "type": "VTL"
102
+ },
103
+ "response": { "name": "AGE" }
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ "id": "roundabout",
109
+ "componentType": "Roundabout",
110
+ "page": "3",
111
+ "conditionFilter": { "value": "true", "type": "VTL" },
112
+ "iterations": { "value": "NB_HAB", "type": "VTL" },
113
+ "label": { "value": "\"Libellé du rondpoint\"", "type": "VTL" },
114
+ "locked": true,
115
+ "progressVariable": "PROGRESS",
116
+ "item": {
117
+ "label": {
118
+ "value": "\"Questions de \" || PRENOMS",
119
+ "type": "VTL"
120
+ },
121
+ "description": {
122
+ "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\"",
123
+ "type": "VTL"
124
+ },
125
+ "disabled": {
126
+ "value": "AGE < 18",
127
+ "type": "VTL"
128
+ }
129
+ },
130
+ "controls": [],
131
+ "components": [
132
+ {
133
+ "id": "radio",
134
+ "componentType": "Radio",
135
+ "mandatory": false,
136
+ "page": "3.1",
137
+ "label": {
138
+ "value": "\"Connaissez-vous le recensement de la population ?\"",
139
+ "type": "VTL|MD"
140
+ },
141
+
142
+ "conditionFilter": { "value": "true", "type": "VTL" },
143
+
144
+ "options": [
145
+ { "value": "1", "label": { "value": "\"oui\"", "type": "VTL|MD" } },
146
+
147
+ { "value": "2", "label": { "value": "\"non\"", "type": "VTL|MD" } }
148
+ ],
149
+ "response": { "name": "KNOWREC" }
150
+ },
151
+ {
152
+ "id": "jsygk7m7",
153
+ "componentType": "Subsequence",
154
+ "page": "3.2",
155
+ "label": {
156
+ "value": "\"Deuxième page de questions pour \"|| PRENOMS",
157
+ "type": "VTL|MD"
158
+ },
159
+ "conditionFilter": { "value": "true", "type": "VTL" }
160
+ },
161
+ {
162
+ "id": "sexe",
163
+ "componentType": "Radio",
164
+ "page": "3.2",
165
+ "label": {
166
+ "value": "\"Sexe\"",
167
+ "type": "VTL"
168
+ },
169
+ "conditionFilter": {
170
+ "value": "true",
171
+ "type": "VTL"
172
+ },
173
+ "options": [
174
+ {
175
+ "value": "1",
176
+ "label": { "value": "\"Homme\"", "type": "VTL|MD" }
177
+ },
178
+ {
179
+ "value": "2",
180
+ "label": { "value": "\"Femme\"", "type": "VTL|MD" }
181
+ }
182
+ ],
183
+ "response": { "name": "SEXE" }
184
+ },
185
+ {
186
+ "id": "jsygk7m7",
187
+ "componentType": "Subsequence",
188
+ "page": "3.3",
189
+ "label": {
190
+ "value": "\"Troisième page de questions \" || PRENOMS",
191
+ "type": "VTL|MD"
192
+ },
193
+ "conditionFilter": { "value": "true", "type": "VTL" }
194
+ },
195
+ {
196
+ "id": "kmno1n7m",
197
+ "componentType": "Input",
198
+ "maxLength": 30,
199
+ "page": "3.3",
200
+ "label": {
201
+ "value": "\"Dites quelque chose.\"))",
202
+ "type": "VTL|MD"
203
+ },
204
+ "conditionFilter": {
205
+ "value": "true",
206
+ "type": "VTL"
207
+ },
208
+ "response": { "name": "SOMETHING" }
209
+ }
210
+ ]
211
+ },
212
+ {
213
+ "id": "seq",
214
+ "componentType": "Sequence",
215
+ "label": {
216
+ "value": "\"Merci !\"",
217
+ "type": "VTL|MD"
218
+ },
219
+ "conditionFilter": { "value": "true", "type": "VTL" },
220
+ "page": "4"
221
+ }
222
+ ],
223
+ "variables": [
224
+ {
225
+ "variableType": "COLLECTED",
226
+ "name": "NB_HAB",
227
+ "values": {
228
+ "PREVIOUS": null,
229
+ "COLLECTED": 2,
230
+ "FORCED": null,
231
+ "EDITED": null,
232
+ "INPUTTED": null
233
+ }
234
+ },
235
+ {
236
+ "variableType": "COLLECTED",
237
+ "name": "SOMETHING",
238
+ "values": {
239
+ "PREVIOUS": [],
240
+ "COLLECTED": [],
241
+ "FORCED": [],
242
+ "EDITED": [],
243
+ "INPUTTED": []
244
+ }
245
+ },
246
+ {
247
+ "variableType": "COLLECTED",
248
+ "name": "SEXE",
249
+ "values": {
250
+ "PREVIOUS": null,
251
+ "COLLECTED": ["H", "F"],
252
+ "FORCED": null,
253
+ "EDITED": null,
254
+ "INPUTTED": null
255
+ }
256
+ },
257
+ {
258
+ "variableType": "COLLECTED",
259
+ "name": "AGE",
260
+ "values": {
261
+ "PREVIOUS": null,
262
+ "COLLECTED": [24, 24],
263
+ "FORCED": null,
264
+ "EDITED": null,
265
+ "INPUTTED": null
266
+ }
267
+ },
268
+ {
269
+ "variableType": "COLLECTED",
270
+ "name": "SEXE",
271
+ "values": {
272
+ "PREVIOUS": [],
273
+ "COLLECTED": [],
274
+ "FORCED": [],
275
+ "EDITED": [],
276
+ "INPUTTED": []
277
+ }
278
+ },
279
+ {
280
+ "variableType": "COLLECTED",
281
+ "name": "PRENOMS",
282
+ "values": {
283
+ "PREVIOUS": null,
284
+ "COLLECTED": ["Fanny", "Ines"],
285
+ "FORCED": null,
286
+ "EDITED": null,
287
+ "INPUTTED": null
288
+ }
289
+ },
290
+ {
291
+ "variableType": "COLLECTED",
292
+ "name": "KNOWREC",
293
+ "values": {
294
+ "PREVIOUS": [],
295
+ "COLLECTED": [],
296
+ "FORCED": [],
297
+ "EDITED": [],
298
+ "INPUTTED": []
299
+ }
300
+ },
301
+ {
302
+ "variableType": "COLLECTED",
303
+ "name": "PROGRESS",
304
+ "values": {
305
+ "PREVIOUS": [],
306
+ "COLLECTED": [0, -1],
307
+ "FORCED": [],
308
+ "EDITED": [],
309
+ "INPUTTED": []
310
+ }
311
+ },
312
+ {
313
+ "variableType": "CALCULATED",
314
+ "name": "PRENOMREF",
315
+ "expression": { "value": "first_value(PRENOMS over())", "type": "VTL" },
316
+ "bindingDependencies": ["PRENOMS"],
317
+ "inFilter": "true"
318
+ },
319
+ {
320
+ "variableType": "CALCULATED",
321
+ "name": "COMPLETE",
322
+ "expression": {
323
+ "value": "not(isnull(KNOWREC)) and not(isnull(SEXE)) and not(isnull(SOMETHING))",
324
+ "type": "VTL"
325
+ },
326
+ "bindingDependencies": ["KNOWREC", "SEXE", "SOMETHING"],
327
+ "shapeFrom": "PRENOMS",
328
+ "inFilter": "true"
329
+ },
330
+ {
331
+ "variableType": "CALCULATED",
332
+ "name": "PARTIAL",
333
+ "expression": {
334
+ "value": "not(isnull(KNOWREC)) or not(isnull(SEXE)) or not(isnull(SOMETHING))",
335
+ "type": "VTL"
336
+ },
337
+ "bindingDependencies": ["KNOWREC", "SEXE", "SOMETHING"],
338
+ "shapeFrom": "PRENOMS",
339
+ "inFilter": "true"
340
+ }
341
+ ],
342
+ "resizing": {
343
+ "NB_HAB": {
344
+ "size": "NB_HAB",
345
+ "variables": ["PRENOMS", "AGE", "SEXE", "SOMETHING", "DATNAIS"]
346
+ }
347
+ }
348
+ }
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- import Orchestrator from '../../utils/orchestrator';
3
2
  import source from './source.json';
4
3
  import { generateData } from '../../../tests/utils/lunatic';
5
4
  import { times } from '../../../utils/array';
5
+ import Orchestrator from '../../utils/orchestrator';
6
6
 
7
7
  const stories = {
8
8
  title: 'Behaviour/Performance',
@@ -2,7 +2,7 @@ import Ajv from 'ajv/dist/2020.js';
2
2
  import { useMemo } from 'react';
3
3
  import LunaticSchema from '../../../lunatic-schema.json';
4
4
 
5
- export function SchemaValidator({ source }) {
5
+ export function SchemaValidator({ source }: { source: any }) {
6
6
  const errors = useMemo(() => {
7
7
  const ajv = new Ajv({
8
8
  removeAdditional: true,
@@ -1,3 +1,5 @@
1
+ /* eslint-disable */
2
+ // @ts-nocheck
1
3
  import './custom-lunatic.scss';
2
4
  import './orchestrator.scss';
3
5
 
@@ -7,19 +9,19 @@ import {
7
9
  LunaticComponents,
8
10
  ModalControls,
9
11
  useLunatic,
10
- } from '../..';
11
- import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
12
+ } from '../../index.js';
13
+ import { memo, useCallback, useEffect, useState } from 'react';
12
14
 
13
- import { Logger } from '../../utils/logger';
14
- import { Overview } from './overview';
15
+ import { Logger } from '../../utils/logger.js';
16
+ import { Overview } from './overview.js';
15
17
  import { SchemaValidator } from './SchemaValidator.jsx';
16
18
 
17
19
  const Input = components.Input;
18
20
 
19
- function DevOptions({ goToPage, getData }) {
21
+ function DevOptions({ goToPage, getData }: { goToPage: any; getData: any }) {
20
22
  const [toPage, setToPage] = useState(1);
21
23
 
22
- function handleChange(_, value) {
24
+ function handleChange(_, value: any) {
23
25
  setToPage(value);
24
26
  }
25
27
 
@@ -33,6 +35,8 @@ function DevOptions({ goToPage, getData }) {
33
35
  </div>
34
36
  <Input
35
37
  id="page-to-jump"
38
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
39
+ // @ts-ignore
36
40
  value={toPage}
37
41
  handleChange={handleChange}
38
42
  min={1}
@@ -89,7 +93,7 @@ function Pager({
89
93
  );
90
94
  }
91
95
 
92
- function onLogChange(response, value, args) {
96
+ function onLogChange(response: any, value: any, args: any) {
93
97
  Logger.log('onChange', { response, value, args });
94
98
  }
95
99
 
@@ -110,7 +114,7 @@ function OrchestratorForStories({
110
114
  missingStrategy = logMissingStrategy,
111
115
  missingShortcut,
112
116
  autoSuggesterLoading,
113
- addExternal,
117
+ // addExternal,
114
118
  preferences,
115
119
  slots,
116
120
  showOverview = false,
@@ -136,7 +140,7 @@ function OrchestratorForStories({
136
140
  pageTag,
137
141
  isFirstPage,
138
142
  isLastPage,
139
- waiting,
143
+ // waiting,
140
144
  overview,
141
145
  compileControls,
142
146
  getData,
@@ -1,3 +1,5 @@
1
+ /* eslint-disable */
2
+ // @ts-nocheck
1
3
  import { Fragment } from 'react';
2
4
  import './overview.scss';
3
5
 
@@ -60,7 +60,7 @@ export class LunaticVariablesStore {
60
60
  if (!source.variables) {
61
61
  return store;
62
62
  }
63
- // Source data (picked from "variables" in the source.json)s
63
+ // Source data (picked from "variables" in the source.json)
64
64
  const sourceValues: Record<string, unknown> = {};
65
65
  // Starting data for the form (merged with data.json or injected data)
66
66
  const initialValues: Record<string, unknown> = {};