Skip to content

Commit

Permalink
DateField interface exposes JS Date
Browse files Browse the repository at this point in the history
  • Loading branch information
veej committed Sep 25, 2023
1 parent 6ad227e commit cca563a
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 56 deletions.
40 changes: 24 additions & 16 deletions packages/bento-design-system/src/DateField/DateField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useDatePicker, useDateRangePicker } from "@react-aria/datepicker";
import { useDatePickerState, useDateRangePickerState } from "@react-stately/datepicker";
import { useRef } from "react";
import { FieldProps } from "../Field/FieldProps";
import { CalendarDate, DateValue } from "@internationalized/date";
import { CalendarDate, DateValue, getLocalTimeZone } from "@internationalized/date";
import { Input } from "./Input";
import { Calendar } from "./Calendar";
import { Box } from "../Box/Box";
Expand All @@ -18,27 +18,36 @@ export type ShortcutProps<Value> = {
};
type SingleDateFieldProps = {
type?: "single";
shortcuts?: ShortcutProps<CalendarDate>[];
} & FieldProps<CalendarDate | null>;
shortcuts?: ShortcutProps<Date>[];
} & FieldProps<Date | null>;
type RangeDateFieldProps = {
type: "range";
shortcuts?: ShortcutProps<[CalendarDate, CalendarDate]>[];
} & FieldProps<[CalendarDate, CalendarDate] | null>;
shortcuts?: ShortcutProps<[Date, Date]>[];
} & FieldProps<[Date, Date] | null>;
type Props = (SingleDateFieldProps | RangeDateFieldProps) & {
minDate?: CalendarDate;
maxDate?: CalendarDate;
minDate?: Date;
maxDate?: Date;
shouldDisableDate?: (date: DateValue) => boolean;
readOnly?: boolean;
};

function dateToCalendarDate(date: Date): CalendarDate {
if (!date) return date;
return new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate());
}

