@ea-lab/reactive-json 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +83 -0
  2. package/dist/reactive-json.css +5 -0
  3. package/dist/reactive-json.js +56303 -0
  4. package/dist/reactive-json.umd.cjs +382 -0
  5. package/lib/component/action/HashChangeListener.jsx +66 -0
  6. package/lib/component/action/Hide.jsx +14 -0
  7. package/lib/component/action/MessageListener.jsx +62 -0
  8. package/lib/component/action/Popover.jsx +53 -0
  9. package/lib/component/action/ReactOnEvent.jsx +118 -0
  10. package/lib/component/action/Redirect.jsx +26 -0
  11. package/lib/component/action/Tooltip.jsx +27 -0
  12. package/lib/component/action/VisuallyHide.jsx +15 -0
  13. package/lib/component/element/chart/BarChart.jsx +40 -0
  14. package/lib/component/element/chart/DoughnutChart.jsx +32 -0
  15. package/lib/component/element/chart/LineChart.jsx +40 -0
  16. package/lib/component/element/chart/PolarAreaChart.jsx +32 -0
  17. package/lib/component/element/form/CheckBoxField.jsx +215 -0
  18. package/lib/component/element/form/DateField.jsx +42 -0
  19. package/lib/component/element/form/NumberField.jsx +29 -0
  20. package/lib/component/element/form/SelectField.jsx +130 -0
  21. package/lib/component/element/form/TextAreaField.jsx +48 -0
  22. package/lib/component/element/form/TextField.jsx +65 -0
  23. package/lib/component/element/form/formElementsCommon.jsx +54 -0
  24. package/lib/component/element/html/AccordionItem.jsx +42 -0
  25. package/lib/component/element/html/FolderSortableTree.jsx +307 -0
  26. package/lib/component/element/html/FormatNumeral.jsx +118 -0
  27. package/lib/component/element/html/Html.jsx +107 -0
  28. package/lib/component/element/html/LabelFromValue.jsx +89 -0
  29. package/lib/component/element/html/Modal.jsx +77 -0
  30. package/lib/component/element/html/ModalForm.jsx +30 -0
  31. package/lib/component/element/html/Paragraph.jsx +10 -0
  32. package/lib/component/element/html/PreformattedMarkup.jsx +54 -0
  33. package/lib/component/element/html/SortableTreeItemCollapseButton.jsx +20 -0
  34. package/lib/component/element/html/Tabs.jsx +55 -0
  35. package/lib/component/element/special/BootstrapElement.jsx +32 -0
  36. package/lib/component/element/special/Count.jsx +46 -0
  37. package/lib/component/element/special/DataFilter.jsx +156 -0
  38. package/lib/component/element/special/DelayedActions.jsx +119 -0
  39. package/lib/component/element/special/PageControls.jsx +19 -0
  40. package/lib/component/element/special/Phantom.jsx +25 -0
  41. package/lib/component/element/special/Switch.jsx +131 -0
  42. package/lib/component/hook/usePagination.jsx +184 -0
  43. package/lib/component/reaction/addData.jsx +23 -0
  44. package/lib/component/reaction/fetchData.jsx +83 -0
  45. package/lib/component/reaction/moveData.jsx +52 -0
  46. package/lib/component/reaction/postMessage.jsx +43 -0
  47. package/lib/component/reaction/redirectNow.jsx +17 -0
  48. package/lib/component/reaction/removeData.jsx +48 -0
  49. package/lib/component/reaction/setClipboardData.jsx +20 -0
  50. package/lib/component/reaction/setData.jsx +23 -0
  51. package/lib/component/reaction/submitData.jsx +136 -0
  52. package/lib/component/reaction/triggerEvent.jsx +62 -0
  53. package/lib/component/utility/formatString.jsx +59 -0
  54. package/lib/engine/Actions.jsx +392 -0
  55. package/lib/engine/EventDispatcherContext.jsx +16 -0
  56. package/lib/engine/EventDispatcherProvider.jsx +80 -0
  57. package/lib/engine/GlobalDataContext.jsx +13 -0
  58. package/lib/engine/GlobalDataContextProvider.jsx +33 -0
  59. package/lib/engine/PaginationContext.jsx +10 -0
  60. package/lib/engine/PaginationProvider.jsx +61 -0
  61. package/lib/engine/ReactiveJsonRoot.jsx +315 -0
  62. package/lib/engine/TemplateContext.jsx +13 -0
  63. package/lib/engine/TemplateSystem.jsx +302 -0
  64. package/lib/engine/View.jsx +240 -0
  65. package/lib/main.jsx +41 -0
  66. package/package.json +72 -0
