beez-ui 0.7.0 → 0.8.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 (96) hide show
  1. package/CHANGELOG.md +21 -3
  2. package/README.md +290 -274
  3. package/dist/components/account-menu.d.ts +53 -0
  4. package/dist/components/account-menu.js +405 -0
  5. package/dist/components/animated-collapse.d.ts +19 -0
  6. package/dist/components/animated-collapse.js +81 -0
  7. package/dist/components/animated-count.d.ts +13 -0
  8. package/dist/components/animated-count.js +105 -0
  9. package/dist/components/animated-list-item.d.ts +25 -0
  10. package/dist/components/animated-list-item.js +132 -0
  11. package/dist/components/bouncing-dots-loader.d.ts +19 -0
  12. package/dist/components/bouncing-dots-loader.js +47 -0
  13. package/dist/components/confirm-delete-button.d.ts +29 -0
  14. package/dist/components/confirm-delete-button.js +254 -0
  15. package/dist/components/empty-state.d.ts +24 -0
  16. package/dist/components/empty-state.js +37 -0
  17. package/dist/components/error-state.d.ts +20 -0
  18. package/dist/components/error-state.js +145 -0
  19. package/dist/components/external-browser-handoff.d.ts +27 -0
  20. package/dist/components/external-browser-handoff.js +306 -0
  21. package/dist/components/file-upload.d.ts +78 -0
  22. package/dist/components/file-upload.js +678 -0
  23. package/dist/components/info-popover.d.ts +23 -0
  24. package/dist/components/info-popover.js +158 -0
  25. package/dist/components/month-calendar-header.d.ts +65 -0
  26. package/dist/components/month-calendar-header.js +337 -0
  27. package/dist/components/month-grid.d.ts +59 -0
  28. package/dist/components/month-grid.js +301 -0
  29. package/dist/components/notification-bell.d.ts +50 -0
  30. package/dist/components/notification-bell.js +338 -0
  31. package/dist/components/notification-panel.d.ts +56 -0
  32. package/dist/components/notification-panel.js +281 -0
  33. package/dist/components/open-in-browser-cta.d.ts +22 -0
  34. package/dist/components/open-in-browser-cta.js +61 -0
  35. package/dist/components/presence-swap.d.ts +22 -0
  36. package/dist/components/presence-swap.js +162 -0
  37. package/dist/components/progress-ring.d.ts +20 -0
  38. package/dist/components/progress-ring.js +53 -0
  39. package/dist/components/pwa-update-control.d.ts +18 -0
  40. package/dist/components/pwa-update-control.js +119 -0
  41. package/dist/components/reaction-button.d.ts +26 -0
  42. package/dist/components/reaction-button.js +114 -0
  43. package/dist/components/rich-link-editor.d.ts +25 -0
  44. package/dist/components/rich-link-editor.js +320 -0
  45. package/dist/components/rich-markdown-content.d.ts +10 -0
  46. package/dist/components/rich-markdown-content.js +56 -0
  47. package/dist/components/rich-text-content.d.ts +19 -0
  48. package/dist/components/rich-text-content.js +26 -0
  49. package/dist/emoji-picker.d.ts +27 -0
  50. package/dist/emoji-picker.js +283 -0
  51. package/dist/hooks/use-horizontal-swipe.d.ts +23 -0
  52. package/dist/hooks/use-horizontal-swipe.js +80 -0
  53. package/dist/hooks/use-is-hydrated.d.ts +6 -0
  54. package/dist/hooks/use-is-hydrated.js +20 -0
  55. package/dist/hooks/use-minute-clock.d.ts +23 -0
  56. package/dist/hooks/use-minute-clock.js +147 -0
  57. package/dist/hooks/use-month-transition-direction.d.ts +21 -0
  58. package/dist/hooks/use-month-transition-direction.js +110 -0
  59. package/dist/hooks/use-rich-link-editor.d.ts +55 -0
  60. package/dist/hooks/use-rich-link-editor.js +515 -0
  61. package/dist/hooks/use-viewer-time-zone.d.ts +6 -0
  62. package/dist/hooks/use-viewer-time-zone.js +20 -0
  63. package/dist/index.d.ts +44 -0
  64. package/dist/index.js +43 -0
  65. package/dist/lib/browser-clipboard.d.ts +13 -0
  66. package/dist/lib/browser-clipboard.js +48 -0
  67. package/dist/lib/browser-navigation.d.ts +21 -0
  68. package/dist/lib/browser-navigation.js +42 -0
  69. package/dist/lib/file-acceptance.d.ts +43 -0
  70. package/dist/lib/file-acceptance.js +107 -0
  71. package/dist/lib/format-file-size.d.ts +16 -0
  72. package/dist/lib/format-file-size.js +34 -0
  73. package/dist/lib/fuzzy-search.d.ts +17 -0
  74. package/dist/lib/fuzzy-search.js +183 -0
  75. package/dist/lib/horizontal-swipe.d.ts +23 -0
  76. package/dist/lib/horizontal-swipe.js +29 -0
  77. package/dist/lib/in-app-browser.d.ts +35 -0
  78. package/dist/lib/in-app-browser.js +80 -0
  79. package/dist/lib/month-grid.d.ts +42 -0
  80. package/dist/lib/month-grid.js +74 -0
  81. package/dist/lib/name-initials.d.ts +7 -0
  82. package/dist/lib/name-initials.js +11 -0
  83. package/dist/lib/rich-text/link-markdown-constants.d.ts +147 -0
  84. package/dist/lib/rich-text/link-markdown-constants.js +458 -0
  85. package/dist/lib/rich-text/link-markdown-types.d.ts +53 -0
  86. package/dist/lib/rich-text/link-markdown-types.js +1 -0
  87. package/dist/lib/rich-text/link-markdown.d.ts +193 -0
  88. package/dist/lib/rich-text/link-markdown.js +592 -0
  89. package/dist/lib/rich-text/rich-markdown.d.ts +41 -0
  90. package/dist/lib/rich-text/rich-markdown.js +105 -0
  91. package/dist/lib/rich-text/rich-text-editor-dom.d.ts +26 -0
  92. package/dist/lib/rich-text/rich-text-editor-dom.js +79 -0
  93. package/dist/motion/tokens.d.ts +17 -1
  94. package/dist/motion/tokens.js +17 -1
  95. package/dist/styles.css +1 -1
  96. package/package.json +211 -1
