Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removing support for mouse and touch events #1750

Merged
merged 5 commits into from Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this true for pointerEnter and pointerLeave too?

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

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