diff --git a/apps/storybook/package.json b/apps/storybook/package.json index f45b217..c4f920a 100644 --- a/apps/storybook/package.json +++ b/apps/storybook/package.json @@ -7,7 +7,17 @@ "build-storybook": "storybook build" }, "dependencies": { - "@repo/ui": "workspace:*" + "@repo/ui": "workspace:*", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", + "input-otp": "^1.4.2", + "lucide-react": "^1.8.0", + "react-day-picker": "^9.14.0", + "react-resizable-panels": "^4.10.0", + "recharts": "^3.8.1", + "sonner": "^2.0.7", + "vaul": "^1.1.2" }, "devDependencies": { "@storybook/addon-docs": "10.3.5", diff --git a/apps/storybook/src/stories/IconButton.stories.tsx b/apps/storybook/src/stories/Custom/IconButton.stories.tsx similarity index 95% rename from apps/storybook/src/stories/IconButton.stories.tsx rename to apps/storybook/src/stories/Custom/IconButton.stories.tsx index 5caa1b7..9449317 100644 --- a/apps/storybook/src/stories/IconButton.stories.tsx +++ b/apps/storybook/src/stories/Custom/IconButton.stories.tsx @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react"; const meta = { component: IconButton, - title: "Inputs/IconButton", + title: "Custom/IconButton", tags: ["autodocs"], } satisfies Meta; diff --git a/apps/storybook/src/stories/SectionTitle.stories.tsx b/apps/storybook/src/stories/Custom/SectionTitle.stories.tsx similarity index 92% rename from apps/storybook/src/stories/SectionTitle.stories.tsx rename to apps/storybook/src/stories/Custom/SectionTitle.stories.tsx index 14369c3..2791399 100644 --- a/apps/storybook/src/stories/SectionTitle.stories.tsx +++ b/apps/storybook/src/stories/Custom/SectionTitle.stories.tsx @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react"; const meta = { component: SectionTitle, - title: "Layout/SectionTitle", + title: "Custom/SectionTitle", tags: ["autodocs"], } satisfies Meta; diff --git a/apps/storybook/src/stories/DataDisplay/Avatar.stories.tsx b/apps/storybook/src/stories/DataDisplay/Avatar.stories.tsx new file mode 100644 index 0000000..b4aebaa --- /dev/null +++ b/apps/storybook/src/stories/DataDisplay/Avatar.stories.tsx @@ -0,0 +1,62 @@ +import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Avatar, + title: "Data Display/Avatar", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + CN + + ), +}; + +export const Fallback: Story = { + render: () => ( + + JB + + ), +}; + +export const Small: Story = { + render: () => ( + + SM + + ), +}; + +export const Large: Story = { + render: () => ( + + + LG + + ), +}; + +export const Group: Story = { + render: () => ( + + + A + + + B + + + C + + +3 + + ), +}; diff --git a/apps/storybook/src/stories/DataDisplay/Badge.stories.tsx b/apps/storybook/src/stories/DataDisplay/Badge.stories.tsx new file mode 100644 index 0000000..be20558 --- /dev/null +++ b/apps/storybook/src/stories/DataDisplay/Badge.stories.tsx @@ -0,0 +1,38 @@ +import { Badge } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Badge, + title: "Data Display/Badge", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Badge", + }, +}; + +export const Secondary: Story = { + args: { + children: "Secondary", + variant: "secondary", + }, +}; + +export const Destructive: Story = { + args: { + children: "Destructive", + variant: "destructive", + }, +}; + +export const Outline: Story = { + args: { + children: "Outline", + variant: "outline", + }, +}; diff --git a/apps/storybook/src/stories/DataDisplay/Card.stories.tsx b/apps/storybook/src/stories/DataDisplay/Card.stories.tsx new file mode 100644 index 0000000..269c711 --- /dev/null +++ b/apps/storybook/src/stories/DataDisplay/Card.stories.tsx @@ -0,0 +1,50 @@ +import { + Button, + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Card, + title: "Data Display/Card", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + Card Title + Card description goes here. + + +

Card content with some example text.

+
+ + + +
+ ), +}; + +export const Small: Story = { + render: () => ( + + + Small Card + A compact card variant. + + +

Smaller padding and gaps.

+
+
+ ), +}; diff --git a/apps/storybook/src/stories/DataDisplay/Carousel.stories.tsx b/apps/storybook/src/stories/DataDisplay/Carousel.stories.tsx new file mode 100644 index 0000000..6276e6d --- /dev/null +++ b/apps/storybook/src/stories/DataDisplay/Carousel.stories.tsx @@ -0,0 +1,41 @@ +import { + Card, + CardContent, + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Carousel, + title: "Data Display/Carousel", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( +
+ + + {["slide-1", "slide-2", "slide-3", "slide-4", "slide-5"].map((id, index) => ( + + + + {index + 1} + + + + ))} + + + + +
+ ), +}; diff --git a/apps/storybook/src/stories/DataDisplay/Chart.stories.tsx b/apps/storybook/src/stories/DataDisplay/Chart.stories.tsx new file mode 100644 index 0000000..ffffbbc --- /dev/null +++ b/apps/storybook/src/stories/DataDisplay/Chart.stories.tsx @@ -0,0 +1,41 @@ +import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Bar, BarChart, XAxis, YAxis } from "recharts"; + +const meta = { + component: ChartContainer, + title: "Data Display/Chart", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const chartData = [ + { month: "Jan", desktop: 186 }, + { month: "Feb", desktop: 305 }, + { month: "Mar", desktop: 237 }, + { month: "Apr", desktop: 73 }, + { month: "May", desktop: 209 }, + { month: "Jun", desktop: 214 }, +]; + +const chartConfig = { + desktop: { + label: "Desktop", + color: "var(--chart-1, #2563eb)", + }, +} satisfies ChartConfig; + +export const Default: Story = { + render: () => ( + + + + + } /> + + + + ), +}; diff --git a/apps/storybook/src/stories/Icon.stories.tsx b/apps/storybook/src/stories/DataDisplay/Icon.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Icon.stories.tsx rename to apps/storybook/src/stories/DataDisplay/Icon.stories.tsx diff --git a/apps/storybook/src/stories/Label.stories.tsx b/apps/storybook/src/stories/DataDisplay/Label.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Label.stories.tsx rename to apps/storybook/src/stories/DataDisplay/Label.stories.tsx diff --git a/apps/storybook/src/stories/DataDisplay/Table.stories.tsx b/apps/storybook/src/stories/DataDisplay/Table.stories.tsx new file mode 100644 index 0000000..b6b6b31 --- /dev/null +++ b/apps/storybook/src/stories/DataDisplay/Table.stories.tsx @@ -0,0 +1,55 @@ +import { + Table, + TableBody, + TableCaption, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Table, + title: "Data Display/Table", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + A list of recent invoices. + + + Invoice + Status + Method + Amount + + + + + INV001 + Paid + Credit Card + $250.00 + + + INV002 + Pending + PayPal + $150.00 + + + INV003 + Unpaid + Bank Transfer + $350.00 + + +
+ ), +}; diff --git a/apps/storybook/src/stories/DataDisplay/Tooltip.stories.tsx b/apps/storybook/src/stories/DataDisplay/Tooltip.stories.tsx new file mode 100644 index 0000000..b4743c3 --- /dev/null +++ b/apps/storybook/src/stories/DataDisplay/Tooltip.stories.tsx @@ -0,0 +1,26 @@ +import { Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Tooltip, + title: "Data Display/Tooltip", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + +

This is a tooltip

+
+
+
+ ), +}; diff --git a/apps/storybook/src/stories/Type.stories.tsx b/apps/storybook/src/stories/DataDisplay/Type.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Type.stories.tsx rename to apps/storybook/src/stories/DataDisplay/Type.stories.tsx diff --git a/apps/storybook/src/stories/Alert.stories.tsx b/apps/storybook/src/stories/Feedback/Alert.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Alert.stories.tsx rename to apps/storybook/src/stories/Feedback/Alert.stories.tsx diff --git a/apps/storybook/src/stories/Feedback/AlertDialog.stories.tsx b/apps/storybook/src/stories/Feedback/AlertDialog.stories.tsx new file mode 100644 index 0000000..febef10 --- /dev/null +++ b/apps/storybook/src/stories/Feedback/AlertDialog.stories.tsx @@ -0,0 +1,44 @@ +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, + Button, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: AlertDialog, + title: "Feedback/AlertDialog", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + Are you sure? + + This action cannot be undone. This will permanently delete the item. + + + + Cancel + Continue + + + + ), +}; diff --git a/apps/storybook/src/stories/Feedback/Dialog.stories.tsx b/apps/storybook/src/stories/Feedback/Dialog.stories.tsx new file mode 100644 index 0000000..d522d3e --- /dev/null +++ b/apps/storybook/src/stories/Feedback/Dialog.stories.tsx @@ -0,0 +1,49 @@ +import { + Button, + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, + Input, + Label, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Dialog, + title: "Feedback/Dialog", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + Edit Profile + + Make changes to your profile here. Click save when you're done. + + +
+
+ + +
+
+ + + +
+
+ ), +}; diff --git a/apps/storybook/src/stories/Feedback/Drawer.stories.tsx b/apps/storybook/src/stories/Feedback/Drawer.stories.tsx new file mode 100644 index 0000000..dbc620a --- /dev/null +++ b/apps/storybook/src/stories/Feedback/Drawer.stories.tsx @@ -0,0 +1,46 @@ +import { + Button, + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Drawer, + title: "Feedback/Drawer", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + Drawer Title + This is a drawer description. + +
+

Drawer content goes here.

+
+ + + + + + +
+
+ ), +}; diff --git a/apps/storybook/src/stories/Feedback/Progress.stories.tsx b/apps/storybook/src/stories/Feedback/Progress.stories.tsx new file mode 100644 index 0000000..9e17b30 --- /dev/null +++ b/apps/storybook/src/stories/Feedback/Progress.stories.tsx @@ -0,0 +1,29 @@ +import { Progress } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Progress, + title: "Feedback/Progress", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + value: 60, + }, +}; + +export const Empty: Story = { + args: { + value: 0, + }, +}; + +export const Complete: Story = { + args: { + value: 100, + }, +}; diff --git a/apps/storybook/src/stories/Feedback/Sheet.stories.tsx b/apps/storybook/src/stories/Feedback/Sheet.stories.tsx new file mode 100644 index 0000000..6ab7786 --- /dev/null +++ b/apps/storybook/src/stories/Feedback/Sheet.stories.tsx @@ -0,0 +1,58 @@ +import { + Button, + Sheet, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Sheet, + title: "Feedback/Sheet", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + Sheet Title + This is a sheet that slides in from the right. + +
+

Sheet content goes here.

+
+ + + +
+
+ ), +}; + +export const Left: Story = { + render: () => ( + + + + + + + Left Sheet + This sheet slides in from the left. + + + + ), +}; diff --git a/apps/storybook/src/stories/Feedback/Skeleton.stories.tsx b/apps/storybook/src/stories/Feedback/Skeleton.stories.tsx new file mode 100644 index 0000000..f115a0e --- /dev/null +++ b/apps/storybook/src/stories/Feedback/Skeleton.stories.tsx @@ -0,0 +1,35 @@ +import { Skeleton } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Skeleton, + title: "Feedback/Skeleton", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( +
+ +
+ + +
+
+ ), +}; + +export const Card: Story = { + render: () => ( +
+ +
+ + +
+
+ ), +}; diff --git a/apps/storybook/src/stories/Feedback/Sonner.stories.tsx b/apps/storybook/src/stories/Feedback/Sonner.stories.tsx new file mode 100644 index 0000000..028ccaa --- /dev/null +++ b/apps/storybook/src/stories/Feedback/Sonner.stories.tsx @@ -0,0 +1,30 @@ +import { Button, Toaster } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; +import { toast } from "sonner"; + +const meta = { + component: Toaster, + title: "Feedback/Sonner", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( +
+ + +
+ ), +}; diff --git a/apps/storybook/src/stories/Button.stories.tsx b/apps/storybook/src/stories/Inputs/Button.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Button.stories.tsx rename to apps/storybook/src/stories/Inputs/Button.stories.tsx diff --git a/apps/storybook/src/stories/Inputs/Calendar.stories.tsx b/apps/storybook/src/stories/Inputs/Calendar.stories.tsx new file mode 100644 index 0000000..de754fe --- /dev/null +++ b/apps/storybook/src/stories/Inputs/Calendar.stories.tsx @@ -0,0 +1,26 @@ +import { Calendar } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; + +const meta = { + component: Calendar, + title: "Inputs/Calendar", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => { + const [date, setDate] = React.useState(new Date()); + return ; + }, +}; + +export const WithOutsideDays: Story = { + render: () => { + const [date, setDate] = React.useState(new Date()); + return ; + }, +}; diff --git a/apps/storybook/src/stories/Checkbox.stories.tsx b/apps/storybook/src/stories/Inputs/Checkbox.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Checkbox.stories.tsx rename to apps/storybook/src/stories/Inputs/Checkbox.stories.tsx diff --git a/apps/storybook/src/stories/Input.stories.tsx b/apps/storybook/src/stories/Inputs/Input.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Input.stories.tsx rename to apps/storybook/src/stories/Inputs/Input.stories.tsx diff --git a/apps/storybook/src/stories/Inputs/InputGroup.stories.tsx b/apps/storybook/src/stories/Inputs/InputGroup.stories.tsx new file mode 100644 index 0000000..ce70c21 --- /dev/null +++ b/apps/storybook/src/stories/Inputs/InputGroup.stories.tsx @@ -0,0 +1,36 @@ +import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; +import { SearchIcon } from "lucide-react"; + +const meta = { + component: InputGroup, + title: "Inputs/InputGroup", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + + + ), +}; + +export const WithAddonEnd: Story = { + render: () => ( + + + + USD + + + ), +}; diff --git a/apps/storybook/src/stories/Inputs/InputOTP.stories.tsx b/apps/storybook/src/stories/Inputs/InputOTP.stories.tsx new file mode 100644 index 0000000..ecda1d9 --- /dev/null +++ b/apps/storybook/src/stories/Inputs/InputOTP.stories.tsx @@ -0,0 +1,42 @@ +import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: InputOTP, + title: "Inputs/InputOTP", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + + + + + + + + ), +}; + +export const FourDigit: Story = { + render: () => ( + + + + + + + + + ), +}; diff --git a/apps/storybook/src/stories/RadioGroup.stories.tsx b/apps/storybook/src/stories/Inputs/RadioGroup.stories.tsx similarity index 100% rename from apps/storybook/src/stories/RadioGroup.stories.tsx rename to apps/storybook/src/stories/Inputs/RadioGroup.stories.tsx diff --git a/apps/storybook/src/stories/Select.stories.tsx b/apps/storybook/src/stories/Inputs/Select.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Select.stories.tsx rename to apps/storybook/src/stories/Inputs/Select.stories.tsx diff --git a/apps/storybook/src/stories/Inputs/Slider.stories.tsx b/apps/storybook/src/stories/Inputs/Slider.stories.tsx new file mode 100644 index 0000000..59372da --- /dev/null +++ b/apps/storybook/src/stories/Inputs/Slider.stories.tsx @@ -0,0 +1,27 @@ +import { Slider } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Slider, + title: "Inputs/Slider", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + defaultValue: [50], + max: 100, + step: 1, + }, +}; + +export const Range: Story = { + args: { + defaultValue: [25, 75], + max: 100, + step: 1, + }, +}; diff --git a/apps/storybook/src/stories/Switch.stories.tsx b/apps/storybook/src/stories/Inputs/Switch.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Switch.stories.tsx rename to apps/storybook/src/stories/Inputs/Switch.stories.tsx diff --git a/apps/storybook/src/stories/Textarea.stories.tsx b/apps/storybook/src/stories/Inputs/Textarea.stories.tsx similarity index 100% rename from apps/storybook/src/stories/Textarea.stories.tsx rename to apps/storybook/src/stories/Inputs/Textarea.stories.tsx diff --git a/apps/storybook/src/stories/Inputs/Toggle.stories.tsx b/apps/storybook/src/stories/Inputs/Toggle.stories.tsx new file mode 100644 index 0000000..007b08c --- /dev/null +++ b/apps/storybook/src/stories/Inputs/Toggle.stories.tsx @@ -0,0 +1,40 @@ +import { Toggle } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; +import { BoldIcon } from "lucide-react"; + +const meta = { + component: Toggle, + title: "Inputs/Toggle", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Toggle", + }, +}; + +export const WithIcon: Story = { + render: () => ( + + + + ), +}; + +export const Outline: Story = { + args: { + children: "Outline", + variant: "outline", + }, +}; + +export const Small: Story = { + args: { + children: "Small", + size: "sm", + }, +}; diff --git a/apps/storybook/src/stories/Inputs/ToggleGroup.stories.tsx b/apps/storybook/src/stories/Inputs/ToggleGroup.stories.tsx new file mode 100644 index 0000000..9d708a6 --- /dev/null +++ b/apps/storybook/src/stories/Inputs/ToggleGroup.stories.tsx @@ -0,0 +1,60 @@ +import { ToggleGroup, ToggleGroupItem } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; +import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon } from "lucide-react"; + +const meta = { + component: ToggleGroup, + title: "Inputs/ToggleGroup", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + + + + + + ), +}; + +export const Outline: Story = { + render: () => ( + + + + + + + + + + + + ), +}; + +export const Multiple: Story = { + render: () => ( + + + + + + + + + + + + ), +}; diff --git a/apps/storybook/src/stories/Layout/AspectRatio.stories.tsx b/apps/storybook/src/stories/Layout/AspectRatio.stories.tsx new file mode 100644 index 0000000..02110bd --- /dev/null +++ b/apps/storybook/src/stories/Layout/AspectRatio.stories.tsx @@ -0,0 +1,35 @@ +import { AspectRatio } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: AspectRatio, + title: "Layout/AspectRatio", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( +
+ +
+ 16:9 +
+
+
+ ), +}; + +export const Square: Story = { + render: () => ( +
+ +
+ 1:1 +
+
+
+ ), +}; diff --git a/apps/storybook/src/stories/Layout/Resizable.stories.tsx b/apps/storybook/src/stories/Layout/Resizable.stories.tsx new file mode 100644 index 0000000..2a07979 --- /dev/null +++ b/apps/storybook/src/stories/Layout/Resizable.stories.tsx @@ -0,0 +1,71 @@ +import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: ResizablePanelGroup, + title: "Layout/Resizable", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + +
+ Panel One +
+
+ + +
+ Panel Two +
+
+
+ ), +}; + +export const WithHandle: Story = { + render: () => ( + + +
+ Left +
+
+ + +
+ Right +
+
+
+ ), +}; + +export const Vertical: Story = { + render: () => ( + + +
+ Top +
+
+ + +
+ Bottom +
+
+
+ ), +}; diff --git a/apps/storybook/src/stories/Layout/ScrollArea.stories.tsx b/apps/storybook/src/stories/Layout/ScrollArea.stories.tsx new file mode 100644 index 0000000..24b0b99 --- /dev/null +++ b/apps/storybook/src/stories/Layout/ScrollArea.stories.tsx @@ -0,0 +1,29 @@ +import { ScrollArea, Separator } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: ScrollArea, + title: "Layout/ScrollArea", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const tags = Array.from({ length: 50 }).map((_, i) => `Tag ${i + 1}`); + +export const Default: Story = { + render: () => ( + +
+

Tags

+ {tags.map((tag) => ( +
+
{tag}
+ +
+ ))} +
+
+ ), +}; diff --git a/apps/storybook/src/stories/Layout/Separator.stories.tsx b/apps/storybook/src/stories/Layout/Separator.stories.tsx new file mode 100644 index 0000000..788c182 --- /dev/null +++ b/apps/storybook/src/stories/Layout/Separator.stories.tsx @@ -0,0 +1,30 @@ +import { Separator } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Separator, + title: "Layout/Separator", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( +
+
+

Radix Primitives

+

An open-source UI component library.

+
+ +
+
Blog
+ +
Docs
+ +
Source
+
+
+ ), +}; diff --git a/apps/storybook/src/stories/Navigation/Breadcrumb.stories.tsx b/apps/storybook/src/stories/Navigation/Breadcrumb.stories.tsx new file mode 100644 index 0000000..aeeb364 --- /dev/null +++ b/apps/storybook/src/stories/Navigation/Breadcrumb.stories.tsx @@ -0,0 +1,38 @@ +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Breadcrumb, + title: "Navigation/Breadcrumb", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + Home + + + + Components + + + + Breadcrumb + + + + ), +}; diff --git a/apps/storybook/src/stories/Navigation/ContextMenu.stories.tsx b/apps/storybook/src/stories/Navigation/ContextMenu.stories.tsx new file mode 100644 index 0000000..42e02e8 --- /dev/null +++ b/apps/storybook/src/stories/Navigation/ContextMenu.stories.tsx @@ -0,0 +1,43 @@ +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuTrigger, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: ContextMenu, + title: "Navigation/ContextMenu", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + Right click here + + + + Back Cmd+[ + + + Forward Cmd+] + + + Reload Cmd+R + + + + Save As... Cmd+S + + + + ), +}; diff --git a/apps/storybook/src/stories/Navigation/DropdownMenu.stories.tsx b/apps/storybook/src/stories/Navigation/DropdownMenu.stories.tsx new file mode 100644 index 0000000..613556a --- /dev/null +++ b/apps/storybook/src/stories/Navigation/DropdownMenu.stories.tsx @@ -0,0 +1,38 @@ +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: DropdownMenu, + title: "Navigation/DropdownMenu", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + My Account + + Profile + Billing + Settings + + Log out + + + ), +}; diff --git a/apps/storybook/src/stories/Navigation/Menubar.stories.tsx b/apps/storybook/src/stories/Navigation/Menubar.stories.tsx new file mode 100644 index 0000000..fbe2dfc --- /dev/null +++ b/apps/storybook/src/stories/Navigation/Menubar.stories.tsx @@ -0,0 +1,57 @@ +import { + Menubar, + MenubarContent, + MenubarItem, + MenubarMenu, + MenubarSeparator, + MenubarShortcut, + MenubarTrigger, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Menubar, + title: "Navigation/Menubar", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + File + + + New Tab Cmd+T + + New Window + + Share + + Print + + + + Edit + + + Undo Cmd+Z + + + Redo Cmd+Shift+Z + + + + + View + + Zoom In + Zoom Out + + + + ), +}; diff --git a/apps/storybook/src/stories/Navigation/NavigationMenu.stories.tsx b/apps/storybook/src/stories/Navigation/NavigationMenu.stories.tsx new file mode 100644 index 0000000..37bf36a --- /dev/null +++ b/apps/storybook/src/stories/Navigation/NavigationMenu.stories.tsx @@ -0,0 +1,64 @@ +import { + NavigationMenu, + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + NavigationMenuTrigger, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: NavigationMenu, + title: "Navigation/NavigationMenu", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + Getting Started + +
+ +
Introduction
+

Learn the basics of the framework.

+
+ +
Installation
+

+ How to install and set up the project. +

+
+
+
+
+ + Components + +
+ +
Button
+

A clickable button component.

+
+
+
+
+
+
+ ), +}; diff --git a/apps/storybook/src/stories/Navigation/Pagination.stories.tsx b/apps/storybook/src/stories/Navigation/Pagination.stories.tsx new file mode 100644 index 0000000..8018719 --- /dev/null +++ b/apps/storybook/src/stories/Navigation/Pagination.stories.tsx @@ -0,0 +1,48 @@ +import { + Pagination, + PaginationContent, + PaginationEllipsis, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Pagination, + title: "Navigation/Pagination", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + 1 + + + + 2 + + + + 3 + + + + + + + + + + ), +}; diff --git a/apps/storybook/src/stories/Navigation/Tabs.stories.tsx b/apps/storybook/src/stories/Navigation/Tabs.stories.tsx new file mode 100644 index 0000000..7084a47 --- /dev/null +++ b/apps/storybook/src/stories/Navigation/Tabs.stories.tsx @@ -0,0 +1,43 @@ +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Tabs, + title: "Navigation/Tabs", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + Account + Password + + +

