From e63c89bc6280462485f257500b204eff0677c2e7 Mon Sep 17 00:00:00 2001 From: tomkp Date: Thu, 19 Feb 2026 10:17:49 +0000 Subject: [PATCH] feat: expose pointerType in ResizeEvent - Add pointerType field to ResizeEvent ('mouse' | 'touch' | 'pen') - Pass pointerType through onResizeStart, onResize, and onResizeEnd callbacks - Allows consumers to differentiate between input types --- src/hooks/useResizer.test.ts | 55 ++++++++++++++++++++++++++++++++++-- src/hooks/useResizer.ts | 12 ++++++-- src/types/index.ts | 2 ++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/hooks/useResizer.test.ts b/src/hooks/useResizer.test.ts index fb3f56c4..79ad8310 100644 --- a/src/hooks/useResizer.test.ts +++ b/src/hooks/useResizer.test.ts @@ -14,12 +14,18 @@ function createMockElement(): HTMLDivElement { // Helper to create a PointerEvent with required properties function createPointerEvent( type: string, - options: { clientX?: number; clientY?: number; pointerId?: number } = {} + options: { + clientX?: number; + clientY?: number; + pointerId?: number; + pointerType?: string; + } = {} ): PointerEvent { return new PointerEvent(type, { clientX: options.clientX ?? 0, clientY: options.clientY ?? 0, pointerId: options.pointerId ?? 1, + pointerType: options.pointerType ?? 'mouse', bubbles: true, }); } @@ -160,6 +166,7 @@ describe('useResizer', () => { expect(onResizeStart).toHaveBeenCalledWith({ sizes: [300, 700], source: 'pointer', + pointerType: 'mouse', originalEvent: expect.any(PointerEvent), }); }); @@ -284,6 +291,7 @@ describe('useResizer', () => { expect(onResizeEnd).toHaveBeenCalledWith([300, 700], { sizes: [300, 700], source: 'pointer', + pointerType: 'mouse', }); }); @@ -590,7 +598,7 @@ describe('useResizer', () => { expect(mockElement.setPointerCapture).toHaveBeenCalledWith(42); }); - it('handles touch input via pointer events', () => { + it('handles touch input via pointer events and passes pointerType', () => { const mockElement = createMockElement(); const onResizeStart = vi.fn(); const { result } = renderHook(() => @@ -619,18 +627,21 @@ describe('useResizer', () => { expect(onResizeStart).toHaveBeenCalledWith({ sizes: [300, 700], source: 'pointer', + pointerType: 'touch', originalEvent: expect.any(PointerEvent), }); }); - it('handles pen input via pointer events', () => { + it('handles pen input via pointer events and passes pointerType', () => { const mockElement = createMockElement(); + const onResizeStart = vi.fn(); const { result } = renderHook(() => useResizer({ direction: 'horizontal', sizes: [300, 700], minSizes: [100, 100], maxSizes: [500, 900], + onResizeStart, }) ); @@ -647,6 +658,44 @@ describe('useResizer', () => { }); expect(result.current.isDragging).toBe(true); + expect(onResizeStart).toHaveBeenCalledWith({ + sizes: [300, 700], + source: 'pointer', + pointerType: 'pen', + originalEvent: expect.any(PointerEvent), + }); + }); + + it('passes mouse pointerType by default', () => { + const mockElement = createMockElement(); + const onResizeStart = vi.fn(); + const { result } = renderHook(() => + useResizer({ + direction: 'horizontal', + sizes: [300, 700], + minSizes: [100, 100], + maxSizes: [500, 900], + onResizeStart, + }) + ); + + act(() => { + const pointerDown = result.current.handlePointerDown(0); + const event = createMockReactPointerEvent(mockElement, { + clientX: 300, + clientY: 0, + pointerId: 1, + pointerType: 'mouse', + }); + pointerDown(event); + }); + + expect(onResizeStart).toHaveBeenCalledWith({ + sizes: [300, 700], + source: 'pointer', + pointerType: 'mouse', + originalEvent: expect.any(PointerEvent), + }); }); it('ignores pointer events from non-captured pointers (multi-touch)', () => { diff --git a/src/hooks/useResizer.ts b/src/hooks/useResizer.ts index f3895fba..348fc613 100644 --- a/src/hooks/useResizer.ts +++ b/src/hooks/useResizer.ts @@ -69,6 +69,7 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { startPosition: number; startSizes: number[]; pointerId: number; + pointerType: 'mouse' | 'touch' | 'pen'; element: HTMLElement | null; } | null>(null); @@ -111,7 +112,8 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { (clientX: number, clientY: number) => { if (!dragStateRef.current || !mountedRef.current) return; - const { dividerIndex, startPosition, startSizes } = dragStateRef.current; + const { dividerIndex, startPosition, startSizes, pointerType } = + dragStateRef.current; const currentPosition = direction === 'horizontal' ? clientX : clientY; let delta = currentPosition - startPosition; @@ -142,6 +144,7 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { onResize(newSizes, { sizes: newSizes, source: 'pointer', + pointerType, }); } }, @@ -186,7 +189,7 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { } // Release pointer capture - const { element, pointerId } = dragStateRef.current; + const { element, pointerId, pointerType } = dragStateRef.current; if (element?.hasPointerCapture?.(pointerId)) { element.releasePointerCapture(pointerId); } @@ -207,6 +210,7 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { latestOnResizeEnd(latestSizes, { sizes: latestSizes, source: 'pointer', + pointerType, }); } @@ -223,11 +227,14 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { // Capture the pointer to receive all pointer events even if pointer leaves element element.setPointerCapture(e.pointerId); + const pointerType = e.pointerType as 'mouse' | 'touch' | 'pen'; + dragStateRef.current = { dividerIndex, startPosition, startSizes: currentSizes, pointerId: e.pointerId, + pointerType, element, }; @@ -237,6 +244,7 @@ export function useResizer(options: UseResizerOptions): UseResizerResult { onResizeStart({ sizes: currentSizes, source: 'pointer', + pointerType, originalEvent: e.nativeEvent, }); } diff --git a/src/types/index.ts b/src/types/index.ts index f65bc303..5d129dfa 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -7,6 +7,8 @@ export type Size = string | number; export interface ResizeEvent { sizes: number[]; source: 'pointer' | 'keyboard'; + /** The type of pointer that initiated the resize (mouse, touch, or pen) */ + pointerType?: 'mouse' | 'touch' | 'pen'; originalEvent?: PointerEvent | KeyboardEvent; }