Skip to content

Commit

Permalink
feat: add focus container styles to last input (#56)
Browse files Browse the repository at this point in the history
* feat: add focus container styles to last input

adds the focus container styles to the last input when the otp is filled and focused

* test: cover scenario with unit test

---------

Co-authored-by: anday013 <anday.ismayilzada@gmail.com>
  • Loading branch information
rob-pathway and anday013 authored May 26, 2024
1 parent 4da4c01 commit d7938f6
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 10 deletions.
14 changes: 8 additions & 6 deletions src/OtpInput/OtpInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useOtpInput } from "./useOtpInput";

export const OtpInput = forwardRef<OtpInputRef, OtpInputProps>((props, ref) => {
const {
models: { text, inputRef, focusedInputIndex, hasCursor },
models: { text, inputRef, focusedInputIndex, isFocused },
actions: { clear, handlePress, handleTextChange, focus, handleFocus, handleBlur },
forms: { setTextWithRef },
} = useOtpInput(props);
Expand Down Expand Up @@ -35,13 +35,13 @@ export const OtpInput = forwardRef<OtpInputRef, OtpInputProps>((props, ref) => {

useImperativeHandle(ref, () => ({ clear, focus, setValue: setTextWithRef }));

const generatePinCodeContainerStyle = (isFocusedInput: boolean, char: string) => {
const generatePinCodeContainerStyle = (isFocusedContainer: boolean, char: string) => {
const stylesArray = [styles.codeContainer, pinCodeContainerStyle];
if (focusColor && isFocusedInput) {
if (focusColor && isFocusedContainer) {
stylesArray.push({ borderColor: focusColor });
}

if (focusedPinCodeContainerStyle && isFocusedInput) {
if (focusedPinCodeContainerStyle && isFocusedContainer) {
stylesArray.push(focusedPinCodeContainerStyle);
}

Expand All @@ -63,14 +63,16 @@ export const OtpInput = forwardRef<OtpInputRef, OtpInputProps>((props, ref) => {
.fill(0)
.map((_, index) => {
const char = text[index];
const isFocusedInput = index === focusedInputIndex && !disabled && Boolean(hasCursor);
const isFocusedInput = index === focusedInputIndex && !disabled && Boolean(isFocused);
const isFilledLastInput = text.length === numberOfDigits && index === text.length - 1;
const isFocusedContainer = isFocusedInput || (isFilledLastInput && Boolean(isFocused))

return (
<Pressable
key={`${char}-${index}`}
disabled={disabled}
onPress={handlePress}
style={generatePinCodeContainerStyle(isFocusedInput, char)}
style={generatePinCodeContainerStyle(isFocusedContainer, char)}
testID="otp-input"
>
{isFocusedInput && !hideStick ? (
Expand Down
10 changes: 10 additions & 0 deletions src/OtpInput/__tests__/OtpInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ describe("OtpInput", () => {
expect(inputs[0]).toHaveStyle({ borderColor: "#000" });
});

test("should set focusColor to border of the last input if all inputs are filled and input is still focused", () => {
renderOtpInput({ focusColor: "red", numberOfDigits: 6 });

const input = screen.getByTestId("otp-input-hidden");
fireEvent.changeText(input, "123456");

const inputs = screen.getAllByTestId("otp-input");
expect(inputs[5]).toHaveStyle({ borderColor: "red" });
});

test("focusedPinCodeContainerStyle should not be overridden by theme", () => {
renderOtpInput({
focusColor: "#000",
Expand Down
8 changes: 4 additions & 4 deletions src/OtpInput/useOtpInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const useOtpInput = ({
autoFocus = true,
}: OtpInputProps) => {
const [text, setText] = useState("");
const [hasCursor, setHasCursor] = useState(autoFocus);
const [isFocused, setIsFocused] = useState(autoFocus);
const inputRef = useRef<TextInput>(null);
const focusedInputIndex = text.length;

Expand Down Expand Up @@ -45,15 +45,15 @@ export const useOtpInput = ({
};

const handleFocus = () => {
setHasCursor(true);
setIsFocused(true);
};

const handleBlur = () => {
setHasCursor(false);
setIsFocused(false);
};

return {
models: { text, inputRef, focusedInputIndex, hasCursor },
models: { text, inputRef, focusedInputIndex, isFocused },
actions: { handlePress, handleTextChange, clear, focus, handleFocus, handleBlur },
forms: { setText, setTextWithRef },
};
Expand Down

0 comments on commit d7938f6

Please sign in to comment.