@bitrise/bitkit 10.34.0 → 10.35.0-alpha-datepicker-rewrite.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -20
- package/src/Components/DatePicker/DatePicker.context.ts +14 -0
- package/src/Components/DatePicker/DatePicker.stories.tsx +16 -0
- package/src/Components/DatePicker/DatePicker.test.tsx +94 -0
- package/src/Components/DatePicker/DatePicker.tsx +178 -0
- package/src/Components/DatePicker/DatePickerDay.theme.ts +108 -0
- package/src/Components/DatePicker/DatePickerDay.tsx +137 -0
- package/src/Components/DatePicker/DatePickerFooter.tsx +41 -0
- package/src/Components/DatePicker/DatePickerGrid.tsx +10 -0
- package/src/Components/DatePicker/DatePickerHeader.tsx +72 -0
- package/src/Components/DatePicker/DatePickerMonth.tsx +94 -0
- package/src/Components/DatePicker/DatePickerMonthSelector.tsx +132 -0
- package/src/Components/DatePicker/useDateRange.ts +48 -0
- package/src/Components/DatePicker/useViewDate.ts +35 -0
- package/src/Components/NumberInput/NumberInput.theme.ts +36 -0
- package/src/Foundations/Shadows/Shadows.ts +1 -0
- package/src/Foundations/Sizes/Sizes.ts +1 -0
- package/src/Old/hooks/index.ts +0 -1
- package/src/index.ts +3 -0
- package/src/old.ts +0 -3
- package/src/theme.ts +4 -0
- package/src/tsconfig.tsbuildinfo +1 -1
- package/src/utils/utils.ts +8 -0
- package/src/Old/DatePicker/DatePicker.css +0 -74
- package/src/Old/DatePicker/DatePicker.tsx +0 -194
- package/src/Old/DatePicker/DatePickerDay.tsx +0 -72
- package/src/Old/DatePicker/DatePickerGrid.tsx +0 -12
- package/src/Old/DatePicker/DatePickerMonth.tsx +0 -87
- package/src/Old/hooks/useMediaQuery.ts +0 -91
package/src/utils/utils.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
1
3
|
export const rem = (input: number | string): number | string => {
|
|
2
4
|
const value = typeof input === 'string' ? parseInt(input, 10) : input;
|
|
3
5
|
if (Number.isNaN(value)) {
|
|
@@ -6,3 +8,9 @@ export const rem = (input: number | string): number | string => {
|
|
|
6
8
|
}
|
|
7
9
|
return `${value / 16}rem`;
|
|
8
10
|
};
|
|
11
|
+
|
|
12
|
+
export function useObjectMemo<T extends object>(obj: T): T {
|
|
13
|
+
return useMemo(() => {
|
|
14
|
+
return obj;
|
|
15
|
+
}, Object.values(obj));
|
|
16
|
+
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
.DatePicker__grid + .DatePicker__grid {
|
|
2
|
-
border-top: 0.0625rem solid var(--color-gray--2);
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
.DatePicker__day {
|
|
6
|
-
position: relative;
|
|
7
|
-
width: 3rem;
|
|
8
|
-
height: 3rem;
|
|
9
|
-
transition-property: color;
|
|
10
|
-
transition-duration: var(--transition-duration--fast);
|
|
11
|
-
transition-timing-function: var(--transition-timing-function);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.DatePicker__day::before {
|
|
15
|
-
content: '';
|
|
16
|
-
position: absolute;
|
|
17
|
-
top: 0;
|
|
18
|
-
right: 0;
|
|
19
|
-
bottom: 0;
|
|
20
|
-
left: 0;
|
|
21
|
-
transform: scale(0);
|
|
22
|
-
opacity: 0;
|
|
23
|
-
border-radius: 50%;
|
|
24
|
-
background-color: var(--color-grape--4);
|
|
25
|
-
transition-property: transform, opacity, background-color;
|
|
26
|
-
transition-duration: var(--transition-duration--fast);
|
|
27
|
-
transition-timing-function: var(--transition-timing-function);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.DatePicker__day-inner {
|
|
31
|
-
position: relative;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.DatePicker__day--selectable {
|
|
35
|
-
cursor: pointer;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.DatePicker__day--selectable.DatePicker__day--unselected:hover {
|
|
39
|
-
color: var(--color-gray--1);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.DatePicker__day--selected::before {
|
|
43
|
-
transform: scale(calc(2.5 / 3));
|
|
44
|
-
opacity: 1;
|
|
45
|
-
background-color: var(--color-grape--4);
|
|
46
|
-
transform: scale(1);
|
|
47
|
-
background-color: var(--color-aqua--3);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.DatePicker__day--selectable.DatePicker__day--unselected:hover::before {
|
|
51
|
-
transform: scale(calc(2.5 / 3));
|
|
52
|
-
opacity: 1;
|
|
53
|
-
background-color: var(--color-grape--4);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.DatePicker__day--selected-from,
|
|
57
|
-
.DatePicker__day--selected-between,
|
|
58
|
-
.DatePicker__day--selected-to {
|
|
59
|
-
background-color: var(--color-aqua--2);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.DatePicker__day--selected-from {
|
|
63
|
-
border-top-left-radius: 50%;
|
|
64
|
-
border-bottom-left-radius: 50%;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.DatePicker__day--selected-to {
|
|
68
|
-
border-top-right-radius: 50%;
|
|
69
|
-
border-bottom-right-radius: 50%;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.DatePicker__day--unselectable {
|
|
73
|
-
color: var(--color-gray--5);
|
|
74
|
-
}
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react/destructuring-assignment */
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { DateTime } from 'luxon';
|
|
4
|
-
import { ReferenceChildrenProps } from 'react-popper';
|
|
5
|
-
import { useMediaQuery, useSyncedStateAndProps } from '../hooks';
|
|
6
|
-
import Button from '../../Components/Button/Button';
|
|
7
|
-
import ButtonGroup from '../../Components/ButtonGroup/ButtonGroup';
|
|
8
|
-
import { Props as FlexProps } from '../Flex/Flex';
|
|
9
|
-
import Placement from '../Placement/Placement';
|
|
10
|
-
import PlacementArea from '../Placement/PlacementArea';
|
|
11
|
-
import PlacementManager from '../Placement/PlacementManager';
|
|
12
|
-
import PlacementReference from '../Placement/PlacementReference';
|
|
13
|
-
import DatePickerMonth from './DatePickerMonth';
|
|
14
|
-
import './DatePicker.css';
|
|
15
|
-
|
|
16
|
-
const { useState } = React;
|
|
17
|
-
|
|
18
|
-
export interface Props extends FlexProps {
|
|
19
|
-
/**
|
|
20
|
-
* PlacementReference children prop for passing down
|
|
21
|
-
* the ref of the target to be placed around.
|
|
22
|
-
*/
|
|
23
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
-
children: (props: ReferenceChildrenProps) => React.ReactNode;
|
|
25
|
-
/**
|
|
26
|
-
* The earliest date that can be selected.
|
|
27
|
-
* Should be given in millisecond form. For example 1558973847330
|
|
28
|
-
*/
|
|
29
|
-
dateSelectableFrom?: number;
|
|
30
|
-
/**
|
|
31
|
-
* The latest date that can be selected.
|
|
32
|
-
* Should be given in millisecond form. For example 1558973847330
|
|
33
|
-
*/
|
|
34
|
-
dateSelectableTo?: number;
|
|
35
|
-
/**
|
|
36
|
-
* The start date of the selected period.
|
|
37
|
-
* Should be given in millisecond form. For example 1558973847330
|
|
38
|
-
*/
|
|
39
|
-
dateSelectedFrom?: number;
|
|
40
|
-
/**
|
|
41
|
-
* The end date of the selected period.
|
|
42
|
-
* Should be given in millisecond form. For example 1558973847330
|
|
43
|
-
*/
|
|
44
|
-
dateSelectedTo?: number;
|
|
45
|
-
/** Handler for when the selected period is chosen. */
|
|
46
|
-
onApply?: (dateSelectedFrom?: number, dateSelectedTo?: number) => void;
|
|
47
|
-
/** Handler for when the date picker has been asked to be closed. */
|
|
48
|
-
onClose: () => void;
|
|
49
|
-
/** Flag for when the date picker should be visible. */
|
|
50
|
-
visible: boolean;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* A simple date selection component, that supports a dual month view and
|
|
55
|
-
* range selection.
|
|
56
|
-
*/
|
|
57
|
-
const DatePicker: React.FunctionComponent<Props> = (props: Props) => {
|
|
58
|
-
const { children, onApply, onClose, visible } = props;
|
|
59
|
-
|
|
60
|
-
const match = useMediaQuery(['56rem']);
|
|
61
|
-
const [dateSelectedFromMillis, setDateSelectedFromMillis] = useSyncedStateAndProps(props.dateSelectedFrom);
|
|
62
|
-
const [dateSelectedToMillis, setDateSelectedToMillis] = useSyncedStateAndProps(props.dateSelectedTo);
|
|
63
|
-
const [viewDateStartMillis, setViewDateStartMillis] = useState(dateSelectedFromMillis);
|
|
64
|
-
const [viewDateEndMillis, setViewDateEndMillis] = useState(dateSelectedToMillis);
|
|
65
|
-
|
|
66
|
-
const dateSelectableFrom =
|
|
67
|
-
props.dateSelectableFrom === undefined ? undefined : DateTime.fromMillis(props.dateSelectableFrom).startOf('day');
|
|
68
|
-
const dateSelectableTo =
|
|
69
|
-
props.dateSelectableTo === undefined ? undefined : DateTime.fromMillis(props.dateSelectableTo);
|
|
70
|
-
const dateSelectedFrom = dateSelectedFromMillis && DateTime.fromMillis(dateSelectedFromMillis).startOf('day');
|
|
71
|
-
const dateSelectedTo = dateSelectedToMillis && DateTime.fromMillis(dateSelectedToMillis).startOf('day');
|
|
72
|
-
|
|
73
|
-
const viewDateStart = viewDateStartMillis
|
|
74
|
-
? DateTime.fromMillis(viewDateStartMillis).startOf('month')
|
|
75
|
-
: DateTime.local().startOf('month');
|
|
76
|
-
|
|
77
|
-
const viewDateEnd =
|
|
78
|
-
viewDateEndMillis && !DateTime.fromMillis(viewDateEndMillis).startOf('month').equals(viewDateStart)
|
|
79
|
-
? DateTime.fromMillis(viewDateEndMillis).startOf('month')
|
|
80
|
-
: viewDateStart.plus({ months: 1 }).startOf('month');
|
|
81
|
-
|
|
82
|
-
const handleClose = () => {
|
|
83
|
-
onClose();
|
|
84
|
-
setDateSelectedFromMillis(undefined);
|
|
85
|
-
setDateSelectedToMillis(undefined);
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const handleApply = () => {
|
|
89
|
-
if (onApply) {
|
|
90
|
-
onApply(dateSelectedFromMillis, dateSelectedToMillis);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
handleClose();
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const handlePreviousMonthStart = () => {
|
|
97
|
-
setViewDateStartMillis(+viewDateStart.minus({ months: 1 }));
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const handleNextMonthStart = () => {
|
|
101
|
-
setViewDateStartMillis(+viewDateStart.plus({ months: 1 }));
|
|
102
|
-
|
|
103
|
-
if (viewDateStart.plus({ months: 1 }).equals(viewDateEnd)) {
|
|
104
|
-
setViewDateEndMillis(+viewDateEnd.plus({ months: 1 }));
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const handlePreviousMonthEnd = () => {
|
|
109
|
-
setViewDateEndMillis(+viewDateEnd.minus({ months: 1 }));
|
|
110
|
-
|
|
111
|
-
if (viewDateEnd.minus({ months: 1 }).equals(viewDateStart)) {
|
|
112
|
-
setViewDateStartMillis(+viewDateStart.minus({ months: 1 }));
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const handleNextMonthEnd = () => {
|
|
117
|
-
setViewDateEndMillis(+viewDateEnd.plus({ months: 1 }));
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const handleSelect = (date: DateTime) => {
|
|
121
|
-
let nextDateSelectedFrom: undefined | DateTime = dateSelectedFrom;
|
|
122
|
-
let nextDateSelectedTo: undefined | DateTime = dateSelectedTo;
|
|
123
|
-
|
|
124
|
-
if (dateSelectedFrom && dateSelectedTo) {
|
|
125
|
-
nextDateSelectedFrom = date;
|
|
126
|
-
nextDateSelectedTo = undefined;
|
|
127
|
-
} else if (dateSelectedFrom) {
|
|
128
|
-
nextDateSelectedTo = date;
|
|
129
|
-
} else {
|
|
130
|
-
nextDateSelectedFrom = date;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (nextDateSelectedFrom && nextDateSelectedTo && +nextDateSelectedFrom > +nextDateSelectedTo) {
|
|
134
|
-
[nextDateSelectedFrom, nextDateSelectedTo] = [nextDateSelectedTo, nextDateSelectedFrom];
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
setDateSelectedFromMillis(nextDateSelectedFrom && nextDateSelectedFrom.toMillis());
|
|
138
|
-
setDateSelectedToMillis(nextDateSelectedTo && nextDateSelectedTo.toMillis());
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
return (
|
|
142
|
-
<PlacementManager>
|
|
143
|
-
<PlacementReference>{children}</PlacementReference>
|
|
144
|
-
|
|
145
|
-
<Placement onClose={onClose} visible={visible}>
|
|
146
|
-
{() => (
|
|
147
|
-
<PlacementArea paddingVertical="x8">
|
|
148
|
-
<PlacementArea direction="horizontal">
|
|
149
|
-
<PlacementArea paddingHorizontal="x8">
|
|
150
|
-
<DatePickerMonth
|
|
151
|
-
dateSelectableFrom={dateSelectableFrom}
|
|
152
|
-
dateSelectableTo={dateSelectableTo}
|
|
153
|
-
dateSelectedFrom={dateSelectedFrom}
|
|
154
|
-
dateSelectedTo={dateSelectedTo}
|
|
155
|
-
onNextMonth={handleNextMonthStart}
|
|
156
|
-
onPreviousMonth={handlePreviousMonthStart}
|
|
157
|
-
onSelect={handleSelect}
|
|
158
|
-
viewDate={viewDateStart}
|
|
159
|
-
/>
|
|
160
|
-
</PlacementArea>
|
|
161
|
-
|
|
162
|
-
{match('56rem') && (
|
|
163
|
-
<PlacementArea paddingHorizontal="x8">
|
|
164
|
-
<DatePickerMonth
|
|
165
|
-
dateSelectableFrom={dateSelectableFrom}
|
|
166
|
-
dateSelectableTo={dateSelectableTo}
|
|
167
|
-
dateSelectedFrom={dateSelectedFrom}
|
|
168
|
-
dateSelectedTo={dateSelectedTo}
|
|
169
|
-
onNextMonth={handleNextMonthEnd}
|
|
170
|
-
onPreviousMonth={handlePreviousMonthEnd}
|
|
171
|
-
onSelect={handleSelect}
|
|
172
|
-
viewDate={viewDateEnd}
|
|
173
|
-
/>
|
|
174
|
-
</PlacementArea>
|
|
175
|
-
)}
|
|
176
|
-
</PlacementArea>
|
|
177
|
-
|
|
178
|
-
<ButtonGroup alignItems="flex-end" marginY="8" paddingX="32">
|
|
179
|
-
<Button variant="secondary" onClick={handleClose} size="small">
|
|
180
|
-
Cancel
|
|
181
|
-
</Button>
|
|
182
|
-
|
|
183
|
-
<Button onClick={handleApply} size="small">
|
|
184
|
-
Apply
|
|
185
|
-
</Button>
|
|
186
|
-
</ButtonGroup>
|
|
187
|
-
</PlacementArea>
|
|
188
|
-
)}
|
|
189
|
-
</Placement>
|
|
190
|
-
</PlacementManager>
|
|
191
|
-
);
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
export default DatePicker;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import classnames from 'classnames';
|
|
3
|
-
import { DateTime } from 'luxon';
|
|
4
|
-
import Flex, { Props as FlexProps } from '../Flex/Flex';
|
|
5
|
-
|
|
6
|
-
interface Props extends FlexProps {
|
|
7
|
-
dateSelectableFrom?: DateTime;
|
|
8
|
-
dateSelectableTo?: DateTime;
|
|
9
|
-
dateSelectedFrom?: DateTime;
|
|
10
|
-
dateSelectedTo?: DateTime;
|
|
11
|
-
n: number;
|
|
12
|
-
onSelect: (date: DateTime) => void;
|
|
13
|
-
viewDate: DateTime;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const DatePickerDay: React.FunctionComponent<Props> = (props: Props) => {
|
|
17
|
-
const { dateSelectableFrom, dateSelectableTo, dateSelectedFrom, dateSelectedTo, n, onSelect, viewDate, ...rest } =
|
|
18
|
-
props;
|
|
19
|
-
|
|
20
|
-
const date = viewDate.plus({ days: n - viewDate.weekday });
|
|
21
|
-
|
|
22
|
-
const dayOfWeek = viewDate.weekday;
|
|
23
|
-
const { daysInMonth } = viewDate;
|
|
24
|
-
const daysInPreviousMonth = viewDate.minus({ month: 1 }).daysInMonth;
|
|
25
|
-
|
|
26
|
-
const isPreviousMonth = n < dayOfWeek;
|
|
27
|
-
const isNextMonth = n - dayOfWeek >= daysInMonth;
|
|
28
|
-
const isCurrentMonth = !isPreviousMonth && !isNextMonth;
|
|
29
|
-
const isAfterSelectableFromDate = !dateSelectableFrom || date.equals(dateSelectableFrom) || date > dateSelectableFrom;
|
|
30
|
-
const isBeforeSelectableToDate = !dateSelectableTo || date.equals(dateSelectableTo) || date < dateSelectableTo;
|
|
31
|
-
const isSelectable = isCurrentMonth && isAfterSelectableFromDate && isBeforeSelectableToDate;
|
|
32
|
-
|
|
33
|
-
const hasSelectionRange = dateSelectedFrom && dateSelectedTo && !dateSelectedFrom.equals(dateSelectedTo);
|
|
34
|
-
|
|
35
|
-
const isSelectedFrom = isCurrentMonth && dateSelectedFrom && date.equals(dateSelectedFrom);
|
|
36
|
-
const isSelectedTo = isCurrentMonth && dateSelectedTo && date.equals(dateSelectedTo);
|
|
37
|
-
const isSelectedBetween =
|
|
38
|
-
isCurrentMonth &&
|
|
39
|
-
dateSelectedFrom &&
|
|
40
|
-
dateSelectedTo &&
|
|
41
|
-
hasSelectionRange &&
|
|
42
|
-
+date > +dateSelectedFrom &&
|
|
43
|
-
+date < +dateSelectedTo;
|
|
44
|
-
|
|
45
|
-
const classes = classnames('DatePicker__day', {
|
|
46
|
-
'DatePicker__day--selected': isSelectedFrom || isSelectedTo,
|
|
47
|
-
'DatePicker__day--selected-between': isSelectedBetween,
|
|
48
|
-
'DatePicker__day--selected-from': hasSelectionRange && isSelectedFrom,
|
|
49
|
-
'DatePicker__day--selected-to': hasSelectionRange && isSelectedTo,
|
|
50
|
-
'DatePicker__day--selectable': isSelectable,
|
|
51
|
-
'DatePicker__day--unselected': !isSelectedFrom && !isSelectedTo && !isSelectedBetween,
|
|
52
|
-
'DatePicker__day--unselectable': !isSelectable,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<Flex
|
|
57
|
-
{...rest}
|
|
58
|
-
alignChildren="middle"
|
|
59
|
-
className={classes}
|
|
60
|
-
direction="horizontal"
|
|
61
|
-
onClick={isSelectable ? () => onSelect(date) : undefined}
|
|
62
|
-
>
|
|
63
|
-
<Flex alignChildren="middle" className="DatePicker__day-inner" direction="horizontal">
|
|
64
|
-
{isPreviousMonth && daysInPreviousMonth - (dayOfWeek - n - 1)}
|
|
65
|
-
{isCurrentMonth && n - dayOfWeek + 1}
|
|
66
|
-
{isNextMonth && n - dayOfWeek - daysInMonth + 1}
|
|
67
|
-
</Flex>
|
|
68
|
-
</Flex>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export default DatePickerDay;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import Box, { BoxProps } from '../../Components/Box/Box';
|
|
3
|
-
|
|
4
|
-
type Props = BoxProps;
|
|
5
|
-
|
|
6
|
-
const DatePickerGrid: React.FunctionComponent<Props> = (props: Props) => {
|
|
7
|
-
return (
|
|
8
|
-
<Box display="grid" {...props} gridTemplateColumns="repeat(7, 3rem)" gridAutoRows="max-content" gridRowGap="4" />
|
|
9
|
-
);
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export default DatePickerGrid;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { DateTime, Info } from 'luxon';
|
|
3
|
-
import Base, { Props as BaseProps } from '../Base/Base';
|
|
4
|
-
import Flex from '../Flex/Flex';
|
|
5
|
-
import Icon from '../../Components/Icon/Icon';
|
|
6
|
-
import Link from '../../Components/Link/Link';
|
|
7
|
-
import Text from '../../Components/Text/Text';
|
|
8
|
-
import DatePickerGrid from './DatePickerGrid';
|
|
9
|
-
import DatePickerDay from './DatePickerDay';
|
|
10
|
-
|
|
11
|
-
const daysOfTheWeek = Info.weekdays('short');
|
|
12
|
-
const daysCount = 6 * 7;
|
|
13
|
-
|
|
14
|
-
interface Props extends BaseProps {
|
|
15
|
-
dateSelectableFrom?: DateTime;
|
|
16
|
-
dateSelectableTo?: DateTime;
|
|
17
|
-
dateSelectedFrom?: DateTime;
|
|
18
|
-
dateSelectedTo?: DateTime;
|
|
19
|
-
onNextMonth: () => void;
|
|
20
|
-
onPreviousMonth: () => void;
|
|
21
|
-
onSelect: (date: DateTime) => void;
|
|
22
|
-
viewDate: DateTime;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const DatePickerMonth: React.FunctionComponent<Props> = (props: Props) => {
|
|
26
|
-
const {
|
|
27
|
-
dateSelectableFrom,
|
|
28
|
-
dateSelectableTo,
|
|
29
|
-
dateSelectedFrom,
|
|
30
|
-
dateSelectedTo,
|
|
31
|
-
onNextMonth,
|
|
32
|
-
onPreviousMonth,
|
|
33
|
-
onSelect,
|
|
34
|
-
viewDate,
|
|
35
|
-
...rest
|
|
36
|
-
} = props;
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<Base {...rest}>
|
|
40
|
-
<Flex alignChildren="middle" direction="horizontal" gap="x4" margin="x4" paddingHorizontal="x12">
|
|
41
|
-
<Flex>
|
|
42
|
-
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
43
|
-
<Link as="button" onClick={onPreviousMonth}>
|
|
44
|
-
<Icon name="ChevronLeft" />
|
|
45
|
-
</Link>
|
|
46
|
-
</Flex>
|
|
47
|
-
|
|
48
|
-
<Flex grow>
|
|
49
|
-
<Text align="center">{viewDate.toFormat('MMMM yyyy')}</Text>
|
|
50
|
-
</Flex>
|
|
51
|
-
|
|
52
|
-
<Flex>
|
|
53
|
-
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
54
|
-
<Link as="button" onClick={onNextMonth}>
|
|
55
|
-
<Icon name="ChevronRight" />
|
|
56
|
-
</Link>
|
|
57
|
-
</Flex>
|
|
58
|
-
</Flex>
|
|
59
|
-
|
|
60
|
-
<DatePickerGrid marginY="4">
|
|
61
|
-
{daysOfTheWeek.map((day) => (
|
|
62
|
-
<Text textAlign="center" key={day} paddingY="16" size="2" color="neutral.70" textTransform="uppercase">
|
|
63
|
-
{day}
|
|
64
|
-
</Text>
|
|
65
|
-
))}
|
|
66
|
-
</DatePickerGrid>
|
|
67
|
-
|
|
68
|
-
<DatePickerGrid borderTop="1px solid" borderTopColor="neutral.93" paddingY="8">
|
|
69
|
-
{Array.from({ length: daysCount }).map((_, i) => (
|
|
70
|
-
<DatePickerDay
|
|
71
|
-
dateSelectableFrom={dateSelectableFrom}
|
|
72
|
-
dateSelectableTo={dateSelectableTo}
|
|
73
|
-
dateSelectedFrom={dateSelectedFrom}
|
|
74
|
-
dateSelectedTo={dateSelectedTo}
|
|
75
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
76
|
-
key={i}
|
|
77
|
-
n={i + 1}
|
|
78
|
-
onSelect={onSelect}
|
|
79
|
-
viewDate={viewDate}
|
|
80
|
-
/>
|
|
81
|
-
))}
|
|
82
|
-
</DatePickerGrid>
|
|
83
|
-
</Base>
|
|
84
|
-
);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export default DatePickerMonth;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
import { useEffect, useRef, useState } from 'react';
|
|
4
|
-
|
|
5
|
-
interface MatchPatternConfig {
|
|
6
|
-
[key: string]: any;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface Listener {
|
|
10
|
-
listener: MediaQueryList;
|
|
11
|
-
media: string;
|
|
12
|
-
query: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type Handler = (e: MediaQueryListEvent) => void;
|
|
16
|
-
|
|
17
|
-
const getListeners = (queries: string[], handler: Handler) => queries.map((query) => {
|
|
18
|
-
const media = `(min-width: ${query})`;
|
|
19
|
-
const listener = window.matchMedia(media);
|
|
20
|
-
|
|
21
|
-
listener.addListener(handler);
|
|
22
|
-
|
|
23
|
-
return { listener, media, query };
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const getMatchQueryIndex = (queries: string[], listeners: Listener[]) => {
|
|
27
|
-
for (let i = queries.length; i--;) {
|
|
28
|
-
if (listeners[i].listener.matches) {
|
|
29
|
-
return queries.indexOf(listeners[i].query);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return -1;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const removeListeners = (listeners: Listener[], handler: Handler) => {
|
|
37
|
-
listeners.forEach(({ listener }) => {
|
|
38
|
-
listener.removeListener(handler);
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export default (queries: string[]) => {
|
|
43
|
-
const handleQueryChange = (event: MediaQueryListEvent) => {
|
|
44
|
-
const listener = listeners.current.find(({ media }) => media === event.media);
|
|
45
|
-
|
|
46
|
-
if (listener && hasMounted.current) {
|
|
47
|
-
setHitIndex(getMatchQueryIndex(queries, listeners.current));
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const hasMounted = useRef(false);
|
|
52
|
-
const listeners = useRef<Listener[]>(getListeners(queries, handleQueryChange));
|
|
53
|
-
const [hitIndex, setHitIndex] = useState(getMatchQueryIndex(queries, listeners.current));
|
|
54
|
-
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
if (!hasMounted.current) {
|
|
57
|
-
hasMounted.current = true;
|
|
58
|
-
} else {
|
|
59
|
-
removeListeners(listeners.current, handleQueryChange);
|
|
60
|
-
listeners.current = getListeners(queries, handleQueryChange);
|
|
61
|
-
setHitIndex(getMatchQueryIndex(queries, listeners.current));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return () => {
|
|
65
|
-
removeListeners(listeners.current, handleQueryChange);
|
|
66
|
-
};
|
|
67
|
-
}, [...queries]);
|
|
68
|
-
|
|
69
|
-
useEffect(() => () => {
|
|
70
|
-
hasMounted.current = false;
|
|
71
|
-
}, []);
|
|
72
|
-
|
|
73
|
-
function match(pattern: string, fallback?: never): boolean;
|
|
74
|
-
function match(pattern: MatchPatternConfig, fallback?: string): any;
|
|
75
|
-
function match(pattern: string | MatchPatternConfig, fallback?: string): any {
|
|
76
|
-
if (typeof pattern === 'string') {
|
|
77
|
-
const patternIndex = queries.indexOf(pattern);
|
|
78
|
-
return patternIndex >= 0 && patternIndex <= hitIndex;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
for (let i = hitIndex + 1; i--;) {
|
|
82
|
-
if (queries[i] in pattern) {
|
|
83
|
-
return pattern[queries[i]];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return fallback;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return match;
|
|
91
|
-
};
|