From a6fa14124d450d42f3706f0d0e0d221de87c3326 Mon Sep 17 00:00:00 2001 From: Amit Haridas Date: Fri, 5 Jun 2026 17:42:21 +0530 Subject: [PATCH] feat(renderer): add shadcn tabs primitive --- package-lock.json | 31 ++++++++++ package.json | 1 + src/renderer/components/ui/tabs.tsx | 91 +++++++++++++++++++++++++++++ tests/component/ui/tabs.test.tsx | 22 +++++++ 4 files changed, 145 insertions(+) create mode 100644 src/renderer/components/ui/tabs.tsx create mode 100644 tests/component/ui/tabs.test.tsx diff --git a/package-lock.json b/package-lock.json index 0fe9d85..64b7656 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "@radix-ui/react-slider": "^1.3.6", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", "@tanstack/react-table": "^8.21.3", "codemirror": "^6.0.2", "core-util-is": "^1.0.3", @@ -4609,6 +4610,36 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", diff --git a/package.json b/package.json index 4932281..626b720 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "@radix-ui/react-slider": "^1.3.6", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", "@tanstack/react-table": "^8.21.3", "codemirror": "^6.0.2", "core-util-is": "^1.0.3", diff --git a/src/renderer/components/ui/tabs.tsx b/src/renderer/components/ui/tabs.tsx new file mode 100644 index 0000000..eb014e6 --- /dev/null +++ b/src/renderer/components/ui/tabs.tsx @@ -0,0 +1,91 @@ +"use client" + +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +function Tabs({ + className, + orientation = "horizontal", + ...props +}: React.ComponentProps) { + return ( + + ) +} + +const tabsListVariants = cva( + "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none", + { + variants: { + variant: { + default: "bg-muted", + line: "gap-1 bg-transparent", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function TabsList({ + className, + variant = "default", + ...props +}: React.ComponentProps & + VariantProps) { + return ( + + ) +} + +function TabsTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants } \ No newline at end of file diff --git a/tests/component/ui/tabs.test.tsx b/tests/component/ui/tabs.test.tsx new file mode 100644 index 0000000..9ca1b8d --- /dev/null +++ b/tests/component/ui/tabs.test.tsx @@ -0,0 +1,22 @@ +import { describe, it, expect } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; + +describe('Tabs', () => { + it('switches content on trigger click', async () => { + render( + + + One + Two + + Content one + Content two + + ); + expect(screen.getByText(/content one/i)).toBeVisible(); + await userEvent.click(screen.getByRole('tab', { name: /two/i })); + expect(screen.getByText(/content two/i)).toBeVisible(); + }); +}); \ No newline at end of file