feat: Add auto-resize on text input
This commit is contained in:
parent
52bd4e4ce4
commit
5288e09b27
28
src/lib/components/ui/textarea/index.ts
Normal file
28
src/lib/components/ui/textarea/index.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import Root from "./textarea.svelte";
|
||||||
|
|
||||||
|
type FormTextareaEvent<T extends Event = Event> = T & {
|
||||||
|
currentTarget: EventTarget & HTMLTextAreaElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TextareaEvents = {
|
||||||
|
blur: FormTextareaEvent<FocusEvent>;
|
||||||
|
change: FormTextareaEvent<Event>;
|
||||||
|
click: FormTextareaEvent<MouseEvent>;
|
||||||
|
focus: FormTextareaEvent<FocusEvent>;
|
||||||
|
keydown: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
keypress: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
keyup: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
mouseover: FormTextareaEvent<MouseEvent>;
|
||||||
|
mouseenter: FormTextareaEvent<MouseEvent>;
|
||||||
|
mouseleave: FormTextareaEvent<MouseEvent>;
|
||||||
|
paste: FormTextareaEvent<ClipboardEvent>;
|
||||||
|
input: FormTextareaEvent<InputEvent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Textarea,
|
||||||
|
type TextareaEvents,
|
||||||
|
type FormTextareaEvent,
|
||||||
|
};
|
43
src/lib/components/ui/textarea/textarea.svelte
Normal file
43
src/lib/components/ui/textarea/textarea.svelte
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn } from '$lib/utils.js';
|
||||||
|
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
||||||
|
import type { TextareaEvents } from './index.js';
|
||||||
|
|
||||||
|
// Note: The autoResize directive is NOT part of the shadcn-svelte package,
|
||||||
|
// it just has to be added directly to the root component because of a
|
||||||
|
// Svelte limitation.
|
||||||
|
import { autoResize } from '$lib/functions/autoresize.svelte';
|
||||||
|
|
||||||
|
type $$Props = HTMLTextareaAttributes;
|
||||||
|
type $$Events = TextareaEvents;
|
||||||
|
|
||||||
|
let className: $$Props['class'] = undefined;
|
||||||
|
export let value: $$Props['value'] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
|
||||||
|
// Workaround for https://github.com/sveltejs/svelte/issues/9305
|
||||||
|
// Fixed in Svelte 5, but not backported to 4.x.
|
||||||
|
export let readonly: $$Props['readonly'] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
class={cn(
|
||||||
|
'flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
bind:value
|
||||||
|
{readonly}
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:click
|
||||||
|
on:focus
|
||||||
|
on:keydown
|
||||||
|
on:keypress
|
||||||
|
on:keyup
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:paste
|
||||||
|
on:input
|
||||||
|
use:autoResize
|
||||||
|
{...$$restProps}></textarea>
|
14
src/lib/functions/autoresize.svelte.ts
Normal file
14
src/lib/functions/autoresize.svelte.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export function autoResize(node: HTMLElement) {
|
||||||
|
function resize() {
|
||||||
|
node.style.height = 'auto';
|
||||||
|
node.style.height = node.scrollHeight + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
resize();
|
||||||
|
node.addEventListener('input', resize);
|
||||||
|
return () => {
|
||||||
|
node.removeEventListener('input', resize);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import Message from '$lib/components/message.svelte';
|
import Message from '$lib/components/message.svelte';
|
||||||
import { Button } from '$lib/components/ui/button/index';
|
import { Button } from '$lib/components/ui/button/index';
|
||||||
import { Input } from '$lib/components/ui/input/index';
|
import Textarea from '$lib/components/ui/textarea/textarea.svelte';
|
||||||
import Websocket from '$lib/functions/clientWebsocket.svelte';
|
import Websocket from '$lib/functions/clientWebsocket.svelte';
|
||||||
import type { TypeMessage } from '$lib/types';
|
import type { TypeMessage } from '$lib/types';
|
||||||
import Send from 'lucide-svelte/icons/send';
|
import Send from 'lucide-svelte/icons/send';
|
||||||
@ -10,6 +10,7 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import { autoResize } from '$lib/functions/autoresize.svelte';
|
||||||
|
|
||||||
const { data }: { data: PageData } = $props();
|
const { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
@ -50,7 +51,7 @@
|
|||||||
socket?.sendMessage(user!, msg);
|
socket?.sendMessage(user!, msg);
|
||||||
msg = '';
|
msg = '';
|
||||||
}}>
|
}}>
|
||||||
<Input type="text" placeholder="Type Here" bind:value={msg} />
|
<Textarea placeholder="Type Here" bind:value={msg} />
|
||||||
<Button class="h-9 w-14" type="submit"><Send class="size-full" /></Button>
|
<Button class="h-full w-14" type="submit"><Send class="size-full" /></Button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user