From 50488e81e621e0cf1777e59f8caa99ab6355518f Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Wed, 18 May 2022 10:38:03 -0700 Subject: [PATCH] NavList: Add `sx` prop (#2077) * Add support for `sx` prop to NavList components * Default sx to empty object * Create happy-brooms-swim.md * Update snapshot --- .changeset/happy-brooms-swim.md | 5 ++ src/NavList/NavList.tsx | 75 ++++++++++++------- .../__snapshots__/NavList.test.tsx.snap | 16 +++- 3 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 .changeset/happy-brooms-swim.md diff --git a/.changeset/happy-brooms-swim.md b/.changeset/happy-brooms-swim.md new file mode 100644 index 00000000000..22071270e62 --- /dev/null +++ b/.changeset/happy-brooms-swim.md @@ -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`) diff --git a/src/NavList/NavList.tsx b/src/NavList/NavList.tsx index 5cea60fb008..2dbed46085d 100644 --- a/src/NavList/NavList.tsx +++ b/src/NavList/NavList.tsx @@ -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(sx) -// TODO: sx prop const Root = React.forwardRef(({children, ...props}, ref) => { return ( - + ) }) @@ -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( - ({href, 'aria-current': ariaCurrent, children}, ref) => { + ({href, 'aria-current': ariaCurrent, children, sx: sxProp = {}}, ref) => { const {depth} = React.useContext(SubNavContext) // Get SubNav from children @@ -54,7 +57,7 @@ const Item = React.forwardRef( ) return ( - + {childrenWithoutSubNav} ) @@ -66,11 +69,14 @@ const Item = React.forwardRef( 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( + { + 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} @@ -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 @@ -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( + { + 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? */} @@ -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) @@ -165,7 +172,18 @@ const SubNav = ({children}: NavListSubNavProps) => { return ( - + ( + { + padding: 0, + margin: 0 + }, + sxProp + )} + > {children} @@ -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 */} - {children} + + {children} + ) } diff --git a/src/NavList/__snapshots__/NavList.test.tsx.snap b/src/NavList/__snapshots__/NavList.test.tsx.snap index f5c83598518..1caedbe2f5a 100644 --- a/src/NavList/__snapshots__/NavList.test.tsx.snap +++ b/src/NavList/__snapshots__/NavList.test.tsx.snap @@ -294,7 +294,9 @@ exports[`NavList renders a simple list 1`] = ` }
-