Skip to content

Commit

Permalink
feat: 🎸 add useStartTypings hook
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Apr 7, 2019
1 parent 5b39ab5 commit 5fda2e0
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
- [`usePageLeave`](./docs/usePageLeave.md) — triggers when mouse leaves page boundaries.
- [`useScroll`](./docs/useScroll.md) — tracks an HTML element's scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usescroll--docs)
- [`useSize`](./docs/useSize.md) — tracks an HTML element's dimensions.
- [`useStartTyping`](./docs/useStartTyping.md) — detects when user starts typing.
- [`useWindowScroll`](./docs/useWindowScroll.md) — tracks `Window` scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usewindowscroll--docs)
- [`useWindowSize`](./docs/useWindowSize.md) — tracks `Window` dimensions. [![][img-demo]](https://codesandbox.io/s/m7ln22668)
<br/>
Expand Down
16 changes: 16 additions & 0 deletions docs/useStartTyping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# `useStartTyping`

React sensor hook that fires a callback when user start typing. Can be use
to focus default input field on the page.

## Usage

```jsx
import useStartTyping from 'react-use/lib/useStartTyping';

const Demo = () => {
useStartTyping(() => alert('Started typing...'));

return null;
};
```
41 changes: 41 additions & 0 deletions src/__stories__/useStartTyping.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {storiesOf} from '@storybook/react';
import * as React from 'react';
import {useStartTyping} from '..';
import ShowDocs from './util/ShowDocs';

const Demo = () => {
const input = React.useRef(null);
useStartTyping(() => {
if (input.current) {
input.current.focus();
}
});

return (
<div>
<p>Start typing, and below field will get focused.</p>
<input ref={input} />

<br />
<hr />

<p>Try focusing below elements and see what happens.</p>
<button>When button is focused, it will lose it.</button>
<br />
<br />
<input />
<br />
<br />
<textarea>Editable textarea</textarea>
<br />
<br />
<div contentEditable>Editable DIV</div>
</div>
);
};

storiesOf('Sensors|useStartTyping', module)
// .add('Docs', () => <ShowDocs md={require('../../docs/useStartTyping.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 @@ -51,6 +51,7 @@ import useSetState from './useSetState';
import useSize from './useSize';
import useSpeech from './useSpeech';
import useSpring from './useSpring';
import useStartTyping from './useStartTyping';
import useThrottle from './useThrottle';
import useThrottleFn from './useThrottleFn';
import useTimeout from './useTimeout';
Expand Down Expand Up @@ -119,6 +120,7 @@ export {
useSize,
useSpeech,
useSpring,
useStartTyping,
useThrottle,
useThrottleFn,
useTimeout,
Expand Down
42 changes: 42 additions & 0 deletions src/useStartTyping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {useLayoutEffect} from 'react';

const isFocusedElementEditable = () => {
const {activeElement, body} = document;

// If not element has focus, we assume it is not editable, too.
if (activeElement === body) return false;

// Assume <input> and <textarea> elements are editable.
switch (activeElement.tagName) {
case 'INPUT':
case 'TEXTAREA':
return true;
}

// Check if any other focused element id editable.
return activeElement.hasAttribute('contenteditable');
};

const isTypedCharGood = ({keyCode}: KeyboardEvent) => {
// 0...9
if ((keyCode >= 48) && (keyCode <= 57)) return true;
// a...z
if ((keyCode >= 65) && (keyCode <= 90)) return true;
// All other keys.
return false;
};

const useStartTyping = (onStartTyping: (event: KeyboardEvent) => void) => {
useLayoutEffect(() => {
const keydown = (event) => {
!isFocusedElementEditable() && isTypedCharGood(event) && onStartTyping(event);
};

document.addEventListener('keydown', keydown);
return () => {
document.removeEventListener('keydown', keydown);
};
}, []);
};

export default useStartTyping;

0 comments on commit 5fda2e0

Please sign in to comment.