Skip to content

Commit

Permalink
fix(MultiInputMask): enhance handling of right, left and backspace ke…
Browse files Browse the repository at this point in the history
…y usage (#3192)
  • Loading branch information
tujoworker authored Jan 9, 2024
1 parent c86c857 commit f3ce934
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import React from 'react'
import { act, render } from '@testing-library/react'
import { fireEvent, render } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import MultiInputMask, {
MultiInputMaskInput,
Expand Down Expand Up @@ -54,9 +54,7 @@ describe('MultiInputMask', () => {
'.dnb-multi-input-mask__input'
)[0] as HTMLInputElement

act(() => {
firstInput.focus()
})
fireEvent.focus(firstInput)

await userEvent.keyboard('08122023')

Expand Down Expand Up @@ -238,9 +236,7 @@ describe('MultiInputMask', () => {
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

act(() => {
first.focus()
})
fireEvent.focus(first)

await userEvent.keyboard('11223333')

Expand Down Expand Up @@ -294,10 +290,8 @@ describe('MultiInputMask', () => {
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

act(() => {
first.focus()
first.setSelectionRange(0, 0)
})
fireEvent.focus(first)
first.setSelectionRange(0, 0)

await userEvent.keyboard('fst')

Expand Down Expand Up @@ -357,10 +351,8 @@ describe('MultiInputMask', () => {
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

act(() => {
first.focus()
first.setSelectionRange(0, 0)
})
fireEvent.focus(first)
first.setSelectionRange(0, 0)

expect(first.selectionStart).toBe(0)
expect(first.selectionEnd).toBe(0)
Expand Down Expand Up @@ -528,10 +520,8 @@ describe('MultiInputMask', () => {
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

act(() => {
first.focus()
first.setSelectionRange(0, 0)
})
fireEvent.focus(first)
first.setSelectionRange(0, 0)

expect(first.selectionStart).toBe(0)
expect(first.selectionEnd).toBe(0)
Expand Down Expand Up @@ -563,9 +553,7 @@ describe('MultiInputMask', () => {
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

act(() => {
first.focus()
})
fireEvent.focus(first)

await userEvent.keyboard('11223333')

Expand Down Expand Up @@ -595,22 +583,20 @@ describe('MultiInputMask', () => {
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

act(() => {
first.focus()
first.setSelectionRange(0, 0)
})
fireEvent.focus(first)
first.setSelectionRange(0, 0)

expect(first.selectionStart).toBe(0)
expect(first.selectionEnd).toBe(0)
expect(document.activeElement).toBe(first)

await userEvent.keyboard('{ArrowRight}{ArrowRight}{ArrowRight}')
await userEvent.keyboard('{ArrowRight>3}')

expect(second.selectionStart).toBe(0)
expect(second.selectionEnd).toBe(0)
expect(document.activeElement).toBe(second)

await userEvent.keyboard('{ArrowRight}{ArrowRight}{ArrowRight}')
await userEvent.keyboard('{ArrowRight>3}')

expect(third.selectionStart).toBe(0)
expect(third.selectionEnd).toBe(0)
Expand All @@ -622,31 +608,75 @@ describe('MultiInputMask', () => {
expect(second.selectionEnd).toBe(2)
expect(document.activeElement).toBe(second)

await userEvent.keyboard('{ArrowLeft}{ArrowLeft}{ArrowLeft}')
await userEvent.keyboard('{ArrowLeft>3}')

expect(first.selectionStart).toBe(2)
expect(first.selectionEnd).toBe(2)
expect(document.activeElement).toBe(first)

await userEvent.keyboard(
'{ArrowRight}{ArrowRight}{ArrowRight}{ArrowRight}'
)
await userEvent.keyboard('{ArrowRight>3}{ArrowRight}')

expect(third.selectionStart).toBe(0)
expect(third.selectionEnd).toBe(0)
expect(document.activeElement).toBe(third)
})

it('should set cursor at the start or end of the input when value is selected', async () => {
render(<MultiInputMask {...defaultProps} />)

const [first, second, third] = Array.from(
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

// 1. Test the ArrowRight

fireEvent.focus(first)

expect(document.activeElement).toBe(first)
expect(first.selectionStart).toBe(0)
expect(first.selectionEnd).toBe(2)

await userEvent.keyboard('{ArrowRight}')

expect(document.activeElement).toBe(first)
expect(first.selectionStart).toBe(2)
expect(first.selectionEnd).toBe(2)

await userEvent.keyboard('{ArrowRight}')

expect(document.activeElement).toBe(second)
expect(second.selectionStart).toBe(0)
expect(second.selectionEnd).toBe(0)

// 2. Test the same but with the last input and backspace

fireEvent.focus(third)

expect(document.activeElement).toBe(third)
expect(third.selectionStart).toBe(0)
expect(third.selectionEnd).toBe(4)

await userEvent.keyboard('{Backspace}')

expect(document.activeElement).toBe(third)
expect(third.selectionStart).toBe(0)
expect(third.selectionEnd).toBe(0)

await userEvent.keyboard('{ArrowLeft}')

expect(document.activeElement).toBe(second)
expect(second.selectionStart).toBe(2)
expect(second.selectionEnd).toBe(2)
})

it('should be able to tab between inputs', async () => {
render(<MultiInputMask {...defaultProps} />)

const [first, second, third] = Array.from(
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

act(() => {
first.focus()
})
fireEvent.focus(first)

expect(document.activeElement).toBe(first)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@ function useHandleCursorPosition(
getKeysToHandle({ keysToHandle, input })?.test(pressedKey) ||
/(ArrowRight|ArrowLeft|Backspace)/.test(pressedKey)

const initialSelectionStart = input.selectionStart
const hasSelection = hasSelectedValue(input)

const inputPosition = getInputPosition(input, inputs)
const inputPosition = !hasSelection && getInputPosition(input, inputs)

window.requestAnimationFrame(() => {
const caretPosition = getCaretPosition(input)
const initialSelectionStart = input.selectionStart

if (!hasPressedKeysToHandle) {
window.requestAnimationFrame(() => {
if (!hasPressedKeysToHandle || hasSelection) {
return // stop here
}

const caretPosition = getCaretPosition(input)

if (
caretPosition === 'last' &&
inputPosition !== 'last' &&
Expand Down Expand Up @@ -113,6 +115,10 @@ function getSelectionPositions(input: HTMLInputElement) {
return { start: 0, end: Number(input.size) }
}

function hasSelectedValue(input: HTMLInputElement) {
return input.selectionEnd > input.selectionStart
}

function getCaretPosition(input: HTMLInputElement) {
const { start, end } = getSelectionPositions(input)

Expand Down

0 comments on commit f3ce934

Please sign in to comment.