Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: getInputProps #746

Open
wants to merge 60 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
d04eec6
first lets move some stuff
juliusmarminge Apr 5, 2024
3481530
move input props to hook
juliusmarminge Apr 5, 2024
ca176fe
ncieeee
juliusmarminge Apr 6, 2024
db16244
nicee
juliusmarminge Apr 6, 2024
655e27b
[wip] custom component example
juliusmarminge Apr 7, 2024
00d2d84
Merge branch 'main' into input-props
juliusmarminge Apr 13, 2024
2435570
merge
juliusmarminge Apr 13, 2024
abd83c5
init demo
juliusmarminge Apr 13, 2024
ec486df
Merge branch 'main' into input-props
juliusmarminge Apr 13, 2024
c1d8139
gettin somewher
juliusmarminge Apr 13, 2024
7f307cf
nit
juliusmarminge Apr 13, 2024
4dd50a1
refactor useDropzone a bit
juliusmarminge Apr 13, 2024
1649f8c
nice
juliusmarminge Apr 13, 2024
467cc66
null
juliusmarminge Apr 13, 2024
cc8f222
fix solid
juliusmarminge Apr 13, 2024
f4584df
fix svelte
juliusmarminge Apr 13, 2024
160ff6c
minify type output
juliusmarminge Apr 13, 2024
e506f61
minify type output for solid and svelte too
juliusmarminge Apr 13, 2024
c111b41
undefined is more natural here
juliusmarminge Apr 13, 2024
fce1a94
fmt
juliusmarminge Apr 13, 2024
564436d
fix svelte linting
juliusmarminge Apr 13, 2024
366a776
re-export useful helper from shared
juliusmarminge Apr 14, 2024
7d115b8
eh
juliusmarminge Apr 15, 2024
c0c15c4
rhf tests
juliusmarminge Apr 15, 2024
fa3d69b
break out
juliusmarminge Apr 15, 2024
6839f2f
check dirty
juliusmarminge Apr 15, 2024
2176789
skippolling
juliusmarminge Apr 15, 2024
84eab1f
auto mode
juliusmarminge Apr 15, 2024
9567b3a
nice
juliusmarminge Apr 15, 2024
3df628c
simple nav
juliusmarminge Apr 15, 2024
66e0cbf
nice
juliusmarminge Apr 15, 2024
f6c6d3b
rm unused
juliusmarminge Apr 15, 2024
8f9e823
rm log
juliusmarminge Apr 15, 2024
bff3a88
simplify
juliusmarminge Apr 15, 2024
5573faa
nice
juliusmarminge Apr 15, 2024
338c61f
with-novel example
juliusmarminge Apr 16, 2024
f9d13c0
readme
juliusmarminge Apr 16, 2024
b559318
nice
juliusmarminge Apr 16, 2024
fd53c56
rename
juliusmarminge Apr 16, 2024
0f08bc0
fix
juliusmarminge Apr 16, 2024
2f03be4
Merge branch 'main' into input-props
juliusmarminge May 12, 2024
32800eb
fix dupe
juliusmarminge May 12, 2024
7ab2c32
Merge branch 'main' into input-props
juliusmarminge May 12, 2024
6c906dc
fix some types
juliusmarminge May 12, 2024
a9431a7
fix more
juliusmarminge May 12, 2024
88576c8
rm ts-expect-error's
juliusmarminge May 12, 2024
7d18883
fix more types
juliusmarminge May 12, 2024
2aacc64
Merge branch 'main' into input-props
markflorkowski May 24, 2024
bc43e09
Merge branch 'main' into input-props
markflorkowski May 25, 2024
5bf7ea3
Merge branch 'main' into input-props
markflorkowski May 29, 2024
53312d7
chore: migrate vue off of `permittedFileInfo` (#837)
markflorkowski Jun 3, 2024
1caf977
chore: Add redirects to docs nextconfig (#843)
markflorkowski May 31, 2024
e0e4740
Merge branch 'main' into input-props
juliusmarminge Jun 3, 2024
a214d80
rm shared dep from pg
juliusmarminge Jun 3, 2024
0c94c52
Merge branch 'main' into input-props
markflorkowski Jun 24, 2024
35d4782
pnpm i
markflorkowski Jun 24, 2024
7182285
remove duplicate imports
markflorkowski Jun 24, 2024
8c592a6
format
markflorkowski Jun 24, 2024
cdb4c0c
Merge branch 'main' into input-props
juliusmarminge Jun 25, 2024
6d0abe7
Merge branch 'main' into input-props
juliusmarminge Jun 26, 2024
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
Prev Previous commit
Next Next commit
[wip] custom component example
juliusmarminge committed Apr 7, 2024
commit 655e27b889bd715ebd93283dbee10088be9a60f3
Binary file modified bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions examples/custom-components/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Go to https://uploadthing.com/dashboard to get your API secret
UPLOADTHING_SECRET='sk_live_xxx'
UPLOADTHING_APP_ID='xxx'
18 changes: 18 additions & 0 deletions examples/custom-components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Minimal Next.js App Router example for UploadThing

<a href="https://stackblitz.com/github/pingdotgg/uploadthing/tree/main/examples/with-tailwindcss">
<img height="64" src="https://github.com/pingdotgg/uploadthing/assets/51714798/45907a4e-aa64-401a-afb3-b6c6df6eb71f" />
</a>

## QuickStart

1. Grab an API key from the UploadThing dashboard:
https://uploadthing.com/dashboard
2. `cp .env.example .env` and paste in your API key in the newly created `.env`
file
3. `bun dev`
4. Upload files!

## Further reference

Check out the docs at: https://docs.uploadthing.com/getting-started/appdir
16 changes: 16 additions & 0 deletions examples/custom-components/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css",
"baseColor": "gray",
"cssVariables": false
},
"aliases": {
"utils": "~/lib/utils",
"components": "~/components"
}
}
5 changes: 5 additions & 0 deletions examples/custom-components/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
7 changes: 7 additions & 0 deletions examples/custom-components/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
eslint: { ignoreDuringBuilds: true },
typescript: { ignoreBuildErrors: true },
};

