feat(inputs) : sanitisation email (suppression des espaces + option lowercase)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 11:54:13 +02:00
parent 120020b210
commit 6081f0c90c
2 changed files with 52 additions and 3 deletions
@@ -23,6 +23,7 @@ type InputEmailProps = {
iconPosition?: 'left' | 'right'
iconSize?: string | number
iconColor?: string
lowercase?: boolean
}
const InputEmailForTest = InputEmail as DefineComponent<InputEmailProps>
@@ -235,4 +236,26 @@ describe('MalioInputEmail', () => {
expect(wrapper.get('input').attributes('autocomplete')).toBe('email')
})
it('supprime tous les espaces saisis', async () => {
const wrapper = mountComponent()
await wrapper.get('input').setValue(' a b @ c.com ')
const emits = wrapper.emitted('update:modelValue')!
expect(emits[emits.length - 1]).toEqual(['ab@c.com'])
expect(wrapper.get('input').element.value).toBe('ab@c.com')
})
it('conserve la casse par défaut', async () => {
const wrapper = mountComponent()
await wrapper.get('input').setValue('User@Example.COM')
const emits = wrapper.emitted('update:modelValue')!
expect(emits[emits.length - 1]).toEqual(['User@Example.COM'])
})
it('met en minuscules quand lowercase est vrai', async () => {
const wrapper = mountComponent({lowercase: true})
await wrapper.get('input').setValue('User@Example.COM')
const emits = wrapper.emitted('update:modelValue')!
expect(emits[emits.length - 1]).toEqual(['user@example.com'])
})
})
+29 -3
View File
@@ -86,6 +86,7 @@ const props = withDefaults(
iconPosition?: 'left' | 'right'
iconSize?: string | number
iconColor?: string
lowercase?: boolean
}>(),
{
id: '',
@@ -106,6 +107,7 @@ const props = withDefaults(
success: '',
iconSize: 24,
iconColor: 'text-m-muted',
lowercase: false,
},
)
@@ -170,12 +172,36 @@ const emit = defineEmits<{
(event: 'update:modelValue', value: string): void
}>()
const sanitizeEmail = (v: string) => {
let out = v.replace(/\s+/g, '')
if (props.lowercase) out = out.toLowerCase()
return out
}
const onInput = (event: Event) => {
const target = event.target as HTMLInputElement
if (!isControlled.value) {
localValue.value = target.value
const raw = target.value
const sanitized = sanitizeEmail(raw)
if (sanitized !== raw) {
// `<input type="email">` ne supporte pas l'API de sélection :
// selectionStart vaut null, setSelectionRange lève. On garde défensivement.
const caret = target.selectionStart
target.value = sanitized
if (caret !== null) {
const newCaret = sanitizeEmail(raw.slice(0, caret)).length
try {
target.setSelectionRange(newCaret, newCaret)
} catch {
/* type d'input sans support de sélection — ignore */
}
}
}
emit('update:modelValue', target.value)
if (!isControlled.value) {
localValue.value = sanitized
}
emit('update:modelValue', sanitized)
}
const iconInputPaddingClass = computed(() => {