feat(stammbaum): touch/mouse/wheel pan & pinch zoom gestures (#692)
Add a panZoomGestures action: one-finger/left-button drag pans, two-finger pinch and Ctrl+wheel zoom around the centroid, plain wheel pans. Pan is edge-clamped via clampPan (no infinite scroll), a real drag suppresses the trailing node click, and inertia decays after release unless prefers-reduced- motion. Canvas container switches from native scroll to overflow-hidden. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -549,6 +549,35 @@ describe('StammbaumTree keyboard pan/zoom (#692)', () => {
|
||||
expect(onPanZoom.mock.calls[0][0].y).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('pans on a pointer drag and suppresses the trailing node click (US-PAN-001)', async () => {
|
||||
const onPanZoom = vi.fn();
|
||||
const onSelect = vi.fn();
|
||||
render(StammbaumTree, {
|
||||
nodes: [{ id: ID_A, displayName: 'Anna', familyMember: true }],
|
||||
edges: [],
|
||||
selectedId: null,
|
||||
// Zoomed in so panning is permitted (clampPan allows movement at z>1).
|
||||
panZoom: { x: 0, y: 0, z: 2 },
|
||||
onPanZoom,
|
||||
onSelect
|
||||
});
|
||||
const svg = document.querySelector('svg')! as SVGSVGElement;
|
||||
const node = document.querySelector('g[role="button"]') as SVGGElement;
|
||||
|
||||
const opts = (x: number) => ({ pointerId: 1, clientX: x, clientY: 100, bubbles: true });
|
||||
svg.dispatchEvent(new PointerEvent('pointerdown', opts(100)));
|
||||
svg.dispatchEvent(new PointerEvent('pointermove', opts(160)));
|
||||
svg.dispatchEvent(new PointerEvent('pointerup', opts(160)));
|
||||
|
||||
expect(onPanZoom).toHaveBeenCalled();
|
||||
// Dragging right reveals content to the left → pan x decreases.
|
||||
expect(onPanZoom.mock.calls.at(-1)![0].x).toBeLessThan(0);
|
||||
|
||||
// The synthetic click after a real drag must not select the node.
|
||||
node.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||
expect(onSelect).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not call onSelect for other keys', async () => {
|
||||
const onSelect = vi.fn();
|
||||
render(StammbaumTree, {
|
||||
|
||||
Reference in New Issue
Block a user