Core: Introduce <Markdown /> component

This commit is contained in:
Fuma Nama
2025-05-24 20:27:03 +08:00
parent 85707722dd
commit 1b999ebb75
7 changed files with 71 additions and 12 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-core': patch
---
Introduce `<Markdown />` component
+5 -1
View File
@@ -24,6 +24,10 @@
"import": "./dist/toc.js",
"types": "./dist/toc.d.ts"
},
"./content": {
"import": "./dist/content/index.js",
"types": "./dist/content/index.d.ts"
},
"./search/*": {
"import": "./dist/search/*.js",
"types": "./dist/search/*.d.ts"
@@ -96,6 +100,7 @@
"react-remove-scroll": "^2.6.3",
"remark": "^15.0.0",
"remark-gfm": "^4.0.1",
"remark-rehype": "^11.1.2",
"scroll-into-view-if-needed": "^3.1.0",
"shiki": "^3.4.2",
"unist-util-visit": "^5.0.0"
@@ -118,7 +123,6 @@
"next": "^15.3.2",
"react-router": "^7.6.0",
"remark-mdx": "^3.1.0",
"remark-rehype": "^11.1.2",
"tsconfig": "workspace:*",
"typescript": "^5.8.3",
"unified": "^11.0.5",
+48
View File
@@ -0,0 +1,48 @@
import { remark } from 'remark';
import remarkGfm from 'remark-gfm';
import remarkRehype from 'remark-rehype';
import type { VFile } from 'vfile';
import { type Components, toJsxRuntime } from 'hast-util-to-jsx-runtime';
import type { Root } from 'hast';
import * as JsxRuntime from 'react/jsx-runtime';
import type { PluggableList, Processor } from 'unified';
import type { ReactNode } from 'react';
function rehypeReact(
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- processor errors
this: Processor<any, any, any, any>,
options: MarkdownProps = {},
) {
this.compiler = (tree, file) => {
return toJsxRuntime(tree as Root, {
development: false,
filePath: file.path,
...JsxRuntime,
...options,
});
};
}
interface MarkdownProps {
components?: Components;
}
export async function Markdown({
children: content,
remarkPlugins = [],
rehypePlugins = [],
...options
}: MarkdownProps & {
remarkPlugins?: PluggableList;
rehypePlugins?: PluggableList;
children: string | VFile;
}) {
const processor = remark()
.use(remarkGfm)
.use(remarkPlugins)
.use(remarkRehype)
.use(rehypePlugins)
.use(rehypeReact, options);
return (await processor.process(content)).result as ReactNode;
}
+3 -5
View File
@@ -23,11 +23,9 @@ let jsEngine: Promise<RegexEngine> | undefined;
function getHighlightOptions(from: HighlightOptions): HighlightOptions {
if (from.engine) return from;
if (!jsEngine) {
jsEngine = import('shiki/engine/javascript').then((res) =>
res.createJavaScriptRegexEngine(),
);
}
jsEngine ??= import('shiki/engine/javascript').then((res) =>
res.createJavaScriptRegexEngine(),
);
return {
...from,
+1 -1
View File
@@ -15,7 +15,7 @@ export default defineConfig({
format: 'esm',
entry: [
'src/{toc,link,breadcrumb,sidebar,dynamic-link}.tsx',
'src/{server,source,mdx-plugins}/index.ts',
'src/{server,source,mdx-plugins,content}/index.ts',
'src/search/client.ts',
'src/search/server.ts',
'src/search/algolia.ts',
+6 -2
View File
@@ -1,12 +1,16 @@
import type { BuildPageTreeOptions } from 'fumadocs-core/source';
import type { FileSystem } from 'fumadocs-core/source';
import { MethodLabel } from '@/ui/components/method-label';
import type { PageTree } from 'fumadocs-core/server';
/**
* Source API Integration
*
* Add this to page tree builder options
*/
export const attachFile: BuildPageTreeOptions['attachFile'] = (node, file) => {
export const attachFile = (
node: PageTree.Item,
file: FileSystem.PageFile | undefined,
): PageTree.Item => {
if (!file) return node;
const data = file.data.data as object;
let method: string | undefined;
+3 -3
View File
@@ -738,6 +738,9 @@ importers:
remark-gfm:
specifier: ^4.0.1
version: 4.0.1
remark-rehype:
specifier: ^11.1.2
version: 11.1.2
scroll-into-view-if-needed:
specifier: ^3.1.0
version: 3.1.0
@@ -799,9 +802,6 @@ importers:
remark-mdx:
specifier: ^3.1.0
version: 3.1.0
remark-rehype:
specifier: ^11.1.2
version: 11.1.2
tsconfig:
specifier: workspace:*
version: link:../tsconfig