fumadocs-core 16.8.7 → 16.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { use } from "react";
1
+ import { use, useMemo } from "react";
2
2
  import * as JsxRuntime from "react/jsx-runtime";
3
3
  import { remark } from "remark";
4
4
  import remarkRehype from "remark-rehype";
@@ -7,7 +7,6 @@ import { toJsxRuntime } from "hast-util-to-jsx-runtime";
7
7
  //#region src/content/md.ts
8
8
  function createMarkdownRenderer({ rehypePlugins = [], remarkPlugins = [], remarkRehypeOptions } = {}) {
9
9
  const processor = remark().use(remarkPlugins).use(remarkRehype, remarkRehypeOptions).use(rehypePlugins);
10
- const cache = {};
11
10
  const promises = {};
12
11
  function render(tree, file, props) {
13
12
  return toJsxRuntime(tree, {
@@ -17,24 +16,23 @@ function createMarkdownRenderer({ rehypePlugins = [], remarkPlugins = [], remark
17
16
  ...JsxRuntime
18
17
  });
19
18
  }
20
- function parse(file, _props) {
19
+ function parse(file) {
21
20
  return processor.parse(file);
22
21
  }
23
22
  return {
24
23
  Markdown(props) {
25
24
  const { async = false, children } = props;
26
25
  const file = new VFile(children);
27
- const key = String(file.value);
26
+ const id = `${file.path}:${file.value}`;
28
27
  if (async) {
29
- promises[key] ??= processor.run(parse(file, props), file);
30
- return render(use(promises[key]), file, props);
28
+ promises[id] ??= processor.run(parse(file), file);
29
+ return render(use(promises[id]), file, props);
31
30
  }
32
- cache[key] ??= processor.runSync(parse(file, props), file);
33
- return render(cache[key], file, props);
31
+ return render(useMemo(() => processor.runSync(parse(file), file), [id]), file, props);
34
32
  },
35
33
  async MarkdownServer(props) {
36
34
  const file = new VFile(props.children);
37
- return render(await processor.run(parse(file, props), file), file, props);
35
+ return render(await processor.run(parse(file), file), file, props);
38
36
  }
39
37
  };
40
38
  }
@@ -2,7 +2,7 @@ import { t as RehypeCodeOptions } from "../../rehype-code-DXCf4vCa.js";
2
2
  import { t as RemarkImageOptions } from "../../remark-image-B8S2Lk0J.js";
3
3
  import { r as StructureOptions } from "../../remark-structure-C2-K9_ko.js";
4
4
  import { t as RemarkHeadingOptions } from "../../remark-heading-BkmtL7mJ.js";
5
- import { t as RemarkCodeTabOptions } from "../../remark-code-tab-B8g4pbaL.js";
5
+ import { t as RemarkCodeTabOptions } from "../../remark-code-tab-Ct56s_uQ.js";
6
6
  import { t as RemarkNpmOptions } from "../../remark-npm-BZsXR24w.js";
7
7
  import { t as ResolvePlugins } from "../../util-D7vTp-Ia.js";
8
8
  import { Pluggable } from "unified";
@@ -2,7 +2,7 @@ import { t as RehypeCodeOptions } from "../../rehype-code-DXCf4vCa.js";
2
2
  import { t as RemarkImageOptions } from "../../remark-image-B8S2Lk0J.js";
3
3
  import { r as StructureOptions } from "../../remark-structure-C2-K9_ko.js";
4
4
  import { t as RemarkHeadingOptions } from "../../remark-heading-BkmtL7mJ.js";
5
- import { t as RemarkCodeTabOptions } from "../../remark-code-tab-B8g4pbaL.js";
5
+ import { t as RemarkCodeTabOptions } from "../../remark-code-tab-Ct56s_uQ.js";
6
6
  import { t as RemarkNpmOptions } from "../../remark-npm-BZsXR24w.js";
7
7
  import { t as ResolvePlugins } from "../../util-D7vTp-Ia.js";
8
8
  import { ProcessorOptions } from "@mdx-js/mdx";
@@ -18,8 +18,8 @@ interface LinkProps extends ComponentProps<'a'> {
18
18
  prefetch?: boolean;
19
19
  }
20
20
  interface Router {
21
- push: (url: string) => void;
22
- refresh: () => void;
21
+ push: (url: string) => void | Promise<void>;
22
+ refresh: () => void | Promise<void>;
23
23
  }
24
24
  interface Framework {
25
25
  usePathname: () => string;
@@ -1,13 +1,12 @@
1
1
  "use client";
2
2
  import { FrameworkProvider } from "./index.js";
3
- import { useMemo } from "react";
3
+ import { useMemo, useRef } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { Link, useRouter } from "waku";
6
6
  //#region src/framework/waku.tsx
7
7
  const framework = {
8
8
  usePathname() {
9
- const { path } = useRouter();
10
- return path;
9
+ return useRouter().path;
11
10
  },
12
11
  useParams() {
13
12
  const { query } = useRouter();
@@ -18,14 +17,16 @@ const framework = {
18
17
  },
19
18
  useRouter() {
20
19
  const router = useRouter();
20
+ const routerRef = useRef(router);
21
+ routerRef.current = router;
21
22
  return useMemo(() => ({
22
23
  push(url) {
23
- router.push(url);
24
+ return routerRef.current.push(url);
24
25
  },
25
26
  refresh() {
26
- router.push(router.path);
27
+ return routerRef.current.reload();
27
28
  }
28
- }), [router]);
29
+ }), []);
29
30
  },
30
31
  Link({ href, prefetch = true, ...props }) {
31
32
  return /* @__PURE__ */ jsx(Link, {
@@ -1,6 +1,6 @@
1
1
  import { t as getNegotiator } from "../negotiation-CvOwibYZ.js";
2
2
  import { NextResponse } from "next/server.js";
3
- //#region ../../node_modules/.pnpm/@formatjs+fast-memoize@3.1.3/node_modules/@formatjs/fast-memoize/index.js
3
+ //#region ../../node_modules/.pnpm/@formatjs+fast-memoize@3.1.4/node_modules/@formatjs/fast-memoize/index.js
4
4
  function memoize(fn, options) {
5
5
  const cache = options && options.cache ? options.cache : cacheDefault;
6
6
  const serializer = options && options.serializer ? options.serializer : serializerDefault;
@@ -56,7 +56,7 @@ const cacheDefault = { create: function create() {
56
56
  return new ObjectWithoutPrototypeCache();
57
57
  } };
58
58
  //#endregion
59
- //#region ../../node_modules/.pnpm/@formatjs+intl-localematcher@0.8.5/node_modules/@formatjs/intl-localematcher/index.js
59
+ //#region ../../node_modules/.pnpm/@formatjs+intl-localematcher@0.8.6/node_modules/@formatjs/intl-localematcher/index.js
60
60
  /**
61
61
  * http://ecma-international.org/ecma-402/7.0/index.html#sec-canonicalizelocalelist
62
62
  * @param locales
@@ -48,20 +48,18 @@ function generateCodeBlockTabs({ persist = false, defaultValue, triggers, tabs,
48
48
  children
49
49
  };
50
50
  }
51
+ const AttributeRegex = /(?<=^|\s)(?<name>[a-zA-Z0-9_-]+)(?:=(?:"([^"]*)"|'([^']*)'))?/g;
51
52
  /**
52
53
  * Parse Fumadocs-style code block attributes from meta string, like `title="hello world"`
53
54
  */
54
55
  function parseCodeBlockAttributes(meta, allowedNames) {
55
- let str = meta;
56
- const StringRegex = /(?<=^|\s)(?<name>\w+)(?:=(?:"([^"]*)"|'([^']*)'))?/g;
57
56
  const attributes = {};
58
- str = str.replaceAll(StringRegex, (match, name, value_1, value_2) => {
59
- if (allowedNames && !allowedNames.includes(name)) return match;
60
- attributes[name] = value_1 ?? value_2 ?? null;
61
- return "";
62
- });
63
57
  return {
64
- rest: str,
58
+ rest: meta.replaceAll(AttributeRegex, (match, name, value_1, value_2) => {
59
+ if (allowedNames && !allowedNames.includes(name)) return match;
60
+ attributes[name] = value_1 ?? value_2 ?? null;
61
+ return "";
62
+ }),
65
63
  attributes
66
64
  };
67
65
  }
@@ -7,7 +7,7 @@ import { n as remarkHeading, t as RemarkHeadingOptions } from "../remark-heading
7
7
  import { n as remarkAdmonition, t as RemarkAdmonitionOptions } from "../remark-admonition-Do12F5_K.js";
8
8
  import { n as remarkDirectiveAdmonition, t as RemarkDirectiveAdmonitionOptions } from "../remark-directive-admonition-WTw742i0.js";
9
9
  import { n as RehypeTocOptions, r as rehypeToc, t as RehypeTOCItemType } from "../rehype-toc-D5_U8iEU.js";
10
- import { n as remarkCodeTab, t as RemarkCodeTabOptions } from "../remark-code-tab-B8g4pbaL.js";
10
+ import { n as remarkCodeTab, t as RemarkCodeTabOptions } from "../remark-code-tab-Ct56s_uQ.js";
11
11
  import { n as remarkSteps, t as RemarkStepsOptions } from "../remark-steps-BcG9tJSi.js";
12
12
  import { n as remarkNpm, t as RemarkNpmOptions } from "../remark-npm-BZsXR24w.js";
13
13
  import { i as parseCodeBlockAttributes, n as CodeBlockTabsOptions, r as generateCodeBlockTabs, t as CodeBlockAttributes } from "../codeblock-utils-BFx9G8T-.js";
@@ -1,2 +1,2 @@
1
- import { n as remarkCodeTab, t as RemarkCodeTabOptions } from "../remark-code-tab-B8g4pbaL.js";
1
+ import { n as remarkCodeTab, t as RemarkCodeTabOptions } from "../remark-code-tab-Ct56s_uQ.js";
2
2
  export { RemarkCodeTabOptions, remarkCodeTab };
@@ -3,21 +3,32 @@ import { visit } from "unist-util-visit";
3
3
  //#region src/mdx-plugins/remark-code-tab.ts
4
4
  const Types = {
5
5
  CodeBlockTabs(processor, nodes, withMdx, withParent) {
6
- const tabs = Array.from(processTabValue(nodes).entries());
7
- const node = generateCodeBlockTabs({
8
- defaultValue: tabs[0][0],
9
- triggers: tabs.map(([name]) => ({
10
- value: name,
11
- children: [withMdx ? mdxToAst(processor, name) : {
6
+ const tabs = processTabValue(nodes);
7
+ let isFirstTab = true;
8
+ const options = {
9
+ triggers: [],
10
+ tabs: []
11
+ };
12
+ for (const [value, list] of tabs) {
13
+ if (isFirstTab) {
14
+ const tagGroup = list[0].data?.tabGroup;
15
+ options.defaultValue = value;
16
+ if (tagGroup) options.persist = { id: tagGroup };
17
+ isFirstTab = false;
18
+ }
19
+ options.triggers.push({
20
+ value,
21
+ children: withMdx ? mdxToAst(processor, value).children : [{
12
22
  type: "text",
13
- value: name
23
+ value
14
24
  }]
15
- })),
16
- tabs: tabs.map(([name, codes]) => ({
17
- value: name,
18
- children: codes
19
- }))
20
- });
25
+ });
26
+ options.tabs.push({
27
+ value,
28
+ children: list
29
+ });
30
+ }
31
+ const node = generateCodeBlockTabs(options);
21
32
  if (!withParent) return node.children;
22
33
  return [node];
23
34
  },
@@ -135,7 +146,7 @@ function remarkCodeTab(options = {}) {
135
146
  close();
136
147
  continue;
137
148
  }
138
- const meta = parseCodeBlockAttributes(child.meta, ["tab"]);
149
+ const meta = parseCodeBlockAttributes(child.meta, ["tab", "tab-group"]);
139
150
  if (!meta.attributes.tab) {
140
151
  close();
141
152
  continue;
@@ -144,6 +155,7 @@ function remarkCodeTab(options = {}) {
144
155
  child.meta = meta.rest;
145
156
  child.data ??= {};
146
157
  child.data.tab = meta.attributes.tab;
158
+ if (meta.attributes["tab-group"]) child.data.tabGroup = meta.attributes["tab-group"];
147
159
  }
148
160
  close();
149
161
  });
@@ -154,9 +166,12 @@ function processTabValue(nodes) {
154
166
  for (let i = 0; i < nodes.length; i++) {
155
167
  const node = nodes[i];
156
168
  const name = node.data?.tab ?? `Tab ${i + 1}`;
157
- const li = out.get(name) ?? [];
169
+ let li = out.get(name);
170
+ if (!li) {
171
+ li = [];
172
+ out.set(name, li);
173
+ }
158
174
  li.push(node);
159
- out.set(name, li);
160
175
  }
161
176
  return out;
162
177
  }
@@ -165,7 +180,7 @@ function processTabValue(nodes) {
165
180
  */
166
181
  function mdxToAst(processor, name) {
167
182
  const node = processor.parse(name);
168
- if (node.type === "root") node.children = node.children.flatMap((child) => {
183
+ node.children = node.children.flatMap((child) => {
169
184
  if (child.type === "paragraph") return child.children;
170
185
  return child;
171
186
  });
@@ -18,6 +18,10 @@ declare module 'mdast' {
18
18
  * [Fumadocs: remark-code-tab] the associated tab value
19
19
  */
20
20
  tab?: string;
21
+ /**
22
+ * [Fumadocs: remark-code-tab] the associated tab group ID
23
+ */
24
+ tabGroup?: string;
21
25
  }
22
26
  interface Data {
23
27
  /**
@@ -1,5 +1,5 @@
1
1
  import { t as __commonJSMin } from "./chunk-CYJPkc-J.js";
2
- //#region ../../node_modules/.pnpm/remove-markdown@0.6.3/node_modules/remove-markdown/index.js
2
+ //#region ../../node_modules/.pnpm/remove-markdown@0.6.4/node_modules/remove-markdown/index.js
3
3
  var require_remove_markdown = /* @__PURE__ */ __commonJSMin(((exports, module) => {
4
4
  module.exports = function(md, options) {
5
5
  options = options || {};
@@ -25,7 +25,7 @@ var require_remove_markdown = /* @__PURE__ */ __commonJSMin(((exports, module) =
25
25
  htmlReplaceRegex = new RegExp(`<(?!\/?(${joinedHtmlTagsToSkip})(?=>|\s[^>]*>))[^>]*>`, "g");
26
26
  }
27
27
  if (options.separateLinksAndTexts) output = output.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1" + options.separateLinksAndTexts + "$2");
28
- output = output.replace(htmlReplaceRegex, "").replace(/^[=\-]{2,}\s*$/g, "").replace(/\[\^.+?\](\: .*?$)?/g, "").replace(/\s{0,2}\[.*?\]: .*?$/g, "").replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? "$1" : "").replace(/\[([\s\S]*?)\]\s*[\(\[].*?[\)\]]/g, options.replaceLinksWithURL ? "$2" : "$1").replace(/^(\n)?\s{0,3}>\s?/gm, "$1").replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, "").replace(/^(\n)?\s{0,}#{1,6}\s*( (.+))? +#+$|^(\n)?\s{0,}#{1,6}\s*( (.+))?$/gm, "$1$3$4$6").replace(/([\*]+)(\S)(.*?\S)??\1/g, "$2$3").replace(/(^|\W)([_]+)(\S)(.*?\S)??\2($|\W)/g, "$1$3$4$5").replace(/(`{3,})(.*?)\1/gm, "$2").replace(/`(.+?)`/g, "$1").replace(/~(.*?)~/g, "$1");
28
+ output = output.replace(htmlReplaceRegex, "").replace(/^[=\-]{2,}\s*$/g, "").replace(/\[\^.+?\](\: .*?$)?/g, "").replace(/\s{0,2}\[.*?\]: .*?$/g, "").replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? "$1" : "").replace(/\[([\s\S]*?)\]\s*[\(\[](.*?)[\)\]]/g, options.replaceLinksWithURL ? "$2" : "$1").replace(/^(\n)?\s{0,3}>\s?/gm, "$1").replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, "").replace(/^(\n)?\s{0,}#{1,6}\s*( (.+))? +#+$|^(\n)?\s{0,}#{1,6}\s*( (.+))?$/gm, "$1$3$4$6").replace(/([\*]+)(\S)(.*?\S)??\1/g, "$2$3").replace(/(^|\W)([_]+)(\S)(.*?\S)??\2($|\W)/g, "$1$3$4$5").replace(/(`{3,})(.*?)\1/gm, "$2").replace(/`(.+?)`/g, "$1").replace(/~(.*?)~/g, "$1");
29
29
  } catch (e) {
30
30
  if (options.throwError) throw e;
31
31
  console.error("remove-markdown encountered error: %s", e);
@@ -9,7 +9,7 @@ const cacheMap = /* @__PURE__ */ new Map();
9
9
  function flexsearchStaticClient(options = {}) {
10
10
  const { from = "/api/search", locale = "", tag } = options;
11
11
  let dbs = cacheMap.get(from);
12
- if (!dbs) {
12
+ if (!dbs && typeof window !== "undefined") {
13
13
  dbs = init(from);
14
14
  cacheMap.set(from, dbs);
15
15
  }
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM } from "../../chunk-CYJPkc-J.js";
2
- import { t as require_remove_markdown } from "../../remove-markdown-e8JvQlzO.js";
2
+ import { t as require_remove_markdown } from "../../remove-markdown-D6zqr8cg.js";
3
3
  import Slugger from "github-slugger";
4
4
  //#region src/search/client/mixedbread.ts
5
5
  var import_remove_markdown = /* @__PURE__ */ __toESM(require_remove_markdown(), 1);
@@ -1,6 +1,6 @@
1
1
  import { r as __toESM } from "../chunk-CYJPkc-J.js";
2
2
  import { t as createEndpoint } from "../endpoint-CAUHRXte.js";
3
- import { t as require_remove_markdown } from "../remove-markdown-e8JvQlzO.js";
3
+ import { t as require_remove_markdown } from "../remove-markdown-D6zqr8cg.js";
4
4
  import Slugger from "github-slugger";
5
5
  //#region src/search/mixedbread.ts
6
6
  var import_remove_markdown = /* @__PURE__ */ __toESM(require_remove_markdown(), 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "16.8.7",
3
+ "version": "16.8.9",
4
4
  "description": "The React.js library for building a documentation website",
5
5
  "keywords": [
6
6
  "Docs",
@@ -113,37 +113,37 @@
113
113
  "vfile": "^6.0.3"
114
114
  },
115
115
  "devDependencies": {
116
- "@formatjs/intl-localematcher": "^0.8.5",
116
+ "@formatjs/intl-localematcher": "^0.8.6",
117
117
  "@mdx-js/mdx": "^3.1.1",
118
- "@mixedbread/sdk": "^0.64.0",
118
+ "@mixedbread/sdk": "^0.65.0",
119
119
  "@orama/core": "^1.2.19",
120
120
  "@oramacloud/client": "^2.1.4",
121
121
  "@shikijs/transformers": "^4.0.2",
122
- "@tanstack/react-router": "1.169.1",
122
+ "@tanstack/react-router": "1.169.2",
123
123
  "@types/estree-jsx": "^1.0.5",
124
124
  "@types/hast": "^3.0.4",
125
125
  "@types/js-yaml": "^4.0.9",
126
126
  "@types/mdast": "^4.0.4",
127
127
  "@types/negotiator": "^0.6.4",
128
- "@types/node": "25.6.0",
128
+ "@types/node": "25.6.2",
129
129
  "@types/react": "^19.2.14",
130
130
  "@types/react-dom": "^19.2.3",
131
- "algoliasearch": "5.52.0",
131
+ "algoliasearch": "5.52.1",
132
132
  "flexsearch": "^0.8.212",
133
133
  "image-size": "^2.0.2",
134
134
  "lucide-react": "^1.14.0",
135
135
  "negotiator": "^1.0.0",
136
- "next": "16.2.4",
136
+ "next": "16.2.6",
137
137
  "npm-to-yarn": "^3.0.1",
138
138
  "path-to-regexp": "^8.4.2",
139
- "react-router": "^7.14.2",
139
+ "react-router": "^7.15.0",
140
140
  "remark-directive": "^4.0.0",
141
141
  "remark-mdx": "^3.1.1",
142
- "remove-markdown": "^0.6.3",
143
- "tsdown": "0.21.10",
142
+ "remove-markdown": "^0.6.4",
143
+ "tsdown": "0.22.0",
144
144
  "typescript": "^6.0.3",
145
- "waku": "1.0.0-alpha.9",
146
- "zod": "^4.4.2",
145
+ "waku": "1.0.0-alpha.10",
146
+ "zod": "^4.4.3",
147
147
  "tsconfig": "0.0.0"
148
148
  },
149
149
  "peerDependencies": {
@@ -223,14 +223,14 @@
223
223
  }
224
224
  },
225
225
  "inlinedDependencies": {
226
- "@formatjs/fast-memoize": "3.1.3",
227
- "@formatjs/intl-localematcher": "0.8.5",
226
+ "@formatjs/fast-memoize": "3.1.4",
227
+ "@formatjs/intl-localematcher": "0.8.6",
228
228
  "@shikijs/transformers": "4.0.2",
229
229
  "image-size": "2.0.2",
230
230
  "negotiator": "1.0.0",
231
231
  "npm-to-yarn": "3.0.1",
232
232
  "path-to-regexp": "8.4.2",
233
- "remove-markdown": "0.6.3"
233
+ "remove-markdown": "0.6.4"
234
234
  },
235
235
  "scripts": {
236
236
  "build": "tsdown",