Skip to content

Commit d759fd3

Browse files
authored
NavList add defaultOpen to NavList.Item (#3698)
* adding defaultOpen to NavList * add console.error if using defaultOpen on a NavList.Item without a NavList.SubNav * update defaultOpen * add changeset * fix lint errors
1 parent 6754627 commit d759fd3

File tree

4 files changed

+29
-6
lines changed

4 files changed

+29
-6
lines changed

.changeset/fifty-seas-relax.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@primer/react': patch
3+
---
4+
5+
Adds the defaultOpen prop to NavList.Item
6+
7+
<!-- Changed components: _none_ -->

src/NavList/NavList.docs.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
"defaultValue": "false",
4848
"description": "Set `aria-current` to `\"page\"` to indicate that the item represents the current page. Set `aria-current` to `\"location\"` to indicate that the item represents the current location on a page. For more information about `aria-current`, see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)."
4949
},
50+
{
51+
"name": "defaultOpen",
52+
"type": "boolean",
53+
"description": "The open state of the item when it is initially rendered if the item has a SubNav."
54+
},
5055
{
5156
"name": "ref",
5257
"type": "React.RefObject<HTMLAnchorElement>"

src/NavList/NavList.stories.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ export const WithNestedSubItems: Story = () => (
5151
<PageLayout>
5252
<PageLayout.Pane position="start">
5353
<NavList>
54-
<NavList.Item href="#">Item 1</NavList.Item>
54+
<NavList.Item defaultOpen={true} href="#">
55+
Item 1
56+
<NavList.SubNav>
57+
<NavList.Item href="#">Sub item 1</NavList.Item>
58+
</NavList.SubNav>
59+
</NavList.Item>
5560
<NavList.Item href="#">
5661
Item 2{/* NOTE: Don't nest SubNavs. For testing purposes only */}
5762
<NavList.SubNav>

src/NavList/NavList.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@ Root.displayName = 'NavList'
4848

4949
export type NavListItemProps = {
5050
children: React.ReactNode
51+
defaultOpen?: boolean
5152
href?: string
5253
'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false' | boolean
5354
} & SxProp
5455

5556
const Item = React.forwardRef<HTMLAnchorElement, NavListItemProps>(
56-
({'aria-current': ariaCurrent, children, sx: sxProp = defaultSxProp, ...props}, ref) => {
57+
({'aria-current': ariaCurrent, children, defaultOpen, sx: sxProp = defaultSxProp, ...props}, ref) => {
5758
const {depth} = React.useContext(SubNavContext)
5859

5960
// Get SubNav from children
@@ -64,10 +65,14 @@ const Item = React.forwardRef<HTMLAnchorElement, NavListItemProps>(
6465
isValidElement(child) ? child.type !== SubNav : true,
6566
)
6667

68+
if (!isValidElement(subNav) && defaultOpen)
69+
// eslint-disable-next-line no-console
70+
console.error('NavList.Item must have a NavList.SubNav to use defaultOpen.')
71+
6772
// Render ItemWithSubNav if SubNav is present
6873
if (subNav && isValidElement(subNav)) {
6974
return (
70-
<ItemWithSubNav subNav={subNav} depth={depth} sx={sxProp}>
75+
<ItemWithSubNav subNav={subNav} depth={depth} defaultOpen={defaultOpen} sx={sxProp}>
7176
{childrenWithoutSubNav}
7277
</ItemWithSubNav>
7378
)
@@ -96,6 +101,7 @@ type ItemWithSubNavProps = {
96101
children: React.ReactNode
97102
subNav: React.ReactNode
98103
depth: number
104+
defaultOpen?: boolean
99105
} & SxProp
100106

101107
const ItemWithSubNavContext = React.createContext<{buttonId: string; subNavId: string; isOpen: boolean}>({
@@ -106,10 +112,10 @@ const ItemWithSubNavContext = React.createContext<{buttonId: string; subNavId: s
106112

107113
// TODO: ref prop
108114
// TODO: Animate open/close transition
109-
function ItemWithSubNav({children, subNav, depth, sx: sxProp = defaultSxProp}: ItemWithSubNavProps) {
115+
function ItemWithSubNav({children, subNav, depth, defaultOpen, sx: sxProp = defaultSxProp}: ItemWithSubNavProps) {
110116
const buttonId = useId()
111117
const subNavId = useId()
112-
const [isOpen, setIsOpen] = React.useState(false)
118+
const [isOpen, setIsOpen] = React.useState((defaultOpen || null) ?? false)
113119
const subNavRef = React.useRef<HTMLDivElement>(null)
114120
const [containsCurrentItem, setContainsCurrentItem] = React.useState(false)
115121

@@ -124,7 +130,7 @@ function ItemWithSubNav({children, subNav, depth, sx: sxProp = defaultSxProp}: I
124130
setIsOpen(true)
125131
}
126132
}
127-
}, [subNav])
133+
}, [subNav, buttonId])
128134

129135
return (
130136
<ItemWithSubNavContext.Provider value={{buttonId, subNavId, isOpen}}>

0 commit comments

Comments
 (0)