@mintlify/common
Version:
Commonly shared code within Mintlify
79 lines (78 loc) • 2.86 kB
JavaScript
import { visit } from 'unist-util-visit';
const KEYBOARD_SYMBOL_RANGES = [
[0x2318, 0x2319], // ⌘⌙ (Command/Apple key)
[0x2325, 0x2326], // ⌥⌦ (Option/Alt key)
[0x2303, 0x2303], // ⌃ (Control key)
[0x21e7, 0x21e7], // ⇧ (Shift key)
[0x232b, 0x232c], // ⌫⌬ (Backspace/Delete keys)
[0x21a9, 0x21a9], // ↩ (Return key)
[0x21b5, 0x21b5], // ↵ (Enter key)
[0x2380, 0x2380], // ⌀ (Null key)
[0x2387, 0x238a], // ⌧⌨〈〉 (Clear, Keyboard, Left/Right angle brackets)
[0x21e4, 0x21e5], // ⇤⇥ (Tab keys)
];
const isKeyboardSymbol = (char) => {
const code = char.codePointAt(0);
if (code === undefined)
return false;
return KEYBOARD_SYMBOL_RANGES.some((range) => {
const [start, end] = range;
return start !== undefined && end !== undefined && code >= start && code <= end;
});
};
const containsKeyboardSymbols = (text) => {
const trimmed = text.trim();
if (trimmed.length === 0)
return false;
for (const char of trimmed) {
if (isKeyboardSymbol(char)) {
return true;
}
}
return false;
};
const extractTextFromChildren = (children) => {
let text = '';
for (const child of children) {
if (child && typeof child === 'object' && 'type' in child) {
if (child.type === 'text' && 'value' in child) {
text += child.value;
}
else if (child.type === 'element' || child.type === 'mdxJsxTextElement') {
if ('children' in child && Array.isArray(child.children)) {
text += extractTextFromChildren(child.children);
}
}
}
}
return text;
};
export const rehypeKeyboardSymbols = () => (tree) => {
visit(tree, 'element', (node, _, parent) => {
if (node.tagName !== 'code')
return;
if (parent && parent.type === 'element' && parent.tagName === 'pre')
return;
const text = extractTextFromChildren(node.children);
if (containsKeyboardSymbols(text)) {
node.properties['data-symbols'] = 'true';
}
});
visit(tree, 'mdxJsxTextElement', (node, _, parent) => {
if (node.name !== 'code')
return;
if (parent && parent.type === 'element' && parent.tagName === 'pre')
return;
const text = extractTextFromChildren(node.children);
if (containsKeyboardSymbols(text)) {
const existingAttr = node.attributes.find((attr) => attr.type === 'mdxJsxAttribute' && attr.name === 'data-symbols');
if (!existingAttr) {
node.attributes.push({
type: 'mdxJsxAttribute',
name: 'data-symbols',
value: 'true',
});
}
}
});
};