@korsolutions/ui 0.0.21 → 0.0.23
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/dist/components/index.d.mts +20 -2
- package/dist/components/index.mjs +152 -7
- package/dist/{index-pCM7YTs1.d.mts → index-CCYJiglk.d.mts} +104 -9
- package/dist/index.mjs +2 -2
- package/dist/primitives/index.d.mts +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/{primitives-DNeYBN-3.mjs → primitives-ApsPS0vU.mjs} +333 -14
- package/dist/{toast-manager-BfoJ-_dB.mjs → toast-manager-Cdhl1ep0.mjs} +1 -1
- package/package.json +1 -1
- package/src/components/calendar/calendar.tsx +31 -0
- package/src/components/calendar/index.ts +1 -0
- package/src/components/calendar/variants/default.tsx +127 -0
- package/src/components/calendar/variants/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/components/popover/variants/default.tsx +0 -3
- package/src/components/popover/variants/index.ts +2 -0
- package/src/components/popover/variants/unstyled.tsx +13 -0
- package/src/primitives/calendar/calendar-day.tsx +64 -0
- package/src/primitives/calendar/calendar-header.tsx +21 -0
- package/src/primitives/calendar/calendar-nav-button.tsx +60 -0
- package/src/primitives/calendar/calendar-root.tsx +41 -0
- package/src/primitives/calendar/calendar-title.tsx +23 -0
- package/src/primitives/calendar/calendar-week-labels.tsx +45 -0
- package/src/primitives/calendar/calendar-weeks.tsx +47 -0
- package/src/primitives/calendar/context.ts +23 -0
- package/src/primitives/calendar/index.ts +26 -0
- package/src/primitives/calendar/types.ts +39 -0
- package/src/primitives/index.ts +1 -0
- package/src/utils/date-utils.ts +113 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, { useMemo, useState } from "react";
|
|
2
|
+
import { Text, StyleProp, TextStyle, ViewStyle, Pressable } from "react-native";
|
|
3
|
+
import { formatDate, isDateSameDay, isDateToday, isDateBefore, isDateAfter, isSameMonth } from "@/utils/date-utils";
|
|
4
|
+
import { useCalendarContext } from "./context";
|
|
5
|
+
import { CalendarDayState } from "./types";
|
|
6
|
+
|
|
7
|
+
export interface CalendarDayProps {
|
|
8
|
+
date: Date;
|
|
9
|
+
onPress?: () => void;
|
|
10
|
+
|
|
11
|
+
style?: StyleProp<ViewStyle>;
|
|
12
|
+
textStyle?: StyleProp<TextStyle>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const calculateState = (
|
|
16
|
+
date: Date,
|
|
17
|
+
selected: Date | null | undefined,
|
|
18
|
+
isCurrentMonth: boolean,
|
|
19
|
+
isDisabled: boolean,
|
|
20
|
+
isHovered: boolean
|
|
21
|
+
): CalendarDayState => {
|
|
22
|
+
if (isDisabled) return "disabled";
|
|
23
|
+
if (selected && isDateSameDay(date, selected)) return "selected";
|
|
24
|
+
if (isDateToday(date)) return "today";
|
|
25
|
+
if (isHovered) return "hovered";
|
|
26
|
+
if (!isCurrentMonth) return "deprioritized";
|
|
27
|
+
return "default";
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function CalendarDay(props: CalendarDayProps) {
|
|
31
|
+
const calendar = useCalendarContext();
|
|
32
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
33
|
+
|
|
34
|
+
const isCurrentMonth = isSameMonth(props.date, calendar.currentMonth);
|
|
35
|
+
|
|
36
|
+
const isDisabled = useMemo(() => {
|
|
37
|
+
if (calendar.minDate && isDateBefore(props.date, calendar.minDate)) return true;
|
|
38
|
+
if (calendar.maxDate && isDateAfter(props.date, calendar.maxDate)) return true;
|
|
39
|
+
return false;
|
|
40
|
+
}, [props.date, calendar.minDate, calendar.maxDate]);
|
|
41
|
+
|
|
42
|
+
const state = calculateState(props.date, calendar.value, isCurrentMonth, isDisabled, isHovered);
|
|
43
|
+
|
|
44
|
+
const handlePress = () => {
|
|
45
|
+
console.log("Day pressed:", isDisabled, calendar.onChange);
|
|
46
|
+
if (isDisabled || !calendar.onChange) return;
|
|
47
|
+
calendar.onChange(props.date);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const composedStyle = [calendar.styles?.dayButton?.default, calendar.styles?.dayButton?.[state], props.style];
|
|
51
|
+
const composedTextStyle = [calendar.styles?.dayText?.default, calendar.styles?.dayText?.[state], props.textStyle];
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Pressable
|
|
55
|
+
onPress={handlePress}
|
|
56
|
+
onHoverIn={() => setIsHovered(true)}
|
|
57
|
+
onHoverOut={() => setIsHovered(false)}
|
|
58
|
+
disabled={isDisabled}
|
|
59
|
+
style={composedStyle}
|
|
60
|
+
>
|
|
61
|
+
<Text style={composedTextStyle}>{formatDate(props.date, "d")}</Text>
|
|
62
|
+
</Pressable>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, ViewProps, StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
import { useCalendarContext } from "./context";
|
|
4
|
+
|
|
5
|
+
export interface CalendarHeaderProps extends ViewProps {
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
style?: StyleProp<ViewStyle>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function CalendarHeader(props: CalendarHeaderProps) {
|
|
11
|
+
const { children, style, ...viewProps } = props;
|
|
12
|
+
const { styles } = useCalendarContext();
|
|
13
|
+
|
|
14
|
+
const headerStyle = [styles?.header, style];
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<View {...viewProps} style={headerStyle}>
|
|
18
|
+
{children}
|
|
19
|
+
</View>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Pressable, PressableProps, Text, StyleProp, ViewStyle, TextStyle } from "react-native";
|
|
3
|
+
import { addMonths, subMonths } from "../../utils/date-utils";
|
|
4
|
+
import { useCalendarContext } from "./context";
|
|
5
|
+
import { CalendarNavButtonState } from "./types";
|
|
6
|
+
|
|
7
|
+
export interface CalendarNavButtonProps extends PressableProps {
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
direction: "prev" | "next";
|
|
10
|
+
style?: StyleProp<ViewStyle>;
|
|
11
|
+
textStyle?: StyleProp<TextStyle>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const calculateState = (isDisabled: boolean, isHovered: boolean): CalendarNavButtonState => {
|
|
15
|
+
if (isDisabled) return "disabled";
|
|
16
|
+
if (isHovered) return "hovered";
|
|
17
|
+
return "default";
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function CalendarNavButton(props: CalendarNavButtonProps) {
|
|
21
|
+
const { children = props.direction === "prev" ? "‹" : "›", direction, style, textStyle, ...pressableProps } = props;
|
|
22
|
+
const { currentMonth, setCurrentMonth, minDate, maxDate, styles } = useCalendarContext();
|
|
23
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
24
|
+
|
|
25
|
+
const isDisabled = React.useMemo(() => {
|
|
26
|
+
if (direction === "prev" && minDate) {
|
|
27
|
+
const prevMonth = subMonths(currentMonth, 1);
|
|
28
|
+
return prevMonth < minDate;
|
|
29
|
+
}
|
|
30
|
+
if (direction === "next" && maxDate) {
|
|
31
|
+
const nextMonth = addMonths(currentMonth, 1);
|
|
32
|
+
return nextMonth > maxDate;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}, [direction, currentMonth, minDate, maxDate]);
|
|
36
|
+
|
|
37
|
+
const state = calculateState(isDisabled, isHovered);
|
|
38
|
+
|
|
39
|
+
const handlePress = () => {
|
|
40
|
+
if (isDisabled) return;
|
|
41
|
+
const newMonth = direction === "prev" ? subMonths(currentMonth, 1) : addMonths(currentMonth, 1);
|
|
42
|
+
setCurrentMonth(newMonth);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const buttonStyle = [styles?.navButton?.default, styles?.navButton?.[state], style];
|
|
46
|
+
const textStyleCombined = [styles?.navButtonText?.default, styles?.navButtonText?.[state], textStyle];
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Pressable
|
|
50
|
+
{...pressableProps}
|
|
51
|
+
onPress={handlePress}
|
|
52
|
+
onHoverIn={() => setIsHovered(true)}
|
|
53
|
+
onHoverOut={() => setIsHovered(false)}
|
|
54
|
+
disabled={isDisabled}
|
|
55
|
+
style={buttonStyle}
|
|
56
|
+
>
|
|
57
|
+
<Text style={textStyleCombined}>{children}</Text>
|
|
58
|
+
</Pressable>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { View, StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
import { CalendarStyles } from "./types";
|
|
4
|
+
import { CalendarContext } from "./context";
|
|
5
|
+
|
|
6
|
+
export interface CalendarRootProps {
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
value?: Date | null;
|
|
9
|
+
onChange?: (date: Date | null) => void;
|
|
10
|
+
defaultMonth?: Date;
|
|
11
|
+
minDate?: Date;
|
|
12
|
+
maxDate?: Date;
|
|
13
|
+
style?: StyleProp<ViewStyle>;
|
|
14
|
+
styles?: CalendarStyles;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function CalendarRoot(props: CalendarRootProps) {
|
|
18
|
+
const { children, value, onChange, defaultMonth = new Date(), minDate, maxDate, style, styles, ...viewProps } = props;
|
|
19
|
+
|
|
20
|
+
const [currentMonth, setCurrentMonth] = useState<Date>(defaultMonth);
|
|
21
|
+
|
|
22
|
+
const containerStyle = [styles?.root, style];
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<CalendarContext.Provider
|
|
26
|
+
value={{
|
|
27
|
+
value,
|
|
28
|
+
onChange,
|
|
29
|
+
currentMonth,
|
|
30
|
+
setCurrentMonth,
|
|
31
|
+
styles,
|
|
32
|
+
minDate,
|
|
33
|
+
maxDate,
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<View {...viewProps} style={containerStyle}>
|
|
37
|
+
{children}
|
|
38
|
+
</View>
|
|
39
|
+
</CalendarContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text, TextProps, StyleProp, TextStyle } from "react-native";
|
|
3
|
+
import { formatDate } from "../../utils/date-utils";
|
|
4
|
+
import { useCalendarContext } from "./context";
|
|
5
|
+
|
|
6
|
+
export interface CalendarTitleProps extends TextProps {
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
style?: StyleProp<TextStyle>;
|
|
9
|
+
formatStr?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function CalendarTitle(props: CalendarTitleProps) {
|
|
13
|
+
const { children, style, formatStr = "MMMM yyyy", ...textProps } = props;
|
|
14
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
15
|
+
|
|
16
|
+
const titleStyle = [styles?.headerTitle, style];
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Text {...textProps} style={titleStyle}>
|
|
20
|
+
{children ?? formatDate(currentMonth, formatStr)}
|
|
21
|
+
</Text>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, Text, StyleProp, ViewStyle, TextStyle } from "react-native";
|
|
3
|
+
import { useCalendarContext } from "./context";
|
|
4
|
+
|
|
5
|
+
export interface CalendarWeekLabelProps {
|
|
6
|
+
children: string;
|
|
7
|
+
style?: StyleProp<TextStyle>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function CalendarWeekLabel(props: CalendarWeekLabelProps) {
|
|
11
|
+
const { styles } = useCalendarContext();
|
|
12
|
+
|
|
13
|
+
const composedStyle = [styles?.weekLabel, props.style];
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Text numberOfLines={1} style={composedStyle}>
|
|
17
|
+
{props.children}
|
|
18
|
+
</Text>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CalendarWeekLabelsProps {
|
|
23
|
+
weekDays?: string[];
|
|
24
|
+
|
|
25
|
+
style?: StyleProp<ViewStyle>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DEFAULT_WEEK_DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
29
|
+
|
|
30
|
+
export function CalendarWeekLabels(props: CalendarWeekLabelsProps) {
|
|
31
|
+
const { weekDays = DEFAULT_WEEK_DAYS, style } = props;
|
|
32
|
+
const { styles } = useCalendarContext();
|
|
33
|
+
|
|
34
|
+
const composedStyle = [styles?.weekLabels, style];
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<View style={composedStyle}>
|
|
38
|
+
{weekDays.map((day, index) => (
|
|
39
|
+
<CalendarWeekLabel key={index} style={styles?.weekLabel}>
|
|
40
|
+
{day}
|
|
41
|
+
</CalendarWeekLabel>
|
|
42
|
+
))}
|
|
43
|
+
</View>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, ViewProps, StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
import { getWeekDays, getWeeksInMonth } from "@/utils/date-utils";
|
|
4
|
+
import { useCalendarContext } from "./context";
|
|
5
|
+
import { CalendarDay } from "./calendar-day";
|
|
6
|
+
|
|
7
|
+
export interface CalendarWeekProps extends ViewProps {
|
|
8
|
+
index: number;
|
|
9
|
+
|
|
10
|
+
style?: StyleProp<ViewStyle>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function CalendarWeek(props: CalendarWeekProps) {
|
|
14
|
+
const { style, ...viewProps } = props;
|
|
15
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
16
|
+
|
|
17
|
+
const days = getWeekDays(currentMonth.getMonth(), currentMonth.getFullYear(), props.index);
|
|
18
|
+
|
|
19
|
+
const composedStyle = [styles?.week, style];
|
|
20
|
+
return (
|
|
21
|
+
<View {...viewProps} style={composedStyle}>
|
|
22
|
+
{days.map((day, index) => {
|
|
23
|
+
return <CalendarDay key={index} date={day} />;
|
|
24
|
+
})}
|
|
25
|
+
</View>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface CalendarWeeksProps extends ViewProps {
|
|
30
|
+
style?: StyleProp<ViewStyle>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function CalendarWeeks(props: CalendarWeeksProps) {
|
|
34
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
35
|
+
|
|
36
|
+
const weeks = getWeeksInMonth(currentMonth);
|
|
37
|
+
|
|
38
|
+
const composedStyle = [styles?.weeks, props.style];
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<View style={composedStyle}>
|
|
42
|
+
{Array.from({ length: weeks }).map((_, index) => {
|
|
43
|
+
return <CalendarWeek key={index} index={index} />;
|
|
44
|
+
})}
|
|
45
|
+
</View>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CalendarStyles } from "./types";
|
|
3
|
+
|
|
4
|
+
export interface CalendarContextValue {
|
|
5
|
+
value?: Date | null;
|
|
6
|
+
onChange?: (date: Date | null) => void;
|
|
7
|
+
currentMonth: Date;
|
|
8
|
+
setCurrentMonth: (month: Date) => void;
|
|
9
|
+
minDate?: Date;
|
|
10
|
+
maxDate?: Date;
|
|
11
|
+
|
|
12
|
+
styles?: CalendarStyles;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const CalendarContext = React.createContext<CalendarContextValue | undefined>(undefined);
|
|
16
|
+
|
|
17
|
+
export const useCalendarContext = () => {
|
|
18
|
+
const context = React.useContext(CalendarContext);
|
|
19
|
+
if (!context) {
|
|
20
|
+
throw new Error("Calendar components must be used within CalendarRoot");
|
|
21
|
+
}
|
|
22
|
+
return context;
|
|
23
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CalendarRoot } from "./calendar-root";
|
|
2
|
+
import { CalendarHeader } from "./calendar-header";
|
|
3
|
+
import { CalendarTitle } from "./calendar-title";
|
|
4
|
+
import { CalendarNavButton } from "./calendar-nav-button";
|
|
5
|
+
import { CalendarWeekLabels } from "./calendar-week-labels";
|
|
6
|
+
import { CalendarWeeks } from "./calendar-weeks";
|
|
7
|
+
import { CalendarDay } from "./calendar-day";
|
|
8
|
+
|
|
9
|
+
export const CalendarPrimitive = {
|
|
10
|
+
Root: CalendarRoot,
|
|
11
|
+
Header: CalendarHeader,
|
|
12
|
+
Title: CalendarTitle,
|
|
13
|
+
NavButton: CalendarNavButton,
|
|
14
|
+
CalendarWeekLabels: CalendarWeekLabels,
|
|
15
|
+
Weeks: CalendarWeeks,
|
|
16
|
+
Day: CalendarDay,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type { CalendarRootProps } from "./calendar-root";
|
|
20
|
+
export type { CalendarHeaderProps } from "./calendar-header";
|
|
21
|
+
export type { CalendarTitleProps } from "./calendar-title";
|
|
22
|
+
export type { CalendarNavButtonProps } from "./calendar-nav-button";
|
|
23
|
+
export type { CalendarWeekLabelsProps } from "./calendar-week-labels";
|
|
24
|
+
export type { CalendarWeeksProps } from "./calendar-weeks";
|
|
25
|
+
export type { CalendarDayProps } from "./calendar-day";
|
|
26
|
+
export type { CalendarStyles, CalendarDayState } from "./types";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ViewStyle, TextStyle } from "react-native";
|
|
2
|
+
import { CalendarWeekProps, CalendarWeeksProps } from "./calendar-weeks";
|
|
3
|
+
import { CalendarWeekLabelProps, CalendarWeekLabelsProps } from "./calendar-week-labels";
|
|
4
|
+
import { CalendarDayProps } from "./calendar-day";
|
|
5
|
+
import { CalendarRootProps } from "./calendar-root";
|
|
6
|
+
import { CalendarHeaderProps } from "./calendar-header";
|
|
7
|
+
import { CalendarTitleProps } from "./calendar-title";
|
|
8
|
+
|
|
9
|
+
export type CalendarDayState = "default" | "selected" | "today" | "disabled" | "deprioritized" | "hovered";
|
|
10
|
+
export type CalendarNavButtonState = "default" | "disabled" | "hovered";
|
|
11
|
+
|
|
12
|
+
export interface CalendarStyles {
|
|
13
|
+
root?: CalendarRootProps["style"];
|
|
14
|
+
header?: CalendarHeaderProps["style"];
|
|
15
|
+
headerTitle?: CalendarTitleProps["style"];
|
|
16
|
+
navButton?: Partial<Record<CalendarNavButtonState, ViewStyle>>;
|
|
17
|
+
navButtonText?: Partial<Record<CalendarNavButtonState, TextStyle>>;
|
|
18
|
+
weekLabels: CalendarWeekLabelsProps["style"];
|
|
19
|
+
weekLabel?: CalendarWeekLabelProps["style"];
|
|
20
|
+
weeks?: CalendarWeekProps["style"];
|
|
21
|
+
week?: CalendarWeeksProps["style"];
|
|
22
|
+
dayButton?: Partial<Record<CalendarDayState, CalendarDayProps["style"]>>;
|
|
23
|
+
dayText?: Partial<Record<CalendarDayState, CalendarDayProps["textStyle"]>>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type Months = [
|
|
27
|
+
january: number,
|
|
28
|
+
february: number,
|
|
29
|
+
march: number,
|
|
30
|
+
april: number,
|
|
31
|
+
may: number,
|
|
32
|
+
june: number,
|
|
33
|
+
july: number,
|
|
34
|
+
august: number,
|
|
35
|
+
september: number,
|
|
36
|
+
october: number,
|
|
37
|
+
november: number,
|
|
38
|
+
december: number
|
|
39
|
+
];
|
package/src/primitives/index.ts
CHANGED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export const formatDate = (date: Date, format: string): string => {
|
|
2
|
+
const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3
|
+
|
|
4
|
+
const day = date.getDate();
|
|
5
|
+
const month = months[date.getMonth()];
|
|
6
|
+
const year = date.getFullYear();
|
|
7
|
+
|
|
8
|
+
if (format === "MMMM yyyy") {
|
|
9
|
+
return `${month} ${year}`;
|
|
10
|
+
}
|
|
11
|
+
if (format === "d") {
|
|
12
|
+
return day.toString();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return date.toLocaleDateString();
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const isDateSameDay = (date1: Date, date2: Date): boolean => {
|
|
19
|
+
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const isDateToday = (date: Date): boolean => {
|
|
23
|
+
return isDateSameDay(date, new Date());
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const isDateBefore = (date1: Date, date2: Date): boolean => {
|
|
27
|
+
const d1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
|
|
28
|
+
const d2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
|
|
29
|
+
return d1.getTime() < d2.getTime();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const isDateAfter = (date1: Date, date2: Date): boolean => {
|
|
33
|
+
const d1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
|
|
34
|
+
const d2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
|
|
35
|
+
return d1.getTime() > d2.getTime();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const isDateTimeWithinInterval = (date: Date, interval: { start: Date; end: Date }): boolean => {
|
|
39
|
+
const time = date.getTime();
|
|
40
|
+
return time >= interval.start.getTime() && time <= interval.end.getTime();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const addMonths = (date: Date, months: number): Date => {
|
|
44
|
+
const newDate = new Date(date);
|
|
45
|
+
newDate.setMonth(newDate.getMonth() + months);
|
|
46
|
+
return newDate;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const subMonths = (date: Date, months: number): Date => {
|
|
50
|
+
return addMonths(date, -months);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const startOfMonth = (date: Date): Date => {
|
|
54
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const endOfMonth = (date: Date): Date => {
|
|
58
|
+
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const getDaysInMonth = (date: Date): number => {
|
|
62
|
+
return endOfMonth(date).getDate();
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const getFirstDayOfMonth = (date: Date): number => {
|
|
66
|
+
return startOfMonth(date).getDay();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const isSameMonth = (date1: Date, date2: Date): boolean => {
|
|
70
|
+
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth();
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const getWeekDays = (month: number, year: number, week: number): Date[] => {
|
|
74
|
+
const days: Date[] = [];
|
|
75
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
76
|
+
const daysInMonth = getDaysInMonth(new Date(year, month));
|
|
77
|
+
|
|
78
|
+
// Calculate the date of the first day in the week
|
|
79
|
+
const startDay = week * 7 - (firstDayOfMonth === 0 ? 6 : firstDayOfMonth - 1);
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < 7; i++) {
|
|
82
|
+
const day = startDay + i;
|
|
83
|
+
let date: Date;
|
|
84
|
+
|
|
85
|
+
if (day < 1) {
|
|
86
|
+
// Days from previous month
|
|
87
|
+
const prevMonth = month === 0 ? 11 : month - 1;
|
|
88
|
+
const prevYear = month === 0 ? year - 1 : year;
|
|
89
|
+
const daysInPrevMonth = getDaysInMonth(new Date(prevYear, prevMonth));
|
|
90
|
+
date = new Date(prevYear, prevMonth, daysInPrevMonth + day);
|
|
91
|
+
} else if (day > daysInMonth) {
|
|
92
|
+
// Days from next month
|
|
93
|
+
const nextMonth = month === 11 ? 0 : month + 1;
|
|
94
|
+
const nextYear = month === 11 ? year + 1 : year;
|
|
95
|
+
date = new Date(nextYear, nextMonth, day - daysInMonth);
|
|
96
|
+
} else {
|
|
97
|
+
// Days from current month
|
|
98
|
+
date = new Date(year, month, day);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
days.push(date);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return days;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const getWeeksInMonth = (date: Date): number => {
|
|
108
|
+
const firstDayOfMonth = getFirstDayOfMonth(date);
|
|
109
|
+
const daysInMonth = getDaysInMonth(date);
|
|
110
|
+
|
|
111
|
+
// Calculate total number of weeks
|
|
112
|
+
return Math.ceil((firstDayOfMonth + daysInMonth) / 7);
|
|
113
|
+
};
|