boltdocs 1.10.2 → 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 (225) 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 -17
  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-AGVF6JBO.mjs +0 -194
  114. package/dist/SearchDialog-YPDOM7Q6.css +0 -2847
  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-TKLQWU7H.mjs +0 -1920
  121. package/dist/chunk-Z7JHYNAS.mjs +0 -57
  122. package/dist/client/index.css +0 -2847
  123. package/dist/client/index.d.mts +0 -372
  124. package/dist/client/index.d.ts +0 -372
  125. package/dist/client/index.js +0 -3630
  126. package/dist/client/index.mjs +0 -697
  127. package/dist/client/ssr.css +0 -2847
  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 -2928
  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 -61
  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 -180
  146. package/src/client/theme/components/Playground/index.ts +0 -1
  147. package/src/client/theme/components/Playground/playground.css +0 -238
  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 -394
  170. package/src/client/theme/styles/variables.css +0 -175
  171. package/src/client/theme/styles.css +0 -39
  172. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +0 -68
  173. package/src/client/theme/ui/Breadcrumbs/index.ts +0 -1
  174. package/src/client/theme/ui/CopyMarkdown/CopyMarkdown.tsx +0 -82
  175. package/src/client/theme/ui/CopyMarkdown/copy-markdown.css +0 -112
  176. package/src/client/theme/ui/CopyMarkdown/index.ts +0 -1
  177. package/src/client/theme/ui/ErrorBoundary/ErrorBoundary.tsx +0 -50
  178. package/src/client/theme/ui/ErrorBoundary/error-boundary.css +0 -55
  179. package/src/client/theme/ui/ErrorBoundary/index.ts +0 -1
  180. package/src/client/theme/ui/Footer/footer.css +0 -32
  181. package/src/client/theme/ui/Head/Head.tsx +0 -69
  182. package/src/client/theme/ui/Head/index.ts +0 -1
  183. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +0 -125
  184. package/src/client/theme/ui/LanguageSwitcher/index.ts +0 -1
  185. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +0 -98
  186. package/src/client/theme/ui/Layout/Layout.tsx +0 -203
  187. package/src/client/theme/ui/Layout/base.css +0 -106
  188. package/src/client/theme/ui/Layout/index.ts +0 -2
  189. package/src/client/theme/ui/Layout/pagination.css +0 -72
  190. package/src/client/theme/ui/Layout/responsive.css +0 -47
  191. package/src/client/theme/ui/Link/Link.tsx +0 -392
  192. package/src/client/theme/ui/Link/LinkPreview.tsx +0 -59
  193. package/src/client/theme/ui/Link/index.ts +0 -2
  194. package/src/client/theme/ui/Link/link-preview.css +0 -48
  195. package/src/client/theme/ui/Loading/Loading.tsx +0 -10
  196. package/src/client/theme/ui/Loading/index.ts +0 -1
  197. package/src/client/theme/ui/Loading/loading.css +0 -30
  198. package/src/client/theme/ui/Navbar/GithubStars.tsx +0 -27
  199. package/src/client/theme/ui/Navbar/Navbar.tsx +0 -193
  200. package/src/client/theme/ui/Navbar/Tabs.tsx +0 -99
  201. package/src/client/theme/ui/Navbar/index.ts +0 -2
  202. package/src/client/theme/ui/Navbar/navbar.css +0 -347
  203. package/src/client/theme/ui/NotFound/NotFound.tsx +0 -19
  204. package/src/client/theme/ui/NotFound/index.ts +0 -1
  205. package/src/client/theme/ui/NotFound/not-found.css +0 -64
  206. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +0 -244
  207. package/src/client/theme/ui/OnThisPage/index.ts +0 -1
  208. package/src/client/theme/ui/OnThisPage/toc.css +0 -152
  209. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +0 -18
  210. package/src/client/theme/ui/PoweredBy/index.ts +0 -1
  211. package/src/client/theme/ui/PoweredBy/powered-by.css +0 -76
  212. package/src/client/theme/ui/ProgressBar/ProgressBar.css +0 -17
  213. package/src/client/theme/ui/ProgressBar/ProgressBar.tsx +0 -51
  214. package/src/client/theme/ui/ProgressBar/index.ts +0 -1
  215. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +0 -209
  216. package/src/client/theme/ui/SearchDialog/index.ts +0 -1
  217. package/src/client/theme/ui/SearchDialog/search.css +0 -152
  218. package/src/client/theme/ui/Sidebar/Sidebar.tsx +0 -244
  219. package/src/client/theme/ui/Sidebar/index.ts +0 -1
  220. package/src/client/theme/ui/Sidebar/sidebar.css +0 -230
  221. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +0 -69
  222. package/src/client/theme/ui/ThemeToggle/index.ts +0 -1
  223. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +0 -136
  224. package/src/client/theme/ui/VersionSwitcher/index.ts +0 -1
  225. package/src/client/utils.ts +0 -49
