boltdocs 2.7.10 → 2.8.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 (193) hide show
  1. package/README.md +2 -2
  2. package/dist/banner-3N4Jd_L9.d.ts +100 -0
  3. package/dist/banner-MynZD_Ox.d.cts +100 -0
  4. package/dist/cache-BMUyNiiA.mjs +6 -0
  5. package/dist/cache-CKm45d2w.cjs +6 -0
  6. package/dist/client/index.cjs +2268 -1
  7. package/dist/client/index.d.cts +86 -110
  8. package/dist/client/index.d.ts +87 -111
  9. package/dist/client/index.js +2214 -1
  10. package/dist/client/mdx.cjs +12 -1
  11. package/dist/client/mdx.d.cts +39 -93
  12. package/dist/client/mdx.d.ts +38 -93
  13. package/dist/client/mdx.js +7 -1
  14. package/dist/client/primitives.cjs +60 -1
  15. package/dist/client/primitives.d.cts +411 -347
  16. package/dist/client/primitives.d.ts +411 -347
  17. package/dist/client/primitives.js +20 -1
  18. package/dist/docs-layout-CwCq42Zt.cjs +1348 -0
  19. package/dist/docs-layout-Dn6S5g59.js +1167 -0
  20. package/dist/doctor-BArviV8X.cjs +28 -0
  21. package/dist/doctor-CgLA7_Uv.mjs +28 -0
  22. package/dist/{doctor-CrytFkqW.cjs → doctor-DyNUVe96.cjs} +1 -1
  23. package/dist/{routes-DP1vmWRj.cjs → doctor-aN_leTbh.mjs} +1 -1
  24. package/dist/{generator-ClVanhvi.mjs → generator-BHCrLU6h.mjs} +2 -2
  25. package/dist/{generator-CHqxiQhF.cjs → generator-CC2yHzhZ.cjs} +2 -2
  26. package/dist/icons-dev-DvJ-hh9x.cjs +1209 -0
  27. package/dist/icons-dev-Oju24Wjp.js +845 -0
  28. package/dist/image-Ch4-GxdO.cjs +268 -0
  29. package/dist/image-Do8V9PCW.js +214 -0
  30. package/dist/mdx-D3A2_l7P.js +520 -0
  31. package/dist/mdx-PLhhPJRS.cjs +531 -0
  32. package/dist/node/cli-entry.cjs +3 -1
  33. package/dist/node/cli-entry.mjs +3 -1
  34. package/dist/node/index.cjs +1 -1
  35. package/dist/node/index.d.cts +258 -152
  36. package/dist/node/index.d.mts +258 -150
  37. package/dist/node/index.mjs +1 -1
  38. package/dist/node/routes/worker.cjs +1 -1
  39. package/dist/node/routes/worker.mjs +1 -1
  40. package/dist/node-BmlP0eBP.cjs +159 -0
  41. package/dist/node-Y8_4ayje.mjs +159 -0
  42. package/dist/package-2nFy_NsW.cjs +6 -0
  43. package/dist/{package--0Yf0t1N.mjs → package-DAbtltXX.mjs} +1 -1
  44. package/dist/parser-B7-6PyQz.cjs +6 -0
  45. package/dist/{parser-Aq8LoH-0.cjs → parser-BzB-zCkF.cjs} +1 -1
  46. package/dist/parser-WGZdWs0X.mjs +6 -0
  47. package/dist/routes-BDDSxAl0.mjs +6 -0
  48. package/dist/routes-DJNJ-rTt.cjs +6 -0
  49. package/dist/routes-DiYC4nD2.cjs +6 -0
  50. package/dist/routes-_Bb2f4eI.mjs +6 -0
  51. package/dist/search-dialog-BXVoecTx.cjs +483 -0
  52. package/dist/search-dialog-BYhOov4S.cjs +331 -0
  53. package/dist/search-dialog-C09riYmx.js +313 -0
  54. package/dist/search-dialog-CUeAfy-8.cjs +8 -0
  55. package/dist/search-dialog-D8gLkhUV.js +453 -0
  56. package/dist/search-dialog-DHc_8FFX.js +8 -0
  57. package/dist/{sidebar-CcBkrm06.d.cts → sidebar-DNq4_ZAa.d.ts} +118 -52
  58. package/dist/{sidebar-CyZS9YOm.d.ts → sidebar-Dlkgbxs6.d.cts} +118 -52
  59. package/dist/utils-BYITg7T5.mjs +7 -0
  60. package/dist/utils-Cjmx1hhk.cjs +7 -0
  61. package/dist/worker-pool-CtqklOXq.cjs +6 -0
  62. package/dist/worker-pool-k0DY6k8T.mjs +6 -0
  63. package/package.json +5 -6
  64. package/src/shared/config-utils.ts +4 -0
  65. package/src/shared/types.ts +52 -6
  66. package/dist/cache-Ba-DZQNH.cjs +0 -6
  67. package/dist/cache-BuMZ58L5.mjs +0 -6
  68. package/dist/cards-BakZPTz9.d.ts +0 -30
  69. package/dist/cards-CQn9mXZS.d.cts +0 -30
  70. package/dist/docs-layout-KoWNZc8_.js +0 -6
  71. package/dist/docs-layout-x2yKt2cL.cjs +0 -6
  72. package/dist/doctor-Be7Ly1oM.mjs +0 -21
  73. package/dist/doctor-jMxWZyLJ.cjs +0 -21
  74. package/dist/icons-dev-B_RZIyxu.js +0 -6
  75. package/dist/icons-dev-BlV3wWFT.cjs +0 -6
  76. package/dist/image-BHhTvQzr.cjs +0 -6
  77. package/dist/image-CqKzYD8f.js +0 -6
  78. package/dist/mdx-DudBEac0.js +0 -7
  79. package/dist/mdx-r4cDQxWu.cjs +0 -7
  80. package/dist/node-DtEDyN1u.cjs +0 -111
  81. package/dist/node-_1jhMGYx.mjs +0 -111
  82. package/dist/package-DrwtlXfk.cjs +0 -6
  83. package/dist/parser-CdNbqN5y.cjs +0 -6
  84. package/dist/parser-nE792MLO.mjs +0 -6
  85. package/dist/rolldown-runtime-fkIsjY3S.mjs +0 -6
  86. package/dist/routes-2k3tbUmC.cjs +0 -6
  87. package/dist/routes-CpxZIsMM.mjs +0 -6
  88. package/dist/search-dialog-B584t9ZF.js +0 -6
  89. package/dist/search-dialog-BvBopRsZ.cjs +0 -6
  90. package/dist/search-dialog-ByvGScjt.js +0 -6
  91. package/dist/search-dialog-Cyko6TJm.cjs +0 -6
  92. package/dist/search-dialog-D6BNohIJ.js +0 -6
  93. package/dist/search-dialog-DuYTIefy.cjs +0 -6
  94. package/dist/utils-CG65J0Sc.mjs +0 -7
  95. package/dist/utils-CKunkU96.cjs +0 -7
  96. package/dist/worker-pool-CGn7DrLb.mjs +0 -6
  97. package/dist/worker-pool-Crbqgw5R.cjs +0 -6
  98. package/src/client/app/config-context.tsx +0 -51
  99. package/src/client/app/doc-page.tsx +0 -38
  100. package/src/client/app/docs-layout.tsx +0 -28
  101. package/src/client/app/head.tsx +0 -122
  102. package/src/client/app/helmet-compat.tsx +0 -36
  103. package/src/client/app/mdx-component.tsx +0 -8
  104. package/src/client/app/mdx-components-context.tsx +0 -72
  105. package/src/client/app/routes-context.tsx +0 -34
  106. package/src/client/app/scroll-handler.tsx +0 -74
  107. package/src/client/app/theme-context.tsx +0 -103
  108. package/src/client/app/ui-context.tsx +0 -42
  109. package/src/client/components/docs-layout-default.tsx +0 -85
  110. package/src/client/components/icons-dev.tsx +0 -282
  111. package/src/client/components/mdx/callout.tsx +0 -97
  112. package/src/client/components/mdx/card.tsx +0 -99
  113. package/src/client/components/mdx/cards.tsx +0 -27
  114. package/src/client/components/mdx/code-block.tsx +0 -184
  115. package/src/client/components/mdx/field.tsx +0 -33
  116. package/src/client/components/mdx/image.tsx +0 -44
  117. package/src/client/components/mdx/index.ts +0 -19
  118. package/src/client/components/mdx/table.tsx +0 -54
  119. package/src/client/components/mdx/typographics.tsx +0 -120
  120. package/src/client/components/mdx/use-code-block.ts +0 -34
  121. package/src/client/components/primitives/breadcrumbs.tsx +0 -54
  122. package/src/client/components/primitives/button-group.tsx +0 -54
  123. package/src/client/components/primitives/button.tsx +0 -6
  124. package/src/client/components/primitives/code-block.tsx +0 -120
  125. package/src/client/components/primitives/docs-layout.tsx +0 -125
  126. package/src/client/components/primitives/error-boundary.tsx +0 -107
  127. package/src/client/components/primitives/heading.tsx +0 -128
  128. package/src/client/components/primitives/helpers/observer.ts +0 -141
  129. package/src/client/components/primitives/image.tsx +0 -26
  130. package/src/client/components/primitives/link.tsx +0 -102
  131. package/src/client/components/primitives/menu.tsx +0 -137
  132. package/src/client/components/primitives/navbar.tsx +0 -466
  133. package/src/client/components/primitives/on-this-page.tsx +0 -430
  134. package/src/client/components/primitives/page-nav.tsx +0 -51
  135. package/src/client/components/primitives/popover.tsx +0 -28
  136. package/src/client/components/primitives/search-dialog.tsx +0 -193
  137. package/src/client/components/primitives/sidebar.tsx +0 -423
  138. package/src/client/components/primitives/skeleton.tsx +0 -26
  139. package/src/client/components/primitives/tabs.tsx +0 -70
  140. package/src/client/components/primitives/tooltip.tsx +0 -81
  141. package/src/client/components/primitives/types.ts +0 -11
  142. package/src/client/components/ui-base/banner.tsx +0 -66
  143. package/src/client/components/ui-base/breadcrumbs.tsx +0 -44
  144. package/src/client/components/ui-base/copy-markdown.tsx +0 -107
  145. package/src/client/components/ui-base/error-boundary.tsx +0 -15
  146. package/src/client/components/ui-base/github-stars.tsx +0 -29
  147. package/src/client/components/ui-base/icons.tsx +0 -240
  148. package/src/client/components/ui-base/index.ts +0 -16
  149. package/src/client/components/ui-base/last-updated.tsx +0 -27
  150. package/src/client/components/ui-base/navbar.tsx +0 -266
  151. package/src/client/components/ui-base/not-found.tsx +0 -26
  152. package/src/client/components/ui-base/on-this-page.tsx +0 -57
  153. package/src/client/components/ui-base/page-nav.tsx +0 -50
  154. package/src/client/components/ui-base/search-dialog.tsx +0 -163
  155. package/src/client/components/ui-base/search-highlight.tsx +0 -10
  156. package/src/client/components/ui-base/sidebar.tsx +0 -92
  157. package/src/client/components/ui-base/tabs.tsx +0 -83
  158. package/src/client/components/ui-base/theme-toggle.tsx +0 -130
  159. package/src/client/components/ui-base/version-i18n.tsx +0 -80
  160. package/src/client/hooks/index.ts +0 -13
  161. package/src/client/hooks/use-analytics.ts +0 -272
  162. package/src/client/hooks/use-breadcrumbs.ts +0 -22
  163. package/src/client/hooks/use-i18n.ts +0 -182
  164. package/src/client/hooks/use-localized-to.ts +0 -113
  165. package/src/client/hooks/use-location.ts +0 -5
  166. package/src/client/hooks/use-navbar.ts +0 -130
  167. package/src/client/hooks/use-page-nav.ts +0 -46
  168. package/src/client/hooks/use-routes.ts +0 -108
  169. package/src/client/hooks/use-search-highlight.ts +0 -185
  170. package/src/client/hooks/use-search.ts +0 -118
  171. package/src/client/hooks/use-sidebar.ts +0 -205
  172. package/src/client/hooks/use-tabs.ts +0 -46
  173. package/src/client/hooks/use-version.ts +0 -111
  174. package/src/client/index.ts +0 -31
  175. package/src/client/mdx.ts +0 -2
  176. package/src/client/primitives.ts +0 -19
  177. package/src/client/ssg/boltdocs-shell.tsx +0 -148
  178. package/src/client/ssg/create-routes.tsx +0 -473
  179. package/src/client/ssg/index.ts +0 -4
  180. package/src/client/ssg/mdx-page.tsx +0 -38
  181. package/src/client/store/boltdocs-context.tsx +0 -137
  182. package/src/client/theme/neutral.css +0 -141
  183. package/src/client/theme/reset.css +0 -189
  184. package/src/client/types.ts +0 -116
  185. package/src/client/utils/cn.ts +0 -6
  186. package/src/client/utils/copy-clipboard.ts +0 -22
  187. package/src/client/utils/get-base-file-path.ts +0 -21
  188. package/src/client/utils/github.ts +0 -121
  189. package/src/client/utils/i18n.ts +0 -23
  190. package/src/client/utils/path.ts +0 -9
  191. package/src/client/utils/react-to-text.ts +0 -34
  192. package/src/client/virtual.d.ts +0 -24
  193. /package/dist/{meta-loader-CWg2gnbY.mjs → meta-loader-DzwDFtdT.mjs} +0 -0
