diff --git a/src/Flicking.ts b/src/Flicking.ts index 22d6af9e3d..2ca51f9ee3 100644 --- a/src/Flicking.ts +++ b/src/Flicking.ts @@ -218,6 +218,13 @@ class Flicking extends Component { * @see Viewport */ public get viewport() { return this._viewport; } + /** + * {@link AutoResizer} instance of the Flicking + * @ko 현재 Flicking에 활성화된 {@link AutoResizer} 인스턴스 + * @internal + * @readonly + */ + public get autoResizer() { return this._autoResizer; } // Internal States /** * Whether Flicking's {@link Flicking#init init()} is called. @@ -906,6 +913,10 @@ class Flicking extends Component { public set autoResize(val: FlickingOptions["autoResize"]) { this._autoResize = val; + if (!this._initialized) { + return; + } + if (val) { this._autoResizer.enable(); } else { @@ -916,7 +927,7 @@ class Flicking extends Component { public set useResizeObserver(val: FlickingOptions["useResizeObserver"]) { this._useResizeObserver = val; - if (this._autoResize) { + if (this._initialized && this._autoResize) { this._autoResizer.enable(); } } diff --git a/src/core/AutoResizer.ts b/src/core/AutoResizer.ts index 56551dbe3d..bd37f0ecc4 100644 --- a/src/core/AutoResizer.ts +++ b/src/core/AutoResizer.ts @@ -4,6 +4,10 @@ */ import Flicking from "../Flicking"; +/** + * A component that detects size change and trigger resize method when the autoResize option is used + * @ko autoResize 옵션을 사용할 때 크기 변화를 감지하고 Flicking의 resize를 호출하는 컴포넌트 + */ class AutoResizer { private _flicking: Flicking; private _enabled: boolean; @@ -36,7 +40,11 @@ class AutoResizer { ? new ResizeObserver(this._skipFirstResize) : new ResizeObserver(this._onResize); - resizeObserver.observe(flicking.viewport.element); + [ + flicking.viewport.element, + flicking.camera.element, + ...flicking.panels.map(panel => panel.element) + ].forEach((element) => { resizeObserver.observe(element); }); this._resizeObserver = resizeObserver; } else { @@ -64,6 +72,13 @@ class AutoResizer { return this; } + public observe(element: Element): this { + if (this._resizeObserver) { + this._resizeObserver.observe(element); + } + return this; + } + private _onResize = () => { const flicking = this._flicking; const resizeDebounce = flicking.resizeDebounce; diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 9df336ea7c..b78a54e175 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -335,6 +335,12 @@ abstract class Renderer { // Update camera & control this._updateCameraAndControl(); + if (flicking.autoResize && flicking.useResizeObserver) { + panelsAdded.forEach((panel) => { + flicking.autoResizer.observe(panel.element); + }); + } + void this.render(); if (!flicking.animating) { diff --git a/test/unit/Flicking.spec.ts b/test/unit/Flicking.spec.ts index a5a3eb8fb9..ad49d609d8 100644 --- a/test/unit/Flicking.spec.ts +++ b/test/unit/Flicking.spec.ts @@ -908,6 +908,76 @@ describe("Flicking", () => { expect(resizeSpy.calledOnce).to.be.true; }); + + ["viewport", "camera", "panel"].forEach(element => { + it(`should call resize when size of ${element} is changed`, async () => { + const flicking = await createFlicking( + El.viewport("1000px", "1000px").add( + El.camera("1000px", "1000px").add( + El.panel("800px", "1000px"), + El.panel("800px", "1000px"), + El.panel("800px", "1000px"), + ) + ), + { autoResize: true, useResizeObserver: true } + ); + const afterResizeSpy = sinon.spy(); + const beforeResizeSpy = sinon.spy(); + + // wait for initial resize + await waitTime(100); + + flicking.on(EVENTS.AFTER_RESIZE, afterResizeSpy); + flicking.on(EVENTS.BEFORE_RESIZE, beforeResizeSpy); + + switch (element) { + case "viewport": + flicking.element.style.height = "3000px"; + break; + case "camera": + flicking.camera.element.style.height = "3000px"; + break; + case "panel": + flicking.panels[2].element.style.height = "3000px"; + break; + } + + await waitEvent(flicking, EVENTS.AFTER_RESIZE); + + expect(afterResizeSpy.calledOnce).to.be.true; + expect(beforeResizeSpy.calledOnce).to.be.true; + }); + }); + + it("should observe size of panel element if panel element is added later", async () => { + const flicking = await createFlicking( + El.viewport("1000px", "1000px").add( + El.camera("1000px", "1000px").add( + El.panel("800px", "1000px"), + El.panel("800px", "1000px"), + El.panel("800px", "1000px"), + ) + ), + { autoResize: true, useResizeObserver: true } + ); + const afterResizeSpy = sinon.spy(); + const beforeResizeSpy = sinon.spy(); + + // wait for initial resize + await waitTime(100); + + flicking.on(EVENTS.AFTER_RESIZE, afterResizeSpy); + flicking.on(EVENTS.BEFORE_RESIZE, beforeResizeSpy); + + flicking.append(flicking.panels[0].element.outerHTML); + + flicking.panels[3].element.style.height = "3000px"; + + await waitEvent(flicking, EVENTS.AFTER_RESIZE); + + expect(afterResizeSpy.calledOnce).to.be.true; + expect(beforeResizeSpy.calledOnce).to.be.true; + }); }); describe("preventClickOnDrag", () => { diff --git a/test/unit/renderer/Renderer.spec.ts b/test/unit/renderer/Renderer.spec.ts index 726cf44e06..f1acf3d439 100644 --- a/test/unit/renderer/Renderer.spec.ts +++ b/test/unit/renderer/Renderer.spec.ts @@ -423,7 +423,7 @@ describe("Renderer", () => { it("should resize the panel with image when it's loaded", async () => { const flicking = await createFlicking(El.viewport("200px", "200px").add( - El.camera().add( + El.camera("100%", "100%").add( El.imgPanel("100%", "100%") ) ), { resizeOnContentsReady: true }); @@ -438,7 +438,7 @@ describe("Renderer", () => { it("should update the camera range after the image's loaded", async () => { const flicking = await createFlicking(El.viewport("200px", "200px").add( - El.camera().add( + El.camera("100%", "100%").add( El.imgPanel("100%", "100%") ) ), { resizeOnContentsReady: true });