Skip to content

Commit 446a9df

Browse files
J-MichalekJakub
andauthored
fix(PinInput): issues with deleting numeric values when type is number (#1965)
* fix(PinInput): issues with deleting numeric values when type is number * fix(PinInput): allow 0 as valid value in numeric mode * test(pin-input): add more cases for type number * refactor(pin-input-input): remove unused computed --------- Co-authored-by: Jakub <jakub.michalek@freelo.io>
1 parent 62a4ee7 commit 446a9df

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

packages/core/src/PinInput/PinInput.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,5 +217,39 @@ describe('give PinInput type=number', async () => {
217217
it('should emit \'complete\' with the result', () => {
218218
expect(wrapper.emitted('complete')?.[0]?.[0]).toStrictEqual([1, 2, 3, 4, 5])
219219
})
220+
221+
it('should delete the last input when pressing Backspace', async () => {
222+
await inputs[4].trigger('keydown', { key: 'Backspace' })
223+
expect(inputs[4].element).toBe(document.activeElement)
224+
expect(inputs.map(i => i.element.value)).toStrictEqual(['1', '2', '3', '4', ''])
225+
})
226+
227+
it('should delete all values input when pressing Backspace for each input', async () => {
228+
// Delete the last value
229+
await inputs[4].trigger('keydown', { key: 'Backspace' })
230+
// Press again to move focus to the previous input
231+
await inputs[4].trigger('keydown', { key: 'Backspace' })
232+
await inputs[3].trigger('keydown', { key: 'Backspace' })
233+
await inputs[2].trigger('keydown', { key: 'Backspace' })
234+
await inputs[1].trigger('keydown', { key: 'Backspace' })
235+
await inputs[0].trigger('keydown', { key: 'Backspace' })
236+
237+
expect(inputs[0].element).toBe(document.activeElement)
238+
expect(inputs.map(i => i.element.value)).toStrictEqual(['', '', '', '', ''])
239+
})
240+
})
241+
242+
describe('after user input numeric word consisting only of zeros', () => {
243+
beforeEach(async () => {
244+
await userEvent.keyboard('00000')
245+
})
246+
247+
it('should populate the word in each box', () => {
248+
expect(inputs.map(i => i.element.value)).toStrictEqual(['0', '0', '0', '0', '0'])
249+
})
250+
251+
it('should emit \'complete\' with the result', () => {
252+
expect(wrapper.emitted('complete')?.[0]?.[0]).toStrictEqual([0, 0, 0, 0, 0])
253+
})
220254
})
221255
})

packages/core/src/PinInput/PinInputInput.vue

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ const currentValue = computed(() => context.currentModelValue.value[props.index]
2626
2727
const disabled = computed(() => props.disabled || context.disabled.value)
2828
const isOtpMode = computed(() => context.otp.value)
29-
const isNumericMode = computed(() => context.type.value === 'number')
3029
const isPasswordMode = computed(() => context.mask.value)
3130
3231
const { primitiveElement, currentElement } = usePrimitiveElement()
@@ -38,7 +37,7 @@ function handleInput(event: InputEvent) {
3837
return
3938
}
4039
41-
if (isNumericMode.value && !/^\d*$/.test(target.value)) {
40+
if (context.isNumericMode.value && !/^\d*$/.test(target.value)) {
4241
target.value = target.value.replace(/\D/g, '')
4342
return
4443
}
@@ -122,7 +121,7 @@ function handleMultipleCharacter(values: string) {
122121
for (let i = initialIndex; i < lastIndex; i++) {
123122
const input = inputElements.value[i]
124123
const value = values[i - initialIndex]
125-
if (isNumericMode.value && !/^\d*$/.test(value))
124+
if (context.isNumericMode.value && !/^\d*$/.test(value))
126125
continue
127126
128127
tempModelValue[i] = value
@@ -145,7 +144,21 @@ function removeTrailingEmptyStrings(input: PinInputValue<typeof context.type.val
145144
146145
function updateModelValueAt(index: number, value: string) {
147146
const tempModelValue = [...context.currentModelValue.value] as PinInputValue<typeof context.type.value>
148-
tempModelValue[index] = isNumericMode.value ? +value : value
147+
148+
if (context.isNumericMode.value) {
149+
const num = +value
150+
151+
if (value === '' || isNaN(num)) {
152+
delete tempModelValue[index]
153+
}
154+
else {
155+
tempModelValue[index] = num
156+
}
157+
}
158+
else {
159+
tempModelValue[index] = value
160+
}
161+
149162
context.modelValue.value = removeTrailingEmptyStrings(tempModelValue)
150163
}
151164
@@ -171,8 +184,8 @@ onUnmounted(() => {
171184
:as-child="asChild"
172185
:autocomplete="isOtpMode ? 'one-time-code' : 'false'"
173186
:type="isPasswordMode ? 'password' : 'text'"
174-
:inputmode="isNumericMode ? 'numeric' : 'text'"
175-
:pattern="isNumericMode ? '[0-9]*' : undefined"
187+
:inputmode="context.isNumericMode.value ? 'numeric' : 'text'"
188+
:pattern="context.isNumericMode.value ? '[0-9]*' : undefined"
176189
:placeholder="context.placeholder.value"
177190
:value="currentValue"
178191
:disabled="disabled"

packages/core/src/PinInput/PinInputRoot.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export interface PinInputRootContext<Type extends PinInputType = 'text'> {
4949
isCompleted: ComputedRef<boolean>
5050
inputElements?: Ref<Set<HTMLInputElement>>
5151
onInputElementChange: (el: HTMLInputElement) => void
52+
isNumericMode: ComputedRef<boolean>
5253
}
5354
5455
export const [injectPinInputRootContext, providePinInputRootContext]
@@ -92,8 +93,9 @@ function onInputElementChange(el: HTMLInputElement) {
9293
inputElements.value.add(el)
9394
}
9495
96+
const isNumericMode = computed(() => props.type === 'number')
9597
const isCompleted = computed(() => {
96-
const modelValues = currentModelValue.value.filter(i => !!i)
98+
const modelValues = currentModelValue.value.filter(i => !!i || (isNumericMode.value && i === 0))
9799
return modelValues.length === inputElements.value.size
98100
})
99101
@@ -114,6 +116,7 @@ providePinInputRootContext({
114116
isCompleted,
115117
inputElements,
116118
onInputElementChange,
119+
isNumericMode,
117120
})
118121
</script>
119122

0 commit comments

Comments
 (0)