Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@atomiks/mdx-pretty-code

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@atomiks/mdx-pretty-code - npm Package Compare versions

Comparing version 0.0.5 to 0.1.0

119

dist/mdx-pretty-code.js

@@ -367,4 +367,32 @@ import { JSDOM } from 'jsdom';

let highlighter = null;
// To make sure we only have one highlighter per theme in a process
const highlighterCache = new Map();
function getThemesFromSettings(settings) {
if (
typeof settings.theme === 'string' ||
settings.theme?.hasOwnProperty('tokenColors')
) {
return {default: settings.theme};
}
return settings.theme;
}
function highlightersFromSettings(settings) {
const themes = getThemesFromSettings(settings);
return Promise.all(
Object.keys(themes).map(async (key) => {
const theme = themes[key];
const highlighter = await shiki.getHighlighter({
...settings,
theme,
});
highlighter.themeKey = key;
return highlighter;
})
);
}
function createRemarkPlugin(options = {}) {

@@ -375,4 +403,10 @@ return () => async (tree) => {

allowedAttributes: {
code: ['style', 'data-language'],
span: ['data-color', 'data-mdx-pretty-code', 'style', 'class'],
code: ['style', 'data-language', 'data-theme'],
span: [
'data-color',
'data-mdx-pretty-code',
'data-theme',
'style',
'class',
],
},

@@ -388,12 +422,46 @@ },

if (!highlighter) {
highlighter = await shiki.getHighlighter(shikiOptions);
if (!highlighterCache.has(shikiOptions)) {
highlighterCache.set(
shikiOptions,
highlightersFromSettings(shikiOptions)
);
}
const loadedLanguages = highlighter.getLoadedLanguages();
const highlighters = await highlighterCache.get(shikiOptions);
const themes = getThemesFromSettings(shikiOptions);
visit(tree, 'inlineCode', inlineCode);
visit(tree, 'code', blockCode);
function remarkVisitor(fn) {
return (node) => {
let results;
const hasMultipleThemes = highlighters.length > 1;
const output = highlighters.map((highlighter, i) => {
const loadedLanguages = highlighter.getLoadedLanguages();
function inlineCode(node) {
const theme = themes[highlighter.themeKey];
return fn(node, {
highlighter,
theme,
loadedLanguages,
hasMultipleThemes,
});
});
// return in case of non-meta inline code
if (output.some((o) => !o)) return;
results = output.join('\n');
if (hasMultipleThemes) {
// If we don't do this the code blocks will be wrapped in <undefined>
// You can set your mdx renderer to replace this span with a React.Fragment during runtime
results = `<span data-mdx-pretty-code-fragment>${results}</span>`;
}
node.value = results;
};
}
visit(tree, 'inlineCode', remarkVisitor(inlineCode));
visit(tree, 'code', remarkVisitor(blockCode));
function inlineCode(node, {highlighter, theme}) {
const meta = node.value.match(/{:([a-zA-Z.-]+)}$/)?.[1];

@@ -406,6 +474,5 @@

node.type = 'html';
// It's a token, not a lang
if (meta[0] === '.') {
if (typeof shikiOptions.theme === 'string') {
if (typeof theme === 'string') {
throw new Error(

@@ -417,15 +484,12 @@ 'MDX Pretty Code: Must be using a JSON theme object to use tokens.'

const color =
shikiOptions.theme.tokenColors.find(({scope}) =>
theme.tokenColors.find(({scope}) =>
scope?.includes(tokensMap[meta.slice(1)] ?? meta.slice(1))
)?.settings.foreground ?? 'inherit';
node.value = sanitizeHtml(
`<span data-mdx-pretty-code data-color="${color}"><span>${node.value.replace(
/{:[a-zA-Z.-]+}/,
''
)}</span></span>`,
return sanitizeHtml(
`<span data-mdx-pretty-code data-color="${color}" data-theme="${
highlighter.themeKey
}"><span>${node.value.replace(/{:[a-zA-Z.-]+}/, '')}</span></span>`,
sanitizeOptions
);
return;
}

@@ -441,4 +505,4 @@

node.value = sanitizeHtml(
`<span data-mdx-pretty-code>${pre.innerHTML}</span>`,
return sanitizeHtml(
`<span data-mdx-pretty-code data-theme="${highlighter.themeKey}">${pre.innerHTML}</span>`,
sanitizeOptions

@@ -448,3 +512,3 @@ );

function blockCode(node) {
function blockCode(node, {highlighter, loadedLanguages}) {
const lang =

@@ -508,10 +572,7 @@ ignoreUnknownLanguage && !loadedLanguages.includes(node.lang)

dom.window.document
.querySelector('code')
.setAttribute('data-language', lang);
const code = dom.window.document.querySelector('code');
node.value = sanitizeHtml(
dom.window.document.body.innerHTML,
sanitizeOptions
);
code.setAttribute('data-language', lang);
code.setAttribute('data-theme', highlighter.themeKey);
return sanitizeHtml(dom.window.document.body.innerHTML, sanitizeOptions);
}

@@ -518,0 +579,0 @@ };

@@ -0,5 +1,7 @@

type theme = JSON | string;
export type Options = {
sanitizeOptions: any;
shikiOptions: {
theme: JSON | string;
theme: theme | Record<any, theme>;
[key: string]: any;

@@ -6,0 +8,0 @@ };

{
"name": "@atomiks/mdx-pretty-code",
"version": "0.0.5",
"version": "0.1.0",
"description": "A Remark plugin to make the code in your MDX docs simply beautiful. Powered by [Shiki](https://github.com/shikijs/shiki).",

@@ -5,0 +5,0 @@ "main": "./dist/mdx-pretty-code.cjs",

@@ -88,2 +88,82 @@ # MDX Pretty Code

## Multiple themes (dark/light mode)
Because Shiki generates themes at build time, client-side theme switching
support is not built in. There are two popular options for supporting something
like Dark Mode with Shiki. See the
[Shiki docs](https://github.com/shikijs/shiki/blob/main/docs/themes.md#dark-mode-support)
for more info.
#### 1. Load multiple themes
This will render duplicate code blocks for each theme. You can then hide the
other blocks with CSS.
Pass your themes to `shikiOptions.theme`, where the keys represent the color
mode:
```js
shikiOptions: {
theme: {
dark: JSON.parse(
fs.readFileSync(require.resolve('./themes/dark.json'), "utf-8")
),
light: JSON.parse(
fs.readFileSync(require.resolve('./themes/light.json'), "utf-8")
),
},
}
```
The `code` elements and the inline code `<span data-mdx-pretty-code>` wrappers
will have a data attribute `data-theme="[key]"`, e.g `data-theme="light"`. You
can target the data attribute `[data-theme='dark']` to apply styles for that
theme.
Now, you can use CSS to display the desired theme:
```css
@media (prefers-color-scheme: dark) {
code[data-theme='light'] {
display: none;
}
}
@media (prefers-color-scheme: light), (prefers-color-scheme: no-preference) {
code[data-theme='dark'] {
display: none;
}
}
```
#### 2. Use the "css-variables" theme (Shiki version `0.9.9` and above)
<details>
This gives you access to CSS variable styling, which you can control across Dark
and Light mode.
Note that **this client-side theme is less granular than most other supported VS
Code themes**. Also, be aware that this will generate unstyled code if you do
not define these CSS variables somewhere else on your page:
```html
<style>
:root {
--shiki-color-text: rgb(248, 248, 242);
--shiki-color-background: rgb(13 13 15);
--shiki-token-constant: rgb(102, 217, 239);
--shiki-token-string: rgb(230, 219, 116);
--shiki-token-comment: rgb(93,93, 95);
--shiki-token-keyword: rgb(249, 38, 114);
--shiki-token-parameter: rgb(230, 219, 116);
--shiki-token-function: rgb(166, 226, 46);
--shiki-token-string-expression: rgb(230, 219, 116);
--shiki-token-punctuation: rgb(230, 219, 116);
--shiki-token-link: rgb(174, 129, 255);
}
</style>
```
</details>
## API

@@ -133,3 +213,6 @@

return (
<code style={{color: props['data-color']}}>
<code
data-theme={props['data-theme']}
style={{color: props['data-color']}}
>
{props.children.props.children}

@@ -143,2 +226,3 @@ </code>

};
```

@@ -145,0 +229,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc