Skip to content

Commit

Permalink
chore(docs): add most of the navigation docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mlaursen committed Apr 22, 2024
1 parent 2012de4 commit 9708b81
Show file tree
Hide file tree
Showing 15 changed files with 1,043 additions and 739 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { FakeLink } from "@/components/FakeLink.jsx";
import { card } from "@react-md/core/card/styles";
import { Navigation } from "@react-md/core/navigation/Navigation";
import { type NavigationItem } from "@react-md/core/navigation/types";
import { type ReactElement } from "react";

const items: readonly NavigationItem[] = [
{
type: "route",
href: "/",
children: "Home",
},
{
type: "route",
href: "/route-1",
children: "Route 1",
},
{
type: "route",
href: "/route-2",
children: "Route 2",
},
{ type: "divider" },
{ type: "subheader", children: "Subheader 1" },
{
type: "route",
href: "/route-3",
children: "Route 3",
},
{
type: "route",
href: "/route-4",
children: "Route 4",
},
];

export default function AddingDividersAndSubheadersExample(): ReactElement {
return (
<nav aria-label="Fake Navigation" className={card()}>
<Navigation
data={{ pathname: "/", linkComponent: FakeLink }}
items={items}
/>
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { FakeLink } from "@/components/FakeLink.jsx";
import { card } from "@react-md/core/card/styles";
import { Navigation } from "@react-md/core/navigation/Navigation";
import { type NavigationItem } from "@react-md/core/navigation/types";
import FavoriteIcon from "@react-md/material-icons/FavoriteIcon";
import HomeIcon from "@react-md/material-icons/HomeIcon";
import StarIcon from "@react-md/material-icons/StarIcon";
import { type ReactElement } from "react";

const items: readonly NavigationItem[] = [
{
type: "route",
href: "/",
children: "Home",
beforeAddon: <HomeIcon />,
},
{
type: "route",
href: "/route-1",
children: "Route 1",
beforeAddon: <StarIcon />,
},
{
type: "route",
href: "/route-2",
children: "Route 2",
beforeAddon: <FavoriteIcon />,
afterAddon: <FavoriteIcon />,
},
];

export default function AddingIconsExample(): ReactElement {
return (
<nav aria-label="Fake Navigation" className={card()}>
<Navigation
data={{ pathname: "/", linkComponent: FakeLink }}
items={items}
/>
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { FakeLink } from "@/components/FakeLink.jsx";
import { card } from "@react-md/core/card/styles";
import { Navigation } from "@react-md/core/navigation/Navigation";
import { type NavigationItem } from "@react-md/core/navigation/types";
import { type ReactElement } from "react";

const items: readonly NavigationItem[] = [
{
type: "route",
href: "/",
children: "Home",
},
{
type: "group",
href: "/route-1",
children: "Prefixed Href",
items: [
{
type: "route",
href: "/page-1",
children: "Page 1",
},
{
type: "route",
href: "/page-2",
children: "Page 2",
},
{
type: "route",
href: "/page-3",
children: "Page 3",
},
],
},
{
type: "group",
children: "No Prexed Href",
items: [
{
type: "route",
href: "/page-1",
children: "Page 1",
},
{
type: "route",
href: "/page-2",
children: "Page 2",
},
{
type: "route",
href: "/page-3",
children: "Page 3",
},
],
},
{
type: "group",
href: "/multi",
children: "Multiple Levels",
items: [
{
type: "route",
href: "/page-1",
children: "Page 1",
},
{
type: "group",
href: "/level-2",
children: "Level 2",
items: [
{
type: "route",
href: "/page-1",
children: "Page 1",
},
],
},
],
},
];

export default function CollapsibleGroupsExample(): ReactElement {
return (
<nav aria-label="Fake Navigation" className={card()}>
<Navigation
data={{ pathname: "/route-1/page-2", linkComponent: FakeLink }}
items={items}
/>
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"use client";
import { LinkUnstyled } from "@/components/LinkUnstyled.jsx";
import { Navigation } from "@react-md/core/navigation/Navigation";
import { type NavigationItem } from "@react-md/core/navigation/types";
import { usePathname } from "next/navigation.js";
import { type ReactElement } from "react";

const items: readonly NavigationItem[] = [
{
type: "route",
href: "/",
children: "Home",
},
{
type: "route",
href: "/page-1",
children: "Page 1",
},
];

export function MainNavigation(): ReactElement {
const pathname = usePathname();
return (
<nav aria-label="Navigation">
<Navigation
data={{ pathname, linkComponent: LinkUnstyled }}
items={items}
/>
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { FakeLink } from "@/components/FakeLink.jsx";
import { card } from "@react-md/core/card/styles";
import { Navigation } from "@react-md/core/navigation/Navigation";
import { type NavigationItem } from "@react-md/core/navigation/types";
import { type ReactElement } from "react";

const items: readonly NavigationItem[] = [
{
type: "route",
href: "/",
children: "Home",
},
{
type: "route",
href: "/route-1",
children: "Route 1",
},
{
type: "route",
href: "/route-2",
children: "Route 2",
},
];

export default function SimpleExample(): ReactElement {
return (
<nav aria-label="Fake Navigation" className={card()}>
<Navigation
data={{ pathname: "/", linkComponent: FakeLink }}
items={items}
/>
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Navigation

The `Navigation` component can be used to create a list of links to different
pages within the app and generally used within a [Sheet](./sheet) or
[LayoutNav](./layout-nav).

> !Info! Most of the demos on this page are for presentational purpose only and
> will use a `FakeLink` with a hard-coded `pathname`. A "real-world" example is
> available as the navigation for this website and some [example layouts](/layout-example/temporary).
# Simple Example

The `Navigation` component accepts a list of `items` defining all the routes to
render and a `data` prop defining the current `pathname` and `linkComponent`.
The `linkComponent` **must** accept and forward a `ref` and accept an `href`.
When an item's `href` matches the current `pathname`, it will gain the active
styles.

> !Info! The `Navigation` component only needs to be wrapped in a `<nav>` when
> not using the [LayoutNav](./layout-nav) component and any of the
> `useTemporaryLayout`, `useExpandableLayout`, or `useResizableLayout` hooks.
```demo source="./SimpleExample.tsx"
```

## Adding Icons

Icons can be added before or after the `children` by using the `beforeAddon` and
`afterAddon` props respectively.

```demo source="./AddingIconsExample.tsx"
```

## Adding Dividers and Subheaders

Dividers and subheaders can be rendered by setting the `type` to `"divider"` or
`"subheader"` respectively.

```demo source="./AddingDividersAndSubheadersExample.tsx"
```

## Collapsible Groups

A group of routes can be created by creating an item with `type: "group"`. If an
`href` is also included in this item, all child routes' `href` will be prefixed
with the group `href`.

```demo source="./CollapsibleGroupsExample.tsx"
```

# Routing Libraries and Frameworks

## Nextjs Example

It is recommended to create a simple `LinkUnstyled` component which can be
customized and used throughout the app:

```import source="@/components/LinkUnstyled.tsx" fileName="src/components/LinkUnstyled.tsx"
```

Then use the `LinkUnstyled` as the `linkComponent` and pass the current
`pathname` with the `usePathname` hook:

```import source="./NextjsExample.tsx" fileName="src/components/Navigation.tsx"
```

## React Router Example

It is recommended to create a simple `LinkUnstyled` component which can be
customized and used throughout the app:

```tsx
import { Link, type LinkProps } from "react-router-dom";

export interface LinkUnstyledProps extends Omit<LinkProps, "to"> {
href: string;
}

export const LinkUnstyled = forwardRef<HTMLAnchorElement, LinkUnstyledProps>(
function LinkUnstyled(props, ref) {
const { href, ...remaining } = props;

return <Link {...remaining} to={href} ref={ref} />;
}
);
```

Then use the `LinkUnstyled` as the `linkComponent` and pass the current
`pathname` with the `useHref` hook:

```tsx
import { LinkUnstyled } from "@/components/LinkUnstyled.jsx";
import { Navigation } from "@react-md/core/navigation/Navigation";
import { type NavigationItem } from "@react-md/core/navigation/types";
import { type ReactElement } from "react";
import { useHref } from "react-router-dom";

const items: readonly NavigationItem[] = [
{
type: "route",
href: "/",
children: "Home",
},
{
type: "route",
href: "/page-1",
children: "Page 1",
},
];

export function MainNavigation(): ReactElement {
const pathname = useHref();
return (
<nav aria-label="Navigation">
<Navigation
data={{ pathname, linkComponent: LinkUnstyled }}
items={items}
/>
</nav>
);
}
```

> !Warn! Disclaimer: I haven't actually tried upgrading to `[email protected]` yet.
Loading

0 comments on commit 9708b81

Please sign in to comment.