boltdocs 1.10.1 → 1.11.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 (226) hide show
  1. package/package.json +29 -7
  2. package/src/client/app/config-context.tsx +18 -0
  3. package/src/client/app/docs-layout.tsx +14 -0
  4. package/src/client/app/index.tsx +132 -260
  5. package/src/client/app/mdx-component.tsx +52 -0
  6. package/src/client/app/mdx-components-context.tsx +23 -0
  7. package/src/client/app/mdx-page.tsx +20 -0
  8. package/src/client/app/preload.tsx +38 -30
  9. package/src/client/app/router.tsx +30 -0
  10. package/src/client/app/scroll-handler.tsx +40 -0
  11. package/src/client/app/theme-context.tsx +75 -0
  12. package/src/client/components/default-layout.tsx +80 -0
  13. package/src/client/components/docs-layout.tsx +105 -0
  14. package/src/client/components/icons-dev.tsx +74 -0
  15. package/src/client/components/mdx/admonition.tsx +107 -0
  16. package/src/client/components/mdx/badge.tsx +41 -0
  17. package/src/client/components/mdx/button.tsx +35 -0
  18. package/src/client/components/mdx/card.tsx +124 -0
  19. package/src/client/components/mdx/code-block.tsx +119 -0
  20. package/src/client/components/mdx/component-preview.tsx +47 -0
  21. package/src/client/components/mdx/component-props.tsx +83 -0
  22. package/src/client/components/mdx/field.tsx +66 -0
  23. package/src/client/components/mdx/file-tree.tsx +287 -0
  24. package/src/client/components/mdx/hooks/use-code-block.ts +56 -0
  25. package/src/client/components/mdx/hooks/use-component-preview.ts +16 -0
  26. package/src/client/components/mdx/hooks/useTable.ts +74 -0
  27. package/src/client/components/mdx/hooks/useTabs.ts +68 -0
  28. package/src/client/components/mdx/image.tsx +23 -0
  29. package/src/client/components/mdx/index.ts +53 -0
  30. package/src/client/components/mdx/link.tsx +38 -0
  31. package/src/client/components/mdx/list.tsx +192 -0
  32. package/src/client/components/mdx/table.tsx +156 -0
  33. package/src/client/components/mdx/tabs.tsx +135 -0
  34. package/src/client/components/mdx/video.tsx +68 -0
  35. package/src/client/components/primitives/breadcrumbs.tsx +79 -0
  36. package/src/client/components/primitives/button-group.tsx +54 -0
  37. package/src/client/components/primitives/button.tsx +145 -0
  38. package/src/client/components/primitives/helpers/observer.ts +120 -0
  39. package/src/client/components/primitives/index.ts +17 -0
  40. package/src/client/components/primitives/link.tsx +122 -0
  41. package/src/client/components/primitives/menu.tsx +159 -0
  42. package/src/client/components/primitives/navbar.tsx +359 -0
  43. package/src/client/components/primitives/navigation-menu.tsx +116 -0
  44. package/src/client/components/primitives/on-this-page.tsx +461 -0
  45. package/src/client/components/primitives/page-nav.tsx +87 -0
  46. package/src/client/components/primitives/popover.tsx +47 -0
  47. package/src/client/components/primitives/search-dialog.tsx +183 -0
  48. package/src/client/components/primitives/sidebar.tsx +154 -0
  49. package/src/client/components/primitives/tabs.tsx +90 -0
  50. package/src/client/components/primitives/tooltip.tsx +83 -0
  51. package/src/client/components/primitives/types.ts +11 -0
  52. package/src/client/components/ui-base/breadcrumbs.tsx +42 -0
  53. package/src/client/components/ui-base/copy-markdown.tsx +112 -0
  54. package/src/client/components/ui-base/error-boundary.tsx +52 -0
  55. package/src/client/components/ui-base/github-stars.tsx +27 -0
  56. package/src/client/components/ui-base/head.tsx +69 -0
  57. package/src/client/components/ui-base/loading.tsx +87 -0
  58. package/src/client/components/ui-base/navbar.tsx +138 -0
  59. package/src/client/components/ui-base/not-found.tsx +24 -0
  60. package/src/client/components/ui-base/on-this-page.tsx +152 -0
  61. package/src/client/components/ui-base/page-nav.tsx +39 -0
  62. package/src/client/components/ui-base/powered-by.tsx +19 -0
  63. package/src/client/components/ui-base/progress-bar.tsx +67 -0
  64. package/src/client/components/ui-base/search-dialog.tsx +82 -0
  65. package/src/client/components/ui-base/sidebar.tsx +104 -0
  66. package/src/client/components/ui-base/tabs.tsx +65 -0
  67. package/src/client/components/ui-base/theme-toggle.tsx +32 -0
  68. package/src/client/hooks/index.ts +12 -0
  69. package/src/client/hooks/use-breadcrumbs.ts +22 -0
  70. package/src/client/hooks/use-i18n.ts +84 -0
  71. package/src/client/hooks/use-localized-to.ts +95 -0
  72. package/src/client/hooks/use-location.ts +5 -0
  73. package/src/client/hooks/use-navbar.ts +60 -0
  74. package/src/client/hooks/use-onthispage.ts +23 -0
  75. package/src/client/hooks/use-page-nav.ts +22 -0
  76. package/src/client/hooks/use-routes.ts +72 -0
  77. package/src/client/hooks/use-search.ts +71 -0
  78. package/src/client/hooks/use-sidebar.ts +49 -0
  79. package/src/client/hooks/use-tabs.ts +43 -0
  80. package/src/client/hooks/use-version.ts +78 -0
  81. package/src/client/index.ts +55 -18
  82. package/src/client/integrations/codesandbox.ts +179 -0
  83. package/src/client/ssr.tsx +27 -16
  84. package/src/client/theme/neutral.css +360 -0
  85. package/src/client/types.ts +131 -27
  86. package/src/client/utils/cn.ts +6 -0
  87. package/src/client/utils/copy-clipboard.ts +22 -0
  88. package/src/client/utils/get-base-file-path.ts +21 -0
  89. package/src/client/utils/github.ts +121 -0
  90. package/src/client/utils/use-on-change.ts +15 -0
  91. package/src/client/virtual.d.ts +24 -0
  92. package/src/node/cache.ts +156 -156
  93. package/src/node/config.ts +159 -103
  94. package/src/node/index.ts +13 -13
  95. package/src/node/mdx.ts +213 -61
  96. package/src/node/plugin/entry.ts +29 -18
  97. package/src/node/plugin/html.ts +11 -11
  98. package/src/node/plugin/index.ts +161 -83
  99. package/src/node/plugin/types.ts +2 -4
  100. package/src/node/routes/cache.ts +6 -6
  101. package/src/node/routes/index.ts +206 -113
  102. package/src/node/routes/parser.ts +106 -81
  103. package/src/node/routes/sorter.ts +15 -15
  104. package/src/node/routes/types.ts +24 -24
  105. package/src/node/ssg/index.ts +46 -46
  106. package/src/node/ssg/meta.ts +4 -4
  107. package/src/node/ssg/options.ts +5 -5
  108. package/src/node/ssg/sitemap.ts +14 -14
  109. package/src/node/utils.ts +31 -31
  110. package/tsconfig.json +25 -20
  111. package/tsup.config.ts +23 -14
  112. package/dist/PackageManagerTabs-NVT7G625.mjs +0 -99
  113. package/dist/SearchDialog-BEVZQ74P.css +0 -2679
  114. package/dist/SearchDialog-MEWGAONO.mjs +0 -194
  115. package/dist/Video-KNTY5BNO.mjs +0 -6
  116. package/dist/cache-KNL5B4EE.mjs +0 -12
  117. package/dist/chunk-7SFUJWTB.mjs +0 -211
  118. package/dist/chunk-FFBNU6IJ.mjs +0 -386
  119. package/dist/chunk-FMTOYQLO.mjs +0 -37
  120. package/dist/chunk-OZLYRXAD.mjs +0 -1914
  121. package/dist/chunk-Z7JHYNAS.mjs +0 -57
  122. package/dist/client/index.css +0 -2679
  123. package/dist/client/index.d.mts +0 -379
  124. package/dist/client/index.d.ts +0 -379
  125. package/dist/client/index.js +0 -3594
  126. package/dist/client/index.mjs +0 -658
  127. package/dist/client/ssr.css +0 -2679
  128. package/dist/client/ssr.d.mts +0 -27
  129. package/dist/client/ssr.d.ts +0 -27
  130. package/dist/client/ssr.js +0 -2930
  131. package/dist/client/ssr.mjs +0 -33
  132. package/dist/config-BsFQ-ErD.d.mts +0 -159
  133. package/dist/config-BsFQ-ErD.d.ts +0 -159
  134. package/dist/node/index.d.mts +0 -91
  135. package/dist/node/index.d.ts +0 -91
  136. package/dist/node/index.js +0 -1187
  137. package/dist/node/index.mjs +0 -762
  138. package/dist/types-Dj-bfnC3.d.mts +0 -74
  139. package/dist/types-Dj-bfnC3.d.ts +0 -74
  140. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +0 -40
  141. package/src/client/theme/components/CodeBlock/index.ts +0 -1
  142. package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +0 -131
  143. package/src/client/theme/components/PackageManagerTabs/index.ts +0 -1
  144. package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +0 -64
  145. package/src/client/theme/components/Playground/Playground.tsx +0 -124
  146. package/src/client/theme/components/Playground/index.ts +0 -1
  147. package/src/client/theme/components/Playground/playground.css +0 -168
  148. package/src/client/theme/components/Video/Video.tsx +0 -84
  149. package/src/client/theme/components/Video/index.ts +0 -1
  150. package/src/client/theme/components/Video/video.css +0 -41
  151. package/src/client/theme/components/mdx/Admonition.tsx +0 -80
  152. package/src/client/theme/components/mdx/Badge.tsx +0 -31
  153. package/src/client/theme/components/mdx/Button.tsx +0 -50
  154. package/src/client/theme/components/mdx/Card.tsx +0 -80
  155. package/src/client/theme/components/mdx/Field.tsx +0 -60
  156. package/src/client/theme/components/mdx/FileTree.tsx +0 -229
  157. package/src/client/theme/components/mdx/List.tsx +0 -57
  158. package/src/client/theme/components/mdx/Table.tsx +0 -151
  159. package/src/client/theme/components/mdx/Tabs.tsx +0 -123
  160. package/src/client/theme/components/mdx/index.ts +0 -27
  161. package/src/client/theme/components/mdx/mdx-components.css +0 -764
  162. package/src/client/theme/icons/bun.tsx +0 -62
  163. package/src/client/theme/icons/deno.tsx +0 -20
  164. package/src/client/theme/icons/discord.tsx +0 -12
  165. package/src/client/theme/icons/github.tsx +0 -15
  166. package/src/client/theme/icons/npm.tsx +0 -13
  167. package/src/client/theme/icons/pnpm.tsx +0 -72
  168. package/src/client/theme/icons/twitter.tsx +0 -12
  169. package/src/client/theme/styles/markdown.css +0 -341
  170. package/src/client/theme/styles/variables.css +0 -187
  171. package/src/client/theme/styles.css +0 -38
  172. package/src/client/theme/ui/BackgroundGradient/BackgroundGradient.tsx +0 -10
  173. package/src/client/theme/ui/BackgroundGradient/index.ts +0 -1
  174. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +0 -68
  175. package/src/client/theme/ui/Breadcrumbs/index.ts +0 -1
  176. package/src/client/theme/ui/CopyMarkdown/CopyMarkdown.tsx +0 -82
  177. package/src/client/theme/ui/CopyMarkdown/copy-markdown.css +0 -114
  178. package/src/client/theme/ui/CopyMarkdown/index.ts +0 -1
  179. package/src/client/theme/ui/ErrorBoundary/ErrorBoundary.tsx +0 -46
  180. package/src/client/theme/ui/ErrorBoundary/index.ts +0 -1
  181. package/src/client/theme/ui/Footer/footer.css +0 -32
  182. package/src/client/theme/ui/Head/Head.tsx +0 -69
  183. package/src/client/theme/ui/Head/index.ts +0 -1
  184. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +0 -125
  185. package/src/client/theme/ui/LanguageSwitcher/index.ts +0 -1
  186. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +0 -98
  187. package/src/client/theme/ui/Layout/Layout.tsx +0 -208
  188. package/src/client/theme/ui/Layout/base.css +0 -105
  189. package/src/client/theme/ui/Layout/index.ts +0 -2
  190. package/src/client/theme/ui/Layout/pagination.css +0 -72
  191. package/src/client/theme/ui/Layout/responsive.css +0 -36
  192. package/src/client/theme/ui/Link/Link.tsx +0 -392
  193. package/src/client/theme/ui/Link/LinkPreview.tsx +0 -59
  194. package/src/client/theme/ui/Link/index.ts +0 -2
  195. package/src/client/theme/ui/Link/link-preview.css +0 -48
  196. package/src/client/theme/ui/Loading/Loading.tsx +0 -10
  197. package/src/client/theme/ui/Loading/index.ts +0 -1
  198. package/src/client/theme/ui/Loading/loading.css +0 -30
  199. package/src/client/theme/ui/Navbar/GithubStars.tsx +0 -27
  200. package/src/client/theme/ui/Navbar/Navbar.tsx +0 -193
  201. package/src/client/theme/ui/Navbar/Tabs.tsx +0 -99
  202. package/src/client/theme/ui/Navbar/index.ts +0 -2
  203. package/src/client/theme/ui/Navbar/navbar.css +0 -347
  204. package/src/client/theme/ui/NotFound/NotFound.tsx +0 -19
  205. package/src/client/theme/ui/NotFound/index.ts +0 -1
  206. package/src/client/theme/ui/NotFound/not-found.css +0 -64
  207. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +0 -244
  208. package/src/client/theme/ui/OnThisPage/index.ts +0 -1
  209. package/src/client/theme/ui/OnThisPage/toc.css +0 -152
  210. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +0 -18
  211. package/src/client/theme/ui/PoweredBy/index.ts +0 -1
  212. package/src/client/theme/ui/PoweredBy/powered-by.css +0 -76
  213. package/src/client/theme/ui/ProgressBar/ProgressBar.css +0 -17
  214. package/src/client/theme/ui/ProgressBar/ProgressBar.tsx +0 -51
  215. package/src/client/theme/ui/ProgressBar/index.ts +0 -1
  216. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +0 -209
  217. package/src/client/theme/ui/SearchDialog/index.ts +0 -1
  218. package/src/client/theme/ui/SearchDialog/search.css +0 -152
  219. package/src/client/theme/ui/Sidebar/Sidebar.tsx +0 -244
  220. package/src/client/theme/ui/Sidebar/index.ts +0 -1
  221. package/src/client/theme/ui/Sidebar/sidebar.css +0 -230
  222. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +0 -69
  223. package/src/client/theme/ui/ThemeToggle/index.ts +0 -1
  224. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +0 -136
  225. package/src/client/theme/ui/VersionSwitcher/index.ts +0 -1
  226. package/src/client/utils.ts +0 -49
