104 lines
2.5 KiB
Vue
104 lines
2.5 KiB
Vue
<template>
|
|
<WordCounter
|
|
:id="id"
|
|
class="ck-word-count"
|
|
/>
|
|
<textarea
|
|
ref="textarea"
|
|
:id="id"
|
|
:class="`input-text-auto-component ${classPath}`"
|
|
:name="name"
|
|
:aria-describedby="ariaDescribedby"
|
|
:placeholder="placeholder"
|
|
:required="required"
|
|
@input="styleElement(checkInput())"
|
|
@blur="onBlur"
|
|
v-model="value"
|
|
/>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, nextTick, onBeforeMount, onMounted, ref, useAttrs } from "vue";
|
|
import WordCounter from "./WordCounterComponent.vue";
|
|
|
|
defineOptions({
|
|
name: "InputTextAutoComponent"
|
|
});
|
|
|
|
// * ATTRIBUTES
|
|
const attrs = useAttrs();
|
|
|
|
// * REFS
|
|
const textarea = ref<HTMLTextAreaElement|null>(null);
|
|
|
|
// * DATA
|
|
/** Hack to set the id for wordCounterComponent. */
|
|
const id = ref<string>(JSON.parse(String(attrs.json ?? "{}")).id);
|
|
const classPath = ref<string>("");
|
|
const name = ref<string>("");
|
|
const placeholder = ref<string>("");
|
|
const ariaDescribedby = ref<string>("");
|
|
const value = ref<string>("");
|
|
const required = ref<boolean>(true);
|
|
|
|
// * COMPUTED
|
|
const isUsedWithProps = computed<boolean>(() => attrs.json === undefined);
|
|
|
|
onBeforeMount(() => {
|
|
if (isUsedWithProps.value) {
|
|
throw new Error("this component requires json");
|
|
}
|
|
});
|
|
|
|
// * LIFECYCLE
|
|
onMounted(() => {
|
|
const json = String(attrs.json ?? "{}"),
|
|
data = JSON.parse(json);
|
|
if (!isUsedWithProps.value) {
|
|
id.value = String(data.id);
|
|
classPath.value = String(data.class);
|
|
name.value = String(data.name);
|
|
placeholder.value = String(data.placeholder);
|
|
ariaDescribedby.value = String(data.ariaDescribedby);
|
|
value.value = String(data.value);
|
|
required.value = data.required;
|
|
textarea.value?.setAttribute("style", "height:1rem;overflow-y:hidden;");
|
|
}
|
|
nextTick(() => {
|
|
styleElement(checkInput());
|
|
});
|
|
});
|
|
|
|
// * METHODS
|
|
|
|
/** When the textarea get the focus. */
|
|
function onBlur() {
|
|
const el = checkInput();
|
|
/** Remove every new line char */
|
|
el.value = el.value.replace(/[\n\r]/g, "");
|
|
nextTick(() => {
|
|
styleElement(el);
|
|
});
|
|
}
|
|
|
|
/** Check if the element is an HTMLTextAreaElement. */
|
|
function checkInput(): HTMLTextAreaElement {
|
|
const el = textarea.value;
|
|
if (!el) {
|
|
throw new Error("undefined textarea element");
|
|
}
|
|
return el;
|
|
}
|
|
|
|
/** Style the textarea element. */
|
|
function styleElement(el: HTMLTextAreaElement): void {
|
|
el.style.height = "auto";
|
|
el.style.height = `${el.scrollHeight}px`;
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scopped>
|
|
.input-text-auto-component {
|
|
resize: none;
|
|
}
|
|
</style>
|