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
@@ -1,229 +0,0 @@
1
- import React, { Children, isValidElement, useState } from "react";
2
- import {
3
- Folder,
4
- FileText,
5
- File,
6
- FileCode,
7
- FileImage,
8
- ChevronRight,
9
- } from "lucide-react";
10
-
11
- export interface FileTreeProps {
12
- children: React.ReactNode;
13
- }
14
-
15
- function getTextContent(node: React.ReactNode): string {
16
- if (typeof node === "string") return node;
17
- if (typeof node === "number") return node.toString();
18
- if (Array.isArray(node)) return node.map(getTextContent).join("");
19
- if (isValidElement(node)) {
20
- return getTextContent((node.props as any).children);
21
- }
22
- return "";
23
- }
24
-
25
- function getFileIcon(filename: string) {
26
- const name = filename.toLowerCase();
27
-
28
- if (
29
- name.endsWith(".ts") ||
30
- name.endsWith(".tsx") ||
31
- name.endsWith(".js") ||
32
- name.endsWith(".jsx") ||
33
- name.endsWith(".json") ||
34
- name.endsWith(".mjs") ||
35
- name.endsWith(".cjs") ||
36
- name.endsWith(".astro") ||
37
- name.endsWith(".vue") ||
38
- name.endsWith(".svelte")
39
- ) {
40
- return (
41
- <FileCode size={16} strokeWidth={2} className="ld-file-tree__icon-file" />
42
- );
43
- }
44
-
45
- if (name.endsWith(".md") || name.endsWith(".mdx") || name.endsWith(".txt")) {
46
- return (
47
- <FileText size={16} strokeWidth={2} className="ld-file-tree__icon-file" />
48
- );
49
- }
50
-
51
- if (
52
- name.endsWith(".png") ||
53
- name.endsWith(".jpg") ||
54
- name.endsWith(".jpeg") ||
55
- name.endsWith(".svg") ||
56
- name.endsWith(".gif")
57
- ) {
58
- return (
59
- <FileImage
60
- size={16}
61
- strokeWidth={2}
62
- className="ld-file-tree__icon-file"
63
- />
64
- );
65
- }
66
-
67
- return <File size={16} strokeWidth={2} className="ld-file-tree__icon-file" />;
68
- }
69
-
70
- // Helper to reliably check for ul and li elements, including MDX wrappers
71
- function isListElement(node: any, tag: "ul" | "li"): boolean {
72
- if (typeof node.type === "string") {
73
- return node.type === tag;
74
- }
75
- if (typeof node.type === "function") {
76
- return node.type.name === tag || node.type.name?.toLowerCase() === tag;
77
- }
78
- // MDX specific wrapper detection
79
- if (node.props && node.props.originalType === tag) {
80
- return true;
81
- }
82
- if (node.props && node.props.mdxType === tag) {
83
- return true;
84
- }
85
- return false;
86
- }
87
-
88
- function FolderNode({
89
- labelText,
90
- nestedNodes,
91
- depth,
92
- }: {
93
- labelText: string;
94
- nestedNodes: React.ReactNode[];
95
- depth: number;
96
- }) {
97
- const [isOpen, setIsOpen] = useState(true);
98
-
99
- return (
100
- <li className="ld-file-tree__item">
101
- <div
102
- className="ld-file-tree__label ld-file-tree__label--folder"
103
- onClick={() => setIsOpen(!isOpen)}
104
- style={{ cursor: "pointer" }}
105
- >
106
- <span className="ld-file-tree__icon ld-file-tree__icon--chevron">
107
- <ChevronRight
108
- size={14}
109
- className={`ld-file-tree__chevron ${isOpen ? "ld-file-tree__chevron--open" : ""}`}
110
- strokeWidth={3}
111
- />
112
- </span>
113
- <span className="ld-file-tree__icon">
114
- <Folder
115
- size={16}
116
- strokeWidth={2}
117
- className="ld-file-tree__icon-folder"
118
- fill="currentColor"
119
- fillOpacity={0.15}
120
- />
121
- </span>
122
- <span className="ld-file-tree__name">{labelText}</span>
123
- </div>
124
- {isOpen && nestedNodes.length > 0 && (
125
- <div className="ld-file-tree__nested">
126
- {nestedNodes.map((child, index) => (
127
- <React.Fragment key={index}>
128
- {parseNode(child, depth)}
129
- </React.Fragment>
130
- ))}
131
- </div>
132
- )}
133
- </li>
134
- );
135
- }
136
-
137
- function parseNode(node: React.ReactNode, depth: number = 0): React.ReactNode {
138
- if (!isValidElement(node)) {
139
- return node;
140
- }
141
-
142
- if (isListElement(node, "ul")) {
143
- return (
144
- <ul
145
- className={`ld-file-tree__list ${depth === 0 ? "ld-file-tree__list--root" : ""}`}
146
- >
147
- {Children.map((node.props as any).children, (child, index) => (
148
- <React.Fragment key={index}>
149
- {parseNode(child, depth + 1)}
150
- </React.Fragment>
151
- ))}
152
- </ul>
153
- );
154
- }
155
-
156
- if (isListElement(node, "li")) {
157
- const children = Children.toArray((node.props as any).children);
158
-
159
- // Find nested list indicating a directory
160
- const nestedListIndex = children.findIndex(
161
- (child) => isValidElement(child) && isListElement(child, "ul"),
162
- );
163
- const hasNested = nestedListIndex !== -1;
164
-
165
- // Separate text label from nested items
166
- const labelNodes = hasNested
167
- ? children.slice(0, nestedListIndex)
168
- : children;
169
- const nestedNodes = hasNested ? children.slice(nestedListIndex) : [];
170
-
171
- const rawLabelContent = getTextContent(labelNodes).trim();
172
- const isExplicitDir = rawLabelContent.endsWith("/");
173
- const labelText = isExplicitDir
174
- ? rawLabelContent.slice(0, -1)
175
- : rawLabelContent;
176
-
177
- const isFolder = hasNested || isExplicitDir;
178
-
179
- if (isFolder) {
180
- return (
181
- <FolderNode
182
- labelText={labelText}
183
- nestedNodes={nestedNodes}
184
- depth={depth}
185
- />
186
- );
187
- }
188
-
189
- return (
190
- <li className="ld-file-tree__item">
191
- <div className="ld-file-tree__label ld-file-tree__label--file">
192
- <span className="ld-file-tree__icon ld-file-tree__icon--spacer"></span>
193
- <span className="ld-file-tree__icon">{getFileIcon(labelText)}</span>
194
- <span className="ld-file-tree__name">{labelText}</span>
195
- </div>
196
- </li>
197
- );
198
- }
199
-
200
- // If node is e.g. a paragraph injected by MDX wrapping the list
201
- if ((node.props as any).children) {
202
- return Children.map((node.props as any).children, (child, index) => (
203
- <React.Fragment key={index}>{parseNode(child, depth)}</React.Fragment>
204
- ));
205
- }
206
-
207
- return node;
208
- }
209
-
210
- /**
211
- * FileTree component displays a customized, styled tree structure for markdown lists.
212
- *
213
- * ```mdx
214
- * <FileTree>
215
- * - src/
216
- * - index.ts
217
- * - components/
218
- * - Button.tsx
219
- * - package.json
220
- * </FileTree>
221
- * ```
222
- */
223
- export function FileTree({ children }: FileTreeProps) {
224
- return (
225
- <div className="ld-file-tree" dir="ltr">
226
- {Children.map(children, (child) => parseNode(child, 0))}
227
- </div>
228
- );
229
- }
@@ -1,57 +0,0 @@
1
- import React, { Children } from "react";
2
- import { Check, ChevronRight } from "lucide-react";
3
-
4
- export interface ListProps extends React.HTMLAttributes<HTMLUListElement> {
5
- /** Visual variant */
6
- variant?: "checked" | "arrow" | "default";
7
- children: React.ReactNode;
8
- }
9
-
10
- const ICON_MAP: Record<string, React.ReactNode> = {
11
- checked: <Check size={14} className="ld-list__icon" />,
12
- arrow: <ChevronRight size={14} className="ld-list__icon" />,
13
- };
14
-
15
- /**
16
- * Enhanced list component with icon variants.
17
- *
18
- * ```mdx
19
- * <List variant="checked">
20
- * <li>File-system routing</li>
21
- * <li>MDX support</li>
22
- * <li>Syntax highlighting</li>
23
- * </List>
24
- * ```
25
- */
26
- export function List({
27
- variant = "default",
28
- children,
29
- className = "",
30
- ...rest
31
- }: ListProps) {
32
- if (variant === "default") {
33
- return (
34
- <ul className={`ld-list ${className}`.trim()} {...rest}>
35
- {children}
36
- </ul>
37
- );
38
- }
39
-
40
- const icon = ICON_MAP[variant];
41
-
42
- return (
43
- <ul className={`ld-list ld-list--${variant} ${className}`.trim()} {...rest}>
44
- {Children.map(children, (child) => {
45
- if (!React.isValidElement(child)) return child;
46
- return (
47
- <li className="ld-list__item">
48
- {icon}
49
- <span className="ld-list__text">
50
- {(child as React.ReactElement<any>).props.children}
51
- </span>
52
- </li>
53
- );
54
- })}
55
- </ul>
56
- );
57
- }
@@ -1,151 +0,0 @@
1
- import React, { useState, useMemo } from "react";
2
- import { ChevronUp, ChevronDown, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react";
3
-
4
- export interface TableProps {
5
- headers?: string[];
6
- data?: (string | React.ReactNode)[][];
7
- children?: React.ReactNode;
8
- className?: string;
9
- sortable?: boolean;
10
- paginated?: boolean;
11
- pageSize?: number;
12
- }
13
-
14
- export function Table({
15
- headers,
16
- data,
17
- children,
18
- className = "",
19
- sortable = false,
20
- paginated = false,
21
- pageSize = 10,
22
- }: TableProps) {
23
- const [sortConfig, setSortConfig] = useState<{ key: number; direction: 'asc' | 'desc' } | null>(null);
24
- const [currentPage, setCurrentPage] = useState(1);
25
-
26
- const processedData = useMemo(() => {
27
- if (!data) return [];
28
- let items = [...data];
29
-
30
- if (sortable && sortConfig !== null) {
31
- items.sort((a, b) => {
32
- const aVal = a[sortConfig.key];
33
- const bVal = b[sortConfig.key];
34
-
35
- // Simple string comparison for sorting
36
- const aStr = typeof aVal === 'string' ? aVal : '';
37
- const bStr = typeof bVal === 'string' ? bVal : '';
38
-
39
- if (aStr < bStr) return sortConfig.direction === 'asc' ? -1 : 1;
40
- if (aStr > bStr) return sortConfig.direction === 'asc' ? 1 : -1;
41
- return 0;
42
- });
43
- }
44
-
45
- return items;
46
- }, [data, sortConfig, sortable]);
47
-
48
- const totalPages = Math.ceil(processedData.length / pageSize);
49
- const paginatedData = useMemo(() => {
50
- if (!paginated) return processedData;
51
- const start = (currentPage - 1) * pageSize;
52
- return processedData.slice(start, start + pageSize);
53
- }, [processedData, paginated, currentPage, pageSize]);
54
-
55
- const requestSort = (index: number) => {
56
- if (!sortable) return;
57
- let direction: 'asc' | 'desc' = 'asc';
58
- if (sortConfig && sortConfig.key === index && sortConfig.direction === 'asc') {
59
- direction = 'desc';
60
- }
61
- setSortConfig({ key: index, direction });
62
- };
63
-
64
- const renderSortIcon = (index: number) => {
65
- if (!sortable) return null;
66
- if (sortConfig?.key !== index) return <ChevronDown size={14} className="ld-table-sort-icon ld-table-sort-icon--hidden" />;
67
- return sortConfig.direction === 'asc' ? <ChevronUp size={14} className="ld-table-sort-icon" /> : <ChevronDown size={14} className="ld-table-sort-icon" />;
68
- };
69
-
70
- const tableContent = children ? (
71
- children
72
- ) : (
73
- <>
74
- {headers && (
75
- <thead>
76
- <tr>
77
- {headers.map((header, i) => (
78
- <th
79
- key={i}
80
- onClick={() => requestSort(i)}
81
- className={sortable ? "ld-table-header--sortable" : ""}
82
- >
83
- <div className="ld-table-header-content">
84
- {header}
85
- {renderSortIcon(i)}
86
- </div>
87
- </th>
88
- ))}
89
- </tr>
90
- </thead>
91
- )}
92
- {paginatedData && (
93
- <tbody>
94
- {paginatedData.map((row, i) => (
95
- <tr key={i}>
96
- {row.map((cell, j) => (
97
- <td key={j}>{cell}</td>
98
- ))}
99
- </tr>
100
- ))}
101
- </tbody>
102
- )}
103
- </>
104
- );
105
-
106
- return (
107
- <div className={`ld-table-container ${className}`.trim()}>
108
- <div className="ld-table-wrapper">
109
- <table className="ld-table">{tableContent}</table>
110
- </div>
111
-
112
- {paginated && totalPages > 1 && (
113
- <div className="ld-table-pagination">
114
- <div className="ld-table-pagination-info">
115
- Page {currentPage} of {totalPages}
116
- </div>
117
- <div className="ld-table-pagination-controls">
118
- <button
119
- onClick={() => setCurrentPage(1)}
120
- disabled={currentPage === 1}
121
- className="ld-table-pagination-btn"
122
- >
123
- <ChevronsLeft size={16} />
124
- </button>
125
- <button
126
- onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))}
127
- disabled={currentPage === 1}
128
- className="ld-table-pagination-btn"
129
- >
130
- <ChevronLeft size={16} />
131
- </button>
132
- <button
133
- onClick={() => setCurrentPage(prev => Math.min(prev + 1, totalPages))}
134
- disabled={currentPage === totalPages}
135
- className="ld-table-pagination-btn"
136
- >
137
- <ChevronRight size={16} />
138
- </button>
139
- <button
140
- onClick={() => setCurrentPage(totalPages)}
141
- disabled={currentPage === totalPages}
142
- className="ld-table-pagination-btn"
143
- >
144
- <ChevronsRight size={16} />
145
- </button>
146
- </div>
147
- </div>
148
- )}
149
- </div>
150
- );
151
- }
@@ -1,123 +0,0 @@
1
- import React, { useState, Children, isValidElement, useRef } from "react";
2
- import { CodeBlock } from "../CodeBlock";
3
- import { NPM } from "../../icons/npm";
4
- import { Pnpm } from "../../icons/pnpm";
5
- import { Bun } from "../../icons/bun";
6
- import { Deno } from "../../icons/deno";
7
-
8
- /* ─── Tab (individual panel) ──────────────────────────────── */
9
- export interface TabProps {
10
- /** The label shown in the tab bar */
11
- label: string;
12
- children: React.ReactNode;
13
- }
14
-
15
- /**
16
- * A single tab panel. Must be used inside `<Tabs>`.
17
- *
18
- * ```mdx
19
- * <Tab label="npm">npm install boltdocs</Tab>
20
- * ```
21
- */
22
- export function Tab({ children }: TabProps) {
23
- // If children is a simple string, wrap it in a CodeBlock for syntax highlighting
24
- const content =
25
- typeof children === "string" ? (
26
- <CodeBlock className="language-bash">
27
- <code>{children.trim()}</code>
28
- </CodeBlock>
29
- ) : (
30
- children
31
- );
32
-
33
- return <div className="ld-tab-panel">{content}</div>;
34
- }
35
-
36
- /* ─── Tabs (container) ────────────────────────────────────── */
37
- export interface TabsProps {
38
- /** Which tab index is initially active (0-based, default 0) */
39
- defaultIndex?: number;
40
- children: React.ReactNode;
41
- }
42
-
43
- const getIconForLabel = (label: string) => {
44
- const l = label.toLowerCase();
45
- if (l.includes("pnpm")) return <Pnpm />;
46
- if (l.includes("npm")) return <NPM />;
47
- if (l.includes("bun")) return <Bun />;
48
- if (l.includes("deno")) return <Deno />;
49
- return null;
50
- };
51
-
52
- /**
53
- * Tab container that manages active state.
54
- *
55
- * ```mdx
56
- * <Tabs>
57
- * <Tab label="npm">npm install boltdocs</Tab>
58
- * <Tab label="pnpm">pnpm add boltdocs</Tab>
59
- * </Tabs>
60
- * ```
61
- */
62
- export function Tabs({ defaultIndex = 0, children }: TabsProps) {
63
- const [active, setActive] = useState(defaultIndex);
64
- const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
65
-
66
- // Extract Tab children
67
- const tabs = Children.toArray(children).filter(
68
- (child) => isValidElement(child) && (child as any).props?.label,
69
- );
70
-
71
- const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
72
- let newIndex = active;
73
- if (e.key === "ArrowRight") {
74
- newIndex = (active + 1) % tabs.length;
75
- } else if (e.key === "ArrowLeft") {
76
- newIndex = (active - 1 + tabs.length) % tabs.length;
77
- }
78
-
79
- if (newIndex !== active) {
80
- setActive(newIndex);
81
- tabRefs.current[newIndex]?.focus();
82
- }
83
- };
84
-
85
- return (
86
- <div className="ld-tabs">
87
- <div className="ld-tabs__bar" role="tablist" onKeyDown={handleKeyDown}>
88
- {tabs.map((child, i) => {
89
- const label = (child as React.ReactElement<TabProps>).props.label;
90
- const Icon = getIconForLabel(label);
91
- return (
92
- <button
93
- key={i}
94
- role="tab"
95
- aria-selected={i === active}
96
- aria-controls={`tabpanel-${i}`}
97
- id={`tab-${i}`}
98
- tabIndex={i === active ? 0 : -1}
99
- ref={(el) => {
100
- tabRefs.current[i] = el;
101
- }}
102
- className={`ld-tabs__trigger ${
103
- i === active ? "ld-tabs__trigger--active" : ""
104
- }`}
105
- onClick={() => setActive(i)}
106
- >
107
- {Icon}
108
- <span>{label}</span>
109
- </button>
110
- );
111
- })}
112
- </div>
113
- <div
114
- className="ld-tabs__content"
115
- role="tabpanel"
116
- id={`tabpanel-${active}`}
117
- aria-labelledby={`tab-${active}`}
118
- >
119
- {tabs[active]}
120
- </div>
121
- </div>
122
- );
123
- }
@@ -1,27 +0,0 @@
1
- // MDX UI Components — barrel export
2
- export { Button } from "./Button";
3
- export type { ButtonProps } from "./Button";
4
-
5
- export { Badge } from "./Badge";
6
- export type { BadgeProps } from "./Badge";
7
-
8
- export { Card, Cards } from "./Card";
9
- export type { CardProps, CardsProps } from "./Card";
10
-
11
- export { Tabs, Tab } from "./Tabs";
12
- export type { TabsProps, TabProps } from "./Tabs";
13
-
14
- export { Admonition, Note, Tip, Warning, Danger, InfoBox } from "./Admonition";
15
- export type { AdmonitionProps } from "./Admonition";
16
-
17
- export { List } from "./List";
18
- export type { ListProps } from "./List";
19
-
20
- export { FileTree } from "./FileTree";
21
- export type { FileTreeProps } from "./FileTree";
22
-
23
- export { Table } from "./Table";
24
- export type { TableProps } from "./Table";
25
-
26
- export { Field } from "./Field";
27
- export type { FieldProps } from "./Field";