diff --git a/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts b/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts new file mode 100644 index 000000000000..58b2625e46c3 --- /dev/null +++ b/app/client/src/widgets/BaseInputWidget/component/__tests__/getInputMode.test.ts @@ -0,0 +1,21 @@ +import { InputMode } from "../../constants"; +import { getInputMode } from "../index"; + +describe("getInputMode", () => { + it('maps NUMBER to InputMode.DECIMAL ("decimal")', () => { + expect(getInputMode("NUMBER")).toBe(InputMode.DECIMAL); + }); + + it('maps TEL to InputMode.TEL ("tel")', () => { + expect(getInputMode("TEL")).toBe(InputMode.TEL); + }); + + it('maps EMAIL to InputMode.EMAIL ("email")', () => { + expect(getInputMode("EMAIL")).toBe(InputMode.EMAIL); + }); + + it("returns undefined for default/unknown type", () => { + expect(getInputMode()).toBeUndefined(); + expect(getInputMode("TEXT")).toBeUndefined(); + }); +}); \ No newline at end of file diff --git a/app/client/src/widgets/BaseInputWidget/component/index.tsx b/app/client/src/widgets/BaseInputWidget/component/index.tsx index 7675510ac32d..b7f1f1a51986 100644 --- a/app/client/src/widgets/BaseInputWidget/component/index.tsx +++ b/app/client/src/widgets/BaseInputWidget/component/index.tsx @@ -17,8 +17,8 @@ import { createMessage, INPUT_WIDGET_DEFAULT_VALIDATION_ERROR, } from "ee/constants/messages"; +import { InputMode, InputTypes } from "../constants"; import type { NumberInputStepButtonPosition } from "../constants"; -import { InputTypes } from "../constants"; // TODO(abhinav): All of the following imports should not be in widgets. import ErrorTooltip from "components/editorComponents/ErrorTooltip"; @@ -424,6 +424,26 @@ export const isNumberInputType = (inputHTMLType: InputHTMLType = "TEXT") => { return inputHTMLType === "NUMBER"; }; +/** + * Maps input type to appropriate HTML5 inputmode attribute for mobile keyboards + * Provides optimal keyboard experience across iOS and Android + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode + */ +export const getInputMode = ( + inputType: InputHTMLType = "TEXT", +): InputMode | undefined => { + switch (inputType) { + case "NUMBER": + return InputMode.DECIMAL; + case "TEL": + return InputMode.TEL; + case "EMAIL": + return InputMode.EMAIL; + default: + return undefined; + } +}; + class BaseInputComponent extends React.Component< BaseInputComponentProps, InputComponentState @@ -500,6 +520,12 @@ class BaseInputComponent extends React.Component< } } + private getInputMode = ( + inputType: InputHTMLType = "TEXT", + ): InputMode | undefined => { + return getInputMode(inputType); + }; + onKeyDownTextArea = (e: React.KeyboardEvent) => { const isEnterKey = e.key === "Enter" || e.keyCode === 13; @@ -606,6 +632,7 @@ class BaseInputComponent extends React.Component< (this.props.rtl ? " rtl" : "") } disabled={this.props.disabled} + inputMode={this.getInputMode(this.props.inputHTMLType)} inputRef={this.props.inputRef as IRef} intent={this.props.intent} leftIcon={this.getLeftIcon()} diff --git a/app/client/src/widgets/BaseInputWidget/constants.ts b/app/client/src/widgets/BaseInputWidget/constants.ts index 0e678e8181cb..55906ac3694b 100644 --- a/app/client/src/widgets/BaseInputWidget/constants.ts +++ b/app/client/src/widgets/BaseInputWidget/constants.ts @@ -6,6 +6,7 @@ export enum InputTypes { EMAIL = "EMAIL", PASSWORD = "PASSWORD", CURRENCY = "CURRENCY", + NONE = "none", } export enum NumberInputStepButtonPosition { @@ -13,3 +14,26 @@ export enum NumberInputStepButtonPosition { RIGHT = "right", NONE = "none", } + +/** + * HTML5 inputmode attribute values + * Controls the virtual keyboard displayed on mobile devices + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode + */ +export enum InputMode { + // Shows numeric keypad with 0-9 + NUMERIC = "numeric", + NONE = "none", + // Shows numeric keypad with 0-9 and decimal point (.) + DECIMAL = "decimal", + // Shows phone keypad with 0-9, *, # and standard dial keys + TEL = "tel", + // Shows email keyboard with @, period, and other email-related keys + EMAIL = "email", + // Shows default text keyboard + TEXT = "text", + // Shows search optimized keyboard + SEARCH = "search", + // Shows URL optimized keyboard with / and .com + URL = "url", +} diff --git a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx index 38ffef709236..e6371e4ea489 100644 --- a/app/client/src/widgets/CurrencyInputWidget/component/index.tsx +++ b/app/client/src/widgets/CurrencyInputWidget/component/index.tsx @@ -48,7 +48,7 @@ class CurrencyInputComponent extends React.Component