Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: dropzone behavior #980

Merged
merged 37 commits into from
Oct 7, 2024
Merged

fix: dropzone behavior #980

merged 37 commits into from
Oct 7, 2024

Conversation

juliusmarminge
Copy link
Collaborator

@juliusmarminge juliusmarminge commented Sep 24, 2024

closes #965

thought this was fixed in #886

Done

  • react
    • fixes file dialog opening twice when clicking the input element
  • solid
    • fixes file dialog opening twice when clicking the input element
    • unifies behavior with React components
  • vue
    • fixes file dialog opening twice when clicking the input element
    • adds abortion
  • svelte button
    • unifies behavior with React components
  • Reorganize so that things appear in the same order for each framework to ease maintenance of keeping these in-line for the future
  • svelte dropzone

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new Cancel component for improved user feedback during upload processes.
    • Enhanced UploadDropzone and UploadButton components with refined state management and event handling for better user experience.
  • Dependency Updates

    • Removed the @uploadthing/dropzone dependency from various packages.
    • Added file-selector dependency (version 0.6.0) to support file selection functionality.
  • Documentation

    • Updated TypeScript configuration references for improved clarity on Next.js integration.
  • Bug Fixes

    • Improved error handling and upload progress management, including specific feedback for aborted uploads.
    • Expanded file size limits for various file types in the upload configuration.

These updates streamline file upload processes and enhance the overall functionality of the application.

Copy link

vercel bot commented Sep 24, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
docs-uploadthing ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 1, 2024 7:20pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
legacy-docs-uploadthing ⬜️ Ignored (Inspect) Visit Preview Oct 1, 2024 7:20pm

Copy link

changeset-bot bot commented Sep 24, 2024

🦋 Changeset detected

Latest commit: 3db2694

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@uploadthing/svelte Patch
@uploadthing/react Patch
@uploadthing/solid Patch
@uploadthing/vue Patch
@uploadthing/expo Patch
@uploadthing/nuxt Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

coderabbitai bot commented Sep 24, 2024

Warning

Rate limit exceeded

@juliusmarminge has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Files that changed from the base of the PR and between 55ac13a and 3db2694.

Walkthrough

This pull request introduces significant changes across multiple files, primarily focusing on the removal of the @uploadthing/dropzone package and its associated components. Enhancements have been made to the file upload functionality within the @uploadthing/react, @uploadthing/vue, and @uploadthing/solid packages. The updates include modifications to configuration files, dependency management, and the introduction of new utility types for improved file handling and user interaction.

Changes

