@inseefr/lunatic 2.7.12 → 2.7.14

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 (25) hide show
  1. package/lib/components/loop/block-for-loop.js +6 -2
  2. package/lib/components/loop/roster-for-loop/__snapshots__/roster-for-loop.spec.tsx.snap +8 -1
  3. package/lib/components/loop/roster-for-loop/roster-for-loop.js +11 -6
  4. package/lib/components/lunatic-components.js +3 -1
  5. package/lib/src/components/loop/block-for-loop.d.ts +1 -1
  6. package/lib/src/components/loop/roster-for-loop/roster-for-loop.d.ts +1 -1
  7. package/lib/src/components/lunatic-components.d.ts +2 -1
  8. package/lib/src/components/type.d.ts +2 -2
  9. package/lib/src/use-lunatic/reducer/commons/index.d.ts +0 -1
  10. package/lib/src/use-lunatic/use-lunatic.d.ts +4 -4
  11. package/lib/stories/behaviour/performance/performance.stories.js +47 -0
  12. package/lib/stories/behaviour/performance/source.json +172 -0
  13. package/lib/stories/loop/source-with-header.json +1 -1
  14. package/lib/stories/utils/orchestrator.js +13 -1
  15. package/lib/stories/utils/referentiel.js +3 -3
  16. package/lib/use-lunatic/commons/compile-controls.js +11 -5
  17. package/lib/use-lunatic/commons/fill-components/fill-component-expressions.js +1 -1
  18. package/lib/use-lunatic/commons/fill-components/fill-specific-expression.js +22 -5
  19. package/lib/use-lunatic/commons/variables/lunatic-variables-store.js +12 -2
  20. package/lib/use-lunatic/commons/variables/lunatic-variables-store.spec.js +23 -0
  21. package/lib/use-lunatic/hooks/use-page-has-response.js +11 -3
  22. package/lib/use-lunatic/reducer/commons/index.js +1 -9
  23. package/package.json +1 -1
  24. package/lib/src/use-lunatic/reducer/commons/is-loop-component.d.ts +0 -10
  25. package/lib/use-lunatic/reducer/commons/is-loop-component.js +0 -9
@@ -73,7 +73,11 @@ var BlockForLoop = exports.BlockForLoop = (0, _commons.createCustomizableLunatic
73
73
  return null;
74
74
  }
