JSFiddle - React, Tailwind, and code Playground
by skirtle
HTML
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
<arabic-number-input v-model="phoneNumber"></arabic-number-input>
</div>
<p>
Select text and drag/drop into the input:
</p>
<p>
0123456789
</p>
<p>
abc123def
</p>
JavaScript
const ArabicNumberInput = {
template: `
<input
ref="input"
v-model="inputValue"
@keypress="onKeyPress"
>
`,
props: ['value'],
computed: {
inputValue: {
get () {
return this.value
},
set () {
this.setInputValue(...this.getInputValue().map(this.toArabicNumerals))
}
}
},
methods: {
getInputValue() {
const input = this.$refs.input
const value = input.value
const start = input.selectionStart
const end = input.selectionEnd
return [
value.slice(0, start), // before selection
value.slice(start, end), // selection
value.slice(end) // after selection
]
},
onKeyPress(ev) {
ev.preventDefault()
const [before, , after] = this.getInputValue()
const keyValue = this.toArabicNumerals(ev.key)
this.setInputValue(before + keyValue, '', after)
},
setInputValue(before, selection, after) {
const input = this.$refs.input
const start = before.length
const end = start + selection.length
const value = input.value = before + selection + after
input.setSelectionRange(start, end)
this.$emit('update', value)
},
toArabicNumerals(str) {
return str.split('').map(chr => {
if ('0' <= chr && chr <= '9') {
return String.fromCharCode(+chr + 1632)
}
if ('\u0660' <= chr && chr <= '\u0669') {
return chr
}
return ''
}).join('')
}
}
}
new Vue({
el: '#app',
components: {
ArabicNumberInput
},
data() {
return {
phoneNumber: ''
}
}
})