Files Change Summary
.gitignore Updated to include new ignore patterns for configuration files.
examples/minimal-appdir/next-env.d.ts Updated TypeScript configuration URL in comments.
package.json Updated turbo package version from 2.1.0 to canary.
packages/dropzone/... Deleted files related to the @uploadthing/dropzone package, including CHANGELOG.md, package.json, and various component files.
packages/react/package.json Removed @uploadthing/dropzone dependency; added file-selector dependency.
packages/react/src/components/button.tsx Modified event handling logic and upload state management in the UploadButton component.
packages/react/src/components/dropzone.tsx Updated UploadDropzone component for improved state management and function simplification.
packages/solid/package.json Removed @uploadthing/dropzone dependency; added file-selector dependency.
packages/solid/src/components/button.tsx Simplified upload handling logic in the UploadButton component.
packages/vue/package.json Removed @uploadthing/dropzone dependency; added file-selector dependency.
packages/vue/src/components/button.tsx Updated upload button functionality and state management.
packages/vue/src/components/dropzone.tsx Enhanced upload handling and state management in the UploadDropzone component.
tooling/eslint-config/package.json Updated eslint-config-turbo version from 2.1.0 to canary.
tooling/tsconfig/base.json Removed path mapping for @uploadthing/dropzone/*.

Assessment against linked issues

Objective Addressed Explanation
Fix multiple file uploads triggering twice (#965) The changes do not explicitly address this bug.

Possibly related PRs

Suggested reviewers

  • Mark Florkowski

🐰 In the meadow, I hop with glee,
Changes made, oh so sprightly!
Dropzones dance, files glide with ease,
A joyful leap, a gentle breeze.
Let's celebrate this code so bright,
With every upload, the future's in sight! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

github-actions bot commented Sep 24, 2024

📦 Bundle size comparison

Bundle Size (gzip) Visualization
Main 26.03KB See Treemap 📊
PR (36c15d4) 26.03KB See Treemap 📊
Diff No change

Copy link

pkg-pr-new bot commented Sep 24, 2024

Open in Stackblitz

More templates

@uploadthing/nuxt

pnpm add https://pkg.pr.new/pingdotgg/uploadthing/@uploadthing/nuxt@980

@uploadthing/react

pnpm add https://pkg.pr.new/pingdotgg/uploadthing/@uploadthing/react@980

@uploadthing/solid

pnpm add https://pkg.pr.new/pingdotgg/uploadthing/@uploadthing/solid@980

@uploadthing/svelte

pnpm add https://pkg.pr.new/pingdotgg/uploadthing/@uploadthing/svelte@980

@uploadthing/vue

pnpm add https://pkg.pr.new/pingdotgg/uploadthing/@uploadthing/vue@980

commit: 3db2694

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post

Actionable comments posted: 8

Outside diff range and nitpick comments (10)
packages/svelte/src/lib/index.ts (1)

6-7: Summary: Changes look good, ensure thorough testing

The changes to createDropzone and its type exports appear to be in line with the PR objectives. Moving to a local implementation should allow for better control over the dropzone behavior.

To ensure the effectiveness of these changes:

  1. Implement comprehensive unit and integration tests for the new createDropzone implementation, focusing on the multiple file upload scenario.
  2. Conduct end-to-end testing to verify that the issue of multiple file uploads triggering twice has been resolved.
  3. If not already done, consider adding a test case that reproduces the original issue to prevent regression in future updates.
packages/react/package.json (1)

Line range hint 1-124: Summary of package.json changes

The modifications to the dependencies in this package.json file align well with the PR's objective of fixing the dropzone behavior issue (#965). By replacing the custom @uploadthing/dropzone with the standardized file-selector library, this change potentially addresses the problem of multiple file uploads triggering twice.

However, to ensure a comprehensive fix:

  1. Verify that all components previously using @uploadthing/dropzone have been updated to use file-selector.
  2. Update the documentation to reflect these changes in the API or usage instructions.
  3. Consider adding or updating tests specifically for multiple file uploads to prevent regression.

These changes represent a significant shift in how file selection is handled. Ensure that this architectural change is consistently applied across all relevant parts of the codebase, including React, Solid, Vue, and Svelte implementations as mentioned in the PR checklist.

packages/shared/src/dropzone-utils.ts (2)

3-11: LGTM: DropzoneOptions type definition is comprehensive.

The DropzoneOptions type definition covers essential configuration options for a dropzone component, including multiple file uploads, file type acceptance, size limits, and more. The required onDrop function ensures that file uploads are always handled.

Consider adding JSDoc comments to describe each option, especially for less obvious properties like minSize and maxSize (are they in bytes?). This would improve the developer experience when using this type.

Example:

export type DropzoneOptions = {
  /** Allow multiple file uploads */
  multiple?: boolean;
  /** Accepted file types */
  accept?: AcceptProp | undefined;
  /** Minimum file size in bytes */
  minSize?: number;
  /** Maximum file size in bytes */
  maxSize?: number;
  // ... (add comments for other properties)
};

13-20: LGTM: DropzoneState type definition is comprehensive.

The DropzoneState type definition effectively captures the various states of a dropzone, including drag-and-drop interactions and the list of accepted files.

Consider adding a rejectedFiles property to the DropzoneState type. This would allow for easier handling and feedback for files that don't meet the acceptance criteria. Here's a suggested addition:

export type DropzoneState = {
  // ... existing properties
  acceptedFiles: File[];
  rejectedFiles: File[]; // Add this line
};

This addition would provide a more complete state representation and potentially simplify error handling and user feedback implementation.

packages/svelte/src/lib/component/UploadDropzone.svelte (1)

Line range hint 1-359: Consider future refactoring for improved maintainability.

While this change addresses the immediate issue, the overall complexity of this component suggests that a future refactoring effort could be beneficial. Consider breaking down this large component into smaller, more manageable sub-components.

Here are some suggestions for future improvements:

  1. Extract the dropzone logic into a separate component.
  2. Create a dedicated component for the upload button.
  3. Consider using Svelte stores for managing the upload state.
  4. Implement proper error handling and user feedback mechanisms.

These refactoring efforts could improve the maintainability and testability of the code in the long run.

packages/solid/src/components/dropzone.tsx (2)

534-535: Prevent default action in onInputElementClick

