@stack-spot/ai-chat-widget 1.36.1-betacitric.1 → 1.36.1

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 (353) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/StackspotAIWidget.d.ts.map +1 -1
  3. package/dist/StackspotAIWidget.js +7 -6
  4. package/dist/StackspotAIWidget.js.map +1 -1
  5. package/dist/app-metadata.json +17 -13
  6. package/dist/chat-interceptors/quick-commands.d.ts.map +1 -1
  7. package/dist/chat-interceptors/quick-commands.js +9 -3
  8. package/dist/chat-interceptors/quick-commands.js.map +1 -1
  9. package/dist/components/Accordion.d.ts +20 -0
  10. package/dist/components/Accordion.d.ts.map +1 -0
  11. package/dist/components/Accordion.js +51 -0
  12. package/dist/components/Accordion.js.map +1 -0
  13. package/dist/components/AdaptiveTextArea.d.ts +1 -1
  14. package/dist/components/AdaptiveTextArea.d.ts.map +1 -1
  15. package/dist/components/AdaptiveTextArea.js +1 -1
  16. package/dist/components/AdaptiveTextArea.js.map +1 -1
  17. package/dist/components/AgentCard/AgentCardCreate.d.ts.map +1 -1
  18. package/dist/components/AgentCard/AgentCardCreate.js +3 -3
  19. package/dist/components/AgentCard/AgentCardCreate.js.map +1 -1
  20. package/dist/components/AgentCard/index.d.ts.map +1 -1
  21. package/dist/components/AgentCard/index.js +6 -5
  22. package/dist/components/AgentCard/index.js.map +1 -1
  23. package/dist/components/ButtonFavorite.d.ts +7 -8
  24. package/dist/components/ButtonFavorite.d.ts.map +1 -1
  25. package/dist/components/ButtonFavorite.js +14 -5
  26. package/dist/components/ButtonFavorite.js.map +1 -1
  27. package/dist/components/Code.d.ts.map +1 -1
  28. package/dist/components/Code.js +9 -11
  29. package/dist/components/Code.js.map +1 -1
  30. package/dist/components/ComponentNavigator.d.ts.map +1 -1
  31. package/dist/components/ComponentNavigator.js +4 -2
  32. package/dist/components/ComponentNavigator.js.map +1 -1
  33. package/dist/components/FadingOverflow.d.ts.map +1 -1
  34. package/dist/components/FadingOverflow.js +4 -3
  35. package/dist/components/FadingOverflow.js.map +1 -1
  36. package/dist/components/FallbackBoundary/ErrorBoundary.d.ts +33 -0
  37. package/dist/components/FallbackBoundary/ErrorBoundary.d.ts.map +1 -0
  38. package/dist/components/FallbackBoundary/ErrorBoundary.js +52 -0
  39. package/dist/components/FallbackBoundary/ErrorBoundary.js.map +1 -0
  40. package/dist/components/FallbackBoundary/Loading.d.ts +2 -0
  41. package/dist/components/FallbackBoundary/Loading.d.ts.map +1 -0
  42. package/dist/components/FallbackBoundary/Loading.js +12 -0
  43. package/dist/components/FallbackBoundary/Loading.js.map +1 -0
  44. package/dist/components/FallbackBoundary/index.d.ts +17 -0
  45. package/dist/components/FallbackBoundary/index.d.ts.map +1 -0
  46. package/dist/components/FallbackBoundary/index.js +9 -0
  47. package/dist/components/FallbackBoundary/index.js.map +1 -0
  48. package/dist/components/FileDescription.d.ts.map +1 -1
  49. package/dist/components/FileDescription.js +4 -3
  50. package/dist/components/FileDescription.js.map +1 -1
  51. package/dist/components/HistoryList.js +1 -1
  52. package/dist/components/HistoryList.js.map +1 -1
  53. package/dist/components/IconInput.d.ts +10 -0
  54. package/dist/components/IconInput.d.ts.map +1 -0
  55. package/dist/components/IconInput.js +61 -0
  56. package/dist/components/IconInput.js.map +1 -0
  57. package/dist/components/ListResource.js +3 -3
  58. package/dist/components/ListResource.js.map +1 -1
  59. package/dist/components/Markdown.js +1 -1
  60. package/dist/components/Markdown.js.map +1 -1
  61. package/dist/components/Modal.d.ts.map +1 -1
  62. package/dist/components/Modal.js +4 -2
  63. package/dist/components/Modal.js.map +1 -1
  64. package/dist/components/OverlayMenu.d.ts +21 -0
  65. package/dist/components/OverlayMenu.d.ts.map +1 -0
  66. package/dist/components/OverlayMenu.js +79 -0
  67. package/dist/components/OverlayMenu.js.map +1 -0
  68. package/dist/components/ProgressBar.d.ts +37 -0
  69. package/dist/components/ProgressBar.d.ts.map +1 -0
  70. package/dist/components/ProgressBar.js +131 -0
  71. package/dist/components/ProgressBar.js.map +1 -0
  72. package/dist/components/QuickStartButton.d.ts +3 -2
  73. package/dist/components/QuickStartButton.d.ts.map +1 -1
  74. package/dist/components/QuickStartButton.js +3 -4
  75. package/dist/components/QuickStartButton.js.map +1 -1
  76. package/dist/components/RightPanelForm.d.ts.map +1 -1
  77. package/dist/components/RightPanelForm.js +13 -20
  78. package/dist/components/RightPanelForm.js.map +1 -1
  79. package/dist/components/RightPanelTabs.d.ts +4 -1
  80. package/dist/components/RightPanelTabs.d.ts.map +1 -1
  81. package/dist/components/RightPanelTabs.js +16 -4
  82. package/dist/components/RightPanelTabs.js.map +1 -1
  83. package/dist/components/Selector/index.d.ts.map +1 -1
  84. package/dist/components/Selector/index.js +8 -5
  85. package/dist/components/Selector/index.js.map +1 -1
  86. package/dist/components/Selector/styled.d.ts.map +1 -1
  87. package/dist/components/Selector/styled.js +5 -8
  88. package/dist/components/Selector/styled.js.map +1 -1
  89. package/dist/components/StackedBadge.js +5 -5
  90. package/dist/components/StackedBadge.js.map +1 -1
  91. package/dist/components/TabManager.d.ts.map +1 -1
  92. package/dist/components/TabManager.js +30 -5
  93. package/dist/components/TabManager.js.map +1 -1
  94. package/dist/components/ToolBadge.d.ts +8 -3
  95. package/dist/components/ToolBadge.d.ts.map +1 -1
  96. package/dist/components/ToolBadge.js +99 -21
  97. package/dist/components/ToolBadge.js.map +1 -1
  98. package/dist/components/Tooltip/Tooltip.d.ts +37 -0
  99. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -0
  100. package/dist/components/Tooltip/Tooltip.js +30 -0
  101. package/dist/components/Tooltip/Tooltip.js.map +1 -0
  102. package/dist/components/Tooltip/TooltipAPI.d.ts +29 -0
  103. package/dist/components/Tooltip/TooltipAPI.d.ts.map +1 -0
  104. package/dist/components/Tooltip/TooltipAPI.js +107 -0
  105. package/dist/components/Tooltip/TooltipAPI.js.map +1 -0
  106. package/dist/components/Tooltip/context.d.ts +5 -0
  107. package/dist/components/Tooltip/context.d.ts.map +1 -0
  108. package/dist/components/Tooltip/context.js +18 -0
  109. package/dist/components/Tooltip/context.js.map +1 -0
  110. package/dist/components/Tooltip/index.d.ts +3 -0
  111. package/dist/components/Tooltip/index.d.ts.map +1 -0
  112. package/dist/components/Tooltip/index.js +3 -0
  113. package/dist/components/Tooltip/index.js.map +1 -0
  114. package/dist/components/Tooltip/style.d.ts +4 -0
  115. package/dist/components/Tooltip/style.d.ts.map +1 -0
  116. package/dist/components/Tooltip/style.js +22 -0
  117. package/dist/components/Tooltip/style.js.map +1 -0
  118. package/dist/components/Tooltip/types.d.ts +27 -0
  119. package/dist/components/Tooltip/types.d.ts.map +1 -0
  120. package/dist/components/Tooltip/types.js +2 -0
  121. package/dist/components/Tooltip/types.js.map +1 -0
  122. package/dist/components/WorkspaceTabNavigator.d.ts.map +1 -1
  123. package/dist/components/WorkspaceTabNavigator.js +9 -7
  124. package/dist/components/WorkspaceTabNavigator.js.map +1 -1
  125. package/dist/components/form/DescribedCheckboxGroup.d.ts +2 -24
  126. package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
  127. package/dist/components/form/DescribedCheckboxGroup.js +29 -46
  128. package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
  129. package/dist/components/form/DescribedRadioGroup.d.ts +4 -24
  130. package/dist/components/form/DescribedRadioGroup.d.ts.map +1 -1
  131. package/dist/components/form/DescribedRadioGroup.js +18 -39
  132. package/dist/components/form/DescribedRadioGroup.js.map +1 -1
  133. package/dist/index.d.ts +2 -1
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +2 -1
  136. package/dist/index.js.map +1 -1
  137. package/dist/layout.css +26 -0
  138. package/dist/right-panel/DefaultPanel.d.ts.map +1 -1
  139. package/dist/right-panel/DefaultPanel.js +4 -2
  140. package/dist/right-panel/DefaultPanel.js.map +1 -1
  141. package/dist/state/ChatEntry.d.ts +4 -3
  142. package/dist/state/ChatEntry.d.ts.map +1 -1
  143. package/dist/state/ChatEntry.js.map +1 -1
  144. package/dist/state/constants.js +2 -2
  145. package/dist/state/constants.js.map +1 -1
  146. package/dist/types.d.ts +3 -3
  147. package/dist/types.d.ts.map +1 -1
  148. package/dist/utils/tools.d.ts +2 -1
  149. package/dist/utils/tools.d.ts.map +1 -1
  150. package/dist/utils/tools.js +12 -1
  151. package/dist/utils/tools.js.map +1 -1
  152. package/dist/utils/upload/FileUpload.d.ts.map +1 -1
  153. package/dist/utils/upload/FileUpload.js +1 -2
  154. package/dist/utils/upload/FileUpload.js.map +1 -1
  155. package/dist/views/Agents/AgentDescription.d.ts.map +1 -1
  156. package/dist/views/Agents/AgentDescription.js +6 -5
  157. package/dist/views/Agents/AgentDescription.js.map +1 -1
  158. package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
  159. package/dist/views/Agents/AgentsPanel.js +7 -7
  160. package/dist/views/Agents/AgentsPanel.js.map +1 -1
  161. package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
  162. package/dist/views/Agents/AgentsTab.js +28 -29
  163. package/dist/views/Agents/AgentsTab.js.map +1 -1
  164. package/dist/views/Agents/dictionary.d.ts +1 -1
  165. package/dist/views/Chat/AgentInfo.d.ts.map +1 -1
  166. package/dist/views/Chat/AgentInfo.js +5 -3
  167. package/dist/views/Chat/AgentInfo.js.map +1 -1
  168. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  169. package/dist/views/Chat/ChatMessage.js +36 -28
  170. package/dist/views/Chat/ChatMessage.js.map +1 -1
  171. package/dist/views/Chat/StepsList.d.ts.map +1 -1
  172. package/dist/views/Chat/StepsList.js +10 -10
  173. package/dist/views/Chat/StepsList.js.map +1 -1
  174. package/dist/views/Chat/styled.d.ts.map +1 -1
  175. package/dist/views/Chat/styled.js +2 -8
  176. package/dist/views/Chat/styled.js.map +1 -1
  177. package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
  178. package/dist/views/ChatHistory/HistoryItem.js +14 -7
  179. package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
  180. package/dist/views/ChatHistory/index.js +1 -1
  181. package/dist/views/ChatHistory/index.js.map +1 -1
  182. package/dist/views/ChatHistory/styled.d.ts.map +1 -1
  183. package/dist/views/ChatHistory/styled.js +5 -3
  184. package/dist/views/ChatHistory/styled.js.map +1 -1
  185. package/dist/views/ChatTabSelection.d.ts.map +1 -1
  186. package/dist/views/ChatTabSelection.js +3 -2
  187. package/dist/views/ChatTabSelection.js.map +1 -1
  188. package/dist/views/Editor.d.ts.map +1 -1
  189. package/dist/views/Editor.js +12 -6
  190. package/dist/views/Editor.js.map +1 -1
  191. package/dist/views/Home/BuiltInAgent.d.ts.map +1 -1
  192. package/dist/views/Home/BuiltInAgent.js +3 -2
  193. package/dist/views/Home/BuiltInAgent.js.map +1 -1
  194. package/dist/views/Home/CustomAgent.js +3 -3
  195. package/dist/views/Home/CustomAgent.js.map +1 -1
  196. package/dist/views/Home/index.js +1 -1
  197. package/dist/views/Home/index.js.map +1 -1
  198. package/dist/views/Home/styled.d.ts.map +1 -1
  199. package/dist/views/Home/styled.js +22 -21
  200. package/dist/views/Home/styled.js.map +1 -1
  201. package/dist/views/KSDocument.d.ts.map +1 -1
  202. package/dist/views/KSDocument.js +4 -3
  203. package/dist/views/KSDocument.js.map +1 -1
  204. package/dist/views/KnowledgeSources.d.ts.map +1 -1
  205. package/dist/views/KnowledgeSources.js +36 -14
  206. package/dist/views/KnowledgeSources.js.map +1 -1
  207. package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
  208. package/dist/views/MessageInput/AgentSelector.js +5 -7
  209. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  210. package/dist/views/MessageInput/ButtonAgent.d.ts.map +1 -1
  211. package/dist/views/MessageInput/ButtonAgent.js +5 -4
  212. package/dist/views/MessageInput/ButtonAgent.js.map +1 -1
  213. package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -1
  214. package/dist/views/MessageInput/ButtonBar.js +4 -2
  215. package/dist/views/MessageInput/ButtonBar.js.map +1 -1
  216. package/dist/views/MessageInput/ContextBar.d.ts.map +1 -1
  217. package/dist/views/MessageInput/ContextBar.js +6 -4
  218. package/dist/views/MessageInput/ContextBar.js.map +1 -1
  219. package/dist/views/MessageInput/QuickCommandSelector.js +2 -2
  220. package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
  221. package/dist/views/MessageInput/SelectContent.d.ts.map +1 -1
  222. package/dist/views/MessageInput/SelectContent.js +35 -30
  223. package/dist/views/MessageInput/SelectContent.js.map +1 -1
  224. package/dist/views/MessageInput/UploadBar.d.ts.map +1 -1
  225. package/dist/views/MessageInput/UploadBar.js +24 -2
  226. package/dist/views/MessageInput/UploadBar.js.map +1 -1
  227. package/dist/views/MessageInput/UploadDragNDrop.d.ts.map +1 -1
  228. package/dist/views/MessageInput/UploadDragNDrop.js +3 -2
  229. package/dist/views/MessageInput/UploadDragNDrop.js.map +1 -1
  230. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  231. package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
  232. package/dist/views/MessageInput/dictionary.js +4 -0
  233. package/dist/views/MessageInput/dictionary.js.map +1 -1
  234. package/dist/views/MessageInput/index.d.ts.map +1 -1
  235. package/dist/views/MessageInput/index.js +4 -3
  236. package/dist/views/MessageInput/index.js.map +1 -1
  237. package/dist/views/MessageInput/styled.d.ts +3 -1
  238. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  239. package/dist/views/MessageInput/styled.js +27 -11
  240. package/dist/views/MessageInput/styled.js.map +1 -1
  241. package/dist/views/MinimizedHeader.d.ts.map +1 -1
  242. package/dist/views/MinimizedHeader.js +4 -2
  243. package/dist/views/MinimizedHeader.js.map +1 -1
  244. package/dist/views/Stacks.d.ts.map +1 -1
  245. package/dist/views/Stacks.js +28 -23
  246. package/dist/views/Stacks.js.map +1 -1
  247. package/dist/views/Steps/FlowChart/NodeStep.d.ts.map +1 -1
  248. package/dist/views/Steps/FlowChart/NodeStep.js +3 -3
  249. package/dist/views/Steps/FlowChart/NodeStep.js.map +1 -1
  250. package/dist/views/Steps/StepModal.d.ts.map +1 -1
  251. package/dist/views/Steps/StepModal.js +6 -4
  252. package/dist/views/Steps/StepModal.js.map +1 -1
  253. package/dist/views/Steps/dictionary.d.ts +1 -1
  254. package/dist/views/Steps/index.d.ts.map +1 -1
  255. package/dist/views/Steps/index.js +4 -3
  256. package/dist/views/Steps/index.js.map +1 -1
  257. package/dist/views/Steps/utils.d.ts +1 -2
  258. package/dist/views/Steps/utils.d.ts.map +1 -1
  259. package/dist/views/Steps/utils.js +8 -8
  260. package/dist/views/Steps/utils.js.map +1 -1
  261. package/dist/views/Tools.js +4 -2
  262. package/dist/views/Tools.js.map +1 -1
  263. package/dist/views/Workspaces/WorkspacesTab.d.ts.map +1 -1
  264. package/dist/views/Workspaces/WorkspacesTab.js +10 -7
  265. package/dist/views/Workspaces/WorkspacesTab.js.map +1 -1
  266. package/dist/views/Workspaces/index.js +2 -4
  267. package/dist/views/Workspaces/index.js.map +1 -1
  268. package/package.json +13 -12
  269. package/src/StackspotAIWidget.tsx +33 -30
  270. package/src/app-metadata.json +17 -13
  271. package/src/chat-interceptors/quick-commands.ts +11 -5
  272. package/src/components/Accordion.tsx +75 -0
  273. package/src/components/AdaptiveTextArea.tsx +1 -1
  274. package/src/components/AgentCard/AgentCardCreate.tsx +5 -3
  275. package/src/components/AgentCard/index.tsx +7 -7
  276. package/src/components/ButtonFavorite.tsx +47 -20
  277. package/src/components/Code.tsx +36 -31
  278. package/src/components/ComponentNavigator.tsx +8 -4
  279. package/src/components/FadingOverflow.tsx +7 -6
  280. package/src/components/FallbackBoundary/ErrorBoundary.tsx +71 -0
  281. package/src/components/FallbackBoundary/Loading.tsx +14 -0
  282. package/src/components/FallbackBoundary/index.tsx +26 -0
  283. package/src/components/FileDescription.tsx +10 -14
  284. package/src/components/HistoryList.tsx +1 -1
  285. package/src/components/IconInput.tsx +73 -0
  286. package/src/components/ListResource.tsx +5 -5
  287. package/src/components/Markdown.tsx +1 -1
  288. package/src/components/Modal.tsx +4 -2
  289. package/src/components/OverlayMenu.tsx +133 -0
  290. package/src/components/ProgressBar.tsx +183 -0
  291. package/src/components/QuickStartButton.tsx +4 -5
  292. package/src/components/RightPanelForm.tsx +13 -20
  293. package/src/components/RightPanelTabs.tsx +32 -4
  294. package/src/components/Selector/index.tsx +13 -17
  295. package/src/components/Selector/styled.ts +5 -8
  296. package/src/components/StackedBadge.tsx +5 -5
  297. package/src/components/TabManager.tsx +36 -8
  298. package/src/components/ToolBadge.tsx +129 -39
  299. package/src/components/Tooltip/Tooltip.tsx +78 -0
  300. package/src/components/Tooltip/TooltipAPI.ts +101 -0
  301. package/src/components/Tooltip/context.tsx +24 -0
  302. package/src/components/Tooltip/index.ts +2 -0
  303. package/src/components/Tooltip/style.tsx +24 -0
  304. package/src/components/Tooltip/types.ts +28 -0
  305. package/src/components/WorkspaceTabNavigator.tsx +25 -22
  306. package/src/components/form/DescribedCheckboxGroup.tsx +65 -90
  307. package/src/components/form/DescribedRadioGroup.tsx +46 -79
  308. package/src/index.ts +2 -1
  309. package/src/layout.css +26 -0
  310. package/src/right-panel/DefaultPanel.tsx +7 -3
  311. package/src/state/ChatEntry.ts +4 -3
  312. package/src/state/constants.ts +2 -2
  313. package/src/types.ts +3 -4
  314. package/src/utils/tools.ts +23 -2
  315. package/src/utils/upload/FileUpload.ts +1 -2
  316. package/src/views/Agents/AgentDescription.tsx +7 -6
  317. package/src/views/Agents/AgentsPanel.tsx +12 -11
  318. package/src/views/Agents/AgentsTab.tsx +56 -37
  319. package/src/views/Chat/AgentInfo.tsx +6 -7
  320. package/src/views/Chat/ChatMessage.tsx +118 -109
  321. package/src/views/Chat/StepsList.tsx +11 -10
  322. package/src/views/Chat/styled.ts +2 -8
  323. package/src/views/ChatHistory/HistoryItem.tsx +19 -12
  324. package/src/views/ChatHistory/index.tsx +1 -1
  325. package/src/views/ChatHistory/styled.ts +5 -3
  326. package/src/views/ChatTabSelection.tsx +3 -2
  327. package/src/views/Editor.tsx +14 -9
  328. package/src/views/Home/BuiltInAgent.tsx +8 -7
  329. package/src/views/Home/CustomAgent.tsx +3 -3
  330. package/src/views/Home/index.tsx +1 -1
  331. package/src/views/Home/styled.ts +22 -21
  332. package/src/views/KSDocument.tsx +8 -7
  333. package/src/views/KnowledgeSources.tsx +66 -24
  334. package/src/views/MessageInput/AgentSelector.tsx +8 -10
  335. package/src/views/MessageInput/ButtonAgent.tsx +12 -24
  336. package/src/views/MessageInput/ButtonBar.tsx +21 -25
  337. package/src/views/MessageInput/ContextBar.tsx +14 -12
  338. package/src/views/MessageInput/QuickCommandSelector.tsx +2 -2
  339. package/src/views/MessageInput/SelectContent.tsx +68 -39
  340. package/src/views/MessageInput/UploadBar.tsx +34 -2
  341. package/src/views/MessageInput/UploadDragNDrop.tsx +5 -2
  342. package/src/views/MessageInput/dictionary.ts +4 -0
  343. package/src/views/MessageInput/index.tsx +7 -5
  344. package/src/views/MessageInput/styled.ts +28 -12
  345. package/src/views/MinimizedHeader.tsx +7 -4
  346. package/src/views/Stacks.tsx +54 -31
  347. package/src/views/Steps/FlowChart/NodeStep.tsx +4 -6
  348. package/src/views/Steps/StepModal.tsx +18 -14
  349. package/src/views/Steps/index.tsx +5 -4
  350. package/src/views/Steps/utils.tsx +9 -9
  351. package/src/views/Tools.tsx +19 -12
  352. package/src/views/Workspaces/WorkspacesTab.tsx +21 -17
  353. package/src/views/Workspaces/index.tsx +2 -4
