fumadocs-core 15.7.13 → 15.8.1

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,6 +1,6 @@
1
1
  import {
2
2
  createContentHighlighter
3
- } from "./chunk-CNWEGOUF.js";
3
+ } from "./chunk-OTD7MV33.js";
4
4
  import "./chunk-JSBRDJBE.js";
5
5
 
6
6
  // src/search/client/algolia.ts
@@ -13,6 +13,7 @@ function groupResults(hits) {
13
13
  grouped.push({
14
14
  id: hit.url,
15
15
  type: "page",
16
+ breadcrumbs: hit.breadcrumbs,
16
17
  url: hit.url,
17
18
  content: hit.title
18
19
  });
@@ -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,6 +1,9 @@
1
1
  import {
2
2
  normalizeUrl
3
3
  } from "./chunk-PFNP6PEB.js";
4
+ import {
5
+ findPath
6
+ } from "./chunk-HV3YIUWE.js";
4
7
  import "./chunk-JSBRDJBE.js";
5
8
 
6
9
  // src/breadcrumb.tsx
@@ -19,33 +22,42 @@ function getBreadcrumbItems(url, tree, options = {}) {
19
22
  );
20
23
  }
21
24
  function getBreadcrumbItemsFromPath(tree, path, options) {
22
- const { includePage = true, includeSeparator = false, includeRoot } = options;
25
+ const {
26
+ includePage = false,
27
+ includeSeparator = false,
28
+ includeRoot = false
29
+ } = options;
23
30
  let items = [];
24
- path.forEach((item, i) => {
25
- if (item.type === "separator" && item.name && includeSeparator) {
26
- items.push({
27
- name: item.name
28
- });
29
- }
30
- if (item.type === "folder") {
31
- const next = path.at(i + 1);
32
- if (next && item.index === next) return;
33
- if (item.root) {
34
- items = [];
35
- return;
36
- }
37
- items.push({
38
- name: item.name,
39
- url: item.index?.url
40
- });
41
- }
42
- if (item.type === "page" && includePage) {
43
- items.push({
44
- name: item.name,
45
- url: item.url
46
- });
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;
47
59
  }
48
- });
60
+ }
49
61
  if (includeRoot) {
50
62
  items.unshift({
51
63
  name: tree.name,
@@ -55,34 +67,11 @@ function getBreadcrumbItemsFromPath(tree, path, options) {
55
67
  return items;
56
68
  }
57
69
  function searchPath(nodes, url) {
58
- const items = [];
59
- url = normalizeUrl(url);
60
- function run(nodes2) {
61
- let separator;
62
- for (const node of nodes2) {
63
- if (node.type === "separator") separator = node;
64
- if (node.type === "folder") {
65
- if (node.index?.url === url) {
66
- if (separator) items.push(separator);
67
- items.push(node, node.index);
68
- return true;
69
- }
70
- if (run(node.children)) {
71
- items.unshift(node);
72
- if (separator) items.unshift(separator);
73
- return true;
74
- }
75
- }
76
- if (node.type === "page" && node.url === url) {
77
- if (separator) items.push(separator);
78
- items.push(node);
79
- return true;
80
- }
81
- }
82
- return false;
83
- }
84
- if (run(nodes)) return items;
85
- return null;
70
+ const normalizedUrl = normalizeUrl(url);
71
+ return findPath(
72
+ nodes,
73
+ (node) => node.type === "page" && node.url === normalizedUrl
74
+ );
86
75
  }
87
76
  export {
88
77
  getBreadcrumbItems,
@@ -0,0 +1,108 @@
1
+ // src/utils/page-tree.tsx
2
+ function flattenTree(nodes) {
3
+ const out = [];
4
+ for (const node of nodes) {
5
+ if (node.type === "folder") {
6
+ if (node.index) out.push(node.index);
7
+ out.push(...flattenTree(node.children));
8
+ } else if (node.type === "page") {
9
+ out.push(node);
10
+ }
11
+ }
12
+ return out;
13
+ }
14
+ function findNeighbour(tree, url, options) {
15
+ const { separateRoot = true } = options ?? {};
16
+ const roots = separateRoot ? getPageTreeRoots(tree) : [tree];
17
+ if (tree.fallback) roots.push(tree.fallback);
18
+ for (const root of roots) {
19
+ const list = flattenTree(root.children);
20
+ const idx = list.findIndex((item) => item.url === url);
21
+ if (idx === -1) continue;
22
+ return {
23
+ previous: list[idx - 1],
24
+ next: list[idx + 1]
25
+ };
26
+ }
27
+ return {};
28
+ }
29
+ function getPageTreeRoots(pageTree) {
30
+ const result = pageTree.children.flatMap((child) => {
31
+ if (child.type !== "folder") return [];
32
+ const roots = getPageTreeRoots(child);
33
+ if (child.root) roots.push(child);
34
+ return roots;
35
+ });
36
+ if (!("type" in pageTree)) result.push(pageTree);
37
+ return result;
38
+ }
39
+ function separatePageTree(pageTree) {
40
+ return pageTree.children.flatMap((child) => {
41
+ if (child.type !== "folder") return [];
42
+ return {
43
+ name: child.name,
44
+ url: child.index?.url,
45
+ children: child.children
46
+ };
47
+ });
48
+ }
49
+ function getPageTreePeers(tree, url) {
50
+ const parent = findParentFromTree(tree, url);
51
+ if (!parent) return [];
52
+ return parent.children.filter(
53
+ (item) => item.type === "page" && item.url !== url
54
+ );
55
+ }
56
+ function findParentFromTree(node, url) {
57
+ if ("index" in node && node.index?.url === url) {
58
+ return node;
59
+ }
60
+ for (const child of node.children) {
61
+ if (child.type === "folder") {
62
+ const parent = findParentFromTree(child, url);
63
+ if (parent) return parent;
64
+ }
65
+ if (child.type === "page" && child.url === url) {
66
+ return node;
67
+ }
68
+ }
69
+ if ("fallback" in node && node.fallback) {
70
+ return findParentFromTree(node.fallback, url);
71
+ }
72
+ }
73
+ function findPath(nodes, matcher, options = {}) {
74
+ const { includeSeparator = true } = options;
75
+ function run(nodes2) {
76
+ let separator;
77
+ for (const node of nodes2) {
78
+ if (matcher(node)) {
79
+ const items = [];
80
+ if (separator) items.push(separator);
81
+ items.push(node);
82
+ return items;
83
+ }
84
+ if (node.type === "separator" && includeSeparator) {
85
+ separator = node;
86
+ continue;
87
+ }
88
+ if (node.type === "folder") {
89
+ const items = node.index && matcher(node.index) ? [node.index] : run(node.children);
90
+ if (items) {
91
+ items.unshift(node);
92
+ if (separator) items.unshift(separator);
93
+ return items;
94
+ }
95
+ }
96
+ }
97
+ }
98
+ return run(nodes) ?? null;
99
+ }
100
+
101
+ export {
102
+ flattenTree,
103
+ findNeighbour,
104
+ getPageTreeRoots,
105
+ separatePageTree,
106
+ getPageTreePeers,
107
+ findPath
108
+ };
@@ -1,4 +1,4 @@
1
- // src/search/shared.ts
1
+ // src/search/index.ts
2
2
  function escapeRegExp(input) {
3
3
  return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4
4
  }
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-ZMWYLUDP.js";
4
4
  import {
5
5
  createContentHighlighter
6
- } from "./chunk-CNWEGOUF.js";
6
+ } from "./chunk-OTD7MV33.js";
7
7
 
8
8
  // src/search/orama/search/simple.ts
9
9
  import { search } from "@orama/orama";
@@ -21,6 +21,7 @@ async function searchSimple(db, query, params = {}) {
21
21
  return result.hits.map((hit) => ({
22
22
  type: "page",
23
23
  content: hit.document.title,
24
+ breadcrumbs: hit.document.breadcrumbs,
24
25
  contentWithHighlights: highlighter.highlight(hit.document.title),
25
26
  id: hit.document.url,
26
27
  url: hit.document.url
@@ -67,6 +68,7 @@ async function searchAdvanced(db, query, tag = [], {
67
68
  id: pageId,
68
69
  type: "page",
69
70
  content: page.content,
71
+ breadcrumbs: page.breadcrumbs,
70
72
  contentWithHighlights: highlighter.highlight(page.content),
71
73
  url: page.url
72
74
  });
@@ -75,6 +77,7 @@ async function searchAdvanced(db, query, tag = [], {
75
77
  list.push({
76
78
  id: hit.document.id.toString(),
77
79
  content: hit.document.content,
80
+ breadcrumbs: hit.document.breadcrumbs,
78
81
  contentWithHighlights: highlighter.highlight(hit.document.content),
79
82
  type: hit.document.type,
80
83
  url: hit.document.url
@@ -185,7 +185,7 @@ interface CodeBlockTabsOptions {
185
185
  }
186
186
  declare function generateCodeBlockTabs({ persist, defaultValue, triggers, tabs, ...options }: CodeBlockTabsOptions): MdxJsxFlowElement;
187
187
  interface CodeBlockAttributes<Name extends string = string> {
188
- attributes: Partial<Record<Name, string>>;
188
+ attributes: Partial<Record<Name, string | null>>;
189
189
  rest: string;
190
190
  }
191
191
  /**
@@ -235,11 +235,11 @@ function generateCodeBlockTabs({
235
235
  }
236
236
  function parseCodeBlockAttributes(meta, allowedNames) {
237
237
  let str = meta;
238
- const StringRegex = /(?<=^|\s)(?<name>\w+)=(?:"([^"]*)"|'([^']*)')/g;
238
+ const StringRegex = /(?<=^|\s)(?<name>\w+)(?:=(?:"([^"]*)"|'([^']*)'))?/g;
239
239
  const attributes = {};
240
240
  str = str.replaceAll(StringRegex, (match, name, value_1, value_2) => {
241
241
  if (allowedNames && !allowedNames.includes(name)) return match;
242
- attributes[name] = value_1 ?? value_2;
242
+ attributes[name] = value_1 ?? value_2 ?? null;
243
243
  return "";
244
244
  });
245
245
  return {
@@ -270,7 +270,7 @@ var rehypeCodeDefaultOptions = {
270
270
  })
271
271
  ],
272
272
  parseMetaString(meta) {
273
- const parsed = parseCodeBlockAttributes(meta);
273
+ const parsed = parseCodeBlockAttributes(meta, ["title", "tab"]);
274
274
  const data = parsed.attributes;
275
275
  parsed.rest = parseLineNumber(parsed.rest, data);
276
276
  data.__parsed_raw = parsed.rest;
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-ZMWYLUDP.js";
4
4
  import {
5
5
  createContentHighlighter
6
- } from "./chunk-CNWEGOUF.js";
6
+ } from "./chunk-OTD7MV33.js";
7
7
  import "./chunk-JSBRDJBE.js";
8
8
 
9
9
  // src/search/client/orama-cloud.ts
@@ -69,6 +69,7 @@ async function searchDocs(query, options) {
69
69
  id: doc.page_id,
70
70
  type: "page",
71
71
  content: doc.title,
72
+ breadcrumbs: doc.breadcrumbs,
72
73
  contentWithHighlights: highlighter.highlight(doc.title),
73
74
  url: doc.url
74
75
  });
@@ -11,6 +11,7 @@ interface DocumentRecord {
11
11
  _id: string;
12
12
  title: string;
13
13
  description?: string;
14
+ breadcrumbs?: string[];
14
15
  /**
15
16
  * URL to the page
16
17
  */
@@ -67,6 +68,7 @@ interface BaseIndex {
67
68
  * Heading (anchor) id
68
69
  */
69
70
  section_id?: string;
71
+ breadcrumbs?: string[];
70
72
  content: string;
71
73
  }
72
74
 
@@ -16,7 +16,8 @@ async function setIndexSettings(client, indexName) {
16
16
  "section",
17
17
  "content",
18
18
  "url",
19
- "section_id"
19
+ "section_id",
20
+ "breadcrumbs"
20
21
  ],
21
22
  searchableAttributes: ["title", "section", "content"],
22
23
  attributesToSnippet: [],
@@ -31,6 +32,7 @@ function toIndex(page) {
31
32
  function createIndex(section, sectionId, content) {
32
33
  return {
33
34
  objectID: `${page._id}-${(id++).toString()}`,
35
+ breadcrumbs: page.breadcrumbs,
34
36
  title: page.title,
35
37
  url: page.url,
36
38
  page_id: page._id,
@@ -4,11 +4,12 @@ import { BaseIndex } from './algolia.js';
4
4
  import { LiteClient, SearchResponse } from 'algoliasearch/lite';
5
5
  import { OramaClient, ClientSearchParams } from '@oramacloud/client';
6
6
  import Mixedbread from '@mixedbread/sdk';
7
- import { S as SortedResult } from '../shared-ORgOfXFw.js';
7
+ import { SortedResult } from './index.js';
8
8
  import 'mdast';
9
9
  import 'unified';
10
10
  import 'mdast-util-mdx-jsx';
11
11
  import 'algoliasearch';
12
+ import 'react';
12
13
 
13
14
  interface FetchOptions {
14
15
  /**
@@ -69,15 +69,15 @@ function useDocsSearch(clientOptions, _locale, _tag, _delayMs = 100, _allowEmpty
69
69
  return fetchDocs(debouncedValue, client);
70
70
  }
71
71
  if (client.type === "algolia") {
72
- const { searchDocs } = await import("../algolia-KPRGMSJO.js");
72
+ const { searchDocs } = await import("../algolia-Z232AL35.js");
73
73
  return searchDocs(debouncedValue, client);
74
74
  }
75
75
  if (client.type === "orama-cloud") {
76
- const { searchDocs } = await import("../orama-cloud-TXCWJTK3.js");
76
+ const { searchDocs } = await import("../orama-cloud-GMFFJOIB.js");
77
77
  return searchDocs(debouncedValue, client);
78
78
  }
79
79
  if (client.type === "static") {
80
- const { search: search2 } = await import("../static-PIZYNE45.js");
80
+ const { search: search2 } = await import("../static-UVSWNGTY.js");
81
81
  return search2(debouncedValue, client);
82
82
  }
83
83
  if (client.type === "mixedbread") {
@@ -0,0 +1,26 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ interface SortedResult<Content = string> {
4
+ id: string;
5
+ url: string;
6
+ type: 'page' | 'heading' | 'text';
7
+ content: Content;
8
+ /**
9
+ * breadcrumbs to be displayed on UI
10
+ */
11
+ breadcrumbs?: Content[];
12
+ contentWithHighlights?: HighlightedText<Content>[];
13
+ }
14
+ type ReactSortedResult = SortedResult<ReactNode>;
15
+ interface HighlightedText<Content = string> {
16
+ type: 'text';
17
+ content: Content;
18
+ styles?: {
19
+ highlight?: boolean;
20
+ };
21
+ }
22
+ declare function createContentHighlighter(query: string | RegExp): {
23
+ highlight(content: string): HighlightedText[];
24
+ };
25
+
26
+ export { type HighlightedText, type ReactSortedResult, type SortedResult, createContentHighlighter };
@@ -0,0 +1,7 @@
1
+ import {
2
+ createContentHighlighter
3
+ } from "../chunk-OTD7MV33.js";
4
+ import "../chunk-JSBRDJBE.js";
5
+ export {
6
+ createContentHighlighter
7
+ };
@@ -50,6 +50,7 @@ interface OramaDocument {
50
50
  * Data to be added to each section index
51
51
  */
52
52
  extra_data?: object;
53
+ breadcrumbs?: string[];
53
54
  }
54
55
  interface OramaIndex {
55
56
  id: string;
@@ -64,6 +65,7 @@ interface OramaIndex {
64
65
  * Heading content
65
66
  */
66
67
  section?: string;
68
+ breadcrumbs?: string[];
67
69
  /**
68
70
  * Heading (anchor) id
69
71
  */
@@ -30,6 +30,7 @@ function toIndex(page) {
30
30
  section,
31
31
  section_id: sectionId,
32
32
  content,
33
+ breadcrumbs: page.breadcrumbs,
33
34
  ...page.extra_data
34
35
  };
35
36
  }
@@ -1,7 +1,7 @@
1
1
  import { TypedDocument, Orama, Language, RawData, create, SearchParams } from '@orama/orama';
2
2
  import { S as StructuredData } from '../remark-structure-DkCXCzpD.js';
3
- import { S as SortedResult } from '../shared-ORgOfXFw.js';
4
- export { H as HighlightedText, c as createContentHighlighter } from '../shared-ORgOfXFw.js';
3
+ import { SortedResult } from './index.js';
4
+ export { HighlightedText, ReactSortedResult, createContentHighlighter } from './index.js';
5
5
  import { I18nConfig } from '../i18n/index.js';
6
6
  import { LoaderOutput, LoaderConfig, InferPageType } from '../source/index.js';
7
7
  import 'mdast';
@@ -10,23 +10,25 @@ import 'mdast-util-mdx-jsx';
10
10
  import 'react';
11
11
  import '../definitions-Q95-psoo.js';
12
12
 
13
+ type SimpleDocument = TypedDocument<Orama<typeof simpleSchema>>;
14
+ declare const simpleSchema: {
15
+ readonly url: "string";
16
+ readonly title: "string";
17
+ readonly breadcrumbs: "string[]";
18
+ readonly description: "string";
19
+ readonly content: "string";
20
+ readonly keywords: "string";
21
+ };
13
22
  type AdvancedDocument = TypedDocument<Orama<typeof advancedSchema>>;
14
23
  declare const advancedSchema: {
15
24
  readonly content: "string";
16
25
  readonly page_id: "string";
17
26
  readonly type: "string";
27
+ readonly breadcrumbs: "string[]";
18
28
  readonly tags: "enum[]";
19
29
  readonly url: "string";
20
30
  readonly embeddings: "vector[512]";
21
31
  };
22
- type SimpleDocument = TypedDocument<Orama<typeof simpleSchema>>;
23
- declare const simpleSchema: {
24
- readonly url: "string";
25
- readonly title: "string";
26
- readonly description: "string";
27
- readonly content: "string";
28
- readonly keywords: "string";
29
- };
30
32
 
31
33
  type Awaitable<T> = T | Promise<T>;
32
34
  interface Options<S extends LoaderOutput<LoaderConfig>> extends Omit<AdvancedOptions, 'indexes'> {
@@ -112,6 +114,7 @@ declare function createSearchAPI<T extends SearchType>(type: T, options: T exten
112
114
  interface Index {
113
115
  title: string;
114
116
  description?: string;
117
+ breadcrumbs?: string[];
115
118
  content: string;
116
119
  url: string;
117
120
  keywords?: string;
@@ -125,6 +128,7 @@ interface AdvancedIndex {
125
128
  * @deprecated No longer used
126
129
  */
127
130
  keywords?: string;
131
+ breadcrumbs?: string[];
128
132
  /**
129
133
  * Required if tag filter is enabled
130
134
  */