@acusti/date-picker 0.10.1 → 0.11.1
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/README.md +3 -3
- package/dist/DatePicker.d.ts +1 -1
- package/dist/index.js +868 -4
- package/dist/index.js.map +1 -1
- package/package.json +17 -9
- package/dist/DatePicker.js +0 -108
- package/dist/DatePicker.js.flow +0 -31
- package/dist/DatePicker.js.map +0 -1
- package/dist/MonthCalendar.js +0 -105
- package/dist/MonthCalendar.js.flow +0 -20
- package/dist/MonthCalendar.js.map +0 -1
- package/dist/index.js.flow +0 -10
- package/dist/styles/date-picker.js +0 -62
- package/dist/styles/date-picker.js.map +0 -1
- package/dist/styles/month-calendar.js +0 -154
- package/dist/styles/month-calendar.js.map +0 -1
- package/dist/utils.js +0 -49
- package/dist/utils.js.flow +0 -20
- package/dist/utils.js.map +0 -1
- package/dist/utils.test.d.ts +0 -1
- package/dist/utils.test.js +0 -88
- package/dist/utils.test.js.flow +0 -6
- package/dist/utils.test.js.map +0 -1
- package/src/DatePicker.tsx +0 -203
- package/src/MonthCalendar.tsx +0 -195
- package/src/index.ts +0 -3
- package/src/styles/date-picker.ts +0 -62
- package/src/styles/month-calendar.ts +0 -154
- package/src/utils.test.ts +0 -163
- package/src/utils.ts +0 -53
package/src/MonthCalendar.tsx
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { Style } from '@acusti/styling';
|
|
2
|
-
import clsx from 'clsx';
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
|
|
5
|
-
import { ROOT_CLASS_NAME, STYLES } from './styles/month-calendar.js';
|
|
6
|
-
import {
|
|
7
|
-
getDateFromMonthAndDay,
|
|
8
|
-
getLastDateFromMonth,
|
|
9
|
-
getMonthFromDate,
|
|
10
|
-
getMonthNameFromMonth,
|
|
11
|
-
getYearFromMonth,
|
|
12
|
-
} from './utils.js';
|
|
13
|
-
|
|
14
|
-
export type Props = {
|
|
15
|
-
className?: string;
|
|
16
|
-
dateEnd?: Date | null | number | string;
|
|
17
|
-
dateEndPreview?: null | string;
|
|
18
|
-
dateStart?: Date | null | number | string;
|
|
19
|
-
isRange?: boolean;
|
|
20
|
-
month: number; // a unique numerical value representing the number of months since jan 1970
|
|
21
|
-
onChange?: (date: string) => void;
|
|
22
|
-
onChangeEndPreview?: (date: string) => void;
|
|
23
|
-
title?: string;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
type DateRangeDays = [null | number, null | number, null | number];
|
|
27
|
-
|
|
28
|
-
const { Fragment, useCallback } = React;
|
|
29
|
-
|
|
30
|
-
const DAYS = Array(7).fill(null);
|
|
31
|
-
|
|
32
|
-
export default function MonthCalendar({
|
|
33
|
-
className,
|
|
34
|
-
dateEnd,
|
|
35
|
-
dateEndPreview,
|
|
36
|
-
dateStart,
|
|
37
|
-
isRange,
|
|
38
|
-
month,
|
|
39
|
-
onChange,
|
|
40
|
-
onChangeEndPreview,
|
|
41
|
-
title,
|
|
42
|
-
}: Props) {
|
|
43
|
-
const year = getYearFromMonth(month);
|
|
44
|
-
title = title ?? `${getMonthNameFromMonth(month)} ${year}`;
|
|
45
|
-
const firstDate = getDateFromMonthAndDay(month, 1);
|
|
46
|
-
const lastDate = getLastDateFromMonth(month);
|
|
47
|
-
const totalDays = lastDate.getDate();
|
|
48
|
-
const firstDay = firstDate.getDay();
|
|
49
|
-
const spacesAfterLastDay = 7 - (lastDate.getDay() % 7); // prettier-ignore
|
|
50
|
-
const daySpaces = totalDays + firstDay + spacesAfterLastDay;
|
|
51
|
-
|
|
52
|
-
const [dateRangeStartDay, dateRangeEndDay, dateRangeEndPreviewDay]: DateRangeDays = [
|
|
53
|
-
dateStart,
|
|
54
|
-
dateEnd,
|
|
55
|
-
dateEndPreview,
|
|
56
|
-
].reduce(
|
|
57
|
-
(acc: DateRangeDays, date, index) => {
|
|
58
|
-
if (date != null && !(date instanceof Date)) {
|
|
59
|
-
date = new Date(date);
|
|
60
|
-
}
|
|
61
|
-
if (date == null || Number.isNaN(date.getTime())) return acc;
|
|
62
|
-
|
|
63
|
-
const dateMonth = getMonthFromDate(date);
|
|
64
|
-
if (dateMonth < month) acc[index] = -1;
|
|
65
|
-
else if (dateMonth > month) acc[index] = totalDays + 1;
|
|
66
|
-
else acc[index] = date.getDate();
|
|
67
|
-
if (index === 1) {
|
|
68
|
-
const startDay = acc[index - 1];
|
|
69
|
-
const endDay = acc[index];
|
|
70
|
-
// Ensure that end date is after start date and swap them if not
|
|
71
|
-
if (startDay != null && endDay != null && startDay > endDay) {
|
|
72
|
-
acc[index - 1] = endDay;
|
|
73
|
-
acc[index] = startDay;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return acc;
|
|
78
|
-
},
|
|
79
|
-
[null, null, null],
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const handleClickDay = useCallback(
|
|
83
|
-
(event: React.SyntheticEvent<HTMLElement>) => {
|
|
84
|
-
const { date } = event.currentTarget.dataset;
|
|
85
|
-
if (date && onChange) onChange(date);
|
|
86
|
-
},
|
|
87
|
-
[onChange],
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
const handleMouseEnterDay = useCallback(
|
|
91
|
-
(event: React.SyntheticEvent<HTMLElement>) => {
|
|
92
|
-
if (isRange && onChangeEndPreview) {
|
|
93
|
-
const { date } = event.currentTarget.dataset;
|
|
94
|
-
if (date) onChangeEndPreview(date);
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
[isRange, onChangeEndPreview],
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
return (
|
|
101
|
-
<Fragment>
|
|
102
|
-
<Style href="@acusti/date-picker/MonthCalendar">{STYLES}</Style>
|
|
103
|
-
<div className={clsx(ROOT_CLASS_NAME, className)}>
|
|
104
|
-
<div className={`${ROOT_CLASS_NAME}-month-title`}>
|
|
105
|
-
<h3 className={`${ROOT_CLASS_NAME}-month-title-text`}>{title}</h3>
|
|
106
|
-
</div>
|
|
107
|
-
<div className={`${ROOT_CLASS_NAME}-month-week`}>
|
|
108
|
-
<div className="week-day-item">
|
|
109
|
-
<span className="week-day-item-text">Su</span>
|
|
110
|
-
</div>
|
|
111
|
-
<div className="week-day-item">
|
|
112
|
-
<span className="week-day-item-text">Mo</span>
|
|
113
|
-
</div>
|
|
114
|
-
<div className="week-day-item">
|
|
115
|
-
<span className="week-day-item-text">Tu</span>
|
|
116
|
-
</div>
|
|
117
|
-
<div className="week-day-item">
|
|
118
|
-
<span className="week-day-item-text">We</span>
|
|
119
|
-
</div>
|
|
120
|
-
<div className="week-day-item">
|
|
121
|
-
<span className="week-day-item-text">Th</span>
|
|
122
|
-
</div>
|
|
123
|
-
<div className="week-day-item">
|
|
124
|
-
<span className="week-day-item-text">Fr</span>
|
|
125
|
-
</div>
|
|
126
|
-
<div className="week-day-item">
|
|
127
|
-
<span className="week-day-item-text">Sa</span>
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
<div className={`${ROOT_CLASS_NAME}-month-days`}>
|
|
131
|
-
{Array(Math.floor(daySpaces / 7))
|
|
132
|
-
.fill(null)
|
|
133
|
-
.map((_, weekIndex) => (
|
|
134
|
-
<div
|
|
135
|
-
className={`${ROOT_CLASS_NAME}-month-row`}
|
|
136
|
-
key={`MonthRow-${weekIndex}`}
|
|
137
|
-
>
|
|
138
|
-
{DAYS.map((__, dayIndex) => {
|
|
139
|
-
dayIndex += weekIndex * 7;
|
|
140
|
-
const dayNumber = (dayIndex - firstDay) + 1; // prettier-ignore
|
|
141
|
-
const isEmpty =
|
|
142
|
-
dayNumber < 1 || dayNumber > totalDays;
|
|
143
|
-
const date = isEmpty
|
|
144
|
-
? null
|
|
145
|
-
: getDateFromMonthAndDay(month, dayNumber);
|
|
146
|
-
const isAfterDateRangeStart =
|
|
147
|
-
dateRangeStartDay != null &&
|
|
148
|
-
dayNumber > dateRangeStartDay;
|
|
149
|
-
const isBeforeDateRangeEnd =
|
|
150
|
-
(dateRangeEndDay == null &&
|
|
151
|
-
dateRangeEndPreviewDay != null &&
|
|
152
|
-
dayNumber < dateRangeEndPreviewDay) ||
|
|
153
|
-
(dateRangeEndDay != null &&
|
|
154
|
-
dayNumber < dateRangeEndDay);
|
|
155
|
-
|
|
156
|
-
return (
|
|
157
|
-
<button
|
|
158
|
-
className={clsx(
|
|
159
|
-
`${ROOT_CLASS_NAME}-month-day-item`,
|
|
160
|
-
{
|
|
161
|
-
'end-date':
|
|
162
|
-
!isEmpty &&
|
|
163
|
-
dayNumber === dateRangeEndDay,
|
|
164
|
-
'is-empty': isEmpty,
|
|
165
|
-
'is-selected':
|
|
166
|
-
!isEmpty &&
|
|
167
|
-
isAfterDateRangeStart &&
|
|
168
|
-
isBeforeDateRangeEnd,
|
|
169
|
-
'start-date':
|
|
170
|
-
!isEmpty &&
|
|
171
|
-
dayNumber === dateRangeStartDay,
|
|
172
|
-
},
|
|
173
|
-
)}
|
|
174
|
-
data-date={date?.toISOString()}
|
|
175
|
-
disabled={isEmpty}
|
|
176
|
-
key={`MonthDayItem-${dayNumber}`}
|
|
177
|
-
onClick={handleClickDay}
|
|
178
|
-
onMouseEnter={handleMouseEnterDay}
|
|
179
|
-
type="button"
|
|
180
|
-
>
|
|
181
|
-
{isEmpty ? null : (
|
|
182
|
-
<span className="month-day-item-text">
|
|
183
|
-
{dayNumber}
|
|
184
|
-
</span>
|
|
185
|
-
)}
|
|
186
|
-
</button>
|
|
187
|
-
);
|
|
188
|
-
})}
|
|
189
|
-
</div>
|
|
190
|
-
))}
|
|
191
|
-
</div>
|
|
192
|
-
</div>
|
|
193
|
-
</Fragment>
|
|
194
|
-
);
|
|
195
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
export const ROOT_CLASS_NAME = 'uktdatepicker';
|
|
2
|
-
|
|
3
|
-
export const STYLES = `
|
|
4
|
-
.${ROOT_CLASS_NAME} {
|
|
5
|
-
display: flex;
|
|
6
|
-
box-sizing: border-box;
|
|
7
|
-
padding: 40px 60px 60px;
|
|
8
|
-
flex: 1 1 auto;
|
|
9
|
-
position: relative;
|
|
10
|
-
max-width: 450px;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.${ROOT_CLASS_NAME}.two-up {
|
|
14
|
-
max-width: 820px;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.${ROOT_CLASS_NAME}-range-arrow-wrap {
|
|
18
|
-
position: absolute;
|
|
19
|
-
top: 30px;
|
|
20
|
-
left: 0px;
|
|
21
|
-
display: flex;
|
|
22
|
-
justify-content: space-between;
|
|
23
|
-
height: 0px;
|
|
24
|
-
width: 100%;
|
|
25
|
-
padding: 0px 60px;
|
|
26
|
-
box-sizing: border-box;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.${ROOT_CLASS_NAME}-range-arrow {
|
|
30
|
-
width: 35px;
|
|
31
|
-
height: 35px;
|
|
32
|
-
text-align: center;
|
|
33
|
-
cursor: pointer;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.${ROOT_CLASS_NAME}-range-arrow.disabled {
|
|
37
|
-
color: #ccc;
|
|
38
|
-
cursor: default;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.${ROOT_CLASS_NAME}-range-arrow:active {
|
|
42
|
-
transform: translateY(1px);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.${ROOT_CLASS_NAME}-range-arrow.left-arrow:after,
|
|
46
|
-
.${ROOT_CLASS_NAME}-range-arrow.right-arrow:after {
|
|
47
|
-
content: "‹";
|
|
48
|
-
font-size: 24px;
|
|
49
|
-
line-height: 35px;
|
|
50
|
-
font-weight: bold;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.${ROOT_CLASS_NAME}-range-arrow.right-arrow:after {
|
|
54
|
-
content: "›";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.${ROOT_CLASS_NAME}-month-container {
|
|
58
|
-
display: flex;
|
|
59
|
-
flex: 1 1 auto;
|
|
60
|
-
justify-content: space-between;
|
|
61
|
-
}
|
|
62
|
-
`;
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
export const ROOT_CLASS_NAME = 'uktmonthcalendar';
|
|
2
|
-
|
|
3
|
-
export const STYLES = `
|
|
4
|
-
.${ROOT_CLASS_NAME} {
|
|
5
|
-
display: flex;
|
|
6
|
-
flex-direction: column;
|
|
7
|
-
flex: 1 1 auto;
|
|
8
|
-
box-sizing: border-box;
|
|
9
|
-
max-width: 325px;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.${ROOT_CLASS_NAME}-month-title {
|
|
13
|
-
display: flex;
|
|
14
|
-
align-items: center;
|
|
15
|
-
justify-content: center;
|
|
16
|
-
flex: 0 0 auto;
|
|
17
|
-
box-sizing: border-box;
|
|
18
|
-
padding-bottom: 25px;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
h3.${ROOT_CLASS_NAME}-month-title-text {
|
|
22
|
-
font-size: 18px;
|
|
23
|
-
line-height: 23px;
|
|
24
|
-
font-weight: 600;
|
|
25
|
-
color: #000;
|
|
26
|
-
margin: 0px;
|
|
27
|
-
text-align: center;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.${ROOT_CLASS_NAME}-month-week {
|
|
31
|
-
flex: 0 0 auto;
|
|
32
|
-
display: grid;
|
|
33
|
-
grid-column-gap: 0px;
|
|
34
|
-
grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
|
|
35
|
-
grid-auto-flow: dense;
|
|
36
|
-
box-sizing: border-box;
|
|
37
|
-
padding-bottom: 12px;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.${ROOT_CLASS_NAME}-month-week .week-day-item {
|
|
41
|
-
flex: 1 1 auto;
|
|
42
|
-
display: flex;
|
|
43
|
-
justify-content: center;
|
|
44
|
-
align-items: center;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.${ROOT_CLASS_NAME}-month-week span.week-day-item-text {
|
|
48
|
-
text-align: center;
|
|
49
|
-
font-size: 13px;
|
|
50
|
-
line-height: 21px;
|
|
51
|
-
margin: 0px;
|
|
52
|
-
color: #9a9a9a;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.${ROOT_CLASS_NAME}-month-days {
|
|
56
|
-
flex: 1 1 auto;
|
|
57
|
-
display: flex;
|
|
58
|
-
flex-direction: column;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.${ROOT_CLASS_NAME}-month-row {
|
|
62
|
-
flex: 1 1 auto;
|
|
63
|
-
display: grid;
|
|
64
|
-
grid-column-gap: 0px;
|
|
65
|
-
grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
|
|
66
|
-
grid-auto-flow: dense;
|
|
67
|
-
margin-bottom: 1px;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.${ROOT_CLASS_NAME}-month-day-item {
|
|
71
|
-
display: flex;
|
|
72
|
-
justify-content: center;
|
|
73
|
-
align-items: center;
|
|
74
|
-
position: relative;
|
|
75
|
-
height: 46px;
|
|
76
|
-
width: 46px;
|
|
77
|
-
cursor: pointer;
|
|
78
|
-
border: none;
|
|
79
|
-
background-color: transparent;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.${ROOT_CLASS_NAME}-month-day-item:disabled {
|
|
83
|
-
cursor: auto;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.${ROOT_CLASS_NAME}-month-day-item.is-selected {
|
|
87
|
-
background-color: #f8f8f8;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.${ROOT_CLASS_NAME}-month-day-item.start-date {
|
|
91
|
-
background-color: #f8f8f8;
|
|
92
|
-
border-top-left-radius: 50%;
|
|
93
|
-
border-bottom-left-radius: 50%;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.${ROOT_CLASS_NAME}-month-day-item.start-date:after {
|
|
97
|
-
background-color: #000;
|
|
98
|
-
opacity: 1;
|
|
99
|
-
visibility: visible;
|
|
100
|
-
}
|
|
101
|
-
.${ROOT_CLASS_NAME}-month-day-item.start-date span.month-day-item-text {
|
|
102
|
-
color: #fff;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.${ROOT_CLASS_NAME}-month-day-item.end-date {
|
|
106
|
-
background-color: #f8f8f8;
|
|
107
|
-
border-top-right-radius: 50%;
|
|
108
|
-
border-bottom-right-radius: 50%;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.${ROOT_CLASS_NAME}-month-day-item.end-date:after {
|
|
112
|
-
background-color: #000;
|
|
113
|
-
opacity: 1;
|
|
114
|
-
visibility: visible;
|
|
115
|
-
}
|
|
116
|
-
.${ROOT_CLASS_NAME}-month-day-item.end-date span.month-day-item-text {
|
|
117
|
-
color: #fff;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.${ROOT_CLASS_NAME}-month-day-item:hover:after {
|
|
121
|
-
opacity: 1;
|
|
122
|
-
visibility: visible;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.${ROOT_CLASS_NAME}-month-day-item:after {
|
|
126
|
-
content: "";
|
|
127
|
-
position: absolute;
|
|
128
|
-
left: 50%;
|
|
129
|
-
top: 50%;
|
|
130
|
-
transform: translate(-50%, -50%);
|
|
131
|
-
pointer-events: none;
|
|
132
|
-
border-radius: 50%;
|
|
133
|
-
border: 1px solid #000;
|
|
134
|
-
width: 43px;
|
|
135
|
-
height: 43px;
|
|
136
|
-
transition: opacity 0.25s ease-in-out;
|
|
137
|
-
opacity: 0;
|
|
138
|
-
visibility: hidden;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.${ROOT_CLASS_NAME}-month-day-item.is-empty:after {
|
|
142
|
-
content: none;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.${ROOT_CLASS_NAME}-month-day-item span.month-day-item-text {
|
|
146
|
-
text-align: center;
|
|
147
|
-
font-size: 13px;
|
|
148
|
-
line-height: 21px;
|
|
149
|
-
margin: 0px;
|
|
150
|
-
color: #000;
|
|
151
|
-
position: relative;
|
|
152
|
-
z-index: 1;
|
|
153
|
-
}
|
|
154
|
-
`;
|
package/src/utils.test.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
getDateFromMonthAndDay,
|
|
5
|
-
getLastDateFromMonth,
|
|
6
|
-
getMonthFromDate,
|
|
7
|
-
getMonthNameFromMonth,
|
|
8
|
-
getYearFromMonth,
|
|
9
|
-
} from './utils.js';
|
|
10
|
-
|
|
11
|
-
const INVALID_DATE = new Date('');
|
|
12
|
-
|
|
13
|
-
describe('@acusti/date-picker', () => {
|
|
14
|
-
describe('utils', () => {
|
|
15
|
-
describe('getMonthFromDate', () => {
|
|
16
|
-
it('returns the correct month digit for a post-unix epoch month', () => {
|
|
17
|
-
expect(getMonthFromDate(new Date(1970, 0, 8))).toBe(0); // january 8, 1970
|
|
18
|
-
expect(getMonthFromDate(new Date(1971, 11, 1))).toBe(23); // november 1, 1971
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('returns the correct month digit for a pre-unix epoch month', () => {
|
|
22
|
-
expect(getMonthFromDate(new Date(1969, 11, 31))).toBe(-1); // december 31, 1969
|
|
23
|
-
expect(getMonthFromDate(new Date(1968, 3, 30))).toBe(-21); // april 30, 1968
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('returns the correct month digit based on UTC time if asUTC is true', () => {
|
|
27
|
-
const date = new Date('1970-01-01T00:00:00.000Z');
|
|
28
|
-
expect(getMonthFromDate(date, true)).toBe(0);
|
|
29
|
-
// if test is run in a timezone behind UTC, ommitting asUTC returns -1
|
|
30
|
-
// if not, the month should be the same with or without asUTC flag
|
|
31
|
-
expect(getMonthFromDate(date)).toBe(
|
|
32
|
-
date.getTimezoneOffset() >= 60 ? -1 : 0,
|
|
33
|
-
);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('returns NaN for an Invalid Date', () => {
|
|
37
|
-
expect(getMonthFromDate(INVALID_DATE)).toBe(NaN);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe('getYearFromMonth', () => {
|
|
42
|
-
it('returns the correct year for a post-unix epoch date', () => {
|
|
43
|
-
expect(getYearFromMonth(getMonthFromDate(new Date(1970, 0, 1)))).toBe(
|
|
44
|
-
1970,
|
|
45
|
-
);
|
|
46
|
-
expect(getYearFromMonth(getMonthFromDate(new Date(2048, 4, 31)))).toBe(
|
|
47
|
-
2048,
|
|
48
|
-
);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('returns the correct year digit for a pre-unix epoch date', () => {
|
|
52
|
-
expect(getYearFromMonth(getMonthFromDate(new Date(1970, 0, 0)))).toBe(
|
|
53
|
-
1969,
|
|
54
|
-
);
|
|
55
|
-
expect(getYearFromMonth(getMonthFromDate(new Date(100, 11, 31)))).toBe(
|
|
56
|
-
100,
|
|
57
|
-
);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('returns NaN for an Invalid Date', () => {
|
|
61
|
-
expect(getYearFromMonth(getMonthFromDate(INVALID_DATE))).toBe(NaN);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe('getMonthNameFromMonth', () => {
|
|
66
|
-
it('returns the correct month name for a post-unix epoch month', () => {
|
|
67
|
-
expect(
|
|
68
|
-
getMonthNameFromMonth(getMonthFromDate(new Date(2023, 5, 19))),
|
|
69
|
-
).toBe('June');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('returns the correct month name for a pre-unix epoch month', () => {
|
|
73
|
-
expect(
|
|
74
|
-
getMonthNameFromMonth(getMonthFromDate(new Date(1865, 5, 2))),
|
|
75
|
-
).toBe('June');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('returns an empty string if given NaN (e.g. if dealing with an Invalid Date)', () => {
|
|
79
|
-
expect(getMonthNameFromMonth(getMonthFromDate(INVALID_DATE))).toBe('');
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('getDateFromMonthAndDay', () => {
|
|
84
|
-
it('returns the date of the specified day for a post-unix epoch month', () => {
|
|
85
|
-
expect(
|
|
86
|
-
getDateFromMonthAndDay(getMonthFromDate(new Date(2008, 2, 13)), 1),
|
|
87
|
-
).toEqual(new Date(2008, 2, 1));
|
|
88
|
-
expect(
|
|
89
|
-
getDateFromMonthAndDay(getMonthFromDate(new Date(1999, 11, 1)), 31),
|
|
90
|
-
).toEqual(new Date(1999, 11, 31));
|
|
91
|
-
expect(
|
|
92
|
-
getDateFromMonthAndDay(getMonthFromDate(new Date(2000, 0, 0)), 31),
|
|
93
|
-
).toEqual(new Date(1999, 11, 31));
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('returns the correct date for a pre-unix epoch month', () => {
|
|
97
|
-
expect(
|
|
98
|
-
getDateFromMonthAndDay(getMonthFromDate(new Date(1865, 5, 2)), 30),
|
|
99
|
-
).toEqual(new Date(1865, 5, 30));
|
|
100
|
-
expect(
|
|
101
|
-
getDateFromMonthAndDay(getMonthFromDate(new Date(101, 0, 0)), 1),
|
|
102
|
-
).toEqual(new Date(100, 11, 1));
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('returns date for start of day as UTC time if asUTC is true', () => {
|
|
106
|
-
expect(
|
|
107
|
-
getDateFromMonthAndDay(
|
|
108
|
-
getMonthFromDate(new Date(1865, 5, 2)),
|
|
109
|
-
30,
|
|
110
|
-
true,
|
|
111
|
-
),
|
|
112
|
-
).toEqual(new Date(Date.UTC(1865, 5, 30)));
|
|
113
|
-
expect(
|
|
114
|
-
getDateFromMonthAndDay(
|
|
115
|
-
getMonthFromDate(new Date(101, 0, 0)),
|
|
116
|
-
1,
|
|
117
|
-
true,
|
|
118
|
-
),
|
|
119
|
-
).toEqual(new Date(Date.UTC(100, 11, 1)));
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('returns an invalid date if given NaN (e.g. if dealing with an Invalid Date)', () => {
|
|
123
|
-
expect(getDateFromMonthAndDay(getMonthFromDate(INVALID_DATE), 1)).toEqual(
|
|
124
|
-
INVALID_DATE,
|
|
125
|
-
);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
describe('getLastDateFromMonth', () => {
|
|
130
|
-
it('returns the date of the last day for a post-unix epoch month', () => {
|
|
131
|
-
expect(
|
|
132
|
-
getLastDateFromMonth(getMonthFromDate(new Date(2008, 2, 13))),
|
|
133
|
-
).toEqual(new Date(2008, 2, 31));
|
|
134
|
-
// february in a leap year
|
|
135
|
-
expect(
|
|
136
|
-
getLastDateFromMonth(getMonthFromDate(new Date(2024, 1, 23))),
|
|
137
|
-
).toEqual(new Date(2024, 1, 29));
|
|
138
|
-
// february in a non-leap year
|
|
139
|
-
expect(
|
|
140
|
-
getLastDateFromMonth(getMonthFromDate(new Date(1985, 1, 1))),
|
|
141
|
-
).toEqual(new Date(1985, 1, 28));
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('returns the correct date for a pre-unix epoch month', () => {
|
|
145
|
-
expect(
|
|
146
|
-
getLastDateFromMonth(getMonthFromDate(new Date(1865, 5, 2))),
|
|
147
|
-
).toEqual(new Date(1865, 5, 30));
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('returns date for start of day as UTC time if asUTC is true', () => {
|
|
151
|
-
expect(
|
|
152
|
-
getLastDateFromMonth(getMonthFromDate(new Date(1865, 5, 2)), true),
|
|
153
|
-
).toEqual(new Date(Date.UTC(1865, 5, 30)));
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('returns an invalid date if given NaN (e.g. if dealing with an Invalid Date)', () => {
|
|
157
|
-
expect(getLastDateFromMonth(getMonthFromDate(INVALID_DATE))).toEqual(
|
|
158
|
-
INVALID_DATE,
|
|
159
|
-
);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
package/src/utils.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// The following utils work on a “month” as a unique numerical value
|
|
2
|
-
// representing the number of months since the unix epoch (jan 1970)
|
|
3
|
-
const START_YEAR = 1970;
|
|
4
|
-
const MONTH_NAMES = [
|
|
5
|
-
'January',
|
|
6
|
-
'February',
|
|
7
|
-
'March',
|
|
8
|
-
'April',
|
|
9
|
-
'May',
|
|
10
|
-
'June',
|
|
11
|
-
'July',
|
|
12
|
-
'August',
|
|
13
|
-
'September',
|
|
14
|
-
'October',
|
|
15
|
-
'November',
|
|
16
|
-
'December',
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
const getYearFromDate = (date: Date, asUTC?: boolean) =>
|
|
20
|
-
(asUTC ? date.getUTCFullYear() : date.getFullYear()) - START_YEAR;
|
|
21
|
-
|
|
22
|
-
export const getMonthFromDate = (date: Date, asUTC?: boolean) => {
|
|
23
|
-
const yearAsMonths = getYearFromDate(date, asUTC) * 12;
|
|
24
|
-
return yearAsMonths + (asUTC ? date.getUTCMonth() : date.getMonth());
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const getYearFromMonth = (month: number) => Math.floor(month / 12) + START_YEAR;
|
|
28
|
-
|
|
29
|
-
export const getMonthNameFromMonth = (month: number): string => {
|
|
30
|
-
let index = month % 12;
|
|
31
|
-
if (Number.isNaN(index)) return '';
|
|
32
|
-
if (index < 0) index = 12 + index;
|
|
33
|
-
return MONTH_NAMES[index];
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const getMonthAbbreviationFromMonth = (month: number) => {
|
|
37
|
-
const monthName = getMonthNameFromMonth(month);
|
|
38
|
-
if (monthName === 'September') return 'Sept';
|
|
39
|
-
return monthName.substring(0, 3);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const getDateFromMonthAndDay = (month: number, day: number, asUTC?: boolean) => {
|
|
43
|
-
const monthIn12 = month < 0 ? (12 - Math.abs(month % 12)) % 12 : month % 12;
|
|
44
|
-
const year = getYearFromMonth(month);
|
|
45
|
-
return asUTC
|
|
46
|
-
? new Date(Date.UTC(year, monthIn12, day))
|
|
47
|
-
: new Date(year, monthIn12, day);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const getLastDateFromMonth = (month: number, asUTC?: boolean) => {
|
|
51
|
-
// day 0 of the next month is the last day of the current month
|
|
52
|
-
return getDateFromMonthAndDay(month + 1, 0, asUTC);
|
|
53
|
-
};
|