Files
provider_editor_text/src/components/SourceEditor.vue
T
2026-07-24 00:15:51 -04:00

95 lines
1.7 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
const emit = defineEmits<{
update: []
}>()
const content = ref('')
const textareaRef = ref<HTMLTextAreaElement | null>(null)
function setContent(value: string) {
content.value = value
}
function getContent(): string {
return content.value
}
function handleInput() {
emit('update')
}
function handleKeydown(e: KeyboardEvent) {
// Tab inserts 2 spaces instead of changing focus
if (e.key === 'Tab') {
e.preventDefault()
const textarea = textareaRef.value
if (!textarea) return
const start = textarea.selectionStart
const end = textarea.selectionEnd
const indent = ' '
content.value =
content.value.substring(0, start) + indent + content.value.substring(end)
// Restore cursor position
nextTick(() => {
textarea.selectionStart = textarea.selectionEnd = start + indent.length
})
emit('update')
}
}
onMounted(() => {
textareaRef.value?.focus()
})
defineExpose({
setContent,
getContent,
})
</script>
<template>
<div class="source-editor">
<textarea
ref="textareaRef"
v-model="content"
class="source-textarea"
spellcheck="false"
autocomplete="off"
autocapitalize="off"
@input="handleInput"
@keydown="handleKeydown"
/>
</div>
</template>
<style scoped>
.source-editor {
flex: 1;
display: flex;
overflow: hidden;
}
.source-textarea {
flex: 1;
width: 100%;
padding: 16px 24px;
border: none;
outline: none;
resize: none;
background: transparent;
color: rgb(var(--v-theme-on-surface));
font-family: 'Roboto Mono', 'Courier New', monospace;
font-size: 0.875rem;
line-height: 1.6;
tab-size: 2;
white-space: pre;
overflow: auto;
}
</style>