@zag-js/date-utils 0.9.2 → 0.10.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/package.json +3 -2
- package/src/align.ts +40 -0
- package/src/assertion.ts +62 -0
- package/src/constrain.ts +109 -0
- package/src/duration.ts +19 -0
- package/src/format-date.ts +67 -0
- package/src/format-range.ts +35 -0
- package/src/format-selected-date.ts +16 -0
- package/src/format-visible-range.ts +26 -0
- package/src/get-day-formatter.ts +14 -0
- package/src/get-decade-range.ts +12 -0
- package/src/get-end-of-week.ts +6 -0
- package/src/get-era-format.ts +5 -0
- package/src/get-month-days.ts +23 -0
- package/src/get-month-formatter.ts +13 -0
- package/src/get-month-names.ts +9 -0
- package/src/get-start-of-week.ts +7 -0
- package/src/get-week-days.ts +10 -0
- package/src/get-weekday-formats.ts +16 -0
- package/src/get-year-range.ts +14 -0
- package/src/index.ts +20 -0
- package/src/mutation.ts +60 -0
- package/src/pagination.ts +285 -0
- package/src/parse-date.ts +45 -0
- package/src/types.ts +14 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zag-js/date-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Date utilities for zag.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"js",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"repository": "https://github.com/chakra-ui/zag/tree/main/packages/utilities/date-utils",
|
|
15
15
|
"sideEffects": false,
|
|
16
16
|
"files": [
|
|
17
|
-
"dist
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
18
19
|
],
|
|
19
20
|
"publishConfig": {
|
|
20
21
|
"access": "public"
|
package/src/align.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DateDuration, DateValue } from "@internationalized/date"
|
|
2
|
+
import { alignCenter, alignEnd, alignStart } from "./constrain"
|
|
3
|
+
import type { DateAlignment } from "./types"
|
|
4
|
+
|
|
5
|
+
export function alignDate(
|
|
6
|
+
date: DateValue,
|
|
7
|
+
alignment: DateAlignment,
|
|
8
|
+
duration: DateDuration,
|
|
9
|
+
locale: string,
|
|
10
|
+
min?: DateValue | undefined,
|
|
11
|
+
max?: DateValue | undefined,
|
|
12
|
+
) {
|
|
13
|
+
switch (alignment) {
|
|
14
|
+
case "start":
|
|
15
|
+
return alignStart(date, duration, locale, min, max)
|
|
16
|
+
case "end":
|
|
17
|
+
return alignEnd(date, duration, locale, min, max)
|
|
18
|
+
case "center":
|
|
19
|
+
default:
|
|
20
|
+
return alignCenter(date, duration, locale, min, max)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function alignStartDate(
|
|
25
|
+
date: DateValue,
|
|
26
|
+
startDate: DateValue,
|
|
27
|
+
endDate: DateValue,
|
|
28
|
+
duration: DateDuration,
|
|
29
|
+
locale: string,
|
|
30
|
+
min?: DateValue | undefined,
|
|
31
|
+
max?: DateValue | undefined,
|
|
32
|
+
) {
|
|
33
|
+
if (date.compare(startDate) < 0) {
|
|
34
|
+
return alignEnd(date, duration, locale, min, max)
|
|
35
|
+
}
|
|
36
|
+
if (date.compare(endDate) > 0) {
|
|
37
|
+
return alignStart(date, duration, locale, min, max)
|
|
38
|
+
}
|
|
39
|
+
return startDate
|
|
40
|
+
}
|
package/src/assertion.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DateValue, isSameDay, isToday } from "@internationalized/date"
|
|
2
|
+
import type { DateAvailableFn } from "./types"
|
|
3
|
+
|
|
4
|
+
export function isTodayDate(date: DateValue, timeZone: string) {
|
|
5
|
+
return isToday(date, timeZone)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function isDateEqual(dateA: DateValue, dateB?: DateValue | null) {
|
|
9
|
+
return dateB != null && isSameDay(dateA, dateB)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isDateInvalid(date: DateValue, minValue?: DateValue | null, maxValue?: DateValue | null) {
|
|
13
|
+
return (minValue != null && date.compare(minValue) < 0) || (maxValue != null && date.compare(maxValue) > 0)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isDateDisabled(
|
|
17
|
+
date: DateValue,
|
|
18
|
+
startDate: DateValue,
|
|
19
|
+
endDate: DateValue,
|
|
20
|
+
minValue?: DateValue | null,
|
|
21
|
+
maxValue?: DateValue | null,
|
|
22
|
+
) {
|
|
23
|
+
return date.compare(startDate) < 0 || date.compare(endDate) > 0 || isDateInvalid(date, minValue, maxValue)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isDateUnavailable(
|
|
27
|
+
date: DateValue | null,
|
|
28
|
+
isUnavailable: DateAvailableFn | undefined,
|
|
29
|
+
locale: string,
|
|
30
|
+
minValue?: DateValue | null,
|
|
31
|
+
maxValue?: DateValue | null,
|
|
32
|
+
) {
|
|
33
|
+
if (!date) {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
if (isUnavailable?.(date, locale)) {
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
39
|
+
return isDateInvalid(date, minValue, maxValue)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isDateOutsideVisibleRange(date: DateValue, startDate: DateValue, endDate: DateValue) {
|
|
43
|
+
return date.compare(startDate) < 0 || date.compare(endDate) > 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function isPreviousVisibleRangeInvalid(
|
|
47
|
+
startDate: DateValue,
|
|
48
|
+
minValue?: DateValue | null,
|
|
49
|
+
maxValue?: DateValue | null,
|
|
50
|
+
) {
|
|
51
|
+
const prevDate = startDate.subtract({ days: 1 })
|
|
52
|
+
return isSameDay(prevDate, startDate) || isDateInvalid(prevDate, minValue, maxValue)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isNextVisibleRangeInvalid(
|
|
56
|
+
endDate: DateValue,
|
|
57
|
+
minValue?: DateValue | null,
|
|
58
|
+
maxValue?: DateValue | null,
|
|
59
|
+
) {
|
|
60
|
+
const nextDate = endDate.add({ days: 1 })
|
|
61
|
+
return isSameDay(nextDate, endDate) || isDateInvalid(nextDate, minValue, maxValue)
|
|
62
|
+
}
|
package/src/constrain.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DateDuration,
|
|
3
|
+
DateValue,
|
|
4
|
+
maxDate,
|
|
5
|
+
minDate,
|
|
6
|
+
startOfMonth,
|
|
7
|
+
startOfWeek,
|
|
8
|
+
startOfYear,
|
|
9
|
+
toCalendarDate,
|
|
10
|
+
} from "@internationalized/date"
|
|
11
|
+
|
|
12
|
+
/* -----------------------------------------------------------------------------
|
|
13
|
+
* Align date to start, end, or center of a duration
|
|
14
|
+
* -----------------------------------------------------------------------------*/
|
|
15
|
+
|
|
16
|
+
export function alignCenter(
|
|
17
|
+
date: DateValue,
|
|
18
|
+
duration: DateDuration,
|
|
19
|
+
locale: string,
|
|
20
|
+
min?: DateValue,
|
|
21
|
+
max?: DateValue,
|
|
22
|
+
): DateValue {
|
|
23
|
+
let halfDuration: DateDuration = {}
|
|
24
|
+
for (let key in duration) {
|
|
25
|
+
halfDuration[key] = Math.floor(duration[key] / 2)
|
|
26
|
+
if (halfDuration[key] > 0 && duration[key] % 2 === 0) {
|
|
27
|
+
halfDuration[key]--
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let aligned = alignStart(date, duration, locale).subtract(halfDuration)
|
|
32
|
+
return constrainStart(date, aligned, duration, locale, min, max)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function alignStart(
|
|
36
|
+
date: DateValue,
|
|
37
|
+
duration: DateDuration,
|
|
38
|
+
locale: string,
|
|
39
|
+
min?: DateValue,
|
|
40
|
+
max?: DateValue,
|
|
41
|
+
): DateValue {
|
|
42
|
+
// align to the start of the largest unit
|
|
43
|
+
let aligned = date
|
|
44
|
+
if (duration.years) {
|
|
45
|
+
aligned = startOfYear(date)
|
|
46
|
+
} else if (duration.months) {
|
|
47
|
+
aligned = startOfMonth(date)
|
|
48
|
+
} else if (duration.weeks) {
|
|
49
|
+
aligned = startOfWeek(date, locale)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return constrainStart(date, aligned, duration, locale, min, max)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function alignEnd(
|
|
56
|
+
date: DateValue,
|
|
57
|
+
duration: DateDuration,
|
|
58
|
+
locale: string,
|
|
59
|
+
min?: DateValue,
|
|
60
|
+
max?: DateValue,
|
|
61
|
+
): DateValue {
|
|
62
|
+
let d: DateDuration = { ...duration }
|
|
63
|
+
// subtract 1 from the smallest unit
|
|
64
|
+
if (d.days) {
|
|
65
|
+
d.days--
|
|
66
|
+
} else if (d.weeks) {
|
|
67
|
+
d.weeks--
|
|
68
|
+
} else if (d.months) {
|
|
69
|
+
d.months--
|
|
70
|
+
} else if (d.years) {
|
|
71
|
+
d.years--
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let aligned = alignStart(date, duration, locale).subtract(d)
|
|
75
|
+
return constrainStart(date, aligned, duration, locale, min, max)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* -----------------------------------------------------------------------------
|
|
79
|
+
* Constrain a date to a min/max range
|
|
80
|
+
* -----------------------------------------------------------------------------*/
|
|
81
|
+
|
|
82
|
+
export function constrainStart(
|
|
83
|
+
date: DateValue,
|
|
84
|
+
aligned: DateValue,
|
|
85
|
+
duration: DateDuration,
|
|
86
|
+
locale: string,
|
|
87
|
+
min?: DateValue,
|
|
88
|
+
max?: DateValue,
|
|
89
|
+
): DateValue {
|
|
90
|
+
if (min && date.compare(min) >= 0) {
|
|
91
|
+
aligned = maxDate(aligned, alignStart(toCalendarDate(min), duration, locale))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (max && date.compare(max) <= 0) {
|
|
95
|
+
aligned = minDate(aligned, alignEnd(toCalendarDate(max), duration, locale))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return aligned
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function constrainValue(date: DateValue, minValue?: DateValue, maxValue?: DateValue): DateValue {
|
|
102
|
+
if (minValue) {
|
|
103
|
+
date = maxDate(date, toCalendarDate(minValue))
|
|
104
|
+
}
|
|
105
|
+
if (maxValue) {
|
|
106
|
+
date = minDate(date, toCalendarDate(maxValue))
|
|
107
|
+
}
|
|
108
|
+
return date
|
|
109
|
+
}
|
package/src/duration.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DateDuration, DateValue } from "@internationalized/date"
|
|
2
|
+
|
|
3
|
+
export function getUnitDuration(duration: DateDuration) {
|
|
4
|
+
let d = { ...duration }
|
|
5
|
+
for (let key in d) {
|
|
6
|
+
d[key] = 1
|
|
7
|
+
}
|
|
8
|
+
return d
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getEndDate(startDate: DateValue, duration: DateDuration) {
|
|
12
|
+
let d = { ...duration }
|
|
13
|
+
if (d.days) {
|
|
14
|
+
d.days--
|
|
15
|
+
} else {
|
|
16
|
+
d.days = -1
|
|
17
|
+
}
|
|
18
|
+
return startDate.add(d)
|
|
19
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { DateValue, toCalendarDateTime } from "@internationalized/date"
|
|
2
|
+
|
|
3
|
+
function createRegEx(sign: string) {
|
|
4
|
+
let symbols = "\\s|\\.|-|/|\\\\|,|\\$|\\!|\\?|:|;"
|
|
5
|
+
return new RegExp("(^|>|" + symbols + ")(" + sign + ")($|<|" + symbols + ")", "g")
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Formats a date using the given format string as defined in:
|
|
10
|
+
* https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
|
|
11
|
+
*/
|
|
12
|
+
export function formatDate(value: DateValue, formatString: string, locale: string, timeZone: string = "UTC") {
|
|
13
|
+
const datetime = toCalendarDateTime(value)
|
|
14
|
+
const date = datetime.toDate(timeZone)
|
|
15
|
+
|
|
16
|
+
const formats = {
|
|
17
|
+
// Time in ms
|
|
18
|
+
T: date.getTime(),
|
|
19
|
+
|
|
20
|
+
// Minutes
|
|
21
|
+
m: date.toLocaleString(locale, { minute: "numeric" }),
|
|
22
|
+
mm: date.toLocaleString(locale, { minute: "2-digit" }),
|
|
23
|
+
|
|
24
|
+
// Seconds
|
|
25
|
+
s: date.toLocaleString(locale, { second: "numeric" }),
|
|
26
|
+
ss: date.toLocaleString(locale, { second: "2-digit" }),
|
|
27
|
+
|
|
28
|
+
// Hours
|
|
29
|
+
h: date.toLocaleString(locale, { hour: "numeric", hour12: true }),
|
|
30
|
+
hh: date.toLocaleString(locale, { hour: "2-digit", hour12: true }),
|
|
31
|
+
H: date.toLocaleString(locale, { hour: "numeric", hour12: false }),
|
|
32
|
+
HH: date.toLocaleString(locale, { hour: "2-digit", hour12: false }),
|
|
33
|
+
|
|
34
|
+
// Day period
|
|
35
|
+
aa: date.toLocaleString(locale, { hour: "numeric", hour12: true }).toLowerCase(),
|
|
36
|
+
AA: date.toLocaleString(locale, { hour: "numeric", hour12: true }).toUpperCase(),
|
|
37
|
+
|
|
38
|
+
// Day of week
|
|
39
|
+
E: date.toLocaleString(locale, { weekday: "short" }),
|
|
40
|
+
EE: date.toLocaleString(locale, { weekday: "short" }),
|
|
41
|
+
EEE: date.toLocaleString(locale, { weekday: "short" }),
|
|
42
|
+
EEEE: date.toLocaleString(locale, { weekday: "long" }),
|
|
43
|
+
|
|
44
|
+
// Date of month
|
|
45
|
+
d: datetime.day,
|
|
46
|
+
dd: date.toLocaleString(locale, { day: "2-digit" }),
|
|
47
|
+
|
|
48
|
+
// Months
|
|
49
|
+
M: datetime.month + 1,
|
|
50
|
+
MM: date.toLocaleString(locale, { month: "2-digit" }),
|
|
51
|
+
MMM: date.toLocaleString(locale, { month: "short" }),
|
|
52
|
+
MMMM: date.toLocaleString(locale, { month: "long" }),
|
|
53
|
+
|
|
54
|
+
// Years
|
|
55
|
+
yy: date.toLocaleString(locale, { year: "2-digit" }),
|
|
56
|
+
yyyy: date.toLocaleString(locale, { year: "numeric" }),
|
|
57
|
+
YY: date.toLocaleString(locale, { year: "2-digit" }),
|
|
58
|
+
YYYY: date.toLocaleString(locale, { year: "numeric" }),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let result = formatString
|
|
62
|
+
for (const key in formats) {
|
|
63
|
+
result = result.replace(createRegEx(key), "$1" + formats[key] + "$3")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return result
|
|
67
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { DateValue, DateFormatter } from "@internationalized/date"
|
|
2
|
+
|
|
3
|
+
export function formatRange(
|
|
4
|
+
startDate: DateValue,
|
|
5
|
+
endDate: DateValue,
|
|
6
|
+
formatter: DateFormatter,
|
|
7
|
+
toString: (start: string, end: string) => string,
|
|
8
|
+
timeZone: string,
|
|
9
|
+
) {
|
|
10
|
+
let parts = formatter.formatRangeToParts(startDate.toDate(timeZone), endDate.toDate(timeZone))
|
|
11
|
+
|
|
12
|
+
let separatorIndex = -1
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < parts.length; i++) {
|
|
15
|
+
let part = parts[i]
|
|
16
|
+
if (part.source === "shared" && part.type === "literal") {
|
|
17
|
+
separatorIndex = i
|
|
18
|
+
} else if (part.source === "endRange") {
|
|
19
|
+
break
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let start = ""
|
|
24
|
+
let end = ""
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < parts.length; i++) {
|
|
27
|
+
if (i < separatorIndex) {
|
|
28
|
+
start += parts[i].value
|
|
29
|
+
} else if (i > separatorIndex) {
|
|
30
|
+
end += parts[i].value
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return toString(start, end)
|
|
35
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DateValue, isSameDay } from "@internationalized/date"
|
|
2
|
+
import { formatRange } from "./format-range"
|
|
3
|
+
import { getDayFormatter } from "./get-day-formatter"
|
|
4
|
+
|
|
5
|
+
export function formatSelectedDate(startDate: DateValue, endDate: DateValue | null, locale: string, timeZone: string) {
|
|
6
|
+
let start = startDate
|
|
7
|
+
let end = endDate ?? startDate
|
|
8
|
+
|
|
9
|
+
let formatter = getDayFormatter(locale, timeZone)
|
|
10
|
+
|
|
11
|
+
if (isSameDay(start, end)) {
|
|
12
|
+
return formatter.format(start.toDate(timeZone))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return formatRange(start, end, formatter, (start, end) => `${start} – ${end}`, timeZone)
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { DateValue, endOfMonth, isSameDay, startOfMonth } from "@internationalized/date"
|
|
2
|
+
import { getDayFormatter } from "./get-day-formatter"
|
|
3
|
+
import { getMonthFormatter } from "./get-month-formatter"
|
|
4
|
+
|
|
5
|
+
export function formatVisibleRange(startDate: DateValue, endDate: DateValue | null, locale: string, timeZone: string) {
|
|
6
|
+
const start = startDate
|
|
7
|
+
const end = endDate ?? startDate
|
|
8
|
+
|
|
9
|
+
const dayFormatter = getDayFormatter(locale, timeZone)
|
|
10
|
+
|
|
11
|
+
if (!isSameDay(start, startOfMonth(start))) {
|
|
12
|
+
return dayFormatter.formatRange(start.toDate(timeZone), end.toDate(timeZone))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const monthFormatter = getMonthFormatter(locale, timeZone)
|
|
16
|
+
|
|
17
|
+
if (isSameDay(end, endOfMonth(start))) {
|
|
18
|
+
return monthFormatter.format(start.toDate(timeZone))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (isSameDay(end, endOfMonth(end))) {
|
|
22
|
+
return monthFormatter.formatRange(start.toDate(timeZone), end.toDate(timeZone))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return ""
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DateFormatter, toCalendarDateTime, today } from "@internationalized/date"
|
|
2
|
+
import { getEraFormat } from "./get-era-format"
|
|
3
|
+
|
|
4
|
+
export function getDayFormatter(locale: string, timeZone: string) {
|
|
5
|
+
const date = toCalendarDateTime(today(timeZone))
|
|
6
|
+
return new DateFormatter(locale, {
|
|
7
|
+
weekday: "long",
|
|
8
|
+
month: "long",
|
|
9
|
+
year: "numeric",
|
|
10
|
+
day: "numeric",
|
|
11
|
+
era: getEraFormat(date),
|
|
12
|
+
timeZone,
|
|
13
|
+
})
|
|
14
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DateValue } from "@internationalized/date"
|
|
2
|
+
import { getStartOfWeek } from "./get-start-of-week"
|
|
3
|
+
|
|
4
|
+
export function getEndOfWeek(date: DateValue, locale: string, firstDayOfWeek: number = 0) {
|
|
5
|
+
return getStartOfWeek(date, locale, firstDayOfWeek).add({ days: 6 })
|
|
6
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DateValue, getWeeksInMonth, isSameDay } from "@internationalized/date"
|
|
2
|
+
import { getStartOfWeek } from "./get-start-of-week"
|
|
3
|
+
|
|
4
|
+
export function getDaysInWeek(weekIndex: number, from: DateValue, locale: string, firstDayOfWeek?: number) {
|
|
5
|
+
const weekDate = from.add({ weeks: weekIndex })
|
|
6
|
+
const dates: DateValue[] = []
|
|
7
|
+
let date = getStartOfWeek(weekDate, locale, firstDayOfWeek)
|
|
8
|
+
while (dates.length < 7) {
|
|
9
|
+
dates.push(date)
|
|
10
|
+
let nextDate = date.add({ days: 1 })
|
|
11
|
+
if (isSameDay(date, nextDate)) {
|
|
12
|
+
break
|
|
13
|
+
}
|
|
14
|
+
date = nextDate
|
|
15
|
+
}
|
|
16
|
+
return dates
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getMonthDays(from: DateValue, locale: string, numOfWeeks?: number, firstDayOfWeek?: number) {
|
|
20
|
+
const monthWeeks = getWeeksInMonth(from, locale)
|
|
21
|
+
const weeks = [...new Array(numOfWeeks ?? monthWeeks).keys()]
|
|
22
|
+
return weeks.map((week) => getDaysInWeek(week, from, locale, firstDayOfWeek))
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { today, toCalendarDate, DateFormatter } from "@internationalized/date"
|
|
2
|
+
import { getEraFormat } from "./get-era-format"
|
|
3
|
+
|
|
4
|
+
export function getMonthFormatter(locale: string, timeZone: string) {
|
|
5
|
+
const date = toCalendarDate(today(timeZone))
|
|
6
|
+
return new DateFormatter(locale, {
|
|
7
|
+
month: "long",
|
|
8
|
+
year: "numeric",
|
|
9
|
+
era: getEraFormat(date),
|
|
10
|
+
calendar: date?.calendar.identifier,
|
|
11
|
+
timeZone: timeZone,
|
|
12
|
+
})
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function getMonthNames(locale: string, format: Intl.DateTimeFormatOptions["month"] = "long") {
|
|
2
|
+
const date = new Date(2021, 0, 1)
|
|
3
|
+
const monthNames: string[] = []
|
|
4
|
+
for (let i = 0; i < 12; i++) {
|
|
5
|
+
monthNames.push(date.toLocaleString(locale, { month: format }))
|
|
6
|
+
date.setMonth(date.getMonth() + 1)
|
|
7
|
+
}
|
|
8
|
+
return monthNames
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DateValue, getDayOfWeek } from "@internationalized/date"
|
|
2
|
+
|
|
3
|
+
export function getStartOfWeek(date: DateValue, locale: string, firstDayOfWeek: number = 0) {
|
|
4
|
+
const day = getDayOfWeek(date, locale)
|
|
5
|
+
const diff = (day - firstDayOfWeek + 7) % 7
|
|
6
|
+
return date.subtract({ days: diff })
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DateValue } from "@internationalized/date"
|
|
2
|
+
import { getWeekdayFormats } from "./get-weekday-formats"
|
|
3
|
+
import { getStartOfWeek } from "./get-start-of-week"
|
|
4
|
+
|
|
5
|
+
export function getWeekDays(date: DateValue, startOfWeekProp: number | undefined, timeZone: string, locale: string) {
|
|
6
|
+
const firstDayOfWeek = getStartOfWeek(date, locale, startOfWeekProp)
|
|
7
|
+
const weeks = [...new Array(7).keys()]
|
|
8
|
+
const format = getWeekdayFormats(locale, timeZone)
|
|
9
|
+
return weeks.map((index) => format(firstDayOfWeek.add({ days: index })))
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DateValue, DateFormatter } from "@internationalized/date"
|
|
2
|
+
|
|
3
|
+
export function getWeekdayFormats(locale: string, timeZone: string) {
|
|
4
|
+
const longFormat = new DateFormatter(locale, { weekday: "long", timeZone })
|
|
5
|
+
const shortFormat = new DateFormatter(locale, { weekday: "short", timeZone })
|
|
6
|
+
const narrowFormat = new DateFormatter(locale, { weekday: "narrow", timeZone })
|
|
7
|
+
return <T extends DateValue | Date>(value: T) => {
|
|
8
|
+
const date = value instanceof Date ? value : value.toDate(timeZone)
|
|
9
|
+
return {
|
|
10
|
+
value,
|
|
11
|
+
short: shortFormat.format(date),
|
|
12
|
+
long: longFormat.format(date),
|
|
13
|
+
narrow: narrowFormat.format(date),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface YearsRange {
|
|
2
|
+
from: number
|
|
3
|
+
to: number
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function getYearsRange(range: YearsRange) {
|
|
7
|
+
const years: number[] = []
|
|
8
|
+
|
|
9
|
+
for (let year = range.from; year <= range.to; year += 1) {
|
|
10
|
+
years.push(year)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return years
|
|
14
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from "./align"
|
|
2
|
+
export * from "./assertion"
|
|
3
|
+
export * from "./constrain"
|
|
4
|
+
export * from "./duration"
|
|
5
|
+
export * from "./format-date"
|
|
6
|
+
export * from "./format-range"
|
|
7
|
+
export * from "./format-selected-date"
|
|
8
|
+
export * from "./format-visible-range"
|
|
9
|
+
export * from "./get-day-formatter"
|
|
10
|
+
export * from "./get-decade-range"
|
|
11
|
+
export * from "./get-month-days"
|
|
12
|
+
export * from "./get-month-formatter"
|
|
13
|
+
export * from "./get-month-names"
|
|
14
|
+
export * from "./get-week-days"
|
|
15
|
+
export * from "./get-weekday-formats"
|
|
16
|
+
export * from "./get-year-range"
|
|
17
|
+
export * from "./mutation"
|
|
18
|
+
export * from "./pagination"
|
|
19
|
+
export * from "./parse-date"
|
|
20
|
+
export type { DateAdjustFn, DateGranularity } from "./types"
|
package/src/mutation.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Calendar, DateValue, getLocalTimeZone, toCalendar, toCalendarDateTime, today } from "@internationalized/date"
|
|
2
|
+
import { constrainValue } from "./constrain"
|
|
3
|
+
import type { DateAvailableFn } from "./types"
|
|
4
|
+
|
|
5
|
+
export function getTodayDate(timeZone?: string) {
|
|
6
|
+
return today(timeZone ?? getLocalTimeZone())
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getNextDay(date: DateValue) {
|
|
10
|
+
return date.add({ days: 1 })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getPreviousDay(date: DateValue) {
|
|
14
|
+
return date.subtract({ days: 1 })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function setMonth(date: DateValue, month: number) {
|
|
18
|
+
return date.set({ month })
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function setYear(date: DateValue, year: number) {
|
|
22
|
+
return date.set({ year })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function setCalendar(date: DateValue, calendar: Calendar) {
|
|
26
|
+
return toCalendar(toCalendarDateTime(date), calendar)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function setDate(
|
|
30
|
+
date: DateValue,
|
|
31
|
+
startDate: DateValue,
|
|
32
|
+
isDateUnavailable: DateAvailableFn,
|
|
33
|
+
locale: string,
|
|
34
|
+
minValue: DateValue,
|
|
35
|
+
maxValue: DateValue,
|
|
36
|
+
) {
|
|
37
|
+
let result: DateValue | undefined
|
|
38
|
+
result = constrainValue(date, minValue, maxValue)
|
|
39
|
+
result = getPreviousAvailableDate(date, startDate, locale, isDateUnavailable)
|
|
40
|
+
return result
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getPreviousAvailableDate(
|
|
44
|
+
date: DateValue,
|
|
45
|
+
minValue: DateValue,
|
|
46
|
+
locale: string,
|
|
47
|
+
isDateUnavailable?: DateAvailableFn,
|
|
48
|
+
) {
|
|
49
|
+
if (!isDateUnavailable) {
|
|
50
|
+
return date
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
while (date.compare(minValue) >= 0 && isDateUnavailable(date, locale)) {
|
|
54
|
+
date = date.subtract({ days: 1 })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (date.compare(minValue) >= 0) {
|
|
58
|
+
return date
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { DateDuration, DateValue, endOfMonth, endOfWeek, startOfMonth, startOfWeek } from "@internationalized/date"
|
|
2
|
+
import { isDateInvalid } from "./assertion"
|
|
3
|
+
import { alignEnd, alignStart, constrainStart, constrainValue } from "./constrain"
|
|
4
|
+
import { getEndDate, getUnitDuration } from "./duration"
|
|
5
|
+
|
|
6
|
+
export function getAdjustedDateFn(
|
|
7
|
+
visibleDuration: DateDuration,
|
|
8
|
+
locale: string,
|
|
9
|
+
minValue?: DateValue,
|
|
10
|
+
maxValue?: DateValue,
|
|
11
|
+
) {
|
|
12
|
+
return function getDate(options: { startDate: DateValue; focusedDate: DateValue }) {
|
|
13
|
+
const { startDate, focusedDate } = options
|
|
14
|
+
const endDate = getEndDate(startDate, visibleDuration)
|
|
15
|
+
|
|
16
|
+
// If the focused date was moved to an invalid value, it can't be focused, so constrain it.
|
|
17
|
+
if (isDateInvalid(focusedDate, minValue, maxValue)) {
|
|
18
|
+
return {
|
|
19
|
+
startDate,
|
|
20
|
+
focusedDate: constrainValue(focusedDate, minValue, maxValue),
|
|
21
|
+
endDate,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (focusedDate.compare(startDate) < 0) {
|
|
26
|
+
return {
|
|
27
|
+
startDate: alignEnd(focusedDate, visibleDuration, locale, minValue, maxValue),
|
|
28
|
+
endDate,
|
|
29
|
+
focusedDate: constrainValue(focusedDate, minValue, maxValue),
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (focusedDate.compare(endDate) > 0) {
|
|
34
|
+
return {
|
|
35
|
+
startDate: alignStart(focusedDate, visibleDuration, locale, minValue, maxValue),
|
|
36
|
+
endDate,
|
|
37
|
+
focusedDate: constrainValue(focusedDate, minValue, maxValue),
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
startDate,
|
|
43
|
+
endDate,
|
|
44
|
+
focusedDate: constrainValue(focusedDate, minValue, maxValue),
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* -----------------------------------------------------------------------------
|
|
50
|
+
* Get next and previous page (for date range)
|
|
51
|
+
* -----------------------------------------------------------------------------*/
|
|
52
|
+
|
|
53
|
+
export function getNextPage(
|
|
54
|
+
focusedDate: DateValue,
|
|
55
|
+
startDate: DateValue,
|
|
56
|
+
visibleDuration: DateDuration,
|
|
57
|
+
locale: string,
|
|
58
|
+
minValue?: DateValue,
|
|
59
|
+
maxValue?: DateValue,
|
|
60
|
+
) {
|
|
61
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
62
|
+
const start = startDate.add(visibleDuration)
|
|
63
|
+
|
|
64
|
+
return adjust({
|
|
65
|
+
focusedDate: focusedDate.add(visibleDuration),
|
|
66
|
+
startDate: alignStart(
|
|
67
|
+
constrainStart(focusedDate, start, visibleDuration, locale, minValue, maxValue),
|
|
68
|
+
visibleDuration,
|
|
69
|
+
locale,
|
|
70
|
+
),
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function getPreviousPage(
|
|
75
|
+
focusedDate: DateValue,
|
|
76
|
+
startDate: DateValue,
|
|
77
|
+
visibleDuration: DateDuration,
|
|
78
|
+
locale: string,
|
|
79
|
+
minValue?: DateValue,
|
|
80
|
+
maxValue?: DateValue,
|
|
81
|
+
) {
|
|
82
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
83
|
+
let start = startDate.subtract(visibleDuration)
|
|
84
|
+
|
|
85
|
+
return adjust({
|
|
86
|
+
focusedDate: focusedDate.subtract(visibleDuration),
|
|
87
|
+
startDate: alignStart(
|
|
88
|
+
constrainStart(focusedDate, start, visibleDuration, locale, minValue, maxValue),
|
|
89
|
+
visibleDuration,
|
|
90
|
+
locale,
|
|
91
|
+
),
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* -----------------------------------------------------------------------------
|
|
96
|
+
* Get the next and previous row (for date range)
|
|
97
|
+
* -----------------------------------------------------------------------------*/
|
|
98
|
+
|
|
99
|
+
export function getNextRow(
|
|
100
|
+
focusedDate: DateValue,
|
|
101
|
+
startDate: DateValue,
|
|
102
|
+
visibleDuration: DateDuration,
|
|
103
|
+
locale: string,
|
|
104
|
+
minValue?: DateValue,
|
|
105
|
+
maxValue?: DateValue,
|
|
106
|
+
) {
|
|
107
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
108
|
+
|
|
109
|
+
if (visibleDuration.days) {
|
|
110
|
+
return getNextPage(focusedDate, startDate, visibleDuration, locale, minValue, maxValue)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (visibleDuration.weeks || visibleDuration.months || visibleDuration.years) {
|
|
114
|
+
return adjust({
|
|
115
|
+
focusedDate: focusedDate.add({ weeks: 1 }),
|
|
116
|
+
startDate,
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function getPreviousRow(
|
|
122
|
+
focusedDate: DateValue,
|
|
123
|
+
startDate: DateValue,
|
|
124
|
+
visibleDuration: DateDuration,
|
|
125
|
+
locale: string,
|
|
126
|
+
minValue?: DateValue,
|
|
127
|
+
maxValue?: DateValue,
|
|
128
|
+
) {
|
|
129
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
130
|
+
|
|
131
|
+
if (visibleDuration.days) {
|
|
132
|
+
return getPreviousPage(focusedDate, startDate, visibleDuration, locale, minValue, maxValue)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (visibleDuration.weeks || visibleDuration.months || visibleDuration.years) {
|
|
136
|
+
return adjust({
|
|
137
|
+
focusedDate: focusedDate.subtract({ weeks: 1 }),
|
|
138
|
+
startDate,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* -----------------------------------------------------------------------------
|
|
144
|
+
* Get start and end date for a date section
|
|
145
|
+
* -----------------------------------------------------------------------------*/
|
|
146
|
+
|
|
147
|
+
export function getSectionStart(
|
|
148
|
+
focusedDate: DateValue,
|
|
149
|
+
startDate: DateValue,
|
|
150
|
+
visibleDuration: DateDuration,
|
|
151
|
+
locale: string,
|
|
152
|
+
minValue?: DateValue,
|
|
153
|
+
maxValue?: DateValue,
|
|
154
|
+
) {
|
|
155
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
156
|
+
|
|
157
|
+
if (visibleDuration.days) {
|
|
158
|
+
return adjust({
|
|
159
|
+
focusedDate: startDate,
|
|
160
|
+
startDate,
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (visibleDuration.weeks) {
|
|
165
|
+
return adjust({
|
|
166
|
+
focusedDate: startOfWeek(focusedDate, locale),
|
|
167
|
+
startDate,
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (visibleDuration.months || visibleDuration.years) {
|
|
172
|
+
return adjust({
|
|
173
|
+
focusedDate: startOfMonth(focusedDate),
|
|
174
|
+
startDate,
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function getSectionEnd(
|
|
180
|
+
focusedDate: DateValue,
|
|
181
|
+
startDate: DateValue,
|
|
182
|
+
visibleDuration: DateDuration,
|
|
183
|
+
locale: string,
|
|
184
|
+
minValue?: DateValue,
|
|
185
|
+
maxValue?: DateValue,
|
|
186
|
+
) {
|
|
187
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
188
|
+
const endDate = getEndDate(startDate, visibleDuration)
|
|
189
|
+
|
|
190
|
+
if (visibleDuration.days) {
|
|
191
|
+
return adjust({
|
|
192
|
+
focusedDate: endDate,
|
|
193
|
+
startDate,
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (visibleDuration.weeks) {
|
|
198
|
+
return adjust({
|
|
199
|
+
//@ts-expect-error - endOfWeek is loosely typed
|
|
200
|
+
focusedDate: endOfWeek(focusedDate, locale),
|
|
201
|
+
startDate,
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (visibleDuration.months || visibleDuration.years) {
|
|
206
|
+
return adjust({
|
|
207
|
+
focusedDate: endOfMonth(focusedDate),
|
|
208
|
+
startDate,
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function getNextSection(
|
|
214
|
+
focusedDate: DateValue,
|
|
215
|
+
startDate: DateValue,
|
|
216
|
+
larger: boolean,
|
|
217
|
+
visibleDuration: DateDuration,
|
|
218
|
+
locale: string,
|
|
219
|
+
minValue?: DateValue,
|
|
220
|
+
maxValue?: DateValue,
|
|
221
|
+
) {
|
|
222
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
223
|
+
|
|
224
|
+
if (!larger && !visibleDuration.days) {
|
|
225
|
+
return adjust({
|
|
226
|
+
focusedDate: focusedDate.add(getUnitDuration(visibleDuration)),
|
|
227
|
+
startDate,
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (visibleDuration.days) {
|
|
232
|
+
return getNextPage(focusedDate, startDate, visibleDuration, locale, minValue, maxValue)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (visibleDuration.weeks) {
|
|
236
|
+
return adjust({
|
|
237
|
+
focusedDate: focusedDate.add({ months: 1 }),
|
|
238
|
+
startDate,
|
|
239
|
+
})
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (visibleDuration.months || visibleDuration.years) {
|
|
243
|
+
return adjust({
|
|
244
|
+
focusedDate: focusedDate.add({ years: 1 }),
|
|
245
|
+
startDate,
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function getPreviousSection(
|
|
251
|
+
focusedDate: DateValue,
|
|
252
|
+
startDate: DateValue,
|
|
253
|
+
larger: boolean,
|
|
254
|
+
visibleDuration: DateDuration,
|
|
255
|
+
locale: string,
|
|
256
|
+
minValue?: DateValue,
|
|
257
|
+
maxValue?: DateValue,
|
|
258
|
+
) {
|
|
259
|
+
const adjust = getAdjustedDateFn(visibleDuration, locale, minValue, maxValue)
|
|
260
|
+
|
|
261
|
+
if (!larger && !visibleDuration.days) {
|
|
262
|
+
return adjust({
|
|
263
|
+
focusedDate: focusedDate.subtract(getUnitDuration(visibleDuration)),
|
|
264
|
+
startDate,
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (visibleDuration.days) {
|
|
269
|
+
return getPreviousPage(focusedDate, startDate, visibleDuration, locale, minValue, maxValue)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (visibleDuration.weeks) {
|
|
273
|
+
return adjust({
|
|
274
|
+
focusedDate: focusedDate.subtract({ months: 1 }),
|
|
275
|
+
startDate,
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (visibleDuration.months || visibleDuration.years) {
|
|
280
|
+
return adjust({
|
|
281
|
+
focusedDate: focusedDate.subtract({ years: 1 }),
|
|
282
|
+
startDate,
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CalendarDateTime, DateFormatter } from "@internationalized/date"
|
|
2
|
+
|
|
3
|
+
export function parseDateString(date: string, locale: string, timeZone: string) {
|
|
4
|
+
const regex = createRegex(locale, timeZone)
|
|
5
|
+
const { year, month, day } = extract(regex, date) ?? {}
|
|
6
|
+
|
|
7
|
+
if (year != null && year.length === 4 && month != null && +month <= 12 && day != null && +day <= 31) {
|
|
8
|
+
return new CalendarDateTime(+year, +month, +day)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const time = Date.parse(date)
|
|
12
|
+
if (!isNaN(time)) {
|
|
13
|
+
const date = new Date(time)
|
|
14
|
+
return new CalendarDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate())
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createRegex(locale: string, timeZone: string) {
|
|
19
|
+
const formatter = new DateFormatter(locale, { day: "numeric", month: "numeric", year: "numeric", timeZone })
|
|
20
|
+
const parts = formatter.formatToParts(new Date(2000, 11, 25))
|
|
21
|
+
return parts.map(({ type, value }) => (type === "literal" ? value : `((?!=<${type}>)\\d+)`)).join("")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function extract(pattern: string | RegExp, str: string) {
|
|
25
|
+
const matches = str.match(pattern)
|
|
26
|
+
return pattern
|
|
27
|
+
.toString()
|
|
28
|
+
.match(/<(.+?)>/g)
|
|
29
|
+
?.map((group) => {
|
|
30
|
+
const groupMatches = group.match(/<(.+)>/)
|
|
31
|
+
if (!groupMatches || groupMatches.length <= 0) {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
return group.match(/<(.+)>/)?.[1]
|
|
35
|
+
})
|
|
36
|
+
.reduce((acc, curr, index) => {
|
|
37
|
+
if (!curr) return acc
|
|
38
|
+
if (matches && matches.length > index) {
|
|
39
|
+
acc[curr] = matches[index + 1]
|
|
40
|
+
} else {
|
|
41
|
+
acc[curr] = null
|
|
42
|
+
}
|
|
43
|
+
return acc
|
|
44
|
+
}, {} as { year: string; month: string; day: string })
|
|
45
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DateFormatter, DateValue } from "@internationalized/date"
|
|
2
|
+
|
|
3
|
+
export type DateGranularity = "day" | "hour" | "minute" | "second" | "year" | "month"
|
|
4
|
+
export type DateAlignment = "start" | "end" | "center"
|
|
5
|
+
|
|
6
|
+
export type GetFormatterFn = (options: Intl.DateTimeFormatOptions) => DateFormatter
|
|
7
|
+
export type DateAvailableFn = (date: DateValue, locale: string) => boolean
|
|
8
|
+
export type GetPlaceholderFn = (options: { field: string; locale: string }) => string
|
|
9
|
+
export type DateAdjustFn = (options: { startDate: DateValue; focusedDate: DateValue }) => {
|
|
10
|
+
startDate: DateValue
|
|
11
|
+
focusedDate: DateValue
|
|
12
|
+
endDate: DateValue
|
|
13
|
+
}
|
|
14
|
+
export type DateFormatOptions = Intl.ResolvedDateTimeFormatOptions
|