@@ -25,6 +25,7 @@ import attrsPlugin from 'markdown-it-attrs'
2525import { full as emojiPlugin } from 'markdown-it-emoji'
2626import type { BuiltinLanguage , BuiltinTheme , Highlighter } from 'shiki'
2727import type { Logger } from 'vite'
28+ import type { Awaitable } from '../shared'
2829import { containerPlugin , type ContainerOptions } from './plugins/containers'
2930import { gitHubAlertsPlugin } from './plugins/githubAlerts'
3031import { highlight as createHighlighter } from './plugins/highlight'
@@ -52,11 +53,11 @@ export interface MarkdownOptions extends Options {
5253 /**
5354 * Setup markdown-it instance before applying plugins
5455 */
55- preConfig ?: ( md : MarkdownItAsync ) => Awaited < void >
56+ preConfig ?: ( md : MarkdownItAsync ) => Awaitable < void >
5657 /**
5758 * Setup markdown-it instance
5859 */
59- config ?: ( md : MarkdownItAsync ) => Awaited < void >
60+ config ?: ( md : MarkdownItAsync ) => Awaitable < void >
6061 /**
6162 * Disable cache (experimental)
6263 */
@@ -245,8 +246,13 @@ export async function createMarkdownRenderer(
245246 )
246247 . use ( lineNumberPlugin , options . lineNumbers )
247248
249+ const tableOpen = md . renderer . rules . table_open
248250 md . renderer . rules . table_open = function ( tokens , idx , options , env , self ) {
249- return '<table tabindex="0">\n'
251+ const token = tokens [ idx ]
252+ if ( token . attrIndex ( 'tabindex' ) < 0 ) token . attrPush ( [ 'tabindex' , '0' ] )
253+ return tableOpen
254+ ? tableOpen ( tokens , idx , options , env , self )
255+ : self . renderToken ( tokens , idx , options )
250256 }
251257
252258 if ( options . gfmAlerts !== false ) {
@@ -268,22 +274,31 @@ export async function createMarkdownRenderer(
268274 . map ( ( t ) => t . content )
269275 . join ( '' )
270276 } ,
271- permalink : anchorPlugin . permalink . linkInsideHeader ( {
272- symbol : '​' ,
273- renderAttrs : ( slug , state ) => {
274- // Find `heading_open` with the id identical to slug
275- const idx = state . tokens . findIndex ( ( token ) => {
276- const attrs = token . attrs
277- const id = attrs ?. find ( ( attr ) => attr [ 0 ] === 'id' )
278- return id && slug === id [ 1 ]
279- } )
280- // Get the actual heading content
281- const title = state . tokens [ idx + 1 ] . content
282- return {
283- 'aria-label' : `Permalink to "${ title } "`
284- }
285- }
286- } ) ,
277+ permalink : ( slug , _ , state , idx ) => {
278+ const title =
279+ state . tokens [ idx + 1 ] ?. children
280+ ?. filter ( ( token ) => [ 'text' , 'code_inline' ] . includes ( token . type ) )
281+ . reduce ( ( acc , t ) => acc + t . content , '' )
282+ . trim ( ) || ''
283+
284+ const linkTokens = [
285+ Object . assign ( new state . Token ( 'text' , '' , 0 ) , { content : ' ' } ) ,
286+ Object . assign ( new state . Token ( 'link_open' , 'a' , 1 ) , {
287+ attrs : [
288+ [ 'class' , 'header-anchor' ] ,
289+ [ 'href' , `#${ slug } ` ] ,
290+ [ 'aria-label' , `Permalink to “${ title } ”` ]
291+ ]
292+ } ) ,
293+ Object . assign ( new state . Token ( 'html_inline' , '' , 0 ) , {
294+ content : '​' ,
295+ meta : { isPermalinkSymbol : true }
296+ } ) ,
297+ new state . Token ( 'link_close' , 'a' , - 1 )
298+ ]
299+
300+ state . tokens [ idx + 1 ] . children ?. push ( ...linkTokens )
301+ } ,
287302 ...options . anchor
288303 } as anchorPlugin . AnchorOptions ) . use ( frontmatterPlugin , {
289304 ...options . frontmatter
0 commit comments