Skip to content

Commit

Permalink
feat: add support for month/year picker
Browse files Browse the repository at this point in the history
  • Loading branch information
lew-cold committed Dec 31, 2024
1 parent 93ac2f4 commit 2911a98
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 8 deletions.
43 changes: 35 additions & 8 deletions src/components/calendarPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
SimpleGrid,
Box,
Stack,
Flex,
Select,
} from '@chakra-ui/react';
import { useDayzed, Props as DayzedHookProps } from 'dayzed';
import { ArrowKeysReact } from '../utils/reactKeysArrow';
Expand All @@ -20,6 +22,9 @@ export interface CalendarPanelProps extends DatepickerProps {
disabledDates?: Set<number>;
onMouseEnterHighlight?: (date: Date) => void;
isInRange?: (date: Date) => boolean | null;
handleMonthChange?: (ev: React.ChangeEvent<HTMLSelectElement>) => void;
handleYearChange?: (ev: React.ChangeEvent<HTMLSelectElement>) => void;
showYearMonthPicker?: boolean;
}

export const CalendarPanel: React.FC<CalendarPanelProps> = ({
Expand All @@ -29,6 +34,9 @@ export const CalendarPanel: React.FC<CalendarPanelProps> = ({
disabledDates,
onMouseEnterHighlight,
isInRange,
showYearMonthPicker,
handleMonthChange,
handleYearChange,
}) => {
const renderProps = useDayzed(dayzedHookProps);
const { calendars, getBackProps, getForwardProps } = renderProps;
Expand Down Expand Up @@ -101,14 +109,33 @@ export const CalendarPanel: React.FC<CalendarPanelProps> = ({
getBackProps={getBackProps}
propsConfigs={propsConfigs}
/>
<Heading
size="sm"
minWidth={'5rem'}
textAlign="center"
{...propsConfigs?.dateHeadingProps}
>
{configs.monthNames[calendar.month]} {calendar.year}
</Heading>
{showYearMonthPicker ? (
<Flex flexDir="row">
<Select onChange={handleMonthChange} {...propsConfigs?.monthSelectProps}>
{configs.monthNames.map((month, idx) => (
<option key={idx} value={idx}>
{month}
</option>
))}
</Select>
<Select onChange={handleYearChange} {...propsConfigs?.yearSelectProps}>
{configs.years.map((year, idx) => (
<option key={idx} value={year}>
{year}
</option>
))}
</Select>
</Flex>
) : (
<Heading
size="sm"
minWidth={'5rem'}
textAlign="center"
{...propsConfigs?.dateHeadingProps}
>
{configs.monthNames[calendar.month]} {calendar.year}
</Heading>
)}
<DatepickerForwardBtns
calendars={calendars}
getForwardProps={getForwardProps}
Expand Down
1 change: 1 addition & 0 deletions src/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const DefaultConfigs: Required<DatepickerConfigs> = {
dayNames: Weekday_Names_Short,
firstDayOfWeek: 0,
monthsToDisplay: 2,
years: []
};

const defaultProps = {
Expand Down
27 changes: 27 additions & 0 deletions src/single.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface SingleProps extends DatepickerProps {
name?: string;
usePortal?: boolean;
portalRef?: React.MutableRefObject<null>;
showYearMonthPicker?: boolean
}

export type VariantProps =
Expand All @@ -71,6 +72,8 @@ const DefaultConfigs: Required<DatepickerConfigs> = {
dayNames: Weekday_Names_Short,
firstDayOfWeek: 0,
monthsToDisplay: 1,
// Populates the years from now until 120 years ago.
years: Array.from({ length: 120 }, (_, i) => new Date().getFullYear() - i),
};

export const SingleDatepicker: React.FC<SingleDatepickerProps> = ({
Expand All @@ -88,10 +91,15 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = ({
defaultIsOpen = false,
closeOnSelect = true,
children,
showYearMonthPicker,
...restProps
}) => {
const [dateInView, setDateInView] = useState(selectedDate);
const [offset, setOffset] = useState(0);
const [selectedMonth, setSelectedMonth] = useState(selectedDate ? selectedDate.getMonth(): new Date().getMonth());
const [selectedYear, setSelectedYear] = useState(selectedDate ? selectedDate.getFullYear() : new Date().getFullYear());
const [selectedDay] = useState(selectedDate ? selectedDate.getDate() : new Date().getDate());

const internalUpdate = useRef(false);

const { onOpen, onClose, isOpen } = useDisclosure({ defaultIsOpen });
Expand Down Expand Up @@ -154,6 +162,22 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = ({
[datepickerConfigs.dateFormat, disabledDates, onDateChange]
);

const handleMonthChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
let newZeroBasedMonth = e.target.value as unknown as number;
let newDateInView = new Date(selectedYear, newZeroBasedMonth, selectedDay);
setSelectedMonth(newDateInView.getMonth());
setDateInView(newDateInView);
setOffset(0);
};

const handleYearChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
let newYear = e.target.value as unknown as number;
let newDateInView = new Date(newYear, selectedMonth, selectedDay);
setSelectedYear(newDateInView.getFullYear());
setDateInView(newDateInView);
setOffset(0);
};

const PopoverContentWrapper = usePortal ? Portal : React.Fragment;

useEffect(() => {
Expand Down Expand Up @@ -264,6 +288,9 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = ({
configs={datepickerConfigs}
propsConfigs={restProps.propsConfigs}
disabledDates={disabledDates}
handleMonthChange={handleMonthChange}
handleYearChange={handleYearChange}
showYearMonthPicker={showYearMonthPicker}
/>
</FocusLock>
</PopoverBody>
Expand Down
5 changes: 5 additions & 0 deletions src/utils/commonTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
HeadingProps,
InputProps,
PopoverBodyProps,
SelectProps,
SimpleGridProps,
StackProps,
} from '@chakra-ui/react';
Expand Down Expand Up @@ -51,6 +52,8 @@ export interface PropsConfigs {
calendarPanelProps?: CalendarPanelProps;
dateHeadingProps?: HeadingProps;
weekdayLabelProps?: BoxProps;
yearSelectProps?: SelectProps;
monthSelectProps?: SelectProps;
}

export interface DatepickerConfigs {
Expand All @@ -59,11 +62,13 @@ export interface DatepickerConfigs {
dayNames?: string[];
firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
monthsToDisplay?: number;
years?: number[]
}

export interface CalendarConfigs {
dateFormat: string;
monthNames: string[];
dayNames: string[];
firstDayOfWeek: 0 | 1 | 2 | 3 | 4 | 5 | 6;
years: number[];
}

0 comments on commit 2911a98

Please sign in to comment.