Skip to content

Commit

Permalink
DatePicker and Calendar updates (#4143)
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-tate authored Oct 4, 2024
1 parent d4486bf commit 3a9d518
Show file tree
Hide file tree
Showing 67 changed files with 2,023 additions and 1,335 deletions.
29 changes: 29 additions & 0 deletions .changeset/pretty-teachers-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
"@salt-ds/lab": patch
---

DatePicker and Calendar API improvements

- `CalendarCarousel` has been renamed to `CarouselDateGrid` so it's more obvious of the content
- `Calendar` previously used `children` to define the `CalendarNavigation`.
We have now changed that so the `children` defines `CalendarNavigation`, `CalendarWeekHeader` and `CalendarDateGrid`
This enables more flexibility in both layout and configuration of the `Calendar` elements.
A typical Calendar will now look like this,

```
<Calendar selectionVariant="single" hideOutOfRangeDates>
<CalendarNavigation />
<CalendarWeekHeader />
<CalendarDateGrid />
</Calendar>
```

`CalendarNavigation` - provides year/month dropdowns and forward/back controls for the visible month.
`CalendarWeekHeader` - provides a header for `CalendarDateGrid` indicating the day of the week.
`CalendarDateGrid` - provides a grid of buttons that represent the days from a calendar month.

- cleaned up selection API, removed `select`, use `setSelectedDate` instead
- fix issues with `Calendar` offset selection
- updated examples, more consistent helper text, error text to match spec
- test improvements to create a known state for tests and avoid failures based on locale differences
- cleaned up Storybook imports in e2e tests
15 changes: 5 additions & 10 deletions packages/lab/src/__tests__/__e2e__/calendar/Calendar.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,19 @@ import * as calendarStories from "@stories/calendar/calendar.stories";
import { composeStories } from "@storybook/react";
import { checkAccessibility } from "../../../../../../cypress/tests/checkAccessibility";

const composedStories = composeStories(calendarStories);
const {
Single,
CustomDayRender,
CustomHeader,
HideYearDropdown,
MinMaxDate,
TodayButton,
TwinCalendars,
WithLocale,
} = composeStories(calendarStories);
} = composedStories;