Make changes to your account here.

+
+ +

Change your password here.

+
+
+ ), +}; + +export const Line: Story = { + render: () => ( + + + Overview + Analytics + Reports + + Overview content + Analytics content + Reports content + + ), +}; diff --git a/apps/storybook/src/stories/Accordion.stories.tsx b/apps/storybook/src/stories/Surfaces/Accordion.stories.tsx similarity index 98% rename from apps/storybook/src/stories/Accordion.stories.tsx rename to apps/storybook/src/stories/Surfaces/Accordion.stories.tsx index 3a870ec..648e964 100644 --- a/apps/storybook/src/stories/Accordion.stories.tsx +++ b/apps/storybook/src/stories/Surfaces/Accordion.stories.tsx @@ -4,7 +4,7 @@ import { expect, userEvent, within } from "storybook/test"; const meta = { component: Accordion, - title: "Data Display/Accordion", + title: "Surfaces/Accordion", tags: ["autodocs"], } satisfies Meta; diff --git a/apps/storybook/src/stories/Surfaces/Collapsible.stories.tsx b/apps/storybook/src/stories/Surfaces/Collapsible.stories.tsx new file mode 100644 index 0000000..e9f9ffd --- /dev/null +++ b/apps/storybook/src/stories/Surfaces/Collapsible.stories.tsx @@ -0,0 +1,33 @@ +import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; +import { ChevronsUpDownIcon } from "lucide-react"; + +const meta = { + component: Collapsible, + title: "Surfaces/Collapsible", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + +
+

Starred repositories

+ + + +
+
@radix-ui/primitives
+ +
@radix-ui/colors
+
@radix-ui/react-icons
+
+
+ ), +}; diff --git a/apps/storybook/src/stories/Surfaces/Command.stories.tsx b/apps/storybook/src/stories/Surfaces/Command.stories.tsx new file mode 100644 index 0000000..aa40383 --- /dev/null +++ b/apps/storybook/src/stories/Surfaces/Command.stories.tsx @@ -0,0 +1,41 @@ +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Command, + title: "Surfaces/Command", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + No results found. + + Calendar + Search + Calculator + + + + Profile + Billing + Settings + + + + ), +}; diff --git a/apps/storybook/src/stories/Surfaces/HoverCard.stories.tsx b/apps/storybook/src/stories/Surfaces/HoverCard.stories.tsx new file mode 100644 index 0000000..2c2ee40 --- /dev/null +++ b/apps/storybook/src/stories/Surfaces/HoverCard.stories.tsx @@ -0,0 +1,30 @@ +import { Button, HoverCard, HoverCardContent, HoverCardTrigger } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: HoverCard, + title: "Surfaces/HoverCard", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + +
+

@shadcn

+

The creator of shadcn/ui and taxonomy.

+
+ Joined December 2021 +
+
+
+
+ ), +}; diff --git a/apps/storybook/src/stories/Surfaces/Popover.stories.tsx b/apps/storybook/src/stories/Surfaces/Popover.stories.tsx new file mode 100644 index 0000000..3c3e19d --- /dev/null +++ b/apps/storybook/src/stories/Surfaces/Popover.stories.tsx @@ -0,0 +1,39 @@ +import { Button, Input, Label, Popover, PopoverContent, PopoverTrigger } from "@repo/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta = { + component: Popover, + title: "Surfaces/Popover", + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + +
+
+

Dimensions

+

Set the dimensions for the layer.

+
+
+
+ + +
+
+ + +
+
+
+
+
+ ), +}; diff --git a/biome.json b/biome.json index 7e70697..b64b498 100644 --- a/biome.json +++ b/biome.json @@ -6,6 +6,32 @@ "recommended": true } }, + "overrides": [ + { + "includes": ["packages/ui/src/components/ui/**"], + "linter": { + "rules": { + "a11y": { + "useFocusableInteractive": "off", + "useSemanticElements": "off", + "useAriaPropsForRole": "off", + "noRedundantRoles": "off", + "useKeyWithClickEvents": "off" + }, + "security": { + "noDangerouslySetInnerHtml": "off" + }, + "suspicious": { + "noArrayIndexKey": "off", + "noDocumentCookie": "off" + }, + "correctness": { + "useExhaustiveDependencies": "off" + } + } + } + } + ], "formatter": { "enabled": true, "indentStyle": "space", diff --git a/bun.lock b/bun.lock index a1a6def..3581cf1 100644 --- a/bun.lock +++ b/bun.lock @@ -65,6 +65,16 @@ "version": "0.0.0", "dependencies": { "@repo/ui": "workspace:*", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", + "input-otp": "^1.4.2", + "lucide-react": "^1.8.0", + "react-day-picker": "^9.14.0", + "react-resizable-panels": "^4.10.0", + "recharts": "^3.8.1", + "sonner": "^2.0.7", + "vaul": "^1.1.2", }, "devDependencies": { "@storybook/addon-docs": "10.3.5", @@ -99,12 +109,22 @@ "@repo/common": "workspace:*", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", + "input-otp": "^1.4.2", "lucide-react": "^1.8.0", "monorepo-networker": "^2.1.0", + "next-themes": "^0.4.6", "radix-ui": "^1.4.3", "react": "^19.2.5", + "react-day-picker": "^9.14.0", "react-dom": "^19.2.5", + "react-resizable-panels": "^4.10.0", + "recharts": "3.8.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", + "vaul": "^1.1.2", }, "devDependencies": { "@iconify/types": "^2.0.0", @@ -376,6 +396,8 @@ "@changesets/write": ["@changesets/write@0.4.0", "", { "dependencies": { "@changesets/types": "^6.1.0", "fs-extra": "^7.0.1", "human-id": "^4.1.1", "prettier": "^2.7.1" } }, "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q=="], + "@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="], + "@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.61.0", "", { "dependencies": { "commander": "^11.1.0", "dotenv": "^17.2.1", "eciesjs": "^0.4.10", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "picomatch": "^4.0.2", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-utL3cpZoFzflyqUkjYbxYujI6STBTmO5LFn4bbin/NZnRWN6wQ7eErhr3/Vpa5h/jicPFC6kTa42r940mQftJQ=="], "@ducanh2912/next-pwa": ["@ducanh2912/next-pwa@10.2.9", "", { "dependencies": { "fast-glob": "3.3.2", "semver": "7.6.3", "workbox-build": "7.1.1", "workbox-core": "7.1.0", "workbox-webpack-plugin": "7.1.0", "workbox-window": "7.1.0" }, "peerDependencies": { "next": ">=14.0.0", "webpack": ">=5.9.0" } }, "sha512-Wtu823+0Ga1owqSu1I4HqKgeRYarduCCKwsh1EJmJiJqgbt+gvVf5cFwFH8NigxYyyEvriAro4hzm0pMSrXdRQ=="], @@ -738,6 +760,8 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + "@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ=="], + "@repo/common": ["@repo/common@workspace:packages/common"], "@repo/design-plugin": ["@repo/design-plugin@workspace:apps/design-plugin"], @@ -866,6 +890,8 @@ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], + "@storybook/addon-docs": ["@storybook/addon-docs@10.3.5", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.3.5", "@storybook/icons": "^2.0.1", "@storybook/react-dom-shim": "10.3.5", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.3.5" } }, "sha512-WuHbxia/o5TX4Rg/IFD0641K5qId/Nk0dxhmAUNoFs5L0+yfZUwh65XOBbzXqrkYmYmcVID4v7cgDRmzstQNkA=="], "@storybook/builder-vite": ["@storybook/builder-vite@10.3.5", "", { "dependencies": { "@storybook/csf-plugin": "10.3.5", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.3.5", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-i4KwCOKbhtlbQIbhm53+Kk7bMnxa0cwTn1pxmtA/x5wm1Qu7FrrBQV0V0DNjkUqzcSKo1CjspASJV/HlY0zYlw=="], @@ -914,6 +940,8 @@ "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + "@tabby_ai/hijri-converter": ["@tabby_ai/hijri-converter@1.0.5", "", {}, "sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ=="], + "@tailwindcss/node": ["@tailwindcss/node@4.2.3", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.3" } }, "sha512-dhXFXkW2dGvX4r/fi24gyXM0t1mFMrpykQjqrdA4SuavaMagm4SY1u5G2SCJwu1/0x/5RlZJ2VPjP3mKYQfCkA=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.3", "@tailwindcss/oxide-darwin-arm64": "4.2.3", "@tailwindcss/oxide-darwin-x64": "4.2.3", "@tailwindcss/oxide-freebsd-x64": "4.2.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.3", "@tailwindcss/oxide-linux-arm64-musl": "4.2.3", "@tailwindcss/oxide-linux-x64-gnu": "4.2.3", "@tailwindcss/oxide-linux-x64-musl": "4.2.3", "@tailwindcss/oxide-wasm32-wasi": "4.2.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.3", "@tailwindcss/oxide-win32-x64-msvc": "4.2.3" } }, "sha512-YyhwSBcxHLS3CU2Mk3dXDuVm8/Ia0+XvfpT8s9YQoICppkUeoobB3hgyGMYbyQ4vn6VgWH9bdv5UnzhTz2NPTQ=="], @@ -980,6 +1008,24 @@ "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], + + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + + "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], + + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + + "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], + + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + + "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], + + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + + "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], @@ -1018,6 +1064,8 @@ "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], + "@types/validate-npm-package-name": ["@types/validate-npm-package-name@4.0.2", "", {}, "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw=="], "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], @@ -1222,6 +1270,8 @@ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="], + "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], @@ -1278,6 +1328,28 @@ "cuint": ["cuint@0.2.2", "", {}, "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw=="], + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + + "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], + + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + + "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], + + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + + "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], + + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], @@ -1288,8 +1360,14 @@ "dataloader": ["dataloader@1.4.0", "", {}, "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw=="], + "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="], + + "date-fns-jalali": ["date-fns-jalali@4.1.0-0", "", {}, "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], "dedent": ["dedent@1.7.2", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA=="], @@ -1354,6 +1432,12 @@ "electron-to-chromium": ["electron-to-chromium@1.5.334", "", {}, "sha512-mgjZAz7Jyx1SRCwEpy9wefDS7GvNPazLthHg8eQMJ76wBdGQQDW33TCrUTvQ4wzpmOrv2zrFoD3oNufMdyMpog=="], + "embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="], + + "embla-carousel-react": ["embla-carousel-react@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA=="], + + "embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="], + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="], @@ -1388,6 +1472,8 @@ "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + "es-toolkit": ["es-toolkit@1.46.0", "", {}, "sha512-IToJ6ct9OLl5zz6WsC/1vZEwfSZ7Myil+ygl5Tf30Xjn9AEkzNB4kqp2G7VUJKF1DtTx/ra5M5KLlXvzOg51BA=="], + "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], @@ -1592,6 +1678,8 @@ "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], + "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="], + "immutable": ["immutable@5.1.5", "", {}, "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A=="], "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], @@ -1604,8 +1692,12 @@ "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -2118,6 +2210,8 @@ "react": ["react@19.2.5", "", {}, "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA=="], + "react-day-picker": ["react-day-picker@9.14.0", "", { "dependencies": { "@date-fns/tz": "^1.4.1", "@tabby_ai/hijri-converter": "1.0.5", "date-fns": "^4.1.0", "date-fns-jalali": "4.1.0-0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA=="], + "react-docgen": ["react-docgen@8.0.3", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.2", "@types/babel__core": "^7.20.5", "@types/babel__traverse": "^7.20.7", "@types/doctrine": "^0.0.9", "@types/resolve": "^1.20.2", "doctrine": "^3.0.0", "resolve": "^1.22.1", "strip-indent": "^4.0.0" } }, "sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w=="], "react-docgen-typescript": ["react-docgen-typescript@2.4.0", "", { "peerDependencies": { "typescript": ">= 4.3.x" } }, "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg=="], @@ -2128,10 +2222,14 @@ "react-medium-image-zoom": ["react-medium-image-zoom@5.4.3", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-cDIwdn35fRUPsGnnj/cG6Pacll+z+Mfv6EWU2wDO5ngbZjg5uLRb2ZhEnh92ufbXCJDFvXHekb8G3+oKqUcv5g=="], + "react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="], + "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + "react-resizable-panels": ["react-resizable-panels@4.10.0", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-frjewRQt7TCv/vCH1pJfjZ7RxAhr5pKuqVQtVgzFq/vherxBFOWyC3xMbryx5Ti2wylViGUFc93Etg4rB3E0UA=="], + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], @@ -2142,6 +2240,8 @@ "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], + "recharts": ["recharts@3.8.1", "", { "dependencies": { "@reduxjs/toolkit": "^1.9.0 || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg=="], + "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], @@ -2152,6 +2252,10 @@ "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], + "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], + + "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], @@ -2190,6 +2294,8 @@ "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], @@ -2282,6 +2388,8 @@ "snake-case": ["snake-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg=="], + "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], + "source-list-map": ["source-list-map@2.0.1", "", {}, "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="], "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], @@ -2486,10 +2594,14 @@ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], + "vite": ["vite@8.0.8", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.15", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw=="], "vite-plugin-generate-file": ["vite-plugin-generate-file@0.3.1", "", { "dependencies": { "ejs": "^3.1.9", "js-yaml": "^4.1.0", "mime-types": "^2.1.35", "picocolors": "^1.0.0" } }, "sha512-tiA3gkPM21MS2+RyqsBMT33GSlM9LM1TJjf6vGvV/e/ml3e3vTKfuH3l2N0NpUgcayvj1fXnmlo5YBuahA6bsg=="], @@ -2632,9 +2744,13 @@ "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="], + "@repo/storybook/@tailwindcss/vite": ["@tailwindcss/vite@4.2.4", "", { "dependencies": { "@tailwindcss/node": "4.2.4", "@tailwindcss/oxide": "4.2.4", "tailwindcss": "4.2.4" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw=="], - "@repo/ui/tailwindcss": ["tailwindcss@4.2.3", "", {}, "sha512-fA/NX5gMf0ooCLISgB0wScaWgaj6rjTN2SVAwleURjiya7ITNkV+VMmoHtKkldP6CIZoYCZyxb8zP/e2TWoEtQ=="], + "@repo/ui/recharts": ["recharts@3.8.0", "", { "dependencies": { "@reduxjs/toolkit": "^1.9.0 || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ=="], + + "@repo/ui/tailwindcss": ["tailwindcss@4.2.4", "", {}, "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA=="], "@rollup/plugin-babel/@rollup/pluginutils": ["@rollup/pluginutils@3.1.0", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="], diff --git a/packages/ui/package.json b/packages/ui/package.json index ed2365c..d22b926 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -19,12 +19,22 @@ "@repo/common": "workspace:*", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", + "input-otp": "^1.4.2", "lucide-react": "^1.8.0", "monorepo-networker": "^2.1.0", + "next-themes": "^0.4.6", "radix-ui": "^1.4.3", "react": "^19.2.5", + "react-day-picker": "^9.14.0", "react-dom": "^19.2.5", - "tailwind-merge": "^3.5.0" + "react-resizable-panels": "^4.10.0", + "recharts": "3.8.0", + "sonner": "^2.0.7", + "tailwind-merge": "^3.5.0", + "vaul": "^1.1.2" }, "devDependencies": { "@testing-library/jest-dom": "^6.9.1", diff --git a/packages/ui/src/components/ui/alert-dialog.test.tsx b/packages/ui/src/components/ui/alert-dialog.test.tsx new file mode 100644 index 0000000..64f87a5 --- /dev/null +++ b/packages/ui/src/components/ui/alert-dialog.test.tsx @@ -0,0 +1,79 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "./alert-dialog"; + +describe("AlertDialog interaction tests", () => { + it("opens when trigger is clicked", async () => { + render( + + Open + + + Are you sure? + This action cannot be undone. + + + Cancel + Continue + + + + ); + expect(screen.queryByText("Are you sure?")).not.toBeInTheDocument(); + await userEvent.click(screen.getByText("Open")); + expect(screen.getByText("Are you sure?")).toBeInTheDocument(); + }); + + it("closes when cancel is clicked", async () => { + render( + + Open + + + Are you sure? + + + Cancel + Continue + + + + ); + await userEvent.click(screen.getByText("Open")); + expect(screen.getByText("Are you sure?")).toBeInTheDocument(); + await userEvent.click(screen.getByText("Cancel")); + expect(screen.queryByText("Are you sure?")).not.toBeInTheDocument(); + }); + + it("fires action callback when action is clicked", async () => { + const onAction = vi.fn(); + render( + + Open + + + Confirm + + + Cancel + Continue + + + + ); + await userEvent.click(screen.getByText("Open")); + await userEvent.click(screen.getByText("Continue")); + expect(onAction).toHaveBeenCalledOnce(); + }); +}); diff --git a/packages/ui/src/components/ui/alert-dialog.tsx b/packages/ui/src/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..39680d3 --- /dev/null +++ b/packages/ui/src/components/ui/alert-dialog.tsx @@ -0,0 +1,179 @@ +import { Button } from "@repo/ui/components/ui/button"; +import { cn } from "@repo/ui/lib/utils"; +import { AlertDialog as AlertDialogPrimitive } from "radix-ui"; +import type * as React from "react"; + +function AlertDialog({ ...props }: React.ComponentProps) { + return ; +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ; +} + +function AlertDialogPortal({ ...props }: React.ComponentProps) { + return ; +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogContent({ + className, + size = "default", + ...props +}: React.ComponentProps & { + size?: "default" | "sm"; +}) { + return ( + + + + + ); +} + +function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDialogMedia({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogAction({ + className, + variant = "default", + size = "default", + ...props +}: React.ComponentProps & + Pick, "variant" | "size">) { + return ( + + ); +} + +function AlertDialogCancel({ + className, + variant = "outline", + size = "default", + ...props +}: React.ComponentProps & + Pick, "variant" | "size">) { + return ( + + ); +} + +export { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogMedia, + AlertDialogOverlay, + AlertDialogPortal, + AlertDialogTitle, + AlertDialogTrigger, +}; diff --git a/packages/ui/src/components/ui/aspect-ratio.tsx b/packages/ui/src/components/ui/aspect-ratio.tsx new file mode 100644 index 0000000..b66a572 --- /dev/null +++ b/packages/ui/src/components/ui/aspect-ratio.tsx @@ -0,0 +1,7 @@ +import { AspectRatio as AspectRatioPrimitive } from "radix-ui"; + +function AspectRatio({ ...props }: React.ComponentProps) { + return ; +} + +export { AspectRatio }; diff --git a/packages/ui/src/components/ui/avatar.test.tsx b/packages/ui/src/components/ui/avatar.test.tsx new file mode 100644 index 0000000..9a04805 --- /dev/null +++ b/packages/ui/src/components/ui/avatar.test.tsx @@ -0,0 +1,35 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; +import { Avatar, AvatarFallback, AvatarImage } from "./avatar"; + +describe("Avatar interaction tests", () => { + it("renders fallback when no image is provided", () => { + render( + + JB + + ); + expect(screen.getByText("JB")).toBeInTheDocument(); + }); + + it("renders fallback when image fails to load", () => { + render( + + + FB + + ); + // Fallback should be rendered since the image won't load in tests + expect(screen.getByText("FB")).toBeInTheDocument(); + }); + + it("renders with size variant", () => { + const { container } = render( + + LG + + ); + const avatar = container.querySelector('[data-slot="avatar"]'); + expect(avatar).toHaveAttribute("data-size", "lg"); + }); +}); diff --git a/packages/ui/src/components/ui/avatar.tsx b/packages/ui/src/components/ui/avatar.tsx new file mode 100644 index 0000000..df00293 --- /dev/null +++ b/packages/ui/src/components/ui/avatar.tsx @@ -0,0 +1,95 @@ +"use client"; + +import { cn } from "@repo/ui/lib/utils"; +import { Avatar as AvatarPrimitive } from "radix-ui"; +import type * as React from "react"; + +function Avatar({ + className, + size = "default", + ...props +}: React.ComponentProps & { + size?: "default" | "sm" | "lg"; +}) { + return ( + + ); +} + +function AvatarImage({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { + return ( + svg]:hidden", + "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", + "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", + className + )} + {...props} + /> + ); +} + +function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AvatarGroupCount({ className, ...props }: React.ComponentProps<"div">) { + return ( +
svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", + className + )} + {...props} + /> + ); +} + +export { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage }; diff --git a/packages/ui/src/components/ui/badge.tsx b/packages/ui/src/components/ui/badge.tsx new file mode 100644 index 0000000..2051ac9 --- /dev/null +++ b/packages/ui/src/components/ui/badge.tsx @@ -0,0 +1,44 @@ +import { cn } from "@repo/ui/lib/utils"; +import { cva, type VariantProps } from "class-variance-authority"; +import { Slot } from "radix-ui"; +import type * as React from "react"; + +const badgeVariants = cva( + "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80", + destructive: + "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20", + outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground", + ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50", + link: "text-primary underline-offset-4 hover:underline", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +function Badge({ + className, + variant = "default", + asChild = false, + ...props +}: React.ComponentProps<"span"> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot.Root : "span"; + + return ( + + ); +} + +export { Badge, badgeVariants }; diff --git a/packages/ui/src/components/ui/breadcrumb.test.tsx b/packages/ui/src/components/ui/breadcrumb.test.tsx new file mode 100644 index 0000000..970c648 --- /dev/null +++ b/packages/ui/src/components/ui/breadcrumb.test.tsx @@ -0,0 +1,48 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "./breadcrumb"; + +describe("Breadcrumb interaction tests", () => { + it("renders links and current page", () => { + render( + + + + Home + + + + Docs + + + + Current + + + + ); + expect(screen.getByText("Home")).toBeInTheDocument(); + expect(screen.getByText("Docs")).toBeInTheDocument(); + expect(screen.getByText("Current")).toBeInTheDocument(); + }); + + it("marks current page with aria-current", () => { + render( + + + + Current + + + + ); + expect(screen.getByText("Current")).toHaveAttribute("aria-current", "page"); + }); +}); diff --git a/packages/ui/src/components/ui/breadcrumb.tsx b/packages/ui/src/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..4a8de1b --- /dev/null +++ b/packages/ui/src/components/ui/breadcrumb.tsx @@ -0,0 +1,103 @@ +import { cn } from "@repo/ui/lib/utils"; +import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"; +import { Slot } from "radix-ui"; +import type * as React from "react"; + +function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) { + return ( +