Skip to content

Commit

Permalink
NavList: Add sx prop (#2077)
Browse files Browse the repository at this point in the history
* Add support for `sx` prop to NavList components

* Default sx to empty object

* Create happy-brooms-swim.md

* Update snapshot
  • Loading branch information
colebemis committed May 18, 2022
1 parent c8f7e23 commit 30f93ff
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .changeset/happy-brooms-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": patch
---

Adds support for the `sx` prop on the draft implementation of `NavList` and all its subcomponents (e.g., `NavList.Item`)
75 changes: 47 additions & 28 deletions src/NavList/NavList.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import {ChevronDownIcon} from '@primer/octicons-react'
import {useSSRSafeId} from '@react-aria/ssr'
import React, {isValidElement} from 'react'
import styled from 'styled-components'
import {ActionList} from '../ActionList'
import Box from '../Box'
import StyledOcticon from '../StyledOcticon'
import sx, {merge, SxProp} from '../sx'

// ----------------------------------------------------------------------------
// NavList

export type NavListProps = {
children: React.ReactNode
} & React.ComponentProps<'nav'>
} & SxProp &
React.ComponentProps<'nav'>

const NavBox = styled.nav<SxProp>(sx)

// TODO: sx prop
const Root = React.forwardRef<HTMLElement, NavListProps>(({children, ...props}, ref) => {
return (
<nav ref={ref} {...props}>
<NavBox {...props} ref={ref}>
<ActionList>{children}</ActionList>
</nav>
</NavBox>
)
})

Expand All @@ -30,12 +34,11 @@ export type NavListItemProps = {
children: React.ReactNode
href?: string
'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false' | boolean
}
} & SxProp

