@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.
- package/README.md +83 -0
- package/dist/reactive-json.css +5 -0
- package/dist/reactive-json.js +56303 -0
- package/dist/reactive-json.umd.cjs +382 -0
- package/lib/component/action/HashChangeListener.jsx +66 -0
- package/lib/component/action/Hide.jsx +14 -0
- package/lib/component/action/MessageListener.jsx +62 -0
- package/lib/component/action/Popover.jsx +53 -0
- package/lib/component/action/ReactOnEvent.jsx +118 -0
- package/lib/component/action/Redirect.jsx +26 -0
- package/lib/component/action/Tooltip.jsx +27 -0
- package/lib/component/action/VisuallyHide.jsx +15 -0
- package/lib/component/element/chart/BarChart.jsx +40 -0
- package/lib/component/element/chart/DoughnutChart.jsx +32 -0
- package/lib/component/element/chart/LineChart.jsx +40 -0
- package/lib/component/element/chart/PolarAreaChart.jsx +32 -0
- package/lib/component/element/form/CheckBoxField.jsx +215 -0
- package/lib/component/element/form/DateField.jsx +42 -0
- package/lib/component/element/form/NumberField.jsx +29 -0
- package/lib/component/element/form/SelectField.jsx +130 -0
- package/lib/component/element/form/TextAreaField.jsx +48 -0
- package/lib/component/element/form/TextField.jsx +65 -0
- package/lib/component/element/form/formElementsCommon.jsx +54 -0
- package/lib/component/element/html/AccordionItem.jsx +42 -0
- package/lib/component/element/html/FolderSortableTree.jsx +307 -0
- package/lib/component/element/html/FormatNumeral.jsx +118 -0
- package/lib/component/element/html/Html.jsx +107 -0
- package/lib/component/element/html/LabelFromValue.jsx +89 -0
- package/lib/component/element/html/Modal.jsx +77 -0
- package/lib/component/element/html/ModalForm.jsx +30 -0
- package/lib/component/element/html/Paragraph.jsx +10 -0
- package/lib/component/element/html/PreformattedMarkup.jsx +54 -0
- package/lib/component/element/html/SortableTreeItemCollapseButton.jsx +20 -0
- package/lib/component/element/html/Tabs.jsx +55 -0
- package/lib/component/element/special/BootstrapElement.jsx +32 -0
- package/lib/component/element/special/Count.jsx +46 -0
- package/lib/component/element/special/DataFilter.jsx +156 -0
- package/lib/component/element/special/DelayedActions.jsx +119 -0
- package/lib/component/element/special/PageControls.jsx +19 -0
- package/lib/component/element/special/Phantom.jsx +25 -0
- package/lib/component/element/special/Switch.jsx +131 -0
- package/lib/component/hook/usePagination.jsx +184 -0
- package/lib/component/reaction/addData.jsx +23 -0
- package/lib/component/reaction/fetchData.jsx +83 -0
- package/lib/component/reaction/moveData.jsx +52 -0
- package/lib/component/reaction/postMessage.jsx +43 -0
- package/lib/component/reaction/redirectNow.jsx +17 -0
- package/lib/component/reaction/removeData.jsx +48 -0
- package/lib/component/reaction/setClipboardData.jsx +20 -0
- package/lib/component/reaction/setData.jsx +23 -0
- package/lib/component/reaction/submitData.jsx +136 -0
- package/lib/component/reaction/triggerEvent.jsx +62 -0
- package/lib/component/utility/formatString.jsx +59 -0
- package/lib/engine/Actions.jsx +392 -0
- package/lib/engine/EventDispatcherContext.jsx +16 -0
- package/lib/engine/EventDispatcherProvider.jsx +80 -0
- package/lib/engine/GlobalDataContext.jsx +13 -0
- package/lib/engine/GlobalDataContextProvider.jsx +33 -0
- package/lib/engine/PaginationContext.jsx +10 -0
- package/lib/engine/PaginationProvider.jsx +61 -0
- package/lib/engine/ReactiveJsonRoot.jsx +315 -0
- package/lib/engine/TemplateContext.jsx +13 -0
- package/lib/engine/TemplateSystem.jsx +302 -0
- package/lib/engine/View.jsx +240 -0
- package/lib/main.jsx +41 -0
- 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;
|