function SingleDateField({ disabled, readOnly, ...props }: Extract<Props, { type?: "single" }>) {
const internalProps = {
...props,
value: props.value ? dateToCalendarDate(props.value) : props.value,
onChange: (date: CalendarDate | null) => {
props.onChange(date?.toDate(getLocalTimeZone()) ?? null);
},
isDisabled: disabled,
isReadOnly: readOnly,
validationState: props.issues ? "invalid" : "valid",
minValue: props.minDate,
maxValue: props.maxDate,
minValue: props.minDate ? dateToCalendarDate(props.minDate) : undefined,
maxValue: props.maxDate ? dateToCalendarDate(props.maxDate) : undefined,
isDateUnavailable: props.shouldDisableDate,
shouldForceLeadingZeros: true,
} as const;
Expand Down Expand Up @@ -85,7 +94,6 @@ function SingleDateField({ disabled, readOnly, ...props }: Extract<Props, { type
type="single"
fieldProps={fieldProps}
buttonProps={buttonProps}
ref={ref}
isCalendarOpen={state.isOpen}
/>
</Box>
Expand All @@ -108,17 +116,18 @@ function RangeDateField({ disabled, readOnly, ...props }: Extract<Props, { type:
isDisabled: disabled,
isReadOnly: readOnly,
validationState: props.issues ? "invalid" : "valid",
minValue: props.minDate,
maxValue: props.maxDate,
minValue: props.minDate ? dateToCalendarDate(props.minDate) : undefined,
maxValue: props.maxDate ? dateToCalendarDate(props.maxDate) : undefined,
isDateUnavailable: props.shouldDisableDate,
value: props.value
? {
start: props.value[0],
end: props.value[1],
start: dateToCalendarDate(props.value[0]),
end: dateToCalendarDate(props.value[1]),
}
: props.value,
onChange: (range: RangeValue<CalendarDate>) => {
props.onChange([range.start, range.end]);
const localTimeZone = getLocalTimeZone();
props.onChange([range.start.toDate(localTimeZone), range.end.toDate(localTimeZone)]);
},
} as const;
const state = useDateRangePickerState(internalProps);
Expand Down Expand Up @@ -165,7 +174,6 @@ function RangeDateField({ disabled, readOnly, ...props }: Extract<Props, { type:
type="range"
fieldProps={{ start: startFieldProps, end: endFieldProps }}
buttonProps={buttonProps}
ref={ref}
isCalendarOpen={state.isOpen}
/>
</Box>
Expand Down
3 changes: 1 addition & 2 deletions packages/bento-design-system/src/DateField/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
DateSegment as DateSegmentType,
useDateFieldState,
} from "@react-stately/datepicker";
import { RefObject, useRef } from "react";
import { useRef } from "react";
import { Box } from "../Box/Box";
import { inputRecipe } from "../Field/Field.css";
import { bodyRecipe } from "../Typography/Body/Body.css";
Expand Down Expand Up @@ -36,7 +36,6 @@ type Props = (
) & {
buttonProps: AriaButtonProps<"button">;
isCalendarOpen: boolean;
ref: RefObject<HTMLInputElement>;
};

function DateSegment({ segment, state }: { segment: DateSegmentType; state: DateFieldState }) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,23 @@
import { DateField, DateFieldProps } from "../../src/DateField/DateField";
import { Meta, StoryObj } from "@storybook/react";
import { useState } from "react";
import { DateField, DateFieldProps } from "..";
import {
CalendarDate,
getLocalTimeZone,
today as _today,
getDayOfWeek,
startOfWeek,
endOfWeek,
startOfMonth,
endOfMonth,
startOfYear,
endOfYear,
} from "@internationalized/date";
import isChromatic from "chromatic";
addMonths,
startOfToday,
addWeeks,
addDays,
} from "date-fns";
import { screen, waitFor } from "@storybook/testing-library";

const ControlledDateField = (props: Omit<DateFieldProps, "onChange">) => {
const [value, setValue] = useState<CalendarDate | null>(props.value);
return (
<DateField
{...props}
value={value}
onChange={(value) => {
setValue(value);
}}
/>
);
};
import isChromatic from "chromatic/isChromatic";
import { Meta, StoryObj } from "@storybook/react";

const meta = {
component: ControlledDateField,
component: DateField,
args: {
type: "single",
name: "date",
label: "Date",
assistiveText: "This is your favorite date",
Expand All @@ -44,40 +29,45 @@ export default meta;

type Story = StoryObj<typeof meta>;

const today = _today(getLocalTimeZone());
const today = startOfToday();
const value = new Date(2022, 1, 4);

export const SingleDate = {} satisfies Story;
export const SingleDate = {
value,
} satisfies Story;

export const Disabled = {
args: {
value: null,
disabled: true,
},
} satisfies Story;

export const ReadOnly = {
args: {
value: new CalendarDate(2022, 2, 4),
value,
readOnly: true,
},
} satisfies Story;

const inOneWeek = today.add({ weeks: 1 });
const inOneWeek = addWeeks(today, 1);
export const SingleWithMinMax = {
args: {
value: null,
minDate: today,
maxDate: inOneWeek,
assistiveText: "You can select a date between today and one week from now",
},
} satisfies Story;

const inOneMonth = today.add({ months: 1 });
const inOneMonth = addMonths(today, 1);
export const SingleWithShortcuts = {
args: {
value: null,
shortcuts: [
{
label: "Today",
value: today,
value: new Date(),
},
{
label: "In a week",
Expand All @@ -92,18 +82,16 @@ export const SingleWithShortcuts = {
} satisfies Story;
export const DisabledDates = {
args: {
shouldDisableDate: (date: CalendarDate) => getDayOfWeek(date, "en-EN") === 0,
shouldDisableDate: (date: Date) => date.getDay() === 0,
},
};
export const CalendarOpen = {
args: {
value: new CalendarDate(2022, 2, 4),
value,
},
play: async () => {
const button = screen.getByRole("button");
await waitFor(async () => {
await button.click();
});
const input = screen.getByRole("textbox");
await waitFor(() => input.click());
// wait a bit to see if it solves Chromatic snapshot flakiness
await new Promise((resolve) => setTimeout(resolve, 1000));
},
Expand All @@ -120,10 +108,11 @@ export const CalendarOpen = {

export const Range = {
args: {
value: [today, today.add({ days: 2 })],
value: [value, addDays(value, 2)],
type: "range",
},
} satisfies Story;

export const RangeWithMinMax = {
args: {
value: [null, null],
Expand All @@ -133,14 +122,15 @@ export const RangeWithMinMax = {
assistiveText: "You can select a date between today and one month from now",
},
} satisfies Story;

export const RangeWithShortcuts = {
args: {
value: [null, null],
type: "range",
shortcuts: [
{
label: "This Week",
value: [startOfWeek(today, "en-EN"), endOfWeek(today, "en-EN")],
value: [startOfWeek(today), endOfWeek(today)],
},
{
label: "This Month",
Expand Down

0 comments on commit cca563a

Please sign in to comment.