@stack-spot/ai-chat-widget 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/dist/StackspotAIWidget.d.ts +13 -0
  2. package/dist/StackspotAIWidget.d.ts.map +1 -0
  3. package/dist/StackspotAIWidget.js +32 -0
  4. package/dist/StackspotAIWidget.js.map +1 -0
  5. package/dist/chat-interceptors/quick-commands.d.ts +4 -0
  6. package/dist/chat-interceptors/quick-commands.d.ts.map +1 -0
  7. package/dist/chat-interceptors/quick-commands.js +11 -0
  8. package/dist/chat-interceptors/quick-commands.js.map +1 -0
  9. package/dist/chat-interceptors/send-message.d.ts +4 -0
  10. package/dist/chat-interceptors/send-message.d.ts.map +1 -0
  11. package/dist/chat-interceptors/send-message.js +36 -0
  12. package/dist/chat-interceptors/send-message.js.map +1 -0
  13. package/dist/components/Accordion.d.ts +10 -0
  14. package/dist/components/Accordion.d.ts.map +1 -0
  15. package/dist/components/Accordion.js +46 -0
  16. package/dist/components/Accordion.js.map +1 -0
  17. package/dist/components/AdaptiveTextArea.d.ts +10 -0
  18. package/dist/components/AdaptiveTextArea.d.ts.map +1 -0
  19. package/dist/components/AdaptiveTextArea.js +28 -0
  20. package/dist/components/AdaptiveTextArea.js.map +1 -0
  21. package/dist/components/Code.d.ts +19 -0
  22. package/dist/components/Code.d.ts.map +1 -0
  23. package/dist/components/Code.js +112 -0
  24. package/dist/components/Code.js.map +1 -0
  25. package/dist/components/Editor.d.ts +9 -0
  26. package/dist/components/Editor.d.ts.map +1 -0
  27. package/dist/components/Editor.js +2 -0
  28. package/dist/components/Editor.js.map +1 -0
  29. package/dist/components/FadingOverflow.d.ts +12 -0
  30. package/dist/components/FadingOverflow.d.ts.map +1 -0
  31. package/dist/components/FadingOverflow.js +216 -0
  32. package/dist/components/FadingOverflow.js.map +1 -0
  33. package/dist/components/FallbackBoundary/ErrorBoundary.d.ts +30 -0
  34. package/dist/components/FallbackBoundary/ErrorBoundary.d.ts.map +1 -0
  35. package/dist/components/FallbackBoundary/ErrorBoundary.js +38 -0
  36. package/dist/components/FallbackBoundary/ErrorBoundary.js.map +1 -0
  37. package/dist/components/FallbackBoundary/Loading.d.ts +2 -0
  38. package/dist/components/FallbackBoundary/Loading.d.ts.map +1 -0
  39. package/dist/components/FallbackBoundary/Loading.js +12 -0
  40. package/dist/components/FallbackBoundary/Loading.js.map +1 -0
  41. package/dist/components/FallbackBoundary/index.d.ts +6 -0
  42. package/dist/components/FallbackBoundary/index.d.ts.map +1 -0
  43. package/dist/components/FallbackBoundary/index.js +9 -0
  44. package/dist/components/FallbackBoundary/index.js.map +1 -0
  45. package/dist/components/HistoryList.d.ts +13 -0
  46. package/dist/components/HistoryList.d.ts.map +1 -0
  47. package/dist/components/HistoryList.js +4 -0
  48. package/dist/components/HistoryList.js.map +1 -0
  49. package/dist/components/IconInput.d.ts +7 -0
  50. package/dist/components/IconInput.d.ts.map +1 -0
  51. package/dist/components/IconInput.js +58 -0
  52. package/dist/components/IconInput.js.map +1 -0
  53. package/dist/components/Markdown.d.ts +9 -0
  54. package/dist/components/Markdown.d.ts.map +1 -0
  55. package/dist/components/Markdown.js +17 -0
  56. package/dist/components/Markdown.js.map +1 -0
  57. package/dist/components/OverlayMenu.d.ts +9 -0
  58. package/dist/components/OverlayMenu.d.ts.map +1 -0
  59. package/dist/components/OverlayMenu.js +2 -0
  60. package/dist/components/OverlayMenu.js.map +1 -0
  61. package/dist/components/ProgressBar.d.ts +11 -0
  62. package/dist/components/ProgressBar.d.ts.map +1 -0
  63. package/dist/components/ProgressBar.js +126 -0
  64. package/dist/components/ProgressBar.js.map +1 -0
  65. package/dist/components/QuickStartButton.d.ts +8 -0
  66. package/dist/components/QuickStartButton.d.ts.map +1 -0
  67. package/dist/components/QuickStartButton.js +40 -0
  68. package/dist/components/QuickStartButton.js.map +1 -0
  69. package/dist/components/RightPanelForm.d.ts +5 -0
  70. package/dist/components/RightPanelForm.d.ts.map +1 -0
  71. package/dist/components/RightPanelForm.js +45 -0
  72. package/dist/components/RightPanelForm.js.map +1 -0
  73. package/dist/components/RightPanelTabs.d.ts +10 -0
  74. package/dist/components/RightPanelTabs.d.ts.map +1 -0
  75. package/dist/components/RightPanelTabs.js +20 -0
  76. package/dist/components/RightPanelTabs.js.map +1 -0
  77. package/dist/components/TabManager.d.ts +34 -0
  78. package/dist/components/TabManager.d.ts.map +1 -0
  79. package/dist/components/TabManager.js +158 -0
  80. package/dist/components/TabManager.js.map +1 -0
  81. package/dist/components/Tooltip/Tooltip.d.ts +11 -0
  82. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -0
  83. package/dist/components/Tooltip/Tooltip.js +9 -0
  84. package/dist/components/Tooltip/Tooltip.js.map +1 -0
  85. package/dist/components/Tooltip/TooltipAPI.d.ts +10 -0
  86. package/dist/components/Tooltip/TooltipAPI.d.ts.map +1 -0
  87. package/dist/components/Tooltip/TooltipAPI.js +48 -0
  88. package/dist/components/Tooltip/TooltipAPI.js.map +1 -0
  89. package/dist/components/Tooltip/context.d.ts +5 -0
  90. package/dist/components/Tooltip/context.d.ts.map +1 -0
  91. package/dist/components/Tooltip/context.js +18 -0
  92. package/dist/components/Tooltip/context.js.map +1 -0
  93. package/dist/components/Tooltip/index.d.ts +3 -0
  94. package/dist/components/Tooltip/index.d.ts.map +1 -0
  95. package/dist/components/Tooltip/index.js +3 -0
  96. package/dist/components/Tooltip/index.js.map +1 -0
  97. package/dist/components/Tooltip/style.d.ts +4 -0
  98. package/dist/components/Tooltip/style.d.ts.map +1 -0
  99. package/dist/components/Tooltip/style.js +23 -0
  100. package/dist/components/Tooltip/style.js.map +1 -0
  101. package/dist/components/Tooltip/types.d.ts +8 -0
  102. package/dist/components/Tooltip/types.d.ts.map +1 -0
  103. package/dist/components/Tooltip/types.js +2 -0
  104. package/dist/components/Tooltip/types.js.map +1 -0
  105. package/dist/components/form/DescribedCheckboxGroup.d.ts +3 -0
  106. package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -0
  107. package/dist/components/form/DescribedCheckboxGroup.js +23 -0
  108. package/dist/components/form/DescribedCheckboxGroup.js.map +1 -0
  109. package/dist/components/form/DescribedRadioGroup.d.ts +3 -0
  110. package/dist/components/form/DescribedRadioGroup.d.ts.map +1 -0
  111. package/dist/components/form/DescribedRadioGroup.js +18 -0
  112. package/dist/components/form/DescribedRadioGroup.js.map +1 -0
  113. package/dist/components/form/styled.d.ts +2 -0
  114. package/dist/components/form/styled.d.ts.map +1 -0
  115. package/dist/components/form/styled.js +41 -0
  116. package/dist/components/form/styled.js.map +1 -0
  117. package/dist/components/form/types.d.ts +19 -0
  118. package/dist/components/form/types.d.ts.map +1 -0
  119. package/dist/components/form/types.js +2 -0
  120. package/dist/components/form/types.js.map +1 -0
  121. package/dist/context/AIWidgetProvider.d.ts +4 -0
  122. package/dist/context/AIWidgetProvider.d.ts.map +1 -0
  123. package/dist/context/AIWidgetProvider.js +4 -0
  124. package/dist/context/AIWidgetProvider.js.map +1 -0
  125. package/dist/context/hooks.d.ts +18 -0
  126. package/dist/context/hooks.d.ts.map +1 -0
  127. package/dist/context/hooks.js +82 -0
  128. package/dist/context/hooks.js.map +1 -0
  129. package/dist/features.d.ts +13 -0
  130. package/dist/features.d.ts.map +1 -0
  131. package/dist/features.js +6 -0
  132. package/dist/features.js.map +1 -0
  133. package/dist/hooks/chat-scroll.d.ts +7 -0
  134. package/dist/hooks/chat-scroll.d.ts.map +1 -0
  135. package/dist/hooks/chat-scroll.js +15 -0
  136. package/dist/hooks/chat-scroll.js.map +1 -0
  137. package/dist/index.d.ts +9 -0
  138. package/dist/index.d.ts.map +1 -0
  139. package/dist/index.js +9 -0
  140. package/dist/index.js.map +1 -0
  141. package/dist/layout.css +119 -0
  142. package/dist/right-panel/DefaultPanel.d.ts +9 -0
  143. package/dist/right-panel/DefaultPanel.d.ts.map +1 -0
  144. package/dist/right-panel/DefaultPanel.js +46 -0
  145. package/dist/right-panel/DefaultPanel.js.map +1 -0
  146. package/dist/right-panel/RightPanel.d.ts +2 -0
  147. package/dist/right-panel/RightPanel.d.ts.map +1 -0
  148. package/dist/right-panel/RightPanel.js +6 -0
  149. package/dist/right-panel/RightPanel.js.map +1 -0
  150. package/dist/right-panel/RightPanelProvider.d.ts +13 -0
  151. package/dist/right-panel/RightPanelProvider.d.ts.map +1 -0
  152. package/dist/right-panel/RightPanelProvider.js +10 -0
  153. package/dist/right-panel/RightPanelProvider.js.map +1 -0
  154. package/dist/right-panel/hooks.d.ts +13 -0
  155. package/dist/right-panel/hooks.d.ts.map +1 -0
  156. package/dist/right-panel/hooks.js +39 -0
  157. package/dist/right-panel/hooks.js.map +1 -0
  158. package/dist/state/ChatEntry.d.ts +48 -0
  159. package/dist/state/ChatEntry.d.ts.map +1 -0
  160. package/dist/state/ChatEntry.js +55 -0
  161. package/dist/state/ChatEntry.js.map +1 -0
  162. package/dist/state/ChatState.d.ts +46 -0
  163. package/dist/state/ChatState.d.ts.map +1 -0
  164. package/dist/state/ChatState.js +53 -0
  165. package/dist/state/ChatState.js.map +1 -0
  166. package/dist/state/ChatTabsController.d.ts +17 -0
  167. package/dist/state/ChatTabsController.d.ts.map +1 -0
  168. package/dist/state/ChatTabsController.js +47 -0
  169. package/dist/state/ChatTabsController.js.map +1 -0
  170. package/dist/state/ObservableState.d.ts +10 -0
  171. package/dist/state/ObservableState.d.ts.map +1 -0
  172. package/dist/state/ObservableState.js +25 -0
  173. package/dist/state/ObservableState.js.map +1 -0
  174. package/dist/state/WidgetState.d.ts +19 -0
  175. package/dist/state/WidgetState.d.ts.map +1 -0
  176. package/dist/state/WidgetState.js +29 -0
  177. package/dist/state/WidgetState.js.map +1 -0
  178. package/dist/types.d.ts +17 -0
  179. package/dist/types.d.ts.map +1 -0
  180. package/dist/types.js +2 -0
  181. package/dist/types.js.map +1 -0
  182. package/dist/utils/chat.d.ts +6 -0
  183. package/dist/utils/chat.d.ts.map +1 -0
  184. package/dist/utils/chat.js +26 -0
  185. package/dist/utils/chat.js.map +1 -0
  186. package/dist/utils/date.d.ts +6 -0
  187. package/dist/utils/date.d.ts.map +1 -0
  188. package/dist/utils/date.js +38 -0
  189. package/dist/utils/date.js.map +1 -0
  190. package/dist/views/Agents.d.ts +2 -0
  191. package/dist/views/Agents.d.ts.map +1 -0
  192. package/dist/views/Agents.js +2 -0
  193. package/dist/views/Agents.js.map +1 -0
  194. package/dist/views/Chat/AgentInfo.d.ts +6 -0
  195. package/dist/views/Chat/AgentInfo.d.ts.map +1 -0
  196. package/dist/views/Chat/AgentInfo.js +7 -0
  197. package/dist/views/Chat/AgentInfo.js.map +1 -0
  198. package/dist/views/Chat/ChatMessage.d.ts +6 -0
  199. package/dist/views/Chat/ChatMessage.d.ts.map +1 -0
  200. package/dist/views/Chat/ChatMessage.js +61 -0
  201. package/dist/views/Chat/ChatMessage.js.map +1 -0
  202. package/dist/views/Chat/ChatMessages.d.ts +7 -0
  203. package/dist/views/Chat/ChatMessages.d.ts.map +1 -0
  204. package/dist/views/Chat/ChatMessages.js +12 -0
  205. package/dist/views/Chat/ChatMessages.js.map +1 -0
  206. package/dist/views/Chat/index.d.ts +6 -0
  207. package/dist/views/Chat/index.d.ts.map +1 -0
  208. package/dist/views/Chat/index.js +8 -0
  209. package/dist/views/Chat/index.js.map +1 -0
  210. package/dist/views/Chat/styled.d.ts +2 -0
  211. package/dist/views/Chat/styled.d.ts.map +1 -0
  212. package/dist/views/Chat/styled.js +116 -0
  213. package/dist/views/Chat/styled.js.map +1 -0
  214. package/dist/views/ChatTabSelection.d.ts +8 -0
  215. package/dist/views/ChatTabSelection.d.ts.map +1 -0
  216. package/dist/views/ChatTabSelection.js +45 -0
  217. package/dist/views/ChatTabSelection.js.map +1 -0
  218. package/dist/views/Editor.d.ts +2 -0
  219. package/dist/views/Editor.d.ts.map +1 -0
  220. package/dist/views/Editor.js +2 -0
  221. package/dist/views/Editor.js.map +1 -0
  222. package/dist/views/Home.d.ts +6 -0
  223. package/dist/views/Home.d.ts.map +1 -0
  224. package/dist/views/Home.js +68 -0
  225. package/dist/views/Home.js.map +1 -0
  226. package/dist/views/KnowledgeSources.d.ts +2 -0
  227. package/dist/views/KnowledgeSources.d.ts.map +1 -0
  228. package/dist/views/KnowledgeSources.js +82 -0
  229. package/dist/views/KnowledgeSources.js.map +1 -0
  230. package/dist/views/MessageInput/ButtonGroup.d.ts +12 -0
  231. package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -0
  232. package/dist/views/MessageInput/ButtonGroup.js +22 -0
  233. package/dist/views/MessageInput/ButtonGroup.js.map +1 -0
  234. package/dist/views/MessageInput/InfoBar.d.ts +2 -0
  235. package/dist/views/MessageInput/InfoBar.d.ts.map +1 -0
  236. package/dist/views/MessageInput/InfoBar.js +28 -0
  237. package/dist/views/MessageInput/InfoBar.js.map +1 -0
  238. package/dist/views/MessageInput/dictionary.d.ts +2 -0
  239. package/dist/views/MessageInput/dictionary.d.ts.map +1 -0
  240. package/dist/views/MessageInput/dictionary.js +35 -0
  241. package/dist/views/MessageInput/dictionary.js.map +1 -0
  242. package/dist/views/MessageInput/index.d.ts +7 -0
  243. package/dist/views/MessageInput/index.d.ts.map +1 -0
  244. package/dist/views/MessageInput/index.js +43 -0
  245. package/dist/views/MessageInput/index.js.map +1 -0
  246. package/dist/views/MessageInput/styled.d.ts +2 -0
  247. package/dist/views/MessageInput/styled.d.ts.map +1 -0
  248. package/dist/views/MessageInput/styled.js +195 -0
  249. package/dist/views/MessageInput/styled.js.map +1 -0
  250. package/dist/views/MinimizedHeader.d.ts +3 -0
  251. package/dist/views/MinimizedHeader.d.ts.map +1 -0
  252. package/dist/views/MinimizedHeader.js +76 -0
  253. package/dist/views/MinimizedHeader.js.map +1 -0
  254. package/dist/views/Stacks.d.ts +2 -0
  255. package/dist/views/Stacks.d.ts.map +1 -0
  256. package/dist/views/Stacks.js +73 -0
  257. package/dist/views/Stacks.js.map +1 -0
  258. package/dist/views/Workspaces.d.ts +2 -0
  259. package/dist/views/Workspaces.d.ts.map +1 -0
  260. package/dist/views/Workspaces.js +59 -0
  261. package/dist/views/Workspaces.js.map +1 -0
  262. package/package.json +52 -0
  263. package/src/StackspotAIWidget.tsx +65 -0
  264. package/src/chat-interceptors/quick-commands.ts +12 -0
  265. package/src/chat-interceptors/send-message.ts +35 -0
  266. package/src/components/Accordion.tsx +64 -0
  267. package/src/components/AdaptiveTextArea.tsx +34 -0
  268. package/src/components/Code.tsx +201 -0
  269. package/src/components/Editor.tsx +12 -0
  270. package/src/components/FadingOverflow.tsx +234 -0
  271. package/src/components/FallbackBoundary/ErrorBoundary.tsx +48 -0
  272. package/src/components/FallbackBoundary/Loading.tsx +14 -0
  273. package/src/components/FallbackBoundary/index.tsx +15 -0
  274. package/src/components/HistoryList.tsx +16 -0
  275. package/src/components/IconInput.tsx +70 -0
  276. package/src/components/Markdown.tsx +53 -0
  277. package/src/components/OverlayMenu.tsx +10 -0
  278. package/src/components/ProgressBar.tsx +153 -0
  279. package/src/components/QuickStartButton.tsx +51 -0
  280. package/src/components/RightPanelForm.tsx +55 -0
  281. package/src/components/RightPanelTabs.tsx +39 -0
  282. package/src/components/TabManager.tsx +223 -0
  283. package/src/components/Tooltip/Tooltip.tsx +30 -0
  284. package/src/components/Tooltip/TooltipAPI.ts +46 -0
  285. package/src/components/Tooltip/context.tsx +24 -0
  286. package/src/components/Tooltip/index.ts +2 -0
  287. package/src/components/Tooltip/style.tsx +25 -0
  288. package/src/components/Tooltip/types.ts +8 -0
  289. package/src/components/form/DescribedCheckboxGroup.tsx +39 -0
  290. package/src/components/form/DescribedRadioGroup.tsx +33 -0
  291. package/src/components/form/styled.ts +41 -0
  292. package/src/components/form/types.ts +21 -0
  293. package/src/context/AIWidgetProvider.tsx +6 -0
  294. package/src/context/hooks.ts +93 -0
  295. package/src/features.ts +18 -0
  296. package/src/hooks/chat-scroll.ts +14 -0
  297. package/src/index.ts +8 -0
  298. package/src/layout.css +119 -0
  299. package/src/right-panel/DefaultPanel.tsx +67 -0
  300. package/src/right-panel/RightPanel.tsx +6 -0
  301. package/src/right-panel/RightPanelProvider.tsx +20 -0
  302. package/src/right-panel/hooks.tsx +47 -0
  303. package/src/state/ChatEntry.ts +95 -0
  304. package/src/state/ChatState.ts +85 -0
  305. package/src/state/ChatTabsController.ts +55 -0
  306. package/src/state/ObservableState.ts +35 -0
  307. package/src/state/WidgetState.ts +42 -0
  308. package/src/types.ts +20 -0
  309. package/src/utils/chat.ts +30 -0
  310. package/src/utils/date.ts +40 -0
  311. package/src/views/Agents.tsx +1 -0
  312. package/src/views/Chat/AgentInfo.tsx +17 -0
  313. package/src/views/Chat/ChatMessage.tsx +89 -0
  314. package/src/views/Chat/ChatMessages.tsx +16 -0
  315. package/src/views/Chat/index.tsx +11 -0
  316. package/src/views/Chat/styled.ts +116 -0
  317. package/src/views/ChatTabSelection.tsx +65 -0
  318. package/src/views/Editor.tsx +1 -0
  319. package/src/views/Home.tsx +109 -0
  320. package/src/views/KnowledgeSources.tsx +115 -0
  321. package/src/views/MessageInput/ButtonGroup.tsx +84 -0
  322. package/src/views/MessageInput/InfoBar.tsx +69 -0
  323. package/src/views/MessageInput/dictionary.ts +36 -0
  324. package/src/views/MessageInput/index.tsx +79 -0
  325. package/src/views/MessageInput/styled.ts +196 -0
  326. package/src/views/MinimizedHeader.tsx +94 -0
  327. package/src/views/Stacks.tsx +104 -0
  328. package/src/views/Workspaces.tsx +88 -0
  329. package/tsconfig.json +22 -0
