Skip to content

Commit 7d37504

Browse files
[DateRangePicker] Avoid unnecessary field section focusing (@LukasTy) (#16569)
Signed-off-by: Lukas Tyla <[email protected]> Co-authored-by: Lukas Tyla <[email protected]>
1 parent 3dca3e1 commit 7d37504

File tree

6 files changed

+66
-1
lines changed

6 files changed

+66
-1
lines changed

packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ const useMultiInputFieldSlotProps = <
202202
}
203203

204204
// bring back focus to the field
205+
// currentView is present on DateTimeRangePicker
205206
currentFieldRef.current.setSelectedSections(
206207
// use the current view or `0` when the range position has just been swapped
207208
previousRangePosition.current === rangePosition ? currentView : 0,

packages/x-date-pickers-pro/src/internals/hooks/useRangePosition.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ export const useRangePosition = (
4848

4949
const sections = singleInputFieldRef.current.getSections();
5050
const targetActiveSectionIndex = newRangePosition === 'start' ? 0 : sections.length / 2;
51+
const activeSectionIndex = singleInputFieldRef.current.getActiveSectionIndex();
52+
// if the active section is already within the target range, we don't need to update it.
53+
if (
54+
activeSectionIndex &&
55+
activeSectionIndex >= targetActiveSectionIndex &&
56+
activeSectionIndex < targetActiveSectionIndex + sections.length / 2
57+
) {
58+
return;
59+
}
5160
singleInputFieldRef.current.setSelectedSections(targetActiveSectionIndex);
5261
};
5362

packages/x-date-pickers/src/internals/hooks/useField/useFieldV6TextField.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ export const useFieldV6TextField: UseFieldTextField<false> = (params) => {
201201
return nextSectionIndex === -1 ? sections.length - 1 : nextSectionIndex - 1;
202202
},
203203
focusField: (newSelectedSection = 0) => {
204+
if (getActiveElement(document) === inputRef.current) {
205+
return;
206+
}
204207
inputRef.current?.focus();
205208
setSelectedSections(newSelectedSection);
206209
},

packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ export const useFieldV7TextField: UseFieldTextField<true> = (params) => {
114114
return sectionListRef.current.getSectionIndexFromDOMElement(activeElement);
115115
},
116116
focusField: (newSelectedSections = 0) => {
117-
if (!sectionListRef.current) {
117+
if (
118+
!sectionListRef.current ||
119+
// if the field is already focused, we don't need to focus it again
120+
interactions.getActiveSectionIndexFromDOM() != null
121+
) {
118122
return;
119123
}
120124

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as React from 'react';
2+
import dayjs from 'dayjs';
3+
import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
4+
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
5+
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
6+
7+
export default function BasicDesktopDateRangePicker() {
8+
return (
9+
<LocalizationProvider dateAdapter={AdapterDayjs}>
10+
<DateRangePicker
11+
defaultValue={[dayjs('2024-04-12'), dayjs('2024-04-14')]}
12+
enableAccessibleFieldDOMStructure
13+
/>
14+
</LocalizationProvider>
15+
);
16+
}

test/e2e/index.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,38 @@ async function initializeEnvironment(
10571057
'MUI X: The timezone of the start and the end date should be the same.',
10581058
);
10591059
});
1060+
1061+
it('should keep the focus on the clicked section', async () => {
1062+
// firefox in CI is not happy with this test
1063+
if (browserType.name() === 'firefox') {
1064+
return;
1065+
}
1066+
await renderFixture('DatePicker/DesktopDateRangePickerWithValue');
1067+
1068+
const startDaySection = page.getByRole('spinbutton', { name: 'Day' }).first();
1069+
await startDaySection.click();
1070+
expect(await page.evaluate(() => document.activeElement?.textContent)).to.equal('12');
1071+
1072+
const endYearSection = page.getByRole('spinbutton', { name: 'Year' }).last();
1073+
await endYearSection.click();
1074+
expect(await page.evaluate(() => document.activeElement?.textContent)).to.equal('2024');
1075+
});
1076+
1077+
it('should keep the focus on the clicked section with single input field', async () => {
1078+
// firefox in CI is not happy with this test
1079+
if (browserType.name() === 'firefox') {
1080+
return;
1081+
}
1082+
await renderFixture('DatePicker/SingleDesktopDateRangePickerWithTZ');
1083+
1084+
const startDaySection = page.getByRole('spinbutton', { name: 'Day' }).first();
1085+
await startDaySection.click();
1086+
expect(await page.evaluate(() => document.activeElement?.textContent)).to.equal('12');
1087+
1088+
const endYearSection = page.getByRole('spinbutton', { name: 'Year' }).last();
1089+
await endYearSection.click();
1090+
expect(await page.evaluate(() => document.activeElement?.textContent)).to.equal('2024');
1091+
});
10601092
});
10611093
});
10621094
});

0 commit comments

Comments
 (0)