index.ts 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { ref } from 'vue'
  2. import type { ShallowRef } from 'vue'
  3. // Keep input cursor in the correct position when we use formatter.
  4. export function useCursor(
  5. input: ShallowRef<HTMLInputElement | undefined>
  6. ): [() => void, () => void] {
  7. const selectionRef = ref<{
  8. selectionStart?: number
  9. selectionEnd?: number
  10. value?: string
  11. beforeTxt?: string
  12. afterTxt?: string
  13. }>()
  14. function recordCursor() {
  15. if (input.value == undefined) return
  16. const { selectionStart, selectionEnd, value } = input.value
  17. if (selectionStart == null || selectionEnd == null) return
  18. const beforeTxt = value.slice(0, Math.max(0, selectionStart))
  19. const afterTxt = value.slice(Math.max(0, selectionEnd))
  20. selectionRef.value = {
  21. selectionStart,
  22. selectionEnd,
  23. value,
  24. beforeTxt,
  25. afterTxt,
  26. }
  27. }
  28. function setCursor() {
  29. if (input.value == undefined || selectionRef.value == undefined) return
  30. const { value } = input.value
  31. const { beforeTxt, afterTxt, selectionStart } = selectionRef.value
  32. if (
  33. beforeTxt == undefined ||
  34. afterTxt == undefined ||
  35. selectionStart == undefined
  36. )
  37. return
  38. let startPos = value.length
  39. if (value.endsWith(afterTxt)) {
  40. startPos = value.length - afterTxt.length
  41. } else if (value.startsWith(beforeTxt)) {
  42. startPos = beforeTxt.length
  43. } else {
  44. const beforeLastChar = beforeTxt[selectionStart - 1]
  45. const newIndex = value.indexOf(beforeLastChar, selectionStart - 1)
  46. if (newIndex !== -1) {
  47. startPos = newIndex + 1
  48. }
  49. }
  50. input.value.setSelectionRange(startPos, startPos)
  51. }
  52. return [recordCursor, setCursor]
  53. }