@ea-lab/reactive-json 0.0.20 → 0.0.21

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 (124) hide show
  1. package/README.md +1 -1
  2. package/dist/esm/types/component/action/HashChangeListener.d.ts +9 -0
  3. package/{lib/component/action/Hide.jsx → dist/esm/types/component/action/Hide.d.ts} +2 -6
  4. package/dist/esm/types/component/action/MessageListener.d.ts +9 -0
  5. package/dist/esm/types/component/action/Popover.d.ts +5 -0
  6. package/dist/esm/types/component/action/ReactOnEvent.d.ts +26 -0
  7. package/dist/esm/types/component/action/Redirect.d.ts +9 -0
  8. package/dist/esm/types/component/action/Tooltip.d.ts +5 -0
  9. package/{lib/component/action/VisuallyHide.jsx → dist/esm/types/component/action/VisuallyHide.d.ts} +1 -4
  10. package/dist/esm/types/component/element/form/CheckBoxField.d.ts +7 -0
  11. package/dist/esm/types/component/element/form/DateField.d.ts +2 -0
  12. package/dist/esm/types/component/element/form/NumberField.d.ts +7 -0
  13. package/dist/esm/types/component/element/form/SelectField.d.ts +7 -0
  14. package/dist/esm/types/component/element/form/TextAreaField.d.ts +6 -0
  15. package/dist/esm/types/component/element/form/TextField.d.ts +6 -0
  16. package/dist/esm/types/component/element/form/formElementsCommon.d.ts +23 -0
  17. package/dist/esm/types/component/element/html/AccordionItem.d.ts +16 -0
  18. package/dist/esm/types/component/element/html/FolderSortableTree.d.ts +6 -0
  19. package/dist/esm/types/component/element/html/FormatNumeral.d.ts +7 -0
  20. package/dist/esm/types/component/element/html/Html.d.ts +8 -0
  21. package/dist/esm/types/component/element/html/LabelFromValue.d.ts +22 -0
  22. package/dist/esm/types/component/element/html/Modal.d.ts +6 -0
  23. package/dist/esm/types/component/element/html/ModalForm.d.ts +9 -0
  24. package/dist/esm/types/component/element/html/Paragraph.d.ts +5 -0
  25. package/dist/esm/types/component/element/html/PreformattedMarkup.d.ts +7 -0
  26. package/dist/esm/types/component/element/html/SortableTreeItemCollapseButton.d.ts +9 -0
  27. package/dist/esm/types/component/element/html/Tabs.d.ts +18 -0
  28. package/dist/esm/types/component/element/special/BootstrapElement.d.ts +10 -0
  29. package/dist/esm/types/component/element/special/Count.d.ts +13 -0
  30. package/dist/esm/types/component/element/special/DataFilter.d.ts +11 -0
  31. package/dist/esm/types/component/element/special/DelayedActions.d.ts +25 -0
  32. package/dist/esm/types/component/element/special/PageControls.d.ts +9 -0
  33. package/dist/esm/types/component/element/special/Phantom.d.ts +17 -0
  34. package/dist/esm/types/component/element/special/Switch.d.ts +6 -0
  35. package/dist/esm/types/component/hook/usePagination.d.ts +30 -0
  36. package/dist/esm/types/component/index.d.ts +5 -0
  37. package/dist/esm/types/component/reaction/addData.d.ts +6 -0
  38. package/dist/esm/types/component/reaction/fetchData.d.ts +8 -0
  39. package/dist/esm/types/component/reaction/moveData.d.ts +6 -0
  40. package/dist/esm/types/component/reaction/postMessage.d.ts +6 -0
  41. package/dist/esm/types/component/reaction/redirectNow.d.ts +6 -0
  42. package/dist/esm/types/component/reaction/removeData.d.ts +6 -0
  43. package/dist/esm/types/component/reaction/setClipboardData.d.ts +6 -0
  44. package/dist/esm/types/component/reaction/setData.d.ts +6 -0
  45. package/dist/esm/types/component/reaction/submitData.d.ts +8 -0
  46. package/dist/esm/types/component/reaction/triggerEvent.d.ts +6 -0
  47. package/dist/esm/types/component/utility/formatString.d.ts +17 -0
  48. package/dist/esm/types/engine/Actions.d.ts +19 -0
  49. package/dist/esm/types/engine/ComponentCollector.d.ts +12 -0
  50. package/{lib/engine/EventDispatcherContext.jsx → dist/esm/types/engine/EventDispatcherContext.d.ts} +4 -7
  51. package/dist/esm/types/engine/EventDispatcherProvider.d.ts +16 -0
  52. package/{lib/engine/GlobalDataContext.jsx → dist/esm/types/engine/GlobalDataContext.d.ts} +1 -4
  53. package/dist/esm/types/engine/GlobalDataContextProvider.d.ts +11 -0
  54. package/{lib/engine/PaginationContext.jsx → dist/esm/types/engine/PaginationContext.d.ts} +3 -4
  55. package/dist/esm/types/engine/PaginationProvider.d.ts +12 -0
  56. package/dist/esm/types/engine/ReactiveJsonRoot.d.ts +28 -0
  57. package/{lib/engine/TemplateContext.jsx → dist/esm/types/engine/TemplateContext.d.ts} +1 -4
  58. package/dist/esm/types/engine/TemplateSystem.d.ts +89 -0
  59. package/dist/esm/types/engine/View.d.ts +7 -0
  60. package/dist/esm/types/index.d.ts +6 -0
  61. package/dist/esm/types/main.d.ts +10 -0
  62. package/dist/index.cjs.js +9201 -0
  63. package/dist/index.cjs.js.map +1 -0
  64. package/dist/index.d.ts +44 -0
  65. package/dist/index.esm.js +9180 -0
  66. package/dist/index.esm.js.map +1 -0
  67. package/package.json +26 -15
  68. package/dist/reactive-json.css +0 -5
  69. package/dist/reactive-json.js +0 -47707
  70. package/dist/reactive-json.js.map +0 -1
  71. package/dist/reactive-json.umd.cjs +0 -366
  72. package/dist/reactive-json.umd.cjs.map +0 -1
  73. package/lib/component/action/HashChangeListener.jsx +0 -66
  74. package/lib/component/action/MessageListener.jsx +0 -62
  75. package/lib/component/action/Popover.jsx +0 -53
  76. package/lib/component/action/ReactOnEvent.jsx +0 -118
  77. package/lib/component/action/Redirect.jsx +0 -26
  78. package/lib/component/action/Tooltip.jsx +0 -27
  79. package/lib/component/element/form/CheckBoxField.jsx +0 -215
  80. package/lib/component/element/form/DateField.jsx +0 -42
  81. package/lib/component/element/form/NumberField.jsx +0 -29
  82. package/lib/component/element/form/SelectField.jsx +0 -130
  83. package/lib/component/element/form/TextAreaField.jsx +0 -48
  84. package/lib/component/element/form/TextField.jsx +0 -65
  85. package/lib/component/element/form/formElementsCommon.jsx +0 -54
  86. package/lib/component/element/html/AccordionItem.jsx +0 -42
  87. package/lib/component/element/html/FolderSortableTree.jsx +0 -307
  88. package/lib/component/element/html/FormatNumeral.jsx +0 -118
  89. package/lib/component/element/html/Html.jsx +0 -107
  90. package/lib/component/element/html/LabelFromValue.jsx +0 -89
  91. package/lib/component/element/html/Modal.jsx +0 -77
  92. package/lib/component/element/html/ModalForm.jsx +0 -30
  93. package/lib/component/element/html/Paragraph.jsx +0 -10
  94. package/lib/component/element/html/PreformattedMarkup.jsx +0 -54
  95. package/lib/component/element/html/SortableTreeItemCollapseButton.jsx +0 -20
  96. package/lib/component/element/html/Tabs.jsx +0 -55
  97. package/lib/component/element/special/BootstrapElement.jsx +0 -32
  98. package/lib/component/element/special/Count.jsx +0 -46
  99. package/lib/component/element/special/DataFilter.jsx +0 -156
  100. package/lib/component/element/special/DelayedActions.jsx +0 -119
  101. package/lib/component/element/special/PageControls.jsx +0 -19
  102. package/lib/component/element/special/Phantom.jsx +0 -25
  103. package/lib/component/element/special/Switch.jsx +0 -131
  104. package/lib/component/hook/usePagination.jsx +0 -184
  105. package/lib/component/reaction/addData.jsx +0 -23
  106. package/lib/component/reaction/fetchData.jsx +0 -83
  107. package/lib/component/reaction/moveData.jsx +0 -52
  108. package/lib/component/reaction/postMessage.jsx +0 -43
  109. package/lib/component/reaction/redirectNow.jsx +0 -17
  110. package/lib/component/reaction/removeData.jsx +0 -48
  111. package/lib/component/reaction/setClipboardData.jsx +0 -20
  112. package/lib/component/reaction/setData.jsx +0 -23
  113. package/lib/component/reaction/submitData.jsx +0 -136
  114. package/lib/component/reaction/triggerEvent.jsx +0 -62
  115. package/lib/component/utility/formatString.jsx +0 -59
  116. package/lib/engine/Actions.jsx +0 -392
  117. package/lib/engine/ComponentCollector.js +0 -28
  118. package/lib/engine/EventDispatcherProvider.jsx +0 -80
  119. package/lib/engine/GlobalDataContextProvider.jsx +0 -33
  120. package/lib/engine/PaginationProvider.jsx +0 -61
  121. package/lib/engine/ReactiveJsonRoot.jsx +0 -318
  122. package/lib/engine/TemplateSystem.jsx +0 -302
  123. package/lib/engine/View.jsx +0 -248
  124. package/lib/main.jsx +0 -52
