fix(PinInput): paste only numeric text in numeric mode#2516
Conversation
📝 WalkthroughWalkthroughSanitizes pasted text for PinInput when type="number" by stripping non-digits before populating inputs; updates input handling logic and adds tests covering mixed alphanumeric paste scenarios and complete-event behavior for both default and numeric variants. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
commit: |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/PinInput/PinInputInput.vue (1)
147-147:⚠️ Potential issue | 🟠 MajorType mismatch: Strings stored instead of numbers in numeric mode.
handleMultipleCharacterstores string values directly intotempModelValue, but whentype="number", the model value type isnumber[]per thePinInputValue<'number'>definition. Compare withupdateModelValueAt(line 175) which correctly converts to numbers withtempModelValue[index] = num.This will cause the
completeevent to emit['1', '2', '3', '4', '5'](strings) instead of[1, 2, 3, 4, 5](numbers) when pasting numeric characters.🐛 Proposed fix to convert values in numeric mode
if (context.isNumericMode.value && !/^\d*$/.test(value)) continue - tempModelValue[i] = value + tempModelValue[i] = context.isNumericMode.value ? +value : value input.focus()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/PinInput/PinInputInput.vue` at line 147, handleMultipleCharacter currently assigns string characters into tempModelValue (tempModelValue[i] = value), causing type mismatch when props.type === 'number'; change the assignment to convert the value to a number in numeric mode (e.g., tempModelValue[i] = props.type === 'number' ? Number(value) : value) following the same conversion pattern used in updateModelValueAt so the emitted model/complete events provide number[] for PinInputValue<'number'>.
🧹 Nitpick comments (1)
packages/core/src/PinInput/PinInputInput.vue (1)
144-145: Consider: residual coupled-counter logic for non-paste paths.This check is now unreachable for paste operations (since
handlePastepre-filters non-digits). However,handleMultipleCharacteris also called fromhandleInput(line 36) for multi-character input events (e.g., autofill). If such input contains mixed characters in numeric mode, the same "counter coupling" bug from issue#2513could manifest there.Low priority since autofill typically sends appropriate data to numeric inputs, but consider applying consistent sanitization at the
handleMultipleCharacterentry point for robustness.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/PinInput/PinInputInput.vue` around lines 144 - 145, handleMultipleCharacter can receive multi-char input from handleInput (e.g., autofill) and currently relies on an unreachable numeric check used only for paste paths; add explicit sanitization at the start of handleMultipleCharacter: when context.isNumericMode.value is true, filter the incoming value to digits only (same /^\d*/ logic) and early-return or transform the value before proceeding, so the counter-coupling bug from mixed characters is avoided; update references in handleInput and handlePaste to pass the sanitized value or rely on the new guard in handleMultipleCharacter.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/core/src/PinInput/PinInput.test.ts`:
- Around line 287-289: Test is asserting string digits while PinInput with
type="number" should emit number[]; update the expectation in PinInput.test.ts
to assert numeric array [1, 2, 3, 4, 5] (i.e., change
expect(wrapper.emitted('complete')?.[0]?.[0]).toStrictEqual(['1','2','3','4','5'])
to expect numbers) and ensure this aligns with the fix in
handleMultipleCharacter so wrapper.emitted('complete') returns number[] for the
'complete' event.
---
Outside diff comments:
In `@packages/core/src/PinInput/PinInputInput.vue`:
- Line 147: handleMultipleCharacter currently assigns string characters into
tempModelValue (tempModelValue[i] = value), causing type mismatch when
props.type === 'number'; change the assignment to convert the value to a number
in numeric mode (e.g., tempModelValue[i] = props.type === 'number' ?
Number(value) : value) following the same conversion pattern used in
updateModelValueAt so the emitted model/complete events provide number[] for
PinInputValue<'number'>.
---
Nitpick comments:
In `@packages/core/src/PinInput/PinInputInput.vue`:
- Around line 144-145: handleMultipleCharacter can receive multi-char input from
handleInput (e.g., autofill) and currently relies on an unreachable numeric
check used only for paste paths; add explicit sanitization at the start of
handleMultipleCharacter: when context.isNumericMode.value is true, filter the
incoming value to digits only (same /^\d*/ logic) and early-return or transform
the value before proceeding, so the counter-coupling bug from mixed characters
is avoided; update references in handleInput and handlePaste to pass the
sanitized value or rely on the new guard in handleMultipleCharacter.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 24f2bb74-8f44-402d-b3d9-e7ef16fd8122
📒 Files selected for processing (2)
packages/core/src/PinInput/PinInput.test.tspackages/core/src/PinInput/PinInputInput.vue
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/PinInput/PinInputInput.vue (1)
140-155:⚠️ Potential issue | 🟠 MajorDecouple value cursor from input cursor to fully prevent numeric shifting
Line 144–150 still advances the input slot when a non-numeric character is skipped, so multi-character non-paste paths can still misalign digits in numeric mode.
Proposed fix
function handleMultipleCharacter(values: string) { const tempModelValue = [...context.currentModelValue.value] as typeof context.currentModelValue.value - const initialIndex = values.length >= inputElements.value.length ? 0 : props.index - const lastIndex = Math.min(initialIndex + values.length, inputElements.value.length) - for (let i = initialIndex; i < lastIndex; i++) { - const input = inputElements.value[i] - const value = values[i - initialIndex] - if (context.isNumericMode.value) { - const num = Number.parseInt(value) - if (Number.isNaN(num)) - continue - tempModelValue[i] = num - } - else { - tempModelValue[i] = value - } - input.focus() - } + const normalizedValues = context.isNumericMode.value + ? values.replace(NON_NUMBER_REG, '') + : values + const initialIndex = normalizedValues.length >= inputElements.value.length ? 0 : props.index + + let inputIndex = initialIndex + let valueIndex = 0 + while (inputIndex < inputElements.value.length && valueIndex < normalizedValues.length) { + const value = normalizedValues[valueIndex] + const input = inputElements.value[inputIndex] + tempModelValue[inputIndex] = context.isNumericMode.value + ? Number(value) + : value + input?.focus() + inputIndex++ + valueIndex++ + } context.modelValue.value = tempModelValue - inputElements.value[lastIndex]?.focus() + inputElements.value[inputIndex]?.focus() }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/PinInput/PinInputInput.vue` around lines 140 - 155, handleMultipleCharacter currently advances the input slot even when a non-numeric character is skipped, causing misalignment in numeric mode; change the loop to decouple the value cursor from the input cursor by using two indices (e.g., slotIndex for inputElements and valueIndex for values) and iterate with a while (slotIndex < lastIndex && valueIndex < values.length) so that when context.isNumericMode.value and Number.parseInt(value) is NaN you only advance valueIndex (skip that character) and do NOT increment slotIndex, and only increment slotIndex when you successfully write into tempModelValue; keep using tempModelValue, inputElements, initialIndex/lastIndex and then write back to context.currentModelValue as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/core/src/PinInput/PinInputInput.vue`:
- Around line 140-155: handleMultipleCharacter currently advances the input slot
even when a non-numeric character is skipped, causing misalignment in numeric
mode; change the loop to decouple the value cursor from the input cursor by
using two indices (e.g., slotIndex for inputElements and valueIndex for values)
and iterate with a while (slotIndex < lastIndex && valueIndex < values.length)
so that when context.isNumericMode.value and Number.parseInt(value) is NaN you
only advance valueIndex (skip that character) and do NOT increment slotIndex,
and only increment slotIndex when you successfully write into tempModelValue;
keep using tempModelValue, inputElements, initialIndex/lastIndex and then write
back to context.currentModelValue as before.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e5d9d0f0-6fa9-41cc-9da0-f7e8c4be9bab
📒 Files selected for processing (2)
packages/core/src/PinInput/PinInput.test.tspackages/core/src/PinInput/PinInputInput.vue
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/core/src/PinInput/PinInput.test.ts
🔗 Linked issue
resolves #2513
❓ Type of change
📚 Description
📸 Screenshots (if appropriate)
📝 Checklist
Summary by CodeRabbit
Bug Fixes
Tests