fumadocs-core 15.0.14 → 15.0.16

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.
@@ -4,6 +4,13 @@ function isDifferent(a, b) {
4
4
  if (Array.isArray(a) && Array.isArray(b)) {
5
5
  return b.length !== a.length || a.some((v, i) => isDifferent(v, b[i]));
6
6
  }
7
+ if (typeof a === "object" && a && typeof b === "object" && b) {
8
+ const aKeys = Object.keys(a);
9
+ const bKeys = Object.keys(b);
10
+ return aKeys.length !== bKeys.length || aKeys.some(
11
+ (key) => isDifferent(a[key], b[key])
12
+ );
13
+ }
7
14
  return a !== b;
8
15
  }
9
16
  function useOnChange(value, onChange, isUpdated = isDifferent) {
@@ -9,9 +9,11 @@ import {
9
9
  useId,
10
10
  useMemo,
11
11
  useRef,
12
- useState
12
+ use,
13
+ useState,
14
+ useLayoutEffect
13
15
  } from "react";
14
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
16
+ import { jsx } from "react/jsx-runtime";
15
17
  var jsEngine;
16
18
  function getHighlightOptions(from) {
17
19
  if (from.engine) return from;
@@ -30,7 +32,7 @@ function useShiki(code, {
30
32
  withPrerenderScript = false,
31
33
  ...options
32
34
  }, deps) {
33
- const scriptKey = useId();
35
+ const markupId = useId();
34
36
  const key = useMemo(
35
37
  () => deps ? JSON.stringify(deps) : `${options.lang}:${code}`,
36
38
  [code, deps, options.lang]
@@ -42,27 +44,19 @@ function useShiki(code, {
42
44
  });
43
45
  const [rendered, setRendered] = useState(() => {
44
46
  if (defaultValue) return defaultValue;
45
- const hast = globalThis._use_shiki?.get(scriptKey);
46
- if (hast && withPrerenderScript) {
47
- return /* @__PURE__ */ jsxs(Fragment, { children: [
48
- /* @__PURE__ */ jsx(PrerenderScript, { scriptKey, tree: hast }),
49
- _renderHighlight(hast, shikiOptions)
50
- ] });
47
+ const element = withPrerenderScript && typeof document !== "undefined" ? document.querySelector(`[data-markup-id="${markupId}"]`) : null;
48
+ const attr = element?.getAttribute("data-markup");
49
+ if (attr) {
50
+ const hast = JSON.parse(attr);
51
+ return renderHighlightWithMarkup(markupId, hast, shikiOptions, attr);
51
52
  }
52
53
  currentTask.current = void 0;
53
54
  const Pre = options.components?.pre ?? "pre";
54
55
  const Code = options.components?.code ?? "code";
55
56
  return /* @__PURE__ */ jsx(Pre, { children: /* @__PURE__ */ jsx(Code, { children: code }) });
56
57
  });
57
- if (typeof window === "undefined") {
58
- return _highlight(code, shikiOptions).then((tree) => {
59
- return /* @__PURE__ */ jsxs(Fragment, { children: [
60
- withPrerenderScript && /* @__PURE__ */ jsx(PrerenderScript, { scriptKey, tree }),
61
- _renderHighlight(tree, shikiOptions)
62
- ] });
63
- });
64
- }
65
- if (!currentTask.current || currentTask.current.key !== key) {
58
+ useLayoutEffect(() => {
59
+ if (currentTask.current?.key === key) return;
66
60
  if (currentTask.current) {
67
61
  currentTask.current.aborted = true;
68
62
  }
@@ -74,15 +68,32 @@ function useShiki(code, {
74
68
  void highlight(code, shikiOptions).then((result) => {
75
69
  if (!task.aborted) setRendered(result);
76
70
  });
71
+ }, [key]);
72
+ if (typeof window === "undefined") {
73
+ return use(
74
+ _highlight(code, shikiOptions).then(
75
+ (tree) => renderHighlightWithMarkup(markupId, tree, shikiOptions)
76
+ )
77
+ );
77
78
  }
78
79
  return rendered;
79
80
  }
80
- function PrerenderScript({
81
- scriptKey,
82
- tree
83
- }) {
84
- return /* @__PURE__ */ jsx("script", { children: `if (typeof globalThis._use_shiki === "undefined") globalThis._use_shiki = new Map()
85
- globalThis._use_shiki.set(${JSON.stringify(scriptKey)}, ${JSON.stringify(tree)})` });
81
+ function renderHighlightWithMarkup(id, tree, shikiOptions, rawAttr) {
82
+ const Pre = shikiOptions.components?.pre ?? "pre";
83
+ return _renderHighlight(tree, {
84
+ ...shikiOptions,
85
+ components: {
86
+ ...shikiOptions.components,
87
+ pre: (props) => /* @__PURE__ */ jsx(
88
+ Pre,
89
+ {
90
+ ...props,
91
+ "data-markup-id": id,
92
+ "data-markup": rawAttr ?? JSON.stringify(tree)
93
+ }
94
+ )
95
+ }
96
+ });
86
97
  }
87
98
 
88
99
  export {
@@ -1,16 +1,20 @@
1
1
  import "./chunk-MLKGABMK.js";
2
2
 
3
3
  // src/search/client/fetch.ts
4
+ var cache = /* @__PURE__ */ new Map();
4
5
  async function fetchDocs(query, locale, tag, options) {
5
6
  const params = new URLSearchParams();
6
7
  params.set("query", query);
7
8
  if (locale) params.set("locale", locale);
8
9
  if (tag) params.set("tag", tag);
9
- const res = await fetch(
10
- `${options.api ?? "/api/search"}?${params.toString()}`
11
- );
10
+ const key = `${options.api ?? "/api/search"}?${params}`;
11
+ const cached = cache.get(key);
12
+ if (cached) return cached;
13
+ const res = await fetch(key);
12
14
  if (!res.ok) throw new Error(await res.text());
13
- return await res.json();
15
+ const result = await res.json();
16
+ cache.set(key, result);
17
+ return result;
14
18
  }
15
19
  export {
16
20
  fetchDocs
@@ -1,15 +1,9 @@
1
1
  import { ReactNode, DependencyList } from 'react';
2
2
  import { HighlightOptions } from './index.js';
3
- import { Root } from 'hast';
4
3
  import 'shiki';
5
4
  import 'shiki/themes';
6
5
  import 'hast-util-to-jsx-runtime';
7
6
 
8
- declare global {
9
- interface Window {
10
- _use_shiki?: Map<string, Root>;
11
- }
12
- }
13
7
  declare function useShiki(code: string, { defaultValue, withPrerenderScript, ...options }: HighlightOptions & {
14
8
  withPrerenderScript?: boolean;
15
9
  defaultValue?: ReactNode;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  useShiki
4
- } from "../chunk-QWBSUU36.js";
4
+ } from "../chunk-Q73QZKHO.js";
5
5
  import "../chunk-E7AASGCN.js";
6
6
  import "../chunk-MLKGABMK.js";
7
7
  export {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  useOnChange
3
- } from "../chunk-EMWGTXSW.js";
3
+ } from "../chunk-ORHEEQVY.js";
4
4
  import "../chunk-MLKGABMK.js";
5
5
 
6
6
  // src/search/client.ts
7
- import { useMemo, useRef as useRef2, useState as useState2 } from "react";
7
+ import { useRef as useRef2, useState as useState2 } from "react";
8
8
 
9
9
  // src/utils/use-debounce.ts
10
10
  import { useRef, useState } from "react";
@@ -23,7 +23,6 @@ function useDebounce(value, delayMs = 1e3) {
23
23
  }
24
24
 
25
25
  // src/search/client.ts
26
- var cache = /* @__PURE__ */ new Map();
27
26
  var staticClient;
28
27
  function useDocsSearch(client, locale, tag, delayMs = 100, allowEmpty = false, key) {
29
28
  const [search, setSearch] = useState2("");
@@ -32,21 +31,11 @@ function useDocsSearch(client, locale, tag, delayMs = 100, allowEmpty = false, k
32
31
  const [isLoading, setIsLoading] = useState2(false);
33
32
  const debouncedValue = useDebounce(search, delayMs);
34
33
  const onStart = useRef2(void 0);
35
- const cacheKey = useMemo(() => {
36
- return key ?? JSON.stringify([client.type, debouncedValue, locale, tag]);
37
- }, [client.type, debouncedValue, locale, tag, key]);
38
- useOnChange(cacheKey, () => {
39
- const cached = cache.get(cacheKey);
34
+ useOnChange(key ?? [client, debouncedValue, locale, tag], () => {
40
35
  if (onStart.current) {
41
36
  onStart.current();
42
37
  onStart.current = void 0;
43
38
  }
44
- if (cached) {
45
- setIsLoading(false);
46
- setError(void 0);
47
- setResults(cached);
48
- return;
49
- }
50
39
  setIsLoading(true);
51
40
  let interrupt = false;
52
41
  onStart.current = () => {
@@ -55,7 +44,7 @@ function useDocsSearch(client, locale, tag, delayMs = 100, allowEmpty = false, k
55
44
  async function run() {
56
45
  if (debouncedValue.length === 0 && !allowEmpty) return "empty";
57
46
  if (client.type === "fetch") {
58
- const { fetchDocs } = await import("../fetch-4K7QOPFM.js");
47
+ const { fetchDocs } = await import("../fetch-W5EHIBOE.js");
59
48
  return fetchDocs(debouncedValue, locale, tag, client);
60
49
  }
61
50
  if (client.type === "algolia") {
@@ -72,7 +61,6 @@ function useDocsSearch(client, locale, tag, delayMs = 100, allowEmpty = false, k
72
61
  return staticClient.search(debouncedValue, locale, tag);
73
62
  }
74
63
  void run().then((res) => {
75
- cache.set(cacheKey, res);
76
64
  if (interrupt) return;
77
65
  setError(void 0);
78
66
  setResults(res);
package/dist/toc.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  useOnChange
4
- } from "./chunk-EMWGTXSW.js";
4
+ } from "./chunk-ORHEEQVY.js";
5
5
  import "./chunk-MLKGABMK.js";
6
6
 
7
7
  // src/toc.tsx
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useOnChange
3
- } from "../chunk-EMWGTXSW.js";
3
+ } from "../chunk-ORHEEQVY.js";
4
4
  import "../chunk-MLKGABMK.js";
5
5
  export {
6
6
  useOnChange
@@ -4,4 +4,3 @@ import '../highlight/index.js';
4
4
  import 'shiki';
5
5
  import 'shiki/themes';
6
6
  import 'hast-util-to-jsx-runtime';
7
- import 'hast';
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useShiki
3
- } from "../chunk-QWBSUU36.js";
3
+ } from "../chunk-Q73QZKHO.js";
4
4
  import "../chunk-E7AASGCN.js";
5
5
  import "../chunk-MLKGABMK.js";
6
6
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "15.0.14",
3
+ "version": "15.0.16",
4
4
  "description": "The library for building a documentation website in Next.js",
5
5
  "keywords": [
6
6
  "NextJs",
@@ -90,12 +90,12 @@
90
90
  ],
91
91
  "dependencies": {
92
92
  "@formatjs/intl-localematcher": "^0.6.0",
93
- "@orama/orama": "^3.1.1",
93
+ "@orama/orama": "^3.1.2",
94
94
  "@shikijs/rehype": "^3.1.0",
95
95
  "@shikijs/transformers": "^3.1.0",
96
96
  "github-slugger": "^2.0.0",
97
- "hast-util-to-estree": "^3.1.2",
98
- "hast-util-to-jsx-runtime": "^2.3.5",
97
+ "hast-util-to-estree": "^3.1.3",
98
+ "hast-util-to-jsx-runtime": "^2.3.6",
99
99
  "image-size": "^2.0.0",
100
100
  "negotiator": "^1.0.0",
101
101
  "react-remove-scroll": "^2.6.3",
@@ -108,19 +108,18 @@
108
108
  "devDependencies": {
109
109
  "@algolia/client-search": "4.24.0",
110
110
  "@mdx-js/mdx": "^3.1.0",
111
- "@orama/tokenizers": "^3.1.1",
112
111
  "@oramacloud/client": "^2.1.4",
113
112
  "@types/estree-jsx": "^1.0.5",
114
113
  "@types/hast": "^3.0.4",
115
114
  "@types/mdast": "^4.0.3",
116
115
  "@types/negotiator": "^0.6.3",
117
- "@types/node": "22.13.8",
116
+ "@types/node": "22.13.10",
118
117
  "@types/react": "^19.0.10",
119
118
  "@types/react-dom": "^19.0.4",
120
119
  "algoliasearch": "4.24.0",
121
120
  "mdast-util-mdx-jsx": "^3.2.0",
122
121
  "mdast-util-mdxjs-esm": "^2.0.1",
123
- "next": "^15.2.0",
122
+ "next": "^15.2.1",
124
123
  "remark-mdx": "^3.1.0",
125
124
  "remark-rehype": "^11.1.1",
126
125
  "typescript": "^5.8.2",
@@ -130,7 +129,6 @@
130
129
  "tsconfig": "0.0.0"
131
130
  },
132
131
  "peerDependencies": {
133
- "@orama/tokenizers": "2.x.x",
134
132
  "@oramacloud/client": "1.x.x || 2.x.x",
135
133
  "algoliasearch": "4.24.0",
136
134
  "next": "14.x.x || 15.x.x",
@@ -138,9 +136,6 @@
138
136
  "react-dom": "18.x.x || 19.x.x"
139
137
  },
140
138
  "peerDependenciesMeta": {
141
- "@orama/tokenizers": {
142
- "optional": true
143
- },
144
139
  "@oramacloud/client": {
145
140
  "optional": true
146
141
  },