@@ -1,122 +0,0 @@
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
- }
@@ -1,36 +0,0 @@
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,8 +0,0 @@
1
- import { NotFound } from '../components/ui-base/not-found'
2
- import { mdx_components_default } from '../components/mdx'
3
-
4
- export const mdxComponentsDefault = {
5
- ...mdx_components_default,
6
- NotFound,
7
- '404': NotFound,
8
- }
@@ -1,72 +0,0 @@
1
- import { createContext, use, useMemo } from 'react'
2
- import type { BoltdocsMdxComponents } from '../../shared/types'
3
-
4
- export type MdxComponentsType = {
5
- [key: string]: React.ComponentType<any>
6
- } & {
7
- Frontmatter?: Record<string, React.ComponentType<any>>
8
- }
9
-
10
- const MDX_COMPONENTS_CONTEXT_SYMBOL = Symbol.for(
11
- '__BDOCS_MDX_COMPONENTS_CONTEXT__',
12
- )
13
- const MDX_COMPONENTS_INSTANCE_SYMBOL = Symbol.for(
14
- '__BDOCS_MDX_COMPONENTS_INSTANCE__',
15
- )
16
-
17
- const MdxComponentsContext =
18
- (globalThis as any)[MDX_COMPONENTS_CONTEXT_SYMBOL] ||
19
- ((globalThis as any)[MDX_COMPONENTS_CONTEXT_SYMBOL] =
20
- createContext<MdxComponentsType>({}))
21
-
22
- export function useMdxComponents(): BoltdocsMdxComponents {
23
- const context = use(MdxComponentsContext)
24
-
25
- // Fallback to global registry for dual-package hazards
26
- if (
27
- (!context || Object.keys(context).length === 0) &&
28
- (globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL]
29
- ) {
30
- return (globalThis as any)[
31
- MDX_COMPONENTS_INSTANCE_SYMBOL
32
- ] as BoltdocsMdxComponents
33
- }
34
-
35
- return context as any as BoltdocsMdxComponents
36
- }
37
-
38
- export function MdxComponentsProvider({
39
- components,
40
- children,
41
- }: {
42
- components: Record<string, React.ComponentType<any>>
43
- children: React.ReactNode
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
-
62
- // Sync with global registry
63
- if (typeof globalThis !== 'undefined') {
64
- ;(globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL] = processedComponents
65
- }
66
-
67
- return (
68
- <MdxComponentsContext.Provider value={processedComponents}>
69
- {children}
70
- </MdxComponentsContext.Provider>
71
- )
72
- }
@@ -1,34 +0,0 @@
1
- import { createContext, use } from 'react'
2
- import type { ComponentRoute } from '../types'
3
-
4
- interface RoutesContextType {
5
- routes: ComponentRoute[]
6
- }
7
-
8
- const RoutesContext = createContext<RoutesContextType>({
9
- routes: [],
10
- })
11
-
12
- /**
13
- * Hook to access the processed routes list from the closest provider.
14
- */
15
- export function useRoutesContext() {
16
- return use(RoutesContext)
17
- }
18
-
19
- /**
20
- * Provider component for the documentation routes.
21
- */
22
- export function RoutesProvider({
23
- routes,
24
- children,
25
- }: {
26
- routes: ComponentRoute[]
27
- children: React.ReactNode
28
- }) {
29
- return (
30
- <RoutesContext.Provider value={{ routes }}>
31
- {children}
32
- </RoutesContext.Provider>
33
- )
34
- }
@@ -1,74 +0,0 @@
1
- import { useEffect, useLayoutEffect } from 'react'
2
- import { useLocation } from 'react-router-dom'
3
-
4
- /**
5
- * Handles scroll restoration and hash scrolling on navigation.
6
- * It ensures the page scrolls to top on pathname changes,
7
- * or specifically to an anchor element if a hash is present.
8
- */
9
- export function ScrollHandler() {
10
- const { pathname, hash } = useLocation()
11
-
12
- // Helper to handle scroll logic
13
- const handleScroll = (behavior: ScrollBehavior = 'auto') => {
14
- const container = document.querySelector('.boltdocs-content') || window
15
-
16
- const getScrollTop = () => {
17
- if (container === window) return window.scrollY
18
- return (container as HTMLElement).scrollTop
19
- }
20
-
21
- const scrollTo = (top: number, scrollBehavior: ScrollBehavior) => {
22
- if (container === window) {
23
- window.scrollTo({ top, behavior: scrollBehavior })
24
- } else {
25
- ;(container as HTMLElement).scrollTo({ top, behavior: scrollBehavior })
26
- }
27
- }
28
-
29
- if (hash) {
30
- const id = hash.replace('#', '')
31
- const element = document.getElementById(id)
32
- if (element) {
33
- const offset = 80
34
- const containerTop =
35
- container === window
36
- ? 0
37
- : (container as HTMLElement).getBoundingClientRect().top
38
- const elementRect = element.getBoundingClientRect().top
39
- const elementPosition = elementRect - containerTop
40
- const offsetPosition = elementPosition - offset + getScrollTop()
41
-
42
- scrollTo(offsetPosition, behavior)
43
- return true
44
- }
45
- }
46
-
47
- scrollTo(0, behavior)
48
- return false
49
- }
50
-
51
- // 1. Immediate sync scroll before paint
52
- // biome-ignore lint/correctness/useExhaustiveDependencies: pathname is used as a trigger for scroll-to-top on navigation
53
- useLayoutEffect(() => {
54
- handleScroll('auto')
55
- }, [pathname, hash])
56
-
57
- // 2. Delayed async scroll as fallback/stabilizer after paint & passive effects
58
- useEffect(() => {
59
- // Immediate run after paint (helps override old component unmount/revert side effects)
60
- handleScroll('auto')
61
-
62
- // Double-check inside requestAnimationFrame to catch concurrent renders or dynamic layout recalculations
63
- const rafId = requestAnimationFrame(() => {
64
- handleScroll('auto')
65
- // Dispatch resize event so external components/scroll libraries (like GSAP ScrollTrigger) recalculate trigger offsets
66
- window.dispatchEvent(new Event('resize'))
67
- })
68
-
69
- return () => cancelAnimationFrame(rafId)
70
- }, [pathname, hash])
71
-
72
- return null
73
- }
74
-
@@ -1,103 +0,0 @@
1
- import { createContext, use, useState, useEffect } from 'react'
2
-
3
- export type Theme = 'light' | 'dark' | 'system'
4
- export type ResolvedTheme = 'light' | 'dark'
5
-
6
- interface ThemeContextType {
7
- theme: Theme
8
- resolvedTheme: ResolvedTheme
9
- setTheme: (theme: Theme) => void
10
- }
11
-
12
- const THEME_CONTEXT_SYMBOL = Symbol.for('__BDOCS_THEME_CONTEXT__')
13
- const THEME_INSTANCE_SYMBOL = Symbol.for('__BDOCS_THEME_INSTANCE__')
14
- const THEME_EVENT = 'boltdocs-theme-change'
15
-
16
- const ThemeContext =
17
- (globalThis as any)[THEME_CONTEXT_SYMBOL] ||
18
- ((globalThis as any)[THEME_CONTEXT_SYMBOL] = createContext<
19
- ThemeContextType | undefined
20
- >(undefined))
21
-
22
- export function ThemeProvider({ children }: { children: React.ReactNode }) {
23
- const [theme, setThemeState] = useState<Theme>('system')
24
- const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>('dark')
25
-
26
- const applyTheme = (targetTheme: Theme) => {
27
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
28
- const isDark =
29
- targetTheme === 'dark' || (targetTheme === 'system' && mediaQuery.matches)
30
-
31
- const root = window.document.documentElement
32
- root.classList.toggle('dark', isDark)
33
- root.dataset.theme = isDark ? 'dark' : 'light'
34
- setResolvedTheme(isDark ? 'dark' : 'light')
35
- }
36
-
37
- useEffect(() => {
38
- const savedTheme = localStorage.getItem('boltdocs-theme') as Theme | null
39
- if (savedTheme) {
40
- setThemeState(savedTheme)
41
- applyTheme(savedTheme)
42
- } else {
43
- applyTheme('system')
44
- }
45
-
46
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
47
- const listener = () => {
48
- const current =
49
- (localStorage.getItem('boltdocs-theme') as Theme) || 'system'
50
- if (current === 'system') applyTheme('system')
51
- }
52
-
53
- mediaQuery.addEventListener('change', listener)
54
- return () => mediaQuery.removeEventListener('change', listener)
55
- }, [])
56
-
57
- const setTheme = (newTheme: Theme) => {
58
- setThemeState(newTheme)
59
- localStorage.setItem('boltdocs-theme', newTheme)
60
- applyTheme(newTheme)
61
-
62
- // Notify external listeners (dual-package hazard)
63
- if (typeof window !== 'undefined') {
64
- window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: newTheme }))
65
- }
66
- }
67
-
68
- const value = { theme, resolvedTheme, setTheme }
69
-
70
- // Sync with global registry
71
- if (typeof globalThis !== 'undefined') {
72
- ;(globalThis as any)[THEME_INSTANCE_SYMBOL] = value
73
- }
74
-
75
- return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
76
- }
77
-
78
- export function useTheme() {
79
- const context = use(ThemeContext)
80
- const [, forceUpdate] = useState({})
81
-
82
- useEffect(() => {
83
- if (context) return
84
-
85
- const handler = () => forceUpdate({})
86
- window.addEventListener(THEME_EVENT, handler)
87
- return () => window.removeEventListener(THEME_EVENT, handler)
88
- }, [context])
89
-
90
- // Fallback to global registry for dual-package hazards
91
- if (
92
- !context &&
93
- typeof globalThis !== 'undefined' &&
94
- (globalThis as any)[THEME_INSTANCE_SYMBOL]
95
- ) {
96
- return (globalThis as any)[THEME_INSTANCE_SYMBOL] as ThemeContextType
97
- }
98
-
99
- if (context === undefined) {
100
- throw new Error('useTheme must be used within a ThemeProvider')
101
- }
102
- return context as ThemeContextType
103
- }
@@ -1,42 +0,0 @@
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
- }
@@ -1,85 +0,0 @@
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-3xl sm:max-w-4xl lg:max-w-4xl 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