Coves frontend - a photon fork
1<script module lang="ts">
2 import { Label } from 'mono-svelte'
3 import type { ClassValue, HTMLTextareaAttributes } from 'svelte/elements'
4 import { generateID } from './helper'
5
6 export type Size = keyof typeof sizeClass
7
8 export const sizeClass = {
9 sm: 'p-3',
10 md: 'p-4',
11 lg: 'p-5',
12 }
13
14 interface Props extends HTMLTextareaAttributes {
15 label?: string | undefined
16 value?: string
17 placeholder?: string
18 disabled?: boolean
19 required?: boolean
20 size?: Size
21 id?: string
22 rows?: number
23 element?: HTMLTextAreaElement | undefined
24 class?: ClassValue
25 customLabel?: import('svelte').Snippet
26 suffix?: import('svelte').Snippet
27 children?: import('svelte').Snippet
28 }
29
30 export type { Props as TextAreaProps }
31</script>
32
33<script lang="ts">
34 const borderClass = `
35 border border-slate-200 dark:border-zinc-800
36 `
37
38 let {
39 label = undefined,
40 value = $bindable(),
41 placeholder = '',
42 disabled = false,
43 required = false,
44 size = 'md',
45 id = generateID(),
46 rows = 4,
47 element = $bindable(),
48 class: clazz = '',
49 customLabel,
50 suffix,
51 children,
52 ...rest
53 }: Props = $props()
54</script>
55
56<div class="flex flex-col gap-1 {clazz}">
57 {#if customLabel || label}
58 <Label
59 for={id}
60 text={label}
61 class="peer-invalid:text-red-500 {required
62 ? "after:content-['*'] after:text-red-500 after:ml-1"
63 : ''}"
64 >
65 {@render customLabel?.()}
66 </Label>
67 {/if}
68 <div
69 class="rounded-xl flex flex-col items-center text-sm bg-white dark:bg-zinc-950 {clazz}"
70 >
71 <textarea
72 {id}
73 {placeholder}
74 {disabled}
75 {rows}
76 bind:value
77 bind:this={element}
78 {...rest}
79 class={[
80 sizeClass[size],
81 borderClass,
82 `focus:border-slate-800 dark:focus:border-zinc-200 bg-white dark:bg-zinc-950
83 focus:outline-hidden focus:ring-2 ring-slate-800/50 rounded-xl dark:ring-zinc-200/50
84 transition-all text-sm w-full disabled:bg-slate-100
85 disabled:cursor-not-allowed dark:disabled:bg-zinc-900 invalid:border-red-500!
86 peer invalid:text-red-500 z-10`,
87 suffix && 'rounded-b-none border-b-0',
88 clazz,
89 ]}
90 ></textarea>
91 {#if suffix}
92 <div
93 class="{borderClass} {sizeClass[
94 size
95 ]} w-full border-t-0 rounded-xl rounded-t-none
96 flex items-center"
97 >
98 {@render suffix?.()}
99 </div>
100 {/if}
101 </div>
102 {@render children?.()}
103</div>