@@ -1,15 +1,43 @@
1
- import { Tab, Tabs } from '@stack-spot/citric-react'
2
- import { useMemo } from 'react'
1
+ import { Tabs, TabsItem } from '@citric/ui'
2
+ import { useMemo, useState } from 'react'
3
+ import styled from 'styled-components'
3
4
  import { RightPanelForm } from './RightPanelForm'
4
5
 
6
+ interface Tab {
7
+ title: string,
8
+ content: React.ReactNode,
9
+ }
10
+
5
11
  interface Props {
6
12
  tabs: Tab[],
7
13
  }
8
14
 
15
+ const StyledTabs = styled(Tabs)`
16
+ > button {
17
+ flex: 1;
18
+ padding: 8px 0;
19
+ }
20
+ `
21
+
22
+ const StyledTabsItem = styled(TabsItem)`
23
+ flex: 1;
24
+ overflow: hidden;
25
+ `
26
+
9
27
  /**
10
28
  * Tabs for the right panel content.
11
29
  */
12
30
  export const RightPanelTabs = ({ tabs }: Props) => {
13
- const tabItems = useMemo(() => tabs.map(t => ({ ...t, content: <RightPanelForm>{t.content}</RightPanelForm> })), [tabs])
14
- return <Tabs tabs={tabItems} />
31
+ const [currentTab, setCurrentTab] = useState(0)
32
+ const tabItems = useMemo(() => tabs.map(({ content, title }) => (
33
+ <StyledTabsItem key={title} title={title}>
34
+ <RightPanelForm>{content}</RightPanelForm>
35
+ </StyledTabsItem>
36
+ )), [tabs])
37
+
38
+ return (
39
+ <StyledTabs activeIndex={currentTab} onChange={setCurrentTab}>
40
+ {tabItems}
41
+ </StyledTabs>
42
+ )
15
43
  }
