@ea-lab/reactive-json 0.0.20 → 0.0.22

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,318 +0,0 @@
1
- import EventDispatcherProvider from "./EventDispatcherProvider";
2
- import GlobalDataContextProvider from "./GlobalDataContextProvider";
3
- import TemplateContext from "./TemplateContext";
4
- import View from "./View";
5
- import axios from "axios";
6
- import {load} from 'js-yaml';
7
- import {isEqual} from "lodash";
8
- import {useEffect, useReducer, useState} from 'react';
9
-
10
- /**
11
- * Production ready app root.
12
- *
13
- * @param {string} dataFetchMethod The fetch method for the init data. Case-insensitive.
14
- * Use "POST" for post. Other values mean "GET".
15
- * @param {string} dataUrl The URL of the document containing the build data. Either JSON or YAML.
16
- * @param {{}} headersForData Headers for the data request, such as authentication info.
17
- * @param {{}} plugins Reactive-JSON plugins.
18
- * @param {boolean} debugMode Set to true to show the data structure and debug info.
19
- * @param {React.Element|null} DebugModeContentWrapper Wrapper around the main reactive-json content when in debug mode.
20
- * @param {React.Element|null} DebugModeDataWrapper Wrapper around the reactive-json debug data when in debug mode.
21
- * @param {React.Element|null} DebugModeMainWrapper Wrapper around the reactive-json root when in debug mode.
22
- *
23
- * @returns {JSX.Element}
24
- *
25
- * @constructor
26
- */
27
- function ReactiveJsonRoot({
28
- dataFetchMethod,
29
- dataUrl,
30
- headersForData,
31
- plugins,
32
- debugMode,
33
- DebugModeContentWrapper,
34
- DebugModeDataWrapper,
35
- DebugModeRootWrapper,
36
- }) {
37
- // Dev note: on PhpStorm, disregard the Function signatures inspection errors of reducers.
38
- // See: https://youtrack.jetbrains.com/issue/WEB-53963.
39
- // noinspection JSCheckFunctionSignatures
40
- const [currentData, dispatchCurrentData] = useReducer((prevState, dispatched) => {
41
- switch (dispatched.type) {
42
- case "setData":
43
- return {updateId: 0, realCurrentData: dispatched.data};
44
-
45
- case "updateData":
46
- return updateObject(prevState, dispatched.path, dispatched.value, dispatched.updateMode);
47
-
48
- default:
49
- // Unknown type.
50
- return prevState;
51
- }
52
- }, {updateId: 0, realCurrentData: {}});
53
- const [updatable, setUpdatable] = useState(0);
54
- const [templates, setTemplates] = useState({});
55
- const [renderView, setRenderView] = useState({});
56
- const [items, setItems] = useState([]);
57
- const [rawAppData, setRawAppData] = useState();
58
-
59
- useEffect(() => {
60
- if (!dataUrl) {
61
- return;
62
- }
63
-
64
- if (typeof dataFetchMethod === "string" && dataFetchMethod.toLowerCase() === "post") {
65
- // TODO: support form data.
66
- axios.post(
67
- dataUrl,
68
- {
69
- headers: headersForData,
70
- }).then((res) => {
71
- setRawAppData(res.data);
72
- });
73
- } else {
74
- axios.get(
75
- dataUrl,
76
- {
77
- headers: headersForData,
78
- }).then((res) => {
79
- setRawAppData(res.data);
80
- });
81
- }
82
- }, [dataUrl, headersForData]);
83
-
84
- useEffect(() => {
85
- if (!rawAppData) {
86
- // Not yet initialized.
87
- return;
88
- }
89
-
90
- let parsedData = rawAppData;
91
-
92
- if (typeof parsedData !== "object") {
93
- try {
94
- // Parse as JSON.
95
- parsedData = JSON.parse(rawAppData);
96
- } catch {
97
- try {
98
- // Parse as YAML.
99
- parsedData = load(rawAppData);
100
- } catch {
101
- console.log("Tried to load app data but the content could not be parsed as JSON nor YAML.");
102
- return;
103
- }
104
- }
105
- }
106
-
107
- // Dev note: listForms is deprecated; will be removed later.
108
- setTemplates(parsedData.templates ?? parsedData.listForms);
109
-
110
- if (!parsedData.templates && parsedData.listForms) {
111
- console.log("'listForms' needs to be renamed to 'templates'. The support for 'listForms' will be removed in the next releases of reactive-json.");
112
- }
113
-
114
- // noinspection JSCheckFunctionSignatures
115
- dispatchCurrentData({type: "setData", "data": parsedData.data});
116
- setRenderView(parsedData.renderView);
117
- setItems(Object.keys(parsedData.renderView));
118
- }, [rawAppData]);
119
-
120
- const updateData = (newValue, pathInData, updateMode = undefined) => {
121
- let path = pathInData.replace('data.', '');
122
-
123
- // noinspection JSCheckFunctionSignatures
124
- dispatchCurrentData({
125
- type: "updateData",
126
- path: path,
127
- value: newValue,
128
- updateMode: updateMode,
129
- });
130
- }
131
-
132
- /**
133
- * Updates the given data object.
134
- *
135
- * This must be a function to be used in the currentData's reducer.
136
- *
137
- * @param {{updateId: Number, realCurrentData: {}}} data The current data to edit. It will be mutated.
138
- * updateId will increment when a re-render is needed.
139
- * @param {string} path The path where to put (or remove) the data.
140
- * @param {any} value The value to set. If undefined, the value will be removed at the given path.
141
- * @param {string} updateMode The update mode, either "add", "move", "remove", or leave empty for replace.
142
- *
143
- * @returns {{updateId: Number, realCurrentData: {}}} Data with update ID changed if a render is needed.
144
- */
145
- function updateObject(data, path, value, updateMode = undefined) {
146
- const splitPath = path.split(".");
147
-
148
- // This will point to the current nested object.
149
- let pointer = data.realCurrentData;
150
-
151
- for (let i = 0, len = splitPath.length; i < len; i++) {
152
- const currentNodeKey = splitPath[i];
153
-
154
- if (i === len - 1) {
155
- // This is the last key from the path.
156
- if (updateMode === "remove" && Array.isArray(pointer)) {
157
- // Remove the entry from the array.
158
- pointer.splice(currentNodeKey, 1);
159
- } else if (updateMode === "move") {
160
- // "value" contains the info about how to move.
161
- if (value.increment) {
162
- // Towards the start of the array.
163
- if (!Array.isArray(pointer)) {
164
- // Not a valid "up" value. Do nothing.
165
- return data;
166
- }
167
-
168
- const newIndex = Math.min(pointer.length, Math.max(0, parseInt(currentNodeKey) + parseInt(value.increment)));
169
-
170
- if (newIndex === parseInt(currentNodeKey)) {
171
- // No changes.
172
- return data;
173
- }
174
-
175
- const itemToMove = pointer.splice(currentNodeKey, 1);
176
-
177
- if (itemToMove.length < 1) {
178
- // Nothing to move.
179
- return data;
180
- }
181
-
182
- pointer.splice(newIndex, 0, itemToMove[0]);
183
- } else {
184
- // Nothing to move.
185
- return data;
186
- }
187
- } else {
188
- if (value === undefined) {
189
- // Unset the key.
190
- delete pointer[currentNodeKey];
191
- } else if (isEqual(value, pointer[currentNodeKey])) {
192
- // The value doesn't change.
193
- return data;
194
- } else {
195
- if (updateMode === "add") {
196
- // Add the value on the property.
197
- if (pointer[currentNodeKey] === undefined) {
198
- pointer[currentNodeKey] = [];
199
- }
200
-
201
- pointer[currentNodeKey].push(value);
202
- } else {
203
- // Set the value on the property.
204
- pointer[currentNodeKey] = value;
205
- }
206
- }
207
- }
208
-
209
- return {
210
- // Using modulo in case of massive update counts in long frontend sessions.
211
- updateId: ((data.updateId ?? 0) % (Number.MAX_SAFE_INTEGER - 1)) + 1,
212
- realCurrentData: data.realCurrentData
213
- };
214
- }
215
-
216
- if (pointer.hasOwnProperty(currentNodeKey)) {
217
- // The pointer already has the specified key.
218
-
219
- // Dig deeper.
220
- if (typeof pointer[currentNodeKey] !== "object" || pointer[currentNodeKey] === null) {
221
- // Ensure the data is writable.
222
- pointer[currentNodeKey] = {};
223
- }
224
-
225
- // Move the pointer.
226
- pointer = pointer[currentNodeKey];
227
- continue;
228
- }
229
-
230
- // This is a new property.
231
- pointer[currentNodeKey] = {};
232
- pointer = pointer[currentNodeKey];
233
- }
234
-
235
- // This should never happen.
236
- throw new Error("Could not update data.");
237
- }
238
-
239
- if (!rawAppData) {
240
- return null;
241
- }
242
-
243
- const rootViews = items.map(view => {
244
- return (<View
245
- datafield={view}
246
- key={view}
247
- props={renderView[view]}
248
- path={"data." + view}
249
- currentData={currentData.realCurrentData[view]}/>)
250
- });
251
-
252
- // Snippet from https://stackoverflow.com/a/1414175.
253
- // Enhanced to support other value types.
254
- function stringToBoolean(stringValue) {
255
- if (!stringValue) {
256
- return false;
257
- }
258
-
259
- if (typeof stringValue === "boolean") {
260
- return stringValue;
261
- }
262
-
263
- if (typeof stringValue !== "string") {
264
- return true;
265
- }
266
-
267
- switch (stringValue?.toLowerCase()?.trim()) {
268
- case "true":
269
- case "yes":
270
- case "1":
271
- return true;
272
-
273
- case "false":
274
- case "no":
275
- case "0":
276
- case "null":
277
- case "undefined":
278
- return false;
279
-
280
- default:
281
- return stringValue.length > 0;
282
- }
283
- }
284
-
285
- const debugMode_bool = stringToBoolean(debugMode);
286
-
287
- const mainBuild = (
288
- <EventDispatcherProvider>
289
- <GlobalDataContextProvider
290
- value={{
291
- element: templates,
292
- headersForData,
293
- plugins,
294
- setRawAppData,
295
- templateData: currentData.realCurrentData,
296
- templatePath: "data",
297
- updateData
298
- }}>
299
- <TemplateContext.Provider value={{templateData: currentData.realCurrentData, templatePath: "data"}}>
300
- {(debugMode_bool && DebugModeContentWrapper)
301
- ? <DebugModeContentWrapper>{rootViews}</DebugModeContentWrapper>
302
- : rootViews}
303
- </TemplateContext.Provider>
304
- {debugMode_bool
305
- ? (DebugModeDataWrapper && <DebugModeDataWrapper>
306
- {JSON.stringify(currentData.realCurrentData, null, ' ')}
307
- </DebugModeDataWrapper>)
308
- : null}
309
- </GlobalDataContextProvider>
310
- </EventDispatcherProvider>
311
- );
312
-
313
- return (debugMode_bool && DebugModeContentWrapper)
314
- ? <DebugModeRootWrapper>{mainBuild}</DebugModeRootWrapper>
315
- : mainBuild;
316
- }
317
-
318
- export default ReactiveJsonRoot;
@@ -1,302 +0,0 @@
1
- import {useContext} from "react";
2
- import GlobalDataContext from "./GlobalDataContext";
3
- import TemplateContext from "./TemplateContext";
4
- import {normalizeAttributesForReactJsx} from "../component/element/html/Html";
5
-
6
- /**
7
- * Transforms a data location string to a path to be used in the UI components.
8
- *
9
- * @param dataLocation
10
- * @param currentPath
11
- * @param globalDataContext
12
- * @param templateContext
13
- * @returns {string|*}
14
- * @constructor
15
- */
16
- export const dataLocationToPath = ({dataLocation, currentPath, globalDataContext, templateContext}) => {
17
- if (!(typeof dataLocation === "string") || !(dataLocation.startsWith("~.") || dataLocation.startsWith("~~.") || dataLocation.startsWith("~>"))) {
18
- if ("~" === dataLocation) {
19
- // The data location is the template root.
20
- return templateContext.templatePath;
21
- }
22
-
23
- if ("~~" === dataLocation) {
24
- // The data location is the global template root.
25
- return globalDataContext.templatePath;
26
- }
27
-
28
- // This value is not a data location.
29
- // Render what is given as is.
30
- return dataLocation;
31
- }
32
-
33
- // This tells if we check in the current template context, the global data, or the current path.
34
- let pathBase;
35
-
36
- if (dataLocation.startsWith("~~.")) {
37
- // Build the path starting from the global data context path (in theory, just "data").
38
- pathBase = globalDataContext.templatePath;
39
- } else if (dataLocation.startsWith("~.")) {
40
- // Build the path starting from the current template path.
41
- pathBase = templateContext.templatePath;
42
- } else if (dataLocation.startsWith("~>")) {
43
- // Build the path starting from an ascendant of the current template path.
44
- const keyToFind = dataLocation.substring(2, dataLocation.indexOf("."));
45
-
46
- if (!templateContext.templatePath.includes(keyToFind)) {
47
- throw new Error(keyToFind + " not found in the current template path.");
48
- }
49
-
50
- const keyToFindIndex = templateContext.templatePath.indexOf(keyToFind);
51
-
52
- pathBase = templateContext.templatePath.substring(0, keyToFindIndex + keyToFind.length);
53
- } else {
54
- pathBase = currentPath;
55
- }
56
-
57
- const splitLocationArray = dataLocation.split(".");
58
-
59
- // Remove the template value detection character.
60
- splitLocationArray.shift();
61
-
62
- return pathBase + "." + splitLocationArray.join(".");
63
- };
64
-
65
- /**
66
- * Evaluates the given attributes with the given contexts.
67
- *
68
- * @param {{}} attrs
69
- * @param {{}} globalDataContext
70
- * @param {{}} templateContext
71
- * @param {{normalizeBeforeEvaluation : boolean}} options normalizeBeforeEvaluation is false if unset.
72
- *
73
- * @returns {{}}
74
- */
75
- export const evaluateAttributes = ({attrs, globalDataContext, templateContext, options = {}}) => {
76
- const evaluated = {};
77
-
78
- if (!attrs) {
79
- return evaluated;
80
- }
81
-
82
- const normalized = options.normalizeBeforeEvaluation ? normalizeAttributesForReactJsx(attrs) : attrs;
83
-
84
- for (const attrName of Object.keys(normalized)) {
85
- // This will replace the value by the template value if it's a valid reference.
86
- // We call directly the TemplateValue component as a function to evaluate the attribute value.
87
- const evaluatedAttr = evaluateTemplateValue({
88
- globalDataContext: globalDataContext,
89
- templateContext: templateContext,
90
- valueToEvaluate: normalized[attrName]
91
- });
92
-
93
- // We only keep the attribute if it can be represented as an attribute value
94
- // or be interpreted by React such as callbacks.
95
- if (evaluatedAttr) {
96
- evaluated[attrName] = evaluatedAttr;
97
- }
98
-
99
- // TODO: the next code block has been commented out, because we found that
100
- // it may be more useful to allow objects as attributes (e.g. the style attribute
101
- // which is an object). Remove this block after testing.
102
- // switch (typeof evaluatedAttr) {
103
- // case "string":
104
- // case "bigint":
105
- // case "number":
106
- // case "boolean":
107
- // case "function":
108
- // evaluated[attrName] = evaluatedAttr;
109
- // break;
110
- //
111
- // default:
112
- // // We only keep the attribute if it can be represented as an attribute value
113
- // // or be interpreted by React such as callbacks.
114
- // delete evaluated[attrName];
115
- // break;
116
- // }
117
- }
118
-
119
- return evaluated;
120
- }
121
-
122
- /**
123
- * Evaluates the template value using the given template and global context.
124
- *
125
- * @param valueToEvaluate The value to evaluate.
126
- * @param globalDataContext The global data context.
127
- * @param templateContext The template context.
128
- * @returns {undefined|*}
129
- */
130
- export const evaluateTemplateValue = ({valueToEvaluate, globalDataContext, templateContext}) => {
131
- if (!isTemplateValue(valueToEvaluate)) {
132
- // This value does not use the template context data.
133
- // Render what is given as is.
134
- return valueToEvaluate;
135
- }
136
-
137
- /*
138
- * Experimental zone.
139
- */
140
-
141
- if ("~" === valueToEvaluate) {
142
- // We want the whole template data.
143
- return templateContext.templateData;
144
- } else if ("~~" === valueToEvaluate) {
145
- // We want the whole global template data.
146
- return globalDataContext.templateData;
147
- }
148
-
149
- /*
150
- * End of experimental zone.
151
- */
152
-
153
- let currentNode;
154
-
155
- if (valueToEvaluate.startsWith("~~.")) {
156
- // Start from the global data context node.
157
- currentNode = globalDataContext?.templateData;
158
- } else if (valueToEvaluate.startsWith("~>")) {
159
- // Start from the global data context node, but evaluate the "valueToEvaluate"
160
- // to use one of the ascending nodes of the current template.
161
- valueToEvaluate = dataLocationToPath({
162
- dataLocation: valueToEvaluate,
163
- currentPath: templateContext.templatePath,
164
- globalDataContext,
165
- templateContext,
166
- });
167
-
168
- currentNode = globalDataContext?.templateData;
169
- } else {
170
- // Start from the current template context node.
171
- currentNode = templateContext?.templateData;
172
- }
173
-
174
- if (!currentNode) {
175
- // No context supplied. This is likely a bug; contexts must be supplied when calling this function.
176
- return undefined;
177
- }
178
-
179
- // Find the value in the template context.
180
- const splitValueArray = valueToEvaluate.split(".");
181
-
182
- // Remove the template value detection character.
183
- splitValueArray.shift();
184
-
185
- while (splitValueArray.length) {
186
- if (typeof currentNode !== "object") {
187
- // Not an object, so there is no need to continue.
188
- // Return an undefined value.
189
- return undefined;
190
- }
191
-
192
- currentNode = currentNode[splitValueArray.shift()];
193
-
194
- if (currentNode === undefined) {
195
- // No need to continue.
196
- // Return an undefined value.
197
- return undefined;
198
- }
199
- }
200
-
201
- return currentNode;
202
- }
203
-
204
- /**
205
- * Evaluates an array or object containing values to evaluate.
206
- *
207
- * You can also pass a single value to evaluate.
208
- *
209
- * @param {Array|object|*} valueToEvaluate The value to evaluate. Usually a string, an array, or an object.
210
- * @param {{}} globalDataContext The global data context values.
211
- * @param {{}} templateContext The current template context values.
212
- *
213
- * @returns {*} The evaluated value. It tries to keep the same structure (array, object, single) as the given value.
214
- */
215
- export const evaluateTemplateValueCollection = ({valueToEvaluate, globalDataContext, templateContext}) => {
216
- let evaluated;
217
-
218
- if (typeof valueToEvaluate === "object") {
219
- // Evaluate any first level values.
220
- // Deep (recursive) evaluation is technically possible,
221
- // but we are not doing this yet for performance and usefulness reasons.
222
- evaluated = Array.isArray(valueToEvaluate) ? [] : {};
223
-
224
- for (const [key, itemContent] of Object.entries(valueToEvaluate)) {
225
- evaluated[key] = evaluateTemplateValue({
226
- globalDataContext,
227
- templateContext,
228
- valueToEvaluate: itemContent
229
- })
230
- }
231
- } else {
232
- // Single value.
233
- evaluated = evaluateTemplateValue({
234
- globalDataContext,
235
- templateContext,
236
- valueToEvaluate
237
- });
238
- }
239
-
240
- return evaluated;
241
- }
242
-
243
- /**
244
- * Checks if the given value is a value which can be replaced by the template system.
245
- * @param valueToEvaluate
246
- * @returns {string|boolean}
247
- */
248
- export const isTemplateValue = (valueToEvaluate) => {
249
- if (!(typeof valueToEvaluate === "string") || !(valueToEvaluate.startsWith("~.") || valueToEvaluate.startsWith("~~.") || valueToEvaluate.startsWith("~>") || "~" === valueToEvaluate || "~~" === valueToEvaluate)) {
250
- // This value does not use the template context data.
251
- return false;
252
- }
253
-
254
- // Render what is given as is for chaining.
255
- return valueToEvaluate;
256
- };
257
-
258
- /**
259
- * A template value is a value that is retrieved from the current template data.
260
- *
261
- * @param valueToEvaluate
262
- *
263
- * @returns {{}}
264
- *
265
- * @constructor
266
- */
267
- const TemplateValue = ({valueToEvaluate}) => {
268
- const globalDataContext = useContext(GlobalDataContext);
269
- const templateContext = useContext(TemplateContext);
270
-
271
- return evaluateTemplateValue({
272
- globalDataContext: globalDataContext,
273
- templateContext: templateContext,
274
- valueToEvaluate: valueToEvaluate,
275
- });
276
- };
277
-
278
- export default TemplateValue;
279
-
280
- /**
281
- * Evaluates the given attributes with the given contexts.
282
- *
283
- * @param {{}} attrs
284
- * @param {{normalizeBeforeEvaluation : boolean}} options normalizeBeforeEvaluation = true if unset.
285
- *
286
- * @returns {{}} Evaluated attributes.
287
- */
288
- export const useEvaluatedAttributes = (attrs, options = {}) => {
289
- const globalDataContext = useContext(GlobalDataContext);
290
- const templateContext = useContext(TemplateContext);
291
-
292
- return evaluateAttributes(
293
- {
294
- attrs,
295
- globalDataContext,
296
- templateContext,
297
- options: options.normalizeBeforeEvaluation === undefined
298
- ? {...options, normalizeBeforeEvaluation: true}
299
- : options,
300
- }
301
- );
302
- };