In react-remark, can I update text from a rehype plugin? #1312
Replies: 2 comments 2 replies
-
The answer to your discussion title: yes! For the rest: reading your question leaves me unsure what you actually want to do. Some more info would be helpful!
There are some guides on unifiedjs.com. But. ASTs and compilers and parsers are complex. You’ll need to have pretty decent knowledge of programming. Be able to read code. So at this point, reading the existing plugins will get you very far, that’s what I’d really recommend, read a lot, try a lot, build different things, post your questions here.
If you want to find and replace, use https://github.com/syntax-tree/hast-util-find-and-replace. |
Beta Was this translation helpful? Give feedback.
-
Hi Titus - thanks for the response! I hope you are having a great weekend. I've got something working with a combination of remark-directive and react-remark (yeah, I'm working with React and MUI in TypeScript .tsx files) A challenge I have had with RTFM and examples to figure things out is that most of the examples are not playing well with TypeScript's typing system. Examples like those shown in remark-directive's readme are all JavaScript, as are the unit tests, so there is not much help there. I have to revert to "any" and spend time in the browser's debugger to figure out what is what. Since you guys have invested a lot of energy building out typings files, I don't think this was the intent. For example, in the function remarkInfoDirective below, I have a visitor set up for 'textDirective" and it works. The node is typed as TextDirective, although I have to put that in manually, it's not inferred. Not a big deal, but I think there might be ways of using 'textDirective' to determine the type of the node parameter A little more surprising, in the function itself when I access node.data, it's typed as TextDirectiveData (awesome!) but TextDirectiveData has no properties and extends mdast Data, which has no properties and extends UnistData, which also has no properties. In order to set hName and hChildren, I have to typecast node.data as "any", and then TypeScript is no longer helpful in determining what I can or cannot put in for hName, hChildren, etc. I have to run it and debug it to see whether it will work or not. Similarly, I can't find what type to use for the component function arguments. None of these things represent blockers to using these libraries. And I am able to do what I need to do -- being able transforming Markdown to React is slick! The process just feels a little bit more "frictional" than it perhaps needs to be. import { useSelector } from 'react-redux'
import { WorkbookState } from '../models/store'
import { Box, Typography } from '@mui/material'
import { HTMLAttributes } from 'react'
import { visit } from 'unist-util-visit';
import { Node as DastNode } from 'mdast';
import { Remark } from 'react-remark'
import RemarkDirective from 'remark-directive'
import { TextDirective } from 'mdast-util-directive'
// Register `hName`, `hProperties` types, used when turning markdown to HTML:
/// <reference types="mdast-util-to-hast" />
// Register directive nodes in mdast:
/// <reference types="mdast-util-directive" />
export function HelpPanel(props: { showHelp: (topic: string) => void }) {
let name = useSelector((state: WorkbookState) => state.navigation.appName)
let version = useSelector((state: WorkbookState) => state.navigation.appVersion)
let help = useSelector((state: WorkbookState) => state.navigation.helpText)
/**
* Replace info[name] and info[version]
* @returns
*/
function remarkInfoDirective() {
return (tree: DastNode) => {
visit(tree, 'textDirective', function (node: TextDirective) {
if (node.name !== 'info' || node.children.length === 0) return
const child = node.children[0]
if (child.type !== 'text') return
// What is the type for "data"? TextDirectiveData does not have hName or hChildren...
const data: any = node.data || (node.data = {})
let replaceWith
switch (child.value) {
case 'name':
replaceWith = name
break
case 'version':
replaceWith = version
break
default:
// if not an information item that we know about, ignore it
return
}
data.hName = 'span'
data.hChildren = [
{
type: 'text',
value: replaceWith
}
]
});
}
}
/**
* Transform HTML headers to MUI Typography and add a slug
* @param component
* @returns
*/
const rehypeTransformHeader = (component: any) => {
if (component.children && component.children.length === 1 && component.node) {
const id = component.children.toString().toLowerCase().replace(/[^\s\w]/g, '').replace(/\s/g, '-')
const name = component.node.tagName
return <Typography id={id} variant={name} {...component} />
} else {
return null
}
}
return (
<Remark
remarkPlugins={[RemarkDirective, remarkInfoDirective]}
rehypeReactOptions={{
passNode: true,
components: {
h1: rehypeTransformHeader,
h2: rehypeTransformHeader,
h3: rehypeTransformHeader,
h4: rehypeTransformHeader,
h5: rehypeTransformHeader,
h6: rehypeTransformHeader,
p: (attrs:any) => <Box {...attrs} />
}
}}
>
{help}
</Remark>
)
} |
Beta Was this translation helpful? Give feedback.
-
Hi, I am experimenting with plugins. In react-remark, I would like to update text in markup with values available in React. I know that there are options like remark-directive, but I still need to be able to write a plug-in to make it work.
While fully realizing I can just do a search/replace on the help variable, I'm trying to learn how this plugin mechanism works.
Spent the better part of the day looking at tutorials, examples, etc. and... I'm lost. I'm pretty sure I can't just replace value, but cannot find what it is I should be doing. Can somebody give me a hint as to where I'm going wrong with this?
Here's what I'm trying to do:
Here's what the plugin is receiving...
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions