Skip to content

Commit 1dececb

Browse files
authored
fix: allow focused disabled days to remain focusable (#2851)
* Fix TestCase2843 today button interaction * Adjust disabled day focus handling * Lint files Signed-off-by: gpbl <io@gpbl.dev> * Build CSS module Signed-off-by: gpbl <io@gpbl.dev> --------- Signed-off-by: gpbl <io@gpbl.dev>
1 parent 818581d commit 1dececb

File tree

6 files changed

+69
-3
lines changed

6 files changed

+69
-3
lines changed

examples/TestCase2843.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from "react";
2+
import { dateButton } from "@/test/elements";
3+
import { render } from "@/test/render";
4+
import { user } from "@/test/user";
5+
import { TestCase2843 } from "./TestCase2843";
6+
7+
const today = new Date(2024, 8, 6);
8+
9+
beforeAll(() => jest.setSystemTime(today));
10+
afterAll(() => jest.useRealTimers());
11+
12+
describe("when clicking the today button", () => {
13+
beforeEach(async () => {
14+
render(<TestCase2843 />);
15+
await user.click(dateButton(today));
16+
});
17+
18+
test('the Today button has aria-disabled="true" but is not disabled', () => {
19+
expect(dateButton(today)).toHaveAttribute("aria-disabled", "true");
20+
expect(dateButton(today)).not.toBeDisabled();
21+
});
22+
});

examples/TestCase2843.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React, { useState } from "react";
2+
3+
import { type DateRange, DayPicker } from "react-day-picker";
4+
5+
export function TestCase2843() {
6+
const [selected, setSelected] = useState<DateRange>();
7+
8+
const disabled = [
9+
...(selected?.from ? [{ before: selected.from }] : []),
10+
...(selected?.from ? [selected.from] : []),
11+
];
12+
13+
return (
14+
<DayPicker
15+
animate
16+
mode="range"
17+
selected={selected}
18+
min={1}
19+
disabled={disabled}
20+
onSelect={(value, date) => {
21+
setSelected((prevValue) => {
22+
if (prevValue?.from && prevValue?.to) {
23+
return {
24+
from: date,
25+
to: undefined,
26+
};
27+
}
28+
29+
return value;
30+
});
31+
}}
32+
/>
33+
);
34+
}

examples/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export * from "./TestCase2389";
9494
export * from "./TestCase2511";
9595
export * from "./TestCase2585";
9696
export * from "./TestCase2835";
97+
export * from "./TestCase2843";
9798
export * from "./Testcase1567";
9899
export * from "./TimeZone";
99100
export * from "./timezone/TestCase2833";

src/DayPicker.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,16 @@ export function DayPicker(initialProps: DayPickerProps) {
727727
type="button"
728728
day={day}
729729
modifiers={modifiers}
730-
disabled={modifiers.disabled || undefined}
730+
disabled={
731+
(!modifiers.focused &&
732+
modifiers.disabled) ||
733+
undefined
734+
}
735+
aria-disabled={
736+
(modifiers.focused &&
737+
modifiers.disabled) ||
738+
undefined
739+
}
731740
tabIndex={isFocusTarget(day) ? 0 : -1}
732741
aria-label={labelDayButton(
733742
date,

src/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@
296296
opacity: var(--rdp-outside-opacity);
297297
}
298298

299-
.rdp-disabled {
299+
.rdp-disabled:not(.rdp-selected) {
300300
opacity: var(--rdp-disabled-opacity);
301301
}
302302

src/style.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@
296296
opacity: var(--rdp-outside-opacity);
297297
}
298298

299-
.disabled {
299+
.disabled:not(.selected) {
300300
opacity: var(--rdp-disabled-opacity);
301301
}
302302

0 commit comments

Comments
 (0)