react-sprucebot
Version:
React components for your Sprucebot Skill 💪🏼
365 lines (345 loc) • 7.13 kB
JavaScript
import React, { Component, Fragment } from 'react'
import PropTypes from 'prop-types'
import styled, { injectGlobal } from 'styled-components'
import is from 'is_js'
import RCTimePicker from 'rc-time-picker'
import moment from 'moment'
import Button from '../Button/Button'
const Input = styled.input`
width: unset;
flex: 2;
background-color: transparent;
border: none;
color: #808080;
font-size: 1.2em;
margin: 0.5em;
padding: 0;
text-align: center;
&::-webkit-clear-button {
display: none;
}
&::-ms-clear {
display: none;
}
`
injectGlobal`
.rc-time-picker {
display: inline-block;
box-sizing: border-box;
}
.rc-time-picker * {
box-sizing: border-box;
}
.rc-time-picker-input {
flex: 2;
background-color: transparent;
border: none;
color: #808080;
font-size: 1.2em;
margin: 0.5em;
padding: 0;
width: 100%;
position: relative;
display: inline-block;
height: 28px;
cursor: text;
line-height: 1.5;
border-radius: 4px;
text-align: center;
transition: border 0.2s cubic-bezier(0.645, 0.045, 0.355, 1),
background 0.2s cubic-bezier(0.645, 0.045, 0.355, 1),
box-shadow 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.rc-time-picker-input[disabled] {
color: #ccc;
background: #f7f7f7;
cursor: not-allowed;
}
.rc-time-picker-panel {
z-index: 1070;
width: 170px;
position: absolute;
box-sizing: border-box;
}
.rc-time-picker-panel * {
box-sizing: border-box;
}
.rc-time-picker-panel-inner {
display: inline-block;
position: relative;
outline: none;
list-style: none;
font-size: 12px;
text-align: left;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 5px #ccc;
background-clip: padding-box;
border: 1px solid #ccc;
line-height: 1.5;
}
.rc-time-picker-panel-narrow {
max-width: 113px;
}
.rc-time-picker-panel-input {
color: #808080;
font-size: 1.2em;
margin: 0;
padding: 0;
width: 100%;
cursor: auto;
line-height: 1.5;
outline: 0;
border: 1px solid transparent;
}
.rc-time-picker-panel-input-wrap {
box-sizing: border-box;
position: relative;
padding: 6px;
border-bottom: 1px solid #e9e9e9;
}
.rc-time-picker-panel-input-invalid {
border-color: red;
}
.rc-time-picker-panel-clear-btn {
position: absolute;
right: 6px;
cursor: pointer;
overflow: hidden;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
top: 6px;
margin: 0;
}
.rc-time-picker-panel-clear-btn:after {
content: 'x';
font-size: 12px;
color: #aaa;
display: inline-block;
line-height: 1;
width: 20px;
transition: color 0.3s ease;
}
.rc-time-picker-panel-clear-btn:hover:after {
color: #666;
}
.rc-time-picker-panel-select {
float: left;
font-size: 12px;
border: 1px solid #e9e9e9;
border-width: 0 1px;
margin-left: -1px;
box-sizing: border-box;
width: 56px;
max-height: 144px;
overflow-y: auto;
position: relative;
}
.rc-time-picker-panel-select-active {
overflow-y: auto;
}
.rc-time-picker-panel-select:first-child {
border-left: 0;
margin-left: 0;
}
.rc-time-picker-panel-select:last-child {
border-right: 0;
}
.rc-time-picker-panel-select ul {
list-style: none;
box-sizing: border-box;
margin: 0;
padding: 0;
width: 100%;
overflow-x: hidden;
}
.rc-time-picker-panel-select li {
color: #808080;
font-size: 1.2em;
list-style: none;
box-sizing: content-box;
margin: 0;
padding: 0 0 0 16px;
width: 100%;
height: 24px;
line-height: 24px;
text-align: left;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.rc-time-picker-panel-select li:hover {
background: #edfaff;
}
li.rc-time-picker-panel-select-option-selected {
background: #f7f7f7;
font-weight: bold;
}
li.rc-time-picker-panel-select-option-disabled {
color: #ccc;
}
li.rc-time-picker-panel-select-option-disabled:hover {
background: transparent;
cursor: not-allowed;
}
.rc-time-picker-panel-combobox {
border-bottom: 1px solid #e9e9e9;
overflow: hidden;
}
`
const ConfirmWrapper = styled.div`
border: 1px solid #e9e9e9;
padding: 5px 0 0;
width: 100%;
`
const ConfirmButton = styled(Button)`
&& {
border-radius: 0;
width: calc(100% - 10px);
margin: 0 auto;
}
`
export default class TimeInput extends Component {
constructor(props) {
super(props)
const { defaultValue, ...rest } = props
this.state = {
value: defaultValue || '',
time: defaultValue ? moment(`2017-04-01 ${defaultValue}`) : '',
rest,
open: false
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.value) {
this.setState({
value: nextProps.value
})
}
}
onChange = async e => {
const { onChange } = this.props
await this.setState({
value: this.input.value
})
if (onChange) {
onChange(this.input.value)
}
}
onKeyDown = e => {
const { disableEnter, onKeyDown } = this.props
if (disableEnter && e.key === 'Enter') {
e.preventDefault()
}
if (onKeyDown) {
onKeyDown(e)
}
}
onTimePickerChange = async momentTime => {
const { onChange } = this.props
const time = momentTime.format('HH:mm')
await this.setState({
value: time
})
if (onChange) {
onChange(time)
}
}
onConfirm = () => {
this.rcOnClose()
if (this.props.onConfirm) {
this.props.onConfirm()
}
}
get value() {
return this.state.value
}
rcAddon = () => {
const { hideConfirm, confirmButtonProps, confirmButtonText } = this.props
const text = confirmButtonText || 'Confirm'
return (
<Fragment>
{!hideConfirm && (
<ConfirmWrapper>
<ConfirmButton
primary
onClick={this.onConfirm}
{...confirmButtonProps}
>
{text}
</ConfirmButton>
</ConfirmWrapper>
)}
</Fragment>
)
}
rcOnOpen = open => {
this.setState({
open: true
})
}
rcOnClose = open => {
this.setState({
open: false
})
}
render() {
const {
onChange,
onKeyDown,
defaultValue,
value,
disableEnter,
usePicker,
hideConfirm,
confirmButtonProps,
...rest
} = this.props
return (
<Fragment>
{(is.chrome() || is.safari()) && is.mobile() && !usePicker ? (
<Input
type="time"
value={this.state.value}
onKeyDown={this.onKeyDown}
onChange={this.onChange}
innerRef={ref => (this.input = ref)}
{...rest}
/>
) : (
<Fragment>
<RCTimePicker
ref={ref => (this.timePicker = ref)}
showSecond={false}
minuteStep={5}
defaultValue={this.state.time}
onChange={this.onTimePickerChange}
format={'h:mm a'}
use12Hours
inputReadOnly
addon={this.rcAddon}
open={this.state.open}
onOpen={this.rcOnOpen}
onClose={this.rcOnClose}
{...rest}
/>
</Fragment>
)}
</Fragment>
)
}
}
TimeInput.propTypes = {
onChange: PropTypes.func,
defaultValue: PropTypes.string,
usePicker: PropTypes.bool,
hideConfirm: PropTypes.bool,
value: PropTypes.string,
confirmButtonProps: PropTypes.object,
placeholder: PropTypes.string
}
TimeInput.defaultProps = {}