@speakeasy-api/moonshine 2.0.0-alpha.1 → 2.0.0-alpha.3

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 (330) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -23
  3. package/package.json +33 -50
  4. package/scripts/generate-utility-docs.js +324 -0
  5. package/src/assets/icons/external/github.svg +3 -0
  6. package/src/assets/icons/external/maven.svg +152 -0
  7. package/src/assets/icons/external/npm.svg +4 -0
  8. package/src/assets/icons/external/nuget.svg +5 -0
  9. package/src/assets/icons/external/packagist.svg +1 -0
  10. package/src/assets/icons/external/pypi.svg +182 -0
  11. package/src/assets/icons/external/rubygems.svg +14 -0
  12. package/src/assets/icons/external/terraform.svg +1 -0
  13. package/src/assets/icons/languages/csharp.svg +1 -0
  14. package/src/assets/icons/languages/go.svg +1 -0
  15. package/src/assets/icons/languages/java.svg +1 -0
  16. package/src/assets/icons/languages/json.svg +2 -0
  17. package/src/assets/icons/languages/php.svg +1 -0
  18. package/src/assets/icons/languages/postman.svg +3 -0
  19. package/src/assets/icons/languages/python.svg +1 -0
  20. package/src/assets/icons/languages/ruby.svg +1 -0
  21. package/src/assets/icons/languages/swift.svg +1 -0
  22. package/src/assets/icons/languages/terraform.svg +1 -0
  23. package/src/assets/icons/languages/typescript.svg +1 -0
  24. package/src/assets/icons/languages/unity.svg +1 -0
  25. package/src/base.css +12 -12
  26. package/src/components/AIChat/AIChatContainer.tsx +71 -0
  27. package/src/components/AIChat/AIChatMessage.tsx +135 -0
  28. package/src/components/AIChat/AIChatMessageComposer.tsx +175 -0
  29. package/src/components/AIChat/AIChatMessageList.tsx +34 -0
  30. package/src/components/AIChat/AIChatModelSelector.tsx +159 -0
  31. package/src/components/AIChat/componentsTypes.ts +36 -0
  32. package/src/components/AIChat/context.ts +15 -0
  33. package/src/components/AIChat/index.ts +12 -0
  34. package/src/components/AIChat/parts/AIChatMessageFilePart.tsx +129 -0
  35. package/src/components/AIChat/parts/AIChatMessageReasoningPart.tsx +23 -0
  36. package/src/components/AIChat/parts/AIChatMessageSourcePart.tsx +58 -0
  37. package/src/components/AIChat/parts/AIChatMessageTextPart.tsx +33 -0
  38. package/src/components/AIChat/parts/AIChatMessageToolInvocationPart.tsx +53 -0
  39. package/src/components/AIChat/parts/AIChatMessageToolPart.tsx +395 -0
  40. package/src/components/AIChat/parts/AIChatMessageToolResultPart.tsx +46 -0
  41. package/src/components/AIChat/toolCallApproval.ts +61 -0
  42. package/src/components/AIChat/types.ts +97 -0
  43. package/src/components/ActionBar/index.tsx +184 -0
  44. package/src/components/Alert/index.tsx +118 -0
  45. package/src/components/Alert/types.ts +12 -0
  46. package/src/components/AppLayout/context.tsx +31 -0
  47. package/src/components/AppLayout/index.tsx +550 -0
  48. package/src/components/AppLayout/provider.tsx +40 -0
  49. package/src/components/AppLayout/useAppLayoutKeys.ts +26 -0
  50. package/src/components/Badge/index.tsx +227 -0
  51. package/src/components/Button/index.tsx +531 -0
  52. package/src/components/Card/index.tsx +193 -0
  53. package/src/components/CodeEditorLayout/index.tsx +394 -0
  54. package/src/components/CodeEditorLayout/styles.module.css +8 -0
  55. package/src/components/CodeHighlight/Pre.tsx +63 -0
  56. package/src/components/CodePlayground/index.tsx +411 -0
  57. package/src/components/CodeSnippet/codeSnippet.css +97 -0
  58. package/src/components/CodeSnippet/index.tsx +224 -0
  59. package/src/components/Combobox/index.tsx +193 -0
  60. package/src/components/Command/index.tsx +152 -0
  61. package/src/components/Container/index.tsx +31 -0
  62. package/src/components/ContextDropdown/index.tsx +150 -0
  63. package/src/components/Dialog/index.tsx +123 -0
  64. package/src/components/DragNDrop/DragNDropArea.tsx +30 -0
  65. package/src/components/DragNDrop/DragOverlay.tsx +4 -0
  66. package/src/components/DragNDrop/Draggable.tsx +97 -0
  67. package/src/components/DragNDrop/Droppable.tsx +51 -0
  68. package/src/components/Dropdown/index.tsx +201 -0
  69. package/src/components/ExternalPill/index.tsx +58 -0
  70. package/src/components/Facepile/index.tsx +309 -0
  71. package/src/components/GradientCircle/gradientCircle.css +34 -0
  72. package/src/components/GradientCircle/index.tsx +143 -0
  73. package/src/components/Grid/index.tsx +150 -0
  74. package/src/components/Heading/index.tsx +54 -0
  75. package/src/components/HighlightedText/index.tsx +152 -0
  76. package/src/components/Icon/customIcons/createCustomLucideIcon.ts +25 -0
  77. package/src/components/Icon/customIcons/gems.ts +26 -0
  78. package/{dist/go-CiWl_aXI.mjs → src/components/Icon/customIcons/go.ts} +21 -19
  79. package/src/components/Icon/customIcons/index.ts +11 -0
  80. package/{dist/maven-DhmnGXoB.mjs → src/components/Icon/customIcons/maven.ts} +17 -15
  81. package/src/components/Icon/customIcons/npm.ts +19 -0
  82. package/{dist/nuget-5a2icRS2.mjs → src/components/Icon/customIcons/nuget.ts} +17 -15
  83. package/src/components/Icon/customIcons/packagist.ts +124 -0
  84. package/{dist/pypi-DsuRYjdK.mjs → src/components/Icon/customIcons/pypi.ts} +16 -14
  85. package/src/components/Icon/index.tsx +83 -0
  86. package/src/components/Icon/isIconName.ts +10 -0
  87. package/src/components/Icon/names.ts +14 -0
  88. package/src/components/IconButton/index.tsx +51 -0
  89. package/src/components/Input/index.tsx +98 -0
  90. package/src/components/KeyHint/index.tsx +118 -0
  91. package/src/components/LanguageIndicator/index.tsx +68 -0
  92. package/src/components/Link/index.tsx +153 -0
  93. package/src/components/LoggedInUserMenu/index.tsx +116 -0
  94. package/src/components/Logo/Animated.tsx +191 -0
  95. package/src/components/Logo/index.tsx +17 -0
  96. package/src/components/Logo/speakeasy-logo.riv +0 -0
  97. package/src/components/Logo/svgs/index.tsx +126 -0
  98. package/src/components/Modal/index.tsx +104 -0
  99. package/src/components/PageHeader/index.tsx +227 -0
  100. package/src/components/PageHeader/styles.module.css +27 -0
  101. package/src/components/Popover/index.tsx +35 -0
  102. package/src/components/PromptInput/index.tsx +372 -0
  103. package/src/components/PullRequestLink/index.tsx +64 -0
  104. package/src/components/ResizablePanel/index.tsx +119 -0
  105. package/src/components/Score/index.module.css +32 -0
  106. package/src/components/Score/index.tsx +268 -0
  107. package/src/components/ScrollArea/index.tsx +48 -0
  108. package/src/components/SegmentedButton/index.module.css +19 -0
  109. package/src/components/SegmentedButton/index.tsx +101 -0
  110. package/src/components/Select/index.tsx +159 -0
  111. package/src/components/Separator/index.tsx +23 -0
  112. package/src/components/Skeleton/index.tsx +61 -0
  113. package/src/components/Skeleton/skeleton.css +52 -0
  114. package/src/components/Stack/index.tsx +137 -0
  115. package/src/components/Subnav/index.tsx +315 -0
  116. package/src/components/Switch/index.tsx +29 -0
  117. package/src/components/Table/context/context.tsx +19 -0
  118. package/src/components/Table/context/tableProvider.tsx +39 -0
  119. package/src/components/Table/index.tsx +707 -0
  120. package/src/components/Table/styles.module.css +25 -0
  121. package/src/components/Tabs/index.tsx +87 -0
  122. package/src/components/TargetLanguageIcon/index.tsx +84 -0
  123. package/src/components/Text/index.tsx +59 -0
  124. package/src/components/ThemeSwitcher/index.tsx +118 -0
  125. package/src/components/Timeline/index.tsx +290 -0
  126. package/src/components/Tooltip/index.tsx +41 -0
  127. package/src/components/UserAvatar/index.tsx +87 -0
  128. package/src/components/UserAvatar/sizeMap.ts +12 -0
  129. package/src/components/Wizard/index.tsx +208 -0
  130. package/src/components/Wizard/types.ts +17 -0
  131. package/src/components/WorkspaceSelector/CreateOrg.tsx +95 -0
  132. package/src/components/WorkspaceSelector/CreateWorkspace.tsx +196 -0
  133. package/src/components/WorkspaceSelector/OrgList.tsx +115 -0
  134. package/src/components/WorkspaceSelector/OrgSelector.tsx +207 -0
  135. package/src/components/WorkspaceSelector/RecentWorkspaces.tsx +83 -0
  136. package/src/components/WorkspaceSelector/ScrollingList.tsx +84 -0
  137. package/src/components/WorkspaceSelector/SearchBox.tsx +40 -0
  138. package/src/components/WorkspaceSelector/WorkspaceItem.tsx +37 -0
  139. package/src/components/WorkspaceSelector/WorkspaceList.tsx +107 -0
  140. package/src/components/WorkspaceSelector/index.tsx +400 -0
  141. package/src/components/WorkspaceSelector/styles.css +74 -0
  142. package/src/components/__beta__/CLIWizard/index.tsx +357 -0
  143. package/src/components/__beta__/CLIWizard/terminal-command.tsx +108 -0
  144. package/src/components/__beta__/CLIWizard/terminal.tsx +83 -0
  145. package/src/components/__beta__/README.md +3 -0
  146. package/src/components/index.mdx +38 -0
  147. package/src/context/ConfigContext.tsx +43 -0
  148. package/src/context/ModalContext.tsx +118 -0
  149. package/src/context/theme.ts +1 -0
  150. package/src/hooks/useAppLayout.ts +10 -0
  151. package/src/hooks/useConfig.ts +10 -0
  152. package/src/hooks/useIsMounted.ts +13 -0
  153. package/src/hooks/useModal.tsx +10 -0
  154. package/src/hooks/useTailwindBreakpoint.ts +47 -0
  155. package/src/hooks/useTheme.ts +13 -0
  156. package/src/index.ts +234 -0
  157. package/src/lib/assert.ts +9 -0
  158. package/src/lib/codeUtils.ts +177 -0
  159. package/src/lib/debounce.ts +9 -0
  160. package/src/lib/responsiveMappers.ts +69 -0
  161. package/src/lib/responsiveUtils.ts +23 -0
  162. package/src/lib/storybookUtils.tsx +26 -0
  163. package/src/lib/typeUtils.ts +109 -0
  164. package/src/lib/utils.ts +85 -0
  165. package/src/styles/codeSyntax.css +59 -0
  166. package/src/styles/globals.css +51 -0
  167. package/src/types.ts +200 -0
  168. package/src/utilities.css +347 -6
  169. package/src/vite-env.d.ts +6 -0
  170. package/types/utilities.d.ts +43 -1
  171. package/dist/components/AIChat/AIChatContainer.d.ts +0 -25
  172. package/dist/components/AIChat/AIChatMessage.d.ts +0 -19
  173. package/dist/components/AIChat/AIChatMessageComposer.d.ts +0 -22
  174. package/dist/components/AIChat/AIChatMessageList.d.ts +0 -6
  175. package/dist/components/AIChat/AIChatModelSelector.d.ts +0 -14
  176. package/dist/components/AIChat/componentsTypes.d.ts +0 -11
  177. package/dist/components/AIChat/context.d.ts +0 -3
  178. package/dist/components/AIChat/index.d.ts +0 -12
  179. package/dist/components/AIChat/parts/AIChatMessageFilePart.d.ts +0 -7
  180. package/dist/components/AIChat/parts/AIChatMessageReasoningPart.d.ts +0 -5
  181. package/dist/components/AIChat/parts/AIChatMessageSourcePart.d.ts +0 -9
  182. package/dist/components/AIChat/parts/AIChatMessageTextPart.d.ts +0 -5
  183. package/dist/components/AIChat/parts/AIChatMessageToolInvocationPart.d.ts +0 -6
  184. package/dist/components/AIChat/parts/AIChatMessageToolPart.d.ts +0 -33
  185. package/dist/components/AIChat/parts/AIChatMessageToolResultPart.d.ts +0 -5
  186. package/dist/components/AIChat/toolCallApproval.d.ts +0 -15
  187. package/dist/components/AIChat/types.d.ts +0 -78
  188. package/dist/components/ActionBar/index.d.ts +0 -36
  189. package/dist/components/Alert/index.d.ts +0 -18
  190. package/dist/components/Alert/types.d.ts +0 -4
  191. package/dist/components/Badge/index.d.ts +0 -10
  192. package/dist/components/Button/index.d.ts +0 -11
  193. package/dist/components/Card/index.d.ts +0 -47
  194. package/dist/components/CodeEditorLayout/index.d.ts +0 -101
  195. package/dist/components/CodePlayground/index.d.ts +0 -108
  196. package/dist/components/CodePlayground/lineNumbers.d.ts +0 -2
  197. package/dist/components/CodePlayground/tokenTransitions.d.ts +0 -2
  198. package/dist/components/CodePlayground/wordWrap.d.ts +0 -2
  199. package/dist/components/CodeSnippet/index.d.ts +0 -50
  200. package/dist/components/Combobox/index.d.ts +0 -35
  201. package/dist/components/Command/index.d.ts +0 -80
  202. package/dist/components/Container/index.d.ts +0 -9
  203. package/dist/components/ContextDropdown/index.d.ts +0 -7
  204. package/dist/components/ContextDropdown/provider.d.ts +0 -22
  205. package/dist/components/ContextDropdown/useModal.d.ts +0 -11
  206. package/dist/components/Dialog/index.d.ts +0 -19
  207. package/dist/components/DragNDrop/DragNDropArea.d.ts +0 -8
  208. package/dist/components/DragNDrop/DragOverlay.d.ts +0 -1
  209. package/dist/components/DragNDrop/Draggable.d.ts +0 -29
  210. package/dist/components/DragNDrop/Droppable.d.ts +0 -28
  211. package/dist/components/Dropdown/index.d.ts +0 -27
  212. package/dist/components/ExternalPill/index.d.ts +0 -12
  213. package/dist/components/Facepile/index.d.ts +0 -16
  214. package/dist/components/GradientCircle/index.d.ts +0 -10
  215. package/dist/components/Grid/index.d.ts +0 -80
  216. package/dist/components/Heading/index.d.ts +0 -12
  217. package/dist/components/HighlightedText/index.d.ts +0 -19
  218. package/dist/components/Icon/customIcons/createCustomLucideIcon.d.ts +0 -3
  219. package/dist/components/Icon/customIcons/gems.d.ts +0 -2
  220. package/dist/components/Icon/customIcons/go.d.ts +0 -2
  221. package/dist/components/Icon/customIcons/index.d.ts +0 -10
  222. package/dist/components/Icon/customIcons/maven.d.ts +0 -2
  223. package/dist/components/Icon/customIcons/npm.d.ts +0 -2
  224. package/dist/components/Icon/customIcons/nuget.d.ts +0 -2
  225. package/dist/components/Icon/customIcons/packagist.d.ts +0 -2
  226. package/dist/components/Icon/customIcons/pypi.d.ts +0 -2
  227. package/dist/components/Icon/index.d.ts +0 -10
  228. package/dist/components/Icon/isIconName.d.ts +0 -2
  229. package/dist/components/Icon/names.d.ts +0 -6
  230. package/dist/components/Input/index.d.ts +0 -8
  231. package/dist/components/KeyHint/index.d.ts +0 -16
  232. package/dist/components/LanguageIndicator/index.d.ts +0 -7
  233. package/dist/components/Link/index.d.ts +0 -19
  234. package/dist/components/LoggedInUserMenu/index.d.ts +0 -17
  235. package/dist/components/Logo/Animated.d.ts +0 -7
  236. package/dist/components/Logo/index.d.ts +0 -7
  237. package/dist/components/Logo/svgs/index.d.ts +0 -6
  238. package/dist/components/Navbar/Slim.d.ts +0 -33
  239. package/dist/components/Navbar/index.d.ts +0 -15
  240. package/dist/components/PageHeader/index.d.ts +0 -45
  241. package/dist/components/Popover/index.d.ts +0 -8
  242. package/dist/components/PromptInput/index.d.ts +0 -55
  243. package/dist/components/PullRequestLink/index.d.ts +0 -10
  244. package/dist/components/ResizablePanel/index.d.ts +0 -26
  245. package/dist/components/Score/index.d.ts +0 -37
  246. package/dist/components/ScrollArea/index.d.ts +0 -5
  247. package/dist/components/Select/index.d.ts +0 -13
  248. package/dist/components/Separator/index.d.ts +0 -6
  249. package/dist/components/Skeleton/index.d.ts +0 -27
  250. package/dist/components/Stack/index.d.ts +0 -33
  251. package/dist/components/Subnav/index.d.ts +0 -12
  252. package/dist/components/Switch/index.d.ts +0 -4
  253. package/dist/components/Table/context/context.d.ts +0 -8
  254. package/dist/components/Table/context/tableProvider.d.ts +0 -6
  255. package/dist/components/Table/index.d.ts +0 -94
  256. package/dist/components/Tabs/index.d.ts +0 -21
  257. package/dist/components/TargetLanguageIcon/index.d.ts +0 -7
  258. package/dist/components/Text/index.d.ts +0 -19
  259. package/dist/components/ThemeSwitcher/index.d.ts +0 -5
  260. package/dist/components/Tooltip/index.d.ts +0 -8
  261. package/dist/components/UserAvatar/index.d.ts +0 -9
  262. package/dist/components/UserAvatar/sizeMap.d.ts +0 -3
  263. package/dist/components/Wizard/index.d.ts +0 -19
  264. package/dist/components/Wizard/types.d.ts +0 -15
  265. package/dist/components/WorkspaceSelector/CreateOrg.d.ts +0 -6
  266. package/dist/components/WorkspaceSelector/CreateWorkspace.d.ts +0 -17
  267. package/dist/components/WorkspaceSelector/OrgList.d.ts +0 -11
  268. package/dist/components/WorkspaceSelector/OrgSelector.d.ts +0 -13
  269. package/dist/components/WorkspaceSelector/RecentWorkspaces.d.ts +0 -11
  270. package/dist/components/WorkspaceSelector/ScrollingList.d.ts +0 -21
  271. package/dist/components/WorkspaceSelector/SearchBox.d.ts +0 -9
  272. package/dist/components/WorkspaceSelector/WorkspaceItem.d.ts +0 -9
  273. package/dist/components/WorkspaceSelector/WorkspaceList.d.ts +0 -10
  274. package/dist/components/WorkspaceSelector/index.d.ts +0 -34
  275. package/dist/components/__beta__/CLIWizard/index.d.ts +0 -21
  276. package/dist/components/__beta__/CLIWizard/terminal-command.d.ts +0 -19
  277. package/dist/components/__beta__/CLIWizard/terminal.d.ts +0 -26
  278. package/dist/context/ConfigContext.d.ts +0 -18
  279. package/dist/context/theme.d.ts +0 -1
  280. package/dist/createCustomLucideIcon-YlrRX5h9.mjs +0 -19
  281. package/dist/createCustomLucideIcon-YlrRX5h9.mjs.map +0 -1
  282. package/dist/gems-BcsO9cXq.mjs +0 -24
  283. package/dist/gems-BcsO9cXq.mjs.map +0 -1
  284. package/dist/github-kgjMtfE7.mjs +0 -11
  285. package/dist/github-kgjMtfE7.mjs.map +0 -1
  286. package/dist/go-CiWl_aXI.mjs.map +0 -1
  287. package/dist/hooks/useConfig.d.ts +0 -2
  288. package/dist/hooks/useIsMounted.d.ts +0 -1
  289. package/dist/hooks/useTailwindBreakpoint.d.ts +0 -3
  290. package/dist/hooks/useTheme.d.ts +0 -6
  291. package/dist/index-COXZ9O-g.mjs +0 -50882
  292. package/dist/index-COXZ9O-g.mjs.map +0 -1
  293. package/dist/index.d.ts +0 -73
  294. package/dist/lib/assert.d.ts +0 -2
  295. package/dist/lib/codeUtils.d.ts +0 -35
  296. package/dist/lib/debounce.d.ts +0 -1
  297. package/dist/lib/responsiveMappers.d.ts +0 -10
  298. package/dist/lib/responsiveUtils.d.ts +0 -3
  299. package/dist/lib/storybookUtils.d.ts +0 -5
  300. package/dist/lib/typeUtils.d.ts +0 -24
  301. package/dist/lib/utils.d.ts +0 -23
  302. package/dist/lucide-icons-BDw0imyx.mjs +0 -28054
  303. package/dist/lucide-icons-BDw0imyx.mjs.map +0 -1
  304. package/dist/maven-DhmnGXoB.mjs.map +0 -1
  305. package/dist/maven-W_nkSDNW.mjs +0 -107
  306. package/dist/maven-W_nkSDNW.mjs.map +0 -1
  307. package/dist/moonshine.es.js +0 -114
  308. package/dist/moonshine.es.js.map +0 -1
  309. package/dist/npm-BWTcVvFH.mjs +0 -11
  310. package/dist/npm-BWTcVvFH.mjs.map +0 -1
  311. package/dist/npm-CvQ4GKW4.mjs +0 -17
  312. package/dist/npm-CvQ4GKW4.mjs.map +0 -1
  313. package/dist/nuget-5a2icRS2.mjs.map +0 -1
  314. package/dist/nuget-CV5HU1JR.mjs +0 -11
  315. package/dist/nuget-CV5HU1JR.mjs.map +0 -1
  316. package/dist/packagist-CET6q9hi.mjs +0 -118
  317. package/dist/packagist-CET6q9hi.mjs.map +0 -1
  318. package/dist/packagist-D01fn9N_.mjs +0 -11
  319. package/dist/packagist-D01fn9N_.mjs.map +0 -1
  320. package/dist/pypi-DLh6kIJe.mjs +0 -11
  321. package/dist/pypi-DLh6kIJe.mjs.map +0 -1
  322. package/dist/pypi-DsuRYjdK.mjs.map +0 -1
  323. package/dist/rubygems-DeiNjcDV.mjs +0 -11
  324. package/dist/rubygems-DeiNjcDV.mjs.map +0 -1
  325. package/dist/speakeasy-logo-ByBTXLWb.mjs +0 -5
  326. package/dist/speakeasy-logo-ByBTXLWb.mjs.map +0 -1
  327. package/dist/style.css +0 -1
  328. package/dist/terraform-C4aktQ0o.mjs +0 -11
  329. package/dist/terraform-C4aktQ0o.mjs.map +0 -1
  330. package/dist/types.d.ts +0 -80