@@ -1,4 +1,6 @@
1
- import { FallbackBoundary, IconLink, Text } from '@stack-spot/citric-react'
1
+ import { IconBox, Text } from '@citric/core'
2
+ import { ExternalLink } from '@citric/icons'
3
+ import { IconButton } from '@citric/ui'
2
4
  import { useKeyboardControls } from '@stack-spot/portal-components'
3
5
  import { AgentVisibilityLevel } from '@stack-spot/portal-network'
4
6
  import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
@@ -7,6 +9,7 @@ import { useCurrentChatState, useWidgetState } from '../../context/hooks'
7
9
  import { getUrlToStackSpotAI } from '../../utils/url'
8
10
  import { ButtonFavorite } from '../ButtonFavorite'
9
11
  import { Fading } from '../Fading'
12
+ import { FallbackBoundary } from '../FallbackBoundary'
10
13
  import { SelectorBox } from './styled'
11
14
 
12
15
  type SectionVisibility = AgentVisibilityLevel
@@ -97,17 +100,10 @@ const ListItem = <T extends Item>({ item, selectorConfig, onSelect, favorite }:
97
100
  >
98
101
  {renderComponentItem(item)}
99
102
  </button>
100
- <IconLink
101
- icon="ExternalLink"
102
- title={linkTitle}
103
- aria-label={linkTitle}
104
- href={`${getUrlToStackSpotAI()}${urlBuilder(item)}`}
105
- target="_blank"
106
- />
107
- <ButtonFavorite
108
- appearance="text"
109
- favorite={{ ...favorite, idOrSlug: favorite?.favoriteIsSlug ? item.slug : item?.id, listFavorites }}
110
- />
103
+ <IconButton as="a" title={linkTitle} aria-label={linkTitle} href={`${getUrlToStackSpotAI()}${urlBuilder(item)}`} target="_blank">
104
+ <ExternalLink />
105
+ </IconButton>
106
+ <ButtonFavorite favorite={{ ...favorite, idOrSlug: favorite?.favoriteIsSlug ? item.slug : item?.id, listFavorites }} isIconButton />
111
107
  </li>
112
108
  )
