@databiosphere/findable-ui 49.0.0 → 49.2.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 (315) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +26 -0
  3. package/lib/common/ai/config/types.d.ts +22 -0
  4. package/lib/common/ai/config/types.js +1 -0
  5. package/lib/common/ai/constants.d.ts +3 -0
  6. package/lib/common/ai/constants.js +3 -0
  7. package/lib/components/Filter/components/FilterLabel/filterLabel.js +1 -1
  8. package/lib/components/Filter/components/FilterLabel/filterLabel.stories.d.ts +3 -0
  9. package/lib/components/Filter/components/FilterLabel/filterLabel.stories.js +5 -0
  10. package/lib/components/Filter/components/Filters/stories/constants.js +21 -1
  11. package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.styles.js +2 -0
  12. package/lib/components/Layout/components/Sidebar/components/SidebarTools/sidebarTools.styles.d.ts +4 -0
  13. package/lib/components/Layout/components/Sidebar/components/SidebarTools/sidebarTools.styles.js +4 -0
  14. package/lib/components/common/Chip/components/Beta/beta.d.ts +10 -0
  15. package/lib/components/common/Chip/components/Beta/beta.js +12 -0
  16. package/lib/components/common/Chip/components/Beta/beta.styles.d.ts +3 -0
  17. package/lib/components/common/Chip/components/Beta/beta.styles.js +14 -0
  18. package/lib/components/common/Chip/components/Beta/stories/beta.stories.d.ts +6 -0
  19. package/lib/components/common/Chip/components/Beta/stories/beta.stories.js +6 -0
  20. package/lib/components/common/CustomIcon/components/UpArrowIcon/upArrowIcon.d.ts +6 -0
  21. package/lib/components/common/CustomIcon/components/UpArrowIcon/upArrowIcon.js +8 -0
  22. package/lib/components/common/Tabs/tabs.js +1 -1
  23. package/lib/components/common/ToggleButtonGroup/provider/context.d.ts +2 -0
  24. package/lib/components/common/ToggleButtonGroup/provider/context.js +5 -0
  25. package/lib/components/common/ToggleButtonGroup/provider/hook.d.ts +7 -0
  26. package/lib/components/common/ToggleButtonGroup/provider/hook.js +9 -0
  27. package/lib/components/common/ToggleButtonGroup/provider/provider.d.ts +12 -0
  28. package/lib/components/common/ToggleButtonGroup/provider/provider.js +22 -0
  29. package/lib/components/common/ToggleButtonGroup/provider/types.d.ts +9 -0
  30. package/lib/components/common/ToggleButtonGroup/provider/types.js +1 -0
  31. package/lib/config/entities.d.ts +2 -0
  32. package/lib/hooks/ai/useAiRoutes/hook.d.ts +6 -0
  33. package/lib/hooks/ai/useAiRoutes/hook.js +18 -0
  34. package/lib/styles/common/mui/drawer.d.ts +9 -0
  35. package/lib/styles/common/mui/drawer.js +15 -0
  36. package/lib/styles/common/mui/inputBase.d.ts +13 -0
  37. package/lib/styles/common/mui/inputBase.js +25 -0
  38. package/lib/styles/common/mui/stack.d.ts +11 -0
  39. package/lib/styles/common/mui/stack.js +22 -0
  40. package/lib/tests/testIds.d.ts +3 -0
  41. package/lib/tests/testIds.js +3 -0
  42. package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.d.ts +6 -0
  43. package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.js +17 -0
  44. package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.styles.d.ts +6 -0
  45. package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.styles.js +23 -0
  46. package/lib/views/ExploreView/entityList/filters/filters.styles.d.ts +7 -0
  47. package/lib/views/ExploreView/entityList/filters/filters.styles.js +17 -0
  48. package/lib/views/ExploreView/exploreView.js +3 -2
  49. package/lib/views/ResearchView/assistant/assistant.d.ts +6 -0
  50. package/lib/views/ResearchView/assistant/assistant.js +16 -0
  51. package/lib/views/ResearchView/assistant/components/Drawer/drawer.d.ts +9 -0
  52. package/lib/views/ResearchView/assistant/components/Drawer/drawer.js +15 -0
  53. package/lib/views/ResearchView/assistant/components/Drawer/drawer.styles.d.ts +4 -0
  54. package/lib/views/ResearchView/assistant/components/Drawer/drawer.styles.js +21 -0
  55. package/lib/views/ResearchView/assistant/components/Drawer/types.d.ts +4 -0
  56. package/lib/views/ResearchView/assistant/components/Drawer/types.js +1 -0
  57. package/lib/views/ResearchView/assistant/components/Form/constants.d.ts +3 -0
  58. package/lib/views/ResearchView/assistant/components/Form/constants.js +3 -0
  59. package/lib/views/ResearchView/assistant/components/Form/form.d.ts +11 -0
  60. package/lib/views/ResearchView/assistant/components/Form/form.js +27 -0
  61. package/lib/views/ResearchView/assistant/components/Form/form.styles.d.ts +4 -0
  62. package/lib/views/ResearchView/assistant/components/Form/form.styles.js +7 -0
  63. package/lib/views/ResearchView/assistant/components/Form/types.d.ts +3 -0
  64. package/lib/views/ResearchView/assistant/components/Form/types.js +1 -0
  65. package/lib/views/ResearchView/assistant/components/Form/utils.d.ts +16 -0
  66. package/lib/views/ResearchView/assistant/components/Form/utils.js +41 -0
  67. package/lib/views/ResearchView/assistant/components/Input/constants.d.ts +2 -0
  68. package/lib/views/ResearchView/assistant/components/Input/constants.js +14 -0
  69. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/constants.d.ts +7 -0
  70. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/constants.js +7 -0
  71. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/hook.d.ts +6 -0
  72. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/hook.js +32 -0
  73. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/types.d.ts +8 -0
  74. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/types.js +1 -0
  75. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/utils.d.ts +32 -0
  76. package/lib/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/utils.js +74 -0
  77. package/lib/views/ResearchView/assistant/components/Input/input.d.ts +9 -0
  78. package/lib/views/ResearchView/assistant/components/Input/input.js +19 -0
  79. package/lib/views/ResearchView/assistant/components/Input/input.styles.d.ts +8 -0
  80. package/lib/views/ResearchView/assistant/components/Input/input.styles.js +19 -0
  81. package/lib/views/ResearchView/assistant/components/Input/stories/input.stories.d.ts +6 -0
  82. package/lib/views/ResearchView/assistant/components/Input/stories/input.stories.js +11 -0
  83. package/lib/views/ResearchView/assistant/components/Input/types.d.ts +2 -0
  84. package/lib/views/ResearchView/assistant/components/Input/types.js +1 -0
  85. package/lib/views/ResearchView/assistant/components/Input/utils.d.ts +9 -0
  86. package/lib/views/ResearchView/assistant/components/Input/utils.js +25 -0
  87. package/lib/views/ResearchView/assistant/components/Messages/components/AssistantMessage/assistantMessage.d.ts +9 -0
  88. package/lib/views/ResearchView/assistant/components/Messages/components/AssistantMessage/assistantMessage.js +15 -0
  89. package/lib/views/ResearchView/assistant/components/Messages/components/AssistantMessage/types.d.ts +4 -0
  90. package/lib/views/ResearchView/assistant/components/Messages/components/AssistantMessage/types.js +1 -0
  91. package/lib/views/ResearchView/assistant/components/Messages/components/AssistantMessage/utils.d.ts +13 -0
  92. package/lib/views/ResearchView/assistant/components/Messages/components/AssistantMessage/utils.js +25 -0
  93. package/lib/views/ResearchView/assistant/components/Messages/components/ErrorMessage/errorMessage.d.ts +9 -0
  94. package/lib/views/ResearchView/assistant/components/Messages/components/ErrorMessage/errorMessage.js +12 -0
  95. package/lib/views/ResearchView/assistant/components/Messages/components/ErrorMessage/types.d.ts +4 -0
  96. package/lib/views/ResearchView/assistant/components/Messages/components/ErrorMessage/types.js +1 -0
  97. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/chips.d.ts +3 -0
  98. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/chips.js +10 -0
  99. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/chips.styles.d.ts +3 -0
  100. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/chips.styles.js +26 -0
  101. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/types.d.ts +5 -0
  102. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/types.js +1 -0
  103. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/promptMessage.d.ts +10 -0
  104. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/promptMessage.js +14 -0
  105. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/types.d.ts +5 -0
  106. package/lib/views/ResearchView/assistant/components/Messages/components/PromptMessage/types.js +1 -0
  107. package/lib/views/ResearchView/assistant/components/Messages/components/UserMessage/types.d.ts +4 -0
  108. package/lib/views/ResearchView/assistant/components/Messages/components/UserMessage/types.js +1 -0
  109. package/lib/views/ResearchView/assistant/components/Messages/components/UserMessage/useMessage.styles.d.ts +5 -0
  110. package/lib/views/ResearchView/assistant/components/Messages/components/UserMessage/useMessage.styles.js +10 -0
  111. package/lib/views/ResearchView/assistant/components/Messages/components/UserMessage/userMessage.d.ts +9 -0
  112. package/lib/views/ResearchView/assistant/components/Messages/components/UserMessage/userMessage.js +13 -0
  113. package/lib/views/ResearchView/assistant/components/Messages/hooks/UseScroll/hook.d.ts +8 -0
  114. package/lib/views/ResearchView/assistant/components/Messages/hooks/UseScroll/hook.js +20 -0
  115. package/lib/views/ResearchView/assistant/components/Messages/messages.d.ts +9 -0
  116. package/lib/views/ResearchView/assistant/components/Messages/messages.js +16 -0
  117. package/lib/views/ResearchView/assistant/components/Messages/messages.styles.d.ts +3 -0
  118. package/lib/views/ResearchView/assistant/components/Messages/messages.styles.js +9 -0
  119. package/lib/views/ResearchView/assistant/components/Messages/selector/messageSelector.d.ts +17 -0
  120. package/lib/views/ResearchView/assistant/components/Messages/selector/messageSelector.js +32 -0
  121. package/lib/views/ResearchView/assistant/components/Messages/selector/types.d.ts +5 -0
  122. package/lib/views/ResearchView/assistant/components/Messages/selector/types.js +1 -0
  123. package/lib/views/ResearchView/assistant/components/Messages/stories/args.d.ts +3 -0
  124. package/lib/views/ResearchView/assistant/components/Messages/stories/args.js +109 -0
  125. package/lib/views/ResearchView/assistant/components/Messages/stories/messages.stories.d.ts +6 -0
  126. package/lib/views/ResearchView/assistant/components/Messages/stories/messages.stories.js +14 -0
  127. package/lib/views/ResearchView/assistant/components/Messages/types.d.ts +4 -0
  128. package/lib/views/ResearchView/assistant/components/Messages/types.js +1 -0
  129. package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/stories/toggleButtonGroup.stories.d.ts +6 -0
  130. package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/stories/toggleButtonGroup.stories.js +12 -0
  131. package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.d.ts +6 -0
  132. package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.js +16 -0
  133. package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.styles.d.ts +6 -0
  134. package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.styles.js +20 -0
  135. package/lib/views/ResearchView/assistant/stories/args.d.ts +4 -0
  136. package/lib/views/ResearchView/assistant/stories/args.js +30 -0
  137. package/lib/views/ResearchView/assistant/stories/assistant.stories.d.ts +6 -0
  138. package/lib/views/ResearchView/assistant/stories/assistant.stories.js +23 -0
  139. package/lib/views/ResearchView/query/constants.d.ts +5 -0
  140. package/lib/views/ResearchView/query/constants.js +5 -0
  141. package/lib/views/ResearchView/query/fetch.d.ts +17 -0
  142. package/lib/views/ResearchView/query/fetch.js +44 -0
  143. package/lib/views/ResearchView/researchView.d.ts +10 -0
  144. package/lib/views/ResearchView/researchView.js +13 -0
  145. package/lib/views/ResearchView/state/actions/setError/action.d.ts +10 -0
  146. package/lib/views/ResearchView/state/actions/setError/action.js +17 -0
  147. package/lib/views/ResearchView/state/actions/setError/dispatch.d.ts +7 -0
  148. package/lib/views/ResearchView/state/actions/setError/dispatch.js +12 -0
  149. package/lib/views/ResearchView/state/actions/setError/types.d.ts +14 -0
  150. package/lib/views/ResearchView/state/actions/setError/types.js +1 -0
  151. package/lib/views/ResearchView/state/actions/setMessage/action.d.ts +10 -0
  152. package/lib/views/ResearchView/state/actions/setMessage/action.js +21 -0
  153. package/lib/views/ResearchView/state/actions/setMessage/dispatch.d.ts +7 -0
  154. package/lib/views/ResearchView/state/actions/setMessage/dispatch.js +12 -0
  155. package/lib/views/ResearchView/state/actions/setMessage/types.d.ts +15 -0
  156. package/lib/views/ResearchView/state/actions/setMessage/types.js +1 -0
  157. package/lib/views/ResearchView/state/actions/setQuery/action.d.ts +10 -0
  158. package/lib/views/ResearchView/state/actions/setQuery/action.js +17 -0
  159. package/lib/views/ResearchView/state/actions/setQuery/dispatch.d.ts +7 -0
  160. package/lib/views/ResearchView/state/actions/setQuery/dispatch.js +12 -0
  161. package/lib/views/ResearchView/state/actions/setQuery/types.d.ts +14 -0
  162. package/lib/views/ResearchView/state/actions/setQuery/types.js +1 -0
  163. package/lib/views/ResearchView/state/actions/setStatus/action.d.ts +10 -0
  164. package/lib/views/ResearchView/state/actions/setStatus/action.js +13 -0
  165. package/lib/views/ResearchView/state/actions/setStatus/dispatch.d.ts +7 -0
  166. package/lib/views/ResearchView/state/actions/setStatus/dispatch.js +12 -0
  167. package/lib/views/ResearchView/state/actions/setStatus/types.d.ts +14 -0
  168. package/lib/views/ResearchView/state/actions/setStatus/types.js +1 -0
  169. package/lib/views/ResearchView/state/actions/types.d.ts +17 -0
  170. package/lib/views/ResearchView/state/actions/types.js +10 -0
  171. package/lib/views/ResearchView/state/constants.d.ts +5 -0
  172. package/lib/views/ResearchView/state/constants.js +7 -0
  173. package/lib/views/ResearchView/state/context.d.ts +5 -0
  174. package/lib/views/ResearchView/state/context.js +9 -0
  175. package/lib/views/ResearchView/state/guards/guards.d.ts +33 -0
  176. package/lib/views/ResearchView/state/guards/guards.js +41 -0
  177. package/lib/views/ResearchView/state/hooks/UseChatDispatch/hook.d.ts +6 -0
  178. package/lib/views/ResearchView/state/hooks/UseChatDispatch/hook.js +26 -0
  179. package/lib/views/ResearchView/state/hooks/UseChatDispatch/types.d.ts +10 -0
  180. package/lib/views/ResearchView/state/hooks/UseChatDispatch/types.js +1 -0
  181. package/lib/views/ResearchView/state/hooks/UseChatReducer/hook.d.ts +8 -0
  182. package/lib/views/ResearchView/state/hooks/UseChatReducer/hook.js +12 -0
  183. package/lib/views/ResearchView/state/hooks/UseChatState/hook.d.ts +7 -0
  184. package/lib/views/ResearchView/state/hooks/UseChatState/hook.js +11 -0
  185. package/lib/views/ResearchView/state/initializer/initializer.d.ts +8 -0
  186. package/lib/views/ResearchView/state/initializer/initializer.js +22 -0
  187. package/lib/views/ResearchView/state/initializer/types.d.ts +2 -0
  188. package/lib/views/ResearchView/state/initializer/types.js +1 -0
  189. package/lib/views/ResearchView/state/provider.d.ts +19 -0
  190. package/lib/views/ResearchView/state/provider.js +20 -0
  191. package/lib/views/ResearchView/state/query/context.d.ts +5 -0
  192. package/lib/views/ResearchView/state/query/context.js +7 -0
  193. package/lib/views/ResearchView/state/query/hooks/UseQuery/hook.d.ts +6 -0
  194. package/lib/views/ResearchView/state/query/hooks/UseQuery/hook.js +9 -0
  195. package/lib/views/ResearchView/state/query/hooks/UseSubmit/hook.d.ts +7 -0
  196. package/lib/views/ResearchView/state/query/hooks/UseSubmit/hook.js +46 -0
  197. package/lib/views/ResearchView/state/query/provider.d.ts +13 -0
  198. package/lib/views/ResearchView/state/query/provider.js +15 -0
  199. package/lib/views/ResearchView/state/query/types.d.ts +24 -0
  200. package/lib/views/ResearchView/state/query/types.js +1 -0
  201. package/lib/views/ResearchView/state/reducer.d.ts +10 -0
  202. package/lib/views/ResearchView/state/reducer.js +32 -0
  203. package/lib/views/ResearchView/state/types.d.ts +125 -0
  204. package/lib/views/ResearchView/state/types.js +22 -0
  205. package/package.json +1 -1
  206. package/src/common/ai/config/types.ts +25 -0
  207. package/src/common/ai/constants.ts +3 -0
  208. package/src/components/Filter/components/FilterLabel/filterLabel.stories.tsx +6 -0
  209. package/src/components/Filter/components/FilterLabel/filterLabel.tsx +6 -1
  210. package/src/components/Filter/components/Filters/stories/constants.ts +25 -1
  211. package/src/components/Filter/components/SearchAllFilters/searchAllFilters.styles.ts +2 -0
  212. package/src/components/Layout/components/Sidebar/components/SidebarTools/sidebarTools.styles.ts +4 -0
  213. package/src/components/common/Chip/components/Beta/beta.styles.ts +15 -0
  214. package/src/components/common/Chip/components/Beta/beta.tsx +25 -0
  215. package/src/components/common/Chip/components/Beta/stories/beta.stories.tsx +12 -0
  216. package/src/components/common/CustomIcon/components/UpArrowIcon/upArrowIcon.tsx +21 -0
  217. package/src/components/common/Tabs/tabs.tsx +5 -1
  218. package/src/components/common/ToggleButtonGroup/provider/context.ts +9 -0
  219. package/src/components/common/ToggleButtonGroup/provider/hook.ts +16 -0
  220. package/src/components/common/ToggleButtonGroup/provider/provider.tsx +37 -0
  221. package/src/components/common/ToggleButtonGroup/provider/types.ts +17 -0
  222. package/src/config/entities.ts +2 -0
  223. package/src/hooks/ai/useAiRoutes/hook.ts +22 -0
  224. package/src/styles/common/mui/drawer.ts +24 -0
  225. package/src/styles/common/mui/inputBase.ts +38 -0
  226. package/src/styles/common/mui/stack.ts +33 -0
  227. package/src/tests/testIds.ts +3 -0
  228. package/src/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.styles.ts +25 -0
  229. package/src/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.tsx +35 -0
  230. package/src/views/ExploreView/entityList/filters/filters.styles.ts +19 -0
  231. package/src/views/ExploreView/exploreView.tsx +16 -12
  232. package/src/views/ResearchView/assistant/assistant.tsx +28 -0
  233. package/src/views/ResearchView/assistant/components/Drawer/drawer.styles.ts +24 -0
  234. package/src/views/ResearchView/assistant/components/Drawer/drawer.tsx +26 -0
  235. package/src/views/ResearchView/assistant/components/Drawer/types.ts +5 -0
  236. package/src/views/ResearchView/assistant/components/Form/constants.ts +3 -0
  237. package/src/views/ResearchView/assistant/components/Form/form.styles.ts +8 -0
  238. package/src/views/ResearchView/assistant/components/Form/form.tsx +40 -0
  239. package/src/views/ResearchView/assistant/components/Form/types.ts +9 -0
  240. package/src/views/ResearchView/assistant/components/Form/utils.ts +51 -0
  241. package/src/views/ResearchView/assistant/components/Input/constants.ts +16 -0
  242. package/src/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/constants.ts +7 -0
  243. package/src/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/hook.ts +45 -0
  244. package/src/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/types.ts +10 -0
  245. package/src/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/utils.ts +93 -0
  246. package/src/views/ResearchView/assistant/components/Input/input.styles.ts +21 -0
  247. package/src/views/ResearchView/assistant/components/Input/input.tsx +37 -0
  248. package/src/views/ResearchView/assistant/components/Input/stories/input.stories.tsx +21 -0
  249. package/src/views/ResearchView/assistant/components/Input/types.ts +3 -0
  250. package/src/views/ResearchView/assistant/components/Input/utils.ts +34 -0
  251. package/src/views/ResearchView/assistant/components/Messages/components/AssistantMessage/assistantMessage.tsx +49 -0
  252. package/src/views/ResearchView/assistant/components/Messages/components/AssistantMessage/types.ts +5 -0
  253. package/src/views/ResearchView/assistant/components/Messages/components/AssistantMessage/utils.ts +31 -0
  254. package/src/views/ResearchView/assistant/components/Messages/components/ErrorMessage/errorMessage.tsx +21 -0
  255. package/src/views/ResearchView/assistant/components/Messages/components/ErrorMessage/types.ts +5 -0
  256. package/src/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/chips.styles.ts +27 -0
  257. package/src/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/chips.tsx +31 -0
  258. package/src/views/ResearchView/assistant/components/Messages/components/PromptMessage/components/Chips/types.ts +6 -0
  259. package/src/views/ResearchView/assistant/components/Messages/components/PromptMessage/promptMessage.tsx +26 -0
  260. package/src/views/ResearchView/assistant/components/Messages/components/PromptMessage/types.ts +6 -0
  261. package/src/views/ResearchView/assistant/components/Messages/components/UserMessage/types.ts +5 -0
  262. package/src/views/ResearchView/assistant/components/Messages/components/UserMessage/useMessage.styles.ts +11 -0
  263. package/src/views/ResearchView/assistant/components/Messages/components/UserMessage/userMessage.tsx +21 -0
  264. package/src/views/ResearchView/assistant/components/Messages/hooks/UseScroll/hook.ts +25 -0
  265. package/src/views/ResearchView/assistant/components/Messages/messages.styles.ts +10 -0
  266. package/src/views/ResearchView/assistant/components/Messages/messages.tsx +29 -0
  267. package/src/views/ResearchView/assistant/components/Messages/selector/messageSelector.tsx +37 -0
  268. package/src/views/ResearchView/assistant/components/Messages/selector/types.ts +6 -0
  269. package/src/views/ResearchView/assistant/components/Messages/stories/args.ts +115 -0
  270. package/src/views/ResearchView/assistant/components/Messages/stories/messages.stories.tsx +24 -0
  271. package/src/views/ResearchView/assistant/components/Messages/types.ts +5 -0
  272. package/src/views/ResearchView/assistant/components/ToggleButtonGroup/stories/toggleButtonGroup.stories.tsx +22 -0
  273. package/src/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.styles.ts +22 -0
  274. package/src/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.tsx +34 -0
  275. package/src/views/ResearchView/assistant/stories/args.ts +36 -0
  276. package/src/views/ResearchView/assistant/stories/assistant.stories.tsx +39 -0
  277. package/src/views/ResearchView/query/constants.ts +5 -0
  278. package/src/views/ResearchView/query/fetch.ts +58 -0
  279. package/src/views/ResearchView/researchView.tsx +19 -0
  280. package/src/views/ResearchView/state/actions/setError/action.ts +22 -0
  281. package/src/views/ResearchView/state/actions/setError/dispatch.ts +14 -0
  282. package/src/views/ResearchView/state/actions/setError/types.ts +16 -0
  283. package/src/views/ResearchView/state/actions/setMessage/action.ts +26 -0
  284. package/src/views/ResearchView/state/actions/setMessage/dispatch.ts +14 -0
  285. package/src/views/ResearchView/state/actions/setMessage/types.ts +19 -0
  286. package/src/views/ResearchView/state/actions/setQuery/action.ts +22 -0
  287. package/src/views/ResearchView/state/actions/setQuery/dispatch.ts +14 -0
  288. package/src/views/ResearchView/state/actions/setQuery/types.ts +16 -0
  289. package/src/views/ResearchView/state/actions/setStatus/action.ts +19 -0
  290. package/src/views/ResearchView/state/actions/setStatus/dispatch.ts +14 -0
  291. package/src/views/ResearchView/state/actions/setStatus/types.ts +16 -0
  292. package/src/views/ResearchView/state/actions/types.ts +23 -0
  293. package/src/views/ResearchView/state/constants.ts +9 -0
  294. package/src/views/ResearchView/state/context.ts +11 -0
  295. package/src/views/ResearchView/state/guards/guards.ts +58 -0
  296. package/src/views/ResearchView/state/hooks/UseChatDispatch/hook.ts +46 -0
  297. package/src/views/ResearchView/state/hooks/UseChatDispatch/types.ts +11 -0
  298. package/src/views/ResearchView/state/hooks/UseChatReducer/hook.ts +15 -0
  299. package/src/views/ResearchView/state/hooks/UseChatState/hook.ts +14 -0
  300. package/src/views/ResearchView/state/initializer/initializer.ts +23 -0
  301. package/src/views/ResearchView/state/initializer/types.ts +3 -0
  302. package/src/views/ResearchView/state/provider.tsx +34 -0
  303. package/src/views/ResearchView/state/query/context.ts +9 -0
  304. package/src/views/ResearchView/state/query/hooks/UseQuery/hook.ts +11 -0
  305. package/src/views/ResearchView/state/query/hooks/UseSubmit/hook.ts +66 -0
  306. package/src/views/ResearchView/state/query/provider.tsx +27 -0
  307. package/src/views/ResearchView/state/query/types.ts +31 -0
  308. package/src/views/ResearchView/state/reducer.ts +34 -0
  309. package/src/views/ResearchView/state/types.ts +149 -0
  310. package/tests/research.assistantMessageUtils.test.ts +149 -0
  311. package/tests/research.chatState.test.ts +463 -0
  312. package/tests/research.fetchResponse.test.ts +164 -0
  313. package/tests/research.queryProvider.test.ts +321 -0
  314. package/tests/research.useKeyShortCuts.test.ts +254 -0
  315. package/tests/toggleButtonGroupProvider.test.tsx +125 -0
