diff --git a/apps/docs/package.json b/apps/docs/package.json index 56794357..fd574fbe 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -13,6 +13,7 @@ "chromatic": "pnpm dlx chromatic --exit-zero-on-changes " }, "dependencies": { + "@signozhq/breadcrumb": "workspace:*", "@signozhq/table": "workspace:*", "@signozhq/callout": "workspace:*", "@signozhq/badge": "workspace:*", diff --git a/apps/docs/stories/breadcrumb.stories.tsx b/apps/docs/stories/breadcrumb.stories.tsx new file mode 100644 index 00000000..6991a416 --- /dev/null +++ b/apps/docs/stories/breadcrumb.stories.tsx @@ -0,0 +1,182 @@ +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import Breadcrumb from '@signozhq/breadcrumb'; +import { generateDocs } from '../utils/generateDocs'; + +const breadcrumbExamples = [ + `import Breadcrumb from '@signozhq/breadcrumb'; + +export default function MyComponent() { + return ( + + ); +}`, + `import Breadcrumb from '@signozhq/breadcrumb'; + +export default function MyComponent() { + const handleClick = (item: string) => { + console.log('Clicked:', item); + // Handle navigation here + }; + + return ( + handleClick('Home') }, + { title: 'Components', onClick: () => handleClick('Components') }, + { title: 'Breadcrumb' }, + ]} + /> + ); +}`, +]; + +const breadcrumbDocs = generateDocs({ + packageName: '@signozhq/breadcrumb', + description: + 'A navigation component that displays the current location within a hierarchy and allows users to navigate back to higher levels.', + examples: breadcrumbExamples, +}); + +const meta: Meta = { + title: 'Components/Breadcrumb', + component: Breadcrumb, + parameters: { + docs: { + description: { + component: breadcrumbDocs, + }, + }, + backgrounds: { + disable: true, + }, + }, + tags: ['autodocs'], + argTypes: { + items: { + control: 'object', + description: + 'Array of breadcrumb items with title, href, and onClick properties', + }, + separator: { + control: 'text', + description: 'Custom separator between breadcrumb items (defaults to "/")', + }, + className: { + control: 'text', + description: 'Additional CSS classes for styling', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + items: [{ title: 'Home' }, { title: 'Components' }, { title: 'Breadcrumb' }], + }, +}; + +export const WithClickHandlers: Story = { + args: { + items: [ + { + title: 'Home', + onClick: () => alert('Home clicked'), + }, + { + title: 'Components', + onClick: () => alert('Components clicked'), + }, + { title: 'Breadcrumb' }, + ], + }, +}; + +export const WithLinks: Story = { + args: { + items: [ + { title: 'Home', href: '/' }, + { title: 'Components', href: '/components' }, + { title: 'Breadcrumb' }, + ], + }, +}; + +export const CustomSeparator: Story = { + args: { + items: [{ title: 'Home' }, { title: 'Components' }, { title: 'Breadcrumb' }], + separator: '>', + }, +}; + +export const LongText: Story = { + args: { + items: [ + { title: 'Home' }, + { title: 'this is a very long breadcrumb that will be truncated' }, + { title: 'Breadcrumb' }, + ], + }, +}; + +export const Showcase: Story = { + render: () => ( +
+
+

Basic

+ +
+ +
+

With Click Handlers

+ alert('Home clicked') }, + { title: 'Components', onClick: () => alert('Components clicked') }, + { title: 'Breadcrumb' }, + ]} + /> +
+ +
+

Custom Separator

+ +
+ +
+

Long Text (Truncated)

+ +
+
+ ), +}; diff --git a/packages/breadcrumb/.eslintrc.js b/packages/breadcrumb/.eslintrc.js new file mode 100644 index 00000000..003e695c --- /dev/null +++ b/packages/breadcrumb/.eslintrc.js @@ -0,0 +1,4 @@ +/** @type {import("eslint").Linter.Config} */ +export default { + extends: ['@repo/eslint-config/react.js'], +}; diff --git a/packages/breadcrumb/.gitignore b/packages/breadcrumb/.gitignore new file mode 100644 index 00000000..f06235c4 --- /dev/null +++ b/packages/breadcrumb/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/packages/breadcrumb/components.json b/packages/breadcrumb/components.json new file mode 100644 index 00000000..dd053426 --- /dev/null +++ b/packages/breadcrumb/components.json @@ -0,0 +1,19 @@ +{ + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "@signozhq/tailwind-config/tailwind.config.js", + "css": "src/index.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "src", + "lib": "@/lib", + "hooks": "@/hooks" + } +} diff --git a/packages/breadcrumb/package.json b/packages/breadcrumb/package.json new file mode 100644 index 00000000..51561a13 --- /dev/null +++ b/packages/breadcrumb/package.json @@ -0,0 +1,58 @@ +{ + "name": "@signozhq/breadcrumb", + "version": "0.0.0", + "license": "MIT", + "type": "module", + "exports": { + ".": { + "types": "./dist/breadcrumb.d.ts", + "import": "./dist/breadcrumb.js" + } + }, + "main": "./dist/breadcrumb.js", + "module": "./dist/breadcrumb.js", + "types": "./dist/breadcrumb.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint . --max-warnings 0", + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*", + "@signozhq/tailwind-config": "workspace:*", + "@tailwindcss/postcss": "^4.1.3", + "@types/node": "^22.5.5", + "@types/react": "^18.2.61", + "@types/react-dom": "^18.2.19", + "@vitejs/plugin-react": "^4.2.1", + "eslint": "^9.11.0", + "postcss": "^8.4.47", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "tailwindcss": "^4.1.3", + "tsup": "^8.0.0", + "typescript": "^5.3.3" + }, + "dependencies": { + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-slot": "^1.2.3", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-react": "^0.445.0", + "@signozhq/tooltip": "workspace:*", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7" + }, + "peerDependencies": { + "react": "^18.2.0" + }, + "publishConfig": { + "access": "public" + }, + "description": "A new package" +} diff --git a/packages/breadcrumb/postcss.config.js b/packages/breadcrumb/postcss.config.js new file mode 100644 index 00000000..1970487b --- /dev/null +++ b/packages/breadcrumb/postcss.config.js @@ -0,0 +1,5 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; diff --git a/packages/breadcrumb/src/breadcrumb.tsx b/packages/breadcrumb/src/breadcrumb.tsx new file mode 100644 index 00000000..4bfaafe0 --- /dev/null +++ b/packages/breadcrumb/src/breadcrumb.tsx @@ -0,0 +1,169 @@ +import './index.css'; +import * as React from 'react'; +import { cn } from './lib/utils'; +import { TooltipProvider } from '@signozhq/tooltip'; + +// Types for the new items-based API +export interface BreadcrumbItemType { + title: React.ReactNode; + href?: string; + onClick?: (e: React.MouseEvent) => void; + className?: string; +} + +export interface BreadcrumbProps extends React.ComponentProps<'nav'> { + items?: BreadcrumbItemType[]; + separator?: React.ReactNode; + className?: string; +} + +function Breadcrumb({ + items, + separator = '/', + className, + ...props +}: BreadcrumbProps) { + if (items) { + return ( + + ); + } + + // Fallback to the original verbose API + return