@farming-labs/theme 0.2.97 → 0.2.99

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.
@@ -0,0 +1,27 @@
1
+ //#region src/reading-time-options.ts
2
+ function resolveReadingTimeOptions(readingTime) {
3
+ if (readingTime === true) return {
4
+ enabled: true,
5
+ format: "long",
6
+ includeCode: false
7
+ };
8
+ if (readingTime === false || readingTime === void 0 || readingTime === null) return {
9
+ enabled: false,
10
+ format: "long",
11
+ includeCode: false
12
+ };
13
+ if (typeof readingTime !== "object") return {
14
+ enabled: false,
15
+ format: "long",
16
+ includeCode: false
17
+ };
18
+ return {
19
+ enabled: readingTime.enabled !== false,
20
+ wordsPerMinute: typeof readingTime.wordsPerMinute === "number" && Number.isFinite(readingTime.wordsPerMinute) ? readingTime.wordsPerMinute : void 0,
21
+ format: readingTime.format === "short" ? "short" : "long",
22
+ includeCode: readingTime.includeCode === true
23
+ };
24
+ }
25
+
26
+ //#endregion
27
+ export { resolveReadingTimeOptions };
@@ -1,3 +1,4 @@
1
+ import { resolveReadingTimeOptions } from "./reading-time-options.mjs";
1
2
  import matter from "gray-matter";
2
3
 
3
4
  //#region src/reading-time.ts