@@ -0,0 +1,124 @@
1
+ import type { MouseEvent as ReactMouseEvent } from 'react'
2
+ import { useCallback, useRef } from 'react'
3
+ import * as RAC from 'react-aria-components'
4
+ import { cn } from '@client/utils/cn'
5
+ import { cva } from 'class-variance-authority'
6
+ import type { VariantProps } from 'class-variance-authority'
7
+
8
+ const cardsVariants = cva('grid gap-4 my-6', {
9
+ variants: {
10
+ cols: {
11
+ 1: 'grid-cols-1',
12
+ 2: 'grid-cols-1 sm:grid-cols-2',
13
+ 3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
14
+ 4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ cols: 3,
19
+ },
20
+ })
21
+ type CardsVariants = VariantProps<typeof cardsVariants>
22
+
23
+ export interface CardsProps
24
+ extends React.HTMLAttributes<HTMLDivElement>,
25
+ CardsVariants {}
26
+
27
+ export function Cards({
28
+ cols = 3,
29
+ children,
30
+ className = '',
31
+ ...rest
32
+ }: CardsProps) {
33
+ return (
34
+ <div className={cn(cardsVariants({ cols }), className)} {...rest}>
35
+ {children}
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
41
+ title?: string
42
+ icon?: React.ReactNode
43
+ href?: string
44
+ children?: React.ReactNode
45
+ }
46
+
47
+ export function Card({
48
+ title,
49
+ icon,
50
+ href,
51
+ children,
52
+ className = '',
53
+ ...rest
54
+ }: CardProps) {
55
+ const cardRef = useRef<HTMLDivElement>(null)
56
+ const linkRef = useRef<HTMLAnchorElement>(null)
57
+
58
+ const handleMouseMove = useCallback((e: ReactMouseEvent<HTMLDivElement>) => {
59
+ const el = cardRef.current || linkRef.current
60
+ if (!el) return
61
+ const { left, top } = el.getBoundingClientRect()
62
+ el.style.setProperty('--x', `${e.clientX - left}px`)
63
+ el.style.setProperty('--y', `${e.clientY - top}px`)
64
+ }, [])
65
+
66
+ const inner = (
67
+ <>
68
+ <div
69
+ className="pointer-events-none absolute -inset-px rounded-xl opacity-0 transition-opacity duration-300 group-hover:opacity-100"
70
+ style={{
71
+ background:
72
+ 'radial-gradient(400px circle at var(--x) var(--y), color-mix(in oklch, var(--color-primary-500), transparent 90%), transparent 80%)',
73
+ }}
74
+ />
75
+ {icon && (
76
+ <div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-primary-500/10 text-primary-400 text-lg transition-transform duration-300 group-hover:scale-105 group-hover:-rotate-3">
77
+ {icon}
78
+ </div>
79
+ )}
80
+ <div className="space-y-1.5">
81
+ {title && <h3 className="text-sm font-bold text-text-main">{title}</h3>}
82
+ {children && (
83
+ <div className="text-sm text-text-muted leading-relaxed">
84
+ {children}
85
+ </div>
86
+ )}
87
+ </div>
88
+ </>
89
+ )
90
+
91
+ const cardClasses = cn(
92
+ 'group relative block rounded-xl border border-border-subtle bg-bg-surface p-5 outline-none overflow-hidden',
93
+ 'transition-all duration-200 hover:border-primary-500/40 hover:shadow-lg hover:shadow-primary-500/5',
94
+ 'focus-visible:ring-2 focus-visible:ring-primary-500/30',
95
+ className,
96
+ )
97
+
98
+ if (href) {
99
+ return (
100
+ <RAC.Link
101
+ ref={linkRef}
102
+ href={href}
103
+ className={cn(cardClasses, 'no-underline cursor-pointer')}
104
+ onMouseMove={handleMouseMove}
105
+ {...(rest as any)}
106
+ >
107
+ {inner}
108
+ </RAC.Link>
109
+ )
110
+ }
111
+
112
+ return (
113
+ // biome-ignore lint/a11y/noStaticElementInteractions: spotlight effect is decorative
114
+ <div
115
+ ref={cardRef}
116
+ role="presentation"
117
+ className={cardClasses}
118
+ onMouseMove={handleMouseMove}
119
+ {...rest}
120
+ >
121
+ {inner}
122
+ </div>
123
+ )
124
+ }
@@ -0,0 +1,119 @@
1
+ import * as RAC from 'react-aria-components'
2
+ import { Copy, Check } from 'lucide-react'
3
+ import { cn } from '@client/utils/cn'
4
+ import { useCodeBlock } from './hooks/use-code-block'
5
+ import { useConfig } from '@client/app/config-context'
6
+ import { CodeSandbox } from '@components/icons-dev'
7
+ import { Tooltip } from '@components/primitives/tooltip'
8
+
9
+ export interface CodeBlockProps {
10
+ children?: React.ReactNode
11
+ className?: string
12
+ sandbox?: boolean | any
13
+ hideCopy?: boolean
14
+ hideSandbox?: boolean
15
+ title?: string
16
+ lang?: string
17
+ highlightedHtml?: string
18
+ [key: string]: any
19
+ }
20
+
21
+ export function CodeBlock(props: CodeBlockProps) {
22
+ const {
23
+ children,
24
+ sandbox: localSandbox,
25
+ hideSandbox = true,
26
+ hideCopy = false,
27
+ highlightedHtml,
28
+ ...rest
29
+ } = props
30
+ const config = useConfig()
31
+ const globalSandbox = config?.integrations?.sandbox
32
+ const isSandboxEnabled = !!globalSandbox?.enable && !hideSandbox
33
+ const {
34
+ copied,
35
+ isExpanded,
36
+ setIsExpanded,
37
+ isExpandable,
38
+ preRef,
39
+ handleCopy,
40
+ handleSandbox,
41
+ shouldTruncate,
42
+ } = useCodeBlock(props)
43
+
44
+ return (
45
+ <div
46
+ className={cn(
47
+ 'group relative my-6 overflow-hidden rounded-lg border border-border-subtle bg-(--color-code-bg)',
48
+ shouldTruncate && '[&>pre]:max-h-[250px] [&>pre]:overflow-hidden',
49
+ )}
50
+ >
51
+ {/* Toolbar */}
52
+ <div className="absolute top-3 right-4 z-50 flex items-center gap-2 transition-all duration-300 opacity-0 group-hover:opacity-100">
53
+ {isSandboxEnabled && (
54
+ <Tooltip content="Open in CodeSandbox">
55
+ <RAC.Button
56
+ onPress={handleSandbox}
57
+ className="grid place-items-center w-8 h-8 bg-transparent text-text-muted outline-none cursor-pointer transition-all duration-200 hover:scale-115 hover:text-sky-400 active:scale-95 [&>svg]:w-5 [&>svg]:h-5 [&>svg]:stroke-2"
58
+ aria-label="Open in CodeSandbox"
59
+ >
60
+ <CodeSandbox size={20} />
61
+ </RAC.Button>
62
+ </Tooltip>
63
+ )}
64
+ {!hideCopy && (
65
+ <Tooltip content={copied ? 'Copied!' : 'Copy code'}>
66
+ <RAC.Button
67
+ onPress={handleCopy}
68
+ className={cn(
69
+ 'grid place-items-center w-8 h-8 bg-transparent outline-none cursor-pointer transition-all duration-200 hover:scale-115 active:scale-95 [&>svg]:w-5 [&>svg]:h-5 [&>svg]:stroke-2',
70
+ copied
71
+ ? 'text-emerald-400'
72
+ : 'text-text-muted hover:text-text-main',
73
+ )}
74
+ aria-label="Copy code"
75
+ >
76
+ {copied ? <Check size={20} /> : <Copy size={20} />}
77
+ </RAC.Button>
78
+ </Tooltip>
79
+ )}
80
+ </div>
81
+
82
+ {/* Code Content */}
83
+ {highlightedHtml ? (
84
+ <div
85
+ // @ts-ignore
86
+ ref={preRef}
87
+ className="shiki-wrapper [&>pre]:m-0! [&>pre]:rounded-none! [&>pre]:border-none! [&>pre]:bg-inherit! [&>pre>code]:grid! [&>pre>code]:p-5! [&>.shiki.shiki-themes]:bg-transparent!"
88
+ dangerouslySetInnerHTML={{ __html: highlightedHtml }}
89
+ />
90
+ ) : (
91
+ <pre
92
+ ref={preRef}
93
+ className="m-0! rounded-none! border-none! bg-inherit! font-mono text-[0.8125rem] leading-[1.7]"
94
+ {...rest}
95
+ >
96
+ {children}
97
+ </pre>
98
+ )}
99
+
100
+ {/* Expand/Collapse */}
101
+ {isExpandable && (
102
+ <div
103
+ className={cn(
104
+ shouldTruncate
105
+ ? 'absolute bottom-0 inset-x-0 h-24 bg-linear-to-t from-(--color-code-bg) to-transparent flex items-end justify-center pb-4 z-10'
106
+ : 'relative flex justify-center py-4',
107
+ )}
108
+ >
109
+ <RAC.Button
110
+ onPress={() => setIsExpanded(!isExpanded)}
111
+ className="rounded-full bg-bg-surface border border-border-subtle px-5 py-2 text-[0.8125rem] font-medium text-text-main outline-none cursor-pointer transition-all hover:bg-border-subtle hover:-translate-y-px backdrop-blur-md"
112
+ >
113
+ {isExpanded ? 'Show less' : 'Expand code'}
114
+ </RAC.Button>
115
+ </div>
116
+ )}
117
+ </div>
118
+ )
119
+ }
@@ -0,0 +1,47 @@
1
+ import type { SandboxOptions } from '../../types'
2
+ import { CodeBlock } from './code-block'
3
+ import { useComponentPreview } from './hooks/use-component-preview'
4
+
5
+ export interface ComponentPreviewProps {
6
+ code?: string
7
+ highlightedHtml?: string
8
+ children?: string
9
+ preview?: React.ReactNode
10
+ hideCode?: boolean
11
+ hideSandbox?: boolean
12
+ hideCopy?: boolean
13
+ sandboxOptions?: SandboxOptions
14
+ }
15
+
16
+ export function ComponentPreview(props: ComponentPreviewProps) {
17
+ const {
18
+ highlightedHtml,
19
+ hideCode = false,
20
+ hideSandbox = false,
21
+ hideCopy = false,
22
+ sandboxOptions = {},
23
+ } = props
24
+ const { initialCode, previewElement } = useComponentPreview(props)
25
+
26
+ return (
27
+ <div className="my-6 overflow-hidden rounded-xl border border-border-subtle">
28
+ <div className="flex items-center justify-center p-8 bg-bg-surface">
29
+ {previewElement}
30
+ </div>
31
+
32
+ {!hideCode && (
33
+ <div className="border-t border-border-subtle">
34
+ <CodeBlock
35
+ hideSandbox={hideSandbox}
36
+ hideCopy={hideCopy}
37
+ title={sandboxOptions.title}
38
+ lang="tsx"
39
+ highlightedHtml={highlightedHtml}
40
+ >
41
+ {initialCode}
42
+ </CodeBlock>
43
+ </div>
44
+ )}
45
+ </div>
46
+ )
47
+ }
@@ -0,0 +1,83 @@
1
+ import { cn } from '@client/utils/cn'
2
+
3
+ export interface PropItem {
4
+ name: string
5
+ type: string
6
+ defaultValue?: string
7
+ required?: boolean
8
+ description: React.ReactNode
9
+ }
10
+
11
+ export interface ComponentPropsProps {
12
+ title?: string
13
+ props: PropItem[]
14
+ className?: string
15
+ }
16
+
17
+ export function ComponentProps({
18
+ title,
19
+ props,
20
+ className = '',
21
+ }: ComponentPropsProps) {
22
+ return (
23
+ <div className={cn('my-6', className)}>
24
+ {title && (
25
+ <h3 className="text-base font-bold text-text-main mb-3">{title}</h3>
26
+ )}
27
+ <div className="overflow-x-auto rounded-lg border border-border-subtle">
28
+ <table className="w-full border-collapse text-sm">
29
+ <thead>
30
+ <tr>
31
+ <th className="text-left px-4 py-3 border-b-2 border-border-subtle text-xs font-bold uppercase tracking-wider text-text-muted">
32
+ Property
33
+ </th>
34
+ <th className="text-left px-4 py-3 border-b-2 border-border-subtle text-xs font-bold uppercase tracking-wider text-text-muted">
35
+ Type
36
+ </th>
37
+ <th className="text-left px-4 py-3 border-b-2 border-border-subtle text-xs font-bold uppercase tracking-wider text-text-muted">
38
+ Default
39
+ </th>
40
+ <th className="text-left px-4 py-3 border-b-2 border-border-subtle text-xs font-bold uppercase tracking-wider text-text-muted">
41
+ Description
42
+ </th>
43
+ </tr>
44
+ </thead>
45
+ <tbody>
46
+ {props.map((prop, index) => (
47
+ <tr
48
+ key={`${prop.name}-${index}`}
49
+ className="transition-colors hover:bg-bg-surface"
50
+ >
51
+ <td className="px-4 py-2.5 border-b border-border-subtle">
52
+ <code className="rounded bg-bg-surface px-1.5 py-0.5 font-mono text-xs font-bold text-primary-400">
53
+ {prop.name}
54
+ </code>
55
+ {prop.required && (
56
+ <span className="ml-1 text-red-400 font-bold">*</span>
57
+ )}
58
+ </td>
59
+ <td className="px-4 py-2.5 border-b border-border-subtle">
60
+ <code className="rounded bg-bg-muted px-1.5 py-0.5 font-mono text-xs text-text-muted">
61
+ {prop.type}
62
+ </code>
63
+ </td>
64
+ <td className="px-4 py-2.5 border-b border-border-subtle">
65
+ {prop.defaultValue ? (
66
+ <code className="rounded bg-bg-muted px-1.5 py-0.5 font-mono text-xs text-primary-400">
67
+ {prop.defaultValue}
68
+ </code>
69
+ ) : (
70
+ <span className="text-text-dim">—</span>
71
+ )}
72
+ </td>
73
+ <td className="px-4 py-2.5 border-b border-border-subtle text-text-muted">
74
+ {prop.description}
75
+ </td>
76
+ </tr>
77
+ ))}
78
+ </tbody>
79
+ </table>
80
+ </div>
81
+ </div>
82
+ )
83
+ }
@@ -0,0 +1,66 @@
1
+ import { cn } from '@client/utils/cn'
2
+
3
+ export interface FieldProps {
4
+ name: string
5
+ type?: string
6
+ defaultValue?: string
7
+ required?: boolean
8
+ children: React.ReactNode
9
+ id?: string
10
+ className?: string
11
+ }
12
+
13
+ export function Field({
14
+ name,
15
+ type,
16
+ defaultValue,
17
+ required = false,
18
+ children,
19
+ id,
20
+ className = '',
21
+ }: FieldProps) {
22
+ return (
23
+ <article
24
+ className={cn(
25
+ 'group relative my-6 rounded-xl border border-border-subtle bg-bg-surface p-5 transition-all duration-300',
26
+ 'hover:border-primary-500/30 hover:shadow-lg hover:shadow-primary-500/5',
27
+ className,
28
+ )}
29
+ id={id}
30
+ >
31
+ <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between mb-4">
32
+ <div className="flex flex-wrap items-center gap-2.5">
33
+ <code className="inline-flex items-center rounded-md bg-primary-500/10 px-2.5 py-1 font-mono text-sm font-bold text-primary-400 border border-primary-500/20 shadow-sm transition-colors group-hover:bg-primary-500/15">
34
+ {name}
35
+ </code>
36
+ {type && (
37
+ <span className="rounded-md bg-bg-muted/80 border border-border-subtle px-2 py-0.5 text-[11px] font-semibold text-text-muted uppercase tracking-wider shadow-sm">
38
+ {type}
39
+ </span>
40
+ )}
41
+ {required && (
42
+ <div className="flex items-center gap-1.5 rounded-full bg-red-500/10 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-red-400 border border-red-500/20 shadow-sm">
43
+ <span className="h-1 w-1 rounded-full bg-red-400 animate-pulse" />
44
+ Required
45
+ </div>
46
+ )}
47
+ </div>
48
+
49
+ {defaultValue && (
50
+ <div className="flex items-center gap-2 text-[11px] text-text-muted bg-bg-muted/30 px-2.5 py-1 rounded-md border border-border-subtle/50">
51
+ <span className="font-semibold opacity-60 uppercase tracking-tighter">
52
+ Default
53
+ </span>
54
+ <code className="font-mono text-text-main font-medium">
55
+ {defaultValue}
56
+ </code>
57
+ </div>
58
+ )}
59
+ </div>
60
+
61
+ <div className="text-sm text-text-muted leading-relaxed [&>p]:m-0 selection:bg-primary-500/30">
62
+ {children}
63
+ </div>
64
+ </article>
65
+ )
66
+ }