@@ -0,0 +1,321 @@
1
+ import { jest } from "@jest/globals";
2
+ import { act, renderHook } from "@testing-library/react";
3
+ import { FormEvent, ReactNode } from "react";
4
+ import React from "react";
5
+
6
+ /**
7
+ * Fetch callbacks passed to fetchResponse.
8
+ */
9
+ interface FetchCallbacks {
10
+ controller: AbortController;
11
+ onError: (error: Error) => void;
12
+ onSettled: () => void;
13
+ onSuccess: (data: unknown) => void;
14
+ }
15
+
16
+ // Mock fetchResponse
17
+ const mockFetchResponse = jest.fn();
18
+
19
+ jest.unstable_mockModule("../src/views/ResearchView/query/fetch", () => ({
20
+ fetchResponse: mockFetchResponse,
21
+ }));
22
+
23
+ const { useQuery } =
24
+ await import("../src/views/ResearchView/state/query/hooks/UseQuery/hook");
25
+ const { ChatProvider } =
26
+ await import("../src/views/ResearchView/state/provider");
27
+
28
+ /**
29
+ * Creates a mock form event for testing.
30
+ * @returns Mock FormEvent.
31
+ */
32
+ function createMockFormEvent(): FormEvent<HTMLFormElement> {
33
+ const mockForm = document.createElement("form");
34
+
35
+ // Mock reset
36
+ mockForm.reset = jest.fn();
37
+
38
+ return {
39
+ currentTarget: mockForm,
40
+ preventDefault: jest.fn(),
41
+ } as unknown as FormEvent<HTMLFormElement>;
42
+ }
43
+
44
+ /**
45
+ * Creates a wrapper component that provides ChatProvider with a URL.
46
+ * @param url - The query endpoint URL.
47
+ * @returns A wrapper component for renderHook.
48
+ */
49
+ function createWrapper(
50
+ url = "https://api.example.com",
51
+ ): ({ children }: { children: ReactNode }) => ReactNode {
52
+ return function Wrapper({ children }: { children: ReactNode }): ReactNode {
53
+ return React.createElement(ChatProvider, { url }, children);
54
+ };
55
+ }
56
+
57
+ describe("QueryProvider", () => {
58
+ beforeEach(() => {
59
+ mockFetchResponse.mockReset();
60
+ mockFetchResponse.mockImplementation(
61
+ async (_url: unknown, _query: unknown, callbacks: unknown) => {
62
+ (callbacks as FetchCallbacks).onSettled();
63
+ },
64
+ );
65
+ });
66
+
67
+ describe("initial state", () => {
68
+ it("should return onSubmit function", () => {
69
+ const { result } = renderHook(() => useQuery(), {
70
+ wrapper: createWrapper(),
71
+ });
72
+
73
+ expect(typeof result.current.onSubmit).toBe("function");
74
+ });
75
+ });
76
+
77
+ describe("submit guards", () => {
78
+ it("should not submit if status is loading", async () => {
79
+ const { result } = renderHook(() => useQuery(), {
80
+ wrapper: createWrapper(),
81
+ });
82
+ const event = createMockFormEvent();
83
+
84
+ await act(async () => {
85
+ await result.current.onSubmit(
86
+ event,
87
+ { query: "valid query" },
88
+ { status: { loading: true } },
89
+ );
90
+ });
91
+
92
+ expect(mockFetchResponse).not.toHaveBeenCalled();
93
+ });
94
+
95
+ it("should not submit if query is empty", async () => {
96
+ const { result } = renderHook(() => useQuery(), {
97
+ wrapper: createWrapper(),
98
+ });
99
+ const event = createMockFormEvent();
100
+
101
+ await act(async () => {
102
+ await result.current.onSubmit(
103
+ event,
104
+ { query: "" },
105
+ { status: { loading: false } },
106
+ );
107
+ });
108
+
109
+ expect(mockFetchResponse).not.toHaveBeenCalled();
110
+ });
111
+
112
+ it("should submit if query is provided", async () => {
113
+ const { result } = renderHook(() => useQuery(), {
114
+ wrapper: createWrapper(),
115
+ });
116
+ const event = createMockFormEvent();
117
+
118
+ await act(async () => {
119
+ await result.current.onSubmit(
120
+ event,
121
+ { query: "valid query" },
122
+ { status: { loading: false } },
123
+ );
124
+ });
125
+
126
+ expect(mockFetchResponse).toHaveBeenCalled();
127
+ });
128
+ });
129
+
130
+ describe("submit behavior", () => {
131
+ it("should call preventDefault on form event", async () => {
132
+ const { result } = renderHook(() => useQuery(), {
133
+ wrapper: createWrapper(),
134
+ });
135
+ const event = createMockFormEvent();
136
+
137
+ await act(async () => {
138
+ await result.current.onSubmit(
139
+ event,
140
+ { query: "diabetes studies" },
141
+ { status: { loading: false } },
142
+ );
143
+ });
144
+
145
+ expect(event.preventDefault).toHaveBeenCalled();
146
+ });
147
+
148
+ it("should call fetchResponse with correct arguments", async () => {
149
+ const { result } = renderHook(() => useQuery(), {
150
+ wrapper: createWrapper(),
151
+ });
152
+ const event = createMockFormEvent();
153
+
154
+ await act(async () => {
155
+ await result.current.onSubmit(
156
+ event,
157
+ { query: "diabetes studies" },
158
+ { status: { loading: false } },
159
+ );
160
+ });
161
+
162
+ expect(mockFetchResponse).toHaveBeenCalledWith(
163
+ "https://api.example.com",
164
+ "diabetes studies",
165
+ expect.objectContaining({
166
+ controller: expect.any(AbortController),
167
+ onError: expect.any(Function),
168
+ onSettled: expect.any(Function),
169
+ onSuccess: expect.any(Function),
170
+ }),
171
+ );
172
+ });
173
+
174
+ it("should pass url to fetchResponse", async () => {
175
+ const testUrl = "https://custom-api.example.com/search";
176
+ const { result } = renderHook(() => useQuery(), {
177
+ wrapper: createWrapper(testUrl),
178
+ });
179
+ const event = createMockFormEvent();
180
+
181
+ await act(async () => {
182
+ await result.current.onSubmit(
183
+ event,
184
+ { query: "cancer studies" },
185
+ { status: { loading: false } },
186
+ );
187
+ });
188
+
189
+ expect(mockFetchResponse).toHaveBeenCalledWith(
190
+ testUrl,
191
+ expect.any(String),
192
+ expect.any(Object),
193
+ );
194
+ });
195
+ });
196
+
197
+ describe("option callbacks", () => {
198
+ it("should call onMutate after dispatching query", async () => {
199
+ const onMutate = jest.fn();
200
+ const { result } = renderHook(() => useQuery(), {
201
+ wrapper: createWrapper(),
202
+ });
203
+ const event = createMockFormEvent();
204
+
205
+ await act(async () => {
206
+ await result.current.onSubmit(
207
+ event,
208
+ { query: "test query" },
209
+ { onMutate, status: { loading: false } },
210
+ );
211
+ });
212
+
213
+ expect(onMutate).toHaveBeenCalledWith(event.currentTarget, "test query");
214
+ });
215
+
216
+ it("should call onSettled after fetch completes", async () => {
217
+ const onSettled = jest.fn();
218
+ const { result } = renderHook(() => useQuery(), {
219
+ wrapper: createWrapper(),
220
+ });
221
+ const event = createMockFormEvent();
222
+
223
+ await act(async () => {
224
+ await result.current.onSubmit(
225
+ event,
226
+ { query: "test query" },
227
+ { onSettled, status: { loading: false } },
228
+ );
229
+ });
230
+
231
+ expect(onSettled).toHaveBeenCalledWith(event.currentTarget);
232
+ });
233
+
234
+ it("should call onSuccess after successful fetch", async () => {
235
+ const mockData = { message: "success" };
236
+ mockFetchResponse.mockImplementation(
237
+ async (_url: unknown, _query: unknown, callbacks: unknown) => {
238
+ (callbacks as FetchCallbacks).onSuccess(mockData);
239
+ (callbacks as FetchCallbacks).onSettled();
240
+ },
241
+ );
242
+
243
+ const onSuccess = jest.fn();
244
+ const { result } = renderHook(() => useQuery(), {
245
+ wrapper: createWrapper(),
246
+ });
247
+ const event = createMockFormEvent();
248
+
249
+ await act(async () => {
250
+ await result.current.onSubmit(
251
+ event,
252
+ { query: "test query" },
253
+ { onSuccess, status: { loading: false } },
254
+ );
255
+ });
256
+
257
+ expect(onSuccess).toHaveBeenCalledWith(mockData);
258
+ });
259
+
260
+ it("should call onError after failed fetch", async () => {
261
+ const mockError = new Error("Network error");
262
+ mockFetchResponse.mockImplementation(
263
+ async (_url: unknown, _query: unknown, callbacks: unknown) => {
264
+ (callbacks as FetchCallbacks).onError(mockError);
265
+ (callbacks as FetchCallbacks).onSettled();
266
+ },
267
+ );
268
+
269
+ const onError = jest.fn();
270
+ const { result } = renderHook(() => useQuery(), {
271
+ wrapper: createWrapper(),
272
+ });
273
+ const event = createMockFormEvent();
274
+
275
+ await act(async () => {
276
+ await result.current.onSubmit(
277
+ event,
278
+ { query: "test query" },
279
+ { onError, status: { loading: false } },
280
+ );
281
+ });
282
+
283
+ expect(onError).toHaveBeenCalledWith(mockError);
284
+ });
285
+ });
286
+
287
+ describe("abort handling", () => {
288
+ it("should create new AbortController for each submit", async () => {
289
+ const controllers: AbortController[] = [];
290
+ mockFetchResponse.mockImplementation(
291
+ async (_url: unknown, _query: unknown, callbacks: unknown) => {
292
+ controllers.push((callbacks as FetchCallbacks).controller);
293
+ (callbacks as FetchCallbacks).onSettled();
294
+ },
295
+ );
296
+
297
+ const { result } = renderHook(() => useQuery(), {
298
+ wrapper: createWrapper(),
299
+ });
300
+
301
+ await act(async () => {
302
+ await result.current.onSubmit(
303
+ createMockFormEvent(),
304
+ { query: "query 1" },
305
+ { status: { loading: false } },
306
+ );
307
+ });
308
+
309
+ await act(async () => {
310
+ await result.current.onSubmit(
311
+ createMockFormEvent(),
312
+ { query: "query 2" },
313
+ { status: { loading: false } },
314
+ );
315
+ });
316
+
317
+ expect(controllers).toHaveLength(2);
318
+ expect(controllers[0]).not.toBe(controllers[1]);
319
+ });
320
+ });
321
+ });
@@ -0,0 +1,254 @@
1
+ import { jest } from "@jest/globals";
2
+ import { renderHook } from "@testing-library/react";
3
+ import { KeyboardEvent } from "react";
4
+ import { Message, MESSAGE_TYPE } from "../src/views/ResearchView/state/types";
5
+
6
+ /**
7
+ * Mock input element for keyboard event testing.
8
+ */
9
+ interface MockInputElement {
10
+ form: { requestSubmit: jest.Mock } | null;
11
+ placeholder: string;
12
+ value: string;
13
+ }
14
+
15
+ // Mock useChatState
16
+ const mockUseChatState = jest.fn();
17
+
18
+ jest.unstable_mockModule(
19
+ "../src/views/ResearchView/state/hooks/UseChatState/hook",
20
+ () => ({ useChatState: mockUseChatState }),
21
+ );
22
+
23
+ const { useKeyShortCuts } =
24
+ await import("../src/views/ResearchView/assistant/components/Input/hooks/UseKeyShortCuts/hook");
25
+
26
+ /**
27
+ * Creates a mock keyboard event for testing.
28
+ * @param key - The key pressed.
29
+ * @param inputEl - The mock input element.
30
+ * @param shiftKey - Whether the shift key is pressed.
31
+ * @returns A mock KeyboardEvent.
32
+ */
33
+ function createMockKeyEvent(
34
+ key: string,
35
+ inputEl: MockInputElement,
36
+ shiftKey = false,
37
+ ): KeyboardEvent<HTMLInputElement> {
38
+ return {
39
+ currentTarget: inputEl,
40
+ key,
41
+ preventDefault: jest.fn(),
42
+ shiftKey,
43
+ } as unknown as KeyboardEvent<HTMLInputElement>;
44
+ }
45
+
46
+ /**
47
+ * Creates a mock input element for testing.
48
+ * @param value - Initial input value.
49
+ * @param placeholder - Placeholder text.
50
+ * @returns A mock input element.
51
+ */
52
+ function createMockInputEl(value = "", placeholder = ""): MockInputElement {
53
+ return {
54
+ form: { requestSubmit: jest.fn() },
55
+ placeholder,
56
+ value,
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Creates a user message for testing.
62
+ * @param text - The message text.
63
+ * @returns A user message object.
64
+ */
65
+ function createUserMessage(text: string): Message {
66
+ return {
67
+ createdAt: Date.now(),
68
+ text,
69
+ type: MESSAGE_TYPE.USER,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Creates a prompt message for testing.
75
+ * @param text - The message text.
76
+ * @returns A prompt message object.
77
+ */
78
+ function createPromptMessage(text: string): Message {
79
+ return {
80
+ createdAt: Date.now(),
81
+ text,
82
+ type: MESSAGE_TYPE.PROMPT,
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Sets up the mock useChatState with the given messages.
88
+ * @param messages - Array of messages.
89
+ */
90
+ function setupMockState(messages: Message[]): void {
91
+ mockUseChatState.mockReturnValue({
92
+ state: { messages },
93
+ });
94
+ }
95
+
96
+ describe("useKeyShortCuts", () => {
97
+ beforeEach(() => {
98
+ mockUseChatState.mockReset();
99
+ setupMockState([]);
100
+ });
101
+
102
+ describe("enter key", () => {
103
+ it("should prevent default and submit form on Enter", () => {
104
+ const { result } = renderHook(() => useKeyShortCuts());
105
+ const inputEl = createMockInputEl("some query");
106
+ const event = createMockKeyEvent("Enter", inputEl);
107
+
108
+ result.current.onKeyDown(event);
109
+
110
+ expect(event.preventDefault).toHaveBeenCalled();
111
+ expect(inputEl.form?.requestSubmit).toHaveBeenCalled();
112
+ });
113
+
114
+ it("should not prevent default on Shift+Enter", () => {
115
+ const { result } = renderHook(() => useKeyShortCuts());
116
+ const inputEl = createMockInputEl("some query");
117
+ const event = createMockKeyEvent("Enter", inputEl, true);
118
+
119
+ result.current.onKeyDown(event);
120
+
121
+ expect(event.preventDefault).not.toHaveBeenCalled();
122
+ expect(inputEl.form?.requestSubmit).not.toHaveBeenCalled();
123
+ });
124
+ });
125
+
126
+ describe("escape key", () => {
127
+ it("should clear input value on Escape", () => {
128
+ const { result } = renderHook(() => useKeyShortCuts());
129
+ const inputEl = createMockInputEl("some text");
130
+ const event = createMockKeyEvent("Escape", inputEl);
131
+
132
+ result.current.onKeyDown(event);
133
+
134
+ expect(inputEl.value).toBe("");
135
+ });
136
+ });
137
+
138
+ describe("arrow key history navigation", () => {
139
+ it("should navigate to most recent history entry on ArrowUp", () => {
140
+ setupMockState([
141
+ createUserMessage("first query"),
142
+ createPromptMessage("response"),
143
+ createUserMessage("second query"),
144
+ ]);
145
+ const { result } = renderHook(() => useKeyShortCuts());
146
+ const inputEl = createMockInputEl();
147
+ const event = createMockKeyEvent("ArrowUp", inputEl);
148
+
149
+ result.current.onKeyDown(event);
150
+
151
+ expect(inputEl.value).toBe("second query");
152
+ });
153
+
154
+ it("should navigate through multiple history entries on ArrowUp", () => {
155
+ setupMockState([
156
+ createUserMessage("first query"),
157
+ createUserMessage("second query"),
158
+ ]);
159
+ const { result } = renderHook(() => useKeyShortCuts());
160
+ const inputEl = createMockInputEl();
161
+
162
+ result.current.onKeyDown(createMockKeyEvent("ArrowUp", inputEl));
163
+ expect(inputEl.value).toBe("second query");
164
+
165
+ result.current.onKeyDown(createMockKeyEvent("ArrowUp", inputEl));
166
+ expect(inputEl.value).toBe("first query");
167
+ });
168
+
169
+ it("should clamp at oldest history entry on ArrowUp", () => {
170
+ setupMockState([createUserMessage("only query")]);
171
+ const { result } = renderHook(() => useKeyShortCuts());
172
+ const inputEl = createMockInputEl();
173
+
174
+ result.current.onKeyDown(createMockKeyEvent("ArrowUp", inputEl));
175
+ result.current.onKeyDown(createMockKeyEvent("ArrowUp", inputEl));
176
+
177
+ expect(inputEl.value).toBe("only query");
178
+ });
179
+
180
+ it("should navigate forward on ArrowDown and restore draft at index -1", () => {
181
+ setupMockState([
182
+ createUserMessage("first query"),
183
+ createUserMessage("second query"),
184
+ ]);
185
+ const { result } = renderHook(() => useKeyShortCuts());
186
+ const inputEl = createMockInputEl("my draft");
187
+
188
+ // Navigate up twice.
189
+ result.current.onKeyDown(createMockKeyEvent("ArrowUp", inputEl));
190
+ result.current.onKeyDown(createMockKeyEvent("ArrowUp", inputEl));
191
+ expect(inputEl.value).toBe("first query");
192
+
193
+ // Navigate down once.
194
+ result.current.onKeyDown(createMockKeyEvent("ArrowDown", inputEl));
195
+ expect(inputEl.value).toBe("second query");
196
+
197
+ // Navigate down to restore draft.
198
+ result.current.onKeyDown(createMockKeyEvent("ArrowDown", inputEl));
199
+ expect(inputEl.value).toBe("my draft");
200
+ });
201
+
202
+ it("should not navigate on ArrowDown when not browsing history", () => {
203
+ setupMockState([createUserMessage("some query")]);
204
+ const { result } = renderHook(() => useKeyShortCuts());
205
+ const inputEl = createMockInputEl("current text");
206
+ const event = createMockKeyEvent("ArrowDown", inputEl);
207
+
208
+ result.current.onKeyDown(event);
209
+
210
+ expect(inputEl.value).toBe("current text");
211
+ });
212
+
213
+ it("should save draft before entering history", () => {
214
+ setupMockState([createUserMessage("history entry")]);
215
+ const { result } = renderHook(() => useKeyShortCuts());
216
+ const inputEl = createMockInputEl("my draft text");
217
+
218
+ // Navigate up to save draft and enter history.
219
+ result.current.onKeyDown(createMockKeyEvent("ArrowUp", inputEl));
220
+ expect(inputEl.value).toBe("history entry");
221
+
222
+ // Navigate down to restore draft.
223
+ result.current.onKeyDown(createMockKeyEvent("ArrowDown", inputEl));
224
+ expect(inputEl.value).toBe("my draft text");
225
+ });
226
+ });
227
+
228
+ describe("tab key", () => {
229
+ it("should fill input with placeholder when input is empty", () => {
230
+ const { result } = renderHook(() => useKeyShortCuts());
231
+ const inputEl = createMockInputEl("", "Search for studies...");
232
+ const event = createMockKeyEvent("Tab", inputEl);
233
+
234
+ result.current.onKeyDown(event);
235
+
236
+ expect(event.preventDefault).toHaveBeenCalled();
237
+ expect(inputEl.value).toBe("Search for studies...");
238
+ });
239
+
240
+ it("should not prevent default when input has value", () => {
241
+ const { result } = renderHook(() => useKeyShortCuts());
242
+ const inputEl = createMockInputEl(
243
+ "existing text",
244
+ "Search for studies...",
245
+ );
246
+ const event = createMockKeyEvent("Tab", inputEl);
247
+
248
+ result.current.onKeyDown(event);
249
+
250
+ expect(event.preventDefault).not.toHaveBeenCalled();
251
+ expect(inputEl.value).toBe("existing text");
252
+ });
253
+ });
254
+ });
@@ -0,0 +1,125 @@
1
+ import { act, render, screen } from "@testing-library/react";
2
+ import React, { JSX } from "react";
3
+ import { ToggleButtonGroupProvider } from "../src/components/common/ToggleButtonGroup/provider/provider";
4
+ import { useToggleButtonGroup } from "../src/components/common/ToggleButtonGroup/provider/hook";
5
+
6
+ enum TEST_VALUE {
7
+ OPTION_A = "OPTION_A",
8
+ OPTION_B = "OPTION_B",
9
+ }
10
+
11
+ const TEST_ID_VALUE = "value";
12
+ const TEST_ID_BUTTON = "button";
13
+
14
+ /**
15
+ * Test component that consumes the toggle button group context via hook.
16
+ * @returns Test component.
17
+ */
18
+ function TestConsumer(): JSX.Element {
19
+ const { onChange, value } = useToggleButtonGroup<TEST_VALUE>();
20
+ return (
21
+ <div>
22
+ <span data-testid={TEST_ID_VALUE}>{value ?? "null"}</span>
23
+ <button
24
+ data-testid={TEST_ID_BUTTON}
25
+ onClick={(e) =>
26
+ onChange?.(
27
+ e as unknown as React.MouseEvent<HTMLElement>,
28
+ TEST_VALUE.OPTION_B,
29
+ )
30
+ }
31
+ >
32
+ Change
33
+ </button>
34
+ </div>
35
+ );
36
+ }
37
+
38
+ describe("ToggleButtonGroupProvider", () => {
39
+ it("should render children", () => {
40
+ render(
41
+ <ToggleButtonGroupProvider>
42
+ <div data-testid="child">child component</div>
43
+ </ToggleButtonGroupProvider>,
44
+ );
45
+
46
+ expect(screen.getByTestId("child")).toBeTruthy();
47
+ });
48
+
49
+ it("should set initial value to null by default", () => {
50
+ render(
51
+ <ToggleButtonGroupProvider>
52
+ <TestConsumer />
53
+ </ToggleButtonGroupProvider>,
54
+ );
55
+
56
+ expect(screen.getByTestId(TEST_ID_VALUE).textContent).toBe("null");
57
+ });
58
+
59
+ it("should set initial value when provided", () => {
60
+ render(
61
+ <ToggleButtonGroupProvider<TEST_VALUE> initialValue={TEST_VALUE.OPTION_A}>
62
+ <TestConsumer />
63
+ </ToggleButtonGroupProvider>,
64
+ );
65
+
66
+ expect(screen.getByTestId(TEST_ID_VALUE).textContent).toBe(
67
+ TEST_VALUE.OPTION_A,
68
+ );
69
+ });
70
+
71
+ it("should update value on onChange", () => {
72
+ render(
73
+ <ToggleButtonGroupProvider<TEST_VALUE> initialValue={TEST_VALUE.OPTION_A}>
74
+ <TestConsumer />
75
+ </ToggleButtonGroupProvider>,
76
+ );
77
+
78
+ expect(screen.getByTestId(TEST_ID_VALUE).textContent).toBe(
79
+ TEST_VALUE.OPTION_A,
80
+ );
81
+
82
+ act(() => {
83
+ screen.getByTestId(TEST_ID_BUTTON).click();
84
+ });
85
+
86
+ expect(screen.getByTestId(TEST_ID_VALUE).textContent).toBe(
87
+ TEST_VALUE.OPTION_B,
88
+ );
89
+ });
90
+
91
+ it("should pass props to render function children", () => {
92
+ render(
93
+ <ToggleButtonGroupProvider<TEST_VALUE> initialValue={TEST_VALUE.OPTION_A}>
94
+ {({ onChange, value }) => (
95
+ <div>
96
+ <span data-testid={TEST_ID_VALUE}>{value}</span>
97
+ <button
98
+ data-testid={TEST_ID_BUTTON}
99
+ onClick={(e) =>
100
+ onChange?.(
101
+ e as unknown as React.MouseEvent<HTMLElement>,
102
+ TEST_VALUE.OPTION_B,
103
+ )
104
+ }
105
+ >
106
+ Change
107
+ </button>
108
+ </div>
109
+ )}
110
+ </ToggleButtonGroupProvider>,
111
+ );
112
+
113
+ expect(screen.getByTestId(TEST_ID_VALUE).textContent).toBe(
114
+ TEST_VALUE.OPTION_A,
115
+ );
116
+
117
+ act(() => {
118
+ screen.getByTestId(TEST_ID_BUTTON).click();
119
+ });
120
+
121
+ expect(screen.getByTestId(TEST_ID_VALUE).textContent).toBe(
122
+ TEST_VALUE.OPTION_B,
123
+ );
124
+ });
125
+ });