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

Add custom date button renderer and event handlers (month change, popover open) #34

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,17 @@ Non Chakra-related configurations :

### other props:

Name | Type | Default value | Description
----------------------|------------------------|-------------------------|--------------
name | string | undefined | name attribute for `<input />` element
usePortal | boolean | undefined | to prevent parent styles from clipping or hiding content
defaultIsOpen | boolean | undefined | open the date panel at the beginning
minDate | Date | undefined | minimum date
maxDate | Date | undefined | maximum date
Name | Type | Default value | Description | Single/Range
----------------------|------------------------|-------------------------|--------------------------------------------------------|---------------
name | string | undefined | name attribute for `<input />` element | both
usePortal | boolean | undefined | to prevent parent styles from clipping or hiding content| both
defaultIsOpen | boolean | undefined | open the date panel at the beginning | both
minDate | Date | undefined | minimum date | both
maxDate | Date | undefined | maximum date | both
onMonthViewChange | ({calendars, offset}: {calendars: Calendar[]; offset: number;}) => void | undefined | runs when the current month is changed | single
onPopoverOpen | () => void | undefined | runs when the calendar popover is opened | single
customDateButton | (dateObj: DateObjExtended, { dateProps, btnProps }: CustomDateButtonProps) => ReactElement; | undefined | custom date button renderer that replaces the original one | single