In the onInputElementClick handler, only event.stopPropagation() is called. To ensure that the default browser action doesn't occur, consider adding event.preventDefault().

Apply this diff:

 const onInputElementClick = (event: MouseEvent) => {
+  event.preventDefault();
   event.stopPropagation();
 };

540-542: Update comment to reflect SolidJS instead of React

The comment mentions React handling state changes, but since this code uses SolidJS, the comment should be updated for accuracy.

Apply this diff:

   // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
-  // to ensure React can handle state changes
+  // to ensure SolidJS can handle state changes
   // See: https://github.com/react-dropzone/react-dropzone/issues/450
packages/react/src/components/dropzone.tsx (3)

Line range hint 235-240: Avoid redundant calls to $props.onChange in handlePaste

In the handlePaste function, the onChange callback is being called twice: once inside the setFiles state updater and once immediately after. This redundancy can lead to unnecessary executions of the callback.

To prevent this, consider removing the inner call to $props.onChange inside setFiles:

setFiles((prev) => {
  filesToUpload = [...prev, ...pastedFiles];

-  $props.onChange?.(filesToUpload);

  return filesToUpload;
});

$props.onChange?.(filesToUpload);

Line range hint 229-245: Clean up dependency array in useEffect to avoid unnecessary re-renders

In the useEffect handling the paste event, including files and rootRef in the dependency array might cause unnecessary re-executions of the effect, since files is updated within the effect and rootRef is a ref which does not change.

Consider updating the dependency array:

- }, [uploadFiles, $props, appendOnPaste, mode, fileTypes, rootRef, files]);
+ }, [uploadFiles, $props, appendOnPaste, mode, fileTypes]);

Line range hint 217-226: Ensure consistent prevention of default behavior in onUploadClick

In the onUploadClick handler, e.preventDefault() and e.stopPropagation() are called in multiple branches. To maintain consistency and prevent unintended side effects, consider structuring the function to handle these calls uniformly.

Review and refactor the onUploadClick function to ensure that default behaviors are prevented only when necessary, and that the code is clear and maintainable.

Comments failed to post (8)
packages/svelte/src/lib/index.ts (1)

6-6: 💡 Codebase verification

Missing createDropzone implementation in React, Solid, and Vue frameworks.

The create-dropzone.ts file was only found in the Svelte package. Please ensure that similar implementations are added for React, Solid, and Vue frameworks as outlined in the PR checklist.

Analysis chain

LGTM! Verify the new implementation and check other frameworks.

The change from an external package to a local implementation for createDropzone looks good. This is likely part of the fix for the dropzone behavior issue.

Please ensure that:

  1. The local implementation in ./component/create-dropzone addresses the issue of multiple file uploads triggering twice.
  2. This change is consistent with the fix implemented for the React framework.
  3. Similar changes are made for Solid and Vue frameworks, as mentioned in the PR checklist.

Run the following script to verify the implementation across frameworks:

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for createDropzone implementation across frameworks

# Check for local implementation in Svelte
echo "Checking Svelte implementation:"
cat packages/svelte/src/lib/component/create-dropzone.ts

# Check for similar changes in React
echo "Checking React implementation:"
cat packages/react/src/component/create-dropzone.ts

# Check for Solid implementation
echo "Checking Solid implementation:"
cat packages/solid/src/component/create-dropzone.ts

# Check for Vue implementation
echo "Checking Vue implementation:"
cat packages/vue/src/component/create-dropzone.ts

Length of output: 1340


Script:

#!/bin/bash
# Description: Search for create-dropzone.ts implementations across the entire repository

echo "Searching for create-dropzone.ts files in the repository:"
fd create-dropzone.ts

Length of output: 201

packages/react/src/index.ts (1)

14-15: 💡 Codebase verification

Error: useDropzone is not exported from the local module

The local module ./components/dropzone does not export useDropzone as expected.

  • Ensure that useDropzone is correctly implemented and exported in dropzone.tsx.
Analysis chain

LGTM! Verify local implementation and update documentation.

The change to export useDropzone and its types from a local module aligns with the PR objective of fixing the dropzone behavior. This should allow for better control over the functionality and potentially resolve the issue with multiple file uploads triggering twice.

Please run the following script to verify the local implementation:

Consider updating the package documentation to reflect this change in implementation. This will help users understand any potential differences in behavior or available properties compared to the previous external package implementation.


Please run the following revised script to verify the local implementation:

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the local implementation of useDropzone

