wip bsky client for the web & android
bbell.vt3e.cat
1<script setup lang="ts">
2import { onMounted, ref, useId } from 'vue'
3
4const props = defineProps<{
5 label?: string
6 placeholder?: string
7 rows?: number
8 error?: string
9 autoresize?: boolean
10}>()
11
12const model = defineModel<string>()
13const id = useId()
14
15const height = ref()
16
17const textareaRef = ref<HTMLTextAreaElement | null>(null)
18function resize(target: HTMLTextAreaElement) {
19 target.style.height = 'auto'
20 target.style.height = `${target.scrollHeight}px`
21 height.value = target.scrollHeight
22}
23
24function onInput(e: Event) {
25 if (!props.autoresize) return
26 resize(e.target as HTMLTextAreaElement)
27}
28
29onMounted(() => {
30 if (props.autoresize && textareaRef.value) {
31 resize(textareaRef.value)
32 }
33})
34</script>
35
36<template>
37 <div class="input-group">
38 <label v-if="label" :for="id" class="label">{{ label }}</label>
39 <textarea
40 ref="textareaRef"
41 :id="id"
42 v-model="model"
43 v-bind="props"
44 rows="1"
45 :style="{ height: height + 'px' }"
46 :placeholder="placeholder"
47 class="input textarea"
48 :oninput="onInput"
49 :class="{ 'has-error': error }"
50 ></textarea>
51 <span v-if="error" class="error-text">{{ error }}</span>
52 </div>
53</template>
54
55<style scoped>
56.input-group {
57 display: flex;
58 flex-direction: column;
59 gap: 0.25rem;
60 width: 100%;
61 margin-bottom: 1rem;
62}
63
64.label {
65 font-size: 0.875rem;
66 font-weight: 600;
67 color: hsl(var(--subtext1));
68 margin-left: 0.25rem;
69}
70
71textarea {
72 width: 100%;
73 border-radius: 0.75rem;
74 border: 1px solid transparent;
75 background-color: hsla(var(--surface0) / 0.3);
76 border: 1px solid hsla(var(--surface2) / 0.5);
77 color: hsl(var(--text));
78 font-size: 1rem;
79 font-family: inherit;
80 resize: none;
81
82 box-sizing: border-box; /* usually default, but good to be sure */
83 line-height: 1.5; /* or whatever fits your design system */
84 min-height: 0; /* overrides some user-agent defaults */
85 overflow: hidden; /* hides the scrollbar jumping */
86
87 &:focus-visible {
88 background-color: hsla(var(--base) / 0.9);
89 }
90 &.has-error {
91 border-color: hsl(var(--red));
92 }
93}
94.error-text {
95 font-size: 0.75rem;
96 color: hsl(var(--red));
97 margin-left: 0.25rem;
98}
99</style>