move showModal helper into its own pack file (#17266)

This commit is contained in:
Suzanne Aitchison 2022-04-13 14:15:07 +01:00 committed by GitHub
parent 240893401d
commit 64ed2c6dec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 51 deletions

View file

@ -5,11 +5,9 @@ import {
initializeMemberMenu,
} from '../topNavigation/utilities';
import { waitOnBaseData } from '../utilities/waitOnBaseData';
import { showWindowModal, closeWindowModal } from '@utilities/showModal';
import * as Runtime from '@utilities/runtime';
// Unique ID applied to modals created using window.Forem.showModal
const WINDOW_MODAL_ID = 'window-modal';
// Namespace for functions which need to be accessed in plain JS initializers
window.Forem = {
preactImport: undefined,
@ -53,54 +51,8 @@ window.Forem = {
originalTextArea,
);
},
modalImports: undefined,
getModalImports() {
if (!this.modalImports) {
this.modalImports = [import('@crayons/Modal'), this.getPreactImport()];
}
return Promise.all(this.modalImports);
},
showModal: async ({ title, contentSelector, size = 'small', onOpen }) => {
const [{ Modal }, { render, h }] = await window.Forem.getModalImports();
// Guard against two modals being opened at once
let currentModalContainer = document.getElementById(WINDOW_MODAL_ID);
if (currentModalContainer) {
render(null, currentModalContainer);
} else {
currentModalContainer = document.createElement('div');
currentModalContainer.setAttribute('id', WINDOW_MODAL_ID);
document.body.appendChild(currentModalContainer);
}
render(
<Modal
title={title}
onClose={() => {
render(null, currentModalContainer);
}}
size={size}
focusTrapSelector={`#${WINDOW_MODAL_ID}`}
>
<div
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: document.querySelector(contentSelector).innerHTML,
}}
/>
</Modal>,
currentModalContainer,
);
onOpen?.();
},
closeModal: async () => {
const currentModalContainer = document.getElementById(WINDOW_MODAL_ID);
if (currentModalContainer) {
const { render } = await window.Forem.getPreactImport();
render(null, currentModalContainer);
}
},
showModal: showWindowModal,
closeModal: closeWindowModal,
Runtime,
};

View file

@ -0,0 +1,81 @@
// Unique ID applied to modals created using the showWindowModal function
const WINDOW_MODAL_ID = 'window-modal';
// We only import these modules if a user actually triggers a modal. Here we cache them so they are only imported once.
let preactImport;
let modalImports;
const getPreactImport = () => {
if (!preactImport) {
preactImport = import('preact');
}
return preactImport;
};
const getModalImports = () => {
if (!modalImports) {
modalImports = [import('@crayons/Modal'), getPreactImport()];
}
return Promise.all(modalImports);
};
/**
* This helper function finds the HTML with the given contentSelector, and presents it inside a Preact modal.
* Only one modal will be presented at any given time.
*
* @param {Object} args
* @param {string} args.title The title of the modal (presented at the top of the modal dialog)
* @param {string} args.contentSelector The CSS query to locate the HTML to be presented in the modal (e.g. '#my-modal-content')
* @param {string} args.size The size prop for the modal ('small', 'medium', or 'large')
* @param {Function} args.onOpen A callback function to run when the modal opens. This can be useful, for example, to attach any event listeners to items inside the modal.
*/
export const showWindowModal = async ({
title,
contentSelector,
size = 'small',
onOpen,
}) => {
const [{ Modal }, { render, h }] = await getModalImports();
// Guard against two modals being opened at once
let currentModalContainer = document.getElementById(WINDOW_MODAL_ID);
if (currentModalContainer) {
render(null, currentModalContainer);
} else {
currentModalContainer = document.createElement('div');
currentModalContainer.setAttribute('id', WINDOW_MODAL_ID);
document.body.appendChild(currentModalContainer);
}
render(
<Modal
title={title}
onClose={() => {
render(null, currentModalContainer);
}}
size={size}
focusTrapSelector={`#${WINDOW_MODAL_ID}`}
>
<div
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: document.querySelector(contentSelector).innerHTML,
}}
/>
</Modal>,
currentModalContainer,
);
onOpen?.();
};
/**
* This helper function closes any currently open window modal. This can be useful, for example, if your modal contains a "cancel" button.
*/
export const closeWindowModal = async () => {
const currentModalContainer = document.getElementById(WINDOW_MODAL_ID);
if (currentModalContainer) {
const { render } = await getPreactImport();
render(null, currentModalContainer);
}
};