@spark-ui/components 11.5.0 → 11.6.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 (44) hide show
  1. package/dist/alert-dialog/index.mjs +3 -3
  2. package/dist/avatar/index.d.mts +2 -2
  3. package/dist/avatar/index.d.ts +2 -2
  4. package/dist/avatar/index.mjs +2 -2
  5. package/dist/button/index.mjs +1 -1
  6. package/dist/carousel/index.mjs +2 -2
  7. package/dist/{chunk-HEKSVWYW.mjs → chunk-2YM6GKWW.mjs} +2 -1
  8. package/dist/{chunk-TKAU6SMC.mjs → chunk-7EWSMIZU.mjs} +21 -4
  9. package/dist/chunk-7EWSMIZU.mjs.map +1 -0
  10. package/dist/{chunk-XYK6V3JF.mjs → chunk-DCXWGQVZ.mjs} +2 -2
  11. package/dist/{chunk-D7YBYT5H.mjs → chunk-GPJMLIHC.mjs} +2 -2
  12. package/dist/{chunk-2BSBKLHG.mjs → chunk-WLI4EPS6.mjs} +2 -2
  13. package/dist/combobox/index.mjs +3 -3
  14. package/dist/dialog/index.mjs +3 -3
  15. package/dist/docgen.json +344 -65
  16. package/dist/drawer/index.mjs +2 -2
  17. package/dist/dropdown/index.mjs +3 -3
  18. package/dist/file-upload/index.d.mts +51 -32
  19. package/dist/file-upload/index.d.ts +51 -32
  20. package/dist/file-upload/index.js +256 -129
  21. package/dist/file-upload/index.js.map +1 -1
  22. package/dist/file-upload/index.mjs +219 -109
  23. package/dist/file-upload/index.mjs.map +1 -1
  24. package/dist/icon-button/index.mjs +2 -2
  25. package/dist/pagination/index.mjs +2 -2
  26. package/dist/popover/index.mjs +3 -3
  27. package/dist/progress/index.d.mts +6 -2
  28. package/dist/progress/index.d.ts +6 -2
  29. package/dist/progress/index.js +20 -3
  30. package/dist/progress/index.js.map +1 -1
  31. package/dist/progress/index.mjs +1 -1
  32. package/dist/scrolling-list/index.mjs +2 -2
  33. package/dist/snackbar/index.mjs +2 -2
  34. package/dist/stepper/index.mjs +2 -2
  35. package/dist/tabs/index.mjs +1 -1
  36. package/dist/toast/index.d.mts +6 -6
  37. package/dist/toast/index.d.ts +6 -6
  38. package/dist/toast/index.mjs +2 -2
  39. package/package.json +5 -5
  40. package/dist/chunk-TKAU6SMC.mjs.map +0 -1
  41. /package/dist/{chunk-HEKSVWYW.mjs.map → chunk-2YM6GKWW.mjs.map} +0 -0
  42. /package/dist/{chunk-XYK6V3JF.mjs.map → chunk-DCXWGQVZ.mjs.map} +0 -0
  43. /package/dist/{chunk-D7YBYT5H.mjs.map → chunk-GPJMLIHC.mjs.map} +0 -0
  44. /package/dist/{chunk-2BSBKLHG.mjs.map → chunk-WLI4EPS6.mjs.map} +0 -0
@@ -20,15 +20,47 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/file-upload/index.ts
21
21
  var file_upload_exports = {};
22
22
  __export(file_upload_exports, {
23
+ FILE_UPLOAD_ERRORS: () => FILE_UPLOAD_ERRORS,
23
24
  FileUpload: () => FileUpload2
24
25
  });
25
26
  module.exports = __toCommonJS(file_upload_exports);
26
27
 
27
28
  // src/file-upload/FileUpload.tsx
28
29
  var import_form_field = require("@spark-ui/components/form-field");
30
+ var import_react3 = require("react");
31
+
32
+ // src/file-upload/useFileUploadState.tsx
29
33
  var import_use_combined_state = require("@spark-ui/hooks/use-combined-state");
30
34
  var import_react2 = require("react");
31
35
 
36
+ // src/file-upload/constants.ts
37
+ var FILE_UPLOAD_ERRORS = {
38
+ /**
39
+ * Exceeds the maxFiles limit
40
+ */
41
+ TOO_MANY_FILES: "TOO_MANY_FILES",
42
+ /**
43
+ * File type not in the accept list
44
+ */
45
+ FILE_INVALID_TYPE: "FILE_INVALID_TYPE",
46
+ /**
47
+ * File size exceeds maxFileSize
48
+ */
49
+ FILE_TOO_LARGE: "FILE_TOO_LARGE",
50
+ /**
51
+ * File size below minFileSize
52
+ */
53
+ FILE_TOO_SMALL: "FILE_TOO_SMALL",
54
+ /**
55
+ * Generic validation failure
56
+ */
57
+ FILE_INVALID: "FILE_INVALID",
58
+ /**
59
+ * Duplicate file detected
60
+ */
61
+ FILE_EXISTS: "FILE_EXISTS"
62
+ };
63
+
32
64
  // src/file-upload/utils.ts
