fumadocs-core 15.2.8 → 16.0.3

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.
Files changed (92) hide show
  1. package/README.md +1 -1
  2. package/dist/algolia-IZEDLPHE.js +58 -0
  3. package/dist/breadcrumb.d.ts +7 -5
  4. package/dist/breadcrumb.js +46 -52
  5. package/dist/builder-feW_xVjc.d.ts +296 -0
  6. package/dist/{chunk-FVY6EZ3N.js → chunk-BBP7MIO4.js} +12 -14
  7. package/dist/{chunk-ORHEEQVY.js → chunk-EMWGTXSW.js} +0 -7
  8. package/dist/chunk-FAEPKD7U.js +20 -0
  9. package/dist/{chunk-NNKVN7WA.js → chunk-H2GMUTQG.js} +4 -2
  10. package/dist/chunk-IZPLHEX4.js +113 -0
  11. package/dist/chunk-OTD7MV33.js +53 -0
  12. package/dist/chunk-PFNP6PEB.js +11 -0
  13. package/dist/{chunk-Y2774T3B.js → chunk-QMATWJ5F.js} +6 -7
  14. package/dist/chunk-U67V476Y.js +35 -0
  15. package/dist/{chunk-BUCUQ3WX.js → chunk-XN2LKXFZ.js} +39 -34
  16. package/dist/{chunk-WFUH5VBX.js → chunk-XOFXGHS4.js} +26 -10
  17. package/dist/chunk-XZSI7AHE.js +67 -0
  18. package/dist/chunk-YVVDKJ2H.js +34 -0
  19. package/dist/chunk-ZMWYLUDP.js +21 -0
  20. package/dist/content/github.d.ts +34 -0
  21. package/dist/content/github.js +43 -0
  22. package/dist/content/index.d.ts +16 -0
  23. package/dist/content/index.js +30 -0
  24. package/dist/{get-toc-Cr2URuiP.d.ts → content/toc.d.ts} +6 -10
  25. package/dist/content/toc.js +21 -0
  26. package/dist/{page-tree-BG3wP0gU.d.ts → definitions-BRsJlZ6m.d.ts} +10 -15
  27. package/dist/dynamic-link.js +3 -3
  28. package/dist/fetch-2XFMBLBA.js +22 -0
  29. package/dist/framework/index.d.ts +1 -1
  30. package/dist/framework/index.js +2 -2
  31. package/dist/framework/next.js +2 -2
  32. package/dist/framework/react-router.js +2 -2
  33. package/dist/framework/tanstack.js +2 -2
  34. package/dist/framework/waku.d.ts +8 -0
  35. package/dist/framework/waku.js +51 -0
  36. package/dist/hide-if-empty.d.ts +18 -0
  37. package/dist/hide-if-empty.js +83 -0
  38. package/dist/highlight/client.d.ts +8 -5
  39. package/dist/highlight/client.js +9 -93
  40. package/dist/highlight/index.d.ts +20 -5
  41. package/dist/highlight/index.js +10 -6
  42. package/dist/i18n/index.d.ts +35 -8
  43. package/dist/i18n/index.js +5 -69
  44. package/dist/i18n/middleware.d.ts +12 -0
  45. package/dist/i18n/middleware.js +63 -0
  46. package/dist/link.js +3 -3
  47. package/dist/mdx-plugins/index.d.ts +124 -18
  48. package/dist/mdx-plugins/index.js +605 -203
  49. package/dist/mixedbread-RAHDVXGJ.js +118 -0
  50. package/dist/negotiation/index.d.ts +19 -0
  51. package/dist/negotiation/index.js +11 -0
  52. package/dist/{orama-cloud-USLSOSXS.js → orama-cloud-WEGQE5A6.js} +37 -27
  53. package/dist/page-tree/index.d.ts +32 -0
  54. package/dist/page-tree/index.js +15 -0
  55. package/dist/remark-code-tab-DmyIyi6m.d.ts +57 -0
  56. package/dist/{remark-structure-FIjTA11P.d.ts → remark-structure-DkCXCzpD.d.ts} +13 -2
  57. package/dist/search/algolia.d.ts +9 -7
  58. package/dist/search/algolia.js +31 -17
  59. package/dist/search/client.d.ts +88 -17
  60. package/dist/search/client.js +71 -50
  61. package/dist/search/index.d.ts +26 -0
  62. package/dist/search/index.js +7 -0
  63. package/dist/search/orama-cloud.d.ts +7 -5
  64. package/dist/search/orama-cloud.js +18 -10
  65. package/dist/search/server.d.ts +33 -25
  66. package/dist/search/server.js +109 -47
  67. package/dist/source/index.d.ts +33 -254
  68. package/dist/source/index.js +532 -353
  69. package/dist/source/plugins/lucide-icons.d.ts +14 -0
  70. package/dist/source/plugins/lucide-icons.js +23 -0
  71. package/dist/static-A2YJ5TXV.js +62 -0
  72. package/dist/toc.d.ts +11 -7
  73. package/dist/toc.js +6 -5
  74. package/dist/utils/use-effect-event.d.ts +4 -3
  75. package/dist/utils/use-effect-event.js +9 -6
  76. package/dist/utils/use-media-query.d.ts +3 -0
  77. package/dist/utils/use-media-query.js +23 -0
  78. package/dist/utils/use-on-change.js +2 -2
  79. package/package.json +92 -40
  80. package/dist/algolia-NTWLS6J3.js +0 -49
  81. package/dist/chunk-KAOEMCTI.js +0 -17
  82. package/dist/chunk-MLKGABMK.js +0 -9
  83. package/dist/chunk-XMCPKVJQ.js +0 -34
  84. package/dist/config-inq6kP6y.d.ts +0 -26
  85. package/dist/fetch-W5EHIBOE.js +0 -21
  86. package/dist/remark-heading-BPCoYwjn.d.ts +0 -31
  87. package/dist/server/index.d.ts +0 -117
  88. package/dist/server/index.js +0 -202
  89. package/dist/sidebar.d.ts +0 -33
  90. package/dist/sidebar.js +0 -89
  91. package/dist/static-VESU2S64.js +0 -61
  92. package/dist/types-Ch8gnVgO.d.ts +0 -8
package/README.md CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  The core library for Fumadocs.
4
4
 
5
- 📘 Learn More: [Documentation](https://fumadocs.vercel.app)
5
+ 📘 Learn More: [Documentation](https://fumadocs.dev)
@@ -0,0 +1,58 @@
1
+ import {
2
+ createContentHighlighter
3
+ } from "./chunk-OTD7MV33.js";
4
+ import "./chunk-U67V476Y.js";
5
+
6
+ // src/search/client/algolia.ts
7
+ function groupResults(hits) {
8
+ const grouped = [];
9
+ const scannedUrls = /* @__PURE__ */ new Set();
10
+ for (const hit of hits) {
11
+ if (!scannedUrls.has(hit.url)) {
12
+ scannedUrls.add(hit.url);
13
+ grouped.push({
14
+ id: hit.url,
15
+ type: "page",
16
+ breadcrumbs: hit.breadcrumbs,
17
+ url: hit.url,
18
+ content: hit.title
19
+ });
20
+ }
21
+ grouped.push({
22
+ id: hit.objectID,
23
+ type: hit.content === hit.section ? "heading" : "text",
24
+ url: hit.section_id ? `${hit.url}#${hit.section_id}` : hit.url,
25
+ content: hit.content
26
+ });
27
+ }
28
+ return grouped;
29
+ }
30
+ async function searchDocs(query, { indexName, onSearch, client, locale, tag }) {
31
+ if (query.trim().length === 0) return [];
32
+ const result = onSearch ? await onSearch(query, tag, locale) : await client.searchForHits({
33
+ requests: [
34
+ {
35
+ type: "default",
36
+ indexName,
37
+ query,
38
+ distinct: 5,
39
+ hitsPerPage: 10,
40
+ filters: tag ? `tag:${tag}` : void 0
41
+ }
42
+ ]
43
+ });
44
+ const highlighter = createContentHighlighter(query);
45
+ return groupResults(result.results[0].hits).flatMap((hit) => {
46
+ if (hit.type === "page") {
47
+ return {
48
+ ...hit,
49
+ contentWithHighlights: hit.contentWithHighlights ?? highlighter.highlight(hit.content)
50
+ };
51
+ }
52
+ return [];
53
+ });
54
+ }
55
+ export {
56
+ groupResults,
57
+ searchDocs
58
+ };
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { R as Root, N as Node } from './page-tree-BG3wP0gU.js';
2
+ import { R as Root, N as Node } from './definitions-BRsJlZ6m.js';
3
3
 
4
4
  interface BreadcrumbItem {
5
5
  name: ReactNode;
@@ -7,18 +7,20 @@ interface BreadcrumbItem {
7
7
  }
8
8
  interface BreadcrumbOptions {
9
9
  /**
10
- * Include the root itself in the breadcrumb items array.
11
- * Specify the url by passing an object instead
10
+ * Include the root folders in the breadcrumb items array.
12
11
  *
13
12
  * @defaultValue false
14
13
  */
15
14
  includeRoot?: boolean | {
15
+ /**
16
+ * Specify the url of root
17
+ */
16
18
  url: string;
17
19
  };
18
20
  /**
19
21
  * Include the page itself in the breadcrumb items array
20
22
  *
21
- * @defaultValue true
23
+ * @defaultValue false
22
24
  */
23
25
  includePage?: boolean;
24
26
  /**
@@ -37,7 +39,7 @@ declare function getBreadcrumbItemsFromPath(tree: Root, path: Node[], options: B
37
39
  * - When the page doesn't exist, return null
38
40
  *
39
41
  * @returns The path to the target node from root
40
- * @internal
42
+ * @internal Don't use this on your own
41
43
  */
42
44
  declare function searchPath(nodes: Node[], url: string): Node[] | null;
43
45
 
@@ -1,4 +1,10 @@
1
- import "./chunk-MLKGABMK.js";
1
+ import {
2
+ normalizeUrl
3
+ } from "./chunk-PFNP6PEB.js";
4
+ import {
5
+ findPath
6
+ } from "./chunk-IZPLHEX4.js";
7
+ import "./chunk-U67V476Y.js";
2
8
 
3
9
  // src/breadcrumb.tsx
4
10
  import { useMemo } from "react";
@@ -16,33 +22,42 @@ function getBreadcrumbItems(url, tree, options = {}) {
16
22
  );
17
23
  }
18
24
  function getBreadcrumbItemsFromPath(tree, path, options) {
19
- const { includePage = true, includeSeparator = false, includeRoot } = options;
25
+ const {
26
+ includePage = false,
27
+ includeSeparator = false,
28
+ includeRoot = false
29
+ } = options;
20
30
  let items = [];
21
- path.forEach((item, i) => {
22
- if (item.type === "separator" && includeSeparator) {
23
- items.push({
24
- name: item.name
25
- });
31
+ for (let i = 0; i < path.length; i++) {
32
+ const item = path[i];
33
+ switch (item.type) {
34
+ case "page":
35
+ if (includePage)
36
+ items.push({
37
+ name: item.name,
38
+ url: item.url
39
+ });
40
+ break;
41
+ case "folder":
42
+ if (item.root && !includeRoot) {
43
+ items = [];
44
+ break;
45
+ }
46
+ if (i === path.length - 1 || item.index !== path[i + 1]) {
47
+ items.push({
48
+ name: item.name,
49
+ url: item.index?.url
50
+ });
51
+ }
52
+ break;
53
+ case "separator":
54
+ if (item.name && includeSeparator)
55
+ items.push({
56
+ name: item.name
57
+ });
58
+ break;
26
59
  }
27
- if (item.type === "folder") {
28
- const next = path.at(i + 1);
29
- if (next && item.index === next) return;
30
- if (item.root) {
31
- items = [];
32
- return;
33
- }
34
- items.push({
35
- name: item.name,
36
- url: item.index?.url
37
- });
38
- }
39
- if (item.type === "page" && includePage) {
40
- items.push({
41
- name: item.name,
42
- url: item.url
43
- });
44
- }
45
- });
60
+ }
46
61
  if (includeRoot) {
47
62
  items.unshift({
48
63
  name: tree.name,
@@ -52,32 +67,11 @@ function getBreadcrumbItemsFromPath(tree, path, options) {
52
67
  return items;
53
68
  }
54
69
  function searchPath(nodes, url) {
55
- if (url.endsWith("/")) url = url.slice(0, -1);
56
- let separator;
57
- for (const node of nodes) {
58
- if (node.type === "separator") separator = node;
59
- if (node.type === "folder") {
60
- if (node.index?.url === url) {
61
- const items2 = [];
62
- if (separator) items2.push(separator);
63
- items2.push(node, node.index);
64
- return items2;
65
- }
66
- const items = searchPath(node.children, url);
67
- if (items) {
68
- items.unshift(node);
69
- if (separator) items.unshift(separator);
70
- return items;
71
- }
72
- }
73
- if (node.type === "page" && node.url === url) {
74
- const items = [];
75
- if (separator) items.push(separator);
76
- items.push(node);
77
- return items;
78
- }
79
- }
80
- return null;
70
+ const normalizedUrl = normalizeUrl(url);
71
+ return findPath(
72
+ nodes,
73
+ (node) => node.type === "page" && node.url === normalizedUrl
74
+ );
81
75
  }
82
76
  export {
83
77
  getBreadcrumbItems,
@@ -0,0 +1,296 @@
1
+ import { R as Root, I as Item, F as Folder, S as Separator } from './definitions-BRsJlZ6m.js';
2
+ import { I18nConfig } from './i18n/index.js';
3
+ import { ReactNode } from 'react';
4
+
5
+ interface LoaderPlugin<Page extends PageData = PageData, Meta extends MetaData = MetaData> {
6
+ name?: string;
7
+ /**
8
+ * Change the order of plugin:
9
+ * - `pre`: before normal plugins
10
+ * - `post`: after normal plugins
11
+ */
12
+ enforce?: 'pre' | 'post';
13
+ /**
14
+ * receive & replace loader options
15
+ */
16
+ config?: (config: ResolvedLoaderConfig) => ResolvedLoaderConfig | void | undefined;
17
+ /**
18
+ * transform the storage after loading
19
+ */
20
+ transformStorage?: (context: {
21
+ storage: ContentStorage<Page, Meta>;
22
+ }) => void;
23
+ /**
24
+ * transform the generated page tree
25
+ */
26
+ transformPageTree?: PageTreeTransformer<Page, Meta>;
27
+ }
28
+ declare function buildPlugins(plugins: (LoaderPlugin | LoaderPlugin[] | undefined)[]): LoaderPlugin[];
29
+
30
+ type IconResolver = (icon: string | undefined) => ReactNode;
31
+
32
+ interface LoaderConfig {
33
+ source: SourceConfig;
34
+ i18n: I18nConfig | undefined;
35
+ }
36
+ interface SourceConfig {
37
+ pageData: PageData;
38
+ metaData: MetaData;
39
+ }
40
+ interface LoaderOptions<S extends SourceConfig = SourceConfig, I18n extends I18nConfig | undefined = I18nConfig | undefined> {
41
+ baseUrl: string;
42
+ i18n?: I18n;
43
+ url?: UrlFn;
44
+ /**
45
+ * Additional options for page tree builder
46
+ */
47
+ pageTree?: PageTreeOptions<S['pageData'], S['metaData']>;
48
+ plugins?: (LoaderPlugin<S['pageData'], S['metaData']> | LoaderPlugin<S['pageData'], S['metaData']>[] | undefined)[];
49
+ icon?: IconResolver;
50
+ slugs?: (info: {
51
+ path: string;
52
+ }) => string[];
53
+ }
54
+ interface ResolvedLoaderConfig {
55
+ source: Source;
56
+ url: UrlFn;
57
+ plugins?: LoaderPlugin[];
58
+ pageTree?: PageTreeOptions;
59
+ i18n?: I18nConfig | undefined;
60
+ }
61
+ interface Source<Config extends SourceConfig = SourceConfig> {
62
+ files: VirtualFile<Config>[];
63
+ }
64
+ interface SharedFileInfo {
65
+ /**
66
+ * Virtualized file path (relative to content directory)
67
+ *
68
+ * @example `docs/page.mdx`
69
+ */
70
+ path: string;
71
+ /**
72
+ * Absolute path of the file (can be empty)
73
+ */
74
+ absolutePath: string;
75
+ }
76
+ interface Page<Data = PageData> extends SharedFileInfo {
77
+ slugs: string[];
78
+ url: string;
79
+ data: Data;
80
+ locale?: string | undefined;
81
+ }
82
+ interface Meta<Data = MetaData> extends SharedFileInfo {
83
+ data: Data;
84
+ }
85
+ interface LoaderOutput<Config extends LoaderConfig> {
86
+ pageTree: Config['i18n'] extends I18nConfig ? Record<string, Root> : Root;
87
+ getPageTree: (locale?: string) => Root;
88
+ getPageByHref: (href: string, options?: {
89
+ language?: string;
90
+ /**
91
+ * resolve relative file paths in `href` from specified dirname, must be a virtual path.
92
+ */
93
+ dir?: string;
94
+ }) => {
95
+ page: Page<Config['source']['pageData']>;
96
+ hash?: string;
97
+ } | undefined;
98
+ /**
99
+ * @internal
100
+ */
101
+ _i18n?: I18nConfig;
102
+ /**
103
+ * Get a list of pages from specified language
104
+ *
105
+ * @param language - If empty, list pages from all languages.
106
+ */
107
+ getPages: (language?: string) => Page<Config['source']['pageData']>[];
108
+ /**
109
+ * get each language and its pages, empty if i18n is not enabled.
110
+ */
111
+ getLanguages: () => {
112
+ language: string;
113
+ pages: Page<Config['source']['pageData']>[];
114
+ }[];
115
+ /**
116
+ * Get page with slugs
117
+ *
118
+ * @param language - If empty, the default language will be used
119
+ */
120
+ getPage: (slugs: string[] | undefined, language?: string) => Page<Config['source']['pageData']> | undefined;
121
+ getNodePage: (node: Item, language?: string) => Page<Config['source']['pageData']> | undefined;
122
+ getNodeMeta: (node: Folder, language?: string) => Meta<Config['source']['metaData']> | undefined;
123
+ /**
124
+ * generate static params for Next.js SSG
125
+ *
126
+ * @param slug - customise parameter name for slugs
127
+ * @param lang - customise parameter name for lang
128
+ */
129
+ generateParams: <TSlug extends string = 'slug', TLang extends string = 'lang'>(slug?: TSlug, lang?: TLang) => (Record<TSlug, string[]> & Record<TLang, string>)[];
130
+ }
131
+ declare function createGetUrl(baseUrl: string, i18n?: I18nConfig): UrlFn;
132
+ declare function loader<Config extends SourceConfig, I18n extends I18nConfig | undefined = undefined>(source: Source<Config>, options: LoaderOptions<NoInfer<Config>, I18n>): LoaderOutput<{
133
+ source: Config;
134
+ i18n: I18n;
135
+ }>;
136
+ declare function loader<Config extends SourceConfig, I18n extends I18nConfig | undefined = undefined>(options: LoaderOptions<NoInfer<Config>, I18n> & {
137
+ source: Source<Config>;
138
+ }): LoaderOutput<{
139
+ source: Config;
140
+ i18n: I18n;
141
+ }>;
142
+ type _ConfigUnion_<T extends Record<string, Source>> = {
143
+ [K in keyof T]: T[K] extends Source<infer Config> ? {
144
+ pageData: Config['pageData'] & {
145
+ type: K;
146
+ };
147
+ metaData: Config['metaData'] & {
148
+ type: K;
149
+ };
150
+ } : never;
151
+ }[keyof T];
152
+ declare function multiple<T extends Record<string, Source>>(sources: T): Source<_ConfigUnion_<T>>;
153
+ /**
154
+ * map virtual files in source
155
+ */
156
+ declare function map<Config extends SourceConfig>(source: Source<Config>): {
157
+ page<$Page extends PageData>(fn: (entry: VirtualPage<Config["pageData"]>) => VirtualPage<$Page>): Source<{
158
+ pageData: $Page;
159
+ metaData: Config["metaData"];
160
+ }>;
161
+ meta<$Meta extends MetaData>(fn: (entry: VirtualMeta<Config["metaData"]>) => VirtualMeta<$Meta>): Source<{
162
+ pageData: Config["pageData"];
163
+ metaData: $Meta;
164
+ }>;
165
+ };
166
+
167
+ interface MetaData {
168
+ icon?: string | undefined;
169
+ title?: string | undefined;
170
+ root?: boolean | undefined;
171
+ pages?: string[] | undefined;
172
+ defaultOpen?: boolean | undefined;
173
+ description?: string | undefined;
174
+ }
175
+ interface PageData {
176
+ icon?: string | undefined;
177
+ title?: string;
178
+ description?: string | undefined;
179
+ }
180
+ interface BaseVirtualFile {
181
+ /**
182
+ * Virtualized path (relative to content directory)
183
+ *
184
+ * @example `docs/page.mdx`
185
+ */
186
+ path: string;
187
+ /**
188
+ * Absolute path of the file
189
+ */
190
+ absolutePath?: string;
191
+ }
192
+ interface VirtualPage<Data extends PageData> extends BaseVirtualFile {
193
+ type: 'page';
194
+ /**
195
+ * Specified Slugs for page
196
+ */
197
+ slugs?: string[];
198
+ data: Data;
199
+ }
200
+ interface VirtualMeta<Data extends MetaData> extends BaseVirtualFile {
201
+ type: 'meta';
202
+ data: Data;
203
+ }
204
+ type VirtualFile<Config extends SourceConfig = SourceConfig> = VirtualPage<Config['pageData']> | VirtualMeta<Config['metaData']>;
205
+ type InferPageType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Page<Config['source']['pageData']> : never;
206
+ type InferMetaType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Meta<Config['source']['metaData']> : never;
207
+ /**
208
+ * @internal
209
+ */
210
+ type UrlFn = (slugs: string[], locale?: string) => string;
211
+
212
+ /**
213
+ * In memory file system.
214
+ */
215
+ declare class FileSystem<File> {
216
+ files: Map<string, File>;
217
+ folders: Map<string, string[]>;
218
+ constructor(inherit?: FileSystem<File>);
219
+ read(path: string): File | undefined;
220
+ /**
221
+ * get the direct children of folder (in virtual file path)
222
+ */
223
+ readDir(path: string): string[] | undefined;
224
+ write(path: string, file: File): void;
225
+ /**
226
+ * Delete files at specified path.
227
+ *
228
+ * @param path - the target path.
229
+ * @param [recursive=false] - if set to `true`, it will also delete directories.
230
+ */
231
+ delete(path: string, recursive?: boolean): boolean;
232
+ getFiles(): string[];
233
+ makeDir(path: string): void;
234
+ }
235
+
236
+ type ContentStorage<Page extends PageData = PageData, Meta extends MetaData = MetaData> = FileSystem<MetaFile<Meta> | PageFile<Page>>;
237
+ interface MetaFile<Data extends MetaData = MetaData> {
238
+ path: string;
239
+ absolutePath: string;
240
+ format: 'meta';
241
+ data: Data;
242
+ }
243
+ interface PageFile<Data extends PageData = PageData> {
244
+ path: string;
245
+ absolutePath: string;
246
+ format: 'page';
247
+ slugs: string[];
248
+ data: Data;
249
+ }
250
+
251
+ interface PageTreeBuilderContext<Page extends PageData = PageData, Meta extends MetaData = MetaData> {
252
+ /**
253
+ * @internal resolve paths without extensions
254
+ */
255
+ resolveName: (name: string, format: 'meta' | 'page') => string;
256
+ options: PageTreeOptions;
257
+ transformers: PageTreeTransformer<Page, Meta>[];
258
+ builder: PageTreeBuilder;
259
+ storage: ContentStorage<Page, Meta>;
260
+ getUrl: UrlFn;
261
+ storages?: Record<string, ContentStorage<Page, Meta>>;
262
+ locale?: string;
263
+ visitedPaths: Set<string>;
264
+ }
265
+ interface PageTreeTransformer<Page extends PageData = PageData, Meta extends MetaData = MetaData> {
266
+ file?: (this: PageTreeBuilderContext<Page, Meta>, node: Item, filePath?: string) => Item;
267
+ folder?: (this: PageTreeBuilderContext<Page, Meta>, node: Folder, folderPath: string, metaPath?: string) => Folder;
268
+ separator?: (this: PageTreeBuilderContext<Page, Meta>, node: Separator) => Separator;
269
+ root?: (this: PageTreeBuilderContext<Page, Meta>, node: Root) => Root;
270
+ }
271
+ interface PageTreeOptions<Page extends PageData = PageData, Meta extends MetaData = MetaData> {
272
+ id?: string;
273
+ /**
274
+ * Remove references to the file path of original nodes (`$ref`)
275
+ *
276
+ * @defaultValue false
277
+ */
278
+ noRef?: boolean;
279
+ /**
280
+ * generate fallback page tree
281
+ *
282
+ * @defaultValue true
283
+ */
284
+ generateFallback?: boolean;
285
+ /**
286
+ * Additional page tree transformers to apply
287
+ */
288
+ transformers?: PageTreeTransformer<Page, Meta>[];
289
+ }
290
+ interface PageTreeBuilder {
291
+ build: (storage: ContentStorage, options?: PageTreeOptions) => Root;
292
+ buildI18n: (storages: Record<string, ContentStorage>, options?: PageTreeOptions) => Record<string, Root>;
293
+ }
294
+ declare function createPageTreeBuilder(getUrl: UrlFn, plugins?: LoaderPlugin[]): PageTreeBuilder;
295
+
296
+ export { type ContentStorage as C, FileSystem as F, type InferPageType as I, type LoaderPlugin as L, type MetaFile as M, type PageTreeTransformer as P, type ResolvedLoaderConfig as R, type SourceConfig as S, type UrlFn as U, type VirtualPage as V, type _ConfigUnion_ as _, type PageTreeBuilder as a, type PageTreeBuilderContext as b, createPageTreeBuilder as c, type PageTreeOptions as d, type PageFile as e, type LoaderConfig as f, type LoaderOptions as g, type Source as h, type Page as i, type Meta as j, type LoaderOutput as k, createGetUrl as l, loader as m, multiple as n, map as o, type MetaData as p, type PageData as q, type VirtualMeta as r, type VirtualFile as s, type InferMetaType as t, buildPlugins as u };
@@ -12,24 +12,22 @@ var FrameworkContext = createContext("FrameworkContext", {
12
12
  usePathname: notImplemented
13
13
  });
14
14
  function FrameworkProvider({
15
- children,
16
- ...props
15
+ Link: Link2,
16
+ useRouter: useRouter2,
17
+ useParams: useParams2,
18
+ usePathname: usePathname2,
19
+ Image: Image2,
20
+ children
17
21
  }) {
18
22
  const framework = React.useMemo(
19
23
  () => ({
20
- usePathname: props.usePathname,
21
- useRouter: props.useRouter,
22
- Link: props.Link,
23
- Image: props.Image,
24
- useParams: props.useParams
24
+ usePathname: usePathname2,
25
+ useRouter: useRouter2,
26
+ Link: Link2,
27
+ Image: Image2,
28
+ useParams: useParams2
25
29
  }),
26
- [
27
- props.Link,
28
- props.usePathname,
29
- props.useRouter,
30
- props.useParams,
31
- props.Image
32
- ]
30
+ [Link2, usePathname2, useRouter2, useParams2, Image2]
33
31
  );
34
32
  return /* @__PURE__ */ jsx(FrameworkContext.Provider, { value: framework, children });
35
33
  }
@@ -4,13 +4,6 @@ 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
- }
14
7
  return a !== b;
15
8
  }
16
9
  function useOnChange(value, onChange, isUpdated = isDifferent) {
@@ -0,0 +1,20 @@
1
+ // src/source/plugins/icon.ts
2
+ function iconPlugin(resolveIcon) {
3
+ function replaceIcon(node) {
4
+ if (node.icon === void 0 || typeof node.icon === "string")
5
+ node.icon = resolveIcon(node.icon);
6
+ return node;
7
+ }
8
+ return {
9
+ name: "fumadocs:icon",
10
+ transformPageTree: {
11
+ file: replaceIcon,
12
+ folder: replaceIcon,
13
+ separator: replaceIcon
14
+ }
15
+ };
16
+ }
17
+
18
+ export {
19
+ iconPlugin
20
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Link
3
- } from "./chunk-FVY6EZ3N.js";
3
+ } from "./chunk-BBP7MIO4.js";
4
4
 
5
5
  // src/link.tsx
6
6
  import { forwardRef } from "react";
@@ -8,7 +8,9 @@ import { jsx } from "react/jsx-runtime";
8
8
  var Link2 = forwardRef(
9
9
  ({
10
10
  href = "#",
11
- external = !(href.startsWith("/") || href.startsWith("#") || href.startsWith(".")),
11
+ // any protocol
12
+ external = href.match(/^\w+:/) || // protocol relative URL
13
+ href.startsWith("//"),
12
14
  prefetch,
13
15
  ...props
14
16
  }, ref) => {