diff --git a/nextjs-shadcn/.bolt/ignore b/nextjs-shadcn/.bolt/ignore index bbe3a15c..4828c31e 100644 --- a/nextjs-shadcn/.bolt/ignore +++ b/nextjs-shadcn/.bolt/ignore @@ -1,2 +1 @@ -components/ui/* -hooks/use-toast.ts +components/ui/* \ No newline at end of file diff --git a/nextjs-shadcn/.bolt/prompt b/nextjs-shadcn/.bolt/prompt index 88d020b6..a7c7ad43 100644 --- a/nextjs-shadcn/.bolt/prompt +++ b/nextjs-shadcn/.bolt/prompt @@ -1,3 +1,7 @@ +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + For all designs I ask you to make, have them be beautiful, not cookie cutter. Make webpages that are fully featured and worthy for production. When using client-side hooks (useState and useEffect) in a component that's being treated as a Server Component by Next.js, always add the "use client" directive at the top of the file. diff --git a/nextjs-shadcn/.eslintrc.json b/nextjs-shadcn/.eslintrc.json deleted file mode 100644 index bffb357a..00000000 --- a/nextjs-shadcn/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/nextjs-shadcn/.gitignore b/nextjs-shadcn/.gitignore index 9b1913ec..c59e98a0 100644 --- a/nextjs-shadcn/.gitignore +++ b/nextjs-shadcn/.gitignore @@ -1,9 +1,12 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - # dependencies /node_modules /.pnp -.pnp.js +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions # testing /coverage @@ -23,13 +26,10 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +pnpm-debug.log* -# local env files -.env -.env*.local - -# vercel -.vercel +# env files (can opt-in for committing if needed) +.env* # typescript *.tsbuildinfo diff --git a/nextjs-shadcn/app/globals.css b/nextjs-shadcn/app/globals.css index 20b1c1db..926ee9ba 100644 --- a/nextjs-shadcn/app/globals.css +++ b/nextjs-shadcn/app/globals.css @@ -1,82 +1,129 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import 'tailwindcss'; +@import 'tw-animate-css'; +@import 'shadcn/tailwind.css'; -:root { - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --font-heading: var(--font-sans); + --font-sans: var(--font-sans); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --color-foreground: var(--foreground); + --color-background: var(--background); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); } -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - } +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } -@layer base { - :root { - --background: 0 0% 100%; - --foreground: 0 0% 3.9%; - --card: 0 0% 100%; - --card-foreground: 0 0% 3.9%; - --popover: 0 0% 100%; - --popover-foreground: 0 0% 3.9%; - --primary: 0 0% 9%; - --primary-foreground: 0 0% 98%; - --secondary: 0 0% 96.1%; - --secondary-foreground: 0 0% 9%; - --muted: 0 0% 96.1%; - --muted-foreground: 0 0% 45.1%; - --accent: 0 0% 96.1%; - --accent-foreground: 0 0% 9%; - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 0 0% 98%; - --border: 0 0% 89.8%; - --input: 0 0% 89.8%; - --ring: 0 0% 3.9%; - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; - --radius: 0.5rem; - } - .dark { - --background: 0 0% 3.9%; - --foreground: 0 0% 98%; - --card: 0 0% 3.9%; - --card-foreground: 0 0% 98%; - --popover: 0 0% 3.9%; - --popover-foreground: 0 0% 98%; - --primary: 0 0% 98%; - --primary-foreground: 0 0% 9%; - --secondary: 0 0% 14.9%; - --secondary-foreground: 0 0% 98%; - --muted: 0 0% 14.9%; - --muted-foreground: 0 0% 63.9%; - --accent: 0 0% 14.9%; - --accent-foreground: 0 0% 98%; - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 0% 98%; - --border: 0 0% 14.9%; - --input: 0 0% 14.9%; - --ring: 0 0% 83.1%; - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - } +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); } @layer base { * { - @apply border-border; + @apply border-border outline-ring/50; } body { @apply bg-background text-foreground; } + html { + @apply font-sans; + } } diff --git a/nextjs-shadcn/app/layout.tsx b/nextjs-shadcn/app/layout.tsx index 9259b547..dc77b5cd 100644 --- a/nextjs-shadcn/app/layout.tsx +++ b/nextjs-shadcn/app/layout.tsx @@ -1,8 +1,18 @@ import './globals.css'; +import { Geist_Mono, Inter } from 'next/font/google'; +import { ThemeProvider } from '@/components/theme-provider'; +import { TooltipProvider } from '@/components/ui/tooltip'; +import { cn } from '@/lib/utils'; import type { Metadata } from 'next'; -import { Inter } from 'next/font/google'; +import { DirectionProvider } from '@/components/ui/direction'; +import { Toaster } from '@/components/ui/toast'; -const inter = Inter({ subsets: ['latin'] }); +const inter = Inter({ subsets: ['latin'], variable: '--font-sans' }); + +const fontMono = Geist_Mono({ + subsets: ['latin'], + variable: '--font-mono', +}); export const metadata: Metadata = { title: 'Create Next App', @@ -26,12 +36,30 @@ export const metadata: Metadata = { export default function RootLayout({ children, -}: { +}: Readonly<{ children: React.ReactNode; -}) { +}>) { return ( - - {children} + + + + + + {children} + + + + + ); } diff --git a/nextjs-shadcn/app/page.tsx b/nextjs-shadcn/app/page.tsx index 4228abd2..39dab6d8 100644 --- a/nextjs-shadcn/app/page.tsx +++ b/nextjs-shadcn/app/page.tsx @@ -1,14 +1,7 @@ -export default function Home() { +export default function Page() { return ( -
- Start prompting. +
+

Start prompting (or editing) to see magic happen :)

); } diff --git a/nextjs-shadcn/components.json b/nextjs-shadcn/components.json index c5974621..f382eb79 100644 --- a/nextjs-shadcn/components.json +++ b/nextjs-shadcn/components.json @@ -1,20 +1,25 @@ { "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", + "style": "base-nova", "rsc": true, "tsx": true, "tailwind": { - "config": "tailwind.config.ts", + "config": "", "css": "app/globals.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" }, + "iconLibrary": "lucide", + "rtl": false, "aliases": { "components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui", "lib": "@/lib", "hooks": "@/hooks" - } + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} } diff --git a/nextjs-shadcn/components/theme-provider.tsx b/nextjs-shadcn/components/theme-provider.tsx new file mode 100644 index 00000000..44f28c5b --- /dev/null +++ b/nextjs-shadcn/components/theme-provider.tsx @@ -0,0 +1,21 @@ +'use client'; + +import { ThemeProvider as NextThemesProvider } from 'next-themes'; +import * as React from 'react'; + +export function ThemeProvider({ + children, + ...props +}: React.ComponentProps) { + return ( + + {children} + + ); +} diff --git a/nextjs-shadcn/components/ui/accordion.tsx b/nextjs-shadcn/components/ui/accordion.tsx index 84bf2ebe..8f4042d5 100644 --- a/nextjs-shadcn/components/ui/accordion.tsx +++ b/nextjs-shadcn/components/ui/accordion.tsx @@ -1,58 +1,78 @@ -'use client'; - -import * as React from 'react'; -import * as AccordionPrimitive from '@radix-ui/react-accordion'; -import { ChevronDown } from 'lucide-react'; +import { Accordion as AccordionPrimitive } from '@base-ui/react/accordion'; import { cn } from '@/lib/utils'; +import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'; -const Accordion = AccordionPrimitive.Root; - -const AccordionItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AccordionItem.displayName = 'AccordionItem'; +function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) { + return ( + + ); +} -const AccordionTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - svg]:rotate-180', - className - )} +function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) { + return ( + - {children} - - - -)); -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; + /> + ); +} -const AccordionContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -
{children}
-
-)); +function AccordionTrigger({ + className, + children, + ...props +}: AccordionPrimitive.Trigger.Props) { + return ( + + + {children} + + + + + ); +} -AccordionContent.displayName = AccordionPrimitive.Content.displayName; +function AccordionContent({ + className, + children, + ...props +}: AccordionPrimitive.Panel.Props) { + return ( + +
+ {children} +
+
+ ); +} export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/nextjs-shadcn/components/ui/alert-dialog.tsx b/nextjs-shadcn/components/ui/alert-dialog.tsx index 5cba559b..1d152826 100644 --- a/nextjs-shadcn/components/ui/alert-dialog.tsx +++ b/nextjs-shadcn/components/ui/alert-dialog.tsx @@ -1,141 +1,187 @@ 'use client'; import * as React from 'react'; -import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'; +import { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog'; import { cn } from '@/lib/utils'; -import { buttonVariants } from '@/components/ui/button'; +import { Button } from '@/components/ui/button'; -const AlertDialog = AlertDialogPrimitive.Root; +function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) { + return ; +} -const AlertDialogTrigger = AlertDialogPrimitive.Trigger; +function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) { + return ( + + ); +} -const AlertDialogPortal = AlertDialogPrimitive.Portal; +function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) { + return ( + + ); +} -const AlertDialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; +function AlertDialogOverlay({ + className, + ...props +}: AlertDialogPrimitive.Backdrop.Props) { + return ( + + ); +} -const AlertDialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - + + + + ); +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
- -)); -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; + ); +} -const AlertDialogHeader = ({ +function AlertDialogFooter({ className, ...props -}: React.HTMLAttributes) => ( -
-); -AlertDialogHeader.displayName = 'AlertDialogHeader'; +}: React.ComponentProps<'div'>) { + return ( +
+ ); +} -const AlertDialogFooter = ({ +function AlertDialogMedia({ className, ...props -}: React.HTMLAttributes) => ( -
-); -AlertDialogFooter.displayName = 'AlertDialogFooter'; +}: React.ComponentProps<'div'>) { + return ( +
+ ); +} -const AlertDialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const AlertDialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogDescription.displayName = - AlertDialogPrimitive.Description.displayName; +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const AlertDialogAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + ); -}); -CarouselPrevious.displayName = 'CarouselPrevious'; +} -const CarouselNext = React.forwardRef< - HTMLButtonElement, - React.ComponentProps ->(({ className, variant = 'outline', size = 'icon', ...props }, ref) => { +function CarouselNext({ + className, + variant = 'outline', + size = 'icon-sm', + ...props +}: React.ComponentProps) { const { orientation, scrollNext, canScrollNext } = useCarousel(); return ( ); -}); -CarouselNext.displayName = 'CarouselNext'; +} export { type CarouselApi, @@ -259,4 +238,5 @@ export { CarouselItem, CarouselPrevious, CarouselNext, + useCarousel, }; diff --git a/nextjs-shadcn/components/ui/chart.tsx b/nextjs-shadcn/components/ui/chart.tsx index 9b6a04b4..3a8bccf2 100644 --- a/nextjs-shadcn/components/ui/chart.tsx +++ b/nextjs-shadcn/components/ui/chart.tsx @@ -2,21 +2,26 @@ import * as React from 'react'; import * as RechartsPrimitive from 'recharts'; +import type { TooltipValueType } from 'recharts'; import { cn } from '@/lib/utils'; // Format: { THEME_NAME: CSS_SELECTOR } const THEMES = { light: '', dark: '.dark' } as const; -export type ChartConfig = { - [k in string]: { +const INITIAL_DIMENSION = { width: 320, height: 200 } as const; +type TooltipNameType = number | string; + +export type ChartConfig = Record< + string, + { label?: React.ReactNode; icon?: React.ComponentType; } & ( | { color?: string; theme?: never } | { color?: never; theme: Record } - ); -}; + ) +>; type ChartContextProps = { config: ChartConfig; @@ -34,42 +39,51 @@ function useChart() { return context; } -const ChartContainer = React.forwardRef< - HTMLDivElement, - React.ComponentProps<'div'> & { - config: ChartConfig; - children: React.ComponentProps< - typeof RechartsPrimitive.ResponsiveContainer - >['children']; - } ->(({ id, className, children, config, ...props }, ref) => { +function ChartContainer({ + id, + className, + children, + config, + initialDimension = INITIAL_DIMENSION, + ...props +}: React.ComponentProps<'div'> & { + config: ChartConfig; + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >['children']; + initialDimension?: { + width: number; + height: number; + }; +}) { const uniqueId = React.useId(); - const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`; + const chartId = `chart-${id ?? uniqueId.replace(/:/g, '')}`; return (
- + {children}
); -}); -ChartContainer.displayName = 'Chart'; +} const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { const colorConfig = Object.entries(config).filter( - ([_, config]) => config.theme || config.color + ([, config]) => config.theme ?? config.color ); if (!colorConfig.length) { @@ -86,7 +100,7 @@ ${prefix} [data-chart=${id}] { ${colorConfig .map(([key, itemConfig]) => { const color = - itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || + itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ?? itemConfig.color; return color ? ` --color-${key}: ${color};` : null; }) @@ -102,97 +116,97 @@ ${colorConfig const ChartTooltip = RechartsPrimitive.Tooltip; -const ChartTooltipContent = React.forwardRef< - HTMLDivElement, - React.ComponentProps & - React.ComponentProps<'div'> & { - hideLabel?: boolean; - hideIndicator?: boolean; - indicator?: 'line' | 'dot' | 'dashed'; - nameKey?: string; - labelKey?: string; +function ChartTooltipContent({ + active, + payload, + className, + indicator = 'dot', + hideLabel = false, + hideIndicator = false, + label, + labelFormatter, + labelClassName, + formatter, + color, + nameKey, + labelKey, +}: React.ComponentProps & + React.ComponentProps<'div'> & { + hideLabel?: boolean; + hideIndicator?: boolean; + indicator?: 'line' | 'dot' | 'dashed'; + nameKey?: string; + labelKey?: string; + } & Omit< + RechartsPrimitive.DefaultTooltipContentProps< + TooltipValueType, + TooltipNameType + >, + 'accessibilityLayer' + >) { + const { config } = useChart(); + + const tooltipLabel = React.useMemo(() => { + if (hideLabel || !payload?.length) { + return null; } ->( - ( - { - active, - payload, - className, - indicator = 'dot', - hideLabel = false, - hideIndicator = false, - label, - labelFormatter, - labelClassName, - formatter, - color, - nameKey, - labelKey, - }, - ref - ) => { - const { config } = useChart(); - - const tooltipLabel = React.useMemo(() => { - if (hideLabel || !payload?.length) { - return null; - } - - const [item] = payload; - const key = `${labelKey || item.dataKey || item.name || 'value'}`; - const itemConfig = getPayloadConfigFromPayload(config, item, key); - const value = - !labelKey && typeof label === 'string' - ? config[label as keyof typeof config]?.label || label - : itemConfig?.label; - - if (labelFormatter) { - return ( -
- {labelFormatter(value, payload)} -
- ); - } - - if (!value) { - return null; - } - - return
{value}
; - }, [ - label, - labelFormatter, - payload, - hideLabel, - labelClassName, - config, - labelKey, - ]); - - if (!active || !payload?.length) { + + const [item] = payload; + const key = `${labelKey ?? item?.dataKey ?? item?.name ?? 'value'}`; + const itemConfig = getPayloadConfigFromPayload(config, item, key); + const value = + !labelKey && typeof label === 'string' + ? config[label]?.label ?? label + : itemConfig?.label; + + if (labelFormatter) { + return ( +
+ {labelFormatter(value, payload)} +
+ ); + } + + if (!value) { return null; } - const nestLabel = payload.length === 1 && indicator !== 'dot'; + return
{value}
; + }, [ + label, + labelFormatter, + payload, + hideLabel, + labelClassName, + config, + labelKey, + ]); + + if (!active || !payload?.length) { + return null; + } - return ( -
- {!nestLabel ? tooltipLabel : null} -
- {payload.map((item, index) => { - const key = `${nameKey || item.name || item.dataKey || 'value'}`; + const nestLabel = payload.length === 1 && indicator !== 'dot'; + + return ( +
+ {!nestLabel ? tooltipLabel : null} +
+ {payload + .filter((item) => item.type !== 'none') + .map((item, index) => { + const key = `${nameKey ?? item.name ?? item.dataKey ?? 'value'}`; const itemConfig = getPayloadConfigFromPayload(config, item, key); - const indicatorColor = color || item.payload.fill || item.color; + const indicatorColor = color ?? item.payload?.fill ?? item.color; return (
svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground', indicator === 'dot' && 'items-center' @@ -208,7 +222,7 @@ const ChartTooltipContent = React.forwardRef< !hideIndicator && (
{nestLabel ? tooltipLabel : null} - {itemConfig?.label || item.name} + {itemConfig?.label ?? item.name}
- {item.value && ( - - {item.value.toLocaleString()} + {item.value != null && ( + + {typeof item.value === 'number' + ? item.value.toLocaleString() + : String(item.value)} )}
@@ -249,49 +265,46 @@ const ChartTooltipContent = React.forwardRef<
); })} -
- ); - } -); -ChartTooltipContent.displayName = 'ChartTooltip'; +
+ ); +} const ChartLegend = RechartsPrimitive.Legend; -const ChartLegendContent = React.forwardRef< - HTMLDivElement, - React.ComponentProps<'div'> & - Pick & { - hideIcon?: boolean; - nameKey?: string; - } ->( - ( - { className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey }, - ref - ) => { - const { config } = useChart(); - - if (!payload?.length) { - return null; - } +function ChartLegendContent({ + className, + hideIcon = false, + payload, + verticalAlign = 'bottom', + nameKey, +}: React.ComponentProps<'div'> & { + hideIcon?: boolean; + nameKey?: string; +} & RechartsPrimitive.DefaultLegendContentProps) { + const { config } = useChart(); + + if (!payload?.length) { + return null; + } - return ( -
- {payload.map((item) => { - const key = `${nameKey || item.dataKey || 'value'}`; + return ( +
+ {payload + .filter((item) => item.type !== 'none') + .map((item, index) => { + const key = `${nameKey ?? item.dataKey ?? 'value'}`; const itemConfig = getPayloadConfigFromPayload(config, item, key); return (
svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground' )} @@ -310,13 +323,10 @@ const ChartLegendContent = React.forwardRef<
); })} -
- ); - } -); -ChartLegendContent.displayName = 'ChartLegend'; +
+ ); +} -// Helper to extract item config from a payload. function getPayloadConfigFromPayload( config: ChartConfig, payload: unknown, @@ -350,9 +360,7 @@ function getPayloadConfigFromPayload( ] as string; } - return configLabelKey in config - ? config[configLabelKey] - : config[key as keyof typeof config]; + return configLabelKey in config ? config[configLabelKey] : config[key]; } export { diff --git a/nextjs-shadcn/components/ui/checkbox.tsx b/nextjs-shadcn/components/ui/checkbox.tsx index 13a6a291..8854ed71 100644 --- a/nextjs-shadcn/components/ui/checkbox.tsx +++ b/nextjs-shadcn/components/ui/checkbox.tsx @@ -1,30 +1,28 @@ 'use client'; -import * as React from 'react'; -import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; -import { Check } from 'lucide-react'; +import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox'; import { cn } from '@/lib/utils'; +import { CheckIcon } from 'lucide-react'; -const Checkbox = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - - -)); -Checkbox.displayName = CheckboxPrimitive.Root.displayName; + + + + + ); +} export { Checkbox }; diff --git a/nextjs-shadcn/components/ui/collapsible.tsx b/nextjs-shadcn/components/ui/collapsible.tsx index 86ab87d8..93a38518 100644 --- a/nextjs-shadcn/components/ui/collapsible.tsx +++ b/nextjs-shadcn/components/ui/collapsible.tsx @@ -1,11 +1,21 @@ 'use client'; -import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'; +import { Collapsible as CollapsiblePrimitive } from '@base-ui/react/collapsible'; -const Collapsible = CollapsiblePrimitive.Root; +function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) { + return ; +} -const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger; +function CollapsibleTrigger({ ...props }: CollapsiblePrimitive.Trigger.Props) { + return ( + + ); +} -const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent; +function CollapsibleContent({ ...props }: CollapsiblePrimitive.Panel.Props) { + return ( + + ); +} export { Collapsible, CollapsibleTrigger, CollapsibleContent }; diff --git a/nextjs-shadcn/components/ui/combobox.tsx b/nextjs-shadcn/components/ui/combobox.tsx new file mode 100644 index 00000000..23c4279d --- /dev/null +++ b/nextjs-shadcn/components/ui/combobox.tsx @@ -0,0 +1,300 @@ +'use client'; + +import * as React from 'react'; +import { Combobox as ComboboxPrimitive } from '@base-ui/react'; + +import { cn } from '@/lib/utils'; +import { Button } from '@/components/ui/button'; +import { + InputGroup, + InputGroupAddon, + InputGroupButton, + InputGroupInput, +} from '@/components/ui/input-group'; +import { ChevronDownIcon, XIcon, CheckIcon } from 'lucide-react'; + +const Combobox = ComboboxPrimitive.Root; + +function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) { + return ; +} + +function ComboboxTrigger({ + className, + children, + ...props +}: ComboboxPrimitive.Trigger.Props) { + return ( + + {children} + + + ); +} + +function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) { + return ( + } + className={cn(className)} + {...props} + > + + + ); +} + +function ComboboxInput({ + className, + children, + disabled = false, + showTrigger = true, + showClear = false, + ...props +}: ComboboxPrimitive.Input.Props & { + showTrigger?: boolean; + showClear?: boolean; +}) { + return ( + + } + {...props} + /> + + {showTrigger && ( + } + data-slot="input-group-button" + className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent" + disabled={disabled} + /> + )} + {showClear && } + + {children} + + ); +} + +function ComboboxContent({ + className, + side = 'bottom', + sideOffset = 6, + align = 'start', + alignOffset = 0, + anchor, + ...props +}: ComboboxPrimitive.Popup.Props & + Pick< + ComboboxPrimitive.Positioner.Props, + 'side' | 'align' | 'sideOffset' | 'alignOffset' | 'anchor' + >) { + return ( + + + + + + ); +} + +function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) { + return ( + + ); +} + +function ComboboxItem({ + className, + children, + ...props +}: ComboboxPrimitive.Item.Props) { + return ( + + {children} + + } + > + + + + ); +} + +function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) { + return ( + + ); +} + +function ComboboxLabel({ + className, + ...props +}: ComboboxPrimitive.GroupLabel.Props) { + return ( + + ); +} + +function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) { + return ( + + ); +} + +function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { + return ( + + ); +} + +function ComboboxSeparator({ + className, + ...props +}: ComboboxPrimitive.Separator.Props) { + return ( + + ); +} + +function ComboboxChips({ + className, + ...props +}: React.ComponentPropsWithRef & + ComboboxPrimitive.Chips.Props) { + return ( + + ); +} + +function ComboboxChip({ + className, + children, + showRemove = true, + ...props +}: ComboboxPrimitive.Chip.Props & { + showRemove?: boolean; +}) { + return ( + + {children} + {showRemove && ( + } + className="-ml-1 opacity-50 hover:opacity-100" + data-slot="combobox-chip-remove" + > + + + )} + + ); +} + +function ComboboxChipsInput({ + className, + ...props +}: ComboboxPrimitive.Input.Props) { + return ( + + ); +} + +function useComboboxAnchor() { + return React.useRef(null); +} + +export { + Combobox, + ComboboxInput, + ComboboxContent, + ComboboxList, + ComboboxItem, + ComboboxGroup, + ComboboxLabel, + ComboboxCollection, + ComboboxEmpty, + ComboboxSeparator, + ComboboxChips, + ComboboxChip, + ComboboxChipsInput, + ComboboxTrigger, + ComboboxValue, + useComboboxAnchor, +}; diff --git a/nextjs-shadcn/components/ui/command.tsx b/nextjs-shadcn/components/ui/command.tsx index 5b9ca503..f77f7a42 100644 --- a/nextjs-shadcn/components/ui/command.tsx +++ b/nextjs-shadcn/components/ui/command.tsx @@ -1,146 +1,184 @@ 'use client'; import * as React from 'react'; -import { type DialogProps } from '@radix-ui/react-dialog'; import { Command as CommandPrimitive } from 'cmdk'; -import { Search } from 'lucide-react'; import { cn } from '@/lib/utils'; -import { Dialog, DialogContent } from '@/components/ui/dialog'; - -const Command = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -Command.displayName = CommandPrimitive.displayName; - -interface CommandDialogProps extends DialogProps {} +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { InputGroup, InputGroupAddon } from '@/components/ui/input-group'; +import { SearchIcon, CheckIcon } from 'lucide-react'; + +function Command({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const CommandDialog = ({ children, ...props }: CommandDialogProps) => { +function CommandDialog({ + title = 'Command Palette', + description = 'Search for a command to run...', + children, + className, + showCloseButton = false, + ...props +}: Omit, 'children'> & { + title?: string; + description?: string; + className?: string; + showCloseButton?: boolean; + children: React.ReactNode; +}) { return ( - - - {children} - + + {title} + {description} + + + {children} ); -}; +} + +function CommandInput({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ + + + + + +
+ ); +} -const CommandInput = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( -
- - ) { + return ( + -
-)); - -CommandInput.displayName = CommandPrimitive.Input.displayName; - -const CommandList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); - -CommandList.displayName = CommandPrimitive.List.displayName; - -const CommandEmpty = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->((props, ref) => ( - -)); - -CommandEmpty.displayName = CommandPrimitive.Empty.displayName; - -const CommandGroup = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); + ); +} -CommandGroup.displayName = CommandPrimitive.Group.displayName; +function CommandEmpty({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const CommandSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -CommandSeparator.displayName = CommandPrimitive.Separator.displayName; +function CommandGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const CommandItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); +function CommandSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -CommandItem.displayName = CommandPrimitive.Item.displayName; +function CommandItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + {children} + + + ); +} -const CommandShortcut = ({ +function CommandShortcut({ className, ...props -}: React.HTMLAttributes) => { +}: React.ComponentProps<'span'>) { return ( ); -}; -CommandShortcut.displayName = 'CommandShortcut'; +} export { Command, diff --git a/nextjs-shadcn/components/ui/context-menu.tsx b/nextjs-shadcn/components/ui/context-menu.tsx index 1046ab83..bbdd89c2 100644 --- a/nextjs-shadcn/components/ui/context-menu.tsx +++ b/nextjs-shadcn/components/ui/context-menu.tsx @@ -1,185 +1,257 @@ 'use client'; import * as React from 'react'; -import * as ContextMenuPrimitive from '@radix-ui/react-context-menu'; -import { Check, ChevronRight, Circle } from 'lucide-react'; +import { ContextMenu as ContextMenuPrimitive } from '@base-ui/react/context-menu'; import { cn } from '@/lib/utils'; +import { ChevronRightIcon, CheckIcon } from 'lucide-react'; -const ContextMenu = ContextMenuPrimitive.Root; - -const ContextMenuTrigger = ContextMenuPrimitive.Trigger; - -const ContextMenuGroup = ContextMenuPrimitive.Group; - -const ContextMenuPortal = ContextMenuPrimitive.Portal; - -const ContextMenuSub = ContextMenuPrimitive.Sub; - -const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup; - -const ContextMenuSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)); -ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName; - -const ContextMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName; - -const ContextMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - ; +} + +function ContextMenuPortal({ ...props }: ContextMenuPrimitive.Portal.Props) { + return ( + + ); +} + +function ContextMenuTrigger({ + className, + ...props +}: ContextMenuPrimitive.Trigger.Props) { + return ( + + ); +} + +function ContextMenuContent({ + className, + align = 'start', + alignOffset = 4, + side = 'right', + sideOffset = 0, + ...props +}: ContextMenuPrimitive.Popup.Props & + Pick< + ContextMenuPrimitive.Positioner.Props, + 'align' | 'alignOffset' | 'side' | 'sideOffset' + >) { + return ( + + + + + + ); +} + +function ContextMenuGroup({ ...props }: ContextMenuPrimitive.Group.Props) { + return ( + + ); +} + +function ContextMenuLabel({ + className, + inset, + ...props +}: ContextMenuPrimitive.GroupLabel.Props & { + inset?: boolean; +}) { + return ( + + ); +} + +function ContextMenuItem({ + className, + inset, + variant = 'default', + ...props +}: ContextMenuPrimitive.Item.Props & { + inset?: boolean; + variant?: 'default' | 'destructive'; +}) { + return ( + + ); +} + +function ContextMenuSub({ ...props }: ContextMenuPrimitive.SubmenuRoot.Props) { + return ( + + ); +} + +function ContextMenuSubTrigger({ + className, + inset, + children, + ...props +}: ContextMenuPrimitive.SubmenuTrigger.Props & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function ContextMenuSubContent({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function ContextMenuCheckboxItem({ + className, + children, + checked, + inset, + ...props +}: ContextMenuPrimitive.CheckboxItem.Props & { + inset?: boolean; +}) { + return ( + + + + + + + {children} + + ); +} + +function ContextMenuRadioGroup({ + ...props +}: ContextMenuPrimitive.RadioGroup.Props) { + return ( + + ); +} + +function ContextMenuRadioItem({ + className, + children, + inset, + ...props +}: ContextMenuPrimitive.RadioItem.Props & { + inset?: boolean; +}) { + return ( + + + + + + + {children} + + ); +} + +function ContextMenuSeparator({ + className, + ...props +}: ContextMenuPrimitive.Separator.Props) { + return ( + - -)); -ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName; - -const ContextMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName; - -const ContextMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)); -ContextMenuCheckboxItem.displayName = - ContextMenuPrimitive.CheckboxItem.displayName; - -const ContextMenuRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)); -ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName; - -const ContextMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName; - -const ContextMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName; - -const ContextMenuShortcut = ({ + ); +} + +function ContextMenuShortcut({ className, ...props -}: React.HTMLAttributes) => { +}: React.ComponentProps<'span'>) { return ( ); -}; -ContextMenuShortcut.displayName = 'ContextMenuShortcut'; +} export { ContextMenu, diff --git a/nextjs-shadcn/components/ui/dialog.tsx b/nextjs-shadcn/components/ui/dialog.tsx index b5529522..f0f8ecc9 100644 --- a/nextjs-shadcn/components/ui/dialog.tsx +++ b/nextjs-shadcn/components/ui/dialog.tsx @@ -1,122 +1,159 @@ 'use client'; import * as React from 'react'; -import * as DialogPrimitive from '@radix-ui/react-dialog'; -import { X } from 'lucide-react'; +import { Dialog as DialogPrimitive } from '@base-ui/react/dialog'; import { cn } from '@/lib/utils'; +import { Button } from '@/components/ui/button'; +import { XIcon } from 'lucide-react'; -const Dialog = DialogPrimitive.Root; +function Dialog({ ...props }: DialogPrimitive.Root.Props) { + return ; +} -const DialogTrigger = DialogPrimitive.Trigger; +function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) { + return ; +} -const DialogPortal = DialogPrimitive.Portal; +function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) { + return ; +} -const DialogClose = DialogPrimitive.Close; +function DialogClose({ ...props }: DialogPrimitive.Close.Props) { + return ; +} -const DialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; - -const DialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)); -DialogContent.displayName = DialogPrimitive.Content.displayName; + /> + ); +} -const DialogHeader = ({ +function DialogContent({ className, + children, + showCloseButton = true, ...props -}: React.HTMLAttributes) => ( -
-); -DialogHeader.displayName = 'DialogHeader'; +}: DialogPrimitive.Popup.Props & { + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && ( + + } + > + + Close + + )} + + + ); +} -const DialogFooter = ({ +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogFooter({ className, + showCloseButton = false, + children, ...props -}: React.HTMLAttributes) => ( -
-); -DialogFooter.displayName = 'DialogFooter'; +}: React.ComponentProps<'div'> & { + showCloseButton?: boolean; +}) { + return ( +
+ {children} + {showCloseButton && ( + }> + Close + + )} +
+ ); +} -const DialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogTitle.displayName = DialogPrimitive.Title.displayName; +function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) { + return ( + + ); +} -const DialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogDescription.displayName = DialogPrimitive.Description.displayName; +function DialogDescription({ + className, + ...props +}: DialogPrimitive.Description.Props) { + return ( + + ); +} export { Dialog, - DialogPortal, - DialogOverlay, DialogClose, - DialogTrigger, DialogContent, - DialogHeader, + DialogDescription, DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, DialogTitle, - DialogDescription, + DialogTrigger, }; diff --git a/nextjs-shadcn/components/ui/direction.tsx b/nextjs-shadcn/components/ui/direction.tsx new file mode 100644 index 00000000..78363f96 --- /dev/null +++ b/nextjs-shadcn/components/ui/direction.tsx @@ -0,0 +1,6 @@ +'use client'; + +export { + DirectionProvider, + useDirection, +} from '@base-ui/react/direction-provider'; diff --git a/nextjs-shadcn/components/ui/drawer.tsx b/nextjs-shadcn/components/ui/drawer.tsx index f78fb477..99b9a827 100644 --- a/nextjs-shadcn/components/ui/drawer.tsx +++ b/nextjs-shadcn/components/ui/drawer.tsx @@ -1,113 +1,223 @@ 'use client'; import * as React from 'react'; -import { Drawer as DrawerPrimitive } from 'vaul'; +import { Drawer as DrawerPrimitive } from '@base-ui/react/drawer'; import { cn } from '@/lib/utils'; -const Drawer = ({ - shouldScaleBackground = true, +type DrawerContextProps = { + hasSnapPoints: boolean; + modal: DrawerPrimitive.Root.Props['modal']; + showSwipeHandle: boolean; + swipeDirection: NonNullable; +}; + +const DrawerContext = React.createContext(null); + +function useDrawer() { + const context = React.useContext(DrawerContext); + + if (!context) { + throw new Error('useDrawer must be used within a Drawer.'); + } + + return context; +} + +function Drawer({ + modal = true, + showSwipeHandle = false, + snapPoints, + swipeDirection = 'down', ...props -}: React.ComponentProps) => ( - -); -Drawer.displayName = 'Drawer'; - -const DrawerTrigger = DrawerPrimitive.Trigger; - -const DrawerPortal = DrawerPrimitive.Portal; - -const DrawerClose = DrawerPrimitive.Close; - -const DrawerOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName; - -const DrawerContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - 0; + const contextValue = React.useMemo( + () => ({ hasSnapPoints, modal, showSwipeHandle, swipeDirection }), + [hasSnapPoints, modal, showSwipeHandle, swipeDirection] + ); + + return ( + + + + ); +} + +function DrawerTrigger({ ...props }: DrawerPrimitive.Trigger.Props) { + return ; +} + +function DrawerPortal({ ...props }: DrawerPrimitive.Portal.Props) { + return ; +} + +function DrawerClose({ ...props }: DrawerPrimitive.Close.Props) { + return ; +} + +function DrawerOverlay({ + className, + ...props +}: DrawerPrimitive.Backdrop.Props) { + return ( + -
- {children} - - -)); -DrawerContent.displayName = 'DrawerContent'; - -const DrawerHeader = ({ + /> + ); +} + +function DrawerSwipeHandle({ className, ...props -}: React.HTMLAttributes) => ( -
-); -DrawerHeader.displayName = 'DrawerHeader'; - -const DrawerFooter = ({ +}: React.ComponentProps<'div'>) { + return ( +