113
109
  }
@@ -132,9 +128,9 @@ const List = <T extends Item>({ selectorConfig, filter, visibility, onSelect, fa
132
128
  }, [filter, items, visibility, favorites])
133
129
 
134
130
 
135
- if (!items.length) return <Text className="empty" color="light.700">{interpolate(t.noData, selectorConfig.resourceName)}</Text>
131
+ if (!items.length) return <Text className="empty" colorScheme="light.700">{interpolate(t.noData, selectorConfig.resourceName)}</Text>
136
132
  if (!filtered?.length)
137
- <Text className="empty" color="light.700">{interpolate(t.noResults, selectorConfig.resourceName)}</Text>
133
+ <Text className="empty" colorScheme="light.700">{interpolate(t.noResults, selectorConfig.resourceName)}</Text>
138
134
 
139
135
  return (
140
136
  <ul className="selector-list">
@@ -184,8 +180,8 @@ const SelectorContent = ({ filter, onClose, selectorConfig, favorite }: ContentP
184
180
  return (
185
181
  <div ref={ref}>
186
182
  <header>
187
- {icon}
188
- <Text tag="h3">{resourceName}</Text>
183
+ <IconBox>{icon}</IconBox>
184
+ <Text as="h3" className="uppercase"> {resourceName} </Text>
189
185
  </header>
190
186
  <div className="body">
191
187
  {isGroupResourcesByScope && (
@@ -194,7 +190,7 @@ const SelectorContent = ({ filter, onClose, selectorConfig, favorite }: ContentP
194
190
  {sections.map(createSectionItem)}
195
191
  </ul>
196
192
  )}
197
- <FallbackBoundary message={interpolate(t.error, selectorConfig.resourceName)}>
193
+ <FallbackBoundary message={interpolate(t.error, selectorConfig.resourceName)} mini>
198
194
  <List filter={filter} visibility={visibility} selectorConfig={selectorConfig} onSelect={onSelectItem} favorite={favorite} />
199
195
  </FallbackBoundary>
200
196
  </div>
@@ -40,16 +40,13 @@ export const SelectorBox = styled.div<{ $tabsCount: number }>`
40
40
  flex-direction: row;
41
41
  gap: 8px;
42
42
  align-items: center;
43
- padding: 0 8px;
43
+ padding: 8px;
44
44
  margin-bottom: 4px;
45
+ font-family: 'San Francisco';
46
+ text-transform: uppercase;
47
+ font-weight: 500;
48
+ font-size: 11px;
45
49
  background-color: ${theme.color.light[500]};
46
- height: 40px;
47
- h3 {
48
- text-transform: uppercase;
49
- font-weight: 500;
50
- font-size: 12px;
51
- margin: 0;
52
- }
53
50
  }
54
51
 
55
52
  .body {
@@ -1,4 +1,4 @@
1
- import { Text } from '@stack-spot/citric-react'
1
+ import { IconBox, Text } from '@citric/core'
2
2
  import { theme } from '@stack-spot/portal-theme'
3
3
  import { DetailedHTMLProps, HTMLAttributes } from 'react'
4
4
  import { styled } from 'styled-components'
@@ -46,9 +46,9 @@ const Styled = styled.div`
46
46
  }
47
47
  }
48
48
 
49
- .citric-icon {
50
- margin: 1px;
51
- font-size: 10px;
49
+ i {
50
+ width: 12px;
51
+ height: 12px;
52
52
  }
53
53
 
54
54
  img, svg {
@@ -67,7 +67,7 @@ export const StackedBadge = ({ label, images, ...props }: Props) => (
67
67
  <li key={key || i}>
68
68
  {url
69
69
  ? <img alt={name} aria-label={name} title={name} src={url} />
70
- : <span aria-label={name} title={name}>{icon}</span>
70
+ : <IconBox size="xs" aria-label={name} title={name}>{icon}</IconBox>
71
71
  }
72
72
  </li>
73
73
  ),
@@ -1,6 +1,8 @@
1
1
  /* Tabs to select chat and add new chats */
2
2
 
3
- import { Button, IconBox, IconButton } from '@stack-spot/citric-react'
3
+ import { Button, IconBox } from '@citric/core'
4
+ import { TimesMini } from '@citric/icons'
5
+ import { IconButton } from '@citric/ui'
4
6
  import { listToClass, theme } from '@stack-spot/portal-theme'
5
7
  import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
6
8
  import { last } from 'lodash'
@@ -69,6 +71,14 @@ const Tabs = styled.nav<{ $numberOfExtraButtons: number }>`
69
71
  }
70
72
  }
71
73
 
74
+ ${IconButton} {
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: center;
78
+ background-color: transparent;
79
+ border: none;
80
+ }
81
+
72
82
  .list-overflow {
73
83
  max-width: ${({ $numberOfExtraButtons }) => `calc(100% - ${$numberOfExtraButtons * (EXTRA_BTN_SIZE + EXTRA_BTN_MARGIN * 2)}px)`};
74
84
  }
@@ -135,6 +145,21 @@ const Tabs = styled.nav<{ $numberOfExtraButtons: number }>`
135
145
  mask-image: linear-gradient(to right, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 1) 70%, rgba(0, 0, 0, 0) 100%);
136
146
  }
137
147
  }
148
+
149
+ ${IconButton} {
150
+ padding: 0;
151
+ width: 18px;
152
+ height: 18px;
153
+ transition: background-color 0.3s;
154
+
155
+ svg {
156
+ height: 14px;
157
+ }
158
+
159
+ &:hover {
160
+ background-color: ${theme.color.light[600]};
161
+ }
162
+ }
138
163
  }
