forked from primer/react
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[UnderlineNav] Accessibility Remediations (primer#2406)
* UnderlineNav accessibility remediations * update tests * lint and interaction story update * ariaLabel optional and add a comment * remove conditional tabindex and find a better way to manage focus * restyle arrow btns and fix focus issue * add aria-label type * aria-label improvements * add changeset * arrow button slide in and out behaviour * bump octicons_react version up * update snapshots * update docs * add docs name
- Loading branch information
1 parent
45afa3d
commit 96b004b
Showing
30 changed files
with
1,954 additions
and
1,632 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@primer/react': patch | ||
--- | ||
|
||
UnderlineNav2: Address accessibility feedback and re-style arrow buttons for scroll behaviour |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,66 @@ | ||
import React, {useContext} from 'react' | ||
import {IconButton} from '../Button/IconButton' | ||
import {ChevronLeftIcon, ChevronRightIcon} from '@primer/octicons-react' | ||
import {getLeftArrowHiddenBtn, getRightArrowHiddenBtn, getLeftArrowVisibleBtn, getRightArrowVisibleBtn} from './styles' | ||
import {btnWrapperStyles, getArrowBtnStyles} from './styles' | ||
import {OnScrollWithButtonEventType} from './types' | ||
import {UnderlineNavContext} from './UnderlineNavContext' | ||
import Box from '../Box' | ||
|
||
const LeftArrowButton = ({ | ||
const ArrowButton = ({ | ||
scrollValue, | ||
type, | ||
show, | ||
onScrollWithButton | ||
onScrollWithButton, | ||
'aria-label': ariaLabel | ||
}: { | ||
scrollValue: number | ||
type: 'left' | 'right' | ||
show: boolean | ||
onScrollWithButton: OnScrollWithButtonEventType | ||
'aria-label'?: React.AriaAttributes['aria-label'] | ||
}) => { | ||
const leftBtnRef = React.useRef<HTMLButtonElement>(null) | ||
const rightBtnRef = React.useRef<HTMLButtonElement>(null) | ||
const {theme} = useContext(UnderlineNavContext) | ||
return ( | ||
<IconButton | ||
aria-label="Scroll Left" | ||
onClick={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => onScrollWithButton(e, -1)} | ||
icon={ChevronLeftIcon} | ||
sx={show ? getLeftArrowVisibleBtn(theme) : getLeftArrowHiddenBtn(theme)} | ||
/> | ||
) | ||
} | ||
const direction = type === 'left' ? -1 : 1 | ||
const ARROW_BTN_WIDTH = 44 // Min touch target size is 44px | ||
|
||
// re-trigger focus on the button with aria-disabled=true when it becomes hidden to communicate to screen readers that the button is no longer available | ||
React.useEffect(() => { | ||
const currentBtn = type === 'left' ? leftBtnRef.current : rightBtnRef.current | ||
if (currentBtn?.getAttribute('aria-disabled') === 'true') { | ||
currentBtn.focus() | ||
} else { | ||
// eslint-disable-next-line github/no-blur | ||
currentBtn?.blur() | ||
} | ||
}, [show, type]) | ||
|
||
let translateX = 0 | ||
let display = 'flex' | ||
|
||
// Determine the translateX value to transform for the slide in/out effect | ||
if (scrollValue === 0) { | ||
// If the scrollValue is 0, the buttons should be hidden | ||
translateX = ARROW_BTN_WIDTH * direction | ||
// This is mainly needed for the right arrow button. Because hiding translateX value for it is positive (44px) and this positive value was causing button to be visibly overflowed rathan than hiding. | ||
display = 'none' | ||
} else if (scrollValue <= ARROW_BTN_WIDTH) translateX = (ARROW_BTN_WIDTH - scrollValue) * direction | ||
else translateX = 0 | ||
|
||
const RightArrowButton = ({ | ||
show, | ||
onScrollWithButton | ||
}: { | ||
show: boolean | ||
onScrollWithButton: OnScrollWithButtonEventType | ||
}) => { | ||
const {theme} = useContext(UnderlineNavContext) | ||
return ( | ||
<IconButton | ||
aria-label="Scroll Right" | ||
onClick={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => onScrollWithButton(e, 1)} | ||
icon={ChevronRightIcon} | ||
sx={show ? getRightArrowVisibleBtn(theme) : getRightArrowHiddenBtn(theme)} | ||
/> | ||
<Box sx={btnWrapperStyles(theme, type, show, translateX, display)}> | ||
<IconButton | ||
tabIndex={show ? 0 : -1} | ||
ref={type === 'left' ? leftBtnRef : rightBtnRef} | ||
aria-label={`Scroll ${ariaLabel} navigation ${type}`} | ||
onClick={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => onScrollWithButton(e, direction)} | ||
icon={type === 'left' ? ChevronLeftIcon : ChevronRightIcon} | ||
sx={getArrowBtnStyles(theme, type)} | ||
aria-disabled={!show} | ||
/> | ||
</Box> | ||
) | ||
} | ||
|
||
export {LeftArrowButton, RightArrowButton} | ||
export {ArrowButton} |
Oops, something went wrong.