1
0
mirror of https://github.com/robonen/lorem-blog.git synced 2026-03-20 02:44:39 +00:00
Files
lorem-blog/src/shared/composables/useTextAreaAutosize.ts
2025-07-14 02:48:28 +07:00

70 lines
1.6 KiB
TypeScript

import type { TemplateRef } from 'vue';
import { clamp } from '@robonen/stdlib';
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
export function useTextAreaAutosize(textareaRef: TemplateRef<HTMLTextAreaElement | null>) {
const minHeight = ref(0);
const maxHeight = ref(Infinity);
const resize = () => nextTick(() => {
const textarea = textareaRef.value;
if (!textarea)
return;
textarea.style.height = 'auto';
const newHeight = clamp(textarea.scrollHeight, minHeight.value, maxHeight.value);
textarea.style.height = `${newHeight}px`;
textarea.style.overflowY = newHeight >= maxHeight.value ? 'auto' : 'hidden';
});
const handleInput = () => {
resize();
};
onMounted(() => {
const textarea = textareaRef.value;
if (textarea) {
minHeight.value = textarea.offsetHeight;
textarea.addEventListener('input', handleInput);
textarea.addEventListener('paste', handleInput);
resize();
}
});
onUnmounted(() => {
const textarea = textareaRef.value;
if (textarea) {
textarea.removeEventListener('input', handleInput);
textarea.removeEventListener('paste', handleInput);
}
});
watch(textareaRef, (newTextarea) => {
if (newTextarea) {
minHeight.value = newTextarea.offsetHeight;
resize();
}
});
const setMinHeight = (height: number) => {
minHeight.value = height;
resize();
};
const setMaxHeight = (height: number) => {
maxHeight.value = height;
resize();
};
return {
resize,
setMinHeight,
setMaxHeight,
};
}