@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.
- package/README.md +1 -1
- package/dist/esm/types/component/action/HashChangeListener.d.ts +9 -0
- package/{lib/component/action/Hide.jsx → dist/esm/types/component/action/Hide.d.ts} +2 -6
- package/dist/esm/types/component/action/MessageListener.d.ts +9 -0
- package/dist/esm/types/component/action/Popover.d.ts +5 -0
- package/dist/esm/types/component/action/ReactOnEvent.d.ts +26 -0
- package/dist/esm/types/component/action/Redirect.d.ts +9 -0
- package/dist/esm/types/component/action/Tooltip.d.ts +5 -0
- package/{lib/component/action/VisuallyHide.jsx → dist/esm/types/component/action/VisuallyHide.d.ts} +1 -4
- package/dist/esm/types/component/element/form/CheckBoxField.d.ts +7 -0
- package/dist/esm/types/component/element/form/DateField.d.ts +2 -0
- package/dist/esm/types/component/element/form/NumberField.d.ts +7 -0
- package/dist/esm/types/component/element/form/SelectField.d.ts +7 -0
- package/dist/esm/types/component/element/form/TextAreaField.d.ts +6 -0
- package/dist/esm/types/component/element/form/TextField.d.ts +6 -0
- package/dist/esm/types/component/element/form/formElementsCommon.d.ts +23 -0
- package/dist/esm/types/component/element/html/AccordionItem.d.ts +16 -0
- package/dist/esm/types/component/element/html/FolderSortableTree.d.ts +6 -0
- package/dist/esm/types/component/element/html/FormatNumeral.d.ts +7 -0
- package/dist/esm/types/component/element/html/Html.d.ts +8 -0
- package/dist/esm/types/component/element/html/LabelFromValue.d.ts +22 -0
- package/dist/esm/types/component/element/html/Modal.d.ts +6 -0
- package/dist/esm/types/component/element/html/ModalForm.d.ts +9 -0
- package/dist/esm/types/component/element/html/Paragraph.d.ts +5 -0
- package/dist/esm/types/component/element/html/PreformattedMarkup.d.ts +7 -0
- package/dist/esm/types/component/element/html/SortableTreeItemCollapseButton.d.ts +9 -0
- package/dist/esm/types/component/element/html/Tabs.d.ts +18 -0
- package/dist/esm/types/component/element/special/BootstrapElement.d.ts +10 -0
- package/dist/esm/types/component/element/special/Count.d.ts +13 -0
- package/dist/esm/types/component/element/special/DataFilter.d.ts +11 -0
- package/dist/esm/types/component/element/special/DelayedActions.d.ts +25 -0
- package/dist/esm/types/component/element/special/PageControls.d.ts +9 -0
- package/dist/esm/types/component/element/special/Phantom.d.ts +17 -0
- package/dist/esm/types/component/element/special/Switch.d.ts +6 -0
- package/dist/esm/types/component/hook/usePagination.d.ts +30 -0
- package/dist/esm/types/component/index.d.ts +5 -0
- package/dist/esm/types/component/reaction/addData.d.ts +6 -0
- package/dist/esm/types/component/reaction/fetchData.d.ts +8 -0
- package/dist/esm/types/component/reaction/moveData.d.ts +6 -0
- package/dist/esm/types/component/reaction/postMessage.d.ts +6 -0
- package/dist/esm/types/component/reaction/redirectNow.d.ts +6 -0
- package/dist/esm/types/component/reaction/removeData.d.ts +6 -0
- package/dist/esm/types/component/reaction/setClipboardData.d.ts +6 -0
- package/dist/esm/types/component/reaction/setData.d.ts +6 -0
- package/dist/esm/types/component/reaction/submitData.d.ts +8 -0
- package/dist/esm/types/component/reaction/triggerEvent.d.ts +6 -0
- package/dist/esm/types/component/utility/formatString.d.ts +17 -0
- package/dist/esm/types/engine/Actions.d.ts +19 -0
- package/dist/esm/types/engine/ComponentCollector.d.ts +12 -0
- package/{lib/engine/EventDispatcherContext.jsx → dist/esm/types/engine/EventDispatcherContext.d.ts} +4 -7
- package/dist/esm/types/engine/EventDispatcherProvider.d.ts +16 -0
- package/{lib/engine/GlobalDataContext.jsx → dist/esm/types/engine/GlobalDataContext.d.ts} +1 -4
- package/dist/esm/types/engine/GlobalDataContextProvider.d.ts +11 -0
- package/{lib/engine/PaginationContext.jsx → dist/esm/types/engine/PaginationContext.d.ts} +3 -4
- package/dist/esm/types/engine/PaginationProvider.d.ts +12 -0
- package/dist/esm/types/engine/ReactiveJsonRoot.d.ts +28 -0
- package/{lib/engine/TemplateContext.jsx → dist/esm/types/engine/TemplateContext.d.ts} +1 -4
- package/dist/esm/types/engine/TemplateSystem.d.ts +89 -0
- package/dist/esm/types/engine/View.d.ts +7 -0
- package/dist/esm/types/index.d.ts +6 -0
- package/dist/esm/types/main.d.ts +10 -0
- package/dist/index.cjs.js +9201 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.esm.js +9180 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +26 -15
- package/dist/reactive-json.css +0 -5
- package/dist/reactive-json.js +0 -47707
- package/dist/reactive-json.js.map +0 -1
- package/dist/reactive-json.umd.cjs +0 -366
- package/dist/reactive-json.umd.cjs.map +0 -1
- package/lib/component/action/HashChangeListener.jsx +0 -66
- package/lib/component/action/MessageListener.jsx +0 -62
- package/lib/component/action/Popover.jsx +0 -53
- package/lib/component/action/ReactOnEvent.jsx +0 -118
- package/lib/component/action/Redirect.jsx +0 -26
- package/lib/component/action/Tooltip.jsx +0 -27
- package/lib/component/element/form/CheckBoxField.jsx +0 -215
- package/lib/component/element/form/DateField.jsx +0 -42
- package/lib/component/element/form/NumberField.jsx +0 -29
- package/lib/component/element/form/SelectField.jsx +0 -130
- package/lib/component/element/form/TextAreaField.jsx +0 -48
- package/lib/component/element/form/TextField.jsx +0 -65
- package/lib/component/element/form/formElementsCommon.jsx +0 -54
- package/lib/component/element/html/AccordionItem.jsx +0 -42
- package/lib/component/element/html/FolderSortableTree.jsx +0 -307
- package/lib/component/element/html/FormatNumeral.jsx +0 -118
- package/lib/component/element/html/Html.jsx +0 -107
- package/lib/component/element/html/LabelFromValue.jsx +0 -89
- package/lib/component/element/html/Modal.jsx +0 -77
- package/lib/component/element/html/ModalForm.jsx +0 -30
- package/lib/component/element/html/Paragraph.jsx +0 -10
- package/lib/component/element/html/PreformattedMarkup.jsx +0 -54
- package/lib/component/element/html/SortableTreeItemCollapseButton.jsx +0 -20
- package/lib/component/element/html/Tabs.jsx +0 -55
- package/lib/component/element/special/BootstrapElement.jsx +0 -32
- package/lib/component/element/special/Count.jsx +0 -46
- package/lib/component/element/special/DataFilter.jsx +0 -156
- package/lib/component/element/special/DelayedActions.jsx +0 -119
- package/lib/component/element/special/PageControls.jsx +0 -19
- package/lib/component/element/special/Phantom.jsx +0 -25
- package/lib/component/element/special/Switch.jsx +0 -131
- package/lib/component/hook/usePagination.jsx +0 -184
- package/lib/component/reaction/addData.jsx +0 -23
- package/lib/component/reaction/fetchData.jsx +0 -83
- package/lib/component/reaction/moveData.jsx +0 -52
- package/lib/component/reaction/postMessage.jsx +0 -43
- package/lib/component/reaction/redirectNow.jsx +0 -17
- package/lib/component/reaction/removeData.jsx +0 -48
- package/lib/component/reaction/setClipboardData.jsx +0 -20
- package/lib/component/reaction/setData.jsx +0 -23
- package/lib/component/reaction/submitData.jsx +0 -136
- package/lib/component/reaction/triggerEvent.jsx +0 -62
- package/lib/component/utility/formatString.jsx +0 -59
- package/lib/engine/Actions.jsx +0 -392
- package/lib/engine/ComponentCollector.js +0 -28
- package/lib/engine/EventDispatcherProvider.jsx +0 -80
- package/lib/engine/GlobalDataContextProvider.jsx +0 -33
- package/lib/engine/PaginationProvider.jsx +0 -61
- package/lib/engine/ReactiveJsonRoot.jsx +0 -318
- package/lib/engine/TemplateSystem.jsx +0 -302
- package/lib/engine/View.jsx +0 -248
- package/lib/main.jsx +0 -52
|
@@ -1,130 +0,0 @@
|
|
|
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;
|
|
@@ -1,48 +0,0 @@
|
|
|
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;
|
|
@@ -1,65 +0,0 @@
|
|
|
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;
|
|
@@ -1,54 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,42 +0,0 @@
|
|
|
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;
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
import ActionDependant from "../../../engine/Actions";
|
|
2
|
-
import GlobalDataContext from "../../../engine/GlobalDataContext";
|
|
3
|
-
import TemplateContext from "../../../engine/TemplateContext";
|
|
4
|
-
import {evaluateTemplateValue} from "../../../engine/TemplateSystem";
|
|
5
|
-
import View from "../../../engine/View";
|
|
6
|
-
import {propsDataLocationToPathAndValue} from "../form/formElementsCommon";
|
|
7
|
-
// clsx is included in dnd-kit-sortable-tree.
|
|
8
|
-
import clsx from "clsx";
|
|
9
|
-
import {FolderTreeItemWrapper} from "dnd-kit-sortable-tree";
|
|
10
|
-
import {SortableTree} from "dnd-kit-sortable-tree";
|
|
11
|
-
import {cloneDeep} from "lodash";
|
|
12
|
-
import React, {forwardRef, useContext} from "react";
|
|
13
|
-
|
|
14
|
-
const FolderSortableTree = ({props, path, datafield}) => {
|
|
15
|
-
const globalDataContext = useContext(GlobalDataContext);
|
|
16
|
-
const templateContext = useContext(TemplateContext);
|
|
17
|
-
|
|
18
|
-
let {
|
|
19
|
-
formData: treeData,
|
|
20
|
-
formDataPath: treeDataPath,
|
|
21
|
-
} = propsDataLocationToPathAndValue({
|
|
22
|
-
currentPath: path,
|
|
23
|
-
datafield: datafield,
|
|
24
|
-
dataLocation: props.dataLocation,
|
|
25
|
-
defaultValue: props.defaultFieldValue,
|
|
26
|
-
globalDataContext,
|
|
27
|
-
templateContext,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
if (treeData === undefined) {
|
|
31
|
-
// Empty tree data.
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Template (the usual structure given to View props) that will be used for each tree item.
|
|
37
|
-
*
|
|
38
|
-
* @type {*|null}
|
|
39
|
-
*/
|
|
40
|
-
const itemTemplate = props.itemTemplate ?? null;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* This value is needed when the user wants to limit the data rendered in this tree.
|
|
44
|
-
*
|
|
45
|
-
* @type {string|undefined|*}
|
|
46
|
-
*/
|
|
47
|
-
const treeRootPath = evaluateTemplateValue({
|
|
48
|
-
valueToEvaluate: props.treeRootPath ?? undefined,
|
|
49
|
-
globalDataContext,
|
|
50
|
-
templateContext
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Sets the maximum depth. Optional.
|
|
55
|
-
*
|
|
56
|
-
* "maxDepth" is not a native SortableTree option;
|
|
57
|
-
* that is why it is not under the sortableTreeOptions key.
|
|
58
|
-
* Please note that it will not fix the data until a drag and drop interaction.
|
|
59
|
-
*
|
|
60
|
-
* @type {number}
|
|
61
|
-
*/
|
|
62
|
-
const maxDepth = props.maxDepth;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Tells if the given maxDepth is expressed in absolute or relative base.
|
|
66
|
-
*
|
|
67
|
-
* If false, the maxDepth will be used to limit the depth relative to the tree root item
|
|
68
|
-
* determined by treeRootItem. If true, the depth will be limited starting from the root
|
|
69
|
-
* item given by treeData.
|
|
70
|
-
*
|
|
71
|
-
* @type {boolean}
|
|
72
|
-
*/
|
|
73
|
-
const maxDepthIsAbsolute = (typeof treeRootPath !== "string") ? true : (props.maxDepthIsAbsolute ?? true);
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Tells if we want to keep the base item when "treeRootPath" is defined.
|
|
77
|
-
*
|
|
78
|
-
* Set this to true to keep in the tree the item
|
|
79
|
-
* that "treeRootPath" (if set) will use as the tree root.
|
|
80
|
-
* When false, the base tree items will be the
|
|
81
|
-
* children of this base item instead.
|
|
82
|
-
*
|
|
83
|
-
* @type {boolean}
|
|
84
|
-
*/
|
|
85
|
-
const keepBaseItem = props.keepBaseItem ?? false;
|
|
86
|
-
|
|
87
|
-
/*
|
|
88
|
-
* Used by the max depth limiter and the trees filtered by treeRootPath.
|
|
89
|
-
*/
|
|
90
|
-
let baseDepth = 0;
|
|
91
|
-
|
|
92
|
-
/*
|
|
93
|
-
* Useful when the treeRootPath option is active.
|
|
94
|
-
* This is the item id that will be set back during the "onItemsChanged" event
|
|
95
|
-
* on the base elements.
|
|
96
|
-
*/
|
|
97
|
-
let baseParentId = null;
|
|
98
|
-
|
|
99
|
-
let baseItemIndex = undefined;
|
|
100
|
-
|
|
101
|
-
if (typeof treeRootPath === "string" && treeRootPath.length > 0) {
|
|
102
|
-
// A tree root path has been specified.
|
|
103
|
-
const pathSplitted = treeRootPath.split(".");
|
|
104
|
-
|
|
105
|
-
let baseParentId_previous = baseParentId;
|
|
106
|
-
let treeData_previous = treeData;
|
|
107
|
-
let treeDataPath_previous = treeDataPath;
|
|
108
|
-
|
|
109
|
-
while (pathSplitted.length > 0) {
|
|
110
|
-
const index = Number.parseInt(pathSplitted.shift());
|
|
111
|
-
|
|
112
|
-
if (Number.isNaN(index)) {
|
|
113
|
-
// This value is invalid. Do not even try to load the tree.
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// The "previous" values are used for the "keepBaseItem" option.
|
|
118
|
-
baseParentId_previous = treeData?.["id"] ?? null;
|
|
119
|
-
treeData_previous = treeData;
|
|
120
|
-
treeDataPath_previous = treeDataPath;
|
|
121
|
-
baseItemIndex = index;
|
|
122
|
-
|
|
123
|
-
baseParentId = treeData[index]?.["id"];
|
|
124
|
-
treeData = treeData[index]?.["children"] ?? undefined;
|
|
125
|
-
treeDataPath = treeDataPath + "." + index + ".children";
|
|
126
|
-
|
|
127
|
-
if (treeData === undefined) {
|
|
128
|
-
// No tree to render.
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
++baseDepth;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (keepBaseItem) {
|
|
136
|
-
// Use the "previous" values.
|
|
137
|
-
baseParentId = baseParentId_previous;
|
|
138
|
-
treeData = treeData_previous;
|
|
139
|
-
treeDataPath = treeDataPath_previous;
|
|
140
|
-
|
|
141
|
-
// Remove all items but the one identified by "indexToKeep".
|
|
142
|
-
// This item will be indexed at 0 for SortableTree.
|
|
143
|
-
treeData = [treeData[baseItemIndex]];
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const onItemsChanged = (e) => {
|
|
148
|
-
let finalData = e;
|
|
149
|
-
let finalDataPath = treeDataPath;
|
|
150
|
-
|
|
151
|
-
if (baseDepth > 0) {
|
|
152
|
-
// Fix the depths of all the items by adding baseDepth.
|
|
153
|
-
// Also fix the parentId if we have the treeRootPath option active.
|
|
154
|
-
finalData = cloneDeep(finalData);
|
|
155
|
-
|
|
156
|
-
const recursiveFixer = (it, currentDepth = 0) => {
|
|
157
|
-
if (currentDepth === 0) {
|
|
158
|
-
it.parentId = baseParentId;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
it.depth += baseDepth;
|
|
162
|
-
|
|
163
|
-
it.children?.forEach((child) => {
|
|
164
|
-
recursiveFixer(child, currentDepth + 1);
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
finalData.forEach((child) => {
|
|
169
|
-
recursiveFixer(child, 0);
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if ((treeRootPath !== undefined) && keepBaseItem) {
|
|
174
|
-
// We are in a partial tree configuration,
|
|
175
|
-
// and this tree has the base item kept in the hierarchy.
|
|
176
|
-
// Fix the data and paths.
|
|
177
|
-
// We take the first and only item.
|
|
178
|
-
finalData = e[0];
|
|
179
|
-
finalDataPath = treeDataPath + "." + baseItemIndex;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
globalDataContext.updateData(finalData, finalDataPath);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const GenericTreeItemComponent = forwardRef((props, ref) => {
|
|
186
|
-
const finalCurrentData = props.item.value ?? {};
|
|
187
|
-
|
|
188
|
-
// Rebuild the data path by inspecting the parents.
|
|
189
|
-
const parentsIndices = [];
|
|
190
|
-
|
|
191
|
-
let itemToInspect = props.item;
|
|
192
|
-
parentsIndices.push(itemToInspect.index);
|
|
193
|
-
|
|
194
|
-
while (itemToInspect.parent) {
|
|
195
|
-
parentsIndices.push("children");
|
|
196
|
-
itemToInspect = itemToInspect.parent;
|
|
197
|
-
parentsIndices.push(itemToInspect.index);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Reverse the order.
|
|
201
|
-
parentsIndices.reverse();
|
|
202
|
-
|
|
203
|
-
// This is the path leading to the "value" key excluded.
|
|
204
|
-
const finalValuePath = treeDataPath + "." + parentsIndices.join(".");
|
|
205
|
-
|
|
206
|
-
// This is the full path, "value" included.
|
|
207
|
-
const finalDataPath = finalValuePath + ".value";
|
|
208
|
-
|
|
209
|
-
finalCurrentData._treeItemDepth = props.item.depth;
|
|
210
|
-
finalCurrentData._treeItemIndex = props.item.index;
|
|
211
|
-
finalCurrentData._treeItemIndex1 = props.item.index + 1;
|
|
212
|
-
|
|
213
|
-
// Put the collapse button into the template data.
|
|
214
|
-
// This is the stylable button which serves as a collapse switch.
|
|
215
|
-
// The implementation is taken directly from the FolderTreeItemWrapper component.
|
|
216
|
-
// We can then include the collapse button in the item
|
|
217
|
-
// thanks to the SortableTreeItemCollapseButton component.
|
|
218
|
-
const sortableTreeData = {};
|
|
219
|
-
|
|
220
|
-
sortableTreeData._treeAddCollapseButton = () => (
|
|
221
|
-
!!props.onCollapse && !!props.childCount &&
|
|
222
|
-
<button
|
|
223
|
-
onClick={(e) => {
|
|
224
|
-
e.preventDefault();
|
|
225
|
-
props.onCollapse?.();
|
|
226
|
-
}}
|
|
227
|
-
className={clsx(
|
|
228
|
-
'dnd-sortable-tree_folder_tree-item-collapse_button',
|
|
229
|
-
props.collapsed &&
|
|
230
|
-
'dnd-sortable-tree_folder_tree-item-collapse_button-collapsed'
|
|
231
|
-
)}/>
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
if (maxDepth) {
|
|
235
|
-
// A maximum depth has been defined for this tree.
|
|
236
|
-
if (maxDepthIsAbsolute) {
|
|
237
|
-
props.item.canHaveChildren = (baseDepth + props.item.depth) < maxDepth;
|
|
238
|
-
} else {
|
|
239
|
-
props.item.canHaveChildren = (props.item.depth) < maxDepth;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return (
|
|
244
|
-
<FolderTreeItemWrapper
|
|
245
|
-
{...props}
|
|
246
|
-
data-htmlbuilder-tree-item-children-count={props.childCount || "0"}
|
|
247
|
-
data-htmlbuilder-tree-item-collapsed={props.collapsed}
|
|
248
|
-
data-htmlbuilder-tree-item-depth={props.item.depth}
|
|
249
|
-
data-htmlbuilder-tree-item-depth-list={getDepthAsList(props.item.depth)}
|
|
250
|
-
data-htmlbuilder-tree-item-index={props.item.index}
|
|
251
|
-
data-htmlbuilder-tree-item-index1={props.item.index + 1}
|
|
252
|
-
data-htmlbuilder-tree-item-is-last={props.isLast}
|
|
253
|
-
ref={ref}>
|
|
254
|
-
<TemplateContext.Provider value={{
|
|
255
|
-
templateData: finalCurrentData,
|
|
256
|
-
templatePath: finalDataPath,
|
|
257
|
-
sortableTreeData: sortableTreeData
|
|
258
|
-
}}>
|
|
259
|
-
<View
|
|
260
|
-
props={itemTemplate}
|
|
261
|
-
currentData={finalCurrentData}
|
|
262
|
-
/>
|
|
263
|
-
</TemplateContext.Provider>
|
|
264
|
-
</FolderTreeItemWrapper>
|
|
265
|
-
);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// Deep copy because SortableTree seems to directly edit the data.
|
|
269
|
-
const clone = cloneDeep(treeData);
|
|
270
|
-
|
|
271
|
-
// Additional properties for SortableTree.
|
|
272
|
-
const sortableTreeOptions = props.sortableTreeOptions ?? {};
|
|
273
|
-
|
|
274
|
-
return (
|
|
275
|
-
<ActionDependant {...props}>
|
|
276
|
-
<SortableTree
|
|
277
|
-
{...sortableTreeOptions}
|
|
278
|
-
items={clone}
|
|
279
|
-
onItemsChanged={onItemsChanged}
|
|
280
|
-
TreeItemComponent={GenericTreeItemComponent}/>
|
|
281
|
-
</ActionDependant>
|
|
282
|
-
);
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Builds a list of depths such as 4 => "0 1 2 3 4".
|
|
287
|
-
*
|
|
288
|
-
* This can be used as an attribute value, for the CSS word selector "~=".
|
|
289
|
-
* E.g.: [data-htmlbuilder-tree-item-depth-list~=3].
|
|
290
|
-
*
|
|
291
|
-
* @param {int} itemDepth The item depth.
|
|
292
|
-
*
|
|
293
|
-
* @returns {string} The string of depths.
|
|
294
|
-
*/
|
|
295
|
-
function getDepthAsList(itemDepth) {
|
|
296
|
-
const depthAsList = [];
|
|
297
|
-
let remainingDepth = itemDepth ?? 0;
|
|
298
|
-
|
|
299
|
-
while (remainingDepth >= 0) {
|
|
300
|
-
depthAsList.push(remainingDepth);
|
|
301
|
-
--remainingDepth;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
return depthAsList.reverse().join(" ");
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
export default FolderSortableTree;
|