# Test 1: Check if the local module exists
if [ ! -f "./packages/react/src/components/dropzone.ts" ] && [ ! -f "./packages/react/src/components/dropzone.tsx" ]; then
    echo "Error: Local module './components/dropzone' not found"
    exit 1
fi

# Test 2: Check if useDropzone is exported from the local module
rg --type typescript "export.*useDropzone" ./packages/react/src/components/dropzone.ts* || echo "Error: useDropzone not exported from local module"

# Test 3: Check for type exports in the local module
rg --type typescript "export.*type" ./packages/react/src/components/dropzone.ts* || echo "Warning: No type exports found in local module"

Length of output: 577


Script:

#!/bin/bash
# Description: Verify the local implementation of useDropzone

# Test 1: Check if the local module exists
if [ ! -f "./packages/react/src/components/dropzone.ts" ] && [ ! -f "./packages/react/src/components/dropzone.tsx" ]; then
    echo "Error: Local module './components/dropzone' not found"
    exit 1
fi

# Test 2: Check if useDropzone is exported from the local module
rg "export\s+\{?\s*useDropzone\s*\}?" ./packages/react/src/components/dropzone.ts* || echo "Error: useDropzone not exported from local module"

# Test 3: Check for type exports in the local module
rg "export\s+type\s+" ./packages/react/src/components/dropzone.ts* || echo "Warning: No type exports found in local module"

Length of output: 442

packages/solid/src/components/dropzone.tsx (2)

470-491: 🛠️ Refactor suggestion

Provide feedback for rejected files

In the setFiles function, files that are rejected due to type, size, or quantity limits are silently discarded. Providing feedback to the user about rejected files and the reasons can enhance user experience.

Consider modifying the function to collect rejected files and inform the user accordingly.


539-544: ⚠️ Potential issue

Simplify onClick handler and update comment to reflect SolidJS

The onClick handler is unnecessarily wrapped in an extra function, and the comment refers to React instead of SolidJS. Simplifying the handler improves readability, and updating the comment ensures consistency with the framework in use.

Apply this diff to fix the issue:

-const onClick = () => () => {
-  // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
-  // to ensure React can handle state changes
-  // See: https://github.com/react-dropzone/react-dropzone/issues/450
-  isIeOrEdge() ? setTimeout(openFileDialog, 0) : openFileDialog();
-};
+const onClick = () => {
+  // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
+  // to ensure SolidJS can handle state changes
+  // See: https://github.com/react-dropzone/react-dropzone/issues/450
+  isIeOrEdge() ? setTimeout(openFileDialog, 0) : openFileDialog();
+};
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  const onClick = () => {
    // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
    // to ensure SolidJS can handle state changes
    // See: https://github.com/react-dropzone/react-dropzone/issues/450
    isIeOrEdge() ? setTimeout(openFileDialog, 0) : openFileDialog();
  };
packages/vue/src/components/dropzone.tsx (2)

664-676: ⚠️ Potential issue

Correct the usage of satisfies within object literals

The use of the satisfies operator within object literals that are immediately spread may not correctly enforce the types as intended. The satisfies operator is used during type checking but does not affect the runtime value. When spreading objects, the type information may not be preserved as you expect.

To ensure type safety and proper typing, consider assigning the object to a variable with the appropriate type assertion before spreading it.

Apply this diff to fix the issue in getRootProps:

 const getRootProps = (): HTMLAttributes & ReservedProps => ({
   ref: rootRef,
   role: "presentation" as const,
   ...(!optionsRef.value.disabled
     ? {
-        tabindex: 0,
-        onKeydown,
-        onFocus,
-        onBlur,
-        onClick,
-        onDragenter,
-        onDragover,
-        onDragleave,
-        onDrop,
-      } satisfies HTMLAttributes & ReservedProps
+        ...({
+          tabindex: 0,
+          onKeydown,
+          onFocus,
+          onBlur,
+          onClick,
+          onDragenter,
+          onDragover,
+          onDragleave,
+          onDrop,
+        } as HTMLAttributes & ReservedProps),
     : {}),
 });