@@ -0,0 +1,678 @@
1
+ "use client";
2
+ import { c as _c } from "react/compiler-runtime";
3
+ /**
4
+ * File upload building blocks: a drop zone that validates picked or dropped files, and a list of
5
+ * files with upload progress, failure and retry. Uploading itself stays with the application.
6
+ */
7
+ import { useId, useRef, useState } from "react";
8
+ import { AnimatePresence } from "motion/react";
9
+ import { CheckCircle2Icon, FileIcon, Trash2Icon, UploadCloudIcon, XCircleIcon } from "lucide-react";
10
+ import { cn } from "../lib/utils.js";
11
+ import { classifyFiles } from "../lib/file-acceptance.js";
12
+ import { formatFileSize } from "../lib/format-file-size.js";
13
+ import { AnimatedListItem } from "./animated-list-item.js";
14
+ import { Button } from "./button.js";
15
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
16
+ const COMPLETE_PROGRESS = 100;
17
+ const FILE_UPLOAD_DROP_ZONE_DEFAULT_LABELS = {
18
+ uploadAction: "Elegí un archivo",
19
+ dragAndDrop: "o arrastralo acá",
20
+ input: "Subir archivos"
21
+ };
22
+ /**
23
+ * Renders the drop zone. The action button and a click anywhere on the zone open the native file
24
+ * picker; the same file can be picked again after a failure.
25
+ * @param props - Constraints, callbacks and optional copy.
26
+ * @returns The drop zone.
27
+ */
28
+ export function FileUploadDropZone(t0) {
29
+ const $ = _c(63);
30
+ const { hint, isDisabled: t1, accept, allowsMultiple: t2, maxSize, onDropFiles, onDropUnacceptedFiles, onSizeLimitExceed, inputId, labels, className } = t0;
31
+ const isDisabled = t1 === undefined ? false : t1;
32
+ const allowsMultiple = t2 === undefined ? true : t2;
33
+ let t3;
34
+ if ($[0] !== labels) {
35
+ t3 = {
36
+ ...FILE_UPLOAD_DROP_ZONE_DEFAULT_LABELS,
37
+ ...labels
38
+ };
39
+ $[0] = labels;
40
+ $[1] = t3;
41
+ } else {
42
+ t3 = $[1];
43
+ }
44
+ const resolvedLabels = t3;
45
+ const generatedInputId = useId();
46
+ const hintId = useId();
47
+ const resolvedInputId = inputId ?? generatedInputId;
48
+ const inputRef = useRef(null);
49
+ const [isInvalid, setIsInvalid] = useState(false);
50
+ const [isDraggingOver, setIsDraggingOver] = useState(false);
51
+ let t4;
52
+ if ($[2] !== accept || $[3] !== allowsMultiple || $[4] !== maxSize || $[5] !== onDropFiles || $[6] !== onDropUnacceptedFiles || $[7] !== onSizeLimitExceed) {
53
+ t4 = (files) => {
54
+ const { accepted, unaccepted, oversized } = classifyFiles(files, {
55
+ accept,
56
+ maxSize,
57
+ allowsMultiple
58
+ });
59
+ setIsInvalid(unaccepted.length > 0 || oversized.length > 0);
60
+ if (oversized.length > 0) {
61
+ onSizeLimitExceed?.(oversized);
62
+ }
63
+ if (accepted.length > 0) {
64
+ onDropFiles?.(accepted);
65
+ }
66
+ if (unaccepted.length > 0) {
67
+ onDropUnacceptedFiles?.(unaccepted);
68
+ }
69
+ if (inputRef.current) {
70
+ inputRef.current.value = "";
71
+ }
72
+ };
73
+ $[2] = accept;
74
+ $[3] = allowsMultiple;
75
+ $[4] = maxSize;
76
+ $[5] = onDropFiles;
77
+ $[6] = onDropUnacceptedFiles;
78
+ $[7] = onSizeLimitExceed;
79
+ $[8] = t4;
80
+ } else {
81
+ t4 = $[8];
82
+ }
83
+ const processFiles = t4;
84
+ let t5;
85
+ if ($[9] !== isDisabled) {
86
+ t5 = (event) => {
87
+ event.preventDefault();
88
+ if (!isDisabled) {
89
+ setIsDraggingOver(true);
90
+ }
91
+ };
92
+ $[9] = isDisabled;
93
+ $[10] = t5;
94
+ } else {
95
+ t5 = $[10];
96
+ }
97
+ const handleDragOver = t5;
98
+ let t6;
99
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
100
+ t6 = (event_0) => {
101
+ event_0.preventDefault();
102
+ setIsDraggingOver(false);
103
+ };
104
+ $[11] = t6;
105
+ } else {
106
+ t6 = $[11];
107
+ }
108
+ const handleDragLeave = t6;
109
+ let t7;
110
+ if ($[12] !== isDisabled || $[13] !== processFiles) {
111
+ t7 = (event_1) => {
112
+ event_1.preventDefault();
113
+ setIsDraggingOver(false);
114
+ if (!isDisabled) {
115
+ processFiles(Array.from(event_1.dataTransfer.files));
116
+ }
117
+ };
118
+ $[12] = isDisabled;
119
+ $[13] = processFiles;
120
+ $[14] = t7;
121
+ } else {
122
+ t7 = $[14];
123
+ }
124
+ const handleDrop = t7;
125
+ let t8;
126
+ if ($[15] !== isDisabled) {
127
+ t8 = () => {
128
+ if (!isDisabled) {
129
+ inputRef.current?.click();
130
+ }
131
+ };
132
+ $[15] = isDisabled;
133
+ $[16] = t8;
134
+ } else {
135
+ t8 = $[16];
136
+ }
137
+ const openFilePicker = t8;
138
+ const t9 = isDraggingOver || undefined;
139
+ const t10 = isDisabled || undefined;
140
+ const t11 = isInvalid || undefined;
141
+ let t12;
142
+ if ($[17] !== className) {
143
+ t12 = cn("relative flex cursor-pointer flex-col items-center gap-3 rounded-xl bg-background px-6 py-4 text-muted-foreground ring-1 ring-border transition-[box-shadow,background-color] ring-inset data-dragging:ring-2 data-dragging:ring-primary data-disabled:cursor-not-allowed data-disabled:bg-muted", className);
144
+ $[17] = className;
145
+ $[18] = t12;
146
+ } else {
147
+ t12 = $[18];
148
+ }
149
+ const t13 = isDisabled && "opacity-50";
150
+ let t14;
151
+ if ($[19] !== t13) {
152
+ t14 = cn("inline-flex size-10 items-center justify-center rounded-lg border border-border bg-background shadow-xs", t13);
153
+ $[19] = t13;
154
+ $[20] = t14;
155
+ } else {
156
+ t14 = $[20];
157
+ }
158
+ let t15;
159
+ if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
160
+ t15 = /* @__PURE__ */ _jsx(UploadCloudIcon, {
161
+ "aria-hidden": true,
162
+ className: "size-5 text-foreground"
163
+ });
164
+ $[21] = t15;
165
+ } else {
166
+ t15 = $[21];
167
+ }
168
+ let t16;
169
+ if ($[22] !== t14) {
170
+ t16 = /* @__PURE__ */ _jsx("span", {
171
+ className: t14,
172
+ children: t15
173
+ });
174
+ $[22] = t14;
175
+ $[23] = t16;
176
+ } else {
177
+ t16 = $[23];
178
+ }
179
+ const t17 = hint ? hintId : undefined;
180
+ let t18;
181
+ if ($[24] !== processFiles) {
182
+ t18 = (event_2) => processFiles(Array.from(event_2.target.files ?? []));
183
+ $[24] = processFiles;
184
+ $[25] = t18;
185
+ } else {
186
+ t18 = $[25];
187
+ }
188
+ let t19;
189
+ if ($[26] !== accept || $[27] !== allowsMultiple || $[28] !== isDisabled || $[29] !== resolvedInputId || $[30] !== resolvedLabels.input || $[31] !== t17 || $[32] !== t18) {
190
+ t19 = /* @__PURE__ */ _jsx("input", {
191
+ ref: inputRef,
192
+ id: resolvedInputId,
193
+ type: "file",
194
+ className: "sr-only",
195
+ disabled: isDisabled,
196
+ "aria-label": resolvedLabels.input,
197
+ "aria-describedby": t17,
198
+ accept,
199
+ multiple: allowsMultiple,
200
+ onChange: t18,
201
+ onClick: _temp
202
+ });
203
+ $[26] = accept;
204
+ $[27] = allowsMultiple;
205
+ $[28] = isDisabled;
206
+ $[29] = resolvedInputId;
207
+ $[30] = resolvedLabels.input;
208
+ $[31] = t17;
209
+ $[32] = t18;
210
+ $[33] = t19;
211
+ } else {
212
+ t19 = $[33];
213
+ }
214
+ let t20;
215
+ if ($[34] !== openFilePicker) {
216
+ t20 = (event_4) => {
217
+ event_4.stopPropagation();
218
+ openFilePicker();
219
+ };
220
+ $[34] = openFilePicker;
221
+ $[35] = t20;
222
+ } else {
223
+ t20 = $[35];
224
+ }
225
+ let t21;
226
+ if ($[36] !== isDisabled || $[37] !== resolvedLabels.uploadAction || $[38] !== t20) {
227
+ t21 = /* @__PURE__ */ _jsx(Button, {
228
+ className: "h-auto p-0 font-semibold",
229
+ disabled: isDisabled,
230
+ type: "button",
231
+ variant: "link",
232
+ onClick: t20,
233
+ children: resolvedLabels.uploadAction
234
+ });
235
+ $[36] = isDisabled;
236
+ $[37] = resolvedLabels.uploadAction;
237
+ $[38] = t20;
238
+ $[39] = t21;
239
+ } else {
240
+ t21 = $[39];
241
+ }
242
+ let t22;
243
+ if ($[40] !== resolvedLabels.dragAndDrop) {
244
+ t22 = /* @__PURE__ */ _jsx("span", {
245
+ className: "text-sm max-md:hidden",
246
+ children: resolvedLabels.dragAndDrop
247
+ });
248
+ $[40] = resolvedLabels.dragAndDrop;
249
+ $[41] = t22;
250
+ } else {
251
+ t22 = $[41];
252
+ }
253
+ let t23;
254
+ if ($[42] !== t19 || $[43] !== t21 || $[44] !== t22) {
255
+ t23 = /* @__PURE__ */ _jsxs("div", {
256
+ className: "flex flex-wrap items-center justify-center gap-1",
257
+ children: [
258
+ t19,
259
+ t21,
260
+ t22
261
+ ]
262
+ });
263
+ $[42] = t19;
264
+ $[43] = t21;
265
+ $[44] = t22;
266
+ $[45] = t23;
267
+ } else {
268
+ t23 = $[45];
269
+ }
270
+ let t24;
271
+ if ($[46] !== hint || $[47] !== hintId || $[48] !== isInvalid) {
272
+ t24 = hint ? /* @__PURE__ */ _jsx("p", {
273
+ id: hintId,
274
+ className: cn("m-0 text-xs transition-colors", isInvalid && "text-destructive"),
275
+ children: hint
276
+ }) : null;
277
+ $[46] = hint;
278
+ $[47] = hintId;
279
+ $[48] = isInvalid;
280
+ $[49] = t24;
281
+ } else {
282
+ t24 = $[49];
283
+ }
284
+ let t25;
285
+ if ($[50] !== t23 || $[51] !== t24) {
286
+ t25 = /* @__PURE__ */ _jsxs("div", {
287
+ className: "flex flex-col gap-1 text-center",
288
+ children: [t23, t24]
289
+ });
290
+ $[50] = t23;
291
+ $[51] = t24;
292
+ $[52] = t25;
293
+ } else {
294
+ t25 = $[52];
295
+ }
296
+ let t26;
297
+ if ($[53] !== handleDragOver || $[54] !== handleDrop || $[55] !== openFilePicker || $[56] !== t10 || $[57] !== t11 || $[58] !== t12 || $[59] !== t16 || $[60] !== t25 || $[61] !== t9) {
298
+ t26 = /* @__PURE__ */ _jsxs("div", {
299
+ "data-slot": "file-upload-drop-zone",
300
+ "data-dragging": t9,
301
+ "data-disabled": t10,
302
+ "data-invalid": t11,
303
+ className: t12,
304
+ onClick: openFilePicker,
305
+ onDragEnter: handleDragOver,
306
+ onDragOver: handleDragOver,
307
+ onDragLeave: handleDragLeave,
308
+ onDragEnd: handleDragLeave,
309
+ onDrop: handleDrop,
310
+ children: [t16, t25]
311
+ });
312
+ $[53] = handleDragOver;
313
+ $[54] = handleDrop;
314
+ $[55] = openFilePicker;
315
+ $[56] = t10;
316
+ $[57] = t11;
317
+ $[58] = t12;
318
+ $[59] = t16;
319
+ $[60] = t25;
320
+ $[61] = t9;
321
+ $[62] = t26;
322
+ } else {
323
+ t26 = $[62];
324
+ }
325
+ return t26;
326
+ }
327
+ function _temp(event_3) {
328
+ return event_3.stopPropagation();
329
+ }
330
+ const FILE_UPLOAD_ITEM_DEFAULT_LABELS = {
331
+ complete: "Completado",
332
+ uploading: "Subiendo...",
333
+ failed: "Falló",
334
+ retry: "Reintentar",
335
+ delete: "Eliminar",
336
+ progress: "Progreso de subida"
337
+ };
338
+ /**
339
+ * Renders one file with its size, status, progress bar, delete action and, after a failure, a
340
+ * retry action. Place it inside `FileUploadList` so additions and removals animate.
341
+ * @param props - File metadata, progress, callbacks and optional copy.
342
+ * @returns The list item.
343
+ */
344
+ export function FileUploadItem(t0) {
345
+ const $ = _c(46);
346
+ const { name, size, progress, failed: t1, onDelete, isDeleteDisabled, onRetry, locale, labels, className } = t0;
347
+ const failed = t1 === undefined ? false : t1;
348
+ let t2;
349
+ if ($[0] !== labels) {
350
+ t2 = {
351
+ ...FILE_UPLOAD_ITEM_DEFAULT_LABELS,
352
+ ...labels
353
+ };
354
+ $[0] = labels;
355
+ $[1] = t2;
356
+ } else {
357
+ t2 = $[1];
358
+ }
359
+ const resolvedLabels = t2;
360
+ const clampedProgress = Math.min(Math.max(progress, 0), COMPLETE_PROGRESS);
361
+ const isComplete = clampedProgress === COMPLETE_PROGRESS && !failed;
362
+ const t3 = failed || undefined;
363
+ let t4;
364
+ if ($[2] !== className) {
365
+ t4 = cn("relative flex w-full min-w-0 gap-3 rounded-xl bg-background p-4 ring-1 ring-border ring-inset data-failed:ring-2 data-failed:ring-destructive", className);
366
+ $[2] = className;
367
+ $[3] = t4;
368
+ } else {
369
+ t4 = $[3];
370
+ }
371
+ let t5;
372
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
373
+ t5 = /* @__PURE__ */ _jsx(FileIcon, {
374
+ "aria-hidden": true,
375
+ className: "size-10 shrink-0 stroke-[1.25] text-muted-foreground"
376
+ });
377
+ $[4] = t5;
378
+ } else {
379
+ t5 = $[4];
380
+ }
381
+ let t6;
382
+ if ($[5] !== name) {
383
+ t6 = /* @__PURE__ */ _jsx("p", {
384
+ className: "m-0 max-w-full text-sm font-medium break-words text-foreground",
385
+ children: name
386
+ });
387
+ $[5] = name;
388
+ $[6] = t6;
389
+ } else {
390
+ t6 = $[6];
391
+ }
392
+ let t7;
393
+ if ($[7] !== locale || $[8] !== size) {
394
+ t7 = formatFileSize(size, { locale });
395
+ $[7] = locale;
396
+ $[8] = size;
397
+ $[9] = t7;
398
+ } else {
399
+ t7 = $[9];
400
+ }
401
+ let t8;
402
+ if ($[10] !== t7) {
403
+ t8 = /* @__PURE__ */ _jsx("span", {
404
+ className: "truncate whitespace-nowrap text-muted-foreground",
405
+ children: t7
406
+ });
407
+ $[10] = t7;
408
+ $[11] = t8;
409
+ } else {
410
+ t8 = $[11];
411
+ }
412
+ let t9;
413
+ if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
414
+ t9 = /* @__PURE__ */ _jsx("span", {
415
+ "aria-hidden": true,
416
+ className: "h-3 w-px rounded-full bg-border"
417
+ });
418
+ $[12] = t9;
419
+ } else {
420
+ t9 = $[12];
421
+ }
422
+ let t10;
423
+ if ($[13] !== failed || $[14] !== isComplete || $[15] !== resolvedLabels.complete || $[16] !== resolvedLabels.failed || $[17] !== resolvedLabels.uploading) {
424
+ t10 = /* @__PURE__ */ _jsx("span", {
425
+ className: "flex items-center gap-1 font-medium",
426
+ role: "status",
427
+ children: failed ? /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsx(XCircleIcon, {
428
+ "aria-hidden": true,
429
+ className: "size-4 text-destructive"
430
+ }), /* @__PURE__ */ _jsx("span", {
431
+ className: "text-destructive",
432
+ children: resolvedLabels.failed
433
+ })] }) : isComplete ? /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsx(CheckCircle2Icon, {
434
+ "aria-hidden": true,
435
+ className: "size-4 text-green-600 dark:text-green-500"
436
+ }), /* @__PURE__ */ _jsx("span", {
437
+ className: "text-green-700 dark:text-green-400",
438
+ children: resolvedLabels.complete
439
+ })] }) : /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsx(UploadCloudIcon, {
440
+ "aria-hidden": true,
441
+ className: "size-4 text-muted-foreground"
442
+ }), /* @__PURE__ */ _jsx("span", {
443
+ className: "text-muted-foreground",
444
+ children: resolvedLabels.uploading
445
+ })] })
446
+ });
447
+ $[13] = failed;
448
+ $[14] = isComplete;
449
+ $[15] = resolvedLabels.complete;
450
+ $[16] = resolvedLabels.failed;
451
+ $[17] = resolvedLabels.uploading;
452
+ $[18] = t10;
453
+ } else {
454
+ t10 = $[18];
455
+ }
456
+ let t11;
457
+ if ($[19] !== t10 || $[20] !== t8) {
458
+ t11 = /* @__PURE__ */ _jsxs("div", {
459
+ className: "mt-0.5 flex items-center gap-2 text-sm",
460
+ children: [
461
+ t8,
462
+ t9,
463
+ t10
464
+ ]
465
+ });
466
+ $[19] = t10;
467
+ $[20] = t8;
468
+ $[21] = t11;
469
+ } else {
470
+ t11 = $[21];
471
+ }
472
+ let t12;
473
+ if ($[22] !== t11 || $[23] !== t6) {
474
+ t12 = /* @__PURE__ */ _jsxs("div", {
475
+ className: "min-w-0 flex-1",
476
+ children: [t6, t11]
477
+ });
478
+ $[22] = t11;
479
+ $[23] = t6;
480
+ $[24] = t12;
481
+ } else {
482
+ t12 = $[24];
483
+ }
484
+ let t13;
485
+ if ($[25] !== isDeleteDisabled || $[26] !== name || $[27] !== onDelete || $[28] !== resolvedLabels.delete) {
486
+ t13 = onDelete ? /* @__PURE__ */ _jsx(Button, {
487
+ "aria-label": `${resolvedLabels.delete} ${name}`,
488
+ className: "-mt-2 -mr-2 self-start text-muted-foreground",
489
+ disabled: isDeleteDisabled,
490
+ size: "icon-sm",
491
+ type: "button",
492
+ variant: "ghost",
493
+ onClick: onDelete,
494
+ children: /* @__PURE__ */ _jsx(Trash2Icon, { "aria-hidden": true })
495
+ }) : null;
496
+ $[25] = isDeleteDisabled;
497
+ $[26] = name;
498
+ $[27] = onDelete;
499
+ $[28] = resolvedLabels.delete;
500
+ $[29] = t13;
501
+ } else {
502
+ t13 = $[29];
503
+ }
504
+ let t14;
505
+ if ($[30] !== t12 || $[31] !== t13) {
506
+ t14 = /* @__PURE__ */ _jsxs("div", {
507
+ className: "flex w-full min-w-0 flex-1",
508
+ children: [t12, t13]
509
+ });
510
+ $[30] = t12;
511
+ $[31] = t13;
512
+ $[32] = t14;
513
+ } else {
514
+ t14 = $[32];
515
+ }
516
+ let t15;
517
+ if ($[33] !== clampedProgress || $[34] !== failed || $[35] !== onRetry || $[36] !== resolvedLabels.progress || $[37] !== resolvedLabels.retry) {
518
+ t15 = failed ? onRetry ? /* @__PURE__ */ _jsx(Button, {
519
+ className: "mt-1.5 h-auto p-0 text-destructive",
520
+ size: "sm",
521
+ type: "button",
522
+ variant: "link",
523
+ onClick: onRetry,
524
+ children: resolvedLabels.retry
525
+ }) : null : /* @__PURE__ */ _jsxs("div", {
526
+ className: "mt-1 flex w-full items-center gap-3",
527
+ children: [/* @__PURE__ */ _jsx("div", {
528
+ "aria-label": resolvedLabels.progress,
529
+ "aria-valuemax": COMPLETE_PROGRESS,
530
+ "aria-valuemin": 0,
531
+ "aria-valuenow": clampedProgress,
532
+ className: "h-2 flex-1 overflow-hidden rounded-full bg-muted",
533
+ role: "progressbar",
534
+ children: /* @__PURE__ */ _jsx("div", {
535
+ className: "h-full rounded-full bg-primary transition-[width] duration-150",
536
+ style: { width: `${clampedProgress}%` }
537
+ })
538
+ }), /* @__PURE__ */ _jsxs("span", {
539
+ className: "text-sm font-medium text-foreground tabular-nums",
540
+ children: [clampedProgress, "%"]
541
+ })]
542
+ });
543
+ $[33] = clampedProgress;
544
+ $[34] = failed;
545
+ $[35] = onRetry;
546
+ $[36] = resolvedLabels.progress;
547
+ $[37] = resolvedLabels.retry;
548
+ $[38] = t15;
549
+ } else {
550
+ t15 = $[38];
551
+ }
552
+ let t16;
553
+ if ($[39] !== t14 || $[40] !== t15) {
554
+ t16 = /* @__PURE__ */ _jsxs("div", {
555
+ className: "flex min-w-0 flex-1 flex-col items-start",
556
+ children: [t14, t15]
557
+ });
558
+ $[39] = t14;
559
+ $[40] = t15;
560
+ $[41] = t16;
561
+ } else {
562
+ t16 = $[41];
563
+ }
564
+ let t17;
565
+ if ($[42] !== t16 || $[43] !== t3 || $[44] !== t4) {
566
+ t17 = /* @__PURE__ */ _jsxs(AnimatedListItem, {
567
+ "data-slot": "file-upload-item",
568
+ "data-failed": t3,
569
+ className: t4,
570
+ children: [t5, t16]
571
+ });
572
+ $[42] = t16;
573
+ $[43] = t3;
574
+ $[44] = t4;
575
+ $[45] = t17;
576
+ } else {
577
+ t17 = $[45];
578
+ }
579
+ return t17;
580
+ }
581
+ /**
582
+ * Lays out a drop zone and its file list.
583
+ * @param props - Native `div` attributes.
584
+ * @returns The container.
585
+ */
586
+ export function FileUpload(t0) {
587
+ const $ = _c(8);
588
+ let className;
589
+ let props;
590
+ if ($[0] !== t0) {
591
+ ({className, ...props} = t0);
592
+ $[0] = t0;
593
+ $[1] = className;
594
+ $[2] = props;
595
+ } else {
596
+ className = $[1];
597
+ props = $[2];
598
+ }
599
+ let t1;
600
+ if ($[3] !== className) {
601
+ t1 = cn("flex w-full min-w-0 flex-col gap-4", className);
602
+ $[3] = className;
603
+ $[4] = t1;
604
+ } else {
605
+ t1 = $[4];
606
+ }
607
+ let t2;
608
+ if ($[5] !== props || $[6] !== t1) {
609
+ t2 = /* @__PURE__ */ _jsx("div", {
610
+ "data-slot": "file-upload",
611
+ className: t1,
612
+ ...props
613
+ });
614
+ $[5] = props;
615
+ $[6] = t1;
616
+ $[7] = t2;
617
+ } else {
618
+ t2 = $[7];
619
+ }
620
+ return t2;
621
+ }
622
+ /**
623
+ * Lists `FileUploadItem`s; only files added after the first render animate in.
624
+ * @param props - Native `ul` attributes and the items.
625
+ * @returns The list.
626
+ */
627
+ export function FileUploadList(t0) {
628
+ const $ = _c(12);
629
+ let children;
630
+ let className;
631
+ let props;
632
+ if ($[0] !== t0) {
633
+ ({className, children, ...props} = t0);
634
+ $[0] = t0;
635
+ $[1] = children;
636
+ $[2] = className;
637
+ $[3] = props;
638
+ } else {
639
+ children = $[1];
640
+ className = $[2];
641
+ props = $[3];
642
+ }
643
+ let t1;
644
+ if ($[4] !== className) {
645
+ t1 = cn("m-0 flex w-full min-w-0 list-none flex-col gap-3 p-0", className);
646
+ $[4] = className;
647
+ $[5] = t1;
648
+ } else {
649
+ t1 = $[5];
650
+ }
651
+ let t2;
652
+ if ($[6] !== children) {
653
+ t2 = /* @__PURE__ */ _jsx(AnimatePresence, {
654
+ initial: false,
655
+ children
656
+ });
657
+ $[6] = children;
658
+ $[7] = t2;
659
+ } else {
660
+ t2 = $[7];
661
+ }
662
+ let t3;
663
+ if ($[8] !== props || $[9] !== t1 || $[10] !== t2) {
664
+ t3 = /* @__PURE__ */ _jsx("ul", {
665
+ "data-slot": "file-upload-list",
666
+ className: t1,
667
+ ...props,
668
+ children: t2
669
+ });
670
+ $[8] = props;
671
+ $[9] = t1;
672
+ $[10] = t2;
673
+ $[11] = t3;
674
+ } else {
675
+ t3 = $[11];
676
+ }
677
+ return t3;
678
+ }
@@ -0,0 +1,23 @@
1
+ /** Icon button that toggles a short explanatory message, for inline help next to labels. */
2
+ import { type ReactNode } from "react";
3
+ export interface InfoPopoverLabels {
4
+ /** Accessible name of the close button inside the message. */
5
+ close?: string;
6
+ /** Accessible name of the icon-only trigger. */
7
+ trigger?: string;
8
+ }
9
+ export interface InfoPopoverProps {
10
+ /** Explanation shown inside the popover. */
11
+ message: ReactNode;
12
+ labels?: InfoPopoverLabels;
13
+ side?: "top" | "right" | "bottom" | "left";
14
+ className?: string;
15
+ contentClassName?: string;
16
+ }
17
+ /**
18
+ * Renders an info icon that opens the message on click or tap, unlike a hover tooltip, so it
19
+ * works on touch devices. Escape, an outside click or the close button dismiss it.
20
+ * @param props - Message, optional labels, side and class names.
21
+ * @returns The trigger with its popover.
22
+ */
23
+ export declare function InfoPopover({ message, labels, side, className, contentClassName }: InfoPopoverProps): import("react").JSX.Element;