diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index c1200432a0..d5143aea79 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -68,6 +68,16 @@ export class Datetime implements ComponentInterface { private clearFocusVisible?: () => void; private overlayIsPresenting = false; + /** + * Whether to highlight the active day with a solid circle (as opposed + * to the outline circle around today). If you don't specify an initial + * value for the datetime, it doesn't automatically init to a default to + * avoid unwanted change events firing. If the solid circle were still + * shown then, it would look like a date had already been selected, which + * is misleading UX. + */ + private highlightActiveParts = false; + private parsedMinuteValues?: number[]; private parsedHourValues?: number[]; private parsedMonthValues?: number[]; @@ -1058,6 +1068,7 @@ export class Datetime implements ComponentInterface { }; private processValue = (value?: string | null) => { + this.highlightActiveParts = !!value; const valueToProcess = value || getToday(); const { month, day, year, hour, minute, tzOffset } = parseDate(valueToProcess); @@ -1349,6 +1360,7 @@ export class Datetime implements ComponentInterface { } private renderMonth(month: number, year: number) { + const { highlightActiveParts } = this; const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year); const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month); const isCalMonthDisabled = !yearAllowed || !monthAllowed; @@ -1424,7 +1436,7 @@ export class Datetime implements ComponentInterface { class={{ 'calendar-day-padding': day === null, 'calendar-day': true, - 'calendar-day-active': isActive, + 'calendar-day-active': isActive && highlightActiveParts, 'calendar-day-today': isToday, }} aria-selected={ariaSelected} @@ -1434,6 +1446,14 @@ export class Datetime implements ComponentInterface { return; } + /** + * Note that for datetimes with confirm/cancel buttons, the value + * isn't updated until you call confirm(). We need to bring the + * solid circle back on day click for UX reasons, rather than only + * show the circle if `value` is truthy. + */ + this.highlightActiveParts = true; + this.setWorkingParts({ ...this.workingParts, month, diff --git a/core/src/components/datetime/test/basic/datetime.e2e.ts b/core/src/components/datetime/test/basic/datetime.e2e.ts new file mode 100644 index 0000000000..8b2e5efe45 --- /dev/null +++ b/core/src/components/datetime/test/basic/datetime.e2e.ts @@ -0,0 +1,30 @@ +import { expect } from '@playwright/test'; +import type { E2EPage } from '@utils/test/playwright'; +import { test } from '@utils/test/playwright'; + +test.describe('datetime: selecting a day', () => { + const testHighlight = async (page: E2EPage, datetimeID: string) => { + const today = new Date(); + await page.goto('/src/components/datetime/test/basic'); + + const todayBtn = page.locator( + `#${datetimeID} .calendar-day[data-day='${today.getDate()}'][data-month='${today.getMonth() + 1}']` + ); + + expect(todayBtn).toHaveClass(/calendar-day-today/); + expect(todayBtn).not.toHaveClass(/calendar-day-active/); + + await todayBtn.click(); + await page.waitForChanges(); + + expect(todayBtn).toHaveClass(/calendar-day-active/); + }; + + test('should not highlight a day until one is selected', async ({ page }) => { + await testHighlight(page, 'inline-datetime-no-value'); + }); + + test('should not highlight a day until one is selected, with default-buttons', async ({ page }) => { + await testHighlight(page, 'custom-datetime'); + }); +}); diff --git a/core/src/components/datetime/test/basic/index.html b/core/src/components/datetime/test/basic/index.html index b918590be2..153c85688a 100644 --- a/core/src/components/datetime/test/basic/index.html +++ b/core/src/components/datetime/test/basic/index.html @@ -261,6 +261,11 @@ +
+

Inline - No Default Value

+ +
+

Popover

Present Popover