Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6e7ba4b
Merge pull request #296 from edgestorejs/next
raviships Oct 11, 2026
0d24d87
docs: standardize EdgeStore branding
raviships Oct 11, 2026
f3eed79
Merge pull request #299 from edgestorejs/t3code/fix-edgestore-branding
raviships Oct 11, 2026
1d9c50a
fix: repair website links and component setup flows
raviships Oct 11, 2026
6f4dd63
fix: reopen manual instructions for repeated anchor clicks
raviships Oct 11, 2026
afbc8c7
fix: keep the PR limited to verified website and docs fixes
raviships Oct 11, 2026
48a8834
fix: select documentation tabs directly and retain upload feedback
raviships Oct 13, 2026
705fc05
fix: restore the upload button file list example
raviships Oct 13, 2026
6c999d5
fix: limit the PR to website link fixes
raviships Oct 13, 2026
da041d6
Merge pull request #300 from edgestorejs/t3code/fix-sponsor-v0-links
raviships Oct 13, 2026
d1d0b42
fix: move file list into its own registry item
raviships Oct 13, 2026
575691e
fix: open registry blocks in v0 as the app page
raviships Oct 13, 2026
9a9a3ad
fix: use alias imports in progress demo blocks
raviships Oct 13, 2026
fa993e2
Merge pull request #301 from edgestorejs/t3code/decouple-button-upload
raviships Oct 13, 2026
19cc3e5
Merge remote-tracking branch 'origin/main' into t3code/fix-v0-registr…
raviships Oct 13, 2026
72df708
style: format progress demo block imports
raviships Oct 13, 2026
adfc622
Merge pull request #302 from edgestorejs/t3code/fix-v0-registry-imports
raviships Oct 13, 2026
01037f5
fix: open hidden docs sections for anchor links
raviships Oct 14, 2026
c227fd6
Merge pull request #303 from edgestorejs/t3code/fix-docs-anchor-navig…
raviships Oct 14, 2026
f79e5bb
fix(deps): upgrade Next.js to 16.4.1 for the October 14 security release
raviships Oct 14, 2026
3dfe505
Merge pull request #304 from edgestorejs/fix/nextjs-16.4.1-security
raviships Oct 14, 2026
a7317a8
chore: forward-merge main into next
raviships Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/content/docs/components/file-field.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ First you will need to follow the [manual install setup](./manual-install) guide

- [uploader-provider](./uploader-provider)
- [dropzone](./dropzone)
- [multi-file](./multi-file)
- [file-list](./file-list)

</Step>

Expand Down
103 changes: 103 additions & 0 deletions docs/content/docs/components/file-list.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
title: File List
description: Lists the files of an UploaderProvider with their status, progress and actions.
---

import { LimitedCode } from '@/components/ui/limited-code';
import {
OpenTabs,
OpenTabsContent,
OpenTabsList,
OpenTabsTrigger,
} from '@/components/ui/open-tabs';
import { Callout } from 'fumadocs-ui/components/callout';
import { Step, Steps } from 'fumadocs-ui/components/steps';

`file-list.tsx` exports:

- `FileList`: lists the files of the nearest `UploaderProvider`.
- `FileListItem`: renders one file with its status, progress and actions (retry, cancel, remove).
- `FileBadge`: renders the colored file-type tile.

Use it next to an [Upload Button](./upload-button), or anywhere you want the files of an `UploaderProvider` shown as a list.

<Callout>
The [multi-file](./multi-file) and [file field](./file-field) components
install it automatically via the CLI.
</Callout>

## Installation

<OpenTabs defaultValue="cli">

<OpenTabsList>
<OpenTabsTrigger value="cli">CLI</OpenTabsTrigger>
<OpenTabsTrigger value="manual">Manual</OpenTabsTrigger>
</OpenTabsList>

<OpenTabsContent value="cli">

Use the shadcn CLI to add the component to your project.

```package-install
npx shadcn@latest add https://edgestore.dev/r/file-list.json
```

</OpenTabsContent>

<OpenTabsContent value="manual">

<Steps>

<Step>

### Setup for manual installation

First you will need to follow the [manual install setup](./manual-install) guide.

</Step>

<Step>

### Install required components

- [uploader-provider](./uploader-provider)
- [progress-bar](./progress-bar)

</Step>

<Step>

### Copy this component

<LimitedCode>

<include lang="tsx" meta='title="components/upload/file-list.tsx"'>../../../src/components/upload/file-list.tsx</include>

