fix: scroll code containers so copy button does not overlay
Closes #19
Luke Karrys committed
Sep 29, 2023 at 13:35 UTC
07c12792539fe5ad1899320faca8937dc1dab576
2 files changed
+29
-26
theme/gatsby-config.js
+3
-1
@@ -20,7 +20,9 @@ module.exports = themeOptions => {
20
resolve: 'gatsby-source-filesystem',
21
options: {
22
name: 'content',
23
- path: path.resolve('./content'),
23
+ path: process.env.GATSBY_PARTIAL_CONTENT
24
+ ? path.resolve(`./content/${process.env.GATSBY_PARTIAL_CONTENT}`)
25
+ : path.resolve('./content'),
26
},
27
},
28
{
theme/src/components/code.js
+26
-25
@@ -9,37 +9,40 @@ import LiveCode from './live-code'
9
* Resize the scroll handle to the size of the code contents, since the former has to be positioned absolutely.
10
*/
11
const useScrollSize = () => {
12
- const ref = React.createRef()
12
+ const scrollRef = React.createRef()
13
+ const paddingRef = React.createRef()
14
const [size, setSize] = useState({})
15
16
useEffect(() => {
16
- // Skip if already resized.
17
- if (typeof size.width !== 'undefined') {
17
+ const scrollNode = scrollRef.current
18
+ const paddingNode = paddingRef.current
19
+
20
+ if (!scrollNode || !paddingNode || typeof size.width !== 'undefined') {
21
return
22
}
23
21
- const node = ref.current
22
- node.parentElement.style.position = 'relative'
23
- const computedStyle = getComputedStyle(node.parentElement)
24
+ const parent = scrollNode.parentElement
25
+ const button = paddingNode.firstChild
26
+
27
+ parent.style.position = 'relative'
28
+ const parentStyle = getComputedStyle(parent)
29
+ const paddingTop = parseInt(parentStyle.paddingTop, 10)
30
+ const paddingBottom = parseInt(parentStyle.paddingBottom, 10)
31
+ const paddingRight = parseInt(parentStyle.paddingRight, 10)
32
+
33
setSize({
25
- height:
26
- node.parentElement.clientHeight -
27
- parseInt(computedStyle.paddingTop, 10) -
28
- parseInt(computedStyle.paddingBottom, 10),
29
- width:
30
- node.parentElement.scrollWidth -
31
- parseInt(computedStyle.paddingLeft, 10) -
32
- parseInt(computedStyle.paddingRight, 10),
34
+ height: parent.clientHeight - paddingTop - paddingBottom,
35
+ width: parent.scrollWidth - paddingRight + button.clientWidth,
36
})
34
- }, [size, ref])
37
+ }, [scrollRef, paddingRef, size])
38
36
- return [ref, size]
39
+ return {scrollRef, paddingRef, size}
40
}
41
42
function Code({className, children, live, noinline}) {
43
const language = className ? className.replace(/language-/, '') : ''
44
const code = children.trim()
42
- const [scrollHandleRef, scrollSize] = useScrollSize()
45
+ const {scrollRef, paddingRef, size} = useScrollSize()
46
47
if (live) {
48
return <LiveCode code={code} language={language} noinline={noinline} />
@@ -47,18 +50,16 @@ function Code({className, children, live, noinline}) {
50
51
return (
52
<Relative>
50
- <Absolute top={0} right={0} p={2} zIndex={1}>
51
- <ClipboardCopy value={code} />
52
- </Absolute>
53
+ <div ref={paddingRef}>
54
+ <Absolute top={0} right={0} p={2} zIndex={1}>
55
+ <ClipboardCopy value={code} />
56
+ </Absolute>
57
+ </div>
58
<Highlight {...defaultProps} code={code} language={language} theme={githubTheme}>
59
{({className, style, tokens, getLineProps, getTokenProps}) => (
60
<BorderBox as="pre" className={className} mt={0} mb={3} p={3} border={0} style={{...style, overflow: 'auto'}}>
61
{/* This is the scroll handle, it is supposed to be focused with keyboard and scroll a wide codebox horizontally */}
57
- <div
58
- aria-hidden="true"
59
- style={{visibility: 'hidden', position: 'absolute', ...scrollSize}}
60
- ref={scrollHandleRef}
61
- />
62
+ <div aria-hidden="true" style={{visibility: 'hidden', position: 'absolute', ...size}} ref={scrollRef} />
63
{tokens.map((line, i) => (
64
<div key={i} {...getLineProps({line, key: i})}>
65
{line.map((token, key) => (