use-scan-detection
Advanced tools
Comparing version 0.1.3 to 0.1.4
{ | ||
"name": "use-scan-detection", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"description": "A react hook for detecting barcode scanner input.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -25,5 +25,6 @@ # useScanDetection | ||
| --- | --- | | ||
| waitTime | Maximum time between characters in milliseconds. Used to determine if input is from keyboard or a scanner. Defaults to `50`. | | ||
| averageWaitTime | Average time between characters in milliseconds. Used to determine if input is from keyboard or a scanner. Defaults to `50`. | | ||
| timeToEvaluate | Time to evaluate the buffer after each character. | | ||
| startCharacter | **Optional**. Character that barcode scanner prefixes input with. Code is only read if this character is read first. | | ||
| endCharacter | Character that barcode scanner suffixes input with. Code is only read if this character is read last. Defaults to line return (key code `13`)| | ||
| endCharacter | **Optional**. Character that barcode scanner suffixes input with. Code is evaluated early if this character is read. Defaults to line return and escape. | | ||
| onComplete | Function that is called when a complete barcode is scanned. Function is called with a single string which is the read code. | | ||
@@ -30,0 +31,0 @@ | onError | **Optional**. Function that is called when an incomplete barcode is scanned. Function is called with a single string which is currently always `incomplete scan detected`| |
@@ -8,2 +8,6 @@ import { renderHook, act } from '@testing-library/react-hooks' | ||
beforeEach(() => { | ||
jest.spyOn(performance, 'now').mockImplementation(() => Math.random() * 50) | ||
}) | ||
afterEach(() => { | ||
@@ -32,2 +36,3 @@ jest.clearAllTimers() | ||
} | ||
const result = renderHook(() => useScanDetection(config)) | ||
@@ -53,2 +58,3 @@ | ||
} | ||
const result = renderHook(() => useScanDetection(config)) | ||
@@ -71,2 +77,5 @@ | ||
} | ||
jest.spyOn(performance, 'now').mockImplementation(() => 100) | ||
const result = renderHook(() => useScanDetection(config)) | ||
@@ -91,3 +100,3 @@ | ||
onComplete: jest.fn(), | ||
startCharacter: 49 | ||
startCharacter: [49] | ||
} | ||
@@ -94,0 +103,0 @@ const result = renderHook(() => useScanDetection(config)) |
@@ -7,13 +7,20 @@ import { | ||
interface bufferCharacter { | ||
time: number, | ||
char: String | ||
} | ||
interface buffer { | ||
current: String | ||
current: Array<bufferCharacter> | ||
} | ||
interface config { | ||
/** Maximum time between characters in milliseconds. Used to determine if input is from keyboard or a scanner. Defaults to 50ms.*/ | ||
waitTime?: number, | ||
/** Time to wait from last character to then trigger an evaluation of the buffer. */ | ||
timeToEvaluate?: number, | ||
/** Average time between characters in milliseconds. Used to determine if input is from keyboard or a scanner. Defaults to 50ms.*/ | ||
averageWaitTime?: number, | ||
/** Character that barcode scanner prefixes input with.*/ | ||
startCharacter?: number, | ||
startCharacter?: Array<number>, | ||
/** Character that barcode scanner suffixes input with. Defaults to line return.*/ | ||
endCharacter?: number, | ||
endCharacter?: Array<number>, | ||
/** Callback to use on complete scan input.*/ | ||
@@ -40,5 +47,6 @@ onComplete: (code: String) => void, | ||
const useScanDetection = ({ | ||
waitTime = 50, | ||
startCharacter, | ||
endCharacter = 13, | ||
timeToEvaluate = 100, | ||
averageWaitTime = 50, | ||
startCharacter = [], | ||
endCharacter = [13, 27], | ||
onComplete, | ||
@@ -53,25 +61,40 @@ onError, | ||
const buffer: buffer = useRef("") | ||
const buffer: buffer = useRef([]) | ||
const timeout: any = useRef(false) | ||
const clearBuffer = () => { | ||
buffer.current = "" | ||
buffer.current = [] | ||
} | ||
const evaluateBuffer = () => { | ||
clearTimeout() | ||
const sum = buffer.current | ||
.reduce((result, { time }) => result + time, 0) | ||
const avg = sum / buffer.current.length | ||
const code = buffer.current | ||
.slice(startCharacter.length > 0 ? 1 : 0) | ||
.map(({ char }) => char) | ||
.join("") | ||
if ( | ||
avg <= averageWaitTime | ||
&& buffer.current.length >= minLength | ||
) { | ||
onComplete(code) | ||
} else { | ||
!!onError && onError(code) | ||
} | ||
clearBuffer() | ||
} | ||
const onKeyDown: Function = useCallback((event: KeyboardEvent) => { | ||
if (event.currentTarget !== ignoreIfFocusOn) { | ||
if (event.keyCode === endCharacter) { | ||
clearTimeout(timeout.current) | ||
if (buffer.current.length >= minLength) { | ||
onComplete(buffer.current.slice(!!startCharacter ? 1 : 0)) | ||
} | ||
else if (!!onError) { | ||
onError("incomplete scan detected") | ||
} | ||
clearBuffer() | ||
if (endCharacter.includes(event.keyCode)) { | ||
evaluateBuffer() | ||
} | ||
if (buffer.current.length > 0 || event.keyCode === startCharacter || !startCharacter) { | ||
if (buffer.current.length > 0 || startCharacter.includes(event.keyCode) || startCharacter.length === 0) { | ||
clearTimeout(timeout.current) | ||
timeout.current = setTimeout(clearBuffer, waitTime) | ||
buffer.current += event.key | ||
timeout.current = setTimeout(evaluateBuffer, timeToEvaluate) | ||
buffer.current.push({ time: performance.now(), char: event.key }) | ||
} | ||
@@ -88,3 +111,3 @@ } | ||
endCharacter, | ||
waitTime, | ||
timeToEvaluate, | ||
onComplete, | ||
@@ -91,0 +114,0 @@ onError, |
@@ -6,3 +6,3 @@ { | ||
"lib": [ | ||
"es2015", | ||
"es2016", | ||
"dom" | ||
@@ -9,0 +9,0 @@ ], |
18183
383
65