@mieweb/ui 0.9.0 → 0.10.0

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.
Files changed (121) hide show
  1. package/MIGRATION.md +112 -0
  2. package/dist/{Animated-Cs-naa2g.d.cts → Animated-XmH6k8pZ.d.cts} +16 -3
  3. package/dist/{Animated-Cs-naa2g.d.ts → Animated-XmH6k8pZ.d.ts} +16 -3
  4. package/dist/{chunk-XUVEF2RQ.js → chunk-24SEAAOH.js} +2 -2
  5. package/dist/{chunk-XUVEF2RQ.js.map → chunk-24SEAAOH.js.map} +1 -1
  6. package/dist/{chunk-FUFBRKOG.cjs → chunk-2WBPNXO2.cjs} +21 -21
  7. package/dist/{chunk-FUFBRKOG.cjs.map → chunk-2WBPNXO2.cjs.map} +1 -1
  8. package/dist/{chunk-IUDY6S7I.cjs → chunk-37UZHCLM.cjs} +35 -14
  9. package/dist/chunk-37UZHCLM.cjs.map +1 -0
  10. package/dist/{chunk-L52N6BEN.cjs → chunk-AUOTJQGO.cjs} +7 -7
  11. package/dist/{chunk-L52N6BEN.cjs.map → chunk-AUOTJQGO.cjs.map} +1 -1
  12. package/dist/{chunk-6XDPJWSC.cjs → chunk-E7G22IQM.cjs} +32 -28
  13. package/dist/chunk-E7G22IQM.cjs.map +1 -0
  14. package/dist/chunk-IIFQ6BSJ.js +1888 -0
  15. package/dist/chunk-IIFQ6BSJ.js.map +1 -0
  16. package/dist/{chunk-ONNY7UO4.js → chunk-JDJQTKTX.js} +3 -3
  17. package/dist/{chunk-ONNY7UO4.js.map → chunk-JDJQTKTX.js.map} +1 -1
  18. package/dist/{chunk-BJKAVWED.js → chunk-MBWF36DJ.js} +35 -14
  19. package/dist/chunk-MBWF36DJ.js.map +1 -0
  20. package/dist/chunk-NV2CWBI2.cjs +290 -0
  21. package/dist/chunk-NV2CWBI2.cjs.map +1 -0
  22. package/dist/{chunk-FQBTGS3E.cjs → chunk-OFUKTVBN.cjs} +363 -285
  23. package/dist/chunk-OFUKTVBN.cjs.map +1 -0
  24. package/dist/{chunk-7KN6J7XV.cjs → chunk-OMAACCFW.cjs} +7 -7
  25. package/dist/{chunk-7KN6J7XV.cjs.map → chunk-OMAACCFW.cjs.map} +1 -1
  26. package/dist/chunk-OYQ7GYAA.cjs +1921 -0
  27. package/dist/chunk-OYQ7GYAA.cjs.map +1 -0
  28. package/dist/{chunk-YJP6DUFO.cjs → chunk-PKD3JLS2.cjs} +6 -6
  29. package/dist/{chunk-YJP6DUFO.cjs.map → chunk-PKD3JLS2.cjs.map} +1 -1
  30. package/dist/{chunk-CXDMZT45.cjs → chunk-PY7XAG4D.cjs} +27 -4
  31. package/dist/chunk-PY7XAG4D.cjs.map +1 -0
  32. package/dist/{chunk-5H7SAEQO.js → chunk-QKFJDQEK.js} +3 -3
  33. package/dist/{chunk-5H7SAEQO.js.map → chunk-QKFJDQEK.js.map} +1 -1
  34. package/dist/{chunk-XJTFZLWH.cjs → chunk-QO6PRHDX.cjs} +2 -2
  35. package/dist/{chunk-XJTFZLWH.cjs.map → chunk-QO6PRHDX.cjs.map} +1 -1
  36. package/dist/{chunk-OHDIJOGG.js → chunk-RD3JDFYJ.js} +3 -3
  37. package/dist/{chunk-OHDIJOGG.js.map → chunk-RD3JDFYJ.js.map} +1 -1
  38. package/dist/{chunk-4SM3I7WE.cjs → chunk-RXPEZXAB.cjs} +67 -38
  39. package/dist/chunk-RXPEZXAB.cjs.map +1 -0
  40. package/dist/{chunk-VTR2KGLY.cjs → chunk-S3BCHPXT.cjs} +9 -9
  41. package/dist/{chunk-VTR2KGLY.cjs.map → chunk-S3BCHPXT.cjs.map} +1 -1
  42. package/dist/{chunk-KU3XRHWA.js → chunk-TZX76ZNZ.js} +67 -38
  43. package/dist/chunk-TZX76ZNZ.js.map +1 -0
  44. package/dist/{chunk-MXQ7J4BB.js → chunk-VSVGMMNO.js} +361 -284
  45. package/dist/chunk-VSVGMMNO.js.map +1 -0
  46. package/dist/{chunk-Q7G56ZIO.js → chunk-WUBMDOTG.js} +3 -3
  47. package/dist/{chunk-Q7G56ZIO.js.map → chunk-WUBMDOTG.js.map} +1 -1
  48. package/dist/{chunk-DGRXAIWK.js → chunk-X5YM3KXY.js} +27 -4
  49. package/dist/chunk-X5YM3KXY.js.map +1 -0
  50. package/dist/chunk-XCP454Q6.js +263 -0
  51. package/dist/chunk-XCP454Q6.js.map +1 -0
  52. package/dist/{chunk-I3DQXUSC.js → chunk-Y6DFMDMH.js} +3 -3
  53. package/dist/{chunk-I3DQXUSC.js.map → chunk-Y6DFMDMH.js.map} +1 -1
  54. package/dist/{chunk-ODYQYLO2.js → chunk-YSEMAI4I.js} +8 -4
  55. package/dist/chunk-YSEMAI4I.js.map +1 -0
  56. package/dist/components/AlertDialog/index.cjs +4 -4
  57. package/dist/components/AlertDialog/index.js +3 -3
  58. package/dist/components/Collapsible/index.cjs +6 -4
  59. package/dist/components/Collapsible/index.js +3 -1
  60. package/dist/components/Dropdown/index.cjs +9 -8
  61. package/dist/components/Dropdown/index.js +2 -1
  62. package/dist/components/KeyboardShortcutsOverlay/index.cjs +5 -5
  63. package/dist/components/KeyboardShortcutsOverlay/index.js +3 -3
  64. package/dist/components/MediaEditor/index.cjs +8 -8
  65. package/dist/components/MediaEditor/index.js +3 -3
  66. package/dist/components/Modal/index.cjs +10 -10
  67. package/dist/components/Modal/index.js +2 -2
  68. package/dist/components/RichTextEditor/index.cjs +6 -5
  69. package/dist/components/RichTextEditor/index.js +3 -2
  70. package/dist/components/SuperChat/index.cjs +40 -17
  71. package/dist/components/SuperChat/index.cjs.map +1 -1
  72. package/dist/components/SuperChat/index.d.cts +20 -7
  73. package/dist/components/SuperChat/index.d.ts +20 -7
  74. package/dist/components/SuperChat/index.js +35 -12
  75. package/dist/components/SuperChat/index.js.map +1 -1
  76. package/dist/components/SuperChat/plugins/index.cjs +10 -3
  77. package/dist/components/SuperChat/plugins/index.cjs.map +1 -1
  78. package/dist/components/SuperChat/plugins/index.d.cts +3 -3
  79. package/dist/components/SuperChat/plugins/index.d.ts +3 -3
  80. package/dist/components/SuperChat/plugins/index.js +9 -2
  81. package/dist/components/SuperChat/plugins/index.js.map +1 -1
  82. package/dist/esheet.cjs +6 -6
  83. package/dist/esheet.js +3 -3
  84. package/dist/hooks/index.cjs +13 -13
  85. package/dist/hooks/index.js +1 -1
  86. package/dist/index.cjs +720 -1671
  87. package/dist/index.cjs.map +1 -1
  88. package/dist/index.d.cts +347 -347
  89. package/dist/index.d.ts +347 -347
  90. package/dist/index.js +459 -1405
  91. package/dist/index.js.map +1 -1
  92. package/dist/motion.cjs +7 -7
  93. package/dist/motion.d.cts +1 -1
  94. package/dist/motion.d.ts +1 -1
  95. package/dist/motion.js +2 -2
  96. package/dist/styles.css +1 -1
  97. package/dist/tailwind-preset.cjs +4 -4
  98. package/dist/tailwind-preset.js +1 -1
  99. package/dist/{types-DZDroUW8.d.cts → types-B97JNRNQ.d.cts} +1 -1
  100. package/dist/{types-B2RLmdVd.d.ts → types-CnPEwzlp.d.cts} +6 -2
  101. package/dist/{types-B2RLmdVd.d.cts → types-CnPEwzlp.d.ts} +6 -2
  102. package/dist/{types-9vK_YdEb.d.ts → types-gZXrfLj6.d.ts} +1 -1
  103. package/package.json +2 -1
  104. package/dist/chunk-4SM3I7WE.cjs.map +0 -1
  105. package/dist/chunk-5BVFVXHN.cjs +0 -1244
  106. package/dist/chunk-5BVFVXHN.cjs.map +0 -1
  107. package/dist/chunk-6XDPJWSC.cjs.map +0 -1
  108. package/dist/chunk-BJKAVWED.js.map +0 -1
  109. package/dist/chunk-BN75TLUN.cjs +0 -163
  110. package/dist/chunk-BN75TLUN.cjs.map +0 -1
  111. package/dist/chunk-CXDMZT45.cjs.map +0 -1
  112. package/dist/chunk-DGRXAIWK.js.map +0 -1
  113. package/dist/chunk-FQBTGS3E.cjs.map +0 -1
  114. package/dist/chunk-IUDY6S7I.cjs.map +0 -1
  115. package/dist/chunk-KU3XRHWA.js.map +0 -1
  116. package/dist/chunk-MXQ7J4BB.js.map +0 -1
  117. package/dist/chunk-O6GJ4IYS.js +0 -1210
  118. package/dist/chunk-O6GJ4IYS.js.map +0 -1
  119. package/dist/chunk-ODYQYLO2.js.map +0 -1
  120. package/dist/chunk-WYMO3IIK.js +0 -136
  121. package/dist/chunk-WYMO3IIK.js.map +0 -1
