-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cbdcfba
commit 915d33c
Showing
4 changed files
with
147 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 42 additions & 33 deletions
75
packages/opub-ui/src/components/DatePicker/DatePicker.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,58 @@ | ||
import { DatePicker } from './DatePicker'; | ||
import { DateRangePicker } from './DateRangePicker'; | ||
import { getLocalTimeZone, today, parseDate } from '@internationalized/date'; | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
import { DatePicker } from './DatePicker' | ||
import { DateRangePicker } from './DateRangePicker' | ||
import { MonthPicker } from './MonthPicker' | ||
import { getLocalTimeZone, today, parseDate } from '@internationalized/date' | ||
import { Meta, StoryObj } from '@storybook/react' | ||
|
||
/** | ||
* A date picker combines a DateField and a Calendar popover to allow users to enter or select a date and time value. | ||
* | ||
* Reference: https://react-spectrum.adobe.com/react-aria/useDatePicker.html | ||
*/ | ||
const meta = { | ||
title: 'Components/DatePicker', | ||
component: DatePicker, | ||
} satisfies Meta<typeof DatePicker>; | ||
title: 'Components/DatePicker', | ||
component: DatePicker, | ||
} satisfies Meta<typeof DatePicker> | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
export default meta | ||
type Story = StoryObj<typeof meta> | ||
|
||
const metaRange = { | ||
component: DateRangePicker, | ||
} satisfies Meta<typeof DateRangePicker>; | ||
type StoryRange = StoryObj<typeof metaRange>; | ||
component: DateRangePicker, | ||
} satisfies Meta<typeof DateRangePicker> | ||
type StoryRange = StoryObj<typeof metaRange> | ||
|
||
export const Default: Story = { | ||
args: { | ||
label: 'Date Picker', | ||
}, | ||
}; | ||
args: { | ||
label: 'Date Picker', | ||
}, | ||
} | ||
|
||
export const Range: StoryRange = { | ||
render: ({ ...args }) => <DateRangePicker {...args} />, | ||
args: { | ||
label: 'Date Range Picker', | ||
onChange: (val) => console.log(val), | ||
}, | ||
}; | ||
render: ({ ...args }) => <DateRangePicker {...args} />, | ||
args: { | ||
label: 'Date Range Picker', | ||
onChange: (val) => console.log(val), | ||
}, | ||
} | ||
|
||
export const Month: Story = { | ||
render: ({ ...args }) => <MonthPicker {...args} />, | ||
args: { | ||
label: 'Month Picker', | ||
onChange: (val) => console.log(val), | ||
}, | ||
} | ||
|
||
export const DisabledDates: StoryRange = { | ||
...Range, | ||
args: { | ||
label: 'Date Picker', | ||
minValue: today(getLocalTimeZone()), | ||
defaultValue: { | ||
start: parseDate('2022-02-03'), | ||
end: parseDate('2022-05-03'), | ||
}, | ||
errorMessage: 'Date must be in the future', | ||
}, | ||
}; | ||
...Range, | ||
args: { | ||
label: 'Date Picker', | ||
minValue: today(getLocalTimeZone()), | ||
defaultValue: { | ||
start: parseDate('2022-02-03'), | ||
end: parseDate('2022-05-03'), | ||
}, | ||
errorMessage: 'Date must be in the future', | ||
}, | ||
} |
102 changes: 102 additions & 0 deletions
102
packages/opub-ui/src/components/DatePicker/MonthPicker.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
'use client' | ||
|
||
import { YearCalendar } from '../Calendar/YearCalendar' | ||
import { DateField } from '../DateField' | ||
import { IconButton } from '../IconButton' | ||
import inputStyles from '../Input/Input.module.scss' | ||
import { Labelled, LabelledProps } from '../Labelled' | ||
import { Popover } from '../Popover' | ||
import styles from './DatePicker.module.scss' | ||
import { DateValue } from '@react-types/calendar' | ||
import { IconCalendar } from '@tabler/icons-react' | ||
import cx from 'classnames' | ||
import React from 'react' | ||
import { AriaDatePickerProps, useDatePicker } from 'react-aria' | ||
import { DatePickerState, useDatePickerState } from 'react-stately' | ||
|
||
export type DatePickerProps = { | ||
/** Label for the field */ | ||
label: string | ||
/** Error to display beneath the label */ | ||
error?: any | ||
/** Adds an action to the label */ | ||
labelAction?: LabelledProps['action'] | ||
/** Visually hide the label */ | ||
labelHidden?: boolean | ||
/** Visual required indicator, add an asterisk to label */ | ||
requiredIndicator?: boolean | ||
/** Additional text to aide in use */ | ||
helpText?: React.ReactNode | ||
} & (DatePickerState | AriaDatePickerProps<DateValue>) | ||
|
||
const MonthPicker = React.forwardRef( | ||
( | ||
{ | ||
error, | ||
labelAction, | ||
labelHidden, | ||
helpText, | ||
requiredIndicator, | ||
...props | ||
}: DatePickerProps, | ||
ref: any | ||
) => { | ||
let state = useDatePickerState(props) | ||
|
||
let { labelProps, fieldProps, buttonProps, dialogProps, calendarProps } = | ||
useDatePicker(props, state, ref) | ||
const themeClass = cx(styles.DatePicker) | ||
|
||
const { | ||
onPress: onPressPrev, | ||
isDisabled: disabledPrev, | ||
...othersProps | ||
} = buttonProps | ||
|
||
return ( | ||
<div className={`opub-MonthPicker ${themeClass}`}> | ||
<Labelled | ||
label={props.label} | ||
{...labelProps} | ||
error={error} | ||
action={labelAction} | ||
labelHidden={labelHidden} | ||
helpText={helpText} | ||
requiredIndicator={requiredIndicator} | ||
> | ||
<div ref={ref} className={styles.Wrapper}> | ||
<DateField | ||
{...fieldProps} | ||
errorMessage={error} | ||
isPicker | ||
granularity="month" | ||
/> | ||
<Popover | ||
onOpenChange={() => | ||
!state.isOpen ? state.open() : state.close() | ||
} | ||
open={state.isOpen} | ||
{...dialogProps} | ||
> | ||
<Popover.Trigger> | ||
<IconButton | ||
{...othersProps} | ||
icon={IconCalendar} | ||
withTooltip={false} | ||
> | ||
trigger calendar | ||
</IconButton> | ||
</Popover.Trigger> | ||
<Popover.Content> | ||
<YearCalendar {...calendarProps} /> | ||
</Popover.Content> | ||
</Popover> | ||
<div className={inputStyles.Backdrop} /> | ||
</div> | ||
</Labelled> | ||
</div> | ||
) | ||
} | ||
) | ||
|
||
export { MonthPicker } |