Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a new methods isYearDisabled, isMonthDisabled for disabling unavailable months, year #140

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions demo/components/examples/single-datepicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default function SingleDatePicker() {
date={date}
onChange={({ date }) => setDate(date)}
timePicker
// minDate={new Date()}
// maxDate={new Date(new Date().getFullYear(), 11, 31)} // end of the year
/>
<DateInput
value={date ? dayjs(date).format('MMMM DD, YYYY HH:mm') : null}
Expand Down
19 changes: 16 additions & 3 deletions src/components/months.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { View, StyleSheet, Pressable, Text } from 'react-native';
import { useCalendarContext } from '../calendar-context';
import { getParsedDate, getMonthsArray, cn } from '../utils';
import { getParsedDate, getMonthsArray, cn, isMonthDisabled } from '../utils';
import { CONTAINER_HEIGHT } from '../enums';

const Months = () => {
Expand All @@ -13,6 +13,8 @@ const Months = () => {
components = {},
containerHeight = CONTAINER_HEIGHT,
monthsFormat = 'full',
minDate,
maxDate
} = useCalendarContext();

const style = useMemo(
Expand All @@ -33,31 +35,41 @@ const Months = () => {
{getMonthsArray()?.map((item, index) => {
const isSelected = index === month;

const isDisabled = isMonthDisabled(index, currentDate, {
minDate,
maxDate,
});

const itemStyle = StyleSheet.flatten([
defaultStyles.month,
styles.month,
isSelected && styles.selected_month,
isDisabled && styles.disabled
]);

const textStyle = StyleSheet.flatten([
styles.month_label,
isSelected && styles.selected_month_label,
isDisabled && styles.disabled_label
]);

const containerClassName = cn(
classNames.month,
isSelected && classNames.selected_month
isSelected && classNames.selected_month,
isDisabled && classNames.disabled
);

const textClassName = cn(
classNames.month_label,
isSelected && classNames.selected_month_label
isSelected && classNames.selected_month_label,
isDisabled && classNames.disabled_label
);

return (
<View key={index} style={style.monthCell}>
{components.Month ? (
<Pressable
disabled={isDisabled}
onPress={() => onSelectMonth(index)}
accessibilityRole="button"
accessibilityLabel={item.name.full}
Expand All @@ -67,6 +79,7 @@ const Months = () => {
</Pressable>
) : (
<Pressable
disabled={isDisabled}
onPress={() => onSelectMonth(index)}
accessibilityRole="button"
accessibilityLabel={item.name.full}
Expand Down
16 changes: 13 additions & 3 deletions src/components/years.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useCallback, useMemo } from 'react';
import { View, StyleSheet, Pressable, Text } from 'react-native';
import { useCalendarContext } from '../calendar-context';
import { cn, formatNumber, getDateYear, getYearRange } from '../utils';
import { cn, formatNumber, getDateYear, getYearRange, isYearDisabled } from '../utils';
import { CONTAINER_HEIGHT } from '../enums';

const Years = () => {
Expand All @@ -16,6 +16,8 @@ const Years = () => {
classNames = {},
components = {},
containerHeight = CONTAINER_HEIGHT,
minDate,
maxDate
} = useCalendarContext();

const style = useMemo(
Expand All @@ -32,35 +34,42 @@ const Years = () => {
const isSelected = year === selectedYear;
const isActivated = year === activeYear;

const isDisabled = isYearDisabled(year, { minDate, maxDate });

const containerStyle = StyleSheet.flatten([
defaultStyles.year,
styles.year,
isActivated && styles.active_year,
isSelected && styles.selected_year,
isDisabled && styles.disabled
]);

const textStyle = StyleSheet.flatten([
styles.year_label,
isActivated && styles.active_year_label,
isSelected && styles.selected_year_label,
isDisabled && styles.disabled_label
]);

const containerClassName = cn(
classNames.year,
isActivated && classNames.active_year,
isSelected && classNames.selected_year
isSelected && classNames.selected_year,
isDisabled && classNames.disabled
);

const textClassName = cn(
classNames.year_label,
isActivated && classNames.active_year_label,
isSelected && classNames.selected_year_label
isSelected && classNames.selected_year_label,
isDisabled && classNames.disabled_label
);

return (
<View key={year} style={style.yearCell}>
{components.Year ? (
<Pressable
disabled={isDisabled}
onPress={() => onSelectYear(year)}
accessibilityRole="button"
accessibilityLabel={year.toString()}
Expand All @@ -75,6 +84,7 @@ const Years = () => {
</Pressable>
) : (
<Pressable
disabled={isDisabled}
onPress={() => onSelectYear(year)}
accessibilityRole="button"
accessibilityLabel={year.toString()}
Expand Down
12 changes: 7 additions & 5 deletions src/theme.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useColorScheme } from 'react-native';
import { ClassNames, Styles } from './types';
import { UI, SelectionState, DayFlag, MonthState, YearState } from './ui';
import { UI, SelectionState, DayFlag, MonthState, YearState, CalenderFlag } from './ui';

export function getDefaultClassNames(): ClassNames {
const classNames: ClassNames = {
Expand Down Expand Up @@ -44,8 +44,9 @@ export function getDefaultClassNames(): ClassNames {
'group bg-primary web:hover:bg-primary web:hover:opacity-90 active:opacity-90',
[SelectionState.selected_label]: 'text-primary-foreground',

[DayFlag.disabled]: '',
[DayFlag.disabled_label]: 'text-muted-foreground opacity-50',
[CalenderFlag.disabled]: '',
[CalenderFlag.disabled_label]: 'text-muted-foreground opacity-50',

[DayFlag.hidden]: '',
[DayFlag.outside]: '',
[DayFlag.outside_label]: 'text-muted-foreground',
Expand Down Expand Up @@ -149,11 +150,12 @@ export function getDefaultStyles(): Styles {
color: COLORS[theme].primaryForeground,
},

[DayFlag.disabled]: {},
[DayFlag.disabled_label]: {
[CalenderFlag.disabled]: {},
[CalenderFlag.disabled_label]: {
color: COLORS[theme].mutedForeground,
opacity: 0.5,
},

[DayFlag.hidden]: {},
[DayFlag.outside]: {},
[DayFlag.outside_label]: { color: COLORS[theme].mutedForeground },
Expand Down
6 changes: 3 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Dayjs } from 'dayjs';
import type { CalendarActionKind, CalendarViews } from './enums';
import type { TextStyle, ViewStyle } from 'react-native';
import { UI, SelectionState, DayFlag, MonthState, YearState } from './ui';
import { UI, SelectionState, DayFlag, MonthState, YearState, CalenderFlag } from './ui';

export type DateType = string | number | Dayjs | Date | null | undefined;

Expand Down Expand Up @@ -87,11 +87,11 @@ export type MultiChange = (params: {
}) => void;

export type ClassNames = Partial<{
[key in UI | SelectionState | DayFlag | MonthState | YearState]: string;
[key in UI | SelectionState | DayFlag | MonthState | YearState | CalenderFlag]: string;
}>;

export type Styles = Partial<{
[key in UI | SelectionState | DayFlag | MonthState | YearState]:
[key in UI | SelectionState | DayFlag | MonthState | YearState | CalenderFlag]:
| ViewStyle
| TextStyle;
}>;
Expand Down
9 changes: 6 additions & 3 deletions src/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,14 @@ export enum SelectionState {
selected_label = 'selected_label',
}

export enum DayFlag {
/** The day is disabled. */
export enum CalenderFlag {
/** The day/month/year is disabled. */
disabled = 'disabled',
/** The label of the disabled day. */
/** The label of the disabled day/month/year. */
disabled_label = 'disabled_label',
}

export enum DayFlag {
/** The day is hidden. */
hidden = 'hidden',
/** The day is outside the current month. */
Expand Down
78 changes: 64 additions & 14 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,56 @@ export function isDateDisabled(
return false;
}

/**
* Check if year is disabled
*
* @param year - year to check
* @param options - options
*
* @returns true if year is disabled, false otherwise
*/
export function isYearDisabled(
year: number,
{
minDate,
maxDate,
}: {
minDate?: DateType;
maxDate?: DateType;
}
): boolean {
if (minDate && year < getDateYear(minDate)) return true;
if (maxDate && year > getDateYear(maxDate)) return true;

return false;
}

/**
* Check if month is disabled
*
* @param month - month to check
* @param date - date to check
* @param options - options
*
* @returns true if month is disabled, false otherwise
*/
export function isMonthDisabled(
month: number,
date: DateType,
{
minDate,
maxDate,
}: {
minDate?: DateType;
maxDate?: DateType;
}
): boolean {
if (minDate && month < getDateMonth(minDate) && getDateYear(date) === getDateYear(minDate)) return true;
if (maxDate && month > getDateMonth(maxDate) && getDateYear(date) === getDateYear(maxDate)) return true;

return false;
}

/**
* Get formated date
*
Expand Down Expand Up @@ -356,20 +406,20 @@ export const getMonthDays = (

const prevDays = showOutsideDays
? Array.from({ length: prevMonthOffset }, (_, index) => {
const number = index + (prevMonthDays - prevMonthOffset + 1);
const thisDay = date.add(-1, 'month').date(number);
return generateCalendarDay(
number,
thisDay,
minDate,
maxDate,
disabledDates,
false,
index + 1,
firstDayOfWeek,
numerals
);
})
const number = index + (prevMonthDays - prevMonthOffset + 1);
const thisDay = date.add(-1, 'month').date(number);
return generateCalendarDay(
number,
thisDay,
minDate,
maxDate,
disabledDates,
false,
index + 1,
firstDayOfWeek,
numerals
);
})
: Array(prevMonthOffset).fill(null);

const currentDays = Array.from({ length: daysInCurrentMonth }, (_, index) => {
Expand Down
Loading