@speakeasy-api/moonshine 1.33.4 → 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/README.md +26 -10
  2. package/package.json +12 -23
  3. package/scripts/generate-utility-docs.js +324 -0
  4. package/src/assets/icons/external/github.svg +3 -0
  5. package/src/assets/icons/external/maven.svg +152 -0
  6. package/src/assets/icons/external/npm.svg +4 -0
  7. package/src/assets/icons/external/nuget.svg +5 -0
  8. package/src/assets/icons/external/packagist.svg +1 -0
  9. package/src/assets/icons/external/pypi.svg +182 -0
  10. package/src/assets/icons/external/rubygems.svg +14 -0
  11. package/src/assets/icons/external/terraform.svg +1 -0
  12. package/src/assets/icons/languages/csharp.svg +1 -0
  13. package/src/assets/icons/languages/go.svg +1 -0
  14. package/src/assets/icons/languages/java.svg +1 -0
  15. package/src/assets/icons/languages/json.svg +2 -0
  16. package/src/assets/icons/languages/php.svg +1 -0
  17. package/src/assets/icons/languages/postman.svg +3 -0
  18. package/src/assets/icons/languages/python.svg +1 -0
  19. package/src/assets/icons/languages/ruby.svg +1 -0
  20. package/src/assets/icons/languages/swift.svg +1 -0
  21. package/src/assets/icons/languages/terraform.svg +1 -0
  22. package/src/assets/icons/languages/typescript.svg +1 -0
  23. package/src/assets/icons/languages/unity.svg +1 -0
  24. package/src/components/AIChat/AIChatContainer.tsx +71 -0
  25. package/src/components/AIChat/AIChatMessage.tsx +135 -0
  26. package/src/components/AIChat/AIChatMessageComposer.tsx +175 -0
  27. package/src/components/AIChat/AIChatMessageList.tsx +34 -0
  28. package/src/components/AIChat/AIChatModelSelector.tsx +159 -0
  29. package/src/components/AIChat/componentsTypes.ts +36 -0
  30. package/src/components/AIChat/context.ts +15 -0
  31. package/src/components/AIChat/index.ts +12 -0
  32. package/src/components/AIChat/parts/AIChatMessageFilePart.tsx +129 -0
  33. package/src/components/AIChat/parts/AIChatMessageReasoningPart.tsx +23 -0
  34. package/src/components/AIChat/parts/AIChatMessageSourcePart.tsx +58 -0
  35. package/src/components/AIChat/parts/AIChatMessageTextPart.tsx +33 -0
  36. package/src/components/AIChat/parts/AIChatMessageToolInvocationPart.tsx +53 -0
  37. package/src/components/AIChat/parts/AIChatMessageToolPart.tsx +395 -0
  38. package/src/components/AIChat/parts/AIChatMessageToolResultPart.tsx +46 -0
  39. package/src/components/AIChat/toolCallApproval.ts +61 -0
  40. package/src/components/AIChat/types.ts +97 -0
  41. package/src/components/ActionBar/index.tsx +184 -0
  42. package/src/components/Alert/index.tsx +118 -0
  43. package/src/components/Alert/types.ts +12 -0
  44. package/src/components/AppLayout/context.tsx +31 -0
  45. package/src/components/AppLayout/index.tsx +550 -0
  46. package/src/components/AppLayout/provider.tsx +40 -0
  47. package/src/components/AppLayout/useAppLayoutKeys.ts +26 -0
  48. package/src/components/Badge/index.tsx +227 -0
  49. package/src/components/Button/index.tsx +531 -0
  50. package/src/components/Card/index.tsx +193 -0
  51. package/src/components/CodeEditorLayout/index.tsx +394 -0
  52. package/src/components/CodeEditorLayout/styles.module.css +8 -0
  53. package/src/components/CodeHighlight/Pre.tsx +63 -0
  54. package/src/components/CodePlayground/index.tsx +411 -0
  55. package/src/components/CodeSnippet/codeSnippet.css +97 -0
  56. package/src/components/CodeSnippet/index.tsx +224 -0
  57. package/src/components/Combobox/index.tsx +193 -0
  58. package/src/components/Command/index.tsx +152 -0
  59. package/src/components/Container/index.tsx +31 -0
  60. package/src/components/ContextDropdown/index.tsx +150 -0
  61. package/src/components/Dialog/index.tsx +123 -0
  62. package/src/components/DragNDrop/DragNDropArea.tsx +30 -0
  63. package/src/components/DragNDrop/DragOverlay.tsx +4 -0
  64. package/src/components/DragNDrop/Draggable.tsx +97 -0
  65. package/src/components/DragNDrop/Droppable.tsx +51 -0
  66. package/src/components/Dropdown/index.tsx +201 -0
  67. package/src/components/ExternalPill/index.tsx +58 -0
  68. package/src/components/Facepile/index.tsx +309 -0
  69. package/src/components/GradientCircle/gradientCircle.css +34 -0
  70. package/src/components/GradientCircle/index.tsx +143 -0
  71. package/src/components/Grid/index.tsx +150 -0
  72. package/src/components/Heading/index.tsx +54 -0
  73. package/src/components/HighlightedText/index.tsx +152 -0
  74. package/src/components/Icon/customIcons/createCustomLucideIcon.ts +25 -0
  75. package/src/components/Icon/customIcons/gems.ts +26 -0
  76. package/{dist/go-DsW1bFpz.mjs → src/components/Icon/customIcons/go.ts} +21 -19
  77. package/src/components/Icon/customIcons/index.ts +11 -0
  78. package/{dist/maven-Dub5liK1.mjs → src/components/Icon/customIcons/maven.ts} +17 -15
  79. package/src/components/Icon/customIcons/npm.ts +19 -0
  80. package/{dist/nuget-D86y5HDl.mjs → src/components/Icon/customIcons/nuget.ts} +17 -15
  81. package/src/components/Icon/customIcons/packagist.ts +124 -0
  82. package/{dist/pypi-2SUX-2OR.mjs → src/components/Icon/customIcons/pypi.ts} +16 -14
  83. package/src/components/Icon/index.tsx +83 -0
  84. package/src/components/Icon/isIconName.ts +10 -0
  85. package/src/components/Icon/names.ts +14 -0
  86. package/src/components/IconButton/index.tsx +51 -0
  87. package/src/components/Input/index.tsx +98 -0
  88. package/src/components/KeyHint/index.tsx +118 -0
  89. package/src/components/LanguageIndicator/index.tsx +68 -0
  90. package/src/components/Link/index.tsx +153 -0
  91. package/src/components/LoggedInUserMenu/index.tsx +116 -0
  92. package/src/components/Logo/Animated.tsx +191 -0
  93. package/src/components/Logo/index.tsx +17 -0
  94. package/src/components/Logo/speakeasy-logo.riv +0 -0
  95. package/src/components/Logo/svgs/index.tsx +126 -0
  96. package/src/components/Modal/index.tsx +104 -0
  97. package/src/components/PageHeader/index.tsx +227 -0
  98. package/src/components/PageHeader/styles.module.css +27 -0
  99. package/src/components/Popover/index.tsx +35 -0
  100. package/src/components/PromptInput/index.tsx +372 -0
  101. package/src/components/PullRequestLink/index.tsx +64 -0
  102. package/src/components/ResizablePanel/index.tsx +119 -0
  103. package/src/components/Score/index.module.css +32 -0
  104. package/src/components/Score/index.tsx +268 -0
  105. package/src/components/ScrollArea/index.tsx +48 -0
  106. package/src/components/SegmentedButton/index.module.css +19 -0
  107. package/src/components/SegmentedButton/index.tsx +101 -0
  108. package/src/components/Select/index.tsx +159 -0
  109. package/src/components/Separator/index.tsx +23 -0
  110. package/src/components/Skeleton/index.tsx +61 -0
  111. package/src/components/Skeleton/skeleton.css +52 -0
  112. package/src/components/Stack/index.tsx +137 -0
  113. package/src/components/Subnav/index.tsx +315 -0
  114. package/src/components/Switch/index.tsx +29 -0
  115. package/src/components/Table/context/context.tsx +19 -0
  116. package/src/components/Table/context/tableProvider.tsx +39 -0
  117. package/src/components/Table/index.tsx +707 -0
  118. package/src/components/Table/styles.module.css +25 -0
  119. package/src/components/Tabs/index.tsx +87 -0
  120. package/src/components/TargetLanguageIcon/index.tsx +84 -0
  121. package/src/components/Text/index.tsx +59 -0
  122. package/src/components/ThemeSwitcher/index.tsx +118 -0
  123. package/src/components/Timeline/index.tsx +290 -0
  124. package/src/components/Tooltip/index.tsx +41 -0
  125. package/src/components/UserAvatar/index.tsx +87 -0
  126. package/src/components/UserAvatar/sizeMap.ts +12 -0
  127. package/src/components/Wizard/index.tsx +208 -0
  128. package/src/components/Wizard/types.ts +17 -0
  129. package/src/components/WorkspaceSelector/CreateOrg.tsx +95 -0
  130. package/src/components/WorkspaceSelector/CreateWorkspace.tsx +196 -0
  131. package/src/components/WorkspaceSelector/OrgList.tsx +115 -0
  132. package/src/components/WorkspaceSelector/OrgSelector.tsx +207 -0
  133. package/src/components/WorkspaceSelector/RecentWorkspaces.tsx +83 -0
  134. package/src/components/WorkspaceSelector/ScrollingList.tsx +84 -0
  135. package/src/components/WorkspaceSelector/SearchBox.tsx +40 -0
  136. package/src/components/WorkspaceSelector/WorkspaceItem.tsx +37 -0
  137. package/src/components/WorkspaceSelector/WorkspaceList.tsx +107 -0
  138. package/src/components/WorkspaceSelector/index.tsx +400 -0
  139. package/src/components/WorkspaceSelector/styles.css +74 -0
  140. package/src/components/__beta__/CLIWizard/index.tsx +357 -0
  141. package/src/components/__beta__/CLIWizard/terminal-command.tsx +108 -0
  142. package/src/components/__beta__/CLIWizard/terminal.tsx +83 -0
  143. package/src/components/__beta__/README.md +3 -0
  144. package/src/components/index.mdx +38 -0
  145. package/src/context/ConfigContext.tsx +43 -0
  146. package/src/context/ModalContext.tsx +118 -0
  147. package/src/context/theme.ts +1 -0
  148. package/src/hooks/useAppLayout.ts +10 -0
  149. package/src/hooks/useConfig.ts +10 -0
  150. package/src/hooks/useIsMounted.ts +13 -0
  151. package/src/hooks/useModal.tsx +10 -0
  152. package/src/hooks/useTailwindBreakpoint.ts +47 -0
  153. package/src/hooks/useTheme.ts +13 -0
  154. package/src/index.ts +234 -0
  155. package/src/lib/assert.ts +9 -0
  156. package/src/lib/codeUtils.ts +177 -0
  157. package/src/lib/debounce.ts +9 -0
  158. package/src/lib/responsiveMappers.ts +69 -0
  159. package/src/lib/responsiveUtils.ts +23 -0
  160. package/src/lib/storybookUtils.tsx +26 -0
  161. package/src/lib/typeUtils.ts +109 -0
  162. package/src/lib/utils.ts +85 -0
  163. package/src/styles/codeSyntax.css +59 -0
  164. package/src/styles/globals.css +51 -0
  165. package/src/types.ts +200 -0
  166. package/src/vite-env.d.ts +6 -0
  167. package/types/utilities.d.ts +1 -1
  168. package/dist/components/AIChat/AIChatContainer.d.ts +0 -26
  169. package/dist/components/AIChat/AIChatMessage.d.ts +0 -19
  170. package/dist/components/AIChat/AIChatMessageComposer.d.ts +0 -22
  171. package/dist/components/AIChat/AIChatMessageList.d.ts +0 -6
  172. package/dist/components/AIChat/AIChatModelSelector.d.ts +0 -14
  173. package/dist/components/AIChat/componentsTypes.d.ts +0 -11
  174. package/dist/components/AIChat/context.d.ts +0 -3
  175. package/dist/components/AIChat/index.d.ts +0 -12
  176. package/dist/components/AIChat/parts/AIChatMessageFilePart.d.ts +0 -7
  177. package/dist/components/AIChat/parts/AIChatMessageReasoningPart.d.ts +0 -5
  178. package/dist/components/AIChat/parts/AIChatMessageSourcePart.d.ts +0 -9
  179. package/dist/components/AIChat/parts/AIChatMessageTextPart.d.ts +0 -5
  180. package/dist/components/AIChat/parts/AIChatMessageToolInvocationPart.d.ts +0 -6
  181. package/dist/components/AIChat/parts/AIChatMessageToolPart.d.ts +0 -33
  182. package/dist/components/AIChat/parts/AIChatMessageToolResultPart.d.ts +0 -5
  183. package/dist/components/AIChat/toolCallApproval.d.ts +0 -15
  184. package/dist/components/AIChat/types.d.ts +0 -79
  185. package/dist/components/ActionBar/index.d.ts +0 -36
  186. package/dist/components/Alert/index.d.ts +0 -18
  187. package/dist/components/Alert/types.d.ts +0 -4
  188. package/dist/components/AppLayout/context.d.ts +0 -16
  189. package/dist/components/AppLayout/index.d.ts +0 -131
  190. package/dist/components/AppLayout/provider.d.ts +0 -8
  191. package/dist/components/AppLayout/useAppLayoutKeys.d.ts +0 -1
  192. package/dist/components/Badge/index.d.ts +0 -21
  193. package/dist/components/Button/index.d.ts +0 -22
  194. package/dist/components/Card/index.d.ts +0 -47
  195. package/dist/components/CodeEditorLayout/index.d.ts +0 -101
  196. package/dist/components/CodeHighlight/Pre.d.ts +0 -8
  197. package/dist/components/CodePlayground/index.d.ts +0 -102
  198. package/dist/components/CodeSnippet/index.d.ts +0 -49
  199. package/dist/components/Combobox/index.d.ts +0 -35
  200. package/dist/components/Command/index.d.ts +0 -80
  201. package/dist/components/Container/index.d.ts +0 -9
  202. package/dist/components/ContextDropdown/index.d.ts +0 -7
  203. package/dist/components/Dialog/index.d.ts +0 -21
  204. package/dist/components/DragNDrop/DragNDropArea.d.ts +0 -8
  205. package/dist/components/DragNDrop/DragOverlay.d.ts +0 -1
  206. package/dist/components/DragNDrop/Draggable.d.ts +0 -29
  207. package/dist/components/DragNDrop/Droppable.d.ts +0 -28
  208. package/dist/components/Dropdown/index.d.ts +0 -27
  209. package/dist/components/ExternalPill/index.d.ts +0 -12
  210. package/dist/components/Facepile/index.d.ts +0 -16
  211. package/dist/components/GradientCircle/index.d.ts +0 -10
  212. package/dist/components/Grid/index.d.ts +0 -80
  213. package/dist/components/Heading/index.d.ts +0 -12
  214. package/dist/components/HighlightedText/index.d.ts +0 -19
  215. package/dist/components/Icon/customIcons/createCustomLucideIcon.d.ts +0 -3
  216. package/dist/components/Icon/customIcons/gems.d.ts +0 -2
  217. package/dist/components/Icon/customIcons/go.d.ts +0 -2
  218. package/dist/components/Icon/customIcons/index.d.ts +0 -10
  219. package/dist/components/Icon/customIcons/maven.d.ts +0 -2
  220. package/dist/components/Icon/customIcons/npm.d.ts +0 -2
  221. package/dist/components/Icon/customIcons/nuget.d.ts +0 -2
  222. package/dist/components/Icon/customIcons/packagist.d.ts +0 -2
  223. package/dist/components/Icon/customIcons/pypi.d.ts +0 -2
  224. package/dist/components/Icon/index.d.ts +0 -10
  225. package/dist/components/Icon/isIconName.d.ts +0 -2
  226. package/dist/components/Icon/names.d.ts +0 -6
  227. package/dist/components/IconButton/index.d.ts +0 -14
  228. package/dist/components/Input/index.d.ts +0 -8
  229. package/dist/components/KeyHint/index.d.ts +0 -16
  230. package/dist/components/LanguageIndicator/index.d.ts +0 -7
  231. package/dist/components/Link/index.d.ts +0 -15
  232. package/dist/components/LoggedInUserMenu/index.d.ts +0 -17
  233. package/dist/components/Logo/Animated.d.ts +0 -7
  234. package/dist/components/Logo/index.d.ts +0 -7
  235. package/dist/components/Logo/svgs/index.d.ts +0 -6
  236. package/dist/components/Modal/index.d.ts +0 -8
  237. package/dist/components/PageHeader/index.d.ts +0 -45
  238. package/dist/components/Popover/index.d.ts +0 -8
  239. package/dist/components/PromptInput/index.d.ts +0 -55
  240. package/dist/components/PullRequestLink/index.d.ts +0 -10
  241. package/dist/components/ResizablePanel/index.d.ts +0 -26
  242. package/dist/components/Score/index.d.ts +0 -37
  243. package/dist/components/ScrollArea/index.d.ts +0 -5
  244. package/dist/components/SegmentedButton/index.d.ts +0 -23
  245. package/dist/components/Select/index.d.ts +0 -13
  246. package/dist/components/Separator/index.d.ts +0 -6
  247. package/dist/components/Skeleton/index.d.ts +0 -27
  248. package/dist/components/Stack/index.d.ts +0 -33
  249. package/dist/components/Subnav/index.d.ts +0 -12
  250. package/dist/components/Switch/index.d.ts +0 -4
  251. package/dist/components/Table/context/context.d.ts +0 -8
  252. package/dist/components/Table/context/tableProvider.d.ts +0 -6
  253. package/dist/components/Table/index.d.ts +0 -94
  254. package/dist/components/Tabs/index.d.ts +0 -21
  255. package/dist/components/TargetLanguageIcon/index.d.ts +0 -7
  256. package/dist/components/Text/index.d.ts +0 -19
  257. package/dist/components/ThemeSwitcher/index.d.ts +0 -6
  258. package/dist/components/Timeline/index.d.ts +0 -49
  259. package/dist/components/Tooltip/index.d.ts +0 -9
  260. package/dist/components/UserAvatar/index.d.ts +0 -9
  261. package/dist/components/UserAvatar/sizeMap.d.ts +0 -3
  262. package/dist/components/Wizard/index.d.ts +0 -19
  263. package/dist/components/Wizard/types.d.ts +0 -15
  264. package/dist/components/WorkspaceSelector/CreateOrg.d.ts +0 -6
  265. package/dist/components/WorkspaceSelector/CreateWorkspace.d.ts +0 -17
  266. package/dist/components/WorkspaceSelector/OrgList.d.ts +0 -12
  267. package/dist/components/WorkspaceSelector/OrgSelector.d.ts +0 -13
  268. package/dist/components/WorkspaceSelector/RecentWorkspaces.d.ts +0 -11
  269. package/dist/components/WorkspaceSelector/ScrollingList.d.ts +0 -21
  270. package/dist/components/WorkspaceSelector/SearchBox.d.ts +0 -9
  271. package/dist/components/WorkspaceSelector/WorkspaceItem.d.ts +0 -9
  272. package/dist/components/WorkspaceSelector/WorkspaceList.d.ts +0 -11
  273. package/dist/components/WorkspaceSelector/index.d.ts +0 -36
  274. package/dist/components/__beta__/CLIWizard/index.d.ts +0 -19
  275. package/dist/components/__beta__/CLIWizard/terminal-command.d.ts +0 -19
  276. package/dist/components/__beta__/CLIWizard/terminal.d.ts +0 -26
  277. package/dist/context/ConfigContext.d.ts +0 -18
  278. package/dist/context/ModalContext.d.ts +0 -22
  279. package/dist/context/theme.d.ts +0 -1
  280. package/dist/createCustomLucideIcon-CatlpFc0.mjs +0 -19
  281. package/dist/createCustomLucideIcon-CatlpFc0.mjs.map +0 -1
  282. package/dist/gems-DQ7pOLLr.mjs +0 -24
  283. package/dist/gems-DQ7pOLLr.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-DsW1bFpz.mjs.map +0 -1
  287. package/dist/hooks/useAppLayout.d.ts +0 -1
  288. package/dist/hooks/useConfig.d.ts +0 -2
  289. package/dist/hooks/useIsMounted.d.ts +0 -1
  290. package/dist/hooks/useModal.d.ts +0 -11
  291. package/dist/hooks/useTailwindBreakpoint.d.ts +0 -3
  292. package/dist/hooks/useTheme.d.ts +0 -6
  293. package/dist/index-C9bJtuJ5.mjs +0 -16347
  294. package/dist/index-C9bJtuJ5.mjs.map +0 -1
  295. package/dist/index.d.ts +0 -80
  296. package/dist/lib/assert.d.ts +0 -2
  297. package/dist/lib/codeUtils.d.ts +0 -36
  298. package/dist/lib/debounce.d.ts +0 -1
  299. package/dist/lib/responsiveMappers.d.ts +0 -10
  300. package/dist/lib/responsiveUtils.d.ts +0 -3
  301. package/dist/lib/storybookUtils.d.ts +0 -5
  302. package/dist/lib/typeUtils.d.ts +0 -24
  303. package/dist/lib/utils.d.ts +0 -24
  304. package/dist/maven-Dub5liK1.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 -125
  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-BYcG5_q9.mjs +0 -17
  312. package/dist/npm-BYcG5_q9.mjs.map +0 -1
  313. package/dist/nuget-CV5HU1JR.mjs +0 -11
  314. package/dist/nuget-CV5HU1JR.mjs.map +0 -1
  315. package/dist/nuget-D86y5HDl.mjs.map +0 -1
  316. package/dist/packagist-BFSSrw4p.mjs +0 -118
  317. package/dist/packagist-BFSSrw4p.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-2SUX-2OR.mjs.map +0 -1
  321. package/dist/pypi-DLh6kIJe.mjs +0 -11
  322. package/dist/pypi-DLh6kIJe.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 -85