@@ -0,0 +1,71 @@
1
+ import { useState, useMemo } from 'react'
2
+ import type { ComponentRoute } from '@client/types'
3
+
4
+ export function useSearch(routes: ComponentRoute[]) {
5
+ const [isOpen, setIsOpen] = useState(false)
6
+ const [query, setQuery] = useState('')
7
+
8
+ const list = useMemo(() => {
9
+ if (!query) {
10
+ return routes.slice(0, 10).map((r) => ({
11
+ id: r.path,
12
+ title: r.title,
13
+ path: r.path,
14
+ bio: r.description || '',
15
+ groupTitle: r.groupTitle,
16
+ }))
17
+ }
18
+
19
+ const results: any[] = []
20
+ const lowerQuery = query.toLowerCase()
21
+
22
+ for (const route of routes) {
23
+ if (route.title?.toLowerCase().includes(lowerQuery)) {
24
+ results.push({
25
+ id: route.path,
26
+ title: route.title,
27
+ path: route.path,
28
+ bio: route.description || '',
29
+ groupTitle: route.groupTitle,
30
+ })
31
+ }
32
+
33
+ if (route.headings) {
34
+ for (const heading of route.headings) {
35
+ if (heading.text.toLowerCase().includes(lowerQuery)) {
36
+ results.push({
37
+ id: `${route.path}#${heading.id}`,
38
+ title: heading.text,
39
+ path: `${route.path}#${heading.id}`,
40
+ bio: `Heading in ${route.title}`,
41
+ groupTitle: route.title,
42
+ isHeading: true,
43
+ })
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ // Deduplicate by path
50
+ const seen = new Set()
51
+ return results
52
+ .filter((r) => {
53
+ if (seen.has(r.path)) return false
54
+ seen.add(r.path)
55
+ return true
56
+ })
57
+ .slice(0, 10)
58
+ }, [routes, query])
59
+
60
+ return {
61
+ isOpen,
62
+ setIsOpen,
63
+ query,
64
+ setQuery,
65
+ list,
66
+ input: {
67
+ value: query,
68
+ onChange: (e: any) => setQuery(e.target.value),
69
+ },
70
+ }
71
+ }
@@ -0,0 +1,49 @@
1
+ import { useLocation } from 'react-router-dom'
2
+ import { useConfig } from '@client/app/config-context'
3
+ import type { ComponentRoute } from '../types'
4
+
5
+ export function useSidebar(routes: ComponentRoute[]) {
6
+ const config = useConfig()
7
+ const location = useLocation()
8
+
9
+ // Find active route and tab
10
+ const activeRoute = routes.find((r) => r.path === location.pathname)
11
+ const activeTabId = activeRoute?.tab?.toLowerCase()
12
+
13
+ // Filter routes by active tab if any
14
+ const filteredRoutes = activeTabId
15
+ ? routes.filter((r) => !r.tab || r.tab.toLowerCase() === activeTabId)
16
+ : routes
17
+
18
+ const ungrouped: ComponentRoute[] = []
19
+ const groupsMap = new Map<
20
+ string,
21
+ { slug: string; title: string; routes: ComponentRoute[]; icon?: string }
22
+ >()
23
+
24
+ for (const route of filteredRoutes) {
25
+ if (!route.group) {
26
+ ungrouped.push(route)
27
+ } else {
28
+ if (!groupsMap.has(route.group)) {
29
+ groupsMap.set(route.group, {
30
+ slug: route.group,
31
+ title: route.groupTitle || route.group,
32
+ routes: [],
33
+ icon: route.groupIcon,
34
+ })
35
+ }
36
+ groupsMap.get(route.group)!.routes.push(route)
37
+ }
38
+ }
39
+
40
+ const groups = Array.from(groupsMap.values())
41
+
42
+ return {
43
+ groups,
44
+ ungrouped,
45
+ activeRoute,
46
+ activePath: location.pathname,
47
+ config,
48
+ }
49
+ }
@@ -0,0 +1,43 @@
1
+ import { useLocation } from 'react-router-dom'
2
+ import { useEffect, useState, useRef } from 'react'
3
+ import type { ComponentRoute, BoltdocsTab } from '@client/types'
4
+
5
+ export function useTabs(
6
+ tabs: BoltdocsTab[] = [],
7
+ routes: ComponentRoute[] = [],
8
+ ) {
9
+ const location = useLocation()
10
+ const tabRefs = useRef<(HTMLAnchorElement | null)[]>([])
11
+ const [indicatorStyle, setIndicatorStyle] = useState<React.CSSProperties>({
12
+ opacity: 0,
13
+ transform: 'translateX(0) scaleX(0)',
14
+ width: 0,
15
+ })
16
+
17
+ const activeRoute = routes.find((r) => r.path === location.pathname)
18
+ const activeTabId = activeRoute?.tab?.toLowerCase()
19
+ const activeIndex = tabs.findIndex(
20
+ (tab) => tab.id.toLowerCase() === activeTabId,
21
+ )
22
+ const finalActiveIndex = activeIndex === -1 ? 0 : activeIndex
23
+
24
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Updated pointer to the tab
25
+ useEffect(() => {
26
+ const activeTab = tabRefs.current[finalActiveIndex]
27
+ if (activeTab) {
28
+ setIndicatorStyle({
29
+ opacity: 1,
30
+ width: activeTab.offsetWidth,
31
+ transform: `translateX(${activeTab.offsetLeft}px)`,
32
+ })
33
+ }
34
+ }, [finalActiveIndex, tabs.length, location.pathname])
35
+
36
+ return {
37
+ tabs,
38
+ activeIndex: finalActiveIndex,
39
+ indicatorStyle,
40
+ tabRefs,
41
+ activeTabId,
42
+ }
43
+ }
@@ -0,0 +1,78 @@
1
+ import { useNavigate } from 'react-router-dom'
2
+ import { getBaseFilePath } from '@client/utils/get-base-file-path'
3
+ import { useRoutes } from './use-routes'
4
+
5
+ export interface VersionOption {
6
+ key: string
7
+ label: string
8
+ value: string
9
+ isCurrent: boolean
10
+ }
11
+
12
+ export interface UseVersionReturn {
13
+ currentVersion: string | undefined
14
+ currentVersionLabel: string | undefined
15
+ availableVersions: VersionOption[]
16
+ handleVersionChange: (version: string) => void
17
+ }
18
+
19
+ /**
20
+ * Hook to manage and switch between different versions of the documentation.
21
+ */
22
+ export function useVersion(): UseVersionReturn {
23
+ const navigate = useNavigate()
24
+ const routeContext = useRoutes()
25
+ const { allRoutes, currentRoute, currentVersion, currentLocale, config } =
26
+ routeContext
27
+ const versions = config.versions
28
+
29
+ const handleVersionChange = (version: string) => {
30
+ if (!versions || version === currentVersion) return
31
+
32
+ let targetPath = `/docs/${version}`
33
+
34
+ if (currentRoute) {
35
+ const baseFile = getBaseFilePath(
36
+ currentRoute.filePath,
37
+ currentRoute.version,
38
+ currentRoute.locale,
39
+ )
40
+
41
+ const targetRoute = allRoutes.find(
42
+ (r) =>
43
+ getBaseFilePath(r.filePath, r.version, r.locale) === baseFile &&
44
+ (r.version || versions.defaultVersion) === version &&
45
+ (currentLocale ? r.locale === currentLocale : !r.locale),
46
+ )
47
+
48
+ if (targetRoute) {
49
+ targetPath = targetRoute.path
50
+ } else {
51
+ const versionIndexRoute = allRoutes.find(
52
+ (r) =>
53
+ getBaseFilePath(r.filePath, r.version, r.locale) === 'index.md' &&
54
+ (r.version || versions.defaultVersion) === version &&
55
+ (currentLocale ? r.locale === currentLocale : !r.locale),
56
+ )
57
+ targetPath = versionIndexRoute
58
+ ? versionIndexRoute.path
59
+ : `/docs/${version}${currentLocale ? `/${currentLocale}` : ''}`
60
+ }
61
+ }
62
+
63
+ navigate(targetPath)
64
+ }
65
+
66
+ const availableVersions = routeContext.availableVersions.map((v) => ({
67
+ ...v,
68
+ label: v.label as string,
69
+ value: v.key,
70
+ }))
71
+
72
+ return {
73
+ currentVersion,
74
+ currentVersionLabel: routeContext.currentVersionLabel,
75
+ availableVersions,
76
+ handleVersionChange,
77
+ }
78
+ }
@@ -1,19 +1,46 @@
1
- export type { BoltdocsConfig, BoltdocsThemeConfig } from "../node/config";
2
- export type { ComponentRoute, CreateBoltdocsAppOptions } from "./types";
3
- import { PackageManagerTabs } from "./theme/components/PackageManagerTabs";
4
- export { createBoltdocsApp } from "./app";
5
- export { ThemeLayout } from "./theme/ui/Layout";
6
- export { Navbar } from "./theme/ui/Navbar";
7
- export { Sidebar } from "./theme/ui/Sidebar";
8
- export { OnThisPage } from "./theme/ui/OnThisPage";
9
- export { Head } from "./theme/ui/Head";
10
- export { Breadcrumbs } from "./theme/ui/Breadcrumbs";
11
- export { BackgroundGradient } from "./theme/ui/BackgroundGradient";
12
- export { Playground } from "./theme/components/Playground";
13
- export { NotFound } from "./theme/ui/NotFound";
14
- export { Loading } from "./theme/ui/Loading";
15
- export { CodeBlock } from "./theme/components/CodeBlock";
16
- export { Video } from "./theme/components/Video";
1
+ export type { BoltdocsConfig, BoltdocsThemeConfig } from '../node/config'
2
+ export type {
3
+ ComponentRoute,
4
+ CreateBoltdocsAppOptions,
5
+ LayoutProps,
6
+ } from './types'
7
+ export { createBoltdocsApp } from './app'
8
+ export { useConfig } from '@client/app/config-context'
9
+ export { useTheme } from '@client/app/theme-context'
10
+ export { useRoutes } from '@client/hooks/use-routes'
11
+ export { useMdxComponents } from '@client/app/mdx-components-context'
12
+
13
+ // Composable layout building blocks
14
+ export { DocsLayout } from '@components/docs-layout'
15
+ export { DefaultLayout } from '@components/default-layout'
16
+
17
+ // Default UI components (for use in custom layout.tsx)
18
+ export { Navbar } from '@components/ui-base/navbar'
19
+ export { Sidebar } from '@components/ui-base/sidebar'
20
+ export { OnThisPage } from '@components/ui-base/on-this-page'
21
+ export { Head } from '@components/ui-base/head'
22
+ export { Breadcrumbs } from '@components/ui-base/breadcrumbs'
23
+ export { PageNav } from '@components/ui-base/page-nav'
24
+ export { ProgressBar } from '@components/ui-base/progress-bar'
25
+ export { ErrorBoundary } from '@components/ui-base/error-boundary'
26
+ export { CopyMarkdown } from '@components/ui-base/copy-markdown'
27
+
28
+ export { NotFound } from '@components/ui-base/not-found'
29
+ export { Loading } from '@components/ui-base/loading'
30
+ export { CodeBlock } from '@components/mdx/code-block'
31
+ export { Video } from '@components/mdx/video'
32
+ export {
33
+ defineSandbox,
34
+ openSandbox,
35
+ embedSandbox,
36
+ } from '@integrations/codesandbox'
37
+
38
+ export type {
39
+ SandboxOptions,
40
+ SandboxFile,
41
+ SandboxFiles,
42
+ SandboxEmbedOptions,
43
+ } from './types'
17
44
  export {
18
45
  Button,
19
46
  Badge,
@@ -27,11 +54,17 @@ export {
27
54
  Warning,
28
55
  Danger,
29
56
  InfoBox,
57
+ ComponentProps,
58
+ ComponentPreview,
59
+ Important,
60
+ Caution,
30
61
  List,
31
62
  FileTree,
32
63
  Table,
33
64
  Field,
34
- } from "./theme/components/mdx";
65
+ Link,
66
+ Image,
67
+ } from './components/mdx'
35
68
  export type {
36
69
  ButtonProps,
37
70
  BadgeProps,
@@ -40,8 +73,12 @@ export type {
40
73
  TabsProps,
41
74
  TabProps,
42
75
  AdmonitionProps,
76
+ ComponentPropsProps,
77
+ ComponentPreviewProps,
43
78
  ListProps,
44
79
  FileTreeProps,
45
80
  TableProps,
46
81
  FieldProps,
47
- } from "./theme/components/mdx";
82
+ LinkProps,
83
+ ImageProps,
84
+ } from './components/mdx'
@@ -0,0 +1,179 @@
1
+ import { getParameters } from 'codesandbox/lib/api/define.js'
2
+ import { SandboxOptions } from '../types'
3
+
4
+ /**
5
+ * Build the files payload for the CodeSandbox Define API.
6
+ * Ensures every file conforms to the `{ content, isBinary }` shape
7
+ * required by the SDK, and auto-generates a `package.json` when one
8
+ * isn't explicitly provided.
9
+ */
10
+ function buildSandboxFiles(options: SandboxOptions) {
11
+ const files = options.files || {}
12
+ const dependencies = options.dependencies || {}
13
+ const devDependencies = options.devDependencies || {}
14
+ const title = options.title || 'codesandbox-project'
15
+ const description = options.description || 'Generic Sandbox'
16
+
17
+ const finalFiles: Record<string, { content: string; isBinary: boolean }> = {}
18
+
19
+ for (const [path, file] of Object.entries(files)) {
20
+ const content =
21
+ typeof file.content === 'object'
22
+ ? JSON.stringify(file.content, null, 2)
23
+ : file.content
24
+ finalFiles[path] = { content, isBinary: file.isBinary ?? false }
25
+ }
26
+
27
+ if (!finalFiles['package.json']) {
28
+ const isVite =
29
+ options.template === 'vite' ||
30
+ !!devDependencies.vite ||
31
+ !!devDependencies['@vitejs/plugin-react']
32
+
33
+ const defaultScripts = isVite
34
+ ? {
35
+ dev: 'vite',
36
+ build: 'vite build',
37
+ preview: 'vite preview',
38
+ }
39
+ : {
40
+ start: 'node index.js',
41
+ }
42
+
43
+ finalFiles['package.json'] = {
44
+ content: JSON.stringify(
45
+ {
46
+ private: true,
47
+ name: title,
48
+ description,
49
+ type: 'module',
50
+ version: '1.0.0',
51
+ scripts: options.scripts || defaultScripts,
52
+ dependencies,
53
+ devDependencies,
54
+ },
55
+ null,
56
+ 2,
57
+ ),
58
+ isBinary: false,
59
+ }
60
+ }
61
+
62
+ return finalFiles
63
+ }
64
+
65
+ /**
66
+ * Helper to define a sandbox and get a URL for the CodeSandbox Define API.
67
+ * Uses the official SDK `getParameters` for proper LZ-string compression.
68
+ */
69
+ export function defineSandbox(options: SandboxOptions) {
70
+ const finalFiles = buildSandboxFiles(options)
71
+ const parameters = getParameters({ files: finalFiles })
72
+
73
+ // FIX: Agregar query params que forzan comportamiento correcto
74
+ const query = new URLSearchParams({
75
+ parameters,
76
+ // FIX: Forzar instalación de dependencias
77
+ installDependencies: 'true',
78
+ })
79
+
80
+ // FIX: Agregar file query para que abra el entry correcto
81
+ if (options.entry) {
82
+ query.set('file', `/${options.entry}`)
83
+ }
84
+
85
+ return {
86
+ parameters,
87
+ url: `https://codesandbox.io/api/v1/sandboxes/define?${query.toString()}`,
88
+ options,
89
+ }
90
+ }
91
+
92
+ /**
93
+ * CORE API: Open a CodeSandbox using a form POST to the Define API.
94
+ *
95
+ * Uses a hidden form + POST which avoids URL length limits and is the
96
+ * recommended approach from CodeSandbox documentation. The SDK's
97
+ * `getParameters` handles LZ-string compression internally.
98
+ */
99
+ export function openSandbox(options: SandboxOptions) {
100
+ if (typeof window === 'undefined') return defineSandbox(options)
101
+
102
+ const finalFiles = buildSandboxFiles(options)
103
+ const parameters = getParameters({ files: finalFiles })
104
+ const entry = options.entry || 'src/App.tsx'
105
+
106
+ // Use form POST – the most reliable method for the Define API
107
+ const form = document.createElement('form')
108
+ form.method = 'POST'
109
+ form.target = '_blank'
110
+ form.action = 'https://codesandbox.io/api/v1/sandboxes/define'
111
+ form.style.display = 'none'
112
+
113
+ const addField = (name: string, value: string) => {
114
+ const input = document.createElement('input')
115
+ input.type = 'hidden'
116
+ input.name = name
117
+ input.value = value
118
+ form.appendChild(input)
119
+ }
120
+
121
+ const queryParams = new URLSearchParams({
122
+ file: `/${entry}`,
123
+ // FIX: Forzar vista de preview (no solo editor)
124
+ // FIX: Deshabilitar eslint que a veces bloquea
125
+ eslint: '0',
126
+ // FIX: Habilitar codemirror
127
+ codemirror: '1',
128
+ // FIX: Forzar instalación de deps
129
+ installDependencies: 'true',
130
+ })
131
+
132
+ addField('query', queryParams.toString())
133
+ addField('parameters', parameters)
134
+
135
+ document.body.appendChild(form)
136
+ form.submit()
137
+ document.body.removeChild(form)
138
+
139
+ return {
140
+ parameters,
141
+ url: `https://codesandbox.io/api/v1/sandboxes/define?parameters=${parameters}`,
142
+ options,
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Generate an embeddable iframe URL for a CodeSandbox.
148
+ *
149
+ * This gives you more control than `openSandbox` — you can embed the sandbox
150
+ * inline on the page rather than opening a new tab. The returned URL can be
151
+ * used as the `src` of an `<iframe>`.
152
+ *
153
+ * @example
154
+ * ```tsx
155
+ * const url = embedSandbox({
156
+ * files: { "index.js": { content: "console.log('hello')" } },
157
+ * embed: { view: "editor", theme: "dark" },
158
+ * }).url;
159
+ * // url → "https://codesandbox.io/api/v1/sandboxes/define?parameters=…&embed=1&view=editor&theme=dark"
160
+ * ```
161
+ */
162
+ export function embedSandbox(options: SandboxOptions) {
163
+ const finalFiles = buildSandboxFiles(options)
164
+ const parameters = getParameters({ files: finalFiles })
165
+ const embedOptions = options.embed || {}
166
+
167
+ const query = new URLSearchParams({ parameters, embed: '1' })
168
+
169
+ if (embedOptions.view) query.set('view', embedOptions.view)
170
+ if (embedOptions.theme) query.set('theme', embedOptions.theme)
171
+ if (embedOptions.hideNavigation) query.set('hidenavigation', '1')
172
+ if (options.entry) query.set('file', `/${options.entry}`)
173
+
174
+ return {
175
+ parameters,
176
+ url: `https://codesandbox.io/api/v1/sandboxes/define?${query.toString()}`,
177
+ options,
178
+ }
179
+ }
@@ -1,25 +1,27 @@
1
- import React from "react";
2
- import ReactDOMServer from "react-dom/server";
3
- import { StaticRouter } from "react-router-dom/server";
4
- import { AppShell } from "./app";
5
- import { ComponentRoute } from "./types";
1
+ import React from 'react'
2
+ import ReactDOMServer from 'react-dom/server'
3
+ import { StaticRouter } from 'react-router-dom/server'
4
+ import { AppShell } from './app'
5
+ import type { ComponentRoute } from './types'
6
6
 
7
7
  /**
8
8
  * Options for rendering the Boltdocs application on the server (SSG).
9
9
  */
10
10
  export interface RenderOptions {
11
11
  /** The URL path currently being rendered */
12
- path: string;
12
+ path: string
13
13
  /** Initial routes generated by the Vite plugin (`virtual:boltdocs-routes`) */
14
- routes: ComponentRoute[];
14
+ routes: ComponentRoute[]
15
15
  /** Site configuration (`virtual:boltdocs-config`) */
16
- config: any;
16
+ config: any
17
17
  /** The name of the documentation directory (e.g. 'docs') */
18
- docsDirName: string;
18
+ docsDirName: string
19
19
  /** Optional custom React component to render when visiting the root path ('/') */
20
- homePage?: React.ComponentType;
20
+ homePage?: React.ComponentType
21
+ /** Custom external pages mapped by their route path */
22
+ externalPages?: Record<string, React.ComponentType<any>>
21
23
  /** Preloaded modules (since SSR cannot use dynamic imports easily) */
22
- modules: Record<string, any>;
24
+ modules: Record<string, any>
23
25
  }
24
26
 
25
27
  /**
@@ -27,13 +29,21 @@ export interface RenderOptions {
27
29
  * This is called by the Node SSG script during the Vite build process.
28
30
  */
29
31
  export async function render(options: RenderOptions): Promise<string> {
30
- const { path, routes, config, modules, homePage, docsDirName } = options;
32
+ const {
33
+ path,
34
+ routes,
35
+ config,
36
+ modules,
37
+ homePage,
38
+ externalPages,
39
+ docsDirName,
40
+ } = options
31
41
 
32
42
  // For SSR, we must resolve modules synchronously. We create a mock 'loader'
33
43
  // that instantly returns the module since the SSG script already loaded it.
34
- const resolvedModules: Record<string, () => Promise<any>> = {};
44
+ const resolvedModules: Record<string, () => Promise<any>> = {}
35
45
  for (const [key, mod] of Object.entries(modules)) {
36
- resolvedModules[key] = () => Promise.resolve(mod);
46
+ resolvedModules[key] = () => Promise.resolve(mod)
37
47
  }
38
48
 
39
49
  const html = ReactDOMServer.renderToString(
@@ -45,10 +55,11 @@ export async function render(options: RenderOptions): Promise<string> {
45
55
  docsDirName={docsDirName}
46
56
  modules={resolvedModules}
47
57
  homePage={homePage}
58
+ externalPages={externalPages}
48
59
  />
49
60
  </StaticRouter>
50
61
  </React.StrictMode>,
51
- );
62
+ )
52
63
 
53
- return html;
64
+ return html
54
65
  }