From 64ed2c6dec55fa85d36d802454f2cdd3116ccf09 Mon Sep 17 00:00:00 2001 From: Suzanne Aitchison Date: Wed, 13 Apr 2022 14:15:07 +0100 Subject: [PATCH] move showModal helper into its own pack file (#17266) --- app/javascript/packs/base.jsx | 54 +---------------- app/javascript/utilities/showModal.jsx | 81 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 51 deletions(-) create mode 100644 app/javascript/utilities/showModal.jsx diff --git a/app/javascript/packs/base.jsx b/app/javascript/packs/base.jsx index 7343e245b..f249a8b2b 100644 --- a/app/javascript/packs/base.jsx +++ b/app/javascript/packs/base.jsx @@ -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( - { - render(null, currentModalContainer); - }} - size={size} - focusTrapSelector={`#${WINDOW_MODAL_ID}`} - > -
- , - 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, }; diff --git a/app/javascript/utilities/showModal.jsx b/app/javascript/utilities/showModal.jsx new file mode 100644 index 000000000..202fabe1e --- /dev/null +++ b/app/javascript/utilities/showModal.jsx @@ -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( + { + render(null, currentModalContainer); + }} + size={size} + focusTrapSelector={`#${WINDOW_MODAL_ID}`} + > +
+ , + 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); + } +};