@@ -1,156 +0,0 @@
1
- import {useContext} from "react";
2
- import {isValid} from "../../../engine/Actions";
3
- import GlobalDataContext from "../../../engine/GlobalDataContext";
4
- import TemplateContext from "../../../engine/TemplateContext";
5
- import View from "../../../engine/View";
6
-
7
- /**
8
- * Use DataFilter to filter data from the global or template data.
9
- *
10
- * @param args Component build data.
11
- *
12
- * @returns {JSX.Element}
13
- *
14
- * @constructor
15
- */
16
- const DataFilter = (args) => {
17
- const globalDataContext = useContext(GlobalDataContext);
18
- const templateContext = useContext(TemplateContext);
19
- const templateContexts = {globalDataContext, templateContext};
20
-
21
- const {
22
- contextToFilter = "global",
23
- filters = [],
24
- } = args.props;
25
-
26
- const filterData = (data) => {
27
- if (!data) {
28
- return true;
29
- }
30
-
31
- for (const filter of filters) {
32
- const subjectsWithProperty = filter?.subjectsWithProperty ?? undefined;
33
-
34
- if (!subjectsWithProperty) {
35
- // Ignore this filter.
36
- continue;
37
- }
38
-
39
- if (!data.hasOwnProperty(subjectsWithProperty)) {
40
- continue;
41
- }
42
-
43
- const additionalConditionHandlers = new Map(
44
- [
45
- [
46
- "whenFilterableData",
47
- ({condition}) => {
48
- // Walk through the data.
49
- const path = condition["whenFilterableData"];
50
- const pathArray = path.split('.');
51
- let current = data;
52
-
53
- for (const segment of pathArray) {
54
- const index = parseInt(segment);
55
- current = current[isNaN(index) ? segment : index];
56
- if (current === undefined) {
57
- return undefined;
58
- }
59
- }
60
-
61
- return current;
62
- }
63
- ]
64
- ]
65
- );
66
-
67
- // The item may be filtered out by this filter definition.
68
- // Now, check the activation conditions.
69
- if (!isValid(filter, templateContexts, additionalConditionHandlers)) {
70
- return false;
71
- }
72
- }
73
-
74
- // No filter for this data, keep it.
75
- return true;
76
- };
77
-
78
-
79
- switch (contextToFilter) {
80
- case "template":
81
- templateContext.templateData = cloneAndFilter(templateContext.templateData, filterData);
82
- templateContext.templatePath = args.path;
83
-
84
- return <TemplateContext.Provider value={templateContext}>
85
- <View
86
- props={args.props.content}
87
- path={args.path + ".content"}
88
- datafield={"content"}
89
- currentData={args.currentData?.["content"] ?? undefined}/>
90
- </TemplateContext.Provider>;
91
-
92
- case "global":
93
- default:
94
- // We rewrite the template data.
95
- globalDataContext.templateData = cloneAndFilter(globalDataContext.templateData, filterData);
96
-
97
- return <GlobalDataContext.Provider value={globalDataContext}>
98
- <View
99
- props={args.props.content}
100
- path={args.path + ".content"}
101
- datafield={"content"}
102
- currentData={args.currentData?.["content"] ?? undefined}/>
103
- </GlobalDataContext.Provider>;
104
- }
105
- };
106
-
107
- /**
108
- * Clones the data to an object only structure.
109
- *
110
- * It means that arrays will be converted to objects,
111
- * with the array indices converted to property keys.
112
- * This is necessary because we want to preserve the
113
- * paths of the items that are still appearing after
114
- * the filtering process, so that they can call
115
- * updateData as usual.
116
- *
117
- * @param data
118
- * @param {function} filterData
119
- *
120
- * @returns {{}|*}
121
- */
122
- const cloneAndFilter = (data, filterData) => {
123
- if (Array.isArray(data)) {
124
- const obj = {};
125
-
126
- data.forEach((item, index) => {
127
- if (!filterData(item)) {
128
- // Do not keep this item.
129
- return;
130
- }
131
-
132
- obj[index] = cloneAndFilter(item, filterData);
133
- });
134
-
135
- return obj;
136
- } else if (typeof data === 'object' && data !== null) {
137
- const obj = {};
138
-
139
- for (const key in data) {
140
- if (data.hasOwnProperty(key)) {
141
- // We only work with own properties, not inherited ones.
142
- if (!filterData(data[key])) {
143
- // Do not keep this item.
144
- continue;
145
- }
146
-
147
- obj[key] = cloneAndFilter(data[key], filterData);
148
- }
149
- }
150
- return obj;
151
- } else {
152
- return data;
153
- }
154
- }
155
-
156
- export default DataFilter;
@@ -1,119 +0,0 @@
1
- import ActionDependant, {isValid} from "../../../engine/Actions";
2
- import GlobalDataContext from "../../../engine/GlobalDataContext";
3
- import TemplateContext from "../../../engine/TemplateContext";
4
- import View from "../../../engine/View";
5
- import {reactionFunctions} from "../../action/ReactOnEvent";
6
- import {useContext, useEffect} from "react";
7
-
8
- /**
9
- * Provides a way to execute actions after a delay, at intervals, etc.
10
- *
11
- * @param {{}} props Build data.
12
- * @param currentData Current data.
13
- * @param path Element path.
14
- *
15
- * @constructor
16
- */
17
- const DelayedActions = ({props, currentData, path}) => {
18
- const globalDataContext = useContext(GlobalDataContext);
19
- const templateContext = useContext(TemplateContext);
20
-
21
- const delayedActions = Array.isArray(props.delayedActions) ? props.delayedActions : [];
22
- const templateContexts = {globalDataContext, templateContext};
23
-
24
- useEffect(() => {
25
- if (!props.interval) {
26
- return;
27
- }
28
-
29
- const interval = setInterval(() => {
30
- const reactionFunctionsToExecute = getReactionFunctionsToExecute(delayedActions, templateContexts);
31
-
32
- // Execute the reaction functions.
33
- // They are supposed to be validated for execution by getReactionFunctionsToExecute.
34
- // The events (on change, on click, etc.) are ignored because
35
- // it does not make sense to have to wait for a delay AND a specific event.
36
- // The time is already an event.
37
- for (let reactionFunctionPropsIndex = 0; reactionFunctionPropsIndex < reactionFunctionsToExecute.length; ++reactionFunctionPropsIndex) {
38
- const singleReactionFunctionProps = reactionFunctionsToExecute[reactionFunctionPropsIndex];
39
-
40
- if (!singleReactionFunctionProps) {
41
- // Empty definition.
42
- continue;
43
- }
44
-
45
- const reactionFunction = singleReactionFunctionProps.what && (reactionFunctions[singleReactionFunctionProps.what] ?? null);
46
-
47
- if (!reactionFunction) {
48
- continue;
49
- }
50
-
51
- // Call the reaction function with the props and context data.
52
- // This differs from the ReactOnEvent implementation by not including event data,
53
- // because we did not trigger an event.
54
- reactionFunction({args: singleReactionFunctionProps, globalDataContext, templateContext});
55
- }
56
-
57
- if (props.once) {
58
- clearInterval(interval);
59
- }
60
- }, props.interval);
61
-
62
- return () => clearInterval(interval);
63
- }, [globalDataContext, templateContext]);
64
-
65
- return <ActionDependant {...props}>
66
- {props.content && <View
67
- props={props.content}
68
- currentData={currentData?.content ?? undefined}
69
- datafield={"content"}
70
- path={path + ".content"}/>}
71
- </ActionDependant>;
72
- };
73
-
74
-
75
- /**
76
- * Gets the reaction functions to execute.
77
- *
78
- * This is a specific adaptation of getActionsToExecute from the Actions core functionality.
79
- *
80
- * @param {Array} actions
81
- * @param {object} templateContexts
82
- * @returns {*[]} The list of reaction function properties. The structure is simpler than getActionsToExecute.
83
- */
84
- export const getReactionFunctionsToExecute = (actions, templateContexts) => {
85
- const result = [];
86
-
87
- if (!Array.isArray(actions)) {
88
- // Not a supported actions structure.
89
- // Dev note: we may also allow objects in the future, to allow specific overrides.
90
- return result;
91
- }
92
-
93
- for (const [, item] of actions.entries()) {
94
- const what = item?.what ?? undefined;
95
-
96
- if (!what) {
97
- continue;
98
- }
99
-
100
- const reactionFunction = reactionFunctions[what] ?? undefined;
101
-
102
- if (!reactionFunction) {
103
- // The component is unknown or not registered,
104
- // and it's not a reaction function.
105
- continue;
106
- }
107
-
108
- // This is a reaction function.
109
- if (!isValid(item, templateContexts)) {
110
- continue;
111
- }
112
-
113
- result.push(item);
114
- }
115
-
116
- return result;
117
- };
118
-
119
- export default DelayedActions;
@@ -1,19 +0,0 @@
1
- import {useContext} from "react";
2
- import PaginationContext from "../../../engine/PaginationContext";
3
-
4
- /**
5
- * Displays the PageControls found in the PaginationContext, if any.
6
- *
7
- * @returns {JSX.Element|null}
8
- *
9
- * @constructor
10
- */
11
- const PageControls = () => {
12
- const {pagination} = useContext(PaginationContext);
13
-
14
- return pagination.PageControls
15
- ? <pagination.PageControls/>
16
- : null;
17
- };
18
-
19
- export default PageControls;
@@ -1,25 +0,0 @@
1
- import ActionDependant from "../../../engine/Actions";
2
- import View from "../../../engine/View";
3
-
4
- /**
5
- * Phantom element without DOM output.
6
- *
7
- * Use this if you want actions without a DOM element.
8
- *
9
- * @param {{}} props Build data.
10
- * @param currentData Current data.
11
- * @param path Element path.
12
- *
13
- * @constructor
14
- */
15
- const Phantom = ({props, currentData, path}) => {
16
- return <ActionDependant {...props}>
17
- {props.content && <View
18
- props={props.content}
19
- currentData={currentData?.content ?? undefined}
20
- datafield={"content"}
21
- path={path + ".content"}/>}
22
- </ActionDependant>;
23
- };
24
-
25
- export default Phantom;
@@ -1,131 +0,0 @@
1
- import {useContext} from 'react';
2
- import ActionDependant from "../../../engine/Actions";
3
- import GlobalDataContext from "../../../engine/GlobalDataContext";
4
- import PaginationContext from "../../../engine/PaginationContext";
5
- import TemplateContext from "../../../engine/TemplateContext";
6
- import {dataLocationToPath, evaluateTemplateValue, isTemplateValue} from "../../../engine/TemplateSystem";
7
- import View from "../../../engine/View";
8
- import {usePagination} from "../../hook/usePagination";
9
-
10
- const Switch = ({props, currentData, path}) => {
11
- const globalDataContext = useContext(GlobalDataContext);
12
- const templateContext = useContext(TemplateContext);
13
-
14
- // The allowed item count. Any value less than 1 means infinite.
15
- const cardinality = props?.cardinality ?? -1;
16
-
17
- // The allowed sub items for this switch.
18
- const options = props?.options ?? [];
19
- const singleOption = props?.singleOption ?? undefined;
20
-
21
- // This will tell if singleOption should be used.
22
- const useSingleOption = !!singleOption;
23
-
24
- // The content property is used to pinpoint on a template data value.
25
- // This is not mandatory; the data can still set the selected value(s)
26
- // by the usual overwrite by using the same render array structure.
27
- const maybeContent = props?.content ?? null;
28
- const evaluatedContent = maybeContent && evaluateTemplateValue({
29
- globalDataContext: globalDataContext,
30
- templateContext: templateContext,
31
- valueToEvaluate: maybeContent,
32
- });
33
- const finalDataSource = typeof evaluatedContent === "object" ? evaluatedContent : currentData;
34
-
35
- // This will limit the values count by the config in case the data is wrong.
36
- const limitedContent = Object
37
- .entries(finalDataSource)
38
- .map(([dataIndex, dataEntry]) => {
39
- const realIndex = dataIndex;
40
-
41
- if (cardinality >= 1 && realIndex >= cardinality) {
42
- // Ignore the data entry.
43
- return null;
44
- }
45
-
46
- if (!dataEntry || typeof dataEntry !== "object") {
47
- // Invalid entries count in the cardinality check.
48
- // If we don't want them counted, we need to change the cardinality check itself
49
- // which is currently based on the data index.
50
- return null;
51
- }
52
-
53
- let dataKey;
54
- let dataValue;
55
- let selectedOption;
56
-
57
- if (useSingleOption) {
58
- dataValue = dataEntry;
59
- selectedOption = singleOption;
60
- } else {
61
- dataKey = Object.keys(dataEntry)[0] ?? undefined;
62
-
63
- if (dataKey === undefined) {
64
- // Render nothing.
65
- return null;
66
- }
67
-
68
- dataValue = Object.values(dataEntry)[0] ?? undefined;
69
- selectedOption = options[dataKey] ?? undefined;
70
- }
71
-
72
- if (selectedOption === undefined) {
73
- // Render nothing.
74
- return null;
75
- }
76
-
77
- let finalPath = ((isTemplateValue(maybeContent) && dataLocationToPath({
78
- dataLocation: maybeContent,
79
- currentPath: templateContext.templatePath,
80
- globalDataContext,
81
- templateContext
82
- })) || path) + "." + realIndex;
83
-
84
- if (!useSingleOption) {
85
- finalPath += "." + dataKey;
86
- }
87
-
88
- return <View
89
- currentData={dataValue}
90
- datafield={realIndex}
91
- key={realIndex}
92
- path={finalPath}
93
- props={selectedOption}
94
- />;
95
- });
96
-
97
- const pagination = usePagination(
98
- {
99
- dataToPaginate: limitedContent,
100
- ...(props?.paginationProps ?? {})
101
- });
102
-
103
- // Slice for the pagination if in effect.
104
- const contentAsViews = props?.paginated
105
- ? limitedContent.slice(pagination.firstShownItemIndex, pagination.maxShownItemIndexExcluded)
106
- : limitedContent;
107
-
108
- const toRender = <>
109
- {props?.before && <View
110
- currentData={currentData?.["before"] ?? undefined}
111
- path={path + ".before"}
112
- datafield={"before"}
113
- props={props?.before}/>}
114
- {contentAsViews}
115
- {props?.after && <View
116
- currentData={currentData?.["after"] ?? undefined}
117
- path={path + ".after"}
118
- datafield={"after"}
119
- props={props?.after}/>}
120
- </>
121
-
122
- return <ActionDependant {...props}>
123
- {props?.paginated
124
- ? <PaginationContext.Provider value={{pagination}}>
125
- {toRender}
126
- </PaginationContext.Provider>
127
- : toRender}
128
- </ActionDependant>
129
- };
130
-
131
- export default Switch;
@@ -1,184 +0,0 @@
1
- import {Pagination} from "react-bootstrap";
2
- import React, {useState} from "react";
3
-
4
- /**
5
- * Use this hook to create paginations.
6
- *
7
- * @param [Array] dataToPaginate The complete data to paginate.
8
- * @param [int] forcePaginationDisplay Set to true to force the pagination even when having less than 2 pages.
9
- * @param [int] maxPageButtonsCount The maximum page buttons count. Must be at least 1. Defaults to 5 when undefined.
10
- * @param [int] pageMaxItemCount The maximum item count per page. Defaults to 10 when undefined.
11
- *
12
- * @returns {{
13
- * firstShownItemIndex: number,
14
- * getPageCountForContent: (function(Array): number),
15
- * maxShownItemIndexExcluded: number,
16
- * PageControls: (function({pageCount: *})),
17
- * pageMaxItemCount: number,
18
- * sliceVisibleContent: ((function(Array): *)|*),
19
- * }}
20
- */
21
- export const usePagination = ({
22
- dataToPaginate = [],
23
- forcePaginationDisplay = false,
24
- maxPageButtonsCount = 5,
25
- pageMaxItemCount = 10,
26
- }) => {
27
- // TODO: la pagination ne se met pas à jour quand les filtres sont changés (currentData).
28
- const [activePageNumber0, setActivePageNumber0] = useState(0);
29
-
30
- /**
31
- * Count of page buttons that shall appear before and after the current page.
32
- *
33
- * When the current page is near the start or the end, this value is ignored
34
- * to show "maxPageButtonsCount" buttons.
35
- *
36
- * For example, when we have maxPageButtonsCount at 5, and 10 pages:
37
- * - When at active page 1, 2, 3: [1,2,3,4,5].
38
- * - When at active page 4, 5, 6, 7, 5 page buttons will appear, but shifted accordingly to the active page:
39
- * - page 4: [2,3,4,5,6]
40
- * - page 5: [3,4,5,6,7]
41
- * - page 6: [4,5,6,7,8]
42
- * - page 7: [5,6,7,8,9]
43
- * - When at active page 8, 9, 10: [6,7,8,9,10].
44
- *
45
- * @type {number}
46
- */
47
- const buttonsBeforeAfterMaxCount = Math.floor(maxPageButtonsCount / 2);
48
-
49
- /**
50
- * Index of the first item in the given content to show for the active page.
51
- *
52
- * This value is ready for slice()'s start.
53
- *
54
- * @type {number}
55
- */
56
- const firstShownItemIndex = activePageNumber0 * pageMaxItemCount;
57
-
58
- /**
59
- * Index of the last item + 1 in the given content to show for the active page.
60
- *
61
- * This value is ready for slice()'s end.
62
- *
63
- * @type {number}
64
- */
65
- const maxShownItemIndexExcluded = firstShownItemIndex + pageMaxItemCount;
66
-
67
- /**
68
- * Gets the expected page count for the given content.
69
- *
70
- * @param {Array} contentSource The content to paginate.
71
- *
72
- * @returns {number} The page count.
73
- */
74
- const getPageCountForContent = (contentSource) => {
75
- // Use ceil to have one last page for remaining items.
76
- return Math.ceil(contentSource.length / pageMaxItemCount);
77
- };
78
-
79
- /**
80
- * Slices the given content with the parameters of this pagination.
81
- *
82
- * Useful if the content array is complete.
83
- * If not, it may be better to work directly in the component
84
- * so that the hidden items are not computed for nothing.
85
- *
86
- * @param {Array} contentToSlice
87
- * @returns {*}
88
- */
89
- const sliceVisibleContent = (contentToSlice) => {
90
- if (!Array.isArray(contentToSlice)) {
91
- // Not an array. Not supported.
92
- return contentToSlice;
93
- }
94
-
95
- return contentToSlice.slice(firstShownItemIndex, maxShownItemIndexExcluded);
96
- };
97
-
98
- /**
99
- * Component which contains the page controls (previous, next, pages).
100
- *
101
- * @returns {JSX.Element}
102
- *
103
- * @constructor
104
- */
105
- const PageControls = () => {
106
- const pageCount = getPageCountForContent(dataToPaginate);
107
-
108
- if (!forcePaginationDisplay && (pageCount <= 1)) {
109
- return null;
110
- }
111
-
112
- return <Pagination>
113
- <Pagination.First
114
- disabled={activePageNumber0 <= 0}
115
- onClick={() => {
116
- setActivePageNumber0(0);
117
- }}/>
118
- <Pagination.Prev
119
- disabled={activePageNumber0 <= 0}
120
- onClick={() => {
121
- setActivePageNumber0(activePageNumber0 - 1);
122
- }}/>
123
- {Math.min(activePageNumber0 - buttonsBeforeAfterMaxCount, pageCount - maxPageButtonsCount) > 0 ?
124
- <Pagination.Ellipsis disabled/> : null}
125
- {(() => {
126
- const intermediateButtons = [];
127
-
128
- // The first button is the leftmost visible button.
129
- // It is either 0,
130
- // or the current page minus buttonsBeforeAfterMaxCount,
131
- // or maxPageButtonsCount starting from the end.
132
- let currentPageButtonNumber0 = Math.min(Math.max(0, pageCount - maxPageButtonsCount), Math.max(0, activePageNumber0 - buttonsBeforeAfterMaxCount));
133
- let remainingPagesToBuildButton = maxPageButtonsCount;
134
-
135
- const insertPageButton = (currentPageButtonNumber0, remainingPagesToBuildButton) => {
136
- intermediateButtons.push(<Pagination.Item
137
- active={activePageNumber0 === currentPageButtonNumber0}
138
- key={maxPageButtonsCount - remainingPagesToBuildButton}
139
- onClick={() => {
140
- setActivePageNumber0(currentPageButtonNumber0)
141
- }}
142
- >
143
- {currentPageButtonNumber0 + 1}
144
- </Pagination.Item>);
145
- };
146
-
147
- while (remainingPagesToBuildButton) {
148
- insertPageButton(currentPageButtonNumber0, remainingPagesToBuildButton);
149
-
150
- ++currentPageButtonNumber0;
151
- --remainingPagesToBuildButton;
152
-
153
- if (currentPageButtonNumber0 >= pageCount) {
154
- // Reached the end of the pages.
155
- break;
156
- }
157
- }
158
-
159
- return intermediateButtons;
160
- })()}
161
- {pageCount > Math.max(buttonsBeforeAfterMaxCount, activePageNumber0) + Math.ceil(maxPageButtonsCount / 2) ?
162
- <Pagination.Ellipsis disabled/> : null}
163
- <Pagination.Next
164
- disabled={activePageNumber0 + 1 >= pageCount}
165
- onClick={() => {
166
- setActivePageNumber0(activePageNumber0 + 1);
167
- }}/>
168
- <Pagination.Last
169
- disabled={activePageNumber0 + 1 >= pageCount}
170
- onClick={() => {
171
- setActivePageNumber0(pageCount - 1);
172
- }}/>
173
- </Pagination>
174
- };
175
-
176
- return {
177
- firstShownItemIndex,
178
- getPageCountForContent,
179
- maxShownItemIndexExcluded,
180
- PageControls,
181
- pageMaxItemCount,
182
- sliceVisibleContent,
183
- };
184
- };
@@ -1,23 +0,0 @@
1
- import {dataLocationToPath, evaluateTemplateValue} from "../../engine/TemplateSystem";
2
- import {cloneDeep} from "lodash";
3
-
4
- /**
5
- * Adds data at the specified path.
6
- *
7
- * @param {{}} props
8
- */
9
- export const addData = (props) => {
10
- const {globalDataContext, templateContext} = props;
11
- const {path, value} = props.args;
12
-
13
- if (path === undefined) {
14
- return;
15
- }
16
-
17
- const dataAbsolutePath = dataLocationToPath({currentPath: templateContext.templatePath, dataLocation: path, globalDataContext, templateContext});
18
-
19
- const evaluatedValue = evaluateTemplateValue({valueToEvaluate: value, globalDataContext, templateContext});
20
-
21
- // We clone the value to have distinct instances when the value is an object.
22
- globalDataContext?.updateData(typeof evaluatedValue !== "object" ? evaluatedValue : cloneDeep(evaluatedValue), dataAbsolutePath, "add");
23
- };