fumadocs-core 16.0.5 → 16.0.7
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.
- package/dist/{chunk-QMATWJ5F.js → chunk-JD3M54YF.js} +37 -1
- package/dist/{chunk-H2GMUTQG.js → chunk-N2ZQXKIX.js} +3 -2
- package/dist/content/toc.d.ts +1 -1
- package/dist/content/toc.js +1 -1
- package/dist/dynamic-link.js +1 -1
- package/dist/link.js +1 -1
- package/dist/mdx-plugins/index.d.ts +8 -2
- package/dist/mdx-plugins/index.js +24 -11
- package/dist/{remark-structure-DkCXCzpD.d.ts → remark-structure-BJxaB5zZ.d.ts} +9 -4
- package/dist/search/algolia.d.ts +1 -1
- package/dist/search/client.d.ts +1 -1
- package/dist/search/orama-cloud.d.ts +1 -1
- package/dist/search/server.d.ts +1 -1
- package/dist/toc.d.ts +3 -4
- package/dist/toc.js +97 -76
- package/package.json +5 -4
|
@@ -2,13 +2,48 @@
|
|
|
2
2
|
import Slugger from "github-slugger";
|
|
3
3
|
import { visit } from "unist-util-visit";
|
|
4
4
|
|
|
5
|
-
// src/mdx-plugins/
|
|
5
|
+
// src/mdx-plugins/mdast-utils.ts
|
|
6
|
+
import { valueToEstree } from "estree-util-value-to-estree";
|
|
6
7
|
function flattenNode(node) {
|
|
7
8
|
if ("children" in node)
|
|
8
9
|
return node.children.map((child) => flattenNode(child)).join("");
|
|
9
10
|
if ("value" in node) return node.value;
|
|
10
11
|
return "";
|
|
11
12
|
}
|
|
13
|
+
function toMdxExport(name, value) {
|
|
14
|
+
return {
|
|
15
|
+
type: "mdxjsEsm",
|
|
16
|
+
value: "",
|
|
17
|
+
data: {
|
|
18
|
+
estree: {
|
|
19
|
+
type: "Program",
|
|
20
|
+
sourceType: "module",
|
|
21
|
+
body: [
|
|
22
|
+
{
|
|
23
|
+
type: "ExportNamedDeclaration",
|
|
24
|
+
attributes: [],
|
|
25
|
+
specifiers: [],
|
|
26
|
+
source: null,
|
|
27
|
+
declaration: {
|
|
28
|
+
type: "VariableDeclaration",
|
|
29
|
+
kind: "let",
|
|
30
|
+
declarations: [
|
|
31
|
+
{
|
|
32
|
+
type: "VariableDeclarator",
|
|
33
|
+
id: {
|
|
34
|
+
type: "Identifier",
|
|
35
|
+
name
|
|
36
|
+
},
|
|
37
|
+
init: valueToEstree(value)
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
12
47
|
|
|
13
48
|
// src/mdx-plugins/remark-heading.ts
|
|
14
49
|
var slugger = new Slugger();
|
|
@@ -53,5 +88,6 @@ function remarkHeading({
|
|
|
53
88
|
|
|
54
89
|
export {
|
|
55
90
|
flattenNode,
|
|
91
|
+
toMdxExport,
|
|
56
92
|
remarkHeading
|
|
57
93
|
};
|
|
@@ -12,6 +12,7 @@ var Link2 = forwardRef(
|
|
|
12
12
|
external = href.match(/^\w+:/) || // protocol relative URL
|
|
13
13
|
href.startsWith("//"),
|
|
14
14
|
prefetch,
|
|
15
|
+
children,
|
|
15
16
|
...props
|
|
16
17
|
}, ref) => {
|
|
17
18
|
if (external) {
|
|
@@ -23,11 +24,11 @@ var Link2 = forwardRef(
|
|
|
23
24
|
rel: "noreferrer noopener",
|
|
24
25
|
target: "_blank",
|
|
25
26
|
...props,
|
|
26
|
-
children
|
|
27
|
+
children
|
|
27
28
|
}
|
|
28
29
|
);
|
|
29
30
|
}
|
|
30
|
-
return /* @__PURE__ */ jsx(Link, { ref, href, prefetch, ...props });
|
|
31
|
+
return /* @__PURE__ */ jsx(Link, { ref, href, prefetch, ...props, children });
|
|
31
32
|
}
|
|
32
33
|
);
|
|
33
34
|
Link2.displayName = "Link";
|
package/dist/content/toc.d.ts
CHANGED
package/dist/content/toc.js
CHANGED
package/dist/dynamic-link.js
CHANGED
package/dist/link.js
CHANGED
|
@@ -4,7 +4,7 @@ import { RehypeShikiOptions } from '@shikijs/rehype';
|
|
|
4
4
|
import { Processor, Transformer } from 'unified';
|
|
5
5
|
import { ShikiTransformer } from 'shiki';
|
|
6
6
|
import { Root as Root$1, BlockContent, Text } from 'mdast';
|
|
7
|
-
export { a as StructureOptions, S as StructuredData, r as remarkStructure, s as structure } from '../remark-structure-
|
|
7
|
+
export { a as StructureOptions, S as StructuredData, r as remarkStructure, s as structure } from '../remark-structure-BJxaB5zZ.js';
|
|
8
8
|
export { a as RemarkCodeTabOptions, R as RemarkHeadingOptions, b as remarkCodeTab, r as remarkHeading } from '../remark-code-tab-DmyIyi6m.js';
|
|
9
9
|
import { MdxJsxAttribute, MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
|
|
10
10
|
|
|
@@ -51,6 +51,12 @@ type RehypeCodeOptions = RehypeShikiOptions & {
|
|
|
51
51
|
declare function rehypeCode(this: Processor, _options?: Partial<RehypeCodeOptions>): Transformer<Root, Root>;
|
|
52
52
|
declare function transformerTab(): ShikiTransformer;
|
|
53
53
|
|
|
54
|
+
type ExternalImageOptions = {
|
|
55
|
+
/**
|
|
56
|
+
* timeout for fetching remote images (in milliseconds)
|
|
57
|
+
*/
|
|
58
|
+
timeout?: number;
|
|
59
|
+
} | boolean;
|
|
54
60
|
interface RemarkImageOptions {
|
|
55
61
|
/**
|
|
56
62
|
* Directory or base URL to resolve absolute image paths
|
|
@@ -91,7 +97,7 @@ interface RemarkImageOptions {
|
|
|
91
97
|
*
|
|
92
98
|
* @defaultValue true
|
|
93
99
|
*/
|
|
94
|
-
external?:
|
|
100
|
+
external?: ExternalImageOptions;
|
|
95
101
|
}
|
|
96
102
|
/**
|
|
97
103
|
* Turn images into Next.js Image compatible usage.
|
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
} from "../chunk-XN2LKXFZ.js";
|
|
5
5
|
import {
|
|
6
6
|
flattenNode,
|
|
7
|
-
remarkHeading
|
|
8
|
-
|
|
7
|
+
remarkHeading,
|
|
8
|
+
toMdxExport
|
|
9
|
+
} from "../chunk-JD3M54YF.js";
|
|
9
10
|
import "../chunk-U67V476Y.js";
|
|
10
11
|
|
|
11
12
|
// src/mdx-plugins/index.ts
|
|
@@ -426,8 +427,7 @@ function remarkImage({
|
|
|
426
427
|
}
|
|
427
428
|
return out;
|
|
428
429
|
}
|
|
429
|
-
|
|
430
|
-
const size = await getImageSize(src).catch((e) => {
|
|
430
|
+
const size = await getImageSize(src, external).catch((e) => {
|
|
431
431
|
throw new Error(
|
|
432
432
|
`[Remark Image] Failed obtain image size for ${node.url} (public directory configured as ${publicDir})`,
|
|
433
433
|
{
|
|
@@ -435,6 +435,7 @@ function remarkImage({
|
|
|
435
435
|
}
|
|
436
436
|
);
|
|
437
437
|
});
|
|
438
|
+
if (!size) return;
|
|
438
439
|
return {
|
|
439
440
|
type: "mdxJsxFlowElement",
|
|
440
441
|
name: "img",
|
|
@@ -550,9 +551,13 @@ function parseSrc(src, publicDir, dir) {
|
|
|
550
551
|
file: path.join(dir, src)
|
|
551
552
|
};
|
|
552
553
|
}
|
|
553
|
-
async function getImageSize(src) {
|
|
554
|
+
async function getImageSize(src, onExternal) {
|
|
554
555
|
if (src.type === "file") return imageSizeFromFile(src.file);
|
|
555
|
-
|
|
556
|
+
if (onExternal === false) return;
|
|
557
|
+
const { timeout } = typeof onExternal === "object" ? onExternal : {};
|
|
558
|
+
const res = await fetch(src.url, {
|
|
559
|
+
signal: typeof timeout === "number" ? AbortSignal.timeout(timeout) : void 0
|
|
560
|
+
});
|
|
556
561
|
if (!res.ok) {
|
|
557
562
|
throw new Error(
|
|
558
563
|
`[Remark Image] Failed to fetch ${src.url} (${res.status}): ${await res.text()}`
|
|
@@ -577,7 +582,8 @@ function remarkStructure({
|
|
|
577
582
|
allowedMdxAttributes = (node) => {
|
|
578
583
|
if (!node.name) return false;
|
|
579
584
|
return ["TypeTable", "Callout"].includes(node.name);
|
|
580
|
-
}
|
|
585
|
+
},
|
|
586
|
+
exportAs = false
|
|
581
587
|
} = {}) {
|
|
582
588
|
const slugger = new Slugger();
|
|
583
589
|
if (Array.isArray(allowedMdxAttributes)) {
|
|
@@ -588,7 +594,7 @@ function remarkStructure({
|
|
|
588
594
|
const arr = types;
|
|
589
595
|
types = (node) => arr.includes(node.type);
|
|
590
596
|
}
|
|
591
|
-
return (
|
|
597
|
+
return (tree, file) => {
|
|
592
598
|
slugger.reset();
|
|
593
599
|
const data = { contents: [], headings: [] };
|
|
594
600
|
let lastHeading;
|
|
@@ -599,9 +605,8 @@ function remarkStructure({
|
|
|
599
605
|
data.contents.push(...frontmatter._openapi.structuredData.contents);
|
|
600
606
|
}
|
|
601
607
|
}
|
|
602
|
-
visit2(
|
|
603
|
-
if (element.type === "root") return;
|
|
604
|
-
if (!types(element)) return;
|
|
608
|
+
visit2(tree, (element) => {
|
|
609
|
+
if (element.type === "root" || !types(element)) return;
|
|
605
610
|
if (element.type === "heading") {
|
|
606
611
|
element.data ||= {};
|
|
607
612
|
element.data.hProperties ||= {};
|
|
@@ -648,6 +653,14 @@ function remarkStructure({
|
|
|
648
653
|
return "skip";
|
|
649
654
|
});
|
|
650
655
|
file.data.structuredData = data;
|
|
656
|
+
if (exportAs) {
|
|
657
|
+
tree.children.unshift(
|
|
658
|
+
toMdxExport(
|
|
659
|
+
typeof exportAs === "string" ? exportAs : "structuredData",
|
|
660
|
+
data
|
|
661
|
+
)
|
|
662
|
+
);
|
|
663
|
+
}
|
|
651
664
|
};
|
|
652
665
|
}
|
|
653
666
|
function structure(content, remarkPlugins = [], options = {}) {
|
|
@@ -31,26 +31,31 @@ interface StructureOptions {
|
|
|
31
31
|
* - a function that determines if attribute should be indexed.
|
|
32
32
|
*/
|
|
33
33
|
allowedMdxAttributes?: string[] | ((node: MdxJsxFlowElement, attribute: MdxJsxAttribute | MdxJsxExpressionAttribute) => boolean);
|
|
34
|
+
/**
|
|
35
|
+
* export as `structuredData` or specified variable name.
|
|
36
|
+
*/
|
|
37
|
+
exportAs?: string | boolean;
|
|
34
38
|
}
|
|
35
39
|
declare module 'mdast' {
|
|
36
40
|
interface Data {
|
|
37
41
|
/**
|
|
38
|
-
* Get content of unserializable element
|
|
39
|
-
*
|
|
40
|
-
* Needed for `remarkStructure` to generate search index
|
|
42
|
+
* [Fumadocs] Get content of unserializable element, `remarkStructure` uses it to generate search index.
|
|
41
43
|
*/
|
|
42
44
|
_string?: string[];
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
declare module 'vfile' {
|
|
46
48
|
interface DataMap {
|
|
49
|
+
/**
|
|
50
|
+
* [Fumadocs] injected by `remarkStructure`
|
|
51
|
+
*/
|
|
47
52
|
structuredData: StructuredData;
|
|
48
53
|
}
|
|
49
54
|
}
|
|
50
55
|
/**
|
|
51
56
|
* Attach structured data to VFile, you can access via `vfile.data.structuredData`.
|
|
52
57
|
*/
|
|
53
|
-
declare function remarkStructure({ types, allowedMdxAttributes, }?: StructureOptions): Transformer<Root, Root>;
|
|
58
|
+
declare function remarkStructure({ types, allowedMdxAttributes, exportAs, }?: StructureOptions): Transformer<Root, Root>;
|
|
54
59
|
/**
|
|
55
60
|
* Extract data from markdown/mdx content
|
|
56
61
|
*/
|
package/dist/search/algolia.d.ts
CHANGED
package/dist/search/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyOrama } from '@orama/orama';
|
|
2
|
-
import '../remark-structure-
|
|
2
|
+
import '../remark-structure-BJxaB5zZ.js';
|
|
3
3
|
import { BaseIndex } from './algolia.js';
|
|
4
4
|
import { LiteClient, SearchResponse } from 'algoliasearch/lite';
|
|
5
5
|
import { OramaCloud, OramaCloudSearchParams } from '@orama/core';
|
package/dist/search/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypedDocument, Orama, Language, RawData, create, SearchParams } from '@orama/orama';
|
|
2
|
-
import { S as StructuredData } from '../remark-structure-
|
|
2
|
+
import { S as StructuredData } from '../remark-structure-BJxaB5zZ.js';
|
|
3
3
|
import { SortedResult } from './index.js';
|
|
4
4
|
export { HighlightedText, ReactSortedResult, createContentHighlighter } from './index.js';
|
|
5
5
|
import { I18nConfig } from '../i18n/index.js';
|
package/dist/toc.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import * as react from 'react';
|
|
2
|
-
import { ReactNode, RefObject, AnchorHTMLAttributes } from 'react';
|
|
3
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, RefObject, ComponentProps } from 'react';
|
|
4
3
|
|
|
5
4
|
interface TOCItemType {
|
|
6
5
|
title: ReactNode;
|
|
@@ -35,10 +34,10 @@ interface ScrollProviderProps {
|
|
|
35
34
|
}
|
|
36
35
|
declare function ScrollProvider({ containerRef, children, }: ScrollProviderProps): react_jsx_runtime.JSX.Element;
|
|
37
36
|
declare function AnchorProvider({ toc, single, children, }: AnchorProviderProps): react_jsx_runtime.JSX.Element;
|
|
38
|
-
interface TOCItemProps extends Omit<
|
|
37
|
+
interface TOCItemProps extends Omit<ComponentProps<'a'>, 'href'> {
|
|
39
38
|
href: string;
|
|
40
39
|
onActiveChange?: (v: boolean) => void;
|
|
41
40
|
}
|
|
42
|
-
declare
|
|
41
|
+
declare function TOCItem({ ref, onActiveChange, ...props }: TOCItemProps): react_jsx_runtime.JSX.Element;
|
|
43
42
|
|
|
44
43
|
export { AnchorProvider, type AnchorProviderProps, ScrollProvider, type ScrollProviderProps, TOCItem, type TOCItemProps, type TOCItemType, type TableOfContents, useActiveAnchor, useActiveAnchors };
|
package/dist/toc.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
useOnChange
|
|
4
|
-
} from "./chunk-EMWGTXSW.js";
|
|
5
2
|
import "./chunk-U67V476Y.js";
|
|
6
3
|
|
|
7
4
|
// src/toc.tsx
|
|
8
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createContext,
|
|
7
|
+
useContext,
|
|
8
|
+
useEffect,
|
|
9
|
+
useEffectEvent,
|
|
10
|
+
useLayoutEffect,
|
|
11
|
+
useMemo,
|
|
12
|
+
useRef,
|
|
13
|
+
useState
|
|
14
|
+
} from "react";
|
|
9
15
|
import scrollIntoView from "scroll-into-view-if-needed";
|
|
10
16
|
|
|
11
17
|
// src/utils/merge-refs.ts
|
|
@@ -14,60 +20,13 @@ function mergeRefs(...refs) {
|
|
|
14
20
|
refs.forEach((ref) => {
|
|
15
21
|
if (typeof ref === "function") {
|
|
16
22
|
ref(value);
|
|
17
|
-
} else if (ref
|
|
23
|
+
} else if (ref != null) {
|
|
18
24
|
ref.current = value;
|
|
19
25
|
}
|
|
20
26
|
});
|
|
21
27
|
};
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
// src/utils/use-anchor-observer.ts
|
|
25
|
-
import { useEffect, useState } from "react";
|
|
26
|
-
function useAnchorObserver(watch, single) {
|
|
27
|
-
const [activeAnchor, setActiveAnchor] = useState([]);
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
let visible = [];
|
|
30
|
-
const observer = new IntersectionObserver(
|
|
31
|
-
(entries) => {
|
|
32
|
-
for (const entry of entries) {
|
|
33
|
-
if (entry.isIntersecting && !visible.includes(entry.target.id)) {
|
|
34
|
-
visible = [...visible, entry.target.id];
|
|
35
|
-
} else if (!entry.isIntersecting && visible.includes(entry.target.id)) {
|
|
36
|
-
visible = visible.filter((v) => v !== entry.target.id);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (visible.length > 0) setActiveAnchor(visible);
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
rootMargin: single ? "-80px 0% -70% 0%" : `-20px 0% -40% 0%`,
|
|
43
|
-
threshold: 1
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
function onScroll() {
|
|
47
|
-
const element = document.scrollingElement;
|
|
48
|
-
if (!element) return;
|
|
49
|
-
const top = element.scrollTop;
|
|
50
|
-
if (top <= 0 && single) setActiveAnchor(watch.slice(0, 1));
|
|
51
|
-
else if (top + element.clientHeight >= element.scrollHeight - 6) {
|
|
52
|
-
setActiveAnchor((active) => {
|
|
53
|
-
return active.length > 0 && !single ? watch.slice(watch.indexOf(active[0])) : watch.slice(-1);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
for (const heading of watch) {
|
|
58
|
-
const element = document.getElementById(heading);
|
|
59
|
-
if (element) observer.observe(element);
|
|
60
|
-
}
|
|
61
|
-
onScroll();
|
|
62
|
-
window.addEventListener("scroll", onScroll);
|
|
63
|
-
return () => {
|
|
64
|
-
window.removeEventListener("scroll", onScroll);
|
|
65
|
-
observer.disconnect();
|
|
66
|
-
};
|
|
67
|
-
}, [single, watch]);
|
|
68
|
-
return single ? activeAnchor.slice(0, 1) : activeAnchor;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
30
|
// src/toc.tsx
|
|
72
31
|
import { jsx } from "react/jsx-runtime";
|
|
73
32
|
var ActiveAnchorContext = createContext([]);
|
|
@@ -75,7 +34,7 @@ var ScrollContext = createContext({
|
|
|
75
34
|
current: null
|
|
76
35
|
});
|
|
77
36
|
function useActiveAnchor() {
|
|
78
|
-
return useContext(ActiveAnchorContext)
|
|
37
|
+
return useContext(ActiveAnchorContext)[0];
|
|
79
38
|
}
|
|
80
39
|
function useActiveAnchors() {
|
|
81
40
|
return useContext(ActiveAnchorContext);
|
|
@@ -96,31 +55,93 @@ function AnchorProvider({
|
|
|
96
55
|
}, [toc]);
|
|
97
56
|
return /* @__PURE__ */ jsx(ActiveAnchorContext.Provider, { value: useAnchorObserver(headings, single), children });
|
|
98
57
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
58
|
+
function TOCItem({
|
|
59
|
+
ref,
|
|
60
|
+
onActiveChange = () => null,
|
|
61
|
+
...props
|
|
62
|
+
}) {
|
|
63
|
+
const containerRef = useContext(ScrollContext);
|
|
64
|
+
const anchorRef = useRef(null);
|
|
65
|
+
const activeOrder = useActiveAnchors().indexOf(props.href.slice(1));
|
|
66
|
+
const isActive = activeOrder !== -1;
|
|
67
|
+
const shouldScroll = activeOrder === 0;
|
|
68
|
+
const onActiveChangeEvent = useEffectEvent(onActiveChange);
|
|
69
|
+
useLayoutEffect(() => {
|
|
70
|
+
const anchor = anchorRef.current;
|
|
71
|
+
const container = containerRef.current;
|
|
72
|
+
if (container && anchor && shouldScroll)
|
|
73
|
+
scrollIntoView(anchor, {
|
|
74
|
+
behavior: "smooth",
|
|
75
|
+
block: "center",
|
|
76
|
+
inline: "center",
|
|
77
|
+
scrollMode: "always",
|
|
78
|
+
boundary: container
|
|
79
|
+
});
|
|
80
|
+
}, [containerRef, shouldScroll]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
return () => onActiveChangeEvent(isActive);
|
|
83
|
+
}, [isActive]);
|
|
84
|
+
return /* @__PURE__ */ jsx("a", { ref: mergeRefs(anchorRef, ref), "data-active": isActive, ...props, children: props.children });
|
|
85
|
+
}
|
|
86
|
+
function useAnchorObserver(watch, single) {
|
|
87
|
+
const observerRef = useRef(null);
|
|
88
|
+
const [activeAnchor, setActiveAnchor] = useState(() => []);
|
|
89
|
+
const stateRef = useRef(null);
|
|
90
|
+
const onChange = useEffectEvent((entries) => {
|
|
91
|
+
stateRef.current ??= {
|
|
92
|
+
visible: /* @__PURE__ */ new Set()
|
|
93
|
+
};
|
|
94
|
+
const state = stateRef.current;
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
if (entry.isIntersecting) {
|
|
97
|
+
state.visible.add(entry.target.id);
|
|
98
|
+
} else {
|
|
99
|
+
state.visible.delete(entry.target.id);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (state.visible.size === 0) {
|
|
103
|
+
const viewTop = entries[0].rootBounds.top;
|
|
104
|
+
let fallback;
|
|
105
|
+
let min = -1;
|
|
106
|
+
for (const id of watch) {
|
|
107
|
+
const element = document.getElementById(id);
|
|
108
|
+
if (!element) continue;
|
|
109
|
+
const d = Math.abs(viewTop - element.getBoundingClientRect().top);
|
|
110
|
+
if (min === -1 || d < min) {
|
|
111
|
+
fallback = element;
|
|
112
|
+
min = d;
|
|
113
|
+
}
|
|
117
114
|
}
|
|
118
|
-
|
|
115
|
+
setActiveAnchor(fallback ? [fallback.id] : []);
|
|
116
|
+
} else {
|
|
117
|
+
const items = watch.filter((item) => state.visible.has(item));
|
|
118
|
+
setActiveAnchor(single ? items.slice(0, 1) : items);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (observerRef.current) return;
|
|
123
|
+
observerRef.current = new IntersectionObserver(onChange, {
|
|
124
|
+
rootMargin: "0px",
|
|
125
|
+
threshold: 0.98
|
|
119
126
|
});
|
|
120
|
-
return
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
127
|
+
return () => {
|
|
128
|
+
observerRef.current?.disconnect();
|
|
129
|
+
observerRef.current = null;
|
|
130
|
+
};
|
|
131
|
+
}, []);
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
const observer = observerRef.current;
|
|
134
|
+
if (!observer) return;
|
|
135
|
+
const elements = watch.flatMap(
|
|
136
|
+
(heading) => document.getElementById(heading) ?? []
|
|
137
|
+
);
|
|
138
|
+
for (const element of elements) observer.observe(element);
|
|
139
|
+
return () => {
|
|
140
|
+
for (const element of elements) observer.unobserve(element);
|
|
141
|
+
};
|
|
142
|
+
}, [watch]);
|
|
143
|
+
return activeAnchor;
|
|
144
|
+
}
|
|
124
145
|
export {
|
|
125
146
|
AnchorProvider,
|
|
126
147
|
ScrollProvider,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-core",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.7",
|
|
4
4
|
"description": "The library for building a documentation website in any React.js framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Fumadocs",
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"@orama/orama": "^3.1.16",
|
|
106
106
|
"@shikijs/rehype": "^3.14.0",
|
|
107
107
|
"@shikijs/transformers": "^3.14.0",
|
|
108
|
+
"estree-util-value-to-estree": "^3.5.0",
|
|
108
109
|
"github-slugger": "^2.0.0",
|
|
109
110
|
"hast-util-to-estree": "^3.1.3",
|
|
110
111
|
"hast-util-to-jsx-runtime": "^2.3.6",
|
|
@@ -123,19 +124,19 @@
|
|
|
123
124
|
"@mdx-js/mdx": "^3.1.1",
|
|
124
125
|
"@mixedbread/sdk": "^0.35.1",
|
|
125
126
|
"@orama/core": "^1.2.13",
|
|
126
|
-
"@tanstack/react-router": "^1.133.
|
|
127
|
+
"@tanstack/react-router": "^1.133.36",
|
|
127
128
|
"@types/estree-jsx": "^1.0.5",
|
|
128
129
|
"@types/hast": "^3.0.4",
|
|
129
130
|
"@types/mdast": "^4.0.4",
|
|
130
131
|
"@types/negotiator": "^0.6.4",
|
|
131
|
-
"@types/node": "24.9.
|
|
132
|
+
"@types/node": "24.9.2",
|
|
132
133
|
"@types/react": "^19.2.2",
|
|
133
134
|
"@types/react-dom": "^19.2.2",
|
|
134
135
|
"algoliasearch": "5.41.0",
|
|
135
136
|
"lucide-react": "^0.548.0",
|
|
136
137
|
"mdast-util-mdx-jsx": "^3.2.0",
|
|
137
138
|
"mdast-util-mdxjs-esm": "^2.0.1",
|
|
138
|
-
"next": "16.0.
|
|
139
|
+
"next": "16.0.1",
|
|
139
140
|
"react-router": "^7.9.4",
|
|
140
141
|
"remark-mdx": "^3.1.1",
|
|
141
142
|
"remove-markdown": "^0.6.2",
|