module.exports = nextConfig;
34 changes: 34 additions & 0 deletions examples/custom-components/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@example/custom-components",
"private": true,
"scripts": {
"dev": "next dev",
"clean": "git clean -xdf .next node_modules",
"build": "next build",
"start": "next start",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@uploadthing/react": "workspace:6.4.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"lucide-react": "^0.365.0",
"next": "14.1.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7",
"uploadthing": "workspace:6.7.0"
},
"devDependencies": {
"@types/node": "^20.11.21",
"@types/react": "18.2.60",
"@types/react-dom": "18.2.19",
"postcss": "8.4.38",
"tailwindcss": "^3.4.1",
"typescript": "^5.4.2"
}
}
5 changes: 5 additions & 0 deletions examples/custom-components/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
plugins: {
tailwindcss: {},
},
};
9 changes: 9 additions & 0 deletions examples/custom-components/src/app/api/uploadthing/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createRouteHandler } from "uploadthing/next";

import { uploadRouter } from "~/server/uploadthing";

// export const runtime = "edge";

export const { GET, POST } = createRouteHandler({
router: uploadRouter,
});
3 changes: 3 additions & 0 deletions examples/custom-components/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
25 changes: 25 additions & 0 deletions examples/custom-components/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Inter } from "next/font/google";

import "./globals.css";

import { NextSSRPlugin } from "@uploadthing/react/next-ssr-plugin";
import { extractRouterConfig } from "uploadthing/server";

import { uploadRouter } from "~/server/uploadthing";

const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={["font-sans", inter.variable].join(" ")}>
<NextSSRPlugin routerConfig={extractRouterConfig(uploadRouter)} />
{children}
</body>
</html>
);
}
9 changes: 9 additions & 0 deletions examples/custom-components/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Uploader } from "./uploader";

export default function Home() {
return (
<main className="mx-auto w-full max-w-7xl p-16">
<Uploader />
</main>
);
}
106 changes: 106 additions & 0 deletions examples/custom-components/src/app/uploader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"use client";

import { Suspense, use } from "react";
import { Loader2, UploadIcon, XIcon } from "lucide-react";

import { generatePermittedFileTypes } from "@uploadthing/shared";

import { Button } from "~/components/ui/button";
import { Card } from "~/components/ui/card";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import { useUploadThing } from "~/utils/uploadthing";

const fileToDataURL = async (file: File) => {
const reader = new FileReader();
return new Promise<string>((resolve, reject) => {
reader.onload = () => resolve(reader.result as string);
reader.onerror = reject;
reader.readAsDataURL(file);
});
};

