From 0d24d878e2c05105c156b7df5708fbf67c738809 Mon Sep 17 00:00:00 2001
From: Ravi <103035973+raviships@users.noreply.github.com>
Date: Sun, 11 Oct 2026 17:55:58 +0900
Subject: [PATCH 01/13] docs: standardize EdgeStore branding
---
docs/content/docs/components/uploader-provider.mdx | 2 +-
docs/src/app/(main)/pricing/_components/pricing.tsx | 4 ++--
docs/src/lib/testimonials.ts | 8 ++++----
docs/src/scripts/download-images.ts | 10 +++++-----
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/docs/content/docs/components/uploader-provider.mdx b/docs/content/docs/components/uploader-provider.mdx
index 66b51c72..44fa59d0 100644
--- a/docs/content/docs/components/uploader-provider.mdx
+++ b/docs/content/docs/components/uploader-provider.mdx
@@ -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,
diff --git a/docs/src/app/(main)/pricing/_components/pricing.tsx b/docs/src/app/(main)/pricing/_components/pricing.tsx
index 3b10a080..9571eddf 100644
--- a/docs/src/app/(main)/pricing/_components/pricing.tsx
+++ b/docs/src/app/(main)/pricing/_components/pricing.tsx
@@ -224,7 +224,7 @@ function buildPricingBlocks(
id: 'STARTER',
title: 'Starter',
description:
- 'Best for start-ups and businesses who build commercial products with Edge Store.',
+ 'Best for start-ups and businesses who build commercial products with EdgeStore.',
price: toDollars(defaultPricing.STARTER.basePrice, 5),
upcoming: toUpcoming(upcomingPricing?.STARTER),
features: [
@@ -286,7 +286,7 @@ function buildPricingBlocks(
id: 'PRO',
title: 'Pro',
description:
- 'Best for businesses who build larger commercial products with Edge Store.',
+ 'Best for businesses who build larger commercial products with EdgeStore.',
price: toDollars(defaultPricing.PRO.basePrice, 35),
upcoming: toUpcoming(upcomingPricing?.PRO),
features: [
diff --git a/docs/src/lib/testimonials.ts b/docs/src/lib/testimonials.ts
index 084caf81..fee17da4 100644
--- a/docs/src/lib/testimonials.ts
+++ b/docs/src/lib/testimonials.ts
@@ -19,7 +19,7 @@ export const testimonials = [
user: '@sathishkannan6600',
image: '/img/testimonials/sathishkannan6600.jpg',
comment:
- 'Unbelievable and exhaustive features.Edge store thought about all the use cases. Also, not using a database for protected files is a nice idea. Very clear explanation in the video.',
+ 'Unbelievable and exhaustive features.EdgeStore thought about all the use cases. Also, not using a database for protected files is a nice idea. Very clear explanation in the video.',
platform: 'youtube',
url: 'https://www.youtube.com/watch?v=Acq9UEA2akU&lc=Ugw4ne4z1Pj3NS_MGbB4AaABAg',
},
@@ -35,7 +35,7 @@ export const testimonials = [
user: '@PhilippeKhin',
image: '/img/testimonials/PhilippeKhin.jpg',
comment:
- "Feeling that Edge Store will take off 🚀 Great stuff you're building here Ravi 👍",
+ "Feeling that EdgeStore will take off 🚀 Great stuff you're building here Ravi 👍",
platform: 'youtube',
url: 'https://www.youtube.com/watch?v=Acq9UEA2akU&lc=UgyEH4ERhW0fXigeWN14AaABAg',
},
@@ -82,7 +82,7 @@ export const testimonials = [
user: '@developerpranav',
image: '/img/testimonials/developerpranav.jpg',
comment:
- '🤯 Blown away by the simplicity of defining the types of asset uploaded, which then determines the file path. Awesome video, and amazing job on Edge Store btw! Highly considering it for my current project! Just one question, can I use my own S3 Bucket? Specifically, I use Cloudflare R2 which has compatibility with the S3 API.',
+ '🤯 Blown away by the simplicity of defining the types of asset uploaded, which then determines the file path. Awesome video, and amazing job on EdgeStore btw! Highly considering it for my current project! Just one question, can I use my own S3 Bucket? Specifically, I use Cloudflare R2 which has compatibility with the S3 API.',
platform: 'youtube',
url: 'https://www.youtube.com/watch?v=Acq9UEA2akU&lc=UgxL7xpOk8ygYV7iYgx4AaABAg',
},
@@ -141,7 +141,7 @@ export const testimonials = [
user: '@alijansoomro4277',
image: '/img/testimonials/alijansoomro4277.jpg',
comment:
- 'This service looks easier to use than UploadThing — I was looking for a better way to upload files in Next-JS, and I like Edge Store.',
+ 'This service looks easier to use than UploadThing — I was looking for a better way to upload files in Next-JS, and I like EdgeStore.',
platform: 'youtube',
url: 'https://www.youtube.com/watch?v=Acq9UEA2akU&lc=Ugw9Jvy13TVCEXCvftR4AaABAg',
},
diff --git a/docs/src/scripts/download-images.ts b/docs/src/scripts/download-images.ts
index 411e0f1c..4add6005 100644
--- a/docs/src/scripts/download-images.ts
+++ b/docs/src/scripts/download-images.ts
@@ -21,14 +21,14 @@ const testimonials = [
image:
'https://yt3.ggpht.com/ytc/AIdro_nzjrEGEW1ljvq0slQBOeXcZwQqHlmFzyPXXTdRQf6ZP8E=s88-c-k-c0x00ffffff-no-rj',
comment:
- 'Unbelievable and exhaustive features.Edge store thought about all the use cases. Also, not using a database for protected files is a nice idea. Very clear explanation in the video.',
+ 'Unbelievable and exhaustive features.EdgeStore thought about all the use cases. Also, not using a database for protected files is a nice idea. Very clear explanation in the video.',
},
{
user: '@PhilippeKhin',
image:
'https://yt3.ggpht.com/ytc/AIdro_noIo8kfGBJIlJ3OqosAAIx0Wmce06n5_N-OYSxM5AhvGI=s88-c-k-c0x00ffffff-no-rj',
comment:
- "Feeling that Edge Store will take off 🚀 Great stuff you're building here Ravi 👍",
+ "Feeling that EdgeStore will take off 🚀 Great stuff you're building here Ravi 👍",
},
{
user: '@IyanSR',
@@ -55,7 +55,7 @@ const testimonials = [
image:
'https://yt3.ggpht.com/ytc/AIdro_kA5_GhiyHqNvdgi44X2S1x2fkUP98mX--QS0B_N9xNGPs=s88-c-k-c0x00ffffff-no-rj',
comment:
- '🤯 Blown away by the simplicity of defining the types of asset uploaded, which then determines the file path. Awesome video, and amazing job on Edge Store btw! Highly considering it for my current project! Just one question, can I use my own S3 Bucket? Specifically, I use Cloudflare R2 which has compatibility with the S3 API.',
+ '🤯 Blown away by the simplicity of defining the types of asset uploaded, which then determines the file path. Awesome video, and amazing job on EdgeStore btw! Highly considering it for my current project! Just one question, can I use my own S3 Bucket? Specifically, I use Cloudflare R2 which has compatibility with the S3 API.',
},
{
user: '@ryanpp27',
@@ -106,13 +106,13 @@ const testimonials = [
image:
'https://yt3.ggpht.com/ytc/AIdro_lBj2_SaydLARaf_VD4cxIDjF_cmHeL_5YSGeFUIfycc9w=s88-c-k-c0x00ffffff-no-rj',
comment:
- 'This service looks easier to use than UploadThing — I was looking for a better way to upload files in Next-JS, and I like Edge Store.',
+ 'This service looks easier to use than UploadThing — I was looking for a better way to upload files in Next-JS, and I like EdgeStore.',
},
{
user: '@hikmatullah2131',
image:
'https://yt3.ggpht.com/NLFF28hZDwFf8SnxYbPyiTb9Gzg8jxa3mfC_4OYmo2gOuHmyuVTXWc9XMHgaJQAsoeBPQkXz4g=s88-c-k-c0x00ffffff-no-rj',
- comment: 'You covered a lot in a short time, and I love Edge Store too.',
+ comment: 'You covered a lot in a short time, and I love EdgeStore too.',
},
];
From 1d9c50aba6cd92567af50082daf5755969fcac5f Mon Sep 17 00:00:00 2001
From: Ravi <103035973+raviships@users.noreply.github.com>
Date: Sun, 11 Oct 2026 18:16:47 +0900
Subject: [PATCH 02/13] fix: repair website links and component setup flows
---
.../content/docs/components/upload-button.mdx | 4 +-
docs/public/r/avatar-dropzone-block.json | 4 +-
docs/public/r/file-field-block.json | 4 +-
docs/public/r/file-uploader-block.json | 4 +-
docs/public/r/multi-image-uploader-block.json | 4 +-
docs/public/r/progress-bar-block.json | 4 +-
docs/public/r/progress-circle-block.json | 4 +-
docs/public/r/registry.json | 32 ++++++-------
.../public/r/single-image-dropzone-block.json | 4 +-
docs/public/r/upload-button-block.json | 4 +-
.../(main)/pricing/_components/pricing.tsx | 3 +-
docs/src/components/ui/open-tabs.tsx | 45 ++++++++++++++++++-
docs/src/lib/constants.ts | 4 +-
registry.json | 32 ++++++-------
14 files changed, 96 insertions(+), 56 deletions(-)
diff --git a/docs/content/docs/components/upload-button.mdx b/docs/content/docs/components/upload-button.mdx
index 3ec36b89..38d6f82c 100644
--- a/docs/content/docs/components/upload-button.mdx
+++ b/docs/content/docs/components/upload-button.mdx
@@ -18,7 +18,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps';
-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`. To show a file list, also install [Multi-file](./multi-file) and add its `FileList`, or build your own list with `useUploader`.
## Installation
@@ -87,7 +87,6 @@ Install or copy the component from [Installation](#installation) before using th
'use client';
import { UploadErrors } from '@/components/upload/dropzone';
-import { FileList } from '@/components/upload/multi-file';
import { UploadButton } from '@/components/upload/upload-button';
import {
UploaderProvider,
@@ -125,7 +124,6 @@ export function UploadButtonUsage() {
Upload files
setErrors([])} />
-
);
}
diff --git a/docs/public/r/avatar-dropzone-block.json b/docs/public/r/avatar-dropzone-block.json
index d67a5e3c..7994f694 100644
--- a/docs/public/r/avatar-dropzone-block.json
+++ b/docs/public/r/avatar-dropzone-block.json
@@ -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
\n
\n \n \n \n
\n
\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;\n }) => {\n // Simulate upload progress. Rejects like EdgeStore when the upload is aborted.\n await new Promise((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"
diff --git a/docs/public/r/file-field-block.json b/docs/public/r/file-field-block.json
index 655e44b4..e93770a7 100644
--- a/docs/public/r/file-field-block.json
+++ b/docs/public/r/file-field-block.json
@@ -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
\n
\n \n \n \n \n
\n
\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;\n }) => {\n // Simulate upload progress. Rejects like EdgeStore when the upload is aborted.\n await new Promise((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"
diff --git a/docs/public/r/file-uploader-block.json b/docs/public/r/file-uploader-block.json
index fab6dd14..6cabbfec 100644
--- a/docs/public/r/file-uploader-block.json
+++ b/docs/public/r/file-uploader-block.json
@@ -11,8 +11,8 @@
{
"path": "examples/components/src/components/upload/blocks/multi-file-block.tsx",
"content": "'use client';\n\nimport { FileUploader } from '@/components/upload/multi-file';\nimport {\n UploaderProvider,\n useUploader,\n type CompletedFileState,\n type UploadFn,\n} from '@/components/upload/uploader-provider';\nimport * as React from 'react';\n\nexport default function FileUploaderBlock() {\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
- );
-}
```
## Props
From 6c999d5f55f4832b36f0f57b4367e4ac62558d22 Mon Sep 17 00:00:00 2001
From: Ravi <103035973+raviships@users.noreply.github.com>
Date: Tue, 13 Oct 2026 19:47:20 +0900
Subject: [PATCH 07/13] fix: limit the PR to website link fixes
---
docs/src/components/ui/open-tabs.tsx | 73 +---------------------------
1 file changed, 2 insertions(+), 71 deletions(-)
diff --git a/docs/src/components/ui/open-tabs.tsx b/docs/src/components/ui/open-tabs.tsx
index b3cb024c..9cafdea3 100644
--- a/docs/src/components/ui/open-tabs.tsx
+++ b/docs/src/components/ui/open-tabs.tsx
@@ -4,74 +4,7 @@ import { cn } from '@/lib/utils';
import * as TabsPrimitive from '@radix-ui/react-tabs';
import * as React from 'react';
-const OpenTabs = React.forwardRef<
- React.ComponentRef,
- React.ComponentPropsWithoutRef
->(({ value: controlledValue, defaultValue, onValueChange, ...props }, ref) => {
- const root = React.useRef(null);
- const [value, setValue] = React.useState(defaultValue);
- const changeValue = React.useCallback(
- (nextValue: string) => {
- setValue(nextValue);
- onValueChange?.(nextValue);
- },
- [onValueChange],
- );
-
- React.useEffect(() => {
- let frame = 0;
- function revealAnchor() {
- const target = document.getElementById(window.location.hash.slice(1));
- if (!target || !root.current?.contains(target)) return;
- const panel = target.closest('[role="tabpanel"]');
- if (panel?.getAttribute('data-state') !== 'inactive') return;
-
- const tabValue = panel.getAttribute('data-value');
- if (!tabValue) return;
- changeValue(tabValue);
- frame = requestAnimationFrame(() => target.scrollIntoView());
- }
-
- function onAnchorClick(event: MouseEvent) {
- if (
- event.button !== 0 ||
- event.metaKey ||
- event.ctrlKey ||
- event.shiftKey ||
- event.altKey
- ) {
- return;
- }
- const anchor =
- event.target instanceof Element ? event.target.closest('a') : null;
- // Clicking the current anchor does not emit another hashchange.
- if (anchor?.href === window.location.href) revealAnchor();
- }
-
- revealAnchor();
- window.addEventListener('hashchange', revealAnchor);
- document.addEventListener('click', onAnchorClick);
- return () => {
- window.removeEventListener('hashchange', revealAnchor);
- document.removeEventListener('click', onAnchorClick);
- cancelAnimationFrame(frame);
- };
- }, [changeValue]);
-
- return (
- {
- root.current = element;
- if (typeof ref === 'function') return ref(element);
- if (ref) ref.current = element;
- }}
- />
- );
-});
-OpenTabs.displayName = TabsPrimitive.Root.displayName;
+const OpenTabs = TabsPrimitive.Root;
const OpenTabsList = React.forwardRef<
React.ComponentRef,
@@ -109,10 +42,8 @@ const OpenTabsContent = React.forwardRef<
>(({ className, ...props }, ref) => (
Date: Tue, 13 Oct 2026 20:38:07 +0900
Subject: [PATCH 08/13] fix: move file list into its own registry item
Upload button usage and block, and file field, imported FileList/FileListItem
from multi-file without the matching registry dependency. Extract FileBadge,
FileListItem and FileList into file-list.tsx with a file-list registry item.
Co-Authored-By: Claude Opus 5.5
---
docs/content/docs/components/file-field.mdx | 2 +-
docs/content/docs/components/file-list.mdx | 103 +++++++++
docs/content/docs/components/multi-file.mdx | 8 +-
.../content/docs/components/upload-button.mdx | 10 +-
docs/content/docs/meta.json | 1 +
docs/public/r/file-field.json | 11 +-
docs/public/r/file-list.json | 23 ++
docs/public/r/file-uploader.json | 4 +-
docs/public/r/registry.json | 25 ++-
docs/public/r/upload-button-block.json | 4 +-
.../upload/blocks/upload-button-block.tsx | 2 +-
docs/src/components/upload/file-field.tsx | 2 +-
docs/src/components/upload/file-list.tsx | 196 ++++++++++++++++++
docs/src/components/upload/multi-file.tsx | 195 +----------------
.../src/app/(tabs)/buttons/page.tsx | 2 +-
.../upload/blocks/upload-button-block.tsx | 2 +-
.../src/components/upload/file-field.tsx | 2 +-
.../src/components/upload/file-list.tsx | 196 ++++++++++++++++++
.../src/components/upload/multi-file.tsx | 195 +----------------
registry.json | 25 ++-
scripts/agentDocs/selection.ts | 1 +
21 files changed, 596 insertions(+), 413 deletions(-)
create mode 100644 docs/content/docs/components/file-list.mdx
create mode 100644 docs/public/r/file-list.json
create mode 100644 docs/src/components/upload/file-list.tsx
create mode 100644 examples/components/src/components/upload/file-list.tsx
diff --git a/docs/content/docs/components/file-field.mdx b/docs/content/docs/components/file-field.mdx
index e1f527ad..8cbd38de 100644
--- a/docs/content/docs/components/file-field.mdx
+++ b/docs/content/docs/components/file-field.mdx
@@ -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)
diff --git a/docs/content/docs/components/file-list.mdx b/docs/content/docs/components/file-list.mdx
new file mode 100644
index 00000000..4ad48a0b
--- /dev/null
+++ b/docs/content/docs/components/file-list.mdx
@@ -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.
+
+
+ The [multi-file](./multi-file) and [file field](./file-field) components
+ install it automatically via the CLI.
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+
+Use the shadcn CLI to add the component to your project.
+
+```package-install
+npx shadcn@latest add https://edgestore.dev/r/file-list.json
+```
+
+
+
+
+
+
+
+
+
+### Setup for manual installation
+
+First you will need to follow the [manual install setup](./manual-install) guide.
+
+
+
+
+
+### Install required components
+
+- [uploader-provider](./uploader-provider)
+- [progress-bar](./progress-bar)
+
+
+
+
+
+### Copy this component
+
+
+
+../../../src/components/upload/file-list.tsx
+
+../../../src/components/upload/upload-utils.ts
+
+
+
+
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+
+ {/* anything that adds files, e.g. */}
+
+
+```
+
+## Props
+
+| Prop | Type | Default | Description |
+| ---------- | --------- | ------- | ------------------------------------------- |
+| `disabled` | `boolean` | `false` | Hides the retry, cancel and remove actions. |
+| `...` | | | Any other `
` prop, such as `className`. |
diff --git a/docs/content/docs/components/multi-file.mdx b/docs/content/docs/components/multi-file.mdx
index a2c46bd6..f2706d40 100644
--- a/docs/content/docs/components/multi-file.mdx
+++ b/docs/content/docs/components/multi-file.mdx
@@ -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)
@@ -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.
diff --git a/docs/content/docs/components/upload-button.mdx b/docs/content/docs/components/upload-button.mdx
index 3ec36b89..a5bf8a02 100644
--- a/docs/content/docs/components/upload-button.mdx
+++ b/docs/content/docs/components/upload-button.mdx
@@ -18,7 +18,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps';
-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
@@ -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,
diff --git a/docs/content/docs/meta.json b/docs/content/docs/meta.json
index 6c84954e..e9cd52c0 100644
--- a/docs/content/docs/meta.json
+++ b/docs/content/docs/meta.json
@@ -18,6 +18,7 @@
"components/avatar",
"components/file-field",
"components/upload-button",
+ "components/file-list",
"components/uploader-provider",
"components/dropzone",
"components/progress-circle",
diff --git a/docs/public/r/file-field.json b/docs/public/r/file-field.json
index f8b49b5f..845eaf86 100644
--- a/docs/public/r/file-field.json
+++ b/docs/public/r/file-field.json
@@ -3,20 +3,23 @@
"name": "file-field",
"title": "File Field",
"description": "A compact single-file input that sits in a form next to regular fields.",
- "dependencies": ["react-dropzone", "lucide-react"],
+ "dependencies": [
+ "react-dropzone",
+ "lucide-react"
+ ],
"registryDependencies": [
"https://edgestore.dev/r/dropzone.json",
- "https://edgestore.dev/r/file-uploader.json",
+ "https://edgestore.dev/r/file-list.json",
"https://edgestore.dev/r/uploader-provider.json",
"https://edgestore.dev/r/upload-utils.json"
],
"files": [
{
"path": "examples/components/src/components/upload/file-field.tsx",
- "content": "'use client';\n\nimport { cn } from '@/lib/utils';\nimport { UploadIcon } from 'lucide-react';\nimport * as React from 'react';\nimport { type Accept } from 'react-dropzone';\nimport { dropzoneState, dropzoneVariants, useUploadDropzone } from './dropzone';\nimport { FileListItem } from './multi-file';\nimport { formatFileSize } from './upload-utils';\nimport { useUploader } from './uploader-provider';\n\n/**\n * Props for the FileField component.\n */\nexport type FileFieldProps = Omit, 'children'> & {\n /**\n * Accepted file types.\n */\n accept?: Accept;\n\n /**\n * Human-readable list of accepted types, shown in the hint and messages.\n *\n * @example \"PDF, DOC or DOCX\"\n */\n typesLabel?: string;\n\n /**\n * Maximum file size in bytes.\n */\n maxSize?: number;\n\n /**\n * Whether the field is disabled.\n */\n disabled?: boolean;\n\n /**\n * Id for the hidden file input, so a `