/
Date.tsx
121 lines (108 loc) · 3.54 KB
/
Date.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import React, { FC, ChangeEvent, RefObject, useState, useRef, useEffect } from 'react';
import { styled } from '@storybook/theming';
import { Form } from '../form';
import { ControlProps, DateValue, DateConfig } from './types';
import { getControlId } from './helpers';
export const parseDate = (value: string) => {
const [year, month, day] = value.split('-');
const result = new Date();
result.setFullYear(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10));
return result;
};
export const parseTime = (value: string) => {
const [hours, minutes] = value.split(':');
const result = new Date();
result.setHours(parseInt(hours, 10));
result.setMinutes(parseInt(minutes, 10));
return result;
};
export const formatDate = (value: Date | number) => {
const date = new Date(value);
const year = `000${date.getFullYear()}`.slice(-4);
const month = `0${date.getMonth() + 1}`.slice(-2);
const day = `0${date.getDate()}`.slice(-2);
return `${year}-${month}-${day}`;
};
export const formatTime = (value: Date | number) => {
const date = new Date(value);
const hours = `0${date.getHours()}`.slice(-2);
const minutes = `0${date.getMinutes()}`.slice(-2);
return `${hours}:${minutes}`;
};
const FlexSpaced = styled.div(({ theme }) => ({
flex: 1,
display: 'flex',
input: {
marginLeft: 10,
flex: 1,
height: 32, // hardcode height bc Chromium bug https://bugs.chromium.org/p/chromium/issues/detail?id=417606
'&::-webkit-calendar-picker-indicator': {
opacity: 0.5,
height: 12,
filter: theme.base === 'light' ? undefined : 'invert(1)',
},
},
'input:first-of-type': {
marginLeft: 0,
flexGrow: 4,
},
'input:last-of-type': {
flexGrow: 3,
},
}));
export type DateProps = ControlProps<DateValue> & DateConfig;
export const DateControl: FC<DateProps> = ({ name, value, onChange, onFocus, onBlur }) => {
const [valid, setValid] = useState(true);
const dateRef = useRef<HTMLInputElement>();
const timeRef = useRef<HTMLInputElement>();
useEffect(() => {
if (valid !== false) {
if (dateRef && dateRef.current) {
dateRef.current.value = formatDate(value);
}
if (timeRef && timeRef.current) {
timeRef.current.value = formatTime(value);
}
}
}, [value]);
const onDateChange = (e: ChangeEvent<HTMLInputElement>) => {
const parsed = parseDate(e.target.value);
const result = new Date(value);
result.setFullYear(parsed.getFullYear(), parsed.getMonth(), parsed.getDate());
const time = result.getTime();
if (time) onChange(time);
setValid(!!time);
};
const onTimeChange = (e: ChangeEvent<HTMLInputElement>) => {
const parsed = parseTime(e.target.value);
const result = new Date(value);
result.setHours(parsed.getHours());
result.setMinutes(parsed.getMinutes());
const time = result.getTime();
if (time) onChange(time);
setValid(!!time);
};
const controlId = getControlId(name);
return (
<FlexSpaced>
<Form.Input
type="date"
max="9999-12-31" // I do this because of a rendering bug in chrome
ref={dateRef as RefObject<HTMLInputElement>}
id={`${controlId}-date`}
name={`${controlId}-date`}
onChange={onDateChange}
{...{ onFocus, onBlur }}
/>
<Form.Input
type="time"
id={`${controlId}-time`}
name={`${controlId}-time`}
ref={timeRef as RefObject<HTMLInputElement>}
onChange={onTimeChange}
{...{ onFocus, onBlur }}
/>
{!valid ? <div>invalid</div> : null}
</FlexSpaced>
);
};