How to revert to normal cursor behavior after dispatch selection?

I’m using vue-codemirror and have some working code that selects an entire substring like <input-value> when single clicking into it. I do a view dispatch selection to select the range and it works fine. However, when typing to replace the placeholder, the selection range still remains after the first keystroke. I was expecting the cursor to revert to normal behavior and be at a single position when typing. Essentially I want dispatch selection to work the same as manually highlighting a range, and then typing. How can I achieve this?

Below is my code, see the dispatch line in highlightPlaceholder(). Please let me know if my question make sense. Thanks!

<template>
  <div>
    <codemirror
      v-model="code"
      :placeholder="placeholder"
      :autofocus="false"
      :indent-with-tab="true"
      :tab-size="2"
      :extensions="extensions"
      @ready="handleReady"
      @change="console.log('change', $event)"
      @focus="console.log('focus', $event)"
      @blur="console.log('blur', $event)"
      @update="highlightPlaceholder()"
      :style="{ 'min-height': '250px', 'max-height': '70vh',
        'border': `${showError ? '2px solid red' : '2px solid black'}`
      }"
    />
    <caption
      :class="{ invisible: showError?.length === 0 || showError === undefined ? true : false }"
      class="row text-caption q-ml-md" 
      style="color: rgb(193, 0, 21); font-size: 12px;"
    >
      {{ showError || '...' }}
    </caption>
  </div>
</template>

<script setup>
  import { computed, shallowRef, ref } from 'vue'
  import { Codemirror } from 'vue-codemirror'
  import { yaml } from '@codemirror/lang-yaml'
  import { oneDark } from '@codemirror/theme-one-dark'
  import { linter, lintGutter } from "@codemirror/lint"
  import parser from "js-yaml"
  import { python } from '@codemirror/lang-python'
  import { EditorState } from '@codemirror/state'

  const props = defineProps(['placeholder', 'language', 'readOnly', 'showError'])

  const code = defineModel()

  // Codemirror EditorView instance ref
  const view = shallowRef()
  const handleReady = (payload) => {
    view.value = payload.view
  }

  defineExpose({ insertText })

  function insertText(text) {
    console.log('inserting text')
    const range = view.value.state.selection.ranges[0]
    view.value.dispatch({
        changes: { from: range.from, to: range.to, insert: text }
    })
  }

  function highlightPlaceholder() {
    if(!view.value) return
    const range = view.value.state.selection.ranges[0]
    const from = range.from
    const to = range.to
    if (from === to) {
      // Define the substring you are looking for
      const placeholder = '<input-value>'

      // Use a loop to find all instances of the placeholder
      let startIndex = code.value.indexOf(placeholder)
      while (startIndex !== -1) {
        const endIndex = startIndex + placeholder.length

        // Check if the cursor position is within the bounds of the current placeholder instance
        if (from >= startIndex && from <= endIndex) {
            console.log(`Cursor is at position ${from}, within the substring '<input-value>' from index ${startIndex} to ${endIndex}`)
            view.value.dispatch({selection: {anchor: startIndex, head: endIndex}})
            break
        }

        // Move to the next possible start index to continue searching
        startIndex = code.value.indexOf(placeholder, startIndex + placeholder.length)
      }
    }
  }

  const yamlLinter = linter((view) => {
    const diagnostics = [];
    try {
      parser.load(view.state.doc);
    } catch (e) {
      const loc = e.mark;
      const from = loc ? loc.position : 0;
      const to = from;
      const severity = "error";

      diagnostics.push({
        from,
        to,
        message: e.message,
        severity
      });
    } 

    return diagnostics;
  })


  const extensions = computed(() => {
    if(props.language === 'python') {
      return [python(), oneDark]
    }
    return [
      yaml(), 
      oneDark,
      yamlLinter,
      lintGutter(),
      EditorState.readOnly.of(props.readOnly)
    ]
  })
</script>

There is no difference between selections dispatched programmatically and those selected by the user, in the library. I’m not sure what you’re describing, but if you can reproduce it with just the core library (no Vue), in a small script, I can take a look.