@razorpay/blade-mcp
Version:
Model Context Protocol server for Blade
297 lines (261 loc) • 7.24 kB
Markdown
## Component Name
BottomNav
## Description
BottomNav is a persistent navigation component designed for mobile interfaces, positioned at the bottom of the screen. It provides quick access to core functionalities through icons and labels, allowing users to navigate between primary destinations in an application. The component is optimized for touch interaction and follows mobile UI design patterns with clear visual indicators for active states.
## TypeScript Types
The following types represent the props that the BottomNav component and its subcomponents accept. These types allow you to properly configure the navigation according to your app's structure.
````typescript
/**
* Props for the BottomNav component
*/
type BottomNavProps = {
/**
* children slot of BottomNav, accepts BottomNavItem
*/
children: React.ReactNode;
/**
* zIndex of BottomNav
*
* @default 100
*/
zIndex?: number;
} & StyledPropsBlade &
TestID &
DataAnalyticsAttribute;
/**
* Props for the BottomNavItem component
*/
type BottomNavItemProps = {
/**
* Title text of the BottomNavItem
*/
title: string;
/**
* Icon rendered above the title.
*
* Accepts icon component from blade
*/
icon: IconComponent;
/**
* href property of link
*
* maps to `to` property when react router is being used
*/
href?: string;
/**
* HTML's `target` attribute for anchor links
*/
target?: string;
/**
* HTML's `rel` tag of anchor links
*/
rel?: string;
/**
* as prop to pass ReactRouter's Link component.
*
* ```jsx
* import { NavLink } from 'react-router-dom';
*
* <BottomNavItem as={NavLink} />
* ```
*/
as?: React.ComponentType<any>;
/**
* Active state of the BottomNavItem.
*
* Use this to set the current page's active state using react router
*/
isActive?: boolean;
/**
* onClick handler of BottomNavItem
*/
onClick?: React.MouseEventHandler;
} & TestID &
DataAnalyticsAttribute;
````
## Example
This example demonstrates how to implement BottomNav with React Router for a mobile application, including active state management and integration with side navigation.
```tsx
import React, { useState } from 'react';
import { BrowserRouter, Routes, Route, NavLink, useLocation, matchPath } from 'react-router-dom';
import {
BottomNav,
BottomNavItem,
SideNav,
SideNavBody,
SideNavLink,
Box,
Text,
HomeIcon,
PaymentGatewayIcon,
TransactionsIcon,
PaymentLinkIcon,
PaymentPagesIcon,
MenuDotsIcon,
CurrentAccountIcon,
RazorpayIcon,
} from '@razorpay/blade/components';
// Sample page component to show when a route is matched
const PageContent = ({ title }) => (
<Box padding="spacing.5" paddingBottom="spacing.6">
<Text variant="body" size="medium">
{title} Page Content
</Text>
</Box>
);
// Helper function to check if a route is active
const isItemActive = (
location: { pathname: string },
{ href, activeOnLinks }: { href?: string; activeOnLinks?: string[] },
): boolean => {
const isCurrentPathActive = Boolean(
href && matchPath({ path: href, end: true }, location.pathname),
);
const isSubItemActive = Boolean(
activeOnLinks?.find((link) => matchPath({ path: link, end: true }, location.pathname)),
);
return isCurrentPathActive || isSubItemActive;
};
// Custom BottomNavItem with React Router integration
const RouterBottomNavItem = (props) => {
const { activeOnLinks, ...rest } = props;
const location = useLocation();
return (
<BottomNavItem
{...rest}
as={NavLink}
isActive={isItemActive(location, {
href: props.href,
activeOnLinks,
})}
/>
);
};
// Custom SideNavLink with React Router integration
const RouterSideNavLink = (props) => {
const { activeOnLinks, ...rest } = props;
const location = useLocation();
return (
<SideNavLink
{...rest}
as={NavLink}
isActive={isItemActive(location, {
href: props.href,
activeOnLinks,
})}
/>
);
};
// Main App component with navigation implementation
const MobileAppExample = () => {
const [isSideNavOpen, setIsSideNavOpen] = useState(false);
// Bottom navigation items
const mainNavItems = [
{
title: 'Home',
href: '/',
icon: HomeIcon,
},
{
title: 'Payments',
href: '/payments',
icon: PaymentGatewayIcon,
},
{
title: 'Transactions',
href: '/transactions',
icon: TransactionsIcon,
},
{
title: 'Links',
href: '/payment-links',
icon: PaymentLinkIcon,
},
];
// Additional items for side navigation
const sideNavItems = [
{
title: 'Pages',
href: '/payment-pages',
icon: PaymentPagesIcon,
},
{
title: 'Account',
href: '/account',
icon: CurrentAccountIcon,
},
{
title: 'Settings',
href: '/settings',
icon: RazorpayIcon,
},
];
return (
<Box height="100vh" width="100%" position="relative">
{/* Routes configuration */}
<Routes>
<Route path="/" element={<PageContent title="Home" />} />
<Route path="/payments" element={<PageContent title="Payments" />} />
<Route path="/transactions" element={<PageContent title="Transactions" />} />
<Route path="/payment-links" element={<PageContent title="Payment Links" />} />
<Route path="/payment-pages" element={<PageContent title="Payment Pages" />} />
<Route path="/account" element={<PageContent title="Account" />} />
<Route path="/settings" element={<PageContent title="Settings" />} />
</Routes>
{/* Side Navigation */}
<SideNav
isOpen={isSideNavOpen}
onDismiss={() => setIsSideNavOpen(false)}
position="absolute"
zIndex={200}
>
<SideNavBody>
{/* Include both main and extra navigation items in side nav */}
{[...mainNavItems, ...sideNavItems].map((item) => (
<RouterSideNavLink
key={item.href}
title={item.title}
href={item.href}
icon={item.icon}
onClick={() => setIsSideNavOpen(false)}
/>
))}
</SideNavBody>
</SideNav>
{/* Bottom Navigation */}
<BottomNav
position="fixed"
bottom="spacing.0"
left="spacing.0"
testID="main-navigation"
data-analytics="bottom-nav"
>
{/* First 3 main navigation items */}
{mainNavItems.slice(0, 3).map((item) => (
<RouterBottomNavItem
key={item.href}
title={item.title}
href={item.href}
icon={item.icon}
testID={`nav-item-${item.title.toLowerCase()}`}
/>
))}
{/* More button that opens side nav */}
<BottomNavItem
title="More"
icon={MenuDotsIcon}
onClick={() => setIsSideNavOpen(true)}
testID="nav-item-more"
/>
</BottomNav>
</Box>
);
};
// Wrap with router for complete example
const App = () => (
<BrowserRouter>
<MobileAppExample />
</BrowserRouter>
);
export default App;
```