@farming-labs/theme 0.0.33-beta.1 → 0.0.34

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,3 +1,6 @@
1
+ import * as react from "react";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+
1
4
  //#region src/ai-search-dialog.d.ts
2
5
  type AIModelOption = {
3
6
  id: string;
@@ -24,7 +27,7 @@ declare function DocsSearchDialog({
24
27
  loadingComponentHtml?: string;
25
28
  models?: AIModelOption[];
26
29
  defaultModelId?: string;
27
- }): any;
30
+ }): react.ReactPortal | null;
28
31
  type FloatingPosition = "bottom-right" | "bottom-left" | "bottom-center";
29
32
  type FloatingStyle = "panel" | "modal" | "popover" | "full-modal";
30
33
  declare function FloatingAIChat({
@@ -49,7 +52,7 @@ declare function FloatingAIChat({
49
52
  loadingComponentHtml?: string;
50
53
  models?: AIModelOption[];
51
54
  defaultModelId?: string;
52
- }): any;
55
+ }): react_jsx_runtime0.JSX.Element | null;
53
56
  declare function AIModalDialog({
54
57
  open,
55
58
  onOpenChange,
@@ -70,6 +73,6 @@ declare function AIModalDialog({
70
73
  loadingComponentHtml?: string;
71
74
  models?: AIModelOption[];
72
75
  defaultModelId?: string;
73
- }): any;
76
+ }): react.ReactPortal | null;
74
77
  //#endregion
75
78
  export { AIModalDialog, DocsSearchDialog, FloatingAIChat };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import { useCallback, useEffect, useRef, useState } from "react";
4
- import { createPortal } from "react-dom";
5
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { createPortal } from "react-dom";
6
6
  import { highlight } from "sugar-high";
7
7
 
8
8
  //#region src/ai-search-dialog.tsx
@@ -0,0 +1,43 @@
1
+ "use client";
2
+
3
+ import { useSyncExternalStore } from "react";
4
+
5
+ //#region src/client-location.ts
6
+ function patchHistoryEvents() {
7
+ if (typeof window === "undefined" || window.__fdHistoryPatched) return;
8
+ const wrap = (method) => {
9
+ const original = window.history[method];
10
+ window.history[method] = function patchedHistoryMethod(...args) {
11
+ const result = original.apply(this, args);
12
+ window.dispatchEvent(new Event("fd-location-change"));
13
+ return result;
14
+ };
15
+ };
16
+ wrap("pushState");
17
+ wrap("replaceState");
18
+ window.__fdHistoryPatched = true;
19
+ }
20
+ function subscribe(onStoreChange) {
21
+ if (typeof window === "undefined") return () => {};
22
+ patchHistoryEvents();
23
+ const notify = () => onStoreChange();
24
+ window.addEventListener("popstate", notify);
25
+ window.addEventListener("hashchange", notify);
26
+ window.addEventListener("fd-location-change", notify);
27
+ return () => {
28
+ window.removeEventListener("popstate", notify);
29
+ window.removeEventListener("hashchange", notify);
30
+ window.removeEventListener("fd-location-change", notify);
31
+ };
32
+ }
33
+ function getSnapshot() {
34
+ if (typeof window === "undefined") return "";
35
+ return window.location.search;
36
+ }
37
+ function useWindowSearchParams() {
38
+ const search = useSyncExternalStore(subscribe, getSnapshot, () => "");
39
+ return new URLSearchParams(search);
40
+ }
41
+
42
+ //#endregion
43
+ export { useWindowSearchParams };
@@ -10,7 +10,12 @@ import { jsx } from "react/jsx-runtime";
10
10
  * The actual copy-to-clipboard is still done by the default component.
11
11
  */
