-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make the navigation wrapping ul component user customisable #9153
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
"@keystone-6/core": major | ||
"@keystone-6/website": patch | ||
--- | ||
|
||
Make the navigation wrapping ul component user customisable | ||
|
||
The `NavigationContainer` component rendered it's children inside a `ul` meaning if you wanted to render anything other than an `li` you would have to do some gymnastics to make it work. This change makes it the users' responsibility to properly wrap list items in a `ul`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,7 +62,7 @@ For more information on the props, please see the [Navigation Props](#navigation | |
Next we'll want to import some components that Keystone provides to help us build our custom Navigation. | ||
|
||
```tsx | ||
import { NavigationContainer, NavItem, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
import { NavigationContainer, NavItem, NavItemGroup, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
``` | ||
|
||
The `NavigationContainer` component provides a container around your navigation links, as well as the different states of the `authenticatedItem` prop. We'll need this to: | ||
|
@@ -71,7 +71,7 @@ The `NavigationContainer` component provides a container around your navigation | |
- Render out the hamburger menu with additional options should a user session be in progress via the `authenticatedItem` prop. | ||
|
||
```tsx | ||
import { NavigationContainer, NavItem, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
import { NavigationContainer, NavItem, NavItemGroup, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
import type { NavigationProps } from '@keystone-6/core/admin-ui/components'; | ||
|
||
export function CustomNavigation({ authenticatedItem, lists }: NavigationProps) { | ||
|
@@ -91,15 +91,22 @@ For more information on the `NavigationContainer` see the [NavigationContainer]( | |
|
||
The `ListNavItems` component takes the provided Array of `lists` and renders a list of NavItems. We'll use this component to help us easily create NavItems from Keystone lists. | ||
|
||
{% hint kind="tip" %} | ||
It's important to wrap all links in a `NavItemGroup` component. This is the `ul` to the `li` produced by `NavItem`. | ||
{% /hint %} | ||
|
||
|
||
```tsx | ||
import { NavigationContainer, NavItem, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
import { NavigationContainer, NavItem, NavItemGroup, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
import type { NavigationProps } from '@keystone-6/core/admin-ui/components'; | ||
|
||
export function CustomNavigation({ authenticatedItem, lists }: NavigationProps) { | ||
return ( | ||
<NavigationContainer authenticatedItem={authenticatedItem}> | ||
<ListNavItems lists={lists}/> | ||
{/* ... */} | ||
<NavItemGroup> | ||
<ListNavItems lists={lists}/> | ||
{/* ... */} | ||
</NavItemGroup> | ||
</NavigationContainer> | ||
) | ||
} | ||
|
@@ -120,11 +127,13 @@ import type { NavigationProps } from '@keystone-6/core/admin-ui/components'; | |
export function CustomNavigation({ authenticatedItem, lists }: NavigationProps) { | ||
return ( | ||
<NavigationContainer authenticatedItem={authenticatedItem}> | ||
<NavItem href="/">Dashboard</NavItem> | ||
<ListNavItems lists={lists}/> | ||
<NavItem href="https://keystonejs.com/"> | ||
Keystone Docs | ||
</NavItem> | ||
<NavItemGroup> | ||
<NavItem href="/">Dashboard</NavItem> | ||
<ListNavItems lists={lists}/> | ||
<NavItem href="https://keystonejs.com/"> | ||
Keystone Docs | ||
</NavItem> | ||
</NavItemGroup> | ||
</NavigationContainer> | ||
) | ||
} | ||
|
@@ -144,17 +153,19 @@ With all that done, your Custom Navigation component should be good to go, and y | |
|
||
```tsx | ||
// admin/components/CustomNavigation.tsx | ||
import { NavigationContainer, NavItem, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
import { NavigationContainer, NavItem, NavItemGroup, ListNavItems } from '@keystone-6/core/admin-ui/components'; | ||
import type { NavigationProps } from '@keystone-6/core/admin-ui/components'; | ||
|
||
export function CustomNavigation({ authenticatedItem, lists }: NavigationProps) { | ||
return ( | ||
<NavigationContainer authenticatedItem={authenticatedItem}> | ||
<NavItem href="/">Dashboard</NavItem> | ||
<ListNavItems lists={lists}/> | ||
<NavItem href="https://keystonejs.com/"> | ||
Keystone Docs | ||
</NavItem> | ||
<NavItemGroup> | ||
<NavItem href="/">Dashboard</NavItem> | ||
<ListNavItems lists={lists}/> | ||
<NavItem href="https://keystonejs.com/"> | ||
Keystone Docs | ||
</NavItem> | ||
</NavItemGroup> | ||
</NavigationContainer> | ||
) | ||
} | ||
|
@@ -230,7 +241,9 @@ Keystone exposes a variety of helper components to make building out your custom | |
|
||
- [NavigationContainer](#navigation-container) | ||
- [ListNavItems](#list-nav-items) | ||
- [ListNavItem](#list-nav-item) | ||
- [NavItem](#nav-item) | ||
- [NavItemGroup](#nav-item-group) | ||
|
||
### NavigationContainer | ||
|
||
|
@@ -280,7 +293,9 @@ If an `include` prop is supplied, the component will only render out lists that | |
```tsx | ||
const CustomNavigation = ({ lists }) => ( | ||
<NavigationContainer> | ||
<ListNavItems lists={lists} include={["Task"]} /> | ||
<NavItemGroup> | ||
<ListNavItems lists={lists} include={["Task"]} /> | ||
</NavItemGroup> | ||
</NavigationContainer> | ||
) | ||
``` | ||
|
@@ -292,13 +307,50 @@ Otherwise, all lists will be added. | |
```tsx | ||
const CustomNavigation = ({ lists }) => ( | ||
<NavigationContainer> | ||
<ListNavItems lists={lists} /> | ||
<NavItemGroup> | ||
<ListNavItems lists={lists} /> | ||
</NavItemGroup> | ||
</NavigationContainer> | ||
) | ||
``` | ||
|
||
![example of navigation without include prop values](/assets/guides/custom-admin-ui-navigation/listNavItems-without-include.png) | ||
|
||
### ListNavItem | ||
|
||
This component will render a single `NavItem` for the given list. | ||
|
||
```tsx | ||
import { ListNavItem } from '@keystone-6/core/admin-ui/components' | ||
``` | ||
|
||
In this example we create groups for our lists. | ||
|
||
```tsx | ||
const listGroups = [ | ||
[ | ||
{ name: 'People', lists: ['User', 'Bio', 'Role']}, | ||
{ name: 'Posts', lists: ['Post', 'Category', 'Tag']}, | ||
] | ||
]; | ||
|
||
const CustomNavigation = ({ lists }) => ( | ||
<NavigationContainer> | ||
{listGroups.map(group => ( | ||
<Box key={group.name}> | ||
<H5 paddingX="xlarge">{group.name}</H5> | ||
<NavItemGroup> | ||
{group.lists.map((key) => { | ||
const list = lists.find((l) => l.key === key); | ||
return list ? <ListNavItem key={key} list={list} /> : null; | ||
})} | ||
</NavItemGroup> | ||
</Box> | ||
))} | ||
</NavigationContainer> | ||
) | ||
``` | ||
Comment on lines
+319
to
+352
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kind of a contrived example. You could do something like this1 with the Footnotes
|
||
|
||
### NavItem | ||
|
||
This component is a thin styling and accessibility wrapper around the `Link` component from Next.js | ||
|
@@ -323,6 +375,29 @@ type NavItemProps = { | |
By default the `isSelected` value will be evaluated by the condition `router.pathname === href`. | ||
Pass in `isSelected` if you have a custom condition or would like more granular control over the "selected" state of Navigation items. | ||
|
||
### NavItemGroup | ||
|
||
This component is a styled unordered list `<ul>` which should be used to wrap `NavItem`, `ListNavItem` and `comp | ||
|
||
```tsx | ||
import { NavItemGroup } from '@keystone-6/core/admin-ui/components' | ||
``` | ||
|
||
{% hint kind="warn" %} | ||
Versions of `@keystone-6/core` before `1.2.0` wrapped all children of `NavigationContainer` with the `NavItemGroup` component. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've guessed what the version number will be. Also I'm not sure we need to call out that this thing has changed. |
||
{% /hint %} | ||
|
||
```tsx | ||
const CustomNavigation = ({ lists }) => ( | ||
<NavigationContainer> | ||
<NavItemGroup> | ||
<ListNavItems lists={lists} /> | ||
</NavItemGroup> | ||
</NavigationContainer> | ||
) | ||
``` | ||
|
||
|
||
## Related resources | ||
|
||
{% related-content %} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically a breaking change? ... custom Navigation in the Admin UI will render weirdly or have invalid DOM structure if not updated.