From 0c6f7519f1adc3d0567f8c7366249bcd9554ea14 Mon Sep 17 00:00:00 2001 From: Philipp Schneider Date: Thu, 5 Mar 2026 18:11:37 +0100 Subject: [PATCH 1/6] feat: New prop for date range picker --- .../calendar/__tests__/utils.test.ts | 38 +++++++++++++++++-- src/date-range-picker/calendar/index.tsx | 3 +- src/date-range-picker/calendar/interfaces.ts | 1 + src/date-range-picker/calendar/utils.ts | 22 +++++++++-- src/date-range-picker/dropdown.tsx | 3 ++ src/date-range-picker/index.tsx | 2 + src/date-range-picker/interfaces.ts | 13 +++++++ 7 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/date-range-picker/calendar/__tests__/utils.test.ts b/src/date-range-picker/calendar/__tests__/utils.test.ts index b0f82e121f..d8212a2ebb 100644 --- a/src/date-range-picker/calendar/__tests__/utils.test.ts +++ b/src/date-range-picker/calendar/__tests__/utils.test.ts @@ -107,11 +107,26 @@ describe('findMonthToDisplay', () => { const result = findMonthToDisplay(value, true); // isSingleGrid doesn't matter in this case expect(result).toEqual(createDate('2023-07-01')); }); - test('should return current month when both start and end dates are null', () => { + test('should return current month when both start and end dates are null for single grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findMonthToDisplay(value, true); // isSingleGrid doesn't matter in this case + const result = findMonthToDisplay(value, true); expect(result).toEqual(createDate('2023-06-01')); // Based on the mocked current date }); + test('should return current month (default previous-and-current) when both dates are null for double grid', () => { + const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; + const result = findMonthToDisplay(value, false); + expect(result).toEqual(createDate('2023-06-01')); // Default: current month as baseDate (right grid) + }); + test('should return current month with startCurrentMonth=false when both dates are null for double grid', () => { + const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; + const result = findMonthToDisplay(value, false, false); + expect(result).toEqual(createDate('2023-06-01')); + }); + test('should return next month with startCurrentMonth=true when both dates are null for double grid', () => { + const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; + const result = findMonthToDisplay(value, false, true); + expect(result).toEqual(createDate('2023-07-01')); // Next month as baseDate so current month appears on the left + }); test('should handle leap years correctly', () => { jest.setSystemTime(createDate('2024-02-15').getTime()); const value = { start: { date: '2024-02-29', time: '00:00' }, end: { date: '', time: '' } }; @@ -151,11 +166,26 @@ describe('findYearToDisplay', () => { const result = findYearToDisplay(value, true); // isSingleGrid doesn't matter in this case expect(result).toEqual(createDate('2024-01-01')); }); - test('should return current year when both start and end dates are empty', () => { + test('should return current year when both start and end dates are empty for single grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findYearToDisplay(value, true); // isSingleGrid doesn't matter in this case + const result = findYearToDisplay(value, true); expect(result).toEqual(createDate('2023-01-01')); // Based on the mocked current date }); + test('should return current year (default previous-and-current) when both dates are empty for double grid', () => { + const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; + const result = findYearToDisplay(value, false); + expect(result).toEqual(createDate('2023-01-01')); // Default: current year as baseDate (right grid) + }); + test('should return current year with startCurrentMonth=false when both dates are empty for double grid', () => { + const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; + const result = findYearToDisplay(value, false, false); + expect(result).toEqual(createDate('2023-01-01')); + }); + test('should return next year with startCurrentMonth=true when both dates are empty for double grid', () => { + const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; + const result = findYearToDisplay(value, false, true); + expect(result).toEqual(createDate('2024-01-01')); // Next year as baseDate so current year appears on the left + }); test('should handle leap years correctly', () => { const value = { start: { date: '2024-02-29', time: '00:00' }, end: { date: '', time: '' } }; const result = findYearToDisplay(value, true); diff --git a/src/date-range-picker/calendar/index.tsx b/src/date-range-picker/calendar/index.tsx index 84de2b5adb..07e1aa06b0 100644 --- a/src/date-range-picker/calendar/index.tsx +++ b/src/date-range-picker/calendar/index.tsx @@ -52,6 +52,7 @@ export default function DateRangePickerCalendar({ dateInputFormat, customAbsoluteRangeControl, granularity = 'day', + startCurrentMonth, }: DateRangePickerCalendarProps) { const isSingleGrid = useMobile(); const isMonthPicker = granularity === 'month'; @@ -66,7 +67,7 @@ export default function DateRangePickerCalendar({ const addPage = isMonthPicker ? addYears : addMonths; const startOfPage = isMonthPicker ? startOfYear : startOfMonth; const findItemToFocus = isMonthPicker ? findMonthToFocus : findDateToFocus; - const [currentPage, setCurrentPage] = useState(() => findPageToDisplay(value, isSingleGrid)); + const [currentPage, setCurrentPage] = useState(() => findPageToDisplay(value, isSingleGrid, startCurrentMonth)); const [focusedDate, setFocusedDate] = useState(() => { if (value.start.date) { const startDate = parseDate(value.start.date); diff --git a/src/date-range-picker/calendar/interfaces.ts b/src/date-range-picker/calendar/interfaces.ts index 317a3a34a2..31c2053d15 100644 --- a/src/date-range-picker/calendar/interfaces.ts +++ b/src/date-range-picker/calendar/interfaces.ts @@ -49,6 +49,7 @@ export interface DateRangePickerCalendarProps | 'customAbsoluteRangeControl' | 'isDateEnabled' | 'dateDisabledReason' + | 'startCurrentMonth' >, 'absoluteFormat' | 'timeInputFormat' > { diff --git a/src/date-range-picker/calendar/utils.ts b/src/date-range-picker/calendar/utils.ts index 0dc45f6b90..62b72de719 100644 --- a/src/date-range-picker/calendar/utils.ts +++ b/src/date-range-picker/calendar/utils.ts @@ -43,7 +43,11 @@ export function findMonthToFocus( return null; } -export function findMonthToDisplay(value: DateRangePickerProps.PendingAbsoluteValue, isSingleGrid: boolean) { +export function findMonthToDisplay( + value: DateRangePickerProps.PendingAbsoluteValue, + isSingleGrid: boolean, + startCurrentMonth = false +) { if (value.start.date) { const startDate = parseDate(value.start.date); if (isSingleGrid) { @@ -54,10 +58,17 @@ export function findMonthToDisplay(value: DateRangePickerProps.PendingAbsoluteVa if (value.end.date) { return startOfMonth(parseDate(value.end.date)); } - return startOfMonth(Date.now()); + if (isSingleGrid || !startCurrentMonth) { + return startOfMonth(Date.now()); + } + return startOfMonth(addMonths(Date.now(), 1)); } -export function findYearToDisplay(value: DateRangePickerProps.PendingAbsoluteValue, isSingleGrid: boolean) { +export function findYearToDisplay( + value: DateRangePickerProps.PendingAbsoluteValue, + isSingleGrid: boolean, + startCurrentMonth = false +) { if (value.start.date) { const startDate = parseDate(value.start.date); if (isSingleGrid) { @@ -68,7 +79,10 @@ export function findYearToDisplay(value: DateRangePickerProps.PendingAbsoluteVal if (value.end.date) { return startOfYear(parseDate(value.end.date)); } - return startOfYear(Date.now()); + if (isSingleGrid || !startCurrentMonth) { + return startOfYear(Date.now()); + } + return startOfYear(addYears(Date.now(), 1)); } export const generateI18NFallbackKey = (isMonthPicker: boolean, isDateOnly: boolean) => { diff --git a/src/date-range-picker/dropdown.tsx b/src/date-range-picker/dropdown.tsx index 521dcac98e..2cbed8fa47 100644 --- a/src/date-range-picker/dropdown.tsx +++ b/src/date-range-picker/dropdown.tsx @@ -62,6 +62,7 @@ interface DateRangePickerDropdownProps isSingleGrid: boolean; customAbsoluteRangeControl: DateRangePickerProps.AbsoluteRangeControl | undefined; renderRelativeRangeContent: DateRangePickerProps.RelativeRangeControl | undefined; + startCurrentMonth: boolean | undefined; } export function DateRangePickerDropdown({ @@ -91,6 +92,7 @@ export function DateRangePickerDropdown({ customRelativeRangeUnits, renderRelativeRangeContent, granularity = 'day', + startCurrentMonth, }: DateRangePickerDropdownProps) { const i18n = useInternalI18n('date-range-picker'); const isMonthPicker = granularity === 'month'; @@ -216,6 +218,7 @@ export function DateRangePickerDropdown({ dateInputFormat={dateInputFormat} customAbsoluteRangeControl={customAbsoluteRangeControl} granularity={granularity} + startCurrentMonth={startCurrentMonth} /> )} diff --git a/src/date-range-picker/index.tsx b/src/date-range-picker/index.tsx index eb369a8538..fc2c36613c 100644 --- a/src/date-range-picker/index.tsx +++ b/src/date-range-picker/index.tsx @@ -116,6 +116,7 @@ const DateRangePicker = React.forwardRef( customRelativeRangeUnits, renderRelativeRangeContent, granularity = 'day', + startCurrentMonth, ...rest }: DateRangePickerProps, ref: Ref @@ -349,6 +350,7 @@ const DateRangePicker = React.forwardRef( customRelativeRangeUnits={customRelativeRangeUnits} renderRelativeRangeContent={renderRelativeRangeContent} granularity={granularity} + startCurrentMonth={startCurrentMonth} /> )} diff --git a/src/date-range-picker/interfaces.ts b/src/date-range-picker/interfaces.ts index c9fc7334a1..1100fe6da3 100644 --- a/src/date-range-picker/interfaces.ts +++ b/src/date-range-picker/interfaces.ts @@ -100,6 +100,19 @@ export interface DateRangePickerBaseProps { */ timeInputFormat?: DateRangePickerProps.TimeInputFormat; + /** + * When set to `true`, the calendar opens with the current month on the left + * and next month on the right (when two grids are visible). + * + * By default (`false`), the left grid shows the previous month and the + * right grid shows the current month. + * + * Has no effect on single-grid (mobile) layout. + * + * Default: `false`. + */ + startCurrentMonth?: boolean; + /** * Fired whenever a user changes the component's value. * The event `detail` contains the current value of the field. From 4f675ff915c98920c919b907d12c5aa67a37753a Mon Sep 17 00:00:00 2001 From: Philipp Schneider Date: Mon, 9 Mar 2026 11:12:54 +0100 Subject: [PATCH 2/6] update snapshots --- .../__snapshots__/documenter.test.ts.snap | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap index b19b3647c2..b545c5b88d 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap @@ -11396,6 +11396,20 @@ allows the user to clear the selected value.", "optional": true, "type": "boolean", }, + { + "description": "When set to \`true\`, the calendar opens with the current month on the left +and next month on the right (when two grids are visible). + +By default (\`false\`), the left grid shows the previous month and the +right grid shows the current month. + +Has no effect on single-grid (mobile) layout. + +Default: \`false\`.", + "name": "startCurrentMonth", + "optional": true, + "type": "boolean", + }, { "description": "Starting day of the week. [0-6] maps to [Sunday-Saturday]. By default the starting day of the week is defined by the locale, From efe0e8d0974c5ebcbbf61a281af53eb26d0d993a Mon Sep 17 00:00:00 2001 From: Philipp Schneider Date: Mon, 9 Mar 2026 15:51:31 +0100 Subject: [PATCH 3/6] using enum --- .../calendar/__tests__/utils.test.ts | 16 ++++++++-------- src/date-range-picker/calendar/index.tsx | 4 ++-- src/date-range-picker/calendar/interfaces.ts | 2 +- src/date-range-picker/calendar/utils.ts | 8 ++++---- src/date-range-picker/dropdown.tsx | 6 +++--- src/date-range-picker/index.tsx | 4 ++-- src/date-range-picker/interfaces.ts | 16 +++++++++------- 7 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/date-range-picker/calendar/__tests__/utils.test.ts b/src/date-range-picker/calendar/__tests__/utils.test.ts index d8212a2ebb..5c697d07e7 100644 --- a/src/date-range-picker/calendar/__tests__/utils.test.ts +++ b/src/date-range-picker/calendar/__tests__/utils.test.ts @@ -117,14 +117,14 @@ describe('findMonthToDisplay', () => { const result = findMonthToDisplay(value, false); expect(result).toEqual(createDate('2023-06-01')); // Default: current month as baseDate (right grid) }); - test('should return current month with startCurrentMonth=false when both dates are null for double grid', () => { + test('should return current month with startMonth="previous" when both dates are null for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findMonthToDisplay(value, false, false); + const result = findMonthToDisplay(value, false, 'previous'); expect(result).toEqual(createDate('2023-06-01')); }); - test('should return next month with startCurrentMonth=true when both dates are null for double grid', () => { + test('should return next month with startMonth="current" when both dates are null for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findMonthToDisplay(value, false, true); + const result = findMonthToDisplay(value, false, 'current'); expect(result).toEqual(createDate('2023-07-01')); // Next month as baseDate so current month appears on the left }); test('should handle leap years correctly', () => { @@ -176,14 +176,14 @@ describe('findYearToDisplay', () => { const result = findYearToDisplay(value, false); expect(result).toEqual(createDate('2023-01-01')); // Default: current year as baseDate (right grid) }); - test('should return current year with startCurrentMonth=false when both dates are empty for double grid', () => { + test('should return current year with startMonth="previous" when both dates are empty for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findYearToDisplay(value, false, false); + const result = findYearToDisplay(value, false, 'previous'); expect(result).toEqual(createDate('2023-01-01')); }); - test('should return next year with startCurrentMonth=true when both dates are empty for double grid', () => { + test('should return next year with startMonth="current" when both dates are empty for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findYearToDisplay(value, false, true); + const result = findYearToDisplay(value, false, 'current'); expect(result).toEqual(createDate('2024-01-01')); // Next year as baseDate so current year appears on the left }); test('should handle leap years correctly', () => { diff --git a/src/date-range-picker/calendar/index.tsx b/src/date-range-picker/calendar/index.tsx index 07e1aa06b0..7292123385 100644 --- a/src/date-range-picker/calendar/index.tsx +++ b/src/date-range-picker/calendar/index.tsx @@ -52,7 +52,7 @@ export default function DateRangePickerCalendar({ dateInputFormat, customAbsoluteRangeControl, granularity = 'day', - startCurrentMonth, + startMonth, }: DateRangePickerCalendarProps) { const isSingleGrid = useMobile(); const isMonthPicker = granularity === 'month'; @@ -67,7 +67,7 @@ export default function DateRangePickerCalendar({ const addPage = isMonthPicker ? addYears : addMonths; const startOfPage = isMonthPicker ? startOfYear : startOfMonth; const findItemToFocus = isMonthPicker ? findMonthToFocus : findDateToFocus; - const [currentPage, setCurrentPage] = useState(() => findPageToDisplay(value, isSingleGrid, startCurrentMonth)); + const [currentPage, setCurrentPage] = useState(() => findPageToDisplay(value, isSingleGrid, startMonth)); const [focusedDate, setFocusedDate] = useState(() => { if (value.start.date) { const startDate = parseDate(value.start.date); diff --git a/src/date-range-picker/calendar/interfaces.ts b/src/date-range-picker/calendar/interfaces.ts index 31c2053d15..310cac25ed 100644 --- a/src/date-range-picker/calendar/interfaces.ts +++ b/src/date-range-picker/calendar/interfaces.ts @@ -49,7 +49,7 @@ export interface DateRangePickerCalendarProps | 'customAbsoluteRangeControl' | 'isDateEnabled' | 'dateDisabledReason' - | 'startCurrentMonth' + | 'startMonth' >, 'absoluteFormat' | 'timeInputFormat' > { diff --git a/src/date-range-picker/calendar/utils.ts b/src/date-range-picker/calendar/utils.ts index 62b72de719..12adbb85b8 100644 --- a/src/date-range-picker/calendar/utils.ts +++ b/src/date-range-picker/calendar/utils.ts @@ -46,7 +46,7 @@ export function findMonthToFocus( export function findMonthToDisplay( value: DateRangePickerProps.PendingAbsoluteValue, isSingleGrid: boolean, - startCurrentMonth = false + startMonth: DateRangePickerProps.StartMonth | undefined = 'previous' ) { if (value.start.date) { const startDate = parseDate(value.start.date); @@ -58,7 +58,7 @@ export function findMonthToDisplay( if (value.end.date) { return startOfMonth(parseDate(value.end.date)); } - if (isSingleGrid || !startCurrentMonth) { + if (isSingleGrid || startMonth !== 'current') { return startOfMonth(Date.now()); } return startOfMonth(addMonths(Date.now(), 1)); @@ -67,7 +67,7 @@ export function findMonthToDisplay( export function findYearToDisplay( value: DateRangePickerProps.PendingAbsoluteValue, isSingleGrid: boolean, - startCurrentMonth = false + startMonth: DateRangePickerProps.StartMonth | undefined = 'previous' ) { if (value.start.date) { const startDate = parseDate(value.start.date); @@ -79,7 +79,7 @@ export function findYearToDisplay( if (value.end.date) { return startOfYear(parseDate(value.end.date)); } - if (isSingleGrid || !startCurrentMonth) { + if (isSingleGrid || startMonth !== 'current') { return startOfYear(Date.now()); } return startOfYear(addYears(Date.now(), 1)); diff --git a/src/date-range-picker/dropdown.tsx b/src/date-range-picker/dropdown.tsx index 2cbed8fa47..749d1c1369 100644 --- a/src/date-range-picker/dropdown.tsx +++ b/src/date-range-picker/dropdown.tsx @@ -62,7 +62,7 @@ interface DateRangePickerDropdownProps isSingleGrid: boolean; customAbsoluteRangeControl: DateRangePickerProps.AbsoluteRangeControl | undefined; renderRelativeRangeContent: DateRangePickerProps.RelativeRangeControl | undefined; - startCurrentMonth: boolean | undefined; + startMonth: DateRangePickerProps.StartMonth | undefined; } export function DateRangePickerDropdown({ @@ -92,7 +92,7 @@ export function DateRangePickerDropdown({ customRelativeRangeUnits, renderRelativeRangeContent, granularity = 'day', - startCurrentMonth, + startMonth, }: DateRangePickerDropdownProps) { const i18n = useInternalI18n('date-range-picker'); const isMonthPicker = granularity === 'month'; @@ -218,7 +218,7 @@ export function DateRangePickerDropdown({ dateInputFormat={dateInputFormat} customAbsoluteRangeControl={customAbsoluteRangeControl} granularity={granularity} - startCurrentMonth={startCurrentMonth} + startMonth={startMonth} /> )} diff --git a/src/date-range-picker/index.tsx b/src/date-range-picker/index.tsx index fc2c36613c..2eb322c049 100644 --- a/src/date-range-picker/index.tsx +++ b/src/date-range-picker/index.tsx @@ -116,7 +116,7 @@ const DateRangePicker = React.forwardRef( customRelativeRangeUnits, renderRelativeRangeContent, granularity = 'day', - startCurrentMonth, + startMonth, ...rest }: DateRangePickerProps, ref: Ref @@ -350,7 +350,7 @@ const DateRangePicker = React.forwardRef( customRelativeRangeUnits={customRelativeRangeUnits} renderRelativeRangeContent={renderRelativeRangeContent} granularity={granularity} - startCurrentMonth={startCurrentMonth} + startMonth={startMonth} /> )} diff --git a/src/date-range-picker/interfaces.ts b/src/date-range-picker/interfaces.ts index 1100fe6da3..4448b35cb2 100644 --- a/src/date-range-picker/interfaces.ts +++ b/src/date-range-picker/interfaces.ts @@ -101,17 +101,17 @@ export interface DateRangePickerBaseProps { timeInputFormat?: DateRangePickerProps.TimeInputFormat; /** - * When set to `true`, the calendar opens with the current month on the left - * and next month on the right (when two grids are visible). + * Determines which month is displayed first (on the left) when the calendar + * opens with two grids visible. * - * By default (`false`), the left grid shows the previous month and the - * right grid shows the current month. + * * `previous` (default) – the left grid shows the previous month and the + * right grid shows the current month. + * * `current` – the left grid shows the current month and the right grid + * shows the next month. * * Has no effect on single-grid (mobile) layout. - * - * Default: `false`. */ - startCurrentMonth?: boolean; + startMonth?: DateRangePickerProps.StartMonth; /** * Fired whenever a user changes the component's value. @@ -311,6 +311,8 @@ export namespace DateRangePickerProps { setSelectedRange: (value: RelativeValue) => void ) => React.ReactNode; + export type StartMonth = 'current' | 'previous'; + export type RangeSelectorMode = 'default' | 'absolute-only' | 'relative-only'; export interface Ref { From a6ec2810378a10eeafc8bbaf007c3faff012e7d6 Mon Sep 17 00:00:00 2001 From: Philipp Schneider Date: Tue, 10 Mar 2026 11:32:41 +0100 Subject: [PATCH 4/6] update snapshots --- .../__snapshots__/documenter.test.ts.snap | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap index b545c5b88d..6efb5d7055 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap @@ -11397,18 +11397,26 @@ allows the user to clear the selected value.", "type": "boolean", }, { - "description": "When set to \`true\`, the calendar opens with the current month on the left -and next month on the right (when two grids are visible). + "description": "Determines which month is displayed first (on the left) when the calendar +opens with two grids visible. -By default (\`false\`), the left grid shows the previous month and the -right grid shows the current month. +* \`previous\` (default) – the left grid shows the previous month and the + right grid shows the current month. +* \`current\` – the left grid shows the current month and the right grid + shows the next month. -Has no effect on single-grid (mobile) layout. - -Default: \`false\`.", - "name": "startCurrentMonth", +Has no effect on single-grid (mobile) layout.", + "inlineType": { + "name": "DateRangePickerProps.StartMonth", + "type": "union", + "values": [ + "current", + "previous", + ], + }, + "name": "startMonth", "optional": true, - "type": "boolean", + "type": "string", }, { "description": "Starting day of the week. [0-6] maps to [Sunday-Saturday]. From bfb4a5f3b63bdf11b8983da9a49f18823fb220a2 Mon Sep 17 00:00:00 2001 From: Philipp Schneider Date: Thu, 12 Mar 2026 09:29:19 +0100 Subject: [PATCH 5/6] add example --- pages/date-range-picker/common.tsx | 17 ++++++++ pages/date-range-picker/start-month.page.tsx | 42 ++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 pages/date-range-picker/start-month.page.tsx diff --git a/pages/date-range-picker/common.tsx b/pages/date-range-picker/common.tsx index 91dc392584..c863a7bc5e 100644 --- a/pages/date-range-picker/common.tsx +++ b/pages/date-range-picker/common.tsx @@ -27,6 +27,7 @@ interface DateRangePickerPageSettings { disabledDates?: DisabledDate; showDisabledReason?: boolean; hasValue?: boolean; + startMonth?: DateRangePickerProps.StartMonth; } const defaultSettings: Required = { @@ -45,6 +46,7 @@ const defaultSettings: Required = { disabledDates: 'none', showDisabledReason: true, hasValue: true, + startMonth: 'previous', }; export function useDateRangePickerSettings( @@ -89,6 +91,7 @@ export function useDateRangePickerSettings( const disabledDates = urlParams.disabledDates ?? def('disabledDates'); const showDisabledReason = parseBoolean(def('showDisabledReason'), urlParams.showDisabledReason); const hasValue = parseBoolean(def('hasValue'), urlParams.hasValue); + const startMonth = urlParams.startMonth ?? def('startMonth'); const settings: Required = { dateOnly, monthOnly, @@ -105,6 +108,7 @@ export function useDateRangePickerSettings( disabledDates, showDisabledReason, hasValue, + startMonth, }; const setSettings = (settings: DateRangePickerPageSettings) => setUrlParams(settings); @@ -212,6 +216,7 @@ export function useDateRangePickerSettings( placeholder, i18nStrings, locale: 'en-GB', + startMonth, }; return { props, settings, setSettings }; @@ -256,6 +261,7 @@ export function Settings({ disabledDates, showDisabledReason, hasValue, + startMonth, }, setSettings, }: { @@ -274,6 +280,7 @@ export function Settings({ const dateFormatOptions = [{ value: 'iso' }, { value: 'slashed' }, { value: 'long-localized' }]; const inputDateFormat = [{ value: 'iso' }, { value: 'slashed' }]; const timeFormatOptions = [{ value: 'hh:mm:ss' }, { value: 'hh:mm' }, { value: 'hh' }]; + const startMonthOptions = [{ value: 'previous' }, { value: 'current' }]; return ( @@ -332,6 +339,16 @@ export function Settings({ /> + + o.value === startMonth) ?? null} + options={secondaryGridOptions} + selectedOption={secondaryGridOptions.find(o => o.value === secondaryGrid) ?? null} onChange={({ detail }) => - setSettings({ startMonth: detail.selectedOption.value as DateRangePickerProps.StartMonth }) + setSettings({ secondaryGrid: detail.selectedOption.value as DateRangePickerProps.SecondaryGrid }) } /> diff --git a/pages/date-range-picker/start-month.page.tsx b/pages/date-range-picker/start-month.page.tsx index 27dd7968d0..9388880838 100644 --- a/pages/date-range-picker/start-month.page.tsx +++ b/pages/date-range-picker/start-month.page.tsx @@ -12,7 +12,7 @@ import { Settings, useDateRangePickerSettings } from './common'; export default function StartMonthScenario() { const { props, settings, setSettings } = useDateRangePickerSettings({ value: null, - startMonth: 'current', + secondaryGrid: 'next', hasValue: false, }); return ( diff --git a/src/date-range-picker/calendar/__tests__/utils.test.ts b/src/date-range-picker/calendar/__tests__/utils.test.ts index 5c697d07e7..dc9590b3b8 100644 --- a/src/date-range-picker/calendar/__tests__/utils.test.ts +++ b/src/date-range-picker/calendar/__tests__/utils.test.ts @@ -117,14 +117,14 @@ describe('findMonthToDisplay', () => { const result = findMonthToDisplay(value, false); expect(result).toEqual(createDate('2023-06-01')); // Default: current month as baseDate (right grid) }); - test('should return current month with startMonth="previous" when both dates are null for double grid', () => { + test('should return current month with secondaryGrid="previous" when both dates are null for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; const result = findMonthToDisplay(value, false, 'previous'); expect(result).toEqual(createDate('2023-06-01')); }); - test('should return next month with startMonth="current" when both dates are null for double grid', () => { + test('should return next month with secondaryGrid="next" when both dates are null for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findMonthToDisplay(value, false, 'current'); + const result = findMonthToDisplay(value, false, 'next'); expect(result).toEqual(createDate('2023-07-01')); // Next month as baseDate so current month appears on the left }); test('should handle leap years correctly', () => { @@ -176,14 +176,14 @@ describe('findYearToDisplay', () => { const result = findYearToDisplay(value, false); expect(result).toEqual(createDate('2023-01-01')); // Default: current year as baseDate (right grid) }); - test('should return current year with startMonth="previous" when both dates are empty for double grid', () => { + test('should return current year with secondaryGrid="previous" when both dates are empty for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; const result = findYearToDisplay(value, false, 'previous'); expect(result).toEqual(createDate('2023-01-01')); }); - test('should return next year with startMonth="current" when both dates are empty for double grid', () => { + test('should return next year with secondaryGrid="next" when both dates are empty for double grid', () => { const value = { start: { date: '', time: '' }, end: { date: '', time: '' } }; - const result = findYearToDisplay(value, false, 'current'); + const result = findYearToDisplay(value, false, 'next'); expect(result).toEqual(createDate('2024-01-01')); // Next year as baseDate so current year appears on the left }); test('should handle leap years correctly', () => { diff --git a/src/date-range-picker/calendar/index.tsx b/src/date-range-picker/calendar/index.tsx index 7292123385..6625cf5680 100644 --- a/src/date-range-picker/calendar/index.tsx +++ b/src/date-range-picker/calendar/index.tsx @@ -52,7 +52,7 @@ export default function DateRangePickerCalendar({ dateInputFormat, customAbsoluteRangeControl, granularity = 'day', - startMonth, + secondaryGrid, }: DateRangePickerCalendarProps) { const isSingleGrid = useMobile(); const isMonthPicker = granularity === 'month'; @@ -67,7 +67,7 @@ export default function DateRangePickerCalendar({ const addPage = isMonthPicker ? addYears : addMonths; const startOfPage = isMonthPicker ? startOfYear : startOfMonth; const findItemToFocus = isMonthPicker ? findMonthToFocus : findDateToFocus; - const [currentPage, setCurrentPage] = useState(() => findPageToDisplay(value, isSingleGrid, startMonth)); + const [currentPage, setCurrentPage] = useState(() => findPageToDisplay(value, isSingleGrid, secondaryGrid)); const [focusedDate, setFocusedDate] = useState(() => { if (value.start.date) { const startDate = parseDate(value.start.date); diff --git a/src/date-range-picker/calendar/interfaces.ts b/src/date-range-picker/calendar/interfaces.ts index 310cac25ed..2fefd5aa98 100644 --- a/src/date-range-picker/calendar/interfaces.ts +++ b/src/date-range-picker/calendar/interfaces.ts @@ -49,7 +49,7 @@ export interface DateRangePickerCalendarProps | 'customAbsoluteRangeControl' | 'isDateEnabled' | 'dateDisabledReason' - | 'startMonth' + | 'secondaryGrid' >, 'absoluteFormat' | 'timeInputFormat' > { diff --git a/src/date-range-picker/calendar/utils.ts b/src/date-range-picker/calendar/utils.ts index 12adbb85b8..ee23b3aef3 100644 --- a/src/date-range-picker/calendar/utils.ts +++ b/src/date-range-picker/calendar/utils.ts @@ -46,7 +46,7 @@ export function findMonthToFocus( export function findMonthToDisplay( value: DateRangePickerProps.PendingAbsoluteValue, isSingleGrid: boolean, - startMonth: DateRangePickerProps.StartMonth | undefined = 'previous' + secondaryGrid: DateRangePickerProps.SecondaryGrid | undefined = 'previous' ) { if (value.start.date) { const startDate = parseDate(value.start.date); @@ -58,7 +58,7 @@ export function findMonthToDisplay( if (value.end.date) { return startOfMonth(parseDate(value.end.date)); } - if (isSingleGrid || startMonth !== 'current') { + if (isSingleGrid || secondaryGrid !== 'next') { return startOfMonth(Date.now()); } return startOfMonth(addMonths(Date.now(), 1)); @@ -67,7 +67,7 @@ export function findMonthToDisplay( export function findYearToDisplay( value: DateRangePickerProps.PendingAbsoluteValue, isSingleGrid: boolean, - startMonth: DateRangePickerProps.StartMonth | undefined = 'previous' + secondaryGrid: DateRangePickerProps.SecondaryGrid | undefined = 'previous' ) { if (value.start.date) { const startDate = parseDate(value.start.date); @@ -79,7 +79,7 @@ export function findYearToDisplay( if (value.end.date) { return startOfYear(parseDate(value.end.date)); } - if (isSingleGrid || startMonth !== 'current') { + if (isSingleGrid || secondaryGrid !== 'next') { return startOfYear(Date.now()); } return startOfYear(addYears(Date.now(), 1)); diff --git a/src/date-range-picker/dropdown.tsx b/src/date-range-picker/dropdown.tsx index 749d1c1369..2f95f79f9f 100644 --- a/src/date-range-picker/dropdown.tsx +++ b/src/date-range-picker/dropdown.tsx @@ -62,7 +62,7 @@ interface DateRangePickerDropdownProps isSingleGrid: boolean; customAbsoluteRangeControl: DateRangePickerProps.AbsoluteRangeControl | undefined; renderRelativeRangeContent: DateRangePickerProps.RelativeRangeControl | undefined; - startMonth: DateRangePickerProps.StartMonth | undefined; + secondaryGrid: DateRangePickerProps.SecondaryGrid | undefined; } export function DateRangePickerDropdown({ @@ -92,7 +92,7 @@ export function DateRangePickerDropdown({ customRelativeRangeUnits, renderRelativeRangeContent, granularity = 'day', - startMonth, + secondaryGrid, }: DateRangePickerDropdownProps) { const i18n = useInternalI18n('date-range-picker'); const isMonthPicker = granularity === 'month'; @@ -218,7 +218,7 @@ export function DateRangePickerDropdown({ dateInputFormat={dateInputFormat} customAbsoluteRangeControl={customAbsoluteRangeControl} granularity={granularity} - startMonth={startMonth} + secondaryGrid={secondaryGrid} /> )} diff --git a/src/date-range-picker/index.tsx b/src/date-range-picker/index.tsx index 2eb322c049..38bd29f062 100644 --- a/src/date-range-picker/index.tsx +++ b/src/date-range-picker/index.tsx @@ -116,7 +116,7 @@ const DateRangePicker = React.forwardRef( customRelativeRangeUnits, renderRelativeRangeContent, granularity = 'day', - startMonth, + secondaryGrid, ...rest }: DateRangePickerProps, ref: Ref @@ -350,7 +350,7 @@ const DateRangePicker = React.forwardRef( customRelativeRangeUnits={customRelativeRangeUnits} renderRelativeRangeContent={renderRelativeRangeContent} granularity={granularity} - startMonth={startMonth} + secondaryGrid={secondaryGrid} /> )} diff --git a/src/date-range-picker/interfaces.ts b/src/date-range-picker/interfaces.ts index 4448b35cb2..d205092630 100644 --- a/src/date-range-picker/interfaces.ts +++ b/src/date-range-picker/interfaces.ts @@ -101,17 +101,20 @@ export interface DateRangePickerBaseProps { timeInputFormat?: DateRangePickerProps.TimeInputFormat; /** - * Determines which month is displayed first (on the left) when the calendar - * opens with two grids visible. + * Determines which period is displayed in the secondary (right) grid + * when the calendar opens with two grids visible. * - * * `previous` (default) – the left grid shows the previous month and the - * right grid shows the current month. - * * `current` – the left grid shows the current month and the right grid - * shows the next month. + * * `previous` (default) – the secondary grid shows the current period, + * and the primary (left) grid shows the previous period. + * * `next` – the secondary grid shows the next period, + * and the primary (left) grid shows the current period. * + * For day granularity, a "period" is a month. For month granularity, a "period" is a year. + * + * When a value is selected, the calendar navigates to the selected date instead. * Has no effect on single-grid (mobile) layout. */ - startMonth?: DateRangePickerProps.StartMonth; + secondaryGrid?: DateRangePickerProps.SecondaryGrid; /** * Fired whenever a user changes the component's value. @@ -311,7 +314,7 @@ export namespace DateRangePickerProps { setSelectedRange: (value: RelativeValue) => void ) => React.ReactNode; - export type StartMonth = 'current' | 'previous'; + export type SecondaryGrid = 'previous' | 'next'; export type RangeSelectorMode = 'default' | 'absolute-only' | 'relative-only';