// TODO: sx prop
// TODO: as prop
const Item = React.forwardRef<HTMLAnchorElement, NavListItemProps>(
({href, 'aria-current': ariaCurrent, children}, ref) => {
({href, 'aria-current': ariaCurrent, children, sx: sxProp = {}}, ref) => {
const {depth} = React.useContext(SubNavContext)

// Get SubNav from children
Expand All @@ -54,7 +57,7 @@ const Item = React.forwardRef<HTMLAnchorElement, NavListItemProps>(
)

return (
<ItemWithSubNav subNav={subNav} subNavContainsCurrentItem={Boolean(currentItem)}>
<ItemWithSubNav subNav={subNav} subNavContainsCurrentItem={Boolean(currentItem)} sx={sxProp}>
{childrenWithoutSubNav}
</ItemWithSubNav>
)
Expand All @@ -66,11 +69,14 @@ const Item = React.forwardRef<HTMLAnchorElement, NavListItemProps>(
href={href}
aria-current={ariaCurrent}
active={Boolean(ariaCurrent) && ariaCurrent !== 'false'}
sx={{
paddingLeft: depth > 0 ? 5 : null, // Indent sub-items
fontSize: depth > 0 ? 0 : null, // Reduce font size of sub-items
fontWeight: depth > 0 ? 'normal' : null // Sub-items don't get bolded
}}
sx={merge<SxProp['sx']>(
{
paddingLeft: depth > 0 ? 5 : null, // Indent sub-items
fontSize: depth > 0 ? 0 : null, // Reduce font size of sub-items
fontWeight: depth > 0 ? 'normal' : null // Sub-items don't get bolded
},
sxProp
)}
>
{children}
</ActionList.LinkItem>
Expand All @@ -87,17 +93,16 @@ type ItemWithSubNavProps = {
children: React.ReactNode
subNav: React.ReactNode
subNavContainsCurrentItem: boolean
}
} & SxProp

const ItemWithSubNavContext = React.createContext<{buttonId: string; subNavId: string}>({
buttonId: '',
subNavId: ''
})

// TODO: sx prop
// TODO: ref prop
// TODO: Animate open/close transition
function ItemWithSubNav({children, subNav, subNavContainsCurrentItem}: ItemWithSubNavProps) {
function ItemWithSubNav({children, subNav, subNavContainsCurrentItem, sx: sxProp = {}}: ItemWithSubNavProps) {
const buttonId = useSSRSafeId()
const subNavId = useSSRSafeId()
// SubNav starts open if current item is in it
Expand All @@ -114,9 +119,12 @@ function ItemWithSubNav({children, subNav, subNavContainsCurrentItem}: ItemWithS
// When the subNav is closed, how should we indicated that the subNav contains the current item?
active={!isOpen && subNavContainsCurrentItem}
onClick={() => setIsOpen(open => !open)}
sx={{
fontWeight: subNavContainsCurrentItem ? 'bold' : null // Parent item is bold if any of it's sub-items are current
}}
sx={merge<SxProp['sx']>(
{
fontWeight: subNavContainsCurrentItem ? 'bold' : null // Parent item is bold if any of it's sub-items are current
},
sxProp
)}
>
{children}
{/* What happens if the user provides a TrailingVisual? */}
Expand All @@ -141,14 +149,13 @@ function ItemWithSubNav({children, subNav, subNavContainsCurrentItem}: ItemWithS

type NavListSubNavProps = {
children: React.ReactNode
}
} & SxProp

const SubNavContext = React.createContext<{depth: number}>({depth: 0})

// TODO: sx prop
// TODO: ref prop
// NOTE: SubNav must be a direct child of an Item
const SubNav = ({children}: NavListSubNavProps) => {
const SubNav = ({children, sx: sxProp = {}}: NavListSubNavProps) => {
const {buttonId, subNavId} = React.useContext(ItemWithSubNavContext)
const {depth} = React.useContext(SubNavContext)

Expand All @@ -165,7 +172,18 @@ const SubNav = ({children}: NavListSubNavProps) => {

return (
<SubNavContext.Provider value={{depth: depth + 1}}>
<Box as="ul" id={subNavId} aria-labelledby={buttonId} sx={{padding: 0, margin: 0}}>
<Box
as="ul"
id={subNavId}
aria-labelledby={buttonId}
sx={merge<SxProp['sx']>(
{
padding: 0,
margin: 0
},
sxProp
)}
>
{children}
</Box>
</SubNavContext.Provider>
Expand Down Expand Up @@ -198,19 +216,20 @@ Divider.displayName = 'NavList.Divider'
// ----------------------------------------------------------------------------
// NavList.Group

type NavListGroupProps = React.PropsWithChildren<{
type NavListGroupProps = {
children: React.ReactNode
title?: string
}>
} & SxProp

// TODO: sx prop
// TODO: ref prop
const Group = ({title, children}: NavListGroupProps) => {
const Group = ({title, children, sx: sxProp = {}}: NavListGroupProps) => {
return (
<>
{/* Hide divider if the group is the first item in the list */}
<ActionList.Divider sx={{'&:first-child': {display: 'none'}}} />
<ActionList.Group title={title}>{children}</ActionList.Group>
<ActionList.Group title={title} sx={sxProp}>
{children}
</ActionList.Group>
</>
)
}
Expand Down
16 changes: 12 additions & 4 deletions src/NavList/__snapshots__/NavList.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,9 @@ exports[`NavList renders a simple list 1`] = `
}
<div>
<nav>
<nav
class=""
>
<ul
class="c0"
>
Expand Down Expand Up @@ -695,7 +697,9 @@ exports[`NavList renders with groups 1`] = `
}
<div>
<nav>
<nav
class=""
>
<ul
class="c0"
>
Expand Down Expand Up @@ -1172,7 +1176,9 @@ exports[`NavList.Item with NavList.SubNav does not have active styles if SubNav
}
<div>
<nav>
<nav
class=""
>
<ul
class="c0"
>
Expand Down Expand Up @@ -1480,7 +1486,9 @@ exports[`NavList.Item with NavList.SubNav has active styles if SubNav contains t
}
<div>
<nav>
<nav
class=""
>
<ul
class="c0"
>
Expand Down

0 comments on commit 30f93ff

Please sign in to comment.