Skip to content

Commit

Permalink
🔨 Retain the open state of the calendar popup on document visibility …
Browse files Browse the repository at this point in the history
…toggle

Closes Hacker0x01#4844
  • Loading branch information
Balaji Sridharan committed Jun 7, 2024
1 parent 8e7dbce commit a393ec2
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 1 deletion.
41 changes: 40 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ export type DatePickerProps = Omit<

interface DatePickerState {
open: boolean;
wasHidden: boolean;
lastPreSelectChange?:
| typeof PRESELECT_CHANGE_VIA_INPUT
| typeof PRESELECT_CHANGE_VIA_NAVIGATE;
Expand Down Expand Up @@ -320,6 +321,10 @@ export default class DatePicker extends Component<

componentDidMount(): void {
window.addEventListener("scroll", this.onScroll, true);
document.addEventListener(
"visibilitychange",
this.setHiddenStateOnVisibilityHidden,
);
}

componentDidUpdate(
Expand Down Expand Up @@ -364,6 +369,10 @@ export default class DatePicker extends Component<
componentWillUnmount(): void {
this.clearPreventFocusTimeout();
window.removeEventListener("scroll", this.onScroll, true);
document.removeEventListener(
"visibilitychange",
this.setHiddenStateOnVisibilityHidden,
);
}

preventFocusTimeout: ReturnType<typeof setTimeout> | undefined;
Expand Down Expand Up @@ -421,9 +430,32 @@ export default class DatePicker extends Component<
// initial render
shouldFocusDayInline: false,
isRenderAriaLiveMessage: false,
wasHidden: false,
};
};

resetHiddenStatus = (): void => {
this.setState({
...this.state,
wasHidden: false,
});
};

setHiddenStatus = (): void => {
this.setState({
...this.state,
wasHidden: true,
});
};

setHiddenStateOnVisibilityHidden = (): void => {
if (document.visibilityState !== "hidden") {
return;
}

this.setHiddenStatus();
};

clearPreventFocusTimeout = () => {
if (this.preventFocusTimeout) {
clearTimeout(this.preventFocusTimeout);
Expand Down Expand Up @@ -478,7 +510,14 @@ export default class DatePicker extends Component<
: this.props.open;

handleFocus = (event: React.FocusEvent<HTMLElement>): void => {
if (!this.state.preventFocus) {
const isAutoReFocus = this.state.wasHidden;
const isOpenAllowed = isAutoReFocus ? this.state.open : true;

if (isAutoReFocus) {
this.resetHiddenStatus();
}

if (!this.state.preventFocus && isOpenAllowed) {
this.props.onFocus?.(event);
if (!this.props.preventOpenOnFocus && !this.props.readOnly) {
this.setOpen(true);
Expand Down
35 changes: 35 additions & 0 deletions test/datepicker_test.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,41 @@ describe("DatePicker", () => {
jest.resetAllMocks();
});

it("should retain the calendar open status when the document visibility change", () => {
const { container } = render(<DatePicker />);
const input = container.querySelector("input")!;

fireEvent.click(input);
expect(container.querySelector(".react-datepicker")).toBeTruthy();

jest.spyOn(document, "visibilityState", "get").mockReturnValue("hidden");
fireEvent(document, new Event("visibilitychange"));

jest.spyOn(document, "visibilityState", "get").mockReturnValue("visible");
fireEvent(document, new Event("visibilitychange"));

expect(container.querySelector(".react-datepicker")).toBeTruthy();
});

it("should retain the calendar close status when the document visibility change", () => {
const { container } = render(<DatePicker />);
const input = container.querySelector("input")!;

fireEvent.click(input);
expect(container.querySelector(".react-datepicker")).toBeTruthy();

fireEvent.keyDown(input, getKey(KeyType.Escape));
expect(container.querySelector(".react-datepicker")).toBeFalsy();

jest.spyOn(document, "visibilityState", "get").mockReturnValue("hidden");
fireEvent(document, new Event("visibilitychange"));

jest.spyOn(document, "visibilityState", "get").mockReturnValue("visible");
fireEvent(document, new Event("visibilitychange"));

expect(container.querySelector(".react-datepicker")).toBeFalsy();
});

it("should show the calendar when focusing on the date input", () => {
const { container } = render(<DatePicker />);
fireEvent.focus(container.querySelector("input") ?? new HTMLElement());
Expand Down

0 comments on commit a393ec2

Please sign in to comment.