From a9edf0393d4a15d5f9ff218e0403b3ec467a9446 Mon Sep 17 00:00:00 2001
From: Zhihao Cui <5257855+origami-z@users.noreply.github.com>
Date: Fri, 13 Dec 2024 16:36:29 +0000
Subject: [PATCH] Date picker fix readOnly overlay (#4472)
---
.changeset/stupid-worms-learn.md | 5 ++
.../date-picker/DatePicker.range.cy.tsx | 55 +++++++++++++++++++
.../date-picker/DatePicker.single.cy.tsx | 54 +++++++++++++++++-
packages/lab/src/date-picker/DatePicker.tsx | 5 +-
.../date-picker/DatePickerOverlayProvider.tsx | 12 +++-
.../src/date-picker/DatePickerRangeInput.tsx | 20 ++++---
.../src/date-picker/DatePickerSingleInput.tsx | 20 ++++---
.../date-picker/date-picker.stories.tsx | 11 ++++
8 files changed, 159 insertions(+), 23 deletions(-)
create mode 100644 .changeset/stupid-worms-learn.md
diff --git a/.changeset/stupid-worms-learn.md b/.changeset/stupid-worms-learn.md
new file mode 100644
index 00000000000..d627d098da0
--- /dev/null
+++ b/.changeset/stupid-worms-learn.md
@@ -0,0 +1,5 @@
+---
+"@salt-ds/lab": patch
+---
+
+Fixed DatePicker showing overlay when `readOnly`. Closes #4470.
diff --git a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx
index 3d407e8558f..86d2e0c0d0a 100644
--- a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx
+++ b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.range.cy.tsx
@@ -38,6 +38,61 @@ const {
} = datePickerStories as any;
describe("GIVEN a DatePicker where selectionVariant is single", () => {
+ describe("WHEN default state", () => {
+ beforeEach(() => {
+ const today = new Date(2024, 4, 6);
+ cy.clock(today, ["Date"]);
+ cy.setDateAdapter(adapterDateFns);
+ });
+
+ afterEach(() => {
+ cy.clock().then((clock) => clock.restore());
+ });
+
+ it("SHOULD show calendar overlay when click the calendar icon button", () => {
+ cy.mount();
+
+ // Simulate opening the calendar
+ cy.findByRole("button", { name: "Open Calendar" }).realClick();
+ // Verify that the calendar is displayed
+ cy.findAllByRole("application").should("have.length", 2);
+ });
+
+ it("SHOULD open calendar overlay when using down arrow", () => {
+ cy.mount();
+
+ cy.findAllByRole("textbox").eq(0).click().type("{downArrow}");
+ // Verify that the calendar is displayed
+ cy.findAllByRole("application").should("have.length", 2);
+ });
+ });
+
+ describe("WHEN readOnly", () => {
+ beforeEach(() => {
+ const today = new Date(2024, 4, 6);
+ cy.clock(today, ["Date"]);
+ cy.setDateAdapter(adapterDateFns);
+ });
+
+ afterEach(() => {
+ cy.clock().then((clock) => clock.restore());
+ });
+
+ it("SHOULD not show calendar icon button", () => {
+ cy.mount();
+ cy.findByRole("button", { name: "Open Calendar" }).should("not.exist");
+ });
+
+ it("SHOULD not open overlay when using down arrow", () => {
+ cy.mount();
+ cy.findAllByRole("textbox")
+ .eq(0)
+ .click()
+ .type("{downArrow}", { force: true });
+ cy.findByRole("application").should("not.exist");
+ });
+ });
+
adapters.forEach((adapter: SaltDateAdapter) => {
describe(`Tests with ${adapter.lib}`, () => {
beforeEach(() => {
diff --git a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx
index 8929ed51c17..7759c061a3a 100644
--- a/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx
+++ b/packages/lab/src/__tests__/__e2e__/date-picker/DatePicker.single.cy.tsx
@@ -35,9 +35,61 @@ const {
SingleWithMinMaxDate,
SingleWithTodayButton,
SingleCustomFormat,
-} = datePickerStories as any;
+} = datePickerStories as any; // not using composeStories yet, will break certain test below
describe("GIVEN a DatePicker where selectionVariant is single", () => {
+ describe("WHEN default state", () => {
+ beforeEach(() => {
+ const today = new Date(2024, 4, 6);
+ cy.clock(today, ["Date"]);
+ cy.setDateAdapter(adapterDateFns);
+ });
+
+ afterEach(() => {
+ cy.clock().then((clock) => clock.restore());
+ });
+
+ it("SHOULD show calendar overlay when click the calendar icon button", () => {
+ cy.mount();
+
+ // Simulate opening the calendar
+ cy.findByRole("button", { name: "Open Calendar" }).realClick();
+ // Verify that the calendar is displayed
+ cy.findByRole("application").should("exist");
+ });
+
+ it("SHOULD open calendar overlay when using down arrow", () => {
+ cy.mount();
+
+ cy.findByRole("textbox").click().type("{downArrow}");
+ // Verify that the calendar is displayed
+ cy.findByRole("application").should("exist");
+ });
+ });
+
+ describe("WHEN readOnly", () => {
+ beforeEach(() => {
+ const today = new Date(2024, 4, 6);
+ cy.clock(today, ["Date"]);
+ cy.setDateAdapter(adapterDateFns);
+ });
+
+ afterEach(() => {
+ cy.clock().then((clock) => clock.restore());
+ });
+
+ it("SHOULD not show calendar icon button", () => {
+ cy.mount();
+ cy.findByRole("button", { name: "Open Calendar" }).should("not.exist");
+ });
+
+ it("SHOULD not open overlay when using down arrow", () => {
+ cy.mount();
+ cy.findByRole("textbox").click().type("{downArrow}", { force: true });
+ cy.findByRole("application").should("not.exist");
+ });
+ });
+
adapters.forEach((adapter: SaltDateAdapter) => {
describe(`Tests with ${adapter.lib}`, () => {
beforeEach(() => {
diff --git a/packages/lab/src/date-picker/DatePicker.tsx b/packages/lab/src/date-picker/DatePicker.tsx
index a4668504bc7..e9a162dd46f 100644
--- a/packages/lab/src/date-picker/DatePicker.tsx
+++ b/packages/lab/src/date-picker/DatePicker.tsx
@@ -124,15 +124,16 @@ export const DatePickerMain = forwardRef>(
export const DatePicker = forwardRef(function DatePicker<
TDate extends DateFrameworkType,
>(props: DatePickerProps, ref: React.Ref) {
- const { open, defaultOpen, onOpen, ...rest } = props;
+ const { open, defaultOpen, onOpen, readOnly, ...rest } = props;
return (
-
+
);
});
diff --git a/packages/lab/src/date-picker/DatePickerOverlayProvider.tsx b/packages/lab/src/date-picker/DatePickerOverlayProvider.tsx
index a9a325e5d13..a8ff0a923f2 100644
--- a/packages/lab/src/date-picker/DatePickerOverlayProvider.tsx
+++ b/packages/lab/src/date-picker/DatePickerOverlayProvider.tsx
@@ -94,11 +94,15 @@ interface DatePickerOverlayProviderProps {
* The content to be rendered inside the overlay provider.
*/
children: ReactNode;
+ /**
+ * When true, shouldn't open the overlay.
+ */
+ readOnly?: boolean;
}
export const DatePickerOverlayProvider: React.FC<
DatePickerOverlayProviderProps
-> = ({ open: openProp, defaultOpen, onOpen, children }) => {
+> = ({ open: openProp, defaultOpen, onOpen, children, readOnly }) => {
const [open, setOpenState] = useControlled({
controlled: openProp,
default: Boolean(defaultOpen),
@@ -130,6 +134,10 @@ export const DatePickerOverlayProvider: React.FC<
reason?: OpenChangeReason | undefined,
) => {
if (newOpen) {
+ if (readOnly) {
+ // When not open overlay when readOnly
+ return;
+ }
triggeringElement.current = document.activeElement as HTMLElement;
}
setOpenState(newOpen);
@@ -141,7 +149,7 @@ export const DatePickerOverlayProvider: React.FC<
onDismissCallback?.current?.();
}
},
- [onOpen],
+ [onOpen, readOnly],
);
const floatingUIResult = useFloatingUI({
diff --git a/packages/lab/src/date-picker/DatePickerRangeInput.tsx b/packages/lab/src/date-picker/DatePickerRangeInput.tsx
index 506f1fcb5ec..f8a9db18e6d 100644
--- a/packages/lab/src/date-picker/DatePickerRangeInput.tsx
+++ b/packages/lab/src/date-picker/DatePickerRangeInput.tsx
@@ -234,15 +234,17 @@ export const DatePickerRangeInput = forwardRef(function DatePickerRangeInput<
onDateValueChange={handleDateValueChange}
onChange={onChange}
endAdornment={
-
+ !readOnly && (
+
+ )
}
format={format}
{...rest}
diff --git a/packages/lab/src/date-picker/DatePickerSingleInput.tsx b/packages/lab/src/date-picker/DatePickerSingleInput.tsx
index 20ec5056e9b..97c625be45c 100644
--- a/packages/lab/src/date-picker/DatePickerSingleInput.tsx
+++ b/packages/lab/src/date-picker/DatePickerSingleInput.tsx
@@ -188,15 +188,17 @@ export const DatePickerSingleInput = forwardRef<
onDateChange={handleDateChange}
onDateValueChange={handleDateValueChange}
endAdornment={
-
+ !readOnly && (
+
+ )
}
onKeyDown={handleOnKeyDown}
{...rest}
diff --git a/packages/lab/stories/date-picker/date-picker.stories.tsx b/packages/lab/stories/date-picker/date-picker.stories.tsx
index 1e82c8fe3b4..8e22b0270bc 100644
--- a/packages/lab/stories/date-picker/date-picker.stories.tsx
+++ b/packages/lab/stories/date-picker/date-picker.stories.tsx
@@ -173,6 +173,17 @@ Range.args = {
selectionVariant: "range",
};
+export const SingleReadOnly = DatePickerSingleTemplate.bind({});
+SingleReadOnly.args = {
+ readOnly: true,
+};
+
+export const RangeReadOnly = DatePickerRangeTemplate.bind({});
+RangeReadOnly.args = {
+ readOnly: true,
+ selectionVariant: "range",
+};
+
export const SingleControlled: StoryFn<
DatePickerSingleProps
> = ({ selectionVariant, defaultSelectedDate, ...args }) => {