@@ -0,0 +1,315 @@
1
+ import { cn } from '../../lib/utils'
2
+ import { motion, Transition, AnimatePresence } from 'motion/react'
3
+ import {
4
+ useState,
5
+ useRef,
6
+ useEffect,
7
+ useCallback,
8
+ useLayoutEffect,
9
+ memo,
10
+ forwardRef,
11
+ } from 'react'
12
+
13
+ export interface SubnavItem {
14
+ label: string
15
+ href: string
16
+ active?: boolean
17
+
18
+ [key: string]: unknown
19
+ }
20
+
21
+ export interface SubnavProps {
22
+ items: SubnavItem[]
23
+ renderItem: (item: SubnavItem) => React.ReactNode
24
+ className?: string
25
+ }
26
+
27
+ const POSITION_TRANSITION: Transition = {
28
+ type: 'spring',
29
+ stiffness: 300,
30
+ damping: 30,
31
+ mass: 0.8,
32
+ duration: 0.35,
33
+ }
34
+
35
+ const SCALE_TRANSITION: Transition = {
36
+ type: 'spring',
37
+ stiffness: 400,
38
+ damping: 40,
39
+ mass: 0.7,
40
+ duration: 0.25,
41
+ }
42
+
43
+ const FADE_TRANSITION: Transition = {
44
+ type: 'tween',
45
+ ease: [0.215, 0.61, 0.355, 1],
46
+ duration: 0.2,
47
+ }
48
+
49
+ const useDebounce = (callback: () => void, delay: number) => {
50
+ const timeoutRef = useRef<ReturnType<typeof setTimeout>>()
51
+
52
+ useEffect(() => {
53
+ return () => {
54
+ if (timeoutRef.current) {
55
+ clearTimeout(timeoutRef.current)
56
+ }
57
+ }
58
+ }, [])
59
+
60
+ return useCallback(() => {
61
+ if (timeoutRef.current) {
62
+ clearTimeout(timeoutRef.current)
63
+ }
64
+ timeoutRef.current = setTimeout(callback, delay)
65
+ }, [callback, delay])
66
+ }
67
+
68
+ export function Subnav({ items, renderItem, className }: SubnavProps) {
69
+ const [activeItem, setActiveItem] = useState<string | null>(
70
+ items.find((item) => item.active)?.href ?? null
71
+ )
72
+ const [hoveredItem, setHoveredItem] = useState<string | null>(null)
73
+ const [baseWidth, setBaseWidth] = useState<number>(0)
74
+ const [activeIndicatorProps, setActiveIndicatorProps] = useState<{
75
+ scaleX: number
76
+ left: number
77
+ } | null>(null)
78
+ const [indicatorProps, setIndicatorProps] = useState<{
79
+ scaleX: number
80
+ left: number
81
+ } | null>(null)
82
+
83
+ const itemRefs = useRef<Map<string, HTMLDivElement>>(new Map())
84
+ const previousHoveredItem = useRef<string | null>(null)
85
+ const isContainerHovered = useRef(false)
86
+ const hasInitialized = useRef(false)
87
+
88
+ useLayoutEffect(() => {
89
+ const newActiveItem: string =
90
+ items.find((item) => item.active)?.href ?? items[0]?.href
91
+ setActiveItem(newActiveItem)
92
+ }, [items])
93
+
94
+ useLayoutEffect(() => {
95
+ if (!hasInitialized.current && activeItem) {
96
+ const element = itemRefs.current.get(activeItem)
97
+ if (element) {
98
+ setBaseWidth(element.offsetWidth)
99
+ hasInitialized.current = true
100
+ }
101
+ }
102
+ }, [activeItem])
103
+
104
+ useLayoutEffect(() => {
105
+ if (!activeItem || !baseWidth) {
106
+ setActiveIndicatorProps(null)
107
+ return
108
+ }
109
+
110
+ const itemElement = itemRefs.current.get(activeItem)
111
+ if (!itemElement) {
112
+ setActiveIndicatorProps(null)
113
+ return
114
+ }
115
+
116
+ const itemWidth = itemElement.offsetWidth
117
+ const itemLeft = itemElement.offsetLeft
118
+ const centerOffset = (itemWidth - baseWidth) / 2
119
+
120
+ setActiveIndicatorProps({
121
+ scaleX: itemWidth / baseWidth,
122
+ left: itemLeft + centerOffset,
123
+ })
124
+
125
+ /**
126
+ * Subnav can be contextual to a page and therefore items can change.
127
+ * items needs to be in the dependancy array even though it's not used in the effect
128
+ * so the position of the indicator is accurate when the menu items change between pages
129
+ */
130
+ }, [activeItem, baseWidth, items])
131
+
132
+ useLayoutEffect(() => {
133
+ if (!hoveredItem || !baseWidth) {
134
+ setIndicatorProps(null)
135
+ return
136
+ }
137
+
138
+ const itemElement = itemRefs.current.get(hoveredItem)
139
+ if (!itemElement) {
140
+ setIndicatorProps(null)
141
+ return
142
+ }
143
+
144
+ const itemWidth = itemElement.offsetWidth
145
+ const itemLeft = itemElement.offsetLeft
146
+ const centerOffset = (itemWidth - baseWidth) / 2
147
+
148
+ setIndicatorProps({
149
+ scaleX: itemWidth / baseWidth,
150
+ left: itemLeft + centerOffset,
151
+ })
152
+
153
+ /**
154
+ * Subnav can be contextual to a page and therefore items can change.
155
+ * items needs to be in the dependancy array even though it's not used in the effect
156
+ * so the position of the indicator is accurate when the menu items change between pages
157
+ */
158
+ }, [hoveredItem, baseWidth, items])
159
+
160
+ const debouncedResize = useDebounce(() => {
161
+ if (activeItem) {
162
+ const element = itemRefs.current.get(activeItem)
163
+ if (element) {
164
+ setBaseWidth(element.offsetWidth)
165
+ }
166
+ }
167
+ }, 100)
168
+
169
+ useEffect(() => {
170
+ window.addEventListener('resize', debouncedResize)
171
+ return () => window.removeEventListener('resize', debouncedResize)
172
+ }, [debouncedResize])
173
+
174
+ const handleItemClick = useCallback((href: string) => {
175
+ setActiveItem(href)
176
+ }, [])
177
+
178
+ const handleContainerMouseEnter = useCallback(() => {
179
+ isContainerHovered.current = true
180
+ }, [])
181
+
182
+ const handleContainerMouseLeave = useCallback(() => {
183
+ isContainerHovered.current = false
184
+ previousHoveredItem.current = null
185
+ setHoveredItem(null)
186
+ }, [])
187
+
188
+ const handleItemHover = useCallback(
189
+ (href: string | null) => {
190
+ if (href !== null) {
191
+ previousHoveredItem.current = hoveredItem
192
+ }
193
+ setHoveredItem(href)
194
+ },
195
+ [hoveredItem]
196
+ )
197
+
198
+ const shouldSlide =
199
+ previousHoveredItem.current !== null && isContainerHovered.current
200
+
201
+ const getItemHandlers = useCallback(
202
+ (href: string) => {
203
+ return {
204
+ onClick: () => handleItemClick(href),
205
+ onMouseEnter: () => handleItemHover(href),
206
+ onMouseLeave: () => handleItemHover(null),
207
+ }
208
+ },
209
+ [handleItemClick, handleItemHover]
210
+ )
211
+
212
+ return (
213
+ <div
214
+ className={cn('relative flex items-center', className)}
215
+ onMouseEnter={handleContainerMouseEnter}
216
+ onMouseLeave={handleContainerMouseLeave}
217
+ >
218
+ <AnimatePresence>
219
+ {indicatorProps && baseWidth > 0 && (
220
+ <motion.div
221
+ className="bg-surface-secondary-default absolute inset-y-0 my-auto h-[calc(100%-10px)] rounded-xs"
222
+ style={{
223
+ width: baseWidth,
224
+ transformOrigin: '50% 50% 0px',
225
+ }}
226
+ initial={shouldSlide ? false : { opacity: 0 }}
227
+ animate={{
228
+ translateX: indicatorProps.left,
229
+ scaleX: indicatorProps.scaleX,
230
+ opacity: 1,
231
+ }}
232
+ exit={{ opacity: 0 }}
233
+ transition={{
234
+ opacity: FADE_TRANSITION,
235
+ translateX: shouldSlide ? POSITION_TRANSITION : { duration: 0 },
236
+ scaleX: shouldSlide ? SCALE_TRANSITION : { duration: 0 },
237
+ }}
238
+ layoutDependency={indicatorProps}
239
+ />
240
+ )}
241
+ </AnimatePresence>
242
+
243
+ {items.map((item) => (
244
+ <SubnavItem
245
+ key={item.href}
246
+ item={item}
247
+ isActive={activeItem === item.href}
248
+ isHovered={hoveredItem === item.href}
249
+ handlers={getItemHandlers(item.href)}
250
+ ref={(el) => {
251
+ if (el) {
252
+ itemRefs.current.set(item.href, el)
253
+ } else {
254
+ itemRefs.current.delete(item.href)
255
+ }
256
+ }}
257
+ renderItem={renderItem}
258
+ />
259
+ ))}
260
+
261
+ {activeIndicatorProps && baseWidth > 0 && (
262
+ <motion.div
263
+ className="bg-surface-primary-inverse absolute bottom-0 h-[2px]"
264
+ style={{
265
+ width: baseWidth,
266
+ transformOrigin: '50% 50% 0px',
267
+ }}
268
+ initial={false}
269
+ animate={{
270
+ translateX: activeIndicatorProps.left,
271
+ scaleX: activeIndicatorProps.scaleX,
272
+ }}
273
+ transition={{
274
+ translateX: POSITION_TRANSITION,
275
+ scaleX: SCALE_TRANSITION,
276
+ }}
277
+ layoutDependency={activeIndicatorProps}
278
+ />
279
+ )}
280
+ </div>
281
+ )
282
+ }
283
+
284
+ const SubnavItem = memo(
285
+ forwardRef<
286
+ HTMLDivElement,
287
+ {
288
+ item: SubnavItem
289
+ isActive: boolean
290
+ isHovered: boolean
291
+ handlers: {
292
+ onClick: () => void
293
+ onMouseEnter: () => void
294
+ onMouseLeave: () => void
295
+ }
296
+ renderItem: (item: SubnavItem & { hovered: boolean }) => React.ReactNode
297
+ }
298
+ >(function SubnavItem(
299
+ { item, isActive, isHovered, handlers, renderItem },
300
+ ref
301
+ ) {
302
+ return (
303
+ <motion.div
304
+ ref={ref}
305
+ className={cn(
306
+ 'text-default relative z-10 cursor-pointer select-none',
307
+ isActive && 'text-highlight font-semibold'
308
+ )}
309
+ {...handlers}
310
+ >
311
+ {renderItem({ ...item, hovered: isHovered })}
312
+ </motion.div>
313
+ )
314
+ })
315
+ )
@@ -0,0 +1,29 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as SwitchPrimitives from '@radix-ui/react-switch'
5
+
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const Switch = React.forwardRef<
9
+ React.ElementRef<typeof SwitchPrimitives.Root>,
10
+ React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
11
+ >(({ className, ...props }, ref) => (
12
+ <SwitchPrimitives.Root
13
+ className={cn(
14
+ 'focus-visible:ring-ring focus-visible:ring-offset-background peer data-[state=unchecked]:bg-surface-tertiary-default inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-emerald-700',
15
+ className
16
+ )}
17
+ {...props}
18
+ ref={ref}
19
+ >
20
+ <SwitchPrimitives.Thumb
21
+ className={cn(
22
+ 'data-[state=unchecked]:bg-surface-tertiary-inverse pointer-events-none block h-5 w-5 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=checked]:bg-white data-[state=unchecked]:translate-x-0'
23
+ )}
24
+ />
25
+ </SwitchPrimitives.Root>
26
+ ))
27
+ Switch.displayName = SwitchPrimitives.Root.displayName
28
+
29
+ export { Switch, type SwitchPrimitives as SwitchProps }
@@ -0,0 +1,19 @@
1
+ import { createContext, useContext } from 'react'
2
+
3
+ type TableContextValue = {
4
+ depth: number
5
+ expandedRowKeys: Set<string | number>
6
+ toggleExpanded: (rowKey: string | number) => void
7
+ }
8
+
9
+ export const TableContext = createContext<TableContextValue>({
10
+ depth: 0,
11
+ expandedRowKeys: new Set(),
12
+ toggleExpanded: () => {},
13
+ })
14
+
15
+ export function useTable() {
16
+ const context = useContext(TableContext)
17
+
18
+ return context
19
+ }
@@ -0,0 +1,39 @@
1
+ import { useCallback, useState } from 'react'
2
+ import { TableContext } from './context'
3
+
4
+ export interface TableProviderProps {
5
+ children: React.ReactNode
6
+ depth: number
7
+ expandedRowKeys?: Set<string | number>
8
+ }
9
+
10
+ export function TableProvider({
11
+ children,
12
+ depth,
13
+ expandedRowKeys: defaultExpanded,
14
+ }: TableProviderProps) {
15
+ const [expandedRowKeys, setExpandedRowKeys] = useState<Set<string | number>>(
16
+ defaultExpanded ?? new Set()
17
+ )
18
+
19
+ const toggleExpanded = useCallback(
20
+ (rowKey: string | number) => {
21
+ setExpandedRowKeys((prev) => {
22
+ const newSet = new Set(prev)
23
+ if (newSet.has(rowKey)) {
24
+ newSet.delete(rowKey)
25
+ } else {
26
+ newSet.add(rowKey)
27
+ }
28
+ return newSet
29
+ })
30
+ },
31
+ [expandedRowKeys, setExpandedRowKeys]
32
+ )
33
+
34
+ return (
35
+ <TableContext.Provider value={{ depth, expandedRowKeys, toggleExpanded }}>
36
+ {children}
37
+ </TableContext.Provider>
38
+ )
39
+ }