@vuetify/nightly 3.9.5-dev.2025-08-23 → 3.9.5-dev.2025-08-24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -3
- package/dist/json/attributes.json +2028 -2028
- package/dist/json/importMap-labs.json +40 -40
- package/dist/json/importMap.json +180 -180
- package/dist/json/web-types.json +3842 -3842
- package/dist/vuetify-labs.cjs +133 -36
- package/dist/vuetify-labs.css +3910 -3910
- package/dist/vuetify-labs.d.ts +92 -92
- package/dist/vuetify-labs.esm.js +133 -36
- package/dist/vuetify-labs.esm.js.map +1 -1
- package/dist/vuetify-labs.js +133 -36
- package/dist/vuetify-labs.min.css +2 -2
- package/dist/vuetify.cjs +16 -3
- package/dist/vuetify.cjs.map +1 -1
- package/dist/vuetify.css +4850 -4850
- package/dist/vuetify.d.ts +71 -71
- package/dist/vuetify.esm.js +16 -3
- package/dist/vuetify.esm.js.map +1 -1
- package/dist/vuetify.js +16 -3
- package/dist/vuetify.js.map +1 -1
- package/dist/vuetify.min.css +2 -2
- package/dist/vuetify.min.js +15 -14
- package/dist/vuetify.min.js.map +1 -1
- package/lib/composables/filter.d.ts +1 -0
- package/lib/composables/filter.js +13 -0
- package/lib/composables/filter.js.map +1 -1
- package/lib/entry-bundler.js +1 -1
- package/lib/framework.d.ts +71 -71
- package/lib/framework.js +1 -1
- package/lib/labs/VMaskInput/VMaskInput.d.ts +22 -21
- package/lib/labs/VMaskInput/VMaskInput.js +118 -34
- package/lib/labs/VMaskInput/VMaskInput.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { makeVTextFieldProps, VTextField } from "../../components/VTextField/VTe
|
|
|
4
4
|
import { forwardRefs } from "../../composables/forwardRefs.js";
|
|
5
5
|
import { isMaskDelimiter, makeMaskProps, useMask } from "../../composables/mask/index.js";
|
|
6
6
|
import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities
|
|
7
|
-
import { computed, onBeforeMount, ref, shallowRef, toRef } from 'vue';
|
|
7
|
+
import { computed, nextTick, onBeforeMount, ref, shallowRef, toRef } from 'vue';
|
|
8
8
|
import { genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
|
|
9
9
|
export const makeVMaskInputProps = propsFactory({
|
|
10
10
|
returnMaskedValue: Boolean,
|
|
@@ -23,59 +23,140 @@ export const VMaskInput = genericComponent()({
|
|
|
23
23
|
emit
|
|
24
24
|
} = _ref;
|
|
25
25
|
const vTextFieldRef = ref();
|
|
26
|
-
const
|
|
27
|
-
const
|
|
26
|
+
const inputAction = shallowRef();
|
|
27
|
+
const caretPosition = shallowRef(0);
|
|
28
28
|
const mask = useMask(props);
|
|
29
29
|
const returnMaskedValue = computed(() => props.mask && props.returnMaskedValue);
|
|
30
30
|
const model = useProxiedModel(props, 'modelValue', undefined,
|
|
31
31
|
// Always display masked value in input when mask is applied
|
|
32
32
|
val => props.mask ? mask.mask(mask.unmask(val)) : val, val => {
|
|
33
33
|
if (props.mask) {
|
|
34
|
-
const
|
|
34
|
+
const valueWithoutDelimiters = removeMaskDelimiters(val);
|
|
35
|
+
|
|
35
36
|
// E.g. mask is #-# and the input value is '2-23'
|
|
36
37
|
// model-value should be enforced to '2-2'
|
|
37
|
-
const
|
|
38
|
-
const newUnmaskedValue = mask.unmask(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
const newMaskedValue = mask.mask(valueWithoutDelimiters);
|
|
39
|
+
const newUnmaskedValue = mask.unmask(newMaskedValue);
|
|
40
|
+
const newCaretPosition = getNewCaretPosition({
|
|
41
|
+
oldValue: model.value,
|
|
42
|
+
newValue: newMaskedValue,
|
|
43
|
+
oldCaret: caretPosition.value
|
|
44
|
+
});
|
|
45
|
+
vTextFieldRef.value.value = newMaskedValue;
|
|
46
|
+
vTextFieldRef.value.setSelectionRange(newCaretPosition, newCaretPosition);
|
|
47
|
+
return returnMaskedValue.value ? mask.mask(newUnmaskedValue) : newUnmaskedValue;
|
|
45
48
|
}
|
|
46
49
|
return val;
|
|
47
50
|
});
|
|
48
51
|
const validationValue = toRef(() => returnMaskedValue.value ? model.value : mask.unmask(model.value));
|
|
52
|
+
function removeMaskDelimiters(val) {
|
|
53
|
+
return val.split('').filter(ch => !isMaskDelimiter(ch)).join('');
|
|
54
|
+
}
|
|
55
|
+
function getNewCaretPosition(_ref2) {
|
|
56
|
+
let {
|
|
57
|
+
oldValue,
|
|
58
|
+
newValue,
|
|
59
|
+
oldCaret
|
|
60
|
+
} = _ref2;
|
|
61
|
+
if (!newValue) return 0;
|
|
62
|
+
if (!oldValue) return newValue.length;
|
|
63
|
+
let newCaret;
|
|
64
|
+
if (inputAction.value === 'Backspace') {
|
|
65
|
+
newCaret = oldCaret - 1;
|
|
66
|
+
while (newCaret > 0 && isMaskDelimiter(newValue[newCaret - 1])) newCaret--;
|
|
67
|
+
} else if (inputAction.value === 'Delete') {
|
|
68
|
+
newCaret = oldCaret;
|
|
69
|
+
} else {
|
|
70
|
+
// insertion
|
|
71
|
+
newCaret = oldCaret + 1;
|
|
72
|
+
while (isMaskDelimiter(newValue[newCaret])) newCaret++;
|
|
73
|
+
if (isMaskDelimiter(newValue[oldCaret])) newCaret++;
|
|
74
|
+
}
|
|
75
|
+
return newCaret;
|
|
76
|
+
}
|
|
49
77
|
onBeforeMount(() => {
|
|
50
78
|
if (props.returnMaskedValue) {
|
|
51
79
|
emit('update:modelValue', model.value);
|
|
52
80
|
}
|
|
53
81
|
});
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
82
|
+
function onKeyDown(e) {
|
|
83
|
+
if (e.metaKey) return;
|
|
84
|
+
const inputElement = e.target;
|
|
85
|
+
caretPosition.value = inputElement.selectionStart || 0;
|
|
86
|
+
inputAction.value = e.key;
|
|
87
|
+
const hasSelection = inputElement.selectionStart !== inputElement.selectionEnd;
|
|
88
|
+
if (e.key === 'Backspace' && hasSelection) {
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
deleteSelection(e);
|
|
91
|
+
}
|
|
57
92
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
93
|
+
async function onCut(e) {
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
copySelectionToClipboard(e);
|
|
96
|
+
deleteSelection(e);
|
|
97
|
+
}
|
|
98
|
+
async function onPaste(e) {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
const inputElement = e.target;
|
|
101
|
+
const pastedString = removeMaskDelimiters(e.clipboardData?.getData('text') || '');
|
|
102
|
+
if (!pastedString) return;
|
|
103
|
+
const pastedCharacters = [...pastedString];
|
|
104
|
+
const hasSelection = inputElement.selectionStart !== inputElement.selectionEnd;
|
|
105
|
+
if (hasSelection) {
|
|
106
|
+
replaceSelection(inputElement, pastedCharacters);
|
|
107
|
+
} else {
|
|
108
|
+
insertCharacters(inputElement, pastedCharacters);
|
|
64
109
|
}
|
|
65
110
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
111
|
+
function copySelectionToClipboard(e) {
|
|
112
|
+
const inputElement = e.target;
|
|
113
|
+
const start = inputElement.selectionStart || 0;
|
|
114
|
+
const end = inputElement.selectionEnd || 0;
|
|
115
|
+
const selectedText = inputElement.value.substring(start, end);
|
|
116
|
+
navigator.clipboard.writeText(selectedText);
|
|
117
|
+
}
|
|
118
|
+
async function deleteSelection(e) {
|
|
119
|
+
const inputElement = e.target;
|
|
120
|
+
const curStart = inputElement.selectionStart || 0;
|
|
121
|
+
caretPosition.value = inputElement.selectionEnd || 0;
|
|
122
|
+
while (caretPosition.value > curStart) {
|
|
123
|
+
const success = await simulateBackspace(inputElement);
|
|
124
|
+
if (!success) break;
|
|
77
125
|
}
|
|
78
|
-
|
|
126
|
+
}
|
|
127
|
+
async function simulateBackspace(inputElement) {
|
|
128
|
+
inputAction.value = 'Backspace';
|
|
129
|
+
model.value = inputElement.value.slice(0, caretPosition.value - 1) + inputElement.value.slice(caretPosition.value);
|
|
130
|
+
inputAction.value = '';
|
|
131
|
+
if (caretPosition.value === inputElement.selectionEnd) return false;
|
|
132
|
+
caretPosition.value = inputElement.selectionEnd || 0;
|
|
133
|
+
await nextTick();
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
async function insertCharacters(inputElement, pastedCharacters) {
|
|
137
|
+
for (let i = 0; i < pastedCharacters.length; i++) {
|
|
138
|
+
await insertCharacter(inputElement, pastedCharacters[i]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function insertCharacter(inputElement, character) {
|
|
142
|
+
caretPosition.value = inputElement.selectionEnd || 0;
|
|
143
|
+
model.value = inputElement.value.slice(0, caretPosition.value) + character + inputElement.value.slice(caretPosition.value);
|
|
144
|
+
await nextTick();
|
|
145
|
+
}
|
|
146
|
+
async function replaceSelection(inputElement, pastedCharacters) {
|
|
147
|
+
caretPosition.value = inputElement.selectionStart || 0;
|
|
148
|
+
for (let i = 0; i < pastedCharacters.length; i++) {
|
|
149
|
+
await replaceCharacter(caretPosition.value, pastedCharacters[i]);
|
|
150
|
+
caretPosition.value++;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function replaceCharacter(index, character) {
|
|
154
|
+
let targetIndex = index;
|
|
155
|
+
|
|
156
|
+
// Find next non-delimiter position
|
|
157
|
+
while (targetIndex < model.value.length && isMaskDelimiter(model.value[targetIndex])) targetIndex++;
|
|
158
|
+
model.value = model.value.slice(0, targetIndex) + character + model.value.slice(targetIndex + 1);
|
|
159
|
+
await nextTick();
|
|
79
160
|
}
|
|
80
161
|
useRender(() => {
|
|
81
162
|
const textFieldProps = VTextField.filterProps(props);
|
|
@@ -83,7 +164,10 @@ export const VMaskInput = genericComponent()({
|
|
|
83
164
|
"modelValue": model.value,
|
|
84
165
|
"onUpdate:modelValue": $event => model.value = $event,
|
|
85
166
|
"ref": vTextFieldRef,
|
|
86
|
-
"validationValue": validationValue.value
|
|
167
|
+
"validationValue": validationValue.value,
|
|
168
|
+
"onCut": onCut,
|
|
169
|
+
"onPaste": onPaste,
|
|
170
|
+
"onKeydown": onKeyDown
|
|
87
171
|
}), {
|
|
88
172
|
...slots
|
|
89
173
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VMaskInput.js","names":["makeVTextFieldProps","VTextField","forwardRefs","isMaskDelimiter","makeMaskProps","useMask","useProxiedModel","computed","onBeforeMount","ref","shallowRef","toRef","genericComponent","propsFactory","useRender","makeVMaskInputProps","returnMaskedValue","Boolean","VMaskInput","name","props","emits","val","setup","_ref","slots","emit","vTextFieldRef","selection","lazySelection","mask","model","undefined","unmask","valueBeforeChange","value","enforcedMaskedValue","newUnmaskedValue","updateRange","validationValue","setCaretPosition","newSelection","setSelectionRange","resetSelections","selectionEnd","index","newValue","length","textFieldProps","filterProps","_createVNode","_mergeProps","$event"],"sources":["../../../src/labs/VMaskInput/VMaskInput.tsx"],"sourcesContent":["// Components\nimport { makeVTextFieldProps, VTextField } from '@/components/VTextField/VTextField'\n\n// Composables\nimport { forwardRefs } from '@/composables/forwardRefs'\nimport { isMaskDelimiter, makeMaskProps, useMask } from '@/composables/mask'\nimport { useProxiedModel } from '@/composables/proxiedModel'\n\n// Utilities\nimport { computed, onBeforeMount, ref, shallowRef, toRef } from 'vue'\nimport { genericComponent, propsFactory, useRender } from '@/util'\n\n// Types\nimport type { VTextFieldSlots } from '@/components/VTextField/VTextField'\n\nexport type VMaskInputSlots = VTextFieldSlots\n\nexport const makeVMaskInputProps = propsFactory({\n returnMaskedValue: Boolean,\n ...makeVTextFieldProps(),\n ...makeMaskProps(),\n}, 'VMaskInput')\n\nexport const VMaskInput = genericComponent<VMaskInputSlots>()({\n name: 'VMaskInput',\n\n props: makeVMaskInputProps(),\n\n emits: {\n 'update:modelValue': (val: string) => true,\n },\n\n setup (props, { slots, emit }) {\n const vTextFieldRef = ref<VTextField>()\n\n const selection = shallowRef(0)\n const lazySelection = shallowRef(0)\n\n const mask = useMask(props)\n const returnMaskedValue = computed(() => props.mask && props.returnMaskedValue)\n\n const model = useProxiedModel(\n props,\n 'modelValue',\n undefined,\n // Always display masked value in input when mask is applied\n val => props.mask ? mask.mask(mask.unmask(val)) : val,\n val => {\n if (props.mask) {\n const valueBeforeChange = mask.unmask(model.value)\n // E.g. mask is #-# and the input value is '2-23'\n // model-value should be enforced to '2-2'\n const enforcedMaskedValue = mask.mask(mask.unmask(val))\n const newUnmaskedValue = mask.unmask(enforcedMaskedValue)\n\n if (newUnmaskedValue === valueBeforeChange) {\n vTextFieldRef.value!.value = enforcedMaskedValue\n }\n val = newUnmaskedValue\n updateRange()\n return returnMaskedValue.value ? mask.mask(val) : val\n }\n return val\n },\n )\n\n const validationValue = toRef(() => returnMaskedValue.value ? model.value : mask.unmask(model.value))\n\n onBeforeMount(() => {\n if (props.returnMaskedValue) {\n emit('update:modelValue', model.value)\n }\n })\n\n function setCaretPosition (newSelection: number) {\n selection.value = newSelection\n vTextFieldRef.value && vTextFieldRef.value.setSelectionRange(selection.value, selection.value)\n }\n\n function resetSelections () {\n if (!vTextFieldRef.value?.selectionEnd) return\n\n selection.value = vTextFieldRef.value.selectionEnd\n lazySelection.value = 0\n\n for (let index = 0; index < selection.value; index++) {\n isMaskDelimiter(vTextFieldRef.value.value[index]) || lazySelection.value++\n }\n }\n\n function updateRange () {\n if (!vTextFieldRef.value) return\n resetSelections()\n\n let selection = 0\n const newValue = vTextFieldRef.value.value\n\n if (newValue) {\n for (let index = 0; index < newValue.length; index++) {\n if (lazySelection.value <= 0) break\n isMaskDelimiter(newValue[index]) || lazySelection.value--\n selection++\n }\n }\n setCaretPosition(selection)\n }\n\n useRender(() => {\n const textFieldProps = VTextField.filterProps(props)\n\n return (\n <VTextField\n { ...textFieldProps }\n v-model={ model.value }\n ref={ vTextFieldRef }\n validationValue={ validationValue.value }\n >\n {{ ...slots }}\n </VTextField>\n )\n })\n\n return forwardRefs({}, vTextFieldRef)\n },\n})\n\nexport type VMaskInput = InstanceType<typeof VMaskInput>\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"VMaskInput.js","names":["makeVTextFieldProps","VTextField","forwardRefs","isMaskDelimiter","makeMaskProps","useMask","useProxiedModel","computed","nextTick","onBeforeMount","ref","shallowRef","toRef","genericComponent","propsFactory","useRender","makeVMaskInputProps","returnMaskedValue","Boolean","VMaskInput","name","props","emits","val","setup","_ref","slots","emit","vTextFieldRef","inputAction","caretPosition","mask","model","undefined","unmask","valueWithoutDelimiters","removeMaskDelimiters","newMaskedValue","newUnmaskedValue","newCaretPosition","getNewCaretPosition","oldValue","value","newValue","oldCaret","setSelectionRange","validationValue","split","filter","ch","join","_ref2","length","newCaret","onKeyDown","e","metaKey","inputElement","target","selectionStart","key","hasSelection","selectionEnd","preventDefault","deleteSelection","onCut","copySelectionToClipboard","onPaste","pastedString","clipboardData","getData","pastedCharacters","replaceSelection","insertCharacters","start","end","selectedText","substring","navigator","clipboard","writeText","curStart","success","simulateBackspace","slice","i","insertCharacter","character","replaceCharacter","index","targetIndex","textFieldProps","filterProps","_createVNode","_mergeProps","$event"],"sources":["../../../src/labs/VMaskInput/VMaskInput.tsx"],"sourcesContent":["// Components\nimport { makeVTextFieldProps, VTextField } from '@/components/VTextField/VTextField'\n\n// Composables\nimport { forwardRefs } from '@/composables/forwardRefs'\nimport { isMaskDelimiter, makeMaskProps, useMask } from '@/composables/mask'\nimport { useProxiedModel } from '@/composables/proxiedModel'\n\n// Utilities\nimport { computed, nextTick, onBeforeMount, ref, shallowRef, toRef } from 'vue'\nimport { genericComponent, propsFactory, useRender } from '@/util'\n\n// Types\nimport type { VTextFieldSlots } from '@/components/VTextField/VTextField'\n\nexport type VMaskInputSlots = VTextFieldSlots\n\nexport const makeVMaskInputProps = propsFactory({\n returnMaskedValue: Boolean,\n ...makeVTextFieldProps(),\n ...makeMaskProps(),\n}, 'VMaskInput')\n\nexport const VMaskInput = genericComponent<VMaskInputSlots>()({\n name: 'VMaskInput',\n\n props: makeVMaskInputProps(),\n\n emits: {\n 'update:modelValue': (val: string) => true,\n },\n\n setup (props, { slots, emit }) {\n const vTextFieldRef = ref<VTextField>()\n\n const inputAction = shallowRef()\n const caretPosition = shallowRef(0)\n\n const mask = useMask(props)\n const returnMaskedValue = computed(() => props.mask && props.returnMaskedValue)\n\n const model = useProxiedModel(\n props,\n 'modelValue',\n undefined,\n // Always display masked value in input when mask is applied\n val => props.mask ? mask.mask(mask.unmask(val)) : val,\n val => {\n if (props.mask) {\n const valueWithoutDelimiters = removeMaskDelimiters(val)\n\n // E.g. mask is #-# and the input value is '2-23'\n // model-value should be enforced to '2-2'\n const newMaskedValue = mask.mask(valueWithoutDelimiters)\n const newUnmaskedValue = mask.unmask(newMaskedValue)\n\n const newCaretPosition = getNewCaretPosition({\n oldValue: model.value,\n newValue: newMaskedValue,\n oldCaret: caretPosition.value,\n })\n\n vTextFieldRef.value!.value = newMaskedValue\n vTextFieldRef.value!.setSelectionRange(newCaretPosition, newCaretPosition)\n\n return returnMaskedValue.value ? mask.mask(newUnmaskedValue) : newUnmaskedValue\n }\n return val\n },\n )\n\n const validationValue = toRef(() => returnMaskedValue.value ? model.value : mask.unmask(model.value))\n\n function removeMaskDelimiters (val: string): string {\n return val.split('').filter(ch => !isMaskDelimiter(ch)).join('')\n }\n\n function getNewCaretPosition ({\n oldValue,\n newValue,\n oldCaret,\n }: {\n oldValue: string\n newValue: string\n oldCaret: number\n }): number {\n if (!newValue) return 0\n if (!oldValue) return newValue.length\n\n let newCaret: number\n\n if (inputAction.value === 'Backspace') {\n newCaret = oldCaret - 1\n while (newCaret > 0 && isMaskDelimiter(newValue[newCaret - 1])) newCaret--\n } else if (inputAction.value === 'Delete') {\n newCaret = oldCaret\n } else { // insertion\n newCaret = oldCaret + 1\n while (isMaskDelimiter(newValue[newCaret])) newCaret++\n if (isMaskDelimiter(newValue[oldCaret])) newCaret++\n }\n\n return newCaret\n }\n\n onBeforeMount(() => {\n if (props.returnMaskedValue) {\n emit('update:modelValue', model.value)\n }\n })\n\n function onKeyDown (e: KeyboardEvent) {\n if (e.metaKey) return\n\n const inputElement = e.target as HTMLInputElement\n\n caretPosition.value = inputElement.selectionStart || 0\n inputAction.value = e.key\n\n const hasSelection = inputElement.selectionStart !== inputElement.selectionEnd\n if (e.key === 'Backspace' && hasSelection) {\n e.preventDefault()\n deleteSelection(e)\n }\n }\n\n async function onCut (e: Event) {\n e.preventDefault()\n\n copySelectionToClipboard(e)\n deleteSelection(e)\n }\n\n async function onPaste (e: ClipboardEvent) {\n e.preventDefault()\n\n const inputElement = e.target as HTMLInputElement\n const pastedString = removeMaskDelimiters(e.clipboardData?.getData('text') || '')\n\n if (!pastedString) return\n\n const pastedCharacters = [...pastedString]\n\n const hasSelection = inputElement.selectionStart !== inputElement.selectionEnd\n\n if (hasSelection) {\n replaceSelection(inputElement, pastedCharacters)\n } else {\n insertCharacters(inputElement, pastedCharacters)\n }\n }\n\n function copySelectionToClipboard (e: Event) {\n const inputElement = e.target as HTMLInputElement\n const start = inputElement.selectionStart || 0\n const end = inputElement.selectionEnd || 0\n const selectedText = inputElement.value.substring(start, end)\n navigator.clipboard.writeText(selectedText)\n }\n\n async function deleteSelection (e: Event) {\n const inputElement = e.target as HTMLInputElement\n const curStart = inputElement.selectionStart || 0\n caretPosition.value = inputElement.selectionEnd || 0\n\n while (caretPosition.value > curStart) {\n const success = await simulateBackspace(inputElement)\n if (!success) break\n }\n }\n\n async function simulateBackspace (inputElement: HTMLInputElement) {\n inputAction.value = 'Backspace'\n model.value = inputElement.value.slice(0, caretPosition.value - 1) + inputElement.value.slice(caretPosition.value)\n inputAction.value = ''\n if (caretPosition.value === inputElement.selectionEnd) return false\n caretPosition.value = inputElement.selectionEnd || 0\n await nextTick()\n return true\n }\n\n async function insertCharacters (inputElement: HTMLInputElement, pastedCharacters: string[]) {\n for (let i = 0; i < pastedCharacters.length; i++) {\n await insertCharacter(inputElement, pastedCharacters[i])\n }\n }\n\n async function insertCharacter (inputElement: HTMLInputElement, character: string) {\n caretPosition.value = inputElement.selectionEnd || 0\n model.value = inputElement.value.slice(0, caretPosition.value) + character + inputElement.value.slice(caretPosition.value)\n await nextTick()\n }\n\n async function replaceSelection (inputElement: HTMLInputElement, pastedCharacters: string[]) {\n caretPosition.value = inputElement.selectionStart || 0\n for (let i = 0; i < pastedCharacters.length; i++) {\n await replaceCharacter(caretPosition.value, pastedCharacters[i])\n caretPosition.value++\n }\n }\n\n async function replaceCharacter (index: number, character: string) {\n let targetIndex = index\n\n // Find next non-delimiter position\n while (targetIndex < model.value.length && isMaskDelimiter(model.value[targetIndex])) targetIndex++\n\n model.value = model.value.slice(0, targetIndex) + character + model.value.slice(targetIndex + 1)\n await nextTick()\n }\n\n useRender(() => {\n const textFieldProps = VTextField.filterProps(props)\n\n return (\n <VTextField\n { ...textFieldProps }\n v-model={ model.value }\n ref={ vTextFieldRef }\n validationValue={ validationValue.value }\n onCut={ onCut }\n onPaste={ onPaste }\n onKeydown={ onKeyDown }\n >\n {{ ...slots }}\n </VTextField>\n )\n })\n\n return forwardRefs({}, vTextFieldRef)\n },\n})\n\nexport type VMaskInput = InstanceType<typeof VMaskInput>\n"],"mappings":"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","ignoreList":[]}
|