Skip to content

Commit

Permalink
feat: add credenza
Browse files Browse the repository at this point in the history
  • Loading branch information
nahoc committed Jun 11, 2024
1 parent 36b8d2b commit acda01b
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 22 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ https://www.npmjs.com/package/@risc0/ui

| Statements | Branches | Functions | Lines |
| --------------------------- | ----------------------- | ------------------------- | ----------------- |
| ![Statements](https://img.shields.io/badge/statements-48.16%25-red.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-75.8%25-red.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-56%25-red.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-48.16%25-red.svg?style=flat) |
| ![Statements](https://img.shields.io/badge/statements-43.76%25-red.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-72.3%25-red.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-50%25-red.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-43.76%25-red.svg?style=flat) |
145 changes: 145 additions & 0 deletions credenza.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"use client";

import { cn } from "cn";
import { useMediaQuery } from "hooks/use-media-query";
import type { ReactNode } from "react";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "./dialog";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "./drawer";

interface BaseProps {
children: ReactNode;
}

interface RootCredenzaProps extends BaseProps {
open?: boolean;
onOpenChange?: (open: boolean) => void;
}

interface CredenzaProps extends BaseProps {
className?: string;
asChild?: true;
}

const desktop = "(min-width: 768px)";

const Credenza = ({ children, ...props }: RootCredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const Credenza = isDesktop ? Dialog : Drawer;

return <Credenza {...props}>{children}</Credenza>;
};

const CredenzaTrigger = ({ className, children, ...props }: CredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const CredenzaTrigger = isDesktop ? DialogTrigger : DrawerTrigger;

return (
<CredenzaTrigger className={className} {...props}>
{children}
</CredenzaTrigger>
);
};

const CredenzaClose = ({ className, children, ...props }: CredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const CredenzaClose = isDesktop ? DialogClose : DrawerClose;

return (
<CredenzaClose className={className} {...props}>
{children}
</CredenzaClose>
);
};

const CredenzaContent = ({ className, children, ...props }: CredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const CredenzaContent = isDesktop ? DialogContent : DrawerContent;

return (
<CredenzaContent className={className} {...props}>
{children}
</CredenzaContent>
);
};

const CredenzaDescription = ({ className, children, ...props }: CredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const CredenzaDescription = isDesktop ? DialogDescription : DrawerDescription;

return (
<CredenzaDescription className={className} {...props}>
{children}
</CredenzaDescription>
);
};

const CredenzaHeader = ({ className, children, ...props }: CredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const CredenzaHeader = isDesktop ? DialogHeader : DrawerHeader;

return (
<CredenzaHeader className={className} {...props}>
{children}
</CredenzaHeader>
);
};

const CredenzaTitle = ({ className, children, ...props }: CredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const CredenzaTitle = isDesktop ? DialogTitle : DrawerTitle;

return (
<CredenzaTitle className={className} {...props}>
{children}
</CredenzaTitle>
);
};

const CredenzaBody = ({ className, children, ...props }: CredenzaProps) => {
return (
<div className={cn("px-4 md:px-0", className)} {...props}>
{children}
</div>
);
};

const CredenzaFooter = ({ className, children, ...props }: CredenzaProps) => {
const isDesktop = useMediaQuery(desktop);
const CredenzaFooter = isDesktop ? DialogFooter : DrawerFooter;

return (
<CredenzaFooter className={className} {...props}>
{children}
</CredenzaFooter>
);
};

export {
Credenza,
CredenzaTrigger,
CredenzaClose,
CredenzaContent,
CredenzaDescription,
CredenzaHeader,
CredenzaTitle,
CredenzaBody,
CredenzaFooter,
};
93 changes: 93 additions & 0 deletions drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"use client";

import { cn } from "cn";
import {
type ComponentProps,
type ComponentPropsWithoutRef,
type ElementRef,
type HTMLAttributes,
forwardRef,
} from "react";
import { Drawer as DrawerPrimitive } from "vaul";

const DrawerTrigger = DrawerPrimitive.Trigger;
const DrawerPortal = DrawerPrimitive.Portal;
const DrawerClose = DrawerPrimitive.Close;

const Drawer = ({ shouldScaleBackground = true, ...props }: ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
);

const DrawerOverlay = forwardRef<
ElementRef<typeof DrawerPrimitive.Overlay>,
ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay ref={ref} className={cn("fixed inset-0 z-50 bg-black/80", className)} {...props} />
));

const DrawerContent = forwardRef<
ElementRef<typeof DrawerPrimitive.Content>,
ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className,
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
));

const DrawerHeader = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
<div className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)} {...props} />
);

