boltdocs 2.6.2 → 2.7.0

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 (177) hide show
  1. package/bin/boltdocs.js +0 -1
  2. package/dist/cache-CQKlT4fI.mjs +6 -0
  3. package/dist/cache-DorPMFgW.cjs +6 -0
  4. package/dist/cards-BLoSiRuL.d.ts +30 -0
  5. package/dist/cards-CQn9mXZS.d.cts +30 -0
  6. package/dist/chunk-Ds5LZdWN.cjs +6 -0
  7. package/dist/client/index.cjs +1 -1
  8. package/dist/client/index.d.cts +167 -1338
  9. package/dist/client/index.d.ts +166 -1337
  10. package/dist/client/index.js +1 -1
  11. package/dist/{package-CFP44vfn.cjs → client/mdx.cjs} +1 -1
  12. package/dist/client/mdx.d.cts +128 -0
  13. package/dist/client/mdx.d.ts +129 -0
  14. package/dist/client/mdx.js +6 -0
  15. package/dist/client/primitives.cjs +6 -0
  16. package/dist/client/primitives.d.cts +818 -0
  17. package/dist/client/primitives.d.ts +818 -0
  18. package/dist/client/primitives.js +6 -0
  19. package/dist/client/theme/neutral.css +74 -361
  20. package/dist/client/theme/reset.css +189 -0
  21. package/dist/docs-layout-BlDhcQRv.cjs +6 -0
  22. package/dist/docs-layout-BvAOWEJw.js +6 -0
  23. package/dist/doctor-BQiQhCTl.cjs +6 -0
  24. package/dist/doctor-COpf35L2.cjs +20 -0
  25. package/dist/doctor-Dh1XP7Pz.mjs +20 -0
  26. package/dist/generator-DGW6pkCC.cjs +22 -0
  27. package/dist/generator-Dv3wEmhZ.mjs +22 -0
  28. package/dist/icons-dev-CrQLjoQp.js +6 -0
  29. package/dist/icons-dev-rzdz6Lf3.cjs +6 -0
  30. package/dist/image-BkIfa9oo.js +6 -0
  31. package/dist/image-DIGjCPe6.cjs +6 -0
  32. package/dist/mdx-K0WYBAJ3.js +7 -0
  33. package/dist/mdx-hpErbRUe.cjs +7 -0
  34. package/dist/meta-loader-0gJ4PtBC.cjs +6 -0
  35. package/dist/meta-loader-9IpAHWDS.mjs +6 -0
  36. package/dist/node/cli-entry.cjs +1 -2
  37. package/dist/node/cli-entry.mjs +1 -2
  38. package/dist/node/index.cjs +1 -1
  39. package/dist/node/index.d.cts +55 -11
  40. package/dist/node/index.d.mts +55 -12
  41. package/dist/node/index.mjs +1 -1
  42. package/dist/node/routes/worker.cjs +6 -0
  43. package/dist/node/routes/worker.d.cts +2 -0
  44. package/dist/node/routes/worker.d.mts +2 -0
  45. package/dist/node/routes/worker.mjs +6 -0
  46. package/dist/node-C2nWXElP.mjs +112 -0
  47. package/dist/node-CinkUtxV.cjs +112 -0
  48. package/dist/package-BMYLDBBP.cjs +6 -0
  49. package/dist/{package-Bqbn1AYK.mjs → package-HegMOTL_.mjs} +1 -1
  50. package/dist/parser-Bh11BsdA.cjs +6 -0
  51. package/dist/parser-D8eQvE7N.mjs +6 -0
  52. package/dist/parser-DYRzXWmA.cjs +6 -0
  53. package/dist/routes-CHf76Ye4.cjs +6 -0
  54. package/dist/routes-CMUZGI6T.mjs +6 -0
  55. package/dist/routes-Co1mRM58.cjs +6 -0
  56. package/dist/search-dialog-BACuzoVX.cjs +6 -0
  57. package/dist/search-dialog-BKagVT17.js +6 -0
  58. package/dist/search-dialog-C8w12eUx.js +6 -0
  59. package/dist/search-dialog-CGyrozZE.cjs +6 -0
  60. package/dist/search-dialog-D26rUnJ_.cjs +6 -0
  61. package/dist/sidebar-DKvg6KOc.d.cts +491 -0
  62. package/dist/sidebar-Dr1TiRIy.d.ts +491 -0
  63. package/dist/utils-BxNAXhZZ.mjs +7 -0
  64. package/dist/utils-Clzu7jvb.cjs +7 -0
  65. package/dist/worker-pool-Bd8Y9KDv.mjs +6 -0
  66. package/dist/worker-pool-BwU8ckrg.cjs +6 -0
  67. package/package.json +27 -8
  68. package/src/client/app/doc-page.tsx +9 -5
  69. package/src/client/app/docs-layout.tsx +17 -3
  70. package/src/client/app/head.tsx +122 -0
  71. package/src/client/app/helmet-compat.tsx +36 -0
  72. package/src/client/app/mdx-component.tsx +5 -52
  73. package/src/client/app/mdx-components-context.tsx +32 -8
  74. package/src/client/app/routes-context.tsx +2 -2
  75. package/src/client/app/scroll-handler.tsx +1 -1
  76. package/src/client/app/theme-context.tsx +5 -5
  77. package/src/client/app/ui-context.tsx +42 -0
  78. package/src/client/components/docs-layout-default.tsx +85 -0
  79. package/src/client/components/icons-dev.tsx +38 -15
  80. package/src/client/components/mdx/callout.tsx +97 -0
  81. package/src/client/components/mdx/card.tsx +73 -98
  82. package/src/client/components/mdx/cards.tsx +27 -0
  83. package/src/client/components/mdx/code-block.tsx +37 -17
  84. package/src/client/components/mdx/field.tsx +24 -56
  85. package/src/client/components/mdx/image.tsx +36 -15
  86. package/src/client/components/mdx/index.ts +19 -53
  87. package/src/client/components/mdx/table.tsx +46 -148
  88. package/src/client/components/mdx/typographics.tsx +120 -0
  89. package/src/client/components/mdx/{hooks/use-code-block.ts → use-code-block.ts} +5 -7
  90. package/src/client/components/primitives/breadcrumbs.tsx +5 -24
  91. package/src/client/components/primitives/button.tsx +3 -142
  92. package/src/client/components/primitives/code-block.tsx +104 -97
  93. package/src/client/components/{docs-layout.tsx → primitives/docs-layout.tsx} +15 -24
  94. package/src/client/components/primitives/error-boundary.tsx +107 -0
  95. package/src/client/components/primitives/heading.tsx +128 -0
  96. package/src/client/components/primitives/helpers/observer.ts +62 -32
  97. package/src/client/components/primitives/image.tsx +26 -0
  98. package/src/client/components/primitives/link.tsx +50 -52
  99. package/src/client/components/primitives/menu.tsx +25 -49
  100. package/src/client/components/primitives/navbar.tsx +234 -59
  101. package/src/client/components/primitives/on-this-page.tsx +169 -40
  102. package/src/client/components/primitives/page-nav.tsx +11 -39
  103. package/src/client/components/primitives/popover.tsx +12 -30
  104. package/src/client/components/primitives/search-dialog.tsx +77 -71
  105. package/src/client/components/primitives/sidebar.tsx +312 -119
  106. package/src/client/components/primitives/skeleton.tsx +1 -1
  107. package/src/client/components/primitives/tabs.tsx +5 -16
  108. package/src/client/components/primitives/tooltip.tsx +1 -1
  109. package/src/client/components/ui-base/banner.tsx +66 -0
  110. package/src/client/components/ui-base/breadcrumbs.tsx +26 -20
  111. package/src/client/components/ui-base/copy-markdown.tsx +43 -35
  112. package/src/client/components/ui-base/error-boundary.tsx +9 -46
  113. package/src/client/components/ui-base/github-stars.tsx +5 -3
  114. package/src/client/components/ui-base/index.ts +3 -3
  115. package/src/client/components/ui-base/last-updated.tsx +27 -0
  116. package/src/client/components/ui-base/navbar.tsx +183 -89
  117. package/src/client/components/ui-base/not-found.tsx +11 -9
  118. package/src/client/components/ui-base/on-this-page.tsx +8 -104
  119. package/src/client/components/ui-base/page-nav.tsx +23 -9
  120. package/src/client/components/ui-base/search-dialog.tsx +111 -36
  121. package/src/client/components/ui-base/search-highlight.tsx +10 -0
  122. package/src/client/components/ui-base/sidebar.tsx +77 -154
  123. package/src/client/components/ui-base/tabs.tsx +20 -7
  124. package/src/client/components/ui-base/theme-toggle.tsx +88 -10
  125. package/src/client/components/ui-base/version-i18n.tsx +80 -0
  126. package/src/client/hooks/index.ts +2 -1
  127. package/src/client/hooks/use-analytics.ts +272 -0
  128. package/src/client/hooks/use-i18n.ts +116 -50
  129. package/src/client/hooks/use-localized-to.ts +70 -27
  130. package/src/client/hooks/use-navbar.ts +69 -39
  131. package/src/client/hooks/use-page-nav.ts +28 -25
  132. package/src/client/hooks/use-routes.ts +63 -80
  133. package/src/client/hooks/use-search-highlight.ts +185 -0
  134. package/src/client/hooks/use-search.ts +12 -3
  135. package/src/client/hooks/use-sidebar.ts +183 -80
  136. package/src/client/hooks/use-tabs.ts +3 -4
  137. package/src/client/hooks/use-version.ts +44 -29
  138. package/src/client/index.ts +13 -87
  139. package/src/client/mdx.ts +2 -0
  140. package/src/client/primitives.ts +19 -0
  141. package/src/client/ssg/boltdocs-shell.tsx +68 -79
  142. package/src/client/ssg/create-routes.tsx +268 -72
  143. package/src/client/ssg/mdx-page.tsx +2 -1
  144. package/src/client/store/boltdocs-context.tsx +72 -20
  145. package/src/client/theme/neutral.css +74 -361
  146. package/src/client/theme/reset.css +189 -0
  147. package/src/client/types.ts +10 -2
  148. package/src/client/utils/path.ts +9 -0
  149. package/src/client/utils/react-to-text.ts +24 -24
  150. package/src/client/virtual.d.ts +1 -1
  151. package/src/shared/types.ts +82 -22
  152. package/dist/node-Bogvkxao.mjs +0 -101
  153. package/dist/node-CXaog6St.cjs +0 -101
  154. package/dist/search-dialog-CV3eJzMm.cjs +0 -6
  155. package/dist/search-dialog-DNTomKgu.js +0 -6
  156. package/dist/use-search-CS3gH19M.js +0 -6
  157. package/dist/use-search-DBpJZQuw.cjs +0 -6
  158. package/src/client/components/mdx/admonition.tsx +0 -91
  159. package/src/client/components/mdx/badge.tsx +0 -41
  160. package/src/client/components/mdx/button.tsx +0 -35
  161. package/src/client/components/mdx/component-preview.tsx +0 -37
  162. package/src/client/components/mdx/component-props.tsx +0 -83
  163. package/src/client/components/mdx/file-tree.tsx +0 -325
  164. package/src/client/components/mdx/hooks/use-component-preview.ts +0 -16
  165. package/src/client/components/mdx/hooks/useTable.ts +0 -74
  166. package/src/client/components/mdx/hooks/useTabs.ts +0 -68
  167. package/src/client/components/mdx/link.tsx +0 -38
  168. package/src/client/components/mdx/list.tsx +0 -192
  169. package/src/client/components/mdx/tabs.tsx +0 -135
  170. package/src/client/components/mdx/video.tsx +0 -68
  171. package/src/client/components/primitives/index.ts +0 -19
  172. package/src/client/components/primitives/navigation-menu.tsx +0 -114
  173. package/src/client/components/ui-base/head.tsx +0 -83
  174. package/src/client/components/ui-base/loading.tsx +0 -57
  175. package/src/client/components/ui-base/powered-by.tsx +0 -25
  176. package/src/client/hooks/use-onthispage.ts +0 -23
  177. package/src/client/utils/use-on-change.ts +0 -15