139
164
  }
140
165
  `
@@ -160,33 +185,36 @@ export function TabManager<T, Key extends React.Key>(
160
185
  const tabItems = useMemo(() => tabs.map((tab) => (
161
186
  <li key={keygen(tab)} className={keygen(tab) === active ? 'active' : undefined} onClick={onClickTab}>
162
187
  <button className="label" onClick={() => onSelect(tab)}><FadingOverflow>{renderLabel(tab)}</FadingOverflow></button>
163
- {tabs.length > 1 && <IconButton icon="TimesMini" aria-label={t.close} title={t.close} onClick={() => onRemove(tab)} />}
188
+ {tabs.length > 1 && <IconButton aria-label={t.close} title={t.close} onClick={() => onRemove(tab)}><TimesMini /></IconButton>}
164
189
  </li>
165
190
  )), [tabs, active])
166
191
 
167
- const extras = useMemo(() => buttons.map(({ ariaLabel, label, onClick, group, icon, className, style }) => (
192
+ const extras = useMemo(() => buttons.map(({ ariaLabel, label, onClick, icon, className, style }) => (
168
193
  <>
169
194
  {label ?
170
195
  <Button
171
- style={{ ...style, paddingLeft: 0, marginRight: '4px', fontWeight: '400' }}
196
+ sx={{ paddingLeft: 0, marginRight: '4px', fontWeight: '400' }}
172
197
  colorScheme="light"
173
198
  size="md"
174
199
  key={ariaLabel}
175
200
  title={label}
201
+ style={style}
176
202
  onClick={onClick}>
177
- <IconBox group={group} icon={icon as any} size="sm" style={{ width: '32px', height: '16px', paddingInline: '8px' }} />
203
+ <IconBox size="sm" sx={{ width: '32px', height: '16px', paddingInline: '8px' }} >
204
+ {icon}
205
+ </IconBox>
178
206
  {label}
179
207
  </Button> :
180
208
  <IconButton
181
209
  key={ariaLabel}
182
- group={group}
183
- icon={icon as any}
184
210
  aria-label={ariaLabel}
185
211
  title={label}
186
212
  className={listToClass([className, 'extra'])}
187
213
  style={style}
188
214
  onClick={onClick}
189
- />}
215
+ >
216
+ {icon}
217
+ </IconButton>}
190
218
  </>)), [buttons])
191
219
 
192
220
  // when a new tab is added, we should scroll to it if there are more tabs that we can show.
@@ -1,58 +1,148 @@
1
- import { Icon } from '@stack-spot/citric-icons'
2
- import { Accordion, Card, ImageBox, ImageWithFallback, Text } from '@stack-spot/citric-react'
3
- import { theme } from '@stack-spot/portal-theme'
1
+ import { IconBox, Text } from '@citric/core'
2
+ import { ChevronDown, Cog } from '@citric/icons'
3
+ import { IconButton } from '@citric/ui'
4
+ import { AnimatedHeight } from '@stack-spot/portal-components/AnimatedHeight'
5
+ import { ColorSchemeKey, listToClass, theme } from '@stack-spot/portal-theme'
6
+ import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
7
+ import { get } from 'lodash'
8
+ import { DetailedHTMLProps, HTMLAttributes, useState } from 'react'
4
9
  import { styled } from 'styled-components'
10
+ import { FastOmit } from 'styled-components/dist/types'
5
11
  import { toPrecision } from '../views/Steps/utils'
6
12
 
7
- type Props = Omit<React.JSX.IntrinsicElements['div'], 'onChange'> & {
13
+ interface Props extends FastOmit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> {
8
14
  name: string,
9
15
  duration?: number,
10
16
  image?: string,
11
17
  description?: string,
18
+ appearance?: 'round' | 'square',
19
+ backgroundColor?: ColorSchemeKey,
12
20
  }
13
21
 
14
- const Styled = styled.div`
15
- [data-citric="card"] {
16
- flex-direction: row;
17
- gap: 8px;
18
- border-radius: ${theme.radius.xl};
19
- border: none;
20
- align-items: center;
21
- padding: 4px 16px 4px 4px;
22
+ const Styled = styled.div<{ $backgroundColor: ColorSchemeKey }>`
23
+ .tool-header-wrapper {
24
+ background-color: ${({ $backgroundColor }) => get(theme.color, $backgroundColor)};
25
+ border-radius: 8px;
22
26
  }
27
+
28
+ .tool-header {
29
+ padding: 4px 8px 4px 4px;
30
+ display: flex;
31
+ flex-direction: column;
32
+ gap: 12px;
33
+ position: relative;
23
34
 
24
- [data-citric="accordion"] {
25
- background-color: ${theme.color.light[500]};
26
- > header > label {
27
- padding: 6px 10px 6px 6px;
28
- font: ${theme.font.body2};
29
- input:before {
30
- font-size: 12px !important;
35
+ .title {
36
+ display: flex;
37
+ gap: 8px;
38
+ align-items: center;
39
+ .tool-image {
40
+ width: 24px;
41
+ height: 24px;
42
+ border-radius: 50%;
43
+ overflow: hidden;
44
+ flex-shrink: 0;
45
+ }
46
+ .name {
47
+ flex: 1;
48
+ overflow: hidden;
49
+ text-overflow: ellipsis;
50
+ }
51
+ }
52
+
53
+ .btn-expand {
54
+ display: none;
55
+ }
56
+
57
+ .duration {
58
+ opacity: 0.7;
59
+ text-align: right;
60
+ }
61
+ }
62
+
63
+ &.with-description {
64
+ .tool-header {
65
+ &:before {
66
+ content: '';
67
+ top: 32px;
68
+ bottom: 8px;
69
+ left: 15px;
70
+ width: 1px;
71
+ background-color: ${theme.color.light[700]};
72
+ opacity: 0.3;
73
+ position: absolute;
74
+ }
75
+
76
+ .btn-expand {
77
+ display: flex;
78
+ transition: transform 0.3s ease-in-out;
79
+ &.open {
80
+ transform: rotate(180deg);
81
+ }
82
+ }
83
+
84
+ .description {
85
+ padding: 0 0 10px 20px;
86
+ opacity: 0.7;
87
+ }
88
+ }
89
+ }
90
+
91
+ &.round {
92
+ .tool-header-wrapper {
93
+ border-radius: 30px;
94
+ }
95
+ &:not(.with-description) {
96
+ .tool-header-wrapper {
97
+ padding-right: 10px;
31
98
  }
32
99
  }
33
100
  }
34
101
  `
35
102
 
36
103
  export const ToolBadge = (
37
- { name, duration, image, description, ...props }: Props,
104
+ { name, duration, image, description, appearance = 'square', backgroundColor = 'light.300', className, ...props }: Props,
38
105
  ) => {
39
- const header = <>
40
- <ImageBox><ImageWithFallback src={image} fallback={<Icon icon="Cog" className="tool-image" />} /></ImageBox>
41
- <Text color="light.700" className="name" style={{ flex: 1 }}>{name}</Text>
42
- {duration !== undefined && <Text color="light.700" className="duration">
43
- {toPrecision(duration)}s
44
- </Text>}
45
- </>
46
-
47
- return <Styled>
48
- {description ? (
49
- <Accordion
50
- appearance="card"
51
- header={header}
52
- {...props}
53
- >
54
- <Text className="description" color="light.700">{description}</Text>
55
- </Accordion>
56
- ) : <Card {...props}>{header}</Card>}
57
- </Styled>
106
+ const t = useTranslate(dictionary)
107
+ const [showDescription, setShowDescription] = useState(false)
108
+ const rootClass = listToClass([className, appearance, description && 'with-description'])
109
+ const wrapperClass = 'tool-header-wrapper'
110
+
111
+ const content = (
112
+ <div className="tool-header">
113
+ <div className="title">
114
+ {image ? <img src={image} className="tool-image" /> : <IconBox className="tool-image"><Cog /></IconBox>}
115
+ <Text colorScheme="light.700" className="name">{name}</Text>
116
+ {duration !== undefined && <Text colorScheme="light.700" className="duration">
117
+ {toPrecision(duration)}s
118
+ </Text>}
119
+ <IconButton
120
+ size="xs"
121
+ className={listToClass(['btn-expand', showDescription && 'open'])}
122
+ onClick={() => setShowDescription(v => !v)}
123
+ aria-label={showDescription ? t.close : t.open}
124
+ >
125
+ <ChevronDown />
126
+ </IconButton>
127
+ </div>
128
+ {showDescription && <Text className="description" colorScheme="light.700">{description}</Text>}
129
+ </div>
130
+ )
131
+
132
+ return (
133
+ <Styled {...props} $backgroundColor={backgroundColor} className={rootClass}>
134
+ {description ? <AnimatedHeight className={wrapperClass}>{content}</AnimatedHeight> : <div className={wrapperClass}>{content}</div>}
135
+ </Styled>
136
+ )
58
137
  }
138
+
139
+ const dictionary = {
140
+ en: {
141
+ open: 'Open',
142
+ close: 'Close',
143
+ },
144
+ pt: {
145
+ open: 'Abrir',
146
+ close: 'Fechar',
147
+ },
148
+ } satisfies Dictionary
@@ -0,0 +1,78 @@
1
+ /* eslint-disable react/display-name */
2
+ import { Text } from '@citric/core'
3
+ import { WithStyle } from '@stack-spot/portal-theme'
4
+ import { forwardRef } from 'react'
5
+ import { WithChildren } from '../../types'
6
+ import { useTooltip } from './context'
7
+ import { DefaultTooltip } from './style'
8
+ import { TooltipPosition } from './types'
9
+
10
+ interface Props extends WithChildren, WithStyle {
11
+ /**
12
+ * The content of the tooltip. Can be either a string or a Rect Element.
13
+ */
14
+ content: React.ReactNode,
15
+ /**
16
+ * Where to position the tooltip relative to the element that triggered it.
17
+ */
18
+ position?: TooltipPosition,
19
+ /**
20
+ * A tooltip can be triggered either by hovering an element or by clicking it.
21
+ * @default 'hover'
22
+ */
23
+ triggeredBy?: 'click' | 'hover',
24
+ /**
25
+ * If true, no style is applied to the tooltip, letting you customize it however you want to.
26
+ */
27
+ custom?: boolean,
28
+ /**
29
+ * Function to run whenever the tooltip is shown.
30
+ */
31
+ onShow?: () => void,
32
+ /**
33
+ * Function to run whenever the tooltip is hidden.
34
+ */
35
+ onHide?: () => void,
36
+ }
37
+
38
+ /**
39
+ * Shows a tooltip for its children. This tooltip element is always reused and placed at a root level in order to not be cut out by
40
+ * hidden overflows in the children and its ascendants.
41
+ */
42
+ export const Tooltip = forwardRef<HTMLDivElement, Props>((
43
+ { content, custom, position, triggeredBy = 'hover', onHide, onShow, children, className, style },
44
+ ref,
45
+ ) => {
46
+ const api = useTooltip()
47
+
48
+ async function show(e: React.UIEvent, hideOnClickOutside?: boolean) {
49
+ await api.show({
50
+ content: custom ? content : <DefaultTooltip><Text appearance="microtext1">{content}</Text></DefaultTooltip>,
51
+ anchor: e.target as HTMLElement,
52
+ position,
53
+ hideOnClickOutside,
54
+ })
55
+ onShow?.()
56
+ }
57
+
58
+ function hide() {
59
+ api.hide()
60
+ onHide?.()
61
+ }
62
+
63
+ return (
64
+ <div
65
+ {...(triggeredBy === 'hover'
66
+ ? { onMouseEnter: show, onMouseLeave: hide }
67
+ : { onClick: (e) => show(e, true), onKeyDown: (e) => e.key === 'Enter' && show(e, true) }
68
+ )}
69
+ className={className}
70
+ style={style}
71
+ tabIndex={triggeredBy === 'click' ? 0 : undefined}
72
+ role={triggeredBy === 'click' ? 'button' : undefined}
73
+ ref={ref}
74
+ >
75
+ {children}
76
+ </div>
77
+ )
78
+ })
@@ -0,0 +1,101 @@
1
+ import { delay } from '@stack-spot/portal-components'
2
+ import { animationTimeMS } from './style'
3
+ import { ShowOptions } from './types'
4
+
5
+ // the maximum amount of pixels a tooltip can get close to the screen edges.
6
+ const MARGIN_TO_CORNERS_PX = 10
7
+
8
+ function isRelative(element: HTMLElement) {
9
+ return ['relative', 'absolute', 'fixed'].includes(element.computedStyleMap().get('position')?.toString() ?? '')
10
+ }
11
+
12
+ /**
13
+ * Allows interaction with the tooltip element.
14
+ *
15
+ * This places the tooltip element at the correct place, shows it, hides it and manages its contents.
16
+ *
17
+ * This also takes into account the screen edges, making adjustments to the tooltip position if it would overflow the screen.
18
+ */
19
+ export class TooltipAPI {
20
+ /**
21
+ * A reference to the tooltip element in the HTML tree.
22
+ */
23
+ tooltipRef: React.RefObject<HTMLDivElement>
24
+ private setContent: React.Dispatch<React.SetStateAction<React.ReactNode>>
25
+ private hideTimeoutId: number | undefined
26
+ private clickListener: ((e: MouseEvent) => void) | undefined
27
+ private relativeTo: HTMLElement | undefined
28
+
29
+ constructor(tooltipRef: React.RefObject<HTMLDivElement>, setContent: React.Dispatch<React.SetStateAction<React.ReactNode>>) {
30
+ this.tooltipRef = tooltipRef
31
+ this.setContent = setContent
32
+ }
33
+
34
+ private computeRelativeTo() {
35
+ if (this.relativeTo) return
36
+ this.relativeTo = this.tooltipRef.current?.parentElement as HTMLElement
37
+ while (this.relativeTo && this.relativeTo !== document.body && !isRelative(this.relativeTo)) {
38
+ this.relativeTo = this.relativeTo.parentElement as HTMLElement
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Shows the tooltip with `content`. Its position is based on `position` and the position of the element referred by `anchor`.
44
+ */
45
+ async show({ content, anchor, position = 'bottom', hideOnClickOutside }: ShowOptions) {
46
+ window.clearTimeout(this.hideTimeoutId)
47
+ this.hideTimeoutId = undefined
48
+ if (this.clickListener) document.removeEventListener('click', this.clickListener)
49
+ this.setContent(content)
50
+ await delay(10)
51
+ if (!this.tooltipRef.current) return
52
+ const anchorRect = anchor.getClientRects()[0]
53
+ this.tooltipRef.current.classList.add('visible')
54
+ const tooltipWidth = this.tooltipRef.current.clientWidth
55
+ const tooltipHeight = this.tooltipRef.current.clientHeight
56
+ let top = 0
57
+ let left = 0
58
+ if (position === 'left' || position === 'right') {
59
+ top = anchorRect.top + anchorRect.height / 2 - tooltipHeight / 2
60
+ if (position === 'left') left = anchorRect.left - tooltipWidth
61
+ else left = anchorRect.left + anchorRect.width
62
+ } else {
63
+ left = anchorRect.left + anchorRect.width / 2 - tooltipWidth / 2
64
+ if (position === 'top') top = anchorRect.top - tooltipHeight
65
+ else top = anchorRect.top + anchorRect.height
66
+ }
67
+ // takes the parent the tooltip is positioned relative to into consideration
68
+ this.computeRelativeTo()
69
+ const relativeRect = this.relativeTo?.getClientRects()[0] ?? { top: 0, left: 0 }
70
+ top -= relativeRect.top
71
+ left -= relativeRect.left
72
+ // adjusts positions in order to avoid overflowing the window and leaving a margin to the corners
73
+ if (top <= 0) top += MARGIN_TO_CORNERS_PX
74
+ else if (top + tooltipHeight >= document.body.clientHeight - MARGIN_TO_CORNERS_PX) {
75
+ top = document.body.clientHeight - MARGIN_TO_CORNERS_PX + tooltipHeight
76
+ }
77
+ if (left <= 0) left += MARGIN_TO_CORNERS_PX
78
+ else if (left + tooltipWidth >= document.body.clientWidth - MARGIN_TO_CORNERS_PX) {
79
+ left = document.body.clientWidth - MARGIN_TO_CORNERS_PX - tooltipWidth
80
+ }
81
+ this.tooltipRef.current.style.top = `${top}px`
82
+ this.tooltipRef.current.style.left = `${left}px`
83
+ if (hideOnClickOutside) {
84
+ this.clickListener = (e: MouseEvent) => {
85
+ if (this.tooltipRef.current?.contains(e.target as HTMLElement)) return
86
+ this.hide()
87
+ }
88
+ document.addEventListener('click', this.clickListener)
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Hides the tooltip. After the animation, the content is removed.
94
+ */
95
+ hide(): void {
96
+ if (!this.tooltipRef.current) return
97
+ this.tooltipRef.current.classList.remove('visible')
98
+ this.hideTimeoutId = window.setTimeout(() => this.setContent(undefined), animationTimeMS)
99
+ if (this.clickListener) document.removeEventListener('click', this.clickListener)
100
+ }
101
+ }
@@ -0,0 +1,24 @@
1
+ import { createContext, useContext, useMemo, useRef, useState } from 'react'
2
+ import { WithChildren } from '../../types'
3
+ import { TooltipBox } from './style'
4
+ import { TooltipAPI } from './TooltipAPI'
5
+
6
+ const Context = createContext<TooltipAPI | undefined>(undefined)
7
+
8
+ export const TooltipProvider = ({ children }: Required<WithChildren>) => {
9
+ const ref = useRef<HTMLDivElement>(null)
10
+ const [content, setContent] = useState<React.ReactNode>()
11
+ const api = useMemo(() => new TooltipAPI(ref, setContent), [])
12
+ return (
13
+ <Context.Provider value={api}>
14
+ {children}
15
+ <TooltipBox ref={ref}>{content}</TooltipBox>
16
+ </Context.Provider>
17
+ )
18
+ }
19
+
20
+ export function useTooltip() {
21
+ const api = useContext(Context)
22
+ if (!api) throw new Error('In order to use tooltips, you must wrap your content in a <TooltipProvider>.')
23
+ return api
24
+ }
@@ -0,0 +1,2 @@
1
+ export { TooltipProvider } from './context'
2
+ export { Tooltip } from './Tooltip'