For version < `npm@0.1.6`:</br>
`dayOfMonthBtnProps` extends from `ButtonProps` and has only `selectedBg` support,
Expand Down
14 changes: 13 additions & 1 deletion src/components/calendarPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import {
import { useDayzed, Props as DayzedHookProps } from 'dayzed';
import { ArrowKeysReact } from '../utils/reactKeysArrow';
import React, { useCallback, useMemo } from 'react';
import { CalendarConfigs, DatepickerProps } from '../utils/commonTypes';
import {
CalendarConfigs,
DatepickerProps,
CustomDateButton,
OnMonthViewChange,
} from '../utils/commonTypes';
import { DatepickerBackBtns, DatepickerForwardBtns } from './dateNavBtns';
import { DayOfMonth } from './dayOfMonth';

Expand All @@ -19,6 +24,8 @@ interface CalendarPanelProps extends DatepickerProps {
configs: CalendarConfigs;
onMouseEnterHighlight?: (date: Date) => void;
isInRange?: (date: Date) => boolean | null;
onMonthViewChange?: OnMonthViewChange;
customDateButton?: CustomDateButton;
}

export const CalendarPanel: React.FC<CalendarPanelProps> = ({
Expand All @@ -27,6 +34,8 @@ export const CalendarPanel: React.FC<CalendarPanelProps> = ({
propsConfigs,
onMouseEnterHighlight,
isInRange,
onMonthViewChange,
customDateButton,
}) => {
const renderProps = useDayzed(dayzedHookProps);
const { calendars, getBackProps, getForwardProps } = renderProps;
Expand Down Expand Up @@ -96,6 +105,7 @@ export const CalendarPanel: React.FC<CalendarPanelProps> = ({
calendars={calendars}
getBackProps={getBackProps}
propsConfigs={propsConfigs}
onMonthViewChange={onMonthViewChange}
/>
<Heading size="sm" minWidth={'5rem'} textAlign="center">
{configs.monthNames[calendar.month]} {calendar.year}
Expand All @@ -104,6 +114,7 @@ export const CalendarPanel: React.FC<CalendarPanelProps> = ({
calendars={calendars}
getForwardProps={getForwardProps}
propsConfigs={propsConfigs}
onMonthViewChange={onMonthViewChange}
/>
</HStack>
<Divider />
Expand All @@ -128,6 +139,7 @@ export const CalendarPanel: React.FC<CalendarPanelProps> = ({
onMouseEnter={() => {
if (onMouseEnterHighlight) onMouseEnterHighlight(date);
}}
customDateButton={customDateButton}
/>
);
});
Expand Down
57 changes: 39 additions & 18 deletions src/components/dateNavBtns.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Button, ButtonProps } from '@chakra-ui/react';
import { Calendar, GetBackForwardPropsOptions } from 'dayzed';
import React, { Fragment } from 'react';
import { DatepickerProps } from '../utils/commonTypes';
import React from 'react';
import {
DatepickerProps,
OnMonthViewChange,
} from '../utils/commonTypes';

export interface DatepickerBackBtnsProps extends DatepickerProps {
calendars: Calendar[];
getBackProps: (data: GetBackForwardPropsOptions) => Record<string, any>;
onMonthViewChange?: OnMonthViewChange;
}

const DefaultBtnStyle: ButtonProps = {
Expand All @@ -16,60 +20,77 @@ const DefaultBtnStyle: ButtonProps = {
export const DatepickerBackBtns: React.FC<DatepickerBackBtnsProps> = (
props
) => {
const { calendars, getBackProps } = props;
const { calendars, getBackProps, onMonthViewChange } = props;
const customBtnProps = props.propsConfigs?.dateNavBtnProps;

const backProps = getBackProps({ calendars });
const backPropsWithOffset = getBackProps({ calendars, offset: 12 });
return (
<Fragment>
<>
<Button
{...getBackProps({
calendars,
offset: 12,
})}
{...backPropsWithOffset}
{...DefaultBtnStyle}
{...customBtnProps}
onClick={(e) => {
onMonthViewChange && onMonthViewChange({ calendars, offset: -12 })
backPropsWithOffset.onClick(e)
}}
>
{'<<'}
</Button>
<Button
{...getBackProps({ calendars })}
{...backProps}
{...DefaultBtnStyle}
{...customBtnProps}
onClick={(e) => {
onMonthViewChange && onMonthViewChange({ calendars, offset: -1 })
backProps.onClick(e)
}}
>
{'<'}
</Button>
</Fragment>
</>
);
};

export interface DatepickerForwardBtnsProps extends DatepickerProps {
calendars: Calendar[];
getForwardProps: (data: GetBackForwardPropsOptions) => Record<string, any>;
onMonthViewChange?: OnMonthViewChange;
}

export const DatepickerForwardBtns: React.FC<DatepickerForwardBtnsProps> = (
props
) => {
const { calendars, getForwardProps } = props;
const { calendars, getForwardProps, onMonthViewChange } = props;
const customBtnProps = props.propsConfigs?.dateNavBtnProps;

const forwardProps = getForwardProps({ calendars });
const forwardPropsWithOffset = getForwardProps({ calendars, offset: 12 });
return (
<Fragment>
<>
<Button
{...getForwardProps({ calendars })}
{...forwardProps}
{...DefaultBtnStyle}
{...customBtnProps}
onClick={(e) => {
onMonthViewChange && onMonthViewChange({ calendars, offset: 1 })
forwardProps.onClick(e)
}}
>
{'>'}
</Button>
<Button
{...getForwardProps({
calendars,
offset: 12,
})}
{...forwardPropsWithOffset}
{...DefaultBtnStyle}
{...customBtnProps}
onClick={(e) => {
onMonthViewChange && onMonthViewChange({ calendars, offset: 12 })
forwardPropsWithOffset.onClick(e)
}}
>
{'>>'}
</Button>
</Fragment>
</>
);
};
22 changes: 20 additions & 2 deletions src/components/dayOfMonth.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { Button } from '@chakra-ui/react';
import { DateObj, RenderProps } from 'dayzed';
import React, { useMemo } from 'react';
import { DatepickerProps, DayOfMonthBtnStyleProps } from '../utils/commonTypes';
import {
CustomDateButton,
DatepickerProps,
DayOfMonthBtnStyleProps,
} from '../utils/commonTypes';

interface DayOfMonthProps extends DatepickerProps {
renderProps: RenderProps;
isInRange?: boolean | null;
dateObj: DateObj;
onMouseEnter?: React.MouseEventHandler<HTMLButtonElement> | undefined;
customDateButton?: CustomDateButton;
}

const halfGap = 0.125; //default Chakra-gap-space-1 is 0.25rem
Expand All @@ -18,6 +23,7 @@ export const DayOfMonth: React.FC<DayOfMonthProps> = ({
isInRange,
renderProps,
onMouseEnter,
customDateButton,
}) => {
const { date, selected, selectable, today } = dateObj;
const { getDateProps } = renderProps;
Expand Down Expand Up @@ -77,7 +83,19 @@ export const DayOfMonth: React.FC<DayOfMonthProps> = ({
]
);

return (
return customDateButton ? (
customDateButton(
{ ...dateObj, isInRange },
{
dateProps: getDateProps({
dateObj,
disabled: !selectable,
onMouseEnter,
}),
btnProps: styleBtnProps,
}
)
) : (
<Button
{...getDateProps({
dateObj,
Expand Down
8 changes: 7 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
export type { DatepickerConfigs } from './utils/commonTypes';
export type {
DatepickerConfigs,
CustomDateButton,
OnMonthViewChange,
DateObjExtended,
CustomDateButtonProps,
} from './utils/commonTypes';
export * from './utils/calanderUtils';
export * from './single';
export * from './range';
23 changes: 20 additions & 3 deletions src/single.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,19 @@ import {
} from '@chakra-ui/react';
import { format } from 'date-fns';
import FocusLock from 'react-focus-lock';
import { Month_Names_Short, Weekday_Names_Short } from './utils/calanderUtils';
import {
Month_Names_Short,
Weekday_Names_Short,
DATE_FORMAT,
} from './utils/calanderUtils';
import { CalendarPanel } from './components/calendarPanel';
import {
CalendarConfigs,
DatepickerConfigs,
DatepickerProps,
OnDateSelected,
CustomDateButton,
OnMonthViewChange,
} from './utils/commonTypes';

export interface SingleDatepickerProps extends DatepickerProps {
Expand All @@ -28,10 +34,13 @@ export interface SingleDatepickerProps extends DatepickerProps {
id?: string;
name?: string;
usePortal?: boolean;
onMonthViewChange?: OnMonthViewChange;
customDateButton?: CustomDateButton;
onPopoverOpen?: () => void;
}

const DefaultConfigs: CalendarConfigs = {
dateFormat: 'yyyy-MM-dd',
dateFormat: DATE_FORMAT,
monthNames: Month_Names_Short,
dayNames: Weekday_Names_Short,
firstDayOfWeek: 0,
Expand All @@ -52,6 +61,9 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = ({
id,
minDate,
maxDate,
onMonthViewChange,
customDateButton,
onPopoverOpen,
} = props;

const [dateInView, setDateInView] = useState(selectedDate);
Expand Down Expand Up @@ -89,7 +101,10 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = ({
placement="bottom-start"
variant="responsive"
isOpen={isOpen}
onOpen={onOpen}
onOpen={() => {
onPopoverOpen && onPopoverOpen();
onOpen();
}}
onClose={onPopoverClose}
isLazy
>
Expand Down Expand Up @@ -133,6 +148,8 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = ({
}}
configs={calendarConfigs}
propsConfigs={propsConfigs}
onMonthViewChange={onMonthViewChange}
customDateButton={customDateButton}
/>
</FocusLock>
</PopoverBody>
Expand Down
2 changes: 2 additions & 0 deletions src/utils/calanderUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ export const Weekday_Names_Short = [
'Fri',
'Sat',
];

export const DATE_FORMAT: string = 'yyyy-MM-dd';
25 changes: 24 additions & 1 deletion src/utils/commonTypes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ButtonProps } from '@chakra-ui/button';
import { InputProps, PopoverBodyProps } from '@chakra-ui/react';
import { PopoverContentProps } from '@chakra-ui/react';
import { DateObj } from 'dayzed';
import { DateObj, Calendar } from 'dayzed';
import { ReactElement } from 'react';

export type OnDateSelected = (
selectedDate: DateObj,
Expand Down Expand Up @@ -46,3 +47,25 @@ export interface CalendarConfigs {
dayNames: string[];
firstDayOfWeek: 0 | 1 | 2 | 3 | 4 | 5 | 6;
}

export type DateObjExtended = DateObj & {
isInRange: boolean | null | undefined;
};

export type CustomDateButtonProps = {
dateProps: Record<string, unknown>;
btnProps: DayOfMonthBtnStyleProps;
};

export type OnMonthViewChange = ({
calendars,
offset,
}: {
calendars: Calendar[];
offset: number;
}) => void;

export type CustomDateButton = (
dateObj: DateObjExtended,
{ dateProps, btnProps }: CustomDateButtonProps
) => ReactElement;