Skip to content

Commit

Permalink
feat: add useMouse hook
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich authored Mar 25, 2019
2 parents 7b3e4d3 + 81cf157 commit 17dfa8e
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- [`useMedia`](./docs/useMedia.md) — tracks state of a CSS media query. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemedia--demo)
- [`useMediaDevices`](./docs/useMediaDevices.md) — tracks state of connected hardware devices.
- [`useMotion`](./docs/useMotion.md) — tracks state of device's motion sensor.
- [`useMouse`](./docs/useMouse.md) — tracks state of mouse position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemouse--docs)
- [`useNetwork`](./docs/useNetwork.md) — tracks state of user's internet connection.
- [`useOrientation`](./docs/useOrientation.md) — tracks state of device's screen orientation.
- [`useScroll`](./docs/useScroll.md) — tracks some HTML element's scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usescroll--docs)
Expand Down
23 changes: 23 additions & 0 deletions docs/useMouse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# `useMouse`

React sensor hook that re-renders on mouse position changes.

## Usage

```jsx
import {useMouse} from 'react-use';

const Demo = () => {
const ref = React.useRef(null);
const {docX, docY, posX, posY, elX, elY, elW, elH} = useScroll(ref);

This comment has been minimized.

Copy link
@kachkaev

kachkaev Mar 25, 2019

Contributor

Should this be useMouse instead of useScroll?

This comment has been minimized.

Copy link
@kachkaev

kachkaev Mar 25, 2019

Contributor

Ah, this has been fixed on master. I see. 91dee93


return (
<div ref={element}>
<div>Mouse position in document - x:{docX} y:{docY}</div>
<div>Mouse position in element - x:{posX} y:{posY}</div>
<div>Element position - x:{elX} y:{elY}</div>
<div>Element dimensions - {elW}x{elH}</div>
</div>
);
};
```
32 changes: 32 additions & 0 deletions src/__stories__/useMouse.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import {storiesOf} from '@storybook/react';
import {useMouse} from '..';
import ShowDocs from '../util/ShowDocs';

const Demo = () => {
const ref = React.useRef(null);
const state = useMouse(ref);

return (
<>
<pre>
{JSON.stringify(state, null, 2)}
</pre>
<div
ref={ref}
style={{
width: '400px',
height: '400px',
backgroundColor: 'whitesmoke',
}}>
Move your mouse over me
</div>
</>
);
};

storiesOf('Sensors|useMouse', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useMouse.md')} />)
.add('Demo', () =>
<Demo/>
)
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import useMedia from './useMedia';
import useMediaDevices from './useMediaDevices';
import useMotion from './useMotion';
import useMount from './useMount';
import useMouse from './useMouse';
import useNetwork from './useNetwork';
import useNumber from './useNumber';
import useObservable from './useObservable';
Expand Down Expand Up @@ -85,6 +86,7 @@ export {
useMediaDevices,
useMotion,
useMount,
useMouse,
useNetwork,
useNumber,
useObservable,
Expand Down
61 changes: 61 additions & 0 deletions src/useMouse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {useState, useEffect, useRef, RefObject} from 'react';

export interface State {
docX: number;
docY: number;
posX: number;
posY: number;
elX: number;
elY: number;
elH: number;
elW: number;
}

const useMouse = (ref: RefObject<HTMLElement>): State => {
const frame = useRef(0);
const [state, setState] = useState<State>({
docX: 0,
docY: 0,
posX: 0,
posY: 0,
elX: 0,
elY: 0,
elH: 0,
elW: 0,
});

useEffect(() => {
const handler = (event: MouseEvent) => {
cancelAnimationFrame(frame.current)
frame.current = requestAnimationFrame(() => {
if (ref && ref.current) {
const {left, top} = ref.current.getBoundingClientRect()
const posX = left + window.scrollX;
const posY = top + window.scrollY;

setState({
docX: event.pageX,
docY: event.pageY,
posX,
posY,
elX: event.pageX - posX,
elY: event.pageY - posY,
elH: ref.current.offsetHeight,
elW: ref.current.offsetWidth,
});
}
});
}

document.addEventListener('mousemove', handler);

return () => {
cancelAnimationFrame(frame.current);
document.removeEventListener('mousemove', handler);
};
}, []);

return state;
}

export default useMouse

0 comments on commit 17dfa8e

Please sign in to comment.