Skip to content

Commit 299fd86

Browse files
committed
feat: 🎸 add useKey hook
1 parent 7d7c36e commit 299fd86

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

src/__stories__/useKey.story.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { storiesOf } from "@storybook/react";
2+
import * as React from "react";
3+
import {useKey} from "..";
4+
import ShowDocs from "../util/ShowDocs";
5+
import {CenterStory} from "./util/CenterStory";
6+
7+
const Demo = () => {
8+
const [count, setCount] = React.useState(0);
9+
10+
const increment = () => setCount(count => ++count);
11+
const decrement = () => setCount(count => --count);
12+
const reset = () => setCount(count => 0);
13+
14+
useKey(']', increment);
15+
useKey('[', decrement);
16+
useKey('r', reset);
17+
18+
return (
19+
<CenterStory>
20+
<style dangerouslySetInnerHTML={{__html: `code {color: red}`}} />
21+
<p>
22+
Try pressing <code>[</code>, <code>]</code>, and <code>r</code> to
23+
see the count incremented and decremented.</p>
24+
<p>Count: {count}</p>
25+
</CenterStory>
26+
);
27+
};
28+
29+
storiesOf("Sensors/useKey", module)
30+
.add("Docs", () => <ShowDocs md={require("../../docs/useKeyPressEvent.md")} />)
31+
.add("Demo", () => <Demo />);

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import useGetSetState from './useGetSetState';
1717
import useHover from './useHover';
1818
import useHoverDirty from './useHoverDirty';
1919
import useIdle from './useIdle';
20+
import useKey from './useKey';
2021
import useKeyPress from './useKeyPress';
2122
import useKeyPressEvent from './useKeyPressEvent';
2223
import useLifecycles from './useLifecycles';
@@ -82,6 +83,7 @@ export {
8283
useHover,
8384
useHoverDirty,
8485
useIdle,
86+
useKey,
8587
useKeyPress,
8688
useKeyPressEvent,
8789
useLifecycles,

src/useEvent.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const defaultTarget = typeof window === 'object' ? window : null;
1616

1717
const useEvent = (name: string, handler?: null | undefined | ((event?: any) => void), target: null | UseEventTarget = defaultTarget, options?: any) => {
1818
useEffect(() => {
19-
console.log('adding event...');
2019
if (!handler) return;
2120
if (!target) return;
2221
((target as ListenerType1).addEventListener || (target as ListenerType2).on).call(target, name, handler, options);

src/useKey.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {useMemo, DependencyList} from 'react';
2+
import useEvent, {UseEventTarget} from './useEvent';
3+
4+
export type KeyPredicate = (event: KeyboardEvent) => boolean;
5+
export type KeyFilter = null | undefined | string | ((event: KeyboardEvent) => boolean);
6+
export type Handler = (event: KeyboardEvent) => void;
7+
export interface UseKeyOptions {
8+
event?: 'keydown' | 'keypress' | 'keyup',
9+
target?: UseEventTarget,
10+
options?: any,
11+
}
12+
13+
const noop = () => {};
14+
const createKeyPredicate = (keyFilter: KeyFilter): KeyPredicate =>
15+
typeof keyFilter === 'function'
16+
? keyFilter
17+
: typeof keyFilter === 'string'
18+
? (event: KeyboardEvent) => event.key === keyFilter
19+
: keyFilter
20+
? () => true
21+
: () => false;
22+
23+
const useKey = (key: KeyFilter, fn: Handler = noop, opts: UseKeyOptions = {}, deps: DependencyList = [key]) => {
24+
const {event = 'keydown', target, options} = opts;
25+
const handler = useMemo(() => {
26+
const predicate: KeyPredicate = createKeyPredicate(key);
27+
const handler: Handler = (event) => {
28+
if (predicate(event)) return fn(event);
29+
};
30+
return handler;
31+
}, deps);
32+
useEvent(event, handler, target, options);
33+
};
34+
35+
export default useKey;

0 commit comments

Comments
 (0)