diff --git a/README.MD b/README.MD index 55d143b..6dfb868 100644 --- a/README.MD +++ b/README.MD @@ -75,6 +75,11 @@ yarn add react-native-otp-entry textInputProps={{ accessibilityLabel: "One-Time Password", }} + textProps={{ + accessibilityRole: "text", + accessibilityLabel: "OTP digit", + allowFontScaling: false, + }} theme={{ containerStyle: styles.container, pinCodeContainerStyle: styles.pinCodeContainer, @@ -97,6 +102,7 @@ The `react-native-otp-entry` component accepts the following props: | `numberOfDigits` | number | The number of digits to be displayed in the OTP entry. | | `theme` | Theme | Custom styles for each element. (See below) | | `textInputProps` | TextInputProps | Extra props passed to underlying hidden TextInput (see: ) | +| `textProps` | TextProps | Props passed to the Text component that renders each digit (see: ) | | `autoFocus` | boolean | _Default: true_. Sets autofocus. | | `focusColor` | ColorValue | The color of the input field border and stick when it is focused. | | `placeholder` | string | Placeholder value to the input. | diff --git a/src/OtpInput/OtpInput.tsx b/src/OtpInput/OtpInput.tsx index 482cb88..55c14b6 100644 --- a/src/OtpInput/OtpInput.tsx +++ b/src/OtpInput/OtpInput.tsx @@ -22,6 +22,7 @@ export const OtpInput = forwardRef((props, ref) => { secureTextEntry = false, theme = {}, textInputProps, + textProps, type = "numeric", } = props; const { @@ -91,10 +92,13 @@ export const OtpInput = forwardRef((props, ref) => { /> ) : ( {char && secureTextEntry ? "•" : char} diff --git a/src/OtpInput/OtpInput.types.ts b/src/OtpInput/OtpInput.types.ts index a1fa77f..85da6e0 100644 --- a/src/OtpInput/OtpInput.types.ts +++ b/src/OtpInput/OtpInput.types.ts @@ -1,4 +1,4 @@ -import { ColorValue, TextInputProps, TextStyle, ViewStyle } from "react-native"; +import { ColorValue, TextInputProps, TextProps, TextStyle, ViewStyle } from "react-native"; export interface OtpInputProps { numberOfDigits?: number; @@ -15,6 +15,7 @@ export interface OtpInputProps { theme?: Theme; disabled?: boolean; textInputProps?: TextInputProps; + textProps?: TextProps; type?: "alpha" | "numeric" | "alphanumeric"; placeholder?: string; } diff --git a/src/OtpInput/__tests__/OtpInput.test.tsx b/src/OtpInput/__tests__/OtpInput.test.tsx index 2146b30..fdfe1da 100644 --- a/src/OtpInput/__tests__/OtpInput.test.tsx +++ b/src/OtpInput/__tests__/OtpInput.test.tsx @@ -164,6 +164,56 @@ describe("OtpInput", () => { expect(inputs[0]).toHaveStyle({ borderBottomColor: "red" }); }); + test("should pass textProps to Text component", () => { + renderOtpInput({ + numberOfDigits: 3, + textProps: { + testID: "custom-text-id", + numberOfLines: 1, + accessibilityLabel: "OTP digit", + allowFontScaling: false, + }, + }); + + const input = screen.getByTestId("otp-input-hidden"); + fireEvent.changeText(input, "123"); + + ["1", "2", "3"].forEach((digit, index) => { + const digitElement = screen.getByTestId(`custom-text-id-${index}`); + expect(digitElement).toBeTruthy(); + expect(digitElement.props.numberOfLines).toBe(1); + expect(digitElement.props.accessibilityLabel).toBe("OTP digit"); + expect(digitElement.props.allowFontScaling).toBe(false); + expect(digitElement).toHaveTextContent(digit); + }); + }); + + test("should correctly merge textProps with theme styles", () => { + renderOtpInput({ + numberOfDigits: 2, + textProps: { + testID: "custom-styled-text", + style: { fontWeight: "bold" }, + }, + theme: { + pinCodeTextStyle: { fontSize: 20, color: "blue" }, + }, + }); + + const input = screen.getByTestId("otp-input-hidden"); + fireEvent.changeText(input, "12"); + const textElement = screen.getByTestId("custom-styled-text-0"); + // Check that our custom style from textProps.style is applied + const styles = textElement.props.style; + const customStyleApplied = styles.some((style: any) => style.fontWeight === "bold"); + expect(customStyleApplied).toBe(true); + // Check that theme styles are also applied + const themeStyleApplied = styles.some( + (style: any) => style.fontSize === 20 && style.color === "blue" + ); + expect(themeStyleApplied).toBe(true); + }); + test('autoComplete should be set "sms-otp" on Android', () => { Platform.OS = "android"; renderOtpInput(); @@ -361,7 +411,7 @@ describe("OtpInput", () => { const input = screen.getByTestId("otp-input-hidden"); const otherInput = screen.getByTestId("other-input"); fireEvent.press(input); - // Blur the input + fireEvent.changeText(input, ""); fireEvent.press(otherInput); const inputs = screen.getAllByTestId("otp-input"); @@ -379,7 +429,6 @@ describe("OtpInput", () => { const otherInput = screen.getByTestId("other-input"); fireEvent.press(input); fireEvent.changeText(input, "123456"); - // Blur the input fireEvent.press(otherInput); const placeholder = screen.queryByText("000000"); diff --git a/src/OtpInput/__tests__/__snapshots__/OtpInput.test.tsx.snap b/src/OtpInput/__tests__/__snapshots__/OtpInput.test.tsx.snap index b6c5818..ffe54ed 100644 --- a/src/OtpInput/__tests__/__snapshots__/OtpInput.test.tsx.snap +++ b/src/OtpInput/__tests__/__snapshots__/OtpInput.test.tsx.snap @@ -143,6 +143,7 @@ exports[`OtpInput UI should render correctly 1`] = ` }, undefined, {}, + undefined, ] } /> @@ -201,6 +202,7 @@ exports[`OtpInput UI should render correctly 1`] = ` }, undefined, {}, + undefined, ] } /> @@ -259,6 +261,7 @@ exports[`OtpInput UI should render correctly 1`] = ` }, undefined, {}, + undefined, ] } /> @@ -317,6 +320,7 @@ exports[`OtpInput UI should render correctly 1`] = ` }, undefined, {}, + undefined, ] } /> @@ -375,6 +379,7 @@ exports[`OtpInput UI should render correctly 1`] = ` }, undefined, {}, + undefined, ] } /> diff --git a/src/index.d.ts b/src/index.d.ts index 565522d..3c93345 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,5 +1,5 @@ declare module "OTPInput" { - import { ColorValue, TextInputProps, TextStyle, ViewStyle } from "react-native"; + import { ColorValue, TextInputProps, TextProps, TextStyle, ViewStyle } from "react-native"; export interface OtpEntryProps { /** @@ -74,6 +74,12 @@ declare module "OTPInput" { */ textInputProps?: TextInputProps; + /** + * Additional props to be passed to the `Text` component that renders each digit. + * Allows customizing text behavior beyond styling (which is handled by pinCodeTextStyle in theme). + */ + textProps?: TextProps; + /** * The type of characters allowed in the OTP entry. */