Skip to content

Commit c5fcb94

Browse files
committed
fix negative input issue
1 parent d90febf commit c5fcb94

File tree

6 files changed

+49
-67
lines changed

6 files changed

+49
-67
lines changed

docs/docs/.vuepress/components/BaseInput.vue

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<input
33
:value="modelValue"
4-
type="text"
4+
:type="type"
55
class="shadow-sm rounded-md text-base transition-all disabled:cursor-not-allowed disabled:border-gray-300 disabled:text-gray-300 focus:border-primary focus:ring focus:ring-offset-0 focus:ring-primary focus:ring-opacity-50"
66
@change="$emit('update:modelValue', $event.target.value)"
77
/>
@@ -12,14 +12,18 @@ export default {
1212
name: 'BaseInput',
1313
props: {
1414
modelValue: {
15-
default: undefined,
15+
default: undefined
1616
},
17-
label: {
17+
type: {
1818
type: String,
19-
required: false,
19+
default: 'input'
2020
},
21+
label: {
22+
type: String,
23+
required: false
24+
}
2125
},
22-
emits: ['update:modelValue'],
26+
emits: ['update:modelValue']
2327
}
2428
</script>
2529

docs/docs/.vuepress/components/Number.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ export default {
2424
precision: Number,
2525
minimumFractionDigits: Number,
2626
decimal: String,
27-
min: Number,
28-
max: Number,
27+
min: [Number, String],
28+
max: [Number, String],
2929
separator: String,
3030
prefix: String,
3131
suffix: String

docs/docs/.vuepress/components/PlayGround.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,21 +98,21 @@
9898
<div class="mb-5 min-w-0 grid">
9999
<div class="mb-2 font-medium">Minimum fraction digits</div>
100100
<BaseInput
101-
type="text"
102-
v-model="config.minimumFractionDigits"
101+
type="number"
102+
v-model.number="config.minimumFractionDigits"
103103
/>
104104
</div>
105105
<div class="mb-5 min-w-0 grid">
106106
<div class="mb-2 font-medium">Minimum value</div>
107107
<BaseInput
108-
type="text"
108+
type="number"
109109
v-model.number="config.min"
110110
/>
111111
</div>
112112
<div class="mb-5 min-w-0 grid">
113113
<div class="mb-2 font-medium">Maximum value</div>
114114
<BaseInput
115-
type="text"
115+
type="number"
116116
v-model.number="config.max"
117117
/>
118118
</div>

src/component.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,19 @@ export default defineComponent({
4949
default: () => options.precision
5050
},
5151
minimumFractionDigits: {
52-
type: [Number, Boolean],
52+
type: Number,
5353
default: () => options.minimumFractionDigits
5454
},
5555
decimal: {
5656
type: String,
5757
default: () => options.decimal
5858
},
5959
min: {
60-
type: [Number, Boolean],
60+
type: Number,
6161
default: () => options.min
6262
},
6363
max: {
64-
type: [Number, Boolean],
64+
type: Number,
6565
default: () => options.max
6666
},
6767
separator: {

src/core.ts

Lines changed: 28 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { VNode } from 'vue'
22
import NumberFormat from './number-format'
33

4+
export const MINUS = '-'
5+
46
export type Input = number | string
57

68
export interface Options {
@@ -12,8 +14,8 @@ export interface Options {
1214
minimumFractionDigits: number
1315
prefill: boolean
1416
reverseFill: boolean
15-
min: number
16-
max: number
17+
min?: number
18+
max?: number
1719
nullValue: string
1820
}
1921

@@ -42,32 +44,12 @@ export function cloneDeep(data: object) {
4244
return JSON.parse(JSON.stringify(data))
4345
}
4446

45-
export function getConfig(el: HTMLInputElement) {
46-
return JSON.parse(el.dataset.config as string) as Config
47-
}
48-
49-
export function setConfig(el: HTMLInputElement, config: any) {
50-
el.dataset.config = JSON.stringify(config)
51-
}
52-
53-
/**
54-
* Creates a CustomEvent('input') with detail = { facade: true }
55-
* used as a way to identify our own input event
56-
*/
57-
export function FacadeInputEvent() {
58-
return new CustomEvent('input', {
59-
bubbles: true,
60-
cancelable: true,
61-
detail: { facade: true }
62-
})
63-
}
64-
6547
/**
66-
* Creates a CustomEvent('change') with detail = { facade: true }
67-
* used as a way to identify our own change event
48+
* Creates a CustomEvent with detail = { facade: true }
49+
* used as a way to identify our own event
6850
*/
69-
export function FacadeChangeEvent() {
70-
return new CustomEvent('change', {
51+
export function FacadeEvent(event: string) {
52+
return new CustomEvent(event, {
7153
bubbles: true,
7254
cancelable: true,
7355
detail: { facade: true }
@@ -139,7 +121,7 @@ export function updateValue(el: CustomInputElement, vnode: VNode | null, { emit
139121

140122
// this part needs to be outside the above IF statement for vuetify in firefox
141123
// drawback is that we endup with two's input events in firefox
142-
return emit && el.dispatchEvent(FacadeInputEvent())
124+
return emit && el.dispatchEvent(FacadeEvent('input'))
143125
}
144126
}
145127

@@ -148,7 +130,7 @@ export function updateValue(el: CustomInputElement, vnode: VNode | null, { emit
148130
*
149131
* @param {CustomInputEvent} event The event object
150132
*/
151-
export function inputHandler(event: CustomInputEvent, el?: CustomInputElement) {
133+
export function inputHandler(event: CustomInputEvent) {
152134
const { target, detail } = event
153135

154136
// We dont need to run this method on the event we emit (prevent event loop)
@@ -180,14 +162,14 @@ export function inputHandler(event: CustomInputEvent, el?: CustomInputElement) {
180162

181163
if (oldValue !== target.value) {
182164
target.oldValue = masked
183-
target.dispatchEvent(FacadeInputEvent())
165+
target.dispatchEvent(FacadeEvent('input'))
184166
}
185167
}
186168

187169
/**
188170
* Blur event handler
189171
*/
190-
export function blurHandler(event: Event, el?: CustomInputElement) {
172+
export function blurHandler(event: Event) {
191173
const { target, detail } = event as CustomInputEvent
192174

193175
// We dont need to run this method on the event we emit (prevent event loop)
@@ -201,7 +183,7 @@ export function blurHandler(event: Event, el?: CustomInputElement) {
201183

202184
if (oldValue !== target.value) {
203185
target.oldValue = masked
204-
target.dispatchEvent(FacadeChangeEvent())
186+
target.dispatchEvent(FacadeEvent('change'))
205187
}
206188
}
207189

@@ -210,38 +192,34 @@ export function blurHandler(event: Event, el?: CustomInputElement) {
210192
*/
211193
export function keydownHandler(event: KeyboardEvent, el: CustomInputElement) {
212194
const { options } = el
213-
const regExp = new RegExp(`${options.prefix}|${options.suffix}`, 'g')
195+
const { prefix, suffix, decimal, min, separator } = options as Options
196+
const { key } = event
197+
const regExp = new RegExp(`${prefix}|${suffix}`, 'g')
214198
const newValue = el.value.replace(regExp, '')
215-
const canNegativeInput = options.min < 0
216-
if (([110, 190].includes(event.keyCode) || event.key === options.decimal) && newValue.includes(options.decimal)) {
199+
const canNegativeInput = min === undefined || Number(min) < 0 || Number(min) !== min
200+
if (key === decimal && newValue.includes(decimal)) {
217201
event.preventDefault()
218-
} else if ([109].includes(event.keyCode) && !canNegativeInput) {
202+
} else if (key === MINUS && !canNegativeInput) {
219203
event.preventDefault()
220-
} else if ([8].includes(event.keyCode)) {
204+
} else if (key === 'Backspace') {
221205
// check current cursor position is after separator when backspace key down
222206
const selectionEnd = el.selectionEnd || 0
223207
const character = el.value.slice(selectionEnd - 1, selectionEnd)
224208
const replace = el.value.slice(selectionEnd - 2, selectionEnd)
225-
if (character === options.separator) {
209+
let positionFromEnd = el.value.length - selectionEnd
210+
if ([prefix, MINUS, separator].includes(character)) {
226211
event.preventDefault()
227-
let positionFromEnd = el.value.length - selectionEnd
228-
// remove separator and before character
229-
el.value = el.value.replace(replace, '')
230-
// updated cursor position
231-
if (options.suffix) {
232-
positionFromEnd = Math.max(positionFromEnd, options.suffix.length)
212+
if (character === separator) {
213+
el.value = el.value.replace(replace, '')
214+
} else {
215+
el.value = el.value.replace(RegExp(`${prefix}|${MINUS}`, 'g'), '')
233216
}
217+
positionFromEnd = Math.max(positionFromEnd, suffix.length)
234218
positionFromEnd = el.value.length - positionFromEnd
235-
if (options.prefix) {
236-
positionFromEnd = Math.max(positionFromEnd, options.prefix.length)
237-
}
219+
positionFromEnd = Math.max(positionFromEnd, prefix.length)
238220
updateCursor(el, positionFromEnd)
239221
// trigger input event
240222
el.dispatchEvent(new Event('input'))
241-
} else if ([options.prefix, '-'].includes(character)) {
242-
event.preventDefault()
243-
el.value = ''
244-
el.dispatchEvent(new Event('input'))
245223
}
246224
}
247225
}

src/options.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ export default {
1818
separator: ',',
1919
decimal: '.',
2020
precision: 2,
21-
minimumFractionDigits: null,
21+
minimumFractionDigits: undefined,
2222
prefill: true,
2323
reverseFill: false,
24-
min: null,
25-
max: null,
24+
min: undefined,
25+
max: undefined,
2626
nullValue: ''
2727
}

0 commit comments

Comments
 (0)