@@ -0,0 +1,193 @@
1
+ import { cn } from '../../lib/utils'
2
+ import React, { FC, PropsWithChildren, ReactNode } from 'react'
3
+ import { Icon } from '../Icon'
4
+ import { Stack } from '../Stack'
5
+ import { Button } from '../Button'
6
+ import { Score } from '../Score'
7
+ import { iconNames } from '../Icon/names'
8
+ import { Children } from 'react'
9
+ import { Range } from '../../lib/typeUtils'
10
+
11
+ type RightElement =
12
+ | {
13
+ type: 'button'
14
+ label: string
15
+ onClick: () => void
16
+ }
17
+ | {
18
+ type: 'gauge'
19
+ value: Range<100>
20
+ }
21
+
22
+ type IconProps = {
23
+ name: (typeof iconNames)[number]
24
+ size?: 'small' | 'medium' | 'large'
25
+ }
26
+
27
+ type CardHeaderProps = PropsWithChildren & {
28
+ subheader?: React.ReactNode
29
+ icon?: IconProps
30
+ rightElement?: RightElement
31
+ className?: string
32
+ }
33
+
34
+ const CardHeader: FC<CardHeaderProps> = ({
35
+ children,
36
+ subheader,
37
+ icon,
38
+ rightElement,
39
+ className,
40
+ }) => (
41
+ <div
42
+ className={cn(
43
+ 'flex w-full flex-row gap-4',
44
+ subheader ? 'items-start' : 'items-center',
45
+ className
46
+ )}
47
+ >
48
+ {icon && (
49
+ <div className="flex-shrink-0 rounded-[8px] border p-2">
50
+ <Icon name={icon.name} size={icon.size} />
51
+ </div>
52
+ )}
53
+
54
+ <div className="flex min-w-0 flex-grow flex-col gap-1">
55
+ <div className="text-md leading-none font-semibold tracking-tight">
56
+ {children}
57
+ </div>
58
+ {subheader && (
59
+ <div className="text-card-foreground mt-1 flex items-center text-sm">
60
+ {subheader}
61
+ </div>
62
+ )}
63
+ </div>
64
+
65
+ {rightElement && (
66
+ <div className="flex flex-shrink-0 justify-end gap-2">
67
+ {rightElement.type === 'button' && (
68
+ <Button onClick={rightElement.onClick} variant="secondary">
69
+ {rightElement.label}
70
+ </Button>
71
+ )}
72
+ {rightElement.type === 'gauge' && rightElement.value && (
73
+ <Score score={rightElement.value} size="small" />
74
+ )}
75
+ </div>
76
+ )}
77
+ </div>
78
+ )
79
+ CardHeader.displayName = 'CardHeader'
80
+
81
+ interface CardContentProps extends PropsWithChildren {
82
+ className?: string
83
+ }
84
+
85
+ const CardContent: FC<CardContentProps> = ({ children, className }) => (
86
+ <div className={cn('text-sm', className)}>{children}</div>
87
+ )
88
+ CardContent.displayName = 'CardContent'
89
+
90
+ type FooterContent = {
91
+ text: string
92
+ link?: {
93
+ label: string
94
+ href: string
95
+ }
96
+ }
97
+
98
+ type CardFooterProps = {
99
+ content: FooterContent
100
+ className?: string
101
+ }
102
+
103
+ const CardFooter: FC<CardFooterProps> = ({ content, className }) => (
104
+ <div className={cn('border-t px-6 py-4', className)}>
105
+ <div className="text-card-foreground flex items-center text-sm">
106
+ {content.text}
107
+ {content.link && (
108
+ <a
109
+ href={content.link.href}
110
+ className="text-primary ml-2 hover:underline"
111
+ >
112
+ {content.link.label}
113
+ </a>
114
+ )}
115
+ </div>
116
+ </div>
117
+ )
118
+ CardFooter.displayName = 'CardFooter'
119
+
120
+ export type CardProps = {
121
+ children: ReactNode | ReactNode[]
122
+ onClick?: () => void
123
+ href?: string
124
+ className?: string
125
+ }
126
+
127
+ const Card: FC<CardProps> = ({ children, onClick, href, className }) => {
128
+ const validChildren = Children.toArray(children).filter(
129
+ (child) =>
130
+ React.isValidElement(child) &&
131
+ (child.type === CardHeader ||
132
+ child.type === CardContent ||
133
+ child.type === CardFooter)
134
+ )
135
+
136
+ const hasButtonElement = Children.toArray(validChildren).some((child) => {
137
+ if (React.isValidElement(child) && child.type === CardHeader) {
138
+ return child.props.rightElement?.type === 'button'
139
+ }
140
+ return false
141
+ })
142
+
143
+ if (hasButtonElement && (onClick || href)) {
144
+ console.warn(
145
+ 'Card: Card-level interaction (onClick/href) will be ignored when header contains a button element. ' +
146
+ 'This prevents confusing UX with nested clickable elements.'
147
+ )
148
+ }
149
+
150
+ const isInteractive = !hasButtonElement && Boolean(onClick || href)
151
+ const Wrapper = href && !hasButtonElement ? 'a' : 'div'
152
+ const wrapperProps = !hasButtonElement
153
+ ? href
154
+ ? { href }
155
+ : onClick
156
+ ? { onClick }
157
+ : {}
158
+ : {}
159
+
160
+ return (
161
+ <Wrapper
162
+ className={cn(
163
+ 'bg-card text-card-foreground relative flex h-full w-full flex-col rounded-[8px] border shadow',
164
+ isInteractive && 'hover:bg-card/70 cursor-pointer',
165
+ className
166
+ )}
167
+ {...wrapperProps}
168
+ >
169
+ <div className="p-6">
170
+ <Stack gap={3}>
171
+ {validChildren.map((child) => {
172
+ if (React.isValidElement(child) && child.type === CardFooter) {
173
+ return null
174
+ }
175
+
176
+ return child
177
+ })}
178
+ </Stack>
179
+ </div>
180
+ {validChildren.find(
181
+ (child) => React.isValidElement(child) && child.type === CardFooter
182
+ )}
183
+ </Wrapper>
184
+ )
185
+ }
186
+
187
+ const CardWithSubcomponents = Object.assign(Card, {
188
+ Header: CardHeader,
189
+ Content: CardContent,
190
+ Footer: CardFooter,
191
+ })
192
+
193
+ export { CardWithSubcomponents as Card }
@@ -0,0 +1,394 @@
1
+ import { Icon } from '../Icon'
2
+ import { cn } from '../../lib/utils'
3
+ import {
4
+ isValidElement,
5
+ ReactNode,
6
+ Children,
7
+ PropsWithChildren,
8
+ useState,
9
+ useMemo,
10
+ HTMLAttributes,
11
+ } from 'react'
12
+ import {
13
+ Panel,
14
+ PanelGroup,
15
+ PanelProps,
16
+ PanelResizeHandle,
17
+ } from 'react-resizable-panels'
18
+ import styles from './styles.module.css'
19
+
20
+ export interface CodeEditorLayoutProps {
21
+ children: ReactNode[] | ReactNode
22
+ className?: string
23
+ }
24
+
25
+ const CodeEditorLayout = ({ children, className }: CodeEditorLayoutProps) => {
26
+ const validChildren = Children.toArray(children).filter((child) => {
27
+ if (!isValidElement(child)) return false
28
+ const type = child.type as { displayName?: string }
29
+ const isValidSubType =
30
+ type.displayName === 'CodeEditor.Pane' ||
31
+ type.displayName === 'CodeEditor.Tabs' ||
32
+ type.displayName === 'CodeEditor.CommandBar' ||
33
+ type.displayName === 'CodeEditor.Empty'
34
+
35
+ if (!isValidSubType) {
36
+ console.warn(
37
+ `Invalid child type: ${type.displayName}. Must be one of: CodeEditor.Pane, CodeEditor.Tabs, CodeEditor.CommandBar, CodeEditor.Empty`
38
+ )
39
+ }
40
+
41
+ return isValidSubType
42
+ })
43
+
44
+ const panes = validChildren.filter((child) => {
45
+ if (!isValidElement(child)) return false
46
+ const type = child.type as { displayName?: string }
47
+ return type.displayName === 'CodeEditor.Pane'
48
+ })
49
+
50
+ const empty = validChildren.find((child) => {
51
+ if (!isValidElement(child)) return false
52
+ const type = child.type as { displayName?: string }
53
+ return type.displayName === 'CodeEditor.Empty'
54
+ })
55
+
56
+ const commandBar = validChildren.find((child) => {
57
+ if (!isValidElement(child)) return false
58
+ const type = child.type as { displayName?: string }
59
+ return type.displayName === 'CodeEditor.CommandBar'
60
+ })
61
+
62
+ return (
63
+ <div className="flex h-full w-full flex-col rounded-lg">
64
+ {commandBar}
65
+ <PanelGroup
66
+ className={cn('flex min-h-0 flex-row', className)}
67
+ direction="horizontal"
68
+ >
69
+ {Children.map(panes, (pane, index) =>
70
+ index < panes.length - 1 ? (
71
+ <>
72
+ {pane}
73
+
74
+ <PanelResizeHandle className="bg-background" />
75
+ </>
76
+ ) : (
77
+ pane
78
+ )
79
+ )}
80
+ {empty && <Panel>{empty}</Panel>}
81
+ </PanelGroup>
82
+ </div>
83
+ )
84
+ }
85
+
86
+ CodeEditorLayout.displayName = 'CodeEditor'
87
+
88
+ export interface CodeEditorPaneProps extends PanelProps {
89
+ className?: string
90
+ containerRef?: React.RefObject<HTMLDivElement>
91
+
92
+ /**
93
+ * Optional tabs to display above the scrolling pane
94
+ */
95
+ tabs?: React.ReactNode
96
+ }
97
+
98
+ const CodeEditorPane = ({
99
+ children,
100
+ className,
101
+ minSize,
102
+ maxSize,
103
+ containerRef,
104
+ tabs,
105
+ ...props
106
+ }: CodeEditorPaneProps) => {
107
+ return (
108
+ <Panel
109
+ {...props}
110
+ minSize={minSize}
111
+ maxSize={maxSize}
112
+ className={cn(className)}
113
+ >
114
+ {tabs}
115
+ <div
116
+ className={cn(
117
+ 'bg-background [&::-webkit-scrollbar-thumb]:bg-foreground/10 [&::-webkit-scrollbar-thumb]:hover:bg-foreground/20 [&::-webkit-scrollbar-track]:bg-card border-neutral-softest h-full flex-1 overflow-x-hidden overflow-y-scroll border',
118
+ className
119
+ )}
120
+ ref={containerRef}
121
+ >
122
+ {children}
123
+ </div>
124
+ </Panel>
125
+ )
126
+ }
127
+ CodeEditorPane.displayName = 'CodeEditor.Pane'
128
+
129
+ export interface CodeEditorTabsProps
130
+ extends PropsWithChildren,
131
+ HTMLAttributes<HTMLDivElement> {
132
+ className?: string
133
+ }
134
+
135
+ const CodeEditorTabs = ({
136
+ children,
137
+ className,
138
+ ...props
139
+ }: CodeEditorTabsProps) => {
140
+ const validChildren = Children.toArray(children).filter((child) => {
141
+ if (!isValidElement(child)) return false
142
+ const type = child.type as { displayName?: string }
143
+ return (
144
+ type.displayName === 'CodeEditor.Tab' ||
145
+ type.displayName === 'CodeEditor.CustomTabElement'
146
+ )
147
+ })
148
+
149
+ return (
150
+ <div
151
+ {...props}
152
+ className={cn(
153
+ 'code-editor-tabs bg-background border-neutral-softest flex w-full flex-row overflow-x-scroll overflow-y-hidden border-b [&::-webkit-scrollbar]:hidden',
154
+ className
155
+ )}
156
+ >
157
+ {validChildren}
158
+ </div>
159
+ )
160
+ }
161
+ CodeEditorTabs.displayName = 'CodeEditor.Tabs'
162
+
163
+ export interface CodeEditorTabProps
164
+ extends Omit<HTMLAttributes<HTMLDivElement>, 'onClick' | 'title'> {
165
+ id: string
166
+ title?: string | ReactNode
167
+ className?: string
168
+ active?: boolean
169
+ closable?: boolean
170
+ grow?: boolean
171
+ icon?: ReactNode
172
+ invalid?: boolean
173
+ dirty?: boolean
174
+ saving?: boolean
175
+ onClick?: (id: string) => void
176
+ onClose?: (id: string) => void
177
+
178
+ /**
179
+ * If true, the tab will not be interactive
180
+ * Useful for loading states
181
+ */
182
+ disabled?: boolean
183
+
184
+ /**
185
+ * Custom styles for the tab
186
+ */
187
+ customStyles?: CodeEditorTabStateCustomStyles
188
+ }
189
+
190
+ /**
191
+ * Allows for custom styles to be applied to the tab based on its state
192
+ *
193
+ * @example
194
+ * <CodeEditor.Tab
195
+ * customStyles={{
196
+ * active: 'text-foreground bg-background',
197
+ * inactive: 'text-body-muted bg-muted',
198
+ * dirty: 'text-yellow-700/90 italic dark:text-yellow-300/70',
199
+ * invalid: 'text-red-700 dark:text-red-400',
200
+ * disabled: 'cursor-not-allowed opacity-75',
201
+ * }}
202
+ * />
203
+ */
204
+ type CodeEditorTabStateCustomStyles = {
205
+ active?: string
206
+ inactive?: string
207
+ dirty?: string
208
+ invalid?: string
209
+ disabled?: string
210
+ saving?: string
211
+ }
212
+
213
+ const CodeEditorTab = ({
214
+ id,
215
+ title,
216
+ className,
217
+ active,
218
+ closable,
219
+ grow,
220
+ dirty,
221
+ invalid,
222
+ saving,
223
+ onClick,
224
+ onClose,
225
+ icon,
226
+ disabled,
227
+ customStyles,
228
+ ...props
229
+ }: CodeEditorTabProps) => {
230
+ const [hoveredCloseIntent, setHoveredCloseIntent] = useState(false)
231
+ const handleClose = (e: React.MouseEvent<HTMLButtonElement>) => {
232
+ // stop the event from bubbling up to the parent tab click handler
233
+ e.stopPropagation()
234
+ onClose?.(id)
235
+ setHoveredCloseIntent(false)
236
+ }
237
+ const closeButton = useMemo(
238
+ () => (
239
+ <button
240
+ className={cn(
241
+ 'text-body-muted hover:bg-muted hover:dark:bg-foreground/15 hover:text-foreground ml-auto h-full rounded-sm p-0.5',
242
+ hoveredCloseIntent && 'bg-background/80',
243
+ hoveredCloseIntent &&
244
+ dirty &&
245
+ `!bg-foreground/5 dark:!bg-foreground/10`
246
+ )}
247
+ onMouseEnter={() => setHoveredCloseIntent(true)}
248
+ onMouseLeave={() => setHoveredCloseIntent(false)}
249
+ onClick={handleClose}
250
+ >
251
+ <Icon name="x" className="h-3.5 w-3.5" />
252
+ </button>
253
+ ),
254
+ [hoveredCloseIntent, onClose, id, active]
255
+ )
256
+
257
+ return (
258
+ <div
259
+ {...props}
260
+ className={cn(
261
+ 'code-editor-tab bg-background relative flex w-fit cursor-pointer items-center justify-start gap-2.5 rounded-sm rounded-t-none border-r py-2 pr-2 pl-3 text-sm whitespace-nowrap select-none first-of-type:border-l-0',
262
+ grow && 'flex-1',
263
+ active && 'text-foreground bg-background',
264
+ !active && 'text-body-muted bg-muted',
265
+ dirty && !saving && 'text-yellow-700/90 italic dark:text-yellow-300/70',
266
+ invalid && 'text-red-700 dark:text-red-400',
267
+ disabled && 'cursor-not-allowed opacity-75',
268
+ className,
269
+
270
+ // Override styles
271
+ customStyles && customStyles.active,
272
+ customStyles && customStyles.inactive,
273
+ customStyles && customStyles.dirty,
274
+ customStyles && customStyles.invalid,
275
+ customStyles && customStyles.disabled,
276
+ customStyles && customStyles.saving
277
+ )}
278
+ key={id}
279
+ onClick={() => onClick?.(id)}
280
+ >
281
+ <div className="flex items-center gap-1.5">
282
+ {icon && <span className="flex items-center">{icon}</span>}
283
+
284
+ <span title={typeof title === 'string' ? title : undefined}>
285
+ {title}
286
+ </span>
287
+ </div>
288
+ {closable && !dirty && closeButton}
289
+ {dirty && !saving && (
290
+ <span
291
+ onMouseEnter={() => setHoveredCloseIntent(true)}
292
+ className="text-body-muted ml-auto flex h-full w-3 items-center justify-center text-xs"
293
+ >
294
+ {!hoveredCloseIntent ? (
295
+ <Icon name="circle" className="fill-foreground h-2.5 w-2.5" />
296
+ ) : closable ? (
297
+ closeButton
298
+ ) : (
299
+ <Icon name="circle" className="fill-foreground h-2.5 w-2.5" />
300
+ )}
301
+ </span>
302
+ )}
303
+
304
+ {saving && (
305
+ <div className="text-muted-foreground ml-auto flex h-full w-3 items-center justify-center">
306
+ <Icon name="loader-circle" className="size-5 animate-spin" />
307
+ </div>
308
+ )}
309
+
310
+ {saving && (
311
+ <div className="pointer-events-none absolute bottom-0 left-0 h-0.5 w-full overflow-hidden">
312
+ <div
313
+ className={cn(
314
+ 'absolute h-full w-3/4 -translate-x-full bg-blue-500 dark:bg-blue-300',
315
+ styles.editorTabLoadingBar
316
+ )}
317
+ />
318
+ </div>
319
+ )}
320
+ </div>
321
+ )
322
+ }
323
+ CodeEditorTab.displayName = 'CodeEditor.Tab'
324
+
325
+ export interface CodeEditorCommandBarProps
326
+ extends PropsWithChildren,
327
+ HTMLAttributes<HTMLDivElement> {
328
+ className?: string
329
+ }
330
+
331
+ const CodeEditorCommandBar = ({
332
+ children,
333
+ className,
334
+ ...props
335
+ }: CodeEditorCommandBarProps) => {
336
+ return (
337
+ <div
338
+ {...props}
339
+ className={cn(
340
+ 'code-editor-command-bar bg-muted rounded-sm rounded-b-none px-3 py-1',
341
+ className
342
+ )}
343
+ >
344
+ {children}
345
+ </div>
346
+ )
347
+ }
348
+ CodeEditorCommandBar.displayName = 'CodeEditor.CommandBar'
349
+
350
+ export interface CodeEditorCustomElementProps
351
+ extends PropsWithChildren,
352
+ HTMLAttributes<HTMLDivElement> {
353
+ className?: string
354
+ }
355
+
356
+ const CustomTabElement = ({
357
+ children,
358
+ className,
359
+ ...props
360
+ }: CodeEditorCustomElementProps) => {
361
+ return (
362
+ <div className={cn('h-full w-full', className)} {...props}>
363
+ {children}
364
+ </div>
365
+ )
366
+ }
367
+ CustomTabElement.displayName = 'CodeEditor.CustomTabElement'
368
+
369
+ export interface CodeEditorEmptyProps
370
+ extends PropsWithChildren,
371
+ HTMLAttributes<HTMLDivElement> {
372
+ className?: string
373
+ }
374
+
375
+ const Empty = ({ children, className, ...props }: CodeEditorEmptyProps) => {
376
+ return (
377
+ <div className={cn('h-full w-full', className)} {...props}>
378
+ {children}
379
+ </div>
380
+ )
381
+ }
382
+
383
+ Empty.displayName = 'CodeEditor.Empty'
384
+
385
+ const CodeEditor = Object.assign(CodeEditorLayout, {
386
+ Pane: CodeEditorPane,
387
+ CommandBar: CodeEditorCommandBar,
388
+ Empty: Empty,
389
+ Tabs: CodeEditorTabs,
390
+ Tab: CodeEditorTab,
391
+ CustomTabElement: CustomTabElement,
392
+ })
393
+
394
+ export { CodeEditor }
@@ -0,0 +1,8 @@
1
+ @keyframes editor-tab-loading-bar {
2
+ 0% { transform: translateX(-100%); }
3
+ 100% { transform: translateX(300%); }
4
+ }
5
+
6
+ .editorTabLoadingBar {
7
+ animation: editor-tab-loading-bar 2.5s linear infinite;
8
+ }
@@ -0,0 +1,63 @@
1
+ import { forwardRef, HTMLAttributes } from 'react'
2
+ import { HighlightedCode } from '../../lib/codeUtils'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ export interface PreProps
6
+ extends Omit<HTMLAttributes<HTMLPreElement>, 'children'> {
7
+ code: HighlightedCode
8
+ showLineNumbers?: boolean
9
+ wordWrap?: boolean
10
+ }
11
+
12
+ export const Pre = forwardRef<HTMLPreElement, PreProps>(
13
+ (
14
+ { code, showLineNumbers = false, wordWrap = false, className, ...props },
15
+ ref
16
+ ) => {
17
+ return (
18
+ <pre
19
+ ref={ref}
20
+ className={cn(
21
+ 'inline-block font-mono outline-none',
22
+ wordWrap && 'whitespace-pre-wrap',
23
+ className
24
+ )}
25
+ {...props}
26
+ >
27
+ <code>
28
+ {code.lines.map((line, lineIndex) => (
29
+ <div
30
+ key={lineIndex}
31
+ className={cn('flex flex-row', wordWrap && 'flex-wrap')}
32
+ >
33
+ {showLineNumbers && (
34
+ <span className="text-body-muted pr-3 select-none">
35
+ {lineIndex + 1}
36
+ </span>
37
+ )}
38
+ <span className={cn('inline-block', wordWrap && 'flex-1')}>
39
+ {line.tokens.map((token, tokenIndex) => (
40
+ <span
41
+ key={tokenIndex}
42
+ style={{
43
+ color: token.color,
44
+ fontStyle: token.fontStyle ? 'italic' : undefined,
45
+ fontWeight:
46
+ token.fontStyle && token.fontStyle & 1
47
+ ? 'bold'
48
+ : undefined,
49
+ }}
50
+ >
51
+ {token.content}
52
+ </span>
53
+ ))}
54
+ </span>
55
+ </div>
56
+ ))}
57
+ </code>
58
+ </pre>
59
+ )
60
+ }
61
+ )
62
+
63
+ Pre.displayName = 'Pre'