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,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
+ }