Can't access theme
& showLineNumbers
directly in pre
tag in MDXComponents
while using MDX & Rehype Plugins on a Next.js blog?
#58
-
I am creating a Next.js Blog & I'm facing a small issue. I have MDX block like: ```jsx theme=orange showLineNumbers=true
import React from 'react'
export function Counter({ initialCount = 0 }) {
const [count, setCount] = React.useState(initialCount)
return (
<button type="button" onClick={() => setCount((prevCount) => prevCount + 1)}>
{count}
</button>
)
}
``` I have a Pre tag like: import React from 'react'
type PreProps = {
children: React.ReactChild
theme: string
showLineNumbers: string
}
export const Pre = ({ children, theme, showLineNumbers }: PreProps) => {
console.log('Pre -> start')
console.log({ children, theme, showLineNumbers })
console.log('Pre -> end')
return (
<pre
className={`px-4 py-3 overflow-x-auto rounded-md ${
theme ? `${theme}-theme` : 'bg-gray-900'
} ${showLineNumbers ? 'line-numbers' : ''}`}
>
{children}
</pre>
)
} However, I can't access And I get the following when I use the
This is probably because of some I have highlight-word const visit = require('unist-util-visit')
const hastToHtml = require('hast-util-to-html')
const unified = require('unified')
const parse = require('rehype-parse')
const CALLOUT = /__(.*?)__/g
module.exports = (code) => {
const html = hastToHtml(code)
const result = html.replace(CALLOUT, (_, text) => `<span class="highlight-word">${text}</span>`)
const hast = unified().use(parse, { emitParseErrors: true, fragment: true }).parse(result)
return hast.children
} I have highlight-line const hastToHtml = require('hast-util-to-html')
const unified = require('unified')
const parse = require('rehype-parse')
const lineNumberify = function lineNumberify(ast, lineNum = 1) {
let lineNumber = lineNum
return ast.reduce(
(result, node) => {
if (node.type === 'text') {
if (node.value.indexOf('\n') === -1) {
node.lineNumber = lineNumber
result.nodes.push(node)
return result
}
const lines = node.value.split('\n')
for (let i = 0; i < lines.length; i++) {
if (i !== 0) ++lineNumber
if (i === lines.length - 1 && lines[i].length === 0) continue
result.nodes.push({
type: 'text',
value: i === lines.length - 1 ? lines[i] : `${lines[i]}\n`,
lineNumber: lineNumber,
})
}
result.lineNumber = lineNumber
return result
}
if (node.children) {
node.lineNumber = lineNumber
const processed = lineNumberify(node.children, lineNumber)
node.children = processed.nodes
result.lineNumber = processed.lineNumber
result.nodes.push(node)
return result
}
result.nodes.push(node)
return result
},
{ nodes: [], lineNumber: lineNumber }
)
}
const wrapLines = function wrapLines(ast, linesToHighlight) {
const highlightAll = linesToHighlight.length === 1 && linesToHighlight[0] === 0
const allLines = Array.from(new Set(ast.map((x) => x.lineNumber)))
let i = 0
const wrapped = allLines.reduce((nodes, marker) => {
const line = marker
const children = []
for (; i < ast.length; i++) {
if (ast[i].lineNumber < line) {
nodes.push(ast[i])
continue
}
if (ast[i].lineNumber === line) {
children.push(ast[i])
continue
}
if (ast[i].lineNumber > line) {
break
}
}
nodes.push({
type: 'element',
tagName: 'div',
properties: {
dataLine: line,
className: 'highlight-line',
dataHighlighted: linesToHighlight.includes(line) || highlightAll ? 'true' : 'false',
},
children: children,
lineNumber: line,
})
return nodes
}, [])
return wrapped
}
// https://github.com/gatsbyjs/gatsby/pull/26161/files
const MULTILINE_TOKEN_SPAN = /<span class="token ([^"]+)">[^<]*\n[^<]*<\/span>/g
const applyMultilineFix = function (ast) {
// AST to HTML
let html = hastToHtml(ast)
// Fix JSX issue
html = html.replace(MULTILINE_TOKEN_SPAN, (match, token) =>
match.replace(/\n/g, `</span>\n<span class="token ${token}">`)
)
// HTML to AST
const hast = unified().use(parse, { emitParseErrors: true, fragment: true }).parse(html)
return hast.children
}
module.exports = function (ast, lines) {
const formattedAst = applyMultilineFix(ast)
const numbered = lineNumberify(formattedAst).nodes
return wrapLines(numbered, lines)
} I have a highlight-code const rangeParser = require('parse-numeric-range')
const visit = require('unist-util-visit')
const nodeToString = require('hast-util-to-string')
const refractor = require('refractor')
const highlightLine = require('./highlight-line')
const highlightWord = require('./highlight-word')
module.exports = (options = {}) => {
return (tree) => {
visit(tree, 'element', visitor)
}
function visitor(node, index, parentNode) {
if (parentNode.tagName === 'pre' && node.tagName === 'code') {
// syntax highlight
const lang = node.properties.className ? node.properties.className[0].split('-')[1] : 'md'
let result = refractor.highlight(nodeToString(node), lang)
// line highlight
const linesToHighlight = rangeParser(node.properties.line || '0')
result = highlightLine(result, linesToHighlight)
// word highlight
result = highlightWord(result)
node.children = result
}
}
} How do I get access to Minimal repro is here → https://github.com/deadcoder0904/better-code-blocks My code is based on this amazing blog post → https://ped.ro/blog/code-blocks-but-better The code for the blog post is here → https://github.com/peduarte/ped.ro The only difference is I am using |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 22 replies
-
I believe this is an xdm related question, and not necessarily related to rehype/html. |
Beta Was this translation helpful? Give feedback.
-
This did the trick: meta-attribute.jsconst visit = require('unist-util-visit')
var re = /\b([-\w]+)(?:=(?:"([^"]*)"|'([^']*)'|([^"'\s]+)))?/g
module.exports = (options = {}) => {
return (tree) => {
visit(tree, 'element', visitor)
}
function visitor(node, index, parentNode) {
let match
if (node.tagName === 'pre') {
const code = node.children.find((d) => d.tagName === 'code')
if (code.properties.metastring) {
code.properties.metastring.split(' ').forEach((item) => {
const [metaKey, metaValue] = item.split('=')
node.properties[metaKey] = metaValue || ''
})
}
}
}
} @wooorm Any way I can remove my custom properties like |
Beta Was this translation helpful? Give feedback.
This did the trick:
meta-attribute.js
@wooorm Any way I can remove my custom properties like
theme
from DOM?