@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,66 +0,0 @@
|
|
|
1
|
-
import {useContext, useEffect} from "react";
|
|
2
|
-
import {reactionFunctions} from "./ReactOnEvent";
|
|
3
|
-
import EventDispatcherContext from "../../engine/EventDispatcherContext";
|
|
4
|
-
import GlobalDataContext from "../../engine/GlobalDataContext";
|
|
5
|
-
import TemplateContext from "../../engine/TemplateContext";
|
|
6
|
-
import {evaluateTemplateValueCollection} from "../../engine/TemplateSystem";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Listens to hash changes (URL fragment) on the window object and executes a reaction function in response.
|
|
10
|
-
*
|
|
11
|
-
* @param {{}} props
|
|
12
|
-
* @returns {JSX.Element}
|
|
13
|
-
* @constructor
|
|
14
|
-
*/
|
|
15
|
-
const HashChangeListener = (props) => {
|
|
16
|
-
const eventDispatcherContext = useContext(EventDispatcherContext);
|
|
17
|
-
const globalDataContext = useContext(GlobalDataContext);
|
|
18
|
-
const templateContext = useContext(TemplateContext);
|
|
19
|
-
|
|
20
|
-
const actionProps = props?.actionProps ?? undefined;
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
const payload = actionProps ?? undefined;
|
|
24
|
-
const functionToCall = actionProps?.what ?? undefined;
|
|
25
|
-
const whenHashIs = actionProps?.whenHashIs ?? undefined;
|
|
26
|
-
const whenHashWas = actionProps?.whenHashWas ?? undefined;
|
|
27
|
-
|
|
28
|
-
const whenHashIs_evaluated = evaluateTemplateValueCollection({
|
|
29
|
-
globalDataContext,
|
|
30
|
-
templateContext,
|
|
31
|
-
valueToEvaluate: whenHashIs
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const whenHashWas_evaluated = evaluateTemplateValueCollection({
|
|
35
|
-
globalDataContext,
|
|
36
|
-
templateContext,
|
|
37
|
-
valueToEvaluate: whenHashWas
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const listener = (event) => {
|
|
41
|
-
// The hash contains the '#' character.
|
|
42
|
-
if (typeof whenHashIs_evaluated === "string" && ((new URL(event.newUrl)).hash !== whenHashIs_evaluated)) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (typeof whenHashWas_evaluated === "string" && ((new URL(event.oldUrl)).hash !== whenHashIs_evaluated)) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const toCall = functionToCall && (reactionFunctions[functionToCall] ?? undefined);
|
|
51
|
-
|
|
52
|
-
toCall && toCall({args: payload, event, globalDataContext, templateContext});
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Dev note: we use a context to prevent adding too many real event listeners which would slow down the build.
|
|
56
|
-
eventDispatcherContext?.addEventListener("hashchange", listener);
|
|
57
|
-
|
|
58
|
-
return () => {
|
|
59
|
-
eventDispatcherContext?.removeEventListener("hashchange", listener);
|
|
60
|
-
};
|
|
61
|
-
}, [eventDispatcherContext, globalDataContext, actionProps, templateContext]);
|
|
62
|
-
|
|
63
|
-
return <>{props.children}</>;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export default HashChangeListener;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import {useContext, useEffect} from "react";
|
|
2
|
-
import {reactionFunctions} from "./ReactOnEvent";
|
|
3
|
-
import EventDispatcherContext from "../../engine/EventDispatcherContext";
|
|
4
|
-
import GlobalDataContext from "../../engine/GlobalDataContext";
|
|
5
|
-
import TemplateContext from "../../engine/TemplateContext";
|
|
6
|
-
import {evaluateTemplateValueCollection} from "../../engine/TemplateSystem";
|
|
7
|
-
import {isEqual} from "lodash";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Listens to messages on the window object and executes a reaction function in response.
|
|
11
|
-
*
|
|
12
|
-
* @param {{}} props
|
|
13
|
-
* @returns {JSX.Element}
|
|
14
|
-
* @constructor
|
|
15
|
-
*/
|
|
16
|
-
const MessageListener = (props) => {
|
|
17
|
-
const eventDispatcherContext = useContext(EventDispatcherContext);
|
|
18
|
-
const globalDataContext = useContext(GlobalDataContext);
|
|
19
|
-
const templateContext = useContext(TemplateContext);
|
|
20
|
-
|
|
21
|
-
const actionProps = props?.actionProps ?? undefined;
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
const payload = actionProps ?? undefined;
|
|
25
|
-
const functionToCall = actionProps?.what ?? undefined;
|
|
26
|
-
const whenMessageIs = actionProps?.whenMessageIs ?? undefined;
|
|
27
|
-
|
|
28
|
-
const whenMessageIs_evaluated = evaluateTemplateValueCollection({
|
|
29
|
-
globalDataContext,
|
|
30
|
-
templateContext,
|
|
31
|
-
valueToEvaluate: whenMessageIs
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const listener = (event) => {
|
|
35
|
-
if (event.origin !== window.location.origin) {
|
|
36
|
-
// The message is not allowed because it targets an unknown origin.
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// The "event.data" is supposed to be already evaluated.
|
|
41
|
-
// Use lodash's isEqual to compare the values properly (deep compare for objects).
|
|
42
|
-
if (!isEqual(event.data, whenMessageIs_evaluated)) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const toCall = functionToCall && (reactionFunctions[functionToCall] ?? undefined);
|
|
47
|
-
|
|
48
|
-
toCall && toCall({args: payload, event, globalDataContext, templateContext});
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Dev note: we use a context to prevent adding too many real event listeners which would slow down the build.
|
|
52
|
-
eventDispatcherContext?.addEventListener("message", listener);
|
|
53
|
-
|
|
54
|
-
return () => {
|
|
55
|
-
eventDispatcherContext?.removeEventListener("message", listener);
|
|
56
|
-
};
|
|
57
|
-
}, [eventDispatcherContext, globalDataContext, actionProps, templateContext]);
|
|
58
|
-
|
|
59
|
-
return <>{props.children}</>;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export default MessageListener;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Action which will append a popover when the current component is hovered.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {OverlayTrigger, Popover as BsPopover} from "react-bootstrap";
|
|
6
|
-
import View from "../../engine/View";
|
|
7
|
-
import {useEvaluatedAttributes} from "../../engine/TemplateSystem";
|
|
8
|
-
import {useRef} from "react";
|
|
9
|
-
|
|
10
|
-
const Popover = (props) => {
|
|
11
|
-
// We use the React Bootstrap Popover component. It works like the Tooltip component.
|
|
12
|
-
// It requires an OverlayTrigger wrapping component that handles the hover interaction.
|
|
13
|
-
// The OverlayTrigger child must be able to get a "ref" (as in react refs),
|
|
14
|
-
// So we wrap the children in a custom HTML tag (popover-reference) to be sure it will work.
|
|
15
|
-
const bodyAttrs = useEvaluatedAttributes(props.actionProps.bodyAttributes || {});
|
|
16
|
-
const headerAttrs = useEvaluatedAttributes(props.actionProps.headerAttributes || {});
|
|
17
|
-
|
|
18
|
-
// This ref is used to help building complex structures like popovers inside modals.
|
|
19
|
-
// Without this, the popover will show behind the modal instead of being in front.
|
|
20
|
-
// It is usually expected to have the popover over the modal, but if we don't want
|
|
21
|
-
// this effect for a specific case, we should make this configurable to not set
|
|
22
|
-
// the ref.
|
|
23
|
-
const containerRef = useRef(null);
|
|
24
|
-
|
|
25
|
-
return <div ref={containerRef}>
|
|
26
|
-
<OverlayTrigger
|
|
27
|
-
container={containerRef}
|
|
28
|
-
placement={props.actionProps.placement ?? "top"}
|
|
29
|
-
trigger={props.actionProps.trigger ?? "click"}
|
|
30
|
-
overlay={<BsPopover>
|
|
31
|
-
{props.actionProps.header && <BsPopover.Header {...headerAttrs}>
|
|
32
|
-
<View
|
|
33
|
-
props={props.actionProps.header}
|
|
34
|
-
currentData={props.componentProps?.currentData?.actions?.[props.actionIndex]?.header ?? undefined}
|
|
35
|
-
datafield={"header"}
|
|
36
|
-
path={props.componentProps.path + ".actions." + props.actionIndex + ".header"}
|
|
37
|
-
/>
|
|
38
|
-
</BsPopover.Header>}
|
|
39
|
-
<BsPopover.Body {...bodyAttrs}>
|
|
40
|
-
<View
|
|
41
|
-
props={props.actionProps.body}
|
|
42
|
-
currentData={props.componentProps?.currentData?.actions?.[props.actionIndex]?.body ?? undefined}
|
|
43
|
-
datafield={"body"}
|
|
44
|
-
path={props.componentProps.path + ".actions." + props.actionIndex + ".body"}
|
|
45
|
-
/>
|
|
46
|
-
</BsPopover.Body>
|
|
47
|
-
</BsPopover>}>
|
|
48
|
-
<popover-reference>{props.children}</popover-reference>
|
|
49
|
-
</OverlayTrigger>
|
|
50
|
-
</div>;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export default Popover;
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import {Children, cloneElement, Fragment, isValidElement, useContext} from "react";
|
|
2
|
-
import GlobalDataContext from "../../engine/GlobalDataContext";
|
|
3
|
-
import TemplateContext from "../../engine/TemplateContext";
|
|
4
|
-
import {addData} from "../reaction/addData";
|
|
5
|
-
import {fetchData} from "../reaction/fetchData";
|
|
6
|
-
import {moveData} from "../reaction/moveData";
|
|
7
|
-
import {postMessage} from "../reaction/postMessage";
|
|
8
|
-
import {redirectNow} from "../reaction/redirectNow";
|
|
9
|
-
import {removeData} from "../reaction/removeData";
|
|
10
|
-
import {setData} from "../reaction/setData";
|
|
11
|
-
import {submitData} from "../reaction/submitData";
|
|
12
|
-
import {triggerEvent} from "../reaction/triggerEvent";
|
|
13
|
-
import {setClipboardData} from "../reaction/setClipboardData";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Functions that will be executed on specific events.
|
|
17
|
-
*
|
|
18
|
-
* @type {{}}
|
|
19
|
-
*/
|
|
20
|
-
export const reactionFunctions = {
|
|
21
|
-
addData,
|
|
22
|
-
fetchData,
|
|
23
|
-
moveData,
|
|
24
|
-
postMessage,
|
|
25
|
-
redirectNow,
|
|
26
|
-
removeData,
|
|
27
|
-
setClipboardData,
|
|
28
|
-
setData,
|
|
29
|
-
submitData,
|
|
30
|
-
triggerEvent,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Action component which will append one or more event listeners on the element.
|
|
35
|
-
*
|
|
36
|
-
* @param {Object} props
|
|
37
|
-
*
|
|
38
|
-
* @constructor
|
|
39
|
-
*/
|
|
40
|
-
const ReactOnEvent = (props) => {
|
|
41
|
-
const globalDataContext = useContext(GlobalDataContext);
|
|
42
|
-
const templateContext = useContext(TemplateContext);
|
|
43
|
-
|
|
44
|
-
const {actionProps: reactionFunctionProps} = props;
|
|
45
|
-
|
|
46
|
-
// Event attributes to inject.
|
|
47
|
-
const eventPropsForAttributes = {};
|
|
48
|
-
|
|
49
|
-
for (const [eventName, eventReactionFunctionProps] of Object.entries(reactionFunctionProps)) {
|
|
50
|
-
// Prepare the callback.
|
|
51
|
-
// There will be 1 callback per eventName.
|
|
52
|
-
// Each callback will have a list of objects, each object representing 1 reaction function call.
|
|
53
|
-
eventPropsForAttributes[eventName] = (event) => {
|
|
54
|
-
let lastStopPropagation = true;
|
|
55
|
-
|
|
56
|
-
for (const singleReactionFunctionProps of eventReactionFunctionProps) {
|
|
57
|
-
// singleReactionFunctionProps is the object containing info from the data structure.
|
|
58
|
-
if (!singleReactionFunctionProps) {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const reactionFunction = singleReactionFunctionProps.what && (reactionFunctions[singleReactionFunctionProps.what] ?? null);
|
|
63
|
-
|
|
64
|
-
if (!reactionFunction) {
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Call the reaction function with the props, the event details, and context data.
|
|
69
|
-
reactionFunction({args: singleReactionFunctionProps, event, globalDataContext, templateContext});
|
|
70
|
-
|
|
71
|
-
if (singleReactionFunctionProps.stopPropagation === true) {
|
|
72
|
-
// Stop executing reaction functions of this event early.
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
lastStopPropagation = singleReactionFunctionProps.stopPropagation ?? true;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (lastStopPropagation !== false) {
|
|
80
|
-
// Stop propagation unless "stopPropagation" is explicitly set on false.
|
|
81
|
-
// Stopping the propagation is the default behavior.
|
|
82
|
-
event.stopPropagation();
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Recreate the component with the event attributes.
|
|
88
|
-
// The recursive map is required because the item can be nested into a React.Fragment,
|
|
89
|
-
// and we want to add the attributes on the "real" element.
|
|
90
|
-
const recursiveMap = (children) => {
|
|
91
|
-
if (!children) {
|
|
92
|
-
return children;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const childrenArray = Children.toArray(children);
|
|
96
|
-
|
|
97
|
-
return Children.map(childrenArray, child => {
|
|
98
|
-
if (child.type === Fragment) {
|
|
99
|
-
// Dig deeper.
|
|
100
|
-
return recursiveMap(child?.props?.children);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (typeof child !== 'object' || !isValidElement(child)) {
|
|
104
|
-
// Not a React element that can welcome attributes.
|
|
105
|
-
return child;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Clone the element and append the attributes.
|
|
109
|
-
return cloneElement(child, eventPropsForAttributes);
|
|
110
|
-
});
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const clonedChild = recursiveMap(props.children);
|
|
114
|
-
|
|
115
|
-
return <>{clonedChild}</>;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
export default ReactOnEvent;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import {evaluateTemplateValue} from "../../engine/TemplateSystem";
|
|
2
|
-
import {useContext} from "react";
|
|
3
|
-
import GlobalDataContext from "../../engine/GlobalDataContext";
|
|
4
|
-
import TemplateContext from "../../engine/TemplateContext";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Redirects when the conditions are valid.
|
|
8
|
-
*
|
|
9
|
-
* @param {{actionProps: {to}}} props Action props.
|
|
10
|
-
*
|
|
11
|
-
* @constructor
|
|
12
|
-
*/
|
|
13
|
-
const Redirect = (props) => {
|
|
14
|
-
const globalDataContext = useContext(GlobalDataContext);
|
|
15
|
-
const templateContext = useContext(TemplateContext);
|
|
16
|
-
|
|
17
|
-
const {to} = props.actionProps;
|
|
18
|
-
|
|
19
|
-
if (!to || typeof to !== "string") {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
window.location.href = evaluateTemplateValue({valueToEvaluate: to, globalDataContext, templateContext});
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default Redirect;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Action which will append a tooltip when the current component is hovered.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {OverlayTrigger, Tooltip as BsTooltip} from "react-bootstrap";
|
|
6
|
-
import View from "../../engine/View";
|
|
7
|
-
|
|
8
|
-
const Tooltip = (props) => {
|
|
9
|
-
// We use the React Bootstrap Tooltip component.
|
|
10
|
-
// It requires an OverlayTrigger wrapping component that handles the hover interaction.
|
|
11
|
-
// The OverlayTrigger child must be able to get a "ref" (as in react refs),
|
|
12
|
-
// So we wrap the children in a custom HTML tag (tooltip-reference) to be sure it will work.
|
|
13
|
-
return <OverlayTrigger
|
|
14
|
-
placement={props.actionProps.placement ?? "top"}
|
|
15
|
-
overlay={<BsTooltip>
|
|
16
|
-
<View
|
|
17
|
-
props={props.actionProps.content}
|
|
18
|
-
currentData={props.componentProps?.currentData?.actions?.[props.actionIndex] ?? undefined}
|
|
19
|
-
datafield={props.actionIndex}
|
|
20
|
-
path={props.componentProps.path + ".actions." + props.actionIndex}
|
|
21
|
-
/>
|
|
22
|
-
</BsTooltip>}>
|
|
23
|
-
<tooltip-reference>{props.children}</tooltip-reference>
|
|
24
|
-
</OverlayTrigger>;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default Tooltip;
|
|
@@ -1,215 +0,0 @@
|
|
|
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;
|
|
@@ -1,42 +0,0 @@
|
|
|
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;
|
|
@@ -1,29 +0,0 @@
|
|
|
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;
|