@@ -1,1210 +0,0 @@
1
- import { cn } from './chunk-TQONQSJO.js';
2
- import { useAnchoredPosition } from './chunk-WSNMQQ4P.js';
3
- import * as React3 from 'react';
4
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
- import { cva } from 'class-variance-authority';
6
- import { createPortal } from 'react-dom';
7
-
8
- function getFileType(mimeType) {
9
- if (mimeType.startsWith("image/")) return "image";
10
- if (mimeType.startsWith("video/")) return "video";
11
- if (mimeType.startsWith("audio/")) return "audio";
12
- if (mimeType.includes("pdf") || mimeType.includes("document") || mimeType.includes("text")) {
13
- return "document";
14
- }
15
- return "file";
16
- }
17
- function formatFileSize(bytes) {
18
- if (bytes < 1024) return `${bytes} B`;
19
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
20
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
21
- }
22
- function validateFile(file, acceptedTypes, maxSize) {
23
- if (acceptedTypes && acceptedTypes.length > 0) {
24
- const isAccepted = acceptedTypes.some((type) => {
25
- if (type.startsWith(".")) {
26
- return file.name.toLowerCase().endsWith(type.toLowerCase());
27
- }
28
- if (type.endsWith("/*")) {
29
- return file.type.startsWith(type.replace("/*", "/"));
30
- }
31
- return file.type === type;
32
- });
33
- if (!isAccepted) {
34
- return { valid: false, error: "File type not supported" };
35
- }
36
- }
37
- if (maxSize && file.size > maxSize) {
38
- return {
39
- valid: false,
40
- error: `File too large (max ${formatFileSize(maxSize)})`
41
- };
42
- }
43
- return { valid: true };
44
- }
45
- function generateAttachmentId() {
46
- return `attachment-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
47
- }
48
- function AttachmentPreviewItem({
49
- attachment,
50
- onRemove,
51
- onRetry,
52
- disabled = false,
53
- className
54
- }) {
55
- const { file, previewUrl, type, state, progress } = attachment;
56
- const isImage = type === "image";
57
- const isVideo = type === "video";
58
- const isUploading = state === "uploading";
59
- const isFailed = state === "failed";
60
- return /* @__PURE__ */ jsxs(
61
- "div",
62
- {
63
- className: cn(
64
- "group relative overflow-hidden rounded-lg",
65
- "bg-neutral-100 dark:bg-neutral-800",
66
- "border border-neutral-200 dark:border-neutral-700",
67
- isFailed && "border-red-500",
68
- className
69
- ),
70
- children: [
71
- (isImage || isVideo) && previewUrl ? /* @__PURE__ */ jsxs("div", { className: "relative h-20 w-20", children: [
72
- isVideo ? /* @__PURE__ */ jsx(
73
- "video",
74
- {
75
- src: previewUrl,
76
- "aria-label": file.name,
77
- muted: true,
78
- playsInline: true,
79
- preload: "metadata",
80
- className: cn(
81
- "h-full w-full object-cover",
82
- (isUploading || isFailed) && "opacity-50"
83
- )
84
- }
85
- ) : /* @__PURE__ */ jsx(
86
- "img",
87
- {
88
- src: previewUrl,
89
- alt: file.name,
90
- className: cn(
91
- "h-full w-full object-cover",
92
- (isUploading || isFailed) && "opacity-50"
93
- )
94
- }
95
- ),
96
- isVideo && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(
97
- "svg",
98
- {
99
- "aria-hidden": "true",
100
- className: "h-6 w-6 text-white drop-shadow",
101
- fill: "currentColor",
102
- viewBox: "0 0 24 24",
103
- children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" })
104
- }
105
- ) })
106
- ] }) : (
107
- /* File preview */
108
- /* @__PURE__ */ jsxs("div", { className: "flex h-20 w-20 flex-col items-center justify-center p-2", children: [
109
- /* @__PURE__ */ jsx(
110
- "svg",
111
- {
112
- "aria-hidden": "true",
113
- className: "h-8 w-8 text-neutral-500",
114
- fill: "none",
115
- viewBox: "0 0 24 24",
116
- stroke: "currentColor",
117
- children: /* @__PURE__ */ jsx(
118
- "path",
119
- {
120
- strokeLinecap: "round",
121
- strokeLinejoin: "round",
122
- strokeWidth: 2,
123
- d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
124
- }
125
- )
126
- }
127
- ),
128
- /* @__PURE__ */ jsx("span", { className: "mt-1 max-w-full truncate px-1 text-xs text-neutral-600 dark:text-neutral-400", children: file.name.split(".").pop()?.toUpperCase() })
129
- ] })
130
- ),
131
- isUploading && progress !== void 0 && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxs("div", { className: "text-center text-white", children: [
132
- /* @__PURE__ */ jsxs(
133
- "svg",
134
- {
135
- "aria-hidden": "true",
136
- className: "mx-auto h-6 w-6 animate-spin",
137
- fill: "none",
138
- viewBox: "0 0 24 24",
139
- children: [
140
- /* @__PURE__ */ jsx(
141
- "circle",
142
- {
143
- className: "opacity-25",
144
- cx: "12",
145
- cy: "12",
146
- r: "10",
147
- stroke: "currentColor",
148
- strokeWidth: "4"
149
- }
150
- ),
151
- /* @__PURE__ */ jsx(
152
- "path",
153
- {
154
- className: "opacity-75",
155
- fill: "currentColor",
156
- d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
157
- }
158
- )
159
- ]
160
- }
161
- ),
162
- /* @__PURE__ */ jsxs("span", { className: "mt-1 text-xs", children: [
163
- progress,
164
- "%"
165
- ] })
166
- ] }) }),
167
- isFailed && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
168
- /* @__PURE__ */ jsx(
169
- "svg",
170
- {
171
- "aria-hidden": "true",
172
- className: "mx-auto h-6 w-6 text-red-400",
173
- fill: "none",
174
- viewBox: "0 0 24 24",
175
- stroke: "currentColor",
176
- children: /* @__PURE__ */ jsx(
177
- "path",
178
- {
179
- strokeLinecap: "round",
180
- strokeLinejoin: "round",
181
- strokeWidth: 2,
182
- d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
183
- }
184
- )
185
- }
186
- ),
187
- onRetry && /* @__PURE__ */ jsx(
188
- "button",
189
- {
190
- type: "button",
191
- onClick: onRetry,
192
- disabled,
193
- className: "mt-1 text-xs text-white underline hover:no-underline disabled:no-underline disabled:opacity-50",
194
- children: "Retry"
195
- }
196
- )
197
- ] }) }),
198
- /* @__PURE__ */ jsx(
199
- "button",
200
- {
201
- type: "button",
202
- onClick: onRemove,
203
- disabled,
204
- className: cn(
205
- "absolute -end-1 -top-1 z-10",
206
- "rounded-full p-1",
207
- "bg-neutral-900 text-white",
208
- "opacity-0 group-hover:opacity-100",
209
- "focus:ring-primary-500 focus:opacity-100 focus:ring-2 focus:outline-none",
210
- "transition-opacity",
211
- "disabled:cursor-not-allowed disabled:group-hover:opacity-0"
212
- ),
213
- "aria-label": `Remove ${file.name}`,
214
- children: /* @__PURE__ */ jsx(
215
- "svg",
216
- {
217
- "aria-hidden": "true",
218
- className: "h-3 w-3",
219
- fill: "none",
220
- viewBox: "0 0 24 24",
221
- stroke: "currentColor",
222
- children: /* @__PURE__ */ jsx(
223
- "path",
224
- {
225
- strokeLinecap: "round",
226
- strokeLinejoin: "round",
227
- strokeWidth: 2,
228
- d: "M6 18L18 6M6 6l12 12"
229
- }
230
- )
231
- }
232
- )
233
- }
234
- ),
235
- /* @__PURE__ */ jsx(
236
- "div",
237
- {
238
- className: cn(
239
- "absolute start-0 end-0 bottom-0",
240
- "bg-black/70 px-1 py-0.5",
241
- "opacity-0 group-hover:opacity-100",
242
- "transition-opacity"
243
- ),
244
- children: /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-white", children: file.name })
245
- }
246
- )
247
- ]
248
- }
249
- );
250
- }
251
- AttachmentPreviewItem.displayName = "AttachmentPreviewItem";
252
- var AttachmentPicker = React3.forwardRef(
253
- ({
254
- onFilesSelected,
255
- acceptedTypes = ["image/*", "video/*", ".pdf", ".doc", ".docx"],
256
- maxFileSize = 25 * 1024 * 1024,
257
- // 25MB
258
- maxFiles = 10,
259
- multiple = true,
260
- disabled = false,
261
- onError,
262
- className,
263
- children
264
- }, ref) => {
265
- const inputRef = React3.useRef(null);
266
- React3.useImperativeHandle(ref, () => inputRef.current);
267
- const handleClick = () => {
268
- inputRef.current?.click();
269
- };
270
- const handleChange = (event) => {
271
- const files = Array.from(event.target.files || []);
272
- if (files.length === 0) return;
273
- const validFiles = [];
274
- for (const file of files.slice(0, maxFiles)) {
275
- const validation = validateFile(file, acceptedTypes, maxFileSize);
276
- if (validation.valid) {
277
- validFiles.push(file);
278
- } else if (onError) {
279
- onError(`${file.name}: ${validation.error}`);
280
- }
281
- }
282
- if (files.length > maxFiles && onError) {
283
- onError(`Maximum ${maxFiles} files allowed`);
284
- }
285
- if (validFiles.length > 0) {
286
- onFilesSelected(validFiles);
287
- }
288
- event.target.value = "";
289
- };
290
- return /* @__PURE__ */ jsxs(Fragment, { children: [
291
- /* @__PURE__ */ jsx(
292
- "input",
293
- {
294
- ref: inputRef,
295
- type: "file",
296
- accept: acceptedTypes.join(","),
297
- multiple,
298
- onChange: handleChange,
299
- disabled,
300
- className: "sr-only",
301
- "aria-label": "Select files to attach"
302
- }
303
- ),
304
- /* @__PURE__ */ jsx(
305
- "button",
306
- {
307
- type: "button",
308
- onClick: handleClick,
309
- disabled,
310
- "data-slot": "attachment-picker-button",
311
- className: cn(
312
- "inline-flex items-center justify-center",
313
- "rounded-full p-2",
314
- "text-neutral-500 hover:text-neutral-700",
315
- "dark:text-neutral-400 dark:hover:text-neutral-200",
316
- "hover:bg-neutral-100 dark:hover:bg-neutral-800",
317
- "focus:ring-primary-500 focus:ring-2 focus:outline-none",
318
- "disabled:cursor-not-allowed disabled:opacity-50",
319
- "transition-colors",
320
- className
321
- ),
322
- "aria-label": "Attach files",
323
- children: children || /* @__PURE__ */ jsx(
324
- "svg",
325
- {
326
- "aria-hidden": "true",
327
- className: "h-5 w-5",
328
- fill: "none",
329
- viewBox: "0 0 24 24",
330
- stroke: "currentColor",
331
- children: /* @__PURE__ */ jsx(
332
- "path",
333
- {
334
- strokeLinecap: "round",
335
- strokeLinejoin: "round",
336
- strokeWidth: 2,
337
- d: "M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"
338
- }
339
- )
340
- }
341
- )
342
- }
343
- )
344
- ] });
345
- }
346
- );
347
- AttachmentPicker.displayName = "AttachmentPicker";
348
- function DragDropZone({
349
- onFilesDropped,
350
- acceptedTypes,
351
- maxFileSize,
352
- maxFiles = 10,
353
- disabled = false,
354
- onError,
355
- overlayLabel = "Drop files here",
356
- children,
357
- className
358
- }) {
359
- const [isDragging, setIsDragging] = React3.useState(false);
360
- const dragCounterRef = React3.useRef(0);
361
- const handleDragEnter = (event) => {
362
- event.preventDefault();
363
- event.stopPropagation();
364
- if (disabled) return;
365
- dragCounterRef.current++;
366
- if (event.dataTransfer.items && event.dataTransfer.items.length > 0) {
367
- setIsDragging(true);
368
- }
369
- };
370
- const handleDragLeave = (event) => {
371
- event.preventDefault();
372
- event.stopPropagation();
373
- if (disabled) return;
374
- dragCounterRef.current--;
375
- if (dragCounterRef.current === 0) {
376
- setIsDragging(false);
377
- }
378
- };
379
- const handleDragOver = (event) => {
380
- event.preventDefault();
381
- event.stopPropagation();
382
- };
383
- const handleDrop = (event) => {
384
- event.preventDefault();
385
- event.stopPropagation();
386
- if (disabled) return;
387
- setIsDragging(false);
388
- dragCounterRef.current = 0;
389
- const files = Array.from(event.dataTransfer.files);
390
- if (files.length === 0) return;
391
- const validFiles = [];
392
- for (const file of files.slice(0, maxFiles)) {
393
- const validation = validateFile(file, acceptedTypes, maxFileSize);
394
- if (validation.valid) {
395
- validFiles.push(file);
396
- } else if (onError) {
397
- onError(`${file.name}: ${validation.error}`);
398
- }
399
- }
400
- if (files.length > maxFiles && onError) {
401
- onError(`Maximum ${maxFiles} files allowed`);
402
- }
403
- if (validFiles.length > 0) {
404
- onFilesDropped(validFiles);
405
- }
406
- };
407
- return /* @__PURE__ */ jsxs(
408
- "div",
409
- {
410
- onDragEnter: handleDragEnter,
411
- onDragLeave: handleDragLeave,
412
- onDragOver: handleDragOver,
413
- onDrop: handleDrop,
414
- className: cn("relative", className),
415
- children: [
416
- children,
417
- isDragging && /* @__PURE__ */ jsx(
418
- "div",
419
- {
420
- className: cn(
421
- "absolute inset-0 z-50",
422
- "flex items-center justify-center",
423
- "bg-primary-50/90 dark:bg-primary-900/90",
424
- "border-primary-500 border-2 border-dashed",
425
- "rounded-lg"
426
- ),
427
- children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
428
- /* @__PURE__ */ jsx(
429
- "svg",
430
- {
431
- "aria-hidden": "true",
432
- className: "text-primary-800 mx-auto h-12 w-12",
433
- fill: "none",
434
- viewBox: "0 0 24 24",
435
- stroke: "currentColor",
436
- children: /* @__PURE__ */ jsx(
437
- "path",
438
- {
439
- strokeLinecap: "round",
440
- strokeLinejoin: "round",
441
- strokeWidth: 2,
442
- d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
443
- }
444
- )
445
- }
446
- ),
447
- /* @__PURE__ */ jsx("p", { className: "text-primary-700 dark:text-primary-300 mt-2 text-sm font-medium", children: overlayLabel })
448
- ] })
449
- }
450
- )
451
- ]
452
- }
453
- );
454
- }
455
- DragDropZone.displayName = "DragDropZone";
456
- function CameraButton({
457
- onCapture,
458
- useFrontCamera = false,
459
- disabled = false,
460
- className
461
- }) {
462
- const inputRef = React3.useRef(null);
463
- const handleClick = () => {
464
- inputRef.current?.click();
465
- };
466
- const handleChange = (event) => {
467
- const file = event.target.files?.[0];
468
- if (file) {
469
- onCapture(file);
470
- }
471
- event.target.value = "";
472
- };
473
- return /* @__PURE__ */ jsxs(Fragment, { children: [
474
- /* @__PURE__ */ jsx(
475
- "input",
476
- {
477
- ref: inputRef,
478
- type: "file",
479
- accept: "image/*",
480
- capture: useFrontCamera ? "user" : "environment",
481
- onChange: handleChange,
482
- disabled,
483
- className: "sr-only",
484
- "aria-label": "Take a photo"
485
- }
486
- ),
487
- /* @__PURE__ */ jsx(
488
- "button",
489
- {
490
- type: "button",
491
- onClick: handleClick,
492
- disabled,
493
- className: cn(
494
- "inline-flex items-center justify-center",
495
- "rounded-full p-2",
496
- "text-neutral-500 hover:text-neutral-700",
497
- "dark:text-neutral-400 dark:hover:text-neutral-200",
498
- "hover:bg-neutral-100 dark:hover:bg-neutral-800",
499
- "focus:ring-primary-500 focus:ring-2 focus:outline-none",
500
- "disabled:cursor-not-allowed disabled:opacity-50",
501
- "transition-colors",
502
- className
503
- ),
504
- "aria-label": "Take a photo",
505
- children: /* @__PURE__ */ jsxs(
506
- "svg",
507
- {
508
- "aria-hidden": "true",
509
- className: "h-5 w-5",
510
- fill: "none",
511
- viewBox: "0 0 24 24",
512
- stroke: "currentColor",
513
- children: [
514
- /* @__PURE__ */ jsx(
515
- "path",
516
- {
517
- strokeLinecap: "round",
518
- strokeLinejoin: "round",
519
- strokeWidth: 2,
520
- d: "M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"
521
- }
522
- ),
523
- /* @__PURE__ */ jsx(
524
- "path",
525
- {
526
- strokeLinecap: "round",
527
- strokeLinejoin: "round",
528
- strokeWidth: 2,
529
- d: "M15 13a3 3 0 11-6 0 3 3 0 016 0z"
530
- }
531
- )
532
- ]
533
- }
534
- )
535
- }
536
- )
537
- ] });
538
- }
539
- CameraButton.displayName = "CameraButton";
540
- function activeMentionQuery(value, caret) {
541
- const upToCaret = value.slice(0, caret);
542
- const match = /(^|\s)@([^\s@]*)$/.exec(upToCaret);
543
- if (!match) return null;
544
- const query = match[2];
545
- return { query, start: caret - query.length - 1 };
546
- }
547
- function useMentionAutocomplete({
548
- options,
549
- value,
550
- setValue,
551
- textareaRef
552
- }) {
553
- const enabled = !!options && options.length > 0;
554
- const [mention, setMention] = React3.useState(null);
555
- const [highlight, setHighlight] = React3.useState(0);
556
- const listId = React3.useId();
557
- const optionId = React3.useCallback(
558
- (index) => `${listId}-option-${index}`,
559
- [listId]
560
- );
561
- const suggestions = React3.useMemo(() => {
562
- if (!mention || !options) return [];
563
- const q = mention.query.toLowerCase();
564
- return options.filter((o) => o.label.toLowerCase().includes(q));
565
- }, [mention, options]);
566
- const menuOpen = enabled && mention !== null && suggestions.length > 0;
567
- const {
568
- anchorRef,
569
- floatingRef,
570
- style: menuStyle
571
- } = useAnchoredPosition({
572
- open: menuOpen,
573
- placement: "top-start",
574
- maxHeight: 224
575
- });
576
- const clampedHighlight = menuOpen ? Math.min(highlight, suggestions.length - 1) : -1;
577
- const activeOptionId = menuOpen ? optionId(clampedHighlight) : void 0;
578
- const sync = React3.useCallback(
579
- (nextValue, caret) => {
580
- if (!enabled) return;
581
- setMention(activeMentionQuery(nextValue, caret));
582
- setHighlight(0);
583
- },
584
- [enabled]
585
- );
586
- const insert = (option) => {
587
- if (!mention) return;
588
- const insertValue = option.value ?? option.label.split(" ")[0];
589
- const before = value.slice(0, mention.start);
590
- const after = value.slice(mention.start + 1 + mention.query.length);
591
- const insertText = `@${insertValue} `;
592
- setValue(before + insertText + after);
593
- setMention(null);
594
- const caret = before.length + insertText.length;
595
- requestAnimationFrame(() => {
596
- const el = textareaRef.current;
597
- if (el) {
598
- el.focus();
599
- el.setSelectionRange(caret, caret);
600
- }
601
- });
602
- };
603
- const handleKeyDown = (event) => {
604
- if (!menuOpen) return false;
605
- if (event.key === "ArrowDown") {
606
- event.preventDefault();
607
- setHighlight(
608
- (h) => (Math.min(h, suggestions.length - 1) + 1) % suggestions.length
609
- );
610
- return true;
611
- }
612
- if (event.key === "ArrowUp") {
613
- event.preventDefault();
614
- setHighlight(
615
- (h) => (Math.min(h, suggestions.length - 1) - 1 + suggestions.length) % suggestions.length
616
- );
617
- return true;
618
- }
619
- if (event.key === "Enter" || event.key === "Tab") {
620
- event.preventDefault();
621
- const chosen = suggestions[clampedHighlight];
622
- if (chosen) insert(chosen);
623
- return true;
624
- }
625
- if (event.key === "Escape") {
626
- event.preventDefault();
627
- setMention(null);
628
- return true;
629
- }
630
- return false;
631
- };
632
- const inputProps = enabled ? {
633
- "aria-controls": menuOpen ? listId : void 0,
634
- "aria-activedescendant": activeOptionId,
635
- "aria-autocomplete": "list"
636
- } : {};
637
- return {
638
- enabled,
639
- menuOpen,
640
- suggestions,
641
- highlight: clampedHighlight,
642
- listId,
643
- optionId,
644
- anchorRef,
645
- floatingRef,
646
- menuStyle,
647
- sync,
648
- insert,
649
- setHighlight,
650
- handleKeyDown,
651
- inputProps
652
- };
653
- }
654
- function MentionMenu({
655
- mention,
656
- label = "Mention",
657
- dataSlot = "composer-mention-list"
658
- }) {
659
- if (!mention.menuOpen) return null;
660
- return createPortal(
661
- /* @__PURE__ */ jsx(
662
- "ul",
663
- {
664
- ref: mention.floatingRef,
665
- style: mention.menuStyle,
666
- id: mention.listId,
667
- role: "listbox",
668
- "aria-label": label,
669
- "data-slot": dataSlot,
670
- className: "w-64 overflow-y-auto rounded-lg border border-neutral-200 bg-white py-1 shadow-lg dark:border-neutral-700 dark:bg-neutral-800",
671
- children: mention.suggestions.map((option, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
672
- "button",
673
- {
674
- type: "button",
675
- id: mention.optionId(i),
676
- role: "option",
677
- "aria-selected": i === mention.highlight,
678
- onMouseDown: (e) => {
679
- e.preventDefault();
680
- mention.insert(option);
681
- },
682
- onMouseEnter: () => mention.setHighlight(i),
683
- className: cn(
684
- "flex w-full items-center gap-2 px-3 py-1.5 text-start text-sm",
685
- i === mention.highlight ? "bg-primary-100 text-primary-900 dark:bg-primary-900/40 dark:text-primary-100" : "text-neutral-700 dark:text-neutral-200"
686
- ),
687
- children: [
688
- option.icon,
689
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 truncate", children: [
690
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label }),
691
- option.description && /* @__PURE__ */ jsx("span", { className: "ms-1 text-xs text-neutral-400", children: option.description })
692
- ] }),
693
- option.meta && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-400", children: option.meta })
694
- ]
695
- }
696
- ) }, option.id))
697
- }
698
- ),
699
- document.body
700
- );
701
- }
702
- MentionMenu.displayName = "MentionMenu";
703
- function isFileAccepted(file, accepted) {
704
- if (!accepted || accepted.length === 0) return true;
705
- const mime = file.type;
706
- const name = file.name.toLowerCase();
707
- return accepted.some((token) => {
708
- if (token.startsWith(".")) return name.endsWith(token.toLowerCase());
709
- if (token.endsWith("/*")) return mime.startsWith(token.slice(0, -1));
710
- if (token.includes("/")) return mime === token;
711
- return false;
712
- });
713
- }
714
- function CharacterCounter({
715
- current,
716
- max,
717
- showWarningAt = 0.9,
718
- className
719
- }) {
720
- const percentage = current / max;
721
- const isWarning = percentage >= showWarningAt && percentage < 1;
722
- const isOver = current > max;
723
- return /* @__PURE__ */ jsxs(
724
- "span",
725
- {
726
- className: cn(
727
- "text-xs tabular-nums",
728
- isOver ? "font-medium text-red-700 dark:text-red-400" : isWarning ? "text-amber-700 dark:text-amber-400" : "text-neutral-600 dark:text-neutral-400",
729
- className
730
- ),
731
- "aria-live": "polite",
732
- "aria-label": `${current} of ${max} characters`,
733
- children: [
734
- current,
735
- "/",
736
- max
737
- ]
738
- }
739
- );
740
- }
741
- CharacterCounter.displayName = "CharacterCounter";
742
- var sendButtonVariants = cva(
743
- [
744
- "inline-flex items-center justify-center",
745
- "rounded-full p-3 self-start",
746
- "transition-all duration-200",
747
- "focus:outline-none focus:ring-2 focus:ring-primary-500",
748
- "disabled:opacity-50 disabled:cursor-not-allowed"
749
- ],
750
- {
751
- variants: {
752
- variant: {
753
- primary: [
754
- "bg-primary-800 text-white",
755
- "hover:bg-primary-900",
756
- "active:scale-95"
757
- ],
758
- subtle: [
759
- "bg-transparent text-primary-800",
760
- "hover:bg-primary-50 dark:hover:bg-primary-900/20"
761
- ]
762
- },
763
- canSend: {
764
- true: "",
765
- false: "opacity-50 cursor-not-allowed"
766
- }
767
- },
768
- defaultVariants: {
769
- variant: "primary",
770
- canSend: false
771
- }
772
- }
773
- );
774
- var SendButton = React3.forwardRef(
775
- ({ className, variant, canSend, isLoading, disabled, ...props }, ref) => {
776
- return /* @__PURE__ */ jsx(
777
- "button",
778
- {
779
- ref,
780
- type: "submit",
781
- disabled: disabled || !canSend || isLoading,
782
- "data-slot": "composer-send-button",
783
- className: cn(sendButtonVariants({ variant, canSend }), className),
784
- "aria-label": isLoading ? "Sending message" : "Send message",
785
- ...props,
786
- children: isLoading ? /* @__PURE__ */ jsxs(
787
- "svg",
788
- {
789
- "aria-hidden": "true",
790
- className: "h-5 w-5 animate-spin",
791
- fill: "none",
792
- viewBox: "0 0 24 24",
793
- children: [
794
- /* @__PURE__ */ jsx(
795
- "circle",
796
- {
797
- className: "opacity-25",
798
- cx: "12",
799
- cy: "12",
800
- r: "10",
801
- stroke: "currentColor",
802
- strokeWidth: "4"
803
- }
804
- ),
805
- /* @__PURE__ */ jsx(
806
- "path",
807
- {
808
- className: "opacity-75",
809
- fill: "currentColor",
810
- d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
811
- }
812
- )
813
- ]
814
- }
815
- ) : /* @__PURE__ */ jsx(
816
- "svg",
817
- {
818
- "aria-hidden": "true",
819
- className: "h-5 w-5",
820
- fill: "none",
821
- viewBox: "0 0 24 24",
822
- stroke: "currentColor",
823
- children: /* @__PURE__ */ jsx(
824
- "path",
825
- {
826
- strokeLinecap: "round",
827
- strokeLinejoin: "round",
828
- strokeWidth: 2,
829
- d: "M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
830
- }
831
- )
832
- }
833
- )
834
- }
835
- );
836
- }
837
- );
838
- SendButton.displayName = "SendButton";
839
- var MessageComposer = React3.forwardRef(
840
- ({
841
- onSend,
842
- onTypingStart,
843
- onTypingStop,
844
- value: controlledValue,
845
- onValueChange,
846
- placeholder = "Type a message...",
847
- maxLength = 1600,
848
- showCharacterCount = false,
849
- disabled = false,
850
- isSending = false,
851
- showAttachmentPicker = true,
852
- showCameraButton = false,
853
- acceptedFileTypes = ["image/*", "video/*", ".pdf", ".doc", ".docx"],
854
- maxFileSize = 25 * 1024 * 1024,
855
- maxAttachments = 10,
856
- onError,
857
- autoFocus = false,
858
- replyTo = null,
859
- onCancelReply,
860
- variant = "default",
861
- inputTrailing,
862
- mentionOptions,
863
- className
864
- }, ref) => {
865
- const textareaRef = React3.useRef(null);
866
- const [internalContent, setInternalContent] = React3.useState("");
867
- const isControlled = controlledValue !== void 0;
868
- const content = isControlled ? controlledValue : internalContent;
869
- const setContent = React3.useCallback(
870
- (val) => {
871
- if (isControlled) {
872
- const newVal = typeof val === "function" ? val(controlledValue) : val;
873
- onValueChange?.(newVal);
874
- } else {
875
- setInternalContent(val);
876
- }
877
- },
878
- [isControlled, controlledValue, onValueChange]
879
- );
880
- const [attachments, setAttachments] = React3.useState(
881
- []
882
- );
883
- const [isTyping, setIsTyping] = React3.useState(false);
884
- const typingTimeoutRef = React3.useRef(null);
885
- React3.useImperativeHandle(ref, () => textareaRef.current);
886
- React3.useEffect(() => {
887
- const textarea = textareaRef.current;
888
- if (textarea) {
889
- textarea.style.height = "auto";
890
- textarea.style.height = `${Math.min(textarea.scrollHeight, 150)}px`;
891
- }
892
- }, [content]);
893
- React3.useEffect(() => {
894
- if (content.length > 0 && !isTyping) {
895
- setIsTyping(true);
896
- onTypingStart?.();
897
- }
898
- if (typingTimeoutRef.current) {
899
- clearTimeout(typingTimeoutRef.current);
900
- }
901
- typingTimeoutRef.current = setTimeout(() => {
902
- if (isTyping) {
903
- setIsTyping(false);
904
- onTypingStop?.();
905
- }
906
- }, 2e3);
907
- return () => {
908
- if (typingTimeoutRef.current) {
909
- clearTimeout(typingTimeoutRef.current);
910
- }
911
- };
912
- }, [content, isTyping, onTypingStart, onTypingStop]);
913
- React3.useEffect(() => {
914
- if (autoFocus) {
915
- textareaRef.current?.focus();
916
- }
917
- }, [autoFocus]);
918
- React3.useEffect(() => {
919
- if (replyTo) {
920
- textareaRef.current?.focus();
921
- }
922
- }, [replyTo]);
923
- const mention = useMentionAutocomplete({
924
- options: mentionOptions,
925
- value: content,
926
- setValue: setContent,
927
- textareaRef
928
- });
929
- const canSend = (content.trim().length > 0 || attachments.length > 0) && content.length <= maxLength && !disabled && !isSending;
930
- const handleSubmit = async (event) => {
931
- event.preventDefault();
932
- if (!canSend) return;
933
- const message = {
934
- content: content.trim(),
935
- attachments: attachments.map((a) => a.file),
936
- replyToId: replyTo?.id
937
- };
938
- setContent("");
939
- setAttachments([]);
940
- setIsTyping(false);
941
- onTypingStop?.();
942
- try {
943
- await onSend(message);
944
- } catch {
945
- setContent(message.content);
946
- onError?.("Failed to send message");
947
- }
948
- };
949
- const handleKeyDown = (event) => {
950
- if (mention.handleKeyDown(event)) return;
951
- if (event.key === "Enter" && !event.shiftKey) {
952
- event.preventDefault();
953
- if (canSend) {
954
- handleSubmit(event);
955
- }
956
- }
957
- };
958
- const handleFilesSelected = (files) => {
959
- const remainingSlots = maxAttachments - attachments.length;
960
- const filesToAdd = files.slice(0, remainingSlots);
961
- if (files.length > remainingSlots) {
962
- onError?.(`Maximum ${maxAttachments} attachments allowed`);
963
- }
964
- const newAttachments = filesToAdd.map((file) => {
965
- const type = getFileType(file.type);
966
- let previewUrl;
967
- if (type === "image" || type === "video") {
968
- previewUrl = URL.createObjectURL(file);
969
- }
970
- return {
971
- id: generateAttachmentId(),
972
- file,
973
- previewUrl,
974
- type,
975
- state: "pending"
976
- };
977
- });
978
- setAttachments((prev) => [...prev, ...newAttachments]);
979
- };
980
- const handlePaste = (event) => {
981
- if (!showAttachmentPicker || disabled) return;
982
- const pasted = Array.from(event.clipboardData.items).filter((item) => item.kind === "file").map((item) => item.getAsFile()).filter((f) => f !== null).filter((f) => isFileAccepted(f, acceptedFileTypes));
983
- if (pasted.length === 0) return;
984
- event.preventDefault();
985
- handleFilesSelected(pasted);
986
- };
987
- const handleRemoveAttachment = (attachmentId) => {
988
- setAttachments((prev) => {
989
- const attachment = prev.find((a) => a.id === attachmentId);
990
- if (attachment?.previewUrl) {
991
- URL.revokeObjectURL(attachment.previewUrl);
992
- }
993
- return prev.filter((a) => a.id !== attachmentId);
994
- });
995
- };
996
- React3.useEffect(() => {
997
- const currentAttachments = attachments;
998
- return () => {
999
- currentAttachments.forEach((a) => {
1000
- if (a.previewUrl) {
1001
- URL.revokeObjectURL(a.previewUrl);
1002
- }
1003
- });
1004
- };
1005
- }, [attachments]);
1006
- return /* @__PURE__ */ jsx(
1007
- DragDropZone,
1008
- {
1009
- onFilesDropped: handleFilesSelected,
1010
- acceptedTypes: acceptedFileTypes,
1011
- maxFileSize,
1012
- maxFiles: maxAttachments - attachments.length,
1013
- disabled: disabled || attachments.length >= maxAttachments,
1014
- onError,
1015
- className: cn("w-full", className),
1016
- children: /* @__PURE__ */ jsxs(
1017
- "form",
1018
- {
1019
- onSubmit: handleSubmit,
1020
- "data-slot": "message-composer",
1021
- className: "w-full",
1022
- children: [
1023
- replyTo && /* @__PURE__ */ jsxs(
1024
- "div",
1025
- {
1026
- "data-slot": "composer-reply-preview",
1027
- className: cn(
1028
- "flex items-center gap-2 px-4 py-2",
1029
- "bg-neutral-50 dark:bg-neutral-800/50",
1030
- "border-primary-500 border-s-4"
1031
- ),
1032
- children: [
1033
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1034
- /* @__PURE__ */ jsxs("span", { className: "text-primary-800 dark:text-primary-400 text-xs font-medium", children: [
1035
- "Replying to ",
1036
- replyTo.senderName
1037
- ] }),
1038
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm text-neutral-600 dark:text-neutral-300", children: replyTo.content })
1039
- ] }),
1040
- /* @__PURE__ */ jsx(
1041
- "button",
1042
- {
1043
- type: "button",
1044
- onClick: onCancelReply,
1045
- className: cn(
1046
- "shrink-0 rounded p-1",
1047
- "text-neutral-500 hover:text-neutral-700",
1048
- "dark:text-neutral-400 dark:hover:text-neutral-200",
1049
- "focus:ring-primary-500 focus:ring-2 focus:outline-none"
1050
- ),
1051
- "aria-label": "Cancel reply",
1052
- children: /* @__PURE__ */ jsx(
1053
- "svg",
1054
- {
1055
- "aria-hidden": "true",
1056
- className: "h-4 w-4",
1057
- fill: "none",
1058
- viewBox: "0 0 24 24",
1059
- stroke: "currentColor",
1060
- children: /* @__PURE__ */ jsx(
1061
- "path",
1062
- {
1063
- strokeLinecap: "round",
1064
- strokeLinejoin: "round",
1065
- strokeWidth: 2,
1066
- d: "M6 18L18 6M6 6l12 12"
1067
- }
1068
- )
1069
- }
1070
- )
1071
- }
1072
- )
1073
- ]
1074
- }
1075
- ),
1076
- attachments.length > 0 && /* @__PURE__ */ jsx(
1077
- "div",
1078
- {
1079
- "data-slot": "composer-attachments",
1080
- className: cn(
1081
- "flex flex-wrap gap-2 p-3",
1082
- "border-t border-neutral-200 dark:border-neutral-700"
1083
- ),
1084
- children: attachments.map((attachment) => /* @__PURE__ */ jsx(
1085
- AttachmentPreviewItem,
1086
- {
1087
- attachment,
1088
- onRemove: () => handleRemoveAttachment(attachment.id)
1089
- },
1090
- attachment.id
1091
- ))
1092
- }
1093
- ),
1094
- /* @__PURE__ */ jsxs(
1095
- "div",
1096
- {
1097
- "data-slot": "composer-input-area",
1098
- className: cn(
1099
- "flex items-center gap-2 p-3",
1100
- "bg-white dark:bg-neutral-900",
1101
- variant === "default" && "border-t border-neutral-200 dark:border-neutral-700"
1102
- ),
1103
- children: [
1104
- showAttachmentPicker && /* @__PURE__ */ jsx(
1105
- AttachmentPicker,
1106
- {
1107
- onFilesSelected: handleFilesSelected,
1108
- acceptedTypes: acceptedFileTypes,
1109
- maxFileSize,
1110
- maxFiles: maxAttachments - attachments.length,
1111
- disabled: disabled || attachments.length >= maxAttachments,
1112
- onError
1113
- }
1114
- ),
1115
- showCameraButton && /* @__PURE__ */ jsx(
1116
- CameraButton,
1117
- {
1118
- onCapture: (file) => handleFilesSelected([file]),
1119
- disabled: disabled || attachments.length >= maxAttachments
1120
- }
1121
- ),
1122
- /* @__PURE__ */ jsxs(
1123
- "div",
1124
- {
1125
- "data-slot": "composer-input-wrapper",
1126
- className: "relative flex-1",
1127
- ref: mention.anchorRef,
1128
- children: [
1129
- /* @__PURE__ */ jsx(MentionMenu, { mention }),
1130
- /* @__PURE__ */ jsx(
1131
- "textarea",
1132
- {
1133
- ref: textareaRef,
1134
- "data-slot": "composer-input",
1135
- value: content,
1136
- onChange: (e) => {
1137
- setContent(e.target.value);
1138
- mention.sync(
1139
- e.target.value,
1140
- e.target.selectionStart ?? e.target.value.length
1141
- );
1142
- },
1143
- onClick: (e) => {
1144
- const el = e.currentTarget;
1145
- mention.sync(el.value, el.selectionStart ?? el.value.length);
1146
- },
1147
- onKeyDown: handleKeyDown,
1148
- onPaste: handlePaste,
1149
- placeholder,
1150
- disabled: disabled || isSending,
1151
- rows: 1,
1152
- className: cn(
1153
- "w-full resize-none rounded-2xl py-2.5",
1154
- inputTrailing ? "ps-4 pe-10" : "px-4",
1155
- "bg-neutral-100 dark:bg-neutral-800",
1156
- "text-neutral-900 dark:text-neutral-100",
1157
- "placeholder:text-neutral-400 dark:placeholder:text-neutral-500",
1158
- "focus:ring-primary-500 focus:ring-2 focus:outline-none",
1159
- "disabled:cursor-not-allowed disabled:opacity-50",
1160
- "transition-colors",
1161
- "max-h-[150px]"
1162
- ),
1163
- "aria-label": "Message",
1164
- "aria-describedby": showCharacterCount ? "char-count" : void 0,
1165
- ...mention.inputProps
1166
- }
1167
- ),
1168
- inputTrailing && /* @__PURE__ */ jsx(
1169
- "div",
1170
- {
1171
- "data-slot": "composer-input-trailing",
1172
- className: "pointer-events-none absolute end-1 top-0 flex h-[44px] items-center [&>*]:pointer-events-auto",
1173
- children: inputTrailing
1174
- }
1175
- ),
1176
- showCharacterCount && /* @__PURE__ */ jsx(
1177
- "div",
1178
- {
1179
- "data-slot": "composer-char-count",
1180
- id: "char-count",
1181
- className: "absolute end-3 bottom-1.5",
1182
- children: /* @__PURE__ */ jsx(CharacterCounter, { current: content.length, max: maxLength })
1183
- }
1184
- )
1185
- ]
1186
- }
1187
- ),
1188
- /* @__PURE__ */ jsx(
1189
- SendButton,
1190
- {
1191
- canSend,
1192
- isLoading: isSending,
1193
- disabled
1194
- }
1195
- )
1196
- ]
1197
- }
1198
- )
1199
- ]
1200
- }
1201
- )
1202
- }
1203
- );
1204
- }
1205
- );
1206
- MessageComposer.displayName = "MessageComposer";
1207
-
1208
- export { AttachmentPicker, AttachmentPreviewItem, CameraButton, CharacterCounter, DragDropZone, MentionMenu, MessageComposer, SendButton, generateAttachmentId, getFileType, sendButtonVariants, useMentionAutocomplete, validateFile };
1209
- //# sourceMappingURL=chunk-O6GJ4IYS.js.map
1210
- //# sourceMappingURL=chunk-O6GJ4IYS.js.map