Skip to content

Commit

Permalink
Updates to keys
Browse files Browse the repository at this point in the history
  • Loading branch information
imbhargav5 committed Aug 10, 2019
1 parent 8a5e136 commit 7721d15
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 123 deletions.
28 changes: 21 additions & 7 deletions packages/key/src/useKey.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useLayoutEffect, Ref, useEffect } from "react";
import { Ref, useEffect, useCallback, useRef } from "react";
import { doesIdentifierMatchKeyboardEvent } from "shared/doesIdentifierMatchKeyboardEvent";

interface Options {
/**
Expand Down Expand Up @@ -37,14 +38,27 @@ function useKey(
): void {
const options = (<any>Object).assign({}, defaultOptions, opts);
const { when, eventTypes } = options;
const callbackRef = useRef<(e: KeyboardEvent) => any>(callback);
let { target } = options;
function handle(e: KeyboardEvent) {
if (keyList.includes(e.key) || keyList.includes(e.keyCode)) {
callback(e);
}
}

useLayoutEffect(() => {
useEffect(() => {
callbackRef.current = callback;
});

const handle = useCallback(
(e: KeyboardEvent) => {
if (
keyList.some(identifier =>
doesIdentifierMatchKeyboardEvent(e, identifier)
)
) {
callbackRef.current(e);
}
},
[keyList]
);

useEffect(() => {
if (when && typeof window !== "undefined") {
const targetNode = target ? target.current : window;
eventTypes.forEach(eventType => {
Expand Down
102 changes: 27 additions & 75 deletions packages/keys/src/useKeys.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,10 @@
import { useEffect, useRef, MutableRefObject, useCallback } from "react";

/**
* An IIFE which assign code {event.code} to actual key values
* This will avoid the need to do rigorous check on the hook side
* avoiding checks e.g ctrl left vs ctrl right, alt left vs alt right
* {"0":"Digit0","1":"Digit1","2":"Digit2","3":"Digit3","4":"Digit4","5":"Digit5","6":"Digit6","7":"Digit7","8":"Digit8","9":"Digit9","A":"KeyA","B":"KeyB","C":"KeyC","D":"KeyD","E":"KeyE","F":"KeyF","G":"KeyG","H":"KeyH","I":"KeyI","J":"KeyJ","K":"KeyK","L":"KeyL","M":"KeyM","N":"KeyN","O":"KeyO","P":"KeyP","Q":"KeyQ","R":"KeyR","S":"KeyS","T":"KeyT","U":"KeyU","V":"KeyV","W":"KeyW","X":"KeyX","Y":"KeyY","Z":"KeyZ"}"
*/
const alphabetAndNumberMap = (() => {
/**
* startLetter: ASCII code for A
* endLetter: ASCII code for Z
* startNumber : ASCII code for 0
* endNumber: ASCII code for 9
*/

let startLetter = 65;
let endLetter = 90;
let startNumber = 48;
let endNumber = 57;

const mapletterToCodes = {};
/**
* mapping character to event.code.
* refer https://keycode.info/ for event.code semantic for character and number
*/
while (startLetter <= endLetter) {
const letter = String.fromCharCode(startLetter);
mapletterToCodes[
String.fromCharCode(startLetter)
] = `Key${letter}`.toUpperCase();
startLetter++;
}

/**
* mapping number to event.code.
*/
while (startNumber <= endNumber) {
const number = String.fromCharCode(startNumber);
mapletterToCodes[
String.fromCharCode(startNumber)
] = `Digit${number}`.toUpperCase();
startNumber++;
}
return mapletterToCodes;
})();
import { doesIdentifierMatchKeyboardEvent } from "shared/doesIdentifierMatchKeyboardEvent";

type TPressedKeyMapping = {
[key: string]: boolean;
};

/**
* checkWhetherRequiredKeyPressed
* Helper function
*
* Checks whether the keys in the keyList are all presses
*/
function checkWhetherRequiredKeyPressed(
keysList: string[],
PressedKeyMapping: TPressedKeyMapping
) {
return keysList.every((elem: string) => {
return (
PressedKeyMapping[elem.toUpperCase()] ||
PressedKeyMapping[alphabetAndNumberMap[elem.toUpperCase()]]
);
});
}

interface Options {
/**
* when boolean to enable and disable events, when passed false
Expand Down Expand Up @@ -123,22 +61,33 @@ function useKeys(
* @param {KeyboardEvent} event
* KeyDown event handler which will wrap the passed in callback
*/
//Need to add comparison logixc for current
// keylist and old keylist, because here keylist always changes
// as it is an array or is this ok? will have to check

const handleKeyDown = useCallback(
function handleKeyDown(event: KeyboardEvent) {
const { code } = event;
PressedKeyMapping[code.toUpperCase()] = true;
if (checkWhetherRequiredKeyPressed(keysList, PressedKeyMapping)) {
let pressedKeyIdentifier = null;
let areAllKeysFromListPressed = false;
// First detect the key that was pressed;
keysList.forEach(identifier => {
if (doesIdentifierMatchKeyboardEvent(event, identifier)) {
PressedKeyMapping[identifier] = true;
pressedKeyIdentifier = identifier;
return;
}
});
if (keysList.every(identifier => PressedKeyMapping[identifier])) {
areAllKeysFromListPressed = true;
}

if (areAllKeysFromListPressed) {
if (savedCallback.current) {
savedCallback.current(event);
}
/**
* If not continuous
* disable identifier immediately
*/
if (!continuous) {
keysList.forEach((keys: string) => {
PressedKeyMapping[keys.toUpperCase()] = false;
PressedKeyMapping[alphabetAndNumberMap[keys.toUpperCase()]] = false;
});
PressedKeyMapping[pressedKeyIdentifier] = false;
}
}
},
Expand All @@ -153,8 +102,11 @@ function useKeys(
* KeyUp event handler which will update the keys pressed state in PressedKeyMapping
*/
const handleKeyUp = useCallback(function handleKeyUp(event: KeyboardEvent) {
const { code } = event;
PressedKeyMapping[code.toUpperCase()] = undefined;
keysList.forEach(identifier => {
if (doesIdentifierMatchKeyboardEvent(event, identifier)) {
PressedKeyMapping[identifier] = undefined;
}
});
}, []);

/**
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/doesIdentifierMatchKeyboardEvent.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare function doesIdentifierMatchKeyboardEvent(e: KeyboardEvent, identifier: any): boolean;
export { doesIdentifierMatchKeyboardEvent };
17 changes: 17 additions & 0 deletions packages/shared/doesIdentifierMatchKeyboardEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function doesIdentifierMatchKeyboardEvent(
e: KeyboardEvent,
identifier
): boolean {
if (
e.key === identifier ||
e.code === identifier ||
e.keyCode === identifier ||
e.which === identifier ||
e.charCode === identifier
) {
return true;
}
return false;
}

export { doesIdentifierMatchKeyboardEvent };
9 changes: 9 additions & 0 deletions packages/shared/tsconfig.tsbuildinfo
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@
"version": "a1205f8b74ba57896ae4eb9ff19a5ffc7f210352b0b535abcd36d6b06225a3ac",
"signature": "a1205f8b74ba57896ae4eb9ff19a5ffc7f210352b0b535abcd36d6b06225a3ac"
},
"/users/bhargavponnapalli/oss/react-hooks/rooks/packages/shared/doesidentifiermatchkeyboardevent.ts": {
"version": "c71f8d3885318084970e3e66e4337638799506d0f183ce46816310b441a57a1d",
"signature": "9cf705cbcdfb21661eeb35cdba9f4b994370b4de4499471a736e4f13f16f7583"
},
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/react/global.d.ts": {
"version": "2bbdfc5ed049f38787376bb01b7bcfe5299eac853c76c16a3e21ab0279078314",
"signature": "2bbdfc5ed049f38787376bb01b7bcfe5299eac853c76c16a3e21ab0279078314"
Expand Down Expand Up @@ -512,6 +516,10 @@
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/node/util.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/node/ts3.2/util.d.ts"
],
"/users/bhargavponnapalli/oss/react-hooks/rooks/packages/shared/doesidentifiermatchkeyboardevent.ts": [
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/node/util.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/node/ts3.2/util.d.ts"
],
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/react/global.d.ts": [
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/node/util.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/node/ts3.2/util.d.ts"
Expand Down Expand Up @@ -1361,6 +1369,7 @@
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/typescript/lib/lib.esnext.intl.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/typescript/lib/lib.esnext.bigint.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/typescript/lib/lib.es2016.full.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/packages/shared/doesidentifiermatchkeyboardevent.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/react/global.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/csstype/index.d.ts",
"/users/bhargavponnapalli/oss/react-hooks/rooks/node_modules/@types/prop-types/index.d.ts",
Expand Down
12 changes: 6 additions & 6 deletions packages/shared/useDidMount.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* @param {function} callback Callback function to be called on mount
*/
declare function useDidMount(callback: () => any): void;
export { useDidMount };
/**
*
* @param {function} callback Callback function to be called on mount
*/
declare function useDidMount(callback: () => any): void;
export { useDidMount };
44 changes: 22 additions & 22 deletions packages/shared/useInterval.d.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
/// <reference types="node" />
interface IntervalHandlerAsArray extends Array<null | NodeJS.Timeout | (() => void)> {
0: () => void;
1: () => void;
2: NodeJS.Timeout | null;
}
interface IntervalHandler extends IntervalHandlerAsArray {
}
/**
*
* useInterval hook
*
* Declaratively creates a setInterval to run a callback after a fixed
* amount of time
*
*@param {funnction} callback - Callback to be fired
*@param {number} intervalId - Interval duration in milliseconds after which the callback is to be fired
*@param {boolean} startImmediate - Whether the interval should start immediately on initialise
*@return {IntervalHandler}
*/
declare function useInterval(callback: () => any, intervalDuration: number, startImmediate?: boolean): IntervalHandler;
export { useInterval };
/// <reference types="node" />
interface IntervalHandlerAsArray extends Array<null | NodeJS.Timeout | (() => void)> {
0: () => void;
1: () => void;
2: NodeJS.Timeout | null;
}
interface IntervalHandler extends IntervalHandlerAsArray {
}
/**
*
* useInterval hook
*
* Declaratively creates a setInterval to run a callback after a fixed
* amount of time
*
*@param {funnction} callback - Callback to be fired
*@param {number} intervalId - Interval duration in milliseconds after which the callback is to be fired
*@param {boolean} startImmediate - Whether the interval should start immediately on initialise
*@return {IntervalHandler}
*/
declare function useInterval(callback: () => any, intervalDuration: number, startImmediate?: boolean): IntervalHandler;
export { useInterval };
26 changes: 13 additions & 13 deletions packages/shared/useMutationObserver.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { MutableRefObject } from "react";
/**
*
* useMutationObserver hook
*
* Returns a mutation observer for a React Ref and fires a callback
*
* @param {MutableRefObject<HTMLElement | null>} ref React ref on which mutations are to be observed
* @param {MutationCallback} callback Function that needs to be fired on mutation
* @param {MutationObserverInit} options
*/
declare function useMutationObserver(ref: MutableRefObject<HTMLElement | null>, callback: MutationCallback, options?: MutationObserverInit): void;
export { useMutationObserver };
import { MutableRefObject } from "react";
/**
*
* useMutationObserver hook
*
* Returns a mutation observer for a React Ref and fires a callback
*
* @param {MutableRefObject<HTMLElement | null>} ref React ref on which mutations are to be observed
* @param {MutationCallback} callback Function that needs to be fired on mutation
* @param {MutationObserverInit} options
*/
declare function useMutationObserver(ref: MutableRefObject<HTMLElement | null>, callback: MutationCallback, options?: MutationObserverInit): void;
export { useMutationObserver };

0 comments on commit 7721d15

Please sign in to comment.