Skip to content

Conversation

@nd0ut
Copy link
Member

@nd0ut nd0ut commented Oct 24, 2025

Description

Checklist

Summary by CodeRabbit

  • New Features

    • Added Storybook demo with an uploader example.
  • Bug Fixes / Improvements

    • Improved uploader modal-close handling to avoid resets when other modals are active.
  • Updates

    • Upgraded example frameworks: Angular → 20.x, React → 19.2.0, Next → 16.0.0.
    • Updated uploader examples to v1.24.3.
    • Added ESLint configs across examples.
  • Documentation

    • Updated README files for Next.js example projects.
  • Chores

    • Adjusted .gitignore entries and devcontainer configs.

@coderabbitai
Copy link

coderabbitai bot commented Oct 24, 2025

Walkthrough

Updates across example projects: dependency bumps (Next.js 14→16, React 18→19, Angular packages to 20.x, @uploadcare/file-uploader to 1.24.3), TypeScript ref-type simplifications, new/rewritten Next.js configs and READMEs, a new Storybook example, added ESLint configs, and added guards to modal-close handlers that prevent state reset when active modals exist.

Changes

Cohort / File(s) Summary
Root/gitignore
/.gitignore
Added Storybook ignore patterns (*storybook.log, storybook-static)
Angular example
examples/angular-uploader/package.json, examples/angular-uploader/tsconfig.json, examples/angular-uploader/src/app/components/file-uploader/file-uploader.component.ts, examples/angular-uploader/src/app/views/*/*
Upgraded Angular and supporting libs to 20.x, changed tsconfig.moduleResolution to bundler, refined ViewChild/ElementRef typings and adjusted modal-close handler signature/guard and uploadedFiles clearing; minor mock formatting changes
JS/React/Svelte/Vue example deps
examples/js-custom-tab/package.json, examples/js-uploader/package.json, examples/react-uploader/package.json, examples/svelte-uploader/package.json, examples/vue-uploader/package.json, examples/react-uploader-adapter/package.json
Bumped @uploadcare/file-uploader to 1.24.3 (and react-adapter to ^1.11.0 where applicable)
React example typing & components
examples/react-uploader/src/components/FileUploader/FileUploader.tsx, examples/react-uploader/src/views/*/*, examples/react-uploader-adapter/src/components/FileUploader/FileUploader.tsx
Normalized quote style, tightened generic/type usages (e.g., OutputFileEntry<"success">), removed InstanceType wrappers for UploadCtxProvider/Config types, adjusted event typings and optional API calls
Modal-close guards (multi-framework)
examples/svelte-uploader/src/lib/.../FileUploader.svelte, examples/vue-uploader/src/components/FileUploader/FileUploader.*.vue, examples/angular-uploader/.../file-uploader.component.ts
Changed handleModalCloseEvent to accept event parameter and early-return when e.detail.hasActiveModals is true to avoid resetting state while modals are active
Next.js projects — root changes
examples/next-uploader/package.json, examples/next-uploader/tsconfig.json, examples/next-uploader/src/pages/*, examples/next-uploader/next.config.ts, examples/next-uploader/.devcontainer/*
Upgraded Next/React to 16.0.0/19.2.0, added lint script, added TypeScript tsconfig and turbopack root in next.config.ts, added _app.jsx importing uploader CSS, removed devcontainer
Next-uploader-adapter (nested app)
examples/next-uploader-adapter/package.json, examples/next-uploader-adapter/tsconfig.json, examples/next-uploader-adapter/next.config.ts, examples/next-uploader-adapter/src/pages/*, examples/next-uploader-adapter/next-uploader/**, examples/next-uploader-adapter/.gitignore, examples/next-uploader-adapter/README.md
Migrated to Next 16/React 19, added tsconfig and next.config.ts (transpilePackages/turbopack), reworked README, added nested next-uploader project (README, tsconfig, next.config.ts, eslint, .gitignore), and replaced .gitignore contents; removed old JS next.config and devcontainer
ESLint configs
examples/next-uploader/eslint.config.mjs, examples/next-uploader-adapter/eslint.config.mjs, examples/next-uploader-adapter/next-uploader/eslint.config.mjs, examples/react-uploader/tsconfig.json, examples/react-uploader-adapter/tsconfig.json
New ESLint configuration modules composing Next.js/TypeScript presets and overriding globalIgnores; some tsconfig moduleResolution changes to bundler
Storybook example
examples/storybook/package.json, examples/storybook/tsconfig.json, examples/storybook/.storybook/main.js, examples/storybook/.storybook/preview.js, examples/storybook/.storybook/tsconfig.json, examples/storybook/stories/Demo.stories.tsx, examples/storybook/types/*
New Storybook project (html-vite) with custom JSX runtime pragma, TypeScript declarations for JSX/react-jsx-runtime, story demonstrating uploader components, and Storybook scripts/deps
Formatting & docs
examples/next-uploader/README.md, examples/next-uploader-adapter/README.md, examples/next-uploader-adapter/next-uploader/README.md, various JSX/JS files under examples/*/src/pages
Rewritten READMEs to Next.js starter style, normalized quoting and formatting in multiple example pages, and adjusted imports to @uploadcare/react-uploader/next where applicable

Sequence Diagram(s)

sequenceDiagram
    participant Modal as Modal
    participant Component as Uploader Component
    participant State as Internal State

    Note over Modal,Component: modal-close event fired
    Modal->>Component: 'modal-close' (with e.detail.hasActiveModals)
    alt e.detail.hasActiveModals == true
        Component->>Component: return early (no reset, no emit)
        Note over Component: active modal(s) present — skip reset
    else e.detail.hasActiveModals == false
        Component->>State: resetUploaderState()
        State->>Component: state cleared
        Component->>State: emit merged files
        Component->>State: uploadedFiles = []
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Areas needing extra attention:
    • Type refinements removing InstanceType<...> across multiple frameworks (ensure runtime/ref usage unaffected).
    • Modal-close guard changes in Angular/Vue/Svelte/React — verify event shape (e.detail.hasActiveModals) consistency and lifecycle interactions.
    • New Storybook setup (custom JSX pragma and type declarations) — ensure build/test of storybook pipeline.
    • Next.js config and dependency upgrades (Next 16 / React 19 / turbopack settings) — check compatibility of example imports and transpilePackages entries.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Chore/bump-uploader' is vague and uses a branch-naming convention rather than describing the actual changes. It doesn't clearly convey what was bumped or updated. Use a more descriptive title that summarizes the main changes, such as 'Chore: Update uploader dependencies and migrate to TypeScript bundler module resolution' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/bump-uploader

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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: 7

🧹 Nitpick comments (14)
examples/react-uploader/src/components/FileUploader/FileUploader.tsx (1)

112-113: Consider adding null safety to API access.

The code accesses ctxProviderRef.current.getAPI() without null checking. While the outer useEffect guards against null at line 99, adding optional chaining would be more defensive and prevent potential runtime errors if the ref is cleared between the check and this call.

Consider this defensive pattern:

 const resetUploaderState = () => {
-  const api = ctxProviderRef.current.getAPI();
+  const api = ctxProviderRef.current?.getAPI();
+  if (!api) return;
   api.removeAllFiles();
 };
examples/svelte-uploader/src/lib/FileUploader/FileUploader.svelte (1)

