react-styled-date-time-picker
Version:
```javascript import React, { Component } from 'react'; import DateTimePicker from 'react-styled-date-time-picker'; import { DateTime } from 'luxon';
213 lines (184 loc) • 5.2 kB
Flow
// @flow
/* eslint-disable import/no-unresolved, import/extensions, import/no-extraneous-dependencies */
import { Component } from 'react';
import styled, { type StyledComponent } from 'styled-components';
import { type DateTime } from 'luxon';
/** eslint-enable */
import Arrow from './Arrow';
const TimeInputContainer: StyledComponent<{}, {}, HTMLDivElement> = styled.div`
text-align: center;
`;
const Label: StyledComponent<{ visible: boolean }, {}, HTMLSpanElement> = styled.span`
display: ${(props) => (props.visible ? 'inline-block' : 'none')};
width: 65px;
height: 65px;
font-size: 38px;
line-height: 65px;
background-color: #00A15F;
border-radius: 3px;
text-align: center;
font-family: Roboto;
cursor: pointer;
`;
const Input: StyledComponent<{ show: boolean }, {}, HTMLInputElement> = styled.input`
display: ${(props) => (props.show ? 'inline-block' : 'none')};
width: 65px;
height: 65px;
font-size: 38px;
line-height: 65px;
background-color: #00A15F;
border-radius: 3px;
text-align: center;
-webkit-appearance: none;
color: #f8f8f8;
border: 0;
padding: 0;
margin: 0;
vertical-align: baseline;
outline: 0;
font-family: Roboto;
`;
const Separator: StyledComponent<{}, {}, HTMLSpanElement> = styled.span`
display: inline-block;
font-size: 32px;
font-weight: bold;
color: #00A15F;
width: 32px;
height: 65px;
line-height: 65px;
text-align: center;
`;
const FlexRow: StyledComponent<{}, {}, HTMLDivElement> = styled.div`
flex: 0 0 100%;
`;
const ArrowContainer: StyledComponent<{}, {}, HTMLSpanElement> = styled.span`
margin: 0 16px;
& svg {
cursor: pointer;
}
`;
const ArrowDownContainer = styled(ArrowContainer)`
& svg {
transform: rotate(180deg);
}
`;
const addZeroInFront = (value: number): string => (
value < 10
? `0${value}`
: `${value}`
);
type Props = {|
+value: DateTime,
+onChange: (date: DateTime) => void,
|};
type State = {|
+editHours: boolean,
+editMinutes: boolean
|};
class Time extends Component<Props, State> {
state: State = {
editHours: false,
editMinutes: false,
};
hours: ?HTMLInputElement;
minutes: ?HTMLInputElement;
updateHours = (e: SyntheticInputEvent<HTMLInputElement>): void => {
const {
value, onChange,
} = this.props;
const date = value.set({ hours: parseInt(e.target.value, 10) });
onChange(date);
this.editHours();
}
updateMinutes = (e: SyntheticInputEvent<HTMLInputElement>): void => {
const {
value, onChange,
} = this.props;
const date = value.set({ minutes: parseInt(e.target.value, 10) });
onChange(date);
this.editMinutes();
}
editHours = (): void => {
this.setState((state) => ({ editHours: !state.editHours }));
setTimeout(() => {
if (this.hours) this.hours.focus();
}, 0);
}
editMinutes = (): void => {
this.setState((state) => ({ editMinutes: !state.editMinutes }));
setTimeout(() => {
if (this.minutes) this.minutes.focus();
}, 0);
}
hoursUp = (): void => {
const { value, onChange } = this.props;
onChange(value.plus({ hour: 1 }));
}
hoursDown = (): void => {
const { value, onChange } = this.props;
onChange(value.minus({ hour: 1 }));
}
minutesUp = (): void => {
const { value, onChange } = this.props;
onChange(value.plus({ minute: 5 }));
}
minutesDown = (): void => {
const { value, onChange } = this.props;
onChange(value.minus({ minute: 5 }));
}
render(): React$Node {
const { editHours, editMinutes } = this.state;
const { value } = this.props;
return (
<TimeInputContainer>
<FlexRow>
<ArrowContainer>
<Arrow height="65" width="65" onClick={this.hoursUp} />
</ArrowContainer>
<ArrowContainer>
<Arrow height="65" width="65" onClick={this.minutesUp} />
</ArrowContainer>
</FlexRow>
<FlexRow>
<Input
type="text"
key={1}
defaultValue={value.hour}
onBlur={this.updateHours}
min={0}
max={23}
ref={(node) => { this.hours = node; }}
show={editHours}
/>
<Label visible={!editHours} onClick={this.editHours}>
{value.hour}
</Label>
<Separator>:</Separator>
<Input
type="text"
key={2}
className="time"
defaultValue={value.minute}
onBlur={this.updateMinutes}
min={0}
max={23}
ref={(node) => { this.minutes = node; }}
show={editMinutes}
/>
<Label visible={!editMinutes} onClick={this.editMinutes}>
{addZeroInFront(value.minute)}
</Label>
</FlexRow>
<FlexRow>
<ArrowDownContainer>
<Arrow height="65" width="65" onClick={this.hoursDown} />
</ArrowDownContainer>
<ArrowDownContainer>
<Arrow height="65" width="65" onClick={this.minutesDown} />
</ArrowDownContainer>
</FlexRow>
</TimeInputContainer>
);
}
}
export default Time;