Added support for <sub> <sup> in markdown (#1215)

* Add support for sub and superscript in markdown

* Removed empty line as per lint

* renamed schema to rehypeSanitizeSchema to make it less generic

* Linting fixes

* Update components/text.js

Co-authored-by: ekzyis <ek@stacker.news>

* Reverting changes: remove rehype-raw&sanitize, clean up

* Draft iteration of rehypeStyler plugin

* rehypeStyler visiting element nodes properly to catch tag-text-tag patterns

* Refreshed package-lock

---------

Co-authored-by: ekzyis <ek@stacker.news>
This commit is contained in:
nichro 2024-06-25 15:23:18 -04:00 committed by GitHub
parent ddaec36617
commit a95402e3be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 2 deletions

View File

@ -15,7 +15,7 @@ import copy from 'clipboard-copy'
import ZoomableImage, { decodeOriginalUrl } from './image' import ZoomableImage, { decodeOriginalUrl } from './image'
import { IMGPROXY_URL_REGEXP, parseInternalLinks, parseEmbedUrl } from '@/lib/url' import { IMGPROXY_URL_REGEXP, parseInternalLinks, parseEmbedUrl } from '@/lib/url'
import reactStringReplace from 'react-string-replace' import reactStringReplace from 'react-string-replace'
import { rehypeInlineCodeProperty } from '@/lib/md' import { rehypeInlineCodeProperty, rehypeSubscript, rehypeSuperscript } from '@/lib/md'
import { Button } from 'react-bootstrap' import { Button } from 'react-bootstrap'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Link from 'next/link' import Link from 'next/link'
@ -313,7 +313,7 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
img: Img img: Img
}} }}
remarkPlugins={[gfm, mention, sub]} remarkPlugins={[gfm, mention, sub]}
rehypePlugins={[rehypeInlineCodeProperty]} rehypePlugins={[rehypeInlineCodeProperty, rehypeSuperscript, rehypeSubscript]}
> >
{children} {children}
</ReactMarkdown> </ReactMarkdown>

View File

@ -252,3 +252,15 @@ img.fullScreen {
top: 0; top: 0;
left: 0; left: 0;
} }
/* Utility classes used in rehype plugins in md.js */
.subscript {
vertical-align: sub;
font-size: smaller;
}
.superscript {
vertical-align: super;
font-size: smaller;
}

View File

@ -2,6 +2,7 @@ import { gfmFromMarkdown } from 'mdast-util-gfm'
import { visit } from 'unist-util-visit' import { visit } from 'unist-util-visit'
import { gfm } from 'micromark-extension-gfm' import { gfm } from 'micromark-extension-gfm'
import { fromMarkdown } from 'mdast-util-from-markdown' import { fromMarkdown } from 'mdast-util-from-markdown'
import { superscript, subscript } from '../components/text.module.css'
export function mdHas (md, test) { export function mdHas (md, test) {
if (!md) return [] if (!md) return []
@ -31,6 +32,37 @@ export function rehypeInlineCodeProperty () {
} }
} }
function rehypeStyler (startTag, endTag, className) {
return function (tree) {
visit(tree, 'element', (node) => {
for (let i = 0; i < node.children.length; i += 1) {
const start = node.children[i]
const text = node.children[i + 1]
const end = node.children[i + 2]
// is this a children slice wrapped with the tags we're looking for?
const isWrapped =
start?.type === 'raw' && start?.value === startTag &&
text?.type === 'text' &&
end?.type === 'raw' && end?.value === endTag
if (!isWrapped) continue
const newChildren = {
type: 'element',
tagName: 'span',
properties: { className: [className] },
children: [{ type: 'text', value: text.value }]
}
node.children.splice(i, 3, newChildren)
}
})
}
}
// Explicitely defined start/end tags & which CSS class from text.module.css to apply
export const rehypeSuperscript = () => rehypeStyler('<sup>', '</sup>', superscript)
export const rehypeSubscript = () => rehypeStyler('<sub>', '</sub>', subscript)
export function extractUrls (md) { export function extractUrls (md) {
if (!md) return [] if (!md) return []
const tree = fromMarkdown(md, { const tree = fromMarkdown(md, {