diff --git a/apps/www/src/content/docs/components/navbar/index.mdx b/apps/www/src/content/docs/components/navbar/index.mdx index ad04488c5..f3fe11496 100644 --- a/apps/www/src/content/docs/components/navbar/index.mdx +++ b/apps/www/src/content/docs/components/navbar/index.mdx @@ -23,6 +23,7 @@ import { Navbar } from "@raystack/apsara"; + ``` @@ -41,6 +42,12 @@ The start section is a container component that accepts all `div` props. It's co +### Center + +The center section sits between Start and End and centers its content. It accepts all `div` props. + + + ### End The end section is a container component that accepts all `div` props. It's commonly used for search inputs, action buttons, user menus, or secondary navigation. @@ -73,7 +80,7 @@ The Navbar implements the following accessibility features: - Proper ARIA roles and attributes - `role="navigation"` for the main navbar - - `role="group"` for Start and End sections when `aria-label` is provided + - `role="group"` for Start, Center, and End sections when `aria-label` is provided - Customizable `aria-label` and `aria-labelledby` support - Semantic HTML diff --git a/apps/www/src/content/docs/components/navbar/props.ts b/apps/www/src/content/docs/components/navbar/props.ts index cca5b6f97..d71584c08 100644 --- a/apps/www/src/content/docs/components/navbar/props.ts +++ b/apps/www/src/content/docs/components/navbar/props.ts @@ -5,6 +5,12 @@ export interface NavbarRootProps { */ sticky?: boolean; + /** + * Show the bottom shadow. + * @default true + */ + shadow?: boolean; + /** * Accessible label for the navigation. * Use this to provide a description of the navbar's purpose. @@ -27,6 +33,13 @@ export interface NavbarStartProps { 'aria-label'?: string; } +export interface NavbarCenterProps { + /** + * Accessible label for the center section. When provided, the section will have `role="group"`. + */ + 'aria-label'?: string; +} + export interface NavbarEndProps { /** * Accessible label for the end section. Use this to describe the purpose diff --git a/packages/raystack/components/navbar/__tests__/navbar.test.tsx b/packages/raystack/components/navbar/__tests__/navbar.test.tsx index 394504123..c4ff2c86c 100644 --- a/packages/raystack/components/navbar/__tests__/navbar.test.tsx +++ b/packages/raystack/components/navbar/__tests__/navbar.test.tsx @@ -1,8 +1,8 @@ import { render, screen } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; import { Navbar } from '../navbar'; -import { NavbarRootProps } from '../navbar-root'; import styles from '../navbar.module.css'; +import { NavbarRootProps } from '../navbar-root'; const START_TEXT = 'Explore'; const END_BUTTON_TEXT = 'Action'; @@ -118,6 +118,22 @@ describe('Navbar', () => { }); }); + describe('Shadow', () => { + it('shows shadow by default', () => { + render(); + + const nav = screen.getByRole('navigation'); + expect(nav).toHaveAttribute('data-shadow', 'true'); + }); + + it('hides shadow when shadow is false', () => { + render(); + + const nav = screen.getByRole('navigation'); + expect(nav).toHaveAttribute('data-shadow', 'false'); + }); + }); + describe('Navbar.Start', () => { it('renders start section content', () => { render( @@ -204,6 +220,31 @@ describe('Navbar', () => { }); }); + describe('Navbar.Center', () => { + it('renders center section content', () => { + render( + + + Center + + + ); + + expect(screen.getByText('Center')).toBeInTheDocument(); + }); + + it('applies center styles', () => { + const { container } = render( + + + + ); + + const center = container.querySelector(`.${styles.center}`); + expect(center).toBeInTheDocument(); + }); + }); + describe('Navbar.End', () => { it('renders end section content', () => { render( @@ -369,18 +410,21 @@ describe('Navbar', () => { expect(containerEl).toBeInTheDocument(); }); - it('positions Start and End correctly', () => { + it('positions Start, Center, and End correctly', () => { const { container } = render( Start + Center End ); const start = container.querySelector(`.${styles.start}`); + const center = container.querySelector(`.${styles.center}`); const end = container.querySelector(`.${styles.end}`); expect(start).toBeInTheDocument(); + expect(center).toBeInTheDocument(); expect(end).toBeInTheDocument(); }); }); diff --git a/packages/raystack/components/navbar/navbar-root.tsx b/packages/raystack/components/navbar/navbar-root.tsx index 6700cd388..84c13a3d4 100644 --- a/packages/raystack/components/navbar/navbar-root.tsx +++ b/packages/raystack/components/navbar/navbar-root.tsx @@ -7,15 +7,17 @@ import styles from './navbar.module.css'; export interface NavbarRootProps extends ComponentPropsWithoutRef<'nav'> { sticky?: boolean; + shadow?: boolean; } export const NavbarRoot = forwardRef, NavbarRootProps>( - ({ className, sticky = false, children, ...props }, ref) => { + ({ className, sticky = false, shadow = true, children, ...props }, ref) => { return (