fumadocs-core
Version:
The React.js library for building a documentation website
184 lines (182 loc) • 4.84 kB
JavaScript
import { generateCodeBlockTabs, parseCodeBlockAttributes } from "./codeblock-utils.js";
import { visit } from "unist-util-visit";
//#region src/mdx-plugins/remark-code-tab.ts
const Types = {
CodeBlockTabs: { convert(processor, nodes, withMdx = false, withParent = true) {
const tabs = Array.from(processTabValue(nodes).entries());
const node = generateCodeBlockTabs({
defaultValue: tabs[0][0],
triggers: tabs.map(([name]) => ({
value: name,
children: [withMdx ? mdxToAst(processor, name) : {
type: "text",
value: name
}]
})),
tabs: tabs.map(([name, codes]) => ({
value: name,
children: codes
}))
});
if (!withParent) return createFragment(node.children);
return node;
} },
Tabs: { convert(processor, nodes, withMdx = false, withParent = true) {
const tabs = Array.from(processTabValue(nodes).entries());
if (!withMdx) {
const children$1 = tabs.map(([name, codes]) => {
return {
type: "mdxJsxFlowElement",
name: "Tab",
attributes: [{
type: "mdxJsxAttribute",
name: "value",
value: name
}],
children: codes
};
});
if (!withParent) return createFragment(children$1);
return {
type: "mdxJsxFlowElement",
name: "Tabs",
attributes: [{
type: "mdxJsxAttribute",
name: "items",
value: {
type: "mdxJsxAttributeValueExpression",
value: tabs.map(([name]) => name).join(", "),
data: { estree: {
type: "Program",
sourceType: "module",
comments: [],
body: [{
type: "ExpressionStatement",
expression: {
type: "ArrayExpression",
elements: tabs.map(([name]) => ({
type: "Literal",
value: name
}))
}
}]
} }
}
}],
children: children$1
};
}
const children = [{
type: "mdxJsxFlowElement",
name: "TabsList",
attributes: [],
children: tabs.map(([name]) => ({
type: "mdxJsxFlowElement",
name: "TabsTrigger",
attributes: [{
type: "mdxJsxAttribute",
name: "value",
value: name
}],
children: [mdxToAst(processor, name)]
}))
}, ...tabs.map(([name, codes]) => ({
type: "mdxJsxFlowElement",
name: "TabsContent",
attributes: [{
type: "mdxJsxAttribute",
name: "value",
value: name
}],
children: codes
}))];
if (!withParent) return createFragment(children);
return {
type: "mdxJsxFlowElement",
name: "Tabs",
attributes: [{
type: "mdxJsxAttribute",
name: "defaultValue",
value: tabs[0][0]
}],
children
};
} }
};
function remarkCodeTab(options = {}) {
const { parseMdx = false, Tabs = "CodeBlockTabs" } = options;
return (tree) => {
const ignored = /* @__PURE__ */ new WeakSet();
visit(tree, (node) => {
if (!("children" in node) || ignored.has(node)) return "skip";
let localTabs = Tabs;
let localParseMdx = parseMdx;
let withParent = true;
if (node.type === "mdxJsxFlowElement" && node.name && node.name in Types) {
withParent = false;
localTabs = node.name;
if (node.name === "Tabs" && localParseMdx) localParseMdx = node.attributes.every((attribute) => attribute.type !== "mdxJsxAttribute" || attribute.name !== "items");
}
let start = -1;
let end = 0;
const close = () => {
if (start === -1 || start === end) return;
const replacement = Types[localTabs].convert(this, node.children.slice(start, end), localParseMdx, withParent);
ignored.add(replacement);
node.children.splice(start, end - start, replacement);
end = start;
start = -1;
};
for (; end < node.children.length; end++) {
const child = node.children[end];
if (child.type !== "code" || !child.meta) {
close();
continue;
}
const meta = parseCodeBlockAttributes(child.meta, ["tab"]);
if (!meta.attributes.tab) {
close();
continue;
}
if (start === -1) start = end;
child.meta = meta.rest;
child.data ??= {};
child.data.tab = meta.attributes.tab;
}
close();
});
};
}
function processTabValue(nodes) {
const out = /* @__PURE__ */ new Map();
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
const name = node.data?.tab ?? `Tab ${i + 1}`;
const li = out.get(name) ?? [];
li.push(node);
out.set(name, li);
}
return out;
}
/**
* MDX tab name to tab trigger node children
*/
function mdxToAst(processor, name) {
const node = processor.parse(name);
if (node.type === "root") node.children = node.children.flatMap((child) => {
if (child.type === "paragraph") return child.children;
return child;
});
return node;
}
function createFragment(children) {
return {
type: "mdxJsxFlowElement",
name: null,
attributes: [],
children
};
}
//#endregion
export { remarkCodeTab };
//# sourceMappingURL=remark-code-tab.js.map