diff options
-rw-r--r-- | .changeset/nine-geckos-act.md | 5 | ||||
-rw-r--r-- | packages/astro/components/Code.astro | 67 | ||||
-rw-r--r-- | packages/astro/test/astro-component-code.test.js | 10 | ||||
-rw-r--r-- | packages/astro/test/fixtures/astro-component-code/src/pages/inline.astro | 10 |
4 files changed, 71 insertions, 21 deletions
diff --git a/.changeset/nine-geckos-act.md b/.changeset/nine-geckos-act.md new file mode 100644 index 000000000..164dbbfd5 --- /dev/null +++ b/.changeset/nine-geckos-act.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Support `<Code inline />` to output inline code HTML (no `pre` tag) diff --git a/packages/astro/components/Code.astro b/packages/astro/components/Code.astro index 0c5f946af..40f99bcd1 100644 --- a/packages/astro/components/Code.astro +++ b/packages/astro/components/Code.astro @@ -1,5 +1,6 @@ --- import type * as shiki from 'shiki'; +import { renderToHtml } from 'shiki'; import { getHighlighter } from './Shiki.js'; export interface Props { @@ -30,36 +31,60 @@ export interface Props { * @default false */ wrap?: boolean | null; + /** + * Generate inline code element only, without the pre element wrapper. + * + * @default false + */ + inline?: boolean; } -const { code, lang = 'plaintext', theme = 'github-dark', wrap = false } = Astro.props; - -/** Replace the shiki class name with a custom astro class name. */ -function repairShikiTheme(html: string): string { - // Replace "shiki" class naming with "astro" - html = html.replace(/<pre class="(.*?)shiki(.*?)"/, '<pre class="$1astro-code$2"'); - // Handle code wrapping - // if wrap=null, do nothing. - if (wrap === false) { - html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"'); - } else if (wrap === true) { - html = html.replace( - /style="(.*?)"/, - 'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"' - ); - } - return html; -} +const { + code, + lang = 'plaintext', + theme = 'github-dark', + wrap = false, + inline = false, +} = Astro.props; +// 1. Get the shiki syntax highlighter const highlighter = await getHighlighter({ theme, // Load custom lang if passed an object, otherwise load the default langs: typeof lang !== 'string' ? [lang] : undefined, }); -const _html = highlighter.codeToHtml(code, { - lang: typeof lang === 'string' ? lang : lang.id, + +// 2. Turn code into shiki theme tokens +const tokens = highlighter.codeToThemedTokens(code, typeof lang === 'string' ? lang : lang.id); + +// 3. Get shiki theme object +const _theme = highlighter.getTheme(); + +// 4. Render the theme tokens as html +const html = renderToHtml(tokens, { + themeName: _theme.name, + fg: _theme.fg, + bg: _theme.bg, + elements: { + pre({ className, style, children }) { + // Swap to `code` tag if inline + const tag = inline ? 'code' : 'pre'; + // Replace "shiki" class naming with "astro-code" + className = className.replace(/shiki/g, 'astro-code'); + // Handle code wrapping + // if wrap=null, do nothing. + if (wrap === false) { + style += '; overflow-x: auto;"'; + } else if (wrap === true) { + style += '; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'; + } + return `<${tag} class="${className}" style="${style}" tabindex="0">${children}</${tag}>`; + }, + code({ children }) { + return inline ? children : `<code>${children}</code>`; + }, + }, }); -const html = repairShikiTheme(_html); --- <Fragment set:html={html} /> diff --git a/packages/astro/test/astro-component-code.test.js b/packages/astro/test/astro-component-code.test.js index e721f9498..6a525f58d 100644 --- a/packages/astro/test/astro-component-code.test.js +++ b/packages/astro/test/astro-component-code.test.js @@ -100,4 +100,14 @@ describe('<Code>', () => { expect($('#lang > pre')).to.have.lengthOf(1); expect($('#lang > pre > code span').length).to.equal(3); }); + + it('<Code inline> has no pre tag', async () => { + let html = await fixture.readFile('/inline/index.html'); + const $ = cheerio.load(html); + const codeEl = $('.astro-code'); + + expect(codeEl.prop('tagName')).to.eq('CODE'); + expect(codeEl.attr('style')).to.include('background-color:'); + expect($('pre')).to.have.lengthOf(0); + }); }); diff --git a/packages/astro/test/fixtures/astro-component-code/src/pages/inline.astro b/packages/astro/test/fixtures/astro-component-code/src/pages/inline.astro new file mode 100644 index 000000000..05422c8bf --- /dev/null +++ b/packages/astro/test/fixtures/astro-component-code/src/pages/inline.astro @@ -0,0 +1,10 @@ +--- +import {Code} from 'astro/components'; +--- +<html> +<head><title>Code component</title></head> +<body> + Simple: + <Code code="console.log('inline code');" lang="js" inline /> +</body> +</html> |