From 406af205e37af2e16c20fa3f699287f5600a1c20 Mon Sep 17 00:00:00 2001 From: streamich Date: Sat, 27 Oct 2018 03:22:55 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20useHover=20hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/useHover.md | 25 +++++++++++++++++++++++ package.json | 5 +++++ src/__stories__/useHover.story.tsx | 23 +++++++++++++++++++++ src/index.ts | 2 ++ src/useHover.ts | 32 ++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+) create mode 100644 docs/useHover.md create mode 100644 src/__stories__/useHover.story.tsx create mode 100644 src/useHover.ts diff --git a/README.md b/README.md index 4c5e860c..3ee6177b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - [`useMap`](./docs/useMap.md) - Sensors - [`useBattery`](./docs/useBattery.md) + - [`useHover`](./docs/useHover.md) - [`useSize`](./docs/useSize.md) - [`useWindowSize`](./docs/useWindowSize.md) - Side effects diff --git a/docs/useHover.md b/docs/useHover.md new file mode 100644 index 00000000..f3760408 --- /dev/null +++ b/docs/useHover.md @@ -0,0 +1,25 @@ +# `useHover` + +React sensor hook that tracks size of some HTML element. + + +## Usage + +```jsx +import {useHover} from 'react-use'; + +const Demo = () => { + const element = (hovered) => +
+ Hover me! {hovered && 'Thanks!'} +
; + const [hoverable, hovered] = useHover(element); + + return ( +
+ {hoverable} +
{hovered ? 'HOVERED' : ''}
+
+ ); +}; +``` diff --git a/package.json b/package.json index 27748094..d165dce2 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Collection of React Hooks", "main": "lib/index.js", "scripts": { + "start": "yarn storybook", "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc", "test:story:build": "build-storybook", @@ -23,5 +24,9 @@ "ts-node": "^7.0.1", "ts-loader": "3", "babel-core": "^6.26.3" + }, + "peerDependencies": { + "react": "16.7.0-alpha.0", + "react-dom": "16.7.0-alpha.0" } } diff --git a/src/__stories__/useHover.story.tsx b/src/__stories__/useHover.story.tsx new file mode 100644 index 00000000..02aa917e --- /dev/null +++ b/src/__stories__/useHover.story.tsx @@ -0,0 +1,23 @@ +import {storiesOf} from '@storybook/react'; +import * as React from 'react'; +import {useHover} from '..'; + +const Demo = () => { + const element = (hovered: boolean) => +
+ Hover me! {hovered && 'Thanks!'} +
; + const [hoverable, hovered] = useHover(element); + + return ( +
+ {hoverable} +
{hovered ? 'HOVERED' : ''}
+
+ ); +}; + +storiesOf('useHover', module) + .add('Example', () => + + ) diff --git a/src/index.ts b/src/index.ts index d6640282..15bad294 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import useBattery from './useBattery'; import useCounter from './useCounter'; +import useHover from './useHover'; import useList from './useList'; import useMap from './useMap'; import useSize from './useSize'; @@ -10,6 +11,7 @@ import useWindowSize from './useWindowSize'; export { useBattery, useCounter, + useHover, useList, useMap, useSize, diff --git a/src/useHover.ts b/src/useHover.ts new file mode 100644 index 00000000..16e03d5b --- /dev/null +++ b/src/useHover.ts @@ -0,0 +1,32 @@ +import * as React from 'react'; +import {useState} from './react'; + +const noop = () => {}; + +export type Element = ((state: boolean) => React.ReactElement) | React.ReactElement; + +const useHover = (element: Element): [React.ReactElement, boolean] => { + const [state, setState] = useState(false); + + const onMouseEnter = (originalOnMouseEnter?: any) => (event: any) => { + (originalOnMouseEnter || noop)(event); + setState(true); + }; + const onMouseLeave = (originalOnMouseLeave?: any) => (event: any) => { + (originalOnMouseLeave || noop)(event); + setState(false); + }; + + if (typeof element === 'function') { + element = element(state); + } + + const el = React.cloneElement(element, { + onMouseEnter: onMouseEnter(element.props.onMouseEnter), + onMouseLeave: onMouseLeave(element.props.onMouseLeave) + }); + + return [el, state]; +}; + +export default useHover;