feat: zoom image improvements for reactive prop handlings (#25286)

This commit is contained in:
Min Idzelis 2026-01-20 07:18:54 -05:00 committed by GitHub
parent 2b4e4051f0
commit ca0d4b283a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 40 additions and 25 deletions

View file

@ -1,48 +1,42 @@
import { photoZoomState } from '$lib/stores/zoom-image.store'; import { photoZoomState } from '$lib/stores/zoom-image.store';
import { useZoomImageWheel } from '@zoom-image/svelte'; import { createZoomImageWheel } from '@zoom-image/core';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
export const zoomImageAction = (node: HTMLElement, options?: { disabled?: boolean }) => { export const zoomImageAction = (node: HTMLElement, options?: { disabled?: boolean }) => {
const { createZoomImage, zoomImageState, setZoomImageState } = useZoomImageWheel(); const state = get(photoZoomState);
const zoomInstance = createZoomImageWheel(node, {
createZoomImage(node, {
maxZoom: 10, maxZoom: 10,
initialState: state,
}); });
const state = get(photoZoomState); const unsubscribes = [
if (state) { photoZoomState.subscribe((state) => zoomInstance.setState(state)),
setZoomImageState(state); zoomInstance.subscribe(({ state }) => {
} photoZoomState.set(state);
}),
];
// Store original event handlers so we can prevent them when disabled const stopIfDisabled = (event: Event) => {
const wheelHandler = (event: WheelEvent) => {
if (options?.disabled) { if (options?.disabled) {
event.stopImmediatePropagation(); event.stopImmediatePropagation();
} }
}; };
const pointerDownHandler = (event: PointerEvent) => { node.addEventListener('wheel', stopIfDisabled, { capture: true });
if (options?.disabled) { node.addEventListener('pointerdown', stopIfDisabled, { capture: true });
event.stopImmediatePropagation();
}
};
// Add handlers at capture phase with higher priority
node.addEventListener('wheel', wheelHandler, { capture: true });
node.addEventListener('pointerdown', pointerDownHandler, { capture: true });
const unsubscribes = [photoZoomState.subscribe(setZoomImageState), zoomImageState.subscribe(photoZoomState.set)];
node.style.overflow = 'visible';
return { return {
update(newOptions?: { disabled?: boolean }) { update(newOptions?: { disabled?: boolean }) {
options = newOptions; options = newOptions;
}, },
destroy() { destroy() {
node.removeEventListener('wheel', wheelHandler, { capture: true });
node.removeEventListener('pointerdown', pointerDownHandler, { capture: true });
for (const unsubscribe of unsubscribes) { for (const unsubscribe of unsubscribes) {
unsubscribe(); unsubscribe();
} }
node.removeEventListener('wheel', stopIfDisabled, { capture: true });
node.removeEventListener('pointerdown', stopIfDisabled, { capture: true });
zoomInstance.cleanup();
}, },
}; };
}; };

View file

@ -1,4 +1,25 @@
import type { ZoomImageWheelState } from '@zoom-image/core'; import type { ZoomImageWheelState } from '@zoom-image/core';
import { writable } from 'svelte/store'; import { derived, writable } from 'svelte/store';
export const photoZoomState = writable<ZoomImageWheelState>(); export const photoZoomState = writable<ZoomImageWheelState>({
currentRotation: 0,
currentZoom: 1,
enable: true,
currentPositionX: 0,
currentPositionY: 0,
});
export const photoZoomTransform = derived(
photoZoomState,
($state) => `translate(${$state.currentPositionX}px,${$state.currentPositionY}px) scale(${$state.currentZoom})`,
);
export const resetZoomState = () => {
photoZoomState.set({
currentRotation: 0,
currentZoom: 1,
enable: true,
currentPositionX: 0,
currentPositionY: 0,
});
};