<include lang="tsx" meta='title="components/upload/upload-utils.ts"'>../../../src/components/upload/upload-utils.ts</include>

</LimitedCode>

</Step>

</Steps>

</OpenTabsContent>

</OpenTabs>

## Usage

```tsx
<UploaderProvider uploadFn={uploadFn} autoUpload>
{/* anything that adds files, e.g. <UploadButton /> */}
<FileList />
</UploaderProvider>
```

## Props

| Prop | Type | Default | Description |
| ---------- | --------- | ------- | ------------------------------------------- |
| `disabled` | `boolean` | `false` | Hides the retry, cancel and remove actions. |
| `...` | | | Any other `<ul>` prop, such as `className`. |
8 changes: 2 additions & 6 deletions docs/content/docs/components/multi-file.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ First you will need to follow the [manual install setup](./manual-install) guide

- [uploader-provider](./uploader-provider)
- [dropzone](./dropzone)
- [progress-bar](./progress-bar)
- [file-list](./file-list)
- [shadcn/ui button](https://ui.shadcn.com/docs/components/button)

</Step>
Expand Down Expand Up @@ -143,8 +143,4 @@ export function MultiFileDropzoneUsage() {

### Building your own layout

`multi-file.tsx` also exports the pieces it is made of, so you can arrange them differently:

- `FileList` lists the files of the nearest `UploaderProvider`.
- `FileListItem` renders one file with its status and actions.
- `FileBadge` renders the colored file-type tile.
`FileUploader` is a `Dropzone` and a [`FileList`](./file-list), so you can arrange the two differently.
10 changes: 7 additions & 3 deletions docs/content/docs/components/upload-button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps';
<UploadButtonBlock />
</DemoBlock>

It takes the same props as the shadcn/ui `Button`. Several buttons can feed the same `UploaderProvider`, so you can pair them with a `FileList` or build your own list with `useUploader`.
It takes the same props as the shadcn/ui `Button`. Several buttons can feed the same `UploaderProvider`, so you can pair them with a [`FileList`](./file-list) or build your own list with `useUploader`.

## Installation

Expand Down Expand Up @@ -81,13 +81,17 @@ First you will need to follow the [manual install setup](./manual-install) guide

## Usage

Install or copy the component from [Installation](#installation) before using this example.
Install or copy the component from [Installation](#installation) before using this example. It also uses [`FileList`](./file-list):

```package-install
npx shadcn@latest add https://edgestore.dev/r/file-list.json
```

```tsx
'use client';

import { UploadErrors } from '@/components/upload/dropzone';
import { FileList } from '@/components/upload/multi-file';
import { FileList } from '@/components/upload/file-list';
import { UploadButton } from '@/components/upload/upload-button';
import {
UploaderProvider,
Expand Down
2 changes: 1 addition & 1 deletion docs/content/docs/components/uploader-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function MyUploaderPage() {
// Define the upload function
const uploadFn: UploadFn = React.useCallback(
async ({ file, onProgressChange, signal }) => {
// Example using Edge Store client
// Example using EdgeStore client
const res = await edgestore.publicFiles.upload({
file,
signal,
Expand Down
1 change: 1 addition & 0 deletions docs/content/docs/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"components/avatar",
"components/file-field",
"components/upload-button",
"components/file-list",
"components/uploader-provider",
"components/dropzone",
"components/progress-circle",
Expand Down
4 changes: 2 additions & 2 deletions docs/public/r/avatar-dropzone-block.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
{
"path": "examples/components/src/components/upload/blocks/avatar-block.tsx",
"content": "'use client';\n\nimport { AvatarDropzone } from '@/components/upload/avatar-dropzone';\nimport {\n UploaderProvider,\n type UploadFn,\n} from '@/components/upload/uploader-provider';\nimport * as React from 'react';\n\nexport default function AvatarDropzoneBlock() {\n const { edgestore } = useMockEdgeStore(); // Mock edgestore for easy v0 integration\n\n const uploadFn: UploadFn = React.useCallback(\n async ({ file, signal, onProgressChange }) => {\n const res = await edgestore.myPublicImages.upload({\n file,\n signal,\n onProgressChange,\n });\n // you can run some server action or api here\n // to add the necessary data to your database\n return { url: res.url };\n },\n [edgestore],\n );\n\n return (\n <div className=\"flex flex-col items-center gap-4 p-4\">\n <div className=\"w-full max-w-md\">\n <UploaderProvider uploadFn={uploadFn} autoUpload>\n <AvatarDropzone\n label=\"Profile photo\"\n maxSize={1024 * 1024 * 2} // 2MB\n minDimension={128}\n />\n </UploaderProvider>\n </div>\n </div>\n );\n}\n\n// Mock implementation of EdgeStore\nfunction useMockEdgeStore() {\n return {\n edgestore: {\n myPublicImages: {\n upload: async ({\n signal,\n onProgressChange,\n }: {\n file: File;\n signal?: AbortSignal;\n onProgressChange?: (progress: number) => void | Promise<void>;\n }) => {\n // Simulate upload progress. Rejects like EdgeStore when the upload is aborted.\n await new Promise<void>((resolve, reject) => {\n let progress = 0;\n const interval = setInterval(() => {\n progress = Math.min(\n progress + Math.floor(Math.random() * 21) + 10,\n 100,\n );\n void onProgressChange?.(progress);\n if (progress >= 100) {\n clearInterval(interval);\n resolve();\n }\n }, 300);\n signal?.addEventListener('abort', () => {\n clearInterval(interval);\n reject(new DOMException('Upload aborted', 'AbortError'));\n });\n });\n\n return {\n url: 'https://edgestore.dev/img/upload-demo.webp',\n };\n },\n },\n },\n };\n}\n",
"type": "registry:block",
"target": "components/upload/blocks/avatar-block.tsx"
"type": "registry:page",
"target": "app/page.tsx"
}
],
"type": "registry:block"
Expand Down
4 changes: 2 additions & 2 deletions docs/public/r/file-field-block.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
{
"path": "examples/components/src/components/upload/blocks/file-field-block.tsx",
"content": "'use client';\n\nimport { FileField } from '@/components/upload/file-field';\nimport { DOCUMENT_ACCEPT } from '@/components/upload/upload-utils';\nimport {\n UploaderProvider,\n type UploadFn,\n} from '@/components/upload/uploader-provider';\nimport * as React from 'react';\n\nexport default function FileFieldBlock() {\n const { edgestore } = useMockEdgeStore(); // Mock edgestore for easy v0 integration\n\n const uploadFn: UploadFn = React.useCallback(\n async ({ file, signal, onProgressChange }) => {\n const res = await edgestore.myPublicFiles.upload({\n file,\n signal,\n onProgressChange,\n });\n // you can run some server action or api here\n // to add the necessary data to your database\n return { url: res.url };\n },\n [edgestore],\n );\n\n return (\n <div className=\"flex flex-col items-center gap-4 p-4\">\n <div className=\"grid w-full max-w-md gap-1.5\">\n <label\n id=\"resume-label\"\n htmlFor=\"resume-input\"\n className=\"text-sm font-medium\"\n >\n Resume\n </label>\n <UploaderProvider uploadFn={uploadFn} autoUpload>\n <FileField\n inputId=\"resume-input\"\n aria-labelledby=\"resume-label\"\n accept={DOCUMENT_ACCEPT}\n typesLabel=\"PDF, DOC or DOCX\"\n maxSize={1024 * 1024 * 5} // 5MB\n />\n </UploaderProvider>\n </div>\n </div>\n );\n}\n\n// Mock implementation of EdgeStore\nfunction useMockEdgeStore() {\n return {\n edgestore: {\n myPublicFiles: {\n upload: async ({\n signal,\n onProgressChange,\n }: {\n file: File;\n signal?: AbortSignal;\n onProgressChange?: (progress: number) => void | Promise<void>;\n }) => {\n // Simulate upload progress. Rejects like EdgeStore when the upload is aborted.\n await new Promise<void>((resolve, reject) => {\n let progress = 0;\n const interval = setInterval(() => {\n progress = Math.min(\n progress + Math.floor(Math.random() * 21) + 10,\n 100,\n );\n void onProgressChange?.(progress);\n if (progress >= 100) {\n clearInterval(interval);\n resolve();\n }\n }, 300);\n signal?.addEventListener('abort', () => {\n clearInterval(interval);\n reject(new DOMException('Upload aborted', 'AbortError'));\n });\n });\n\n return {\n url: 'https://edgestore.dev/img/upload-demo.webp',\n };\n },\n },\n },\n };\n}\n",
"type": "registry:block",
"target": "components/upload/blocks/file-field-block.tsx"
"type": "registry:page",
"target": "app/page.tsx"
}
],
"type": "registry:block"
Expand Down
Loading
Loading