12
12
  function createPreWithCopyCallback(DefaultPre, onCopyClick) {
13
- if (!onCopyClick) return typeof DefaultPre === "string" ? DefaultPre : DefaultPre;
13
+ if (!onCopyClick) {
14
+ if (typeof DefaultPre !== "string") return DefaultPre;
15
+ return function NativePre(props) {
16
+ return /* @__PURE__ */ jsx("pre", { ...props });
17
+ };
18
+ }
14
19
  function PreWithCopyCallback(props) {
15
20
  const ref = React$1.useRef(null);
16
21
  React$1.useEffect(() => {
@@ -25,8 +30,9 @@ function createPreWithCopyCallback(DefaultPre, onCopyClick) {
25
30
  const content = code.textContent ?? "";
26
31
  const url = typeof window !== "undefined" ? window.location.href : "";
27
32
  const language = code.getAttribute("data-language") ?? figure.getAttribute("data-language") ?? void 0;
28
- onCopyClick({
29
- title: figure.querySelector("[data-title]")?.textContent?.trim() ?? figure.querySelector(".fd-codeblock-title-text")?.textContent?.trim() ?? void 0,
33
+ const title = figure.querySelector("[data-title]")?.textContent?.trim() ?? figure.querySelector(".fd-codeblock-title-text")?.textContent?.trim() ?? void 0;
34
+ onCopyClick?.({
35
+ title,
30
36
  content,
31
37
  url,
32
38
  language
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
 
3
+ import { useWindowSearchParams } from "./client-location.mjs";
3
4
  import { resolveClientLocale, withLangInUrl } from "./i18n.mjs";
4
5
  import { AIModalDialog, DocsSearchDialog, FloatingAIChat } from "./ai-search-dialog.mjs";
5
6
  import { useEffect, useState } from "react";
6
- import { useSearchParams } from "next/navigation";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
 
9
9
  //#region src/docs-ai-features.tsx
@@ -22,7 +22,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
22
22
  * never needs to be modified — AI features work purely from `docs.config.ts`.
23
23
  */
24
24
  function DocsAIFeatures({ mode, api = "/api/docs", locale, position = "bottom-right", floatingStyle = "panel", triggerComponentHtml, suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml, models, defaultModelId }) {
25
- const localizedApi = withLangInUrl(api, resolveClientLocale(useSearchParams(), locale));
25
+ const localizedApi = withLangInUrl(api, resolveClientLocale(useWindowSearchParams(), locale));
26
26
  if (mode === "search") return /* @__PURE__ */ jsx(SearchModeAI, {
27
27
  api: localizedApi,
28
28
  suggestedQuestions,
package/dist/docs-api.mjs CHANGED
@@ -51,7 +51,7 @@ function readI18nConfig(root) {
51
51
  if (!content.includes("i18n")) continue;
52
52
  const localesMatch = content.match(/i18n\s*:\s*\{[\s\S]*?locales\s*:\s*\[([^\]]+)\]/);
53
53
  if (!localesMatch) continue;
54
- const locales = localesMatch[1].split(",").map((l) => l.trim().replace(/^['\"`]|['\"`]$/g, "")).filter(Boolean);
54
+ const locales = localesMatch[1].split(",").map((l) => l.trim().replace(/^['"`]|['"`]$/g, "")).filter(Boolean);
55
55
  if (locales.length === 0) continue;
56
56
  return {
57
57
  locales,
@@ -1,3 +1,5 @@
1
+ import * as React$1 from "react";
2
+
1
3
  //#region src/docs-command-search.d.ts
2
4
  /**
3
5
  * Built-in docs search command palette.
@@ -11,6 +13,6 @@ declare function DocsCommandSearch({
11
13
  }: {
12
14
  api?: string;
13
15
  locale?: string;
14
- }): any;
16
+ }): React$1.ReactPortal | null;
15
17
  //#endregion
16
18
  export { DocsCommandSearch };
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
 
3
+ import { useWindowSearchParams } from "./client-location.mjs";
3
4
  import { resolveClientLocale, withLangInUrl } from "./i18n.mjs";
4
5
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
- import { createPortal } from "react-dom";
6
- import { useSearchParams } from "next/navigation";
7
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { createPortal } from "react-dom";
8
8
 
9
9
  //#region src/docs-command-search.tsx
10
10
  function cn(...classes) {
@@ -308,7 +308,7 @@ function DocsCommandSearch({ api = "/api/docs", locale }) {
308
308
  const [activeIndex, setActiveIndex] = useState(0);
309
309
  const [recents, setRecents] = useState([]);
310
310
  const [mounted, setMounted] = useState(false);
311
- const activeLocale = resolveClientLocale(useSearchParams(), locale);
311
+ const activeLocale = resolveClientLocale(useWindowSearchParams(), locale);
312
312
  const searchApi = useMemo(() => withLangInUrl(api, activeLocale), [activeLocale, api]);
313
313
  const inputRef = useRef(null);
314
314
  const listRef = useRef(null);
@@ -52,17 +52,25 @@ function resolveDocsI18nConfig(i18n) {
52
52
  }
53
53
  function resolveDocsLocaleContext(config, locale) {
54
54
  const entryBase = config.entry ?? "docs";
55
- const appDir = getNextAppDir(process.cwd());
56
55
  const i18n = resolveDocsI18nConfig(getDocsI18n(config));
56
+ const contentDir = config.contentDir;
57
+ function resolveContentDir(localeValue) {
58
+ if (!contentDir) {
59
+ const appDir = getNextAppDir(process.cwd());
60
+ return path.join(process.cwd(), appDir, entryBase, ...localeValue ? [localeValue] : []);
61
+ }
62
+ const base = path.isAbsolute(contentDir) ? contentDir : path.join(process.cwd(), contentDir);
63
+ return localeValue ? path.join(base, localeValue) : base;
64
+ }
57
65
  if (!i18n) return {
58
66
  entryPath: entryBase,
59
- docsDir: path.join(process.cwd(), appDir, entryBase)
67
+ docsDir: resolveContentDir()
60
68
  };
61
69
  const resolvedLocale = locale && i18n.locales.includes(locale) ? locale : i18n.defaultLocale;
62
70
  return {
63
71
  entryPath: entryBase,
64
72
  locale: resolvedLocale,
65
- docsDir: path.join(process.cwd(), appDir, entryBase, resolvedLocale)
73
+ docsDir: resolveContentDir(resolvedLocale)
66
74
  };
67
75
  }
68
76
  function buildTree(config, ctx, flat = false) {
@@ -467,6 +475,7 @@ function createDocsLayout(config, options) {
467
475
  const githubUrl = typeof githubRaw === "string" ? githubRaw.replace(/\/$/, "") : githubRaw?.url.replace(/\/$/, "");
468
476
  const githubBranch = typeof githubRaw === "object" ? githubRaw.branch ?? "main" : "main";
469
477
  const githubDirectory = typeof githubRaw === "object" ? githubRaw.directory?.replace(/^\/|\/$/g, "") : void 0;
478
+ const contentDir = config.contentDir;
470
479
  const staticExport = !!config.staticExport;
471
480
  const aiConfig = config.ai;
472
481
  const aiEnabled = !staticExport && !!aiConfig?.enabled;
@@ -572,6 +581,7 @@ function createDocsLayout(config, options) {
572
581
  pageActionsPosition,
573
582
  pageActionsAlignment,
574
583
  githubUrl,
584
+ contentDir,
575
585
  githubBranch,
576
586
  githubDirectory,
577
587
  lastModifiedMap,
@@ -25,12 +25,18 @@ interface DocsPageClientProps {
25
25
  pageActionsAlignment?: "left" | "right";
26
26
  /** GitHub repository URL (e.g. "https://github.com/user/repo") */
27
27
  githubUrl?: string;
28
+ /** Path to docs content relative to the repo root (used for Edit on GitHub outside Next.js app/docs) */
29
+ contentDir?: string;
28
30
  /** GitHub branch name @default "main" */
29
31
  githubBranch?: string;
30
32
  /** Subdirectory in the repo where the docs site lives (for monorepos) */
31
33
  githubDirectory?: string;
34
+ /** Direct GitHub URL override for the current page. */
35
+ editOnGithubUrl?: string;
32
36
  /** Map of pathname → formatted last-modified date string */
33
37
  lastModifiedMap?: Record<string, string>;
38
+ /** Direct last-modified value override for the current page. */
39
+ lastModified?: string;
34
40
  /** Whether to show "Last updated" at all */
35
41
  lastUpdatedEnabled?: boolean;
36
42
  /** Where to show the "Last updated" date: "footer" (next to Edit on GitHub) or "below-title" */
@@ -55,9 +61,12 @@ declare function DocsPageClient({
55
61
  pageActionsPosition,
56
62
  pageActionsAlignment,
57
63
  githubUrl,
64
+ contentDir,
58
65
  githubBranch,
59
66
  githubDirectory,
67
+ editOnGithubUrl,
60
68
  lastModifiedMap,
69
+ lastModified: lastModifiedProp,
61
70
  lastUpdatedEnabled,
62
71
  lastUpdatedPosition,
63
72
  llmsTxtEnabled,
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
 
3
3
  import { PageActions } from "./page-actions.mjs";
4
+ import { useWindowSearchParams } from "./client-location.mjs";
4
5
  import { resolveClientLocale, withLangInUrl } from "./i18n.mjs";
5
- import { useEffect, useState } from "react";
6
+ import { Children, cloneElement, isValidElement, useEffect, useState } from "react";
6
7
  import { DocsBody, DocsPage, EditOnGitHub } from "fumadocs-ui/layouts/docs/page";
7
- import { createPortal } from "react-dom";
8
- import { usePathname, useRouter, useSearchParams } from "next/navigation";
8
+ import { usePathname, useRouter } from "fumadocs-core/framework";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
 
11
11
  //#region src/docs-page-client.tsx
@@ -62,13 +62,14 @@ function PathBreadcrumb({ pathname, entry, locale }) {
62
62
  * No directory: https://github.com/user/repo/edit/main/app/docs/cli/page.mdx
63
63
  * With directory: https://github.com/farming-labs/docs/edit/main/website/app/docs/cli/page.mdx
64
64
  */
65
- function buildGithubFileUrl(githubUrl, branch, pathname, entry, locale, directory) {
65
+ function buildGithubFileUrl(githubUrl, branch, pathname, entry, locale, directory, contentDir) {
66
66
  const normalizedEntry = entry.replace(/^\/+|\/+$/g, "") || "docs";
67
+ const normalizedContentDir = contentDir?.replace(/^\/+|\/+$/g, "");
67
68
  const entryParts = normalizedEntry.split("/").filter(Boolean);
68
69
  const pathnameParts = pathname.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
69
70
  const slugParts = pathnameParts.slice(0, entryParts.length).join("/") === entryParts.join("/") ? pathnameParts.slice(entryParts.length) : pathnameParts;
70
71
  const dirPrefix = directory ? `${directory}/` : "";
71
- const basePath = `app/${normalizedEntry}`;
72
+ const basePath = normalizedContentDir || `app/${normalizedEntry}`;
72
73
  const relativePath = [locale, slugParts.join("/")].filter(Boolean).join("/");
73
74
  return `${githubUrl}/edit/${branch}/${`${dirPrefix}${basePath}${relativePath ? `/${relativePath}` : ""}/page.mdx`}`;
74
75
  }
@@ -86,13 +87,44 @@ function localizeInternalLinks(root, locale) {
86
87
  } catch {}
87
88
  }
88
89
  }
89
- function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, entry = "docs", locale, copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, githubBranch = "main", githubDirectory, lastModifiedMap, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, children }) {
90
+ function injectTitleDecorations(node, { description, belowTitle }) {
91
+ if (!description && !belowTitle) return node;
92
+ let inserted = false;
93
+ const extras = [description, belowTitle].filter(Boolean);
94
+ if (extras.length === 0) return node;
95
+ function visit(current) {
96
+ if (current == null || typeof current === "boolean") return current;
97
+ if (inserted) return current;
98
+ if (Array.isArray(current)) return current.flatMap((child) => {
99
+ const next = visit(child);
100
+ return Array.isArray(next) ? next : [next];
101
+ });
102
+ if (!isValidElement(current)) return current;
103
+ if (typeof current.type === "string" && current.type === "h1") {
104
+ inserted = true;
105
+ return [current, ...extras];
106
+ }
107
+ const childProps = current.props ?? null;
108
+ if (childProps?.children === void 0) return current;
109
+ const nextChildren = Children.toArray(childProps.children).flatMap((child) => {
110
+ const next = visit(child);
111
+ return Array.isArray(next) ? next : [next];
112
+ });
113
+ if (!inserted) return current;
114
+ return cloneElement(current, void 0, nextChildren);
115
+ }
116
+ if (Array.isArray(node)) return node.flatMap((child) => {
117
+ const next = visit(child);
118
+ return Array.isArray(next) ? next : [next];
119
+ });
120
+ return visit(node);
121
+ }
122
+ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, entry = "docs", locale, copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, contentDir, githubBranch = "main", githubDirectory, editOnGithubUrl, lastModifiedMap, lastModified: lastModifiedProp, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, children }) {
90
123
  const fdTocStyle = tocStyle === "directional" ? "clerk" : void 0;
91
124
  const [toc, setToc] = useState([]);
92
125
  const pathname = usePathname();
93
- const activeLocale = resolveClientLocale(useSearchParams(), locale);
126
+ const activeLocale = resolveClientLocale(useWindowSearchParams(), locale);
94
127
  const llmsLangParam = activeLocale ? `&lang=${encodeURIComponent(activeLocale)}` : "";
95
- const [actionsPortalTarget, setActionsPortalTarget] = useState(null);
96
128
  const pageDescription = description ?? descriptionMap?.[pathname.replace(/\/$/, "") || "/"];
97
129
  useEffect(() => {
98
130
  if (!tocEnabled) return;
@@ -109,26 +141,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
109
141
  return () => cancelAnimationFrame(timer);
110
142
  }, [tocEnabled, pathname]);
111
143
  useEffect(() => {
112
- if (!pageDescription) return;
113
- const timer = requestAnimationFrame(() => {
114
- const container = document.getElementById("nd-page");
115
- if (!container) return;
116
- const existingDesc = container.querySelector(".fd-page-description");
117
- if (existingDesc) existingDesc.remove();
118
- const h1 = container.querySelector("h1");
119
- if (!h1) return;
120
- const descEl = document.createElement("p");
121
- descEl.className = "fd-page-description";
122
- descEl.textContent = pageDescription;
123
- h1.insertAdjacentElement("afterend", descEl);
124
- });
125
- return () => {
126
- cancelAnimationFrame(timer);
127
- const desc = document.querySelector("#nd-page .fd-page-description");
128
- if (desc) desc.remove();
129
- };
130
- }, [pageDescription, pathname]);
131
- useEffect(() => {
144
+ if (!activeLocale) return;
132
145
  const timer = requestAnimationFrame(() => {
133
146
  const container = document.getElementById("nd-page");
134
147
  if (!container) return;
@@ -141,59 +154,40 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
141
154
  pathname
142
155
  ]);
143
156
  const showActions = copyMarkdown || openDocs;
144
- const githubFileUrl = githubUrl ? buildGithubFileUrl(githubUrl, githubBranch, pathname, entry, activeLocale, githubDirectory) : void 0;
157
+ const showActionsBelowTitle = showActions && pageActionsPosition === "below-title";
158
+ const showActionsAboveTitle = showActions && pageActionsPosition === "above-title";
159
+ const githubFileUrl = editOnGithubUrl ?? (githubUrl ? buildGithubFileUrl(githubUrl, githubBranch, pathname, entry, activeLocale, githubDirectory, contentDir) : void 0);
145
160
  const normalizedPath = pathname.replace(/\/$/, "") || "/";
146
- const lastModified = lastUpdatedEnabled ? lastModifiedMap?.[normalizedPath] : void 0;
161
+ const lastModified = lastUpdatedEnabled ? lastModifiedProp ?? lastModifiedMap?.[normalizedPath] : void 0;
147
162
  const showLastUpdatedBelowTitle = !!lastModified && lastUpdatedPosition === "below-title";
148
163
  const showLastUpdatedInFooter = !!lastModified && lastUpdatedPosition === "footer";
149
164
  const showFooter = !!githubFileUrl || showLastUpdatedInFooter || llmsTxtEnabled;
150
- const needsBelowTitleBlock = showLastUpdatedBelowTitle || showActions;
151
- useEffect(() => {
152
- if (!needsBelowTitleBlock) return;
153
- const timer = requestAnimationFrame(() => {
154
- const container = document.getElementById("nd-page");
155
- if (!container) return;
156
- container.querySelectorAll(".fd-below-title-block").forEach((el) => el.remove());
157
- const h1 = container.querySelector("h1");
158
- if (!h1) return;
159
- let insertAfter = h1;
160
- const desc = container.querySelector(".fd-page-description");
161
- if (desc) insertAfter = desc;
162
- const wrapper = document.createElement("div");
163
- wrapper.className = "fd-below-title-block not-prose";
164
- if (showLastUpdatedBelowTitle) {
165
- const lastUpdatedEl = document.createElement("p");
166
- lastUpdatedEl.className = "fd-last-updated-inline";
167
- lastUpdatedEl.textContent = `Last updated ${lastModified}`;
168
- wrapper.appendChild(lastUpdatedEl);
169
- }
170
- if (showLastUpdatedBelowTitle || showActions) {
171
- const hr = document.createElement("hr");
172
- hr.className = "fd-title-separator";
173
- wrapper.appendChild(hr);
174
- }
175
- if (showActions) {
176
- const portalEl = document.createElement("div");
177
- portalEl.className = "fd-actions-portal";
178
- portalEl.setAttribute("data-actions-alignment", pageActionsAlignment);
179
- wrapper.appendChild(portalEl);
180
- setActionsPortalTarget(portalEl);
181
- }
182
- insertAfter.insertAdjacentElement("afterend", wrapper);
183
- });
184
- return () => {
185
- cancelAnimationFrame(timer);
186
- setActionsPortalTarget(null);
187
- document.querySelectorAll("#nd-page .fd-below-title-block").forEach((el) => el.remove());
188
- };
189
- }, [
190
- lastModified,
191
- needsBelowTitleBlock,
192
- showLastUpdatedBelowTitle,
193
- showActions,
194
- pageActionsAlignment,
195
- pathname
196
- ]);
165
+ const decoratedChildren = injectTitleDecorations(children, {
166
+ description: pageDescription ? /* @__PURE__ */ jsx("p", {
167
+ className: "fd-page-description",
168
+ children: pageDescription
169
+ }) : void 0,
170
+ belowTitle: showLastUpdatedBelowTitle || showActionsBelowTitle ? /* @__PURE__ */ jsxs("div", {
171
+ className: "fd-below-title-block not-prose",
172
+ children: [
173
+ showLastUpdatedBelowTitle && /* @__PURE__ */ jsxs("p", {
174
+ className: "fd-last-updated-inline",
175
+ children: ["Last updated ", lastModified]
176
+ }),
177
+ /* @__PURE__ */ jsx("hr", { className: "fd-title-separator" }),
178
+ showActionsBelowTitle && /* @__PURE__ */ jsx("div", {
179
+ className: "fd-actions-portal",
180
+ "data-actions-alignment": pageActionsAlignment,
181
+ children: /* @__PURE__ */ jsx(PageActions, {
182
+ copyMarkdown,
183
+ openDocs,
184
+ providers: openDocsProviders,
185
+ githubFileUrl
186
+ })
187
+ })
188
+ ]
189
+ }) : void 0
190
+ });
197
191
  return /* @__PURE__ */ jsxs(DocsPage, {
198
192
  toc,
199
193
  tableOfContent: {
@@ -211,12 +205,15 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
211
205
  entry,
212
206
  locale: activeLocale
213
207
  }),
214
- showActions && actionsPortalTarget && createPortal(/* @__PURE__ */ jsx(PageActions, {
215
- copyMarkdown,
216
- openDocs,
217
- providers: openDocsProviders,
218
- githubFileUrl
219
- }), actionsPortalTarget),
208
+ showActionsAboveTitle && /* @__PURE__ */ jsx("div", {
209
+ className: "fd-below-title-block not-prose",
210
+ children: /* @__PURE__ */ jsx(PageActions, {
211
+ copyMarkdown,
212
+ openDocs,
213
+ providers: openDocsProviders,
214
+ githubFileUrl
215
+ })
216
+ }),
220
217
  /* @__PURE__ */ jsxs(DocsBody, {
221
218
  style: {
222
219
  display: "flex",
@@ -224,7 +221,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
224
221
  },
225
222
  children: [/* @__PURE__ */ jsx("div", {
226
223
  style: { flex: 1 },
227
- children
224
+ children: decoratedChildren
228
225
  }), showFooter && /* @__PURE__ */ jsxs("div", {
229
226
  className: "not-prose fd-page-footer",
230
227
  children: [
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
 
3
+ import { useWindowSearchParams } from "./client-location.mjs";
3
4
  import { resolveClientLocale, withLangInUrl } from "./i18n.mjs";
4
5
  import { useEffect, useMemo, useState } from "react";
5
- import { usePathname, useRouter, useSearchParams } from "next/navigation";
6
+ import { usePathname, useRouter } from "fumadocs-core/framework";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
8
 
8
9
  //#region src/locale-theme-control.tsx
@@ -102,7 +103,7 @@ function ChevronDownIcon() {
102
103
  function LocaleThemeControl({ locales, defaultLocale, locale, showThemeToggle = true, themeMode = "light-dark" }) {
103
104
  const router = useRouter();
104
105
  const pathname = usePathname();
105
- const searchParams = useSearchParams();
106
+ const searchParams = useWindowSearchParams();
106
107
  const [mounted, setMounted] = useState(false);
107
108
  const [themeValue, setThemeValue] = useState("system");
108
109
  const [resolvedTheme, setResolvedTheme] = useState("light");
@@ -1,6 +1,6 @@
1
1
  import { ComponentProps } from "react";
2
+ import { Image } from "fumadocs-core/framework";
2
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
3
- import Image from "next/image";
4
4
 
5
5
  //#region src/mdx-img.d.ts
6
6
  type ImgProps = ComponentProps<typeof Image>;
package/dist/mdx-img.mjs CHANGED
@@ -1,14 +1,13 @@
1
1
  "use client";
2
2
 
3
+ import { Image } from "fumadocs-core/framework";
3
4
  import { jsx } from "react/jsx-runtime";
4
- import Image from "next/image";
5
5
 
6
6
  //#region src/mdx-img.tsx
7
7
  /**
8
8
  * MDX image component that works with ![alt](url) when width/height are not provided.
9
- * Fumadocs-ui's default img uses Next.js Image which requires width and height;
10
- * markdown image syntax cannot provide these. This override uses unoptimized Image
11
- * with default dimensions when missing, so external (e.g. GitHub) images work.
9
+ * Fumadocs-ui's framework-aware image component keeps Next.js optimization when available
10
+ * and falls back to a plain <img> in other runtimes.
12
11
  */
13
12
  const DEFAULT_WIDTH = 800;
14
13
  const DEFAULT_HEIGHT = 600;
@@ -19,7 +18,6 @@ function MDXImg(props) {
19
18
  alt,
20
19
  width: width != null ? Number(width) : DEFAULT_WIDTH,
21
20
  height: height != null ? Number(height) : DEFAULT_HEIGHT,
22
- unoptimized: !(width != null && height != null),
23
21
  style: {
24
22
  maxWidth: "100%",
25
23
  height: "auto",
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { useCallback, useEffect, useRef, useState } from "react";
4
- import { usePathname } from "next/navigation";
4
+ import { usePathname } from "fumadocs-core/framework";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
 
7
7
  //#region src/page-actions.tsx
@@ -0,0 +1,14 @@
1
+ import { ComponentPropsWithoutRef } from "react";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { RootProvider as RootProvider$1 } from "fumadocs-ui/provider/tanstack";
4
+
5
+ //#region src/provider-tanstack.d.ts
6
+ type FumadocsProviderProps = ComponentPropsWithoutRef<typeof RootProvider$1>;
7
+ interface DocsTanstackRootProviderProps extends FumadocsProviderProps {}
8
+ declare function RootProvider({
9
+ children,
10
+ search,
11
+ ...props
12
+ }: DocsTanstackRootProviderProps): react_jsx_runtime0.JSX.Element;
13
+ //#endregion
14
+ export { DocsTanstackRootProviderProps, RootProvider };
@@ -0,0 +1,22 @@
1
+ "use client";
2
+
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { RootProvider as RootProvider$1 } from "fumadocs-ui/provider/tanstack";
5
+
6
+ //#region src/provider-tanstack.tsx
7
+ function RootProvider({ children, search, ...props }) {
8
+ return /* @__PURE__ */ jsx(RootProvider$1, {
9
+ search: {
10
+ ...search,
11
+ options: {
12
+ api: "/api/docs",
13
+ ...search?.options
14
+ }
15
+ },
16
+ ...props,
17
+ children
18
+ });
19
+ }
20
+
21
+ //#endregion
22
+ export { RootProvider };
@@ -0,0 +1,45 @@
1
+ import { ReactNode } from "react";
2
+ import { DocsConfig } from "@farming-labs/docs";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region src/tanstack-layout.d.ts
6
+ interface PageNode {
7
+ type: "page";
8
+ name: string;
9
+ url: string;
10
+ icon?: ReactNode;
11
+ }
12
+ interface FolderNode {
13
+ type: "folder";
14
+ name: string;
15
+ icon?: ReactNode;
16
+ index?: PageNode;
17
+ children: (PageNode | FolderNode)[];
18
+ collapsible?: boolean;
19
+ defaultOpen?: boolean;
20
+ }
21
+ type TreeNode = PageNode | FolderNode;
22
+ interface TreeRoot {
23
+ name: string;
24
+ children: TreeNode[];
25
+ }
26
+ interface TanstackDocsLayoutProps {
27
+ config: DocsConfig;
28
+ tree: TreeRoot;
29
+ locale?: string;
30
+ description?: string;
31
+ lastModified?: string;
32
+ editOnGithubUrl?: string;
33
+ children: ReactNode;
34
+ }
35
+ declare function TanstackDocsLayout({
36
+ config,
37
+ tree,
38
+ locale,
39
+ description,
40
+ lastModified,
41
+ editOnGithubUrl,
42
+ children
43
+ }: TanstackDocsLayoutProps): react_jsx_runtime0.JSX.Element;
44
+ //#endregion
45
+ export { TanstackDocsLayout, TanstackDocsLayoutProps };
@@ -0,0 +1,328 @@
1
+ import { withLangInUrl } from "./i18n.mjs";
2
+ import { DocsPageClient } from "./docs-page-client.mjs";
3
+ import { DocsAIFeatures } from "./docs-ai-features.mjs";
4
+ import { DocsCommandSearch } from "./docs-command-search.mjs";
5
+ import { SidebarSearchWithAI } from "./sidebar-search-ai.mjs";
6
+ import { LocaleThemeControl } from "./locale-theme-control.mjs";
7
+ import { DocsLayout } from "fumadocs-ui/layouts/docs";
8
+ import { Suspense } from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+
11
+ //#region src/tanstack-layout.tsx
12
+ function resolveTreeIcon(icon, registry) {
13
+ if (!icon) return void 0;
14
+ if (typeof icon !== "string") return icon;
15
+ const fromRegistry = registry?.[icon];
16
+ if (fromRegistry) return fromRegistry;
17
+ }
18
+ function resolveTreeIcons(tree, registry) {
19
+ function mapNode(node) {
20
+ if (node.type === "page") return {
21
+ ...node,
22
+ icon: resolveTreeIcon(node.icon, registry)
23
+ };
24
+ return {
25
+ ...node,
26
+ icon: resolveTreeIcon(node.icon, registry),
27
+ index: node.index ? {
28
+ ...node.index,
29
+ icon: resolveTreeIcon(node.index.icon, registry)
30
+ } : void 0,
31
+ children: node.children.map(mapNode)
32
+ };
33
+ }
34
+ return {
35
+ ...tree,
36
+ children: tree.children.map(mapNode)
37
+ };
38
+ }
39
+ function localizeTreeUrls(tree, locale) {
40
+ function mapNode(node) {
41
+ if (node.type === "page") return {
42
+ ...node,
43
+ url: withLangInUrl(node.url, locale)
44
+ };
45
+ return {
46
+ ...node,
47
+ index: node.index ? {
48
+ ...node.index,
49
+ url: withLangInUrl(node.index.url, locale)
50
+ } : void 0,
51
+ children: node.children.map(mapNode)
52
+ };
53
+ }
54
+ return {
55
+ ...tree,
56
+ children: tree.children.map(mapNode)
57
+ };
58
+ }
59
+ function resolveThemeSwitch(toggle) {
60
+ if (toggle === void 0 || toggle === true) return { enabled: true };
61
+ if (toggle === false) return { enabled: false };
62
+ return {
63
+ enabled: toggle.enabled !== false,
64
+ mode: toggle.mode
65
+ };
66
+ }
67
+ function resolveSidebar(sidebar) {
68
+ if (sidebar === void 0 || sidebar === true) return {};
69
+ if (sidebar === false) return { enabled: false };
70
+ return {
71
+ enabled: sidebar.enabled !== false,
72
+ componentFn: typeof sidebar.component === "function" ? sidebar.component : void 0,
73
+ footer: sidebar.footer,
74
+ banner: sidebar.banner,
75
+ collapsible: sidebar.collapsible,
76
+ flat: sidebar.flat
77
+ };
78
+ }
79
+ const COLOR_MAP = {
80
+ primary: "--color-fd-primary",
81
+ primaryForeground: "--color-fd-primary-foreground",
82
+ background: "--color-fd-background",
83
+ foreground: "--color-fd-foreground",
84
+ muted: "--color-fd-muted",
85
+ mutedForeground: "--color-fd-muted-foreground",
86
+ border: "--color-fd-border",
87
+ card: "--color-fd-card",
88
+ cardForeground: "--color-fd-card-foreground",
89
+ accent: "--color-fd-accent",
90
+ accentForeground: "--color-fd-accent-foreground",
91
+ popover: "--color-fd-popover",
92
+ popoverForeground: "--color-fd-popover-foreground",
93
+ secondary: "--color-fd-secondary",
94
+ secondaryForeground: "--color-fd-secondary-foreground",
95
+ ring: "--color-fd-ring"
96
+ };
97
+ function buildColorsCSS(colors) {
98
+ if (!colors) return "";
99
+ const vars = [];
100
+ for (const [key, value] of Object.entries(colors)) {
101
+ if (!value || !COLOR_MAP[key]) continue;
102
+ vars.push(`${COLOR_MAP[key]}: ${value};`);
103
+ }
104
+ if (vars.length === 0) return "";
105
+ const block = vars.join("\n ");
106
+ return `:root {\n ${block}\n}\n.dark {\n ${block}\n}`;
107
+ }
108
+ function ColorStyle({ colors }) {
109
+ const css = buildColorsCSS(colors);
110
+ if (!css) return null;
111
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } });
112
+ }
113
+ function buildFontStyleVars(prefix, style) {
114
+ if (!style) return "";
115
+ const parts = [];
116
+ if (style.size) parts.push(`${prefix}-size: ${style.size};`);
117
+ if (style.weight != null) parts.push(`${prefix}-weight: ${style.weight};`);
118
+ if (style.lineHeight) parts.push(`${prefix}-line-height: ${style.lineHeight};`);
119
+ if (style.letterSpacing) parts.push(`${prefix}-letter-spacing: ${style.letterSpacing};`);
120
+ return parts.join("\n ");
121
+ }
122
+ function buildTypographyCSS(typo) {
123
+ if (!typo?.font) return "";
124
+ const vars = [];
125
+ const fontStyle = typo.font.style;
126
+ if (fontStyle?.sans) vars.push(`--fd-font-sans: ${fontStyle.sans};`);
127
+ if (fontStyle?.mono) vars.push(`--fd-font-mono: ${fontStyle.mono};`);
128
+ for (const element of [
129
+ "h1",
130
+ "h2",
131
+ "h3",
132
+ "h4",
133
+ "body",
134
+ "small"
135
+ ]) {
136
+ const style = typo.font[element];
137
+ if (style) {
138
+ const cssVars = buildFontStyleVars(`--fd-${element}`, style);
139
+ if (cssVars) vars.push(cssVars);
140
+ }
141
+ }
142
+ if (vars.length === 0) return "";
143
+ return `:root {\n ${vars.join("\n ")}\n}`;
144
+ }
145
+ function TypographyStyle({ typography }) {
146
+ const css = buildTypographyCSS(typography);
147
+ if (!css) return null;
148
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } });
149
+ }
150
+ function LayoutStyle({ layout }) {
151
+ if (!layout) return null;
152
+ const rootVars = [];
153
+ const desktopRootVars = [];
154
+ const desktopGridVars = [];
155
+ if (layout.sidebarWidth) {
156
+ const value = `--fd-sidebar-width: ${layout.sidebarWidth}px`;
157
+ desktopRootVars.push(`${value};`);
158
+ desktopGridVars.push(`${value} !important;`);
159
+ }
160
+ if (layout.contentWidth) rootVars.push(`--fd-content-width: ${layout.contentWidth}px;`);
161
+ if (layout.tocWidth) {
162
+ const value = `--fd-toc-width: ${layout.tocWidth}px`;
163
+ desktopRootVars.push(`${value};`);
164
+ desktopGridVars.push(`${value} !important;`);
165
+ }
166
+ if (rootVars.length === 0 && desktopRootVars.length === 0) return null;
167
+ const parts = [];
168
+ if (rootVars.length > 0) parts.push(`:root {\n ${rootVars.join("\n ")}\n}`);
169
+ if (desktopRootVars.length > 0) {
170
+ const inner = [`:root {\n ${desktopRootVars.join("\n ")}\n }`];
171
+ if (desktopGridVars.length > 0) inner.push(`[style*="fd-sidebar-col"] {\n ${desktopGridVars.join("\n ")}\n }`);
172
+ parts.push(`@media (min-width: 1024px) {\n ${inner.join("\n ")}\n}`);
173
+ }
174
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: parts.join("\n") } });
175
+ }
176
+ function resolveBool(value) {
177
+ if (value === void 0) return false;
178
+ if (typeof value === "boolean") return value;
179
+ return value.enabled !== false;
180
+ }
181
+ function ForcedThemeScript({ theme }) {
182
+ return /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: `document.documentElement.classList.remove('light','dark');document.documentElement.classList.add('${theme === "light" || theme === "dark" ? theme : "light"}');` } });
183
+ }
184
+ function TanstackDocsLayout({ config, tree, locale, description, lastModified, editOnGithubUrl, children }) {
185
+ const tocConfig = config.theme?.ui?.layout?.toc;
186
+ const tocEnabled = tocConfig?.enabled !== false;
187
+ const tocStyle = tocConfig?.style;
188
+ const docsApiUrl = withLangInUrl("/api/docs", locale);
189
+ const navTitle = config.nav?.title ?? "Docs";
190
+ const navUrl = withLangInUrl(config.nav?.url ?? `/${config.entry ?? "docs"}`, locale);
191
+ const themeSwitch = resolveThemeSwitch(config.themeToggle);
192
+ const toggleConfig = typeof config.themeToggle === "object" ? config.themeToggle : void 0;
193
+ const forcedTheme = themeSwitch.enabled === false && toggleConfig?.default && toggleConfig.default !== "system" ? toggleConfig.default : void 0;
194
+ const resolvedSidebar = resolveSidebar(config.sidebar);
195
+ const sidebarFlat = resolvedSidebar.flat;
196
+ const sidebarComponentFn = resolvedSidebar.componentFn;
197
+ const { flat: _sidebarFlat, componentFn: _componentFn, ...sidebarProps } = resolvedSidebar;
198
+ const breadcrumbConfig = config.breadcrumb;
199
+ const breadcrumbEnabled = breadcrumbConfig === void 0 || breadcrumbConfig === true || typeof breadcrumbConfig === "object" && breadcrumbConfig.enabled !== false;
200
+ const colors = config.theme?._userColorOverrides;
201
+ const typography = config.theme?.ui?.typography;
202
+ const layoutDimensions = config.theme?.ui?.layout;
203
+ const pageActions = config.pageActions;
204
+ const copyMarkdownEnabled = resolveBool(pageActions?.copyMarkdown);
205
+ const openDocsEnabled = resolveBool(pageActions?.openDocs);
206
+ const pageActionsPosition = pageActions?.position ?? "below-title";
207
+ const pageActionsAlignment = pageActions?.alignment ?? "left";
208
+ const lastUpdatedRaw = config.lastUpdated;
209
+ const lastUpdatedEnabled = lastUpdatedRaw !== false && (typeof lastUpdatedRaw !== "object" || lastUpdatedRaw.enabled !== false);
210
+ const lastUpdatedPosition = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.position ?? "footer" : "footer";
211
+ const llmsTxtEnabled = resolveBool(config.llmsTxt);
212
+ const staticExport = !!config.staticExport;
213
+ const openDocsProviders = (typeof pageActions?.openDocs === "object" && pageActions.openDocs.providers ? pageActions.openDocs.providers : void 0)?.map((provider) => ({
214
+ name: provider.name,
215
+ urlTemplate: provider.urlTemplate
216
+ }));
217
+ const aiConfig = config.ai;
218
+ const aiEnabled = !staticExport && !!aiConfig?.enabled;
219
+ const aiMode = aiConfig?.mode ?? "search";
220
+ const aiPosition = aiConfig?.position ?? "bottom-right";
221
+ const aiFloatingStyle = aiConfig?.floatingStyle ?? "panel";
222
+ const aiSuggestedQuestions = aiConfig?.suggestedQuestions;
223
+ const aiLabel = aiConfig?.aiLabel;
224
+ const aiLoaderVariant = aiConfig?.loader;
225
+ const rawModelConfig = aiConfig?.model;
226
+ let aiModels = aiConfig?.models;
227
+ let aiDefaultModelId = aiConfig?.defaultModel ?? (typeof aiConfig?.model === "string" ? aiConfig.model : void 0);
228
+ if (rawModelConfig && typeof rawModelConfig === "object") {
229
+ aiModels = rawModelConfig.models ?? aiModels;
230
+ aiDefaultModelId = rawModelConfig.defaultModel ?? rawModelConfig.models?.[0]?.id ?? aiDefaultModelId;
231
+ }
232
+ const i18n = config.i18n;
233
+ const resolvedTree = resolveTreeIcons(locale ? localizeTreeUrls(tree, locale) : tree, config.icons);
234
+ const finalSidebarProps = { ...sidebarProps };
235
+ const sidebarFooter = sidebarProps.footer;
236
+ if (locale && i18n?.locales && i18n.defaultLocale) finalSidebarProps.footer = /* @__PURE__ */ jsxs("div", {
237
+ style: {
238
+ display: "flex",
239
+ flexDirection: "column",
240
+ gap: 12
241
+ },
242
+ children: [sidebarFooter, /* @__PURE__ */ jsx(Suspense, {
243
+ fallback: null,
244
+ children: /* @__PURE__ */ jsx(LocaleThemeControl, {
245
+ locales: i18n.locales,
246
+ defaultLocale: i18n.defaultLocale,
247
+ locale,
248
+ showThemeToggle: themeSwitch.enabled !== false,
249
+ themeMode: themeSwitch.mode
250
+ })
251
+ })]
252
+ });
253
+ if (sidebarComponentFn) finalSidebarProps.component = sidebarComponentFn({
254
+ tree: resolvedTree,
255
+ collapsible: sidebarProps.collapsible !== false,
256
+ flat: !!sidebarFlat
257
+ });
258
+ return /* @__PURE__ */ jsx("div", {
259
+ id: "nd-docs-layout",
260
+ style: { display: "contents" },
261
+ children: /* @__PURE__ */ jsxs(DocsLayout, {
262
+ tree: resolvedTree,
263
+ nav: {
264
+ title: navTitle,
265
+ url: navUrl
266
+ },
267
+ themeSwitch: locale && i18n?.locales ? {
268
+ ...themeSwitch,
269
+ enabled: false
270
+ } : themeSwitch,
271
+ sidebar: finalSidebarProps,
272
+ ...aiMode === "sidebar-icon" && aiEnabled ? { searchToggle: { components: { lg: /* @__PURE__ */ jsx(SidebarSearchWithAI, {}) } } } : {},
273
+ children: [
274
+ /* @__PURE__ */ jsx(ColorStyle, { colors }),
275
+ /* @__PURE__ */ jsx(TypographyStyle, { typography }),
276
+ /* @__PURE__ */ jsx(LayoutStyle, { layout: layoutDimensions }),
277
+ forcedTheme && /* @__PURE__ */ jsx(ForcedThemeScript, { theme: forcedTheme }),
278
+ !staticExport && /* @__PURE__ */ jsx(Suspense, {
279
+ fallback: null,
280
+ children: /* @__PURE__ */ jsx(DocsCommandSearch, {
281
+ api: docsApiUrl,
282
+ locale
283
+ })
284
+ }),
285
+ aiEnabled && /* @__PURE__ */ jsx(Suspense, {
286
+ fallback: null,
287
+ children: /* @__PURE__ */ jsx(DocsAIFeatures, {
288
+ mode: aiMode,
289
+ api: docsApiUrl,
290
+ locale,
291
+ position: aiPosition,
292
+ floatingStyle: aiFloatingStyle,
293
+ suggestedQuestions: aiSuggestedQuestions,
294
+ aiLabel,
295
+ loaderVariant: aiLoaderVariant,
296
+ models: aiModels,
297
+ defaultModelId: aiDefaultModelId
298
+ })
299
+ }),
300
+ /* @__PURE__ */ jsx(Suspense, {
301
+ fallback: children,
302
+ children: /* @__PURE__ */ jsx(DocsPageClient, {
303
+ tocEnabled,
304
+ tocStyle,
305
+ breadcrumbEnabled,
306
+ entry: config.entry ?? "docs",
307
+ locale,
308
+ copyMarkdown: copyMarkdownEnabled,
309
+ openDocs: openDocsEnabled,
310
+ openDocsProviders,
311
+ pageActionsPosition,
312
+ pageActionsAlignment,
313
+ editOnGithubUrl,
314
+ lastUpdatedEnabled,
315
+ lastUpdatedPosition,
316
+ lastModified,
317
+ llmsTxtEnabled,
318
+ description,
319
+ children
320
+ })
321
+ })
322
+ ]
323
+ })
324
+ });
325
+ }
326
+
327
+ //#endregion
328
+ export { TanstackDocsLayout };
@@ -0,0 +1,3 @@
1
+ import { RootProvider } from "./provider-tanstack.mjs";
2
+ import { TanstackDocsLayout } from "./tanstack-layout.mjs";
3
+ export { RootProvider, TanstackDocsLayout };
@@ -0,0 +1,4 @@
1
+ import { RootProvider } from "./provider-tanstack.mjs";
2
+ import { TanstackDocsLayout } from "./tanstack-layout.mjs";
3
+
4
+ export { RootProvider, TanstackDocsLayout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.0.33-beta.1",
3
+ "version": "0.0.34",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -73,6 +73,11 @@
73
73
  "import": "./dist/docs-api.mjs",
74
74
  "default": "./dist/docs-api.mjs"
75
75
  },
76
+ "./tanstack": {
77
+ "types": "./dist/tanstack.d.mts",
78
+ "import": "./dist/tanstack.mjs",
79
+ "default": "./dist/tanstack.mjs"
80
+ },
76
81
  "./ai": {
77
82
  "types": "./dist/ai-search-dialog.d.mts",
78
83
  "import": "./dist/ai-search-dialog.mjs",
@@ -100,11 +105,12 @@
100
105
  "devDependencies": {
101
106
  "@types/node": "^22.10.0",
102
107
  "@types/react": "^19.0.0",
108
+ "@types/react-dom": "^19.0.0",
103
109
  "next": ">=14.0.0",
104
110
  "tsdown": "^0.20.3",
105
111
  "typescript": "^5.9.3",
106
112
  "vitest": "^3.2.4",
107
- "@farming-labs/docs": "0.0.33-beta.1"
113
+ "@farming-labs/docs": "0.0.34"
108
114
  },
109
115
  "peerDependencies": {
110
116
  "@farming-labs/docs": ">=0.0.1",