@mieweb/ui 0.11.0-dev.28 → 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-3XVJYGEE.js → chunk-43QBEF6N.js} +51 -18
- package/dist/chunk-43QBEF6N.js.map +1 -0
- package/dist/{chunk-J4IIHRMP.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-24MB5436.js → chunk-AK4LHJPC.js} +5 -2
- 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-E63B5DB7.js → chunk-MBDT2MGR.js} +4 -4
- package/dist/{chunk-E63B5DB7.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-CXJWYWST.cjs → chunk-PRA2V5BP.cjs} +7 -7
- package/dist/{chunk-CXJWYWST.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-XL4XN4I6.cjs → chunk-ZLBNYCYT.cjs} +5 -2
- 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 +20 -0
- package/dist/components/RichTextEditor/index.d.ts +20 -0
- 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 -151
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +113 -52
- package/dist/index.d.ts +113 -52
- 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-24MB5436.js.map +0 -1
- package/dist/chunk-3XVJYGEE.js.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-J4IIHRMP.cjs.map +0 -1
- package/dist/chunk-XL4XN4I6.cjs.map +0 -1
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk6GKIISNZ_cjs = require('./chunk-6GKIISNZ.cjs');
|
|
4
|
+
var chunkZ5S5JEJD_cjs = require('./chunk-Z5S5JEJD.cjs');
|
|
5
|
+
var chunkS5RVSXDV_cjs = require('./chunk-S5RVSXDV.cjs');
|
|
6
|
+
var React2 = require('react');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
|
|
29
|
+
|
|
30
|
+
var TextAreaRich = React2__namespace.forwardRef(
|
|
31
|
+
({ className, markdownShortcuts = true, defaultToolbar = "hidden", ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
32
|
+
chunk6GKIISNZ_cjs.RichTextEditor,
|
|
33
|
+
{
|
|
34
|
+
ref,
|
|
35
|
+
chromeless: true,
|
|
36
|
+
blockMenu: true,
|
|
37
|
+
markdownShortcuts,
|
|
38
|
+
defaultToolbar,
|
|
39
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
40
|
+
// Textarea's chrome: border, radius, focus ring (on the wrapper via
|
|
41
|
+
// focus-within since the editable sits inside it).
|
|
42
|
+
"border-input rounded-lg border",
|
|
43
|
+
"transition-colors duration-200",
|
|
44
|
+
"focus-within:ring-ring focus-within:border-transparent focus-within:ring-2",
|
|
45
|
+
className
|
|
46
|
+
),
|
|
47
|
+
...rest
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
TextAreaRich.displayName = "TextAreaRich";
|
|
52
|
+
var textareaVariants = classVarianceAuthority.cva(
|
|
53
|
+
[
|
|
54
|
+
"w-full px-3 py-2",
|
|
55
|
+
"border border-input rounded-lg",
|
|
56
|
+
"bg-background text-foreground",
|
|
57
|
+
"placeholder:text-muted-foreground",
|
|
58
|
+
"transition-colors duration-200",
|
|
59
|
+
"focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent",
|
|
60
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
61
|
+
"resize-y"
|
|
62
|
+
],
|
|
63
|
+
{
|
|
64
|
+
variants: {
|
|
65
|
+
size: {
|
|
66
|
+
sm: "text-sm min-h-[60px]",
|
|
67
|
+
md: "text-base min-h-[80px]",
|
|
68
|
+
lg: "text-lg min-h-[100px]"
|
|
69
|
+
},
|
|
70
|
+
hasError: {
|
|
71
|
+
true: "border-destructive focus:ring-destructive",
|
|
72
|
+
false: ""
|
|
73
|
+
},
|
|
74
|
+
resize: {
|
|
75
|
+
none: "resize-none",
|
|
76
|
+
vertical: "resize-y",
|
|
77
|
+
horizontal: "resize-x",
|
|
78
|
+
both: "resize"
|
|
79
|
+
},
|
|
80
|
+
labelVariant: {
|
|
81
|
+
stacked: "",
|
|
82
|
+
floating: "peer placeholder:text-transparent"
|
|
83
|
+
},
|
|
84
|
+
autoResize: {
|
|
85
|
+
true: "",
|
|
86
|
+
false: ""
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
compoundVariants: [
|
|
90
|
+
// Floating labels reserve top padding so entered text always starts
|
|
91
|
+
// below the floated label, plus a little extra min-height.
|
|
92
|
+
{
|
|
93
|
+
labelVariant: "floating",
|
|
94
|
+
size: "sm",
|
|
95
|
+
className: "pt-5 min-h-[76px]"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
labelVariant: "floating",
|
|
99
|
+
size: "md",
|
|
100
|
+
className: "pt-6 min-h-[96px]"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
labelVariant: "floating",
|
|
104
|
+
size: "lg",
|
|
105
|
+
className: "pt-7 min-h-[120px]"
|
|
106
|
+
},
|
|
107
|
+
// Auto-growing textareas start at the same visual height as a
|
|
108
|
+
// single-line Input (h-8/h-10/h-12): min-height matches the Input
|
|
109
|
+
// size token and the vertical padding is tuned so one line of text
|
|
110
|
+
// plus padding plus borders lands exactly on that height.
|
|
111
|
+
{
|
|
112
|
+
autoResize: true,
|
|
113
|
+
labelVariant: "stacked",
|
|
114
|
+
size: "sm",
|
|
115
|
+
className: "min-h-8 py-[5px]"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
autoResize: true,
|
|
119
|
+
labelVariant: "stacked",
|
|
120
|
+
size: "md",
|
|
121
|
+
className: "min-h-10 py-[7px]"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
autoResize: true,
|
|
125
|
+
labelVariant: "stacked",
|
|
126
|
+
size: "lg",
|
|
127
|
+
className: "min-h-12 py-[9px]"
|
|
128
|
+
},
|
|
129
|
+
// Floating label + auto-grow: single line below the floated label.
|
|
130
|
+
{
|
|
131
|
+
autoResize: true,
|
|
132
|
+
labelVariant: "floating",
|
|
133
|
+
size: "sm",
|
|
134
|
+
className: "min-h-[50px]"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
autoResize: true,
|
|
138
|
+
labelVariant: "floating",
|
|
139
|
+
size: "md",
|
|
140
|
+
className: "min-h-[58px]"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
autoResize: true,
|
|
144
|
+
labelVariant: "floating",
|
|
145
|
+
size: "lg",
|
|
146
|
+
className: "min-h-[66px]"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
defaultVariants: {
|
|
150
|
+
size: "md",
|
|
151
|
+
hasError: false,
|
|
152
|
+
resize: "vertical",
|
|
153
|
+
labelVariant: "stacked",
|
|
154
|
+
autoResize: true
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
var floatingLabelVariants = classVarianceAuthority.cva(
|
|
159
|
+
[
|
|
160
|
+
"absolute start-3 pointer-events-none select-none",
|
|
161
|
+
"transition-all duration-200 ease-out"
|
|
162
|
+
],
|
|
163
|
+
{
|
|
164
|
+
variants: {
|
|
165
|
+
size: {
|
|
166
|
+
sm: [
|
|
167
|
+
"text-sm top-3",
|
|
168
|
+
"peer-focus:top-1 peer-[:not(:placeholder-shown)]:top-1 peer-autofill:top-1",
|
|
169
|
+
"peer-focus:text-[0.65rem] peer-[:not(:placeholder-shown)]:text-[0.65rem] peer-autofill:text-[0.65rem]"
|
|
170
|
+
],
|
|
171
|
+
md: [
|
|
172
|
+
"text-base top-4",
|
|
173
|
+
"peer-focus:top-1.5 peer-[:not(:placeholder-shown)]:top-1.5 peer-autofill:top-1.5",
|
|
174
|
+
"peer-focus:text-xs peer-[:not(:placeholder-shown)]:text-xs peer-autofill:text-xs"
|
|
175
|
+
],
|
|
176
|
+
lg: [
|
|
177
|
+
"text-lg top-5",
|
|
178
|
+
"peer-focus:top-2 peer-[:not(:placeholder-shown)]:top-2 peer-autofill:top-2",
|
|
179
|
+
"peer-focus:text-sm peer-[:not(:placeholder-shown)]:text-sm peer-autofill:text-sm"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
hasError: {
|
|
183
|
+
true: "text-destructive",
|
|
184
|
+
false: "text-muted-foreground"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
defaultVariants: {
|
|
188
|
+
size: "md",
|
|
189
|
+
hasError: false
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
var TextAreaPlain = React2__namespace.forwardRef(
|
|
194
|
+
({
|
|
195
|
+
className,
|
|
196
|
+
size,
|
|
197
|
+
hasError,
|
|
198
|
+
resize,
|
|
199
|
+
label,
|
|
200
|
+
labelVariant = "stacked",
|
|
201
|
+
hideLabel,
|
|
202
|
+
error,
|
|
203
|
+
helperText,
|
|
204
|
+
maxLength,
|
|
205
|
+
showCount = false,
|
|
206
|
+
autoResize = true,
|
|
207
|
+
required = false,
|
|
208
|
+
requiredVariant,
|
|
209
|
+
id,
|
|
210
|
+
rows,
|
|
211
|
+
value,
|
|
212
|
+
defaultValue,
|
|
213
|
+
onChange,
|
|
214
|
+
placeholder,
|
|
215
|
+
"aria-describedby": ariaDescribedBy,
|
|
216
|
+
...props
|
|
217
|
+
}, ref) => {
|
|
218
|
+
const internalRef = React2__namespace.useRef(null);
|
|
219
|
+
const [internalValue, setInternalValue] = React2__namespace.useState(
|
|
220
|
+
defaultValue || ""
|
|
221
|
+
);
|
|
222
|
+
const generatedId = React2__namespace.useId();
|
|
223
|
+
const textareaId = id || generatedId;
|
|
224
|
+
const errorId = `${textareaId}-error`;
|
|
225
|
+
const helperId = `${textareaId}-helper`;
|
|
226
|
+
const countId = `${textareaId}-count`;
|
|
227
|
+
React2__namespace.useImperativeHandle(ref, () => internalRef.current);
|
|
228
|
+
const currentValue = value !== void 0 ? String(value) : internalValue;
|
|
229
|
+
const characterCount = currentValue.length;
|
|
230
|
+
const userFloorRef = React2__namespace.useRef(null);
|
|
231
|
+
const expectedHeightRef = React2__namespace.useRef(null);
|
|
232
|
+
const initialFloorCapturedRef = React2__namespace.useRef(false);
|
|
233
|
+
const adjustHeight = React2__namespace.useCallback(() => {
|
|
234
|
+
const textarea = internalRef.current;
|
|
235
|
+
if (textarea && autoResize) {
|
|
236
|
+
textarea.style.height = "auto";
|
|
237
|
+
const borders = textarea.offsetHeight - textarea.clientHeight;
|
|
238
|
+
const next = Math.max(
|
|
239
|
+
textarea.scrollHeight + borders,
|
|
240
|
+
userFloorRef.current ?? 0
|
|
241
|
+
);
|
|
242
|
+
textarea.style.height = `${next}px`;
|
|
243
|
+
expectedHeightRef.current = textarea.offsetHeight || next;
|
|
244
|
+
}
|
|
245
|
+
}, [autoResize]);
|
|
246
|
+
React2__namespace.useEffect(() => {
|
|
247
|
+
const textarea = internalRef.current;
|
|
248
|
+
if (textarea && autoResize && !initialFloorCapturedRef.current) {
|
|
249
|
+
initialFloorCapturedRef.current = true;
|
|
250
|
+
const configured = textarea.offsetHeight;
|
|
251
|
+
adjustHeight();
|
|
252
|
+
if (configured - textarea.offsetHeight > 1) {
|
|
253
|
+
userFloorRef.current = configured;
|
|
254
|
+
textarea.style.height = `${configured}px`;
|
|
255
|
+
expectedHeightRef.current = textarea.offsetHeight || configured;
|
|
256
|
+
}
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
adjustHeight();
|
|
260
|
+
}, [currentValue, adjustHeight, autoResize]);
|
|
261
|
+
React2__namespace.useEffect(() => {
|
|
262
|
+
const textarea = internalRef.current;
|
|
263
|
+
if (!autoResize || !textarea || typeof ResizeObserver === "undefined") {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
let lastWidth = textarea.offsetWidth;
|
|
267
|
+
const observer = new ResizeObserver(() => {
|
|
268
|
+
const expected = expectedHeightRef.current;
|
|
269
|
+
const height = textarea.offsetHeight;
|
|
270
|
+
if (expected !== null && Math.abs(height - expected) > 1) {
|
|
271
|
+
userFloorRef.current = height;
|
|
272
|
+
expectedHeightRef.current = height;
|
|
273
|
+
}
|
|
274
|
+
if (textarea.offsetWidth !== lastWidth) {
|
|
275
|
+
lastWidth = textarea.offsetWidth;
|
|
276
|
+
adjustHeight();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
observer.observe(textarea);
|
|
280
|
+
return () => observer.disconnect();
|
|
281
|
+
}, [autoResize, adjustHeight]);
|
|
282
|
+
const handleChange = React2__namespace.useCallback(
|
|
283
|
+
(e) => {
|
|
284
|
+
if (value === void 0) {
|
|
285
|
+
setInternalValue(e.target.value);
|
|
286
|
+
}
|
|
287
|
+
onChange?.(e);
|
|
288
|
+
adjustHeight();
|
|
289
|
+
},
|
|
290
|
+
[value, onChange, adjustHeight]
|
|
291
|
+
);
|
|
292
|
+
const describedByIds = [
|
|
293
|
+
error ? errorId : null,
|
|
294
|
+
helperText && !error ? helperId : null,
|
|
295
|
+
showCount ? countId : null,
|
|
296
|
+
ariaDescribedBy
|
|
297
|
+
].filter(Boolean).join(" ");
|
|
298
|
+
const isFloating = labelVariant === "floating" && !!label && !hideLabel;
|
|
299
|
+
const requiredMark = required && /* @__PURE__ */ jsxRuntime.jsx(chunkZ5S5JEJD_cjs.RequiredMark, { variant: requiredVariant });
|
|
300
|
+
const textareaElement = /* @__PURE__ */ jsxRuntime.jsx(
|
|
301
|
+
"textarea",
|
|
302
|
+
{
|
|
303
|
+
"data-slot": "textarea",
|
|
304
|
+
"data-auto-resize": autoResize ? "true" : void 0,
|
|
305
|
+
ref: internalRef,
|
|
306
|
+
id: textareaId,
|
|
307
|
+
value,
|
|
308
|
+
defaultValue: value === void 0 ? defaultValue : void 0,
|
|
309
|
+
onChange: handleChange,
|
|
310
|
+
maxLength,
|
|
311
|
+
"aria-invalid": hasError || !!error,
|
|
312
|
+
"aria-describedby": describedByIds || void 0,
|
|
313
|
+
required,
|
|
314
|
+
rows: autoResize ? rows ?? 1 : rows,
|
|
315
|
+
placeholder: isFloating ? " " : placeholder,
|
|
316
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
317
|
+
textareaVariants({
|
|
318
|
+
size,
|
|
319
|
+
hasError: hasError || !!error,
|
|
320
|
+
resize,
|
|
321
|
+
labelVariant: isFloating ? "floating" : "stacked",
|
|
322
|
+
autoResize
|
|
323
|
+
}),
|
|
324
|
+
className
|
|
325
|
+
),
|
|
326
|
+
...props
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "textarea-wrapper", className: "flex flex-col gap-1.5", children: [
|
|
330
|
+
label && !isFloating && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
331
|
+
"label",
|
|
332
|
+
{
|
|
333
|
+
"data-slot": "textarea-label",
|
|
334
|
+
htmlFor: textareaId,
|
|
335
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
336
|
+
"text-foreground text-sm font-medium",
|
|
337
|
+
hideLabel && "sr-only"
|
|
338
|
+
),
|
|
339
|
+
children: [
|
|
340
|
+
label,
|
|
341
|
+
requiredMark
|
|
342
|
+
]
|
|
343
|
+
}
|
|
344
|
+
),
|
|
345
|
+
isFloating ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
346
|
+
textareaElement,
|
|
347
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
348
|
+
"label",
|
|
349
|
+
{
|
|
350
|
+
"data-slot": "textarea-label",
|
|
351
|
+
htmlFor: textareaId,
|
|
352
|
+
className: floatingLabelVariants({
|
|
353
|
+
size,
|
|
354
|
+
hasError: hasError || !!error
|
|
355
|
+
}),
|
|
356
|
+
children: [
|
|
357
|
+
label,
|
|
358
|
+
requiredMark
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
] }) : textareaElement,
|
|
363
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
364
|
+
"div",
|
|
365
|
+
{
|
|
366
|
+
"data-slot": "textarea-footer",
|
|
367
|
+
className: "flex items-center justify-between gap-2",
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
370
|
+
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
371
|
+
"p",
|
|
372
|
+
{
|
|
373
|
+
id: errorId,
|
|
374
|
+
"data-slot": "textarea-error",
|
|
375
|
+
className: "text-destructive-700 dark:text-destructive-400 text-sm",
|
|
376
|
+
role: "alert",
|
|
377
|
+
children: error
|
|
378
|
+
}
|
|
379
|
+
),
|
|
380
|
+
helperText && !error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
381
|
+
"p",
|
|
382
|
+
{
|
|
383
|
+
id: helperId,
|
|
384
|
+
"data-slot": "textarea-helper",
|
|
385
|
+
className: "text-muted-foreground text-sm",
|
|
386
|
+
children: helperText
|
|
387
|
+
}
|
|
388
|
+
)
|
|
389
|
+
] }),
|
|
390
|
+
showCount && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
391
|
+
"p",
|
|
392
|
+
{
|
|
393
|
+
id: countId,
|
|
394
|
+
"data-slot": "textarea-count",
|
|
395
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
396
|
+
"text-muted-foreground shrink-0 text-xs",
|
|
397
|
+
maxLength && characterCount >= maxLength && "text-destructive"
|
|
398
|
+
),
|
|
399
|
+
children: [
|
|
400
|
+
characterCount,
|
|
401
|
+
maxLength && `/${maxLength}`
|
|
402
|
+
]
|
|
403
|
+
}
|
|
404
|
+
)
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
] });
|
|
409
|
+
}
|
|
410
|
+
);
|
|
411
|
+
TextAreaPlain.displayName = "TextAreaPlain";
|
|
412
|
+
function escapeHtml(text) {
|
|
413
|
+
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
414
|
+
}
|
|
415
|
+
function normalizeNewlines(text) {
|
|
416
|
+
return text.replace(/\r\n?/g, "\n");
|
|
417
|
+
}
|
|
418
|
+
function plainToHtml(text) {
|
|
419
|
+
if (!text) return "";
|
|
420
|
+
return normalizeNewlines(text).split("\n").map((line) => line ? `<p>${escapeHtml(line)}</p>` : "<p><br></p>").join("");
|
|
421
|
+
}
|
|
422
|
+
var BLOCK_TAGS = /* @__PURE__ */ new Set([
|
|
423
|
+
"P",
|
|
424
|
+
"DIV",
|
|
425
|
+
"H1",
|
|
426
|
+
"H2",
|
|
427
|
+
"H3",
|
|
428
|
+
"H4",
|
|
429
|
+
"H5",
|
|
430
|
+
"H6",
|
|
431
|
+
"LI",
|
|
432
|
+
"UL",
|
|
433
|
+
"OL",
|
|
434
|
+
"BLOCKQUOTE",
|
|
435
|
+
"PRE",
|
|
436
|
+
"TABLE",
|
|
437
|
+
"CAPTION",
|
|
438
|
+
"THEAD",
|
|
439
|
+
"TBODY",
|
|
440
|
+
"TFOOT",
|
|
441
|
+
"TR"
|
|
442
|
+
]);
|
|
443
|
+
var CELL_TAGS = /* @__PURE__ */ new Set(["TD", "TH"]);
|
|
444
|
+
var TABLE_STRUCTURE_TAGS = /* @__PURE__ */ new Set([
|
|
445
|
+
"TABLE",
|
|
446
|
+
"THEAD",
|
|
447
|
+
"TBODY",
|
|
448
|
+
"TFOOT",
|
|
449
|
+
"TR"
|
|
450
|
+
]);
|
|
451
|
+
var IGNORED_TAGS = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "TEMPLATE", "NOSCRIPT"]);
|
|
452
|
+
function nodeListToText(nodes) {
|
|
453
|
+
let out = "";
|
|
454
|
+
let afterCell = false;
|
|
455
|
+
for (const node of nodes) {
|
|
456
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
457
|
+
const text = node.textContent ?? "";
|
|
458
|
+
const parentTag = node.parentElement?.tagName;
|
|
459
|
+
if (!text.trim() && parentTag && TABLE_STRUCTURE_TAGS.has(parentTag)) {
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
out += text;
|
|
463
|
+
if (text.trim()) afterCell = false;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
467
|
+
const el = node;
|
|
468
|
+
if (IGNORED_TAGS.has(el.tagName)) continue;
|
|
469
|
+
if (el.tagName === "BR") {
|
|
470
|
+
afterCell = false;
|
|
471
|
+
out += "\n";
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
if (CELL_TAGS.has(el.tagName)) {
|
|
475
|
+
if (afterCell) out += " ";
|
|
476
|
+
out += nodeListToText(el.childNodes);
|
|
477
|
+
afterCell = true;
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
afterCell = false;
|
|
481
|
+
if (BLOCK_TAGS.has(el.tagName)) {
|
|
482
|
+
if (out && !out.endsWith("\n")) out += "\n";
|
|
483
|
+
let inner = nodeListToText(el.childNodes);
|
|
484
|
+
if (inner === "\n") inner = "";
|
|
485
|
+
out += inner;
|
|
486
|
+
if (inner === "" || !inner.endsWith("\n")) out += "\n";
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
out += nodeListToText(el.childNodes);
|
|
490
|
+
}
|
|
491
|
+
return out;
|
|
492
|
+
}
|
|
493
|
+
function htmlToPlain(html) {
|
|
494
|
+
if (!html) return "";
|
|
495
|
+
const root = document.createElement("template");
|
|
496
|
+
root.innerHTML = html;
|
|
497
|
+
const text = nodeListToText(root.content.childNodes);
|
|
498
|
+
return text.endsWith("\n") ? text.slice(0, -1) : text;
|
|
499
|
+
}
|
|
500
|
+
function sanitizePastedHtml(html) {
|
|
501
|
+
return plainToHtml(htmlToPlain(html));
|
|
502
|
+
}
|
|
503
|
+
var warned = /* @__PURE__ */ new Set();
|
|
504
|
+
function warnOnce(key, message) {
|
|
505
|
+
if (process.env.NODE_ENV !== "production" && !warned.has(key)) {
|
|
506
|
+
warned.add(key);
|
|
507
|
+
console.warn(`[mieweb/ui Textarea] ${message}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
var RichTextarea = React2__namespace.forwardRef(
|
|
511
|
+
({
|
|
512
|
+
label,
|
|
513
|
+
labelVariant = "stacked",
|
|
514
|
+
hideLabel,
|
|
515
|
+
error,
|
|
516
|
+
helperText,
|
|
517
|
+
maxLength,
|
|
518
|
+
showCount,
|
|
519
|
+
autoResize = true,
|
|
520
|
+
requiredVariant,
|
|
521
|
+
size = "md",
|
|
522
|
+
hasError,
|
|
523
|
+
resize,
|
|
524
|
+
className,
|
|
525
|
+
value,
|
|
526
|
+
defaultValue,
|
|
527
|
+
onChange,
|
|
528
|
+
onBlur,
|
|
529
|
+
onFocus,
|
|
530
|
+
onKeyDown,
|
|
531
|
+
onKeyUp,
|
|
532
|
+
name,
|
|
533
|
+
form,
|
|
534
|
+
id,
|
|
535
|
+
rows,
|
|
536
|
+
required,
|
|
537
|
+
readOnly,
|
|
538
|
+
disabled,
|
|
539
|
+
placeholder,
|
|
540
|
+
"aria-describedby": ariaDescribedBy,
|
|
541
|
+
"aria-label": ariaLabel,
|
|
542
|
+
"aria-labelledby": ariaLabelledBy
|
|
543
|
+
}, ref) => {
|
|
544
|
+
warnOnce(
|
|
545
|
+
"rich-upgrade",
|
|
546
|
+
'Since 0.12.0 Textarea renders a rich text surface (plain-text value contract unchanged). Watch for: CSS "textarea" selectors, E2E fill()/type(), and maxLength no longer blocking typing. Opt out per field with richText={false} or use TextAreaPlain. See MIGRATION.md.'
|
|
547
|
+
);
|
|
548
|
+
if (labelVariant === "floating") {
|
|
549
|
+
warnOnce(
|
|
550
|
+
"floating",
|
|
551
|
+
'labelVariant="floating" is not supported by the rich surface; falling back to a stacked label. Use TextAreaPlain for floating labels.'
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
if (autoResize === false) {
|
|
555
|
+
warnOnce(
|
|
556
|
+
"autoResize",
|
|
557
|
+
"autoResize={false} is ignored; the rich surface always grows with content. Use TextAreaPlain for a fixed-height textarea."
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
if (resize !== void 0) {
|
|
561
|
+
warnOnce(
|
|
562
|
+
"resize",
|
|
563
|
+
"resize is ignored; the rich surface has no native resize handle. Use TextAreaPlain for drag-resizing."
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
if (maxLength !== void 0) {
|
|
567
|
+
warnOnce(
|
|
568
|
+
"maxLength",
|
|
569
|
+
"maxLength is not enforced while typing; the character count still reflects it. Enforce limits in onChange or use TextAreaPlain."
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
const reactId = React2__namespace.useId();
|
|
573
|
+
const errorId = `${reactId}-error`;
|
|
574
|
+
const helperId = `${reactId}-helper`;
|
|
575
|
+
const countId = `${reactId}-count`;
|
|
576
|
+
const controlledValue = value !== void 0 ? normalizeNewlines(String(value)) : void 0;
|
|
577
|
+
const [state, setState] = React2__namespace.useState(() => {
|
|
578
|
+
const plain = controlledValue ?? (defaultValue !== void 0 ? normalizeNewlines(String(defaultValue)) : "");
|
|
579
|
+
return { html: plainToHtml(plain), plain };
|
|
580
|
+
});
|
|
581
|
+
if (controlledValue !== void 0 && controlledValue !== state.plain) {
|
|
582
|
+
setState({ html: plainToHtml(controlledValue), plain: controlledValue });
|
|
583
|
+
}
|
|
584
|
+
const hiddenRef = React2__namespace.useRef(null);
|
|
585
|
+
const editorWrapperRef = React2__namespace.useRef(null);
|
|
586
|
+
React2__namespace.useEffect(() => {
|
|
587
|
+
const editable = editorWrapperRef.current?.querySelector(
|
|
588
|
+
'[role="textbox"]'
|
|
589
|
+
);
|
|
590
|
+
if (editable && htmlToPlain(editable.innerHTML) !== state.plain) {
|
|
591
|
+
editable.innerHTML = state.html;
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
const focusEditor = React2__namespace.useCallback(() => {
|
|
595
|
+
editorWrapperRef.current?.querySelector('[role="textbox"]')?.focus();
|
|
596
|
+
}, []);
|
|
597
|
+
React2__namespace.useImperativeHandle(ref, () => {
|
|
598
|
+
const node = hiddenRef.current;
|
|
599
|
+
node.focus = focusEditor;
|
|
600
|
+
node.blur = () => {
|
|
601
|
+
const editable = editorWrapperRef.current?.querySelector(
|
|
602
|
+
'[role="textbox"]'
|
|
603
|
+
);
|
|
604
|
+
if (document.activeElement === editable) editable?.blur();
|
|
605
|
+
};
|
|
606
|
+
return node;
|
|
607
|
+
}, [focusEditor]);
|
|
608
|
+
const [externalLabelId, setExternalLabelId] = React2__namespace.useState();
|
|
609
|
+
React2__namespace.useEffect(() => {
|
|
610
|
+
if (!id) return;
|
|
611
|
+
const externalLabel = document.querySelector(
|
|
612
|
+
`label[for="${globalThis.CSS.escape(id)}"]`
|
|
613
|
+
);
|
|
614
|
+
if (!externalLabel) return;
|
|
615
|
+
if (!externalLabel.id) externalLabel.id = `${reactId}-external-label`;
|
|
616
|
+
setExternalLabelId(externalLabel.id);
|
|
617
|
+
const handleClick = () => focusEditor();
|
|
618
|
+
externalLabel.addEventListener("click", handleClick);
|
|
619
|
+
return () => externalLabel.removeEventListener("click", handleClick);
|
|
620
|
+
}, [id, reactId, focusEditor]);
|
|
621
|
+
const retargetEvent = React2__namespace.useCallback(
|
|
622
|
+
(event) => {
|
|
623
|
+
const node = hiddenRef.current;
|
|
624
|
+
if (!node) return event;
|
|
625
|
+
const retargeted = Object.create(event);
|
|
626
|
+
Object.defineProperties(retargeted, {
|
|
627
|
+
target: { value: node, enumerable: true },
|
|
628
|
+
currentTarget: { value: node, enumerable: true },
|
|
629
|
+
stopPropagation: { value: () => event.stopPropagation() },
|
|
630
|
+
preventDefault: { value: () => event.preventDefault() }
|
|
631
|
+
});
|
|
632
|
+
return retargeted;
|
|
633
|
+
},
|
|
634
|
+
[]
|
|
635
|
+
);
|
|
636
|
+
const focusStaysInside = (event) => {
|
|
637
|
+
const related = event.relatedTarget;
|
|
638
|
+
if (!related) return false;
|
|
639
|
+
if (event.currentTarget.contains(related)) return true;
|
|
640
|
+
const menuId = related.closest('[data-slot="dropdown-menu"]')?.querySelector('[role="menu"]')?.id;
|
|
641
|
+
return !!menuId && !!event.currentTarget.querySelector(
|
|
642
|
+
`[aria-controls="${globalThis.CSS.escape(menuId)}"]`
|
|
643
|
+
);
|
|
644
|
+
};
|
|
645
|
+
const handleHtmlChange = (html) => {
|
|
646
|
+
const plain = htmlToPlain(html);
|
|
647
|
+
setState({ html, plain });
|
|
648
|
+
const node = hiddenRef.current;
|
|
649
|
+
if (onChange && node) {
|
|
650
|
+
node.value = plain;
|
|
651
|
+
const nativeEvent = new Event("change");
|
|
652
|
+
onChange({
|
|
653
|
+
target: node,
|
|
654
|
+
currentTarget: node,
|
|
655
|
+
type: "change",
|
|
656
|
+
bubbles: false,
|
|
657
|
+
cancelable: false,
|
|
658
|
+
defaultPrevented: false,
|
|
659
|
+
eventPhase: 0,
|
|
660
|
+
isTrusted: false,
|
|
661
|
+
timeStamp: Date.now(),
|
|
662
|
+
nativeEvent,
|
|
663
|
+
preventDefault: () => {
|
|
664
|
+
},
|
|
665
|
+
stopPropagation: () => {
|
|
666
|
+
},
|
|
667
|
+
isDefaultPrevented: () => false,
|
|
668
|
+
isPropagationStopped: () => false,
|
|
669
|
+
persist: () => {
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
const showError = !!error;
|
|
675
|
+
const invalid = hasError || showError;
|
|
676
|
+
const describedByIds = [
|
|
677
|
+
showError ? errorId : null,
|
|
678
|
+
helperText && !showError ? helperId : null,
|
|
679
|
+
showCount ? countId : null,
|
|
680
|
+
ariaDescribedBy
|
|
681
|
+
].filter(Boolean).join(" ") || void 0;
|
|
682
|
+
const characterCount = state.plain.length;
|
|
683
|
+
const lineHeightPx = size === "sm" ? 20 : size === "lg" ? 28 : 24;
|
|
684
|
+
const editorStyle = rows ? (
|
|
685
|
+
// 7px block padding each side, matching the editable's py-[7px].
|
|
686
|
+
{ minHeight: `${rows * lineHeightPx + 14}px` }
|
|
687
|
+
) : void 0;
|
|
688
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "textarea-wrapper", className: "flex flex-col gap-1.5", children: [
|
|
689
|
+
label && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
690
|
+
"label",
|
|
691
|
+
{
|
|
692
|
+
"data-slot": "textarea-label",
|
|
693
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
694
|
+
"text-foreground text-sm font-medium",
|
|
695
|
+
hideLabel && "sr-only"
|
|
696
|
+
),
|
|
697
|
+
children: [
|
|
698
|
+
label,
|
|
699
|
+
required && /* @__PURE__ */ jsxRuntime.jsx(chunkZ5S5JEJD_cjs.RequiredMark, { variant: requiredVariant })
|
|
700
|
+
]
|
|
701
|
+
}
|
|
702
|
+
),
|
|
703
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
704
|
+
"div",
|
|
705
|
+
{
|
|
706
|
+
ref: editorWrapperRef,
|
|
707
|
+
className: "w-full",
|
|
708
|
+
onBlur: onBlur && ((event) => {
|
|
709
|
+
if (focusStaysInside(event)) return;
|
|
710
|
+
onBlur(retargetEvent(event));
|
|
711
|
+
}),
|
|
712
|
+
onFocus: onFocus && ((event) => {
|
|
713
|
+
if (focusStaysInside(event)) return;
|
|
714
|
+
onFocus(retargetEvent(event));
|
|
715
|
+
}),
|
|
716
|
+
onKeyDown: onKeyDown && ((event) => onKeyDown(retargetEvent(event))),
|
|
717
|
+
onKeyUp: onKeyUp && ((event) => onKeyUp(retargetEvent(event))),
|
|
718
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
719
|
+
TextAreaRich,
|
|
720
|
+
{
|
|
721
|
+
value: state.html,
|
|
722
|
+
onChange: handleHtmlChange,
|
|
723
|
+
placeholder,
|
|
724
|
+
disabled,
|
|
725
|
+
readOnly,
|
|
726
|
+
id,
|
|
727
|
+
sanitizeHtml: sanitizePastedHtml,
|
|
728
|
+
"aria-label": ariaLabel ?? label,
|
|
729
|
+
"aria-labelledby": ariaLabelledBy ?? externalLabelId,
|
|
730
|
+
"aria-describedby": describedByIds,
|
|
731
|
+
"aria-invalid": invalid || void 0,
|
|
732
|
+
"aria-required": required || void 0,
|
|
733
|
+
editorClassName: chunkS5RVSXDV_cjs.cn(
|
|
734
|
+
// A native textarea renders repeated spaces and tabs
|
|
735
|
+
// faithfully; normal HTML layout would collapse them.
|
|
736
|
+
"whitespace-pre-wrap",
|
|
737
|
+
size === "sm" && "text-sm",
|
|
738
|
+
size === "lg" && "text-lg"
|
|
739
|
+
),
|
|
740
|
+
editorStyle,
|
|
741
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
742
|
+
size === "sm" && "text-sm",
|
|
743
|
+
size === "lg" && "text-lg",
|
|
744
|
+
invalid && "border-destructive focus-within:ring-destructive focus-within:border-destructive",
|
|
745
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
746
|
+
className
|
|
747
|
+
)
|
|
748
|
+
}
|
|
749
|
+
)
|
|
750
|
+
}
|
|
751
|
+
),
|
|
752
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
753
|
+
"textarea",
|
|
754
|
+
{
|
|
755
|
+
"data-slot": "textarea-mirror",
|
|
756
|
+
ref: hiddenRef,
|
|
757
|
+
hidden: true,
|
|
758
|
+
readOnly: true,
|
|
759
|
+
tabIndex: -1,
|
|
760
|
+
"aria-hidden": "true",
|
|
761
|
+
name,
|
|
762
|
+
form,
|
|
763
|
+
required,
|
|
764
|
+
disabled,
|
|
765
|
+
value: state.plain
|
|
766
|
+
}
|
|
767
|
+
),
|
|
768
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
769
|
+
"div",
|
|
770
|
+
{
|
|
771
|
+
"data-slot": "textarea-footer",
|
|
772
|
+
className: "flex items-center justify-between gap-2",
|
|
773
|
+
children: [
|
|
774
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
775
|
+
showError && /* @__PURE__ */ jsxRuntime.jsx(
|
|
776
|
+
"p",
|
|
777
|
+
{
|
|
778
|
+
id: errorId,
|
|
779
|
+
"data-slot": "textarea-error",
|
|
780
|
+
className: "text-destructive-700 dark:text-destructive-400 text-sm",
|
|
781
|
+
role: "alert",
|
|
782
|
+
children: error
|
|
783
|
+
}
|
|
784
|
+
),
|
|
785
|
+
helperText && !showError && /* @__PURE__ */ jsxRuntime.jsx(
|
|
786
|
+
"p",
|
|
787
|
+
{
|
|
788
|
+
id: helperId,
|
|
789
|
+
"data-slot": "textarea-helper",
|
|
790
|
+
className: "text-muted-foreground text-sm",
|
|
791
|
+
children: helperText
|
|
792
|
+
}
|
|
793
|
+
)
|
|
794
|
+
] }),
|
|
795
|
+
showCount && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
796
|
+
"p",
|
|
797
|
+
{
|
|
798
|
+
id: countId,
|
|
799
|
+
"data-slot": "textarea-count",
|
|
800
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
801
|
+
"text-muted-foreground shrink-0 text-xs",
|
|
802
|
+
maxLength && characterCount >= maxLength && "text-destructive"
|
|
803
|
+
),
|
|
804
|
+
children: [
|
|
805
|
+
characterCount,
|
|
806
|
+
maxLength && `/${maxLength}`
|
|
807
|
+
]
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
]
|
|
811
|
+
}
|
|
812
|
+
)
|
|
813
|
+
] });
|
|
814
|
+
}
|
|
815
|
+
);
|
|
816
|
+
RichTextarea.displayName = "RichTextarea";
|
|
817
|
+
var Textarea = React2__namespace.forwardRef(
|
|
818
|
+
({ richText = true, ...props }, ref) => richText ? /* @__PURE__ */ jsxRuntime.jsx(RichTextarea, { ref, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(TextAreaPlain, { ref, ...props })
|
|
819
|
+
);
|
|
820
|
+
Textarea.displayName = "Textarea";
|
|
821
|
+
|
|
822
|
+
exports.TextAreaPlain = TextAreaPlain;
|
|
823
|
+
exports.TextAreaRich = TextAreaRich;
|
|
824
|
+
exports.Textarea = Textarea;
|
|
825
|
+
exports.htmlToPlain = htmlToPlain;
|
|
826
|
+
exports.plainToHtml = plainToHtml;
|
|
827
|
+
exports.textareaVariants = textareaVariants;
|
|
828
|
+
//# sourceMappingURL=chunk-AQUHEKXL.cjs.map
|
|
829
|
+
//# sourceMappingURL=chunk-AQUHEKXL.cjs.map
|