From 55decb135239700685e1a4ad29e551836cfa196d Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 5 Jun 2022 00:02:24 +0900 Subject: [PATCH 1/3] Update browser interface to add an interface for updating DOMs --- src/browser.ts | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/browser.ts b/src/browser.ts index 234dcb0e..87abad2b 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -4,24 +4,43 @@ export { observer } const marpCoreBrowserScript = Symbol() -export const browser = (target: ParentNode = document): (() => void) => { +export interface MarpCoreBrowser { + /** Clean-up observer for applying polyfills. */ + (): void + + /** Clean-up observer for applying polyfills. */ + cleanup: () => void + + /** + * Update DOMs to apply custom elements for Marp Core. It should call whenever + * rendered DOMs rendered by Marp. + * + * It has exactly same meaning to call `browser()` with the same arguments + * again. + */ + update: () => MarpCoreBrowser +} + +export const browser = (target: ParentNode = document): MarpCoreBrowser => { if (typeof window === 'undefined') { throw new Error( "Marp Core's browser script is valid only in browser context." ) } - if (target[marpCoreBrowserScript]) return target[marpCoreBrowserScript] - - // --- + applyCustomElements(target) // Should call in every update of Marp rendering - applyCustomElements(target) + if (target[marpCoreBrowserScript]) return target[marpCoreBrowserScript] const cleanupObserver = observer({ target }) - const cleanup = () => { + const cleanupFn = () => { cleanupObserver() delete target[marpCoreBrowserScript] } + const cleanup = Object.assign(cleanupFn, { + cleanup: cleanupFn, + update: () => browser(target), + }) Object.defineProperty(target, marpCoreBrowserScript, { configurable: true, From aaf1549194cbf2b0436ac21cb53f1ab5a0b3e549 Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 5 Jun 2022 00:17:46 +0900 Subject: [PATCH 2/3] Add test cases for updated browser interface --- test/browser.ts | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/test/browser.ts b/test/browser.ts index c82b68a8..d347684a 100644 --- a/test/browser.ts +++ b/test/browser.ts @@ -14,14 +14,16 @@ beforeEach(() => jest.clearAllMocks()) afterEach(() => jest.restoreAllMocks()) describe('Browser script', () => { - it('executes observers for polyfill and fitting', () => { + it('executes polyfill observer and set-up for custom elements', () => { const spy = jest.spyOn(window, 'requestAnimationFrame') - const cleanup = browser() + const browserInterface = browser() expect(spy).toHaveBeenCalledTimes(1) expect(polyfill).toHaveBeenCalledTimes(1) expect(applyCustomElements).toHaveBeenCalledTimes(1) - expect(browser()).toStrictEqual(cleanup) + expect(browser()).toStrictEqual(browserInterface) + expect(browserInterface).toStrictEqual(expect.any(Function)) + expect(browserInterface).toStrictEqual(browserInterface.cleanup) const rafFunc = spy.mock.calls[0][0] rafFunc(performance.now()) @@ -29,19 +31,39 @@ describe('Browser script', () => { expect(spy).toHaveBeenCalledTimes(2) expect(polyfill).toHaveBeenCalledTimes(2) - cleanup() + browserInterface.cleanup() rafFunc(performance.now()) expect(spy).toHaveBeenCalledTimes(2) // No more calling function after cleanup }) describe('with passed shadow root', () => { - it('calls polyfills and fitting observer with specific target', () => { + it('calls polyfill observer and custom elements set-up with specific target', () => { const root = document.createElement('div').attachShadow({ mode: 'open' }) - const cleanup = browser(root) + const browserInterface = browser(root) expect(polyfill).toHaveBeenCalledWith({ target: root }) expect(applyCustomElements).toHaveBeenCalledWith(root) - cleanup() + browserInterface.cleanup() + }) + }) + + describe('#update', () => { + it('calls itself again to update custom element DOMs', () => { + const browserInterface = browser() + + expect(applyCustomElements).toHaveBeenCalledTimes(1) + expect(browserInterface.update()).toStrictEqual(browserInterface) + expect(applyCustomElements).toHaveBeenCalledTimes(2) + browserInterface.cleanup() + + // For shadow root + const root = document.createElement('div').attachShadow({ mode: 'open' }) + const interfaceShadowRoot = browser(root) + + expect(applyCustomElements).toHaveBeenNthCalledWith(3, root) + expect(interfaceShadowRoot.update()).toStrictEqual(interfaceShadowRoot) + expect(applyCustomElements).toHaveBeenNthCalledWith(4, root) + interfaceShadowRoot.cleanup() }) }) }) From a7aaa19179b0b1565ca13e984df4c72296265b06 Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 5 Jun 2022 17:46:36 +0900 Subject: [PATCH 3/3] [ci skip] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c39e6581..a52cb42c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Apply hydration for custom elements whenever calling browser script ([#305](https://github.com/marp-team/marp-core/pull/305)) + ## v3.2.0 - 2022-05-21 ### Changed