diff --git a/bulma-ui/src/components/Navbar.tsx b/bulma-ui/src/components/Navbar.tsx index 6263912cf..accbab709 100644 --- a/bulma-ui/src/components/Navbar.tsx +++ b/bulma-ui/src/components/Navbar.tsx @@ -150,7 +150,7 @@ export const NavbarBrand: React.FC = ({ * Props for the NavbarItem component. * * @property {string} [className] - Additional CSS classes. - * @property {React.ElementType} [as] - Render as a custom component. + * @property {React.ElementType} [as] - Render as a custom component (e.g., a router link). * @property {boolean} [active] - Whether the item is active. * @property {(typeof validColors)[number] | 'inherit' | 'current'} [textColor] - Text color for the item. * @property {(typeof validColors)[number] | 'inherit' | 'current'} [bgColor] - Background color for the item. @@ -166,6 +166,8 @@ export interface NavbarItemProps textColor?: (typeof validColors)[number] | 'inherit' | 'current'; bgColor?: (typeof validColors)[number] | 'inherit' | 'current'; children?: React.ReactNode; + // Allow router props like `to` when rendering via `as` (matches MenuItemProps) + [key: string]: unknown; } /** diff --git a/bulma-ui/src/components/__tests__/Navbar.test.tsx b/bulma-ui/src/components/__tests__/Navbar.test.tsx index 3c7794fb0..481b73051 100644 --- a/bulma-ui/src/components/__tests__/Navbar.test.tsx +++ b/bulma-ui/src/components/__tests__/Navbar.test.tsx @@ -1,4 +1,5 @@ import { render, screen, fireEvent } from '@testing-library/react'; +import type { ComponentProps } from 'react'; import Navbar from '../Navbar'; import { ConfigProvider } from '../../helpers/Config'; @@ -187,6 +188,22 @@ describe('Navbar.Item', () => { expect(item).toHaveClass('navbar-item'); }); + it('forwards router props like "to" to a custom "as" component', () => { + // Stand-in for a router link (e.g. react-router-dom's Link) + const RouterLink = ({ + to, + ...rest + }: { to: string } & ComponentProps<'a'>) => ; + render( + + Pricing + + ); + const item = screen.getByTestId('item'); + expect(item).toHaveAttribute('href', '/pricing'); + expect(item).toHaveClass('navbar-item'); + }); + it('applies textColor and bgColor', () => { render( diff --git a/docs/docs/api/components/navbar.md b/docs/docs/api/components/navbar.md index 1e6406b79..aef9e2af9 100644 --- a/docs/docs/api/components/navbar.md +++ b/docs/docs/api/components/navbar.md @@ -196,6 +196,33 @@ A more complex example with navigation links and a dropdown menu. The dropdown i --- +### Custom Link Component + +Use the `as` prop on `Navbar.Item` to render a custom link component, such as a router link. Extra props like `to` are forwarded to the link component and type-check without casts, so client-side routing libraries integrate directly. See the [Routing guide](../../guides/features/routing.md) for the full patterns. + +```tsx live +// import { Link } from 'react-router-dom'; +function example() { + const Link = props => {props.children}; + return ( + + + + + Home + + + Pricing + + + + + ); +} +``` + +--- + ### Transparent Navbar Example of a navbar with a transparent background. This is often used for navbars that overlay content, like images or videos, giving a more integrated look. diff --git a/docs/docs/guides/features/routing.md b/docs/docs/guides/features/routing.md index f408c215e..4eb31f2dc 100644 --- a/docs/docs/guides/features/routing.md +++ b/docs/docs/guides/features/routing.md @@ -40,37 +40,28 @@ import { Menu } from '@allxsmith/bestax-bulma'; ## Navbar items as router links -`Navbar.Item` accepts `as={Link}` the same way, and at runtime every extra prop (including -`to`) is forwarded to your link component. In **TypeScript**, however, `to` isn't part of -`Navbar.Item`'s prop type (it extends anchor attributes), so `` -is a type error today. The recommended pattern is a one-line typed alias, declared once: +`Navbar.Item` works the same way — pass the router's link component via `as`, and `to` (or +any other router prop) is forwarded to it. Like `Menu.Item`, its prop type accepts extra +keys, so this compiles without errors or casts: ```tsx -import { Link, LinkProps } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import { Navbar } from '@allxsmith/bestax-bulma'; -// One cast, reused everywhere — runtime behavior is unchanged. -const NavbarLink = Navbar.Item as React.FC< - React.ComponentProps & LinkProps ->; - - + Home - - + + Pricing - + ; ``` -(Plain-JavaScript apps can skip the alias — `` just -works.) - ## Buttons that navigate `Button`'s `as` prop is polymorphic (any `React.ElementType`), so the same two options apply: @@ -164,5 +155,5 @@ On Next.js **before 13**, `` required an `` child by default — wrap i - [Navbar](../../api/components/navbar.md) · [Menu](../../api/components/menu.md) · [Button](../../api/elements/button.md) - `Button`/`Link` polymorphism landed in [#238](https://github.com/allxsmith/bestax/pull/238); - first-class `to` typing on `Navbar.Item` (dropping the cast alias above) is tracked in + first-class `to` typing on `Navbar.Item` landed via [#306](https://github.com/allxsmith/bestax/issues/306). diff --git a/skills/bestax-layout-scaffold/references/layout-components.md b/skills/bestax-layout-scaffold/references/layout-components.md index 32b9c3900..fa07b1d05 100644 --- a/skills/bestax-layout-scaffold/references/layout-components.md +++ b/skills/bestax-layout-scaffold/references/layout-components.md @@ -225,11 +225,9 @@ document.documentElement.classList.add('has-navbar-fixed-top'); ``` **Routing:** in a routed app, don't use `href="#"` — render items as the router's link -component. `Menu.Item as={Link} to="/x"` compiles without casts (its props allow extra keys); -`Navbar.Item as={Link}` forwards `to` -at runtime but needs a one-line typed alias in TypeScript (`Navbar.Item as React.FC<…Props & -LinkProps>`). Drive `active` from `useLocation().pathname`. Full patterns (including Buttons -that navigate and Next.js `href`): the docs guide at +component. `Menu.Item as={Link} to="/x"` and `Navbar.Item as={Link} to="/x"` both compile +without casts (their props allow extra keys). Drive `active` from `useLocation().pathname`. +Full patterns (including Buttons that navigate and Next.js `href`): the docs guide at https://bestax.io/docs/guides/features/routing. ## Menu