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

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,411 @@
1
+ import {
2
+ useCallback,
3
+ useEffect,
4
+ useMemo,
5
+ useState,
6
+ Children,
7
+ isValidElement,
8
+ HTMLAttributes,
9
+ forwardRef,
10
+ useRef,
11
+ } from 'react'
12
+ import {
13
+ Select,
14
+ SelectContent,
15
+ SelectItem,
16
+ SelectTrigger,
17
+ SelectValue,
18
+ } from '../Select'
19
+ import { prettyLanguageName, SupportedLanguage } from '../../types'
20
+ import '../../styles/codeSyntax.css'
21
+ import { motion } from 'motion/react'
22
+ import { cn } from '../../lib/utils'
23
+ import { AnimatePresence } from 'motion/react'
24
+ import { Icon } from '../Icon'
25
+ import { Skeleton } from '../Skeleton'
26
+ import {
27
+ highlightCode,
28
+ HighlightedCode,
29
+ LIGHT_THEME,
30
+ DARK_THEME,
31
+ } from '../../lib/codeUtils'
32
+ import React from 'react'
33
+ import { Pre } from '../CodeHighlight/Pre'
34
+ import { useConfig } from '../../hooks/useConfig'
35
+
36
+ const copyIconVariants = {
37
+ hidden: { opacity: 0, scale: 0.5 },
38
+ visible: { opacity: 1, scale: 1 },
39
+ }
40
+ export interface CodePlaygroundSnippet {
41
+ /**
42
+ * The code to display in the playground.
43
+ */
44
+ code?: string | undefined
45
+ /**
46
+ * Whether the code is loading.
47
+ */
48
+ loading?: boolean | undefined
49
+ }
50
+
51
+ export type CodePlaygroundSnippets = Partial<
52
+ Record<SupportedLanguage, CodePlaygroundSnippet>
53
+ >
54
+
55
+ export interface CodePlaygroundProps {
56
+ /**
57
+ * The children of the playground.
58
+ * Accepts a `CodePlayground.Header` and a `CodePlayground.Footer` or a `CodePlayground.Code` component.
59
+ */
60
+ children: React.ReactNode
61
+
62
+ /**
63
+ * The error to display in the playground if the code could not be loaded.
64
+ */
65
+ error?: React.ReactNode | undefined
66
+
67
+ /**
68
+ * An object of snippets to display in the playground.
69
+ *
70
+ * @example
71
+ * <CodePlayground
72
+ * snippets={{
73
+ * javascript: { code: 'console.log("Hello, world!");' },
74
+ * typescript: { code: 'console.log("Hello, world!");' },
75
+ * }}
76
+ * />
77
+ */
78
+ snippets: CodePlaygroundSnippets
79
+
80
+ /**
81
+ * The language that should be selected when the playground is mounted.
82
+ */
83
+ selectedLanguage: SupportedLanguage
84
+
85
+ /**
86
+ * Whether the code should be copyable.
87
+ *
88
+ * @default true
89
+ */
90
+ copyable?: boolean
91
+
92
+ /** Custom class name to apply to the container */
93
+ className?: string
94
+
95
+ /**
96
+ * Whether to wrap the code.
97
+ *
98
+ * @default true
99
+ */
100
+ wordWrap?: boolean
101
+
102
+ /**
103
+ * A callback to be called when the language is changed.
104
+ */
105
+ onChangeLanguage?: (language: SupportedLanguage) => void
106
+
107
+ /**
108
+ * Whether to show the language selector.
109
+ */
110
+ showLanguageSelector?: boolean
111
+
112
+ /**
113
+ * Whether to show line numbers.
114
+ *
115
+ * @default true
116
+ */
117
+ showLineNumbers?: boolean
118
+ }
119
+
120
+ const CodePlayground = ({
121
+ children,
122
+ snippets,
123
+ copyable = true,
124
+ selectedLanguage,
125
+ className,
126
+ onChangeLanguage,
127
+ error,
128
+ showLineNumbers = true,
129
+ showLanguageSelector = true,
130
+ wordWrap = true,
131
+ }: CodePlaygroundProps) => {
132
+ const codeRef = useRef<HTMLDivElement>(null)
133
+ const validChildren = Children.toArray(children).filter((child) => {
134
+ if (!isValidElement(child)) return false
135
+ const type = child.type as { displayName?: string }
136
+ const isValidSubType =
137
+ type.displayName === 'CodePlayground.Header' ||
138
+ type.displayName === 'CodePlayground.Footer' ||
139
+ type.displayName === 'CodePlayground.Code'
140
+
141
+ if (!isValidSubType) {
142
+ console.warn(
143
+ `Invalid child type: ${type.displayName}. Must be one of: CodePlayground.Header, CodePlayground.Footer`
144
+ )
145
+ }
146
+
147
+ return isValidSubType
148
+ })
149
+
150
+ const header = validChildren.find(
151
+ (child) =>
152
+ isValidElement(child) &&
153
+ (child.type as { displayName?: string }).displayName ===
154
+ 'CodePlayground.Header'
155
+ )
156
+
157
+ const [highlighted, setHighlighted] = useState<HighlightedCode | null>(null)
158
+ const selectedCode = snippets[selectedLanguage]!
159
+ const { theme } = useConfig()
160
+
161
+ const loadingSkeleton = useMemo(() => {
162
+ // Try to measure the existing height of the code container if code has
163
+ // already been rendered. Otherwise, use a default height
164
+
165
+ // TODO: improve this logic
166
+ const measuredHeight =
167
+ codeRef.current?.getBoundingClientRect().height ?? 400
168
+
169
+ const lines = Math.ceil(measuredHeight / 40)
170
+ return (
171
+ <Skeleton className={`w-full`}>
172
+ {Array.from({ length: lines }).map((_, i) => (
173
+ <div id={`skeleton-line-${i}`} key={i} className="h-4 w-full" />
174
+ ))}
175
+ </Skeleton>
176
+ )
177
+ }, [codeRef.current])
178
+
179
+ const codeContents = error ? (
180
+ error
181
+ ) : selectedCode.loading ? (
182
+ <div className="flex items-center p-4">{loadingSkeleton}</div>
183
+ ) : highlighted ? (
184
+ <Pre
185
+ code={highlighted}
186
+ showLineNumbers={showLineNumbers}
187
+ wordWrap={wordWrap}
188
+ className="bg-muted/15 dark:bg-background relative m-0 mr-4 w-full px-4 py-3 text-sm"
189
+ />
190
+ ) : null
191
+
192
+ const foundCustomCodeContainer = useMemo(
193
+ () =>
194
+ validChildren.find(
195
+ (child) =>
196
+ isValidElement(child) &&
197
+ (child.type as { displayName?: string }).displayName ===
198
+ 'CodePlayground.Code'
199
+ ),
200
+ [validChildren]
201
+ )
202
+
203
+ const code = foundCustomCodeContainer ? (
204
+ React.cloneElement(foundCustomCodeContainer as React.ReactElement, {
205
+ __children__: codeContents,
206
+ ref: codeRef,
207
+ })
208
+ ) : (
209
+ <CodePlaygroundCode __children__={codeContents} ref={codeRef} />
210
+ )
211
+
212
+ const footer = validChildren.find(
213
+ (child) =>
214
+ isValidElement(child) &&
215
+ (child.type as { displayName?: string }).displayName ===
216
+ 'CodePlayground.Footer'
217
+ )
218
+
219
+ const updateHighlighted = useCallback(
220
+ async (code: string, language: SupportedLanguage) => {
221
+ const shikiTheme = theme === 'dark' ? DARK_THEME : LIGHT_THEME
222
+ const highlighted = await highlightCode(code, language, shikiTheme)
223
+ setHighlighted(highlighted)
224
+ },
225
+ [theme]
226
+ )
227
+
228
+ const [copying, setCopying] = useState(false)
229
+
230
+ const handleCopy = useCallback(() => {
231
+ setCopying(true)
232
+ navigator.clipboard.writeText(selectedCode.code ?? '')
233
+ setTimeout(() => {
234
+ setCopying(false)
235
+ }, 1000)
236
+ }, [selectedCode.code])
237
+
238
+ useEffect(() => {
239
+ if (selectedCode.code) {
240
+ updateHighlighted(selectedCode.code, selectedLanguage)
241
+ }
242
+ }, [selectedCode, selectedLanguage, updateHighlighted])
243
+
244
+ const handleChangeLanguage = useCallback(
245
+ (language: SupportedLanguage) => {
246
+ onChangeLanguage?.(language)
247
+ },
248
+ [onChangeLanguage]
249
+ )
250
+
251
+ return (
252
+ <div
253
+ className={cn(
254
+ 'overflow-hidden rounded-lg border shadow-md shadow-white/5',
255
+ className
256
+ )}
257
+ >
258
+ <div className="bg-card flex items-center border-b p-2">
259
+ <div className="select-none">{header && header}</div>
260
+ {showLanguageSelector && (
261
+ <div className="ml-auto">
262
+ <Select
263
+ value={selectedLanguage}
264
+ onValueChange={handleChangeLanguage}
265
+ >
266
+ <SelectTrigger className="text-body gap-1.5 !border-none !bg-transparent !p-0 !shadow-none !ring-0 select-none">
267
+ <SelectValue />
268
+ </SelectTrigger>
269
+ <SelectContent side="bottom" align="start" alignOffset={-30}>
270
+ {Object.keys(snippets).map((language) => (
271
+ <SelectItem key={language} value={language}>
272
+ {prettyLanguageName(language as SupportedLanguage)}
273
+ </SelectItem>
274
+ ))}
275
+ </SelectContent>
276
+ </Select>
277
+ </div>
278
+ )}
279
+ </div>
280
+
281
+ <div className="relative">
282
+ {code}
283
+
284
+ {selectedCode.code && copyable && (
285
+ <div className="pointer-events-auto absolute top-5 right-6 bg-transparent">
286
+ <button
287
+ role="button"
288
+ className={cn('ml-2 border-none bg-transparent outline-none')}
289
+ onClick={handleCopy}
290
+ >
291
+ <AnimatePresence mode="wait" initial={false}>
292
+ {copying ? (
293
+ <motion.span
294
+ key="checkmark"
295
+ variants={copyIconVariants}
296
+ initial="hidden"
297
+ animate="visible"
298
+ className="text-green-500"
299
+ exit="hidden"
300
+ >
301
+ <Icon name="check" stroke="currentColor" />
302
+ </motion.span>
303
+ ) : (
304
+ <motion.span
305
+ key="copy"
306
+ variants={copyIconVariants}
307
+ initial="hidden"
308
+ animate="visible"
309
+ className="text-body-muted hover:text-foreground"
310
+ exit="hidden"
311
+ >
312
+ <Icon name="copy" stroke="currentColor" />
313
+ </motion.span>
314
+ )}
315
+ </AnimatePresence>
316
+ </button>
317
+ </div>
318
+ )}
319
+ </div>
320
+
321
+ {footer && footer}
322
+ </div>
323
+ )
324
+ }
325
+
326
+ CodePlayground.displayName = 'CodePlayground'
327
+
328
+ export interface CodePlaygroundCodeProps
329
+ extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
330
+ className?: string
331
+
332
+ /**
333
+ * internal api for passing children
334
+ */
335
+ __children__?: React.ReactNode
336
+ }
337
+
338
+ const CodePlaygroundCode = forwardRef<HTMLDivElement, CodePlaygroundCodeProps>(
339
+ ({ className, __children__, ...props }, ref) => {
340
+ return (
341
+ <div
342
+ ref={ref}
343
+ {...props}
344
+ className={cn('bg-background overflow-auto', className)}
345
+ >
346
+ {__children__}
347
+ </div>
348
+ )
349
+ }
350
+ )
351
+
352
+ CodePlaygroundCode.displayName = 'CodePlayground.Code'
353
+
354
+ export interface CodePlaygroundHeaderProps
355
+ extends HTMLAttributes<HTMLDivElement> {
356
+ children: React.ReactNode
357
+ }
358
+
359
+ const CodePlaygroundHeader = ({
360
+ children,
361
+ className,
362
+ ...props
363
+ }: CodePlaygroundHeaderProps) => {
364
+ return (
365
+ <div className={cn('bg-card flex items-center', className)} {...props}>
366
+ {children}
367
+ </div>
368
+ )
369
+ }
370
+
371
+ CodePlaygroundHeader.displayName = 'CodePlayground.Header'
372
+
373
+ export interface CodePlaygroundFooterProps
374
+ extends HTMLAttributes<HTMLDivElement> {
375
+ children: React.ReactNode
376
+ }
377
+
378
+ const CodePlaygroundFooter = ({
379
+ children,
380
+ className,
381
+ ...props
382
+ }: CodePlaygroundFooterProps) => {
383
+ return (
384
+ <div
385
+ className={cn(
386
+ 'bg-card flex items-center border-t p-2 select-none',
387
+ className
388
+ )}
389
+ {...props}
390
+ >
391
+ {children}
392
+ </div>
393
+ )
394
+ }
395
+
396
+ CodePlaygroundFooter.displayName = 'CodePlayground.Footer'
397
+
398
+ const CodePlaygroundWithSubcomponents = Object.assign(CodePlayground, {
399
+ Header: CodePlaygroundHeader,
400
+ Footer: CodePlaygroundFooter,
401
+
402
+ /**
403
+ * Can be used to manipulate the properties of the code container. You can pass a custom class name to control the maximum height of the code container for example.
404
+ * No children are expected as the parent component will handle that.
405
+ * @example
406
+ * <CodePlayground.Code className="max-h-72 overflow-y-auto" />
407
+ */
408
+ Code: CodePlaygroundCode,
409
+ })
410
+
411
+ export { CodePlaygroundWithSubcomponents as CodePlayground }
@@ -0,0 +1,97 @@
1
+ @property --rotation {
2
+ syntax: '<angle>';
3
+ inherits: false;
4
+ initial-value: 0deg;
5
+ }
6
+
7
+ @property --x {
8
+ syntax: '<length>';
9
+ inherits: false;
10
+ initial-value: 0;
11
+ }
12
+
13
+ @keyframes rotate {
14
+ 0% {
15
+ --rotation: 0deg;
16
+ }
17
+
18
+ 32.8228% {
19
+ --rotation: 0deg;
20
+ }
21
+ 50% {
22
+ --rotation: 180deg;
23
+ }
24
+ 82.8228% {
25
+ --rotation: 180deg;
26
+ }
27
+ 100% {
28
+ --rotation: 360deg;
29
+ }
30
+ }
31
+
32
+ @keyframes shimmer {
33
+ 0% {
34
+ --x: 20px;
35
+ }
36
+
37
+ 32.8228% {
38
+ --x: calc(var(--width) - 20px);
39
+ }
40
+ 50% {
41
+ --x: calc(var(--width) - 20px);
42
+ }
43
+ 82.8228% {
44
+ --x: 20px;
45
+ }
46
+ 100% {
47
+ --x: 20px;
48
+ }
49
+ }
50
+
51
+ .snippet-inner {
52
+ z-index: 2;
53
+ }
54
+
55
+ .snippet {
56
+ box-sizing: border-box;
57
+ padding: 2px;
58
+ }
59
+
60
+ .snippet::before {
61
+ content: '';
62
+ display: block;
63
+ height: 100%;
64
+ width: 100%;
65
+ position: absolute;
66
+ z-index: 1;
67
+ visibility: hidden;
68
+ }
69
+
70
+ .shimmer::before {
71
+ content: '';
72
+ display: block;
73
+ padding: 1px;
74
+ background: conic-gradient(
75
+ from calc(var(--rotation) - 80deg) at var(--x) 30px,
76
+ transparent 0,
77
+ var(--border-neutral-softest) 20%,
78
+ transparent 25%
79
+ ),
80
+ transparent;
81
+ transition: all 0.2s ease;
82
+ transform: translateZ(0);
83
+ visibility: visible;
84
+ position: absolute;
85
+ top: 0;
86
+ left: 0;
87
+ right: 0;
88
+ bottom: 0;
89
+ animation:
90
+ rotate -0.64s linear 5s infinite,
91
+ shimmer -0.64s linear 5s infinite;
92
+ z-index: 1;
93
+ }
94
+
95
+ .highlighted-code {
96
+ transition: background-color cubic-bezier(0.25, 0.1, 0.25, 1) 400ms;
97
+ }