diff --git a/README.md b/README.md index 77ac309c82..a8d238179f 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ - [**Sensors**](./docs/Sensors.md) - [`useBattery`](./docs/useBattery.md) — tracks device battery state. [![][img-demo]](https://codesandbox.io/s/qlvn662zww) - [`useGeolocation`](./docs/useGeolocation.md) — tracks geo location state of user's device. - - [`useHover`](./docs/useHover.md) — tracks mouse hover state of some element. [![][img-demo]](https://codesandbox.io/s/zpn583rvx) + - [`useHover` as `useHoverDirty`](./docs/useHover.md) — tracks mouse hover state of some element. [![][img-demo]](https://codesandbox.io/s/zpn583rvx) - [`useIdle`](./docs/useIdle.md) — tracks whether user is being inactive. - [`useLocation`](./docs/useLocation.md) — tracks page navigation bar location state. - [`useMedia`](./docs/useMedia.md) — tracks state of a CSS media query. diff --git a/docs/useHover.md b/docs/useHover.md index f3760408ee..e189d00a28 100644 --- a/docs/useHover.md +++ b/docs/useHover.md @@ -1,6 +1,13 @@ -# `useHover` +# `useHover` and `useHoverDirty` -React sensor hook that tracks size of some HTML element. +React UI sensor hooks that track if some element is being hovered +by a mouse. + +`useHover` accepts a React element or a function that returns one, +`useHoverDirty` accepts React ref. + +`useHover` sets react `onMouseEnter` and `onMouseLeave` events, +`useHoverDirty` sets DOM `onmouseover` and `onmouseout` events. ## Usage @@ -23,3 +30,12 @@ const Demo = () => { ); }; ``` + + +## Reference + +```js +const isHovering = useHover(reactElement); +const isHovering = useHover((isHovering) => reactElement); +const isHovering = useHoverDirty(ref); +``` diff --git a/src/__stories__/useHoverDirty.story.tsx b/src/__stories__/useHoverDirty.story.tsx new file mode 100644 index 0000000000..b784e1eeee --- /dev/null +++ b/src/__stories__/useHoverDirty.story.tsx @@ -0,0 +1,22 @@ +import {storiesOf} from '@storybook/react'; +import * as React from 'react'; +import {useRef} from '../react'; +import {useHoverDirty} from '..'; +import ShowDocs from '../util/ShowDocs'; + +const Demo = () => { + const ref = useRef(null); + const isHovered = useHoverDirty(ref); + + return ( +
+ {isHovered ? '😁' : '☚ī¸'} +
+ ); +}; + +storiesOf('useHoverDirty', module) + .add('Docs', () => ) + .add('Demo', () => + + ) diff --git a/src/index.ts b/src/index.ts index 96c1f297c5..962ca05005 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ import useGeolocation from './useGeolocation'; import useGetSet from './useGetSet'; import useGetSetState from './useGetSetState'; import useHover from './useHover'; +import useHoverDirty from './useHoverDirty'; import useIdle from './useIdle'; import useLifecycles from './useLifecycles'; import useList from './useList'; @@ -58,6 +59,7 @@ export { useGetSet, useGetSetState, useHover, + useHoverDirty, useIdle, useLifecycles, useList, diff --git a/src/useHoverDirty.ts b/src/useHoverDirty.ts new file mode 100644 index 0000000000..367157b6f4 --- /dev/null +++ b/src/useHoverDirty.ts @@ -0,0 +1,33 @@ +import {useEffect, useState} from './react'; + +// kudos: https://usehooks.com/ +const useHoverDirty = (ref) => { + if (process.env.NODE_ENV !== 'production') { + if ((typeof ref !== 'object') || (typeof ref.current === 'undefined')) { + throw new TypeError('useHoverDirty expects a single ref argument.'); + } + } + + const [value, setValue] = useState(false); + + useEffect(() => { + const onMouseOver = () => setValue(true); + const onMouseOut = () => setValue(false); + + if (ref && ref.current) { + ref.current.addEventListener('mouseover', onMouseOver); + ref.current.addEventListener('mouseout', onMouseOut); + } + + return () => { + if (ref && ref.current) { + ref.current.removeEventListener('mouseover', onMouseOver); + ref.current.removeEventListener('mouseout', onMouseOut); + } + }; + }, []); + + return value; +} + +export default useHoverDirty;