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:
parent
ddaec36617
commit
a95402e3be
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
32
lib/md.js
32
lib/md.js
|
@ -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, {
|
||||||
|
|
Loading…
Reference in New Issue