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) {