33
65
  var import_CvOutline = require("@spark-ui/icons/CvOutline");
34
66
  var import_FilePdfOutline = require("@spark-ui/icons/FilePdfOutline");
@@ -128,13 +160,8 @@ function getFileIcon(file) {
128
160
  return (0, import_react.createElement)(import_CvOutline.CvOutline);
129
161
  }
130
162
 
131
- // src/file-upload/FileUpload.tsx
132
- var import_jsx_runtime = require("react/jsx-runtime");
133
- var FileUploadContext = (0, import_react2.createContext)(null);
134
- var ID_PREFIX = ":file-upload";
135
- var FileUpload = ({
136
- asChild: _asChild = false,
137
- children,
163
+ // src/file-upload/useFileUploadState.tsx
164
+ function useFileUploadState({
138
165
  defaultValue = [],
139
166
  value: controlledValue,
140
167
  onFileAccept,
@@ -145,31 +172,12 @@ var FileUpload = ({
145
172
  maxFiles,
146
173
  maxFileSize,
147
174
  minFileSize,
148
- disabled: disabledProp = false,
149
- readOnly: readOnlyProp = false,
175
+ disabled = false,
176
+ readOnly = false,
150
177
  locale
151
- }) => {
152
- const field = (0, import_form_field.useFormFieldControl)();
153
- const {
154
- id: fieldId,
155
- name: fieldName,
156
- isInvalid,
157
- isRequired,
158
- description,
159
- disabled: fieldDisabled,
160
- readOnly: fieldReadOnly
161
- } = field;
178
+ }) {
162
179
  const defaultLocale = locale || (typeof navigator !== "undefined" && navigator.language ? navigator.language : "en");
163
- const internalId = (0, import_react2.useId)();
164
- const inputId = fieldId || `${ID_PREFIX}-${internalId}`;
165
- const inputName = fieldName;
166
- const inputRef = (0, import_react2.useRef)(null);
167
- const triggerRef = (0, import_react2.useRef)(null);
168
- const dropzoneRef = (0, import_react2.useRef)(null);
169
- const deleteButtonRefs = (0, import_react2.useRef)([]);
170
- const disabled = fieldDisabled ?? disabledProp;
171
- const readOnly = fieldReadOnly ?? readOnlyProp;
172
- const [filesState, setFilesState, ,] = (0, import_use_combined_state.useCombinedState)(controlledValue, defaultValue);
180
+ const [filesState, setFilesState] = (0, import_use_combined_state.useCombinedState)(controlledValue, defaultValue);
173
181
  const files = filesState ?? [];
174
182
  const setFiles = setFilesState;
175
183
  const [rejectedFiles, setRejectedFiles] = (0, import_react2.useState)([]);
@@ -201,20 +209,17 @@ var FileUpload = ({
201
209
  };
202
210
  setFiles((prev) => {
203
211
  const currentFiles = prev ?? [];
204
- if (maxFiles !== void 0) {
205
- const currentCount = currentFiles.length;
206
- const remainingSlots = maxFiles - currentCount;
207
- if (remainingSlots <= 0) {
208
- newFiles.forEach((file) => {
209
- addRejectedFile(file, "TOO_MANY_FILES");
210
- });
211
- }
212
+ const remainingSlots = maxFiles !== void 0 ? maxFiles - currentFiles.length : void 0;
213
+ if (remainingSlots !== void 0 && remainingSlots <= 0) {
214
+ newFiles.forEach((file) => {
215
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.TOO_MANY_FILES);
216
+ });
212
217
  }
213
218
  let filteredFiles = newFiles;
214
219
  if (accept) {
215
220
  const rejectedByAccept = newFiles.filter((file) => !validateFileAccept(file, accept));
216
221
  rejectedByAccept.forEach((file) => {
217
- addRejectedFile(file, "FILE_INVALID_TYPE");
222
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.FILE_INVALID_TYPE);
218
223
  });
219
224
  filteredFiles = newFiles.filter((file) => validateFileAccept(file, accept));
220
225
  }
@@ -224,11 +229,11 @@ var FileUpload = ({
224
229
  const validation = validateFileSize(file, minFileSize, maxFileSize, defaultLocale);
225
230
  if (!validation.valid) {
226
231
  if (maxFileSize !== void 0 && file.size > maxFileSize) {
227
- addRejectedFile(file, "FILE_TOO_LARGE");
232
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.FILE_TOO_LARGE);
228
233
  } else if (minFileSize !== void 0 && file.size < minFileSize) {
229
- addRejectedFile(file, "FILE_TOO_SMALL");
234
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.FILE_TOO_SMALL);
230
235
  } else {
231
- addRejectedFile(file, "FILE_INVALID");
236
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.FILE_INVALID);
232
237
  }
233
238
  return false;
234
239
  }
@@ -236,35 +241,27 @@ var FileUpload = ({
236
241
  });
237
242
  }
238
243
  const seenFiles = /* @__PURE__ */ new Map();
239
- const duplicateFiles = [];
240
244
  const uniqueFiles = validSizeFiles.filter((file) => {
241
245
  const fileKey = `${file.name}-${file.size}`;
242
246
  const existsInPrev = fileExists(file, currentFiles);
243
247
  if (existsInPrev) {
244
- duplicateFiles.push(file);
245
- addRejectedFile(file, "FILE_EXISTS");
248
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.FILE_EXISTS);
246
249
  return false;
247
250
  }
248
251
  if (seenFiles.has(fileKey)) {
249
- duplicateFiles.push(file);
250
- addRejectedFile(file, "FILE_EXISTS");
252
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.FILE_EXISTS);
251
253
  return false;
252
254
  }
253
255
  seenFiles.set(fileKey, file);
254
256
  return true;
255
257
  });
256
258
  let filesToAdd = multiple ? uniqueFiles : uniqueFiles.slice(0, 1);
257
- if (maxFiles !== void 0) {
258
- const currentCount = currentFiles.length;
259
- const remainingSlots = maxFiles - currentCount;
259
+ if (remainingSlots !== void 0) {
260
260
  if (remainingSlots <= 0) {
261
- filesToAdd.forEach((file) => {
262
- addRejectedFile(file, "TOO_MANY_FILES");
263
- });
264
261
  filesToAdd = [];
265
262
  } else if (filesToAdd.length > remainingSlots) {
266
263
  filesToAdd.forEach((file) => {
267
- addRejectedFile(file, "TOO_MANY_FILES");
264
+ addRejectedFile(file, FILE_UPLOAD_ERRORS.TOO_MANY_FILES);
268
265
  });
269
266
  filesToAdd = [];
270
267
  }
@@ -297,7 +294,7 @@ var FileUpload = ({
297
294
  let updatedRejectedFiles = rejectedFiles;
298
295
  if (maxFiles !== void 0 && updated.length < maxFiles) {
299
296
  updatedRejectedFiles = rejectedFiles.filter(
300
- (rejected) => !rejected.errors.includes("TOO_MANY_FILES")
297
+ (rejected) => !rejected.errors.includes(FILE_UPLOAD_ERRORS.TOO_MANY_FILES)
301
298
  );
302
299
  setRejectedFiles(updatedRejectedFiles);
303
300
  }
@@ -316,7 +313,6 @@ var FileUpload = ({
316
313
  }
317
314
  setFiles([]);
318
315
  setRejectedFiles([]);
319
- deleteButtonRefs.current = [];
320
316
  if (onFileChange) {
321
317
  onFileChange({
322
318
  acceptedFiles: [],
@@ -334,6 +330,77 @@ var FileUpload = ({
334
330
  setRejectedFiles([]);
335
331
  };
336
332
  const maxFilesReached = maxFiles !== void 0 && files.length >= maxFiles;
333
+ return {
334
+ files,
335
+ rejectedFiles,
336
+ addFiles,
337
+ removeFile,
338
+ removeRejectedFile,
339
+ clearFiles,
340
+ clearRejectedFiles,
341
+ maxFilesReached
342
+ };
343
+ }
344
+
345
+ // src/file-upload/FileUpload.tsx
346
+ var import_jsx_runtime = require("react/jsx-runtime");
347
+ var FileUploadContext = (0, import_react3.createContext)(null);
348
+ var ID_PREFIX = ":file-upload";
349
+ var FileUpload = ({
350
+ asChild: _asChild = false,
351
+ children,
352
+ defaultValue = [],
353
+ value: controlledValue,
354
+ onFileAccept,
355
+ onFileReject,
356
+ onFileChange,
357
+ multiple = true,
358
+ accept,
359
+ maxFiles,
360
+ maxFileSize,
361
+ minFileSize,
362
+ disabled: disabledProp = false,
363
+ readOnly: readOnlyProp = false,
364
+ locale
365
+ }) => {
366
+ const field = (0, import_form_field.useFormFieldControl)();
367
+ const internalId = (0, import_react3.useId)();
368
+ const inputId = field.id || `${ID_PREFIX}-${internalId}`;
369
+ const inputName = field.name;
370
+ const inputRef = (0, import_react3.useRef)(null);
371
+ const triggerRef = (0, import_react3.useRef)(null);
372
+ const dropzoneRef = (0, import_react3.useRef)(null);
373
+ const deleteButtonRefs = (0, import_react3.useRef)([]);
374
+ const disabled = field.disabled ?? disabledProp;
375
+ const readOnly = field.readOnly ?? readOnlyProp;
376
+ const {
377
+ files,
378
+ rejectedFiles,
379
+ addFiles,
380
+ removeFile,
381
+ removeRejectedFile,
382
+ clearFiles: clearFilesFromHook,
383
+ clearRejectedFiles,
384
+ maxFilesReached
385
+ } = useFileUploadState({
386
+ defaultValue,
387
+ value: controlledValue,
388
+ onFileAccept,
389
+ onFileReject,
390
+ onFileChange,
391
+ multiple,
392
+ accept,
393
+ maxFiles,
394
+ maxFileSize,
395
+ minFileSize,
396
+ disabled,
397
+ readOnly,
398
+ locale
399
+ });
400
+ const clearFiles = () => {
401
+ clearFilesFromHook();
402
+ deleteButtonRefs.current = [];
403
+ };
337
404
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
338
405
  FileUploadContext.Provider,
339
406
  {
@@ -354,10 +421,10 @@ var FileUpload = ({
354
421
  maxFilesReached,
355
422
  disabled,
356
423
  readOnly,
357
- locale: defaultLocale,
358
- description,
359
- isInvalid,
360
- isRequired
424
+ locale: locale || (typeof navigator !== "undefined" && navigator.language ? navigator.language : "en"),
425
+ description: field.description,
426
+ isInvalid: field.isInvalid,
427
+ isRequired: field.isRequired
361
428
  },
362
429
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative", children: [
363
430
  children,
@@ -373,9 +440,10 @@ var FileUpload = ({
373
440
  accept,
374
441
  disabled,
375
442
  readOnly: readOnly && !disabled,
376
- required: isRequired,
377
- "aria-invalid": isInvalid,
378
- "aria-describedby": description,
443
+ required: field.isRequired,
444
+ "aria-invalid": field.isInvalid,
445
+ "aria-describedby": field.description,
446
+ "aria-label": !field.labelId ? "Upload files" : void 0,
379
447
  className: "sr-only",
380
448
  onChange: (e) => {
381
449
  if (e.target.files && !disabled && !readOnly) {
@@ -394,7 +462,7 @@ var FileUpload = ({
394
462
  };
395
463
  FileUpload.displayName = "FileUpload";
396
464
  var useFileUploadContext = () => {
397
- const context = (0, import_react2.useContext)(FileUploadContext);
465
+ const context = (0, import_react3.useContext)(FileUploadContext);
398
466
  if (!context) {
399
467
  throw Error("useFileUploadContext must be used within a FileUpload provider");
400
468
  }
@@ -403,13 +471,14 @@ var useFileUploadContext = () => {
403
471
 
404
472
  // src/file-upload/FileUploadAcceptedFile.tsx
405
473
  var import_class_variance_authority10 = require("class-variance-authority");
474
+ var import_react11 = require("react");
406
475
 
407
476
  // src/icon/Icon.tsx
408
- var import_react4 = require("react");
477
+ var import_react5 = require("react");
409
478
 
410
479
  // src/slot/Slot.tsx
411
480
  var import_radix_ui = require("radix-ui");
412
- var import_react3 = require("react");
481
+ var import_react4 = require("react");
413
482
  var import_jsx_runtime2 = require("react/jsx-runtime");
414
483
  var Slottable = import_radix_ui.Slot.Slottable;
415
484
  var Slot = ({ ref, ...props }) => {
@@ -417,7 +486,7 @@ var Slot = ({ ref, ...props }) => {
417
486
  };
418
487
  var wrapPolymorphicSlot = (asChild, children, callback) => {
419
488
  if (!asChild) return callback(children);
420
- return (0, import_react3.isValidElement)(children) ? (0, import_react3.cloneElement)(
489
+ return (0, import_react4.isValidElement)(children) ? (0, import_react4.cloneElement)(
421
490
  children,
422
491
  void 0,
423
492
  callback(children.props.children)
@@ -495,9 +564,9 @@ var Icon = ({
495
564
  children,
496
565
  ...others
497
566
  }) => {
498
- const child = import_react4.Children.only(children);
567
+ const child = import_react5.Children.only(children);
499
568
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
500
- (0, import_react4.cloneElement)(child, {
569
+ (0, import_react5.cloneElement)(child, {
501
570
  className: iconStyles({ className, size, intent }),
502
571
  "data-spark-component": "icon",
503
572
  "aria-hidden": "true",
@@ -512,7 +581,7 @@ Icon.displayName = "Icon";
512
581
  // src/progress/Progress.tsx
513
582
  var import_class_variance_authority4 = require("class-variance-authority");
514
583
  var import_radix_ui3 = require("radix-ui");
515
- var import_react6 = require("react");
584
+ var import_react7 = require("react");
516
585
 
517
586
  // src/progress/ProgressBar.styles.ts
518
587
  var import_class_variance_authority2 = require("class-variance-authority");
@@ -529,11 +598,11 @@ var progressBarStyles = (0, import_class_variance_authority2.cva)(
529
598
  );
530
599
 
531
600
  // src/progress/ProgressContext.tsx
532
- var import_react5 = require("react");
533
- var ProgressContext = (0, import_react5.createContext)(null);
601
+ var import_react6 = require("react");
602
+ var ProgressContext = (0, import_react6.createContext)(null);
534
603
  var ID_PREFIX2 = ":progress";
535
604
  var useProgress = () => {
536
- const context = (0, import_react5.useContext)(ProgressContext);
605
+ const context = (0, import_react6.useContext)(ProgressContext);
537
606
  if (!context) {
538
607
  throw new Error("useProgress must be used within a Progress provider");
539
608
  }
@@ -584,10 +653,17 @@ var ProgressIndicator = ({
584
653
  className,
585
654
  style,
586
655
  ref,
656
+ onTransitionEnd,
587
657
  ...others
588
658
  }) => {
589
- const { value, max, intent, shape, isIndeterminate } = useProgress();
659
+ const { value, max, intent, shape, isIndeterminate, onComplete } = useProgress();
590
660
  const x = (max - value) / max * 100;
661
+ const handleTransitionEnd = (event) => {
662
+ onTransitionEnd?.(event);
663
+ if (value >= max && onComplete && !isIndeterminate) {
664
+ onComplete();
665
+ }
666
+ };
591
667
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
592
668
  import_radix_ui2.Progress.ProgressIndicator,
593
669
  {
@@ -595,6 +671,7 @@ var ProgressIndicator = ({
595
671
  className: progressIndicatorStyles({ className, intent, shape, isIndeterminate }),
596
672
  style: { ...style, ...!isIndeterminate && { transform: `translateX(-${x}%)` } },
597
673
  ref,
674
+ onTransitionEnd: handleTransitionEnd,
598
675
  ...others
599
676
  }
600
677
  );
@@ -632,14 +709,23 @@ var Progress = ({
632
709
  shape = "square",
633
710
  intent = "basic",
634
711
  isIndeterminate = false,
712
+ onComplete,
635
713
  children = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ProgressBar, {}),
636
714
  ref,
637
715
  ...others
638
716
  }) => {
639
- const [labelId, setLabelId] = (0, import_react6.useState)();
640
- const value = (0, import_react6.useMemo)(() => {
641
- return { value: valueProp ?? 0, max, intent, shape, isIndeterminate, onLabelId: setLabelId };
642
- }, [max, valueProp, intent, shape, isIndeterminate, setLabelId]);
717
+ const [labelId, setLabelId] = (0, import_react7.useState)();
718
+ const value = (0, import_react7.useMemo)(() => {
719
+ return {
720
+ value: valueProp ?? 0,
721
+ max,
722
+ intent,
723
+ shape,
724
+ isIndeterminate,
725
+ onLabelId: setLabelId,
726
+ onComplete
727
+ };
728
+ }, [max, valueProp, intent, shape, isIndeterminate, setLabelId, onComplete]);
643
729
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ProgressContext.Provider, { "data-spark-component": "progress", value, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
644
730
  import_radix_ui3.Progress.Progress,
645
731
  {
@@ -659,7 +745,7 @@ Progress.displayName = "Progress";
659
745
 
660
746
  // src/progress/ProgressLabel.tsx
661
747
  var import_use_merge_refs = require("@spark-ui/hooks/use-merge-refs");
662
- var import_react7 = require("react");
748
+ var import_react8 = require("react");
663
749
  var import_jsx_runtime8 = require("react/jsx-runtime");
664
750
  var ProgressLabel = ({
665
751
  id: idProp,
@@ -667,10 +753,10 @@ var ProgressLabel = ({
667
753
  ref: forwardedRef,
668
754
  ...others
669
755
  }) => {
670
- const internalID = `${ID_PREFIX2}-label-${(0, import_react7.useId)()}`;
756
+ const internalID = `${ID_PREFIX2}-label-${(0, import_react8.useId)()}`;
671
757
  const id = idProp || internalID;
672
758
  const { onLabelId } = useProgress();
673
- const rootRef = (0, import_react7.useCallback)(
759
+ const rootRef = (0, import_react8.useCallback)(
674
760
  (el) => {
675
761
  onLabelId(el ? id : void 0);
676
762
  },
@@ -705,11 +791,11 @@ ProgressLabel.displayName = "Progress.Label";
705
791
  // src/file-upload/FileUploadItemDeleteTrigger.tsx
706
792
  var import_Close = require("@spark-ui/icons/Close");
707
793
  var import_class_variance_authority9 = require("class-variance-authority");
708
- var import_react9 = require("react");
794
+ var import_react10 = require("react");
709
795
 
710
796
  // src/button/Button.tsx
711
797
  var import_class_variance_authority7 = require("class-variance-authority");
712
- var import_react8 = require("react");
798
+ var import_react9 = require("react");
713
799
 
714
800
  // src/spinner/Spinner.styles.tsx
715
801
  var import_internal_utils2 = require("@spark-ui/internal-utils");
@@ -1514,7 +1600,7 @@ var Button = ({
1514
1600
  }) => {
1515
1601
  const Component = asChild ? Slot : "button";
1516
1602
  const shouldNotInteract = !!disabled || isLoading;
1517
- const disabledEventHandlers = (0, import_react8.useMemo)(() => {
1603
+ const disabledEventHandlers = (0, import_react9.useMemo)(() => {
1518
1604
  const result = {};
1519
1605
  if (shouldNotInteract) {
1520
1606
  blockedEventHandlers.forEach((eventHandler) => result[eventHandler] = void 0);
@@ -1621,14 +1707,14 @@ var ItemDeleteTrigger = ({
1621
1707
  ...props
1622
1708
  }) => {
1623
1709
  const { removeFile, triggerRef, dropzoneRef, deleteButtonRefs, disabled, readOnly, files } = useFileUploadContext();
1624
- const buttonRef = (0, import_react9.useRef)(null);
1710
+ const buttonRef = (0, import_react10.useRef)(null);
1625
1711
  const fileIndex = files.findIndex((f) => f.name === file.name && f.size === file.size);
1626
1712
  const handleClick = (e) => {
1627
1713
  if (disabled || readOnly) {
1628
1714
  return;
1629
1715
  }
1630
1716
  removeFile(fileIndex);
1631
- setTimeout(() => {
1717
+ requestAnimationFrame(() => {
1632
1718
  const remainingButtons = deleteButtonRefs.current.filter(Boolean);
1633
1719
  if (remainingButtons.length > 0) {
1634
1720
  const targetIndex = Math.min(fileIndex, remainingButtons.length - 1);
@@ -1642,7 +1728,7 @@ var ItemDeleteTrigger = ({
1642
1728
  focusTarget.focus();
1643
1729
  }
1644
1730
  }
1645
- }, 0);
1731
+ });
1646
1732
  onClick?.(e);
1647
1733
  };
1648
1734
  const setRef = (node) => {
@@ -1679,7 +1765,6 @@ ItemDeleteTrigger.displayName = "FileUpload.ItemDeleteTrigger";
1679
1765
  // src/file-upload/FileUploadAcceptedFile.tsx
1680
1766
  var import_jsx_runtime13 = require("react/jsx-runtime");
1681
1767
  var AcceptedFile = ({
1682
- asChild: _asChild = false,
1683
1768
  className,
1684
1769
  file,
1685
1770
  uploadProgress,
@@ -1688,6 +1773,17 @@ var AcceptedFile = ({
1688
1773
  ...props
1689
1774
  }) => {
1690
1775
  const { locale } = useFileUploadContext();
1776
+ const [showProgress, setShowProgress] = (0, import_react11.useState)(uploadProgress !== void 0);
1777
+ (0, import_react11.useEffect)(() => {
1778
+ if (uploadProgress !== void 0) {
1779
+ setShowProgress(true);
1780
+ } else {
1781
+ setShowProgress(false);
1782
+ }
1783
+ }, [uploadProgress]);
1784
+ const handleProgressComplete = (0, import_react11.useCallback)(() => {
1785
+ setShowProgress(false);
1786
+ }, []);
1691
1787
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1692
1788
  "li",
1693
1789
  {
@@ -1700,13 +1796,19 @@ var AcceptedFile = ({
1700
1796
  ),
1701
1797
  ...props,
1702
1798
  children: [
1703
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "size-sz-40 bg-support-container flex items-center justify-center rounded-md", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: "md", children: getFileIcon(file) }) }),
1704
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "min-w-0 flex-1", children: [
1705
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gap-md flex flex-row items-center justify-between", children: [
1706
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-body-2 truncate font-medium", children: file.name }),
1707
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-caption opacity-dim-1", children: formatFileSize(file.size, locale) })
1708
- ] }),
1709
- uploadProgress !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-md", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Progress2, { value: uploadProgress, max: 100, "aria-label": progressAriaLabel }) })
1799
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "size-sz-36 bg-support-container flex items-center justify-center rounded-md", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: "md", children: getFileIcon(file) }) }),
1800
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gap-md relative flex min-w-0 flex-1 flex-row items-center justify-between self-stretch", children: [
1801
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-body-2 truncate font-medium", children: file.name }),
1802
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-caption opacity-dim-1", children: formatFileSize(file.size, locale) }),
1803
+ showProgress && uploadProgress !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute bottom-0 left-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1804
+ Progress2,
1805
+ {
1806
+ value: uploadProgress,
1807
+ max: 100,
1808
+ "aria-label": progressAriaLabel,
1809
+ onComplete: handleProgressComplete
1810
+ }
1811
+ ) })
1710
1812
  ] }),
1711
1813
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ItemDeleteTrigger, { "aria-label": deleteButtonAriaLabel, file })
1712
1814
  ]
@@ -1730,15 +1832,17 @@ Context.displayName = "FileUpload.Context";
1730
1832
 
1731
1833
  // src/file-upload/FileUploadDropzone.tsx
1732
1834
  var import_class_variance_authority11 = require("class-variance-authority");
1733
- var import_react10 = require("react");
1835
+ var import_react12 = require("react");
1734
1836
  var import_jsx_runtime15 = require("react/jsx-runtime");
1837
+ var DropzoneContext = (0, import_react12.createContext)(false);
1838
+ var useDropzoneContext = () => (0, import_react12.useContext)(DropzoneContext);
1735
1839
  function Dropzone({
1736
1840
  children,
1737
1841
  className,
1738
1842
  unstyled = false
1739
1843
  }) {
1740
1844
  const ctx = useFileUploadContext();
1741
- const dropzoneRef = (0, import_react10.useRef)(null);
1845
+ const dropzoneRef = (0, import_react12.useRef)(null);
1742
1846
  if (!ctx) throw new Error("FileUploadDropzone must be used inside <FileUpload>");
1743
1847
  const handleDrop = (e) => {
1744
1848
  e.preventDefault();
@@ -1770,7 +1874,7 @@ function Dropzone({
1770
1874
  }
1771
1875
  };
1772
1876
  const isDisabled = ctx.disabled || ctx.readOnly;
1773
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1877
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DropzoneContext.Provider, { value: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1774
1878
  "div",
1775
1879
  {
1776
1880
  ref: (node) => {
@@ -1814,26 +1918,25 @@ function Dropzone({
1814
1918
  },
1815
1919
  children
1816
1920
  }
1817
- );
1921
+ ) });
1818
1922
  }
1819
1923
  Dropzone.displayName = "FileUploadDropzone";
1820
1924
 
1821
1925
  // src/file-upload/FileUploadPreviewImage.tsx
1822
1926
  var import_class_variance_authority12 = require("class-variance-authority");
1823
- var import_react11 = require("react");
1927
+ var import_react13 = require("react");
1824
1928
  var import_jsx_runtime16 = require("react/jsx-runtime");
1825
1929
  var PreviewImage = ({
1826
- asChild: _asChild = false,
1827
1930
  className,
1828
1931
  file,
1829
1932
  fallback = "\u{1F4C4}",
1830
1933
  ...props
1831
1934
  }) => {
1832
- const [imageError, setImageError] = (0, import_react11.useState)(false);
1833
- const [imageLoaded, setImageLoaded] = (0, import_react11.useState)(false);
1935
+ const [imageError, setImageError] = (0, import_react13.useState)(false);
1936
+ const [imageLoaded, setImageLoaded] = (0, import_react13.useState)(false);
1834
1937
  const isImage = file.type.startsWith("image/");
1835
1938
  const imageUrl = isImage ? URL.createObjectURL(file) : null;
1836
- (0, import_react11.useEffect)(() => {
1939
+ (0, import_react13.useEffect)(() => {
1837
1940
  return () => {
1838
1941
  if (imageUrl) {
1839
1942
  URL.revokeObjectURL(imageUrl);
@@ -1885,7 +1988,7 @@ var import_class_variance_authority14 = require("class-variance-authority");
1885
1988
  // src/file-upload/FileUploadRejectedFileDeleteTrigger.tsx
1886
1989
  var import_Close2 = require("@spark-ui/icons/Close");
1887
1990
  var import_class_variance_authority13 = require("class-variance-authority");
1888
- var import_react12 = require("react");
1991
+ var import_react14 = require("react");
1889
1992
  var import_jsx_runtime17 = require("react/jsx-runtime");
1890
1993
  var RejectedFileDeleteTrigger = ({
1891
1994
  className,
@@ -1894,7 +1997,7 @@ var RejectedFileDeleteTrigger = ({
1894
1997
  ...props
1895
1998
  }) => {
1896
1999
  const { removeRejectedFile, triggerRef, dropzoneRef, disabled, readOnly, rejectedFiles } = useFileUploadContext();
1897
- const buttonRef = (0, import_react12.useRef)(null);
2000
+ const buttonRef = (0, import_react14.useRef)(null);
1898
2001
  const rejectedFileIndex = rejectedFiles.findIndex(
1899
2002
  (rf) => rf.file.name === rejectedFile.file.name && rf.file.size === rejectedFile.file.size
1900
2003
  );
@@ -1932,7 +2035,6 @@ RejectedFileDeleteTrigger.displayName = "FileUpload.RejectedFileDeleteTrigger";
1932
2035
  // src/file-upload/FileUploadRejectedFile.tsx
1933
2036
  var import_jsx_runtime18 = require("react/jsx-runtime");
1934
2037
  var RejectedFile = ({
1935
- asChild: _asChild = false,
1936
2038
  className,
1937
2039
  rejectedFile,
1938
2040
  renderError,
@@ -1953,7 +2055,7 @@ var RejectedFile = ({
1953
2055
  ),
1954
2056
  ...props,
1955
2057
  children: [
1956
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "size-sz-40 bg-error-container flex items-center justify-center rounded-md", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { size: "md", className: "text-error", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_WarningOutline.WarningOutline, {}) }) }),
2058
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "size-sz-36 bg-error-container flex items-center justify-center rounded-md", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { size: "md", className: "text-error", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_WarningOutline.WarningOutline, {}) }) }),
1957
2059
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "gap-md flex flex-col", children: [
1958
2060
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "gap-md flex flex-row items-center justify-between", children: [
1959
2061
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-body-2 truncate font-medium", children: rejectedFile.file.name }),
@@ -1978,10 +2080,13 @@ var Trigger = ({
1978
2080
  unstyled = false,
1979
2081
  design = "filled",
1980
2082
  intent = "basic",
2083
+ size = "md",
2084
+ shape = "rounded",
1981
2085
  ref,
1982
2086
  ...props
1983
2087
  }) => {
1984
2088
  const { inputRef, triggerRef, disabled, readOnly, description, isInvalid, isRequired } = useFileUploadContext();
2089
+ const isInsideDropzone = useDropzoneContext();
1985
2090
  const handleClick = (e) => {
1986
2091
  e.stopPropagation();
1987
2092
  e.preventDefault();
@@ -1989,26 +2094,47 @@ var Trigger = ({
1989
2094
  inputRef.current?.click();
1990
2095
  }
1991
2096
  };
1992
- const buttonComponent = unstyled ? "button" : Button;
1993
- const Comp = asChild ? Slot : buttonComponent;
1994
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1995
- Comp,
1996
- {
2097
+ const handleRef = (node) => {
2098
+ if (triggerRef) {
2099
+ triggerRef.current = node;
2100
+ }
2101
+ if (ref) {
2102
+ if (typeof ref === "function") {
2103
+ ref(node);
2104
+ } else {
2105
+ ref.current = node;
2106
+ }
2107
+ }
2108
+ };
2109
+ let Component;
2110
+ let componentProps;
2111
+ if (isInsideDropzone) {
2112
+ Component = "span";
2113
+ const spanStyles = unstyled ? className : buttonStyles({
2114
+ design,
2115
+ intent,
2116
+ size,
2117
+ shape,
2118
+ disabled: disabled || readOnly,
2119
+ className
2120
+ });
2121
+ componentProps = {
2122
+ ref: handleRef,
2123
+ "data-spark-component": "file-upload-trigger",
2124
+ className: spanStyles
2125
+ // No onClick, no role, no tabIndex - Dropzone handles interaction
2126
+ // No aria attributes here - they're on the Dropzone
2127
+ };
2128
+ } else {
2129
+ const buttonComponent = unstyled ? "button" : Button;
2130
+ Component = asChild ? Slot : buttonComponent;
2131
+ componentProps = {
2132
+ ref: handleRef,
1997
2133
  type: "button",
1998
- ref: (node) => {
1999
- if (triggerRef) {
2000
- triggerRef.current = node;
2001
- }
2002
- if (ref) {
2003
- if (typeof ref === "function") {
2004
- ref(node);
2005
- } else {
2006
- ref.current = node;
2007
- }
2008
- }
2009
- },
2010
2134
  design,
2011
2135
  intent,
2136
+ size,
2137
+ shape,
2012
2138
  "data-spark-component": "file-upload-trigger",
2013
2139
  className: (0, import_class_variance_authority15.cx)(className),
2014
2140
  disabled: disabled || readOnly,
@@ -2016,10 +2142,10 @@ var Trigger = ({
2016
2142
  "aria-describedby": description,
2017
2143
  "aria-invalid": isInvalid,
2018
2144
  "aria-required": isRequired,
2019
- ...props,
2020
- children
2021
- }
2022
- );
2145
+ ...props
2146
+ };
2147
+ }
2148
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Component, { ...componentProps, children });
2023
2149
  };
2024
2150
  Trigger.displayName = "FileUpload.Trigger";
2025
2151
 
@@ -2048,6 +2174,7 @@ RejectedFile.displayName = "FileUpload.RejectedFile";
2048
2174
  RejectedFileDeleteTrigger.displayName = "FileUpload.RejectedFileDeleteTrigger";
2049
2175
  // Annotate the CommonJS export names for ESM import in node:
2050
2176
  0 && (module.exports = {
2177
+ FILE_UPLOAD_ERRORS,
2051
2178
  FileUpload
2052
2179
  });
2053
2180
  //# sourceMappingURL=index.js.map