From 48b731be876af22f27a9edbbbfa0a110137ce1a2 Mon Sep 17 00:00:00 2001 From: Hector Garcia Date: Thu, 14 Jul 2022 18:26:59 +0200 Subject: [PATCH] Add line highlighting --- docs/content/usage/live-code.mdx | 31 +++++++++++++- theme/src/components/code.js | 6 ++- theme/src/components/live-code.js | 71 +++++++++++++++++++++++-------- 3 files changed, 88 insertions(+), 20 deletions(-) diff --git a/docs/content/usage/live-code.mdx b/docs/content/usage/live-code.mdx index 3408fbe5..6d9a1f7c 100644 --- a/docs/content/usage/live-code.mdx +++ b/docs/content/usage/live-code.mdx @@ -55,6 +55,35 @@ Every property on the object exported by `live-code-scope.js` will be available ``` ```` +## Line highlighting + +If you want to emphasize a particular range of lines, use the `highlight` attribute on the code block. The expected format is `higlight=start-end`. The line highlighting will disappear when the live example is edited. + + +````markdown +``` jsx live highlight=2-4 +
+

+ This paragraph element should be higlighted. +

+

+ This paragraph element should not be higlighted. +

+
+``` +```` + +``` jsx live highlight=2-4 +
+

+ This paragraph element should be higlighted. +

+

+ This paragraph element should not be higlighted. +

+
+``` + ## Global styles Live previews are completely isolated from the rest of the page because they are rendered inside [iframes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe). This means that you can apply global styles inside live previews without affecting the rest of the page: @@ -120,4 +149,4 @@ function DemoApp() { } render() -``` +``` \ No newline at end of file diff --git a/theme/src/components/code.js b/theme/src/components/code.js index 82a98852..d05b89be 100644 --- a/theme/src/components/code.js +++ b/theme/src/components/code.js @@ -6,12 +6,14 @@ import Prism from '../prism' import ClipboardCopy from './clipboard-copy' import LiveCode from './live-code' -function Code({className, children, live, noinline, metastring}) { +function Code({className, children, live, highlight, noinline, metastring}) { const language = className ? className.replace(/language-/, '') : '' const code = children.trim() if (live) { - return + return ( + + ) } return ( diff --git a/theme/src/components/live-code.js b/theme/src/components/live-code.js index 884c2403..059af618 100644 --- a/theme/src/components/live-code.js +++ b/theme/src/components/live-code.js @@ -8,6 +8,8 @@ import {ThemeContext} from 'styled-components' import scope from '../live-code-scope' import ClipboardCopy from './clipboard-copy' import LivePreviewWrapper from './live-preview-wrapper' +import styled from 'styled-components' +import themeGet from '@styled-system/theme-get' const languageTransformers = { html: html => htmlToJsx(html), @@ -39,10 +41,43 @@ const getResolvedScope = metastring => { return scope } -function LiveCode({code, language, noinline, metastring}) { +function parseHighlightRange(highlight) { + // Captures numbers separated by a dash: 2-3, 34-5, 2-101 + const numbersWithDash = new RegExp('([0-9]+)-([0-9]+)') + + const match = numbersWithDash.exec(highlight) + if (!match) return null + + return {firstLine: match[1], lastLine: match[2]} +} + +const LineWrapper = styled.div` + // Using negative and positive nth-child values to select the children. + pre .token-line:nth-child(n + ${props => props.range.firstLine}):nth-child(-n + ${props => props.range.lastLine}) { + // 16px is the padding of the react-live
 element that wraps the .token-line elements.
+    // The margin/padding combo extends the token-line elements so the background color reaches the border.
+    margin: 0px -16px;
+    padding: 0px 16px;
+    background-color: ${themeGet('colors.accent.subtle')};
+    // We use box-shadow instead of a border to avoid flickering when toggling the highlighting on/off.
+    box-shadow: inset 3px 0px 0px 0px ${themeGet('colors.accent.fg')};
+  }
+`
+
+function LineHighlighter({enabled, range, children}) {
+  if (!enabled || !range) return children
+
+  return {children}
+}
+
+function LiveCode({code, language, highlight, noinline, metastring}) {
   const theme = React.useContext(ThemeContext)
   const [liveCode, setLiveCode] = useState(code)
-  const handleChange = updatedLiveCode => setLiveCode(updatedLiveCode)
+  const [pristine, setPristine] = useState(true)
+  const handleChange = updatedLiveCode => {
+    setLiveCode(updatedLiveCode)
+    setPristine(false)
+  }
 
   return (
     
@@ -66,21 +101,23 @@ function LiveCode({code, language, noinline, metastring}) {
           
         
         
-          
+          
+            
+