@mieweb/ui 0.11.0-dev.27 → 0.11.0-dev.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +49 -0
- package/dist/chunk-2VISTX7O.js +802 -0
- package/dist/chunk-2VISTX7O.js.map +1 -0
- package/dist/{chunk-UWHVSRSU.js → chunk-43QBEF6N.js} +51 -18
- package/dist/chunk-43QBEF6N.js.map +1 -0
- package/dist/{chunk-FA7STF2M.cjs → chunk-6GKIISNZ.cjs} +51 -18
- package/dist/chunk-6GKIISNZ.cjs.map +1 -0
- package/dist/{chunk-IEZXJWHJ.cjs → chunk-7XKM6V2K.cjs} +3 -3
- package/dist/{chunk-IEZXJWHJ.cjs.map → chunk-7XKM6V2K.cjs.map} +1 -1
- package/dist/{chunk-STDGAFW2.js → chunk-AK4LHJPC.js} +6 -3
- package/dist/chunk-AK4LHJPC.js.map +1 -0
- package/dist/chunk-AQUHEKXL.cjs +829 -0
- package/dist/chunk-AQUHEKXL.cjs.map +1 -0
- package/dist/{chunk-GTAHQBUK.js → chunk-MBDT2MGR.js} +4 -4
- package/dist/{chunk-GTAHQBUK.js.map → chunk-MBDT2MGR.js.map} +1 -1
- package/dist/{chunk-DXFP53KF.js → chunk-NIO3XVUV.js} +3 -3
- package/dist/{chunk-DXFP53KF.js.map → chunk-NIO3XVUV.js.map} +1 -1
- package/dist/{chunk-S2QKRL5S.cjs → chunk-PRA2V5BP.cjs} +7 -7
- package/dist/{chunk-S2QKRL5S.cjs.map → chunk-PRA2V5BP.cjs.map} +1 -1
- package/dist/{chunk-3E7C5N2G.js → chunk-SFSBYC46.js} +3 -3
- package/dist/{chunk-3E7C5N2G.js.map → chunk-SFSBYC46.js.map} +1 -1
- package/dist/{chunk-ZWKC4JML.cjs → chunk-ZIJMLRI3.cjs} +9 -9
- package/dist/{chunk-ZWKC4JML.cjs.map → chunk-ZIJMLRI3.cjs.map} +1 -1
- package/dist/{chunk-7S3GBPRD.cjs → chunk-ZLBNYCYT.cjs} +6 -3
- package/dist/chunk-ZLBNYCYT.cjs.map +1 -0
- package/dist/components/EmailEditor/index.cjs +16 -16
- package/dist/components/EmailEditor/index.js +7 -7
- package/dist/components/RecordHeader/index.cjs +4 -4
- package/dist/components/RecordHeader/index.js +2 -2
- package/dist/components/RichTextEditor/index.cjs +5 -5
- package/dist/components/RichTextEditor/index.d.cts +21 -1
- package/dist/components/RichTextEditor/index.d.ts +21 -1
- package/dist/components/RichTextEditor/index.js +2 -2
- package/dist/components/SuperChat/index.cjs +2 -2
- package/dist/components/SuperChat/index.js +2 -2
- package/dist/components/Textarea/index.cjs +22 -4
- package/dist/components/Textarea/index.d.cts +40 -14
- package/dist/components/Textarea/index.d.ts +40 -14
- package/dist/components/Textarea/index.js +15 -1
- package/dist/esheet.cjs +10 -5
- package/dist/esheet.cjs.map +1 -1
- package/dist/esheet.js +7 -2
- package/dist/esheet.js.map +1 -1
- package/dist/index.cjs +147 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -56
- package/dist/index.d.ts +117 -56
- package/dist/index.js +14 -37
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind-preset.cjs +4 -4
- package/dist/tailwind-preset.js +1 -1
- package/dist/utils/index.cjs +9 -9
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-7S3GBPRD.cjs.map +0 -1
- package/dist/chunk-BUN6RUJ5.cjs +0 -393
- package/dist/chunk-BUN6RUJ5.cjs.map +0 -1
- package/dist/chunk-CPG7SDON.js +0 -370
- package/dist/chunk-CPG7SDON.js.map +0 -1
- package/dist/chunk-FA7STF2M.cjs.map +0 -1
- package/dist/chunk-STDGAFW2.js.map +0 -1
- package/dist/chunk-UWHVSRSU.js.map +0 -1
package/dist/chunk-CPG7SDON.js
DELETED
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import { RequiredMark } from './chunk-3IMM2PM4.js';
|
|
2
|
-
import { cn } from './chunk-TQONQSJO.js';
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { cva } from 'class-variance-authority';
|
|
5
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
-
|
|
7
|
-
var textareaVariants = cva(
|
|
8
|
-
[
|
|
9
|
-
"w-full px-3 py-2",
|
|
10
|
-
"border border-input rounded-lg",
|
|
11
|
-
"bg-background text-foreground",
|
|
12
|
-
"placeholder:text-muted-foreground",
|
|
13
|
-
"transition-colors duration-200",
|
|
14
|
-
"focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent",
|
|
15
|
-
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
16
|
-
"resize-y"
|
|
17
|
-
],
|
|
18
|
-
{
|
|
19
|
-
variants: {
|
|
20
|
-
size: {
|
|
21
|
-
sm: "text-sm min-h-[60px]",
|
|
22
|
-
md: "text-base min-h-[80px]",
|
|
23
|
-
lg: "text-lg min-h-[100px]"
|
|
24
|
-
},
|
|
25
|
-
hasError: {
|
|
26
|
-
true: "border-destructive focus:ring-destructive",
|
|
27
|
-
false: ""
|
|
28
|
-
},
|
|
29
|
-
resize: {
|
|
30
|
-
none: "resize-none",
|
|
31
|
-
vertical: "resize-y",
|
|
32
|
-
horizontal: "resize-x",
|
|
33
|
-
both: "resize"
|
|
34
|
-
},
|
|
35
|
-
labelVariant: {
|
|
36
|
-
stacked: "",
|
|
37
|
-
floating: "peer placeholder:text-transparent"
|
|
38
|
-
},
|
|
39
|
-
autoResize: {
|
|
40
|
-
true: "",
|
|
41
|
-
false: ""
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
compoundVariants: [
|
|
45
|
-
// Floating labels reserve top padding so entered text always starts
|
|
46
|
-
// below the floated label, plus a little extra min-height.
|
|
47
|
-
{
|
|
48
|
-
labelVariant: "floating",
|
|
49
|
-
size: "sm",
|
|
50
|
-
className: "pt-5 min-h-[76px]"
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
labelVariant: "floating",
|
|
54
|
-
size: "md",
|
|
55
|
-
className: "pt-6 min-h-[96px]"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
labelVariant: "floating",
|
|
59
|
-
size: "lg",
|
|
60
|
-
className: "pt-7 min-h-[120px]"
|
|
61
|
-
},
|
|
62
|
-
// Auto-growing textareas start at the same visual height as a
|
|
63
|
-
// single-line Input (h-8/h-10/h-12): min-height matches the Input
|
|
64
|
-
// size token and the vertical padding is tuned so one line of text
|
|
65
|
-
// plus padding plus borders lands exactly on that height.
|
|
66
|
-
{
|
|
67
|
-
autoResize: true,
|
|
68
|
-
labelVariant: "stacked",
|
|
69
|
-
size: "sm",
|
|
70
|
-
className: "min-h-8 py-[5px]"
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
autoResize: true,
|
|
74
|
-
labelVariant: "stacked",
|
|
75
|
-
size: "md",
|
|
76
|
-
className: "min-h-10 py-[7px]"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
autoResize: true,
|
|
80
|
-
labelVariant: "stacked",
|
|
81
|
-
size: "lg",
|
|
82
|
-
className: "min-h-12 py-[9px]"
|
|
83
|
-
},
|
|
84
|
-
// Floating label + auto-grow: single line below the floated label.
|
|
85
|
-
{
|
|
86
|
-
autoResize: true,
|
|
87
|
-
labelVariant: "floating",
|
|
88
|
-
size: "sm",
|
|
89
|
-
className: "min-h-[50px]"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
autoResize: true,
|
|
93
|
-
labelVariant: "floating",
|
|
94
|
-
size: "md",
|
|
95
|
-
className: "min-h-[58px]"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
autoResize: true,
|
|
99
|
-
labelVariant: "floating",
|
|
100
|
-
size: "lg",
|
|
101
|
-
className: "min-h-[66px]"
|
|
102
|
-
}
|
|
103
|
-
],
|
|
104
|
-
defaultVariants: {
|
|
105
|
-
size: "md",
|
|
106
|
-
hasError: false,
|
|
107
|
-
resize: "vertical",
|
|
108
|
-
labelVariant: "stacked",
|
|
109
|
-
autoResize: true
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
);
|
|
113
|
-
var floatingLabelVariants = cva(
|
|
114
|
-
[
|
|
115
|
-
"absolute start-3 pointer-events-none select-none",
|
|
116
|
-
"transition-all duration-200 ease-out"
|
|
117
|
-
],
|
|
118
|
-
{
|
|
119
|
-
variants: {
|
|
120
|
-
size: {
|
|
121
|
-
sm: [
|
|
122
|
-
"text-sm top-3",
|
|
123
|
-
"peer-focus:top-1 peer-[:not(:placeholder-shown)]:top-1 peer-autofill:top-1",
|
|
124
|
-
"peer-focus:text-[0.65rem] peer-[:not(:placeholder-shown)]:text-[0.65rem] peer-autofill:text-[0.65rem]"
|
|
125
|
-
],
|
|
126
|
-
md: [
|
|
127
|
-
"text-base top-4",
|
|
128
|
-
"peer-focus:top-1.5 peer-[:not(:placeholder-shown)]:top-1.5 peer-autofill:top-1.5",
|
|
129
|
-
"peer-focus:text-xs peer-[:not(:placeholder-shown)]:text-xs peer-autofill:text-xs"
|
|
130
|
-
],
|
|
131
|
-
lg: [
|
|
132
|
-
"text-lg top-5",
|
|
133
|
-
"peer-focus:top-2 peer-[:not(:placeholder-shown)]:top-2 peer-autofill:top-2",
|
|
134
|
-
"peer-focus:text-sm peer-[:not(:placeholder-shown)]:text-sm peer-autofill:text-sm"
|
|
135
|
-
]
|
|
136
|
-
},
|
|
137
|
-
hasError: {
|
|
138
|
-
true: "text-destructive",
|
|
139
|
-
false: "text-muted-foreground"
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
defaultVariants: {
|
|
143
|
-
size: "md",
|
|
144
|
-
hasError: false
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
);
|
|
148
|
-
var Textarea = React.forwardRef(
|
|
149
|
-
({
|
|
150
|
-
className,
|
|
151
|
-
size,
|
|
152
|
-
hasError,
|
|
153
|
-
resize,
|
|
154
|
-
label,
|
|
155
|
-
labelVariant = "stacked",
|
|
156
|
-
hideLabel,
|
|
157
|
-
error,
|
|
158
|
-
helperText,
|
|
159
|
-
maxLength,
|
|
160
|
-
showCount = false,
|
|
161
|
-
autoResize = true,
|
|
162
|
-
required = false,
|
|
163
|
-
requiredVariant,
|
|
164
|
-
id,
|
|
165
|
-
rows,
|
|
166
|
-
value,
|
|
167
|
-
defaultValue,
|
|
168
|
-
onChange,
|
|
169
|
-
placeholder,
|
|
170
|
-
"aria-describedby": ariaDescribedBy,
|
|
171
|
-
...props
|
|
172
|
-
}, ref) => {
|
|
173
|
-
const internalRef = React.useRef(null);
|
|
174
|
-
const [internalValue, setInternalValue] = React.useState(
|
|
175
|
-
defaultValue || ""
|
|
176
|
-
);
|
|
177
|
-
const generatedId = React.useId();
|
|
178
|
-
const textareaId = id || generatedId;
|
|
179
|
-
const errorId = `${textareaId}-error`;
|
|
180
|
-
const helperId = `${textareaId}-helper`;
|
|
181
|
-
const countId = `${textareaId}-count`;
|
|
182
|
-
React.useImperativeHandle(ref, () => internalRef.current);
|
|
183
|
-
const currentValue = value !== void 0 ? String(value) : internalValue;
|
|
184
|
-
const characterCount = currentValue.length;
|
|
185
|
-
const userFloorRef = React.useRef(null);
|
|
186
|
-
const expectedHeightRef = React.useRef(null);
|
|
187
|
-
const initialFloorCapturedRef = React.useRef(false);
|
|
188
|
-
const adjustHeight = React.useCallback(() => {
|
|
189
|
-
const textarea = internalRef.current;
|
|
190
|
-
if (textarea && autoResize) {
|
|
191
|
-
textarea.style.height = "auto";
|
|
192
|
-
const borders = textarea.offsetHeight - textarea.clientHeight;
|
|
193
|
-
const next = Math.max(
|
|
194
|
-
textarea.scrollHeight + borders,
|
|
195
|
-
userFloorRef.current ?? 0
|
|
196
|
-
);
|
|
197
|
-
textarea.style.height = `${next}px`;
|
|
198
|
-
expectedHeightRef.current = textarea.offsetHeight || next;
|
|
199
|
-
}
|
|
200
|
-
}, [autoResize]);
|
|
201
|
-
React.useEffect(() => {
|
|
202
|
-
const textarea = internalRef.current;
|
|
203
|
-
if (textarea && autoResize && !initialFloorCapturedRef.current) {
|
|
204
|
-
initialFloorCapturedRef.current = true;
|
|
205
|
-
const configured = textarea.offsetHeight;
|
|
206
|
-
adjustHeight();
|
|
207
|
-
if (configured - textarea.offsetHeight > 1) {
|
|
208
|
-
userFloorRef.current = configured;
|
|
209
|
-
textarea.style.height = `${configured}px`;
|
|
210
|
-
expectedHeightRef.current = textarea.offsetHeight || configured;
|
|
211
|
-
}
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
adjustHeight();
|
|
215
|
-
}, [currentValue, adjustHeight, autoResize]);
|
|
216
|
-
React.useEffect(() => {
|
|
217
|
-
const textarea = internalRef.current;
|
|
218
|
-
if (!autoResize || !textarea || typeof ResizeObserver === "undefined") {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
let lastWidth = textarea.offsetWidth;
|
|
222
|
-
const observer = new ResizeObserver(() => {
|
|
223
|
-
const expected = expectedHeightRef.current;
|
|
224
|
-
const height = textarea.offsetHeight;
|
|
225
|
-
if (expected !== null && Math.abs(height - expected) > 1) {
|
|
226
|
-
userFloorRef.current = height;
|
|
227
|
-
expectedHeightRef.current = height;
|
|
228
|
-
}
|
|
229
|
-
if (textarea.offsetWidth !== lastWidth) {
|
|
230
|
-
lastWidth = textarea.offsetWidth;
|
|
231
|
-
adjustHeight();
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
observer.observe(textarea);
|
|
235
|
-
return () => observer.disconnect();
|
|
236
|
-
}, [autoResize, adjustHeight]);
|
|
237
|
-
const handleChange = React.useCallback(
|
|
238
|
-
(e) => {
|
|
239
|
-
if (value === void 0) {
|
|
240
|
-
setInternalValue(e.target.value);
|
|
241
|
-
}
|
|
242
|
-
onChange?.(e);
|
|
243
|
-
adjustHeight();
|
|
244
|
-
},
|
|
245
|
-
[value, onChange, adjustHeight]
|
|
246
|
-
);
|
|
247
|
-
const describedByIds = [
|
|
248
|
-
error ? errorId : null,
|
|
249
|
-
helperText && !error ? helperId : null,
|
|
250
|
-
showCount ? countId : null,
|
|
251
|
-
ariaDescribedBy
|
|
252
|
-
].filter(Boolean).join(" ");
|
|
253
|
-
const isFloating = labelVariant === "floating" && !!label && !hideLabel;
|
|
254
|
-
const requiredMark = required && /* @__PURE__ */ jsx(RequiredMark, { variant: requiredVariant });
|
|
255
|
-
const textareaElement = /* @__PURE__ */ jsx(
|
|
256
|
-
"textarea",
|
|
257
|
-
{
|
|
258
|
-
"data-slot": "textarea",
|
|
259
|
-
"data-auto-resize": autoResize ? "true" : void 0,
|
|
260
|
-
ref: internalRef,
|
|
261
|
-
id: textareaId,
|
|
262
|
-
value,
|
|
263
|
-
defaultValue: value === void 0 ? defaultValue : void 0,
|
|
264
|
-
onChange: handleChange,
|
|
265
|
-
maxLength,
|
|
266
|
-
"aria-invalid": hasError || !!error,
|
|
267
|
-
"aria-describedby": describedByIds || void 0,
|
|
268
|
-
required,
|
|
269
|
-
rows: autoResize ? rows ?? 1 : rows,
|
|
270
|
-
placeholder: isFloating ? " " : placeholder,
|
|
271
|
-
className: cn(
|
|
272
|
-
textareaVariants({
|
|
273
|
-
size,
|
|
274
|
-
hasError: hasError || !!error,
|
|
275
|
-
resize,
|
|
276
|
-
labelVariant: isFloating ? "floating" : "stacked",
|
|
277
|
-
autoResize
|
|
278
|
-
}),
|
|
279
|
-
className
|
|
280
|
-
),
|
|
281
|
-
...props
|
|
282
|
-
}
|
|
283
|
-
);
|
|
284
|
-
return /* @__PURE__ */ jsxs("div", { "data-slot": "textarea-wrapper", className: "flex flex-col gap-1.5", children: [
|
|
285
|
-
label && !isFloating && /* @__PURE__ */ jsxs(
|
|
286
|
-
"label",
|
|
287
|
-
{
|
|
288
|
-
"data-slot": "textarea-label",
|
|
289
|
-
htmlFor: textareaId,
|
|
290
|
-
className: cn(
|
|
291
|
-
"text-foreground text-sm font-medium",
|
|
292
|
-
hideLabel && "sr-only"
|
|
293
|
-
),
|
|
294
|
-
children: [
|
|
295
|
-
label,
|
|
296
|
-
requiredMark
|
|
297
|
-
]
|
|
298
|
-
}
|
|
299
|
-
),
|
|
300
|
-
isFloating ? /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
301
|
-
textareaElement,
|
|
302
|
-
/* @__PURE__ */ jsxs(
|
|
303
|
-
"label",
|
|
304
|
-
{
|
|
305
|
-
"data-slot": "textarea-label",
|
|
306
|
-
htmlFor: textareaId,
|
|
307
|
-
className: floatingLabelVariants({
|
|
308
|
-
size,
|
|
309
|
-
hasError: hasError || !!error
|
|
310
|
-
}),
|
|
311
|
-
children: [
|
|
312
|
-
label,
|
|
313
|
-
requiredMark
|
|
314
|
-
]
|
|
315
|
-
}
|
|
316
|
-
)
|
|
317
|
-
] }) : textareaElement,
|
|
318
|
-
/* @__PURE__ */ jsxs(
|
|
319
|
-
"div",
|
|
320
|
-
{
|
|
321
|
-
"data-slot": "textarea-footer",
|
|
322
|
-
className: "flex items-center justify-between gap-2",
|
|
323
|
-
children: [
|
|
324
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
325
|
-
error && /* @__PURE__ */ jsx(
|
|
326
|
-
"p",
|
|
327
|
-
{
|
|
328
|
-
id: errorId,
|
|
329
|
-
"data-slot": "textarea-error",
|
|
330
|
-
className: "text-destructive-700 dark:text-destructive-400 text-sm",
|
|
331
|
-
role: "alert",
|
|
332
|
-
children: error
|
|
333
|
-
}
|
|
334
|
-
),
|
|
335
|
-
helperText && !error && /* @__PURE__ */ jsx(
|
|
336
|
-
"p",
|
|
337
|
-
{
|
|
338
|
-
id: helperId,
|
|
339
|
-
"data-slot": "textarea-helper",
|
|
340
|
-
className: "text-muted-foreground text-sm",
|
|
341
|
-
children: helperText
|
|
342
|
-
}
|
|
343
|
-
)
|
|
344
|
-
] }),
|
|
345
|
-
showCount && /* @__PURE__ */ jsxs(
|
|
346
|
-
"p",
|
|
347
|
-
{
|
|
348
|
-
id: countId,
|
|
349
|
-
"data-slot": "textarea-count",
|
|
350
|
-
className: cn(
|
|
351
|
-
"text-muted-foreground shrink-0 text-xs",
|
|
352
|
-
maxLength && characterCount >= maxLength && "text-destructive"
|
|
353
|
-
),
|
|
354
|
-
children: [
|
|
355
|
-
characterCount,
|
|
356
|
-
maxLength && `/${maxLength}`
|
|
357
|
-
]
|
|
358
|
-
}
|
|
359
|
-
)
|
|
360
|
-
]
|
|
361
|
-
}
|
|
362
|
-
)
|
|
363
|
-
] });
|
|
364
|
-
}
|
|
365
|
-
);
|
|
366
|
-
Textarea.displayName = "Textarea";
|
|
367
|
-
|
|
368
|
-
export { Textarea, textareaVariants };
|
|
369
|
-
//# sourceMappingURL=chunk-CPG7SDON.js.map
|
|
370
|
-
//# sourceMappingURL=chunk-CPG7SDON.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Textarea/Textarea.tsx"],"names":[],"mappings":"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","file":"chunk-CPG7SDON.js","sourcesContent":["import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils/cn';\nimport { RequiredMark, type RequiredMarkVariant } from '../Input';\n\nconst textareaVariants = cva(\n [\n 'w-full px-3 py-2',\n 'border border-input rounded-lg',\n 'bg-background text-foreground',\n 'placeholder:text-muted-foreground',\n 'transition-colors duration-200',\n 'focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'resize-y',\n ],\n {\n variants: {\n size: {\n sm: 'text-sm min-h-[60px]',\n md: 'text-base min-h-[80px]',\n lg: 'text-lg min-h-[100px]',\n },\n hasError: {\n true: 'border-destructive focus:ring-destructive',\n false: '',\n },\n resize: {\n none: 'resize-none',\n vertical: 'resize-y',\n horizontal: 'resize-x',\n both: 'resize',\n },\n labelVariant: {\n stacked: '',\n floating: 'peer placeholder:text-transparent',\n },\n autoResize: {\n true: '',\n false: '',\n },\n },\n compoundVariants: [\n // Floating labels reserve top padding so entered text always starts\n // below the floated label, plus a little extra min-height.\n {\n labelVariant: 'floating',\n size: 'sm',\n className: 'pt-5 min-h-[76px]',\n },\n {\n labelVariant: 'floating',\n size: 'md',\n className: 'pt-6 min-h-[96px]',\n },\n {\n labelVariant: 'floating',\n size: 'lg',\n className: 'pt-7 min-h-[120px]',\n },\n // Auto-growing textareas start at the same visual height as a\n // single-line Input (h-8/h-10/h-12): min-height matches the Input\n // size token and the vertical padding is tuned so one line of text\n // plus padding plus borders lands exactly on that height.\n {\n autoResize: true,\n labelVariant: 'stacked',\n size: 'sm',\n className: 'min-h-8 py-[5px]',\n },\n {\n autoResize: true,\n labelVariant: 'stacked',\n size: 'md',\n className: 'min-h-10 py-[7px]',\n },\n {\n autoResize: true,\n labelVariant: 'stacked',\n size: 'lg',\n className: 'min-h-12 py-[9px]',\n },\n // Floating label + auto-grow: single line below the floated label.\n {\n autoResize: true,\n labelVariant: 'floating',\n size: 'sm',\n className: 'min-h-[50px]',\n },\n {\n autoResize: true,\n labelVariant: 'floating',\n size: 'md',\n className: 'min-h-[58px]',\n },\n {\n autoResize: true,\n labelVariant: 'floating',\n size: 'lg',\n className: 'min-h-[66px]',\n },\n ],\n defaultVariants: {\n size: 'md',\n hasError: false,\n resize: 'vertical',\n labelVariant: 'stacked',\n autoResize: true,\n },\n }\n);\n\nconst floatingLabelVariants = cva(\n [\n 'absolute start-3 pointer-events-none select-none',\n 'transition-all duration-200 ease-out',\n ],\n {\n variants: {\n size: {\n sm: [\n 'text-sm top-3',\n 'peer-focus:top-1 peer-[:not(:placeholder-shown)]:top-1 peer-autofill:top-1',\n 'peer-focus:text-[0.65rem] peer-[:not(:placeholder-shown)]:text-[0.65rem] peer-autofill:text-[0.65rem]',\n ],\n md: [\n 'text-base top-4',\n 'peer-focus:top-1.5 peer-[:not(:placeholder-shown)]:top-1.5 peer-autofill:top-1.5',\n 'peer-focus:text-xs peer-[:not(:placeholder-shown)]:text-xs peer-autofill:text-xs',\n ],\n lg: [\n 'text-lg top-5',\n 'peer-focus:top-2 peer-[:not(:placeholder-shown)]:top-2 peer-autofill:top-2',\n 'peer-focus:text-sm peer-[:not(:placeholder-shown)]:text-sm peer-autofill:text-sm',\n ],\n },\n hasError: {\n true: 'text-destructive',\n false: 'text-muted-foreground',\n },\n },\n defaultVariants: {\n size: 'md',\n hasError: false,\n },\n }\n);\n\nexport interface TextareaProps\n extends\n Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>,\n Omit<VariantProps<typeof textareaVariants>, 'labelVariant'> {\n /** Label for the textarea */\n label?: string;\n /**\n * How the label is rendered.\n * - `stacked` (default): label above the textarea.\n * - `floating`: label rests inside the textarea like a placeholder and\n * floats to the top (staying inside it) when focused or filled.\n * Ignores `placeholder`; when `hideLabel` is set, falls back to a\n * visually-hidden stacked label.\n */\n labelVariant?: 'stacked' | 'floating';\n /** Whether the label should be visually hidden */\n hideLabel?: boolean;\n /** Error message to display */\n error?: string;\n /** Helper text to display */\n helperText?: string;\n /** Maximum character count */\n maxLength?: number;\n /** Show character count */\n showCount?: boolean;\n /**\n * Grow and shrink with content (default). The empty control matches a\n * single-line `Input`'s height; `rows` sets a taller growth floor, and\n * dragging the native resize handle sets a new floor the same way. Set\n * `false` for a classic fixed-height textarea.\n */\n autoResize?: boolean;\n /**\n * Color of the required asterisk.\n * - `default`: destructive (hard requirement).\n * - `warning`: warning color (soft requirement / recommended).\n */\n requiredVariant?: RequiredMarkVariant;\n}\n\n/**\n * A multi-line text input component with character count and auto-resize.\n *\n * @example\n * ```tsx\n * <Textarea label=\"Description\" placeholder=\"Enter a description...\" />\n * <Textarea\n * label=\"Bio\"\n * maxLength={280}\n * showCount\n * helperText=\"Tell us about yourself\"\n * />\n * ```\n */\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n (\n {\n className,\n size,\n hasError,\n resize,\n label,\n labelVariant = 'stacked',\n hideLabel,\n error,\n helperText,\n maxLength,\n showCount = false,\n autoResize = true,\n required = false,\n requiredVariant,\n id,\n rows,\n value,\n defaultValue,\n onChange,\n placeholder,\n 'aria-describedby': ariaDescribedBy,\n ...props\n },\n ref\n ) => {\n const internalRef = React.useRef<HTMLTextAreaElement>(null);\n const [internalValue, setInternalValue] = React.useState(\n (defaultValue as string) || ''\n );\n\n const generatedId = React.useId();\n const textareaId = id || generatedId;\n const errorId = `${textareaId}-error`;\n const helperId = `${textareaId}-helper`;\n const countId = `${textareaId}-count`;\n\n // Combine refs\n React.useImperativeHandle(ref, () => internalRef.current!);\n\n // Get current value\n const currentValue = value !== undefined ? String(value) : internalValue;\n const characterCount = currentValue.length;\n\n // Auto-resize logic: collapse to natural height, then grow to fit\n // content. CSS min-height (single-line baseline) and rows (via\n // scrollHeight) act as floors; a consumer-configured initial height\n // (style/class) and dragging the native resize handle set a user floor;\n // a consumer max-height still caps the rendered height.\n const userFloorRef = React.useRef<number | null>(null);\n const expectedHeightRef = React.useRef<number | null>(null);\n const initialFloorCapturedRef = React.useRef(false);\n\n const adjustHeight = React.useCallback(() => {\n const textarea = internalRef.current;\n if (textarea && autoResize) {\n textarea.style.height = 'auto';\n const borders = textarea.offsetHeight - textarea.clientHeight;\n const next = Math.max(\n textarea.scrollHeight + borders,\n userFloorRef.current ?? 0\n );\n textarea.style.height = `${next}px`;\n // Record the actual rendered height (a CSS max-height may clamp the\n // value we set) so clamping is never mistaken for a manual drag.\n expectedHeightRef.current = textarea.offsetHeight || next;\n }\n }, [autoResize]);\n\n // Measures prefilled values on mount and controlled values on update.\n // On mount, a consumer-configured initial height (inline style or a\n // height class) that exceeds the content height becomes the growth\n // floor — auto-sizing must not collapse below a configured baseline.\n React.useEffect(() => {\n const textarea = internalRef.current;\n if (textarea && autoResize && !initialFloorCapturedRef.current) {\n initialFloorCapturedRef.current = true;\n const configured = textarea.offsetHeight;\n adjustHeight();\n if (configured - textarea.offsetHeight > 1) {\n userFloorRef.current = configured;\n textarea.style.height = `${configured}px`;\n expectedHeightRef.current = textarea.offsetHeight || configured;\n }\n return;\n }\n adjustHeight();\n }, [currentValue, adjustHeight, autoResize]);\n\n // Re-measure when the available width changes (wrapping changes), and\n // detect heights we didn't set ourselves — the user dragging the native\n // resize handle — adopting the dragged height as the new growth floor.\n // The drag check runs first so a diagonal resize (width + height in one\n // notification) keeps the dragged height through the re-measure.\n React.useEffect(() => {\n const textarea = internalRef.current;\n if (!autoResize || !textarea || typeof ResizeObserver === 'undefined') {\n return;\n }\n let lastWidth = textarea.offsetWidth;\n const observer = new ResizeObserver(() => {\n const expected = expectedHeightRef.current;\n const height = textarea.offsetHeight;\n if (expected !== null && Math.abs(height - expected) > 1) {\n userFloorRef.current = height;\n expectedHeightRef.current = height;\n }\n if (textarea.offsetWidth !== lastWidth) {\n lastWidth = textarea.offsetWidth;\n adjustHeight();\n }\n });\n observer.observe(textarea);\n return () => observer.disconnect();\n }, [autoResize, adjustHeight]);\n\n // Handle change\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n if (value === undefined) {\n setInternalValue(e.target.value);\n }\n onChange?.(e);\n adjustHeight();\n },\n [value, onChange, adjustHeight]\n );\n\n // Build aria-describedby\n const describedByIds = [\n error ? errorId : null,\n helperText && !error ? helperId : null,\n showCount ? countId : null,\n ariaDescribedBy,\n ]\n .filter(Boolean)\n .join(' ');\n\n const isFloating = labelVariant === 'floating' && !!label && !hideLabel;\n\n const requiredMark = required && <RequiredMark variant={requiredVariant} />;\n\n const textareaElement = (\n <textarea\n data-slot=\"textarea\"\n data-auto-resize={autoResize ? 'true' : undefined}\n ref={internalRef}\n id={textareaId}\n value={value}\n defaultValue={value === undefined ? defaultValue : undefined}\n onChange={handleChange}\n maxLength={maxLength}\n aria-invalid={hasError || !!error}\n aria-describedby={describedByIds || undefined}\n required={required}\n // Auto-grow starts at one visible line; an explicit rows raises the\n // floor (scrollHeight never reports less than the rows box).\n rows={autoResize ? (rows ?? 1) : rows}\n // A single-space placeholder keeps :placeholder-shown reliable so the\n // label can float via CSS alone.\n placeholder={isFloating ? ' ' : placeholder}\n className={cn(\n textareaVariants({\n size,\n hasError: hasError || !!error,\n resize,\n labelVariant: isFloating ? 'floating' : 'stacked',\n autoResize,\n }),\n className\n )}\n {...props}\n />\n );\n\n return (\n <div data-slot=\"textarea-wrapper\" className=\"flex flex-col gap-1.5\">\n {label && !isFloating && (\n <label\n data-slot=\"textarea-label\"\n htmlFor={textareaId}\n className={cn(\n 'text-foreground text-sm font-medium',\n hideLabel && 'sr-only'\n )}\n >\n {label}\n {requiredMark}\n </label>\n )}\n {isFloating ? (\n <div className=\"relative\">\n {textareaElement}\n <label\n data-slot=\"textarea-label\"\n htmlFor={textareaId}\n className={floatingLabelVariants({\n size,\n hasError: hasError || !!error,\n })}\n >\n {label}\n {requiredMark}\n </label>\n </div>\n ) : (\n textareaElement\n )}\n <div\n data-slot=\"textarea-footer\"\n className=\"flex items-center justify-between gap-2\"\n >\n <div className=\"flex-1\">\n {error && (\n <p\n id={errorId}\n data-slot=\"textarea-error\"\n className=\"text-destructive-700 dark:text-destructive-400 text-sm\"\n role=\"alert\"\n >\n {error}\n </p>\n )}\n {helperText && !error && (\n <p\n id={helperId}\n data-slot=\"textarea-helper\"\n className=\"text-muted-foreground text-sm\"\n >\n {helperText}\n </p>\n )}\n </div>\n {showCount && (\n <p\n id={countId}\n data-slot=\"textarea-count\"\n className={cn(\n 'text-muted-foreground shrink-0 text-xs',\n maxLength && characterCount >= maxLength && 'text-destructive'\n )}\n >\n {characterCount}\n {maxLength && `/${maxLength}`}\n </p>\n )}\n </div>\n </div>\n );\n }\n);\n\nTextarea.displayName = 'Textarea';\n\nexport { Textarea, textareaVariants };\n"]}
|