From 9212e645d32b7719096d5f1cf6565d92552253d9 Mon Sep 17 00:00:00 2001 From: Alexander Ackermann Date: Tue, 3 Nov 2026 05:12:40 +0100 Subject: [PATCH] fix: ignore deferred panzoom transforms after the preview image unmounts --- .../src/components/Sources/MediaImage.vue | 5 +++++ .../tests/unit/components/MediaImage.spec.ts | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/web-app-preview/src/components/Sources/MediaImage.vue b/packages/web-app-preview/src/components/Sources/MediaImage.vue index 2a8ccac84b5..474bbb492d2 100644 --- a/packages/web-app-preview/src/components/Sources/MediaImage.vue +++ b/packages/web-app-preview/src/components/Sources/MediaImage.vue @@ -93,6 +93,11 @@ const onWheelEvent = (e: WheelEvent) => { } const setTransform = ({ scale, x, y }: { scale: number; x: number; y: number }) => { + // panzoom calls this deferred, possibly after it got destroyed on unmount + if (!unref(panzoom)) { + return + } + let h: number let v: number diff --git a/packages/web-app-preview/tests/unit/components/MediaImage.spec.ts b/packages/web-app-preview/tests/unit/components/MediaImage.spec.ts index a755e9d594d..cc61436a6ea 100644 --- a/packages/web-app-preview/tests/unit/components/MediaImage.spec.ts +++ b/packages/web-app-preview/tests/unit/components/MediaImage.spec.ts @@ -3,6 +3,7 @@ import { defaultPlugins, shallowMount } from '@opencloud-eu/web-test-helpers' import { flushPromises } from '@vue/test-utils' import { Resource } from '@opencloud-eu/web-client' import { MediaFile } from '../../../src/helpers/types' +import Panzoom, { PanzoomOptions } from '@panzoom/panzoom' // panzoom touches real DOM geometry which jsdom does not provide const panzoom = { @@ -13,7 +14,7 @@ const panzoom = { getScale: () => 1, getPan: () => ({ x: 0, y: 0 }) } -vi.mock('@panzoom/panzoom', () => ({ default: () => panzoom })) +vi.mock('@panzoom/panzoom', () => ({ default: vi.fn(() => panzoom) })) const mediaFile = (mimeType: string): MediaFile => ({ @@ -92,6 +93,19 @@ describe('MediaImage component', () => { }) }) + it('ignores a deferred panzoom transform after unmount', async () => { + const { wrapper } = getWrapper('image/png') + await flushPromises() + const { setTransform } = vi.mocked(Panzoom).mock.calls[0][1] as PanzoomOptions + + wrapper.unmount() + + expect(() => + setTransform(document.createElement('div'), { scale: 1, x: 0, y: 0 }, {}) + ).not.toThrow() + expect(panzoom.setStyle).not.toHaveBeenCalled() + }) + it('reports an image the browser cannot decode', async () => { const { wrapper } = getWrapper('image/heic')