export function Uploader() {
const {
startUpload,
getInputProps,
files,
setFiles,
isUploading,
uploadProgress,
permittedFileInfo,
} = useUploadThing("videoAndImage");
const { fileTypes } = generatePermittedFileTypes(permittedFileInfo?.config);

return (
<div className="grid w-full gap-4 px-4">
<div className="mx-auto flex w-1/2 flex-col gap-4">
<div className="flex items-center justify-center gap-4 rounded-lg border border-dashed border-gray-300 p-6 text-center dark:border-gray-800">
<div className="grid gap-1.5">
<Label className="dark:peer-overflow-hidden peer-overflow-hidden flex w-full cursor-pointer items-center gap-2 rounded-md border border-gray-300 p-4 text-sm transition-colors [&:has(:focus)]:outline-none [&:has(:focus)]:ring-2 [&:has(:focus)]:ring-gray-200 dark:[&:has(:focus)]:ring-gray-800">
<UploadIcon className="h-6 w-6" />
<span className="peer-overflow-ellipsis">
Choose a file to upload
</span>
<Input
className="sr-only"
{...getInputProps({ mode: "manual" })}
/>
</Label>
<p className="text-xs text-gray-500 dark:text-gray-400">
Supported file types: {fileTypes.join(", ")}
</p>
</div>
</div>
<Button
size="sm"
className="flex"
onClick={() => startUpload(files)}
disabled={isUploading}
>
{isUploading ? (
<span>
<Loader2 /> Uploading... {uploadProgress?.toFixed(2)}%
</span>
) : (
<span>Upload</span>
)}
</Button>
</div>

<div className="grid grid-cols-3 gap-4">
{files.map((file) => (
<Suspense fallback={null}>
<PreviewCard
file={file}
deselect={() =>
setFiles((files) => files.filter((f) => f !== file))
}
/>
</Suspense>
))}
</div>
</div>
);
}

function PreviewCard(props: { file: File; deselect: () => void }) {
const data = use(fileToDataURL(props.file));

return (
<Card className="flex flex-col gap-2 p-2">
<div className="flex items-center justify-between gap-4">
<span className="text-sm">{props.file.name}</span>
<Button className="h-max w-max p-1" onClick={props.deselect}>
<XIcon className="h-4 w-4" />
<span className="sr-only">Remove</span>
</Button>
</div>
<img
alt={`Preview of ${props.file.name}`}
className="aspect-[4/3] overflow-hidden rounded-lg object-cover"
src={data}
/>
</Card>
);
}
58 changes: 58 additions & 0 deletions examples/custom-components/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "~/lib/utils";

const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-gray-950 dark:focus-visible:ring-gray-300",
{
variants: {
variant: {
default:
"bg-gray-900 text-gray-50 hover:bg-gray-900/90 dark:bg-gray-50 dark:text-gray-900 dark:hover:bg-gray-50/90",
destructive:
"bg-red-500 text-gray-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-gray-50 dark:hover:bg-red-900/90",
outline:
"border border-gray-200 bg-white hover:bg-gray-100 hover:text-gray-900 dark:border-gray-800 dark:bg-gray-950 dark:hover:bg-gray-800 dark:hover:text-gray-50",
secondary:
"bg-gray-100 text-gray-900 hover:bg-gray-100/80 dark:bg-gray-800 dark:text-gray-50 dark:hover:bg-gray-800/80",
ghost:
"hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-50",
link: "text-gray-900 underline-offset-4 hover:underline dark:text-gray-50",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = "Button";

export { Button, buttonVariants };
86 changes: 86 additions & 0 deletions examples/custom-components/src/components/ui/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import * as React from "react";

import { cn } from "~/lib/utils";

const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border border-gray-200 bg-white text-gray-950 shadow-sm dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50",
className,
)}
{...props}
/>
));
Card.displayName = "Card";

const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
));
CardHeader.displayName = "CardHeader";

const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className,
)}
{...props}
/>
));
CardTitle.displayName = "CardTitle";

const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-gray-500 dark:text-gray-400", className)}
{...props}
/>
));
CardDescription.displayName = "CardDescription";

const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
));
CardContent.displayName = "CardContent";

const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
));
CardFooter.displayName = "CardFooter";

export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};
Loading