Skip to content

Commit

Permalink
Merge pull request #1750 from framer/fix/pointer-events
Browse files Browse the repository at this point in the history
Removing support for mouse and touch events
  • Loading branch information
mergetron[bot] committed Dec 21, 2022
2 parents c888c9b + 496f671 commit 2a3c406
Show file tree
Hide file tree
Showing 24 changed files with 195 additions and 360 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,17 @@ Framer Motion adheres to [Semantic Versioning](http://semver.org/).

Undocumented APIs should be considered internal and may change without warning.

## [8.0.0] 2022-12-23

### Removed

- Removed polyfilled support for mouse/touch events.
- Removed drag pointerup patch for Safari over `<select />` elements.

### Changed

- `DragControls.start` now accepts `PointerEvent` only.

## [7.10.3] 2022-12-20

### Changed
Expand Down
18 changes: 9 additions & 9 deletions packages/framer-motion-3d/jest.setup.tsx
@@ -1,6 +1,6 @@
import "@testing-library/jest-dom"
// Get fireEvent from the native testing library
// because @testing-library/react one switches out mouseEnter and mouseLeave
// because @testing-library/react one switches out pointerEnter and pointerLeave
import { fireEvent, getByTestId } from "@testing-library/dom"
import { render as testRender, act } from "@testing-library/react"
import * as React from "react"
Expand All @@ -18,21 +18,21 @@ export const click = (element: Element) =>
act(() => {
fireEvent.click(element)
})
export const mouseEnter = (element: Element) =>
export const pointerEnter = (element: Element) =>
act(() => {
fireEvent.mouseEnter(element)
fireEvent.pointerEnter(element)
})
export const mouseLeave = (element: Element) =>
export const pointerLeave = (element: Element) =>
act(() => {
fireEvent.mouseLeave(element)
fireEvent.pointerLeave(element)
})
export const mouseDown = (element: Element) =>
export const pointerDown = (element: Element) =>
act(() => {
fireEvent.mouseDown(element)
fireEvent.pointerDown(element)
})
export const mouseUp = (element: Element) =>
export const pointerUp = (element: Element) =>
act(() => {
fireEvent.mouseUp(element)
fireEvent.pointerUp(element)
})
export const focus = (element: HTMLElement, testId: string) =>
act(() => {
Expand Down
41 changes: 32 additions & 9 deletions packages/framer-motion/jest.setup.tsx
@@ -1,10 +1,26 @@
import "@testing-library/jest-dom"
// Get fireEvent from the native testing library
// because @testing-library/react one switches out mouseEnter and mouseLeave
// because @testing-library/react one switches out pointerEnter and pointerLeave
import { fireEvent, getByTestId } from "@testing-library/dom"
import { render as testRender, act } from "@testing-library/react"
import * as React from "react"

/**
* Stub PointerEvent - this is so we can pass through PointerEvent.isPrimary
*/
const pointerEventProps = ["isPrimary"]
class PointerEventFake extends Event {
constructor(type: any, props: any) {
super(type, props)
pointerEventProps.forEach((prop) => {
if (props[prop] !== null) {
this[prop] = props[prop]
}
})
}
}
;(global as any).PointerEvent = PointerEventFake

// Stub ResizeObserver
if (!(global as any).ResizeObserver) {
;(global as any).ResizeObserver = class ResizeObserver {
Expand All @@ -18,21 +34,28 @@ export const click = (element: Element) =>
act(() => {
fireEvent.click(element)
})
export const mouseEnter = (element: Element) =>
export const pointerEnter = (element: Element) =>
act(() => {
fireEvent.pointerEnter(element)
})
export const pointerLeave = (element: Element) =>
act(() => {
fireEvent.mouseEnter(element)
fireEvent.pointerLeave(element)
})
export const mouseLeave = (element: Element) =>
export const pointerDown = (element: Element) =>
act(() => {
fireEvent.mouseLeave(element)
fireEvent.pointerDown(
element,
new PointerEventFake("pointerdown", { isPrimary: true })
)
})
export const mouseDown = (element: Element) =>
export const pointerUp = (element: Element) =>
act(() => {
fireEvent.mouseDown(element)
fireEvent.pointerUp(element)
})
export const mouseUp = (element: Element) =>
export const pointerMove = (element: Element) =>
act(() => {
fireEvent.mouseUp(element)
fireEvent.pointerMove(element)
})
export const focus = (element: HTMLElement, testId: string) =>
act(() => {
Expand Down
10 changes: 5 additions & 5 deletions packages/framer-motion/package.json
Expand Up @@ -72,31 +72,31 @@
"bundlesize": [
{
"path": "./dist/size-rollup-motion.js",
"maxSize": "29.6 kB"
"maxSize": "29.30 kB"
},
{
"path": "./dist/size-rollup-m.js",
"maxSize": "4.74 kB"
},
{
"path": "./dist/size-rollup-dom-animation.js",
"maxSize": "14.76kb"
"maxSize": "14.53 kB"
},
{
"path": "./dist/size-rollup-dom-max.js",
"maxSize": "25.49 kB"
"maxSize": "25.25 kB"
},
{
"path": "./dist/size-webpack-m.js",
"maxSize": "4.96 kB"
},
{
"path": "./dist/size-webpack-dom-animation.js",
"maxSize": "19 kB"
"maxSize": "18.7 kB"
},
{
"path": "./dist/size-webpack-dom-max.js",
"maxSize": "30.5kB"
"maxSize": "30.23kB"
}
],
"gitHead": "b0267f01c58c549a282ff3c97f0fb32ac1450668"
Expand Down
16 changes: 8 additions & 8 deletions packages/framer-motion/src/events/__tests__/use-event.test.tsx
Expand Up @@ -10,24 +10,24 @@ describe("useDomEvent", () => {
const handler = jest.fn()
const Component = () => {
const ref = useRef(null)
useDomEvent(ref, "mousedown", handler)
useDomEvent(ref, "pointerdown", handler)
return <div />
}
const { container, rerender } = render(<Component />)
rerender(<Component />)
fireEvent.mouseDown(container.firstChild as Element)
fireEvent.pointerDown(container.firstChild as Element)
expect(handler).not.toHaveBeenCalled()
})
it("should call the handler when the event is fired", () => {
const handler = jest.fn()
const Component = () => {
const ref = useRef(null)
useDomEvent(ref, "mousedown", handler)
useDomEvent(ref, "pointerdown", handler)
return <div ref={ref} />
}
const { container, rerender } = render(<Component />)
rerender(<Component />)
fireEvent.mouseDown(container.firstChild as Element)
fireEvent.pointerDown(container.firstChild as Element)
expect(handler).toHaveBeenCalledTimes(1)
})

Expand All @@ -36,13 +36,13 @@ describe("useDomEvent", () => {
const promise = new Promise<void>((resolve) => {
const Component = () => {
const ref = useRef(document.body)
useDomEvent(ref, "mousedown", handler)
useDomEvent(ref, "pointerdown", handler)
useEffect(resolve)
return <div />
}
const { rerender } = render(<Component />)
rerender(<Component />)
fireEvent.mouseDown(document.body)
fireEvent.pointerDown(document.body)
})
await expect(promise).resolves.toEqual(undefined)
expect(handler).toHaveBeenCalled()
Expand All @@ -52,14 +52,14 @@ describe("useDomEvent", () => {
const promise = new Promise<void>((resolve) => {
const Component = () => {
const ref = useRef(document.body)
useDomEvent(ref, "mousedown", handler)
useDomEvent(ref, "pointerdown", handler)
return <div />
}
const { rerender, unmount } = render(<Component />)
rerender(<Component />)
unmount()
requestAnimationFrame(() => {
fireEvent.mouseDown(document.body)
fireEvent.pointerDown(document.body)
resolve()
})
})
Expand Down

This file was deleted.

47 changes: 9 additions & 38 deletions packages/framer-motion/src/events/event-info.ts
@@ -1,64 +1,35 @@
import { EventInfo } from "./types"
import { isTouchEvent } from "../gestures/utils/event-type"

/**
* Filters out events not attached to the primary pointer (currently left mouse button)
* @param eventHandler
*/
function filterPrimaryPointer(eventHandler: EventListener): EventListener {
return (event: Event) => {
const isMouseEvent = event instanceof MouseEvent
const isPrimaryPointer =
!isMouseEvent ||
(isMouseEvent && (event as MouseEvent).button === 0)

if (isPrimaryPointer) {
return (event: PointerEvent) => {
if (event.isPrimary) {
eventHandler(event)
}
}
}

export type EventListenerWithPointInfo = (
e: MouseEvent | TouchEvent | PointerEvent,
e: PointerEvent,
info: EventInfo
) => void

const defaultPagePoint = { pageX: 0, pageY: 0 }

function pointFromTouch(e: TouchEvent, pointType: "page" | "client" = "page") {
const primaryTouch = e.touches[0] || e.changedTouches[0]
const point = primaryTouch || defaultPagePoint

return {
x: point[pointType + "X"],
y: point[pointType + "Y"],
}
}

function pointFromMouse(
point: MouseEvent | PointerEvent,
pointType: "page" | "client" = "page"
) {
return {
x: point[pointType + "X"],
y: point[pointType + "Y"],
}
}

export function extractEventInfo(
event: MouseEvent | TouchEvent | PointerEvent,
event: PointerEvent,
pointType: "page" | "client" = "page"
): EventInfo {
return {
point: isTouchEvent(event)
? pointFromTouch(event, pointType)
: pointFromMouse(event, pointType),
point: {
x: event[pointType + "X"],
y: event[pointType + "Y"],
},
}
}

export function getViewportPointFromEvent(
event: MouseEvent | TouchEvent | PointerEvent
) {
export function getViewportPointFromEvent(event: PointerEvent) {
return extractEventInfo(event, "client")
}

Expand Down
5 changes: 1 addition & 4 deletions packages/framer-motion/src/events/types.ts
Expand Up @@ -6,10 +6,7 @@ export interface EventInfo {
point: Point
}

export type EventHandler = (
event: MouseEvent | TouchEvent | PointerEvent,
info: EventInfo
) => void
export type EventHandler = (event: PointerEvent, info: EventInfo) => void

export type ListenerControls = [() => void, () => void]

Expand Down

0 comments on commit 2a3c406

Please sign in to comment.