From c7b8a6890435f8b2adee9fa6a6886b96845bf682 Mon Sep 17 00:00:00 2001 From: Anveshreddy mekala Date: Mon, 17 Jun 2024 17:21:42 -0500 Subject: [PATCH] fix(input-date-picker, input-time-picker): focus input element on `setFocus` (#9584) **Related Issue:** https://github.com/Esri/calcite-design-system/issues/9491 ## Summary Focuses input element on `setFocus` method. --- .../calcite-components/src/components.d.ts | 84 +++++++++++++++++++ .../input-date-picker.e2e.ts | 10 ++- .../input-date-picker.stories.ts | 14 ++++ .../input-date-picker/input-date-picker.tsx | 4 +- .../input-time-picker.e2e.ts | 11 ++- .../input-time-picker.stories.ts | 14 ++++ .../input-time-picker/input-time-picker.tsx | 3 +- 7 files changed, 129 insertions(+), 11 deletions(-) diff --git a/packages/calcite-components/src/components.d.ts b/packages/calcite-components/src/components.d.ts index 47dc8d40b8c..74896a54302 100644 --- a/packages/calcite-components/src/components.d.ts +++ b/packages/calcite-components/src/components.d.ts @@ -1595,6 +1595,46 @@ export namespace Components { */ "startDate"?: Date; } + interface CalciteDatePickerMonthFloatingMenu { + /** + * Active date + */ + "activeDate": Date; + /** + * Defines the available placements that can be used when a flip occurs. + */ + "flipPlacements": FlipPlacement[]; + /** + * CLDR locale data for translated calendar info. + */ + "localeData": DateLocaleData; + /** + * When `true`, month will be abbreviated. + */ + "monthAbbreviations": boolean; + /** + * Whether the component is opened. + */ + "open": boolean; + /** + * Determines the type of positioning to use for the overlaid content. Using `"absolute"` will work for most cases. The component will be positioned inside of overflowing parent containers and will affect the container's layout. `"fixed"` should be used to escape an overflowing parent container, or when the reference element's `position` CSS property is `"fixed"`. + */ + "overlayPositioning": OverlayPositioning; + /** + * Specifies the placement of the `calcite-date-picker` relative to the component. + * @default "bottom-start" + */ + "placement": MenuPlacement; + /** + * Specifies the position of the component in a range date-picker. + */ + "position": "start" | "end"; + /** + * Updates the position of the component. + * @param delayed + */ + "reposition": (delayed?: boolean) => Promise; + } interface CalciteDatePickerMonthHeader { /** * The focused date is indicated and will become the selected date if the user proceeds. @@ -6499,6 +6539,12 @@ declare global { prototype: HTMLCalciteDatePickerMonthElement; new (): HTMLCalciteDatePickerMonthElement; }; + interface HTMLCalciteDatePickerMonthFloatingMenuElement extends Components.CalciteDatePickerMonthFloatingMenu, HTMLStencilElement { + } + var HTMLCalciteDatePickerMonthFloatingMenuElement: { + prototype: HTMLCalciteDatePickerMonthFloatingMenuElement; + new (): HTMLCalciteDatePickerMonthFloatingMenuElement; + }; interface HTMLCalciteDatePickerMonthHeaderElementEventMap { "calciteInternalDatePickerSelect": Date; } @@ -7836,6 +7882,7 @@ declare global { "calcite-date-picker": HTMLCalciteDatePickerElement; "calcite-date-picker-day": HTMLCalciteDatePickerDayElement; "calcite-date-picker-month": HTMLCalciteDatePickerMonthElement; + "calcite-date-picker-month-floating-menu": HTMLCalciteDatePickerMonthFloatingMenuElement; "calcite-date-picker-month-header": HTMLCalciteDatePickerMonthHeaderElement; "calcite-dropdown": HTMLCalciteDropdownElement; "calcite-dropdown-group": HTMLCalciteDropdownGroupElement; @@ -9415,6 +9462,41 @@ declare namespace LocalJSX { */ "startDate"?: Date; } + interface CalciteDatePickerMonthFloatingMenu { + /** + * Active date + */ + "activeDate"?: Date; + /** + * Defines the available placements that can be used when a flip occurs. + */ + "flipPlacements"?: FlipPlacement[]; + /** + * CLDR locale data for translated calendar info. + */ + "localeData"?: DateLocaleData; + /** + * When `true`, month will be abbreviated. + */ + "monthAbbreviations"?: boolean; + /** + * Whether the component is opened. + */ + "open"?: boolean; + /** + * Determines the type of positioning to use for the overlaid content. Using `"absolute"` will work for most cases. The component will be positioned inside of overflowing parent containers and will affect the container's layout. `"fixed"` should be used to escape an overflowing parent container, or when the reference element's `position` CSS property is `"fixed"`. + */ + "overlayPositioning"?: OverlayPositioning; + /** + * Specifies the placement of the `calcite-date-picker` relative to the component. + * @default "bottom-start" + */ + "placement"?: MenuPlacement; + /** + * Specifies the position of the component in a range date-picker. + */ + "position"?: "start" | "end"; + } interface CalciteDatePickerMonthHeader { /** * The focused date is indicated and will become the selected date if the user proceeds. @@ -13782,6 +13864,7 @@ declare namespace LocalJSX { "calcite-date-picker": CalciteDatePicker; "calcite-date-picker-day": CalciteDatePickerDay; "calcite-date-picker-month": CalciteDatePickerMonth; + "calcite-date-picker-month-floating-menu": CalciteDatePickerMonthFloatingMenu; "calcite-date-picker-month-header": CalciteDatePickerMonthHeader; "calcite-dropdown": CalciteDropdown; "calcite-dropdown-group": CalciteDropdownGroup; @@ -13898,6 +13981,7 @@ declare module "@stencil/core" { "calcite-date-picker": LocalJSX.CalciteDatePicker & JSXBase.HTMLAttributes; "calcite-date-picker-day": LocalJSX.CalciteDatePickerDay & JSXBase.HTMLAttributes; "calcite-date-picker-month": LocalJSX.CalciteDatePickerMonth & JSXBase.HTMLAttributes; + "calcite-date-picker-month-floating-menu": LocalJSX.CalciteDatePickerMonthFloatingMenu & JSXBase.HTMLAttributes; "calcite-date-picker-month-header": LocalJSX.CalciteDatePickerMonthHeader & JSXBase.HTMLAttributes; "calcite-dropdown": LocalJSX.CalciteDropdown & JSXBase.HTMLAttributes; "calcite-dropdown-group": LocalJSX.CalciteDropdownGroup & JSXBase.HTMLAttributes; diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts index 80997178aee..316727d037e 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts @@ -10,6 +10,7 @@ import { openClose, renders, t9n, + focusable, } from "../../tests/commonTests"; import { html } from "../../../support/formatting"; import { CSS as MONTH_HEADER_CSS } from "../date-picker-month-header/resources"; @@ -76,6 +77,12 @@ describe("calcite-input-date-picker", () => { t9n("calcite-input-date-picker"); }); + describe("should focus the input when setFocus is called", () => { + focusable(`calcite-input-date-picker`, { + shadowFocusTargetSelector: "calcite-input-text", + }); + }); + async function navigateMonth(page: E2EPage, direction: "previous" | "next"): Promise { const linkIndex = direction === "previous" ? 0 : 1; @@ -717,7 +724,6 @@ describe("calcite-input-date-picker", () => { }); describe("cross-century date values", () => { - async function assertCenturyDateValue(year: number, timezone?: string) { const initialValue = `${year}-03-12`; const page = await newE2EPage(); @@ -748,7 +754,7 @@ describe("calcite-input-date-picker", () => { it("sets value to the clicked day in the 1800s in Zurich timezone", async () => { await assertCenturyDateValue(1850, "Europe/Zurich"); - }); + }); }); }); diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.stories.ts b/packages/calcite-components/src/components/input-date-picker/input-date-picker.stories.ts index 6c16a6b2297..45968206cee 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.stories.ts +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.stories.ts @@ -233,3 +233,17 @@ export const widthSetToBreakpoints_TestOnly = (): string => createBreakpointStories( html``, ); + +export const Focus = (): string => + html` + `; + +Focus.parameters = { + chromatic: { delay: 2000 }, +}; diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx index c18ef55a705..3a4ab680cdc 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx @@ -23,7 +23,7 @@ import { dateToISO, inRange, } from "../../utils/date"; -import { toAriaBoolean } from "../../utils/dom"; +import { focusFirstTabbable, toAriaBoolean } from "../../utils/dom"; import { connectFloatingUI, defaultMenuPlacement, @@ -429,7 +429,7 @@ export class InputDatePicker @Method() async setFocus(): Promise { await componentFocusable(this); - this.el.focus(); + focusFirstTabbable(this.el); } /** diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts index 5e8c5882160..106fcc3cb61 100644 --- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts +++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts @@ -630,15 +630,14 @@ describe("calcite-input-time-picker", () => { await page.setContent(``); const inputTimePicker = await page.find("calcite-input-time-picker"); - await inputTimePicker.callMethod("setFocus"); await page.waitForChanges(); await page.keyboard.press("ArrowLeft"); - await page.keyboard.press("ArrowRight"); - await page.keyboard.press("ArrowRight"); - await page.keyboard.press("ArrowRight"); - await page.keyboard.press("ArrowRight"); - await page.keyboard.press("ArrowRight"); + await page.keyboard.press("ArrowLeft"); + await page.keyboard.press("ArrowLeft"); + await page.keyboard.press("ArrowLeft"); + await page.keyboard.press("ArrowLeft"); + await page.keyboard.press("ArrowLeft"); await page.keyboard.press("Backspace"); await page.keyboard.press("5"); diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.stories.ts b/packages/calcite-components/src/components/input-time-picker/input-time-picker.stories.ts index 7e42b6e62fd..34141650acd 100644 --- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.stories.ts +++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.stories.ts @@ -151,3 +151,17 @@ export const validationMessageAllScales_TestOnly = (): string => html` export const widthSetToBreakpoints_TestOnly = (): string => createBreakpointStories(html``); + +export const Focus = (): string => + html` + `; + +Focus.parameters = { + chromatic: { delay: 2000 }, +}; diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx index d488950a0cc..66d85db2b2c 100644 --- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx +++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx @@ -79,6 +79,7 @@ import { onToggleOpenCloseComponent, OpenCloseComponent } from "../../utils/open import { decimalPlaces } from "../../utils/math"; import { getIconScale } from "../../utils/component"; import { Validation } from "../functional/Validation"; +import { focusFirstTabbable } from "../../utils/dom"; import { CSS } from "./resources"; import { InputTimePickerMessages } from "./assets/input-time-picker/t9n"; @@ -523,7 +524,7 @@ export class InputTimePicker @Method() async setFocus(): Promise { await componentFocusable(this); - this.el.focus(); + focusFirstTabbable(this.el); } /**