@@ -0,0 +1,215 @@
1
+ import React, {useContext} from 'react';
2
+ import Form from 'react-bootstrap/Form';
3
+ import {propsDataLocationToPathAndValue} from "./formElementsCommon";
4
+ import ActionDependant from "../../../engine/Actions";
5
+ import GlobalDataContext from "../../../engine/GlobalDataContext";
6
+ import TemplateContext from "../../../engine/TemplateContext";
7
+ import {
8
+ evaluateAttributes,
9
+ evaluateTemplateValue,
10
+ } from "../../../engine/TemplateSystem";
11
+ import View from "../../../engine/View";
12
+
13
+ const CheckBoxField = ({props, currentData, datafield, path}) => {
14
+ const globalDataContext = useContext(GlobalDataContext);
15
+ const templateContext = useContext(TemplateContext);
16
+
17
+ const {updateData} = globalDataContext;
18
+
19
+ const attributes = evaluateAttributes(
20
+ {
21
+ attrs: props.attributes,
22
+ globalDataContext,
23
+ templateContext,
24
+ options: {
25
+ normalizeBeforeEvaluation: true,
26
+ },
27
+ });
28
+
29
+ let options;
30
+
31
+ const dynamicOptions = props.dynamicOptions ?? undefined;
32
+
33
+ if (dynamicOptions) {
34
+ // Build the options through the given data.
35
+ options = evaluateTemplateValue({valueToEvaluate: dynamicOptions, globalDataContext, templateContext}) ?? [];
36
+ } else {
37
+ options = props.options ?? [];
38
+ }
39
+
40
+ const controlType = props.controlType ?? undefined;
41
+
42
+ // This tells how to save the data when one or more inputs are available.
43
+ const isUsingSingleValueData = () => {
44
+ if (props.controlType === "radio") {
45
+ // Radios can only have a single value.
46
+ return true;
47
+ }
48
+
49
+ if (props.multiple !== undefined && props.multiple !== false) {
50
+ // Use the array structure.
51
+ return props.multiple;
52
+ }
53
+
54
+ // If the options length is > 1, we use the array structure.
55
+ return props.options?.length === 1;
56
+ };
57
+
58
+ const usesSingleValueData = isUsingSingleValueData();
59
+
60
+ // This is the field value when the data is not supplied on initialization.
61
+ const defaultFieldValue = props.defaultFieldValue ?? (!usesSingleValueData ? [] : undefined);
62
+
63
+ const {
64
+ formData: checkboxFormData,
65
+ formDataPath,
66
+ } = propsDataLocationToPathAndValue({
67
+ currentPath: path,
68
+ datafield,
69
+ dataLocation: props.dataLocation,
70
+ defaultValue: defaultFieldValue,
71
+ globalDataContext,
72
+ templateContext,
73
+ });
74
+
75
+ const changeValue = (e) => {
76
+ if (controlType === "radio") {
77
+ // When radio, use the "value" property.
78
+ // When the value is an empty string, we unset the value.
79
+ // Note: this could be made configurable, to keep the data key when the value is an empty string.
80
+ let valueToSet;
81
+
82
+ switch (e.currentTarget.value) {
83
+ case "":
84
+ valueToSet = undefined;
85
+ break;
86
+
87
+ case "true":
88
+ valueToSet = true;
89
+ break;
90
+
91
+ case "false":
92
+ valueToSet = false;
93
+ break;
94
+
95
+ case "null":
96
+ valueToSet = null;
97
+ break;
98
+
99
+ default:
100
+ valueToSet = e.currentTarget.value;
101
+ break;
102
+ }
103
+
104
+ updateData(valueToSet, formDataPath);
105
+ return;
106
+ }
107
+
108
+ if (usesSingleValueData) {
109
+ // Save the value directly.
110
+ updateData(e.currentTarget.checked, formDataPath);
111
+ return;
112
+ }
113
+
114
+ // Add the value or remove it from the array.
115
+ let formDataClone = JSON.parse(JSON.stringify(checkboxFormData));
116
+
117
+ if (typeof formDataClone !== "object") {
118
+ // Normalize the value with an object-like structure.
119
+ formDataClone = [formDataClone];
120
+ }
121
+
122
+ if (e.currentTarget.checked) {
123
+ // Add the item.
124
+ formDataClone = addCheckedValueToData(formDataClone, e.currentTarget.value);
125
+ } else {
126
+ // Remove the item.
127
+ formDataClone = removeCheckedValueFromData(formDataClone, e.currentTarget.value);
128
+ }
129
+
130
+ updateData(formDataClone, formDataPath);
131
+ }
132
+
133
+ return <ActionDependant {...props}>
134
+ <Form.Group {...attributes} controlId={Math.random().toString()}>
135
+ {options.map((option, i) => {
136
+ // The option value.
137
+ const finalOptionValue = typeof option.value === "string" ? evaluateTemplateValue({
138
+ globalDataContext: globalDataContext,
139
+ templateContext: templateContext,
140
+ valueToEvaluate: option.value,
141
+ }) : option.value;
142
+
143
+ const optionAttributes = evaluateAttributes({attrs: option.attributes ?? [], templateContext, globalDataContext, options: {normalizeBeforeEvaluation: true}});
144
+
145
+ return <Form.Check
146
+ {...optionAttributes}
147
+ checked={isChecked(checkboxFormData, finalOptionValue)}
148
+ key={i}
149
+ label={<View
150
+ currentData={currentData?.["options"]?.[i]?.["label"] ?? undefined}
151
+ datafield={"label"}
152
+ path={path + ".options." + i + ".label"}
153
+ props={option.label}/>}
154
+ id={`${Math.random()}`}
155
+ name={path}
156
+ onChange={changeValue}
157
+ type={controlType}
158
+ value={finalOptionValue}
159
+ />
160
+ })}
161
+ </Form.Group>
162
+ </ActionDependant>;
163
+ }
164
+
165
+ function isChecked(checkboxFormData, finalOptionValue) {
166
+ if (Array.isArray(checkboxFormData)) {
167
+ return checkboxFormData.includes(finalOptionValue);
168
+ }
169
+
170
+ if (typeof checkboxFormData === 'object') {
171
+ return Object.values(checkboxFormData).includes(finalOptionValue);
172
+ }
173
+
174
+ if (typeof checkboxFormData === "string") {
175
+ return checkboxFormData === finalOptionValue;
176
+ }
177
+
178
+ return checkboxFormData === finalOptionValue;
179
+ }
180
+
181
+ function addCheckedValueToData(checkboxFormData, optionValue) {
182
+ if (Array.isArray(checkboxFormData)) {
183
+ checkboxFormData.includes(optionValue) || checkboxFormData.push(optionValue);
184
+ return checkboxFormData;
185
+ }
186
+
187
+ if (typeof checkboxFormData === 'object') {
188
+ const arrayValuesCopy = Object.values(checkboxFormData);
189
+ arrayValuesCopy.includes(optionValue) || arrayValuesCopy.push(optionValue);
190
+ return arrayValuesCopy;
191
+ }
192
+
193
+ throw new Error('CheckboxField: the value to set is not properly initialized as an object or array.');
194
+ }
195
+
196
+ function removeCheckedValueFromData(checkboxFormData, optionValue) {
197
+ function removeIfIncluded(data, optionValue) {
198
+ data.includes(optionValue) && data.splice(data.indexOf(optionValue), 1);
199
+ }
200
+
201
+ if (Array.isArray(checkboxFormData)) {
202
+ removeIfIncluded(checkboxFormData, optionValue);
203
+ return checkboxFormData;
204
+ }
205
+
206
+ if (typeof checkboxFormData === 'object') {
207
+ const arrayValuesCopy = Object.values(checkboxFormData);
208
+ removeIfIncluded(arrayValuesCopy, optionValue);
209
+ return arrayValuesCopy;
210
+ }
211
+
212
+ throw new Error('CheckboxField: the value to set is not properly initialized as an object or array.');
213
+ }
214
+
215
+ export default CheckBoxField;
@@ -0,0 +1,42 @@
1
+ import Form from "react-bootstrap/Form";
2
+ import ActionDependant from "../../../engine/Actions";
3
+ import {useEvaluatedAttributes} from "../../../engine/TemplateSystem";
4
+ import {propsDataLocationToPathAndValue} from "./formElementsCommon";
5
+ import {useContext} from "react";
6
+ import GlobalDataContext from "../../../engine/GlobalDataContext";
7
+ import TemplateContext from "../../../engine/TemplateContext";
8
+
9
+ const DateField = (componentProps) => {
10
+ // TODO: type date & datetime-local support.
11
+ const globalDataContext = useContext(GlobalDataContext);
12
+ const templateContext = useContext(TemplateContext);
13
+
14
+ const props = componentProps.props;
15
+
16
+ const attributes = useEvaluatedAttributes(props.attributes);
17
+
18
+ const {
19
+ formData,
20
+ formDataPath,
21
+ } = propsDataLocationToPathAndValue({
22
+ currentPath: componentProps.path,
23
+ datafield: componentProps.datafield,
24
+ dataLocation: props.dataLocation,
25
+ defaultValue: props.defaultFieldValue,
26
+ globalDataContext,
27
+ templateContext,
28
+ });
29
+
30
+ const onChange = (e) => {
31
+ globalDataContext.updateData(e.target.value, formDataPath);
32
+ };
33
+
34
+ return <ActionDependant {...props}>
35
+ <Form.Group {...attributes} controlId={Math.random().toString()}>
36
+ {props.label && (<Form.Label>{props.label}</Form.Label>)}
37
+ <Form.Control onChange={onChange} type={"datetime-local"} value={formData ?? ""}/>
38
+ </Form.Group>
39
+ </ActionDependant>;
40
+ };
41
+
42
+ export default DateField;
@@ -0,0 +1,29 @@
1
+ import React, {useContext, useState} from 'react';
2
+ import Form from 'react-bootstrap/Form';
3
+ import GlobalDataContext from "../../../engine/GlobalDataContext";
4
+
5
+ const NumberField = ({props, currentData, datafield, path}) => {
6
+ const globalDataContext = useContext(GlobalDataContext);
7
+
8
+ let [inputValue] = useState(currentData);
9
+
10
+ let attributes = props.attributes ?? {};
11
+
12
+ const {updateData} = globalDataContext;
13
+
14
+ const changeValue = (e) => {
15
+ updateData(e.currentTarget.value, path);
16
+ }
17
+
18
+ return (
19
+ <Form.Group className="mb-3" controlId={Math.random().toString()}>
20
+ <Form.Label>{props.label}</Form.Label>
21
+ <Form.Control onBlur={changeValue} type={"number"} {...attributes}
22
+ defaultValue={inputValue !== "" ? inputValue : (props.default_value ?? "")}
23
+ placeholder={props.label}/>
24
+
25
+ </Form.Group>
26
+ )
27
+ }
28
+
29
+ export default NumberField;
@@ -0,0 +1,130 @@
1
+ import ActionDependant from "../../../engine/Actions";
2
+ import GlobalDataContext from "../../../engine/GlobalDataContext";
3
+ import TemplateContext from "../../../engine/TemplateContext";
4
+ import {dataLocationToPath, evaluateAttributes, evaluateTemplateValue} from "../../../engine/TemplateSystem";
5
+ import {useContext} from 'react';
6
+ import Form from 'react-bootstrap/Form';
7
+
8
+ const SelectField = ({props, data, path, datafield}) => {
9
+ const globalDataContext = useContext(GlobalDataContext);
10
+ const templateContext = useContext(TemplateContext);
11
+
12
+ const {updateData} = globalDataContext;
13
+
14
+ const dynamicOptions = props.dynamicOptions ?? undefined;
15
+
16
+ let options;
17
+
18
+ if (dynamicOptions) {
19
+ // Build the options through the given data.
20
+ options = evaluateTemplateValue({valueToEvaluate: dynamicOptions, globalDataContext, templateContext}) ?? [];
21
+ } else {
22
+ options = props.options ?? [];
23
+ }
24
+
25
+ let attributes = evaluateAttributes({
26
+ attrs: props.attributes ?? {},
27
+ globalDataContext,
28
+ templateContext,
29
+ options: {normalizeBeforeEvaluation: true}
30
+ });
31
+
32
+ const inputAttributes = evaluateAttributes({
33
+ attrs: props.inputAttributes ?? {},
34
+ globalDataContext,
35
+ templateContext,
36
+ options: {normalizeBeforeEvaluation: true}
37
+ });
38
+
39
+ // This is the data that contains the current value of SelectField.
40
+ let formData;
41
+
42
+ // This is the path that leads to the data.
43
+ let formDataPath;
44
+
45
+ // This is the field value when the data is not supplied on initialization.
46
+ const defaultFieldValue = props.defaultFieldValue ?? undefined;
47
+
48
+ const dataLocation = props.dataLocation ?? undefined;
49
+
50
+ if (dataLocation) {
51
+ // A custom data location has been specified.
52
+ formData = evaluateTemplateValue({
53
+ globalDataContext: globalDataContext,
54
+ templateContext: templateContext,
55
+ valueToEvaluate: dataLocation,
56
+ }) ?? defaultFieldValue;
57
+
58
+ formDataPath = dataLocationToPath({
59
+ dataLocation: dataLocation,
60
+ currentPath: path,
61
+ globalDataContext,
62
+ templateContext
63
+ });
64
+ } else {
65
+ // Use the template data.
66
+ if ((templateContext.templateData[datafield] ?? undefined) === undefined) {
67
+ // Initialize the data for this component.
68
+ templateContext.templateData = (typeof templateContext.templateData === "object") ? templateContext.templateData : {};
69
+ templateContext.templateData[datafield] = defaultFieldValue;
70
+ }
71
+
72
+ // The "form" data is located in the template context data,
73
+ // under the datafield key. (Dev note: this is maybe not the best way to handle this.)
74
+ formData = templateContext.templateData[datafield];
75
+
76
+ formDataPath = dataLocationToPath({dataLocation: "~." + datafield, currentPath: templateContext.templatePath});
77
+ }
78
+
79
+ const changeValue = (e) => {
80
+ let valueToSet;
81
+
82
+ switch (e.currentTarget.value) {
83
+ case "":
84
+ if (props.allowEmptyStringAsValue) {
85
+ valueToSet = "";
86
+ } else {
87
+ valueToSet = undefined;
88
+ }
89
+
90
+ break;
91
+
92
+ case "true":
93
+ valueToSet = true;
94
+ break;
95
+
96
+ case "false":
97
+ valueToSet = false;
98
+ break;
99
+
100
+ case "null":
101
+ valueToSet = null;
102
+ break;
103
+
104
+ default:
105
+ valueToSet = e.currentTarget.value;
106
+ break;
107
+ }
108
+
109
+ updateData(valueToSet, formDataPath);
110
+ }
111
+
112
+ return (
113
+ <ActionDependant {...props}>
114
+ <Form.Group {...attributes} controlId={Math.random().toString()}>
115
+ {props.label && <Form.Label>{props.label}</Form.Label>}
116
+ <Form.Select
117
+ aria-label={props.label}
118
+ onChange={changeValue}
119
+ value={formData}
120
+ {...inputAttributes}>
121
+ {options.map((item, ind) => {
122
+ return <option key={'opt' + ind} value={item.value}>{item.label}</option>;
123
+ })}
124
+ </Form.Select>
125
+ </Form.Group>
126
+ </ActionDependant>
127
+ )
128
+ }
129
+
130
+ export default SelectField;
@@ -0,0 +1,48 @@
1
+ import {useContext} from 'react';
2
+ import Form from 'react-bootstrap/Form';
3
+ import GlobalDataContext from "../../../engine/GlobalDataContext";
4
+ import ActionDependant from "../../../engine/Actions";
5
+ import TemplateContext from "../../../engine/TemplateContext";
6
+ import {useEvaluatedAttributes} from "../../../engine/TemplateSystem";
7
+ import {propsDataLocationToPathAndValue} from "./formElementsCommon";
8
+
9
+ const TextAreaField = ({props, datafield, path}) => {
10
+ const globalDataContext = useContext(GlobalDataContext);
11
+ const templateContext = useContext(TemplateContext);
12
+
13
+ const attributes = useEvaluatedAttributes(props.attributes);
14
+ const inputAttributes = useEvaluatedAttributes(props.inputAttributes ?? []);
15
+
16
+ const {
17
+ formData,
18
+ formDataPath,
19
+ } = propsDataLocationToPathAndValue({
20
+ currentPath: path,
21
+ datafield: datafield,
22
+ dataLocation: props.dataLocation,
23
+ defaultValue: props.defaultFieldValue,
24
+ globalDataContext,
25
+ templateContext,
26
+ });
27
+
28
+ const onChange = (e) => {
29
+ globalDataContext.updateData(e.currentTarget.value, formDataPath);
30
+ };
31
+
32
+ return (
33
+ <ActionDependant {...props}>
34
+ <Form.Group {...attributes} controlId={Math.random().toString()}>
35
+ {props.label && <Form.Label>{props.label}</Form.Label>}
36
+ <Form.Control
37
+ as={"textarea"}
38
+ onChange={onChange}
39
+ placeholder={props.placeholder}
40
+ rows={props.rows ?? 3}
41
+ value={formData ?? ""}
42
+ {...inputAttributes}/>
43
+ </Form.Group>
44
+ </ActionDependant>
45
+ );
46
+ }
47
+
48
+ export default TextAreaField;
@@ -0,0 +1,65 @@
1
+ import {useContext} from 'react';
2
+ import Form from 'react-bootstrap/Form';
3
+ import GlobalDataContext from "../../../engine/GlobalDataContext";
4
+ import ActionDependant from "../../../engine/Actions";
5
+ import TemplateContext from "../../../engine/TemplateContext";
6
+ import {evaluateTemplateValue, useEvaluatedAttributes} from "../../../engine/TemplateSystem";
7
+ import {propsDataLocationToPathAndValue} from "./formElementsCommon";
8
+
9
+ const TextField = ({props, datafield, path}) => {
10
+ const globalDataContext = useContext(GlobalDataContext);
11
+ const templateContext = useContext(TemplateContext);
12
+
13
+ const attributes = useEvaluatedAttributes(props.attributes);
14
+ const inputAttributes = useEvaluatedAttributes(props.inputAttributes ?? []);
15
+
16
+ const {
17
+ formData,
18
+ formDataPath,
19
+ } = propsDataLocationToPathAndValue({
20
+ currentPath: path,
21
+ datafield: datafield,
22
+ dataLocation: props.dataLocation,
23
+ defaultValue: props.defaultFieldValue,
24
+ globalDataContext,
25
+ templateContext,
26
+ });
27
+
28
+ const onChange = (e) => {
29
+ globalDataContext.updateData(e.currentTarget.value, formDataPath);
30
+ };
31
+
32
+ const maybeLabel = evaluateTemplateValue({
33
+ valueToEvaluate: props.label,
34
+ globalDataContext,
35
+ templateContext
36
+ });
37
+
38
+ const maybePlaceholder = evaluateTemplateValue({
39
+ valueToEvaluate: props.placeholder,
40
+ globalDataContext,
41
+ templateContext
42
+ });
43
+
44
+ const maybeInputType = evaluateTemplateValue({
45
+ valueToEvaluate: props.inputType,
46
+ globalDataContext,
47
+ templateContext
48
+ });
49
+
50
+ return (
51
+ <ActionDependant {...props}>
52
+ <Form.Group {...attributes} controlId={Math.random().toString()}>
53
+ {maybeLabel && <Form.Label>{maybeLabel}</Form.Label>}
54
+ <Form.Control
55
+ onChange={onChange}
56
+ placeholder={maybePlaceholder}
57
+ type={maybeInputType ?? "text"}
58
+ value={formData ?? ""}
59
+ {...inputAttributes}/>
60
+ </Form.Group>
61
+ </ActionDependant>
62
+ );
63
+ }
64
+
65
+ export default TextField;
@@ -0,0 +1,54 @@
1
+ import {dataLocationToPath, evaluateTemplateValue} from "../../../engine/TemplateSystem";
2
+
3
+ /**
4
+ * Gets the path and the data for the specified dataLocation and contexts.
5
+ *
6
+ * @param {string} currentPath The current path of the component calling this function.
7
+ * @param {string} datafield The datafield (field name) of the component calling this function.
8
+ * @param {string|undefined} dataLocation The dataLocation value set in the component structure.
9
+ * @param {any} defaultValue The default value set in the component structure.
10
+ * @param {{}} globalDataContext The global data context of the component calling this function.
11
+ * @param {{}} templateContext The template context of the component calling this function.
12
+ *
13
+ * @returns {{formDataPath: undefined, formData: undefined}}
14
+ */
15
+ export const propsDataLocationToPathAndValue = ({
16
+ currentPath,
17
+ datafield,
18
+ dataLocation,
19
+ defaultValue,
20
+ globalDataContext,
21
+ templateContext
22
+ }) => {
23
+
24
+ const result = {
25
+ // This is the data that contains the current checked state.
26
+ formData: undefined, // This is the path that leads to the data.
27
+ formDataPath: undefined,
28
+ };
29
+
30
+ if (dataLocation && typeof dataLocation === "string") {
31
+ // A custom data location has been specified.
32
+ result.formData = evaluateTemplateValue({
33
+ globalDataContext: globalDataContext, templateContext: templateContext, valueToEvaluate: dataLocation,
34
+ }) ?? defaultValue;
35
+ result.formDataPath = dataLocationToPath({dataLocation: dataLocation, currentPath: currentPath, globalDataContext, templateContext});
36
+ } else {
37
+ // Use the template data.
38
+ if ((templateContext.templateData[datafield] ?? undefined) === undefined) {
39
+ // Initialize the data for this component.
40
+ templateContext.templateData = (typeof templateContext.templateData === "object") ? templateContext.templateData : {};
41
+ templateContext.templateData[datafield] = defaultValue;
42
+ }
43
+
44
+ // The data is located in the template context data,
45
+ // under the datafield key. (Dev note: this is maybe not the best way to handle this.)
46
+ result.formData = templateContext.templateData[datafield];
47
+
48
+ result.formDataPath = dataLocationToPath({
49
+ dataLocation: "~." + datafield, currentPath: templateContext.templatePath, globalDataContext, templateContext
50
+ });
51
+ }
52
+
53
+ return result;
54
+ };
@@ -0,0 +1,42 @@
1
+ import {Accordion as BsAccordion} from "react-bootstrap";
2
+ import View from "../../../engine/View";
3
+ import {useEvaluatedAttributes} from "../../../engine/TemplateSystem";
4
+ import ActionDependant from "../../../engine/Actions";
5
+
6
+ /**
7
+ * To use with the BsAccordion component.
8
+ *
9
+ * To use this, use the BsAccordion component, and add
10
+ * AccordionItem in the content.
11
+ *
12
+ * You can of course use the Switch component to map to
13
+ * dynamic data.
14
+ */
15
+ const AccordionItem = ({props, path, currentData, datafield}) => {
16
+ const attributes = useEvaluatedAttributes(props.attributes);
17
+
18
+ return <ActionDependant {...props}>
19
+ <BsAccordion.Item {...attributes} eventKey={datafield} key={datafield}>
20
+ {props?.header
21
+ ? <BsAccordion.Header>
22
+ <View
23
+ props={props.header}
24
+ path={path + ".header"}
25
+ currentData={currentData?.["header"]}
26
+ datafield={"header"}/>
27
+ </BsAccordion.Header>
28
+ : null}
29
+ {props?.body
30
+ ? <BsAccordion.Body>
31
+ <View
32
+ props={props.body}
33
+ path={path + ".body"}
34
+ currentData={currentData?.["body"]}
35
+ datafield={"body"}/>
36
+ </BsAccordion.Body>
37
+ : null}
38
+ </BsAccordion.Item>
39
+ </ActionDependant>;
40
+ }
41
+
42
+ export default AccordionItem;