-
Notifications
You must be signed in to change notification settings - Fork 0
/
Input.tsx
96 lines (84 loc) · 3.62 KB
/
Input.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import React, {ReactElement, useEffect, useRef} from "react";
import {DEFAULT_DIVIDEND} from "./App";
import './Input.scss'
function InputArrows(props: { onClick: (increment?: boolean) => void }): ReactElement {
const upArrowDown = useRef<boolean>(false)
const downArrowDown = useRef<boolean>(false)
const incrementInterval = useRef<NodeJS.Timer | null>()
const startIncrementTimeout = useRef<NodeJS.Timer | null>()
function onMouseDown(arrowDown: React.MutableRefObject<boolean>): void {
if (arrowDown.current) {
return
}
arrowDown.current = true
startIncrementTimeout.current = setTimeout(() => {
incrementInterval.current = setInterval(() => {
props.onClick(upArrowDown.current)
}, 100)
}, 200)
document.addEventListener('mouseup', () => {
upArrowDown.current = false
downArrowDown.current = false
clearInterval(incrementInterval.current!)
clearTimeout(startIncrementTimeout.current!)
}, {once: true})
}
function onMouseOver(oldArrowDown: React.MutableRefObject<boolean>, newArrowDown: React.MutableRefObject<boolean>): void {
if (oldArrowDown.current) {
oldArrowDown.current = false
newArrowDown.current = true
}
}
function onClick(event: React.MouseEvent<HTMLDivElement>, increment?: boolean): void {
event.preventDefault()
props.onClick(increment);
}
return <div className={'input-arrows'}>
<div className={'input-arrow-up'} onClick={(e): void => onClick(e, true)}
onMouseOver={(): void => onMouseOver(downArrowDown, upArrowDown)}
onMouseDown={(): void => onMouseDown(upArrowDown)}>▾</div>
<div className={'input-arrow-down'} onClick={(e): void => onClick(e)}
onMouseOver={(): void => onMouseOver(upArrowDown, downArrowDown)}
onMouseDown={(): void => onMouseDown(downArrowDown)}>▾</div>
</div>;
}
export function Input(props: { onChange: (n: number) => void }): ReactElement {
const maxValue = 999999
const minValue = 0
const inputRef = useRef<HTMLInputElement>(null)
const currentNumberRef = useRef(-1)
useEffect(() => {
if (inputRef.current) {
currentNumberRef.current = parseInt(inputRef.current.value)
props.onChange(currentNumberRef.current)
}
}, [])
function onTextfieldChange(e: React.ChangeEvent<HTMLInputElement>): void {
let value = parseInt(e.target.value)
if (value > maxValue) {
value = currentNumberRef.current
} else if (value < minValue) {
value = minValue
}
currentNumberRef.current = value
e.target.value = String(value)
props.onChange(value);
}
function onArrowsChange(increment?: boolean): void {
const newValue = currentNumberRef.current + (increment ? 1 : -1)
currentNumberRef.current = newValue
if (inputRef.current) {
inputRef.current.value = String(newValue)
}
props.onChange(newValue)
}
return <>
<label>Number to test
<div className={'input-container'}>
<input ref={inputRef} type={'number'} defaultValue={DEFAULT_DIVIDEND} maxLength={6} max={maxValue}
min={minValue} onChange={(e): void => onTextfieldChange(e)}/>
<InputArrows onClick={(increment?: boolean): void => onArrowsChange(increment)}/>
</div>
</label>
</>
}