describe("GIVEN a Calendar", () => {
// TODO design a compliant Header example
const {
default: _ignored,
CustomHeader: _CustomHeader,
...allAxeStories
} = calendarStories;
checkAccessibility(allAxeStories);
checkAccessibility(composedStories);

const testDate = parseDate("2022-02-03");
const testTimeZone = "Europe/London";
Expand Down Expand Up @@ -351,7 +346,7 @@ describe("GIVEN a Calendar", () => {

it("SHOULD render custom headers", () => {
cy.mount(
<CustomHeader defaultVisibleMonth={testDate} locale={testLocale} />,
<TodayButton defaultVisibleMonth={testDate} locale={testLocale} />,
);
// Simulate clicking the "Today" button
cy.findByRole("button", { name: /Today/i }).click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@ import {
today,
} from "@internationalized/date";
import * as datePickerStories from "@stories/date-picker/date-picker.stories";
import {
RangeControlled,
RangeWithConfirmation,
RangeWithCustomPanel,
RangeWithFormField,
RangeWithMinMaxDate,
} from "@stories/date-picker/date-picker.stories";
import { composeStories } from "@storybook/react";
import React from "react";
import { formatDate } from "../../../calendar";
Expand All @@ -25,7 +18,14 @@ import {
} from "../../../date-picker";

const composedStories = composeStories(datePickerStories);
const { Range } = composedStories;
const {
Range,
RangeControlled,
RangeWithConfirmation,
RangeWithCustomPanel,
RangeWithFormField,
RangeWithMinMaxDate,
} = composedStories;

describe("GIVEN a DatePicker where selectionVariant is range", () => {
const testLocale = "en-GB";
Expand Down Expand Up @@ -61,11 +61,19 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
};

it("SHOULD only be able to select a date between min/max", () => {
const selectedDateChangeSpy = cy.stub().as("selectedDateChangeSpy");
cy.mount(
<RangeWithMinMaxDate selectionVariant={"range"} locale={testLocale} />,
<RangeWithMinMaxDate
defaultSelectedDate={initialRangeDate}
onSelectedDateChange={selectedDateChangeSpy}
selectionVariant={"range"}
locale={testLocale}
/>,
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Verify that dates outside the min/max range are disabled
cy.findByRole("button", {
name: formatDay(parseDate("2030-01-14")),
Expand All @@ -79,6 +87,14 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
cy.findByRole("button", {
name: formatDay(parseDate("2031-01-16")),
}).should("have.attr", "aria-disabled", "true");
// Simulate selecting a date outside the min/max range
cy.findByRole("button", {
name: formatDay(parseDate("2030-01-14")),
})
.realHover()
.realClick();
cy.findAllByRole("application").should("have.length", 2);
cy.get("@selectedDateChangeSpy").should("not.have.been.called");
// Simulate selecting a date within the min/max range
cy.findByRole("button", {
name: formatDay(parseDate("2030-01-15")),
Expand All @@ -96,6 +112,14 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
"have.value",
formatDate(parseDate("2031-01-15"), testLocale),
);
cy.get("@selectedDateChangeSpy").should(
"have.been.calledWith",
{
startDate: parseDate("2030-01-15"),
endDate: parseDate("2031-01-15"),
},
{ startDate: false, endDate: false },
);
});

it("SHOULD support validation", () => {
Expand Down Expand Up @@ -163,7 +187,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the custom panel is displayed
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Simulate selecting a tenor option
cy.findByRole("option", {
Expand Down Expand Up @@ -199,7 +223,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
cy.mount(
<RangeWithConfirmation
selectionVariant={"range"}
selectedDate={initialRangeDate}
defaultSelectedDate={initialRangeDate}
onSelectedDateChange={selectedDateChangeSpy}
onApply={appliedDateSpy}
onCancel={cancelSpy}
Expand All @@ -217,6 +241,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Simulate selecting an unconfirmed date
cy.findByRole("button", {
Expand Down Expand Up @@ -265,7 +290,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
cy.mount(
<RangeWithConfirmation
selectionVariant={"range"}
selectedDate={initialRangeDate}
defaultSelectedDate={initialRangeDate}
onSelectedDateChange={selectedDateChangeSpy}
onApply={appliedDateSpy}
onCancel={cancelSpy}
Expand All @@ -283,6 +308,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Simulate selecting a new date range
cy.findByRole("button", {
Expand Down Expand Up @@ -344,6 +370,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Verify that the default selected dates are highlighted in the calendar
cy.findByRole("button", {
Expand All @@ -360,6 +387,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Simulate selecting a new start date
cy.findByRole("button", {
Expand Down Expand Up @@ -394,7 +422,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
cy.mount(
<RangeControlled
selectionVariant={"range"}
selectedDate={initialRangeDate}
defaultSelectedDate={initialRangeDate}
locale={testLocale}
/>,
);
Expand All @@ -409,6 +437,7 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Verify that the selected dates are highlighted in the calendar
cy.findByRole("button", {
Expand All @@ -423,12 +452,13 @@ describe("GIVEN a DatePicker where selectionVariant is range", () => {
cy.mount(
<RangeControlled
selectionVariant={"range"}
selectedDate={initialRangeDate}
defaultSelectedDate={initialRangeDate}
locale={testLocale}
/>,
);
// Simulate opening the calendar
cy.findByRole("button", { name: "Open Calendar" }).realClick();
// Verify that the calendar is displayed
cy.findAllByRole("application").should("have.length", 2);
// Simulate selecting a new start date
cy.findByRole("button", {
Expand Down
Loading

0 comments on commit 3a9d518

Please sign in to comment.