diff --git a/docs/stories/bExternalFilters.stories.tsx b/docs/stories/bExternalFilters.stories.tsx index 43d60da..4e930c5 100644 --- a/docs/stories/bExternalFilters.stories.tsx +++ b/docs/stories/bExternalFilters.stories.tsx @@ -66,7 +66,6 @@ export const Primary = () => { setBirthday(null); }} columns={(col) => [ - // col((x) => x.avatar, { header: 'Avatar', renderCell: (avatar) => , diff --git a/docs/stories/fDatePicker.stories.tsx b/docs/stories/fDatePicker.stories.tsx new file mode 100644 index 0000000..1708b28 --- /dev/null +++ b/docs/stories/fDatePicker.stories.tsx @@ -0,0 +1,41 @@ +import { useState } from 'react'; +import { DatePicker, DatePickerProps, DateRange } from '../../src'; + +const today = new Date(); +const nextWeek = new Date(); +nextWeek.setDate(today.getDate() + 7); + +export default { + title: 'Date Picker', + component: DatePicker, + argTypes: { + value: { control: 'date' }, + onChange: { action: 'changed' }, + blockedRanges: { + control: 'object', + }, + }, +}; + +export const Primary = (args: DatePickerProps) => { + const [date, setDate] = useState(null); + + return ( + { + if (v instanceof Date) { + setDate({ min: v, max: v }); + } else { + setDate(v); + } + args.onChange(v); + }} + /> + ); +}; + +Primary.args = { + value: new Date(), +}; diff --git a/src/components/datePicker.tsx b/src/components/datePicker.tsx index 57915d8..efe396c 100644 --- a/src/components/datePicker.tsx +++ b/src/components/datePicker.tsx @@ -14,6 +14,7 @@ import { gray } from '../theme/defaultTheme/defaultClasses'; import { useCssVariables } from '../theme/useCssVariables'; import { DateInput } from './dateInput'; import { Text } from './text'; +import { Interpolation, Theme } from '@emotion/react'; export type DateRange = { min: Date; max: Date }; @@ -45,6 +46,8 @@ export type DatePickerProps = { /** Show buttons to quickly select suggested dates or date ranges */ quickOptions?: DatePickerQuickOption[]; /** Minimum selectable date */ + /** Date ranges that are visually marked as blocked */ + blockedRanges?: DateRange[]; minDate?: Date; /** Maximum selectable date */ maxDate?: Date; @@ -209,6 +212,7 @@ export function DatePicker(props: DatePickerProps) { minDate, maxDate, showCalendarWeek, + blockedRanges = [], } = defaults(props, context); function onChange(value: Date | DateRange | null) { @@ -228,6 +232,65 @@ export function DatePicker(props: DatePickerProps) { const IconButton = useTheme((t) => t.components.IconButton); const ChevronRight = useTheme((t) => t.icons.ChevronRight); const cssVariables = useCssVariables(); + function getDayCssStyles({ + disabled, + prevMonth, + nextMonth, + today, + blocked, + selected, + preSelected, + }: { + disabled?: boolean; + prevMonth?: boolean; + nextMonth?: boolean; + today?: boolean; + blocked?: boolean; + selected?: boolean; + preSelected?: boolean; + }): Interpolation { + return [ + { + padding: 10, + border: 'none', + background: 'transparent', + cursor: disabled ? undefined : 'pointer', + font: 'inherit', + }, + (prevMonth || nextMonth) && { + color: gray, + }, + today && { + outline: '1px solid var(--secondaryMain)', + }, + blocked && { + background: 'var(--blockedMain)', + color: 'var(--blockedContrastText)', + }, + selected && { + background: 'var(--primaryMain)', + color: 'var(--primaryContrastText)', + }, + blocked && + selected && { + position: 'relative', + '::before': { + content: '""', + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + background: 'var(--blockedMain)', + clipPath: 'polygon(0 0, 0 50%, 50% 0)', + }, + }, + preSelected && { + background: 'var(--primaryLight)', + color: 'var(--primaryContrastText)', + }, + ]; + } const mountTime = useMemo(() => new Date(), []); const [dateInView, setDateInView] = useState(defaultDateInView ?? mountTime); @@ -252,6 +315,7 @@ export function DatePicker(props: DatePickerProps) {