40-43: Optional: Add defensive access and clarifying comment for the modal guard.

The hasActiveModals property is valid for the modal-close event in @uploadcare/file-uploader 1.24.0-alpha.2, so the guard logic is correct. For better defensive coding and clarity, consider using optional chaining and an explanatory comment:

  const handleModalCloseEvent = (e) => {
+   // Don't reset state if there are still active modals open
-   if (e.detail.hasActiveModals) {
+   if (e?.detail?.hasActiveModals) {
      return;
    }
examples/next-uploader-adapter/next-uploader/eslint.config.mjs (2)

5-16: Deduplicate identical configs across examples via a shared module.

Both Next examples appear to carry the same config. Centralize once to reduce copy/paste.

Example:

  1. Create examples/shared/eslint-next-flat.mjs:
import { defineConfig } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";

export default defineConfig([ ...nextVitals, ...nextTs ]);
  1. Replace this file with:
-import { defineConfig, globalIgnores } from "eslint/config";
-import nextVitals from "eslint-config-next/core-web-vitals";
-import nextTs from "eslint-config-next/typescript";
-
-const eslintConfig = defineConfig([
-  ...nextVitals,
-  ...nextTs,
-]);
-
-export default eslintConfig;
+import sharedNextConfig from "../../shared/eslint-next-flat.mjs";
+export default sharedNextConfig;

1-3: Version compatibility confirmed; remove redundant globalIgnores and centralize duplicate configs.

ESLint ^9 + eslint-config-next 16.0.0 support flat config correctly. However:

  1. globalIgnores duplication: The block repeats upstream defaults (.next/**, out/**, build/**, next-env.d.ts) already provided by eslint-config-next. Remove this block unless adding new patterns beyond defaults.

  2. Config duplication: All three eslint.config.mjs files are identical. Consolidate into a shared config module to avoid drift and maintenance overhead.

Suggested action:

  • Remove the globalIgnores([...]) block (lines 8–15) to rely on eslint-config-next defaults, OR
  • Keep only if adding custom patterns (e.g., storybook-static, coverage).
  • Centralize the config to a single shared file or utility export.
examples/next-uploader/eslint.config.mjs (1)

5-16: Consider extracting the shared ESLint configuration.

This exact configuration pattern is duplicated in three files:

  • examples/next-uploader/eslint.config.mjs
  • examples/next-uploader-adapter/eslint.config.mjs
  • examples/next-uploader-adapter/next-uploader/eslint.config.mjs

Consider creating a shared ESLint config at the repository root to reduce duplication:

// eslint.config.shared.mjs (at root)
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";

export default defineConfig([
  ...nextVitals,
  ...nextTs,
  globalIgnores([
    ".next/**",
    "out/**",
    "build/**",
    "next-env.d.ts",
  ]),
]);

Then import it in each example:

// examples/*/eslint.config.mjs
export { default } from "../../eslint.config.shared.mjs";
examples/storybook/package.json (2)

1-5: Add engines to lock Node runtime.

Storybook 9 + ESM configs benefit from a consistent Node version. Recommend declaring engines.

 {
   "name": "storybook",
   "version": "0.1.0",
   "private": true,
   "type": "module",
+  "engines": { "node": ">=18.18 || >=20" },

10-13: Pin devDependencies to avoid accidental minor/patch drift during example runs.

Examples are teaching artifacts; deterministic installs help.

   "devDependencies": {
-    "@storybook/html-vite": "^9.1.3",
-    "storybook": "^9.1.3"
+    "@storybook/html-vite": "9.1.3",
+    "storybook": "9.1.3"
   },
examples/storybook/.storybook/preview.js (1)

1-13: Register uploader web components once in preview to avoid re-definitions.

Move registration and CSS import here; guard against double-define. This prevents HMR errors like “already defined”.

 /** @type { import('@storybook/html-vite').Preview } */
 const preview = {
   parameters: {
     controls: {
       matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
       },
     },
   },
 };
 
 export default preview;
+
+// Uploader components registration (run once for all stories)
+import * as UC from "@uploadcare/file-uploader";
+import "@uploadcare/file-uploader/web/uc-file-uploader-regular.min.css";
+if (!customElements.get("uc-config")) {
+  UC.defineComponents(UC);
+}

Changes outside this file to complete the move (Demo.stories.tsx):

- import * as UC from "@uploadcare/file-uploader";
- import '@uploadcare/file-uploader/web/uc-file-uploader-regular.min.css'
- UC.defineComponents(UC);
+ // Components are registered globally in .storybook/preview.js
examples/storybook/types/react-jsx-runtime.d.ts (1)

1-6: Likely unnecessary with classic JSX; consider removing to reduce ambient type noise.

Your TS config uses classic JSX (jsx: "react" with jsxFactory "__h"). The react/jsx-runtime shim may be redundant.

  • Remove this file and drop it from "types" in tsconfig if builds still pass.

If it’s needed for a specific tool, scope it only to this project via tsconfig “types” (already done) and add a brief comment explaining why.

examples/storybook/tsconfig.json (2)

6-13: Prune react-jsx-runtime from types; classic JSX doesn’t need it.

This keeps the program surface smaller and avoids accidental React type bleed.

   // Use classic JSX factory names to avoid react/jsx-runtime requirements
   "jsx": "react",
   "jsxFactory": "__h",
   "jsxFragmentFactory": "Fragment",
   "types": [
-      "./types/jsx",
-      "./types/react-jsx-runtime"
+      "./types/jsx"
   ],

14-18: allowJs not needed if only TS in includes.

You only include ./stories and ./types (both TS). Safe to drop.

-    "allowJs": true,
-    "checkJs": false,
+    "checkJs": false,
examples/storybook/.storybook/main.js (2)

14-18: Enable essentials addon for docs/controls/actions out of the box.

Improves UX with minimal cost; add as devDependency if not present.

-  addons: [],
+  addons: ["@storybook/addon-essentials"],

20-77: Consider extracting the injected JSX runtime to a module for readability and reuse.

Moving the long jsxInject string into a file (e.g., .storybook/jsx-runtime.js) and importing it keeps config tidy and enables unit tests on the runtime.

  • Create .storybook/jsx-runtime.js exporting { __h, Fragment }.
  • Replace jsxInject with: import { __h, Fragment } from "/.storybook/jsx-runtime.js";
  • Keep esbuild.jsxFactory="__h" and esbuild.jsxFragment="Fragment".
examples/storybook/stories/Demo.stories.tsx (1)

1-4: Avoid registering custom elements per story; do it once in preview.

Prevents “custom element already defined” during HMR.

-import * as UC from "@uploadcare/file-uploader";
-import '@uploadcare/file-uploader/web/uc-file-uploader-regular.min.css'
-UC.defineComponents(UC);
+// Components and CSS are registered globally in .storybook/preview.js

If registration must stay local, guard each element:

for (const tag of ["uc-config","uc-file-uploader-regular","uc-upload-ctx-provider"]) {
  if (!customElements.get(tag)) {
    // @ts-ignore defineComponents registers all tags; this is a safety net
    UC.defineComponents(UC);
    break;
  }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between af8d63f and b0b72f5.

⛔ Files ignored due to path filters (12)
  • examples/angular-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/js-custom-tab/package-lock.json is excluded by !**/package-lock.json
  • examples/js-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/js-uploader/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • examples/next-uploader-adapter/package-lock.json is excluded by !**/package-lock.json
  • examples/next-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/react-uploader-adapter/package-lock.json is excluded by !**/package-lock.json
  • examples/react-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/storybook/package-lock.json is excluded by !**/package-lock.json
  • examples/svelte-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/vue-uploader/package-lock.json is excluded by !**/package-lock.json
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (53)
  • .gitignore (1 hunks)
  • examples/angular-uploader/package.json (1 hunks)
  • examples/angular-uploader/src/app/components/file-uploader/file-uploader.component.ts (5 hunks)
  • examples/angular-uploader/src/app/views/form-view/mocks.ts (8 hunks)
  • examples/angular-uploader/src/app/views/minimal-view/minimal-view.component.ts (1 hunks)
  • examples/angular-uploader/src/app/views/regular-view/regular-view.component.ts (1 hunks)
  • examples/angular-uploader/tsconfig.json (1 hunks)
  • examples/js-custom-tab/package.json (1 hunks)
  • examples/js-uploader/package.json (1 hunks)
  • examples/next-uploader-adapter/.devcontainer/devcontainer.json (0 hunks)
  • examples/next-uploader-adapter/.gitignore (1 hunks)
  • examples/next-uploader-adapter/README.md (1 hunks)
  • examples/next-uploader-adapter/eslint.config.mjs (1 hunks)
  • examples/next-uploader-adapter/next-uploader/.gitignore (1 hunks)
  • examples/next-uploader-adapter/next-uploader/README.md (1 hunks)
  • examples/next-uploader-adapter/next-uploader/eslint.config.mjs (1 hunks)
  • examples/next-uploader-adapter/next-uploader/next.config.ts (1 hunks)
  • examples/next-uploader-adapter/next.config.js (0 hunks)
  • examples/next-uploader-adapter/next.config.ts (1 hunks)
  • examples/next-uploader-adapter/package.json (1 hunks)
  • examples/next-uploader-adapter/src/pages/_app.jsx (1 hunks)
  • examples/next-uploader-adapter/src/pages/minimal.jsx (1 hunks)
  • examples/next-uploader-adapter/src/pages/regular.jsx (1 hunks)
  • examples/next-uploader-adapter/tsconfig.json (1 hunks)
  • examples/next-uploader/.devcontainer/devcontainer.json (0 hunks)
  • examples/next-uploader/.gitignore (1 hunks)
  • examples/next-uploader/README.md (1 hunks)
  • examples/next-uploader/eslint.config.mjs (1 hunks)
  • examples/next-uploader/next.config.js (0 hunks)
  • examples/next-uploader/next.config.ts (1 hunks)
  • examples/next-uploader/package.json (1 hunks)
  • examples/next-uploader/src/pages/_app.jsx (1 hunks)
  • examples/next-uploader/src/pages/minimal.jsx (5 hunks)
  • examples/next-uploader/src/pages/regular.jsx (5 hunks)
  • examples/next-uploader/tsconfig.json (1 hunks)
  • examples/react-uploader-adapter/src/components/FileUploader/FileUploader.tsx (1 hunks)
  • examples/react-uploader/package.json (1 hunks)
  • examples/react-uploader/src/components/FileUploader/FileUploader.tsx (7 hunks)
  • examples/react-uploader/src/views/MinimalView/MinimalView.tsx (1 hunks)
  • examples/react-uploader/src/views/RegularView/RegularView.tsx (1 hunks)
  • examples/storybook/.storybook/main.js (1 hunks)
  • examples/storybook/.storybook/preview.js (1 hunks)
  • examples/storybook/.storybook/tsconfig.json (1 hunks)
  • examples/storybook/package.json (1 hunks)
  • examples/storybook/stories/Demo.stories.tsx (1 hunks)
  • examples/storybook/tsconfig.json (1 hunks)
  • examples/storybook/types/jsx.d.ts (1 hunks)
  • examples/storybook/types/react-jsx-runtime.d.ts (1 hunks)
  • examples/svelte-uploader/package.json (1 hunks)
  • examples/svelte-uploader/src/lib/FileUploader/FileUploader.svelte (1 hunks)
  • examples/vue-uploader/package.json (1 hunks)
  • examples/vue-uploader/src/components/FileUploader/FileUploader.composition.vue (1 hunks)
  • examples/vue-uploader/src/components/FileUploader/FileUploader.options.vue (1 hunks)
💤 Files with no reviewable changes (4)
  • examples/next-uploader-adapter/next.config.js
  • examples/next-uploader-adapter/.devcontainer/devcontainer.json
  • examples/next-uploader/.devcontainer/devcontainer.json
  • examples/next-uploader/next.config.js
🧰 Additional context used
🧬 Code graph analysis (8)
examples/next-uploader/eslint.config.mjs (2)
examples/next-uploader-adapter/eslint.config.mjs (1)
  • eslintConfig (5-16)
examples/next-uploader-adapter/next-uploader/eslint.config.mjs (1)
  • eslintConfig (5-16)
examples/next-uploader-adapter/src/pages/_app.jsx (1)
examples/next-uploader/src/pages/_app.jsx (1)
  • App (3-5)
examples/next-uploader/src/pages/_app.jsx (1)
examples/next-uploader-adapter/src/pages/_app.jsx (1)
  • App (3-5)
examples/next-uploader/src/pages/regular.jsx (3)
examples/next-uploader/src/pages/minimal.jsx (3)
  • isClient (9-9)
  • k (92-92)
  • sizes (93-93)
examples/next-uploader-adapter/src/pages/minimal.jsx (3)
  • handleChangeEvent (9-13)
  • k (55-55)
  • sizes (56-56)
examples/next-uploader-adapter/src/pages/regular.jsx (3)
  • handleChangeEvent (11-15)
  • k (57-57)
  • sizes (58-58)
examples/next-uploader-adapter/next-uploader/eslint.config.mjs (2)
examples/next-uploader-adapter/eslint.config.mjs (1)
  • eslintConfig (5-16)
examples/next-uploader/eslint.config.mjs (1)
  • eslintConfig (5-16)
examples/storybook/types/jsx.d.ts (1)
examples/storybook/types/react-jsx-runtime.d.ts (1)
  • Fragment (5-5)
examples/react-uploader/src/components/FileUploader/FileUploader.tsx (3)
examples/react-uploader-adapter/src/components/FileUploader/FileUploader.tsx (1)
  • FileUploader (38-101)
examples/angular-uploader/src/app/components/file-uploader/file-uploader.component.ts (2)
  • handleRemoveClick (110-112)
  • resetUploaderState (106-108)
examples/js-uploader/headless.js (1)
  • api (17-17)
examples/next-uploader/src/pages/minimal.jsx (2)
examples/next-uploader/src/pages/regular.jsx (3)
  • isClient (9-9)
  • k (93-93)
  • sizes (94-94)
examples/next-uploader-adapter/src/pages/minimal.jsx (3)
  • handleChangeEvent (9-13)
  • k (55-55)
  • sizes (56-56)
🪛 Biome (2.1.2)
examples/storybook/types/jsx.d.ts

[error] 9-9: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🔇 Additional comments (56)
examples/angular-uploader/src/app/views/form-view/mocks.ts (1)

20-21: LGTM! Systematic mock data update aligns with library API changes.

The addition of isValidationPending and source fields to all photo entries is consistent and well-structured, matching the updated OutputFileEntry type shape from the @uploadcare/file-uploader library upgrade to v1.24.0-alpha.2. The mock values (false and null respectively) are appropriate for testing purposes.

Also applies to: 87-88, 154-155, 221-222, 288-289, 355-356

examples/react-uploader-adapter/src/components/FileUploader/FileUploader.tsx (1)

40-40: LGTM: Type simplification aligns with updated library interface.

The ref type has been correctly simplified from the indirect InstanceType pattern to use UploadCtxProvider directly, matching the public interface of @uploadcare/file-uploader 1.24.0-alpha.2.

examples/react-uploader/src/views/MinimalView/MinimalView.tsx (1)

12-12: LGTM: Type simplification aligns with updated library interface.

The ref type has been correctly simplified to use UC.UploadCtxProvider directly instead of wrapping it with InstanceType.

examples/react-uploader/src/views/RegularView/RegularView.tsx (1)

12-12: LGTM: Type simplification aligns with updated library interface.

The ref type has been correctly simplified to use UC.UploadCtxProvider directly.

examples/react-uploader/src/components/FileUploader/FileUploader.tsx (5)

1-6: Quote style normalization improves consistency.

The switch from single to double quotes throughout the file creates a consistent code style.


28-29: LGTM: Type simplifications align with updated library interface.

Both ref types have been correctly simplified to use the library's public interfaces directly (UC.UploadCtxProvider and UC.Config) instead of the InstanceType wrapper pattern.


116-119: Excellent defensive guard against premature state reset.

The hasActiveModals check prevents the uploader state from being reset while the user is still interacting with modal dialogs, improving the user experience and preventing potential race conditions.


160-163: LGTM: Theme handling via CSS classes is cleaner.

The dynamic application of uc-dark and uc-light CSS classes based on the theme prop provides a clean, declarative way to control the uploader's appearance.


69-91: Locale definition formatting normalized.

The quote style changes in the locale definition object maintain consistency with the rest of the file's formatting updates.

examples/next-uploader-adapter/next-uploader/eslint.config.mjs (1)

8-15: Remove this review comment—the premise is incorrect.

Based on verification, eslint-config-next does not provide these ignore patterns as defaults. The patterns (.next/, out/, build/, next-env.d.ts) are legitimate Next.js-specific artifacts that the developer is intentionally configuring to prevent ESLint from linting generated/build output. This is not redundant re-statement of upstream defaults; it is necessary and appropriate configuration. Removing this block would cause ESLint to lint build artifacts, creating undesirable noise and errors.

Likely an incorrect or invalid review comment.

examples/next-uploader/src/pages/minimal.jsx (6)

8-15: Hydration pattern looks good.

The isClient state guard is the correct approach for preventing hydration mismatches when rendering client-only components with Next.js 16. This aligns well with the Next.js 14→16 upgrade.


39-46: Formatting and whitespace cleanup is appropriate.

The restructuring of the anchor and hr elements is purely cosmetic (indentation, whitespace, quote normalization). No functional impact.


66-82: Preview rendering and accessibility attributes look good.

The fallback for alt and title attributes (|| "") prevents potential undefined values, which is good for accessibility. The JSX formatting is clean and maintainable.


89-98: Utility function is correct and well-formatted.

The formatSize function logic is unchanged; only quote normalization has been applied. The early return for falsy values is appropriate.


1-4: ****

The original review comment's premise is incorrect. This is not a CSS migration from remote to local. The change represents an API shift:

  • Old approach: @uploadcare/react-uploader (React wrapper) required external core.css
  • New approach: @uploadcare/file-uploader (web components) includes built-in styling via Shadow DOM

The styles.module.css file exists and is appropriate—it contains only page-level styling (layout, typography, links, previews). The uploader components (uc-file-uploader-minimal, uc-config, etc.) use the built-in "uc-light" theme class from the file-uploader library, not external CSS. No styling is missing or needs to be added to the local module.

Likely an incorrect or invalid review comment.


21-25: Event handler API is correct and verified against file-uploader documentation.

The File Uploader "change" event is a CustomEvent where detail contains the payload, and detail.allEntries is an array of OutputFileEntry objects. The refactored handler correctly uses e.detail.allEntries, which is the standard DOM CustomEvent access pattern. This implementation is consistent across both next-uploader examples (minimal.jsx and regular.jsx), and the filter by f.status === "success" is valid per the documented OutputFileEntry structure.

The next-uploader-adapter examples use a different pattern (onChange prop) because they integrate via React component wrapper rather than direct addEventListener, which is not an inconsistency.

examples/next-uploader/src/pages/regular.jsx (1)

1-98: Apply the same verification concerns from minimal.jsx to regular.jsx.

Since both files (minimal.jsx and regular.jsx) receive identical changes to imports, event handling, CSS module usage, and utility functions, all verification concerns from the minimal.jsx review apply here as well—particularly:

  1. Verify styles.module.css exists and is complete.
  2. Verify the event handler API (e.detail.allEntries) matches file-uploader 1.24.0-alpha.2.
  3. Check consistency with other example projects (e.g., next-uploader-adapter).

The configuration difference (sourceList attribute) is appropriate and expected.

examples/angular-uploader/tsconfig.json (1)

16-16: LGTM: Modern module resolution strategy.

The change from "node" to "bundler" moduleResolution aligns with modern bundler-based workflows and is appropriate for Angular applications. This provides more accurate type resolution for bundled code.

.gitignore (1)

4-5: LGTM: Standard Storybook exclusions.

The added patterns appropriately exclude Storybook build artifacts and logs from version control, which is standard practice for projects using Storybook.

examples/react-uploader/package.json (1)

13-13: Alpha version concern already flagged.

The alpha version usage has already been flagged in examples/js-custom-tab/package.json. This is part of the coordinated upgrade across all examples.

examples/vue-uploader/package.json (1)

13-13: Alpha version concern already flagged.

The alpha version usage has already been flagged in examples/js-custom-tab/package.json. This is part of the coordinated upgrade across all examples.

examples/js-uploader/package.json (1)

12-12: Alpha version concern already flagged.

The alpha version usage has already been flagged in examples/js-custom-tab/package.json. This is part of the coordinated upgrade across all examples.

examples/svelte-uploader/package.json (1)

20-20: Alpha version concern already flagged.

The alpha version usage has already been flagged in examples/js-custom-tab/package.json. This is part of the coordinated upgrade across all examples.

examples/next-uploader-adapter/src/pages/minimal.jsx (1)

4-4: No issues found—styling and import patterns are correct.

The verification confirms that the switch to the Next.js-specific entry point is implemented consistently:

  • Both minimal.jsx and regular.jsx use @uploadcare/react-uploader/next
  • CSS is properly imported globally in _app.jsx
  • No conflicting or missing imports detected

The changes follow Next.js conventions and styling will work as expected.

examples/next-uploader-adapter/next-uploader/.gitignore (1)

1-41: LGTM!

Standard Next.js .gitignore patterns are comprehensive and appropriate for the project.

examples/vue-uploader/src/components/FileUploader/FileUploader.composition.vue (1)

63-66: LGTM! Good defensive pattern.

The hasActiveModals guard correctly prevents state reset when nested modals remain open, ensuring proper modal lifecycle management.

examples/next-uploader-adapter/src/pages/regular.jsx (1)

3-3: LGTM! Correct Next.js-specific import.

The switch to @uploadcare/react-uploader/next is appropriate for Next.js integration. The CSS is now imported globally in _app.jsx.

examples/next-uploader/src/pages/_app.jsx (1)

1-5: LGTM! Correct Next.js Pages Router pattern.

Global CSS import and minimal App wrapper follow Next.js best practices for the Pages Router.

examples/next-uploader-adapter/tsconfig.json (1)

1-34: LGTM! Standard Next.js TypeScript configuration.

The TypeScript configuration is appropriate for a Next.js project with modern settings and correct path aliases.

examples/next-uploader/next.config.ts (1)

4-6: Turbopack root path is correct.

The turbopack.root of '../../' correctly points to the repository root where package.json is located, confirming the monorepo setup is properly configured.

examples/next-uploader/package.json (1)

12-15: No critical compatibility issues found; alpha version is appropriate for example project.

The code is compatible with React 19 and Next.js 16. Verification shows:

  • ✅ No deprecated patterns (no cookies(), headers(), useFormState, or forwardRef)
  • ✅ Standard React hooks (useState, useRef, useEffect) work identically in React 19
  • ✅ Pages Router is fully supported in Next.js 16
  • ✅ Simple event-driven architecture requires no breaking-change adaptations

The alpha version of @uploadcare/[email protected] is appropriate here since this is an example project demonstrating the uploader functionality. Example projects commonly use pre-release versions to showcase new features.

examples/next-uploader/tsconfig.json (1)

1-34: LGTM!

The TypeScript configuration is well-structured for Next.js 15+ with React 19. The use of "react-jsx" for automatic JSX transform and "bundler" module resolution aligns with modern Next.js best practices.

examples/angular-uploader/src/app/views/regular-view/regular-view.component.ts (1)

18-20: LGTM! Type annotation simplified appropriately.

Removing the InstanceType<> wrapper is correct when UC.UploadCtxProvider is already a class type. This simplification improves readability while maintaining type safety.

examples/angular-uploader/src/app/views/minimal-view/minimal-view.component.ts (1)

26-28: LGTM! Consistent type simplification.

This change aligns with the same type refinement applied to regular-view and file-uploader components, maintaining consistency across the Angular example.

examples/next-uploader/.gitignore (1)

1-41: LGTM!

The gitignore rules are comprehensive and well-organized, covering all standard Next.js build artifacts, dependency directories, and environment files.

examples/vue-uploader/src/components/FileUploader/FileUploader.options.vue (1)

63-71: LGTM! Good defensive check for active modals.

The guard if (e.detail.hasActiveModals) return; prevents premature uploader state reset when nested modals are still open. This improves UX by ensuring file emission and state cleanup only occur when the user has fully closed all modal dialogs.

examples/next-uploader-adapter/src/pages/_app.jsx (1)

1-5: LGTM! Standard Next.js App pattern.

The global CSS import ensures uploader styling is available throughout the application, and the App component properly forwards props to each page component.

examples/next-uploader-adapter/eslint.config.mjs (1)

1-1: Import path is correct for ESLint 9.

The verification confirms that "eslint/config" is the correct import path and both defineConfig and globalIgnores are official helpers available in ESLint 9's flat config system. The functions are standard utilities in ESLint v9 that can be imported from "eslint/config". No changes needed.

Likely an incorrect or invalid review comment.

examples/next-uploader-adapter/.gitignore (1)

1-41: LGTM!

The gitignore patterns are appropriate for a Next.js project and follow standard conventions.

examples/next-uploader/README.md (1)

1-36: LGTM!

The README now follows the standard Next.js starter template format with clear instructions for multiple package managers and deployment guidance.

examples/next-uploader-adapter/package.json (2)

6-9: LGTM!

The script updates align with Next.js 15+ requirements:

  • dev now explicitly uses next dev
  • start correctly uses next start (not npm run dev)
  • Added lint script for ESLint

13-15: Next.js 16 and React 19.2 versions are compatible and correctly configured.

Next.js 16 is designed to work with React 19.2 with explicit framework alignment for React 19.2 features. The package.json already specifies the recommended versions (next 16.0.0, react 19.2.0, react-dom 19.2.0). No changes needed.

examples/angular-uploader/src/app/components/file-uploader/file-uploader.component.ts (3)

31-34: Type simplification looks correct.

The removal of InstanceType<> wrappers simplifies the types. This is correct if UC.UploadCtxProvider and UC.Config are already the instantiated class types (not constructors).


60-62: Cosmetic formatting change only.

The localization keys changed from quoted ('photo__one') to unquoted (photo__one) property syntax. This is purely a formatting change with no runtime impact.


120-128: Behavioral change requires manual verification; no tests found.

The guard condition at lines 121-123 is a new conditional that prevents state reset when hasActiveModals is true. This appears intentional and defensive (avoid resetting state while modals are open), and the uploadedFiles reset at line 127 logically prevents duplicate emissions.

However, no test files (.spec.ts) exist in the angular-uploader example to verify this change doesn't break existing workflows. The developer should confirm:

  1. This guard behavior is intentional and expected
  2. No existing usage patterns rely on the prior unconditional reset behavior
examples/next-uploader-adapter/next.config.ts (1)

3-8: LGTM!

The configuration properly sets up:

  • transpilePackages to handle the @uploadcare/react-uploader ESM package
  • turbopack.root pointing to the repository root for monorepo module resolution

Both settings are appropriate for this project structure.

examples/next-uploader-adapter/next-uploader/next.config.ts (1)

3-7: Remove the review comment entirely—it is based on incorrect assumptions about the nested config.

The nested next.config.ts at examples/next-uploader-adapter/next-uploader/ is correct as written. The directory contains only the config file with no source code or package.json. The @uploadcare/react-uploader dependency and transpilePackages configuration exist in the parent config at examples/next-uploader-adapter/next.config.ts, which is where the actual Next.js application code resides. The nested config's sole purpose is to set turbopack.root for monorepo module resolution—no transpiling configuration is needed here.

Likely an incorrect or invalid review comment.

examples/next-uploader/eslint.config.mjs (1)

1-3: ****

The imports are standard and correct. ESLint 9 officially exports defineConfig and globalIgnores from "eslint/config", and the code in this PR exactly matches the official documented pattern. No issues.

Likely an incorrect or invalid review comment.

examples/angular-uploader/package.json (1)

13-23: Angular 20 upgrade is properly implemented with no breaking changes detected.

All deprecated Angular 17→20 patterns have been addressed:

  • Control flow syntax migrated: @if and @for used throughout (not *ngIf/*ngFor)
  • No TestBed.get() calls (no tests present)
  • Standalone components fully implemented
  • Modern bootstrap approach with bootstrapApplication()
  • TypeScript v5.9.3 meets Angular 20 requirement (v5.8+)

No code changes needed.

examples/storybook/.storybook/preview.js (1)

1-13: LGTM on base preview config.
Parameters/controls setup is standard.

examples/storybook/.storybook/tsconfig.json (1)

1-24: Looks consistent with project TS setup.

Bundler resolution + classic JSX factories match vite/esbuild config.

examples/storybook/stories/Demo.stories.tsx (1)

5-23: Story content LGTM.
Tags, render function, and ctx-name wiring look right for uploader examples.

examples/storybook/package.json (1)

14-18: Confirm intent for alpha version — if no specific feature is required, use stable v1.20.1.

The latest stable is v1.20.1, but the file uses 1.24.0-alpha.2 (pre-release). The git commit "chore: bump uploader" provides no explanation for this choice. For Storybook examples (non-production context), using a stable version is safer unless the alpha contains specific features or fixes needed for the examples. Either document the rationale or switch to v1.20.1.

examples/storybook/types/jsx.d.ts (3)

1-3: Clear documentation of design rationale.

The comments effectively explain why permissive typing is used for hyperscript compatibility.


15-18: LGTM!

The hyperscript module declaration correctly wires the default export for use with the custom JSX pragma.


12-12: Fragment declarations are properly scoped and do not conflict.

The two Fragment declarations serve different purposes and exist in different scopes. The global Fragment: unique symbol in jsx.d.ts is correctly used as the JSX fragment factory (referenced by jsxFragmentFactory in tsconfig), while the exported Fragment: any in react-jsx-runtime.d.ts is a module stub for the automatic JSX runtime pattern. TypeScript properly resolves both without ambiguity. No changes needed.

Likely an incorrect or invalid review comment.

"@angular/platform-browser": "^20.3.7",
"@angular/platform-browser-dynamic": "^20.3.7",
"@angular/router": "^20.3.7",
"@uploadcare/file-uploader": "1.24.0-alpha.2",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Alpha version with exact pinning.

The @uploadcare/file-uploader uses an alpha version (1.24.0-alpha.2) with exact pinning (no caret). Alpha versions may have bugs or breaking changes.

Verify if this alpha version is stable for production use:


🌐 Web query:

What is the latest stable version of @uploadcare/file-uploader?

💡 Result:

The latest stable version is @uploadcare/file-uploader v1.20.1 (published Oct 13, 2025). [1][2]

Sources:
[1] npm package page for @uploadcare/file-uploader.
[2] Uploadcare changelog / docs.


Review verified: Consider using stable version or removing exact pinning for alpha.

The latest stable version of @uploadcare/file-uploader is v1.20.1, whereas the package.json specifies 1.24.0-alpha.2. The alpha version is unstable and uses exact pinning, which locks the project to that specific pre-release. Either upgrade to the stable version (1.20.1) or, if testing the alpha features is intentional, consider using ~1.24.0-alpha.2 or documenting why this pre-release is required.

🤖 Prompt for AI Agents
In examples/angular-uploader/package.json around line 20, the dependency
"@uploadcare/file-uploader": "1.24.0-alpha.2" pins a pre-release exact version;
change it to the stable release "1.20.1" if you don't need alpha features, or if
alpha is intentional relax pinning to a range like "~1.24.0-alpha.2" and add a
brief comment in package.json or README explaining why the pre-release is
required.

"dependencies": {
"@splidejs/splide": "4.1.4",
"@uploadcare/file-uploader": "^1.2.0"
"@uploadcare/file-uploader": "1.24.0-alpha.2"
Copy link

@coderabbitai coderabbitai bot Oct 24, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify documentation mentions alpha version usage.

The dependency has been updated to an alpha prerelease (1.24.0-alpha.2). While this is acceptable for example projects, ensure that the README or documentation clearly indicates that these examples use a prerelease version to prevent users from unknowingly adopting unstable code in production.

Run the following script to check if documentation mentions the alpha version:


🏁 Script executed:

#!/bin/bash
# Description: Check if README files mention alpha or prerelease versions

# Search for README files and check for mentions of alpha/prerelease
fd -e md README | xargs rg -i "alpha|prerelease|pre-release|unstable|preview" -C 2

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Find and examine README files in the examples directory

# List contents of examples/js-custom-tab directory
echo "=== Contents of examples/js-custom-tab ===" 
fd . examples/js-custom-tab -max-depth 1 -type f

# Check for any README files (case-insensitive)
echo -e "\n=== Searching for README files ===" 
fd -i readme examples/js-custom-tab

# Show full content if README exists
if [ -f "examples/js-custom-tab/README.md" ]; then
  echo -e "\n=== Content of examples/js-custom-tab/README.md ===" 
  cat examples/js-custom-tab/README.md
fi

# Check root README for mentions of examples or this specific example
echo -e "\n=== Root README mentions of 'examples' or 'js-custom-tab' ===" 
rg -i "examples|js-custom-tab" README.md -C 3 || echo "No matches found"

Length of output: 3823



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Check what the examples/js-custom-tab README should mention

# Display the actual README content more clearly
echo "=== Full README.md content ===" 
cat examples/js-custom-tab/README.md

# Check if there are other doc files in the directory
echo -e "\n=== All files in examples/js-custom-tab ===" 
find examples/js-custom-tab -type f

Length of output: 1090


Update README to reflect alpha version and correct outdated information.

The documentation gap confirmed: examples/js-custom-tab/README.md does not indicate that @uploadcare/[email protected] is a prerelease version. Additionally, the README appears to contain outdated information (referencing "examples/composition" instead of "js-custom-tab").

Update the README to:

  • Clearly state that this example uses an alpha prerelease version
  • Correct the directory references to match "js-custom-tab"
  • Warn users of potential breaking changes and instability
🤖 Prompt for AI Agents
In examples/js-custom-tab/README.md around the section describing dependencies
and example paths (related to package.json line 18), update the README to state
that @uploadcare/[email protected] is an alpha prerelease, correct
any references that mention "examples/composition" to "examples/js-custom-tab",
and add a short warning note that the example uses an alpha release which may
contain breaking changes or instability; keep the language concise and clearly
visible near the top of the README.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!


Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Documentation inconsistency with project structure.

The README references app/page.tsx (App Router), but the project appears to use the Pages Router based on the file structure (src/pages/ directory). Update this line to reference the correct entry point for your routing approach.

-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+You can start editing the pages by modifying files in `src/pages/`. The page auto-updates as you edit the file.
📝 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.

Suggested change
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
You can start editing the pages by modifying files in `src/pages/`. The page auto-updates as you edit the file.
🤖 Prompt for AI Agents
In examples/next-uploader-adapter/next-uploader/README.md around line 19, the
README incorrectly references app/page.tsx (App Router) while the project uses
the Pages Router (src/pages/). Update that sentence to point to the correct
entry file for Pages Router (for example src/pages/index.tsx or
src/pages/index.jsx) so documentation matches the repository structure.

"next": "14.1.4",
"react": "^18",
"react-dom": "^18"
"@uploadcare/react-uploader": "^1.11.0-alpha.0",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Alpha version in production code.

The @uploadcare/react-uploader is using version ^1.11.0-alpha.0. Alpha versions may contain breaking changes and bugs.

Verify whether this alpha version is stable enough for the example or if a stable version should be used:


🌐 Web query:

What is the latest stable version of @uploadcare/react-uploader package?

💡 Result:

The latest stable version is 1.10.2 (published Oct 8, 2025). [1][2]

Sources:
[1] npm package page for @uploadcare/react-uploader.
[2] Package info on Socket (package registry summary).


Replace alpha version with stable release.

The @uploadcare/react-uploader package has a stable version 1.10.2 available (released Oct 8, 2025). Update line 12 to use ^1.10.2 instead of the alpha version to provide a reliable example.

🤖 Prompt for AI Agents
In examples/next-uploader-adapter/package.json around line 12, replace the alpha
dependency version for "@uploadcare/react-uploader": "^1.11.0-alpha.0" with the
stable release "^1.10.2" so the example uses the reliable, non-alpha package;
update the package.json dependency entry accordingly and run a quick
install/test to verify no breaking changes.

Comment on lines +1 to +36
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
# clone this repo and go to the cloned folder
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

$ cd examples/next-uploader-adapter
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

$ npm install
# or `yarn install`, if you wish
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

$ npm run start
# or `yarn start`
```
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Contribution
## Deploy on Vercel

You’re always welcome to contribute:
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

* Create [issues](https://github.com/uploadcare/file-uploader-examples/issues) every time you feel something is missing or goes wrong.
* Provide your feedback or drop us a support request at <a href="mailto:[email protected]">[email protected]</a>.
* Ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/uploadcare) with "uploadcare" tag if others can have these questions as well.
* Star this repo if you like it ⭐️
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

README replaced with generic Next.js boilerplate.

The README no longer describes what this uploader adapter example demonstrates. The current content is standard create-next-app documentation that doesn't explain:

  • What the adapter pattern showcases
  • How to use the Uploadcare uploader in this example
  • What makes this example different from other uploader examples

Consider restoring example-specific documentation that helps users understand the purpose and usage of this particular adapter implementation.

🤖 Prompt for AI Agents
examples/next-uploader-adapter/README.md lines 1-36: The README was replaced
with generic Next.js boilerplate; restore example-specific documentation that
explains the uploader adapter purpose and usage. Replace the boilerplate with a
short description of what this example demonstrates (the adapter pattern for
Uploadcare in a Next.js app), minimal setup and run steps (install, env vars
like UPLOADCARE_PUBLIC_KEY/SECRET, dev command), how to use the example in the
app (which page or API route to open, how to trigger uploads and where files are
stored), a brief note about key implementation files to inspect (adapter
implementation and integration points), and one-line deployment notes; keep it
concise and focused on this example rather than general Next.js docs.

Comment on lines +1 to +9
import { join, dirname } from "path";

/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value) {
return dirname(require.resolve(join(value, "package.json")));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix require in ESM Storybook config (ReferenceError risk).

With "type": "module", require is undefined. Use createRequire.

-import { join, dirname } from "path";
+import { join, dirname } from "path";
+import { createRequire } from "module";
+
+const require = createRequire(import.meta.url);
 
 /**
  * This function is used to resolve the absolute path of a package.
  * It is needed in projects that use Yarn PnP or are set up within a monorepo.
  */
 function getAbsolutePath(value) {
   return dirname(require.resolve(join(value, "package.json")));
 }
📝 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.

Suggested change
import { join, dirname } from "path";
/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value) {
return dirname(require.resolve(join(value, "package.json")));
}
import { join, dirname } from "path";
import { createRequire } from "module";
const require = createRequire(import.meta.url);
/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value) {
return dirname(require.resolve(join(value, "package.json")));
}
🤖 Prompt for AI Agents
In examples/storybook/.storybook/main.js around lines 1 to 9, the code uses
require.resolve which throws a ReferenceError in ESM ("type":"module"); import
createRequire from the 'module' package (import { createRequire } from 'module')
and instantiate a require bound to the current file (const require =
createRequire(import.meta.url)); then use that require.resolve inside
getAbsolutePath (no other API changes) so the function works under ESM/Yarn
PnP/monorepo setups.

interface IntrinsicElements {
[elemName: string]: any;
}
interface Element {}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace empty interface with type alias.

The empty Element interface is equivalent to {} and violates linting rules. Use a type alias instead.

Apply this diff to fix the linter warning:

-  interface Element {}
+  type Element = any;
📝 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.

Suggested change
interface Element {}
type Element = any;
🧰 Tools
🪛 Biome (2.1.2)

[error] 9-9: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🤖 Prompt for AI Agents
In examples/storybook/types/jsx.d.ts around line 9, the declaration `interface
Element {}` is an empty interface (equivalent to `{}`) that triggers lint
warnings; replace it with a type alias like `type Element = {}` or a more
specific alias as needed. Update the file by removing the empty interface
declaration and adding a type alias named Element to satisfy the linter and
preserve the same shape.

@nd0ut nd0ut requested a review from egordidenko November 6, 2025 14:02
Copy link

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
examples/js-custom-tab/package.json (1)

2-2: Package name mismatch: "composition" should be "js-custom-tab".

The package.json declares "name": "composition" but the file resides in examples/js-custom-tab/. Update the package name to match the directory name for clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b0b72f5 and 0ad6f39.

⛔ Files ignored due to path filters (11)
  • examples/js-custom-tab/package-lock.json is excluded by !**/package-lock.json
  • examples/js-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/js-uploader/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • examples/next-uploader-adapter/package-lock.json is excluded by !**/package-lock.json
  • examples/next-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/react-uploader-adapter/package-lock.json is excluded by !**/package-lock.json
  • examples/react-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/storybook/package-lock.json is excluded by !**/package-lock.json
  • examples/svelte-uploader/package-lock.json is excluded by !**/package-lock.json
  • examples/vue-uploader/package-lock.json is excluded by !**/package-lock.json
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (14)
  • examples/angular-uploader/package.json (1 hunks)
  • examples/js-custom-tab/package.json (1 hunks)
  • examples/js-uploader/package.json (1 hunks)
  • examples/next-uploader-adapter/package.json (1 hunks)
  • examples/next-uploader/package.json (1 hunks)
  • examples/react-uploader-adapter/package.json (1 hunks)
  • examples/react-uploader-adapter/src/components/FileUploader/FileUploader.tsx (3 hunks)
  • examples/react-uploader-adapter/tsconfig.json (1 hunks)
  • examples/react-uploader/package.json (1 hunks)
  • examples/react-uploader/src/components/FileUploader/FileUploader.tsx (7 hunks)
  • examples/react-uploader/tsconfig.json (1 hunks)
  • examples/storybook/package.json (1 hunks)
  • examples/svelte-uploader/package.json (1 hunks)
  • examples/vue-uploader/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • examples/storybook/package.json
  • examples/vue-uploader/package.json
  • examples/svelte-uploader/package.json
  • examples/react-uploader/package.json
  • examples/react-uploader/src/components/FileUploader/FileUploader.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
examples/react-uploader-adapter/src/components/FileUploader/FileUploader.tsx (2)
examples/react-uploader/src/components/FileUploader/FileUploader.tsx (1)
  • FileUploader (18-192)
examples/angular-uploader/src/app/components/file-uploader/file-uploader.component.ts (2)
  • handleRemoveClick (110-112)
  • resetUploaderState (106-108)
🔇 Additional comments (12)
examples/react-uploader-adapter/tsconfig.json (1)

13-13: Good modernization choice.

Updating moduleResolution to "bundler" aligns with React 19 and modern tooling. This strategy is the recommended setting for bundler-based projects and correctly handles package.json exports fields.

examples/react-uploader/tsconfig.json (1)

13-13: Good modernization choice.

Updating moduleResolution to "bundler" aligns with React 19 and modern tooling. This strategy is the recommended setting for bundler-based projects and correctly handles package.json exports fields.

examples/react-uploader-adapter/package.json (1)

13-13: Approve: Minor version bump with caret versioning.

The upgrade from ^1.10.1 to ^1.11.0 is appropriate for a minor release, and caret versioning permits patch updates automatically. This is part of a coordinated upgrade across adapters.

examples/js-custom-tab/package.json (1)

18-18: Approve: @uploadcare/file-uploader upgraded to stable release.

The previous review flagged an alpha version; this PR correctly upgrades to the stable 1.24.3 release. The large jump from ^1.2.0 to 1.24.3 represents significant new features, but exact pinning ensures reproducible builds. Verify that the example code works with the new API surface of v1.24.

examples/js-uploader/package.json (1)

12-12: Approve: Coordinated upgrade to stable @uploadcare/file-uploader.

The upgrade from ^1.2.0 to 1.24.3 is part of the coordinated dependency bump across examples. The stable release (previously flagged as alpha in prior reviews) is now used with exact pinning. Verify example compatibility with the new API.

examples/next-uploader/package.json (3)

6-9: Approve: Script updates are correct for Next.js 16 and ESLint 9.

The script changes correctly specify explicit Next.js commands (next dev, next start) and add ESLint linting. However, ensure your example code adheres to ESLint config-next 16.0.0 rules and uses the new script names in any CI/CD pipelines.


17-24: Approve: DevDependencies section correctly configured for Next.js 16 and React 19.

The newly added devDependencies are properly versioned for the updated framework versions:

  • @types/react@^19 and @types/react-dom@^19 match React 19
  • [email protected] matches Next.js 16
  • eslint@^9 is the latest major version
  • typescript@^5 is compatible with React 19

Ensure your build process runs npm install to fetch these new devDependencies.


12-15: Remove the review comment – it's based on incorrect assumptions about the codebase.

After examining the example code in examples/next-uploader/, the review comment's concerns do not apply to this codebase:

  1. Async APIs concern: The review mentions cookies(), headers(), params, searchParams requiring await. These are App Router APIs. The example uses the Pages Router (src/pages/ structure), which has different APIs and does not use these patterns.

  2. useFormState() concern: No usage found in any component. The code uses standard useState() for state management.

  3. propTypes/defaultProps concern: Not present in any component files.

  4. Ref callback concern: The example uses useRef() objects (ref={ctxProviderRef}), not callback refs, so this is not an issue.

  5. Route handler configuration concern: Pages Router does not have route handlers. This pattern only applies to App Router.

The actual code is minimal and migration-ready for Next.js 16 and React 19.

Likely an incorrect or invalid review comment.

examples/next-uploader-adapter/package.json (3)

6-9: Approve: Script updates correctly specify Next.js 16 commands and add ESLint.

The script changes align with Next.js 16 conventions. Ensure your CI/CD and local development workflows use these new script names.


19-22: Approve: DevDependencies correctly updated for Next.js 16, React 19, and ESLint 9.

The type definitions and linting tools are properly versioned:

  • @types/react@^19 and @types/react-dom@^19 support React 19
  • eslint@^9 with [email protected] enforce Next.js 16 standards
  • TypeScript ^5 remains compatible

Ensure these devDependencies are installed before development.


12-15: Version mismatch: @uploadcare/[email protected] does not exist on npm.

The example code itself is already compatible with React 19 and Next.js 16—it does not use useFormState, propTypes, defaultProps, or server-side async APIs requiring await. However, the latest published version is 1.10.2, not 1.11.0. The package.json specifies "@uploadcare/react-uploader": "^1.11.0", which cannot be resolved and will cause installation to fail.

Update the dependency to an existing version (e.g., ^1.10.2).

Likely an incorrect or invalid review comment.

examples/angular-uploader/package.json (1)

13-23: No critical issues found — Angular 20 migration is properly implemented.

Verification confirms:

  • All example components use Angular 20 patterns (standalone components, provideRouter)
  • No deprecated APIs remain in the code
  • @uploadcare/file-uploader 1.24.3 is compatible with Angular 20 and correctly integrated via CUSTOM_ELEMENTS_SCHEMA
  • TypeScript 5.9.3 and all supporting dependencies (RxJS 7.8.2, zone.js 0.15.1) are correctly aligned

The three-major-version upgrade (Angular 17→20) has been properly executed. The dependency versions and example code are production-ready.

Comment on lines +63 to 71
const handleModalCloseEvent = (e: EventMap["modal-close"]["detail"]) => {
if (e.hasActiveModals) {
return;
}
resetUploaderState();

onChange([...files, ...uploadedFiles])
onChange([...files, ...uploadedFiles]);

setUploadedFiles([]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Uploaded files vanish because uploadedFiles is stale when the modal auto-closes

With confirmUpload={false}, the uploader closes its modal immediately after the "change" detail reports a successful upload. handleChangeEvent schedules setUploadedFiles(...), but React has not re-rendered yet when "modal-close" fires, so handleModalCloseEvent still sees the previous (often empty) uploadedFiles array. The result is that fresh uploads are dropped and never merged into files.

Store the latest successful entries in a ref (or read them before clearing the collection) so the modal-close handler always works with up-to-date data:

@@
-export default function FileUploader({
+export default function FileUploader({
   files,
   uploaderClassName,
   onChange,
   theme,
 }: FileUploaderProps) {
+  const uploadedFilesRef = useRef<OutputFileEntry<"success">[]>([]);
   const [uploadedFiles, setUploadedFiles] = useState<
     OutputFileEntry<"success">[]
   >([]);
@@
-  const handleModalCloseEvent = (e: EventMap["modal-close"]["detail"]) => {
+  const handleModalCloseEvent = (e: EventMap["modal-close"]["detail"]) => {
     if (e.hasActiveModals) {
       return;
     }
+    const successfulEntries = uploadedFilesRef.current;
     resetUploaderState();
-
-    onChange([...files, ...uploadedFiles]);
-
+    if (successfulEntries.length) {
+      onChange([...files, ...successfulEntries]);
+    }
+    uploadedFilesRef.current = [];
     setUploadedFiles([]);
   };
 
   const handleChangeEvent = (e: EventMap["change"]["detail"]) => {
-    setUploadedFiles([
-      ...e.allEntries.filter((f) => f.status === "success"),
-    ] as OutputFileEntry<"success">[]);
+    const successfulEntries = e.allEntries.filter(
+      (f) => f.status === "success",
+    ) as OutputFileEntry<"success">[];
+    uploadedFilesRef.current = successfulEntries;
+    setUploadedFiles(successfulEntries);
   };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In examples/react-uploader-adapter/src/components/FileUploader/FileUploader.tsx
around lines 63 to 71, handleModalCloseEvent reads the uploadedFiles state which
can be stale when the modal auto-closes; change the logic to keep the latest
successful uploads in a mutable ref (e.g. uploadedFilesRef.current) or capture
the current uploadedFiles array immediately before clearing it so
handleModalCloseEvent always uses up-to-date entries; update handleChangeEvent
to update the ref when uploads complete, have handleModalCloseEvent read from
the ref (or from the captured value) when merging into files, and only then
clear state so no newly uploaded files are lost.

"dependencies": {
"@splidejs/splide": "4.1.4",
"@uploadcare/file-uploader": "^1.2.0"
"@uploadcare/file-uploader": "1.24.0-alpha.2"
Copy link
Contributor

Choose a reason for hiding this comment

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

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants