Skip to content

Commit

Permalink
feat(calendar/datepicker): add shouldSetDateOnTodayButtonClick prop…
Browse files Browse the repository at this point in the history
… to select date on today click (#557)

* feat: allow selection of today's date when clicked on calendar

* feat(storybook): move calendar and rangecalendar into top level

* feat: allow datepicker components to select date on today btn click

* fix: be explicit with useFormControlProps

was passing in extra props for some reason >:(
  • Loading branch information
karrui authored Nov 21, 2023
1 parent 34c11ee commit b7f4a8a
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 5 deletions.
13 changes: 12 additions & 1 deletion react/src/Calendar/Calendar.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useControllableState } from '@chakra-ui/react'
import { Meta, StoryFn } from '@storybook/react'
import { userEvent, within } from '@storybook/testing-library'
import { isWeekend } from 'date-fns'

import { mockDateDecorator } from '~/utils/storybook'

import { Calendar, CalendarProps } from './Calendar'

export default {
title: 'Components/Calendar/Calendar',
title: 'Components/Calendar',
component: Calendar,
tags: ['autodocs'],
decorators: [mockDateDecorator],
Expand Down Expand Up @@ -39,6 +40,16 @@ CalendarWithValue.args = {
value: new Date('2001-01-01'),
}

export const SelectTodayWhenTodayButtonClicked = CalendarOnlyTemplate.bind({})
SelectTodayWhenTodayButtonClicked.args = {
shouldSetDateOnTodayButtonClick: true,
}
SelectTodayWhenTodayButtonClicked.play = async ({ canvasElement }) => {
const canvas = within(canvasElement)
const todayButton = canvas.getByText('Today')
userEvent.click(todayButton)
}

export const HideOutsideDays = CalendarOnlyTemplate.bind({})
HideOutsideDays.args = {
showOutsideDays: false,
Expand Down
13 changes: 12 additions & 1 deletion react/src/Calendar/CalendarBase/CalendarContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
differenceInCalendarMonths,
isFirstDayOfMonth,
isSameDay,
startOfDay,
} from 'date-fns'
import { Props as DayzedProps, RenderProps, useDayzed } from 'dayzed'
import { inRange } from 'lodash'
Expand Down Expand Up @@ -85,6 +86,11 @@ type PassthroughProps = {
* @default false
*/
isCalendarFixedHeight?: boolean
/**
* Whether clicking the Today button should set the date on the input to today.
* @default false
*/
shouldSetDateOnTodayButtonClick?: boolean
}

// Removed - and _ from alphabets for simpler classnames
Expand Down Expand Up @@ -163,6 +169,7 @@ const useProvideCalendar = ({
defaultFocusedDate,
showOutsideDays,
isCalendarFixedHeight,
shouldSetDateOnTodayButtonClick,
}: UseProvideCalendarProps) => {
const isMobile = useIsMobile({ ssr })
// Ensure that calculations are always made based on date of initial render,
Expand Down Expand Up @@ -216,7 +223,11 @@ const useProvideCalendar = ({
) as HTMLButtonElement | null
elementToFocus?.focus()
})
}, [classNameId])

if (shouldSetDateOnTodayButtonClick) {
onSelectDate?.(startOfDay(today))
}
}, [classNameId, onSelectDate, shouldSetDateOnTodayButtonClick])

const updateMonthYear = useCallback(
(newDate: Date) => {
Expand Down
1 change: 1 addition & 0 deletions react/src/Calendar/CalendarBase/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type CalendarBaseProps = Pick<
| 'size'
| 'defaultFocusedDate'
| 'isCalendarFixedHeight'
| 'shouldSetDateOnTodayButtonClick'
> & {
/**
* Whether to show or hide the button to focus on Today.
Expand Down
15 changes: 14 additions & 1 deletion react/src/Calendar/RangeCalendar.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useControllableState } from '@chakra-ui/react'
import { Meta, StoryFn } from '@storybook/react'
import { userEvent, within } from '@storybook/testing-library'
import { isWeekend } from 'date-fns'

import { mockDateDecorator } from '~/utils/storybook'

import { RangeCalendar, RangeCalendarProps } from './RangeCalendar'

export default {
title: 'Components/Calendar/RangeCalendar',
title: 'Components/RangeCalendar',
component: RangeCalendar,
tags: ['autodocs'],
decorators: [mockDateDecorator],
Expand Down Expand Up @@ -43,6 +44,18 @@ RangeCalendarWithValue.args = {
value: [new Date('2001-01-01'), null],
}

export const SelectTodayWhenTodayButtonClicked = RangeCalendarOnlyTemplate.bind(
{},
)
SelectTodayWhenTodayButtonClicked.args = {
shouldSetDateOnTodayButtonClick: true,
}
SelectTodayWhenTodayButtonClicked.play = async ({ canvasElement }) => {
const canvas = within(canvasElement)
const todayButton = canvas.getByText('Today')
userEvent.click(todayButton)
}

export const RangeCalendarWithRange = RangeCalendarOnlyTemplate.bind({})
RangeCalendarWithRange.args = {
value: [new Date('2001-01-01'), new Date('2001-02-02')],
Expand Down
6 changes: 6 additions & 0 deletions react/src/DatePicker/DatePicker.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Meta, StoryFn } from '@storybook/react'
import { userEvent, within } from '@storybook/testing-library'

import { getMobileViewParameters, mockDateDecorator } from '~/utils/storybook'

Expand All @@ -22,6 +23,11 @@ DatePickerWithValue.args = {
defaultValue: new Date('2001-01-01'),
}

export const SelectTodayWhenTodayButtonClicked = Template.bind({})
SelectTodayWhenTodayButtonClicked.args = {
shouldSetDateOnTodayButtonClick: true,
}

export const DatePickerInvalid = Template.bind({})
DatePickerInvalid.args = {
isInvalid: true,
Expand Down
5 changes: 4 additions & 1 deletion react/src/DatePicker/DatePickerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ interface DatePickerContextReturn {
| 'defaultFocusedDate'
| 'showOutsideDays'
| 'showTodayButton'
| 'shouldSetDateOnTodayButtonClick'
>
inputPattern?: string
}
Expand Down Expand Up @@ -155,7 +156,9 @@ const useProvideDatePicker = ({
isDisabled: isDisabledProp,
isReadOnly: isReadOnlyProp,
isRequired: isRequiredProp,
...props,
'aria-describedby': props['aria-describedby'],
onFocus: props.onFocus,
id: props.id,
})

const handleInputBlur: FocusEventHandler<HTMLInputElement> = useCallback(
Expand Down
1 change: 1 addition & 0 deletions react/src/DatePicker/utils/pickCalendarProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export const pickCalendarProps = (props: DatePickerProps) => {
'defaultFocusedDate',
'showOutsideDays',
'showTodayButton',
'shouldSetDateOnTodayButtonClick',
)
}
4 changes: 4 additions & 0 deletions react/src/DateRangePicker/DateRangePicker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export const DateRangePickerWithValue = Template.bind({})
DateRangePickerWithValue.args = {
defaultValue: [new Date('2001-01-01'), null],
}
export const SelectTodayWhenTodayButtonClicked = Template.bind({})
SelectTodayWhenTodayButtonClicked.args = {
shouldSetDateOnTodayButtonClick: true,
}

export const DateRangePickerDisallowManualInput = Template.bind({})
DateRangePickerDisallowManualInput.args = {
Expand Down
5 changes: 4 additions & 1 deletion react/src/DateRangePicker/DateRangePickerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ interface DateRangePickerContextReturn {
| 'isDateUnavailable'
| 'defaultFocusedDate'
| 'showTodayButton'
| 'shouldSetDateOnTodayButtonClick'
>
inputPattern?: string
}
Expand Down Expand Up @@ -195,7 +196,9 @@ const useProvideDateRangePicker = ({
isDisabled: isDisabledProp,
isReadOnly: isReadOnlyProp,
isRequired: isRequiredProp,
...props,
'aria-describedby': props['aria-describedby'],
onFocus: props.onFocus,
id: props.id,
})

const handleInputBlur: FocusEventHandler<HTMLInputElement> = useCallback(
Expand Down

0 comments on commit b7f4a8a

Please sign in to comment.