├── .prettierrc.json ├── app ├── favicon.ico ├── not-found.tsx ├── page.tsx ├── (secondary) │ ├── preview │ │ ├── layout.tsx │ │ ├── animated-form │ │ │ └── page.tsx │ │ ├── animated-otp │ │ │ └── page.tsx │ │ ├── security-card │ │ │ └── page.tsx │ │ ├── bot-detection │ │ │ └── page.tsx │ │ ├── animated-tabs │ │ │ └── page.tsx │ │ ├── onboard-card │ │ │ └── page.tsx │ │ ├── stats-card │ │ │ └── page.tsx │ │ ├── framework-agnostic │ │ │ └── page.tsx │ │ ├── notification-center │ │ │ └── page.tsx │ │ ├── text-shimmer │ │ │ └── page.tsx │ │ ├── vault-lock │ │ │ └── page.tsx │ │ └── fraud-card │ │ │ └── page.tsx │ ├── privacypolicy │ │ └── page.tsx │ └── termsofservice │ │ └── page.tsx └── (primary) │ ├── components │ ├── framework-agnostic │ │ ├── _components │ │ │ └── frameworkagnostic.css │ │ └── page.tsx │ ├── fraud-card │ │ ├── _components │ │ │ └── fraudcard.css │ │ └── page.tsx │ ├── stats-card │ │ ├── _components │ │ │ └── statscard.css │ │ └── page.tsx │ ├── security-card │ │ ├── _components │ │ │ └── security-card.css │ │ └── page.tsx │ ├── text-reveal │ │ ├── _components │ │ │ └── text-reveal.tsx │ │ └── page.tsx │ ├── text-shimmer │ │ ├── _components │ │ │ └── text-shimmer.tsx │ │ └── page.tsx │ ├── page.tsx │ ├── animated-tabs │ │ ├── page.tsx │ │ └── _components │ │ │ └── animated-tabs.tsx │ ├── vault-lock │ │ └── page.tsx │ ├── onboard-card │ │ └── page.tsx │ ├── expandable-card │ │ └── page.tsx │ ├── social-card │ │ └── page.tsx │ ├── animated-otp │ │ └── page.tsx │ ├── bot-detection │ │ └── page.tsx │ ├── notification-center │ │ └── page.tsx │ └── animated-form │ │ └── page.tsx │ ├── layout.tsx │ └── docs │ ├── page.tsx │ ├── install-tailwindcss │ └── page.tsx │ ├── introduction │ └── page.tsx │ └── install-nextjs │ └── page.tsx ├── public ├── pfp.png ├── demopfp.png ├── logo-ui.png ├── newlogo.png ├── robots.txt ├── assets │ ├── gojo.png │ └── toji.png ├── logo-ui-new.png ├── forgeui-ogimage-v2.png ├── vercel.svg ├── window.svg ├── file.svg ├── globe.svg ├── next.svg ├── effect.svg └── r │ ├── text-reveal.json │ └── text-shimmer.json ├── .gitattributes ├── postcss.config.mjs ├── next.config.ts ├── lib ├── utils.ts ├── getNavigationItems.ts └── getNavigationFeaturedItems.ts ├── LICENSE.txt ├── provider ├── theme-provider.tsx └── provider.tsx ├── components ├── layout │ ├── livepreview.tsx │ ├── lazy-show.tsx │ ├── anchor-nav.tsx │ └── navbar.tsx ├── content │ ├── maincontentcontainer.tsx │ ├── screen-notice.tsx │ ├── clidependencies.tsx │ ├── previewcomponentcontainer.tsx │ ├── dependencies.tsx │ ├── maintitle.tsx │ └── props-table.tsx ├── icons │ ├── maccontrols.tsx │ ├── shadcn.tsx │ ├── grid.tsx │ ├── motion.tsx │ ├── tailwindcss.tsx │ ├── logo.tsx │ └── nextjs.tsx ├── code │ ├── componentsource.tsx │ ├── TextMorph.tsx │ ├── code-block-wrapper.tsx │ ├── CopyCode.tsx │ └── commmand-block.tsx ├── features │ ├── localhost.tsx │ ├── build-with-forgeui.tsx │ ├── features-container.tsx │ ├── component-container.tsx │ ├── build-feature.tsx │ ├── features-block.tsx │ └── cli-compatible.tsx ├── ui │ ├── ThemeToggle.tsx │ ├── textarea.tsx │ ├── label.tsx │ ├── input.tsx │ ├── separator.tsx │ ├── toaster.tsx │ ├── collapsible.tsx │ ├── SocialButtons.tsx │ ├── tooltip.tsx │ ├── badge.tsx │ ├── scroll-area.tsx │ ├── spotlight.tsx │ ├── button.tsx │ ├── card.tsx │ ├── accordion.tsx │ └── anchor-single.tsx ├── landing │ ├── landingpage.tsx │ ├── notfound.tsx │ ├── herobuttons.tsx │ ├── hero-badge.tsx │ ├── primaryitems.tsx │ ├── landing-footer.tsx │ └── landing-navbar.tsx └── docs │ └── nextjsinstallationpage.tsx ├── eslint.config.mjs ├── components.json ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── component_request.md │ └── bug_report.md ├── .gitignore ├── CONTRIBUTING.md ├── tsconfig.json ├── registry └── forgeui │ ├── text-reveal.tsx │ ├── text-shimmer.tsx │ └── animated-tabs.tsx ├── contants └── index.ts ├── README.md ├── package.json └── hooks └── use-active-section.ts /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-tailwindcss"] 3 | } 4 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /public/pfp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/pfp.png -------------------------------------------------------------------------------- /public/demopfp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/demopfp.png -------------------------------------------------------------------------------- /public/logo-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/logo-ui.png -------------------------------------------------------------------------------- /public/newlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/newlogo.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | 4 | Sitemap: https://forgeui.in/sitemap.xml 5 | -------------------------------------------------------------------------------- /public/assets/gojo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/assets/gojo.png -------------------------------------------------------------------------------- /public/assets/toji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/assets/toji.png -------------------------------------------------------------------------------- /public/logo-ui-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/logo-ui-new.png -------------------------------------------------------------------------------- /public/forgeui-ogimage-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmanShakya0018/forgeui/HEAD/public/forgeui-ogimage-v2.png -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | #git check-attr linguist-vendored -- app/components/fraud-card/_components/fraudcard.css 2 | app/components/*/_components/*.css linguist-vendored 3 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | output: "export" 6 | }; 7 | 8 | export default nextConfig; -------------------------------------------------------------------------------- /app/not-found.tsx: -------------------------------------------------------------------------------- 1 | import NotFound from "@/components/landing/notfound"; 2 | import React from "react"; 3 | 4 | const Page = () => { 5 | return ; 6 | }; 7 | 8 | export default Page; 9 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | 2 | import { clsx, type ClassValue } from "clsx" 3 | import { twMerge } from "tailwind-merge" 4 | 5 | export function cn(...inputs: ClassValue[]) { 6 | return twMerge(clsx(inputs)) 7 | } 8 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import LandingPage from "@/components/landing/landingpage"; 2 | import React from "react"; 3 | 4 | const home = () => { 5 | return ( 6 | <> 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default home; 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Aman Shakya 2 | All rights reserved. 3 | 4 | This repository is publicly available for learning and portfolio purposes only. 5 | You may not copy, modify, distribute, or use this code, in whole or in part, 6 | for any purpose — commercial or non-commercial — without prior written consent 7 | from the author. 8 | -------------------------------------------------------------------------------- /provider/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { ThemeProvider as NextThemesProvider } from "next-themes"; 5 | 6 | export function ThemeProvider({ 7 | children, 8 | ...props 9 | }: React.ComponentProps) { 10 | return {children}; 11 | } 12 | -------------------------------------------------------------------------------- /public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/layout/livepreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from "react"; 2 | 3 | interface LivePreviewComponentProps { 4 | children: ReactNode; 5 | } 6 | 7 | const LivePreviewComponent = ({ children }: LivePreviewComponentProps) => { 8 | return ( 9 |
10 | {children} 11 |
12 | ); 13 | }; 14 | 15 | export default LivePreviewComponent; 16 | -------------------------------------------------------------------------------- /components/content/maincontentcontainer.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from "react"; 2 | 3 | interface MainContentContainerProps { 4 | children: ReactNode; 5 | } 6 | 7 | const MainContentContainer = ({ children }: MainContentContainerProps) => { 8 | return ( 9 |
10 | {children} 11 |
12 | ); 13 | }; 14 | 15 | export default MainContentContainer; 16 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /components/icons/maccontrols.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { GoTerminal } from "react-icons/go"; 3 | 4 | const MacControls = () => { 5 | return ( 6 | <> 7 | 8 |
9 |
10 |
11 | 12 | ); 13 | }; 14 | 15 | export default MacControls; 16 | -------------------------------------------------------------------------------- /app/(secondary)/preview/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | 3 | export const metadata: Metadata = { 4 | title: "Component Preview | ForgeUI", 5 | description: 6 | "Live preview of open-source UI components from ForgeUI. Built with React and Tailwind CSS, these components are customizable, accessible, and production-ready.", 7 | }; 8 | 9 | export default function PreviewLayout({ 10 | children, 11 | }: { 12 | children: React.ReactNode; 13 | }) { 14 | return <>{children}; 15 | } 16 | -------------------------------------------------------------------------------- /components/content/screen-notice.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import React from "react"; 3 | 4 | type ScreenNoticeProps = { 5 | text: string; 6 | className?: string; 7 | }; 8 | 9 | const ScreenNotice = ({ text, className }: ScreenNoticeProps) => { 10 | return ( 11 |

17 | {text} 18 |

19 | ); 20 | }; 21 | 22 | export default ScreenNotice; 23 | -------------------------------------------------------------------------------- /provider/provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { ReactNode } from "react"; 3 | import { ThemeProvider } from "@/provider/theme-provider"; 4 | 5 | type Props = { 6 | children: ReactNode; 7 | }; 8 | 9 | const Provider = ({ children }: Props) => { 10 | return ( 11 | 17 | {children} 18 | 19 | ); 20 | }; 21 | 22 | export default Provider; 23 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } 22 | -------------------------------------------------------------------------------- /components/content/clidependencies.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from "react"; 2 | 3 | interface SectionProps { 4 | title?: string; 5 | children?: ReactNode; 6 | } 7 | 8 | const CliDependencies = ({ title, children }: SectionProps) => { 9 | return ( 10 |
11 |
12 |

{title}

13 | {children} 14 |
15 |
16 | ); 17 | }; 18 | 19 | export default CliDependencies; 20 | -------------------------------------------------------------------------------- /components/icons/shadcn.tsx: -------------------------------------------------------------------------------- 1 | const ShadcnIcon = (props: React.SVGProps) => ( 2 | 9 | Shadcn UI 10 | 11 | 18 | 19 | ); 20 | export default ShadcnIcon; 21 | -------------------------------------------------------------------------------- /lib/getNavigationItems.ts: -------------------------------------------------------------------------------- 1 | import { primaryItems } from "@/contants"; 2 | 3 | export const getNavigationItems = (title: string) => { 4 | const sorted = [...primaryItems].sort((a, b) => a.name.localeCompare(b.name)); 5 | const index = sorted.findIndex(item => item.name === title); 6 | 7 | const previous = index > 0 8 | ? { label: sorted[index - 1].name, href: sorted[index - 1].href } 9 | : undefined; 10 | 11 | const next = index < sorted.length - 1 12 | ? { label: sorted[index + 1].name, href: sorted[index + 1].href } 13 | : undefined; 14 | 15 | return { previous, next }; 16 | }; 17 | -------------------------------------------------------------------------------- /lib/getNavigationFeaturedItems.ts: -------------------------------------------------------------------------------- 1 | import { eliteItems } from "@/contants"; 2 | 3 | export const getNavigationFeaturedItems = (title: string) => { 4 | const sorted = [...eliteItems].sort((a, b) => a.name.localeCompare(b.name)); 5 | const index = sorted.findIndex(item => item.name === title); 6 | 7 | const previous = index > 0 8 | ? { label: sorted[index - 1].name, href: sorted[index - 1].href } 9 | : undefined; 10 | 11 | const next = index < sorted.length - 1 12 | ? { label: sorted[index + 1].name, href: sorted[index + 1].href } 13 | : undefined; 14 | 15 | return { previous, next }; 16 | }; 17 | -------------------------------------------------------------------------------- /app/(primary)/components/framework-agnostic/_components/frameworkagnostic.css: -------------------------------------------------------------------------------- 1 | .frameworkline { 2 | offset-anchor: 10px 0px; 3 | animation: frameworkline-animation-path; 4 | animation-iteration-count: infinite; 5 | animation-timing-function: cubic-bezier(0.9, 0.8, 0.8, 0.9); 6 | animation-duration: 3.5s; 7 | } 8 | 9 | .framework-line { 10 | offset-path: path( 11 | "M 1 0 v 5 q 0 5 5 5 h 39 q 5 0 5 5 v 71 q 0 5 5 5 h 39 q 5 0 5 5 v 20" 12 | ); 13 | } 14 | 15 | @keyframes frameworkline-animation-path { 16 | 0% { 17 | offset-distance: 0%; 18 | } 19 | 85% { 20 | offset-distance: 100%; 21 | } 22 | 100% { 23 | offset-distance: 100%; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/(primary)/components/fraud-card/_components/fraudcard.css: -------------------------------------------------------------------------------- 1 | .clbeam { 2 | offset-anchor: 10px 0px; 3 | animation: none; 4 | } 5 | 6 | .clbeam-container:hover .clbeam { 7 | animation: clbeam-animation-path; 8 | animation-iteration-count: infinite; 9 | animation-timing-function: cubic-bezier(0.05, 0.05, 0.05, 0.03); 10 | animation-duration: 3s; 11 | animation-delay: 0s; 12 | } 13 | 14 | .clbeam-line-1 { 15 | offset-path: path("M 3.7 -5 v 5.8 l 6.7 5.9 v 80"); 16 | } 17 | 18 | @keyframes clbeam-animation-path { 19 | 0% { 20 | offset-distance: 0%; 21 | } 22 | 50% { 23 | offset-distance: 100%; 24 | } 25 | 100% { 26 | offset-distance: 100%; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /components/code/componentsource.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | import { CodeBlockWrapper } from "@/components/code/code-block-wrapper"; 7 | 8 | interface ComponentSourceProps extends React.HTMLAttributes { 9 | src?: string; 10 | } 11 | 12 | export function ComponentSource({ 13 | children, 14 | className, 15 | ...props 16 | }: ComponentSourceProps) { 17 | return ( 18 | 23 | {children} 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | .env 36 | 37 | # vercel 38 | .vercel 39 | 40 | # typescript 41 | *.tsbuildinfo 42 | next-env.d.ts 43 | 44 | #velite files 45 | .velite -------------------------------------------------------------------------------- /components/features/localhost.tsx: -------------------------------------------------------------------------------- 1 | import { TerminalIcon } from "lucide-react"; 2 | 3 | const LocalHost = () => { 4 | return ( 5 |
6 |
7 | 8 |

localhost:3000

9 |
10 |
New App Created!
11 |
12 | ); 13 | }; 14 | 15 | export default LocalHost; 16 | -------------------------------------------------------------------------------- /components/content/previewcomponentcontainer.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import React, { ReactNode } from "react"; 3 | 4 | interface PreviewComponentContainerProps { 5 | children: ReactNode; 6 | className?: string; 7 | } 8 | 9 | const PreviewComponentContainer = ({ 10 | children, 11 | className, 12 | }: PreviewComponentContainerProps) => { 13 | return ( 14 |
20 | {children} 21 |
22 | ); 23 | }; 24 | 25 | export default PreviewComponentContainer; 26 | -------------------------------------------------------------------------------- /components/layout/lazy-show.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useInView } from "react-intersection-observer"; 4 | import React, { Suspense } from "react"; 5 | 6 | type LazyShowProps = { 7 | children: React.ReactNode; 8 | fallback?: React.ReactNode; 9 | threshold?: number; 10 | rootMargin?: string; 11 | }; 12 | 13 | const LazyShow = ({ 14 | children, 15 | fallback = null, 16 | threshold = 0.01, 17 | rootMargin = "500px", 18 | }: LazyShowProps) => { 19 | const { ref, inView } = useInView({ 20 | triggerOnce: true, 21 | threshold, 22 | rootMargin, 23 | }); 24 | 25 | return ( 26 |
27 | {inView ? {children} : fallback} 28 |
29 | ); 30 | }; 31 | 32 | export default LazyShow; 33 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ForgeUI 2 | 3 | Hi there! 👋 4 | Thanks for stopping by and checking out ForgeUI. 5 | 6 | This project is a personal space where I experiment with UI, animation, and motion design using React and Framer Motion. 7 | Think of it less as an open-source framework and more like a UI playground — a living lab that evolves as I learn and explore. 8 | 9 | That said, you're more than welcome to: 10 | 11 | - Explore the components 12 | - Take inspiration for your own projects 13 | - Share feedback or ideas 14 | 15 | However, I'm currently not accepting external contributions or PRs, as the direction and code structure are tightly connected to my learning flow. 16 | 17 | Thanks for understanding — and feel free to star the repo if you found anything useful! 🌟 18 | -------------------------------------------------------------------------------- /components/ui/ThemeToggle.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { RxMoon, RxSun } from "react-icons/rx"; 5 | import { useTheme } from "next-themes"; 6 | import { cn } from "@/lib/utils"; 7 | 8 | export function Themetoggle() { 9 | const { theme, setTheme } = useTheme(); 10 | 11 | return ( 12 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |