2021-05-09 18:06:11 +00:00
|
|
|
import React, { useRef, useState, useEffect } from 'react';
|
2021-05-10 07:59:17 +00:00
|
|
|
import { default as BootstrapModal } from 'react-bootstrap/Modal';
|
2021-05-09 18:06:11 +00:00
|
|
|
import { SubCustomDragLayer } from '../SubCustomDragLayer';
|
|
|
|
|
import { SubContainer } from '../SubContainer';
|
2021-05-10 13:44:58 +00:00
|
|
|
import { ConfigHandle } from '../ConfigHandle';
|
2022-09-26 10:16:21 +00:00
|
|
|
var tinycolor = require('tinycolor2');
|
2021-05-09 18:06:11 +00:00
|
|
|
|
2021-12-15 04:23:57 +00:00
|
|
|
export const Modal = function Modal({
|
|
|
|
|
id,
|
|
|
|
|
component,
|
|
|
|
|
height,
|
|
|
|
|
containerProps,
|
|
|
|
|
darkMode,
|
|
|
|
|
properties,
|
|
|
|
|
styles,
|
|
|
|
|
exposedVariables,
|
|
|
|
|
setExposedVariable,
|
2022-07-14 12:56:53 +00:00
|
|
|
registerAction,
|
2022-09-26 10:16:21 +00:00
|
|
|
fireEvent,
|
2023-01-24 09:33:45 +00:00
|
|
|
dataCy,
|
2021-12-15 04:23:57 +00:00
|
|
|
}) {
|
|
|
|
|
const [showModal, setShowModal] = useState(false);
|
2022-09-26 10:16:21 +00:00
|
|
|
const { hideOnEsc, hideCloseButton, hideTitleBar, loadingState, useDefaultButton, triggerButtonLabel } = properties;
|
|
|
|
|
const {
|
|
|
|
|
headerBackgroundColor,
|
|
|
|
|
headerTextColor,
|
|
|
|
|
bodyBackgroundColor,
|
|
|
|
|
disabledState,
|
|
|
|
|
visibility,
|
|
|
|
|
triggerButtonBackgroundColor,
|
|
|
|
|
triggerButtonTextColor,
|
|
|
|
|
} = styles;
|
2021-05-09 18:06:11 +00:00
|
|
|
const parentRef = useRef(null);
|
|
|
|
|
|
2021-12-15 04:23:57 +00:00
|
|
|
const title = properties.title ?? '';
|
|
|
|
|
const size = properties.size ?? 'lg';
|
2021-05-10 07:59:17 +00:00
|
|
|
|
2022-09-27 05:25:51 +00:00
|
|
|
registerAction(
|
|
|
|
|
'open',
|
|
|
|
|
async function () {
|
|
|
|
|
setExposedVariable('show', true);
|
|
|
|
|
setShowModal(true);
|
|
|
|
|
},
|
|
|
|
|
[setShowModal]
|
|
|
|
|
);
|
|
|
|
|
registerAction(
|
|
|
|
|
'close',
|
|
|
|
|
async function () {
|
|
|
|
|
setShowModal(false);
|
|
|
|
|
setExposedVariable('show', false);
|
|
|
|
|
},
|
|
|
|
|
[setShowModal]
|
|
|
|
|
);
|
2022-07-14 12:56:53 +00:00
|
|
|
|
2022-09-26 10:16:21 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (exposedVariables.show !== showModal) {
|
|
|
|
|
setExposedVariable('show', showModal).then(() => fireEvent(showModal ? 'onOpen' : 'onClose'));
|
|
|
|
|
}
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, [showModal]);
|
|
|
|
|
|
2021-05-09 18:06:11 +00:00
|
|
|
useEffect(() => {
|
2021-12-15 04:23:57 +00:00
|
|
|
const canShowModal = exposedVariables.show ?? false;
|
2022-09-26 10:16:21 +00:00
|
|
|
if (canShowModal !== showModal) {
|
|
|
|
|
setShowModal(canShowModal);
|
|
|
|
|
fireEvent(canShowModal ? 'onOpen' : 'onClose');
|
|
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2021-12-15 04:23:57 +00:00
|
|
|
}, [exposedVariables.show]);
|
2021-05-09 18:06:11 +00:00
|
|
|
|
|
|
|
|
function hideModal() {
|
2021-12-15 04:23:57 +00:00
|
|
|
setShowModal(false);
|
2021-05-09 18:06:11 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-26 10:16:21 +00:00
|
|
|
const customStyles = {
|
|
|
|
|
modalBody: {
|
|
|
|
|
height,
|
|
|
|
|
backgroundColor:
|
|
|
|
|
['#fff', '#ffffffff'].includes(bodyBackgroundColor) && darkMode ? '#1F2837' : bodyBackgroundColor,
|
|
|
|
|
overflowX: 'hidden',
|
|
|
|
|
overflowY: 'auto',
|
|
|
|
|
},
|
|
|
|
|
modalHeader: {
|
|
|
|
|
backgroundColor:
|
|
|
|
|
['#fff', '#ffffffff'].includes(headerBackgroundColor) && darkMode ? '#1F2837' : headerBackgroundColor,
|
|
|
|
|
color: ['#000', '#000000', '#000000ff'].includes(headerTextColor) && darkMode ? '#fff' : headerTextColor,
|
|
|
|
|
},
|
|
|
|
|
buttonStyles: {
|
|
|
|
|
backgroundColor: triggerButtonBackgroundColor,
|
|
|
|
|
color: triggerButtonTextColor,
|
|
|
|
|
width: '100%',
|
|
|
|
|
display: visibility ? '' : 'none',
|
|
|
|
|
'--tblr-btn-color-darker': tinycolor(triggerButtonBackgroundColor).darken(8).toString(),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (containerProps.mode === 'view') {
|
|
|
|
|
const handleClickOutside = (event) => {
|
|
|
|
|
const modalRef = parentRef.current.parentElement.parentElement.parentElement;
|
|
|
|
|
|
|
|
|
|
if (modalRef && modalRef === event.target) {
|
|
|
|
|
hideModal();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
|
return () => {
|
|
|
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}, [containerProps.mode, parentRef]);
|
|
|
|
|
|
2021-05-09 18:06:11 +00:00
|
|
|
return (
|
2023-01-24 09:33:45 +00:00
|
|
|
<div className="container" data-disabled={disabledState} data-cy={dataCy}>
|
2022-09-26 10:16:21 +00:00
|
|
|
{useDefaultButton && (
|
|
|
|
|
<button
|
|
|
|
|
disabled={disabledState}
|
|
|
|
|
className="jet-button btn btn-primary p-1 overflow-hidden"
|
|
|
|
|
style={customStyles.buttonStyles}
|
|
|
|
|
onClick={(event) => {
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
setShowModal(true);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{triggerButtonLabel ?? 'Show Modal'}
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Modal.Component
|
2021-12-15 04:23:57 +00:00
|
|
|
show={showModal}
|
2022-09-26 10:16:21 +00:00
|
|
|
contentClassName="modal-component"
|
2021-05-10 09:28:44 +00:00
|
|
|
container={document.getElementsByClassName('canvas-area')[0]}
|
2021-05-10 07:59:17 +00:00
|
|
|
size={size}
|
|
|
|
|
keyboard={true}
|
2021-05-10 09:29:21 +00:00
|
|
|
enforceFocus={false}
|
2021-05-09 18:06:11 +00:00
|
|
|
animation={false}
|
2022-07-04 09:13:36 +00:00
|
|
|
onEscapeKeyDown={() => hideOnEsc && hideModal()}
|
2022-08-24 21:26:08 +00:00
|
|
|
id="modal-container"
|
2022-09-26 10:16:21 +00:00
|
|
|
backdrop={'static'}
|
|
|
|
|
scrollable={true}
|
|
|
|
|
modalProps={{
|
|
|
|
|
customStyles,
|
|
|
|
|
parentRef,
|
|
|
|
|
id,
|
|
|
|
|
title,
|
|
|
|
|
hideTitleBar,
|
|
|
|
|
hideCloseButton,
|
|
|
|
|
hideModal,
|
|
|
|
|
component,
|
|
|
|
|
showConfigHandler: containerProps.mode === 'edit',
|
|
|
|
|
removeComponent: containerProps.removeComponent,
|
|
|
|
|
setSelected: containerProps.setSelectedComponent,
|
|
|
|
|
}}
|
2021-05-09 18:06:11 +00:00
|
|
|
>
|
2022-09-26 10:16:21 +00:00
|
|
|
{!loadingState ? (
|
|
|
|
|
<>
|
2022-10-21 08:21:32 +00:00
|
|
|
<SubContainer parent={id} {...containerProps} parentRef={parentRef} />
|
2022-09-26 10:16:21 +00:00
|
|
|
<SubCustomDragLayer
|
|
|
|
|
snapToGrid={true}
|
|
|
|
|
parentRef={parentRef}
|
|
|
|
|
parent={id}
|
|
|
|
|
currentLayout={containerProps.currentLayout}
|
|
|
|
|
/>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="p-2">
|
|
|
|
|
<center>
|
|
|
|
|
<div className="spinner-border mt-5" role="status"></div>
|
|
|
|
|
</center>
|
|
|
|
|
</div>
|
2022-07-04 09:13:36 +00:00
|
|
|
)}
|
2022-09-26 10:16:21 +00:00
|
|
|
</Modal.Component>
|
2021-05-09 18:06:11 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
2022-09-26 10:16:21 +00:00
|
|
|
|
|
|
|
|
const Component = ({ children, ...restProps }) => {
|
|
|
|
|
const {
|
|
|
|
|
customStyles,
|
|
|
|
|
parentRef,
|
|
|
|
|
id,
|
|
|
|
|
title,
|
|
|
|
|
hideTitleBar,
|
|
|
|
|
hideCloseButton,
|
|
|
|
|
hideModal,
|
|
|
|
|
component,
|
|
|
|
|
showConfigHandler,
|
|
|
|
|
removeComponent,
|
|
|
|
|
setSelected,
|
|
|
|
|
} = restProps['modalProps'];
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<BootstrapModal {...restProps}>
|
|
|
|
|
{showConfigHandler && (
|
|
|
|
|
<ConfigHandle
|
|
|
|
|
id={id}
|
|
|
|
|
component={component}
|
|
|
|
|
removeComponent={removeComponent}
|
|
|
|
|
setSelectedComponent={setSelected} //! Only Modal uses setSelectedComponent instead of selecto lib
|
|
|
|
|
customClassName={hideTitleBar ? 'modalWidget-config-handle' : ''}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{!hideTitleBar && (
|
|
|
|
|
<BootstrapModal.Header style={{ ...customStyles.modalHeader }}>
|
|
|
|
|
<BootstrapModal.Title id="contained-modal-title-vcenter">{title}</BootstrapModal.Title>
|
|
|
|
|
{!hideCloseButton && (
|
|
|
|
|
<span className="cursor-pointer" size="sm" onClick={() => hideModal()}>
|
|
|
|
|
<svg
|
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
className="icon icon-tabler icon-tabler-x"
|
|
|
|
|
width="24"
|
|
|
|
|
height="24"
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
strokeWidth="2"
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
fill="none"
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
>
|
|
|
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
|
|
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
|
|
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
|
|
|
</svg>
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</BootstrapModal.Header>
|
|
|
|
|
)}
|
|
|
|
|
<BootstrapModal.Body style={{ ...customStyles.modalBody }} ref={parentRef} id={id}>
|
|
|
|
|
{children}
|
|
|
|
|
</BootstrapModal.Body>
|
|
|
|
|
</BootstrapModal>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Modal.Component = Component;
|