feat : ajouts du composant input amount

This commit is contained in:
2026-03-03 09:27:28 +01:00
parent ca18f4f3b9
commit 8bf40050e2
2 changed files with 8 additions and 33 deletions

View File

@@ -117,26 +117,26 @@ describe('MalioInputAmount', () => {
expect(wrapper.get('input').element.value).toBe('0.5') expect(wrapper.get('input').element.value).toBe('0.5')
}) })
it('formats the value with two decimals on blur', async () => { it('keeps the normalized decimal value on blur', async () => {
const wrapper = mountInputAmount() const wrapper = mountInputAmount()
const input = wrapper.get('input') const input = wrapper.get('input')
await input.setValue('12.5') await input.setValue('12.5')
await input.trigger('blur') await input.trigger('blur')
expect(wrapper.emitted('update:modelValue')?.[1]).toEqual(['12.50']) expect(wrapper.emitted('update:modelValue')).toEqual([['12.5']])
expect(input.element.value).toBe('12.50') expect(input.element.value).toBe('12.5')
}) })
it('formats integer values with trailing decimals on blur', async () => { it('keeps integer values unchanged on blur', async () => {
const wrapper = mountInputAmount() const wrapper = mountInputAmount()
const input = wrapper.get('input') const input = wrapper.get('input')
await input.setValue('12') await input.setValue('12')
await input.trigger('blur') await input.trigger('blur')
expect(wrapper.emitted('update:modelValue')?.[1]).toEqual(['12.00']) expect(wrapper.emitted('update:modelValue')).toEqual([['12']])
expect(input.element.value).toBe('12.00') expect(input.element.value).toBe('12')
}) })
it('keeps an empty value empty on blur', async () => { it('keeps an empty value empty on blur', async () => {

View File

@@ -176,15 +176,11 @@ const emit = defineEmits<{
(event: 'update:modelValue', value: string): void (event: 'update:modelValue', value: string): void
}>() }>()
// Normalize user input into a decimal amount string using "." as separator.
const normalizeAmount = (value: string) => { const normalizeAmount = (value: string) => {
const sanitizedValue = value const sanitizedValue = value
.replace(/\s+/g, '') .replace(/\s+/g, '')
.replace(/,/g, '.') .replace(/,/g, '.')
.replace(/[^\d.]/g, '') .replace(/[^\d.]/g, '')
// Keep the first decimal separator and collapse the remaining parts into
// the decimal portion, limited to two digits.
const [integerPartRaw = '', ...decimalParts] = sanitizedValue.split('.') const [integerPartRaw = '', ...decimalParts] = sanitizedValue.split('.')
const integerPart = integerPartRaw.replace(/^0+(?=\d)/, '') const integerPart = integerPartRaw.replace(/^0+(?=\d)/, '')
const decimalPart = decimalParts.join('').slice(0, 2) const decimalPart = decimalParts.join('').slice(0, 2)
@@ -196,20 +192,6 @@ const normalizeAmount = (value: string) => {
return integerPart return integerPart
} }
// Apply the final display format when the field loses focus.
// Examples:
// "12" -> "12.00"
// "12.5" -> "12.50"
const formatAmountForBlur = (value: string) => {
const normalizedValue = normalizeAmount(value)
if (!normalizedValue) return ''
const [integerPart = '0', decimalPart = ''] = normalizedValue.split('.')
return `${integerPart}.${decimalPart.padEnd(2, '0').slice(0, 2)}`
}
// Keep the DOM input value, local state, and v-model emission in sync. // Keep the DOM input value, local state, and v-model emission in sync.
const updateValue = (target: HTMLInputElement, value: string) => { const updateValue = (target: HTMLInputElement, value: string) => {
target.value = value target.value = value
@@ -225,16 +207,9 @@ const onInput = (event: Event) => {
updateValue(target, normalizeAmount(target.value)) updateValue(target, normalizeAmount(target.value))
} }
// Finalize the amount format with exactly two decimals on blur. // Keep the blur handler only for focus-driven UI state.
const onBlur = (event: Event) => { const onBlur = () => {
isFocused.value = false isFocused.value = false
const target = event.target as HTMLInputElement
const formattedValue = formatAmountForBlur(target.value)
if (formattedValue !== target.value) {
updateValue(target, formattedValue)
}
} }
const iconInputPaddingClass = computed(() => { const iconInputPaddingClass = computed(() => {