From 26d6255ed2ef65346eff65b5a5a327206616e5c5 Mon Sep 17 00:00:00 2001 From: Divyansh Singh <40380293+brc-dd@users.noreply.github.com> Date: Sat, 19 Apr 2025 18:16:48 +0530 Subject: [PATCH] keep it easier to revert to older behavior and add heading level to wrapper --- src/node/markdown/markdown.ts | 96 +++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index 8e92874f..35564771 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -122,7 +122,12 @@ export interface MarkdownOptions extends Options { * Options for `markdown-it-anchor` * @see https://github.com/valeriangalliat/markdown-it-anchor */ - anchor?: anchorPlugin.AnchorOptions + anchor?: Omit & { + permalink?: + | anchorPlugin.PermalinkGenerator + | anchorPlugin.LinkAfterHeaderPermalinkOptions + | 'legacy' + } /** * Options for `markdown-it-attrs` * @see https://github.com/arve0/markdown-it-attrs @@ -267,21 +272,90 @@ export async function createMarkdownRenderer( } md.use(emojiPlugin, { ...options.emoji }) + const { permalink, ...anchorOptions } = options.anchor ?? {} + + const linkAfterHeader = anchorPlugin.permalink.linkAfterHeader({ + assistiveText: (title) => `Permalink to “${title.trim()}”`, + visuallyHiddenClass: 'visually-hidden', + ...(typeof permalink === 'object' ? permalink : {}) + }) + + const linkInsideHeader = anchorPlugin.permalink.linkInsideHeader({ + symbol: '​' + }) + + const permalinkV2: anchorPlugin.PermalinkGenerator = ( + slug, + opts, + state, + idx + ) => { + state.tokens.splice( + idx, + 0, + Object.assign(new state.Token('div_open', 'div', 1), { + attrs: [['class', `header-wrapper ${state.tokens[idx].tag}`]], + block: true + }) + ) + + state.tokens.splice( + idx + 4, + 0, + Object.assign(new state.Token('div_close', 'div', -1), { + block: true + }) + ) + + linkAfterHeader(slug, opts, state, idx + 1) + } + + const permalinkV1: anchorPlugin.PermalinkGenerator = ( + slug, + opts, + state, + idx + ) => { + const title = + state.tokens[idx + 1]?.children + ?.reduce( + (acc, t) => + t.type === 'text' || t.type === 'code_inline' + ? acc + t.content + : acc, + '' + ) + .trim() || '' + + linkInsideHeader(slug, opts, state, idx) + + state.tokens[idx + 1].children + ?.find( + (t) => + t.type === 'link_open' && + t + .attrGet('class') + ?.split(' ') + .includes(opts.class || 'header-anchor') + ) + ?.attrPush(['aria-label', `Permalink to “${title}”`]) + } + // mdit-vue plugins md.use(anchorPlugin, { slugify, - getTokensText: (tokens) => { - return tokens + getTokensText: (tokens) => + tokens .filter((t) => !['html_inline', 'emoji'].includes(t.type)) .map((t) => t.content) - .join('') - }, - permalink: anchorPlugin.permalink.linkAfterHeader({ - assistiveText: (title) => `Permalink to “${title.trim()}”`, - visuallyHiddenClass: 'visually-hidden', - wrapper: ['
', '
'] - }), - ...options.anchor + .join(''), + permalink: + typeof permalink === 'function' + ? permalink + : permalink === 'legacy' + ? permalinkV1 + : permalinkV2, + ...anchorOptions } as anchorPlugin.AnchorOptions).use(frontmatterPlugin, { ...options.frontmatter } as FrontmatterPluginOptions)