@@ -3,8 +3,8 @@ import styled, {css} from 'styled-components'
33
44import Box from './Box'
55import type { ComponentProps } from './utils/types'
6- import Link from './Link'
7- import React from 'react'
6+ import Link , { type LinkProps } from './Link'
7+ import React , { type PropsWithChildren } from 'react'
88import { clsx } from 'clsx'
99import type { SxProp } from './sx'
1010import sx from './sx'
@@ -61,10 +61,14 @@ function SideNav({
6161 const enabled = useFeatureFlag ( CSS_MODULES_FEATURE_FLAG )
6262 const variantClassName = variant === 'lightweight' ? 'lightweight' : 'normal'
6363 const newClassName = clsx (
64- { [ classes . SideNav ] : enabled , [ classes . SideNavBordered ] : enabled && bordered } ,
65- 'sidenav' ,
64+ {
65+ [ classes . SideNav ] : enabled ,
66+ [ classes . SideNavBordered ] : enabled && bordered ,
67+ [ classes [ `SideNavVariant-${ variantClassName } ` ] ] : enabled ,
68+ sidenav : ! enabled ,
69+ [ `variant-${ variantClassName } ` ] : ! enabled ,
70+ } ,
6671 className ,
67- `variant-${ variantClassName } ` ,
6872 )
6973 return (
7074 < StyledNav
@@ -79,11 +83,12 @@ function SideNav({
7983 )
8084}
8185
82- type StyledSideNavLinkProps = {
86+ type StyledSideNavLinkProps = PropsWithChildren < {
8387 to ?: To
8488 selected ?: boolean
8589 variant ?: 'full' | 'normal'
86- }
90+ } > &
91+ LinkProps
8792
8893// used for variant normal hover, focus pseudo selectors
8994const CommonAccessibilityVariantNormalStyles = css `
@@ -97,106 +102,124 @@ const CommonAccessibilityVariantLightWeightStyles = css`
97102 text-decoration : none;
98103`
99104
100- const SideNavLink = styled ( Link ) . attrs < StyledSideNavLinkProps > ( props => {
101- const isReactRouter = typeof props . to === 'string'
102- if ( isReactRouter || props . selected ) {
103- // according to their docs, NavLink supports aria-current:
104- // https://reacttraining.com/react-router/web/api/NavLink/aria-current-string
105- return { 'aria-current' : 'page' }
106- } else {
107- return { }
108- }
109- } ) < StyledSideNavLinkProps & SxProp > `
110- position: relative;
111- display: block;
112- ${ props =>
113- props . variant === 'full' &&
114- css `
115- display : flex;
116- align-items : center;
117- justify-content : space-between;
118- ` }
119- width: 100%;
120- text-align: left;
121- font-size: var(--base-size-14);
122-
123- & > .sidenav {
124- border-bottom: none;
125- }
126-
127- .sidenav.variant-normal > & {
128- color: var(--fgColor-default);
129- padding: var(--base-size-16);
130- border: 0;
131- border-top: var(--borderWidth-thin) solid var(--borderColor-muted);
132-
133- &:first-child {
134- border-top: 0;
135- border-top-right-radius: var(--borderRadius-medium);
136- border-top-left-radius: var(--borderRadius-medium);
137- }
138-
139- &:last-child {
140- border-bottom-right-radius: var(--borderRadius-medium);
141- border-bottom-left-radius: var(--borderRadius-medium);
142- }
143-
144- // Bar on the left
145- &::before {
146- position: absolute;
147- top: 0;
148- bottom: 0;
149- left: 0;
150- z-index: 1;
151- width: 3px;
152- pointer-events: none;
153- content: '';
154- }
105+ const StyledSideNavLink = toggleStyledComponent (
106+ CSS_MODULES_FEATURE_FLAG ,
107+ Link ,
108+ styled ( Link ) < StyledSideNavLinkProps & SxProp > `
109+ position: relative;
110+ display: block;
111+ width: 100%;
112+ font-size: 14px;
113+ text-align: left;
114+ text-decoration: none;
115+ ${ props =>
116+ props . variant === 'full' &&
117+ css `
118+ display : flex;
119+ align-items : center;
120+ justify-content : space-between;
121+ ` }
155122
156- &:hover {
157- ${ CommonAccessibilityVariantNormalStyles }
123+ & > .sidenav {
124+ border-bottom: none;
158125 }
159126
160- &:focus {
161- ${ CommonAccessibilityVariantNormalStyles }
162- outline: solid 2px var(--fgColor-accent);
163- z-index: 1;
164- }
127+ .sidenav.variant-normal > & {
128+ color: var(--fgColor-default);
129+ padding: var(--base-size-16);
130+ border: 0;
131+ border-top: var(--borderWidth-thin) solid var(--borderColor-muted);
132+
133+ &:first-child {
134+ border-top: 0;
135+ border-top-right-radius: var(--borderRadius-medium);
136+ border-top-left-radius: var(--borderRadius-medium);
137+ }
165138
166- &[aria-current='page'],
167- &[aria-selected='true'] {
168- background-color: var(--bgColor-default);
139+ &:last-child {
140+ border-bottom-right-radius: var(--borderRadius-medium);
141+ border-bottom-left-radius: var(--borderRadius-medium);
142+ }
169143
170144 // Bar on the left
171145 &::before {
172- background-color: #fd8c73;
146+ position: absolute;
147+ top: 0;
148+ bottom: 0;
149+ left: 0;
150+ z-index: 1;
151+ width: 3px;
152+ pointer-events: none;
153+ content: '';
173154 }
174- }
175- }
176155
177- .sidenav.variant-lightweight > & {
178- padding: var(--base-size-4) 0;
179- color: var(--fgColor-accent);
156+ &:hover {
157+ ${ CommonAccessibilityVariantNormalStyles }
158+ }
180159
181- &:hover {
182- ${ CommonAccessibilityVariantLightWeightStyles }
183- }
160+ &:focus {
161+ ${ CommonAccessibilityVariantNormalStyles }
162+ outline: solid 2px var(--fgColor-accent);
163+ z-index: 1;
164+ }
165+
166+ &[aria-current='page'],
167+ &[aria-selected='true'] {
168+ background-color: var(--bgColor-default);
184169
185- &:focus {
186- ${ CommonAccessibilityVariantLightWeightStyles }
187- outline: solid 1px var(--fgColor-accent);
188- z-index: 1;
170+ // Bar on the left
171+ &::before {
172+ background-color: var(--underlineNav-borderColor-active, var(--color-primer-border-active, #fd8c73));
173+ }
174+ }
189175 }
190176
191- &[aria-current='page'],
192- &[aria-selected='true'] {
193- color: var(--fgColor-default);
194- font-weight: var(--base-text-weight-medium);
177+ .sidenav.variant-lightweight > & {
178+ padding: var(--base-size-4) 0;
179+ color: var(--fgColor-accent);
180+
181+ &:hover {
182+ ${ CommonAccessibilityVariantLightWeightStyles }
183+ }
184+
185+ &:focus {
186+ ${ CommonAccessibilityVariantLightWeightStyles }
187+ outline: solid 1px var(--fgColor-accent);
188+ z-index: 1;
189+ }
190+
191+ &[aria-current='page'],
192+ &[aria-selected='true'] {
193+ color: var(--fgColor-default);
194+ font-weight: var(--base-text-weight-medium);
195+ }
195196 }
196- }
197197
198- ${ sx } ;
199- `
198+ ${ sx } ;
199+ ` ,
200+ )
201+
202+ const SideNavLink = ( { selected, to, variant, className, children, ...rest } : StyledSideNavLinkProps ) => {
203+ const isReactRouter = typeof to === 'string'
204+ const enabled = useFeatureFlag ( CSS_MODULES_FEATURE_FLAG )
205+ const newClassName = clsx (
206+ { [ classes . SideNavLink ] : true , [ classes . SideNavLinkFull ] : enabled && variant === 'full' } ,
207+ className ,
208+ )
209+
210+ // according to their docs, NavLink supports aria-current:
211+ // https://reacttraining.com/react-router/web/api/NavLink/aria-current-string
212+ return (
213+ < StyledSideNavLink
214+ aria-current = { isReactRouter || selected ? 'page' : undefined }
215+ className = { newClassName }
216+ variant = { variant }
217+ { ...rest }
218+ >
219+ { children }
220+ </ StyledSideNavLink >
221+ )
222+ }
200223
201224SideNavLink . displayName = 'SideNav.Link'
202225
0 commit comments