diff --git a/README.md b/README.md
index d6d44c40b02b..8caf151c4244 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Collection of essential Vue Composition Utilities
-
+
diff --git a/indexes.json b/indexes.json
index d90d92879798..57e871a56562 100644
--- a/indexes.json
+++ b/indexes.json
@@ -792,6 +792,14 @@
"category": "Browser",
"description": "reactive [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API)"
},
+ {
+ "name": "usePointer",
+ "package": "core",
+ "component": true,
+ "docs": "https://vueuse.org/core/usePointer/",
+ "category": "Sensors",
+ "description": "reactive pointer state"
+ },
{
"name": "usePointerSwipe",
"package": "core",
diff --git a/packages/components/index.ts b/packages/components/index.ts
index 6da7bc03676d..2e2efcce322e 100644
--- a/packages/components/index.ts
+++ b/packages/components/index.ts
@@ -22,6 +22,7 @@ export * from '../core/useNetwork/component'
export * from '../core/useNow/component'
export * from '../core/useOnline/component'
export * from '../core/usePageLeave/component'
+export * from '../core/usePointer/component'
export * from '../core/usePreferredColorScheme/component'
export * from '../core/usePreferredDark/component'
export * from '../core/usePreferredLanguages/component'
diff --git a/packages/core/index.ts b/packages/core/index.ts
index a5d9da97eae5..ee53f3f0a8e6 100644
--- a/packages/core/index.ts
+++ b/packages/core/index.ts
@@ -47,6 +47,7 @@ export * from './useOnline'
export * from './usePageLeave'
export * from './useParallax'
export * from './usePermission'
+export * from './usePointer'
export * from './usePointerSwipe'
export * from './usePreferredColorScheme'
export * from './usePreferredDark'
diff --git a/packages/core/usePointer/component.ts b/packages/core/usePointer/component.ts
new file mode 100644
index 000000000000..2de229e2af2b
--- /dev/null
+++ b/packages/core/usePointer/component.ts
@@ -0,0 +1,17 @@
+import { defineComponent, reactive } from 'vue-demi'
+import { usePointer, UsePointerOptions } from '@vueuse/core'
+
+export const UsePointer = defineComponent({
+ name: 'UsePointer',
+ props: [
+ 'pointerTypes',
+ 'initialValue',
+ ] as unknown as undefined,
+ setup(props, { slots }) {
+ const data = reactive(usePointer(props))
+ return () => {
+ if (slots.default)
+ return slots.default(data)
+ }
+ },
+})
diff --git a/packages/core/usePointer/demo.vue b/packages/core/usePointer/demo.vue
new file mode 100644
index 000000000000..71ba685dc093
--- /dev/null
+++ b/packages/core/usePointer/demo.vue
@@ -0,0 +1,11 @@
+
+
+
+ {{ pointer }}
+
diff --git a/packages/core/usePointer/index.md b/packages/core/usePointer/index.md
new file mode 100644
index 000000000000..0630d7f6e86b
--- /dev/null
+++ b/packages/core/usePointer/index.md
@@ -0,0 +1,23 @@
+---
+category: Sensors
+---
+
+# usePointer
+
+Reactive [pointer state](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events).
+
+## Basic Usage
+
+```js
+import { usePointer } from '@vueuse/core'
+
+const { x, y, pressure, pointerType } = usePointer()
+```
+
+## Component
+```html
+
+ x: {{ x }}
+ y: {{ y }}
+
+```
diff --git a/packages/core/usePointer/index.ts b/packages/core/usePointer/index.ts
new file mode 100644
index 000000000000..6fd9861220ef
--- /dev/null
+++ b/packages/core/usePointer/index.ts
@@ -0,0 +1,75 @@
+import { MaybeRef, objectPick, toRefs } from '@vueuse/shared'
+import { ref, Ref } from 'vue-demi'
+import { useEventListener } from '../useEventListener'
+import { ConfigurableWindow, defaultWindow } from '../_configurable'
+import { PointerType, Position } from '../_types'
+
+export interface UsePointerState extends Position {
+ pressure: number
+ pointerId: number
+ tiltX: number
+ tiltY: number
+ width: number
+ height: number
+ twist: number
+ pointerType: PointerType | null
+}
+
+export interface UsePointerOptions extends ConfigurableWindow {
+ /**
+ * Pointer types that listen to.
+ *
+ * @default ['mouse', 'touch', 'pen']
+ */
+ pointerTypes?: PointerType[]
+
+ /**
+ * Initial values
+ */
+ initialValue?: MaybeRef>
+}
+
+const defaultState: UsePointerState = /* #__PURE__ */ {
+ x: 0,
+ y: 0,
+ pointerId: 0,
+ pressure: 0,
+ tiltX: 0,
+ tiltY: 0,
+ width: 0,
+ height: 0,
+ twist: 0,
+ pointerType: null,
+}
+const keys = /* #__PURE__ */ Object.keys(defaultState) as (keyof UsePointerState)[]
+
+/**
+ * Reactive pointer state.
+ *
+ * @see https://vueuse.org/usePointer
+ * @param options
+ */
+export function usePointer(options: UsePointerOptions = {}) {
+ const {
+ window = defaultWindow,
+ } = options
+
+ const state = ref(options.initialValue || {}) as unknown as Ref
+ Object.assign(state.value, defaultState, state.value)
+
+ const handler = (event: PointerEvent) => {
+ if (options.pointerTypes && !options.pointerTypes.includes(event.pointerType as PointerType))
+ return
+
+ state.value = objectPick(event, keys, false) as UsePointerState
+ }
+
+ if (window) {
+ useEventListener(window, 'pointerdown', handler, { passive: true })
+ useEventListener(window, 'pointermove', handler, { passive: true })
+ }
+
+ return {
+ ...toRefs(state),
+ }
+}
diff --git a/packages/functions.md b/packages/functions.md
index 4778f0acf62e..95dc2a19960d 100644
--- a/packages/functions.md
+++ b/packages/functions.md
@@ -86,6 +86,7 @@
- [`useOnline`](https://vueuse.org/core/useOnline/) — reactive online state
- [`usePageLeave`](https://vueuse.org/core/usePageLeave/) — reactive state to show whether the mouse leaves the page
- [`useParallax`](https://vueuse.org/core/useParallax/) — create parallax effect easily
+ - [`usePointer`](https://vueuse.org/core/usePointer/) — reactive pointer state
- [`usePointerSwipe`](https://vueuse.org/core/usePointerSwipe/) — reactive swipe detection based on [PointerEvents](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent)
- [`useResizeObserver`](https://vueuse.org/core/useResizeObserver/) — reports changes to the dimensions of an Element's content or the border-box
- [`useSpeechRecognition`](https://vueuse.org/core/useSpeechRecognition/) — reactive [SpeechRecognition](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition)
diff --git a/packages/shared/utils/index.ts b/packages/shared/utils/index.ts
index cf890ec9718d..6d93ab8ef20a 100644
--- a/packages/shared/utils/index.ts
+++ b/packages/shared/utils/index.ts
@@ -85,3 +85,16 @@ export function increaseWithUnit(target: string | number, delta: number): string
return target
return result + unit
}
+
+/**
+ * Create a new subset object by giving keys
+ *
+ * @category Object
+ */
+export function objectPick(obj: O, keys: T[], omitUndefined = false) {
+ return keys.reduce((n, k) => {
+ if (k in obj)
+ if (!omitUndefined || !obj[k] === undefined) n[k] = obj[k]
+ return n
+ }, {} as Pick)
+}