const DrawerFooter = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
<div className={cn("mt-auto flex flex-col gap-2 p-4", className)} {...props} />
);

const DrawerTitle = forwardRef<
ElementRef<typeof DrawerPrimitive.Title>,
ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn("font-semibold text-lg leading-none tracking-tight", className)}
{...props}
/>
));

const DrawerDescription = forwardRef<
ElementRef<typeof DrawerPrimitive.Description>,
ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description ref={ref} className={cn("text-muted-foreground text-sm", className)} {...props} />
));

DrawerHeader.displayName = "DrawerHeader";
DrawerFooter.displayName = "DrawerFooter";
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
Drawer.displayName = "Drawer";
DrawerContent.displayName = "DrawerContent";

export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
};
19 changes: 19 additions & 0 deletions hooks/use-media-query.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useEffect, useState } from "react";

export function useMediaQuery(query: string) {
const [value, setValue] = useState<boolean>(false);

useEffect(() => {
function onChange(event: MediaQueryListEvent) {
setValue(event.matches);
}

const result = matchMedia(query);
result.addEventListener("change", onChange);
setValue(result.matches);

return () => result.removeEventListener("change", onChange);
}, [query]);

return value;
}
43 changes: 22 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@risc0/ui",
"version": "0.0.91",
"version": "0.0.92",
"sideEffects": false,
"type": "module",
"scripts": {
Expand All @@ -11,27 +11,27 @@
"test": "vitest run --silent --coverage && istanbul-badges-readme"
},
"dependencies": {
"@radix-ui/react-avatar": "1.1.0-rc.3",
"@radix-ui/react-checkbox": "1.1.0-rc.3",
"@radix-ui/react-dialog": "1.0.6-rc.5",
"@radix-ui/react-dropdown-menu": "2.1.0-rc.3",
"@radix-ui/react-label": "2.1.0-rc.3",
"@radix-ui/react-navigation-menu": "1.2.0-rc.3",
"@radix-ui/react-popover": "1.1.0-rc.3",
"@radix-ui/react-progress": "1.1.0-rc.3",
"@radix-ui/react-radio-group": "1.2.0-rc.3",
"@radix-ui/react-select": "2.1.0-rc.3",
"@radix-ui/react-separator": "1.1.0-rc.3",
"@radix-ui/react-slider": "1.2.0-rc.6",
"@radix-ui/react-slot": "1.1.0-rc.3",
"@radix-ui/react-switch": "1.1.0-rc.3",
"@radix-ui/react-tabs": "1.1.0-rc.3",
"@radix-ui/react-tooltip": "1.1.0-rc.3",
"@radix-ui/react-avatar": "1.1.0-rc.5",
"@radix-ui/react-checkbox": "1.1.0-rc.5",
"@radix-ui/react-dialog": "1.0.5",
"@radix-ui/react-dropdown-menu": "2.1.0-rc.5",
"@radix-ui/react-label": "2.1.0-rc.5",
"@radix-ui/react-navigation-menu": "1.2.0-rc.5",
"@radix-ui/react-popover": "1.1.0-rc.5",
"@radix-ui/react-progress": "1.1.0-rc.5",
"@radix-ui/react-radio-group": "1.2.0-rc.5",
"@radix-ui/react-select": "2.1.0-rc.5",
"@radix-ui/react-separator": "1.1.0-rc.5",
"@radix-ui/react-slider": "1.2.0-rc.8",
"@radix-ui/react-slot": "1.1.0-rc.5",
"@radix-ui/react-switch": "1.1.0-rc.5",
"@radix-ui/react-tabs": "1.1.0-rc.5",
"@radix-ui/react-tooltip": "1.1.0-rc.5",
"autoprefixer": "10.4.19",
"class-variance-authority": "0.7.1-canary.2",
"clsx": "2.1.1",
"cmdk": "0.2.0",
"lucide-react": "0.390.0",
"lucide-react": "0.394.0",
"next-themes": "0.3.0",
"radash": "12.1.0",
"react-hook-form": "7.51.5",
Expand All @@ -41,11 +41,12 @@
"tailwind-merge": "2.3.0",
"tailwindcss": "3.4.4",
"tailwindcss-animate": "1.0.7",
"typescript": "5.6.0-dev.20240608"
"typescript": "5.6.0-dev.20240611",
"vaul": "0.9.1"
},
"devDependencies": {
"@biomejs/biome": "1.8.0",
"@testing-library/jest-dom": "6.4.5",
"@biomejs/biome": "1.8.1",
"@testing-library/jest-dom": "6.4.6",
"@testing-library/react": "16.0.0",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.5.12",
Expand Down

0 comments on commit acda01b

Please sign in to comment.