feat: textarea resizes as text is added/removed (#209)

Co-authored-by: Barbara Gomes <barbara@barbaragomes.com>
This commit is contained in:
Vojtech Simetka 2023-02-17 15:11:49 +01:00 committed by GitHub
parent 9d939b78a5
commit 73ca7d72d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,8 +1,41 @@
<script lang="ts"> <script lang="ts">
import { onDestroy, onMount } from 'svelte'
export let value = '' export let value = ''
export let placeholder = '' export let placeholder = ''
export let label = '' export let label = ''
let placeholderHeight: number let placeholderHeight: number
let textarea: HTMLTextAreaElement
const resizeEvents = ['change']
const delayedResizeEvents = ['cut', 'paste', 'drop', 'keydown']
function resize() {
textarea.style.height = 'auto'
textarea.style.height = `${Math.max(placeholderHeight, textarea.scrollHeight)}px`
}
function delayedResize() {
setTimeout(resize, 0)
}
// The resize mechanism is heavily inspired by https://stackoverflow.com/a/5346855
onMount(() => {
resizeEvents.forEach((eventName) => textarea.addEventListener(eventName, resize))
delayedResizeEvents.forEach((eventName) => textarea.addEventListener(eventName, delayedResize))
resize()
})
// This cleans up all the listeners from the textarea element when the component is about to be destroyed
onDestroy(() => {
if (!textarea) return
resizeEvents.forEach((eventName) => textarea.removeEventListener(eventName, resize))
delayedResizeEvents.forEach((eventName) =>
textarea.removeEventListener(eventName, delayedResize),
)
})
</script> </script>
<label> <label>
@ -14,11 +47,7 @@
> >
{placeholder} {placeholder}
</div> </div>
<textarea <textarea bind:value bind:this={textarea} class={value != '' ? 'content' : ''} />
bind:value
class={value != '' ? 'content' : ''}
style={`${value != '' ? 'min-height: ' + placeholderHeight : ''}px;`}
/>
</div> </div>
</label> </label>
@ -35,11 +64,13 @@
position: relative; position: relative;
width: 100%; width: 100%;
height: fit-content; height: fit-content;
.placeholder-text { .placeholder-text {
font-size: var(--font-size-lg); font-size: var(--font-size-lg);
color: var(--grey-300); color: var(--grey-300);
width: 100%; width: 100%;
height: fit-content; height: fit-content;
&.hide { &.hide {
display: none; display: none;
} }
@ -55,9 +86,12 @@
&:focus, &:focus,
&.content { &.content {
background-color: #ffffff; background-color: #000;
transition: background-color 0.2s; transition: background-color 0.2s;
outline: none; outline: none;
@media (prefers-color-scheme: light) {
background-color: #ffffff;
}
} }
&.content { &.content {