Skip to content

Commit fc3bc9b

Browse files
committed
[Fix] Empty prefix causes weird behaviour
1 parent ae9e037 commit fc3bc9b

7 files changed

+95
-29
lines changed

src/component.vue

+2-3
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,8 @@ export default defineComponent({
119119
watch(
120120
() => props.modelValue,
121121
(newValue) => {
122-
const number = formatNumber.format(newValue)
123-
if (number !== maskedValue.value) {
124-
maskedValue.value = number
122+
if (emittedValue.value != newValue) {
123+
maskedValue.value = formatNumber.format(newValue)
125124
}
126125
}
127126
)

src/core.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,11 @@ export function updateValue(el: CustomInputElement, vnode: VNode | null, { emit
120120
if (el.value !== masked) {
121121
el.value = masked
122122
}
123-
124-
// this part needs to be outside the above IF statement for vuetify in firefox
125-
// drawback is that we endup with two's input events in firefox
126-
return emit && el.dispatchEvent(InputEvent('input'))
127123
}
124+
125+
// this part needs to be outside the above IF statement for vuetify in firefox
126+
// drawback is that we endup with two's input events in firefox
127+
return emit && el.dispatchEvent(InputEvent('input'))
128128
}
129129

130130
/**
@@ -200,7 +200,7 @@ export function keydownHandler(event: KeyboardEvent, el: CustomInputElement) {
200200
if (newValue.includes(decimal)) {
201201
event.preventDefault()
202202
} else if (!newValue) {
203-
el.value = '0' + decimal
203+
el.value = '0'
204204
// trigger input event
205205
el.dispatchEvent(new Event('input'))
206206
}

src/number-format.ts

+76-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import defaultOptions, { Options } from './options'
2-
import { Input, cloneDeep } from './core'
2+
import { Input, cloneDeep, MINUS } from './core'
33

44
export interface Config {
55
prefix: string
@@ -34,7 +34,12 @@ export default class NumberFormat {
3434
number: Input
3535
isClean: boolean
3636
isCustomDecimal: boolean
37-
preSurRegExp: RegExp
37+
noPreSuffix: boolean
38+
hasPreOrSuffix: boolean
39+
prefix: string
40+
preSufRegExp?: RegExp
41+
prefixRegExp?: RegExp
42+
suffixRegExp?: RegExp
3843
numberRegExp: RegExp
3944
cleanRegExp: RegExp
4045
negativeRegExp: RegExp
@@ -47,14 +52,28 @@ export default class NumberFormat {
4752
this.number = ''
4853
this.isClean = !reverseFill
4954

50-
const escapedPrefix = prefix.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
51-
const escapedSuffix = suffix.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
55+
// Use Negative Medium Space Unicode as default prefix if none provided
56+
const safePrefix = prefix
57+
const safeSuffix = suffix
58+
59+
const escapedPrefix = safePrefix.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
60+
const escapedSuffix = safeSuffix.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
61+
62+
if (escapedPrefix) {
63+
this.prefixRegExp = new RegExp(`^${escapedPrefix}`)
64+
}
65+
66+
if (escapedSuffix) {
67+
this.suffixRegExp = new RegExp(`${escapedSuffix}$`)
68+
}
5269

53-
this.preSurRegExp = new RegExp(`${escapedPrefix}|${escapedSuffix}`, 'g')
70+
this.prefix = prefix
5471
this.numberRegExp = new RegExp(`[^0-9\\${decimal}]+`, 'gi')
5572
this.cleanRegExp = new RegExp('[^0-9]+', 'gi')
5673
this.negativeRegExp = new RegExp('[^0-9\\-]+', 'gi')
5774
this.isCustomDecimal = decimal !== '.'
75+
this.noPreSuffix = !safePrefix && !safeSuffix
76+
this.hasPreOrSuffix = !this.noPreSuffix
5877
}
5978

6079
isNull() {
@@ -70,11 +89,11 @@ export default class NumberFormat {
7089
if (this.input === null || this.input === undefined) {
7190
return ''
7291
}
73-
const hasMinus = this.input.toString().indexOf('-') >= 0
92+
const hasMinus = this.input.toString().indexOf(MINUS) >= 0
7493
if (this.isClean) {
75-
return hasMinus && this.realNumber() > 0 ? '-' : ''
94+
return hasMinus && this.realNumber() > 0 ? MINUS : ''
7695
}
77-
return hasMinus ? '-' : ''
96+
return hasMinus ? MINUS : ''
7897
}
7998

8099
toFixed() {
@@ -88,29 +107,65 @@ export default class NumberFormat {
88107
}
89108

90109
numberOnly(regExp?: RegExp) {
91-
return this.input
92-
?.toString()
93-
.replace(this.preSurRegExp, '')
94-
.replace(regExp || this.numberRegExp, '')
110+
let number = this.input?.toString()
111+
112+
if (this.prefixRegExp) {
113+
number = number.replace(this.prefixRegExp, '')
114+
}
115+
116+
if (this.suffixRegExp) {
117+
number = number.replace(this.suffixRegExp, '')
118+
}
119+
120+
return number.replace(regExp || this.numberRegExp, '')
121+
}
122+
123+
inputWithPreOrSuffix() {
124+
if (this.input && this.prefixRegExp) {
125+
return this.prefixRegExp.test(this.input.toString())
126+
}
127+
128+
if (this.input && this.suffixRegExp) {
129+
return this.suffixRegExp.test(this.input.toString())
130+
}
131+
132+
return true
95133
}
96134

97135
isNegative() {
98-
return this.sign() === '-'
136+
return this.sign() === MINUS
137+
}
138+
139+
isNumber(val?: any) {
140+
return !isNaN(this.toNumber(val || this.input))
99141
}
100142

101143
numbers() {
102-
const { reverseFill, decimal } = this.options
103-
const hasDeciaml = this.input.toString().indexOf(decimal) >= 0
104-
const input = !hasDeciaml && this.isCustomDecimal ? this.input + decimal : this.input
144+
const { reverseFill, decimal, separator } = this.options
105145

106146
if (reverseFill) {
107147
this.number = this.toFixed().replace('.', decimal)
108-
} else if (typeof this.input === 'number') {
109-
this.number = this.parts(this.input.toString().replace('-', ''), '.').join(decimal)
110-
} else if (!isNaN(this.toNumber(input))) {
111-
this.number = this.parts(this.input.replace('-', ''), '.').join(decimal)
112148
} else {
113-
this.number = this.parts(this.numberOnly()).join(decimal)
149+
const number = this.input
150+
?.toString()
151+
.replace(this.prefixRegExp ?? '', '')
152+
.replace(this.suffixRegExp ?? '', '')
153+
.replace(new RegExp(MINUS, 'g'), '')
154+
155+
const hasCustomDecimal = this.input.toString().indexOf(decimal) >= 0 && this.isCustomDecimal
156+
const realNumber = number.replace(new RegExp(`\\${separator}`, 'g'), '').replace(decimal, '.')
157+
158+
if (typeof this.input === 'number') {
159+
this.number = this.parts(number, '.').join(decimal)
160+
} else if (this.isNumber() && !hasCustomDecimal && !this.inputWithPreOrSuffix() && this.hasPreOrSuffix) {
161+
// Only process separator-to-decimal conversion when necessary
162+
this.number = this.parts(number, '.').join(decimal)
163+
} else if (this.isNumber(realNumber) && !hasCustomDecimal && this.inputWithPreOrSuffix() && this.hasPreOrSuffix) {
164+
this.number = this.parts(realNumber, '.').join(decimal)
165+
} else {
166+
// If no custom decimal is detected, do not convert the separator
167+
this.number = this.parts(this.numberOnly()).join(decimal)
168+
}
114169
}
115170

116171
return this.number

tests/unit/number-format.custom.spec.ts

+3
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,7 @@ test('format when options are custom', () => {
3131
expect(numberFormat.format(12345.12345)).toEqual('$12.345,12')
3232
expect(numberFormat.format(12345.54321)).toEqual('$12.345,54')
3333
expect(numberFormat.format(12345.54321)).toEqual('$12.345,54')
34+
35+
expect(numberFormat.format('0,539')).toEqual('$0,54')
36+
expect(numberFormat.format(0.539)).toEqual('$0,54')
3437
})

tests/unit/number-format.custom.unformat.spec.ts

+3
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,7 @@ test('unformat when options are default', () => {
3030
expect(numberFormat.unformat(12345.12345)).toEqual('12345.12')
3131
expect(numberFormat.unformat(12345.54321)).toEqual('12345.54')
3232
expect(numberFormat.unformat(12345.54321)).toEqual('12345.54')
33+
34+
expect(numberFormat.unformat('0,539')).toEqual('0.54')
35+
expect(numberFormat.unformat(0.539)).toEqual('0.54')
3336
})

tests/unit/number-format.default.unformat.spec.ts

+3
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ test('unformat when options are default', () => {
2525
expect(numberFormat.unformat(12345.12345)).toEqual('12345.12')
2626
expect(numberFormat.unformat(12345.54321)).toEqual('12345.54')
2727
expect(numberFormat.unformat(12345.54321)).toEqual('12345.54')
28+
29+
expect(numberFormat.unformat('0.539')).toEqual('0.54')
30+
expect(numberFormat.unformat(0.539)).toEqual('0.54')
2831
})

tests/unit/number-format.spec.ts

+3
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,7 @@ test('test number format: minimumFractionDigits', async () => {
3131
})
3232

3333
expect(number.format('458.2')).toBe('$458.20')
34+
35+
expect(number.format('0.539')).toEqual('$0.539')
36+
expect(number.format(0.539)).toEqual('$0.539')
3437
})

0 commit comments

Comments
 (0)