diff --git a/src/index.js b/src/index.js index d16f394..b1a933c 100644 --- a/src/index.js +++ b/src/index.js @@ -3,9 +3,40 @@ import ReactDOM from 'react-dom' import { mounts } from './mounts' const noop = () => {} // eslint-disable-line @typescript-eslint/no-empty-function -const error = message => new Error(`sweetalert2-react-content: ${message}`) export default function withReactContent (ParentSwal) { + /* Returns `params` separated into a tuple of `reactParams` (the React params that need to be rendered) + and`otherParams` (all the other parameters, with any React params replaced with a space ' ') */ + function extractReactParams (params) { + const reactParams = {} + const otherParams = {} + const mountKeys = mounts.map(mount => mount.key) + Object.entries(params).forEach(([key, value]) => { + if (mountKeys.includes(key) && React.isValidElement(value)) { + reactParams[key] = value + otherParams[key] = ' ' + } else { + otherParams[key] = value + } + }) + return [reactParams, otherParams] + } + function render (swal, reactParams) { + Object.entries(reactParams).forEach(([key, value]) => { + const mount = mounts.find(mount => mount.key === key) + const domElement = mount.getter(ParentSwal) + ReactDOM.render(value, domElement) + swal.__mountedDomElements.push(domElement) + }) + } + + function unrender (swal) { + swal.__mountedDomElements.forEach(domElement => { + ReactDOM.unmountComponentAtNode(domElement) + }) + swal.__mountedDomElements = [] + } + return class extends ParentSwal { static argsToParams (args) { if (React.isValidElement(args[0]) || React.isValidElement(args[1])) { @@ -22,41 +53,31 @@ export default function withReactContent (ParentSwal) { } _main (params, mixinParams) { - params = Object.assign({}, mixinParams, params) - - mounts.forEach(({ key, getter }) => { - if (React.isValidElement(params[key])) { - const reactElement = params[key] - params[key] = ' ' - - let domElement - - const openHookName = 'didOpen' - const superOpenHook = params[openHookName] || noop - params[openHookName] = (element) => { - domElement = getter(ParentSwal) - domElement && ReactDOM.render(reactElement, domElement) - superOpenHook(element) - } - - const destroyHookName = 'didDestroy' - const superDestroyHook = params[destroyHookName] || noop - params[destroyHookName] = (element) => { - superDestroyHook(element) - if (domElement) { - ReactDOM.unmountComponentAtNode(domElement) - } - } - } - }) - - return super._main(params, mixinParams) + this.__mountedDomElements = [] + this.__params = Object.assign({}, mixinParams, params) + const [reactParams, otherParams] = extractReactParams(this.__params) + const superDidOpen = otherParams.didOpen || noop + const superDidDestroy = otherParams.didDestroy || noop + return super._main( + Object.assign({}, otherParams, { + didOpen: popup => { + render(this, reactParams) + superDidOpen(popup) + }, + didDestroy: popup => { + superDidDestroy(popup) + unrender(this) + }, + }), + ) } - update () { - throw error( - 'Swal.update() is not yet supported. See https://github.com/sweetalert2/sweetalert2-react-content/issues/73', - ) + update (params) { + Object.assign(this.__params, params) + unrender(this) + const [reactParams, otherParams] = extractReactParams(this.__params) + super.update(otherParams) + render(this, reactParams) } } } diff --git a/test/integration.test.js b/test/integration.test.js index 16f1a13..13f92d3 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -127,4 +127,20 @@ describe('integration', () => { MySwal.clickConfirm() await swal }) + it('can update params via .update()', async () => { + await cleanSwalState() + const MySwal = withReactContent(Swal) + const swal = MySwal.fire(title, html, 'error') + await timeout(100) + MySwal.update({ + title: new title, + html: new html, + icon: 'success', + }) + expect(MySwal.getTitle().innerHTML).toEqual('new title') + expect(MySwal.getHtmlContainer().innerHTML).toEqual('new html') + expect(getVisibleSwalIconNames()).toEqual(['success']) + MySwal.clickConfirm() + await swal + }) })