Skip to content

Commit

Permalink
Merge pull request #14 from farhoudshapouran/add-custom-header-buttons
Browse files Browse the repository at this point in the history
chore: add custom button options to header
  • Loading branch information
farhoudshapouran authored Oct 26, 2023
2 parents 935680a + afca590 commit 6bd1c03
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 115 deletions.
10 changes: 8 additions & 2 deletions src/DateTimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import type {
CalendarAction,
CalendarState,
CalendarTheme,
HeaderProps,
} from './types';
import Calendar from './components/Calendar';

interface PropTypes extends CalendarTheme {
interface PropTypes extends CalendarTheme, HeaderProps {
value: DateType;
mode?: CalendarModes;
locale?: string | ILocale;
Expand Down Expand Up @@ -46,6 +47,8 @@ const DateTimePicker = ({
selectedItemColor,
timePickerContainerStyle,
timePickerTextStyle,
buttonLeftIcon,
buttonRightIcon,
}: PropTypes) => {
const utils = new calendarUtils({
mode,
Expand Down Expand Up @@ -173,7 +176,10 @@ const DateTimePicker = ({

return (
<CalendarContext.Provider value={{ ...state, ...actions, utils, theme }}>
<Calendar />
<Calendar
buttonLeftIcon={buttonLeftIcon}
buttonRightIcon={buttonRightIcon}
/>
</CalendarContext.Provider>
);
};
Expand Down
16 changes: 12 additions & 4 deletions src/components/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
import React, { ReactElement } from 'react';
import React, { ReactNode } from 'react';
import { View, StyleSheet } from 'react-native';
import { useCalendarContext } from '../CalendarContext';
import type { CalendarViews } from '../enums';
import type { HeaderProps } from '../types';
import Header from './Header';
import YearSelector from './YearSelector';
import MonthSelector from './MonthSelector';
import DaySelector from './DaySelector';
import TimeSelector from './TimeSelector';

const CalendarView: Record<CalendarViews, ReactElement> = {
const CalendarView: Record<CalendarViews, ReactNode> = {
year: <YearSelector />,
month: <MonthSelector />,
day: <DaySelector />,
time: <TimeSelector />,
};

const Calendar = () => {
interface PropTypes extends HeaderProps {}

const Calendar = ({ buttonLeftIcon, buttonRightIcon }: PropTypes) => {
const { calendarView, mode } = useCalendarContext();

return (
<View style={styles.container}>
{mode !== 'time' ? <Header /> : null}
{mode !== 'time' ? (
<Header
buttonLeftIcon={buttonLeftIcon}
buttonRightIcon={buttonRightIcon}
/>
) : null}
<View style={styles.calendarContainer}>{CalendarView[calendarView]}</View>
</View>
);
Expand Down
10 changes: 8 additions & 2 deletions src/components/DaySelector.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import React, { memo } from 'react';
import React, { memo, useMemo } from 'react';
import { Text, View, TouchableOpacity, StyleSheet } from 'react-native';
import { useCalendarContext } from '../CalendarContext';

const DaySelector = () => {
const { utils, currentDate, selectedDate, onSelectDate, theme } =
useCalendarContext();
const days = utils.getMonthDays(currentDate);
const month = utils.getDateMonth(currentDate);
const year = utils.getDateYear(currentDate);
const days = useMemo(
() => utils.getMonthDays(currentDate),
// eslint-disable-next-line react-hooks/exhaustive-deps
[month, year]
);

const handleSelectDate = (date: string) => {
const newDate = utils
Expand Down
207 changes: 100 additions & 107 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { View, Text, TouchableOpacity, StyleSheet, Image } from 'react-native';
import { useCalendarContext } from '../CalendarContext';
import dayjs from 'dayjs';
import { CalendarViews } from '../enums';
import type { HeaderProps } from '../types';

const arrow_left = require('../assets/images/arrow_left.png');
const arrow_right = require('../assets/images/arrow_right.png');

const Header = () => {
const Header = ({ buttonLeftIcon, buttonRightIcon }: HeaderProps) => {
const {
currentDate,
selectedDate,
Expand All @@ -19,20 +20,20 @@ const Header = () => {
theme,
} = useCalendarContext();

const renderPrevButton = () => {
return (
<TouchableOpacity
onPress={() =>
calendarView === CalendarViews.day
? onChangeMonth(-1)
: calendarView === CalendarViews.month
? onChangeYear(-1)
: calendarView === CalendarViews.year && onChangeYear(-12)
}
const renderPrevButton = (
<TouchableOpacity
onPress={() =>
calendarView === CalendarViews.day
? onChangeMonth(-1)
: calendarView === CalendarViews.month
? onChangeYear(-1)
: calendarView === CalendarViews.year && onChangeYear(-12)
}
>
<View
style={[styles.iconContainer, styles.prev, theme?.headerButtonStyle]}
>
<View
style={[styles.iconContainer, styles.prev, theme?.headerButtonStyle]}
>
{buttonLeftIcon || (
<Image
source={arrow_left}
style={{
Expand All @@ -41,25 +42,25 @@ const Header = () => {
tintColor: theme?.headerButtonColor,
}}
/>
</View>
</TouchableOpacity>
);
};
)}
</View>
</TouchableOpacity>
);

const renderNextButton = () => {
return (
<TouchableOpacity
onPress={() =>
calendarView === CalendarViews.day
? onChangeMonth(1)
: calendarView === CalendarViews.month
? onChangeYear(1)
: calendarView === CalendarViews.year && onChangeYear(12)
}
const renderNextButton = (
<TouchableOpacity
onPress={() =>
calendarView === CalendarViews.day
? onChangeMonth(1)
: calendarView === CalendarViews.month
? onChangeYear(1)
: calendarView === CalendarViews.year && onChangeYear(12)
}
>
<View
style={[styles.iconContainer, styles.next, theme?.headerButtonStyle]}
>
<View
style={[styles.iconContainer, styles.next, theme?.headerButtonStyle]}
>
{buttonRightIcon || (
<Image
source={arrow_right}
style={{
Expand All @@ -68,99 +69,91 @@ const Header = () => {
tintColor: theme?.headerButtonColor,
}}
/>
</View>
</TouchableOpacity>
);
};
)}
</View>
</TouchableOpacity>
);

const renderSelectors = () => {
return (
<>
<View style={styles.selectorContainer}>
<TouchableOpacity
onPress={() =>
setCalendarView(
calendarView === CalendarViews.month
? CalendarViews.day
: CalendarViews.month
)
}
>
<View
style={[styles.textContainer, theme?.headerTextContainerStyle]}
>
<Text style={[styles.text, theme?.headerTextStyle]}>
{dayjs(currentDate).format('MMMM')}
</Text>
</View>
</TouchableOpacity>
const renderSelectors = (
<>
<View style={styles.selectorContainer}>
<TouchableOpacity
onPress={() =>
setCalendarView(
calendarView === CalendarViews.month
? CalendarViews.day
: CalendarViews.month
)
}
>
<View style={[styles.textContainer, theme?.headerTextContainerStyle]}>
<Text style={[styles.text, theme?.headerTextStyle]}>
{dayjs(currentDate).format('MMMM')}
</Text>
</View>
</TouchableOpacity>

<TouchableOpacity
onPress={() =>
setCalendarView(
calendarView === CalendarViews.year
? CalendarViews.day
: CalendarViews.year
)
}
>
<View
style={[styles.textContainer, theme?.headerTextContainerStyle]}
>
<Text style={[styles.text, theme?.headerTextStyle]}>
{calendarView === CalendarViews.year
? dayjs(selectedDate).format('YYYY')
: dayjs(currentDate).format('YYYY')}
</Text>
</View>
</TouchableOpacity>
</View>
{mode === 'datetime' ? (
<TouchableOpacity
onPress={() =>
setCalendarView(
calendarView === CalendarViews.time
? CalendarViews.day
: CalendarViews.time
)
}
>
<View
style={[styles.textContainer, theme?.headerTextContainerStyle]}
>
<Text style={[styles.text, theme?.headerTextStyle]}>
{dayjs(selectedDate).format('HH:mm')}
</Text>
</View>
</TouchableOpacity>
) : null}
</>
);
};
<TouchableOpacity
onPress={() =>
setCalendarView(
calendarView === CalendarViews.year
? CalendarViews.day
: CalendarViews.year
)
}
>
<View style={[styles.textContainer, theme?.headerTextContainerStyle]}>
<Text style={[styles.text, theme?.headerTextStyle]}>
{calendarView === CalendarViews.year
? dayjs(selectedDate).format('YYYY')
: dayjs(currentDate).format('YYYY')}
</Text>
</View>
</TouchableOpacity>
</View>
{mode === 'datetime' ? (
<TouchableOpacity
onPress={() =>
setCalendarView(
calendarView === CalendarViews.time
? CalendarViews.day
: CalendarViews.time
)
}
>
<View style={[styles.textContainer, theme?.headerTextContainerStyle]}>
<Text style={[styles.text, theme?.headerTextStyle]}>
{dayjs(selectedDate).format('HH:mm')}
</Text>
</View>
</TouchableOpacity>
) : null}
</>
);

return (
<View style={[styles.headerContainer, theme?.headerContainerStyle]}>
{theme?.headerButtonsPosition === 'left' ? (
<View style={styles.container}>
<View style={styles.row}>
{renderPrevButton()}
{renderNextButton()}
{renderPrevButton}
{renderNextButton}
</View>
{renderSelectors()}
{renderSelectors}
</View>
) : theme?.headerButtonsPosition === 'right' ? (
<View style={styles.container}>
{renderSelectors()}
{renderSelectors}
<View style={styles.row}>
{renderPrevButton()}
{renderNextButton()}
{renderPrevButton}
{renderNextButton}
</View>
</View>
) : (
<View style={styles.container}>
{renderPrevButton()}
{renderSelectors()}
{renderNextButton()}
{renderPrevButton}
{renderSelectors}
{renderNextButton}
</View>
)}
</View>
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Dayjs } from 'dayjs';
import type { CalendarActionKind, CalendarViews } from './enums';
import type { TextStyle, ViewStyle } from 'react-native';
import type { ReactNode } from 'react';

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

Expand Down Expand Up @@ -39,3 +40,8 @@ export type CalendarTheme = {
timePickerContainerStyle?: ViewStyle;
timePickerTextStyle?: TextStyle;
};

export type HeaderProps = {
buttonLeftIcon?: ReactNode;
buttonRightIcon?: ReactNode;
};

0 comments on commit 6bd1c03

Please sign in to comment.