@@ -16,29 +17,6 @@ function estimateReadingTimeMinutes(content, wordsPerMinute, options) {
16
17
  const wordCount = stripNonReadingContent(content, options).match(/\b[\p{L}\p{N}][\p{L}\p{N}'’-]*\b/gu)?.length ?? 0;
17
18
  return Math.max(1, Math.ceil(wordCount / normalizeWordsPerMinute(wordsPerMinute)));
18
19
  }
19
- function resolveReadingTimeOptions(readingTime) {
20
- if (readingTime === true) return {
21
- enabled: true,
22
- format: "long",
23
- includeCode: false
24
- };
25
- if (readingTime === false || readingTime === void 0 || readingTime === null) return {
26
- enabled: false,
27
- format: "long",
28
- includeCode: false
29
- };
30
- if (typeof readingTime !== "object") return {
31
- enabled: false,
32
- format: "long",
33
- includeCode: false
34
- };
35
- return {
36
- enabled: readingTime.enabled !== false,
37
- wordsPerMinute: typeof readingTime.wordsPerMinute === "number" && Number.isFinite(readingTime.wordsPerMinute) ? readingTime.wordsPerMinute : void 0,
38
- format: readingTime.format === "short" ? "short" : "long",
39
- includeCode: readingTime.includeCode === true
40
- };
41
- }
42
20
  function resolveReadingTimeFromContent(frontmatter, content, wordsPerMinute, options) {
43
21
  const pageData = frontmatter ?? {};
44
22
  if (pageData.readingTime === false) return null;
@@ -51,4 +29,4 @@ function resolvePageReadingTime(frontmatter, content, options) {
51
29
  }
52
30
 
53
31
  //#endregion
54
- export { resolvePageReadingTime, resolveReadingTimeOptions };
32
+ export { resolvePageReadingTime };
@@ -0,0 +1,64 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ import { useSidebar } from "fumadocs-ui/components/sidebar/base";
6
+
7
+ //#region src/tablet-sidebar-bridge.tsx
8
+ const tabletSidebarQuery = "(min-width: 768px) and (max-width: 1023px)";
9
+ /**
10
+ * Extends Fumadocs' sidebar state through the tablet breakpoint without
11
+ * intercepting its trigger or cloning the configured navigation tree.
12
+ */
13
+ function TabletSidebarBridge() {
14
+ const { open, setOpen } = useSidebar();
15
+ const [isTablet, setIsTablet] = useState(false);
16
+ const closeButtonRef = useRef(null);
17
+ const returnFocusRef = useRef(null);
18
+ const visible = isTablet && open;
19
+ useEffect(() => {
20
+ const media = window.matchMedia(tabletSidebarQuery);
21
+ const update = () => setIsTablet(media.matches);
22
+ update();
23
+ media.addEventListener("change", update);
24
+ return () => media.removeEventListener("change", update);
25
+ }, []);
26
+ useEffect(() => {
27
+ if (!visible) return;
28
+ returnFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
29
+ closeButtonRef.current?.focus();
30
+ const closeOnEscape = (event) => {
31
+ if (event.key !== "Escape") return;
32
+ event.preventDefault();
33
+ setOpen(false);
34
+ };
35
+ window.addEventListener("keydown", closeOnEscape);
36
+ return () => {
37
+ window.removeEventListener("keydown", closeOnEscape);
38
+ returnFocusRef.current?.focus();
39
+ returnFocusRef.current = null;
40
+ };
41
+ }, [setOpen, visible]);
42
+ if (!isTablet) return null;
43
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
44
+ hidden: true,
45
+ "aria-hidden": "true",
46
+ "data-fd-tablet-sidebar-state": visible ? "open" : "closed"
47
+ }), visible && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
48
+ type: "button",
49
+ tabIndex: -1,
50
+ "aria-hidden": "true",
51
+ className: "fd-tablet-sidebar-backdrop",
52
+ onClick: () => setOpen(false)
53
+ }), /* @__PURE__ */ jsx("button", {
54
+ ref: closeButtonRef,
55
+ type: "button",
56
+ "aria-label": "Close Sidebar",
57
+ className: "fd-tablet-sidebar-close",
58
+ onClick: () => setOpen(false),
59
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true" })
60
+ })] })] });
61
+ }
62
+
63
+ //#endregion
64
+ export { TabletSidebarBridge };
@@ -29,6 +29,7 @@ interface TanstackDocsLayoutProps {
29
29
  tree: TreeRoot;
30
30
  locale?: string;
31
31
  description?: string;
32
+ descriptionInBody?: boolean;
32
33
  readingTime?: number | null;
33
34
  lastModified?: string;
34
35
  previousPage?: {
@@ -48,6 +49,7 @@ declare function TanstackDocsLayout({
48
49
  tree,
49
50
  locale,
50
51
  description,
52
+ descriptionInBody,
51
53
  readingTime,
52
54
  lastModified,
53
55
  previousPage,
@@ -1,17 +1,18 @@
1
+ import { resolveOpenDocsProviders } from "./open-docs-providers.mjs";
1
2
  import { withLangInUrl } from "./i18n.mjs";
2
3
  import { escapeJsonLdForScript } from "./json-ld.mjs";
3
4
  import { DocsPageClient } from "./docs-page-client.mjs";
4
5
  import { DocsAIFeatures } from "./docs-ai-features.mjs";
5
6
  import { resolveDocsCloudAIClientRequest } from "./docs-cloud-ai-client.mjs";
6
7
  import { DocsCommandSearch } from "./docs-command-search.mjs";
7
- import { resolveOpenDocsProviders } from "./open-docs-providers.mjs";
8
- import { resolveReadingTimeOptions } from "./reading-time.mjs";
8
+ import { resolveReadingTimeOptions } from "./reading-time-options.mjs";
9
9
  import { SidebarSearchWithAI } from "./sidebar-search-ai.mjs";
10
+ import { TabletSidebarBridge } from "./tablet-sidebar-bridge.mjs";
10
11
  import { LocaleThemeControl } from "./locale-theme-control.mjs";
11
12
  import { DocsLayout } from "fumadocs-ui/layouts/docs";
12
13
  import { Suspense } from "react";
13
- import { applySidebarFolderIndexBehavior, resolveDocsAnalyticsConfig } from "@farming-labs/docs";
14
14
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
15
+ import { applySidebarFolderIndexBehavior, resolveDocsAnalyticsConfig } from "@farming-labs/docs/browser";
15
16
 
16
17
  //#region src/tanstack-layout.tsx
17
18
  function resolveTreeIcon(icon, registry) {
@@ -223,7 +224,7 @@ function resolveFeedbackConfig(feedback) {
223
224
  function ForcedThemeScript({ theme }) {
224
225
  return /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: `document.documentElement.classList.remove('light','dark');document.documentElement.classList.add('${theme === "light" || theme === "dark" ? theme : "light"}');` } });
225
226
  }
226
- function TanstackDocsLayout({ config, tree, locale, description, readingTime, lastModified, previousPage, nextPage, structuredData, editOnGithubUrl, children }) {
227
+ function TanstackDocsLayout({ config, tree, locale, description, descriptionInBody, readingTime, lastModified, previousPage, nextPage, structuredData, editOnGithubUrl, children }) {
227
228
  const tocConfig = config.theme?.ui?.layout?.toc;
228
229
  const tocEnabled = tocConfig?.enabled !== false;
229
230
  const tocStyle = tocConfig?.style;
@@ -328,6 +329,7 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
328
329
  /* @__PURE__ */ jsx(TypographyStyle, { typography }),
329
330
  /* @__PURE__ */ jsx(LayoutStyle, { layout: layoutDimensions }),
330
331
  forcedTheme && /* @__PURE__ */ jsx(ForcedThemeScript, { theme: forcedTheme }),
332
+ config.theme?.name === "fumadocs-pixel-border" && /* @__PURE__ */ jsx(TabletSidebarBridge, {}),
331
333
  !staticExport && /* @__PURE__ */ jsx(Suspense, {
332
334
  fallback: null,
333
335
  children: /* @__PURE__ */ jsx(DocsCommandSearch, {
@@ -359,6 +361,7 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
359
361
  fallback: children,
360
362
  children: /* @__PURE__ */ jsx(DocsPageClient, {
361
363
  tocEnabled,
364
+ themeName: config.theme?.name,
362
365
  tocStyle,
363
366
  breadcrumbEnabled,
364
367
  entry: config.entry ?? "docs",
@@ -386,6 +389,7 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
386
389
  readingTime: typeof readingTime === "number" ? readingTime : void 0,
387
390
  llmsTxtEnabled,
388
391
  description,
392
+ descriptionInBody,
389
393
  feedbackEnabled: feedbackConfig.enabled,
390
394
  feedbackQuestion: feedbackConfig.question,
391
395
  feedbackPlaceholder: feedbackConfig.placeholder,
@@ -1,4 +1,4 @@
1
+ import { TanstackDocsLayout } from "./tanstack-layout.mjs";
1
2
  import { DocsClientHooks } from "./docs-client-hooks.mjs";
2
3
  import { RootProvider } from "./provider-tanstack.mjs";
3
- import { TanstackDocsLayout } from "./tanstack-layout.mjs";
4
4
  export { DocsClientHooks, RootProvider, TanstackDocsLayout };
package/dist/tanstack.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { DocsClientHooks } from "./docs-client-hooks.mjs";
2
- import { RootProvider } from "./provider-tanstack.mjs";
3
2
  import { TanstackDocsLayout } from "./tanstack-layout.mjs";
3
+ import { RootProvider } from "./provider-tanstack.mjs";
4
4
 
5
5
  export { DocsClientHooks, RootProvider, TanstackDocsLayout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.2.97",
3
+ "version": "0.2.99",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -33,6 +33,12 @@
33
33
  "import": "./dist/docs-client-hooks.mjs",
34
34
  "default": "./dist/docs-client-hooks.mjs"
35
35
  },
36
+ "./browser": {
37
+ "types": "./dist/browser.d.mts",
38
+ "import": "./dist/browser.mjs",
39
+ "default": "./dist/browser.mjs"
40
+ },
41
+ "./browser/css": "./styles/bundles/browser-framework.css",
36
42
  "./default": {
37
43
  "types": "./dist/default/index.d.mts",
38
44
  "import": "./dist/default/index.mjs",
@@ -151,10 +157,11 @@
151
157
  "ajv": "^8.18.0",
152
158
  "ajv-formats": "^3.0.1",
153
159
  "next": ">=14.0.0",
160
+ "postcss": "^8.5.6",
154
161
  "tsdown": "^0.20.3",
155
162
  "typescript": "^5.9.3",
156
163
  "vitest": "^4.1.8",
157
- "@farming-labs/docs": "0.2.97"
164
+ "@farming-labs/docs": "0.2.99"
158
165
  },
159
166
  "peerDependencies": {
160
167
  "@farming-labs/docs": ">=0.0.1",