Skip to content

Instantly share code, notes, and snippets.

@souporserious
Created November 13, 2017 14:33
Show Gist options
  • Save souporserious/490935622d1ad0ad06bc669234590424 to your computer and use it in GitHub Desktop.
Save souporserious/490935622d1ad0ad06bc669234590424 to your computer and use it in GitHub Desktop.
function pad(num, size) {
let s = num + ''
while (s.length < size) s = '0' + s
return s
}
class NumberField extends Component {
// modified from: https://stackoverflow.com/questions/995183/how-to-allow-only-numeric-0-9-in-html-inputbox-using-jquery
handleKeyDown = e => {
if (
[46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 ||
(e.keyCode === 65 && (e.ctrlKey === true || e.metaKey === true)) ||
(e.keyCode >= 35 && e.keyCode <= 40)
) {
let amount = null
if (e.key === 'ArrowDown') {
amount = -1
} else if (e.key === 'ArrowUp') {
amount = 1
}
if (amount !== null) {
const { min, max } = this.props
let newValue = parseInt(e.target.value, 10) + amount
if (newValue < min) {
newValue = max
} else if (newValue > max) {
newValue = min
}
if (this.props.onChange) {
this.props.onChange({
...e,
value: newValue,
})
} else {
e.target.value = pad(newValue, 2)
e.target.setAttribute('aria-valuenow', pad(newValue, 2))
}
e.preventDefault()
e.target.select()
}
return
}
// Ensure that it is a number and stop the keypress
if (
(e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) &&
(e.keyCode < 96 || e.keyCode > 105)
) {
e.preventDefault()
}
}
handleChange = e => {
const newValue = parseInt(e.target.value, 10)
const { min, max } = this.props
e.preventDefault()
if (newValue >= min && newValue <= max) {
if (this.props.onChange) {
this.props.onChange({
...e,
value: newValue,
})
} else {
e.target.value = pad(newValue, 2)
e.target.setAttribute('aria-valuenow', pad(newValue, 2))
}
e.target.select()
}
}
render() {
const { defaultValue, max, min, value, ...restProps } = this.props
return (
<InputField
role="spinbutton"
type="text"
pattern="\d*"
maxLength={2}
aria-valuemin={min}
aria-valuemax={max}
aria-valuenow={value || defaultValue}
selectOnFocus
onKeyDown={this.handleKeyDown}
onChange={this.handleChange}
basis={2.5}
grow={0}
shrink={0}
textAlign="center"
defaultValue={defaultValue}
value={value}
{...restProps}
/>
)
}
}
class TimeField extends Component {
state = {
beforeMidday: true,
}
toggleMidday = () => {
this.setState(state => ({ beforeMidday: !state.beforeMidday }))
}
handleButtonKeyDown = e => {
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault()
this.toggleMidday()
}
}
render() {
const { defaultValue = '', value, ...restProps } = this.props
const { beforeMidday } = this.state
const [hours, minutes] = (value || defaultValue).split(':')
return (
<InputBox width={11.5} size="xxs" grow={0} shrink={0} {...restProps}>
<NumberField min="1" max="12" defaultValue={hours} aria-label="Hours" />
<Box basis={0.5} height={2.5} grow={0} shrink={0}>
:
</Box>
<NumberField
min="0"
max="59"
defaultValue={minutes}
aria-label="Minutes"
/>
<Button
basis={3.5}
grow={0}
shrink={0}
title={beforeMidday ? 'AM' : 'PM'}
aria-label="AM/PM"
radiusLeft={0}
radiusRight={0}
size="xxs"
color="grey-8"
onKeyDown={this.handleButtonKeyDown}
onClick={this.toggleMidday}
/>
<Button
icon={{ name: 'close' }}
size="xxs"
backgroundColor="grey-6"
radiusLeft={0}
/>
</InputBox>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment