TRIVIAL: Add xray-core-subnet-mimicry article (#4)

This commit is contained in:
deytenit authored and GitHub committed 2026-03-08 02:29:09 +03:00
1 parent 49b545f1b4
commit ea35a3d9f5
21 files changed
+785 -79

No files matched your search

@@ -33,6 +33,18 @@ export const Default: Story = {
),
};
export const Interactive: Story = {
render: () => (
<Breadcrumbs>
<Breadcrumbs.Item href="/">Home</Breadcrumbs.Item>
<Breadcrumbs.Separator variant="arrow" />
<Breadcrumbs.Item onClick={() => alert('Clicked!')}>Click Me</Breadcrumbs.Item>
<Breadcrumbs.Separator variant="arrow" />
<Breadcrumbs.Item isCurrent>Current Page</Breadcrumbs.Item>
</Breadcrumbs>
),
};
export const WithArrows: Story = {
render: () => (
<Breadcrumbs>
@@ -1,7 +1,7 @@
import React from 'react';
import { Breadcrumbs } from './Breadcrumbs';
import { render, screen } from '../../lib/testing';
import { render, screen, fireEvent } from '../../lib/testing';
import { Link } from '../Link/Link';
describe('components/Breadcrumbs', () => {
@@ -12,14 +12,58 @@ describe('components/Breadcrumbs', () => {
<Link href="/">Home</Link>
</Breadcrumbs.Item>
<Breadcrumbs.Separator variant="slash" />
<Breadcrumbs.Item>Current</Breadcrumbs.Item>
<Breadcrumbs.Item isCurrent>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();
const currentItem = screen.getByText('Current').parentElement;
expect(currentItem).toHaveAttribute('aria-current', 'page');
});
it('supports isCurrent state', () => {
render(
<Breadcrumbs>
<Breadcrumbs.Item isCurrent>Current Page</Breadcrumbs.Item>
</Breadcrumbs>
);
const item = screen.getByText('Current Page').parentElement;
expect(item).toHaveAttribute('aria-current', 'page');
});
it('supports href directly on Item', () => {
render(
<Breadcrumbs>
<Breadcrumbs.Item href="/test-url">Test Link</Breadcrumbs.Item>
</Breadcrumbs>
);
const link = screen.getByRole('link', { name: 'Test Link' });
expect(link).toHaveAttribute('href', '/test-url');
});
it('supports onClick on Item', () => {
const handleClick = vi.fn();
render(
<Breadcrumbs>
<Breadcrumbs.Item onClick={handleClick}>Clickable</Breadcrumbs.Item>
</Breadcrumbs>
);
const button = screen.getByRole('button', { name: 'Clickable' });
fireEvent.click(button);
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('renders as a non-submit button when onClick is provided', () => {
render(
<Breadcrumbs>
<Breadcrumbs.Item onClick={vi.fn()}>Clickable</Breadcrumbs.Item>
</Breadcrumbs>
);
const button = screen.getByRole('button', { name: 'Clickable' });
expect(button).toHaveAttribute('type', 'button');
});
it('supports different separator variants', () => {
@@ -29,20 +29,57 @@ const BreadcrumbsRoot = memo(function Breadcrumbs({ children, ...props }: Breadc
);
});
/**
* Props for the individual Breadcrumbs item.
*/
export interface BreadcrumbsItemProps extends TestIdProps {
/** Content to be rendered inside the item */
children: React.ReactNode;
/** Optional className for the list item */
className?: string;
/** Whether this is the current page */
isCurrent?: boolean;
/** Optional href for the item (renders as a link) */
href?: string;
/** Optional click handler for the item */
onClick?: React.MouseEventHandler<HTMLElement>;
}
/**
* Individual step in the breadcrumb trail.
*/
const BreadcrumbsItem = memo(function BreadcrumbsItem({
children,
className,
isCurrent,
href,
onClick,
'data-testid': testId,
}: {
children: React.ReactNode;
className?: string;
} & TestIdProps) {
}: BreadcrumbsItemProps) {
const isClickable = !!(href ?? onClick);
return (
<li className={className} data-testid={testId}>
<Text color="muted" size="m" type="label">
<li
aria-current={isCurrent ? 'page' : undefined}
className={cn(
'group flex items-center transition-all duration-200',
!isCurrent && isClickable && 'cursor-pointer',
className
)}
data-testid={testId}
>
<Text
as={href ? 'a' : onClick ? 'button' : 'span'}
className={cn(
'transition-all duration-200',
!isCurrent && 'group-hover:text-[var(--rb-text)] group-hover:underline underline-offset-4'
)}
color={isCurrent ? 'default' : 'muted'}
href={href}
size="m"
type="label"
onClick={onClick}
>
{children}
</Text>
</li>