And in getInputProps:

 const getInputProps = (): InputHTMLAttributes & ReservedProps => ({
   ref: inputRef,
   type: "file",
   style: "display: none",
   accept: acceptAttr.value ?? "", // exactOptionalPropertyTypes: true
   multiple: optionsRef.value.multiple,
   tabindex: -1,
   ...(!optionsRef.value.disabled
     ? {
-        onChange: onDrop,
-        onClick: onInputElementClick,
-      } satisfies InputHTMLAttributes & ReservedProps
+        ...({
+          onChange: onDrop,
+          onClick: onInputElementClick,
+        } as InputHTMLAttributes & ReservedProps),
     : {}),
 });

Also applies to: 686-692


652-653: ⚠️ Potential issue

Avoid assignments within arrow function return expressions

The assignments within the arrow functions onFocus and onBlur can be confusing, as they are performed within the return expression. Expressions are often considered side-effect free, so this pattern may reduce code readability. To improve clarity, consider using a block body for the arrow functions.

Apply this diff to fix the issue:

-const onFocus = () => (state.isFocused = true);
-const onBlur = () => (state.isFocused = false);
+const onFocus = () => {
+  state.isFocused = true;
+};
+const onBlur = () => {
+  state.isFocused = false;
+};
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  const onFocus = () => {
    state.isFocused = true;
  };
  const onBlur = () => {
    state.isFocused = false;
  };
Tools
Biome

[error] 652-652: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 653-653: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

packages/react/src/components/dropzone.tsx (2)

494-495: 🛠️ Refactor suggestion

Remove unnecessary event.persist() calls

The event.persist() method is no longer necessary in modern versions of React (17+), as Synthetic Events are not pooled. These calls can be safely removed to simplify the code.

Apply the following diffs to remove the unnecessary event.persist() calls:

// In onDragEnter handler
- event.persist();

// In onDragOver handler
- event.persist();

// In onDragLeave handler
- event.persist();

// In onDropCb handler
- event.persist();

Also applies to: 532-533, 549-550, 605-606


658-661: 🛠️ Refactor suggestion

Evaluate the necessity of IE11/Edge-specific handling in onClick

The onClick handler uses isIeOrEdge() to handle specific behavior for legacy browsers. Given that Internet Explorer 11 is no longer supported and Edge has transitioned to Chromium, this compatibility code may be unnecessary.

Consider removing the IE11/Edge-specific code to simplify the onClick function:

const onClick = useCallback(() => {
-  isIeOrEdge() ? setTimeout(openFileDialog, 0) : openFileDialog();
+  openFileDialog();
}, [openFileDialog]);
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  const onClick = useCallback(() => {
    openFileDialog();
  }, [openFileDialog]);

@vercel vercel bot temporarily deployed to Preview – legacy-docs-uploadthing September 30, 2024 19:12 Inactive
@vercel vercel bot temporarily deployed to Preview – legacy-docs-uploadthing September 30, 2024 19:13 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
packages/svelte/src/lib/component/UploadDropzone.svelte (3)

105-107: Approved: Improved upload handling and error management

The changes to the uploadFiles function enhance its functionality:

  1. Removing the await keyword allows for non-blocking asynchronous uploads.
  2. The added error handling for UploadAbortedError improves the robustness of the upload process.

These modifications align well with the PR objectives to fix dropzone behavior.

Consider adding a generic error handler to log unexpected errors:

 const uploadFiles = (files: File[]) => {
   const input = "input" in uploader ? uploader.input : undefined;
   startUpload(files, input).catch((e) => {
     if (e instanceof UploadAbortedError) {
       void uploader.onUploadAborted?.();
     } else {
+      console.error('Unexpected error during upload:', e);
       throw e;
     }
   });
 };

143-156: Approved: New onUploadClick function improves upload control

The new onUploadClick function significantly improves the control over the upload process:

  1. It handles different states (uploading, manual mode with files) appropriately.
  2. The function includes logic to abort ongoing uploads and start new ones, addressing the issue of multiple file uploads triggering twice.
  3. The abort functionality aligns well with the PR objectives.

These changes enhance the overall user experience and fix the reported bug.

Consider adding a debounce mechanism to prevent rapid successive clicks:

+ import { debounce } from 'lodash-es';

- const onUploadClick = (e: MouseEvent) => {
+ const onUploadClick = debounce((e: MouseEvent) => {
   // ... existing function body ...
- };
+ }, 300);

This will help prevent unintended multiple uploads if the user clicks rapidly.


232-233: Approved: Enhanced visual feedback and state handling

The changes to the component's markup significantly improve the user experience and align with the PR objectives:

  1. Updated class bindings for the label provide better visual cues based on the component's state.
  2. Modified button classes and disabled state handling improve the dropzone behavior.
  3. The button content now reflects different states (readying, uploading, manual mode), providing clearer feedback to the user during the upload process.

