refactor: Refactor UI structure
This commit is contained in:
33 files changed
+435
-247
No files matched your search
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Breadcrumbs } from './Breadcrumbs';
|
||||
import { Link } from '../Link/Link';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
const meta: Meta<typeof Breadcrumbs> = {
|
||||
title: 'components/Breadcrumbs',
|
||||
component: Breadcrumbs,
|
||||
tags: ['autodocs'],
|
||||
};
|
||||
|
||||
export default meta;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
type Story = StoryObj<typeof Breadcrumbs>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => (
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>
|
||||
<Link href="/">Home</Link>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator variant="slash" />
|
||||
<Breadcrumbs.Item>
|
||||
<Link href="/blog">Blog</Link>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator variant="slash" />
|
||||
<Breadcrumbs.Item>Modern Web Design</Breadcrumbs.Item>
|
||||
</Breadcrumbs>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithArrows: Story = {
|
||||
render: () => (
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>
|
||||
<Link href="/">Home</Link>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator variant="arrow" />
|
||||
<Breadcrumbs.Item>
|
||||
<Link href="/docs">Docs</Link>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator variant="arrow" />
|
||||
<Breadcrumbs.Item>Components</Breadcrumbs.Item>
|
||||
</Breadcrumbs>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithBullets: Story = {
|
||||
render: () => (
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>
|
||||
<Link href="/">Home</Link>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator variant="bull" />
|
||||
<Breadcrumbs.Item>
|
||||
<Link href="/about">About</Link>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator variant="bull" />
|
||||
<Breadcrumbs.Item>Team</Breadcrumbs.Item>
|
||||
</Breadcrumbs>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Breadcrumbs } from './Breadcrumbs';
|
||||
import { render, screen } from '../../../test-utils';
|
||||
import { Link } from '../Link/Link';
|
||||
|
||||
describe('components/generic/Breadcrumbs', () => {
|
||||
it('renders correctly with multiple items and separators', () => {
|
||||
render(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>
|
||||
<Link href="/">Home</Link>
|
||||
</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator variant="slash" />
|
||||
<Breadcrumbs.Item>Current</Breadcrumbs.Item>
|
||||
</Breadcrumbs>
|
||||
);
|
||||
|
||||
expect(screen.getByRole('navigation')).toHaveAttribute('aria-label', 'Breadcrumb');
|
||||
expect(screen.getByRole('link', { name: 'Home' })).toBeInTheDocument();
|
||||
expect(screen.getByText('/')).toBeInTheDocument();
|
||||
expect(screen.getByText('Current')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('supports different separator variants', () => {
|
||||
const { rerender } = render(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Separator data-testid="sep" variant="bull" />
|
||||
</Breadcrumbs>
|
||||
);
|
||||
expect(screen.getByTestId('sep')).toHaveTextContent('•');
|
||||
|
||||
rerender(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Separator data-testid="sep" variant="slash" />
|
||||
</Breadcrumbs>
|
||||
);
|
||||
expect(screen.getByTestId('sep')).toHaveTextContent('/');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
import { cn } from '@ermnvldmr/stl';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import React, { memo } from 'react';
|
||||
|
||||
import { HStack } from '../HStack/HStack';
|
||||
import { Text } from '../Text/Text';
|
||||
|
||||
import type { HStackProps } from '../HStack/HStack';
|
||||
import type { ClassNameProps, TestIdProps } from '@ermnvldmr/stl';
|
||||
|
||||
/**
|
||||
* Props for the Breadcrumbs component.
|
||||
*/
|
||||
export interface BreadcrumbsProps extends HStackProps {
|
||||
/** Breadcrumb items and separators */
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Root component for hierarchical navigation.
|
||||
*/
|
||||
const BreadcrumbsRoot = memo(function Breadcrumbs({ children, ...props }: BreadcrumbsProps) {
|
||||
return (
|
||||
<nav aria-label="Breadcrumb">
|
||||
<HStack align="center" as="ol" gap={2} {...props}>
|
||||
{children}
|
||||
</HStack>
|
||||
</nav>
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Individual step in the breadcrumb trail.
|
||||
*/
|
||||
const BreadcrumbsItem = memo(function BreadcrumbsItem({
|
||||
children,
|
||||
className,
|
||||
'data-testid': testId,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
} & TestIdProps) {
|
||||
return (
|
||||
<li className={className} data-testid={testId}>
|
||||
<Text color="muted" size="m" type="label">
|
||||
{children}
|
||||
</Text>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Visual divider between breadcrumb items.
|
||||
*/
|
||||
export interface BreadcrumbsSeparatorProps extends ClassNameProps, TestIdProps {
|
||||
/** Visual variant of the separator */
|
||||
variant?: 'slash' | 'bull' | 'arrow';
|
||||
}
|
||||
|
||||
const BreadcrumbsSeparator = memo(function BreadcrumbsSeparator({
|
||||
variant = 'slash',
|
||||
className,
|
||||
'data-testid': testId,
|
||||
}: BreadcrumbsSeparatorProps) {
|
||||
const content = {
|
||||
slash: '/',
|
||||
bull: '•',
|
||||
arrow: <ChevronRight className="size-4" />,
|
||||
};
|
||||
|
||||
return (
|
||||
<li
|
||||
aria-hidden="true"
|
||||
className={cn('text-[var(--rb-muted-text)]', className)}
|
||||
data-testid={testId}
|
||||
>
|
||||
<Text color="muted" size="m" type="label">
|
||||
{content[variant]}
|
||||
</Text>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* A hierarchical navigation component.
|
||||
*
|
||||
* Breadcrumbs provides a flexible way to display the current location within
|
||||
* a site's hierarchy. It uses a compound component pattern for maximum flexibility.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <Breadcrumbs>
|
||||
* <Breadcrumbs.Item><Link href="/">Home</Link></Breadcrumbs.Item>
|
||||
* <Breadcrumbs.Separator variant="arrow" />
|
||||
* <Breadcrumbs.Item>Current Page</Breadcrumbs.Item>
|
||||
* </Breadcrumbs>
|
||||
* ```
|
||||
*/
|
||||
export const Breadcrumbs = Object.assign(BreadcrumbsRoot, {
|
||||
Item: BreadcrumbsItem,
|
||||
Separator: BreadcrumbsSeparator,
|
||||
});
|
||||
Reference in new issue
Block a user