From d9905de374be1853c438a1d9dae74b47feb9e603 Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Tue, 16 Jul 2019 17:48:23 -0700 Subject: [PATCH 01/27] feat(www): add standalone pre component with copy functionality --- www/gatsby-config.js | 3 --- www/src/components/copy.js | 48 ++++++++++++++++++++++++++++++++++++++ www/src/components/pre.js | 30 ++++++++++++++++++++++++ www/wrap-root-element.js | 2 ++ 4 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 www/src/components/copy.js create mode 100644 www/src/components/pre.js diff --git a/www/gatsby-config.js b/www/gatsby-config.js index b4985499ea47a..eac17ae45de1a 100644 --- a/www/gatsby-config.js +++ b/www/gatsby-config.js @@ -122,7 +122,6 @@ module.exports = { gatsbyRemarkPlugins: [ `gatsby-remark-graphviz`, `gatsby-remark-embed-video`, - `gatsby-remark-code-titles`, { resolve: `gatsby-remark-images`, options: { @@ -136,8 +135,6 @@ module.exports = { wrapperStyle: `margin-bottom: 1.5rem`, }, }, - `gatsby-remark-autolink-headers`, - `gatsby-remark-prismjs`, `gatsby-remark-copy-linked-files`, `gatsby-remark-smartypants`, ], diff --git a/www/src/components/copy.js b/www/src/components/copy.js new file mode 100644 index 0000000000000..e1055c5efcbef --- /dev/null +++ b/www/src/components/copy.js @@ -0,0 +1,48 @@ +import React, { useState } from "react" +import PropTypes from "prop-types" + +const copyToClipboard = content => { + const el = document.createElement(`textarea`) + el.value = content + el.setAttribute(`readonly`, ``) + el.style.position = `absolute` + el.style.left = `-9999px` + document.body.appendChild(el) + el.select() + document.execCommand(`copy`) + document.body.removeChild(el) +} + +const delay = duration => new Promise(resolve => setTimeout(resolve, duration)) + +function Copy({ content, duration = 2500, trim = false }) { + const [text, setText] = useState(`Copy`) + + return ( + + ) +} + +Copy.propTypes = { + content: PropTypes.string.isRequired, + duration: PropTypes.number, + trim: PropTypes.bool, +} + +Copy.defaultProps = { + duration: 2500, +} + +export default Copy diff --git a/www/src/components/pre.js b/www/src/components/pre.js new file mode 100644 index 0000000000000..dda65c82ec586 --- /dev/null +++ b/www/src/components/pre.js @@ -0,0 +1,30 @@ +import React from "react" + +import Copy from "./copy" + +const getParams = (name = ``) => { + const [lang, params = ``] = name.split(`:`) + return [lang.split(`language-`).pop()].concat( + params.split(`&`).reduce((merged, param) => { + const [key, value] = param.split(`=`) + merged[key] = value + return merged + }, {}) + ) +} + +export default props => { + const [language, { title = `` }] = getParams(props.children.props.className) + const content = props.children.props.children + return ( +
+ + {title &&
{title}
} + +
+
+        {content}
+      
+
+ ) +} diff --git a/www/wrap-root-element.js b/www/wrap-root-element.js index baa01f2e608e7..391da500d2820 100644 --- a/www/wrap-root-element.js +++ b/www/wrap-root-element.js @@ -4,12 +4,14 @@ import GuideList from "./src/components/guide-list.js" import HubspotForm from "./src/components/hubspot-form" import Pullquote from "./src/components/shared/pullquote" import DateChart from "./src/components/chart" +import Pre from "./src/components/pre" const components = { GuideList, HubspotForm, DateChart, Pullquote, + pre: Pre, } export default ({ element }) => ( From ed4801a341d1de725e43daa96f6abbf027e1375d Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Tue, 16 Jul 2019 17:52:33 -0700 Subject: [PATCH 02/27] chore: make it vaguely appealing --- www/src/components/copy.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/www/src/components/copy.js b/www/src/components/copy.js index e1055c5efcbef..2130c4feabc8a 100644 --- a/www/src/components/copy.js +++ b/www/src/components/copy.js @@ -1,6 +1,16 @@ import React, { useState } from "react" import PropTypes from "prop-types" +import { + space, + fonts, + fontSizes, + colors, + radii, + lineHeights, + letterSpacings, +} from "../utils/presets" + const copyToClipboard = content => { const el = document.createElement(`textarea`) el.value = content @@ -20,6 +30,21 @@ function Copy({ content, duration = 2500, trim = false }) { return ( ) } @@ -72,7 +71,8 @@ Copy.propTypes = { } Copy.defaultProps = { - duration: 2500, + duration: 5000, + fileName: ``, } export default Copy diff --git a/www/src/components/pre.js b/www/src/components/pre.js index 9a8af9fe692ce..4321592d2093d 100644 --- a/www/src/components/pre.js +++ b/www/src/components/pre.js @@ -2,7 +2,7 @@ import React from "react" import Highlight, { defaultProps } from "prism-react-renderer" import Copy from "./copy" -import { space } from "../utils/presets" +import { radii, space } from "../utils/presets" const getParams = (name = ``) => { const [lang, params = ``] = name.split(`:`) @@ -33,7 +33,15 @@ export default ({ children }) => { {title} )} - +
             {tokens.map((line, i) => (

From 16d3cbe34b1f44e9b5fb14dce49170ea78fc55ef Mon Sep 17 00:00:00 2001
From: Dustin Schau 
Date: Wed, 17 Jul 2019 12:09:39 -0700
Subject: [PATCH 08/27] feat: add screenreader text

---
 www/src/components/copy.js | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/www/src/components/copy.js b/www/src/components/copy.js
index ac19f1171bcf4..215ef37160d1e 100644
--- a/www/src/components/copy.js
+++ b/www/src/components/copy.js
@@ -1,6 +1,7 @@
 import React, { useState } from "react"
 import PropTypes from "prop-types"
 
+import { ScreenReaderText } from "./feedback-widget/styled-elements"
 import {
   space,
   fonts,
@@ -27,13 +28,13 @@ const delay = duration => new Promise(resolve => setTimeout(resolve, duration))
 function Copy({ className, content, duration, fileName, trim = false }) {
   const [copied, setCopied] = useState(false)
 
+  const label = copied
+    ? `${fileName ? fileName + ` ` : ``}copied to clipboard`
+    : `${fileName ? fileName + `: ` : ``}copy code to clipboard`
+
   return (
     
   )
 }

From 57559478b008dfe45badee2628134846b3b7e91e Mon Sep 17 00:00:00 2001
From: Dustin Schau 
Date: Wed, 17 Jul 2019 12:11:42 -0700
Subject: [PATCH 09/27] chore: swap to name

---
 www/src/components/copy.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www/src/components/copy.js b/www/src/components/copy.js
index 215ef37160d1e..7f0647bc4aa19 100644
--- a/www/src/components/copy.js
+++ b/www/src/components/copy.js
@@ -34,7 +34,7 @@ function Copy({ className, content, duration, fileName, trim = false }) {
 
   return (
     
   )
 }

From a6fe77eaf775ae4085cda42e7ec7616ecae8ac3b Mon Sep 17 00:00:00 2001
From: Dustin Schau 
Date: Thu, 18 Jul 2019 11:42:29 -0700
Subject: [PATCH 11/27] feat: get line highlighting mostly working

---
 .../code-block/__tests__/normalize.js         |  7 ++
 .../{pre.js => code-block/index.js}           | 40 +++++++---
 www/src/components/code-block/normalize.js    | 77 +++++++++++++++++++
 www/wrap-root-element.js                      |  4 +-
 4 files changed, 115 insertions(+), 13 deletions(-)
 create mode 100644 www/src/components/code-block/__tests__/normalize.js
 rename www/src/components/{pre.js => code-block/index.js} (55%)
 create mode 100644 www/src/components/code-block/normalize.js

diff --git a/www/src/components/code-block/__tests__/normalize.js b/www/src/components/code-block/__tests__/normalize.js
new file mode 100644
index 0000000000000..57e757f4c753c
--- /dev/null
+++ b/www/src/components/code-block/__tests__/normalize.js
@@ -0,0 +1,7 @@
+import normalize from "../normalize"
+
+describe(`stripping of comments`, () => {
+  it(`strips highlight-line`, () => {
+    expect(normalize(``)).toEqual([``, {}])
+  })
+})
diff --git a/www/src/components/pre.js b/www/src/components/code-block/index.js
similarity index 55%
rename from www/src/components/pre.js
rename to www/src/components/code-block/index.js
index 4321592d2093d..873f6a9e5b085 100644
--- a/www/src/components/pre.js
+++ b/www/src/components/code-block/index.js
@@ -1,8 +1,9 @@
 import React from "react"
 import Highlight, { defaultProps } from "prism-react-renderer"
 
-import Copy from "./copy"
-import { radii, space } from "../utils/presets"
+import Copy from "../copy"
+import normalize from "./normalize"
+import { fontSizes, radii, space } from "../../utils/presets"
 
 const getParams = (name = ``) => {
   const [lang, params = ``] = name.split(`:`)
@@ -17,7 +18,11 @@ const getParams = (name = ``) => {
 
 export default ({ children }) => {
   const [language, { title = `` }] = getParams(children.props.className)
-  const content = children.props.children
+  const [content, highlights] = normalize(
+    children.props.children,
+    children.props.className
+  )
+
   return (
      {
         
{title && ( -
+
{title}
)} @@ -44,13 +52,23 @@ export default ({ children }) => { />
-            {tokens.map((line, i) => (
-              
- {line.map((token, key) => ( - - ))} -
- ))} + {tokens.map((line, i) => { + const lineProps = getLineProps({ line, key: i }) + return ( +
+ {line.map((token, key) => ( + + ))} +
+ ) + })}
)} diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js new file mode 100644 index 0000000000000..b01af3579a468 --- /dev/null +++ b/www/src/components/code-block/normalize.js @@ -0,0 +1,77 @@ +const COMMENT_START = new RegExp(`(#|\\/\\/|\\{\\/\\*|\\/\\*+)`) + +const createDirectiveRegExp = featureSelector => + new RegExp(`${featureSelector}-(next-line|line|start|end|range)({([^}]+)})?`) + +const COMMENT_END = new RegExp(`(-->|\\*\\/\\}|\\*\\/)?`) +const DIRECTIVE = createDirectiveRegExp(`(highlight|hide)`) +const HIGHLIGHT_DIRECTIVE = createDirectiveRegExp(`highlight`) + +const END_DIRECTIVE = { + highlight: /highlight-end/, + hide: /hide-end/, +} + +const stripComment = line => + /** + * This regexp does the following: + * 1. Match a comment start, along with the accompanying PrismJS opening comment span tag; + * 2. Match one of the directives; + * 3. Match a comment end, along with the accompanying PrismJS closing span tag. + */ + line.replace( + new RegExp( + `\\s*(${COMMENT_START.source})\\s*${DIRECTIVE.source}\\s*(${ + COMMENT_END.source + })` + ), + `` + ) + +/* + * This function will output the normalized content (stripped of comment directives) + * alongside a lookup of filtered lines + * Note: this does not as of yet handle the hide directive + */ +export default content => { + const split = content.split(`\n`) + let filtered = [] + let highlights = {} + + for (let i = 0; i < split.length; i++) { + const line = split[i] + if (HIGHLIGHT_DIRECTIVE.test(line)) { + const [, , directive] = line.match(DIRECTIVE) + switch (directive) { + case `start`: { + const endIndex = split + .slice(i + 1) + .findIndex(line => END_DIRECTIVE.highlight.test(line)) + + const end = endIndex === -1 ? split.length : endIndex + i + + for (let j = i + 1; j < end + 1; j++) { + highlights[j - 1] = true + } + break + } + case `line`: { + highlights[i] = true + filtered.push(stripComment(line)) + break + } + case `next-line`: { + highlights[i] = true + break + } + default: { + break + } + } + } else { + filtered.push(line) + } + } + + return [filtered.join(`\n`), highlights] +} diff --git a/www/wrap-root-element.js b/www/wrap-root-element.js index 391da500d2820..afdc666658dcd 100644 --- a/www/wrap-root-element.js +++ b/www/wrap-root-element.js @@ -4,14 +4,14 @@ import GuideList from "./src/components/guide-list.js" import HubspotForm from "./src/components/hubspot-form" import Pullquote from "./src/components/shared/pullquote" import DateChart from "./src/components/chart" -import Pre from "./src/components/pre" +import CodeBlock from "./src/components/code-block" const components = { GuideList, HubspotForm, DateChart, Pullquote, - pre: Pre, + pre: CodeBlock, } export default ({ element }) => ( From 2ea5c81582a676120a2f51cdb4313cadaacd344c Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 18 Jul 2019 12:08:25 -0700 Subject: [PATCH 12/27] feat: get hide directive working too --- www/src/components/code-block/normalize.js | 32 ++++++++++++++++------ 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js index b01af3579a468..1f6a343f14db9 100644 --- a/www/src/components/code-block/normalize.js +++ b/www/src/components/code-block/normalize.js @@ -6,6 +6,7 @@ const createDirectiveRegExp = featureSelector => const COMMENT_END = new RegExp(`(-->|\\*\\/\\}|\\*\\/)?`) const DIRECTIVE = createDirectiveRegExp(`(highlight|hide)`) const HIGHLIGHT_DIRECTIVE = createDirectiveRegExp(`highlight`) +const HIDE_DIRECTIVE = createDirectiveRegExp(`hide`) const END_DIRECTIVE = { highlight: /highlight-end/, @@ -28,6 +29,9 @@ const stripComment = line => `` ) +const containsDirective = line => + [HIDE_DIRECTIVE, HIGHLIGHT_DIRECTIVE].some(expr => expr.test(line)) + /* * This function will output the normalized content (stripped of comment directives) * alongside a lookup of filtered lines @@ -40,28 +44,40 @@ export default content => { for (let i = 0; i < split.length; i++) { const line = split[i] - if (HIGHLIGHT_DIRECTIVE.test(line)) { - const [, , directive] = line.match(DIRECTIVE) + if (containsDirective(line)) { + const [, keyword, directive] = line.match(DIRECTIVE) switch (directive) { case `start`: { const endIndex = split .slice(i + 1) - .findIndex(line => END_DIRECTIVE.highlight.test(line)) + .findIndex(line => END_DIRECTIVE[keyword].test(line)) const end = endIndex === -1 ? split.length : endIndex + i - for (let j = i + 1; j < end + 1; j++) { - highlights[j - 1] = true + if (keyword === `highlight`) { + for (let j = i + 1; j < end + 1; j++) { + highlights[j - 1] = true + } + } else if (keyword === `hide`) { + i = end } break } case `line`: { - highlights[i] = true - filtered.push(stripComment(line)) + if (keyword === `highlight`) { + highlights[i] = true + filtered.push(stripComment(line)) + } else if (keyword === `hide`) { + i += 1 + } break } case `next-line`: { - highlights[i] = true + if (keyword === `highlight`) { + highlights[i] = true + } else if (keyword === `hide`) { + i += 1 + } break } default: { From 253eef5171214b70fd1272af8c7bb59124a38cd8 Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 18 Jul 2019 12:21:41 -0700 Subject: [PATCH 13/27] feat: iron out highlights and use correct aria-role --- www/src/components/code-block/index.js | 8 +++++--- www/src/components/code-block/normalize.js | 19 ++++++++++++++----- www/src/components/copy.js | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/www/src/components/code-block/index.js b/www/src/components/code-block/index.js index 873f6a9e5b085..295674cba62bb 100644 --- a/www/src/components/code-block/index.js +++ b/www/src/components/code-block/index.js @@ -54,13 +54,15 @@ export default ({ children }) => {
             {tokens.map((line, i) => {
               const lineProps = getLineProps({ line, key: i })
+              const className = [lineProps.className]
+                .concat(highlights[i] && `gatsby-highlight-code-line`)
+                .filter(Boolean)
+                .join(` `)
               return (
                 
{line.map((token, key) => ( diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js index 1f6a343f14db9..0e699ff570a3a 100644 --- a/www/src/components/code-block/normalize.js +++ b/www/src/components/code-block/normalize.js @@ -56,7 +56,7 @@ export default content => { if (keyword === `highlight`) { for (let j = i + 1; j < end + 1; j++) { - highlights[j - 1] = true + highlights[split[j]] = true } } else if (keyword === `hide`) { i = end @@ -65,8 +65,9 @@ export default content => { } case `line`: { if (keyword === `highlight`) { - highlights[i] = true - filtered.push(stripComment(line)) + const stripped = stripComment(line) + highlights[stripped] = true + filtered.push(stripped) } else if (keyword === `hide`) { i += 1 } @@ -74,7 +75,7 @@ export default content => { } case `next-line`: { if (keyword === `highlight`) { - highlights[i] = true + highlights[split[i + 1]] = true } else if (keyword === `hide`) { i += 1 } @@ -89,5 +90,13 @@ export default content => { } } - return [filtered.join(`\n`), highlights] + return [ + filtered.join(`\n`), + filtered.reduce((merged, line, index) => { + if (highlights[line]) { + merged[index] = true + } + return merged + }, {}), + ] } diff --git a/www/src/components/copy.js b/www/src/components/copy.js index 49baa3bf12dc6..8aebf52ba7c6a 100644 --- a/www/src/components/copy.js +++ b/www/src/components/copy.js @@ -61,7 +61,7 @@ function Copy({ className, content, duration, fileName, trim = false }) { }} > {copied ? `Copied` : `Copy`} - {label} + {label} ) } From a8eff918b2033d6738016710353c0dbea03d58f2 Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 18 Jul 2019 12:33:09 -0700 Subject: [PATCH 14/27] chore: iron-out hide --- www/src/components/code-block/normalize.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js index 0e699ff570a3a..d186e5119c688 100644 --- a/www/src/components/code-block/normalize.js +++ b/www/src/components/code-block/normalize.js @@ -68,8 +68,6 @@ export default content => { const stripped = stripComment(line) highlights[stripped] = true filtered.push(stripped) - } else if (keyword === `hide`) { - i += 1 } break } @@ -77,6 +75,7 @@ export default content => { if (keyword === `highlight`) { highlights[split[i + 1]] = true } else if (keyword === `hide`) { + filtered.push(stripComment(line)) i += 1 } break From 083c71fa64fbf74d57f668f266d6d2cd68658ccd Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 18 Jul 2019 13:33:22 -0700 Subject: [PATCH 15/27] feat: add support for braces in language --- www/src/components/code-block/index.js | 8 ++++- www/src/components/code-block/normalize.js | 42 ++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/www/src/components/code-block/index.js b/www/src/components/code-block/index.js index 295674cba62bb..a580f63d5b53e 100644 --- a/www/src/components/code-block/index.js +++ b/www/src/components/code-block/index.js @@ -7,7 +7,13 @@ import { fontSizes, radii, space } from "../../utils/presets" const getParams = (name = ``) => { const [lang, params = ``] = name.split(`:`) - return [lang.split(`language-`).pop()].concat( + return [ + lang + .split(`language-`) + .pop() + .split(`{`) + .shift(), + ].concat( params.split(`&`).reduce((merged, param) => { const [key, value] = param.split(`=`) merged[key] = value diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js index d186e5119c688..fc4c6108f9a1a 100644 --- a/www/src/components/code-block/normalize.js +++ b/www/src/components/code-block/normalize.js @@ -1,4 +1,4 @@ -const COMMENT_START = new RegExp(`(#|\\/\\/|\\{\\/\\*|\\/\\*+)`) +const COMMENT_START = new RegExp(`(#|\\/\\/|\\{\\/\\*|\\/\\*+| +
+ `.trim(), + `html` + ) + ).toEqual([expect.any(String), { 1: true }]) + }) + + it(`handles yaml`, () => { + expect( + normalize( + ` + something: true + highlighted: you bedda believe it # highlight-line + `.trim(), + `html` + ) + ).toEqual([expect.any(String), { 1: true }]) + }) + + it(`handles css`, () => { + expect( + normalize( + ` + p { + color: red; // highlight-line + } + `.trim(), + `css` + ) + ).toEqual([expect.any(String), { 1: true }]) + }) + + it(`handles graphql`, () => { + expect( + normalize( + ` + query whatever { + field # highlight-line + } + `.trim(), + `graphql` + ) + ).toEqual([expect.any(String), { 1: true }]) + }) +}) + describe(`hiding`, () => { it(`hide-line`, () => { expect( @@ -80,6 +160,20 @@ describe(`hiding`, () => { ).toEqual([``, expect.any(Object)]) }) + it(`hide-start without end`, () => { + expect( + normalize( + ` + var a = 'b' + // hide-start + var b = 'c' + var d = 'e' + `.trim(), + `jsx` + ) + ).toEqual([`var a = 'b'`, expect.any(Object)]) + }) + describe(`next-line`, () => { it(`on same line`, () => { expect( From 45d92a418b310f1d5bec48cb14f7c47e8743c97d Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 18 Jul 2019 20:30:08 -0700 Subject: [PATCH 24/27] chore: more fixes --- www/src/components/code-block/normalize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js index 45109eb892e16..f36c7d43ef6e3 100644 --- a/www/src/components/code-block/normalize.js +++ b/www/src/components/code-block/normalize.js @@ -118,8 +118,8 @@ export default (content, className = ``) => { filtered.push({ code: stripComment(line), }) - i += 1 } + i += 1 break } default: { From 7a89649c244189ef2b7ac9961991de06bed1043c Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Fri, 19 Jul 2019 09:17:05 -0700 Subject: [PATCH 25/27] test: more tests; and calling this done! --- .../components/code-block/__tests__/index.js | 69 +++++++++++++++++++ .../code-block/__tests__/normalize.js | 4 +- www/src/components/code-block/index.js | 18 +++-- www/src/components/code-block/normalize.js | 40 ++++++----- 4 files changed, 109 insertions(+), 22 deletions(-) create mode 100644 www/src/components/code-block/__tests__/index.js diff --git a/www/src/components/code-block/__tests__/index.js b/www/src/components/code-block/__tests__/index.js new file mode 100644 index 0000000000000..8bbcbc7a8962a --- /dev/null +++ b/www/src/components/code-block/__tests__/index.js @@ -0,0 +1,69 @@ +import React from "react" +import CodeBlock from ".." +import { fireEvent, render } from "react-testing-library" + +beforeEach(() => { + document.execCommand = jest.fn() +}) + +describe(`basic functionality`, () => { + describe(`copy`, () => { + it(`renders a copy button`, () => { + const { queryByText } = render( + {`var a = 'b'`} + ) + + expect(queryByText(`copy`)).toBeDefined() + }) + + it(`copies text to clipboard`, () => { + const text = `alert('hello world')` + const { queryByText } = render( + {text} + ) + + const copyButton = queryByText(`Copy`) + + fireEvent.click(copyButton) + + expect(document.execCommand).toHaveBeenCalledWith(`copy`) + }) + }) + + describe(`highlighting`, () => { + let instance + const hidden = `var a = 'i will be hidden'` + const highlighted = ` +
+

Oh shit waddup

+
+ `.trim() + beforeEach(() => { + const text = ` + import React from 'react' + + ${hidden} // hide-line + + export default function HelloWorld() { + return ( + {/* highlight-start */} + ${highlighted} + {/* highlight-end */} + ) + } + `.trim() + instance = render({text}) + }) + + it(`hides lines appropriately`, () => { + expect(instance.queryByText(hidden)).toBeNull() + }) + + it(`highlights lines appropriately`, () => { + const lines = highlighted.split(`\n`) + expect( + instance.container.querySelectorAll(`.gatsby-highlight-code-line`) + ).toHaveLength(lines.length) + }) + }) +}) diff --git a/www/src/components/code-block/__tests__/normalize.js b/www/src/components/code-block/__tests__/normalize.js index 1438d3e29ebfe..c77a99031687b 100644 --- a/www/src/components/code-block/__tests__/normalize.js +++ b/www/src/components/code-block/__tests__/normalize.js @@ -12,7 +12,7 @@ describe(`highlighting`, () => { `.trim(), `jsx` ) - ).toEqual([expect.any(String), { 0: true, 1: true, 2: true }]) + ).toEqual([expect.any(String), { 0: true, 1: true }]) }) it(`highlight-start, without end`, () => { @@ -26,7 +26,7 @@ describe(`highlighting`, () => { `.trim(), `jsx` ) - ).toEqual([expect.any(String), { 1: true, 2: true, 3: true }]) + ).toEqual([expect.any(String), { 1: true, 2: true }]) }) it(`highlight-line`, () => { diff --git a/www/src/components/code-block/index.js b/www/src/components/code-block/index.js index 525dd5e2042ab..44db706ff7ec4 100644 --- a/www/src/components/code-block/index.js +++ b/www/src/components/code-block/index.js @@ -22,11 +22,21 @@ const getParams = (name = ``) => { ) } -export default ({ children }) => { - const [language, { title = `` }] = getParams(children.props.className) +/* + * MDX passes the code block as JSX + * we un-wind it a bit to get the string content + * but keep it extensible so it can be used with just children (string) and className + */ +export default ({ + children, + className = children.props ? children.props.className : ``, +}) => { + const [language, { title = `` }] = getParams(className) const [content, highlights] = normalize( - children.props.children, - children.props.className + children.props && children.props.children + ? children.props.children + : children, + className ) return ( diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js index f36c7d43ef6e3..1a19a24746280 100644 --- a/www/src/components/code-block/normalize.js +++ b/www/src/components/code-block/normalize.js @@ -82,12 +82,16 @@ export default (content, className = ``) => { if (keyword === `highlight`) { filtered = filtered.concat( - split.slice(i, end + 1).map(line => { - return { - code: stripComment(line), - highlighted: true, + split.slice(i, end + 1).reduce((merged, line) => { + const code = stripComment(line) + if (code) { + merged.push({ + code, + highlighted: true, + }) } - }) + return merged + }, []) ) } @@ -95,25 +99,29 @@ export default (content, className = ``) => { break } case `line`: { - if (keyword === `highlight`) { + const code = stripComment(line) + if (keyword === `highlight` && code) { filtered.push({ - code: stripComment(line), + code, highlighted: true, }) } break } case `next-line`: { + const code = stripComment(line) if (keyword === `highlight`) { - filtered = filtered.concat([ - { - code: stripComment(line), - }, - { - code: stripComment(split[i + 1]), - highlighted: true, - }, - ]) + filtered = filtered.concat( + [ + { + code, + }, + { + code: stripComment(split[i + 1]), + highlighted: true, + }, + ].filter(line => line.code) + ) } else if (keyword === `hide`) { filtered.push({ code: stripComment(line), From 1742d2be4072bc1c9ab054576103f54c10bdba3e Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Fri, 19 Jul 2019 09:18:40 -0700 Subject: [PATCH 26/27] chore: tiny fix --- www/src/components/code-block/normalize.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/src/components/code-block/normalize.js b/www/src/components/code-block/normalize.js index 1a19a24746280..fd1aa6836cdf8 100644 --- a/www/src/components/code-block/normalize.js +++ b/www/src/components/code-block/normalize.js @@ -122,9 +122,9 @@ export default (content, className = ``) => { }, ].filter(line => line.code) ) - } else if (keyword === `hide`) { + } else if (keyword === `hide` && code) { filtered.push({ - code: stripComment(line), + code, }) } i += 1 From 1be3da0c389a5eb885ce2c1c26a835d4662a42e4 Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Fri, 19 Jul 2019 09:21:19 -0700 Subject: [PATCH 27/27] chore: add back missing autolink headers --- www/gatsby-config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/gatsby-config.js b/www/gatsby-config.js index eac17ae45de1a..42f4b9800f3e2 100644 --- a/www/gatsby-config.js +++ b/www/gatsby-config.js @@ -135,6 +135,7 @@ module.exports = { wrapperStyle: `margin-bottom: 1.5rem`, }, }, + `gatsby-remark-autolink-headers`, `gatsby-remark-copy-linked-files`, `gatsby-remark-smartypants`, ],