These changes enhance the overall usability and visual consistency of the component.

Consider adding an aria-label to the button to improve accessibility:

 <button
   class={cn(
     // ... existing classes ...
   )}
   style={styleFieldToClassName(appearance?.button, styleFieldArg)}
   on:click={onUploadClick}
   data-ut-element="button"
   data-state={state}
   type="button"
   disabled={files.length === 0 || state === "disabled"}
+  aria-label={state === "uploading" ? "Cancel upload" : "Upload files"}
 >
   <!-- ... button content ... -->
 </button>

This will provide better context for screen reader users.

Also applies to: 262-268, 272-272, 275-276, 279-287

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 5271203 and 55ac13a.

📒 Files selected for processing (2)
  • packages/svelte/src/lib/component/UploadDropzone.svelte (8 hunks)
  • packages/svelte/src/lib/component/create-dropzone.ts (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/svelte/src/lib/component/create-dropzone.ts
🔇 Additional comments (4)
packages/svelte/src/lib/component/UploadDropzone.svelte (4)

31-32: Approved: Simplified component API and updated import

The changes to the import statements and component props appear to streamline the component's external API. The removal of internal state properties (__internal_state, __internal_upload_progress, __internal_ready) and the use of routeConfig instead of permittedFileInfo suggest an improvement in the underlying logic for handling file types and permissions.

These changes may impact how the component is used in parent components, so ensure that any existing usage is updated accordingly.

Also applies to: 70-76, 85-89


123-123: Approved: Simplified drop callback and immediate upload in auto mode

The changes to the onDropCallback function and the subsequent logic improve the component's behavior:

  1. The function has been simplified, making it easier to understand and maintain.
  2. In "auto" mode, the upload is now triggered immediately after files are dropped, which enhances the user experience.

These modifications align well with the PR objectives to fix dropzone behavior and improve the overall functionality of the component.

Also applies to: 126-127


158-178: Approved: Improved paste handling and lifecycle management

The changes to the onMount lifecycle hook enhance the component's efficiency and resource management:

  1. The conditional return based on appendOnPaste prevents unnecessary event listener setup, improving performance.
  2. Encapsulating paste event handling within onMount ensures proper cleanup on component unmount, preventing potential memory leaks.
  3. The paste handling logic aligns with the PR objectives by providing better control over file uploads.

These modifications contribute to a more robust and efficient component.


Line range hint 1-296: Summary: Significant improvements to UploadDropzone component

This PR introduces several important enhancements to the UploadDropzone component:

  1. Simplified component API by removing internal state properties.
  2. Improved upload handling with better error management.
  3. Enhanced dropzone behavior, particularly in auto and manual modes.
  4. Added abort functionality for ongoing uploads.
  5. Optimized paste handling and lifecycle management.
  6. Improved visual feedback and state handling in the component's markup.

These changes effectively address the reported issues with multiple file uploads and align well with the PR objectives. The component now provides a more robust and user-friendly experience for file uploads.

A few minor suggestions have been made to further improve error handling, prevent rapid successive clicks, and enhance accessibility. Consider implementing these suggestions to further refine the component.

Overall, this is a high-quality update that significantly improves the UploadDropzone component.

@vercel vercel bot temporarily deployed to Preview – legacy-docs-uploadthing October 1, 2024 18:54 Inactive
Copy link
Member

@t3dotgg t3dotgg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, ty for the grind getting all frameworks to behave

@@ -221,7 +237,7 @@ export function UploadButton<
return "Loading...";
}
case "uploading": {
if (uploadProgress === 100) return <Spinner />;
if (uploadProgress >= 100) return <Spinner />;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can this go over 100 lol

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha idk. Math is hard. Probably a bug in here somewhere but felt out of scope so this was a quick fix to get the UI to behave. Will look at the progress calculation later

https://github.com/pingdotgg/uploadthing/blob/main/packages/react/src/useUploadThing.ts#L84-L97
https://github.com/pingdotgg/uploadthing/blob/main/packages/uploadthing/src/internal/upload.browser.ts#L157-L168

@juliusmarminge juliusmarminge merged commit e53bc01 into main Oct 7, 2024
19 checks passed
@AlemTuzlak
Copy link
Contributor

Thanks for the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[bug]: Multiple file uploads seem to trigger twice
3 participants