Skip to content

Commit c2cfe93

Browse files
authored
Make scrollable code boxes accessible by keyboards (npm#296)
* Make scrollable code boxes accessible by keyboards * Fixed the issue on MacOS+Chrome (triple announce) * Resize the scroll handle * Add aria-label to the scroll handle
1 parent 6ceb487 commit c2cfe93

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

theme/src/components/code.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,27 @@ import {Absolute, BorderBox, Relative, Text} from '@primer/components'
22
import Highlight, {defaultProps} from 'prism-react-renderer'
33
import githubTheme from 'prism-react-renderer/themes/github'
44
import React from 'react'
5+
import {useState, useEffect} from 'react'
56
import ClipboardCopy from './clipboard-copy'
67
import LiveCode from './live-code'
78

89
function Code({className, children, live, noinline}) {
10+
const [scrollHandleStyle, setScrollHandleStyle] = useState({position: 'absolute'})
911
const language = className ? className.replace(/language-/, '') : ''
1012
const code = children.trim()
13+
const scrollHandleRef = React.createRef()
14+
15+
useEffect(() => {
16+
resizeScrollHandle()
17+
})
1118

1219
if (live) {
1320
return <LiveCode code={code} language={language} noinline={noinline} />
1421
}
1522

1623
return (
1724
<Relative>
18-
<Absolute top={0} right={0} p={2}>
25+
<Absolute top={0} right={0} p={2} zIndex={1}>
1926
<ClipboardCopy value={code} />
2027
</Absolute>
2128
<Highlight
@@ -34,6 +41,8 @@ function Code({className, children, live, noinline}) {
3441
border={0}
3542
style={{...style, overflow: 'auto'}}
3643
>
44+
{/* This is the scroll handle, it is supposed to be focused with keyboard and scroll a wide codebox horizontally */}
45+
<div aria-hidden="true" tabIndex={0} style={scrollHandleStyle} ref={scrollHandleRef} aria-label={code}>&nbsp;</div>
3746
{tokens.map((line, i) => (
3847
<div key={i} {...getLineProps({line, key: i})}>
3948
{line.map((token, key) => (
@@ -51,6 +60,22 @@ function Code({className, children, live, noinline}) {
5160
</Highlight>
5261
</Relative>
5362
)
63+
64+
/**
65+
* Resize the scroll handle to the size of the code contents, since the former has to be positioned absolutely.
66+
*/
67+
function resizeScrollHandle() {
68+
// Skip if already resized.
69+
if (typeof scrollHandleStyle.width !== 'undefined')
70+
return
71+
72+
const node = scrollHandleRef.current
73+
node.parentElement.style.position = 'relative'
74+
const computedStyle = getComputedStyle(node.parentElement)
75+
const height = node.parentElement.clientHeight - parseInt(computedStyle.paddingTop, 10) - parseInt(computedStyle.paddingBottom, 10)
76+
const width = node.parentElement.scrollWidth - parseInt(computedStyle.paddingLeft, 10) - parseInt(computedStyle.paddingRight, 10)
77+
setScrollHandleStyle({...scrollHandleStyle, height, width})
78+
}
5479
}
5580

5681
export default Code

0 commit comments

Comments
 (0)