75
75
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
76
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_declarations.DeclarationsBeforeText, {
76
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_commons.Label, {
77
+ htmlFor: id,
78
+ id: "label-".concat(id),
79
+ children: label
80
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_declarations.DeclarationsBeforeText, {
77
81
  declarations: declarations,
78
82
  id: id
79
83
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_declarations.DeclarationsAfterText, {
@@ -96,7 +100,7 @@ var BlockForLoop = exports.BlockForLoop = (0, _commons.createCustomizableLunatic
96
100
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_loopButton.LoopButton, {
97
101
  onClick: addRow,
98
102
  disabled: nbRows === max,
99
- children: label || _i18n["default"].DEFAULT_BUTTON_ADD
103
+ children: _i18n["default"].DEFAULT_BUTTON_ADD
100
104
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_loopButton.LoopButton, {
101
105
  onClick: removeRow,
102
106
  disabled: nbRows === 1,
@@ -2,6 +2,13 @@
2
2
 
3
3
  exports[`RosterForLoop > renders the right number of columns 1`] = `
4
4
  <div>
5
+ <label
6
+ class="lunatic-label"
7
+ for="table"
8
+ id="label-table"
9
+ >
10
+ Ceci est un test
11
+ </label>
5
12
  <table
6
13
  class="lunatic-table"
7
14
  id="table-table"
@@ -77,7 +84,7 @@ exports[`RosterForLoop > renders the right number of columns 1`] = `
77
84
  <input
78
85
  class="button-lunatic"
79
86
  type="button"
80
- value="Ceci est un test"
87
+ value="Add row"
81
88
  />
82
89
  <input
83
90
  class="button-lunatic"
@@ -18,7 +18,7 @@ var _lunaticComponents = require("../../lunatic-components");
18
18
  var _constant = require("../constant");
19
19
  var _errors = require("../../commons/components/errors/errors");
20
20
  var _jsxRuntime = require("react/jsx-runtime");
21
- var _excluded = ["value", "lines", "handleChange", "declarations", "label", "headers", "iterations", "id", "getComponents"];
21
+ var _excluded = ["value", "lines", "handleChange", "declarations", "header", "iterations", "id", "getComponents", "label"];
22
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
23
23
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
24
24
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -44,11 +44,11 @@ var RosterForLoop = exports.RosterForLoop = (0, _commons.createCustomizableLunat
44
44
  lines = props.lines,
45
45
  handleChange = props.handleChange,
46
46
  declarations = props.declarations,
47
- label = props.label,
48
- headers = props.headers,
47
+ header = props.header,
49
48
  iterations = props.iterations,
50
49
  id = props.id,
51
50
  getComponents = props.getComponents,
51
+ label = props.label,
52
52
  otherProps = _objectWithoutProperties(props, _excluded);
53
53
  var min = (lines === null || lines === void 0 ? void 0 : lines.min) || DEFAULT_MIN_ROWS;
54
54
  var max = (lines === null || lines === void 0 ? void 0 : lines.max) || DEFAULT_MAX_ROWS;
@@ -85,7 +85,11 @@ var RosterForLoop = exports.RosterForLoop = (0, _commons.createCustomizableLunat
85
85
  }
86
86
  var cols = 0;
87
87
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
88
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_declarations.DeclarationsBeforeText, {
88
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_commons.Label, {
89
+ htmlFor: id,
90
+ id: "label-".concat(id),
91
+ children: label
92
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_declarations.DeclarationsBeforeText, {
89
93
  declarations: declarations,
90
94
  id: id
91
95
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_declarations.DeclarationsAfterText, {
@@ -94,7 +98,7 @@ var RosterForLoop = exports.RosterForLoop = (0, _commons.createCustomizableLunat
94
98
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_htmlTable.Table, {
95
99
  id: id,
96
100
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_tableHeader.TableHeader, {
97
- header: headers,
101
+ header: header,
98
102
  id: id
99
103
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_htmlTable.Tbody, {
100
104
  id: id,
@@ -111,6 +115,7 @@ var RosterForLoop = exports.RosterForLoop = (0, _commons.createCustomizableLunat
111
115
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_lunaticComponents.LunaticComponents, {
112
116
  blocklist: _constant.blockedInLoopComponents,
113
117
  components: components,
118
+ memo: true,
114
119
  componentProps: function componentProps(c) {
115
120
  return _objectSpread(_objectSpread(_objectSpread({}, otherProps), c), {}, {
116
121
  id: "".concat(c.id, "-").concat(n)
@@ -146,7 +151,7 @@ var RosterForLoop = exports.RosterForLoop = (0, _commons.createCustomizableLunat
146
151
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_loopButton.LoopButton, {
147
152
  onClick: addRow,
148
153
  disabled: nbRows === max,
149
- children: label || _i18n["default"].DEFAULT_BUTTON_ADD
154
+ children: _i18n["default"].DEFAULT_BUTTON_ADD
150
155
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_loopButton.LoopButton, {
151
156
  onClick: removeRow,
152
157
  disabled: nbRows === min,
@@ -26,6 +26,7 @@ function LunaticComponents(_ref) {
26
26
  autoFocusKey = _ref.autoFocusKey,
27
27
  componentProps = _ref.componentProps,
28
28
  blocklist = _ref.blocklist,
29
+ memo = _ref.memo,
29
30
  _ref$wrapper = _ref.wrapper,
30
31
  wrapper = _ref$wrapper === void 0 ? function (_ref2) {
31
32
  var children = _ref2.children;
@@ -58,7 +59,7 @@ function LunaticComponents(_ref) {
58
59
  var _props = _objectSpread(_objectSpread({}, component), componentProps === null || componentProps === void 0 ? void 0 : componentProps(component));
59
60
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.Fragment, {
60
61
  children: wrapper(_objectSpread({
61
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(LunaticComponent, _objectSpread({}, _props)),
62
+ children: memo ? /*#__PURE__*/(0, _jsxRuntime.jsx)(LunaticComponentMemo, _objectSpread({}, _props)) : /*#__PURE__*/(0, _jsxRuntime.jsx)(LunaticComponent, _objectSpread({}, _props)),
62
63
  index: k
63
64
  }, _props))
64
65
  }, computeId(component, k));
@@ -92,6 +93,7 @@ function LunaticComponent(props) {
92
93
  var Component = lunaticComponents[props.componentType];
93
94
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(Component, _objectSpread({}, props));
94
95
  }
96
+ var LunaticComponentMemo = /*#__PURE__*/(0, _react.memo)(LunaticComponent);
95
97
  function computeId(component, fallback) {
96
98
  if ('id' in component && typeof component.id === 'string') {
97
99
  return component.id;
@@ -15,7 +15,7 @@ export declare const BlockForLoop: import("react").ComponentType<import("../type
15
15
  deps?: string[] | undefined;
16
16
  } | undefined) => T;
17
17
  value: Record<string, unknown[]>;
18
- headers?: {
18
+ header?: {
19
19
  label: import("react").ReactNode;
20
20
  }[] | undefined;
21
21
  paginatedLoop?: boolean | undefined;
@@ -16,7 +16,7 @@ export declare const RosterForLoop: import("react").ComponentType<import("../../
16
16
  deps?: string[] | undefined;
17
17
  } | undefined) => T;
18
18
  value: Record<string, unknown[]>;
19
- headers?: {
19
+ header?: {
20
20
  label: import("react").ReactNode;
21
21
  }[] | undefined;
22
22
  paginatedLoop?: boolean | undefined;
@@ -5,6 +5,7 @@ type Props<T extends FilledLunaticComponentProps, V = undefined> = {
5
5
  label: string;
6
6
  [key: string]: unknown;
7
7
  })[];
8
+ memo?: boolean;
8
9
  autoFocusKey?: string;
9
10
  componentProps?: (component: FilledLunaticComponentProps) => V;
10
11
  blocklist?: string[];
@@ -15,7 +16,7 @@ type Props<T extends FilledLunaticComponentProps, V = undefined> = {
15
16
  /**
16
17
  * Entry point for orchestrators, this component display the list of fields
17
18
  */
18
- export declare function LunaticComponents<T extends FilledLunaticComponentProps, V = undefined>({ components, autoFocusKey, componentProps, blocklist, wrapper, }: Props<T, V>): import("react/jsx-runtime").JSX.Element;
19
+ export declare function LunaticComponents<T extends FilledLunaticComponentProps, V = undefined>({ components, autoFocusKey, componentProps, blocklist, memo, wrapper, }: Props<T, V>): import("react/jsx-runtime").JSX.Element;
19
20
  export declare function hasLabel(component: unknown): component is {
20
21
  label: ReactNode;
21
22
  } & FilledLunaticComponentProps;
@@ -98,7 +98,7 @@ type ComponentPropsByType = {
98
98
  getComponents: (n: number) => FilledLunaticComponentProps[];
99
99
  executeExpression: LunaticState['executeExpression'];
100
100
  value: Record<string, unknown[]>;
101
- headers?: Array<{
101
+ header?: Array<{
102
102
  label: ReactNode;
103
103
  }>;
104
104
  paginatedLoop?: boolean;
@@ -112,7 +112,7 @@ type ComponentPropsByType = {
112
112
  getComponents: (n: number) => FilledLunaticComponentProps[];
113
113
  executeExpression: LunaticState['executeExpression'];
114
114
  value: Record<string, unknown[]>;
115
- headers?: Array<{
115
+ header?: Array<{
116
116
  label: ReactNode;
117
117
  }>;
118
118
  paginatedLoop?: boolean;
@@ -1,3 +1,2 @@
1
1
  export { default as resizeArrayVariable } from './resize-array-variable';
2
- export { isLoopComponent } from './is-loop-component';
3
2
  export * from './validate-condition-filter';
@@ -72,7 +72,7 @@ declare function useLunatic(source: LunaticSource, data: LunaticData | undefined
72
72
  deps?: string[] | undefined;
73
73
  } | undefined) => T;
74
74
  value: Record<string, unknown[]>;
75
- headers?: {
75
+ header?: {
76
76
  label: import("react").ReactNode;
77
77
  }[] | undefined;
78
78
  paginatedLoop?: boolean | undefined;
@@ -90,7 +90,7 @@ declare function useLunatic(source: LunaticSource, data: LunaticData | undefined
90
90
  deps?: string[] | undefined;
91
91
  } | undefined) => T;
92
92
  value: Record<string, unknown[]>;
93
- headers?: {
93
+ header?: {
94
94
  label: import("react").ReactNode;
95
95
  }[] | undefined;
96
96
  paginatedLoop?: boolean | undefined;
@@ -320,7 +320,7 @@ declare function useLunatic(source: LunaticSource, data: LunaticData | undefined
320
320
  deps?: string[] | undefined;
321
321
  } | undefined) => T;
322
322
  value: Record<string, unknown[]>;
323
- headers?: {
323
+ header?: {
324
324
  label: import("react").ReactNode;
325
325
  }[] | undefined;
326
326
  paginatedLoop?: boolean | undefined;
@@ -338,7 +338,7 @@ declare function useLunatic(source: LunaticSource, data: LunaticData | undefined
338
338
  deps?: string[] | undefined;
339
339
  } | undefined) => T;
340
340
  value: Record<string, unknown[]>;
341
- headers?: {
341
+ header?: {
342
342
  label: import("react").ReactNode;
343
343
  }[] | undefined;
344
344
  paginatedLoop?: boolean | undefined;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = exports.Default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _orchestrator = _interopRequireDefault(require("../../utils/orchestrator"));
9
+ var _source = _interopRequireDefault(require("./source.json"));
10
+ var _lunatic = require("../../../../tests/utils/lunatic");
11
+ var _array = require("../../../utils/array");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
14
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
15
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
16
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
18
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
19
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
20
+ var stories = {
21
+ title: 'Behaviour/Performance',
22
+ component: _orchestrator["default"]
23
+ };
24
+ var _default = exports["default"] = stories;
25
+ var Template = function Template(args) {
26
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_orchestrator["default"], _objectSpread({}, args));
27
+ };
28
+ var Default = exports.Default = Template.bind({});
29
+ Default.args = {
30
+ id: 'performance-default',
31
+ pagination: true,
32
+ source: _source["default"],
33
+ data: (0, _lunatic.generateData)({
34
+ PRENOM: (0, _array.times)(200, function (k) {
35
+ return "John".concat(k);
36
+ }),
37
+ NOM: (0, _array.times)(200, function (k) {
38
+ return "Doe".concat(k);
39
+ }),
40
+ AGE: (0, _array.times)(200, function (k) {
41
+ return k + 1;
42
+ }),
43
+ BIRTHDAY: (0, _array.times)(200, function (k) {
44
+ return "2".concat(k.toString().padStart(3, '0'), "-01-01");
45
+ })
46
+ })
47
+ };
@@ -0,0 +1,172 @@
1
+ {
2
+ "maxPage": "3",
3
+ "components": [
4
+ {
5
+ "id": "seq",
6
+ "componentType": "Sequence",
7
+ "label": {
8
+ "value": "\"Description des individus de votre logement\"",
9
+ "type": "VTL|MD"
10
+ },
11
+ "conditionFilter": { "value": "true", "type": "VTL" },
12
+ "page": "1"
13
+ },
14
+ {
15
+ "id": "loop-prenom",
16
+ "componentType": "RosterForLoop",
17
+ "header": [
18
+ { "headerCell": true, "label": "Prénom" },
19
+ { "headerCell": true, "label": "Nom" },
20
+ { "headerCell": true, "label": "Date de naissance" },
21
+ { "headerCell": true, "label": "Age" }
22
+ ],
23
+ "label": { "value": "\"Ajouter un individu\"", "type": "VTL|MD" },
24
+ "conditionFilter": { "value": "true", "type": "VTL" },
25
+ "bindingDependencies": ["PRENOM", "AGE"],
26
+ "lines": {
27
+ "min": { "value": 1, "type": "VTL" },
28
+ "max": { "value": 250, "type": "VTL" }
29
+ },
30
+ "page": "1",
31
+ "components": [
32
+ {
33
+ "componentType": "Input",
34
+ "conditionFilter": { "value": "true", "type": "VTL" },
35
+ "maxLength": 30,
36
+ "bindingDependencies": ["PRENOM"],
37
+ "id": "prenom",
38
+ "response": {
39
+ "name": "PRENOM"
40
+ }
41
+ },
42
+ {
43
+ "componentType": "Input",
44
+ "conditionFilter": { "value": "true", "type": "VTL" },
45
+ "maxLength": 30,
46
+ "bindingDependencies": ["NOM"],
47
+ "id": "nom",
48
+ "response": {
49
+ "name": "NOM"
50
+ }
51
+ },
52
+ {
53
+ "componentType": "Datepicker",
54
+ "conditionFilter": { "value": "true", "type": "VTL" },
55
+ "maxLength": 30,
56
+ "bindingDependencies": ["BIRTHDAY"],
57
+ "id": "birthday",
58
+ "dateFormat": "YYYY-MM-DD",
59
+ "response": {
60
+ "name": "BIRTHDAY"
61
+ }
62
+ },
63
+ {
64
+ "componentType": "Input",
65
+ "conditionFilter": { "value": "true", "type": "VTL" },
66
+ "maxLength": 30,
67
+ "bindingDependencies": ["AGE"],
68
+ "id": "age",
69
+ "response": {
70
+ "name": "AGE"
71
+ }
72
+ }
73
+ ]
74
+ },
75
+ {
76
+ "id": "loop",
77
+ "componentType": "Loop",
78
+
79
+ "loopDependencies": ["PRENOM"],
80
+ "iterations": { "value": "count(PRENOM)", "type": "VTL" },
81
+ "page": "2",
82
+ "maxPage": "1",
83
+ "depth": 1,
84
+ "paginatedLoop": true,
85
+ "conditionFilter": {
86
+ "value": "true",
87
+ "type": "VTL"
88
+ },
89
+ "components": [
90
+ {
91
+ "id": "age",
92
+ "label": {
93
+ "value": "PRENOM || \", quel est vôtre âge ?\"",
94
+ "type": "VTL"
95
+ },
96
+ "conditionFilter": {
97
+ "value": "true",
98
+ "type": "VTL"
99
+ },
100
+ "page": "2.1",
101
+ "componentType": "InputNumber",
102
+ "min": 0,
103
+ "max": 120,
104
+ "decimals": 0,
105
+ "response": { "name": "AGE" }
106
+ }
107
+ ]
108
+ },
109
+ {
110
+ "id": "seq-end",
111
+ "componentType": "Sequence",
112
+ "label": {
113
+ "value": "\"End\"",
114
+ "type": "VTL|MD"
115
+ },
116
+ "conditionFilter": { "value": "true", "type": "VTL" },
117
+ "page": "3"
118
+ }
119
+ ],
120
+ "resizing": {
121
+ "PRENOM": {
122
+ "size": "count(PRENOM)",
123
+ "variables": ["AGE"]
124
+ }
125
+ },
126
+ "variables": [
127
+ {
128
+ "variableType": "COLLECTED",
129
+ "name": "PRENOM",
130
+ "values": {
131
+ "PREVIOUS": [null],
132
+ "COLLECTED": [null],
133
+ "FORCED": [null],
134
+ "EDITED": [null],
135
+ "INPUTED": [null]
136
+ }
137
+ },
138
+ {
139
+ "variableType": "COLLECTED",
140
+ "name": "NOM",
141
+ "values": {
142
+ "PREVIOUS": [null],
143
+ "COLLECTED": [null],
144
+ "FORCED": [null],
145
+ "EDITED": [null],
146
+ "INPUTED": [null]
147
+ }
148
+ },
149
+ {
150
+ "variableType": "COLLECTED",
151
+ "name": "BIRTHDAY",
152
+ "values": {
153
+ "PREVIOUS": [null],
154
+ "COLLECTED": [null],
155
+ "FORCED": [null],
156
+ "EDITED": [null],
157
+ "INPUTED": [null]
158
+ }
159
+ },
160
+ {
161
+ "variableType": "COLLECTED",
162
+ "name": "AGE",
163
+ "values": {
164
+ "PREVIOUS": [null],
165
+ "COLLECTED": [null],
166
+ "FORCED": [null],
167
+ "EDITED": [null],
168
+ "INPUTED": [null]
169
+ }
170
+ }
171
+ ]
172
+ }
@@ -14,7 +14,7 @@
14
14
  {
15
15
  "id": "loop-prenom",
16
16
  "componentType": "RosterForLoop",
17
- "headers": [
17
+ "header": [
18
18
  { "headerCell": true, "label": "Prénom" },
19
19
  { "headerCell": true, "label": "Age" }
20
20
  ],
@@ -204,7 +204,8 @@ function OrchestratorForStories(_ref3) {
204
204
  overview = _lunatic$useLunatic.overview,
205
205
  compileControls = _lunatic$useLunatic.compileControls,
206
206
  getData = _lunatic$useLunatic.getData,
207
- Provider = _lunatic$useLunatic.Provider;
207
+ Provider = _lunatic$useLunatic.Provider,
208
+ hasPageResponse = _lunatic$useLunatic.hasPageResponse;
208
209
  var components = getComponents();
209
210
  var lastReachedPage = pager.lastReachedPage;
210
211
  var _useState3 = (0, _react.useState)({}),
@@ -286,6 +287,17 @@ function OrchestratorForStories(_ref3) {
286
287
  maxPage: maxPage,
287
288
  getData: getData,
288
289
  pager: pager
290
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
291
+ className: "story-pager",
292
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("h3", {
293
+ children: "Misc"
294
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", {
295
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("li", {
296
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("strong", {
297
+ children: "pageHasResponse:"
298
+ }), ' ', JSON.stringify(hasPageResponse())]
299
+ })
300
+ })]
289
301
  }), showOverview && /*#__PURE__*/(0, _jsxRuntime.jsx)(_overview.Overview, {
290
302
  overview: overview,
291
303
  goToPage: goToPage
@@ -21,15 +21,15 @@ var getReferentiel = exports.getReferentiel = /*#__PURE__*/function () {
21
21
  return r.json();
22
22
  }));
23
23
  case 4:
24
- return _context.abrupt("return", fetch('https://inseefr.github.io/Lunatic/storybook/naf-rev2.json').then(function (r) {
24
+ return _context.abrupt("return", fetch('/naf-rev2.json').then(function (r) {
25
25
  return r.json();
26
26
  }));
27
27
  case 5:
28
- return _context.abrupt("return", fetch('https://inseefr.github.io/Lunatic/storybook/communes-2019.json').then(function (r) {
28
+ return _context.abrupt("return", fetch('/communes-2019.json').then(function (r) {
29
29
  return r.json();
30
30
  }));
31
31
  case 6:
32
- throw new Error("Unkonw r\xE9f\xE9rentiel ".concat(name));
32
+ throw new Error("Unknown r\xE9f\xE9rentiel ".concat(name));
33
33
  case 7:
34
34
  case "end":
35
35
  return _context.stop();
@@ -1,11 +1,9 @@
1
1
  "use strict";
2
2
 
3
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
7
6
  exports.compileControls = compileControls;
8
- var _commons = require("../reducer/commons");
9
7
  var _replaceComponentSequence = require("../replace-component-sequence");
10
8
  var _typeSource = require("../type-source");
11
9
  var _fillComponentExpressions = _interopRequireDefault(require("./fill-components/fill-component-expressions"));
@@ -13,6 +11,7 @@ var _getComponentsFromState = _interopRequireDefault(require("./get-components-f
13
11
  var _checkRoundaboutControl = require("../reducer/controls/check-roundabout-control");
14
12
  var _checkBaseControl = require("../reducer/controls/check-base-control");
15
13
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
14
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
16
15
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17
16
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
18
17
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -21,6 +20,10 @@ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input ==
21
20
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
22
21
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
23
22
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
23
+ var isLoopComponent = function isLoopComponent(component) {
24
+ return ['Loop', 'RosterForLoop'].includes(component.componentType);
25
+ };
26
+
24
27
  /**
25
28
  * Check if components of the current page have errors, and return a map of error (indexed by component ID)
26
29
  */
@@ -33,6 +36,7 @@ function checkComponents(state, components) {
33
36
  var component = _step.value;
34
37
  var controls = component.controls,
35
38
  id = component.id;
39
+
36
40
  // The component has global level controls
37
41
  if (Array.isArray(controls)) {
38
42
  var componentErrors = checkControls(controls.filter(function (c) {
@@ -44,7 +48,7 @@ function checkComponents(state, components) {
44
48
  }
45
49
 
46
50
  // For loop, inspect children
47
- if ((0, _commons.isLoopComponent)(component)) {
51
+ if (isLoopComponent(component)) {
48
52
  var _component$controls;
49
53
  var rowControls = (_component$controls = component.controls) === null || _component$controls === void 0 ? void 0 : _component$controls.filter(function (c) {
50
54
  return c.type === _typeSource.ControlTypeEnum.row;
@@ -92,7 +96,7 @@ function checkControls(controls, executeExpression, pager) {
92
96
  * Figure out the number of iterations of a component
93
97
  */
94
98
  function computeIterations(component, executeExpression) {
95
- if ('iterations' in component) {
99
+ if ('iterations' in component && component.iterations && _typeof(component.iterations) === 'object' && 'value' in component.iterations) {
96
100
  return executeExpression(component.iterations.value);
97
101
  }
98
102
  if ('response' in component) {
@@ -127,7 +131,9 @@ function checkComponentInLoop(state, component, errors) {
127
131
  nbIterations: iterations
128
132
  });
129
133
  // The component is filtered on this iteration, skip it
130
- if (component.conditionFilter && !state.executeExpression(component.conditionFilter.value, iterationPager)) {
134
+ if (
135
+ // conditionFilter can be the interpreted expression, or the object representing the expression
136
+ _typeof(component.conditionFilter) == 'object' && !state.executeExpression(component.conditionFilter.value, iterationPager) || component.conditionFilter === false) {
131
137
  continue;
132
138
  }
133
139
  var componentErrors = checkControls(component.controls, state.executeExpression, iterationPager);
@@ -24,7 +24,7 @@ var VTL_ATTRIBUTES = ['label', 'options.label', 'responses.label', 'hierarchy.la
24
24
  // Disable controls compilation
25
25
  // 'controls.control',
26
26
  // 'controls.errorMessage',
27
- 'controls.iterations', 'lines.min', 'lines.max', 'xAxisIterations', 'yAxisIterations', 'conditionFilter', 'headers.label', 'header.label', 'disabled', 'readOnly'];
27
+ 'controls.iterations', 'lines.min', 'lines.max', 'xAxisIterations', 'yAxisIterations', 'conditionFilter', 'header.label', 'disabled', 'readOnly'];
28
28
 
29
29
  // Utility type to replace all expression from an object into a translated version
30
30
 
@@ -59,11 +59,7 @@ function fillChildComponentsWithIteration(component, state) {
59
59
  return _objectSpread(_objectSpread({}, component), {}, {
60
60
  getComponents: function getComponents(iteration) {
61
61
  return (0, _fillComponents["default"])(component.components, _objectSpread(_objectSpread({}, state), {}, {
62
- handleChange: function handleChange(response, value) {
63
- state.handleChange(response, value, {
64
- iteration: [iteration]
65
- });
66
- },
62
+ handleChange: createChangeHandlerForIteration(state.handleChange, iteration),
67
63
  pager: _objectSpread(_objectSpread({}, state.pager), {}, {
68
64
  iteration: iteration,
69
65
  subPage: 0 // Fake a subpage to simulate an iteration
@@ -73,6 +69,27 @@ function fillChildComponentsWithIteration(component, state) {
73
69
  });
74
70
  }
75
71
 
72
+ // Create change handler memoized for every iteration
73
+ var changeHandler = null;
74
+ var changeHandlerMap = new Map();
75
+ function createChangeHandlerForIteration(handleChange, iteration) {
76
+ if (handleChange !== changeHandler) {
77
+ changeHandler = handleChange;
78
+ changeHandlerMap.clear();
79
+ }
80
+ var handler = changeHandlerMap.get(iteration);
81
+ if (handler) {
82
+ return handler;
83
+ }
84
+ handler = function handler(response, value) {
85
+ handleChange(response, value, {
86
+ iteration: [iteration]
87
+ });
88
+ };
89
+ changeHandlerMap.set(iteration, handler);
90
+ return handler;
91
+ }
92
+
76
93
  /**
77
94
  * For pairwise, inject a method to retrieve component at a specific iteration combination
78
95
  */
@@ -260,6 +260,11 @@ var LunaticVariable = /*#__PURE__*/function () {
260
260
 
261
261
  // Calculate bindings first to refresh "updatedAt" on calculated dependencies
262
262
  var bindings = this.getDependenciesValues(iteration);
263
+ // A variable without binding is a primitive (string, boolean...)
264
+ // it yields the same results for every iteration, so we can ignore iteration
265
+ if (Object.keys(bindings).length === 0) {
266
+ iteration = undefined;
267
+ }
263
268
  if (!this.isOutdated(iteration)) {
264
269
  return this.getSavedValue(iteration);
265
270
  }
@@ -387,8 +392,13 @@ var LunaticVariable = /*#__PURE__*/function () {
387
392
  var _this4 = this,
388
393
  _this$calculatedAt$ge;
389
394
  var dependenciesUpdatedAt = Math.max.apply(Math, [0].concat(_toConsumableArray(this.getDependencies().map(function (dep) {
390
- var _this4$dictionary$get, _this4$dictionary;
391
- return (_this4$dictionary$get = (_this4$dictionary = _this4.dictionary) === null || _this4$dictionary === void 0 || (_this4$dictionary = _this4$dictionary.get(dep)) === null || _this4$dictionary === void 0 ? void 0 : _this4$dictionary.updatedAt.get(iteration === null || iteration === void 0 ? void 0 : iteration.join('.'))) !== null && _this4$dictionary$get !== void 0 ? _this4$dictionary$get : 0;
395
+ var _ref2, _this4$dictionary$get, _this4$dictionary, _this4$dictionary2;
396
+ return (// Check when a value at the same iteration was calculated
397
+ (_ref2 = (_this4$dictionary$get = (_this4$dictionary = _this4.dictionary) === null || _this4$dictionary === void 0 || (_this4$dictionary = _this4$dictionary.get(dep)) === null || _this4$dictionary === void 0 ? void 0 : _this4$dictionary.updatedAt.get(iteration === null || iteration === void 0 ? void 0 : iteration.join('.'))) !== null && _this4$dictionary$get !== void 0 ? _this4$dictionary$get : // For aggregated value (max / min) look the global updatedAt time
398
+ (_this4$dictionary2 = _this4.dictionary) === null || _this4$dictionary2 === void 0 || (_this4$dictionary2 = _this4$dictionary2.get(dep)) === null || _this4$dictionary2 === void 0 ? void 0 : _this4$dictionary2.updatedAt.get(undefined)) !== null && _ref2 !== void 0 ? _ref2 :
399
+ // Otherwise this is a static value that never changes
400
+ 0
401
+ );
392
402
  }))));
393
403
  return dependenciesUpdatedAt > ((_this$calculatedAt$ge = this.calculatedAt.get(iteration === null || iteration === void 0 ? void 0 : iteration.join('.'))) !== null && _this$calculatedAt$ge !== void 0 ? _this$calculatedAt$ge : -1);
394
404
  }
@@ -199,6 +199,29 @@ var _lunaticVariablesStore = require("./lunatic-variables-store");
199
199
  });
200
200
  (0, _vitest.expect)(variables.get('FULLNAME')).toEqual(['John 1', 'Jane 2']);
201
201
  });
202
+ (0, _vitest.it)('should handle aggregate functions', function () {
203
+ variables.set('AGE', [1, 2, 3]);
204
+ variables.setCalculated('MAXAGE', 'max(AGE)');
205
+ variables.setCalculated('AGE_AND_MAX', 'AGE + MAXAGE', {
206
+ shapeFrom: 'AGE'
207
+ });
208
+ (0, _vitest.expect)(variables.get('AGE_AND_MAX', [0])).toEqual(4);
209
+ variables.set('AGE', 12, {
210
+ iteration: [1]
211
+ });
212
+ (0, _vitest.expect)(variables.get('AGE', [1])).toEqual(12);
213
+ (0, _vitest.expect)(variables.get('AGE_AND_MAX', [0])).toEqual(13);
214
+ });
215
+ (0, _vitest.it)('should handle primitive value', function () {
216
+ variables.run('"hello"', {
217
+ iteration: [0]
218
+ });
219
+ variables.run('"hello"', {
220
+ iteration: [1]
221
+ });
222
+ (0, _vitest.expect)(variables.run('"hello"')).toEqual('hello');
223
+ (0, _vitest.expect)(variables.interpretCount).toBe(1);
224
+ });
202
225
  });
203
226
  (0, _vitest.describe)('resizing', function () {
204
227
  (0, _vitest.it)('should resize variables', function () {
@@ -19,8 +19,8 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
19
19
  */
20
20
  function usePageHasResponse(components, executeExpression) {
21
21
  return (0, _react.useCallback)(function () {
22
- if (!Array.isArray(components)) {
23
- return false;
22
+ if (!Array.isArray(components) || components.length === 0) {
23
+ return true;
24
24
  }
25
25
  var _iterator = _createForOfIteratorHelper(components),
26
26
  _step;
@@ -28,9 +28,16 @@ function usePageHasResponse(components, executeExpression) {
28
28
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
29
29
  var component = _step.value;
30
30
  // Some components are considered as "filled" by default
31
- if (['PairwiseLinks', 'Roundabout'].includes(component.componentType)) {
31
+ // We assume they are not in the same page has other components
32
+ if (['PairwiseLinks', 'Roundabout', 'Sequence', 'Subsequence'].includes(component.componentType)) {
32
33
  return true;
33
34
  }
35
+
36
+ // We have a missing response for this component
37
+ if ('missingResponse' in component && component.missingResponse && component.missingResponse.value) {
38
+ return true;
39
+ }
40
+
34
41
  // For Table, we have to extract components from its body and apply isSubComponentsEmpty function
35
42
  if (component.componentType === 'Table') {
36
43
  // Body is array for array (row), each "cell" could be an Label or Component, so we filter array.
@@ -47,6 +54,7 @@ function usePageHasResponse(components, executeExpression) {
47
54
  if ('value' in component && !isEmpty(component.value)) {
48
55
  return true;
49
56
  }
57
+
50
58
  // For rosterForLoop we need to inspect child components
51
59
  if ('components' in component && Array.isArray(component.components) && !isSubComponentsEmpty(component.components, executeExpression)) {
52
60
  return true;
@@ -4,15 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  var _exportNames = {
7
- resizeArrayVariable: true,
8
- isLoopComponent: true
7
+ resizeArrayVariable: true
9
8
  };
10
- Object.defineProperty(exports, "isLoopComponent", {
11
- enumerable: true,
12
- get: function get() {
13
- return _isLoopComponent.isLoopComponent;
14
- }
15
- });
16
9
  Object.defineProperty(exports, "resizeArrayVariable", {
17
10
  enumerable: true,
18
11
  get: function get() {
@@ -20,7 +13,6 @@ Object.defineProperty(exports, "resizeArrayVariable", {
20
13
  }
21
14
  });
22
15
  var _resizeArrayVariable = _interopRequireDefault(require("./resize-array-variable"));
23
- var _isLoopComponent = require("./is-loop-component");
24
16
  var _validateConditionFilter = require("./validate-condition-filter");
25
17
  Object.keys(_validateConditionFilter).forEach(function (key) {
26
18
  if (key === "default" || key === "__esModule") return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inseefr/lunatic",
3
- "version": "2.7.12",
3
+ "version": "2.7.14",
4
4
  "workersVersion": "0.3.0",
5
5
  "description": "Library of questionnaire components",
6
6
  "repository": {
@@ -1,10 +0,0 @@
1
- import type { LunaticComponentDefinition } from '../../type';
2
- export declare const isLoopComponent: (component: LunaticComponentDefinition) => component is (import("../../type-source").ComponentTypeBase & import("../../type-source").ComponentRosterForLoopType & {
3
- componentType: "CheckboxOne" | "ConfirmationModal" | "Sequence" | "Subsequence" | "RosterForLoop" | "Loop" | "Table" | "InputNumber" | "Datepicker" | "CheckboxGroup" | "CheckboxBoolean" | "Radio" | "FilterDescription" | "Dropdown" | "PairwiseLinks" | "Roundabout" | "Suggester" | "Input" | "Textarea" | "ComponentSet" | "QuestionExplication";
4
- } & {
5
- componentType: 'Loop' | 'RosterForLoop';
6
- }) | (import("../../type-source").ComponentTypeBase & import("../../type-source").ComponentLoopType & {
7
- componentType: "CheckboxOne" | "ConfirmationModal" | "Sequence" | "Subsequence" | "RosterForLoop" | "Loop" | "Table" | "InputNumber" | "Datepicker" | "CheckboxGroup" | "CheckboxBoolean" | "Radio" | "FilterDescription" | "Dropdown" | "PairwiseLinks" | "Roundabout" | "Suggester" | "Input" | "Textarea" | "ComponentSet" | "QuestionExplication";
8
- } & {
9
- componentType: 'Loop' | 'RosterForLoop';
10
- });
@@ -1,9 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.isLoopComponent = void 0;
7
- var isLoopComponent = exports.isLoopComponent = function isLoopComponent(component) {
8
- return ['Loop', 'RosterForLoop'].includes(component.componentType);
9
- };