@@ -0,0 +1,234 @@
1
+ import { IconBox } from '@citric/core'
2
+ import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from '@citric/icons'
3
+ import { listToClass, theme, WithStyle } from '@stack-spot/portal-theme'
4
+ import { debounce } from 'lodash'
5
+ import { useEffect, useRef } from 'react'
6
+ import { styled } from 'styled-components'
7
+ import { WithChildren } from '../types'
8
+
9
+ type Side = 'top' | 'right' | 'left' | 'bottom'
10
+ type ScrollType = 'none' | 'wheel' | 'bar' | 'arrows'
11
+
12
+ interface Props extends WithChildren, WithStyle {
13
+ scroll?: ScrollType,
14
+ enableHorizontalScrollWithVerticalWheel?: boolean,
15
+ sides?: Side[],
16
+ }
17
+
18
+ const MIN_CHECK_INTERVAL_MS = 20
19
+ const masks = {
20
+ right: 'linear-gradient(to left, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) min(30%, 100px), rgba(0, 0, 0) 100%)',
21
+ left: 'linear-gradient(to right, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) min(30%, 100px), rgba(0, 0, 0) 100%)',
22
+ top: 'linear-gradient(to bottom, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) min(30%, 100px), rgba(0, 0, 0) 100%)',
23
+ bottom: 'linear-gradient(to top, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) min(30%, 100px), rgba(0, 0, 0) 100%)',
24
+ horizontal: 'linear-gradient(to left, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) min(30%, 100px), rgb(0, 0, 0) max(70%, calc(100% - 100px)), rgba(0, 0, 0, 0) 100%)',
25
+ vertical: 'linear-gradient(to top, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) min(30%, 100px), rgb(0, 0, 0) max(70%, calc(100% - 100px)), rgba(0, 0, 0, 0) 100%)',
26
+ }
27
+
28
+ const OverflowBox = styled.div`
29
+ &.hidden-scroll-bars::-webkit-scrollbar, &.scroll-arrows ::-webkit-scrollbar {
30
+ width: 0;
31
+ height: 0;
32
+ }
33
+
34
+ &.scroll-arrows {
35
+ position: relative;
36
+
37
+ > .content {
38
+ width: 100%;
39
+ }
40
+ }
41
+
42
+ .scroll-to-left, .scroll-to-right, .scroll-to-top, .scroll-to-bottom {
43
+ position: absolute;
44
+ top: 0;
45
+ bottom: 0;
46
+ left: 0;
47
+ right: 0;
48
+ width: 30px;
49
+ height: 30px;
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ opacity: 0;
54
+ pointer-events: none;
55
+ transition: opacity 0.3s;
56
+
57
+ ${IconBox} {
58
+ background-color: ${theme.color.light[300]};
59
+ border-radius: 50%;
60
+ width: 16px;
61
+ height: 16px;
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: center;
65
+ }
66
+
67
+ &.visible {
68
+ opacity: 0.6;
69
+ pointer-events: auto;
70
+
71
+ &:hover {
72
+ opacity: 1;
73
+ }
74
+ }
75
+ }
76
+
77
+ .scroll-to-left {
78
+ right: unset;
79
+ height: unset;
80
+ }
81
+
82
+ .scroll-to-right {
83
+ left: unset;
84
+ height: unset;
85
+ }
86
+
87
+ .scroll-to-top {
88
+ bottom: unset;
89
+ width: unset;
90
+ }
91
+
92
+ .scroll-to-bottom {
93
+ top: unset;
94
+ width: unset;
95
+ }
96
+ `
97
+
98
+ const SCROLL_INTERVAL_MS = 20
99
+ const SCROLL_PX = 4
100
+
101
+ export const FadingOverflow = (
102
+ { children, scroll = 'none', sides, enableHorizontalScrollWithVerticalWheel, className, ...props }: Props,
103
+ ) => {
104
+ const ref = useRef<HTMLDivElement>(null)
105
+
106
+ useEffect(() => {
107
+ if (!ref.current) return
108
+ const element = ref.current
109
+ const fadeTop = !sides || sides.includes('top')
110
+ const fadeRight = !sides || sides.includes('right')
111
+ const fadeBottom = !sides || sides.includes('bottom')
112
+ const fadeLeft = !sides || sides.includes('left')
113
+ let intervalId: number | undefined
114
+ const overflow = scroll === 'none' ? 'clip' : 'auto'
115
+ element.style.overflowX = (fadeLeft || fadeRight) ? overflow : ''
116
+ element.style.overflowY = (fadeTop || fadeBottom) ? overflow : ''
117
+ if (scroll === 'arrows' || scroll === 'wheel') element.classList.add('hidden-scroll-bars')
118
+
119
+ function stopScrolling() {
120
+ clearInterval(intervalId)
121
+ }
122
+
123
+ function checkOverflow() {
124
+ // masking (fading)
125
+ const overflowsRight = element.clientWidth < element.scrollWidth && element.scrollLeft < (element.scrollWidth - element.clientWidth)
126
+ const overflowsLeft = element.scrollLeft > 0
127
+ const overflowsTop = element.clientHeight < element.scrollHeight && element.scrollTop < (element.scrollHeight - element.clientHeight)
128
+ const overflowsBottom = element.scrollTop > 0
129
+ const masksToApply: string[] = []
130
+ if (overflowsLeft && fadeLeft && overflowsRight && fadeRight) masksToApply.push(masks.horizontal)
131
+ else {
132
+ if (overflowsRight && fadeRight) masksToApply.push(masks.right)
133
+ if (overflowsLeft && fadeLeft) masksToApply.push(masks.left)
134
+ }
135
+ if (overflowsTop && fadeTop && overflowsBottom && fadeBottom) masksToApply.push(masks.vertical)
136
+ else {
137
+ if (overflowsTop && fadeTop) masksToApply.push(masks.top)
138
+ if (overflowsBottom && fadeBottom) masksToApply.push(masks.bottom)
139
+ }
140
+ element.style.maskImage = masksToApply.join(', ')
141
+
142
+ // arrow buttons
143
+ if (scroll !== 'arrows') return
144
+
145
+ function startScrolling(side: Side) {
146
+ stopScrolling()
147
+ const direction = side === 'bottom' || side === 'top' ? 'scrollTop' : 'scrollLeft'
148
+ const multiplier = side === 'bottom' || side === 'right' ? 1 : -1
149
+ intervalId = window.setInterval(() => {
150
+ element[direction] += SCROLL_PX * multiplier
151
+ }, SCROLL_INTERVAL_MS)
152
+ }
153
+
154
+ const startScrollingBySide = {
155
+ left: () => startScrolling('left'),
156
+ right: () => startScrolling('right'),
157
+ top: () => startScrolling('top'),
158
+ bottom: () => startScrolling('bottom'),
159
+ }
160
+
161
+ const scrollToMaxBySide = {
162
+ left: () => element.scrollLeft = 0,
163
+ right: () => element.scrollLeft = element.scrollWidth - element.clientWidth,
164
+ top: () => element.scrollTop = 0,
165
+ bottom: () => element.scrollTop = element.scrollHeight - element.clientHeight,
166
+ }
167
+
168
+ function enableArrowButton(side: Side) {
169
+ const button = element.parentNode?.querySelector(`.scroll-to-${side}`)
170
+ if (button?.classList.contains('visible')) return
171
+ button?.classList.add('visible')
172
+ button?.addEventListener('mouseenter', startScrollingBySide[side])
173
+ button?.addEventListener('mouseleave', stopScrolling)
174
+ button?.addEventListener('click', scrollToMaxBySide[side])
175
+ }
176
+
177
+ function disableArrowButton(side: Side) {
178
+ const button = element.parentNode?.querySelector(`.scroll-to-${side}`)
179
+ if (!button?.classList.contains('visible')) return
180
+ button?.classList.remove('visible')
181
+ stopScrolling()
182
+ button?.removeEventListener('mouseenter', startScrollingBySide[side])
183
+ button?.removeEventListener('mouseleave', stopScrolling)
184
+ button?.removeEventListener('click', scrollToMaxBySide[side])
185
+ }
186
+
187
+ if (overflowsRight && fadeRight) enableArrowButton('right')
188
+ else disableArrowButton('right')
189
+ if (overflowsLeft && fadeLeft) enableArrowButton('left')
190
+ else disableArrowButton('left')
191
+ if (overflowsTop && fadeTop) enableArrowButton('top')
192
+ else disableArrowButton('top')
193
+ if (overflowsBottom && fadeBottom) enableArrowButton('bottom')
194
+ else disableArrowButton('bottom')
195
+ }
196
+
197
+ const debouncedCheck = debounce(checkOverflow, MIN_CHECK_INTERVAL_MS)
198
+ const resizeObserver = new ResizeObserver(debouncedCheck)
199
+ resizeObserver.observe(element)
200
+ element.addEventListener('scroll', debouncedCheck)
201
+
202
+ return () => {
203
+ stopScrolling()
204
+ resizeObserver.disconnect()
205
+ element.removeEventListener('scroll', debouncedCheck)
206
+ }
207
+ }, [sides, ref.current, scroll])
208
+
209
+ useEffect(() => {
210
+ if (!enableHorizontalScrollWithVerticalWheel || !ref.current) return
211
+ const element = ref.current
212
+
213
+ function scrollWithWheel(event: WheelEvent) {
214
+ if (event.deltaY) {
215
+ element.scrollLeft += event.deltaY
216
+ event.preventDefault()
217
+ event.stopPropagation()
218
+ }
219
+ }
220
+
221
+ element.addEventListener('wheel', scrollWithWheel)
222
+ return () => element.removeEventListener('wheel', scrollWithWheel)
223
+ }, [ref.current, enableHorizontalScrollWithVerticalWheel])
224
+
225
+ return scroll === 'arrows' ? (
226
+ <OverflowBox {...props} className={listToClass(['scroll-arrows', className])}>
227
+ <div className="content" ref={ref}>{children}</div>
228
+ <div className="scroll-to-left" aria-hidden><IconBox size="xs"><ChevronLeft /></IconBox></div>
229
+ <div className="scroll-to-right" aria-hidden><IconBox size="xs"><ChevronRight /></IconBox></div>
230
+ <div className="scroll-to-top" aria-hidden><IconBox size="xs"><ChevronUp /></IconBox></div>
231
+ <div className="scroll-to-bottom" aria-hidden><IconBox size="xs"><ChevronDown /></IconBox></div>
232
+ </OverflowBox>
233
+ ) : <OverflowBox {...props} className={className} ref={ref}>{children}</OverflowBox>
234
+ }
@@ -0,0 +1,48 @@
1
+ import { ErrorDescription, ErrorFeedback } from '@stack-spot/portal-components/error'
2
+ import { StackspotAPIError } from '@stack-spot/portal-network'
3
+ import { Component } from 'react'
4
+
5
+ interface State extends ErrorDescription {
6
+ hasError: boolean,
7
+ }
8
+
9
+ interface Props {
10
+ children: React.ReactNode,
11
+ }
12
+
13
+ /**
14
+ * An Error Boundary that renders an ErrorFeedback instead of its content if any of its children throws.
15
+ *
16
+ * To customize what properties are passed to the ErrorFeedback component, setup an error descriptor for the ErrorManager class. If you're
17
+ * using the component `Layout` or `RawLayout`, you can use the property `errorDescriptor`.
18
+ *
19
+ * To run an error handler every time an error is catch by this boundary, setup an error handler for the ErrorManager class. If you're
20
+ * using the component `Layout` or `RawLayout`, you can use the property `onError`.
21
+ */
22
+ export class ErrorBoundary extends Component<Props, State> {
23
+ constructor(props: Props) {
24
+ super(props)
25
+ this.state = { hasError: false }
26
+ }
27
+
28
+ static getDerivedStateFromError(error: any) {
29
+ const message = error instanceof StackspotAPIError ? error.translate() : (error.message ?? `${error}`)
30
+ const code = error instanceof StackspotAPIError ? error.status : undefined
31
+ return { hasError: true, message, code }
32
+ }
33
+
34
+ componentDidCatch(error: any, errorInfo: any) {
35
+ // eslint-disable-next-line no-console
36
+ console.error(error, errorInfo)
37
+ }
38
+
39
+ componentDidUpdate(prevProps: Readonly<Props>) {
40
+ if (this.props.children !== prevProps.children) this.setState({ hasError: false })
41
+ }
42
+
43
+ render() {
44
+ return this.state.hasError
45
+ ? <ErrorFeedback code={this.state.code} message={this.state.message} />
46
+ : this.props.children
47
+ }
48
+ }
@@ -0,0 +1,14 @@
1
+ import { LoadingCircular } from '@citric/ui'
2
+ import styled from 'styled-components'
3
+
4
+ const LoadingBox = styled.div`
5
+ width: 100%;
6
+ height: 100%;
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+ `
11
+
12
+ export const Loading = () => (
13
+ <LoadingBox><LoadingCircular /></LoadingBox>
14
+ )
@@ -0,0 +1,15 @@
1
+ import { Suspense } from 'react'
2
+ import { WithChildren } from '../../types'
3
+ import { ErrorBoundary } from './ErrorBoundary'
4
+ import { Loading } from './Loading'
5
+
6
+ /**
7
+ * Fallbacks for errors and loadings (suspense).
8
+ */
9
+ export const FallbackBoundary = ({ children }: WithChildren) => (
10
+ <ErrorBoundary>
11
+ <Suspense fallback={<Loading />}>
12
+ {children}
13
+ </Suspense>
14
+ </ErrorBoundary>
15
+ )
@@ -0,0 +1,16 @@
1
+ /* eslint-disable no-empty-pattern */
2
+ import { WithStyle } from '@stack-spot/portal-theme'
3
+ import { ButtonAction } from '../types'
4
+
5
+ interface Props<T> extends WithStyle {
6
+ items: T[],
7
+ renderLabel: (item: T) => React.ReactElement,
8
+ getDate: (item: T) => Date,
9
+ keygen: (item: T) => React.Key,
10
+ getActions?: (item: T) => ButtonAction[],
11
+ onSelect?: (item: T) => void,
12
+ }
13
+
14
+ export function HistoryList<T>({}: Props<T>) {
15
+ return null
16
+ }
@@ -0,0 +1,70 @@
1
+ import { IconBox } from '@citric/core'
2
+ import { listToClass, theme } from '@stack-spot/portal-theme'
3
+ import { useMemo, useState } from 'react'
4
+ import { styled } from 'styled-components'
5
+
6
+ interface Props extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
7
+ icon: React.ReactElement,
8
+ onChange?: (value: string) => void,
9
+ }
10
+
11
+ const InputBox = styled.div`
12
+ display: flex;
13
+ flex-direction: row;
14
+ transition: border-color 0.3s, box-shadow 0.3s;
15
+ border: 1px solid ${theme.color.light[600]};
16
+ border-radius: 0.25rem;
17
+ background-color: ${theme.color.light[300]};
18
+ overflow: hidden;
19
+ flex-shrink: 0;
20
+
21
+ &.focused {
22
+ border-color: ${theme.color.primary[500]};
23
+ box-shadow: 0 0 0 1px ${theme.color.primary[500]};
24
+ }
25
+
26
+ &.disabled {
27
+ background-color: ${theme.color.light[500]};
28
+ }
29
+
30
+ ${IconBox} {
31
+ width: 40px;
32
+ height: 40px;
33
+ border-radius: 0;
34
+ background-color: ${theme.color.light[600]};
35
+ }
36
+
37
+ input {
38
+ padding: 8px;
39
+ border: none;
40
+ background-color: transparent;
41
+ flex: 1;
42
+ color: ${theme.color.light.contrastText};
43
+
44
+ &:focus {
45
+ outline: none;
46
+ }
47
+ }
48
+ `
49
+
50
+ export const IconInput = ({ icon, onChange, style, className, disabled, onFocus, onBlur, ...props }: Props) => {
51
+ const [focused, setFocused] = useState(false)
52
+
53
+ const { focus, blur } = useMemo(() => ({
54
+ focus: (e: React.FocusEvent<HTMLInputElement, Element>) => {
55
+ setFocused(true)
56
+ onFocus?.(e)
57
+ },
58
+ blur: (e: React.FocusEvent<HTMLInputElement, Element>) => {
59
+ setFocused(false)
60
+ onBlur?.(e)
61
+ },
62
+ }), [])
63
+
64
+ return (
65
+ <InputBox style={style} className={listToClass([className, focused && !disabled && 'focused', disabled && 'disabled'])}>
66
+ <IconBox>{icon}</IconBox>
67
+ <input {...props} disabled={disabled} onFocus={focus} onBlur={blur} onChange={e => onChange?.(e.target.value)} />
68
+ </InputBox>
69
+ )
70
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Copied from the extension's webview.
3
+ */
4
+
5
+ import { Children, Fragment } from 'react'
6
+ import ReactMarkdown from 'react-markdown'
7
+ import remarkGfm from 'remark-gfm'
8
+ import { WithChildren } from '../types'
9
+ import { Code, Props as CodeProps } from './Code'
10
+
11
+ type Props = Omit<CodeProps, 'language'> & WithChildren<string>
12
+
13
+ const renderP = (child: any, key: number) => (
14
+ <Fragment key={key}>
15
+ {typeof child === 'string'
16
+ ? child.split('\n').map((content, subKey, array) => (
17
+ <Fragment key={subKey}>
18
+ {content}
19
+ {subKey < array.length - 1 ? <br /> : null}
20
+ </Fragment>
21
+ )) : child}
22
+ </Fragment>
23
+ )
24
+
25
+ export const Markdown = (
26
+ {
27
+ onInsertCode,
28
+ onNewFile,
29
+ onCopyCode,
30
+ children,
31
+ }: Props,
32
+ ) => (
33
+ <>
34
+ <ReactMarkdown
35
+ remarkPlugins={[[remarkGfm]]}
36
+ components={{
37
+ a: props => <a target="_blank" rel="noopener noreferrer" {...props} />,
38
+ code: props =>
39
+ <Code
40
+ {...props}
41
+ onInsertCode={onInsertCode}
42
+ onNewFile={onNewFile}
43
+ onCopyCode={onCopyCode}
44
+ showActionBar
45
+ />,
46
+ pre: ({ children }) => <>{children}</>,
47
+ p: ({ children }) => <p>{Children.map(children, renderP)}</p>,
48
+ }}
49
+ >
50
+ {children}
51
+ </ReactMarkdown>
52
+ </>
53
+ )
@@ -0,0 +1,10 @@
1
+ /* eslint-disable no-empty-pattern */
2
+ import { WithStyle } from '@stack-spot/portal-theme'
3
+ import { ButtonAction, WithChildren } from '../types'
4
+
5
+ interface Props extends WithStyle, WithChildren {
6
+ position?: 'left' | 'top' | 'bottom' | 'right',
7
+ actions: ButtonAction[],
8
+ }
9
+
10
+ export const OverlayMenu = ({}: Props) => null
@@ -0,0 +1,153 @@
1
+ import { listToClass, theme, WithStyle } from '@stack-spot/portal-theme'
2
+ import { styled } from 'styled-components'
3
+
4
+ interface Props extends WithStyle {
5
+ visible?: boolean,
6
+ shimmer?: boolean,
7
+ foregroundColor?: string | string[],
8
+ backgroundColor?: string | string[],
9
+ shimmerColor?: string | string[],
10
+ }
11
+
12
+ function gradientFromColorArray(colors: string[]) {
13
+ if (colors.length === 1) return colors[0]
14
+ const step = 100 / (colors.length - 1)
15
+ const partials: string[] = []
16
+ let current = 0
17
+ for (const color of colors) {
18
+ partials.push(`${color} ${Math.ceil(current)}%`)
19
+ current += step
20
+ }
21
+ return `linear-gradient(to right, ${partials.join(', ')})`
22
+ }
23
+
24
+ const SHIMMER_PADDING = '10px'
25
+
26
+ const Styled = styled.div<{ $bg: string[], $fg: string[], $shimmer: string[] }>`
27
+ margin: 7px 0;
28
+ opacity: 0;
29
+ transition: opacity 0.5s;
30
+
31
+ &.visible {
32
+ opacity: 1;
33
+ }
34
+
35
+ .shimmer {
36
+ display: flex;
37
+ flex-direction: column;
38
+ justify-content: center;
39
+ height: 10px;
40
+ position: relative;
41
+ padding: 0 ${SHIMMER_PADDING};
42
+ margin: 3px 0;
43
+
44
+ .progress-glow {
45
+ filter: blur(2px);
46
+ position: absolute;
47
+ top: 0;
48
+ left: ${SHIMMER_PADDING};
49
+ bottom: 0;
50
+ right: ${SHIMMER_PADDING};
51
+ display: flex;
52
+ flex-direction: column;
53
+ justify-content: center;
54
+ overflow: hidden;
55
+
56
+ &::before {
57
+ content: '';
58
+ height: 3px;
59
+ display: block;
60
+ width: 33%;
61
+ display: block;
62
+ animation: slide 3s infinite forwards;
63
+ background: ${({ $fg }) => gradientFromColorArray($fg)};
64
+ }
65
+ }
66
+
67
+ .colors {
68
+ position: absolute;
69
+ top: 0;
70
+ bottom: 0;
71
+ left: 0;
72
+ right: 0;
73
+ overflow: hidden;
74
+ filter: blur(10px);
75
+
76
+ ${({ $shimmer }) => `
77
+ &:before {
78
+ content: '';
79
+ position: absolute;
80
+ top: 0;
81
+ bottom: 0;
82
+ width: ${$shimmer.length * 100}%;
83
+ background: ${gradientFromColorArray($shimmer)};
84
+ ${$shimmer.length > 2 ? `animation: shimmer-slide ${$shimmer.length}s ease-in infinite alternate;` : ''}
85
+ }
86
+
87
+ @keyframes shimmer-slide {
88
+ from {
89
+ left: 0;
90
+ }
91
+ to {
92
+ left: -${($shimmer.length - 1) * 100}%;
93
+ }
94
+ }
95
+ `}
96
+ }
97
+ }
98
+
99
+ .progress-bar {
100
+ height: 2px;
101
+ width: 100%;
102
+ background: ${({ $bg }) => gradientFromColorArray($bg)};
103
+ position: relative;
104
+ overflow-x: clip;
105
+
106
+ &:before {
107
+ content: '';
108
+ display: block;
109
+ width: 33%;
110
+ height: 100%;
111
+ background: ${({ $fg }) => gradientFromColorArray($fg)};
112
+ animation: slide 3s infinite forwards;
113
+ }
114
+
115
+ @keyframes slide {
116
+ from {
117
+ margin-left: -33%;
118
+ }
119
+ to {
120
+ margin-left: 100%;
121
+ }
122
+ }
123
+ }
124
+ `
125
+
126
+ export const ProgressBar = ({
127
+ visible = true,
128
+ shimmer,
129
+ backgroundColor = shimmer ? 'rgba(255, 255, 255, 0.4)' : theme.color.light[500],
130
+ foregroundColor = shimmer ? ['#FFF0', '#FFF', '#FFF0'] : theme.color.primary[500],
131
+ shimmerColor = ['#ff6633', '#d668cd', '#ff6633', '#FFF8', '#299cf4'],
132
+ className,
133
+ style,
134
+ }: Props) => {
135
+ const $bg = Array.isArray(backgroundColor) ? backgroundColor : [backgroundColor]
136
+ const $fg = Array.isArray(foregroundColor) ? foregroundColor : [...$bg, foregroundColor, ...$bg]
137
+ const $shimmer = Array.isArray(shimmerColor) ? shimmerColor : [shimmerColor]
138
+ const progress = <div className="progress-bar"></div>
139
+ const result = shimmer
140
+ ? (
141
+ <div className="shimmer">
142
+ <div className="colors"></div>
143
+ <div className="progress-glow"></div>
144
+ {progress}
145
+ </div>
146
+ )
147
+ : progress
148
+ return (
149
+ <Styled className={listToClass([className, visible && 'visible'])} style={style} $fg={$fg} $bg={$bg} $shimmer={$shimmer}>
150
+ {result}
151
+ </Styled>
152
+ )
153
+ }
@@ -0,0 +1,51 @@
1
+ import { IconBox, Text } from '@citric/core'
2
+ import { theme, WithStyle } from '@stack-spot/portal-theme'
3
+ import { styled } from 'styled-components'
4
+ import { ButtonAction } from '../types'
5
+
6
+ interface Props extends ButtonAction, WithStyle {
7
+ background?: string,
8
+ }
9
+
10
+ const QuickButton = styled.button<{ $color?: string, $bg?: string }>`
11
+ display: flex;
12
+ flex-direction: column;
13
+ padding: 12px;
14
+ gap: 12px;
15
+ background-color: ${theme.color.light[500]};
16
+ border: none;
17
+ color: inherit;
18
+ flex: 1;
19
+ border-radius: 4px;
20
+ border: 2px solid;
21
+ border-color: ${theme.color.light[500]};
22
+ transition: border-color 0.3s;
23
+ cursor: pointer;
24
+ text-align: left;
25
+
26
+ &:hover {
27
+ border-color: ${theme.color.light[600]};
28
+ }
29
+
30
+ i {
31
+ border-radius: 2px;
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ background-color: ${({ $bg }) => $bg || 'transparent'};
36
+ ${({ $color }) => $color
37
+ ? `
38
+ svg {
39
+ fill: ${$color};
40
+ }`
41
+ : ''
42
+ };
43
+ }
44
+ `
45
+
46
+ export const QuickStartButton = ({ label, onClick, background, className, color, icon, style }: Props) => (
47
+ <QuickButton className={className} style={style} onClick={onClick} $color={color} $bg={background}>
48
+ <IconBox aria-hidden>{icon}</IconBox>
49
+ <Text>{label}</Text>
50
+ </QuickButton>
51
+ )