@@ -1,14 +1,28 @@
1
1
  import { Outlet } from 'react-router-dom'
2
2
  import UserLayout from 'virtual:boltdocs-layout'
3
+ import { useRoutes } from '../hooks/use-routes'
4
+ import { useConfig } from './config-context'
5
+ import { Head } from './head'
3
6
 
4
7
  /**
5
8
  * Wraps the docs Outlet with the user's (or default) layout component.
6
9
  * The Layout receives the routed page as `children`.
10
+ * We use useRoutes to pass the current route context to the persistent layout.
7
11
  */
8
12
  export function DocsLayout() {
13
+ const config = useConfig()
14
+ const { currentRoute, allRoutes } = useRoutes()
15
+
9
16
  return (
10
- <UserLayout>
11
- <Outlet />
12
- </UserLayout>
17
+ <>
18
+ <Head
19
+ siteTitle={config.theme?.title}
20
+ siteDescription={config.theme?.description}
21
+ routes={allRoutes || []}
22
+ />
23
+ <UserLayout route={currentRoute}>
24
+ <Outlet />
25
+ </UserLayout>
26
+ </>
13
27
  )
14
28
  }
@@ -0,0 +1,122 @@
1
+ import { useMemo } from 'react'
2
+ import { useLocation } from 'react-router-dom'
3
+ import { Helmet } from './helmet-compat'
4
+ import { useConfig } from './config-context'
5
+ import { getTranslated } from '../utils/i18n'
6
+ import { useRoutes } from '../hooks/use-routes'
7
+
8
+ interface HeadProps {
9
+ siteTitle?: string | Record<string, string>
10
+ siteDescription?: string | Record<string, string>
11
+ routes: Array<{
12
+ path: string
13
+ title: string
14
+ description?: string
15
+ seo?: Record<string, unknown>
16
+ }>
17
+ }
18
+
19
+ export function Head({ siteTitle, siteDescription, routes }: HeadProps) {
20
+ const location = useLocation()
21
+ const config = useConfig()
22
+ const { currentLocale } = useRoutes()
23
+
24
+ // Find the current route's metadata — memoized so the O(n) search only
25
+ // re-runs when the routes array or the current URL changes, not on every render.
26
+ const currentRoute = useMemo(
27
+ () => routes?.find?.((r) => r.path === location.pathname),
28
+ [routes, location.pathname],
29
+ )
30
+ const pageTitle = currentRoute?.title
31
+ const translatedSiteDescription = getTranslated(
32
+ siteDescription,
33
+ currentLocale,
34
+ )
35
+ const pageDescription =
36
+ currentRoute?.description || translatedSiteDescription || ''
37
+
38
+ const translatedSiteTitle = getTranslated(siteTitle, currentLocale)
39
+ const finalTitle = pageTitle
40
+ ? `${pageTitle} | ${translatedSiteTitle}`
41
+ : translatedSiteTitle
42
+
43
+ const seo = currentRoute?.seo || {}
44
+
45
+ // Merge custom global metatags
46
+ const globalMetatags = config?.seo?.metatags || {}
47
+
48
+ // Calculate specific ones
49
+ const defaultOgImage = config?.seo?.thumbnails?.background
50
+ const ogImage = (seo['og:image'] || defaultOgImage) as string | undefined
51
+
52
+ return (
53
+ <Helmet>
54
+ <title>{finalTitle}</title>
55
+ <meta name="description" content={pageDescription} />
56
+
57
+ {/* Default OG Tags */}
58
+ <meta property="og:title" content={finalTitle} />
59
+ <meta property="og:description" content={pageDescription} />
60
+ <meta property="og:type" content="article" />
61
+ {/* Canonical URL for both <link> and og:url */}
62
+ {typeof window !== 'undefined' && (
63
+ <meta property="og:url" content={window.location.href} />
64
+ )}
65
+ {typeof window !== 'undefined' && (
66
+ <link
67
+ rel="canonical"
68
+ href={window.location.origin + location.pathname}
69
+ />
70
+ )}
71
+
72
+ {/* Default Twitter Card */}
73
+ <meta name="twitter:card" content="summary" />
74
+ <meta name="twitter:title" content={finalTitle} />
75
+ <meta name="twitter:description" content={pageDescription} />
76
+ {ogImage && <meta name="twitter:image" content={ogImage} />}
77
+ {ogImage && <meta property="og:image" content={ogImage} />}
78
+
79
+ {/* Generator */}
80
+ <meta name="generator" content="Boltdocs" />
81
+
82
+ {/* User-defined global metatags */}
83
+ {Object.entries(globalMetatags).map(([key, value]) => {
84
+ const isProperty =
85
+ key.startsWith('og:') ||
86
+ key.startsWith('music:') ||
87
+ key.startsWith('video:') ||
88
+ key.startsWith('article:') ||
89
+ key.startsWith('book:') ||
90
+ key.startsWith('profile:')
91
+ return isProperty ? (
92
+ <meta key={key} property={key} content={value as string} />
93
+ ) : (
94
+ <meta key={key} name={key} content={value as string} />
95
+ )
96
+ })}
97
+
98
+ {/* Page granular SEO tags (override global) */}
99
+ {Object.entries(seo).map(([key, value]) => {
100
+ if (key === 'noindex' && value === true)
101
+ return <meta key="noindex" name="robots" content="noindex" />
102
+ if (key === 'robots')
103
+ return <meta key="robots" name="robots" content={value as string} />
104
+ if (key === 'canonical')
105
+ return <link key="canonical" rel="canonical" href={value as string} />
106
+
107
+ const isProperty =
108
+ key.startsWith('og:') ||
109
+ key.startsWith('music:') ||
110
+ key.startsWith('video:') ||
111
+ key.startsWith('article:') ||
112
+ key.startsWith('book:') ||
113
+ key.startsWith('profile:')
114
+ return isProperty ? (
115
+ <meta key={key} property={key} content={value as string} />
116
+ ) : (
117
+ <meta key={key} name={key} content={value as string} />
118
+ )
119
+ })}
120
+ </Helmet>
121
+ )
122
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared Helmet module compatibility helpers.
3
+ *
4
+ * react-helmet-async ships different module shapes depending on whether it is
5
+ * loaded via CJS or ESM. Instead of duplicating the same detection logic in
6
+ * every component that needs Helmet/HelmetProvider, we centralise it here.
7
+ */
8
+ import type { ComponentType, ReactNode } from 'react'
9
+ import * as ReactHelmetAsync from 'react-helmet-async'
10
+
11
+ type HelmetModule = {
12
+ Helmet?: ComponentType<{ children?: ReactNode }>
13
+ HelmetProvider?: ComponentType<{ children?: ReactNode }>
14
+ default?: {
15
+ Helmet?: ComponentType<{ children?: ReactNode }>
16
+ HelmetProvider?: ComponentType<{ children?: ReactNode }>
17
+ }
18
+ }
19
+
20
+ const mod = ReactHelmetAsync as unknown as HelmetModule
21
+
22
+ /**
23
+ * The `<Helmet>` component, resolved across CJS/ESM module shapes.
24
+ * Falls back to a transparent fragment wrapper if the module cannot be resolved.
25
+ */
26
+ export const Helmet: ComponentType<{ children?: ReactNode }> =
27
+ mod.Helmet || mod.default?.Helmet || (({ children }) => <>{children}</>)
28
+
29
+ /**
30
+ * The `<HelmetProvider>` component, resolved across CJS/ESM module shapes.
31
+ * Falls back to a transparent fragment wrapper if the module cannot be resolved.
32
+ */
33
+ export const HelmetProvider: ComponentType<{ children?: ReactNode }> =
34
+ mod.HelmetProvider ||
35
+ mod.default?.HelmetProvider ||
36
+ (({ children }) => <>{children}</>)
@@ -1,55 +1,8 @@
1
- import { Link as LucideLink } from 'lucide-react'
2
- import * as MdxComponents from '../components/mdx'
3
-
4
- const Heading = ({
5
- level,
6
- id,
7
- children,
8
- ...props
9
- }: {
10
- level: number
11
- id?: string
12
- children?: React.ReactNode
13
- } & React.HTMLAttributes<HTMLHeadingElement>) => {
14
- const Tag = `h${level}` as any
15
- return (
16
- <Tag id={id} {...props} className="boltdocs-heading">
17
- {children}
18
- {id && (
19
- <a href={`#${id}`} className="header-anchor" aria-label="Anchor">
20
- <LucideLink size={16} />
21
- </a>
22
- )}
23
- </Tag>
24
- )
25
- }
26
-
27
- import { Loading } from '../components/ui-base/loading'
1
+ import { NotFound } from '../components/ui-base/not-found'
2
+ import { mdx_components_default } from '../components/mdx'
28
3
 
29
4
  export const mdxComponentsDefault = {
30
- ...MdxComponents,
31
- Loading,
32
- h1: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
33
- <Heading level={1} {...props} />
34
- ),
35
- h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
36
- <Heading level={2} {...props} />
37
- ),
38
- h3: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
39
- <Heading level={3} {...props} />
40
- ),
41
- h4: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
42
- <Heading level={4} {...props} />
43
- ),
44
- h5: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
45
- <Heading level={5} {...props} />
46
- ),
47
- h6: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
48
- <Heading level={6} {...props} />
49
- ),
50
- pre: (props: React.HTMLAttributes<HTMLPreElement>) => (
51
- <MdxComponents.CodeBlock {...props}>
52
- {props.children}
53
- </MdxComponents.CodeBlock>
54
- ),
5
+ ...mdx_components_default,
6
+ NotFound,
7
+ '404': NotFound,
55
8
  }
@@ -1,6 +1,11 @@
1
- import { createContext, use } from 'react'
1
+ import { createContext, use, useMemo } from 'react'
2
+ import type { BoltdocsMdxComponents } from '../../shared/types'
2
3
 
3
- export type MdxComponentsType = Record<string, React.ComponentType<any>>
4
+ export type MdxComponentsType = {
5
+ [key: string]: React.ComponentType<any>
6
+ } & {
7
+ Frontmatter?: Record<string, React.ComponentType<any>>
8
+ }
4
9
 
5
10
  const MDX_COMPONENTS_CONTEXT_SYMBOL = Symbol.for(
6
11
  '__BDOCS_MDX_COMPONENTS_CONTEXT__',
@@ -14,7 +19,7 @@ const MdxComponentsContext =
14
19
  ((globalThis as any)[MDX_COMPONENTS_CONTEXT_SYMBOL] =
15
20
  createContext<MdxComponentsType>({}))
16
21
 
17
- export function useMdxComponents() {
22
+ export function useMdxComponents(): BoltdocsMdxComponents {
18
23
  const context = use(MdxComponentsContext)
19
24
 
20
25
  // Fallback to global registry for dual-package hazards
@@ -22,26 +27,45 @@ export function useMdxComponents() {
22
27
  (!context || Object.keys(context).length === 0) &&
23
28
  (globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL]
24
29
  ) {
25
- return (globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL]
30
+ return (globalThis as any)[
31
+ MDX_COMPONENTS_INSTANCE_SYMBOL
32
+ ] as BoltdocsMdxComponents
26
33
  }
27
34
 
28
- return context
35
+ return context as any as BoltdocsMdxComponents
29
36
  }
30
37
 
31
38
  export function MdxComponentsProvider({
32
39
  components,
33
40
  children,
34
41
  }: {
35
- components: MdxComponentsType
42
+ components: Record<string, React.ComponentType<any>>
36
43
  children: React.ReactNode
37
44
  }) {
45
+ const processedComponents = useMemo(() => {
46
+ const processed: Record<string, any> = {}
47
+ const frontmatter: Record<string, React.ComponentType<any>> = {}
48
+
49
+ Object.entries(components).forEach(([key, value]) => {
50
+ if (key.startsWith('Frontmatter_')) {
51
+ const cleanKey = key.slice('Frontmatter_'.length)
52
+ frontmatter[cleanKey] = value
53
+ } else {
54
+ processed[key] = value
55
+ }
56
+ })
57
+
58
+ processed.Frontmatter = frontmatter
59
+ return processed as MdxComponentsType
60
+ }, [components])
61
+
38
62
  // Sync with global registry
39
63
  if (typeof globalThis !== 'undefined') {
40
- ;(globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL] = components
64
+ ;(globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL] = processedComponents
41
65
  }
42
66
 
43
67
  return (
44
- <MdxComponentsContext.Provider value={components}>
68
+ <MdxComponentsContext.Provider value={processedComponents}>
45
69
  {children}
46
70
  </MdxComponentsContext.Provider>
47
71
  )
@@ -1,4 +1,4 @@
1
- import { createContext, useContext } from 'react'
1
+ import { createContext, use } from 'react'
2
2
  import type { ComponentRoute } from '../types'
3
3
 
4
4
  interface RoutesContextType {
@@ -13,7 +13,7 @@ const RoutesContext = createContext<RoutesContextType>({
13
13
  * Hook to access the processed routes list from the closest provider.
14
14
  */
15
15
  export function useRoutesContext() {
16
- return useContext(RoutesContext)
16
+ return use(RoutesContext)
17
17
  }
18
18
 
19
19
  /**
@@ -41,7 +41,7 @@ export function ScrollHandler() {
41
41
  const elementPosition = elementRect - containerTop
42
42
  const offsetPosition = elementPosition - offset + getScrollTop()
43
43
 
44
- scrollTo(offsetPosition, 'smooth')
44
+ scrollTo(offsetPosition, 'auto')
45
45
  return
46
46
  }
47
47
  }
@@ -26,8 +26,7 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
26
26
  const applyTheme = (targetTheme: Theme) => {
27
27
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
28
28
  const isDark =
29
- targetTheme === 'dark' ||
30
- (targetTheme === 'system' && mediaQuery.matches)
29
+ targetTheme === 'dark' || (targetTheme === 'system' && mediaQuery.matches)
31
30
 
32
31
  const root = window.document.documentElement
33
32
  root.classList.toggle('dark', isDark)
@@ -46,7 +45,8 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
46
45
 
47
46
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
48
47
  const listener = () => {
49
- const current = (localStorage.getItem('boltdocs-theme') as Theme) || 'system'
48
+ const current =
49
+ (localStorage.getItem('boltdocs-theme') as Theme) || 'system'
50
50
  if (current === 'system') applyTheme('system')
51
51
  }
52
52
 
@@ -58,7 +58,7 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
58
58
  setThemeState(newTheme)
59
59
  localStorage.setItem('boltdocs-theme', newTheme)
60
60
  applyTheme(newTheme)
61
-
61
+
62
62
  // Notify external listeners (dual-package hazard)
63
63
  if (typeof window !== 'undefined') {
64
64
  window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: newTheme }))
@@ -81,7 +81,7 @@ export function useTheme() {
81
81
 
82
82
  useEffect(() => {
83
83
  if (context) return
84
-
84
+
85
85
  const handler = () => forceUpdate({})
86
86
  window.addEventListener(THEME_EVENT, handler)
87
87
  return () => window.removeEventListener(THEME_EVENT, handler)
@@ -0,0 +1,42 @@
1
+ import { createContext, useContext, useState, useEffect } from 'react'
2
+ import { useLocation } from 'react-router-dom'
3
+
4
+ interface UIContextType {
5
+ isSidebarOpen: boolean
6
+ toggleSidebar: () => void
7
+ closeSidebar: () => void
8
+ }
9
+
10
+ const UIContext = createContext<UIContextType | undefined>(undefined)
11
+
12
+ export function UIProvider({ children }: { children: React.ReactNode }) {
13
+ const [isSidebarOpen, setIsSidebarOpen] = useState(false)
14
+ const location = useLocation()
15
+
16
+ const toggleSidebar = () => setIsSidebarOpen((prev) => !prev)
17
+ const closeSidebar = () => setIsSidebarOpen(false)
18
+
19
+ // Close sidebar on navigation
20
+ useEffect(() => {
21
+ setIsSidebarOpen(false)
22
+ }, [location.pathname])
23
+
24
+ return (
25
+ <UIContext.Provider value={{ isSidebarOpen, toggleSidebar, closeSidebar }}>
26
+ {children}
27
+ </UIContext.Provider>
28
+ )
29
+ }
30
+
31
+ export function useUI() {
32
+ const context = useContext(UIContext)
33
+ if (context === undefined) {
34
+ // Safe fallback for split bundles, independent component renders, or during SSR
35
+ return {
36
+ isSidebarOpen: false,
37
+ toggleSidebar: () => {},
38
+ closeSidebar: () => {},
39
+ }
40
+ }
41
+ return context
42
+ }
@@ -0,0 +1,85 @@
1
+ import { DocsLayout as DocsLayoutPrimitive } from './primitives/docs-layout'
2
+ import { Navbar } from './ui-base/navbar'
3
+ import { Sidebar } from './ui-base/sidebar'
4
+ import { OnThisPage } from './ui-base/on-this-page'
5
+ import { Breadcrumbs } from './ui-base/breadcrumbs'
6
+ import { PageNav } from './ui-base/page-nav'
7
+ import { ErrorBoundary } from './ui-base/error-boundary'
8
+ import { CopyMarkdown } from './ui-base/copy-markdown'
9
+ import { useRoutes } from '../hooks/use-routes'
10
+ import { useConfig } from '../app/config-context'
11
+
12
+ interface DocsLayoutThemeProps {
13
+ children?: React.ReactNode
14
+ }
15
+
16
+ /**
17
+ * Pre-assembled high-fidelity documentation layout component.
18
+ * Fully styled and optimized to adapt seamlessly to our custom Parchment/Slate theme.
19
+ */
20
+ function DocsLayoutComponent({ children }: DocsLayoutThemeProps) {
21
+ const { routes: filteredRoutes, currentRoute } = useRoutes()
22
+ const config = useConfig()
23
+
24
+ return (
25
+ <DocsLayoutPrimitive className="selection:bg-primary-500/10 selection:text-primary-500">
26
+ <Navbar />
27
+ <DocsLayoutPrimitive.Body className="bg-main">
28
+ <Sidebar routes={filteredRoutes || []} config={config} />
29
+ <DocsLayoutPrimitive.Content className="animate-in fade-in duration-500 scroll-smooth">
30
+ <DocsLayoutPrimitive.ContentMdx className="max-w-5xl px-2 pt-8 pb-24">
31
+ <DocsLayoutPrimitive.Header>
32
+ <div className="mb-4 border-b border-subtle pb-4 flex flex-wrap items-center justify-between gap-3">
33
+ <Breadcrumbs />
34
+ <CopyMarkdown
35
+ mdxRaw={currentRoute?._rawContent}
36
+ route={currentRoute}
37
+ />
38
+ </div>
39
+
40
+ {/* Inject Main Page Heading automatically */}
41
+ {currentRoute?.title && (
42
+ <h1 className="text-4xl font-bold tracking-tight text-default mb-3">
43
+ {currentRoute.title}
44
+ </h1>
45
+ )}
46
+ {currentRoute?.description && (
47
+ <p className="text-lg text-muted-foreground mb-6 leading-relaxed">
48
+ {currentRoute.description}
49
+ </p>
50
+ )}
51
+ </DocsLayoutPrimitive.Header>
52
+
53
+ <ErrorBoundary>
54
+ <div className="prose prose-neutral dark:prose-invert max-w-none">
55
+ {children}
56
+ </div>
57
+ </ErrorBoundary>
58
+
59
+ <DocsLayoutPrimitive.Footer>
60
+ <PageNav />
61
+ </DocsLayoutPrimitive.Footer>
62
+ </DocsLayoutPrimitive.ContentMdx>
63
+ </DocsLayoutPrimitive.Content>
64
+ <OnThisPage
65
+ headings={currentRoute?.headings}
66
+ editLink={config.theme?.editLink}
67
+ communityHelp={config.theme?.communityHelp}
68
+ filePath={currentRoute?.filePath}
69
+ />
70
+ </DocsLayoutPrimitive.Body>
71
+ </DocsLayoutPrimitive>
72
+ )
73
+ }
74
+
75
+ // Expose the primitive sub-components directly on the Default DocsLayout
76
+ // to maintain complete backward-compatibility for custom theme assemblies.
77
+ export const DocsLayout = Object.assign(DocsLayoutComponent, {
78
+ Body: DocsLayoutPrimitive.Body,
79
+ Content: DocsLayoutPrimitive.Content,
80
+ ContentMdx: DocsLayoutPrimitive.ContentMdx,
81
+ Header: DocsLayoutPrimitive.Header,
82
+ Footer: DocsLayoutPrimitive.Footer,
83
+ }) as any
84
+
85
+ export default DocsLayout
@@ -23,39 +23,65 @@ export const Github = (props: WrapperProps) => (
23
23
  </svg>
24
24
  )
25
25
 
26
- export const Discord = (props: WrapperProps) => (
26
+ export const Csv = (props: WrapperProps) => (
27
27
  <svg
28
28
  xmlns="http://www.w3.org/2000/svg"
29
+ fill="none"
29
30
  viewBox="0 0 24 24"
30
- fill="currentColor"
31
31
  {...wrapperProps(props)}
32
32
  >
33
- <title>{'Discord'}</title>
34
- <path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418Z" />
33
+ <title>{'CSV'}</title>
34
+ <mask
35
+ id="a"
36
+ maskUnits="userSpaceOnUse"
37
+ x="3"
38
+ y="3"
39
+ width="18"
40
+ height="18"
41
+ fill="#000"
42
+ >
43
+ <path fill="#fff" d="M3 3h18v18H3z" />
44
+ <path
45
+ fillRule="evenodd"
46
+ clipRule="evenodd"
47
+ d="M15.8889 5H8.11111C6.39289 5 5 6.39289 5 8.11111v7.77779C5 17.6071 6.39289 19 8.11111 19h7.77779C17.6071 19 19 17.6071 19 15.8889V8.11111C19 6.39289 17.6071 5 15.8889 5Zm0 12.4444H8.1111c-.05369 0-.10674-.0027-.15904-.008.0523.0053.10536.008.15905.008h7.77779Zm1.5555-1.5555c0 .8054-.6121 1.4679-1.3965 1.5475.7844-.0797 1.3965-.7421 1.3965-1.5475V8.11111v7.77779Z"
48
+ />
49
+ </mask>
50
+ <path
51
+ d="M15.8889 19.4444c1.1046 0 2-.8954 2-2 0-1.1045-.8954-2-2-2v4Zm-7.7778-2 .00001-2H8.1111v2Zm-.15904-.008.20206-1.9898c-1.09891-.1115-2.08022.6888-2.19182 1.7877-.1116 1.099.68877 2.0803 1.78768 2.1919l.20208-1.9898Zm8.09584 0-.2021-1.9897c-1.0989.1116-1.8992 1.0929-1.7876 2.1918.1116 1.0989 1.0929 1.8993 2.1918 1.7877l-.2021-1.9898Zm3.3965-9.32529c0-1.10457-.8954-2-2-2-1.1045 0-2 .89543-2 2h4ZM8.11111 7h7.77779V3H8.11111v4ZM7 8.11111C7 7.49746 7.49746 7 8.11111 7V3C5.28832 3 3 5.28832 3 8.11111h4Zm0 7.77779V8.11111H3v7.77779h4ZM8.11111 17C7.49746 17 7 16.5025 7 15.8889H3C3 18.7117 5.28832 21 8.11111 21v-4Zm7.77779 0H8.11111v4h7.77779v-4ZM17 15.8889C17 16.5025 16.5025 17 15.8889 17v4C18.7117 21 21 18.7117 21 15.8889h-4Zm0-7.77779v7.77779h4V8.11111h-4ZM15.8889 7C16.5025 7 17 7.49746 17 8.11111h4C21 5.28832 18.7117 3 15.8889 3v4Zm0 8.4444H8.11111l-.00001 4h7.7778v-4Zm-7.7778 0c.01378 0 .02816.0007.04302.0022l-.40411 3.9796c.11944.0121.23994.0182.36109.0182v-4Zm-.36112 3.9818c.11935.0121.23985.0182.36113.0182v-4c.01389 0 .02828.0008.04304.0022l-.40417 3.9796Zm.36113.0182h7.77779v-4H8.11111v4Zm8.13889-.0182c1.7951-.1823 3.1944-1.6951 3.1944-3.5373h-4c0-.2314.1752-.4193.4015-.4423l.4041 3.9796Zm-.8056-3.5373c0-.2314.1752-.4193.4014-.4422l.4042 3.9795c1.795-.1823 3.1944-1.6951 3.1944-3.5373h-4Zm0-7.77779v7.77779h4V8.11111h-4Zm4 0c0-.07155-.0038-.14596-.0124-.22267-.0086-.07678-.0218-.15478-.0403-.23343-.0184-.07869-.0416-.15651-.0697-.233-.0281-.07648-.0604-.15005-.0963-.22045-.036-.07036-.0749-.13629-.1158-.1978-.0408-.06145-.0832-.11775-.1258-.16912-.085-.10251-.1704-.18478-.2468-.2495-.0383-.03245-.0749-.061-.1089-.08594-.034-.02494-.0659-.04672-.0949-.06556-.029-.01883-.0558-.03518-.0797-.04914-.0239-.01396-.0456-.02598-.0644-.03606-.0188-.01008-.0355-.01864-.0493-.02558-.0139-.00694-.0257-.01268-.0348-.01701-.009-.00429-.0163-.00769-.0207-.00971-.0022-.00104-.004-.00187-.0051-.00238-.0006-.00025-.001-.00046-.0013-.00059-.0002-.00006-.0003-.00011-.0003-.00014-.0001-.00001-.0001-.00003-.0001-.00004v-.00001c-.0006-.00027.0028.00131.0068.00316.0044.00202.0117.00541.0207.00971.0091.00433.0209.01007.0348.01701.0138.00694.0305.0155.0493.02558.0188.01008.0405.0221.0644.03606.0239.01396.0507.03031.0797.04914.029.01883.0609.04062.0949.06556.0339.02494.0706.05349.1089.08594.0764.06472.1618.14698.2468.24949.0426.05138.085.10768.1258.16913.0409.06151.0798.12744.1157.19779.036.07041.0683.14397.0964.22046.028.07648.0513.15431.0697.23299.0185.07865.0317.15665.0403.23344.0086.07671.0124.15112.0124.22267h-4c0 .07154.0039.14595.0125.22267.0086.07678.0218.15478.0402.23343.0185.07868.0417.15651.0698.233.0281.07648.0604.15005.0963.22045.036.07036.0749.13629.1158.1978.0408.06144.0832.11775.1258.16912.0849.10251.1704.18478.2468.2495.0383.03244.0749.061.1089.08594.0339.02493.0658.04672.0949.06556.029.01883.0558.03517.0797.04914.0239.01396.0456.02598.0644.03606.0188.01007.0354.01864.0493.02558.0139.00693.0257.01268.0348.01701.009.00429.0163.00769.0207.00971.0022.00104.004.00187.0051.00237.0006.00026.001.00047.0013.00059.0001.00007.0003.00012.0003.00015.0001.00001.0001.00003.0001.00004v.00001c.0006.00026-.0028-.00131-.0068-.00316-.0044-.00202-.0117-.00542-.0207-.00971-.0091-.00433-.0209-.01008-.0348-.01701-.0139-.00694-.0305-.01551-.0493-.02558-.0188-.01008-.0405-.0221-.0644-.03606-.0239-.01396-.0507-.03031-.0797-.04914-.029-.01884-.061-.04062-.0949-.06556-.034-.02494-.0706-.0535-.1089-.08594-.0764-.06472-.1619-.14699-.2468-.2495-.0426-.05137-.085-.10767-.1258-.16912-.0409-.06151-.0798-.12744-.1158-.1978-.0359-.0704-.0682-.14397-.0963-.22045-.0281-.07649-.0513-.15431-.0698-.233-.0184-.07865-.0316-.15665-.0402-.23343-.0086-.07671-.0125-.15112-.0125-.22267h4Zm0 7.77779V8.11111h-4v7.77779h4Z"
52
+ fill="#14B8A6"
53
+ mask="url(#a)"
54
+ />
55
+ <rect x="7" y="7" width="4" height="2" rx="1" fill="#14B8A6" />
56
+ <rect x="7" y="11" width="4" height="2" rx="1" fill="#14B8A6" />
57
+ <rect x="7" y="15" width="4" height="2" rx="1" fill="#14B8A6" />
58
+ <rect x="13" y="7" width="4" height="2" rx="1" fill="#14B8A6" />
59
+ <rect x="13" y="11" width="4" height="2" rx="1" fill="#14B8A6" />
60
+ <rect x="13" y="15" width="4" height="2" rx="1" fill="#14B8A6" />
35
61
  </svg>
36
62
  )
37
63
 
38
- export const XSocial = (props: WrapperProps) => (
64
+ export const Discord = (props: WrapperProps) => (
39
65
  <svg
40
66
  xmlns="http://www.w3.org/2000/svg"
41
67
  viewBox="0 0 24 24"
42
68
  fill="currentColor"
43
69
  {...wrapperProps(props)}
44
70
  >
45
- <title>{'X'}</title>
46
- <path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z" />
71
+ <title>{'Discord'}</title>
72
+ <path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418Z" />
47
73
  </svg>
48
74
  )
49
75
 
50
- export const CodeSandbox = (props: WrapperProps) => (
76
+ export const XSocial = (props: WrapperProps) => (
51
77
  <svg
52
78
  xmlns="http://www.w3.org/2000/svg"
53
79
  viewBox="0 0 24 24"
54
80
  fill="currentColor"
55
81
  {...wrapperProps(props)}
56
82
  >
57
- <title>{'CodeSandbox'}</title>
58
- <path d="M0 24h24V0H0v2.455h21.546v19.09H2.454V0H0Z" />
83
+ <title>{'X'}</title>
84
+ <path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z" />
59
85
  </svg>
60
86
  )
61
87
 
@@ -148,7 +174,6 @@ export const BracketsOrange = (props: WrapperProps) => (
148
174
  </svg>
149
175
  )
150
176
 
151
-
152
177
  export const React = (props: WrapperProps) => (
153
178
  <svg
154
179
  xmlns="http://www.w3.org/2000/svg"
@@ -239,8 +264,7 @@ export const Rust = (props: WrapperProps) => (
239
264
  clipRule="evenodd"
240
265
  ></path>
241
266
  </svg>
242
- );
243
-
267
+ )
244
268
 
245
269
  export const BracketsRed = (props: WrapperProps) => (
246
270
  <svg
@@ -255,5 +279,4 @@ export const BracketsRed = (props: WrapperProps) => (
255
279
  d="M4.778 6.667A2.667 2.667 0 017.444 4a.889.889 0 010 1.778.889.889 0 00-.888.889v3.5c0 .701-.273 1.35-.73 1.833.457.483.73 1.132.73 1.832v3.501c0 .491.398.89.888.89a.889.889 0 010 1.777 2.667 2.667 0 01-2.666-2.667v-3.5a.889.889 0 00-.674-.863l-.43-.108a.889.889 0 010-1.724l.43-.108a.889.889 0 00.674-.862V6.667zm14.222 0A2.667 2.667 0 0016.333 4a.889.889 0 000 1.778c.491 0 .89.398.89.889v3.5c0 .701.272 1.35.729 1.833a2.664 2.664 0 00-.73 1.832v3.501a.889.889 0 01-.889.89.889.889 0 000 1.777A2.667 2.667 0 0019 17.333v-3.5c0-.408.278-.764.673-.863l.431-.108a.889.889 0 000-1.724l-.43-.108a.889.889 0 01-.674-.862V6.667z"
256
280
  ></path>
257
281
  </svg>
258
- );
259
-
282
+ )